mirror of
https://github.com/faiztyanirh/clqms-shadcn-v1.git
synced 2026-04-24 18:18:07 +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": {
|
||||
"@eslint/compat": "^1.4.0",
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@internationalized/date": "^3.10.1",
|
||||
"@internationalized/date": "^3.12.1",
|
||||
"@lucide/svelte": "^0.561.0",
|
||||
"@sveltejs/adapter-auto": "^7.0.0",
|
||||
"@sveltejs/kit": "^2.49.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||
"@tanstack/table-core": "^8.21.3",
|
||||
"@types/node": "^22",
|
||||
"bits-ui": "^2.15.4",
|
||||
"bits-ui": "^2.18.0",
|
||||
"clsx": "^2.1.1",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
@ -715,9 +715,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@internationalized/date": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.10.1.tgz",
|
||||
"integrity": "sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==",
|
||||
"version": "3.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.1.tgz",
|
||||
"integrity": "sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@ -1618,9 +1618,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bits-ui": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.15.4.tgz",
|
||||
"integrity": "sha512-7H9YUfp03KOk1LVDh8wPYSRPxlZgG/GRWLNSA8QC73/8Z8ytun+DWJhIuibyFyz7A0cP/RANVcB4iDrbY8q+Og==",
|
||||
"version": "2.18.0",
|
||||
"resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.18.0.tgz",
|
||||
"integrity": "sha512-GLOBZRVy3hxNHIQ2MpD/+5aK9KcBFZRhUJtZ1UDABXdlVR4K6zFpgt4T+Rwuhf2sQzlc6yK1q/DprHPjwT4Pjw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@ -14,14 +14,14 @@
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.4.0",
|
||||
"@eslint/js": "^9.39.1",
|
||||
"@internationalized/date": "^3.10.1",
|
||||
"@internationalized/date": "^3.12.1",
|
||||
"@lucide/svelte": "^0.561.0",
|
||||
"@sveltejs/adapter-auto": "^7.0.0",
|
||||
"@sveltejs/kit": "^2.49.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
||||
"@tanstack/table-core": "^8.21.3",
|
||||
"@types/node": "^22",
|
||||
"bits-ui": "^2.15.4",
|
||||
"bits-ui": "^2.18.0",
|
||||
"clsx": "^2.1.1",
|
||||
"eslint": "^9.39.1",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
|
||||
@ -143,10 +143,11 @@ export const orderTestFormFields = [
|
||||
columns: [
|
||||
{
|
||||
key: "Tests",
|
||||
label: "Search Test",
|
||||
required: true,
|
||||
type: "tests",
|
||||
withLabel: false,
|
||||
type: "tests2",
|
||||
optionsEndpoint: `${API.BASE_URL}${API.TEST}`,
|
||||
otherEndpoint: `${API.BASE_URL}${API.DISCIPLINE}`,
|
||||
valueKey: 'TestSiteCode',
|
||||
labelKey: (item) => `${item.TestSiteCode} - ${item.TestSiteName}`,
|
||||
validateOn: ['input']
|
||||
|
||||
@ -53,7 +53,7 @@ $inspect(formState.form)
|
||||
</script>
|
||||
|
||||
<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 flex-col">
|
||||
<span class="font-bold tracking-wide underline">
|
||||
@ -77,7 +77,7 @@ $inspect(formState.form)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if} -->
|
||||
<OrderFormRenderer
|
||||
{formState}
|
||||
formFields={formFields}
|
||||
|
||||
@ -24,6 +24,11 @@
|
||||
import ReusableUpload from "$lib/components/reusable/reusable-upload.svelte";
|
||||
import * as Table from "$lib/components/ui/table/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 {
|
||||
formState,
|
||||
@ -39,7 +44,9 @@
|
||||
let selectedCodes = $derived(
|
||||
new Set((formState.form.Tests ?? []).map(t => t.TestSiteCode))
|
||||
);
|
||||
|
||||
let discipline = $state([]);
|
||||
let selectedDiscipline = $state(null);
|
||||
$inspect(discipline)
|
||||
function getFilteredOptions(key) {
|
||||
const query = searchQuery[key] || '';
|
||||
if (!query) return formState.selectOptions?.[key] ?? [];
|
||||
@ -101,10 +108,30 @@
|
||||
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(() => {
|
||||
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>
|
||||
|
||||
{#snippet Fieldset({
|
||||
@ -113,34 +140,26 @@
|
||||
required,
|
||||
type,
|
||||
optionsEndpoint,
|
||||
otherEndpoint,
|
||||
options,
|
||||
validateOn,
|
||||
allowFuture,
|
||||
valueKey,
|
||||
labelKey,
|
||||
withLabel = true,
|
||||
})}
|
||||
<div class="flex w-full flex-col gap-1.5">
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<Label>{label}</Label>
|
||||
{#if required}
|
||||
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
||||
{/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 class="flex w-full flex-col min-h-0 flex-1 h-full gap-1.5 overflow-hidden">
|
||||
{#if withLabel}
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<div class="ps-1">
|
||||
<Label>{label}</Label>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="relative flex flex-col items-start w-full">
|
||||
{#if required}
|
||||
<span class="text-destructive text-xl leading-none h-3.5">*</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="relative flex flex-col h-full items-start w-full flex-1 p-1 overflow-hidden">
|
||||
{#if type === 'text'}
|
||||
<Input
|
||||
type="text"
|
||||
@ -335,6 +354,212 @@
|
||||
{/if}
|
||||
</Table.Body>
|
||||
</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}
|
||||
<Input
|
||||
type="text"
|
||||
@ -354,9 +579,9 @@
|
||||
{/snippet}
|
||||
|
||||
{#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}
|
||||
<div class="space-y-6">
|
||||
<div class="flex flex-col flex-1 space-y-4 h-full">
|
||||
{#if group.title}
|
||||
<div class="text-md 2xl:text-lg font-semibold italic">
|
||||
<span class="border-b-2 border-primary">{group.title}</span>
|
||||
@ -365,7 +590,8 @@
|
||||
|
||||
{#each group.rows as row}
|
||||
<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-2={row.columns.length === 2}
|
||||
class:md:grid-cols-3={row.columns.length === 3}
|
||||
@ -380,11 +606,11 @@
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<div class="flex w-full h-full gap-1">
|
||||
<div class="w-1/3 h-full min-w-0 overflow-y-auto [scrollbar-width:thin] [&::-webkit-scrollbar]:w-1">
|
||||
<div class="flex w-full h-full min-h-0 overflow-hidden gap-1">
|
||||
<div class="w-1/3 h-full min-h-0 overflow-hidden flex flex-col">
|
||||
{@render GroupBlock(leftGroups)}
|
||||
</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)}
|
||||
</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