Change box list display

This commit is contained in:
2026-03-11 13:04:51 +07:00
parent c2981ed7d8
commit ded6f0eb0a
5 changed files with 274 additions and 5 deletions

View File

@@ -0,0 +1,170 @@
import { cn } from '@/lib/utils';
import { m } from '@/paraglide/messages';
import {
CirclesThreeIcon,
HourglassIcon,
TagIcon,
} from '@phosphor-icons/react';
import {
ColumnDef,
flexRender,
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table';
import { Label } from '@ui/label';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@ui/select';
import BoxIcon from './boxes/box-icon';
import Pagination from './Pagination';
interface BoxDisplayProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
page: number;
setPage: (page: number) => void;
limit: number;
setLimit: (page: number) => void;
pagination: {
currentPage: number;
totalPage: number;
totalItem: number;
};
}
const BoxDisplay = <TData, TValue>({
columns,
data,
page,
setPage,
limit,
setLimit,
pagination,
}: BoxDisplayProps<TData, TValue>) => {
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
return (
<>
<div className="overflow-hidden rounded-md border p-5 pr-1 bg-white gap-4 flex flex-row flex-wrap">
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<div
className="relative group border rounded-lg w-full md:w-[calc(100%/2-var(--spacing)*4)] lg:w-56"
key={row.id}
>
<div className="py-4 px-5 [&_svg]:w-full [&_svg]:h-full">
<BoxIcon />
</div>
<div className="flex flex-col">
{row.getVisibleCells().map((cell) => {
if (cell.column.columnDef.id === 'actions') {
return (
<div className="bg-gray-200 py-1 px-3 justify-center">
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</div>
);
}
return (
<div
data-slot={cell.column.columnDef.id}
className={cn('px-5 mb-2 text-center w-full', {
'text-xs flex items-center justify-center gap-2':
cell.column.columnDef.id !== 'name',
'text-sm font-bold line-clamp-1':
cell.column.columnDef.id === 'name',
})}
>
{cell.column.columnDef.id === 'name' && (
<TagIcon size={15} className="inline-block mr-2" />
)}
{cell.column.columnDef.id === 'quantity' && (
<CirclesThreeIcon
size={15}
className="inline-block mr-2"
/>
)}
{cell.column.columnDef.id === 'time' && (
<HourglassIcon
size={15}
className="inline-block mr-2"
/>
)}
{flexRender(
cell.column.columnDef.cell,
cell.getContext(),
)}
</div>
);
})}
</div>
</div>
))
) : (
<div className="flex justify-center p-10 text-sm">No Results</div>
)}
</div>
<div className="flex items-center justify-between gap-2">
<div className="hidden text-sm gap-2 lg:flex">
<span>
{m.common_page_show({
count: pagination.totalItem,
start: (pagination.currentPage - 1) * 10 + 1,
end: Math.min(pagination.currentPage * 10, pagination.totalItem),
})}
</span>
</div>
<div className="flex max-w-full items-center gap-2 justify-between w-full lg:w-fit lg:gap-8">
<div className="items-center gap-2 flex">
<Label
htmlFor="rows-per-page"
className="hidden text-sm font-medium lg:block"
>
{m.common_per_page()}
</Label>
<Select
value={`${limit}`}
onValueChange={(value) => {
setLimit(+value);
setPage(1);
}}
>
<SelectTrigger
type="button"
size="sm"
className="w-30"
id="rows-per-page"
>
<SelectValue placeholder={m.common_select_page_size()} />
</SelectTrigger>
<SelectContent side="top">
{[10, 30, 50, 100].map((pageSize) => (
<SelectItem key={pageSize} value={`${pageSize}`}>
{pageSize}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Pagination
currentPage={page}
totalPages={pagination.totalPage}
onPageChange={(newPage) => setPage(newPage)}
/>
</div>
</div>
</>
);
};
export default BoxDisplay;

View File

@@ -7,6 +7,7 @@ export const boxColumns: ColumnDef<BoxWithCount>[] = [
{
accessorKey: 'name',
header: m.boxes_page_ui_table_header_name(),
id: 'name',
meta: {
thClass: 'w-1/6',
mLabel: m.boxes_page_ui_table_header_name(),
@@ -15,6 +16,7 @@ export const boxColumns: ColumnDef<BoxWithCount>[] = [
{
accessorFn: (row) => row._count.items,
header: m.boxes_page_ui_table_header_item_count(),
id: 'quantity',
meta: {
thClass: 'w-1/6',
mLabel: m.boxes_page_ui_table_header_item_count(),
@@ -23,6 +25,7 @@ export const boxColumns: ColumnDef<BoxWithCount>[] = [
{
accessorKey: 'createdAt',
header: m.boxes_page_ui_table_header_create_at(),
id: 'time',
meta: {
thClass: 'w-2/6',
mLabel: m.boxes_page_ui_table_header_create_at(),

View File

@@ -0,0 +1,90 @@
const BoxIcon = () => {
return (
<svg viewBox="0 0 101 108" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="box">
<path
d="M50.7094 106.914L98.92 79.0797L98.9199 30.5769L56.8966 54.8177L50.7095 58.3867L50.7093 58.3866L50.7094 106.914Z"
fill="#F09C14"
/>
<path
d="M2.49883 79.0797L50.7094 106.914L50.7093 58.3866L44.5221 54.8176L2.49873 30.5767L2.49883 79.0797Z"
fill="#F09C14"
/>
<path
d="M50.7096 106.914L98.92 79.0797L98.9201 30.577L56.8966 54.8177L50.7097 58.3868L50.7095 58.3867L50.7096 106.914Z"
fill="black"
fill-opacity="0.1"
/>
<path
d="M50.7093 2.7423L2.49873 30.5767L44.5221 54.8176L50.7093 51.2454V2.7423Z"
fill="#F09C14"
/>
<path
d="M50.7093 58.3866L50.7095 58.3867L56.8966 54.8177L50.7093 51.2454L44.5221 54.8176L50.7093 58.3866Z"
fill="#F09C14"
/>
<path
d="M50.7093 2.7423V51.2454L56.8966 54.8177L98.9199 30.5769L50.7093 2.7423Z"
fill="#F09C14"
/>
<path
d="M50.7093 2.7423V51.2454L56.8966 54.8177L98.9199 30.5769L50.7093 2.7423Z"
fill="black"
fill-opacity="0.2"
/>
<path
d="M50.7091 58.3865L50.7093 58.3866L56.8964 54.8176L50.7091 51.2453L44.5219 54.8175L50.7091 58.3865Z"
fill="black"
fill-opacity="0.3"
/>
<path
d="M50.7091 2.74219L2.49854 30.5765L44.5219 54.8175L50.7091 51.2453V2.74219Z"
fill="black"
fill-opacity="0.3"
/>
<path
d="M98.92 79.0797L98.9199 30.5769M98.92 79.0797L50.7096 106.914L50.7095 58.3867M98.92 79.0797L98.9201 30.577M98.92 79.0797L50.7094 106.914M50.7094 106.914L2.49883 79.0797L2.49873 30.5767M50.7094 106.914L50.7093 58.3866M50.7095 58.3867L50.7093 58.3866M50.7095 58.3867L50.7097 58.3868L56.8966 54.8177M50.7095 58.3867L56.8966 54.8177M98.9199 30.5769L56.8966 54.8177M98.9199 30.5769L50.7093 2.7423M2.49873 30.5767L50.7093 2.7423M2.49873 30.5767L44.5221 54.8176M50.7093 58.3866L44.5221 54.8176M50.7093 58.3866L50.7091 58.3865L44.5219 54.8175M50.7093 58.3866L56.8964 54.8176L50.7091 51.2453M98.9201 30.577L56.8966 54.8177M98.9201 30.577L50.7093 2.7423M50.7093 2.7423V51.2454M50.7093 51.2454L44.5221 54.8176M50.7093 51.2454L56.8966 54.8177M50.7091 51.2453L44.5219 54.8175M50.7091 51.2453V2.74219L2.49854 30.5765L44.5219 54.8175"
stroke="black"
/>
</g>
<g data-lid="close" className="group-hover:hidden">
<path
d="M100.5 29.4447L50.5 0.577148L0.5 29.4446L50.5 58.3122L100.5 29.4447Z"
fill="#F09C14"
/>
<path
d="M100.5 37.8208V29.4447L50.5 58.3122V66.6629L100.5 37.8208Z"
fill="#F09C14"
/>
<path
d="M50.5 66.6629V58.3122L0.5 29.4446V37.8208L50.4998 66.6628L50.5 66.6629Z"
fill="#F09C14"
/>
<path
d="M50.5 66.6629V58.3122M50.5 66.6629L50.4998 66.6628L0.5 37.8208V29.4446M50.5 66.6629L100.5 37.8208V29.4447M0.5 29.4446L50.5 0.577148L100.5 29.4447M0.5 29.4446L50.5 58.3122M100.5 29.4447L50.5 58.3122"
stroke="black"
/>
</g>
<g data-lid="open" className="hidden group-hover:block">
<path
d="M100.5 29.4159L50.5 0.54834L0.5 18.2581L50.5 47.1256L100.5 29.4159Z"
fill="#F09C14"
/>
<path
d="M100.5 37.7919V29.4159L50.5 47.1256V55.4763L100.5 37.7919Z"
fill="#F09C14"
/>
<path
d="M50.5 55.4763V47.1256L0.5 18.2581V26.6342L50.5 55.4763Z"
fill="#F09C14"
/>
<path
d="M50.5 55.4763V47.1256M50.5 55.4763L0.5 26.6342V18.2581M50.5 55.4763L100.5 37.7919V29.4159M0.5 18.2581L50.5 0.54834L100.5 29.4159M0.5 18.2581L50.5 47.1256M100.5 29.4159L50.5 47.1256"
stroke="black"
/>
</g>
</svg>
);
};
export default BoxIcon;

View File

@@ -1,6 +1,6 @@
import BoxDisplay from '@/components/BoxDisplay';
import { boxColumns } from '@/components/boxes/box-columns';
import CreateBoxAction from '@/components/boxes/create-box-dialog';
import DataTable from '@/components/DataTable';
import SearchInput from '@/components/ui/search-input';
import { Skeleton } from '@/components/ui/skeleton';
import useDebounced from '@/hooks/use-debounced';
@@ -65,7 +65,7 @@ function RouteComponent() {
<CreateBoxAction />
</div>
{data && (
<DataTable
<BoxDisplay
data={data.result || []}
columns={boxColumns}
page={page}

View File

@@ -1,9 +1,15 @@
import { createFileRoute } from '@tanstack/react-router'
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/(app)/(auth)/kanri/items')({
component: RouteComponent,
})
});
function RouteComponent() {
return <div>Hello "/(app)/(auth)/kanri/items"!</div>
return (
<div className="@container/main flex flex-1 flex-col gap-2 p-4">
<div className="*:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card *:data-[slot=card]:bg-linear-to-br *:data-[slot=card]:shadow-xs">
Hello "/(app)/(auth)/kanri/items"!
</div>
</div>
);
}