Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Svelte
at icy/tmrrpn
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106<script module lang="ts"> import { tv, type VariantProps } from "tailwind-variants";
export const welcomeCard = tv({ slots: { root: "overflow-hidden rounded-sm border border-border-default bg-background-default shadow-xs", header: "overflow-x-auto border-b border-border-default px-6 py-5", body: "grid overflow-hidden p-6", pane: "col-start-1 row-start-1 min-w-0", footer: "flex items-center justify-between gap-4 border-t border-border-default px-6 py-4" } });
export type WelcomeCardVariants = VariantProps<typeof welcomeCard>;</script>
<script lang="ts"> import type { Snippet } from "svelte"; import { untrack } from "svelte"; import { cubicIn, cubicOut } from "svelte/easing"; import { prefersReducedMotion } from "svelte/motion"; import { fly } from "svelte/transition"; import ArrowLeft from "$icon/arrow-left"; import ArrowRight from "$icon/arrow-right"; import Check from "$icon/check"; import Button from "$lib/components/ui/Button.svelte"; import Steps from "./Steps.svelte"; import { WELCOME_STEPS, LAST_STEP } from "./steps";
interface Props { step: number; /** +1 when advancing, -1 when going back — decides which way the pane slides */ direction: number; /** the appview greens Next once the step has something worth saving */ nextReady?: boolean; nextLoading?: boolean; onBack: () => void; onNext: () => void; /** rendered per step index, frozen at pane creation so the outgoing pane keeps its own content */ children: Snippet<[number]>; }
let { step, direction, nextReady = false, nextLoading = false, onBack, onNext, children }: Props = $props();
const slot = welcomeCard();
const DISTANCE = 40; const enter = $derived( prefersReducedMotion.current ? { duration: 0 } : { x: direction * DISTANCE, duration: 240, delay: 90, easing: cubicOut } ); const leave = $derived( prefersReducedMotion.current ? { duration: 0 } : { x: direction * -DISTANCE, duration: 150, easing: cubicIn } );
const isLast = $derived(step === LAST_STEP);</script>
<div class={slot.root()}> <div class={slot.header()}> <Steps items={WELCOME_STEPS} current={step} /> </div>
<div class={slot.body()}> {#key step} <!-- untrack freezes the index at creation: `children` is a live snippet, so without this the leaving pane would re-render with the new step's content halfway through its own exit transition --> {@const frozen = untrack(() => step)} <div class={slot.pane()} in:fly={enter} out:fly={leave}> {@render children(frozen)} </div> {/key} </div>
<div class={slot.footer()}> {#if step > 0} <Button variant="ghost" icon={ArrowLeft} onclick={onBack}>Back</Button> {:else} <span></span> {/if}
<Button variant={nextReady ? "primary" : "default"} icon={isLast ? Check : ArrowRight} loading={nextLoading} disabled={nextLoading} iconSide={isLast ? "left" : "right"} onclick={onNext} > {isLast ? "Finish" : "Next"} </Button> </div></div>