Handle changing the list layout and search term using a coordinator pattern

This commit is contained in:
Jackson Harper
2022-08-15 14:44:05 +08:00
parent b6d58d15be
commit bd89ee4e17
4 changed files with 118 additions and 58 deletions

View File

@ -1,4 +1,4 @@
import { Box, HStack, SpanBox, VStack } from './../../elements/LayoutPrimitives'
import { HStack, SpanBox, VStack } from './../../elements/LayoutPrimitives'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { LibraryMenu } from './LibraryMenu'
@ -6,19 +6,58 @@ import { LibraryAvatar } from './LibraryAvatar'
import { LibrarySearchBar } from './LibrarySearchBar'
import { LibraryList } from './LibraryList'
import { LibraryHeadline } from './LibraryHeadline'
import { useCallback, useState } from 'react'
import { LibraryItemsQueryInput } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { usePersistedState } from '../../../lib/hooks/usePersistedState'
export type SearchCoordinator = {
applySearch: (searchTerm: string) => void
}
const useSearchCoordinator = () => {
const applySearch = useCallback((searchTerm: string) => {
}, [])
return {
applySearch
}
}
export type LibraryLayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
export type LayoutCoordinator = {
layout: LibraryLayoutType
setLayout: (type: LibraryLayoutType) => void
}
const useLibraryLayoutCoordinator = () => {
const [layout, setLayout] = usePersistedState<LibraryLayoutType>({
key: 'libraryLayout',
initialValue: 'GRID_LAYOUT',
})
return {
layout,
setLayout
}
}
export function LibraryContainer(): JSX.Element {
useGetUserPreferences()
const { viewerData } = useGetViewerQuery()
const searchCoordinator = useSearchCoordinator()
const layoutCoordinator = useLibraryLayoutCoordinator()
return (
<>
<VStack alignment="start" distribution="start" css={{ width: '100vw', height: '100vh', overflow: 'hidden', bg: '$libraryBackground' }}>
<HStack alignment="start" distribution="start" css={{ width: '100%' }}>
<SpanBox css={{ width: '100%', height: '90px' }}>
<LibrarySearchBar />
<LibrarySearchBar coordinator={searchCoordinator} />
</SpanBox>
<SpanBox css={{ marginLeft: 'auto', width: '130px', height: '100%' }}>
<LibraryAvatar viewer={viewerData?.me} />
@ -27,8 +66,8 @@ export function LibraryContainer(): JSX.Element {
<HStack alignment="start" distribution="start" css={{ width: '100%', height: '100%' }}>
<LibraryMenu />
<VStack alignment="start" distribution="start" css={{ width: '100%', height: '100%', mr: '20px' }}>
<LibraryHeadline />
<LibraryList />
<LibraryHeadline layoutCoordinator={layoutCoordinator} />
<LibraryList layoutCoordinator={layoutCoordinator} />
</VStack>
</HStack>
</VStack>

View File

@ -5,21 +5,33 @@ import { theme } from '../../tokens/stitches.config'
import { LibraryListLayoutIcon } from '../../elements/images/LibraryListLayoutIcon'
import { LibraryGridLayoutIcon } from '../../elements/images/LibraryGridLayoutIcon'
import { Button } from '../../elements/Button'
import { LayoutCoordinator, LibraryLayoutType } from './LibraryContainer'
import { useCallback } from 'react'
export type LibraryHeadlineProps = {
layoutCoordinator: LayoutCoordinator
}
export function LibraryHeadline(): JSX.Element {
useGetUserPreferences()
export function LibraryHeadline(props: LibraryHeadlineProps): JSX.Element {
const typeColor = useCallback((type: LibraryLayoutType) => {
return (
props.layoutCoordinator.layout === type
? theme.colors.omnivoreCtaYellow.toString()
: "#D6D6D6"
)
}, [props.layoutCoordinator.layout])
return (
<HStack alignment="center" distribution="start" css={{ pt: '4px', pb: '8px', width: '100%', pr: '15px' }}>
<StyledText style="libraryHeader">Home</StyledText>
<HStack alignment="center" distribution="start" css={{ marginLeft: 'auto', gap: '16px' }}>
<Button style="ctaDarkYellow">Add Link</Button>
<Button style="ghost">
<LibraryListLayoutIcon color="#D6D6D6" />
<Button style="ghost" onClick={() => props.layoutCoordinator.setLayout('LIST_LAYOUT')}>
<LibraryListLayoutIcon color={typeColor('LIST_LAYOUT')} />
</Button>
<Button style="ghost">
<LibraryGridLayoutIcon color={theme.colors.omnivoreCtaYellow.toString()} />
<Button style="ghost" onClick={() => props.layoutCoordinator.setLayout('GRID_LAYOUT')}>
<LibraryGridLayoutIcon color={typeColor('GRID_LAYOUT')} />
</Button>
</HStack>
</HStack>

View File

@ -1,21 +1,22 @@
import { Box } from '../../elements/LayoutPrimitives'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { useMemo, useState } from 'react'
import { useMemo } from 'react'
import { useGetLibraryItemsQuery } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
import { LinkedItemCardAction } from '../../patterns/LibraryCards/CardTypes'
import { LibraryGridCard } from '../../patterns/LibraryCards/LibraryGridCard'
import { LayoutCoordinator } from './LibraryContainer'
import { EmptyLibrary } from '../homeFeed/EmptyLibrary'
export type LayoutType = 'LIST_LAYOUT' | 'GRID_LAYOUT'
export type LibraryListProps = {
layoutCoordinator: LayoutCoordinator
}
export function LibraryList(): JSX.Element {
export function LibraryList(props: LibraryListProps): JSX.Element {
useGetUserPreferences()
const [layout, setLayout] = useState<LayoutType>('GRID_LAYOUT')
const { viewerData } = useGetViewerQuery()
const defaultQuery = {
limit: 50,
sortDescending: true,
@ -33,40 +34,43 @@ export function LibraryList(): JSX.Element {
return items
}, [itemsPages, performActionOnItem])
if (!isValidating && libraryItems.length == 0) {
return (
<EmptyLibrary
onAddLinkClicked={() => {
}}
/>
)
}
return (
<Box css={{ overflowY: 'scroll' }}>
{/* // {!isValidating && items.length == 0 ? (
// <EmptyLibrary
// onAddLinkClicked={() => {
// }}
// />
// ) : ( */}
<Box
css={{
display: 'grid',
gridGap: layout == 'LIST_LAYOUT' ? '0' : '16px',
width: '100%',
display: 'grid',
gridAutoRows: 'auto',
borderRadius: '8px',
marginBottom: '0px',
paddingRight: '14px',
paddingTop: '0px',
marginTop: layout == 'LIST_LAYOUT' ? '21px' : '0',
paddingBottom: layout == 'LIST_LAYOUT' ? '0px' : '21px',
marginTop: '0px',
paddingBottom: '21px',
'@smDown': {
border: 'unset',
width: layout == 'LIST_LAYOUT' ? '100vw' : undefined,
margin: layout == 'LIST_LAYOUT' ? '16px -16px' : undefined,
borderRadius: layout == 'LIST_LAYOUT' ? 0 : undefined,
width: props.layoutCoordinator.layout == 'LIST_LAYOUT' ? '100vw' : undefined,
margin: props.layoutCoordinator.layout == 'LIST_LAYOUT' ? '16px -16px' : undefined,
borderRadius: props.layoutCoordinator.layout == 'LIST_LAYOUT' ? 0 : undefined,
},
'@lg': {
gridTemplateColumns:
layout == 'LIST_LAYOUT' ? 'none' : '1fr 1fr',
props.layoutCoordinator.layout == 'LIST_LAYOUT' ? 'none' : '1fr 1fr',
},
'@xl': {
gridTemplateColumns:
layout == 'LIST_LAYOUT' ? 'none' : 'repeat(3, 1fr)',
props.layoutCoordinator.layout == 'LIST_LAYOUT' ? 'none' : 'repeat(3, 1fr)',
},
}}
>
@ -96,7 +100,7 @@ export function LibraryList(): JSX.Element {
>
{viewerData?.me && (
<LibraryGridCard
layout={layout}
layout={props.layoutCoordinator.layout}
item={linkedItem.node}
viewer={viewerData.me}
handleAction={(action: LinkedItemCardAction) => {

View File

@ -1,26 +1,22 @@
import { Box, HStack, SpanBox, VStack } from './../../elements/LayoutPrimitives'
import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import { useRouter } from 'next/router'
import { useGetUserPreferences } from '../../../lib/networking/queries/useGetUserPreferences'
import { HStack, SpanBox, VStack } from './../../elements/LayoutPrimitives'
import { useState } from 'react'
import { FormInput } from '../../elements/FormElements'
import { Button } from '../../elements/Button'
import { X } from 'phosphor-react'
import { Sliders, SlidersHorizontal, X } from 'phosphor-react'
import { theme } from '../../tokens/stitches.config'
import { SearchCoordinator } from './LibraryContainer'
export type LibrarySearchBarProps = {
coordinator: SearchCoordinator
}
export function LibrarySearchBar(): JSX.Element {
useGetUserPreferences()
const router = useRouter()
const [searchTerm, setSearchTerm] = useState('')
const { viewerData } = useGetViewerQuery()
export function LibrarySearchBar(props: LibrarySearchBarProps): JSX.Element {
const [searchTerm, setSearchTerm] = useState('')
return (
<>
<VStack alignment="start" distribution="start" css={{ pl: '32px', width: '100%', height: '100%' }}>
<HStack alignment="start" distribution="start" css={{ width: '100%' }}>
<HStack alignment="start" distribution="start" css={{ width: '100%', borderBottom: 'solid 1px $grayBorder' }}>
<form
style={{ width: '100%' }}
onSubmit={(event) => {
@ -33,24 +29,34 @@ export function LibrarySearchBar(): JSX.Element {
css={{
width: '100%',
height: '80px',
fontFamily: 'Inter',
fontSize: '24px',
fontFamily: 'Inter',
}}
type="text"
tabIndex={0}
value={searchTerm}
placeholder="Search"
// onFocus={(event) => {
// event.target.select()
// setFocused(true)
// }}
// onBlur={() => {
// setFocused(false)
// }}
// onChange={(event) => {
// setSearchTerm(event.target.value)
// }}
onChange={(event) => {
setSearchTerm(event.target.value)
}}
/>
</form>
{!searchTerm && (
<Button
style="plainIcon"
onClick={(event) => {
// Display the advanced search sheet
}}
css={{
display: 'flex',
flexDirection: 'row',
height: '100%',
alignItems: 'center',
}}
>
<Sliders size={24} color={theme.colors.utilityTextDefault.toString()} />
</Button>
)}
{searchTerm && (
<HStack alignment="center" distribution="start" css={{ height: '100%' }}>
<Button
@ -90,7 +96,6 @@ export function LibrarySearchBar(): JSX.Element {
</HStack>
)}
</HStack>
<SpanBox css={{ width: '100%', height: '1px', bg: '$grayBorder' }} />
</VStack>
</>
)