This commit is contained in:
27
src/app.css
27
src/app.css
@@ -19,6 +19,33 @@
|
||||
--teal: #007d79;
|
||||
--gray-tag: #e0e0e0;
|
||||
--focus: #0f62fe;
|
||||
/* The top bar stays dark in both themes; a dedicated token keeps it
|
||||
independent of --text, which flips between light and dark modes. */
|
||||
--header-bg: #161616;
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
:root[data-theme='dark'] {
|
||||
--bg: #161616;
|
||||
--layer: #262626;
|
||||
--layer-hover: #333333;
|
||||
--border: #393939;
|
||||
--border-strong: #6f6f6f;
|
||||
--text: #f4f4f4;
|
||||
--text-secondary: #c6c6c6;
|
||||
--text-helper: #a8a8a8;
|
||||
--interactive: #4589ff;
|
||||
--interactive-hover: #6ea6ff;
|
||||
--danger: #fa4d56;
|
||||
--success: #42be65;
|
||||
--warning-bg: #302915;
|
||||
--warning: #f1c21b;
|
||||
--purple: #a56eff;
|
||||
--teal: #3ddbd9;
|
||||
--gray-tag: #393939;
|
||||
--focus: #4589ff;
|
||||
--header-bg: #0b0b0b;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
* {
|
||||
|
||||
12
src/app.html
12
src/app.html
@@ -4,6 +4,18 @@
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script>
|
||||
// Apply the saved (or system) theme before first paint to avoid a flash.
|
||||
(function () {
|
||||
try {
|
||||
var t = localStorage.getItem('theme');
|
||||
if (t !== 'light' && t !== 'dark') {
|
||||
t = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
}
|
||||
document.documentElement.dataset.theme = t;
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
|
||||
73
src/lib/components/ThemeToggle.svelte
Normal file
73
src/lib/components/ThemeToggle.svelte
Normal file
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
type Theme = 'light' | 'dark';
|
||||
let theme = $state<Theme>('light');
|
||||
|
||||
onMount(() => {
|
||||
theme = (document.documentElement.dataset.theme as Theme) === 'dark' ? 'dark' : 'light';
|
||||
});
|
||||
|
||||
function toggle() {
|
||||
theme = theme === 'dark' ? 'light' : 'dark';
|
||||
document.documentElement.dataset.theme = theme;
|
||||
try {
|
||||
localStorage.setItem('theme', theme);
|
||||
} catch {
|
||||
// storage may be unavailable (private mode); toggle still works for the session
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="theme-toggle"
|
||||
type="button"
|
||||
onclick={toggle}
|
||||
aria-label={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}
|
||||
title={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'}
|
||||
>
|
||||
{#if theme === 'dark'}
|
||||
<!-- Sun: shown in dark mode to switch to light -->
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
|
||||
<circle cx="12" cy="12" r="4.2" fill="currentColor" />
|
||||
<g stroke="currentColor" stroke-width="1.6" stroke-linecap="round">
|
||||
<line x1="12" y1="2" x2="12" y2="4.6" />
|
||||
<line x1="12" y1="19.4" x2="12" y2="22" />
|
||||
<line x1="2" y1="12" x2="4.6" y2="12" />
|
||||
<line x1="19.4" y1="12" x2="22" y2="12" />
|
||||
<line x1="4.9" y1="4.9" x2="6.7" y2="6.7" />
|
||||
<line x1="17.3" y1="17.3" x2="19.1" y2="19.1" />
|
||||
<line x1="4.9" y1="19.1" x2="6.7" y2="17.3" />
|
||||
<line x1="17.3" y1="6.7" x2="19.1" y2="4.9" />
|
||||
</g>
|
||||
</svg>
|
||||
{:else}
|
||||
<!-- Moon: shown in light mode to switch to dark -->
|
||||
<svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
|
||||
<path
|
||||
d="M20.5 14.2A8.2 8.2 0 0 1 9.8 3.5a8.2 8.2 0 1 0 10.7 10.7Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<style>
|
||||
.theme-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
border: 1px solid #6f6f6f;
|
||||
padding: 0;
|
||||
}
|
||||
.theme-toggle:hover {
|
||||
background: #353535;
|
||||
}
|
||||
.theme-toggle svg {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { TOOLS } from '$lib/defaults';
|
||||
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
|
||||
</script>
|
||||
|
||||
<svelte:head><title>Project SDE | Meeting Toolkit</title></svelte:head>
|
||||
@@ -7,6 +8,7 @@
|
||||
<header>
|
||||
<div class="brand"><strong>Project SDE</strong> <span>| Meeting Toolkit</span></div>
|
||||
<div class="spacer"></div>
|
||||
<ThemeToggle />
|
||||
</header>
|
||||
|
||||
<main>
|
||||
@@ -34,7 +36,7 @@
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 30;
|
||||
background: var(--text);
|
||||
background: var(--header-bg);
|
||||
color: #fff;
|
||||
padding: 0 24px;
|
||||
display: flex;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { toast } from '$lib/toast.svelte';
|
||||
import Toast from '$lib/components/Toast.svelte';
|
||||
import SyncBadge from '$lib/components/SyncBadge.svelte';
|
||||
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
|
||||
import {
|
||||
DECISION_OWNERS,
|
||||
DECISION_STATUSES,
|
||||
@@ -223,6 +224,7 @@
|
||||
<SyncBadge status={ws.status} updatedAt={ws.updatedAt} />
|
||||
<button class="hdr-btn" onclick={reset}>Reset all</button>
|
||||
<button class="hdr-btn primary" onclick={exportSummary}>Export meeting summary</button>
|
||||
<ThemeToggle />
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
@@ -407,7 +409,7 @@
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 30;
|
||||
background: var(--text);
|
||||
background: var(--header-bg);
|
||||
color: #fff;
|
||||
padding: 0 24px;
|
||||
display: flex;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { toast } from '$lib/toast.svelte';
|
||||
import Toast from '$lib/components/Toast.svelte';
|
||||
import SyncBadge from '$lib/components/SyncBadge.svelte';
|
||||
import ThemeToggle from '$lib/components/ThemeToggle.svelte';
|
||||
import { PEOPLE, SUGGESTIONS } from '$lib/defaults/workshop';
|
||||
import { suggestBreadcrumb, DOMAIN_OPTIONS } from '$lib/breadcrumbs';
|
||||
import type { Breadcrumb, Cluster, Problem, WorkshopState } from '$lib/types';
|
||||
@@ -359,6 +360,7 @@
|
||||
<button class="hdr-btn" onclick={saveJson}>Save JSON</button>
|
||||
<button class="hdr-btn" onclick={reset}>Reset</button>
|
||||
<button class="hdr-btn primary" onclick={exportSummary}>Export summary</button>
|
||||
<ThemeToggle />
|
||||
<input type="file" accept=".json,application/json" bind:this={fileInput} onchange={loadJson} style="display:none" />
|
||||
</header>
|
||||
|
||||
@@ -605,7 +607,7 @@
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 30;
|
||||
background: var(--text);
|
||||
background: var(--header-bg);
|
||||
color: #fff;
|
||||
padding: 0 24px;
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user