Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775<script lang="ts"> import type { Snippet } from "svelte"; import { resolve } from "$app/paths"; import ArrowRight from "$icon/arrow-right"; import BookMarked from "$icon/book-marked"; import ChevronDown from "$icon/chevron-down"; import CircleCheck from "$icon/circle-check"; import GitFork from "$icon/git-fork"; import GitMerge from "$icon/git-merge"; import Hash from "$icon/hash"; import Inbox from "$icon/inbox"; import LogOut from "$icon/log-out"; import Pencil from "$icon/pencil"; import Plus from "$icon/plus"; import Rss from "$icon/rss"; import Search from "$icon/search"; import Settings from "$icon/settings"; import SquareChartGantt from "$icon/square-chart-gantt"; import Star from "$icon/star"; import Trash2 from "$icon/trash-2"; import TriangleAlert from "$icon/triangle-alert"; import bonesRadioLoadingRow from "$lib/bones/bones-radio--loading-row.bones.json"; import ActorInput from "$lib/components/ui/ActorInput.svelte"; import Avatar from "$lib/components/ui/Avatar.svelte"; import Bones from "$lib/components/ui/Bones.svelte"; import Button from "$lib/components/ui/Button.svelte"; import ButtonCard from "$lib/components/ui/ButtonCard.svelte"; import ButtonGroup from "$lib/components/ui/ButtonGroup.svelte"; import Segment from "$lib/components/ui/Segment.svelte"; import SegmentedControl from "$lib/components/ui/SegmentedControl.svelte"; import Card from "$lib/components/ui/Card.svelte"; import Checkbox from "$lib/components/ui/Checkbox.svelte"; import ColorBall from "$lib/components/ui/ColorBall.svelte"; import Combobox from "$lib/components/ui/Combobox.svelte"; import ConfirmModal from "$lib/components/ui/ConfirmModal.svelte"; import CopyButton from "$lib/components/ui/CopyButton.svelte"; import Dropdown from "$lib/components/ui/Dropdown.svelte"; import DropdownItem from "$lib/components/ui/DropdownItem.svelte"; import EmptyState from "$lib/components/ui/EmptyState.svelte"; import ErrorMessage from "$lib/components/ui/Error.svelte"; import Field from "$lib/components/ui/Field.svelte"; import FormStep from "$lib/components/ui/FormStep.svelte"; import FormStepDisclosure from "$lib/components/ui/FormStepDisclosure.svelte"; import GraphCell, { type Band } from "$lib/components/ui/GraphCell.svelte"; import Hovercard from "$lib/components/ui/Hovercard.svelte"; import Input from "$lib/components/ui/Input.svelte"; import Kbd from "$lib/components/ui/Kbd.svelte"; import Lightbox from "$lib/components/ui/Lightbox.svelte"; import Link from "$lib/components/ui/Link.svelte"; import ListPanel, { listRows } from "$lib/components/ui/ListPanel.svelte"; import ListToolbar from "$lib/components/ui/ListToolbar.svelte"; import Logo from "$lib/components/ui/Logo.svelte"; import MarkdownEditor from "$lib/components/ui/MarkdownEditor.svelte"; import Modal from "$lib/components/ui/Modal.svelte"; import MoreMenu from "$lib/components/ui/MoreMenu.svelte"; import Pagination from "$lib/components/ui/Pagination.svelte"; import Radio from "$lib/components/ui/Radio.svelte"; import RangeSelector, { type Range, type RowActions } from "$lib/components/ui/RangeSelector.svelte"; import ResizeHandle from "$lib/components/ui/ResizeHandle.svelte"; import Section from "$lib/components/ui/Section.svelte"; import Select from "$lib/components/ui/Select.svelte"; import Separator from "$lib/components/ui/Separator.svelte"; import ShimmerText from "$lib/components/ui/ShimmerText.svelte"; import SignupPrompt from "$lib/components/ui/SignupPrompt.svelte"; import Spinner from "$lib/components/ui/Spinner.svelte"; import SplitButton from "$lib/components/ui/SplitButton.svelte"; import StepMarker from "$lib/components/ui/StepMarker.svelte"; import Tabs from "$lib/components/ui/Tabs.svelte"; import Tag from "$lib/components/ui/Tag.svelte"; import Textarea from "$lib/components/ui/Textarea.svelte"; import TextSwap from "$lib/components/ui/TextSwap.svelte"; import TimeAgo from "$lib/components/ui/TimeAgo.svelte"; import Toggle from "$lib/components/ui/Toggle.svelte"; import ToggleFaces from "$lib/components/ui/ToggleFaces.svelte"; import Tooltip from "$lib/components/ui/Tooltip.svelte"; import User from "$lib/components/ui/User.svelte"; import type { InputTag } from "$lib/components/ui/inputField"; import type { SelectOption } from "$lib/components/ui/selectField"; import type { LightboxImage } from "$lib/lightbox.svelte"; import Shell from "$routes/dev/components/Shell.svelte"; import Tile from "$routes/dev/components/Tile.svelte";
const versions: SelectOption[] = [ { value: "v1.2.0", hint: "latest" }, { value: "v1.1.0" }, { value: "v1.0.0" } ];
const refs: SelectOption[] = [ { value: "main", hint: "default", group: "Branches" }, { value: "next", group: "Branches" }, { value: "feature/combobox", group: "Branches" }, { value: "v1.0.0", group: "Tags" }, { value: "v0.9.0", group: "Tags" } ];
const tabs = [ { id: "overview", label: "Overview", icon: SquareChartGantt, href: "#tabs" }, { id: "repos", label: "Repositories", icon: BookMarked, count: 12, href: "#tabs" }, { id: "starred", label: "Starred", icon: Star, count: 3, href: "#tabs" } ];
const team: { handle: string; did?: string }[] = [ { handle: "ptr.pet", did: "did:plc:dfl62fgb7wtjj3fcbb72naae" }, { handle: "eti.tf", did: "did:plc:xu5apv6kmu5jp7g5hwdnej42" }, { handle: "oppi.li", did: "did:plc:qfpnj4og54vl56wngdriaxug" }, { handle: "oyster.cafe", did: "did:plc:3fwecdnvtcscjnrx2p4n7alz" }, { handle: "anirudh.fi", did: "did:plc:hwevmowznbiukdf6uk5dwrrq" }, { handle: "boltless.dev" } ];
const people: InputTag[] = team.map(({ handle }) => ({ value: handle }));
const sha = "013b7330f0a2a7f4d0d1d6f4c9d51d1f3a0e1b2c"; const graphRun: Band[] = ["first", "middle", "middle", "last"]; const graphOverlay: Band[] = ["none", "first", "middle", "last"];
const plate = (label: string, from: string, to: string) => `data:image/svg+xml,${encodeURIComponent( `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="800" viewBox="0 0 1200 800"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="${from}"/><stop offset="1" stop-color="${to}"/></linearGradient></defs><rect width="1200" height="800" fill="url(#g)"/><text x="50%" y="50%" font-family="ui-sans-serif,system-ui" font-size="100" fill="white" text-anchor="middle" dominant-baseline="middle">${label}</text></svg>` )}`;
const shots: LightboxImage[] = [ { src: plate("one", "#4568FF", "#93B0FF"), alt: "Screenshot one", width: 1200, height: 800 }, { src: plate("two", "#16a34a", "#bbf7d0"), alt: "Screenshot two", width: 1200, height: 800 } ];
let { data } = $props();
let query = $state(""); let toggled = $state(true); let checked = $state(true); let radio = $state("spindle.tangled.sh"); let select = $state(""); let combobox = $state("main"); let segmented = $state("push"); let pageNumber = $state(3); let tags = $state<InputTag[]>([{ value: "oppi.li" }]); let modalOpen = $state(false); let confirmOpen = $state(false); let lightboxOpen = $state(false); let lightboxIndex = $state(0); let swapped = $state(true); let starred = $state(false); let range = $state<Range>({ start: 1, end: 2 }); let panelWidth = $state(120); let actor = $state(""); let markdown = $state("## Hello\n\nSome **markdown**.");
const markup = { repo: "tangled.org/core", ref: "main", host: "tangled.org" };
const demos: { name: string; demo: Snippet }[] = [ { name: "Button", demo: button }, { name: "Input", demo: input }, { name: "Select", demo: selectDemo }, { name: "ButtonGroup", demo: buttonGroup }, { name: "SegmentedControl", demo: segmentedControlDemo }, { name: "Combobox", demo: comboboxDemo }, { name: "Toggle", demo: toggle }, { name: "Field", demo: field }, { name: "Modal", demo: modal }, { name: "Tooltip", demo: tooltip }, { name: "Dropdown", demo: dropdown }, { name: "Checkbox", demo: checkbox }, { name: "Card", demo: card }, { name: "Spinner", demo: spinner }, { name: "Bones", demo: bones }, { name: "Tag", demo: tag }, { name: "Error", demo: error }, { name: "Tabs", demo: tabsDemo }, { name: "ConfirmModal", demo: confirmModal }, { name: "Pagination", demo: pagination }, { name: "Textarea", demo: textarea }, { name: "TagInput", demo: tagInput }, { name: "Avatar", demo: avatar }, { name: "User", demo: user }, { name: "Kbd", demo: kbd }, { name: "Link", demo: link }, { name: "CopyButton", demo: copyButton }, { name: "SplitButton", demo: splitButton }, { name: "MoreMenu", demo: moreMenu }, { name: "Hovercard", demo: hovercard }, { name: "Radio", demo: radioDemo }, { name: "EmptyState", demo: emptyState }, { name: "Section", demo: section }, { name: "Separator", demo: separator }, { name: "StepMarker", demo: stepMarker }, { name: "FormStep", demo: formStep }, { name: "RangeSelector", demo: rangeSelector }, { name: "GraphCell", demo: graphCell }, { name: "ShimmerText", demo: shimmerText }, { name: "TextSwap", demo: textSwap }, { name: "ToggleFaces", demo: toggleFaces }, { name: "ColorBall", demo: colorBall }, { name: "Logo", demo: logo }, { name: "TimeAgo", demo: timeAgo }, { name: "ResizeHandle", demo: resizeHandle }, { name: "Lightbox", demo: lightbox }, { name: "MarkdownEditor", demo: markdownEditor }, { name: "ButtonCard", demo: buttonCard }, { name: "ListPanel", demo: listPanel }, { name: "ActorInput", demo: actorInput }, { name: "SignupPrompt", demo: signupPrompt } ];
const entries = demos.map((d) => ({ ...d, slug: d.name.toLowerCase() }));
const visible = $derived( entries.filter((entry) => entry.name.toLowerCase().includes(query.trim().toLowerCase())) );</script>
<svelte:head> <title>Components · Tangled</title></svelte:head>
{#snippet button()} <div class="grid gap-sm"> <Button>Create repository</Button> <Button variant="primary" icon={GitFork}>Fork</Button> <Button variant="ghost" icon={Star}>Star</Button> </div>{/snippet}
{#snippet input()} <div class="grid w-full max-w-64 gap-sm"> <Input placeholder="Repository name" /> <Input error value="invalid name!" /> </div>{/snippet}
{#snippet selectDemo()} <div class="w-56"> <Select rich options={versions} placeholder="Select version" bind:value={select} /> </div>{/snippet}
{#snippet buttonGroup()} <ButtonGroup> <Button>Button</Button> <Button>Button</Button> <Button>Button</Button> </ButtonGroup>{/snippet}
{#snippet segmentedControlDemo()} <SegmentedControl bind:value={segmented} label="Trigger"> <Segment value="all">All</Segment> <Segment value="push">Push</Segment> <Segment value="pull_request">Pull request</Segment> </SegmentedControl>{/snippet}
{#snippet comboboxDemo()} <div class="w-56"> <Combobox options={refs} bind:value={combobox} searchPlaceholder="Find a ref…" /> </div>{/snippet}
{#snippet toggle()} <Toggle bind:checked={toggled}>Notifications</Toggle>{/snippet}
{#snippet field()} <div class="w-full max-w-64"> <Field label="Email" subtitle="Where we send notifications" required> {#snippet children({ id })} <Input {id} error value="eti@" /> <ErrorMessage label="Enter a valid email address." class="mt-2xs" /> {/snippet} </Field> </div>{/snippet}
{#snippet modal()} <Button onclick={() => (modalOpen = true)}>Open modal</Button> <Modal bind:open={modalOpen} title="Delete this branch?" description="This cannot be undone."> {#snippet footer()} <Button class="flex-1" onclick={() => (modalOpen = false)}>Cancel</Button> <Button variant="primary" class="flex-1" onclick={() => (modalOpen = false)} >Confirm</Button > {/snippet} </Modal>{/snippet}
{#snippet tooltip()} <div class="flex gap-xs"> <Tooltip content="New issue"> <Button icon={Plus} aria-label="New issue" /> </Tooltip> <Tooltip content="Settings" side="bottom"> <Button icon={Settings} aria-label="Settings" /> </Tooltip> </div>{/snippet}
{#snippet actionsTrigger()} <span>Actions</span> <ChevronDown class="size-4" />{/snippet}
{#snippet dropdown()} <Dropdown variant="button" trigger={actionsTrigger} label="Actions"> <DropdownItem icon={Pencil}>Edit</DropdownItem> <DropdownItem icon={Settings}>Settings</DropdownItem> <DropdownItem icon={LogOut} danger>Log out</DropdownItem> </Dropdown>{/snippet}
{#snippet checkbox()} <div class="flex flex-col gap-sm"> <Checkbox bind:checked>Sign commits</Checkbox> <Checkbox indeterminate>Some files</Checkbox> <Checkbox disabled>Disabled</Checkbox> </div>{/snippet}
{#snippet card()} <Card class="w-56"> <p class="font-medium">tangled.org/core</p> <p class="typography-paragraph-small text-foreground-subtle">Monorepo for Tangled</p> </Card>{/snippet}
{#snippet spinner()} <div class="flex items-center gap-sm"> <Spinner class="size-3" /> <Spinner class="size-4" /> <Spinner class="size-6" /> <Spinner class="size-8" /> </div>{/snippet}
{#snippet bones()} <Bones capture={bonesRadioLoadingRow} repeat={3} class="w-56" />{/snippet}
{#snippet tag()} <div class="flex flex-col items-start gap-xs"> <Tag>Default</Tag> <Tag color="gray">Gray</Tag> <Tag color="success">Passed</Tag> <Tag color="danger">Failed</Tag> <Tag color="warning">Timed out</Tag> <Tag color="info">Primary</Tag> <Tag icon={Hash}>topic</Tag> </div>{/snippet}
{#snippet error()} <div class="flex flex-col gap-md"> <ErrorMessage label="This email address is already in use." /> <ErrorMessage size="large" label="Something went wrong." /> </div>{/snippet}
{#snippet tabsDemo()} <div class="w-full"> <Tabs {tabs} active="repos" /> <div class="h-8 rounded-md bg-background-default edge-ring"></div> </div>{/snippet}
{#snippet confirmModal()} <Button variant="danger" onclick={() => (confirmOpen = true)}>Delete</Button> <ConfirmModal bind:open={confirmOpen} title="Delete this?" description="This cannot be undone." confirmLabel="Delete" onconfirm={() => (confirmOpen = false)} />{/snippet}
{#snippet pagination()} <Pagination bind:page={pageNumber} total={10} />{/snippet}
{#snippet textarea()} <Textarea class="w-full" rows={4} placeholder="Leave a comment" />{/snippet}
{#snippet tagInput()} <div class="w-full max-w-64"> <Input rich bind:tags suggestions={people} label="Reviewers" placeholder="Add a reviewer" hint="Pick from the list, or type a handle" emptyLabel="No one left to add" > {#snippet tag(t)} <User handle={t.value} did={team.find((m) => m.handle === t.value)?.did} link={false} /> {/snippet} {#snippet suggestion(t)} <User handle={t.value} did={team.find((m) => m.handle === t.value)?.did} link={false} /> {/snippet} </Input> </div>{/snippet}
{#snippet avatar()} <div class="flex flex-col items-center gap-md"> <div class="flex items-end gap-sm"> {#each ["mini", "small", "regular", "large"] as const as size, i (size)} <Avatar handle={team[i].handle} did={team[i].did} {size} /> {/each} </div> <div class="flex items-center gap-xs"> {#each team as member (member.handle)} <Avatar handle={member.handle} did={member.did} size="large" /> {/each} </div> </div>{/snippet}
{#snippet user()} <div class="flex flex-col items-start gap-sm"> {#each team as member (member.handle)} <User handle={member.handle} did={member.did} /> {/each} </div>{/snippet}
{#snippet kbd()} <div class="flex flex-col items-center gap-sm"> <span class="inline-flex items-center gap-3xs"><Kbd>⌘</Kbd><Kbd>K</Kbd></span> <span class="inline-flex items-center gap-3xs" ><Kbd>Ctrl</Kbd><Kbd>Shift</Kbd><Kbd>Enter</Kbd></span > </div>{/snippet}
{#snippet link()} <div class="flex flex-col gap-xs"> <Link href={resolve("/")}>Default link</Link> <Link variant="danger" href={resolve("/")}>Danger link</Link> <Link iconRight={ArrowRight} href={resolve("/")}>Continue</Link> <Link disabled>Disabled link</Link> </div>{/snippet}
{#snippet copyButton()} <div class="flex w-full max-w-72 items-center gap-xs rounded-md border border-border-default p-2xs pl-sm" > <code class="min-w-0 flex-1 truncate typography-monospace-small text-foreground-muted" >{sha}</code > <CopyButton value={sha} label="Copy SHA" showLabel /> </div>{/snippet}
{#snippet splitButton()} <SplitButton variant="primary" options={[ { label: "Rebase & merge", icon: GitMerge }, { label: "Manually mark as merged", buttonLabel: "Merge (manual)", icon: CircleCheck }, { label: "Close without merging", icon: Trash2, danger: true } ]} />{/snippet}
{#snippet moreMenu()} <MoreMenu label="More actions for @oppi.li" buttonVariant="default"> <DropdownItem icon={Rss}>RSS feed</DropdownItem> <DropdownItem icon={TriangleAlert} danger>Report user</DropdownItem> </MoreMenu>{/snippet}
{#snippet hovercardBody()} <div class="w-64 p-sm"> <p class="font-semibold">Rich content</p> <p class="typography-paragraph-regular text-foreground-subtle"> It stays open while the pointer moves into it. </p> </div>{/snippet}
{#snippet hovercard()} <Hovercard content={hovercardBody}> <Button>Hover me</Button> </Hovercard>{/snippet}
{#snippet radioDemo()} <fieldset class="flex flex-col gap-sm"> <legend class="mb-xs font-medium">Spindle</legend> <Radio name="spindle" value="spindle.tangled.sh" bind:group={radio} >spindle.tangled.sh</Radio > <Radio name="spindle" value="self-hosted" bind:group={radio}>Self-hosted</Radio> <Radio name="spindle" value="" bind:group={radio}>No spindle</Radio> </fieldset>{/snippet}
{#snippet emptyState()} <EmptyState icon={Inbox} message="No issues yet." messageDirection="vertical" class="w-full" />{/snippet}
{#snippet sectionItem(label: string)} <div class="rounded-md border border-border-default p-sm">{label}</div>{/snippet}
{#snippet section()} <div class="w-full"> <Section title="Repositories" empty={false} emptyMessage="No repositories yet." listClass="flex flex-col gap-xs" > {@render sectionItem("core")} {@render sectionItem("knot")} </Section> </div>{/snippet}
{#snippet separator()} <div class="flex w-full flex-col items-center gap-md"> <Separator class="w-full" /> <div class="flex h-6 items-stretch gap-sm"> <span>Before</span> <Separator orientation="vertical" /> <span>After</span> </div> <div class="flex items-center gap-xs text-foreground-muted"> <span class="typography-monospace-regular text-foreground-default">a1b2c3d</span> <Separator variant="dot" /> <span>2 hours ago</span> </div> </div>{/snippet}
{#snippet stepMarker()} <div class="flex flex-col"> {#each ["Details", "Configuration", "Review"] as step, i (step)} <div class={["relative border-l border-border-default pl-xl", i < 2 && "pb-xl"]}> <StepMarker class="absolute top-0 -left-3">{i + 1}</StepMarker> <p class="font-medium">{step}</p> </div> {/each} </div>{/snippet}
{#snippet formStep()} <form class="w-full"> <FormStep step={1} title="Details" description="Basic repository information."> <Input placeholder="repository-name" /> </FormStep> <FormStepDisclosure title="Advanced" last> <Radio value="" group="" name="formstep-spindle">No spindle</Radio> </FormStepDisclosure> </form>{/snippet}
{#snippet rangeRow(index: number, item: unknown, actions: RowActions)} <div class="relative flex w-48 items-stretch justify-between px-sm"> <button type="button" class="absolute inset-0 cursor-pointer" aria-label="Select line {item}" onclick={actions.onclick} ></button> <div class="relative flex h-9 flex-1 items-center typography-monospace-small"> line {index + 1} </div> </div>{/snippet}
{#snippet rangeSelector()} <RangeSelector items={[1, 2, 3, 4, 5]} row={rangeRow} bind:range />{/snippet}
{#snippet graphCell()} <div class="flex flex-col" style="--range-accent: var(--color-background-info-emphasis); --range-fill: var(--color-background-info-subtle)" > {#each graphRun as band, i (i)} <div class="relative flex"> <GraphCell {band} /> <GraphCell band={graphOverlay[i]} fill={graphOverlay[i] !== "middle"} style="--graph-line: var(--range-accent); --graph-fill: var(--range-fill)" class="absolute inset-y-0 left-0" /> </div> {/each} </div>{/snippet}
{#snippet shimmerText()} <div class="flex flex-col gap-2xs typography-paragraph-large"> <ShimmerText color="muted">Resolving knots</ShimmerText> <ShimmerText color="muted" delay={0.3}>Fetching objects</ShimmerText> <ShimmerText color="warning" delay={0.6}>Pipeline running</ShimmerText> </div>{/snippet}
{#snippet textSwap()} <Card padding="small" class="flex w-56 items-center justify-between"> <TextSwap value={swapped ? "Changes" : "Commits"} /> <Button onclick={() => (swapped = !swapped)}>Swap</Button> </Card>{/snippet}
{#snippet toggleFaces()} <Button class="min-w-22" onclick={() => (starred = !starred)}> <ToggleFaces on={starred} size="small" offLabel="Star" onLabel="Starred"> {#snippet off(cls)} <Star class={cls} /> {/snippet} {#snippet onIcon(cls)} <Star class={[cls, "[&_path]:fill-current"]} /> {/snippet} {#snippet err(cls)} <TriangleAlert class={cls} /> {/snippet} </ToggleFaces> </Button>{/snippet}
{#snippet colorBall()} <div class="flex flex-col gap-xs"> {#each [["TypeScript", "#3178c6"], ["Go", "#00ADD8"], ["Rust", "#dea584"], ["Nix", "#7e7eff"]] as [name, color] (name)} <span class="flex items-center gap-xs typography-paragraph-small"> <ColorBall {color} /> {name} </span> {/each} </div>{/snippet}
{#snippet logo()} <div class="flex flex-col items-center gap-md"> <Logo /> <Logo wordmark /> </div>{/snippet}
{#snippet timeAgo()} <div class="flex flex-col gap-xs"> <TimeAgo value={new Date(Date.now() - 5 * 60 * 1000)} /> <TimeAgo value={new Date(Date.now() - 3 * 24 * 60 * 60 * 1000)} variant="full" /> </div>{/snippet}
{#snippet resizeHandle()} <div class="flex h-32 w-full rounded-md border border-border-default"> <div class="flex shrink-0 items-center justify-center bg-background-subtle typography-paragraph-small" style:width="{panelWidth}px" > Panel </div> <ResizeHandle bind:width={panelWidth} min={64} max={200} resetTo={120} side="before" /> <div class="flex min-w-0 flex-1 items-center justify-center typography-paragraph-small"> Content </div> </div>{/snippet}
{#snippet lightbox()} <div class="flex gap-xs"> {#each shots as shot, i (shot.src)} <button type="button" class="cursor-zoom-in overflow-hidden rounded-md border border-border-default" onclick={() => { lightboxIndex = i; lightboxOpen = true; }} > <img src={shot.src} alt={shot.alt} class="h-16 w-auto" /> </button> {/each} </div> <Lightbox open={lightboxOpen} images={shots} bind:index={lightboxIndex} onClose={() => (lightboxOpen = false)} />{/snippet}
{#snippet markdownEditor()} <div class="w-full"> <MarkdownEditor {markup} bind:value={markdown} rows={4} compact /> </div>{/snippet}
{#snippet buttonCard()} <div class="grid w-full gap-xs"> <ButtonCard icon={Settings} title="Settings" description="Manage this repository" /> <ButtonCard variant="ghost" icon={GitFork} title="Fork" description="Copy to your account" /> </div>{/snippet}
{#snippet listSearch()} <Input size="small" iconLeft={Search} placeholder="Filter" class="w-full" />{/snippet}
{#snippet listTrailing()} <Button size="small" variant="primary">New</Button>{/snippet}
{#snippet listToolbar()} <ListToolbar search={listSearch} trailing={listTrailing} />{/snippet}
{#snippet listPanel()} <div class="w-full"> <ListPanel toolbar={listToolbar}> <div class={listRows}> {#each ["Fix login redirect", "Add sitemap", "Bump deps"] as row (row)} <div class="px-sm py-xs typography-paragraph-small">{row}</div> {/each} </div> </ListPanel> </div>{/snippet}
{#snippet actorInput()} <div class="w-full max-w-64"> <ActorInput bobbinUrl={data.publicConfig.bobbinUrl} bind:value={actor} placeholder="Search people" /> </div>{/snippet}
{#snippet signupPrompt()} <SignupPrompt />{/snippet}
<Shell title="Tangled UI" entries={visible} total={entries.length} bind:query> <ul class="grid auto-rows-min grid-cols-1 gap-px bg-border-default md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4" > {#each visible as entry (entry.slug)} <Tile name={entry.name} slug={entry.slug}> {@render entry.demo()} </Tile> {/each} </ul></Shell>