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
@@ -39,11 +39,11 @@ interface Props {
|
||||
}
|
||||
|
||||
const VOLUME_TYPES: { key: VolumeForm['type']; label: string; icon: typeof HardDrive; color: string }[] = [
|
||||
{ key: 'persistentVolumeClaim', label: '存储卷声明', icon: Database, color: 'text-emerald-400' },
|
||||
{ key: 'emptyDir', label: '临时目录(EmptyDir)', icon: Disc, color: 'text-slate-400' },
|
||||
{ key: 'hostPath', label: 'HostPath', icon: HardDrive, color: 'text-amber-400' },
|
||||
{ key: 'nfs', label: 'NFS', icon: Server, color: 'text-purple-400' },
|
||||
{ key: 'configMap', label: '配置字典', icon: File, color: 'text-blue-400' },
|
||||
{ key: 'persistentVolumeClaim', label: '存储卷声明', icon: Database, color: 'dg-text-green' },
|
||||
{ key: 'emptyDir', label: '临时目录(EmptyDir)', icon: Disc, color: 'dg-text-secondary' },
|
||||
{ key: 'hostPath', label: 'HostPath', icon: HardDrive, color: 'dg-text-yellow' },
|
||||
{ key: 'nfs', label: 'NFS', icon: Server, color: 'dg-text-purple' },
|
||||
{ key: 'configMap', label: '配置字典', icon: File, color: 'dg-text-blue' },
|
||||
{ key: 'secret', label: '密文', icon: Lock, color: 'text-rose-400' },
|
||||
];
|
||||
|
||||
@@ -162,10 +162,10 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Card className="bg-slate-900 border-slate-800">
|
||||
<Card className="dg-card">
|
||||
<CardContent className="p-12 text-center">
|
||||
<Loader2 className="h-6 w-6 animate-spin mx-auto text-slate-500" />
|
||||
<p className="text-slate-500 mt-3 text-sm">加载中...</p>
|
||||
<Loader2 className="h-6 w-6 animate-spin mx-auto dg-text-muted" />
|
||||
<p className="dg-text-muted mt-3 text-sm">加载中...</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
@@ -173,8 +173,8 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
|
||||
if (!manifest) {
|
||||
return (
|
||||
<Card className="bg-slate-900 border-slate-800">
|
||||
<CardContent className="p-8 text-center text-slate-500">未获取到 manifest 数据,请使用 YAML 编辑模式。</CardContent>
|
||||
<Card className="dg-card">
|
||||
<CardContent className="p-8 text-center dg-text-muted">未获取到 manifest 数据,请使用 YAML 编辑模式。</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -192,26 +192,26 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
onSaved={() => { loadResources(); setCreateResource(null); }}
|
||||
/>
|
||||
)}
|
||||
<Card className="bg-slate-900 border-slate-800">
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<CardTitle className="text-sm text-slate-200 flex items-center gap-2">
|
||||
<Database className="h-4 w-4 text-emerald-400" />
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Database className="h-4 w-4 dg-text-green" />
|
||||
数据卷
|
||||
<Badge variant="outline" className="border-slate-700 text-slate-400">{entries.length}</Badge>
|
||||
<Badge variant="outline" className="border-[var(--dg-border)] dg-text-secondary">{entries.length}</Badge>
|
||||
</CardTitle>
|
||||
<p className="text-[11px] text-slate-500 mt-1">定义数据卷,并将其挂载到工作负载的容器中</p>
|
||||
<p className="text-[11px] dg-text-muted mt-1">定义数据卷,并将其挂载到工作负载的容器中</p>
|
||||
</div>
|
||||
<Button size="sm" variant="outline" className="h-7 border-slate-700 text-slate-300 text-xs shrink-0" onClick={addEntry}>
|
||||
<Button size="sm" variant="outline" className="h-7 border-[var(--dg-border)] text-[var(--dg-text-secondary)] text-xs shrink-0" onClick={addEntry}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加数据卷
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 space-y-4">
|
||||
{entries.length === 0 ? (
|
||||
<div className="text-center py-10 text-slate-500 text-sm border border-dashed border-slate-800 rounded-lg">
|
||||
<Database className="h-8 w-8 mx-auto mb-2 text-slate-700" />
|
||||
<div className="text-center py-10 dg-text-muted text-sm border border-dashed border-[var(--dg-border)] rounded-lg">
|
||||
<Database className="h-8 w-8 mx-auto mb-2 dg-text-muted" />
|
||||
未配置数据卷,点击「添加数据卷」开始
|
||||
</div>
|
||||
) : entries.map((entry, i) => {
|
||||
@@ -220,12 +220,12 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
const VIcon = vtype?.icon || Folder;
|
||||
const selectValue = SELECTABLE_TYPES.has(vol.type) ? vol.type : 'emptyDir';
|
||||
return (
|
||||
<div key={i} className="bg-slate-950/60 border border-slate-800 rounded-lg">
|
||||
<div key={i} className="bg-[var(--dg-bg-primary)]/60 border border-[var(--dg-border)] rounded-lg">
|
||||
{/* 卷定义 */}
|
||||
<div className="p-3 space-y-2.5 border-b border-slate-800/80">
|
||||
<div className="p-3 space-y-2.5 border-b border-[var(--dg-border)]/80">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<VIcon className={`h-4 w-4 ${vtype?.color || 'text-slate-400'}`} />
|
||||
<span className="text-xs text-slate-400 shrink-0">数据卷名称</span>
|
||||
<VIcon className={`h-4 w-4 ${vtype?.color || 'dg-text-secondary'}`} />
|
||||
<span className="text-xs dg-text-secondary shrink-0">数据卷名称</span>
|
||||
<Input
|
||||
value={vol.name}
|
||||
onChange={(e) => {
|
||||
@@ -237,7 +237,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
updateVolume(i, patch);
|
||||
}}
|
||||
placeholder="如 app-logs / fluent-bit-config"
|
||||
className="h-8 w-44 bg-slate-800 border-slate-700 text-slate-200 text-sm font-mono"
|
||||
className="h-8 w-44 dg-input text-sm font-mono"
|
||||
/>
|
||||
{/* 原生 select,避免 Radix Select 在 overflow 容器内无法下拉 // Logan.Li */}
|
||||
<select
|
||||
@@ -250,13 +250,13 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
if (type === 'persistentVolumeClaim' && resources.pvcs.length === 1) patch.pvcName = resources.pvcs[0];
|
||||
updateVolume(i, patch);
|
||||
}}
|
||||
className="h-8 min-w-[168px] bg-slate-800 border border-slate-700 rounded-md text-xs text-slate-300 px-2"
|
||||
className="h-8 min-w-[168px] bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded-md text-xs text-[var(--dg-text-secondary)] px-2"
|
||||
>
|
||||
{VOLUME_TYPES.map((t) => (
|
||||
<option key={t.key} value={t.key}>{t.label}</option>
|
||||
))}
|
||||
</select>
|
||||
<Button size="icon" variant="ghost" className="h-8 w-8 text-red-400 ml-auto" onClick={() => removeEntry(i)}>
|
||||
<Button size="icon" variant="ghost" className="h-8 w-8 dg-text-red ml-auto" onClick={() => removeEntry(i)}>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -280,34 +280,34 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
</div>
|
||||
|
||||
{/* 挂载到容器(支持一卷多容器,Kuboard 同卡) */}
|
||||
<div className="px-3 py-2.5 bg-slate-900/40 space-y-2">
|
||||
<div className="px-3 py-2.5 bg-[var(--dg-bg-secondary)]/40 space-y-2">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="text-[11px] text-slate-500 flex items-center gap-1.5">
|
||||
<Container className="h-3.5 w-3.5 text-blue-400" />
|
||||
<p className="text-[11px] dg-text-muted flex items-center gap-1.5">
|
||||
<Container className="h-3.5 w-3.5 dg-text-blue" />
|
||||
将上述数据卷挂载到容器
|
||||
</p>
|
||||
<Button size="sm" variant="ghost" className="h-6 px-2 text-[11px] text-slate-400 hover:text-slate-200" onClick={() => addMount(i)}>
|
||||
<Button size="sm" variant="ghost" className="h-6 px-2 text-[11px] dg-text-secondary hover:text-[var(--dg-text-primary)]" onClick={() => addMount(i)}>
|
||||
<Plus className="h-3 w-3 mr-0.5" />添加挂载
|
||||
</Button>
|
||||
</div>
|
||||
{entry.mounts.map((mount, mi) => (
|
||||
<div key={mi} className="space-y-2 rounded-md border border-slate-800/60 bg-slate-950/40 p-2.5">
|
||||
<div key={mi} className="space-y-2 rounded-md border border-[var(--dg-border)]/60 bg-[var(--dg-bg-primary)]/40 p-2.5">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<select
|
||||
value={mount.containerName}
|
||||
onChange={(e) => updateMount(i, mi, { containerName: e.target.value })}
|
||||
className="h-8 min-w-[140px] max-w-[280px] bg-slate-800 border border-slate-700 rounded-md text-sm text-slate-200 px-2 font-medium truncate"
|
||||
className="h-8 min-w-[140px] max-w-[280px] bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded-md text-sm text-[var(--dg-text-primary)] px-2 font-medium truncate"
|
||||
>
|
||||
{containers.length === 0 && <option value="">(无容器)</option>}
|
||||
{containers.map((cn) => <option key={cn} value={cn}>{cn}</option>)}
|
||||
</select>
|
||||
<div className="flex items-center gap-1 bg-slate-800 rounded-lg p-0.5 border border-slate-700">
|
||||
<div className="flex items-center gap-1 bg-[var(--dg-bg-tertiary)] rounded-lg p-0.5 border border-[var(--dg-border)]">
|
||||
<button type="button" onClick={() => updateMount(i, mi, { readOnly: true })}
|
||||
className={`px-2.5 py-1 rounded text-xs font-medium transition-all ${mount.readOnly ? 'bg-amber-500/20 text-amber-300' : 'text-slate-500 hover:text-slate-300'}`}>
|
||||
className={`px-2.5 py-1 rounded text-xs font-medium transition-all ${mount.readOnly ? 'bg-amber-500/20 text-amber-300' : 'dg-text-muted hover:text-[var(--dg-text-secondary)]'}`}>
|
||||
只读
|
||||
</button>
|
||||
<button type="button" onClick={() => updateMount(i, mi, { readOnly: false })}
|
||||
className={`px-2.5 py-1 rounded text-xs font-medium transition-all ${!mount.readOnly ? 'bg-blue-500/20 text-blue-300' : 'text-slate-500 hover:text-slate-300'}`}>
|
||||
className={`px-2.5 py-1 rounded text-xs font-medium transition-all ${!mount.readOnly ? 'bg-blue-500/20 text-blue-300' : 'dg-text-muted hover:text-[var(--dg-text-secondary)]'}`}>
|
||||
读写
|
||||
</button>
|
||||
</div>
|
||||
@@ -315,21 +315,21 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
value={mount.mountPath}
|
||||
onChange={(e) => updateMount(i, mi, { mountPath: e.target.value })}
|
||||
placeholder="挂载路径 /bitcloud/app/.../logs"
|
||||
className="h-8 flex-1 min-w-[200px] bg-slate-800 border-slate-700 text-slate-200 text-sm font-mono"
|
||||
className="h-8 flex-1 min-w-[200px] dg-input text-sm font-mono"
|
||||
/>
|
||||
{entry.mounts.length > 1 && (
|
||||
<Button size="icon" variant="ghost" className="h-8 w-8 text-red-400/70 shrink-0" onClick={() => removeMount(i, mi)}>
|
||||
<Button size="icon" variant="ghost" className="h-8 w-8 dg-text-red/70 shrink-0" onClick={() => removeMount(i, mi)}>
|
||||
<Trash2 className="h-3.5 w-3.5" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[11px] text-slate-500 shrink-0">子路径 subPath</span>
|
||||
<span className="text-[11px] dg-text-muted shrink-0">子路径 subPath</span>
|
||||
<Input
|
||||
value={mount.subPath}
|
||||
onChange={(e) => updateMount(i, mi, { subPath: e.target.value })}
|
||||
placeholder="如 config.yaml(挂载单文件时填写)"
|
||||
className="h-7 flex-1 max-w-md bg-slate-800 border-slate-700 text-slate-300 text-xs font-mono"
|
||||
className="h-7 flex-1 max-w-md dg-input text-[var(--dg-text-secondary)] text-xs font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -342,7 +342,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
</Card>
|
||||
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button variant="outline" className="border-slate-700 text-slate-400" onClick={onCancel}>取消</Button>
|
||||
<Button variant="outline" className="border-[var(--dg-border)] dg-text-secondary" onClick={onCancel}>取消</Button>
|
||||
<Button className="bg-blue-600 hover:bg-blue-700" disabled={saving} onClick={save}>
|
||||
{saving ? <Loader2 className="h-4 w-4 animate-spin mr-1" /> : <Save className="h-4 w-4 mr-1" />}
|
||||
保存
|
||||
|
||||
Reference in new issue
Block a user