Darkmode cookie fix (#38)

This commit is contained in:
Ben Allfree 2022-10-26 13:04:31 -07:00 committed by GitHub
parent a149df0d58
commit 22e6966fcb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 80 additions and 55 deletions

View File

@ -6,3 +6,12 @@ export function assertExists<TType>(
throw new Error(message)
}
}
export function assertTruthy<TType>(
v: unknown,
message = `Value should be truthy`
): asserts v is NonNullable<TType> {
if (!v) {
throw new Error(message)
}
}

View File

@ -28,6 +28,8 @@
"dependencies": {
"@pockethost/common": "0.0.1",
"@s-libs/micro-dash": "12",
"@types/js-cookie": "^3.0.2",
"js-cookie": "^3.0.1",
"pocketbase": "^0.7.0",
"random-word-slugs": "^0.1.6",
"sass": "^1.54.9",

View File

@ -1,76 +1,66 @@
<script lang="ts">
import { browser } from '$app/environment'
import { assertTruthy } from '@pockethost/common'
import { find } from '@s-libs/micro-dash'
import Cookies from 'js-cookie'
import { onMount } from 'svelte'
// Set some default values to be referenced later
enum ThemeNames {
Light = 'light',
Dark = 'dark'
}
const ALLOWED_THEMES: ThemeNames[] = [ThemeNames.Light, ThemeNames.Dark]
const DEFAULT_THEME: ThemeNames = ThemeNames.Light
const STORAGE_NAME: string = 'theme'
const THEME_ATTRIBUTE: string = 'data-theme'
const THEME_ICONS: { [_ in ThemeNames]: string } = {
[ThemeNames.Light]: 'bi bi-moon-stars',
[ThemeNames.Dark]: 'bi bi-brightness-high'
}
const html = () => {
const htmlElement = document.querySelector('html')
assertTruthy(htmlElement, `Expected <html> element to exist`)
return htmlElement
}
const currentTheme = () => {
const htmlElement = html()
const _att = htmlElement.getAttribute(THEME_ATTRIBUTE)
const currentTheme = find(ALLOWED_THEMES, (v) => _att === v) || DEFAULT_THEME
return currentTheme
}
const currentIcon = () => {
return THEME_ICONS[currentTheme()]
}
// This can change the CSS a bit depending on where the theme toggle is rendered
export let navLink: boolean = false
// Set the default icon to be light mode
let iconClass: string = 'bi bi-moon-stars'
// Set some default values to be referenced later
const STORAGE_NAME: string = 'theme'
const THEME_ATTRIBUTE: string = 'data-theme'
// FIXME: I don't think these enums are right
enum PossibleThemeValues {
Dark = {
icon: 'bi bi-brightness-high',
theme: 'dark'
},
Light = {
icon: 'bi bi-moon-stars',
theme: 'light'
}
}
// This will track the user's theme throughout the app
let localStorageTheme = ''
let iconClass: string = browser ? currentIcon() : ''
// Wait for the DOM to be available
onMount(() => {
// First get the site default theme
const htmlElement: Element = document.querySelector('html')
const currentTheme: string = htmlElement.getAttribute(THEME_ATTRIBUTE)
// If this is the user's first time on the site, set the default theme
if (localStorage.getItem(STORAGE_NAME) === null) {
localStorage.setItem(STORAGE_NAME, currentTheme)
}
// Now get the user's theme value
localStorageTheme = localStorage.getItem(STORAGE_NAME)
// If the storage item is different from the HTML theme attribute, update the HTML
if (localStorageTheme === 'light') {
updateTheme(PossibleThemeValues.Light)
} else {
updateTheme(PossibleThemeValues.Dark)
}
updateTheme(currentTheme())
})
// Alternate the theme values on toggle click
const handleClick = () => {
// Get the user's current theme setting
localStorageTheme = localStorage.getItem(STORAGE_NAME)
if (localStorageTheme === 'light') {
updateTheme(PossibleThemeValues.Dark)
} else {
updateTheme(PossibleThemeValues.Light)
}
const newTheme = currentTheme() === ThemeNames.Light ? ThemeNames.Dark : ThemeNames.Light
updateTheme(newTheme)
}
const updateTheme = (type: PossibleThemeValues) => {
const htmlElement: Element = document.querySelector('html')
const updateTheme = (themeName: ThemeNames) => {
const htmlElement = html()
// Update the icon class name to toggle between light and dark mode
iconClass = type['icon']
iconClass = THEME_ICONS[themeName]
// Update the HTML element to have the right data-theme value
htmlElement.setAttribute(THEME_ATTRIBUTE, type['theme'])
htmlElement.setAttribute(THEME_ATTRIBUTE, themeName)
// Now update the localStorage to have the latest value
localStorage.setItem(STORAGE_NAME, type['theme'])
Cookies.set(STORAGE_NAME, themeName)
}
</script>

View File

@ -2,6 +2,21 @@
import Navbar from '$components/Navbar.svelte'
</script>
<svelte:head>
<script>
{
const THEME_ATTRIBUTE = 'data-theme'
const currentTheme =
document.cookie
.split('; ')
.find((row) => row.startsWith('theme='))
?.split('=')?.[1] || 'light'
console.log(`Current theme is ${currentTheme}`)
document.querySelector('html')?.setAttribute(THEME_ATTRIBUTE, currentTheme)
console.log(document.querySelector('html'))
}
</script>
</svelte:head>
<Navbar />
<main data-sveltekit-prefetch>

View File

@ -35,8 +35,7 @@ export const createCleanupManagerAsync = () => {
return cleanup
}
const cleanupAll = () =>
reduce(cleanups, (c, v) => c.then(v()), Promise.resolve())
const cleanupAll = () => reduce(cleanups, (c, v) => c.then(v()), Promise.resolve())
return { add, cleanupAll }
}

View File

@ -924,6 +924,11 @@
dependencies:
"@types/node" "*"
"@types/js-cookie@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.2.tgz#451eaeece64c6bdac8b2dde0caab23b085899e0d"
integrity sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA==
"@types/node@*":
version "18.8.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.8.5.tgz#6a31f820c1077c3f8ce44f9e203e68a176e8f59e"
@ -1982,6 +1987,11 @@ is-reference@1.2.1:
dependencies:
"@types/estree" "*"
js-cookie@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"