Ziel des QR-Codes auf der Rückwandgrafik. Der gedruckte Code zeigt auf https://her-career.anelia-wolf.com – die Adresse ist damit unveränderlich. Die Seite liegt als /her-career/ im normalen Export, die Subdomain liefert dieselbe Datei aus demselben Docroot aus; DNS, Zertifikat, Vhosts für nginx und Apache und die Prüfbefehle stehen in docs/SUBDOMAIN-HERCAREER.md. Aufbau in beiden Sprachen: Hero (ink) → 01 Messe-Special → 02 Themen → 03 Auf der Messe → 04 Kontakt mit dem Formular. Die vier Themenblöcke der Rückwand liegen auf den drei Leistungsseiten, wie in der Navigation; jede Zeile verlinkt absolut auf die Hauptdomain. Der Wortlaut des Messe-Specials fehlt noch und steht sichtbar als „[…]“ auf der Seite. Der Build-Guard hält den Launch-Flip an, bis er da ist (CONTENT_TODO in src/lib/legal.ts, docs/OFFENE-DATEN.md Punkte 2.7–2.9). Deadline ist nicht der Livegang, sondern der 22.10.2026. - Canonical auf anelia-wolf.com/her-career/, damit die Subdomain-Kopie nicht ein zweites Mal im Index steht - flags.showHerCareer trägt Termine-Ledger, Sitemap-Eintrag und die Meta-Beschreibung mit Stand und Uhrzeit. Ab dem 24.10.2026 auf false - ServiceHero: facts und cta sind optional – ohne beides und ohne Foto entfällt die rechte Spalte - ProcessContact: optionaler Zähler, die Messeseite nummeriert ihre Abschnitte - Kopf-CTA auf dieser Seite ausgeblendet. Das macht eine Regel in globals.css, weil der Kopf außerhalb von <main> liegt und auf der Subdomain der Pfad ohnehin „/“ ist Enthält außerdem die bis dahin nicht committeten Änderungen an Header, LangSwitch, OverlayMenu, Wordmark und globals.css. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
101 lines
3.7 KiB
TypeScript
101 lines
3.7 KiB
TypeScript
"use client";
|
||
|
||
import { usePathname } from "next/navigation";
|
||
import { cn } from "@/lib/utils";
|
||
import { counterpart, langSwitch, otherLang, type Lang } from "@/lib/i18n";
|
||
import { TransitionLink } from "@/components/motion/TransitionLink";
|
||
|
||
export interface LangSwitchProps {
|
||
lang: Lang;
|
||
className?: string;
|
||
/**
|
||
* `pair` zeigt beide Sprachen nebeneinander (Platz ab 1024 px).
|
||
* `compact` zeigt nur die andere Sprache als einen Knopf – ein Tipp, ein Wechsel.
|
||
* Auf dem Telefon ist das die einzige Form, die neben Wortmarke und „Menü“ passt.
|
||
*/
|
||
variant?: "pair" | "compact";
|
||
}
|
||
|
||
const BASE =
|
||
"inline-flex items-center gap-1.5 font-mono text-[11px] uppercase tracking-[0.14em] transition-colors duration-300";
|
||
|
||
/**
|
||
* Sprachumschalter im Kopf. Steht an der Stelle, an der vorher „Kontakt“ stand.
|
||
*
|
||
* Zielt auf das Gegenstück derselben Seite (`counterpart()`), nicht pauschal auf die
|
||
* Startseite.
|
||
*
|
||
* Zur Flagge: Eine Flagge steht für ein Land, nicht für eine Sprache – deshalb steht
|
||
* neben ihr immer das Sprachkürzel, und der zugängliche Name nennt die Sprache
|
||
* ausgeschrieben. Wer die Flaggen weglassen will, entfernt hier zwei Zeilen.
|
||
*/
|
||
export function LangSwitch({ lang, className, variant = "pair" }: LangSwitchProps) {
|
||
const pathname = usePathname() ?? "/";
|
||
const other = otherLang(lang);
|
||
const href = counterpart(pathname, other);
|
||
|
||
/* Kompakt: Die aktive Sprache steht nicht da – sie steht ja im Dokument. Gezeigt wird,
|
||
wohin es geht. Die negativen Ränder heben das Tippziel auf 54 × 42 px, ohne die
|
||
Grundlinie oder den Abstand zum Nachbarn zu verschieben (WCAG 2.5.8: 24 × 24 px
|
||
Minimum, 44 × 44 px ist die Empfehlung – die Breite von 38 px lag darunter). */
|
||
if (variant === "compact") {
|
||
return (
|
||
<TransitionLink
|
||
href={href}
|
||
label={langSwitch[other].label}
|
||
hrefLang={other}
|
||
aria-label={langSwitch[other].title}
|
||
className={cn(BASE, "-mx-2 -my-3 shrink-0 px-2 py-3 text-fg", className)}
|
||
>
|
||
<Flag lang={other} />
|
||
{langSwitch[other].short}
|
||
</TransitionLink>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div className={cn("flex items-center gap-2", className)}>
|
||
<span className={cn(BASE, "text-accent")} aria-current="true" title={langSwitch[lang].title}>
|
||
<Flag lang={lang} />
|
||
{langSwitch[lang].short}
|
||
</span>
|
||
<span aria-hidden="true" className="h-3 w-px bg-line" />
|
||
<TransitionLink
|
||
href={href}
|
||
label={langSwitch[other].label}
|
||
hrefLang={other}
|
||
aria-label={langSwitch[other].title}
|
||
className={cn(BASE, "-my-3 py-3 text-fg-muted hover:text-accent focus-visible:text-accent")}
|
||
>
|
||
<Flag lang={other} />
|
||
{langSwitch[other].short}
|
||
</TransitionLink>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
/** 16 × 11 px, randlos, damit die Fahne neben 11-px-Versalien nicht dominiert. */
|
||
function Flag({ lang }: { lang: Lang }) {
|
||
const common = { width: 16, height: 11, viewBox: "0 0 16 11", "aria-hidden": true as const, className: "shrink-0" };
|
||
if (lang === "de") {
|
||
return (
|
||
<svg {...common}>
|
||
<rect width="16" height="11" fill="#0C0C0C" />
|
||
<rect y="3.667" width="16" height="3.667" fill="#DD0000" />
|
||
<rect y="7.334" width="16" height="3.666" fill="#FFCE00" />
|
||
</svg>
|
||
);
|
||
}
|
||
return (
|
||
<svg {...common}>
|
||
<rect width="16" height="11" fill="#012169" />
|
||
<path d="M0 0 16 11M16 0 0 11" stroke="#FFF" strokeWidth="2.2" />
|
||
<path d="M0 0 16 11M16 0 0 11" stroke="#C8102E" strokeWidth="1.1" />
|
||
<path d="M8 0v11M0 5.5h16" stroke="#FFF" strokeWidth="3.7" />
|
||
<path d="M8 0v11M0 5.5h16" stroke="#C8102E" strokeWidth="2.2" />
|
||
</svg>
|
||
);
|
||
}
|
||
|
||
export default LangSwitch;
|