From 7b4a7e1950510d17c6f0d79028cf9ed0b1f8b7d3 Mon Sep 17 00:00:00 2001 From: Macbook Date: Thu, 11 Jun 2026 16:48:32 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EC=B9=B4=EB=93=9C=20=E2=80=94=20=EB=88=88=EA=B8=88?= =?UTF-8?q?=20=EB=A0=88=EC=9D=B4=EB=B8=94+=EB=B8=94=EB=A1=9D=EB=B0=94+?= =?UTF-8?q?=EC=8B=A0=ED=98=B8=EB=93=B1=20=EB=8F=99=EC=9D=BC=20=EB=86=92?= =?UTF-8?q?=EC=9D=B4=20=EC=A0=95=EB=A0=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../dashboard/DashboardSystemCard.tsx | 48 +++++++++---- frontend/src/styles/dashboardCommand.css | 68 ++++++++++++++----- 2 files changed, 85 insertions(+), 31 deletions(-) diff --git a/frontend/src/components/dashboard/DashboardSystemCard.tsx b/frontend/src/components/dashboard/DashboardSystemCard.tsx index 1a6dfd4..5cb5d96 100644 --- a/frontend/src/components/dashboard/DashboardSystemCard.tsx +++ b/frontend/src/components/dashboard/DashboardSystemCard.tsx @@ -1,13 +1,15 @@ import React from 'react'; interface Props { - label: string; - pct: number; // 0–100 - usedLabel: string; // e.g. "5.8GB" - totalLabel: string; // e.g. "7.8GB" + label: string; + pct: number; // 0–100 + usedLabel: string; + totalLabel: string; } -const BLOCKS = 12; +const BLOCKS = 10; // 10단계 (0%~100%, 10%씩) +// 눈금 레이블: top→bottom (100%→0%) +const TICK_LABELS = ['100%', '80%', '60%', '40%', '20%', '0%']; function trafficLevel(pct: number): 'green' | 'yellow' | 'red' { if (pct >= 90) return 'red'; @@ -15,9 +17,17 @@ function trafficLevel(pct: number): 'green' | 'yellow' | 'red' { return 'green'; } -/** 리소스 카드 — 세로 블록 바 + 신호등 */ +/** 블록 인덱스(0=bottom)에 따른 색상 — 낮은 사용률=초록, 높은 사용률=빨강 */ +function blockTone(idx: number): string { + if (idx >= 8) return 'gc-sys-block--hi'; // 80–100% → 빨강 + if (idx >= 5) return 'gc-sys-block--mid'; // 50–80% → 노랑 + return 'gc-sys-block--lo'; // 0–50% → 초록 +} + +/** 리소스 카드 — 눈금 + 세로 블록 바 + 신호등 (같은 높이 정렬) */ export default function DashboardSystemCard({ label, pct, usedLabel, totalLabel }: Props) { const clamped = Math.max(0, Math.min(100, pct)); + // 아래→위로 채움: filled 개수만큼 하단부터 켜짐 const filled = Math.round((clamped / 100) * BLOCKS); const level = trafficLevel(clamped); @@ -25,15 +35,23 @@ export default function DashboardSystemCard({ label, pct, usedLabel, totalLabel
{label} + {/* 바 + 신호등을 같은 높이로 정렬 */}
+ + {/* 눈금 레이블 열 */} +
+ {TICK_LABELS.map(t => ( + {t} + ))} +
+ {/* 세로 블록 바 */}
{Array.from({ length: BLOCKS }, (_, i) => { - const idx = BLOCKS - 1 - i; // 위→낮음, 아래→높음 - const on = idx < filled; - let tone = 'gc-sys-block--mid'; - if (idx >= BLOCKS - 3) tone = 'gc-sys-block--lo'; // 하위(초록) - else if (idx <= 2) tone = 'gc-sys-block--hi'; // 상위(빨강) + // i=0 → 화면 상단(100%), i=BLOCKS-1 → 화면 하단(0%) + const idxFromBottom = BLOCKS - 1 - i; + const on = idxFromBottom < filled; + const tone = blockTone(idxFromBottom); return ( - {/* 신호등 */} -
+ {/* 신호등 (바와 같은 높이) */} +
+ {/* 하단 수치 */}
{clamped.toFixed(0)}% {usedLabel} / {totalLabel} diff --git a/frontend/src/styles/dashboardCommand.css b/frontend/src/styles/dashboardCommand.css index c1ed7f4..d2262ad 100644 --- a/frontend/src/styles/dashboardCommand.css +++ b/frontend/src/styles/dashboardCommand.css @@ -340,62 +340,94 @@ display: flex; flex-direction: column; align-items: center; - gap: 6px; - padding: 10px 8px; + gap: 8px; + padding: 12px 10px 10px; border-radius: 10px; border: 1px solid var(--se-border); - background: color-mix(in srgb, var(--se-bg) 60%, transparent); + background: color-mix(in srgb, var(--se-bg) 55%, transparent); min-width: 0; } .gc-sys-card-title { - font-size: 0.65rem; + font-size: 0.67rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--se-text-muted); } +/* 바 영역 + 신호등 — 세로 높이 동일 */ .gc-sys-card-body { display: flex; flex-direction: row; - align-items: center; - gap: 8px; + align-items: stretch; /* 같은 높이 */ + gap: 6px; +} + +/* 눈금 레이블 열 */ +.gc-sys-ticks { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; + padding: 2px 0; +} + +.gc-sys-tick { + font-size: 0.55rem; + color: var(--se-text-dim, #666); + line-height: 1; + white-space: nowrap; } /* 세로 블록 바 */ .gc-sys-bar-wrap { display: flex; flex-direction: column; + justify-content: space-between; gap: 3px; + padding: 2px 0; } .gc-sys-block { - width: 18px; - height: 8px; - border-radius: 2px; - background: color-mix(in srgb, var(--se-text-dim, #666) 18%, #111); - opacity: 0.28; + width: 28px; + flex: 1; + border-radius: 3px; + background: color-mix(in srgb, var(--se-text-dim, #555) 15%, #0d0d0d); + opacity: 0.3; } .gc-sys-block--on { opacity: 1; } -/* 하위 블록 (낮은 사용률 = 초록) */ +/* 낮은 사용률 (하단 = 0~50%) → 초록 */ .gc-sys-block--lo.gc-sys-block--on { background: #34d399; - box-shadow: 0 0 4px rgba(52,211,153,0.6); + box-shadow: 0 0 5px rgba(52, 211, 153, 0.65); } -/* 중간 블록 (중간 사용률 = 노랑) */ +/* 중간 사용률 (50~80%) → 노랑 */ .gc-sys-block--mid.gc-sys-block--on { background: #fbbf24; - box-shadow: 0 0 4px rgba(251,191,36,0.6); + box-shadow: 0 0 5px rgba(251, 191, 36, 0.65); } -/* 상위 블록 (높은 사용률 = 빨강) */ +/* 높은 사용률 (80~100%) → 빨강 */ .gc-sys-block--hi.gc-sys-block--on { background: #f87171; - box-shadow: 0 0 4px rgba(248,113,113,0.6); + box-shadow: 0 0 5px rgba(248, 113, 113, 0.65); +} + +/* 신호등 — 바와 같은 높이에 맞춤 */ +.gc-traffic-light--sized { + width: 44px; + margin: 0; + height: 100%; + justify-content: space-evenly; +} + +.gc-traffic-light--sized .gc-traffic-bulb { + width: 26px; + height: 26px; } .gc-sys-card-foot { @@ -406,7 +438,7 @@ } .gc-sys-card-pct { - font-size: 0.95rem; + font-size: 1rem; font-weight: 800; color: var(--se-text); line-height: 1;