Retro Bulletin Board Systems on atproto. Web app and TUI. lazy mirror of alyraffauf/atbbs atbbs.xyz
forums python tui atproto bbs
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

web: add PageSkeleton

+17 -37
-10
web/src/components/layout/HydrateFallback.tsx
··· 1 - export default function HydrateFallback() { 2 - return ( 3 - <div className="flex flex-col h-dvh"> 4 - <div 5 - className="fixed top-0 left-0 right-0 h-0.5 bg-neutral-400 z-50" 6 - style={{ animation: "atbbs-progress 1.5s ease-out infinite" }} 7 - /> 8 - </div> 9 - ); 10 - }
+3 -12
web/src/components/layout/Layout.tsx
··· 1 1 import { Suspense } from "react"; 2 - import { Outlet, useLocation, useNavigation } from "react-router-dom"; 3 - import { useIsFetching } from "@tanstack/react-query"; 2 + import { Outlet, useLocation } from "react-router-dom"; 4 3 import Header from "./Header"; 5 4 import MobileBackButton from "./MobileBackButton"; 6 5 import Footer from "./Footer"; 7 6 import ErrorBoundary from "./ErrorBoundary"; 7 + import PageSkeleton from "./PageSkeleton"; 8 8 import LoginModal from "../auth/LoginModal"; 9 9 import { LoginModalProvider } from "../../lib/loginModal"; 10 10 11 11 export default function Layout() { 12 - const routeLoading = useNavigation().state === "loading"; 13 - const queriesLoading = useIsFetching() > 0; 14 - const showProgress = routeLoading || queriesLoading; 15 12 // Remount ErrorBoundary + Suspense on navigation so a fresh page doesn't 16 13 // inherit the previous page's error or fallback state. 17 14 const routeKey = useLocation().pathname; ··· 19 16 return ( 20 17 <LoginModalProvider> 21 18 <div className="flex flex-col h-dvh"> 22 - {showProgress && ( 23 - <div 24 - className="fixed top-0 left-0 right-0 h-0.5 bg-neutral-400 z-50" 25 - style={{ animation: "atbbs-progress 1.5s ease-out infinite" }} 26 - /> 27 - )} 28 19 <Header /> 29 20 <main className="max-w-2xl mx-auto px-4 py-8 flex-1 w-full"> 30 21 <MobileBackButton /> 31 22 <ErrorBoundary key={routeKey}> 32 - <Suspense fallback={null}> 23 + <Suspense fallback={<PageSkeleton />}> 33 24 <Outlet /> 34 25 </Suspense> 35 26 </ErrorBoundary>
+14
web/src/components/layout/PageSkeleton.tsx
··· 1 + export default function PageSkeleton() { 2 + return ( 3 + <div className="space-y-4 animate-pulse" aria-hidden> 4 + <div className="h-6 w-2/3 bg-neutral-800 rounded" /> 5 + <div className="h-4 w-full bg-neutral-900 rounded" /> 6 + <div className="h-4 w-5/6 bg-neutral-900 rounded" /> 7 + <div className="space-y-2 pt-4"> 8 + <div className="h-16 w-full bg-neutral-900 rounded" /> 9 + <div className="h-16 w-full bg-neutral-900 rounded" /> 10 + <div className="h-16 w-full bg-neutral-900 rounded" /> 11 + </div> 12 + </div> 13 + ); 14 + }
-15
web/src/index.css
··· 52 52 } 53 53 } 54 54 55 - @keyframes atbbs-progress { 56 - 0% { 57 - transform: scaleX(0); 58 - transform-origin: left; 59 - } 60 - 50% { 61 - transform: scaleX(0.6); 62 - transform-origin: left; 63 - } 64 - 100% { 65 - transform: scaleX(1); 66 - transform-origin: left; 67 - opacity: 0; 68 - } 69 - }