mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
MOre work on notebook side pane
This commit is contained in:
parent
1e38154e54
commit
aab893584e
13 changed files with 446 additions and 290 deletions
|
|
@ -263,6 +263,7 @@ export const Button = styled('button', {
|
|||
padding: '4px',
|
||||
height: '100%',
|
||||
pt: '6px',
|
||||
minWidth: '25px',
|
||||
|
||||
'&:hover': {
|
||||
bg: '$grayBgHover',
|
||||
|
|
|
|||
113
packages/web/components/patterns/HighlightHoverActions.tsx
Normal file
113
packages/web/components/patterns/HighlightHoverActions.tsx
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import { useState } from 'react'
|
||||
import { Box, SpanBox } from '../elements/LayoutPrimitives'
|
||||
import { LibraryItemNode } from '../../lib/networking/queries/useGetLibraryItemsQuery'
|
||||
import { Button } from '../elements/Button'
|
||||
import { theme } from '../tokens/stitches.config'
|
||||
import {
|
||||
ArchiveBox,
|
||||
Book,
|
||||
BookOpen,
|
||||
Copy,
|
||||
DotsThree,
|
||||
Notebook,
|
||||
Tag,
|
||||
Trash,
|
||||
Tray,
|
||||
} from 'phosphor-react'
|
||||
//import { CardMenu } from '../CardMenu'
|
||||
import { UserBasicData } from '../../lib/networking/queries/useGetViewerQuery'
|
||||
import { Highlight } from '../../lib/networking/fragments/highlightFragment'
|
||||
import { showErrorToast, showSuccessToast } from '../../lib/toastHelpers'
|
||||
|
||||
type HighlightHoverActionsProps = {
|
||||
viewer: UserBasicData
|
||||
highlight: Highlight
|
||||
|
||||
isHovered: boolean
|
||||
|
||||
viewInReader: (highlightId: string) => void
|
||||
|
||||
setLabelsTarget: (target: Highlight) => void
|
||||
setShowConfirmDeleteHighlightId: (set: string) => void
|
||||
}
|
||||
|
||||
export const HighlightHoverActions = (props: HighlightHoverActionsProps) => {
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<Box
|
||||
css={{
|
||||
height: '33px',
|
||||
width: '135px',
|
||||
bg: '$thBackground',
|
||||
display: 'flex',
|
||||
|
||||
pt: '0px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
border: '1px solid $thBackground5',
|
||||
borderRadius: '5px',
|
||||
|
||||
gap: '5px',
|
||||
px: '5px',
|
||||
visibility: props.isHovered || menuOpen ? 'unset' : 'hidden',
|
||||
'&:hover': {
|
||||
boxShadow:
|
||||
'0 1px 3px 0 rgba(0, 0, 0, 0.1),0 1px 2px 0 rgba(0, 0, 0, 0.06);',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
const quote = props.highlight.quote
|
||||
if (quote && navigator.clipboard) {
|
||||
;(async () => {
|
||||
const text = props.highlight.annotation
|
||||
? `> ${quote}\n${props.highlight.annotation}`
|
||||
: quote
|
||||
await navigator.clipboard.writeText(text)
|
||||
showSuccessToast('Highlight copied', {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
})()
|
||||
} else {
|
||||
showErrorToast('No highlight text.', {
|
||||
position: 'bottom-right',
|
||||
})
|
||||
}
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Copy size={19} color={theme.colors.thNotebookSubtle.toString()} />
|
||||
</Button>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
props.setLabelsTarget(props.highlight)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Tag size={18} color={theme.colors.thNotebookSubtle.toString()} />
|
||||
</Button>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
props.viewInReader(props.highlight.id)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<BookOpen size={18} color={theme.colors.thNotebookSubtle.toString()} />
|
||||
</Button>
|
||||
<Button
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
props.setShowConfirmDeleteHighlightId(props.highlight.id)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<Trash size={18} color={theme.colors.thNotebookSubtle.toString()} />
|
||||
</Button>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
@ -145,6 +145,7 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element {
|
|||
{props.mode == 'edit' ? (
|
||||
<VStack
|
||||
css={{
|
||||
pt: '5px',
|
||||
width: '100%',
|
||||
...RcEditorStyles(isDark, false),
|
||||
}}
|
||||
|
|
@ -257,26 +258,11 @@ export function MarkdownNote(props: MarkdownNote): JSX.Element {
|
|||
<>
|
||||
<SpanBox
|
||||
css={{
|
||||
p: '5px',
|
||||
p: props.text ? '10px' : '0px',
|
||||
width: '100%',
|
||||
fontSize: '12px',
|
||||
marginTop: '0px',
|
||||
paddingTop: '5px',
|
||||
|
||||
paddingLeft:
|
||||
props.fillBackground && props.text
|
||||
? '10px'
|
||||
: !props.text
|
||||
? '5px'
|
||||
: '0px',
|
||||
paddingRight:
|
||||
props.fillBackground && props.text
|
||||
? '10px'
|
||||
: !props.text
|
||||
? '5px'
|
||||
: '0px',
|
||||
color: props.text ? '$thHighContrast' : '#898989',
|
||||
// border: props.text ? 'unset' : '1px solid $thBorderColor',
|
||||
borderRadius: '5px',
|
||||
background:
|
||||
props.text && props.fillBackground ? '$thBackground5' : 'unset',
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
/* eslint-disable react/no-children-prop */
|
||||
import {
|
||||
BookOpen,
|
||||
CaretDown,
|
||||
HighlighterCircle,
|
||||
Notebook,
|
||||
PencilLine,
|
||||
} from 'phosphor-react'
|
||||
import { useState } from 'react'
|
||||
import { useMemo, useState } from 'react'
|
||||
import type { Highlight } from '../../lib/networking/fragments/highlightFragment'
|
||||
import { LabelChip } from '../elements/LabelChip'
|
||||
import {
|
||||
|
|
@ -24,6 +17,16 @@ 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 {
|
||||
autoUpdate,
|
||||
offset,
|
||||
size,
|
||||
useFloating,
|
||||
useHover,
|
||||
useInteractions,
|
||||
} from '@floating-ui/react'
|
||||
import { LibraryHoverActions } from './LibraryCards/LibraryHoverActions'
|
||||
import { HighlightHoverActions } from './HighlightHoverActions'
|
||||
|
||||
type HighlightViewProps = {
|
||||
item: ReadableItem
|
||||
|
|
@ -40,95 +43,71 @@ type HighlightViewProps = {
|
|||
}
|
||||
|
||||
const StyledQuote = styled(Blockquote, {
|
||||
p: '10px',
|
||||
p: '0px',
|
||||
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')
|
||||
const [isHovered, setIsHovered] = useState(false)
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
const { refs, floatingStyles, context } = useFloating({
|
||||
open: isOpen,
|
||||
onOpenChange: setIsOpen,
|
||||
middleware: [
|
||||
offset({
|
||||
mainAxis: -25,
|
||||
}),
|
||||
size(),
|
||||
],
|
||||
placement: 'top-end',
|
||||
whileElementsMounted: autoUpdate,
|
||||
})
|
||||
|
||||
const hover = useHover(context)
|
||||
|
||||
const { getReferenceProps, getFloatingProps } = useInteractions([hover])
|
||||
|
||||
console.log(
|
||||
'ref={refs.setFloating, style={floatingStyles}',
|
||||
refs.setFloating,
|
||||
floatingStyles
|
||||
)
|
||||
|
||||
return (
|
||||
<VStack
|
||||
ref={refs.setReference}
|
||||
{...getReferenceProps()}
|
||||
css={{
|
||||
p: '0px',
|
||||
width: '100%',
|
||||
alignItems: 'stretch',
|
||||
bg: isDark ? '#3D3D3D' : '$thBackground',
|
||||
borderRadius: '6px',
|
||||
border: '1px solid $thBorderSubtle',
|
||||
boxShadow: '0px 4px 4px rgba(33, 33, 33, 0.1)',
|
||||
'@mdDown': {
|
||||
p: '0px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HStack
|
||||
css={{
|
||||
borderBottom: '1px solid $thBorderSubtle',
|
||||
width: '100%',
|
||||
height: '40px',
|
||||
px: '15px',
|
||||
}}
|
||||
distribution="start"
|
||||
alignment="center"
|
||||
<Box
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
{...getFloatingProps()}
|
||||
>
|
||||
{props.highlight.annotation ? (
|
||||
<Notebook size={20} color="#757575" />
|
||||
) : (
|
||||
<HighlighterCircle size={20} color="#757575" />
|
||||
)}
|
||||
|
||||
<SpanBox css={{ marginLeft: 'auto' }}>
|
||||
<HighlightsMenu
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
highlight={props.highlight}
|
||||
viewInReader={props.viewInReader}
|
||||
setLabelsTarget={props.setLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={
|
||||
props.setShowConfirmDeleteHighlightId
|
||||
}
|
||||
/>
|
||||
</SpanBox>
|
||||
</HStack>
|
||||
{/* <VStack
|
||||
css={{
|
||||
minHeight: '100%',
|
||||
width: '10px',
|
||||
pt: '10px',
|
||||
pl: '10px',
|
||||
pr: '10px',
|
||||
'@mdDown': {
|
||||
display: 'none',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
css={{
|
||||
width: '2px',
|
||||
flexGrow: '1',
|
||||
background: '#FFD234',
|
||||
marginTop: '5px',
|
||||
marginLeft: '5px',
|
||||
flex: '1',
|
||||
marginBottom: '25px',
|
||||
}}
|
||||
<HighlightHoverActions
|
||||
viewer={props.viewer}
|
||||
highlight={props.highlight}
|
||||
isHovered={isOpen ?? false}
|
||||
viewInReader={props.viewInReader}
|
||||
setLabelsTarget={props.setLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={
|
||||
props.setShowConfirmDeleteHighlightId
|
||||
}
|
||||
/>
|
||||
</VStack> */}
|
||||
|
||||
</Box>
|
||||
<VStack
|
||||
css={{
|
||||
width: '100%',
|
||||
padding: '10px',
|
||||
|
||||
paddingTop: '15px',
|
||||
paddingRight: '15px',
|
||||
|
||||
'@mdDown': {
|
||||
padding: '0px',
|
||||
|
|
@ -140,6 +119,14 @@ export function HighlightView(props: HighlightViewProps): JSX.Element {
|
|||
css={{
|
||||
'> *': {
|
||||
m: '0px',
|
||||
display: 'inline',
|
||||
padding: '2px',
|
||||
backgroundColor:
|
||||
'rgba(var(--colors-highlightBackground), 0.35)',
|
||||
boxShadow:
|
||||
'1px 0 0 rgba(var(--colors-highlightBackground), 0.35), -1px 0 0 rgba(var(--colors-highlightBackground), 0.35)',
|
||||
boxDecorationBreak: 'clone',
|
||||
borderRadius: '2px',
|
||||
},
|
||||
fontSize: '15px',
|
||||
lineHeight: 1.5,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ export const RcEditorStyles = (isDark: boolean, shadow: boolean) => {
|
|||
borderRadius: '5px',
|
||||
backgroundColor: isDark ? '#2A2A2A' : 'white',
|
||||
border: '1px solid $thBorderSubtle',
|
||||
boxShadow: shadow ? '0px 4px 4px rgba(33, 33, 33, 0.1)' : 'unset',
|
||||
},
|
||||
'.rc-md-navigation': {
|
||||
borderRadius: '5px',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { ReadableItem } from '../../../lib/networking/queries/useGetLibraryItems
|
|||
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
|
||||
import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
|
||||
import { HighlightView } from '../../patterns/HighlightView'
|
||||
import { HighlightsMenu } from '../homeFeed/HighlightItem'
|
||||
|
||||
type HighlightViewItemProps = {
|
||||
viewer: UserBasicData
|
||||
|
|
@ -27,8 +26,8 @@ export function HighlightViewItem(props: HighlightViewItemProps): JSX.Element {
|
|||
<HStack
|
||||
css={{
|
||||
width: '100%',
|
||||
pt: '10px',
|
||||
pb: '20px',
|
||||
pt: '0px',
|
||||
pb: '0px',
|
||||
}}
|
||||
onMouseEnter={() => setHover(true)}
|
||||
onMouseLeave={() => setHover(false)}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ import { isTouchScreenDevice } from '../../../lib/deviceType'
|
|||
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
|
||||
import { ReadableItem } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
|
||||
import { SetHighlightLabelsModalPresenter } from './SetLabelsModalPresenter'
|
||||
import SlidingPane from 'react-sliding-pane'
|
||||
import 'react-sliding-pane/dist/react-sliding-pane.css'
|
||||
import { NotebookContent } from './Notebook'
|
||||
import { NotebookHeader } from './NotebookHeader'
|
||||
|
||||
type HighlightsLayerProps = {
|
||||
viewer: UserBasicData
|
||||
|
|
@ -74,15 +78,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<Highlight | undefined>(undefined)
|
||||
|
||||
const [selectionData, setSelectionData] = useSelection(highlightLocations)
|
||||
|
||||
const [labelsTarget, setLabelsTarget] = useState<Highlight | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [labelsTarget, setLabelsTarget] =
|
||||
useState<Highlight | undefined>(undefined)
|
||||
|
||||
const createHighlightFromSelection = useCallback(
|
||||
async (
|
||||
|
|
@ -746,6 +748,50 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
|
|||
|
||||
if (props.showHighlightsModal) {
|
||||
return (
|
||||
<SlidingPane
|
||||
className="sliding-pane-class"
|
||||
isOpen={props.showHighlightsModal}
|
||||
width={/* windowDimensions.width < 600 ? '100%' : */ '420px'}
|
||||
hideHeader={true}
|
||||
from="right"
|
||||
overlayClassName="slide-panel-overlay"
|
||||
onRequestClose={() => {
|
||||
props.setShowHighlightsModal(false)
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<NotebookHeader setShowNotebook={props.setShowHighlightsModal} />
|
||||
<NotebookContent
|
||||
viewer={props.viewer}
|
||||
item={props.item}
|
||||
// highlights={highlights}
|
||||
// onClose={handleCloseNotebook}
|
||||
viewInReader={(highlightId) => {
|
||||
// The timeout here is a bit of a hack to work around rerendering
|
||||
setTimeout(() => {
|
||||
const target = document.querySelector(
|
||||
`[omnivore-highlight-id="${highlightId}"]`
|
||||
)
|
||||
target?.scrollIntoView({
|
||||
block: 'center',
|
||||
behavior: 'auto',
|
||||
})
|
||||
}, 1)
|
||||
history.replaceState(
|
||||
undefined,
|
||||
window.location.href,
|
||||
`#${highlightId}`
|
||||
)
|
||||
|
||||
// props.setShowHighlightsModal(false)
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
</SlidingPane>
|
||||
)
|
||||
|
||||
{
|
||||
/* return (
|
||||
<NotebookModal
|
||||
viewer={props.viewer}
|
||||
item={props.item}
|
||||
|
|
@ -769,7 +815,8 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
|
|||
props.setShowHighlightsModal(false)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) */
|
||||
}
|
||||
}
|
||||
|
||||
return <></>
|
||||
|
|
|
|||
|
|
@ -60,9 +60,8 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
|
|||
const [noteText, setNoteText] = useState<string>('')
|
||||
const [showConfirmDeleteHighlightId, setShowConfirmDeleteHighlightId] =
|
||||
useState<undefined | string>(undefined)
|
||||
const [labelsTarget, setLabelsTarget] = useState<Highlight | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [labelsTarget, setLabelsTarget] =
|
||||
useState<Highlight | undefined>(undefined)
|
||||
const noteState = useRef<NoteState>({
|
||||
isCreating: false,
|
||||
note: undefined,
|
||||
|
|
@ -174,12 +173,9 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
|
|||
return
|
||||
}
|
||||
if (noteState.current.isCreating) {
|
||||
console.log('note is being created, deferring')
|
||||
|
||||
if (noteState.current.createStarted) {
|
||||
const timeSinceStart =
|
||||
new Date().getTime() - noteState.current.createStarted.getTime()
|
||||
console.log(' -- timeSinceStart: ', timeSinceStart)
|
||||
|
||||
if (timeSinceStart > 4000) {
|
||||
createNote(text)
|
||||
|
|
@ -208,8 +204,8 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
|
|||
setNoteText('')
|
||||
}, [noteState, highlights])
|
||||
|
||||
const [articleNotesCollapsed, setArticleNotesCollapsed] = useState(false)
|
||||
const [highlightsCollapsed, setHighlightsCollapsed] = useState(false)
|
||||
const [tabSelected, setTabSelected] = useState<'note' | 'highlights'>('note')
|
||||
|
||||
const [errorSaving, setErrorSaving] = useState<string | undefined>(undefined)
|
||||
const [lastChanged, setLastChanged] = useState<Date | undefined>(undefined)
|
||||
const [lastSaved, setLastSaved] = useState<Date | undefined>(undefined)
|
||||
|
|
@ -221,120 +217,118 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
|
|||
height: '100%',
|
||||
width: '100%',
|
||||
p: '20px',
|
||||
|
||||
bg: '$thLibrarySearchbox',
|
||||
'@mdDown': { p: '15px' },
|
||||
}}
|
||||
>
|
||||
<SectionTitle
|
||||
title="Article Notes"
|
||||
collapsed={articleNotesCollapsed}
|
||||
setCollapsed={setArticleNotesCollapsed}
|
||||
/>
|
||||
{!articleNotesCollapsed && (
|
||||
<>
|
||||
<HStack
|
||||
alignment="start"
|
||||
distribution="start"
|
||||
css={{ width: '100%', mt: '10px', gap: '10px' }}
|
||||
>
|
||||
<ArticleNotes
|
||||
targetId={props.item.id}
|
||||
text={noteText}
|
||||
setText={setNoteText}
|
||||
placeHolder="Add notes to this document..."
|
||||
saveText={handleSaveNoteText}
|
||||
/>
|
||||
</HStack>
|
||||
<HStack
|
||||
css={{
|
||||
minHeight: '15px',
|
||||
width: '100%',
|
||||
fontSize: '9px',
|
||||
mt: '5px',
|
||||
color: '$thTextSubtle',
|
||||
}}
|
||||
alignment="start"
|
||||
distribution="start"
|
||||
>
|
||||
{errorSaving && (
|
||||
<SpanBox
|
||||
css={{
|
||||
width: '100%',
|
||||
fontSize: '9px',
|
||||
mt: '5px',
|
||||
}}
|
||||
>
|
||||
{errorSaving}
|
||||
</SpanBox>
|
||||
)}
|
||||
{lastSaved !== undefined ? (
|
||||
<>
|
||||
{lastChanged === lastSaved
|
||||
? 'Saved'
|
||||
: `Last saved ${formattedShortTime(lastSaved.toISOString())}`}
|
||||
</>
|
||||
) : null}
|
||||
</HStack>
|
||||
</>
|
||||
)}
|
||||
|
||||
<SpanBox css={{ mt: '10px', mb: '25px' }} />
|
||||
<Box css={{ width: '100%' }}>
|
||||
{/* <HStack
|
||||
css={{
|
||||
width: '100%',
|
||||
gap: '30px',
|
||||
fontSize: '13px',
|
||||
borderBottom: '1px solid $thBorderSubtle',
|
||||
}}
|
||||
distribution="start"
|
||||
alignment="start"
|
||||
>
|
||||
<SectionTitle
|
||||
title="Article Note"
|
||||
selected={tabSelected == 'note'}
|
||||
setSelected={() => setTabSelected('note')}
|
||||
/>
|
||||
<SectionTitle
|
||||
title="Highlights"
|
||||
collapsed={highlightsCollapsed}
|
||||
setCollapsed={setHighlightsCollapsed}
|
||||
selected={tabSelected == 'highlights'}
|
||||
setSelected={() => setTabSelected('highlights')}
|
||||
/>
|
||||
</HStack> */}
|
||||
|
||||
{!highlightsCollapsed && (
|
||||
<>
|
||||
{sortedHighlights.map((highlight) => (
|
||||
<HighlightViewItem
|
||||
key={highlight.id}
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
highlight={highlight}
|
||||
viewInReader={props.viewInReader}
|
||||
setSetLabelsTarget={setLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={
|
||||
setShowConfirmDeleteHighlightId
|
||||
}
|
||||
updateHighlight={() => {
|
||||
mutate()
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{sortedHighlights.length === 0 && (
|
||||
<Box
|
||||
css={{
|
||||
p: '10px',
|
||||
mt: '15px',
|
||||
width: '100%',
|
||||
fontSize: '13px',
|
||||
color: '$thTextSubtle',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mb: '100px',
|
||||
|
||||
bg: isDark ? '#3D3D3D' : '$thBackground',
|
||||
borderRadius: '6px',
|
||||
boxShadow: '0px 4px 4px rgba(33, 33, 33, 0.1)',
|
||||
}}
|
||||
>
|
||||
You have not added any highlights to this document.
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{/* <Box
|
||||
{/* {tabSelected == 'note' && ( */}
|
||||
<>
|
||||
<HStack
|
||||
alignment="start"
|
||||
distribution="start"
|
||||
css={{ width: '100%', mt: '20px', gap: '10px' }}
|
||||
>
|
||||
<ArticleNotes
|
||||
targetId={props.item.id}
|
||||
text={noteText}
|
||||
setText={setNoteText}
|
||||
placeHolder="Add notes to this document..."
|
||||
saveText={handleSaveNoteText}
|
||||
/>
|
||||
</HStack>
|
||||
<HStack
|
||||
css={{
|
||||
'@mdDown': {
|
||||
height: '320px',
|
||||
width: '100%',
|
||||
background: 'transparent',
|
||||
},
|
||||
minHeight: '15px',
|
||||
width: '100%',
|
||||
fontSize: '9px',
|
||||
mt: '5px',
|
||||
color: '$thTextSubtle',
|
||||
}}
|
||||
/> */}
|
||||
</Box>
|
||||
alignment="start"
|
||||
distribution="start"
|
||||
>
|
||||
{errorSaving && (
|
||||
<SpanBox
|
||||
css={{
|
||||
width: '100%',
|
||||
fontSize: '9px',
|
||||
mt: '5px',
|
||||
}}
|
||||
>
|
||||
{errorSaving}
|
||||
</SpanBox>
|
||||
)}
|
||||
{lastSaved !== undefined ? (
|
||||
<>
|
||||
{lastChanged === lastSaved
|
||||
? 'Saved'
|
||||
: `Last saved ${formattedShortTime(lastSaved.toISOString())}`}
|
||||
</>
|
||||
) : null}
|
||||
</HStack>
|
||||
</>
|
||||
{/* )} */}
|
||||
|
||||
{/* {tabSelected == 'highlights' && ( */}
|
||||
<VStack css={{ mt: '20px', gap: '30px' }}>
|
||||
{sortedHighlights.map((highlight) => (
|
||||
<HighlightViewItem
|
||||
key={highlight.id}
|
||||
item={props.item}
|
||||
viewer={props.viewer}
|
||||
highlight={highlight}
|
||||
viewInReader={props.viewInReader}
|
||||
setSetLabelsTarget={setLabelsTarget}
|
||||
setShowConfirmDeleteHighlightId={setShowConfirmDeleteHighlightId}
|
||||
updateHighlight={() => {
|
||||
mutate()
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{sortedHighlights.length === 0 && (
|
||||
<Box
|
||||
css={{
|
||||
p: '10px',
|
||||
mt: '15px',
|
||||
width: '100%',
|
||||
fontSize: '13px',
|
||||
color: '$thTextSubtle',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
mb: '100px',
|
||||
bg: isDark ? '#3D3D3D' : '$thBackground',
|
||||
borderRadius: '6px',
|
||||
boxShadow: '0px 4px 4px rgba(33, 33, 33, 0.1)',
|
||||
}}
|
||||
>
|
||||
You have not added any highlights to this document.
|
||||
</Box>
|
||||
)}
|
||||
</VStack>
|
||||
{/* )} */}
|
||||
|
||||
{showConfirmDeleteHighlightId && (
|
||||
<ConfirmationModal
|
||||
|
|
@ -395,8 +389,8 @@ export function NotebookContent(props: NotebookContentProps): JSX.Element {
|
|||
|
||||
type SectionTitleProps = {
|
||||
title: string
|
||||
collapsed: boolean
|
||||
setCollapsed: (set: boolean) => void
|
||||
selected: boolean
|
||||
setSelected: (set: boolean) => void
|
||||
}
|
||||
|
||||
function SectionTitle(props: SectionTitleProps): JSX.Element {
|
||||
|
|
@ -408,30 +402,25 @@ function SectionTitle(props: SectionTitleProps): JSX.Element {
|
|||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
color: props.selected ? '$thTextContrast' : '$thTextSubtle',
|
||||
borderBottom: props.selected
|
||||
? '1px solid $thTextContrast'
|
||||
: '1px solid transparent',
|
||||
}}
|
||||
onClick={(event) => {
|
||||
props.setCollapsed(!props.collapsed)
|
||||
props.setSelected(true)
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
{props.collapsed ? (
|
||||
<CaretRight
|
||||
size={12}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
) : (
|
||||
<CaretDown
|
||||
size={12}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
)}
|
||||
<StyledText
|
||||
css={{
|
||||
m: '0px',
|
||||
pt: '2px',
|
||||
pb: '2px',
|
||||
px: '5px',
|
||||
fontFamily: '$inter',
|
||||
fontWeight: '500',
|
||||
fontSize: '12px',
|
||||
fontSize: '13px',
|
||||
color: '$thNotebookSubtle',
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@ export const NotebookHeader = (props: NotebookHeaderProps) => {
|
|||
top: '0px',
|
||||
height: '50px',
|
||||
p: '20px',
|
||||
background: '#F8FAFB',
|
||||
borderTopLeftRadius: '10px',
|
||||
overflow: 'clip',
|
||||
background: '$thLibrarySearchbox',
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
|
|
@ -49,18 +51,18 @@ export const NotebookHeader = (props: NotebookHeaderProps) => {
|
|||
alignment="center"
|
||||
>
|
||||
<Dropdown triggerElement={<MenuTrigger />}>
|
||||
{/* <DropdownOption
|
||||
<DropdownOption
|
||||
onSelect={() => {
|
||||
exportHighlights()
|
||||
// exportHighlights()
|
||||
}}
|
||||
title="Export Notebook"
|
||||
/>
|
||||
<DropdownOption
|
||||
onSelect={() => {
|
||||
setShowConfirmDeleteNote(true)
|
||||
// setShowConfirmDeleteNote(true)
|
||||
}}
|
||||
title="Delete Article Note"
|
||||
/> */}
|
||||
/>
|
||||
</Dropdown>
|
||||
<CloseButton close={handleClose} />
|
||||
</HStack>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { useGetLabelsQuery } from '../../../lib/networking/queries/useGetLabelsQ
|
|||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { randomLabelColorHex } from '../../../utils/settings-page/labels/labelColorObjects'
|
||||
import { LabelsDispatcher } from '../../../lib/hooks/useSetPageLabels'
|
||||
import * as Dialog from '@radix-ui/react-dialog'
|
||||
|
||||
type SetLabelsModalProps = {
|
||||
provider: LabelsProvider
|
||||
|
|
@ -30,9 +31,8 @@ export function SetLabelsModal(props: SetLabelsModalProps): JSX.Element {
|
|||
const availableLabels = useGetLabelsQuery()
|
||||
const [tabCount, setTabCount] = useState(-1)
|
||||
const [tabStartValue, setTabStartValue] = useState('')
|
||||
const [errorMessage, setErrorMessage] = useState<string | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [errorMessage, setErrorMessage] =
|
||||
useState<string | undefined>(undefined)
|
||||
const errorTimeoutRef = useRef<NodeJS.Timeout | undefined>()
|
||||
const [highlightLastLabel, setHighlightLastLabel] = useState(false)
|
||||
|
||||
|
|
@ -171,44 +171,46 @@ export function SetLabelsModal(props: SetLabelsModalProps): JSX.Element {
|
|||
|
||||
return (
|
||||
<ModalRoot defaultOpen onOpenChange={props.onOpenChange}>
|
||||
<ModalOverlay />
|
||||
<ModalContent
|
||||
tabIndex={0}
|
||||
css={{
|
||||
border: '1px solid $grayBorder',
|
||||
backgroundColor: '$thBackground',
|
||||
}}
|
||||
onPointerDownOutside={(event) => {
|
||||
event.preventDefault()
|
||||
props.onOpenChange(false)
|
||||
}}
|
||||
onEscapeKeyDown={(event) => {
|
||||
props.onOpenChange(false)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<VStack distribution="start" css={{ height: '100%' }}>
|
||||
<SpanBox css={{ pt: '0px', px: '16px', width: '100%' }}>
|
||||
<ModalTitleBar title="Labels" onOpenChange={props.onOpenChange} />
|
||||
</SpanBox>
|
||||
<SetLabelsControl
|
||||
inputValue={inputValue}
|
||||
setInputValue={setInputValue}
|
||||
clearInputState={clearInputState}
|
||||
selectedLabels={props.selectedLabels}
|
||||
dispatchLabels={props.dispatchLabels}
|
||||
tabCount={tabCount}
|
||||
setTabCount={setTabCount}
|
||||
tabStartValue={tabStartValue}
|
||||
setTabStartValue={setTabStartValue}
|
||||
highlightLastLabel={highlightLastLabel}
|
||||
setHighlightLastLabel={setHighlightLastLabel}
|
||||
deleteLastLabel={deleteLastLabel}
|
||||
selectOrCreateLabel={selectOrCreateLabel}
|
||||
errorMessage={errorMessage}
|
||||
/>
|
||||
</VStack>
|
||||
</ModalContent>
|
||||
<Dialog.Portal>
|
||||
<ModalOverlay />
|
||||
<ModalContent
|
||||
tabIndex={0}
|
||||
css={{
|
||||
border: '1px solid $grayBorder',
|
||||
backgroundColor: '$thBackground',
|
||||
}}
|
||||
onPointerDownOutside={(event) => {
|
||||
event.preventDefault()
|
||||
props.onOpenChange(false)
|
||||
}}
|
||||
onEscapeKeyDown={(event) => {
|
||||
props.onOpenChange(false)
|
||||
event.preventDefault()
|
||||
}}
|
||||
>
|
||||
<VStack distribution="start" css={{ height: '100%' }}>
|
||||
<SpanBox css={{ pt: '0px', px: '16px', width: '100%' }}>
|
||||
<ModalTitleBar title="Labels" onOpenChange={props.onOpenChange} />
|
||||
</SpanBox>
|
||||
<SetLabelsControl
|
||||
inputValue={inputValue}
|
||||
setInputValue={setInputValue}
|
||||
clearInputState={clearInputState}
|
||||
selectedLabels={props.selectedLabels}
|
||||
dispatchLabels={props.dispatchLabels}
|
||||
tabCount={tabCount}
|
||||
setTabCount={setTabCount}
|
||||
tabStartValue={tabStartValue}
|
||||
setTabStartValue={setTabStartValue}
|
||||
highlightLastLabel={highlightLastLabel}
|
||||
setHighlightLastLabel={setHighlightLastLabel}
|
||||
deleteLastLabel={deleteLastLabel}
|
||||
selectOrCreateLabel={selectOrCreateLabel}
|
||||
errorMessage={errorMessage}
|
||||
/>
|
||||
</VStack>
|
||||
</ModalContent>
|
||||
</Dialog.Portal>
|
||||
</ModalRoot>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
"react-markdown-editor-lite": "^1.3.4",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-pro-sidebar": "^0.7.1",
|
||||
"react-sliding-pane": "^7.3.0",
|
||||
"react-spinners": "^0.13.7",
|
||||
"react-super-responsive-table": "^5.2.1",
|
||||
"react-topbar-progress-indicator": "^4.1.1",
|
||||
|
|
|
|||
|
|
@ -419,20 +419,22 @@ button {
|
|||
margin: 0px;
|
||||
}
|
||||
|
||||
.omnivore-masonry-grid {
|
||||
display: -webkit-box; /* Not needed if autoprefixing */
|
||||
display: -ms-flexbox; /* Not needed if autoprefixing */
|
||||
display: flex;
|
||||
margin-left: -16px; /* gutter size offset */
|
||||
margin-right: 14px;
|
||||
width: auto;
|
||||
.slide-panel-overlay {
|
||||
z-index: 100 !important;
|
||||
background: transparent !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
.omnivore-masonry-grid_column {
|
||||
padding-left: 16px; /* gutter size */
|
||||
background-clip: padding-box;
|
||||
|
||||
.slide-pane__content {
|
||||
padding: 0px !important;
|
||||
pointer-events: all;
|
||||
border-top-left-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
border-left: 1px solid var(--colors-thNotebookSubtle);
|
||||
background: var(--colors-thLibrarySearchbox);
|
||||
}
|
||||
|
||||
/* .omnivore-masonry-grid_column > div {
|
||||
background: grey;
|
||||
margin-bottom: 16px;
|
||||
} */
|
||||
.slide-pane {
|
||||
background: transparent !important;
|
||||
box-shadow: 0px 4px 4px rgba(33, 33, 33, 0.1) !important;
|
||||
}
|
||||
30
yarn.lock
30
yarn.lock
|
|
@ -14467,6 +14467,11 @@ executable@^4.1.1:
|
|||
dependencies:
|
||||
pify "^2.2.0"
|
||||
|
||||
exenv@^1.2.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==
|
||||
|
||||
exit@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
|
||||
|
|
@ -23841,6 +23846,11 @@ react-is@^18.0.0:
|
|||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-lifecycles-compat@^3.0.0:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-markdown-editor-lite@^1.3.4:
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-markdown-editor-lite/-/react-markdown-editor-lite-1.3.4.tgz#77992d2389b9427a06595c63d95f52be66e5fea9"
|
||||
|
|
@ -23877,6 +23887,16 @@ react-masonry-css@^1.0.16:
|
|||
resolved "https://registry.yarnpkg.com/react-masonry-css/-/react-masonry-css-1.0.16.tgz#72b28b4ae3484e250534700860597553a10f1a2c"
|
||||
integrity sha512-KSW0hR2VQmltt/qAa3eXOctQDyOu7+ZBevtKgpNDSzT7k5LA/0XntNa9z9HKCdz3QlxmJHglTZ18e4sX4V8zZQ==
|
||||
|
||||
react-modal@^3.14.3:
|
||||
version "3.16.1"
|
||||
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b"
|
||||
integrity sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==
|
||||
dependencies:
|
||||
exenv "^1.2.0"
|
||||
prop-types "^15.7.2"
|
||||
react-lifecycles-compat "^3.0.0"
|
||||
warning "^4.0.3"
|
||||
|
||||
react-popper-tooltip@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz#329569eb7b287008f04fcbddb6370452ad3f9eac"
|
||||
|
|
@ -23960,6 +23980,14 @@ react-slidedown@^2.4.5:
|
|||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
react-sliding-pane@^7.3.0:
|
||||
version "7.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-sliding-pane/-/react-sliding-pane-7.3.0.tgz#a6a03b90db216e7ec6f746c7e649d19ba03ff4e0"
|
||||
integrity sha512-KCyxw2BBvXjwYm1UX83Vk67D4kxec2icJxrSPidNus8voh1yB1K6bluwShAe3OvN5zk8H9InL22jGomTUOOudw==
|
||||
dependencies:
|
||||
prop-types "^15.7.2"
|
||||
react-modal "^3.14.3"
|
||||
|
||||
react-spinners@^0.13.7:
|
||||
version "0.13.7"
|
||||
resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.13.7.tgz#0f423c415bfa56765ce9fb36ff604e52a92b37a9"
|
||||
|
|
@ -27779,7 +27807,7 @@ walker@~1.0.5:
|
|||
dependencies:
|
||||
makeerror "1.0.12"
|
||||
|
||||
warning@^4.0.2:
|
||||
warning@^4.0.2, warning@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
|
||||
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
|
||||
|
|
|
|||
Loading…
Reference in a new issue