diff --git a/PlanTempus.Application/wwwroot/css/employees.css b/PlanTempus.Application/wwwroot/css/employees.css index d3fc766..92b2e5d 100644 --- a/PlanTempus.Application/wwwroot/css/employees.css +++ b/PlanTempus.Application/wwwroot/css/employees.css @@ -889,6 +889,11 @@ swp-schedule-scroll { overflow-x: auto; } +/* Når drawer er åben: giv plads til drawer med margin */ +body.schedule-drawer-open swp-schedule-scroll { + margin-right: var(--drawer-width, 420px); +} + /* =========================================== WORK SCHEDULE TABLE =========================================== */ diff --git a/PlanTempus.Application/wwwroot/js/app.js.map b/PlanTempus.Application/wwwroot/js/app.js.map deleted file mode 100644 index f5adfaa..0000000 --- a/PlanTempus.Application/wwwroot/js/app.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../ts/modules/sidebar.ts", "../ts/modules/drawers.ts", "../ts/modules/theme.ts", "../ts/modules/search.ts", "../ts/modules/lockscreen.ts", "../ts/modules/cash.ts", "../ts/modules/employees.ts", "../ts/app.ts"], - "sourcesContent": ["/**\n * Sidebar Controller\n *\n * Handles sidebar collapse/expand and tooltip functionality\n */\n\nexport class SidebarController {\n private menuToggle: HTMLElement | null = null;\n private appLayout: HTMLElement | null = null;\n private menuTooltip: HTMLElement | null = null;\n\n constructor() {\n this.menuToggle = document.getElementById('menuToggle');\n this.appLayout = document.querySelector('swp-app-layout');\n this.menuTooltip = document.getElementById('menuTooltip');\n\n this.setupListeners();\n this.setupTooltips();\n this.restoreState();\n }\n\n /**\n * Check if sidebar is collapsed\n */\n get isCollapsed(): boolean {\n return this.appLayout?.classList.contains('menu-collapsed') ?? false;\n }\n\n /**\n * Toggle sidebar collapsed state\n */\n toggle(): void {\n if (!this.appLayout) return;\n\n this.appLayout.classList.toggle('menu-collapsed');\n localStorage.setItem('sidebar-collapsed', String(this.isCollapsed));\n }\n\n /**\n * Collapse the sidebar\n */\n collapse(): void {\n this.appLayout?.classList.add('menu-collapsed');\n localStorage.setItem('sidebar-collapsed', 'true');\n }\n\n /**\n * Expand the sidebar\n */\n expand(): void {\n this.appLayout?.classList.remove('menu-collapsed');\n localStorage.setItem('sidebar-collapsed', 'false');\n }\n\n private setupListeners(): void {\n this.menuToggle?.addEventListener('click', () => this.toggle());\n }\n\n private setupTooltips(): void {\n if (!this.menuTooltip) return;\n\n const menuItems = document.querySelectorAll('swp-side-menu-item[data-tooltip]');\n\n menuItems.forEach(item => {\n item.addEventListener('mouseenter', () => this.showTooltip(item));\n item.addEventListener('mouseleave', () => this.hideTooltip());\n });\n }\n\n private showTooltip(item: HTMLElement): void {\n if (!this.isCollapsed || !this.menuTooltip) return;\n\n const rect = item.getBoundingClientRect();\n const tooltipText = item.dataset.tooltip;\n\n if (!tooltipText) return;\n\n this.menuTooltip.textContent = tooltipText;\n this.menuTooltip.style.left = `${rect.right + 8}px`;\n this.menuTooltip.style.top = `${rect.top + rect.height / 2}px`;\n this.menuTooltip.style.transform = 'translateY(-50%)';\n this.menuTooltip.showPopover();\n }\n\n private hideTooltip(): void {\n this.menuTooltip?.hidePopover();\n }\n\n private restoreState(): void {\n if (!this.appLayout) return;\n\n if (localStorage.getItem('sidebar-collapsed') === 'true') {\n this.appLayout.classList.add('menu-collapsed');\n }\n }\n}\n", "/**\n * Drawer Controller\n *\n * Handles all drawer functionality including profile, notifications, and todo drawers\n */\n\nexport type DrawerName = 'profile' | 'notification' | 'todo' | 'newTodo';\n\nexport class DrawerController {\n private profileDrawer: HTMLElement | null = null;\n private notificationDrawer: HTMLElement | null = null;\n private todoDrawer: HTMLElement | null = null;\n private newTodoDrawer: HTMLElement | null = null;\n private overlay: HTMLElement | null = null;\n private activeDrawer: DrawerName | null = null;\n private activeGenericDrawer: HTMLElement | null = null;\n\n constructor() {\n this.profileDrawer = document.getElementById('profileDrawer');\n this.notificationDrawer = document.getElementById('notificationDrawer');\n this.todoDrawer = document.getElementById('todoDrawer');\n this.newTodoDrawer = document.getElementById('newTodoDrawer');\n this.overlay = document.getElementById('drawerOverlay');\n\n this.setupListeners();\n this.setupGenericDrawers();\n }\n\n /**\n * Get currently active drawer name\n */\n get active(): DrawerName | null {\n return this.activeDrawer;\n }\n\n /**\n * Open a drawer by name\n */\n open(name: DrawerName): void {\n this.closeAll();\n\n const drawer = this.getDrawer(name);\n if (drawer && this.overlay) {\n drawer.classList.add('active');\n this.overlay.classList.add('active');\n document.body.style.overflow = 'hidden';\n this.activeDrawer = name;\n }\n }\n\n /**\n * Close a specific drawer\n */\n close(name: DrawerName): void {\n const drawer = this.getDrawer(name);\n drawer?.classList.remove('active');\n\n // Only hide overlay if no drawers are active\n if (this.overlay && !document.querySelector('.active[class*=\"drawer\"]')) {\n this.overlay.classList.remove('active');\n document.body.style.overflow = '';\n }\n\n if (this.activeDrawer === name) {\n this.activeDrawer = null;\n }\n }\n\n /**\n * Close all drawers\n */\n closeAll(): void {\n [this.profileDrawer, this.notificationDrawer, this.todoDrawer, this.newTodoDrawer]\n .forEach(drawer => drawer?.classList.remove('active'));\n\n // Close any generic drawers\n this.closeGenericDrawer();\n\n this.overlay?.classList.remove('active');\n document.body.style.overflow = '';\n this.activeDrawer = null;\n }\n\n /**\n * Open a generic drawer by ID\n */\n openGenericDrawer(drawerId: string): void {\n this.closeAll();\n\n const drawer = document.getElementById(drawerId);\n if (drawer && this.overlay) {\n drawer.classList.add('open');\n this.overlay.classList.add('active');\n document.body.style.overflow = 'hidden';\n this.activeGenericDrawer = drawer;\n }\n }\n\n /**\n * Close the currently open generic drawer\n */\n closeGenericDrawer(): void {\n this.activeGenericDrawer?.classList.remove('open');\n this.activeGenericDrawer = null;\n }\n\n /**\n * Open profile drawer\n */\n openProfile(): void {\n this.open('profile');\n }\n\n /**\n * Open notification drawer\n */\n openNotification(): void {\n this.open('notification');\n }\n\n /**\n * Open todo drawer (slides on top of profile)\n */\n openTodo(): void {\n this.todoDrawer?.classList.add('active');\n }\n\n /**\n * Close todo drawer\n */\n closeTodo(): void {\n this.todoDrawer?.classList.remove('active');\n this.closeNewTodo();\n }\n\n /**\n * Open new todo drawer\n */\n openNewTodo(): void {\n this.newTodoDrawer?.classList.add('active');\n }\n\n /**\n * Close new todo drawer\n */\n closeNewTodo(): void {\n this.newTodoDrawer?.classList.remove('active');\n }\n\n /**\n * Mark all notifications as read\n */\n markAllNotificationsRead(): void {\n if (!this.notificationDrawer) return;\n\n const unreadItems = this.notificationDrawer.querySelectorAll(\n 'swp-notification-item[data-unread=\"true\"]'\n );\n unreadItems.forEach(item => item.removeAttribute('data-unread'));\n\n const badge = document.querySelector('swp-notification-badge');\n if (badge) {\n badge.style.display = 'none';\n }\n }\n\n private getDrawer(name: DrawerName): HTMLElement | null {\n switch (name) {\n case 'profile': return this.profileDrawer;\n case 'notification': return this.notificationDrawer;\n case 'todo': return this.todoDrawer;\n case 'newTodo': return this.newTodoDrawer;\n }\n }\n\n private setupListeners(): void {\n // Profile drawer triggers\n document.getElementById('profileTrigger')\n ?.addEventListener('click', () => this.openProfile());\n document.getElementById('drawerClose')\n ?.addEventListener('click', () => this.close('profile'));\n\n // Notification drawer triggers\n document.getElementById('notificationsBtn')\n ?.addEventListener('click', () => this.openNotification());\n document.getElementById('notificationDrawerClose')\n ?.addEventListener('click', () => this.close('notification'));\n document.getElementById('markAllRead')\n ?.addEventListener('click', () => this.markAllNotificationsRead());\n\n // Todo drawer triggers\n document.getElementById('openTodoDrawer')\n ?.addEventListener('click', () => this.openTodo());\n document.getElementById('todoDrawerBack')\n ?.addEventListener('click', () => this.closeTodo());\n\n // New todo drawer triggers\n document.getElementById('addTodoBtn')\n ?.addEventListener('click', () => this.openNewTodo());\n document.getElementById('newTodoDrawerBack')\n ?.addEventListener('click', () => this.closeNewTodo());\n document.getElementById('cancelNewTodo')\n ?.addEventListener('click', () => this.closeNewTodo());\n document.getElementById('saveNewTodo')\n ?.addEventListener('click', () => this.closeNewTodo());\n\n // Overlay click closes all\n this.overlay?.addEventListener('click', () => this.closeAll());\n\n // Escape key closes all\n document.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key === 'Escape') this.closeAll();\n });\n\n // Todo interactions\n this.todoDrawer?.addEventListener('click', (e) => this.handleTodoClick(e));\n\n // Visibility options\n document.addEventListener('click', (e) => this.handleVisibilityClick(e));\n }\n\n private handleTodoClick(e: Event): void {\n const target = e.target as HTMLElement;\n const todoItem = target.closest('swp-todo-item');\n const checkbox = target.closest('swp-todo-checkbox');\n\n if (checkbox && todoItem) {\n const isCompleted = todoItem.dataset.completed === 'true';\n if (isCompleted) {\n todoItem.removeAttribute('data-completed');\n } else {\n todoItem.dataset.completed = 'true';\n }\n }\n\n // Toggle section collapse\n const sectionHeader = target.closest('swp-todo-section-header');\n if (sectionHeader) {\n const section = sectionHeader.closest('swp-todo-section');\n section?.classList.toggle('collapsed');\n }\n }\n\n private handleVisibilityClick(e: Event): void {\n const target = e.target as HTMLElement;\n const option = target.closest('swp-visibility-option');\n\n if (option) {\n document.querySelectorAll('swp-visibility-option')\n .forEach(o => o.classList.remove('active'));\n option.classList.add('active');\n }\n }\n\n /**\n * Setup generic drawer triggers and close buttons\n * Uses data-drawer-trigger=\"drawer-id\" and data-drawer-close attributes\n */\n private setupGenericDrawers(): void {\n // Handle drawer triggers\n document.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n const trigger = target.closest('[data-drawer-trigger]');\n\n if (trigger) {\n const drawerId = trigger.dataset.drawerTrigger;\n if (drawerId) {\n this.openGenericDrawer(drawerId);\n }\n }\n });\n\n // Handle drawer close buttons\n document.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n const closeBtn = target.closest('[data-drawer-close]');\n\n if (closeBtn) {\n this.closeGenericDrawer();\n this.overlay?.classList.remove('active');\n document.body.style.overflow = '';\n }\n });\n }\n}\n", "/**\n * Theme Controller\n *\n * Handles dark/light mode switching and system preference detection\n */\n\nexport type Theme = 'light' | 'dark' | 'system';\n\nexport class ThemeController {\n private static readonly STORAGE_KEY = 'theme-preference';\n private static readonly DARK_CLASS = 'dark-mode';\n private static readonly LIGHT_CLASS = 'light-mode';\n\n private root: HTMLElement;\n private themeOptions: NodeListOf;\n\n constructor() {\n this.root = document.documentElement;\n this.themeOptions = document.querySelectorAll('swp-theme-option');\n\n this.applyTheme(this.current);\n this.updateUI();\n this.setupListeners();\n }\n\n /**\n * Get the current theme setting\n */\n get current(): Theme {\n const stored = localStorage.getItem(ThemeController.STORAGE_KEY) as Theme | null;\n if (stored === 'dark' || stored === 'light' || stored === 'system') {\n return stored;\n }\n return 'system';\n }\n\n /**\n * Check if dark mode is currently active\n */\n get isDark(): boolean {\n return this.root.classList.contains(ThemeController.DARK_CLASS) ||\n (this.systemPrefersDark && !this.root.classList.contains(ThemeController.LIGHT_CLASS));\n }\n\n /**\n * Check if system prefers dark mode\n */\n get systemPrefersDark(): boolean {\n return window.matchMedia('(prefers-color-scheme: dark)').matches;\n }\n\n /**\n * Set theme and persist preference\n */\n set(theme: Theme): void {\n localStorage.setItem(ThemeController.STORAGE_KEY, theme);\n this.applyTheme(theme);\n this.updateUI();\n }\n\n /**\n * Toggle between light and dark themes\n */\n toggle(): void {\n this.set(this.isDark ? 'light' : 'dark');\n }\n\n private applyTheme(theme: Theme): void {\n this.root.classList.remove(ThemeController.DARK_CLASS, ThemeController.LIGHT_CLASS);\n\n if (theme === 'dark') {\n this.root.classList.add(ThemeController.DARK_CLASS);\n } else if (theme === 'light') {\n this.root.classList.add(ThemeController.LIGHT_CLASS);\n }\n // 'system' leaves both classes off, letting CSS media query handle it\n }\n\n private updateUI(): void {\n if (!this.themeOptions) return;\n\n const darkActive = this.isDark;\n\n this.themeOptions.forEach(option => {\n const theme = option.dataset.theme as Theme;\n const isActive = (theme === 'dark' && darkActive) || (theme === 'light' && !darkActive);\n option.classList.toggle('active', isActive);\n });\n }\n\n private setupListeners(): void {\n // Theme option clicks\n this.themeOptions.forEach(option => {\n option.addEventListener('click', (e) => this.handleOptionClick(e));\n });\n\n // System theme changes\n window.matchMedia('(prefers-color-scheme: dark)')\n .addEventListener('change', () => this.handleSystemChange());\n }\n\n private handleOptionClick(e: Event): void {\n const target = e.target as HTMLElement;\n const option = target.closest('swp-theme-option');\n\n if (option) {\n const theme = option.dataset.theme as Theme;\n if (theme) {\n this.set(theme);\n }\n }\n }\n\n private handleSystemChange(): void {\n // Only react to system changes if we're using system preference\n if (this.current === 'system') {\n this.updateUI();\n }\n }\n}\n", "/**\n * Search Controller\n *\n * Handles global search functionality and keyboard shortcuts\n */\n\nexport class SearchController {\n private input: HTMLInputElement | null = null;\n private container: HTMLElement | null = null;\n\n constructor() {\n this.input = document.getElementById('globalSearch') as HTMLInputElement | null;\n this.container = document.querySelector('swp-topbar-search');\n\n this.setupListeners();\n }\n\n /**\n * Get current search value\n */\n get value(): string {\n return this.input?.value ?? '';\n }\n\n /**\n * Set search value\n */\n set value(val: string) {\n if (this.input) {\n this.input.value = val;\n }\n }\n\n /**\n * Focus the search input\n */\n focus(): void {\n this.input?.focus();\n }\n\n /**\n * Blur the search input\n */\n blur(): void {\n this.input?.blur();\n }\n\n /**\n * Clear the search input\n */\n clear(): void {\n this.value = '';\n }\n\n private setupListeners(): void {\n // Keyboard shortcuts\n document.addEventListener('keydown', (e) => this.handleKeyboard(e));\n\n // Input handlers\n if (this.input) {\n this.input.addEventListener('input', (e) => this.handleInput(e));\n\n // Prevent form submission if wrapped in form\n const form = this.input.closest('form');\n form?.addEventListener('submit', (e) => this.handleSubmit(e));\n }\n }\n\n private handleKeyboard(e: KeyboardEvent): void {\n // Cmd/Ctrl + K to focus search\n if ((e.metaKey || e.ctrlKey) && e.key === 'k') {\n e.preventDefault();\n this.focus();\n return;\n }\n\n // Escape to blur search when focused\n if (e.key === 'Escape' && document.activeElement === this.input) {\n this.blur();\n }\n }\n\n private handleInput(e: Event): void {\n const target = e.target as HTMLInputElement;\n const query = target.value.trim();\n\n // Emit custom event for search\n document.dispatchEvent(new CustomEvent('app:search', {\n detail: { query },\n bubbles: true\n }));\n }\n\n private handleSubmit(e: Event): void {\n e.preventDefault();\n\n const query = this.value.trim();\n if (!query) return;\n\n // Emit custom event for search submit\n document.dispatchEvent(new CustomEvent('app:search-submit', {\n detail: { query },\n bubbles: true\n }));\n }\n}\n", "/**\n * Lock Screen Controller\n *\n * Handles PIN-based lock screen functionality\n */\n\nimport { DrawerController } from './drawers';\n\nexport class LockScreenController {\n private static readonly CORRECT_PIN = '1234'; // Demo PIN\n\n private lockScreen: HTMLElement | null = null;\n private pinInput: HTMLElement | null = null;\n private pinKeypad: HTMLElement | null = null;\n private lockTimeEl: HTMLElement | null = null;\n private pinDigits: NodeListOf | null = null;\n private currentPin = '';\n private drawers: DrawerController | null = null;\n\n constructor(drawers?: DrawerController) {\n this.drawers = drawers ?? null;\n this.lockScreen = document.getElementById('lockScreen');\n this.pinInput = document.getElementById('pinInput');\n this.pinKeypad = document.getElementById('pinKeypad');\n this.lockTimeEl = document.getElementById('lockTime');\n this.pinDigits = this.pinInput?.querySelectorAll('swp-pin-digit') ?? null;\n\n this.setupListeners();\n }\n\n /**\n * Check if lock screen is active\n */\n get isActive(): boolean {\n return this.lockScreen?.classList.contains('active') ?? false;\n }\n\n /**\n * Show the lock screen\n */\n show(): void {\n this.drawers?.closeAll();\n\n if (this.lockScreen) {\n this.lockScreen.classList.add('active');\n document.body.style.overflow = 'hidden';\n }\n\n this.currentPin = '';\n this.updateDisplay();\n\n // Update lock time\n if (this.lockTimeEl) {\n this.lockTimeEl.textContent = `L\u00E5st kl. ${this.formatTime()}`;\n }\n }\n\n /**\n * Hide the lock screen\n */\n hide(): void {\n if (this.lockScreen) {\n this.lockScreen.classList.remove('active');\n document.body.style.overflow = '';\n }\n\n this.currentPin = '';\n this.updateDisplay();\n }\n\n private formatTime(): string {\n const now = new Date();\n const hours = now.getHours().toString().padStart(2, '0');\n const minutes = now.getMinutes().toString().padStart(2, '0');\n return `${hours}:${minutes}`;\n }\n\n private updateDisplay(): void {\n if (!this.pinDigits) return;\n\n this.pinDigits.forEach((digit, index) => {\n digit.classList.remove('filled', 'error');\n if (index < this.currentPin.length) {\n digit.textContent = '\u2022';\n digit.classList.add('filled');\n } else {\n digit.textContent = '';\n }\n });\n }\n\n private showError(): void {\n if (!this.pinDigits) return;\n\n this.pinDigits.forEach(digit => digit.classList.add('error'));\n\n // Shake animation\n this.pinInput?.classList.add('shake');\n\n setTimeout(() => {\n this.currentPin = '';\n this.updateDisplay();\n this.pinInput?.classList.remove('shake');\n }, 500);\n }\n\n private verify(): void {\n if (this.currentPin === LockScreenController.CORRECT_PIN) {\n this.hide();\n } else {\n this.showError();\n }\n }\n\n private addDigit(digit: string): void {\n if (this.currentPin.length >= 4) return;\n\n this.currentPin += digit;\n this.updateDisplay();\n\n // Auto-verify when 4 digits entered\n if (this.currentPin.length === 4) {\n setTimeout(() => this.verify(), 200);\n }\n }\n\n private removeDigit(): void {\n if (this.currentPin.length === 0) return;\n this.currentPin = this.currentPin.slice(0, -1);\n this.updateDisplay();\n }\n\n private clearPin(): void {\n this.currentPin = '';\n this.updateDisplay();\n }\n\n private setupListeners(): void {\n // Keypad click handler\n this.pinKeypad?.addEventListener('click', (e) => this.handleKeypadClick(e));\n\n // Keyboard input\n document.addEventListener('keydown', (e) => this.handleKeyboard(e));\n\n // Lock button in sidebar\n document.querySelector('swp-side-menu-action.lock')\n ?.addEventListener('click', () => this.show());\n }\n\n private handleKeypadClick(e: Event): void {\n const target = e.target as HTMLElement;\n const key = target.closest('swp-pin-key');\n\n if (!key) return;\n\n const digit = key.dataset.digit;\n const action = key.dataset.action;\n\n if (digit) {\n this.addDigit(digit);\n } else if (action === 'backspace') {\n this.removeDigit();\n } else if (action === 'clear') {\n this.clearPin();\n }\n }\n\n private handleKeyboard(e: KeyboardEvent): void {\n if (!this.isActive) return;\n\n // Prevent default to avoid other interactions\n e.preventDefault();\n\n if (e.key >= '0' && e.key <= '9') {\n this.addDigit(e.key);\n } else if (e.key === 'Backspace') {\n this.removeDigit();\n } else if (e.key === 'Escape') {\n this.clearPin();\n }\n }\n}\n", "/**\n * Cash Controller\n *\n * Handles tab switching, cash calculations, and form interactions\n * for the Cash Register page.\n */\n\nexport class CashController {\n // Base values (from system - would come from server in real app)\n private readonly startBalance = 2000;\n private readonly cashSales = 3540;\n\n constructor() {\n this.setupTabs();\n this.setupCashCalculation();\n this.setupCheckboxSelection();\n this.setupApprovalCheckbox();\n this.setupDateFilters();\n this.setupRowToggle();\n this.setupDraftRowClick();\n }\n\n /**\n * Setup tab switching functionality\n */\n private setupTabs(): void {\n const tabs = document.querySelectorAll('swp-tab[data-tab]');\n\n tabs.forEach(tab => {\n tab.addEventListener('click', () => {\n const targetTab = tab.dataset.tab;\n if (targetTab) {\n this.switchToTab(targetTab);\n }\n });\n });\n }\n\n /**\n * Switch to a specific tab by name\n */\n private switchToTab(targetTab: string): void {\n const tabs = document.querySelectorAll('swp-tab[data-tab]');\n const contents = document.querySelectorAll('swp-tab-content[data-tab]');\n const statsBars = document.querySelectorAll('swp-cash-stats[data-for-tab]');\n\n // Update tab states\n tabs.forEach(t => {\n if (t.dataset.tab === targetTab) {\n t.classList.add('active');\n } else {\n t.classList.remove('active');\n }\n });\n\n // Update content visibility\n contents.forEach(content => {\n if (content.dataset.tab === targetTab) {\n content.classList.add('active');\n } else {\n content.classList.remove('active');\n }\n });\n\n // Update stats bar visibility\n statsBars.forEach(stats => {\n if (stats.dataset.forTab === targetTab) {\n stats.classList.add('active');\n } else {\n stats.classList.remove('active');\n }\n });\n }\n\n /**\n * Setup cash calculation with real-time updates\n */\n private setupCashCalculation(): void {\n const payoutsInput = document.getElementById('payouts') as HTMLInputElement;\n const toBankInput = document.getElementById('toBank') as HTMLInputElement;\n const actualCashInput = document.getElementById('actualCash') as HTMLInputElement;\n\n if (!payoutsInput || !toBankInput || !actualCashInput) return;\n\n const calculate = () => this.calculateCash(payoutsInput, toBankInput, actualCashInput);\n\n payoutsInput.addEventListener('input', calculate);\n toBankInput.addEventListener('input', calculate);\n actualCashInput.addEventListener('input', calculate);\n\n // Initial calculation\n calculate();\n }\n\n /**\n * Calculate expected cash and difference\n */\n private calculateCash(\n payoutsInput: HTMLInputElement,\n toBankInput: HTMLInputElement,\n actualCashInput: HTMLInputElement\n ): void {\n const payouts = this.parseNumber(payoutsInput.value);\n const toBank = this.parseNumber(toBankInput.value);\n const actual = this.parseNumber(actualCashInput.value);\n\n // Expected = start + sales - payouts - to bank\n const expectedCash = this.startBalance + this.cashSales - payouts - toBank;\n\n const expectedElement = document.getElementById('expectedCash');\n if (expectedElement) {\n expectedElement.textContent = this.formatNumber(expectedCash);\n }\n\n // Calculate and display difference\n this.updateDifference(actual, expectedCash, actualCashInput.value);\n }\n\n /**\n * Update difference box with color coding\n */\n private updateDifference(actual: number, expected: number, rawValue: string): void {\n const box = document.getElementById('differenceBox');\n const value = document.getElementById('differenceValue');\n if (!box || !value) return;\n\n const diff = actual - expected;\n\n // Remove all state classes\n box.classList.remove('positive', 'negative', 'neutral');\n\n if (actual === 0 && rawValue === '') {\n // No input yet\n value.textContent = '\u2013 kr';\n box.classList.add('neutral');\n } else if (diff > 0) {\n // More cash than expected\n value.textContent = '+' + this.formatNumber(diff) + ' kr';\n box.classList.add('positive');\n } else if (diff < 0) {\n // Less cash than expected\n value.textContent = this.formatNumber(diff) + ' kr';\n box.classList.add('negative');\n } else {\n // Exact match\n value.textContent = '0,00 kr';\n box.classList.add('neutral');\n }\n }\n\n /**\n * Setup checkbox selection for table rows\n */\n private setupCheckboxSelection(): void {\n const selectAll = document.getElementById('selectAll') as HTMLInputElement;\n const rowCheckboxes = document.querySelectorAll('.row-select');\n const exportBtn = document.getElementById('exportBtn') as HTMLButtonElement;\n const selectionCount = document.getElementById('selectionCount');\n\n if (!selectAll || !exportBtn || !selectionCount) return;\n\n const updateSelection = () => {\n const checked = document.querySelectorAll('.row-select:checked');\n const count = checked.length;\n\n selectionCount.textContent = count === 0 ? '0 valgt' : `${count} valgt`;\n exportBtn.disabled = count === 0;\n\n // Update select all state\n selectAll.checked = count === rowCheckboxes.length && count > 0;\n selectAll.indeterminate = count > 0 && count < rowCheckboxes.length;\n };\n\n selectAll.addEventListener('change', () => {\n rowCheckboxes.forEach(cb => cb.checked = selectAll.checked);\n updateSelection();\n });\n\n rowCheckboxes.forEach(cb => {\n cb.addEventListener('change', updateSelection);\n // Stop click from bubbling to row\n cb.addEventListener('click', e => e.stopPropagation());\n });\n }\n\n /**\n * Setup approval checkbox to enable/disable approve button\n */\n private setupApprovalCheckbox(): void {\n const checkbox = document.getElementById('confirmCheckbox') as HTMLInputElement;\n const approveBtn = document.getElementById('approveBtn') as HTMLButtonElement;\n\n if (!checkbox || !approveBtn) return;\n\n checkbox.addEventListener('change', () => {\n approveBtn.disabled = !checkbox.checked;\n });\n }\n\n /**\n * Setup date filter defaults (last 30 days)\n */\n private setupDateFilters(): void {\n const dateFrom = document.getElementById('dateFrom') as HTMLInputElement;\n const dateTo = document.getElementById('dateTo') as HTMLInputElement;\n\n if (!dateFrom || !dateTo) return;\n\n const today = new Date();\n const thirtyDaysAgo = new Date(today);\n thirtyDaysAgo.setDate(today.getDate() - 30);\n\n dateTo.value = this.formatDateISO(today);\n dateFrom.value = this.formatDateISO(thirtyDaysAgo);\n }\n\n /**\n * Format number as Danish currency\n */\n private formatNumber(num: number): string {\n return num.toLocaleString('da-DK', {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2\n });\n }\n\n /**\n * Parse Danish number format\n */\n private parseNumber(str: string): number {\n if (!str) return 0;\n return parseFloat(str.replace(/\\./g, '').replace(',', '.')) || 0;\n }\n\n /**\n * Format date as ISO string (YYYY-MM-DD)\n */\n private formatDateISO(date: Date): string {\n return date.toISOString().split('T')[0];\n }\n\n /**\n * Setup row toggle for expandable details\n */\n private setupRowToggle(): void {\n const rows = document.querySelectorAll('swp-cash-table-row[data-id]:not(.draft-row)');\n\n rows.forEach(row => {\n const rowId = row.getAttribute('data-id');\n if (!rowId) return;\n\n const detail = document.querySelector(`swp-cash-row-detail[data-for=\"${rowId}\"]`);\n if (!detail) return;\n\n row.addEventListener('click', (e) => {\n // Don't toggle if clicking on checkbox\n if ((e.target as HTMLElement).closest('input[type=\"checkbox\"]')) return;\n\n const icon = row.querySelector('swp-row-toggle i');\n const isExpanded = row.classList.contains('expanded');\n\n // Close other expanded rows\n document.querySelectorAll('swp-cash-table-row.expanded').forEach(r => {\n if (r !== row) {\n const otherId = r.getAttribute('data-id');\n if (otherId) {\n const otherDetail = document.querySelector(`swp-cash-row-detail[data-for=\"${otherId}\"]`);\n const otherIcon = r.querySelector('swp-row-toggle i');\n if (otherDetail && otherIcon) {\n this.collapseRow(r, otherDetail, otherIcon as HTMLElement);\n }\n }\n }\n });\n\n // Toggle current row\n if (isExpanded) {\n this.collapseRow(row, detail, icon);\n } else {\n this.expandRow(row, detail, icon);\n }\n });\n });\n }\n\n /**\n * Expand a row with animation\n */\n private expandRow(row: Element, detail: HTMLElement, icon: Element | null): void {\n row.classList.add('expanded');\n detail.classList.add('expanded');\n\n // Animate icon rotation\n icon?.animate([\n { transform: 'rotate(0deg)' },\n { transform: 'rotate(90deg)' }\n ], {\n duration: 200,\n easing: 'ease-out',\n fill: 'forwards'\n });\n\n // Animate detail expansion\n const content = detail.querySelector('swp-row-detail-content') as HTMLElement;\n if (content) {\n const height = content.offsetHeight;\n detail.animate([\n { height: '0px', opacity: 0 },\n { height: `${height}px`, opacity: 1 }\n ], {\n duration: 250,\n easing: 'ease-out',\n fill: 'forwards'\n });\n }\n }\n\n /**\n * Collapse a row with animation\n */\n private collapseRow(row: Element, detail: HTMLElement, icon: Element | null): void {\n // Animate icon rotation\n icon?.animate([\n { transform: 'rotate(90deg)' },\n { transform: 'rotate(0deg)' }\n ], {\n duration: 200,\n easing: 'ease-out',\n fill: 'forwards'\n });\n\n // Animate detail collapse\n const content = detail.querySelector('swp-row-detail-content') as HTMLElement;\n if (content) {\n const height = content.offsetHeight;\n const animation = detail.animate([\n { height: `${height}px`, opacity: 1 },\n { height: '0px', opacity: 0 }\n ], {\n duration: 200,\n easing: 'ease-out',\n fill: 'forwards'\n });\n\n animation.onfinish = () => {\n row.classList.remove('expanded');\n detail.classList.remove('expanded');\n };\n } else {\n row.classList.remove('expanded');\n detail.classList.remove('expanded');\n }\n }\n\n /**\n * Setup draft row click to navigate to reconciliation tab\n */\n private setupDraftRowClick(): void {\n const draftRow = document.querySelector('swp-cash-table-row.draft-row');\n if (!draftRow) return;\n\n draftRow.style.cursor = 'pointer';\n draftRow.addEventListener('click', (e) => {\n // Don't navigate if clicking on checkbox\n if ((e.target as HTMLElement).closest('input[type=\"checkbox\"]')) return;\n\n this.switchToTab('afstemning');\n });\n }\n}\n", "/**\n * Employees Controller\n *\n * Handles content swap between list view and detail view,\n * plus tab switching within each view.\n * Uses History API for browser back/forward navigation.\n */\n\nexport class EmployeesController {\n private ratesSync: RatesSyncController | null = null;\n private listView: HTMLElement | null = null;\n private detailView: HTMLElement | null = null;\n\n constructor() {\n this.listView = document.getElementById('employees-list-view');\n this.detailView = document.getElementById('employee-detail-view');\n\n // Only initialize if we're on the employees page\n if (!this.listView) return;\n\n this.setupListTabs();\n this.setupDetailTabs();\n this.setupChevronNavigation();\n this.setupBackNavigation();\n this.setupHistoryNavigation();\n this.restoreStateFromUrl();\n this.ratesSync = new RatesSyncController();\n }\n\n /**\n * Setup popstate listener for browser back/forward\n */\n private setupHistoryNavigation(): void {\n window.addEventListener('popstate', (e: PopStateEvent) => {\n if (e.state?.employeeKey) {\n this.showDetailViewInternal(e.state.employeeKey);\n } else {\n this.showListViewInternal();\n }\n });\n }\n\n /**\n * Restore view state from URL on page load\n */\n private restoreStateFromUrl(): void {\n const hash = window.location.hash;\n if (hash.startsWith('#employee-')) {\n const employeeKey = hash.substring(1); // Remove #\n this.showDetailViewInternal(employeeKey);\n }\n }\n\n /**\n * Setup tab switching for the list view\n */\n private setupListTabs(): void {\n if (!this.listView) return;\n\n const tabs = this.listView.querySelectorAll('swp-tab-bar > swp-tab[data-tab]');\n\n tabs.forEach(tab => {\n tab.addEventListener('click', () => {\n const targetTab = tab.dataset.tab;\n if (targetTab) {\n this.switchTab(this.listView!, targetTab);\n }\n });\n });\n }\n\n /**\n * Setup tab switching for the detail view\n */\n private setupDetailTabs(): void {\n if (!this.detailView) return;\n\n const tabs = this.detailView.querySelectorAll('swp-tab-bar > swp-tab[data-tab]');\n\n tabs.forEach(tab => {\n tab.addEventListener('click', () => {\n const targetTab = tab.dataset.tab;\n if (targetTab) {\n this.switchTab(this.detailView!, targetTab);\n }\n });\n });\n }\n\n /**\n * Switch to a specific tab within a container\n */\n private switchTab(container: HTMLElement, targetTab: string): void {\n const tabs = container.querySelectorAll('swp-tab-bar > swp-tab[data-tab]');\n const contents = container.querySelectorAll('swp-tab-content[data-tab]');\n\n tabs.forEach(t => {\n t.classList.toggle('active', t.dataset.tab === targetTab);\n });\n\n contents.forEach(content => {\n content.classList.toggle('active', content.dataset.tab === targetTab);\n });\n }\n\n /**\n * Setup row click to show detail view\n * Ignores clicks on action buttons\n */\n private setupChevronNavigation(): void {\n document.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n\n // Ignore clicks on action buttons\n if (target.closest('swp-icon-btn') || target.closest('swp-table-actions')) {\n return;\n }\n\n const row = target.closest('swp-employee-row[data-employee-detail]');\n\n if (row) {\n const employeeKey = row.dataset.employeeDetail;\n if (employeeKey) {\n this.showDetailView(employeeKey);\n }\n }\n });\n }\n\n /**\n * Setup back button to return to list view\n */\n private setupBackNavigation(): void {\n document.addEventListener('click', (e: Event) => {\n const target = e.target as HTMLElement;\n const backLink = target.closest('[data-employee-back]');\n\n if (backLink) {\n this.showListView();\n }\n });\n }\n\n /**\n * Show the detail view and hide list view (with history push)\n */\n private showDetailView(employeeKey: string): void {\n // Push state to history\n history.pushState(\n { employeeKey },\n '',\n `#${employeeKey}`\n );\n this.showDetailViewInternal(employeeKey);\n }\n\n /**\n * Show detail view without modifying history (for popstate)\n */\n private showDetailViewInternal(employeeKey: string): void {\n if (this.listView && this.detailView) {\n this.listView.style.display = 'none';\n this.detailView.style.display = 'block';\n this.detailView.dataset.employee = employeeKey;\n\n // Reset to first tab\n this.switchTab(this.detailView, 'general');\n }\n }\n\n /**\n * Show the list view and hide detail view (with history push)\n */\n private showListView(): void {\n // Push state to history (clear hash)\n history.pushState(\n {},\n '',\n window.location.pathname\n );\n this.showListViewInternal();\n }\n\n /**\n * Show list view without modifying history (for popstate)\n */\n private showListViewInternal(): void {\n if (this.listView && this.detailView) {\n this.detailView.style.display = 'none';\n this.listView.style.display = 'block';\n }\n }\n}\n\n/**\n * Rates Sync Controller\n *\n * Syncs changes between the rates drawer and the salary tab cards.\n * Uses ID-based lookups:\n * - Checkbox: id=\"rate-{key}-enabled\"\n * - Text input: id=\"rate-{key}\"\n * - Card row: id=\"card-{key}\"\n */\nclass RatesSyncController {\n private drawer: HTMLElement | null = null;\n\n constructor() {\n this.drawer = document.getElementById('rates-drawer');\n\n if (!this.drawer) return;\n\n this.setupCheckboxListeners();\n this.setupInputListeners();\n }\n\n /**\n * Extract rate key from checkbox ID (e.g., \"rate-normal-enabled\" \u2192 \"normal\")\n */\n private extractRateKey(checkboxId: string): string | null {\n const match = checkboxId.match(/^rate-(.+)-enabled$/);\n return match ? match[1] : null;\n }\n\n /**\n * Setup checkbox change listeners in drawer\n */\n private setupCheckboxListeners(): void {\n if (!this.drawer) return;\n\n this.drawer.addEventListener('change', (e: Event) => {\n const target = e.target as HTMLInputElement;\n if (target.type !== 'checkbox' || !target.id) return;\n\n const rateKey = this.extractRateKey(target.id);\n if (!rateKey) return;\n\n const isChecked = target.checked;\n const row = target.closest('swp-data-row');\n if (!row) return;\n\n // Toggle disabled class in drawer row\n const label = row.querySelector('swp-data-label');\n const input = row.querySelector('swp-data-input');\n if (label) label.classList.toggle('disabled', !isChecked);\n if (input) input.classList.toggle('disabled', !isChecked);\n\n // Toggle visibility in card\n this.toggleCardRow(rateKey, isChecked);\n\n // If enabling, also sync the current value\n if (isChecked) {\n const textInput = document.getElementById(`rate-${rateKey}`) as HTMLInputElement | null;\n if (textInput) {\n this.syncValueToCard(rateKey, textInput.value);\n }\n }\n });\n }\n\n /**\n * Setup input change listeners in drawer\n */\n private setupInputListeners(): void {\n if (!this.drawer) return;\n\n this.drawer.addEventListener('input', (e: Event) => {\n const target = e.target as HTMLInputElement;\n if (target.type !== 'text' || !target.id) return;\n\n // Extract rate key from input ID (e.g., \"rate-normal\" \u2192 \"normal\")\n const match = target.id.match(/^rate-(.+)$/);\n if (!match) return;\n\n const rateKey = match[1];\n // Skip if this matches the checkbox pattern\n if (rateKey.endsWith('-enabled')) return;\n\n this.syncValueToCard(rateKey, target.value);\n });\n }\n\n /**\n * Toggle card row visibility by ID\n */\n private toggleCardRow(rateKey: string, visible: boolean): void {\n const cardRow = document.getElementById(`card-${rateKey}`);\n if (cardRow) {\n cardRow.style.display = visible ? '' : 'none';\n }\n }\n\n /**\n * Format number with 2 decimals using Danish locale (comma as decimal separator)\n */\n private formatNumber(value: string): string {\n // Parse the input (handle both dot and comma as decimal separator)\n const normalized = value.replace(',', '.');\n const num = parseFloat(normalized);\n\n if (isNaN(num)) return value;\n\n // Format with 2 decimals and comma as decimal separator\n return num.toFixed(2).replace('.', ',');\n }\n\n /**\n * Sync value from drawer to card by ID\n */\n private syncValueToCard(rateKey: string, value: string): void {\n const cardInput = document.getElementById(`value-${rateKey}`) as HTMLInputElement | null;\n if (!cardInput) return;\n\n // Get the unit from drawer input container\n const textInput = document.getElementById(`rate-${rateKey}`);\n const inputContainer = textInput?.closest('swp-data-input');\n const unit = inputContainer?.textContent?.trim().replace(value, '').trim() || 'kr';\n\n // Format with 2 decimals\n const formattedValue = this.formatNumber(value);\n cardInput.value = `${formattedValue} ${unit}`;\n }\n}\n", "/**\n * Salon OS App\n *\n * Main application class that orchestrates all UI controllers\n */\n\nimport { SidebarController } from './modules/sidebar';\nimport { DrawerController } from './modules/drawers';\nimport { ThemeController } from './modules/theme';\nimport { SearchController } from './modules/search';\nimport { LockScreenController } from './modules/lockscreen';\nimport { CashController } from './modules/cash';\nimport { EmployeesController } from './modules/employees';\n\n/**\n * Main application class\n */\nexport class App {\n readonly sidebar: SidebarController;\n readonly drawers: DrawerController;\n readonly theme: ThemeController;\n readonly search: SearchController;\n readonly lockScreen: LockScreenController;\n readonly cash: CashController;\n readonly employees: EmployeesController;\n\n constructor() {\n // Initialize controllers\n this.sidebar = new SidebarController();\n this.drawers = new DrawerController();\n this.theme = new ThemeController();\n this.search = new SearchController();\n this.lockScreen = new LockScreenController(this.drawers);\n this.cash = new CashController();\n this.employees = new EmployeesController();\n }\n}\n\n/**\n * Global app instance\n */\nlet app: App;\n\n/**\n * Initialize the application\n */\nfunction init(): void {\n app = new App();\n\n // Expose to window for debugging\n if (typeof window !== 'undefined') {\n (window as unknown as { app: App }).app = app;\n }\n}\n\n// Wait for DOM ready\nif (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init);\n} else {\n init();\n}\n\nexport { app };\nexport default App;\n"], - "mappings": ";;;AAMO,MAAM,oBAAN,MAAwB;AAAA,IAK7B,cAAc;AAJd,WAAQ,aAAiC;AACzC,WAAQ,YAAgC;AACxC,WAAQ,cAAkC;AAGxC,WAAK,aAAa,SAAS,eAAe,YAAY;AACtD,WAAK,YAAY,SAAS,cAAc,gBAAgB;AACxD,WAAK,cAAc,SAAS,eAAe,aAAa;AAExD,WAAK,eAAe;AACpB,WAAK,cAAc;AACnB,WAAK,aAAa;AAAA,IACpB;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,cAAuB;AACzB,aAAO,KAAK,WAAW,UAAU,SAAS,gBAAgB,KAAK;AAAA,IACjE;AAAA;AAAA;AAAA;AAAA,IAKA,SAAe;AACb,UAAI,CAAC,KAAK,UAAW;AAErB,WAAK,UAAU,UAAU,OAAO,gBAAgB;AAChD,mBAAa,QAAQ,qBAAqB,OAAO,KAAK,WAAW,CAAC;AAAA,IACpE;AAAA;AAAA;AAAA;AAAA,IAKA,WAAiB;AACf,WAAK,WAAW,UAAU,IAAI,gBAAgB;AAC9C,mBAAa,QAAQ,qBAAqB,MAAM;AAAA,IAClD;AAAA;AAAA;AAAA;AAAA,IAKA,SAAe;AACb,WAAK,WAAW,UAAU,OAAO,gBAAgB;AACjD,mBAAa,QAAQ,qBAAqB,OAAO;AAAA,IACnD;AAAA,IAEQ,iBAAuB;AAC7B,WAAK,YAAY,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AAAA,IAChE;AAAA,IAEQ,gBAAsB;AAC5B,UAAI,CAAC,KAAK,YAAa;AAEvB,YAAM,YAAY,SAAS,iBAA8B,kCAAkC;AAE3F,gBAAU,QAAQ,UAAQ;AACxB,aAAK,iBAAiB,cAAc,MAAM,KAAK,YAAY,IAAI,CAAC;AAChE,aAAK,iBAAiB,cAAc,MAAM,KAAK,YAAY,CAAC;AAAA,MAC9D,CAAC;AAAA,IACH;AAAA,IAEQ,YAAY,MAAyB;AAC3C,UAAI,CAAC,KAAK,eAAe,CAAC,KAAK,YAAa;AAE5C,YAAM,OAAO,KAAK,sBAAsB;AACxC,YAAM,cAAc,KAAK,QAAQ;AAEjC,UAAI,CAAC,YAAa;AAElB,WAAK,YAAY,cAAc;AAC/B,WAAK,YAAY,MAAM,OAAO,GAAG,KAAK,QAAQ,CAAC;AAC/C,WAAK,YAAY,MAAM,MAAM,GAAG,KAAK,MAAM,KAAK,SAAS,CAAC;AAC1D,WAAK,YAAY,MAAM,YAAY;AACnC,WAAK,YAAY,YAAY;AAAA,IAC/B;AAAA,IAEQ,cAAoB;AAC1B,WAAK,aAAa,YAAY;AAAA,IAChC;AAAA,IAEQ,eAAqB;AAC3B,UAAI,CAAC,KAAK,UAAW;AAErB,UAAI,aAAa,QAAQ,mBAAmB,MAAM,QAAQ;AACxD,aAAK,UAAU,UAAU,IAAI,gBAAgB;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;;;ACvFO,MAAM,mBAAN,MAAuB;AAAA,IAS5B,cAAc;AARd,WAAQ,gBAAoC;AAC5C,WAAQ,qBAAyC;AACjD,WAAQ,aAAiC;AACzC,WAAQ,gBAAoC;AAC5C,WAAQ,UAA8B;AACtC,WAAQ,eAAkC;AAC1C,WAAQ,sBAA0C;AAGhD,WAAK,gBAAgB,SAAS,eAAe,eAAe;AAC5D,WAAK,qBAAqB,SAAS,eAAe,oBAAoB;AACtE,WAAK,aAAa,SAAS,eAAe,YAAY;AACtD,WAAK,gBAAgB,SAAS,eAAe,eAAe;AAC5D,WAAK,UAAU,SAAS,eAAe,eAAe;AAEtD,WAAK,eAAe;AACpB,WAAK,oBAAoB;AAAA,IAC3B;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,SAA4B;AAC9B,aAAO,KAAK;AAAA,IACd;AAAA;AAAA;AAAA;AAAA,IAKA,KAAK,MAAwB;AAC3B,WAAK,SAAS;AAEd,YAAM,SAAS,KAAK,UAAU,IAAI;AAClC,UAAI,UAAU,KAAK,SAAS;AAC1B,eAAO,UAAU,IAAI,QAAQ;AAC7B,aAAK,QAAQ,UAAU,IAAI,QAAQ;AACnC,iBAAS,KAAK,MAAM,WAAW;AAC/B,aAAK,eAAe;AAAA,MACtB;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,MAAwB;AAC5B,YAAM,SAAS,KAAK,UAAU,IAAI;AAClC,cAAQ,UAAU,OAAO,QAAQ;AAGjC,UAAI,KAAK,WAAW,CAAC,SAAS,cAAc,0BAA0B,GAAG;AACvE,aAAK,QAAQ,UAAU,OAAO,QAAQ;AACtC,iBAAS,KAAK,MAAM,WAAW;AAAA,MACjC;AAEA,UAAI,KAAK,iBAAiB,MAAM;AAC9B,aAAK,eAAe;AAAA,MACtB;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,WAAiB;AACf,OAAC,KAAK,eAAe,KAAK,oBAAoB,KAAK,YAAY,KAAK,aAAa,EAC9E,QAAQ,YAAU,QAAQ,UAAU,OAAO,QAAQ,CAAC;AAGvD,WAAK,mBAAmB;AAExB,WAAK,SAAS,UAAU,OAAO,QAAQ;AACvC,eAAS,KAAK,MAAM,WAAW;AAC/B,WAAK,eAAe;AAAA,IACtB;AAAA;AAAA;AAAA;AAAA,IAKA,kBAAkB,UAAwB;AACxC,WAAK,SAAS;AAEd,YAAM,SAAS,SAAS,eAAe,QAAQ;AAC/C,UAAI,UAAU,KAAK,SAAS;AAC1B,eAAO,UAAU,IAAI,MAAM;AAC3B,aAAK,QAAQ,UAAU,IAAI,QAAQ;AACnC,iBAAS,KAAK,MAAM,WAAW;AAC/B,aAAK,sBAAsB;AAAA,MAC7B;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,qBAA2B;AACzB,WAAK,qBAAqB,UAAU,OAAO,MAAM;AACjD,WAAK,sBAAsB;AAAA,IAC7B;AAAA;AAAA;AAAA;AAAA,IAKA,cAAoB;AAClB,WAAK,KAAK,SAAS;AAAA,IACrB;AAAA;AAAA;AAAA;AAAA,IAKA,mBAAyB;AACvB,WAAK,KAAK,cAAc;AAAA,IAC1B;AAAA;AAAA;AAAA;AAAA,IAKA,WAAiB;AACf,WAAK,YAAY,UAAU,IAAI,QAAQ;AAAA,IACzC;AAAA;AAAA;AAAA;AAAA,IAKA,YAAkB;AAChB,WAAK,YAAY,UAAU,OAAO,QAAQ;AAC1C,WAAK,aAAa;AAAA,IACpB;AAAA;AAAA;AAAA;AAAA,IAKA,cAAoB;AAClB,WAAK,eAAe,UAAU,IAAI,QAAQ;AAAA,IAC5C;AAAA;AAAA;AAAA;AAAA,IAKA,eAAqB;AACnB,WAAK,eAAe,UAAU,OAAO,QAAQ;AAAA,IAC/C;AAAA;AAAA;AAAA;AAAA,IAKA,2BAAiC;AAC/B,UAAI,CAAC,KAAK,mBAAoB;AAE9B,YAAM,cAAc,KAAK,mBAAmB;AAAA,QAC1C;AAAA,MACF;AACA,kBAAY,QAAQ,UAAQ,KAAK,gBAAgB,aAAa,CAAC;AAE/D,YAAM,QAAQ,SAAS,cAA2B,wBAAwB;AAC1E,UAAI,OAAO;AACT,cAAM,MAAM,UAAU;AAAA,MACxB;AAAA,IACF;AAAA,IAEQ,UAAU,MAAsC;AACtD,cAAQ,MAAM;AAAA,QACZ,KAAK;AAAW,iBAAO,KAAK;AAAA,QAC5B,KAAK;AAAgB,iBAAO,KAAK;AAAA,QACjC,KAAK;AAAQ,iBAAO,KAAK;AAAA,QACzB,KAAK;AAAW,iBAAO,KAAK;AAAA,MAC9B;AAAA,IACF;AAAA,IAEQ,iBAAuB;AAE7B,eAAS,eAAe,gBAAgB,GACpC,iBAAiB,SAAS,MAAM,KAAK,YAAY,CAAC;AACtD,eAAS,eAAe,aAAa,GACjC,iBAAiB,SAAS,MAAM,KAAK,MAAM,SAAS,CAAC;AAGzD,eAAS,eAAe,kBAAkB,GACtC,iBAAiB,SAAS,MAAM,KAAK,iBAAiB,CAAC;AAC3D,eAAS,eAAe,yBAAyB,GAC7C,iBAAiB,SAAS,MAAM,KAAK,MAAM,cAAc,CAAC;AAC9D,eAAS,eAAe,aAAa,GACjC,iBAAiB,SAAS,MAAM,KAAK,yBAAyB,CAAC;AAGnE,eAAS,eAAe,gBAAgB,GACpC,iBAAiB,SAAS,MAAM,KAAK,SAAS,CAAC;AACnD,eAAS,eAAe,gBAAgB,GACpC,iBAAiB,SAAS,MAAM,KAAK,UAAU,CAAC;AAGpD,eAAS,eAAe,YAAY,GAChC,iBAAiB,SAAS,MAAM,KAAK,YAAY,CAAC;AACtD,eAAS,eAAe,mBAAmB,GACvC,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AACvD,eAAS,eAAe,eAAe,GACnC,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AACvD,eAAS,eAAe,aAAa,GACjC,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AAGvD,WAAK,SAAS,iBAAiB,SAAS,MAAM,KAAK,SAAS,CAAC;AAG7D,eAAS,iBAAiB,WAAW,CAAC,MAAqB;AACzD,YAAI,EAAE,QAAQ,SAAU,MAAK,SAAS;AAAA,MACxC,CAAC;AAGD,WAAK,YAAY,iBAAiB,SAAS,CAAC,MAAM,KAAK,gBAAgB,CAAC,CAAC;AAGzE,eAAS,iBAAiB,SAAS,CAAC,MAAM,KAAK,sBAAsB,CAAC,CAAC;AAAA,IACzE;AAAA,IAEQ,gBAAgB,GAAgB;AACtC,YAAM,SAAS,EAAE;AACjB,YAAM,WAAW,OAAO,QAAqB,eAAe;AAC5D,YAAM,WAAW,OAAO,QAAqB,mBAAmB;AAEhE,UAAI,YAAY,UAAU;AACxB,cAAM,cAAc,SAAS,QAAQ,cAAc;AACnD,YAAI,aAAa;AACf,mBAAS,gBAAgB,gBAAgB;AAAA,QAC3C,OAAO;AACL,mBAAS,QAAQ,YAAY;AAAA,QAC/B;AAAA,MACF;AAGA,YAAM,gBAAgB,OAAO,QAAqB,yBAAyB;AAC3E,UAAI,eAAe;AACjB,cAAM,UAAU,cAAc,QAAqB,kBAAkB;AACrE,iBAAS,UAAU,OAAO,WAAW;AAAA,MACvC;AAAA,IACF;AAAA,IAEQ,sBAAsB,GAAgB;AAC5C,YAAM,SAAS,EAAE;AACjB,YAAM,SAAS,OAAO,QAAqB,uBAAuB;AAElE,UAAI,QAAQ;AACV,iBAAS,iBAA8B,uBAAuB,EAC3D,QAAQ,OAAK,EAAE,UAAU,OAAO,QAAQ,CAAC;AAC5C,eAAO,UAAU,IAAI,QAAQ;AAAA,MAC/B;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,IAMQ,sBAA4B;AAElC,eAAS,iBAAiB,SAAS,CAAC,MAAa;AAC/C,cAAM,SAAS,EAAE;AACjB,cAAM,UAAU,OAAO,QAAqB,uBAAuB;AAEnE,YAAI,SAAS;AACX,gBAAM,WAAW,QAAQ,QAAQ;AACjC,cAAI,UAAU;AACZ,iBAAK,kBAAkB,QAAQ;AAAA,UACjC;AAAA,QACF;AAAA,MACF,CAAC;AAGD,eAAS,iBAAiB,SAAS,CAAC,MAAa;AAC/C,cAAM,SAAS,EAAE;AACjB,cAAM,WAAW,OAAO,QAAqB,qBAAqB;AAElE,YAAI,UAAU;AACZ,eAAK,mBAAmB;AACxB,eAAK,SAAS,UAAU,OAAO,QAAQ;AACvC,mBAAS,KAAK,MAAM,WAAW;AAAA,QACjC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;;;ACpRO,MAAM,kBAAN,MAAM,iBAAgB;AAAA,IAC3B;AAAA,WAAwB,cAAc;AAAA;AAAA,IACtC;AAAA,WAAwB,aAAa;AAAA;AAAA,IACrC;AAAA,WAAwB,cAAc;AAAA;AAAA,IAKtC,cAAc;AACZ,WAAK,OAAO,SAAS;AACrB,WAAK,eAAe,SAAS,iBAA8B,kBAAkB;AAE7E,WAAK,WAAW,KAAK,OAAO;AAC5B,WAAK,SAAS;AACd,WAAK,eAAe;AAAA,IACtB;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,UAAiB;AACnB,YAAM,SAAS,aAAa,QAAQ,iBAAgB,WAAW;AAC/D,UAAI,WAAW,UAAU,WAAW,WAAW,WAAW,UAAU;AAClE,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,SAAkB;AACpB,aAAO,KAAK,KAAK,UAAU,SAAS,iBAAgB,UAAU,KAC3D,KAAK,qBAAqB,CAAC,KAAK,KAAK,UAAU,SAAS,iBAAgB,WAAW;AAAA,IACxF;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,oBAA6B;AAC/B,aAAO,OAAO,WAAW,8BAA8B,EAAE;AAAA,IAC3D;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,OAAoB;AACtB,mBAAa,QAAQ,iBAAgB,aAAa,KAAK;AACvD,WAAK,WAAW,KAAK;AACrB,WAAK,SAAS;AAAA,IAChB;AAAA;AAAA;AAAA;AAAA,IAKA,SAAe;AACb,WAAK,IAAI,KAAK,SAAS,UAAU,MAAM;AAAA,IACzC;AAAA,IAEQ,WAAW,OAAoB;AACrC,WAAK,KAAK,UAAU,OAAO,iBAAgB,YAAY,iBAAgB,WAAW;AAElF,UAAI,UAAU,QAAQ;AACpB,aAAK,KAAK,UAAU,IAAI,iBAAgB,UAAU;AAAA,MACpD,WAAW,UAAU,SAAS;AAC5B,aAAK,KAAK,UAAU,IAAI,iBAAgB,WAAW;AAAA,MACrD;AAAA,IAEF;AAAA,IAEQ,WAAiB;AACvB,UAAI,CAAC,KAAK,aAAc;AAExB,YAAM,aAAa,KAAK;AAExB,WAAK,aAAa,QAAQ,YAAU;AAClC,cAAM,QAAQ,OAAO,QAAQ;AAC7B,cAAM,WAAY,UAAU,UAAU,cAAgB,UAAU,WAAW,CAAC;AAC5E,eAAO,UAAU,OAAO,UAAU,QAAQ;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,IAEQ,iBAAuB;AAE7B,WAAK,aAAa,QAAQ,YAAU;AAClC,eAAO,iBAAiB,SAAS,CAAC,MAAM,KAAK,kBAAkB,CAAC,CAAC;AAAA,MACnE,CAAC;AAGD,aAAO,WAAW,8BAA8B,EAC7C,iBAAiB,UAAU,MAAM,KAAK,mBAAmB,CAAC;AAAA,IAC/D;AAAA,IAEQ,kBAAkB,GAAgB;AACxC,YAAM,SAAS,EAAE;AACjB,YAAM,SAAS,OAAO,QAAqB,kBAAkB;AAE7D,UAAI,QAAQ;AACV,cAAM,QAAQ,OAAO,QAAQ;AAC7B,YAAI,OAAO;AACT,eAAK,IAAI,KAAK;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,IAEQ,qBAA2B;AAEjC,UAAI,KAAK,YAAY,UAAU;AAC7B,aAAK,SAAS;AAAA,MAChB;AAAA,IACF;AAAA,EACF;;;ACjHO,MAAM,mBAAN,MAAuB;AAAA,IAI5B,cAAc;AAHd,WAAQ,QAAiC;AACzC,WAAQ,YAAgC;AAGtC,WAAK,QAAQ,SAAS,eAAe,cAAc;AACnD,WAAK,YAAY,SAAS,cAA2B,mBAAmB;AAExE,WAAK,eAAe;AAAA,IACtB;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,QAAgB;AAClB,aAAO,KAAK,OAAO,SAAS;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA,IAKA,IAAI,MAAM,KAAa;AACrB,UAAI,KAAK,OAAO;AACd,aAAK,MAAM,QAAQ;AAAA,MACrB;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,QAAc;AACZ,WAAK,OAAO,MAAM;AAAA,IACpB;AAAA;AAAA;AAAA;AAAA,IAKA,OAAa;AACX,WAAK,OAAO,KAAK;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA,IAKA,QAAc;AACZ,WAAK,QAAQ;AAAA,IACf;AAAA,IAEQ,iBAAuB;AAE7B,eAAS,iBAAiB,WAAW,CAAC,MAAM,KAAK,eAAe,CAAC,CAAC;AAGlE,UAAI,KAAK,OAAO;AACd,aAAK,MAAM,iBAAiB,SAAS,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AAG/D,cAAM,OAAO,KAAK,MAAM,QAAQ,MAAM;AACtC,cAAM,iBAAiB,UAAU,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC;AAAA,MAC9D;AAAA,IACF;AAAA,IAEQ,eAAe,GAAwB;AAE7C,WAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,KAAK;AAC7C,UAAE,eAAe;AACjB,aAAK,MAAM;AACX;AAAA,MACF;AAGA,UAAI,EAAE,QAAQ,YAAY,SAAS,kBAAkB,KAAK,OAAO;AAC/D,aAAK,KAAK;AAAA,MACZ;AAAA,IACF;AAAA,IAEQ,YAAY,GAAgB;AAClC,YAAM,SAAS,EAAE;AACjB,YAAM,QAAQ,OAAO,MAAM,KAAK;AAGhC,eAAS,cAAc,IAAI,YAAY,cAAc;AAAA,QACnD,QAAQ,EAAE,MAAM;AAAA,QAChB,SAAS;AAAA,MACX,CAAC,CAAC;AAAA,IACJ;AAAA,IAEQ,aAAa,GAAgB;AACnC,QAAE,eAAe;AAEjB,YAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,UAAI,CAAC,MAAO;AAGZ,eAAS,cAAc,IAAI,YAAY,qBAAqB;AAAA,QAC1D,QAAQ,EAAE,MAAM;AAAA,QAChB,SAAS;AAAA,MACX,CAAC,CAAC;AAAA,IACJ;AAAA,EACF;;;ACjGO,MAAM,uBAAN,MAAM,sBAAqB;AAAA,IAWhC,YAAY,SAA4B;AARxC;AAAA,WAAQ,aAAiC;AACzC,WAAQ,WAA+B;AACvC,WAAQ,YAAgC;AACxC,WAAQ,aAAiC;AACzC,WAAQ,YAA4C;AACpD,WAAQ,aAAa;AACrB,WAAQ,UAAmC;AAGzC,WAAK,UAAU,WAAW;AAC1B,WAAK,aAAa,SAAS,eAAe,YAAY;AACtD,WAAK,WAAW,SAAS,eAAe,UAAU;AAClD,WAAK,YAAY,SAAS,eAAe,WAAW;AACpD,WAAK,aAAa,SAAS,eAAe,UAAU;AACpD,WAAK,YAAY,KAAK,UAAU,iBAA8B,eAAe,KAAK;AAElF,WAAK,eAAe;AAAA,IACtB;AAAA,IAnBA;AAAA,WAAwB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,IAwBtC,IAAI,WAAoB;AACtB,aAAO,KAAK,YAAY,UAAU,SAAS,QAAQ,KAAK;AAAA,IAC1D;AAAA;AAAA;AAAA;AAAA,IAKA,OAAa;AACX,WAAK,SAAS,SAAS;AAEvB,UAAI,KAAK,YAAY;AACnB,aAAK,WAAW,UAAU,IAAI,QAAQ;AACtC,iBAAS,KAAK,MAAM,WAAW;AAAA,MACjC;AAEA,WAAK,aAAa;AAClB,WAAK,cAAc;AAGnB,UAAI,KAAK,YAAY;AACnB,aAAK,WAAW,cAAc,eAAY,KAAK,WAAW,CAAC;AAAA,MAC7D;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKA,OAAa;AACX,UAAI,KAAK,YAAY;AACnB,aAAK,WAAW,UAAU,OAAO,QAAQ;AACzC,iBAAS,KAAK,MAAM,WAAW;AAAA,MACjC;AAEA,WAAK,aAAa;AAClB,WAAK,cAAc;AAAA,IACrB;AAAA,IAEQ,aAAqB;AAC3B,YAAM,MAAM,oBAAI,KAAK;AACrB,YAAM,QAAQ,IAAI,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACvD,YAAM,UAAU,IAAI,WAAW,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AAC3D,aAAO,GAAG,KAAK,IAAI,OAAO;AAAA,IAC5B;AAAA,IAEQ,gBAAsB;AAC5B,UAAI,CAAC,KAAK,UAAW;AAErB,WAAK,UAAU,QAAQ,CAAC,OAAO,UAAU;AACvC,cAAM,UAAU,OAAO,UAAU,OAAO;AACxC,YAAI,QAAQ,KAAK,WAAW,QAAQ;AAClC,gBAAM,cAAc;AACpB,gBAAM,UAAU,IAAI,QAAQ;AAAA,QAC9B,OAAO;AACL,gBAAM,cAAc;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEQ,YAAkB;AACxB,UAAI,CAAC,KAAK,UAAW;AAErB,WAAK,UAAU,QAAQ,WAAS,MAAM,UAAU,IAAI,OAAO,CAAC;AAG5D,WAAK,UAAU,UAAU,IAAI,OAAO;AAEpC,iBAAW,MAAM;AACf,aAAK,aAAa;AAClB,aAAK,cAAc;AACnB,aAAK,UAAU,UAAU,OAAO,OAAO;AAAA,MACzC,GAAG,GAAG;AAAA,IACR;AAAA,IAEQ,SAAe;AACrB,UAAI,KAAK,eAAe,sBAAqB,aAAa;AACxD,aAAK,KAAK;AAAA,MACZ,OAAO;AACL,aAAK,UAAU;AAAA,MACjB;AAAA,IACF;AAAA,IAEQ,SAAS,OAAqB;AACpC,UAAI,KAAK,WAAW,UAAU,EAAG;AAEjC,WAAK,cAAc;AACnB,WAAK,cAAc;AAGnB,UAAI,KAAK,WAAW,WAAW,GAAG;AAChC,mBAAW,MAAM,KAAK,OAAO,GAAG,GAAG;AAAA,MACrC;AAAA,IACF;AAAA,IAEQ,cAAoB;AAC1B,UAAI,KAAK,WAAW,WAAW,EAAG;AAClC,WAAK,aAAa,KAAK,WAAW,MAAM,GAAG,EAAE;AAC7C,WAAK,cAAc;AAAA,IACrB;AAAA,IAEQ,WAAiB;AACvB,WAAK,aAAa;AAClB,WAAK,cAAc;AAAA,IACrB;AAAA,IAEQ,iBAAuB;AAE7B,WAAK,WAAW,iBAAiB,SAAS,CAAC,MAAM,KAAK,kBAAkB,CAAC,CAAC;AAG1E,eAAS,iBAAiB,WAAW,CAAC,MAAM,KAAK,eAAe,CAAC,CAAC;AAGlE,eAAS,cAA2B,2BAA2B,GAC3D,iBAAiB,SAAS,MAAM,KAAK,KAAK,CAAC;AAAA,IACjD;AAAA,IAEQ,kBAAkB,GAAgB;AACxC,YAAM,SAAS,EAAE;AACjB,YAAM,MAAM,OAAO,QAAqB,aAAa;AAErD,UAAI,CAAC,IAAK;AAEV,YAAM,QAAQ,IAAI,QAAQ;AAC1B,YAAM,SAAS,IAAI,QAAQ;AAE3B,UAAI,OAAO;AACT,aAAK,SAAS,KAAK;AAAA,MACrB,WAAW,WAAW,aAAa;AACjC,aAAK,YAAY;AAAA,MACnB,WAAW,WAAW,SAAS;AAC7B,aAAK,SAAS;AAAA,MAChB;AAAA,IACF;AAAA,IAEQ,eAAe,GAAwB;AAC7C,UAAI,CAAC,KAAK,SAAU;AAGpB,QAAE,eAAe;AAEjB,UAAI,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAChC,aAAK,SAAS,EAAE,GAAG;AAAA,MACrB,WAAW,EAAE,QAAQ,aAAa;AAChC,aAAK,YAAY;AAAA,MACnB,WAAW,EAAE,QAAQ,UAAU;AAC7B,aAAK,SAAS;AAAA,MAChB;AAAA,IACF;AAAA,EACF;;;AC9KO,MAAM,iBAAN,MAAqB;AAAA,IAK1B,cAAc;AAHd;AAAA,WAAiB,eAAe;AAChC,WAAiB,YAAY;AAG3B,WAAK,UAAU;AACf,WAAK,qBAAqB;AAC1B,WAAK,uBAAuB;AAC5B,WAAK,sBAAsB;AAC3B,WAAK,iBAAiB;AACtB,WAAK,eAAe;AACpB,WAAK,mBAAmB;AAAA,IAC1B;AAAA;AAAA;AAAA;AAAA,IAKQ,YAAkB;AACxB,YAAM,OAAO,SAAS,iBAA8B,mBAAmB;AAEvE,WAAK,QAAQ,SAAO;AAClB,YAAI,iBAAiB,SAAS,MAAM;AAClC,gBAAM,YAAY,IAAI,QAAQ;AAC9B,cAAI,WAAW;AACb,iBAAK,YAAY,SAAS;AAAA,UAC5B;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,YAAY,WAAyB;AAC3C,YAAM,OAAO,SAAS,iBAA8B,mBAAmB;AACvE,YAAM,WAAW,SAAS,iBAA8B,2BAA2B;AACnF,YAAM,YAAY,SAAS,iBAA8B,8BAA8B;AAGvF,WAAK,QAAQ,OAAK;AAChB,YAAI,EAAE,QAAQ,QAAQ,WAAW;AAC/B,YAAE,UAAU,IAAI,QAAQ;AAAA,QAC1B,OAAO;AACL,YAAE,UAAU,OAAO,QAAQ;AAAA,QAC7B;AAAA,MACF,CAAC;AAGD,eAAS,QAAQ,aAAW;AAC1B,YAAI,QAAQ,QAAQ,QAAQ,WAAW;AACrC,kBAAQ,UAAU,IAAI,QAAQ;AAAA,QAChC,OAAO;AACL,kBAAQ,UAAU,OAAO,QAAQ;AAAA,QACnC;AAAA,MACF,CAAC;AAGD,gBAAU,QAAQ,WAAS;AACzB,YAAI,MAAM,QAAQ,WAAW,WAAW;AACtC,gBAAM,UAAU,IAAI,QAAQ;AAAA,QAC9B,OAAO;AACL,gBAAM,UAAU,OAAO,QAAQ;AAAA,QACjC;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,uBAA6B;AACnC,YAAM,eAAe,SAAS,eAAe,SAAS;AACtD,YAAM,cAAc,SAAS,eAAe,QAAQ;AACpD,YAAM,kBAAkB,SAAS,eAAe,YAAY;AAE5D,UAAI,CAAC,gBAAgB,CAAC,eAAe,CAAC,gBAAiB;AAEvD,YAAM,YAAY,MAAM,KAAK,cAAc,cAAc,aAAa,eAAe;AAErF,mBAAa,iBAAiB,SAAS,SAAS;AAChD,kBAAY,iBAAiB,SAAS,SAAS;AAC/C,sBAAgB,iBAAiB,SAAS,SAAS;AAGnD,gBAAU;AAAA,IACZ;AAAA;AAAA;AAAA;AAAA,IAKQ,cACN,cACA,aACA,iBACM;AACN,YAAM,UAAU,KAAK,YAAY,aAAa,KAAK;AACnD,YAAM,SAAS,KAAK,YAAY,YAAY,KAAK;AACjD,YAAM,SAAS,KAAK,YAAY,gBAAgB,KAAK;AAGrD,YAAM,eAAe,KAAK,eAAe,KAAK,YAAY,UAAU;AAEpE,YAAM,kBAAkB,SAAS,eAAe,cAAc;AAC9D,UAAI,iBAAiB;AACnB,wBAAgB,cAAc,KAAK,aAAa,YAAY;AAAA,MAC9D;AAGA,WAAK,iBAAiB,QAAQ,cAAc,gBAAgB,KAAK;AAAA,IACnE;AAAA;AAAA;AAAA;AAAA,IAKQ,iBAAiB,QAAgB,UAAkB,UAAwB;AACjF,YAAM,MAAM,SAAS,eAAe,eAAe;AACnD,YAAM,QAAQ,SAAS,eAAe,iBAAiB;AACvD,UAAI,CAAC,OAAO,CAAC,MAAO;AAEpB,YAAM,OAAO,SAAS;AAGtB,UAAI,UAAU,OAAO,YAAY,YAAY,SAAS;AAEtD,UAAI,WAAW,KAAK,aAAa,IAAI;AAEnC,cAAM,cAAc;AACpB,YAAI,UAAU,IAAI,SAAS;AAAA,MAC7B,WAAW,OAAO,GAAG;AAEnB,cAAM,cAAc,MAAM,KAAK,aAAa,IAAI,IAAI;AACpD,YAAI,UAAU,IAAI,UAAU;AAAA,MAC9B,WAAW,OAAO,GAAG;AAEnB,cAAM,cAAc,KAAK,aAAa,IAAI,IAAI;AAC9C,YAAI,UAAU,IAAI,UAAU;AAAA,MAC9B,OAAO;AAEL,cAAM,cAAc;AACpB,YAAI,UAAU,IAAI,SAAS;AAAA,MAC7B;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKQ,yBAA+B;AACrC,YAAM,YAAY,SAAS,eAAe,WAAW;AACrD,YAAM,gBAAgB,SAAS,iBAAmC,aAAa;AAC/E,YAAM,YAAY,SAAS,eAAe,WAAW;AACrD,YAAM,iBAAiB,SAAS,eAAe,gBAAgB;AAE/D,UAAI,CAAC,aAAa,CAAC,aAAa,CAAC,eAAgB;AAEjD,YAAM,kBAAkB,MAAM;AAC5B,cAAM,UAAU,SAAS,iBAAmC,qBAAqB;AACjF,cAAM,QAAQ,QAAQ;AAEtB,uBAAe,cAAc,UAAU,IAAI,YAAY,GAAG,KAAK;AAC/D,kBAAU,WAAW,UAAU;AAG/B,kBAAU,UAAU,UAAU,cAAc,UAAU,QAAQ;AAC9D,kBAAU,gBAAgB,QAAQ,KAAK,QAAQ,cAAc;AAAA,MAC/D;AAEA,gBAAU,iBAAiB,UAAU,MAAM;AACzC,sBAAc,QAAQ,QAAM,GAAG,UAAU,UAAU,OAAO;AAC1D,wBAAgB;AAAA,MAClB,CAAC;AAED,oBAAc,QAAQ,QAAM;AAC1B,WAAG,iBAAiB,UAAU,eAAe;AAE7C,WAAG,iBAAiB,SAAS,OAAK,EAAE,gBAAgB,CAAC;AAAA,MACvD,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,wBAA8B;AACpC,YAAM,WAAW,SAAS,eAAe,iBAAiB;AAC1D,YAAM,aAAa,SAAS,eAAe,YAAY;AAEvD,UAAI,CAAC,YAAY,CAAC,WAAY;AAE9B,eAAS,iBAAiB,UAAU,MAAM;AACxC,mBAAW,WAAW,CAAC,SAAS;AAAA,MAClC,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,mBAAyB;AAC/B,YAAM,WAAW,SAAS,eAAe,UAAU;AACnD,YAAM,SAAS,SAAS,eAAe,QAAQ;AAE/C,UAAI,CAAC,YAAY,CAAC,OAAQ;AAE1B,YAAM,QAAQ,oBAAI,KAAK;AACvB,YAAM,gBAAgB,IAAI,KAAK,KAAK;AACpC,oBAAc,QAAQ,MAAM,QAAQ,IAAI,EAAE;AAE1C,aAAO,QAAQ,KAAK,cAAc,KAAK;AACvC,eAAS,QAAQ,KAAK,cAAc,aAAa;AAAA,IACnD;AAAA;AAAA;AAAA;AAAA,IAKQ,aAAa,KAAqB;AACxC,aAAO,IAAI,eAAe,SAAS;AAAA,QACjC,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,MACzB,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,YAAY,KAAqB;AACvC,UAAI,CAAC,IAAK,QAAO;AACjB,aAAO,WAAW,IAAI,QAAQ,OAAO,EAAE,EAAE,QAAQ,KAAK,GAAG,CAAC,KAAK;AAAA,IACjE;AAAA;AAAA;AAAA;AAAA,IAKQ,cAAc,MAAoB;AACxC,aAAO,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IACxC;AAAA;AAAA;AAAA;AAAA,IAKQ,iBAAuB;AAC7B,YAAM,OAAO,SAAS,iBAA8B,6CAA6C;AAEjG,WAAK,QAAQ,SAAO;AAClB,cAAM,QAAQ,IAAI,aAAa,SAAS;AACxC,YAAI,CAAC,MAAO;AAEZ,cAAM,SAAS,SAAS,cAA2B,iCAAiC,KAAK,IAAI;AAC7F,YAAI,CAAC,OAAQ;AAEb,YAAI,iBAAiB,SAAS,CAAC,MAAM;AAEnC,cAAK,EAAE,OAAuB,QAAQ,wBAAwB,EAAG;AAEjE,gBAAM,OAAO,IAAI,cAAc,kBAAkB;AACjD,gBAAM,aAAa,IAAI,UAAU,SAAS,UAAU;AAGpD,mBAAS,iBAAiB,6BAA6B,EAAE,QAAQ,OAAK;AACpE,gBAAI,MAAM,KAAK;AACb,oBAAM,UAAU,EAAE,aAAa,SAAS;AACxC,kBAAI,SAAS;AACX,sBAAM,cAAc,SAAS,cAA2B,iCAAiC,OAAO,IAAI;AACpG,sBAAM,YAAY,EAAE,cAAc,kBAAkB;AACpD,oBAAI,eAAe,WAAW;AAC5B,uBAAK,YAAY,GAAG,aAAa,SAAwB;AAAA,gBAC3D;AAAA,cACF;AAAA,YACF;AAAA,UACF,CAAC;AAGD,cAAI,YAAY;AACd,iBAAK,YAAY,KAAK,QAAQ,IAAI;AAAA,UACpC,OAAO;AACL,iBAAK,UAAU,KAAK,QAAQ,IAAI;AAAA,UAClC;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,UAAU,KAAc,QAAqB,MAA4B;AAC/E,UAAI,UAAU,IAAI,UAAU;AAC5B,aAAO,UAAU,IAAI,UAAU;AAG/B,YAAM,QAAQ;AAAA,QACZ,EAAE,WAAW,eAAe;AAAA,QAC5B,EAAE,WAAW,gBAAgB;AAAA,MAC/B,GAAG;AAAA,QACD,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,MAAM;AAAA,MACR,CAAC;AAGD,YAAM,UAAU,OAAO,cAAc,wBAAwB;AAC7D,UAAI,SAAS;AACX,cAAM,SAAS,QAAQ;AACvB,eAAO,QAAQ;AAAA,UACb,EAAE,QAAQ,OAAO,SAAS,EAAE;AAAA,UAC5B,EAAE,QAAQ,GAAG,MAAM,MAAM,SAAS,EAAE;AAAA,QACtC,GAAG;AAAA,UACD,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKQ,YAAY,KAAc,QAAqB,MAA4B;AAEjF,YAAM,QAAQ;AAAA,QACZ,EAAE,WAAW,gBAAgB;AAAA,QAC7B,EAAE,WAAW,eAAe;AAAA,MAC9B,GAAG;AAAA,QACD,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,MAAM;AAAA,MACR,CAAC;AAGD,YAAM,UAAU,OAAO,cAAc,wBAAwB;AAC7D,UAAI,SAAS;AACX,cAAM,SAAS,QAAQ;AACvB,cAAM,YAAY,OAAO,QAAQ;AAAA,UAC/B,EAAE,QAAQ,GAAG,MAAM,MAAM,SAAS,EAAE;AAAA,UACpC,EAAE,QAAQ,OAAO,SAAS,EAAE;AAAA,QAC9B,GAAG;AAAA,UACD,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,MAAM;AAAA,QACR,CAAC;AAED,kBAAU,WAAW,MAAM;AACzB,cAAI,UAAU,OAAO,UAAU;AAC/B,iBAAO,UAAU,OAAO,UAAU;AAAA,QACpC;AAAA,MACF,OAAO;AACL,YAAI,UAAU,OAAO,UAAU;AAC/B,eAAO,UAAU,OAAO,UAAU;AAAA,MACpC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKQ,qBAA2B;AACjC,YAAM,WAAW,SAAS,cAA2B,8BAA8B;AACnF,UAAI,CAAC,SAAU;AAEf,eAAS,MAAM,SAAS;AACxB,eAAS,iBAAiB,SAAS,CAAC,MAAM;AAExC,YAAK,EAAE,OAAuB,QAAQ,wBAAwB,EAAG;AAEjE,aAAK,YAAY,YAAY;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;;;ACzWO,MAAM,sBAAN,MAA0B;AAAA,IAK/B,cAAc;AAJd,WAAQ,YAAwC;AAChD,WAAQ,WAA+B;AACvC,WAAQ,aAAiC;AAGvC,WAAK,WAAW,SAAS,eAAe,qBAAqB;AAC7D,WAAK,aAAa,SAAS,eAAe,sBAAsB;AAGhE,UAAI,CAAC,KAAK,SAAU;AAEpB,WAAK,cAAc;AACnB,WAAK,gBAAgB;AACrB,WAAK,uBAAuB;AAC5B,WAAK,oBAAoB;AACzB,WAAK,uBAAuB;AAC5B,WAAK,oBAAoB;AACzB,WAAK,YAAY,IAAI,oBAAoB;AAAA,IAC3C;AAAA;AAAA;AAAA;AAAA,IAKQ,yBAA+B;AACrC,aAAO,iBAAiB,YAAY,CAAC,MAAqB;AACxD,YAAI,EAAE,OAAO,aAAa;AACxB,eAAK,uBAAuB,EAAE,MAAM,WAAW;AAAA,QACjD,OAAO;AACL,eAAK,qBAAqB;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,sBAA4B;AAClC,YAAM,OAAO,OAAO,SAAS;AAC7B,UAAI,KAAK,WAAW,YAAY,GAAG;AACjC,cAAM,cAAc,KAAK,UAAU,CAAC;AACpC,aAAK,uBAAuB,WAAW;AAAA,MACzC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKQ,gBAAsB;AAC5B,UAAI,CAAC,KAAK,SAAU;AAEpB,YAAM,OAAO,KAAK,SAAS,iBAA8B,iCAAiC;AAE1F,WAAK,QAAQ,SAAO;AAClB,YAAI,iBAAiB,SAAS,MAAM;AAClC,gBAAM,YAAY,IAAI,QAAQ;AAC9B,cAAI,WAAW;AACb,iBAAK,UAAU,KAAK,UAAW,SAAS;AAAA,UAC1C;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,kBAAwB;AAC9B,UAAI,CAAC,KAAK,WAAY;AAEtB,YAAM,OAAO,KAAK,WAAW,iBAA8B,iCAAiC;AAE5F,WAAK,QAAQ,SAAO;AAClB,YAAI,iBAAiB,SAAS,MAAM;AAClC,gBAAM,YAAY,IAAI,QAAQ;AAC9B,cAAI,WAAW;AACb,iBAAK,UAAU,KAAK,YAAa,SAAS;AAAA,UAC5C;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,UAAU,WAAwB,WAAyB;AACjE,YAAM,OAAO,UAAU,iBAA8B,iCAAiC;AACtF,YAAM,WAAW,UAAU,iBAA8B,2BAA2B;AAEpF,WAAK,QAAQ,OAAK;AAChB,UAAE,UAAU,OAAO,UAAU,EAAE,QAAQ,QAAQ,SAAS;AAAA,MAC1D,CAAC;AAED,eAAS,QAAQ,aAAW;AAC1B,gBAAQ,UAAU,OAAO,UAAU,QAAQ,QAAQ,QAAQ,SAAS;AAAA,MACtE,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,IAMQ,yBAA+B;AACrC,eAAS,iBAAiB,SAAS,CAAC,MAAa;AAC/C,cAAM,SAAS,EAAE;AAGjB,YAAI,OAAO,QAAQ,cAAc,KAAK,OAAO,QAAQ,mBAAmB,GAAG;AACzE;AAAA,QACF;AAEA,cAAM,MAAM,OAAO,QAAqB,wCAAwC;AAEhF,YAAI,KAAK;AACP,gBAAM,cAAc,IAAI,QAAQ;AAChC,cAAI,aAAa;AACf,iBAAK,eAAe,WAAW;AAAA,UACjC;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,sBAA4B;AAClC,eAAS,iBAAiB,SAAS,CAAC,MAAa;AAC/C,cAAM,SAAS,EAAE;AACjB,cAAM,WAAW,OAAO,QAAqB,sBAAsB;AAEnE,YAAI,UAAU;AACZ,eAAK,aAAa;AAAA,QACpB;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,eAAe,aAA2B;AAEhD,cAAQ;AAAA,QACN,EAAE,YAAY;AAAA,QACd;AAAA,QACA,IAAI,WAAW;AAAA,MACjB;AACA,WAAK,uBAAuB,WAAW;AAAA,IACzC;AAAA;AAAA;AAAA;AAAA,IAKQ,uBAAuB,aAA2B;AACxD,UAAI,KAAK,YAAY,KAAK,YAAY;AACpC,aAAK,SAAS,MAAM,UAAU;AAC9B,aAAK,WAAW,MAAM,UAAU;AAChC,aAAK,WAAW,QAAQ,WAAW;AAGnC,aAAK,UAAU,KAAK,YAAY,SAAS;AAAA,MAC3C;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKQ,eAAqB;AAE3B,cAAQ;AAAA,QACN,CAAC;AAAA,QACD;AAAA,QACA,OAAO,SAAS;AAAA,MAClB;AACA,WAAK,qBAAqB;AAAA,IAC5B;AAAA;AAAA;AAAA;AAAA,IAKQ,uBAA6B;AACnC,UAAI,KAAK,YAAY,KAAK,YAAY;AACpC,aAAK,WAAW,MAAM,UAAU;AAChC,aAAK,SAAS,MAAM,UAAU;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAWA,MAAM,sBAAN,MAA0B;AAAA,IAGxB,cAAc;AAFd,WAAQ,SAA6B;AAGnC,WAAK,SAAS,SAAS,eAAe,cAAc;AAEpD,UAAI,CAAC,KAAK,OAAQ;AAElB,WAAK,uBAAuB;AAC5B,WAAK,oBAAoB;AAAA,IAC3B;AAAA;AAAA;AAAA;AAAA,IAKQ,eAAe,YAAmC;AACxD,YAAM,QAAQ,WAAW,MAAM,qBAAqB;AACpD,aAAO,QAAQ,MAAM,CAAC,IAAI;AAAA,IAC5B;AAAA;AAAA;AAAA;AAAA,IAKQ,yBAA+B;AACrC,UAAI,CAAC,KAAK,OAAQ;AAElB,WAAK,OAAO,iBAAiB,UAAU,CAAC,MAAa;AACnD,cAAM,SAAS,EAAE;AACjB,YAAI,OAAO,SAAS,cAAc,CAAC,OAAO,GAAI;AAE9C,cAAM,UAAU,KAAK,eAAe,OAAO,EAAE;AAC7C,YAAI,CAAC,QAAS;AAEd,cAAM,YAAY,OAAO;AACzB,cAAM,MAAM,OAAO,QAAqB,cAAc;AACtD,YAAI,CAAC,IAAK;AAGV,cAAM,QAAQ,IAAI,cAAc,gBAAgB;AAChD,cAAM,QAAQ,IAAI,cAAc,gBAAgB;AAChD,YAAI,MAAO,OAAM,UAAU,OAAO,YAAY,CAAC,SAAS;AACxD,YAAI,MAAO,OAAM,UAAU,OAAO,YAAY,CAAC,SAAS;AAGxD,aAAK,cAAc,SAAS,SAAS;AAGrC,YAAI,WAAW;AACb,gBAAM,YAAY,SAAS,eAAe,QAAQ,OAAO,EAAE;AAC3D,cAAI,WAAW;AACb,iBAAK,gBAAgB,SAAS,UAAU,KAAK;AAAA,UAC/C;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,sBAA4B;AAClC,UAAI,CAAC,KAAK,OAAQ;AAElB,WAAK,OAAO,iBAAiB,SAAS,CAAC,MAAa;AAClD,cAAM,SAAS,EAAE;AACjB,YAAI,OAAO,SAAS,UAAU,CAAC,OAAO,GAAI;AAG1C,cAAM,QAAQ,OAAO,GAAG,MAAM,aAAa;AAC3C,YAAI,CAAC,MAAO;AAEZ,cAAM,UAAU,MAAM,CAAC;AAEvB,YAAI,QAAQ,SAAS,UAAU,EAAG;AAElC,aAAK,gBAAgB,SAAS,OAAO,KAAK;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA,IAKQ,cAAc,SAAiB,SAAwB;AAC7D,YAAM,UAAU,SAAS,eAAe,QAAQ,OAAO,EAAE;AACzD,UAAI,SAAS;AACX,gBAAQ,MAAM,UAAU,UAAU,KAAK;AAAA,MACzC;AAAA,IACF;AAAA;AAAA;AAAA;AAAA,IAKQ,aAAa,OAAuB;AAE1C,YAAM,aAAa,MAAM,QAAQ,KAAK,GAAG;AACzC,YAAM,MAAM,WAAW,UAAU;AAEjC,UAAI,MAAM,GAAG,EAAG,QAAO;AAGvB,aAAO,IAAI,QAAQ,CAAC,EAAE,QAAQ,KAAK,GAAG;AAAA,IACxC;AAAA;AAAA;AAAA;AAAA,IAKQ,gBAAgB,SAAiB,OAAqB;AAC5D,YAAM,YAAY,SAAS,eAAe,SAAS,OAAO,EAAE;AAC5D,UAAI,CAAC,UAAW;AAGhB,YAAM,YAAY,SAAS,eAAe,QAAQ,OAAO,EAAE;AAC3D,YAAM,iBAAiB,WAAW,QAAQ,gBAAgB;AAC1D,YAAM,OAAO,gBAAgB,aAAa,KAAK,EAAE,QAAQ,OAAO,EAAE,EAAE,KAAK,KAAK;AAG9E,YAAM,iBAAiB,KAAK,aAAa,KAAK;AAC9C,gBAAU,QAAQ,GAAG,cAAc,IAAI,IAAI;AAAA,IAC7C;AAAA,EACF;;;AChTO,MAAM,MAAN,MAAU;AAAA,IASf,cAAc;AAEZ,WAAK,UAAU,IAAI,kBAAkB;AACrC,WAAK,UAAU,IAAI,iBAAiB;AACpC,WAAK,QAAQ,IAAI,gBAAgB;AACjC,WAAK,SAAS,IAAI,iBAAiB;AACnC,WAAK,aAAa,IAAI,qBAAqB,KAAK,OAAO;AACvD,WAAK,OAAO,IAAI,eAAe;AAC/B,WAAK,YAAY,IAAI,oBAAoB;AAAA,IAC3C;AAAA,EACF;AAKA,MAAI;AAKJ,WAAS,OAAa;AACpB,UAAM,IAAI,IAAI;AAGd,QAAI,OAAO,WAAW,aAAa;AACjC,MAAC,OAAmC,MAAM;AAAA,IAC5C;AAAA,EACF;AAGA,MAAI,SAAS,eAAe,WAAW;AACrC,aAAS,iBAAiB,oBAAoB,IAAI;AAAA,EACpD,OAAO;AACL,SAAK;AAAA,EACP;AAGA,MAAO,cAAQ;", - "names": [] -} diff --git a/PlanTempus.Application/wwwroot/ts/modules/employees.ts b/PlanTempus.Application/wwwroot/ts/modules/employees.ts index f763390..4359db5 100644 --- a/PlanTempus.Application/wwwroot/ts/modules/employees.ts +++ b/PlanTempus.Application/wwwroot/ts/modules/employees.ts @@ -1025,12 +1025,11 @@ class ScheduleController { } /** - * Open the schedule drawer + * Open the schedule drawer (no overlay - user can still interact with table) */ private openDrawer(): void { this.drawer?.classList.add('open'); - document.getElementById('drawerOverlay')?.classList.add('active'); - document.body.style.overflow = 'hidden'; + document.body.classList.add('schedule-drawer-open'); } /** @@ -1038,7 +1037,6 @@ class ScheduleController { */ private closeDrawer(): void { this.drawer?.classList.remove('open'); - document.getElementById('drawerOverlay')?.classList.remove('active'); - document.body.style.overflow = ''; + document.body.classList.remove('schedule-drawer-open'); } }