Skip to content

Commit

Permalink
feat(ui/web): move theme handling to ui package
Browse files Browse the repository at this point in the history
Signed-off-by: Jordan Shatford <[email protected]>
  • Loading branch information
jordanshatford committed Sep 13, 2023
1 parent 5a440aa commit 7cb9137
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 70 deletions.
13 changes: 0 additions & 13 deletions apps/web/src/lib/components/ThemeChangeIcon.svelte

This file was deleted.

54 changes: 0 additions & 54 deletions apps/web/src/lib/stores/theme.ts

This file was deleted.

5 changes: 2 additions & 3 deletions apps/web/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
import '../app.css';
import { onMount } from 'svelte';
import { page } from '$app/stores';
import { Toasts, NavBar, Footer } from '@yd/ui';
import { Toasts, NavBar, Footer, ThemeToggle } from '@yd/ui';
import Loading from '$lib/components/Loading.svelte';
import { session } from '$lib/stores/session';
import { downloads } from '$lib/stores/downloads';
import config from '$lib/config';
import { RoutePathConstants, links } from '$lib/utils/route';
import Logo from '$lib/components/Logo.svelte';
import ThemeChangeIcon from '$lib/components/ThemeChangeIcon.svelte';
// Use session as token when making requests with client
OpenAPI.TOKEN = async () => {
Expand All @@ -38,7 +37,7 @@
<div class="h-full">
<NavBar {links} activeLink={$page.url.pathname}>
<Logo slot="logo" />
<ThemeChangeIcon slot="right" />
<ThemeToggle slot="right" />
</NavBar>
<main class="mx-auto h-full max-w-7xl px-4 pt-20 sm:px-6 lg:px-8">
<slot />
Expand Down
11 changes: 11 additions & 0 deletions packages/ui/src/lib/components/theme/ThemeToggle.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script lang="ts">
import IconButton from '../IconButton.svelte';
import { MoonIcon, SunIcon } from '../../icons';
import { theme } from './store';
</script>

<IconButton
on:click={() => theme.toggle()}
src={$theme === 'dark' ? SunIcon : MoonIcon}
class="h-10 w-10 text-zinc-500 hover:text-indigo-800 dark:bg-zinc-800 dark:text-zinc-200 dark:hover:text-indigo-600"
/>
2 changes: 2 additions & 0 deletions packages/ui/src/lib/components/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { theme } from './store';
export { default as ThemeToggle } from './ThemeToggle.svelte';
61 changes: 61 additions & 0 deletions packages/ui/src/lib/components/theme/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { writable } from 'svelte/store';
import { browser } from '../../utilities';

type Theme = 'dark' | 'light';

const THEME_LOCALSTORAGE_KEY = 'theme';
const DEFAULT_THEME: Theme = 'light';

// Get the default theme value inferred by the browser settings.
function getInferredDefaultTheme(): Theme {
if (browser()) {
// Cant match preferred color scheme, return default.
if (!window.matchMedia) {
return DEFAULT_THEME;
}
// Use dark theme if preferred by the user.
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
} else {
return 'light';
}
} else {
return DEFAULT_THEME;
}
}

function createThemeStore() {
const { subscribe, set, update } = writable<Theme>(getInferredDefaultTheme());

if (browser()) {
let data = localStorage?.getItem(THEME_LOCALSTORAGE_KEY) as Theme;
if (!data) {
data = getInferredDefaultTheme();
}
set(data);
if (data === 'dark') {
document.querySelector('html')?.classList.add('dark');
}
}

subscribe((value) => {
if (browser()) {
localStorage?.setItem(THEME_LOCALSTORAGE_KEY, value);
}
});

function toggle() {
update((state) => {
state = state === 'dark' ? 'light' : 'dark';
return state;
});
document.querySelector('html')?.classList.toggle('dark');
}

return {
subscribe,
toggle
};
}

export const theme = createThemeStore();
1 change: 1 addition & 0 deletions packages/ui/src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Component exports
export { NavBar } from './components/nav';
export { ThemeToggle, theme } from './components/theme';
export { Toast, Toasts, toast } from './components/toast';
export { Description, List, Title } from './components/typography';
export { default as Alert, type AlertVariants } from './components/Alert.svelte';
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/src/lib/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,9 @@ export function toIcon(value: unknown, extras?: { loading?: boolean }): IconSour
return undefined;
}
}

/**
* Helper function to check if running in browser
* @returns true when running in browser, false otherwise
*/
export const browser = () => typeof window !== 'undefined';

1 comment on commit 7cb9137

@vercel
Copy link

@vercel vercel bot commented on 7cb9137 Sep 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.