From e294ed4b4b88a5d8be626840213bb658ab15126c Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Thu, 22 Jun 2023 17:16:54 +0800 Subject: [PATCH] Clean up notebooks design and saving --- .../components/patterns/HighlightNotes.tsx | 141 ++++------- .../web/components/patterns/HighlightView.tsx | 78 +++--- .../LibraryCards/LibraryCardStyles.tsx | 6 +- .../patterns/LibraryCards/LibraryGridCard.tsx | 3 - .../patterns/LibraryCards/LibraryListCard.tsx | 32 ++- .../templates/article/HighlightViewItem.tsx | 37 ++- .../components/templates/article/Notebook.tsx | 222 ++++++++++-------- .../templates/article/NotebookModal.tsx | 7 +- .../templates/homeFeed/HighlightItem.tsx | 128 +++++----- .../web/components/tokens/stitches.config.ts | 1 + packages/web/lib/themeUpdater.tsx | 1 + 11 files changed, 324 insertions(+), 332 deletions(-) diff --git a/packages/web/components/patterns/HighlightNotes.tsx b/packages/web/components/patterns/HighlightNotes.tsx index 98ee1c35d..e0d3644c5 100644 --- a/packages/web/components/patterns/HighlightNotes.tsx +++ b/packages/web/components/patterns/HighlightNotes.tsx @@ -26,6 +26,9 @@ import { import { CloseButton } from '../elements/CloseButton' import { StyledText } from '../elements/StyledText' import remarkGfm from 'remark-gfm' +import { RcEditorStyles } from './RcEditorStyles' +import { isDarkTheme } from '../../lib/themeUpdater' +import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers' const mdParser = new MarkdownIt() @@ -34,6 +37,8 @@ MdEditor.use(Plugins.TabInsert, { }) type NoteSectionProps = { + targetId: string + placeHolder: string mode: 'edit' | 'preview' @@ -60,6 +65,7 @@ export function HighlightNoteBox(props: NoteSectionProps): JSX.Element { return ( (null) const [lastChanged, setLastChanged] = useState(undefined) const [errorSaving, setErrorSaving] = useState(undefined) - - const saveRef = useRef(props.saveText) - - useEffect(() => { - saveRef.current = props.saveText - }, [props.lastSaved, lastChanged]) - - const debouncedSave = useMemo< - (text: string, updateTime: Date) => void - >(() => { - const func = (text: string, updateTime: Date) => { - saveRef.current?.(text, updateTime) - } - return throttle(func, 3000) - }, []) - - const handleEditorChange = useCallback( - ( - data: { text: string; html: string }, - event?: ChangeEvent | undefined - ) => { - if (event) { - event.preventDefault() - } - - const updateTime = new Date() - setLastChanged(updateTime) - debouncedSave(data.text, updateTime) - }, - [props.lastSaved, lastChanged] - ) + const isDark = isDarkTheme() return ( <> @@ -175,28 +163,13 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element { .section': { - borderRight: 'unset', - }, - '.rc-md-editor .editor-container .sec-md .input': { - padding: '10px', - borderRadius: '5px', - fontSize: '16px', - }, + ...RcEditorStyles(isDark), }} onKeyDown={(event: React.KeyboardEvent) => { if (event.code.toLowerCase() === 'escape') { props.setEditMode('preview') event.preventDefault() + event.stopPropagation() } }} > @@ -233,7 +206,6 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element { height: props.sizeMode == 'normal' ? '160px' : '320px', }} renderHTML={(text: string) => mdParser.render(text)} - onChange={handleEditorChange} /> )} - {props.lastSaved !== undefined ? ( - <> - {lastChanged === props.lastSaved - ? 'Saved' - : `Last saved ${formattedShortTime( - props.lastSaved.toISOString() - )}`} - - ) : null} - {lastChanged !== props.lastSaved && ( - + - - )} + Save + + ) : ( @@ -306,9 +264,9 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element { css={{ p: '5px', width: '100%', - fontSize: '15px', - // borderRadius: '3px', - marginTop: props.fillBackground || !props.text ? '10px' : '0px', + fontSize: '12px', + marginTop: '0px', + paddingTop: '0px', paddingLeft: props.fillBackground && props.text @@ -344,6 +302,8 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element { } type MarkdownModalProps = { + targetId: string + placeHolder: string mode: 'edit' | 'preview' @@ -435,6 +395,7 @@ export function MarkdownModal(props: MarkdownModalProps): JSX.Element { ('preview') return ( > - + {/* */} + @@ -89,7 +98,7 @@ export function HighlightView(props: HighlightViewProps): JSX.Element { }, fontSize: '15px', lineHeight: 1.5, - color: '$grayText', + color: '$thTextSubtle2', img: { display: 'block', margin: '0.5em auto !important', @@ -110,11 +119,18 @@ export function HighlightView(props: HighlightViewProps): JSX.Element { ))} - { - setNoteMode(noteMode == 'preview' ? 'edit' : 'preview') - event.preventDefault() - }} - > - {noteMode === 'edit' ? ( - - ) : ( - - )} - diff --git a/packages/web/components/patterns/LibraryCards/LibraryCardStyles.tsx b/packages/web/components/patterns/LibraryCards/LibraryCardStyles.tsx index faa441bc5..954211043 100644 --- a/packages/web/components/patterns/LibraryCards/LibraryCardStyles.tsx +++ b/packages/web/components/patterns/LibraryCards/LibraryCardStyles.tsx @@ -18,9 +18,9 @@ export const MenuStyle = { display: 'flex', marginLeft: 'auto', height: '30px', - width: '150px', - mt: '-5px', - mr: '-5px', + width: '180px', + // mt: '-5px', + // mr: '-5px', pt: '2px', alignItems: 'center', justifyContent: 'center', diff --git a/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx b/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx index 2ae6986bb..dc73339d0 100644 --- a/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx +++ b/packages/web/components/patterns/LibraryCards/LibraryGridCard.tsx @@ -145,9 +145,6 @@ const LibraryGridCardContent = (props: LinkedItemCardProps): JSX.Element => { gap: '10px', px: '20px', borderRadius: '1000px', - - bg: 'red', - visibility: props.isHovered || menuOpen ? 'unset' : 'hidden', '@media (hover: none)': { visibility: 'unset', diff --git a/packages/web/components/patterns/LibraryCards/LibraryListCard.tsx b/packages/web/components/patterns/LibraryCards/LibraryListCard.tsx index a4fb3ae38..fe3956871 100644 --- a/packages/web/components/patterns/LibraryCards/LibraryListCard.tsx +++ b/packages/web/components/patterns/LibraryCards/LibraryListCard.tsx @@ -6,6 +6,8 @@ import { Archive, ArchiveBox, DotsThree, + Note, + Notebook, Tag, Trash, Tray, @@ -116,6 +118,27 @@ export function LibraryListCardContent( }, }} > + + - setHover(true)} onMouseLeave={() => setHover(false)} > - + - - - + ) } diff --git a/packages/web/components/templates/article/Notebook.tsx b/packages/web/components/templates/article/Notebook.tsx index 420568cfd..ac991d2b4 100644 --- a/packages/web/components/templates/article/Notebook.tsx +++ b/packages/web/components/templates/article/Notebook.tsx @@ -3,7 +3,15 @@ import { StyledText } from '../../elements/StyledText' import { theme } from '../../tokens/stitches.config' import type { Highlight } from '../../../lib/networking/fragments/highlightFragment' import { useCallback, useEffect, useMemo, useReducer, useState } from 'react' -import { BookOpen, CaretDown, PencilLine, X } from 'phosphor-react' +import { + BookOpen, + CaretDown, + CaretRight, + DotsThree, + Pencil, + PencilLine, + X, +} from 'phosphor-react' import { updateHighlightMutation } from '../../../lib/networking/mutations/updateHighlightMutation' import { showErrorToast, showSuccessToast } from '../../../lib/toastHelpers' import { diff_match_patch } from 'diff-match-patch' @@ -20,6 +28,8 @@ import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery import { ReadableItem } from '../../../lib/networking/queries/useGetLibraryItemsQuery' import { SetHighlightLabelsModalPresenter } from './SetLabelsModalPresenter' import { Button } from '../../elements/Button' +import { Dropdown, DropdownOption } from '../../elements/DropdownElements' +import { ArticleNoteBox } from '../../patterns/ArticleNotes' type NotebookProps = { viewer: UserBasicData @@ -93,6 +103,7 @@ export function Notebook(props: NotebookProps): JSX.Element { if (!action.note) { throw new Error('No note on CREATE_NOTE action') } + console.log(' - CREATE_NOTE', action.note) return { ...state, note: action.note, @@ -234,6 +245,14 @@ export function Notebook(props: NotebookProps): JSX.Element { const handleSaveNoteText = useCallback( (text, cb: (success: boolean) => void) => { + console.log( + 'saving note text: ', + text, + 'annotations.loaded: ', + annotations.loaded, + 'annotations.note: ', + annotations.note + ) if (!annotations.loaded) { // We haven't loaded the user's annotations yet, so we can't // find or create their highlight note. @@ -285,72 +304,89 @@ export function Notebook(props: NotebookProps): JSX.Element { [annotations, props.item] ) + const [articleNotesCollapsed, setArticleNotesCollapsed] = useState(false) + const [highlightsCollapsed, setHighlightsCollapsed] = useState(false) + return ( - setNotesEditMode(edit ? 'edit' : 'preview')} + collapsed={articleNotesCollapsed} + setCollapsed={setArticleNotesCollapsed} /> - - - + {!articleNotesCollapsed && ( + + + + )} + - + - {sortedHighlights.map((highlight) => ( - { - dispatchAnnotations({ - type: 'UPDATE_HIGHLIGHT', - updateHighlight: highlight, - }) - }} - /> - ))} - {sortedHighlights.length === 0 && ( - - You have not added any highlights to this document. - + {!highlightsCollapsed && ( + <> + {sortedHighlights.map((highlight) => ( + { + dispatchAnnotations({ + type: 'UPDATE_HIGHLIGHT', + updateHighlight: highlight, + }) + }} + /> + ))} + {sortedHighlights.length === 0 && ( + + You have not added any highlights to this document. + + )} + )} - + /> */} {showConfirmDeleteHighlightId && ( @@ -419,62 +455,52 @@ export function Notebook(props: NotebookProps): JSX.Element { ) } -type TitledSectionProps = { +type SectionTitleProps = { title: string - editMode?: boolean - setEditMode?: (set: boolean) => void + collapsed: boolean + setCollapsed: (set: boolean) => void } -function TitledSection(props: TitledSectionProps): JSX.Element { +function SectionTitle(props: SectionTitleProps): JSX.Element { return ( <> - { + props.setCollapsed(!props.collapsed) + event.stopPropagation() + }} > - {/* */} + {props.collapsed ? ( + + ) : ( + + )} {props.title} - {props.setEditMode && ( - { - if (props.setEditMode) { - props.setEditMode(!props.editMode) - } - event.preventDefault() - }} - > - {props.editMode ? ( - - ) : ( - - )} - - )} - + ) } diff --git a/packages/web/components/templates/article/NotebookModal.tsx b/packages/web/components/templates/article/NotebookModal.tsx index a563c7059..7cf0d877a 100644 --- a/packages/web/components/templates/article/NotebookModal.tsx +++ b/packages/web/components/templates/article/NotebookModal.tsx @@ -89,8 +89,9 @@ export function NotebookModal(props: NotebookModalProps): JSX.Element { css={{ overflow: 'auto', bg: '$thLibraryBackground', + width: '100%', height: sizeMode === 'normal' ? 'unset' : '100%', - maxWidth: sizeMode === 'normal' ? '640px' : '100%', + maxWidth: sizeMode === 'normal' ? '748px' : '1050px', minHeight: sizeMode === 'normal' ? '525px' : 'unset', '@mdDown': { top: '20px', @@ -102,7 +103,7 @@ export function NotebookModal(props: NotebookModalProps): JSX.Element { }} > - + {/* */} }> { diff --git a/packages/web/components/templates/homeFeed/HighlightItem.tsx b/packages/web/components/templates/homeFeed/HighlightItem.tsx index eea578052..2588de8b6 100644 --- a/packages/web/components/templates/homeFeed/HighlightItem.tsx +++ b/packages/web/components/templates/homeFeed/HighlightItem.tsx @@ -10,7 +10,7 @@ import { DropdownOption, DropdownSeparator, } from '../../elements/DropdownElements' -import { Box } from '../../elements/LayoutPrimitives' +import { Box, VStack } from '../../elements/LayoutPrimitives' import { styled, theme } from '../../tokens/stitches.config' @@ -57,70 +57,76 @@ export function HighlightsMenu(props: HighlightsMenuProps): JSX.Element { }, [props.highlight]) return ( - - - - } + - { - copyHighlight() - }} - title="Copy" - /> - { - props.setLabelsTarget(props.highlight) - }} - title="Labels" - /> - { - props.setShowConfirmDeleteHighlightId(props.highlight.id) - }} - title="Delete" - /> - - + + + } > - { - console.log('event.ctrlKey: ', event.ctrlKey, event.metaKey) - if (event.ctrlKey || event.metaKey) { - window.open( - `/${props.viewer.profile.username}/${props.item.slug}#${props.highlight.id}`, - '_blank' - ) - return - } - props.viewInReader(props.highlight.id) - event.preventDefault() - event.stopPropagation() + { + copyHighlight() }} + title="Copy" + /> + { + props.setLabelsTarget(props.highlight) + }} + title="Labels" + /> + { + props.setShowConfirmDeleteHighlightId(props.highlight.id) + }} + title="Delete" + /> + + - View In Reader - - - + { + console.log('event.ctrlKey: ', event.ctrlKey, event.metaKey) + if (event.ctrlKey || event.metaKey) { + window.open( + `/${props.viewer.profile.username}/${props.item.slug}#${props.highlight.id}`, + '_blank' + ) + return + } + props.viewInReader(props.highlight.id) + event.preventDefault() + event.stopPropagation() + }} + > + View In Reader + + + + ) } diff --git a/packages/web/components/tokens/stitches.config.ts b/packages/web/components/tokens/stitches.config.ts index 237002bf3..1b0eae447 100644 --- a/packages/web/components/tokens/stitches.config.ts +++ b/packages/web/components/tokens/stitches.config.ts @@ -277,6 +277,7 @@ const darkThemeSpec = { thLibrarySelectionColor: '#3D3D3D', thNotebookSubtle: '#898989', + thNotebookHighContrast: '#2A2A2A', thTextContrast: '#FFFFFF', thTextContrast2: '#EBEBEB', diff --git a/packages/web/lib/themeUpdater.tsx b/packages/web/lib/themeUpdater.tsx index 07b860c5c..6c57109a6 100644 --- a/packages/web/lib/themeUpdater.tsx +++ b/packages/web/lib/themeUpdater.tsx @@ -107,6 +107,7 @@ export function isDarkTheme(): boolean { return ( currentTheme === 'Dark' || currentTheme === 'Darker' || + currentTheme === 'Apollo' || currentTheme == 'Black' ) }