Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Svelte
at icy/tmrrpn
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576<script module lang="ts"> import { tv, type VariantProps } from "tailwind-variants";
// the numbered rail from Figma node 191:6514 — same shape as the appview's // onboarding/fragments/steps, restyled onto the design-system tokens. export const steps = tv({ slots: { root: "flex w-full items-center gap-2", item: "flex shrink-0 items-center gap-2", marker: "flex size-5 shrink-0 items-center justify-center rounded-full typography-paragraph-small", // labels are desktop-only, but sr-only rather than hidden so the rail still // reads as a named list of steps on a narrow screen label: "sr-only typography-paragraph-small whitespace-nowrap sm:not-sr-only", connector: "h-px min-w-4 flex-1 bg-border-default" }, variants: { state: { done: { marker: "bg-background-inset text-foreground-default", label: "text-foreground-subtle" }, current: { marker: "bg-background-muted text-foreground-default", label: "text-foreground-default" }, upcoming: { marker: "bg-background-inset text-foreground-subtle", label: "text-foreground-subtle" } } }, defaultVariants: { state: "upcoming" } });
export type StepsVariants = VariantProps<typeof steps>; export type StepState = NonNullable<StepsVariants["state"]>;</script>
<script lang="ts"> import Check from "$icon/check";
interface Props { items: readonly { key: string; label: string }[]; current: number; }
let { items, current }: Props = $props();
const shell = steps();
const stateOf = (index: number): StepState => index < current ? "done" : index === current ? "current" : "upcoming";</script>
<ol class={shell.root()}> {#each items as item, index (item.key)} {#if index > 0} <li aria-hidden="true" class={shell.connector()}></li> {/if} {@const state = stateOf(index)} {@const slot = steps({ state })} <li class={slot.item()} aria-current={state === "current" ? "step" : undefined}> <span class={slot.marker()} aria-label={state === "done" ? "done" : undefined}> {#if state === "done"} <Check class="size-3.5" aria-hidden="true" /> {:else} {index + 1} {/if} </span> <span class={slot.label()}>{item.label}</span> </li> {/each}</ol>