Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/ottabase-template-app-nextjs-homepage/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ NEXT_PUBLIC_MODEL_DEFAULT_REL_KEY="defaults"
# Development
NODE_ENV="development"

# Homepage Configurator Panel (FAB at bottom-right)
# Set to "true" to show on production, or leave unset to auto-show in dev only
# NEXT_PUBLIC_SHOW_CONFIG_PANEL="true"

# ============================================================
# Database Configuration (Prisma + D1)
# ============================================================
Expand Down
204 changes: 204 additions & 0 deletions apps/ottabase-template-app-nextjs-homepage/HOMEPAGE_vNEXT.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Homepage vNEXT — Roadmap

> Roadmap for the Next.js homepage template: deep integration with the Ottabase core framework and feature enhancements for the dynamic, slot-based homepage system.

---

## 1. Core Framework Integration

### 1.1 Database-Backed Content (OttaORM + D1)

**Goal:** Store homepage section content in Cloudflare D1 so that all slots (hero, features, CTA, about, etc.) render from a single source of truth — edit once, render any way you want.

- [ ] Add Cloudflare D1 binding to `wrangler.jsonc` and `cloudflare-env.d.ts`
- [ ] Create `HomepageSection` model using OttaORM `BaseModel`:
```typescript
// Schema: id, sectionType (hero|features|cta|about), contentJson, sortOrder, isActive, createdAt, updatedAt
export class HomepageSection extends BaseModel {
static entity = 'homepage_sections';
static table = homepageSectionsTable;
static primaryKey = 'id';
}
```
- [ ] Create `HomepageFeature` model for the features list (title, description, icon, sortOrder)
- [ ] Create `HomepageAction` model for CTA buttons (label, href, variant, isExternal)
- [ ] Wire models into `db-utils.ts` and register in `schemas-helper.ts` for auto-migration
- [ ] Create API routes: `GET /api/homepage/sections`, `PATCH /api/homepage/sections/:id`
- [ ] Refactor `SlotRenderer` to accept data from DB queries (SSR via `fetch()` in server components) while falling back to static defaults when no DB is configured
- [ ] Add seed script to populate initial content matching current static data

### 1.2 Brand Engine Persistence

**Goal:** Save the active theme preset and slot variant selections in the database so configuration survives across browsers and can be managed by admins.

- [ ] Use `@ottabase/brand-engine/persistence` (`BrandKit`, `LayoutTemplate`, `MenuSlotAssignment`) models
- [ ] Store active theme preset + slot config in `BrandKit` table instead of (or in addition to) localStorage
- [ ] Add admin endpoint: `POST /api/brand/homepage-config` to save config
- [ ] ConfigPanel reads from DB on mount (with localStorage as cache/fallback)
- [ ] Multi-tenant support: different orgs can have different homepage configs

### 1.3 Authentication Integration

**Goal:** Add optional auth so that admins can edit homepage content via an inline editing UI.

- [ ] Wire `@ottabase/auth` with D1 adapter into the homepage worker
- [ ] Add optional login/signup button in navbar (hidden when auth is not configured)
- [ ] Create `AdminGuard` wrapper that shows edit controls only when authenticated as admin
- [ ] Inline edit mode: click-to-edit hero text, feature cards, CTA copy — saves to DB via OttaORM
- [ ] Role check via `@ottabase/rbac` for admin-only editing permissions

### 1.4 Media & File Uploads

**Goal:** Allow hero images, feature icons, and logo to be uploaded and served from Cloudflare R2.

- [ ] Add R2 binding for asset storage
- [ ] Integrate `@ottabase/ottaupload` for drag-and-drop image upload in admin mode
- [ ] Store media references in `@ottabase/medialibrary` `Media` model
- [ ] Hero variants can render a dynamic background image from R2
- [ ] Feature cards support uploaded icons/illustrations

### 1.5 Blog Integration

**Goal:** Surface recent blog posts on the homepage as a dynamic section.

- [ ] Add a `blog` slot with variants: `BlogLatest` (3-card grid), `BlogFeatured` (single spotlight), `BlogList` (compact list)
- [ ] Fetch posts from `@ottabase/ottablog` `Post` model via API: `GET /api/ottaorm/posts?limit=3&orderBy=createdAt`
- [ ] Link to full blog powered by ottablog package
- [ ] Support draft/published filtering, tag-based filtering

