diff --git a/packages/web/components/elements/icons/FollowingIcon.tsx b/packages/web/components/elements/icons/FollowingIcon.tsx index ef882dce2..e9fca6c04 100644 --- a/packages/web/components/elements/icons/FollowingIcon.tsx +++ b/packages/web/components/elements/icons/FollowingIcon.tsx @@ -22,20 +22,20 @@ export class FollowingIcon extends React.Component { 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" /> diff --git a/packages/web/components/templates/article/HighlightsLayer.tsx b/packages/web/components/templates/article/HighlightsLayer.tsx index d5bb8b0bb..dd1ed5bf1 100644 --- a/packages/web/components/templates/article/HighlightsLayer.tsx +++ b/packages/web/components/templates/article/HighlightsLayer.tsx @@ -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(undefined) const [selectionData, setSelectionData] = useSelection(highlightLocations) - const [labelsTarget, setLabelsTarget] = useState( - undefined - ) + const [labelsTarget, setLabelsTarget] = + useState(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( diff --git a/packages/web/components/templates/reader/ReaderHeader.tsx b/packages/web/components/templates/reader/ReaderHeader.tsx index 992152222..0f6bb88f4 100644 --- a/packages/web/components/templates/reader/ReaderHeader.tsx +++ b/packages/web/components/templates/reader/ReaderHeader.tsx @@ -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, diff --git a/packages/web/lib/highlights/highlightGenerator.ts b/packages/web/lib/highlights/highlightGenerator.ts index 19d1131bb..a74b33185 100644 --- a/packages/web/lib/highlights/highlightGenerator.ts +++ b/packages/web/lib/highlights/highlightGenerator.ts @@ -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 = ( diff --git a/packages/web/lib/highlights/highlightHelpers.ts b/packages/web/lib/highlights/highlightHelpers.ts index f000ca207..7136bfed8 100644 --- a/packages/web/lib/highlights/highlightHelpers.ts +++ b/packages/web/lib/highlights/highlightHelpers.ts @@ -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 +} diff --git a/packages/web/styles/articleInnerStyling.css b/packages/web/styles/articleInnerStyling.css index faf39b314..c38f290a7 100644 --- a/packages/web/styles/articleInnerStyling.css +++ b/packages/web/styles/articleInnerStyling.css @@ -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,