feat: import page separates your repos (Import) from others (Fork to Cospan)
Author: Aaron Steven White
Commit
152049508c758090761bb8662d0c096f434d4ffcParent: 90953c07a9
Structural diff unavailable
These commits were pushed via plain git push, so no pre-parsed
schemas are available. Install git-remote-cospan and re-push via panproto:// to
see scope-level changes, breaking change detection, and semantic diffs.
brew install panproto/tap/git-remote-cospan1 file changed +101 -84
@@ -8,9 +8,7 @@
88 99 let auth = $derived(getAuth()); 1010 let searchQuery = $state(''); 11- let showMineOnly = $state(false); 1211 13- // Resolve handles for all repos 1412 let handles = $state<Record<string, string>>({}); 1513 1614 onMount(async () => {
@@ -29,15 +27,16 @@
2927 return handles[did] || (did.startsWith('did:plc:') ? did.slice(8, 18) + '…' : did); 3028 } 3129 32- let filteredRepos = $derived(() => { 33- let repos = data.repos.items; 30+ let myRepos = $derived(() => { 31+ if (!auth.authenticated || !auth.did) return []; 32+ return data.repos.items.filter((r: Repo) => r.did === auth.did); 33+ }); 3434 35- // Filter to user's repos 36- if (showMineOnly && auth.authenticated && auth.did) { 37- repos = repos.filter((r: Repo) => r.did === auth.did); 35+ let otherRepos = $derived(() => { 36+ let repos = data.repos.items; 37+ if (auth.authenticated && auth.did) { 38+ repos = repos.filter((r: Repo) => r.did !== auth.did); 3839 } 39- 40- // Search filter 4140 if (searchQuery.trim()) { 4241 const q = searchQuery.toLowerCase(); 4342 repos = repos.filter((r: Repo) =>
@@ -46,7 +45,6 @@
4645 getHandle(r.did).toLowerCase().includes(q) 4746 ); 4847 } 49- 5048 return repos; 5149 }); 5250
@@ -65,95 +63,114 @@
6563 <div class="mb-6"> 6664 <h1 class="mb-1 text-lg font-semibold text-ink">Import from Tangled</h1> 6765 <p class="text-[13px] text-caption"> 68- Browse repositories from the Tangled network and import them into Cospan for schema-aware version control. 66+ Bring your Tangled repositories into Cospan for schema-aware version control. 6967 </p> 7068 </div> 7169 72- <!-- Search + filters --> 73- <div class="mb-6 flex flex-wrap items-center gap-3"> 74- <div class="relative flex-1"> 70+ <!-- Your repos section --> 71+ {#if auth.authenticated} 72+ {#if myRepos().length > 0} 73+ <div class="mb-8"> 74+ <h2 class="mb-3 text-[13px] font-semibold uppercase tracking-wide text-ink">Your Tangled repos</h2> 75+ <div class="divide-y divide-line/40 rounded-lg border border-line/60 bg-ground"> 76+ {#each myRepos() as repo (repo.did + '/' + repo.name)} 77+ <div class="flex items-center justify-between gap-4 px-4 py-3"> 78+ <div class="min-w-0 flex-1"> 79+ <div class="flex items-center gap-2"> 80+ <a href="/{repo.did}/{repo.name}" class="font-mono text-[13px] font-medium text-ink hover:text-focus-bright transition-colors"> 81+ {repo.name} 82+ </a> 83+ {#if repo.description} 84+ <span class="truncate text-[12px] text-ghost">{repo.description}</span> 85+ {/if} 86+ </div> 87+ </div> 88+ <button class="shrink-0 rounded-md bg-focus/10 border border-focus/30 px-3 py-1.5 text-[12px] font-medium text-focus-bright transition-all hover:bg-focus/15 hover:border-focus"> 89+ Import 90+ </button> 91+ </div> 92+ {/each} 93+ </div> 94+ </div> 95+ {:else} 96+ <div class="mb-8 rounded-lg border border-line/40 bg-ground px-4 py-6 text-center"> 97+ <p class="text-[13px] text-caption">You don't have any Tangled repositories yet.</p> 98+ <p class="mt-1 text-[12px] text-ghost">Create a repo on <a href="https://tangled.sh" target="_blank" rel="noopener" class="text-focus-bright hover:underline">tangled.sh</a> to import it here.</p> 99+ </div> 100+ {/if} 101+ {:else} 102+ <div class="mb-8 rounded-lg border border-line/40 bg-ground px-4 py-6 text-center"> 103+ <p class="text-[13px] text-caption">Sign in to import your Tangled repositories.</p> 104+ </div> 105+ {/if} 106+ 107+ <!-- All Tangled repos --> 108+ <div> 109+ <div class="mb-3 flex items-center justify-between gap-3"> 110+ <h2 class="text-[13px] font-semibold uppercase tracking-wide text-ink">Browse all</h2> 111+ <span class="text-[11px] text-ghost">{otherRepos().length} repos</span> 112+ </div> 113+ 114+ <div class="relative mb-4"> 75115 <svg class="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-ghost" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> 76116 <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" /> 77117 </svg> 78118 <input 79119 type="text" 80120 bind:value={searchQuery} 81- placeholder="Search Tangled repos…" 121+ placeholder="Search repos…" 82122 class="w-full rounded-md border border-line bg-surface py-2 pl-10 pr-3 text-[13px] text-ink placeholder:text-ghost focus:border-focus/50 focus:outline-none transition-colors" 83123 /> 84124 </div> 85125 86- {#if auth.authenticated} 87- <button 88- type="button" 89- onclick={() => showMineOnly = !showMineOnly} 90- class="rounded-md px-3 py-2 text-[12px] font-medium transition-all 91- {showMineOnly ? 'bg-focus/10 text-focus-bright border border-focus/30' : 'bg-surface text-ghost border border-line hover:text-caption'}" 92- > 93- My repos 94- </button> 95- {/if} 96- 97- <span class="text-[11px] text-ghost"> 98- {filteredRepos().length} repos 99- </span> 100- </div> 101- 102- <!-- Repo list --> 103- {#if filteredRepos().length === 0} 104- <div class="flex flex-col items-center justify-center py-24 text-center"> 105- <div class="mb-4 text-ghost"> 106- <svg class="mx-auto h-10 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1"> 107- <path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" /> 108- </svg> 126+ {#if otherRepos().length === 0} 127+ <div class="flex flex-col items-center justify-center py-16 text-center"> 128+ {#if searchQuery.trim()} 129+ <p class="text-sm text-caption">No repos matching "{searchQuery}"</p> 130+ {:else} 131+ <div class="mb-4 text-ghost"> 132+ <svg class="mx-auto h-10 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1"> 133+ <path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" /> 134+ </svg> 135+ </div> 136+ <p class="text-sm text-caption">No Tangled repositories found yet.</p> 137+ <p class="mt-1 text-xs text-ghost">Repositories are being backfilled from the network.</p> 138+ {/if} 109139 </div> 110- {#if searchQuery.trim()} 111- <p class="text-sm text-caption">No repos matching "{searchQuery}"</p> 112- {:else if showMineOnly} 113- <p class="text-sm text-caption">No Tangled repos found for your account.</p> 114- {:else} 115- <p class="text-sm text-caption">No Tangled repositories found yet.</p> 116- <p class="mt-1 text-xs text-ghost">Repositories are being backfilled from the network. Check back soon.</p> 117- {/if} 118- </div> 119- {:else} 120- <div class="divide-y divide-line/40"> 121- {#each filteredRepos() as repo (repo.did + '/' + repo.name)} 122- <div class="flex items-start justify-between gap-4 py-4"> 123- <div class="min-w-0 flex-1"> 124- <div class="flex items-center gap-2"> 125- <a href="/{repo.did}/{repo.name}" class="font-mono text-[14px] font-medium text-ink hover:text-focus-bright transition-colors"> 126- {getHandle(repo.did)}/{repo.name} 127- </a> 128- {#if repo.protocol} 129- <span class="text-[11px] text-ghost">{repo.protocol}</span> 130- {:else} 131- <span class="text-[11px] text-ghost">git</span> 132- {/if} 133- </div> 134- {#if repo.description} 135- <p class="mt-1 line-clamp-1 text-[13px] text-caption">{repo.description}</p> 136- {/if} 137- <div class="mt-1.5 flex items-center gap-3 text-[11px] text-ghost"> 138- {#if repo.starCount > 0} 139- <span>★ {repo.starCount}</span> 140- {/if} 141- {#if repo.openIssueCount > 0} 142- <span>{repo.openIssueCount} issues</span> 140+ {:else} 141+ <div class="divide-y divide-line/40"> 142+ {#each otherRepos() as repo (repo.did + '/' + repo.name)} 143+ <div class="flex items-start justify-between gap-4 py-3"> 144+ <div class="min-w-0 flex-1"> 145+ <div class="flex items-center gap-2"> 146+ <a href="/{repo.did}/{repo.name}" class="font-mono text-[13px] font-medium text-ink hover:text-focus-bright transition-colors"> 147+ {getHandle(repo.did)}/{repo.name} 148+ </a> 149+ {#if repo.protocol} 150+ <span class="text-[11px] text-ghost">{repo.protocol}</span> 151+ {:else} 152+ <span class="text-[11px] text-ghost">git</span> 153+ {/if} 154+ </div> 155+ {#if repo.description} 156+ <p class="mt-0.5 line-clamp-1 text-[12px] text-caption">{repo.description}</p> 143157 {/if} 144- <a href={tangledUrl(repo)} target="_blank" rel="noopener" class="hover:text-caption transition-colors"> 145- View on Tangled ↗ 146- </a> 158+ <div class="mt-1 flex items-center gap-3 text-[11px] text-ghost"> 159+ {#if repo.starCount > 0} 160+ <span>★ {repo.starCount}</span> 161+ {/if} 162+ <a href={tangledUrl(repo)} target="_blank" rel="noopener" class="hover:text-caption transition-colors"> 163+ View on Tangled ↗ 164+ </a> 165+ </div> 147166 </div> 148- </div> 149167 150- <button 151- class="shrink-0 rounded-md border border-focus/40 bg-focus/5 px-3 py-1.5 text-[12px] font-medium text-focus-bright transition-all hover:bg-focus/10 hover:border-focus" 152- > 153- Import 154- </button> 155- </div> 156- {/each} 157- </div> 158- {/if} 168+ <button class="shrink-0 rounded-md border border-line px-3 py-1.5 text-[12px] font-medium text-caption transition-all hover:border-line-bright hover:text-ink"> 169+ Fork to Cospan 170+ </button> 171+ </div> 172+ {/each} 173+ </div> 174+ {/if} 175+ </div> 159176 </section>