From b13cbceab492dee06fd64e9bdebfad57847d4a9a Mon Sep 17 00:00:00 2001 From: kaan Date: Tue, 25 Apr 2023 11:49:44 +0200 Subject: [PATCH 1/8] chore: convert composable to a plugin Closes #11. --- src/composables/theme.ts | 48 ---------- src/main.ts | 6 +- src/plugins/themeManager/index.ts | 124 ++++++++++++++++++++++++++ src/plugins/themeManager/reactives.ts | 13 +++ tailwind.config.js | 69 ++++++++++++-- 5 files changed, 200 insertions(+), 60 deletions(-) delete mode 100644 src/composables/theme.ts create mode 100644 src/plugins/themeManager/index.ts create mode 100644 src/plugins/themeManager/reactives.ts diff --git a/src/composables/theme.ts b/src/composables/theme.ts deleted file mode 100644 index a157880..0000000 --- a/src/composables/theme.ts +++ /dev/null @@ -1,48 +0,0 @@ -type DaisThemes = - | 'light' - | 'dark' - | 'cupcake' - | 'bumblebee' - | 'emerald' - | 'corporate' - | 'synthwave' - | 'retro' - | 'cyberpunk' - | 'valentine' - | 'halloween' - | 'garden' - | 'forest' - | 'aqua' - | 'lofi' - | 'pastel' - | 'fantasy' - | 'wireframe' - | 'black' - | 'luxury' - | 'dracula' - | 'cmyk' - | 'autumn' - | 'business' - | 'acid' - | 'lemonade' - | 'night' - | 'coffee' - | 'winter' - -export const useThemeManager = () => { - const setTheme = (theme: DaisThemes | 'default') => { - document.documentElement.setAttribute('data-theme', theme) - } - const getTheme = () => { - return document.documentElement.getAttribute('data-theme') - } - const toggleDark = () => { - const currentTheme = getTheme() - if (currentTheme === 'dark') { - setTheme('light') - } else { - setTheme('dark') - } - } - return { setTheme, getTheme, toggleDark } -} diff --git a/src/main.ts b/src/main.ts index 0a8200b..9c51dce 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,12 @@ import { createApp } from 'vue' import App from './App.vue' import router from './router' - +import { createThemeManager } from './plugins/themeManager' import './assets/main.css' import './assets/style.css' const app = createApp(App) - -app.use(router) + .use(router) + .use(createThemeManager({ light: 'breeze', dark: 'storm', watchSystemTheme: true })) app.mount('#app') diff --git a/src/plugins/themeManager/index.ts b/src/plugins/themeManager/index.ts new file mode 100644 index 0000000..50145ec --- /dev/null +++ b/src/plugins/themeManager/index.ts @@ -0,0 +1,124 @@ +import type { App } from 'vue' +import { defaults, pluginInitiated, currentTheme, isDark } from './reactives' +export type DaisyThemes = + | 'default' + | 'storm' + | 'breeze' + | 'light' + | 'dark' + | 'cupcake' + | 'bumblebee' + | 'emerald' + | 'corporate' + | 'synthwave' + | 'retro' + | 'cyberpunk' + | 'valentine' + | 'halloween' + | 'garden' + | 'forest' + | 'aqua' + | 'lofi' + | 'pastel' + | 'fantasy' + | 'wireframe' + | 'black' + | 'luxury' + | 'dracula' + | 'cmyk' + | 'autumn' + | 'business' + | 'acid' + | 'lemonade' + | 'night' + | 'coffee' + | 'winter' + +export type ThemeOptions = { + light: DaisyThemes + dark: DaisyThemes + watchSystemTheme?: boolean +} + +export const useThemeManager = () => { + const options: ThemeOptions = { + light: defaults.light, + dark: defaults.dark, + watchSystemTheme: defaults.watchSystemTheme + } + + if (!pluginInitiated) { + defaults.light = options?.light as DaisyThemes + defaults.dark = options?.dark as DaisyThemes + defaults.watchSystemTheme = options?.watchSystemTheme + currentTheme.value = isDark.value ? defaults.dark : defaults.light + } + // Watch for system preferred theme changes + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (event) => { + isDark.value = event.matches + const theme = event.matches ? (defaults.dark as DaisyThemes) : (defaults.light as DaisyThemes) + if (defaults.watchSystemTheme === true) setTheme(theme) + }) + + // Set theme + const setTheme = (theme: DaisyThemes) => { + let _light = defaults.light as DaisyThemes + let _dark = defaults.dark as DaisyThemes + // if default, set theme based on system preferred theme and the default light and dark themes + let newTheme: DaisyThemes = 'default' + if (theme === 'default') newTheme = isDark.value ? _dark : _light + else newTheme = theme + + return document.documentElement.setAttribute('data-theme', (currentTheme.value = newTheme)) + } + setTheme(currentTheme.value) + // Get theme + const getTheme = () => { + return currentTheme.value + } + // Toggle dark mode, using default light and dark themes + const toggleDark = () => { + let _light = defaults.light as DaisyThemes + let _dark = defaults.dark as DaisyThemes + return document.documentElement.setAttribute( + 'data-theme', + (currentTheme.value = currentTheme.value === _light ? _dark : _light) + ) + } + // Set default light and dark themes + const setDefaults = (themes: { light?: DaisyThemes; dark?: DaisyThemes }) => { + defaults.light = themes.light ?? defaults.light + defaults.dark = themes.dark ?? defaults.dark + setTheme('default') + } + // Get default light and dark themes + const getDefaults = () => { + return { light: defaults.light, dark: defaults.dark } + } + const isWatchingSystemTheme = (bool?: boolean, updateTheme: boolean = true) => { + if (bool === undefined) return defaults.watchSystemTheme + if (bool && updateTheme) setTheme('default') + return (defaults.watchSystemTheme = bool) + } + + const themeManagerInstance = { + set: setTheme, + get: getTheme, + toggleDark, + setDefaults, + getDefaults, + watchSystemTheme: isWatchingSystemTheme + } + pluginInitiated.value = true + return { ...themeManagerInstance } +} + +export const createThemeManager = (options?: ThemeOptions) => { + return (app: App) => { + defaults.light = options?.light as DaisyThemes + defaults.dark = options?.dark as DaisyThemes + defaults.watchSystemTheme = options?.watchSystemTheme ?? true + app.config.globalProperties.$theme = useThemeManager() + } +} diff --git a/src/plugins/themeManager/reactives.ts b/src/plugins/themeManager/reactives.ts new file mode 100644 index 0000000..b9cd036 --- /dev/null +++ b/src/plugins/themeManager/reactives.ts @@ -0,0 +1,13 @@ +import { reactive, ref } from 'vue' +import type { DaisyThemes, ThemeOptions } from './index' +const isDark = ref( + window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches +) +const defaults = reactive({ + light: 'light', + dark: 'dark', + watchSystemTheme: false +}) +const currentTheme = ref('default') +const pluginInitiated = ref(false) +export { defaults, currentTheme, pluginInitiated, isDark } diff --git a/tailwind.config.js b/tailwind.config.js index 6148805..8c9221b 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,15 +1,66 @@ /** @type {import('tailwindcss').Config} */ -import daisyui from "daisyui" +import daisyui from 'daisyui' export default { - content: [ - "./index.html", - "./src/**/*.{vue,js,ts,jsx,tsx}", - ], + content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], theme: { - extend: {}, + extend: {} }, plugins: [daisyui], daisyui: { - themes: ["light", "dark", "cupcake", "bumblebee", "emerald", "corporate", "synthwave", "retro", "cyberpunk", "valentine", "halloween", "garden", "forest", "aqua", "lofi", "pastel", "fantasy", "wireframe", "black", "luxury", "dracula", "cmyk", "autumn", "business", "acid", "lemonade", "night", "coffee", "winter"], - }, -} \ No newline at end of file + themes: [ + { + storm: { + primary: '#9aa5ce', + secondary: '#565f89', + accent: '#bb9af7', + neutral: '#111827', + 'base-100': '#24283b', + info: '#2ac3de', + success: '#9ece6a', + warning: '#e0af68', + error: '#f7768e' + }, + breeze: { + primary: '#6807f0', + secondary: '#6b21a8', + accent: '#db2777', + neutral: '#170824', + 'base-100': '#f2f2f2', + info: '#2ac3de', + success: '#9ece6a', + warning: '#e0af68', + error: '#f7768e' + }, + }, + 'light', + 'dark', + 'cupcake', + 'bumblebee', + 'emerald', + 'corporate', + 'synthwave', + 'retro', + 'cyberpunk', + 'valentine', + 'halloween', + 'garden', + 'forest', + 'aqua', + 'lofi', + 'pastel', + 'fantasy', + 'wireframe', + 'black', + 'luxury', + 'dracula', + 'cmyk', + 'autumn', + 'business', + 'acid', + 'lemonade', + 'night', + 'coffee', + 'winter' + ] + } +} From 6ce728e5cdd94d2b55aa7596afe424e2c574452a Mon Sep 17 00:00:00 2001 From: kaan Date: Tue, 25 Apr 2023 11:50:18 +0200 Subject: [PATCH 2/8] chore: update About view --- src/views/AboutView.vue | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/views/AboutView.vue b/src/views/AboutView.vue index 756ad2a..afb0485 100644 --- a/src/views/AboutView.vue +++ b/src/views/AboutView.vue @@ -1,15 +1,29 @@ - From 580a676acc25419be428e413059202f8e743991e Mon Sep 17 00:00:00 2001 From: kaan Date: Tue, 25 Apr 2023 11:50:41 +0200 Subject: [PATCH 3/8] chore: added Theme Preview page --- src/App.vue | 5 +- src/components/WelcomeItem.vue | 10 +- src/router/index.ts | 7 +- src/views/ThemeView.vue | 180 +++++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 8 deletions(-) create mode 100644 src/views/ThemeView.vue diff --git a/src/App.vue b/src/App.vue index 7905b05..e4b51dc 100644 --- a/src/App.vue +++ b/src/App.vue @@ -13,6 +13,7 @@ import HelloWorld from './components/HelloWorld.vue' @@ -39,7 +40,7 @@ nav { } nav a.router-link-exact-active { - color: var(--color-text); + color: currentColor; } nav a.router-link-exact-active:hover { @@ -49,7 +50,7 @@ nav a.router-link-exact-active:hover { nav a { display: inline-block; padding: 0 1rem; - border-left: 1px solid var(--color-border); + border-left: 1px solid currentColor; } nav a:first-of-type { diff --git a/src/components/WelcomeItem.vue b/src/components/WelcomeItem.vue index ba0def3..ef8259d 100644 --- a/src/components/WelcomeItem.vue +++ b/src/components/WelcomeItem.vue @@ -30,14 +30,14 @@ i { width: 32px; height: 32px; - color: var(--color-text); + color: currentColor; } h3 { font-size: 1.2rem; font-weight: 500; margin-bottom: 0.4rem; - color: var(--color-heading); + color: theme('colors.accent'); } @media (min-width: 1024px) { @@ -51,7 +51,7 @@ h3 { left: -26px; position: absolute; border: 1px solid var(--color-border); - background: var(--color-background); + background: #f2f2f2; border-radius: 8px; width: 50px; height: 50px; @@ -59,7 +59,7 @@ h3 { .item:before { content: ' '; - border-left: 1px solid var(--color-border); + border-left: 1px solid currentColor; position: absolute; left: 0; bottom: calc(50% + 25px); @@ -68,7 +68,7 @@ h3 { .item:after { content: ' '; - border-left: 1px solid var(--color-border); + border-left: 1px solid currentColor; position: absolute; left: 0; top: calc(50% + 25px); diff --git a/src/router/index.ts b/src/router/index.ts index 6cbe46a..63b4a7b 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,6 +1,6 @@ import { createRouter, createWebHashHistory } from 'vue-router' import HomeView from '../views/HomeView.vue' - +import ThemeView from '../views/ThemeView.vue' const router = createRouter({ history: createWebHashHistory(import.meta.env.BASE_URL), routes: [ @@ -16,6 +16,11 @@ const router = createRouter({ // this generates a separate chunk (About.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import('../views/AboutView.vue') + }, + { + path: '/theme-preview', + name: 'theme-preview', + component: () => import('../views/ThemeView.vue') } ] }) diff --git a/src/views/ThemeView.vue b/src/views/ThemeView.vue new file mode 100644 index 0000000..5171122 --- /dev/null +++ b/src/views/ThemeView.vue @@ -0,0 +1,180 @@ + + + + + From 58ee2744a185768330db5eee165496cacdb80b7b Mon Sep 17 00:00:00 2001 From: kaan Date: Tue, 25 Apr 2023 13:17:37 +0200 Subject: [PATCH 4/8] chore: refactored daisy theme types --- src/plugins/themeManager/index.ts | 69 ++++++++++++++++--------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/plugins/themeManager/index.ts b/src/plugins/themeManager/index.ts index 50145ec..0e13e38 100644 --- a/src/plugins/themeManager/index.ts +++ b/src/plugins/themeManager/index.ts @@ -1,39 +1,40 @@ import type { App } from 'vue' import { defaults, pluginInitiated, currentTheme, isDark } from './reactives' -export type DaisyThemes = - | 'default' - | 'storm' - | 'breeze' - | 'light' - | 'dark' - | 'cupcake' - | 'bumblebee' - | 'emerald' - | 'corporate' - | 'synthwave' - | 'retro' - | 'cyberpunk' - | 'valentine' - | 'halloween' - | 'garden' - | 'forest' - | 'aqua' - | 'lofi' - | 'pastel' - | 'fantasy' - | 'wireframe' - | 'black' - | 'luxury' - | 'dracula' - | 'cmyk' - | 'autumn' - | 'business' - | 'acid' - | 'lemonade' - | 'night' - | 'coffee' - | 'winter' - +export const daisyThemes = [ + 'default', + 'storm', + 'breeze', + 'light', + 'dark', + 'cupcake', + 'bumblebee', + 'emerald', + 'corporate', + 'synthwave', + 'retro', + 'cyberpunk', + 'valentine', + 'halloween', + 'garden', + 'forest', + 'aqua', + 'lofi', + 'pastel', + 'fantasy', + 'wireframe', + 'black', + 'luxury', + 'dracula', + 'cmyk', + 'autumn', + 'business', + 'acid', + 'lemonade', + 'night', + 'coffee', + 'winter' +] as const +export type DaisyThemes = (typeof daisyThemes)[number] export type ThemeOptions = { light: DaisyThemes dark: DaisyThemes From e87761ff102400ca40a97e0c51bd4f49d9deb904 Mon Sep 17 00:00:00 2001 From: kaan Date: Tue, 25 Apr 2023 13:58:42 +0200 Subject: [PATCH 5/8] chore: added google material icons Closes #14 --- index.html | 2 ++ src/assets/google-material.css | 24 ++++++++++++++++++++++++ src/assets/main.css | 1 + 3 files changed, 27 insertions(+) create mode 100644 src/assets/google-material.css diff --git a/index.html b/index.html index 4732114..c923479 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,8 @@ + + Vite App diff --git a/src/assets/google-material.css b/src/assets/google-material.css new file mode 100644 index 0000000..1fa0af9 --- /dev/null +++ b/src/assets/google-material.css @@ -0,0 +1,24 @@ +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + + /* Support for IE. */ + font-feature-settings: 'liga'; + } diff --git a/src/assets/main.css b/src/assets/main.css index e8667cd..c50e063 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -1,4 +1,5 @@ @import './base.css'; +@import './google-material.css'; #app { max-width: 1280px; From eeb66f451abe29cf9e5f4c65e5a662af226d808f Mon Sep 17 00:00:00 2001 From: kaan Date: Tue, 25 Apr 2023 14:43:17 +0200 Subject: [PATCH 6/8] chore: update theme preview & added google material symbols --- index.html | 4 +- src/plugins/themeManager/index.ts | 5 ++- src/views/ThemeView.vue | 68 ++++++++++++++++++++++++++----- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index c923479..449681d 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,9 @@ - + + + Vite App diff --git a/src/plugins/themeManager/index.ts b/src/plugins/themeManager/index.ts index 0e13e38..0744ae8 100644 --- a/src/plugins/themeManager/index.ts +++ b/src/plugins/themeManager/index.ts @@ -38,7 +38,7 @@ export type DaisyThemes = (typeof daisyThemes)[number] export type ThemeOptions = { light: DaisyThemes dark: DaisyThemes - watchSystemTheme?: boolean + watchSystemTheme: boolean } export const useThemeManager = () => { @@ -109,7 +109,8 @@ export const useThemeManager = () => { toggleDark, setDefaults, getDefaults, - watchSystemTheme: isWatchingSystemTheme + watchSystemTheme: isWatchingSystemTheme, + isDark } pluginInitiated.value = true return { ...themeManagerInstance } diff --git a/src/views/ThemeView.vue b/src/views/ThemeView.vue index 5171122..52ca67a 100644 --- a/src/views/ThemeView.vue +++ b/src/views/ThemeView.vue @@ -1,20 +1,53 @@