diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..1541906 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,102 @@ +import { AppProvider, useApp } from './store'; +import Sidebar from './components/Sidebar'; +import Dashboard from './components/Dashboard'; +import ChannelView from './components/ChannelView'; +import PlaylistView from './components/PlaylistView'; +import ChannelBrowser from './components/ChannelBrowser'; +import FolderView from './components/FolderView'; +import { Search, Bell, Settings } from 'lucide-react'; +import { useState } from 'react'; + +function TopBar() { + const { currentView, searchQuery, setSearchQuery } = useApp(); + const [focused, setFocused] = useState(false); + + const getTitle = () => { + switch (currentView.type) { + case 'dashboard': return 'الرئيسية'; + case 'browser': return 'استكشف القنوات'; + case 'channel': return 'القناة'; + case 'playlist': return 'قائمة التشغيل'; + case 'folder': return 'المجلد'; + default: return 'مساري'; + } + }; + + if (currentView.type === 'playlist') return null; + + return ( +
+
+

{getTitle()}

+
+ +
+
+ + setSearchQuery(e.target.value)} + onFocus={() => setFocused(true)} + onBlur={() => setFocused(false)} + placeholder="ابحث في قنواتك..." + className={`w-full bg-gray-50 rounded-xl pr-10 pl-4 py-2 text-sm border transition-all outline-none ${ + focused ? 'border-orange-300 ring-2 ring-orange-100 bg-white' : 'border-transparent' + }`} + /> +
+
+ +
+ + +
+
+ ); +} + +function MainContent() { + const { currentView } = useApp(); + + switch (currentView.type) { + case 'dashboard': + return ; + case 'channel': + return ; + case 'playlist': + return ; + case 'browser': + return ; + case 'folder': + return ; + default: + return ; + } +} + +function AppContent() { + return ( +
+ +
+ +
+ +
+
+
+ ); +} + +export default function App() { + return ( + + + + ); +} diff --git a/src/data.ts b/src/data.ts new file mode 100644 index 0000000..ea453d0 --- /dev/null +++ b/src/data.ts @@ -0,0 +1,679 @@ +import { Channel, Playlist, Video, Folder } from './types'; + +// ── Channels ────────────────────────────────────────────── +export const channels: Channel[] = [ + { + id: 'ch-tech', + name: 'أبدع تقنيًا', + description: 'قناة تعليمية متخصصة في البرمجة والتقنية وتطوير البرمجيات. نقدم دورات تعليمية شاملة في مختلف لغات البرمجة والتقنيات الحديثة.', + gradient: 'from-blue-500 to-cyan-400', + emoji: '💻', + categories: ['تعليم', 'تقنية', 'برمجة', 'ذكاء اصطناعي'], + subscriberCount: 1250000, + videoCount: 342, + }, + { + id: 'ch-history', + name: 'تاريخنا المجيد', + description: 'قناة مخصصة لتاريخ الإسلام والأمة العربية. نستعرض أحداث التاريخ الإسلامي والعربي بأسلوب شيق ومبسط.', + gradient: 'from-amber-500 to-orange-400', + emoji: '🏰', + categories: ['تاريخ', 'إسلام', 'حروب', 'حضارة', 'تراث'], + subscriberCount: 2100000, + videoCount: 256, + }, + { + id: 'ch-invent', + name: 'المخترع العربي', + description: 'قناة تهتم بالاختراعات والابتكارات العربية والعالمية. نصنع ونشرح ونبني مشاريع تقنية وعلمية متنوعة.', + gradient: 'from-emerald-500 to-teal-400', + emoji: '🔧', + categories: ['اختراعات', 'تقنية', 'ابتكار', 'روبوتات', 'إلكترونيات'], + subscriberCount: 890000, + videoCount: 178, + }, + { + id: 'ch-sharia', + name: 'علوم الشريعة', + description: 'قناة علمية شرعية متخصصة في العلوم الشرعية والفقه والعقيدة والتفسير والحديث. نهج أهل السنة والجماعة.', + gradient: 'from-purple-500 to-indigo-400', + emoji: '📖', + categories: ['دين', 'شريعة', 'فقه', 'عقيدة', 'تفسير', 'حديث'], + subscriberCount: 3200000, + videoCount: 520, + }, + { + id: 'ch-lang', + name: 'لغتنا الجميلة', + description: 'قناة مخصصة للغة العربية الفصحى والنحو والصرف والبلاغة والأدب العربي والشعر والنثر.', + gradient: 'from-rose-500 to-pink-400', + emoji: '✨', + categories: ['لغة عربية', 'أدب', 'شعر', 'نثر', 'بلاغة', 'نحو'], + subscriberCount: 760000, + videoCount: 195, + }, + { + id: 'ch-biz', + name: 'ريادة المستقبل', + description: 'قناة متخصصة في ريادة الأعمال والمشاريع الناشئة وقصص النجاح العربية. نقدم نصائح عملية لرواد الأعمال.', + gradient: 'from-orange-500 to-yellow-400', + emoji: '🚀', + categories: ['ريادة', 'أعمال', 'إدارة', 'تسويق', 'اقتصاد'], + subscriberCount: 540000, + videoCount: 134, + }, + { + id: 'ch-design', + name: 'عالم التصميم', + description: 'قناة متخصصة في التصميم الهندسي والمعماري. نستعرض أعظم التصاميم في العالم والمشاريع المعمارية الفريدة.', + gradient: 'from-violet-500 to-fuchsia-400', + emoji: '🎨', + categories: ['تصميم', 'هندسة', 'عمارة', 'فن إسلامي'], + subscriberCount: 430000, + videoCount: 98, + }, + { + id: 'ch-projects', + name: 'مشاريع عربية', + description: 'قناة تعرض المشاريع العربية والإسلامية الكبرى في مختلف المجالات التقنية والإنشائية والاقتصادية.', + gradient: 'from-sky-500 to-blue-400', + emoji: '🏗️', + categories: ['مشاريع', 'تقنية', 'ابتكار', 'اقتصاد'], + subscriberCount: 380000, + videoCount: 87, + }, + { + id: 'ch-culture', + name: 'ثقافتنا هويتنا', + description: 'قناة تهتم بالثقافة العربية والإسلامية والعادات والتقاليد واللباس الإسلامي والتراث العربي الأصيل.', + gradient: 'from-red-500 to-rose-400', + emoji: '🕌', + categories: ['ثقافة', 'تراث', 'حضارة', 'إسلام'], + subscriberCount: 920000, + videoCount: 167, + }, + { + id: 'ch-innovation', + name: 'عالم الابتكار', + description: 'قناة عن الابتكار والتصميم الحديث والاختراعات الثورية التي تغير العالم. نسلط الضوء على القمة في التصميم.', + gradient: 'from-teal-500 to-emerald-400', + emoji: '💡', + categories: ['ابتكار', 'تصميم', 'اختراعات', 'تقنية'], + subscriberCount: 670000, + videoCount: 143, + }, + { + id: 'ch-politics', + name: 'ساحة السياسة', + description: 'قناة تحليلية سياسية تتناول القضايا السياسية العربية والإسلامية والصراعات في المنطقة بأسلوب موضوعي.', + gradient: 'from-slate-600 to-gray-500', + emoji: '⚖️', + categories: ['سياسة', 'تاريخ', 'حروب', 'قانون'], + subscriberCount: 1800000, + videoCount: 312, + }, + { + id: 'ch-wars', + name: 'الملاحم والفتوحات', + description: 'قناة مخصصة لتاريخ الحروب العربية والإسلامية والفتوحات والمعارك الكبرى والقادة العسكريين المسلمين.', + gradient: 'from-zinc-700 to-stone-600', + emoji: '⚔️', + categories: ['حروب', 'تاريخ', 'عسكرية', 'استراتيجية', 'إسلام'], + subscriberCount: 1500000, + videoCount: 245, + }, +]; + +// ── Playlists ───────────────────────────────────────────── +function makeVideos(channelId: string, playlistId: string, titles: string[], durations: number[]): Video[] { + return titles.map((title, i) => ({ + id: `v-${channelId}-${playlistId}-${i}`, + playlistId, + channelId, + title, + description: `${title} - شرح مفصل مع أمثلة وتطبيقات عملية.`, + duration: `${Math.floor(durations[i] / 60)}:${String(durations[i] % 60).padStart(2, '0')}`, + durationSeconds: durations[i], + viewCount: Math.floor(Math.random() * 500000) + 10000, + publishedAt: `2024-${String(Math.floor(Math.random() * 12) + 1).padStart(2, '0')}-${String(Math.floor(Math.random() * 28) + 1).padStart(2, '0')}`, + position: i, + })); +} + +export const playlists: Playlist[] = [ + // Tech Channel + { + id: 'pl-tech-1', + channelId: 'ch-tech', + title: 'أساسيات البرمجة بلغة Python', + description: 'دورة شاملة لتعلم أساسيات البرمجة بلغة بايثون من الصفر حتى الاحتراف', + videoCount: 12, + gradient: 'from-blue-600 to-cyan-500', + emoji: '🐍', + categories: ['برمجة', 'تقنية', 'تعليم'], + }, + { + id: 'pl-tech-2', + channelId: 'ch-tech', + title: 'تطوير تطبيقات الويب الكاملة', + description: 'دورة تطوير تطبيقات الويب من الواجهة إلى الخادم باستخدام React و Node.js', + videoCount: 8, + gradient: 'from-indigo-500 to-blue-400', + emoji: '🌐', + categories: ['برمجة', 'تقنية', 'تعليم'], + }, + { + id: 'pl-tech-3', + channelId: 'ch-tech', + title: 'الذكاء الاصطناعي للمبتدئين', + description: 'مقدمة شاملة في الذكاء الاصطناعي وتعلم الآلة والشبكات العصبية', + videoCount: 10, + gradient: 'from-purple-500 to-pink-400', + emoji: '🤖', + categories: ['ذكاء اصطناعي', 'تقنية', 'تعليم'], + }, + // History Channel + { + id: 'pl-hist-1', + channelId: 'ch-history', + title: 'فتوحات الإسلام الكبرى', + description: 'سلسلة عن الفتوحات الإسلامية الكبرى من عهد النبوة إلى الدولة الأموية', + videoCount: 15, + gradient: 'from-amber-600 to-orange-500', + emoji: '⚔️', + categories: ['تاريخ', 'إسلام', 'حروب'], + }, + { + id: 'pl-hist-2', + channelId: 'ch-history', + title: 'حضارة الأندلس الإسلامية', + description: 'رحلة في تاريخ الأندلس الإسلامية depuis الفتح حتى السقوط', + videoCount: 8, + gradient: 'from-yellow-500 to-amber-400', + emoji: '🏛️', + categories: ['تاريخ', 'حضارة', 'إسلام'], + }, + { + id: 'pl-hist-3', + channelId: 'ch-history', + title: 'عظماء المسلمين', + description: 'سير وحكايات عظماء المسلمين الذين غيروا مجرى التاريخ', + videoCount: 12, + gradient: 'from-orange-600 to-red-400', + emoji: '🌟', + categories: ['تاريخ', 'إسلام', 'سيرة'], + }, + // Inventor Channel + { + id: 'pl-inv-1', + channelId: 'ch-invent', + title: 'اختراعات غيرت العالم', + description: 'سلسلة عن أعظم الاختراعات التي غيرت مسار البشرية', + videoCount: 10, + gradient: 'from-emerald-600 to-green-400', + emoji: '🔧', + categories: ['اختراعات', 'ابتكار', 'علوم'], + }, + { + id: 'pl-inv-2', + channelId: 'ch-invent', + title: 'اصنع روبوتك بنفسك', + description: 'دورة عملية لبناء روبوت من الصفر باستخدام Arduino', + videoCount: 8, + gradient: 'from-teal-500 to-emerald-400', + emoji: '🤖', + categories: ['روبوتات', 'إلكترونيات', 'اختراعات'], + }, + // Sharia Channel + { + id: 'pl-sharia-1', + channelId: 'ch-sharia', + title: 'فقه العبادات الميسّر', + description: 'شرح ميسر لأحكام العبادات من الطهارة إلى الحج', + videoCount: 20, + gradient: 'from-purple-600 to-indigo-500', + emoji: '🕌', + categories: ['فقه', 'شريعة', 'دين'], + }, + { + id: 'pl-sharia-2', + channelId: 'ch-sharia', + title: 'أصول العقيدة الإسلامية', + description: 'شرح أصول عقيدة أهل السنة والجماعة', + videoCount: 15, + gradient: 'from-indigo-600 to-violet-500', + emoji: '💫', + categories: ['عقيدة', 'شريعة', 'دين'], + }, + // Language Channel + { + id: 'pl-lang-1', + channelId: 'ch-lang', + title: 'النحو الواضح المبسّط', + description: 'دورة في النحو العربي مبسطة وميسرة للمبتدئين والمتقدمين', + videoCount: 12, + gradient: 'from-rose-500 to-pink-400', + emoji: '📝', + categories: ['لغة عربية', 'نحو', 'تعليم'], + }, + { + id: 'pl-lang-2', + channelId: 'ch-lang', + title: 'بلاغة القرآن الكريم', + description: 'دراسة بلاغة القرآن والإعجاز اللغوي في آياته الكريمة', + videoCount: 10, + gradient: 'from-pink-500 to-rose-400', + emoji: '📜', + categories: ['بلاغة', 'لغة عربية', 'قرآن'], + }, + // Business Channel + { + id: 'pl-biz-1', + channelId: 'ch-biz', + title: 'كيف تبني شركة ناشئة ناجحة', + description: 'دليلك الشامل لبناء وإدارة شركة ناشئة من الفكرة إلى التنفيذ', + videoCount: 8, + gradient: 'from-orange-500 to-amber-400', + emoji: '🏢', + categories: ['ريادة', 'أعمال', 'إدارة'], + }, + { + id: 'pl-biz-2', + channelId: 'ch-biz', + title: 'قصص نجاح عربية ملهمة', + description: 'قصص نجاح حقيقية لرواد أعمال ومبتكرين عرب غيروا الواقع', + videoCount: 6, + gradient: 'from-yellow-500 to-orange-400', + emoji: '⭐', + categories: ['ريادة', 'أعمال', 'قصص'], + }, + // Design Channel + { + id: 'pl-design-1', + channelId: 'ch-design', + title: 'أساسيات التصميم الهندسي', + description: 'مدخل إلى عالم التصميم الهندسي والمعماري', + videoCount: 10, + gradient: 'from-violet-500 to-purple-400', + emoji: '✏️', + categories: ['تصميم', 'هندسة', 'عمارة'], + }, + { + id: 'pl-design-2', + channelId: 'ch-design', + title: 'أعظم التصاميم المعمارية الإسلامية', + description: 'جولة في أعظم المباني والتصاميم المعمارية الإسلامية عبر التاريخ', + videoCount: 8, + gradient: 'from-fuchsia-500 to-violet-400', + emoji: '🕌', + categories: ['عمارة', 'فن إسلامي', 'تصميم'], + }, + // Projects Channel + { + id: 'pl-proj-1', + channelId: 'ch-projects', + title: 'مشاريع تقنية عربية رائدة', + description: 'استعراض أبرز المشاريع التقنية العربية التي تنافس عالميًا', + videoCount: 6, + gradient: 'from-sky-500 to-blue-400', + emoji: '💻', + categories: ['مشاريع', 'تقنية', 'ابتكار'], + }, + // Culture Channel + { + id: 'pl-cult-1', + channelId: 'ch-culture', + title: 'العادات والتقاليد العربية', + description: 'رحلة في العادات والتقاليد العربية الأصيلة عبر البلدان العربية', + videoCount: 8, + gradient: 'from-red-500 to-rose-400', + emoji: '🌍', + categories: ['ثقافة', 'تراث', 'حضارة'], + }, + { + id: 'pl-cult-2', + channelId: 'ch-culture', + title: 'اللباس الإسلامي عبر التاريخ', + description: 'تطور اللباس الإسلامي والعربي عبر العصور ودلالاته الثقافية', + videoCount: 6, + gradient: 'from-rose-500 to-red-400', + emoji: '👔', + categories: ['ثقافة', 'تراث', 'إسلام'], + }, + // Innovation Channel + { + id: 'pl-innov-1', + channelId: 'ch-innovation', + title: 'الابتكار في العالم العربي', + description: 'قصص الابتكار والإبداع في العالم العربي والمشاريع المتميزة', + videoCount: 8, + gradient: 'from-teal-500 to-cyan-400', + emoji: '💡', + categories: ['ابتكار', 'مشاريع', 'تقنية'], + }, + // Politics Channel + { + id: 'pl-pol-1', + channelId: 'ch-politics', + title: 'القضية الفلسطينية: تاريخ ومستقبل', + description: 'سلسلة تحليلية شاملة عن القضية الفلسطينية depuis بدايتها حتى اليوم', + videoCount: 12, + gradient: 'from-slate-600 to-gray-500', + emoji: '🇵🇸', + categories: ['سياسة', 'تاريخ', 'قانون'], + }, + // Wars Channel + { + id: 'pl-wars-1', + channelId: 'ch-wars', + title: 'حروب العرب عبر التاريخ', + description: 'سلسلة عن أبرز الحروب والمعارك التي خاضها العرب والمسلمون', + videoCount: 15, + gradient: 'from-zinc-700 to-stone-500', + emoji: '⚔️', + categories: ['حروب', 'تاريخ', 'عسكرية'], + }, + { + id: 'pl-wars-2', + channelId: 'ch-wars', + title: 'القادة العسكريون المسلمون', + description: 'سير أعظم القادة العسكريين في التاريخ الإسلامي', + videoCount: 10, + gradient: 'from-stone-600 to-zinc-500', + emoji: '🗡️', + categories: ['حروب', 'تاريخ', 'سيرة', 'عسكرية'], + }, +]; + +// ── Video Data ──────────────────────────────────────────── +const videoTitlesMap: Record = { + 'pl-tech-1': [ + 'مقدمة في لغة Python وتثبيت البيئة', 'المتغيرات وأنواع البيانات', + 'العمليات الحسابية والمنطقية', 'الشروط وجملة if-else', + 'الحلقات التكرارية for و while', 'القوائم (Lists) والعمليات عليها', + 'القواميس (Dictionaries) والتعامل معها', 'الدوال (Functions) والنطاق', + 'البرمجة الكائنية (OOP) - الجزء الأول', 'البرمجة الكائنية (OOP) - الجزء الثاني', + 'التعامل مع الملفات', 'مشروع تطبيقي: بناء برنامج إدارة مهام', + ], + 'pl-tech-2': [ + 'مقدمة في تطوير الويب و HTML', 'تنسيق الصفحات بـ CSS', + 'أساسيات JavaScript', 'مقدمة في React.js', + 'إدارة الحالة في React', 'بناء واجهة برمجة التطبيقات (API)', + 'قواعد البيانات مع MongoDB', 'نشر التطبيق على الإنترنت', + ], + 'pl-tech-3': [ + 'ما هو الذكاء الاصطناعي؟', 'أنواع التعلم الآلي', + 'الانحدار الخطي واللوجستي', 'أشجار القرار والغابات العشوائية', + 'الشبكات العصبية الاصطناعية', 'التعلم العميق (Deep Learning)', + 'معالجة اللغات الطبيعية (NLP)', 'الرؤية الحاسوبية (Computer Vision)', + 'التعلم المعزز', 'أخلاقيات الذكاء الاصطناعي', + ], + 'pl-hist-1': [ + 'مقدمة في الفتوحات الإسلامية', 'غزوات النبي ﷺ', + 'فتح مكة المكرمة', 'الفتوحات في عهد أبي بكر الصديق', + 'فتح العراق وفارس', 'فتح الشام ومصر', + 'معركة اليرموك', 'معركة القادسية', + 'فتح فارس والأهواز', 'الفتوحات في عهد عثمان بن عفان', + 'الفتوحات في أفريقيا', 'فتح الأندلس', + 'معركة Tours وبلاط الشهداء', 'الفتوحات في عهد عبد الملك بن مروان', + 'ميراث الفتوحات الإسلامية', + ], + 'pl-hist-2': [ + 'الفتح الإسلامي للأندلس', 'عهد الولاة في الأندلس', + 'تأسيس إمارة قرطبة', 'عصر الخلافة الأموية في الأندلس', + 'عصر ملوك الطوائف', 'دولة المرابطين والموحدون', + 'مملكة غرناطة آخر المعاقل', 'سقوط غرناطة ومأساة التطهير', + ], + 'pl-hist-3': [ + 'خالد بن الوليد سيف الله', 'صلاح الدين الأيوبي', + 'طارق بن زياد فاتح الأندلس', 'عقبة بن نافع فاتح أفريقيا', + 'موسى بن نصير', 'الإمام البخاري', + 'ابن سينا شيخ الأطباء', 'ابن خلدون مؤسس علم الاجتماع', + 'طه حسين عميد الأدب العربي', 'الشافعي إمام الفقهاء', + 'ابن تيمية شيخ الإسلام', 'محمد الفاتح فاتح القسطنطينة', + ], + 'pl-inv-1': [ + 'اختراع الطباعة وتأثيرها', 'المحرك البخاري والثورة الصناعية', + 'الكهرباء وتغير العالم', 'اختراع الهاتف والاتصالات', + 'الطائرة: تحقيق حلم الطيران', 'الكمبيوتر والثورة الرقمية', + 'الإنترنت: الشبكة التي غيرت العالم', 'اختراع الهاتف الذكي', + 'الطباعة ثلاثية الأبعاد', 'السيارة الكهربائية ومستقبل النقل', + ], + 'pl-inv-2': [ + 'مقدمة في الروبوتات و Arduino', 'المكونات الإلكترونية الأساسية', + 'التحكم بالمحركات والحركة', 'المستشعرات وقراءة البيانات', + 'التحكم عن بعد بالبلوتوث', 'بناء هيكل الروبوت', + 'برمجة سلوك الروبوت', 'المشروع النهائي: روبوت متكامل', + ], + 'pl-sharia-1': [ + 'مقدمة في علم الفقه وأهميته', 'المياه والطهارة', + 'الوضوء: أحكامه وسننه', 'التيمم والمسح على الخفين', + 'الصلاة: أركانها وشروطها', 'صلاة الجماعة وصلاة الجمعة', + 'صلاة المريض وقضاء الصلاة', 'الصيام: أحكامه وآدابه', + 'صيام التطوع والنوافل', 'الزكاة: شروطها ومصارفها', + 'زكاة الفطر والأموال', 'الحج والعمرة: المناسك', + 'أحكام الجهاد في الإسلام', 'الأيمان والنذور', + 'الأطعمة والأشربة في الإسلام', 'اللباس والزينة في الإسلام', + 'آداب الطعام والشراب', 'آداب النوم والاستيقاظ', + 'صلة الرحم وبر الوالدين', 'الأمر بالمعروف والنهي عن المنكر', + ], + 'pl-sharia-2': [ + 'مقدمة في علم العقيدة', 'أركان الإيمان الستة', + 'الإيمان بالله تعالى', 'الإيمان بالملائكة', + 'الإيمان بالكتب السماوية', 'الإيمان بالرسل والأنبياء', + 'الإيمان باليوم الآخر', 'الإيمان بالقدر خيره وشره', + 'التوحيد وأقسامه', 'الشرك وأنواعه', + 'البدع والمحدثات في الدين', 'الصحابة ومنزلتهم', + 'أشراط الساعة الصغرى والكبرى', 'القضاء والقدر', + 'أسماء الله الحسنى وصفاته', + ], + 'pl-lang-1': [ + 'مقدمة في علم النحو وأهميته', 'أقسام الكلام: اسم وفعل وحرف', + 'المعرب والمبني', 'الجملة الاسمية: المبتدأ والخبر', + 'الجملة الفعلية: الفاعل والمفعول به', 'المضاف والمضاف إليه', + 'النعت والتوكيد والعطف', 'الحال والتمييز', + 'المفعول لأجله والمفعول معه', 'الاستثناء', + 'النداء وأحكامه', 'إعراب الجمل', + ], + 'pl-lang-2': [ + 'مقدمة في علم البلاغة', 'علم البيان والتشبيه', + 'الاستعارة والمجاز', 'علم المعاني والخبر والإنشاء', + 'التقديم والتأخير', 'القصر والاختصاص', + 'علم البديع: المحسنات اللفظية', 'علم البديع: المحسنات المعنوية', + 'الإعجاز البياني للقرآن', 'تحليل بلاغي لسور مختارة', + ], + 'pl-biz-1': [ + 'من أين تبدأ فكرتك؟', 'دراسة الجدوى وتحليل السوق', + 'كتابة خطة العمل (Business Plan)', 'بناء فريق العمل', + 'التمويل وجمع رأس المال', 'التسويق الرقمي للمشروعات الناشئة', + 'إدارة المال والميزانية', 'توسيع المشروع والنمو', + ], + 'pl-biz-2': [ + 'قصة نجاح: محمد العريفي', 'قصة نجاح: سوق.كم (Souq.com)', + 'قصة نجاح: كريم (Careem)', 'قصة نجاح: نون (Noon)', + 'قصة نجاح: طلبات (Talabat)', 'قصة نجاح: أنجزي (Anghami)', + ], + 'pl-design-1': [ + 'مقدمة في التصميم الهندسي', 'أساسيات الرسم الهندسي', + 'الإسقاط والمساقط', 'التصميم ثلاثي الأبعاد', + 'استخدام برامج التصميم CAD', 'تصميم الأبنية السكنية', + 'التصميم المستدام والبيئي', 'تصميم المساجد والمراكز الإسلامية', + 'التصميم الداخلي وتنسيق المساحات', 'مشروع تطبيقي: تصميم فيلا متكاملة', + ], + 'pl-design-2': [ + 'المسجد الحرام والمسجد النبوي', 'مسجد الصخرة في القدس', + 'جامع قرطبة الكبير', 'مسجد السلطان أحمد في إسطنبول', + 'تاج محل في الهند', 'قصر الحمراء في غرناطة', + 'المدرسة المستنصرية في بغداد', 'مسجد الشيخ زايد الكبير', + ], + 'pl-proj-1': [ + 'تطبيق كريم: أول يونيكورن عربي', 'منصة بايت: ثورة في التعليم', + 'شركة أرامكو: عملاق الطاقة', 'مدينة NEOM: رؤية المستقبل', + 'برج المملكة: أيقونة الرياض', 'وادي السيليكون العربي', + ], + 'pl-cult-1': [ + 'الضيافة العربية: كرم لا حدود له', 'القهوة العربية وثقافة تقديمها', + 'الأعياد والمناسبات العربية', 'الموسيقى والفنون العربية', + 'الخط العربي وفنونه', 'الأسواق الشعبية العربية', + 'الحرف اليدوية العربية', 'الطبخ العربي وتنوعه', + ], + 'pl-cult-2': [ + 'اللباس في العصر الجاهلي', 'لباس الرسول ﷺ والصحابة', + 'اللباس في العصر الأموي والعباسي', 'اللباس في الأندلس', + 'اللباس في العصر العثماني', 'اللباس العربي المعاصر والحجاب', + ], + 'pl-innov-1': [ + 'الابتكار في الإمارات', 'التقنية في السعودية: رؤية 2030', + 'الابتكار في مصر: وادي التكنولوجيا', 'الأردن: وادي السيليكون الجديد', + 'الابتكار في تونس والمغرب', 'المرأة العربية والابتكار', + 'الابتكار في التعليم العربي', 'مستقبل الابتكار العربي', + ], + 'pl-pol-1': [ + 'جذور القضية الفلسطينية', 'وعد بلفور والانتداب البريطاني', + 'النكبة عام 1948', 'حرب 1967 وحرب الاستنزاف', + 'حرب أكتوبر 1973', 'اتفاقيات كامب ديفيد وأوسلو', + 'الانتفاضة الأولى والثانية', 'حصار غزة', + 'القدس ومكانتها', 'المقاومة الفلسطينية', + 'القضية في المحافل الدولية', 'مستقبل القضية الفلسطينية', + ], + 'pl-wars-1': [ + 'حروب ما قبل الإسلام', 'غزوات الرسول ﷺ', + 'حروب الردة', 'الفتوحات الإسلامية الكبرى', + 'الحروب الصليبية', 'معركة حطين', + 'فتح القسطنطينية', 'معركة عين جالوت', + 'حرب الاستقلال الجزائرية', 'حرب 1948', + 'حرب 1967', 'حرب 1973', + 'الحرب اللبنانية الأهلية', 'الحرب العراقية الإيرانية', + 'حرب الخليج الثانية', + ], + 'pl-wars-2': [ + 'خالد بن الوليد: سيف الله المسلول', 'صلاح الدين الأيوبي: محرر القدس', + 'طارق بن زياد: فاتح الأندلس', 'عقبة بن نافع: فاتح أفريقيا', + 'أسامة بن زيد: أصغر قائد', 'المعتصم بالله: بطل عمورية', + 'قطز: بطل عين جالوت', 'محمد الفاتح: فاتح القسطنطينية', + 'صلاح الدين الصفدي', 'أبو عبيدة عامر بن الجراح', + ], +}; + +// Generate durations for each playlist +function generateDurations(count: number): number[] { + return Array.from({ length: count }, () => Math.floor(Math.random() * 30 + 8) * 60 + Math.floor(Math.random() * 60)); +} + +export const videos: Record = {}; +for (const pl of playlists) { + const titles = videoTitlesMap[pl.id]; + if (titles) { + const durations = generateDurations(titles.length); + videos[pl.id] = makeVideos(pl.channelId, pl.id, titles, durations); + } +} + +// Standalone videos (not in playlists) +export const standaloneVideos: Video[] = [ + { id: 'sv-1', playlistId: '', channelId: 'ch-tech', title: 'لماذا يجب أن تتعلم البرمجة في 2024؟', description: 'في هذا الفيديو نناقش أهمية تعلم البرمجة وأفضل اللغات للبدء', duration: '18:30', durationSeconds: 1110, viewCount: 342000, publishedAt: '2024-03-15', position: 0 }, + { id: 'sv-2', playlistId: '', channelId: 'ch-tech', title: 'أفضل 10 محررات أكواد للمبرمجين', description: 'مقارنة بين أفضل محررات الأكواد ومميزات كل منها', duration: '22:15', durationSeconds: 1335, viewCount: 198000, publishedAt: '2024-03-20', position: 0 }, + { id: 'sv-3', playlistId: '', channelId: 'ch-history', title: 'كيف بنى المسلمون حضارة عظيمة؟', description: 'نظرة شاملة على عوامل قيام الحضارة الإسلامية', duration: '35:45', durationSeconds: 2145, viewCount: 567000, publishedAt: '2024-02-10', position: 0 }, + { id: 'sv-4', playlistId: '', channelId: 'ch-history', title: 'أعظم المعارك في التاريخ الإسلامي', description: 'استعراض لأعظم المعارك التي غيرت مجرى التاريخ', duration: '42:00', durationSeconds: 2520, viewCount: 421000, publishedAt: '2024-01-25', position: 0 }, + { id: 'sv-5', playlistId: '', channelId: 'ch-sharia', title: 'أهمية طلب العلم الشرعي', description: 'فضيلة طلب العلم الشرعي وأهميته في حياة المسلم', duration: '25:10', durationSeconds: 1510, viewCount: 890000, publishedAt: '2024-04-01', position: 0 }, + { id: 'sv-6', playlistId: '', channelId: 'ch-invent', title: 'اختراع عربي ي revolutionize عالم الطاقة', description: 'تعرف على اختراع عربي جديد في مجال الطاقة المتجددة', duration: '15:45', durationSeconds: 945, viewCount: 234000, publishedAt: '2024-03-28', position: 0 }, + { id: 'sv-7', playlistId: '', channelId: 'ch-lang', title: 'جمال اللغة العربية: 10 كلمات لا مثيل لها', description: 'كلمات عربية فريدة لا توجد في أي لغة أخرى', duration: '12:30', durationSeconds: 750, viewCount: 456000, publishedAt: '2024-03-10', position: 0 }, + { id: 'sv-8', playlistId: '', channelId: 'ch-biz', title: '5 مشاريع ناشئة عربية حققت نجاحًا عالميًا', description: 'قصص نجاح لمشاريع عربية وصلت للعالمية', duration: '28:20', durationSeconds: 1700, viewCount: 312000, publishedAt: '2024-02-20', position: 0 }, + { id: 'sv-9', playlistId: '', channelId: 'ch-design', title: 'التصميم المستدام: مستقبل العمارة', description: 'كيف يغير التصميم المستدام وجه العمارة العالمية', duration: '19:55', durationSeconds: 1195, viewCount: 167000, publishedAt: '2024-03-05', position: 0 }, + { id: 'sv-10', playlistId: '', channelId: 'ch-culture', title: 'الخط العربي: فن وتاريخ', description: 'تاريخ فن الخط العربي وأشهر الخطاطين', duration: '32:10', durationSeconds: 1930, viewCount: 278000, publishedAt: '2024-01-30', position: 0 }, + { id: 'sv-11', playlistId: '', channelId: 'ch-politics', title: 'النظام السياسي العربي: تحليل شامل', description: 'تحليل معمق للأنظمة السياسية في الدول العربية', duration: '45:30', durationSeconds: 2730, viewCount: 534000, publishedAt: '2024-02-15', position: 0 }, + { id: 'sv-12', playlistId: '', channelId: 'ch-wars', title: 'أعظم 10 قادة عسكريين في التاريخ', description: 'ترتيب أعظم القادة العسكريين عبر التاريخ', duration: '38:20', durationSeconds: 2300, viewCount: 678000, publishedAt: '2024-03-22', position: 0 }, +]; + +// ── Default Folders ─────────────────────────────────────── +export const defaultFolders: Folder[] = [ + { + id: 'folder-1', + name: 'البرمجة والتقنية', + color: 'blue', + emoji: '💻', + channelIds: ['ch-tech', 'ch-invent', 'ch-innovation'], + }, + { + id: 'folder-2', + name: 'العلوم الشرعية', + color: 'purple', + emoji: '📖', + channelIds: ['ch-sharia', 'ch-culture'], + }, + { + id: 'folder-3', + name: 'التاريخ والحروب', + color: 'amber', + emoji: '⚔️', + channelIds: ['ch-history', 'ch-wars'], + }, + { + id: 'folder-4', + name: 'اللغة والأدب', + color: 'rose', + emoji: '✨', + channelIds: ['ch-lang'], + }, + { + id: 'folder-5', + name: 'ريادة الأعمال', + color: 'orange', + emoji: '🚀', + channelIds: ['ch-biz', 'ch-projects'], + }, +]; + +// ── Helper functions ────────────────────────────────────── +export function getChannel(id: string): Channel | undefined { + return channels.find(c => c.id === id); +} + +export function getPlaylist(id: string): Playlist | undefined { + return playlists.find(p => p.id === id); +} + +export function getChannelPlaylists(channelId: string): Playlist[] { + return playlists.filter(p => p.channelId === channelId); +} + +export function getPlaylistVideos(playlistId: string): Video[] { + return videos[playlistId] || []; +} + +export function getChannelVideos(channelId: string): Video[] { + const allVideos: Video[] = []; + for (const pl of playlists.filter(p => p.channelId === channelId)) { + allVideos.push(...(videos[pl.id] || [])); + } + allVideos.push(...standaloneVideos.filter(v => v.channelId === channelId)); + return allVideos; +} + +export function formatNumber(num: number): string { + if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M'; + if (num >= 1000) return (num / 1000).toFixed(0) + 'K'; + return num.toString(); +} + +export function getCategoryColor(cat: string): string { + const map: Record = { + 'تعليم': 'bg-blue-100 text-blue-700', + 'تقنية': 'bg-cyan-100 text-cyan-700', + 'برمجة': 'bg-indigo-100 text-indigo-700', + 'تاريخ': 'bg-amber-100 text-amber-700', + 'إسلام': 'bg-green-100 text-green-700', + 'حروب': 'bg-red-100 text-red-700', + 'اختراعات': 'bg-emerald-100 text-emerald-700', + 'دين': 'bg-purple-100 text-purple-700', + 'شريعة': 'bg-violet-100 text-violet-700', + 'لغة عربية': 'bg-pink-100 text-pink-700', + 'ريادة': 'bg-orange-100 text-orange-700', + 'تصميم': 'bg-fuchsia-100 text-fuchsia-700', + 'ثقافة': 'bg-rose-100 text-rose-700', + 'سياسة': 'bg-slate-100 text-slate-700', + 'ابتكار': 'bg-teal-100 text-teal-700', + 'مشاريع': 'bg-sky-100 text-sky-700', + }; + return map[cat] || 'bg-gray-100 text-gray-700'; +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..c477a3e --- /dev/null +++ b/src/index.css @@ -0,0 +1,116 @@ +@import "tailwindcss"; + +@theme { + --font-family-tajawal: 'Tajawal', sans-serif; + --color-primary: #FF6B35; + --color-primary-dark: #E55A2B; + --color-secondary: #7C3AED; + --color-accent: #10B981; + --color-accent-gold: #F59E0B; + --color-surface: #FFF8F0; + --color-surface-card: #FFFFFF; + --color-surface-dark: #1E1B2E; +} + +* { + font-family: 'Tajawal', sans-serif; +} + +body { + background-color: #FFF8F0; + overflow: hidden; +} + +@keyframes shimmer { + 0% { background-position: -200% 0; } + 100% { background-position: 200% 0; } +} + +@keyframes pulse-glow { + 0%, 100% { box-shadow: 0 0 5px rgba(255, 107, 53, 0.3); } + 50% { box-shadow: 0 0 20px rgba(255, 107, 53, 0.6); } +} + +@keyframes slide-up { + from { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes slide-in-right { + from { opacity: 0; transform: translateX(-30px); } + to { opacity: 1; transform: translateX(0); } +} + +@keyframes progress-fill { + from { width: 0%; } +} + +@keyframes float { + 0%, 100% { transform: translateY(0); } + 50% { transform: translateY(-5px); } +} + +@keyframes gradient-shift { + 0% { background-position: 0% 50%; } + 50% { background-position: 100% 50%; } + 100% { background-position: 0% 50%; } +} + +.animate-shimmer { + animation: shimmer 2s infinite; + background-size: 200% 100%; +} + +.animate-pulse-glow { + animation: pulse-glow 2s infinite; +} + +.animate-slide-up { + animation: slide-up 0.4s ease-out; +} + +.animate-slide-in { + animation: slide-in-right 0.3s ease-out; +} + +.animate-progress { + animation: progress-fill 1s ease-out; +} + +.animate-float { + animation: float 3s ease-in-out infinite; +} + +.gradient-animated { + background-size: 200% 200%; + animation: gradient-shift 3s ease infinite; +} + +.custom-scrollbar::-webkit-scrollbar { + width: 6px; +} + +.custom-scrollbar::-webkit-scrollbar-track { + background: transparent; +} + +.custom-scrollbar::-webkit-scrollbar-thumb { + background: rgba(124, 58, 237, 0.2); + border-radius: 3px; +} + +.custom-scrollbar::-webkit-scrollbar-thumb:hover { + background: rgba(124, 58, 237, 0.4); +} + +.video-card:hover .video-overlay { + opacity: 1; +} + +.progress-ring { + transform: rotate(-90deg); +} + +.playlist-gradient { + background: linear-gradient(135deg, #FF6B35 0%, #7C3AED 50%, #10B981 100%); +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..12fa35b --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import "./index.css"; +import App from "./App"; + +createRoot(document.getElementById("root")!).render( + + + +); diff --git a/src/store.tsx b/src/store.tsx new file mode 100644 index 0000000..8aec2d6 --- /dev/null +++ b/src/store.tsx @@ -0,0 +1,192 @@ +import React, { createContext, useContext, useState, useCallback, useEffect } from 'react'; +import { ViewType, Folder, UserProgress } from './types'; +import { defaultFolders } from './data'; + +interface AppState { + currentView: ViewType; + followedChannelIds: string[]; + folders: Folder[]; + progress: UserProgress; + sidebarOpen: boolean; + searchQuery: string; +} + +interface AppContextType extends AppState { + setView: (view: ViewType) => void; + followChannel: (id: string) => void; + unfollowChannel: (id: string) => void; + toggleSidebar: () => void; + setSearchQuery: (q: string) => void; + markVideoWatched: (videoId: string) => void; + updatePlaylistProgress: (playlistId: string, videoIndex: number) => void; + completePlaylist: (playlistId: string) => void; + createFolder: (name: string, color: string, emoji: string) => void; + deleteFolder: (id: string) => void; + addChannelToFolder: (folderId: string, channelId: string) => void; + removeChannelFromFolder: (folderId: string, channelId: string) => void; + updateFolder: (folderId: string, updates: Partial) => void; +} + +const AppContext = createContext(null); + +export function useApp() { + const ctx = useContext(AppContext); + if (!ctx) throw new Error('useApp must be used within AppProvider'); + return ctx; +} + +const STORAGE_KEY = 'masari-state'; + +function loadState(): Partial { + try { + const saved = localStorage.getItem(STORAGE_KEY); + if (saved) return JSON.parse(saved); + } catch {} + return {}; +} + +function saveState(state: AppState) { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify({ + followedChannelIds: state.followedChannelIds, + folders: state.folders, + progress: state.progress, + })); + } catch {} +} + +export function AppProvider({ children }: { children: React.ReactNode }) { + const saved = loadState(); + + const [currentView, setCurrentView] = useState({ type: 'dashboard' }); + const [followedChannelIds, setFollowedChannelIds] = useState( + saved.followedChannelIds || ['ch-tech', 'ch-history', 'ch-sharia', 'ch-lang', 'ch-biz'] + ); + const [folders, setFolders] = useState( + saved.folders || defaultFolders + ); + const [progress, setProgress] = useState( + saved.progress || { + watchedVideos: [], + playlistProgress: {}, + completedPlaylists: [], + streak: 3, + lastWatchDate: new Date().toISOString().split('T')[0], + totalWatched: 0, + } + ); + const [sidebarOpen, setSidebarOpen] = useState(true); + const [searchQuery, setSearchQuery] = useState(''); + + // Save to localStorage on changes + useEffect(() => { + saveState({ followedChannelIds, folders, progress } as AppState); + }, [followedChannelIds, folders, progress]); + + const setView = useCallback((view: ViewType) => { + setCurrentView(view); + }, []); + + const followChannel = useCallback((id: string) => { + setFollowedChannelIds(prev => prev.includes(id) ? prev : [...prev, id]); + }, []); + + const unfollowChannel = useCallback((id: string) => { + setFollowedChannelIds(prev => prev.filter(c => c !== id)); + }, []); + + const toggleSidebar = useCallback(() => { + setSidebarOpen(prev => !prev); + }, []); + + const markVideoWatched = useCallback((videoId: string) => { + setProgress(prev => ({ + ...prev, + watchedVideos: prev.watchedVideos.includes(videoId) + ? prev.watchedVideos + : [...prev.watchedVideos, videoId], + totalWatched: prev.totalWatched + 1, + lastWatchDate: new Date().toISOString().split('T')[0], + })); + }, []); + + const updatePlaylistProgress = useCallback((playlistId: string, videoIndex: number) => { + setProgress(prev => ({ + ...prev, + playlistProgress: { + ...prev.playlistProgress, + [playlistId]: Math.max(prev.playlistProgress[playlistId] || 0, videoIndex), + }, + })); + }, []); + + const completePlaylist = useCallback((playlistId: string) => { + setProgress(prev => ({ + ...prev, + completedPlaylists: prev.completedPlaylists.includes(playlistId) + ? prev.completedPlaylists + : [...prev.completedPlaylists, playlistId], + })); + }, []); + + const createFolder = useCallback((name: string, color: string, emoji: string) => { + const newFolder: Folder = { + id: `folder-${Date.now()}`, + name, + color, + emoji, + channelIds: [], + }; + setFolders(prev => [...prev, newFolder]); + }, []); + + const deleteFolder = useCallback((id: string) => { + setFolders(prev => prev.filter(f => f.id !== id)); + }, []); + + const addChannelToFolder = useCallback((folderId: string, channelId: string) => { + setFolders(prev => prev.map(f => + f.id === folderId && !f.channelIds.includes(channelId) + ? { ...f, channelIds: [...f.channelIds, channelId] } + : f + )); + }, []); + + const removeChannelFromFolder = useCallback((folderId: string, channelId: string) => { + setFolders(prev => prev.map(f => + f.id === folderId + ? { ...f, channelIds: f.channelIds.filter(c => c !== channelId) } + : f + )); + }, []); + + const updateFolder = useCallback((folderId: string, updates: Partial) => { + setFolders(prev => prev.map(f => + f.id === folderId ? { ...f, ...updates } : f + )); + }, []); + + const value: AppContextType = { + currentView, + followedChannelIds, + folders, + progress, + sidebarOpen, + searchQuery, + setView, + followChannel, + unfollowChannel, + toggleSidebar, + setSearchQuery, + markVideoWatched, + updatePlaylistProgress, + completePlaylist, + createFolder, + deleteFolder, + addChannelToFolder, + removeChannelFromFolder, + updateFolder, + }; + + return {children}; +}