StackCard.tsx

2.1 KB · raw

1import type { JSX } from "solid-js";2import { CardIcon } from "./CardIcon";3import type { StackCardSpec } from "./types";45interface StackCardProps {6  spec: StackCardSpec;7  active: boolean;8  focused?: boolean;9  concealed?: boolean;10  top: number;11  zIndex: number;12  height: number;13  onClick: () => void;14  onScrollToTop?: () => void;15  children: JSX.Element;16}1718export function StackCard(props: StackCardProps) {19  return (20    <article21      class={`stk-card ${props.active ? "is-active" : "is-tab"} ${props.focused ? "is-focused" : ""} ${props.concealed ? "is-concealed" : ""}`}22      data-settings-card-id={props.spec.id}23      data-active={props.active ? "true" : "false"}24      role={props.active || props.concealed ? undefined : "button"}25      aria-hidden={props.concealed ? "true" : undefined}26      aria-label={props.active || props.concealed ? undefined : `Open ${props.spec.title}`}27      tabIndex={props.active || props.concealed ? -1 : 0}28      onClick={() => {29        if (!props.active && !props.concealed) props.onClick();30      }}31      onKeyDown={(e) => {32        if (props.active) return;33        if (e.key === "Enter" || e.key === " ") {34          e.preventDefault();35          props.onClick();36        }37      }}38      style={{39        background: `var(${props.spec.bgVar})`,40        color: `var(${props.spec.fgVar})`,41        "--stk-card-top": `${props.top}px`,42        transform: `translateY(var(--stk-card-top))`,43        "z-index": props.zIndex,44        height: `${props.height}px`,45      }}46    >47      <div class="stk-card-top">48        <span class="stk-card-num">{props.spec.num}</span>49        <span class="stk-card-icon">50          <CardIcon kind={props.spec.icon} />51        </span>52      </div>53      <h2 class="stk-card-title">{props.spec.title}</h2>54      <p class="stk-card-lede">{props.spec.lede}</p>55      <div56        class="stk-card-body"57        onWheel={(e) => {58          if (!props.onScrollToTop) return;59          if (e.deltaY < 0 && (e.currentTarget as HTMLElement).scrollTop === 0) {60            props.onScrollToTop();61          }62        }}63      >{props.children}</div>64    </article>65  );66}