fix: homogenize page headers + landing shows cospan-only + import search

Author: Aaron Steven White
Commit 25a0b27b706180403a45621d9a72611d98b8c26e
Parent: 99b13f7ab7
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-cospan
4 files changed +79 -19
@@ -3,7 +3,8 @@ 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;
6+	// Landing page shows only Cospan-native repos. Tangled repos are on /import.
7+	const source = 'cospan';
78 
89 	try {
910 		const [trending, recent] = await Promise.all([
@@ -36,8 +36,8 @@
3636 </svelte:head>
3737 
3838 <section>
39-	<h1 class="mb-1 text-xl font-semibold text-text-primary">Activity Feed</h1>
40-	<p class="mb-6 text-sm text-text-muted">
39+	<h1 class="mb-1 text-lg font-semibold text-ink">Activity Feed</h1>
40+	<p class="mb-6 text-[13px] text-caption">
4141 		Recent activity from users and repositories you follow.
4242 	</p>
4343 
@@ -2,9 +2,14 @@
22 	import { onMount } from 'svelte';
33 	import type { Repo } from '$lib/api/repo.js';
44 	import { resolveHandle } from '$lib/api/handle.js';
5+	import { getAuth } from '$lib/stores/auth.svelte';
56 
67 	let { data } = $props();
78 
9+	let auth = $derived(getAuth());
10+	let searchQuery = $state('');
11+	let showMineOnly = $state(false);
12+
813 	// Resolve handles for all repos
914 	let handles = $state<Record<string, string>>({});
1015 
@@ -24,12 +29,30 @@
2429 		return handles[did] || (did.startsWith('did:plc:') ? did.slice(8, 18) + '…' : did);
2530 	}
2631 
32+	let filteredRepos = $derived(() => {
33+		let repos = data.repos.items;
34+
35+		// Filter to user's repos
36+		if (showMineOnly && auth.authenticated && auth.did) {
37+			repos = repos.filter((r: Repo) => r.did === auth.did);
38+		}
39+
40+		// Search filter
41+		if (searchQuery.trim()) {
42+			const q = searchQuery.toLowerCase();
43+			repos = repos.filter((r: Repo) =>
44+				r.name.toLowerCase().includes(q) ||
45+				(r.description ?? '').toLowerCase().includes(q) ||
46+				getHandle(r.did).toLowerCase().includes(q)
47+			);
48+		}
49+
50+		return repos;
51+	});
52+
2753 	function tangledUrl(repo: Repo): string {
28-		// Build Tangled web URL from nodeUrl or knot hostname
2954 		const host = repo.nodeUrl || '';
30-		if (host) {
31-			return `${host}/${repo.did}/${repo.name}`;
32-		}
55+		if (host) return `${host}/${repo.did}/${repo.name}`;
3356 		return `https://tangled.sh/${repo.did}/${repo.name}`;
3457 	}
3558 </script>
@@ -40,29 +63,64 @@
4063 
4164 <div class="py-2">
4265 	<!-- Header -->
43-	<div class="mb-8">
44-		<h1 class="text-2xl font-semibold text-ink">Import from Tangled</h1>
45-		<p class="mt-2 text-[14px] text-caption">
66+	<div class="mb-6">
67+		<h1 class="mb-1 text-lg font-semibold text-ink">Import from Tangled</h1>
68+		<p class="text-[13px] text-caption">
4669 			Browse repositories from the Tangled network and import them into Cospan for schema-aware version control.
4770 		</p>
4871 	</div>
4972 
73+	<!-- Search + filters -->
74+	<div class="mb-6 flex flex-wrap items-center gap-3">
75+		<div class="relative flex-1">
76+			<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">
77+				<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" />
78+			</svg>
79+			<input
80+				type="text"
81+				bind:value={searchQuery}
82+				placeholder="Search Tangled repos…"
83+				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"
84+			/>
85+		</div>
86+
87+		{#if auth.authenticated}
88+			<button
89+				type="button"
90+				onclick={() => showMineOnly = !showMineOnly}
91+				class="rounded-md px-3 py-2 text-[12px] font-medium transition-all
92+					{showMineOnly ? 'bg-focus/10 text-focus-bright border border-focus/30' : 'bg-surface text-ghost border border-line hover:text-caption'}"
93+			>
94+				My repos
95+			</button>
96+		{/if}
97+
98+		<span class="text-[11px] text-ghost">
99+			{filteredRepos().length} repos
100+		</span>
101+	</div>
102+
50103 	<!-- Repo list -->
51-	{#if data.repos.items.length === 0}
104+	{#if filteredRepos().length === 0}
52105 		<div class="flex flex-col items-center justify-center py-24 text-center">
53106 			<div class="mb-4 text-ghost">
54107 				<svg class="mx-auto h-10 w-10" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
55108 					<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" />
56109 				</svg>
57110 			</div>
58-			<p class="text-sm text-caption">No Tangled repositories found yet.</p>
59-			<p class="mt-1 text-xs text-ghost">Repositories are being backfilled from the network. Check back soon.</p>
111+			{#if searchQuery.trim()}
112+				<p class="text-sm text-caption">No repos matching "{searchQuery}"</p>
113+			{:else if showMineOnly}
114+				<p class="text-sm text-caption">No Tangled repos found for your account.</p>
115+			{:else}
116+				<p class="text-sm text-caption">No Tangled repositories found yet.</p>
117+				<p class="mt-1 text-xs text-ghost">Repositories are being backfilled from the network. Check back soon.</p>
118+			{/if}
60119 		</div>
61120 	{:else}
62121 		<div class="divide-y divide-line/40">
63-			{#each data.repos.items as repo (repo.did + '/' + repo.name)}
122+			{#each filteredRepos() as repo (repo.did + '/' + repo.name)}
64123 				<div class="flex items-start justify-between gap-4 py-4">
65-					<!-- Repo info -->
66124 					<div class="min-w-0 flex-1">
67125 						<div class="flex items-center gap-2">
68126 							<a href="/{repo.did}/{repo.name}" class="font-mono text-[14px] font-medium text-ink hover:text-focus-bright transition-colors">
@@ -90,7 +148,6 @@
90148 						</div>
91149 					</div>
92150 
93-					<!-- Import button -->
94151 					<button
95152 						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"
96153 					>
@@ -32,14 +32,16 @@
3232 </svelte:head>
3333 
3434 <section>
35-	<div class="mb-8">
35+	<div class="mb-6">
36+		<h1 class="mb-1 text-lg font-semibold text-ink">Search</h1>
37+		<p class="mb-4 text-[13px] text-caption">Find repositories across Cospan.</p>
3638 		<input
3739 			type="text"
3840 			value={inputValue}
3941 			oninput={handleInput}
4042 			onkeydown={handleKeydown}
41-			placeholder="Search repositories..."
42-			class="w-full border-0 border-b-2 border-border bg-transparent pb-3 text-xl text-text-primary placeholder:text-text-muted focus:border-accent focus:outline-none"
43+			placeholder="Search repositories…"
44+			class="w-full rounded-md border border-line bg-surface px-3 py-2 text-[14px] text-ink placeholder:text-ghost focus:border-focus/50 focus:outline-none transition-colors"
4345 		/>
4446 	</div>
4547 
cospan · schematic version control on atproto built on AT Protocol