Add trash and archive section, css fixups

This commit is contained in:
Jackson Harper
2024-06-11 16:00:25 +08:00
parent f0898de5d5
commit 64ea02bb2c
14 changed files with 114 additions and 161 deletions

View File

@ -27,6 +27,8 @@ export type NavigationSection =
| 'library'
| 'subscriptions'
| 'highlights'
| 'archive'
| 'trash'
type NavigationLayoutProps = {
children: ReactNode

View File

@ -116,7 +116,7 @@ export function HomeFeedContainer(): JSX.Element {
performActionOnItem,
mutate,
error: fetchItemsError,
} = useGetLibraryItemsQuery(queryInputs)
} = useGetLibraryItemsQuery('inbox', queryInputs)
useEffect(() => {
const handleRevalidate = () => {

View File

@ -73,7 +73,11 @@ const debouncedFetchSearchResults = debounce((query, cb) => {
// the state as Failed. On refresh it will try again if the backend sends "PROCESSING"
const TIMEOUT_DELAYS = [2000, 3500, 5000]
export function LibraryContainer(): JSX.Element {
type LibraryContainerProps = {
folder: string
}
export function LibraryContainer(props: LibraryContainerProps): JSX.Element {
const { viewerData } = useGetViewerQuery()
const router = useRouter()
const { queryValue } = useKBar((state) => ({ queryValue: state.searchQuery }))
@ -81,6 +85,7 @@ export function LibraryContainer(): JSX.Element {
const defaultQuery = {
limit: 10,
folder: props.folder,
sortDescending: true,
searchQuery: undefined,
}
@ -111,7 +116,7 @@ export function LibraryContainer(): JSX.Element {
performActionOnItem,
mutate,
error: fetchItemsError,
} = useGetLibraryItemsQuery(queryInputs)
} = useGetLibraryItemsQuery(props.folder, queryInputs)
useEffect(() => {
const handleRevalidate = () => {
@ -920,7 +925,7 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
height: '100%',
px: '20px',
py: '20px',
width: !showItems ? '100%' : 'unset',
width: '100%',
}}
distribution="start"
alignment="start"
@ -1181,34 +1186,13 @@ function LibraryItems(props: LibraryItemsProps): JSX.Element {
paddingBottom: '0px',
overflow: 'visible',
px: '70px',
'@lgDown': {
px: '10px',
},
gridTemplateColumns:
props.layout == 'LIST_LAYOUT'
? 'none'
: `repeat( auto-fit, minmax(300px, 1fr) )`,
// '@media (max-width: 930px)': {
// gridGap: props.layout == 'LIST_LAYOUT' ? '0px' : '20px',
// },
// '@xlgDown': {
// borderRadius: props.layout == 'LIST_LAYOUT' ? 0 : undefined,
// },
// '@smDown': {
// border: 'unset',
// width: props.layout == 'LIST_LAYOUT' ? '100vw' : undefined,
// margin: props.layout == 'LIST_LAYOUT' ? '16px -16px' : undefined,
// borderRadius: props.layout == 'LIST_LAYOUT' ? 0 : undefined,
// },
// '@media (min-width: 930px)': {
// gridTemplateColumns:
// props.layout == 'LIST_LAYOUT' ? 'none' : 'repeat(2, 1fr)',
// },
// '@media (min-width: 1280px)': {
// gridTemplateColumns:
// props.layout == 'LIST_LAYOUT' ? 'none' : 'repeat(3, 1fr)',
// },
// '@media (min-width: 1600px)': {
// gridTemplateColumns:
// props.layout == 'LIST_LAYOUT' ? 'none' : 'repeat(4, 1fr)',
// },
}}
>
{props.items.map((linkedItem) => (

View File

@ -1,20 +1,12 @@
import { Allotment } from 'allotment'
import 'allotment/dist/style.css'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useRouter } from 'next/router'
import { useKBar } from 'kbar'
import { useState } from 'react'
import { LibraryContainer } from './LibraryContainer'
import { LibrarySideBar } from './LibrarySideBar'
import { HighlightsList } from '../../../pages/highlights'
export function LibraryItemsContainer(): JSX.Element {
const router = useRouter()
return (
<Allotment>
<Allotment.Pane minSize={200}>
<LibraryContainer />
<LibraryContainer folder="inbox" />
</Allotment.Pane>
{/* <Allotment.Pane snap maxSize={400}>
<HighlightsList />

View File

@ -2,7 +2,7 @@ import { ReactNode, useEffect, useMemo, useRef } from 'react'
import { StyledText } from '../../elements/StyledText'
import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
import { Button } from '../../elements/Button'
import { Circle, NewspaperClipping, X } from '@phosphor-icons/react'
import { Circle, X } from '@phosphor-icons/react'
import {
Subscription,
SubscriptionType,

View File

@ -46,55 +46,6 @@ type LibraryFilterMenuProps = {
}
export function LibraryFilterMenu(props: LibraryFilterMenuProps): JSX.Element {
const [labels, setLabels] = usePersistedState<Label[]>({
key: 'menu-labels',
isSessionStorage: false,
initialValue: [],
})
const [savedSearches, setSavedSearches] = usePersistedState<SavedSearch[]>({
key: 'menu-searches',
isSessionStorage: false,
initialValue: [],
})
const [subscriptions, setSubscriptions] = usePersistedState<Subscription[]>({
key: 'menu-subscriptions',
isSessionStorage: false,
initialValue: [],
})
const labelsResponse = useGetLabelsQuery()
const searchesResponse = useGetSavedSearchQuery()
const subscriptionsResponse = useGetSubscriptionsQuery()
useEffect(() => {
if (
!labelsResponse.error &&
!labelsResponse.isLoading &&
labelsResponse.labels
) {
setLabels(labelsResponse.labels)
}
}, [setLabels, labelsResponse])
useEffect(() => {
if (
!subscriptionsResponse.error &&
!subscriptionsResponse.isLoading &&
subscriptionsResponse.subscriptions
) {
setSubscriptions(subscriptionsResponse.subscriptions)
}
}, [setSubscriptions, subscriptionsResponse])
useEffect(() => {
if (
!searchesResponse.error &&
!searchesResponse.isLoading &&
searchesResponse.savedSearches
) {
setSavedSearches(searchesResponse.savedSearches)
}
}, [setSavedSearches, searchesResponse])
return (
<>
<Box

View File

@ -17,17 +17,13 @@ import {
Folder,
FolderOpen,
Tag,
ArrowDown,
CaretDown,
CaretUp,
} from '@phosphor-icons/react'
import {
Subscription,
useGetSubscriptionsQuery,
} from '../../../lib/networking/queries/useGetSubscriptionsQuery'
import { useGetLabelsQuery } from '../../../lib/networking/queries/useGetLabelsQuery'
import { Label } from '../../../lib/networking/fragments/labelFragment'
import { theme } from '../../tokens/stitches.config'
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
import { useGetSavedSearchQuery } from '../../../lib/networking/queries/useGetSavedSearchQuery'
import { SavedSearch } from '../../../lib/networking/fragments/savedSearchFragment'
import Link from 'next/link'
import { NavMenuFooter } from './Footer'
import { FollowingIcon } from '../../elements/icons/FollowingIcon'
@ -49,6 +45,10 @@ import { requestHeaders } from '../../../lib/networking/networkHelpers'
import { v4 as uuidv4 } from 'uuid'
import { showErrorToast } from '../../../lib/toastHelpers'
import { OpenMap } from 'react-arborist/dist/module/state/open-slice'
import { ToggleCaretLeftIcon } from '../../elements/icons/ToggleCaretLeftIcon'
import { ToggleCaretDownIcon } from '../../elements/icons/ToggleCaretDownIcon'
import { TrashIcon } from '../../elements/icons/TrashIcon'
import { ArchiveActionIcon } from '../../elements/icons/home/ArchiveActionIcon'
export const LIBRARY_LEFT_MENU_WIDTH = '275px'
@ -81,55 +81,6 @@ type LibraryFilterMenuProps = {
}
export function NavigationMenu(props: LibraryFilterMenuProps): JSX.Element {
const [labels, setLabels] = usePersistedState<Label[]>({
key: 'menu-labels',
isSessionStorage: false,
initialValue: [],
})
const [savedSearches, setSavedSearches] = usePersistedState<SavedSearch[]>({
key: 'menu-searches',
isSessionStorage: false,
initialValue: [],
})
const [subscriptions, setSubscriptions] = usePersistedState<Subscription[]>({
key: 'menu-subscriptions',
isSessionStorage: false,
initialValue: [],
})
const labelsResponse = useGetLabelsQuery()
const searchesResponse = useGetSavedSearchQuery()
const subscriptionsResponse = useGetSubscriptionsQuery()
useEffect(() => {
if (
!labelsResponse.error &&
!labelsResponse.isLoading &&
labelsResponse.labels
) {
setLabels(labelsResponse.labels)
}
}, [setLabels, labelsResponse])
useEffect(() => {
if (
!subscriptionsResponse.error &&
!subscriptionsResponse.isLoading &&
subscriptionsResponse.subscriptions
) {
setSubscriptions(subscriptionsResponse.subscriptions)
}
}, [setSubscriptions, subscriptionsResponse])
useEffect(() => {
if (
!searchesResponse.error &&
!searchesResponse.isLoading &&
searchesResponse.savedSearches
) {
setSavedSearches(searchesResponse.savedSearches)
}
}, [setSavedSearches, searchesResponse])
return (
<>
<Box
@ -224,6 +175,12 @@ export function NavigationMenu(props: LibraryFilterMenuProps): JSX.Element {
}
const LibraryNav = (props: LibraryFilterMenuProps): JSX.Element => {
const [moreFoldersOpenState, setMoreFoldersOpenState] =
usePersistedState<boolean>({
key: 'nav-menu-more-folders-open',
isSessionStorage: false,
initialValue: false,
})
return (
<VStack
css={{
@ -266,6 +223,48 @@ const LibraryNav = (props: LibraryFilterMenuProps): JSX.Element => {
isSelected={props.section == 'highlights'}
icon={<HighlightsIcon color={theme.colors.highlight.toString()} />}
/>
<Button
style="articleActionIcon"
css={{
display: 'flex',
ml: '15px',
width: '100%',
'&:hover': {
backgroundColor: '$thBackground4',
},
}}
onClick={(event) => {
setMoreFoldersOpenState(!moreFoldersOpenState)
event.preventDefault()
}}
>
<HStack css={{ gap: '20px' }}>
{moreFoldersOpenState ? (
<CaretUp size={12} />
) : (
<CaretDown size={12} />
)}
<SpanBox>More</SpanBox>
</HStack>
</Button>
{moreFoldersOpenState && (
<SpanBox css={{ width: '100%' }}>
<NavButton
{...props}
text="Archive"
section="archive"
isSelected={props.section == 'archive'}
icon={<ArchiveActionIcon color="#F59932" />}
/>
<NavButton
{...props}
text="Trash"
section="trash"
isSelected={props.section == 'trash'}
icon={<TrashIcon color={theme.colors.highlight.toString()} />}
/>
</SpanBox>
)}
</VStack>
)
}

View File

@ -142,13 +142,11 @@ export const recommendationFragment = gql`
}
`
export function useGetLibraryItemsQuery({
limit,
sortDescending,
searchQuery,
cursor,
includeContent = false,
}: LibraryItemsQueryInput): LibraryItemsQueryResponse {
export function useGetLibraryItemsQuery(
folder: string,
{ limit, searchQuery, cursor, includeContent = false }: LibraryItemsQueryInput
): LibraryItemsQueryResponse {
const fullQuery = (`in:${folder} use:folders ` + (searchQuery ?? '')).trim()
const query = gql`
query Search(
$after: String
@ -236,13 +234,13 @@ export function useGetLibraryItemsQuery({
const variables = {
after: cursor,
first: limit,
query: searchQuery,
query: fullQuery,
includeContent,
}
const { data, error, mutate, size, setSize, isValidating } = useSWRInfinite(
(pageIndex, previousPageData) => {
const key = [query, limit, sortDescending, searchQuery, undefined]
const key = [query, variables.first, variables.query, undefined]
const previousResult = previousPageData as LibraryItemsData
if (pageIndex === 0) {
return key
@ -250,7 +248,6 @@ export function useGetLibraryItemsQuery({
return [
query,
limit,
sortDescending,
searchQuery,
pageIndex === 0 ? undefined : previousResult.search.pageInfo.endCursor,
]

View File

@ -0,0 +1,16 @@
import { NavigationLayout } from '../../components/templates/NavigationLayout'
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
export default function Archive(): JSX.Element {
return (
<NavigationLayout
section="archive"
pageMetaDataProps={{
title: 'Archive',
path: '/archive',
}}
>
<LibraryContainer folder="archive" />
</NavigationLayout>
)
}

View File

@ -1,5 +1,4 @@
import { NavigationLayout } from '../../components/templates/NavigationLayout'
import { Box } from '../../components/elements/LayoutPrimitives'
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
export default function Library(): JSX.Element {
@ -11,7 +10,7 @@ export default function Library(): JSX.Element {
path: '/library',
}}
>
<LibraryContainer />
<LibraryContainer folder="inbox" />
</NavigationLayout>
)
}

View File

@ -99,7 +99,7 @@ export default function Account(): JSX.Element {
isUsernameValidationLoading,
])
const { itemsPages, isValidating } = useGetLibraryItemsQuery({
const { itemsPages, isValidating } = useGetLibraryItemsQuery('', {
limit: 0,
searchQuery: 'in:all',
sortDescending: false,

View File

@ -1,7 +1,4 @@
import { NavigationLayout } from '../../components/templates/NavigationLayout'
import { PrimaryLayout } from '../../components/templates/PrimaryLayout'
import { HomeFeedContainer } from '../../components/templates/homeFeed/HomeFeedContainer'
import { Box, VStack } from '../../components/elements/LayoutPrimitives'
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
export default function Subscriptions(): JSX.Element {
@ -13,7 +10,7 @@ export default function Subscriptions(): JSX.Element {
path: '/subscriptions',
}}
>
<LibraryContainer />
<LibraryContainer folder="following" />
</NavigationLayout>
)
}

View File

@ -33,7 +33,7 @@ export default function BulkPerformer(): JSX.Element {
const [errorMessage, setErrorMessage] = useState<string | undefined>()
const [runningState, setRunningState] = useState<RunningState>('none')
const { itemsPages, isValidating } = useGetLibraryItemsQuery({
const { itemsPages, isValidating } = useGetLibraryItemsQuery('', {
searchQuery: query,
limit: 1,
sortDescending: false,

View File

@ -0,0 +1,16 @@
import { NavigationLayout } from '../../components/templates/NavigationLayout'
import { LibraryContainer } from '../../components/templates/library/LibraryContainer'
export default function Trash(): JSX.Element {
return (
<NavigationLayout
section="trash"
pageMetaDataProps={{
title: 'Trash',
path: '/trash',
}}
>
<LibraryContainer folder="trash" />
</NavigationLayout>
)
}