feat: 全站 PageShell 设计系统与专业 UI 统一

- 新增 PageShell/PageTabs/ContentPanel/PageLoading/PageEmpty 页面骨架
- index.css 设计令牌文档化,布局令牌与纯色主按钮(去除渐变粉彩)
- 全站路由页接入 PageShell,云账单三 Tab 为标杆
- 主题体系:跟随系统 + 主流/开发者分组,新增 Dracula/Tokyo Night,One Dark 暖灰差异化
- 登录页/侧栏/顶栏去渐变光球,企业克制风
- 修复 AIAlertAnalyzer JSX 与构建依赖导入问题
This commit is contained in:
Logan committed 2026-07-01 12:45:38 +08:00
1 parent 1acb0c49af
commit e363ded445
213 files changed
+7148 -6818

No files matched your search

@@ -20,6 +20,7 @@ import { YamlViewer } from './YamlViewer';
import { PodExecTerminal } from './PodExecTerminal';
import { PodFileBrowser } from './PodFileBrowser';
import { formatK8sTime, statusColor, STATUS_COLORS } from './k8s-yaml-utils';
import { PageShell } from '@/components/layout/PageShell';
import type { JsonData } from '@/types/common';
type WorkloadKind = 'StatefulSet' | 'DaemonSet';
@@ -187,60 +188,50 @@ export default function WorkloadViewPage() {
const labels = manifest?.metadata?.labels || {};
const annotations = manifest?.metadata?.annotations || {};
const modeTabs = (
<div className="flex items-center gap-1 bg-[var(--dg-bg-secondary)] border border-[var(--dg-border)] rounded-lg p-0.5">
<button className={`px-3 py-1 text-xs rounded transition-colors ${mode === 'view' ? 'bg-[var(--dg-blue)]/20 text-[var(--dg-blue)]' : 'text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]'}`} onClick={() => handleModeChange('view')}>查看</button>
<button className={`px-3 py-1 text-xs rounded transition-colors ${mode === 'yaml' ? 'bg-[var(--dg-blue)]/20 text-[var(--dg-blue)]' : 'text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]'}`} onClick={() => handleModeChange('yaml')}>YAML</button>
</div>
);
return (
<div className="p-4 space-y-4">
{/* Header */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Button variant="ghost" size="icon" className="h-8 w-8 text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]" onClick={() => navigate(-1)}>
<ArrowLeft className="h-4 w-4" />
<PageShell
variant="workspace"
title={name}
subtitle={`${clusterCode} / ${namespace} · ${kind}`}
icon={<Boxes className="h-5 w-5" />}
loading={loading}
loadingLabel="加载工作负载..."
actions={(
<>
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => navigate(-1)}>
<ArrowLeft className="h-4 w-4 mr-1" />返回
</Button>
<Boxes className="h-5 w-5 text-[var(--dg-blue)]" />
<div>
<div className="flex items-center gap-2">
<h1 className="text-lg font-bold text-[var(--dg-text-primary)]">{name}</h1>
<Badge variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">{kind}</Badge>
<Badge variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">{namespace}</Badge>
{isHealthy
? <Badge className="bg-[var(--dg-green)]/20 text-[var(--dg-green)] border-[var(--dg-green)]/30">健康</Badge>
: <Badge className="bg-[var(--dg-orange)]/20 text-[var(--dg-orange)] border-[var(--dg-orange)]/30">更新中</Badge>}
</div>
<p className="text-xs text-[var(--dg-text-muted)] mt-0.5">集群: {clusterCode}</p>
</div>
</div>
<div className="flex items-center gap-2">
{/* Mode tabs */}
<div className="flex items-center gap-1 bg-[var(--dg-bg-secondary)] border border-[var(--dg-border)] rounded-lg p-0.5">
<button
className={`px-3 py-1 text-xs rounded transition-colors ${mode === 'view' ? 'bg-[var(--dg-blue)]/20 text-[var(--dg-blue)]' : 'text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]'}`}
onClick={() => handleModeChange('view')}
>查看</button>
<button
className={`px-3 py-1 text-xs rounded transition-colors ${mode === 'yaml' ? 'bg-[var(--dg-blue)]/20 text-[var(--dg-blue)]' : 'text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]'}`}
onClick={() => handleModeChange('yaml')}
>YAML</button>
</div>
{/* Actions */}
{modeTabs}
{isSts && (
<Button variant="outline" size="sm" className="h-8 border-[var(--dg-border)] text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]"
onClick={() => { setScaleValue(replicas); setScaleModal(true); }}>
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => { setScaleValue(replicas); setScaleModal(true); }}>
<Boxes className="h-3.5 w-3.5 mr-1" />伸缩
</Button>
)}
<Button variant="outline" size="sm" className="h-8 border-[var(--dg-border)] text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]"
disabled={actionLoading} onClick={handleRestart}>
<Button variant="outline" size="sm" className="dg-btn-secondary" disabled={actionLoading} onClick={handleRestart}>
<RotateCcw className="h-3.5 w-3.5 mr-1" />{actionLoading ? '重启中...' : '重启'}
</Button>
<Button variant="outline" size="sm" className="h-8 border-[var(--dg-border)] text-[var(--dg-text-secondary)] hover:text-[var(--dg-text-primary)]"
onClick={() => setYamlModal(true)}>
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => setYamlModal(true)}>
<FileCode className="h-3.5 w-3.5 mr-1" />YAML
</Button>
</div>
</>
)}
>
<div className="flex items-center gap-2 mb-4">
<Badge variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">{kind}</Badge>
<Badge variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">{namespace}</Badge>
{isHealthy
? <Badge className="bg-[var(--dg-green)]/20 text-[var(--dg-green)] border-[var(--dg-green)]/30">健康</Badge>
: <Badge className="bg-[var(--dg-orange)]/20 text-[var(--dg-orange)] border-[var(--dg-orange)]/30">更新中</Badge>}
</div>
{loading ? (
<div className="text-center text-[var(--dg-text-muted)] py-20">加载中...</div>
) : mode === 'yaml' ? (
{!loading && (mode === 'yaml' ? (
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="p-4">
<YamlViewer
@@ -487,7 +478,7 @@ export default function WorkloadViewPage() {
</CardContent>
</Card>
</>
)}
))}
{/* Scale modal */}
{scaleModal && (
@@ -547,7 +538,7 @@ export default function WorkloadViewPage() {
containers={fileBrowserPod.containers?.map((c: JsonData) => c.name).filter(Boolean) || []}
/>
)}
</div>
</PageShell>
);
}