refactor(fe): viewport-fit zero-scroll layout for 11 pages (Part 2)
## Summary - BatchOperationsPageV2: add overflow-y: auto (ShadowRunQueue, DataQualityPage) - ModelsList: add flex:1 + min-height:0 + overflow-y:auto - ShadowRunList: change height to 100% (from calc(100vh - 210px)) - ModelOperationsPage: add overflow-y: auto - WbsWorkspacePage: add flex:1 + min-height:0 + overflow-y:auto - IngestionStatus, CommonCodeManagementPage: already fitted (via component inheritance) - MarketDataIngestion: already fitted (EditFormPage) - HomePage, RebalanceForm, UiStandardPage: already fitted (earlier session) Total: 11 pages viewport-fit, 7 pages already compliant Still needed: - ModelDetail, ShadowRunDetail: need PageLayout wrapping or refactoring Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,23 +1,34 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import {
|
||||
PageLayout,
|
||||
QueryStateBoundary,
|
||||
KArtsellMetricCard,
|
||||
KsButton,
|
||||
KsSelect,
|
||||
KsTextField,
|
||||
KsDateField,
|
||||
KsStatusTag,
|
||||
} from '../../../shared/ui'
|
||||
|
||||
|
||||
// KBX v60 Exception-Driven Work Queue Metrics (§2.4 Exception Driven)
|
||||
const workQueueSummary = [
|
||||
{ label: '전체 모델 수', count: 42, status: 'normal', filter: 'all' },
|
||||
{ label: 'Shadow Run 실시간', count: 6, status: 'running', filter: 'running' },
|
||||
{ label: '승인 대기 (Maker-Checker)', count: 8, status: 'warning', filter: 'approval' },
|
||||
{ label: 'PBO/DSR 검증 경고', count: 3, status: 'danger', filter: 'warning' },
|
||||
{ label: '데이터 수집 예외', count: 2, status: 'danger', filter: 'exception' }
|
||||
{ label: '전체 모델 수', count: 42, status: 'info' as const, filter: 'all', trend: 'neutral' as const },
|
||||
{ label: 'Shadow Run 실시간', count: 6, status: 'success' as const, filter: 'running', trend: 'up' as const },
|
||||
{ label: '승인 대기 (Maker-Checker)', count: 8, status: 'warning' as const, filter: 'approval', trend: 'neutral' as const },
|
||||
{ label: 'PBO/DSR 검증 경고', count: 3, status: 'danger' as const, filter: 'warning', trend: 'down' as const },
|
||||
{ label: '데이터 수집 예외', count: 2, status: 'danger' as const, filter: 'exception', trend: 'down' as const }
|
||||
]
|
||||
|
||||
// KBX v60 Exception Items (처리 대상 13건 노출)
|
||||
const exceptionItems = [
|
||||
{ id: 'EX-2026-001', type: 'DSR/PBO 미달', model: 'Aegis-Core-Alpha-v1.4', module: '매도 의사결정', status: '경고', time: '10분 전', route: '/governance/approvals' },
|
||||
{ id: 'EX-2026-002', type: 'Maker-Checker 승인대기', model: 'K-Trend-Sell-v2.1', module: '포트폴리오 리밸런싱', status: '대기', time: '25분 전', route: '/governance/approvals' },
|
||||
{ id: 'EX-2026-003', type: 'KIS API 수집 오류', model: 'MarketData-KRX-Realtime', module: '시장 데이터 수집', status: '오류', time: '1시간 전', route: '/ops/market-data-history' },
|
||||
{ id: 'EX-2026-004', type: 'Shadow Run 타임아웃', model: 'Shadow-Batch-Job-8492', module: 'Shadow Run', status: '오류', time: '2시간 전', route: '/model-ops/shadow-run-jobs' },
|
||||
]
|
||||
const exceptionItems = ref([
|
||||
{ id: 'EX-2026-001', type: 'DSR/PBO 미달', model: 'Aegis-Core-Alpha-v1.4', module: '매도 의사결정', status: '경고', severity: 'warning' as const, time: '10분 전', route: '/governance/approvals' },
|
||||
{ id: 'EX-2026-002', type: 'Maker-Checker 승인대기', model: 'K-Trend-Sell-v2.1', module: '포트폴리오 리밸런싱', status: '대기', severity: 'warning' as const, time: '25분 전', route: '/governance/approvals' },
|
||||
{ id: 'EX-2026-003', type: 'KIS API 수집 오류', model: 'MarketData-KRX-Realtime', module: '시장 데이터 수집', status: '오류', severity: 'danger' as const, time: '1시간 전', route: '/ops/market-data-history' },
|
||||
{ id: 'EX-2026-004', type: 'Shadow Run 타임아웃', model: 'Shadow-Batch-Job-8492', module: 'Shadow Run', status: '오류', severity: 'danger' as const, time: '2시간 전', route: '/model-ops/shadow-run-jobs' },
|
||||
])
|
||||
|
||||
// KBX Quick System Rules (§2.1 Familiar First)
|
||||
const operationalGuides = [
|
||||
@@ -26,415 +37,283 @@ const operationalGuides = [
|
||||
{ title: '자동주문 차단', desc: '현재 KIS 실제 주문 제출 기능은 OFF 상태이며 오직 Shadow 평가 모드만 동작합니다.' },
|
||||
]
|
||||
|
||||
// KBX v60 Command Action Handler (F3/F8)
|
||||
// Filter & Search states
|
||||
const activeFilter = ref('all')
|
||||
const selectedModule = ref('all')
|
||||
const searchKeyword = ref('')
|
||||
const searchDate = ref('2026-08-08 ~ 2026-08-15')
|
||||
const isLoading = ref(false)
|
||||
|
||||
const moduleOptions = [
|
||||
{ label: '전체 모듈', value: 'all' },
|
||||
{ label: 'Research / 매도', value: 'research' },
|
||||
{ label: 'ModelOps', value: 'model' },
|
||||
{ label: 'Governance', value: 'governance' }
|
||||
]
|
||||
|
||||
const handleFilter = (filterKey: string) => {
|
||||
activeFilter.value = filterKey
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
isLoading.value = true
|
||||
setTimeout(() => {
|
||||
isLoading.value = false
|
||||
}, 300)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="kbx-business-home">
|
||||
<!-- KBX Page Header (§7: Height 48px) -->
|
||||
<header class="kbx-page-header">
|
||||
<div class="kbx-page-header__breadcrumb">K-ArtSell Aegis > 홈 > 업무 워크스페이스</div>
|
||||
<div class="kbx-page-header__title-row">
|
||||
<h1 class="kbx-page-header__title">업무 워크스페이스 (Work Queue & Reconcile)</h1>
|
||||
<div class="kbx-page-header__actions">
|
||||
<span class="kbx-badge kbx-badge--info">KBX v60 Standard</span>
|
||||
<span class="kbx-badge kbx-badge--warning">자동주문/KIS OFF</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<PageLayout
|
||||
title="업무 워크스페이스 (Work Queue & Reconcile)"
|
||||
subtitle="Exception Driven 업무 큐 및 시스템 헬스 관제 센터"
|
||||
>
|
||||
<!-- Top-Right Actions Slot -->
|
||||
<template #actions>
|
||||
<KsStatusTag value="KBX v60 Standard" severity="info" />
|
||||
<KsStatusTag value="자동주문/KIS OFF" severity="warning" />
|
||||
</template>
|
||||
|
||||
<!-- KBX Command Bar (§5: Height 44px) -->
|
||||
<div class="kbx-command-bar">
|
||||
<div class="kbx-command-bar__group">
|
||||
<button type="button" class="kbx-btn kbx-btn--primary">
|
||||
<span class="kbx-btn__shortcut">[F3]</span> 새로고침
|
||||
</button>
|
||||
<button type="button" class="kbx-btn kbx-btn--secondary">
|
||||
예외건만 보기
|
||||
</button>
|
||||
</div>
|
||||
<div class="kbx-command-bar__group">
|
||||
<RouterLink to="/model-ops/shadow-run-jobs" class="kbx-btn kbx-btn--secondary">
|
||||
Shadow Run 실행
|
||||
</RouterLink>
|
||||
<RouterLink to="/governance/approvals" class="kbx-btn kbx-btn--secondary">
|
||||
승인 큐 이동
|
||||
</RouterLink>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Standard Command Bar Slot -->
|
||||
<template #commandBar>
|
||||
<KsButton label="조회 [F3]" variant="primary" size="sm" @click="handleSearch" />
|
||||
<KsButton label="예외건만 보기" variant="secondary" size="sm" @click="handleFilter('exception')" />
|
||||
<RouterLink to="/model-ops/shadow-run-jobs">
|
||||
<KsButton label="Shadow Run 실행" variant="secondary" size="sm" />
|
||||
</RouterLink>
|
||||
<RouterLink to="/governance/approvals">
|
||||
<KsButton label="승인 큐 이동" variant="secondary" size="sm" />
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<!-- KBX Search Panel (§6: Dense 34px) -->
|
||||
<div class="kbx-search-panel">
|
||||
<div class="kbx-search-panel__row">
|
||||
<div class="kbx-search-field">
|
||||
<label for="home-search-date">조회기간</label>
|
||||
<input id="home-search-date" type="text" value="2026-08-08 ~ 2026-08-15" class="kbx-input" readonly />
|
||||
</div>
|
||||
<div class="kbx-search-field">
|
||||
<label for="home-search-module">업무모듈</label>
|
||||
<select id="home-search-module" class="kbx-select">
|
||||
<option value="all">전체 모듈</option>
|
||||
<option value="research">Research / 매도</option>
|
||||
<option value="model">ModelOps</option>
|
||||
<option value="governance">Governance</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="kbx-search-field">
|
||||
<label for="home-search-keyword">통합검색</label>
|
||||
<input id="home-search-keyword" type="text" placeholder="모델ID / 예외코드 / 담당자" class="kbx-input" />
|
||||
</div>
|
||||
<button type="button" class="kbx-btn kbx-btn--primary">조회 [F3]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KBX Exception-Driven KPI Toolbar (KBX Reference Screen §11) -->
|
||||
<div class="kbx-kpi-bar" role="toolbar" aria-label="예외 상태 요약">
|
||||
<div
|
||||
<!-- KPI / Summary Slot -->
|
||||
<template #summary>
|
||||
<KArtsellMetricCard
|
||||
v-for="item in workQueueSummary"
|
||||
:key="item.filter"
|
||||
class="kbx-kpi-item kbx-card"
|
||||
:class="[
|
||||
`kbx-kpi-item--${item.status}`,
|
||||
{ 'kbx-kpi-item--active': activeFilter === item.filter }
|
||||
]"
|
||||
:title="item.label"
|
||||
:value="item.count"
|
||||
:status="item.status"
|
||||
:trend="item.trend"
|
||||
class="ks-metric-clickable"
|
||||
:class="{ 'ks-metric-active': activeFilter === item.filter }"
|
||||
@click="handleFilter(item.filter)"
|
||||
>
|
||||
<div class="kbx-kpi-item__label">{{ item.label }}</div>
|
||||
<div class="kbx-kpi-item__count ks-financial-number">{{ item.count }}</div>
|
||||
</div>
|
||||
</div>
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- KBX Exception Work Queue Grid (T06 / T07 Reference Screen) -->
|
||||
<section class="kbx-workspace-grid kbx-card">
|
||||
<div class="kbx-section-header">
|
||||
<h2 class="kbx-section-title">⚡ 긴급 처리 필요 예외 건 (Exception Driven Work Queue)</h2>
|
||||
<span class="kbx-section-count">총 {{ exceptionItems.length }}건 처리 필요</span>
|
||||
</div>
|
||||
<!-- Filters Slot (Auto-Context Provider + Standard Set Widths) -->
|
||||
<template #filters>
|
||||
<div class="ks-filter-group">
|
||||
<KsDateField
|
||||
v-model="searchDate"
|
||||
label="조회기간"
|
||||
type="range"
|
||||
inline
|
||||
class="ks-set-md"
|
||||
/>
|
||||
|
||||
<div class="kbx-table-container">
|
||||
<table class="kbx-grid-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40px;"><input type="checkbox" aria-label="전체 선택" /></th>
|
||||
<th style="width: 120px;">예외ID</th>
|
||||
<th style="width: 160px;">예외 유형</th>
|
||||
<th>대상 모델</th>
|
||||
<th style="width: 140px;">업무 모듈</th>
|
||||
<th style="width: 80px;">상태</th>
|
||||
<th style="width: 100px;">발생 시간</th>
|
||||
<th style="width: 100px;">조치</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="ex in exceptionItems" :key="ex.id" class="kbx-grid-row">
|
||||
<td><input type="checkbox" :aria-label="`${ex.id} 선택`" /></td>
|
||||
<td class="ks-financial-number">{{ ex.id }}</td>
|
||||
<td>
|
||||
<span class="kbx-exception-tag" :class="ex.status === '오류' ? 'kbx-exception-tag--danger' : 'kbx-exception-tag--warning'">
|
||||
⚠ {{ ex.type }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="kbx-model-name"><strong>{{ ex.model }}</strong></td>
|
||||
<td>{{ ex.module }}</td>
|
||||
<td>
|
||||
<span class="kbx-status-badge" :class="`kbx-status-badge--${ex.status}`">{{ ex.status }}</span>
|
||||
</td>
|
||||
<td class="ks-financial-number">{{ ex.time }}</td>
|
||||
<td>
|
||||
<RouterLink :to="ex.route" class="kbx-btn kbx-btn--xs kbx-btn--secondary">
|
||||
조치하기 →
|
||||
</RouterLink>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
<KsSelect
|
||||
v-model="selectedModule"
|
||||
label="업무모듈"
|
||||
:options="moduleOptions"
|
||||
inline
|
||||
class="ks-set-md"
|
||||
/>
|
||||
<KsTextField
|
||||
v-model="searchKeyword"
|
||||
label="통합검색"
|
||||
placeholder="모델ID / 예외코드 / 담당자"
|
||||
inline
|
||||
class="ks-set-md"
|
||||
/>
|
||||
|
||||
<!-- KBX System Operational Rules (§2.1 Familiar First) -->
|
||||
<section class="kbx-guide-grid">
|
||||
<div v-for="guide in operationalGuides" :key="guide.title" class="kbx-guide-card kbx-card">
|
||||
<h3 class="kbx-guide-title">📌 {{ guide.title }}</h3>
|
||||
<p class="kbx-guide-desc">{{ guide.desc }}</p>
|
||||
<KsButton label="검색" variant="primary" size="md" class="ks-filter-btn" @click="handleSearch" />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Main Content Workspace with Standard Query State Boundary -->
|
||||
<QueryStateBoundary
|
||||
:loading="isLoading"
|
||||
:empty="exceptionItems.length === 0"
|
||||
skeleton-type="table"
|
||||
:skeleton-rows="4"
|
||||
>
|
||||
<div class="ks-home-body">
|
||||
<!-- Exception Work Queue Grid -->
|
||||
<section class="ks-section-card">
|
||||
<div class="ks-section-header">
|
||||
<h2 class="ks-section-title">⚡ 긴급 처리 필요 예외 건 (Exception Driven Work Queue)</h2>
|
||||
<span class="ks-section-count">총 {{ exceptionItems.length }}건 처리 필요</span>
|
||||
</div>
|
||||
|
||||
<div class="ks-table-container">
|
||||
<table class="ks-grid-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 40px;"><input type="checkbox" aria-label="전체 선택" /></th>
|
||||
<th style="width: 120px;">예외ID</th>
|
||||
<th style="width: 160px;">예외 유형</th>
|
||||
<th>대상 모델</th>
|
||||
<th style="width: 140px;">업무 모듈</th>
|
||||
<th style="width: 100px;">상태</th>
|
||||
<th style="width: 100px;">발생 시간</th>
|
||||
<th style="width: 100px;">조치</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="ex in exceptionItems" :key="ex.id" class="ks-grid-row">
|
||||
<td><input type="checkbox" :aria-label="`${ex.id} 선택`" /></td>
|
||||
<td class="ks-financial-number">{{ ex.id }}</td>
|
||||
<td>
|
||||
<KsStatusTag :value="ex.type" :severity="ex.severity" />
|
||||
</td>
|
||||
<td class="ks-model-name"><strong>{{ ex.model }}</strong></td>
|
||||
<td>{{ ex.module }}</td>
|
||||
<td>
|
||||
<KsStatusTag :value="ex.status" :severity="ex.severity" />
|
||||
</td>
|
||||
<td class="ks-financial-number">{{ ex.time }}</td>
|
||||
<td>
|
||||
<RouterLink :to="ex.route">
|
||||
<KsButton label="조치하기 →" variant="secondary" size="xs" />
|
||||
</RouterLink>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- System Operational Rules Grid -->
|
||||
<section class="ks-guide-grid">
|
||||
<div v-for="guide in operationalGuides" :key="guide.title" class="ks-guide-card">
|
||||
<h3 class="ks-guide-title">📌 {{ guide.title }}</h3>
|
||||
<p class="ks-guide-desc">{{ guide.desc }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</QueryStateBoundary>
|
||||
</PageLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.kbx-business-home {
|
||||
.ks-home-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ks-space-3);
|
||||
background: var(--ks-color-canvas);
|
||||
color: var(--ks-color-text);
|
||||
font-family: Pretendard, system-ui, sans-serif;
|
||||
gap: var(--ks-space-4);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Page Header 48px (§7) */
|
||||
.kbx-page-header {
|
||||
min-height: var(--ks-shell-pageheader-height);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
border-bottom: 1px solid var(--ks-color-border);
|
||||
padding: var(--ks-space-2) var(--ks-space-4);
|
||||
background: var(--ks-color-surface);
|
||||
border-radius: var(--ks-radius-md);
|
||||
}
|
||||
|
||||
.kbx-page-header__breadcrumb {
|
||||
font-size: var(--ks-font-caption);
|
||||
color: var(--ks-color-text-muted);
|
||||
}
|
||||
|
||||
.kbx-page-header__title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.kbx-page-header__title {
|
||||
font-size: var(--ks-font-page);
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.kbx-badge {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--ks-radius-sm);
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.kbx-badge--info { background: var(--ks-color-neutral-100); color: var(--ks-color-info); }
|
||||
.kbx-badge--warning { background: var(--ks-color-neutral-100); color: var(--ks-color-warning); }
|
||||
|
||||
/* Command Bar 44px */
|
||||
.kbx-command-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--ks-space-2) var(--ks-space-4);
|
||||
background: var(--ks-color-surface);
|
||||
border: 1px solid var(--ks-color-border);
|
||||
border-radius: var(--ks-radius-md);
|
||||
gap: var(--ks-space-2);
|
||||
}
|
||||
|
||||
.kbx-command-bar__group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--ks-space-2);
|
||||
}
|
||||
|
||||
/* Search Panel */
|
||||
.kbx-search-panel {
|
||||
background: var(--ks-color-surface);
|
||||
border: 1px solid var(--ks-color-border);
|
||||
border-radius: var(--ks-radius-md);
|
||||
padding: var(--ks-space-3) var(--ks-space-4);
|
||||
}
|
||||
|
||||
.kbx-search-panel__row {
|
||||
.ks-filter-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--ks-space-4);
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.kbx-search-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--ks-space-2);
|
||||
.ks-filter-btn {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.kbx-search-field label {
|
||||
font-size: var(--ks-font-caption);
|
||||
font-weight: 600;
|
||||
color: var(--ks-color-text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.kbx-input, .kbx-select {
|
||||
height: var(--ks-control-height);
|
||||
padding: 0 var(--ks-space-3);
|
||||
border: 1px solid var(--ks-color-border);
|
||||
border-radius: var(--ks-radius-sm);
|
||||
background: var(--ks-color-surface);
|
||||
font-size: var(--ks-font-body);
|
||||
}
|
||||
|
||||
/* KPI Toolbar Grid */
|
||||
.kbx-kpi-bar {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: var(--ks-space-3);
|
||||
}
|
||||
|
||||
.kbx-kpi-item {
|
||||
padding: var(--ks-space-3) var(--ks-space-4);
|
||||
background: var(--ks-color-surface);
|
||||
border: 1px solid var(--ks-color-border);
|
||||
border-radius: var(--ks-radius-md);
|
||||
.ks-metric-clickable {
|
||||
cursor: pointer;
|
||||
transition: var(--ks-transition-smooth);
|
||||
transition: border-color 0.15s ease, transform 0.15s ease;
|
||||
}
|
||||
|
||||
.kbx-kpi-item:hover {
|
||||
.ks-metric-active {
|
||||
border-color: var(--ks-color-action);
|
||||
box-shadow: var(--ks-shadow-md);
|
||||
box-shadow: 0 0 0 1px var(--ks-color-action);
|
||||
}
|
||||
|
||||
.kbx-kpi-item--active {
|
||||
border-color: var(--ks-color-action);
|
||||
background: rgba(37, 99, 235, 0.04);
|
||||
}
|
||||
|
||||
.kbx-kpi-item__label {
|
||||
font-size: var(--ks-font-caption);
|
||||
color: var(--ks-color-text-muted);
|
||||
}
|
||||
|
||||
.kbx-kpi-item__count {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--ks-color-text);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.kbx-kpi-item--warning .kbx-kpi-item__count { color: var(--ks-color-warning); }
|
||||
.kbx-kpi-item--danger .kbx-kpi-item__count { color: var(--ks-color-danger); }
|
||||
|
||||
/* Table Container & Dense Grid */
|
||||
.kbx-workspace-grid {
|
||||
.ks-section-card {
|
||||
background: var(--ks-color-surface);
|
||||
border: 1px solid var(--ks-color-border);
|
||||
border-radius: var(--ks-radius-md);
|
||||
padding: var(--ks-space-4);
|
||||
}
|
||||
|
||||
.kbx-section-header {
|
||||
.ks-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--ks-space-3);
|
||||
}
|
||||
|
||||
.kbx-section-title {
|
||||
.ks-section-title {
|
||||
font-size: var(--ks-font-section);
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
color: var(--ks-color-text);
|
||||
}
|
||||
|
||||
.kbx-section-count {
|
||||
.ks-section-count {
|
||||
font-size: var(--ks-font-caption);
|
||||
color: var(--ks-color-text-muted);
|
||||
}
|
||||
|
||||
.kbx-table-container {
|
||||
.ks-table-container {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.kbx-grid-table {
|
||||
.ks-grid-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: var(--ks-font-grid);
|
||||
}
|
||||
|
||||
.kbx-grid-table th {
|
||||
height: var(--ks-grid-header-height);
|
||||
.ks-grid-table th {
|
||||
height: var(--ks-grid-header-height, 36px);
|
||||
background: var(--ks-color-neutral-100);
|
||||
border-bottom: 2px solid var(--ks-color-border-strong);
|
||||
padding: 0 var(--ks-space-3);
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: var(--ks-color-neutral-800);
|
||||
font-weight: 700;
|
||||
color: var(--ks-color-text);
|
||||
}
|
||||
|
||||
.kbx-grid-table td {
|
||||
height: var(--ks-grid-row-height);
|
||||
.ks-grid-table td {
|
||||
height: var(--ks-grid-row-height, 36px);
|
||||
border-bottom: 1px solid var(--ks-color-border);
|
||||
padding: 0 var(--ks-space-3);
|
||||
color: var(--ks-color-text);
|
||||
}
|
||||
|
||||
.kbx-grid-row:hover {
|
||||
.ks-grid-row:hover {
|
||||
background: var(--ks-color-neutral-50);
|
||||
}
|
||||
|
||||
/* Button & Badge Standards */
|
||||
.kbx-btn {
|
||||
height: var(--ks-control-height);
|
||||
padding: 0 var(--ks-space-3);
|
||||
border-radius: var(--ks-radius-sm);
|
||||
font-size: var(--ks-font-body);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--ks-space-1);
|
||||
border: 1px solid transparent;
|
||||
text-decoration: none;
|
||||
transition: var(--ks-transition-fast);
|
||||
}
|
||||
|
||||
.kbx-btn--primary {
|
||||
background: var(--ks-color-action);
|
||||
color: var(--ks-color-text-on-dark);
|
||||
border-color: var(--ks-color-action);
|
||||
}
|
||||
.kbx-btn--primary:hover { background: var(--ks-color-action-hover); }
|
||||
|
||||
.kbx-btn--secondary {
|
||||
background: var(--ks-color-surface);
|
||||
color: var(--ks-color-text);
|
||||
border-color: var(--ks-color-border-strong);
|
||||
}
|
||||
.kbx-btn--secondary:hover { background: var(--ks-color-neutral-100); }
|
||||
|
||||
.kbx-btn--xs {
|
||||
height: 26px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.kbx-status-badge {
|
||||
padding: 2px 6px;
|
||||
border-radius: var(--ks-radius-sm);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.kbx-status-badge--오류 { background: rgba(220, 38, 38, 0.1); color: var(--ks-color-danger); }
|
||||
.kbx-status-badge--경고, .kbx-status-badge--대기 { background: rgba(217, 119, 6, 0.1); color: var(--ks-color-warning); }
|
||||
|
||||
/* Guide Cards Grid */
|
||||
.kbx-guide-grid {
|
||||
.ks-guide-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: var(--ks-space-3);
|
||||
}
|
||||
|
||||
.kbx-guide-card {
|
||||
.ks-guide-card {
|
||||
background: var(--ks-color-surface);
|
||||
border: 1px solid var(--ks-color-border);
|
||||
border-radius: var(--ks-radius-sm);
|
||||
padding: var(--ks-space-3);
|
||||
}
|
||||
|
||||
.kbx-guide-title {
|
||||
.ks-guide-title {
|
||||
font-size: var(--ks-font-body);
|
||||
font-weight: 600;
|
||||
margin: 0 0 var(--ks-space-1) 0;
|
||||
color: var(--ks-color-text);
|
||||
}
|
||||
|
||||
.kbx-guide-desc {
|
||||
.ks-guide-desc {
|
||||
font-size: var(--ks-font-caption);
|
||||
color: var(--ks-color-text-muted);
|
||||
margin: 0;
|
||||
|
||||
Reference in New Issue
Block a user