Skip to content

Commit f9e4d51

Browse files
committed
Added Tracking
1 parent 50b92c8 commit f9e4d51

55 files changed

Lines changed: 1878 additions & 1218 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

assets/css/cookie-banner.css

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
.cookie-banner {
2+
position: fixed;
3+
bottom: 0;
4+
left: 0;
5+
right: 0;
6+
background-color: rgba(30, 30, 30, 0.95);
7+
backdrop-filter: blur(10px);
8+
border-top: 1px solid rgba(255, 255, 255, 0.1);
9+
padding: 12px;
10+
z-index: 10000;
11+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
12+
box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.3);
13+
}
14+
15+
.cookie-content {
16+
max-width: 1400px;
17+
margin: 0 auto;
18+
display: flex;
19+
flex-direction: row;
20+
align-items: center;
21+
gap: 20px;
22+
flex-wrap: wrap;
23+
justify-content: center;
24+
}
25+
26+
.cookie-content p {
27+
margin: 0;
28+
text-align: left;
29+
font-size: 0.85rem;
30+
color: #ccc;
31+
line-height: 1.5;
32+
flex: 1;
33+
min-width: 300px;
34+
max-width: 900px;
35+
}
36+
37+
.cookie-buttons {
38+
display: flex;
39+
gap: 8px;
40+
flex-wrap: nowrap;
41+
justify-content: center;
42+
}
43+
44+
.cookie-buttons button {
45+
padding: 6px 12px;
46+
border: none;
47+
border-radius: 4px;
48+
cursor: pointer;
49+
font-size: 0.85rem;
50+
transition: all 0.2s;
51+
font-weight: 500;
52+
white-space: nowrap;
53+
}
54+
55+
.cookie-buttons button:active {
56+
transform: scale(0.98);
57+
}
58+
59+
.btn-accept {
60+
background-color: #8dc63f;
61+
color: #000;
62+
}
63+
64+
.btn-accept:hover {
65+
background-color: #9ad14b;
66+
transform: translateY(-1px);
67+
}
68+
69+
.btn-reject {
70+
background-color: #6c757d;
71+
color: white;
72+
}
73+
74+
.btn-reject:hover {
75+
background-color: #5a6268;
76+
transform: translateY(-1px);
77+
}
78+
79+
@media (max-width: 768px) {
80+
.cookie-content {
81+
flex-direction: column;
82+
text-align: center;
83+
gap: 12px;
84+
}
85+
86+
.cookie-content p {
87+
font-size: 0.8rem;
88+
min-width: unset;
89+
text-align: center;
90+
}
91+
92+
.cookie-buttons {
93+
width: 100%;
94+
gap: 6px;
95+
}
96+
97+
.cookie-buttons button {
98+
flex: 1;
99+
font-size: 0.8rem;
100+
padding: 8px 6px;
101+
}
102+
}

assets/js/cookie-banner.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Cookie banner functionality
2+
document.addEventListener('DOMContentLoaded', function() {
3+
const cookieBanner = document.getElementById('cookie-banner');
4+
const acceptButton = document.getElementById('accept-cookies');
5+
const rejectButton = document.getElementById('reject-cookies');
6+
7+
// Check if user has already made a choice
8+
if (getCookie('cookie-consent')) {
9+
cookieBanner.style.display = 'none';
10+
initializeTracking();
11+
return;
12+
}
13+
14+
// Show the cookie banner
15+
cookieBanner.style.display = 'block';
16+
17+
// Accept cookies
18+
acceptButton.addEventListener('click', function() {
19+
setCookie('cookie-consent', 'accepted', 365);
20+
setCookie('analytics-cookies', 'accepted', 365);
21+
cookieBanner.style.display = 'none';
22+
enableTracking();
23+
});
24+
25+
// Reject cookies
26+
rejectButton.addEventListener('click', function() {
27+
setCookie('cookie-consent', 'rejected', 365);
28+
setCookie('analytics-cookies', 'rejected', 365);
29+
cookieBanner.style.display = 'none';
30+
disableTracking();
31+
});
32+
33+
// Initialize tracking based on existing preferences
34+
initializeTracking();
35+
});
36+
37+
// Set a cookie
38+
function setCookie(name, value, days) {
39+
const expires = new Date();
40+
expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
41+
document.cookie = name + '=' + value + ';expires=' + expires.toUTCString() + ';path=/';
42+
}
43+
44+
// Get a cookie value
45+
function getCookie(name) {
46+
const nameEQ = name + '=';
47+
const ca = document.cookie.split(';');
48+
for (let i = 0; i < ca.length; i++) {
49+
let c = ca[i];
50+
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
51+
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
52+
}
53+
return null;
54+
}
55+
56+
// Enable tracking (accept)
57+
function enableTracking() {
58+
updateDatabuddyTracking(true);
59+
}
60+
61+
// Disable tracking (deny)
62+
function disableTracking() {
63+
updateDatabuddyTracking(false);
64+
}
65+
66+
// Initialize tracking based on cookie preferences
67+
function initializeTracking() {
68+
const analyticsCookies = getCookie('analytics-cookies');
69+
70+
if (analyticsCookies === 'accepted') {
71+
enableTracking();
72+
} else if (analyticsCookies === 'rejected') {
73+
disableTracking();
74+
}
75+
}
76+
77+
// Update Databuddy tracking settings
78+
function updateDatabuddyTracking(enableTracking) {
79+
// Find the Databuddy script
80+
const script = document.querySelector('script[src="https://cdn.databuddy.cc/databuddy.js"]');
81+
if (script) {
82+
// Clear all existing data attributes
83+
Object.keys(script.dataset).forEach(key => {
84+
delete script.dataset[key];
85+
});
86+
87+
// Set common attributes
88+
script.dataset.clientId = '1DL7tse_ZTnMsjrVbv_Bp';
89+
script.dataset.enableBatching = 'true';
90+
script.crossOrigin = 'anonymous';
91+
92+
// Set tracking-specific attributes based on user preference
93+
if (enableTracking) {
94+
// When accepted, enable all tracking features
95+
script.dataset.trackOutgoingLinks = 'true';
96+
script.dataset.trackInteractions = 'true';
97+
script.dataset.trackEngagement = 'true';
98+
script.dataset.trackScrollDepth = 'true';
99+
script.dataset.trackWebVitals = 'true';
100+
script.dataset.trackErrors = 'true';
101+
}
102+
// When denied, only the common attributes remain (no additional tracking)
103+
}
104+
}

