feat: add Bluesky thread Alpine.js component
Build & Deploy / build-and-deploy (push) Has been cancelled
Build & Deploy / build-and-deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* Client-side Bluesky thread fetcher (Alpine.js)
|
||||||
|
* Fetches a Bluesky post thread via the public AT Protocol API
|
||||||
|
* and renders replies in a nested conversation view.
|
||||||
|
*/
|
||||||
|
|
||||||
|
document.addEventListener("alpine:init", () => {
|
||||||
|
Alpine.data("bskyThread", (bskyUrl) => ({
|
||||||
|
replies: [],
|
||||||
|
loading: true,
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
try {
|
||||||
|
const match = bskyUrl.match(/bsky\.app\/profile\/([^/?#]+)\/post\/([^/?#]+)/);
|
||||||
|
if (!match) { this.loading = false; return; }
|
||||||
|
|
||||||
|
const [, actor, rkey] = match;
|
||||||
|
const atUri = `at://${actor}/app.bsky.feed.post/${rkey}`;
|
||||||
|
const res = await fetch(
|
||||||
|
`https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=${encodeURIComponent(atUri)}&depth=10`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
const data = await res.json();
|
||||||
|
this.replies = this._flatten(data.thread, 0);
|
||||||
|
} catch {
|
||||||
|
// Fail silently — section stays hidden if loading stays true... no, set empty
|
||||||
|
this.replies = [];
|
||||||
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_flatten(node, depth) {
|
||||||
|
const out = [];
|
||||||
|
for (const r of (node.replies || [])) {
|
||||||
|
if (r.$type !== "app.bsky.feed.defs#threadViewPost") continue;
|
||||||
|
const p = r.post;
|
||||||
|
const rkey = p.uri.split("/").pop();
|
||||||
|
out.push({
|
||||||
|
depth: Math.min(depth, 3),
|
||||||
|
uri: p.uri,
|
||||||
|
url: `https://bsky.app/profile/${p.author.handle}/post/${rkey}`,
|
||||||
|
author: {
|
||||||
|
name: p.author.displayName || p.author.handle,
|
||||||
|
handle: p.author.handle,
|
||||||
|
avatar: p.author.avatar || "",
|
||||||
|
url: `https://bsky.app/profile/${p.author.handle}`,
|
||||||
|
},
|
||||||
|
text: p.record.text,
|
||||||
|
published: p.record.createdAt,
|
||||||
|
likeCount: p.likeCount || 0,
|
||||||
|
});
|
||||||
|
out.push(...this._flatten(r, depth + 1));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
|
||||||
|
formatDate(dateStr) {
|
||||||
|
try {
|
||||||
|
return new Date(dateStr).toLocaleDateString("de-DE", {
|
||||||
|
day: "numeric", month: "long", year: "numeric",
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return dateStr;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user