Thread viewer for Bluesky
at 2.0 78 lines 2.1 kB view raw
1<script lang="ts"> 2 import { getPostContext } from './PostComponent.svelte'; 3 import { sanitizeHTML } from '../../utils.js'; 4 import { type Facet } from '../../../lib/rich_text_lite.js'; 5 import RichTextFromFacets from '../RichTextFromFacets.svelte'; 6 7 const highlightID = 'search-results'; 8 9 let { post } = getPostContext(); 10 let { highlightedMatches = undefined }: { highlightedMatches?: string[] | undefined } = $props(); 11 12 let bodyElement: HTMLElement | undefined = $state(); 13 14 function highlightSearchResults(terms: string[]) { 15 let regexp = new RegExp(`\\b(${terms.join('|')})\\b`, 'gi'); 16 let walker = document.createTreeWalker(bodyElement!, NodeFilter.SHOW_TEXT); 17 let ranges: Range[] = []; 18 19 while (walker.nextNode()) { 20 let node = walker.currentNode; 21 if (!node.textContent) { continue; } 22 23 regexp.lastIndex = 0; 24 25 for (;;) { 26 let match = regexp.exec(node.textContent); 27 if (match === null) break; 28 29 let range = new Range(); 30 range.setStart(node, match.index); 31 range.setEnd(node, match.index + match[0].length); 32 ranges.push(range); 33 } 34 } 35 36 let highlight = CSS.highlights.get(highlightID) || new Highlight(); 37 ranges.forEach(r => highlight.add(r)); 38 CSS.highlights.set(highlightID, highlight); 39 } 40 41 $effect(() => { 42 if (highlightedMatches && highlightedMatches.length > 0) { 43 highlightSearchResults(highlightedMatches); 44 45 return () => { 46 CSS.highlights.delete(highlightID); 47 }; 48 } else { 49 return; 50 } 51 }); 52</script> 53 54{#if post.originalFediContent} 55 <div class="bridged-body" bind:this={bodyElement}> 56 {@html sanitizeHTML(post.originalFediContent)} 57 </div> 58{:else} 59 <p class="body" bind:this={bodyElement}> 60 <RichTextFromFacets text={post.text} facets={post.facets as Facet[]} /> 61 </p> 62{/if} 63 64<style> 65 .bridged-body :global(p + p) { 66 margin-top: 18px; 67 } 68 69 ::highlight(search-results) { 70 background-color: rgba(255, 255, 0, 0.75); 71 } 72 73 @media (prefers-color-scheme: dark) { 74 ::highlight(search-results) { 75 background-color: rgba(255, 255, 0, 0.35); 76 } 77 } 78</style>