Skip to content

Commit 575d379

Browse files
authored
Merge pull request #7645 from QwikDev/docs-remove-theme-store
refactor(docs theme): no globalStore.theme
2 parents 1274d78 + b6c73aa commit 575d379

File tree

12 files changed

+95
-138
lines changed

12 files changed

+95
-138
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 & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
import {
2-
component$,
3-
useContext,
4-
useSignal,
5-
useStyles$,
6-
useVisibleTask$,
7-
type PropsOf,
8-
} from '@qwik.dev/core';
1+
import { component$, useContext, useStyles$, useSignal, type PropsOf } from '@qwik.dev/core';
92
import { useLocation } from '@qwik.dev/router';
103
import { GlobalStore } from '../../context';
114
import { DocSearch } from '../docsearch/doc-search';
@@ -16,12 +9,7 @@ import { GithubLogo } from '../svgs/github-logo';
169
import { MoreIcon } from '../svgs/more-icon';
1710
import { QwikLogo } from '../svgs/qwik-logo';
1811
import { TwitterLogo } from '../svgs/twitter-logo';
19-
import {
20-
colorSchemeChangeListener,
21-
getColorPreference,
22-
setPreference,
23-
ThemeToggle,
24-
} from '../theme-toggle/theme-toggle';
12+
import { ThemeToggle } from '../theme-toggle/theme-toggle';
2513
import styles from './header.css?inline';
2614

