update
This commit is contained in:
@@ -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 },
|
||||
|
||||
Reference in New Issue
Block a user