catalog/ts_web/elements/consentsoftware-cookieconsent.ts

336 lines
10 KiB
TypeScript
Raw Permalink 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(255, 255, 255, 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;
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;
}
.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('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.handleConsentButtonClick(event, ['functional'])}
>
Functional cookies
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.handleConsentButtonClick(event, ['functional', 'analytics'])}
>
Analytics cookies
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.handleConsentButtonClick(event, ['functional', 'analytics', 'marketing'])}
>
Marketing cookies
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.handleConsentButtonClick(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.handleConsentButtonClick(event, ['functional'])}
>
Deny
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.handleConsentButtonClick(event, ['functional', 'analytics'])}
>
Accept selection
</div>
<div
class="consent-button"
@click=${(event: MouseEvent) =>
this.handleConsentButtonClick(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>
(Open Source)
</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');
requestAnimationFrame(async () => {
await this.updated();
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
if (pageOverlay) {
pageOverlay.style.background = 'rgba(255,255,255, 0.1)';
pageOverlay.style.backdropFilter = 'blur(1px)';
}
const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox');
if (modalBox) {
modalBox.style.transform = `scale(1)`;
modalBox.style.opacity = '1';
}
});
} else {
this.setAttribute('show', 'false');
}
}
/**
* 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 handleConsentButtonClick(
event: MouseEvent,
levelsArg: csInterfaces.TCookieLevel[]
) {
console.log(`Set level to ${levelsArg}`);
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
if (pageOverlay) {
pageOverlay.style.background = 'rgba(255,255,255, 0)';
pageOverlay.style.backdropFilter = 'blur(0px)';
}
const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox');
if (modalBox) {
modalBox.style.transform = `scale(0.95)`;
modalBox.style.opacity = '0';
}
await this.csWebclientInstance.setCookieLevels(levelsArg);
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';
});
}
}