2715
export const SearchButton = component$<PropsOf<'button'>>(({ ...props }) => {
@@ -45,14 +33,6 @@ export const Header = component$(() => {
4533
const globalStore = useContext(GlobalStore);
4634
const pathname = useLocation().url.pathname;
4735

48-
useVisibleTask$(() => {
49-
globalStore.theme = getColorPreference();
50-
return colorSchemeChangeListener((isDark) => {
51-
globalStore.theme = isDark ? 'dark' : 'light';
52-
setPreference(globalStore.theme);
53-
});
54-
});
55-
5636
return (
5737
<>
5838
<header

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ import { GithubLogo } from '../svgs/github-logo';
66
import { TwitterLogo } from '../svgs/twitter-logo';
77

88
type OnThisPageMoreProps = {
9-
theme: 'light' | 'dark' | 'auto';
109
editUrl: string;
1110
};
1211

13-
export const OnThisPageMore = component$<OnThisPageMoreProps>(({ theme, editUrl }) => {
12+
export const OnThisPageMore = component$<OnThisPageMoreProps>(({ editUrl }) => {
1413
const OnThisPageMore = [
1514
{
1615
href: editUrl,
@@ -45,15 +44,11 @@ export const OnThisPageMore = component$<OnThisPageMoreProps>(({ theme, editUrl
4544
{OnThisPageMore.map((el, index) => {
4645
return (
4746
<li
48-
class={`${
49-
theme === 'light'
50-
? 'hover:bg-[var(--qwik-light-blue)]'
51-
: 'hover:bg-[var(--on-this-page-hover-bg-color)]'
52-
} rounded-lg`}
47+
class="hover:bg-(--on-this-page-hover-bg-color) rounded-lg"
5348
key={`more-items-on-this-page-${index}`}
5449
>
5550
<a class="more-item" href={el.href} rel="noopener" target="_blank">
56-
{el.icon && <el.icon width={20} height={20} />}
51+
<el.icon width={20} height={20} />
5752
<span>{el.text}</span>
5853
</a>
5954
</li>

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

Lines changed: 3 additions & 12 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 styles from './on-this-page.css?inline';
54
import { OnThisPageMore } from './on-this-page-more';
65

@@ -108,7 +107,6 @@ const makeEditPageUrl = (url: string): string => {
108107

109108
export const OnThisPage = component$(() => {
110109
useStyles$(styles);
111-
const theme = useContext(GlobalStore);
112110
const { headings } = useContent();
113111
const contentHeadings = headings?.filter((h) => h.level <= 3) || [];
114112

@@ -162,14 +160,7 @@ export const OnThisPage = component$(() => {
162160
<h6>On This Page</h6>
163161
<ul class="px-2 font-medium text-[var(--interactive-text-color)]">
164162
{contentHeadings.map((h) => (
165-
<li
166-
key={h.id}
167-
class={`${
168-
theme.theme === 'light'
169-
? 'hover:bg-[var(--qwik-light-blue)]'
170-
: 'hover:bg-[var(--on-this-page-hover-bg-color)]'
171-
}`}
172-
>
163+
<li key={h.id} class="hover:bg-(--on-this-page-hover-bg-color)">
173164
{activeId.value === h.id ? (
174165
<span class="on-this-page-item">{h.text}</span>
175166
) : (
@@ -180,7 +171,7 @@ export const OnThisPage = component$(() => {
180171
</li>
181172
))}
182173
</ul>
183-
<OnThisPageMore theme={theme.theme} editUrl={editUrl} />
174+
<OnThisPageMore editUrl={editUrl} />
184175
</>
185176
) : null}
186177
</aside>

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 & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,76 @@
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';
812

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-
};
20-
21-
export const setPreference = (theme: ThemePreference) => {
22-
localStorage.setItem(themeStorageKey, theme);
23-
reflectPreference(theme);
24-
};
25-
26-
export const reflectPreference = (theme: ThemePreference) => {
27-
document.firstElementChild?.setAttribute('data-theme', theme);
28-
};
13+
type ThemeName = 'dark' | 'light' | undefined;
2914

30-
export const getColorPreference = (): ThemePreference => {
15+
export const getTheme = (): ThemeName => {
3116
let theme;
17+
const matchMedia = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
3218
try {
3319
theme = localStorage.getItem(themeStorageKey);
34-
} catch (err) {
35-
//
20+
return (theme as ThemeName) || matchMedia;
21+
} catch {
22+
return matchMedia;
3623
}
37-
if (theme) {
38-
return theme as ThemePreference;
24+
};
25+
26+
let currentThemeSignal: Signal<ThemeName>;
27+
export const getThemeSignal = () => {
28+
if (!isBrowser) {
29+
throw new Error('getThemeSignal is only available in the browser');
30+
}
31+
if (!currentThemeSignal) {
32+
currentThemeSignal = createSignal(getTheme());
33+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
34+
currentThemeSignal.value = getTheme();
35+
});
36+
}
37+
return currentThemeSignal;
38+
};
39+
40+
export const setTheme = (theme: ThemeName) => {
41+
if (!theme) {
42+
localStorage.removeItem(themeStorageKey);
43+
theme = getTheme();
3944
} else {
40-
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
45+
localStorage.setItem(themeStorageKey, theme);
46+
}
47+
document.firstElementChild?.setAttribute('data-theme', theme!);
48+
if (currentThemeSignal) {
49+
currentThemeSignal.value = theme;
4150
}
4251
};
4352

4453
export const ThemeToggle = component$(() => {
4554
useStyles$(themeToggle);
46-
const state = useContext(GlobalStore);
4755

4856
const onClick$ = event$(() => {
49-
state.theme = state.theme === 'light' ? 'dark' : 'light';
50-
setPreference(state.theme);
57+
const currentTheme = getTheme();
58+
setTheme(currentTheme === 'dark' ? 'light' : 'dark');
5159
});
5260

5361
return (
5462
<>
5563
<span class="lg:hidden">
56-
<button onClick$={onClick$}>{state.theme === 'light' ? 'Dark' : 'Light'} theme</button>
64+
<button onClick$={onClick$}>
65+
<span class="theme-name" /> theme
66+
</button>
5767
</span>
5868
<span class="hidden lg:block">
5969
<button
6070
type="button"
6171
class="theme-toggle"
6272
id="theme-toggle"
6373
title="Toggles light & dark"
64-
aria-label={state.theme}
65-
aria-live="polite"
6674
onClick$={onClick$}
6775
>
6876
<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');

0 commit comments

Comments
 (0)