Skip to content

Commit b82a629

Browse files
committed
Add landing page
Improved the landing-page theme control. What changed: - Turned the control into a compact right-aligned pill instead of a wide banner. - Reduced the label weight/size so it doesn’t dominate the viewport. - Hid the secondary helper text on mobile so it stays clean. Files updated: - metbit/docs/app/globals.css:150 Verified: - npm run lint passed. - npm run build passed.
1 parent 204ba05 commit b82a629

6 files changed

Lines changed: 528 additions & 25 deletions

File tree

docs/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<p align="center">
2-
<img src="public/logo/Metbit-logo-only.svg" alt="metbit" width="180" />
2+
<img src="public/logo/Metbit-logo-dark-mode.svg" alt="metbit" width="180" />
33
</p>
44

55
# metbit documentation site

docs/app/components/MetbitMark.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import Image from 'next/image'
22

3-
export default function MetbitMark() {
3+
type MetbitMarkProps = {
4+
variant?: 'full' | 'compact'
5+
}
6+
7+
export default function MetbitMark({ variant = 'full' }: MetbitMarkProps) {
8+
const lightSrc = variant === 'compact' ? '/logo/Metbit-logo-only.svg' : '/logo/Metbit-logo-light-mode.svg'
9+
const darkSrc = variant === 'compact' ? '/logo/Metbit-logo-only.svg' : '/logo/Metbit-logo-dark-mode.svg'
10+
411
return (
512
<span className="metbitLogo" aria-hidden="true">
613
<Image
714
className="metbitLogoImage metbitLogoLight"
8-
src="/logo/Metbit-logo-dark-mode.svg"
15+
src={lightSrc}
916
alt=""
1017
aria-hidden="true"
1118
fill
@@ -14,7 +21,7 @@ export default function MetbitMark() {
1421
/>
1522
<Image
1623
className="metbitLogoImage metbitLogoDark"
17-
src="/logo/Metbit-logo-dark-mode.svg"
24+
src={darkSrc}
1825
alt=""
1926
aria-hidden="true"
2027
fill

docs/app/components/ThemeToggle.tsx

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,50 @@
11
'use client'
22

3-
import { useEffect, useState } from 'react'
3+
import { useEffect, useSyncExternalStore } from 'react'
44
import { FiSun, FiMonitor, FiMoon } from 'react-icons/fi'
55

66
type Mode = 'light' | 'dark' | 'system'
7+
type ThemeSnapshot = 'light' | 'dark' | 'system-light' | 'system-dark'
78

89
function getStoredMode(): Mode {
9-
if (typeof window === 'undefined') return 'system'
1010
const stored = localStorage.getItem('theme')
11-
if (stored === 'light' || stored === 'dark' || stored === 'system') {
12-
return stored
11+
return stored === 'light' || stored === 'dark' || stored === 'system' ? stored : 'system'
12+
}
13+
14+
function getThemeSnapshot(): ThemeSnapshot {
15+
if (typeof window === 'undefined') return 'system-light'
16+
const stored = getStoredMode()
17+
if (stored === 'system') {
18+
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
19+
return isDark ? 'system-dark' : 'system-light'
1320
}
14-
return 'system'
21+
return stored
22+
}
23+
24+
function subscribe(onStoreChange: () => void) {
25+
if (typeof window === 'undefined') return () => {}
26+
27+
const mq = window.matchMedia('(prefers-color-scheme: dark)')
28+
const onThemeChange = () => onStoreChange()
29+
30+
window.addEventListener('storage', onThemeChange)
31+
window.addEventListener('themechange', onThemeChange)
32+
mq.addEventListener?.('change', onThemeChange)
33+
34+
return () => {
35+
window.removeEventListener('storage', onThemeChange)
36+
window.removeEventListener('themechange', onThemeChange)
37+
mq.removeEventListener?.('change', onThemeChange)
38+
}
39+
}
40+
41+
function snapshotToMode(snapshot: ThemeSnapshot): Mode {
42+
return snapshot === 'light' || snapshot === 'dark' ? snapshot : 'system'
43+
}
44+
45+
function snapshotToAppliedTheme(snapshot: ThemeSnapshot): Exclude<Mode, 'system'> {
46+
if (snapshot === 'light' || snapshot === 'dark') return snapshot
47+
return snapshot === 'system-dark' ? 'dark' : 'light'
1548
}
1649

1750
function applyTheme(mode: Mode) {
@@ -26,24 +59,21 @@ function applyTheme(mode: Mode) {
2659
}
2760

2861
export default function ThemeToggle() {
29-
const [mode, setMode] = useState<Mode>(getStoredMode)
62+
const snapshot = useSyncExternalStore<ThemeSnapshot>(
63+
subscribe,
64+
getThemeSnapshot,
65+
() => 'system-light',
66+
)
67+
const mode = snapshotToMode(snapshot)
3068

3169
useEffect(() => {
32-
const current = getStoredMode()
33-
applyTheme(current)
34-
35-
const mq = window.matchMedia('(prefers-color-scheme: dark)')
36-
const onChange = () => {
37-
if (getStoredMode() === 'system') applyTheme('system')
38-
}
39-
mq.addEventListener?.('change', onChange)
40-
return () => mq.removeEventListener?.('change', onChange)
41-
}, [])
70+
applyTheme(snapshotToAppliedTheme(snapshot))
71+
}, [snapshot])
4272

4373
const choose = (m: Mode) => {
4474
localStorage.setItem('theme', m)
45-
setMode(m)
4675
applyTheme(m)
76+
window.dispatchEvent(new Event('themechange'))
4777
}
4878

4979
return (

docs/app/components/VersionedDocsShell.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export default function VersionedDocsShell({
5959
<header className="docsTopbar">
6060
<Link
6161
className="docsBrand"
62-
href={`/docs/${encodeURIComponent(release.tag)}`}
62+
href="/"
6363
aria-label="metbit documentation home"
6464
>
6565
<MetbitMark />

0 commit comments

Comments
 (0)