"use client"; import type { ReactNode } from "react"; import HeaderLockup from "../../type/HeaderLockup"; import type { HeaderLockupSizeValue } from "../../type/HeaderLockup/HeaderLockup.types"; import Selection from "../Selection"; import type { CardStackViewProps } from "./CardStack.types"; function CardStackHeaderLockup({ title, description, justification, size, wrapperClassName, }: { title: string; description: ReactNode; justification: "center" | "left"; size: HeaderLockupSizeValue; wrapperClassName?: string; }) { if (!title && !description) { return null; } return (
); } function CardStackAddCardButton({ label, ariaLabel, onClick, }: { label: string; ariaLabel: string; onClick: () => void; }) { return ( ); } export function CardStackView({ cards, selectedIds, onCardSelect, expanded, onToggleExpand, hasMore, toggleLabel, showLessLabel, title, description, layout, compactRecommendedLimit, compactCardIds, compactDesktopLayout, headerLockupSize, toggleAlignment, className, showAddCard, addCardLabel, addCardAriaLabel, onAddCard, }: CardStackViewProps) { const addTile = showAddCard && onAddCard && addCardLabel.length > 0 ? ( ) : null; const lockupSize = headerLockupSize ?? "L"; const isSelected = (id: string) => selectedIds.includes(id); // Compact: explicit `compactCardIds` (caller-driven, used by create-flow // facet ranker) takes precedence over the legacy `recommended`-filter so // the screen can show un-tagged cards in the compact slot when there is // no facet signal yet (CR-88 §10). const compactCards = (() => { if (compactCardIds && compactCardIds.length > 0) { const byId = new Map(cards.map((c) => [c.id, c])); return compactCardIds .map((id) => byId.get(id)) .filter((c): c is (typeof cards)[number] => c !== undefined) .slice(0, compactRecommendedLimit); } return cards .filter((c) => c.recommended ?? false) .slice(0, compactRecommendedLimit); })(); // Single stack: always one column; expand reveals more in same stack (scrollable) if (layout === "singleStack") { const displayedCards = expanded ? cards : compactCards; return (
{displayedCards.map((item) => ( onCardSelect(item.id)} /> ))} {addTile}
{hasMore ? ( ) : null}
); } return (
{expanded ? (
{cards.map((item) => ( onCardSelect(item.id)} /> ))} {addTile ? (
{addTile}
) : null}
) : compactDesktopLayout === "pyramidFive" ? ( <>
{compactCards.map((item) => ( onCardSelect(item.id)} /> ))} {addTile}
{/* lg+: fixed 3 + 2 rows (no flex-wrap on the top row — avoids 2+1+2 when the first row wraps). md–lg: same shell as the 3-card step — each row is `flex justify-center gap-2` so cards stay a tight cluster with gap-2 until lg expands to the 3+2 pyramid. */}
{compactCards.slice(0, 3).map((item) => ( onCardSelect(item.id)} /> ))}
{compactCards.length > 3 ? (
{compactCards .slice(3, compactRecommendedLimit) .map((item) => ( onCardSelect(item.id)} /> ))}
) : null}
{compactCards.slice(0, 2).map((item) => ( onCardSelect(item.id)} /> ))}
{compactCards.slice(2, 4).map((item) => ( onCardSelect(item.id)} /> ))}
{compactCards[4] ? (
onCardSelect(compactCards[4].id)} />
) : null}
{addTile ? (
{addTile}
) : null} ) : compactDesktopLayout === "flexWrap" ? ( <>
{compactCards.map((item) => ( onCardSelect(item.id)} /> ))} {addTile}
{/* md–lg: pyramid (2 + 1), each row centered; lg+: one centered row (not edge-to-edge in a 2-col grid) */} {compactCards.length === 3 ? ( <>
{compactCards.slice(0, 2).map((item) => ( onCardSelect(item.id)} /> ))}
onCardSelect(compactCards[2].id)} />
{addTile ? (
{addTile}
) : null}
{compactCards.map((item) => ( onCardSelect(item.id)} /> ))}
{addTile ? (
{addTile}
) : null} ) : (
{compactCards.map((item) => (
onCardSelect(item.id)} />
))} {addTile ? (
{addTile}
) : null}
)} ) : ( <> {/* Compact under 640: single column, up to 5 recommended cards */}
{compactCards.map((item) => ( onCardSelect(item.id)} /> ))} {addTile}
{/* Compact 640+: 6-col grid so each card spans 2; second row centered (cols 2–3 and 4–5) */}
{compactCards.map((item, index) => { const colClass = index <= 2 ? "md:col-span-2" : index === 3 && compactCards.length === 4 ? "md:col-start-3 md:col-span-2" : index === 3 ? "md:col-start-2 md:col-span-2" : "md:col-start-4 md:col-span-2"; return (
onCardSelect(item.id)} />
); })} {addTile ? (
{addTile}
) : null}
)} {hasMore ? ( ) : null}
); }