refactor(web): 前端改用 @stash/ui 组件库

- 新增本地依赖 @stash/ui(file:../../stash-ui),引入其 style.css 与设计令牌
- 页面骨架改用 Layout(contained + header/sider),搜索框改为吸顶
- 卡片/菜单/按钮/标签/头像/分页/空态/提示全部换成组件库组件
- 删除本地 iconfont 与 1400 行手写组件样式,App.css 只保留页面级样式
- 数据层、路由、过滤逻辑未改动;33 个 Rust 测试通过
This commit is contained in:
stash
2026-10-28 12:44:50 +08:00
parent 19ead7b716
commit 64f1fbf906
35 changed files with 735 additions and 2154 deletions
@@ -1,5 +1,5 @@
import { Button, Card, Divider, Icon, Space, Tag, Text, Title } from '@stash/ui'
import type { Project } from '../../api'
import { LinkIcon, RefreshIcon } from '../common/Icon'
/**
* 本地服务面板:连接状态、项目数、访问地址,以及两个操作入口。
@@ -16,50 +16,52 @@ export function ServicePanel({ projects, live, refreshing, onRefresh }: ServiceP
const host = typeof window === 'undefined' ? '-' : window.location.host
return (
<section className="service-panel card-box" aria-label="本地服务状态">
<header className="service-head">
<h2 className="service-title">本地服务</h2>
<span className={`service-pill${live ? ' is-on' : ''}`}>
<span className={`status-dot${live ? ' is-on' : ''}`} aria-hidden="true" />
<Card padding="md" className="service-panel">
<Space justify="between">
<Title level={4} as="h2">
本地服务
</Title>
<Tag tone={live ? 'success' : 'neutral'} dot>
{live ? '已连接' : '未连接'}
</span>
</header>
</Tag>
</Space>
<dl className="service-stats">
<div>
<dt>项目数</dt>
<dd>{projects.length}</dd>
</div>
<div>
<dt>访问地址</dt>
<dd title={host}>{host}</dd>
</div>
</dl>
<Divider spacing="sm" />
<div className="service-actions">
<button
type="button"
className="service-action"
title="重新扫描项目"
data-spinning={refreshing}
disabled={refreshing}
onClick={onRefresh}
>
<RefreshIcon />
<span>重新扫描</span>
</button>
<a
className="service-action"
href="/api/projects"
target="_blank"
rel="noreferrer"
title="查看项目接口"
>
<LinkIcon />
<span>查看接口</span>
</a>
<div className="service-stats">
<Space justify="between">
<Text size="sm" tone="sub">
项目数
</Text>
<Text strong>{projects.length}</Text>
</Space>
<Space justify="between">
<Text size="sm" tone="sub">
访问地址
</Text>
<Text size="sm" truncate title={host} className="service-host">
{host}
</Text>
</Space>
</div>
</section>
<Space gap="sm" wrap>
<Button
size="sm"
variant="ghost"
loading={refreshing}
icon={<Icon name="refresh_3_line" />}
onClick={onRefresh}
title="重新扫描项目"
>
重新扫描
</Button>
<a className="link-button" href="/api/projects" target="_blank" rel="noreferrer">
<Icon name="link_3_line" />
查看接口
</a>
</Space>
</Card>
)
}