aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/layouts/BasicLayout.tsx2
-rw-r--r--src/layouts/SiteSettings.module.css16
-rw-r--r--src/layouts/SiteSettings.tsx73
-rw-r--r--src/main.tsx2
4 files changed, 92 insertions, 1 deletions
diff --git a/src/layouts/BasicLayout.tsx b/src/layouts/BasicLayout.tsx
index 6af8564..9851fd4 100644
--- a/src/layouts/BasicLayout.tsx
+++ b/src/layouts/BasicLayout.tsx
@@ -19,6 +19,7 @@ import { NavLink as RouterNavLink, Outlet, useLocation, useMatches } from 'react
import { pageRoutes } from '../routes.ts'
import type { PageRoute } from '../routes.ts'
import classes from './BasicLayout.module.css'
+import { SiteSettings } from './SiteSettings.tsx'
const collapsedNavbarWidth = rem(64)
@@ -194,6 +195,7 @@ export function BasicLayout() {
aria-controls="mobile-navigation"
/>
<Text fw={600}>{title}</Text>
+ <SiteSettings />
</Group>
</AppShell.Header>
diff --git a/src/layouts/SiteSettings.module.css b/src/layouts/SiteSettings.module.css
new file mode 100644
index 0000000..4718208
--- /dev/null
+++ b/src/layouts/SiteSettings.module.css
@@ -0,0 +1,16 @@
+.trigger {
+ margin-inline-start: auto;
+ flex-shrink: 0;
+}
+
+.header {
+ padding-top: max(var(--mantine-spacing-md), env(safe-area-inset-top));
+ padding-left: max(var(--mantine-spacing-md), env(safe-area-inset-left));
+ padding-right: max(var(--mantine-spacing-md), env(safe-area-inset-right));
+}
+
+.body {
+ padding-bottom: max(var(--mantine-spacing-md), env(safe-area-inset-bottom));
+ padding-left: max(var(--mantine-spacing-md), env(safe-area-inset-left));
+ padding-right: max(var(--mantine-spacing-md), env(safe-area-inset-right));
+}
diff --git a/src/layouts/SiteSettings.tsx b/src/layouts/SiteSettings.tsx
new file mode 100644
index 0000000..5c0eef8
--- /dev/null
+++ b/src/layouts/SiteSettings.tsx
@@ -0,0 +1,73 @@
+import { useRef } from 'react'
+import {
+ ActionIcon, Drawer, SegmentedControl, Stack, Text, Tooltip,
+ useMantineColorScheme, useMatches,
+} from '@mantine/core'
+import { GearIcon } from '@phosphor-icons/react'
+import { useNavigate, useSearchParams } from 'react-router'
+import classes from './SiteSettings.module.css'
+
+export function SiteSettings() {
+ const { colorScheme, setColorScheme } = useMantineColorScheme()
+ const size = useMatches({ base: '100%', sm: 'sm' })
+ const [searchParams, setSearchParams] = useSearchParams()
+ const navigate = useNavigate()
+ const openedHere = useRef(false)
+ const opened = searchParams.get('settings') === 'appearance'
+
+ function open() {
+ if (opened) return
+ openedHere.current = true
+ setSearchParams((previous) => {
+ const next = new URLSearchParams(previous)
+ next.set('settings', 'appearance')
+ return next
+ }, { preventScrollReset: true })
+ }
+
+ function close() {
+ if (openedHere.current) {
+ openedHere.current = false
+ void navigate(-1)
+ return
+ }
+
+ // 直接访问或刷新设置链接时,关闭抽屉不应离开当前页面。
+ setSearchParams((previous) => {
+ const next = new URLSearchParams(previous)
+ next.delete('settings')
+ return next
+ }, { replace: true, preventScrollReset: true })
+ }
+
+ return (
+ <>
+ <Tooltip label="网站设置" events={{ hover: true, focus: true, touch: false }}>
+ <ActionIcon className={classes.trigger} variant="subtle" color="gray" size="xl"
+ aria-label="打开网站设置" aria-haspopup="dialog" aria-expanded={opened} onClick={open}>
+ <GearIcon size={22} aria-hidden="true" />
+ </ActionIcon>
+ </Tooltip>
+ <Drawer opened={opened} onClose={close} title="网站设置" position="right" size={size}
+ closeButtonProps={{ 'aria-label': '关闭网站设置', size: 'lg' }}
+ classNames={{ header: classes.header, body: classes.body }}>
+ <Stack gap="md">
+ <Text id="site-color-scheme-label" fw={600}>外观模式</Text>
+ <SegmentedControl
+ aria-labelledby="site-color-scheme-label"
+ value={colorScheme}
+ data={[
+ { value: 'light', label: '亮色' },
+ { value: 'dark', label: '暗色' },
+ { value: 'auto', label: '跟随系统' },
+ ]}
+ onChange={(value) => {
+ if (value === 'light' || value === 'dark' || value === 'auto') setColorScheme(value)
+ }}
+ />
+ <Text size="sm" c="dimmed">设置即时生效并自动保存。选择“跟随系统”时,外观随设备主题变化。</Text>
+ </Stack>
+ </Drawer>
+ </>
+ )
+}
diff --git a/src/main.tsx b/src/main.tsx
index 39053ab..744c2ae 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -10,7 +10,7 @@ import { theme } from './theme.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
- <MantineProvider theme={theme}>
+ <MantineProvider theme={theme} defaultColorScheme="auto">
<RouterProvider router={router} />
</MantineProvider>
</StrictMode>,