Skip to content

Commit db218b9

Browse files
NotYuShengclaude
andauthored
feat: dark mode with light/dark/system toggle (#178)
* feat: add dark mode with light/dark/system toggle - Add `themeSlice` to Zustand store with `themeMode: 'light' | 'dark' | 'system'` persisted to localStorage; cycles light → dark → system on click - `MainLayout` applies `data-theme` attribute to `<html>`, listens to `prefers-color-scheme` in system mode for live OS-level updates - Header toggle button shows `bi-sun` / `bi-moon-stars` / `bi-circle-half` with tooltip describing the current mode and next action - Define `--tp-*` CSS token set in `index.css`; dark block placed after `:root` so it correctly wins the cascade - Override all SGDS `--sgds-*` component-local variables directly on the component selector (card, table, list-group, modal, dropdown, nav-tabs, popover, pagination, input-group-text) — inheriting from `html` is not sufficient because SGDS re-declares them locally - Add `tp-stream-pane`, `tp-stat-box`, `tp-code-inline`, `tp-payload-pre` utility classes replacing hardcoded `bg-light` in JSX - Fix `bg-light`, `bg-white`, `text-dark`, `sticky-top` Bootstrap utilities and alert-danger readability in dark mode - `ndpi-reference.html` gains a `prefers-color-scheme: dark` media query that flips its own CSS variable set - `captureNetworkDiagrams` temporarily sets `data-theme="light"` before screenshotting so PDF reports always render in light mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address dark mode PR review comments - Remove duplicate alert-danger override (earlier block shadowed by later one) - Remove redundant tp-* dark overrides from sgds-overrides.css (index.css variables already handle these; also resolves tp-payload-pre inconsistency) - Remove hardcoded backgroundColor in SessionTab body pre so tp-stream-pane CSS class takes effect correctly - Fix NetworkGraph darkMode to reactively listen to prefers-color-scheme in system mode instead of reading it once on render Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent b41fbc7 commit db218b9

File tree

21 files changed

+659
-87
lines changed

21 files changed

+659
-87
lines changed

frontend/public/ndpi-reference.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@
2323
--sans: Inter, system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
2424
}
2525

26+
@media (prefers-color-scheme: dark) {
27+
:root {
28+
--bg: #0f1117;
29+
--surface: #1e2130;
30+
--surface2: #252840;
31+
--border: #2e3349;
32+
--border2: #3a4060;
33+
--accent: #4da3e8;
34+
--accent-hover: #74b8f0;
35+
--text: #e2e8f0;
36+
--muted: #8892a4;
37+
--tag-bg: #1a1d27;
38+
}
39+
}
40+
2641
body {
2742
background: var(--bg);
2843
color: var(--text);

frontend/src/assets/styles/index.css

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,35 @@
2222
--network-neutral: #95a5a6;
2323
}
2424

25+
/* Light mode tokens (default) */
26+
[data-theme='light'],
27+
:root {
28+
--tp-bg: #f8fafc;
29+
--tp-bg-subtle: #f8f9fa;
30+
--tp-surface: #ffffff;
31+
--tp-surface-hover: #f8f9fa;
32+
--tp-border: #dee2e6;
33+
--tp-text: #212529;
34+
--tp-text-muted: #6c757d;
35+
--tp-header-bg: #ffffff;
36+
--tp-footer-bg: #f8f9fa;
37+
--tp-scrollbar: #adb5bd;
38+
}
39+
40+
/* Dark mode tokens — must come after :root to win the cascade */
41+
[data-theme='dark'] {
42+
--tp-bg: #0f1117;
43+
--tp-bg-subtle: #1a1d27;
44+
--tp-surface: #1e2130;
45+
--tp-surface-hover: #252840;
46+
--tp-border: #2e3349;
47+
--tp-text: #e2e8f0;
48+
--tp-text-muted: #8892a4;
49+
--tp-header-bg: #13151f;
50+
--tp-footer-bg: #13151f;
51+
--tp-scrollbar: #3a4060;
52+
}
53+
2554
body {
2655
font-family:
2756
Inter,
@@ -31,7 +60,8 @@ body {
3160
margin: 0;
3261
padding: 0;
3362
min-height: 100vh;
34-
background-color: #f8f9fa;
63+
background-color: var(--tp-bg);
64+
color: var(--tp-text);
3565
}
3666

3767
#root {
@@ -50,12 +80,12 @@ body {
5080
display: flex;
5181
flex-direction: column;
5282
min-height: 100vh;
53-
background-color: #f8fafc;
83+
background-color: var(--tp-bg);
5484
}
5585

5686
.main-header {
57-
background-color: white;
58-
border-bottom: 1px solid #dee2e6;
87+
background-color: var(--tp-header-bg);
88+
border-bottom: 1px solid var(--tp-border);
5989
position: sticky;
6090
top: 0;
6191
z-index: 100;
@@ -67,7 +97,9 @@ body {
6797
}
6898

6999
.main-footer {
70-
border-top: 1px solid #dee2e6;
100+
border-top: 1px solid var(--tp-border);
101+
background-color: var(--tp-footer-bg) !important;
102+
color: var(--tp-text-muted);
71103
}
72104

73105
/* Upload progress scroll row */
@@ -79,7 +111,7 @@ body {
79111
padding: 0.25rem 0.125rem 0.625rem;
80112
-webkit-overflow-scrolling: touch;
81113
scrollbar-width: thin;
82-
scrollbar-color: var(--sgds-gray-300, #d0d5dd) transparent;
114+
scrollbar-color: var(--tp-scrollbar) transparent;
83115
}
84116

85117
.upload-progress-scroll::-webkit-scrollbar {
@@ -99,6 +131,29 @@ body {
99131
flex: 0 0 320px;
100132
}
101133

134+
/* Utility classes that adapt to dark mode via CSS variables */
135+
.tp-stat-box {
136+
background-color: var(--tp-bg-subtle);
137+
color: var(--tp-text);
138+
border-color: var(--tp-border);
139+
}
140+
141+
.tp-stream-pane {
142+
background-color: var(--tp-surface);
143+
border-color: var(--tp-border);
144+
color: var(--tp-text);
145+
}
146+
147+
.tp-code-inline {
148+
background-color: var(--tp-bg-subtle);
149+
color: var(--tp-text);
150+
}
151+
152+
.tp-payload-pre {
153+
background-color: var(--tp-bg-subtle);
154+
color: var(--tp-text);
155+
}
156+
102157
/* Page Styles */
103158
.home-page,
104159
.upload-page,

0 commit comments

Comments
 (0)