A calm place to write long-form, and publish it to the open social web.
skypress.blog/
1import type { Agent } from '@atproto/api';
2
3/** The signed-in writer's identity, as shown in the home pill and editor bar. */
4export interface ViewerProfile {
5 did: string;
6 handle: string | null;
7 displayName: string | null;
8 avatar: string | null;
9}
10
11/**
12 * Fetch the viewer's profile for display. Wraps a single `getProfile` call and
13 * never throws: on failure (e.g. the appview is unreachable) it returns the DID
14 * with null display fields, so callers always have something to render.
15 */
16export async function fetchViewerProfile( agent: Agent, did: string ): Promise< ViewerProfile > {
17 try {
18 const { data } = await agent.getProfile( { actor: did } );
19 return {
20 did,
21 handle: data.handle ?? null,
22 displayName: data.displayName ?? null,
23 avatar: data.avatar ?? null,
24 };
25 } catch {
26 return { did, handle: null, displayName: null, avatar: null };
27 }
28}
29
30/** Best display label for a viewer: real name, else handle, else the raw DID. */
31export function displayNameFor( profile: ViewerProfile ): string {
32 return profile.displayName ?? profile.handle ?? profile.did;
33}
34
35/**
36 * Public author-page path for a handle (the `/[author]` route requires a leading
37 * `@` and resolves by handle). Returns null when no handle is known, so callers
38 * can omit the link rather than render a broken one.
39 */
40export function authorPath( handle: string | null ): string | null {
41 return handle ? `/@${ handle }` : null;
42}
43
44/** One entry in the signed-in account dropdown. */
45export interface MenuItem {
46 label: string;
47 href: string;
48}
49
50/**
51 * Dropdown items for a signed-in viewer: Dashboard, Write, then Profile. The
52 * Profile entry links to the public author page and is omitted when no handle
53 * is known (so we never render a broken link).
54 */
55export function accountMenuItems( profile: ViewerProfile ): MenuItem[] {
56 const items: MenuItem[] = [
57 { label: 'Dashboard', href: '/dashboard' },
58 { label: 'Write', href: '/write' },
59 ];
60 const profileHref = authorPath( profile.handle );
61 if ( profileHref ) {
62 items.push( { label: 'Profile', href: profileHref } );
63 }
64 return items;
65}