diff --git a/packages/api/src/jobs/update_home.ts b/packages/api/src/jobs/update_home.ts index ac28ffcac..bf2ccc7ea 100644 --- a/packages/api/src/jobs/update_home.ts +++ b/packages/api/src/jobs/update_home.ts @@ -319,8 +319,8 @@ const appendSectionsToHome = async ( const ttl = 86_400_000 pipeline.zremrangebyscore(key, '-inf', Date.now() - ttl) - // keep only the top MAX_FEED_ITEMS items - pipeline.zremrangebyrank(key, 0, -(MAX_FEED_ITEMS + 1)) + // keep only the new sections and remove the oldest ones + pipeline.zremrangebyrank(key, 0, -(sections.length + 1)) logger.info('Adding home sections to redis') await pipeline.exec() diff --git a/packages/web/components/elements/Pagination.tsx b/packages/web/components/elements/Pagination.tsx new file mode 100644 index 000000000..595f130ec --- /dev/null +++ b/packages/web/components/elements/Pagination.tsx @@ -0,0 +1,48 @@ +import React, { useState } from 'react' +import { Button } from './Button' +import { HStack, VStack } from './LayoutPrimitives' + +type PaginationProps = { + items: T[] + itemsPerPage: number + render: (item: T) => React.ReactNode +} + +const Pagination = ({ + items, + itemsPerPage, + render, +}: PaginationProps) => { + const [currentPage, setCurrentPage] = useState(1) + const maxPage = Math.ceil(items.length / itemsPerPage) + + function createChangePageHandler(page: number) { + return function handlePageChange() { + setCurrentPage(page) + } + } + + const itemsToShow = items.slice( + (currentPage - 1) * itemsPerPage, + currentPage * itemsPerPage + ) + + return ( + + {itemsToShow.map(render)} + + {Array.from({ length: maxPage }, (_, i) => i + 1).map((pageNum) => ( + + ))} + + + ) +} + +export default Pagination diff --git a/packages/web/pages/justread/index.tsx b/packages/web/pages/justread/index.tsx index f62884e89..45c767a38 100644 --- a/packages/web/pages/justread/index.tsx +++ b/packages/web/pages/justread/index.tsx @@ -1,18 +1,17 @@ +import * as HoverCard from '@radix-ui/react-hover-card' import { styled } from '@stitches/react' +import { useRouter } from 'next/router' +import { useMemo } from 'react' +import { Button } from '../../components/elements/Button' import { AddToLibraryActionIcon } from '../../components/elements/icons/home/AddToLibraryActionIcon' import { ArchiveActionIcon } from '../../components/elements/icons/home/ArchiveActionIcon' import { CommentActionIcon } from '../../components/elements/icons/home/CommentActionIcon' import { RemoveActionIcon } from '../../components/elements/icons/home/RemoveActionIcon' import { ShareActionIcon } from '../../components/elements/icons/home/ShareActionIcon' +import Pagination from '../../components/elements/Pagination' +import { timeAgo } from '../../components/patterns/LibraryCards/LibraryCardStyles' +import { theme } from '../../components/tokens/stitches.config' import { useApplyLocalTheme } from '../../lib/hooks/useApplyLocalTheme' -import { - HStack, - SpanBox, - VStack, -} from './../../components/elements/LayoutPrimitives' - -import * as HoverCard from '@radix-ui/react-hover-card' -import { Button } from '../../components/elements/Button' import { HomeItem, HomeItemSource, @@ -20,14 +19,15 @@ import { HomeSection, useGetHomeItems, } from '../../lib/networking/queries/useGetHome' -import { timeAgo } from '../../components/patterns/LibraryCards/LibraryCardStyles' -import { theme } from '../../components/tokens/stitches.config' -import { useRouter } from 'next/router' import { SubscriptionType, useGetSubscriptionsQuery, } from '../../lib/networking/queries/useGetSubscriptionsQuery' -import { useMemo } from 'react' +import { + HStack, + SpanBox, + VStack, +} from './../../components/elements/LayoutPrimitives' export default function Home(): JSX.Element { const homeData = useGetHomeItems() @@ -59,6 +59,12 @@ export default function Home(): JSX.Element { {homeData.sections?.map((homeSection, idx) => { switch (homeSection.layout) { case 'just added': + return ( + + ) case 'long': return ( ) + case 'quick links': + return ( + + ) } })} @@ -77,13 +90,92 @@ type HomeSectionProps = { homeSection: HomeSection } +const JustReadHomeSection = (props: HomeSectionProps): JSX.Element => { + return ( + + + {props.homeSection.title} + + + {props.homeSection.items.map((homeItem) => { + return + })} + + ) +} + const LongHomeSection = (props: HomeSectionProps): JSX.Element => { return ( - - {props.homeSection.items.map((homeItem) => { - return - })} - + + + {props.homeSection.title} + + + ( + + )} + /> + + ) +} + +const QuickLinksHomeSection = (props: HomeSectionProps): JSX.Element => { + return ( + + + {props.homeSection.title} + + + ( + + )} + /> + ) } @@ -130,7 +222,59 @@ const Title = (props: HomeItemViewProps): JSX.Element => { ) } -const HomeItemView = (props: HomeItemViewProps): JSX.Element => { +const JustReadItemView = (props: HomeItemViewProps): JSX.Element => { + const router = useRouter() + + return ( + { + if (event.metaKey || event.ctrlKey) { + window.open(props.homeItem.url, '_blank') + } else { + router.push(props.homeItem.url) + } + }} + > + + + + + + + + </VStack> + <SpanBox css={{ ml: 'auto' }}> + {props.homeItem.thumbnail && ( + <CoverImage + css={{ + mt: '6px', + width: '120px', + height: '70px', + borderRadius: '4px', + }} + src={props.homeItem.thumbnail} + ></CoverImage> + )} + </SpanBox> + </HStack> + </VStack> + ) +} + +const LongHomeItemView = (props: HomeItemViewProps): JSX.Element => { const router = useRouter() return ( @@ -204,6 +348,39 @@ const HomeItemView = (props: HomeItemViewProps): JSX.Element => { ) } +const QuickLinkHomeItemView = (props: HomeItemViewProps): JSX.Element => { + const router = useRouter() + + return ( + <VStack + css={{ + width: '100%', + padding: '10px', + borderRadius: '5px', + '&:hover': { + bg: '$thBackground', + borderRadius: '0px', + }, + }} + onClick={(event) => { + if (event.metaKey || event.ctrlKey) { + window.open(props.homeItem.url, '_blank') + } else { + router.push(props.homeItem.url) + } + }} + > + <TimeAgo homeItem={props.homeItem} /> + <Title homeItem={props.homeItem} /> + <SpanBox + css={{ fontFamily: '$inter', fontSize: '13px', lineHeight: '23px' }} + > + {props.homeItem.previewContent} + </SpanBox> + </VStack> + ) +} + const SiteIconSmall = styled('img', { width: '16px', height: '16px',