From e8ac520f5af227e4b9acf4b566ed414dda6d4ada Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 8 Aug 2023 15:36:16 +0800 Subject: [PATCH 1/5] Add ability to export highlights and notes from notebook --- .../templates/article/HighlightsLayer.tsx | 6 ++- .../templates/article/NotebookHeader.tsx | 54 ++++++++++++++----- .../templates/article/NotebookPresenter.tsx | 6 ++- .../templates/article/PdfArticleContainer.tsx | 6 ++- .../templates/homeFeed/HighlightItem.tsx | 35 +++++++++++- 5 files changed, 88 insertions(+), 19 deletions(-) diff --git a/packages/web/components/templates/article/HighlightsLayer.tsx b/packages/web/components/templates/article/HighlightsLayer.tsx index 84372b1aa..95b07f762 100644 --- a/packages/web/components/templates/article/HighlightsLayer.tsx +++ b/packages/web/components/templates/article/HighlightsLayer.tsx @@ -776,7 +776,11 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element { }} > <> - + void } export const NotebookHeader = (props: NotebookHeaderProps) => { - const handleClose = useCallback(() => { - props.setShowNotebook(false) - }, [props]) + const { articleData } = useGetArticleQuery({ + slug: props.item.slug, + username: props.viewer.profile.username, + includeFriendsHighlights: false, + }) + + const exportHighlights = useCallback(() => { + if (articleData?.article.article.highlights) { + const markdown = highlightsAsMarkdown( + articleData?.article.article.highlights + ) + ;(async () => { + await navigator.clipboard.writeText(markdown) + showSuccessToast('Highlights and notes copied') + })() + } + }, [articleData]) return ( { title="Delete Article Note" /> */} + + diff --git a/packages/web/components/templates/article/NotebookPresenter.tsx b/packages/web/components/templates/article/NotebookPresenter.tsx index ec81bb501..6626d6815 100644 --- a/packages/web/components/templates/article/NotebookPresenter.tsx +++ b/packages/web/components/templates/article/NotebookPresenter.tsx @@ -34,7 +34,11 @@ export const NotebookPresenter = (props: NotebookPresenterProps) => { }} > <> - + <> - + { + const sorted = (a: number, b: number) => { + if (a < b) { + return -1 + } + if (a > b) { + return 1 + } + return 0 + } + + return (highlights ?? []) + .filter((h) => h.type === 'HIGHLIGHT') + .sort((a: Highlight, b: Highlight) => { + if (a.highlightPositionPercent && b.highlightPositionPercent) { + return sorted(a.highlightPositionPercent, b.highlightPositionPercent) + } + // We do this in a try/catch because it might be an invalid diff + // With PDF it will definitely be an invalid diff. + try { + const aPos = getHighlightLocation(a.patch) + const bPos = getHighlightLocation(b.patch) + if (aPos && bPos) { + return sorted(aPos, bPos) + } + } catch {} + return a.createdAt.localeCompare(b.createdAt) + }) +} + export function highlightAsMarkdown(highlight: Highlight) { let buffer = `> ${highlight.quote}` if (highlight.annotation) { @@ -143,14 +174,14 @@ export function highlightAsMarkdown(highlight: Highlight) { export function highlightsAsMarkdown(highlights: Highlight[]) { const noteMD = highlights.find((h) => h.type == 'NOTE') - const highlightMD = highlights + const highlightMD = sortHighlights(highlights) .filter((h) => h.type == 'HIGHLIGHT') .map((highlight) => { return highlightAsMarkdown(highlight) }) .join('\n\n') - if (noteMD) { + if (noteMD?.annotation) { return `${noteMD.annotation}\n\n${highlightMD}` } return highlightMD From c08674ac54b110d38fbe62a13ab0d2f5933c95c4 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 8 Aug 2023 15:40:34 +0800 Subject: [PATCH 2/5] Some error messages --- .../templates/article/NotebookHeader.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/web/components/templates/article/NotebookHeader.tsx b/packages/web/components/templates/article/NotebookHeader.tsx index eff0dfe7f..284bd8cb3 100644 --- a/packages/web/components/templates/article/NotebookHeader.tsx +++ b/packages/web/components/templates/article/NotebookHeader.tsx @@ -9,7 +9,7 @@ import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery import { ReadableItem } from '../../../lib/networking/queries/useGetLibraryItemsQuery' import { useGetArticleQuery } from '../../../lib/networking/queries/useGetArticleQuery' import { highlightsAsMarkdown } from '../homeFeed/HighlightItem' -import { showSuccessToast } from '../../../lib/toastHelpers' +import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers' type NotebookHeaderProps = { viewer: UserBasicData @@ -30,10 +30,16 @@ export const NotebookHeader = (props: NotebookHeaderProps) => { const markdown = highlightsAsMarkdown( articleData?.article.article.highlights ) - ;(async () => { - await navigator.clipboard.writeText(markdown) - showSuccessToast('Highlights and notes copied') - })() + if (markdown.length > 1) { + ;(async () => { + await navigator.clipboard.writeText(markdown) + showSuccessToast('Highlights and notes copied') + })() + } else { + showSuccessToast('Nothing to export') + } + } else { + showErrorToast('Could not copy highlights') } }, [articleData]) From 544021f4751cf07adc25e82d3952fd29018aa6e0 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 8 Aug 2023 16:05:44 +0800 Subject: [PATCH 3/5] Add missing icon --- .../components/elements/icons/ExportIcon.tsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 packages/web/components/elements/icons/ExportIcon.tsx diff --git a/packages/web/components/elements/icons/ExportIcon.tsx b/packages/web/components/elements/icons/ExportIcon.tsx new file mode 100644 index 000000000..97d775b86 --- /dev/null +++ b/packages/web/components/elements/icons/ExportIcon.tsx @@ -0,0 +1,46 @@ +/* eslint-disable functional/no-class */ +/* eslint-disable functional/no-this-expression */ +import { IconProps } from './IconProps' + +import React from 'react' + +export class ExportIcon extends React.Component { + render() { + const size = (this.props.size || 26).toString() + const color = (this.props.color || '#2A2A2A').toString() + + return ( + + + + + + + + ) + } +} From 267b47e9592eaeeb9c3e6d2d6493b4572751f222 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 8 Aug 2023 16:46:41 +0800 Subject: [PATCH 4/5] Improve styling of highlight view items --- .../web/components/patterns/HighlightView.tsx | 54 +++++++++++++++---- .../components/templates/article/Notebook.tsx | 45 ---------------- .../web/components/tokens/stitches.config.ts | 4 +- 3 files changed, 47 insertions(+), 56 deletions(-) diff --git a/packages/web/components/patterns/HighlightView.tsx b/packages/web/components/patterns/HighlightView.tsx index 361f6c131..01b90cf92 100644 --- a/packages/web/components/patterns/HighlightView.tsx +++ b/packages/web/components/patterns/HighlightView.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/no-children-prop */ -import { useMemo, useState } from 'react' +import { useState } from 'react' import type { Highlight } from '../../lib/networking/fragments/highlightFragment' import { LabelChip } from '../elements/LabelChip' import { @@ -14,7 +14,6 @@ import { HighlightViewNote } from './HighlightNotes' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import { isDarkTheme } from '../../lib/themeUpdater' -import { HighlightsMenu } from '../templates/homeFeed/HighlightItem' import { ReadableItem } from '../../lib/networking/queries/useGetLibraryItemsQuery' import { UserBasicData } from '../../lib/networking/queries/useGetViewerQuery' import { @@ -25,7 +24,6 @@ import { useHover, useInteractions, } from '@floating-ui/react' -import { LibraryHoverActions } from './LibraryCards/LibraryHoverActions' import { HighlightHoverActions } from './HighlightHoverActions' type HighlightViewProps = { @@ -54,7 +52,6 @@ const StyledQuote = styled(Blockquote, { export function HighlightView(props: HighlightViewProps): JSX.Element { const isDark = isDarkTheme() const [noteMode, setNoteMode] = useState<'preview' | 'edit'>('preview') - const [isHovered, setIsHovered] = useState(false) const [isOpen, setIsOpen] = useState(false) const { refs, floatingStyles, context } = useFloating({ @@ -73,7 +70,7 @@ export function HighlightView(props: HighlightViewProps): JSX.Element { const hover = useHover(context) const { getReferenceProps, getFloatingProps } = useInteractions([hover]) - const highlightAlpha = isDark ? 1.0 : 0.35 + const highlightAlpha = isDark ? 0.5 : 0.35 return ( *': { + display: 'inline', + padding: '2px', backgroundColor: `rgba(var(--colors-highlightBackground), ${highlightAlpha})`, boxShadow: `3px 0 0 rgba(var(--colors-highlightBackground), ${highlightAlpha}), -3px 0 0 rgba(var(--colors-highlightBackground), ${highlightAlpha})`, boxDecorationBreak: 'clone', borderRadius: '2px', }, + '> ul': { + display: 'block', + boxShadow: 'unset', + backgroundColor: 'unset', + }, + // '> ul li span': { + // backgroundColor: `rgba(var(--colors-highlightBackground), ${highlightAlpha})`, + // boxShadow: `3px 0 0 rgba(var(--colors-highlightBackground), ${highlightAlpha}), -3px 0 0 rgba(var(--colors-highlightBackground), ${highlightAlpha})`, + // boxDecorationBreak: 'clone', + // borderRadius: '2px', + // }, fontSize: '15px', lineHeight: 1.5, color: '$thTextSubtle2', @@ -130,10 +139,37 @@ export function HighlightView(props: HighlightViewProps): JSX.Element { }, }} > - + Expertise Laptops, desktops and computer and PC gaming accessories + including keyboards, mice and controllers, cameras, action cameras + and drones Credentials +

+
    +
  • + + More than two decades experience writing about PCs and + accessories, and 15 years writing about cameras of all kinds. + +
  • +
+

+ Apple's MacBook Air is the company's lightest, thinnest and most + affordable laptop. The Air is regularly{' '} + + our top recommendation + {' '} + for anyone in need of a solid, reliable everyday laptop. And when + Apple released the{' '} + + 2020 MacBook Air with its first-gen M1 + {' '} + system-on-chip, the performance was as impressive as its design + for the $999 price. +

+ {/* + /> */}
diff --git a/packages/web/components/templates/article/Notebook.tsx b/packages/web/components/templates/article/Notebook.tsx index a4c1c0011..21ae2abdb 100644 --- a/packages/web/components/templates/article/Notebook.tsx +++ b/packages/web/components/templates/article/Notebook.tsx @@ -3,7 +3,6 @@ import { StyledText } from '../../elements/StyledText' import { theme } from '../../tokens/stitches.config' import type { Highlight } from '../../../lib/networking/fragments/highlightFragment' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { CaretDown, CaretRight } from 'phosphor-react' import { updateHighlightMutation } from '../../../lib/networking/mutations/updateHighlightMutation' import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers' import { diff_match_patch } from 'diff-match-patch' @@ -382,47 +381,3 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
) } - -type SectionTitleProps = { - title: string - selected: boolean - setSelected: (set: boolean) => void -} - -function SectionTitle(props: SectionTitleProps): JSX.Element { - return ( - <> - - - ) -} diff --git a/packages/web/components/tokens/stitches.config.ts b/packages/web/components/tokens/stitches.config.ts index 6e57310c7..74a105863 100644 --- a/packages/web/components/tokens/stitches.config.ts +++ b/packages/web/components/tokens/stitches.config.ts @@ -280,8 +280,8 @@ const darkThemeSpec = { thLibrarySelectionColor: '#3D3D3D', thNotebookSubtle: '#898989', - thNotebookBorder: '#898989', - thNotebookBackground: '#3B3938', + thNotebookBorder: '#3D3D3D', + thNotebookBackground: '#2F2F2F', thNotebookTextBackground: '#3D3D3D', thNotebookHighContrast: '#2A2A2A', From a5fcee6240de2b559bc85e36f033194c3be1b881 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Tue, 8 Aug 2023 16:55:58 +0800 Subject: [PATCH 5/5] Remove debug --- .../web/components/patterns/HighlightView.tsx | 37 +------------------ 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/packages/web/components/patterns/HighlightView.tsx b/packages/web/components/patterns/HighlightView.tsx index 01b90cf92..b258cbe88 100644 --- a/packages/web/components/patterns/HighlightView.tsx +++ b/packages/web/components/patterns/HighlightView.tsx @@ -122,12 +122,6 @@ export function HighlightView(props: HighlightViewProps): JSX.Element { boxShadow: 'unset', backgroundColor: 'unset', }, - // '> ul li span': { - // backgroundColor: `rgba(var(--colors-highlightBackground), ${highlightAlpha})`, - // boxShadow: `3px 0 0 rgba(var(--colors-highlightBackground), ${highlightAlpha}), -3px 0 0 rgba(var(--colors-highlightBackground), ${highlightAlpha})`, - // boxDecorationBreak: 'clone', - // borderRadius: '2px', - // }, fontSize: '15px', lineHeight: 1.5, color: '$thTextSubtle2', @@ -139,37 +133,10 @@ export function HighlightView(props: HighlightViewProps): JSX.Element { }, }} > -

- Expertise Laptops, desktops and computer and PC gaming accessories - including keyboards, mice and controllers, cameras, action cameras - and drones Credentials -

-
    -
  • - - More than two decades experience writing about PCs and - accessories, and 15 years writing about cameras of all kinds. - -
  • -
-

- Apple's MacBook Air is the company's lightest, thinnest and most - affordable laptop. The Air is regularly{' '} - - our top recommendation - {' '} - for anyone in need of a solid, reliable everyday laptop. And when - Apple released the{' '} - - 2020 MacBook Air with its first-gen M1 - {' '} - system-on-chip, the performance was as impressive as its design - for the $999 price. -

- {/* */} + />