diff --git a/CHANGELOG.md b/CHANGELOG.md index b763a3d..eaef49b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Redesigned the Web UI into dedicated overview, login workspace, accounts, send console, logs, and settings views. - Moved the console styling and interaction scripts into `DouYinSparkFlow/webui/static/` with a denser admin-console layout and mobile drawer navigation. - Added safer confirmations for manual operations and localized the main Web UI feedback messages. +- Removed the redundant send-console navigation label while keeping send details available from contextual actions. +- Added a persistent sun/moon toggle for switching between light and dark console themes. - Added a project disclaimer to the root README. - Added a Linux Do friendly link and GitHub star history chart. - Refined the root README wording and structure for an open source project style. diff --git a/DouYinSparkFlow/webui/static/app.css b/DouYinSparkFlow/webui/static/app.css index 39fc7ff..25cdf44 100644 --- a/DouYinSparkFlow/webui/static/app.css +++ b/DouYinSparkFlow/webui/static/app.css @@ -1,8 +1,11 @@ :root { --bg: #f5f7fb; + --bg-start: #f8fafc; + --login-bg-end: #eef2f7; --surface: #ffffff; --surface-muted: #f8fafc; --surface-soft: #f1f5f9; + --surface-overlay: rgba(255, 255, 255, 0.92); --border: #e2e8f0; --border-strong: #cbd5e1; --text: #0f172a; @@ -11,14 +14,29 @@ --primary: #2563eb; --primary-hover: #1d4ed8; --primary-soft: #eff6ff; + --primary-border: #bfdbfe; + --on-primary: #ffffff; --success: #16a34a; --success-soft: #ecfdf3; + --success-text: #166534; + --success-border: #bbf7d0; --danger: #dc2626; --danger-soft: #fef2f2; + --danger-text: #991b1b; + --danger-border: #fecaca; --warning: #d97706; --warning-soft: #fff7ed; + --warning-text: #92400e; + --warning-border: #fed7aa; --info: #0284c7; --info-soft: #eff6ff; + --input-bg: #ffffff; + --frame-bg: #0f172a; + --frame-toolbar-bg: #111827; + --frame-text: #e5e7eb; + --frame-muted: #cbd5e1; + --focus-ring: rgba(37, 99, 235, 0.12); + --backdrop: rgba(15, 23, 42, 0.32); --shadow: 0 14px 34px rgba(15, 23, 42, 0.07); --shadow-soft: 0 8px 22px rgba(15, 23, 42, 0.05); --radius-lg: 18px; @@ -27,6 +45,49 @@ --sidebar-width: 248px; } +html[data-theme="dark"] { + color-scheme: dark; + --bg: #0b1120; + --bg-start: #111827; + --login-bg-end: #0b1120; + --surface: #111827; + --surface-muted: #0f172a; + --surface-soft: #1e293b; + --surface-overlay: rgba(15, 23, 42, 0.94); + --border: #263449; + --border-strong: #334155; + --text: #e5e7eb; + --text-muted: #94a3b8; + --text-soft: #64748b; + --primary: #3b82f6; + --primary-hover: #60a5fa; + --primary-soft: rgba(59, 130, 246, 0.16); + --primary-border: rgba(96, 165, 250, 0.42); + --success: #4ade80; + --success-soft: rgba(74, 222, 128, 0.14); + --success-text: #bbf7d0; + --success-border: rgba(74, 222, 128, 0.32); + --danger: #f87171; + --danger-soft: rgba(248, 113, 113, 0.14); + --danger-text: #fecaca; + --danger-border: rgba(248, 113, 113, 0.35); + --warning: #fbbf24; + --warning-soft: rgba(251, 191, 36, 0.14); + --warning-text: #fde68a; + --warning-border: rgba(251, 191, 36, 0.32); + --info: #38bdf8; + --info-soft: rgba(56, 189, 248, 0.14); + --input-bg: #0f172a; + --frame-bg: #020617; + --frame-toolbar-bg: #0f172a; + --frame-text: #e2e8f0; + --frame-muted: #94a3b8; + --focus-ring: rgba(96, 165, 250, 0.18); + --backdrop: rgba(2, 6, 23, 0.58); + --shadow: 0 18px 38px rgba(0, 0, 0, 0.28); + --shadow-soft: 0 12px 28px rgba(0, 0, 0, 0.22); +} + * { box-sizing: border-box; } @@ -39,7 +100,7 @@ body { body { color: var(--text); - background: linear-gradient(180deg, #f8fafc 0%, var(--bg) 100%); + background: linear-gradient(180deg, var(--bg-start) 0%, var(--bg) 100%); font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; font-size: 14px; } @@ -72,7 +133,7 @@ button { height: 100vh; padding: 22px 16px; border-right: 1px solid var(--border); - background: rgba(255, 255, 255, 0.92); + background: var(--surface-overlay); display: flex; flex-direction: column; gap: 24px; @@ -94,7 +155,7 @@ button { align-items: center; justify-content: center; background: var(--primary); - color: #fff; + color: var(--on-primary); font-weight: 800; box-shadow: 0 10px 20px rgba(37, 99, 235, 0.2); } @@ -466,7 +527,7 @@ button, border-radius: 10px; padding: 10px 14px; background: var(--primary); - color: #fff; + color: var(--on-primary); cursor: pointer; display: inline-flex; align-items: center; @@ -499,7 +560,7 @@ button:hover, .ghost-button { color: var(--text); - background: #fff; + background: var(--surface); } .ghost-button:hover { @@ -509,33 +570,33 @@ button:hover, .soft-button { color: var(--primary); background: var(--primary-soft); - border-color: #bfdbfe; + border-color: var(--primary-border); } .soft-button:hover { - color: #fff; + color: var(--on-primary); background: var(--primary); } .danger-button { color: var(--danger); background: var(--danger-soft); - border-color: #fecaca; + border-color: var(--danger-border); } .danger-button:hover { - color: #fff; + color: var(--on-primary); background: var(--danger); } .success-button { color: var(--success); background: var(--success-soft); - border-color: #bbf7d0; + border-color: var(--success-border); } .success-button:hover { - color: #fff; + color: var(--on-primary); background: var(--success); } @@ -546,6 +607,63 @@ button:hover, padding: 0; } +.theme-toggle { + min-height: 40px; + width: 72px; + min-width: 72px; + border: 1px solid var(--border); + border-radius: 999px; + padding: 4px; + background: var(--surface); + color: var(--text-muted); + box-shadow: var(--shadow-soft); + display: inline-grid; + grid-template-columns: 1fr 1fr; + align-items: center; + gap: 2px; +} + +.theme-toggle:hover { + background: var(--surface-muted); +} + +.theme-icon { + width: 30px; + height: 30px; + border-radius: 999px; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; + font-size: 15px; + transition: + background 0.16s ease, + color 0.16s ease; +} + +.theme-sun { + color: var(--warning); +} + +.theme-moon { + color: var(--text-soft); +} + +html[data-theme="light"] .theme-sun, +html:not([data-theme]) .theme-sun { + background: var(--warning); + color: var(--on-primary); +} + +html[data-theme="dark"] .theme-moon { + background: var(--primary); + color: var(--on-primary); +} + +html[data-theme="dark"] .theme-sun { + color: var(--warning); +} + .stack-form { display: grid; gap: 14px; @@ -587,7 +705,7 @@ select { min-height: 40px; border: 1px solid var(--border-strong); border-radius: 10px; - background: #fff; + background: var(--input-bg); color: var(--text); padding: 10px 12px; outline: none; @@ -597,7 +715,7 @@ input:focus, textarea:focus, select:focus { border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.12); + box-shadow: 0 0 0 3px var(--focus-ring); } textarea { @@ -659,33 +777,33 @@ textarea { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 12px 14px; - background: #fff; + background: var(--surface); box-shadow: var(--shadow-soft); } .flash.success { - color: #166534; + color: var(--success-text); background: var(--success-soft); - border-color: #bbf7d0; + border-color: var(--success-border); } .flash.warning { - color: #92400e; + color: var(--warning-text); background: var(--warning-soft); - border-color: #fed7aa; + border-color: var(--warning-border); } .flash.error { - color: #991b1b; + color: var(--danger-text); background: var(--danger-soft); - border-color: #fecaca; + border-color: var(--danger-border); } .table-shell { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-md); - background: #fff; + background: var(--surface); } table { @@ -752,7 +870,7 @@ tbody tr:last-child td { align-items: center; justify-content: center; flex: 0 0 40px; - color: #fff; + color: var(--on-primary); background: var(--primary); font-weight: 850; } @@ -815,7 +933,7 @@ tbody tr:last-child td { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius-sm); - background: #fff; + background: var(--surface); padding: 8px; display: grid; gap: 6px; @@ -832,7 +950,7 @@ tbody tr:last-child td { } .friend-option.selected { - border-color: #bfdbfe; + border-color: var(--primary-border); background: var(--primary-soft); } @@ -862,7 +980,7 @@ tbody tr:last-child td { border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; - background: #0f172a; + background: var(--frame-bg); } .browser-frame-toolbar { @@ -871,8 +989,8 @@ tbody tr:last-child td { justify-content: space-between; gap: 12px; padding: 12px; - background: #111827; - color: #e5e7eb; + background: var(--frame-toolbar-bg); + color: var(--frame-text); } .url-field { @@ -887,14 +1005,14 @@ tbody tr:last-child td { min-height: 520px; border: 0; display: block; - background: #0f172a; + background: var(--frame-bg); } .frame-help { - border-top: 1px solid rgba(255, 255, 255, 0.08); + border-top: 1px solid var(--border); padding: 12px 14px; - color: #cbd5e1; - background: #111827; + color: var(--frame-muted); + background: var(--frame-toolbar-bg); font-size: 13px; } @@ -1026,7 +1144,7 @@ tbody tr:last-child td { overflow: auto; border-radius: var(--radius-md); padding: 14px; - background: #0f172a; + background: var(--frame-bg); color: #dbeafe; font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; font-size: 12px; @@ -1048,7 +1166,11 @@ tbody tr:last-child td { display: grid; place-items: center; padding: 24px; - background: linear-gradient(180deg, #f8fafc 0%, #eef2f7 100%); + background: linear-gradient( + 180deg, + var(--bg-start) 0%, + var(--login-bg-end) 100% + ); } .login-card { @@ -1056,7 +1178,7 @@ tbody tr:last-child td { border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 28px; - background: #fff; + background: var(--surface); box-shadow: var(--shadow); } @@ -1097,7 +1219,7 @@ tbody tr:last-child td { height: 58px; padding: 10px 16px; border-bottom: 1px solid var(--border); - background: rgba(255, 255, 255, 0.94); + background: var(--surface-overlay); display: flex; align-items: center; justify-content: space-between; @@ -1119,7 +1241,7 @@ tbody tr:last-child td { position: fixed; inset: 0; z-index: 15; - background: rgba(15, 23, 42, 0.32); + background: var(--backdrop); } body.nav-open .sidebar-backdrop { diff --git a/DouYinSparkFlow/webui/static/app.js b/DouYinSparkFlow/webui/static/app.js index b943fb4..a6d49b9 100644 --- a/DouYinSparkFlow/webui/static/app.js +++ b/DouYinSparkFlow/webui/static/app.js @@ -1,3 +1,57 @@ +(() => { + const storageKey = "sparkflow-theme"; + const root = document.documentElement; + + const readStoredTheme = () => { + try { + return window.localStorage.getItem(storageKey); + } catch { + return null; + } + }; + + const writeStoredTheme = (theme) => { + try { + window.localStorage.setItem(storageKey, theme); + } catch { + // Ignore storage restrictions; the current page can still switch theme. + } + }; + + const preferredTheme = () => { + const stored = readStoredTheme(); + if (stored === "dark" || stored === "light") return stored; + return window.matchMedia?.("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + }; + + const applyTheme = (theme) => { + const normalized = theme === "dark" ? "dark" : "light"; + root.dataset.theme = normalized; + root.style.colorScheme = normalized; + const nextLabel = normalized === "dark" ? "切换白天模式" : "切换黑夜模式"; + document.querySelectorAll("[data-theme-toggle]").forEach((button) => { + button.setAttribute("aria-label", nextLabel); + button.setAttribute("title", nextLabel); + button.setAttribute( + "aria-pressed", + normalized === "dark" ? "true" : "false", + ); + }); + }; + + applyTheme(preferredTheme()); + + document.querySelectorAll("[data-theme-toggle]").forEach((button) => { + button.addEventListener("click", () => { + const next = root.dataset.theme === "dark" ? "light" : "dark"; + writeStoredTheme(next); + applyTheme(next); + }); + }); +})(); + (() => { const body = document.body; const navToggle = document.querySelector("[data-nav-toggle]"); diff --git a/DouYinSparkFlow/webui/templates/accounts.html b/DouYinSparkFlow/webui/templates/accounts.html index 5a9cf55..9b73fca 100644 --- a/DouYinSparkFlow/webui/templates/accounts.html +++ b/DouYinSparkFlow/webui/templates/accounts.html @@ -7,7 +7,6 @@ {% block topbar_actions %} 登录工作区 -发送控制台 {% endblock %} {% block content %} diff --git a/DouYinSparkFlow/webui/templates/base.html b/DouYinSparkFlow/webui/templates/base.html index 1713170..e2b13b2 100644 --- a/DouYinSparkFlow/webui/templates/base.html +++ b/DouYinSparkFlow/webui/templates/base.html @@ -22,6 +22,16 @@ ⚡ 自动续火花 +
@@ -31,7 +41,7 @@