Monorepo for Tangled
tangled.org
1<script lang="ts">
2 import { resolve } from "$app/paths";
3 import SquareChartGantt from "$icon/square-chart-gantt";
4 import BookMarked from "$icon/book-marked";
5 import Star from "$icon/star";
6 import LineSquiggle from "$icon/line-squiggle";
7 import Shield from "$icon/shield";
8 import type { Component } from "svelte";
9 import type { SvelteHTMLElements } from "svelte/elements";
10 import type { ProfileCounts } from "./types";
11
12 interface Props {
13 handle: string;
14 active: string;
15 counts: ProfileCounts;
16 }
17
18 let { handle, active, counts }: Props = $props();
19
20 interface TabDef {
21 id: string;
22 label: string;
23 icon: Component<SvelteHTMLElements["svg"]>;
24 count?: number;
25 }
26
27 const tabs = $derived<TabDef[]>([
28 { id: "overview", label: "Overview", icon: SquareChartGantt },
29 { id: "repos", label: "Repositories", icon: BookMarked, count: counts.repos },
30 { id: "starred", label: "Starred", icon: Star, count: counts.stars },
31 { id: "strings", label: "Strings", icon: LineSquiggle, count: counts.strings },
32 { id: "vouches", label: "Vouches", icon: Shield, count: counts.vouches }
33 ]);
34
35 const hrefFor = (id: string) =>
36 resolve((id === "overview" ? `/${handle}` : `/${handle}?tab=${id}`) as "/");
37</script>
38
39<nav class="w-full overflow-x-auto overflow-y-hidden pl-4" aria-label="profile sections">
40 <div class="flex">
41 {#each tabs as tab (tab.id)}
42 {@const isActive = active === tab.id}
43 {@const Glyph = tab.icon}
44 <a
45 href={hrefFor(tab.id)}
46 class="group relative -mr-px no-underline hover:no-underline"
47 aria-current={isActive ? "page" : undefined}
48 >
49 <div
50 class={`relative mr-1 min-w-[80px] rounded-t px-4 py-1 text-center whitespace-nowrap text-foreground-default ${
51 isActive
52 ? "-mb-px bg-background-default font-medium"
53 : "group-hover:bg-background-inset/25"
54 }`}
55 >
56 <span class="flex items-center justify-center">
57 <Glyph class="mr-2 h-4 w-4" aria-hidden="true" />
58 {tab.label}
59 {#if tab.count}
60 <span class="ml-1 rounded bg-background-inset px-1 text-sm">{tab.count}</span>
61 {/if}
62 </span>
63 </div>
64 </a>
65 {/each}
66 </div>
67</nav>