fix(ui): 對齊 figma-v2 設計稿 — IncidentCard + OpenClawPanel 視覺修正
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 35s
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 35s
IncidentCard: - 背景 #fff、圓角 12px、頂邊條 4px(對齊設計稿) - P1 嚴重度色修正為 #F59E0B(amber,非 orange) - Severity badge 改為 4px 圓角 uppercase 樣式 - Impact 指標列移除灰底方塊,改為細邊框分隔線 - AI 提案按鈕改為全寬居中橙色風格 OpenClawPanel: - 移除多餘 rounded-xl/backdrop/border(由父層卡片容器提供) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -182,13 +182,8 @@ export function OpenClawPanel({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'relative overflow-hidden rounded-xl',
|
||||
// awoooi-glass effect
|
||||
'bg-white/70 backdrop-blur-[20px]',
|
||||
// 骨架細框線
|
||||
'border border-nothing-gray-200/50',
|
||||
// 輕柔陰影
|
||||
'shadow-[0_4px_24px_rgba(0,0,0,0.06)]',
|
||||
'relative overflow-hidden',
|
||||
'bg-white',
|
||||
'p-4',
|
||||
className
|
||||
)}
|
||||
|
||||
@@ -39,10 +39,10 @@ export interface IncidentCardProps {
|
||||
// =============================================================================
|
||||
|
||||
const SEV_CONFIG = {
|
||||
P0: { barColor: '#cc2200', label: 'P0', labelBg: '#ffeaea', labelColor: '#cc2200' },
|
||||
P1: { barColor: '#d97757', label: 'P1', labelBg: '#fff0ea', labelColor: '#b05030' },
|
||||
P2: { barColor: '#4A90D9', label: 'P2', labelBg: '#eaf4ff', labelColor: '#2a6cb0' },
|
||||
P3: { barColor: '#22C55E', label: 'P3', labelBg: '#eafff2', labelColor: '#166534' },
|
||||
P0: { barColor: '#cc2200', label: 'P0', labelBg: 'rgba(204,34,0,0.1)', labelColor: '#cc2200' },
|
||||
P1: { barColor: '#F59E0B', label: 'P1', labelBg: 'rgba(245,158,11,0.12)', labelColor: '#d97000' },
|
||||
P2: { barColor: '#4A90D9', label: 'P2', labelBg: 'rgba(74,144,217,0.12)', labelColor: '#4A90D9' },
|
||||
P3: { barColor: '#22C55E', label: 'P3', labelBg: 'rgba(34,197,94,0.1)', labelColor: '#16a34a' },
|
||||
} as const
|
||||
|
||||
/** 根據 incident status 對應 FlowStage */
|
||||
@@ -282,37 +282,38 @@ export function IncidentCard({ incident, decision, onApprovalChange }: IncidentC
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
background: '#faf9f3',
|
||||
background: '#fff',
|
||||
border: '0.5px solid #e0ddd4',
|
||||
borderRadius: 8,
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
marginBottom: 8,
|
||||
boxShadow: '0 1px 4px rgba(0,0,0,0.05)',
|
||||
}}>
|
||||
{/* 頂邊條 3px */}
|
||||
<div style={{ height: 3, background: sevCfg.barColor, borderRadius: '8px 8px 0 0' }} />
|
||||
{/* 頂邊條 4px */}
|
||||
<div style={{ height: 4, background: sevCfg.barColor }} />
|
||||
|
||||
{/* 標頭列:嚴重度 + 服務標籤 + 時間 */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '8px 10px 4px' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 14px 4px' }}>
|
||||
<span style={{
|
||||
fontSize: 12, fontWeight: 700, padding: '2px 8px',
|
||||
fontSize: 10, fontWeight: 700, padding: '2px 7px',
|
||||
background: sevCfg.labelBg, color: sevCfg.labelColor,
|
||||
borderRadius: 10, flexShrink: 0,
|
||||
borderRadius: 4, flexShrink: 0, textTransform: 'uppercase', letterSpacing: '1px',
|
||||
}}>
|
||||
{sevCfg.label}
|
||||
</span>
|
||||
<span style={{
|
||||
fontSize: 12, color: '#87867f', background: '#ece9e0',
|
||||
border: '0.5px solid #dedad0', padding: '2px 7px', borderRadius: 10,
|
||||
fontSize: 10, color: '#87867f',
|
||||
border: '0.5px solid #e0ddd4', padding: '2px 7px', borderRadius: 4,
|
||||
background: '#fff',
|
||||
}}>
|
||||
{serviceName}
|
||||
</span>
|
||||
<span style={{ marginLeft: 'auto', fontSize: 12, color: '#b0ad9f' }}>
|
||||
<span style={{ marginLeft: 'auto', fontSize: 11, color: '#b0ad9f' }}>
|
||||
{duration}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* 事件標題 — 從 decision action 或 affected_services 組合 */}
|
||||
<div style={{ padding: '2px 10px 4px', fontSize: 14, fontWeight: 600, color: '#141413', lineHeight: 1.4 }}>
|
||||
<div style={{ padding: '4px 14px 2px', fontSize: 15, fontWeight: 600, color: '#141413', lineHeight: 1.3, fontFamily: 'var(--font-body), monospace' }}>
|
||||
{incident.decision?.proposal_data?.action
|
||||
?? (incident.affected_services?.length
|
||||
? `${incident.affected_services.join(', ')} ${t('anomaly')}`
|
||||
@@ -320,7 +321,7 @@ export function IncidentCard({ incident, decision, onApprovalChange }: IncidentC
|
||||
</div>
|
||||
|
||||
{/* INC-ID */}
|
||||
<div style={{ padding: '0 10px 4px', fontSize: 12, color: '#b0ad9f', fontFamily: 'var(--font-body), monospace' }}>
|
||||
<div style={{ padding: '0 14px 6px', fontSize: 12, color: '#b0ad9f', fontFamily: 'var(--font-body), monospace' }}>
|
||||
{incident.incident_id}
|
||||
</div>
|
||||
|
||||
@@ -329,22 +330,20 @@ export function IncidentCard({ incident, decision, onApprovalChange }: IncidentC
|
||||
|
||||
{/* Impact 指標列 */}
|
||||
<div style={{
|
||||
margin: '0 10px 6px',
|
||||
padding: '5px 8px',
|
||||
background: '#f0efe8',
|
||||
border: '0.5px solid #e0ddd4',
|
||||
borderRadius: 6,
|
||||
margin: '0 14px 8px',
|
||||
padding: '6px 0',
|
||||
borderTop: '0.5px solid #e0ddd4',
|
||||
borderBottom: '0.5px solid #e0ddd4',
|
||||
display: 'flex',
|
||||
gap: 12,
|
||||
flexWrap: 'wrap' as const,
|
||||
gap: 16,
|
||||
}}>
|
||||
<span style={{ fontSize: 13, color: '#87867f' }}>
|
||||
<span style={{ fontSize: 11, color: '#87867f' }}>
|
||||
{t('affectedServices')} <strong style={{ color: '#141413' }}>{incident.affected_services?.length ?? 0}</strong>
|
||||
</span>
|
||||
<span style={{ fontSize: 13, color: '#87867f' }}>
|
||||
<span style={{ fontSize: 11, color: '#87867f' }}>
|
||||
{t('signalCount')} <strong style={{ color: '#141413' }}>{incident.signal_count ?? '--'}</strong>
|
||||
</span>
|
||||
<span style={{ fontSize: 13, color: '#87867f' }}>
|
||||
<span style={{ fontSize: 11, color: '#87867f' }}>
|
||||
{t('statusLabel')} <strong style={{ color: '#141413' }}>{incident.status}</strong>
|
||||
</span>
|
||||
</div>
|
||||
@@ -355,26 +354,24 @@ export function IncidentCard({ incident, decision, onApprovalChange }: IncidentC
|
||||
<button
|
||||
onClick={() => setAiExpanded(v => !v)}
|
||||
style={{
|
||||
margin: '0 10px 6px',
|
||||
padding: '5px 8px',
|
||||
background: '#f0efe8',
|
||||
border: '0.5px solid #e0ddd4',
|
||||
borderLeft: '3px solid rgba(217,119,87,0.5)',
|
||||
margin: '0 14px 10px',
|
||||
padding: '7px 0',
|
||||
background: 'rgba(217,119,87,0.08)',
|
||||
border: '0.5px solid rgba(217,119,87,0.3)',
|
||||
borderRadius: 6,
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 5,
|
||||
fontSize: 13,
|
||||
color: '#87867f',
|
||||
width: 'calc(100% - 20px)',
|
||||
textAlign: 'left' as const,
|
||||
fontSize: 12,
|
||||
color: '#d97757',
|
||||
width: 'calc(100% - 28px)',
|
||||
textAlign: 'center' as const,
|
||||
fontFamily: 'inherit',
|
||||
}}
|
||||
>
|
||||
<span style={{ color: '#d97757' }}>▶</span>
|
||||
<span>{t('aiProposal')}: {decisionAction.slice(0, 50)}{decisionAction.length > 50 ? '...' : ''}</span>
|
||||
<span style={{ marginLeft: 'auto' }}>{aiExpanded ? '▲' : '▼'}</span>
|
||||
<span>▸ {t('aiProposal')}: {decisionAction.slice(0, 50)}{decisionAction.length > 50 ? '...' : ''}</span>
|
||||
</button>
|
||||
{aiExpanded && (
|
||||
<div style={{
|
||||
@@ -400,7 +397,7 @@ export function IncidentCard({ incident, decision, onApprovalChange }: IncidentC
|
||||
|
||||
{/* 授權按鈕(僅 waiting_approval 狀態)*/}
|
||||
{isWaitingApproval && (
|
||||
<div style={{ padding: '6px 10px 10px', display: 'flex', justifyContent: 'flex-end' }}>
|
||||
<div style={{ padding: '6px 14px 12px', display: 'flex', justifyContent: 'flex-end' }}>
|
||||
{renderApproveButtons()}
|
||||
{errorMessage && (
|
||||
<span style={{ fontSize: 12, color: '#cc2200', marginLeft: 6, maxWidth: 160, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }} title={errorMessage}>
|
||||
|
||||
Reference in New Issue
Block a user