diff --git a/packages/web/components/elements/ProgressBar.tsx b/packages/web/components/elements/ProgressBar.tsx
new file mode 100644
index 000000000..c8d15b868
--- /dev/null
+++ b/packages/web/components/elements/ProgressBar.tsx
@@ -0,0 +1,30 @@
+import { Box } from './../elements/LayoutPrimitives'
+
+type ProgressBarProps = {
+ fillPercentage: number
+ fillColor: string
+ backgroundColor: string
+ borderRadius: string
+}
+
+export function ProgressBar(props: ProgressBarProps): JSX.Element {
+ return (
+
+
+
+ )
+}
diff --git a/packages/web/components/patterns/ArticleSubtitle.tsx b/packages/web/components/patterns/ArticleSubtitle.tsx
index 811f028f6..96fe5e15e 100644
--- a/packages/web/components/patterns/ArticleSubtitle.tsx
+++ b/packages/web/components/patterns/ArticleSubtitle.tsx
@@ -51,7 +51,7 @@ function articleSubtitle(url: string, author?: string): string {
}
export function authoredByText(author: string): string {
- return `By ${removeHTMLTags(author)}`
+ return `by ${removeHTMLTags(author)}`
}
function removeHTMLTags(str: string | null | undefined): string {
diff --git a/packages/web/components/patterns/LibraryCards/CardTypes.tsx b/packages/web/components/patterns/LibraryCards/CardTypes.tsx
new file mode 100644
index 000000000..6fd207761
--- /dev/null
+++ b/packages/web/components/patterns/LibraryCards/CardTypes.tsx
@@ -0,0 +1,22 @@
+import { LayoutType } from '../../templates/homeFeed/HomeFeedContainer'
+import { UserBasicData } from '../../../lib/networking/queries/useGetViewerQuery'
+import type { LibraryItemNode } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
+
+export type LinkedItemCardAction =
+ | 'showDetail'
+ | 'showOriginal'
+ | 'archive'
+ | 'unarchive'
+ | 'delete'
+ | 'mark-read'
+ | 'mark-unread'
+ | 'share'
+ | 'snooze'
+
+export type LinkedItemCardProps = {
+ item: LibraryItemNode
+ layout: LayoutType
+ viewer: UserBasicData
+ originText?: string
+ handleAction: (action: LinkedItemCardAction) => void
+}
diff --git a/packages/web/components/patterns/LibraryCards/GridLinkedItemCard.tsx b/packages/web/components/patterns/LibraryCards/GridLinkedItemCard.tsx
new file mode 100644
index 000000000..bb60b4c37
--- /dev/null
+++ b/packages/web/components/patterns/LibraryCards/GridLinkedItemCard.tsx
@@ -0,0 +1,188 @@
+import { Box, VStack, HStack, SpanBox } from '../../elements/LayoutPrimitives'
+import { CoverImage } from '../../elements/CoverImage'
+import { StyledText } from '../../elements/StyledText'
+import { authoredByText } from '../ArticleSubtitle'
+import { MoreOptionsIcon } from '../../elements/images/MoreOptionsIcon'
+import { theme } from '../../tokens/stitches.config'
+import { CardMenu } from '../CardMenu'
+import { LabelChip } from '../../elements/LabelChip'
+import { ProgressBar } from '../../elements/ProgressBar'
+import type { LinkedItemCardProps } from './CardTypes'
+
+export function GridLinkedItemCard(props: LinkedItemCardProps): JSX.Element {
+ return (
+ {
+ props.handleAction('showDetail')
+ }}
+ >
+ div': {
+ borderRadius: '100vmax 100vmax 0 0',
+ },
+ }}
+ >
+
+
+
+
+
+ {
+ // This is here to prevent menu click events from bubbling
+ // up and causing us to "click" on the link item.
+ e.stopPropagation()
+ }}
+ >
+
+ }
+ actionHandler={props.handleAction}
+ />
+
+
+
+
+ {props.item.author && (
+
+ {authoredByText(props.item.author)}
+
+ )}
+
+ {props.originText}
+
+
+
+
+
+
+ {props.item.description}
+
+ {props.item.image && (
+ {
+ ;(e.target as HTMLElement).style.display = 'none'
+ }}
+ />
+ )}
+
+
+ {props.item.labels?.map(({ description, color }, index) => (
+
+ ))}
+
+
+ )
+}
+
+type CardTitleProps = {
+ title: string
+}
+
+function CardTitle(props: CardTitleProps): JSX.Element {
+ return (
+
+ {props.title}
+
+ )
+}
diff --git a/packages/web/components/patterns/LibraryCards/LinkedItemCard.tsx b/packages/web/components/patterns/LibraryCards/LinkedItemCard.tsx
new file mode 100644
index 000000000..12a4a4be7
--- /dev/null
+++ b/packages/web/components/patterns/LibraryCards/LinkedItemCard.tsx
@@ -0,0 +1,23 @@
+import { GridLinkedItemCard } from './GridLinkedItemCard'
+import { ListLinkedItemCard } from './ListLinkedItemCard'
+import type { LinkedItemCardProps } from './CardTypes'
+
+const siteName = (originalArticleUrl: string, itemUrl: string): string => {
+ try {
+ return new URL(originalArticleUrl).hostname
+ } catch {}
+ try {
+ return new URL(itemUrl).hostname
+ } catch {}
+ return ''
+}
+
+export function LinkedItemCard(props: LinkedItemCardProps): JSX.Element {
+ const originText = siteName(props.item.originalArticleUrl, props.item.url)
+
+ if (props.layout == 'LIST_LAYOUT') {
+ return
+ } else {
+ return
+ }
+}
diff --git a/packages/web/components/patterns/LibraryCards/ListLinkedItemCard.tsx b/packages/web/components/patterns/LibraryCards/ListLinkedItemCard.tsx
new file mode 100644
index 000000000..98a4af2f8
--- /dev/null
+++ b/packages/web/components/patterns/LibraryCards/ListLinkedItemCard.tsx
@@ -0,0 +1,213 @@
+import {
+ Box,
+ HStack,
+ VStack,
+ MediumBreakpointBox,
+} from '../../elements/LayoutPrimitives'
+import { StyledText } from '../../elements/StyledText'
+import { authoredByText } from '../ArticleSubtitle'
+import { MoreOptionsIcon } from '../../elements/images/MoreOptionsIcon'
+import { theme } from '../../tokens/stitches.config'
+import { CardMenu } from '../CardMenu'
+import type { LinkedItemCardProps } from './CardTypes'
+import { ProgressBar } from '../../elements/ProgressBar'
+
+export function ListLinkedItemCard(props: LinkedItemCardProps): JSX.Element {
+ return (
+ }
+ largerLayoutNode={}
+ />
+ )
+}
+
+export function ListLinkedItemCardNarrow(
+ props: LinkedItemCardProps
+): JSX.Element {
+ return (
+ {
+ props.handleAction('showDetail')
+ }}
+ >
+
+
+
+ {props.item.title}
+
+
+ {props.item.author && (
+
+ {authoredByText(props.item.author)}
+
+ )}
+
+ {props.originText}
+
+
+
+
+ {
+ // This is here to prevent menu click events from bubbling
+ // up and causing us to "click" on the link item.
+ e.stopPropagation()
+ }}
+ >
+
+ }
+ actionHandler={props.handleAction}
+ />
+
+
+ )
+}
+
+export function ListLinkedItemCardWide(
+ props: LinkedItemCardProps
+): JSX.Element {
+ return (
+ {
+ props.handleAction('showDetail')
+ }}
+ >
+
+
+ {props.item.title}
+
+ {props.item.author && (
+
+ {authoredByText(props.item.author)}
+
+ )}
+
+ {props.originText}
+
+
+
+
+
+ {
+ // This is here to prevent menu click events from bubbling
+ // up and causing us to "click" on the link item.
+ e.stopPropagation()
+ }}
+ >
+
+ }
+ actionHandler={props.handleAction}
+ />
+
+
+ )
+}
diff --git a/packages/web/components/patterns/LinkedItemCard.tsx b/packages/web/components/patterns/LinkedItemCard.tsx
deleted file mode 100644
index 1dc194d36..000000000
--- a/packages/web/components/patterns/LinkedItemCard.tsx
+++ /dev/null
@@ -1,270 +0,0 @@
-import { Box, VStack, HStack, SpanBox } from './../elements/LayoutPrimitives'
-import type { LibraryItemNode } from '../../lib/networking/queries/useGetLibraryItemsQuery'
-import { CoverImage } from './../elements/CoverImage'
-import { StyledText } from './../elements/StyledText'
-import { authoredByText } from './../patterns/ArticleSubtitle'
-import { MoreOptionsIcon } from './../elements/images/MoreOptionsIcon'
-import { theme } from './../tokens/stitches.config'
-import { CardMenu } from './../patterns/CardMenu'
-import { LayoutType } from '../templates/homeFeed/HomeFeedContainer'
-import { UserBasicData } from '../../lib/networking/queries/useGetViewerQuery'
-
-export type LinkedItemCardAction =
- | 'showDetail'
- | 'showOriginal'
- | 'archive'
- | 'unarchive'
- | 'delete'
- | 'mark-read'
- | 'mark-unread'
- | 'share'
- | 'snooze'
-
-type LinkedItemCardProps = {
- item: LibraryItemNode
- layout: LayoutType
- viewer: UserBasicData
- handleAction: (action: LinkedItemCardAction) => void
-}
-
-const siteName = (originalArticleUrl: string, itemUrl: string): string => {
- try {
- return new URL(originalArticleUrl).hostname
- } catch { }
- try {
- return new URL(itemUrl).hostname
- } catch { }
- return ''
-}
-
-export function LinkedItemCard(props: LinkedItemCardProps): JSX.Element {
- if (props.layout == 'LIST_LAYOUT') {
- return
- } else {
- return
- }
-}
-
-export function GridLinkedItemCard(props: LinkedItemCardProps): JSX.Element {
- const originText = siteName(props.item.originalArticleUrl, props.item.url)
-
- return (
- //
- {
- props.handleAction('showDetail')
- }}
- >
-
-
-
- {originText}
-
- {
- // This is here to prevent menu click events from bubbling
- // up and causing us to "click" on the link item.
- e.stopPropagation()
- }}
- >
-
- }
- actionHandler={props.handleAction}
- />
-
-
-
- {props.item.title}
-
-
-
-
- {props.item.author && (
-
- {authoredByText(props.item.author)}
- {props.item.description ? ' \u2013 ' : ''}
-
- )}
- {props.item.description?.substring(0, 300)}
-
- {props.item.image && (
- {
- ;(e.target as HTMLElement).style.display = 'none'
- }}
- />
- )}
-
-
-
- //
- )
-}
-
-export function ListLinkedItemCard(props: LinkedItemCardProps): JSX.Element {
- const originText = siteName(props.item.originalArticleUrl, props.item.url)
-
- return (
- //
- {
- props.handleAction('showDetail')
- }}
- >
-
-
-
- {props.item.title}
-
- {props.item.author && (
-
- {authoredByText(props.item.author)}
-
- )}
-
- {originText}
-
-
- {
- // This is here to prevent menu click events from bubbling
- // up and causing us to "click" on the link item.
- e.stopPropagation()
- }}
- >
-
- }
- actionHandler={props.handleAction}
- />
-
-
-
-
- //
- )
-}
-
-type ProgressBarProps = {
- fillPercentage: number
- fillColor: string
- backgroundColor: string
-}
-
-function ProgressBar(props: ProgressBarProps): JSX.Element {
- return (
-
-
-
- )
-}
diff --git a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx
index fb55e6910..b25ce4480 100644
--- a/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx
+++ b/packages/web/components/templates/homeFeed/HomeFeedContainer.tsx
@@ -1,14 +1,12 @@
import { Box, HStack, VStack } from './../../elements/LayoutPrimitives'
+import { useGetLibraryItemsQuery } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
+import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
import type {
LibraryItem,
LibraryItemsQueryInput,
} from '../../../lib/networking/queries/useGetLibraryItemsQuery'
-import { useGetLibraryItemsQuery } from '../../../lib/networking/queries/useGetLibraryItemsQuery'
-import { useGetViewerQuery } from '../../../lib/networking/queries/useGetViewerQuery'
-import {
- LinkedItemCard,
- LinkedItemCardAction,
-} from '../../patterns/LinkedItemCard'
+import { LinkedItemCardAction } from '../../patterns/LibraryCards/CardTypes'
+import { LinkedItemCard } from '../../patterns/LibraryCards/LinkedItemCard'
import { useRouter } from 'next/router'
import { Button } from '../../elements/Button'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
@@ -115,6 +113,13 @@ export function HomeFeedContainer(props: HomeFeedContainerProps): JSX.Element {
setSize(size + 1)
}, [size, isValidating])
+ useEffect(() => {
+ if (isValidating || !hasMore || size !== 1) {
+ return
+ }
+ setSize(size + 1)
+ }, [size, isValidating])
+
const focusFirstItem = useCallback(() => {
if (libraryItems.length < 1) {
return
@@ -433,6 +438,7 @@ type HomeFeedContentProps = {
function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
const { viewerData } = useGetViewerQuery()
+
const { preferencesData, isValidating: isValidatingPreferences } =
useGetUserPreferences()
const [layout, setLayout] = useState(
@@ -553,19 +559,15 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
gridAutoRows: 'auto',
borderRadius: '8px',
gridGap: layout == 'LIST_LAYOUT' ? '0' : '$3',
- border:
- props.hasData && layout == 'LIST_LAYOUT'
- ? '1px solid $grayBorder'
- : 'none',
marginTop: layout == 'LIST_LAYOUT' ? '21px' : '0',
marginBottom: '0px',
- paddingTop: layout == 'LIST_LAYOUT' ? '2px' : '21px',
+ paddingTop: layout == 'LIST_LAYOUT' ? '0' : '21px',
paddingBottom: layout == 'LIST_LAYOUT' ? '0px' : '21px',
- overflow: 'visible',
+ overflow: 'hidden',
'@smDown': {
border: 'unset',
width: layout == 'LIST_LAYOUT' ? '100vw' : undefined,
- margin: layout == 'LIST_LAYOUT' ? '0 -16px' : undefined,
+ margin: layout == 'LIST_LAYOUT' ? '16px -16px' : undefined,
borderRadius: layout == 'LIST_LAYOUT' ? 0 : undefined,
},
'@md': {
@@ -577,24 +579,6 @@ function HomeFeedGrid(props: HomeFeedContentProps): JSX.Element {
},
}}
>
- {props.hasData && layout === 'LIST_LAYOUT' && (
- // list view gets a title
-
-
- {props.totalItems} links
-
-
- )}
{props.items.map((linkedItem) => (
div': {
bg: '$grayBg',
},
diff --git a/packages/web/components/tokens/stitches.config.ts b/packages/web/components/tokens/stitches.config.ts
index 6e78f741f..7e9500fcf 100644
--- a/packages/web/components/tokens/stitches.config.ts
+++ b/packages/web/components/tokens/stitches.config.ts
@@ -102,7 +102,8 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
borderStyles: {},
shadows: {
panelShadow: '0px 4px 18px rgba(120, 123, 134, 0.12)',
- cardBoxShadow: '0px 0px 9px -2px rgba(32, 31, 29, 0.09), 0px 7px 12px rgba(32, 31, 29, 0.07)'
+ cardBoxShadow:
+ '0px 0px 9px -2px rgba(32, 31, 29, 0.09), 0px 7px 12px rgba(32, 31, 29, 0.07)',
},
zIndices: {},
transitions: {},
@@ -148,7 +149,7 @@ export const { styled, css, theme, getCssText, globalCss, keyframes, config } =
avatarFont: '#0A0806',
labelButtonsBg: '#F5F5F4',
- tooltipIcons: '#FDFAEC'
+ tooltipIcons: '#FDFAEC',
},
},
media: {
@@ -197,8 +198,9 @@ const darkThemeSpec = {
labelButtonsBg: '#5F5E58',
},
shadows: {
- cardBoxShadow: '0px 0px 9px -2px rgba(32, 31, 29, 0.09), 0px 7px 12px rgba(32, 31, 29, 0.07)'
- }
+ cardBoxShadow:
+ '0px 0px 9px -2px rgba(32, 31, 29, 0.09), 0px 7px 12px rgba(32, 31, 29, 0.07)',
+ },
}
// Avatar Fallback color