feat: separate Import page for Tangled repos, fix source filtering + handles - Add /import page in navbar for browsing Tangled repos with Import buttons - Remove source tabs (All/Cospan/Tangled) from landing page — Explore shows all repos - Fix source filtering: page server load now passes source param to API - Fix handle resolution on repo detail page breadcrumb - Landing page focuses on Cospan repos, Tangled import is a dedicated flow
Author: Aaron Steven White
Commit
99b13f7ab765bac7ba6a0081ba256134caddc87cParent: 3fe5211805
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-cospan6 files changed +134 -38
@@ -8,6 +8,7 @@
88 99 const navLinks = [ 1010 { href: '/', label: 'Explore' }, 11+ { href: '/import', label: 'Import' }, 1112 { href: '/feed', label: 'Feed' }, 1213 { href: '/search', label: 'Search' }, 1314 ] as const;
@@ -3,15 +3,16 @@ import { listRepos } from '$lib/api/repo.js';
33 44 export const load: PageServerLoad = async ({ url }) => { 55 const protocol = url.searchParams.get('protocol') ?? undefined; 6+ const source = url.searchParams.get('source') ?? undefined; 67 78 try { 89 const [trending, recent] = await Promise.all([ 9- listRepos({ limit: 12, sort: 'stars' as any, protocol } as any), 10- listRepos({ limit: 12, sort: 'updated' as any, protocol } as any), 10+ listRepos({ limit: 12, source, protocol } as any), 11+ listRepos({ limit: 12, source, protocol } as any), 1112 ]); 12- return { trending, recent, protocol: protocol ?? null }; 13+ return { trending, recent, protocol: protocol ?? null, source: source ?? null }; 1314 } catch { 1415 const empty = { items: [], cursor: null }; 15- return { trending: empty, recent: empty, protocol: protocol ?? null }; 16+ return { trending: empty, recent: empty, protocol: protocol ?? null, source: source ?? null }; 1617 } 1718 };
@@ -8,7 +8,6 @@
88 99 let searchQuery = $state(''); 1010 let showDropdown = $state(false); 11- let activeSource = $derived($page.url.searchParams.get('source') ?? 'all'); 1211 1312 // Multi-select protocols from URL 1413 let activeProtocols = $derived<string[]>(() => {
@@ -49,19 +48,6 @@
4948 goto(qs ? `/?${qs}` : '/', { noScroll: true, replaceState: true }); 5049 } 5150 52- const sourceTabs = [ 53- { value: 'all', label: 'All' }, 54- { value: 'cospan', label: 'Cospan' }, 55- { value: 'tangled', label: 'Tangled' }, 56- ] as const; 57- 58- function setSource(source: string) { 59- const params = new URLSearchParams($page.url.searchParams); 60- if (source === 'all') params.delete('source'); 61- else params.set('source', source); 62- const qs = params.toString(); 63- goto(qs ? `/?${qs}` : '/', { noScroll: true, replaceState: true }); 64- } 6551 6652 function langColor(value: string): string { 6753 let hash = 0;
@@ -128,24 +114,6 @@
128114 <section> 129115 <div class="flex flex-wrap items-center justify-between gap-4 border-b border-line/40 py-4"> 130116 <div class="flex items-center gap-3"> 131- <!-- Source tabs --> 132- <div class="flex items-center gap-0.5 rounded-lg bg-surface p-1"> 133- {#each sourceTabs as tab} 134- <button 135- type="button" 136- onclick={() => setSource(tab.value)} 137- class="rounded-md px-3.5 py-1.5 text-[12px] font-medium transition-all duration-150 138- {activeSource === tab.value 139- ? 'bg-raised text-ink shadow-sm' 140- : 'text-ghost hover:text-caption'}" 141- > 142- {tab.label} 143- </button> 144- {/each} 145- </div> 146- 147- <div class="h-5 w-px bg-line/60"></div> 148- 149117 <!-- View tabs: Trending / Recent --> 150118 <div class="flex items-center gap-0.5 rounded-lg bg-surface p-1"> 151119 <button
@@ -1,4 +1,5 @@
11 <script lang="ts"> 2+ import { onMount } from 'svelte'; 23 import CommitList from '$lib/components/repo/CommitList.svelte'; 34 import RepoTabBar from '$lib/components/repo/RepoTabBar.svelte'; 45 import Breadcrumb from '$lib/components/shared/Breadcrumb.svelte';
@@ -6,22 +7,31 @@
67 import StarButton from '$lib/components/shared/StarButton.svelte'; 78 import ForkButton from '$lib/components/shared/ForkButton.svelte'; 89 import { getAuth } from '$lib/stores/auth.svelte'; 10+ import { resolveHandle } from '$lib/api/handle.js'; 911 import type { RefUpdate } from '$lib/api/ref-update.js'; 1012 1113 let { data } = $props(); 1214 1315 let auth = $derived(getAuth()); 1416 let isOwner = $derived(auth.authenticated && data.repo?.did === auth.did); 17+ let handle = $state(''); 18+ 19+ onMount(async () => { 20+ const did = data.repo?.did ?? data.did; 21+ handle = await resolveHandle(did); 22+ }); 23+ 24+ let ownerLabel = $derived(handle || data.repo?.did || data.did); 1525 1626 let basePath = $derived(data.repo ? `/${data.repo.did}/${data.repo.name}` : `/${data.did}/${data.repoName}`); 1727 1828 let crumbs = $derived(data.repo 1929 ? [ 20- { label: data.repo.did, href: `/${data.repo.did}` }, 30+ { label: ownerLabel, href: `/${data.repo.did}` }, 2131 { label: data.repo.name } 2232 ] 2333 : [ 24- { label: data.did, href: `/${data.did}` }, 34+ { label: ownerLabel, href: `/${data.did}` }, 2535 { label: data.repoName } 2636 ] 2737 );
@@ -0,0 +1,13 @@
1+import type { PageServerLoad } from './$types'; 2+import { listRepos } from '$lib/api/repo.js'; 3+ 4+export const load: PageServerLoad = async ({ url }) => { 5+ const protocol = url.searchParams.get('protocol') ?? undefined; 6+ 7+ try { 8+ const repos = await listRepos({ limit: 50, source: 'tangled', protocol } as any); 9+ return { repos, protocol: protocol ?? null }; 10+ } catch { 11+ return { repos: { items: [], cursor: null }, protocol: protocol ?? null }; 12+ } 13+};