This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

web/settings: space settings list rows 8px apart like figma

figma lays every one of these cards out as [row, separator, row] with an 8px
auto-layout gap, so there is only ever one value to express: py-2 on each row,
which is the spacing unit that resolves to 8px on the default scale. that
leaves the card py-1, the rest of the 12px figma puts between its edge and the
first row.

with a single value the gap variant has nothing left to vary, so it folds into
the base and SettingsSection loses the rowGap prop it only forwarded. the repo
pages drop gap="3", which was 6px either side of the hairline, and the lists
reached through SettingsSection drop 4px either side — both now 8.

figma still draws 16px on the keys, emails, knots and spindles cards and 12px
on hooks; those follow the new single value here.

Signed-off-by: eti <eti@eti.tf>

author
eti
committer
dawn
date (Jul 31, 2026, 10:57 PM +0300) commit 7c7d03b5 parent 477dfdbe change-id vzzzlnzk
+21 -33
+8 -17
web/src/lib/components/settings/SettingsList.svelte
··· 2 2 import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const settingsList = tv({ 5 - base: "flex w-full flex-col divide-y divide-border-default rounded-sm border border-border-default", 5 + // Figma lays these cards out as [row, separator, row] with an 8px gap, so every 6 + // row carries 8px of its own padding and divide-y draws the hairline between two 7 + // of them — the line ends up centred in the space rather than flush against the 8 + // row above. That leaves py-1 for the card itself, which is the rest of the 12px 9 + // Figma puts between the card edge and the first row. 10 + base: "flex w-full flex-col divide-y divide-border-default rounded-sm border border-border-default py-1 [&>*]:py-2", 6 11 variants: { 7 - // Figma spaces rows with a gap and drops the hairline in the middle of it, 8 - // so each row carries half the gap as its own padding and divide-y draws the 9 - // line between the two halves — that way the divider is split evenly across 10 - // the rows it separates rather than sitting flush against one of them. The 11 - // card's own vertical padding is whatever is left of 12px once a row's half 12 - // is counted, which is why it lives here rather than in `padding`. Named in 13 - // Tailwind spacing units because the designs use all three of 8 / 12 / 16px. 14 - gap: { 15 - "2": "py-2 [&>*]:py-1", 16 - "3": "py-1.5 [&>*]:py-1.5", 17 - "4": "py-1 [&>*]:py-2" 18 - }, 19 12 padding: { 20 13 default: "px-4", 21 14 tight: "px-3" 22 15 } 23 16 }, 24 17 defaultVariants: { 25 - gap: "4", 26 18 padding: "default" 27 19 } 28 20 }); ··· 34 26 import type { Snippet } from "svelte"; 35 27 36 28 interface Props { 37 - gap?: SettingsListVariants["gap"]; 38 29 padding?: SettingsListVariants["padding"]; 39 30 class?: string; 40 31 children: Snippet; 41 32 } 42 33 43 - let { gap = "4", padding = "default", class: className, children }: Props = $props(); 34 + let { padding = "default", class: className, children }: Props = $props(); 44 35 45 - const classes = $derived(settingsList({ gap, padding, class: className })); 36 + const classes = $derived(settingsList({ padding, class: className })); 46 37 </script> 47 38 48 39 <div class={classes}>
+1 -1
web/src/lib/components/settings/SettingsPanel.stories.svelte
··· 94 94 {#snippet action()} 95 95 <Button icon={UserRoundPlus}>Add collaborator</Button> 96 96 {/snippet} 97 - <SettingsList gap="3"> 97 + <SettingsList> 98 98 <SettingsRow stack> 99 99 {#snippet label()} 100 100 <span class="flex min-w-0 items-center gap-2">
+2 -5
web/src/lib/components/settings/SettingsSection.svelte
··· 1 1 <script lang="ts"> 2 2 import type { Snippet } from "svelte"; 3 3 import SettingsList from "./SettingsList.svelte"; 4 - import type { SettingsListVariants } from "./SettingsList.svelte"; 5 4 6 5 interface Props { 7 6 /** omit for the leading card, which Figma leaves unlabelled */ 8 7 title?: string; 9 8 /** gap between the heading and its card — 12px on the user pages, 16 on repo */ 10 9 headingGap?: "3" | "4"; 11 - /** row spacing inside the framed card */ 12 - rowGap?: SettingsListVariants["gap"]; 13 10 /** set false when the children provide their own container(s) */ 14 11 framed?: boolean; 15 12 children: Snippet; 16 13 } 17 14 18 - let { title, headingGap = "3", rowGap = "2", framed = true, children }: Props = $props(); 15 + let { title, headingGap = "3", framed = true, children }: Props = $props(); 19 16 20 17 const gapClass = $derived(headingGap === "4" ? "gap-4" : "gap-3"); 21 18 </script> ··· 25 22 <h2 class="typography-heading-4 text-foreground-default">{title}</h2> 26 23 {/if} 27 24 {#if framed} 28 - <SettingsList gap={rowGap}> 25 + <SettingsList> 29 26 {@render children()} 30 27 </SettingsList> 31 28 {:else}
+4 -4
web/src/routes/[handle]/[repo]/settings/+page.svelte
··· 76 76 <div class="flex w-full flex-col gap-10"> 77 77 <!-- the leading pair of cards carries no heading in the design --> 78 78 <div class="flex w-full flex-col gap-4"> 79 - <SettingsList gap="3"> 79 + <SettingsList> 80 80 <SettingsRow title="Description" stack> 81 81 <Input 82 82 bind:value={form.description} ··· 96 96 </SettingsRow> 97 97 </SettingsList> 98 98 99 - <SettingsList gap="3"> 99 + <SettingsList> 100 100 <SettingsRow 101 101 title="Default branch" 102 102 description={[ ··· 127 127 <Button icon={X} onclick={unsubscribeAll}>Unsubscribe all</Button> 128 128 {/snippet} 129 129 130 - <SettingsList gap="3"> 130 + <SettingsList> 131 131 {#each labels as item (item.name)} 132 132 <SettingsRow> 133 133 {#snippet label()} ··· 164 164 165 165 <hr class="w-full border-0 border-t border-border-default" /> 166 166 167 - <SettingsSection title="Danger zone" headingGap="4" rowGap="3"> 167 + <SettingsSection title="Danger zone" headingGap="4"> 168 168 <SettingsRow title="Rename"> 169 169 <Button icon={Pencil} href={path(`${base}/rename`)}>Rename repository</Button> 170 170 </SettingsRow>
+1 -1
web/src/routes/[handle]/[repo]/settings/access/+page.svelte
··· 46 46 <Button icon={UserRoundPlus} href={path(`${base}/access/new`)}>Add collaborator</Button> 47 47 {/snippet} 48 48 49 - <SettingsList gap="3"> 49 + <SettingsList> 50 50 {#each collaborators as person (person.handle)} 51 51 <SettingsRow stack> 52 52 {#snippet label()}
+1 -1
web/src/routes/[handle]/[repo]/settings/hooks/+page.svelte
··· 61 61 {#if hooks.length === 0} 62 62 <SettingsEmpty message="No webhooks yet" /> 63 63 {:else} 64 - <SettingsList gap="3"> 64 + <SettingsList> 65 65 {#each hooks as hook (hook.id)} 66 66 <!-- the toggle rides the top-right corner while the actions sit under it, 67 67 so this row is a two-column block rather than a SettingsRow. On a
+2 -2
web/src/routes/[handle]/[repo]/settings/pipelines/+page.svelte
··· 49 49 <DocsButton href="https://docs.tangled.org/spindles" /> 50 50 {/snippet} 51 51 52 - <SettingsList gap="3"> 52 + <SettingsList> 53 53 <SettingsRow title="Spindle" stack> 54 54 <Select bind:value={spindle} aria-label="Spindle" class="w-full sm:w-80"> 55 55 {#each spindles as option (option)} ··· 72 72 <Button icon={Plus} href={path(`${base}/pipelines/secrets/new`)}>Add secret</Button> 73 73 {/snippet} 74 74 75 - <SettingsList gap="3"> 75 + <SettingsList> 76 76 {#each secrets as secret (secret.name)} 77 77 <SettingsRow stack> 78 78 {#snippet label()}
+2 -2
web/src/routes/[handle]/[repo]/settings/sites/+page.svelte
··· 68 68 {/if} 69 69 </div> 70 70 71 - <SettingsList gap="3"> 71 + <SettingsList> 72 72 <SettingsRow title="Branch" description="The branch to build and deploy the site from." stack> 73 73 <Select bind:value={form.branch} aria-label="Branch" class="w-full sm:w-80"> 74 74 {#each branches as branch (branch.value)} ··· 121 121 122 122 <hr class="w-full border-0 border-t border-border-default" /> 123 123 124 - <SettingsSection title="Recent deploys" headingGap="4" rowGap="3" framed={deploys.length > 0}> 124 + <SettingsSection title="Recent deploys" headingGap="4" framed={deploys.length > 0}> 125 125 {#if deploys.length === 0} 126 126 <SettingsEmpty message="No deploys yet." /> 127 127 {:else}