A production-ready Next.js 14 landing page for Counted, an affordable multi-location inventory tool for small retail and restaurant operators.
| Tool | Purpose |
|---|---|
| Next.js 14 | App Router, server components, file-based routing |
| React 18 | UI components |
| Tailwind CSS 3 | Utility-first styling with custom design tokens |
| lucide-react | Icon library |
| Google Fonts | Instrument Serif (display) + Inter (body via next/font) |
# 1. Install dependencies
npm install
# 2. Start the dev server
npm run dev
# → http://localhost:3000
# 3. Build for production
npm run build
# 4. Start production server
npm startsrc/
├── app/
│ ├── layout.jsx # Root layout — metadata, fonts, global CSS
│ ├── page.jsx # Home page — assembles all sections (server component)
│ └── globals.css # Tailwind base + custom utilities
├── components/
│ ├── Button.jsx # Reusable button (server-safe, no hooks)
│ ├── Badge.jsx # Coloured label chip
│ └── HeroWidget.jsx # 'use client' — interactive live inventory demo
└── sections/
├── Navbar.jsx # 'use client' — scroll detection + mobile menu
├── Hero.jsx # Server — headline + HeroWidget
├── SocialProof.jsx # Server — stats bar + category pills
├── Problem.jsx # Server — the "before" problem cards
├── Features.jsx # Server — 5-feature grid
├── HowItWorks.jsx # Server — 4-step process, sticky left column
├── Testimonials.jsx # Server — 3 customer quote cards
├── Pricing.jsx # 'use client' — per-location pricing with live slider
├── FinalCTA.jsx # Server — dark closing CTA
└── Footer.jsx # Server — full footer with link groups
This project follows Next.js best practices — only components that need browser APIs or React state are marked 'use client':
| Component | Type | Reason |
|---|---|---|
HeroWidget |
Client | useState for live stock adjustment |
Navbar |
Client | useState (mobile menu) + useEffect (scroll) |
Pricing |
Client | useState for location count slider |
| Everything else | Server | Static markup, no interactivity needed |
| Token | Value | Usage |
|---|---|---|
ink |
#0f1117 |
Primary text |
ink-2 |
#3d3f4a |
Secondary text |
ink-3 |
#7a7d8a |
Muted / labels |
brand |
#1a56f5 |
Primary CTA, active states |
brand-light |
#eef2ff |
Brand tint backgrounds |
slate |
#f4f5f7 |
Section / card backgrounds |
border |
#e4e5ea |
Default borders |
All copy is inline in each section file in src/sections/. No separate CMS or content layer.
Create src/app/about/page.jsx — Next.js App Router picks it up automatically at /about.
Replace the href="#pricing" links in Hero.jsx, FinalCTA.jsx, and Pricing.jsx with your auth provider's signup URL (Clerk, Auth0, Better Auth, etc.).
layout.jsx loads Inter via next/font/google (zero layout shift). The display serif (Instrument Serif) is loaded via a <link> tag. Swap either by changing the import.
npx vercel --prodVercel auto-detects Next.js and configures everything.
npm run build # → .next/ build output
npm start # → runs production server on port 3000Or use next export for a fully static build (remove dynamic server features first).
The dashboard requires DATABASE_URL, BETTER_AUTH_SECRET, and NEXT_PUBLIC_BETTER_AUTH_URL. Copy .env.example to .env.local and fill them in:
DATABASE_URL=postgresql://USER:PASSWORD@HOST.neon.tech/neondb?sslmode=require
BETTER_AUTH_SECRET=... # openssl rand -base64 32
NEXT_PUBLIC_BETTER_AUTH_URL=http://localhost:3000
- Server components by default — only 3 components ship JS to the client
next/font— Inter is self-hosted, zero FOUT- Images — add product screenshots via
next/imagefor automatic optimisation - Core Web Vitals — no layout shift sources; all animations respect
prefers-reduced-motion