From 4a2a8c34e87c5dd25f6d01a1aafaa10799aa907f Mon Sep 17 00:00:00 2001 From: Guillermo Serrahima Date: Fri, 20 Feb 2026 16:21:00 +0100 Subject: added facets and markdown rendering --- frontend/src/main.ts | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) (limited to 'frontend/src/main.ts') diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 099193a..f53632c 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,5 +1,58 @@ +import { marked } from 'marked'; import './style.css' +function renderTextWithFacets(text: string, facets: any[]): string { + if (!facets || facets.length === 0) { + return text; + } + + // convert text to UTF-8 bytes because Bluesky counts bytes in UTF-8 + const encoder = new TextEncoder(); + const postBytes = encoder.encode(text); + + // sort facets by start position + facets.sort((a, b) => a.byteStart - b.byteStart); + + let result = ''; + let lastPos = 0; + + const decoder = new TextDecoder(); + for (const facet of facets) { + // add text before this facet + const beforeBytes = postBytes.slice(lastPos, facet.byteStart); + result += decoder.decode(beforeBytes); + + // add the faceted text as a link + const facetBytes = postBytes.slice(facet.byteStart, facet.byteEnd); + const facetText = decoder.decode(facetBytes); + + switch (facet.type) { + case 'link': + result += `${facetText}`; + break; + case 'mention': + result += `${facetText}`; + break; + case 'tag': + result += `#${facetText}`; + break; + default: // in case Bluesky ever adds other fcaet types + result += facetText; // if we don't recognize the type, just add it as plain text + break; + } + + lastPos = facet.byteEnd; + } + + // add remaining text + const remainingBytes = postBytes.slice(lastPos); + result += decoder.decode(remainingBytes); + + console.log(result); + + return result; +} + async function main() { const app = document.querySelector('#app'); if (!app) { @@ -17,12 +70,20 @@ async function main() { app.innerHTML = ''; for (const post of posts) { + let parsedText = ''; + if(post.facets && post.facets.length > 0) { + parsedText = renderTextWithFacets(post.text || '', post.facets || []); + } else { + parsedText = post.text; + } + const postText = marked.parseInline(parsedText, { breaks: true }); + const postHTML = `
avatar
@${post.authorHandle}
-
${post.text || '
'}
+
${postText || '
'}
${new Date(post.createdAt).toLocaleString()}
-- cgit v1.2.3