This commit is contained in:
2026-01-12 10:57:54 +00:00
parent c55cd25a88
commit 72900086cd
63 changed files with 3963 additions and 5078 deletions

View File

@@ -0,0 +1,20 @@
import { html } from '@design.estate/dees-element';
export const demo = () => html`
<style>
.demo-container {
padding: 48px;
background: hsl(240 10% 4%);
min-height: 300px;
display: flex;
justify-content: center;
}
</style>
<div class="demo-container">
<eco-applauncher-powermenu
open
@power-action=${(e: CustomEvent) => console.log('Power action:', e.detail.action)}
@menu-close=${() => console.log('Menu closed')}
></eco-applauncher-powermenu>
</div>
`;

View File

@@ -0,0 +1,261 @@
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-powermenu.demo.js';
// Ensure dees-icon is registered
DeesIcon;
declare global {
interface HTMLElementTagNameMap {
'eco-applauncher-powermenu': EcoApplauncherPowermenu;
}
}
export type TPowerAction = 'lock' | 'lock-sleep' | 'reboot';
@customElement('eco-applauncher-powermenu')
export class EcoApplauncherPowermenu extends DeesElement {
public static demo = demo;
public static demoGroup = 'App Launcher';
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
position: relative;
pointer-events: none;
}
:host([open]) {
pointer-events: auto;
}
.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: 200px;
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 {
padding: 12px 16px;
border-bottom: 1px solid ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(240 5% 15%)')};
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: ${cssManager.bdTheme('hsl(0 0% 50%)', 'hsl(0 0% 60%)')};
}
.menu-options {
padding: 8px 0;
}
.menu-option {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
cursor: pointer;
transition: background 0.15s ease;
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
}
.menu-option:hover {
background: ${cssManager.bdTheme('hsl(0 0% 96%)', 'hsl(240 5% 15%)')};
}
.menu-option:active {
background: ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(240 5% 18%)')};
}
.menu-option.danger {
color: ${cssManager.bdTheme('hsl(0 72% 45%)', 'hsl(0 72% 60%)')};
}
.menu-option.danger:hover {
background: ${cssManager.bdTheme('hsl(0 72% 97%)', 'hsl(0 50% 15%)')};
}
.option-icon {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 6px;
background: ${cssManager.bdTheme('hsl(0 0% 94%)', 'hsl(240 5% 18%)')};
}
.menu-option.danger .option-icon {
background: ${cssManager.bdTheme('hsl(0 72% 94%)', 'hsl(0 50% 18%)')};
}
.option-text {
display: flex;
flex-direction: column;
gap: 2px;
}
.option-label {
font-size: 14px;
font-weight: 500;
}
.option-description {
font-size: 11px;
color: ${cssManager.bdTheme('hsl(0 0% 55%)', 'hsl(0 0% 50%)')};
}
.menu-divider {
height: 1px;
background: ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(240 5% 15%)')};
margin: 4px 0;
}
`,
];
@property({ type: Boolean, reflect: true })
accessor open = false;
private boundHandleClickOutside = this.handleClickOutside.bind(this);
private inactivityTimeout: ReturnType<typeof setTimeout> | null = null;
private readonly INACTIVITY_TIMEOUT = 60000; // 1 minute
private lastActivityTime = 0;
public render(): TemplateResult {
return html`
<div class="menu-container"
@click=${(e: MouseEvent) => e.stopPropagation()}
@mousedown=${this.resetInactivityTimer}
>
<div class="menu-header">Power</div>
<div class="menu-options">
<div class="menu-option" @click=${() => this.handleAction('lock')}>
<div class="option-icon">
<dees-icon .icon=${'lucide:lock'} .iconSize=${16}></dees-icon>
</div>
<div class="option-text">
<span class="option-label">Lock</span>
<span class="option-description">Lock the screen</span>
</div>
</div>
<div class="menu-option" @click=${() => this.handleAction('lock-sleep')}>
<div class="option-icon">
<dees-icon .icon=${'lucide:moon'} .iconSize=${16}></dees-icon>
</div>
<div class="option-text">
<span class="option-label">Lock + Sleep</span>
<span class="option-description">Lock and turn off display</span>
</div>
</div>
<div class="menu-divider"></div>
<div class="menu-option danger" @click=${() => this.handleAction('reboot')}>
<div class="option-icon">
<dees-icon .icon=${'lucide:refreshCw'} .iconSize=${16}></dees-icon>
</div>
<div class="option-text">
<span class="option-label">Reboot</span>
<span class="option-description">Restart the system</span>
</div>
</div>
</div>
</div>
`;
}
private handleAction(action: TPowerAction): void {
this.dispatchEvent(new CustomEvent('power-action', {
detail: { action },
bubbles: true,
composed: true,
}));
this.closeMenu();
}
private handleClickOutside(e: MouseEvent): void {
if (this.open && !this.contains(e.target as Node)) {
this.closeMenu();
}
}
private resetInactivityTimer(): void {
const now = Date.now();
// Throttle: only reset if 5+ seconds since last reset
if (now - this.lastActivityTime < 5000) {
return;
}
this.lastActivityTime = now;
this.clearInactivityTimer();
if (this.open) {
this.inactivityTimeout = setTimeout(() => {
this.closeMenu();
}, this.INACTIVITY_TIMEOUT);
}
}
private clearInactivityTimer(): void {
if (this.inactivityTimeout) {
clearTimeout(this.inactivityTimeout);
this.inactivityTimeout = null;
}
}
private closeMenu(): void {
this.open = false;
this.dispatchEvent(new CustomEvent('menu-close', {
bubbles: true,
composed: true,
}));
}
protected updated(changedProperties: Map<string, unknown>): void {
if (changedProperties.has('open')) {
if (this.open) {
this.resetInactivityTimer();
} else {
this.clearInactivityTimer();
}
}
}
async connectedCallback(): Promise<void> {
await super.connectedCallback();
setTimeout(() => {
document.addEventListener('click', this.boundHandleClickOutside);
}, 0);
}
async disconnectedCallback(): Promise<void> {
await super.disconnectedCallback();
document.removeEventListener('click', this.boundHandleClickOutside);
this.clearInactivityTimer();
}
}

View File

@@ -0,0 +1 @@
export * from './eco-applauncher-powermenu.js';

View File

@@ -1,21 +1,18 @@
import { html } from '@design.estate/dees-element';
import type { IAppIcon } from './eco-applauncher.js';
import type { IAppIcon, ILoginConfig, ILoginCredentials, TApplauncherMode } from './eco-applauncher.js';
import type { IWifiNetwork } from '../eco-applauncher-wifimenu/index.js';
import type { IAudioDevice } from '../eco-applauncher-soundmenu/index.js';
import '../../../views/eco-view-settings/eco-view-settings.js';
import '../../../views/eco-view-peripherals/eco-view-peripherals.js';
import '../../../views/eco-view-saasshare/eco-view-saasshare.js';
import '../../../views/eco-view-system/eco-view-system.js';
import type { EcoApplauncher } from './eco-applauncher.js';
const mockApps: IAppIcon[] = [
{ name: 'Settings', icon: 'lucide:settings', action: () => console.log('Settings clicked') },
{ name: 'Browser', icon: 'lucide:globe', action: () => console.log('Browser clicked') },
{ name: 'Terminal', icon: 'lucide:terminal', action: () => console.log('Terminal clicked') },
{ name: 'Files', icon: 'lucide:folder', action: () => console.log('Files clicked') },
{ name: 'Calendar', icon: 'lucide:calendar', action: () => console.log('Calendar clicked') },
{ name: 'Mail', icon: 'lucide:mail', action: () => console.log('Mail clicked') },
{ name: 'Music', icon: 'lucide:music', action: () => console.log('Music clicked') },
{ name: 'Photos', icon: 'lucide:image', action: () => console.log('Photos clicked') },
{ name: 'Notes', icon: 'lucide:fileText', action: () => console.log('Notes clicked') },
{ name: 'Calculator', icon: 'lucide:calculator', action: () => console.log('Calculator clicked') },
{ name: 'Weather', icon: 'lucide:cloudSun', action: () => console.log('Weather clicked') },
{ name: 'Maps', icon: 'lucide:map', action: () => console.log('Maps clicked') },
{ name: 'SaaS Share', icon: 'lucide:share2', view: html`<eco-view-saasshare></eco-view-saasshare>` },
{ name: 'System', icon: 'lucide:activity', view: html`<eco-view-system></eco-view-system>` },
{ name: 'Peripherals', icon: 'lucide:monitor', view: html`<eco-view-peripherals></eco-view-peripherals>` },
{ name: 'Settings', icon: 'lucide:settings', view: html`<eco-view-settings></eco-view-settings>` },
];
const mockNetworks: IWifiNetwork[] = [
@@ -32,7 +29,33 @@ const mockAudioDevices: IAudioDevice[] = [
{ id: 'hdmi', name: 'LG Monitor', type: 'hdmi' },
];
export const demo = () => html`
const loginConfig: ILoginConfig = {
allowedMethods: ['pin', 'password', 'qr'],
pinLength: 4,
welcomeMessage: 'Welcome to EcoBridge',
};
const handleLoginAttempt = (e: CustomEvent) => {
const credentials = e.detail as ILoginCredentials;
const applauncher = e.target as EcoApplauncher;
console.log('Login attempt:', credentials);
// Demo validation: PIN "1234" or password "demo"
if (
(credentials.method === 'pin' && credentials.value === '1234') ||
(credentials.method === 'password' && credentials.value === 'demo')
) {
console.log('Login successful!');
applauncher.setLoginResult(true);
} else {
console.log('Login failed');
applauncher.setLoginResult(false, 'Invalid credentials. Try PIN: 1234 or Password: demo');
}
};
// Home mode demo
const demoHome = () => html`
<style>
.demo-container {
width: 100%;
@@ -41,6 +64,8 @@ export const demo = () => html`
</style>
<div class="demo-container">
<eco-applauncher
.mode=${'home' as TApplauncherMode}
.loginConfig=${loginConfig}
.apps=${mockApps}
.batteryLevel=${85}
.networkStatus=${'online'}
@@ -54,6 +79,9 @@ export const demo = () => html`
.muted=${false}
.userName=${'John Doe'}
.notificationCount=${3}
@login-attempt=${handleLoginAttempt}
@login-success=${() => console.log('Login success event received')}
@login-failure=${(e: CustomEvent) => console.log('Login failure:', e.detail)}
@wifi-toggle=${(e: CustomEvent) => console.log('WiFi toggle:', e.detail)}
@network-select=${(e: CustomEvent) => console.log('Network selected:', e.detail)}
@wifi-settings-click=${() => console.log('WiFi settings clicked')}
@@ -69,3 +97,37 @@ export const demo = () => html`
></eco-applauncher>
</div>
`;
demoHome.demoTitle = 'Home Mode';
// Login mode demo
const demoLogin = () => html`
<style>
.demo-container {
width: 100%;
height: 100%;
}
</style>
<div class="demo-container">
<eco-applauncher
.mode=${'login' as TApplauncherMode}
.loginConfig=${loginConfig}
.apps=${mockApps}
.batteryLevel=${85}
.networkStatus=${'online'}
.soundLevel=${70}
.networks=${mockNetworks}
.connectedNetwork=${'HomeNetwork'}
.wifiEnabled=${true}
.outputDevices=${mockAudioDevices}
.activeDeviceId=${'speakers'}
.muted=${false}
@login-attempt=${handleLoginAttempt}
@login-success=${() => console.log('Login success event received')}
@login-failure=${(e: CustomEvent) => console.log('Login failure:', e.detail)}
></eco-applauncher>
</div>
`;
demoLogin.demoTitle = 'Login Mode';
// Export array of demo functions
export const demo = [demoHome, demoLogin];

View File

@@ -14,6 +14,9 @@ import { EcoApplauncherWifimenu, type IWifiNetwork } from '../eco-applauncher-wi
import { EcoApplauncherBatterymenu } from '../eco-applauncher-batterymenu/index.js';
import { EcoApplauncherSoundmenu, type IAudioDevice } from '../eco-applauncher-soundmenu/index.js';
import { EcoApplauncherKeyboard } from '../eco-applauncher-keyboard/index.js';
import { EcoApplauncherPowermenu, type TPowerAction } from '../eco-applauncher-powermenu/index.js';
import { EcoViewHome } from '../../../views/eco-view-home/index.js';
import { EcoViewLogin, type ILoginConfig, type ILoginCredentials } from '../../../views/eco-view-login/index.js';
// Ensure components are registered
DeesIcon;
@@ -21,6 +24,9 @@ EcoApplauncherWifimenu;
EcoApplauncherBatterymenu;
EcoApplauncherSoundmenu;
EcoApplauncherKeyboard;
EcoApplauncherPowermenu;
EcoViewHome;
EcoViewLogin;
declare global {
interface HTMLElementTagNameMap {
@@ -28,12 +34,18 @@ declare global {
}
}
export type TApplauncherMode = 'login' | 'home';
export interface IAppIcon {
name: string;
icon: string;
action?: () => void;
view?: TemplateResult;
}
export type { ILoginConfig, ILoginCredentials } from '../../../views/eco-view-login/index.js';
export type { TPowerAction } from '../eco-applauncher-powermenu/index.js';
export interface IStatusBarConfig {
showTime?: boolean;
showNetwork?: boolean;
@@ -153,6 +165,10 @@ export class EcoApplauncher extends DeesElement {
background: ${cssManager.bdTheme('hsl(220 15% 88%)', 'hsl(240 5% 15%)')};
}
.top-icon-button.active {
background: ${cssManager.bdTheme('hsl(220 15% 85%)', 'hsl(240 5% 18%)')};
}
.user-avatar {
width: 32px;
height: 32px;
@@ -195,9 +211,6 @@ export class EcoApplauncher extends DeesElement {
.apps-area {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 48px;
overflow-y: auto;
}
@@ -206,7 +219,6 @@ export class EcoApplauncher extends DeesElement {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
gap: 32px;
max-width: 800px;
width: 100%;
}
@@ -415,6 +427,18 @@ export class EcoApplauncher extends DeesElement {
pointer-events: none;
}
.topbar-menu-wrapper {
position: relative;
}
.topbar-menu-popup {
position: absolute;
top: calc(100% + 8px);
right: 0;
z-index: 100;
pointer-events: none;
}
.keyboard-area {
flex-shrink: 0;
height: 0;
@@ -430,6 +454,53 @@ export class EcoApplauncher extends DeesElement {
overflow: visible;
}
.view-area {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.view-header {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 24px;
background: ${cssManager.bdTheme('hsl(220 15% 94%)', 'hsl(240 6% 8%)')};
border-bottom: 1px solid ${cssManager.bdTheme('hsl(220 15% 88%)', 'hsl(240 5% 15%)')};
flex-shrink: 0;
}
.back-button {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 8px 14px;
background: ${cssManager.bdTheme('hsl(220 15% 88%)', 'hsl(240 5% 14%)')};
border-radius: 8px;
cursor: pointer;
transition: background 0.15s ease;
color: ${cssManager.bdTheme('hsl(0 0% 30%)', 'hsl(0 0% 80%)')};
font-size: 13px;
font-weight: 500;
}
.back-button:hover {
background: ${cssManager.bdTheme('hsl(220 15% 82%)', 'hsl(240 5% 18%)')};
}
.view-title {
font-size: 16px;
font-weight: 600;
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
}
.view-content {
flex: 1;
overflow: auto;
}
@media (max-width: 600px) {
.apps-area {
padding: 24px;
@@ -462,6 +533,16 @@ export class EcoApplauncher extends DeesElement {
`,
];
@property({ type: String })
accessor mode: TApplauncherMode = 'home';
@property({ type: Object })
accessor loginConfig: ILoginConfig = {
allowedMethods: ['pin', 'password', 'qr'],
pinLength: 4,
welcomeMessage: 'Welcome',
};
@property({ type: Array })
accessor apps: IAppIcon[] = [];
@@ -512,9 +593,18 @@ export class EcoApplauncher extends DeesElement {
@state()
accessor soundMenuOpen = false;
@state()
accessor powerMenuOpen = false;
@state()
accessor keyboardVisible = false;
@state()
accessor activeView: TemplateResult | null = null;
@state()
accessor activeViewName: string | null = null;
@property({ type: Array })
accessor networks: IWifiNetwork[] = [];
@@ -552,12 +642,8 @@ export class EcoApplauncher extends DeesElement {
public render(): TemplateResult {
return html`
<div class="launcher-container">
${this.renderTopBar()}
<div class="apps-area">
<div class="apps-grid">
${this.apps.map((app) => this.renderAppIcon(app))}
</div>
</div>
${this.mode === 'login' ? '' : this.renderTopBar()}
${this.renderMainContent()}
<div class="keyboard-area ${this.keyboardVisible ? 'visible' : ''}">
<eco-applauncher-keyboard
?visible=${this.keyboardVisible}
@@ -585,6 +671,58 @@ export class EcoApplauncher extends DeesElement {
`;
}
private renderMainContent(): TemplateResult {
if (this.mode === 'login') {
return this.renderLoginView();
}
// Home mode
if (this.activeView) {
return this.renderActiveView();
}
return this.renderHomeView();
}
private renderLoginView(): TemplateResult {
return html`
<eco-view-login
.config=${this.loginConfig}
@login-attempt=${this.handleLoginAttempt}
@key-press=${this.handleKeyboardKeyPress}
@backspace=${this.handleKeyboardBackspace}
style="flex: 1;"
></eco-view-login>
`;
}
private renderHomeView(): TemplateResult {
return html`
<eco-view-home
.apps=${this.apps}
@app-click=${this.handleHomeAppClick}
></eco-view-home>
`;
}
private renderAppsArea(): TemplateResult {
return html`
<div class="apps-area">
<div class="apps-grid">
${this.apps.map((app) => this.renderAppIcon(app))}
</div>
</div>
`;
}
private renderActiveView(): TemplateResult {
return html`
<div class="view-area">
<div class="view-content">
${this.activeView}
</div>
</div>
`;
}
private renderAppIcon(app: IAppIcon): TemplateResult {
return html`
<div class="app-icon" @click=${() => this.handleAppClick(app)}>
@@ -607,7 +745,13 @@ export class EcoApplauncher extends DeesElement {
return html`
<div class="top-bar">
<div class="top-left">
${this.topBarConfig.showDate ? html`
${this.activeView ? html`
<div class="back-button" @click=${this.handleBackClick}>
<dees-icon .icon=${'lucide:arrowLeft'} .iconSize=${16}></dees-icon>
<span>Back</span>
</div>
<span class="view-title">${this.activeViewName}</span>
` : this.topBarConfig.showDate ? html`
<span class="top-date">${this.currentDate}</span>
` : ''}
</div>
@@ -636,6 +780,21 @@ export class EcoApplauncher extends DeesElement {
${userInitials}
</div>
` : ''}
<div class="topbar-menu-wrapper">
<div
class="top-icon-button ${this.powerMenuOpen ? 'active' : ''}"
@click=${this.handlePowerClick}
>
<dees-icon .icon=${'lucide:power'} .iconSize=${18}></dees-icon>
</div>
<div class="topbar-menu-popup">
<eco-applauncher-powermenu
?open=${this.powerMenuOpen}
@menu-close=${this.handlePowerMenuClose}
@power-action=${this.handlePowerAction}
></eco-applauncher-powermenu>
</div>
</div>
</div>
</div>
`;
@@ -831,15 +990,91 @@ export class EcoApplauncher extends DeesElement {
composed: true,
})
);
// If app has a view, open it inside the applauncher
if (app.view) {
this.activeView = app.view;
this.activeViewName = app.name;
return;
}
// Otherwise execute the action
if (app.action) {
app.action();
}
}
private handleHomeAppClick(e: CustomEvent): void {
const app = e.detail.app as IAppIcon;
this.handleAppClick(app);
}
private handleLoginAttempt(e: CustomEvent): void {
const credentials = e.detail as ILoginCredentials;
// Dispatch event for parent to handle validation
this.dispatchEvent(new CustomEvent('login-attempt', {
detail: credentials,
bubbles: true,
composed: true,
}));
}
/**
* Set the login result after validation
* @param success Whether login was successful
* @param errorMessage Optional error message to display
*/
public setLoginResult(success: boolean, errorMessage?: string): void {
const loginView = this.shadowRoot?.querySelector('eco-view-login') as EcoViewLogin | null;
if (success) {
this.mode = 'home';
this.dispatchEvent(new CustomEvent('login-success', {
bubbles: true,
composed: true,
}));
} else {
if (loginView && errorMessage) {
loginView.showErrorMessage(errorMessage);
}
this.dispatchEvent(new CustomEvent('login-failure', {
detail: { error: errorMessage },
bubbles: true,
composed: true,
}));
}
}
/**
* Switch to login mode
*/
public showLogin(): void {
this.mode = 'login';
this.activeView = null;
this.activeViewName = null;
}
/**
* Switch to home mode
*/
public showHome(): void {
this.mode = 'home';
}
private handleBackClick(): void {
this.activeView = null;
this.activeViewName = null;
this.dispatchEvent(new CustomEvent('view-close', {
bubbles: true,
composed: true,
}));
}
private handleNetworkClick(e: MouseEvent): void {
e.stopPropagation();
this.batteryMenuOpen = false;
this.soundMenuOpen = false;
this.powerMenuOpen = false;
this.wifiMenuOpen = !this.wifiMenuOpen;
}
@@ -847,6 +1082,7 @@ export class EcoApplauncher extends DeesElement {
e.stopPropagation();
this.wifiMenuOpen = false;
this.soundMenuOpen = false;
this.powerMenuOpen = false;
this.batteryMenuOpen = !this.batteryMenuOpen;
}
@@ -854,9 +1090,18 @@ export class EcoApplauncher extends DeesElement {
e.stopPropagation();
this.wifiMenuOpen = false;
this.batteryMenuOpen = false;
this.powerMenuOpen = false;
this.soundMenuOpen = !this.soundMenuOpen;
}
private handlePowerClick(e: MouseEvent): void {
e.stopPropagation();
this.wifiMenuOpen = false;
this.batteryMenuOpen = false;
this.soundMenuOpen = false;
this.powerMenuOpen = !this.powerMenuOpen;
}
private handleWifiMenuClose(): void {
this.wifiMenuOpen = false;
}
@@ -869,6 +1114,19 @@ export class EcoApplauncher extends DeesElement {
this.soundMenuOpen = false;
}
private handlePowerMenuClose(): void {
this.powerMenuOpen = false;
}
private handlePowerAction(e: CustomEvent): void {
const action = e.detail.action as TPowerAction;
this.dispatchEvent(new CustomEvent('power-action', {
detail: { action },
bubbles: true,
composed: true,
}));
}
private handleVolumeChange(e: CustomEvent): void {
this.soundLevel = e.detail.volume;
this.dispatchEvent(new CustomEvent('volume-change', {
@@ -953,6 +1211,7 @@ export class EcoApplauncher extends DeesElement {
this.wifiMenuOpen = false;
this.batteryMenuOpen = false;
this.soundMenuOpen = false;
this.powerMenuOpen = false;
}
this.dispatchEvent(new CustomEvent('keyboard-toggle', {
detail: { visible: this.keyboardVisible },

View File

@@ -4,5 +4,4 @@ export * from './eco-applauncher-wifimenu/index.js';
export * from './eco-applauncher-batterymenu/index.js';
export * from './eco-applauncher-soundmenu/index.js';
export * from './eco-applauncher-keyboard/index.js';
export * from './eco-settings/index.js';
export * from './eco-peripherals/index.js';
export * from './eco-applauncher-powermenu/index.js';