### 1.6 Analytics & Tracking

**Goal:** Track page views and section engagement using Cloudflare Analytics Engine.

- [ ] Integrate `@ottabase/analytics` for page-view tracking
- [ ] Add section-level visibility tracking (which hero/features/CTA variants get more engagement)
- [ ] Dashboard widget showing homepage analytics in admin panel
- [ ] A/B testing support: randomly assign visitors to different slot variants and track conversion

### 1.7 Email & Newsletter

**Goal:** Add a newsletter signup component as a homepage slot.

- [ ] Create `newsletter` slot with variants: inline form, modal popup, footer-embedded
- [ ] Integrate `@ottabase/email` for sending confirmation emails
- [ ] Store subscribers in a `NewsletterSubscriber` OttaORM model
- [ ] Double opt-in flow with verification token

### 1.8 Comments & Feedback

**Goal:** Allow visitors to leave feedback or testimonials.

- [ ] Create `testimonials` slot using `@ottabase/comments` for user-submitted reviews
- [ ] Admin moderation panel for approving/rejecting testimonials
- [ ] Display approved testimonials in a carousel or grid variant

### 1.9 Real-Time Updates

**Goal:** Push live content updates to visitors without page reload.

- [ ] Integrate `@ottabase/cf-realtime` WebSocket pub/sub
- [ ] Admin edits to homepage content broadcast live to connected visitors
- [ ] Live visitor count display (optional widget)

---

## 2. Feature Enhancements

### 2.1 New Slot Types

- [ ] **Pricing** — pricing table with tiers (Free, Pro, Enterprise) and feature comparison
- [ ] **FAQ** — accordion-based frequently asked questions section
- [ ] **Team** — team member cards with photos, roles, and social links
- [ ] **Testimonials** — customer quotes in carousel, grid, or marquee layouts
- [ ] **Stats/Metrics** — animated counters showing key numbers (users, uptime, etc.)
- [ ] **Integrations/Partners** — logo cloud with partner/integration badges
- [ ] **Changelog** — recent updates feed (could pull from `ChangelogEntry` model)
- [ ] **Contact** — contact form with email integration via `@ottabase/email`
- [ ] **Blog Preview** — latest posts section (see §1.5)
- [ ] **Newsletter** — email signup section (see §1.7)

### 2.2 Enhanced Config Panel UX

- [ ] Drag-and-drop slot reordering (change section order on the homepage)
- [ ] Live preview thumbnails for each variant option
- [ ] Import/export config as JSON for sharing configurations
- [ ] Undo/redo for config changes
- [ ] Preset homepage layouts (e.g., "SaaS Landing", "Developer Docs", "Portfolio")
- [ ] Section visibility toggle (show/hide individual slots without removing them)

### 2.3 Animation & Transitions

- [ ] Scroll-triggered fade-in animations for each section
- [ ] Smooth section transitions when switching variants in the config panel
- [ ] Parallax effects for hero backgrounds
- [ ] Animated number counters for stats sections
- [ ] Page transition animations between routes

### 2.4 SEO & Performance

- [ ] Dynamic `<meta>` tags and Open Graph data from DB content
- [ ] JSON-LD structured data for homepage sections
- [ ] Automatic sitemap generation including dynamic pages
- [ ] Image optimization pipeline (WebP/AVIF via Cloudflare Images)
- [ ] Critical CSS extraction per active variant combination
- [ ] Lighthouse CI integration for automated performance monitoring

### 2.5 Internationalization (i18n)

- [ ] Multi-language support for all homepage content
- [ ] Language switcher in navbar
- [ ] DB-backed translations per section and locale
- [ ] RTL layout support
- [ ] Automatic browser locale detection

### 2.6 Multi-Page Support

- [ ] Extend slot system to arbitrary pages (not just homepage + about)
- [ ] Page builder: create new pages with drag-and-drop slot composition
- [ ] Dynamic routes from DB: `/pages/:slug` renders slot-composed pages
- [ ] Navigation auto-generated from page registry

