Restructures project with feature-based organization

Refactors project structure to support modular, feature-driven development

Introduces comprehensive language localization support
Adds menu management with role-based access control
Implements dynamic sidebar and theme switching capabilities

Enhances project scalability and maintainability
This commit is contained in:
Janus C. H. Knudsen 2026-01-08 15:44:11 +01:00
parent fac7754d7a
commit d7f3c55a2a
60 changed files with 3214 additions and 20 deletions

View file

@ -0,0 +1,106 @@
/**
* Search Controller
*
* Handles global search functionality and keyboard shortcuts
*/
export class SearchController {
private input: HTMLInputElement | null = null;
private container: HTMLElement | null = null;
constructor() {
this.input = document.getElementById('globalSearch') as HTMLInputElement | null;
this.container = document.querySelector<HTMLElement>('swp-topbar-search');
this.setupListeners();
}
/**
* Get current search value
*/
get value(): string {
return this.input?.value ?? '';
}
/**
* Set search value
*/
set value(val: string) {
if (this.input) {
this.input.value = val;
}
}
/**
* Focus the search input
*/
focus(): void {
this.input?.focus();
}
/**
* Blur the search input
*/
blur(): void {
this.input?.blur();
}
/**
* Clear the search input
*/
clear(): void {
this.value = '';
}
private setupListeners(): void {
// Keyboard shortcuts
document.addEventListener('keydown', (e) => this.handleKeyboard(e));
// Input handlers
if (this.input) {
this.input.addEventListener('input', (e) => this.handleInput(e));
// Prevent form submission if wrapped in form
const form = this.input.closest('form');
form?.addEventListener('submit', (e) => this.handleSubmit(e));
}
}
private handleKeyboard(e: KeyboardEvent): void {
// Cmd/Ctrl + K to focus search
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
this.focus();
return;
}
// Escape to blur search when focused
if (e.key === 'Escape' && document.activeElement === this.input) {
this.blur();
}
}
private handleInput(e: Event): void {
const target = e.target as HTMLInputElement;
const query = target.value.trim();
// Emit custom event for search
document.dispatchEvent(new CustomEvent('app:search', {
detail: { query },
bubbles: true
}));
}
private handleSubmit(e: Event): void {
e.preventDefault();
const query = this.value.trim();
if (!query) return;
// Emit custom event for search submit
document.dispatchEvent(new CustomEvent('app:search-submit', {
detail: { query },
bubbles: true
}));
}
}