Add consent reopener: floating widget + anchor link trigger
Allow visitors to reopen the cookie preferences modal after making their choice via a configurable floating button (bottom-right or right-side vertical) or any anchor link with href="#att-cc-preferences". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -248,6 +248,55 @@ body.att-cc-modal-active {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* --- Floating Widget --- */
|
||||
|
||||
.att-cc-widget {
|
||||
position: fixed;
|
||||
z-index: 999998;
|
||||
padding: 8px 14px;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: var(--att-cc-bg, #1a1a2e);
|
||||
color: var(--att-cc-text, #fff);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
||||
transition: opacity 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.att-cc-widget:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.att-cc-widget:focus-visible {
|
||||
outline: 2px solid #fff;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.att-cc-widget--bottom-right {
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.att-cc-widget--right {
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: rotate(-90deg) translateX(50%);
|
||||
transform-origin: right center;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.att-cc-widget svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
/* --- Responsive --- */
|
||||
|
||||
@media (max-width: 600px) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/**
|
||||
* ATT Consent Banner UI
|
||||
*
|
||||
* Handles banner display, preferences modal, focus trapping, and user interactions.
|
||||
* Handles banner display, preferences modal, floating widget, anchor link
|
||||
* triggers, focus trapping, and user interactions.
|
||||
* Depends on AttConsent (consent-manager.js) for consent state management.
|
||||
*/
|
||||
(function() {
|
||||
@@ -9,43 +10,12 @@
|
||||
|
||||
var banner = document.getElementById('att-cc-banner');
|
||||
var modal = document.getElementById('att-cc-modal');
|
||||
var widget = document.getElementById('att-cc-widget');
|
||||
|
||||
if (!banner || !modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If consent already exists, hide the banner immediately.
|
||||
if (AttConsent.hasConsent()) {
|
||||
hideBanner();
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Banner buttons ---
|
||||
|
||||
var acceptBtn = banner.querySelector('[data-att-cc="accept-all"]');
|
||||
var rejectBtn = banner.querySelector('[data-att-cc="reject-all"]');
|
||||
var prefsBtn = banner.querySelector('[data-att-cc="preferences"]');
|
||||
|
||||
if (acceptBtn) {
|
||||
acceptBtn.addEventListener('click', function() {
|
||||
AttConsent.update({ functional: true, analytics: true, marketing: true });
|
||||
hideBanner();
|
||||
});
|
||||
}
|
||||
|
||||
if (rejectBtn) {
|
||||
rejectBtn.addEventListener('click', function() {
|
||||
AttConsent.update({ functional: false, analytics: false, marketing: false });
|
||||
hideBanner();
|
||||
});
|
||||
}
|
||||
|
||||
if (prefsBtn) {
|
||||
prefsBtn.addEventListener('click', function() {
|
||||
openModal();
|
||||
});
|
||||
}
|
||||
|
||||
// --- Modal buttons ---
|
||||
|
||||
var saveBtn = modal.querySelector('[data-att-cc="save-preferences"]');
|
||||
@@ -62,6 +32,7 @@
|
||||
AttConsent.update(categories);
|
||||
closeModal();
|
||||
hideBanner();
|
||||
showWidget();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,6 +48,59 @@
|
||||
});
|
||||
}
|
||||
|
||||
// --- Floating widget click handler ---
|
||||
|
||||
if (widget) {
|
||||
widget.addEventListener('click', function() {
|
||||
openModal();
|
||||
});
|
||||
}
|
||||
|
||||
// --- Anchor link listener ---
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
var link = e.target.closest('a[href="#att-cc-preferences"]');
|
||||
if (link) {
|
||||
e.preventDefault();
|
||||
openModal();
|
||||
}
|
||||
});
|
||||
|
||||
// --- Initial state ---
|
||||
|
||||
if (AttConsent.hasConsent()) {
|
||||
hideBanner();
|
||||
showWidget();
|
||||
} else {
|
||||
// --- Banner buttons (only needed for first-time visitors) ---
|
||||
|
||||
var acceptBtn = banner.querySelector('[data-att-cc="accept-all"]');
|
||||
var rejectBtn = banner.querySelector('[data-att-cc="reject-all"]');
|
||||
var prefsBtn = banner.querySelector('[data-att-cc="preferences"]');
|
||||
|
||||
if (acceptBtn) {
|
||||
acceptBtn.addEventListener('click', function() {
|
||||
AttConsent.update({ functional: true, analytics: true, marketing: true });
|
||||
hideBanner();
|
||||
showWidget();
|
||||
});
|
||||
}
|
||||
|
||||
if (rejectBtn) {
|
||||
rejectBtn.addEventListener('click', function() {
|
||||
AttConsent.update({ functional: false, analytics: false, marketing: false });
|
||||
hideBanner();
|
||||
showWidget();
|
||||
});
|
||||
}
|
||||
|
||||
if (prefsBtn) {
|
||||
prefsBtn.addEventListener('click', function() {
|
||||
openModal();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// --- Helper functions ---
|
||||
|
||||
function hideBanner() {
|
||||
@@ -84,6 +108,12 @@
|
||||
banner.classList.add('att-cc-hidden');
|
||||
}
|
||||
|
||||
function showWidget() {
|
||||
if (widget) {
|
||||
widget.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
function openModal() {
|
||||
// Pre-fill checkboxes with existing consent if available.
|
||||
var existing = AttConsent.getConsent();
|
||||
@@ -104,9 +134,14 @@
|
||||
modal.classList.remove('att-cc-modal--open');
|
||||
document.body.classList.remove('att-cc-modal-active');
|
||||
|
||||
// Return focus to the preferences button.
|
||||
if (prefsBtn) {
|
||||
prefsBtn.focus();
|
||||
// Return focus to the widget if visible, otherwise the banner prefs button.
|
||||
if (widget && widget.style.display !== 'none') {
|
||||
widget.focus();
|
||||
} else {
|
||||
var prefsBtn = banner.querySelector('[data-att-cc="preferences"]');
|
||||
if (prefsBtn) {
|
||||
prefsBtn.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,13 +197,4 @@
|
||||
|
||||
element.addEventListener('keydown', handleKeydown);
|
||||
}
|
||||
|
||||
// Listen for programmatic consent revocation to re-show banner.
|
||||
document.addEventListener('att_consent_update', function(e) {
|
||||
var cats = e.detail;
|
||||
if (!cats.functional && !cats.analytics && !cats.marketing) {
|
||||
// All denied - consent was effectively revoked, but don't re-show
|
||||
// banner immediately (user just clicked reject).
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user