wip: add form data pelaksanaan operasi

todo: blood input section

* ui: patch focus ring state
* layouts-pages: fix width layout calculation

feat(treatment-report): add fill-notes component and validation messages
- Add new FillNotes component for tissue notes input with dynamic fields
- Update schema validation with required error messages for operation and specimen fields
- Adjust form layout to include new FillNotes component and improve field organization

cherry-pick arrangement procedure from feat/protokol-terapi-116
This commit is contained in:
Khafid Prayoga
2025-11-26 10:18:29 +07:00
parent f5704536d1
commit 5ad286a44e
21 changed files with 1198 additions and 67 deletions
+48 -40
View File
@@ -2,76 +2,84 @@
import CardContent from '~/components/pub/ui/card/CardContent.vue'
const route = useRoute()
const contentFrame = computed(() => route.meta.contentFrame)
// Ambil meta dan set default
const contentFrame = computed(() => route.meta.contentFrame ?? 'cf-container-lg')
// Mapping aman supaya tidak ada class invalid
const contentFrameClass = computed(() => {
switch (contentFrame.value) {
case 'cf-container-2xl':
return 'cf-container-2xl'
case 'cf-container-xl':
return 'cf-container-xl'
case 'cf-container-lg':
return 'cf-container-lg'
case 'cf-container-md':
return 'cf-container-md'
case 'cf-container-sm':
return 'cf-container-sm'
case 'cf-full-width':
return 'cf-full-width'
default:
return 'cf-container-lg'
}
const allowed = [
'cf-container-2xl',
'cf-container-xl',
'cf-container-lg',
'cf-container-md',
'cf-container-sm',
'cf-full-width',
'cf-no-frame',
]
return allowed.includes(contentFrame.value as string) ? contentFrame.value : 'cf-container-lg'
})
</script>
<template>
<SidebarProvider>
<LayoutAppSidebar />
<SidebarInset>
<LayoutHeader />
<div :class="`w-full p-4 2xl:p-5 flex justify-center ${contentFrameClass}`">
<div v-if="contentFrame !== 'cf-no-frame'">
<Card>
<CardContent>
<slot />
</CardContent>
</Card>
</div>
<slot v-else />
<!-- Outer wrapper always full width -->
<div class="flex w-full justify-center p-4 2xl:p-5">
<!-- Frame mode (container + card) -->
<template v-if="contentFrameClass !== 'cf-no-frame'">
<div :class="['content-frame', contentFrameClass]">
<Card>
<CardContent>
<slot />
</CardContent>
</Card>
</div>
</template>
<!-- No frame direct slot -->
<template v-else>
<slot />
</template>
</div>
</SidebarInset>
</SidebarProvider>
</template>
<style scoped>
.cf-container > *,
.cf-container-lg > *,
.cf-container-md > *,
.cf-container-sm > *,
.cf-full-width {
/* Base: semua frame full width by default */
.content-frame {
width: 100%;
}
.cf-full-width > * {
width: 100%;
}
.cf-container-2xl > * {
/* Max-width container variants */
.cf-container-2xl {
max-width: 1400px;
}
.cf-container-xl > * {
.cf-container-xl {
max-width: 1200px;
}
.cf-container-lg > * {
.cf-container-lg {
max-width: 992px;
}
.cf-container-md > * {
.cf-container-md {
max-width: 768px;
}
.cf-container-sm > * {
.cf-container-sm {
max-width: 576px;
}
/* Full width (no max width) */
.cf-full-width {
width: 100%;
max-width: 100%;
}
</style>