Skip to content

Commit

Permalink
feat(ui/sidebar): add dark mode toggle for dashboard (#790)
Browse files Browse the repository at this point in the history
  • Loading branch information
qwqcode committed Aug 29, 2024
1 parent d6ececd commit 965efcc
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 26 deletions.
19 changes: 9 additions & 10 deletions ui/artalk-sidebar/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useNavStore } from './stores/nav'
import { bootParams } from './global'
const nav = useNavStore()
const { scrollableArea } = storeToRefs(nav)
const { scrollableArea, darkMode } = storeToRefs(nav)
const darkMode = ref(bootParams.darkMode)
const query = window.matchMedia('(prefers-color-scheme: dark)')
;(function initDarkModeWatchMedia() {
if (!window.matchMedia) return
const query = window.matchMedia('(prefers-color-scheme: dark)')
query.addEventListener('change', (e) => {
darkMode.value = e.matches
})
})()
onMounted(() => query.addEventListener('change', onDarkModeChange))
onUnmounted(() => query.removeEventListener('change', onDarkModeChange))
const onDarkModeChange = (e: MediaQueryListEvent) => {
// auto switch when localStorage is empty
if (localStorage.getItem('ATK_SIDEBAR_DARK_MODE') === null) darkMode.value = e.matches
}
</script>

