Thread viewer for Bluesky
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>