mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Fix reader header offset, add labels icon to highlights
This commit is contained in:
parent
2615a0d33e
commit
2aa7c1a7d4
6 changed files with 85 additions and 33 deletions
|
|
@ -22,20 +22,20 @@ export class FollowingIcon extends React.Component<IconProps> {
|
|||
d="M12.5 4.5L4.5 8.5L12.5 12.5L20.5 8.5L12.5 4.5Z"
|
||||
fill={color}
|
||||
stroke={color}
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4.5 12.5L12.5 16.5L20.5 12.5"
|
||||
stroke={color}
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M4.5 16.5L12.5 20.5L20.5 16.5"
|
||||
stroke={color}
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import type { Highlight } from '../../../lib/networking/fragments/highlightFragm
|
|||
import {
|
||||
getHighlightElements,
|
||||
highlightIdAttribute,
|
||||
highlightLabelIdAttribute,
|
||||
highlightNoteIdAttribute,
|
||||
SelectionAttributes,
|
||||
} from '../../../lib/highlights/highlightHelpers'
|
||||
|
|
@ -79,15 +80,13 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
|
|||
const focusedHighlightMousePos = useRef({ pageX: 0, pageY: 0 })
|
||||
|
||||
const [currentHighlightIdx, setCurrentHighlightIdx] = useState(0)
|
||||
const [focusedHighlight, setFocusedHighlight] = useState<
|
||||
Highlight | undefined
|
||||
>(undefined)
|
||||
const [focusedHighlight, setFocusedHighlight] =
|
||||
useState<Highlight | undefined>(undefined)
|
||||
|
||||
const [selectionData, setSelectionData] = useSelection(highlightLocations)
|
||||
|
||||
const [labelsTarget, setLabelsTarget] = useState<Highlight | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [labelsTarget, setLabelsTarget] =
|
||||
useState<Highlight | undefined>(undefined)
|
||||
|
||||
const [
|
||||
confirmDeleteHighlightWithNoteId,
|
||||
|
|
@ -388,6 +387,13 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
|
|||
highlight: highlight,
|
||||
highlightModalAction: 'addComment',
|
||||
})
|
||||
} else if ((target as Element).hasAttribute(highlightLabelIdAttribute)) {
|
||||
const id = (target as HTMLSpanElement).getAttribute(
|
||||
highlightLabelIdAttribute
|
||||
)
|
||||
const highlight = highlights.find(($0) => $0.id === id)
|
||||
setFocusedHighlight(highlight)
|
||||
setLabelsTarget(highlight)
|
||||
} else {
|
||||
window?.webkit?.messageHandlers.viewerAction?.postMessage({
|
||||
actionID: 'pageTapped',
|
||||
|
|
@ -395,7 +401,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
|
|||
setFocusedHighlight(undefined)
|
||||
}
|
||||
},
|
||||
[openNoteModal, highlights]
|
||||
[openNoteModal, highlights, setLabelsTarget]
|
||||
)
|
||||
|
||||
const handleDoubleClick = useCallback(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ export function ReaderHeader(props: ReaderHeaderProps): JSX.Element {
|
|||
left: '0',
|
||||
zIndex: 1,
|
||||
pt: '0px',
|
||||
pb: '15px',
|
||||
position: 'fixed',
|
||||
width: '100%',
|
||||
height: DEFAULT_HEADER_HEIGHT,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import type { Highlight } from '../networking/fragments/highlightFragment'
|
|||
import { interpolationSearch } from './interpolationSearch'
|
||||
import {
|
||||
highlightIdAttribute,
|
||||
highlightLabelIdAttribute,
|
||||
highlightNoteIdAttribute,
|
||||
labelsImage,
|
||||
noteImage,
|
||||
} from './highlightHelpers'
|
||||
|
||||
|
|
@ -80,10 +82,18 @@ function nodeAttributesFromHighlight(
|
|||
const patch = highlight.patch
|
||||
const id = highlight.id
|
||||
const withNote = !!highlight.annotation
|
||||
const withLabels = (highlight.labels?.length ?? 0) > 0
|
||||
const tooltip = undefined
|
||||
const customColor = highlight.color
|
||||
|
||||
return makeHighlightNodeAttributes(patch, id, withNote, customColor, tooltip)
|
||||
return makeHighlightNodeAttributes(
|
||||
patch,
|
||||
id,
|
||||
withNote,
|
||||
withLabels,
|
||||
customColor,
|
||||
tooltip
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -100,6 +110,7 @@ export function makeHighlightNodeAttributes(
|
|||
patch: string,
|
||||
id: string,
|
||||
withNote: boolean,
|
||||
withLabels: boolean,
|
||||
customColor?: string,
|
||||
tooltip?: string
|
||||
): HighlightNodeAttributes {
|
||||
|
|
@ -183,12 +194,10 @@ export function makeHighlightNodeAttributes(
|
|||
startingTextNodeIndex++
|
||||
}
|
||||
if (withNote && lastElement) {
|
||||
lastElement.classList.add('last_element')
|
||||
|
||||
const svg = noteImage(customColor)
|
||||
svg.setAttribute(highlightNoteIdAttribute, id)
|
||||
|
||||
const ctr = document.createElement('div')
|
||||
const ctr = document.createElement('span')
|
||||
ctr.className = 'highlight_note_button'
|
||||
ctr.appendChild(svg)
|
||||
ctr.setAttribute(highlightNoteIdAttribute, id)
|
||||
|
|
@ -197,6 +206,19 @@ export function makeHighlightNodeAttributes(
|
|||
|
||||
lastElement.appendChild(ctr)
|
||||
}
|
||||
if (withLabels && lastElement) {
|
||||
const svg = labelsImage(customColor)
|
||||
svg.setAttribute(highlightLabelIdAttribute, id)
|
||||
|
||||
const ctr = document.createElement('span')
|
||||
ctr.className = 'highlight_label_button'
|
||||
ctr.appendChild(svg)
|
||||
ctr.setAttribute(highlightLabelIdAttribute, id)
|
||||
ctr.setAttribute('width', '14px')
|
||||
ctr.setAttribute('height', '14px')
|
||||
|
||||
lastElement.appendChild(ctr)
|
||||
}
|
||||
|
||||
return {
|
||||
prefix,
|
||||
|
|
@ -209,10 +231,10 @@ export function makeHighlightNodeAttributes(
|
|||
|
||||
/**
|
||||
* Given a text selection by user, annotate the article around the selection and
|
||||
* produce a {@link https://github.com/google/diff-match-patch | diff patch}
|
||||
*
|
||||
* produce a {@link https://github.com/google/diff-match-patch | diff patch}
|
||||
*
|
||||
* The diff patch is used for identifying the selection/highlight location
|
||||
*
|
||||
*
|
||||
* @param range text selection range
|
||||
* @returns diff patch
|
||||
*/
|
||||
|
|
@ -304,11 +326,11 @@ const getArticleTextNodes = (
|
|||
|
||||
/**
|
||||
* Return the offsets to the selection/highlight
|
||||
*
|
||||
*
|
||||
* @param patch {@link generateDiffPatch|diff patch} identifying a selection/highlight location
|
||||
* @returns
|
||||
* @returns
|
||||
* - highlightTextStart - The start of highlight, offset from the start of article by characters
|
||||
* - highlightTextEnd - The end of highlight (non-inclusive), offset from the start of article by characters
|
||||
* - highlightTextEnd - The end of highlight (non-inclusive), offset from the start of article by characters
|
||||
* - matchingHighlightContent - the matched highlight
|
||||
*/
|
||||
const selectionOffsetsFromPatch = (
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export type SelectionAttributes = {
|
|||
|
||||
export const highlightIdAttribute = 'omnivore-highlight-id'
|
||||
export const highlightNoteIdAttribute = 'omnivore-highlight-note-id'
|
||||
export const highlightLabelIdAttribute = 'omnivore-highlight-label-id'
|
||||
|
||||
export function getHighlightElements(highlightId: string): Element[] {
|
||||
return Array.from(
|
||||
|
|
@ -46,3 +47,23 @@ export function noteImage(color: string | undefined): SVGSVGElement {
|
|||
svg.appendChild(path)
|
||||
return svg
|
||||
}
|
||||
|
||||
export const labelsImage = (color: string | undefined): SVGSVGElement => {
|
||||
const svgURI = 'http://www.w3.org/2000/svg'
|
||||
const svg = document.createElementNS(svgURI, 'svg')
|
||||
svg.setAttribute('viewBox', '0 0 14 14')
|
||||
svg.setAttribute('width', '14')
|
||||
svg.setAttribute('height', '14')
|
||||
svg.setAttribute('fill', 'none')
|
||||
|
||||
const path = document.createElementNS(svgURI, 'path')
|
||||
path.setAttribute(
|
||||
'd',
|
||||
'M1.75 3.5V6.517C1.75007 6.82639 1.87303 7.12309 2.09183 7.34183L6.58933 11.8393C6.85297 12.1029 7.21052 12.251 7.58333 12.251C7.95615 12.251 8.3137 12.1029 8.57733 11.8393L11.8393 8.57733C12.1029 8.3137 12.251 7.95615 12.251 7.58333C12.251 7.21052 12.1029 6.85297 11.8393 6.58933L7.34183 2.09183C7.12309 1.87303 6.82639 1.75007 6.517 1.75H3.5C3.03587 1.75 2.59075 1.93437 2.26256 2.26256C1.93437 2.59075 1.75 3.03587 1.75 3.5Z'
|
||||
)
|
||||
path.setAttribute('stroke', `rgba(${highlightColorVar(color)}, 0.8)`)
|
||||
path.setAttribute('stroke-width', '1.8')
|
||||
path.setAttribute('stroke-linejoin', 'round')
|
||||
svg.appendChild(path)
|
||||
return svg
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,23 +44,25 @@
|
|||
font-family: var(--text-font-family);
|
||||
}
|
||||
|
||||
.article-inner-css .highlight_with_note .highlight_note_button {
|
||||
.article-inner-css .highlight_note_button {
|
||||
display: unset !important;
|
||||
margin: 0px !important;
|
||||
max-width: unset !important;
|
||||
height: unset !important;
|
||||
padding: 0px 8px;
|
||||
cursor: pointer;
|
||||
margin-left: 5px !important;
|
||||
}
|
||||
|
||||
.article-inner-css .highlight_label_button {
|
||||
display: unset !important;
|
||||
margin: 0px !important;
|
||||
max-width: unset !important;
|
||||
height: unset !important;
|
||||
padding: 0px 8px;
|
||||
cursor: pointer;
|
||||
margin-left: 4px !important;
|
||||
}
|
||||
/*
|
||||
on smaller screens we display the note icon
|
||||
@media (max-width: 768px) {
|
||||
.highlight_with_note.last_element:after {
|
||||
content: url(/static/icons/highlight-note-icon.svg);
|
||||
padding: 0 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
} */
|
||||
|
||||
.article-inner-css h1,
|
||||
.article-inner-css h2,
|
||||
|
|
|
|||
Loading…
Reference in a new issue