import { useEffect, useState } from 'react' import { BrowserRouter, Link, Route, Routes } from 'react-router-dom' import { Container, Nav, Navbar, NavDropdown } from 'react-bootstrap' import { AuthProvider, useAuth } from './context/AuthContext' import Home from './pages/Home' import ForumView from './pages/ForumView' import ThreadView from './pages/ThreadView' import Login from './pages/Login' import Register from './pages/Register' import Acp from './pages/Acp' import { useTranslation } from 'react-i18next' import { fetchSetting, fetchVersion } from './api/client' function Navigation({ theme, onThemeChange }) { const { token, email, logout, isAdmin } = useAuth() const { t, i18n } = useTranslation() const handleLanguageChange = (locale) => { i18n.changeLanguage(locale) localStorage.setItem('speedbb_lang', locale) } const handleThemeChange = (value) => { onThemeChange(value) localStorage.setItem('speedbb_theme', value) } return ( {t('app.brand')} {isAdmin && ( )} ) } function AppShell() { const { t } = useTranslation() const { isAdmin } = useAuth() const [loadMs, setLoadMs] = useState(null) const [versionInfo, setVersionInfo] = useState(null) const [theme, setTheme] = useState(() => localStorage.getItem('speedbb_theme') || 'auto') useEffect(() => { const [entry] = performance.getEntriesByType('navigation') if (entry?.duration) { setLoadMs(Math.round(entry.duration)) return } setLoadMs(Math.round(performance.now())) }, []) useEffect(() => { fetchVersion() .then((data) => setVersionInfo(data)) .catch(() => setVersionInfo(null)) }, []) useEffect(() => { fetchSetting('accent_color') .then((setting) => { if (setting?.value) { document.documentElement.style.setProperty('--bb-accent', setting.value) } }) .catch(() => {}) }, []) useEffect(() => { const root = document.documentElement const media = window.matchMedia('(prefers-color-scheme: dark)') const applyTheme = (mode) => { if (mode === 'auto') { root.setAttribute('data-bs-theme', media.matches ? 'dark' : 'light') } else { root.setAttribute('data-bs-theme', mode) } } applyTheme(theme) const handleChange = () => { if (theme === 'auto') { applyTheme('auto') } } media.addEventListener('change', handleChange) return () => { media.removeEventListener('change', handleChange) } }, [theme]) return (
} /> } /> } /> } /> } /> } />
) } export default function App() { return ( ) }