Merge pull request #4102 from omnivore-app/feat/web-home-tweaks-03
More tweaks to the web home section
This commit is contained in:
38
packages/web/components/elements/icons/MoveToInboxIcon.tsx
Normal file
38
packages/web/components/elements/icons/MoveToInboxIcon.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
/* eslint-disable functional/no-class */
|
||||
/* eslint-disable functional/no-this-expression */
|
||||
import { IconProps } from './IconProps'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
export class MoveToInboxIcon extends React.Component<IconProps> {
|
||||
render() {
|
||||
const size = (this.props.size || 26).toString()
|
||||
const color = (this.props.color || '#2A2A2A').toString()
|
||||
return (
|
||||
<svg
|
||||
width="21"
|
||||
height="21"
|
||||
viewBox="0 0 21 21"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M13.125 8.75V18.375L8.75 15.75L4.375 18.375V8.75C4.375 8.05381 4.65156 7.38613 5.14384 6.89384C5.63613 6.40156 6.30381 6.125 7 6.125H10.5C11.1962 6.125 11.8639 6.40156 12.3562 6.89384C12.8484 7.38613 13.125 8.05381 13.125 8.75Z"
|
||||
stroke={color}
|
||||
strokeWidth="1.25"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.625 2.625H14C14.6962 2.625 15.3639 2.90156 15.8562 3.39384C16.3484 3.88613 16.625 4.55381 16.625 5.25V14.875"
|
||||
stroke={color}
|
||||
strokeWidth="1.25"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -128,9 +128,8 @@ function HighlightCard(props: HighlightCardProps): JSX.Element {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const [showConfirmDeleteHighlightId, setShowConfirmDeleteHighlightId] =
|
||||
useState<undefined | string>(undefined)
|
||||
const [labelsTarget, setLabelsTarget] = useState<Highlight | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [labelsTarget, setLabelsTarget] =
|
||||
useState<Highlight | undefined>(undefined)
|
||||
|
||||
const viewInReader = useCallback(
|
||||
(highlightId: string) => {
|
||||
@ -187,9 +186,21 @@ function HighlightCard(props: HighlightCardProps): JSX.Element {
|
||||
fontFamily: '$inter',
|
||||
padding: '20px',
|
||||
marginBottom: '20px',
|
||||
bg: '$thBackground2',
|
||||
bg: '$readerBg',
|
||||
borderRadius: '8px',
|
||||
cursor: 'pointer',
|
||||
border: '1px solid $thLeftMenuBackground',
|
||||
'&:focus': {
|
||||
outline: 'none',
|
||||
'> div': {
|
||||
outline: 'none',
|
||||
bg: '$thBackgroundActive',
|
||||
},
|
||||
},
|
||||
'&:hover': {
|
||||
bg: '$thBackgroundActive',
|
||||
boxShadow: '$cardBoxShadow',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
|
||||
@ -75,7 +75,6 @@ export function HomeContainer(): JSX.Element {
|
||||
>
|
||||
{homeData.sections?.map((homeSection, idx) => {
|
||||
if (homeSection.items.length < 1) {
|
||||
console.log('empty home section: ', homeSection)
|
||||
return <SpanBox key={`section-${idx}`}></SpanBox>
|
||||
}
|
||||
switch (homeSection.layout) {
|
||||
@ -224,7 +223,6 @@ const TopPicksHomeSection = (props: HomeSectionProps): JSX.Element => {
|
||||
items?: HomeItem[]
|
||||
}
|
||||
) => {
|
||||
console.log('handling action: ', action)
|
||||
switch (action.type) {
|
||||
case 'RESET':
|
||||
return action.items ?? []
|
||||
|
||||
@ -65,6 +65,7 @@ export function LibraryGridCard(props: LinkedItemCardProps): JSX.Element {
|
||||
pl: '0px',
|
||||
padding: '0px',
|
||||
width: '100%',
|
||||
maxWidth: '400px',
|
||||
height: '100%',
|
||||
minHeight: '270px',
|
||||
borderRadius: '5px',
|
||||
|
||||
@ -13,6 +13,9 @@ import { TrashIcon } from '../../elements/icons/TrashIcon'
|
||||
import { LabelIcon } from '../../elements/icons/LabelIcon'
|
||||
import { UnarchiveIcon } from '../../elements/icons/UnarchiveIcon'
|
||||
import { BrowserIcon } from '../../elements/icons/BrowserIcon'
|
||||
import { LibraryIcon } from '../../elements/icons/LibraryIcon'
|
||||
import useLibraryItemActions from '../../../lib/hooks/useLibraryItemActions'
|
||||
import { MoveToInboxIcon } from '../../elements/icons/MoveToInboxIcon'
|
||||
|
||||
type LibraryHoverActionsProps = {
|
||||
viewer: UserBasicData
|
||||
@ -25,6 +28,7 @@ type LibraryHoverActionsProps = {
|
||||
|
||||
export const LibraryHoverActions = (props: LibraryHoverActionsProps) => {
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
const { moveItem } = useLibraryItemActions()
|
||||
|
||||
return (
|
||||
<Box
|
||||
@ -71,28 +75,47 @@ export const LibraryHoverActions = (props: LibraryHoverActionsProps) => {
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
title={props.item.isArchived ? 'Unarchive (e)' : 'Archive (e)'}
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
const action = props.item.isArchived ? 'unarchive' : 'archive'
|
||||
props.handleAction(action)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
{props.item.isArchived ? (
|
||||
<UnarchiveIcon
|
||||
{props.item.folder == 'following' ? (
|
||||
<Button
|
||||
title="Move to library"
|
||||
style="hoverActionIcon"
|
||||
onClick={async (event) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
if (await moveItem(props.item.id)) {
|
||||
props.handleAction('update-item')
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MoveToInboxIcon
|
||||
size={21}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
) : (
|
||||
<ArchiveIcon
|
||||
size={21}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
title={props.item.isArchived ? 'Unarchive (e)' : 'Archive (e)'}
|
||||
style="hoverActionIcon"
|
||||
onClick={(event) => {
|
||||
const action = props.item.isArchived ? 'unarchive' : 'archive'
|
||||
props.handleAction(action)
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}}
|
||||
>
|
||||
{props.item.isArchived ? (
|
||||
<UnarchiveIcon
|
||||
size={21}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
) : (
|
||||
<ArchiveIcon
|
||||
size={21}
|
||||
color={theme.colors.thNotebookSubtle.toString()}
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
title="Remove (#)"
|
||||
style="hoverActionIcon"
|
||||
|
||||
@ -17,7 +17,6 @@ import { ThemeId, theme } from '../tokens/stitches.config'
|
||||
import { NavigationMenu } from './navMenu/NavigationMenu'
|
||||
import { Button } from '../elements/Button'
|
||||
import { List } from '@phosphor-icons/react'
|
||||
import { usePersistedState } from '../../lib/hooks/usePersistedState'
|
||||
import { LIBRARY_LEFT_MENU_WIDTH } from './navMenu/LibraryLegacyMenu'
|
||||
import { AddLinkModal } from './AddLinkModal'
|
||||
import { saveUrlMutation } from '../../lib/networking/mutations/saveUrlMutation'
|
||||
@ -39,6 +38,9 @@ type NavigationLayoutProps = {
|
||||
rightPane?: ReactNode
|
||||
section: NavigationSection
|
||||
pageMetaDataProps?: PageMetaDataProps
|
||||
|
||||
showNavigationMenu: boolean
|
||||
setShowNavigationMenu: (show: boolean) => void
|
||||
}
|
||||
|
||||
export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
|
||||
@ -50,12 +52,6 @@ export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
|
||||
const [showKeyboardCommandsModal, setShowKeyboardCommandsModal] =
|
||||
useState(false)
|
||||
|
||||
const [showNavMenu, setShowNavMenu, isLoading] = usePersistedState<boolean>({
|
||||
key: 'nav-show-menu',
|
||||
isSessionStorage: false,
|
||||
initialValue: true,
|
||||
})
|
||||
|
||||
useKeyboardShortcuts(navigationCommands(router))
|
||||
|
||||
useKeyboardShortcuts(
|
||||
@ -136,15 +132,15 @@ export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
|
||||
}
|
||||
}, [showLogout])
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<HStack
|
||||
css={{ width: '100vw', height: '100vh' }}
|
||||
distribution="start"
|
||||
alignment="start"
|
||||
></HStack>
|
||||
)
|
||||
}
|
||||
// if (isLoading) {
|
||||
// return (
|
||||
// <HStack
|
||||
// css={{ width: '100vw', height: '100vh' }}
|
||||
// distribution="start"
|
||||
// alignment="start"
|
||||
// ></HStack>
|
||||
// )
|
||||
// }
|
||||
|
||||
return (
|
||||
<HStack
|
||||
@ -157,21 +153,22 @@ export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
|
||||
) : null}
|
||||
|
||||
<Header
|
||||
menuOpen={showNavMenu}
|
||||
menuOpen={props.showNavigationMenu}
|
||||
toggleMenu={() => {
|
||||
setShowNavMenu(!showNavMenu)
|
||||
props.setShowNavigationMenu(!props.showNavigationMenu)
|
||||
}}
|
||||
/>
|
||||
{!isLoading && showNavMenu && (
|
||||
{props.showNavigationMenu && (
|
||||
<>
|
||||
<NavigationMenu
|
||||
section={props.section}
|
||||
setShowAddLinkModal={setShowAddLinkModal}
|
||||
showMenu={showNavMenu}
|
||||
showMenu={props.showNavigationMenu}
|
||||
/>
|
||||
<SpanBox
|
||||
css={{
|
||||
width: LIBRARY_LEFT_MENU_WIDTH,
|
||||
flexShrink: '0',
|
||||
'@mdDown': {
|
||||
display: 'none',
|
||||
},
|
||||
|
||||
@ -21,9 +21,6 @@ export type MultiSelectProps = {
|
||||
searchTerm: string | undefined
|
||||
applySearchQuery: (searchQuery: string) => void
|
||||
|
||||
showFilterMenu: boolean
|
||||
setShowFilterMenu: (show: boolean) => void
|
||||
|
||||
numItemsSelected: number
|
||||
multiSelectMode: MultiSelectMode
|
||||
setMultiSelectMode: (mode: MultiSelectMode) => void
|
||||
|
||||
@ -19,6 +19,7 @@ import {
|
||||
} from '../../../lib/networking/queries/typeaheadSearch'
|
||||
import type {
|
||||
LibraryItem,
|
||||
LibraryItemNode,
|
||||
LibraryItemsQueryInput,
|
||||
} from '../../../lib/networking/queries/useGetLibraryItemsQuery'
|
||||
import { useGetLibraryItemsQuery } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
|
||||
@ -35,7 +36,7 @@ import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
|
||||
import { AddLinkModal } from '../AddLinkModal'
|
||||
import { EditLibraryItemModal } from '../homeFeed/EditItemModals'
|
||||
import { EmptyLibrary } from '../homeFeed/EmptyLibrary'
|
||||
import { LegacyLibraryHeader, MultiSelectMode } from '../homeFeed/LibraryHeader'
|
||||
import { MultiSelectMode } from '../homeFeed/LibraryHeader'
|
||||
import { UploadModal } from '../UploadModal'
|
||||
import { BulkAction } from '../../../lib/networking/mutations/bulkActionMutation'
|
||||
import { bulkActionMutation } from '../../../lib/networking/mutations/bulkActionMutation'
|
||||
@ -75,6 +76,9 @@ const TIMEOUT_DELAYS = [2000, 3500, 5000]
|
||||
|
||||
type LibraryContainerProps = {
|
||||
folder: string
|
||||
filterFunc: (item: LibraryItemNode) => boolean
|
||||
|
||||
showNavigationMenu: boolean
|
||||
}
|
||||
|
||||
export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
@ -92,13 +96,11 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
|
||||
const gridContainerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const [labelsTarget, setLabelsTarget] = useState<LibraryItem | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [labelsTarget, setLabelsTarget] =
|
||||
useState<LibraryItem | undefined>(undefined)
|
||||
|
||||
const [notebookTarget, setNotebookTarget] = useState<LibraryItem | undefined>(
|
||||
undefined
|
||||
)
|
||||
const [notebookTarget, setNotebookTarget] =
|
||||
useState<LibraryItem | undefined>(undefined)
|
||||
|
||||
const [showAddLinkModal, setShowAddLinkModal] = useState(false)
|
||||
const [showEditTitleModal, setShowEditTitleModal] = useState(false)
|
||||
@ -151,12 +153,14 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
|
||||
const libraryItems = useMemo(() => {
|
||||
const items =
|
||||
itemsPages?.flatMap((ad) => {
|
||||
return ad.search.edges.map((it) => ({
|
||||
...it,
|
||||
isLoading: it.node.state === 'PROCESSING',
|
||||
}))
|
||||
}) || []
|
||||
itemsPages
|
||||
?.flatMap((ad) => {
|
||||
return ad.search.edges.map((it) => ({
|
||||
...it,
|
||||
isLoading: it.node.state === 'PROCESSING',
|
||||
}))
|
||||
})
|
||||
.filter((item) => props.filterFunc(item.node)) || []
|
||||
return items
|
||||
}, [itemsPages, performActionOnItem])
|
||||
|
||||
@ -785,6 +789,7 @@ export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
|
||||
setIsChecked={setIsChecked}
|
||||
itemIsChecked={itemIsChecked}
|
||||
multiSelectMode={multiSelectMode}
|
||||
showNavigationMenu={props.showNavigationMenu}
|
||||
setMultiSelectMode={setMultiSelectMode}
|
||||
performMultiSelectAction={performMultiSelectAction}
|
||||
searchTerm={queryInputs.searchQuery}
|
||||
@ -883,6 +888,8 @@ export type HomeFeedContentProps = {
|
||||
locale: string
|
||||
) => Promise<void>
|
||||
|
||||
showNavigationMenu: boolean
|
||||
|
||||
setIsChecked: (itemId: string, set: boolean) => void
|
||||
itemIsChecked: (itemId: string) => boolean
|
||||
|
||||
@ -937,9 +944,7 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
|
||||
layout={layout}
|
||||
viewer={viewerData?.me}
|
||||
updateLayout={updateLayout}
|
||||
showFilterMenu={true}
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
setShowFilterMenu={() => {}}
|
||||
showFilterMenu={props.showNavigationMenu}
|
||||
searchTerm={props.searchTerm}
|
||||
applySearchQuery={(searchQuery: string) => {
|
||||
props.applySearchQuery(searchQuery)
|
||||
|
||||
@ -4,18 +4,15 @@ import { theme } from '../../tokens/stitches.config'
|
||||
import { FormInput } from '../../elements/FormElements'
|
||||
import { searchBarCommands } from '../../../lib/keyboardShortcuts/navigationShortcuts'
|
||||
import { useKeyboardShortcuts } from '../../../lib/keyboardShortcuts/useKeyboardShortcuts'
|
||||
import { Button, IconButton } from '../../elements/Button'
|
||||
import { Button } from '../../elements/Button'
|
||||
import { FunnelSimple, X } from '@phosphor-icons/react'
|
||||
import { LayoutType, LibraryMode } from '../homeFeed/HomeFeedContainer'
|
||||
import { LayoutType } from '../homeFeed/HomeFeedContainer'
|
||||
import { OmnivoreSmallLogo } from '../../elements/images/OmnivoreNameLogo'
|
||||
import { DEFAULT_HEADER_HEIGHT, HeaderSpacer } from '../homeFeed/HeaderSpacer'
|
||||
import { LIBRARY_LEFT_MENU_WIDTH } from '../navMenu/LibraryMenu'
|
||||
import { BulkAction } from '../../../lib/networking/mutations/bulkActionMutation'
|
||||
import { HeaderToggleGridIcon } from '../../elements/icons/HeaderToggleGridIcon'
|
||||
import { HeaderToggleListIcon } from '../../elements/icons/HeaderToggleListIcon'
|
||||
import { HeaderToggleTLDRIcon } from '../../elements/icons/HeaderToggleTLDRIcon'
|
||||
import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
|
||||
import { userHasFeature } from '../../../lib/featureFlag'
|
||||
import {
|
||||
MultiSelectControls,
|
||||
CheckBoxButton,
|
||||
@ -33,7 +30,6 @@ export type LibraryHeaderProps = {
|
||||
applySearchQuery: (searchQuery: string) => void
|
||||
|
||||
showFilterMenu: boolean
|
||||
setShowFilterMenu: (show: boolean) => void
|
||||
|
||||
numItemsSelected: number
|
||||
multiSelectMode: MultiSelectMode
|
||||
@ -93,7 +89,7 @@ export function LibraryHeader(props: LibraryHeaderProps): JSX.Element {
|
||||
right: '0',
|
||||
},
|
||||
'@xlgDown': {
|
||||
px: '40px',
|
||||
px: props.showFilterMenu ? '0px' : '40px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
||||
@ -2,15 +2,15 @@ import { Allotment } from 'allotment'
|
||||
import 'allotment/dist/style.css'
|
||||
import { LibraryContainer } from './LibraryContainer'
|
||||
|
||||
export function LibraryItemsContainer(): JSX.Element {
|
||||
return (
|
||||
<Allotment>
|
||||
<Allotment.Pane minSize={200}>
|
||||
<LibraryContainer folder="inbox" />
|
||||
</Allotment.Pane>
|
||||
{/* <Allotment.Pane snap maxSize={400}>
|
||||
<HighlightsList />
|
||||
</Allotment.Pane> */}
|
||||
</Allotment>
|
||||
)
|
||||
}
|
||||
// export function LibraryItemsContainer(): JSX.Element {
|
||||
// return (
|
||||
// <Allotment>
|
||||
// {/* <Allotment.Pane minSize={200}>
|
||||
// <LibraryContainer folder="inbox" />
|
||||
// </Allotment.Pane> */}
|
||||
// {/* <Allotment.Pane snap maxSize={400}>
|
||||
// <HighlightsList />
|
||||
// </Allotment.Pane> */}
|
||||
// </Allotment>
|
||||
// )
|
||||
// }
|
||||
|
||||
@ -185,6 +185,8 @@ const Shortcuts = (props: LibraryFilterMenuProps): JSX.Element => {
|
||||
initialValue: [],
|
||||
})
|
||||
|
||||
console.log('got shortcuts: ', shortcuts)
|
||||
|
||||
// const shortcuts: Shortcut[] = [
|
||||
// {
|
||||
// id: '12asdfasdf',
|
||||
|
||||
@ -57,6 +57,8 @@ export type Shortcut = {
|
||||
label?: Label
|
||||
|
||||
join?: string
|
||||
|
||||
children?: Shortcut[]
|
||||
}
|
||||
|
||||
type NavigationMenuProps = {
|
||||
@ -93,7 +95,20 @@ export function NavigationMenu(props: NavigationMenuProps): JSX.Element {
|
||||
zIndex: 5,
|
||||
}}
|
||||
>
|
||||
{/* This gives a header when scrolling so the menu button is visible still */}
|
||||
<Box
|
||||
css={{
|
||||
position: 'fixed',
|
||||
width: LIBRARY_LEFT_MENU_WIDTH,
|
||||
top: '0',
|
||||
left: '0',
|
||||
height: '60px',
|
||||
bg: '$thLeftMenuBackground',
|
||||
zIndex: '100',
|
||||
}}
|
||||
></Box>
|
||||
<Box css={{ width: '100%', height: '60px' }}></Box>
|
||||
|
||||
<LibraryNav {...props} />
|
||||
<Shortcuts {...props} />
|
||||
<NavMenuFooter {...props} showFullThemeSection={true} />
|
||||
@ -248,7 +263,6 @@ const Shortcuts = (props: NavigationMenuProps): JSX.Element => {
|
||||
type: 'internal',
|
||||
index: 0,
|
||||
})
|
||||
console.log('create leaf: ', result)
|
||||
}
|
||||
}, [treeRef])
|
||||
|
||||
@ -411,6 +425,7 @@ const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
|
||||
const { ref, width, height } = useResizeObserver()
|
||||
|
||||
const { isValidating, data } = useSWR('/api/shortcuts', getShortcuts, {
|
||||
revalidateOnFocus: false,
|
||||
fallbackData: cachedShortcutsData(),
|
||||
onSuccess(data) {
|
||||
localStorage.setItem('/api/shortcuts', JSON.stringify(data))
|
||||
@ -496,7 +511,6 @@ const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
|
||||
|
||||
const onActivate = useCallback(
|
||||
(node: NodeApi<Shortcut>) => {
|
||||
console.log('onActivate: ', node)
|
||||
if (node.data.type == 'folder') {
|
||||
const join = node.data.join
|
||||
if (join == 'or') {
|
||||
@ -505,7 +519,6 @@ const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
|
||||
return `(${child.data.filter})`
|
||||
})
|
||||
.join(' OR ')
|
||||
console.log('query: ', query)
|
||||
}
|
||||
} else if (node.data.section != null && node.data.filter != null) {
|
||||
router.push(`/l/${node.data.section}?q=${node.data.filter}`)
|
||||
@ -514,8 +527,38 @@ const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
|
||||
[tree, router]
|
||||
)
|
||||
|
||||
function countTotalShortcuts(shortcuts: Shortcut[]): number {
|
||||
let total = 0
|
||||
|
||||
for (const shortcut of shortcuts) {
|
||||
// Count the current shortcut
|
||||
total++
|
||||
|
||||
// If the shortcut has children, recursively count them
|
||||
if (shortcut.children && shortcut.children.length > 0) {
|
||||
total += countTotalShortcuts(shortcut.children)
|
||||
}
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
const maximumHeight = useMemo(() => {
|
||||
if (!data) {
|
||||
return 320
|
||||
}
|
||||
return countTotalShortcuts(data as Shortcut[]) * 36
|
||||
}, [data])
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<Box
|
||||
ref={ref}
|
||||
css={{
|
||||
height: maximumHeight,
|
||||
flexGrow: 1,
|
||||
minBlockSize: 0,
|
||||
}}
|
||||
>
|
||||
{!isValidating && (
|
||||
<Tree
|
||||
ref={props.treeRef}
|
||||
@ -529,12 +572,12 @@ const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
|
||||
rowHeight={36}
|
||||
initialOpenState={folderOpenState}
|
||||
width={width}
|
||||
height={640}
|
||||
height={maximumHeight}
|
||||
>
|
||||
{NodeRenderer}
|
||||
</Tree>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { useCallback } from 'react'
|
||||
import { setLinkArchivedMutation } from '../networking/mutations/setLinkArchivedMutation'
|
||||
import {
|
||||
showErrorToast,
|
||||
@ -8,6 +8,7 @@ import {
|
||||
import { deleteLinkMutation } from '../networking/mutations/deleteLinkMutation'
|
||||
import { updatePageMutation } from '../networking/mutations/updatePageMutation'
|
||||
import { State } from '../networking/fragments/articleFragment'
|
||||
import { moveToFolderMutation } from '../networking/mutations/moveToLibraryMutation'
|
||||
|
||||
export default function useLibraryItemActions() {
|
||||
const archiveItem = useCallback(async (itemId: string) => {
|
||||
@ -51,15 +52,11 @@ export default function useLibraryItemActions() {
|
||||
}, [])
|
||||
|
||||
const moveItem = useCallback(async (itemId: string) => {
|
||||
const result = await setLinkArchivedMutation({
|
||||
linkId: itemId,
|
||||
archived: true,
|
||||
})
|
||||
|
||||
const result = await moveToFolderMutation(itemId, 'inbox')
|
||||
if (result) {
|
||||
showSuccessToast('Link archived', { position: 'bottom-right' })
|
||||
showSuccessToast('Moved to library', { position: 'bottom-right' })
|
||||
} else {
|
||||
showErrorToast('Error archiving link', { position: 'bottom-right' })
|
||||
showErrorToast('Error moving item', { position: 'bottom-right' })
|
||||
}
|
||||
|
||||
return !!result
|
||||
|
||||
@ -31,6 +31,8 @@ export enum State {
|
||||
SUCCEEDED = 'SUCCEEDED',
|
||||
PROCESSING = 'PROCESSING',
|
||||
FAILED = 'FAILED',
|
||||
DELETED = 'DELETED',
|
||||
ARCHIVED = 'ARCHIVED',
|
||||
}
|
||||
|
||||
export enum PageType {
|
||||
|
||||
@ -147,8 +147,6 @@ export function useGetHomeItems(): HomeItemResponse {
|
||||
}
|
||||
|
||||
const result = data as HomeResult
|
||||
console.log('result: ', result)
|
||||
|
||||
if (result && result.home.errorCodes) {
|
||||
const errorCodes = result.home.errorCodes
|
||||
return {
|
||||
@ -159,7 +157,6 @@ export function useGetHomeItems(): HomeItemResponse {
|
||||
}
|
||||
|
||||
if (result && result.home && result.home.edges) {
|
||||
console.log('data', result.home)
|
||||
return {
|
||||
mutate,
|
||||
error: false,
|
||||
|
||||
@ -82,6 +82,7 @@ export type LibraryItemNode = {
|
||||
readingProgressTopPercent?: number
|
||||
readingProgressAnchorIndex: number
|
||||
slug: string
|
||||
folder?: string
|
||||
isArchived: boolean
|
||||
description: string
|
||||
ownedByViewer: boolean
|
||||
@ -168,6 +169,7 @@ export function useGetLibraryItemsQuery(
|
||||
title
|
||||
slug
|
||||
url
|
||||
folder
|
||||
pageType
|
||||
contentReader
|
||||
createdAt
|
||||
@ -284,6 +286,7 @@ export function useGetLibraryItemsQuery(
|
||||
action: LibraryItemAction,
|
||||
item: LibraryItem
|
||||
) => {
|
||||
console.log('performing action on items: ', action)
|
||||
if (!responsePages) {
|
||||
return
|
||||
}
|
||||
@ -295,11 +298,16 @@ export function useGetLibraryItemsQuery(
|
||||
|
||||
for (const searchResults of responsePages) {
|
||||
const itemIndex = getIndexOf(searchResults.search, item)
|
||||
console.log(' --- item index', itemIndex)
|
||||
if (itemIndex !== -1) {
|
||||
if (typeof mutatedItem === 'undefined') {
|
||||
searchResults.search.edges.splice(itemIndex, 1)
|
||||
} else {
|
||||
searchResults.search.edges.splice(itemIndex, 1, mutatedItem)
|
||||
console.log(
|
||||
'earchResults.search.edges:',
|
||||
searchResults.search.edges[itemIndex]
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
@ -309,17 +317,14 @@ export function useGetLibraryItemsQuery(
|
||||
|
||||
switch (action) {
|
||||
case 'archive':
|
||||
if (/in:all/.test(query)) {
|
||||
updateData({
|
||||
cursor: item.cursor,
|
||||
node: {
|
||||
...item.node,
|
||||
isArchived: true,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
updateData(undefined)
|
||||
}
|
||||
console.log('setting item archived')
|
||||
updateData({
|
||||
cursor: item.cursor,
|
||||
node: {
|
||||
...item.node,
|
||||
isArchived: true,
|
||||
},
|
||||
})
|
||||
|
||||
setLinkArchivedMutation({
|
||||
linkId: item.node.id,
|
||||
@ -332,6 +337,8 @@ export function useGetLibraryItemsQuery(
|
||||
}
|
||||
})
|
||||
|
||||
mutate()
|
||||
|
||||
break
|
||||
case 'unarchive':
|
||||
if (/in:all/.test(query)) {
|
||||
@ -421,27 +428,6 @@ export function useGetLibraryItemsQuery(
|
||||
readingProgressAnchorIndex: 0,
|
||||
})
|
||||
break
|
||||
// case 'unsubscribe':
|
||||
// if (!!item.node.subscription) {
|
||||
// updateData({
|
||||
// cursor: item.cursor,
|
||||
// node: {
|
||||
// ...item.node,
|
||||
// subscription: undefined,
|
||||
// },
|
||||
// })
|
||||
// unsubscribeMutation(item.node.subscription).then((res) => {
|
||||
// if (res) {
|
||||
// showSuccessToast('Unsubscribed successfully', {
|
||||
// position: 'bottom-right',
|
||||
// })
|
||||
// } else {
|
||||
// showErrorToast('Error unsubscribing', {
|
||||
// position: 'bottom-right',
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
case 'update-item':
|
||||
updateData(item)
|
||||
break
|
||||
|
||||
@ -8,11 +8,19 @@ import { HomeContainer } from '../../components/nav-containers/HomeContainer'
|
||||
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
|
||||
import { useMemo } from 'react'
|
||||
import { HighlightsContainer } from '../../components/nav-containers/HighlightsContainer'
|
||||
import { usePersistedState } from '../../lib/hooks/usePersistedState'
|
||||
|
||||
export default function Home(): JSX.Element {
|
||||
const router = useRouter()
|
||||
useApplyLocalTheme()
|
||||
|
||||
const [showNavigationMenu, setShowNavigationMenu] =
|
||||
usePersistedState<boolean>({
|
||||
key: 'nav-show-menu',
|
||||
isSessionStorage: false,
|
||||
initialValue: true,
|
||||
})
|
||||
|
||||
const section: NavigationSection | undefined = useMemo(() => {
|
||||
if (!router.isReady) {
|
||||
return undefined
|
||||
@ -34,13 +42,50 @@ export default function Home(): JSX.Element {
|
||||
case 'highlights':
|
||||
return <HighlightsContainer />
|
||||
case 'library':
|
||||
return <LibraryContainer folder="inbox" />
|
||||
return (
|
||||
<LibraryContainer
|
||||
folder="inbox"
|
||||
filterFunc={(item) => {
|
||||
console.log('filtering: ', item)
|
||||
return (
|
||||
item.state != 'DELETED' &&
|
||||
!item.isArchived &&
|
||||
item.folder == 'inbox'
|
||||
)
|
||||
}}
|
||||
showNavigationMenu={showNavigationMenu}
|
||||
/>
|
||||
)
|
||||
case 'subscriptions':
|
||||
return <LibraryContainer folder="following" />
|
||||
return (
|
||||
<LibraryContainer
|
||||
folder="following"
|
||||
filterFunc={(item) => {
|
||||
return (
|
||||
item.state != 'DELETED' &&
|
||||
!item.isArchived &&
|
||||
item.folder == 'following'
|
||||
)
|
||||
}}
|
||||
showNavigationMenu={showNavigationMenu}
|
||||
/>
|
||||
)
|
||||
case 'archive':
|
||||
return <LibraryContainer folder="archive" />
|
||||
return (
|
||||
<LibraryContainer
|
||||
folder="archive"
|
||||
filterFunc={(item) => item.state != 'DELETED' && item.isArchived}
|
||||
showNavigationMenu={showNavigationMenu}
|
||||
/>
|
||||
)
|
||||
case 'trash':
|
||||
return <LibraryContainer folder="trash" />
|
||||
return (
|
||||
<LibraryContainer
|
||||
folder="trash"
|
||||
filterFunc={(item) => item.state == 'DELETED'}
|
||||
showNavigationMenu={showNavigationMenu}
|
||||
/>
|
||||
)
|
||||
|
||||
default:
|
||||
return <></>
|
||||
@ -48,7 +93,11 @@ export default function Home(): JSX.Element {
|
||||
}
|
||||
|
||||
return (
|
||||
<NavigationLayout section={section ?? 'home'}>
|
||||
<NavigationLayout
|
||||
section={section ?? 'home'}
|
||||
showNavigationMenu={showNavigationMenu}
|
||||
setShowNavigationMenu={setShowNavigationMenu}
|
||||
>
|
||||
{sectionView(section)}
|
||||
</NavigationLayout>
|
||||
)
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
import { NavigationLayout } from '../../components/templates/NavigationLayout'
|
||||
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
|
||||
|
||||
export default function Subscriptions(): JSX.Element {
|
||||
return (
|
||||
<NavigationLayout
|
||||
section="subscriptions"
|
||||
pageMetaDataProps={{
|
||||
title: 'Subscriptions',
|
||||
path: '/subscriptions',
|
||||
}}
|
||||
>
|
||||
<LibraryContainer folder="following" />
|
||||
</NavigationLayout>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user