1import { createMemo, createSignal, For, Show } from "solid-js";2import { StackCard } from "./StackCard";3import type { CardId, StackBodies, StackCardSpec } from "./types";45interface StackDeckProps {6 active: CardId;7 onActiveChange: (id: CardId) => void;8 onBack: () => void;9 cards: readonly StackCardSpec[];10 bodies: StackBodies;11}1213const EXPANDED_H = 248;14const FOCUS_H = 420;15const TAB_H = 46;16const TAB_OVERLAP = 14;1718export function StackDeck(props: StackDeckProps) {19 const [deckOpen, setDeckOpen] = createSignal(true);20 const activeIndex = createMemo(() => {21 const idx = props.cards.findIndex((card) => card.id === props.active);22 return idx >= 0 ? idx : 0;23 });2425 return (26 <section class="stk-shell" aria-label="Settings">27 <div class="stk-mast">28 <button29 class="stk-back"30 onClick={props.onBack}31 aria-label="Back"32 type="button"33 >34 <svg width="7" height="12" viewBox="0 0 7 12" fill="none" stroke="currentColor" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round">35 <path d="M6 1L1 6L6 11" />36 </svg>37 </button>38 <div class="stk-mast-title">Settings</div>39 <div class="stk-mast-meta">40 {activeIndex() + 1} / {props.cards.length}41 </div>42 </div>4344 <div class={`stk-deck ${deckOpen() ? "is-open" : "is-focused"}`}>45 <For each={props.cards}>46 {(card, index) => {47 const active = () => card.id === props.active;48 const concealed = () => !deckOpen() && !active();49 const distance = createMemo(() => {50 const ai = activeIndex();51 const ci = index();52 if (ci === ai) return -1;53 if (ci > ai) return ci - ai - 1;54 return props.cards.length - ai + ci - 1;55 });56 const top = () => {57 if (active()) return 0;58 if (!deckOpen()) return FOCUS_H + 44 + distance() * 8;59 return EXPANDED_H + distance() * (TAB_H - TAB_OVERLAP);60 };61 const zIndex = () => (active() ? 99 : 50 - distance());6263 return (64 <StackCard65 spec={card}66 active={active()}67 focused={!deckOpen() && active()}68 concealed={concealed()}69 top={top()}70 zIndex={zIndex()}71 height={active() ? (deckOpen() ? EXPANDED_H : FOCUS_H) : TAB_H + 4}72 onClick={() => {73 if (active()) return;74 props.onActiveChange(card.id);75 setDeckOpen(false);76 }}77 >78 {props.bodies[card.id]}79 </StackCard>80 );81 }}82 </For>83 <Show when={!deckOpen()}>84 <button85 class="stk-tray-handle"86 type="button"87 aria-label="Show settings sections"88 onClick={() => setDeckOpen(true)}89 >90 <span>sections</span>91 </button>92 </Show>93 </div>94 </section>95 );96}