Add custom intervention modals

This commit is contained in:
adilallo
2026-05-01 22:05:05 -06:00
parent 58d0e33500
commit dee2dd800e
67 changed files with 3480 additions and 197 deletions
+121 -20
View File
@@ -1,9 +1,77 @@
"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 (
<div className={wrapperClassName ?? "min-w-0"}>
<HeaderLockup
title={title}
description={description}
justification={justification}
size={size}
/>
</div>
);
}
function CardStackAddCardButton({
label,
ariaLabel,
onClick,
}: {
label: string;
ariaLabel: string;
onClick: () => void;
}) {
return (
<button
type="button"
onClick={onClick}
aria-label={ariaLabel}
className="flex min-h-[88px] w-full shrink-0 items-center justify-center rounded-[var(--measures-radius-medium,8px)] bg-[var(--color-surface-default-secondary)] font-inter text-base font-medium text-[var(--color-content-default-primary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)]"
>
<span className="flex items-center gap-2">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden
>
<path
d="M12 5v14M5 12h14"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
/>
</svg>
{label}
</span>
</button>
);
}
export function CardStackView({
cards,
selectedIds,
@@ -22,7 +90,19 @@ export function CardStackView({
headerLockupSize,
toggleAlignment,
className,
showAddCard,
addCardLabel,
addCardAriaLabel,
onAddCard,
}: CardStackViewProps) {
const addTile =
showAddCard && onAddCard && addCardLabel.length > 0 ? (
<CardStackAddCardButton
label={addCardLabel}
ariaLabel={addCardAriaLabel || addCardLabel}
onClick={onAddCard}
/>
) : null;
const lockupSize = headerLockupSize ?? "L";
const isSelected = (id: string) => selectedIds.includes(id);
// Compact: explicit `compactCardIds` (caller-driven, used by create-flow
@@ -47,16 +127,13 @@ export function CardStackView({
const displayedCards = expanded ? cards : compactCards;
return (
<div className={`flex w-full flex-col gap-6 min-w-0 ${className}`}>
{title || description ? (
<div className="min-w-0 shrink-0">
<HeaderLockup
title={title}
description={description}
justification="center"
size={lockupSize}
/>
</div>
) : null}
<CardStackHeaderLockup
title={title}
description={description}
justification="center"
size={lockupSize}
wrapperClassName="min-w-0 shrink-0"
/>
<div className="flex w-full min-w-0 flex-col gap-2">
{displayedCards.map((item) => (
<Selection
@@ -71,6 +148,7 @@ export function CardStackView({
onClick={() => onCardSelect(item.id)}
/>
))}
{addTile}
</div>
{hasMore ? (
<button
@@ -89,16 +167,12 @@ export function CardStackView({
return (
<div className={`flex w-full flex-col gap-6 min-w-0 ${className}`}>
{title || description ? (
<div className="min-w-0">
<HeaderLockup
title={title}
description={description}
justification="center"
size={lockupSize}
/>
</div>
) : null}
<CardStackHeaderLockup
title={title}
description={description}
justification="center"
size={lockupSize}
/>
{expanded ? (
<div className="mx-auto grid w-full max-w-[min(100%,860px)] grid-cols-1 gap-x-4 gap-y-6 md:grid-cols-2">
@@ -115,6 +189,9 @@ export function CardStackView({
onClick={() => onCardSelect(item.id)}
/>
))}
{addTile ? (
<div className="min-w-0 md:col-span-2">{addTile}</div>
) : null}
</div>
) : compactDesktopLayout === "pyramidFive" ? (
<>
@@ -133,6 +210,7 @@ export function CardStackView({
onClick={() => onCardSelect(item.id)}
/>
))}
{addTile}
</div>
<div className="mx-auto hidden w-full max-w-[min(100%,860px)] md:block">
{/*
@@ -228,6 +306,11 @@ export function CardStackView({
) : null}
</div>
</div>
{addTile ? (
<div className="mx-auto hidden w-full max-w-[min(100%,860px)] md:block">
{addTile}
</div>
) : null}
</>
) : compactDesktopLayout === "flexWrap" ? (
<>
@@ -246,6 +329,7 @@ export function CardStackView({
onClick={() => onCardSelect(item.id)}
/>
))}
{addTile}
</div>
{/* mdlg: pyramid (2 + 1), each row centered; lg+: one centered row (not edge-to-edge in a 2-col grid) */}
{compactCards.length === 3 ? (
@@ -280,6 +364,9 @@ export function CardStackView({
onClick={() => onCardSelect(compactCards[2].id)}
/>
</div>
{addTile ? (
<div className="flex w-full justify-center px-2">{addTile}</div>
) : null}
</div>
<div className="mx-auto hidden w-full max-w-[min(100%,860px)] flex-wrap justify-center gap-2 lg:flex">
{compactCards.map((item) => (
@@ -297,6 +384,11 @@ export function CardStackView({
/>
))}
</div>
{addTile ? (
<div className="mx-auto hidden w-full max-w-[min(100%,860px)] lg:flex lg:justify-center">
<div className="w-full min-w-[281px] max-w-[574px]">{addTile}</div>
</div>
) : null}
</>
) : (
<div className="mx-auto hidden w-full max-w-[min(100%,860px)] flex-wrap justify-center gap-2 md:flex">
@@ -318,6 +410,11 @@ export function CardStackView({
/>
</div>
))}
{addTile ? (
<div className="flex w-full min-w-0 shrink-0 justify-center md:w-[281px] md:max-w-[574px] md:flex-[1_1_100%]">
{addTile}
</div>
) : null}
</div>
)}
</>
@@ -338,6 +435,7 @@ export function CardStackView({
onClick={() => onCardSelect(item.id)}
/>
))}
{addTile}
</div>
{/* Compact 640+: 6-col grid so each card spans 2; second row centered (cols 23 and 45) */}
<div className="hidden md:grid grid-cols-6 gap-x-4 gap-y-6 w-full">
@@ -365,6 +463,9 @@ export function CardStackView({
</div>
);
})}
{addTile ? (
<div className="col-span-6 min-w-0">{addTile}</div>
) : null}
</div>
</>
)}