Eve/src/components/General/Toggle.ts
Danny Morabito dc9abee715
🎨 🚀 Overhaul UI/UX with comprehensive design system improvements
 Features added:

- 🔍 Implement functional search in header navigation
- ⚙️ Add basic user settings page
- 📱 Make dashboard fully responsive

🔧 Enhancements:

- 🎭 Standardize CSS with consistent theming across components
- 🧹 Remove unused CSS for better performance
- 📊 Improve dashboard layout and visual hierarchy
- 📦 Redesign last block widget for better usability

💅 This commit introduces a cohesive design system with functional design-token components for a more  polished user experience.
2025-03-20 09:46:47 +01:00

216 lines
6.4 KiB
TypeScript

import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js';
@customElement('arx-toggle')
export class StyledToggle extends LitElement {
@property() label = '';
@property({ type: Boolean, reflect: true }) checked = false;
@property({ type: Boolean }) disabled = false;
@property() name = '';
@property({ type: Boolean }) required = false;
@property() value = 'on';
static override styles = css`
:host {
display: inline-block;
width: 100%;
margin-bottom: 8px;
}
.toggle-container {
display: flex;
align-items: center;
gap: 12px;
}
label {
font-size: 14px;
color: var(--color-base-content);
font-weight: 500;
cursor: pointer;
}
.toggle-wrapper {
position: relative;
display: inline-block;
width: 48px;
height: 24px;
}
.toggle-input {
opacity: 0;
width: 0;
height: 0;
position: absolute;
}
.toggle-track {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--color-base-100);
border-radius: 24px;
transition: all 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
border: var(--border) solid var(--color-base-300);
box-shadow: inset calc(var(--depth) * 2px) calc(var(--depth) * 2px)
calc(var(--depth) * 4px)
oklch(from var(--color-base-content) l c h / 0.15),
inset calc(var(--depth) * -2px) calc(var(--depth) * -2px)
calc(var(--depth) * 4px) oklch(from var(--color-base-100) l c h / 0.7);
}
.toggle-track:hover {
background-color: oklch(from var(--color-base-100) calc(l + 0.02) c h);
}
.toggle-knob {
position: absolute;
height: 18px;
width: 18px;
left: 3px;
bottom: 2px;
background-color: var(--color-base-content);
border-radius: 50%;
transition: all 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
box-shadow: calc(var(--depth) * 2px) calc(var(--depth) * 2px)
calc(var(--depth) * 4px)
oklch(from var(--color-base-content) l c h / 0.2),
calc(var(--depth) * -1px) calc(var(--depth) * -1px)
calc(var(--depth) * 3px) oklch(from var(--color-base-100) l c h / 0.3);
}
.toggle-input:checked + .toggle-track {
background-color: var(--color-base-100);
border-top: var(--border) solid
oklch(from var(--color-base-300) l c h / 0.8);
border-left: var(--border) solid
oklch(from var(--color-base-300) l c h / 0.8);
border-bottom: var(--border) solid
oklch(from var(--color-base-200) l c h / 0.8);
border-right: var(--border) solid
oklch(from var(--color-base-200) l c h / 0.8);
box-shadow: inset calc(var(--depth) * 3px) calc(var(--depth) * 3px)
calc(var(--depth) * 5px)
oklch(from var(--color-base-content) l c h / 0.2),
inset calc(var(--depth) * -1px) calc(var(--depth) * -1px)
calc(var(--depth) * 3px) oklch(from var(--color-base-100) l c h / 0.5);
}
.toggle-input:checked + .toggle-track .toggle-knob {
transform: translateX(24px);
background-color: var(--color-accent);
}
.toggle-input:focus + .toggle-track {
outline: none;
box-shadow: inset calc(var(--depth) * 3px) calc(var(--depth) * 3px)
calc(var(--depth) * 5px)
oklch(from var(--color-base-content) l c h / 0.2),
inset calc(var(--depth) * -1px) calc(var(--depth) * -1px)
calc(var(--depth) * 3px) oklch(from var(--color-base-100) l c h / 0.5),
0 0 0 2px oklch(from var(--color-accent) l c h / 0.3);
}
.toggle-input:disabled + .toggle-track {
opacity: 0.7;
cursor: not-allowed;
box-shadow: inset calc(var(--depth) * 1px) calc(var(--depth) * 1px)
calc(var(--depth) * 2px)
oklch(from var(--color-base-content) l c h / 0.05),
inset calc(var(--depth) * -1px) calc(var(--depth) * -1px)
calc(var(--depth) * 2px) oklch(from var(--color-base-100) l c h / 0.4);
}
.toggle-input:disabled + .toggle-track .toggle-knob {
background-color: var(--color-secondary);
box-shadow: calc(var(--depth) * 1px) calc(var(--depth) * 1px)
calc(var(--depth) * 2px)
oklch(from var(--color-base-content) l c h / 0.1),
calc(var(--depth) * -1px) calc(var(--depth) * -1px)
calc(var(--depth) * 2px) oklch(from var(--color-base-100) l c h / 0.2);
}
`;
override render() {
return html`
<div class="toggle-container">
${when(this.label, () => html` <label for="toggle-${this.name}">${this.label}</label> `)}
<div class="toggle-wrapper">
<input
type="checkbox"
id="toggle-${this.name}"
class="toggle-input"
.checked=${this.checked}
?disabled=${this.disabled}
?required=${this.required}
name=${this.name}
value=${this.value}
@change=${this._handleChange}
@focus=${this._handleFocus}
@blur=${this._handleBlur}
@keydown=${this._handleKeyDown}
/>
<label for="toggle-${this.name}" class="toggle-track">
<span class="toggle-knob"></span>
</label>
</div>
</div>
`;
}
private _handleChange(e: Event) {
const checkbox = e.target as HTMLInputElement;
this.checked = checkbox.checked;
this.dispatchEvent(
new CustomEvent('change', {
detail: { checked: this.checked, value: this.value },
bubbles: true,
composed: true,
}),
);
}
private _handleFocus() {
this.dispatchEvent(
new CustomEvent('focus', {
bubbles: true,
composed: true,
}),
);
}
private _handleBlur() {
this.dispatchEvent(
new CustomEvent('blur', {
bubbles: true,
composed: true,
}),
);
}
private _handleKeyDown(e: KeyboardEvent) {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
this.checked = !this.checked;
this.dispatchEvent(
new CustomEvent('change', {
detail: { checked: this.checked, value: this.value },
bubbles: true,
composed: true,
}),
);
}
this.dispatchEvent(
new CustomEvent('keydown', {
detail: { key: e.key },
bubbles: true,
composed: true,
}),
);
}
}