feat: extracted theme change logic

This commit is contained in:
Roberto Tonino 2020-11-11 00:11:24 +01:00
parent 351cd2d626
commit 48503e0abf
4 changed files with 164 additions and 137 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,16 @@
<template> <template>
<aside <aside
id="sidebar" id="sidebar"
class="top-0 left-0 flex flex-col w-64 h-screen bg-panels-bg text-foreground" class="top-0 left-0 flex flex-col h-screen bg-panels-bg text-foreground"
:class="{ slim: isSlim }" :class="{ 'w-12': isSlim, 'w-64': !isSlim }"
role="navigation" role="navigation"
aria-label="sidebar" aria-label="sidebar"
ref="sidebar"
> >
<router-link <router-link
tag="a" tag="a"
v-for="link in links" v-for="link in links"
:key="link.id" :key="link.name"
class="relative flex items-center h-16 no-underline group main_tablinks hover:bg-background-main text-foreground" class="relative flex items-center h-16 no-underline group main_tablinks hover:bg-background-main text-foreground"
:id="link.id"
:class="{ 'bg-background-main': activeTablink === link.name }" :class="{ 'bg-background-main': activeTablink === link.name }"
:aria-label="link.ariaLabel" :aria-label="link.ariaLabel"
:to="{ name: link.routerName }" :to="{ name: link.routerName }"
@ -24,50 +22,49 @@
> >
{{ link.icon }} {{ link.icon }}
</i> </i>
<span class="ml-5 overflow-hidden capitalize whitespace-no-wrap main_tablinks_text" style="letter-spacing: 1.3px"> <span
class="ml-5 overflow-hidden capitalize whitespace-no-wrap main-tablinks-text"
:class="{ hidden: isSlim }"
style="letter-spacing: 1.3px"
>
{{ $t(link.label) }} {{ $t(link.label) }}
</span> </span>
<span <span
v-if="link.name === 'about' && updateAvailable" v-if="link.name === 'about' && updateAvailable"
id="update-notification" id="update-notification"
class="w-3 h-3 bg-red-600 rounded-full" class="absolute w-3 h-3 bg-red-600 rounded-full"
></span> ></span>
</router-link> </router-link>
<span id="theme_selector" class="flex h-12 mt-5" role="link" aria-label="theme selector"> <span
id="theme_selector"
class="flex h-12 mt-5"
role="link"
aria-label="theme selector"
:class="{ 'inline-grid gap-2': isSlim }"
>
<i class="p-2 text-3xl transition-all duration-500 cursor-default material-icons side_icon side_icon--theme"> <i class="p-2 text-3xl transition-all duration-500 cursor-default material-icons side_icon side_icon--theme">
brush brush
</i> </i>
<div id="theme_togglers" class="relative flex items-center w-full justify-evenly">
<div <div
v-for="theme of themes" id="theme_togglers"
class="relative flex items-center w-full justify-evenly"
:class="{ 'inline-grid gap-2': isSlim }"
>
<div
v-for="theme of THEMES"
:key="theme" :key="theme"
class="w-6 h-6 border rounded-full cursor-pointer theme_toggler border-grayscale-500" class="w-6 h-6 border rounded-full cursor-pointer theme_toggler border-grayscale-500 gap"
:class="[{ 'theme_toggler--active': activeTheme === theme }, `theme_toggler--${theme}`]" :class="[{ 'theme_toggler--active': currentTheme === theme }, `theme_toggler--${theme}`]"
@click="changeTheme(theme)" @click="currentTheme = theme"
></div> />
</div> </div>
</span> </span>
</aside> </aside>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
#sidebar.slim {
width: 46px;
}
#sidebar.slim .main_tablinks_text {
display: none;
}
#sidebar.slim #theme_selector,
#sidebar.slim #theme_togglers {
display: inline-grid;
grid-gap: 8px;
}
#update-notification { #update-notification {
position: absolute;
left: 30px; left: 30px;
top: 12px; top: 12px;
} }
@ -94,121 +91,40 @@
</style> </style>
<script> <script>
import { socket } from '@/utils/socket' import { computed, defineComponent, reactive, toRefs } from '@vue/composition-api'
import { mapGetters } from 'vuex'
export default { import { links } from '@/data/sidebar'
data() { import { socket } from '@/utils/socket'
return { import { useTheme } from '@/use/theme'
activeTheme: 'light',
themes: ['purple', 'dark', 'light'], export default defineComponent({
setup(props, ctx) {
const state = reactive({
activeTablink: 'home', activeTablink: 'home',
updateAvailable: false, updateAvailable: false,
links: [ links
{
id: 'main_home_tablink',
name: 'home',
ariaLabel: 'home',
routerName: 'Home',
icon: 'home',
label: 'sidebar.home'
},
{
id: 'main_search_tablink',
name: 'search',
ariaLabel: 'search',
routerName: 'Search',
icon: 'search',
label: 'sidebar.search'
},
{
id: 'main_charts_tablink',
name: 'charts',
ariaLabel: 'charts',
routerName: 'Charts',
icon: 'show_chart',
label: 'sidebar.charts'
},
{
id: 'main_favorites_tablink',
name: 'favorites',
ariaLabel: 'favorites',
routerName: 'Favorites',
icon: 'star',
label: 'sidebar.favorites'
},
{
id: 'main_analyzer_tablink',
name: 'analyzer',
ariaLabel: 'link analyzer',
routerName: 'Link Analyzer',
icon: 'link',
label: 'sidebar.linkAnalyzer'
},
{
id: 'main_settings_tablink',
name: 'settings',
ariaLabel: 'settings',
routerName: 'Settings',
icon: 'settings',
label: 'sidebar.settings'
},
{
id: 'main_about_tablink',
name: 'about',
ariaLabel: 'info',
routerName: 'About',
icon: 'info',
label: 'sidebar.about'
}
]
}
},
computed: {
...mapGetters({
isSlim: 'getSlimSidebar'
})
},
mounted() {
/* === Current theme handling === */
this.activeTheme = localStorage.getItem('selectedTheme') || 'dark'
this.$router.afterEach((to, from) => {
const linkInSidebar = this.links.find(link => link.routerName === to.name)
if (!linkInSidebar) return
this.activeTablink = linkInSidebar.name
}) })
const { THEMES, currentTheme } = useTheme()
/* === Add update notification near info === */ /* === Add update notification near info === */
socket.on('updateAvailable', () => { socket.on('updateAvailable', () => {
this.updateAvailable = true state.updateAvailable = true
})
},
methods: {
changeTheme(newTheme) {
if (newTheme === this.activeTheme) return
this.activeTheme = newTheme
document.documentElement.setAttribute('data-theme', newTheme)
localStorage.setItem('selectedTheme', newTheme)
// Animating everything to have a smoother theme switch
const allElements = document.querySelectorAll('*')
allElements.forEach(el => {
el.classList.add('changing-theme')
}) })
document.documentElement.addEventListener('transitionend', function transitionHandler() { ctx.root.$router.afterEach((to, from) => {
allElements.forEach(el => { const linkInSidebar = state.links.find(link => link.routerName === to.name)
el.classList.remove('changing-theme')
if (!linkInSidebar) return
state.activeTablink = linkInSidebar.name
}) })
document.documentElement.removeEventListener('transitionend', transitionHandler) return {
}) ...toRefs(state),
THEMES,
currentTheme,
isSlim: computed(() => ctx.root.$store.getters.getSlimSidebar)
} }
} }
} })
</script> </script>

