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 +}