a tool for shared writing and social publishing

adding tabs to Reader

+12 -116
-100
app/(home-pages)/reader/ReaderContent.tsx
··· 1 - "use client"; 2 - import { ButtonPrimary } from "components/Buttons"; 3 - import { DiscoverSmall } from "components/Icons/DiscoverSmall"; 4 - import type { Cursor, Post } from "./getReaderFeed"; 5 - import useSWRInfinite from "swr/infinite"; 6 - import { getReaderFeed } from "./getReaderFeed"; 7 - import { useEffect, useRef } from "react"; 8 - import Link from "next/link"; 9 - import { PostListing } from "components/PostListing"; 10 - 11 - export const ReaderContent = (props: { 12 - posts: Post[]; 13 - nextCursor: Cursor | null; 14 - }) => { 15 - const getKey = ( 16 - pageIndex: number, 17 - previousPageData: { 18 - posts: Post[]; 19 - nextCursor: Cursor | null; 20 - } | null, 21 - ) => { 22 - // Reached the end 23 - if (previousPageData && !previousPageData.nextCursor) return null; 24 - 25 - // First page, we don't have previousPageData 26 - if (pageIndex === 0) return ["reader-feed", null] as const; 27 - 28 - // Add the cursor to the key 29 - return ["reader-feed", previousPageData?.nextCursor] as const; 30 - }; 31 - 32 - const { data, size, setSize, isValidating } = useSWRInfinite( 33 - getKey, 34 - ([_, cursor]) => getReaderFeed(cursor), 35 - { 36 - fallbackData: [{ posts: props.posts, nextCursor: props.nextCursor }], 37 - revalidateFirstPage: false, 38 - }, 39 - ); 40 - 41 - const loadMoreRef = useRef<HTMLDivElement>(null); 42 - 43 - // Set up intersection observer to load more when trigger element is visible 44 - useEffect(() => { 45 - const observer = new IntersectionObserver( 46 - (entries) => { 47 - if (entries[0].isIntersecting && !isValidating) { 48 - const hasMore = data && data[data.length - 1]?.nextCursor; 49 - if (hasMore) { 50 - setSize(size + 1); 51 - } 52 - } 53 - }, 54 - { threshold: 0.1 }, 55 - ); 56 - 57 - if (loadMoreRef.current) { 58 - observer.observe(loadMoreRef.current); 59 - } 60 - 61 - return () => observer.disconnect(); 62 - }, [data, size, setSize, isValidating]); 63 - 64 - const allPosts = data ? data.flatMap((page) => page.posts) : []; 65 - 66 - if (allPosts.length === 0 && !isValidating) return <ReaderEmpty />; 67 - 68 - return ( 69 - <div className="flex flex-col gap-3 relative"> 70 - {allPosts.map((p) => ( 71 - <PostListing {...p} key={p.documents.uri} /> 72 - ))} 73 - {/* Trigger element for loading more posts */} 74 - <div 75 - ref={loadMoreRef} 76 - className="absolute bottom-96 left-0 w-full h-px pointer-events-none" 77 - aria-hidden="true" 78 - /> 79 - {isValidating && ( 80 - <div className="text-center text-tertiary py-4"> 81 - Loading more posts... 82 - </div> 83 - )} 84 - </div> 85 - ); 86 - }; 87 - 88 - export const ReaderEmpty = () => { 89 - return ( 90 - <div className="flex flex-col gap-2 container bg-[rgba(var(--bg-page),.7)] sm:p-4 p-3 justify-between text-center text-tertiary"> 91 - Nothing to read yet… <br /> 92 - Subscribe to publications and find their posts here! 93 - <Link href={"/discover"}> 94 - <ButtonPrimary className="mx-auto place-self-center"> 95 - <DiscoverSmall /> Discover Publications 96 - </ButtonPrimary> 97 - </Link> 98 - </div> 99 - ); 100 - };
+12 -16
app/(home-pages)/reader/page.tsx
··· 1 - import { getIdentityData } from "actions/getIdentityData"; 2 - 3 1 import { DashboardLayout } from "components/PageLayouts/DashboardLayout"; 4 - import { ReaderContent } from "./ReaderContent"; 5 - import { SubscriptionsContent } from "./SubscriptionsContent"; 2 + import { InboxContent } from "./InboxContent"; 3 + import { LocalContent } from "./LocalContent"; 4 + import { GlobalContent } from "./GlobalContent"; 6 5 import { getReaderFeed } from "./getReaderFeed"; 7 - import { getSubscriptions } from "./getSubscriptions"; 8 6 9 7 export default async function Reader(props: {}) { 10 8 let posts = await getReaderFeed(); 11 - let publications = await getSubscriptions(); 12 9 return ( 13 10 <DashboardLayout 14 11 id="reader" 15 12 currentPage="reader" 16 - defaultTab="Read" 13 + defaultTab="Inbox" 17 14 actions={null} 18 15 tabs={{ 19 - Read: { 16 + Inbox: { 20 17 controls: null, 21 18 content: ( 22 - <ReaderContent nextCursor={posts.nextCursor} posts={posts.posts} /> 19 + <InboxContent nextCursor={posts.nextCursor} posts={posts.posts} /> 23 20 ), 24 21 }, 25 - Subscriptions: { 22 + Friends: { 26 23 controls: null, 27 - content: ( 28 - <SubscriptionsContent 29 - publications={publications.subscriptions} 30 - nextCursor={publications.nextCursor} 31 - /> 32 - ), 24 + content: <LocalContent />, 25 + }, 26 + Global: { 27 + controls: null, 28 + content: <GlobalContent />, 33 29 }, 34 30 }} 35 31 />