Use German umlauts in landing copy
This commit is contained in:
@@ -4,7 +4,7 @@ title: Redesign dev website from Canva reference
|
|||||||
status: In Progress
|
status: In Progress
|
||||||
assignee: []
|
assignee: []
|
||||||
created_date: '2026-05-05 20:20'
|
created_date: '2026-05-05 20:20'
|
||||||
updated_date: '2026-05-05 20:32'
|
updated_date: '2026-05-05 20:35'
|
||||||
labels: []
|
labels: []
|
||||||
dependencies: []
|
dependencies: []
|
||||||
priority: high
|
priority: high
|
||||||
@@ -40,4 +40,6 @@ Create an isolated worktree and redesign the regional dev landing page to match
|
|||||||
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.
|
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.
|
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.
|
||||||
|
|
||||||
|
Converted visible German UI copy from ae/oe/ue fallbacks to real umlauts in the Canva landing page and legacy section components. Added smoke-test coverage for the Canva landing copy.
|
||||||
<!-- SECTION:NOTES:END -->
|
<!-- SECTION:NOTES:END -->
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ const services = [
|
|||||||
{
|
{
|
||||||
number: "02",
|
number: "02",
|
||||||
title: "Struktur",
|
title: "Struktur",
|
||||||
text: "Angebot, Beweise, Ablauf und Kontakt werden so sortiert, dass Besucher nicht suchen muessen.",
|
text: "Angebot, Beweise, Ablauf und Kontakt werden so sortiert, dass Besucher nicht suchen müssen.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
number: "03",
|
number: "03",
|
||||||
title: "Technik",
|
title: "Technik",
|
||||||
text: "Schnell, mobil sauber, DSGVO-arm und so gebaut, dass spaetere Aenderungen nicht zum Projekt werden.",
|
text: "Schnell, mobil sauber, DSGVO-arm und so gebaut, dass spätere Änderungen nicht zum Projekt werden.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -37,15 +37,15 @@ const packages = [
|
|||||||
{
|
{
|
||||||
name: "Basis",
|
name: "Basis",
|
||||||
price: "799 EUR",
|
price: "799 EUR",
|
||||||
detail: "Eine starke Seite fuer ein klares Angebot.",
|
detail: "Eine starke Seite für ein klares Angebot.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Profi",
|
name: "Profi",
|
||||||
price: "1.499 EUR",
|
price: "1.499 EUR",
|
||||||
detail: "Mehrere Seiten fuer Betriebe mit erklaerungsbeduerftigem Angebot.",
|
detail: "Mehrere Seiten für Betriebe mit erklärungsbedürftigem Angebot.",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Massarbeit",
|
name: "Maßarbeit",
|
||||||
price: "2.499 EUR+",
|
price: "2.499 EUR+",
|
||||||
detail: "Individuelle Struktur, CMS und besondere Anforderungen.",
|
detail: "Individuelle Struktur, CMS und besondere Anforderungen.",
|
||||||
},
|
},
|
||||||
@@ -69,7 +69,7 @@ const CanvaLanding = () => {
|
|||||||
|
|
||||||
<div className="max-w-5xl py-16 sm:py-20 lg:py-24">
|
<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">
|
<p className="mb-6 max-w-sm text-sm uppercase tracking-[0.32em] text-primary">
|
||||||
Projektbrief fuer regionale Unternehmen
|
Projektbrief für regionale Unternehmen
|
||||||
</p>
|
</p>
|
||||||
<h1 className="max-w-[11ch] text-[clamp(4.25rem,13vw,11.5rem)] font-black uppercase leading-[0.78] tracking-normal text-foreground">
|
<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
|
Website ohne Umweg
|
||||||
@@ -79,9 +79,9 @@ const CanvaLanding = () => {
|
|||||||
Strategie trifft Umsetzung
|
Strategie trifft Umsetzung
|
||||||
</p>
|
</p>
|
||||||
<p className="max-w-2xl text-lg leading-8 text-foreground/78">
|
<p className="max-w-2xl text-lg leading-8 text-foreground/78">
|
||||||
Ich baue Websites fuer Handwerk, Praxen, Salons und
|
Ich baue Websites für Handwerk, Praxen, Salons und
|
||||||
Dienstleister aus der Region. Direkt, glaubwuerdig und so
|
Dienstleister aus der Region. Direkt, glaubwürdig und so
|
||||||
reduziert, dass der naechste Kontakt naheliegt.
|
reduziert, dass der nächste Kontakt naheliegt.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -105,7 +105,7 @@ const CanvaLanding = () => {
|
|||||||
01
|
01
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-7 max-w-sm text-2xl font-semibold uppercase leading-none">
|
<p className="mt-7 max-w-sm text-2xl font-semibold uppercase leading-none">
|
||||||
Klarer Auftritt. Harte Kante. Weniger Agenturlaerm.
|
Klarer Auftritt. Harte Kante. Weniger Agenturlärm.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
@@ -214,10 +214,10 @@ const CanvaLanding = () => {
|
|||||||
Kontakt (05)
|
Kontakt (05)
|
||||||
</p>
|
</p>
|
||||||
<h2 className="mt-8 max-w-[12ch] text-5xl font-black uppercase leading-[0.86] sm:text-7xl lg:text-8xl">
|
<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
|
Erzählen Sie mir kurz vom Projekt
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-8 max-w-2xl text-xl leading-8 text-muted-foreground">
|
<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
|
Ein paar Sätze reichen: Was bieten Sie an, was soll die Website
|
||||||
leisten, und wann soll sie online sein?
|
leisten, und wann soll sie online sein?
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
@@ -235,7 +235,7 @@ const CanvaLanding = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<Phone className="size-5" />
|
<Phone className="size-5" />
|
||||||
<span>Rueckmeldung innerhalb von 24 Stunden</span>
|
<span>Rückmeldung innerhalb von 24 Stunden</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<MapPin className="size-5" />
|
<MapPin className="size-5" />
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const contactFormSchema = z.object({
|
|||||||
email: z
|
email: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, "Bitte geben Sie Ihre E-Mail ein")
|
.min(1, "Bitte geben Sie Ihre E-Mail ein")
|
||||||
.email("Bitte geben Sie eine gueltige E-Mail ein"),
|
.email("Bitte geben Sie eine gültige E-Mail ein"),
|
||||||
message: z.string().min(1, "Bitte beschreiben Sie kurz Ihr Anliegen"),
|
message: z.string().min(1, "Bitte beschreiben Sie kurz Ihr Anliegen"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default function CTASection() {
|
|||||||
<p className="text-base leading-7 text-muted-foreground">
|
<p className="text-base leading-7 text-muted-foreground">
|
||||||
Noch bevor es um Pakete oder Features geht, soll direkt klar sein,
|
Noch bevor es um Pakete oder Features geht, soll direkt klar sein,
|
||||||
warum diese Zusammenarbeit für regionale Unternehmen greifbar und
|
warum diese Zusammenarbeit für regionale Unternehmen greifbar und
|
||||||
verlaesslich wirkt.
|
verlässlich wirkt.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<dl className="mt-8 grid gap-6 sm:grid-cols-3 lg:mt-0 lg:gap-0">
|
<dl className="mt-8 grid gap-6 sm:grid-cols-3 lg:mt-0 lg:gap-0">
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const Faq7 = ({ className }: Faq7Props) => {
|
|||||||
</span>
|
</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-lg text-muted-foreground md:text-xl">
|
<p className="text-lg text-muted-foreground md:text-xl">
|
||||||
Falls noch etwas offen ist, schreiben Sie mir gern ueber das
|
Falls noch etwas offen ist, schreiben Sie mir gern über das
|
||||||
<a href="#" className="mx-1 whitespace-nowrap underline">
|
<a href="#" className="mx-1 whitespace-nowrap underline">
|
||||||
Kontaktformular
|
Kontaktformular
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -6,35 +6,35 @@ import { cn } from "@/lib/utils";
|
|||||||
|
|
||||||
const featureData = [
|
const featureData = [
|
||||||
{
|
{
|
||||||
desc: "Ihre Website erklaert in wenigen Sekunden, fuer wen Sie arbeiten und was Sie konkret anbieten.",
|
desc: "Ihre Website erklärt in wenigen Sekunden, für wen Sie arbeiten und was Sie konkret anbieten.",
|
||||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img1.jpeg",
|
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img1.jpeg",
|
||||||
title: "Klare Positionierung",
|
title: "Klare Positionierung",
|
||||||
badgeTitle: "Vorteil 01",
|
badgeTitle: "Vorteil 01",
|
||||||
gridClass: "md:col-span-1",
|
gridClass: "md:col-span-1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Ein zeitgemaesses Design sorgt fuer einen starken ersten Eindruck und passt zu Ihrem Unternehmen.",
|
desc: "Ein zeitgemäßes Design sorgt für einen starken ersten Eindruck und passt zu Ihrem Unternehmen.",
|
||||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img7.jpeg",
|
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img7.jpeg",
|
||||||
title: "Modernes Erscheinungsbild",
|
title: "Modernes Erscheinungsbild",
|
||||||
badgeTitle: "Vorteil 02",
|
badgeTitle: "Vorteil 02",
|
||||||
gridClass: "lg:col-span-2",
|
gridClass: "lg:col-span-2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Ihre Inhalte funktionieren sauber auf Smartphone, Tablet und Desktop - ohne Umwege fuer Besucher.",
|
desc: "Ihre Inhalte funktionieren sauber auf Smartphone, Tablet und Desktop - ohne Umwege für Besucher.",
|
||||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img11.jpeg",
|
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img11.jpeg",
|
||||||
title: "Mobil optimiert",
|
title: "Mobil optimiert",
|
||||||
badgeTitle: "Vorteil 03",
|
badgeTitle: "Vorteil 03",
|
||||||
gridClass: "md:col-span-1 lg:row-span-2 ",
|
gridClass: "md:col-span-1 lg:row-span-2 ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Klare Kontaktwege mit gut sichtbaren Handlungsaufforderungen machen den naechsten Schritt leicht.",
|
desc: "Klare Kontaktwege mit gut sichtbaren Handlungsaufforderungen machen den nächsten Schritt leicht.",
|
||||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img2.jpeg",
|
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img2.jpeg",
|
||||||
title: "Anfragen ohne Huerden",
|
title: "Anfragen ohne Hürden",
|
||||||
badgeTitle: "Vorteil 04",
|
badgeTitle: "Vorteil 04",
|
||||||
gridClass: "lg:col-span-2",
|
gridClass: "lg:col-span-2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Die Seite bleibt wartbar aufgebaut, damit Inhalte spaeter schnell angepasst oder erweitert werden koennen.",
|
desc: "Die Seite bleibt wartbar aufgebaut, damit Inhalte später schnell angepasst oder erweitert werden können.",
|
||||||
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img4.jpeg",
|
img: "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/guri3/img4.jpeg",
|
||||||
title: "Pflegeleicht aufgebaut",
|
title: "Pflegeleicht aufgebaut",
|
||||||
badgeTitle: "Vorteil 05",
|
badgeTitle: "Vorteil 05",
|
||||||
|
|||||||
@@ -7,7 +7,26 @@ const componentPath = new URL("../src/components/canva-landing.tsx", import.meta
|
|||||||
test("Canva landing component contains the core brief anchors", async () => {
|
test("Canva landing component contains the core brief anchors", async () => {
|
||||||
const source = await readFile(componentPath, "utf8");
|
const source = await readFile(componentPath, "utf8");
|
||||||
|
|
||||||
for (const phrase of ["Projektbrief", "01", "Website", "Kontakt"]) {
|
for (const phrase of ["Projektbrief", "01", "Website", "Kontakt", "für", "müssen", "Änderungen"]) {
|
||||||
assert.match(source, new RegExp(phrase));
|
assert.match(source, new RegExp(phrase));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Canva landing component uses real German umlauts in visible copy", async () => {
|
||||||
|
const source = await readFile(componentPath, "utf8");
|
||||||
|
|
||||||
|
for (const asciiFallback of [
|
||||||
|
"fuer",
|
||||||
|
"muessen",
|
||||||
|
"spaetere",
|
||||||
|
"Aenderungen",
|
||||||
|
"glaubwuerdig",
|
||||||
|
"naechste",
|
||||||
|
"Agenturlaerm",
|
||||||
|
"Erzaehlen",
|
||||||
|
"Saetze",
|
||||||
|
"Rueckmeldung",
|
||||||
|
]) {
|
||||||
|
assert.doesNotMatch(source, new RegExp(asciiFallback));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user