* feat: add landing page and docs website package Add packages/website — a Vue 3 + Naive UI static site with landing page and documentation, sharing the Pure Ink monochrome design with the main app. Features: particle network hero animation, screenshot carousel, feature grid, install guide tabs, GitHub star history, scroll reveal animations, and Chinese/English bilingual support. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: add favicon to website package Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: use dynamic theme param for star history chart Switch from CSS media query to JS-based dark mode detection so the star-history SVG matches the current theme toggle state. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: resolve TypeScript strict mode errors in website components - Remove unused isDark import in HeroSection - Add null check for canvas parent element - Rename unused img loop variable in ScreenshotsSection - Remove unused NIcon import in SiteHeader Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: resolve TS narrowing errors in canvas resize closure Use canvasRef.value directly inside resize() with local null check instead of relying on outer closure narrowing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
55 lines
1.1 KiB
TypeScript
55 lines
1.1 KiB
TypeScript
import { ref, watch } from 'vue'
|
|
|
|
export type ThemeMode = 'light' | 'dark' | 'system'
|
|
|
|
const STORAGE_KEY = 'hermes_website_theme'
|
|
|
|
const mode = ref<ThemeMode>(
|
|
(localStorage.getItem(STORAGE_KEY) as ThemeMode) || 'system',
|
|
)
|
|
|
|
const isDark = ref(false)
|
|
|
|
function applyTheme(dark: boolean) {
|
|
isDark.value = dark
|
|
document.documentElement.classList.toggle('dark', dark)
|
|
}
|
|
|
|
function resolveDark(m: ThemeMode): boolean {
|
|
if (m === 'system') {
|
|
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
}
|
|
return m === 'dark'
|
|
}
|
|
|
|
applyTheme(resolveDark(mode.value))
|
|
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
mediaQuery.addEventListener('change', () => {
|
|
if (mode.value === 'system') {
|
|
applyTheme(resolveDark('system'))
|
|
}
|
|
})
|
|
|
|
watch(mode, (newMode) => {
|
|
localStorage.setItem(STORAGE_KEY, newMode)
|
|
applyTheme(resolveDark(newMode))
|
|
})
|
|
|
|
export function useTheme() {
|
|
function setMode(m: ThemeMode) {
|
|
mode.value = m
|
|
}
|
|
|
|
function toggleTheme() {
|
|
mode.value = isDark.value ? 'light' : 'dark'
|
|
}
|
|
|
|
return {
|
|
mode,
|
|
isDark,
|
|
setMode,
|
|
toggleTheme,
|
|
}
|
|
}
|