From 77480d7548b467fed963a3c74e615560f3ebbe9f Mon Sep 17 00:00:00 2001 From: Simplereally Date: Wed, 14 Jan 2026 00:09:10 +1100 Subject: [PATCH 01/17] feat: initial high prio items mvp --- app/feed/[type]/page.tsx | 64 ++++++++++- app/sitemap.ts | 12 +- components/gallery/feed-cta.test.tsx | 126 +++++++++++++++++++++ components/gallery/feed-cta.tsx | 113 ++++++++++++++++++ components/gallery/feed-tabs.test.tsx | 69 +++++++++++ components/gallery/feed-tabs.tsx | 16 ++- components/images/image-lightbox.test.tsx | 6 + components/images/image-lightbox.tsx | 75 ++++++++---- components/ui/image-card.tsx | 21 +++- proxy.ts | 1 + todo/public-feed-unauthenticated-access.md | 36 +++--- 11 files changed, 492 insertions(+), 47 deletions(-) create mode 100644 components/gallery/feed-cta.test.tsx create mode 100644 components/gallery/feed-cta.tsx create mode 100644 components/gallery/feed-tabs.test.tsx diff --git a/app/feed/[type]/page.tsx b/app/feed/[type]/page.tsx index d0739bd..4ff7f91 100644 --- a/app/feed/[type]/page.tsx +++ b/app/feed/[type]/page.tsx @@ -1,5 +1,7 @@ import { FeedClient } from "@/components/gallery/feed-client" +import { FeedCta } from "@/components/gallery/feed-cta" import { FEED_TYPES, isValidFeedType, type FeedType } from "@/lib/feed-types" +import type { Metadata } from "next" import { notFound } from "next/navigation" interface FeedPageProps { @@ -13,6 +15,41 @@ export function generateStaticParams() { return FEED_TYPES.map((type) => ({ type })) } +/** + * Generate dynamic metadata based on feed type. + */ +export async function generateMetadata({ params }: FeedPageProps): Promise { + const { type } = await params + + const isPublic = type === "public" + const title = isPublic + ? "Community Creations | Bloom Studio" + : "Following Feed | Bloom Studio" + const description = isPublic + ? "Explore stunning AI-generated images and videos created by the Bloom Studio community. Get inspired by thousands of creative works and create your own masterpieces." + : "See the latest creations from creators you follow on Bloom Studio." + + return { + title, + description, + openGraph: { + title, + description, + type: "website", + siteName: "Bloom Studio", + }, + twitter: { + card: "summary_large_image", + title, + description, + }, + // Only index public feed, not following (which requires auth) + robots: isPublic + ? { index: true, follow: true } + : { index: false, follow: false }, + } +} + export default async function FeedTypePage({ params }: FeedPageProps) { const { type } = await params @@ -22,6 +59,7 @@ export default async function FeedTypePage({ params }: FeedPageProps) { } const feedType: FeedType = type + const isPublicFeed = feedType === "public" return (
@@ -45,7 +83,31 @@ export default async function FeedTypePage({ params }: FeedPageProps) {

+ + {/* Floating CTA for unauthenticated users (only on public feed) */} + {isPublicFeed && } + + {/* JSON-LD Structured Data for SEO (public feed only) */} + {isPublicFeed && ( +