Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 777acd06a5 | |||
| 0d90a7ae7f | |||
| 0b366b360d | |||
| 8a26378689 | |||
| 1e74560aca | |||
| 2184d8be18 | |||
| 46602851aa | |||
| fc2ba54725 | |||
| a9ae67b43b |
34
changelog.md
34
changelog.md
@@ -1,5 +1,39 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-11-30 - 2.0.0 - BREAKING CHANGE(elements)
|
||||||
|
Migrate web components to @design.estate/dees-element, introduce shared theme colors and cssManager, and update imports/usages across ts_web.
|
||||||
|
|
||||||
|
- Replaced direct lit usage with @design.estate/dees-element across the project (imports and base classes).
|
||||||
|
- Added cssManager export and a Shadcn-inspired color palette (colors) in ts_web/elements/shared.ts to centralize theming.
|
||||||
|
- Updated all components to extend DeesElement and include cssManager.defaultStyles in their static styles.
|
||||||
|
- Adjusted lifecycle and event typings (firstUpdated signatures, pointer/mouse event typing) and minor behaviour refinements in consentsoftware-toggle (drag handling, sync logic).
|
||||||
|
- Updated package.json dependencies to remove 'lit' and add '@design.estate/dees-element'.
|
||||||
|
- Updated page imports (ts_web/pages/page1.ts) to use the new html export from @design.estate/dees-element.
|
||||||
|
|
||||||
|
## 2025-11-30 - 1.6.1 - fix(build)
|
||||||
|
Update TypeScript config and build tooling; use accessor for Lit properties; bump deps and adjust package metadata
|
||||||
|
|
||||||
|
- ts_web/tsconfig.json: target -> ES2022, module -> ES2022, moduleResolution -> bundler, lib updated to ES2022/DOM/DOM.Iterable
|
||||||
|
- tsconfig.json (root): target -> ES2022, module -> NodeNext, moduleResolution -> NodeNext
|
||||||
|
- Component properties migrated to use the TypeScript 'accessor' modifier (consentsoftware-cookieconsent, consentsoftware-mainselection, consentsoftware-toggle)
|
||||||
|
- Bumped runtime and dev dependencies: lit -> ^3.3.1; upgrades to @design.estate/dees-wcctools, @git.zone/tsbuild, @git.zone/tsbundle, @git.zone/tswatch
|
||||||
|
- Package metadata: author updated to Task Venture Capital GmbH and test script changed to use pnpm
|
||||||
|
|
||||||
|
## 2025-01-22 - 1.6.0 - feat(elements)
|
||||||
|
Enhance theme handling and CSS organization for consent component
|
||||||
|
|
||||||
|
- Introduced theme-specific CSS variables for better theming support in consentsoftware-cookieconsent.
|
||||||
|
- Reorganized styles in consentsoftware-cookieconsent for cleaner look and consistency.
|
||||||
|
- Added media queries for responsive design in consentsoftware-tabs.
|
||||||
|
|
||||||
|
## 2025-01-21 - 1.5.4 - fix(consentsoftware-components)
|
||||||
|
Add interactive consent software components for managing cookie levels.
|
||||||
|
|
||||||
|
- Implemented 'consentsoftware-cookieconsent' component for cookie management
|
||||||
|
- Introduced 'consentsoftware-toggle' for user interaction improvements
|
||||||
|
- Added theme support for light/dark modes in consent components
|
||||||
|
- Enhanced consent interface with responsive design and accessibility features
|
||||||
|
|
||||||
## 2025-01-20 - 1.5.3 - fix(consentsoftware-cookieconsent)
|
## 2025-01-20 - 1.5.3 - fix(consentsoftware-cookieconsent)
|
||||||
Fix visual inconsistencies in the consent software modal overlay and shadow.
|
Fix visual inconsistencies in the consent software modal overlay and shadow.
|
||||||
|
|
||||||
|
|||||||
18
package.json
18
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@consent.software/catalog",
|
"name": "@consent.software/catalog",
|
||||||
"version": "1.5.3",
|
"version": "2.0.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A library of web components designed to integrate robust consent management capabilities into web applications, ensuring compliance with privacy regulations.",
|
"description": "A library of web components designed to integrate robust consent management capabilities into web applications, ensuring compliance with privacy regulations.",
|
||||||
"exports": {
|
"exports": {
|
||||||
@@ -8,23 +8,23 @@
|
|||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run build",
|
"test": "pnpm run build",
|
||||||
"build": "tsbuild tsfolders --allowimplicitany && tsbundle element --production",
|
"build": "tsbuild tsfolders --allowimplicitany && tsbundle element --production",
|
||||||
"watch": "tswatch element"
|
"watch": "tswatch element"
|
||||||
},
|
},
|
||||||
"author": "Lossless GmbH",
|
"author": "Task Venture Capital GmbH",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@consent.software/interfaces": "^1.0.14",
|
"@consent.software/interfaces": "^1.0.14",
|
||||||
"@consent.software/webclient": "^1.1.0",
|
"@consent.software/webclient": "^1.1.0",
|
||||||
"@push.rocks/smartdelay": "^3.0.5",
|
"@design.estate/dees-element": "^2.1.3",
|
||||||
"lit": "^3.2.1"
|
"@push.rocks/smartdelay": "^3.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@design.estate/dees-wcctools": "^1.0.90",
|
"@design.estate/dees-wcctools": "^1.2.1",
|
||||||
"@git.zone/tsbuild": "^2.2.0",
|
"@git.zone/tsbuild": "^3.1.2",
|
||||||
"@git.zone/tsbundle": "^2.1.0",
|
"@git.zone/tsbundle": "^2.6.2",
|
||||||
"@git.zone/tswatch": "^2.0.37",
|
"@git.zone/tswatch": "^2.2.1",
|
||||||
"@push.rocks/projectinfo": "^5.0.2"
|
"@push.rocks/projectinfo": "^5.0.2"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
2180
pnpm-lock.yaml
generated
2180
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
251
readme.md
251
readme.md
@@ -1,138 +1,207 @@
|
|||||||
# @consent.software_private/catalog
|
# @consent.software/catalog
|
||||||
|
|
||||||
Webcomponents for consent.software widget.
|
A sleek, modern library of web components for seamless consent management integration. Built with Lit and designed for GDPR/CCPA compliance out of the box.
|
||||||
|
|
||||||
## Install
|
## Issue Reporting and Security
|
||||||
|
|
||||||
To install this module, you need to have [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/) installed on your machine. You can then run the following command in your terminal to add the module to your project:
|
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||||
|
|
||||||
```shell
|
## Features
|
||||||
npm install @consent.software_private/catalog
|
|
||||||
|
🍪 **Cookie Consent Modal** - Beautiful, responsive consent dialog with light/dark theme support
|
||||||
|
🎛️ **Interactive Toggles** - Draggable toggle switches with smooth animations
|
||||||
|
📱 **Mobile-First Design** - Fully responsive across all device sizes
|
||||||
|
🎨 **Theme-Aware** - Automatically detects system light/dark mode preference
|
||||||
|
🔒 **Privacy-First** - Integrates with consent.software backend for compliant consent tracking
|
||||||
|
⚡ **Zero Config** - Drop-in components that just work
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @consent.software/catalog
|
||||||
|
# or
|
||||||
|
pnpm add @consent.software/catalog
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensure you have ESM support enabled in your TypeScript configuration, as this package uses ES module syntax.
|
## Quick Start
|
||||||
|
|
||||||
## Usage
|
Import the components and add the consent banner to your page:
|
||||||
|
|
||||||
The `@consent.software_private/catalog` module offers a set of web components to integrate consent management capabilities into your web application. These components leverage modern browser APIs and employ a system for cookie management that aligns with regulatory requirements.
|
|
||||||
|
|
||||||
### Initial Setup
|
|
||||||
|
|
||||||
First, import the necessary modules and set up your project to use the web components provided:
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import '@consent.software_private/catalog';
|
import '@consent.software/catalog';
|
||||||
|
|
||||||
|
// That's it! Add the component to your HTML
|
||||||
```
|
```
|
||||||
|
|
||||||
Ensure this import statement is included in your main JavaScript/TypeScript file where you want to utilize the consent management web components. It is vital to transpile with TypeScript compiler settings that support ES modules.
|
```html
|
||||||
|
<consentsoftware-cookieconsent></consentsoftware-cookieconsent>
|
||||||
### Building a Consent Modal
|
|
||||||
|
|
||||||
A primary feature of this module is the `consentsoftware-cookieconsent` component. This component can be embedded into your application to allow users to select their preferred cookie levels.
|
|
||||||
|
|
||||||
#### Setting Up the Environment
|
|
||||||
|
|
||||||
Before creating instances of the components, make sure your project environment is ready. Setup the DOM tools and any associated dependencies:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { domtools } from '@design.estate/dees-domtools';
|
|
||||||
|
|
||||||
domtools.elementBasic.setup();
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using the Consentsoftware-Cookieconsent Component
|
The consent banner automatically:
|
||||||
|
- Shows on first visit when no consent preferences are stored
|
||||||
|
- Hides after user makes a selection
|
||||||
|
- Respects system dark/light mode
|
||||||
|
- Stores preferences via the consent.software backend
|
||||||
|
|
||||||
Here's how you can include the `consentsoftware-cookieconsent` component in your application:
|
## Components
|
||||||
|
|
||||||
```typescript
|
### `<consentsoftware-cookieconsent>`
|
||||||
import { html, render } from 'lit-html';
|
|
||||||
|
|
||||||
const template = html`
|
The main consent modal component. Provides a full-screen overlay with cookie preference options.
|
||||||
<consentsoftware-cookieconsent></consentsoftware-cookieconsent>
|
|
||||||
`;
|
|
||||||
|
|
||||||
render(template, document.body);
|
```html
|
||||||
|
<consentsoftware-cookieconsent></consentsoftware-cookieconsent>
|
||||||
```
|
```
|
||||||
|
|
||||||
This will add the consent banner to the bottom of the page, providing users options to set their preferences.
|
**Features:**
|
||||||
|
- Three-button interface: Deny, Accept Selection, Accept All
|
||||||
|
- Four cookie categories: Required, Preferences, Statistics, Marketing
|
||||||
|
- Animated modal with backdrop blur
|
||||||
|
- Shake feedback when clicking outside the modal
|
||||||
|
- Automatic theme detection (light/dark)
|
||||||
|
|
||||||
#### Customizing the Component
|
### `<consentsoftware-toggle>`
|
||||||
|
|
||||||
The `consentsoftware-cookieconsent` component allows you to customize its design via CSS properties. Leverage light and dark themes through the CSS manager used in styling attributes:
|
A draggable toggle switch component with touch support.
|
||||||
|
|
||||||
```typescript
|
```html
|
||||||
const styles = `
|
<consentsoftware-toggle>Label Text</consentsoftware-toggle>
|
||||||
:host {
|
<consentsoftware-toggle required>Required</consentsoftware-toggle>
|
||||||
--cookieconsent-height: 70px;
|
|
||||||
--cookieconsent-background: #222;
|
|
||||||
--cookieconsent-text-color: #fff;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Apply these custom styles to modify the appearance to match your site's design language.
|
**Properties:**
|
||||||
|
- `required` (boolean) - When true, toggle is locked in the "on" position
|
||||||
|
- `selected` (boolean) - Current toggle state
|
||||||
|
|
||||||
#### Handling User Interactions
|
**Events:**
|
||||||
|
- `toggle` - Fired when state changes, includes `{ selected: boolean }` in detail
|
||||||
|
|
||||||
The component is interactive, responding to user actions to set cookie levels. Here’s how the interaction flow works:
|
### `<consentsoftware-tabs>`
|
||||||
|
|
||||||
1. **User Interaction**: Users click one of the consent buttons (e.g., "Functional Cookies").
|
Tab navigation component with animated indicator.
|
||||||
2. **Handling Consent Levels**: The component's `setLevel` method is invoked, updating the user's cookie preferences, e.g.:
|
|
||||||
|
```html
|
||||||
|
<consentsoftware-tabs></consentsoftware-tabs>
|
||||||
|
```
|
||||||
|
|
||||||
|
Displays three tabs: Consent, Details, and Cookie Policy.
|
||||||
|
|
||||||
|
### `<consentsoftware-header>`
|
||||||
|
|
||||||
|
Simple header component for the consent modal.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<consentsoftware-header></consentsoftware-header>
|
||||||
|
```
|
||||||
|
|
||||||
|
### `<consentsoftware-mainselection>`
|
||||||
|
|
||||||
|
Grid layout containing toggle switches for each cookie category.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<consentsoftware-mainselection></consentsoftware-mainselection>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backend Integration
|
||||||
|
|
||||||
|
This catalog integrates with the `@consent.software/webclient` package for backend communication:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
private async setLevel(event: MouseEvent, levelsArg: Array<TCookieLevel>) {
|
import { CsWebclient } from '@consent.software/webclient';
|
||||||
await this.csWebclientInstance.setCookieLevels(levelsArg);
|
|
||||||
// Adjust styling and visibility
|
const client = new CsWebclient();
|
||||||
this.setAttribute('gotIt', 'true');
|
|
||||||
await delayFor(300);
|
// Check current consent levels
|
||||||
this.setAttribute('show', 'false');
|
const levels = await client.getCookieLevels();
|
||||||
// Update other business logic based on consent levels
|
if (!levels) {
|
||||||
|
// Show consent dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set consent levels programmatically
|
||||||
|
await client.setCookieLevels(['functional', 'analytics']);
|
||||||
|
|
||||||
|
// Run consent-dependent scripts
|
||||||
|
await client.getAndRunConsentTuples();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Styling & Theming
|
||||||
|
|
||||||
|
The components use CSS custom properties for easy theming:
|
||||||
|
|
||||||
|
```css
|
||||||
|
consentsoftware-cookieconsent {
|
||||||
|
/* Text and colors */
|
||||||
|
--text-color: #333;
|
||||||
|
--background-color: #eeeeee;
|
||||||
|
--accent-color: #333333;
|
||||||
|
|
||||||
|
/* Buttons */
|
||||||
|
--button-bg: #ffffff;
|
||||||
|
--button-hover-bg: #f2f2f2;
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
--link-color: #333;
|
||||||
|
--icon-color: #4496f5;
|
||||||
|
|
||||||
|
/* Modal */
|
||||||
|
--modal-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
--info-bg: rgba(0, 0, 0, 0.1);
|
||||||
|
--info-text: rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The system remembers user choices using a backend managed by the `consent.software` infrastructure.
|
The component automatically switches to dark theme variables when `theme="dark"` is set or when the system prefers dark mode.
|
||||||
|
|
||||||
### Integrating with Your Backend
|
## Cookie Levels
|
||||||
|
|
||||||
For full functionality, the component interacts with a backend to manage user consent states. Using `@consent.software/webclient`, you can query the user's current consent levels, perform updates, and verify whether consent has been previously granted:
|
The consent system uses three user-selectable levels plus a required baseline:
|
||||||
|
|
||||||
```typescript
|
| Level | Description |
|
||||||
const webclientInstance = new CsWebclient();
|
|-------|-------------|
|
||||||
const cookieLevels = await webclientInstance.getCookieLevels();
|
| `functional` | Required cookies for site operation (always enabled) |
|
||||||
|
| `preferences` | User preference cookies |
|
||||||
|
| `analytics` | Statistics and analytics tracking |
|
||||||
|
| `marketing` | Marketing and advertising cookies |
|
||||||
|
|
||||||
if (!cookieLevels) {
|
## Browser Support
|
||||||
// Show consent dialog if no consent levels are set
|
|
||||||
document.querySelector('consentsoftware-cookieconsent').show = true;
|
- Chrome (last 2 versions)
|
||||||
} else {
|
- Firefox (last 2 versions)
|
||||||
// Apply the consent settings to your analytics, advertisements, etc.
|
- Safari (last 2 versions)
|
||||||
applyConsentSettings(cookieLevels);
|
- Edge (last 2 versions)
|
||||||
}
|
|
||||||
|
Built with modern ES modules and requires browsers with native Custom Elements v1 support.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
pnpm install
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
pnpm run build
|
||||||
|
|
||||||
|
# Watch mode for development
|
||||||
|
pnpm run watch
|
||||||
```
|
```
|
||||||
|
|
||||||
### Advanced Considerations
|
## License and Legal Information
|
||||||
|
|
||||||
#### Responsive Design
|
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
||||||
|
|
||||||
The component is responsive, optimized for various screen sizes using a grid layout. Ensure your main HTML elements are responsive to accommodate the consent bar.
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
#### Accessibility and Compliance
|
### Trademarks
|
||||||
|
|
||||||
Ensure your application properly adheres to legal and accessibility standards by aligning with the consent management system's features. This often involves using correct semantics, polyfills for custom elements, and thorough testing on different devices and browsers.
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
||||||
|
|
||||||
#### Managing State Across Sessions
|
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
||||||
|
|
||||||
Store user's consent preferences beyond the session using either localStorage, cookies, or server-side sessions. Adjust the component’s connectedCallback and updated lifecycle methods to fetch and apply these stored settings.
|
### Company Information
|
||||||
|
|
||||||
Proper handling ensures a seamless user experience, helping companies comply with international privacy laws like GDPR.
|
Task Venture Capital GmbH
|
||||||
|
Registered at District Court Bremen HRB 35230 HB, Germany
|
||||||
|
|
||||||
### Integration and Testing
|
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
||||||
|
|
||||||
Test extensively in your development environment, ensure correct rendering, and simulate various user interactions to gain confidence in production-level functionality. Automated testing might include:
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||||
|
|
||||||
- Unit tests for lifecycle behavior using testing libraries such as Mocha or Jest.
|
|
||||||
- Integration trials ensuring the component plays well with surrounding UI elements.
|
|
||||||
|
|
||||||
### Conclusion
|
|
||||||
|
|
||||||
With these guidelines, developers can integrate, customize, and extend the consent management capabilities within their applications using `@consent.software_private/catalog`. Adapt the styling, maximize UX, and ensure regulatory compliance for a robust implementation. Mastery of the component enables seamless user consent handling and enhances your app's governance credentials.
|
|
||||||
undefined
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@consent.software/catalog',
|
name: '@consent.software/catalog',
|
||||||
version: '1.5.3',
|
version: '2.0.0',
|
||||||
description: 'A library of web components designed to integrate robust consent management capabilities into web applications, ensuring compliance with privacy regulations.'
|
description: 'A library of web components designed to integrate robust consent management capabilities into web applications, ensuring compliance with privacy regulations.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import * as shared from './shared.js';
|
import { cssManager, colors } from './shared.js';
|
||||||
|
|
||||||
import { LitElement, html, css, type TemplateResult } from 'lit';
|
import {
|
||||||
import { customElement } from 'lit/decorators.js';
|
DeesElement,
|
||||||
import { property } from 'lit/decorators/property.js';
|
customElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import * as csInterfaces from '@consent.software/interfaces';
|
import * as csInterfaces from '@consent.software/interfaces';
|
||||||
import * as csWebclient from '@consent.software/webclient';
|
import * as csWebclient from '@consent.software/webclient';
|
||||||
@@ -15,179 +20,162 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@customElement('consentsoftware-cookieconsent')
|
@customElement('consentsoftware-cookieconsent')
|
||||||
export class ConsentsoftwareCookieconsent extends LitElement {
|
export class ConsentsoftwareCookieconsent extends DeesElement {
|
||||||
public static demo = () => html`<consentsoftware-cookieconsent></consentsoftware-cookieconsent>`;
|
public static demo = () => html`<consentsoftware-cookieconsent></consentsoftware-cookieconsent>`;
|
||||||
|
|
||||||
public csWebclientInstance = new csWebclient.CsWebclient();
|
public csWebclientInstance = new csWebclient.CsWebclient();
|
||||||
public csWebclientRan = false;
|
public csWebclientRan = false;
|
||||||
|
|
||||||
@property({ type: String, reflect: true })
|
public static styles = [
|
||||||
public theme: 'light' | 'dark' = 'light';
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
/**
|
|
||||||
* We bind `heightPixels` to a CSS variable (--cookieconsent-height).
|
|
||||||
* Then we can do margin-bottom animations in CSS.
|
|
||||||
*/
|
|
||||||
public static styles = css`
|
|
||||||
:host {
|
:host {
|
||||||
font-family: ${shared.fontStack};
|
font-size: 14px;
|
||||||
user-select: none;
|
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 {
|
.pageOverlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0px;
|
inset: 0;
|
||||||
bottom: 0px;
|
|
||||||
right: 0px;
|
|
||||||
left: 0px;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 1000; /* standard z-index for fixed elements */
|
z-index: 1000;
|
||||||
background: rgba(255, 255, 255, 0);
|
background: rgba(0, 0, 0, 0);
|
||||||
backdrop-filter: blur(0px);
|
backdrop-filter: blur(0px);
|
||||||
transition: all 0.2s;
|
transition: all 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pageOverlay.shake {
|
.pageOverlay.shake {
|
||||||
background: rgba(0, 0, 0, 0.5) !important;
|
background: rgba(0, 0, 0, 0.6) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modalBox {
|
.modalBox {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--text-color);
|
color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)};
|
||||||
background: var(--background-color);
|
background: ${cssManager.bdTheme(colors.light.background, colors.dark.background)};
|
||||||
box-shadow: 0px 0px 8px rgba(255, 255, 255, 0.6);
|
box-shadow:
|
||||||
position: realtive;
|
0 0 0 1px ${cssManager.bdTheme(colors.light.border, colors.dark.border)},
|
||||||
border: 1px dotted rgba(255, 255, 255, 0.1);
|
0 16px 70px ${cssManager.bdTheme('rgba(0, 0, 0, 0.15)', 'rgba(0, 0, 0, 0.35)')};
|
||||||
border-top: 1px solid var(--accent-color);
|
position: relative;
|
||||||
border-radius: 16px;
|
border-radius: 8px;
|
||||||
max-width: 1100px;
|
max-width: 520px;
|
||||||
min-width: calc(100vw / 3);
|
min-width: 320px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
will-change: transform; /* ensure efficient rendering */
|
will-change: transform;
|
||||||
transition: all 0.3s;
|
transition: all 0.2s ease-out;
|
||||||
transform: scale(0.95);
|
transform: scale(0.96);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.modalBox {
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.modalBox.shake {
|
.modalBox.shake {
|
||||||
animation: shake 150ms 2 linear;
|
animation: shake 120ms 2 linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes shake {
|
@keyframes shake {
|
||||||
0% {
|
0% { transform: translateX(3px); }
|
||||||
transform: translate(3px, 0);
|
50% { transform: translateX(-3px); }
|
||||||
}
|
100% { transform: translateX(0); }
|
||||||
50% {
|
|
||||||
transform: translate(-3px, 0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translate(0, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
:host([show='false']) { display: none; }
|
||||||
* Toggle display based on [show] attribute
|
:host([show='true']) { display: block; }
|
||||||
* (so if show=false, the banner doesn't show at all).
|
|
||||||
*/
|
|
||||||
:host([show='false']) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
:host([show='true']) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-container {
|
.text-container {
|
||||||
padding-left: var(--padding-sides);
|
padding: 12px 16px;
|
||||||
padding-right: var(--padding-sides);
|
font-size: 0.9em;
|
||||||
display: grid;
|
line-height: 1.5;
|
||||||
grid-template-columns: auto;
|
color: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)};
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-container a {
|
.text-container a {
|
||||||
color: var(--link-color);
|
color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)};
|
||||||
text-decoration: none;
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-container a:hover {
|
||||||
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container {
|
.button-container {
|
||||||
padding: var(--padding-sides);
|
padding: 12px 16px 16px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
gap: 16px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-container {
|
@media (max-width: 560px) {
|
||||||
color: var(--text-color);
|
.button-container {
|
||||||
text-align: center;
|
grid-template-columns: 1fr;
|
||||||
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 {
|
.consent-button {
|
||||||
border-radius: 3px;
|
border-radius: 6px;
|
||||||
background: var(--button-bg);
|
background: ${cssManager.bdTheme(colors.light.secondary, colors.dark.secondary)};
|
||||||
box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
|
border: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)};
|
||||||
padding: 10px;
|
padding: 8px 16px;
|
||||||
line-height: 30px;
|
font-size: 0.85em;
|
||||||
|
font-weight: 500;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.15s ease;
|
||||||
|
color: ${cssManager.bdTheme(colors.light.secondaryForeground, colors.dark.secondaryForeground)};
|
||||||
}
|
}
|
||||||
|
|
||||||
.consent-button:hover {
|
.consent-button:hover {
|
||||||
background: var(--button-hover-bg);
|
background: ${cssManager.bdTheme(colors.light.accent, colors.dark.accent)};
|
||||||
|
border-color: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)};
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
.consent-button:last-child {
|
||||||
|
background: ${cssManager.bdTheme(colors.light.primary, colors.dark.primary)};
|
||||||
|
color: ${cssManager.bdTheme(colors.light.primaryForeground, colors.dark.primaryForeground)};
|
||||||
|
border-color: ${cssManager.bdTheme(colors.light.primary, colors.dark.primary)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.consent-button:last-child:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-container {
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: ${cssManager.bdTheme(colors.light.muted, colors.dark.muted)};
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)};
|
||||||
|
font-size: 0.75em;
|
||||||
|
color: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-container a {
|
||||||
|
color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)};
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-container a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
// Initially hide the consent banner until needed
|
||||||
this.setAttribute('show', 'false');
|
this.setAttribute('show', 'false');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,43 +186,13 @@ export class ConsentsoftwareCookieconsent extends LitElement {
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<consentsoftware-header></consentsoftware-header>
|
<consentsoftware-header></consentsoftware-header>
|
||||||
<consentsoftware-tabs></consentsoftware-tabs>
|
<consentsoftware-tabs></consentsoftware-tabs>
|
||||||
<div class="text-container" style="padding: 16px;">
|
<div class="text-container">
|
||||||
<div class="toptext">
|
<div class="toptext">
|
||||||
This page uses cookies. Please review our
|
We use cookies to enhance your experience. Review our
|
||||||
<a href="https://lossless.gmbh/cookie" target="_blank">cookie policy</a>
|
<a href="https://lossless.gmbh/cookie" target="_blank">cookie policy</a>
|
||||||
and choose which cookie level you are willing to accept.
|
and select your preferences.
|
||||||
</div>
|
</div>
|
||||||
</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>
|
<consentsoftware-mainselection></consentsoftware-mainselection>
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<div
|
<div
|
||||||
@@ -262,7 +220,6 @@ export class ConsentsoftwareCookieconsent extends LitElement {
|
|||||||
<div class="info-container">
|
<div class="info-container">
|
||||||
consent management powered by
|
consent management powered by
|
||||||
<a href="https://consent.software">consent.software</a>
|
<a href="https://consent.software">consent.software</a>
|
||||||
(Open Source)
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -271,44 +228,39 @@ export class ConsentsoftwareCookieconsent extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the element is inserted into the DOM.
|
* Lifecycle method called when the element is connected to the DOM.
|
||||||
|
* Displays the consent banner if no cookie levels are set.
|
||||||
*/
|
*/
|
||||||
public async connectedCallback() {
|
public async connectedCallback() {
|
||||||
super.connectedCallback();
|
await super.connectedCallback();
|
||||||
this.updateTheme();
|
|
||||||
|
|
||||||
const cookieLevel = await this.csWebclientInstance.getCookieLevels();
|
const cookieLevel = await this.csWebclientInstance.getCookieLevels();
|
||||||
if (!cookieLevel) {
|
if (!cookieLevel) {
|
||||||
|
// Show consent banner if cookie levels haven't been set yet
|
||||||
this.setAttribute('show', 'true');
|
this.setAttribute('show', 'true');
|
||||||
requestAnimationFrame(async () => {
|
requestAnimationFrame(async () => {
|
||||||
await this.updated();
|
await this.updateComplete;
|
||||||
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
|
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
|
||||||
if (pageOverlay) {
|
if (pageOverlay) {
|
||||||
pageOverlay.style.background = 'rgba(0,0,0, 0.5)';
|
// Apply subtle backdrop blur when modal appears
|
||||||
pageOverlay.style.backdropFilter = 'blur(20px)';
|
pageOverlay.style.background = 'rgba(0,0,0, 0.6)';
|
||||||
|
pageOverlay.style.backdropFilter = 'blur(4px)';
|
||||||
}
|
}
|
||||||
const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox');
|
const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox');
|
||||||
if (modalBox) {
|
if (modalBox) {
|
||||||
|
// Animate modal box appearance
|
||||||
modalBox.style.transform = `scale(1)`;
|
modalBox.style.transform = `scale(1)`;
|
||||||
modalBox.style.opacity = '1';
|
modalBox.style.opacity = '1';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// Hide banner if cookie levels are already set
|
||||||
this.setAttribute('show', 'false');
|
this.setAttribute('show', 'false');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public async firstUpdated() {
|
||||||
* Called after the first render of the component.
|
// Run consent scripts if levels are already set
|
||||||
* 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();
|
const acceptedCookieLevels = await this.csWebclientInstance.getCookieLevels();
|
||||||
if (!this.csWebclientRan && acceptedCookieLevels) {
|
if (!this.csWebclientRan && acceptedCookieLevels) {
|
||||||
this.csWebclientRan = true;
|
this.csWebclientRan = true;
|
||||||
@@ -317,7 +269,7 @@ export class ConsentsoftwareCookieconsent extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the user’s chosen cookie level(s) and hides the banner.
|
* Handles consent button clicks, sets cookie levels, and hides the banner.
|
||||||
*/
|
*/
|
||||||
private async handleConsentButtonClick(
|
private async handleConsentButtonClick(
|
||||||
event: MouseEvent,
|
event: MouseEvent,
|
||||||
@@ -326,21 +278,31 @@ export class ConsentsoftwareCookieconsent extends LitElement {
|
|||||||
console.log(`Set level to ${levelsArg}`);
|
console.log(`Set level to ${levelsArg}`);
|
||||||
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
|
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
|
||||||
if (pageOverlay) {
|
if (pageOverlay) {
|
||||||
pageOverlay.style.background = 'rgba(255,255,255, 0)';
|
pageOverlay.style.background = 'rgba(0,0,0, 0)';
|
||||||
pageOverlay.style.backdropFilter = 'blur(0px)';
|
pageOverlay.style.backdropFilter = 'blur(0px)';
|
||||||
}
|
}
|
||||||
const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox');
|
const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox');
|
||||||
if (modalBox) {
|
if (modalBox) {
|
||||||
|
// Scale down and fade out modal box before hiding
|
||||||
modalBox.style.transform = `scale(0.95)`;
|
modalBox.style.transform = `scale(0.95)`;
|
||||||
modalBox.style.opacity = '0';
|
modalBox.style.opacity = '0';
|
||||||
}
|
}
|
||||||
|
// Save user consent preferences
|
||||||
await this.csWebclientInstance.setCookieLevels(levelsArg);
|
await this.csWebclientInstance.setCookieLevels(levelsArg);
|
||||||
await delayFor(300);
|
await delayFor(300);
|
||||||
this.setAttribute('show', 'false');
|
this.setAttribute('show', 'false'); // Hide the consent banner
|
||||||
// After user selection, re-check for any required scripts to run
|
|
||||||
this.updated();
|
// Run consent scripts
|
||||||
|
if (!this.csWebclientRan) {
|
||||||
|
this.csWebclientRan = true;
|
||||||
|
await this.csWebclientInstance.getAndRunConsentTuples();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles clicks on the page overlay. If clicked outside the modal,
|
||||||
|
* triggers a shake animation as feedback.
|
||||||
|
*/
|
||||||
private async pageOverlayClick(e: MouseEvent) {
|
private async pageOverlayClick(e: MouseEvent) {
|
||||||
if (e.target === e.currentTarget) {
|
if (e.target === e.currentTarget) {
|
||||||
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
|
const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay');
|
||||||
@@ -354,16 +316,4 @@ export class ConsentsoftwareCookieconsent extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,52 @@
|
|||||||
import * as shared from './shared.js';
|
import { cssManager, colors } from './shared.js';
|
||||||
|
|
||||||
import { LitElement, html, css, type TemplateResult } from 'lit';
|
import {
|
||||||
import { customElement } from 'lit/decorators.js';
|
DeesElement,
|
||||||
import { property } from 'lit/decorators/property.js';
|
customElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
type TemplateResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
@customElement('consentsoftware-header')
|
@customElement('consentsoftware-header')
|
||||||
export class ConsentsoftwareHeader extends LitElement {
|
export class ConsentsoftwareHeader extends DeesElement {
|
||||||
public static demo = () => html`<consentsoftware-tabs></consentsoftware-tabs>`;
|
public static demo = () => html`<consentsoftware-header></consentsoftware-header>`;
|
||||||
|
|
||||||
public static styles = css`
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 3em;
|
padding: 14px 16px;
|
||||||
text-align: center;
|
border-bottom: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)};
|
||||||
font-family: ${shared.fontStack};
|
|
||||||
border-bottom: 1px dotted rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 0.95em;
|
||||||
|
font-weight: 600;
|
||||||
|
color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)};
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
constructor() {
|
.icon {
|
||||||
super();
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="heading">
|
<div class="heading">
|
||||||
What about cookies?
|
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<circle cx="12" cy="12" r="10"/>
|
||||||
|
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/>
|
||||||
|
<path d="M12 17h.01"/>
|
||||||
|
</svg>
|
||||||
|
Cookie Preferences
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
import { LitElement, html, css, type TemplateResult } from 'lit';
|
import { cssManager, colors } from './shared.js';
|
||||||
import { customElement } from 'lit/decorators.js';
|
|
||||||
import { property } from 'lit/decorators/property.js';
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
@customElement('consentsoftware-mainselection')
|
@customElement('consentsoftware-mainselection')
|
||||||
export class ConsentsoftwareMainSelection extends LitElement {
|
export class ConsentsoftwareMainSelection extends DeesElement {
|
||||||
public static demo = () => html`<consentsoftware-mainselection></consentsoftware-mainselection>`;
|
public static demo = () => html`<consentsoftware-mainselection></consentsoftware-mainselection>`;
|
||||||
|
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
public required = false;
|
public accessor required = false;
|
||||||
|
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
public selected = false;
|
public accessor selected = false;
|
||||||
|
|
||||||
public static styles = css`
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -21,23 +30,44 @@ export class ConsentsoftwareMainSelection extends LitElement {
|
|||||||
.maincontainer {
|
.maincontainer {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.maincontainer {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemBox {
|
.itemBox {
|
||||||
padding: 16px;
|
padding: 12px 8px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-right: 1px solid;
|
border-right: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)};
|
||||||
border-image: radial-gradient(circle, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%) 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemBox:last-child {
|
.itemBox:last-child {
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
constructor() {
|
@media (max-width: 560px) {
|
||||||
super();
|
.itemBox {
|
||||||
|
padding: 10px 8px;
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.itemBox:nth-child(odd) {
|
||||||
|
border-right: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)};
|
||||||
|
}
|
||||||
|
|
||||||
|
.itemBox:nth-last-child(-n+2) {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="maincontainer">
|
<div class="maincontainer">
|
||||||
@@ -57,5 +87,5 @@ export class ConsentsoftwareMainSelection extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getResults(mouseEvent) {}
|
public async getResults() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
import { LitElement, html, css, type TemplateResult } from 'lit';
|
import { cssManager, colors } from './shared.js';
|
||||||
import { customElement } from 'lit/decorators.js';
|
|
||||||
import { property } from 'lit/decorators/property.js';
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
type TemplateResult,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
@customElement('consentsoftware-tabs')
|
@customElement('consentsoftware-tabs')
|
||||||
export class ConsentsoftwareTabs extends LitElement {
|
export class ConsentsoftwareTabs extends DeesElement {
|
||||||
public static demo = () => html`<consentsoftware-tabs></consentsoftware-tabs>`;
|
public static demo = () => html`<consentsoftware-tabs></consentsoftware-tabs>`;
|
||||||
|
|
||||||
public static styles = css`
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
background: ${cssManager.bdTheme(colors.light.muted, colors.dark.muted)};
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
@@ -20,37 +28,50 @@ export class ConsentsoftwareTabs extends LitElement {
|
|||||||
|
|
||||||
.tabs .tab {
|
.tabs .tab {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 3em;
|
padding: 8px 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: 500;
|
||||||
|
color: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs .tab:hover {
|
||||||
|
color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)};
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 560px) {
|
||||||
|
.tabs .tab {
|
||||||
|
font-size: 0.75em;
|
||||||
|
padding: 6px 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.selector {
|
.selector {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: calc(100% / 3);
|
width: calc(100% / 3);
|
||||||
height: 1px;
|
height: 2px;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0px;
|
bottom: 0;
|
||||||
background: orange;
|
background: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)};
|
||||||
transition: all 0.2s;
|
transition: all 0.2s ease-out;
|
||||||
}
|
border-radius: 1px;
|
||||||
`;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="tabs">
|
<div class="tabs">
|
||||||
<div class="tab" @click=${this.handleClick}>Consent</div>
|
<div class="tab" @click=${this.handleClick}>Consent</div>
|
||||||
<div class="tab" @click=${this.handleClick}>Details</div>
|
<div class="tab" @click=${this.handleClick}>Details</div>
|
||||||
<div class="tab" @click=${this.handleClick}>Cookie Policy + Legal Info</div>
|
<div class="tab" @click=${this.handleClick}>Cookie Policy</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="selector"></div>
|
<div class="selector"></div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleClick(mouseEvent) {
|
public async handleClick(mouseEvent: MouseEvent) {
|
||||||
const target = mouseEvent.target as HTMLElement;
|
const target = mouseEvent.target as HTMLElement;
|
||||||
const tab: HTMLDivElement = target.closest('.tab');
|
const tab: HTMLDivElement = target.closest('.tab');
|
||||||
if (tab) {
|
if (tab) {
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
import { LitElement, html, css, type TemplateResult } from 'lit';
|
import { cssManager, colors } from './shared.js';
|
||||||
import { customElement } from 'lit/decorators.js';
|
|
||||||
import { property } from 'lit/decorators/property.js';
|
import {
|
||||||
|
DeesElement,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
css,
|
||||||
|
type TemplateResult,
|
||||||
|
property,
|
||||||
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import { delayFor } from '@push.rocks/smartdelay';
|
import { delayFor } from '@push.rocks/smartdelay';
|
||||||
|
|
||||||
@customElement('consentsoftware-toggle')
|
@customElement('consentsoftware-toggle')
|
||||||
export class ConsentsoftwareToggle extends LitElement {
|
export class ConsentsoftwareToggle extends DeesElement {
|
||||||
@property({ type: Boolean })
|
@property({ type: Boolean })
|
||||||
public accessor required = false;
|
public accessor required = false;
|
||||||
|
|
||||||
@@ -12,9 +20,9 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
public accessor selected = false;
|
public accessor selected = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We always track the knob’s left offset in `currentX`.
|
* Knob position tracking (0 = off, maxTravel = on)
|
||||||
* - 0 => fully left
|
* This is the travel distance, not absolute left position.
|
||||||
* - 30 => fully right
|
* Actual left = padding + currentX
|
||||||
*/
|
*/
|
||||||
private currentX = 0;
|
private currentX = 0;
|
||||||
|
|
||||||
@@ -23,39 +31,54 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
*/
|
*/
|
||||||
private isDragging = false;
|
private isDragging = false;
|
||||||
private hasDragged = false;
|
private hasDragged = false;
|
||||||
private startX = 0; // pointerdown offset
|
private startX = 0;
|
||||||
private readonly knobWidth = 30;
|
|
||||||
private readonly trackWidth = 60;
|
|
||||||
|
|
||||||
public static styles = css`
|
// Toggle dimensions (with border-box, 1px border reduces inner by 2px)
|
||||||
|
private readonly trackWidth = 36; // outer width
|
||||||
|
private readonly trackHeight = 20; // outer height
|
||||||
|
private readonly knobSize = 14;
|
||||||
|
private readonly padding = 2; // padding from inner edge to knob
|
||||||
|
private readonly maxTravel = 16; // (36 - 2) - 14 - (2 * 2) = 34 - 14 - 4 = 16
|
||||||
|
|
||||||
|
public static styles = [
|
||||||
|
cssManager.defaultStyles,
|
||||||
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 8px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: 500;
|
||||||
|
color: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)};
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle {
|
.toggle {
|
||||||
user-select: none; /* helps avoid text selection on drag */
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggleKnobArea {
|
.toggleKnobArea {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
height: 30px;
|
height: 20px;
|
||||||
width: 60px;
|
width: 36px;
|
||||||
border-radius: 20px;
|
border-radius: 10px;
|
||||||
background: rgba(255, 255, 255, 0.1);
|
background: ${cssManager.bdTheme(colors.light.input, colors.dark.input)};
|
||||||
border: 1px solid rgba(255, 255, 255, 0);
|
border: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)};
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: background 0.2s ease;
|
transition: all 0.15s ease;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggleKnobArea:hover {
|
||||||
|
border-color: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)};
|
||||||
|
}
|
||||||
|
|
||||||
:host([selected]) .toggleKnobArea {
|
:host([selected]) .toggleKnobArea {
|
||||||
background: green;
|
background: ${cssManager.bdTheme(colors.light.primary, colors.dark.primary)};
|
||||||
|
border-color: ${cssManager.bdTheme(colors.light.primary, colors.dark.primary)};
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggleKnobMover {
|
.toggleKnobMover {
|
||||||
@@ -66,39 +89,37 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
|
|
||||||
.toggleKnobInner {
|
.toggleKnobInner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 2px;
|
||||||
left: 0;
|
width: 14px;
|
||||||
width: 30px;
|
height: 14px;
|
||||||
height: 30px;
|
border-radius: 7px;
|
||||||
border-radius: 15px;
|
background: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)};
|
||||||
background: rgba(255, 255, 255, 0.5);
|
transition: left 0.15s ease, background 0.15s ease;
|
||||||
transition: left 0.2s ease, background 0.2s ease;
|
|
||||||
transform: scale(0.7);
|
|
||||||
/* Prevent scroll gestures on mobile */
|
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggleKnobInner.dragging {
|
.toggleKnobInner.dragging {
|
||||||
transition: background 0.2s ease;
|
transition: background 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([selected]) .toggleKnobInner {
|
:host([selected]) .toggleKnobInner {
|
||||||
background: white;
|
background: ${cssManager.bdTheme(colors.light.primaryForeground, colors.dark.primaryForeground)};
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([required]) .toggleKnobArea {
|
:host([required]) .toggleKnobArea {
|
||||||
background: none;
|
cursor: not-allowed;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([required]) .toggleKnobInner {
|
:host([required][selected]) .toggleKnobArea {
|
||||||
background: rgba(255, 255, 255, 0.1);
|
background: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)};
|
||||||
|
border-color: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)};
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
constructor() {
|
:host([required][selected]) .toggleKnobInner {
|
||||||
super();
|
background: ${cssManager.bdTheme(colors.light.muted, colors.dark.muted)};
|
||||||
}
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
@@ -110,7 +131,7 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
<!-- The knob itself, with pointer events for dragging. -->
|
<!-- The knob itself, with pointer events for dragging. -->
|
||||||
<div
|
<div
|
||||||
class="toggleKnobInner"
|
class="toggleKnobInner"
|
||||||
style="left: ${this.currentX}px;"
|
style="left: ${this.padding + this.currentX}px;"
|
||||||
@pointerdown=${this.onPointerDown}
|
@pointerdown=${this.onPointerDown}
|
||||||
@pointermove=${this.onPointerMove}
|
@pointermove=${this.onPointerMove}
|
||||||
@pointerup=${this.onPointerUp}
|
@pointerup=${this.onPointerUp}
|
||||||
@@ -125,15 +146,14 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
/**
|
/**
|
||||||
* If required = true on first render, auto-select and set the knob to the right.
|
* If required = true on first render, auto-select and set the knob to the right.
|
||||||
*/
|
*/
|
||||||
public async firstUpdated() {
|
public async firstUpdated(_changedProperties: Map<PropertyKey, unknown>) {
|
||||||
|
await super.firstUpdated(_changedProperties);
|
||||||
if (this.required) {
|
if (this.required) {
|
||||||
// If "required" => always selected
|
|
||||||
this.selected = true;
|
this.selected = true;
|
||||||
this.currentX = this.knobWidth; // 30
|
this.currentX = this.maxTravel;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
} else {
|
} else {
|
||||||
// If not required, set knob to 0 or 30 depending on `selected`
|
this.currentX = this.selected ? this.maxTravel : 0;
|
||||||
this.currentX = this.selected ? this.knobWidth : 0;
|
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +162,6 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
* CLICK HANDLER
|
* CLICK HANDLER
|
||||||
*/
|
*/
|
||||||
public async handleClick(event: MouseEvent) {
|
public async handleClick(event: MouseEvent) {
|
||||||
// If the user truly dragged the knob, skip the normal click toggle.
|
|
||||||
if (this.isDragging || this.hasDragged) {
|
if (this.isDragging || this.hasDragged) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -150,26 +169,23 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.required) {
|
if (this.required) {
|
||||||
// small bounce from 30 -> 20 -> 30
|
// Small bounce animation for required toggles
|
||||||
this.currentX = this.knobWidth; // ensure at 30
|
this.currentX = this.maxTravel;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
await new Promise((r) => setTimeout(r, 10));
|
await new Promise((r) => setTimeout(r, 10));
|
||||||
|
this.currentX = this.maxTravel - 3;
|
||||||
this.currentX = 20; // small bounce left
|
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
await delayFor(200);
|
await delayFor(150);
|
||||||
|
this.currentX = this.maxTravel;
|
||||||
this.currentX = this.knobWidth; // back to 30
|
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal toggle if no drag & not required
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
this.selected = !this.selected;
|
this.selected = !this.selected;
|
||||||
this.currentX = this.selected ? this.knobWidth : 0; // snap knob left(0) or right(30)
|
this.currentX = this.selected ? this.maxTravel : 0;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent('toggle', { detail: { selected: this.selected } }));
|
this.dispatchEvent(new CustomEvent('toggle', { detail: { selected: this.selected } }));
|
||||||
@@ -189,7 +205,7 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
|
|
||||||
// Start dragging
|
// Start dragging
|
||||||
this.isDragging = true;
|
this.isDragging = true;
|
||||||
// The difference between the pointer’s X and the knob’s current position
|
// The difference between the pointer's X and the knob's current position
|
||||||
this.startX = event.clientX - this.currentX;
|
this.startX = event.clientX - this.currentX;
|
||||||
|
|
||||||
// capture pointer so we keep receiving pointermove/pointerup
|
// capture pointer so we keep receiving pointermove/pointerup
|
||||||
@@ -203,8 +219,8 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
const toggleKnobInner: HTMLDivElement = this.shadowRoot.querySelector('.toggleKnobInner');
|
const toggleKnobInner: HTMLDivElement = this.shadowRoot.querySelector('.toggleKnobInner');
|
||||||
toggleKnobInner.classList.add('dragging');
|
toggleKnobInner.classList.add('dragging');
|
||||||
|
|
||||||
// Clamp
|
// Clamp to valid travel range (0 to maxTravel)
|
||||||
this.currentX = Math.max(0, Math.min(newX, this.trackWidth - this.knobWidth));
|
this.currentX = Math.max(0, Math.min(newX, this.maxTravel));
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,17 +229,17 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
(event.target as HTMLElement).releasePointerCapture(event.pointerId);
|
(event.target as HTMLElement).releasePointerCapture(event.pointerId);
|
||||||
this.isDragging = false;
|
this.isDragging = false;
|
||||||
|
|
||||||
// If we didn’t truly drag, pointerup does nothing; click handler handles toggling.
|
// If we didn't truly drag, pointerup does nothing; click handler handles toggling.
|
||||||
if (!this.hasDragged) {
|
if (!this.hasDragged) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const toggleKnobInner: HTMLDivElement = this.shadowRoot.querySelector('.toggleKnobInner');
|
const toggleKnobInner: HTMLDivElement = this.shadowRoot.querySelector('.toggleKnobInner');
|
||||||
toggleKnobInner.classList.remove('dragging');
|
toggleKnobInner.classList.remove('dragging');
|
||||||
|
|
||||||
// Real drag => decide final side
|
// Real drag => decide final side based on midpoint
|
||||||
const midpoint = (this.trackWidth - this.knobWidth) / 2; // 15
|
const midpoint = this.maxTravel / 2;
|
||||||
this.selected = this.currentX > midpoint;
|
this.selected = this.currentX > midpoint;
|
||||||
this.currentX = this.selected ? this.knobWidth : 0; // snap to edge
|
this.currentX = this.selected ? this.maxTravel : 0; // snap to edge
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
|
|
||||||
// Dispatch toggle event
|
// Dispatch toggle event
|
||||||
@@ -243,7 +259,7 @@ export class ConsentsoftwareToggle extends LitElement {
|
|||||||
!this.hasDragged &&
|
!this.hasDragged &&
|
||||||
!this.required
|
!this.required
|
||||||
) {
|
) {
|
||||||
this.currentX = this.selected ? this.knobWidth : 0;
|
this.currentX = this.selected ? this.maxTravel : 0;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
super.updated(changedProperties);
|
super.updated(changedProperties);
|
||||||
|
|||||||
@@ -1,3 +1,39 @@
|
|||||||
import { unsafeCSS } from 'lit'
|
import { unsafeCSS, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
|
export { cssManager };
|
||||||
|
|
||||||
export const fontStack = unsafeCSS('system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif');
|
export const fontStack = unsafeCSS('system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif');
|
||||||
|
|
||||||
|
// Shadcn-inspired color palette
|
||||||
|
export const colors = {
|
||||||
|
light: {
|
||||||
|
background: '#ffffff',
|
||||||
|
foreground: '#09090b',
|
||||||
|
muted: '#f4f4f5',
|
||||||
|
mutedForeground: '#71717a',
|
||||||
|
border: '#e4e4e7',
|
||||||
|
input: '#e4e4e7',
|
||||||
|
primary: '#18181b',
|
||||||
|
primaryForeground: '#fafafa',
|
||||||
|
secondary: '#f4f4f5',
|
||||||
|
secondaryForeground: '#18181b',
|
||||||
|
accent: '#f4f4f5',
|
||||||
|
accentForeground: '#18181b',
|
||||||
|
ring: '#a1a1aa',
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
background: '#09090b',
|
||||||
|
foreground: '#fafafa',
|
||||||
|
muted: '#27272a',
|
||||||
|
mutedForeground: '#a1a1aa',
|
||||||
|
border: '#27272a',
|
||||||
|
input: '#27272a',
|
||||||
|
primary: '#fafafa',
|
||||||
|
primaryForeground: '#18181b',
|
||||||
|
secondary: '#27272a',
|
||||||
|
secondaryForeground: '#fafafa',
|
||||||
|
accent: '#27272a',
|
||||||
|
accentForeground: '#fafafa',
|
||||||
|
ring: '#52525b',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import { html } from 'lit';
|
import { html } from '@design.estate/dees-element';
|
||||||
|
|
||||||
export const page1 = () => html``;
|
export const page1 = () => html``;
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es2017",
|
"target": "ES2022",
|
||||||
"module": "es2015",
|
"module": "ES2022",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "bundler",
|
||||||
"lib": ["es2017", "dom"],
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"inlineSources": true,
|
"inlineSources": true,
|
||||||
"inlineSourceMap": true,
|
"inlineSourceMap": true,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2020",
|
"target": "ES2022",
|
||||||
"module": "ES2020",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "node12"
|
"moduleResolution": "NodeNext"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user