Working on dynamic theme

This commit is contained in:
2023-05-02 23:19:18 +02:00
parent c05d1a9e6e
commit 6640b319f0
10 changed files with 122 additions and 24 deletions

View File

@@ -5,6 +5,10 @@ export default defineNuxtConfig({
transpile: ['trpc-nuxt'], transpile: ['trpc-nuxt'],
}, },
css: [
'@/assets/css/main.scss',
],
modules: [ modules: [
'@pinia/nuxt', '@pinia/nuxt',
'@pinia-plugin-persistedstate/nuxt', '@pinia-plugin-persistedstate/nuxt',
@@ -17,6 +21,13 @@ export default defineNuxtConfig({
'nuxt-icon', 'nuxt-icon',
], ],
colorMode: {
preference: 'system',
fallback: 'light',
classPrefix: '',
classSuffix: '',
},
devtools: { devtools: {
enabled: true, enabled: true,
vscode: { vscode: {

View File

@@ -36,6 +36,8 @@
"@types/node": "^18", "@types/node": "^18",
"@unocss/eslint-config": "^0.51.8", "@unocss/eslint-config": "^0.51.8",
"@unocss/nuxt": "^0.51.8", "@unocss/nuxt": "^0.51.8",
"@unocss/transformer-directives": "^0.51.8",
"@unocss/transformer-variant-group": "^0.51.8",
"@vueuse/core": "^10.1.0", "@vueuse/core": "^10.1.0",
"@vueuse/nuxt": "^10.1.0", "@vueuse/nuxt": "^10.1.0",
"eslint": "^8.39.0", "eslint": "^8.39.0",

4
src/assets/css/main.scss Normal file
View File

@@ -0,0 +1,4 @@
body {
font-family: 'DM Sans', sans-serif;
@apply bg-gray-100 dark:bg-dark-900 dark:text-white duration-200
}

View File

@@ -48,9 +48,9 @@ export const useTheme = () => {
case ColorsTheme.YELLOW: case ColorsTheme.YELLOW:
return 'bg-yellow-500' return 'bg-yellow-500'
case ColorsTheme.BLACK: case ColorsTheme.BLACK:
return 'bg-black dark:(bg-white text-black) text-white' return 'bg-black dark:bg-white dark:text-black text-white'
case ColorsTheme.WHITE: case ColorsTheme.WHITE:
return 'bg-black dark:(bg-white text-black) text-white' return 'bg-black dark:bg-white dark:text-black text-white'
} }
}) })

View File

@@ -1,20 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import { useThemeStore } from '~/store/theme' import { useThemeStore } from '~/store/theme'
const { getColor, getTheme, nextColor, nextTheme } = useThemeStore() const { getColor, getTheme, swapColor, nextTheme } = useThemeStore()
const { getThemeTextColor, getThemeBackgroundColor } = useTheme() const { getThemeTextColor, getThemeBackgroundColor } = useTheme()
onMounted(() => swapColor())
const { query } = useRoute() const { query } = useRoute()
const { $trpc } = useNuxtApp() const { $trpc } = useNuxtApp()
const color = useColorMode()
const user = await $trpc.hello.query({ name: query.name?.toString() }) const user = await $trpc.hello.query({ name: query.name?.toString() })
</script> </script>
<template> <template>
<section> <section>
<h1 :class="`text-sm ${getThemeTextColor}`"> <h1 :class="`${getThemeTextColor}`" duration="1000">
Main page Main page
</h1> </h1>
<h1 :class="`${getThemeBackgroundColor}`"> <h1 :class="`${getThemeBackgroundColor}`" duration="1000">
Main Page Main Page
</h1> </h1>
<div> <div>
@@ -26,12 +29,12 @@ const user = await $trpc.hello.query({ name: query.name?.toString() })
<div> <div>
Theme colors : {{ getTheme.colors.map((color) => color.charAt(0).toUpperCase() + color.slice(1)).join(', ') }} Theme colors : {{ getTheme.colors.map((color) => color.charAt(0).toUpperCase() + color.slice(1)).join(', ') }}
</div> </div>
<div @click="nextColor()">
setNextColor()
</div>
<div @click="nextTheme()"> <div @click="nextTheme()">
setNextTheme() setNextTheme()
</div> </div>
<div @click="color.preference = color.value === 'dark' ? 'light' : 'dark'">
toggleDarkMode()
</div>
<div> <div>
{{ user.greeting }} {{ user.greeting }}
</div> </div>

View File

@@ -8,7 +8,7 @@ export const appRouter = router({
})) }))
.query(({ input }) => { .query(({ input }) => {
return { return {
greeting: `Hello ${input.name ?? 'world'}!`, greeting: `Hello ${input.name ?? 'World'}!`,
} }
}), }),
}) })

View File

