Supra_App/src/lib/components/recipe-details/recipelist-table.svelte
pakintada@gmail.com dbb5ce466c feat: showing recipe list values
- add displaying for values in recipe list, with some editable fields except topping, string params, feed pattern/level

Signed-off-by: pakintada@gmail.com <Pakin>
2026-03-04 13:28:14 +07:00

196 lines
5.5 KiB
Svelte

<script module>
export { DragHandle };
</script>
<script lang="ts">
import * as Card from '$lib/components/ui/card/index';
import Label from '$lib/components/ui/label/label.svelte';
import Input from '$lib/components/ui/input/input.svelte';
import RecipeDetail from './recipe-detail.svelte';
import {
createTable,
getCoreRowModel,
getFacetedRowModel,
getSortedRowModel,
type ColumnDef,
type Row,
type RowSelectionState,
type SortingState
} from '@tanstack/table-core';
import { createSvelteTable } from '../ui/data-table';
import * as Table from '$lib/components/ui/table/index';
import FlexRender from '../ui/data-table/flex-render.svelte';
import ScrollArea from '../ui/scroll-area/scroll-area.svelte';
import { type Attachment } from 'svelte/attachments';
import Button from '../ui/button/button.svelte';
import { GripVerticalIcon } from '@lucide/svelte/icons';
import { DragDropProvider } from '@dnd-kit-svelte/svelte';
import { move } from '@dnd-kit/helpers';
import { RestrictToVerticalAxis } from '@dnd-kit/abstract/modifiers';
import { type UniqueIdentifier } from '@dnd-kit/abstract';
import { type RecipelistMaterial } from './columns';
import { useSortable } from '@dnd-kit-svelte/svelte/sortable';
import { onMount } from 'svelte';
import { get, writable, type Writable } from 'svelte/store';
// type DataTableProps<TData, TValue> = {
// columns: ColumnDef<TData, TValue>[];
// data: TData[];
// };
let {
data,
columns,
onStateChange
}: {
data: RecipelistMaterial[];
columns: ColumnDef<any, any>[];
onStateChange: any;
} = $props();
let sorting = $state<SortingState>([]);
let rowSelection = $state<RowSelectionState>({});
// let recipeMatState = $state<RecipelistMaterial[]>(data);
const table = createSvelteTable({
get data() {
return data;
},
columns,
enableRowSelection: true,
enableMultiRowSelection: true,
getRowId: (row: any) => row.id.toString(),
state: {
get sorting() {
return sorting;
},
get rowSelection() {
return rowSelection;
}
},
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFacetedRowModel: getFacetedRowModel(),
onStateChange: async (updater) => {
console.log('table state change', data);
await onStateChange(table.getRowModel().rows.map((x) => x.original));
},
onSortingChange: async (updater) => {
console.log('triggering sorting');
if (typeof updater === 'function') {
sorting = updater(sorting);
} else {
sorting = updater;
}
await onStateChange(table.getRowModel().rows.map((x) => x.original));
},
onRowSelectionChange: async (updater) => {
// table.getRowModel().rows.find((x) => x.original.id == )
if (typeof updater === 'function') {
rowSelection = updater(rowSelection);
let rows = table.getRowModel().rows;
console.log('state size', data, rows);
} else {
rowSelection = updater;
}
await onStateChange(table.getRowModel().rows.map((x) => x.original));
}
});
</script>
<!-- use card -->
<Card.Root>
<Card.Header>
<Card.Title>Recipe List</Card.Title>
<Card.Description>Material used in this menu's brewing process.</Card.Description>
<Card.Content>
<!-- table -->
<DragDropProvider
modifiers={[
// @ts-expect-error @dnd-kit/adbstract types are botched atm
RestrictToVerticalAxis
]}
onDragEnd={(e) => {
// snap
data = move(data as any, e as any);
//
}}
>
<ScrollArea class="h-[60vh] w-full rounded-md border" type="always">
<Table.Root class="relative w-full">
<Table.Header class="sticky top-0 z-10">
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
<Table.Row>
{#each headerGroup.headers as header (header.id)}
<Table.Head colspan={header.colSpan}>
{#if !header.isPlaceholder}
<FlexRender
content={header.column.columnDef.header}
context={header.getContext()}
/>
{/if}
</Table.Head>
{/each}
</Table.Row>
{/each}
</Table.Header>
<Table.Body class="**:data-[slot=table-cell]:first:w-8">
{#if table.getRowModel().rows?.length}
{#each table.getRowModel().rows as row, index (row.id)}
{@render DraggableRow({ row, index })}
{/each}
{:else}
<Table.Row>
<Table.Cell colspan={columns.length} class="h-24 text-center"
>Empty recipe.</Table.Cell
>
</Table.Row>
{/if}
</Table.Body>
</Table.Root>
</ScrollArea>
</DragDropProvider>
</Card.Content>
</Card.Header>
</Card.Root>
{#snippet DraggableRow({ row, index }: { row: Row<any>; index: number })}
{@const { ref, isDragging, handleRef } = useSortable({
id: row.original.id,
index: () => index
})}
<Table.Row
data-state={row.original.is_use ? 'selected' : undefined}
data-dragging={isDragging.current}
class="relative z-0 data-[dragging=true]:z-10 data-[dragging=true]:opacity-80"
{@attach ref}
>
{#each row.getVisibleCells() as cell (cell.id)}
<Table.Cell>
<FlexRender
attach={handleRef}
content={cell.column.columnDef.cell}
context={cell.getContext()}
/>
</Table.Cell>
{/each}
</Table.Row>
{/snippet}
{#snippet DragHandle({ attach }: { attach: Attachment })}
<Button
{@attach attach}
variant="ghost"
size="icon"
class="size-7 text-muted-foreground hover:bg-transparent"
>
<GripVerticalIcon class="size-3 text-muted-foreground" />
<span class="sr-only">Drag to reorder</span>
</Button>
{/snippet}