Dark mode: portal (tokens/toggle) + dsh chat (vars + toggle)

This commit is contained in:
2026-09-03 12:32:55 +10:00
parent 4cf702cd5f
commit 485319812c
4 changed files with 81 additions and 10 deletions

View File

@@ -6,8 +6,16 @@
<title>DeepSeek Harness — {{ DSH_USER }}</title>
<link rel="stylesheet" href="/static/app.css">
<style>
:root {
--canvas-soft: #f7f7f7; --surface: #ffffff; --surface-2: #f2f2f1; --hairline: #e6e6e6;
--ink: #111111; --ink-secondary: #333333; --ink-muted: #666666; --ink-faint: #999999; --primary: #0075de;
}
[data-theme="dark"] {
--canvas-soft: #141518; --surface: #1c1e22; --surface-2: #24262c; --hairline: #33363d;
--ink: #f5f6f7; --ink-secondary: #dcdee2; --ink-muted: #a9adb6; --ink-faint: #727680; --primary: #3d8be0;
}
html, body { height: 100%; margin: 0; }
body { display: flex; flex-direction: column; }
body { display: flex; flex-direction: column; background: var(--surface, #fff); color: var(--ink, #111); }
header.top { flex: none; }
.app { display: flex; flex: 1; min-height: 0; }
#sidebar {
@@ -15,7 +23,7 @@
display: flex; flex-direction: column; background: var(--canvas-soft, #f7f7f7);
}
#sidebar h2 { font: 600 12px/1.3 var(--font-family, sans-serif); color: var(--ink-faint, #999); margin: 12px 12px 6px; }
#newBtn, #dlBtn { margin: 4px 12px; padding: 7px 10px; border: 1px solid #ddd; border-radius: 8px; background: #fff; cursor: pointer; text-align: left; }
#newBtn, #dlBtn { margin: 4px 12px; padding: 7px 10px; border: 1px solid var(--hairline, #e6e6e6); border-radius: 8px; background: #fff; cursor: pointer; text-align: left; }
#sessions { list-style: none; margin: 0; padding: 0 8px; overflow: auto; flex: 1; }
#sessions li {
display: flex; align-items: center; gap: 6px; padding: 7px 8px; margin: 2px 0;
@@ -30,11 +38,11 @@
.bubble { position: relative; white-space: pre-wrap; }
.bubble .copy {
position: absolute; top: 4px; right: 4px; display: none;
font-size: 11px; padding: 2px 6px; border: 1px solid #ddd; border-radius: 6px; background: #fff; cursor: pointer; color: #555;
font-size: 11px; padding: 2px 6px; border: 1px solid var(--hairline, #e6e6e6); border-radius: 6px; background: #fff; cursor: pointer; color: #555;
}
.msg:hover .bubble .copy { display: block; }
.modelrow { display: flex; gap: 8px; align-items: center; }
.modelrow select { border: 1px solid #ddd; border-radius: 8px; padding: 6px 8px; font-size: 13px; }
.modelrow select { border: 1px solid var(--hairline, #e6e6e6); border-radius: 8px; padding: 6px 8px; font-size: 13px; }
.modelrow label { font-size: 12px; color: #777; }
@@ -42,7 +50,7 @@
.composer { display: flex; flex-direction: column; gap: 8px; padding: 8px 12px; }
#input {
width: 100%; min-height: 2.9em; padding: 9px 11px; box-sizing: border-box;
border: 1px solid #ddd; border-radius: 8px;
border: 1px solid var(--hairline, #e6e6e6); border-radius: 8px;
font: 15px/1.4 var(--font-family, sans-serif); resize: vertical;
}
.send-row { display: flex; justify-content: flex-end; }
@@ -56,10 +64,10 @@
#toolsBody { padding: 0 12px 10px; }
#toolsBody.hidden { display: none; }
.tools-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
.tools-row input[type=text], .tools-row input[type=file] { flex: 2 1 170px; border: 1px solid #ddd; border-radius: 8px; padding: 6px 10px; font-size: 13px; }
.tools-row button { flex: 0 0 auto; border: 1px solid #ddd; border-radius: 8px; padding: 6px 10px; cursor: pointer; background: #fff; }
.tools-row input[type=text], .tools-row input[type=file] { flex: 2 1 170px; border: 1px solid var(--hairline, #e6e6e6); border-radius: 8px; padding: 6px 10px; font-size: 13px; }
.tools-row button { flex: 0 0 auto; border: 1px solid var(--hairline, #e6e6e6); border-radius: 8px; padding: 6px 10px; cursor: pointer; background: #fff; }
.modelrow { display: flex; gap: 8px; align-items: center; }
.modelrow select { border: 1px solid #ddd; border-radius: 8px; padding: 5px 8px; font-size: 13px; }
.modelrow select { border: 1px solid var(--hairline, #e6e6e6); border-radius: 8px; padding: 5px 8px; font-size: 13px; }
@media (max-width: 720px) {
#menuBtn { display: inline-flex !important; }
#sidebar {
@@ -79,7 +87,8 @@
</head>
<body>
<header class="top" style="display:flex;align-items:center;gap:8px;padding:10px 14px">
<button id="menuBtn" type="button" aria-label="Conversations" title="Conversations" style="display:none;align-items:center;justify-content:center;background:none;border:1px solid #ddd;border-radius:8px;padding:4px 9px;font-size:17px;cursor:pointer;line-height:1">☰</button>
<button id="menuBtn" type="button" aria-label="Conversations" title="Conversations" style="display:none;align-items:center;justify-content:center;background:none;border:1px solid var(--hairline, #e6e6e6);border-radius:8px;padding:4px 9px;font-size:17px;cursor:pointer;line-height:1">☰</button>
<button id="themeBtn" type="button" title="Toggle dark mode" style="background:none;border:1px solid var(--hairline, #e6e6e6);border-radius:8px;padding:4px 8px;font-size:16px;cursor:pointer;color:var(--ink, #111)">🌙</button>
<div class="logo">DeepSeek Harness</div>
<div class="who" style="margin-left:auto">{{ DSH_SLOT }} · <span class="model">{{ DSH_MODEL }}</span></div>
</header>
@@ -301,6 +310,23 @@
});
fetchModels(); loadSessions();
// dark mode toggle (dsh standalone page)
(function () {
var root = document.documentElement;
var saved = null; try { saved = localStorage.getItem('dshTheme'); } catch(_) {}
if (saved === 'dark' || (!saved && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)) root.setAttribute('data-theme', 'dark');
var b = document.getElementById('themeBtn');
if (b) {
function sync(){ b.textContent = root.getAttribute('data-theme') === 'dark' ? '☀️' : '🌙'; }
b.addEventListener('click', function () {
if (root.getAttribute('data-theme') === 'dark') { root.removeAttribute('data-theme'); try{localStorage.setItem('dshTheme','light');}catch(_){} }
else { root.setAttribute('data-theme','dark'); try{localStorage.setItem('dshTheme','dark');}catch(_){} }
sync();
});
sync();
}
})();
</script>
</body>
</html>

View File

@@ -71,7 +71,7 @@ a:hover { text-decoration: underline; }
padding: 10px 12px;
font: var(--type-body-sm);
color: var(--ink);
border: 1px solid rgb(221, 221, 221);
border: 1px solid var(--hairline);
border-radius: var(--rounded-xs);
background: var(--surface);
}
@@ -340,3 +340,8 @@ button.button, input[type="submit"].button { font-family: inherit; }
.page { padding: var(--space-lg) var(--space-md); }
.greeting { font: var(--type-heading-2); }
}
/* ---------- Dark-mode tweaks (hardcoded colours that need a dark variant) ---------- */
[data-theme="dark"] .form-error { background: #3a2424; color: #ffb4ab; border-color: #7a4e4c; }
[data-theme="dark"] .tool-icon { color: #1c1e22; }
[data-theme="dark"] .category-pill { background: var(--surface-2); }

View File

@@ -14,6 +14,7 @@
/* --- Surface --- */
--canvas-soft: #f6f5f4;
--surface: #ffffff;
--surface-2: #f2f2f1;
--hairline: #e6e6e6;
/* --- Text --- */
@@ -86,5 +87,23 @@
--rounded-full: 9999px;
}
/* Dark mode — flip the semantic tokens only (components use var(--…)). */
[data-theme="dark"] {
--canvas-soft: #141518;
--surface: #1c1e22;
--surface-2: #24262c;
--hairline: #33363d;
--ink: #f5f6f7;
--ink-secondary: #dcdee2;
--ink-muted: #a9adb6;
--ink-faint: #727680;
--primary: #3d8be0;
--primary-active: #5d9ff0;
--on-primary: #ffffff;
--secondary: #10142a;
--shadow-level-1: rgba(0, 0, 0, 0.45) 0 1px 3px;
--shadow-level-2: rgba(0, 0, 0, 0.55) 0 5px 22px;
}
/* Numerals: enable OpenType lnum */
html { font-feature-settings: "lnum" 1; }

View File

@@ -25,6 +25,7 @@
<span>{{ user.full_name }}</span>
</div>
<a href="/account/password" class="button-utility" title="Change password">Password</a>
<button type="button" id="themeToggle" class="button-utility" title="Toggle dark mode" aria-label="Toggle dark mode">🌙</button>
<a href="/logout" class="button-utility">Sign out</a>
</div>
</nav>
@@ -32,5 +33,25 @@
<main>
{% block content %}{% endblock %}
</main>
<script>
(function () {
var root = document.documentElement;
var saved = null;
try { saved = localStorage.getItem('fhlTheme'); } catch (_) {}
var dark = saved === 'dark' || (!saved && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
if (dark) root.setAttribute('data-theme', 'dark');
function sync() {
var b = document.getElementById('themeToggle');
if (b) b.textContent = root.getAttribute('data-theme') === 'dark' ? '☀️' : '🌙';
}
var t = document.getElementById('themeToggle');
if (t) t.addEventListener('click', function () {
if (root.getAttribute('data-theme') === 'dark') { root.removeAttribute('data-theme'); try { localStorage.setItem('fhlTheme','light'); } catch(_){} }
else { root.setAttribute('data-theme','dark'); try { localStorage.setItem('fhlTheme','dark'); } catch(_){} }
sync();
});
sync();
})();
</script>
</body>
</html>