Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions internal/panel/assets/css/components/settings.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* Settings page chrome. Cards stack vertically with consistent
spacing; theme picker uses a radiogroup of pill cards. Pulls every
dimension from tokens — the cards themselves swap palette when the
theme variant changes. */

.settings-card {
background: var(--bg-elev-1);
border-radius: var(--radius-md);
padding: var(--space-6);
margin: 0 0 var(--space-5);
}

.settings-card h2 {
font-size: var(--text-md);
font-weight: var(--w-medium);
margin: 0 0 var(--space-4);
color: var(--text-1);
}

.settings-card dl {
display: grid;
grid-template-columns: 110px 1fr;
gap: var(--space-2) var(--space-4);
margin: 0 0 var(--space-4);
font-size: var(--text-sm);
}

.settings-card dt {
color: var(--text-3);
text-transform: uppercase;
letter-spacing: 0.06em;
font-size: var(--text-xs);
padding-top: 2px;
}

.settings-card dd {
margin: 0;
color: var(--text-1);
}

.settings-hint {
margin: 0 0 var(--space-4);
color: var(--text-3);
font-size: var(--text-sm);
}

.theme-options {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-3);
}

@media (max-width: 700px) {
.theme-options {
grid-template-columns: 1fr;
}
}

.theme-option {
display: flex;
flex-direction: column;
gap: var(--space-1);
padding: var(--space-4);
background: var(--bg-elev-2);
border: 1px solid var(--divider);
border-radius: var(--radius-sm);
cursor: pointer;
user-select: none;
transition: border-color var(--duration-fast) var(--ease),
background var(--duration-fast) var(--ease);
}

.theme-option:hover {
border-color: var(--text-3);
}

.theme-option.is-active {
border-color: var(--accent);
background: var(--bg-elev-1);
}

.theme-option input[type="radio"] {
position: absolute;
opacity: 0;
pointer-events: none;
}

.theme-option-label {
font-size: var(--text-sm);
font-weight: var(--w-medium);
color: var(--text-1);
}

.theme-option-hint {
font-size: var(--text-xs);
color: var(--text-3);
}
40 changes: 39 additions & 1 deletion internal/panel/assets/css/tokens.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Other CSS layers reference these vars, never literals. */

:root {
/* Dark palette ---------------------------------------------------- */
/* Dark palette (default) ----------------------------------------- */
--bg: #0f1117;
--bg-elev-1: #1a1d27;
--bg-elev-2: #232733;
Expand Down Expand Up @@ -78,3 +78,41 @@
--agent-hermes: #5be0d6;
--agent-hermes-soft: #5be0d626;
}

/* Light palette ---------------------------------------------------- */
/* Applied when the user picks Light explicitly OR when the user is
on System and the OS reports prefers-color-scheme: light. The
palette mirrors the dark one (bg → elev-1 → elev-2 = depth steps,
text-1 strongest → text-3 quietest, accent + softs) so every
component picks up the swap with no per-rule changes. */
[data-theme="light"] {
--bg: #fafbfc;
--bg-elev-1: #f1f3f7;
--bg-elev-2: #e3e7ee;
--text-1: #1c1f29;
--text-2: #4d5468;
--text-3: #7d8497;
--accent: #4a5af0;
--accent-soft: #4a5af029;
--ok: #1f9d55;
--danger: #d63648;
--divider: #d8dde6;
--warn: #c48415;
}

@media (prefers-color-scheme: light) {
[data-theme="system"] {
--bg: #fafbfc;
--bg-elev-1: #f1f3f7;
--bg-elev-2: #e3e7ee;
--text-1: #1c1f29;
--text-2: #4d5468;
--text-3: #7d8497;
--accent: #4a5af0;
--accent-soft: #4a5af029;
--ok: #1f9d55;
--danger: #d63648;
--divider: #d8dde6;
--warn: #c48415;
}
}
1 change: 1 addition & 0 deletions internal/panel/assets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
@import url("css/components/dashboard.css");
@import url("css/components/agent-badge.css");
@import url("css/components/active-filters.css");
@import url("css/components/settings.css");

/* Layout */
.app {
Expand Down
13 changes: 13 additions & 0 deletions internal/panel/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@
<head>
<meta charset="utf-8">
<title>{{.Title}} · prosa</title>
<script>
/* Apply theme BEFORE stylesheets load to avoid FOUC. Persists in
localStorage; unknown / missing → "dark" (the historical default). */
(function () {
try {
var t = localStorage.getItem("prosa-theme");
if (t !== "light" && t !== "system") t = "dark";
document.documentElement.dataset.theme = t;
} catch (_) {
document.documentElement.dataset.theme = "dark";
}
})();
</script>
<link rel="stylesheet" href="{{assetPath "style.css"}}">
<script src="{{assetPath "htmx.min.js"}}"></script>
</head>
Expand Down
33 changes: 33 additions & 0 deletions internal/panel/templates/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,37 @@ <h2>Logged in as</h2>
<button class="btn" type="submit">Log out</button>
</form>
</section>

<section class="settings-card"
x-data="{
theme: localStorage.getItem('prosa-theme') || 'dark',
apply(t) {
this.theme = t;
localStorage.setItem('prosa-theme', t);
document.documentElement.dataset.theme = t;
}
}">
<h2>Appearance</h2>
<p class="settings-hint">Applies immediately. Persists across reloads (per-browser).</p>
<div class="theme-options" role="radiogroup" aria-label="Theme">
<label class="theme-option" :class="{ 'is-active': theme === 'system' }">
<input type="radio" name="theme" value="system"
:checked="theme === 'system'" @change="apply('system')">
<span class="theme-option-label">System</span>
<span class="theme-option-hint">Follow OS preference</span>
</label>
<label class="theme-option" :class="{ 'is-active': theme === 'light' }">
<input type="radio" name="theme" value="light"
:checked="theme === 'light'" @change="apply('light')">
<span class="theme-option-label">Light</span>
<span class="theme-option-hint">Always light</span>
</label>
<label class="theme-option" :class="{ 'is-active': theme === 'dark' }">
<input type="radio" name="theme" value="dark"
:checked="theme === 'dark'" @change="apply('dark')">
<span class="theme-option-label">Dark</span>
<span class="theme-option-hint">Always dark (default)</span>
</label>
</div>
</section>
{{end}}
Loading