Files
markone/packages/web/src/app/collections/-collection-list.tsx

131 lines
3.6 KiB
TypeScript

import type { Collection } from "@markone/core"
import { Link } from "@tanstack/react-router"
import { clsx } from "clsx"
import { memo, useCallback, useRef } from "react"
import { Button } from "~/components/button"
import { List, type ListRef } from "~/components/list"
import { DialogKind, useCollectionPageStore } from "./-store"
import { useMnemonics } from "~/hooks/use-mnemonics"
export enum CollectionListItemAction {
Delete = "Delete",
Edit = "Edit",
}
interface CollectionListProps {
collections: Collection[]
className?: string
onItemAction: (collection: Collection, action: CollectionListItemAction) => void
}
const CollectionListItem = memo(
({
collection,
isSelected,
isExpanded,
onSelect,
onExpand,
onItemAction,
}: {
collection: Collection
isSelected: boolean
isExpanded: boolean
onSelect: () => void
onExpand: () => void
onItemAction: (collection: Collection, action: CollectionListItemAction) => void
}) => (
<div
className={clsx("group flex flex-row justify-start py-2", {
"bg-teal-600 text-stone-100": isExpanded,
"text-teal-600": isSelected && !isExpanded,
})}
>
<button
type="button"
disabled={!isSelected}
className={clsx("select-none flex items-start font-bold hover:bg-teal-600 hover:text-stone-100", {
invisible: !isSelected,
})}
onClick={onExpand}
>
<span className="sr-only">Options for this collection</span>
<span>&nbsp;</span>
<span className={isExpanded ? "rotate-90" : ""}>&gt;</span>
<span>&nbsp;</span>
</button>
<div className="flex flex-col w-full">
<div className="block w-full text-start font-bold">
<Link to={`/collections/${collection.id}`} className={isSelected ? "underline" : ""}>
{collection.name}
</Link>
</div>
<p className="opacity-80 text-sm">{collection.description}</p>
{isExpanded ? (
<div className="flex flex-col space-y-1 md:flex-row md:space-y-0 md:space-x-2 items-end justify-between pt-2">
<div className="flex space-x-2">
<Button
variant="light"
className="text-sm"
onClick={() => onItemAction(collection, CollectionListItemAction.Edit)}
>
<span className="underline">E</span>DIT
</Button>
<Button
variant="light"
className="text-sm"
onClick={() => onItemAction(collection, CollectionListItemAction.Delete)}
>
<span className="underline">D</span>ELETE
</Button>
<span className="-ml-2">&nbsp;</span>
</div>
</div>
) : null}
</div>
</div>
),
)
function CollectionList({ collections, className, onItemAction }: CollectionListProps) {
const listRef = useRef<ListRef<Collection>>(null)
useMnemonics(
{
e: () => {
const selectedCollection = listRef.current?.selectedItem
if (selectedCollection) {
onItemAction(selectedCollection, CollectionListItemAction.Edit)
}
},
d: () => {
const selectedCollection = listRef.current?.selectedItem
if (selectedCollection) {
onItemAction(selectedCollection, CollectionListItemAction.Delete)
}
},
},
{ ignore: useCallback(() => useCollectionPageStore.getState().dialog.kind !== DialogKind.None, []) },
)
return (
<List
ref={listRef}
className="-mt-2"
items={collections}
emptyMessage="No collections found!"
renderItem={({ item: collection, isSelected, isExpanded, onSelect, onExpand }) => (
<CollectionListItem
collection={collection}
isSelected={isSelected}
isExpanded={isExpanded}
onSelect={onSelect}
onExpand={onExpand}
onItemAction={onItemAction}
/>
)}
/>
)
}
export { CollectionList }