Skip to content

Commit

Permalink
feat: add multi class themes
Browse files Browse the repository at this point in the history
  • Loading branch information
Makisuo committed Jan 22, 2024
1 parent 350f653 commit a175fef
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 33 deletions.
Empty file added CHANGELOG.md
Empty file.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,33 @@ If your Qwik app uses a class to style the page based on the theme, change the a

Now, setting the theme to "dark" will set `class="dark"` on the `html` element.

### Multi Class Themes

You can also use multi Class Themes like `[dark, skeumorphic]`


```tsx
<ThemeProvider
themes={[
["simple", "light-yellow"],
["simple", "dark-yellow"],
["brutalist", "light-yellow"],
["brutalist", "dark-yellow"],
["hand-drawn", "light"],
["hand-drawn", "dark"],
]
}>
```

and then you can simply change the theme as before, just with your arrays instead!

```tsx
const { setTheme } = useTheme()

setTheme(["simple", "light-yellow"])
```


### Force page to a theme
TODO

Expand Down
Binary file modified bun.lockb
Binary file not shown.
33 changes: 18 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"types": "./lib-types/index.d.ts"
}
},
"files": ["lib", "lib-types"],
"files": [
"lib",
"lib-types"
],
"engines": {
"node": ">=15.0.0"
},
Expand All @@ -33,20 +36,20 @@
"qwik": "qwik"
},
"devDependencies": {
"@builder.io/qwik": "1.2.10",
"@types/eslint": "8.44.1",
"@types/node": "^20.4.5",
"@typescript-eslint/eslint-plugin": "6.2.0",
"@typescript-eslint/parser": "6.2.0",
"eslint": "8.45.0",
"@builder.io/qwik": "1.4.0",
"@types/eslint": "8.56.2",
"@types/node": "^20.11.5",
"@typescript-eslint/eslint-plugin": "6.19.1",
"@typescript-eslint/parser": "6.19.1",
"eslint": "8.56.0",
"eslint-plugin-qwik": "latest",
"np": "7.6.1",
"prettier": "3.0.0",
"typescript": "5.1.6",
"undici": "5.22.1",
"vite": "4.4.7",
"vite-tsconfig-paths": "4.2.0",
"@biomejs/biome": "^1.1.2"
"np": "9.2.0",
"prettier": "3.2.4",
"typescript": "5.3.3",
"undici": "6.4.0",
"vite": "5.0.12",
"vite-tsconfig-paths": "4.3.1",
"@biomejs/biome": "^1.5.3"
},
"dependencies": {}
}
}
20 changes: 15 additions & 5 deletions src/lib/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const ThemeProvider = component$<ThemeProviderProps>(
value,
nonce,
}) => {
const attrs = !value ? themes : Object.values(value)
const attrs = !value ? themes.flat() : Object.values(value)

const applyTheme = $((theme: Theme) => {
let resolved = theme
Expand All @@ -44,14 +44,20 @@ export const ThemeProvider = component$<ThemeProviderProps>(
resolved = getSystemTheme()
}

const name = value ? value[resolved] : resolved
// Join the array of attr if the theme is an array
const computedResolved = Array.isArray(resolved)
? resolved.join(attribute === "class" ? " " : "-")
: resolved

const name = value ? value[computedResolved] : computedResolved

disableTransitionOnChange ? disableAnimation() : null
const d = document.documentElement

if (attribute === "class") {
d.classList.remove(...attrs)

if (name) d.classList.add(name)
if (name) d.classList.add(...name.split(" "))
} else {
if (name) {
d.setAttribute(attribute, name)
Expand All @@ -74,13 +80,17 @@ export const ThemeProvider = component$<ThemeProviderProps>(
this.theme = theme

try {
localStorage.setItem(storageKey, theme as string)
localStorage.setItem(storageKey, Array.isArray(theme) ? theme.join(" ") : (theme as string))
} catch (e) {
// Unsupported
}
}),
forcedTheme,
themes: enableSystem ? [...themes, "system"] : themes,
themes: enableSystem
? Array.isArray(themes[0])
? [...(themes as string[][]), ["system"]]
: [...(themes as string[]), "system"]
: themes,
systemTheme: (enableSystem ? resolvedThemeStore.value : undefined) as "light" | "dark" | undefined,
})

Expand Down
8 changes: 4 additions & 4 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ interface ValueObject {

export type SystemTheme = "dark" | "light"

export type Theme = "dark" | "light" | (string & {}) | undefined
export type Theme = "dark" | "light" | (string & {}) | string[] | undefined

export interface UseThemeProps {
/** List of all available theme names */
themes: string[]
themes: string[] | string[][]
/** Forced theme name for the current page */
forcedTheme?: string | undefined
/** Update the theme */
Expand All @@ -26,7 +26,7 @@ export interface UseThemeProps {

export interface ThemeProviderProps {
/** List of all available theme names */
themes?: string[] | undefined
themes?: string[] | string[][] | undefined
/** Forced theme name for the current page */
forcedTheme?: string | undefined
/** Whether to switch between dark and light themes based on prefers-color-scheme */
Expand All @@ -40,7 +40,7 @@ export interface ThemeProviderProps {
/** Default theme name (for v0.0.12 and lower the default was light). If `enableSystem` is false, the default theme is light */
defaultTheme?: string | undefined
/** HTML attribute modified based on the active theme. Accepts `class` and `data-*` (meaning any data attribute, `data-mode`, `data-color`, etc.) */
attribute?: string | "class" | undefined
attribute?: "class" | (string & {}) | undefined
/** Mapping of theme name to HTML attribute value. Object where key is the theme name and value is the attribute value */
value?: ValueObject | undefined
/** Nonce string to pass to the inline script for CSP headers */
Expand Down
18 changes: 15 additions & 3 deletions src/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@ export default () => {
<meta charSet="utf-8" />
<title>Qwik Blank App</title>
</head>
<body class="dark">
<ThemeProvider>
<div>Cool</div>
<body>
<ThemeProvider
themes={[
["simple", "light-yellow"],
["simple", "dark-yellow"],
["brutalist", "light-yellow"],
["brutalist", "dark-yellow"],
["hand-drawn", "light"],
["hand-drawn", "dark"],
]}
// themes={["dark", "light"]}
attribute="class"
// defaultTheme="dark"
>
<div>Nested Theme test</div>
<Test />
</ThemeProvider>
</body>
Expand Down
31 changes: 25 additions & 6 deletions src/test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,39 @@ import { component$ } from "@builder.io/qwik"
import { useTheme } from "./lib/provider"

export const Test = component$(() => {
const { theme, setTheme, resolvedTheme } = useTheme()
console.log(theme, resolvedTheme)
const { theme, setTheme, themes, resolvedTheme } = useTheme()
console.log(theme, themes, resolvedTheme)
return (
<div>
{theme}
<button
<div
style={{
display: "flex",
flexDirection: "column",
gap: 4,
}}
>
{theme?.toString()}
{themes?.map((theme) => (
<button
key={theme.toString()}
type="button"
onClick$={() => {
console.log(theme)
setTheme(theme)
}}
>
{theme.toString()}
</button>
))}

{/* <button
type="button"
onClick$={() => {
setTheme(theme === "dark" ? "light" : "dark")
// themeSig.value = themeSig.value === "dark" ? "light" : "dark"
}}
>
Toggle
</button>
</button> */}
</div>
)
})

0 comments on commit a175fef

Please sign in to comment.