51
src/data/sidebar.js Normal file
View File

@ -0,0 +1,51 @@
export const links = [
{
name: 'home',
ariaLabel: 'home',
routerName: 'Home',
icon: 'home',
label: 'sidebar.home'
},
{
name: 'search',
ariaLabel: 'search',
routerName: 'Search',
icon: 'search',
label: 'sidebar.search'
},
{
name: 'charts',
ariaLabel: 'charts',
routerName: 'Charts',
icon: 'show_chart',
label: 'sidebar.charts'
},
{
name: 'favorites',
ariaLabel: 'favorites',
routerName: 'Favorites',
icon: 'star',
label: 'sidebar.favorites'
},
{
name: 'analyzer',
ariaLabel: 'link analyzer',
routerName: 'Link Analyzer',
icon: 'link',
label: 'sidebar.linkAnalyzer'
},
{
name: 'settings',
ariaLabel: 'settings',
routerName: 'Settings',
icon: 'settings',
label: 'sidebar.settings'
},
{
name: 'about',
ariaLabel: 'info',
routerName: 'About',
icon: 'info',
label: 'sidebar.about'
}
]

46
src/use/theme.js Normal file
View File

@ -0,0 +1,46 @@
import { ref, watch } from '@vue/composition-api'
/**
* @typedef {string} Theme
*/
const THEMES = {
dark: 'dark',
light: 'light',
purple: 'purple'
}
const initialTheme = localStorage.getItem('selectedTheme') || document.documentElement.dataset.theme || THEMES.dark
const currentTheme = ref(initialTheme)
watch(currentTheme, (newTheme, oldTheme) => {
// No operation needed
if (oldTheme === newTheme) return
localStorage.setItem('selectedTheme', newTheme)
document.documentElement.dataset.theme = newTheme
animateAllElements()
})
function animateAllElements() {
// Animating everything to have a smoother theme switch
const allElements = document.querySelectorAll('*')
allElements.forEach(el => {
el.classList.add('changing-theme')
})
document.documentElement.addEventListener('transitionend', function transitionHandler() {
allElements.forEach(el => {
el.classList.remove('changing-theme')
})
document.documentElement.removeEventListener('transitionend', transitionHandler)
})
}
export const useTheme = () => ({
THEMES,
currentTheme
})