From 0f3652d871c5d40737f6de68b2e700696b2b71de Mon Sep 17 00:00:00 2001 From: root Date: Mon, 19 Jan 2026 13:48:52 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20Modernisation=20compl=C3=A8te=20UI/UX?= =?UTF-8?q?=20du=20site=20web?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design & Animations: - ✨ Background animé avec gradients qui se déplacent - 🎨 Glassmorphism (backdrop-filter blur) sur tous les éléments - ⚡ Animations fluides (cubic-bezier easing) sur toutes les interactions - 🌟 Effets néon glow améliorés avec ombres colorées - 📱 Responsive design perfectionné (mobile, tablette, desktop) Améliorations CSS: - Spinner double rotation (cyan + violet) - Logo avec animation glow cyclique (3 couleurs) - Formulaires avec icônes FontAwesome intégrées - Boutons avec effet shine au hover - Cartes avec barre supérieure animée - Scrollbar custom néon - Animations: fadeIn, slideIn, pulse, shimmer, shake Nouvelles Fonctionnalités HTML: - 🎉 Toast notifications container - 📱 Bouton menu mobile - ❤️ Section "Titres likés" - ⏰ Section "Récemment écoutées" - 🔀 Contrôles player: shuffle, repeat, mute, like, add to playlist - 🔊 Bouton volume interactif - 🎯 Attributs autocomplete sur les formulaires Nouveaux Contrôles Player: - Bouton shuffle (aléatoire) - Bouton repeat (répéter) - Bouton mute (couper le son) - Bouton like (aimer) - Bouton add to playlist - Times affichés de chaque côté du progress bar Micro-interactions: - Hover states sur tous les éléments cliquables - Transformations scale/translate au hover - Transitions 0.3s cubic-bezier fluides - Focus states avec glow sur les inputs - Loading states avec skeleton shimmer Accessibilité: - Attributs autocomplete pour les formulaires - Titles sur tous les boutons - Input types corrects (email, password) - Labels sémantiques Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- backend/app/static/css/style.css | 769 +++++++++++++++++++++++++++---- backend/app/templates/index.html | 85 +++- 2 files changed, 740 insertions(+), 114 deletions(-) diff --git a/backend/app/static/css/style.css b/backend/app/static/css/style.css index 7c974a5..1b65399 100644 --- a/backend/app/static/css/style.css +++ b/backend/app/static/css/style.css @@ -1,8 +1,9 @@ -/* AudiOhm - Neon Cyberpunk Theme */ +/* AudiOhm - Modern Neon Cyberpunk Theme 2.0 */ :root { --bg-dark: #0A0E27; --bg-darker: #050814; - --bg-card: rgba(15, 23, 50, 0.8); + --bg-card: rgba(15, 23, 50, 0.6); + --bg-card-hover: rgba(15, 23, 50, 0.8); --primary: #00F0FF; --secondary: #BF00FF; --accent: #FF006E; @@ -11,6 +12,8 @@ --border: rgba(0, 240, 255, 0.2); --glow-primary: 0 0 20px rgba(0, 240, 255, 0.5); --glow-secondary: 0 0 20px rgba(191, 0, 255, 0.5); + --glass-bg: rgba(10, 14, 39, 0.7); + --glass-border: rgba(255, 255, 255, 0.1); } * { @@ -20,10 +23,32 @@ } body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + font-family: 'Segoe UI', 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif; background: var(--bg-dark); color: var(--text-primary); overflow: hidden; + position: relative; +} + +/* Animated Background */ +body::before { + content: ''; + position: fixed; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle at 20% 80%, rgba(0, 240, 255, 0.1) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(191, 0, 255, 0.1) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(255, 0, 110, 0.05) 0%, transparent 50%); + animation: gradientShift 20s ease infinite; + z-index: -1; +} + +@keyframes gradientShift { + 0%, 100% { transform: translate(0, 0) rotate(0deg); } + 33% { transform: translate(30px, -30px) rotate(120deg); } + 66% { transform: translate(-20px, 20px) rotate(240deg); } } /* Loading Screen */ @@ -39,25 +64,74 @@ body { justify-content: center; align-items: center; z-index: 9999; + animation: fadeIn 0.5s ease; +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } } .spinner { - width: 60px; - height: 60px; - border: 4px solid rgba(0, 240, 255, 0.2); - border-top-color: var(--primary); + width: 80px; + height: 80px; + position: relative; +} + +.spinner::before, +.spinner::after { + content: ''; + position: absolute; + inset: 0; border-radius: 50%; + border: 4px solid transparent; +} + +.spinner::before { + border-top-color: var(--primary); animation: spin 1s linear infinite; } +.spinner::after { + border-bottom-color: var(--secondary); + animation: spin 1.5s linear infinite reverse; +} + @keyframes spin { to { transform: rotate(360deg); } } +.loading-screen h2 { + margin-top: 2rem; + font-size: 1.5rem; + background: linear-gradient(135deg, var(--primary), var(--secondary)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: pulse 2s ease-in-out infinite; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} + /* Screens */ .screen { width: 100%; height: 100vh; + animation: slideIn 0.5s ease; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } } .screen.hidden { @@ -72,65 +146,135 @@ body { align-items: center; height: 100vh; background: linear-gradient(135deg, var(--bg-dark) 0%, var(--bg-darker) 100%); + padding: 2rem; } .logo { - font-size: 3rem; + font-size: 4rem; margin-bottom: 2rem; - color: var(--primary); - text-shadow: var(--glow-primary); + background: linear-gradient(135deg, var(--primary), var(--secondary), var(--accent)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: logoGlow 3s ease-in-out infinite; + text-align: center; +} + +@keyframes logoGlow { + 0%, 100% { filter: drop-shadow(0 0 20px rgba(0, 240, 255, 0.5)); } + 33% { filter: drop-shadow(0 0 30px rgba(191, 0, 255, 0.7)); } + 66% { filter: drop-shadow(0 0 25px rgba(255, 0, 110, 0.6)); } } .login-form { - background: var(--bg-card); - padding: 2rem; - border-radius: 10px; - border: 1px solid var(--border); - box-shadow: 0 0 30px rgba(0, 240, 255, 0.3); + background: var(--glass-bg); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + padding: 3rem 2rem; + border-radius: 20px; + border: 1px solid var(--glass-border); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4), + var(--glow-primary); width: 100%; - max-width: 400px; + max-width: 420px; + animation: formAppear 0.6s ease; +} + +@keyframes formAppear { + from { + opacity: 0; + transform: scale(0.9) translateY(20px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } } .form-group { margin-bottom: 1.5rem; + position: relative; } .form-group input { width: 100%; - padding: 0.8rem; + padding: 1rem 1rem 1rem 3rem; background: rgba(255, 255, 255, 0.05); - border: 1px solid var(--border); - border-radius: 5px; + border: 2px solid var(--border); + border-radius: 12px; color: var(--text-primary); font-size: 1rem; + transition: all 0.3s ease; +} + +.form-group::before { + content: '\f007'; + font-family: 'Font Awesome 6 Free'; + font-weight: 900; + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + color: var(--text-secondary); + transition: all 0.3s ease; +} + +.form-group:has(input[type="password"])::before { + content: '\f023'; } .form-group input:focus { outline: none; border-color: var(--primary); + background: rgba(0, 240, 255, 0.05); box-shadow: var(--glow-primary); } +.form-group:has(input:focus)::before { + color: var(--primary); +} + .btn { width: 100%; - padding: 0.8rem; + padding: 1rem; background: linear-gradient(135deg, var(--primary), var(--secondary)); border: none; - border-radius: 5px; + border-radius: 12px; color: white; - font-size: 1rem; - font-weight: bold; + font-size: 1.1rem; + font-weight: 600; cursor: pointer; transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.btn::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + transition: left 0.5s ease; } .btn:hover { - transform: translateY(-2px); - box-shadow: var(--glow-primary); + transform: translateY(-3px); + box-shadow: var(--glow-primary), 0 10px 30px rgba(0, 240, 255, 0.3); +} + +.btn:hover::before { + left: 100%; +} + +.btn:active { + transform: translateY(-1px); } .register-link { - margin-top: 1rem; + margin-top: 1.5rem; text-align: center; color: var(--text-secondary); } @@ -138,19 +282,39 @@ body { .register-link a { color: var(--primary); text-decoration: none; + font-weight: 600; + position: relative; } -.register-link a:hover { - text-decoration: underline; +.register-link a::after { + content: ''; + position: absolute; + bottom: -2px; + left: 0; + width: 0; + height: 2px; + background: var(--primary); + transition: width 0.3s ease; +} + +.register-link a:hover::after { + width: 100%; } .error-message { margin-top: 1rem; padding: 1rem; - background: rgba(255, 0, 110, 0.2); + background: rgba(255, 0, 110, 0.1); border: 1px solid var(--accent); - border-radius: 5px; + border-radius: 12px; color: var(--accent); + animation: shake 0.5s ease; +} + +@keyframes shake { + 0%, 100% { transform: translateX(0); } + 20%, 60% { transform: translateX(-10px); } + 40%, 80% { transform: translateX(10px); } } /* Main App */ @@ -161,16 +325,34 @@ body { /* Sidebar */ .sidebar { - width: 250px; + width: 280px; background: var(--bg-darker); border-right: 1px solid var(--border); display: flex; flex-direction: column; - padding: 1rem; + padding: 2rem 1rem; + position: relative; + overflow: hidden; +} + +.sidebar::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, var(--primary), transparent); } .sidebar-header { - margin-bottom: 2rem; + margin-bottom: 3rem; +} + +.sidebar-header .logo { + font-size: 2rem; + margin-bottom: 0; + text-align: left; } .sidebar-nav { @@ -180,39 +362,102 @@ body { .nav-item { display: flex; align-items: center; - padding: 1rem; + padding: 1rem 1.2rem; color: var(--text-secondary); text-decoration: none; - border-radius: 5px; + border-radius: 12px; margin-bottom: 0.5rem; - transition: all 0.3s ease; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; +} + +.nav-item::before { + content: ''; + position: absolute; + left: 0; + top: 0; + width: 4px; + height: 100%; + background: linear-gradient(180deg, var(--primary), var(--secondary)); + transform: scaleY(0); + transition: transform 0.3s ease; } .nav-item:hover, .nav-item.active { background: rgba(0, 240, 255, 0.1); color: var(--primary); + transform: translateX(5px); +} + +.nav-item:hover::before, +.nav-item.active::before { + transform: scaleY(1); } .nav-item i { margin-right: 1rem; - width: 20px; + width: 24px; + font-size: 1.2rem; } .sidebar-footer { margin-top: auto; } +.btn-secondary { + background: rgba(255, 255, 255, 0.05); + border: 1px solid var(--border); +} + +.btn-secondary:hover { + background: rgba(255, 0, 110, 0.1); + border-color: var(--accent); + color: var(--accent); +} + /* Main Content */ .main-content { flex: 1; overflow-y: auto; - padding: 2rem; - padding-bottom: 120px; + padding: 3rem; + padding-bottom: 140px; + scrollbar-width: thin; + scrollbar-color: var(--border) transparent; +} + +.main-content::-webkit-scrollbar { + width: 8px; +} + +.main-content::-webkit-scrollbar-track { + background: transparent; +} + +.main-content::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 4px; +} + +.main-content::-webkit-scrollbar-thumb:hover { + background: var(--primary); } .page { display: none; + animation: pageFadeIn 0.4s ease; +} + +@keyframes pageFadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } } .page.active { @@ -220,27 +465,43 @@ body { } .page-header { - margin-bottom: 2rem; + margin-bottom: 3rem; } .page-header h1 { - font-size: 2.5rem; + font-size: 3rem; margin-bottom: 0.5rem; + background: linear-gradient(135deg, var(--primary), var(--secondary)); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; } .page-header p { color: var(--text-secondary); + font-size: 1.2rem; } /* Sections */ .section { - margin-bottom: 3rem; + margin-bottom: 4rem; } .section h2 { - font-size: 1.8rem; - margin-bottom: 1.5rem; + font-size: 2rem; + margin-bottom: 2rem; color: var(--primary); + display: flex; + align-items: center; + gap: 1rem; +} + +.section h2::before { + content: ''; + width: 4px; + height: 2rem; + background: linear-gradient(180deg, var(--primary), var(--secondary)); + border-radius: 2px; } /* Search Bar */ @@ -248,21 +509,31 @@ body { display: flex; gap: 1rem; margin-bottom: 2rem; + position: relative; } .search-bar input { flex: 1; - padding: 1rem; + padding: 1.2rem 1.5rem; background: var(--bg-card); - border: 1px solid var(--border); - border-radius: 5px; + backdrop-filter: blur(10px); + border: 2px solid var(--border); + border-radius: 15px; color: var(--text-primary); font-size: 1rem; + transition: all 0.3s ease; +} + +.search-bar input:focus { + outline: none; + border-color: var(--primary); + box-shadow: var(--glow-primary); + transform: scale(1.01); } .search-bar button { width: auto; - padding: 0 2rem; + padding: 0 2.5rem; } /* Track List */ @@ -274,25 +545,45 @@ body { .track-card { display: flex; align-items: center; - padding: 1rem; + padding: 1.2rem; background: var(--bg-card); + backdrop-filter: blur(10px); border: 1px solid var(--border); - border-radius: 10px; - transition: all 0.3s ease; + border-radius: 15px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; +} + +.track-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, var(--primary), var(--secondary)); + transform: scaleX(0); + transition: transform 0.3s ease; } .track-card:hover { border-color: var(--primary); - box-shadow: var(--glow-primary); - transform: translateY(-2px); + box-shadow: var(--glow-primary), 0 10px 30px rgba(0, 240, 255, 0.2); + transform: translateY(-3px) scale(1.01); +} + +.track-card:hover::before { + transform: scaleX(1); } .track-cover { width: 80px; height: 80px; object-fit: cover; - border-radius: 5px; - margin-right: 1rem; + border-radius: 12px; + margin-right: 1.5rem; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3); } .track-info { @@ -301,12 +592,14 @@ body { .track-title { font-size: 1.2rem; - font-weight: bold; + font-weight: 600; margin-bottom: 0.3rem; + color: var(--text-primary); } .track-artist { color: var(--text-secondary); + font-size: 1rem; } .track-duration { @@ -316,58 +609,87 @@ body { .track-actions { display: flex; - gap: 0.5rem; + gap: 0.8rem; } .btn-play-track { - padding: 0.5rem 1rem; + padding: 0.6rem 1.5rem; background: linear-gradient(135deg, var(--primary), var(--secondary)); border: none; - border-radius: 5px; + border-radius: 10px; color: white; cursor: pointer; - font-size: 0.9rem; + font-size: 0.95rem; + font-weight: 600; + transition: all 0.3s ease; +} + +.btn-play-track:hover { + transform: scale(1.05); + box-shadow: var(--glow-primary); } /* Playlist List */ .playlist-list { display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 1.5rem; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 2rem; } .playlist-card { background: var(--bg-card); + backdrop-filter: blur(10px); border: 1px solid var(--border); - border-radius: 10px; - padding: 1rem; + border-radius: 15px; + padding: 1.2rem; cursor: pointer; - transition: all 0.3s ease; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; + overflow: hidden; +} + +.playlist-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, rgba(0, 240, 255, 0.1), rgba(191, 0, 255, 0.1)); + opacity: 0; + transition: opacity 0.3s ease; } .playlist-card:hover { border-color: var(--primary); - box-shadow: var(--glow-primary); - transform: translateY(-5px); + box-shadow: var(--glow-primary), 0 15px 40px rgba(0, 240, 255, 0.3); + transform: translateY(-8px) scale(1.02); +} + +.playlist-card:hover::before { + opacity: 1; } .playlist-cover { width: 100%; aspect-ratio: 1; object-fit: cover; - border-radius: 5px; + border-radius: 12px; margin-bottom: 1rem; + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4); } .playlist-name { font-size: 1.1rem; - font-weight: bold; + font-weight: 600; margin-bottom: 0.3rem; + position: relative; } .playlist-info { color: var(--text-secondary); font-size: 0.9rem; + position: relative; } /* Player */ @@ -376,13 +698,26 @@ body { bottom: 0; left: 0; right: 0; - background: var(--bg-darker); + background: var(--glass-bg); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); border-top: 1px solid var(--border); - padding: 1rem 2rem; + padding: 1.2rem 2rem; display: flex; align-items: center; gap: 2rem; z-index: 1000; + box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.3); +} + +.player::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 2px; + background: linear-gradient(90deg, var(--primary), var(--secondary), var(--accent)); } /* Hide player on login screen */ @@ -393,20 +728,38 @@ body:not(:has(#main-app.visible)) .player { #main-app.visible .player { display: flex !important; + animation: playerSlideUp 0.5s ease; +} + +@keyframes playerSlideUp { + from { + transform: translateY(100%); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } } .player-info { display: flex; align-items: center; gap: 1rem; - min-width: 250px; + min-width: 280px; } .player-cover { - width: 60px; - height: 60px; + width: 70px; + height: 70px; object-fit: cover; - border-radius: 5px; + border-radius: 12px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4); + transition: transform 0.3s ease; +} + +.player-cover:hover { + transform: scale(1.1); } .player-details { @@ -414,20 +767,20 @@ body:not(:has(#main-app.visible)) .player { } .player-title { - font-size: 1rem; - font-weight: bold; - margin-bottom: 0.2rem; + font-size: 1.1rem; + font-weight: 600; + margin-bottom: 0.3rem; } .player-artist { color: var(--text-secondary); - font-size: 0.9rem; + font-size: 0.95rem; } .player-controls { display: flex; align-items: center; - gap: 1rem; + gap: 1.2rem; flex: 1; justify-content: center; } @@ -439,26 +792,31 @@ body:not(:has(#main-app.visible)) .player { font-size: 1.5rem; cursor: pointer; transition: all 0.3s ease; + padding: 0.5rem; + border-radius: 50%; } .btn-control:hover { color: var(--primary); + background: rgba(0, 240, 255, 0.1); + transform: scale(1.1); } .btn-play { - width: 50px; - height: 50px; + width: 55px; + height: 55px; border-radius: 50%; - background: var(--primary); + background: linear-gradient(135deg, var(--primary), var(--secondary)); color: var(--bg-dark); display: flex; align-items: center; justify-content: center; + box-shadow: 0 4px 15px rgba(0, 240, 255, 0.4); } .btn-play:hover { - transform: scale(1.1); - box-shadow: var(--glow-primary); + transform: scale(1.15); + box-shadow: var(--glow-primary), 0 8px 25px rgba(0, 240, 255, 0.6); } .player-progress { @@ -472,56 +830,200 @@ body:not(:has(#main-app.visible)) .player { .progress-bar, .volume-bar { flex: 1; - height: 4px; + height: 5px; background: rgba(255, 255, 255, 0.1); border: none; - border-radius: 2px; + border-radius: 5px; cursor: pointer; + transition: all 0.3s ease; +} + +.progress-bar:hover, +.volume-bar:hover { + height: 7px; } .progress-bar::-webkit-slider-thumb, .volume-bar::-webkit-slider-thumb { -webkit-appearance: none; - width: 12px; - height: 12px; - background: var(--primary); + width: 14px; + height: 14px; + background: linear-gradient(135deg, var(--primary), var(--secondary)); border-radius: 50%; cursor: pointer; + box-shadow: 0 0 10px rgba(0, 240, 255, 0.5); + transition: transform 0.2s ease; +} + +.progress-bar::-webkit-slider-thumb:hover, +.volume-bar::-webkit-slider-thumb:hover { + transform: scale(1.3); } .time { - font-size: 0.8rem; + font-size: 0.85rem; color: var(--text-secondary); - min-width: 40px; + min-width: 45px; + font-weight: 600; } .player-volume { + display: flex; + align-items: center; + gap: 0.8rem; + min-width: 160px; +} + +.player-volume i { + color: var(--text-secondary); + font-size: 1.2rem; + transition: color 0.3s ease; +} + +.player-volume:hover i { + color: var(--primary); +} + +.player-actions { display: flex; align-items: center; gap: 0.5rem; - min-width: 150px; +} + +.player-actions .btn-control { + font-size: 1.2rem; +} + +.player-actions #like-btn.liked { + color: var(--accent); +} + +.player-actions #like-btn.liked i { + font-weight: 900; +} + +/* Loading States */ +.loading { + text-align: center; + padding: 3rem; + color: var(--text-secondary); + font-size: 1.1rem; +} + +/* Skeleton Loading */ +.skeleton { + background: linear-gradient(90deg, + rgba(255, 255, 255, 0.05) 0%, + rgba(255, 255, 255, 0.1) 50%, + rgba(255, 255, 255, 0.05) 100% + ); + background-size: 200% 100%; + animation: shimmer 1.5s infinite; + border-radius: 8px; +} + +@keyframes shimmer { + 0% { background-position: 200% 0; } + 100% { background-position: -200% 0; } +} + +/* Toast Notifications */ +.toast-container { + position: fixed; + top: 2rem; + right: 2rem; + z-index: 10000; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.toast { + background: var(--glass-bg); + backdrop-filter: blur(20px); + border: 1px solid var(--border); + border-left: 4px solid var(--primary); + padding: 1rem 1.5rem; + border-radius: 10px; + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4); + animation: toastSlideIn 0.4s ease; + display: flex; + align-items: center; + gap: 1rem; + min-width: 300px; +} + +@keyframes toastSlideIn { + from { + transform: translateX(400px); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } +} + +.toast.success { + border-left-color: #00FF88; +} + +.toast.error { + border-left-color: var(--accent); +} + +.toast i { + font-size: 1.5rem; +} + +.toast.success i { + color: #00FF88; +} + +.toast.error i { + color: var(--accent); } /* Responsive */ +@media (max-width: 1024px) { + .main-content { + padding: 2rem; + } + + .page-header h1 { + font-size: 2.5rem; + } + + .playlist-list { + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + } +} + @media (max-width: 768px) { .sidebar { position: fixed; - left: -250px; + left: -280px; z-index: 1001; - transition: left 0.3s ease; + transition: left 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .sidebar.open { left: 0; + box-shadow: 5px 0 30px rgba(0, 0, 0, 0.5); } .main-content { - padding: 1rem; + padding: 1.5rem; + } + + .page-header h1 { + font-size: 2rem; } .player { flex-wrap: wrap; padding: 1rem; + gap: 1rem; } .player-info { @@ -529,12 +1031,87 @@ body:not(:has(#main-app.visible)) .player { flex: 1; } + .player-cover { + width: 50px; + height: 50px; + } + .player-controls { order: 3; width: 100%; + justify-content: space-around; } .player-progress { max-width: none; + order: 2; + flex: 1; + } + + .player-volume { + display: none; + } + + .playlist-list { + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 1rem; + } + + .track-card { + flex-wrap: wrap; + } + + .track-cover { + width: 60px; + height: 60px; } } + +/* Mobile Menu Button */ +.mobile-menu-btn { + display: none; + position: fixed; + top: 1rem; + left: 1rem; + z-index: 1002; + background: var(--primary); + border: none; + width: 50px; + height: 50px; + border-radius: 50%; + color: var(--bg-dark); + font-size: 1.5rem; + cursor: pointer; + box-shadow: var(--glow-primary); +} + +@media (max-width: 768px) { + .mobile-menu-btn { + display: flex; + align-items: center; + justify-content: center; + } +} + +/* Scroll Animations */ +.fade-in-up { + opacity: 0; + transform: translateY(20px); + animation: fadeInUp 0.6s ease forwards; +} + +@keyframes fadeInUp { + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Hover Effects */ +.hover-glow { + transition: all 0.3s ease; +} + +.hover-glow:hover { + box-shadow: var(--glow-primary); +} diff --git a/backend/app/templates/index.html b/backend/app/templates/index.html index 0ba1c03..1431577 100644 --- a/backend/app/templates/index.html +++ b/backend/app/templates/index.html @@ -8,6 +8,9 @@ + +
+
@@ -24,12 +27,14 @@