Skip to content

Commit 2416a3b

Browse files
michaeloboyleclaude
andcommitted
feat: Add system light/dark theme support to visualization browser
- CSS variables for light/dark theme colors - @media (prefers-color-scheme: dark) for automatic theme detection - Real-time theme switching when system preference changes - vis.js network colors synchronized with theme - Smooth color transitions between themes 🤖 Generated with Claude Code Co-Authored-By: Claude <[email protected]>
1 parent c43d8db commit 2416a3b

File tree

1 file changed

+85
-24
lines changed

1 file changed

+85
-24
lines changed

examples/visualization-browser.html

Lines changed: 85 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,38 @@
66
<title>sqlite-graph Interactive Visualization</title>
77
<script type="text/javascript" src="https://unpkg.com/[email protected]/standalone/umd/vis-network.min.js"></script>
88
<style>
9+
/* Light theme (default) */
10+
:root {
11+
--bg-primary: #f5f5f5;
12+
--bg-secondary: #ffffff;
13+
--bg-tertiary: #f8f9fa;
14+
--text-primary: #333;
15+
--text-secondary: #666;
16+
--shadow: rgba(0, 0, 0, 0.1);
17+
--button-primary: #007bff;
18+
--button-primary-hover: #0056b3;
19+
--button-secondary: #6c757d;
20+
--button-secondary-hover: #545b62;
21+
--accent-color: #007bff;
22+
}
23+
24+
/* Dark theme (when system prefers dark) */
25+
@media (prefers-color-scheme: dark) {
26+
:root {
27+
--bg-primary: #1e1e1e;
28+
--bg-secondary: #2a2a2a;
29+
--bg-tertiary: #333333;
30+
--text-primary: #e0e0e0;
31+
--text-secondary: #999999;
32+
--shadow: rgba(0, 0, 0, 0.3);
33+
--button-primary: #0d6efd;
34+
--button-primary-hover: #0b5ed7;
35+
--button-secondary: #6c757d;
36+
--button-secondary-hover: #5a6268;
37+
--accent-color: #0d6efd;
38+
}
39+
}
40+
941
* {
1042
margin: 0;
1143
padding: 0;
@@ -14,7 +46,9 @@
1446

1547
body {
1648
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
17-
background: #f5f5f5;
49+
background: var(--bg-primary);
50+
color: var(--text-primary);
51+
transition: background 0.3s ease, color 0.3s ease;
1852
}
1953

2054
.container {
@@ -24,29 +58,29 @@
2458
}
2559

2660
header {
27-
background: white;
61+
background: var(--bg-secondary);
2862
padding: 20px;
2963
border-radius: 8px;
3064
margin-bottom: 20px;
31-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
65+
box-shadow: 0 2px 4px var(--shadow);
3266
}
3367

3468
h1 {
35-
color: #333;
69+
color: var(--text-primary);
3670
margin-bottom: 10px;
3771
}
3872

3973
.description {
40-
color: #666;
74+
color: var(--text-secondary);
4175
line-height: 1.6;
4276
}
4377

4478
.controls {
45-
background: white;
79+
background: var(--bg-secondary);
4680
padding: 20px;
4781
border-radius: 8px;
4882
margin-bottom: 20px;
49-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
83+
box-shadow: 0 2px 4px var(--shadow);
5084
}
5185

5286
.button-group {
@@ -57,7 +91,7 @@
5791

5892
button {
5993
padding: 10px 20px;
60-
background: #007bff;
94+
background: var(--button-primary);
6195
color: white;
6296
border: none;
6397
border-radius: 4px;
@@ -67,40 +101,40 @@
67101
}
68102

69103
button:hover {
70-
background: #0056b3;
104+
background: var(--button-primary-hover);
71105
}
72106

73107
button.secondary {
74-
background: #6c757d;
108+
background: var(--button-secondary);
75109
}
76110

77111
button.secondary:hover {
78-
background: #545b62;
112+
background: var(--button-secondary-hover);
79113
}
80114

81115
#mynetwork {
82116
width: 100%;
83117
height: 700px;
84-
background: white;
118+
background: var(--bg-secondary);
85119
border-radius: 8px;
86-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
120+
box-shadow: 0 2px 4px var(--shadow);
87121
}
88122

89123
.info-panel {
90-
background: white;
124+
background: var(--bg-secondary);
91125
padding: 20px;
92126
border-radius: 8px;
93127
margin-top: 20px;
94-
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
128+
box-shadow: 0 2px 4px var(--shadow);
95129
}
96130

97131
.info-panel h3 {
98132
margin-bottom: 10px;
99-
color: #333;
133+
color: var(--text-primary);
100134
}
101135

102136
.node-details {
103-
background: #f8f9fa;
137+
background: var(--bg-tertiary);
104138
padding: 15px;
105139
border-radius: 4px;
106140
margin-top: 10px;
@@ -109,9 +143,10 @@
109143
.node-details pre {
110144
margin: 10px 0 0 0;
111145
padding: 10px;
112-
background: white;
146+
background: var(--bg-secondary);
113147
border-radius: 4px;
114148
overflow-x: auto;
149+
color: var(--text-primary);
115150
}
116151

117152
.stats {
@@ -122,7 +157,7 @@
122157
}
123158

124159
.stat-card {
125-
background: #f8f9fa;
160+
background: var(--bg-tertiary);
126161
padding: 15px;
127162
border-radius: 4px;
128163
text-align: center;
@@ -131,11 +166,11 @@
131166
.stat-value {
132167
font-size: 32px;
133168
font-weight: bold;
134-
color: #007bff;
169+
color: var(--accent-color);
135170
}
136171

137172
.stat-label {
138-
color: #666;
173+
color: var(--text-secondary);
139174
margin-top: 5px;
140175
}
141176
</style>
@@ -192,20 +227,26 @@ <h4>Node Details</h4>
192227
let network;
193228
let nodes, edges;
194229

230+
// Detect system theme preference
231+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
232+
195233
const options = {
196234
nodes: {
197235
shape: 'dot',
198236
size: 20,
199237
font: {
200238
size: 14,
201-
color: '#333'
239+
color: prefersDark ? '#e0e0e0' : '#333'
202240
},
203241
borderWidth: 2,
204242
shadow: true
205243
},
206244
edges: {
207245
width: 2,
208-
color: { color: '#848484', highlight: '#007bff' },
246+
color: {
247+
color: prefersDark ? '#666' : '#848484',
248+
highlight: prefersDark ? '#0d6efd' : '#007bff'
249+
},
209250
smooth: {
210251
type: 'continuous'
211252
},
@@ -214,7 +255,8 @@ <h4>Node Details</h4>
214255
},
215256
font: {
216257
size: 12,
217-
align: 'middle'
258+
align: 'middle',
259+
color: prefersDark ? '#999' : '#666'
218260
}
219261
},
220262
physics: {
@@ -233,6 +275,25 @@ <h4>Node Details</h4>
233275
}
234276
};
235277

278+
// Listen for system theme changes and update graph colors
279+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
280+
const isDark = e.matches;
281+
network.setOptions({
282+
nodes: {
283+
font: { color: isDark ? '#e0e0e0' : '#333' }
284+
},
285+
edges: {
286+
color: {
287+
color: isDark ? '#666' : '#848484',
288+
highlight: isDark ? '#0d6efd' : '#007bff'
289+
},
290+
font: {
291+
color: isDark ? '#999' : '#666'
292+
}
293+
}
294+
});
295+
});
296+
236297
// Color schemes for different node types
237298
const nodeColors = {
238299
Job: { background: '#4CAF50', border: '#388E3C' },

0 commit comments

Comments
 (0)