Files
boris/src/utils/highlightMatching.tsx
Gigi 59ecc29b9c refactor(highlights): split highlighting utilities into modules
- Create textMatching module for text search utilities
- Create domUtils module for DOM manipulation helpers
- Create htmlMatching module for HTML highlight application
- Reduce highlightMatching.tsx from 217 lines to 59 lines
- All files now under 210 lines
2025-10-07 21:54:41 +01:00

60 lines
1.7 KiB
TypeScript

import React from 'react'
import { Highlight } from '../types/highlights'
export type { HighlightMatch } from './highlightMatching/textMatching'
export { findHighlightMatches } from './highlightMatching/textMatching'
export { applyHighlightsToHTML } from './highlightMatching/htmlMatching'
import { findHighlightMatches as _findHighlightMatches } from './highlightMatching/textMatching'
/**
* Apply highlights to text content by wrapping matched text in span elements
*/
export function applyHighlightsToText(
text: string,
highlights: Highlight[]
): React.ReactNode {
const matches = _findHighlightMatches(text, highlights)
if (matches.length === 0) {
return text
}
const result: React.ReactNode[] = []
let lastIndex = 0
for (let i = 0; i < matches.length; i++) {
const match = matches[i]
if (match.startIndex < lastIndex) {
continue
}
if (match.startIndex > lastIndex) {
result.push(text.substring(lastIndex, match.startIndex))
}
const highlightedText = text.substring(match.startIndex, match.endIndex)
const levelClass = match.highlight.level ? ` level-${match.highlight.level}` : ''
result.push(
<mark
key={`highlight-${match.highlight.id}-${match.startIndex}`}
className={`content-highlight${levelClass}`}
data-highlight-id={match.highlight.id}
data-highlight-level={match.highlight.level || 'nostrverse'}
title={`Highlighted ${new Date(match.highlight.created_at * 1000).toLocaleDateString()}`}
>
{highlightedText}
</mark>
)
lastIndex = match.endIndex
}
if (lastIndex < text.length) {
result.push(text.substring(lastIndex))
}
return <>{result}</>
}