jan/web-app/src/utils/highlight.ts
Sam Hoang Van ad962c2cf6
feat(webapp): Replace Fuse.js with Fzf for thread search and enhance highlighting (#5052)
This commit replaces Fuse.js with Fzf for client-side thread searching
within the web application, offering potentially improved performance and
a different fuzzy matching algorithm.

Key changes include:

- Updated `package.json` to remove `fuse.js` and add `fzf`.
- Refactored `useThreads.ts` hook:
    - Replaced Fuse.js instantiation and search logic with Fzf.
    - Integrated a new `highlightFzfMatch` utility to return thread
      titles with HTML highlighting for matched characters.
- Created `utils/highlight.ts` for the `highlightFzfMatch` function.
- Updated `ThreadList.tsx`:
    - Renders highlighted thread titles using `dangerouslySetInnerHTML`.
    - Ensures the rename functionality uses and edits a plain text
      version of the title, stripping any highlight tags.
- Updated `index.css`:
    - Modified the `.search-highlight` class to use `font-bold` and
      `color-mix(in srgb, currentColor 80%, white 20%)` for a
      subtly brighter text effect on highlighted matches, replacing
      previous styling.

This provides a more robust search experience with clear visual feedback
for matched terms in the thread list.
2025-05-21 22:31:01 +07:00

41 lines
1.2 KiB
TypeScript

// web-app/src/utils/highlight.ts
export function highlightFzfMatch(text: string, positions: number[], highlightClassName: string = "search-highlight") {
if (!text || !positions || !positions.length) return text;
const parts: { text: string; highlight: boolean }[] = [];
let lastIndex = 0;
// Sort positions to ensure we process them in order
const sortedPositions = [...positions].sort((a, b) => a - b);
sortedPositions.forEach((pos) => {
if (pos > lastIndex) {
parts.push({
text: text.substring(lastIndex, pos),
highlight: false
});
}
if (pos < text.length) { // Ensure pos is within bounds
parts.push({
text: text[pos],
highlight: true
});
}
lastIndex = pos + 1;
});
if (lastIndex < text.length) {
parts.push({
text: text.substring(lastIndex),
highlight: false
});
}
return parts
.map(part =>
part.highlight
? `<span class="${highlightClassName}">${part.text}</span>`
: part.text
)
.join('');
}