Files
kjol/web/uikit/Cards.tsx
2026-07-13 09:17:11 -04:00

99 lines
2.9 KiB
TypeScript

import { JSXElement } from "solid-js";
interface CardProps {
class?: string;
children?: JSXElement;
}
// `ui-card` / `no-flex` class names are kept so page-specific CSS (e.g.
// support.css) that targets them can keep overriding. All baseline
// styling is Tailwind.
const CARD_BASE = "ui-card bg-white shadow-sm rounded-default w-full";
const CARD_WITH_PADDING = CARD_BASE + " p-5 flex-1";
const CARD_NO_FLEX = CARD_BASE + " no-flex p-5";
const CARD_NO_PADDING_NO_FLEX = CARD_BASE + " no-padding no-flex";
const BORDER_CARD = "border border-neutral-300 rounded-default p-5 w-full";
// Cut-corner card uses two pseudo-elements with clip-paths to create the
// notched corners. Tailwind supports arbitrary clip-path values.
const CUT_CORNER_CARD =
"relative isolate p-5 w-full " +
"before:content-[''] before:absolute before:inset-0 before:bg-neutral-300 before:-z-20 " +
"before:[clip-path:polygon(16px_0,100%_0,100%_calc(100%_-_16px),calc(100%_-_16px)_100%,0_100%,0_16px)] " +
"after:content-[''] after:absolute after:inset-[1px] after:bg-white after:-z-10 " +
"after:[clip-path:polygon(15px_0,100%_0,100%_calc(100%_-_15px),calc(100%_-_15px)_100%,0_100%,0_15px)]";
export function Card(props: CardProps) {
return (
<div class={CARD_WITH_PADDING + " " + (props.class || "")}>
{props.children}
</div>
);
}
export function CardNoPadding(props: CardProps) {
return (
<div class={CARD_NO_PADDING_NO_FLEX + " " + (props.class || "")}>
{props.children}
</div>
);
}
export function CardNoFlexGrow(props: CardProps) {
return (
<div class={CARD_NO_FLEX + " " + (props.class || "")}>
{props.children}
</div>
);
}
export function BorderCard(props: CardProps) {
return (
<div class={BORDER_CARD + " " + (props.class || "")}>
{props.children}
</div>
);
}
export function BorderCutCornerCard(props: CardProps) {
return (
<div class={CUT_CORNER_CARD + " " + (props.class || "")}>
{props.children}
</div>
);
}
const CARD_HEADER = "text-xl tracking-tight text-black mb-5";
const CARD_HEADER_HR = "text-neutral-200 mt-1 mb-3";
export function CardHeader(props: CardProps) {
return (
<div class={CARD_HEADER + " " + (props.class || "")}>
{props.children}
<hr class={CARD_HEADER_HR}/>
</div>
);
}
export function CardHeaderTextCenter(props: CardProps) {
return (
<div class={CARD_HEADER + " text-center " + (props.class || "")}>
{props.children}
<hr class={CARD_HEADER_HR}/>
</div>
);
}
export function CardSubheader(props: CardProps) {
return (
<div class={"text-lg tracking-tight text-black mb-2 " + (props.class || "")}>
{props.children}
</div>
);
}
export function CardSpacer() {
return <div class="mb-6"></div>;
}