-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathPlantTable.tsx
More file actions
116 lines (110 loc) · 4.6 KB
/
PlantTable.tsx
File metadata and controls
116 lines (110 loc) · 4.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import {Cell, Column, Row, Table, TableHeader, TableBody} from 'tailwind-starter/Table';
import {StarIcon} from 'lucide-react';
import {ColumnProps, Key, SortDescriptor, ToggleButton, ToggleButtonProps, VisuallyHidden} from 'react-aria-components';
import {focusRing} from 'tailwind-starter/utils';
import {Plant} from './plants';
import React, {useMemo} from 'react';
import {tv} from 'tailwind-variants';
import {CycleLabel, getSunlight, SunLabel, WateringLabel} from './Labels';
import {PlantActionMenu} from './PlantActionMenu';
const allColumns: ColumnProps[] = [
{id: 'favorite', children: <VisuallyHidden>Favorite</VisuallyHidden>, width: 40, minWidth: 40},
{id: 'common_name', children: 'Name', minWidth: 150, allowsSorting: true},
{id: 'cycle', children: 'Cycle', defaultWidth: 120, allowsSorting: true},
{id: 'sunlight', children: 'Sunlight', defaultWidth: 120, allowsSorting: true},
{id: 'watering', children: 'Watering', defaultWidth: 120, allowsSorting: true},
{id: 'actions', children: <VisuallyHidden>Actions</VisuallyHidden>, width: 64, minWidth: 64}
];
interface PlantTableProps {
sortDescriptor: SortDescriptor,
onSortChange: (sortDescriptor: SortDescriptor) => void,
visibleColumns: 'all' | Set<Key>,
items: Plant[],
onFavoriteChange: (id: number, isFavorite: boolean) => void,
onEdit: (item: Plant) => void,
onDelete: (item: Plant) => void
}
export function PlantTable(props: PlantTableProps): React.ReactNode {
let {sortDescriptor, onSortChange, visibleColumns, items, onFavoriteChange, onEdit, onDelete} = props;
let columns = useMemo(() => {
let res = allColumns.filter(c => visibleColumns === 'all' || visibleColumns.has(c.id!));
res[1] = {...res[1], isRowHeader: true};
return res;
}, [visibleColumns]);
return (
<Table
aria-label="My plants"
selectionMode="multiple"
sortDescriptor={sortDescriptor}
onSortChange={onSortChange}
className="h-[320px] hidden md:block">
<TableHeader columns={columns}>
{column => <Column {...column} />}
</TableHeader>
<TableBody
items={items}
dependencies={[columns]}
renderEmptyState={() => 'No results. Try changing the filters.'}>
{item => (
<Row columns={columns}>
{column => {
switch (column.id) {
case 'favorite':
return (
<Cell>
<FavoriteButton isSelected={item.isFavorite} onChange={v => onFavoriteChange(item.id, v)} />
</Cell>
);
case 'common_name':
return (
<Cell textValue={item.common_name}>
<div className="grid grid-cols-[40px_1fr] gap-x-2">
<img alt="" src={item.default_image?.thumbnail} className="inline rounded-sm row-span-2 object-contain h-[40px] w-[40px]" />
<span className="truncate capitalize">{item.common_name}</span>
<span className="truncate text-xs text-gray-600 dark:text-zinc-400">{item.scientific_name}</span>
</div>
</Cell>
);
case 'cycle':
return <Cell><CycleLabel cycle={item.cycle} /></Cell>;
case 'sunlight':
return <Cell><SunLabel sun={getSunlight(item)} /></Cell>;
case 'watering':
return <Cell><WateringLabel watering={item.watering} /></Cell>;
case 'actions':
return (
<Cell>
<PlantActionMenu
item={item}
onFavoriteChange={onFavoriteChange}
onEdit={onEdit}
onDelete={onDelete} />
</Cell>
);
default:
return <></>;
}
} }
</Row>
)}
</TableBody>
</Table>
);
}
const favoriteButtonStyles = tv({
extend: focusRing,
base: 'group cursor-default align-middle rounded-sm border-0 bg-transparent p-0',
variants: {
isSelected: {
false: 'text-gray-500 dark:text-zinc-400 pressed:text-gray-600 dark:pressed:text-zinc-300',
true: 'text-gray-700 dark:text-slate-300 pressed:text-gray-800 dark:pressed:text-slate-200'
}
}
});
function FavoriteButton(props: ToggleButtonProps) {
return (
<ToggleButton aria-label="Favorite" {...props} className={favoriteButtonStyles}>
<StarIcon className="w-5 h-5 fill-white dark:fill-zinc-900 group-selected:fill-current" />
</ToggleButton>
);
}