This repository has no description
1<script module lang="ts">
2 import { tv, type VariantProps } from "tailwind-variants";
3
4 // the finish bento: a two-column grid where one tile runs the full width and
5 // another spans both rows (appview onboarding/fragments/finish.html)
6 export const tile = tv({
7 slots: {
8 root: "flex flex-col gap-2 rounded-sm border border-border-default p-4",
9 heading: "flex items-center gap-2 typography-paragraph-regular text-foreground-default",
10 body: "flex-1 typography-paragraph-small text-foreground-muted",
11 action:
12 "ml-auto flex w-fit items-center gap-1 typography-paragraph-small text-foreground-default no-underline hover:underline"
13 },
14 variants: {
15 span: {
16 full: { root: "sm:col-span-2" },
17 tall: { root: "sm:row-span-2" },
18 single: { root: "" }
19 },
20 // the community row's tiles are themselves the link, so they need the hover
21 // surface and the tighter gap the four bento tiles don't want
22 link: {
23 true: {
24 root: "flex-1 gap-1 no-underline transition-colors hover:bg-background-subtle hover:no-underline"
25 },
26 false: { root: "" }
27 }
28 },
29 defaultVariants: {
30 span: "single",
31 link: false
32 }
33 });
34
35 export type TileVariants = VariantProps<typeof tile>;
36</script>
37
38<script lang="ts">
39 import type { Component } from "svelte";
40 import type { SvelteHTMLElements } from "svelte/elements";
41 import { resolve } from "$app/paths";
42 import ArrowRight from "$icon/arrow-right";
43 import BookMarked from "$icon/book-marked";
44 import GitPullRequest from "$icon/git-pull-request";
45 import Layers2 from "$icon/layers-2";
46 import MessageCircle from "$icon/message-circle";
47 import Server from "$icon/server";
48 import Twitter from "$icon/twitter";
49 import Bluesky from "$lib/components/icons/Bluesky.svelte";
50 import StepHeader from "./StepHeader.svelte";
51
52 const slot = tile();
53
54 // the appview links /core, a shortcut route it owns; the svelte app addresses
55 // repositories as /[handle]/[repo]
56 const coreHref = resolve("/tangled.org/core" as "/");
57 const newRepoHref = resolve("/repo/new");
58
59 const docs: {
60 icon: Component<SvelteHTMLElements["svg"]>;
61 title: string;
62 body: string;
63 href: string;
64 }[] = [
65 {
66 icon: Server,
67 title: "Host your own knot",
68 body: "Host repositories on your own infrastructure with knots.",
69 href: "https://docs.tangled.org/knot-self-hosting-guide.html"
70 },
71 {
72 icon: Layers2,
73 title: "Host your own spindle",
74 body: "Run CI jobs on your own infrastructure using spindles.",
75 href: "https://docs.tangled.org/spindles.html#self-hosting-guide"
76 }
77 ];
78
79 const community: {
80 icon: Component<SvelteHTMLElements["svg"]>;
81 title: string;
82 body: string;
83 href: string;
84 }[] = [
85 {
86 icon: Bluesky,
87 title: "Bluesky",
88 body: "Follow us @tangled.org on Bluesky for updates.",
89 href: "https://bsky.app/profile/tangled.org"
90 },
91 {
92 icon: MessageCircle,
93 title: "Discord",
94 body: "Join the community on Discord.",
95 href: "https://chat.tangled.org"
96 },
97 {
98 icon: Twitter,
99 title: "X (Twitter)",
100 body: "Follow us @tangled_org on X for updates.",
101 href: "https://x.com/tangled_org"
102 }
103 ];
104</script>
105
106<div class="flex flex-col gap-6">
107 <StepHeader title="You're all set!" subtitle="Here are a few things to explore next:" />
108
109 <div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
110 <div class={tile({ span: "full" }).root()}>
111 {@render heading(BookMarked, "Create a repository")}
112 <p class={slot.body()}>Kick things off by creating your first repository.</p>
113 <a href={newRepoHref} class={slot.action()}>
114 Create
115 <ArrowRight class="size-4 shrink-0" aria-hidden="true" />
116 </a>
117 </div>
118
119 <div class={tile({ span: "tall" }).root()}>
120 {@render heading(GitPullRequest, "Contribute to the Tangled project")}
121 <p class={slot.body()}>
122 Tangled is fully open-source: Open a feature request, or submit a bug-fix!
123 <br /><br />
124 All contributions are welcome.
125 </p>
126 <a href={coreHref} class={slot.action()}>
127 Contribute
128 <ArrowRight class="size-4 shrink-0" aria-hidden="true" />
129 </a>
130 </div>
131
132 {#each docs as doc (doc.title)}
133 <div class={slot.root()}>
134 {@render heading(doc.icon, doc.title)}
135 <p class={slot.body()}>{doc.body}</p>
136 <a href={doc.href} target="_blank" rel="external noopener noreferrer" class={slot.action()}>
137 Read the docs
138 <ArrowRight class="size-4 shrink-0" aria-hidden="true" />
139 </a>
140 </div>
141 {/each}
142 </div>
143
144 <ul class="grid grid-cols-1 gap-3 sm:grid-cols-3">
145 {#each community as link (link.title)}
146 <li class="flex">
147 <a
148 href={link.href}
149 target="_blank"
150 rel="external noopener noreferrer"
151 class={tile({ link: true }).root()}
152 >
153 {@render heading(link.icon, link.title)}
154 <span class={slot.body()}>{link.body}</span>
155 </a>
156 </li>
157 {/each}
158 </ul>
159</div>
160
161{#snippet heading(icon: Component<SvelteHTMLElements["svg"]>, title: string)}
162 {@const Icon = icon}
163 <span class={slot.heading()}>
164 <Icon class="size-4 shrink-0" aria-hidden="true" />
165 {title}
166 </span>
167{/snippet}