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-soundmenu.demo.js'; // Ensure dees-icon is registered DeesIcon; declare global { interface HTMLElementTagNameMap { 'eco-applauncher-soundmenu': EcoApplauncherSoundmenu; } } export interface IAudioDevice { id: string; name: string; type: 'speaker' | 'headphones' | 'bluetooth' | 'hdmi'; active?: boolean; } @customElement('eco-applauncher-soundmenu') export class EcoApplauncherSoundmenu 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; } .menu-header { display: flex; align-items: center; justify-content: space-between; padding: 16px; border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(240 5% 15%)')}; } .menu-title { font-size: 15px; font-weight: 600; color: ${cssManager.bdTheme('hsl(0 0% 10%)', 'hsl(0 0% 98%)')}; display: flex; align-items: center; gap: 10px; } .volume-section { padding: 20px 16px; } .volume-slider-container { display: flex; align-items: center; gap: 12px; } .volume-icon { color: ${cssManager.bdTheme('hsl(0 0% 40%)', 'hsl(0 0% 70%)')}; cursor: pointer; transition: color 0.15s ease; } .volume-icon:hover { color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')}; } .volume-icon.muted { color: hsl(0 72% 51%); } .volume-slider { flex: 1; height: 6px; background: ${cssManager.bdTheme('hsl(0 0% 88%)', 'hsl(240 5% 20%)')}; border-radius: 3px; position: relative; cursor: pointer; } .volume-fill { height: 100%; background: hsl(217 91% 60%); border-radius: 3px; transition: width 0.1s ease; } .volume-fill.muted { background: ${cssManager.bdTheme('hsl(0 0% 70%)', 'hsl(0 0% 40%)')}; } .volume-thumb { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 16px; height: 16px; background: white; border-radius: 50%; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3); cursor: grab; } .volume-thumb:active { cursor: grabbing; } .volume-percentage { min-width: 36px; text-align: right; font-size: 14px; font-weight: 500; color: ${cssManager.bdTheme('hsl(0 0% 30%)', 'hsl(0 0% 80%)')}; } .menu-divider { height: 1px; background: ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(240 5% 15%)')}; } .section-title { padding: 12px 16px 8px; font-size: 12px; font-weight: 600; color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 50%)')}; text-transform: uppercase; letter-spacing: 0.5px; } .device-list { max-height: 160px; overflow-y: auto; } .device-item { display: flex; align-items: center; gap: 12px; padding: 10px 16px; cursor: pointer; transition: background 0.15s ease; } .device-item:hover { background: ${cssManager.bdTheme('hsl(0 0% 96%)', 'hsl(240 5% 15%)')}; } .device-item.active { background: ${cssManager.bdTheme('hsl(217 91% 95%)', 'hsl(217 91% 60% / 0.15)')}; } .device-item.active:hover { background: ${cssManager.bdTheme('hsl(217 91% 92%)', 'hsl(217 91% 60% / 0.25)')}; } .device-icon { color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 60%)')}; } .device-item.active .device-icon { color: hsl(217 91% 60%); } .device-name { flex: 1; font-size: 14px; color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')}; } .device-check { color: hsl(217 91% 60%); } .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 volume = 50; @property({ type: Boolean }) accessor muted = false; @property({ type: Array }) accessor outputDevices: IAudioDevice[] = []; @property({ type: String }) accessor activeDeviceId: string | null = null; private boundHandleClickOutside = this.handleClickOutside.bind(this); private isDragging = false; public render(): TemplateResult { const volumeIcon = this.getVolumeIcon(); return html`
`; } private renderDeviceItem(device: IAudioDevice): TemplateResult { const isActive = device.id === this.activeDeviceId; const icon = this.getDeviceIcon(device.type); return html`