mirror of
https://github.com/dergigi/boris.git
synced 2026-02-19 14:04:38 +01:00
feat: add toggle button to show/hide highlight underlines
- Add eye/eye-slash toggle button in highlights panel header - Button only appears when there are highlights to show - Clicking toggles underlines on/off in the main content panel - When hidden, removes existing <mark> elements from DOM - Add showUnderlines state management through Bookmarks component - Style toggle button consistently with collapse button - Add highlights-actions container for button group Users can now toggle highlight visibility without losing the highlight list.
This commit is contained in:
@@ -28,6 +28,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
const [isCollapsed, setIsCollapsed] = useState(false)
|
||||
const [isHighlightsCollapsed, setIsHighlightsCollapsed] = useState(false)
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('cards')
|
||||
const [showUnderlines, setShowUnderlines] = useState(true)
|
||||
const activeAccount = Hooks.useActiveAccount()
|
||||
const accountManager = Hooks.useAccountManager()
|
||||
|
||||
@@ -123,6 +124,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
markdown={readerContent?.markdown}
|
||||
selectedUrl={selectedUrl}
|
||||
highlights={highlights}
|
||||
showUnderlines={showUnderlines}
|
||||
/>
|
||||
</div>
|
||||
<div className="pane highlights">
|
||||
@@ -133,6 +135,7 @@ const Bookmarks: React.FC<BookmarksProps> = ({ relayPool, onLogout }) => {
|
||||
onToggleCollapse={() => setIsHighlightsCollapsed(!isHighlightsCollapsed)}
|
||||
onSelectUrl={handleSelectUrl}
|
||||
selectedUrl={selectedUrl}
|
||||
onToggleUnderlines={setShowUnderlines}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ interface ContentPanelProps {
|
||||
markdown?: string
|
||||
selectedUrl?: string
|
||||
highlights?: Highlight[]
|
||||
showUnderlines?: boolean
|
||||
}
|
||||
|
||||
const ContentPanel: React.FC<ContentPanelProps> = ({
|
||||
@@ -21,7 +22,8 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
|
||||
html,
|
||||
markdown,
|
||||
selectedUrl,
|
||||
highlights = []
|
||||
highlights = [],
|
||||
showUnderlines = true
|
||||
}) => {
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
@@ -88,13 +90,27 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
|
||||
console.log('🔍 useEffect triggered:', {
|
||||
hasContentRef: !!contentRef.current,
|
||||
relevantHighlightsCount: relevantHighlights.length,
|
||||
hasHtml: !!html
|
||||
hasHtml: !!html,
|
||||
showUnderlines
|
||||
})
|
||||
|
||||
if (!contentRef.current || relevantHighlights.length === 0) {
|
||||
if (!contentRef.current || relevantHighlights.length === 0 || !showUnderlines) {
|
||||
console.log('⚠️ Skipping highlight application:', {
|
||||
reason: !contentRef.current ? 'no contentRef' : 'no relevant highlights'
|
||||
reason: !contentRef.current ? 'no contentRef' :
|
||||
!showUnderlines ? 'underlines hidden' :
|
||||
'no relevant highlights'
|
||||
})
|
||||
|
||||
// If underlines are hidden, remove any existing highlights
|
||||
if (!showUnderlines && contentRef.current) {
|
||||
const marks = contentRef.current.querySelectorAll('mark.content-highlight')
|
||||
marks.forEach(mark => {
|
||||
const text = mark.textContent || ''
|
||||
const textNode = document.createTextNode(text)
|
||||
mark.parentNode?.replaceChild(textNode, mark)
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -119,7 +135,7 @@ const ContentPanel: React.FC<ContentPanelProps> = ({
|
||||
}, 100)
|
||||
|
||||
return () => clearTimeout(timer)
|
||||
}, [relevantHighlights, html])
|
||||
}, [relevantHighlights, html, showUnderlines])
|
||||
|
||||
const highlightedMarkdown = useMemo(() => {
|
||||
if (!markdown || relevantHighlights.length === 0) return markdown
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faChevronRight, faChevronLeft, faHighlighter } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faChevronRight, faChevronLeft, faHighlighter, faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'
|
||||
import { Highlight } from '../types/highlights'
|
||||
import { HighlightItem } from './HighlightItem'
|
||||
|
||||
@@ -11,6 +11,7 @@ interface HighlightsPanelProps {
|
||||
onToggleCollapse: () => void
|
||||
onSelectUrl?: (url: string) => void
|
||||
selectedUrl?: string
|
||||
onToggleUnderlines?: (show: boolean) => void
|
||||
}
|
||||
|
||||
export const HighlightsPanel: React.FC<HighlightsPanelProps> = ({
|
||||
@@ -19,8 +20,17 @@ export const HighlightsPanel: React.FC<HighlightsPanelProps> = ({
|
||||
isCollapsed,
|
||||
onToggleCollapse,
|
||||
onSelectUrl,
|
||||
selectedUrl
|
||||
selectedUrl,
|
||||
onToggleUnderlines
|
||||
}) => {
|
||||
const [showUnderlines, setShowUnderlines] = useState(true)
|
||||
|
||||
const handleToggleUnderlines = () => {
|
||||
const newValue = !showUnderlines
|
||||
setShowUnderlines(newValue)
|
||||
onToggleUnderlines?.(newValue)
|
||||
}
|
||||
|
||||
// Filter highlights to show only those relevant to the current URL
|
||||
const filteredHighlights = useMemo(() => {
|
||||
if (!selectedUrl) return highlights
|
||||
@@ -68,14 +78,26 @@ export const HighlightsPanel: React.FC<HighlightsPanelProps> = ({
|
||||
<h3>Highlights</h3>
|
||||
{!loading && <span className="count">({filteredHighlights.length})</span>}
|
||||
</div>
|
||||
<button
|
||||
onClick={onToggleCollapse}
|
||||
className="toggle-highlights-btn"
|
||||
title="Collapse highlights panel"
|
||||
aria-label="Collapse highlights panel"
|
||||
>
|
||||
<FontAwesomeIcon icon={faChevronRight} rotation={180} />
|
||||
</button>
|
||||
<div className="highlights-actions">
|
||||
{filteredHighlights.length > 0 && (
|
||||
<button
|
||||
onClick={handleToggleUnderlines}
|
||||
className="toggle-underlines-btn"
|
||||
title={showUnderlines ? 'Hide underlines' : 'Show underlines'}
|
||||
aria-label={showUnderlines ? 'Hide underlines' : 'Show underlines'}
|
||||
>
|
||||
<FontAwesomeIcon icon={showUnderlines ? faEye : faEyeSlash} />
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={onToggleCollapse}
|
||||
className="toggle-highlights-btn"
|
||||
title="Collapse highlights panel"
|
||||
aria-label="Collapse highlights panel"
|
||||
>
|
||||
<FontAwesomeIcon icon={faChevronRight} rotation={180} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
|
||||
@@ -1136,6 +1136,13 @@ body {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.highlights-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.toggle-underlines-btn,
|
||||
.toggle-highlights-btn {
|
||||
background: transparent;
|
||||
color: #ddd;
|
||||
@@ -1151,11 +1158,13 @@ body {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.toggle-underlines-btn:hover,
|
||||
.toggle-highlights-btn:hover {
|
||||
background: #2a2a2a;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.toggle-underlines-btn:active,
|
||||
.toggle-highlights-btn:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user