fix: Move EWR toggle to banner header with info button
Build + Deploy / build-backend-compliance (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / nodejs-build (push) Successful in 3m9s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 42s
CI / test-python-backend (push) Successful in 43s
CI / test-python-document-crawler (push) Successful in 29s
CI / test-python-dsms-gateway (push) Successful in 23s
Build + Deploy / build-admin-compliance (push) Successful in 2m9s
Build + Deploy / build-ai-sdk (push) Successful in 8s
Build + Deploy / build-developer-portal (push) Successful in 7s
Build + Deploy / build-tts (push) Successful in 11s
Build + Deploy / build-document-crawler (push) Successful in 7s
Build + Deploy / build-dsms-gateway (push) Successful in 7s
Build + Deploy / build-dsms-node (push) Successful in 13s
CI / loc-budget (push) Failing after 15s
CI / secret-scan (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
Build + Deploy / trigger-orca (push) Successful in 2m26s
CI / validate-canonical-controls (push) Successful in 14s
Build + Deploy / build-backend-compliance (push) Successful in 8s
CI / branch-name (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / nodejs-build (push) Successful in 3m9s
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / test-go (push) Successful in 42s
CI / test-python-backend (push) Successful in 43s
CI / test-python-document-crawler (push) Successful in 29s
CI / test-python-dsms-gateway (push) Successful in 23s
Build + Deploy / build-admin-compliance (push) Successful in 2m9s
Build + Deploy / build-ai-sdk (push) Successful in 8s
Build + Deploy / build-developer-portal (push) Successful in 7s
Build + Deploy / build-tts (push) Successful in 11s
Build + Deploy / build-document-crawler (push) Successful in 7s
Build + Deploy / build-dsms-gateway (push) Successful in 7s
Build + Deploy / build-dsms-node (push) Successful in 13s
CI / loc-budget (push) Failing after 15s
CI / secret-scan (push) Has been skipped
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
Build + Deploy / trigger-orca (push) Successful in 2m26s
CI / validate-canonical-controls (push) Successful in 14s
- EWR toggle now visible on initial banner view (top-right, always visible) - Info button (i) with tooltip explaining EWR-only mode - Blocked vendors count badge below toggle - Blocked vendor pills shown below header text - Removed duplicate EWR section from settings view Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -125,16 +125,41 @@ export function CookieBannerOverlay() {
|
||||
<div className="max-w-3xl mx-auto m-4 bg-white rounded-2xl shadow-2xl border border-gray-200 overflow-hidden">
|
||||
{/* Header */}
|
||||
<div className="px-6 pt-6 pb-4">
|
||||
<h2 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
Cookie-Einstellungen
|
||||
</h2>
|
||||
<p className="text-sm text-gray-600 mt-2 leading-relaxed">
|
||||
Wir verwenden Cookies und aehnliche Technologien, um Ihnen die bestmoegliche Erfahrung zu bieten.
|
||||
Sie koennen Ihre Praeferenzen jederzeit aendern.
|
||||
</p>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
</svg>
|
||||
Cookie-Einstellungen
|
||||
</h2>
|
||||
<p className="text-sm text-gray-600 mt-2 leading-relaxed">
|
||||
Wir verwenden Cookies und aehnliche Technologien, um Ihnen die bestmoegliche Erfahrung zu bieten.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* EWR-Only Toggle — always visible in header */}
|
||||
<EWRToggle
|
||||
checked={consent.ewrOnly}
|
||||
onChange={() => setConsent(prev => ({ ...prev, ewrOnly: !prev.ewrOnly }))}
|
||||
blockedCount={blockedVendors.length}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Blocked vendors pills */}
|
||||
{consent.ewrOnly && blockedVendors.length > 0 && (
|
||||
<div className="mt-3 flex flex-wrap gap-1">
|
||||
{blockedVendors.map(name => (
|
||||
<span key={name} className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-red-50 text-red-600 text-[10px] font-medium border border-red-100">
|
||||
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
|
||||
</svg>
|
||||
{name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-4 mt-2 text-xs text-gray-500">
|
||||
<a href="/sdk/einwilligungen/cookie-banner" className="hover:text-purple-600 underline">
|
||||
Datenschutzerklaerung
|
||||
@@ -149,51 +174,6 @@ export function CookieBannerOverlay() {
|
||||
{/* Settings */}
|
||||
{showSettings && (
|
||||
<div className="border-t border-gray-100">
|
||||
{/* === DRITTLAND-SCHUTZ === */}
|
||||
<div className="px-6 py-4 bg-gradient-to-r from-blue-50 to-indigo-50 border-b border-blue-100">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center shrink-0 mt-0.5">
|
||||
<svg className="w-5 h-5 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-semibold text-blue-900">
|
||||
Nur EU/EWR-Anbieter
|
||||
</div>
|
||||
<p className="text-xs text-blue-700 mt-0.5 leading-relaxed">
|
||||
Erlaubt nur Anbieter mit Sitz im Europaeischen Wirtschaftsraum (EWR) oder
|
||||
der Schweiz. Anbieter ausserhalb werden blockiert — auch wenn Sie einer
|
||||
Kategorie zustimmen. {nonEWRCount} Anbieter betroffen.
|
||||
</p>
|
||||
{consent.ewrOnly && blockedVendors.length > 0 && (
|
||||
<div className="mt-2 flex flex-wrap gap-1">
|
||||
{blockedVendors.map(name => (
|
||||
<span key={name} className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-red-100 text-red-700 text-[10px] font-medium">
|
||||
<svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
|
||||
</svg>
|
||||
{name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setConsent(prev => ({ ...prev, ewrOnly: !prev.ewrOnly }))}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors shrink-0 mt-1 ${
|
||||
consent.ewrOnly ? 'bg-blue-600' : 'bg-gray-200'
|
||||
} cursor-pointer`}
|
||||
>
|
||||
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow-sm transition-transform ${
|
||||
consent.ewrOnly ? 'translate-x-6' : 'translate-x-1'
|
||||
}`} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Category Sections */}
|
||||
<div className="px-6 py-4 space-y-1 max-h-[40vh] overflow-y-auto">
|
||||
{Object.entries(CATEGORY_VENDORS).map(([key, cat]) => (
|
||||
@@ -430,3 +410,81 @@ function CategorySection({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function EWRToggle({
|
||||
checked,
|
||||
onChange,
|
||||
blockedCount,
|
||||
}: {
|
||||
checked: boolean
|
||||
onChange: () => void
|
||||
blockedCount: number
|
||||
}) {
|
||||
const [showInfo, setShowInfo] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-end gap-1.5 shrink-0">
|
||||
{/* Toggle Row */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Info Button */}
|
||||
<button
|
||||
onClick={() => setShowInfo(!showInfo)}
|
||||
className="w-5 h-5 rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 flex items-center justify-center text-xs font-bold transition-colors"
|
||||
aria-label="Info zu Nur EU/EWR"
|
||||
>
|
||||
i
|
||||
</button>
|
||||
|
||||
<span className={`text-xs font-medium whitespace-nowrap ${checked ? 'text-blue-700' : 'text-gray-500'}`}>
|
||||
Nur EU/EWR
|
||||
</span>
|
||||
|
||||
<button
|
||||
onClick={onChange}
|
||||
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors shrink-0 cursor-pointer ${
|
||||
checked ? 'bg-blue-600' : 'bg-gray-200'
|
||||
}`}
|
||||
>
|
||||
<span className={`inline-block h-4 w-4 transform rounded-full bg-white shadow-sm transition-transform ${
|
||||
checked ? 'translate-x-6' : 'translate-x-1'
|
||||
}`} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Blocked count badge */}
|
||||
{checked && blockedCount > 0 && (
|
||||
<span className="text-[10px] text-red-600 font-medium">
|
||||
{blockedCount} Anbieter blockiert
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Info Tooltip */}
|
||||
{showInfo && (
|
||||
<div className="absolute right-6 top-16 w-72 p-3 bg-blue-50 border border-blue-200 rounded-lg shadow-lg z-10 text-xs text-blue-800 leading-relaxed">
|
||||
<div className="font-semibold mb-1 flex items-center gap-1.5">
|
||||
<svg className="w-4 h-4 text-blue-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
Nur EU/EWR-Anbieter
|
||||
</div>
|
||||
<p>
|
||||
Erlaubt nur Datenverarbeitung durch Anbieter mit Sitz im Europaeischen
|
||||
Wirtschaftsraum (EU + Island, Liechtenstein, Norwegen) oder der Schweiz.
|
||||
</p>
|
||||
<p className="mt-1.5">
|
||||
Anbieter ausserhalb (z.B. USA) werden blockiert — auch wenn Sie einer
|
||||
Cookie-Kategorie zustimmen. So behalten Sie die volle Kontrolle ueber
|
||||
internationale Datentransfers.
|
||||
</p>
|
||||
<button
|
||||
onClick={() => setShowInfo(false)}
|
||||
className="mt-2 text-blue-600 hover:text-blue-800 font-medium"
|
||||
>
|
||||
Verstanden
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user