feat(web): 页头滚动信息、移除返回按钮、面包屑左侧可点、侧栏加首页

- 页头中间信息改为无缝滚动 ticker(3 份拼接,24s 线性,尊重 reduced-motion)
- 去掉分区 / 条目 / 文章三处「返回」「返回首页」按钮
- 面包屑移到左侧,中间项可点击并通过 onNavigate 走 SPA 路由
- 侧栏新增「首页」,首页时高亮,点击回首页
This commit is contained in:
stash
2026-10-29 11:26:47 +08:00
parent 2724d6f3ff
commit 22f7853bdd
9 changed files with 221 additions and 130 deletions
@@ -1,29 +0,0 @@
import { Space, Tag, Text } from '@stash/ui'
import type { ReactNode } from 'react'
/**
* 顶栏中间的一条信息,形如「[标签] 文本」。
* 标签用组件库的 Tag(success / primary 两种语气)。
*/
type HeaderInfoItemProps = {
/** 可选的前缀标签 */
tag?: string
/** 标签配色:默认蓝色,状态类用绿色 */
tone?: 'blue' | 'green'
children: ReactNode
}
export function HeaderInfoItem({ tag, tone = 'blue', children }: HeaderInfoItemProps) {
return (
<Space gap="sm">
{tag !== undefined && (
<Tag tone={tone === 'green' ? 'success' : 'primary'} shape="rounded">
{tag}
</Tag>
)}
<Text size="sm" tone="sub">
{children}
</Text>
</Space>
)
}
+56 -16
View File
@@ -1,8 +1,7 @@
import { Icon, IconButton, Space } from '@stash/ui'
import { HeaderInfoItem } from './HeaderInfoItem'
import { Icon, IconButton, Tag } from '@stash/ui'
/**
* 顶部栏:左品牌、中间运行信息、右侧操作图标。
* 顶部栏:左品牌、中间滚动信息、右侧操作图标。
* 外层 <header> 由 Layout 提供,这里只渲染栏内的内容。
*/
type SiteHeaderProps = {
@@ -13,6 +12,40 @@ type SiteHeaderProps = {
onFocusSearch: () => void
}
type InfoGroupProps = Omit<SiteHeaderProps, 'onFocusSearch'> & {
'aria-hidden'?: boolean
}
/** 运行信息:同一份内容渲染两遍,轨道平移 50% 形成无缝滚动 */
function InfoGroup({
projectCount,
sampleProject,
live,
'aria-hidden': ariaHidden,
}: InfoGroupProps) {
return (
<span className="header-ticker-group" aria-hidden={ariaHidden}>
<span className="header-ticker-item">共 {projectCount} 个本地应用</span>
{sampleProject !== undefined && (
<span className="header-ticker-item">
<Tag tone="primary" shape="rounded">
本地
</Tag>
{sampleProject}
</span>
)}
<span className="header-ticker-item">
<Tag tone={live ? 'success' : 'neutral'} shape="rounded">
状态
</Tag>
{live ? '实时同步已连接' : '等待服务连接'}
</span>
</span>
)
}
export function SiteHeader({ projectCount, sampleProject, live, onFocusSearch }: SiteHeaderProps) {
return (
<div className="site-header-inner">
@@ -23,19 +56,26 @@ export function SiteHeader({ projectCount, sampleProject, live, onFocusSearch }:
<span className="site-brand-name">STASH</span>
</a>
<Space gap="lg" className="header-info">
<HeaderInfoItem>共 {projectCount} 个本地应用</HeaderInfoItem>
<div className="header-ticker" role="status" aria-label="运行状态">
<div className="header-ticker-track">
<InfoGroup projectCount={projectCount} sampleProject={sampleProject} live={live} />
<InfoGroup
projectCount={projectCount}
sampleProject={sampleProject}
live={live}
// 后两份只用于视觉无缝,读屏忽略
aria-hidden
/>
<InfoGroup
projectCount={projectCount}
sampleProject={sampleProject}
live={live}
aria-hidden
/>
</div>
</div>
{sampleProject !== undefined && (
<HeaderInfoItem tag="本地">{sampleProject}</HeaderInfoItem>
)}
<HeaderInfoItem tag="状态" tone={live ? 'green' : 'blue'}>
{live ? '实时同步已连接' : '等待服务连接'}
</HeaderInfoItem>
</Space>
<Space gap="sm" className="header-actions">
<div className="header-actions">
<IconButton
label="聚焦搜索框(Ctrl+K)"
icon={<Icon name="search_3_line" />}
@@ -43,7 +83,7 @@ export function SiteHeader({ projectCount, sampleProject, live, onFocusSearch }:
/>
{/* TODO(auth): 后端登录接口就绪后接上,目前仅作入口占位 */}
<IconButton label="登录" icon={<Icon name="user_3_line" />} />
</Space>
</div>
</div>
)
}