Files
Profeto/frontend/src/components/Masthead.tsx
T
WorkBuddy 9c77efaa4b refactor(frontend): 报头抽组件 Masthead + 回到顶部抽组件 BackTop
- Masthead:统一 HomePage/StandingsLayout 双份复制实现,当前版面
  印报红高亮 + aria-current;⚙ 字符改线条 SVG;管理类入口加 title
  提示需登录,访客不再被无声踢到登录页
- BackTop:两页各一份的浮动按钮收敛为共享组件,去 rounded-full/
  shadow-lg,与全站方角无阴影语言对齐
2026-09-22 16:55:59 +08:00

78 lines
3.3 KiB
TypeScript

/**
* 报头组件(前台共用)。
*
* 此前 HomePage 与 StandingsLayout 各自复制一份报头,导航项已经漂移
* (首页有「积分榜」、积分榜页有「比赛/预测」),且无当前页高亮。
* 现在统一为 Masthead:
* - active 声明当前版面,对应导航项加印报红高亮 + aria-current
* - 「管理」入口改用与全站一致的线条 SVG(替代字符 ⚙)
* - 管理类入口带 title 提示,避免访客被无声踢到登录页
* 页脚文案各页不同,仍由调用方自行渲染。
*/
import { Link } from 'react-router-dom'
export type MastheadActive = 'home' | 'standings'
function GearIcon() {
return (
<svg className="h-3 w-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2} aria-hidden="true">
<circle cx="12" cy="12" r="3" />
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68 1.65 1.65 0 0 0 10 3.17V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
</svg>
)
}
function MastheadLink({
to,
active = false,
title,
children,
}: {
to: string
/** 当前版面才高亮;管理类入口无高亮概念 */
active?: boolean
title?: string
children: React.ReactNode
}) {
return (
<Link
to={to}
title={title}
aria-current={active ? 'page' : undefined}
className={`transition-colors ${
active ? 'font-medium text-press' : 'text-ink-500 hover:text-press'
}`}
>
{children}
</Link>
)
}
export default function Masthead({ active }: { active: MastheadActive }) {
return (
<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>{new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' })}</span>
<nav className="flex items-center gap-4" aria-label="页面导航">
<MastheadLink to="/" active={active === 'home'}>比赛 / 预测</MastheadLink>
<MastheadLink to="/standings" active={active === 'standings'}>积分榜</MastheadLink>
{/* 管理类页面对访客需要登录,入口处先说明,避免无声跳登录页 */}
<MastheadLink to="/admin/eval" title="评估页面向管理员开放,需登录">评估</MastheadLink>
<MastheadLink to="/admin" title="管理后台,需登录">
<span className="inline-flex items-center gap-1">
<GearIcon /> 管理
</span>
</MastheadLink>
</nav>
</div>
</div>
</header>
)
}