@@ -325,6 +325,60 @@
Bluesky Thread Viewer 325325 return posts ;
326326 }
327327
328+ // Render text with facets (links, mentions, etc.)
329+ function renderTextWithFacets ( text , facets ) {
330+ if ( ! facets || ! facets . length ) {
331+ return document . createTextNode ( text ) ;
332+ }
333+
334+ // Convert string to bytes for accurate indexing
335+ const encoder = new TextEncoder ( ) ;
336+ const decoder = new TextDecoder ( ) ;
337+ const bytes = encoder . encode ( text ) ;
338+
339+ // Sort facets by start index
340+ const sorted = [ ...facets ] . sort ( ( a , b ) => a . index . byteStart - b . index . byteStart ) ;
341+
342+ const container = document . createDocumentFragment ( ) ;
343+ let lastEnd = 0 ;
344+
345+ for ( const facet of sorted ) {
346+ const { byteStart, byteEnd } = facet . index ;
347+
348+ // Add text before this facet
349+ if ( byteStart > lastEnd ) {
350+ const before = decoder . decode ( bytes . slice ( lastEnd , byteStart ) ) ;
351+ container . appendChild ( document . createTextNode ( before ) ) ;
352+ }
353+
354+ // Get the facet text
355+ const facetText = decoder . decode ( bytes . slice ( byteStart , byteEnd ) ) ;
356+
357+ // Check for link feature
358+ const linkFeature = facet . features . find ( f => f . $type === 'app.bsky.richtext.facet#link' ) ;
359+ if ( linkFeature ) {
360+ const link = document . createElement ( 'a' ) ;
361+ link . href = linkFeature . uri ;
362+ link . target = '_blank' ;
363+ link . textContent = facetText ;
364+ container . appendChild ( link ) ;
365+ } else {
366+ // For other facet types (mentions, tags), just render as text for now
367+ container . appendChild ( document . createTextNode ( facetText ) ) ;
368+ }
369+
370+ lastEnd = byteEnd ;
371+ }
372+
373+ // Add remaining text after last facet
374+ if ( lastEnd < bytes . length ) {
375+ const after = decoder . decode ( bytes . slice ( lastEnd ) ) ;
376+ container . appendChild ( document . createTextNode ( after ) ) ;
377+ }
378+
379+ return container ;
380+ }
381+
328382 // Image modal setup
329383 const imageModal = document . getElementById ( 'imageModal' ) ;
330384 const modalImg = imageModal . querySelector ( 'img' ) ;
@@ -520,7 +574,7 @@
Bluesky Thread Viewer 520574 metaEl . appendChild ( link ) ;
521575 const textEl = document . createElement ( 'div' ) ;
522576 textEl . className = 'text' ;
523- textEl . textContent = item . post . record . text ;
577+ textEl . appendChild ( renderTextWithFacets ( item . post . record . text , item . post . record . facets ) ) ;
524578 el . append ( authorEl , metaEl , textEl ) ;
525579 // Render embed if present
526580 if ( item . post . embed ) {
@@ -575,7 +629,7 @@
Bluesky Thread Viewer 575629 metaEl . appendChild ( link ) ;
576630 const textEl = document . createElement ( 'div' ) ;
577631 textEl . className = 'text' ;
578- textEl . textContent = item . post . record . text ;
632+ textEl . appendChild ( renderTextWithFacets ( item . post . record . text , item . post . record . facets ) ) ;
579633 el . append ( authorEl , metaEl , textEl ) ;
580634 // Render embed if present
581635 if ( item . post . embed ) {
0 commit comments