Handy ansicht und website ansicht für den Qr gemacht
This commit is contained in:
knso committed 2026-09-10 20:06:42 +02:00
1 parent 9725e0229d
commit c09f674653
15 files changed
+639 -103

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
import { cn } from "@/lib/utils";
export interface CouponContent {
/** Mono-Caps über dem Satz, z. B. „Ihr Messe-Special“. */
kicker: string;
/** Der Nachlass in Display-Ziffern, z. B. „−20“. */
rate: string;
/** Einheit neben der Zahl, z. B. „%“. */
unit: string;
/** Worauf er gilt – der eine Satz, der den Gutschein trägt. */
on: string;
/** Was drinsteckt. Eine Zeile je Leistung, mit goldenem Strich davor. */
includes: readonly string[];
/** Frist und Stichwort im Abriss unter der Perforation. */
valid: { label: string; value: string };
code: { label: string; value: string };
}
export interface CouponProps {
content: CouponContent;
className?: string;
}
const MONO = "font-mono text-xs tracking-[0.06em] tabular-nums";
/**
* Der Grund eines Gutscheins: blasses Gold, goldene Haarlinie, runde Ecken.
*
* Exportiert, weil zwei Bauteile denselben Gegenstand darstellen – der große
* Gutschein im Hero und der kleine Hinweis über dem Kontaktformular, dass der
* Vorteil schon anhängt. Sie müssen gleich aussehen, also gibt es die Werte
* einmal. Die runden Ecken sind die ausdrückliche Ausnahme von „Radius 0“
* (Kundenwunsch 10.09.2026) und gelten nur für diese beiden Stellen.
*/
export const COUPON_SURFACE = "rounded-[14px] border border-gold-700 bg-gold-100 text-ink";
/**
* Die Reißkante: gestrichelte Haarlinie über die volle Breite, an beiden Enden
* eine Kerbe. Die Kerben sind auf die Ecke gestellte Quadrate in der Grundfarbe
* des umgebenden Abschnitts (`bg-bg`) – sie sehen aus wie gestanzt und kommen
* ohne einen einzigen Eckenradius aus. Auf hellem Grund elfenbein, auf dunklem
* tintenschwarz, ganz von selbst.
*/
export function CouponPerforation() {
return (
<div aria-hidden="true" className="relative border-t border-dashed border-gold-700">
<span className="absolute left-0 top-0 h-3.5 w-3.5 -translate-x-1/2 -translate-y-1/2 rotate-45 bg-bg" />
<span className="absolute right-0 top-0 h-3.5 w-3.5 translate-x-1/2 -translate-y-1/2 rotate-45 bg-bg" />
</div>
);
}
/**
* Der Messe-Gutschein (/her-career/, Sektion 01).
*
* Er soll als Gutschein erkennbar sein, ohne aus dem Haus-Stil zu fallen –
* also kein abgerundetes Ticket mit Schatten und Fremdschrift, sondern die
* drei Merkmale, die ein Gutschein wirklich braucht, in der Sprache der Seite:
*
* 0. Runde Ecken. Die einzige Stelle der Website mit einem Eckenradius
* (Projektregel ist sonst Radius 0, ausdrückliche Ausnahme vom 10.09.2026):
* Der Gutschein stellt einen Gegenstand dar, kein Interface-Element, und
* ein Gutschein mit scharfen Ecken sieht aus wie eine Tabelle. Der Radius
* bleibt auf dieses eine Bauteil beschränkt – Knöpfe, Rahmen und Tafeln
* ringsum sind weiter eckig.
* 1. Ein eigener Grund. `--gold-100` ist der blasse Goldton der Palette –
* bis hierher nirgends als Fläche benutzt und damit frei für genau das
* eine Objekt, das sich vom Elfenbein abheben soll. Die Schrift darauf ist
* Tinte, nicht Gold: Gold auf Gold liest sich nicht, und goldene Schrift
* bleibt ohnehin dem dunklen Grund vorbehalten.
* 2. Eine Reißkante. Gestrichelte Haarlinie über die volle Breite, an beiden
* Enden eine Kerbe. Die Kerben sind auf die Ecke gestellte Quadrate in der
* Grundfarbe der Sektion – gestanzt aussehende Löcher ohne einen einzigen
* Eckenradius.
* 3. Ein Abriss. Unter der Kante stehen Frist und Stichwort, das Stichwort im
* eigenen Kästchen wie ein Stempelfeld.
*
* Der Block steht immer auf `data-theme="light"`; die Kerben nehmen mit `bg-bg`
* den Grund der Sektion an.
*/
export function Coupon({ content, className }: CouponProps) {
const { kicker, rate, unit, on, includes, valid, code } = content;
return (
<div className={cn("relative", COUPON_SURFACE, className)}>
<div className="p-7 sm:p-12">
<p className={cn(MONO, "uppercase tracking-[0.16em] text-gold-900")}>{kicker}</p>
{/* Zahl und Einheit auf einer Grundlinie; die Einheit misst sich an der Zahl. */}
<p className="mt-5 flex items-baseline gap-[0.1em] font-display font-normal leading-[0.82] tracking-[-0.02em] [font-variant-numeric:lining-nums]">
<span className="text-[clamp(4.5rem,2.2rem+9vw,8.5rem)]">{rate}</span>
<span className="text-[clamp(1.75rem,1rem+3vw,3rem)]">{unit}</span>
</p>
<p className="mt-6 max-w-[22ch] font-display text-[clamp(1.75rem,1.35rem+1.5vw,2.75rem)] font-normal leading-[1.08] tracking-[-0.01em] [text-wrap:balance]">
{on}
</p>
{/* Dieselben Schienen wie <Facts variant="stack"/>: Strich | Text. */}
<ul className={cn(MONO, "mt-9 grid gap-y-3")}>
{includes.map((item) => (
<li key={item} className="grid grid-cols-[1.5rem_1fr] gap-x-3">
<span aria-hidden="true" className="mt-[0.55em] h-px w-6 self-start bg-gold-900" />
<span>{item}</span>
</li>
))}
</ul>
</div>
<CouponPerforation />
{/* Der Abriss: Frist links, Stichwort rechts im Stempelfeld. */}
<dl className={cn(MONO, "flex flex-wrap items-center justify-between gap-x-10 gap-y-4 p-7 sm:px-12 sm:py-8")}>
<div className="flex items-baseline gap-2">
<dt className="text-gold-900">{valid.label}</dt>
<dd>{valid.value}</dd>
</div>
<div className="flex items-center gap-3">
<dt className="text-gold-900">{code.label}</dt>
{/* Kein `uppercase`: „herCAREER“ ist gemischt geschrieben, Versalien
machten daraus ein „HERCAREER“, das die Messe so nicht führt. */}
<dd className="rounded-[6px] border border-gold-700 px-3 py-1.5 tracking-[0.14em]">{code.value}</dd>
</div>
</dl>
</div>
);
}
export default Coupon;