Skip to content

Commit

Permalink
starts to implement auto theme support
Browse files Browse the repository at this point in the history
  • Loading branch information
cars10 committed Oct 15, 2024
1 parent cb67704 commit c14eeab
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 31 deletions.
12 changes: 4 additions & 8 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,17 @@
import ModalLoader from './components/shared/ModalLoader.vue'
import AlertSnackbar from './components/shared/AlertSnackbar.vue'
import NetworkError from './components/shared/NetworkError.vue'
import { useThemeStore } from './store/theme.js'
import { useThemeStore } from './store/theme.ts'
import { useConnectionStore } from './store/connection'
import { setAppThemeCss, setupThemeListener } from './helpers/theme.ts'
const themeStore = useThemeStore()
const connectionStore = useConnectionStore()
const route = useRoute()
onMounted(() => {
if (themeStore.dark) {
document.body.classList.remove('body--light')
document.body.classList.add('theme--dark')
} else {
document.body.classList.remove('theme--dark')
document.body.classList.add('theme--light')
}
setAppThemeCss(themeStore.appTheme)
setupThemeListener()
})
</script>
1 change: 0 additions & 1 deletion src/components/base/LanguageSwitcher.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
v-close-popup
clickable
dense

active-class="bg-grey-8"
:active="store.language === code"
:title="title"
Expand Down
46 changes: 38 additions & 8 deletions src/components/base/ThemeSwitcher.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,50 @@
<template>
<q-btn id="change_theme"
<q-btn :icon="themeIcon"
round
:icon="icon"
class="q-mr-md"
color="dark-grey"
class="q-mr-md"
:title="t('base.theme_switcher.title')"
data-testid="change-theme-button"
@click="store.toggleTheme" />
data-testid="change-theme-button">
<q-menu>
<q-list>
<q-item v-for="(icon, theme) in themes"
:key="theme"
v-close-popup
clickable
dense
:active="themeStore.preference === theme"
:title="theme"
:data-testid="`change-theme__${theme}`"
@click="changeTheme(theme)">
<q-item-section>
<q-icon :name="icon" :alt="theme" />
</q-item-section>
<q-item-section>
{{ theme }}
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</template>

<script setup lang="ts">
import { useThemeStore } from '../../store/theme.js'
import { computed } from 'vue'
import { useTranslation } from '../../composables/i18n.ts'
import { setAppThemeCss } from '../../helpers/theme.ts'
const store = useThemeStore()
const themeStore = useThemeStore()
const t = useTranslation()
const icon = computed(() => (store.dark ? 'light_mode' : 'nightlight'))
</script>
const themes = {
light: 'light_mode',
dark: 'dark_mode',
auto: 'brightness_medium'
}
const changeTheme = (theme) => {
themeStore.setPreference(theme)
setAppThemeCss(themeStore.appTheme)
}
const themeIcon = computed(() => (themes[themeStore.preference]))
</script>
8 changes: 4 additions & 4 deletions src/composables/Logo.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import white from '../assets/images/logo/white_96.png'
import blue from '../assets/images/logo/blue_96.png'
import { useThemeStore } from '../store/theme'
import { AppThemes, useThemeStore } from '../store/theme.ts'
import { computed } from 'vue'

export const useLogo = () => {
const themeStore = useThemeStore()

return computed(() => {
if (themeStore.dark) {
return white
} else {
if (themeStore.appTheme === AppThemes.light) {
return blue
} else {
return white
}
})
}
25 changes: 25 additions & 0 deletions src/helpers/theme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AppThemes, ThemePreferences, useThemeStore } from '../store/theme.ts'

export const setAppThemeCss = (theme: AppThemes) => {
if (theme === AppThemes.light) {
document.body.classList.add('theme--light')
document.body.classList.remove('theme--dark')
} else {
document.body.classList.add('theme--dark')
document.body.classList.remove('theme--light')
}
}

export const setupThemeListener = () => {
const mediaQuery = window.matchMedia('(prefers-color-scheme: light)')
const themeStore = useThemeStore()

mediaQuery.addEventListener('change', (e) => {
if (themeStore.preference !== ThemePreferences.auto) return

const appTheme = e.matches ? AppThemes.light : AppThemes.dark
themeStore.appTheme = appTheme

setAppThemeCss(appTheme)
})
}
31 changes: 21 additions & 10 deletions src/store/theme.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
import { defineStore } from 'pinia'

export type ThemeState = {
dark: boolean
export enum ThemePreferences {
light = 'light',
dark = 'dark',
auto = 'auto'
}

export enum AppThemes {
light = 'light',
dark = 'dark'
}

type ThemeState = {
preference: ThemePreferences,
appTheme: AppThemes
}

export const useThemeStore = defineStore('theme', {
state: (): ThemeState => ({
dark: window.matchMedia('(prefers-color-scheme: dark)').matches
preference: ThemePreferences.auto,
appTheme: window.matchMedia('(prefers-color-scheme: light)').matches ? AppThemes.light : AppThemes.dark
}),
actions: {
toggleTheme () {
this.dark = !this.dark
setPreference(preference: ThemePreferences) {
this.preference = preference

if (this.dark) {
document.body.classList.add('theme--dark')
document.body.classList.remove('theme--light')
if (preference === ThemePreferences.auto) {
this.appTheme = window.matchMedia('(prefers-color-scheme: light)').matches ? AppThemes.light : AppThemes.dark
} else {
document.body.classList.add('theme--light')
document.body.classList.remove('theme--dark')
this.appTheme = preference as unknown as AppThemes
}
}
},
Expand Down

0 comments on commit c14eeab

Please sign in to comment.