enhance search view & close #41

This commit is contained in:
amirhouieh 2023-05-14 12:37:28 +02:00 committed by Jinho Jang
parent 1f41575d98
commit bc2da5ebac
6 changed files with 92 additions and 52 deletions

View File

@ -10,6 +10,7 @@ type Props = {
posts: PostDataProps[] posts: PostDataProps[]
pageSize?: number pageSize?: number
layout?: PostListLayout layout?: PostListLayout
loading?: boolean
} }
const getGridItemWidth = (index: number) => { const getGridItemWidth = (index: number) => {
@ -56,7 +57,7 @@ export const PostsList = (props: Props) => {
key={index} key={index}
> >
<PostLink href={`/article/${post.slug}`}> <PostLink href={`/article/${post.slug}`}>
<PostWrapper> <PostWrapper className={props.loading ? 'loading' : ''}>
<Post data={post} /> <Post data={post} />
</PostWrapper> </PostWrapper>
</PostLink> </PostLink>
@ -82,6 +83,12 @@ const PostWrapper = styled.div`
padding: 16px 0; padding: 16px 0;
border-top: 1px solid rgb(var(--lsd-theme-primary)); border-top: 1px solid rgb(var(--lsd-theme-primary));
width: 100%; width: 100%;
transition: opacity 0.3s ease-in-out;
&.loading {
opacity: 0.5;
}
` `
const PostLink = styled(Link)` const PostLink = styled(Link)`

View File

@ -1,10 +1,9 @@
import { getArticleCover } from '@/utils/data.utils' import { getArticleCover } from '@/utils/data.utils'
import { Typography } from '@acid-info/lsd-react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { PostsList } from '../PostList/PostList' import { PostsList } from '../PostList/PostList'
import { Section } from '../Section/Section' import { SearchHook } from '@/types/data.types'
import { SearchHook, SearchResultItem } from '@/types/data.types'
import { UnbodyGoogleDoc } from '@/lib/unbody/unbody.types' import { UnbodyGoogleDoc } from '@/lib/unbody/unbody.types'
import { SearchResultsSection } from '@/components/SearchResultsSection/SearchResultsSection'
type Props = { type Props = {
data: SearchHook<UnbodyGoogleDoc> data: SearchHook<UnbodyGoogleDoc>
@ -12,32 +11,29 @@ type Props = {
export default function RelatedArticles({ data }: Props) { export default function RelatedArticles({ data }: Props) {
if (!data.loading && !data.data) return null if (!data.loading && !data.data) return null
return ( return (
<Container> <Container>
<Section <SearchResultsSection
title={data.loading ? 'Loading...' : 'Related Articles'} resultSize={data.data.length}
matches={data.loading ? undefined : data.data.length} loading={data.loading}
title={'Related Articles'}
> >
{ {
<PostsList <PostsList
posts={ posts={data.data.map((article) => ({
data.loading slug: article.doc.slug,
? [] date: article.doc.modifiedAt,
: data.data.map((article) => ({ title: article.doc.title,
slug: article.doc.slug, description: article.doc.subtitle, // TODO: summary is not available
date: article.doc.modifiedAt, mentions: article.doc.mentions,
title: article.doc.title, tags: article.doc.tags,
description: article.doc.subtitle, // TODO: summary is not available coverImage: getArticleCover(article.doc.blocks),
mentions: article.doc.mentions, }))}
tags: article.doc.tags,
coverImage: getArticleCover(article.doc.blocks),
}))
}
pageSize={4} pageSize={4}
loading={data.loading}
/> />
} }
</Section> </SearchResultsSection>
</Container> </Container>
) )
} }

View File

@ -1,21 +1,24 @@
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { Section } from '../Section/Section' import { SearchHook, SearchResultItem } from '@/types/data.types'
import { SearchResultItem } from '@/types/data.types'
import { UnbodyImageBlock, UnbodyTextBlock } from '@/lib/unbody/unbody.types' import { UnbodyImageBlock, UnbodyTextBlock } from '@/lib/unbody/unbody.types'
import { Grid } from '../Grid/Grid' import { Grid } from '../Grid/Grid'
import { ImageBlock, TextBlock } from '../ContentBlock' import { ImageBlock, TextBlock } from '../ContentBlock'
import { UnbodyGraphQl } from '@/lib/unbody/unbody-content.types' import { UnbodyGraphQl } from '@/lib/unbody/unbody-content.types'
import { SearchResultsSection } from '@/components/SearchResultsSection/SearchResultsSection'
type Props = { type Props = {
blocks: SearchResultItem<UnbodyImageBlock | UnbodyTextBlock>[] data: SearchHook<UnbodyTextBlock | UnbodyImageBlock>
} }
export default function RelatedContent({ data }: Props) {
export default function RelatedContent({ blocks }: Props) {
return ( return (
<Container> <Container>
<Section title={'Related Content'} matches={blocks?.length}> <SearchResultsSection
resultSize={data.data.length}
loading={data.loading}
title={'Related Content'}
>
<Grid> <Grid>
{blocks.map( {data.data.map(
(block: SearchResultItem<UnbodyImageBlock | UnbodyTextBlock>) => { (block: SearchResultItem<UnbodyImageBlock | UnbodyTextBlock>) => {
if (!block.doc.document || !block.doc.document[0]) return null if (!block.doc.document || !block.doc.document[0]) return null
@ -23,7 +26,6 @@ export default function RelatedContent({ blocks }: Props) {
if (UnbodyGraphQl.UnbodyDocumentTypeNames.GoogleDoc) { if (UnbodyGraphQl.UnbodyDocumentTypeNames.GoogleDoc) {
refArticle = block.doc.document[0] refArticle = block.doc.document[0]
} }
switch (block.doc.__typename) { switch (block.doc.__typename) {
case UnbodyGraphQl.UnbodyDocumentTypeNames.TextBlock: case UnbodyGraphQl.UnbodyDocumentTypeNames.TextBlock:
return <TextBlock doc={block.doc} /> return <TextBlock doc={block.doc} />
@ -34,7 +36,7 @@ export default function RelatedContent({ blocks }: Props) {
}, },
)} )}
</Grid> </Grid>
</Section> </SearchResultsSection>
</Container> </Container>
) )
} }

View File

@ -0,0 +1,35 @@
import { Section } from '@/components/Section/Section'
import React, { PropsWithChildren } from 'react'
import { Typography } from '@acid-info/lsd-react'
type Props = PropsWithChildren<{
resultSize: number
loading: boolean
title: string
}>
export const SearchResultsSection = ({
resultSize,
loading,
title,
children,
}: Props) => (
<Section
title={title}
subtitle={
loading ? (
<Typography genericFontFamily="sans-serif" variant="body2">
Loading...
</Typography>
) : (
<>
<Typography genericFontFamily="sans-serif" variant="body2">
{resultSize} matches
</Typography>
</>
)
}
>
{children}
</Section>
)

View File

@ -1,25 +1,29 @@
import { Typography } from '@acid-info/lsd-react' import { Typography } from '@acid-info/lsd-react'
import styled from '@emotion/styled' import styled from '@emotion/styled'
import { PropsWithChildren } from 'react' import React, { PropsWithChildren } from 'react'
type Props = PropsWithChildren<{ type Props = PropsWithChildren<{
title: string title: string
matches?: number | string subtitle?: string | React.ReactNode
}> }>
export const Section = ({ title, matches, children, ...props }: Props) => { export const Section = ({ title, subtitle, children, ...props }: Props) => {
return ( return (
<section style={{ width: '100%' }} {...props}> <section style={{ width: '100%' }} {...props}>
<Container> <Container>
<Typography genericFontFamily="sans-serif" variant="body2"> <Typography genericFontFamily="sans-serif" variant="body2">
{title} {title}
</Typography> </Typography>
{matches && ( {subtitle && (
<> <>
<Typography variant="body2"></Typography> <Typography variant="body2"></Typography>
<Typography genericFontFamily="sans-serif" variant="body2"> {typeof subtitle === 'string' ? (
{matches} matches <Typography genericFontFamily="sans-serif" variant="body2">
</Typography> subtitle
</Typography>
) : (
subtitle
)}
</> </>
)} )}
</Container> </Container>

View File

@ -54,26 +54,22 @@ export default function SearchPage({
useEffect(() => { useEffect(() => {
if (mounted) { if (mounted) {
if (query.length > 0 || topics.length > 0) { const serchArgs = [
const serchArgs = [ extractQueryFromQuery(router.query),
extractQueryFromQuery(router.query), extractTopicsFromQuery(router.query),
extractTopicsFromQuery(router.query), ]
] articles.search(...(serchArgs as [string, string[]]))
articles.search(...(serchArgs as [string, string[]])) blocks.search(...(serchArgs as [string, string[]]))
blocks.search(...(serchArgs as [string, string[]]))
} else {
articles.reset(initialArticles)
blocks.reset(initialBlocks)
}
} else { } else {
hasUpdated.current = true articles.reset(initialArticles)
blocks.reset(initialBlocks)
} }
}, [mounted, router.query]) }, [mounted, router.query])
return ( return (
<div> <div style={{ minHeight: '80vh' }}>
<RelatedArticles data={articles} /> <RelatedArticles data={articles} />
{blocks.data?.length && <RelatedContent blocks={blocks.data} />} <RelatedContent data={blocks} />
</div> </div>
) )
} }