Files
DeveloperandClaude Opus 4.6 12768a890b feat: 优化标题栏高度和垂直居中显示
- 调整 AppShell header 高度为 56px 并添加内联样式强制垂直居中
- 优化月份选择器按钮大小为 36px
- 更新 SPEC.md 添加端口配置说明 (前端 3500, 后端 3501)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 11:36:27 +08:00

71 lines
2.5 KiB
JavaScript

import { useMemo } from 'react';
import { useRouter } from 'next/router';
import { Icon } from './icons';
const tabs = [
{ href: '/', label: '首页', icon: 'home' },
{ href: '/stats', label: '统计', icon: 'chart' },
{ href: '/recurring', label: '周期', icon: 'repeat' },
{ href: '/categories', label: '分类', icon: 'tags' },
];
export default function AppShell({ title, subtitle, actions, headerContent, children, contentClassName = '', hideNav = false, compactHeader = false }) {
const router = useRouter();
const activeTab = useMemo(() => {
const matched = tabs.find((tab) => tab.href === router.pathname);
return matched?.href || null;
}, [router.pathname]);
const headerNode = headerContent || (title ? (
<div className="app-header__text">
<h1>{title}</h1>
{subtitle ? <p>{subtitle}</p> : null}
</div>
) : null);
const headerClassName = [
'app-header',
compactHeader ? 'app-header--compact' : '',
headerNode ? 'app-header--with-content' : 'app-header--actions-only',
actions ? 'app-header--with-actions' : '',
].filter(Boolean).join(' ');
return (
<div className={`app-shell${hideNav ? ' app-shell--standalone' : ''}`}>
<header className={headerClassName} style={{minHeight: 56, height: 56, padding: 0, display: 'flex', alignItems: 'center'}}>
<div className="app-shell__container app-header__inner">
{headerNode ? <div className="app-header__main">{headerNode}</div> : <div className="app-header__spacer" aria-hidden="true" />}
{actions ? <div className="app-header__actions">{actions}</div> : null}
</div>
</header>
<main className={`app-content ${contentClassName}`.trim()}>
<div className="app-shell__container app-content__inner">{children}</div>
</main>
{!hideNav ? (
<nav className="bottom-nav" aria-label="主导航">
<div className="app-shell__container bottom-nav__inner">
{tabs.map((tab) => {
const isActive = activeTab === tab.href;
return (
<button
key={tab.href}
type="button"
className={`bottom-nav__item${isActive ? ' is-active' : ''}`}
onClick={() => router.push(tab.href)}
aria-current={isActive ? 'page' : undefined}
>
<Icon name={tab.icon} size={20} />
<span>{tab.label}</span>
</button>
);
})}
</div>
</nav>
) : null}
</div>
);
}