WIP
This commit is contained in:
parent
54b057886c
commit
7fc1ae0650
204 changed files with 4345 additions and 134 deletions
226
PlanTempus.Application/wwwroot/ts/modules/drawers.ts
Normal file
226
PlanTempus.Application/wwwroot/ts/modules/drawers.ts
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/**
|
||||
* Drawer Controller
|
||||
*
|
||||
* Handles all drawer functionality including profile, notifications, and todo drawers
|
||||
*/
|
||||
|
||||
export type DrawerName = 'profile' | 'notification' | 'todo' | 'newTodo';
|
||||
|
||||
export class DrawerController {
|
||||
private profileDrawer: HTMLElement | null = null;
|
||||
private notificationDrawer: HTMLElement | null = null;
|
||||
private todoDrawer: HTMLElement | null = null;
|
||||
private newTodoDrawer: HTMLElement | null = null;
|
||||
private overlay: HTMLElement | null = null;
|
||||
private activeDrawer: DrawerName | null = null;
|
||||
|
||||
constructor() {
|
||||
this.profileDrawer = document.getElementById('profileDrawer');
|
||||
this.notificationDrawer = document.getElementById('notificationDrawer');
|
||||
this.todoDrawer = document.getElementById('todoDrawer');
|
||||
this.newTodoDrawer = document.getElementById('newTodoDrawer');
|
||||
this.overlay = document.getElementById('drawerOverlay');
|
||||
|
||||
this.setupListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currently active drawer name
|
||||
*/
|
||||
get active(): DrawerName | null {
|
||||
return this.activeDrawer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a drawer by name
|
||||
*/
|
||||
open(name: DrawerName): void {
|
||||
this.closeAll();
|
||||
|
||||
const drawer = this.getDrawer(name);
|
||||
if (drawer && this.overlay) {
|
||||
drawer.classList.add('active');
|
||||
this.overlay.classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
this.activeDrawer = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a specific drawer
|
||||
*/
|
||||
close(name: DrawerName): void {
|
||||
const drawer = this.getDrawer(name);
|
||||
drawer?.classList.remove('active');
|
||||
|
||||
// Only hide overlay if no drawers are active
|
||||
if (this.overlay && !document.querySelector('.active[class*="drawer"]')) {
|
||||
this.overlay.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
if (this.activeDrawer === name) {
|
||||
this.activeDrawer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all drawers
|
||||
*/
|
||||
closeAll(): void {
|
||||
[this.profileDrawer, this.notificationDrawer, this.todoDrawer, this.newTodoDrawer]
|
||||
.forEach(drawer => drawer?.classList.remove('active'));
|
||||
|
||||
this.overlay?.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
this.activeDrawer = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open profile drawer
|
||||
*/
|
||||
openProfile(): void {
|
||||
this.open('profile');
|
||||
}
|
||||
|
||||
/**
|
||||
* Open notification drawer
|
||||
*/
|
||||
openNotification(): void {
|
||||
this.open('notification');
|
||||
}
|
||||
|
||||
/**
|
||||
* Open todo drawer (slides on top of profile)
|
||||
*/
|
||||
openTodo(): void {
|
||||
this.todoDrawer?.classList.add('active');
|
||||
}
|
||||
|
||||
/**
|
||||
* Close todo drawer
|
||||
*/
|
||||
closeTodo(): void {
|
||||
this.todoDrawer?.classList.remove('active');
|
||||
this.closeNewTodo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open new todo drawer
|
||||
*/
|
||||
openNewTodo(): void {
|
||||
this.newTodoDrawer?.classList.add('active');
|
||||
}
|
||||
|
||||
/**
|
||||
* Close new todo drawer
|
||||
*/
|
||||
closeNewTodo(): void {
|
||||
this.newTodoDrawer?.classList.remove('active');
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark all notifications as read
|
||||
*/
|
||||
markAllNotificationsRead(): void {
|
||||
if (!this.notificationDrawer) return;
|
||||
|
||||
const unreadItems = this.notificationDrawer.querySelectorAll<HTMLElement>(
|
||||
'swp-notification-item[data-unread="true"]'
|
||||
);
|
||||
unreadItems.forEach(item => item.removeAttribute('data-unread'));
|
||||
|
||||
const badge = document.querySelector<HTMLElement>('swp-notification-badge');
|
||||
if (badge) {
|
||||
badge.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
private getDrawer(name: DrawerName): HTMLElement | null {
|
||||
switch (name) {
|
||||
case 'profile': return this.profileDrawer;
|
||||
case 'notification': return this.notificationDrawer;
|
||||
case 'todo': return this.todoDrawer;
|
||||
case 'newTodo': return this.newTodoDrawer;
|
||||
}
|
||||
}
|
||||
|
||||
private setupListeners(): void {
|
||||
// Profile drawer triggers
|
||||
document.getElementById('profileTrigger')
|
||||
?.addEventListener('click', () => this.openProfile());
|
||||
document.getElementById('drawerClose')
|
||||
?.addEventListener('click', () => this.close('profile'));
|
||||
|
||||
// Notification drawer triggers
|
||||
document.getElementById('notificationsBtn')
|
||||
?.addEventListener('click', () => this.openNotification());
|
||||
document.getElementById('notificationDrawerClose')
|
||||
?.addEventListener('click', () => this.close('notification'));
|
||||
document.getElementById('markAllRead')
|
||||
?.addEventListener('click', () => this.markAllNotificationsRead());
|
||||
|
||||
// Todo drawer triggers
|
||||
document.getElementById('openTodoDrawer')
|
||||
?.addEventListener('click', () => this.openTodo());
|
||||
document.getElementById('todoDrawerBack')
|
||||
?.addEventListener('click', () => this.closeTodo());
|
||||
|
||||
// New todo drawer triggers
|
||||
document.getElementById('addTodoBtn')
|
||||
?.addEventListener('click', () => this.openNewTodo());
|
||||
document.getElementById('newTodoDrawerBack')
|
||||
?.addEventListener('click', () => this.closeNewTodo());
|
||||
document.getElementById('cancelNewTodo')
|
||||
?.addEventListener('click', () => this.closeNewTodo());
|
||||
document.getElementById('saveNewTodo')
|
||||
?.addEventListener('click', () => this.closeNewTodo());
|
||||
|
||||
// Overlay click closes all
|
||||
this.overlay?.addEventListener('click', () => this.closeAll());
|
||||
|
||||
// Escape key closes all
|
||||
document.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') this.closeAll();
|
||||
});
|
||||
|
||||
// Todo interactions
|
||||
this.todoDrawer?.addEventListener('click', (e) => this.handleTodoClick(e));
|
||||
|
||||
// Visibility options
|
||||
document.addEventListener('click', (e) => this.handleVisibilityClick(e));
|
||||
}
|
||||
|
||||
private handleTodoClick(e: Event): void {
|
||||
const target = e.target as HTMLElement;
|
||||
const todoItem = target.closest<HTMLElement>('swp-todo-item');
|
||||
const checkbox = target.closest<HTMLElement>('swp-todo-checkbox');
|
||||
|
||||
if (checkbox && todoItem) {
|
||||
const isCompleted = todoItem.dataset.completed === 'true';
|
||||
if (isCompleted) {
|
||||
todoItem.removeAttribute('data-completed');
|
||||
} else {
|
||||
todoItem.dataset.completed = 'true';
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle section collapse
|
||||
const sectionHeader = target.closest<HTMLElement>('swp-todo-section-header');
|
||||
if (sectionHeader) {
|
||||
const section = sectionHeader.closest<HTMLElement>('swp-todo-section');
|
||||
section?.classList.toggle('collapsed');
|
||||
}
|
||||
}
|
||||
|
||||
private handleVisibilityClick(e: Event): void {
|
||||
const target = e.target as HTMLElement;
|
||||
const option = target.closest<HTMLElement>('swp-visibility-option');
|
||||
|
||||
if (option) {
|
||||
document.querySelectorAll<HTMLElement>('swp-visibility-option')
|
||||
.forEach(o => o.classList.remove('active'));
|
||||
option.classList.add('active');
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue