66 lines
1.8 KiB
TypeScript
66 lines
1.8 KiB
TypeScript
import type { Project } from '../../api'
|
|
import { LinkIcon, RefreshIcon } from '../common/Icon'
|
|
|
|
/**
|
|
* 本地服务面板:连接状态、项目数、访问地址,以及两个操作入口。
|
|
* 只读展示 + 触发刷新,不负责导航。
|
|
*/
|
|
type ServicePanelProps = {
|
|
projects: Project[]
|
|
live: boolean
|
|
refreshing: boolean
|
|
onRefresh: () => void
|
|
}
|
|
|
|
export function ServicePanel({ projects, live, refreshing, onRefresh }: ServicePanelProps) {
|
|
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" />
|
|
{live ? '已连接' : '未连接'}
|
|
</span>
|
|
</header>
|
|
|
|
<dl className="service-stats">
|
|
<div>
|
|
<dt>项目数</dt>
|
|
<dd>{projects.length}</dd>
|
|
</div>
|
|
<div>
|
|
<dt>访问地址</dt>
|
|
<dd title={host}>{host}</dd>
|
|
</div>
|
|
</dl>
|
|
|
|
<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>
|
|
</section>
|
|
)
|
|
}
|