Skip to content

Commit

Permalink
Merge pull request #6 from tagconcierge/feature/bundle
Browse files Browse the repository at this point in the history
Feature/bundle
  • Loading branch information
michaloo authored Apr 20, 2024
2 parents aa1068d + e050de8 commit 148d4af
Show file tree
Hide file tree
Showing 8 changed files with 368 additions and 218 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.1.1

- introduced bundled version with CSS included

## 1.1.0

- prevent showing buttons if their text is empty
Expand Down
90 changes: 59 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
# Consent Banner JS

> <p align="center">A zero-dependency, lightweight (~1.9kB), consent platform agnostic, cookie banner for any website.</p>
> <p align="center">A zero-dependency, lightweight (~3kB), consent platform agnostic, cookie banner for any website.</p>
![Consent Banner as a bottom bar](assets/consent-banner-js-demo.gif "Consent Banner Demo")
![Consent Banner Demo](assets/consent-banner-js-demo.gif "Consent Banner Demo")

## How does it work?

1. It takes **JSON configuration** that controls display of the banner.
2. It fires **JS callback** when user interacts with the banner
3. It provides simple **JS object** with consent state

## Get started

Obviously, it's easy to get started.
## Get started

First include simple CSS for the banner in the `<head>` of the page:
First, include simple CSS for the banner in the `<head>` of the page:
```html
<link rel="stylesheet" href="https://public-assets.tagconcierge.com/cookies-banner-js/1.0.0/styles/light.css" />
<link rel="stylesheet" href="https://public-assets.tagconcierge.com/consent-banner/1.1.0/styles/light.css" />
```

Then in the footer you can include the actual JS:

```html
<script src="https://public-assets.tagconcierge.com/cookies-banner-js/1.0.0/consent-banner.min.js"></script>
<script src="https://public-assets.tagconcierge.com/consent-banner/1.1.0/cb.min.js"></script>
<script>
cookiesBannerJs(
loadConsentState,
Expand All @@ -26,18 +31,13 @@ Then in the footer you can include the actual JS:
</script>
```

In a nutshell you need to:

1. Load the styles CSS and `consent-banner.min.js` (obviously)
2. Call the global function called `cookiesBannerJs` with 3 parameters

**INFO:** You can call the `cookiesBannerJs` function whenever, wherever you want, inside it is wrapped with DOM Ready thingy.

To make that work you need to prepare **three** things:

