[object Object]

← back to Grant

Serve fit-feed landing at / for logged-out visitors; AppShell for signed-in (shared Landing component)

f42a32602436a02b0386a2c0ec17854e65abf474 · 2026-05-30 09:21:04 -0700 · Steve Abrams

Files touched

Diff

commit f42a32602436a02b0386a2c0ec17854e65abf474
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat May 30 09:21:04 2026 -0700

    Serve fit-feed landing at / for logged-out visitors; AppShell for signed-in (shared Landing component)
---
 app/landing/page.tsx                    | 24 ++----------------------
 app/page.tsx                            | 14 ++++++++++++--
 components/landing/Landing.tsx          | 30 ++++++++++++++++++++++++++++++
 {app => components}/landing/landing.css |  0
 4 files changed, 44 insertions(+), 24 deletions(-)

diff --git a/app/landing/page.tsx b/app/landing/page.tsx
index 699a659..1e42d43 100644
--- a/app/landing/page.tsx
+++ b/app/landing/page.tsx
@@ -1,21 +1,5 @@
 import type { Metadata } from 'next';
-import { Space_Grotesk, IBM_Plex_Sans } from 'next/font/google';
-import FitFeed from '@/components/landing/FitFeed';
-import './landing.css';
-
-const display = Space_Grotesk({
-  subsets: ['latin'],
-  weight: ['500', '600', '700'],
-  variable: '--ff-display',
-  display: 'swap',
-});
-
-const body = IBM_Plex_Sans({
-  subsets: ['latin'],
-  weight: ['400', '500', '600'],
-  variable: '--ff-body',
-  display: 'swap',
-});
+import Landing from '@/components/landing/Landing';
 
 export const metadata: Metadata = {
   title: 'Grant — One fit-scored feed for every funding source',
@@ -24,9 +8,5 @@ export const metadata: Metadata = {
 };
 
 export default function LandingPage() {
-  return (
-    <div className={`${display.variable} ${body.variable}`}>
-      <FitFeed />
-    </div>
-  );
+  return <Landing />;
 }
diff --git a/app/page.tsx b/app/page.tsx
index c6bdf56..f374e8f 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,5 +1,15 @@
+import { headers } from 'next/headers';
 import AppShell from '@/components/AppShell';
+import Landing from '@/components/landing/Landing';
+import { verifyAuth } from '@/lib/auth';
 
-export default function Home() {
-  return <AppShell />;
+// Auth-branch the root route: signed-in visitors get the app; everyone else
+// sees the public fit-feed landing. verifyAuth only reads the `cookie` header,
+// so we hand it a minimal shim built from the incoming request headers.
+export default async function Home() {
+  const cookie = (await headers()).get('cookie') ?? '';
+  const shim = { headers: { get: (k: string) => (k.toLowerCase() === 'cookie' ? cookie : null) } };
+  const session = verifyAuth(shim as unknown as Request);
+
+  return session ? <AppShell /> : <Landing />;
 }
diff --git a/components/landing/Landing.tsx b/components/landing/Landing.tsx
new file mode 100644
index 0000000..0082478
--- /dev/null
+++ b/components/landing/Landing.tsx
@@ -0,0 +1,30 @@
+import { Space_Grotesk, IBM_Plex_Sans } from 'next/font/google';
+import FitFeed from './FitFeed';
+import './landing.css';
+
+/* Shared public marketing landing — rendered both at /landing and at / for
+   logged-out visitors (app/page.tsx auth-branches to it). Fonts are
+   self-hosted via next/font and exposed to landing.css as --ff-display /
+   --ff-body on the wrapper. */
+
+const display = Space_Grotesk({
+  subsets: ['latin'],
+  weight: ['500', '600', '700'],
+  variable: '--ff-display',
+  display: 'swap',
+});
+
+const body = IBM_Plex_Sans({
+  subsets: ['latin'],
+  weight: ['400', '500', '600'],
+  variable: '--ff-body',
+  display: 'swap',
+});
+
+export default function Landing() {
+  return (
+    <div className={`${display.variable} ${body.variable}`}>
+      <FitFeed />
+    </div>
+  );
+}
diff --git a/app/landing/landing.css b/components/landing/landing.css
similarity index 100%
rename from app/landing/landing.css
rename to components/landing/landing.css

← 5692f38 Build out fit-feed landing as real /landing route (interacti  ·  back to Grant  ·  SEO (robots/sitemap/OG image/metadata) + reusable deploy.sh 580b213 →