diff --git a/src/components/ContentPanel.tsx b/src/components/ContentPanel.tsx index 2aa5fef4..871ae898 100644 --- a/src/components/ContentPanel.tsx +++ b/src/components/ContentPanel.tsx @@ -6,6 +6,7 @@ import { faSpinner, faHighlighter, faClock } from '@fortawesome/free-solid-svg-i import { Highlight } from '../types/highlights' import { applyHighlightsToHTML } from '../utils/highlightMatching' import { readingTime } from 'reading-time-estimator' +import { filterHighlightsByUrl } from '../utils/urlHelpers' interface ContentPanelProps { loading: boolean @@ -51,35 +52,7 @@ const ContentPanel: React.FC = ({ } }, [selectedHighlightId]) - // Filter highlights relevant to the current URL - const relevantHighlights = useMemo(() => { - if (!selectedUrl || highlights.length === 0) return [] - - // Normalize URLs for comparison (remove trailing slashes, protocols, www, query params, fragments) - const normalizeUrl = (url: string) => { - try { - const urlObj = new URL(url.startsWith('http') ? url : `https://${url}`) - // Get just the hostname + pathname, remove trailing slash - return `${urlObj.hostname.replace(/^www\./, '')}${urlObj.pathname}`.replace(/\/$/, '').toLowerCase() - } catch { - // Fallback for invalid URLs - return url.replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/$/, '').toLowerCase() - } - } - - const normalizedSelected = normalizeUrl(selectedUrl) - - const filtered = highlights.filter(h => { - if (!h.urlReference) return false - - const normalizedRef = normalizeUrl(h.urlReference) - return normalizedSelected === normalizedRef || - normalizedSelected.includes(normalizedRef) || - normalizedRef.includes(normalizedSelected) - }) - - return filtered - }, [selectedUrl, highlights]) + const relevantHighlights = useMemo(() => filterHighlightsByUrl(highlights, selectedUrl), [selectedUrl, highlights]) // Store original HTML when content changes useEffect(() => { @@ -144,11 +117,7 @@ const ContentPanel: React.FC = ({ } }, [onHighlightClick, relevantHighlights]) - const highlightedMarkdown = useMemo(() => { - if (!markdown || relevantHighlights.length === 0) return markdown - // For markdown, we'll apply highlights after rendering - return markdown - }, [markdown, relevantHighlights]) + const highlightedMarkdown = useMemo(() => markdown, [markdown]) // Calculate reading time from content (must be before early returns) const readingStats = useMemo(() => { @@ -219,5 +188,3 @@ const ContentPanel: React.FC = ({ } export default ContentPanel - - diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx index c6ed8531..5210ed80 100644 --- a/src/components/Settings.tsx +++ b/src/components/Settings.tsx @@ -121,12 +121,8 @@ const Settings: React.FC = ({ settings, onSave, onClose }) => { }} >

The Quick Brown Fox

-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. -

-

- Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.

+

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.

@@ -137,27 +133,9 @@ const Settings: React.FC = ({ settings, onSave, onClose }) => {
- setLocalSettings({ ...localSettings, defaultViewMode: 'compact' })} - title="Compact list view" - ariaLabel="Compact list view" - variant={(localSettings.defaultViewMode || 'compact') === 'compact' ? 'primary' : 'ghost'} - /> - setLocalSettings({ ...localSettings, defaultViewMode: 'cards' })} - title="Cards view" - ariaLabel="Cards view" - variant={localSettings.defaultViewMode === 'cards' ? 'primary' : 'ghost'} - /> - setLocalSettings({ ...localSettings, defaultViewMode: 'large' })} - title="Large preview view" - ariaLabel="Large preview view" - variant={localSettings.defaultViewMode === 'large' ? 'primary' : 'ghost'} - /> + setLocalSettings({ ...localSettings, defaultViewMode: 'compact' })} title="Compact list view" ariaLabel="Compact list view" variant={(localSettings.defaultViewMode || 'compact') === 'compact' ? 'primary' : 'ghost'} /> + setLocalSettings({ ...localSettings, defaultViewMode: 'cards' })} title="Cards view" ariaLabel="Cards view" variant={localSettings.defaultViewMode === 'cards' ? 'primary' : 'ghost'} /> + setLocalSettings({ ...localSettings, defaultViewMode: 'large' })} title="Large preview view" ariaLabel="Large preview view" variant={localSettings.defaultViewMode === 'large' ? 'primary' : 'ghost'} />
diff --git a/src/utils/urlHelpers.ts b/src/utils/urlHelpers.ts new file mode 100644 index 00000000..932a2036 --- /dev/null +++ b/src/utils/urlHelpers.ts @@ -0,0 +1,24 @@ +import { Highlight } from '../types/highlights' + +export function normalizeUrl(url: string): string { + try { + const urlObj = new URL(url.startsWith('http') ? url : `https://${url}`) + return `${urlObj.hostname.replace(/^www\./, '')}${urlObj.pathname}`.replace(/\/$/, '').toLowerCase() + } catch { + return url.replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/$/, '').toLowerCase() + } +} + +export function filterHighlightsByUrl(highlights: Highlight[], selectedUrl: string | undefined): Highlight[] { + if (!selectedUrl || highlights.length === 0) return [] + + const normalizedSelected = normalizeUrl(selectedUrl) + + return highlights.filter(h => { + if (!h.urlReference) return false + const normalizedRef = normalizeUrl(h.urlReference) + return normalizedSelected === normalizedRef || + normalizedSelected.includes(normalizedRef) || + normalizedRef.includes(normalizedSelected) + }) +}