mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-25 18:42:05 +07:00
continue ordertest
This commit is contained in:
parent
e236a20527
commit
d4becb0a12
16
package-lock.json
generated
16
package-lock.json
generated
@ -17,14 +17,14 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/compat": "^1.4.0",
|
"@eslint/compat": "^1.4.0",
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
"@internationalized/date": "^3.10.1",
|
"@internationalized/date": "^3.12.1",
|
||||||
"@lucide/svelte": "^0.561.0",
|
"@lucide/svelte": "^0.561.0",
|
||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"@sveltejs/kit": "^2.49.1",
|
"@sveltejs/kit": "^2.49.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||||
"@tanstack/table-core": "^8.21.3",
|
"@tanstack/table-core": "^8.21.3",
|
||||||
"@types/node": "^22",
|
"@types/node": "^22",
|
||||||
"bits-ui": "^2.15.4",
|
"bits-ui": "^2.18.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
@ -715,9 +715,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@internationalized/date": {
|
"node_modules/@internationalized/date": {
|
||||||
"version": "3.10.1",
|
"version": "3.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.1.tgz",
|
||||||
"integrity": "sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==",
|
"integrity": "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -1618,9 +1618,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/bits-ui": {
|
"node_modules/bits-ui": {
|
||||||
"version": "2.15.4",
|
"version": "2.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.15.4.tgz",
|
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.18.0.tgz",
|
||||||
"integrity": "sha512-7H9YUfp03KOk1LVDh8wPYSRPxlZgG/GRWLNSA8QC73/8Z8ytun+DWJhIuibyFyz7A0cP/RANVcB4iDrbY8q+Og==",
|
"integrity": "sha512-GLOBZRVy3hxNHIQ2MpD/+5aK9KcBFZRhUJtZ1UDABXdlVR4K6zFpgt4T+Rwuhf2sQzlc6yK1q/DprHPjwT4Pjw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@ -14,14 +14,14 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/compat": "^1.4.0",
|
"@eslint/compat": "^1.4.0",
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
"@internationalized/date": "^3.10.1",
|
"@internationalized/date": "^3.12.1",
|
||||||
"@lucide/svelte": "^0.561.0",
|
"@lucide/svelte": "^0.561.0",
|
||||||
"@sveltejs/adapter-auto": "^7.0.0",
|
"@sveltejs/adapter-auto": "^7.0.0",
|
||||||
"@sveltejs/kit": "^2.49.1",
|
"@sveltejs/kit": "^2.49.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||||
"@tanstack/table-core": "^8.21.3",
|
"@tanstack/table-core": "^8.21.3",
|
||||||
"@types/node": "^22",
|
"@types/node": "^22",
|
||||||
"bits-ui": "^2.15.4",
|
"bits-ui": "^2.18.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.39.1",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
|||||||
@ -143,10 +143,11 @@ export const orderTestFormFields = [
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
key: "Tests",
|
key: "Tests",
|
||||||
label: "Search Test",
|
|
||||||
required: true,
|
required: true,
|
||||||
type: "tests",
|
withLabel: false,
|
||||||
|
type: "tests2",
|
||||||
optionsEndpoint: `${API.BASE_URL}${API.TEST}`,
|
optionsEndpoint: `${API.BASE_URL}${API.TEST}`,
|
||||||
|
otherEndpoint: `${API.BASE_URL}${API.DISCIPLINE}`,
|
||||||
valueKey: 'TestSiteCode',
|
valueKey: 'TestSiteCode',
|
||||||
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`,
|
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`,
|
||||||
validateOn: ['input']
|
validateOn: ['input']
|
||||||
|
|||||||
@ -53,7 +53,7 @@ $inspect(formState.form)
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<FormPageContainer title="Create Order for {formState.form?.PatientID} - {formState.form?.PatientName}" {primaryAction} {secondaryActions} {actions}>
|
<FormPageContainer title="Create Order for {formState.form?.PatientID} - {formState.form?.PatientName}" {primaryAction} {secondaryActions} {actions}>
|
||||||
{#if orderStore.selectedPatient}
|
<!-- {#if orderStore.selectedPatient}
|
||||||
<div class="flex justify-between w-full rounded-md border p-2">
|
<div class="flex justify-between w-full rounded-md border p-2">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<span class="font-bold tracking-wide underline">
|
<span class="font-bold tracking-wide underline">
|
||||||
@ -77,7 +77,7 @@ $inspect(formState.form)
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if} -->
|
||||||
<OrderFormRenderer
|
<OrderFormRenderer
|
||||||
{formState}
|
{formState}
|
||||||
formFields={formFields}
|
formFields={formFields}
|
||||||
|
|||||||
@ -24,6 +24,11 @@
|
|||||||
import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";
|
import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";
|
||||||
import * as Table from "$lib/components/ui/table/index.js";
|
import * as Table from "$lib/components/ui/table/index.js";
|
||||||
import * as Tooltip from "$lib/components/ui/tooltip/index.js";
|
import * as Tooltip from "$lib/components/ui/tooltip/index.js";
|
||||||
|
import * as Card from "$lib/components/ui/card/index.js";
|
||||||
|
import { ScrollArea } from "$lib/components/ui/scroll-area/index.js";
|
||||||
|
import * as Collapsible from "$lib/components/ui/collapsible/index.js";
|
||||||
|
import { Checkbox } from "$lib/components/ui/checkbox/index.js";
|
||||||
|
import { untrack } from 'svelte';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
formState,
|
formState,
|
||||||
@ -39,7 +44,9 @@
|
|||||||
let selectedCodes = $derived(
|
let selectedCodes = $derived(
|
||||||
new Set((formState.form.Tests ?? []).map(t => t.TestSiteCode))
|
new Set((formState.form.Tests ?? []).map(t => t.TestSiteCode))
|
||||||
);
|
);
|
||||||
|
let discipline = $state([]);
|
||||||
|
let selectedDiscipline = $state(null);
|
||||||
|
$inspect(discipline)
|
||||||
function getFilteredOptions(key) {
|
function getFilteredOptions(key) {
|
||||||
const query = searchQuery[key] || '';
|
const query = searchQuery[key] || '';
|
||||||
if (!query) return formState.selectOptions?.[key] ?? [];
|
if (!query) return formState.selectOptions?.[key] ?? [];
|
||||||
@ -101,10 +108,30 @@
|
|||||||
formState.validateField?.('Tests', formState.form.Tests, false);
|
formState.validateField?.('Tests', formState.form.Tests, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchDiscipline(endpoint) {
|
||||||
|
if (!endpoint || discipline.length > 0) return;
|
||||||
|
const res = await fetch(endpoint);
|
||||||
|
const response = await res.json();
|
||||||
|
discipline = await response.data;
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
initializeDefaultValues();
|
initializeDefaultValues();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
untrack(() => {
|
||||||
|
for (const group of formFields) {
|
||||||
|
for (const row of group.rows) {
|
||||||
|
for (const col of row.columns) {
|
||||||
|
if (col.type === 'tests2' && col.otherEndpoint) {
|
||||||
|
fetchDiscipline(col.otherEndpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet Fieldset({
|
{#snippet Fieldset({
|
||||||
@ -113,34 +140,26 @@
|
|||||||
required,
|
required,
|
||||||
type,
|
type,
|
||||||
optionsEndpoint,
|
optionsEndpoint,
|
||||||
|
otherEndpoint,
|
||||||
options,
|
options,
|
||||||
validateOn,
|
validateOn,
|
||||||
allowFuture,
|
allowFuture,
|
||||||
valueKey,
|
valueKey,
|
||||||
labelKey,
|
labelKey,
|
||||||
|
withLabel = true,
|
||||||
})}
|
})}
|
||||||
<div class="flex w-full flex-col gap-1.5">
|
<div class="flex w-full flex-col min-h-0 flex-1 h-full gap-1.5 overflow-hidden">
|
||||||
<div class="flex justify-between items-center w-full">
|
{#if withLabel}
|
||||||
<Label>{label}</Label>
|
<div class="flex justify-between items-center w-full">
|
||||||
{#if required}
|
<div class="ps-1">
|
||||||
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
<Label>{label}</Label>
|
||||||
{/if}
|
|
||||||
{#if key === 'FormulaCode' && formState.form.FormulaInput?.length}
|
|
||||||
{@const inputStatus = onGetErrorStatus?.()}
|
|
||||||
<div class="flex items-center gap-2 text-sm text-destructive">
|
|
||||||
<span>Must included :</span>
|
|
||||||
|
|
||||||
<div class="flex gap-1 flex-wrap">
|
|
||||||
{#each inputStatus as item (item.value)}
|
|
||||||
<Badge class="px-1 text-[10px]" variant={item.done ? 'default' : 'destructive'}>
|
|
||||||
{item.value}
|
|
||||||
</Badge>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{#if required}
|
||||||
</div>
|
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
||||||
<div class="relative flex flex-col items-start w-full">
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div class="relative flex flex-col h-full items-start w-full flex-1 p-1 overflow-hidden">
|
||||||
{#if type === 'text'}
|
{#if type === 'text'}
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
@ -335,6 +354,212 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</Table.Body>
|
</Table.Body>
|
||||||
</Table.Root>
|
</Table.Root>
|
||||||
|
{:else if type === "tests2"}
|
||||||
|
{@const allTests = formState.selectOptions?.[key] ?? []}
|
||||||
|
{@const _ = console.log('allTests', allTests)}
|
||||||
|
{@const disciplineList = [
|
||||||
|
...new Map(
|
||||||
|
allTests
|
||||||
|
.filter(t => t.DisciplineID !== null)
|
||||||
|
.map(t => [t.DisciplineID, { id: t.DisciplineID, name: t.DisciplineName }])
|
||||||
|
).values()
|
||||||
|
]}
|
||||||
|
{@const filteredOptions = getFilteredOptions(key)}
|
||||||
|
{@const filteredTests = selectedDiscipline
|
||||||
|
? allTests.filter(t => t.DisciplineID === selectedDiscipline)
|
||||||
|
: allTests}
|
||||||
|
<div class="flex flex-1 h-full min-h-0 w-full gap-2">
|
||||||
|
<div class="flex flex-1 flex-col gap-2 overflow-hidden min-h-0 h-full w-full">
|
||||||
|
<div class="shrink-0 h-18 p-1 flex gap-2 border-b-2 flex flex-col">
|
||||||
|
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wide">Test list</p>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<Select.Root
|
||||||
|
type="single"
|
||||||
|
onValueChange={(val) => selectedDiscipline = val || null}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (open && otherEndpoint) {
|
||||||
|
formState.fetchOptions?.(
|
||||||
|
{ key, otherEndpoint, valueKey, labelKey },
|
||||||
|
formState.form
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Select.Trigger class="w-full truncate">
|
||||||
|
{disciplineList.find(d => d.id === selectedDiscipline)?.name || 'All Disciplines'}
|
||||||
|
</Select.Trigger>
|
||||||
|
<Select.Content>
|
||||||
|
<Select.Item value="">- All -</Select.Item>
|
||||||
|
{#each discipline as disc}
|
||||||
|
<Select.Item value={disc.DisciplineID}>{disc.DisciplineName}</Select.Item>
|
||||||
|
{/each}
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-h-0 overflow-y-auto [scrollbar-width:thin] [&::-webkit-scrollbar]:w-1" >
|
||||||
|
<Collapsible.Root>
|
||||||
|
<Collapsible.Trigger
|
||||||
|
class="flex w-full items-center justify-between px-3 py-2 rounded-md bg-muted/50 hover:bg-muted transition-colors text-left"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<ChevronDownIcon />
|
||||||
|
<span class="text-sm font-medium">Hematologi</span>
|
||||||
|
<span class="text-xs text-muted-foreground">5 tests</span>
|
||||||
|
</div>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content>
|
||||||
|
<div class="py-1 px-1">
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">HB</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Hemoglobin</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">HCT</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Hematokrit</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">HCT</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Hematocrit</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">HCT</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Hematocret</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">HCT</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Hematocrut</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Collapsible.Root>
|
||||||
|
<Collapsible.Trigger
|
||||||
|
class="flex w-full items-center justify-between px-3 py-2 rounded-md bg-muted/50 hover:bg-muted transition-colors text-left"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<ChevronDownIcon />
|
||||||
|
<span class="text-sm font-medium">Kimia Klenik</span>
|
||||||
|
<span class="text-xs text-muted-foreground">17 tests</span>
|
||||||
|
</div>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content>
|
||||||
|
<div class="py-1 px-1">
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">CREA</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Creatinine</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">GLU</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Glukosa</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">GLUP</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Glukosa Puasa</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">GPU</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Yahud</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">ASOE</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Israhell</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
<Collapsible.Root>
|
||||||
|
<Collapsible.Trigger
|
||||||
|
class="flex w-full items-center justify-between px-3 py-2 rounded-md bg-muted/50 hover:bg-muted transition-colors text-left"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<ChevronDownIcon />
|
||||||
|
<span class="text-sm font-medium">Immunologi</span>
|
||||||
|
<span class="text-xs text-muted-foreground">10 tests</span>
|
||||||
|
</div>
|
||||||
|
</Collapsible.Trigger>
|
||||||
|
<Collapsible.Content>
|
||||||
|
<div class="py-1 px-1">
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">HIV</span>
|
||||||
|
<Label class="text-sm cursor-pointer">HIV</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">TESTO</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Testosteron</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">ESTR</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Estrogen</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">GPU</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Yahud</Label>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 px-3 py-2 rounded-md transition-colors">
|
||||||
|
<Checkbox />
|
||||||
|
<span class="text-xs font-semibold text-primary w-14 shrink-0">ASOE</span>
|
||||||
|
<Label class="text-sm cursor-pointer">Israhell</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Collapsible.Content>
|
||||||
|
</Collapsible.Root>
|
||||||
|
</div>
|
||||||
|
<div class="shrink-0 p-2 border-t border-b flex items-center justify-between">
|
||||||
|
<span class="text-sm">0 selected</span>
|
||||||
|
<Button size="sm" class="px-4 py-2 rounded">Add selected</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-1 flex-col overflow-hidden min-h-0 h-full w-1/2 gap-2">
|
||||||
|
<div class="shrink-0 h-7 border-b-2 flex justify-between items-start">
|
||||||
|
<p class="text-xs font-medium text-muted-foreground uppercase tracking-wide">Test ordered</p>
|
||||||
|
<Badge variant="outline">0 test(s)</Badge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 p-1 flex-1 min-h-0 overflow-y-auto w-full [scrollbar-width:thin] [&::-webkit-scrollbar]:w-1">
|
||||||
|
{#each [1,2,3,3] as x }
|
||||||
|
<InputGroup.Root class="p-1">
|
||||||
|
<InputGroup.Addon align="inline-start">
|
||||||
|
1
|
||||||
|
</InputGroup.Addon>
|
||||||
|
<InputGroup.Addon align="inline-start">
|
||||||
|
CREAD
|
||||||
|
</InputGroup.Addon>
|
||||||
|
<InputGroup.Addon align="inline-start">
|
||||||
|
MCU PT. XYZ
|
||||||
|
</InputGroup.Addon>
|
||||||
|
<InputGroup.Input readonly />
|
||||||
|
<InputGroup.Addon align="inline-end">
|
||||||
|
<InputGroup.Button
|
||||||
|
aria-label="Delete"
|
||||||
|
title="Delete"
|
||||||
|
size="icon-xs"
|
||||||
|
>
|
||||||
|
<Trash2Icon />
|
||||||
|
</InputGroup.Button>
|
||||||
|
</InputGroup.Addon>
|
||||||
|
</InputGroup.Root>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
@ -354,9 +579,9 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{#snippet GroupBlock(groups)}
|
{#snippet GroupBlock(groups)}
|
||||||
<div class="p-2 space-y-6">
|
<div class="p-2 min-h-0 flex-1 flex flex-col h-full">
|
||||||
{#each groups as group}
|
{#each groups as group}
|
||||||
<div class="space-y-6">
|
<div class="flex flex-col flex-1 space-y-4 h-full">
|
||||||
{#if group.title}
|
{#if group.title}
|
||||||
<div class="text-md 2xl:text-lg font-semibold italic">
|
<div class="text-md 2xl:text-lg font-semibold italic">
|
||||||
<span class="border-b-2 border-primary">{group.title}</span>
|
<span class="border-b-2 border-primary">{group.title}</span>
|
||||||
@ -365,7 +590,8 @@
|
|||||||
|
|
||||||
{#each group.rows as row}
|
{#each group.rows as row}
|
||||||
<div
|
<div
|
||||||
class="grid grid-cols-1 space-y-2 gap-6 md:gap-4"
|
class="grid grid-cols-1 grid-rows-1 space-y-2 h-full gap-3 min-h-0 md:gap-2"
|
||||||
|
class:h-full={row.columns.some(col => col.key === "Tests")}
|
||||||
class:md:grid-cols-1={row.columns.length === 1}
|
class:md:grid-cols-1={row.columns.length === 1}
|
||||||
class:md:grid-cols-2={row.columns.length === 2}
|
class:md:grid-cols-2={row.columns.length === 2}
|
||||||
class:md:grid-cols-3={row.columns.length === 3}
|
class:md:grid-cols-3={row.columns.length === 3}
|
||||||
@ -380,11 +606,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
<div class="flex w-full h-full gap-1">
|
<div class="flex w-full h-full min-h-0 overflow-hidden gap-1">
|
||||||
<div class="w-1/3 h-full min-w-0 overflow-y-auto [scrollbar-width:thin] [&::-webkit-scrollbar]:w-1">
|
<div class="w-1/3 h-full min-h-0 overflow-hidden flex flex-col">
|
||||||
{@render GroupBlock(leftGroups)}
|
{@render GroupBlock(leftGroups)}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 h-full min-w-0 overflow-y-auto [scrollbar-width:thin] [&::-webkit-scrollbar]:w-1">
|
<div class="flex-1 h-full min-h-0 overflow-hidden flex flex-col">
|
||||||
{@render GroupBlock(rightGroups)}
|
{@render GroupBlock(rightGroups)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
10
src/lib/components/ui/scroll-area/index.js
Normal file
10
src/lib/components/ui/scroll-area/index.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import Scrollbar from "./scroll-area-scrollbar.svelte";
|
||||||
|
import Root from "./scroll-area.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Scrollbar,
|
||||||
|
//,
|
||||||
|
Root as ScrollArea,
|
||||||
|
Scrollbar as ScrollAreaScrollbar,
|
||||||
|
};
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
<script>
|
||||||
|
import { ScrollArea as ScrollAreaPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
orientation = "vertical",
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ScrollAreaPrimitive.Scrollbar
|
||||||
|
bind:ref
|
||||||
|
data-slot="scroll-area-scrollbar"
|
||||||
|
data-orientation={orientation}
|
||||||
|
{orientation}
|
||||||
|
class={cn(
|
||||||
|
"data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent flex touch-none p-px transition-colors select-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
<ScrollAreaPrimitive.Thumb
|
||||||
|
data-slot="scroll-area-thumb"
|
||||||
|
class="rounded-full bg-border relative flex-1"
|
||||||
|
/>
|
||||||
|
</ScrollAreaPrimitive.Scrollbar>
|
||||||
38
src/lib/components/ui/scroll-area/scroll-area.svelte
Normal file
38
src/lib/components/ui/scroll-area/scroll-area.svelte
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<script>
|
||||||
|
import { ScrollArea as ScrollAreaPrimitive } from "bits-ui";
|
||||||
|
import { Scrollbar } from "./index.js";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
viewportRef = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
orientation = "vertical",
|
||||||
|
scrollbarXClasses = "",
|
||||||
|
scrollbarYClasses = "",
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ScrollAreaPrimitive.Root
|
||||||
|
bind:ref
|
||||||
|
data-slot="scroll-area"
|
||||||
|
class={cn("relative", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
<ScrollAreaPrimitive.Viewport
|
||||||
|
bind:ref={viewportRef}
|
||||||
|
data-slot="scroll-area-viewport"
|
||||||
|
class="cn-scroll-area-viewport focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</ScrollAreaPrimitive.Viewport>
|
||||||
|
{#if orientation === "vertical" || orientation === "both"}
|
||||||
|
<Scrollbar orientation="vertical" class={scrollbarYClasses} />
|
||||||
|
{/if}
|
||||||
|
{#if orientation === "horizontal" || orientation === "both"}
|
||||||
|
<Scrollbar orientation="horizontal" class={scrollbarXClasses} />
|
||||||
|
{/if}
|
||||||
|
<ScrollAreaPrimitive.Corner />
|
||||||
|
</ScrollAreaPrimitive.Root>
|
||||||
26
src/routes/order/coba/+page.svelte
Normal file
26
src/routes/order/coba/+page.svelte
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<div class="flex w-full h-full min-h-0 overflow-hidden gap-1 bg-rose-300">
|
||||||
|
<div class="flex-1 h-full min-h-0 overflow-hidden flex flex-col">
|
||||||
|
|
||||||
|
<div class="p-2 min-h-0 flex-1 flex flex-col h-full">
|
||||||
|
<div class="flex flex-col flex-1 h-full min-h-0"> <div class="grid grid-cols-1 grid-rows-1 h-full min-h-0">
|
||||||
|
|
||||||
|
<div class="flex w-full flex-col min-h-0 flex-1 h-full gap-1.5 overflow-hidden">
|
||||||
|
<div class="relative flex flex-col h-full items-start w-full flex-1 overflow-hidden">
|
||||||
|
|
||||||
|
<div class="flex flex-1 flex-col overflow-hidden min-h-0 bg-rose-100 h-full w-full">
|
||||||
|
<div class="shrink-0 p-2">...</div>
|
||||||
|
|
||||||
|
<div class="flex-1 min-h-0 overflow-y-auto">
|
||||||
|
<div class="h-[1000px] bg-red-300">long</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="shrink-0 p-2">...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
x
Reference in New Issue
Block a user