From a333797b55261a6c9a64a5b186cba538aef24cc3 Mon Sep 17 00:00:00 2001 From: Nivyasudeesh Date: Mon, 26 Oct 2026 21:13:15 +0530 Subject: [PATCH] feat: add dark or light theme toggle --- backend/.env.example | 2 +- frontend/index.html | 14 ++++++-- frontend/static/css/style.css | 65 ++++++++++++++++++++++++++++++++--- frontend/static/js/app.js | 25 ++++++++++++++ 4 files changed, 98 insertions(+), 8 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index 8323337..a343c2e 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -17,4 +17,4 @@ HOST=0.0.0.0 PORT=7654 # Logging -LOG_LEVEL=INFO +LOG_LEVEL=INFO \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html index a293196..dc586ad 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -25,7 +25,7 @@ Reelo - YT & Insta Converter - +
+ @@ -323,6 +333,6 @@

1-Hour Auto Delete

- + diff --git a/frontend/static/css/style.css b/frontend/static/css/style.css index 8489bc5..6ed3891 100644 --- a/frontend/static/css/style.css +++ b/frontend/static/css/style.css @@ -23,6 +23,13 @@ /* Slate 50 */ --text-muted: #94a3b8; /* Slate 400 */ + --logo-start: #fff; + --logo-end: #94a3b8; + --gradient-primary: rgba(99, 102, 241, 0.08); + --gradient-secondary: rgba(236, 72, 153, 0.08); + --tab-hover: rgba(255, 255, 255, 0.05); + --focus-glow: rgba(99, 102, 241, 0.1); + color-scheme: dark; /* Borders & Shadows */ --border: rgba(255, 255, 255, 0.1); @@ -41,6 +48,23 @@ /* Narrower for better focus */ } +[data-theme="light"] { + --bg-body: #f1f5f9; + --bg-card: #ffffff; + --bg-input: #e2e8f0; + --bg-hover: #cbd5e1; + --text-main: #1e293b; + --text-muted: #64748b; + --border: rgba(15, 23, 42, 0.12); + --logo-start: #312e81; + --logo-end: #6366f1; + --gradient-primary: rgba(99, 102, 241, 0.12); + --gradient-secondary: rgba(236, 72, 153, 0.1); + --tab-hover: rgba(15, 23, 42, 0.06); + --focus-glow: rgba(99, 102, 241, 0.16); + color-scheme: light; +} + /* ==================== Reset & Base ==================== */ * { margin: 0; @@ -74,12 +98,12 @@ body { background: radial-gradient( circle at 15% 50%, - rgba(99, 102, 241, 0.08), + var(--gradient-primary), transparent 25% ), radial-gradient( circle at 85% 30%, - rgba(236, 72, 153, 0.08), + var(--gradient-secondary), transparent 25% ); pointer-events: none; @@ -99,8 +123,39 @@ body { /* ==================== Header ==================== */ .header { + position: relative; text-align: center; margin-bottom: 2.5rem; + padding-top: 3.25rem; +} + +.theme-toggle { + position: absolute; + top: 0; + right: 0; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.55rem 0.8rem; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--bg-card); + color: var(--text-main); + font: inherit; + font-size: 0.875rem; + font-weight: 600; + cursor: pointer; + transition: background-color 0.2s ease, border-color 0.2s ease; +} + +.theme-toggle:hover { + background: var(--bg-input); +} + +.theme-toggle:focus-visible { + outline: 2px solid var(--primary); + outline-offset: 2px; } .logo { @@ -119,7 +174,7 @@ body { font-size: 2rem; font-weight: 800; letter-spacing: -0.025em; - background: linear-gradient(to right, #fff, #94a3b8); + background: linear-gradient(to right, var(--logo-start), var(--logo-end)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; @@ -174,7 +229,7 @@ body { outline: none; border-color: var(--primary); background: var(--bg-body); - box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1); + box-shadow: 0 0 0 4px var(--focus-glow); } .url-input::placeholder { @@ -248,7 +303,7 @@ body { .format-btn:hover { color: var(--text-main); - background: rgba(255, 255, 255, 0.05); + background: var(--tab-hover); } .format-btn.active { diff --git a/frontend/static/js/app.js b/frontend/static/js/app.js index e3e86e3..c793c34 100644 --- a/frontend/static/js/app.js +++ b/frontend/static/js/app.js @@ -13,6 +13,7 @@ let currentMode = 'audio'; // ==================== DOM Elements ==================== const elements = { + themeToggle: document.getElementById('theme-toggle'), urlInput: document.getElementById('youtube-url'), pasteBtn: document.getElementById('paste-btn'), convertBtn: document.getElementById('convert-btn'), @@ -42,6 +43,30 @@ const elements = { tryAgainBtn: document.getElementById('try-again-btn') }; +function setTheme(theme, persist = true) { + const isLight = theme === 'light'; + document.documentElement.dataset.theme = isLight ? 'light' : 'dark'; + elements.themeToggle.setAttribute('aria-pressed', String(isLight)); + elements.themeToggle.setAttribute( + 'aria-label', + `Switch to ${isLight ? 'dark' : 'light'} theme` + ); + elements.themeToggle.innerHTML = ` + + ${isLight ? 'Dark mode' : 'Light mode'} + `; + + if (persist) { + localStorage.setItem('reelo-theme', isLight ? 'light' : 'dark'); + } +} + +setTheme(localStorage.getItem('reelo-theme') === 'light' ? 'light' : 'dark', false); +elements.themeToggle.addEventListener('click', () => { + const nextTheme = document.documentElement.dataset.theme === 'light' ? 'dark' : 'light'; + setTheme(nextTheme); +}); + // ==================== Utility Functions ==================== function normalizeYouTubeUrl(url) { // Convert YouTube Shorts URLs to standard watch URLs