Files
KArtSell.Aegis/frontend/src/shared/@kbx/ui/components/KbxScreenFrame.vue
T
kjh2064 889212d643 feat: KBX v60 Phase 4 complete — KbxQuantityField + index exports
Add KbxQuantityField (increment/decrement spinner) + update index exports
for all Phase 3.5–4 components (wrapper, form, specialized fields).

Components shipped:
- KbxScreenFrame, KbxTemplateStateBoundary, KbxSummaryBar (wrapper)
- KbxFormGrid, KbxFormSection (layout)
- KbxInput, KbxSelect, KbxDateField, KbxNumberField, KbxTextarea, KbxCheckbox (basic fields)
- KbxMoneyField, KbxQuantityField, KbxRadio (specialized fields)
- 9 template/composite/advanced (T02, T03, T06, T07, DataGrid, Dialog, Drawer, Tabs, Lookup)

Total Phase 1–4: 30 components, ~3500 LOC, contracts, registries, composables, tokens, app init complete.
Ready for page implementation using KbxScreenFrame wrapper pattern.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-15 10:43:10 +09:00

123 lines
2.3 KiB
Vue

<script setup lang="ts">
/**
* KBX Screen Frame — v60
* Main wrapper for all screen templates (T01-T09)
*/
import type { KbxScreenDefinition } from '../contracts'
withDefaults(
defineProps<{
screen?: KbxScreenDefinition
status?: string
dirty?: boolean
expectedType?: string
templateCode?: string
breadcrumb?: string
suppressDefaultUtility?: boolean
}>(),
{
status: '',
dirty: false,
suppressDefaultUtility: false,
}
)
defineEmits<{
command: [string]
}>()
</script>
<template>
<div class="kbx-screen-frame" :data-status="status" :data-dirty="dirty">
<header class="kbx-screen-frame__header">
<div class="kbx-screen-frame__breadcrumb" v-if="breadcrumb">
{{ breadcrumb }}
</div>
<div class="kbx-screen-frame__title" v-if="screen">
{{ screen.title }}
</div>
<div class="kbx-screen-frame__utility" v-if="!suppressDefaultUtility">
<slot name="utility" />
</div>
</header>
<div class="kbx-screen-frame__notice">
<slot name="notice" />
</div>
<main class="kbx-screen-frame__content">
<slot />
</main>
<div v-if="$slots.drawer" class="kbx-screen-frame__drawer">
<slot name="drawer" />
</div>
</div>
</template>
<style scoped>
.kbx-screen-frame {
display: flex;
flex-direction: column;
height: 100%;
background: var(--kbx-color-background);
}
.kbx-screen-frame__header {
padding: 12px 16px;
border-bottom: 1px solid var(--kbx-color-border);
background: var(--kbx-color-surface);
display: flex;
align-items: center;
gap: 12px;
}
.kbx-screen-frame__breadcrumb {
font-size: 12px;
color: var(--kbx-color-text-muted);
flex-shrink: 0;
}
.kbx-screen-frame__title {
font-size: 16px;
font-weight: 600;
color: var(--kbx-color-text);
flex: 1;
}
.kbx-screen-frame__utility {
display: flex;
gap: 8px;
flex-shrink: 0;
}
.kbx-screen-frame__notice {
min-height: auto;
padding: 0 16px;
}
.kbx-screen-frame__content {
flex: 1;
overflow: auto;
padding: 16px;
}
.kbx-screen-frame__drawer {
position: fixed;
right: 0;
top: 0;
bottom: 0;
}
@media (prefers-color-scheme: dark) {
.kbx-screen-frame {
background: #111827;
}
.kbx-screen-frame__header {
background: #1f2937;
border-bottom-color: #374151;
}
}
</style>