/** * `` — one level of the catalogue as a list of links. * * The four arms of `LoadList` are the point of this file, not decoration: * "still syncing", "the sync failed", "this category has no sub-categories" * and "here they are" are four different sentences, and the third is the one a * leaf category legitimately gets. Collapsing any two is the incident * `@stapel/core`'s `loadState.ts` was written for; the substrate renders the * first three so every pair's version of them is the same shape. * * A fifth condition rides alongside them: `truncated`. The sync walk hit its * page budget, so what is on screen is a PARTIAL catalogue — which is neither * an empty one nor a failed one, and gets its own line rather than being * silently indistinguishable from a complete tree. * * The rows themselves are ``, shared with the id path of * `` — this pane owns the CATALOGUE resolution (a slug has no * server-side lookup, so it costs the sync) and the four load sentences * around it, not the row markup. See that file's header for why the split * exists. */ import { spacing } from "@stapel/tokens"; import type { ReactElement } from "react"; import { Alert, Flex, Typography } from "antd"; import { useT } from "@stapel/core"; import { CategoryTree } from "../headless/CategoryTree.js"; import { CATEGORIES_I18N_KEYS } from "../i18n/keys.js"; import { CategoryLevelList } from "./CategoryLevelList.js"; import type { LinkComponentProp } from "./CategoryLink.js"; import { EmptyState, ErrorAlert, LoadList, SkinTheme, } from "@stapel/tokens-antd/skin"; import type { ThemeModeProp } from "./types.js"; export interface CategoryTreePaneProps extends ThemeModeProp, LinkComponentProp { /** Render this category's children. Omitted renders the roots. */ readonly parentId?: number | null; /** Render the children of the category at this slug (the `/c/:slug` page). */ readonly slug?: string; /** Path prefix for a row's link. Default `/c`. */ readonly basePath?: string; /** Heading above the list. Omitted renders no heading. */ readonly titleKey?: string; } export function CategoryTreePane(props: CategoryTreePaneProps): ReactElement { const t = useT(); const base = props.basePath ?? "/c"; return ( {(bag) => ( {props.titleKey !== undefined ? ( {t(props.titleKey)} ) : null} {bag.truncated ? ( ) : null} ( )} empty={ } > {(nodes) => ( node.category)} // The built tree already knows every level, so a count // here is never unknown — `0` is a true leaf, not a guess. childCount={(row) => nodes.find((node) => node.id === row.id)?.children .length ?? 0 } basePath={base} /> )} )} ); }