mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Clean up notebooks design and saving
This commit is contained in:
parent
fa0efe7794
commit
e294ed4b4b
11 changed files with 324 additions and 332 deletions
|
|
@ -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 (
|
||||
<MarkdownNote
|
||||
targetId={props.targetId}
|
||||
placeHolder={props.placeHolder}
|
||||
mode={props.mode}
|
||||
sizeMode={props.sizeMode}
|
||||
|
|
@ -73,6 +79,8 @@ export function HighlightNoteBox(props: NoteSectionProps): JSX.Element {
|
|||
}
|
||||
|
||||
type HighlightViewNoteProps = {
|
||||
targetId: string
|
||||
|
||||
placeHolder: string
|
||||
mode: 'edit' | 'preview'
|
||||
|
||||
|
|
@ -99,6 +107,13 @@ export function HighlightViewNote(props: HighlightViewNoteProps): JSX.Element {
|
|||
setLastSaved(updateTime)
|
||||
props.highlight.annotation = text
|
||||
props.updateHighlight(props.highlight)
|
||||
showSuccessToast('Note saved.', {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
} else {
|
||||
showErrorToast('Error saving note.', {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
}
|
||||
})()
|
||||
},
|
||||
|
|
@ -107,6 +122,7 @@ export function HighlightViewNote(props: HighlightViewNoteProps): JSX.Element {
|
|||
|
||||
return (
|
||||
<MarkdownNote
|
||||
targetId={props.targetId}
|
||||
placeHolder={props.placeHolder}
|
||||
mode={props.mode}
|
||||
sizeMode={props.sizeMode}
|
||||
|
|
@ -120,6 +136,8 @@ export function HighlightViewNote(props: HighlightViewNoteProps): JSX.Element {
|
|||
}
|
||||
|
||||
type MarkdownNote = {
|
||||
targetId: string
|
||||
|
||||
placeHolder: string
|
||||
mode: 'edit' | 'preview'
|
||||
|
||||
|
|
@ -137,37 +155,7 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element {
|
|||
const editorRef = useRef<MdEditor | null>(null)
|
||||
const [lastChanged, setLastChanged] = useState<Date | undefined>(undefined)
|
||||
const [errorSaving, setErrorSaving] = useState<string | undefined>(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<HTMLTextAreaElement> | 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 {
|
|||
<VStack
|
||||
css={{
|
||||
width: '100%',
|
||||
mt: '15px',
|
||||
'.rc-md-editor': {
|
||||
borderRadius: '5px',
|
||||
},
|
||||
'.rc-md-navigation': {
|
||||
borderRadius: '5px',
|
||||
borderBottomLeftRadius: '0px',
|
||||
borderBottomRightRadius: '0px',
|
||||
},
|
||||
'.rc-md-editor .editor-container >.section': {
|
||||
borderRight: 'unset',
|
||||
},
|
||||
'.rc-md-editor .editor-container .sec-md .input': {
|
||||
padding: '10px',
|
||||
borderRadius: '5px',
|
||||
fontSize: '16px',
|
||||
},
|
||||
...RcEditorStyles(isDark),
|
||||
}}
|
||||
onKeyDown={(event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
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}
|
||||
/>
|
||||
<HStack
|
||||
css={{
|
||||
|
|
@ -258,46 +230,32 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element {
|
|||
{errorSaving}
|
||||
</SpanBox>
|
||||
)}
|
||||
{props.lastSaved !== undefined ? (
|
||||
<>
|
||||
{lastChanged === props.lastSaved
|
||||
? 'Saved'
|
||||
: `Last saved ${formattedShortTime(
|
||||
props.lastSaved.toISOString()
|
||||
)}`}
|
||||
</>
|
||||
) : null}
|
||||
{lastChanged !== props.lastSaved && (
|
||||
<SpanBox
|
||||
css={{
|
||||
fontSize: '9px',
|
||||
mt: '1px',
|
||||
color: 'green',
|
||||
marginLeft: 'auto',
|
||||
<SpanBox
|
||||
css={{
|
||||
fontSize: '9px',
|
||||
mt: '10px',
|
||||
color: 'green',
|
||||
marginLeft: 'auto',
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style="ctaDarkYellow"
|
||||
onClick={(event) => {
|
||||
const value = editorRef.current?.getMdValue()
|
||||
if (value) {
|
||||
props.saveText(value, new Date())
|
||||
props.setEditMode('preview')
|
||||
} else {
|
||||
showErrorToast('Error saving note.', {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
}
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
css={{
|
||||
textDecoration: 'underline',
|
||||
border: 'unset',
|
||||
background: 'unset',
|
||||
'&:hover': {
|
||||
border: 'unset',
|
||||
background: 'unset',
|
||||
},
|
||||
}}
|
||||
onClick={(event) => {
|
||||
const value = editorRef.current?.getMdValue()
|
||||
if (value) {
|
||||
props.saveText(value, new Date())
|
||||
}
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
</SpanBox>
|
||||
)}
|
||||
Save
|
||||
</Button>
|
||||
</SpanBox>
|
||||
</HStack>
|
||||
</VStack>
|
||||
) : (
|
||||
|
|
@ -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 {
|
|||
</HStack>
|
||||
<SpanBox css={{ padding: '20px', width: '100%', height: '100%' }}>
|
||||
<MarkdownNote
|
||||
targetId={props.targetId}
|
||||
placeHolder={props.placeHolder}
|
||||
mode={props.mode}
|
||||
sizeMode={props.sizeMode}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { styled } from '../tokens/stitches.config'
|
|||
import { HighlightViewNote } from './HighlightNotes'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { isDarkTheme } from '../../lib/themeUpdater'
|
||||
|
||||
type HighlightViewProps = {
|
||||
highlight: Highlight
|
||||
|
|
@ -23,62 +24,70 @@ type HighlightViewProps = {
|
|||
}
|
||||
|
||||
const StyledQuote = styled(Blockquote, {
|
||||
p: '10px',
|
||||
margin: '0px 0px 0px 0px',
|
||||
fontSize: '18px',
|
||||
lineHeight: '27px',
|
||||
borderRadius: '4px',
|
||||
width: '100%',
|
||||
background: 'rgba(255, 210, 52, 0.10)',
|
||||
})
|
||||
|
||||
export function HighlightView(props: HighlightViewProps): JSX.Element {
|
||||
const isDark = isDarkTheme()
|
||||
const [noteMode, setNoteMode] = useState<'preview' | 'edit'>('preview')
|
||||
|
||||
return (
|
||||
<HStack
|
||||
css={{
|
||||
p: '5px',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
alignItems: 'stretch',
|
||||
|
||||
background: '$thBackground',
|
||||
bg: isDark ? '#3D3D3D' : '$thBackground',
|
||||
borderRadius: '6px',
|
||||
boxShadow: '0px 4px 4px rgba(33, 33, 33, 0.1)',
|
||||
'@mdDown': {
|
||||
p: '0px',
|
||||
},
|
||||
}}
|
||||
// <Box
|
||||
// css={{
|
||||
// width: '100%',
|
||||
// height: '100%',
|
||||
// padding: '10px',
|
||||
// background: '$thBackground',
|
||||
// borderRadius: '6px',
|
||||
// boxShadow: '0px 4px 4px rgba(33, 33, 33, 0.1)',
|
||||
// }}
|
||||
// >
|
||||
>
|
||||
<VStack
|
||||
css={{
|
||||
minHeight: '100%',
|
||||
width: '10px',
|
||||
pt: '15px',
|
||||
pt: '10px',
|
||||
pl: '10px',
|
||||
pr: '10px',
|
||||
'@mdDown': {
|
||||
display: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CaretDown size={15} color="#898989" weight="fill" />
|
||||
{/* <CaretDown size={12} color="#898989" weight="fill" /> */}
|
||||
<Box
|
||||
css={{
|
||||
width: '2px',
|
||||
flexGrow: '1',
|
||||
background: '#FFD234',
|
||||
marginTop: '5px',
|
||||
marginLeft: '6px',
|
||||
marginLeft: '5px',
|
||||
flex: '1',
|
||||
marginBottom: '10px',
|
||||
marginBottom: '25px',
|
||||
}}
|
||||
/>
|
||||
</VStack>
|
||||
|
||||
<VStack
|
||||
css={{
|
||||
width: '100%',
|
||||
padding: '10px',
|
||||
paddingLeft: '20px',
|
||||
|
||||
paddingTop: '15px',
|
||||
paddingRight: '15px',
|
||||
|
||||
'@mdDown': {
|
||||
padding: '0px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<StyledQuote>
|
||||
|
|
@ -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 {
|
|||
))}
|
||||
</Box>
|
||||
<HStack
|
||||
css={{ width: '100%', height: '100%', pt: '15px' }}
|
||||
css={{
|
||||
width: '100%',
|
||||
pt: '15px',
|
||||
'@mdDown': {
|
||||
p: '10px',
|
||||
},
|
||||
}}
|
||||
alignment="start"
|
||||
distribution="start"
|
||||
>
|
||||
<HighlightViewNote
|
||||
targetId={props.highlight.id}
|
||||
text={props.highlight.annotation}
|
||||
placeHolder="Add notes to this highlight..."
|
||||
highlight={props.highlight}
|
||||
|
|
@ -123,28 +139,6 @@ export function HighlightView(props: HighlightViewProps): JSX.Element {
|
|||
setEditMode={setNoteMode}
|
||||
updateHighlight={props.updateHighlight}
|
||||
/>
|
||||
<SpanBox
|
||||
css={{
|
||||
lineHeight: '1',
|
||||
marginLeft: '20px',
|
||||
marginTop: '15px',
|
||||
cursor: 'pointer',
|
||||
borderRadius: '1000px',
|
||||
'&:hover': {
|
||||
background: '#EBEBEB',
|
||||
},
|
||||
}}
|
||||
onClick={(event) => {
|
||||
setNoteMode(noteMode == 'preview' ? 'edit' : 'preview')
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
{noteMode === 'edit' ? (
|
||||
<BookOpen size={15} color="#898989" />
|
||||
) : (
|
||||
<PencilLine size={15} color="#898989" />
|
||||
)}
|
||||
</SpanBox>
|
||||
</HStack>
|
||||
</VStack>
|
||||
</HStack>
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import {
|
|||
Archive,
|
||||
ArchiveBox,
|
||||
DotsThree,
|
||||
Note,
|
||||
Notebook,
|
||||
Tag,
|
||||
Trash,
|
||||
Tray,
|
||||
|
|
@ -116,6 +118,27 @@ export function LibraryListCardContent(
|
|||
},
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
props.handleAction('open-notebook')
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Notebook
|
||||
size={19}
|
||||
color={theme.colors.thHighContrast.toString()}
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
props.handleAction('set-labels')
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Tag size={18} color={theme.colors.thHighContrast.toString()} />
|
||||
</Button>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
|
|
@ -145,15 +168,6 @@ export function LibraryListCardContent(
|
|||
>
|
||||
<Trash size={18} color={theme.colors.thHighContrast.toString()} />
|
||||
</Button>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
props.handleAction('set-labels')
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Tag size={18} color={theme.colors.thHighContrast.toString()} />
|
||||
</Button>
|
||||
<CardMenu
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
|
|
|
|||
|
|
@ -25,38 +25,29 @@ export function HighlightViewItem(props: HighlightViewItemProps): JSX.Element {
|
|||
|
||||
return (
|
||||
<HStack
|
||||
css={{ width: '100%', py: '20px' }}
|
||||
css={{
|
||||
width: '100%',
|
||||
pt: '10px',
|
||||
pb: '20px',
|
||||
}}
|
||||
onMouseEnter={() => setHover(true)}
|
||||
onMouseLeave={() => setHover(false)}
|
||||
>
|
||||
<VStack css={{ width: '100%' }}>
|
||||
<VStack css={{ width: '100%', height: '100%' }}>
|
||||
<HighlightView
|
||||
highlight={props.highlight}
|
||||
updateHighlight={props.updateHighlight}
|
||||
/>
|
||||
<SpanBox css={{ mb: '15px' }} />
|
||||
</VStack>
|
||||
<SpanBox
|
||||
css={{
|
||||
marginLeft: 'auto',
|
||||
width: '20px',
|
||||
visibility: hover ? 'unset' : 'hidden',
|
||||
'@media (hover: none)': {
|
||||
visibility: 'unset',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HighlightsMenu
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
highlight={props.highlight}
|
||||
viewInReader={props.viewInReader}
|
||||
setLabelsTarget={props.setSetLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={
|
||||
props.setShowConfirmDeleteHighlightId
|
||||
}
|
||||
/>
|
||||
</SpanBox>
|
||||
<HighlightsMenu
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
highlight={props.highlight}
|
||||
viewInReader={props.viewInReader}
|
||||
setLabelsTarget={props.setSetLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={props.setShowConfirmDeleteHighlightId}
|
||||
/>
|
||||
</HStack>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<VStack
|
||||
distribution="start"
|
||||
css={{ height: '100%', width: '100%', p: '20px' }}
|
||||
css={{
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
p: '40px',
|
||||
'@mdDown': { p: '10px' },
|
||||
}}
|
||||
>
|
||||
<TitledSection
|
||||
<SectionTitle
|
||||
title="Article Notes"
|
||||
editMode={notesEditMode == 'edit'}
|
||||
setEditMode={(edit) => setNotesEditMode(edit ? 'edit' : 'preview')}
|
||||
collapsed={articleNotesCollapsed}
|
||||
setCollapsed={setArticleNotesCollapsed}
|
||||
/>
|
||||
<Box
|
||||
css={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
padding: '10px',
|
||||
background: '$thBackground',
|
||||
borderRadius: '6px',
|
||||
boxShadow: '0px 4px 4px rgba(33, 33, 33, 0.1)',
|
||||
}}
|
||||
>
|
||||
<HighlightNoteBox
|
||||
mode={notesEditMode}
|
||||
sizeMode={props.sizeMode}
|
||||
setEditMode={setNotesEditMode}
|
||||
text={annotations.note?.annotation}
|
||||
placeHolder="Add notes to this document..."
|
||||
saveText={handleSaveNoteText}
|
||||
/>
|
||||
</Box>
|
||||
{!articleNotesCollapsed && (
|
||||
<HStack
|
||||
alignment="start"
|
||||
distribution="start"
|
||||
css={{ width: '100%', mt: '10px', gap: '10px' }}
|
||||
>
|
||||
<ArticleNoteBox
|
||||
mode={notesEditMode}
|
||||
targetId={props.item.id}
|
||||
sizeMode={props.sizeMode}
|
||||
setEditMode={setNotesEditMode}
|
||||
text={annotations.note?.annotation}
|
||||
placeHolder="Add notes to this document..."
|
||||
saveText={handleSaveNoteText}
|
||||
/>
|
||||
</HStack>
|
||||
)}
|
||||
|
||||
<SpanBox css={{ mt: '10px', mb: '25px' }} />
|
||||
<Box css={{ width: '100%' }}>
|
||||
<TitledSection title="Highlights" />
|
||||
<SectionTitle
|
||||
title="Highlights"
|
||||
collapsed={highlightsCollapsed}
|
||||
setCollapsed={setHighlightsCollapsed}
|
||||
/>
|
||||
|
||||
{sortedHighlights.map((highlight) => (
|
||||
<HighlightViewItem
|
||||
key={highlight.id}
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
highlight={highlight}
|
||||
viewInReader={props.viewInReader}
|
||||
setSetLabelsTarget={setLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={setShowConfirmDeleteHighlightId}
|
||||
updateHighlight={() => {
|
||||
dispatchAnnotations({
|
||||
type: 'UPDATE_HIGHLIGHT',
|
||||
updateHighlight: highlight,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{sortedHighlights.length === 0 && (
|
||||
<Box
|
||||
css={{
|
||||
mt: '15px',
|
||||
width: '100%',
|
||||
fontSize: '9px',
|
||||
color: '$thTextSubtle',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mb: '100px',
|
||||
}}
|
||||
>
|
||||
You have not added any highlights to this document.
|
||||
</Box>
|
||||
{!highlightsCollapsed && (
|
||||
<>
|
||||
{sortedHighlights.map((highlight) => (
|
||||
<HighlightViewItem
|
||||
key={highlight.id}
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
highlight={highlight}
|
||||
viewInReader={props.viewInReader}
|
||||
setSetLabelsTarget={setLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={
|
||||
setShowConfirmDeleteHighlightId
|
||||
}
|
||||
updateHighlight={() => {
|
||||
dispatchAnnotations({
|
||||
type: 'UPDATE_HIGHLIGHT',
|
||||
updateHighlight: highlight,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{sortedHighlights.length === 0 && (
|
||||
<Box
|
||||
css={{
|
||||
mt: '15px',
|
||||
width: '100%',
|
||||
fontSize: '9px',
|
||||
color: '$thTextSubtle',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mb: '100px',
|
||||
}}
|
||||
>
|
||||
You have not added any highlights to this document.
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Box
|
||||
{/* <Box
|
||||
css={{
|
||||
'@mdDown': {
|
||||
height: '320px',
|
||||
|
|
@ -358,7 +394,7 @@ export function Notebook(props: NotebookProps): JSX.Element {
|
|||
background: 'transparent',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
/> */}
|
||||
</Box>
|
||||
|
||||
{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 (
|
||||
<>
|
||||
<HStack
|
||||
css={{ width: '100%', gap: '10px' }}
|
||||
alignment="center"
|
||||
distribution="start"
|
||||
<Button
|
||||
style="plainIcon"
|
||||
css={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
gap: '5px',
|
||||
}}
|
||||
onClick={(event) => {
|
||||
props.setCollapsed(!props.collapsed)
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
{/* <CaretDown size={12} color={theme.colors.thNotebookSubtle.toString()} /> */}
|
||||
{props.collapsed ? (
|
||||
<CaretRight
|
||||
size={12}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
) : (
|
||||
<CaretDown
|
||||
size={12}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
)}
|
||||
<StyledText
|
||||
css={{
|
||||
m: '0px',
|
||||
pt: '2px',
|
||||
fontFamily: '$inter',
|
||||
fontStyle: 'normal',
|
||||
fontWeight: '500',
|
||||
fontSize: '12px',
|
||||
lineHeight: '20px',
|
||||
color: '$thNotebookSubtle',
|
||||
}}
|
||||
>
|
||||
{props.title}
|
||||
</StyledText>
|
||||
{props.setEditMode && (
|
||||
<SpanBox
|
||||
css={{
|
||||
marginLeft: 'auto',
|
||||
justifyContent: 'end',
|
||||
lineHeight: '1',
|
||||
alignSelf: 'end',
|
||||
padding: '2px',
|
||||
cursor: 'pointer',
|
||||
borderRadius: '1000px',
|
||||
'&:hover': {
|
||||
background: '#EBEBEB',
|
||||
},
|
||||
}}
|
||||
onClick={(event) => {
|
||||
if (props.setEditMode) {
|
||||
props.setEditMode(!props.editMode)
|
||||
}
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
{props.editMode ? (
|
||||
<BookOpen size={15} color="#898989" />
|
||||
) : (
|
||||
<PencilLine size={15} color="#898989" />
|
||||
)}
|
||||
</SpanBox>
|
||||
)}
|
||||
</HStack>
|
||||
</Button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
|||
}}
|
||||
>
|
||||
<HStack
|
||||
distribution="between"
|
||||
distribution="center"
|
||||
alignment="center"
|
||||
css={{
|
||||
width: '100%',
|
||||
|
|
@ -127,7 +128,7 @@ export function NotebookModal(props: NotebookModalProps): JSX.Element {
|
|||
distribution="center"
|
||||
alignment="center"
|
||||
>
|
||||
<SizeToggle mode={sizeMode} setMode={setSizeMode} />
|
||||
{/* <SizeToggle mode={sizeMode} setMode={setSizeMode} /> */}
|
||||
<Dropdown triggerElement={<MenuTrigger />}>
|
||||
<DropdownOption
|
||||
onSelect={() => {
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<Dropdown
|
||||
triggerElement={
|
||||
<Box
|
||||
css={{
|
||||
display: 'flex',
|
||||
height: '20px',
|
||||
width: '20px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '1000px',
|
||||
'&:hover': {
|
||||
bg: '#898989',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DotsThreeVertical
|
||||
size={20}
|
||||
color={theme.colors.thTextContrast2.toString()}
|
||||
weight="bold"
|
||||
/>
|
||||
</Box>
|
||||
}
|
||||
<VStack
|
||||
distribution="center"
|
||||
alignment="center"
|
||||
css={{ height: '100%', pl: '5px', pt: '5px' }}
|
||||
>
|
||||
<DropdownOption
|
||||
onSelect={async () => {
|
||||
copyHighlight()
|
||||
}}
|
||||
title="Copy"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => {
|
||||
props.setLabelsTarget(props.highlight)
|
||||
}}
|
||||
title="Labels"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => {
|
||||
props.setShowConfirmDeleteHighlightId(props.highlight.id)
|
||||
}}
|
||||
title="Delete"
|
||||
/>
|
||||
<DropdownSeparator />
|
||||
<Link
|
||||
href={`/${props.viewer.profile.username}/${props.item.slug}#${props.highlight.id}`}
|
||||
<Dropdown
|
||||
triggerElement={
|
||||
<Box
|
||||
css={{
|
||||
display: 'flex',
|
||||
height: '20px',
|
||||
width: '20px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: '1000px',
|
||||
'&:hover': {
|
||||
bg: '#898989',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DotsThreeVertical
|
||||
size={20}
|
||||
color={theme.colors.thTextContrast2.toString()}
|
||||
weight="bold"
|
||||
/>
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
<StyledLinkItem
|
||||
onClick={(event) => {
|
||||
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()
|
||||
<DropdownOption
|
||||
onSelect={async () => {
|
||||
copyHighlight()
|
||||
}}
|
||||
title="Copy"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => {
|
||||
props.setLabelsTarget(props.highlight)
|
||||
}}
|
||||
title="Labels"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => {
|
||||
props.setShowConfirmDeleteHighlightId(props.highlight.id)
|
||||
}}
|
||||
title="Delete"
|
||||
/>
|
||||
<DropdownSeparator />
|
||||
<Link
|
||||
href={`/${props.viewer.profile.username}/${props.item.slug}#${props.highlight.id}`}
|
||||
>
|
||||
View In Reader
|
||||
</StyledLinkItem>
|
||||
</Link>
|
||||
</Dropdown>
|
||||
<StyledLinkItem
|
||||
onClick={(event) => {
|
||||
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
|
||||
</StyledLinkItem>
|
||||
</Link>
|
||||
</Dropdown>
|
||||
</VStack>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ const darkThemeSpec = {
|
|||
thLibrarySelectionColor: '#3D3D3D',
|
||||
|
||||
thNotebookSubtle: '#898989',
|
||||
thNotebookHighContrast: '#2A2A2A',
|
||||
|
||||
thTextContrast: '#FFFFFF',
|
||||
thTextContrast2: '#EBEBEB',
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ export function isDarkTheme(): boolean {
|
|||
return (
|
||||
currentTheme === 'Dark' ||
|
||||
currentTheme === 'Darker' ||
|
||||
currentTheme === 'Apollo' ||
|
||||
currentTheme == 'Black'
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue