feat: project setup & repository (Feature 1)
- Next.js 16.1.6 with App Router, TypeScript strict, Tailwind CSS v4 - ESLint 9, Prettier with Tailwind class sorting plugin - Husky + lint-staged pre-commit hooks - Multi-stage Dockerfile (dev/build/production) with pnpm + Node 20 - docker-compose.yml with hot reload + PostgreSQL 17 - src/ directory structure (components, lib, hooks, types, payload) - .env.example template with all required variables - standalone output mode for production Docker builds Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
160
.claude/commands/design-guidelines.md
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
---
|
||||
name: design-guidelines
|
||||
description: Generate, update, or audit frontend design guidelines for Axil Accountants. Use this skill to create/maintain the design system documentation, review component consistency, or produce a design guidelines document.
|
||||
---
|
||||
|
||||
You are a senior frontend design systems engineer working on **Axil Accountants** — a premium British accounting firm website.
|
||||
|
||||
## Your Role
|
||||
|
||||
When invoked, you produce or update the **Frontend Design Guidelines** document for the project. This document is the single source of truth for all visual and interaction decisions on the site.
|
||||
|
||||
## Project Context (Always Apply)
|
||||
|
||||
**Stack:** Next.js 15 · TypeScript · Tailwind CSS v4 · Framer Motion · GSAP · Three.js / R3F
|
||||
|
||||
**Design Philosophy:**
|
||||
|
||||
- Premium, airy, light — predominantly white/near-white backgrounds
|
||||
- Sage green as an **accent**, not the dominant colour
|
||||
- Generous whitespace — every element has room to breathe
|
||||
- Glassmorphism cards for interactive surfaces
|
||||
- Soft shadows only — no harsh drop shadows
|
||||
- Every animation has a purpose — no decoration for its own sake
|
||||
- British English throughout all copy
|
||||
|
||||
---
|
||||
|
||||
## Design Guidelines Structure
|
||||
|
||||
When asked to generate or update design guidelines, produce a document covering:
|
||||
|
||||
### 1. Colour System
|
||||
|
||||
- Full palette with hex values and usage rules
|
||||
- Which colours are safe on dark backgrounds vs light
|
||||
- Colour combinations to **avoid** (contrast failures)
|
||||
- Overlay and tint values for interactive states (hover, focus, pressed)
|
||||
- Green tints: `#6BAF7D`, `#A8C5A0`, `#F4FAF5`, `#2E7D52`, `#1A2E1F`
|
||||
|
||||
### 2. Typography Rules
|
||||
|
||||
- Font families and when to use each (Satoshi for display, Inter for body, DM Mono for numbers)
|
||||
- Type scale: specific sizes for H1–H6, body, small, caption
|
||||
- Line height and letter spacing rules per scale
|
||||
- Forbidden: Arial, Roboto, system-ui as display fonts
|
||||
- Max line length: 70 characters for body text
|
||||
|
||||
### 3. Spacing & Layout
|
||||
|
||||
- 8px base grid — all spacing multiples of 4px or 8px
|
||||
- Section padding rules (desktop vs mobile)
|
||||
- Container max-width (1440px) and gutter rules
|
||||
- Card internal padding standards
|
||||
|
||||
### 4. Component Patterns
|
||||
|
||||
For each component, specify:
|
||||
|
||||
- Default state
|
||||
- Hover / focus state
|
||||
- Active / pressed state
|
||||
- Disabled state
|
||||
- Dark background variant
|
||||
- Mobile variant
|
||||
|
||||
**Components to document:**
|
||||
|
||||
- Button (primary, secondary, ghost)
|
||||
- Card (glass, solid, feature)
|
||||
- Navigation (desktop, mobile, dropdown)
|
||||
- Form fields (input, select, checkbox, textarea)
|
||||
- Badge / Tag
|
||||
- Testimonial card
|
||||
- Blog card
|
||||
- Service card
|
||||
- Modal / Overlay
|
||||
- Accordion / FAQ
|
||||
|
||||
### 5. Animation Principles
|
||||
|
||||
- **Timing functions:** ease-out for entrances, ease-in for exits, ease-in-out for loops
|
||||
- **Duration rules:**
|
||||
- Micro-interactions (button hover): 150–200ms
|
||||
- Element reveals (fade in): 300–500ms
|
||||
- Page transitions: 400–600ms
|
||||
- 3D loop animations: 8–20s
|
||||
- **Stagger:** 80–120ms between sibling elements
|
||||
- **ScrollTrigger start:** `top 80%` (element enters when 80% down viewport)
|
||||
- **`prefers-reduced-motion`:** all animations must be wrapped in a media query check — skip or reduce motion for users who request it
|
||||
- GSAP for scroll-driven + complex sequences
|
||||
- Framer Motion for page transitions + React state-driven animations
|
||||
- CSS transitions for simple hover states
|
||||
|
||||
### 6. Iconography
|
||||
|
||||
- Style: line icons, 1.5px stroke, rounded caps
|
||||
- Size: 16px (small), 20px (default), 24px (large), 32px (feature)
|
||||
- Colour: inherits text colour or explicit sage green
|
||||
- Never use filled icons mixed with line icons in the same context
|
||||
- Custom SVG components — no icon font libraries
|
||||
|
||||
### 7. Imagery Guidelines
|
||||
|
||||
- Photography: real people, authentic UK business settings, natural light
|
||||
- Never use: stock photo clichés, handshake photos, generic office scenes
|
||||
- All images: `next/image` with correct `alt` text
|
||||
- Cover images: 16:9 ratio for blog, 4:3 for cards
|
||||
- Hero images: full-width, overlaid with dark tint if text is on top
|
||||
- Alt text: descriptive, contextual, British English
|
||||
|
||||
### 8. Accessibility Standards
|
||||
|
||||
- All text: WCAG AA (4.5:1 body, 3:1 large text) minimum
|
||||
- Focus styles: `ring-2 ring-sage ring-offset-2` — never `outline: none` without replacement
|
||||
- Interactive elements: minimum 44×44px touch target
|
||||
- Form fields: always have a visible `<label>`
|
||||
- Modals: focus trap required, Escape key closes
|
||||
- Keyboard: all functionality available without mouse
|
||||
|
||||
### 9. Responsive Breakpoints
|
||||
|
||||
| Name | Min width | Tailwind prefix |
|
||||
| ------- | --------- | --------------- |
|
||||
| Mobile | 0px | (default) |
|
||||
| Small | 640px | `sm:` |
|
||||
| Tablet | 768px | `md:` |
|
||||
| Desktop | 1024px | `lg:` |
|
||||
| Wide | 1280px | `xl:` |
|
||||
| Max | 1440px | `2xl:` |
|
||||
|
||||
Mobile-first: always write base styles for mobile, then override at breakpoints.
|
||||
|
||||
### 10. Do / Don't Checklist
|
||||
|
||||
**Do:**
|
||||
|
||||
- Use CSS variables for all colours
|
||||
- Use `next/image` for all images
|
||||
- Wrap all animations in `prefers-reduced-motion` check
|
||||
- Use `font-display` for headlines, `font-sans` for body
|
||||
- Apply `focus-visible:` for keyboard styles, not `focus:`
|
||||
|
||||
**Don't:**
|
||||
|
||||
- Hardcode hex values in JSX (use Tailwind tokens)
|
||||
- Use `!important` in CSS
|
||||
- Nest more than 3 levels of layout components
|
||||
- Use `px` for font sizes (use `rem` via Tailwind scale)
|
||||
- Animate `width`, `height`, or `top/left` (use `transform` instead)
|
||||
|
||||
---
|
||||
|
||||
## Output Format
|
||||
|
||||
When generating or updating guidelines:
|
||||
|
||||
1. Output the full guidelines document in Markdown
|
||||
2. Include code examples for each pattern (Tailwind class strings or JSX)
|
||||
3. Flag any existing components that violate guidelines
|
||||
4. Suggest `CLAUDE.md` entries to enforce the most critical rules automatically
|
||||
99
.claude/commands/tailwind-design-system.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
name: tailwind-design-system
|
||||
description: Generate, audit, or extend the Tailwind CSS design system for Axil Accountants. Use this skill when working on design tokens, component styles, theme configuration, or Tailwind utility patterns.
|
||||
---
|
||||
|
||||
You are a Tailwind CSS design system expert working on the **Axil Accountants** website.
|
||||
|
||||
## Project Design System Context
|
||||
|
||||
**Brand colours:**
|
||||
| Token | Hex | Tailwind class |
|
||||
|---|---|---|
|
||||
| Primary (Sage Green) | `#6BAF7D` | `sage` |
|
||||
| Primary Light (Soft Mint) | `#A8C5A0` | `sage-light` |
|
||||
| Background (Near-White) | `#F4FAF5` | `mint` |
|
||||
| Accent / Dark (Deep Forest) | `#2E7D52` | `forest` |
|
||||
| Text Dark (Charcoal) | `#1A2E1F` | `charcoal` |
|
||||
| Text Muted (Slate Grey) | `#6B7280` | `muted` |
|
||||
| Dark BG (Forest Night) | `#1A2E1F` | `forest-dark` |
|
||||
|
||||
**Typography scale:**
|
||||
|
||||
- Display / H1–H2: `font-display` (Satoshi) — `text-5xl`–`text-7xl`, `font-bold`
|
||||
- H3–H4: `font-display` — `text-2xl`–`text-4xl`, `font-semibold`
|
||||
- Body: `font-sans` (Inter) — `text-base`–`text-lg`, `font-normal`
|
||||
- Numbers / Stats: `font-mono` (DM Mono) — `text-4xl`–`text-6xl`, `font-bold`
|
||||
|
||||
**Spacing & layout:**
|
||||
|
||||
- Section vertical padding: `py-20 md:py-32`
|
||||
- Container: `max-w-[1440px] mx-auto px-4 sm:px-6 lg:px-8`
|
||||
- Card border radius: `rounded-2xl` (16px)
|
||||
- Hero card radius: `rounded-3xl` (24px)
|
||||
- Button radius: `rounded-full` (pill)
|
||||
|
||||
**Shadows (custom):**
|
||||
|
||||
- Card: `shadow-[0_4px_24px_rgba(107,175,125,0.08)]`
|
||||
- Card hover: `shadow-[0_8px_40px_rgba(107,175,125,0.18)]`
|
||||
- Button: `shadow-[0_2px_12px_rgba(46,125,82,0.25)]`
|
||||
|
||||
**Glass morphism pattern:**
|
||||
|
||||
```css
|
||||
backdrop-blur-md bg-white/70 border border-sage/20 rounded-2xl
|
||||
```
|
||||
|
||||
## What You Can Do
|
||||
|
||||
When the user asks to:
|
||||
|
||||
### 1. Generate / extend `tailwind.config.ts`
|
||||
|
||||
Produce a fully typed Tailwind v4 config with all Axil tokens registered as CSS variables and Tailwind utilities. Include:
|
||||
|
||||
- Custom `colors` (sage, forest, mint, charcoal, muted)
|
||||
- Custom `fontFamily` (display → Satoshi, sans → Inter, mono → DM Mono)
|
||||
- Custom `borderRadius` (card, hero, pill)
|
||||
- Custom `boxShadow` (card, card-hover, button, glow)
|
||||
- Custom `animation` and `keyframes` (float, pulse-glow, draw-line)
|
||||
|
||||
### 2. Audit existing component styles
|
||||
|
||||
Review a component for:
|
||||
|
||||
- Consistency with the Axil design system
|
||||
- Correct use of design tokens (no hardcoded hex values)
|
||||
- WCAG AA contrast compliance
|
||||
- Mobile-first responsive patterns
|
||||
- Proper use of `transition` and `hover:` states
|
||||
|
||||
### 3. Create utility class patterns
|
||||
|
||||
Define reusable Tailwind patterns for:
|
||||
|
||||
- `.btn-primary`, `.btn-secondary`, `.btn-ghost`
|
||||
- `.card-glass`, `.card-solid`
|
||||
- `.section-dark`, `.section-light`
|
||||
- `.heading-display`, `.heading-section`
|
||||
- `.tag-badge`
|
||||
|
||||
### 4. Generate component styles
|
||||
|
||||
When asked to style a specific component, output:
|
||||
|
||||
- Full Tailwind class strings (no inline CSS)
|
||||
- Responsive variants (`sm:`, `md:`, `lg:`)
|
||||
- State variants (`hover:`, `focus:`, `active:`, `disabled:`)
|
||||
- Dark-section variants (styles for when component sits on `#1A2E1F` background)
|
||||
|
||||
## Output Format
|
||||
|
||||
Always output:
|
||||
|
||||
1. The Tailwind classes / config code (in a code block)
|
||||
2. A brief note on design decisions made
|
||||
3. Any accessibility considerations
|
||||
|
||||
Never use arbitrary values when a design token exists. Prefer `text-sage` over `text-[#6BAF7D]`.
|
||||
6
.claude/settings.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"enabledPlugins": {
|
||||
"frontend-design@claude-code-plugins": false,
|
||||
"feature-dev@claude-code-plugins": false
|
||||
}
|
||||
}
|
||||
23
.claude/settings.local.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"WebFetch(domain:axil1.local)",
|
||||
"Bash(claude plugins install:*)",
|
||||
"Bash(pnpm --version:*)",
|
||||
"Bash(node --version:*)",
|
||||
"Bash(npx --version:*)",
|
||||
"Bash(docker:*)",
|
||||
"Bash(docker compose:*)",
|
||||
"Bash(git init:*)",
|
||||
"Bash(git remote add:*)",
|
||||
"WebFetch(domain:medium.com)",
|
||||
"WebFetch(domain:htalbot.dev)",
|
||||
"WebFetch(domain:charlie2code.com)",
|
||||
"Bash(chmod:*)",
|
||||
"Bash(for dir in src/components/ui src/components/layout src/components/sections src/components/three src/components/cms src/lib src/hooks src/types src/payload)",
|
||||
"Bash(do touch \"$dir/.gitkeep\")",
|
||||
"Bash(done)",
|
||||
"Bash(git add:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
10
.dockerignore
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
node_modules
|
||||
.next
|
||||
.git
|
||||
.env.local
|
||||
.DS_Store
|
||||
Logo
|
||||
Concept.md
|
||||
implementation_plan.md
|
||||
docs
|
||||
*.docx
|
||||
21
.env.example
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Database (Neon PostgreSQL)
|
||||
DATABASE_URI=postgresql://user:password@localhost:5432/axil
|
||||
|
||||
# Payload CMS
|
||||
PAYLOAD_SECRET=your-payload-secret-min-32-chars-here
|
||||
|
||||
# Email (Resend)
|
||||
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# Site
|
||||
NEXT_PUBLIC_SITE_URL=http://localhost:3000
|
||||
|
||||
# Media Storage (Uploadthing)
|
||||
UPLOADTHING_SECRET=sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
UPLOADTHING_APP_ID=your-app-id
|
||||
|
||||
# AI Chat Bot (optional)
|
||||
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
|
||||
# Error Monitoring
|
||||
SENTRY_DSN=https://xxxx@sentry.io/xxxx
|
||||
43
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnpm-store
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
1
.husky/pre-commit
Executable file
|
|
@ -0,0 +1 @@
|
|||
pnpm exec lint-staged
|
||||
4
.lintstagedrc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
|
||||
"*.{json,md,css}": ["prettier --write"]
|
||||
}
|
||||
4
.prettierignore
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
node_modules
|
||||
.next
|
||||
.pnpm-store
|
||||
pnpm-lock.yaml
|
||||
8
.prettierrc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
}
|
||||
620
Concept.md
Normal file
|
|
@ -0,0 +1,620 @@
|
|||
# Axil Accountants — Website Concept
|
||||
|
||||
> **Language:** All website content is in British English.
|
||||
> **Status:** Concept v1.0 — February 2026
|
||||
> **Type:** Modern marketing website with headless CMS
|
||||
|
||||
---
|
||||
|
||||
## 1. Project Overview
|
||||
|
||||
**Client:** Axil Accountants
|
||||
**Goal:** A high-converting, premium marketing website that positions Axil Accountants as the go-to accounting firm for sole traders, limited companies, and startups in the UK. The site functions as a professional sales funnel — driving visitors to book a free consultation.
|
||||
|
||||
**Core Principle:** No pricing on the site. Every CTA leads to a consultation request. The funnel is designed to build trust first, then convert.
|
||||
|
||||
---
|
||||
|
||||
## 2. Brand & Visual Identity
|
||||
|
||||
### Logo
|
||||
|
||||
- Existing logo — provided by client
|
||||
- Logo used in header (light version on dark backgrounds, dark version on white)
|
||||
|
||||
### Colour Palette
|
||||
|
||||
| Role | Colour | Hex |
|
||||
| ------------- | --------------- | ------------------------ |
|
||||
| Primary | Sage Green | `#6BAF7D` |
|
||||
| Primary Light | Soft Mint | `#A8C5A0` |
|
||||
| Background | Near-White | `#F4FAF5` |
|
||||
| Accent / Dark | Deep Forest | `#2E7D52` |
|
||||
| Text Dark | Charcoal | `#1A2E1F` |
|
||||
| Text Muted | Slate Grey | `#6B7280` |
|
||||
| White | Pure White | `#FFFFFF` |
|
||||
| Overlay | Dark Green Tint | `rgba(30, 60, 40, 0.85)` |
|
||||
|
||||
### Typography
|
||||
|
||||
- **Headlines:** `Satoshi` or `Cabinet Grotesk` — geometric, modern, confident
|
||||
- **Body:** `Inter` — clean, readable, professional
|
||||
- **Accent / Numbers:** `DM Mono` — for stats, figures, financial data
|
||||
|
||||
### Design Language
|
||||
|
||||
- Light, airy, predominantly white/near-white backgrounds
|
||||
- Sage green as accent — not dominant, used for highlights, borders, CTAs
|
||||
- Generous whitespace — premium feel
|
||||
- Subtle grain texture overlays on hero sections
|
||||
- Glassmorphism cards (frosted glass with green tint) for service blocks
|
||||
- Soft shadows — no harsh drop shadows
|
||||
- Rounded corners: `16px` standard, `24px` hero cards, `999px` buttons
|
||||
|
||||
---
|
||||
|
||||
## 3. Technology Stack
|
||||
|
||||
### Frontend
|
||||
|
||||
| Technology | Purpose |
|
||||
| -------------------------------- | ---------------------------------------- |
|
||||
| **Next.js 15** (App Router) | Core framework — SSR, SSG, ISR |
|
||||
| **TypeScript** | Type safety across the entire codebase |
|
||||
| **Tailwind CSS v4** | Utility-first styling |
|
||||
| **Framer Motion** | Page transitions, element animations |
|
||||
| **GSAP + ScrollTrigger** | Scroll-driven animations, reveal effects |
|
||||
| **Three.js / React Three Fiber** | 3D hero scene (globe, particles) |
|
||||
| **Lenis** | Smooth scrolling |
|
||||
|
||||
### CMS & Backend
|
||||
|
||||
| Technology | Purpose |
|
||||
| ----------------------- | ------------------------------------------------------ |
|
||||
| **Payload CMS 3** | Headless CMS — runs natively inside Next.js |
|
||||
| **PostgreSQL** | Primary database (via Neon or Supabase) |
|
||||
| **Payload Admin Panel** | Full content management UI |
|
||||
| **Resend** | Transactional emails (form submissions, notifications) |
|
||||
|
||||
### Infrastructure
|
||||
|
||||
| Technology | Purpose |
|
||||
| ----------------------------- | ----------------------------------- |
|
||||
| **Vercel** | Hosting & deployment (Edge Network) |
|
||||
| **Cloudinary or Uploadthing** | Image/media management via CMS |
|
||||
| **Sentry** | Error monitoring |
|
||||
|
||||
### Why This Stack
|
||||
|
||||
- **Payload CMS** runs inside the same Next.js codebase — no separate server needed, zero friction
|
||||
- Admin panel is fully customisable and extensible
|
||||
- Webhooks, custom fields, form builders all built-in
|
||||
- Performance: Lighthouse score target 95+
|
||||
|
||||
---
|
||||
|
||||
## 4. Site Architecture
|
||||
|
||||
### Pages
|
||||
|
||||
```
|
||||
/ → Home (main funnel page)
|
||||
/services → Services overview
|
||||
/services/bookkeeping → Bookkeeping detail page
|
||||
/services/tax-returns → Self Assessment & Corporation Tax
|
||||
/services/payroll → Payroll Management
|
||||
/services/vat-returns → VAT Returns
|
||||
/about → About the company & team
|
||||
/blog → Blog index
|
||||
/blog/[slug] → Individual blog post
|
||||
/contact → Contact page (consultation form)
|
||||
/privacy-policy → Legal
|
||||
/cookie-policy → Legal
|
||||
```
|
||||
|
||||
### Navigation Structure
|
||||
|
||||
```
|
||||
Logo | Services ▾ | About | Blog | Contact [Book a Free Consultation →]
|
||||
```
|
||||
|
||||
- Sticky header with blur backdrop on scroll
|
||||
- Mobile: hamburger menu with full-screen overlay, animated slide-in
|
||||
- Services dropdown with icon cards for each service
|
||||
|
||||
---
|
||||
|
||||
## 5. Home Page — Sales Funnel Design
|
||||
|
||||
The homepage is structured as a sequential sales funnel. Each section is designed to move the visitor one step closer to booking a consultation.
|
||||
|
||||
---
|
||||
|
||||
### Section 1 — Hero (Above the Fold)
|
||||
|
||||
**Purpose:** Capture attention, establish premium positioning, deliver core value proposition.
|
||||
|
||||
**Layout:**
|
||||
|
||||
- Full-viewport height
|
||||
- Split layout: left — text content; right — 3D animated scene
|
||||
|
||||
**3D Scene (Three.js / React Three Fiber):**
|
||||
|
||||
- Interactive 3D globe with soft green particle network
|
||||
- Globe rotates slowly, responds to mouse/cursor movement (parallax)
|
||||
- Floating financial data nodes (dots connected by lines, like a network graph)
|
||||
- Subtle green particle field in the background
|
||||
- On mobile: simplified 2D animated version (performance-first)
|
||||
|
||||
**Content:**
|
||||
|
||||
```
|
||||
[EYEBROW TAG] Trusted by 500+ UK Businesses
|
||||
|
||||
[HEADLINE H1]
|
||||
Smart Accounting
|
||||
for Growing
|
||||
British Businesses
|
||||
|
||||
[SUBHEADLINE]
|
||||
From sole traders to limited companies — Axil Accountants handles
|
||||
your numbers so you can focus on what you do best.
|
||||
|
||||
[CTA PRIMARY] → Book a Free Consultation
|
||||
[CTA SECONDARY] → See Our Services
|
||||
|
||||
[TRUST STRIP] ★ 4.9 Google Rating | ICAEW Certified | 500+ Clients Served
|
||||
```
|
||||
|
||||
**Animation:**
|
||||
|
||||
- Headline words appear with staggered slide-up (GSAP)
|
||||
- CTAs fade in after headline
|
||||
- Trust strip slides in from bottom
|
||||
- 3D globe loads with scale-in and rotation ease
|
||||
|
||||
---
|
||||
|
||||
### Section 2 — Pain Points / "We Understand"
|
||||
|
||||
**Purpose:** Create empathy. Show we understand client problems.
|
||||
|
||||
**Layout:** Full-width section, dark green background (`#1A2E1F`), white text
|
||||
|
||||
**Content:**
|
||||
|
||||
```
|
||||
[HEADLINE]
|
||||
Running a business is hard enough.
|
||||
Tax deadlines shouldn't keep you up at night.
|
||||
|
||||
[SUBTEXT]
|
||||
Whether you're a freelancer juggling invoices or a director managing
|
||||
payroll and VAT — the financial admin never stops.
|
||||
|
||||
[3-column pain point cards — frosted glass on dark green]
|
||||
📋 Missed deadlines & HMRC penalties
|
||||
🧮 Confused by tax rules that keep changing
|
||||
⏰ Hours wasted on bookkeeping instead of growing your business
|
||||
```
|
||||
|
||||
**Animation:**
|
||||
|
||||
- Cards appear on scroll with staggered reveal (ScrollTrigger)
|
||||
- Section uses subtle parallax background movement
|
||||
|
||||
---
|
||||
|
||||
### Section 3 — Services Overview
|
||||
|
||||
**Purpose:** Present services clearly. Each service links to its own detail page.
|
||||
|
||||
**Layout:** Light background, 2×2 grid of service cards (desktop), vertical stack (mobile)
|
||||
|
||||
**Services:**
|
||||
|
||||
1. **Bookkeeping** — Accurate, up-to-date records. Monthly reports. Peace of mind.
|
||||
2. **Tax Returns** — Self Assessment & Corporation Tax prepared and filed on time, every time.
|
||||
3. **Payroll** — Compliant payroll for your team. RTI submissions to HMRC. Payslips handled.
|
||||
4. **VAT Returns** — MTD-compliant VAT preparation, filing, and advice.
|
||||
|
||||
**Card Design:**
|
||||
|
||||
- Frosted glass with sage green border
|
||||
- Icon (custom SVG, line-style)
|
||||
- Service name + short description
|
||||
- "Learn More →" link
|
||||
- Hover: subtle lift effect + green glow border
|
||||
|
||||
**CTA below grid:**
|
||||
|
||||
```
|
||||
Not sure which service you need?
|
||||
[→ Let's Talk — Book a Free Consultation]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Section 4 — Why Choose Axil Accountants
|
||||
|
||||
**Purpose:** Build trust and differentiate from competitors.
|
||||
|
||||
**Layout:** Alternating left/right layout with animated stat counters
|
||||
|
||||
**Content:**
|
||||
|
||||
```
|
||||
[HEADLINE] Why Businesses Choose Axil
|
||||
|
||||
[STAT COUNTERS — animate on scroll]
|
||||
500+ Businesses Served
|
||||
98% Client Retention Rate
|
||||
£2M+ Tax Saved for Our Clients
|
||||
12+ Years of Experience
|
||||
|
||||
[3 USP blocks]
|
||||
|
||||
✓ ICAEW & ACCA Qualified
|
||||
Our accountants hold the UK's most respected professional qualifications.
|
||||
|
||||
✓ Fixed Monthly Engagement
|
||||
No surprise bills. You always know what you're paying for.
|
||||
|
||||
✓ Dedicated Account Manager
|
||||
One point of contact who knows your business inside-out.
|
||||
|
||||
✓ Cloud-Based & Paper-Free
|
||||
We work with Xero, QuickBooks, and FreeAgent — wherever you are.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Section 5 — Testimonials / Social Proof
|
||||
|
||||
**Purpose:** Validate trust with real client voices.
|
||||
|
||||
**Layout:** Carousel / marquee with client cards
|
||||
|
||||
**Sources:**
|
||||
|
||||
- Google Reviews (embedded widget or scraped/cached in CMS)
|
||||
- Manual reviews added via Payload CMS admin panel
|
||||
- ICAEW / ACCA badge display
|
||||
|
||||
**Card Design:**
|
||||
|
||||
- Client name + business type
|
||||
- Star rating (5 stars)
|
||||
- Quote (2–3 sentences)
|
||||
- Optional: client photo or avatar
|
||||
|
||||
**CTA below:**
|
||||
|
||||
```
|
||||
Join hundreds of satisfied UK businesses.
|
||||
[→ Book Your Free Consultation Today]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Section 6 — Who We Work With
|
||||
|
||||
**Purpose:** Help visitors self-identify. Reinforces audience segmentation.
|
||||
|
||||
**Layout:** 3 illustrated cards with icons
|
||||
|
||||
```
|
||||
[Sole Traders] [Limited Companies] [Startups]
|
||||
Self-employed? Running an Ltd? Just launched?
|
||||
We handle your We manage your We'll set you up
|
||||
Self Assessment, annual accounts, right from day one —
|
||||
bookkeeping, and payroll, VAT, and HMRC registration,
|
||||
more. Corp Tax. bookkeeping, payroll.
|
||||
|
||||
[→ Learn More] [→ Learn More] [→ Learn More]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Section 7 — How It Works
|
||||
|
||||
**Purpose:** Remove friction. Show how easy it is to get started.
|
||||
|
||||
**Layout:** Horizontal step-by-step process (3 steps), animated connecting line
|
||||
|
||||
```
|
||||
Step 1 → Step 2 → Step 3
|
||||
Book a Free We Review You Focus on
|
||||
Consultation Your Needs Your Business
|
||||
|
||||
15-minute call, We propose a We handle everything
|
||||
no commitment. tailored plan. — you get reports.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Section 8 — Blog Preview
|
||||
|
||||
**Purpose:** SEO value + content authority. Show expertise.
|
||||
|
||||
**Layout:** 3 latest blog post cards in a row
|
||||
|
||||
- Managed entirely through Payload CMS
|
||||
- Cards: cover image, category tag, headline, excerpt, date, read time
|
||||
- CTA: "Visit Our Blog →"
|
||||
|
||||
---
|
||||
|
||||
### Section 9 — Final CTA Section
|
||||
|
||||
**Purpose:** Last chance to convert before footer. High-urgency design.
|
||||
|
||||
**Layout:** Full-width, deep green background, centred content
|
||||
|
||||
```
|
||||
[HEADLINE]
|
||||
Ready to take the stress out of your finances?
|
||||
|
||||
[SUBHEADLINE]
|
||||
Book a free 15-minute consultation with our team today.
|
||||
No commitment. No jargon. Just clear, honest advice.
|
||||
|
||||
[CTA BUTTON — large, white on green]
|
||||
→ Book a Free Consultation
|
||||
|
||||
[Trust reassurance below]
|
||||
★ 4.9/5 on Google · ICAEW Certified · No lock-in contracts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Footer
|
||||
|
||||
**4-column layout:**
|
||||
|
||||
1. Logo + tagline + social icons (LinkedIn, Facebook, Instagram)
|
||||
2. Services links
|
||||
3. Company links (About, Blog, Contact, Careers)
|
||||
4. Contact info (address, phone, email) + ICAEW/ACCA badge
|
||||
|
||||
**Bottom bar:** Copyright · Privacy Policy · Cookie Policy
|
||||
|
||||
---
|
||||
|
||||
## 6. Individual Service Pages
|
||||
|
||||
Each service has a dedicated landing page, structured as a mini-funnel:
|
||||
|
||||
1. **Hero** — Service name, bold headline, CTA ("Get a Quote" → consultation form)
|
||||
2. **What's Included** — Bullet list of deliverables
|
||||
3. **Who It's For** — Targeted at sole traders / Ltd / startups as relevant
|
||||
4. **How It Works** — 3-step process specific to this service
|
||||
5. **FAQ** — 5–7 questions, managed in CMS
|
||||
6. **Testimonials** — Filtered by service tag from CMS
|
||||
7. **CTA** — Book consultation
|
||||
|
||||
---
|
||||
|
||||
## 7. About Page
|
||||
|
||||
**Sections:**
|
||||
|
||||
1. **Hero** — Company story headline + team photo
|
||||
2. **Our Story** — Founding, mission, values
|
||||
3. **Team** — Staff profiles (photo, name, role, qualification) — managed in CMS
|
||||
4. **Our Values** — 4 core values (integrity, clarity, reliability, growth)
|
||||
5. **Certifications** — ICAEW / ACCA logos + descriptions
|
||||
6. **CTA** — Meet us for a free consultation
|
||||
|
||||
---
|
||||
|
||||
## 8. Blog
|
||||
|
||||
**Features:**
|
||||
|
||||
- Blog index with search + category filter
|
||||
- Articles managed entirely in Payload CMS
|
||||
- Rich text editor with image upload, code blocks, pull quotes
|
||||
- Author, publish date, reading time, category tags
|
||||
- Open Graph / SEO metadata per post (editable in CMS)
|
||||
- Related posts section on each article
|
||||
|
||||
**Content Strategy:** Articles targeting UK accounting SEO terms (e.g., "How to file a Self Assessment tax return", "What expenses can I claim as a sole trader UK", "MTD for VAT explained")
|
||||
|
||||
---
|
||||
|
||||
## 9. CMS Admin Panel (Payload CMS)
|
||||
|
||||
The Payload CMS admin panel is available at `/admin` and allows the client to manage all website content without touching code.
|
||||
|
||||
### Collections (Manageable Content)
|
||||
|
||||
| Collection | What you can manage |
|
||||
| ----------------- | ----------------------------------------------- |
|
||||
| **Pages** | Edit text, headings, CTAs on any page |
|
||||
| **Services** | Add/edit service pages, descriptions, FAQs |
|
||||
| **Blog Posts** | Create, edit, schedule, publish articles |
|
||||
| **Team Members** | Add/remove staff profiles, photos, bios |
|
||||
| **Testimonials** | Add client reviews manually |
|
||||
| **FAQs** | Global FAQ entries, tagged by service |
|
||||
| **Media Library** | Upload images, PDFs, videos |
|
||||
| **Forms** | Create contact forms, newsletter sign-ups |
|
||||
| **Navigation** | Edit menu items, dropdown links |
|
||||
| **Footer** | Edit footer links, contact details, social URLs |
|
||||
| **Site Settings** | Global settings — phone, email, address, logo |
|
||||
|
||||
### Form Builder
|
||||
|
||||
- Drag-and-drop form fields (text, email, phone, dropdown, checkbox, file upload)
|
||||
- Per-form settings:
|
||||
- **Email notification** — send submissions to any email address
|
||||
- **Webhook** — send payload to external URL (CRM, Slack, Zapier, etc.)
|
||||
- **Redirect** — after submission, redirect to thank-you page
|
||||
- **Confirmation message** — custom success message shown to user
|
||||
- All form submissions stored in CMS admin panel
|
||||
|
||||
### Integration Settings (Admin-Configurable)
|
||||
|
||||
- **Calendly URL** — booking widget embed URL
|
||||
- **Google Analytics ID**
|
||||
- **Google Tag Manager ID**
|
||||
- **Facebook Pixel ID**
|
||||
- **Tawk.to / chat widget** — paste widget code in admin
|
||||
- **Webhook endpoints** — add named webhooks, assign to forms
|
||||
- **SMTP / Email provider** — configure Resend API key
|
||||
- **Social media URLs** — LinkedIn, Facebook, Instagram
|
||||
|
||||
---
|
||||
|
||||
## 10. Chat Bot
|
||||
|
||||
**Recommended approach:** Configurable in admin panel — client can activate one of:
|
||||
|
||||
### Option A — AI Chat (recommended)
|
||||
|
||||
- Custom-built chat widget powered by OpenAI GPT-4o or Claude API
|
||||
- Trained on company services, FAQs, pricing guidance
|
||||
- Collects visitor name + email before chat
|
||||
- Escalates to human (email notification) when it cannot answer
|
||||
- Conversation logs stored in CMS / sent to email
|
||||
|
||||
### Option B — Live Chat Widget
|
||||
|
||||
- Tawk.to embed — free, supports operators going online/offline
|
||||
- Chat widget code paste-able in admin settings
|
||||
|
||||
### Option C — Lead Capture Bot
|
||||
|
||||
- Scripted flow: asks 3–4 qualifying questions
|
||||
- Collects name, email, business type, main concern
|
||||
- Sends lead to email + optional webhook to CRM
|
||||
|
||||
**Admin can switch between options or disable chat entirely from settings panel.**
|
||||
|
||||
---
|
||||
|
||||
## 11. Animations & Visual Effects
|
||||
|
||||
### Hero — 3D Scene (Three.js / R3F)
|
||||
|
||||
- Slowly rotating 3D sphere with dot-matrix surface
|
||||
- Particle network floats above globe — financial data visualisation metaphor
|
||||
- Mouse parallax: globe and particles shift slightly with cursor movement
|
||||
- Colour palette: sage green particles on near-white background
|
||||
- Performance: reduced particle count on mobile, falls back gracefully
|
||||
|
||||
### Scroll Animations (GSAP + ScrollTrigger)
|
||||
|
||||
- Headlines: word-by-word or line-by-line slide-up reveal
|
||||
- Section entries: fade-in + translate-up on scroll
|
||||
- Stat counters: number count-up animation when entering viewport
|
||||
- Service cards: staggered reveal with 100ms delay between cards
|
||||
- "How It Works" timeline: animated line draws left-to-right as user scrolls
|
||||
|
||||
### Page Transitions (Framer Motion)
|
||||
|
||||
- Page-level: smooth fade + slight vertical slide between routes
|
||||
- Overlay: green full-screen wipe on navigation (optional — client preference)
|
||||
|
||||
### Micro-Interactions
|
||||
|
||||
- Buttons: subtle scale + colour shift on hover
|
||||
- Nav links: underline slides in from left on hover
|
||||
- Cards: lift + border glow on hover
|
||||
- Form fields: smooth focus state with green border transition
|
||||
- CTA button: gentle pulse animation when idle (draws attention)
|
||||
|
||||
### Smooth Scrolling
|
||||
|
||||
- Lenis for buttery-smooth scroll physics across all sections
|
||||
|
||||
---
|
||||
|
||||
## 12. Performance & SEO
|
||||
|
||||
### Performance Targets
|
||||
|
||||
- Lighthouse Performance: **95+**
|
||||
- First Contentful Paint: **< 1.2s**
|
||||
- Largest Contentful Paint: **< 2.5s**
|
||||
- Cumulative Layout Shift: **< 0.1**
|
||||
|
||||
### SEO
|
||||
|
||||
- Next.js App Router with built-in metadata API
|
||||
- Per-page SEO title, description, Open Graph image — all editable in CMS
|
||||
- Structured data (JSON-LD): LocalBusiness, AccountingService, FAQPage schemas
|
||||
- Sitemap auto-generated (`/sitemap.xml`)
|
||||
- Robots.txt configurable
|
||||
- Blog articles optimised for UK accounting search terms
|
||||
|
||||
### Accessibility
|
||||
|
||||
- WCAG 2.1 AA compliant
|
||||
- Keyboard navigation throughout
|
||||
- Proper ARIA labels on interactive elements
|
||||
- Sufficient colour contrast for all text
|
||||
|
||||
---
|
||||
|
||||
## 13. Responsive Design
|
||||
|
||||
| Breakpoint | Behaviour |
|
||||
| ------------------- | ------------------------------------------- |
|
||||
| Mobile (< 640px) | Single column, 3D simplified, hamburger nav |
|
||||
| Tablet (640–1024px) | 2-column grids, condensed nav |
|
||||
| Desktop (> 1024px) | Full layout, all animations active |
|
||||
| Large (> 1440px) | Max-width container `1440px`, centred |
|
||||
|
||||
---
|
||||
|
||||
## 14. Key Conversion Points (CTA Map)
|
||||
|
||||
Every CTA across the site leads to the consultation booking form.
|
||||
|
||||
| Location | CTA Text | Action |
|
||||
| ---------------------- | -------------------------- | ----------------------------------- |
|
||||
| Hero | "Book a Free Consultation" | Opens booking form / Calendly modal |
|
||||
| Hero | "See Our Services" | Smooth scroll to services section |
|
||||
| Services section | "Let's Talk" | Opens booking form |
|
||||
| Each service page hero | "Get Started Today" | Opens booking form |
|
||||
| Testimonials section | "Join Our Clients" | Opens booking form |
|
||||
| Final CTA section | "Book a Free Consultation" | Opens booking form |
|
||||
| Header (sticky) | "Book a Consultation" | Opens booking form |
|
||||
| Chat bot | Collect name + email | Sends lead to CRM / email |
|
||||
|
||||
---
|
||||
|
||||
## 15. Project Deliverables
|
||||
|
||||
- [ ] Full Next.js 15 codebase (TypeScript)
|
||||
- [ ] Payload CMS configured with all collections
|
||||
- [ ] Admin panel at `/admin`
|
||||
- [ ] All pages: Home, Services (5 pages), About, Blog, Contact
|
||||
- [ ] 3D animated hero scene (Three.js / R3F)
|
||||
- [ ] GSAP scroll animations
|
||||
- [ ] Framer Motion page transitions
|
||||
- [ ] Consultation booking form (with email notifications + webhook support)
|
||||
- [ ] Responsive design (mobile-first)
|
||||
- [ ] SEO metadata system
|
||||
- [ ] Google Analytics / GTM integration
|
||||
- [ ] Chat bot integration (configurable in admin)
|
||||
- [ ] Deployment to Vercel
|
||||
- [ ] CMS training documentation for client
|
||||
|
||||
---
|
||||
|
||||
## 16. Out of Scope (v1)
|
||||
|
||||
- Client portal / login area
|
||||
- Online payment processing
|
||||
- Accounting software integration (Xero API, etc.)
|
||||
- Multi-language support
|
||||
- A/B testing framework
|
||||
|
||||
_These can be considered for v2 based on business needs._
|
||||
|
||||
---
|
||||
|
||||
_Document maintained by development team. Last updated: February 2026._
|
||||
46
Dockerfile
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
FROM node:20-slim AS base
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||
WORKDIR /app
|
||||
|
||||
# --- Dependencies ---
|
||||
FROM base AS deps
|
||||
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
# --- Development ---
|
||||
FROM base AS dev
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
ENV NODE_ENV=development
|
||||
ENV WATCHPACK_POLLING=true
|
||||
EXPOSE 3000
|
||||
CMD ["pnpm", "dev"]
|
||||
|
||||
# --- Build ---
|
||||
FROM base AS build
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
RUN pnpm build
|
||||
|
||||
# --- Production ---
|
||||
FROM node:20-slim AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY --from=build /app/public ./public
|
||||
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
EXPOSE 3000
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
BIN
Logo/6fe4e3dc-3f0f-4529-88cd-153c947bbe1f.jpg
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
Logo/Axil Accounants (1).jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
Logo/Axil Accounants (2).jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
Logo/Axil Accounting.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
Logo/Axil Accounting[94].png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
Logo/dc10ea74-a0e1-445c-858a-8cde260a35b0.jpg
Normal file
|
After Width: | Height: | Size: 61 KiB |
36
README.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
41
docker-compose.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
target: dev
|
||||
ports:
|
||||
- '3000:3000'
|
||||
volumes:
|
||||
- ./src:/app/src
|
||||
- ./public:/app/public
|
||||
- ./next.config.ts:/app/next.config.ts
|
||||
- ./tailwind.config.ts:/app/tailwind.config.ts
|
||||
- ./tsconfig.json:/app/tsconfig.json
|
||||
- ./postcss.config.mjs:/app/postcss.config.mjs
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- WATCHPACK_POLLING=true
|
||||
env_file:
|
||||
- .env.local
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
db:
|
||||
image: postgres:17-alpine
|
||||
ports:
|
||||
- '5432:5432'
|
||||
environment:
|
||||
POSTGRES_USER: axil
|
||||
POSTGRES_PASSWORD: axil_dev
|
||||
POSTGRES_DB: axil
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'pg_isready -U axil']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
199
docs/guides/01-nextjs-docker-setup.md
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
# Next.js + Docker Setup Guide
|
||||
|
||||
## Principle
|
||||
|
||||
Run Next.js 16 in Docker using multi-stage builds with pnpm standalone output for minimal production images, and volume-mounted source code with filesystem polling for fast development hot reload.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Multi-Stage Build Flow
|
||||
|
||||
```
|
||||
+------------------+ +------------------+ +------------------+
|
||||
| Stage: deps | | Stage: build | | Stage: runner |
|
||||
| | | | | |
|
||||
| node:20-slim | | node:20-slim | | node:20-slim |
|
||||
| | | | | |
|
||||
| - corepack | --> | - Copy deps from | --> | - Copy standalone|
|
||||
| enable pnpm | | deps stage | | from build |
|
||||
| - pnpm install | | - Copy src | | - Copy static |
|
||||
| --frozen- | | - next build | | assets |
|
||||
| lockfile | | (standalone) | | - Run server.js |
|
||||
+------------------+ +------------------+ +------------------+
|
||||
~600 MB ~900 MB ~200 MB
|
||||
(cached between (discarded after (final image)
|
||||
builds) build completes)
|
||||
```
|
||||
|
||||
### Docker Compose Topology (Development)
|
||||
|
||||
```
|
||||
+---------------------------------------------------+
|
||||
| docker-compose.yml |
|
||||
| |
|
||||
| +-------------+ +-------------------+ |
|
||||
| | app | | db | |
|
||||
| | :3000 | -------> | :5432 | |
|
||||
| | | depends | | |
|
||||
| | Next.js dev | on | PostgreSQL 17 | |
|
||||
| | (webpack) | healthy | pgdata volume | |
|
||||
| +------+------+ +-------------------+ |
|
||||
| | |
|
||||
| bind mount |
|
||||
| ./src -> /app/src |
|
||||
| ./public -> /app/public |
|
||||
+---------------------------------------------------+
|
||||
```
|
||||
|
||||
## Patterns
|
||||
|
||||
| Do | Don't | When |
|
||||
| -------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| Use `output: "standalone"` in next.config.ts | Ship full `node_modules` in production image | Always in production |
|
||||
| Use `corepack enable pnpm` in Dockerfile | Install pnpm globally with `npm i -g pnpm` | pnpm projects (respects version pinning in package.json) |
|
||||
| Use `pnpm install --frozen-lockfile` | Use `pnpm install` without lockfile flag | CI and Docker builds (ensures reproducibility) |
|
||||
| Use `WATCHPACK_POLLING=true` for dev hot reload | Rely on native filesystem events in Docker | Development on macOS/Windows hosts |
|
||||
| Use `--turbopack` flag with `next dev` only when not in Docker | Use Turbopack in Docker dev containers | Docker dev (Turbopack ignores polled fs events) |
|
||||
| Mount only `./src` and `./public` as bind mounts | Mount the entire project root as a bind mount | Docker dev (avoids overwriting container node_modules) |
|
||||
| Use named volumes for `node_modules` and `.next` | Let bind mounts shadow container-built directories | Docker dev (prevents host/container version mismatches) |
|
||||
| Run as non-root user (`nextjs:nodejs`) in runner stage | Run as root in production containers | Always in production (limits blast radius) |
|
||||
| Copy only `standalone`, `static`, and `public` to runner | Copy the entire `.next` folder to runner | Production builds (minimizes image size) |
|
||||
| Set `HOSTNAME=0.0.0.0` in runner stage | Omit hostname binding | Docker networking (allows external access to container) |
|
||||
| Use `depends_on` with `condition: service_healthy` | Start app before database is ready | When app needs database at startup (e.g., Prisma migrations) |
|
||||
| Use `.dockerignore` to exclude `node_modules`, `.next`, `.git` | Let Docker context include everything | Always (speeds up builds, prevents leaking secrets) |
|
||||
|
||||
## Configuration
|
||||
|
||||
### next.config.ts
|
||||
|
||||
| Option | Value | Why |
|
||||
| -------- | -------------- | ---------------------------------------------------------------------------------------------------------- |
|
||||
| `output` | `"standalone"` | Produces self-contained build with only required `node_modules` files; reduces image from ~1 GB to ~200 MB |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Value | Stage | Why |
|
||||
| ------------------------- | ------------------ | ------------- | ---------------------------------------------------------- |
|
||||
| `PNPM_HOME` | `/pnpm` | deps, build | Ensures pnpm store is in a known location for caching |
|
||||
| `PATH` | `$PNPM_HOME:$PATH` | deps, build | Makes pnpm binary available on PATH |
|
||||
| `NEXT_TELEMETRY_DISABLED` | `1` | build, runner | Disables Vercel telemetry in CI/production |
|
||||
| `NODE_ENV` | `production` | build, runner | Enables production optimizations in Next.js and React |
|
||||
| `HOSTNAME` | `0.0.0.0` | runner | Binds server to all interfaces so Docker can route traffic |
|
||||
| `PORT` | `3000` | runner | Explicit port for `server.js` (matches EXPOSE) |
|
||||
| `WATCHPACK_POLLING` | `true` | dev only | Forces webpack to poll for file changes in Docker volumes |
|
||||
|
||||
### .dockerignore
|
||||
|
||||
| Entry | Why |
|
||||
| --------------------- | ----------------------------------------------------------- |
|
||||
| `node_modules` | Prevent host dependencies from overriding container install |
|
||||
| `.next` | Prevent stale build artifacts from entering build context |
|
||||
| `.git` | Reduce context size; not needed for builds |
|
||||
| `*.md` | Documentation not needed in image |
|
||||
| `.env*.local` | Prevent secrets from leaking into image layers |
|
||||
| `docker-compose*.yml` | Not needed inside the image |
|
||||
|
||||
## Dockerfile Stages
|
||||
|
||||
### Production (Multi-Stage)
|
||||
|
||||
| Stage | Base Image | Purpose | Key Actions |
|
||||
| -------- | -------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `deps` | `node:20-slim` | Install dependencies | `corepack enable pnpm`, copy `package.json` + `pnpm-lock.yaml`, run `pnpm install --frozen-lockfile` |
|
||||
| `build` | `node:20-slim` | Compile application | Copy `node_modules` from deps, copy source code, run `pnpm build` (triggers `next build` with standalone output) |
|
||||
| `runner` | `node:20-slim` | Run production server | Create `nextjs` user/group, copy `.next/standalone`, copy `.next/static` to `.next/standalone/.next/static`, copy `public` to `.next/standalone/public`, run `node server.js` |
|
||||
|
||||
### Stage Details
|
||||
|
||||
| Concern | Implementation | Notes |
|
||||
| ------------- | ------------------------------------------------------------ | ------------------------------------------------------ |
|
||||
| Layer caching | Copy lockfile before source code | Dependency layer is rebuilt only when lockfile changes |
|
||||
| Security | `RUN addgroup --system nodejs && adduser --system nextjs` | Non-root user in runner stage |
|
||||
| Permissions | `RUN chown -R nextjs:nodejs /app/.next` | Ensures Next.js can write cache at runtime |
|
||||
| Final size | Only `standalone` + `static` + `public` in runner | No `node_modules` directory, no build tools |
|
||||
| Health check | `HEALTHCHECK CMD curl -f http://localhost:3000/ \|\| exit 1` | Optional; useful for orchestrators |
|
||||
|
||||
### Base Image Comparison
|
||||
|
||||
| Image | Size | Pros | Cons | Recommendation |
|
||||
| ------------------------------------- | ------ | ----------------------------------------- | -------------------------------------------------------- | --------------------------- |
|
||||
| `node:20-alpine` | ~50 MB | Smallest, popular | Uses musl libc; can break native modules (bcrypt, sharp) | Use if no native deps |
|
||||
| `node:20-slim` | ~80 MB | Debian-based (glibc), broad compatibility | Slightly larger than Alpine | Default choice for Next.js |
|
||||
| `node:20-bookworm-slim` | ~80 MB | Same as slim, pinned Debian release | None significant | Equivalent to slim |
|
||||
| `gcr.io/distroless/nodejs20-debian12` | ~40 MB | Minimal attack surface, no shell | No shell for debugging, no package manager | Advanced: runner stage only |
|
||||
|
||||
## Docker Compose Services
|
||||
|
||||
### Development
|
||||
|
||||
| Service | Image / Build | Ports | Volumes | Environment | Purpose |
|
||||
| ------- | ------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -------------------------- |
|
||||
| `app` | `build: .` (dev Dockerfile or target) | `3000:3000` | `./src:/app/src`, `./public:/app/public`, `node_modules:/app/node_modules`, `next-cache:/app/.next` | `NODE_ENV=development`, `WATCHPACK_POLLING=true`, `DATABASE_URL=postgres://...` | Dev server with hot reload |
|
||||
| `db` | `postgres:17-alpine` | `5432:5432` | `pgdata:/var/lib/postgresql/data` | `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` | Development database |
|
||||
|
||||
### Production
|
||||
|
||||
| Service | Image / Build | Ports | Volumes | Environment | Purpose |
|
||||
| ------- | --------------------------------------- | -------------------------- | --------------------------------- | ---------------------------------------------------- | ------------------- |
|
||||
| `app` | `build: .` (multi-stage, runner target) | `3000:3000` | None (stateless) | `NODE_ENV=production`, `DATABASE_URL=postgres://...` | Production server |
|
||||
| `db` | `postgres:17-alpine` | `5432:5432` (or unexposed) | `pgdata:/var/lib/postgresql/data` | `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` | Production database |
|
||||
|
||||
### PostgreSQL Health Check
|
||||
|
||||
| Parameter | Value | Why |
|
||||
| ---------- | ----------------------------------------- | --------------------------------------------------- |
|
||||
| `test` | `["CMD-SHELL", "pg_isready -U postgres"]` | Lightweight check that Postgres accepts connections |
|
||||
| `interval` | `5s` | Check every 5 seconds |
|
||||
| `timeout` | `3s` | Fail check if no response in 3 seconds |
|
||||
| `retries` | `10` | Mark unhealthy after 10 consecutive failures |
|
||||
|
||||
### Named Volumes
|
||||
|
||||
| Volume | Mount Point | Why |
|
||||
| -------------- | -------------------------- | --------------------------------------------------------------- |
|
||||
| `pgdata` | `/var/lib/postgresql/data` | Persist database between container restarts |
|
||||
| `node_modules` | `/app/node_modules` | Prevent host bind mount from shadowing container-installed deps |
|
||||
| `next-cache` | `/app/.next` | Preserve build cache between dev restarts |
|
||||
|
||||
## Hot Reload Checklist (Development)
|
||||
|
||||
| Step | Detail |
|
||||
| --------------------------------------- | ---------------------------------------------------------------- |
|
||||
| 1. Set `WATCHPACK_POLLING=true` | Forces webpack to poll for changes instead of relying on inotify |
|
||||
| 2. Bind mount only source directories | `./src:/app/src` and `./public:/app/public` (not entire project) |
|
||||
| 3. Use named volume for `node_modules` | Prevents host `node_modules` from overwriting container deps |
|
||||
| 4. Use named volume for `.next` | Prevents stale build cache conflicts |
|
||||
| 5. Use `next dev` without `--turbopack` | Turbopack does not detect polled filesystem events in Docker |
|
||||
| 6. Expose WebSocket port if needed | HMR uses WebSocket; ensure port 3000 is forwarded |
|
||||
|
||||
## Common Issues
|
||||
|
||||
| Problem | Cause | Fix |
|
||||
| ---------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------- |
|
||||
| Hot reload not working in Docker | Missing `WATCHPACK_POLLING=true` or using Turbopack | Set env var; use webpack for dev in Docker |
|
||||
| `pnpm: not found` in Dockerfile | Corepack not enabled | Add `RUN corepack enable pnpm` before pnpm commands |
|
||||
| Image is 1+ GB | Not using standalone output | Set `output: "standalone"` in next.config.ts |
|
||||
| App crashes with EACCES | Running as non-root without proper ownership | `chown nextjs:nodejs /app/.next` before switching user |
|
||||
| Container can't reach database | Using `localhost` instead of service name | Use `db` (service name) as PostgreSQL host in `DATABASE_URL` |
|
||||
| `sharp` module fails on Alpine | musl libc incompatibility | Use `node:20-slim` (Debian) or install `sharp` platform-specific build |
|
||||
| Corepack signature verification error | Outdated corepack in base image | Add `RUN corepack prepare pnpm@<version> --activate` |
|
||||
| Static assets (CSS/images) missing after build | Forgot to copy `public` and `.next/static` to runner | Copy both directories alongside `standalone` in final stage |
|
||||
|
||||
## Sources
|
||||
|
||||
- [Next.js Official Deployment Docs](https://nextjs.org/docs/app/getting-started/deploying) - 2025
|
||||
- [Next.js output: standalone Configuration](https://nextjs.org/docs/app/api-reference/config/next-config-js/output) - 2025
|
||||
- [Next.js 16 Release Blog Post](https://nextjs.org/blog/next-16) - October 2025
|
||||
- [Next.js 16.1 Release Blog Post](https://nextjs.org/blog/next-16-1) - December 2025
|
||||
- [Optimizing Next.js Docker Builds with PNPM, Corepack, and Standalone Mode](https://htalbot.dev/posts/build-nextjs-standalone-docker) - 2025
|
||||
- [Dockerizing Next.js 15 with pnpm for Production](https://medium.com/@she11fish/dockerizing-next-js-15-application-with-pnpm-for-production-39c841ce8323) - 2025
|
||||
- [Best Next.js Docker Compose Hot-Reload Setup](https://medium.com/@elifront/best-next-js-docker-compose-hot-reload-production-ready-docker-setup-28a9125ba1dc) - 2025
|
||||
- [How to Configure Next.js with Docker](https://oneuptime.com/blog/post/2026-01-24-nextjs-docker-configuration/view) - January 2026
|
||||
- [pnpm Docker Documentation](https://pnpm.io/next/docker) - 2025
|
||||
- [How to use Prisma in Docker](https://www.prisma.io/docs/guides/docker) - 2025
|
||||
- [Security Advice for Self-Hosting Next.js in Docker](https://blog.arcjet.com/security-advice-for-self-hosting-next-js-in-docker/) - 2025
|
||||
- [Node.js Docker Optimization 2025: Multi-Stage Builds](https://markaicode.com/nodejs-docker-optimization-2025/) - 2025
|
||||
- [Container Images Guide: Alpine, Slim, Distroless](https://www.ykira.com/blog/container-images-guide) - 2025
|
||||
- [Choosing the Best Node.js Docker Image (Snyk)](https://snyk.io/blog/choosing-the-best-node-js-docker-image/) - 2025
|
||||
- [Turbopack Polling Feature Issue #80665](https://github.com/vercel/next.js/issues/80665) - 2025
|
||||
- [Docker Compose Watch + Turbopack Issue #12827](https://github.com/docker/compose/issues/12827) - 2025
|
||||
18
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import nextVitals from 'eslint-config-next/core-web-vitals';
|
||||
import nextTs from 'eslint-config-next/typescript';
|
||||
|
||||
const eslintConfig = defineConfig([
|
||||
...nextVitals,
|
||||
...nextTs,
|
||||
// Override default ignores of eslint-config-next.
|
||||
globalIgnores([
|
||||
// Default ignores of eslint-config-next:
|
||||
'.next/**',
|
||||
'out/**',
|
||||
'build/**',
|
||||
'next-env.d.ts',
|
||||
]),
|
||||
]);
|
||||
|
||||
export default eslintConfig;
|
||||
898
implementation_plan.md
Normal file
|
|
@ -0,0 +1,898 @@
|
|||
# Axil Accountants — Implementation Plan
|
||||
|
||||
> Based on: `Concept.md` v1.0
|
||||
> Stack: Next.js 15 · TypeScript · Tailwind CSS v4 · Payload CMS 3 · PostgreSQL (Neon) · Vercel
|
||||
> Each feature is isolated and can be developed, tested, and reviewed independently.
|
||||
|
||||
---
|
||||
|
||||
## Legend
|
||||
|
||||
- `[ ]` — Not started
|
||||
- `[x]` — Complete
|
||||
- `[~]` — In progress
|
||||
- `[!]` — Blocked / needs decision
|
||||
|
||||
---
|
||||
|
||||
## Feature 1 — Project Setup & Repository
|
||||
|
||||
- [ ] Scaffold Next.js 15 project with App Router and TypeScript (`create-next-app`)
|
||||
- [ ] Configure TypeScript (`tsconfig.json`): strict mode, path aliases (`@/*`, `@/components/*`, `@/lib/*`, `@/types/*`)
|
||||
- [ ] Install and configure **Tailwind CSS v4**
|
||||
- [ ] Install and configure **ESLint** (Next.js preset + custom rules)
|
||||
- [ ] Install and configure **Prettier** with Tailwind class sorting plugin
|
||||
- [ ] Set up **Husky** + **lint-staged** (pre-commit: lint + format)
|
||||
- [ ] Define `.env.local` structure and `.env.example` template:
|
||||
- `DATABASE_URI` (Neon PostgreSQL)
|
||||
- `PAYLOAD_SECRET`
|
||||
- `RESEND_API_KEY`
|
||||
- `NEXT_PUBLIC_SITE_URL`
|
||||
- `UPLOADTHING_SECRET` / `UPLOADTHING_APP_ID`
|
||||
- `OPENAI_API_KEY` (for AI chat bot, optional)
|
||||
- `SENTRY_DSN`
|
||||
- [ ] Create `src/` directory structure:
|
||||
```
|
||||
src/
|
||||
├── app/ # Next.js App Router pages
|
||||
├── components/
|
||||
│ ├── ui/ # Primitive components
|
||||
│ ├── layout/ # Header, Footer, Nav
|
||||
│ ├── sections/ # Page sections (Hero, Services, etc.)
|
||||
│ ├── three/ # Three.js / R3F components
|
||||
│ └── cms/ # CMS-driven components
|
||||
├── lib/ # Utilities, helpers
|
||||
├── hooks/ # Custom React hooks
|
||||
├── types/ # Shared TypeScript types
|
||||
└── payload/ # Payload CMS config & collections
|
||||
```
|
||||
- [ ] Initialise Git repository, create `main` and `develop` branches
|
||||
- [ ] Create **Vercel** project, connect to Git repository
|
||||
- [ ] Configure Vercel environment variables (production + preview)
|
||||
|
||||
---
|
||||
|
||||
## Feature 2 — Database & Cloud Infrastructure
|
||||
|
||||
- [ ] Create **Neon PostgreSQL** project (serverless, auto-scaling)
|
||||
- [ ] Copy connection string to `DATABASE_URI` environment variable
|
||||
- [ ] Verify database connectivity from local environment
|
||||
- [ ] Set up **Uploadthing** account for media storage
|
||||
- Create app, get `UPLOADTHING_SECRET` and `UPLOADTHING_APP_ID`
|
||||
- Configure allowed file types: images (jpg, png, webp, svg), documents (pdf)
|
||||
- [ ] Set up **Resend** account for transactional emails
|
||||
- Create API key, add to `RESEND_API_KEY`
|
||||
- Verify sending domain
|
||||
|
||||
---
|
||||
|
||||
## Feature 3 — Payload CMS — Core Installation
|
||||
|
||||
- [ ] Install Payload CMS 3 into the Next.js project (`npx create-payload-app` or manual)
|
||||
- [ ] Configure `payload.config.ts`:
|
||||
- `serverURL` from `NEXT_PUBLIC_SITE_URL`
|
||||
- `secret` from `PAYLOAD_SECRET`
|
||||
- `db`: PostgreSQL adapter pointing to `DATABASE_URI`
|
||||
- `editor`: Lexical rich text editor
|
||||
- `admin` panel configuration
|
||||
- [ ] Mount Payload API handler at `src/app/(payload)/api/[...slug]/route.ts`
|
||||
- [ ] Mount admin panel at `src/app/(payload)/admin/[[...segments]]/page.tsx`
|
||||
- [ ] Configure **Uploadthing storage adapter** for Payload media
|
||||
- [ ] Configure **Resend email adapter** for Payload email notifications
|
||||
- [ ] Create initial admin superuser (seed script or first-run prompt)
|
||||
- [ ] Verify admin panel loads at `/admin`
|
||||
- [ ] Install **Payload Form Builder plugin** (`@payloadcms/plugin-form-builder`)
|
||||
|
||||
---
|
||||
|
||||
## Feature 4 — CMS Collections Schema
|
||||
|
||||
Define all Payload collections and globals. Each collection = one content type the client manages.
|
||||
|
||||
### 4.1 — Media Collection
|
||||
|
||||
- [ ] `Media` collection with Uploadthing adapter
|
||||
- Fields: `alt` (text, required), `caption` (text, optional)
|
||||
- Image sizes: `thumbnail` (400×300), `card` (800×600), `hero` (1920×1080)
|
||||
|
||||
### 4.2 — Users Collection
|
||||
|
||||
- [ ] `Users` collection (extends Payload default)
|
||||
- Fields: `name`, `email`, `role` (select: admin | editor)
|
||||
- Role-based access control: editors can manage content, not settings
|
||||
|
||||
### 4.3 — Services Collection
|
||||
|
||||
- [ ] `Services` collection
|
||||
- `title` (text, required)
|
||||
- `slug` (slug, auto from title, unique)
|
||||
- `icon` (select: bookkeeping | tax | payroll | vat)
|
||||
- `tagline` (text — short subtitle)
|
||||
- `description` (rich text — full description)
|
||||
- `whatsIncluded` (array of bullet strings)
|
||||
- `whoItsFor` (array: `{ audience: select, description: text }`)
|
||||
- `howItWorks` (array of 3: `{ step: number, title: text, description: text }`)
|
||||
- `faq` (array: `{ question: text, answer: rich text }`)
|
||||
- `relatedTestimonials` (relationship → Testimonials, many)
|
||||
- `seo` group: `{ metaTitle, metaDescription, ogImage → Media }`
|
||||
- `publishedAt` (date), `status` (select: draft | published)
|
||||
|
||||
### 4.4 — Blog Posts Collection
|
||||
|
||||
- [ ] `Posts` collection
|
||||
- `title` (text, required)
|
||||
- `slug` (slug, unique)
|
||||
- `author` (relationship → Users)
|
||||
- `category` (relationship → Categories)
|
||||
- `coverImage` (upload → Media)
|
||||
- `excerpt` (textarea, 150 chars max)
|
||||
- `content` (rich text — Lexical with full feature set)
|
||||
- `readingTime` (number, auto-calculated on save via hook)
|
||||
- `publishedAt` (date)
|
||||
- `status` (select: draft | published | scheduled)
|
||||
- `tags` (array of text)
|
||||
- `seo` group: `{ metaTitle, metaDescription, ogImage → Media }`
|
||||
|
||||
### 4.5 — Categories Collection
|
||||
|
||||
- [ ] `Categories` collection
|
||||
- `name` (text, required)
|
||||
- `slug` (slug)
|
||||
- `colour` (text — hex, for tag colour)
|
||||
|
||||
### 4.6 — Team Members Collection
|
||||
|
||||
- [ ] `TeamMembers` collection
|
||||
- `name` (text, required)
|
||||
- `role` (text)
|
||||
- `qualifications` (text — e.g. "ACCA, MAAT")
|
||||
- `bio` (textarea)
|
||||
- `photo` (upload → Media)
|
||||
- `linkedIn` (text — URL)
|
||||
- `order` (number — display order)
|
||||
|
||||
### 4.7 — Testimonials Collection
|
||||
|
||||
- [ ] `Testimonials` collection
|
||||
- `clientName` (text, required)
|
||||
- `businessName` (text)
|
||||
- `businessType` (select: sole-trader | limited-company | startup | other)
|
||||
- `rating` (select: 1–5)
|
||||
- `quote` (textarea, required)
|
||||
- `photo` (upload → Media, optional)
|
||||
- `source` (select: google | manual)
|
||||
- `service` (relationship → Services, optional — for filtering)
|
||||
- `featured` (checkbox — show in homepage carousel)
|
||||
- `publishedAt` (date)
|
||||
|
||||
### 4.8 — FAQs Collection
|
||||
|
||||
- [ ] `FAQs` collection (global FAQ bank)
|
||||
- `question` (text, required)
|
||||
- `answer` (rich text)
|
||||
- `service` (relationship → Services, optional)
|
||||
- `global` (checkbox — show on generic FAQ sections)
|
||||
- `order` (number)
|
||||
|
||||
### 4.9 — Form Builder (Payload Plugin Collections)
|
||||
|
||||
- [ ] Enable `@payloadcms/plugin-form-builder` — provides:
|
||||
- `Forms` collection (drag-and-drop field builder in admin)
|
||||
- `FormSubmissions` collection (stores all submissions)
|
||||
- [ ] Configure supported field types: `text`, `email`, `phone`, `select`, `checkbox`, `textarea`
|
||||
- [ ] Configure submission handlers:
|
||||
- Email notification (to: configurable per form)
|
||||
- Webhook trigger (URL: from webhook registry in Site Settings)
|
||||
- Redirect URL or confirmation message (per form)
|
||||
|
||||
### 4.10 — Navigation Global
|
||||
|
||||
- [ ] `Navigation` global
|
||||
- `items` (array):
|
||||
- `label` (text)
|
||||
- `href` (text, optional — for simple links)
|
||||
- `isDropdown` (checkbox)
|
||||
- `children` (array, conditional): `{ label, href, icon, description }`
|
||||
|
||||
### 4.11 — Footer Global
|
||||
|
||||
- [ ] `Footer` global
|
||||
- `columns` (array of 4):
|
||||
- `heading` (text)
|
||||
- `links` (array: `{ label, href }`)
|
||||
- `contactInfo` group: `{ address, phone, email }`
|
||||
- `socialLinks` group: `{ linkedIn, facebook, instagram }`
|
||||
- `legalLinks` (array: `{ label, href }`)
|
||||
- `copyrightText` (text)
|
||||
|
||||
### 4.12 — Site Settings Global
|
||||
|
||||
- [ ] `SiteSettings` global
|
||||
- **Brand**: `siteName`, `tagline`, `logo → Media`, `logoDark → Media`, `favicon → Media`
|
||||
- **Contact**: `address`, `phone`, `email`, `officeHours`
|
||||
- **Social**: `linkedIn`, `facebook`, `instagram`
|
||||
- **Analytics**: `googleAnalyticsId`, `googleTagManagerId`, `facebookPixelId`
|
||||
- **Booking**: `calendlyUrl`, `calendlyInline` (checkbox)
|
||||
- **Chat Bot**: `chatBotMode` (select: disabled | ai | livechat | leadcapture), `chatBotCustomCode` (code field — for Tawk.to etc.)
|
||||
- **Webhooks Registry**: `webhooks` (array: `{ name, url, active }`)
|
||||
- **Email**: `notificationEmail` (default recipient for form submissions)
|
||||
- **SEO Defaults**: `defaultMetaTitle`, `defaultMetaDescription`, `defaultOgImage → Media`
|
||||
- **Scripts**: `headerScripts` (code), `footerScripts` (code) — for third-party embeds
|
||||
|
||||
---
|
||||
|
||||
## Feature 5 — Design System & Base UI Components
|
||||
|
||||
- [ ] Configure Tailwind CSS with custom design tokens:
|
||||
```js
|
||||
// tailwind.config.ts
|
||||
colors: {
|
||||
sage: { DEFAULT: '#6BAF7D', light: '#A8C5A0' },
|
||||
forest: { DEFAULT: '#2E7D52', dark: '#1A2E1F' },
|
||||
mint: '#F4FAF5',
|
||||
charcoal: '#1A2E1F',
|
||||
muted: '#6B7280',
|
||||
}
|
||||
borderRadius: { card: '16px', hero: '24px', pill: '999px' }
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'sans-serif'],
|
||||
display: ['Satoshi', 'sans-serif'],
|
||||
mono: ['DM Mono', 'monospace'],
|
||||
}
|
||||
```
|
||||
- [ ] Set up fonts:
|
||||
- `Satoshi` (variable font) — self-hosted via `@font-face` or Fontshare CDN
|
||||
- `Inter` — Google Fonts / `next/font`
|
||||
- `DM Mono` — Google Fonts / `next/font`
|
||||
- [ ] Create CSS variables in `globals.css` for all design tokens (enables runtime theming)
|
||||
- [ ] **Button** component (`src/components/ui/Button.tsx`):
|
||||
- Variants: `primary` (green fill), `secondary` (outline), `ghost` (text only)
|
||||
- Sizes: `sm`, `md`, `lg`
|
||||
- States: hover (scale + colour shift), focus (ring), loading (spinner), disabled
|
||||
- Optional: trailing arrow icon, leading icon
|
||||
- [ ] **Icon system** (`src/components/ui/icons/`):
|
||||
- Custom SVG line icons for each service (Bookkeeping, Tax, Payroll, VAT)
|
||||
- Shared icons: ArrowRight, CheckCircle, Star, Menu, X, ChevronDown
|
||||
- All exported as React components with `size` and `color` props
|
||||
- [ ] **Heading** component — `h1`–`h4` with correct size + weight from design system
|
||||
- [ ] **Tag/Badge** component — pill with colour variant (green, grey)
|
||||
- [ ] **StarRating** component — 1–5 filled star SVGs
|
||||
- [ ] **GlassCard** component — frosted glass base with sage green border, hover glow
|
||||
- [ ] **Section** layout wrapper — `max-w-[1440px]`, horizontal padding, `py` spacing
|
||||
- [ ] **Divider** component — subtle sage green horizontal rule
|
||||
- [ ] **Spinner** component — loading state for forms and async content
|
||||
|
||||
---
|
||||
|
||||
## Feature 6 — Animation Infrastructure
|
||||
|
||||
- [ ] Install dependencies: `gsap`, `@gsap/react`, `lenis`, `framer-motion`, `@react-three/fiber`, `three`
|
||||
- [ ] **Lenis smooth scroll** provider (`src/lib/lenis.tsx`):
|
||||
- `LenisProvider` wraps the app in root layout
|
||||
- Integrates with GSAP ticker for synchronized animations
|
||||
- Disabled on mobile if causing performance issues
|
||||
- [ ] **GSAP context provider** (`src/lib/gsap.ts`):
|
||||
- Registers ScrollTrigger plugin
|
||||
- Exports `gsap` instance with plugins pre-registered
|
||||
- Custom hook `useGSAP` for component-level animation cleanup
|
||||
- [ ] **`useAnimateOnScroll` hook** (`src/hooks/useAnimateOnScroll.ts`):
|
||||
- Accepts `ref`, `animation type` (fadeUp, fadeIn, slideLeft, etc.), `delay`, `stagger`
|
||||
- Returns trigger state
|
||||
- Uses ScrollTrigger under the hood
|
||||
- [ ] **`useCountUp` hook** (`src/hooks/useCountUp.ts`):
|
||||
- Accepts `target` (number), `duration`, `prefix` (`£`, `+`), `suffix` (`%`, `+`)
|
||||
- Triggers animation when element enters viewport
|
||||
- Returns current display value (string)
|
||||
- [ ] **`AnimatedText` component** (`src/components/ui/AnimatedText.tsx`):
|
||||
- Splits text into words or lines
|
||||
- Each word/line slides up on a stagger delay
|
||||
- GSAP-driven, respects `prefers-reduced-motion`
|
||||
- [ ] **`FadeInSection` component** (`src/components/ui/FadeInSection.tsx`):
|
||||
- Wraps any content
|
||||
- Fades + translates up when enters viewport
|
||||
- Accepts `delay` and `duration` props
|
||||
- [ ] **Framer Motion page transition** (`src/components/layout/PageTransition.tsx`):
|
||||
- Wraps each page with `AnimatePresence`
|
||||
- Default: fade + subtle Y translate
|
||||
- Used in root layout
|
||||
- [ ] **`prefers-reduced-motion` utility** — all animation components check and skip if enabled
|
||||
|
||||
---
|
||||
|
||||
## Feature 7 — Header & Navigation
|
||||
|
||||
- [ ] **`Header` component** (`src/components/layout/Header.tsx`):
|
||||
- Fixed/sticky at top, `z-50`
|
||||
- On scroll: applies `backdrop-blur` + white/85% opacity background (Framer Motion)
|
||||
- Transparent when at top of page
|
||||
- Max-width container, flex layout: logo | nav | CTA
|
||||
- [ ] **Logo component** — renders logo image from CMS Site Settings, supports light/dark variant
|
||||
- [ ] **Desktop navigation** (`src/components/layout/DesktopNav.tsx`):
|
||||
- Renders items from CMS Navigation global
|
||||
- Simple links: hover underline slide-in animation
|
||||
- Dropdown trigger: `Services ▾` — renders `ServicesDropdown`
|
||||
- [ ] **`ServicesDropdown` component**:
|
||||
- Opens on hover/focus, closes on blur/outside click
|
||||
- Grid of service cards: icon + name + short description
|
||||
- Framer Motion: animate-in (scale + fade from top)
|
||||
- [ ] **Header CTA button** — "Book a Free Consultation" → opens booking modal
|
||||
- [ ] **`MobileMenu` component** (`src/components/layout/MobileMenu.tsx`):
|
||||
- Hamburger icon button (animated → X on open)
|
||||
- Full-screen overlay, `fixed inset-0`, dark green tint background
|
||||
- Framer Motion: slide-in from right or fade-in
|
||||
- Staggered nav item reveal
|
||||
- Large CTA button at bottom
|
||||
- Closes on link click or backdrop click
|
||||
- [ ] Fetch navigation data from Payload at build/request time (cached)
|
||||
|
||||
---
|
||||
|
||||
## Feature 8 — Footer
|
||||
|
||||
- [ ] **`Footer` component** (`src/components/layout/Footer.tsx`):
|
||||
- 4-column grid (collapses to 2×2 on tablet, 1 column on mobile)
|
||||
- Column 1: Logo, tagline, social icon links
|
||||
- Column 2: Services links
|
||||
- Column 3: Company links (About, Blog, Contact)
|
||||
- Column 4: Contact info (address, phone, email) + ICAEW/ACCA badges
|
||||
- [ ] Social icon links (LinkedIn, Facebook, Instagram) — SVG icons, hover colour transition
|
||||
- [ ] ICAEW / ACCA badge images (stored in media, linked from Site Settings)
|
||||
- [ ] **Bottom bar**: copyright text | Privacy Policy | Cookie Policy
|
||||
- [ ] Data fetched from CMS Footer global + Site Settings global
|
||||
|
||||
---
|
||||
|
||||
## Feature 9 — 3D Hero Scene (Three.js / R3F)
|
||||
|
||||
- [ ] Install: `@react-three/fiber`, `@react-three/drei`, `three`
|
||||
- [ ] **`GlobeScene` component** (`src/components/three/GlobeScene.tsx`):
|
||||
- Canvas with `@react-three/fiber`
|
||||
- Camera position, fog, ambient + directional lighting (soft green tint)
|
||||
- [ ] **`Globe` mesh**:
|
||||
- `SphereGeometry` with high segment count
|
||||
- Custom `PointsMaterial` shader: dot-matrix surface pattern
|
||||
- Colour: sage green `#6BAF7D` on near-white background
|
||||
- Slow auto-rotation around Y axis (`useFrame`)
|
||||
- [ ] **`ParticleNetwork`**:
|
||||
- 150–300 floating particle nodes (reduced on mobile: 60–80)
|
||||
- Lines connecting nearby particles (`LineSegments`)
|
||||
- Nodes float with subtle Perlin noise movement
|
||||
- Colour: soft mint with 40% opacity
|
||||
- [ ] **Mouse parallax interaction**:
|
||||
- Track `mousemove` on hero section
|
||||
- Globe and particle network shift slightly (opposite to mouse direction)
|
||||
- `useSpring` (React Spring or Framer Motion) for smooth interpolation
|
||||
- [ ] **Device-adaptive performance**:
|
||||
- Detect mobile / low-power device
|
||||
- Reduce particle count, disable post-processing effects
|
||||
- `React.Suspense` boundary with skeleton loader during WebGL init
|
||||
- [ ] **Mobile fallback** (`src/components/three/GlobeFallback.tsx`):
|
||||
- 2D SVG animated globe (CSS animation, no WebGL)
|
||||
- Shown when WebGL unavailable or `prefers-reduced-motion` is set
|
||||
- [ ] **`useWebGLSupport` hook** — detects WebGL availability, returns boolean
|
||||
|
||||
---
|
||||
|
||||
## Feature 10 — Home Page: Hero Section
|
||||
|
||||
- [ ] **`HeroSection` component** (`src/components/sections/home/HeroSection.tsx`)
|
||||
- [ ] Full-viewport height (`min-h-screen`), flex / grid split layout
|
||||
- [ ] Left column:
|
||||
- Eyebrow tag (e.g. "Trusted by 500+ UK Businesses") — Badge component, fade-in
|
||||
- `AnimatedText` H1: "Smart Accounting for Growing British Businesses" — word stagger
|
||||
- Subheadline paragraph — fade-in with delay
|
||||
- Button group: Primary CTA + Secondary CTA (with arrow icon)
|
||||
- Trust strip: star rating + "4.9 Google Rating" · "ICAEW Certified" · "500+ Clients Served"
|
||||
- [ ] Right column: `GlobeScene` (or `GlobeFallback` on mobile/no WebGL)
|
||||
- [ ] Mobile layout: stacked, 3D scene below text, reduced height
|
||||
- [ ] Content driven from CMS Pages collection (hero fields)
|
||||
|
||||
---
|
||||
|
||||
## Feature 11 — Home Page: Pain Points Section
|
||||
|
||||
- [ ] **`PainPointsSection` component**
|
||||
- [ ] Dark green background (`#1A2E1F`), full-width
|
||||
- [ ] Headline + subtext — `AnimatedText` reveal
|
||||
- [ ] 3 `GlassCard` components (frosted glass on dark background):
|
||||
- Card 1: "Missed deadlines & HMRC penalties"
|
||||
- Card 2: "Confused by tax rules that keep changing"
|
||||
- Card 3: "Hours wasted on bookkeeping instead of growing"
|
||||
- [ ] ScrollTrigger staggered reveal: cards slide up 100ms apart
|
||||
- [ ] Subtle parallax: background shifts 20px on scroll
|
||||
|
||||
---
|
||||
|
||||
## Feature 12 — Home Page: Services Overview Section
|
||||
|
||||
- [ ] **`ServicesSection` component**
|
||||
- [ ] Section header: headline + subheadline
|
||||
- [ ] 2×2 `GlassCard` grid (CSS Grid, responsive)
|
||||
- [ ] Each card:
|
||||
- Custom SVG icon (from icon system)
|
||||
- Service name (heading)
|
||||
- Short description (from CMS)
|
||||
- "Learn More →" link to `/services/[slug]`
|
||||
- Hover: `translateY(-4px)` + sage green border glow (`box-shadow`)
|
||||
- [ ] ScrollTrigger staggered card reveal
|
||||
- [ ] CTA block below grid: "Not sure which service you need? → Let's Talk"
|
||||
- [ ] Data: fetch all Services from Payload
|
||||
|
||||
---
|
||||
|
||||
## Feature 13 — Home Page: Why Choose Axil Section
|
||||
|
||||
- [ ] **`WhyAxilSection` component**
|
||||
- [ ] Section headline: "Why Businesses Choose Axil"
|
||||
- [ ] **Stat counter row** (4 stats):
|
||||
- `500+` Businesses Served
|
||||
- `98%` Client Retention Rate
|
||||
- `£2M+` Tax Saved for Our Clients
|
||||
- `12+` Years of Experience
|
||||
- Each uses `useCountUp` hook, triggers on ScrollTrigger enter
|
||||
- Numbers in `DM Mono` font
|
||||
- [ ] **4 USP blocks** (icon + heading + description):
|
||||
- ICAEW & ACCA Qualified
|
||||
- Fixed Monthly Engagement
|
||||
- Dedicated Account Manager
|
||||
- Cloud-Based & Paper-Free
|
||||
- [ ] `FadeInSection` wrapper per block, staggered
|
||||
|
||||
---
|
||||
|
||||
## Feature 14 — Home Page: Testimonials Section
|
||||
|
||||
- [ ] **`TestimonialsSection` component**
|
||||
- [ ] Auto-scrolling marquee carousel (infinite horizontal scroll, CSS animation)
|
||||
- Pause on hover
|
||||
- Two rows scrolling in opposite directions (optional premium touch)
|
||||
- [ ] **`TestimonialCard`** component:
|
||||
- Client name + business type
|
||||
- `StarRating` (1–5)
|
||||
- Quote text (truncated at 3 lines, expand on click)
|
||||
- Optional client avatar (from Media, fallback to initials)
|
||||
- [ ] Google Reviews badge (static badge image or API widget)
|
||||
- [ ] ICAEW / ACCA certification badge display
|
||||
- [ ] CTA below: "Join hundreds of satisfied UK businesses → Book Your Free Consultation"
|
||||
- [ ] Data: fetch featured testimonials from Payload (where `featured = true`)
|
||||
|
||||
---
|
||||
|
||||
## Feature 15 — Home Page: Who We Work With Section
|
||||
|
||||
- [ ] **`AudienceSection` component**
|
||||
- [ ] 3 audience cards:
|
||||
- Sole Traders — illustrated icon, description, "Learn More →"
|
||||
- Limited Companies — illustrated icon, description, "Learn More →"
|
||||
- Startups — illustrated icon, description, "Learn More →"
|
||||
- [ ] Illustrated icons: custom SVG per audience type
|
||||
- [ ] Cards: `GlassCard`, hover lift effect
|
||||
- [ ] FadeIn reveal on scroll
|
||||
|
||||
---
|
||||
|
||||
## Feature 16 — Home Page: How It Works Section
|
||||
|
||||
- [ ] **`HowItWorksSection` component**
|
||||
- [ ] 3-step horizontal layout (flex row on desktop, vertical stack on mobile)
|
||||
- [ ] Each step: numbered circle + title + description
|
||||
- [ ] **Animated connecting line**:
|
||||
- SVG path between steps
|
||||
- GSAP `DrawSVGPlugin` or stroke `dashoffset` animation
|
||||
- Draws left-to-right as section scrolls into view
|
||||
- [ ] Step data driven from CMS (global or hardcoded — TBD with client)
|
||||
|
||||
---
|
||||
|
||||
## Feature 17 — Home Page: Blog Preview Section
|
||||
|
||||
- [ ] **`BlogPreviewSection` component**
|
||||
- [ ] Section headline + "Visit Our Blog →" link
|
||||
- [ ] Fetch 3 most recent published posts from Payload
|
||||
- [ ] **`BlogCard`** component (reused on blog index):
|
||||
- Cover image (`next/image`, lazy-loaded)
|
||||
- Category tag badge
|
||||
- Title (heading)
|
||||
- Excerpt (truncated)
|
||||
- Author name + date + read time
|
||||
- Hover: image subtle zoom, card lift
|
||||
- [ ] Grid: 3 columns desktop, 1 column mobile
|
||||
|
||||
---
|
||||
|
||||
## Feature 18 — Home Page: Final CTA Section
|
||||
|
||||
- [ ] **`FinalCTASection` component**
|
||||
- [ ] Full-width, deep forest green background (`#1A2E1F` or `#2E7D52`)
|
||||
- [ ] Centred content:
|
||||
- Large headline: "Ready to take the stress out of your finances?"
|
||||
- Subheadline
|
||||
- Large primary CTA button (white on green): "Book a Free Consultation"
|
||||
- Trust reassurance: "★ 4.9/5 on Google · ICAEW Certified · No lock-in contracts"
|
||||
- [ ] Optional: subtle animated background (particle drift or gradient shift)
|
||||
|
||||
---
|
||||
|
||||
## Feature 19 — Consultation Booking Modal & Form
|
||||
|
||||
This is the primary conversion mechanism. Opens from every CTA across the site.
|
||||
|
||||
- [ ] **`BookingModal` component** (`src/components/BookingModal.tsx`):
|
||||
- Global state: `useBookingModal()` Zustand store or React Context
|
||||
- Triggered by `openBookingModal()` from any component
|
||||
- `AnimatePresence` + Framer Motion: fade-in backdrop, slide-up modal
|
||||
- Close on backdrop click, Escape key, close button
|
||||
- Accessible: focus trap, `role="dialog"`, `aria-modal`
|
||||
- [ ] **Two modes** (configurable in CMS Site Settings):
|
||||
- **Mode A — Calendly**: renders `<iframe>` from `calendlyUrl` setting
|
||||
- **Mode B — Custom Form**: renders the consultation form
|
||||
- [ ] **Consultation form fields**:
|
||||
- Full name (text, required)
|
||||
- Email address (email, required)
|
||||
- Phone number (text, optional)
|
||||
- Business type (select: sole trader / limited company / startup / other)
|
||||
- What do you need help with? (select: bookkeeping / tax / payroll / VAT / not sure)
|
||||
- Message (textarea, optional)
|
||||
- [ ] Form validation: client-side (React Hook Form + Zod schema)
|
||||
- [ ] Submit handler (API route `POST /api/contact`):
|
||||
- Save to Payload FormSubmissions collection
|
||||
- Send notification email via Resend to admin email (from Site Settings)
|
||||
- Trigger webhook if configured (from webhooks registry)
|
||||
- Return success/error response
|
||||
- [ ] Success state: animated checkmark + "We'll be in touch within 1 business day" message
|
||||
- [ ] Error state: clear error messages per field + general error fallback
|
||||
|
||||
---
|
||||
|
||||
## Feature 20 — Services Pages
|
||||
|
||||
### 20.1 — Services Overview Page (`/services`)
|
||||
|
||||
- [ ] Grid of all 4 service cards (large format)
|
||||
- [ ] Each card links to individual service page
|
||||
- [ ] Intro section: headline + subheadline
|
||||
- [ ] CTA at bottom
|
||||
|
||||
### 20.2 — Individual Service Pages (`/services/[slug]`)
|
||||
|
||||
- [ ] Dynamic route with `generateStaticParams` (ISR)
|
||||
- [ ] Fetch service data by slug from Payload at build/revalidate time
|
||||
- [ ] **Hero section**: service name, bold tagline, illustration/icon, CTA button
|
||||
- [ ] **What's Included section**: bullet list of deliverables (from CMS `whatsIncluded`)
|
||||
- [ ] **Who It's For section**: audience cards filtered to relevant segments
|
||||
- [ ] **How It Works section**: 3-step process (service-specific, from CMS)
|
||||
- [ ] **FAQ section**: accordion component
|
||||
- Fetch FAQs related to this service from Payload
|
||||
- Animated expand/collapse (Framer Motion `AnimatePresence` + height animation)
|
||||
- JSON-LD `FAQPage` schema injected via `generateMetadata`
|
||||
- [ ] **Testimonials section**: filtered by service (from Payload relationship)
|
||||
- [ ] **Final CTA section**
|
||||
- [ ] `generateMetadata`: SEO title, description, OG image from CMS `seo` group
|
||||
|
||||
---
|
||||
|
||||
## Feature 21 — About Page (`/about`)
|
||||
|
||||
- [ ] Fetch team members, site settings from Payload
|
||||
- [ ] **Hero section**: large headline + team group photo (from Media)
|
||||
- [ ] **Our Story section**: rich text from CMS (Lexical renderer)
|
||||
- [ ] **Team grid section**:
|
||||
- `TeamMemberCard` component: photo, name, role, qualifications, LinkedIn link
|
||||
- Responsive grid: 3 col desktop, 2 col tablet, 1 col mobile
|
||||
- Hover: subtle overlay with LinkedIn button
|
||||
- Data from Payload TeamMembers collection (ordered by `order` field)
|
||||
- [ ] **Core Values section**: 4 value blocks (icon + title + description)
|
||||
- [ ] **Certifications section**: ICAEW + ACCA logo badges with descriptions
|
||||
- [ ] **Final CTA section**
|
||||
|
||||
---
|
||||
|
||||
## Feature 22 — Blog System
|
||||
|
||||
### 22.1 — Blog Index Page (`/blog`)
|
||||
|
||||
- [ ] Fetch all published posts (ISR, revalidate: 3600s)
|
||||
- [ ] **Search input**: client-side filter by title/excerpt
|
||||
- [ ] **Category filter tabs**: "All" + each category — filters post grid
|
||||
- [ ] Blog post card grid (3 columns desktop, 1 mobile) — `BlogCard` component
|
||||
- [ ] Pagination (10 posts per page, Payload `limit`/`page` query)
|
||||
- [ ] SEO metadata for blog index
|
||||
|
||||
### 22.2 — Individual Blog Post Page (`/blog/[slug]`)
|
||||
|
||||
- [ ] `generateStaticParams` + ISR (revalidate: 3600s)
|
||||
- [ ] Fetch post by slug from Payload
|
||||
- [ ] **Lexical rich text renderer** (`src/lib/lexical-renderer.tsx`):
|
||||
- Renders all Lexical nodes: headings, paragraphs, lists, blockquotes, images, code blocks
|
||||
- Custom component for pull quotes (green left border, large text)
|
||||
- Syntax highlighting for code blocks (`shiki` or `prism`)
|
||||
- [ ] **Article layout**: hero image (full-width), title, author + date + read time + category tag
|
||||
- [ ] **Table of Contents** (auto-generated from H2/H3 headings):
|
||||
- Sticky sidebar on desktop
|
||||
- Active heading highlight on scroll (Intersection Observer)
|
||||
- [ ] **Social share buttons**: copy link, Twitter/X, LinkedIn
|
||||
- [ ] **Related posts section**: 2–3 posts from same category
|
||||
- [ ] `generateMetadata`: full SEO + Open Graph from CMS seo group
|
||||
|
||||
---
|
||||
|
||||
## Feature 23 — Contact Page (`/contact`)
|
||||
|
||||
- [ ] Hero: "Get in Touch" + brief description
|
||||
- [ ] **Contact form** (renders a Payload Form via form builder):
|
||||
- Fields: name, email, phone, subject, message
|
||||
- Submission saves to Payload FormSubmissions + email notification
|
||||
- [ ] **Contact info panel**: address, phone, email, office hours
|
||||
- [ ] **Google Maps embed** (iframe, optional — lazy-loaded)
|
||||
- [ ] Office hours block
|
||||
|
||||
---
|
||||
|
||||
## Feature 24 — Legal Pages (`/privacy-policy`, `/cookie-policy`)
|
||||
|
||||
- [ ] Static page routes
|
||||
- [ ] Content editable via CMS Pages collection (rich text fields)
|
||||
- [ ] Standard typography layout: table of contents sidebar + main content
|
||||
- [ ] Last updated date (from CMS)
|
||||
|
||||
---
|
||||
|
||||
## Feature 25 — Chat Bot Module
|
||||
|
||||
- [ ] **`ChatWidget` component** (`src/components/chat/ChatWidget.tsx`):
|
||||
- Floating button (bottom-right), "Chat with us" label
|
||||
- Slide-up panel animation (Framer Motion)
|
||||
- Reads `chatBotMode` from Site Settings global
|
||||
- [ ] **Mode: disabled** — component renders nothing
|
||||
- [ ] **Mode: livechat** (Tawk.to or custom):
|
||||
- Reads `chatBotCustomCode` from Site Settings
|
||||
- Injects script via `useEffect` (no SSR)
|
||||
- Custom button hidden; Tawk.to button shown instead
|
||||
- [ ] **Mode: ai** — AI Chat:
|
||||
- Pre-chat form: collect visitor name + email
|
||||
- Chat messages UI: user + bot bubbles, loading dots
|
||||
- API route `POST /api/chat`:
|
||||
- Sends message to OpenAI/Claude with system prompt
|
||||
- System prompt: company info, services, FAQs — fetched from Payload
|
||||
- Streams response back (SSE or JSON)
|
||||
- Escalation: if bot confidence low → "Let me connect you with our team" → email notification
|
||||
- Conversation log saved to Payload (custom `ChatLogs` collection or email)
|
||||
- [ ] **Mode: leadcapture** — Scripted Bot:
|
||||
- Step 1: "Hi! What's your name?"
|
||||
- Step 2: "Great, {name}! What's your email address?"
|
||||
- Step 3: "Are you a sole trader, limited company, or startup?"
|
||||
- Step 4: "What's your main concern? (tax / bookkeeping / payroll / other)"
|
||||
- Step 5: "Thanks! Our team will be in touch shortly."
|
||||
- On completion: POST lead to `/api/contact` → email + webhook
|
||||
|
||||
---
|
||||
|
||||
## Feature 26 — SEO & Metadata System
|
||||
|
||||
- [ ] **`generateMetadata` function** utility (`src/lib/metadata.ts`):
|
||||
- Accepts CMS seo object + fallback to Site Settings defaults
|
||||
- Returns Next.js `Metadata` object
|
||||
- Handles: title, description, OG image, canonical URL
|
||||
- [ ] **Open Graph image generation** (`src/app/og/route.tsx`):
|
||||
- Dynamic OG images for blog posts using `@vercel/og`
|
||||
- Template: Axil logo + post title + sage green background
|
||||
- [ ] **Structured data helpers** (`src/lib/structured-data.ts`):
|
||||
- `LocalBusiness` schema (name, address, phone, opening hours)
|
||||
- `AccountingService` schema
|
||||
- `FAQPage` schema (for service pages)
|
||||
- `BlogPosting` schema (for blog articles)
|
||||
- Injected via `<script type="application/ld+json">` in page `<head>`
|
||||
- [ ] **`sitemap.ts`** (`src/app/sitemap.ts`):
|
||||
- Fetches all published blog posts + service slugs from Payload
|
||||
- Returns `MetadataRoute.Sitemap` array
|
||||
- Revalidates on ISR
|
||||
- [ ] **`robots.ts`** (`src/app/robots.ts`):
|
||||
- Allow all crawlers
|
||||
- Point to sitemap
|
||||
- Block `/admin/*`
|
||||
- [ ] Verify all pages have correct `<title>` tags in browser devtools
|
||||
|
||||
---
|
||||
|
||||
## Feature 27 — Analytics, Tracking & Cookie Consent
|
||||
|
||||
- [ ] **`AnalyticsProvider` component** (`src/components/AnalyticsProvider.tsx`):
|
||||
- Reads GA ID, GTM ID, FB Pixel ID from CMS Site Settings
|
||||
- Conditionally loads scripts only after cookie consent granted
|
||||
- [ ] **Google Tag Manager** integration:
|
||||
- `<Script>` in `<head>` and `<noscript>` in `<body>`
|
||||
- Only loads after consent
|
||||
- [ ] **Cookie consent banner** (`src/components/CookieBanner.tsx`):
|
||||
- GDPR / UK GDPR compliant
|
||||
- Framer Motion: slides up from bottom on first visit
|
||||
- Buttons: "Accept All" | "Reject Non-Essential" | "Manage Preferences"
|
||||
- Stores consent in `localStorage`
|
||||
- Triggers analytics scripts on accept
|
||||
- [ ] **`useConsent` hook** — reads/writes consent state, exposes `hasConsent(category)`
|
||||
- [ ] **Custom code injection** from CMS Site Settings:
|
||||
- `headerScripts` — injected in `<head>` via Next.js root layout
|
||||
- `footerScripts` — injected before `</body>`
|
||||
|
||||
---
|
||||
|
||||
## Feature 28 — Form Builder Frontend Renderer
|
||||
|
||||
Allows any Payload-built form to be rendered on the frontend.
|
||||
|
||||
- [ ] **`FormRenderer` component** (`src/components/cms/FormRenderer.tsx`):
|
||||
- Accepts `formId` prop (Payload form document ID or slug)
|
||||
- Fetches form schema from Payload API
|
||||
- Dynamically renders all field types:
|
||||
- `text`, `email`, `phone`, `textarea` → `<input>` / `<textarea>`
|
||||
- `select` → `<select>` or custom dropdown
|
||||
- `checkbox` → styled checkbox
|
||||
- React Hook Form + Zod validation from field config (required, type)
|
||||
- [ ] **`FormField` component** — renders individual field with label, input, error message
|
||||
- [ ] **Submit handler**: `POST /api/form-submissions`
|
||||
- Saves to Payload FormSubmissions
|
||||
- Triggers email + webhook from form config
|
||||
- [ ] Success / error UI states
|
||||
- [ ] Usage: embed `<FormRenderer formId="..." />` anywhere on any CMS-managed page
|
||||
|
||||
---
|
||||
|
||||
## Feature 29 — Performance Optimisation
|
||||
|
||||
- [ ] All images use `next/image` with correct `sizes` prop and `priority` for LCP images
|
||||
- [ ] `next/font` for Inter + DM Mono (eliminates layout shift from font load)
|
||||
- [ ] **Dynamic imports** for heavy components:
|
||||
- `GlobeScene` — `dynamic(() => import(...), { ssr: false })`
|
||||
- `ChatWidget` — `dynamic(() => import(...), { ssr: false })`
|
||||
- Lexical renderer — `dynamic` import
|
||||
- [ ] **ISR** (Incremental Static Regeneration):
|
||||
- Service pages: `revalidate = 86400` (24h)
|
||||
- Blog posts: `revalidate = 3600` (1h)
|
||||
- Homepage: `revalidate = 3600`
|
||||
- [ ] Install `@next/bundle-analyzer`, run bundle analysis, eliminate large dependencies
|
||||
- [ ] Lazy-load all sections below fold (Intersection Observer or Next.js `loading="lazy"`)
|
||||
- [ ] Verify no unused CSS (Tailwind PurgeCSS is automatic)
|
||||
- [ ] Run Lighthouse on all key pages — target: Performance 95+, SEO 100, Accessibility 95+
|
||||
- [ ] Fix any Lighthouse findings before delivery
|
||||
|
||||
---
|
||||
|
||||
## Feature 30 — Accessibility Audit & Fixes
|
||||
|
||||
- [ ] Add `<a href="#main-content">Skip to content</a>` as first focusable element
|
||||
- [ ] Verify all interactive elements are keyboard-navigable (Tab, Enter, Escape)
|
||||
- [ ] All images have meaningful `alt` text (enforced by Payload Media collection)
|
||||
- [ ] All form fields have associated `<label>` elements
|
||||
- [ ] All icon-only buttons have `aria-label`
|
||||
- [ ] Modals: focus trap, `role="dialog"`, `aria-modal`, return focus on close
|
||||
- [ ] Navigation dropdowns: `aria-expanded`, `aria-haspopup`
|
||||
- [ ] Colour contrast: check all text/background combos meet WCAG AA (4.5:1 body, 3:1 large text)
|
||||
- [ ] Test with screen reader (VoiceOver / NVDA)
|
||||
- [ ] Verify `prefers-reduced-motion` disables all non-essential animations
|
||||
|
||||
---
|
||||
|
||||
## Feature 31 — Responsive Design QA
|
||||
|
||||
- [ ] Test every page at: `320px`, `375px`, `414px`, `768px`, `1024px`, `1280px`, `1440px`, `1920px`
|
||||
- [ ] Verify 3D scene: WebGL on desktop, SVG fallback on mobile
|
||||
- [ ] Verify hamburger menu: opens, nav links work, closes correctly
|
||||
- [ ] Verify booking modal: fills screen on mobile, scrollable content
|
||||
- [ ] Verify all form fields usable with touch keyboard (no content hidden behind keyboard)
|
||||
- [ ] Verify testimonials marquee / carousel: touch-swipeable on mobile
|
||||
- [ ] Verify blog grid: 1-column on mobile, readable font sizes
|
||||
- [ ] Verify footer: stacks correctly on mobile
|
||||
|
||||
---
|
||||
|
||||
## Feature 32 — Error Handling & Monitoring
|
||||
|
||||
- [ ] **Sentry** setup (`@sentry/nextjs`):
|
||||
- Install and configure with `SENTRY_DSN`
|
||||
- Client + server + edge error capture
|
||||
- Source maps upload on build
|
||||
- [ ] **Custom 404 page** (`src/app/not-found.tsx`):
|
||||
- Brand-styled, helpful message
|
||||
- Links back to home + contact
|
||||
- [ ] **Custom 500 page** (`src/app/error.tsx`):
|
||||
- Brand-styled error page
|
||||
- Reports error to Sentry
|
||||
- [ ] All API routes return proper HTTP status codes + JSON error bodies
|
||||
- [ ] Form submission error states: clear per-field errors + general fallback
|
||||
- [ ] Payload API fetch failures: graceful degradation (show fallback content, not crash)
|
||||
|
||||
---
|
||||
|
||||
## Feature 33 — Deployment & CI/CD
|
||||
|
||||
- [ ] Configure Vercel project settings:
|
||||
- Build command: `pnpm build`
|
||||
- Output directory: `.next`
|
||||
- Node.js version: 20.x
|
||||
- [ ] Add all production environment variables to Vercel dashboard
|
||||
- [ ] Configure **preview deployments**: auto-deploy on every PR to `develop`
|
||||
- [ ] Configure **production deployment**: auto-deploy on merge to `main`
|
||||
- [ ] Set up custom domain (e.g. `axilaccountants.co.uk`) in Vercel
|
||||
- [ ] Verify SSL/HTTPS certificate
|
||||
- [ ] Configure `www` → apex redirect (or vice versa)
|
||||
- [ ] Run production build locally (`pnpm build && pnpm start`) — verify no build errors
|
||||
- [ ] Run Lighthouse on production URL — confirm scores meet targets
|
||||
- [ ] Set up Vercel Speed Insights (optional)
|
||||
|
||||
---
|
||||
|
||||
## Feature 34 — Content Seeding & CMS Setup
|
||||
|
||||
- [ ] Create seed script (`src/payload/seed.ts`):
|
||||
- Site Settings: company name, logo, contact details, placeholder social URLs
|
||||
- 4 Services: Bookkeeping, Tax Returns, Payroll, VAT Returns (full content per service)
|
||||
- 3 Sample Testimonials (marked as featured)
|
||||
- 3 FAQs per service
|
||||
- Blog Categories: "Tax Tips", "Business Advice", "HMRC Updates", "Payroll Guide"
|
||||
- Navigation: full nav structure from concept
|
||||
- Footer: all columns with links
|
||||
- [ ] Run seed script against production database
|
||||
- [ ] Verify all seeded content displays correctly on frontend
|
||||
- [ ] Create CMS editor user account for client
|
||||
|
||||
---
|
||||
|
||||
## Feature 35 — Client Handover & Documentation
|
||||
|
||||
- [ ] **CMS User Guide** (`docs/cms-guide.md`):
|
||||
- How to log into the admin panel
|
||||
- How to edit page content (services, hero text, etc.)
|
||||
- How to write and publish a blog post
|
||||
- How to add a testimonial
|
||||
- How to add a team member
|
||||
- How to create a contact form
|
||||
- How to set up a webhook on a form
|
||||
- How to change the chat bot mode
|
||||
- How to update integration settings (GA, GTM, Calendly URL)
|
||||
- [ ] **Handover checklist**:
|
||||
- [ ] Client has admin login credentials
|
||||
- [ ] Client has Vercel access (viewer role)
|
||||
- [ ] Client has Resend account access (for email settings)
|
||||
- [ ] DNS properly pointing to Vercel
|
||||
- [ ] Google Analytics connected and receiving data
|
||||
- [ ] Booking form submissions arriving in CMS + email
|
||||
- [ ] Mobile tested on real device (iPhone + Android)
|
||||
- [ ] Lighthouse scores confirmed ≥ 95 Performance
|
||||
|
||||
---
|
||||
|
||||
## Summary: Feature Dependency Order
|
||||
|
||||
```
|
||||
Feature 1 (Project Setup)
|
||||
└── Feature 2 (Database)
|
||||
└── Feature 3 (Payload CMS Core)
|
||||
└── Feature 4 (CMS Collections Schema)
|
||||
├── Feature 5 (Design System) ← parallel from here
|
||||
├── Feature 6 (Animation Infrastructure)
|
||||
└── Feature 7 + 8 (Header + Footer)
|
||||
└── Feature 9 (3D Scene)
|
||||
└── Feature 10 (Hero Section)
|
||||
└── Features 11–18 (Home Page Sections)
|
||||
└── Feature 19 (Booking Modal) ← needed by all CTAs
|
||||
├── Feature 20 (Services Pages)
|
||||
├── Feature 21 (About Page)
|
||||
├── Feature 22 (Blog)
|
||||
├── Feature 23 (Contact Page)
|
||||
└── Feature 24 (Legal Pages)
|
||||
├── Feature 25 (Chat Bot)
|
||||
├── Feature 26 (SEO)
|
||||
├── Feature 27 (Analytics)
|
||||
├── Feature 28 (Form Renderer)
|
||||
├── Feature 29 (Performance)
|
||||
├── Feature 30 (Accessibility)
|
||||
├── Feature 31 (Responsive QA)
|
||||
├── Feature 32 (Error Handling)
|
||||
└── Feature 33 (Deployment)
|
||||
├── Feature 34 (Content Seed)
|
||||
└── Feature 35 (Handover)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_Total features: 35 | Estimated tasks: ~220_
|
||||
_Last updated: February 2026_
|
||||
7
next.config.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import type { NextConfig } from 'next';
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: 'standalone',
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
32
package.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "axil-accountants",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "eslint",
|
||||
"format": "prettier --write .",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "16.1.6",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "^4",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.1.6",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.7",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
4375
pnpm-lock.yaml
generated
Normal file
3
pnpm-workspace.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
ignoredBuiltDependencies:
|
||||
- sharp
|
||||
- unrs-resolver
|
||||
7
postcss.config.mjs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
const config = {
|
||||
plugins: {
|
||||
'@tailwindcss/postcss': {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
1
public/file.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 391 B |
1
public/globe.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1 KiB |
1
public/next.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
public/vercel.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 128 B |
1
public/window.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
After Width: | Height: | Size: 385 B |
BIN
src/app/favicon.ico
Normal file
|
After Width: | Height: | Size: 25 KiB |
26
src/app/globals.css
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
@import 'tailwindcss';
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
30
src/app/layout.tsx
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import type { Metadata } from 'next';
|
||||
import { Geist, Geist_Mono } from 'next/font/google';
|
||||
import './globals.css';
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: '--font-geist-sans',
|
||||
subsets: ['latin'],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: '--font-geist-mono',
|
||||
subsets: ['latin'],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Create Next App',
|
||||
description: 'Generated by create next app',
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
65
src/app/page.tsx
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import Image from 'next/image';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
||||
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between bg-white px-16 py-32 sm:items-start dark:bg-black">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
/>
|
||||
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
||||
<h1 className="max-w-xs text-3xl leading-10 font-semibold tracking-tight text-black dark:text-zinc-50">
|
||||
To get started, edit the page.tsx file.
|
||||
</h1>
|
||||
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
||||
Looking for a starting point or more instructions? Head over to{' '}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Templates
|
||||
</a>{' '}
|
||||
or the{' '}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Learning
|
||||
</a>{' '}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
||||
<a
|
||||
className="bg-foreground text-background flex h-12 w-full items-center justify-center gap-2 rounded-full px-5 transition-colors hover:bg-[#383838] md:w-[158px] dark:hover:bg-[#ccc]"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] md:w-[158px] dark:border-white/[.145] dark:hover:bg-[#1a1a1a]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
0
src/components/cms/.gitkeep
Normal file
0
src/components/layout/.gitkeep
Normal file
0
src/components/sections/.gitkeep
Normal file
0
src/components/three/.gitkeep
Normal file
0
src/components/ui/.gitkeep
Normal file
0
src/hooks/.gitkeep
Normal file
0
src/lib/.gitkeep
Normal file
0
src/payload/.gitkeep
Normal file
0
src/types/.gitkeep
Normal file
34
tsconfig.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts",
|
||||
"**/*.mts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||