add AI-generated landing page photography (Gemini 3 Pro)

20 images generated via gemini-3-pro-image-preview (Nano Banana Pro):
- Documentary street photography style, British-diverse subjects
- 12 square (1:1), 8 landscape (16:9) matching placeholder aspect ratios
- Replaced all ImagePlaceholder components with LandingImage + next/image
- Images in public/images/landing/, served statically

Pages updated: /, /for/charities, /for/fundraisers, /for/volunteers, /for/organisations
New component: LandingImage (next/image with fill + object-cover)
This commit is contained in:
2026-03-03 19:27:36 +08:00
parent 581f1e5f14
commit f4ad6df45a
27 changed files with 182 additions and 29 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 KiB

View File

@@ -1,4 +1,5 @@
import Link from "next/link"
import Image from "next/image"
/* ── Nav ── */
export function Nav() {
@@ -79,7 +80,24 @@ export function BottomCta({ headline, sub }: { headline?: string; sub?: string }
)
}
/* ── Image Placeholder ── */
/* ── Landing Image ── */
export function LandingImage({ src, alt, aspect = "video" }: { src: string; alt: string; aspect?: "video" | "square" | "wide" }) {
const aspectClass = aspect === "square" ? "aspect-square" : aspect === "wide" ? "aspect-[2/1]" : "aspect-video"
return (
<div className={`${aspectClass} w-full relative overflow-hidden bg-gray-100`}>
<Image
src={src}
alt={alt}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, 50vw"
quality={85}
/>
</div>
)
}
/* ── Image Placeholder (kept as fallback) ── */
export function ImagePlaceholder({ aspect = "video", label }: { aspect?: "video" | "square" | "wide"; label?: string }) {
const aspectClass = aspect === "square" ? "aspect-square" : aspect === "wide" ? "aspect-[2/1]" : "aspect-video"
return (

View File

@@ -1,5 +1,5 @@
import Link from "next/link"
import { Nav, Footer, BottomCta, ImagePlaceholder } from "../_components"
import { Nav, Footer, BottomCta, LandingImage } from "../_components"
export default function ForCharitiesPage() {
return (
@@ -26,7 +26,7 @@ export default function ForCharitiesPage() {
</Link>
</div>
</div>
<ImagePlaceholder aspect="square" label="Charity manager reviewing dashboard on laptop at event" />
<LandingImage src="/images/landing/08-charities-hero.jpg" alt="Charity manager reviewing dashboard on laptop at mosque fundraising event" aspect="square" />
</div>
</section>
@@ -49,7 +49,7 @@ export default function ForCharitiesPage() {
</div>
</section>
{/* ── How it works — with image ── */}
{/* ── How it works — with images ── */}
<section className="py-24 px-6">
<div className="max-w-5xl mx-auto grid md:grid-cols-2 gap-16 items-start">
<div>
@@ -73,8 +73,8 @@ export default function ForCharitiesPage() {
</div>
</div>
<div className="space-y-6">
<ImagePlaceholder aspect="square" label="Mobile pledge form — amount selection" />
<ImagePlaceholder aspect="video" label="WhatsApp reminder conversation" />
<LandingImage src="/images/landing/09-charities-amount-selection.jpg" alt="Hand holding phone at charity dinner table showing pledge amount selection" aspect="square" />
<LandingImage src="/images/landing/10-charities-whatsapp.jpg" alt="Woman on sofa viewing WhatsApp pledge reminder conversation" aspect="video" />
</div>
</div>
</section>

View File

@@ -1,5 +1,5 @@
import Link from "next/link"
import { Nav, Footer, BottomCta, ImagePlaceholder } from "../_components"
import { Nav, Footer, BottomCta, LandingImage } from "../_components"
export default function ForFundraisersPage() {
return (
@@ -26,7 +26,7 @@ export default function ForFundraisersPage() {
</Link>
</div>
</div>
<ImagePlaceholder aspect="square" label="Fundraiser sharing pledge link on phone" />
<LandingImage src="/images/landing/11-fundraisers-hero.jpg" alt="Fundraiser sharing pledge link on phone with friend on London high street" aspect="square" />
</div>
</section>
@@ -73,8 +73,8 @@ export default function ForFundraisersPage() {
</div>
</div>
<div className="space-y-6">
<ImagePlaceholder aspect="square" label="External redirect — branded LaunchGood handoff" />
<ImagePlaceholder aspect="video" label="Pledge tracking dashboard conversion funnel" />
<LandingImage src="/images/landing/12-fundraisers-redirect.jpg" alt="Hands holding phone in café showing fundraising page redirect" aspect="square" />
<LandingImage src="/images/landing/13-fundraisers-dashboard.jpg" alt="Laptop showing pledge tracking dashboard with conversion funnel" aspect="video" />
</div>
</div>
</section>

View File

@@ -1,5 +1,5 @@
import Link from "next/link"
import { Nav, Footer, BottomCta, ImagePlaceholder } from "../_components"
import { Nav, Footer, BottomCta, LandingImage } from "../_components"
export default function ForOrganisationsPage() {
return (
@@ -26,7 +26,7 @@ export default function ForOrganisationsPage() {
</Link>
</div>
</div>
<ImagePlaceholder aspect="square" label="Multi-org pledge pipeline — boardroom view" />
<LandingImage src="/images/landing/17-orgs-hero-boardroom.jpg" alt="Three people in charity office meeting room discussing pledge pipeline" aspect="square" />
</div>
</section>
@@ -74,8 +74,8 @@ export default function ForOrganisationsPage() {
</div>
</div>
<div className="space-y-6">
<ImagePlaceholder aspect="square" label="Pipeline view — pledges by organisation" />
<ImagePlaceholder aspect="video" label="Instalment schedule — multi-month commitment" />
<LandingImage src="/images/landing/18-orgs-pipeline.jpg" alt="Laptop showing Kanban-style pledge pipeline view by organisation" aspect="square" />
<LandingImage src="/images/landing/19-orgs-instalment-schedule.jpg" alt="Laptop showing instalment schedule with monthly progress bars" aspect="video" />
</div>
</div>
</section>
@@ -83,7 +83,7 @@ export default function ForOrganisationsPage() {
{/* ── Why this works ── */}
<section className="py-24 bg-gray-50 px-6">
<div className="max-w-5xl mx-auto grid md:grid-cols-2 gap-12 items-center">
<ImagePlaceholder aspect="square" label="Organisation dashboard — commitment tracking" />
<LandingImage src="/images/landing/20-orgs-laptop-desk.jpg" alt="Laptop on charity office desk showing commitment tracking dashboard" aspect="square" />
<div>
<h2 className="text-3xl font-black text-gray-900 tracking-tight mb-8">Spreadsheets don&apos;t send reminders</h2>
<div className="space-y-5">

View File

@@ -1,5 +1,5 @@
import Link from "next/link"
import { Nav, Footer, ImagePlaceholder } from "../_components"
import { Nav, Footer, LandingImage } from "../_components"
export default function ForVolunteersPage() {
return (
@@ -26,7 +26,7 @@ export default function ForVolunteersPage() {
</Link>
</div>
</div>
<ImagePlaceholder aspect="square" label="Volunteer at event table with QR code stand" />
<LandingImage src="/images/landing/14-volunteers-hero.jpg" alt="Volunteer at charity dinner table with QR code stand" aspect="square" />
</div>
</section>
@@ -72,8 +72,8 @@ export default function ForVolunteersPage() {
</div>
</div>
<div className="space-y-6">
<ImagePlaceholder aspect="square" label="Volunteer stats — live pledge counter on mobile" />
<ImagePlaceholder aspect="video" label="Leaderboard — top collectors" />
<LandingImage src="/images/landing/15-volunteers-phone-stats.jpg" alt="Volunteer holding phone showing live pledge counter at event" aspect="square" />
<LandingImage src="/images/landing/16-volunteers-leaderboard.jpg" alt="Phone showing volunteer leaderboard with rankings" aspect="video" />
</div>
</div>
</section>

View File

@@ -1,5 +1,5 @@
import Link from "next/link"
import { Nav, Footer, BottomCta, ImagePlaceholder } from "./for/_components"
import { Nav, Footer, BottomCta, LandingImage } from "./for/_components"
const PERSONAS = [
{
@@ -7,28 +7,28 @@ const PERSONAS = [
title: "Charity Manager",
oneLiner: "You raise pledges at events. We make sure the money actually arrives.",
tags: ["Dashboard", "WhatsApp reminders", "Gift Aid", "Zakat", "HMRC export"],
image: "charity-manager-gala-dinner",
image: "/images/landing/02-main-charity-manager-card.jpg",
},
{
slug: "fundraisers",
title: "Personal Fundraiser",
oneLiner: "You share a LaunchGood or JustGiving link. We track who actually donates.",
tags: ["LaunchGood", "Enthuse", "JustGiving", "Social sharing", "Conversion tracking"],
image: "fundraiser-sharing-phone",
image: "/images/landing/03-main-fundraiser-card.jpg",
},
{
slug: "volunteers",
title: "Volunteer",
oneLiner: "You help collect pledges at events. We show you exactly how much you raised.",
tags: ["Personal link", "Live stats", "Leaderboard", "WhatsApp share"],
image: "volunteer-event-table",
image: "/images/landing/04-main-volunteer-card.jpg",
},
{
slug: "organisations",
title: "Organisation",
oneLiner: "You coordinate pledges across multiple charities or departments. We track every commitment.",
tags: ["Multi-party", "Fund allocation", "Pipeline view", "Instalments"],
image: "org-boardroom-meeting",
image: "/images/landing/05-main-org-card.jpg",
},
]
@@ -62,10 +62,10 @@ export default function HomePage() {
</div>
</section>
{/* ── Hero image placeholder ── */}
{/* ── Hero image ── */}
<section className="px-6 pb-20">
<div className="max-w-5xl mx-auto">
<ImagePlaceholder aspect="video" label="Dashboard screenshot — live pledge pipeline" />
<LandingImage src="/images/landing/01-main-dashboard-hero.jpg" alt="Charity analytics dashboard showing live pledge pipeline" aspect="video" />
</div>
</section>
@@ -97,7 +97,7 @@ export default function HomePage() {
href={`/for/${p.slug}`}
className="group block bg-white border border-gray-200 hover:border-gray-900 transition-colors"
>
<ImagePlaceholder aspect="video" label={p.image} />
<LandingImage src={p.image} alt={p.title} aspect="video" />
<div className="p-6 space-y-3">
<h3 className="text-lg font-black text-gray-900 group-hover:text-trust-blue transition-colors">{p.title}</h3>
<p className="text-sm text-gray-500 leading-relaxed">{p.oneLiner}</p>
@@ -142,7 +142,7 @@ export default function HomePage() {
{/* ── Split: Image + compliance ── */}
<section className="py-24 px-6">
<div className="max-w-5xl mx-auto grid md:grid-cols-2 gap-12 items-center">
<ImagePlaceholder aspect="square" label="Pledge form Gift Aid, Zakat, consent checkboxes" />
<LandingImage src="/images/landing/06-main-pledge-form.jpg" alt="Person holding phone showing pledge form with Gift Aid and consent checkboxes" aspect="square" />
<div className="space-y-8">
<div>
<h2 className="text-3xl font-black text-gray-900 tracking-tight">Compliance is not optional</h2>
@@ -184,7 +184,7 @@ export default function HomePage() {
</div>
</div>
<div className="order-1 md:order-2">
<ImagePlaceholder aspect="square" label="Schedule step — now, date, monthly options" />
<LandingImage src="/images/landing/07-main-schedule-step.jpg" alt="Hands holding phone at kitchen table showing payment schedule options" aspect="square" />
</div>
</div>
</section>