(
+
+ {inDragOperation && uploadingFiles.length < 1 && (
+
+
+
- Uploading file
-
-
-
-
- )}
-
- {!props.isValidating && props.items.length == 0 ? (
- {
- props.setShowAddLinkModal(true)
- }}
- />
- ) : (
-
- {props.items.map((linkedItem) => (
- div': {
- bg: '$grayBg',
- },
- '&:focus': {
- '> div': {
- bg: '$grayBgActive',
- },
- },
- '&:hover': {
- '> div': {
- bg: '$grayBgActive',
- },
- },
- }}
- >
- {viewerData?.me && (
- {
- if (action === 'delete') {
- setShowRemoveLinkConfirmation(true)
- props.setLinkToRemove(linkedItem)
- } else if (action === 'editTitle') {
- props.setShowEditTitleModal(true)
- props.setLinkToEdit(linkedItem)
- } else if (action == 'unsubscribe') {
- setShowUnsubscribeConfirmation(true)
- props.setLinkToUnsubscribe(linkedItem)
- } else {
- props.actionHandler(action, linkedItem)
- }
- }}
- />
- )}
-
- ))}
-
- )}
-
- {props.hasMore ? (
-
- ) : (
-
+ Drop PDF document to to upload and add to your library
+
+
+
)}
-
-
- )}
-
-
- {/* Temporary code */}
- {/*
+ {uploadingFiles.length > 0 && (
+
+
+
+
+
+
+
+ Uploading file
+
+
+
+
+ )}
+
+ {!props.isValidating && props.items.length == 0 ? (
+
{
+ props.setShowAddLinkModal(true)
+ }}
+ />
+ ) : (
+
+ {props.items.map((linkedItem) => (
+ div': {
+ bg: '$grayBg',
+ },
+ '&:focus': {
+ '> div': {
+ bg: '$grayBgActive',
+ },
+ },
+ '&:hover': {
+ '> div': {
+ bg: '$grayBgActive',
+ },
+ },
+ }}
+ >
+ {viewerData?.me && (
+ {
+ if (action === 'delete') {
+ setShowRemoveLinkConfirmation(true)
+ props.setLinkToRemove(linkedItem)
+ } else if (action === 'editTitle') {
+ props.setShowEditTitleModal(true)
+ props.setLinkToEdit(linkedItem)
+ } else if (action == 'unsubscribe') {
+ setShowUnsubscribeConfirmation(true)
+ props.setLinkToUnsubscribe(linkedItem)
+ } else {
+ props.actionHandler(action, linkedItem)
+ }
+ }}
+ />
+ )}
+
+ ))}
+
+ )}
+
+ {props.hasMore ? (
+
+ ) : (
+
+ )}
+
+
+ )}
+
+
+ {/* Temporary code */}
+ {/*
Files:
{uploadingFiles.map((fileName) => (
@@ -1093,142 +1123,143 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
))}
*/}
- {/* Temporary code */}
- {props.showAddLinkModal && (
- props.setShowAddLinkModal(false)} />
- )}
- {props.showEditTitleModal && (
-
- props.actionHandler('update-item', item)
- }
- onOpenChange={() => props.setShowEditTitleModal(false)}
- item={props.linkToEdit as LibraryItem}
- />
- )}
- {props.shareTarget && viewerData?.me?.profile.username && (
- {
- if (props.shareTarget) {
- const item = document.getElementById(props.shareTarget.node.id)
- if (item) {
- item.focus()
+ {/* Temporary code */}
+ {props.showAddLinkModal && (
+ props.setShowAddLinkModal(false)} />
+ )}
+ {props.showEditTitleModal && (
+
+ props.actionHandler('update-item', item)
+ }
+ onOpenChange={() => props.setShowEditTitleModal(false)}
+ item={props.linkToEdit as LibraryItem}
+ />
+ )}
+ {props.shareTarget && viewerData?.me?.profile.username && (
+ {
+ if (props.shareTarget) {
+ const item = document.getElementById(props.shareTarget.node.id)
+ if (item) {
+ item.focus()
+ }
+ props.setShareTarget(undefined)
}
- props.setShareTarget(undefined)
- }
- }}
- />
- )}
- {props.snoozeTarget && (
- {
- if (!props.snoozeTarget) return
- createReminderMutation(
- props.snoozeTarget?.node.id,
- ReminderType.Tonight,
- true,
- sendReminder
- )
- .then(() => {
- return props.actionHandler('archive', props.snoozeTarget)
- })
- .then(() => {
- showSuccessToast(msg, { position: 'bottom-right' })
- })
- .catch((error) => {
- showErrorToast('There was an error snoozing your link.', {
- position: 'bottom-right',
- })
- })
- }}
- onOpenChange={() => {
- if (props.snoozeTarget) {
- const item = document.getElementById(props.snoozeTarget.node.id)
- if (item) {
- item.focus()
- }
- props.setSnoozeTarget(undefined)
- }
- }}
- />
- )}
- {showRemoveLinkConfirmation && (
-
-
- Are you sure you want to delete this item? All associated notes
- and highlights will be deleted.
-
- {props.linkToRemove?.node && viewerData?.me && (
-
- {}}
- />
-
- )}
-
- }
- onAccept={removeItem}
- acceptButtonLabel="Delete Item"
- onOpenChange={() => setShowRemoveLinkConfirmation(false)}
- />
- )}
- {showUnsubscribeConfirmation && (
- setShowUnsubscribeConfirmation(false)}
- />
- )}
- {props.labelsTarget?.node.id && (
- {
- if (props.labelsTarget) {
- props.labelsTarget.node.labels = labels
- updateState({})
- }
- }}
- save={(labels: Label[]) => {
- if (props.labelsTarget?.node.id) {
- return setLabelsMutation(
- props.labelsTarget.node.id,
- labels.map((label) => label.id)
+ }}
+ />
+ )}
+ {props.snoozeTarget && (
+ {
+ if (!props.snoozeTarget) return
+ createReminderMutation(
+ props.snoozeTarget?.node.id,
+ ReminderType.Tonight,
+ true,
+ sendReminder
)
+ .then(() => {
+ return props.actionHandler('archive', props.snoozeTarget)
+ })
+ .then(() => {
+ showSuccessToast(msg, { position: 'bottom-right' })
+ })
+ .catch((error) => {
+ showErrorToast('There was an error snoozing your link.', {
+ position: 'bottom-right',
+ })
+ })
+ }}
+ onOpenChange={() => {
+ if (props.snoozeTarget) {
+ const item = document.getElementById(props.snoozeTarget.node.id)
+ if (item) {
+ item.focus()
+ }
+ props.setSnoozeTarget(undefined)
+ }
+ }}
+ />
+ )}
+ {showRemoveLinkConfirmation && (
+
+
+ Are you sure you want to delete this item? All associated
+ notes and highlights will be deleted.
+
+ {props.linkToRemove?.node && viewerData?.me && (
+
+ {}}
+ />
+
+ )}
+
}
- return Promise.resolve(undefined)
- }}
- onOpenChange={() => {
- if (props.labelsTarget) {
- const activate = props.labelsTarget
- props.setActiveItem(activate)
- props.setLabelsTarget(undefined)
- }
- }}
- />
- )}
- >
+ onAccept={removeItem}
+ acceptButtonLabel="Delete Item"
+ onOpenChange={() => setShowRemoveLinkConfirmation(false)}
+ />
+ )}
+ {showUnsubscribeConfirmation && (
+ setShowUnsubscribeConfirmation(false)}
+ />
+ )}
+ {props.labelsTarget?.node.id && (
+ {
+ if (props.labelsTarget) {
+ props.labelsTarget.node.labels = labels
+ updateState({})
+ }
+ }}
+ save={(labels: Label[]) => {
+ if (props.labelsTarget?.node.id) {
+ return setLabelsMutation(
+ props.labelsTarget.node.id,
+ labels.map((label) => label.id)
+ )
+ }
+ return Promise.resolve(undefined)
+ }}
+ onOpenChange={() => {
+ if (props.labelsTarget) {
+ const activate = props.labelsTarget
+ props.setActiveItem(activate)
+ props.setLabelsTarget(undefined)
+ }
+ }}
+ />
+ )}
+
+
)
}
diff --git a/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx b/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx
new file mode 100644
index 000000000..6e9e10d35
--- /dev/null
+++ b/packages/web/components/templates/homeFeed/LibraryFilterMenu.tsx
@@ -0,0 +1,219 @@
+import {
+ InputHTMLAttributes,
+ ReactNode,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+import { StyledText } from '../../elements/StyledText'
+import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
+import { SearchIcon } from '../../elements/images/SearchIcon'
+import { theme } from '../../tokens/stitches.config'
+import { Dropdown, DropdownOption } from '../../elements/DropdownElements'
+import { FormInput } from '../../elements/FormElements'
+import { searchBarCommands } from '../../../lib/keyboardShortcuts/navigationShortcuts'
+import { useKeyboardShortcuts } from '../../../lib/keyboardShortcuts/useKeyboardShortcuts'
+import { Button, IconButton } from '../../elements/Button'
+import { Circle, MagnifyingGlass, Plus, Textbox, X } from 'phosphor-react'
+import { OmnivoreNameLogo } from '../../elements/images/OmnivoreNameLogo'
+import { OmnivoreFullLogo } from '../../elements/images/OmnivoreFullLogo'
+import { AvatarDropdown } from '../../elements/AvatarDropdown'
+import { ListSelectorIcon } from '../../elements/images/ListSelectorIcon'
+import { GridSelectorIcon } from '../../elements/images/GridSelectorIcon'
+import { useGetSubscriptionsQuery } from '../../../lib/networking/queries/useGetSubscriptionsQuery'
+import { useGetLabelsQuery } from '../../../lib/networking/queries/useGetLabelsQuery'
+import { Label } from '../../../lib/networking/fragments/labelFragment'
+import { Checkbox } from '@radix-ui/react-checkbox'
+
+export function LibraryFilterMenu(): JSX.Element {
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+function SavedSearches(): JSX.Element {
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+function Subscriptions(): JSX.Element {
+ const { subscriptions } = useGetSubscriptionsQuery()
+ console.log('subscriptions: ', subscriptions)
+
+ return (
+
+ {subscriptions.slice(0, 4).map((item) => {
+ return
+ })}
+
+ View All
+
+
+ )
+}
+
+function Labels(): JSX.Element {
+ const { labels } = useGetLabelsQuery()
+ console.log('labels: ', labels)
+
+ return (
+
+ {labels.slice(0, 4).map((item) => {
+ return
+ })}
+
+ View All
+
+
+ )
+}
+
+type MenuPanelProps = {
+ title: string
+ children: ReactNode
+}
+
+function MenuPanel(props: MenuPanelProps): JSX.Element {
+ return (
+
+
+ {props.title}
+
+ {props.children}
+
+ )
+}
+
+type FilterButtonProps = {
+ text: string
+ spaced?: boolean
+ selected: boolean
+}
+
+function FilterButton(props: FilterButtonProps): JSX.Element {
+ return (
+
+ {props.text}
+
+ )
+}
+
+type LabelButtonProps = {
+ label: Label
+ state: 'on' | 'off' | 'unset'
+}
+
+function LabelButton(props: LabelButtonProps): JSX.Element {
+ return (
+
+
+ {props.label.name}
+
+
+
+
+ )
+}
+
+function AddLinkButton(): JSX.Element {
+ return (
+
+
+
+ )
+}
diff --git a/packages/web/components/templates/homeFeed/LibraryHeader.tsx b/packages/web/components/templates/homeFeed/LibraryHeader.tsx
new file mode 100644
index 000000000..6bf65a93c
--- /dev/null
+++ b/packages/web/components/templates/homeFeed/LibraryHeader.tsx
@@ -0,0 +1,281 @@
+import {
+ InputHTMLAttributes,
+ ReactNode,
+ useEffect,
+ useRef,
+ useState,
+} from 'react'
+import { StyledText } from '../../elements/StyledText'
+import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
+import { SearchIcon } from '../../elements/images/SearchIcon'
+import { theme } from '../../tokens/stitches.config'
+import { Dropdown, DropdownOption } from '../../elements/DropdownElements'
+import { FormInput } from '../../elements/FormElements'
+import { searchBarCommands } from '../../../lib/keyboardShortcuts/navigationShortcuts'
+import { useKeyboardShortcuts } from '../../../lib/keyboardShortcuts/useKeyboardShortcuts'
+import { Button, IconButton } from '../../elements/Button'
+import { MagnifyingGlass, Textbox, X } from 'phosphor-react'
+import { OmnivoreNameLogo } from '../../elements/images/OmnivoreNameLogo'
+import { OmnivoreFullLogo } from '../../elements/images/OmnivoreFullLogo'
+import { AvatarDropdown } from '../../elements/AvatarDropdown'
+import { ListSelectorIcon } from '../../elements/images/ListSelectorIcon'
+import { GridSelectorIcon } from '../../elements/images/GridSelectorIcon'
+
+type LibrarySearchBarProps = {
+ searchTerm?: string
+ applySearchQuery: (searchQuery: string) => void
+}
+
+type LibraryFilter =
+ | 'in:inbox'
+ | 'in:all'
+ | 'in:archive'
+ | 'type:file'
+ | 'type:highlights'
+ | `saved:${string}`
+ | `sort:read`
+
+// get last week's date
+const recentlySavedStartDate = new Date(
+ new Date().getTime() - 7 * 24 * 60 * 60 * 1000
+).toLocaleDateString('en-US')
+
+const FOCUSED_BOXSHADOW = '0px 0px 2px 2px rgba(255, 234, 159, 0.56)'
+
+export function LibraryHeader(props: LibrarySearchBarProps): JSX.Element {
+ const [focused, setFocused] = useState(false)
+ const inputRef = useRef(null)
+ const [searchTerm, setSearchTerm] = useState(props.searchTerm || '')
+
+ useEffect(() => {
+ setSearchTerm(props.searchTerm || '')
+ }, [props.searchTerm])
+
+ useKeyboardShortcuts(
+ searchBarCommands((action) => {
+ if (action === 'focusSearchBar' && inputRef.current) {
+ inputRef.current.select()
+ }
+ })
+ )
+
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+function SearchBox(props: LibrarySearchBarProps): JSX.Element {
+ const inputRef = useRef(null)
+ const [focused, setFocused] = useState(false)
+ const [searchTerm, setSearchTerm] = useState('')
+
+ return (
+
+
+
+
+
+
+ {searchTerm ? (
+
+ ) : (
+
+ requestAnimationFrame(() => inputRef.current.focus())}
+ // we can make it unreachable via keyboard as we have the same message for the SR label
+ tabIndex={-1}
+ >
+ /
+
+
+ )}
+
+
+ )
+}
+
+// Displays the full logo on larger screens, small logo on mobile
+function LogoBox(): JSX.Element {
+ return (
+ <>
+
+
+
+
+
+
+ >
+ )
+}
+
+function ControlButtonBox(): JSX.Element {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ >
+ )
+}