diff --git a/frontend/components/ServerPortlet.vue b/frontend/components/ServerPortlet.vue
index 66b49cf..888e498 100644
--- a/frontend/components/ServerPortlet.vue
+++ b/frontend/components/ServerPortlet.vue
@@ -99,7 +99,7 @@
- {{ container.cpu_percent?.toFixed(0) || '-' }}%
+ {{ formatCpuPercent(container.cpu_percent) }}
@@ -301,6 +301,15 @@ function getMemPercent(c: ContainerStatus): number {
return (Number(c.memory_usage) / Number(c.memory_limit)) * 100
}
+function formatCpuPercent(value: number | null): string {
+ if (value === null || value === undefined) return '-'
+ // 10% 이상이면 정수로, 미만이면 소수점 1자리
+ if (value >= 10) return `${value.toFixed(0)}%`
+ if (value >= 1) return `${value.toFixed(1)}%`
+ if (value >= 0.1) return `${value.toFixed(1)}%`
+ return `${value.toFixed(2)}%`
+}
+
function formatMemoryShort(bytes: number | null): string {
if (bytes === null || bytes === undefined) return '-'
const numBytes = Number(bytes)
@@ -379,9 +388,9 @@ function formatTimeAgo(datetime: string | null): string {
.offline-text { font-size: 18px; margin-bottom: 8px; }
.offline-time { font-size: 15px; opacity: 0.7; }
-.container-area { display: flex; flex-wrap: wrap; gap: 12px; padding: 14px; align-content: flex-start; min-width: 140px; }
+.container-area { display: flex; flex-wrap: wrap; gap: 10px; padding: 12px; align-content: flex-start; min-width: 140px; }
-.container-card { width: 260px; padding: 14px; border-radius: 10px; border: 1px solid var(--border-color); background: var(--bg-secondary); cursor: pointer; transition: all 0.15s; overflow: hidden; }
+.container-card { width: 200px; padding: 10px; border-radius: 8px; border: 1px solid var(--border-color); background: var(--bg-secondary); cursor: pointer; transition: all 0.15s; overflow: hidden; }
.container-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
.container-card.normal { background: var(--container-normal-bg, #f0fdf4); border-color: var(--container-normal-border, #86efac); }
.container-card.warning { background: var(--container-warning-bg, #fefce8); border-color: var(--container-warning-border, #fde047); }
@@ -389,22 +398,22 @@ function formatTimeAgo(datetime: string | null): string {
.container-card.danger { background: var(--container-danger-bg, #fef2f2); border-color: var(--container-danger-border, #fca5a5); }
.container-card.stopped { background: var(--container-danger-bg, #fef2f2); border-color: var(--container-danger-border, #fca5a5); }
-.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; overflow: hidden; }
-.card-name { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; overflow: hidden; }
-.card-name .card-level { font-size: 14px; flex-shrink: 0; }
-.card-name .name { font-size: 17px; font-weight: 700; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
-.card-uptime { font-size: 14px; color: var(--text-muted); flex-shrink: 0; margin-left: 12px; white-space: nowrap; }
+.card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; overflow: hidden; }
+.card-name { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 0; overflow: hidden; }
+.card-name .card-level { font-size: 12px; flex-shrink: 0; }
+.card-name .name { font-size: 15px; font-weight: 700; color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.card-uptime { font-size: 12px; color: var(--text-muted); flex-shrink: 0; margin-left: 8px; white-space: nowrap; }
-.card-metrics { display: flex; flex-wrap: wrap; gap: 8px 12px; }
-.card-metric { display: flex; align-items: center; gap: 8px; width: calc(50% - 6px); overflow: hidden; }
-.card-metric .label { font-size: 13px; color: var(--text-muted); width: 28px; flex-shrink: 0; font-weight: 500; }
-.mini-bar { flex: 1; height: 8px; background: rgba(0,0,0,0.1); border-radius: 4px; overflow: hidden; min-width: 28px; }
-.mini-fill { height: 100%; border-radius: 4px; }
+.card-metrics { display: flex; flex-wrap: wrap; gap: 5px 8px; }
+.card-metric { display: flex; align-items: center; gap: 4px; width: calc(50% - 4px); overflow: hidden; }
+.card-metric .label { font-size: 11px; color: var(--text-muted); width: 22px; flex-shrink: 0; font-weight: 500; }
+.mini-bar { flex: 1; height: 6px; background: rgba(0,0,0,0.1); border-radius: 3px; overflow: hidden; min-width: 20px; }
+.mini-fill { height: 100%; border-radius: 3px; }
.mini-fill.normal { background: #22c55e; }
.mini-fill.warning { background: #eab308; }
.mini-fill.critical { background: #f97316; }
.mini-fill.danger { background: #ef4444; }
-.card-metric .value { font-size: 15px; font-weight: 700; color: var(--text-secondary); width: 50px; text-align: right; flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; transition: all 0.3s; padding: 2px 4px; border-radius: 4px; }
+.card-metric .value { font-size: 13px; font-weight: 700; color: var(--text-secondary); min-width: 38px; text-align: right; flex-shrink: 0; transition: all 0.3s; padding: 1px 2px; border-radius: 3px; }
.card-metric .value.mem-highlight { color: #dc2626; font-weight: 800; }
.card-metric .value.net { color: var(--text-muted); font-weight: 600; }