Redesign landing page from Canva brief
This commit is contained in:
@@ -4,7 +4,7 @@ title: Redesign dev website from Canva reference
|
||||
status: In Progress
|
||||
assignee: []
|
||||
created_date: '2026-05-05 20:20'
|
||||
updated_date: '2026-05-05 20:25'
|
||||
updated_date: '2026-05-05 20:32'
|
||||
labels: []
|
||||
dependencies: []
|
||||
priority: high
|
||||
@@ -19,7 +19,7 @@ Create an isolated worktree and redesign the regional dev landing page to match
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [x] #1 A new git worktree exists under .worktrees for the redesign branch
|
||||
- [ ] #2 The landing page visual style follows the provided Canva reference
|
||||
- [x] #2 The landing page visual style follows the provided Canva reference
|
||||
- [x] #3 The Astro site builds successfully
|
||||
- [ ] #4 The redesigned page is reviewed locally before handoff
|
||||
<!-- AC:END -->
|
||||
@@ -38,4 +38,6 @@ Create an isolated worktree and redesign the regional dev landing page to match
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
Created worktree at .worktrees/canva-redesign on branch codex/canva-redesign. Baseline build passes with CI=true pnpm run build after approving dependency build scripts.
|
||||
|
||||
Implemented a consolidated Canva-inspired landing page in src/components/canva-landing.tsx and switched src/pages/index.astro to it. Smoke test and CI=true pnpm run build pass. Local dev server responds with HTTP 200 at http://127.0.0.1:4321/. Browser screenshot tooling is not available in this session, so visual review remains open.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
41
docs/superpowers/plans/2026-05-05-canva-redesign.md
Normal file
41
docs/superpowers/plans/2026-05-05-canva-redesign.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Canva Redesign Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Rework the dev landing page into a bold black, red, and white editorial site inspired by the Canva creative brief deck.
|
||||
|
||||
**Architecture:** Replace the current stacked section imports on the homepage with one focused React landing component. Keep existing UI primitives available but avoid broad refactors of old sections so the redesign remains easy to review or revert.
|
||||
|
||||
**Tech Stack:** Astro 6, React 19, Tailwind CSS 4, lucide-react, Node test runner.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Landing Smoke Test
|
||||
|
||||
**Files:**
|
||||
- Create: `tests/landing-content.test.mjs`
|
||||
- Modify: `package.json`
|
||||
|
||||
- [x] Add a Node smoke test that checks the new component source for key content anchors: `Projektbrief`, `01`, `Website`, `Kontakt`.
|
||||
- [x] Run `node --test tests/landing-content.test.mjs` and confirm it fails before the component exists.
|
||||
|
||||
### Task 2: Canva-Inspired Landing Page
|
||||
|
||||
**Files:**
|
||||
- Create: `src/components/canva-landing.tsx`
|
||||
- Modify: `src/pages/index.astro`
|
||||
- Modify: `src/styles/global.css`
|
||||
|
||||
- [ ] Build a single-page layout with a dark editorial shell, red accent panels, large German headline, numbered sections, pricing/service strips, and a contact brief section.
|
||||
- [ ] Replace the existing homepage component stack with the new `CanvaLanding` component.
|
||||
- [ ] Update global tokens for the dark, high-contrast Canva reference style.
|
||||
|
||||
### Task 3: Verification
|
||||
|
||||
**Files:**
|
||||
- Modify: `backlog/tasks/task-1 - Redesign-dev-website-from-Canva-reference.md`
|
||||
|
||||
- [ ] Run `node --test tests/landing-content.test.mjs` and confirm it passes.
|
||||
- [ ] Run `CI=true pnpm run build` and confirm Astro builds the page.
|
||||
- [ ] Start the local dev server and visually review the page in a browser/screenshot.
|
||||
- [ ] Check off remaining acceptance criteria that have direct evidence.
|
||||
250
src/components/canva-landing.tsx
Normal file
250
src/components/canva-landing.tsx
Normal file
@@ -0,0 +1,250 @@
|
||||
import {
|
||||
ArrowUpRight,
|
||||
Check,
|
||||
CornerDownRight,
|
||||
Mail,
|
||||
MapPin,
|
||||
Phone,
|
||||
} from "lucide-react";
|
||||
|
||||
const services = [
|
||||
{
|
||||
number: "01",
|
||||
title: "Website",
|
||||
text: "Eine klare Startseite oder ein kompletter Auftritt, der sofort zeigt, warum man Ihnen vertrauen kann.",
|
||||
},
|
||||
{
|
||||
number: "02",
|
||||
title: "Struktur",
|
||||
text: "Angebot, Beweise, Ablauf und Kontakt werden so sortiert, dass Besucher nicht suchen muessen.",
|
||||
},
|
||||
{
|
||||
number: "03",
|
||||
title: "Technik",
|
||||
text: "Schnell, mobil sauber, DSGVO-arm und so gebaut, dass spaetere Aenderungen nicht zum Projekt werden.",
|
||||
},
|
||||
];
|
||||
|
||||
const deliverables = [
|
||||
"Strategie und Seitenstruktur",
|
||||
"Individuelles Screen-Design",
|
||||
"Astro/React Umsetzung",
|
||||
"Kontaktformular und Datenschutz",
|
||||
"Hosting, Wartung und Analytics",
|
||||
];
|
||||
|
||||
const packages = [
|
||||
{
|
||||
name: "Basis",
|
||||
price: "799 EUR",
|
||||
detail: "Eine starke Seite fuer ein klares Angebot.",
|
||||
},
|
||||
{
|
||||
name: "Profi",
|
||||
price: "1.499 EUR",
|
||||
detail: "Mehrere Seiten fuer Betriebe mit erklaerungsbeduerftigem Angebot.",
|
||||
},
|
||||
{
|
||||
name: "Massarbeit",
|
||||
price: "2.499 EUR+",
|
||||
detail: "Individuelle Struktur, CMS und besondere Anforderungen.",
|
||||
},
|
||||
];
|
||||
|
||||
const CanvaLanding = () => {
|
||||
return (
|
||||
<main className="min-h-screen overflow-hidden bg-background text-foreground">
|
||||
<section className="relative grid min-h-screen grid-cols-1 border-b border-border lg:grid-cols-[1.08fr_0.92fr]">
|
||||
<div className="flex min-h-[640px] flex-col justify-between px-5 py-5 sm:px-8 lg:px-12">
|
||||
<header className="grid gap-4 border-b border-border pb-5 text-xs uppercase tracking-[0.28em] text-muted-foreground sm:grid-cols-[1fr_auto]">
|
||||
<a href="/" className="font-semibold text-foreground">
|
||||
Matthias Meister
|
||||
</a>
|
||||
<nav className="flex flex-wrap gap-5">
|
||||
<a href="#leistungen">Leistungen</a>
|
||||
<a href="#pakete">Pakete</a>
|
||||
<a href="#kontakt">Kontakt</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<div className="max-w-5xl py-16 sm:py-20 lg:py-24">
|
||||
<p className="mb-6 max-w-sm text-sm uppercase tracking-[0.32em] text-primary">
|
||||
Projektbrief fuer regionale Unternehmen
|
||||
</p>
|
||||
<h1 className="max-w-[11ch] text-[clamp(4.25rem,13vw,11.5rem)] font-black uppercase leading-[0.78] tracking-normal text-foreground">
|
||||
Website ohne Umweg
|
||||
</h1>
|
||||
<div className="mt-8 grid gap-7 border-t border-border pt-7 lg:grid-cols-[0.72fr_1fr]">
|
||||
<p className="text-sm uppercase tracking-[0.24em] text-muted-foreground">
|
||||
Strategie trifft Umsetzung
|
||||
</p>
|
||||
<p className="max-w-2xl text-lg leading-8 text-foreground/78">
|
||||
Ich baue Websites fuer Handwerk, Praxen, Salons und
|
||||
Dienstleister aus der Region. Direkt, glaubwuerdig und so
|
||||
reduziert, dass der naechste Kontakt naheliegt.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 border-t border-border pt-5 text-sm uppercase tracking-[0.2em] text-muted-foreground sm:grid-cols-3">
|
||||
<span>Antwort in 24h</span>
|
||||
<span>DSGVO-arm</span>
|
||||
<span>Hosting aus DE</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside className="relative flex min-h-[520px] flex-col justify-between bg-primary px-5 py-5 text-primary-foreground sm:px-8 lg:px-12">
|
||||
<div className="flex items-start justify-between border-b border-primary-foreground/30 pb-5 text-xs uppercase tracking-[0.28em]">
|
||||
<span>Creative Direction</span>
|
||||
<span>2026</span>
|
||||
</div>
|
||||
<div className="absolute left-0 top-28 h-28 w-28 bg-background" />
|
||||
<div className="absolute bottom-32 right-10 h-36 w-36 border border-primary-foreground/35" />
|
||||
<div className="relative mt-28 max-w-xl">
|
||||
<p className="text-[clamp(4rem,10vw,9rem)] font-black uppercase leading-[0.75] tracking-normal">
|
||||
01
|
||||
</p>
|
||||
<p className="mt-7 max-w-sm text-2xl font-semibold uppercase leading-none">
|
||||
Klarer Auftritt. Harte Kante. Weniger Agenturlaerm.
|
||||
</p>
|
||||
</div>
|
||||
<a
|
||||
href="#kontakt"
|
||||
className="group inline-flex w-fit items-center gap-3 border border-primary-foreground px-5 py-4 text-sm font-semibold uppercase tracking-[0.18em] transition hover:bg-primary-foreground hover:text-primary"
|
||||
>
|
||||
Projekt anfragen
|
||||
<ArrowUpRight className="size-5 transition group-hover:-translate-y-0.5 group-hover:translate-x-0.5" />
|
||||
</a>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="leistungen"
|
||||
className="grid border-b border-border lg:grid-cols-[0.36fr_0.64fr]"
|
||||
>
|
||||
<div className="border-b border-border px-5 py-12 sm:px-8 lg:border-b-0 lg:border-r lg:px-12 lg:py-20">
|
||||
<p className="text-sm uppercase tracking-[0.3em] text-primary">
|
||||
Leistungen (02)
|
||||
</p>
|
||||
<h2 className="mt-6 max-w-[9ch] text-5xl font-black uppercase leading-[0.86] sm:text-7xl">
|
||||
Vom Brief zur Seite
|
||||
</h2>
|
||||
</div>
|
||||
<div className="divide-y divide-border">
|
||||
{services.map((service) => (
|
||||
<article
|
||||
key={service.number}
|
||||
className="grid gap-8 px-5 py-10 sm:px-8 md:grid-cols-[7rem_0.4fr_1fr] lg:px-12"
|
||||
>
|
||||
<span className="text-5xl font-black text-primary">
|
||||
{service.number}
|
||||
</span>
|
||||
<h3 className="text-3xl font-black uppercase leading-none">
|
||||
{service.title}
|
||||
</h3>
|
||||
<p className="max-w-2xl text-lg leading-8 text-muted-foreground">
|
||||
{service.text}
|
||||
</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="grid border-b border-border lg:grid-cols-2">
|
||||
<div className="bg-foreground px-5 py-14 text-background sm:px-8 lg:px-12 lg:py-24">
|
||||
<p className="text-sm uppercase tracking-[0.3em] text-primary">
|
||||
Deliverables (03)
|
||||
</p>
|
||||
<h2 className="mt-8 max-w-[10ch] text-5xl font-black uppercase leading-[0.86] sm:text-7xl">
|
||||
Was am Ende steht
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid content-center gap-4 px-5 py-12 sm:px-8 lg:px-12">
|
||||
{deliverables.map((item) => (
|
||||
<div
|
||||
key={item}
|
||||
className="flex items-center gap-4 border-b border-border pb-4 text-lg font-semibold uppercase tracking-[0.08em]"
|
||||
>
|
||||
<Check className="size-5 text-primary" />
|
||||
<span>{item}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="pakete" className="border-b border-border px-5 py-14 sm:px-8 lg:px-12 lg:py-24">
|
||||
<div className="grid gap-8 lg:grid-cols-[0.45fr_0.55fr]">
|
||||
<div>
|
||||
<p className="text-sm uppercase tracking-[0.3em] text-primary">
|
||||
Pakete (04)
|
||||
</p>
|
||||
<h2 className="mt-8 max-w-[9ch] text-5xl font-black uppercase leading-[0.86] sm:text-7xl">
|
||||
Kosten ohne Nebel
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid gap-4">
|
||||
{packages.map((item) => (
|
||||
<article
|
||||
key={item.name}
|
||||
className="grid gap-4 border border-border p-5 sm:grid-cols-[0.5fr_0.5fr] sm:p-6"
|
||||
>
|
||||
<div>
|
||||
<p className="text-sm uppercase tracking-[0.24em] text-primary">
|
||||
{item.name}
|
||||
</p>
|
||||
<p className="mt-4 text-4xl font-black uppercase">
|
||||
{item.price}
|
||||
</p>
|
||||
</div>
|
||||
<p className="self-end text-lg leading-7 text-muted-foreground">
|
||||
{item.detail}
|
||||
</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="kontakt"
|
||||
className="grid min-h-[620px] lg:grid-cols-[0.72fr_0.28fr]"
|
||||
>
|
||||
<div className="px-5 py-14 sm:px-8 lg:px-12 lg:py-24">
|
||||
<p className="text-sm uppercase tracking-[0.3em] text-primary">
|
||||
Kontakt (05)
|
||||
</p>
|
||||
<h2 className="mt-8 max-w-[12ch] text-5xl font-black uppercase leading-[0.86] sm:text-7xl lg:text-8xl">
|
||||
Erzaehlen Sie mir kurz vom Projekt
|
||||
</h2>
|
||||
<p className="mt-8 max-w-2xl text-xl leading-8 text-muted-foreground">
|
||||
Ein paar Saetze reichen: Was bieten Sie an, was soll die Website
|
||||
leisten, und wann soll sie online sein?
|
||||
</p>
|
||||
<a
|
||||
href="mailto:hallo@matthias-meister.com"
|
||||
className="mt-10 inline-flex items-center gap-3 bg-primary px-6 py-5 text-sm font-black uppercase tracking-[0.18em] text-primary-foreground transition hover:bg-foreground hover:text-background"
|
||||
>
|
||||
<CornerDownRight className="size-5" />
|
||||
Anfrage per Mail senden
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex flex-col justify-end gap-6 bg-primary px-5 py-10 text-primary-foreground sm:px-8 lg:px-10">
|
||||
<div className="flex gap-3">
|
||||
<Mail className="size-5" />
|
||||
<span>hallo@matthias-meister.com</span>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<Phone className="size-5" />
|
||||
<span>Rueckmeldung innerhalb von 24 Stunden</span>
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<MapPin className="size-5" />
|
||||
<span>Regionale KMU in Deutschland</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export { CanvaLanding };
|
||||
@@ -1,13 +1,5 @@
|
||||
---
|
||||
import { About19 } from "@/components/about19";
|
||||
import { Contact21 } from "@/components/contact21";
|
||||
import { Faq7 } from "@/components/faq7";
|
||||
import { Feature284 } from "@/components/feature284";
|
||||
import { Footer27 } from "@/components/footer27";
|
||||
import { Hero235 } from "@/components/hero235";
|
||||
import { Pricing4 } from "@/components/pricing4";
|
||||
import { Stats11 } from "@/components/stats11";
|
||||
import CTASection from "@/components/cta";
|
||||
import { CanvaLanding } from "@/components/canva-landing";
|
||||
import "@/styles/global.css";
|
||||
---
|
||||
|
||||
@@ -25,16 +17,6 @@ import "@/styles/global.css";
|
||||
defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="mx-auto w-full max-w-7xl">
|
||||
<Hero235 client:load />
|
||||
<CTASection client:load />
|
||||
<Feature284 client:load />
|
||||
<Stats11 client:load />
|
||||
<Pricing4 client:load />
|
||||
<Faq7 client:load />
|
||||
<About19 client:load />
|
||||
<Contact21 client:load />
|
||||
<Footer27 client:load />
|
||||
</div>
|
||||
<CanvaLanding />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -49,38 +49,38 @@
|
||||
}
|
||||
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.205 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.556 0 0);
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--background: oklch(0.115 0.012 22);
|
||||
--foreground: oklch(0.965 0.013 76);
|
||||
--card: oklch(0.16 0.014 22);
|
||||
--card-foreground: oklch(0.965 0.013 76);
|
||||
--popover: oklch(0.16 0.014 22);
|
||||
--popover-foreground: oklch(0.965 0.013 76);
|
||||
--primary: oklch(0.61 0.235 27);
|
||||
--primary-foreground: oklch(0.985 0.01 76);
|
||||
--secondary: oklch(0.22 0.016 22);
|
||||
--secondary-foreground: oklch(0.965 0.013 76);
|
||||
--muted: oklch(0.19 0.014 22);
|
||||
--muted-foreground: oklch(0.73 0.021 76);
|
||||
--accent: oklch(0.61 0.235 27);
|
||||
--accent-foreground: oklch(0.985 0.01 76);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--border: oklch(0.965 0.013 76 / 20%);
|
||||
--input: oklch(0.965 0.013 76 / 20%);
|
||||
--ring: oklch(0.61 0.235 27);
|
||||
--chart-1: oklch(0.87 0 0);
|
||||
--chart-2: oklch(0.556 0 0);
|
||||
--chart-3: oklch(0.439 0 0);
|
||||
--chart-4: oklch(0.371 0 0);
|
||||
--chart-5: oklch(0.269 0 0);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.985 0 0);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--sidebar: oklch(0.16 0.014 22);
|
||||
--sidebar-foreground: oklch(0.965 0.013 76);
|
||||
--sidebar-primary: oklch(0.61 0.235 27);
|
||||
--sidebar-primary-foreground: oklch(0.985 0.01 76);
|
||||
--sidebar-accent: oklch(0.22 0.016 22);
|
||||
--sidebar-accent-foreground: oklch(0.965 0.013 76);
|
||||
--sidebar-border: oklch(0.965 0.013 76 / 20%);
|
||||
--sidebar-ring: oklch(0.61 0.235 27);
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -123,8 +123,10 @@
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
text-rendering: geometricPrecision;
|
||||
}
|
||||
html {
|
||||
@apply font-sans;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
13
tests/landing-content.test.mjs
Normal file
13
tests/landing-content.test.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const componentPath = new URL("../src/components/canva-landing.tsx", import.meta.url);
|
||||
|
||||
test("Canva landing component contains the core brief anchors", async () => {
|
||||
const source = await readFile(componentPath, "utf8");
|
||||
|
||||
for (const phrase of ["Projektbrief", "01", "Website", "Kontakt"]) {
|
||||
assert.match(source, new RegExp(phrase));
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user