This repository has no description
1<script lang="ts">
2 import { resolve } from "$app/paths";
3 import { getAuth } from "$lib/auth.svelte";
4 import { createBobbinClient } from "$lib/api/client";
5 import { count } from "$lib/api/count";
6 import type { RepoInfo } from "./types";
7
8 interface Props {
9 repo: RepoInfo;
10 /**
11 * Overrides the SSH key lookup, for deterministic stories/tests.
12 * Left unset in real usage, in which case it's figured out from the API.
13 */
14 hasSshKey?: boolean;
15 }
16
17 let { repo, hasSshKey }: Props = $props();
18
19 const auth = getAuth();
20 const isOwner = $derived(auth.currentDid === repo.ownerDid);
21 // same host rewrite as the clone urls
22 const sshHost = $derived(
23 (repo.knot === "knot1.tangled.sh" ? "tangled.org" : repo.knot)
24 .replace(/^[a-z]+:\/\//, "")
25 .split(/[:/]/)[0]
26 );
27 const remote = $derived(`git@${sshHost}:${repo.repoDid ?? `${repo.ownerHandle}/${repo.name}`}`);
28
29 type KeyStatus = "checking" | "has-key" | "no-key";
30
31 let keyStatus = $state<KeyStatus>("checking");
32
33 $effect(() => {
34 if (hasSshKey !== undefined) {
35 keyStatus = hasSshKey ? "has-key" : "no-key";
36 return;
37 }
38
39 if (!isOwner) return;
40 const did = auth.currentDid;
41 if (!did) return;
42
43 let cancelled = false;
44 keyStatus = "checking";
45
46 (async () => {
47 try {
48 const ctx = createBobbinClient({ serviceUrl: auth.bobbinUrl });
49 const result = await count(ctx, "sh.tangled.publicKey.countKeys", did);
50 if (!cancelled) keyStatus = result.count > 0 ? "has-key" : "no-key";
51 } catch {
52 // safe fallback: guide the owner through generating a key.
53 if (!cancelled) keyStatus = "no-key";
54 }
55 })();
56
57 return () => {
58 cancelled = true;
59 };
60 });
61</script>
62
63{#snippet bullet(n: number)}
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-xs"
66 >
67 {n}
68 </span>
69{/snippet}
70
71{#snippet codeBlock(lines: string[])}
72 <pre class="overflow-x-auto rounded bg-background-inset p-3 font-mono text-sm">{lines.join(
73 "\n"
74 )}</pre>
75{/snippet}
76
77{#if isOwner}
78 {#if keyStatus === "checking"}
79 <div class="py-6" aria-hidden="true"></div>
80 {:else if keyStatus === "has-key"}
81 <div class="flex w-full place-content-center">
82 <div class="flex w-fit flex-col gap-5 py-6 text-sm">
83 <p>This is an empty repository.</p>
84 <div class="flex flex-col gap-2">
85 <p class="text-foreground-subtle">…create a new repository on the command line</p>
86 {@render codeBlock([
87 `echo "# ${repo.name}" >> README.md`,
88 "git init",
89 "git add README.md",
90 'git commit -m "initial commit"',
91 `git branch -M ${repo.defaultBranch}`,
92 `git remote add origin ${remote}`,
93 `git push -u origin ${repo.defaultBranch}`
94 ])}
95 </div>
96 <div class="flex flex-col gap-2">
97 <p class="text-foreground-subtle">
98 …or push an existing repository from the command line
99 </p>
100 {@render codeBlock([
101 `git remote add origin ${remote}`,
102 `git branch -M ${repo.defaultBranch}`,
103 `git push -u origin ${repo.defaultBranch}`
104 ])}
105 </div>
106 </div>
107 </div>
108 {:else}
109 <div class="flex w-full place-content-center">
110 <div class="flex w-fit flex-col gap-4 py-6 text-sm">
111 <p>This is an empty repository. To get started:</p>
112 <p>
113 {@render bullet(1)}First, generate a new
114 <a
115 href="https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key"
116 rel="noopener"
117 class="underline">SSH key pair</a
118 >.
119 </p>
120 <p>
121 {@render bullet(2)}Then add the public key from the
122 <a href={resolve("/settings/keys")} class="underline">keys page</a> in your settings.
123 </p>
124 <p>
125 {@render bullet(3)}Configure your remote to
126 <code class="rounded bg-background-inset px-1 font-mono">{remote}</code>
127 </p>
128 <p>{@render bullet(4)}Push!</p>
129 </div>
130 </div>
131 {/if}
132{:else}
133 <p class="py-6 text-center text-foreground-subtle">This is an empty repository.</p>
134{/if}