diff options
| author | Guillermo Serrahima <dev@vylion.com> | 2026-02-20 16:21:00 +0100 |
|---|---|---|
| committer | Guillermo Serrahima <dev@vylion.com> | 2026-02-20 16:23:30 +0100 |
| commit | 4a2a8c34e87c5dd25f6d01a1aafaa10799aa907f (patch) | |
| tree | b3b090a38a2e2748cd110a043e6369be9450e063 /frontend/src | |
| parent | e4c0caadc07b050ca827483263d15d2c118df3d2 (diff) | |
| download | llostre-4a2a8c34e87c5dd25f6d01a1aafaa10799aa907f.tar.xz llostre-4a2a8c34e87c5dd25f6d01a1aafaa10799aa907f.zip | |
added facets and markdown rendering
Diffstat (limited to 'frontend/src')
| -rw-r--r-- | frontend/src/main.ts | 63 | ||||
| -rw-r--r-- | frontend/src/style.css | 7 |
2 files changed, 68 insertions, 2 deletions
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 += `<a href="${facet.value}" target="_blank">${facetText}</a>`; + break; + case 'mention': + result += `<a href="https://bsky.app/profile/${facet.value}" target="_blank">${facetText}</a>`; + break; + case 'tag': + result += `<a href="https://bsky.app/hashtag/${facet.value}" target="_blank">#${facetText}</a>`; + 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 = ` <div class="note"> <img class="note-avatar" src="https://cdn.bsky.app/img/avatar/plain/did:plc:hyyqbqqhpxt2bnn7s2e2iuxd/bafkreidoiynom7v2y5rpsm467l3d2cnr7ozvlfusrchjey3k2jtyquufq4@jpeg" alt="avatar"> <div class="note-content"> <div style="font-weight: bold">@${post.authorHandle}</div> - <div class="note-text">${post.text || '<br>'}</div> + <div class="note-text">${postText || '<br>'}</div> <div style="font-size: 12px; color: #888">${new Date(post.createdAt).toLocaleString()}</div> </div> </div> diff --git a/frontend/src/style.css b/frontend/src/style.css index 13d2217..549c596 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -60,6 +60,11 @@ h1 { white-space: pre-wrap; } +.muted { + opacity: 0.5; + font-size: 12px; +} + .spinner { border: 16px solid #f3f3f3; border-top: 16px solid #3498db; @@ -80,4 +85,4 @@ h1 { color: #213547; background-color: #ffffff; } -}
\ No newline at end of file +} |
