mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-10 04:22:18 +00:00
fix: theme select
This commit is contained in:
48
src/app.html
48
src/app.html
@@ -1,34 +1,18 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
<head>
|
||||||
<link rel="icon" type="image/svg+xml" href="/images/logos/logo.svg" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" href="/icon-font/aw-icon.css" />
|
<link rel="icon" type="image/svg+xml" href="/images/logos/logo.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<link rel="stylesheet" href="/icon-font/aw-icon.css" />
|
||||||
<meta name="”twitter:site”" content="@appwrite" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
%sveltekit.head%
|
<meta name="”twitter:site”" content="@appwrite" />
|
||||||
</head>
|
%sveltekit.head%
|
||||||
<body class="theme-dark" data-sveltekit-preload-data="hover">
|
</head>
|
||||||
<script
|
|
||||||
type="module"
|
<body class="theme-dark" data-sveltekit-preload-data="hover">
|
||||||
src="https://unpkg.com/@splinetool/viewer@0.9.455/build/spline-viewer.js"
|
<div id="top" style="display: contents">%sveltekit.body%</div>
|
||||||
></script>
|
<script type="module" src="https://unpkg.com/@splinetool/viewer@0.9.455/build/spline-viewer.js" defer></script>
|
||||||
<script>
|
</body>
|
||||||
const isDocs = window.location.pathname.startsWith('/docs');
|
|
||||||
if (isDocs) {
|
</html>
|
||||||
const theme = localStorage.getItem('theme');
|
|
||||||
document.body.classList.remove('theme-dark', 'theme-light') || 'dark';
|
|
||||||
if (theme === 'system') {
|
|
||||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
||||||
? 'dark'
|
|
||||||
: 'light';
|
|
||||||
document.body.classList.add(`theme-${systemTheme}`);
|
|
||||||
} else {
|
|
||||||
document.body.classList.add(`theme-${theme}`);
|
|
||||||
}
|
|
||||||
localStorage.setItem('theme', theme);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<div id="top" style="display: contents">%sveltekit.body%</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,21 +1,16 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { capitalize } from '$lib/utils/capitalize.js';
|
import { capitalize } from '$lib/utils/capitalize.js';
|
||||||
|
import { currentTheme, setTheme, type Theme } from '$routes/+layout.svelte';
|
||||||
import { createSelect, melt } from '@melt-ui/svelte';
|
import { createSelect, melt } from '@melt-ui/svelte';
|
||||||
import { onMount } from 'svelte';
|
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
|
|
||||||
const iconMap = {
|
const iconMap: Record<Theme, string> = {
|
||||||
dark: 'aw-icon-dark',
|
dark: 'aw-icon-dark',
|
||||||
light: 'aw-icon-light',
|
light: 'aw-icon-light',
|
||||||
system: 'icon-server'
|
system: 'icon-server'
|
||||||
} as const;
|
};
|
||||||
|
|
||||||
const themes = ['dark', 'light', 'system'] as const;
|
const themes: Array<Theme> = ['dark', 'light', 'system'];
|
||||||
|
|
||||||
type Theme = (typeof themes)[number];
|
|
||||||
function isTheme(theme: unknown): theme is Theme {
|
|
||||||
return themes.includes(theme as Theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
elements: { trigger, menu, option },
|
elements: { trigger, menu, option },
|
||||||
@@ -23,8 +18,8 @@
|
|||||||
} = createSelect<Theme>({
|
} = createSelect<Theme>({
|
||||||
preventScroll: false,
|
preventScroll: false,
|
||||||
defaultSelected: {
|
defaultSelected: {
|
||||||
value: 'dark',
|
value: $currentTheme,
|
||||||
label: 'Dark'
|
label: capitalize($currentTheme)
|
||||||
},
|
},
|
||||||
positioning: {
|
positioning: {
|
||||||
sameWidth: true,
|
sameWidth: true,
|
||||||
@@ -33,44 +28,13 @@
|
|||||||
forceVisible: true,
|
forceVisible: true,
|
||||||
onSelectedChange({ curr, next }) {
|
onSelectedChange({ curr, next }) {
|
||||||
const t = next?.value;
|
const t = next?.value;
|
||||||
if (isTheme(t) && t !== curr?.value) {
|
if (t && t !== curr?.value) {
|
||||||
setTheme(t);
|
setTheme(t);
|
||||||
}
|
}
|
||||||
open.set(false);
|
open.set(false);
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function setSelected(theme: Theme) {
|
|
||||||
selected.set({
|
|
||||||
value: theme,
|
|
||||||
label: capitalize(theme)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setTheme(theme: Theme) {
|
|
||||||
document.body.classList.remove('theme-dark', 'theme-light');
|
|
||||||
if (theme === 'system') {
|
|
||||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
||||||
? 'dark'
|
|
||||||
: 'light';
|
|
||||||
document.body.classList.add(`theme-${systemTheme}`);
|
|
||||||
} else {
|
|
||||||
document.body.classList.add(`theme-${theme}`);
|
|
||||||
}
|
|
||||||
localStorage.setItem('theme', theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
const theme = localStorage.getItem('theme');
|
|
||||||
if (isTheme(theme)) {
|
|
||||||
setTheme(theme);
|
|
||||||
setSelected(theme);
|
|
||||||
} else {
|
|
||||||
setTheme('dark');
|
|
||||||
setSelected('dark');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button class="aw-select is-colored" use:melt={$trigger}>
|
<button class="aw-select is-colored" use:melt={$trigger}>
|
||||||
|
|||||||
@@ -90,10 +90,6 @@
|
|||||||
label: 'Blog',
|
label: 'Blog',
|
||||||
href: '/blog'
|
href: '/blog'
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// label: 'Changelog',
|
|
||||||
// href: '#'
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
label: 'Pricing',
|
label: 'Pricing',
|
||||||
href: '/pricing'
|
href: '/pricing'
|
||||||
|
|||||||
@@ -1,3 +1,41 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
export type Theme = 'dark' | 'light' | 'system';
|
||||||
|
export const currentTheme = writable<Theme>(getPreferredTheme());
|
||||||
|
|
||||||
|
function isTheme(theme: unknown): theme is Theme {
|
||||||
|
return ['dark', 'light', 'system'].includes(theme as Theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSystemTheme(): Theme {
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPreferredTheme() {
|
||||||
|
if (!browser) {
|
||||||
|
return 'dark';
|
||||||
|
}
|
||||||
|
|
||||||
|
const theme = globalThis?.localStorage.getItem('theme');
|
||||||
|
|
||||||
|
if (!isTheme(theme)) {
|
||||||
|
return 'dark';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theme === 'system') {
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||||
|
}
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setTheme(theme: string) {
|
||||||
|
if (!isTheme(theme)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentTheme.set(theme === 'system' ? getSystemTheme() : theme);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import '@fontsource/inter/100.css';
|
import '@fontsource/inter/100.css';
|
||||||
import '@fontsource/inter/200.css';
|
import '@fontsource/inter/200.css';
|
||||||
@@ -9,7 +47,40 @@
|
|||||||
import '@fontsource/inter/800.css';
|
import '@fontsource/inter/800.css';
|
||||||
import '@fontsource/inter/900.css';
|
import '@fontsource/inter/900.css';
|
||||||
import '$scss/index.scss';
|
import '$scss/index.scss';
|
||||||
import { dev } from '$app/environment';
|
import { browser, dev } from '$app/environment';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import { navigating, page } from '$app/stores';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
function applyTheme(theme: Omit<Theme, 'system'>) {
|
||||||
|
const className = `theme-${theme}`;
|
||||||
|
document.body.classList.add(className);
|
||||||
|
document.body.classList.remove(`theme-${theme === 'dark' ? 'light' : 'dark'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const initialTheme = $page.route.id?.startsWith('/docs') ? getPreferredTheme() : 'dark';
|
||||||
|
applyTheme(initialTheme);
|
||||||
|
|
||||||
|
currentTheme.subscribe((theme) => applyTheme(theme));
|
||||||
|
navigating.subscribe((n) => {
|
||||||
|
if (!n?.to) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isDocs = n.to.route.id?.startsWith('/docs');
|
||||||
|
|
||||||
|
if (isDocs) {
|
||||||
|
console.log('isDocs');
|
||||||
|
if (!document.body.classList.contains(`theme-${$currentTheme}`)) {
|
||||||
|
console.log('set 123');
|
||||||
|
applyTheme($currentTheme);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
applyTheme('dark');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|||||||
Reference in New Issue
Block a user