Klaro polish: remove redundant toggle-all text, responsive button rows, real per-service descriptions
- Empties Klaro's own "Mit diesem Schalter..." boilerplate under the modal's per-service toggle-all switch — redundant next to a plainly labeled switch. - .cn-ok/.cn-buttons/.cm-buttons now explicit flex-wrap rows (side by side until they genuinely don't fit, then wrap) instead of relying on Klaro's own fragile inline-block flow. - Every tracking-codes provider gets a real description in the modal's service list (was title-only) — what it does and, where publicly documented and stable, the actual cookie names/lifetimes (_ga/ _ga_<container-id> for GA4, _fbp/fr for Facebook Pixel). GTM/Maps descriptions are deliberately non-specific about exact cookies — neither has a fixed, publicly enumerable list. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -73,6 +73,19 @@ function KlaroTheme() {
|
||||
.klaro .cm-btn:hover { opacity: 0.88; }
|
||||
.klaro .cm-btn:active { transform: scale(0.97); }
|
||||
.klaro .cm-btn:focus-visible { outline: 2px solid #f6a701 !important; outline-offset: 2px; }
|
||||
/* Side-by-side by default (accept/decline in the notice, the
|
||||
modal's own bottom action row), only wrapping to a stacked
|
||||
layout once they genuinely don't fit — flex-wrap does this
|
||||
naturally at any width, no fixed breakpoint needed. Klaro's own
|
||||
.cn-ok/.cn-buttons rely on inline-block flow for the same
|
||||
result, which is fragile; this is the explicit version. */
|
||||
.klaro .cn-ok, .klaro .cn-buttons, .klaro .cm-buttons {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
gap: 10px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
.klaro .cn-buttons .cm-btn, .klaro .cm-buttons .cm-btn { width: auto !important; margin: 0 !important; }
|
||||
/* The "Karte laden?" placeholder ContextualConsentNotice renders in
|
||||
place of a gated embed (GoogleMapsEmbed.tsx) — fills that embed's
|
||||
own aspect-ratio box, so this needs to look like a real card
|
||||
|
||||
+35
-2
@@ -56,14 +56,40 @@ function providerTitle(code: TrackingCode): string {
|
||||
}
|
||||
}
|
||||
|
||||
// Shown per service in the modal's expanded list — without this, Klaro
|
||||
// only ever shows the bare provider title (see providerTitle above),
|
||||
// which is thin for real TTDSG transparency ("what does this actually
|
||||
// do") and reads as less trustworthy than a CMP that explains itself.
|
||||
// Generic per-provider text, not per-row — a second Google Analytics row
|
||||
// would get the identical description, which is fine since the "what
|
||||
// GA does" fact doesn't change between rows, only which property it's
|
||||
// wired to (already visible via the row's own `name` if an admin sets a
|
||||
// distinguishing one).
|
||||
function providerDescription(code: TrackingCode): string {
|
||||
switch (code.provider) {
|
||||
case "google-analytics":
|
||||
return "Erfasst anonymisierte Nutzungsstatistiken (z. B. welche Seiten wie oft besucht werden), damit wir verstehen, was bei euch ankommt. Setzt die Cookies _ga (Laufzeit 2 Jahre, unterscheidet Besucher:innen) und _ga_<Container-ID> (2 Jahre, Sitzungsstatus).";
|
||||
case "facebook-pixel":
|
||||
return "Misst, ob ein Besuch von hier zu einer Anzeige bei Facebook/Instagram passt, und hilft uns, Werbung zielgerichteter zu schalten. Setzt den Cookie _fbp (3 Monate, eigene Domain); ist ein Facebook-Konto im selben Browser aktiv, setzt facebook.com zusätzlich den Cookie fr (3 Monate).";
|
||||
case "google-tag-manager":
|
||||
return "Lädt weitere Mess-/Marketing-Skripte je nach Konfiguration nach, ohne dass wir dafür jedes Mal den Code der Seite ändern müssen. Setzt selbst keine eigenen Cookies — welche Cookies letztlich gesetzt werden, hängt von den darüber geladenen Diensten ab (siehe deren eigene Einträge hier).";
|
||||
case "google-maps":
|
||||
return "Bindet eine interaktive Karte von Google ein. Beim Laden überträgt dein Browser deine IP-Adresse an Google und Google setzt eigene Cookies (u. a. NID), deren genauer Umfang außerhalb unserer Kontrolle liegt.";
|
||||
default:
|
||||
return "Ein zusätzliches Skript, das diese Seite einbindet.";
|
||||
}
|
||||
}
|
||||
|
||||
// `onAccept` is threaded in rather than importing loadTrackingCode.ts
|
||||
// directly here — this module only builds a plain config object (no DOM
|
||||
// access), kept separate from the actual script-injection side effect so
|
||||
// it stays trivially testable/reusable if the loading mechanism ever
|
||||
// changes.
|
||||
export function buildKlaroConfig(codes: TrackingCode[], onAccept: (code: TrackingCode) => void): KlaroConfig {
|
||||
const serviceTranslations: Record<string, { title: string }> = {};
|
||||
for (const code of codes) serviceTranslations[serviceName(code)] = { title: providerTitle(code) };
|
||||
const serviceTranslations: Record<string, { title: string; description: string }> = {};
|
||||
for (const code of codes) {
|
||||
serviceTranslations[serviceName(code)] = { title: providerTitle(code), description: providerDescription(code) };
|
||||
}
|
||||
|
||||
return {
|
||||
version: 1,
|
||||
@@ -129,6 +155,13 @@ export function buildKlaroConfig(codes: TrackingCode[], onAccept: (code: Trackin
|
||||
marketing: "Marketing",
|
||||
content: "Inhalte",
|
||||
},
|
||||
// Klaro's own bundled German copy for the per-service "alle
|
||||
// umschalten" toggle in the modal — the explanatory line reads as
|
||||
// redundant boilerplate next to a plainly-labeled switch, and the
|
||||
// toggle's own text color made it barely legible anyway (see
|
||||
// KlaroTheme's own comment). Title stays (Klaro's own default is
|
||||
// fine), only the description is emptied.
|
||||
service: { disableAll: { description: "" } },
|
||||
...serviceTranslations,
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user