feat: Add profile dropdown component and integrate with appbar for user menu
This commit is contained in:
@ -11,11 +11,13 @@ import {
|
||||
|
||||
import * as domtools from '@design.estate/dees-domtools';
|
||||
import * as interfaces from './interfaces/index.js';
|
||||
import * as plugins from './00plugins.js';
|
||||
import { demoFunc } from './dees-appui-appbar.demo.js';
|
||||
|
||||
// Import required components
|
||||
import './dees-icon.js';
|
||||
import './dees-windowcontrols.js';
|
||||
import './dees-appui-profiledropdown.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
@ -44,10 +46,14 @@ export class DeesAppuiBar extends DeesElement {
|
||||
@property({ type: Object })
|
||||
public user?: {
|
||||
name: string;
|
||||
email?: string;
|
||||
avatar?: string;
|
||||
status?: 'online' | 'offline' | 'busy' | 'away';
|
||||
};
|
||||
|
||||
@property({ type: Array })
|
||||
public profileMenuItems: (plugins.tsclass.website.IMenuItem & { shortcut?: string } | { divider: true })[] = [];
|
||||
|
||||
@property({ type: Boolean })
|
||||
public showSearch: boolean = false;
|
||||
|
||||
@ -64,6 +70,9 @@ export class DeesAppuiBar extends DeesElement {
|
||||
@state()
|
||||
private focusedDropdownItem: number = -1;
|
||||
|
||||
@state()
|
||||
private isProfileDropdownOpen: boolean = false;
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
@ -102,7 +111,7 @@ export class DeesAppuiBar extends DeesElement {
|
||||
border-radius: 4px;
|
||||
-webkit-app-region: no-drag;
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
outline: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -162,7 +171,7 @@ export class DeesAppuiBar extends DeesElement {
|
||||
|
||||
.dropdown-item {
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
@ -206,7 +215,7 @@ export class DeesAppuiBar extends DeesElement {
|
||||
|
||||
.breadcrumb-item {
|
||||
color: ${cssManager.bdTheme('#00000080', '#ffffff80')};
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
@ -229,7 +238,7 @@ export class DeesAppuiBar extends DeesElement {
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
@ -242,7 +251,7 @@ export class DeesAppuiBar extends DeesElement {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
cursor: default;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
transition: background 0.2s;
|
||||
@ -413,22 +422,31 @@ export class DeesAppuiBar extends DeesElement {
|
||||
${this.showSearch ? html`
|
||||
<dees-icon
|
||||
class="search-icon"
|
||||
.iconName=${'search'}
|
||||
.icon=${'lucide:search'}
|
||||
@click=${this.handleSearchClick}
|
||||
></dees-icon>
|
||||
` : ''}
|
||||
${this.user ? html`
|
||||
<div class="user-info" @click=${this.handleUserClick}>
|
||||
<div class="user-avatar">
|
||||
${this.user.avatar ?
|
||||
html`<img src="${this.user.avatar}" alt="${this.user.name}">` :
|
||||
html`${this.user.name.charAt(0).toUpperCase()}`
|
||||
}
|
||||
${this.user.status ? html`
|
||||
<div class="user-status ${this.user.status}"></div>
|
||||
` : ''}
|
||||
<div style="position: relative;">
|
||||
<div class="user-info" @click=${this.handleUserClick}>
|
||||
<div class="user-avatar">
|
||||
${this.user.avatar ?
|
||||
html`<img src="${this.user.avatar}" alt="${this.user.name}">` :
|
||||
html`${this.user.name.charAt(0).toUpperCase()}`
|
||||
}
|
||||
${this.user.status ? html`
|
||||
<div class="user-status ${this.user.status}"></div>
|
||||
` : ''}
|
||||
</div>
|
||||
<span>${this.user.name}</span>
|
||||
</div>
|
||||
<span>${this.user.name}</span>
|
||||
<dees-appui-profiledropdown
|
||||
.user=${this.user}
|
||||
.menuItems=${this.profileMenuItems}
|
||||
.isOpen=${this.isProfileDropdownOpen}
|
||||
.position=${'top-right'}
|
||||
@menu-select=${(e: CustomEvent) => this.handleProfileMenuSelect(e)}
|
||||
></dees-appui-profiledropdown>
|
||||
</div>
|
||||
` : ''}
|
||||
`;
|
||||
@ -536,12 +554,26 @@ export class DeesAppuiBar extends DeesElement {
|
||||
}
|
||||
|
||||
private handleUserClick() {
|
||||
this.isProfileDropdownOpen = !this.isProfileDropdownOpen;
|
||||
|
||||
// Also emit the event for backward compatibility
|
||||
this.dispatchEvent(new CustomEvent('user-menu-open', {
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
}
|
||||
|
||||
private handleProfileMenuSelect(e: CustomEvent) {
|
||||
this.isProfileDropdownOpen = false;
|
||||
|
||||
// Re-emit the event
|
||||
this.dispatchEvent(new CustomEvent('profile-menu-select', {
|
||||
detail: e.detail,
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
async connectedCallback() {
|
||||
await super.connectedCallback();
|
||||
@ -564,6 +596,7 @@ export class DeesAppuiBar extends DeesElement {
|
||||
// Close all dropdowns when clicking outside
|
||||
this.activeMenu = null;
|
||||
this.focusedDropdownItem = -1;
|
||||
// Note: Profile dropdown handles its own outside clicks
|
||||
}
|
||||
|
||||
private handleDropdownKeydown(e: KeyboardEvent, items: interfaces.IAppBarMenuItem[], _parentId: string) {
|
||||
|
Reference in New Issue
Block a user