From 0d90a7ae7f178ad2fb89595c5d8408909fd07078 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Sun, 30 Nov 2025 21:54:10 +0000 Subject: [PATCH] BREAKING CHANGE(elements): Migrate web components to @design.estate/dees-element, introduce shared theme colors and cssManager, and update imports/usages across ts_web. --- changelog.md | 10 + package.json | 4 +- pnpm-lock.yaml | 69 +--- ts_web/00_commitinfo_data.ts | 2 +- .../elements/consentsoftware-cookieconsent.ts | 354 +++++++----------- ts_web/elements/consentsoftware-header.ts | 66 ++-- .../elements/consentsoftware-mainselection.ts | 92 ++--- ts_web/elements/consentsoftware-tabs.ts | 105 +++--- ts_web/elements/consentsoftware-toggle.ts | 170 +++++---- ts_web/elements/shared.ts | 40 +- ts_web/pages/page1.ts | 2 +- 11 files changed, 428 insertions(+), 486 deletions(-) diff --git a/changelog.md b/changelog.md index 6c2a726..2a2717d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,15 @@ # 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 diff --git a/package.json b/package.json index 9ce0f0e..7bd42dd 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,8 @@ "dependencies": { "@consent.software/interfaces": "^1.0.14", "@consent.software/webclient": "^1.1.0", - "@push.rocks/smartdelay": "^3.0.5", - "lit": "^3.3.1" + "@design.estate/dees-element": "^2.1.3", + "@push.rocks/smartdelay": "^3.0.5" }, "devDependencies": { "@design.estate/dees-wcctools": "^1.2.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4f2c4e..2ac2d8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,12 +14,12 @@ importers: '@consent.software/webclient': specifier: ^1.1.0 version: 1.1.0 + '@design.estate/dees-element': + specifier: ^2.1.3 + version: 2.1.3 '@push.rocks/smartdelay': specifier: ^3.0.5 version: 3.0.5 - lit: - specifier: ^3.3.1 - version: 3.3.1 devDependencies: '@design.estate/dees-wcctools': specifier: ^1.2.1 @@ -236,15 +236,9 @@ packages: '@design.estate/dees-comms@1.0.27': resolution: {integrity: sha512-GvzTUwkV442LD60T08iqSoqvhA02Mou5lFvvqBPc4yBUiU7cZISqBx+76xvMgMIEI9Dx9JfTl4/2nW8MoVAanw==} - '@design.estate/dees-domtools@2.1.1': - resolution: {integrity: sha512-ZYe7rt2pOWZ6av4YDc88i+Li9WquOHuvE4Xyf+Wo9jAZ37XyTw53wzzviaW3zDG77ggX2VlCLFkAs8Tm5Lf4gg==} - '@design.estate/dees-domtools@2.3.6': resolution: {integrity: sha512-cKaPNtSpp/ZuuXVx2dXO3K2FU3/HjC4ZkqtXb8Kl6yy9rNDbgtjcI4PuOk9Ux1SJzw7FgcxqVh7OSEV60htbmg==} - '@design.estate/dees-element@2.0.39': - resolution: {integrity: sha512-AQdGU/+GmWmU5M5pDf+GWT7GU8UN073WZvtIkfqQZemxd35HYU1vpi629m8/PjKd5dIHAU7QN2mKb6IQ8anPgw==} - '@design.estate/dees-element@2.1.3': resolution: {integrity: sha512-TjXWxVcdSPaT1IOk31ckfxvAZnJLuTxhFGsNCKoh63/UE2FVf6slp8//UFvN+ADigiA9ZsY0azkY99XbJCwDDA==} @@ -820,9 +814,6 @@ packages: '@push.rocks/smartrequest@4.4.2': resolution: {integrity: sha512-Om4y1Ce4YdSu8VoXREz2SgFz9pDxcFEm0+SC1YYa3RXd0AH2Mknaj/1XfvfMqojnK9L7N2z1fY4xX8tO1IwqFQ==} - '@push.rocks/smartrouter@1.3.2': - resolution: {integrity: sha512-JtkxClN4CaHXMSeLDNvfWPwiVEPdEoQVSX2ee3gLgbXNO9dt9hvXdIhFrnFeLwyeA6M8nJdb9SqjrjZroYJsxw==} - '@push.rocks/smartrouter@1.3.3': resolution: {integrity: sha512-1+xZEnWlhzqLWAaJ1zFNhQ0zgbfCWQl1DBT72LygLxTs+P0K8AwJKgqo/IX6CT55kGCFnPAZIYSbVJlGsgrB0w==} @@ -847,9 +838,6 @@ packages: '@push.rocks/smartspawn@3.0.3': resolution: {integrity: sha512-DyrGPV69wwOiJgKkyruk5hS3UEGZ99xFAqBE9O2nM8VXCRLbbty3xt1Ug5Z092ZZmJYaaGMSnMw3ijyZJFCT0Q==} - '@push.rocks/smartstate@2.0.19': - resolution: {integrity: sha512-Rx2/2n8YaSBW6b4Ww+lYceq5dwkD+QzcnRwAjQDXlsEe8K+KU2T6revTZyf9PchBoC9pNFaAJofIZNebEGMzYA==} - '@push.rocks/smartstate@2.0.27': resolution: {integrity: sha512-q4UKir7GV3hakJWXQR4DoA4tUVwT5GRkJ/MtanHYF0wZLHfS19+nGmyO9y974zk3eT9hmy3+Lq5cKtU2W6+Y3w==} @@ -3774,28 +3762,6 @@ snapshots: '@push.rocks/smartdelay': 3.0.5 broadcast-channel: 7.0.0 - '@design.estate/dees-domtools@2.1.1': - dependencies: - '@api.global/typedrequest': 3.1.10 - '@design.estate/dees-comms': 1.0.27 - '@push.rocks/lik': 6.2.2 - '@push.rocks/smartdelay': 3.0.5 - '@push.rocks/smartjson': 5.2.0 - '@push.rocks/smartmarkdown': 3.0.3 - '@push.rocks/smartpromise': 4.2.3 - '@push.rocks/smartrouter': 1.3.2 - '@push.rocks/smartrx': 3.0.10 - '@push.rocks/smartstate': 2.0.19 - '@push.rocks/smartstring': 4.0.15 - '@push.rocks/smarturl': 3.1.0 - '@push.rocks/webrequest': 3.0.37 - '@push.rocks/websetup': 3.0.19 - '@push.rocks/webstore': 2.0.20 - lit: 3.3.1 - sweet-scroll: 4.0.0 - transitivePeerDependencies: - - supports-color - '@design.estate/dees-domtools@2.3.6': dependencies: '@api.global/typedrequest': 3.1.10 @@ -3822,15 +3788,6 @@ snapshots: - supports-color - vue - '@design.estate/dees-element@2.0.39': - dependencies: - '@design.estate/dees-domtools': 2.1.1 - '@push.rocks/isounique': 1.0.5 - '@push.rocks/smartrx': 3.0.10 - lit: 3.3.1 - transitivePeerDependencies: - - supports-color - '@design.estate/dees-element@2.1.3': dependencies: '@design.estate/dees-domtools': 2.3.6 @@ -4547,12 +4504,15 @@ snapshots: '@push.rocks/smartntml@2.0.8': dependencies: - '@design.estate/dees-element': 2.0.39 + '@design.estate/dees-element': 2.1.3 '@happy-dom/global-registrator': 15.11.7 '@push.rocks/smartpromise': 4.2.3 fake-indexeddb: 6.0.0 transitivePeerDependencies: + - '@nuxt/kit' + - react - supports-color + - vue '@push.rocks/smartobject@1.0.12': dependencies: @@ -4598,12 +4558,6 @@ snapshots: agentkeepalive: 4.6.0 form-data: 4.0.5 - '@push.rocks/smartrouter@1.3.2': - dependencies: - '@push.rocks/lik': 6.2.2 - '@push.rocks/smartrx': 3.0.10 - path-to-regexp: 8.2.0 - '@push.rocks/smartrouter@1.3.3': dependencies: '@push.rocks/lik': 6.2.2 @@ -4677,15 +4631,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@push.rocks/smartstate@2.0.19': - dependencies: - '@push.rocks/isohash': 2.0.1 - '@push.rocks/lik': 6.2.2 - '@push.rocks/smartjson': 5.2.0 - '@push.rocks/smartpromise': 4.2.3 - '@push.rocks/smartrx': 3.0.10 - '@push.rocks/webstore': 2.0.20 - '@push.rocks/smartstate@2.0.27': dependencies: '@push.rocks/lik': 6.2.2 diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index a85a46d..38a3cf0 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@consent.software/catalog', - version: '1.6.1', + 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.' } diff --git a/ts_web/elements/consentsoftware-cookieconsent.ts b/ts_web/elements/consentsoftware-cookieconsent.ts index 964fdb5..7c6a867 100644 --- a/ts_web/elements/consentsoftware-cookieconsent.ts +++ b/ts_web/elements/consentsoftware-cookieconsent.ts @@ -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 { 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 * as csInterfaces from '@consent.software/interfaces'; import * as csWebclient from '@consent.software/webclient'; @@ -15,212 +20,158 @@ declare global { } @customElement('consentsoftware-cookieconsent') -export class ConsentsoftwareCookieconsent extends LitElement { +export class ConsentsoftwareCookieconsent extends DeesElement { public static demo = () => html``; public csWebclientInstance = new csWebclient.CsWebclient(); public csWebclientRan = false; - // Reflects the current theme ('light' or 'dark') - @property({ type: String, reflect: true }) - public accessor theme: 'light' | 'dark' = 'light'; + public static styles = [ + cssManager.defaultStyles, + css` + :host { + font-size: 14px; + user-select: none; + } - /** - * Define component styles with CSS variables that adjust based on theme. - * The default variables serve as baseline for the light theme. - * Theme-specific overrides modify these for dark mode. - */ - public static styles = css` - :host { - font-family: ${shared.fontStack}; - font-size: 14px; - user-select: none; - /* Shadcn-inspired Dark Theme (default) */ - --background: hsl(0 0% 7%); - --foreground: hsl(0 0% 95%); - --muted: hsl(0 0% 15%); - --muted-foreground: hsl(0 0% 64%); - --border: hsl(0 0% 18%); - --input: hsl(0 0% 15%); - --primary: hsl(0 0% 98%); - --primary-foreground: hsl(0 0% 9%); - --secondary: hsl(0 0% 15%); - --secondary-foreground: hsl(0 0% 98%); - --accent: hsl(0 0% 15%); - --accent-foreground: hsl(0 0% 98%); - --ring: hsl(0 0% 30%); - --radius: 8px; - } + .pageOverlay { + position: fixed; + inset: 0; + display: grid; + align-items: center; + justify-content: center; + z-index: 1000; + background: rgba(0, 0, 0, 0); + backdrop-filter: blur(0px); + transition: all 0.2s ease-out; + } - :host([theme='dark']) { - --background: hsl(0 0% 7%); - --foreground: hsl(0 0% 95%); - --muted: hsl(0 0% 15%); - --muted-foreground: hsl(0 0% 64%); - --border: hsl(0 0% 18%); - --input: hsl(0 0% 15%); - --primary: hsl(0 0% 98%); - --primary-foreground: hsl(0 0% 9%); - --secondary: hsl(0 0% 15%); - --secondary-foreground: hsl(0 0% 98%); - --accent: hsl(0 0% 15%); - --accent-foreground: hsl(0 0% 98%); - --ring: hsl(0 0% 30%); - } + .pageOverlay.shake { + background: rgba(0, 0, 0, 0.6) !important; + } - :host([theme='light']) { - --background: hsl(0 0% 100%); - --foreground: hsl(0 0% 9%); - --muted: hsl(0 0% 96%); - --muted-foreground: hsl(0 0% 45%); - --border: hsl(0 0% 90%); - --input: hsl(0 0% 90%); - --primary: hsl(0 0% 9%); - --primary-foreground: hsl(0 0% 98%); - --secondary: hsl(0 0% 96%); - --secondary-foreground: hsl(0 0% 9%); - --accent: hsl(0 0% 96%); - --accent-foreground: hsl(0 0% 9%); - --ring: hsl(0 0% 64%); - } - - .pageOverlay { - position: fixed; - inset: 0; - display: grid; - align-items: center; - justify-content: center; - z-index: 1000; - background: rgba(0, 0, 0, 0); - backdrop-filter: blur(0px); - transition: all 0.2s ease-out; - } - - .pageOverlay.shake { - background: rgba(0, 0, 0, 0.6) !important; - } - - .modalBox { - display: block; - color: var(--foreground); - background: var(--background); - box-shadow: - 0 0 0 1px var(--border), - 0 16px 70px rgba(0, 0, 0, 0.35); - position: relative; - border-radius: var(--radius); - max-width: 520px; - min-width: 320px; - box-sizing: border-box; - overflow: hidden; - will-change: transform; - transition: all 0.2s ease-out; - transform: scale(0.96); - opacity: 0; - } - - @media (max-width: 560px) { .modalBox { - max-width: 100%; - min-width: 100%; - height: 100vh; - border-radius: 0; + display: block; + color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)}; + background: ${cssManager.bdTheme(colors.light.background, colors.dark.background)}; + box-shadow: + 0 0 0 1px ${cssManager.bdTheme(colors.light.border, colors.dark.border)}, + 0 16px 70px ${cssManager.bdTheme('rgba(0, 0, 0, 0.15)', 'rgba(0, 0, 0, 0.35)')}; + position: relative; + border-radius: 8px; + max-width: 520px; + min-width: 320px; + box-sizing: border-box; + overflow: hidden; + will-change: transform; + transition: all 0.2s ease-out; + transform: scale(0.96); + opacity: 0; } - } - .modalBox.shake { - animation: shake 120ms 2 linear; - } + @media (max-width: 560px) { + .modalBox { + max-width: 100%; + min-width: 100%; + height: 100vh; + border-radius: 0; + } + } - @keyframes shake { - 0% { transform: translateX(3px); } - 50% { transform: translateX(-3px); } - 100% { transform: translateX(0); } - } + .modalBox.shake { + animation: shake 120ms 2 linear; + } - :host([show='false']) { display: none; } - :host([show='true']) { display: block; } + @keyframes shake { + 0% { transform: translateX(3px); } + 50% { transform: translateX(-3px); } + 100% { transform: translateX(0); } + } - .content { - margin: auto; - } + :host([show='false']) { display: none; } + :host([show='true']) { display: block; } - .text-container { - padding: 12px 16px; - font-size: 0.9em; - line-height: 1.5; - color: var(--muted-foreground); - } + .content { + margin: auto; + } - .text-container a { - color: var(--foreground); - text-decoration: underline; - text-underline-offset: 2px; - } + .text-container { + padding: 12px 16px; + font-size: 0.9em; + line-height: 1.5; + color: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)}; + } - .text-container a:hover { - opacity: 0.8; - } + .text-container a { + color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)}; + text-decoration: underline; + text-underline-offset: 2px; + } - .button-container { - padding: 12px 16px 16px; - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 8px; - } + .text-container a:hover { + opacity: 0.8; + } - @media (max-width: 560px) { .button-container { - grid-template-columns: 1fr; + padding: 12px 16px 16px; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; } - } - .consent-button { - border-radius: calc(var(--radius) - 2px); - background: var(--secondary); - border: 1px solid var(--border); - padding: 8px 16px; - font-size: 0.85em; - font-weight: 500; - text-align: center; - cursor: pointer; - transition: all 0.15s ease; - color: var(--secondary-foreground); - } + @media (max-width: 560px) { + .button-container { + grid-template-columns: 1fr; + } + } - .consent-button:hover { - background: var(--accent); - border-color: var(--ring); - } + .consent-button { + border-radius: 6px; + background: ${cssManager.bdTheme(colors.light.secondary, colors.dark.secondary)}; + border: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)}; + padding: 8px 16px; + font-size: 0.85em; + font-weight: 500; + text-align: center; + cursor: pointer; + transition: all 0.15s ease; + color: ${cssManager.bdTheme(colors.light.secondaryForeground, colors.dark.secondaryForeground)}; + } - .consent-button:last-child { - background: var(--primary); - color: var(--primary-foreground); - border-color: var(--primary); - } + .consent-button:hover { + background: ${cssManager.bdTheme(colors.light.accent, colors.dark.accent)}; + border-color: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)}; + } - .consent-button:last-child:hover { - opacity: 0.9; - } + .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)}; + } - .info-container { - text-align: center; - padding: 10px 16px; - background: var(--muted); - border-top: 1px solid var(--border); - font-size: 0.75em; - color: var(--muted-foreground); - } + .consent-button:last-child:hover { + opacity: 0.9; + } - .info-container a { - color: var(--foreground); - text-decoration: none; - } + .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:hover { - text-decoration: underline; - } - `; + .info-container a { + color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)}; + text-decoration: none; + } + + .info-container a:hover { + text-decoration: underline; + } + `, + ]; constructor() { super(); @@ -278,18 +229,17 @@ export class ConsentsoftwareCookieconsent extends LitElement { /** * Lifecycle method called when the element is connected to the DOM. - * It sets up the theme and displays the consent banner if no cookie levels are set. + * Displays the consent banner if no cookie levels are set. */ public async connectedCallback() { - super.connectedCallback(); - this.updateTheme(); // Initialize theme based on system preference + await super.connectedCallback(); const cookieLevel = await this.csWebclientInstance.getCookieLevels(); if (!cookieLevel) { // Show consent banner if cookie levels haven't been set yet this.setAttribute('show', 'true'); requestAnimationFrame(async () => { - await this.updated(); + await this.updateComplete; const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay'); if (pageOverlay) { // Apply subtle backdrop blur when modal appears @@ -310,14 +260,7 @@ export class ConsentsoftwareCookieconsent extends LitElement { } public async firstUpdated() { - // Placeholder for any logic needed after first render - } - - /** - * Called after updates. Logs banner height and runs consent scripts if necessary. - */ - public async updated() { - console.log(`The height of the cookie banner is ${this.shadowRoot?.host?.clientHeight}px`); + // Run consent scripts if levels are already set const acceptedCookieLevels = await this.csWebclientInstance.getCookieLevels(); if (!this.csWebclientRan && acceptedCookieLevels) { this.csWebclientRan = true; @@ -327,7 +270,6 @@ export class ConsentsoftwareCookieconsent extends LitElement { /** * Handles consent button clicks, sets cookie levels, and hides the banner. - * Uses theme variables for styling transitions. */ private async handleConsentButtonClick( event: MouseEvent, @@ -349,7 +291,12 @@ export class ConsentsoftwareCookieconsent extends LitElement { await this.csWebclientInstance.setCookieLevels(levelsArg); await delayFor(300); this.setAttribute('show', 'false'); // Hide the consent banner - this.updated(); // Trigger any post-consent actions + + // Run consent scripts + if (!this.csWebclientRan) { + this.csWebclientRan = true; + await this.csWebclientInstance.getAndRunConsentTuples(); + } } /** @@ -369,19 +316,4 @@ export class ConsentsoftwareCookieconsent extends LitElement { } } } - - /** - * Dynamically switches the theme between light and dark. - * Listens for system theme changes to update the component's theme. - */ - private updateTheme() { - // Check the initial system preference for dark mode - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - this.theme = prefersDark ? 'dark' : 'light'; - - // Listen for changes in the system color scheme preference - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { - this.theme = e.matches ? 'dark' : 'light'; - }); - } } diff --git a/ts_web/elements/consentsoftware-header.ts b/ts_web/elements/consentsoftware-header.ts index f5cd8bf..29e0380 100644 --- a/ts_web/elements/consentsoftware-header.ts +++ b/ts_web/elements/consentsoftware-header.ts @@ -1,40 +1,42 @@ -import * as shared from './shared.js'; +import { cssManager, colors } 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 { + DeesElement, + customElement, + html, + css, + type TemplateResult, +} from '@design.estate/dees-element'; @customElement('consentsoftware-header') -export class ConsentsoftwareHeader extends LitElement { - public static demo = () => html``; +export class ConsentsoftwareHeader extends DeesElement { + public static demo = () => html``; - public static styles = css` - :host { - display: block; - padding: 14px 16px; - font-family: ${shared.fontStack}; - border-bottom: 1px solid var(--border, hsl(0 0% 18%)); - } + public static styles = [ + cssManager.defaultStyles, + css` + :host { + display: block; + padding: 14px 16px; + border-bottom: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)}; + } - .heading { - display: flex; - align-items: center; - gap: 8px; - font-size: 0.95em; - font-weight: 600; - color: var(--foreground, hsl(0 0% 95%)); - } + .heading { + display: flex; + align-items: center; + gap: 8px; + font-size: 0.95em; + font-weight: 600; + color: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)}; + } - .icon { - width: 18px; - height: 18px; - opacity: 0.7; - } - `; - - constructor() { - super(); - } + .icon { + width: 18px; + height: 18px; + opacity: 0.7; + } + `, + ]; public render(): TemplateResult { return html` @@ -48,4 +50,4 @@ export class ConsentsoftwareHeader extends LitElement { `; } -} \ No newline at end of file +} diff --git a/ts_web/elements/consentsoftware-mainselection.ts b/ts_web/elements/consentsoftware-mainselection.ts index 727574d..06c9bf8 100644 --- a/ts_web/elements/consentsoftware-mainselection.ts +++ b/ts_web/elements/consentsoftware-mainselection.ts @@ -1,9 +1,16 @@ -import { LitElement, html, css, type TemplateResult } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import { property } from 'lit/decorators/property.js'; +import { cssManager, colors } from './shared.js'; + +import { + DeesElement, + customElement, + html, + css, + type TemplateResult, + property, +} from '@design.estate/dees-element'; @customElement('consentsoftware-mainselection') -export class ConsentsoftwareMainSelection extends LitElement { +export class ConsentsoftwareMainSelection extends DeesElement { public static demo = () => html``; @property({ type: Boolean }) @@ -12,55 +19,54 @@ export class ConsentsoftwareMainSelection extends LitElement { @property({ type: Boolean }) public accessor selected = false; - public static styles = css` - :host { - display: block; - position: relative; - } + public static styles = [ + cssManager.defaultStyles, + css` + :host { + display: block; + position: relative; + } - .maincontainer { - display: grid; - grid-template-columns: repeat(4, 1fr); - padding: 8px 0; - } - - @media (max-width: 560px) { .maincontainer { - grid-template-columns: repeat(2, 1fr); - gap: 4px; + display: grid; + grid-template-columns: repeat(4, 1fr); + padding: 8px 0; } - } - .itemBox { - padding: 12px 8px; - text-align: center; - border-right: 1px solid var(--border, hsl(0 0% 18%)); - } + @media (max-width: 560px) { + .maincontainer { + grid-template-columns: repeat(2, 1fr); + gap: 4px; + } + } - .itemBox:last-child { - border-right: none; - } - - @media (max-width: 560px) { .itemBox { - padding: 10px 8px; + padding: 12px 8px; + text-align: center; + border-right: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)}; + } + + .itemBox:last-child { border-right: none; - border-bottom: 1px solid var(--border, hsl(0 0% 18%)); } - .itemBox:nth-child(odd) { - border-right: 1px solid var(--border, hsl(0 0% 18%)); - } + @media (max-width: 560px) { + .itemBox { + padding: 10px 8px; + border-right: none; + border-bottom: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)}; + } - .itemBox:nth-last-child(-n+2) { - border-bottom: none; - } - } - `; + .itemBox:nth-child(odd) { + border-right: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)}; + } - constructor() { - super(); - } + .itemBox:nth-last-child(-n+2) { + border-bottom: none; + } + } + `, + ]; public render(): TemplateResult { return html` @@ -81,5 +87,5 @@ export class ConsentsoftwareMainSelection extends LitElement { `; } - public async getResults(mouseEvent) {} + public async getResults() {} } diff --git a/ts_web/elements/consentsoftware-tabs.ts b/ts_web/elements/consentsoftware-tabs.ts index 8b14c03..088850a 100644 --- a/ts_web/elements/consentsoftware-tabs.ts +++ b/ts_web/elements/consentsoftware-tabs.ts @@ -1,59 +1,64 @@ -import { LitElement, html, css, type TemplateResult } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import { property } from 'lit/decorators/property.js'; +import { cssManager, colors } from './shared.js'; + +import { + DeesElement, + customElement, + html, + css, + type TemplateResult, +} from '@design.estate/dees-element'; @customElement('consentsoftware-tabs') -export class ConsentsoftwareTabs extends LitElement { +export class ConsentsoftwareTabs extends DeesElement { public static demo = () => html``; - public static styles = css` - :host { - display: block; - position: relative; - background: var(--muted, hsl(0 0% 15%)); - } - - .tabs { - display: grid; - grid-template-columns: repeat(3, 1fr); - } - - .tabs .tab { - text-align: center; - padding: 8px 0; - font-size: 0.8em; - font-weight: 500; - color: var(--muted-foreground, hsl(0 0% 64%)); - cursor: pointer; - transition: color 0.15s ease; - } - - .tabs .tab:hover { - color: var(--foreground, hsl(0 0% 95%)); - } - - @media (max-width: 560px) { - .tabs .tab { - font-size: 0.75em; - padding: 6px 0; + public static styles = [ + cssManager.defaultStyles, + css` + :host { + display: block; + position: relative; + background: ${cssManager.bdTheme(colors.light.muted, colors.dark.muted)}; } - } - .selector { - position: absolute; - width: calc(100% / 3); - height: 2px; - left: 0; - bottom: 0; - background: var(--foreground, hsl(0 0% 95%)); - transition: all 0.2s ease-out; - border-radius: 1px; - } - `; + .tabs { + display: grid; + grid-template-columns: repeat(3, 1fr); + } - constructor() { - super(); - } + .tabs .tab { + text-align: center; + padding: 8px 0; + font-size: 0.8em; + font-weight: 500; + color: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)}; + 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 { + position: absolute; + width: calc(100% / 3); + height: 2px; + left: 0; + bottom: 0; + background: ${cssManager.bdTheme(colors.light.foreground, colors.dark.foreground)}; + transition: all 0.2s ease-out; + border-radius: 1px; + } + `, + ]; public render(): TemplateResult { return html` @@ -66,7 +71,7 @@ export class ConsentsoftwareTabs extends LitElement { `; } - public async handleClick(mouseEvent) { + public async handleClick(mouseEvent: MouseEvent) { const target = mouseEvent.target as HTMLElement; const tab: HTMLDivElement = target.closest('.tab'); if (tab) { diff --git a/ts_web/elements/consentsoftware-toggle.ts b/ts_web/elements/consentsoftware-toggle.ts index 9953a2a..906045d 100644 --- a/ts_web/elements/consentsoftware-toggle.ts +++ b/ts_web/elements/consentsoftware-toggle.ts @@ -1,10 +1,18 @@ -import { LitElement, html, css, type TemplateResult } from 'lit'; -import { customElement } from 'lit/decorators.js'; -import { property } from 'lit/decorators/property.js'; +import { cssManager, colors } from './shared.js'; + +import { + DeesElement, + customElement, + html, + css, + type TemplateResult, + property, +} from '@design.estate/dees-element'; + import { delayFor } from '@push.rocks/smartdelay'; @customElement('consentsoftware-toggle') -export class ConsentsoftwareToggle extends LitElement { +export class ConsentsoftwareToggle extends DeesElement { @property({ type: Boolean }) public accessor required = false; @@ -25,96 +33,93 @@ export class ConsentsoftwareToggle extends LitElement { private hasDragged = false; private startX = 0; - // Toggle dimensions - private readonly trackWidth = 36; - private readonly trackHeight = 20; + // 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 = 3; // padding from track edge to knob - private readonly maxTravel = 16; // trackWidth - knobSize - (2 * padding) = 36 - 14 - 6 = 16 + 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 = css` - :host { - display: block; - position: relative; - } + public static styles = [ + cssManager.defaultStyles, + css` + :host { + display: block; + position: relative; + } - .label { - margin-bottom: 8px; - font-size: 0.8em; - font-weight: 500; - color: var(--muted-foreground, hsl(0 0% 64%)); - } + .label { + margin-bottom: 8px; + font-size: 0.8em; + font-weight: 500; + color: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)}; + } - .toggle { - user-select: none; - } + .toggle { + user-select: none; + } - .toggleKnobArea { - position: relative; - margin: auto; - height: 20px; - width: 36px; - border-radius: 10px; - background: var(--input, hsl(0 0% 15%)); - border: 1px solid var(--border, hsl(0 0% 18%)); - overflow: hidden; - transition: all 0.15s ease; - cursor: pointer; - } + .toggleKnobArea { + position: relative; + margin: auto; + height: 20px; + width: 36px; + border-radius: 10px; + background: ${cssManager.bdTheme(colors.light.input, colors.dark.input)}; + border: 1px solid ${cssManager.bdTheme(colors.light.border, colors.dark.border)}; + overflow: hidden; + transition: all 0.15s ease; + cursor: pointer; + } - .toggleKnobArea:hover { - border-color: var(--ring, hsl(0 0% 30%)); - } + .toggleKnobArea:hover { + border-color: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)}; + } - :host([selected]) .toggleKnobArea { - background: var(--primary, hsl(0 0% 98%)); - border-color: var(--primary, hsl(0 0% 98%)); - } + :host([selected]) .toggleKnobArea { + background: ${cssManager.bdTheme(colors.light.primary, colors.dark.primary)}; + border-color: ${cssManager.bdTheme(colors.light.primary, colors.dark.primary)}; + } - .toggleKnobMover { - position: relative; - height: 100%; - width: 100%; - } + .toggleKnobMover { + position: relative; + height: 100%; + width: 100%; + } - .toggleKnobInner { - position: absolute; - top: 3px; - width: 14px; - height: 14px; - border-radius: 7px; - background: var(--muted-foreground, hsl(0 0% 64%)); - transition: left 0.15s ease, background 0.15s ease; - touch-action: none; - } + .toggleKnobInner { + position: absolute; + top: 2px; + width: 14px; + height: 14px; + border-radius: 7px; + background: ${cssManager.bdTheme(colors.light.mutedForeground, colors.dark.mutedForeground)}; + transition: left 0.15s ease, background 0.15s ease; + touch-action: none; + } - .toggleKnobInner.dragging { - transition: background 0.15s ease; - } + .toggleKnobInner.dragging { + transition: background 0.15s ease; + } - :host([selected]) .toggleKnobInner { - background: var(--primary-foreground, hsl(0 0% 9%)); - } + :host([selected]) .toggleKnobInner { + background: ${cssManager.bdTheme(colors.light.primaryForeground, colors.dark.primaryForeground)}; + } - :host([required]) .toggleKnobArea { - background: var(--muted, hsl(0 0% 15%)); - border-color: var(--border, hsl(0 0% 18%)); - opacity: 0.6; - cursor: not-allowed; - } + :host([required]) .toggleKnobArea { + cursor: not-allowed; + } - :host([required]) .toggleKnobInner { - background: var(--muted-foreground, hsl(0 0% 45%)); - } + :host([required][selected]) .toggleKnobArea { + background: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)}; + border-color: ${cssManager.bdTheme(colors.light.ring, colors.dark.ring)}; + } - :host([required][selected]) .toggleKnobArea { - background: var(--muted-foreground, hsl(0 0% 45%)); - } - `; - - constructor() { - super(); - } + :host([required][selected]) .toggleKnobInner { + background: ${cssManager.bdTheme(colors.light.muted, colors.dark.muted)}; + } + `, + ]; public render(): TemplateResult { return html` @@ -141,7 +146,8 @@ export class ConsentsoftwareToggle extends LitElement { /** * If required = true on first render, auto-select and set the knob to the right. */ - public async firstUpdated() { + public async firstUpdated(_changedProperties: Map) { + await super.firstUpdated(_changedProperties); if (this.required) { this.selected = true; this.currentX = this.maxTravel; @@ -199,7 +205,7 @@ export class ConsentsoftwareToggle extends LitElement { // Start dragging 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; // capture pointer so we keep receiving pointermove/pointerup diff --git a/ts_web/elements/shared.ts b/ts_web/elements/shared.ts index 65b207c..cfa5457 100644 --- a/ts_web/elements/shared.ts +++ b/ts_web/elements/shared.ts @@ -1,3 +1,39 @@ -import { unsafeCSS } from 'lit' +import { unsafeCSS, cssManager } from '@design.estate/dees-element'; -export const fontStack = unsafeCSS('system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'); \ No newline at end of file +export { cssManager }; + +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', + }, +}; diff --git a/ts_web/pages/page1.ts b/ts_web/pages/page1.ts index 6c21652..883c15f 100644 --- a/ts_web/pages/page1.ts +++ b/ts_web/pages/page1.ts @@ -1,3 +1,3 @@ -import { html } from 'lit'; +import { html } from '@design.estate/dees-element'; export const page1 = () => html``; \ No newline at end of file