1. A function to load the consent state from somewhere, for instance `localStorage` (see [examples](#examples))
2. A function to do something when the user provides their consent, for instance save it in `localStorage` (see [examples](#examples))
3. A config object that contains complete configuration for the whole thing (see [examples](#examples))
3. A config object that contains complete configuration for the banner content (see [examples](#examples))


## Config Object
Expand All @@ -50,31 +50,44 @@ To make that work you need to prepare **three** things:
wall: true // covers the page with opaque layer to prevent user interactions
},
consent_types: [{
name: 'ad_storage', // internal name of consent type, used for final JSON
name: 'ad_storage', // internal name of consent type, used for final JS object
title: 'Ad Storage', // user facing title for consent type
description: 'Cookies used for advertising purposes', // description visible in the settings view
default: 'denied', // what should be the default state when user decides to customize the settings
require: false // if set to true it won't be possible to save consent without this granted
}],
settings: {
title: '',
description: '',
modal: {
title: 'Learn how we protect your privacy', // title of the first view
description: 'Longer description with *simple markdown support*.',
buttons: {
save: '',
close: ''
settings: 'Settings',
close: 'Close',
reject: 'Reject',
accept: 'Accept all'
}
},
modal: {
title: '',
description: '',
}
settings: {
title: 'Customise your preferences',
description: 'Longer description with *simple markdown support*.',
buttons: {
accept: '',
settings: ''
reject: 'Reject',
close: 'Close',
save: 'Save',
accept: 'Accept all'
}
}
}
```

**Simple Markdown**

All `description` fields in config object support simplified Markdown-like syntax:

- [links](https://link)
- **bold** or __bold__
- *italic* or _italic_


## Styling

This banner comes with mininal set of CSS with all elements prefixed with `consent-banner-`.
Expand All @@ -91,18 +104,33 @@ Buttons can be styles using following CSS selectors:

## Examples

[Bottom bar without "wall"](./www/bar.html)
See following examples for complete setups:

- [Bottom bar without "wall"](https://tagconcierge.github.io/consent-banner-js/www/bar.html)
- [Central modal with "wall"](https://tagconcierge.github.io/consent-banner-js/www/modal.html)
- [Single JS Bundle](https://tagconcierge.github.io/consent-banner-js/www/bundle.html)
- [Google Consent Mode](https://tagconcierge.github.io/consent-banner-js/www/gtm.html)


## Integrations

Instead of doing direct installation in HTML you can use one of the following integrations:

**Google Tag Manager**

Use this [Google Tag Manager Template](https://github.com/tagconcierge/tagconcierge-gtm-cookies-template) to quickly configure and deploy the Consent Banner on any GTM enabled website. It obviously integrates with Google Consent Mode.

[Central modal with "wall"](./www/modal.html)
**WordPress**

[Some snippets for Google Tag thing](./www/gtm.html)
Simple [WordPress plugin](https://github.com/tagconcierge/tc-wordpress-gtm-consent-mode-banner-free) that provides UI for configuration, injects required files and integrates with Google Consent Mode.

**PrestaShop**

## Installation
Simple [PrestaShop plugin](https://github.com/tagconcierge/tc-prestashop-gtm-consent-mode-banner-free) that provides UI for configuration, injects required files and integrates with Google Consent Mode.

Just include the JS and optionally CSS in the page html.
**Cloudflare Worker**

There is a cool way to do it with Workers@Edge for instance CloudFlare Workers though. Check out this [example](./www/worker.js) to see how to quickly inject on any page without touching the source code.
[Example CF Worker code](./www/cf-worker-bundle.js) to inject Consent Banner and the configuration without touching HTML code.


## Development
Expand Down
14 changes: 14 additions & 0 deletions bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const fs = require('node:fs');

const css = fs.readFileSync(`./styles/light.css`).toString().replace(/(?:\r\n|\r|\n)/g, '');
const app = fs.readFileSync(`./src/app.js`);

const bundle = `
var style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode('${css}'));
document.head.appendChild(style);
${app}
`;

fs.writeFileSync('./dist/bundle.js', bundle);
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "cookies-banner-js",
"version": "1.1.0",
"name": "consent-banner-js",
"version": "1.1.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"serve": "esbuild src/app.js --outdir=www/js --bundle --servedir=www --target=es6",
"build": "rimraf dist; esbuild src/app.js --outfile=dist/consent-banner-js/$npm_package_version/consent-banner.min.js --bundle --target=es6 --minify; cpr styles/ dist/consent-banner-js/$npm_package_version/styles;"
"build": "rimraf dist; esbuild src/app.js --outfile=dist/consent-banner-js/$npm_package_version/consent-banner.min.js --bundle --target=es6 --minify; cpr styles/ dist/consent-banner-js/$npm_package_version/styles; node bundle.js; esbuild dist/bundle.js --outfile=dist/consent-banner-js/$npm_package_version/consent-banner.bundle.min.js --bundle --target=es6 --minify"
},
"author": "",
"license": "MIT",
Expand Down
82 changes: 82 additions & 0 deletions www/cf-worker-bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});

class BodyHandler {
element(element) {
element.append(`
<script src="https://public-assets.tagconcierge.com/consent-banner/1.1.0/cb.bundle.min.js"></script>
<script>
var config = {
display: {
mode: "bar"
},
consent_types: [{
name: 'analytics_storage',
title: "Analytics storage",
description: 'These cookies help us understand how visitors interact with our website. Measure and analyze traffic to improve our service.',
default: 'denied'
}, {
name: "ad_storage",
title: "Ads storage",
description: "These cookies help us run ads conversion tracking.",
default: 'denied'
}, {
name: 'ad_user_data',
title: "User Data",
description: 'These cookies helps us optimise advertising campaigns by sharing some of the user data with 3rd party services',
default: 'denied'
}, {
name: 'ad_personalization',
title: "Personalization",
description: 'These cookies allows us to personalise ads',
default: 'denied'
}],
settings: {
title: "Cookies Settings",
description: "We use cookies to improve user experience. Choose what cookie categories you allow us to use. You can read more about our [Privacy Policy](/privacy-policy)",
buttons: {
save: "Save preferences",
close: "Close"
}
},
modal: {
title: 'Cookies',
description: 'We are using various cookies files. Learn more in our [privacy policy](/privacy-policy) and make your choice.',
buttons: {
accept: 'Accept',
settings: 'Settings'
}
}
};
cookiesBannerJs(
function() {
try {
return JSON.parse(localStorage.getItem('consent_preferences'));
} catch (error) {
return null;
}
},
function(consentState) {
gtag('consent', 'update', consentState);
localStorage.setItem('consent_preferences', JSON.stringify(consentState));
},
config
);
</script>`, { html: true });
}
}

async function handleRequest(request) {

const url = new URL(request.url)
const res = await fetch(request)

return new HTMLRewriter()
.on("body", new BodyHandler())
.transform(res)
}
113 changes: 113 additions & 0 deletions www/cf-worker-consent-mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* Example of Cloud Flare worker injecting Consent Banner
* with Google Consent Mode compatible code
*/
addEventListener("fetch", (event) => {
event.respondWith(
handleRequest(event.request).catch(
(err) => new Response(err.stack, { status: 500 })
)
);
});

class HeadHandler {
element(element) {
element.prepend(`
<link rel="stylesheet" href="https://public-assets.tagconcierge.com/cookies-banner-js/1.1.0/styles/light.css" />
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Set default consent to 'denied' as a placeholder
// Determine actual values based on your own requirements
gtag('consent', 'default', {
'ad_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'analytics_storage': 'denied'
});
try {
var consentPreferences = JSON.parse(localStorage.getItem('consent_preferences'));
if (consentPreferences !== null) {
gtag('consent', 'update', consentPreferences);
}
} catch (error) {}
</script>`, { html: true });
}
}


class BodyHandler {
element(element) {
element.append(`
<script src="https://public-assets.tagconcierge.com/cookies-banner-js/1.1.0/consent-banner.min.js"></script>
<script>
var config = {
display: {
mode: "bar"
},
consent_types: [{
name: 'analytics_storage',
title: "Analytics storage",
description: 'These cookies help us understand how visitors interact with our website. Measure and analyze traffic to improve our service.',
default: 'denied'
}, {
name: "ad_storage",
title: "Ads storage",
description: "These cookies help us run ads conversion tracking.",
default: 'denied'
}, {
name: 'ad_user_data',
title: "User Data",
description: 'These cookies helps us optimise advertising campaigns by sharing some of the user data with 3rd party services',
default: 'denied'
}, {
name: 'ad_personalization',
title: "Personalization",
description: 'These cookies allows us to personalise ads',
default: 'denied'
}],
settings: {
title: "Cookies Settings",
description: "We use cookies to improve user experience. Choose what cookie categories you allow us to use. You can read more about our [Privacy Policy](/privacy-policy)",
buttons: {
save: "Save preferences",
close: "Close"
}
},
modal: {
title: 'Cookies',
description: 'We are using various cookies files. Learn more in our [privacy policy](/privacy-policy) and make your choice.',
buttons: {
accept: 'Accept',
settings: 'Settings'
}
}
};
cookiesBannerJs(
function() {
try {
return JSON.parse(localStorage.getItem('consent_preferences'));
} catch (error) {
return null;
}
},
function(consentState) {
gtag('consent', 'update', consentState);
localStorage.setItem('consent_preferences', JSON.stringify(consentState));
},
config
);
</script>`, { html: true });
}
}

async function handleRequest(request) {

const url = new URL(request.url)
const res = await fetch(request)

return new HTMLRewriter()
.on("head", new HeadHandler())
.on("body", new BodyHandler())
.transform(res)
}
Loading

0 comments on commit 148d4af

Please sign in to comment.