Skip to content

Commit

Permalink
Add the toolbar button for theme switching
Browse files Browse the repository at this point in the history
  • Loading branch information
obulat committed Sep 18, 2024
1 parent fe37093 commit effb9d2
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 42 deletions.
38 changes: 0 additions & 38 deletions frontend/.storybook/decorators/with-theme-switcher.js

This file was deleted.

79 changes: 79 additions & 0 deletions frontend/.storybook/decorators/with-theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { watch, onMounted, reactive, h } from "vue"
import { useEffect } from "@storybook/preview-api"

import { EffectiveColorMode } from "~/types/ui"

import { useDarkMode } from "~/composables/use-dark-mode"
import { useUiStore } from "~/stores/ui"

import VThemeSelect from "~/components/VThemeSelect/VThemeSelect.vue"

const themeState = reactive<{ value: EffectiveColorMode }>({ value: "light" })

const setElementTheme = (
el: HTMLElement,
cssClass: `${EffectiveColorMode}-mode`
) => {
if (cssClass === "dark-mode") {
el.classList.add("dark-mode")
el.classList.remove("light-mode")
} else {
el.classList.add("light-mode")
el.classList.remove("dark-mode")
}
}

/**
* Decorator to add the Storybook theme switcher to the addon toolbar, and the Openverse
* theme switcher to the bottom of the screen.
* We cannot use the toolbar during the tests that open an iframe without the toolbars,
* so we need to add the theme switcher to the bottom of the screen.
* The state of both is kept in sync.
*/
export const WithTheme = (story, context) => {
useEffect(() => {
themeState.value = context.globals.theme
}, [context.globals.theme])

return {
components: { story },
setup() {
const { cssClass } = useDarkMode()
const uiStore = useUiStore()

onMounted(() => {
document.body.classList.add("bg-default")

watch(
themeState,
(newTheme) => {
if (["light", "dark"].includes(newTheme.value)) {
uiStore.setColorMode(newTheme.value)
}
},
{ immediate: true }
)

watch(
cssClass,
(newCssClass) => {
setElementTheme(document.body, newCssClass)
},
{ immediate: true }
)
})

// Set the height to the full height of the Storybook iframe minus the padding
// to position the theme switcher at the bottom of the screen.
return () =>
h("div", { class: "relative", style: "height: calc(100dvh - 32px);" }, [
h(story()),
h(
"div",
{ class: "absolute bottom-0", id: "storybook-theme-switcher" },
[h(VThemeSelect)]
),
])
},
}
}
25 changes: 21 additions & 4 deletions frontend/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,27 @@ import { VIEWPORTS } from "~/constants/screens"

import { WithUiStore } from "~~/.storybook/decorators/with-ui-store"
import { WithRTL } from "~~/.storybook/decorators/with-rtl"

import { WithThemeSwitcher } from "~~/.storybook/decorators/with-theme-switcher"
import { WithTheme } from "~~/.storybook/decorators/with-theme"

import type { Preview } from "@storybook/vue3"

const preview: Preview = {
decorators: [WithRTL, WithUiStore, WithThemeSwitcher],
decorators: [WithRTL, WithUiStore, WithTheme],
globalTypes: {
theme: {
name: "Theme",
description: "Color theme",
table: {
defaultValue: { summary: "light" },
},
toolbar: {
icon: "circlehollow",
items: [
{ value: "light", title: "Light" },
{ value: "dark", title: "Dark" },
],
},
},
languageDirection: {
name: "RTL",
description: "Simulate an RTL language.",
Expand All @@ -27,7 +40,6 @@ const preview: Preview = {
},
parameters: {
backgrounds: {
default: "light",
values: [
{ name: "light", value: "#ffffff" },
{ name: "dark", value: "#0d0d0d" },
Expand All @@ -44,6 +56,11 @@ const preview: Preview = {
},
},
},
initialGlobals: {
theme: "light",
languageDirection: "ltr",
backgrounds: { value: "light" },
},
}

export default preview

0 comments on commit effb9d2

Please sign in to comment.