Skip to content

Commit 9869df0

Browse files
authored
docs: Add toggleable dark and light mode (#246)
1 parent ed62a55 commit 9869df0

File tree

8 files changed

+208
-44
lines changed

8 files changed

+208
-44
lines changed

docs/src/components/AttributeCard.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ const rawJson = JSON.stringify(attribute, null, 2);
9191
)}
9292

9393
{isDeprecated && (
94-
<div class="mt-3 p-3 bg-error/10 rounded-md border-l-[3px] border-error">
94+
<div class="mt-3 p-3 bg-error-soft rounded-md border-l-[3px] border-error">
9595
{attribute.deprecation?.replacement ? (
9696
<p class="text-sm m-0">Use <code class="text-accent">{attribute.deprecation.replacement}</code> instead.</p>
9797
) : (

docs/src/components/PiiBadge.astro

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ const labels = {
1313
};
1414
1515
const colorClasses = {
16-
true: 'bg-pii-true/15 text-pii-true',
17-
maybe: 'bg-pii-maybe/15 text-pii-maybe',
18-
false: 'bg-pii-false/15 text-pii-false',
16+
true: 'bg-pii-true-soft text-pii-true',
17+
maybe: 'bg-pii-maybe-soft text-pii-maybe',
18+
false: 'bg-pii-false-soft text-pii-false',
1919
};
2020
---
2121

docs/src/components/SearchModal.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ function highlightMatch(key: string, searchQuery: string): { before: string; mat
323323
{#each attributeResults as attr, index}
324324
{@const highlighted = highlightMatch(attr.key, query)}
325325
<button
326-
class="flex flex-col gap-1 w-full px-4 py-3 bg-transparent border-none border-b border-border last:border-b-0 text-left cursor-pointer transition-all duration-fast border-l-2 {index === selectedIndex ? 'bg-accent/15 border-l-accent selected shadow-[inset_0_0_0_1px_rgba(149,128,255,0.2)]' : 'border-l-transparent hover:bg-bg-hover hover:border-l-border-light'}"
326+
class="flex flex-col gap-1 w-full px-4 py-3 bg-transparent border-none border-b border-border last:border-b-0 text-left cursor-pointer transition-all duration-fast border-l-2 {index === selectedIndex ? 'bg-accent-soft border-l-accent selected shadow-[inset_0_0_0_1px_var(--color-accent-soft)]' : 'border-l-transparent hover:bg-bg-hover hover:border-l-border-light'}"
327327
onclick={() => navigateToAttribute(attr)}
328328
onmouseenter={() => handleMouseEnter(index)}
329329
onmousemove={handleMouseMove}
@@ -340,7 +340,7 @@ function highlightMatch(key: string, searchQuery: string): { before: string; mat
340340
<span class="text-xs px-2 py-0.5 rounded-sm font-sans bg-bg-elevated text-text-muted">{attr.type}</span>
341341
<span class="text-xs px-2 py-0.5 rounded-sm font-sans bg-bg-elevated text-text-secondary">{attr.category}</span>
342342
{#if attr.deprecated}
343-
<span class="text-xs px-2 py-0.5 rounded-sm font-sans bg-error/15 text-error">deprecated</span>
343+
<span class="text-xs px-2 py-0.5 rounded-sm font-sans bg-error-soft text-error">deprecated</span>
344344
{/if}
345345
</div>
346346
</div>
@@ -359,7 +359,7 @@ function highlightMatch(key: string, searchQuery: string): { before: string; mat
359359
{#each pageResults as result, index}
360360
{@const actualIndex = attributeResults.length + index}
361361
<button
362-
class="flex flex-col gap-1 w-full px-4 py-3 bg-transparent border-none border-b border-border last:border-b-0 text-left cursor-pointer transition-all duration-fast border-l-2 {actualIndex === selectedIndex ? 'bg-accent/15 border-l-accent selected shadow-[inset_0_0_0_1px_rgba(149,128,255,0.2)]' : 'border-l-transparent hover:bg-bg-hover hover:border-l-border-light'}"
362+
class="flex flex-col gap-1 w-full px-4 py-3 bg-transparent border-none border-b border-border last:border-b-0 text-left cursor-pointer transition-all duration-fast border-l-2 {actualIndex === selectedIndex ? 'bg-accent-soft border-l-accent selected shadow-[inset_0_0_0_1px_var(--color-accent-soft)]' : 'border-l-transparent hover:bg-bg-hover hover:border-l-border-light'}"
363363
onclick={() => navigateToResult(result)}
364364
onmouseenter={() => handleMouseEnter(actualIndex)}
365365
onmousemove={handleMouseMove}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<script lang="ts">
2+
let isDark = $state(false);
3+
4+
// Initialize theme state from document
5+
$effect(() => {
6+
isDark = document.documentElement.classList.contains('dark');
7+
});
8+
9+
// Listen for system preference changes
10+
$effect(() => {
11+
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
12+
13+
function handleChange(e: MediaQueryListEvent) {
14+
// Only apply system preference if user hasn't set a manual preference
15+
if (!localStorage.getItem('theme')) {
16+
isDark = e.matches;
17+
document.documentElement.classList.toggle('dark', isDark);
18+
}
19+
}
20+
21+
mediaQuery.addEventListener('change', handleChange);
22+
23+
return () => {
24+
mediaQuery.removeEventListener('change', handleChange);
25+
};
26+
});
27+
28+
function toggleTheme() {
29+
isDark = !isDark;
30+
document.documentElement.classList.toggle('dark', isDark);
31+
localStorage.setItem('theme', isDark ? 'dark' : 'light');
32+
}
33+
</script>
34+
35+
<button
36+
onclick={toggleTheme}
37+
class="flex items-center justify-center w-9 h-9 bg-bg-elevated border border-border rounded-md text-text-secondary cursor-pointer transition-all duration-fast hover:border-border-light hover:text-text-primary"
38+
aria-label={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
39+
title={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
40+
>
41+
{#if isDark}
42+
<!-- Sun icon (shown in dark mode to switch to light) -->
43+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
44+
<circle cx="12" cy="12" r="5"/>
45+
<line x1="12" y1="1" x2="12" y2="3"/>
46+
<line x1="12" y1="21" x2="12" y2="23"/>
47+
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
48+
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
49+
<line x1="1" y1="12" x2="3" y2="12"/>
50+
<line x1="21" y1="12" x2="23" y2="12"/>
51+
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
52+
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
53+
</svg>
54+
{:else}
55+
<!-- Moon icon (shown in light mode to switch to dark) -->
56+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
57+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
58+
</svg>
59+
{/if}
60+
</button>

docs/src/layouts/BaseLayout.astro

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
import '../styles/global.css';
33
import SearchModal from '../components/SearchModal.svelte';
4+
import ThemeToggle from '../components/ThemeToggle.svelte';
45
import SearchIcon from '../components/icons/SearchIcon.astro';
56
import ExternalLinkIcon from '../components/icons/ExternalLinkIcon.astro';
67
@@ -25,6 +26,14 @@ const currentPath = Astro.url.pathname;
2526
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
2627
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300..700;1,9..40,300..700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
2728
<title>{title} | Sentry Conventions</title>
29+
<script is:inline>
30+
// Initialize theme before render to prevent flash
31+
const theme = localStorage.getItem('theme');
32+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
33+
if (theme === 'dark' || (!theme && prefersDark)) {
34+
document.documentElement.classList.add('dark');
35+
}
36+
</script>
2837
</head>
2938
<body>
3039
<div class="flex flex-col min-h-screen">
@@ -80,17 +89,20 @@ const currentPath = Astro.url.pathname;
8089
</a>
8190
</nav>
8291

83-
<button
84-
class="flex items-center gap-3 px-3 py-2 bg-bg-elevated border border-border rounded-md text-text-muted text-sm cursor-pointer transition-fast hover:border-border-light hover:text-text-secondary"
85-
id="search-trigger"
86-
aria-label="Search"
87-
>
88-
<SearchIcon />
89-
<span class="hidden md:flex gap-1">
90-
<kbd class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 bg-bg-secondary border border-border rounded-sm font-sans text-xs font-medium">⌘</kbd>
91-
<kbd class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 bg-bg-secondary border border-border rounded-sm font-sans text-xs font-medium">K</kbd>
92-
</span>
93-
</button>
92+
<div class="flex items-center gap-2">
93+
<button
94+
class="flex items-center gap-3 px-3 py-2 bg-bg-elevated border border-border rounded-md text-text-muted text-sm cursor-pointer transition-fast hover:border-border-light hover:text-text-secondary"
95+
id="search-trigger"
96+
aria-label="Search"
97+
>
98+
<SearchIcon />
99+
<span class="hidden md:flex gap-1">
100+
<kbd class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 bg-bg-secondary border border-border rounded-sm font-sans text-xs font-medium">⌘</kbd>
101+
<kbd class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 bg-bg-secondary border border-border rounded-sm font-sans text-xs font-medium">K</kbd>
102+
</span>
103+
</button>
104+
<ThemeToggle client:load />
105+
</div>
94106
</div>
95107
</header>
96108

docs/src/pages/names/index.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const totalOperations = allNames.reduce((acc, name) => acc + name.data.operation
7676
<p class="text-sm text-text-secondary mb-4">{op.brief}</p>
7777

7878
{!op.is_in_otel && (
79-
<div class="flex items-start gap-2 p-3 rounded-md text-sm mb-4 bg-warning/10 border border-warning/30 text-warning">
79+
<div class="flex items-start gap-2 p-3 rounded-md text-sm mb-4 bg-warning-soft border border-warning text-warning">
8080
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="flex-shrink-0 mt-0.5">
8181
<path d="M12 9v2m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
8282
</svg>
@@ -85,7 +85,7 @@ const totalOperations = allNames.reduce((acc, name) => acc + name.data.operation
8585
)}
8686

8787
{op.is_in_otel && op.otel_notes && (
88-
<div class="flex items-start gap-2 p-3 rounded-md text-sm mb-4 bg-info/10 border border-info/30 text-info">
88+
<div class="flex items-start gap-2 p-3 rounded-md text-sm mb-4 bg-info-soft border border-info text-info">
8989
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="flex-shrink-0 mt-0.5">
9090
<circle cx="12" cy="12" r="10"/>
9191
<path d="M12 16v-4M12 8h.01"/>

docs/src/styles/global.css

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,80 @@
1+
/* Theme CSS Custom Properties */
2+
:root {
3+
/* Light theme (default) */
4+
--color-bg-primary: #ffffff;
5+
--color-bg-secondary: #f8f9fa;
6+
--color-bg-elevated: #f0f1f3;
7+
--color-bg-hover: #e8e9eb;
8+
9+
--color-text-primary: #1a1d23;
10+
--color-text-secondary: #4a5568;
11+
--color-text-muted: #718096;
12+
13+
--color-accent: #7c3aed;
14+
--color-accent-hover: #6d28d9;
15+
--color-accent-soft: rgba(124, 58, 237, 0.12);
16+
17+
--color-border: #e2e8f0;
18+
--color-border-light: #cbd5e1;
19+
20+
--color-success: #22c55e;
21+
--color-success-soft: rgba(34, 197, 94, 0.15);
22+
--color-warning: #eab308;
23+
--color-warning-soft: rgba(234, 179, 8, 0.15);
24+
--color-error: #ef4444;
25+
--color-error-soft: rgba(239, 68, 68, 0.15);
26+
--color-info: #3b82f6;
27+
--color-info-soft: rgba(59, 130, 246, 0.15);
28+
29+
--color-code-string: #16a34a;
30+
--color-code-number: #ea580c;
31+
32+
--color-pii-true: #ef4444;
33+
--color-pii-true-soft: rgba(239, 68, 68, 0.15);
34+
--color-pii-maybe: #eab308;
35+
--color-pii-maybe-soft: rgba(234, 179, 8, 0.15);
36+
--color-pii-false: #22c55e;
37+
--color-pii-false-soft: rgba(34, 197, 94, 0.15);
38+
}
39+
40+
.dark {
41+
/* Dark theme */
42+
--color-bg-primary: #111318;
43+
--color-bg-secondary: #181b21;
44+
--color-bg-elevated: #1f2329;
45+
--color-bg-hover: #262b33;
46+
47+
--color-text-primary: #d4d7db;
48+
--color-text-secondary: #8b919a;
49+
--color-text-muted: #5c6370;
50+
51+
--color-accent: #9580ff;
52+
--color-accent-hover: #a899ff;
53+
--color-accent-soft: rgba(149, 128, 255, 0.12);
54+
55+
--color-border: #282d36;
56+
--color-border-light: #343a45;
57+
58+
--color-success: #50a060;
59+
--color-success-soft: rgba(80, 160, 96, 0.15);
60+
--color-warning: #d4a72c;
61+
--color-warning-soft: rgba(212, 167, 44, 0.15);
62+
--color-error: #c25450;
63+
--color-error-soft: rgba(194, 84, 80, 0.15);
64+
--color-info: #5c9fd4;
65+
--color-info-soft: rgba(92, 159, 212, 0.15);
66+
67+
--color-code-string: #98c379;
68+
--color-code-number: #d19a66;
69+
70+
--color-pii-true: #c25450;
71+
--color-pii-true-soft: rgba(194, 84, 80, 0.15);
72+
--color-pii-maybe: #d4a72c;
73+
--color-pii-maybe-soft: rgba(212, 167, 44, 0.15);
74+
--color-pii-false: #50a060;
75+
--color-pii-false-soft: rgba(80, 160, 96, 0.15);
76+
}
77+
178
@tailwind base;
279
@tailwind components;
380
@tailwind utilities;
@@ -127,15 +204,15 @@
127204
}
128205

129206
.badge-deprecated {
130-
@apply bg-error/15 text-error;
207+
@apply bg-error-soft text-error;
131208
}
132209

133210
.badge-otel {
134-
@apply bg-info/15 text-info;
211+
@apply bg-info-soft text-info;
135212
}
136213

137214
.badge-dynamic {
138-
@apply bg-warning/15 text-warning;
215+
@apply bg-warning-soft text-warning;
139216
}
140217

141218
.badge-type {

docs/tailwind.config.mjs

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,44 +5,59 @@ export default {
55
extend: {
66
colors: {
77
// Background colors
8-
'bg-primary': '#111318',
9-
'bg-secondary': '#181b21',
10-
'bg-elevated': '#1f2329',
11-
'bg-hover': '#262b33',
8+
'bg-primary': 'var(--color-bg-primary)',
9+
'bg-secondary': 'var(--color-bg-secondary)',
10+
'bg-elevated': 'var(--color-bg-elevated)',
11+
'bg-hover': 'var(--color-bg-hover)',
1212

1313
// Text colors
14-
'text-primary': '#d4d7db',
15-
'text-secondary': '#8b919a',
16-
'text-muted': '#5c6370',
14+
'text-primary': 'var(--color-text-primary)',
15+
'text-secondary': 'var(--color-text-secondary)',
16+
'text-muted': 'var(--color-text-muted)',
1717

1818
// Accent
1919
accent: {
20-
DEFAULT: '#9580ff',
21-
hover: '#a899ff',
22-
soft: 'rgba(149, 128, 255, 0.12)',
20+
DEFAULT: 'var(--color-accent)',
21+
hover: 'var(--color-accent-hover)',
22+
soft: 'var(--color-accent-soft)',
2323
},
2424

2525
// Border colors
2626
border: {
27-
DEFAULT: '#282d36',
28-
light: '#343a45',
27+
DEFAULT: 'var(--color-border)',
28+
light: 'var(--color-border-light)',
2929
},
3030

3131
// Semantic colors
32-
success: '#50a060',
33-
warning: '#d4a72c',
34-
error: '#c25450',
35-
info: '#5c9fd4',
32+
success: {
33+
DEFAULT: 'var(--color-success)',
34+
soft: 'var(--color-success-soft)',
35+
},
36+
warning: {
37+
DEFAULT: 'var(--color-warning)',
38+
soft: 'var(--color-warning-soft)',
39+
},
40+
error: {
41+
DEFAULT: 'var(--color-error)',
42+
soft: 'var(--color-error-soft)',
43+
},
44+
info: {
45+
DEFAULT: 'var(--color-info)',
46+
soft: 'var(--color-info-soft)',
47+
},
3648

3749
// Code syntax highlighting
38-
'code-string': '#98c379',
39-
'code-number': '#d19a66',
50+
'code-string': 'var(--color-code-string)',
51+
'code-number': 'var(--color-code-number)',
4052

4153
// PII indicator colors
4254
pii: {
43-
true: '#c25450',
44-
maybe: '#d4a72c',
45-
false: '#50a060',
55+
true: 'var(--color-pii-true)',
56+
'true-soft': 'var(--color-pii-true-soft)',
57+
maybe: 'var(--color-pii-maybe)',
58+
'maybe-soft': 'var(--color-pii-maybe-soft)',
59+
false: 'var(--color-pii-false)',
60+
'false-soft': 'var(--color-pii-false-soft)',
4661
},
4762
},
4863
fontFamily: {

0 commit comments

Comments
 (0)