### 2.7 Developer Experience

- [ ] CLI command: `pnpm ottabase homepage:seed` to populate DB with sample content
- [ ] CLI command: `pnpm ottabase homepage:export` to export current config
- [ ] Storybook stories for every slot variant (visual documentation)
- [ ] Variant development mode: hot-reload preview of variant changes
- [ ] TypeScript codegen for slot data types from DB schema

### 2.8 Deployment & Multi-Tenancy

- [ ] Per-tenant homepage configuration (different orgs get different homepages)
- [ ] Custom domain mapping per tenant homepage
- [ ] Preview deployments with config snapshots
- [ ] Staging/production config promotion workflow
- [ ] Config versioning with rollback support

---

## Priority Tiers

### Tier 1 — Foundation (Do First)
1. §1.1 Database-backed content (OttaORM models for sections)
2. §1.2 Brand engine persistence (save config to DB)
3. §2.2 Enhanced config panel (reorder, show/hide, presets)
4. §2.1 New slots: Pricing, FAQ, Testimonials

### Tier 2 — Growth
5. §1.3 Authentication + inline editing
6. §1.5 Blog integration
7. §1.4 Media uploads (R2)
8. §2.4 SEO and performance
9. §2.3 Animations

### Tier 3 — Scale
10. §1.6 Analytics and A/B testing
11. §1.7 Newsletter integration
12. §2.5 Internationalization
13. §2.6 Multi-page support
14. §2.8 Multi-tenancy

### Tier 4 — Polish
15. §1.8 Comments and testimonials from users
16. §1.9 Real-time updates
17. §2.7 Developer experience tooling
159 changes: 137 additions & 22 deletions apps/ottabase-template-app-nextjs-homepage/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Ottabase Next.js Homepage Template

Next.js 16 homepage template deployed to Cloudflare Workers via OpenNext. Uses Brand Engine for theming with 8 presets
and live switching.
and live switching, plus an **extensible slot framework** for hot-swappable homepage sections.

> **Monorepo note:** The main TanStack app (`ottabase-template-app-tanstack`) drives its brand config from a D1
> database, editable via the admin UI at `/admin/brand-engine`. This homepage is intentionally **config-first** — no DB,
Expand All @@ -21,30 +21,145 @@ pnpm dev

```
app/
├── page.tsx # Homepage
├── about/page.tsx # About
├── theme-demo/page.tsx # Live theme switcher
├── layout.tsx # Root layout (SSR critical CSS)
├── layout-shell.tsx # Navbar + Footer wrapper
├── providers.tsx # Theme providers + saved preset restore
├── globals.css # Global styles
├── not-found.tsx # 404
├── error.tsx # Error boundary
└── loading.tsx # Route spinner
├── page.tsx # Homepage (uses SlotRenderer for each section)
├── about/page.tsx # About
├── theme-demo/page.tsx # Live theme switcher
├── homepage-config/page.tsx # Slot variant config page
├── layout.tsx # Root layout (SSR critical CSS)
├── layout-shell.tsx # Navbar + Footer wrapper (slot-driven)
├── providers.tsx # Theme providers + HomepageConfigProvider
├── globals.css # Global styles
├── not-found.tsx # 404
├── error.tsx # Error boundary
└── loading.tsx # Route spinner
components/
├── Navbar.tsx # Sticky navbar, mobile menu, dark mode toggle
├── Footer.tsx # Footer with links
├── Hero.tsx # Hero section
├── FeatureCard.tsx # Feature list items
├── CTASection.tsx # Call-to-action block
├── ThemePresetSwitcher.tsx # Preset picker (persists to localStorage)
└── index.ts # Barrel exports
config/
└── brand.config.ts # Theme preset + brand overrides
├── SlotRenderer.tsx # Resolves slot → variant component at runtime
├── Navbar.tsx # Legacy navbar (still exported for direct use)
├── Footer.tsx # Legacy footer
├── Hero.tsx # Legacy hero
├── FeatureCard.tsx # Legacy feature grid
├── CTASection.tsx # Legacy CTA
├── ThemePresetSwitcher.tsx # Theme preset picker
├── index.ts # Barrel exports
└── variants/ # ← Slot variant components
├── hero/
│ ├── types.ts # HeroData contract
│ ├── HeroCentered.tsx # Large centred headline (default)
│ ├── HeroSplit.tsx # Text left + visual right
│ └── HeroMinimal.tsx # Compact headline
├── features/
│ ├── types.ts # FeaturesData contract
│ ├── FeaturesGrid.tsx # Two-column bordered list (default)
│ ├── FeaturesCards.tsx # Card layout with hover
│ └── FeaturesList.tsx # Vertical stacked list
├── cta/
│ ├── types.ts # CTAData contract
│ ├── CTADefault.tsx # Centred text + buttons (default)
│ ├── CTABanner.tsx # Full-width coloured banner
│ └── CTAMinimal.tsx # Compact inline
├── navbar/
│ ├── types.ts # NavbarData contract
│ ├── NavbarDefault.tsx # Logo left, links right (default)
│ ├── NavbarCentered.tsx # Centred links
│ └── NavbarMinimal.tsx # Logo + dark-mode only
└── footer/
├── types.ts # FooterData contract
├── FooterDefault.tsx # Copyright + links row (default)
├── FooterMinimal.tsx # Single-line copyright
└── FooterColumns.tsx # Multi-column with grouped links
lib/
└── brand-server.ts # Server-side brand/theme utilities
__tests__/ # Vitest test suite
├── brand-server.ts # Server-side brand/theme utilities
├── homepage-config.ts # Slot registry, types, localStorage persistence
└── homepage-config-context.tsx # React context + useHomepageConfig() hook
config/
└── brand.config.ts # Theme preset + brand overrides
__tests__/ # Vitest test suite (68 tests)
```