layouts/_default/baseof.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,15 @@
3333
{{- partial "search.html" . -}}
3434
{{ end }}
3535
</div>
36+
{{- partial "cookie-banner.html" . -}}
3637
</body>
3738
{{ if .Site.Params.buymeacoffee.globalWidget | default false }}
3839
<script data-name="BMC-Widget" data-cfasync="false" src="https://cdnjs.buymeacoffee.com/1.0.0/widget.prod.min.js"
3940
data-id="{{ .Site.Params.buymeacoffee.identifier }}" data-description="Support me on Buy me a coffee!" data-message="{{ .Site.Params.buymeacoffee.globalWidgetMessage | default "" }}"
4041
data-color="{{ .Site.Params.buymeacoffee.globalWidgetColor | default "#FFDD00" }}" data-position="{{ .Site.Params.buymeacoffee.globalWidgetPosition | default "Left" }}" data-x_margin="18" data-y_margin="18"></script>
4142
{{ end }}
43+
{{ $cookieJS := resources.Get "js/cookie-banner.js" }}
44+
{{ if $cookieJS }}
45+
<script src="{{ $cookieJS.RelPermalink }}"></script>
46+
{{ end }}
4247
</html>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<div id="cookie-banner" class="cookie-banner">
2+
<div class="cookie-content">
3+
<p>This website uses DataBuddy, a privacy-first analytics service. DataBuddy does not use cookies, does not collect personal data, and anonymizes all information. Analytics are aggregated and cannot be linked to individual visitors. Legal basis: Art. 6(1)(f) GDPR (legitimate interest in website optimization).</p>
4+
<div class="cookie-buttons">
5+
<button id="accept-cookies" class="btn-accept">Accept</button>
6+
<button id="reject-cookies" class="btn-reject">Reject</button>
7+
</div>
8+
</div>
9+
</div>

layouts/partials/head.html

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,32 +153,56 @@
153153
{{ end }}
154154
{{ end }}
155155

