component Timeline { outputs { select(payload: { sourceEvent?: Event; [key: string]: string | number | boolean | null | object }) } props { size: string = "default" color: string = "primary" title: string = "Timeline" description: string = "" items: unknown[] = [] variant: string = "default" numbered: boolean = false class: string = "" } functions { // Explicit status wins; otherwise the item flagged current is "current" // and everything after it is "upcoming". shared function statusOf(item, index, currentIndex) { if (item.status) { return item.status } if (item.current) { return "current" } currentIndex = -1 for (var position = 0; position < items.length; position++) { if (currentIndex < 0 && items[position] && items[position].current) { currentIndex = position } } if (currentIndex >= 0 && index > currentIndex) { return "upcoming" } return "default" } } view {
{#if title || description}
{#if title}

{title}

{/if} {#if description}

{description}

{/if}
{/if}
    {#each items as item, index}
  1. {#if numbered} {:else} {/if}
    {#if title}

    {item.title || item.label}

    {:else}

    {item.title || item.label}

    {/if} {#if item.subtitle}

    {item.subtitle}

    {/if}
    {#if item.date || item.time || item.meta} {/if}
    {#if item.description}

    {item.description}

    {/if} {#if item.href} {item.actionLabel || "View details"} {/if}
  2. {:empty}
  3. No timeline items available.
  4. {/each}
} style { .wrn-timeline { --wrn-timeline-accent: var(--wrn-color-primary); width: 100%; min-width: 0; color: var(--wrn-color-text); } .wrn-timeline[data-color="success"] { --wrn-timeline-accent: var(--wrn-color-success); } .wrn-timeline[data-color="info"] { --wrn-timeline-accent: var(--wrn-color-info); } .wrn-timeline__header { margin-bottom: 1.5rem; } .wrn-timeline__title { color: var(--wrn-color-text); font-size: 1.25rem; font-weight: 650; letter-spacing: -0.02em; } .wrn-timeline__description { max-width: 42rem; margin-top: 0.5rem; color: var(--wrn-color-text-muted); line-height: 1.75rem; } .wrn-timeline__list { position: relative; display: grid; gap: 1rem; margin: 0; padding: 0 0 0 3rem; list-style: none; } .wrn-timeline__list::before { position: absolute; inset-block: 1rem; inset-inline-start: 0.9375rem; width: 2px; border-radius: 999px; background: var(--wrn-color-border); content: ""; } .wrn-timeline__item { position: relative; min-width: 0; } .wrn-timeline__item:last-child { padding-bottom: 0; } .wrn-timeline__marker { position: absolute; z-index: 1; top: 1.125rem; inset-inline-start: -3rem; display: flex; width: 2rem; height: 2rem; align-items: center; justify-content: center; border: 3px solid var(--wrn-color-bg); border-radius: 50%; color: var(--wrn-color-on-primary); background: var(--wrn-timeline-accent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--wrn-timeline-accent) 40%, var(--wrn-color-border)), var(--wrn-highlight-edge, none); } .wrn-timeline__marker:is([data-status="complete"], [data-status="success"]) { background: var(--wrn-color-success); } .wrn-timeline__marker:is([data-status="warning"], [data-status="pending"]) { background: var(--wrn-color-warning); } .wrn-timeline__marker:is([data-status="danger"], [data-status="failed"]) { background: var(--wrn-color-danger); } .wrn-timeline__number { font-family: var(--wrn-font-mono, monospace); font-size: 0.72rem; font-weight: 650; } .wrn-timeline__card { min-width: 0; padding: 1.125rem 1.25rem; border: 1px solid var(--wrn-color-border); border-radius: var(--wrn-radius); background: var(--wrn-color-surface-raised); box-shadow: var(--wrn-shadow-1); transition: border-color 160ms ease, transform 160ms ease, box-shadow 160ms ease; } .wrn-timeline__item[data-interactive="true"] { cursor: pointer; } .wrn-timeline__item[data-interactive="true"]:hover .wrn-timeline__card { border-color: var(--wrn-color-border-strong, var(--wrn-color-border)); transform: translateY(-1px); box-shadow: var(--wrn-shadow-2); } .wrn-timeline__card[data-variant="minimal"] { padding: 0; border-color: transparent; background: transparent; box-shadow: none; } .wrn-timeline__card-header { display: flex; flex-direction: column; gap: 0.5rem; } .wrn-timeline__item-title { color: var(--wrn-color-text); font-weight: 620; letter-spacing: -0.01em; } .wrn-timeline__subtitle { margin-top: 0.125rem; color: var(--wrn-color-primary-text, var(--wrn-color-primary)); font-size: 0.8125rem; font-weight: 550; } .wrn-timeline__time { flex: none; color: var(--wrn-color-text-subtle, var(--wrn-color-text-muted)); font-family: var(--wrn-font-mono, monospace); font-size: 0.72rem; font-variant-numeric: tabular-nums; } .wrn-timeline__copy { margin-top: 0.75rem; color: var(--wrn-color-text-muted); font-size: 0.875rem; line-height: 1.5rem; } .wrn-timeline__action { display: inline-flex; align-items: center; gap: 0.375rem; margin-top: 0.875rem; color: var(--wrn-color-primary-text, var(--wrn-color-primary)); font-size: 0.8125rem; font-weight: 600; } .wrn-timeline__action:hover { color: var(--wrn-color-primary-hover); } .wrn-timeline__action-icon { width: 1rem; height: 1rem; } .wrn-timeline__empty { padding-left: 2rem; color: var(--wrn-color-text-muted); font-size: 0.875rem; } @media (min-width: 40rem) { .wrn-timeline__card-header { flex-direction: row; align-items: flex-start; justify-content: space-between; } } @media (max-width: 39.99rem) { .wrn-timeline__list { padding-inline-start: 2.5rem; } .wrn-timeline__list::before { inset-inline-start: 0.75rem; } .wrn-timeline__marker { inset-inline-start: -2.5rem; } .wrn-timeline__card { padding: 1rem; } } /* --- Status: current rings and pulses, upcoming goes hollow ------------ */ .wrn-timeline__marker[data-status="current"] { box-shadow: 0 0 0 1px var(--wrn-timeline-accent), 0 0 0 5px color-mix(in srgb, var(--wrn-timeline-accent) 20%, transparent); animation: wrn-timeline-pulse 2.2s ease-in-out infinite; } .wrn-timeline__marker[data-status="upcoming"] { color: var(--wrn-color-text-subtle, var(--wrn-color-text-muted)); background: var(--wrn-color-surface); box-shadow: inset 0 0 0 1.5px var(--wrn-color-border-strong, var(--wrn-color-border)); } .wrn-timeline__item[data-status="current"] .wrn-timeline__card { border-color: color-mix(in srgb, var(--wrn-timeline-accent) 45%, var(--wrn-color-border)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--wrn-timeline-accent) 10%, transparent), var(--wrn-shadow-1); } .wrn-timeline__item[data-status="upcoming"] .wrn-timeline__card { opacity: 0.72; } .wrn-timeline__item[data-status="upcoming"] .wrn-timeline__item-title { color: var(--wrn-color-text-muted); } @keyframes wrn-timeline-pulse { 50% { box-shadow: 0 0 0 1px var(--wrn-timeline-accent), 0 0 0 8px color-mix(in srgb, var(--wrn-timeline-accent) 6%, transparent); } } /* --- Card variants ----------------------------------------------------- */ .wrn-timeline[data-variant="soft"] .wrn-timeline__card { border-color: transparent; background: color-mix(in srgb, var(--wrn-timeline-accent) 5%, var(--wrn-color-surface-soft, var(--wrn-color-surface))); box-shadow: none; } .wrn-timeline[data-variant="raised"] .wrn-timeline__card { border-color: var(--wrn-color-border); box-shadow: var(--wrn-highlight-edge, none), var(--wrn-shadow-2); } .wrn-timeline[data-variant="outline"] .wrn-timeline__card { background: transparent; border-style: dashed; box-shadow: none; } /* Compact: a dense dot rail with the time inline, for drawers and panels. */ .wrn-timeline[data-variant="compact"] .wrn-timeline__list { gap: 0; padding-inline-start: 1.75rem; } .wrn-timeline[data-variant="compact"] .wrn-timeline__list::before { inset-block: 0.5rem; inset-inline-start: 0.4375rem; width: 1px; } .wrn-timeline[data-variant="compact"] .wrn-timeline__marker { top: 0.625rem; inset-inline-start: -1.75rem; width: 0.875rem; height: 0.875rem; border-width: 2px; box-shadow: 0 0 0 1px color-mix(in srgb, var(--wrn-timeline-accent) 40%, var(--wrn-color-border)); } .wrn-timeline[data-variant="compact"] .wrn-timeline__marker > * { display: none; } .wrn-timeline[data-variant="compact"] .wrn-timeline__card { padding: 0.4rem 0 0.9rem; border: 0; border-radius: 0; background: transparent; box-shadow: none; } .wrn-timeline[data-variant="compact"] .wrn-timeline__card-header { flex-direction: row; align-items: baseline; justify-content: space-between; } .wrn-timeline[data-variant="compact"] .wrn-timeline__item-title { font-size: 0.875rem; font-weight: 550; } .wrn-timeline[data-variant="compact"] .wrn-timeline__copy { margin-top: 0.125rem; font-size: 0.8125rem; } /* Alternate: a centred spine with cards alternating sides once the timeline itself is wide enough (container query, not viewport). */ .wrn-timeline[data-variant="alternate"] { container: wrn-timeline / inline-size; } @container wrn-timeline (min-width: 40rem) { .wrn-timeline[data-variant="alternate"] .wrn-timeline__list { padding-inline-start: 0; gap: 1.5rem; } .wrn-timeline[data-variant="alternate"] .wrn-timeline__list::before { inset-inline-start: calc(50% - 1px); } .wrn-timeline[data-variant="alternate"] .wrn-timeline__item { width: calc(50% - 2rem); } .wrn-timeline[data-variant="alternate"] .wrn-timeline__item:nth-of-type(even) { margin-inline-start: auto; } .wrn-timeline[data-variant="alternate"] .wrn-timeline__item:nth-of-type(odd) .wrn-timeline__marker { inset-inline-start: auto; inset-inline-end: -3rem; } .wrn-timeline[data-variant="alternate"] .wrn-timeline__item:nth-of-type(even) .wrn-timeline__marker { inset-inline-start: -3rem; } .wrn-timeline[data-variant="alternate"] .wrn-timeline__item:nth-of-type(odd) .wrn-timeline__card { text-align: end; } .wrn-timeline[data-variant="alternate"] .wrn-timeline__item:nth-of-type(odd) .wrn-timeline__card-header { flex-direction: row-reverse; } } /* --- Sizes --------------------------------------------------------------- */ .wrn-timeline[data-size="sm"] .wrn-timeline__title { font-size: 1rem; } .wrn-timeline[data-size="sm"] .wrn-timeline__card { padding: 0.75rem 0.875rem; } .wrn-timeline[data-size="sm"] .wrn-timeline__item-title { font-size: 0.875rem; } .wrn-timeline[data-size="sm"] .wrn-timeline__list { gap: 0.625rem; } .wrn-timeline[data-size="lg"] .wrn-timeline__title { font-size: 1.5rem; } .wrn-timeline[data-size="lg"] .wrn-timeline__card { padding: 1.375rem 1.5rem; } .wrn-timeline[data-size="lg"] .wrn-timeline__item-title { font-size: 1.0625rem; } .wrn-timeline[data-size="lg"] .wrn-timeline__list { gap: 1.25rem; } @media (prefers-reduced-motion: reduce) { .wrn-timeline__marker[data-status="current"] { animation: none; } } } }