a tool for shared writing and social publishing

add loading.tsx for route level suspense boundary

+22 -34
+1 -7
app/(home-pages)/reader/GlobalContent.tsx
··· 14 14 }) => { 15 15 const initialData = use(props.promise); 16 16 17 - const { data, isLoading } = useSWR( 17 + const { data } = useSWR( 18 18 "hot_feed", 19 19 async () => { 20 20 const res = await callRPC("get_hot_feed", {}); ··· 26 26 ); 27 27 28 28 const posts = data?.posts ?? []; 29 - 30 - if (isLoading) { 31 - return ( 32 - <div className="text-center text-tertiary py-8">Loading posts...</div> 33 - ); 34 - } 35 29 36 30 if (posts.length === 0) { 37 31 return (
+1 -7
app/(home-pages)/reader/hot/page.tsx
··· 1 - import { Suspense } from "react"; 2 1 import { getHotFeed } from "../getHotFeed"; 3 2 import { GlobalContent } from "../GlobalContent"; 4 - import { FeedSkeleton } from "../FeedSkeleton"; 5 3 6 4 export default async function HotPage() { 7 5 const feedPromise = getHotFeed(); 8 - return ( 9 - <Suspense fallback={<FeedSkeleton />}> 10 - <GlobalContent promise={feedPromise} /> 11 - </Suspense> 12 - ); 6 + return <GlobalContent promise={feedPromise} />; 13 7 }
+4
app/(home-pages)/reader/loading.tsx
··· 1 + import { FeedSkeleton } from "./FeedSkeleton"; 2 + export default function Loading() { 3 + return <FeedSkeleton />; 4 + }
+1 -7
app/(home-pages)/reader/new/page.tsx
··· 1 - import { Suspense } from "react"; 2 1 import { getNewFeed } from "../getNewFeed"; 3 2 import { NewContent } from "../NewContent"; 4 - import { FeedSkeleton } from "../FeedSkeleton"; 5 3 6 4 export default async function NewPage() { 7 5 const feedPromise = getNewFeed(); 8 - return ( 9 - <Suspense fallback={<FeedSkeleton />}> 10 - <NewContent promise={feedPromise} /> 11 - </Suspense> 12 - ); 6 + return <NewContent promise={feedPromise} />; 13 7 }
+1 -7
app/(home-pages)/reader/page.tsx
··· 1 - import { Suspense } from "react"; 2 1 import { getReaderFeed } from "./getReaderFeed"; 3 2 import { InboxContent } from "./InboxContent"; 4 - import { FeedSkeleton } from "./FeedSkeleton"; 5 3 6 4 export default async function Reader() { 7 5 const feedPromise = getReaderFeed(); 8 - return ( 9 - <Suspense fallback={<FeedSkeleton />}> 10 - <InboxContent promise={feedPromise} /> 11 - </Suspense> 12 - ); 6 + return <InboxContent promise={feedPromise} />; 13 7 }
+14 -6
components/PostListing.tsx
··· 11 11 import type { Post } from "app/(home-pages)/reader/getReaderFeed"; 12 12 13 13 import Link from "next/link"; 14 + import { useEffect, useRef, useState } from "react"; 14 15 import { InteractionPreview, TagPopover } from "./InteractionsPreview"; 15 16 import { useLocalizedDate } from "src/hooks/useLocalizedDate"; 16 17 import { useSmoker } from "./Toast"; ··· 42 43 let isStandalone = !pubRecord; 43 44 let theme = usePubTheme(pubRecord?.theme || postRecord?.theme, isStandalone); 44 45 let themeRecord = pubRecord?.theme || postRecord?.theme; 45 - let el = document?.getElementById(`post-listing-${postUri}`); 46 + let elRef = useRef<HTMLDivElement>(null); 47 + let [hasBackgroundImage, setHasBackgroundImage] = useState(false); 46 48 47 - let hasBackgroundImage = 48 - !!themeRecord?.backgroundImage?.image && 49 - el && 50 - Number(window.getComputedStyle(el).getPropertyValue("--bg-page-alpha")) < 51 - 0.7; 49 + useEffect(() => { 50 + if (!themeRecord?.backgroundImage?.image || !elRef.current) { 51 + setHasBackgroundImage(false); 52 + return; 53 + } 54 + let alpha = Number( 55 + window.getComputedStyle(elRef.current).getPropertyValue("--bg-page-alpha"), 56 + ); 57 + setHasBackgroundImage(alpha < 0.7); 58 + }, [themeRecord?.backgroundImage?.image]); 52 59 53 60 let backgroundImage = 54 61 themeRecord?.backgroundImage?.image?.ref && uri ··· 82 89 <div className="postListing flex flex-col gap-1"> 83 90 <BaseThemeProvider {...theme} local> 84 91 <div 92 + ref={elRef} 85 93 id={`post-listing-${postUri}`} 86 94 className={` 87 95 relative