This repository has no description
0

Configure Feed

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

web: move the type scale onto typography-* utilities

the scale lived in @theme as --text-heading-*, --text-paragraph-* and
--text-monospace-*, so it generated text-heading-3, text-paragraph-small and so
on. tailwind-merge classes anything shaped like that as a colour, so inside a
tv() whose variants set text colours it dropped the size as soon as a colour
followed — which, in those definitions, is always. $lib/tv.ts existed only to
re-register the twelve names as font sizes, and every tv() in the app had to
import from there rather than from tailwind-variants to pick that up.

naming them typography-* sidesteps the collision instead of patching it: the
classes match no tailwind-merge group at all, so nothing can read them as
colours and the shim is gone. they're @utility blocks rather than theme tokens
now, since --text-* is precisely the namespace that spells its utilities text-*.

font-size comes first in each block on purpose. tailwind sorts a custom utility
into the bucket of its first declared property, which keeps typography-* ahead
of every font-weight, leading-* and tracking-* utility in the sheet, so the call
sites pairing typography-heading-4 with leading-8 font-normal still resolve the
way they did.

this does give up size-against-size merging: two typography-* classes in one
string no longer collapse, so a size passed in through class= sits next to the
component's own and the stylesheet order picks the winner. nothing does that
today — Typography takes a variant prop for it — and one classGroups entry
brings the merging back if it ever comes up.

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

