Files
omnivore/packages/web/components/templates/ArticleHighlights.tsx
2022-03-24 12:52:02 -07:00

218 lines
6.3 KiB
TypeScript

import { useRouter } from 'next/router'
import { PublicArticleAttributes } from '../../lib/networking/queries/useGetPublicArticleQuery'
import { PrimaryLayout } from './PrimaryLayout'
import { StyledText } from '../elements/StyledText'
import { VStack, HStack, Box } from '../elements/LayoutPrimitives'
import { authoredByText } from '../patterns/ArticleSubtitle'
import Image from 'next/image'
import { HighlightFooter, PublicHighlightView } from '../patterns/HighlightView'
import { useMemo, useRef, useState } from 'react'
import { Highlight } from '../../lib/networking/fragments/highlightFragment'
import { Button } from '../elements/Button'
type ArticleHighlightsProps = {
publicArticle: PublicArticleAttributes
showAllHighlights: boolean
selectedHighlightId?: string
previewImagePath?: string
}
export function ArticleHighlights(props: ArticleHighlightsProps): JSX.Element {
const router = useRouter()
return (
<PrimaryLayout
pageMetaDataProps={{
title: props.publicArticle.title,
description: props.publicArticle.description,
path: router.pathname,
ogImage: props.previewImagePath,
ogImageType: 'image/png',
}}
pageTestId={router.pathname}
>
<VStack alignment="center" css={{ width: '100%' }}>
<LoadedContent
publicArticle={props.publicArticle}
showAllHighlights={props.showAllHighlights}
selectedHighlightId={props.selectedHighlightId}
/>
</VStack>
</PrimaryLayout>
)
}
type LoadedContentProps = {
publicArticle: PublicArticleAttributes
showAllHighlights: boolean
selectedHighlightId?: string
}
function LoadedContent(props: LoadedContentProps): JSX.Element {
const router = useRouter()
const container = useRef<HTMLDivElement>(null)
const [showAllHighlights, setShowAllHighlights] = useState(
props.showAllHighlights
)
const selectedHighlights =
props.publicArticle.highlights.filter((highlight) => {
return highlight.shortId === props.selectedHighlightId
}) ?? ([] as Highlight[])
const unselectedHighlights =
props.publicArticle.highlights.filter((highlight) => {
return highlight.shortId !== props.selectedHighlightId
}) ?? ([] as Highlight[])
const moreHighlightsCount = useMemo(() => {
return props.publicArticle.highlights.length - 1
}, [props.publicArticle.highlights])
// const sharedBy = useMemo(() => {
// if (moreHighlightsCount < 1) return undefined
// return props.publicArticle.highlights[0].user
// }, [moreHighlightsCount, props.publicArticle.highlights])
const articleSite = useMemo(() => {
try {
const url = new URL(props.publicArticle.url)
return url.hostname
} catch (e) {
console.log('error ', e)
return ''
}
}, [props.publicArticle.url])
return (
<VStack
alignment="center"
css={{
p: props.selectedHighlightId ? '66px $3 0px $3' : '0px $3 0px $3',
width: '66%',
maxWidth: '600px',
mb: '$4',
'@smDown': {
p: '32px $3 0px $3',
width: '100%',
},
aspectRatio: router.query.adjustAspectRatio as string,
}}
ref={container}
>
{!props.selectedHighlightId && (
<LinkedItem publicArticle={props.publicArticle} />
)}
{selectedHighlights.map((highlight) => (
<PublicHighlightView
key={highlight.id}
highlight={highlight}
title={props.publicArticle.title}
author={props.publicArticle.author}
/>
))}
{showAllHighlights &&
unselectedHighlights.map((highlight) => (
<PublicHighlightView key={highlight.id} highlight={highlight} />
))}
<HighlightFooter
title={props.publicArticle.title}
author={props.publicArticle.author}
site={articleSite}
/>
{!showAllHighlights && moreHighlightsCount > 0 && (
<Button onClick={() => setShowAllHighlights(true)}>
<Box
css={{ width: '8px', color: '$grayBackground', mr: '4px' }}
className="dropdown-arrow"
/>
Read {moreHighlightsCount} more highlight
{moreHighlightsCount > 1 ? 's ' : ' '}
{/* from {sharedBy.name} */}
</Button>
)}
<Button
style="ctaDarkYellow"
css={{ m: '44px', p: '14px 16px', alignSelf: 'center' }}
onClick={() => {
if (window !== undefined) {
window.open(props.publicArticle.url, '_blank')
}
}}
>
Read Original
</Button>
</VStack>
)
}
type LinkedItemProps = {
publicArticle: PublicArticleAttributes
}
function LinkedItem(props: LinkedItemProps): JSX.Element {
const originText = new URL(props.publicArticle.url).hostname
return (
<VStack
alignment="start"
css={{
bg: '$grayBgActive',
borderRadius: '$2',
p: '$2',
width: '100%',
}}
>
<HStack distribution="start" css={{ width: '100%' }}>
<HStack distribution="start" alignment="start">
<Box>
<Image
src={
'/static/images/linked-item-card-placeholder.png'
// props.image ?? '/static/images/linked-item-card-placeholder.png'
}
alt="Link Preview Image"
layout="fixed"
width={88}
height={88}
/>
</Box>
<VStack
distribution="start"
alignment="start"
css={{ px: '$2', flexGrow: 1 }}
>
<StyledText
style="caption"
css={{ my: '$1', textAlign: 'left', overflow: 'auto' }}
>
{props.publicArticle.title}
</StyledText>
{props.publicArticle.author && (
<StyledText style="caption" css={{ my: '$1' }}>
{authoredByText(props.publicArticle.author)}
</StyledText>
)}
<StyledText style="caption" css={{ my: '$1' }}>
{originText}
</StyledText>
</VStack>
</HStack>
</HStack>
<StyledText
style="caption"
css={{ m: 0, py: '$2', height: '5em', overflow: 'hidden' }}
>
{props.publicArticle.description}
</StyledText>
</VStack>
)
}