Sicherheit: "Jetzt per Stripe erstatten" loeste die Rueckerstattung bisher mit einem einzigen Klick aus. Erstatten und Ablehnen einer Retoure laufen jetzt ueber ConfirmForm; die Rueckfrage nennt Bestellnummer und Betrag. Admin: Produkte, Bestellungen und Retouren nutzen dieselben Bausteine wie die uebrigen Listen (Seitenkopf, Suche mit Zusatzfiltern und Archiv- Parameter, Status-Badges, Leerzustaende). Produkttabelle ohne seitliches Scrollen bei 1440 px: Bearbeiten ueber den Produktnamen, Charge ohne Umbruch. Geschenk-Markierung als SVG statt Emoji. Letzte rohe Knoepfe (Bestelldetail, ApiCore, Inhalte) auf Button umgestellt. Mobil (390 px): Ueberlauf auf /konto (Datenexport) und /kontakt (E-Mail-Adresse) behoben. Tippziele unter 24 px vergroessert (Zurueck-Link, "Zum Honig", Links auf der Produktseite). Wunschliste mit SVG-Stern statt Unicode-Zeichen. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
77 lines
3.4 KiB
TypeScript
77 lines
3.4 KiB
TypeScript
import type { Metadata } from "next";
|
|
import { Container, SectionHeading } from "@/components/ui";
|
|
import { HoneycombPattern, HexMark } from "@/components/honeycomb";
|
|
import { ScrollReveal } from "@/components/scroll-reveal";
|
|
import { getCompanyInfo } from "@/lib/company-info";
|
|
import { getLocale } from "@/i18n/locale";
|
|
import { getDictionary } from "@/i18n/get-dictionary";
|
|
|
|
export async function generateMetadata(): Promise<Metadata> {
|
|
const t = getDictionary(await getLocale());
|
|
return {
|
|
title: t.kontaktPage.eyebrow,
|
|
description: t.kontaktPage.title,
|
|
alternates: { canonical: "/kontakt" },
|
|
};
|
|
}
|
|
|
|
export default async function KontaktPage() {
|
|
const t = getDictionary(await getLocale());
|
|
const company = await getCompanyInfo();
|
|
return (
|
|
<div className="py-20">
|
|
<Container className="max-w-5xl">
|
|
<ScrollReveal>
|
|
<SectionHeading level="h1" eyebrow={t.kontaktPage.eyebrow} title={t.kontaktPage.title} />
|
|
</ScrollReveal>
|
|
|
|
<div className="mt-12 grid gap-6 md:grid-cols-5">
|
|
{/* Kontaktkarte auf Wabenraster: die E-Mail ist der Hauptweg und
|
|
steht deshalb gross in Serifenschrift. */}
|
|
<ScrollReveal delay={0.1} className="min-w-0 md:col-span-3">
|
|
<div className="relative h-full overflow-hidden bg-forest px-8 py-10 text-cream md:px-10">
|
|
<HoneycombPattern className="text-honey-light/[0.1]" size={24} fade="right" />
|
|
<div className="relative">
|
|
<a
|
|
href={`mailto:${company.email}`}
|
|
className="group inline-flex items-center gap-3 font-serif text-2xl sm:text-3xl md:text-4xl text-cream"
|
|
>
|
|
<span className="link-draw pb-1">{company.email}</span>
|
|
<svg
|
|
aria-hidden="true"
|
|
viewBox="0 0 24 24"
|
|
className="h-5 w-5 text-honey-light transition-transform duration-300 ease-[var(--ease-arrive)] group-hover:translate-x-1"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth="1.6"
|
|
>
|
|
<path d="M4 12h15M13 6l6 6-6 6" strokeLinecap="round" strokeLinejoin="round" />
|
|
</svg>
|
|
</a>
|
|
{/* Ohne gepflegte Nummer entfaellt die Zeile ganz. Eine
|
|
Platzhalternummer waere schlimmer als keine: sie sieht nach
|
|
einem Kontaktweg aus, an dessen Ende niemand abnimmt. */}
|
|
{company.phone ? <p className="mt-4 text-lg text-cream/85 tabular-nums">{company.phone}</p> : null}
|
|
<address className="mt-10 not-italic text-cream/75 leading-relaxed">
|
|
<span className="block text-cream">{company.name}</span>
|
|
{company.address.street}
|
|
<br />
|
|
{company.address.zip} {company.address.city}
|
|
</address>
|
|
</div>
|
|
</div>
|
|
</ScrollReveal>
|
|
|
|
<ScrollReveal delay={0.18} className="md:col-span-2">
|
|
<div className="h-full border border-honey/30 bg-honey/[0.06] px-8 py-10">
|
|
<HexMark className="h-4 w-4 text-honey-dark" />
|
|
<h2 className="mt-5 text-2xl text-forest">{t.kontaktPage.pickupHeading}</h2>
|
|
<p className="mt-3 text-ink/70 leading-relaxed">{t.kontaktPage.pickupText}</p>
|
|
</div>
|
|
</ScrollReveal>
|
|
</div>
|
|
</Container>
|
|
</div>
|
|
);
|
|
}
|