@yatoday/astro-ui 0.18.2 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Analytics/AnalyticsGTM.astro +3 -3
- package/components/Analytics/AnalyticsGTMBody.astro +16 -12
- package/components/Analytics/AnalyticsGoogle.astro +3 -1
- package/components/BreadcrumbsItem/BreadcrumbsItem.astro +8 -1
- package/components/Button/types.ts +2 -1
- package/components/CallToAction/CallToAction.astro +1 -1
- package/components/Card0/Card0.astro +20 -32
- package/components/Card1/Card1.astro +11 -19
- package/components/Card2/Card2.astro +10 -14
- package/components/Card3/Card3.astro +15 -20
- package/components/Card4/Card4.astro +6 -2
- package/components/Card5/Card5.astro +8 -1
- package/components/Card6/Card6.astro +76 -59
- package/components/Card7/Card7.astro +27 -18
- package/components/CookieConsent/CookieConsent.astro +323 -308
- package/components/CopyToClipboard/CopyToClipboard.astro +6 -14
- package/components/CopyToClipboard/copy.ts +1 -1
- package/components/DarkMode/__tests__/DarkMode.test.ts +8 -8
- package/components/Headline/Headline.astro +4 -1
- package/components/HeroSection/HeroSection.astro +13 -16
- package/components/Image/Image.astro +1 -7
- package/components/ImageGallery/ImageGallery.astro +85 -90
- package/components/ImageGalleryIkea/ImageGalleryIkea.astro +3 -2
- package/components/ImagePreload/ImagePreload.astro +22 -20
- package/components/ItemGrid1/ItemGrid1.astro +34 -24
- package/components/Metadata/Metadata.astro +1 -5
- package/components/PointMap/PointMap.astro +62 -48
- package/components/PointMap/types.ts +3 -3
- package/components/SEO/SEO.astro +34 -33
- package/components/WidgetBrands/WidgetBrands.astro +8 -1
- package/components/WidgetContent/WidgetContent.astro +22 -9
- package/components/WidgetContent/types.ts +1 -1
- package/components/WidgetFeaturesCard/WidgetFeaturesCard.astro +10 -2
- package/components/WidgetHeroSlider/WidgetHeroSlider.astro +6 -1
- package/components/WidgetNavbarFlyout/WidgetNavbarFlyout.astro +16 -7
- package/components/WidgetSwiperPhotoSlider/WidgetSwiperPhotoSlider.astro +18 -7
- package/components/WidgetTestimonials/WidgetTestimonials.astro +8 -1
- package/components/WidgetWrapper/WidgetWrapper.astro +11 -2
- package/index.d.ts +20 -20
- package/package.json +11 -9
- package/styles/styles.css +303 -160
- package/utils/i18n.ts +2 -2
- package/utils/images.ts +0 -1
- package/utils/slugify.ts +3 -0
- package/vendor-config/config.example.yaml +0 -1
- package/vendor-config/index.ts +1 -1
- package/vendor-config/utils/loadConfig.ts +15 -18
|
@@ -45,11 +45,7 @@ const positionClasses = {
|
|
|
45
45
|
<!-- Cookie Consent Banner -->
|
|
46
46
|
<div
|
|
47
47
|
id="cookie-consent-banner"
|
|
48
|
-
class={cn(
|
|
49
|
-
'fixed z-[9999] hidden',
|
|
50
|
-
positionClasses[position],
|
|
51
|
-
containerClass
|
|
52
|
-
)}
|
|
48
|
+
class={cn('fixed z-[9999] hidden', positionClasses[position], containerClass)}
|
|
53
49
|
data-cookie-name={cookieName}
|
|
54
50
|
data-cookie-expire-days={cookieExpireDays}
|
|
55
51
|
data-consent-version={consentVersion}
|
|
@@ -71,19 +67,9 @@ const positionClasses = {
|
|
|
71
67
|
>
|
|
72
68
|
<div class="container mx-auto px-4 py-6">
|
|
73
69
|
<div class="flex flex-col gap-4">
|
|
74
|
-
{title && (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
set:html={title}
|
|
78
|
-
/>
|
|
79
|
-
)}
|
|
80
|
-
|
|
81
|
-
{description && (
|
|
82
|
-
<p
|
|
83
|
-
class={cn('text-sm text-muted-foreground', descriptionClass)}
|
|
84
|
-
set:html={description}
|
|
85
|
-
/>
|
|
86
|
-
)}
|
|
70
|
+
{title && <div class={cn('text-lg font-semibold text-foreground', titleClass)} set:html={title} />}
|
|
71
|
+
|
|
72
|
+
{description && <p class={cn('text-sm text-muted-foreground', descriptionClass)} set:html={description} />}
|
|
87
73
|
|
|
88
74
|
<div class={cn('flex flex-wrap gap-3', actionsClass)}>
|
|
89
75
|
<button
|
|
@@ -127,7 +113,16 @@ const positionClasses = {
|
|
|
127
113
|
aria-label="Cookie settings"
|
|
128
114
|
title="Cookie settings"
|
|
129
115
|
>
|
|
130
|
-
<svg
|
|
116
|
+
<svg
|
|
117
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
118
|
+
class="w-6 h-6 mx-auto"
|
|
119
|
+
viewBox="0 0 24 24"
|
|
120
|
+
fill="none"
|
|
121
|
+
stroke="currentColor"
|
|
122
|
+
stroke-width="2"
|
|
123
|
+
stroke-linecap="round"
|
|
124
|
+
stroke-linejoin="round"
|
|
125
|
+
>
|
|
131
126
|
<path d="M12 2a10 10 0 1 0 10 10 4 4 0 0 1-5-5 4 4 0 0 1-5-5"></path>
|
|
132
127
|
<path d="M8.5 8.5v.01"></path>
|
|
133
128
|
<path d="M16 15.5v.01"></path>
|
|
@@ -152,7 +147,12 @@ const positionClasses = {
|
|
|
152
147
|
<!-- Consent ID -->
|
|
153
148
|
<div class="text-sm">
|
|
154
149
|
<span class="text-muted-foreground" id="cookie-info-id-label">{consentIdLabel}</span>
|
|
155
|
-
<div
|
|
150
|
+
<div
|
|
151
|
+
class="font-mono text-xs text-foreground mt-1 break-all bg-muted rounded px-2 py-1"
|
|
152
|
+
id="cookie-info-id-value"
|
|
153
|
+
>
|
|
154
|
+
—
|
|
155
|
+
</div>
|
|
156
156
|
</div>
|
|
157
157
|
|
|
158
158
|
<!-- Actions -->
|
|
@@ -179,351 +179,366 @@ const positionClasses = {
|
|
|
179
179
|
<script is:inline>
|
|
180
180
|
// Initialize dataLayer and gtag
|
|
181
181
|
window.dataLayer = window.dataLayer || [];
|
|
182
|
-
function gtag(){
|
|
182
|
+
function gtag() {
|
|
183
|
+
dataLayer.push(arguments);
|
|
184
|
+
}
|
|
183
185
|
|
|
184
186
|
// Set default consent state to denied (GDPR requirement)
|
|
185
187
|
// This MUST run before Google Analytics loads
|
|
186
188
|
gtag('consent', 'default', {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
189
|
+
analytics_storage: 'denied',
|
|
190
|
+
ad_storage: 'denied',
|
|
191
|
+
ad_user_data: 'denied',
|
|
192
|
+
ad_personalization: 'denied',
|
|
193
|
+
wait_for_update: 500, // Wait 500ms for consent update
|
|
192
194
|
});
|
|
193
195
|
</script>
|
|
194
196
|
|
|
195
197
|
<script is:inline>
|
|
196
|
-
(function() {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// Generate UUID v4
|
|
213
|
-
function generateUUID() {
|
|
214
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
215
|
-
const r = Math.random() * 16 | 0;
|
|
216
|
-
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
217
|
-
return v.toString(16);
|
|
218
|
-
});
|
|
219
|
-
}
|
|
198
|
+
(function () {
|
|
199
|
+
const banner = document.getElementById('cookie-consent-banner');
|
|
200
|
+
const fab = document.getElementById('cookie-consent-fab');
|
|
201
|
+
const infoDialog = document.getElementById('cookie-consent-info-dialog');
|
|
202
|
+
if (!banner) return;
|
|
203
|
+
|
|
204
|
+
// Configuration from data attributes
|
|
205
|
+
const config = {
|
|
206
|
+
cookieName: banner.dataset.cookieName || 'cookie_consent_id',
|
|
207
|
+
cookieExpireDays: parseInt(banner.dataset.cookieExpireDays || '365', 10),
|
|
208
|
+
consentVersion: banner.dataset.consentVersion || '1.0',
|
|
209
|
+
apiEndpoint: banner.dataset.apiEndpoint || '',
|
|
210
|
+
organisationSuid: banner.dataset.organisationSuid || '',
|
|
211
|
+
gaId: banner.dataset.gaId || '',
|
|
212
|
+
};
|
|
220
213
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
214
|
+
// Generate UUID v4
|
|
215
|
+
function generateUUID() {
|
|
216
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
217
|
+
const r = (Math.random() * 16) | 0;
|
|
218
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
219
|
+
return v.toString(16);
|
|
220
|
+
});
|
|
228
221
|
}
|
|
229
|
-
return null;
|
|
230
|
-
}
|
|
231
222
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
223
|
+
// Get or create consent ID
|
|
224
|
+
function getConsentId() {
|
|
225
|
+
const value = document.cookie.split('; ').find((row) => row.startsWith(config.cookieName + '='));
|
|
226
|
+
if (value) {
|
|
227
|
+
return value.split('=')[1];
|
|
228
|
+
}
|
|
238
229
|
return null;
|
|
239
230
|
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Save consent status to localStorage
|
|
243
|
-
function saveConsentStatus(status, categories) {
|
|
244
|
-
try {
|
|
245
|
-
localStorage.setItem('cookie_consent_status', JSON.stringify({
|
|
246
|
-
status: status,
|
|
247
|
-
categories: categories,
|
|
248
|
-
timestamp: new Date().toISOString()
|
|
249
|
-
}));
|
|
250
|
-
} catch (e) {
|
|
251
|
-
// Ignore localStorage errors
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Set consent ID cookie
|
|
256
|
-
function setConsentIdCookie(consentId) {
|
|
257
|
-
const date = new Date();
|
|
258
|
-
date.setTime(date.getTime() + (config.cookieExpireDays * 24 * 60 * 60 * 1000));
|
|
259
|
-
document.cookie = config.cookieName + '=' + consentId + ';expires=' + date.toUTCString() + ';path=/;SameSite=Lax';
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Update Google Consent Mode
|
|
263
|
-
function updateGoogleConsent(granted) {
|
|
264
|
-
if (typeof gtag !== 'function') return;
|
|
265
|
-
|
|
266
|
-
const consentState = granted ? 'granted' : 'denied';
|
|
267
|
-
|
|
268
|
-
gtag('consent', 'update', {
|
|
269
|
-
'analytics_storage': consentState,
|
|
270
|
-
'ad_storage': consentState,
|
|
271
|
-
'ad_user_data': consentState,
|
|
272
|
-
'ad_personalization': consentState
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
gtag('event', `consent_${consentState}`);
|
|
276
231
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
232
|
+
// Get consent status from localStorage (faster than API call)
|
|
233
|
+
function getConsentStatus() {
|
|
234
|
+
try {
|
|
235
|
+
const data = localStorage.getItem('cookie_consent_status');
|
|
236
|
+
return data ? JSON.parse(data) : null;
|
|
237
|
+
} catch (e) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
285
240
|
}
|
|
286
241
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
method: 'POST',
|
|
301
|
-
headers: {
|
|
302
|
-
'Content-Type': 'application/json',
|
|
303
|
-
},
|
|
304
|
-
body: JSON.stringify(payload)
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
if (!response.ok) {
|
|
308
|
-
throw new Error('API response: ' + response.status);
|
|
242
|
+
// Save consent status to localStorage
|
|
243
|
+
function saveConsentStatus(status, categories) {
|
|
244
|
+
try {
|
|
245
|
+
localStorage.setItem(
|
|
246
|
+
'cookie_consent_status',
|
|
247
|
+
JSON.stringify({
|
|
248
|
+
status: status,
|
|
249
|
+
categories: categories,
|
|
250
|
+
timestamp: new Date().toISOString(),
|
|
251
|
+
})
|
|
252
|
+
);
|
|
253
|
+
} catch (e) {
|
|
254
|
+
// Ignore localStorage errors
|
|
309
255
|
}
|
|
256
|
+
}
|
|
310
257
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
258
|
+
// Set consent ID cookie
|
|
259
|
+
function setConsentIdCookie(consentId) {
|
|
260
|
+
const date = new Date();
|
|
261
|
+
date.setTime(date.getTime() + config.cookieExpireDays * 24 * 60 * 60 * 1000);
|
|
262
|
+
document.cookie = config.cookieName + '=' + consentId + ';expires=' + date.toUTCString() + ';path=/;SameSite=Lax';
|
|
314
263
|
}
|
|
315
|
-
}
|
|
316
264
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (fab) fab.classList.add('hidden');
|
|
321
|
-
if (infoDialog) infoDialog.classList.add('hidden');
|
|
322
|
-
}
|
|
265
|
+
// Update Google Consent Mode
|
|
266
|
+
function updateGoogleConsent(granted) {
|
|
267
|
+
if (typeof gtag !== 'function') return;
|
|
323
268
|
|
|
324
|
-
|
|
325
|
-
banner.classList.add('hidden');
|
|
326
|
-
if (fab) fab.classList.remove('hidden');
|
|
327
|
-
}
|
|
269
|
+
const consentState = granted ? 'granted' : 'denied';
|
|
328
270
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
271
|
+
gtag('consent', 'update', {
|
|
272
|
+
analytics_storage: consentState,
|
|
273
|
+
ad_storage: consentState,
|
|
274
|
+
ad_user_data: consentState,
|
|
275
|
+
ad_personalization: consentState,
|
|
276
|
+
});
|
|
332
277
|
|
|
333
|
-
|
|
334
|
-
if (fab) fab.classList.add('hidden');
|
|
335
|
-
}
|
|
278
|
+
gtag('event', `consent_${consentState}`);
|
|
336
279
|
|
|
337
|
-
|
|
338
|
-
|
|
280
|
+
console.log('[CookieConsent] Google Consent Mode updated:', consentState);
|
|
281
|
+
}
|
|
339
282
|
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
|
|
283
|
+
// Send consent to backend API
|
|
284
|
+
async function sendConsentToBackend(consentId, status, categories) {
|
|
285
|
+
if (!config.apiEndpoint) {
|
|
286
|
+
console.log('[CookieConsent] No API endpoint configured, skipping backend call');
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
343
289
|
|
|
344
|
-
|
|
345
|
-
|
|
290
|
+
const payload = {
|
|
291
|
+
consent_id: consentId,
|
|
292
|
+
organisation_suid: config.organisationSuid || undefined,
|
|
293
|
+
status: status,
|
|
294
|
+
consent_version: config.consentVersion,
|
|
295
|
+
categories: categories,
|
|
296
|
+
page_url: window.location.href,
|
|
297
|
+
locale: document.documentElement.lang || 'en',
|
|
298
|
+
user_agent: navigator.userAgent,
|
|
299
|
+
};
|
|
346
300
|
|
|
347
|
-
if (dateValueEl && savedConsent && savedConsent.timestamp) {
|
|
348
301
|
try {
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
minute: '2-digit'
|
|
302
|
+
const response = await fetch(config.apiEndpoint, {
|
|
303
|
+
method: 'POST',
|
|
304
|
+
headers: {
|
|
305
|
+
'Content-Type': 'application/json',
|
|
306
|
+
},
|
|
307
|
+
body: JSON.stringify(payload),
|
|
356
308
|
});
|
|
357
|
-
|
|
358
|
-
|
|
309
|
+
|
|
310
|
+
if (!response.ok) {
|
|
311
|
+
throw new Error('API response: ' + response.status);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
console.log('[CookieConsent] Consent saved to backend');
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error('[CookieConsent] Failed to save consent to backend:', error);
|
|
359
317
|
}
|
|
360
318
|
}
|
|
361
319
|
|
|
362
|
-
|
|
363
|
-
|
|
320
|
+
// Show/hide banner, FAB, and info dialog
|
|
321
|
+
function showBanner() {
|
|
322
|
+
banner.classList.remove('hidden');
|
|
323
|
+
if (fab) fab.classList.add('hidden');
|
|
324
|
+
if (infoDialog) infoDialog.classList.add('hidden');
|
|
364
325
|
}
|
|
365
326
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
function hideInfoDialog() {
|
|
370
|
-
if (infoDialog) infoDialog.classList.add('hidden');
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Handle consent
|
|
374
|
-
function handleConsent(accepted) {
|
|
375
|
-
const status = accepted ? 'accepted' : 'denied';
|
|
376
|
-
|
|
377
|
-
// Get or create consent ID
|
|
378
|
-
let consentId = getConsentId();
|
|
379
|
-
if (!consentId) {
|
|
380
|
-
consentId = generateUUID();
|
|
381
|
-
setConsentIdCookie(consentId);
|
|
327
|
+
function hideBanner() {
|
|
328
|
+
banner.classList.add('hidden');
|
|
329
|
+
if (fab) fab.classList.remove('hidden');
|
|
382
330
|
}
|
|
383
331
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
ad_storage: accepted,
|
|
388
|
-
ad_user_data: accepted,
|
|
389
|
-
ad_personalization: accepted
|
|
390
|
-
};
|
|
391
|
-
|
|
392
|
-
// Save to localStorage for quick access
|
|
393
|
-
saveConsentStatus(status, categories);
|
|
394
|
-
|
|
395
|
-
// Update Google Consent Mode
|
|
396
|
-
updateGoogleConsent(accepted);
|
|
397
|
-
|
|
398
|
-
// Send to backend
|
|
399
|
-
sendConsentToBackend(consentId, status, categories);
|
|
332
|
+
function showFab() {
|
|
333
|
+
if (fab) fab.classList.remove('hidden');
|
|
334
|
+
}
|
|
400
335
|
|
|
401
|
-
|
|
402
|
-
|
|
336
|
+
function hideFab() {
|
|
337
|
+
if (fab) fab.classList.add('hidden');
|
|
338
|
+
}
|
|
403
339
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
340
|
+
function showInfoDialog() {
|
|
341
|
+
if (!infoDialog) return;
|
|
342
|
+
|
|
343
|
+
// Populate dialog with current consent info
|
|
344
|
+
const consentId = getConsentId();
|
|
345
|
+
const savedConsent = getConsentStatus();
|
|
346
|
+
|
|
347
|
+
const dateValueEl = document.getElementById('cookie-info-date-value');
|
|
348
|
+
const idValueEl = document.getElementById('cookie-info-id-value');
|
|
349
|
+
|
|
350
|
+
if (dateValueEl && savedConsent && savedConsent.timestamp) {
|
|
351
|
+
try {
|
|
352
|
+
const date = new Date(savedConsent.timestamp);
|
|
353
|
+
dateValueEl.textContent = date.toLocaleDateString(document.documentElement.lang || 'en', {
|
|
354
|
+
year: 'numeric',
|
|
355
|
+
month: 'long',
|
|
356
|
+
day: 'numeric',
|
|
357
|
+
hour: '2-digit',
|
|
358
|
+
minute: '2-digit',
|
|
359
|
+
});
|
|
360
|
+
} catch (e) {
|
|
361
|
+
dateValueEl.textContent = savedConsent.timestamp;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
409
364
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
365
|
+
if (idValueEl && consentId) {
|
|
366
|
+
idValueEl.textContent = consentId;
|
|
367
|
+
}
|
|
413
368
|
|
|
414
|
-
|
|
415
|
-
if (accepted) {
|
|
416
|
-
window.dispatchEvent(new CustomEvent('cookie-consent-analytics-enabled', {
|
|
417
|
-
detail: { consentId }
|
|
418
|
-
}));
|
|
369
|
+
infoDialog.classList.remove('hidden');
|
|
419
370
|
}
|
|
420
|
-
}
|
|
421
371
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
const savedConsent = getConsentStatus();
|
|
372
|
+
function hideInfoDialog() {
|
|
373
|
+
if (infoDialog) infoDialog.classList.add('hidden');
|
|
374
|
+
}
|
|
426
375
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
showFab();
|
|
376
|
+
// Handle consent
|
|
377
|
+
function handleConsent(accepted) {
|
|
378
|
+
const status = accepted ? 'accepted' : 'denied';
|
|
431
379
|
|
|
432
|
-
//
|
|
433
|
-
|
|
380
|
+
// Get or create consent ID
|
|
381
|
+
let consentId = getConsentId();
|
|
382
|
+
if (!consentId) {
|
|
383
|
+
consentId = generateUUID();
|
|
384
|
+
setConsentIdCookie(consentId);
|
|
385
|
+
}
|
|
434
386
|
|
|
435
|
-
//
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
387
|
+
// Define categories based on acceptance
|
|
388
|
+
const categories = {
|
|
389
|
+
analytics_storage: accepted,
|
|
390
|
+
ad_storage: accepted,
|
|
391
|
+
ad_user_data: accepted,
|
|
392
|
+
ad_personalization: accepted,
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
// Save to localStorage for quick access
|
|
396
|
+
saveConsentStatus(status, categories);
|
|
397
|
+
|
|
398
|
+
// Update Google Consent Mode
|
|
399
|
+
updateGoogleConsent(accepted);
|
|
400
|
+
|
|
401
|
+
// Send to backend
|
|
402
|
+
sendConsentToBackend(consentId, status, categories);
|
|
403
|
+
|
|
404
|
+
// Hide banner, show FAB
|
|
405
|
+
hideBanner();
|
|
406
|
+
|
|
407
|
+
// Dispatch custom events
|
|
408
|
+
const eventName = accepted ? 'cookie-consent-accepted' : 'cookie-consent-denied';
|
|
409
|
+
window.dispatchEvent(
|
|
410
|
+
new CustomEvent(eventName, {
|
|
411
|
+
detail: { status, consentId, categories },
|
|
412
|
+
})
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
window.dispatchEvent(
|
|
416
|
+
new CustomEvent('cookie-consent-changed', {
|
|
417
|
+
detail: { status, accepted, consentId, categories },
|
|
418
|
+
})
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
// If accepted, enable analytics
|
|
422
|
+
if (accepted) {
|
|
423
|
+
window.dispatchEvent(
|
|
424
|
+
new CustomEvent('cookie-consent-analytics-enabled', {
|
|
425
|
+
detail: { consentId },
|
|
426
|
+
})
|
|
427
|
+
);
|
|
440
428
|
}
|
|
441
|
-
} else {
|
|
442
|
-
// No consent yet - show banner, hide FAB
|
|
443
|
-
showBanner();
|
|
444
429
|
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Event listeners for buttons
|
|
448
|
-
const denyBtn = document.getElementById('cookie-consent-deny');
|
|
449
|
-
const allowBtn = document.getElementById('cookie-consent-allow');
|
|
450
430
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
431
|
+
// Initialize on page load
|
|
432
|
+
function init() {
|
|
433
|
+
const consentId = getConsentId();
|
|
434
|
+
const savedConsent = getConsentStatus();
|
|
435
|
+
|
|
436
|
+
if (consentId && savedConsent) {
|
|
437
|
+
// User has already made a choice - show FAB, hide banner
|
|
438
|
+
console.log('[CookieConsent] Existing consent found:', savedConsent.status);
|
|
439
|
+
showFab();
|
|
440
|
+
|
|
441
|
+
// Apply saved consent to Google
|
|
442
|
+
updateGoogleConsent(savedConsent.status === 'accepted');
|
|
443
|
+
|
|
444
|
+
// Re-dispatch event for SPA navigation
|
|
445
|
+
if (savedConsent.status === 'accepted') {
|
|
446
|
+
window.dispatchEvent(
|
|
447
|
+
new CustomEvent('cookie-consent-analytics-enabled', {
|
|
448
|
+
detail: { consentId },
|
|
449
|
+
})
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
} else {
|
|
453
|
+
// No consent yet - show banner, hide FAB
|
|
454
|
+
showBanner();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
456
457
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
});
|
|
461
|
-
}
|
|
458
|
+
// Event listeners for buttons
|
|
459
|
+
const denyBtn = document.getElementById('cookie-consent-deny');
|
|
460
|
+
const allowBtn = document.getElementById('cookie-consent-allow');
|
|
462
461
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
}
|
|
462
|
+
if (denyBtn) {
|
|
463
|
+
denyBtn.addEventListener('click', function () {
|
|
464
|
+
handleConsent(false);
|
|
465
|
+
});
|
|
466
|
+
}
|
|
469
467
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
468
|
+
if (allowBtn) {
|
|
469
|
+
allowBtn.addEventListener('click', function () {
|
|
470
|
+
handleConsent(true);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
473
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
474
|
+
// FAB click - show info dialog (not banner directly)
|
|
475
|
+
if (fab) {
|
|
476
|
+
fab.addEventListener('click', function () {
|
|
477
|
+
showInfoDialog();
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
480
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
});
|
|
485
|
-
}
|
|
481
|
+
// Info dialog buttons
|
|
482
|
+
const infoChangeBtn = document.getElementById('cookie-info-change-btn');
|
|
483
|
+
const infoCloseBtn = document.getElementById('cookie-info-close-btn');
|
|
486
484
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
if (infoDialog && !infoDialog.classList.contains('hidden')) {
|
|
490
|
-
const target = e.target;
|
|
491
|
-
if (!infoDialog.contains(target) && target !== fab && !fab.contains(target)) {
|
|
485
|
+
if (infoChangeBtn) {
|
|
486
|
+
infoChangeBtn.addEventListener('click', function () {
|
|
492
487
|
hideInfoDialog();
|
|
493
|
-
|
|
488
|
+
showBanner();
|
|
489
|
+
});
|
|
494
490
|
}
|
|
495
|
-
});
|
|
496
491
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
show: showBanner,
|
|
502
|
-
hide: hideBanner,
|
|
503
|
-
showInfo: showInfoDialog,
|
|
504
|
-
hideInfo: hideInfoDialog,
|
|
505
|
-
accept: function() { handleConsent(true); },
|
|
506
|
-
deny: function() { handleConsent(false); },
|
|
507
|
-
reset: function() {
|
|
508
|
-
// Clear cookie
|
|
509
|
-
document.cookie = config.cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/';
|
|
510
|
-
// Clear localStorage
|
|
511
|
-
localStorage.removeItem('cookie_consent_status');
|
|
512
|
-
// Reset Google consent to denied
|
|
513
|
-
updateGoogleConsent(false);
|
|
514
|
-
// Hide info dialog if open
|
|
515
|
-
hideInfoDialog();
|
|
516
|
-
// Show banner, hide FAB
|
|
517
|
-
showBanner();
|
|
518
|
-
console.log('[CookieConsent] Consent reset');
|
|
519
|
-
},
|
|
520
|
-
// For footer "Manage cookies" button - now shows info dialog first
|
|
521
|
-
manage: function() {
|
|
522
|
-
showInfoDialog();
|
|
492
|
+
if (infoCloseBtn) {
|
|
493
|
+
infoCloseBtn.addEventListener('click', function () {
|
|
494
|
+
hideInfoDialog();
|
|
495
|
+
});
|
|
523
496
|
}
|
|
524
|
-
};
|
|
525
497
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
498
|
+
// Close info dialog when clicking outside
|
|
499
|
+
document.addEventListener('click', function (e) {
|
|
500
|
+
if (infoDialog && !infoDialog.classList.contains('hidden')) {
|
|
501
|
+
const target = e.target;
|
|
502
|
+
if (!infoDialog.contains(target) && target !== fab && !fab.contains(target)) {
|
|
503
|
+
hideInfoDialog();
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// Expose API for external use
|
|
509
|
+
window.CookieConsent = {
|
|
510
|
+
getConsentId: getConsentId,
|
|
511
|
+
getStatus: getConsentStatus,
|
|
512
|
+
show: showBanner,
|
|
513
|
+
hide: hideBanner,
|
|
514
|
+
showInfo: showInfoDialog,
|
|
515
|
+
hideInfo: hideInfoDialog,
|
|
516
|
+
accept: function () {
|
|
517
|
+
handleConsent(true);
|
|
518
|
+
},
|
|
519
|
+
deny: function () {
|
|
520
|
+
handleConsent(false);
|
|
521
|
+
},
|
|
522
|
+
reset: function () {
|
|
523
|
+
// Clear cookie
|
|
524
|
+
document.cookie = config.cookieName + '=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/';
|
|
525
|
+
// Clear localStorage
|
|
526
|
+
localStorage.removeItem('cookie_consent_status');
|
|
527
|
+
// Reset Google consent to denied
|
|
528
|
+
updateGoogleConsent(false);
|
|
529
|
+
// Hide info dialog if open
|
|
530
|
+
hideInfoDialog();
|
|
531
|
+
// Show banner, hide FAB
|
|
532
|
+
showBanner();
|
|
533
|
+
console.log('[CookieConsent] Consent reset');
|
|
534
|
+
},
|
|
535
|
+
// For footer "Manage cookies" button - now shows info dialog first
|
|
536
|
+
manage: function () {
|
|
537
|
+
showInfoDialog();
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
// Initialize
|
|
542
|
+
init();
|
|
543
|
+
})();
|
|
529
544
|
</script>
|