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"
/>
*/}
+
+ {
+ exportHighlights()
+ event.preventDefault()
+ }}
+ >
+
+
props.setShowNotebook(false)}>
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 (
- <>
- {
- props.setSelected(true)
- event.stopPropagation()
- }}
- >
-
- {props.title}
-
-
- >
- )
-}
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.
-
- {/* */}
+ />