init
This commit is contained in:
127
src/app/features/shell/title-bar.component.ts
Normal file
127
src/app/features/shell/title-bar.component.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { Component, inject, computed, signal } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||
import { lucideMinus, lucideSquare, lucideX, lucideChevronLeft, lucideHash, lucideMenu } from '@ng-icons/lucide';
|
||||
import { Router } from '@angular/router';
|
||||
import { selectCurrentRoom } from '../../store/rooms/rooms.selectors';
|
||||
import * as RoomsActions from '../../store/rooms/rooms.actions';
|
||||
import { selectCurrentUser } from '../../store/users/users.selectors';
|
||||
import { ServerDirectoryService } from '../../core/services/server-directory.service';
|
||||
import { WebRTCService } from '../../core/services/webrtc.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-title-bar',
|
||||
standalone: true,
|
||||
imports: [CommonModule, NgIcon],
|
||||
viewProviders: [provideIcons({ lucideMinus, lucideSquare, lucideX, lucideChevronLeft, lucideHash, lucideMenu })],
|
||||
template: `
|
||||
<div class="fixed top-0 left-16 right-0 h-10 bg-card border-b border-border flex items-center justify-between px-4 z-50 select-none" style="-webkit-app-region: drag;">
|
||||
<div class="flex items-center gap-2 min-w-0 relative" style="-webkit-app-region: no-drag;">
|
||||
<button *ngIf="inRoom()" (click)="onBack()" class="p-2 hover:bg-secondary rounded" title="Back">
|
||||
<ng-icon name="lucideChevronLeft" class="w-5 h-5 text-muted-foreground" />
|
||||
</button>
|
||||
<ng-container *ngIf="inRoom(); else userServer">
|
||||
<ng-icon name="lucideHash" class="w-5 h-5 text-muted-foreground" />
|
||||
<span class="text-sm font-semibold text-foreground truncate">{{ roomName() }}</span>
|
||||
<span *ngIf="roomDescription()" class="hidden md:inline text-sm text-muted-foreground border-l border-border pl-2 truncate">{{ roomDescription() }}</span>
|
||||
<button (click)="toggleMenu()" class="ml-2 p-2 hover:bg-secondary rounded" title="Menu">
|
||||
<ng-icon name="lucideMenu" class="w-5 h-5 text-muted-foreground" />
|
||||
</button>
|
||||
<!-- Anchored dropdown under the menu button -->
|
||||
<div *ngIf="showMenu()" class="absolute right-0 top-full mt-1 z-50 bg-card border border-border rounded-lg shadow-lg w-48">
|
||||
<button (click)="leaveServer()" class="w-full text-left px-3 py-2 text-sm hover:bg-secondary transition-colors text-foreground">Leave Server</button>
|
||||
<div class="border-t border-border"></div>
|
||||
<button (click)="logout()" class="w-full text-left px-3 py-2 text-sm hover:bg-secondary transition-colors text-foreground">Logout</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #userServer>
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<span class="text-sm text-muted-foreground truncate">{{ username() }} | {{ serverName() }}</span>
|
||||
<span *ngIf="!isConnected()" class="text-xs px-2 py-0.5 rounded bg-destructive/15 text-destructive">Reconnecting…</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div class="flex items-center gap-2" style="-webkit-app-region: no-drag;">
|
||||
<button *ngIf="!isAuthed()" class="px-3 h-8 grid place-items-center hover:bg-secondary rounded text-sm text-foreground" (click)="goLogin()" title="Login">Login</button>
|
||||
<button class="w-8 h-8 grid place-items-center hover:bg-secondary rounded" title="Minimize" (click)="minimize()">
|
||||
<ng-icon name="lucideMinus" class="w-4 h-4" />
|
||||
</button>
|
||||
<button class="w-8 h-8 grid place-items-center hover:bg-secondary rounded" title="Maximize" (click)="maximize()">
|
||||
<ng-icon name="lucideSquare" class="w-4 h-4" />
|
||||
</button>
|
||||
<button class="w-8 h-8 grid place-items-center hover:bg-destructive/10 rounded" title="Close" (click)="close()">
|
||||
<ng-icon name="lucideX" class="w-4 h-4 text-destructive" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Click-away overlay to close dropdown -->
|
||||
<div *ngIf="showMenu()" class="fixed inset-0 z-40" (click)="closeMenu()" style="-webkit-app-region: no-drag;"></div>
|
||||
`,
|
||||
})
|
||||
export class TitleBarComponent {
|
||||
private store = inject(Store);
|
||||
private serverDirectory = inject(ServerDirectoryService);
|
||||
private router = inject(Router);
|
||||
private webrtc = inject(WebRTCService);
|
||||
showMenuState = computed(() => false);
|
||||
|
||||
private currentUserSig = this.store.selectSignal(selectCurrentUser);
|
||||
username = computed(() => this.currentUserSig()?.displayName || 'Guest');
|
||||
serverName = computed(() => this.serverDirectory.activeServer()?.name || 'No Server');
|
||||
isConnected = computed(() => this.webrtc.isConnected());
|
||||
isAuthed = computed(() => !!this.currentUserSig());
|
||||
private currentRoomSig = this.store.selectSignal(selectCurrentRoom);
|
||||
inRoom = computed(() => !!this.currentRoomSig());
|
||||
roomName = computed(() => this.currentRoomSig()?.name || '');
|
||||
roomDescription = computed(() => this.currentRoomSig()?.description || '');
|
||||
private _showMenu = signal(false);
|
||||
showMenu = computed(() => this._showMenu());
|
||||
|
||||
minimize() {
|
||||
const api = (window as any).electronAPI;
|
||||
if (api?.minimizeWindow) api.minimizeWindow();
|
||||
}
|
||||
|
||||
maximize() {
|
||||
const api = (window as any).electronAPI;
|
||||
if (api?.maximizeWindow) api.maximizeWindow();
|
||||
}
|
||||
|
||||
close() {
|
||||
const api = (window as any).electronAPI;
|
||||
if (api?.closeWindow) api.closeWindow();
|
||||
}
|
||||
|
||||
goLogin() {
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
|
||||
onBack() {
|
||||
// Leave room to ensure header switches to user/server view
|
||||
this.store.dispatch(RoomsActions.leaveRoom());
|
||||
this.router.navigate(['/search']);
|
||||
}
|
||||
|
||||
toggleMenu() {
|
||||
this._showMenu.set(!this._showMenu());
|
||||
}
|
||||
|
||||
leaveServer() {
|
||||
this._showMenu.set(false);
|
||||
this.store.dispatch(RoomsActions.leaveRoom());
|
||||
window.dispatchEvent(new CustomEvent('navigate:servers'));
|
||||
}
|
||||
|
||||
closeMenu() {
|
||||
this._showMenu.set(false);
|
||||
}
|
||||
|
||||
logout() {
|
||||
this._showMenu.set(false);
|
||||
try {
|
||||
localStorage.removeItem('metoyou_currentUserId');
|
||||
} catch {}
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user