## Slot Framework

The homepage is built around an extensible **slot framework** that separates data from rendering. Each section of the
page (hero, features, CTA, navbar, footer) is a **slot** with multiple **variant** components. All variants for a slot
accept the same data props — you write your content data once and switch the visual presentation via config.

### Architecture

```
┌──────────────────────┐
lib/homepage-config.ts ─────▶│ SLOT_REGISTRY │
(slot definitions, │ navbar: 3 variants │
variant metadata, │ hero: 3 variants │
localStorage persist) │ features: 3 variants│
│ cta: 3 variants │
│ footer: 3 variants │
└──────────┬───────────┘
lib/homepage-config-context.tsx ────────▶│ React Context
(useHomepageConfig hook) │ (config state + setVariant)
┌──────────▼───────────┐
components/SlotRenderer.tsx ▶│ VARIANT_COMPONENTS │
(<SlotRenderer slot="hero" │ Maps slot+variantId │
data={heroData} />) │ → React component │
└──────────────────────┘
```

### How to use

```tsx
// In page.tsx — data is defined once, rendering driven by config
const HERO_DATA = {
title: 'Welcome',
subtitle: 'Build fast.',
actions: [{ href: '/docs', label: 'Get Started' }],
};

export default function HomePage() {
return <SlotRenderer slot="hero" data={HERO_DATA} />;
}
```

### Config page

Visit `/homepage-config` to switch variant for each slot. Changes are saved to `localStorage` and applied instantly — no
page reload needed. A "Reset to defaults" button restores the original configuration.

### Adding a new variant

1. Create a component in `components/variants/<slot>/` that accepts the slot's data type:

```tsx
// components/variants/hero/HeroGradient.tsx
import type { HeroData } from './types';

export function HeroGradient({ title, subtitle, actions }: HeroData) {
return <section>/* your markup */</section>;
}
```

2. Register it in `components/SlotRenderer.tsx` (`VARIANT_COMPONENTS`):

```tsx
hero: {
centered: HeroCentered,
split: HeroSplit,
minimal: HeroMinimal,
gradient: HeroGradient, // ← add here
},
```

3. Add metadata to `lib/homepage-config.ts` (`SLOT_REGISTRY`):

```tsx
hero: {
variants: [
// ...existing...
{ id: 'gradient', label: 'Gradient', description: 'Bold gradient background hero.' },
],
},
```

The new variant immediately appears in the config page and can be selected.

## Brand Engine Integration

Expand Down
Loading