admin/home: switch-theme button
Massimo Melina committed
Apr 19, 2024 at 00:13 UTC
edb088bfc6b32db630b43f87a50b91353a18362e
4 files changed
+24
-5
admin/src/HomePage.ts
+3
-1
@@ -14,6 +14,7 @@ import { VfsNode } from './VfsPage'
14
import { Account } from './AccountsPage'
15
import _ from 'lodash'
16
import { subscribeKey } from 'valtio/utils'
17
+import { SwitchThemeBtn } from './theme'
18
19
interface ServerStatus { listening: boolean, port: number, error?: string, busy?: string }
20
@@ -126,7 +127,8 @@ export default function HomePage() {
127
h(Box, { mt: 1 }, renderChangelog(x.body))
128
)),
129
)),
129
- ))
130
+ )),
131
+ h(SwitchThemeBtn, { variant: 'outlined' }),
132
)
133
}
134
admin/src/mui.ts
+1
-1
@@ -121,7 +121,7 @@ interface IconBtnProps extends Omit<BtnProps, 'icon' | 'children'> { icon: SvgIc
121
export const IconBtn = forwardRef((props: IconBtnProps, ref: ForwardedRef<HTMLButtonElement>) =>
122
h(Btn, { ref, ...props }))
123
124
-interface BtnProps extends Omit<ButtonProps & IconButtonProps,'disabled'|'title'|'onClick'> {
124
+export interface BtnProps extends Omit<ButtonProps & IconButtonProps,'disabled'|'title'|'onClick'> {
125
icon?: SvgIconComponent
126
title?: ReactNode
127
disabled?: boolean | string
admin/src/state.ts
+2
-1
@@ -17,6 +17,7 @@ const INIT = {
17
username: '',
18
monitorOnlyFiles: true,
19
customHtmlSection: '',
20
+ darkTheme: undefined as undefined | boolean,
21
onlinePluginsColumns: {
22
version: false,
23
pushed_at: false,
@@ -26,7 +27,7 @@ const INIT = {
27
Object.assign(INIT, JSON.parse(localStorage[STORAGE_KEY]||null))
28
export const state = proxy(INIT)
29
29
-const SETTINGS_TO_STORE: (keyof typeof state)[] = ['onlinePluginsColumns', 'monitorOnlyFiles', 'customHtmlSection']
30
+const SETTINGS_TO_STORE: (keyof typeof state)[] = ['onlinePluginsColumns', 'monitorOnlyFiles', 'customHtmlSection', 'darkTheme']
31
const storeSettings = _.debounce(() =>
32
localStorage[STORAGE_KEY] = JSON.stringify(_.pick(state, SETTINGS_TO_STORE)), 500, { maxWait: 1000 })
33
for (const k of SETTINGS_TO_STORE)
admin/src/theme.ts
+18
-2
@@ -1,7 +1,10 @@
1
// This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import { createTheme, useMediaQuery } from '@mui/material'
4
-import { useMemo } from 'react'
4
+import { createElement as h, useMemo } from 'react'
5
+import { state, useSnapState } from './state'
6
+import { Btn, BtnProps } from './mui'
7
+import { Brightness4, Brightness7 } from '@mui/icons-material'
8
9
export function useDark() {
10
return useMediaQuery('(prefers-color-scheme: dark)')
@@ -9,7 +12,9 @@ export function useDark() {
12
13
const EMPTY = {}
14
export function useMyTheme() {
12
- const lightMode = useDark() ? null : EMPTY
15
+ const { darkTheme } = useSnapState()
16
+ const detected = useDark()
17
+ const lightMode = (darkTheme ?? detected) ? null : EMPTY
18
return useMemo(() => createTheme({
19
palette: lightMode || {
20
mode: 'dark',
@@ -43,3 +48,14 @@ export function useMyTheme() {
48
}
49
}), [lightMode])
50
}
51
+
52
+export function SwitchThemeBtn(props: BtnProps) {
53
+ const { darkTheme } = useSnapState()
54
+ const darkDetected = useDark()
55
+ const currentlyDark = darkTheme ?? darkDetected
56
+ return h(Btn, {
57
+ icon: currentlyDark ? Brightness7 : Brightness4,
58
+ onClick: () => state.darkTheme = !currentlyDark,
59
+ ...props,
60
+ }, currentlyDark ? "Light theme" : "Dark theme")
61
+}