first commit

This commit is contained in:
LeonspaceX
2026-01-22 18:52:07 +08:00
commit d5ab09c9dc
32 changed files with 6295 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
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;
};