Merge pull request #4055 from omnivore-app/feat/recently-added

This commit is contained in:
Jackson Harper 2024-06-12 22:11:59 +08:00 committed by GitHub
commit 833a83f235
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 177 additions and 50 deletions

View file

@ -628,7 +628,7 @@ export const functionResolvers = {
switch (section.layout) {
case 'just_added':
return 'Just Added'
return 'Recently Added'
case 'top_picks':
return 'Top Picks'
case 'quick_links':

View file

@ -436,7 +436,7 @@ export const Button = styled('button', {
cursor: 'pointer',
p: '5px',
borderRadius: '5px',
'&:hover': { bg: '$readerHoverBg', opacity: '1' },
'&:hover': { bg: '$homeActionHoverBg', opacity: '1' },
},
menuAction: {
display: 'flex',

View file

@ -26,11 +26,18 @@ import {
} from '../../lib/networking/queries/useGetSubscriptionsQuery'
import { Box, HStack, SpanBox, VStack } from '../elements/LayoutPrimitives'
import { Toaster } from 'react-hot-toast'
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
export function HomeContainer(): JSX.Element {
const homeData = useGetHomeItems()
const { viewerData } = useGetViewerQuery()
useApplyLocalTheme()
const viewerUsername = useMemo(() => {
return viewerData?.me?.profile.username
}, [viewerData])
return (
<VStack
distribution="start"
@ -47,7 +54,7 @@ export function HomeContainer(): JSX.Element {
distribution="start"
css={{
width: '646px',
gap: '40px',
gap: '50px',
minHeight: '100vh',
'@mdDown': {
width: '100%',
@ -64,6 +71,7 @@ export function HomeContainer(): JSX.Element {
<JustAddedHomeSection
key={`section-${idx}`}
homeSection={homeSection}
viewerUsername={viewerUsername}
/>
)
case 'top_picks':
@ -71,6 +79,7 @@ export function HomeContainer(): JSX.Element {
<TopPicksHomeSection
key={`section-${idx}`}
homeSection={homeSection}
viewerUsername={viewerUsername}
/>
)
case 'quick_links':
@ -78,6 +87,7 @@ export function HomeContainer(): JSX.Element {
<QuickLinksHomeSection
key={`section-${idx}`}
homeSection={homeSection}
viewerUsername={viewerUsername}
/>
)
case 'hidden':
@ -85,6 +95,7 @@ export function HomeContainer(): JSX.Element {
<HiddenHomeSection
key={`section-${idx}`}
homeSection={homeSection}
viewerUsername={viewerUsername}
/>
)
default:
@ -98,9 +109,11 @@ export function HomeContainer(): JSX.Element {
type HomeSectionProps = {
homeSection: HomeSection
viewerUsername: string | undefined
}
const JustAddedHomeSection = (props: HomeSectionProps): JSX.Element => {
const router = useRouter()
return (
<VStack
distribution="start"
@ -109,19 +122,64 @@ const JustAddedHomeSection = (props: HomeSectionProps): JSX.Element => {
gap: '20px',
}}
>
<SpanBox
css={{
fontFamily: '$inter',
fontSize: '16px',
fontWeight: '600',
color: '$homeTextTitle',
}}
<HStack
css={{ width: '100%', lineHeight: '1' }}
distribution="start"
alignment="start"
>
{props.homeSection.title}
</SpanBox>
{props.homeSection.items.map((homeItem) => {
return <JustAddedItemView key={homeItem.id} homeItem={homeItem} />
})}
<SpanBox
css={{
fontFamily: '$inter',
fontSize: '16px',
fontWeight: '600',
color: '$homeTextTitle',
}}
>
{props.homeSection.title}
</SpanBox>
<SpanBox
css={{
ml: 'auto',
fontFamily: '$inter',
fontSize: '13px',
fontWeight: '400',
color: '$homeTextTitle',
}}
>
<Button
style="link"
onClick={(event) => {
router.push('/l/library')
event.preventDefault()
}}
css={{
'&:hover': {
textDecoration: 'underline',
},
}}
>
View All
</Button>
</SpanBox>
</HStack>
<HStack
css={{
width: '100%',
lineHeight: '1',
overflow: 'scroll',
gap: '25px',
scrollbarWidth: 'none',
'::-webkit-scrollbar': {
display: 'none',
},
}}
distribution="start"
alignment="start"
>
{props.homeSection.items.map((homeItem) => {
return <JustAddedItemView key={homeItem.id} homeItem={homeItem} />
})}
</HStack>
</VStack>
)
}
@ -165,7 +223,7 @@ const QuickLinksHomeSection = (props: HomeSectionProps): JSX.Element => {
css={{
width: '100%',
gap: '20px',
bg: '#3D3D3D',
bg: '$thNavMenuFooter',
py: '30px',
px: '20px',
borderRadius: '5px',
@ -279,6 +337,7 @@ const CoverImage = styled('img', {
type HomeItemViewProps = {
homeItem: HomeItem
viewerUsername?: string | undefined
}
const TimeAgo = (props: HomeItemViewProps): JSX.Element => {
@ -301,6 +360,7 @@ const TimeAgo = (props: HomeItemViewProps): JSX.Element => {
const Title = (props: HomeItemViewProps): JSX.Element => {
return (
<HStack
className="title-text"
distribution="start"
alignment="center"
css={{
@ -315,6 +375,34 @@ const Title = (props: HomeItemViewProps): JSX.Element => {
display: '-webkit-box',
'-webkit-line-clamp': '3',
'-webkit-box-orient': 'vertical',
'&:title-text': {
transition: 'text-decoration 0.3s ease',
},
}}
>
{props.homeItem.title}
</HStack>
)
}
const TitleSmall = (props: HomeItemViewProps): JSX.Element => {
return (
<HStack
className="title-text"
distribution="start"
alignment="center"
css={{
fontSize: '13px',
lineHeight: '26px',
fontWeight: '500',
fontFamily: '$inter',
color: '$homeTextTitle',
overflow: 'hidden',
textOverflow: 'ellipsis',
wordBreak: 'break-word',
display: '-webkit-box',
'-webkit-line-clamp': '3',
'-webkit-box-orient': 'vertical',
}}
>
{props.homeItem.title}
@ -353,31 +441,41 @@ const JustAddedItemView = (props: HomeItemViewProps): JSX.Element => {
return (
<VStack
css={{
width: '100%',
padding: '5px',
minWidth: '377px',
gap: '5px',
padding: '12px',
cursor: 'pointer',
bg: '$homeCardHover',
borderRadius: '5px',
'&:hover': {
bg: '$homeCardHover',
borderRadius: '0px',
},
'&:hover .title-text': {
textDecoration: 'underline',
},
}}
onClick={(event) => {
const path = `/${props.viewerUsername ?? 'me'}/${props.homeItem.slug}`
if (event.metaKey || event.ctrlKey) {
window.open(props.homeItem.url, '_blank')
window.open(path, '_blank')
} else {
router.push(props.homeItem.url)
router.push(path)
}
}}
>
<HStack
distribution="start"
alignment="center"
css={{ gap: '5px', lineHeight: '1' }}
css={{ width: '100%', gap: '5px', lineHeight: '1' }}
>
<SourceInfo homeItem={props.homeItem} />
<TimeAgo homeItem={props.homeItem} />
<SourceInfo homeItem={props.homeItem} subtle={true} />
<SpanBox css={{ ml: 'auto' }}>
<TimeAgo homeItem={props.homeItem} />
</SpanBox>
</HStack>
<Title homeItem={props.homeItem} />
<TitleSmall homeItem={props.homeItem} />
</VStack>
)
}
@ -391,18 +489,22 @@ const TopicPickHomeItemView = (props: HomeItemViewProps): JSX.Element => {
width: '100%',
p: '0px',
pt: '35px',
cursor: 'pointer',
borderRadius: '5px',
'&:hover': {
bg: '$homeCardHover',
borderRadius: '0px',
},
'&:hover .title-text': {
textDecoration: 'underline',
},
}}
onClick={(event) => {
const path = `/${props.viewerUsername ?? 'me'}/${props.homeItem.slug}`
if (event.metaKey || event.ctrlKey) {
window.open(props.homeItem.url, '_blank')
window.open(path, '_blank')
} else {
router.push(props.homeItem.url)
router.push(path)
}
}}
alignment="start"
@ -482,10 +584,11 @@ const QuickLinkHomeItemView = (props: HomeItemViewProps): JSX.Element => {
},
}}
onClick={(event) => {
const path = `/${props.viewerUsername ?? 'me'}/${props.homeItem.slug}`
if (event.metaKey || event.ctrlKey) {
window.open(props.homeItem.url, '_blank')
window.open(path, '_blank')
} else {
router.push(props.homeItem.url)
router.push(path)
}
}}
>
@ -511,13 +614,17 @@ const SiteIconLarge = styled('img', {
borderRadius: '100px',
})
const SourceInfo = (props: HomeItemViewProps) => (
type SourceInfoProps = {
subtle?: boolean
}
const SourceInfo = (props: HomeItemViewProps & SourceInfoProps) => (
<HoverCard.Root>
<HoverCard.Trigger asChild>
<HStack
distribution="start"
alignment="center"
css={{ gap: '5px', cursor: 'pointer' }}
css={{ gap: '8px', cursor: 'pointer' }}
>
{props.homeItem.source.icon && (
<SiteIconSmall
@ -528,11 +635,10 @@ const SourceInfo = (props: HomeItemViewProps) => (
<HStack
css={{
lineHeight: '1',
pb: '3px',
fontFamily: '$inter',
fontWeight: '500',
fontSize: '13px',
color: '$homeTextSource',
fontSize: props.subtle ? '12px' : '13px',
color: props.subtle ? '$homeTextSubtle' : '$homeTextSource',
textDecoration: 'underline',
}}
>

View file

@ -1,10 +1,10 @@
import { PageMetaData, PageMetaDataProps } from '../patterns/PageMetaData'
import { Box, HStack, VStack } from '../elements/LayoutPrimitives'
import { HStack, SpanBox, VStack } from '../elements/LayoutPrimitives'
import { ReactNode, useEffect, useState, useCallback } from 'react'
import { useGetViewerQuery } from '../../lib/networking/queries/useGetViewerQuery'
import { navigationCommands } from '../../lib/keyboardShortcuts/navigationShortcuts'
import { useKeyboardShortcuts } from '../../lib/keyboardShortcuts/useKeyboardShortcuts'
import { NextRouter, useRouter } from 'next/router'
import { useRouter } from 'next/router'
import { ConfirmationModal } from '../patterns/ConfirmationModal'
import { KeyboardShortcutListModal } from './KeyboardShortcutListModal'
import { setupAnalytics } from '../../lib/analytics'
@ -19,8 +19,6 @@ import { DEFAULT_HEADER_HEIGHT } from './homeFeed/HeaderSpacer'
import { Button } from '../elements/Button'
import { List } from '@phosphor-icons/react'
import { usePersistedState } from '../../lib/hooks/usePersistedState'
import 'allotment/dist/style.css'
import { LibrarySideBar } from './library/LibrarySideBar'
export type NavigationSection =
| 'home'
@ -122,11 +120,19 @@ export function NavigationLayout(props: NavigationLayoutProps): JSX.Element {
{props.pageMetaDataProps ? (
<PageMetaData {...props.pageMetaDataProps} />
) : null}
<Header
toggleMenu={() => {
setShowNavMenu(!showNavMenu)
<SpanBox
css={{
'@lgDown': {
display: 'none',
},
}}
/>
>
<Header
toggleMenu={() => {
setShowNavMenu(!showNavMenu)
}}
/>
</SpanBox>
{showNavMenu && (
<NavigationMenu
section={props.section}

View file

@ -926,6 +926,9 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
px: '20px',
py: '20px',
width: '100%',
'@mdDown': {
px: '0px',
},
}}
distribution="start"
alignment="start"
@ -1189,6 +1192,10 @@ function LibraryItems(props: LibraryItemsProps): JSX.Element {
'@lgDown': {
px: '10px',
},
'@mdDown': {
px: '0px',
gap: '0px',
},
gridTemplateColumns:
props.layout == 'LIST_LAYOUT'
? 'none'

View file

@ -133,7 +133,7 @@ const HeaderControls = (props: LibraryHeaderProps): JSX.Element => {
<SpanBox
css={{
display: 'none',
'@mdDown': { display: 'flex' },
'@lgDown': { display: 'flex' },
}}
>
<MenuHeaderButton {...props} />

View file

@ -39,6 +39,7 @@ import { NavMoreButtonUpIcon } from '../../elements/icons/NavMoreButtonUp'
import { ShortcutFolderClosed } from '../../elements/icons/ShortcutFolderClosed'
import { TrashSectionIcon } from '../../elements/icons/TrashSectionIcon'
import { ShortcutFolderOpen } from '../../elements/icons/ShortcutFolderOpen'
import useResizeObserver from 'use-resize-observer'
export const LIBRARY_LEFT_MENU_WIDTH = '275px'
@ -356,6 +357,8 @@ const Shortcuts = (props: NavigationMenuProps): JSX.Element => {
</HStack>
<Box
css={{
width: '100%',
height: '100%',
'[role="treeitem"]': {
outline: 'none',
},
@ -456,6 +459,7 @@ const cachedShortcutsData = (): Shortcut[] | undefined => {
const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
const router = useRouter()
const { ref, width, height } = useResizeObserver()
const { isValidating, data } = useSWR('/api/shortcuts', getShortcuts, {
fallbackData: cachedShortcutsData(),
@ -562,7 +566,7 @@ const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
)
return (
<>
<div ref={ref}>
{!isValidating && (
<Tree
ref={props.treeRef}
@ -575,12 +579,13 @@ const ShortcutsTree = (props: ShortcutsTreeProps): JSX.Element => {
onActivate={onActivate}
rowHeight={36}
initialOpenState={folderOpenState}
width={275}
width={width}
height={640}
>
{NodeRenderer}
</Tree>
)}
</>
</div>
)
}

View file

@ -157,7 +157,6 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
readerTableHeader: '#FFFFFF',
readerMargin: 'white',
readerTextSubtle: '#898989',
readerHoverBg: '#1E1E1E',
// Avatar Fallback color
avatarBg: '#FFEA9F',
@ -236,6 +235,7 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
homeTextBody: '#3D3D3D',
homeTextSubtle: '#898989',
homeActionIcons: '#898989',
homeActionHoverBg: '#DFDFDF',
homeDivider: '#D9D9D9',
thLibraryAISummaryBorder: '#6A6968',
@ -306,7 +306,6 @@ const darkThemeSpec = {
readerFontHighContrast: 'white',
readerTableHeader: '#FFFFFF',
readerMargin: '#2A2A2A',
readerHoverBg: '#1E1E1E',
readerTextSubtle: '#EDEDED',
avatarBg: '#7B5C3E',
@ -390,6 +389,7 @@ const darkThemeSpec = {
homeTextBody: '#D9D9D9',
homeTextSubtle: '#898989',
homeActionIcons: '#898989',
homeActionHoverBg: '#515151',
homeDivider: '#3D3D3D',
thLibraryAISummaryBorder: '#6A6968',
@ -427,6 +427,7 @@ const apolloThemeSpec = {
homeCardHover: '#525252',
homeDivider: '#6A6968',
homeActionHoverBg: '#515151',
thBackground: '#474747',
thBackground2: '#515151',
@ -456,6 +457,7 @@ const sepiaThemeSpec = {
homeCardHover: '#EEE8D5',
homeDivider: '#DDD6C1',
homeActionHoverBg: '#DDD6C1',
thLibraryMultiselectHover: '#EEE8D5',
},

View file

@ -67,6 +67,7 @@
"remark-gfm": "^3.0.1",
"sharp": "^0.32.6",
"swr": "^2.2.5",
"use-resize-observer": "^9.1.0",
"uuid": "^8.3.2",
"yet-another-react-lightbox": "^3.12.0"
},
@ -108,4 +109,4 @@
"volta": {
"extends": "../../package.json"
}
}
}

View file

@ -31183,7 +31183,7 @@ use-latest@^1.0.0:
dependencies:
use-isomorphic-layout-effect "^1.0.0"
use-resize-observer@^9.0.0:
use-resize-observer@^9.0.0, use-resize-observer@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/use-resize-observer/-/use-resize-observer-9.1.0.tgz#14735235cf3268569c1ea468f8a90c5789fc5c6c"
integrity sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==