diff --git a/src/lib/atproto/settings.ts b/src/lib/atproto/settings.ts index 1b26ac8..e812e6b 100644 --- a/src/lib/atproto/settings.ts +++ b/src/lib/atproto/settings.ts @@ -24,7 +24,8 @@ export const permissions = { 'site.standard.document', 'xyz.statusphere.status', 'community.lexicon.calendar.rsvp', - 'community.lexicon.calendar.event' + 'community.lexicon.calendar.event', + 'app.nearhorizon.actor.pronouns' ], // what types of authenticated proxied requests you can make to services diff --git a/src/lib/helper.ts b/src/lib/helper.ts index a208837..d891902 100644 --- a/src/lib/helper.ts +++ b/src/lib/helper.ts @@ -291,6 +291,28 @@ export async function savePage( console.log('updating or adding publication', data.publication); } + // check if pronouns edited and save + if (data.pronounsRecord?.value?.sets?.length) { + const existing = data.pronounsRecord.value; + const now = new Date().toISOString(); + const record: Record = { + $type: 'app.nearhorizon.actor.pronouns', + sets: existing.sets, + displayMode: existing.displayMode ?? 'all', + createdAt: existing.createdAt ?? now + }; + if (existing.createdAt) { + record.updatedAt = now; + } + promises.push( + putRecord({ + collection: 'app.nearhorizon.actor.pronouns', + rkey: 'self', + record + }) + ); + } + await Promise.all(promises); } diff --git a/src/lib/types.ts b/src/lib/types.ts index b4dfa50..56394f7 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -27,6 +27,19 @@ export type Item = { page?: string; }; +export type PronounSet = { + forms: string[]; +}; + +export type PronounsRecord = { + value?: { + sets?: PronounSet[]; + displayMode?: string; + createdAt?: string; + updatedAt?: string; + }; +}; + export type WebsiteData = { page: string; did: string; @@ -61,6 +74,8 @@ export type WebsiteData = { }; }; profile: AppBskyActorDefs.ProfileViewDetailed; + pronouns?: string; + pronounsRecord?: PronounsRecord; additionalData: Record; updatedAt: number; diff --git a/src/lib/website/EditableProfile.svelte b/src/lib/website/EditableProfile.svelte index 80fb369..e725c41 100644 --- a/src/lib/website/EditableProfile.svelte +++ b/src/lib/website/EditableProfile.svelte @@ -1,16 +1,32 @@
{/if} + {#if editingPronouns} +
+
+ {#each pronounSets as set, i (i)} +
0 && 'opacity-40' + ]} + > + updateSetInput(i, e.currentTarget.value)} + placeholder="e.g. she/her" + class="bg-base-100 dark:bg-base-800 text-base-600 dark:text-base-300 w-full rounded px-2 py-1 text-sm outline-none" + /> + {#if pronounSets.length > 1} + + {/if} +
+ {/each} +
+ {#if pronounSets.length > 1} +
+ { + displayMode = checked ? 'firstOnly' : 'all'; + updatePronouns(); + }} + class="scale-75" + /> + +
+ {/if} +
+ {#if pronounSets.length < 10} + + {/if} + +
+
+ {:else} + + {/if} +
{#if data.publication} diff --git a/src/lib/website/EditableWebsite.svelte b/src/lib/website/EditableWebsite.svelte index a811cdd..99ef9bb 100644 --- a/src/lib/website/EditableWebsite.svelte +++ b/src/lib/website/EditableWebsite.svelte @@ -65,6 +65,9 @@ // svelte-ignore state_referenced_locally let savedItemsSnapshot = JSON.stringify(data.cards); + // svelte-ignore state_referenced_locally + let savedPronouns = $state(JSON.stringify(data.pronounsRecord)); + let hasUnsavedChanges = $state(false); // Detect card content and publication changes (e.g. sidebar edits) @@ -75,7 +78,8 @@ if (hasUnsavedChanges) return; if ( JSON.stringify(items) !== savedItemsSnapshot || - JSON.stringify(data.publication) !== publication + JSON.stringify(data.publication) !== publication || + JSON.stringify(data.pronounsRecord) !== savedPronouns ) { hasUnsavedChanges = true; } @@ -226,6 +230,7 @@ await savePage(data, items, publication); publication = JSON.stringify(data.publication); + savedPronouns = JSON.stringify(data.pronounsRecord); savedItemsSnapshot = JSON.stringify(items); hasUnsavedChanges = false; diff --git a/src/lib/website/Profile.svelte b/src/lib/website/Profile.svelte index 872aaee..94b5765 100644 --- a/src/lib/website/Profile.svelte +++ b/src/lib/website/Profile.svelte @@ -61,6 +61,12 @@ {getName(data)}
+ {#if data.pronouns} +
+ {data.pronouns} +
+ {/if} +
s.forms.join('/')).join(' · '); + } + // fallback to bsky pronouns + const pronouns = (profile as Record)?.pronouns; + if (pronouns && typeof pronouns === 'string') return pronouns; + return undefined; +} + export async function getCache(identifier: ActorIdentifier, page: string, cache?: CacheService) { try { const cachedResult = await cache?.getBlento(identifier); @@ -66,7 +83,7 @@ export async function loadData( throw error(404); } - const [cards, mainPublication, pages, profile] = await Promise.all([ + const [cards, mainPublication, pages, profile, pronounsRecord] = await Promise.all([ listRecords({ did, collection: 'app.blento.card', limit: 0 }).catch((e) => { console.error('error getting records for collection app.blento.card', e); return [] as Awaited>; @@ -83,7 +100,12 @@ export async function loadData( console.error('error getting records for collection app.blento.page'); return [] as Awaited>; }), - getDetailedProfile({ did }) + getDetailedProfile({ did }), + getRecord({ + did, + collection: 'app.nearhorizon.actor.pronouns', + rkey: 'self' + }).catch(() => undefined) ]); const additionalData = await loadAdditionalData( @@ -102,6 +124,8 @@ export async function loadData( publications: [mainPublication, ...pages].filter((v) => v), additionalData, profile, + pronouns: formatPronouns(pronounsRecord, profile), + pronounsRecord: pronounsRecord as PronounsRecord | undefined, updatedAt: Date.now(), version: CURRENT_CACHE_VERSION }; @@ -145,13 +169,18 @@ export async function loadCardData( throw error(404); } - const [cardRecord, profile] = await Promise.all([ + const [cardRecord, profile, pronounsRecord] = await Promise.all([ getRecord({ did, collection: 'app.blento.card', rkey }).catch(() => undefined), - getDetailedProfile({ did }) + getDetailedProfile({ did }), + getRecord({ + did, + collection: 'app.nearhorizon.actor.pronouns', + rkey: 'self' + }).catch(() => undefined) ]); if (!cardRecord?.value) { @@ -189,6 +218,8 @@ export async function loadCardData( } as WebsiteData['publication']), additionalData, profile, + pronouns: formatPronouns(pronounsRecord, profile), + pronounsRecord: pronounsRecord as PronounsRecord | undefined, updatedAt: Date.now(), version: CURRENT_CACHE_VERSION }; @@ -220,13 +251,18 @@ export async function loadCardTypeData( throw error(404); } - const [publication, profile] = await Promise.all([ + const [publication, profile, pronounsRecord] = await Promise.all([ getRecord({ did, collection: 'site.standard.publication', rkey: 'blento.self' }).catch(() => undefined), - getDetailedProfile({ did }) + getDetailedProfile({ did }), + getRecord({ + did, + collection: 'app.nearhorizon.actor.pronouns', + rkey: 'self' + }).catch(() => undefined) ]); const card = createEmptyCard('blento.self'); @@ -260,6 +296,8 @@ export async function loadCardTypeData( } as WebsiteData['publication']), additionalData, profile, + pronouns: formatPronouns(pronounsRecord, profile), + pronounsRecord: pronounsRecord as PronounsRecord | undefined, updatedAt: Date.now(), version: CURRENT_CACHE_VERSION };