diff --git a/app/static/app.js b/app/static/app.js index 9265b34..0552c4d 100644 --- a/app/static/app.js +++ b/app/static/app.js @@ -1,5 +1,6 @@ (function () { const STORAGE_KEY = "rename_mvp_session_id"; + const THEME_STORAGE_KEY = "rename_mvp_theme"; const state = { sessionId: initSessionId(), @@ -29,6 +30,7 @@ const el = { sessionMeta: document.getElementById("sessionMeta"), outputBox: document.getElementById("outputBox"), + themeToggleBtn: document.getElementById("themeToggleBtn"), searchInput: document.getElementById("searchInput"), searchDropdownBtn: document.getElementById("searchDropdownBtn"), searchCombobox: document.getElementById("searchCombobox"), @@ -92,6 +94,33 @@ return created; } + function getStoredTheme() { + const stored = localStorage.getItem(THEME_STORAGE_KEY); + if (stored === "light" || stored === "dark") return stored; + return "dark"; + } + + function applyTheme(theme) { + const normalized = theme === "light" ? "light" : "dark"; + document.documentElement.setAttribute("data-theme", normalized); + localStorage.setItem(THEME_STORAGE_KEY, normalized); + if (el.themeToggleBtn) { + const isDark = normalized === "dark"; + // Icon represents switch action: dark -> light (sun), light -> dark (moon). + el.themeToggleBtn.textContent = isDark ? "☀️" : "🌙"; + el.themeToggleBtn.setAttribute( + "aria-label", + isDark ? "Switch to light theme" : "Switch to dark theme" + ); + el.themeToggleBtn.title = isDark ? "Switch to light theme" : "Switch to dark theme"; + } + } + + function toggleTheme() { + const current = document.documentElement.getAttribute("data-theme") === "light" ? "light" : "dark"; + applyTheme(current === "dark" ? "light" : "dark"); + } + function q(path) { return path.includes("?") ? `${path}&session_id=${encodeURIComponent(state.sessionId)}` @@ -834,6 +863,9 @@ } function bindEvents() { + if (el.themeToggleBtn) { + el.themeToggleBtn.addEventListener("click", toggleTheme); + } el.searchBtn.addEventListener("click", () => withHandler(doSearch, el.searchBtn)); el.searchInput.addEventListener("focus", openRememberedDropdown); el.searchInput.addEventListener("click", openRememberedDropdown); @@ -903,6 +935,7 @@ } async function init() { + applyTheme(getStoredTheme()); el.sessionMeta.textContent = `session_id: ${state.sessionId}`; el.modalRecursiveInput.checked = true; renderSelectedSeriesDetails(); diff --git a/app/static/styles.css b/app/static/styles.css index 4afc7c9..011f04d 100644 --- a/app/static/styles.css +++ b/app/static/styles.css @@ -2,12 +2,74 @@ box-sizing: border-box; } +:root { + --bg-page: #111827; + --text-primary: #e5e7eb; + --text-muted: #94a3b8; + --topbar-bg: #020617; + --topbar-text: #e2e8f0; + --surface: #1f2937; + --surface-elevated: #0f172a; + --surface-subtle: #1e293b; + --border: #334155; + --border-soft: #475569; + --divider: #334155; + --button-primary-bg: #2563eb; + --button-primary-border: #2563eb; + --button-primary-text: #ffffff; + --button-secondary-bg: #334155; + --button-secondary-border: #475569; + --button-secondary-text: #e2e8f0; + --button-secondary-hover-bg: #3b4a61; + --badge-bg: #0b3a6e; + --badge-border: #1d4f85; + --badge-text: #dbeafe; + --list-selected-bg: #1e3a8a; + --season-header-bg: #1e293b; + --season-header-border: #334155; + --danger-text: #f87171; + --overlay-bg: rgba(2, 6, 23, 0.7); + --shadow-lg: 0 8px 22px rgba(2, 6, 23, 0.45); + --series-image-bg: #0b1220; +} + +[data-theme="light"] { + --bg-page: #f2f4f8; + --text-primary: #1a1f2b; + --text-muted: #64748b; + --topbar-bg: #0f172a; + --topbar-text: #e2e8f0; + --surface: #ffffff; + --surface-elevated: #ffffff; + --surface-subtle: #f8fafc; + --border: #d7dee9; + --border-soft: #c3cedf; + --divider: #e4eaf2; + --button-primary-bg: #0f172a; + --button-primary-border: #0f172a; + --button-primary-text: #ffffff; + --button-secondary-bg: #e2e8f0; + --button-secondary-border: #c3cedf; + --button-secondary-text: #1a1f2b; + --button-secondary-hover-bg: #eef2f7; + --badge-bg: #dbeafe; + --badge-border: #bfdbfe; + --badge-text: #0f172a; + --list-selected-bg: #e0f2fe; + --season-header-bg: #eef2ff; + --season-header-border: #dbe4fb; + --danger-text: #b91c1c; + --overlay-bg: rgba(2, 6, 23, 0.55); + --shadow-lg: 0 8px 22px rgba(15, 23, 42, 0.12); + --series-image-bg: #f8fafc; +} + body { margin: 0; padding: 0; font-family: "Segoe UI", Tahoma, sans-serif; - background: #f2f4f8; - color: #1a1f2b; + background: var(--bg-page); + color: var(--text-primary); height: 100vh; overflow: hidden; display: flex; @@ -19,8 +81,8 @@ body { justify-content: space-between; align-items: center; padding: 12px 16px; - background: #0f172a; - color: #e2e8f0; + background: var(--topbar-bg); + color: var(--topbar-text); } .topbar h1 { @@ -32,6 +94,26 @@ body { font-size: 12px; } +.topbar-right { + display: flex; + align-items: center; + gap: 10px; +} + +.theme-toggle-btn { + border: 1px solid var(--button-secondary-border); + background: var(--button-secondary-bg); + color: var(--button-secondary-text); + border-radius: 999px; + width: 34px; + height: 34px; + padding: 0; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; +} + .grid { display: grid; grid-template-columns: repeat(4, minmax(280px, 1fr)); @@ -44,8 +126,8 @@ body { } .panel { - background: #ffffff; - border: 1px solid #d7dee9; + background: var(--surface); + border: 1px solid var(--border); border-radius: 8px; padding: 10px; min-height: 420px; @@ -130,10 +212,10 @@ body { right: 0; top: calc(100% - 6px); z-index: 20; - background: #ffffff; - border: 1px solid #d7dee9; + background: var(--surface-elevated); + border: 1px solid var(--border); border-radius: 6px; - box-shadow: 0 8px 22px rgba(15, 23, 42, 0.12); + box-shadow: var(--shadow-lg); padding: 6px; } @@ -157,7 +239,7 @@ body { #rememberedDropdownList .remembered-remove-btn { border: none; background: transparent; - color: #64748b; + color: var(--text-muted); width: 22px; height: 22px; line-height: 1; @@ -168,8 +250,8 @@ body { } #rememberedDropdownList .remembered-remove-btn:hover { - background: #eef2f7; - color: #0f172a; + background: var(--button-secondary-hover-bg); + color: var(--text-primary); } .stack { @@ -186,25 +268,27 @@ body { input[type="text"], select { - border: 1px solid #c3cedf; + border: 1px solid var(--border-soft); border-radius: 6px; padding: 6px 8px; min-width: 160px; + background: var(--surface-subtle); + color: var(--text-primary); } button { - border: 1px solid #0f172a; - background: #0f172a; - color: #ffffff; + border: 1px solid var(--button-primary-border); + background: var(--button-primary-bg); + color: var(--button-primary-text); border-radius: 6px; padding: 6px 10px; cursor: pointer; } button.secondary { - background: #e2e8f0; - color: #1a1f2b; - border-color: #c3cedf; + background: var(--button-secondary-bg); + color: var(--button-secondary-text); + border-color: var(--button-secondary-border); } .list { @@ -213,8 +297,9 @@ button.secondary { padding: 0; max-height: 260px; overflow: auto; - border: 1px solid #e4eaf2; + border: 1px solid var(--divider); border-radius: 6px; + background: var(--surface-elevated); } .linked-list-wrap { @@ -256,22 +341,22 @@ button.secondary { display: inline-block; font-size: 11px; font-weight: 700; - color: #0f172a; - background: #dbeafe; - border: 1px solid #bfdbfe; + color: var(--badge-text); + background: var(--badge-bg); + border: 1px solid var(--badge-border); border-radius: 999px; padding: 1px 6px; margin-right: 6px; } .list li.selected { - background: #e0f2fe; + background: var(--list-selected-bg); } .list li.season-header { - background: #eef2ff; - border-bottom: 1px solid #dbe4fb; - color: #1e293b; + background: var(--season-header-bg); + border-bottom: 1px solid var(--season-header-border); + color: var(--text-primary); font-weight: 700; justify-content: flex-start; padding: 8px; @@ -280,8 +365,8 @@ button.secondary { .panel-footer { position: sticky; bottom: 0; - background: #ffffff; - border-top: 1px solid #e4eaf2; + background: var(--surface); + border-top: 1px solid var(--divider); padding-top: 8px; margin-top: 10px; display: flex; @@ -297,14 +382,14 @@ button.secondary { } .mismatch { - color: #b91c1c; + color: var(--danger-text); font-weight: 700; } .modal { position: fixed; inset: 0; - background: rgba(2, 6, 23, 0.55); + background: var(--overlay-bg); display: flex; align-items: center; justify-content: center; @@ -318,8 +403,8 @@ button.secondary { .modal-card { width: min(1400px, 90vw); height: 80vh; - background: #ffffff; - border: 1px solid #d7dee9; + background: var(--surface); + border: 1px solid var(--border); border-radius: 10px; padding: 12px; display: flex; @@ -377,7 +462,7 @@ button.secondary { margin-top: 10px; margin-bottom: 0; justify-content: flex-end; - border-top: 1px solid #e4eaf2; + border-top: 1px solid var(--divider); padding-top: 10px; } @@ -388,7 +473,7 @@ button.secondary { .settings-section h4 { margin: 0 0 8px; font-size: 14px; - color: #1e293b; + color: var(--text-primary); } .settings-field { @@ -400,7 +485,7 @@ button.secondary { .settings-field label { font-size: 12px; - color: #64748b; + color: var(--text-muted); } .settings-field select { @@ -422,7 +507,7 @@ button.secondary { align-items: center; gap: 8px; font-size: 13px; - color: #334155; + color: var(--text-primary); } .settings-actions { @@ -434,16 +519,16 @@ button.secondary { #panelSelectedEpisodes .panel-footer button:last-child, #panelSelectedFiles .panel-footer button:first-child, #panelSelectedFiles .panel-footer button:last-child { - border-color: #0b3a6e; - background: #0b3a6e; - color: #ffffff; + border-color: var(--button-primary-border); + background: var(--button-primary-bg); + color: var(--button-primary-text); } .list li { display: flex; justify-content: space-between; gap: 8px; - border-bottom: 1px solid #edf1f7; + border-bottom: 1px solid var(--divider); padding: 6px 8px; font-size: 13px; } @@ -474,7 +559,7 @@ button.secondary { } .muted { - color: #475569; + color: var(--text-muted); font-size: 12px; margin-bottom: 8px; } @@ -503,7 +588,7 @@ button.secondary { } .series-details { - border-top: 1px solid #e4eaf2; + border-top: 1px solid var(--divider); padding-top: 10px; } @@ -522,32 +607,32 @@ button.secondary { display: block; margin: 0; border-radius: 6px; - border: 1px solid #d7dee9; - background: #f8fafc; + border: 1px solid var(--border); + background: var(--series-image-bg); } .series-meta { font-size: 12px; - color: #334155; + color: var(--text-primary); display: grid; gap: 4px; margin-bottom: 8px; } .series-meta span:first-child { - color: #64748b; + color: var(--text-muted); } .series-overview { margin: 0 0 8px; font-size: 12px; line-height: 1.35; - color: #1e293b; + color: var(--text-primary); } .series-link { font-size: 12px; - color: #64748b; + color: var(--text-muted); text-decoration: none; } @@ -557,13 +642,14 @@ button.secondary { #outputBox { margin: 0; - background: #0b1220; - color: #dbeafe; + background: var(--surface-subtle); + color: var(--text-primary); border-radius: 6px; padding: 10px; max-height: 320px; overflow: auto; font-size: 12px; + border: 1px solid var(--border); } .debug-page { diff --git a/app/templates/debug.html b/app/templates/debug.html index ac885e6..f67ad57 100644 --- a/app/templates/debug.html +++ b/app/templates/debug.html @@ -4,6 +4,16 @@