156+
{{/* Cookie Banner CSS */}}
157+
{{ $cookieCSS := resources.Get "css/cookie-banner.css" }}
158+
{{ if $cookieCSS }}
159+
<link type="text/css" rel="stylesheet" href="{{ $cookieCSS.RelPermalink }}" />
160+
{{ end }}
161+
156162
{{/* Databuddy Analytics */}}
157163
<script>
164+
// Check cookie consent before loading Databuddy
165+
function getCookie(name) {
166+
const nameEQ = name + '=';
167+
const ca = document.cookie.split(';');
168+
for (let i = 0; i < ca.length; i++) {
169+
let c = ca[i];
170+
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
171+
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
172+
}
173+
return null;
174+
}
175+
158176
// Only load Databuddy analytics in production environment
159177
if (window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1' && window.location.protocol !== 'file:') {
160178
var script = document.createElement('script');
161179
script.src = 'https://cdn.databuddy.cc/databuddy.js';
162180
script.async = true;
163181
script.crossOrigin = 'anonymous';
164182
script.dataset.clientId = '1DL7tse_ZTnMsjrVbv_Bp';
165-
script.dataset.trackHashChanges = 'true';
166-
script.dataset.trackAttributes = 'true';
167-
script.dataset.trackOutgoingLinks = 'true';
168-
script.dataset.trackInteractions = 'true';
169-
script.dataset.trackEngagement = 'true';
170-
script.dataset.trackScrollDepth = 'true';
171-
script.dataset.trackExitIntent = 'true';
172-
script.dataset.trackBounceRate = 'true';
173-
script.dataset.trackWebVitals = 'true';
174-
script.dataset.trackErrors = 'true';
175183
script.dataset.enableBatching = 'true';
176-
184+
185+
// Check user consent for tracking
186+
const analyticsCookies = getCookie('analytics-cookies');
187+
const enableTracking = analyticsCookies === 'accepted';
188+
189+
// Set tracking options based on user preference
190+
if (enableTracking) {
191+
// When accepted, enable all tracking features
192+
script.dataset.trackOutgoingLinks = 'true';
193+
script.dataset.trackInteractions = 'true';
194+
script.dataset.trackEngagement = 'true';
195+
script.dataset.trackScrollDepth = 'true';
196+
script.dataset.trackWebVitals = 'true';
197+
script.dataset.trackErrors = 'true';
198+
}
199+
// When denied, only the common attributes remain (no additional tracking)
200+
177201
// Add error handling
178202
script.onerror = function() {
179203
console.warn('Failed to load Databuddy analytics script');
180204
};
181-
205+
182206
document.head.appendChild(script);
183207
}
184208
</script>

public/404.html

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -137,31 +137,55 @@
137137

138138

139139

140+
141+
142+
<link type="text/css" rel="stylesheet" href="/css/cookie-banner.css" />
143+
144+
145+
140146
<script>
141147

148+
function getCookie(name) {
149+
const nameEQ = name + '=';
150+
const ca = document.cookie.split(';');
151+
for (let i = 0; i < ca.length; i++) {
152+
let c = ca[i];
153+
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
154+
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
155+
}
156+
return null;
157+
}
158+
159+
142160
if (window.location.hostname !== 'localhost' && window.location.hostname !== '127.0.0.1' && window.location.protocol !== 'file:') {
143161
var script = document.createElement('script');
144162
script.src = 'https://cdn.databuddy.cc/databuddy.js';
145163
script.async = true;
146164
script.crossOrigin = 'anonymous';
147165
script.dataset.clientId = '1DL7tse_ZTnMsjrVbv_Bp';
148-
script.dataset.trackHashChanges = 'true';
149-
script.dataset.trackAttributes = 'true';
150-
script.dataset.trackOutgoingLinks = 'true';
151-
script.dataset.trackInteractions = 'true';
152-
script.dataset.trackEngagement = 'true';
153-
script.dataset.trackScrollDepth = 'true';
154-
script.dataset.trackExitIntent = 'true';
155-
script.dataset.trackBounceRate = 'true';
156-
script.dataset.trackWebVitals = 'true';
157-
script.dataset.trackErrors = 'true';
158166
script.dataset.enableBatching = 'true';
159-
167+
168+
169+
const analyticsCookies = getCookie('analytics-cookies');
170+
const enableTracking = analyticsCookies === 'accepted';
171+
172+
173+
if (enableTracking) {
174+
175+
script.dataset.trackOutgoingLinks = 'true';
176+
script.dataset.trackInteractions = 'true';
177+
script.dataset.trackEngagement = 'true';
178+
script.dataset.trackScrollDepth = 'true';
179+
script.dataset.trackWebVitals = 'true';
180+
script.dataset.trackErrors = 'true';
181+
}
182+
183+
160184

161185
script.onerror = function() {
162186
console.warn('Failed to load Databuddy analytics script');
163187
};
164-
188+
165189
document.head.appendChild(script);
166190
}
167191
</script>
@@ -539,7 +563,18 @@ <h1 class="mb-3 text-4xl font-extrabold">Page Not Found 😕</h1>
539563
</div>
540564
</div>
541565

566+
</div><div id="cookie-banner" class="cookie-banner">
567+
<div class="cookie-content">
568+
<p>This website uses DataBuddy, a privacy-first analytics service. DataBuddy does not use cookies, does not collect personal data, and anonymizes all information. Analytics are aggregated and cannot be linked to individual visitors. Legal basis: Art. 6(1)(f) GDPR (legitimate interest in website optimization).</p>
569+
<div class="cookie-buttons">
570+
<button id="accept-cookies" class="btn-accept">Accept</button>
571+
<button id="reject-cookies" class="btn-reject">Reject</button>
572+
</div>
542573
</div>
543-
</body>
574+
</div></body>
575+
576+
577+
578+
<script src="/js/cookie-banner.js"></script>
544579

545580
</html>

0 commit comments

Comments
 (0)