feat: 全站 PageShell 设计系统与专业 UI 统一
- 新增 PageShell/PageTabs/ContentPanel/PageLoading/PageEmpty 页面骨架 - index.css 设计令牌文档化,布局令牌与纯色主按钮(去除渐变粉彩) - 全站路由页接入 PageShell,云账单三 Tab 为标杆 - 主题体系:跟随系统 + 主流/开发者分组,新增 Dracula/Tokyo Night,One Dark 暖灰差异化 - 登录页/侧栏/顶栏去渐变光球,企业克制风 - 修复 AIAlertAnalyzer JSX 与构建依赖导入问题
This commit is contained in:
1 parent
1acb0c49af
commit
e363ded445
213 files changed
+7148
-6818
No files matched your search
@@ -57,24 +57,24 @@ export function ActionModals({
|
||||
{modal?.kind === 'scale' && (
|
||||
<ModalShell title="伸缩 (Scale)" onClose={onClose}>
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs text-slate-500">当前副本: {deployment.replicas || 0}</p>
|
||||
<p className="text-xs dg-text-muted">当前副本: {deployment.replicas || 0}</p>
|
||||
<div className="flex items-center justify-center gap-3 py-3">
|
||||
<Button variant="outline" size="icon" className="border-slate-700 text-slate-300"
|
||||
<Button variant="outline" size="icon" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]"
|
||||
disabled={actionLoading === 'scale' || scaleValue <= 0}
|
||||
onClick={() => setScaleValue(v => Math.max(0, v - 1))}>
|
||||
<Minus className="h-4 w-4" />
|
||||
</Button>
|
||||
<Input type="number" min={0} value={scaleValue}
|
||||
onChange={e => setScaleValue(Math.max(0, Number(e.target.value)))}
|
||||
className="w-24 text-center text-lg font-bold bg-slate-800 border-slate-700 text-slate-200" />
|
||||
<Button variant="outline" size="icon" className="border-slate-700 text-slate-300"
|
||||
className="w-24 text-center text-lg font-bold dg-input" />
|
||||
<Button variant="outline" size="icon" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]"
|
||||
disabled={actionLoading === 'scale'}
|
||||
onClick={() => setScaleValue(v => v + 1)}>
|
||||
<Plus className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button variant="outline" className="border-slate-700 text-slate-400" onClick={onClose}>取消</Button>
|
||||
<Button variant="outline" className="border-[var(--dg-border)] dg-text-secondary" onClick={onClose}>取消</Button>
|
||||
<Button className="bg-blue-600 hover:bg-blue-700" disabled={actionLoading === 'scale'} onClick={onScaleTo}>
|
||||
{actionLoading === 'scale' ? <Loader2 className="h-4 w-4 animate-spin" /> : '确认'}
|
||||
</Button>
|
||||
@@ -87,16 +87,16 @@ export function ActionModals({
|
||||
{modal?.kind === 'delete' && (
|
||||
<ModalShell title="删除 Deployment" onClose={onClose}>
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2 text-red-400">
|
||||
<div className="flex items-center gap-2 dg-text-red">
|
||||
<AlertTriangle className="h-5 w-5" />
|
||||
<span className="font-semibold">此操作不可撤销</span>
|
||||
</div>
|
||||
<p className="text-sm text-slate-400">
|
||||
确认删除 Deployment <code className="text-slate-200 font-mono">{namespace}/{deploymentName}</code>?
|
||||
<p className="text-sm dg-text-secondary">
|
||||
确认删除 Deployment <code className="text-[var(--dg-text-primary)] font-mono">{namespace}/{deploymentName}</code>?
|
||||
其管理的所有 Pod 将被一并回收。
|
||||
</p>
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button variant="outline" className="border-slate-700 text-slate-400" onClick={onClose}>取消</Button>
|
||||
<Button variant="outline" className="border-[var(--dg-border)] dg-text-secondary" onClick={onClose}>取消</Button>
|
||||
<Button variant="destructive" disabled={actionLoading === 'delete'} onClick={onDelete}>
|
||||
{actionLoading === 'delete' ? <Loader2 className="h-4 w-4 animate-spin mr-1" /> : <Trash2 className="h-4 w-4 mr-1" />}
|
||||
确认删除
|
||||
|
||||
@@ -53,7 +53,7 @@ export function EditModeContainer({ clusterCode, namespace, deploymentName, mani
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-1 border-b border-slate-800 pb-px overflow-x-auto">
|
||||
<div className="flex items-center gap-1 border-b border-[var(--dg-border)] pb-px overflow-x-auto">
|
||||
{tabs.map((tab) => {
|
||||
const active = activeTab === tab.key;
|
||||
const Icon = tab.icon;
|
||||
@@ -62,7 +62,7 @@ export function EditModeContainer({ clusterCode, namespace, deploymentName, mani
|
||||
key={tab.key}
|
||||
onClick={() => setActiveTab(tab.key)}
|
||||
className={`flex items-center gap-1.5 px-3 py-2 text-xs font-medium border-b-2 transition-colors whitespace-nowrap ${
|
||||
active ? 'border-blue-500 text-blue-400' : 'border-transparent text-slate-400 hover:text-slate-200'
|
||||
active ? 'border-blue-500 dg-text-blue' : 'border-transparent dg-text-secondary hover:text-[var(--dg-text-primary)]'
|
||||
}`}
|
||||
>
|
||||
<Icon className="h-3.5 w-3.5" />
|
||||
|
||||
@@ -17,12 +17,12 @@ export function ModalShell({ title, children, onClose, size = 'default' }: Modal
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4" onClick={onClose}>
|
||||
<div
|
||||
className={`bg-slate-900 border border-slate-700 rounded-xl ${widthClass} max-w-[92vw] max-h-[85vh] flex flex-col shadow-2xl`}
|
||||
className={`bg-[var(--dg-bg-secondary)] border border-[var(--dg-border)] rounded-xl ${widthClass} max-w-[92vw] max-h-[85vh] flex flex-col shadow-2xl`}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<div className="flex items-center justify-between gap-3 px-6 pt-6 pb-4 shrink-0">
|
||||
<h2 className="text-base font-bold text-slate-100 truncate min-w-0" title={title}>{title}</h2>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 shrink-0 text-slate-400" onClick={onClose}><X className="h-4 w-4" /></Button>
|
||||
<h2 className="text-base font-bold text-[var(--dg-text-primary)] truncate min-w-0" title={title}>{title}</h2>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 shrink-0 dg-text-secondary" onClick={onClose}><X className="h-4 w-4" /></Button>
|
||||
</div>
|
||||
<div className="flex-1 min-h-0 overflow-y-auto px-6 pb-6">{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -63,35 +63,35 @@ export function PodLogsModal({ clusterCode, namespace, podName, containers, onCl
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60" onClick={onClose}>
|
||||
<div className="bg-slate-900 border border-slate-700 rounded-xl w-[90vw] max-w-4xl max-h-[80vh] flex flex-col" onClick={e => e.stopPropagation()}>
|
||||
<div className="flex items-center justify-between p-3 border-b border-slate-700 gap-3 shrink-0">
|
||||
<div className="bg-[var(--dg-bg-secondary)] border border-[var(--dg-border)] rounded-xl w-[90vw] max-w-4xl max-h-[80vh] flex flex-col" onClick={e => e.stopPropagation()}>
|
||||
<div className="flex items-center justify-between p-3 border-b border-[var(--dg-border)] gap-3 shrink-0">
|
||||
<div className="flex items-center gap-2 min-w-0 flex-1">
|
||||
<FileText className="h-4 w-4 shrink-0 text-blue-400" />
|
||||
<span className="text-sm font-semibold text-slate-200 truncate" title={podName}>{podName}</span>
|
||||
{container && <Badge variant="outline" className="border-slate-700 text-slate-400 text-[10px] shrink-0">{container}</Badge>}
|
||||
<FileText className="h-4 w-4 shrink-0 dg-text-blue" />
|
||||
<span className="text-sm font-semibold text-[var(--dg-text-primary)] truncate" title={podName}>{podName}</span>
|
||||
{container && <Badge variant="outline" className="border-[var(--dg-border)] dg-text-secondary text-[10px] shrink-0">{container}</Badge>}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0 flex-wrap justify-end">
|
||||
{containers.length > 0 && (
|
||||
<select value={container} onChange={e => setContainer(e.target.value)}
|
||||
className="bg-slate-800 border border-slate-700 rounded text-xs text-slate-300 px-2 py-1">
|
||||
className="bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-2 py-1">
|
||||
{containers.map(c => <option key={c} value={c}>{c}</option>)}
|
||||
</select>
|
||||
)}
|
||||
<span className="text-[11px] text-slate-500">最近</span>
|
||||
<span className="text-[11px] dg-text-muted">最近</span>
|
||||
<Input type="number" value={tail} onChange={e => setTail(Number(e.target.value) || 200)}
|
||||
className="w-16 h-7 bg-slate-800 border-slate-700 text-slate-200 text-xs" />
|
||||
<span className="text-[11px] text-slate-500">行</span>
|
||||
<Button size="sm" variant="outline" className="h-7 border-slate-700 text-slate-300 text-xs" onClick={loadLogs} disabled={loading}>
|
||||
className="w-16 h-7 dg-input text-xs" />
|
||||
<span className="text-[11px] dg-text-muted">行</span>
|
||||
<Button size="sm" variant="outline" className="h-7 border-[var(--dg-border)] text-[var(--dg-text-secondary)] text-xs" onClick={loadLogs} disabled={loading}>
|
||||
{loading ? <Loader2 className="h-3 w-3 animate-spin" /> : <RefreshCw className="h-3 w-3" />}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" className="h-7 border-slate-700 text-emerald-400 text-xs" onClick={startStream} disabled={streaming}>
|
||||
<Button size="sm" variant="outline" className="h-7 border-[var(--dg-border)] dg-text-green text-xs" onClick={startStream} disabled={streaming}>
|
||||
{streaming ? '流中...' : '实时流'}
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 text-slate-400" onClick={onClose}><X className="h-4 w-4" /></Button>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 dg-text-secondary" onClick={onClose}><X className="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto p-3">
|
||||
<pre className="bg-slate-950 rounded p-3 text-xs text-slate-300 font-mono whitespace-pre-wrap max-h-[60vh] overflow-auto">
|
||||
<pre className="bg-[var(--dg-bg-primary)] rounded p-3 text-xs text-[var(--dg-text-secondary)] font-mono whitespace-pre-wrap max-h-[60vh] overflow-auto">
|
||||
{logs || '无日志内容'}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
@@ -49,34 +49,34 @@ export function UpdateImageModal({
|
||||
<ModalShell title="调整镜像版本" onClose={onClose} size="xl">
|
||||
<div className="space-y-5">
|
||||
{/* 当前镜像:只读展示完整地址与 Tag // Logan.Li */}
|
||||
<div className="rounded-lg border border-slate-700/80 bg-slate-800/40 p-4 space-y-3">
|
||||
<p className="text-xs font-medium text-slate-400">当前镜像</p>
|
||||
<div className="rounded-lg border border-[var(--dg-border)]/80 bg-[var(--dg-bg-tertiary)]/40 p-4 space-y-3">
|
||||
<p className="text-xs font-medium dg-text-secondary">当前镜像</p>
|
||||
<div className="grid grid-cols-[1fr_180px] gap-3">
|
||||
<div>
|
||||
<Label className="text-slate-500 text-xs">镜像地址</Label>
|
||||
<Label className="dg-text-muted text-xs">镜像地址</Label>
|
||||
<p
|
||||
className="mt-1.5 text-sm text-slate-200 font-mono break-all leading-relaxed bg-slate-900/60 rounded-md px-3 py-2.5 min-h-[42px]"
|
||||
className="mt-1.5 text-sm text-[var(--dg-text-primary)] font-mono break-all leading-relaxed bg-[var(--dg-bg-secondary)]/60 rounded-md px-3 py-2.5 min-h-[42px]"
|
||||
title={current.repository || '-'}
|
||||
>
|
||||
{current.repository || '-'}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-slate-500 text-xs">当前 Tag</Label>
|
||||
<Label className="dg-text-muted text-xs">当前 Tag</Label>
|
||||
<p
|
||||
className="mt-1.5 text-sm text-cyan-300 font-mono break-all leading-relaxed bg-slate-900/60 rounded-md px-3 py-2.5 min-h-[42px]"
|
||||
className="mt-1.5 text-sm text-cyan-300 font-mono break-all leading-relaxed bg-[var(--dg-bg-secondary)]/60 rounded-md px-3 py-2.5 min-h-[42px]"
|
||||
title={current.tag || '-'}
|
||||
>
|
||||
{current.tag || '-'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-[11px] text-slate-500 font-mono break-all" title={currentImage}>
|
||||
完整引用:<span className="text-slate-400">{currentImage || '-'}</span>
|
||||
<p className="text-[11px] dg-text-muted font-mono break-all" title={currentImage}>
|
||||
完整引用:<span className="dg-text-secondary">{currentImage || '-'}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center text-slate-600">
|
||||
<div className="flex items-center justify-center dg-text-muted">
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</div>
|
||||
|
||||
@@ -85,7 +85,7 @@ export function UpdateImageModal({
|
||||
<p className="text-xs font-medium text-blue-300/90">新镜像</p>
|
||||
<div className="grid grid-cols-[1fr_180px] gap-3">
|
||||
<div>
|
||||
<Label className="text-slate-400 text-xs">镜像地址</Label>
|
||||
<Label className="dg-text-secondary text-xs">镜像地址</Label>
|
||||
<Input
|
||||
value={newRepo}
|
||||
onChange={e => {
|
||||
@@ -94,11 +94,11 @@ export function UpdateImageModal({
|
||||
syncImage(v, newTag);
|
||||
}}
|
||||
placeholder="harbor.example.com/project/app"
|
||||
className="mt-1.5 h-10 bg-slate-800 border-slate-700 text-slate-200 text-sm font-mono"
|
||||
className="mt-1.5 h-10 dg-input text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-slate-400 text-xs">新版本 Tag</Label>
|
||||
<Label className="dg-text-secondary text-xs">新版本 Tag</Label>
|
||||
<Input
|
||||
value={newTag}
|
||||
onChange={e => {
|
||||
@@ -107,37 +107,37 @@ export function UpdateImageModal({
|
||||
syncImage(newRepo, v);
|
||||
}}
|
||||
placeholder="v2.0.0"
|
||||
className="mt-1.5 h-10 bg-slate-800 border-slate-700 text-cyan-200 text-sm font-mono"
|
||||
className="mt-1.5 h-10 dg-input text-cyan-200 text-sm font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs">
|
||||
<span className="text-slate-500">Tag 变更:</span>
|
||||
<code className="px-2 py-0.5 rounded bg-slate-800 text-slate-400 font-mono">{current.tag}</code>
|
||||
<ArrowRight className="h-3 w-3 text-slate-600" />
|
||||
<span className="dg-text-muted">Tag 变更:</span>
|
||||
<code className="px-2 py-0.5 rounded bg-[var(--dg-bg-tertiary)] dg-text-secondary font-mono">{current.tag}</code>
|
||||
<ArrowRight className="h-3 w-3 dg-text-muted" />
|
||||
<code
|
||||
className={`px-2 py-0.5 rounded font-mono ${
|
||||
tagChanged ? 'bg-cyan-500/15 text-cyan-300' : 'bg-slate-800 text-slate-400'
|
||||
tagChanged ? 'bg-cyan-500/15 text-cyan-300' : 'bg-[var(--dg-bg-tertiary)] dg-text-secondary'
|
||||
}`}
|
||||
>
|
||||
{newTag.trim() || '-'}
|
||||
</code>
|
||||
{!tagChanged && !repoChanged && (
|
||||
<span className="text-slate-600">(未修改)</span>
|
||||
<span className="dg-text-muted">(未修改)</span>
|
||||
)}
|
||||
{repoChanged && !tagChanged && (
|
||||
<span className="text-amber-400/80">地址已变更</span>
|
||||
<span className="dg-text-yellow/80">地址已变更</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="text-[11px] text-slate-500 font-mono break-all">
|
||||
更新预览:<span className="text-slate-300">{previewImage || '-'}</span>
|
||||
<p className="text-[11px] dg-text-muted font-mono break-all">
|
||||
更新预览:<span className="text-[var(--dg-text-secondary)]">{previewImage || '-'}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 pt-1">
|
||||
<Button variant="outline" className="border-slate-700 text-slate-400" onClick={onClose}>
|
||||
<Button variant="outline" className="border-[var(--dg-border)] dg-text-secondary" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
|
||||
Reference in new issue
Block a user