Files
Profeto/frontend/src/App.tsx
T
shangfangjian 95be59bc9f 去掉刊头下方副标题文案
- 首页移除「足球比分预测 · 五路专家 · 终裁汇总」
- 积分榜页移除「联赛积分榜 · 积分 / 净胜 / xG差 / 近期走势」
- 刊头仅保留「先知」毛笔字,更简洁

Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
)
2026-09-20 23:01:13 +08:00

136 lines
4.8 KiB
TypeScript

/**
* 主应用入口
*
* 页面结构:
* - / → 先知主站(报纸风赛程 + 预测),报头含「评估」「管理」入口
* - /admin/* → 管理后台(鉴权门禁,未登录引导登录)
*
* 导航策略:
* - 首页报头放「评估」「管理」入口(极简,不另加导航条)
* - 管理后台由 AdminLayout 侧边栏处理所有管理页导航
* - 未登录访问管理 → AdminLayout 门禁 → 登录页(不静默失败)
*/
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import { ErrorBoundary } from './components/ErrorBoundary'
import Matches from './pages/Matches'
import Standings from './pages/Standings'
import { adminRoutes } from './admin/routes'
/** 报眉日期行 */
function dateLine(): string {
return new Date().toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
})
}
function StandingsLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen bg-paper-50">
<header className="masthead-rule">
<div className="mx-auto max-w-5xl px-5 sm:px-8">
<div className="border-b border-ink-900 py-5 text-center sm:py-6">
<h1 className="font-brush text-5xl text-ink-900 sm:text-6xl">
先知
</h1>
</div>
<div className="flex items-center justify-between border-b border-ink-200 py-2 text-2xs text-ink-500">
<span>{dateLine()}</span>
<nav className="flex items-center gap-4" aria-label="页面导航">
<a href="/" className="text-ink-500 hover:text-press transition-colors">
比赛 / 预测
</a>
<a href="/admin/eval" className="text-ink-500 hover:text-press transition-colors">
评估
</a>
<a href="/admin" className="flex items-center gap-1 text-ink-500 hover:text-press transition-colors">
<span aria-hidden="true"></span> 管理
</a>
</nav>
</div>
</div>
</header>
<main className="mx-auto max-w-5xl px-5 py-6 sm:px-8 sm:py-8">
{children}
</main>
<footer className="mx-auto max-w-5xl px-5 pb-10 sm:px-8">
<div className="border-t border-ink-200 pt-3 text-center text-2xs leading-relaxed text-ink-400">
数据由 bzzoiro 提供 · 仅供研究参考
</div>
</footer>
</div>
)
}
function HomePage() {
return (
<div className="min-h-screen bg-paper-50">
{/* ── 报头:粗线 + 居中刊名 + 日期与分区链接 ── */}
<header className="masthead-rule">
<div className="mx-auto max-w-5xl px-5 sm:px-8">
<div className="border-b border-ink-900 py-5 text-center sm:py-6">
<h1 className="font-brush text-5xl text-ink-900 sm:text-6xl">
先知
</h1>
</div>
<div className="flex items-center justify-between border-b border-ink-200 py-2 text-2xs text-ink-500">
<span>{dateLine()}</span>
<nav className="flex items-center gap-4" aria-label="页面导航">
<a href="/standings" className="text-ink-500 hover:text-press transition-colors">
积分榜
</a>
<a href="/admin/eval" className="text-ink-500 hover:text-press transition-colors">
评估
</a>
<a href="/admin" className="flex items-center gap-1 text-ink-500 hover:text-press transition-colors">
<span aria-hidden="true"></span> 管理
</a>
</nav>
</div>
</div>
</header>
<main className="mx-auto max-w-5xl px-5 py-6 sm:px-8 sm:py-8">
<Matches />
</main>
<footer className="mx-auto max-w-5xl px-5 pb-10 sm:px-8">
<div className="border-t border-ink-200 pt-3 text-center text-2xs leading-relaxed text-ink-400">
预测结果由大语言模型生成 · 仅供研究参考 · 不构成任何投注建议
</div>
</footer>
</div>
)
}
export default function App() {
return (
<ErrorBoundary>
<BrowserRouter>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/standings" element={<StandingsLayout><Standings /></StandingsLayout>} />
{adminRoutes.map(route => (
<Route key={route.path} path={route.path} element={route.element}>
{route.children.map(child => (
<Route
key={child.path ?? 'index'}
index={child.index}
path={child.path}
element={child.element}
/>
))}
</Route>
))}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>
</ErrorBoundary>
)
}