a simple pds frontend for listing accounts and generating invite codes
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

improved handling for empty, but activated repos

this also has a new variable PINNED_DIDS for putting your own/admin accounts at the top of the list, no extra styling is applied

Winter e3b66a72 fecb9e86

+31 -3
+6
src/lib/server/env.ts
··· 14 14 15 15 // rate limit window in ms (env var is in seconds, default 86400 = 24h) 16 16 export const INVITE_RATE_WINDOW = (parseInt(env.INVITE_RATE_WINDOW ?? '86400', 10) || 86400) * 1000; 17 + 18 + // comma-separated DIDs to pin at the top of the account list 19 + export const PINNED_DIDS: string[] = (env.PINNED_DIDS ?? '') 20 + .split(',') 21 + .map((d) => d.trim()) 22 + .filter(Boolean);
+15 -3
src/routes/+page.server.ts
··· 1 1 import type { PageServerLoad } from './$types'; 2 2 import { publicRpc } from '$lib/server/pds'; 3 - import { CDN_URL } from '$lib/server/env'; 3 + import { CDN_URL, PINNED_DIDS } from '$lib/server/env'; 4 4 5 5 const DID_RE = /^did:[a-z]+:[a-zA-Z0-9._:%-]+$/; 6 6 ··· 71 71 72 72 let displayName: string | null = null; 73 73 let avatarUrl: string | null = null; 74 - if (profileResult.status === 'fulfilled') { 75 - const value = profileResult.value.data.value as Record<string, unknown>; 74 + const value = 75 + profileResult.status === 'fulfilled' 76 + ? (profileResult.value.data.value as Record<string, unknown> | undefined) 77 + : undefined; 78 + if (value) { 76 79 if (typeof value.displayName === 'string' && value.displayName.trim()) { 77 80 displayName = value.displayName.trim().slice(0, 640); 78 81 } ··· 95 98 const accounts: Account[] = results 96 99 .filter((r) => r.status === 'fulfilled') 97 100 .map((r) => (r as PromiseFulfilledResult<Account>).value); 101 + 102 + if (PINNED_DIDS.length) { 103 + const pinSet = new Set(PINNED_DIDS); 104 + accounts.sort((a, b) => { 105 + const ap = pinSet.has(a.did) ? PINNED_DIDS.indexOf(a.did) : Infinity; 106 + const bp = pinSet.has(b.did) ? PINNED_DIDS.indexOf(b.did) : Infinity; 107 + return ap - bp; 108 + }); 109 + } 98 110 99 111 return { accounts, contactEmail }; 100 112 };
+10
src/routes/+page.svelte
··· 81 81 loading="lazy" 82 82 onerror={(e) => ((e.currentTarget as HTMLImageElement).style.visibility = "hidden")} 83 83 /> 84 + {:else} 85 + <div class="avatar avatar-placeholder">?</div> 84 86 {/if} 85 87 <div class="account-info"> 86 88 {#if account.displayName} ··· 253 255 object-fit: cover; 254 256 flex-shrink: 0; 255 257 background-color: oklch(from var(--color-fg) l c h / 0.1); 258 + } 259 + 260 + .avatar-placeholder { 261 + display: flex; 262 + align-items: center; 263 + justify-content: center; 264 + font-size: 1.25rem; 265 + color: oklch(from var(--color-fg) l c h / 0.4); 256 266 } 257 267 258 268 .account-info {