From fb4d93d005816c5db7e7737a959b6435d4dd2f8f Mon Sep 17 00:00:00 2001
From: Florian <45694132+flo-bit@users.noreply.github.com>
Date: Sat, 14 Feb 2026 20:18:37 +0100
Subject: [PATCH] add og images
---
docs/Autofill.md | 2 +-
src/lib/atproto/methods.ts | 6 +-
src/lib/cards/social/EventCard/index.ts | 3 +-
src/routes/[[actor=actor]]/e/+page.server.ts | 77 ++++++++
src/routes/[[actor=actor]]/e/+page.svelte | 170 ++++++++++++++++++
.../[[actor=actor]]/e/[rkey]/+page.svelte | 20 ++-
.../e/[rkey]/og.png/+server.ts | 84 +++++++++
.../e/[rkey]/og.png/EventOgImage.svelte | 63 +++++++
8 files changed, 416 insertions(+), 9 deletions(-)
create mode 100644 src/routes/[[actor=actor]]/e/+page.server.ts
create mode 100644 src/routes/[[actor=actor]]/e/+page.svelte
create mode 100644 src/routes/[[actor=actor]]/e/[rkey]/og.png/+server.ts
create mode 100644 src/routes/[[actor=actor]]/e/[rkey]/og.png/EventOgImage.svelte
diff --git a/docs/Autofill.md b/docs/Autofill.md
index 2b0c690..462f266 100644
--- a/docs/Autofill.md
+++ b/docs/Autofill.md
@@ -11,7 +11,7 @@
- blue.flashes.actor.portfolio
- social.grain.gallery
- xyz.statusphere.status
- - site.standard.publication
+ - site.standard.publication
- fm.teal.alpha.feed.play
- dev.npmx.feed.like
- add bluesky profile card
diff --git a/src/lib/atproto/methods.ts b/src/lib/atproto/methods.ts
index 7ed0b2f..0bf31db 100644
--- a/src/lib/atproto/methods.ts
+++ b/src/lib/atproto/methods.ts
@@ -395,7 +395,8 @@ export async function getBlobURL({
*/
export function getCDNImageBlobUrl({
did,
- blob
+ blob,
+ type = 'webp'
}: {
did?: string;
blob: {
@@ -404,11 +405,12 @@ export function getCDNImageBlobUrl({
$link: string;
};
};
+ type?: 'webp' | 'jpeg';
}) {
if (!blob || !did) return;
did ??= user.did;
- return `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${blob.ref.$link}@webp`;
+ return `https://cdn.bsky.app/img/feed_thumbnail/plain/${did}/${blob.ref.$link}@${type}`;
}
/**
diff --git a/src/lib/cards/social/EventCard/index.ts b/src/lib/cards/social/EventCard/index.ts
index 0e8baf3..8d14aa1 100644
--- a/src/lib/cards/social/EventCard/index.ts
+++ b/src/lib/cards/social/EventCard/index.ts
@@ -24,7 +24,8 @@ export type EventData = {
alt?: string;
role?: string;
content?: {
- ref?: {
+ $type: 'blob';
+ ref: {
$link: string;
};
mimeType?: string;
diff --git a/src/routes/[[actor=actor]]/e/+page.server.ts b/src/routes/[[actor=actor]]/e/+page.server.ts
new file mode 100644
index 0000000..e94b77e
--- /dev/null
+++ b/src/routes/[[actor=actor]]/e/+page.server.ts
@@ -0,0 +1,77 @@
+import { error } from '@sveltejs/kit';
+import type { EventData } from '$lib/cards/social/EventCard';
+import { getBlentoOrBskyProfile, resolveHandle } from '$lib/atproto/methods.js';
+import { isHandle } from '@atcute/lexicons/syntax';
+import { createCache, type CachedProfile } from '$lib/cache';
+import type { ActorIdentifier, Did } from '@atcute/lexicons';
+import { env as publicEnv } from '$env/dynamic/public';
+
+export async function load({ params, platform, request }) {
+ const cache = createCache(platform);
+
+ const customDomain = request.headers.get('X-Custom-Domain')?.toLowerCase();
+
+ let actor: ActorIdentifier | undefined = params.actor;
+
+ if (!actor) {
+ const kv = platform?.env?.CUSTOM_DOMAINS;
+
+ if (kv && customDomain) {
+ try {
+ const did = await kv.get(customDomain);
+
+ if (did) actor = did as ActorIdentifier;
+ } catch (error) {
+ console.error('failed to get custom domain kv', error);
+ }
+ } else {
+ actor = publicEnv.PUBLIC_HANDLE as ActorIdentifier;
+ }
+ } else if (customDomain && params.actor) {
+ actor = undefined;
+ }
+
+ const did = isHandle(actor) ? await resolveHandle({ handle: actor }) : actor;
+
+ if (!did) {
+ throw error(404, 'Events not found');
+ }
+
+ try {
+ const [eventsResponse, hostProfile] = await Promise.all([
+ fetch(
+ `https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?repository=${encodeURIComponent(did)}&query=upcoming`
+ ),
+ cache
+ ? cache.getProfile(did as Did).catch(() => null)
+ : getBlentoOrBskyProfile({ did: did as Did })
+ .then(
+ (p): CachedProfile => ({
+ did: p.did as string,
+ handle: p.handle as string,
+ displayName: p.displayName as string | undefined,
+ avatar: p.avatar as string | undefined,
+ hasBlento: p.hasBlento,
+ url: p.url
+ })
+ )
+ .catch(() => null)
+ ]);
+
+ if (!eventsResponse.ok) {
+ throw error(404, 'Events not found');
+ }
+
+ const data: { results: EventData[] } = await eventsResponse.json();
+ const events = data.results;
+
+ return {
+ events,
+ did,
+ hostProfile: hostProfile ?? null
+ };
+ } catch (e) {
+ if (e && typeof e === 'object' && 'status' in e) throw e;
+ throw error(404, 'Events not found');
+ }
+}
diff --git a/src/routes/[[actor=actor]]/e/+page.svelte b/src/routes/[[actor=actor]]/e/+page.svelte
new file mode 100644
index 0000000..6a67240
--- /dev/null
+++ b/src/routes/[[actor=actor]]/e/+page.svelte
@@ -0,0 +1,170 @@
+
+
+
Hosted by {hostName}
+No events found.
+ {:else} ++ {formatDate(event.startsAt)} · {formatTime(event.startsAt)} +
+ ++ {event.countGoing} going +
+ {/if} +