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 facet 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);
return result;
}
function renderAuthor(note: any): string {
const hasDisplayName = note.authorName && note.authorName !== '';
const hasValidHandle = note.authorHandle !== 'handle.invalid';
const pronouns = note.pronouns ? `@${note.authorHandle}`;
} else if (hasDisplayName && !hasValidHandle) {
return `
${note.authorName}${pronouns}
⚠️ InvalidHandle
`;
} else if (!hasDisplayName && hasValidHandle) {
return `
@${note.authorHandle}${pronouns}
`;
} else {
return `
⚠️ InvalidHandle${pronouns}
`;
}
}
async function main() {
const app = document.querySelector('#app');
if (!app) {
console.error('App container not found');
throw new Error('App container not found');
}
app.innerHTML = '';
try {
const response = await fetch('http://localhost:8080/api/posts');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const notes = await response.json();
app.innerHTML = '';
for (const note of notes) {
let parsedText = '';
if(note.facets && note.facets.length > 0) {
parsedText = renderTextWithFacets(note.text || '', note.facets || []);
} else {
parsedText = note.text;
}
const noteText = marked.parseInline(parsedText, { breaks: true });
const postHTML = `