catalog/ts_web/elements/consentsoftware-cookieconsent.ts

338 lines
9.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as shared from './shared.js';
import { LitElement, html, css, type TemplateResult } from 'lit';
import { customElement } from 'lit/decorators.js';
import { property } from 'lit/decorators/property.js';
import * as csInterfaces from '@consent.software/interfaces';
import * as csWebclient from '@consent.software/webclient';
import { delayFor } from '@push.rocks/smartdelay';
declare global {
interface HTMLElementTagNameMap {
'consentsoftware-cookieconsent': ConsentsoftwareCookieconsent;
}
}
@customElement('consentsoftware-cookieconsent')
export class ConsentsoftwareCookieconsent extends LitElement {
public static demo = () => html`<consentsoftware-cookieconsent></consentsoftware-cookieconsent>`;
public csWebclientInstance = new csWebclient.CsWebclient();
public csWebclientRan = false;
@property({ type: String, reflect: true })
public theme: 'light' | 'dark' = 'light';
/**
* We bind `heightPixels` to a CSS variable (--cookieconsent-height).
* Then we can do margin-bottom animations in CSS.
*/
public static styles = css`
:host {
font-family: ${shared.fontStack};
user-select: none;
/* Default theme variables */
--text-color: #333;
--background-color: #eeeeee;
--accent-color: #333333;
--button-bg: #ffffff;
--button-hover-bg: #f2f2f2;
--icon-color: #4496f5;
--link-color: #333;
--padding-sides: 16px;
}
:host([theme='dark']) {
--text-color: #fff;
--background-color: #111;
--accent-color: #333333;
--button-bg: #252525;
--button-hover-bg: #222222;
--icon-color: #4496f5;
--link-color: #fff;
}
:host([theme='light']) {
--text-color: #333;
--background-color: #eeeeee;
--accent-color: #333333;
--button-bg: #ffffff;
--button-hover-bg: #f2f2f2;
--icon-color: #4496f5;
--link-color: #333;
}
.pageOverlay {
position: fixed;
top: 0px;
bottom: 0px;
right: 0px;
left: 0px;
display: grid;
align-items: center;
justify-content: center;
z-index: 1000; /* standard z-index for fixed elements */
background: rgba(0, 0, 0, 0);
backdrop-filter: blur(0px);
transition: all 0.2s;
}
.modalBox {
display: block;
color: var(--text-color);
background: var(--background-color);
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.6);
position: realtive;
border: 1px dotted rgba(255, 255, 255, 0.1);
border-top: 1px solid var(--accent-color);
border-radius: 16px;
max-width: 1100px;
min-width: calc(100vw / 3);
box-sizing: border-box;
overflow: hidden;
/*
* We start with margin-bottom as negative to hide the banner.
* The animation occurs when we toggle the gotIt/show attributes.
*/
will-change: transform; /* ensure efficient rendering */
transition: all 0.3s;
transform: scale(0.95);
opacity: 0;
}
/*
* Toggle display based on [show] attribute
* (so if show=false, the banner doesn't show at all).
*/
:host([show='false']) {
display: none;
}
:host([show='true']) {
display: block;
}
/*
* Animate margin-bottom when [gotIt] toggles.
* If gotIt=true, push the banner down off-screen.
* If gotIt=false, pull the banner into view.
*/
:host([gotIt='true']) {
background: blue;
}
:host([gotIt='false']) {
background: red;
}
.content {
margin: auto;
}
.text-container {
padding-left: var(--padding-sides);
padding-right: var(--padding-sides);
display: grid;
grid-template-columns: auto;
}
.text-container a {
color: var(--link-color);
text-decoration: none;
}
.button-container {
padding: var(--padding-sides);
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.info-container {
color: var(--text-color);
text-align: center;
line-height: 3em;
background: rgba(0, 0, 0, 0.1);
border-top: 1px dotted rgba(255, 255, 255, 0.1);
font-size: 0.8em;
color: rgba(255, 255, 255, 0.5);
}
.info-container a {
text-decoration: underline;
color: var(--link-color);
transition: color 0.2s;
}
.info-container a:hover {
color: #ffffff;
}
.consent-button {
border-radius: 3px;
background: var(--button-bg);
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
padding: 10px;
line-height: 30px;
text-align: center;
cursor: pointer;
transition: all 0.2s;
}
.consent-button:hover {
background: var(--button-hover-bg);
}
`;
constructor() {
super();
this.setAttribute('gotIt', 'true');
this.setAttribute('show', 'false');
}
public render(): TemplateResult {
return html`
<div class="pageOverlay">
<div class="modalBox">
<div class="content">
<consentsoftware-header></consentsoftware-header>
<consentsoftware-tabs></consentsoftware-tabs>
<div class="text-container" style="padding: 16px;">
<div class="toptext">
This page uses cookies. Please review our
<a href="https://lossless.gmbh/cookie" target="_blank">cookie policy</a>
and choose which cookie level you are willing to accept.
</div>
</div>
<!-- <div class="button-container">
<div
class="consent-button"
@click=${(event: MouseEvent) => this.setLevel(event, ['functional'])}
>
Functional cookies
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) => this.setLevel(event, ['functional', 'analytics'])}
>
Analytics cookies
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.setLevel(event, ['functional', 'analytics', 'marketing'])}
>
Marketing cookies
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.setLevel(event, ['functional', 'analytics', 'marketing', 'all'])}
>
All cookies
</div>
</div> -->
<consentsoftware-mainselection></consentsoftware-mainselection>
<div class="button-container">
<div
class="consent-button"
@click=${(event: MouseEvent) => this.setLevel(event, ['functional'])}
>
Deny
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) => this.setLevel(event, ['functional', 'analytics'])}
>
Accept selection
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.setLevel(event, ['functional', 'analytics', 'marketing'])}
>
Accept all cookies
</div>
</div>
<div class="info-container">
consent management powered by
<a href="https://consent.software">consent.software</a>
</div>
</div>
</div>
</div>
`;
}
/**
* Called when the element is inserted into the DOM.
*/
public async connectedCallback() {
super.connectedCallback();
this.updateTheme();
const cookieLevel = await this.csWebclientInstance.getCookieLevels();
if (!cookieLevel) {
this.setAttribute('show', 'true');
this.setAttribute('gotIt', 'false');
requestAnimationFrame(async () => {
await this.updated();
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
if (pageOverlay) {
pageOverlay.style.background = 'rgba(0, 0, 0, 0.1)';
pageOverlay.style.backdropFilter = 'blur(2px)';
}
const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox');
if (modalBox) {
modalBox.style.transform = `scale(1)`;
modalBox.style.opacity = '1';
}
});
} else {
this.setAttribute('show', 'false');
this.setAttribute('gotIt', 'true');
}
}
/**
* Called after the first render of the component.
* We measure the actual height of the banner and update the CSS variable.
*/
public async firstUpdated() {}
/**
* Called whenever the element is updated or re-rendered.
*/
public async updated() {
console.log(`The height of the cookie banner is ${this.shadowRoot?.host?.clientHeight}px`);
const acceptedCookieLevels = await this.csWebclientInstance.getCookieLevels();
if (!this.csWebclientRan && acceptedCookieLevels) {
this.csWebclientRan = true;
await this.csWebclientInstance.getAndRunConsentTuples();
}
}
/**
* Sets the users chosen cookie level(s) and hides the banner.
*/
private async setLevel(event: MouseEvent, levelsArg: csInterfaces.TCookieLevel[]) {
console.log(`Set level to ${levelsArg}`);
await this.csWebclientInstance.setCookieLevels(levelsArg);
this.setAttribute('gotIt', 'true');
await delayFor(300);
this.setAttribute('show', 'false');
// After user selection, re-check for any required scripts to run
this.updated();
}
/**
* Dynamically switches the theme between light/dark,
* respecting `prefers-color-scheme` by default.
*/
private updateTheme() {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
this.theme = prefersDark ? 'dark' : 'light';
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
this.theme = e.matches ? 'dark' : 'light';
});
}
}