diff --git a/ts_web/elements/consentsoftware-cookieconsent.ts b/ts_web/elements/consentsoftware-cookieconsent.ts index e045069..964fdb5 100644 --- a/ts_web/elements/consentsoftware-cookieconsent.ts +++ b/ts_web/elements/consentsoftware-cookieconsent.ts @@ -33,191 +33,192 @@ export class ConsentsoftwareCookieconsent extends LitElement { public static styles = css` :host { font-family: ${shared.fontStack}; + font-size: 14px; user-select: none; - /* Default variables for Light Theme */ - --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; - /* Additional variables for modal and info container styling */ - --info-bg: rgba(0, 0, 0, 0.1); - --info-text: rgba(255, 255, 255, 0.5); - --modal-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.2); + /* 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; } - /* Dark Theme Overrides: - When theme attribute is 'dark', override variables accordingly. */ :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; - --info-bg: rgba(0, 0, 0, 0.1); - --info-text: rgba(255, 255, 255, 0.5); - --modal-box-shadow: 0px 0px 8px rgba(255, 255, 255, 0.6); + --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%); } - /* Light Theme Overrides: - Explicit light theme settings, currently matching defaults. - Can be customized independently if desired. */ :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; - --info-bg: rgba(0, 0, 0, 0.1); - --info-text: rgba(0, 0, 0, 0.5); - --modal-box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.2); + --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%); } - /* Overlay covering the page behind the modal */ .pageOverlay { position: fixed; - top: 0; - bottom: 0; - right: 0; - left: 0; + inset: 0; display: grid; align-items: center; justify-content: center; - z-index: 1000; /* Ensures the overlay is on top of other elements */ - background: rgba(255, 255, 255, 0); + z-index: 1000; + background: rgba(0, 0, 0, 0); backdrop-filter: blur(0px); - transition: all 0.2s; + transition: all 0.2s ease-out; } - /* Shake animation for overlay when clicked */ .pageOverlay.shake { - background: rgba(0, 0, 0, 0.5) !important; + background: rgba(0, 0, 0, 0.6) !important; } - /* Modal box styling using theme variables for colors and shadows */ .modalBox { display: block; - color: var(--text-color); - background: var(--background-color); - box-shadow: var(--modal-box-shadow); + 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: 1px dotted rgba(255, 255, 255, 0.1); - border-top: 1px solid var(--accent-color); - border-radius: 16px; - max-width: 1100px; - min-width: calc(100vw / 3); + border-radius: var(--radius); + max-width: 520px; + min-width: 320px; box-sizing: border-box; overflow: hidden; will-change: transform; - transition: all 0.3s; - transform: scale(0.95); + transition: all 0.2s ease-out; + transform: scale(0.96); opacity: 0; } - /* Media query for mobile devices: stack buttons vertically */ - @media (max-width: 600px) { + @media (max-width: 560px) { .modalBox { + max-width: 100%; + min-width: 100%; height: 100vh; - box-shadow: none; - border-radius: 0px; + border-radius: 0; } } - /* Shake animation for modal box */ .modalBox.shake { - animation: shake 150ms 2 linear; + animation: shake 120ms 2 linear; } @keyframes shake { - 0% { - transform: translate(3px, 0); - } - 50% { - transform: translate(-3px, 0); - } - 100% { - transform: translate(0, 0); - } + 0% { transform: translateX(3px); } + 50% { transform: translateX(-3px); } + 100% { transform: translateX(0); } } - /* Toggle display based on [show] attribute */ - :host([show='false']) { - display: none; - } - :host([show='true']) { - display: block; - } + :host([show='false']) { display: none; } + :host([show='true']) { display: block; } .content { margin: auto; } .text-container { - padding-left: var(--padding-sides); - padding-right: var(--padding-sides); - display: grid; - grid-template-columns: auto; + padding: 12px 16px; + font-size: 0.9em; + line-height: 1.5; + color: var(--muted-foreground); } .text-container a { - color: var(--link-color); - text-decoration: none; + color: var(--foreground); + text-decoration: underline; + text-underline-offset: 2px; + } + + .text-container a:hover { + opacity: 0.8; } .button-container { - padding: var(--padding-sides); + padding: 12px 16px 16px; display: grid; grid-template-columns: repeat(3, 1fr); - gap: 16px; + gap: 8px; } - /* Media query for mobile devices: stack buttons vertically */ - @media (max-width: 600px) { + @media (max-width: 560px) { .button-container { grid-template-columns: 1fr; } } - /* Consent button styling using theme variables */ .consent-button { - border-radius: 3px; - background: var(--button-bg); - box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2); - padding: 10px; - line-height: 30px; + 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.2s; + transition: all 0.15s ease; + color: var(--secondary-foreground); } .consent-button:hover { - background: var(--button-hover-bg); + background: var(--accent); + border-color: var(--ring); + } + + .consent-button:last-child { + background: var(--primary); + color: var(--primary-foreground); + border-color: var(--primary); + } + + .consent-button:last-child:hover { + opacity: 0.9; } - /* Use theme variables for info container background and text */ .info-container { text-align: center; - line-height: 3em; - background: var(--info-bg); - border-top: 1px dotted rgba(255, 255, 255, 0.1); - font-size: 0.8em; - color: var(--info-text); + padding: 10px 16px; + background: var(--muted); + border-top: 1px solid var(--border); + font-size: 0.75em; + color: var(--muted-foreground); } .info-container a { - text-decoration: underline; - color: var(--link-color); - transition: color 0.2s; + color: var(--foreground); + text-decoration: none; } + .info-container a:hover { - color: #ffffff; + text-decoration: underline; } `; @@ -234,11 +235,11 @@ export class ConsentsoftwareCookieconsent extends LitElement {
-
+
- This page uses cookies. Please review our + We use cookies to enhance your experience. Review our cookie policy - and choose which cookie level you are willing to accept. + and select your preferences.
@@ -291,9 +292,9 @@ export class ConsentsoftwareCookieconsent extends LitElement { await this.updated(); const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay'); if (pageOverlay) { - // Apply dark overlay styling when modal appears - pageOverlay.style.background = 'rgba(0,0,0, 0.5)'; - pageOverlay.style.backdropFilter = 'blur(20px)'; + // Apply subtle backdrop blur when modal appears + pageOverlay.style.background = 'rgba(0,0,0, 0.6)'; + pageOverlay.style.backdropFilter = 'blur(4px)'; } const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox'); if (modalBox) { @@ -335,8 +336,7 @@ export class ConsentsoftwareCookieconsent extends LitElement { console.log(`Set level to ${levelsArg}`); const pageOverlay: HTMLDivElement = this.shadowRoot?.querySelector('.pageOverlay'); if (pageOverlay) { - // Fade out overlay effect using inline styles for transition - pageOverlay.style.background = 'rgba(255,255,255, 0)'; + pageOverlay.style.background = 'rgba(0,0,0, 0)'; pageOverlay.style.backdropFilter = 'blur(0px)'; } const modalBox: HTMLDivElement = this.shadowRoot?.querySelector('.modalBox'); diff --git a/ts_web/elements/consentsoftware-header.ts b/ts_web/elements/consentsoftware-header.ts index 7d285c1..f5cd8bf 100644 --- a/ts_web/elements/consentsoftware-header.ts +++ b/ts_web/elements/consentsoftware-header.ts @@ -11,14 +11,24 @@ export class ConsentsoftwareHeader extends LitElement { public static styles = css` :host { display: block; - line-height: 3em; - text-align: center; + padding: 14px 16px; font-family: ${shared.fontStack}; - border-bottom: 1px dotted rgba(255, 255, 255, 0.1); + border-bottom: 1px solid var(--border, hsl(0 0% 18%)); } .heading { - + display: flex; + align-items: center; + gap: 8px; + font-size: 0.95em; + font-weight: 600; + color: var(--foreground, hsl(0 0% 95%)); + } + + .icon { + width: 18px; + height: 18px; + opacity: 0.7; } `; @@ -29,7 +39,12 @@ export class ConsentsoftwareHeader extends LitElement { public render(): TemplateResult { return html`
- What about cookies? + + + + + + Cookie Preferences
`; } diff --git a/ts_web/elements/consentsoftware-mainselection.ts b/ts_web/elements/consentsoftware-mainselection.ts index a0e94b8..727574d 100644 --- a/ts_web/elements/consentsoftware-mainselection.ts +++ b/ts_web/elements/consentsoftware-mainselection.ts @@ -21,17 +21,41 @@ export class ConsentsoftwareMainSelection extends LitElement { .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; + } } .itemBox { - padding: 16px; + padding: 12px 8px; text-align: center; - border-right: 1px solid; - border-image: radial-gradient(circle, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%) 1; + border-right: 1px solid var(--border, hsl(0 0% 18%)); } + .itemBox:last-child { border-right: none; } + + @media (max-width: 560px) { + .itemBox { + padding: 10px 8px; + 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%)); + } + + .itemBox:nth-last-child(-n+2) { + border-bottom: none; + } + } `; constructor() { diff --git a/ts_web/elements/consentsoftware-tabs.ts b/ts_web/elements/consentsoftware-tabs.ts index 193c296..8b14c03 100644 --- a/ts_web/elements/consentsoftware-tabs.ts +++ b/ts_web/elements/consentsoftware-tabs.ts @@ -10,7 +10,7 @@ export class ConsentsoftwareTabs extends LitElement { :host { display: block; position: relative; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); + background: var(--muted, hsl(0 0% 15%)); } .tabs { @@ -20,25 +20,34 @@ export class ConsentsoftwareTabs extends LitElement { .tabs .tab { text-align: center; - line-height: 3em; + 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; } - /* Media query for mobile devices: stack buttons vertically */ - @media (max-width: 600px) { + .tabs .tab:hover { + color: var(--foreground, hsl(0 0% 95%)); + } + + @media (max-width: 560px) { .tabs .tab { - font-size: 0.8em; + font-size: 0.75em; + padding: 6px 0; } } .selector { position: absolute; width: calc(100% / 3); - height: 1px; + height: 2px; left: 0; - bottom: 0px; - background: orange; - transition: all 0.2s; + bottom: 0; + background: var(--foreground, hsl(0 0% 95%)); + transition: all 0.2s ease-out; + border-radius: 1px; } `; diff --git a/ts_web/elements/consentsoftware-toggle.ts b/ts_web/elements/consentsoftware-toggle.ts index 498df5c..9953a2a 100644 --- a/ts_web/elements/consentsoftware-toggle.ts +++ b/ts_web/elements/consentsoftware-toggle.ts @@ -12,9 +12,9 @@ export class ConsentsoftwareToggle extends LitElement { public accessor selected = false; /** - * We always track the knob’s left offset in `currentX`. - * - 0 => fully left - * - 30 => fully right + * Knob position tracking (0 = off, maxTravel = on) + * This is the travel distance, not absolute left position. + * Actual left = padding + currentX */ private currentX = 0; @@ -23,9 +23,14 @@ export class ConsentsoftwareToggle extends LitElement { */ private isDragging = false; private hasDragged = false; - private startX = 0; // pointerdown offset - private readonly knobWidth = 30; - private readonly trackWidth = 60; + private startX = 0; + + // Toggle dimensions + private readonly trackWidth = 36; + private readonly trackHeight = 20; + 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 public static styles = css` :host { @@ -34,28 +39,36 @@ export class ConsentsoftwareToggle extends LitElement { } .label { - margin-bottom: 16px; + margin-bottom: 8px; + font-size: 0.8em; + font-weight: 500; + color: var(--muted-foreground, hsl(0 0% 64%)); } .toggle { - user-select: none; /* helps avoid text selection on drag */ + user-select: none; } .toggleKnobArea { position: relative; margin: auto; - height: 30px; - width: 60px; - border-radius: 20px; - background: rgba(255, 255, 255, 0.1); - border: 1px solid rgba(255, 255, 255, 0); + 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: background 0.2s ease; + transition: all 0.15s ease; cursor: pointer; } + .toggleKnobArea:hover { + border-color: var(--ring, hsl(0 0% 30%)); + } + :host([selected]) .toggleKnobArea { - background: green; + background: var(--primary, hsl(0 0% 98%)); + border-color: var(--primary, hsl(0 0% 98%)); } .toggleKnobMover { @@ -66,33 +79,36 @@ export class ConsentsoftwareToggle extends LitElement { .toggleKnobInner { position: absolute; - top: 0; - left: 0; - width: 30px; - height: 30px; - border-radius: 15px; - background: rgba(255, 255, 255, 0.5); - transition: left 0.2s ease, background 0.2s ease; - transform: scale(0.7); - /* Prevent scroll gestures on mobile */ + 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.dragging { - transition: background 0.2s ease; + transition: background 0.15s ease; } :host([selected]) .toggleKnobInner { - background: white; + background: var(--primary-foreground, hsl(0 0% 9%)); } :host([required]) .toggleKnobArea { - background: none; - border: 1px solid rgba(255, 255, 255, 0.1); + background: var(--muted, hsl(0 0% 15%)); + border-color: var(--border, hsl(0 0% 18%)); + opacity: 0.6; + cursor: not-allowed; } :host([required]) .toggleKnobInner { - background: rgba(255, 255, 255, 0.1); + background: var(--muted-foreground, hsl(0 0% 45%)); + } + + :host([required][selected]) .toggleKnobArea { + background: var(--muted-foreground, hsl(0 0% 45%)); } `; @@ -110,7 +126,7 @@ export class ConsentsoftwareToggle extends LitElement {
always selected this.selected = true; - this.currentX = this.knobWidth; // 30 + this.currentX = this.maxTravel; this.requestUpdate(); } else { - // If not required, set knob to 0 or 30 depending on `selected` - this.currentX = this.selected ? this.knobWidth : 0; + this.currentX = this.selected ? this.maxTravel : 0; this.requestUpdate(); } } @@ -142,7 +156,6 @@ export class ConsentsoftwareToggle extends LitElement { * CLICK HANDLER */ public async handleClick(event: MouseEvent) { - // If the user truly dragged the knob, skip the normal click toggle. if (this.isDragging || this.hasDragged) { event.stopPropagation(); event.preventDefault(); @@ -150,26 +163,23 @@ export class ConsentsoftwareToggle extends LitElement { } if (this.required) { - // small bounce from 30 -> 20 -> 30 - this.currentX = this.knobWidth; // ensure at 30 + // Small bounce animation for required toggles + this.currentX = this.maxTravel; this.requestUpdate(); await new Promise((r) => setTimeout(r, 10)); - - this.currentX = 20; // small bounce left + this.currentX = this.maxTravel - 3; this.requestUpdate(); - await delayFor(200); - - this.currentX = this.knobWidth; // back to 30 + await delayFor(150); + this.currentX = this.maxTravel; this.requestUpdate(); return; } - // Normal toggle if no drag & not required event.stopPropagation(); event.preventDefault(); 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.dispatchEvent(new CustomEvent('toggle', { detail: { selected: this.selected } })); @@ -203,8 +213,8 @@ export class ConsentsoftwareToggle extends LitElement { const toggleKnobInner: HTMLDivElement = this.shadowRoot.querySelector('.toggleKnobInner'); toggleKnobInner.classList.add('dragging'); - // Clamp - this.currentX = Math.max(0, Math.min(newX, this.trackWidth - this.knobWidth)); + // Clamp to valid travel range (0 to maxTravel) + this.currentX = Math.max(0, Math.min(newX, this.maxTravel)); this.requestUpdate(); } @@ -213,17 +223,17 @@ export class ConsentsoftwareToggle extends LitElement { (event.target as HTMLElement).releasePointerCapture(event.pointerId); 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) { return; } const toggleKnobInner: HTMLDivElement = this.shadowRoot.querySelector('.toggleKnobInner'); toggleKnobInner.classList.remove('dragging'); - // Real drag => decide final side - const midpoint = (this.trackWidth - this.knobWidth) / 2; // 15 + // Real drag => decide final side based on midpoint + const midpoint = this.maxTravel / 2; 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(); // Dispatch toggle event @@ -243,7 +253,7 @@ export class ConsentsoftwareToggle extends LitElement { !this.hasDragged && !this.required ) { - this.currentX = this.selected ? this.knobWidth : 0; + this.currentX = this.selected ? this.maxTravel : 0; this.requestUpdate(); } super.updated(changedProperties);