64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||
import { getSettings } from '../api';
|
||
import type { SiteSettings } from '../api';
|
||
import { useToastController, Toast, ToastTitle } from '@fluentui/react-components';
|
||
|
||
interface LayoutContextType {
|
||
settings: SiteSettings | null;
|
||
isSidebarCollapsed: boolean;
|
||
toggleSidebar: () => void;
|
||
isDarkMode: boolean;
|
||
toggleTheme: () => void;
|
||
}
|
||
|
||
const LayoutContext = createContext<LayoutContextType | undefined>(undefined);
|
||
|
||
export const LayoutProvider: React.FC<{ children: React.ReactNode; toasterId: string }> = ({ children, toasterId }) => {
|
||
const [settings, setSettings] = useState<SiteSettings | null>(null);
|
||
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
|
||
const [isDarkMode, setIsDarkMode] = useState(false);
|
||
const { dispatchToast } = useToastController(toasterId);
|
||
|
||
useEffect(() => {
|
||
getSettings().then((data) => {
|
||
setSettings(data);
|
||
if (data.favicon) {
|
||
let link = document.querySelector("link[rel~='icon']") as HTMLLinkElement;
|
||
if (!link) {
|
||
link = document.createElement('link');
|
||
link.rel = 'icon';
|
||
document.head.appendChild(link);
|
||
}
|
||
link.href = data.favicon;
|
||
}
|
||
if (data.siteTitle) {
|
||
document.title = data.siteTitle;
|
||
}
|
||
}).catch(() => {
|
||
dispatchToast(
|
||
<Toast>
|
||
<ToastTitle>站点配置获取失败!</ToastTitle>
|
||
</Toast>,
|
||
{ intent: 'error' }
|
||
);
|
||
});
|
||
}, [dispatchToast]);
|
||
|
||
const toggleSidebar = () => setIsSidebarCollapsed(prev => !prev);
|
||
const toggleTheme = () => setIsDarkMode(prev => !prev);
|
||
|
||
return (
|
||
<LayoutContext.Provider value={{ settings, isSidebarCollapsed, toggleSidebar, isDarkMode, toggleTheme }}>
|
||
{children}
|
||
</LayoutContext.Provider>
|
||
);
|
||
};
|
||
|
||
export const useLayout = () => {
|
||
const context = useContext(LayoutContext);
|
||
if (!context) {
|
||
throw new Error('useLayout must be used within a LayoutProvider');
|
||
}
|
||
return context;
|
||
};
|