✨ 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.
216 lines
6.4 KiB
TypeScript
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,
|
|
}),
|
|
);
|
|
}
|
|
}
|