First draft.
This commit is contained in:
@@ -1,3 +1,85 @@
|
||||
# hugo-cookie-consent
|
||||
|
||||
Hugo module that implements a cookie-consent message and functionality to change the cookie-consent decision.
|
||||
**Hugo module that implements a cookie-consent message and functionality to change
|
||||
the cookie-consent decision.**
|
||||
|
||||
The purpose of this module is to help make a site [GDPR][] compliant. It can
|
||||
optionally insert tracking code that calls a [Matomo][] instance. This will only
|
||||
happen after visitors have accepted the use of a cookie -- no logging will take
|
||||
place before visitors have interacted with the cookie information message. Their
|
||||
decision is stored in the browser's Local Storage, and it is _not_ personal data
|
||||
as defined by the GDPR.
|
||||
|
||||
This Hugo Module requires Hugo [v0.146.0][]+ which uses the new layout directory
|
||||
structure with `_partials` and `_shortcode` directories with leading underscores.
|
||||
|
||||
[Anthropic Claude][] helped in creating this module (paid subscription).
|
||||
|
||||
## Installation in your Hugo site
|
||||
|
||||
1. Turn the Hugo site into a Hugo module:
|
||||
|
||||
```bash
|
||||
hugo mod init <identifier>
|
||||
```
|
||||
|
||||
Where `<identifier>` may be the path to the site's Git repository or anything
|
||||
else; see [Hugo's docs][mod-doc].
|
||||
|
||||
2. Add the hugo-cookie-consent module by adding this `module.imports.path` to your
|
||||
site configuration file:
|
||||
|
||||
```yaml
|
||||
# config/_default/hugo.yaml
|
||||
module:
|
||||
imports:
|
||||
- path: git.bovender.de/daniel/hugo-cookie-consent
|
||||
```
|
||||
|
||||
3. Add configuration keys (see [below](#configuration)).
|
||||
|
||||
4. If your site's language is neither English nor German, add a few terms in the
|
||||
desired language to the language tables.
|
||||
|
||||
5. Make your pages load the JavaScript code, e. g. by adding this to a `script.html`
|
||||
partial:
|
||||
|
||||
```html
|
||||
{{- $js := resources.Get "js/cookie-consent.js" | minify -}}
|
||||
<script src="{{ $js.RelPermalink }}" defer></script>
|
||||
{{- $js := resources.Get "js/tracker-code.js" | minify -}}
|
||||
<script src="{{ $js.RelPermalink }}" defer></script>
|
||||
```
|
||||
|
||||
6. Optionally, insert a `cookie-settings` partial somewhere on your site to enable
|
||||
visitors to review and revise their choice. The privacy statement page might
|
||||
be a good place for this.
|
||||
|
||||
```md
|
||||
{{< cookie-settings >}}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
You can configure the module by defining site parameters in your
|
||||
`hugo.yaml` or `hugo.toml` configuration file. The following
|
||||
snippet shows the default values.
|
||||
|
||||
```yaml
|
||||
# config/_default/params.yaml
|
||||
hugo_cookie_consent:
|
||||
privacy_policy_url:
|
||||
enable_matomo: false
|
||||
matomo_host:
|
||||
matomo_site_id:
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| `privacy_policy_url` | URL of the privacy policy page
|
||||
|
||||
[anthropic claude]: https://claude.ai
|
||||
[gdpr]: https://en.wikipedia.org/wiki/GDPR
|
||||
[matomo]: https://matomo.org
|
||||
[mod-doc]: https://gohugo.io/hugo-modules/use-modules/#import
|
||||
[v0.146.0]: https://github.com/gohugoio/hugo/releases/tag/v0.146.0
|
||||
@@ -0,0 +1,51 @@
|
||||
(function () {
|
||||
var KEY = 'cookie_consent';
|
||||
var banner = document.getElementById('cookie-banner');
|
||||
if (!banner) return;
|
||||
updateStatus();
|
||||
|
||||
var consent = localStorage.getItem(KEY);
|
||||
if (!consent) banner.style.display = 'flex';
|
||||
|
||||
function dismiss() {
|
||||
banner.classList.add('fade-out');
|
||||
setTimeout(function () { banner.style.display = 'none'; }, 500);
|
||||
}
|
||||
|
||||
function updateStatus() {
|
||||
var el = document.getElementById('cookie-status');
|
||||
if (!el) return;
|
||||
var consent = localStorage.getItem(KEY);
|
||||
el.textContent = consent === 'accepted' ? el.dataset.accepted
|
||||
: consent === 'declined' ? el.dataset.declined
|
||||
: el.dataset.none;
|
||||
}
|
||||
|
||||
document.getElementById('cookie-accept').onclick = function () {
|
||||
localStorage.setItem(KEY, 'accepted');
|
||||
updateStatus();
|
||||
dismiss();
|
||||
window.dispatchEvent(new Event('cookieAccepted'));
|
||||
};
|
||||
|
||||
document.getElementById('cookie-decline').onclick = function () {
|
||||
localStorage.setItem(KEY, 'declined');
|
||||
updateStatus();
|
||||
dismiss();
|
||||
};
|
||||
|
||||
window.reopenCookieBanner = function () {
|
||||
localStorage.removeItem(KEY);
|
||||
updateStatus();
|
||||
banner.classList.remove('fade-out');
|
||||
banner.style.display = 'flex';
|
||||
};
|
||||
|
||||
window.addEventListener('cookieAccepted', function () {
|
||||
if (typeof window.trackVisit === 'function') window.trackVisit();
|
||||
});
|
||||
|
||||
if (localStorage.getItem(KEY) === 'accepted') {
|
||||
if (typeof window.trackVisit === 'function') window.trackVisit();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,24 @@
|
||||
(function () {
|
||||
function trackVisit() {
|
||||
var banner = document.getElementById('cookie_banner');
|
||||
if (!banner) return;
|
||||
var matomoUrl = banner.dataset.matomoUrl;
|
||||
var siteId = banner.dataset.matomoSiteId;
|
||||
if (!matomoUrl || !siteId) return;
|
||||
|
||||
var _paq = window._paq = window._paq || [];
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
_paq.push(['setTrackerUrl', matomoUrl + 'matomo.php']);
|
||||
_paq.push(['setSiteId', siteId]);
|
||||
var d = document, g = d.createElement('script'),
|
||||
s = d.getElementsByTagName('script')[0];
|
||||
g.async = true; g.src = matomoUrl + 'matomo.js';
|
||||
s.parentNode.insertBefore(g, s);
|
||||
}
|
||||
|
||||
window.addEventListener('cookieAccepted', trackVisit);
|
||||
if (localStorage.getItem('cookie_consent') === 'accepted') {
|
||||
trackVisit();
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,39 @@
|
||||
#cookie-banner {
|
||||
position: fixed;
|
||||
top: 2.5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: min(480px, calc(100vw - 2rem));
|
||||
background: #fff;
|
||||
border: 1px solid #e2e2e2;
|
||||
border-radius: 12px;
|
||||
padding: 1rem 1.25rem;
|
||||
box-shadow: 0 4px 24px rgba(0,0,0,.08);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
z-index: 9999;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
#cookie-banner.fade-out {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#cookie-banner p { margin: 0; font-size: 14px; flex: 1; }
|
||||
|
||||
#cookie-banner button {
|
||||
margin: 0.1rem 0;
|
||||
padding: .45rem 1rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ccc;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#cookie-accept {
|
||||
background: #0b913a; color: #fff; border-color: #1a1a1a;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
hugo_cookie_consent:
|
||||
privacy_policy_url:
|
||||
enable_matomo: false
|
||||
matomo_host:
|
||||
matomo_site_id:
|
||||
@@ -0,0 +1,18 @@
|
||||
site_wants_cookie:
|
||||
other: Diese Website möchte ein Cookie speichern.
|
||||
cookie_more_info:
|
||||
other: Mehr darüber.
|
||||
cookie_button_accept:
|
||||
other: Akzeptieren
|
||||
cookie_button_decline:
|
||||
other: Ablehnen
|
||||
cookie_status:
|
||||
other: Aktueller Status
|
||||
cookie_accepted:
|
||||
other: Akzeptiert
|
||||
cookie_declined:
|
||||
other: Abgelehnt
|
||||
cookie_none:
|
||||
other: Noch keine Entscheidung
|
||||
cookie_change:
|
||||
other: Cookie-Einstellungen ändern
|
||||
@@ -0,0 +1,18 @@
|
||||
site_wants_cookie:
|
||||
other: This site would like to store a cookie.
|
||||
cookie_more_info:
|
||||
other: More about this.
|
||||
cookie_button_accept:
|
||||
other: Accept
|
||||
cookie_button_decline:
|
||||
other: Decline
|
||||
cookie_status:
|
||||
other: Current status
|
||||
cookie_accepted:
|
||||
other: Accepted
|
||||
cookie_declined:
|
||||
other: Declined
|
||||
cookie_none:
|
||||
other: No decision yet
|
||||
cookie_change:
|
||||
other: Change cookie preferences
|
||||
@@ -0,0 +1,19 @@
|
||||
<div id="cookie-banner" style="display:none" role="dialog"
|
||||
aria-label="Cookie consent" aria-live="polite"
|
||||
data-matomo-url="{{ .Site.Params.hugo_cookie_consent.matomo_host }}"
|
||||
data-matomo-site-id="{{ .Site.Params.hugo_cookie_consent_matomo_site_id }}" >
|
||||
<p>
|
||||
{{ i18n "site_wants_cookie" }}
|
||||
<a href="{{ .Site.Params.hugo_cookie_consent.privacy_policy_url }}">
|
||||
{{ i18n "cookie_more_info" }}
|
||||
</a>
|
||||
</p>
|
||||
<div>
|
||||
<button id="cookie-accept">
|
||||
{{ i18n "cookie_button_accept" }}
|
||||
</button>
|
||||
<button id="cookie-decline">
|
||||
{{ i18n "cookie_button_decline" }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<p>
|
||||
{{ i18n "cookie_status" }}:
|
||||
<strong id="cookie_status"
|
||||
data-accepted="{{ i18n "cookie_accepted" }}"
|
||||
data-declined="{{ i18n "cookie_declined" }}"
|
||||
data-none="{{ i18n "cookie_none" }}">
|
||||
—
|
||||
</strong>
|
||||
</p>
|
||||
<button onclick="reopenCookieBanner()">
|
||||
{{ i18n "cookie_change" }}
|
||||
</button>
|
||||
Reference in New Issue
Block a user