a tool for shared writing and social publishing

persist nav state on reader/home

+85 -14
+3
app/(home-pages)/layout.tsx
··· 1 1 import { getIdentityData } from "actions/getIdentityData"; 2 2 import { EntitySetProvider } from "components/EntitySetProvider"; 3 + import { NavStateTracker } from "components/NavStateTracker"; 3 4 import { 4 5 ThemeProvider, 5 6 ThemeBackgroundProvider, ··· 13 14 if (!identityData?.home_leaflet) 14 15 return ( 15 16 <> 17 + <NavStateTracker /> 16 18 <ThemeProvider entityID={""}>{props.children}</ThemeProvider> 17 19 </> 18 20 ); ··· 34 36 > 35 37 <ThemeProvider entityID={root_entity}> 36 38 <ThemeBackgroundProvider entityID={root_entity}> 39 + <NavStateTracker /> 37 40 {props.children} 38 41 </ThemeBackgroundProvider> 39 42 </ThemeProvider>
+31
app/(home-pages)/page.tsx
··· 1 + import { cookies } from "next/headers"; 2 + import ReaderLayout from "./reader/layout"; 3 + import ReaderPage from "./reader/page"; 4 + import HomePage from "./home/page"; 5 + 6 + export default async function RootPage() { 7 + const cookieStore = await cookies(); 8 + const hasAuth = 9 + cookieStore.has("auth_token") || 10 + cookieStore.has("external_auth_token"); 11 + 12 + if (!hasAuth) { 13 + return ( 14 + <ReaderLayout> 15 + <ReaderPage /> 16 + </ReaderLayout> 17 + ); 18 + } 19 + 20 + const navState = cookieStore.get("nav-state")?.value; 21 + 22 + if (navState === "reader") { 23 + return ( 24 + <ReaderLayout> 25 + <ReaderPage /> 26 + </ReaderLayout> 27 + ); 28 + } 29 + 30 + return <HomePage />; 31 + }
+8 -3
app/(home-pages)/reader/layout.tsx
··· 27 27 const tabs = allTabs.filter((tab) => !tab.requiresAuth || isLoggedIn); 28 28 29 29 const isActive = (href: string) => { 30 - if (href === "/reader") return pathname === "/reader"; 31 - if (href === "/reader/hot" && !isLoggedIn && pathname === "/reader") 30 + if (href === "/reader") 31 + return pathname === "/reader" || pathname === "/"; 32 + if ( 33 + href === "/reader/hot" && 34 + !isLoggedIn && 35 + (pathname === "/reader" || pathname === "/") 36 + ) 32 37 return true; 33 38 return pathname.startsWith(href); 34 39 }; ··· 62 67 ))} 63 68 </div> 64 69 <div className="sm:block grow"> 65 - {pathname === "/reader" && ( 70 + {(pathname === "/reader" || pathname === "/") && ( 66 71 <div className="place-self-end text text-tertiary text-sm"> 67 72 Publications 68 73 </div>
+16
app/api/update-nav-state/route.ts
··· 1 + import { NextRequest, NextResponse } from "next/server"; 2 + 3 + export async function POST(request: NextRequest) { 4 + const { state } = (await request.json()) as { state: string }; 5 + if (state !== "home" && state !== "reader") { 6 + return NextResponse.json({ error: "Invalid state" }, { status: 400 }); 7 + } 8 + 9 + const response = NextResponse.json({ ok: true }); 10 + response.cookies.set("nav-state", state, { 11 + path: "/", 12 + sameSite: "lax", 13 + maxAge: 60 * 60 * 24 * 365, 14 + }); 15 + return response; 16 + }
-11
app/route.ts
··· 1 - import { createNewLeaflet } from "actions/createNewLeaflet"; 2 - import { cookies } from "next/headers"; 3 - import { redirect } from "next/navigation"; 4 - 5 - export const preferredRegion = ["sfo1"]; 6 - export const dynamic = "force-dynamic"; 7 - export const fetchCache = "force-no-store"; 8 - 9 - export async function GET() { 10 - redirect("/home"); 11 - }
+27
components/NavStateTracker.tsx
··· 1 + "use client"; 2 + 3 + import { usePathname } from "next/navigation"; 4 + import { useEffect, useRef } from "react"; 5 + 6 + export function NavStateTracker() { 7 + const pathname = usePathname(); 8 + const lastState = useRef<string | null>(null); 9 + 10 + useEffect(() => { 11 + let state: string | null = null; 12 + if (pathname === "/home") state = "home"; 13 + else if (pathname === "/reader" || pathname.startsWith("/reader/")) 14 + state = "reader"; 15 + 16 + if (state && state !== lastState.current) { 17 + lastState.current = state; 18 + fetch("/api/update-nav-state", { 19 + method: "POST", 20 + headers: { "Content-Type": "application/json" }, 21 + body: JSON.stringify({ state }), 22 + }); 23 + } 24 + }, [pathname]); 25 + 26 + return null; 27 + }