67 lines
2.6 KiB
TypeScript
67 lines
2.6 KiB
TypeScript
import { cn } from "@/lib/utils";
|
||
|
||
export interface MarginaliaItem {
|
||
/** Optional mono label, e.g. „Praxis“ → „Praxis: B2B-Außendienst“. */
|
||
label?: string;
|
||
value: string;
|
||
href?: string;
|
||
/** `target="_blank"` + ↗ */
|
||
external?: boolean;
|
||
}
|
||
|
||
export interface MarginaliaProps {
|
||
items: readonly MarginaliaItem[];
|
||
/** Optional caps heading above the list, e.g. „Was du bekommst“. */
|
||
title?: string;
|
||
/** `lg:sticky lg:top-[30vh]` */
|
||
sticky?: boolean;
|
||
className?: string;
|
||
}
|
||
|
||
/** Shared mono meta style (DM Mono 12 px, ls .06em, tabular). */
|
||
export const MONO = "font-mono text-xs tracking-[0.06em] tabular-nums";
|
||
|
||
/**
|
||
* Verifiable facts in the outer column: DM Mono 12 px, muted, one gold tick
|
||
* per line. Links get the growing accent underline; external ones ↗.
|
||
*/
|
||
export function Marginalia({ items, title, sticky = false, className }: MarginaliaProps) {
|
||
return (
|
||
<aside className={cn(MONO, "text-fg-muted", sticky && "lg:sticky lg:top-[30vh]", className)}>
|
||
{title && <p className="mb-4 uppercase tracking-[0.12em] text-accent">{title}</p>}
|
||
<ul className="flex flex-col gap-3">
|
||
{items.map((item, i) => {
|
||
const text = item.label ? `${item.label}: ${item.value}` : item.value;
|
||
return (
|
||
<li key={`${item.value}-${i}`} className="flex items-start gap-3">
|
||
<span aria-hidden="true" className="mt-[0.55em] h-px w-6 shrink-0 bg-accent" />
|
||
{item.href ? (
|
||
<a
|
||
href={item.href}
|
||
target={item.external ? "_blank" : undefined}
|
||
rel={item.external ? "noopener noreferrer" : undefined}
|
||
/* Tap target via ::before – padding + negative margin on the flex child
|
||
collapsed the <li> box and broke the 12 px tick rhythm of the list. */
|
||
className="relative inline-block text-fg before:absolute before:inset-x-0 before:-inset-y-3 before:content-[''] bg-[linear-gradient(currentColor,currentColor)] bg-[length:0%_1px] bg-left-bottom bg-no-repeat pb-px transition-[background-size] duration-[400ms] ease-[var(--ease-out-quart)] hover:bg-[length:100%_1px] focus-visible:bg-[length:100%_1px]"
|
||
>
|
||
{text}
|
||
{item.external && (
|
||
<>
|
||
{" "}
|
||
<span aria-hidden="true">↗</span>
|
||
</>
|
||
)}
|
||
</a>
|
||
) : (
|
||
<span>{text}</span>
|
||
)}
|
||
</li>
|
||
);
|
||
})}
|
||
</ul>
|
||
</aside>
|
||
);
|
||
}
|
||
|
||
export default Marginalia;
|