<template>
Expand Down Expand Up @@ -42,6 +40,7 @@ $sidebarWidth: 280px;
.app-wrap {
background: var(--at-color-bg);
color: var(--at-color-font);
min-height: 100vh;
}
.main {
Expand Down
1 change: 1 addition & 0 deletions ui/artalk-sidebar/src/assets/icon-darkmode-off.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions ui/artalk-sidebar/src/assets/icon-darkmode-on.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 44 additions & 1 deletion ui/artalk-sidebar/src/components/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const router = useRouter()
const user = useUserStore()
const { t } = useI18n()
const { site: curtSite, is_admin: isAdmin, avatar } = storeToRefs(user)
const { darkMode } = storeToRefs(nav)
const avatarClickHandler = () => {
if (!isOpenFromSidebar()) logout()
Expand Down Expand Up @@ -53,6 +54,7 @@ const logout = () => {
</div>

<div class="close-btn"></div>
<div class="dark-mode-toggle" :data-darkmode="darkMode ? 'on' : 'off'" @click="nav.toggleDarkMode()"></div>
</div>
<SiteSwitcher v-if="isAdmin" />
</template>
Expand All @@ -65,7 +67,7 @@ const logout = () => {
border-bottom: 1px solid var(--at-color-border);
@media (min-width: 1024px) {
background: #f6f8fa;
background: var(--at-sidebar-header-bg);
}
.avatar {
Expand Down Expand Up @@ -184,5 +186,46 @@ const logout = () => {
height: 60px;
margin-left: 10px;
}
.dark-mode-toggle {
display: none;
width: 60px;
height: 60px;
margin-left: 10px;
justify-content: center;
align-items: center;
user-select: none;
cursor: pointer;
@media (min-width: 1024px) {
display: flex;
}
&:hover {
&::after {
background-color: var(--at-color-bg-grey);
}
}
&::after {
content: '';
display: block;
transition: background-color 0.2s;
width: 35px;
height: 35px;
background-repeat: no-repeat;
background-position: center;
background-size: 60%;
border-radius: 50%;
}
&[data-darkmode='on']::after {
background-image: url('@/assets/icon-darkmode-on.svg');
}
&[data-darkmode='off']::after {
background-image: url('@/assets/icon-darkmode-off.svg');
}
}
}
</style>
6 changes: 3 additions & 3 deletions ui/artalk-sidebar/src/components/AppNavigationDesktop.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ $colorMain: #8ecee2;
top: 61px;
height: calc(100vh - 61px - 41px);
padding: 20px;
background: #fff;
background: var(--at-color-bg);
border-right: 1px solid var(--at-color-border);
@media (max-width: 1023px) {
Expand All @@ -82,7 +82,7 @@ $colorMain: #8ecee2;
&.active {
font-weight: bold;
color: #181a1e;
color: var(--at-color-deep);
&::before {
content: '';
Expand All @@ -99,7 +99,7 @@ $colorMain: #8ecee2;
&:hover,
&.active {
background: #f4f5f7;
background: var(--at-color-bg-grey-transl);
}
.icon {
Expand Down
12 changes: 11 additions & 1 deletion ui/artalk-sidebar/src/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,23 @@ function getBootParams() {
is_admin: userFromURL.is_admin || false,
}

let darkMode: boolean
if (p.get('darkMode') != null) {
darkMode = p.get('darkMode') == '1'
} else {
darkMode =
localStorage.getItem('ATK_SIDEBAR_DARK_MODE') != null
? localStorage.getItem('ATK_SIDEBAR_DARK_MODE') == '1'
: window.matchMedia('(prefers-color-scheme: dark)').matches
}

return {
user,
pageKey: p.get('pageKey') || '',
site: p.get('site') || '',
view: p.get('view') || '',
viewParams: <any>null,
darkMode: p.get('darkMode') === '1',
darkMode,
}
}

Expand Down
16 changes: 15 additions & 1 deletion ui/artalk-sidebar/src/stores/nav.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import type { ArtalkType } from 'artalk'
import { artalk } from '../global'
import { artalk, bootParams, getArtalk } from '@/global'
import { useMobileWidth } from '@/hooks/MobileWidth'

type TabsObj = { [name: string]: string }
Expand All @@ -20,6 +20,14 @@ export const useNavStore = defineStore('nav', () => {
const isPageLoading = ref(false)
const scrollableArea = ref<HTMLElement | null>(null)

const darkMode = ref(bootParams.darkMode)
watch(darkMode, (val) => {
getArtalk()?.setDarkMode(val)
if (val != window.matchMedia('(prefers-color-scheme: dark)').matches)
localStorage.setItem('ATK_SIDEBAR_DARK_MODE', val ? '1' : '0')
else localStorage.removeItem('ATK_SIDEBAR_DARK_MODE') // enable auto switch
})

const updateTabs = (aTabs: TabsObj, activeTab?: string) => {
tabs.value = aTabs
if (activeTab) curtTab.value = activeTab
Expand Down Expand Up @@ -68,6 +76,10 @@ export const useNavStore = defineStore('nav', () => {
searchResetEvent.value = searchResetEvt
}

const toggleDarkMode = () => {
darkMode.value = !darkMode.value
}

useRouter().beforeEach((to, from) => {
isSearchEnabled.value = false
})
Expand Down Expand Up @@ -96,5 +108,7 @@ export const useNavStore = defineStore('nav', () => {
searchResetEvent,
enableSearch,
isMobile,
darkMode,
toggleDarkMode,
}
})
12 changes: 12 additions & 0 deletions ui/artalk-sidebar/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ body {
font-family: $font-family;
}

.artalk {
--at-sidebar-header-bg: #f6f8fa;
}

.artalk.atk-dark-mode {
--at-sidebar-header-bg: #1e1e1e;

.atk-comment-wrap.atk-openable:hover {
background: #1e1e1e;
}
}

.atk-sidebar {
.atk-list {
.atk-main-editor {
Expand Down
18 changes: 8 additions & 10 deletions ui/artalk/src/layer/sidebar-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ export default class SidebarLayer extends Component {

// event
this.ctx.on('user-changed', () => {
this.refreshOnShow = true
this.refreshWhenShow = true
})
}

/** Refresh iFrame on show */
private refreshOnShow = true
/** Refresh iFrame when show */
private refreshWhenShow = true

/** Animation timer */
private animTimer?: any = undefined
Expand All @@ -45,8 +45,8 @@ export default class SidebarLayer extends Component {
this.layer!.show()

// init iframe
if (this.refreshOnShow) {
this.refreshOnShow = false
if (this.refreshWhenShow) {
this.refreshWhenShow = false
this.$iframeWrap.innerHTML = ''
this.$iframe = this.createIframe(conf.view)
this.$iframeWrap.append(this.$iframe)
Expand All @@ -57,9 +57,7 @@ export default class SidebarLayer extends Component {
if (this.getDarkMode() !== iFrameSrc.includes('&darkMode=1')) {
this.iframeLoad(
$iframe,
this.getDarkMode()
? iFrameSrc.concat('&darkMode=1')
: iFrameSrc.replace('&darkMode=1', ''),
iFrameSrc.replace(/&darkMode=\d/, `&darkMode=${Number(this.getDarkMode())}`),
)
}
}
Expand Down Expand Up @@ -96,7 +94,7 @@ export default class SidebarLayer extends Component {
})
).data
if (data.is_admin && !data.is_login) {
this.refreshOnShow = true
this.refreshWhenShow = true

// show checker layer
this.ctx.checkAdmin({
Expand Down Expand Up @@ -155,7 +153,7 @@ export default class SidebarLayer extends Component {
}

if (view) query.view = view
if (this.getDarkMode()) query.darkMode = '1'
query.darkMode = this.getDarkMode() ? '1' : '0'

const urlParams = new URLSearchParams(query)
this.iframeLoad($iframe, `${baseURL}?${urlParams.toString()}`)
Expand Down

0 comments on commit 965efcc

Please sign in to comment.