Spaces:
Running
Running
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>StreamTube - Visionnage de Vidéos</title> | |
| <!-- Importation de FontAwesome pour les icônes --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <!-- Police Google Fonts: Roboto --> | |
| <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet"> | |
| <style> | |
| /* --- VARIABLES CSS & RESET --- */ | |
| :root { | |
| --primary-color: #ff0000; | |
| --bg-color: #0f0f0f; | |
| --bg-secondary: #1f1f1f; | |
| --text-main: #ffffff; | |
| --text-secondary: #aaaaaa; | |
| --hover-color: #272727; | |
| --border-color: #303030; | |
| --sidebar-width: 240px; | |
| --header-height: 60px; | |
| --transition-speed: 0.3s; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Roboto', sans-serif; | |
| } | |
| body { | |
| background-color: var(--bg-color); | |
| color: var(--text-main); | |
| overflow-x: hidden; | |
| } | |
| /* --- UI COMPONENTS (Toasts, Buttons) --- */ | |
| button { | |
| cursor: pointer; | |
| border: none; | |
| outline: none; | |
| background: transparent; | |
| color: inherit; | |
| transition: var(--transition-speed); | |
| } | |
| .btn-primary { | |
| background-color: var(--primary-color); | |
| color: white; | |
| padding: 8px 16px; | |
| border-radius: 18px; | |
| font-weight: 500; | |
| } | |
| .btn-primary:hover { | |
| background-color: #cc0000; | |
| } | |
| .btn-icon { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .btn-icon:hover { | |
| background-color: var(--hover-color); | |
| } | |
| /* Custom Scrollbar */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: var(--bg-color); | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: #717171; | |
| border-radius: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: #a0a0a0; | |
| } | |
| /* Toast Notification */ | |
| #toast-container { | |
| position: fixed; | |
| bottom: 20px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| z-index: 2000; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 10px; | |
| } | |
| .toast { | |
| background-color: #333; | |
| color: white; | |
| padding: 12px 24px; | |
| border-radius: 4px; | |
| font-size: 0.9rem; | |
| box-shadow: 0 4px 6px rgba(0,0,0,0.3); | |
| animation: slideUp 0.3s ease-out forwards; | |
| } | |
| @keyframes slideUp { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| /* --- HEADER --- */ | |
| header { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: var(--header-height); | |
| background-color: var(--bg-color); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0 24px; | |
| z-index: 1000; | |
| border-bottom: 1px solid var(--border-color); | |
| } | |
| .header-left { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| font-size: 1.2rem; | |
| font-weight: 700; | |
| letter-spacing: -0.5px; | |
| color: white; | |
| text-decoration: none; | |
| } | |
| .logo i { | |
| color: var(--primary-color); | |
| font-size: 1.5rem; | |
| } | |
| .header-center { | |
| flex: 1; | |
| max-width: 600px; | |
| margin: 0 20px; | |
| display: flex; | |
| } | |
| .search-bar { | |
| display: flex; | |
| width: 100%; | |
| } | |
| .search-bar input { | |
| width: 100%; | |
| background-color: #121212; | |
| border: 1px solid var(--border-color); | |
| border-right: none; | |
| padding: 8px 16px; | |
| border-radius: 20px 0 0 20px; | |
| color: white; | |
| font-size: 1rem; | |
| } | |
| .search-bar input:focus { | |
| border-color: #1c62b9; | |
| outline: none; | |
| } | |
| .search-bar button { | |
| background-color: #222; | |
| border: 1px solid var(--border-color); | |
| border-radius: 0 20px 20px 0; | |
| padding: 0 20px; | |
| color: var(--text-secondary); | |
| } | |
| .header-right { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .user-avatar { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 50%; | |
| background-color: #555; | |
| overflow: hidden; | |
| } | |
| .user-avatar img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| } | |
| .built-with-link { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| text-decoration: none; | |
| margin-right: 10px; | |
| display: none; /* Hidden on very small screens */ | |
| } | |
| @media (min-width: 768px) { | |
| .built-with-link { display: block; } | |
| } | |
| /* --- SIDEBAR --- */ | |
| .sidebar { | |
| position: fixed; | |
| top: var(--header-height); | |
| left: 0; | |
| width: var(--sidebar-width); | |
| height: calc(100vh - var(--header-height)); | |
| background-color: var(--bg-color); | |
| overflow-y: auto; | |
| padding: 12px; | |
| transition: transform 0.3s ease; | |
| z-index: 900; | |
| } | |
| .nav-item { | |
| display: flex; | |
| align-items: center; | |
| padding: 10px 12px; | |
| border-radius: 10px; | |
| color: var(--text-main); | |
| text-decoration: none; | |
| margin-bottom: 4px; | |
| } | |
| .nav-item:hover { | |
| background-color: var(--hover-color); | |
| } | |
| .nav-item.active { | |
| background-color: var(--hover-color); | |
| font-weight: 500; | |
| } | |
| .nav-item i { | |
| margin-right: 20px; | |
| font-size: 1.1rem; | |
| width: 24px; | |
| text-align: center; | |
| } | |
| .nav-section-title { | |
| padding: 16px 12px 8px; | |
| font-size: 1rem; | |
| font-weight: 500; | |
| color: var(--text-main); | |
| } | |
| /* --- MAIN CONTENT AREA --- */ | |
| main { | |
| margin-top: var(--header-height); | |
| margin-left: var(--sidebar-width); | |
| padding: 24px; | |
| min-height: calc(100vh - var(--header-height)); | |
| transition: margin-left 0.3s ease; | |
| } | |
| /* --- HOME VIEW (GRID) --- */ | |
| .chips-container { | |
| display: flex; | |
| gap: 12px; | |
| margin-bottom: 24px; | |
| overflow-x: auto; | |
| padding-bottom: 8px; | |
| } | |
| .chip { | |
| background-color: var(--bg-secondary); | |
| color: var(--text-main); | |
| padding: 6px 12px; | |
| border-radius: 8px; | |
| font-size: 0.9rem; | |
| white-space: nowrap; | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| border: 1px solid transparent; | |
| } | |
| .chip:hover { | |
| background-color: #3f3f3f; | |
| } | |
| .chip.active { | |
| background-color: var(--text-main); | |
| color: var(--bg-color); | |
| } | |
| .video-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 20px 16px; | |
| } | |
| .video-card { | |
| cursor: pointer; | |
| transition: transform 0.2s; | |
| } | |
| .thumbnail-container { | |
| position: relative; | |
| width: 100%; | |
| padding-top: 56.25%; /* 16:9 Aspect Ratio */ | |
| border-radius: 12px; | |
| overflow: hidden; | |
| background-color: #222; | |
| } | |
| .thumbnail-container img { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| transition: transform 0.3s ease; | |
| } | |
| .video-card:hover .thumbnail-container img { | |
| transform: scale(1.05); | |
| } | |
| .duration { | |
| position: absolute; | |
| bottom: 8px; | |
| right: 8px; | |
| background-color: rgba(0, 0, 0, 0.8); | |
| color: white; | |
| padding: 2px 4px; | |
| border-radius: 4px; | |
| font-size: 0.8rem; | |
| font-weight: 500; | |
| } | |
| .video-info { | |
| display: flex; | |
| margin-top: 12px; | |
| gap: 12px; | |
| } | |
| .channel-icon { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 50%; | |
| background-color: #333; | |
| flex-shrink: 0; | |
| } | |
| .video-details { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .video-title { | |
| font-size: 1rem; | |
| font-weight: 500; | |
| line-height: 1.4; | |
| margin-bottom: 4px; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| } | |
| .channel-name, .video-meta { | |
| font-size: 0.85rem; | |
| color: var(--text-secondary); | |
| } | |
| .channel-name:hover { | |
| color: var(--text-main); | |
| } | |
| /* --- WATCH VIEW --- */ | |
| #watch-view { | |
| display: none; /* Hidden by default */ | |
| flex-direction: row; | |
| gap: 24px; | |
| } | |
| .player-column { | |
| flex: 1; | |
| max-width: 900px; | |
| } | |
| .video-wrapper { | |
| width: 100%; | |
| aspect-ratio: 16/9; | |
| background-color: black; | |
| border-radius: 12px; | |
| overflow: hidden; | |
| margin-bottom: 12px; | |
| } | |
| video { | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .watch-title { | |
| font-size: 1.25rem; | |
| font-weight: 600; | |
| margin-bottom: 8px; | |
| } | |
| .watch-actions-bar { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| border-bottom: 1px solid var(--border-color); | |
| padding-bottom: 12px; | |
| margin-bottom: 16px; | |
| } | |
| .channel-info-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| } | |
| .subscribe-btn { | |
| background-color: var(--text-main); | |
| color: var(--bg-color); | |
| padding: 8px 16px; | |
| border-radius: 18px; | |
| font-weight: 500; | |
| font-size: 1rem; | |
| margin-left: 12px; | |
| } | |
| .subscribe-btn.subscribed { | |
| background-color: var(--bg-secondary); | |
| color: var(--text-main); | |
| } | |
| .actions-buttons { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .action-chip { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| background-color: var(--bg-secondary); | |
| padding: 8px 16px; | |
| border-radius: 18px; | |
| font-size: 0.9rem; | |
| font-weight: 500; | |
| } | |
| .action-chip:hover { | |
| background-color: var(--hover-color); | |
| } | |
| .description-box { | |
| background-color: var(--bg-secondary); | |
| padding: 12px; | |
| border-radius: 12px; | |
| font-size: 0.9rem; | |
| line-height: 1.5; | |
| margin-bottom: 24px; | |
| } | |
| .comments-section { | |
| margin-top: 24px; | |
| } | |
| .comment { | |
| display: flex; | |
| gap: 12px; | |
| margin-bottom: 16px; | |
| } | |
| .comment-body h4 { | |
| font-size: 0.85rem; | |
| margin-bottom: 4px; | |
| } | |
| .comment-body p { | |
| font-size: 0.9rem; | |
| line-height: 1.4; | |
| } | |
| /* Recommendations Sidebar in Watch View */ | |
| .recommendations-column { | |
| width: 350px; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| } | |
| .rec-video-card { | |
| display: flex; | |
| gap: 8px; | |
| cursor: pointer; | |
| } | |
| .rec-thumbnail { | |
| width: 168px; | |
| height: 94px; | |
| border-radius: 8px; | |
| overflow: hidden; | |
| position: relative; | |
| flex-shrink: 0; | |
| background-color: #222; | |
| } | |
| .rec-thumbnail img { | |
| width: 100%; | |
| height: 100%; | |
| object-fit: cover; | |
| } | |
| .rec-info h4 { | |
| font-size: 0.9rem; | |
| font-weight: 500; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| overflow: hidden; | |
| margin-bottom: 4px; | |
| } | |
| .rec-info p { | |
| font-size: 0.8rem; | |
| color: var(--text-secondary); | |
| } | |
| /* --- RESPONSIVE MEDIA QUERIES --- */ | |
| @media (max-width: 1024px) { | |
| .video-grid { | |
| grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); | |
| } | |
| .recommendations-column { | |
| width: 280px; | |
| } | |
| .rec-thumbnail { | |
| width: 140px; | |
| height: 80px; | |
| } | |
| } | |
| @media (max-width: 900px) { | |
| #watch-view { | |
| flex-direction: column; | |
| } | |
| .recommendations-column { | |
| width: 100%; | |
| } | |
| .rec-video-card { | |
| flex-direction: row; | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| .sidebar { | |
| transform: translateX(-100%); | |
| } | |
| .sidebar.active { | |
| transform: translateX(0); | |
| box-shadow: 2px 0 10px rgba(0,0,0,0.5); | |
| } | |
| main { | |
| margin-left: 0; | |
| } | |
| .header-center { | |
| display: none; /* Simplify header for mobile */ | |
| } | |
| .search-bar-mobile { | |
| display: flex; /* Would need to implement mobile search toggle */ | |
| } | |
| .video-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Header --> | |
| <header> | |
| <div class="header-left"> | |
| <button class="btn-icon" id="menu-btn" aria-label="Menu"> | |
| <i class="fa-solid fa-bars"></i> | |
| </button> | |
| <a href="#" class="logo" onclick="app.goHome()"> | |
| <i class="fa-brands fa-youtube"></i> | |
| <span>StreamTube</span> | |
| </a> | |
| </div> | |
| <div class="header-center"> | |
| <div class="search-bar"> | |
| <input type="text" placeholder="Rechercher" id="search-input"> | |
| <button id="search-btn"> | |
| <i class="fa-solid fa-magnifying-glass"></i> | |
| </button> | |
| </div> | |
| <button class="btn-icon" style="margin-left: 8px;"> | |
| <i class="fa-solid fa-microphone"></i> | |
| </button> | |
| </div> | |
| <div class="header-right"> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with-link"> | |
| Built with anycoder | |
| </a> | |
| <button class="btn-icon"> | |
| <i class="fa-solid fa-video"></i> | |
| </button> | |
| <button class="btn-icon"> | |
| <i class="fa-solid fa-bell"></i> | |
| </button> | |
| <div class="user-avatar"> | |
| <img src="https://picsum.photos/seed/user/100/100" alt="Avatar"> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Sidebar --> | |
| <aside class="sidebar" id="sidebar"> | |
| <a href="#" class="nav-item active" onclick="app.goHome()"> | |
| <i class="fa-solid fa-house"></i> | |
| <span>Accueil</span> | |
| </a> | |
| <a href="#" class="nav-item"> | |
| <i class="fa-solid fa-fire"></i> | |
| <span>Tendances</span> | |
| </a> | |
| <a href="#" class="nav-item"> | |
| <i class="fa-solid fa-music"></i> | |
| <span>Musique</span> | |
| </a> | |
| <a href="#" class="nav-item"> | |
| <i class="fa-solid fa-gamepad"></i> | |
| <span>Jeux vidéo</span> | |
| </a> | |
| <div class="nav-section-title">Mes Abonnements</div> | |
| <a href="#" class="nav-item"> | |
| <i class="fa-solid fa-user-circle"></i> | |
| <span>TechMaster</span> | |
| </a> | |
| <a href="#" class="nav-item"> | |
| <i class="fa-solid fa-user-circle"></i> | |
| <span>NatureVibe</span> | |
| </a> | |
| <a href="#" class="nav-item"> | |
| <i class="fa-solid fa-user-circle"></i> | |
| <span>CodingLife</span> | |
| </a> | |
| </aside> | |
| <!-- Main Content --> | |
| <main id="main-content"> | |
| <!-- HOME VIEW --> | |
| <section id="home-view"> | |
| <div class="chips-container"> | |
| <div class="chip active">Tout</div> | |
| <div class="chip">Jeux vidéo</div> | |
| <div class="chip">Musique</div> | |
| <div class="chip">Direct</div> | |
| <div class="chip">Programmation</div> | |
| <div class="chip">Nature</div> | |
| <div class="chip">Cuisine</div> | |
| <div class="chip">Actualités</div> | |
| </div> | |
| <div class="video-grid" id="video-grid"> | |
| <!-- Video cards injected by JS --> | |
| </div> | |
| </section> | |
| <!-- WATCH VIEW --> | |
| <section id="watch-view"> | |
| <div class="player-column"> | |
| <div class="video-wrapper"> | |
| <video id="main-player" controls> | |
| <source src="" type="video/mp4"> | |
| Votre navigateur ne supporte pas la lecture vidéo. | |
| </video> | |
| </div> | |
| <h1 class="watch-title" id="watch-title">Titre de la vidéo</h1> | |
| <div class="watch-actions-bar"> | |
| <div class="channel-info-row"> | |
| <img src="" alt="" class="channel-icon" id="watch-channel-icon"> | |
| <div> | |
| <h3 id="watch-channel-name">Nom de la chaîne</h3> | |
| <span style="font-size: 0.8rem; color: #aaa;">120 k abonnés</span> | |
| </div> | |
| <button class="subscribe-btn" onclick="app.toggleSubscribe(this)">S'abonner</button> | |
| </div> | |
| <div class="actions-buttons"> | |
| <button class="action-chip" onclick="app.showToast('J\'aime cette vidéo')"> | |
| <i class="fa-regular fa-thumbs-up"></i> 12k | |
| </button> | |
| <button class="action-chip" onclick="app.showToast('Je n\'aime pas cette vidéo')"> | |
| <i class="fa-regular fa-thumbs-down"></i> | |
| </button> | |
| <button class="action-chip" onclick="app.showToast('Lien copié !')"> | |
| <i class="fa-solid fa-share"></i> Partager | |
| </button> | |
| </div> | |
| </div> | |
| <div class="description-box" id="watch-description"> | |
| <!-- Description injected here --> | |
| </div> | |
| <div class="comments-section"> | |
| <h3>142 Commentaires</h3> | |
| <br> | |
| <div class="comment"> | |
| <div class="user-avatar" style="width: 40px; height: 40px;"> | |
| <img src="https://picsum.photos/seed/c1/40/40" alt="User"> | |
| </div> | |
| <div class="comment-body"> | |
| <h4>Jean Dupont <span style="color:#aaa; font-weight:400; font-size:0.75rem;">Il y a 2 heures</span></h4> | |
| <p>Super vidéo, merci pour le contenu ! J'ai appris beaucoup de choses.</p> | |
| </div> | |
| </div> | |
| <div class="comment"> | |
| <div class="user-avatar" style="width: 40px; height: 40px;"> | |
| <img src="https://picsum.photos/seed/c2/40/40" alt="User"> | |
| </div> | |
| <div class="comment-body"> | |
| <h4>Sarah Connor <span style="color:#aaa; font-weight:400; font-size:0.75rem;">Il y a 5 heures</span></h4> | |
| >La qualité est incroyable. Continue comme ça !</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="recommendations-column" id="recommendations-list"> | |
| <!-- Recommendations injected by JS --> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Toast Container --> | |
| <div id="toast-container"></div> | |
| <script> | |
| /** | |
| * Application Logic | |
| * Handles data, routing between Home and Watch views, and interactions. | |
| */ | |
| const app = { | |
| // Mock Data: Videos | |
| // Using Pexels Sample Videos for functionality | |
| videos: [ | |
| { | |
| id: 1, | |
| title: "L'avenir de l'Intelligence Artificielle en 2024", | |
| channel: "TechMaster", | |
| views: "1.2 M de vues", | |
| date: "il y a 2 jours", | |
| duration: "12:34", | |
| thumbnail: "https://picsum.photos/seed/tech1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar1/50/50", | |
| description: "Découvrez comment l'IA va transformer notre quotidien dans cette analyse approfondie des dernières technologies.", | |
| videoSrc: "https://videos.pexels.com/video-files/3129671/3129671-uhd_2560_1440_30fps.mp4" | |
| }, | |
| { | |
| id: 2, | |
| title: "Relaxation : Sons de la forêt et pluie douce", | |
| channel: "NatureVibe", | |
| views: "850 k vues", | |
| date: "il y a 1 semaine", | |
| duration: "45:00", | |
| thumbnail: "https://picsum.photos/seed/nature1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar2/50/50", | |
| description: "Une vidéo pour se détendre et se concentrer. Enregistrement binaural haute qualité.", | |
| videoSrc: "https://videos.pexels.com/video-files/855564/855564-hd_1920_1080_30fps.mp4" | |
| }, | |
| { | |
| id: 3, | |
| title: "Apprendre le CSS Grid en 10 minutes", | |
| channel: "CodeFast", | |
| views: "45 k vues", | |
| date: "il y a 4 heures", | |
| duration: "10:05", | |
| thumbnail: "https://picsum.photos/seed/code1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar3/50/50", | |
| description: "Le guide ultime pour maîtriser les mises en page modernes avec CSS Grid.", | |
| videoSrc: "https://videos.pexels.com/video-files/3129957/3129957-uhd_2560_1440_25fps.mp4" | |
| }, | |
| { | |
| id: 4, | |
| title: "Voyage au Japon : Les rues de Tokyo", | |
| channel: "TravelDiaries", | |
| views: "2.5 M de vues", | |
| date: "il y a 1 mois", | |
| duration: "24:10", | |
| thumbnail: "https://picsum.photos/seed/travel1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar4/50/50", | |
| description: "Explorons la capitale japonaise, de Shinjuku à Akihabara. Une immersion culturelle totale.", | |
| videoSrc: "https://videos.pexels.com/video-files/5752729/5752729-hd_1920_1080_25fps.mp4" | |
| }, | |
| { | |
| id: 5, | |
| title: "Recette : Pâtes Carbonara Authentiques", | |
| channel: "Chef Luigi", | |
| views: "300 k vues", | |
| date: "il y a 3 jours", | |
| duration: "08:45", | |
| thumbnail: "https://picsum.photos/seed/food1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar5/50/50", | |
| description: "Oubliez la crème ! Voici la vraie recette romaine pour des pâtes parfaites.", | |
| videoSrc: "https://videos.pexels.com/video-files/5497132/5497132-hd_1920_1080_25fps.mp4" | |
| }, | |
| { | |
| id: 6, | |
| title: "Top 10 des Buts de l'Année", | |
| channel: "SportCenter", | |
| views: "5 M de vues", | |
| date: "il y a 2 mois", | |
| duration: "15:20", | |
| thumbnail: "https://picsum.photos/seed/sport1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar6/50/50", | |
| description: "Les moments les plus spectaculaires du monde sportif cette année.", | |
| videoSrc: "https://videos.pexels.com/video-files/4763826/4763826-hd_1920_1080_24fps.mp4" | |
| }, | |
| { | |
| id: 7, | |
| title: "Musique Lofi pour coder et travailler", | |
| channel: "LofiGirl", | |
| views: "10 vues en direct", | |
| date: "En cours", | |
| duration: "LIVE", | |
| thumbnail: "https://picsum.photos/seed/music1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar7/50/50", | |
| description: "Beats to relax/study to. Stream 24/7.", | |
| videoSrc: "https://videos.pexels.com/video-files/6789143/6789143-hd_1920_1080_30fps.mp4" | |
| }, | |
| { | |
| id: 8, | |
| title: "Review du nouveau Smartphone X", | |
| channel: "GadgetsRev", | |
| views: "600 k vues", | |
| date: "il y a 5 jours", | |
| duration: "18:30", | |
| thumbnail: "https://picsum.photos/seed/gadget1/400/225", | |
| avatar: "https://picsum.photos/seed/avatar8/50/50", | |
| description: "Vaut-il vraiment son prix ? Tests de performance, autonomie et photo.", | |
| videoSrc: "https://videos.pexels.com/video-files/853800/853800-hd_1920_1080_24fps.mp4" | |
| } | |
| ], | |
| /** | |
| * Initialize the application | |
| */ | |
| init: function() { | |
| this.renderHome(); | |
| this.setupEventListeners(); | |
| }, | |
| /** | |
| * Render the Home Grid | |
| */ | |
| renderHome: function() { | |
| const grid = document.getElementById('video-grid'); | |
| grid.innerHTML = this.videos.map(video => ` | |
| <div class="video-card" onclick="app.watchVideo(${video.id})"> | |
| <div class="thumbnail-container"> | |
| <img src="${video.thumbnail}" alt="${video.title}"> | |
| <div class="duration">${video.duration}</div> | |
| </div> | |
| <div class="video-info"> | |
| <img class="channel-icon" src="${video.avatar}" alt="${video.channel}"> | |
| <div class="video-details"> | |
| <h3 class="video-title">${video.title}</h3> | |
| <div class="channel-name">${video.channel}</div> | |
| <div class="video-meta">${video.views} • ${video.date}</div> | |
| </div> | |
| </div> | |
| </div> | |
| `).join(''); | |
| }, | |
| /** | |
| * Switch to Watch View for a specific video | |
| */ | |
| watchVideo: function(id) { | |
| const video = this.videos.find(v => v.id === id); | |
| if (!video) return; | |
| // Hide Home, Show Watch | |
| document.getElementById('home-view').style.display = 'none'; | |
| document.getElementById('watch-view').style.display = 'flex'; | |
| document.getElementById('sidebar').style.transform = 'translateX(-100%)'; // Hide sidebar on mobile/tablet when watching | |
| // Set Player Source | |
| const player = document.getElementById('main-player'); | |
| player.src = video.videoSrc; | |
| player.load(); | |
| player.play().catch(e => console.log("Auto-play prevented by browser")); | |
| // Set Metadata | |
| document.getElementById('watch-title').innerText = video.title; | |
| document.getElementById('watch-channel-name').innerText = video.channel; | |
| document.getElementById('watch-channel-icon').src = video.avatar; | |
| document.getElementById('watch-description').innerText = video.description; | |
| // Reset Subscribe Button | |
| const subBtn = document.querySelector('.subscribe-btn'); | |
| subBtn.classList.remove('subscribed'); | |
| subBtn.innerText = "S'abonner"; | |
| // Render Recommendations (exclude current) | |
| this.renderRecommendations(id); | |
| // Scroll to top | |
| window.scrollTo(0, 0); | |
| }, | |
| /** | |
| * Render Recommendations Sidebar | |
| */ | |
| renderRecommendations: function(currentId) { | |
| const list = document.getElementById('recommendations-list'); | |
| const others = this.videos.filter(v => v.id !== currentId); | |
| list.innerHTML = others.map(video => ` | |
| <div class="rec-video-card" onclick="app.watchVideo(${video.id})"> | |
| <div class="rec-thumbnail"> | |
| <img src="${video.thumbnail}" alt="${video.title}"> | |
| <div class="duration" style="font-size: 0.7rem; padding: 1px 3px;">${video.duration}</div> | |
| </div> | |
| <div class="rec-info"> | |
| <h4>${video.title}</h4> | |
| <p>${video.channel}</p> | |
| <p>${video.views} • ${video.date}</p> | |
| </div> | |
| </div> | |
| `).join(''); | |
| }, | |
| /** | |
| * Return to Home View | |
| */ | |
| goHome: function() { | |
| // Stop Video | |
| const player = document.getElementById('main-player'); | |
| player.pause(); | |
| player.src = ""; | |
| // Show Home, Hide Watch | |
| document.getElementById('home-view').style.display = 'block'; | |
| document.getElementById('watch-view').style.display = 'none'; | |
| // Reset Sidebar visibility for desktop | |
| if (window.innerWidth > 768) { | |
| document.getElementById('sidebar').style.transform = 'translateX(0)'; | |
| } | |
| }, | |
| /** | |
| * Toggle Subscribe Button State | |
| */ | |
| toggleSubscribe: function(btn) { | |
| if (btn.classList.contains('subscribed')) { | |
| btn.classList.remove('subscribed'); | |
| btn.innerText = "S'abonner"; | |
| this.showToast("Abonnement annulé"); | |
| } else { | |
| btn.classList.add('subscribed'); | |
| btn.innerText = "Abonné"; | |
| this.showToast("Abonnement réussi !"); | |
| } | |
| }, | |
| /** | |
| * Show a Toast Notification | |
| */ | |
| showToast: function(message) { | |
| const container = document.getElementById('toast-container'); | |
| const toast = document.createElement('div'); | |
| toast.className = 'toast'; | |
| toast.innerText = message; | |
| container.appendChild(toast); | |
| // Remove after 3 seconds | |
| setTimeout(() => { | |
| toast.style.opacity = '0'; | |
| setTimeout(() => toast.remove(), 300); | |
| }, 3000); | |
| }, | |
| /** | |
| * Setup Event Listeners | |
| */ | |
| setupEventListeners: function() { | |
| // Mobile Menu Toggle | |
| document.getElementById('menu-btn').addEventListener('click', () => { | |
| const sidebar = document.getElementById('sidebar'); | |
| if (sidebar.style.transform === 'translateX(0px)') { | |
| sidebar.style.transform = ''; // Revert to CSS default (media query dependent) | |
| if(window.innerWidth <= 768) sidebar.style.transform = 'translateX(-100%)'; | |
| } else { | |
| sidebar.style.transform = 'translateX(0px)'; | |
| } | |
| }); | |
| // Search Functionality | |
| document.getElementById('search-btn').addEventListener('click', () => { | |
| const query = document.getElementById('search-input').value.toLowerCase(); | |
| if (!query) return; | |
| const filtered = this.videos.filter(v => | |
| v.title.toLowerCase().includes(query) || | |
| v.channel.toLowerCase().includes(query) | |
| ); | |
| const grid = document.getElementById('video-grid'); | |
| if (filtered.length > 0) { | |
| this.goHome(); // Ensure we are on home view | |
| grid.innerHTML = filtered.map(video => ` | |
| <div class="video-card" onclick="app.watchVideo(${video.id})"> | |
| <div class="thumbnail-container"> | |
| <img src="${video.thumbnail}" alt="${video.title}"> | |
| <div class="duration">${video.duration}</div> | |
| </div> | |
| <div class="video-info"> | |
| <img class="channel-icon" src="${video.avatar}" alt="${video.channel}"> | |
| <div class="video-details"> | |
| <h3 class="video-title">${video.title}</h3> | |
| <div class="channel-name">${video.channel}</div> | |
| <div class="video-meta">${video.views} • ${video.date}</div> | |
| </div> | |
| </div> | |
| </div> | |
| `).join(''); | |
| this.showToast(`${filtered.length} résultat(s) trouvé(s)`); | |
| } else { | |
| this.showToast("Aucune vidéo trouvée"); | |
| } | |
| }); | |
| // Allow 'Enter' key for search | |
| document.getElementById('search-input').addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| document.getElementById('search-btn').click(); | |
| } | |
| }); | |
| } | |
| }; | |
| // Start App | |
| document.addEventListener('DOMContentLoaded', () => { | |
| app.init(); | |
| }); | |
| </script> | |
| </body> | |
| </html> |