/// import { Cell, computed, Default, ifElse, lift, NAME, navigateTo, pattern, UI, } from "commontools"; import ReadingItemDetail, { type ItemStatus, type ItemType, type ReadingItem, } from "./reading-item-detail.tsx"; interface Input { items: Cell>; } interface Output { items: ReadingItem[]; } const typeEmoji: Record = { book: "📚", article: "📄", paper: "📑", video: "🎬", }; const filterByStatus = lift( ( args: { items: ReadingItem[]; status: ItemStatus | "all" }, ): ReadingItem[] => { const { items, status } = args; if (!Array.isArray(items)) return []; if (status === "all") return items; return items.filter((item) => item.status === status); }, ); const renderStars = lift((rating: number | null): string => { if (!rating) return ""; return "★".repeat(rating) + "☆".repeat(5 - rating); }); export default pattern(({ items }) => { const filterStatus = Cell.of("all"); const newTitle = Cell.of(""); const newAuthor = Cell.of(""); const newType = Cell.of("article"); const totalCount = computed(() => items.get().length); const filteredItems = filterByStatus({ items, status: filterStatus }); const filteredCount = lift((arr: ReadingItem[]) => arr.length)(filteredItems); return { [NAME]: "Reading List", [UI]: ( Reading List ({totalCount}) All Want Reading Done Dropped {filteredItems.map((item) => ( { const detail = ReadingItemDetail({ item }); return navigateTo(detail); }} > {lift((t: ItemType) => typeEmoji[t] || "📄")(item.type)} {item.title || "(untitled)"} {item.author && ( by {item.author} )} {item.status} {item.rating && ( {renderStars(item.rating)} )} { const current = items.get(); const idx = current.findIndex((i) => Cell.equals(item, i) ); if (idx >= 0) { items.set(current.toSpliced(idx, 1)); } }} > × ))} {ifElse( lift((count: number) => count === 0)(filteredCount),
No items yet. Add something to read!
, null, )}
{ const title = newTitle.get().trim(); if (title) { items.push({ title, author: newAuthor.get().trim(), url: "", type: newType.get(), status: "want", rating: null, notes: "", addedAt: Date.now(), finishedAt: null, }); newTitle.set(""); newAuthor.set(""); } }} > Add
), items, }; });