import { customElement, DeesElement, type TemplateResult, html, property, css, cssManager, } from '@design.estate/dees-element'; import { DeesIcon } from '@design.estate/dees-catalog'; import { demo } from './eco-applauncher-batterymenu.demo.js'; // Ensure dees-icon is registered DeesIcon; declare global { interface HTMLElementTagNameMap { 'eco-applauncher-batterymenu': EcoApplauncherBatterymenu; } } @customElement('eco-applauncher-batterymenu') export class EcoApplauncherBatterymenu extends DeesElement { public static demo = demo; public static demoGroup = 'App Launcher'; public static styles = [ cssManager.defaultStyles, css` :host { display: block; position: relative; } .menu-container { background: ${cssManager.bdTheme('#ffffff', 'hsl(240 6% 10%)')}; border: 1px solid ${cssManager.bdTheme('hsl(0 0% 90%)', 'hsl(240 5% 20%)')}; border-radius: 12px; box-shadow: ${cssManager.bdTheme( '0 8px 32px rgba(0, 0, 0, 0.15)', '0 8px 32px rgba(0, 0, 0, 0.4)' )}; min-width: 280px; overflow: hidden; opacity: 0; transform: scale(0.95) translateY(-8px); transition: all 0.2s ease-out; pointer-events: none; } :host([open]) .menu-container { opacity: 1; transform: scale(1) translateY(0); pointer-events: auto; } .battery-display { padding: 24px 16px; display: flex; flex-direction: column; align-items: center; gap: 12px; } .battery-visual { display: flex; align-items: center; gap: 8px; } .battery-icon { position: relative; width: 80px; height: 36px; border: 2px solid ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 70%)')}; border-radius: 6px; overflow: hidden; } .battery-icon::after { content: ''; position: absolute; right: -6px; top: 50%; transform: translateY(-50%); width: 4px; height: 14px; background: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 70%)')}; border-radius: 0 2px 2px 0; } .battery-fill { height: 100%; transition: width 0.3s ease, background 0.3s ease; } .battery-fill.good { background: hsl(142 71% 45%); } .battery-fill.medium { background: hsl(47 100% 50%); } .battery-fill.low { background: hsl(0 72% 51%); } .battery-fill.charging { background: linear-gradient( 90deg, hsl(142 71% 45%) 0%, hsl(142 71% 55%) 50%, hsl(142 71% 45%) 100% ); background-size: 200% 100%; animation: charging-pulse 1.5s ease-in-out infinite; } @keyframes charging-pulse { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } } .charging-icon { color: hsl(47 100% 50%); } .battery-percentage { font-size: 32px; font-weight: 600; color: ${cssManager.bdTheme('hsl(0 0% 10%)', 'hsl(0 0% 98%)')}; } .battery-status { font-size: 14px; color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 60%)')}; display: flex; align-items: center; gap: 6px; } .menu-divider { height: 1px; background: ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(240 5% 15%)')}; } .menu-option { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; cursor: pointer; transition: background 0.15s ease; } .menu-option:hover { background: ${cssManager.bdTheme('hsl(0 0% 96%)', 'hsl(240 5% 15%)')}; } .option-label { display: flex; align-items: center; gap: 10px; font-size: 14px; color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')}; } .option-description { font-size: 12px; color: ${cssManager.bdTheme('hsl(0 0% 60%)', 'hsl(0 0% 50%)')}; margin-top: 2px; } .toggle-switch { position: relative; width: 44px; height: 24px; background: ${cssManager.bdTheme('hsl(0 0% 85%)', 'hsl(240 5% 25%)')}; border-radius: 12px; cursor: pointer; transition: background 0.2s ease; flex-shrink: 0; } .toggle-switch.active { background: hsl(217 91% 60%); } .toggle-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: white; border-radius: 50%; transition: transform 0.2s ease; box-shadow: ${cssManager.bdTheme('0 1px 3px rgba(0,0,0,0.2)', 'none')}; } .toggle-switch.active::after { transform: translateX(20px); } .menu-footer { padding: 12px 16px; border-top: 1px solid ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(240 5% 15%)')}; } .settings-link { display: flex; align-items: center; gap: 8px; font-size: 14px; color: hsl(217 91% 60%); cursor: pointer; transition: color 0.15s ease; } .settings-link:hover { color: hsl(217 91% 50%); } `, ]; @property({ type: Boolean, reflect: true }) accessor open = false; @property({ type: Number }) accessor batteryLevel = 100; @property({ type: Boolean }) accessor isCharging = false; @property({ type: Boolean }) accessor batterySaverEnabled = false; @property({ type: String }) accessor timeRemaining: string | null = null; private boundHandleClickOutside = this.handleClickOutside.bind(this); public render(): TemplateResult { const fillClass = this.getFillClass(); return html` `; } private getFillClass(): string { if (this.batteryLevel > 50) return 'good'; if (this.batteryLevel > 20) return 'medium'; return 'low'; } private handleBatterySaverToggle(): void { this.batterySaverEnabled = !this.batterySaverEnabled; this.dispatchEvent(new CustomEvent('battery-saver-toggle', { detail: { enabled: this.batterySaverEnabled }, bubbles: true, composed: true, })); } private handleSettingsClick(): void { this.dispatchEvent(new CustomEvent('settings-click', { bubbles: true, composed: true, })); } private handleClickOutside(e: MouseEvent): void { if (this.open && !this.contains(e.target as Node)) { this.open = false; this.dispatchEvent(new CustomEvent('menu-close', { bubbles: true, composed: true, })); } } async connectedCallback(): Promise { await super.connectedCallback(); setTimeout(() => { document.addEventListener('click', this.boundHandleClickOutside); }, 0); } async disconnectedCallback(): Promise { await super.disconnectedCallback(); document.removeEventListener('click', this.boundHandleClickOutside); } }