diff --git a/app/(home-pages)/discover/SortButtons.tsx b/app/(home-pages)/discover/SortButtons.tsx deleted file mode 100644 index 3b90228d..00000000 --- a/app/(home-pages)/discover/SortButtons.tsx +++ /dev/null @@ -1,97 +0,0 @@ -"use client"; -import Link from "next/link"; -import { useState } from "react"; -import { theme } from "tailwind.config"; - -export default function SortButtons(props: { order: string }) { - const [selected, setSelected] = useState<"recentlyUpdated" | "popular">( - "recentlyUpdated", - ); - - return ( -
- - - Recently Updated - - - - - Popular - -
- ); -} - -const SortButton = (props: { - children: React.ReactNode; - selected: boolean; -}) => { - return ( -
- - {props.selected && ( - <> -
- -
-
- -
-
- -
- - )} -
- ); -}; - -const GlitterBig = () => { - return ( - - - - ); -}; - -const GlitterSmall = () => { - return ( - - - - ); -}; diff --git a/app/(home-pages)/discover/SortedPublicationList.tsx b/app/(home-pages)/discover/SortedPublicationList.tsx deleted file mode 100644 index d72a3e14..00000000 --- a/app/(home-pages)/discover/SortedPublicationList.tsx +++ /dev/null @@ -1,195 +0,0 @@ -"use client"; -import Link from "next/link"; -import { useState, useEffect, useRef } from "react"; -import { theme } from "tailwind.config"; -import { PubListing } from "./PubListing"; -import useSWRInfinite from "swr/infinite"; -import { getPublications, type Cursor, type Publication } from "./getPublications"; - -export function SortedPublicationList(props: { - publications: Publication[]; - order: string; - nextCursor: Cursor | null; -}) { - let [order, setOrder] = useState(props.order); - - const getKey = ( - pageIndex: number, - previousPageData: { publications: Publication[]; nextCursor: Cursor | null } | null, - ) => { - // Reached the end - if (previousPageData && !previousPageData.nextCursor) return null; - - // First page, we don't have previousPageData - if (pageIndex === 0) return ["discover-publications", order, null] as const; - - // Add the cursor to the key - return ["discover-publications", order, previousPageData?.nextCursor] as const; - }; - - const { data, error, size, setSize, isValidating } = useSWRInfinite( - getKey, - ([_, orderValue, cursor]) => { - const orderParam = orderValue === "popular" ? "popular" : "recentlyUpdated"; - return getPublications(orderParam, cursor); - }, - { - fallbackData: order === props.order - ? [{ publications: props.publications, nextCursor: props.nextCursor }] - : undefined, - revalidateFirstPage: false, - }, - ); - - const loadMoreRef = useRef(null); - - // Set up intersection observer to load more when trigger element is visible - useEffect(() => { - const observer = new IntersectionObserver( - (entries) => { - if (entries[0].isIntersecting && !isValidating) { - const hasMore = data && data[data.length - 1]?.nextCursor; - if (hasMore) { - setSize(size + 1); - } - } - }, - { threshold: 0.1 }, - ); - - if (loadMoreRef.current) { - observer.observe(loadMoreRef.current); - } - - return () => observer.disconnect(); - }, [data, size, setSize, isValidating]); - - const allPublications = data ? data.flatMap((page) => page.publications) : []; - - return ( -
- { - const url = new URL(window.location.href); - url.searchParams.set("order", o); - window.history.pushState({}, "", url); - setOrder(o); - }} - /> -
- {allPublications.map((pub) => ( - - ))} - {/* Trigger element for loading more publications */} - -
- ); -} - -export default function SortButtons(props: { - order: string; - setOrder: (order: string) => void; -}) { - const [selected, setSelected] = useState<"recentlyUpdated" | "popular">( - "recentlyUpdated", - ); - - return ( -
- props.setOrder("recentlyUpdated")} - > - Recently Updated - - - props.setOrder("popular")} - > - Popular - -
- ); -} - -const SortButton = (props: { - children: React.ReactNode; - onClick: () => void; - selected: boolean; -}) => { - return ( -
- - {props.selected && ( - <> -
- -
-
- -
-
- -
- - )} -
- ); -}; - -const GlitterBig = () => { - return ( - - - - ); -}; - -const GlitterSmall = () => { - return ( - - - - ); -}; diff --git a/app/(home-pages)/discover/getPublications.ts b/app/(home-pages)/discover/getPublications.ts deleted file mode 100644 index aa633c1a..00000000 --- a/app/(home-pages)/discover/getPublications.ts +++ /dev/null @@ -1,133 +0,0 @@ -"use server"; - -import { supabaseServerClient } from "supabase/serverClient"; -import { - normalizePublicationRow, - hasValidPublication, -} from "src/utils/normalizeRecords"; -import { deduplicateByUri } from "src/utils/deduplicateRecords"; - -export type Cursor = { - sort_date?: string; - count?: number; - uri: string; -}; - -export type Publication = Awaited< - ReturnType ->["publications"][number]; - -export async function getPublications( - order: "recentlyUpdated" | "popular" = "recentlyUpdated", - cursor?: Cursor | null, -): Promise<{ publications: any[]; nextCursor: Cursor | null }> { - const limit = 25; - - // Fetch all publications with their most recent document - let { data: publications, error } = await supabaseServerClient - .from("publications") - .select( - "*, documents_in_publications(*, documents(*)), publication_subscriptions(count)", - ) - .or( - "record->preferences->showInDiscover.is.null,record->preferences->>showInDiscover.eq.true", - ) - .order("documents(sort_date)", { - referencedTable: "documents_in_publications", - ascending: false, - }) - .limit(1, { referencedTable: "documents_in_publications" }); - - if (error) { - console.error("Error fetching publications:", error); - return { publications: [], nextCursor: null }; - } - - // Deduplicate records that may exist under both pub.leaflet and site.standard namespaces - const dedupedPublications = deduplicateByUri(publications || []); - - // Filter out publications without documents - const allPubs = dedupedPublications.filter( - (pub) => pub.documents_in_publications.length > 0, - ); - - // Sort on the server - allPubs.sort((a, b) => { - if (order === "popular") { - const aCount = a.publication_subscriptions[0]?.count || 0; - const bCount = b.publication_subscriptions[0]?.count || 0; - if (bCount !== aCount) { - return bCount - aCount; - } - // Secondary sort by uri for stability - return b.uri.localeCompare(a.uri); - } else { - // recentlyUpdated - const aDate = new Date( - a.documents_in_publications[0]?.documents?.sort_date || 0, - ).getTime(); - const bDate = new Date( - b.documents_in_publications[0]?.documents?.sort_date || 0, - ).getTime(); - if (bDate !== aDate) { - return bDate - aDate; - } - // Secondary sort by uri for stability - return b.uri.localeCompare(a.uri); - } - }); - - // Find cursor position and slice - let startIndex = 0; - if (cursor) { - startIndex = allPubs.findIndex((pub) => { - if (order === "popular") { - const pubCount = pub.publication_subscriptions[0]?.count || 0; - // Find first pub after cursor - return ( - pubCount < (cursor.count || 0) || - (pubCount === cursor.count && pub.uri < cursor.uri) - ); - } else { - const pubDate = pub.documents_in_publications[0]?.documents?.sort_date || ""; - // Find first pub after cursor - return ( - pubDate < (cursor.sort_date || "") || - (pubDate === cursor.sort_date && pub.uri < cursor.uri) - ); - } - }); - // If not found, we're at the end - if (startIndex === -1) { - return { publications: [], nextCursor: null }; - } - } - - // Get the page - const page = allPubs.slice(startIndex, startIndex + limit); - - // Normalize publication records - const normalizedPage = page - .map(normalizePublicationRow) - .filter(hasValidPublication); - - // Create next cursor based on last item in normalizedPage - const lastItem = normalizedPage[normalizedPage.length - 1]; - const nextCursor = - normalizedPage.length > 0 && startIndex + limit < allPubs.length - ? order === "recentlyUpdated" - ? { - sort_date: lastItem.documents_in_publications[0]?.documents?.sort_date, - uri: lastItem.uri, - } - : { - count: lastItem.publication_subscriptions[0]?.count || 0, - uri: lastItem.uri, - } - : null; - - return { - publications: normalizedPage, - nextCursor, - }; -} diff --git a/app/(home-pages)/discover/page.tsx b/app/(home-pages)/discover/page.tsx deleted file mode 100644 index facf7c12..00000000 --- a/app/(home-pages)/discover/page.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import Link from "next/link"; -import { SortedPublicationList } from "./SortedPublicationList"; -import { Metadata } from "next"; -import { DashboardLayout } from "components/PageLayouts/DashboardLayout"; -import { getPublications } from "./getPublications"; - -export const metadata: Metadata = { - title: "Leaflet Discover", - description: "Explore publications on Leaflet ✨ Or make your own!", -}; - -export default async function Discover(props: { - searchParams: Promise<{ [key: string]: string | string[] | undefined }>; -}) { - let order = ((await props.searchParams).order as string) || "recentlyUpdated"; - - return ( - , - }, - }} - /> - ); -} - -const DiscoverContent = async (props: { order: string }) => { - const orderValue = props.order === "popular" ? "popular" : "recentlyUpdated"; - let { publications, nextCursor } = await getPublications(orderValue); - - return ( -
-
-

Discover

-

- Explore publications on Leaflet ✨ Or{" "} - make your own! -

-
- -
- ); -}; diff --git a/app/(home-pages)/home/Actions/AccountSettings.tsx b/app/(home-pages)/home/Actions/AccountSettings.tsx index 67df4f37..c3cb0043 100644 --- a/app/(home-pages)/home/Actions/AccountSettings.tsx +++ b/app/(home-pages)/home/Actions/AccountSettings.tsx @@ -1,134 +1,24 @@ "use client"; import { ActionButton } from "components/ActionBar/ActionButton"; -import { mutate } from "swr"; -import { AccountSmall } from "components/Icons/AccountSmall"; -import { LogoutSmall } from "components/Icons/LogoutSmall"; import { Popover } from "components/Popover"; -import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; -import { SpeedyLink } from "components/SpeedyLink"; -import { GoBackSmall } from "components/Icons/GoBackSmall"; -import { useState } from "react"; import { ThemeSetterContent } from "components/ThemeManager/ThemeSetter"; import { useIsMobile } from "src/hooks/isMobile"; +import { PaintSmall } from "components/Icons/PaintSmall"; -export const AccountSettings = (props: { entityID: string }) => { - let [state, setState] = useState<"menu" | "general" | "theme">("menu"); +export const AccountTheme = (props: { entityID: string }) => { let isMobile = useIsMobile(); return ( setState("menu")} side={isMobile ? "top" : "right"} align={isMobile ? "center" : "start"} - className={`max-w-xs w-[1000px] ${state === "theme" && "bg-white!"}`} - trigger={ label="Settings" />} + className={`w-xs bg-white!`} + arrowFill="bg-white" + trigger={ label="Theme" />} > - {state === "general" ? ( - setState("menu")} /> - ) : state === "theme" ? ( - setState("menu")} - /> - ) : ( - - )} - - ); -}; - -const SettingsMenu = (props: { - state: "menu" | "general" | "theme"; - setState: (s: typeof props.state) => void; -}) => { - let menuItemClassName = - "menuItem -mx-[8px] text-left flex items-center justify-between hover:no-underline!"; - - return ( -
- - - -
- ); -}; - -const GeneralSettings = (props: { backToMenu: () => void }) => { - return ( -
- props.backToMenu()} - /> - - -
- ); -}; -const AccountThemeSettings = (props: { - entityID: string; - backToMenu: () => void; -}) => { - return ( -
- props.backToMenu()} - /> -
- ); -}; -export const AccountSettingsHeader = (props: { - state: "menu" | "general" | "theme"; - backToMenuAction?: () => void; -}) => { - return ( -
- {props.state === "menu" - ? "Settings" - : props.state === "general" - ? "General" - : props.state === "theme" - ? "Account Theme" - : ""} - {props.backToMenuAction && ( - - )} -
+ ); }; diff --git a/app/(home-pages)/home/Actions/Actions.tsx b/app/(home-pages)/home/Actions/Actions.tsx index 20852f4d..050f7f16 100644 --- a/app/(home-pages)/home/Actions/Actions.tsx +++ b/app/(home-pages)/home/Actions/Actions.tsx @@ -2,7 +2,7 @@ import { ThemePopover } from "components/ThemeManager/ThemeSetter"; import { CreateNewLeafletButton } from "./CreateNewButton"; import { HelpButton } from "app/[leaflet_id]/actions/HelpButton"; -import { AccountSettings } from "./AccountSettings"; +import { AccountTheme } from "./AccountSettings"; import { useIdentityData } from "components/IdentityProvider"; import { useReplicache } from "src/replicache"; import { LoginActionButton } from "components/LoginButton"; @@ -13,11 +13,7 @@ export const Actions = () => { return ( <> - {identity ? ( - - ) : ( - - )} + {identity && } ); }; diff --git a/app/(home-pages)/home/Actions/CreateNewButton.tsx b/app/(home-pages)/home/Actions/CreateNewButton.tsx index 417c5dcd..454ae7ca 100644 --- a/app/(home-pages)/home/Actions/CreateNewButton.tsx +++ b/app/(home-pages)/home/Actions/CreateNewButton.tsx @@ -26,8 +26,9 @@ export const CreateNewLeafletButton = (props: {}) => { + icon= label="New" + smallOnMobile /> } > diff --git a/app/(home-pages)/home/HomeEmpty/HomeEmpty.tsx b/app/(home-pages)/home/HomeEmpty/HomeEmpty.tsx index ecabbabc..517e2580 100644 --- a/app/(home-pages)/home/HomeEmpty/HomeEmpty.tsx +++ b/app/(home-pages)/home/HomeEmpty/HomeEmpty.tsx @@ -1,107 +1,83 @@ "use client"; - import { PubListEmptyIllo } from "components/ActionBar/Publications"; -import { ButtonPrimary } from "components/Buttons"; -import { AddSmall } from "components/Icons/AddSmall"; -import { Link } from "react-aria-components"; -import { DiscoverIllo } from "./DiscoverIllo"; +import { ButtonPrimary, ButtonSecondary } from "components/Buttons"; import { WelcomeToLeafletIllo } from "./WelcomeToLeafletIllo"; -import { DiscoverSmall } from "components/Icons/DiscoverSmall"; -import { PublishSmall } from "components/Icons/PublishSmall"; import { createNewLeaflet } from "actions/createNewLeaflet"; import { useIsMobile } from "src/hooks/isMobile"; +import { SpeedyLink } from "components/SpeedyLink"; export function HomeEmptyState() { - let isMobile = useIsMobile(); return ( -
-
-
- -
-
-

Leaflet

- {/*

A platform for social publishing.

*/} -
- Write and share delightful documents! -
- { - let openNewLeaflet = (id: string) => { - if (isMobile) { - window.location.href = `/${id}?focusFirstBlock`; - } else { - window.open(`/${id}?focusFirstBlock`, "_blank"); - } - }; - - let id = await createNewLeaflet({ - pageType: "doc", - redirectUser: false, - }); - openNewLeaflet(id); - }} - > - Write a Doc! - -
-
-
-
-
or
-
-
- +
- -
- Right now docs and publications are separate. Soon you'll be able to add - docs to pubs! +
+
+
or
+
+
); } -export const PublicationBanner = (props: { small?: boolean }) => { +let bannerStyles = + "flex flex-row sm:flex-col py-4 px-4 sm:items-center items-start gap-4"; + +const PublicationBanner = () => { return ( -
- {props.small ? ( - - ) : ( +
+
- )} -
- - Start a Publication - {" "} - and blog in the Atmosphere +
+

Create a Publication!

+
+ You can decide to share or publish it later. +
+ + Create a Publication + +
); }; -export const DiscoverBanner = (props: { small?: boolean }) => { +const DocBanner = () => { + let isMobile = useIsMobile(); + return ( -
- {props.small ? ( - - ) : ( -
- +
+
+ +
+ +
+

Just write something

+
+ You can decide to share or publish it later.
- )} -
- - Explore Publications - {" "} - on art, tech, games, music & more! + { + let openNewLeaflet = (id: string) => { + if (isMobile) { + window.location.href = `/${id}?focusFirstBlock`; + } else { + window.open(`/${id}?focusFirstBlock`, "_blank"); + } + }; + + let id = await createNewLeaflet({ + pageType: "doc", + redirectUser: false, + }); + openNewLeaflet(id); + }} + > + New Doc! +
); diff --git a/app/(home-pages)/home/HomeEmpty/WelcomeToLeafletIllo.tsx b/app/(home-pages)/home/HomeEmpty/WelcomeToLeafletIllo.tsx index 289d8355..d88c55a5 100644 --- a/app/(home-pages)/home/HomeEmpty/WelcomeToLeafletIllo.tsx +++ b/app/(home-pages)/home/HomeEmpty/WelcomeToLeafletIllo.tsx @@ -3,8 +3,8 @@ import { theme } from "tailwind.config"; export const WelcomeToLeafletIllo = () => { return ( ); }; @@ -170,10 +167,6 @@ export function HomeLeafletList(props: { showPreview />
- - {leaflets.filter((l) => !!l.token.leaflets_in_publications).length === - 0 && } - ); } @@ -204,7 +197,7 @@ export function LeafletList(props: { className={` leafletList w-full - ${display === "grid" ? "grid auto-rows-max md:grid-cols-4 sm:grid-cols-3 grid-cols-2 gap-y-4 gap-x-4 sm:gap-x-6 sm:gap-y-5 grow" : "flex flex-col gap-2 pt-2"} `} + ${display === "grid" ? "grid auto-rows-max md:grid-cols-4 sm:grid-cols-3 grid-cols-2 gap-y-4 gap-x-4 sm:gap-x-6 sm:gap-y-5 grow" : "flex flex-col gap-2"} `} > {props.leaflets.map(({ token: leaflet, added_at, archived }, index) => ( + {props.children} ); @@ -34,6 +36,7 @@ export default async function HomePagesLayout(props: { > + {props.children} diff --git a/app/(home-pages)/looseleafs/LooseleafsLayout.tsx b/app/(home-pages)/looseleafs/LooseleafsLayout.tsx index 5f0c12b3..c389d6e4 100644 --- a/app/(home-pages)/looseleafs/LooseleafsLayout.tsx +++ b/app/(home-pages)/looseleafs/LooseleafsLayout.tsx @@ -47,6 +47,7 @@ export const LooseleafsLayout = (props: { ), }, }} + pageTitle="Looseleafs" /> ); }; diff --git a/app/(home-pages)/p/[didOrHandle]/PostsContent.tsx b/app/(home-pages)/p/[didOrHandle]/PostsContent.tsx index eb841838..7bd67c3c 100644 --- a/app/(home-pages)/p/[didOrHandle]/PostsContent.tsx +++ b/app/(home-pages)/p/[didOrHandle]/PostsContent.tsx @@ -68,7 +68,7 @@ export const ProfilePostsContent = (props: { } return ( -
+
{allPosts.map((post) => ( ))} diff --git a/app/(home-pages)/p/[didOrHandle]/ProfileHeader.tsx b/app/(home-pages)/p/[didOrHandle]/ProfileHeader.tsx index 3fb2b0fd..f99934c7 100644 --- a/app/(home-pages)/p/[didOrHandle]/ProfileHeader.tsx +++ b/app/(home-pages)/p/[didOrHandle]/ProfileHeader.tsx @@ -42,8 +42,6 @@ export const ProfileHeader = (props: { @{props.profile.handle}
); - console.log(props.profile); - return (
-
+
{props.publications.map((p) => ( diff --git a/app/(home-pages)/p/[didOrHandle]/ProfileLayout.tsx b/app/(home-pages)/p/[didOrHandle]/ProfileLayout.tsx index a298dec3..15e598d0 100644 --- a/app/(home-pages)/p/[didOrHandle]/ProfileLayout.tsx +++ b/app/(home-pages)/p/[didOrHandle]/ProfileLayout.tsx @@ -11,10 +11,10 @@ export function ProfileLayout(props: { children: React.ReactNode }) { ${ cardBorderHidden ? "" - : "overflow-y-scroll h-full border border-border-light rounded-lg bg-bg-page" + : "overflow-y-scroll h-full border border-border-light rounded-lg bg-bg-page px-3 sm:px-4" } max-w-prose mx-auto w-full - flex flex-col + flex flex-col pb-3 text-center `} > diff --git a/app/(home-pages)/p/[didOrHandle]/ProfileTabs.tsx b/app/(home-pages)/p/[didOrHandle]/ProfileTabs.tsx index c5b9e3a2..bb058749 100644 --- a/app/(home-pages)/p/[didOrHandle]/ProfileTabs.tsx +++ b/app/(home-pages)/p/[didOrHandle]/ProfileTabs.tsx @@ -41,7 +41,7 @@ export const ProfileTabs = (props: { didOrHandle: string }) => { const bgColor = cardBorderHidden ? "var(--bg-leaflet)" : "var(--bg-page)"; return ( -
+
{ +export const PubListing = (props: PublicationSubscription) => { let record = props.record; let theme = usePubTheme(record?.theme); let backgroundImage = record?.theme?.backgroundImage?.image?.ref @@ -28,8 +25,7 @@ export const PubListing = ( if (!record) return null; return ( - +
); }; diff --git a/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx b/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx index b7a9a350..a2a3f474 100644 --- a/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx +++ b/app/(home-pages)/p/[didOrHandle]/comments/CommentsContent.tsx @@ -85,7 +85,7 @@ export const ProfileCommentsContent = (props: { } return ( -
+
{allComments.map((comment) => ( ))} diff --git a/app/(home-pages)/p/[didOrHandle]/layout.tsx b/app/(home-pages)/p/[didOrHandle]/layout.tsx index 4108fe28..eb9f3531 100644 --- a/app/(home-pages)/p/[didOrHandle]/layout.tsx +++ b/app/(home-pages)/p/[didOrHandle]/layout.tsx @@ -82,6 +82,7 @@ export default async function ProfilePageLayout(props: { id="profile" defaultTab="default" currentPage="profile" + profileDid={did} actions={null} tabs={{ default: { @@ -93,9 +94,7 @@ export default async function ProfilePageLayout(props: { publications={publications || []} /> -
- {props.children} -
+ <>{props.children} ), }, diff --git a/app/(home-pages)/p/[didOrHandle]/subscriptions/SubscriptionsContent.tsx b/app/(home-pages)/p/[didOrHandle]/subscriptions/SubscriptionsContent.tsx index 9e5e4ca8..49818ecd 100644 --- a/app/(home-pages)/p/[didOrHandle]/subscriptions/SubscriptionsContent.tsx +++ b/app/(home-pages)/p/[didOrHandle]/subscriptions/SubscriptionsContent.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef } from "react"; import useSWRInfinite from "swr/infinite"; -import { PubListing } from "app/(home-pages)/discover/PubListing"; +import { PubListing } from "app/(home-pages)/p/[didOrHandle]/PubListing"; import { getSubscriptions, type PublicationSubscription, @@ -82,7 +82,7 @@ export const ProfileSubscriptionsContent = (props: { return (
-
+
{allSubscriptions.map((sub) => ( ))} diff --git a/app/(home-pages)/page.tsx b/app/(home-pages)/page.tsx new file mode 100644 index 00000000..036e9562 --- /dev/null +++ b/app/(home-pages)/page.tsx @@ -0,0 +1,31 @@ +import { cookies } from "next/headers"; +import ReaderLayout from "./reader/layout"; +import ReaderPage from "./reader/page"; +import HomePage from "./home/page"; + +export default async function RootPage() { + const cookieStore = await cookies(); + const hasAuth = + cookieStore.has("auth_token") || + cookieStore.has("external_auth_token"); + + if (!hasAuth) { + return ( + + + + ); + } + + const navState = cookieStore.get("nav-state")?.value; + + if (navState === "reader") { + return ( + + + + ); + } + + return ; +} diff --git a/app/(home-pages)/reader/FeedSkeleton.tsx b/app/(home-pages)/reader/FeedSkeleton.tsx new file mode 100644 index 00000000..2541b869 --- /dev/null +++ b/app/(home-pages)/reader/FeedSkeleton.tsx @@ -0,0 +1,13 @@ +export function FeedSkeleton() { + return ( +
+ {[...Array(3)].map((_, i) => ( +
+
+
+
+
+ ))} +
+ ); +} diff --git a/app/(home-pages)/reader/GlobalContent.tsx b/app/(home-pages)/reader/GlobalContent.tsx new file mode 100644 index 00000000..53cf2462 --- /dev/null +++ b/app/(home-pages)/reader/GlobalContent.tsx @@ -0,0 +1,49 @@ +"use client"; +import { use } from "react"; +import useSWR from "swr"; +import { callRPC } from "app/api/rpc/client"; +import { PostListing } from "components/PostListing"; +import type { Post } from "./getReaderFeed"; +import { + DesktopInteractionPreviewDrawer, + MobileInteractionPreviewDrawer, +} from "./InteractionDrawers"; + +export const GlobalContent = (props: { + promise: Promise<{ posts: Post[] }>; +}) => { + const initialData = use(props.promise); + + const { data } = useSWR( + "hot_feed", + async () => { + const res = await callRPC("get_hot_feed", {}); + return res as unknown as { posts: Post[] }; + }, + { + fallbackData: { posts: initialData.posts }, + }, + ); + + const posts = data?.posts ?? []; + + if (posts.length === 0) { + return ( +
+ Nothing trending right now. Check back soon! +
+ ); + } + + return ( +
+
+ {posts.map((p) => ( + + ))} +
+ + +
+ ); +}; diff --git a/app/(home-pages)/reader/ReaderContent.tsx b/app/(home-pages)/reader/InboxContent.tsx similarity index 61% rename from app/(home-pages)/reader/ReaderContent.tsx rename to app/(home-pages)/reader/InboxContent.tsx index e73b3df9..791d4827 100644 --- a/app/(home-pages)/reader/ReaderContent.tsx +++ b/app/(home-pages)/reader/InboxContent.tsx @@ -1,4 +1,5 @@ "use client"; +import { use } from "react"; import { ButtonPrimary } from "components/Buttons"; import { DiscoverSmall } from "components/Icons/DiscoverSmall"; import type { Cursor, Post } from "./getReaderFeed"; @@ -7,11 +8,17 @@ import { getReaderFeed } from "./getReaderFeed"; import { useEffect, useRef } from "react"; import Link from "next/link"; import { PostListing } from "components/PostListing"; +import { useHasBackgroundImage } from "components/Pages/useHasBackgroundImage"; +import { + DesktopInteractionPreviewDrawer, + MobileInteractionPreviewDrawer, +} from "./InteractionDrawers"; -export const ReaderContent = (props: { - posts: Post[]; - nextCursor: Cursor | null; +export const InboxContent = (props: { + promise: Promise<{ posts: Post[]; nextCursor: Cursor | null }>; }) => { + const { posts, nextCursor } = use(props.promise); + const getKey = ( pageIndex: number, previousPageData: { @@ -33,7 +40,7 @@ export const ReaderContent = (props: { getKey, ([_, cursor]) => getReaderFeed(cursor), { - fallbackData: [{ posts: props.posts, nextCursor: props.nextCursor }], + fallbackData: [{ posts, nextCursor }], revalidateFirstPage: false, }, ); @@ -63,24 +70,36 @@ export const ReaderContent = (props: { const allPosts = data ? data.flatMap((page) => page.posts) : []; + const sortedPosts = allPosts.sort( + (a, b) => + new Date(b.documents.data?.publishedAt || 0).getTime() - + new Date(a.documents.data?.publishedAt || 0).getTime(), + ); + if (allPosts.length === 0 && !isValidating) return ; + let hasBackgroundImage = useHasBackgroundImage(); + return ( -
- {allPosts.map((p) => ( - - ))} - {/* Trigger element for loading more posts */} -