Skip to content

Commit 1590df3

Browse files
authored
Add cookie banner (#44)
* can be button or link * can be button or link * cookie notification banner
1 parent 2ac32eb commit 1590df3

File tree

7 files changed

+162
-9
lines changed

7 files changed

+162
-9
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PUBLIC_GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX

messages/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
"socials.facebook.cta": "Facebook",
4848
"socials.facebook.href": "https://www.facebook.com/SeattleCommNet",
4949

50+
"cookieBanner.message": "We use cookies to improve your experience.<br /> By clicking \"Accept\", you consent to the use of analytics cookies.",
51+
"cookieBanner.accept": "Accept",
52+
"cookieBanner.deny": "Deny",
53+
"cookieBanner.settings": "Cookie Settings",
54+
5055

5156
"=== PAGES HOME ===" : "comment",
5257

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<script>
2+
import { onMount } from "svelte";
3+
import { fly } from "svelte/transition";
4+
5+
import { PUBLIC_GOOGLE_ANALYTICS_ID } from "$env/static/public";
6+
7+
import { m } from '$lib/paraglide/messages.js';
8+
9+
import Button from "./Button.svelte";
10+
11+
let showBanner = $state(false);
12+
13+
onMount(() => {
14+
const consentStatus = localStorage.getItem("consent_status");
15+
16+
if (consentStatus === null) {
17+
showBanner = true;
18+
} else if (consentStatus === "granted") {
19+
window.gtag("consent", "update", {
20+
analytics_storage: "granted",
21+
ad_storage: "granted",
22+
ad_user_data: "granted",
23+
ad_personalization: "granted",
24+
});
25+
}
26+
});
27+
28+
function handleAccept() {
29+
showBanner = false;
30+
localStorage.setItem("consent_status", "granted");
31+
32+
window.gtag("consent", "update", {
33+
analytics_storage: "granted",
34+
ad_storage: "granted",
35+
ad_user_data: "granted",
36+
ad_personalization: "granted",
37+
});
38+
}
39+
40+
function handleDeny() {
41+
showBanner = false;
42+
localStorage.setItem("consent_status", "denied");
43+
}
44+
45+
export function reopenBanner() {
46+
showBanner = true;
47+
localStorage.removeItem("consent_status");
48+
}
49+
</script>
50+
51+
<svelte:head>
52+
<script>
53+
window.dataLayer = window.dataLayer || [];
54+
55+
function gtag() {
56+
dataLayer.push(arguments);
57+
}
58+
59+
window.gtag = gtag;
60+
61+
gtag("consent", "default", {
62+
analytics_storage: "denied",
63+
ad_storage: "denied",
64+
ad_user_data: "denied",
65+
ad_personalization: "denied",
66+
});
67+
</script>
68+
69+
<script async src={`https://www.googletagmanager.com/gtag/js?id=${PUBLIC_GOOGLE_ANALYTICS_ID}`}></script>
70+
<script>
71+
gtag("js", new Date());
72+
gtag("config", "{PUBLIC_GOOGLE_ANALYTICS_ID}");
73+
</script>
74+
</svelte:head>
75+
76+
{#if showBanner}
77+
<div transition:fly="{{ x: 20, duration: 300 }}" class="banner">
78+
<p>
79+
{@html m["cookieBanner.message"]() }
80+
</p>
81+
82+
<div class="buttons">
83+
<Button type="medium" onclick={handleAccept}>{ m["cookieBanner.accept"]() }</Button>
84+
<Button type="medium" onclick={handleDeny}>{ m["cookieBanner.deny"]() }</Button>
85+
</div>
86+
</div>
87+
{/if}
88+
89+
<style lang="postcss">
90+
.banner {
91+
position: fixed;
92+
bottom: 1em;
93+
right: 0;
94+
width: 370px;
95+
96+
background-color: #fff;
97+
98+
padding: 1rem;
99+
100+
border: solid 1px #ccc;
101+
border-right-width:0;
102+
border-top-left-radius: 0.6em;
103+
border-bottom-left-radius: 0.6em;
104+
box-shadow: 0 0 1em #0004;
105+
106+
p {
107+
margin: 0 0 1em;
108+
font-size: 1em;
109+
}
110+
}
111+
112+
.buttons {
113+
display: flex;
114+
gap: 0.5em;
115+
}
116+
</style>

src/lib/components/Button.svelte

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
<script lang="ts">
22
let {
3-
href,
3+
href = null,
44
children,
55
type = null,
66
arrow = null,
77
dataTest = null,
8+
onclick = null
89
} = $props();
910
1011
let cssClass = $state("button");
@@ -20,12 +21,21 @@
2021
}
2122
</script>
2223

23-
<a href={href} class={cssClass} data-test={dataTest}>
24-
{@render children()}
25-
{#if arrow}
26-
27-
{/if}
28-
</a>
24+
{#if href}
25+
<a href={href} class={cssClass} data-test={dataTest}>
26+
{@render children()}
27+
{#if arrow}
28+
29+
{/if}
30+
</a>
31+
{:else}
32+
<button class={cssClass} data-test={dataTest} onclick={onclick}>
33+
{@render children()}
34+
{#if arrow}
35+
36+
{/if}
37+
</button>
38+
{/if}
2939

3040
<style>
3141
.button {

src/lib/components/Footer.svelte

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
<script>
22
import { m } from '$lib/paraglide/messages.js';
3-
// import { setLocale } from '$lib/paraglide/runtime';
43
import Button from './Button.svelte';
54
import Socials from './Socials.svelte';
65
import Wrapper from './Wrapper.svelte';
6+
import Analytics from './Analytics.svelte';
7+
8+
let analytics;
79
810
const buttons = [
911
{
@@ -33,14 +35,22 @@
3335
<Button {href} type="medium">{cta}</Button>
3436
</div>
3537
{/each}
38+
39+
<div>
40+
<Button type="medium" onclick={() => analytics?.reopenBanner()}>
41+
{m["cookieBanner.settings"]()}
42+
</Button>
43+
</div>
3644
</div>
3745

3846
<!-- <button onclick={() => setLocale('en')}>en</button> -->
3947
</footer>
4048
</Wrapper>
4149
</div>
4250

43-
<style>
51+
<Analytics bind:this={analytics} />
52+
53+
<style lang="postcss">
4454
.footer {
4555
background-color: var(--color-brand-primary);
4656
@@ -57,6 +67,7 @@
5767
margin: 0;
5868
}
5969
}
70+
6071
footer {
6172
display: flex;
6273
flex-direction: column;

src/lib/styles/globals.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ a {
9090
color: var(--color-link);
9191
}
9292

93+
button {
94+
color: var(--color-text);
95+
border: none;
96+
cursor: pointer;
97+
}
98+
9399
section {
94100
margin: var(--layout-section-vertical) 0;
95101
}

src/routes/+layout.svelte

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import Header from '$lib/components/Header.svelte';
55
import Footer from '$lib/components/Footer.svelte';
66
import Metatags from '$lib/components/Metatags.svelte';
7+
import Analytics from '$lib/components/Analytics.svelte';
78
89
let { children } = $props();
910
</script>
1011

12+
1113
<Metatags />
1214

1315
<Header />
@@ -18,6 +20,8 @@
1820

1921
<Footer/>
2022

23+
<Analytics />
24+
2125
<style lang="postcss">
2226
2327
</style>

0 commit comments

Comments
 (0)