author
eti
committer
dawn
date (Jul 30, 2026, 7:45 PM +0300) commit 62830504 parent 1008c37c change-id klxknxtx
+182 -169
+77 -32
web/src/app.css
··· 13 13 here; dark-mode overrides live in the prefers-color-scheme block below. 14 14 ========================================================================= */ 15 15 16 - /* --- typography — synced from Figma "Font Styles" (node 1:186) --- */ 17 - --text-heading-0: 5rem; 18 - --text-heading-0--line-height: 5rem; 19 - --text-heading-0--font-weight: 600; 20 - --text-heading-0--letter-spacing: -0.25px; 21 - --text-heading-1: 3rem; 22 - --text-heading-1--line-height: 3.5rem; 23 - --text-heading-1--font-weight: 500; 24 - --text-heading-2: 1.875rem; 25 - --text-heading-2--line-height: 1.875rem; 26 - --text-heading-2--font-weight: 600; 27 - --text-heading-3: 1.5rem; 28 - --text-heading-3--line-height: 1.875rem; 29 - --text-heading-3--font-weight: 500; 30 - --text-heading-4: 1.25rem; 31 - --text-heading-4--line-height: 1.75rem; 32 - --text-heading-4--font-weight: 500; 33 - --text-paragraph-large: 1rem; 34 - --text-paragraph-large--line-height: 1.6875rem; 35 - --text-paragraph-regular: 0.875rem; 36 - --text-paragraph-regular--line-height: 1.5rem; 37 - --text-paragraph-small: 0.75rem; 38 - --text-paragraph-small--line-height: 1.25rem; 39 - --text-paragraph-mini: 0.625rem; 40 - --text-paragraph-mini--line-height: 1rem; 41 - --text-monospace-large: 1rem; 42 - --text-monospace-large--line-height: 1.5rem; 43 - --text-monospace-regular: 0.875rem; 44 - --text-monospace-regular--line-height: 1.375rem; 45 - --text-monospace-small: 0.75rem; 46 - --text-monospace-small--line-height: 1.25rem; 47 - 48 16 /* --- background --- */ 49 17 --color-background-default: #ffffff; 50 18 --color-background-subtle: #f9fafb; ··· 157 125 --color-alpha-dark-85: color-mix(in srgb, var(--color-foreground-default) 85%, transparent); 158 126 --color-alpha-dark-90: color-mix(in srgb, var(--color-foreground-default) 90%, transparent); 159 127 --color-alpha-dark-95: color-mix(in srgb, var(--color-foreground-default) 95%, transparent); 128 + } 129 + 130 + /* ============================================================================= 131 + Type scale — synced from Figma "Font Styles" (node 1:186) 132 + 133 + These are `typography-*` utilities rather than `--text-*` theme tokens on 134 + purpose: named `text-heading-3` & co. they collided with `text-<colour>` in 135 + tailwind-merge, which classes them as colours and drops the size as soon as a 136 + colour follows. Declare `font-size` first in each block — Tailwind sorts a 137 + custom utility by its first property, and that is what keeps an explicit 138 + `font-medium`/`font-bold` winning over the weight baked in here. 139 + ============================================================================= */ 140 + 141 + @utility typography-heading-0 { 142 + font-size: 5rem; 143 + line-height: 5rem; 144 + font-weight: 600; 145 + letter-spacing: -0.25px; 146 + } 147 + 148 + @utility typography-heading-1 { 149 + font-size: 3rem; 150 + line-height: 3.5rem; 151 + font-weight: 500; 152 + } 153 + 154 + @utility typography-heading-2 { 155 + font-size: 1.875rem; 156 + line-height: 1.875rem; 157 + font-weight: 600; 158 + } 159 + 160 + @utility typography-heading-3 { 161 + font-size: 1.5rem; 162 + line-height: 1.875rem; 163 + font-weight: 500; 164 + } 165 + 166 + @utility typography-heading-4 { 167 + font-size: 1.25rem; 168 + line-height: 1.75rem; 169 + font-weight: 500; 170 + } 171 + 172 + @utility typography-paragraph-large { 173 + font-size: 1rem; 174 + line-height: 1.6875rem; 175 + } 176 + 177 + @utility typography-paragraph-regular { 178 + font-size: 0.875rem; 179 + line-height: 1.5rem; 180 + } 181 + 182 + @utility typography-paragraph-small { 183 + font-size: 0.75rem; 184 + line-height: 1.25rem; 185 + } 186 + 187 + @utility typography-paragraph-mini { 188 + font-size: 0.625rem; 189 + line-height: 1rem; 190 + } 191 + 192 + @utility typography-monospace-large { 193 + font-size: 1rem; 194 + line-height: 1.5rem; 195 + } 196 + 197 + @utility typography-monospace-regular { 198 + font-size: 0.875rem; 199 + line-height: 1.375rem; 200 + } 201 + 202 + @utility typography-monospace-small { 203 + font-size: 0.75rem; 204 + line-height: 1.25rem; 160 205 } 161 206 162 207 @layer base {
+6 -4
web/src/lib/components/home/MarketingHome.svelte
··· 14 14 15 15 {#snippet marketingButton(label: string, showArrow: boolean, className: string)} 16 16 <button 17 - class="inline-flex cursor-pointer items-center justify-center gap-2 rounded border border-border-success bg-background-success-emphasis px-4 py-2 text-paragraph-large font-medium text-foreground-on-emphasis hover:bg-background-success-emphasis-hover {className}" 17 + class="inline-flex cursor-pointer items-center justify-center gap-2 rounded border border-border-success bg-background-success-emphasis px-4 py-2 typography-paragraph-large font-medium text-foreground-on-emphasis hover:bg-background-success-emphasis-hover {className}" 18 18 type="submit" 19 19 > 20 20 {label} ··· 39 39 name="id" 40 40 required 41 41 placeholder="Enter your email" 42 - class="min-w-0 flex-1 rounded border border-border-strong bg-background-default px-3 py-2 text-paragraph-large text-foreground-default placeholder:text-foreground-placeholder focus:border-foreground-subtle focus:outline-none" 42 + class="min-w-0 flex-1 rounded border border-border-strong bg-background-default px-3 py-2 typography-paragraph-large text-foreground-default placeholder:text-foreground-placeholder focus:border-foreground-subtle focus:outline-none" 43 43 /> 44 44 {@render marketingButton(label, showArrow, buttonClass)} 45 45 </form> ··· 53 53 tightly-knit<br />social coding. 54 54 </h1> 55 55 56 - <div class="max-w-2xl space-y-6 text-heading-4 leading-8 font-normal text-foreground-default"> 56 + <div 57 + class="max-w-2xl space-y-6 typography-heading-4 leading-8 font-normal text-foreground-default" 58 + > 57 59 <p>The next-generation social coding platform.</p> 58 60 <p> 59 61 We envision a place where developers have ownership of their code, communities can freely ··· 90 92 <h2 class="text-5xl font-bold tracking-[-0.04em] text-foreground-default md:text-6xl"> 91 93 Stay in the loop 92 94 </h2> 93 - <p class="mt-6 max-w-2xl text-heading-4 leading-8 font-normal text-foreground-muted"> 95 + <p class="mt-6 max-w-2xl typography-heading-4 leading-8 font-normal text-foreground-muted"> 94 96 We've got a newsletter. Punch in your email to stay updated on what we're shipping at Tangled. 95 97 </p> 96 98 {@render signupForm(
+1 -1
web/src/lib/components/profile/ActivityStub.svelte
··· 1 1 <div 2 - class="flex min-h-32 items-center justify-center text-paragraph-large text-foreground-subtle italic" 2 + class="flex min-h-32 items-center justify-center typography-paragraph-large text-foreground-subtle italic" 3 3 > 4 4 Activity is not available yet. 5 5 </div>
+1 -1
web/src/lib/components/profile/FollowButton.svelte
··· 93 93 <span>{following ? "Unfollow" : "Follow"}</span> 94 94 </Button> 95 95 {#if relation.failed} 96 - <p class="mt-1 text-paragraph-small text-foreground-danger"> 96 + <p class="mt-1 typography-paragraph-small text-foreground-danger"> 97 97 Something went wrong. Try again. 98 98 </p> 99 99 {/if}
+2 -2
web/src/lib/components/profile/ProfileCard.svelte
··· 53 53 <div class="flex flex-row flex-nowrap items-center gap-2"> 54 54 <h1 55 55 title={identity.handle} 56 - class="overflow-hidden text-heading-4 font-bold text-ellipsis whitespace-nowrap" 56 + class="overflow-hidden typography-heading-4 font-bold text-ellipsis whitespace-nowrap" 57 57 > 58 58 {identity.handle} 59 59 </h1> ··· 79 79 {:else} 80 80 <div class="space-y-2 text-sm"> 81 81 {#if shown?.description} 82 - <p class="pb-4 text-paragraph-large md:pb-2">{shown.description}</p> 82 + <p class="pb-4 typography-paragraph-large md:pb-2">{shown.description}</p> 83 83 {/if} 84 84 85 85 <div class="hidden md:block">
+1 -1
web/src/lib/components/profile/ProfileEditForm.svelte
··· 114 114 </div> 115 115 116 116 {#if error} 117 - <p class="text-paragraph-small text-foreground-danger">{error}</p> 117 + <p class="typography-paragraph-small text-foreground-danger">{error}</p> 118 118 {/if} 119 119 120 120 <div class="flex items-center justify-between gap-2">
+1 -1
web/src/lib/components/profile/StringCardContent.svelte
··· 23 23 {/if} 24 24 25 25 <div 26 - class="mt-auto flex flex-wrap items-center gap-4 pt-2 font-mono text-monospace-small text-foreground-subtle" 26 + class="mt-auto flex flex-wrap items-center gap-4 pt-2 font-mono typography-monospace-small text-foreground-subtle" 27 27 > 28 28 <span class="shrink-0" 29 29 >{entry.lines} line{entry.lines === 1 ? "" : "s"} &middot; {compactRelativeTime(
+1 -1
web/src/lib/components/profile/tabs/OverviewTab.svelte
··· 25 25 </div> 26 26 27 27 <section class="order-2 md:col-span-4"> 28 - <h2 class="px-2 pb-4 text-paragraph-large font-medium">Activity</h2> 28 + <h2 class="px-2 pb-4 typography-paragraph-large font-medium">Activity</h2> 29 29 <ActivityStub /> 30 30 </section> 31 31 </div>
+2 -2
web/src/lib/components/repo/BranchList.svelte
··· 20 20 21 21 <div class="flex flex-col gap-1"> 22 22 {#each branches as branch (branch.name)} 23 - <div class="flex items-center justify-between overflow-hidden text-paragraph-large"> 23 + <div class="flex items-center justify-between overflow-hidden typography-paragraph-large"> 24 24 <div class="flex min-w-0 flex-1 items-center gap-2"> 25 25 <a 26 26 href={resolve(`${base}/tree/${encodeURIComponent(branch.name)}` as "/")} ··· 34 34 > 35 35 <TimeAgo 36 36 value={branch.when} 37 - class="shrink-0 text-paragraph-regular whitespace-nowrap text-foreground-subtle" 37 + class="shrink-0 typography-paragraph-regular whitespace-nowrap text-foreground-subtle" 38 38 /> 39 39 {/if} 40 40 {#if branch.isDefault}
+3 -3
web/src/lib/components/repo/CloneDropdown.svelte
··· 74 74 <div class="flex items-center justify-between"> 75 75 <h3 class="text-sm font-medium text-foreground-default">Clone this repository</h3> 76 76 {#if repo.repoDid} 77 - <Checkbox bind:checked={permalink} class="text-paragraph-small text-foreground-muted"> 77 + <Checkbox bind:checked={permalink} class="typography-paragraph-small text-foreground-muted"> 78 78 Use permalink 79 79 </Checkbox> 80 80 {/if} ··· 83 83 {#each urls as entry (entry.label)} 84 84 {@const value = permalink && entry.perma ? entry.perma : entry.handle} 85 85 <div class="mt-4"> 86 - <span class="mb-1 block text-paragraph-small font-medium text-foreground-muted" 86 + <span class="mb-1 block typography-paragraph-small font-medium text-foreground-muted" 87 87 >{entry.label}</span 88 88 > 89 89 <div ··· 110 110 </div> 111 111 {/each} 112 112 113 - <p class="mt-2 text-paragraph-small text-foreground-subtle"> 113 + <p class="mt-2 typography-paragraph-small text-foreground-subtle"> 114 114 For self-hosted knots, clone URLs may differ based on your setup. 115 115 </p> 116 116
+2 -2
web/src/lib/components/repo/CommitList.svelte
··· 24 24 <div class="flex items-start gap-1"> 25 25 <a 26 26 href={resolve(`${base}/commit/${commit.hash}` as "/")} 27 - class="text-paragraph-large text-foreground-default no-underline hover:underline" 27 + class="typography-paragraph-large text-foreground-default no-underline hover:underline" 28 28 > 29 29 {commit.subject} 30 30 </a> ··· 46 46 {/if} 47 47 48 48 <div 49 - class="mt-2 flex flex-wrap items-center gap-2 text-paragraph-regular text-foreground-subtle" 49 + class="mt-2 flex flex-wrap items-center gap-2 typography-paragraph-regular text-foreground-subtle" 50 50 > 51 51 <a 52 52 href={resolve(`${base}/commit/${commit.hash}` as "/")}
+1 -1
web/src/lib/components/repo/EmptyRepo.svelte
··· 62 62 63 63 {#snippet bullet(n: number)} 64 64 <span 65 - class="mr-2 inline-flex size-5 shrink-0 items-center justify-center rounded-full bg-background-inset align-middle font-mono text-monospace-small" 65 + class="mr-2 inline-flex size-5 shrink-0 items-center justify-center rounded-full bg-background-inset align-middle font-mono typography-monospace-small" 66 66 > 67 67 {n} 68 68 </span>
+1 -1
web/src/lib/components/repo/LanguageBar.svelte
··· 29 29 class="flex flex-wrap items-center justify-center gap-4 border-b border-border-default px-4 py-2" 30 30 > 31 31 {#each languages as language (language.name)} 32 - <div class="flex items-center gap-2 text-paragraph-small"> 32 + <div class="flex items-center gap-2 typography-paragraph-small"> 33 33 <span 34 34 class="inline-block size-2.5 shrink-0 rounded-full" 35 35 style={`background-color: ${colorFor(language.name)}`}
+1 -1
web/src/lib/components/repo/LastCommitPanel.svelte
··· 33 33 </div> 34 34 <a 35 35 {href} 36 - class="w-fit rounded bg-background-inset px-2 py-1 font-mono text-monospace-small text-foreground-muted no-underline hover:underline" 36 + class="w-fit rounded bg-background-inset px-2 py-1 font-mono typography-monospace-small text-foreground-muted no-underline hover:underline" 37 37 > 38 38 {commit.shortHash} 39 39 </a>
+1 -1
web/src/lib/components/repo/RepoCardContent.svelte
··· 53 53 54 54 {#if repo.language !== undefined || stats.length > 0} 55 55 <div 56 - class="mt-auto flex flex-wrap items-center gap-4 pt-2 font-mono text-monospace-small text-foreground-subtle" 56 + class="mt-auto flex flex-wrap items-center gap-4 pt-2 font-mono typography-monospace-small text-foreground-subtle" 57 57 > 58 58 {#if repo.language} 59 59 <span class="flex items-center gap-2">
+1 -1
web/src/lib/components/repo/RepoHeader.svelte
··· 28 28 <section class="mb-2 px-4 py-2"> 29 29 <div class="mb-2 flex flex-col items-start justify-between gap-4 sm:flex-row"> 30 30 <div class="flex min-w-0 flex-col gap-2"> 31 - <div class="flex flex-wrap items-center gap-2 text-heading-4 font-normal"> 31 + <div class="flex flex-wrap items-center gap-2 typography-heading-4 font-normal"> 32 32 <a 33 33 href={resolve(`/${repo.ownerHandle}` as "/")} 34 34 class="flex items-center gap-2 text-foreground-default no-underline hover:underline"
+3 -2
web/src/lib/components/repo/StarButton.svelte
··· 66 66 <Button 67 67 variant="default" 68 68 size="sm" 69 + insetShadow={true} 69 70 class="flex-1" 70 71 loading={busy} 71 72 disabled={!relation.known} ··· 79 80 </Button> 80 81 <Button 81 82 href={`/${repoOwnerHandle}/${repoName}/stars`} 82 - variant="default" 83 + variant="ghost" 83 84 size="sm" 84 85 title="Starred by" 85 86 > ··· 87 88 </Button> 88 89 </ButtonGroup> 89 90 {#if failed} 90 - <p class="mt-1 text-paragraph-small text-foreground-danger"> 91 + <p class="mt-1 typography-paragraph-small text-foreground-danger"> 91 92 Something went wrong. Try again. 92 93 </p> 93 94 {/if}
+2 -2
web/src/lib/components/repo/TagList.svelte
··· 18 18 <div class="flex flex-col gap-1"> 19 19 {#each tags as tag, index (tag.name)} 20 20 <div> 21 - <div class="flex items-center gap-2 text-paragraph-large"> 21 + <div class="flex items-center gap-2 typography-paragraph-large"> 22 22 <a 23 23 href={resolve(`${base}/tags/${encodeURIComponent(tag.name)}` as "/")} 24 24 class="truncate text-foreground-default no-underline hover:underline" ··· 28 28 </div> 29 29 <div class="flex items-center gap-2"> 30 30 {#if tag.when} 31 - <TimeAgo value={tag.when} class="text-paragraph-regular text-foreground-subtle" /> 31 + <TimeAgo value={tag.when} class="typography-paragraph-regular text-foreground-subtle" /> 32 32 {/if} 33 33 {#if index === 0} 34 34 <Tag color="gray" class="font-mono">Latest</Tag>
+1 -1
web/src/lib/components/repo/issues/IssueHeader.svelte
··· 9 9 </script> 10 10 11 11 <header class="pb-2"> 12 - <h1 class="text-heading-3 font-normal"> 12 + <h1 class="typography-heading-3 font-normal"> 13 13 {title} 14 14 <span class="text-foreground-subtle">#{rkey}</span> 15 15 </h1>
+1 -1
web/src/lib/components/repo/issues/IssueStatePill.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const issueStatePill = tv({ 5 5 base: "inline-flex items-center gap-1.5 rounded px-2 py-1 text-sm text-foreground-on-emphasis select-none",
+1 -1
web/src/lib/components/settings/tabs/EmailsTab.svelte
··· 1 1 <div> 2 - <h2 class="text-paragraph-large font-medium text-foreground-default">Email addresses</h2> 2 + <h2 class="typography-paragraph-large font-medium text-foreground-default">Email addresses</h2> 3 3 <p class="text-sm text-foreground-subtle"> 4 4 Commits authored using emails listed here will be associated with your Tangled profile. 5 5 </p>
+1 -1
web/src/lib/components/settings/tabs/KeysTab.svelte
··· 124 124 <div class="flex flex-col gap-4"> 125 125 <div> 126 126 <div class="flex items-center justify-between gap-4"> 127 - <h2 class="text-paragraph-large font-medium text-foreground-default">SSH keys</h2> 127 + <h2 class="typography-paragraph-large font-medium text-foreground-default">SSH keys</h2> 128 128 <Button variant="primary" icon={Plus} popovertarget="add-key-popover">Add</Button> 129 129 </div> 130 130 <p class="pt-4 text-sm text-foreground-subtle">
+1 -1
web/src/lib/components/settings/tabs/KnotsTab.svelte
··· 1 1 <div> 2 - <h2 class="text-paragraph-large font-medium text-foreground-default">Knots</h2> 2 + <h2 class="typography-paragraph-large font-medium text-foreground-default">Knots</h2> 3 3 <p class="text-sm text-foreground-subtle"> 4 4 Knots are lightweight headless servers that enable users to host Git repositories with ease. 5 5 When creating a repository, you can choose a knot to store it on.
+3 -1
web/src/lib/components/settings/tabs/NotificationsTab.svelte
··· 1 1 <div> 2 - <h2 class="text-paragraph-large font-medium text-foreground-default">Notification preferences</h2> 2 + <h2 class="typography-paragraph-large font-medium text-foreground-default"> 3 + Notification preferences 4 + </h2> 3 5 <p class="text-sm text-foreground-subtle"> 4 6 Choose which notifications you want to receive when activity happens on your repositories and 5 7 profile.
+1 -1
web/src/lib/components/settings/tabs/ProfileTab.svelte
··· 27 27 </script> 28 28 29 29 <div> 30 - <h2 class="text-paragraph-large font-medium text-foreground-default">Profile</h2> 30 + <h2 class="typography-paragraph-large font-medium text-foreground-default">Profile</h2> 31 31 <p class="pb-2 text-sm text-foreground-subtle"> 32 32 Your account information from your AT Protocol identity. 33 33 </p>
+1 -1
web/src/lib/components/settings/tabs/SitesTab.svelte
··· 1 1 <div> 2 - <h2 class="text-paragraph-large font-medium text-foreground-default">Git sites</h2> 2 + <h2 class="typography-paragraph-large font-medium text-foreground-default">Git sites</h2> 3 3 <!-- TODO: claim and manage a static site subdomain --> 4 4 </div>
+1 -1
web/src/lib/components/settings/tabs/SpindlesTab.svelte
··· 1 1 <div> 2 - <h2 class="text-paragraph-large font-medium text-foreground-default">Spindles</h2> 2 + <h2 class="typography-paragraph-large font-medium text-foreground-default">Spindles</h2> 3 3 <p class="text-sm text-foreground-subtle"> 4 4 Spindles are servers that run continuous integration pipelines for your repositories. 5 5 </p>
+3 -3
web/src/lib/components/shell/Footer.svelte
··· 46 46 const appPath = (path: string) => resolve(path as "/"); 47 47 const headerStyle = "text-foreground-default font-bold text-sm tracking-wide mb-1"; 48 48 const mobileHeaderStyle = 49 - "text-foreground-default font-bold text-paragraph-small tracking-wide mb-1"; 49 + "text-foreground-default font-bold typography-paragraph-small tracking-wide mb-1"; 50 50 const linkStyle = 51 51 "inline-flex items-center gap-1 text-foreground-subtle hover:text-foreground-default hover:underline"; 52 52 const minimalLinkStyle = "text-foreground-subtle hover:text-foreground-default hover:underline"; ··· 405 405 </div> 406 406 407 407 <div class="text-right"> 408 - <div class="text-paragraph-small"> 408 + <div class="typography-paragraph-small"> 409 409 &copy; 2026 Tangled Labs Oy. All rights reserved. 410 410 </div> 411 411 </div> ··· 439 439 </div> 440 440 441 441 <div class="text-center"> 442 - <div class="text-paragraph-small"> 442 + <div class="typography-paragraph-small"> 443 443 &copy; 2026 Tangled Labs Oy. All rights reserved. 444 444 </div> 445 445 </div>
+2 -2
web/src/lib/components/ui/Button.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const button = tv({ 5 5 base: [ ··· 47 47 size: { 48 48 sm: "min-h-8 gap-1.5 px-2 py-1.5 text-sm", 49 49 md: "min-h-9 gap-2 px-3 py-1.5 text-sm", 50 - lg: "min-h-10 gap-2.5 px-4 py-2 text-paragraph-large" 50 + lg: "min-h-10 gap-2.5 px-4 py-2 typography-paragraph-large" 51 51 }, 52 52 insetShadow: { 53 53 true: "",
+2 -2
web/src/lib/components/ui/ButtonCard.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const buttonCard = tv({ 5 5 base: [ ··· 95 95 </div> 96 96 {/if} 97 97 {#if description} 98 - <span class="text-paragraph-small text-foreground-muted">{description}</span> 98 + <span class="typography-paragraph-small text-foreground-muted">{description}</span> 99 99 {/if} 100 100 </div> 101 101 {/snippet}
+1 -1
web/src/lib/components/ui/ButtonGroup.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 import type { ButtonVariants } from "./Button.svelte"; 4 4 5 5 export const buttonGroup = tv({
+1 -1
web/src/lib/components/ui/Dropdown.svelte
··· 1 1 <script module lang="ts"> 2 2 import { SvelteMap, SvelteSet } from "svelte/reactivity"; 3 - import { tv, type VariantProps } from "$lib/tv"; 3 + import { tv, type VariantProps } from "tailwind-variants"; 4 4 5 5 export const dropdown = tv({ 6 6 slots: {
+1 -1
web/src/lib/components/ui/DropdownItem.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const dropdownItem = tv({ 5 5 base: "flex w-full cursor-pointer items-center gap-2 bg-transparent p-2 text-left no-underline hover:no-underline",
+1 -1
web/src/lib/components/ui/EmptyState.svelte
··· 10 10 </script> 11 11 12 12 <div 13 - class="flex items-center justify-center rounded-sm border border-border-default p-12 text-paragraph-large text-foreground-subtle italic" 13 + class="flex items-center justify-center rounded-sm border border-border-default p-12 typography-paragraph-large text-foreground-subtle italic" 14 14 > 15 15 <span class="flex items-center gap-2">{message}{@render children?.()}</span> 16 16 </div>
+3 -3
web/src/lib/components/ui/Error.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const error = tv({ 5 5 slots: { ··· 19 19 icon: "size-4", 20 20 toggle: "px-3 py-2 text-sm", 21 21 chevron: "size-4", 22 - body: "px-3 py-2 text-paragraph-small" 22 + body: "px-3 py-2 typography-paragraph-small" 23 23 }, 24 24 large: { 25 - header: "px-4 py-3 text-paragraph-large", 25 + header: "px-4 py-3 typography-paragraph-large", 26 26 icon: "size-5", 27 27 toggle: "px-4 py-3 text-sm", 28 28 chevron: "size-4",
+2 -2
web/src/lib/components/ui/Field.svelte
··· 29 29 {#if label} 30 30 <label 31 31 for={id} 32 - class="text-paragraph-small font-medium tracking-wide text-foreground-default uppercase" 32 + class="typography-paragraph-small font-medium tracking-wide text-foreground-default uppercase" 33 33 > 34 34 {label} 35 35 {#if required} ··· 39 39 {/if} 40 40 {@render children({ id })} 41 41 {#if subtitle} 42 - <p class="text-paragraph-small text-foreground-muted">{subtitle}</p> 42 + <p class="typography-paragraph-small text-foreground-muted">{subtitle}</p> 43 43 {/if} 44 44 </div>
+1 -1
web/src/lib/components/ui/Input.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const inputField = tv({ 5 5 base: "flex min-h-9 items-center gap-2 rounded border bg-background-default px-2 py-1 transition-colors",
+2 -2
web/src/lib/components/ui/Link.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const link = tv({ 5 5 base: "inline-flex cursor-pointer items-center gap-1 no-underline transition-colors duration-150 ease-in-out select-none hover:underline focus-visible:outline-2 focus-visible:outline-offset-2", ··· 16 16 }, 17 17 size: { 18 18 regular: "", 19 - small: "text-paragraph-small" 19 + small: "typography-paragraph-small" 20 20 }, 21 21 disabled: { 22 22 true: "pointer-events-none opacity-50",
+1 -1
web/src/lib/components/ui/Pagination.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv } from "$lib/tv"; 2 + import { tv } from "tailwind-variants"; 3 3 4 4 export const pagination = tv({ 5 5 base: "flex items-center gap-1"
+1 -1
web/src/lib/components/ui/Section.svelte
··· 23 23 24 24 <section> 25 25 {#if title} 26 - <h2 class="px-2 pb-4 text-paragraph-large font-medium">{title}</h2> 26 + <h2 class="px-2 pb-4 typography-paragraph-large font-medium">{title}</h2> 27 27 {/if} 28 28 {@render header?.()} 29 29 {#if empty}
+1 -1
web/src/lib/components/ui/Select.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const select = tv({ 5 5 base: "w-full appearance-none rounded border bg-background-default px-3 py-2 pr-9 text-sm transition-colors outline-none disabled:cursor-not-allowed",
+2 -2
web/src/lib/components/ui/Tag.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 export const tag = tv({ 5 - base: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-paragraph-small leading-none font-medium select-none", 5 + base: "inline-flex items-center gap-1 rounded px-1.5 py-0.5 typography-paragraph-small leading-none font-medium select-none", 6 6 variants: { 7 7 color: { 8 8 default: "border border-border-default bg-background-default text-foreground-default",
+1 -1
web/src/lib/components/ui/Textarea.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 4 4 // the field's resting height, exported so anything that swaps itself in for the field — 5 5 // MarkdownEditor's preview pane — can match it and avoid resizing the box as you toggle
+13 -13
web/src/lib/components/ui/Typography.svelte
··· 1 1 <script module lang="ts"> 2 - import { tv, type VariantProps } from "$lib/tv"; 2 + import { tv, type VariantProps } from "tailwind-variants"; 3 3 import type { SvelteHTMLElements } from "svelte/elements"; 4 4 5 5 export const typography = tv({ 6 6 base: "font-sans text-foreground-default", 7 7 variants: { 8 8 variant: { 9 - h0: "text-heading-0", 10 - h1: "text-heading-1", 11 - h2: "text-heading-2", 12 - h3: "text-heading-3", 13 - h4: "text-heading-4", 14 - large: "text-paragraph-large", 15 - regular: "text-paragraph-regular", 16 - small: "text-paragraph-small", 17 - mini: "text-paragraph-mini", 18 - "mono-large": "font-mono text-monospace-large font-normal", 19 - mono: "font-mono text-monospace-regular font-normal", 20 - "mono-small": "font-mono text-monospace-small font-normal" 9 + h0: "typography-heading-0", 10 + h1: "typography-heading-1", 11 + h2: "typography-heading-2", 12 + h3: "typography-heading-3", 13 + h4: "typography-heading-4", 14 + large: "typography-paragraph-large", 15 + regular: "typography-paragraph-regular", 16 + small: "typography-paragraph-small", 17 + mini: "typography-paragraph-mini", 18 + "mono-large": "font-mono typography-monospace-large font-normal", 19 + mono: "font-mono typography-monospace-regular font-normal", 20 + "mono-small": "font-mono typography-monospace-small font-normal" 21 21 }, 22 22 weight: { 23 23 regular: "",
-39
web/src/lib/tv.ts
··· 1 - import { createTV } from "tailwind-variants"; 2 - 3 - /** 4 - * The design-system type scale lives in `app.css` as `--text-heading-*`, 5 - * `--text-paragraph-*` and `--text-monospace-*`, so its utilities read 6 - * `text-heading-3`, `text-paragraph-small`, `text-monospace-regular`, and so on. 7 - * 8 - * tailwind-merge can't tell those apart from `text-<colour>` utilities on its own, 9 - * so it treats them as colours and quietly drops the size as soon as a colour 10 - * follows — which, in a `tv()` definition whose variants set text colours, is 11 - * always. Registering them as font sizes is what keeps both the size and the 12 - * colour, and it leaves Tailwind's own `text-sm`/`text-lg` merging intact. 13 - * 14 - * Use this `tv` rather than importing it straight from `tailwind-variants`. 15 - */ 16 - const fontSizes = [ 17 - "heading-0", 18 - "heading-1", 19 - "heading-2", 20 - "heading-3", 21 - "heading-4", 22 - "paragraph-large", 23 - "paragraph-regular", 24 - "paragraph-small", 25 - "paragraph-mini", 26 - "monospace-large", 27 - "monospace-regular", 28 - "monospace-small" 29 - ]; 30 - 31 - export const tv = createTV({ 32 - twMergeConfig: { 33 - classGroups: { 34 - "font-size": [{ text: fontSizes }] 35 - } 36 - } 37 - }); 38 - 39 - export type { VariantProps } from "tailwind-variants";
+9 -9
web/src/markup.css
··· 2 2 set of tags and classes, so everything here is addressed by element */ 3 3 @layer components { 4 4 .markup { 5 - @apply text-paragraph-regular text-foreground-default; 5 + @apply typography-paragraph-regular text-foreground-default; 6 6 } 7 7 8 8 .markup > :first-child { ··· 23 23 } 24 24 25 25 .markup h1 { 26 - @apply border-b border-border-default pb-2 text-heading-3; 26 + @apply border-b border-border-default pb-2 typography-heading-3; 27 27 } 28 28 29 29 .markup h2 { 30 - @apply border-b border-border-default pb-2 text-heading-4; 30 + @apply border-b border-border-default pb-2 typography-heading-4; 31 31 } 32 32 33 33 .markup h3 { 34 - @apply text-paragraph-large font-semibold; 34 + @apply typography-paragraph-large font-semibold; 35 35 } 36 36 37 37 .markup h4, 38 38 .markup h5, 39 39 .markup h6 { 40 - @apply text-paragraph-regular font-semibold; 40 + @apply typography-paragraph-regular font-semibold; 41 41 } 42 42 43 43 .markup a.anchor { ··· 106 106 } 107 107 108 108 .markup code { 109 - @apply rounded bg-background-inset px-1 py-0.5 font-mono text-monospace-small; 109 + @apply rounded bg-background-inset px-1 py-0.5 font-mono typography-monospace-small; 110 110 } 111 111 112 112 .markup pre { ··· 115 115 116 116 /* pre above already has the padding and background, inline code would double it */ 117 117 .markup pre code { 118 - @apply bg-transparent p-0 font-mono text-monospace-small; 118 + @apply bg-transparent p-0 font-mono typography-monospace-small; 119 119 } 120 120 121 121 .markup kbd { 122 - @apply rounded border border-border-default bg-background-subtle px-1.5 py-0.5 font-mono text-monospace-small; 122 + @apply rounded border border-border-default bg-background-subtle px-1.5 py-0.5 font-mono typography-monospace-small; 123 123 } 124 124 125 125 .markup hr { ··· 177 177 } 178 178 179 179 .markup section.footnotes { 180 - @apply text-paragraph-small text-foreground-muted; 180 + @apply typography-paragraph-small text-foreground-muted; 181 181 } 182 182 183 183 /* github style alerts, `> [!NOTE]` and friends */
+2 -2
web/src/routes/+error.svelte
··· 47 47 <div 48 48 class={`mx-auto mb-4 flex size-16 items-center justify-center rounded-full ${copy.tone}`} 49 49 > 50 - <span class="font-mono text-heading-4 font-bold" aria-hidden="true">{copy.mark}</span> 50 + <span class="font-mono typography-heading-4 font-bold" aria-hidden="true">{copy.mark}</span> 51 51 </div> 52 52 </div> 53 53 54 54 <div class="space-y-4"> 55 - <h1 class="text-heading-3 font-bold text-foreground-default sm:text-heading-2"> 55 + <h1 class="typography-heading-3 font-bold text-foreground-default sm:typography-heading-2"> 56 56 {copy.status} &mdash; {copy.title} 57 57 </h1> 58 58 <p class="text-foreground-muted">{copy.message}</p>
+1 -1
web/src/routes/+page.svelte
··· 15 15 16 16 {#if auth.currentUser} 17 17 <section class="mx-auto flex w-full max-w-screen-lg flex-col gap-2 px-6 py-8"> 18 - <h1 class="text-heading-3 font-semibold">Home</h1> 18 + <h1 class="typography-heading-3 font-semibold">Home</h1> 19 19 </section> 20 20 {:else} 21 21 <MarketingHome />
+1 -1
web/src/routes/[handle]/[repo]/issues/new/+page.svelte
··· 31 31 </svelte:head> 32 32 33 33 <TabPanel class="py-6"> 34 - <h1 class="mb-4 text-heading-4 font-bold text-foreground-default">Create a new issue</h1> 34 + <h1 class="mb-4 typography-heading-4 font-bold text-foreground-default">Create a new issue</h1> 35 35 <IssueForm 36 36 {markup} 37 37 repoDid={data.repo.repoDid ?? ""}
+5 -5
web/src/routes/login/+page.svelte
··· 43 43 <a href={appPath("/")} class="flex items-center gap-2 no-underline hover:no-underline"> 44 44 <img src="/logos/logotype.svg" alt="tangled" class="h-24 w-48 dark:invert" /> 45 45 </a> 46 - <p class="text-center text-heading-4 font-normal text-foreground-default italic"> 46 + <p class="text-center typography-heading-4 font-normal text-foreground-default italic"> 47 47 tightly-knit social coding. 48 48 </p> 49 49 </div> ··· 62 62 inputmode="url" 63 63 required 64 64 placeholder="akshay.tngl.sh" 65 - class="w-full rounded border border-border-default bg-background-default p-3 text-paragraph-large text-foreground-default placeholder:text-foreground-placeholder focus:ring-1 focus:ring-border-strong focus:outline-none" 65 + class="w-full rounded border border-border-default bg-background-default p-3 typography-paragraph-large text-foreground-default placeholder:text-foreground-placeholder focus:ring-1 focus:ring-border-strong focus:outline-none" 66 66 /> 67 67 <p class="mt-1 text-sm text-foreground-subtle"> 68 68 Use your <span class="text-foreground-default">AT Protocol</span> handle to log in. If 69 69 you're unsure, this is likely your Tangled 70 70 <code 71 - class="rounded bg-background-inset px-1 font-mono text-monospace-small text-foreground-default" 71 + class="rounded bg-background-inset px-1 font-mono typography-monospace-small text-foreground-default" 72 72 >(.tngl.sh)</code 73 73 > 74 74 or Bluesky 75 75 <code 76 - class="rounded bg-background-inset px-1 font-mono text-monospace-small text-foreground-default" 76 + class="rounded bg-background-inset px-1 font-mono typography-monospace-small text-foreground-default" 77 77 >(.bsky.social)</code 78 78 > 79 79 account. ··· 87 87 loading={isSubmitting} 88 88 spinnerClass="size-4" 89 89 aria-label={isSubmitting ? "Logging in" : undefined} 90 - class="my-2 mt-6 w-full text-paragraph-large disabled:opacity-100" 90 + class="my-2 mt-6 w-full typography-paragraph-large disabled:opacity-100" 91 91 > 92 92 Login 93 93 </Button>
+1 -1
web/src/routes/oauth/callback/+page.svelte
··· 25 25 26 26 {#if auth.error} 27 27 <section class="mx-auto flex max-w-md flex-col items-center gap-4 px-7 py-16 text-center"> 28 - <p class="text-paragraph-large text-foreground-danger">{auth.error}</p> 28 + <p class="typography-paragraph-large text-foreground-danger">{auth.error}</p> 29 29 <a href={appPath("/login")} class="inline-flex underline">Try again</a> 30 30 </section> 31 31 {:else}
+5 -3
web/src/routes/repo/new/+page.svelte
··· 23 23 24 24 <div class="mx-auto w-full max-w-2xl px-4 py-12"> 25 25 <div class="px-6 py-2"> 26 - <h1 class="text-heading-4 font-bold text-foreground-default">Create a new repository</h1> 26 + <h1 class="typography-heading-4 font-bold text-foreground-default">Create a new repository</h1> 27 27 <p class="mb-1 text-sm text-foreground-subtle"> 28 28 Repositories contain a project's files and version history. All repositories are publicly 29 29 accessible. ··· 42 42 </div> 43 43 44 44 <div class="flex-1 pb-12"> 45 - <h2 class="text-paragraph-large font-medium text-foreground-default">General</h2> 45 + <h2 class="typography-paragraph-large font-medium text-foreground-default">General</h2> 46 46 <div class="mb-4 text-sm text-foreground-subtle">Basic repository information.</div> 47 47 48 48 <div class="space-y-2"> ··· 105 105 </div> 106 106 107 107 <div class="flex-1"> 108 - <h2 class="text-paragraph-large font-medium text-foreground-default">Configuration</h2> 108 + <h2 class="typography-paragraph-large font-medium text-foreground-default"> 109 + Configuration 110 + </h2> 109 111 <div class="mb-4 text-sm text-foreground-subtle">Repository settings and hosting.</div> 110 112 111 113 <div class="space-y-2">
+1 -1
web/src/routes/settings/+layout.svelte
··· 35 35 36 36 <div class="mx-auto w-full max-w-screen-lg px-4 py-12"> 37 37 <div class="px-2 py-2"> 38 - <h1 class="text-heading-4 font-bold text-foreground-default">Settings</h1> 38 + <h1 class="typography-heading-4 font-bold text-foreground-default">Settings</h1> 39 39 </div> 40 40 41 41 <div class="mt-4 rounded border border-border-default bg-background-default p-6">
+1 -1
web/src/routes/strings/new/+page.svelte
··· 17 17 18 18 <div class="mx-auto w-full max-w-screen-lg px-4 py-12"> 19 19 <div class="px-2 py-2"> 20 - <h1 class="text-heading-4 font-bold text-foreground-default">Create a new string</h1> 20 + <h1 class="typography-heading-4 font-bold text-foreground-default">Create a new string</h1> 21 21 <p class="text-sm text-foreground-subtle">Store and share code snippets with ease.</p> 22 22 </div> 23 23