Improve empty state next action suggestions

This commit is contained in:
Jackson Harper 2023-08-28 18:24:48 +08:00
parent 1eee42f2f3
commit 766e32d872
3 changed files with 156 additions and 39 deletions

View file

@ -1,8 +1,4 @@
import {
VStack,
HStack,
SpanBox,
} from '../elements/LayoutPrimitives'
import { VStack, HStack, SpanBox } from '../elements/LayoutPrimitives'
import { StyledText } from '../elements/StyledText'
import Link from 'next/link'
import { Button } from '../elements/Button'
@ -22,11 +18,14 @@ export function ErrorLayout(props: ErrorLayoutProps): JSX.Element {
return (
<VStack alignment="center" distribution="start" css={{ height: '100%' }}>
<HStack alignment="center" css={{ mt: '64px', verticalAlign: 'middle' }}>
<StyledText style="headline" css={{
marginRight: '25px',
padding: '32px',
borderRight: '1px solid $grayText',
}}>
<StyledText
style="headline"
css={{
marginRight: '25px',
padding: '32px',
borderRight: '1px solid $grayText',
}}
>
{props.statusCode}
</StyledText>
<StyledText style="body">
@ -34,9 +33,11 @@ export function ErrorLayout(props: ErrorLayoutProps): JSX.Element {
</StyledText>
</HStack>
<SpanBox css={{ height: '64px' }} />
<Link passHref href={viewerData?.me ? "/home" : "/login"}>
<Button style="ctaDarkYellow">{viewerData?.me ? "Go Home" : "Login"}</Button>
<Link passHref href={viewerData?.me ? '/home' : '/login'}>
<Button style="ctaDarkYellow">
{viewerData?.me ? 'Go Home' : 'Login'}
</Button>
</Link>
</VStack>
)
}
}

View file

@ -1,15 +1,20 @@
import Link from 'next/link'
import { Book } from 'phosphor-react'
import { Button } from '../../elements/Button'
import { VStack } from '../../elements/LayoutPrimitives'
import { Box, HStack, SpanBox, VStack } from '../../elements/LayoutPrimitives'
import { StyledText } from '../../elements/StyledText'
import { theme } from '../../tokens/stitches.config'
import { useMemo } from 'react'
import { searchQuery } from '../../../lib/networking/queries/search'
import { LIBRARY_LEFT_MENU_WIDTH } from './LibraryFilterMenu'
import { LayoutType } from './HomeFeedContainer'
import { ArrowRightIcon } from '../../elements/icons/ArrowRightIcon'
type EmptyLibraryProps = {
searchTerm: string | undefined
onAddLinkClicked: () => void
layoutType: LayoutType
}
type MessageType = 'feed' | 'newsletter' | 'library'
@ -75,6 +80,108 @@ const HelpMessage = (props: HelpMessageProps) => {
return <></>
}
export const ErrorBox = (props: HelpMessageProps) => {
const errorTitle = useMemo(() => {
switch (props.type) {
case 'feed':
return 'You do not have any feed items matching this query.'
case 'newsletter':
return 'You do not have any newsletter item matching this query.'
}
return 'No results found for this query.'
}, [props.type])
return (
<Box
css={{
width: 'fit-content',
borderRadius: '5px',
background: 'rgba(255, 59, 48, 0.3)',
fontSize: '15px',
fontFamily: '$inter',
fontWeight: '500',
color: '$thTextContrast',
padding: '10px',
'@smDown': {
width: '100%',
},
'@xlgDown': {
justifyContent: 'flex-start',
},
}}
>
{errorTitle}
</Box>
)
}
export const SuggestionBox = (props: HelpMessageProps) => {
const helpMessage = useMemo(() => {
switch (props.type) {
case 'feed':
return 'Want to add an RSS or Atom Subscription?'
case 'newsletter':
return 'Create an Omnivore email address and subscribe to newsletters.'
}
return "Add a link or read more about Omnivore's Advanced Search."
}, [props.type])
const helpTarget = useMemo(() => {
switch (props.type) {
case 'feed':
return '/settings/feeds'
case 'newsletter':
return '/settings/emails'
}
return 'https://docs.omnivore.app/'
}, [props.type])
return (
<HStack
css={{
gap: '10px',
width: 'fit-content',
borderRadius: '5px',
background: '$thBackground3',
fontSize: '15px',
fontFamily: '$inter',
fontWeight: '500',
color: '$thTextContrast',
padding: '10px',
justifyContent: 'flex-start',
'@smDown': {
flexDirection: 'column',
alignItems: 'center',
width: '100%',
},
}}
>
{helpMessage}
<SpanBox css={{ cursor: 'pointer' }}>
<Link href={helpTarget} passHref>
<SpanBox
css={{
display: 'flex',
alignItems: 'center',
color: '$omnivoreCtaYellow',
gap: '2px',
'&:hover': {
textDecoration: 'underline',
},
}}
>
<>Click Here</>
<ArrowRightIcon
size={25}
color={theme.colors.omnivoreCtaYellow.toString()}
/>
</SpanBox>
</Link>
</SpanBox>
</HStack>
)
}
export const EmptyLibrary = (props: EmptyLibraryProps) => {
const type = useMemo<MessageType>(() => {
if (props.searchTerm) {
@ -88,35 +195,43 @@ export const EmptyLibrary = (props: EmptyLibraryProps) => {
return 'library'
}, [props])
const helpTitle = useMemo(() => {
switch (type) {
case 'feed':
return 'You do not have any feed items matching this query.'
case 'newsletter':
return 'You do not have any newsletter items.'
}
return 'No results found.'
}, [type])
return (
<VStack
alignment="center"
distribution="center"
<Box
css={{
display: 'inline-flex',
color: '$grayTextContrast',
textAlign: 'center',
paddingTop: '88px',
flex: '1',
gap: '10px',
pl: '0px',
width: '100%',
'@media (max-width: 1300px)': {
flexDirection: 'column',
},
'@media (max-width: 768px)': {
p: '15px',
},
'@media (min-width: 768px)': {
pl: '15px',
width: `calc(100vw - ${LIBRARY_LEFT_MENU_WIDTH})`,
},
'@media (min-width: 930px)': {
pl: '0px',
width: props.layoutType == 'GRID_LAYOUT' ? '660px' : '640px',
},
'@media (min-width: 1280px)': {
pl: '0px',
width: '1000px',
},
'@media (min-width: 1600px)': {
pl: '0px',
width: '1340px',
},
}}
>
<Book size={44} color={theme.colors.grayTextContrast.toString()} />
<StyledText style="fixedHeadline" css={{ color: '$grayTextContrast' }}>
{helpTitle}
</StyledText>
<StyledText style="footnote" css={{ color: '$grayTextContrast' }}>
<HelpMessage type={type} />
</StyledText>
</VStack>
<ErrorBox type={type} />
<SuggestionBox type={type} />
</Box>
)
}

View file

@ -1066,6 +1066,7 @@ function LibraryItemsLayout(props: LibraryItemsLayoutProps): JSX.Element {
>
{!props.isValidating && props.items.length == 0 ? (
<EmptyLibrary
layoutType={props.layout}
searchTerm={props.searchTerm}
onAddLinkClicked={() => {
props.setShowAddLinkModal(true)