1
0
forked from a/lifeto-shop
lifeto-shop/src/lib/table/tanstack.tsx

139 lines
4.2 KiB
TypeScript
Raw Normal View History

2025-05-25 05:17:41 +00:00
import { createColumnHelper } from '@tanstack/react-table';
import { ItemWithSelection } from './defs';
import { useAtomValue, useSetAtom } from 'jotai';
import { currentItemSelectionAtom, itemSelectionSetActionAtom } from '@/state/atoms';
import { useMemo } from 'react';
import { StatsColumns } from '../columns';
const ch = createColumnHelper<ItemWithSelection>();
const columns = {
icon: ch.display({
id: 'icon',
header: function Component(col) {
return <div className="flex flex-row justify-center"></div>
},
cell: function Component({ row }){
const setItemSelection= useSetAtom(itemSelectionSetActionAtom);
const c = useAtomValue(currentItemSelectionAtom);
const selected = useMemo(()=> {
return c[0].has(row.original.item.id);
}, [c])
return <div
className={`no-select flex flex-row ${ row.original.status?.selected ? "animate-pulse" : ""}`}
onClick={(e)=>{
setItemSelection({
[row.original.item.id]: selected ? undefined : row.original.item.item_count,
})
}}
>
<div className="flex flex-row w-6 h-6 justify-center">
<img src={row.original.item.item_image || ""} alt="icon" className="select-none object-contain select-none"/>
</div>
</div>
},
}),
count: ch.display({
id: 'count',
header: function Component(col){
return <div className="flex flex-row justify-center">#</div>
},
cell: function Component({ row }){
const c = useAtomValue(currentItemSelectionAtom);
const setItemSelection= useSetAtom(itemSelectionSetActionAtom);
const currentValue = useMemo(()=> {
const got = c[0].get(row.original.item.id);
if(got !== undefined) {
return got.toString();
}
return ""
}, [c])
const itemCount = row.original.item.item_count
return <div
className={`flex flex-row select-none ${ row.original.status?.selected ? "bg-gray-200" : ""}`}
>
<input
className="w-10 text-center "
value={currentValue}
onChange={(e)=>{
if(e.target.value === ""){
setItemSelection({[row.original.item.id]: undefined});
return
}
if(e.target.value === "-"){
setItemSelection({
[row.original.item.id]: itemCount,
})
}
let parsedInt = parseInt(e.target.value);
if (isNaN(parsedInt)) {
return;
}
if(parsedInt > itemCount){
parsedInt = itemCount;
}
setItemSelection({
[row.original.item.id]: parsedInt,
})
}}
placeholder={itemCount.toString()} />
</div>
},
}),
name: ch.display({
id: 'name',
header: (col)=> {
return <div
className="flex flex-row text-sm"
>name</div>
},
cell: function Component({ row }){
return <div className="flex flex-row whitespace-pre">
<span>{row.original.item.item_name}</span>
</div>
},
}),
slots: ch.display({
id: 'slots',
header: (col)=>{
return <div
className="flex flex-row text-sm"
>slots</div>
},
cell: function Component({ row }){
return <div className="flex flex-row justify-center">
<span>{row.original.item.item_slots}</span>
</div>
},
}),
stats: ch.group({
id: 'stats',
header: (col)=>{
return <div
className="flex flex-row text-sm"
>stats</div>
},
columns: [
...StatsColumns.map((c)=>{
return ch.display({
id: 'stats.'+c,
header: (col)=>{
return <div
className="flex flex-row text-sm justify-center"
>{c}</div>
},
cell: function Component({ row }){
const stats = row.original.item.stats
const stat = stats ? stats[c] : ""
return <div className={`flex flex-row justify-start ${stat ? "border" : ""}`}>
<span>{stat}</span>
</div>
},
})
})
]
}),
} as const;
export const InventoryColumns = columns;