@@ -7,20 +7,47 @@ export const useThemeStore = defineStore(
() => { () => {
const currentTheme = ref<Theme>(Themes[THEMES.RainbowTheme]) const currentTheme = ref<Theme>(Themes[THEMES.RainbowTheme])
const currentColor = ref<ColorsTheme>(currentTheme.value.colors[0]) const currentColor = ref<ColorsTheme>(currentTheme.value.colors[0])
let intervalId: NodeJS.Timeout | null = null
const isAvailable = (next: Theme): boolean => {
if (!next.availability)
return true
const today = new Date()
const [startDay, startMonth] = next.availability.start.split('/')
const [endDay, endMonth] = next.availability.end.split('/')
const start = new Date(today.getFullYear(), Number(startMonth) - 1, Number(startDay))
const end = new Date(today.getFullYear(), Number(endMonth) - 1, Number(endDay))
return today >= start && today <= end
}
const swapColor = () => {
if (intervalId !== null)
clearInterval(intervalId)
intervalId = setInterval(() => {
const colors = currentTheme.value.colors
const currentIndex = colors.indexOf(currentColor.value)
const nextIndex = (currentIndex + 1) % colors.length
currentColor.value = colors[nextIndex]
}, 5000)
}
const nextTheme = () => { const nextTheme = () => {
const themes = Object.values(Themes) const themes = Object.values(Themes)
const currentIndex = themes.findIndex(theme => theme.name === currentTheme.value.name) const currentIndex = themes.findIndex(theme => theme.name === currentTheme.value.name)
const nextIndex = (currentIndex + 1) % themes.length let nextIndex = (currentIndex + 1) % themes.length
while (!isAvailable(themes[nextIndex])) {
nextIndex = (nextIndex + 1) % themes.length
if (nextIndex === currentIndex)
return
}
currentTheme.value = themes[nextIndex] currentTheme.value = themes[nextIndex]
currentColor.value = currentTheme.value.colors[0] currentColor.value = currentTheme.value.colors[0]
} swapColor()
const nextColor = () => {
const colors = currentTheme.value.colors
const currentIndex = colors.indexOf(currentColor.value)
const nextIndex = (currentIndex + 1) % colors.length
currentColor.value = colors[nextIndex]
} }
const getTheme = computed(() => currentTheme) const getTheme = computed(() => currentTheme)
@@ -30,7 +57,7 @@ export const useThemeStore = defineStore(
getTheme, getTheme,
getColor, getColor,
nextTheme, nextTheme,
nextColor, swapColor,
} }
}, },
{ {

View File

@@ -1,3 +1,4 @@
// Define a theme
export enum ColorsTheme { export enum ColorsTheme {
ORANGE = 'orange', ORANGE = 'orange',
YELLOW = 'yellow', YELLOW = 'yellow',
@@ -14,8 +15,13 @@ export enum ColorsTheme {
export interface Theme { export interface Theme {
name: String name: String
colors: ColorsTheme[] colors: ColorsTheme[]
availability?: {
start: String
end: String
}
} }
// Create the themes
const RainbowTheme: Theme = { const RainbowTheme: Theme = {
name: 'Rainbow', name: 'Rainbow',
colors: [ colors: [
@@ -32,11 +38,19 @@ const RainbowTheme: Theme = {
const XMasTheme: Theme = { const XMasTheme: Theme = {
name: 'Xmas', name: 'Xmas',
colors: [ColorsTheme.RED, ColorsTheme.GREEN], colors: [ColorsTheme.RED, ColorsTheme.GREEN],
availability: {
start: '01/12',
end: '31/12',
},
} }
const EasterTheme: Theme = { const EasterTheme: Theme = {
name: 'Easter', name: 'Easter',
colors: [ColorsTheme.ROSE, ColorsTheme.YELLOW, ColorsTheme.CYAN], colors: [ColorsTheme.ROSE, ColorsTheme.YELLOW, ColorsTheme.CYAN],
availability: {
start: '01/04',
end: '12/04',
},
} }
const BlackAndWhiteTheme: Theme = { const BlackAndWhiteTheme: Theme = {
@@ -44,11 +58,40 @@ const BlackAndWhiteTheme: Theme = {
colors: [ColorsTheme.BLACK, ColorsTheme.WHITE], colors: [ColorsTheme.BLACK, ColorsTheme.WHITE],
} }
const HalloweenTheme: Theme = {
name: 'Halloween',
colors: [
ColorsTheme.ORANGE,
ColorsTheme.BLACK,
ColorsTheme.GREEN,
ColorsTheme.PURPLE,
],
availability: {
start: '28/10',
end: '01/11',
},
}
const ValentineTheme: Theme = {
name: 'Valentine',
colors: [
ColorsTheme.RED,
ColorsTheme.ROSE,
],
availability: {
start: '12/02',
end: '16/02',
},
}
// List the themes
export enum THEMES { export enum THEMES {
RainbowTheme, RainbowTheme,
EasterTheme, EasterTheme,
XMasTheme, XMasTheme,
BlackAndWhiteTheme, BlackAndWhiteTheme,
ValentineTheme,
HalloweenTheme,
} }
export const Themes = { export const Themes = {
@@ -56,4 +99,6 @@ export const Themes = {
[THEMES.EasterTheme]: EasterTheme, [THEMES.EasterTheme]: EasterTheme,
[THEMES.XMasTheme]: XMasTheme, [THEMES.XMasTheme]: XMasTheme,
[THEMES.BlackAndWhiteTheme]: BlackAndWhiteTheme, [THEMES.BlackAndWhiteTheme]: BlackAndWhiteTheme,
[THEMES.ValentineTheme]: ValentineTheme,
[THEMES.HalloweenTheme]: HalloweenTheme,
} }

View File

@@ -1,8 +1,9 @@
import { import {
defineConfig, presetAttributify, presetIcons, defineConfig, presetAttributify, presetIcons,
presetTypography, presetUno, presetWind, presetTypography, presetUno, presetWind,
transformerDirectives, transformerVariantGroup,
} from 'unocss' } from 'unocss'
import transformerVariantGroup from '@unocss/transformer-variant-group'
import transformerDirectives from '@unocss/transformer-directives'
import { presetScrollbar } from 'unocss-preset-scrollbar' import { presetScrollbar } from 'unocss-preset-scrollbar'
import { ColorsTheme } from './types' import { ColorsTheme } from './types'
@@ -13,16 +14,21 @@ export default defineConfig({
presetIcons(), presetIcons(),
presetTypography(), presetTypography(),
presetScrollbar(), presetScrollbar(),
presetWind(), presetWind({
dark: 'class',
}),
], ],
transformers: [ transformers: [
transformerDirectives(), transformerDirectives(),
transformerVariantGroup(), transformerVariantGroup(),
], ],
safelist: [ safelist: [
// Theme text colors
...Object.values(ColorsTheme).map(color => `text-${color}-500`), ...Object.values(ColorsTheme).map(color => `text-${color}-500`),
'text-white', 'text-black', ...'bg-black dark:bg-white dark:text-black text-white'.split(' '),
// Theme background colors
...Object.values(ColorsTheme).map(color => `bg-${color}-500`), ...Object.values(ColorsTheme).map(color => `bg-${color}-500`),
'bg-white', 'bg-black', ...'text-black dark:text-white'.split(' '),
], ],
}) })

View File

@@ -1745,7 +1745,7 @@
dependencies: dependencies:
"@unocss/core" "0.51.8" "@unocss/core" "0.51.8"
"@unocss/transformer-directives@0.51.8": "@unocss/transformer-directives@0.51.8", "@unocss/transformer-directives@^0.51.8":
version "0.51.8" version "0.51.8"
resolved "https://registry.yarnpkg.com/@unocss/transformer-directives/-/transformer-directives-0.51.8.tgz#4fee9fa3fb97dbacc744a21f88b45eff5e835698" resolved "https://registry.yarnpkg.com/@unocss/transformer-directives/-/transformer-directives-0.51.8.tgz#4fee9fa3fb97dbacc744a21f88b45eff5e835698"
integrity sha512-Q1vG0dZYaxbdz0pVnvpuFreGoSqmrk7TgKUHNuJP/XzTi04sriQoDSpC2QMIAuOyU7FyGpSjUORiaBm0/VNURw== integrity sha512-Q1vG0dZYaxbdz0pVnvpuFreGoSqmrk7TgKUHNuJP/XzTi04sriQoDSpC2QMIAuOyU7FyGpSjUORiaBm0/VNURw==
@@ -1753,7 +1753,7 @@
"@unocss/core" "0.51.8" "@unocss/core" "0.51.8"
css-tree "^2.3.1" css-tree "^2.3.1"
"@unocss/transformer-variant-group@0.51.8": "@unocss/transformer-variant-group@0.51.8", "@unocss/transformer-variant-group@^0.51.8":
version "0.51.8" version "0.51.8"
resolved "https://registry.yarnpkg.com/@unocss/transformer-variant-group/-/transformer-variant-group-0.51.8.tgz#342fdade1ece77a0874fd6ff9903c111de1bdfe0" resolved "https://registry.yarnpkg.com/@unocss/transformer-variant-group/-/transformer-variant-group-0.51.8.tgz#342fdade1ece77a0874fd6ff9903c111de1bdfe0"
integrity sha512-blFQtAntyijFOm+BiiQhroaPwFNX6zYi19wUjY6NdvMAl/g4JzOFTzo+KehQf+lCI3Dvhr8Z2dGtDcnwfqUcDg== integrity sha512-blFQtAntyijFOm+BiiQhroaPwFNX6zYi19wUjY6NdvMAl/g4JzOFTzo+KehQf+lCI3Dvhr8Z2dGtDcnwfqUcDg==