Skip to content

Commit bce2f5a

Browse files
committed
refactor(docs theme): no globalStore.theme
1 parent 50141a9 commit bce2f5a

File tree

11 files changed

+92
-124
lines changed

11 files changed

+92
-124
lines changed

packages/docs/src/components/code-sandbox/index.tsx

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { component$, Slot, useContext, useSignal, useStylesScoped$ } from '@qwik.dev/core';
2-
import { GlobalStore } from '../../context';
1+
import { component$, Slot, useSignal, useStylesScoped$ } from '@qwik.dev/core';
32
import { EditIcon } from '../svgs/edit-icon';
43
import CSS from './index.css?inline';
54

@@ -10,10 +9,9 @@ export default component$<{
109
console?: boolean;
1110
maxHeight?: number;
1211
style?: Record<string, string>;
13-
}>(({ url, tabs, src, style, console, maxHeight }) => {
12+
}>(({ url, tabs, src, style, console }) => {
1413
const activeTab = useSignal(0);
1514
useStylesScoped$(CSS);
16-
const state = useContext(GlobalStore);
1715
const exampleUrl = (url || src) + (console ? '?console=true' : '');
1816
return (
1917
<>
@@ -71,7 +69,7 @@ export default component$<{
7169
<div>
7270
<iframe
7371
loading="lazy"
74-
src={examplePath({ path: exampleUrl, theme: state.theme, includeTheme: true })}
72+
src={examplePath(exampleUrl)}
7573
style={{ width: '100%', height: '200px', ...style }}
7674
/>
7775
</div>
@@ -80,37 +78,16 @@ export default component$<{
8078
);
8179
});
8280

83-
function examplePath(
84-
opts:
85-
| {
86-
path: string;
87-
theme?: string;
88-
includeTheme?: boolean;
89-
}
90-
| string
91-
) {
92-
const {
93-
path,
94-
theme = 'light',
95-
includeTheme = false,
96-
} = typeof opts === 'string' ? ({ path: opts } as any) : opts;
81+
function examplePath(path: string) {
9782
const newPath = path
9883
.replace('/(qwik)/', '/')
9984
.replace('/(qwikrouter)/', '/')
10085
.replace('/src/routes/demo', '/demo')
10186
.replace(/\/[\w\d]+\.tsx?$/, '/');
10287

103-
if (!includeTheme) {
104-
return newPath;
105-
}
106-
107-
if (newPath.indexOf('?') > -1) {
108-
return newPath + '&theme=' + theme;
109-
}
110-
111-
return newPath + '?theme=' + theme;
88+
return newPath;
11289
}
11390

114-
export const CodeFile = component$<{ src: string }>((props) => {
91+
export const CodeFile = component$<{ src: string }>(() => {
11592
return <Slot />;
11693
});

packages/docs/src/components/header/header.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { component$, useContext, useStyles$, useVisibleTask$ } from '@qwik.dev/core';
1+
import { component$, useContext, useStyles$ } from '@qwik.dev/core';
22
import { useLocation } from '@qwik.dev/router';
33
import { GlobalStore } from '../../context';
44
import { DocSearch } from '../docsearch/doc-search';
@@ -8,27 +8,14 @@ import { GithubLogo } from '../svgs/github-logo';
88
import { MoreIcon } from '../svgs/more-icon';
99
import { QwikLogo } from '../svgs/qwik-logo';
1010
import { TwitterLogo } from '../svgs/twitter-logo';
11-
import {
12-
colorSchemeChangeListener,
13-
getColorPreference,
14-
setPreference,
15-
ThemeToggle,
16-
} from '../theme-toggle/theme-toggle';
11+
import { ThemeToggle } from '../theme-toggle/theme-toggle';
1712
import styles from './header.css?inline';
1813

1914
export const Header = component$(() => {
2015
useStyles$(styles);
2116
const globalStore = useContext(GlobalStore);
2217
const pathname = useLocation().url.pathname;
2318

24-
useVisibleTask$(() => {
25-
globalStore.theme = getColorPreference();
26-
return colorSchemeChangeListener((isDark) => {
27-
globalStore.theme = isDark ? 'dark' : 'light';
28-
setPreference(globalStore.theme);
29-
});
30-
});
31-
3219
return (
3320
<>
3421
<header

packages/docs/src/components/on-this-page/on-this-page.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { $, component$, useContext, useOnDocument, useSignal, useStyles$ } from '@qwik.dev/core';
1+
import { $, component$, useOnDocument, useSignal, useStyles$ } from '@qwik.dev/core';
22
import { useContent, useLocation } from '@qwik.dev/router';
3-
import { GlobalStore } from '../../context';
43
import { AlertIcon } from '../svgs/alert-icon';
54
import { ChatIcon } from '../svgs/chat-icon';
65
import { EditIcon } from '../svgs/edit-icon';
@@ -86,7 +85,6 @@ const makeEditPageUrl = (url: string): string => {
8685

8786
export const OnThisPage = component$(() => {
8887
useStyles$(styles);
89-
const theme = useContext(GlobalStore);
9088
const { headings } = useContent();
9189
const contentHeadings = headings?.filter((h) => h.level <= 3) || [];
9290

@@ -170,14 +168,7 @@ export const OnThisPage = component$(() => {
170168
<h6>On This Page</h6>
171169
<ul class="px-2 font-medium text-[var(--interactive-text-color)]">
172170
{contentHeadings.map((h) => (
173-
<li
174-
key={h.id}
175-
class={`${
176-
theme.theme === 'light'
177-
? 'hover:bg-[var(--qwik-light-blue)]'
178-
: 'hover:bg-[var(--on-this-page-hover-bg-color)]'
179-
}`}
180-
>
171+
<li key={h.id} class="hover:bg-(--on-this-page-hover-bg-color)">
181172
{activeId.value === h.id ? (
182173
<span class="on-this-page-item">{h.text}</span>
183174
) : (
@@ -196,11 +187,7 @@ export const OnThisPage = component$(() => {
196187
{OnThisPageMore.map((el, index) => {
197188
return (
198189
<li
199-
class={`${
200-
theme.theme === 'light'
201-
? 'hover:bg-[var(--qwik-light-blue)]'
202-
: 'hover:bg-[var(--on-this-page-hover-bg-color)]'
203-
} rounded-lg`}
190+
class="hover:bg-(--on-this-page-hover-bg-color) rounded-lg"
204191
key={`more-items-on-this-page-${index}`}
205192
>
206193
<a class="more-item" href={el.href} rel="noopener" target="_blank">

packages/docs/src/components/package-manager-tabs/index.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { Tabs } from '@qwik-ui/headless';
2-
import { $, Slot, component$, useContext, useSignal, type PropsOf } from '@qwik.dev/core';
3-
import { GlobalStore } from '~/context';
2+
import { $, Slot, component$, useSignal, type PropsOf } from '@qwik.dev/core';
43

54
const pkgManagers = ['pnpm', 'npm', 'yarn', 'bun'] as const;
65
type PkgManagers = (typeof pkgManagers)[number];
76

87
export default component$(() => {
9-
const globalStore = useContext(GlobalStore);
108
const selectedPkgManagersSig = useSignal<PkgManagers>('pnpm');
119

12-
const activeClass = `${globalStore.theme === 'light' ? 'bg-gray-300 text-black' : 'bg-slate-800 text-white'}`;
10+
const activeClass = `font-bold bg-(--color-tab-active-bg) text-(--color-tab-active-text)`;
1311

1412
return (
1513
<Tabs.Root
@@ -21,7 +19,7 @@ export default component$(() => {
2119
<Tabs.List>
2220
<Tabs.Tab
2321
tabId="pnpm"
24-
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'pnpm' ? `font-bold ${activeClass}` : ''}`}
22+
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'pnpm' ? activeClass : ''}`}
2523
>
2624
<span class="inline-flex items-center gap-x-2">
2725
<PnpmIcon />
@@ -30,7 +28,7 @@ export default component$(() => {
3028
</Tabs.Tab>
3129
<Tabs.Tab
3230
tabId="npm"
33-
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'npm' ? `font-bold ${activeClass}` : ''}`}
31+
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'npm' ? activeClass : ''}`}
3432
>
3533
<span class="inline-flex items-center gap-x-2">
3634
<NpmIcon />
@@ -39,7 +37,7 @@ export default component$(() => {
3937
</Tabs.Tab>
4038
<Tabs.Tab
4139
tabId="yarn"
42-
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'yarn' ? `font-bold ${activeClass}` : ''}`}
40+
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'yarn' ? activeClass : ''}`}
4341
>
4442
<span class="inline-flex items-center gap-x-2">
4543
<YarnIcon />
@@ -48,7 +46,7 @@ export default component$(() => {
4846
</Tabs.Tab>
4947
<Tabs.Tab
5048
tabId="bun"
51-
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'bun' ? `font-bold ${activeClass}` : ''}`}
49+
class={`px-4 pt-2 rounded-md ${selectedPkgManagersSig.value === 'bun' ? activeClass : ''}`}
5250
>
5351
<span class="inline-flex items-center gap-x-2">
5452
<BunIcon />

packages/docs/src/components/router-head/theme-script.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ export const ThemeScript = () => {
88
localStorage.getItem('${themeStorageKey}') ??
99
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
1010
);
11-
} catch (err) { }`;
11+
} catch (e) { }`.replaceAll(/\s+/gm, '');
1212
return <script dangerouslySetInnerHTML={themeScript} />;
1313
};

packages/docs/src/components/theme-toggle/theme-toggle.tsx

Lines changed: 45 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,79 @@
1-
import { component$, event$, useContext, useStyles$ } from '@qwik.dev/core';
2-
import { SunAndMoon } from './sun-and-moon';
1+
import {
2+
component$,
3+
createSignal,
4+
event$,
5+
isBrowser,
6+
useStyles$,
7+
type Signal,
8+
} from '@qwik.dev/core';
39
import { themeStorageKey } from '../router-head/theme-script';
10+
import { SunAndMoon } from './sun-and-moon';
411
import themeToggle from './theme-toggle.css?inline';
5-
import { GlobalStore } from '../../context';
6-
7-
export type ThemePreference = 'dark' | 'light';
8-
9-
export const colorSchemeChangeListener = (onColorSchemeChange: (isDark: boolean) => void) => {
10-
const listener = ({ matches: isDark }: MediaQueryListEvent) => {
11-
onColorSchemeChange(isDark);
12-
};
13-
window
14-
.matchMedia('(prefers-color-scheme: dark)')
15-
.addEventListener('change', (event) => listener(event));
16-
17-
return () =>
18-
window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', listener);
19-
};
2012

21-
export const setPreference = (theme: ThemePreference) => {
22-
localStorage.setItem(themeStorageKey, theme);
23-
reflectPreference(theme);
24-
};
13+
type ThemeName = 'dark' | 'light' | undefined;
2514

26-
export const reflectPreference = (theme: ThemePreference) => {
27-
document.firstElementChild?.setAttribute('data-theme', theme);
28-
};
29-
30-
export const getColorPreference = (): ThemePreference => {
15+
export const getTheme = (): ThemeName => {
3116
let theme;
3217
try {
3318
theme = localStorage.getItem(themeStorageKey);
34-
} catch (err) {
19+
} catch {
3520
//
3621
}
3722
if (theme) {
38-
return theme as ThemePreference;
23+
return theme as ThemeName;
3924
} else {
4025
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
4126
}
4227
};
4328

29+
let currentThemeSignal: Signal<ThemeName>;
30+
export const getThemeSignal = () => {
31+
if (!isBrowser) {
32+
throw new Error('getThemeSignal is only available in the browser');
33+
}
34+
if (!currentThemeSignal) {
35+
currentThemeSignal = createSignal(getTheme());
36+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
37+
currentThemeSignal.value = getTheme();
38+
});
39+
}
40+
return currentThemeSignal;
41+
};
42+
43+
export const setTheme = (theme: ThemeName) => {
44+
if (!theme) {
45+
localStorage.removeItem(themeStorageKey);
46+
theme = getTheme();
47+
} else {
48+
localStorage.setItem(themeStorageKey, theme);
49+
}
50+
document.firstElementChild?.setAttribute('data-theme', theme!);
51+
if (currentThemeSignal) {
52+
currentThemeSignal.value = theme;
53+
}
54+
};
55+
4456
export const ThemeToggle = component$(() => {
4557
useStyles$(themeToggle);
46-
const state = useContext(GlobalStore);
4758

4859
const onClick$ = event$(() => {
49-
state.theme = state.theme === 'light' ? 'dark' : 'light';
50-
setPreference(state.theme);
60+
const currentTheme = getTheme();
61+
setTheme(currentTheme === 'dark' ? 'light' : 'dark');
5162
});
5263

5364
return (
5465
<>
5566
<span class="lg:hidden">
56-
<button onClick$={onClick$}>{state.theme === 'light' ? 'Dark' : 'Light'} theme</button>
67+
<button onClick$={onClick$}>
68+
<span class="theme-name" /> theme
69+
</button>
5770
</span>
5871
<span class="hidden lg:block">
5972
<button
6073
type="button"
6174
class="theme-toggle"
6275
id="theme-toggle"
6376
title="Toggles light & dark"
64-
aria-label={state.theme}
65-
aria-live="polite"
6677
onClick$={onClick$}
6778
>
6879
<SunAndMoon />

packages/docs/src/context.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { createContextId } from '@qwik.dev/core';
2-
import type { ThemePreference } from './components/theme-toggle/theme-toggle';
32

43
export interface SiteStore {
54
headerMenuOpen: boolean;
65
sideMenuOpen: boolean;
7-
theme: ThemePreference | 'auto';
86
}
97

108
export const GlobalStore = createContextId<SiteStore>('site-store');

packages/docs/src/global.css

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@
5959

6060
:root {
6161
color-scheme: light;
62+
--theme-name: 'light';
63+
64+
--color-tab-active-bg: #046ee959;
65+
--color-tab-active-text: black;
66+
6267
--header-height: 80px;
6368
--aside-width: 300px;
6469
--container-max-width: 1400px;
@@ -119,7 +124,7 @@
119124

120125
--made-with-love-text-color: #333333;
121126

122-
--on-this-page-hover-bg-color: #0093ee17;
127+
--on-this-page-hover-bg-color: var(--qwik-light-blue);
123128

124129
--media-separator-color: #dddddd;
125130
--media-video-shadow-color: var(--qwik-dark-blue);
@@ -129,6 +134,11 @@
129134

130135
:root[data-theme='dark'] {
131136
color-scheme: dark;
137+
--theme-name: 'dark';
138+
139+
--color-tab-active-bg: #3e3e3e;
140+
--color-tab-active-text: white;
141+
132142
--qwik-blue: #009dfd;
133143

134144
--bg-color: #101010;
@@ -160,12 +170,19 @@
160170

161171
--made-with-love-text-color: #c6c5cb;
162172

173+
--on-this-page-hover-bg-color: #0093ee17;
174+
163175
--media-separator-color: rgba(255, 255, 255, 0.1);
164176
--media-video-shadow-color: var(--qwik-blue);
165177

166178
--panel-toggle-background-color: var(--qwik-dark-blue);
167179
}
168180

181+
.theme-name::before {
182+
content: var(--theme-name);
183+
text-transform: capitalize;
184+
}
185+
169186
@media (max-width: 768px) {
170187
:root {
171188
--panel-toggle-height: 56px;

0 commit comments

Comments
 (0)