Change box list display
This commit is contained in:
170
src/components/BoxDisplay.tsx
Normal file
170
src/components/BoxDisplay.tsx
Normal 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;
|
||||||
@@ -7,6 +7,7 @@ export const boxColumns: ColumnDef<BoxWithCount>[] = [
|
|||||||
{
|
{
|
||||||
accessorKey: 'name',
|
accessorKey: 'name',
|
||||||
header: m.boxes_page_ui_table_header_name(),
|
header: m.boxes_page_ui_table_header_name(),
|
||||||
|
id: 'name',
|
||||||
meta: {
|
meta: {
|
||||||
thClass: 'w-1/6',
|
thClass: 'w-1/6',
|
||||||
mLabel: m.boxes_page_ui_table_header_name(),
|
mLabel: m.boxes_page_ui_table_header_name(),
|
||||||
@@ -15,6 +16,7 @@ export const boxColumns: ColumnDef<BoxWithCount>[] = [
|
|||||||
{
|
{
|
||||||
accessorFn: (row) => row._count.items,
|
accessorFn: (row) => row._count.items,
|
||||||
header: m.boxes_page_ui_table_header_item_count(),
|
header: m.boxes_page_ui_table_header_item_count(),
|
||||||
|
id: 'quantity',
|
||||||
meta: {
|
meta: {
|
||||||
thClass: 'w-1/6',
|
thClass: 'w-1/6',
|
||||||
mLabel: m.boxes_page_ui_table_header_item_count(),
|
mLabel: m.boxes_page_ui_table_header_item_count(),
|
||||||
@@ -23,6 +25,7 @@ export const boxColumns: ColumnDef<BoxWithCount>[] = [
|
|||||||
{
|
{
|
||||||
accessorKey: 'createdAt',
|
accessorKey: 'createdAt',
|
||||||
header: m.boxes_page_ui_table_header_create_at(),
|
header: m.boxes_page_ui_table_header_create_at(),
|
||||||
|
id: 'time',
|
||||||
meta: {
|
meta: {
|
||||||
thClass: 'w-2/6',
|
thClass: 'w-2/6',
|
||||||
mLabel: m.boxes_page_ui_table_header_create_at(),
|
mLabel: m.boxes_page_ui_table_header_create_at(),
|
||||||
|
|||||||
90
src/components/boxes/box-icon.tsx
Normal file
90
src/components/boxes/box-icon.tsx
Normal 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;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import BoxDisplay from '@/components/BoxDisplay';
|
||||||
import { boxColumns } from '@/components/boxes/box-columns';
|
import { boxColumns } from '@/components/boxes/box-columns';
|
||||||
import CreateBoxAction from '@/components/boxes/create-box-dialog';
|
import CreateBoxAction from '@/components/boxes/create-box-dialog';
|
||||||
import DataTable from '@/components/DataTable';
|
|
||||||
import SearchInput from '@/components/ui/search-input';
|
import SearchInput from '@/components/ui/search-input';
|
||||||
import { Skeleton } from '@/components/ui/skeleton';
|
import { Skeleton } from '@/components/ui/skeleton';
|
||||||
import useDebounced from '@/hooks/use-debounced';
|
import useDebounced from '@/hooks/use-debounced';
|
||||||
@@ -65,7 +65,7 @@ function RouteComponent() {
|
|||||||
<CreateBoxAction />
|
<CreateBoxAction />
|
||||||
</div>
|
</div>
|
||||||
{data && (
|
{data && (
|
||||||
<DataTable
|
<BoxDisplay
|
||||||
data={data.result || []}
|
data={data.result || []}
|
||||||
columns={boxColumns}
|
columns={boxColumns}
|
||||||
page={page}
|
page={page}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router'
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
|
||||||
export const Route = createFileRoute('/(app)/(auth)/kanri/items')({
|
export const Route = createFileRoute('/(app)/(auth)/kanri/items')({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
})
|
});
|
||||||
|
|
||||||
function 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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user