@excellore/ui 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { inject, PLATFORM_ID, signal, effect, Injectable, input, output, HostListener, Component, computed } from '@angular/core';
3
- import { isPlatformBrowser, CommonModule } from '@angular/common';
4
- import { Router, RouterLink, RouterLinkActive } from '@angular/router';
5
- import { LucideGrid, LucideBuilding, LucideCheck, LucideChevronDown, LucideBellOff, LucideCheckCheck, LucideTrash2, LucideBell, LucideCreditCard, LucideLogOut, LucideSettings, LucideUser, LucideBuilding2, LucideMenu, LucideMonitor, LucideMoon, LucideSearch, LucideSun, LucideX } from '@lucide/angular';
3
+ import { isPlatformBrowser, CommonModule, NgClass, NgTemplateOutlet } from '@angular/common';
4
+ import { RouterLink, RouterLinkActive, Router } from '@angular/router';
5
+ import { LucideGrid, LucideBellOff, LucideCheckCheck, LucideTrash2, LucideBell, LucideChevronDown, LucideCreditCard, LucideLogOut, LucideSettings, LucideUser, LucideBuilding2, LucideMenu, LucideMonitor, LucideMoon, LucideSearch, LucideSun, LucideX } from '@lucide/angular';
6
6
 
7
7
  const THEME_STORAGE_KEY = 'excellore-theme';
8
8
  class ThemeService {
@@ -150,47 +150,76 @@ class AppSwitcherComponent {
150
150
  }
151
151
  }
152
152
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AppSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
153
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: AppSwitcherComponent, isStandalone: true, selector: "lib-app-switcher", inputs: { applications: { classPropertyName: "applications", publicName: "applications", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { applicationSelected: "applicationSelected" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, ngImport: i0, template: "<div class=\"app-switcher-wrapper\">\n <button\n type=\"button\"\n class=\"app-switcher-trigger\"\n (click)=\"toggleSwitcher()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"Toggle application switcher\"\r\n >\r\n <svg lucideGrid class=\"app-switcher-trigger-icon\"></svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"app-switcher-dropdown\">\n <div class=\"app-switcher-header\">\n <div>\n <h3>Excellore Apps</h3>\n <p>Switch between available workspaces</p>\n </div>\n </div>\n \n @if (applications().length === 0) {\n <div class=\"app-switcher-empty\">\n No other apps available\n </div>\n } @else {\n <div class=\"app-switcher-list\">\n @for (app of applications(); track app.id) {\n @if (app.available !== false) {\n <a\n [href]=\"app.url\"\n (click)=\"onSelect(app)\"\n class=\"app-switcher-item app-switcher-link\"\n >\n <div class=\"app-switcher-app-mark\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"app-switcher-app-content\">\n <div class=\"app-switcher-app-name\" [title]=\"app.name\">{{ app.name }}</div>\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-open-pill\">\n Open\n </span>\n </a>\n } @else {\n <div class=\"app-switcher-item unavailable\">\n <div class=\"app-switcher-app-mark unavailable\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"app-switcher-app-content\">\n <div class=\"app-switcher-app-name\">{{ app.name }}</div>\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-soon-pill\">\n Soon\n </span>\n </div>\n }\n }\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.app-switcher-wrapper{position:relative;display:inline-block;text-align:left}.app-switcher-trigger{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.app-switcher-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.app-switcher-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-trigger-icon{width:1.125rem;height:1.125rem}.app-switcher-dropdown{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;max-height:calc(100dvh - 4.5rem);overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.625rem;box-shadow:0 12px 30px #0f172a24;animation:switcherEnter .15s cubic-bezier(.16,1,.3,1)}.app-switcher-header{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);margin-bottom:.375rem;padding:0 .25rem .625rem}.app-switcher-header h3{margin:0;color:var(--secondary);font-size:.65rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.app-switcher-header p{margin:.125rem 0 0;color:var(--secondary);font-size:.72rem;line-height:1.35}.app-switcher-empty{padding:1.5rem .5rem;color:var(--secondary);font-size:.8rem;text-align:center}.app-switcher-list{max-height:calc(100dvh - 10rem);overflow-y:auto;padding:.25rem 0}.app-switcher-item{display:flex;align-items:center;gap:.75rem;border:1px solid transparent;border-radius:.75rem;padding:.65rem;text-decoration:none;transition:background-color .15s ease,border-color .15s ease}.app-switcher-item+.app-switcher-item{margin-top:.125rem}.app-switcher-link:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 34%,transparent)}.app-switcher-link:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-item.unavailable{opacity:.55;-webkit-user-select:none;user-select:none}.app-switcher-app-mark{display:flex;width:2.5rem;height:2.5rem;align-items:center;justify-content:center;flex-shrink:0;border-radius:.7rem;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--primary) 15%,transparent);font-size:.875rem;font-weight:800}.app-switcher-app-content{min-width:0;flex:1 1 auto}.app-switcher-app-name{overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:750;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-url{overflow:hidden;margin-top:.125rem;color:var(--secondary);font-size:.72rem;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-mark.unavailable{border:1px dashed var(--border);color:var(--secondary);background:color-mix(in srgb,var(--border) 32%,transparent);box-shadow:none}.app-switcher-open-pill{flex-shrink:0;border-radius:999px;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;opacity:0;transition:opacity .15s ease}.app-switcher-link:hover .app-switcher-open-pill{opacity:1}.app-switcher-soon-pill{flex-shrink:0;border:1px solid var(--border);border-radius:999px;color:var(--secondary);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.app-switcher-dropdown ::-webkit-scrollbar{width:.45rem}.app-switcher-dropdown ::-webkit-scrollbar-track{background:transparent}.app-switcher-dropdown ::-webkit-scrollbar-thumb{background:var(--border);border-radius:999px}@keyframes switcherEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.app-switcher-dropdown{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:22.5rem;max-width:calc(100vw - 1rem);max-height:calc(100dvh - 5rem);transform-origin:top right}.app-switcher-list{max-height:26.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideGrid, selector: "svg[lucideGrid3x3], svg[lucideGrid], svg[lucideGrid3X3]" }] });
153
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: AppSwitcherComponent, isStandalone: true, selector: "lib-app-switcher", inputs: { applications: { classPropertyName: "applications", publicName: "applications", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { applicationSelected: "applicationSelected" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, ngImport: i0, template: "<div class=\"app-switcher-wrapper\">\r\n <button\r\n type=\"button\"\r\n class=\"app-switcher-trigger\"\r\n (click)=\"toggleSwitcher()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"Toggle application switcher\"\r\n >\r\n <svg lucideGrid class=\"app-switcher-trigger-icon\"></svg>\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"app-switcher-dropdown\">\r\n <div class=\"app-switcher-header\">\r\n <div>\r\n <h3>Excellore Apps</h3>\r\n <p>Switch between available workspaces</p>\r\n </div>\r\n </div>\r\n \r\n @if (applications().length === 0) {\r\n <div class=\"app-switcher-empty\">\r\n No other apps available\r\n </div>\r\n } @else {\r\n <div class=\"app-switcher-list\">\r\n @for (app of applications(); track app.id) {\r\n @if (app.available !== false) {\r\n <a\r\n [href]=\"app.url\"\r\n (click)=\"onSelect(app)\"\r\n class=\"app-switcher-item app-switcher-link\"\r\n >\r\n <div class=\"app-switcher-app-mark\">\r\n {{ app.initials || getInitials(app.name) }}\r\n </div>\r\n <div class=\"app-switcher-app-content\">\r\n <div class=\"app-switcher-app-name\" [title]=\"app.name\">{{ app.name }}</div>\r\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\r\n </div>\r\n <span class=\"app-switcher-open-pill\">\r\n Open\r\n </span>\r\n </a>\r\n } @else {\r\n <div class=\"app-switcher-item unavailable\">\r\n <div class=\"app-switcher-app-mark unavailable\">\r\n {{ app.initials || getInitials(app.name) }}\r\n </div>\r\n <div class=\"app-switcher-app-content\">\r\n <div class=\"app-switcher-app-name\">{{ app.name }}</div>\r\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\r\n </div>\r\n <span class=\"app-switcher-soon-pill\">\r\n Soon\r\n </span>\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.app-switcher-wrapper{position:relative;display:inline-block;text-align:left}.app-switcher-trigger{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.app-switcher-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.app-switcher-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-trigger-icon{width:1.125rem;height:1.125rem}.app-switcher-dropdown{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;max-height:calc(100dvh - 4.5rem);overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.625rem;box-shadow:0 12px 30px #0f172a24;animation:switcherEnter .15s cubic-bezier(.16,1,.3,1)}.app-switcher-header{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);margin-bottom:.375rem;padding:0 .25rem .625rem}.app-switcher-header h3{margin:0;color:var(--secondary);font-size:.65rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.app-switcher-header p{margin:.125rem 0 0;color:var(--secondary);font-size:.72rem;line-height:1.35}.app-switcher-empty{padding:1.5rem .5rem;color:var(--secondary);font-size:.8rem;text-align:center}.app-switcher-list{max-height:calc(100dvh - 10rem);overflow-y:auto;padding:.25rem 0}.app-switcher-item{display:flex;align-items:center;gap:.75rem;border:1px solid transparent;border-radius:.75rem;padding:.65rem;text-decoration:none;transition:background-color .15s ease,border-color .15s ease}.app-switcher-item+.app-switcher-item{margin-top:.125rem}.app-switcher-link:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 34%,transparent)}.app-switcher-link:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-item.unavailable{opacity:.55;-webkit-user-select:none;user-select:none}.app-switcher-app-mark{display:flex;width:2.5rem;height:2.5rem;align-items:center;justify-content:center;flex-shrink:0;border-radius:.7rem;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--primary) 15%,transparent);font-size:.875rem;font-weight:800}.app-switcher-app-content{min-width:0;flex:1 1 auto}.app-switcher-app-name{overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:750;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-url{overflow:hidden;margin-top:.125rem;color:var(--secondary);font-size:.72rem;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-mark.unavailable{border:1px dashed var(--border);color:var(--secondary);background:color-mix(in srgb,var(--border) 32%,transparent);box-shadow:none}.app-switcher-open-pill{flex-shrink:0;border-radius:999px;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;opacity:0;transition:opacity .15s ease}.app-switcher-link:hover .app-switcher-open-pill{opacity:1}.app-switcher-soon-pill{flex-shrink:0;border:1px solid var(--border);border-radius:999px;color:var(--secondary);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.app-switcher-dropdown ::-webkit-scrollbar{width:.45rem}.app-switcher-dropdown ::-webkit-scrollbar-track{background:transparent}.app-switcher-dropdown ::-webkit-scrollbar-thumb{background:var(--border);border-radius:999px}@keyframes switcherEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.app-switcher-dropdown{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:22.5rem;max-width:calc(100vw - 1rem);max-height:calc(100dvh - 5rem);transform-origin:top right}.app-switcher-list{max-height:26.25rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideGrid, selector: "svg[lucideGrid3x3], svg[lucideGrid], svg[lucideGrid3X3]" }] });
154
154
  }
155
155
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AppSwitcherComponent, decorators: [{
156
156
  type: Component,
157
- args: [{ selector: 'lib-app-switcher', standalone: true, imports: [CommonModule, LucideGrid], template: "<div class=\"app-switcher-wrapper\">\n <button\n type=\"button\"\n class=\"app-switcher-trigger\"\n (click)=\"toggleSwitcher()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"Toggle application switcher\"\r\n >\r\n <svg lucideGrid class=\"app-switcher-trigger-icon\"></svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"app-switcher-dropdown\">\n <div class=\"app-switcher-header\">\n <div>\n <h3>Excellore Apps</h3>\n <p>Switch between available workspaces</p>\n </div>\n </div>\n \n @if (applications().length === 0) {\n <div class=\"app-switcher-empty\">\n No other apps available\n </div>\n } @else {\n <div class=\"app-switcher-list\">\n @for (app of applications(); track app.id) {\n @if (app.available !== false) {\n <a\n [href]=\"app.url\"\n (click)=\"onSelect(app)\"\n class=\"app-switcher-item app-switcher-link\"\n >\n <div class=\"app-switcher-app-mark\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"app-switcher-app-content\">\n <div class=\"app-switcher-app-name\" [title]=\"app.name\">{{ app.name }}</div>\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-open-pill\">\n Open\n </span>\n </a>\n } @else {\n <div class=\"app-switcher-item unavailable\">\n <div class=\"app-switcher-app-mark unavailable\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"app-switcher-app-content\">\n <div class=\"app-switcher-app-name\">{{ app.name }}</div>\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-soon-pill\">\n Soon\n </span>\n </div>\n }\n }\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.app-switcher-wrapper{position:relative;display:inline-block;text-align:left}.app-switcher-trigger{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.app-switcher-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.app-switcher-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-trigger-icon{width:1.125rem;height:1.125rem}.app-switcher-dropdown{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;max-height:calc(100dvh - 4.5rem);overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.625rem;box-shadow:0 12px 30px #0f172a24;animation:switcherEnter .15s cubic-bezier(.16,1,.3,1)}.app-switcher-header{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);margin-bottom:.375rem;padding:0 .25rem .625rem}.app-switcher-header h3{margin:0;color:var(--secondary);font-size:.65rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.app-switcher-header p{margin:.125rem 0 0;color:var(--secondary);font-size:.72rem;line-height:1.35}.app-switcher-empty{padding:1.5rem .5rem;color:var(--secondary);font-size:.8rem;text-align:center}.app-switcher-list{max-height:calc(100dvh - 10rem);overflow-y:auto;padding:.25rem 0}.app-switcher-item{display:flex;align-items:center;gap:.75rem;border:1px solid transparent;border-radius:.75rem;padding:.65rem;text-decoration:none;transition:background-color .15s ease,border-color .15s ease}.app-switcher-item+.app-switcher-item{margin-top:.125rem}.app-switcher-link:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 34%,transparent)}.app-switcher-link:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-item.unavailable{opacity:.55;-webkit-user-select:none;user-select:none}.app-switcher-app-mark{display:flex;width:2.5rem;height:2.5rem;align-items:center;justify-content:center;flex-shrink:0;border-radius:.7rem;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--primary) 15%,transparent);font-size:.875rem;font-weight:800}.app-switcher-app-content{min-width:0;flex:1 1 auto}.app-switcher-app-name{overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:750;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-url{overflow:hidden;margin-top:.125rem;color:var(--secondary);font-size:.72rem;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-mark.unavailable{border:1px dashed var(--border);color:var(--secondary);background:color-mix(in srgb,var(--border) 32%,transparent);box-shadow:none}.app-switcher-open-pill{flex-shrink:0;border-radius:999px;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;opacity:0;transition:opacity .15s ease}.app-switcher-link:hover .app-switcher-open-pill{opacity:1}.app-switcher-soon-pill{flex-shrink:0;border:1px solid var(--border);border-radius:999px;color:var(--secondary);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.app-switcher-dropdown ::-webkit-scrollbar{width:.45rem}.app-switcher-dropdown ::-webkit-scrollbar-track{background:transparent}.app-switcher-dropdown ::-webkit-scrollbar-thumb{background:var(--border);border-radius:999px}@keyframes switcherEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.app-switcher-dropdown{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:22.5rem;max-width:calc(100vw - 1rem);max-height:calc(100dvh - 5rem);transform-origin:top right}.app-switcher-list{max-height:26.25rem}}\n"] }]
157
+ args: [{ selector: 'lib-app-switcher', standalone: true, imports: [CommonModule, LucideGrid], template: "<div class=\"app-switcher-wrapper\">\r\n <button\r\n type=\"button\"\r\n class=\"app-switcher-trigger\"\r\n (click)=\"toggleSwitcher()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"Toggle application switcher\"\r\n >\r\n <svg lucideGrid class=\"app-switcher-trigger-icon\"></svg>\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"app-switcher-dropdown\">\r\n <div class=\"app-switcher-header\">\r\n <div>\r\n <h3>Excellore Apps</h3>\r\n <p>Switch between available workspaces</p>\r\n </div>\r\n </div>\r\n \r\n @if (applications().length === 0) {\r\n <div class=\"app-switcher-empty\">\r\n No other apps available\r\n </div>\r\n } @else {\r\n <div class=\"app-switcher-list\">\r\n @for (app of applications(); track app.id) {\r\n @if (app.available !== false) {\r\n <a\r\n [href]=\"app.url\"\r\n (click)=\"onSelect(app)\"\r\n class=\"app-switcher-item app-switcher-link\"\r\n >\r\n <div class=\"app-switcher-app-mark\">\r\n {{ app.initials || getInitials(app.name) }}\r\n </div>\r\n <div class=\"app-switcher-app-content\">\r\n <div class=\"app-switcher-app-name\" [title]=\"app.name\">{{ app.name }}</div>\r\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\r\n </div>\r\n <span class=\"app-switcher-open-pill\">\r\n Open\r\n </span>\r\n </a>\r\n } @else {\r\n <div class=\"app-switcher-item unavailable\">\r\n <div class=\"app-switcher-app-mark unavailable\">\r\n {{ app.initials || getInitials(app.name) }}\r\n </div>\r\n <div class=\"app-switcher-app-content\">\r\n <div class=\"app-switcher-app-name\">{{ app.name }}</div>\r\n <div class=\"app-switcher-app-url\">{{ app.url }}</div>\r\n </div>\r\n <span class=\"app-switcher-soon-pill\">\r\n Soon\r\n </span>\r\n </div>\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.app-switcher-wrapper{position:relative;display:inline-block;text-align:left}.app-switcher-trigger{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.app-switcher-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.app-switcher-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-trigger-icon{width:1.125rem;height:1.125rem}.app-switcher-dropdown{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;max-height:calc(100dvh - 4.5rem);overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.625rem;box-shadow:0 12px 30px #0f172a24;animation:switcherEnter .15s cubic-bezier(.16,1,.3,1)}.app-switcher-header{display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);margin-bottom:.375rem;padding:0 .25rem .625rem}.app-switcher-header h3{margin:0;color:var(--secondary);font-size:.65rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.app-switcher-header p{margin:.125rem 0 0;color:var(--secondary);font-size:.72rem;line-height:1.35}.app-switcher-empty{padding:1.5rem .5rem;color:var(--secondary);font-size:.8rem;text-align:center}.app-switcher-list{max-height:calc(100dvh - 10rem);overflow-y:auto;padding:.25rem 0}.app-switcher-item{display:flex;align-items:center;gap:.75rem;border:1px solid transparent;border-radius:.75rem;padding:.65rem;text-decoration:none;transition:background-color .15s ease,border-color .15s ease}.app-switcher-item+.app-switcher-item{margin-top:.125rem}.app-switcher-link:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 34%,transparent)}.app-switcher-link:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.app-switcher-item.unavailable{opacity:.55;-webkit-user-select:none;user-select:none}.app-switcher-app-mark{display:flex;width:2.5rem;height:2.5rem;align-items:center;justify-content:center;flex-shrink:0;border-radius:.7rem;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--primary) 15%,transparent);font-size:.875rem;font-weight:800}.app-switcher-app-content{min-width:0;flex:1 1 auto}.app-switcher-app-name{overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:750;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-url{overflow:hidden;margin-top:.125rem;color:var(--secondary);font-size:.72rem;text-overflow:ellipsis;white-space:nowrap}.app-switcher-app-mark.unavailable{border:1px dashed var(--border);color:var(--secondary);background:color-mix(in srgb,var(--border) 32%,transparent);box-shadow:none}.app-switcher-open-pill{flex-shrink:0;border-radius:999px;color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;opacity:0;transition:opacity .15s ease}.app-switcher-link:hover .app-switcher-open-pill{opacity:1}.app-switcher-soon-pill{flex-shrink:0;border:1px solid var(--border);border-radius:999px;color:var(--secondary);padding:.15rem .5rem;font-size:.65rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase}.app-switcher-dropdown ::-webkit-scrollbar{width:.45rem}.app-switcher-dropdown ::-webkit-scrollbar-track{background:transparent}.app-switcher-dropdown ::-webkit-scrollbar-thumb{background:var(--border);border-radius:999px}@keyframes switcherEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.app-switcher-dropdown{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:22.5rem;max-width:calc(100vw - 1rem);max-height:calc(100dvh - 5rem);transform-origin:top right}.app-switcher-list{max-height:26.25rem}}\n"] }]
158
158
  }], propDecorators: { applications: [{ type: i0.Input, args: [{ isSignal: true, alias: "applications", required: false }] }], applicationSelected: [{ type: i0.Output, args: ["applicationSelected"] }], onOutsideClick: [{
159
159
  type: HostListener,
160
160
  args: ['document:click', ['$event']]
161
161
  }] } });
162
162
 
163
- class OrganizationSwitcherComponent {
164
- organizations = input([], ...(ngDevMode ? [{ debugName: "organizations" }] : /* istanbul ignore next */ []));
165
- selectedOrganization = input(null, ...(ngDevMode ? [{ debugName: "selectedOrganization" }] : /* istanbul ignore next */ []));
166
- organizationChanged = output();
167
- isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
168
- toggleSwitcher() {
169
- this.isOpen.update((v) => !v);
163
+ class SidebarMenuComponent {
164
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
165
+ errorMessage = input(null, ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
166
+ defaultIcon = input('bi-dot', ...(ngDevMode ? [{ debugName: "defaultIcon" }] : /* istanbul ignore next */ []));
167
+ menuItemSelected = output();
168
+ expandedIds = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedIds" }] : /* istanbul ignore next */ []));
169
+ sortedItems = computed(() => this.sortItems(this.items()), ...(ngDevMode ? [{ debugName: "sortedItems" }] : /* istanbul ignore next */ []));
170
+ toggle(item) {
171
+ if (item.disabled) {
172
+ return;
173
+ }
174
+ this.expandedIds.update((ids) => {
175
+ const next = new Set(ids);
176
+ if (next.has(item.id)) {
177
+ next.delete(item.id);
178
+ }
179
+ else {
180
+ next.add(item.id);
181
+ }
182
+ return next;
183
+ });
170
184
  }
171
- closeSwitcher() {
172
- this.isOpen.set(false);
185
+ isExpanded(item) {
186
+ return this.expandedIds().has(item.id);
173
187
  }
174
- onSelect(org) {
175
- this.organizationChanged.emit(org);
176
- this.closeSwitcher();
188
+ hasChildren(item) {
189
+ return !!item.children?.length;
177
190
  }
178
- onOutsideClick(event) {
179
- const target = event.target;
180
- if (!target.closest('.org-switcher-wrapper')) {
181
- this.closeSwitcher();
191
+ hasRoute(item) {
192
+ return !!item.route;
193
+ }
194
+ hasHref(item) {
195
+ return !!item.href;
196
+ }
197
+ iconFor(item) {
198
+ return item.icon || this.defaultIcon();
199
+ }
200
+ onSelect(item) {
201
+ if (!item.disabled) {
202
+ this.menuItemSelected.emit(item);
182
203
  }
183
204
  }
184
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: OrganizationSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
185
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: OrganizationSwitcherComponent, isStandalone: true, selector: "lib-organization-switcher", inputs: { organizations: { classPropertyName: "organizations", publicName: "organizations", isSignal: true, isRequired: false, transformFunction: null }, selectedOrganization: { classPropertyName: "selectedOrganization", publicName: "selectedOrganization", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { organizationChanged: "organizationChanged" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, ngImport: i0, template: "<div class=\"org-switcher-wrapper relative inline-block text-left\">\r\n <button\r\n type=\"button\"\r\n class=\"flex items-center gap-1.5 rounded-md border border-[var(--border)] bg-[var(--background)] px-2.5 py-1.5 text-xs font-medium text-[var(--foreground)] hover:bg-[rgba(var(--foreground),0.03)] focus:outline-none focus:ring-2 focus:ring-[var(--primary)] cursor-pointer\"\r\n (click)=\"toggleSwitcher()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"Switch organization\"\r\n >\r\n <svg lucideBuilding class=\"h-3.5 w-3.5 text-[var(--secondary)]\"></svg>\n <span class=\"truncate max-w-[120px]\">{{ selectedOrganization()?.name || 'Select Tenant' }}</span>\n <svg lucideChevronDown class=\"h-3 w-3 text-[var(--secondary)] transition-transform duration-200\" [class.rotate-180]=\"isOpen()\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"org-switcher-dropdown absolute left-0 mt-2 w-52 origin-top-left rounded-lg border border-[var(--border)] bg-[var(--background)] p-1 shadow-lg focus:outline-none z-50\">\r\n <div class=\"px-2 py-1.5 border-b border-[var(--border)] mb-1\">\r\n <span class=\"text-[9px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Switch Organization</span>\r\n </div>\r\n\r\n <div class=\"py-0.5 space-y-0.5 max-h-48 overflow-y-auto\">\r\n @for (org of organizations(); track org.id) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full items-center justify-between rounded-md px-2 py-1.5 text-xs text-[var(--foreground)] transition hover:bg-[rgba(var(--foreground),0.05)] text-left cursor-pointer\"\r\n (click)=\"onSelect(org)\"\r\n >\r\n <span class=\"truncate pr-2\" [class.font-semibold]=\"org.id === selectedOrganization()?.id\">{{ org.name }}</span>\r\n @if (org.id === selectedOrganization()?.id) {\r\n <svg lucideCheck class=\"h-3.5 w-3.5 text-[var(--primary)] flex-shrink-0\"></svg>\n }\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.org-switcher-dropdown{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;animation:orgEnter .15s cubic-bezier(.16,1,.3,1)}@keyframes orgEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideBuilding, selector: "svg[lucideBuilding]" }, { kind: "component", type: LucideCheck, selector: "svg[lucideCheck]" }, { kind: "component", type: LucideChevronDown, selector: "svg[lucideChevronDown]" }] });
205
+ sortedChildren(item) {
206
+ return this.sortItems(item.children ?? []);
207
+ }
208
+ sortItems(items) {
209
+ return [...items]
210
+ .sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0) || a.label.localeCompare(b.label))
211
+ .map((item) => ({
212
+ ...item,
213
+ children: item.children ? this.sortItems(item.children) : undefined,
214
+ }));
215
+ }
216
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: SidebarMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
217
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: SidebarMenuComponent, isStandalone: true, selector: "lib-sidebar-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, defaultIcon: { classPropertyName: "defaultIcon", publicName: "defaultIcon", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuItemSelected: "menuItemSelected" }, ngImport: i0, template: "<nav class=\"sidebar-menu\" aria-label=\"Sidebar menu\">\n @if (errorMessage()) {\n <div class=\"sidebar-menu__error\" role=\"alert\">\n {{ errorMessage() }}\n </div>\r\n }\r\n\r\n <ng-template #menuList let-menuItems let-level=\"level\">\r\n @for (item of menuItems; track item.id) {\r\n @if (hasChildren(item)) {\r\n <div class=\"sidebar-menu__group\">\r\n <button\r\n type=\"button\"\r\n class=\"sidebar-menu__item sidebar-menu__button\"\r\n [class.disabled]=\"item.disabled\"\r\n [class.expanded]=\"isExpanded(item)\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n [attr.aria-expanded]=\"isExpanded(item)\"\r\n (click)=\"toggle(item)\"\r\n >\r\n <span class=\"sidebar-menu__item-main\">\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </span>\r\n <svg class=\"sidebar-menu__chevron\" [class.expanded]=\"isExpanded(item)\" viewBox=\"0 0 20 20\" aria-hidden=\"true\">\r\n <path d=\"M6 8l4 4 4-4\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.8\" />\r\n </svg>\r\n </button>\r\n\r\n @if (isExpanded(item)) {\r\n <div class=\"sidebar-menu__children\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"menuList\"\r\n [ngTemplateOutletContext]=\"{ $implicit: sortedChildren(item), level: level + 1 }\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @else if (hasRoute(item)) {\r\n <a\r\n [routerLink]=\"item.route\"\r\n routerLinkActive=\"active\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact ?? true }\"\r\n class=\"sidebar-menu__item\"\r\n [class.disabled]=\"item.disabled\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n (click)=\"onSelect(item)\"\r\n >\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </a>\r\n } @else if (hasHref(item)) {\r\n <a\r\n [href]=\"item.href\"\r\n [target]=\"item.target || '_self'\"\r\n class=\"sidebar-menu__item\"\r\n [class.disabled]=\"item.disabled\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n (click)=\"onSelect(item)\"\r\n >\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </a>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"sidebar-menu__item sidebar-menu__button\"\r\n [class.disabled]=\"item.disabled\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n (click)=\"onSelect(item)\"\r\n >\r\n <span class=\"sidebar-menu__item-main\">\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"menuList\" [ngTemplateOutletContext]=\"{ $implicit: sortedItems(), level: 0 }\" />\r\n</nav>\r\n", styles: [":host{display:block;height:100%;min-width:0;min-height:0}.sidebar-menu{display:flex;flex-direction:column;gap:.25rem;height:100%;min-height:0;overflow-x:hidden;overflow-y:auto;padding:.5rem}.sidebar-menu__item{display:flex;min-height:2.5rem;width:100%;align-items:center;gap:.625rem;border:0;border-radius:.375rem;background:transparent;color:var(--bs-body-color, var(--foreground, #111827));cursor:pointer;font:inherit;padding:.625rem .75rem;text-align:left;text-decoration:none;transition:background-color .15s ease,color .15s ease}.sidebar-menu__item:hover,.sidebar-menu__item.expanded{background:var(--bs-secondary-bg, color-mix(in srgb, var(--border, #e5e7eb) 65%, transparent));color:var(--bs-body-color, var(--foreground, #111827))}.sidebar-menu__item.active{background:var(--accent-light, color-mix(in srgb, var(--accent-primary, #0067b8) 12%, transparent));color:var(--accent-primary, #0067b8)}.sidebar-menu__button{justify-content:space-between}.sidebar-menu__item-main{display:inline-flex;min-width:0;align-items:center;gap:.625rem}.sidebar-menu__icon{width:1.1rem;min-width:1.1rem;font-size:1.1rem;line-height:1;text-align:center}.sidebar-menu__label{min-width:0;overflow:hidden;font-size:.875rem;font-weight:500;text-overflow:ellipsis;white-space:nowrap}.sidebar-menu__chevron{height:1rem;width:1rem;color:var(--text-secondary, var(--secondary, #6b7280));transition:transform .2s ease}.sidebar-menu__chevron.expanded{transform:rotate(180deg)}.sidebar-menu__children{display:grid;gap:.25rem;margin-top:.25rem}.sidebar-menu__error{border-radius:.375rem;color:var(--danger, #dc2626);font-size:.875rem;padding:.5rem .75rem}.sidebar-menu__item.disabled{cursor:not-allowed;opacity:.45;pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
186
218
  }
187
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: OrganizationSwitcherComponent, decorators: [{
219
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: SidebarMenuComponent, decorators: [{
188
220
  type: Component,
189
- args: [{ selector: 'lib-organization-switcher', standalone: true, imports: [CommonModule, LucideBuilding, LucideCheck, LucideChevronDown], template: "<div class=\"org-switcher-wrapper relative inline-block text-left\">\r\n <button\r\n type=\"button\"\r\n class=\"flex items-center gap-1.5 rounded-md border border-[var(--border)] bg-[var(--background)] px-2.5 py-1.5 text-xs font-medium text-[var(--foreground)] hover:bg-[rgba(var(--foreground),0.03)] focus:outline-none focus:ring-2 focus:ring-[var(--primary)] cursor-pointer\"\r\n (click)=\"toggleSwitcher()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"Switch organization\"\r\n >\r\n <svg lucideBuilding class=\"h-3.5 w-3.5 text-[var(--secondary)]\"></svg>\n <span class=\"truncate max-w-[120px]\">{{ selectedOrganization()?.name || 'Select Tenant' }}</span>\n <svg lucideChevronDown class=\"h-3 w-3 text-[var(--secondary)] transition-transform duration-200\" [class.rotate-180]=\"isOpen()\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"org-switcher-dropdown absolute left-0 mt-2 w-52 origin-top-left rounded-lg border border-[var(--border)] bg-[var(--background)] p-1 shadow-lg focus:outline-none z-50\">\r\n <div class=\"px-2 py-1.5 border-b border-[var(--border)] mb-1\">\r\n <span class=\"text-[9px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Switch Organization</span>\r\n </div>\r\n\r\n <div class=\"py-0.5 space-y-0.5 max-h-48 overflow-y-auto\">\r\n @for (org of organizations(); track org.id) {\r\n <button\r\n type=\"button\"\r\n class=\"flex w-full items-center justify-between rounded-md px-2 py-1.5 text-xs text-[var(--foreground)] transition hover:bg-[rgba(var(--foreground),0.05)] text-left cursor-pointer\"\r\n (click)=\"onSelect(org)\"\r\n >\r\n <span class=\"truncate pr-2\" [class.font-semibold]=\"org.id === selectedOrganization()?.id\">{{ org.name }}</span>\r\n @if (org.id === selectedOrganization()?.id) {\r\n <svg lucideCheck class=\"h-3.5 w-3.5 text-[var(--primary)] flex-shrink-0\"></svg>\n }\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.org-switcher-dropdown{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;animation:orgEnter .15s cubic-bezier(.16,1,.3,1)}@keyframes orgEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"] }]
190
- }], propDecorators: { organizations: [{ type: i0.Input, args: [{ isSignal: true, alias: "organizations", required: false }] }], selectedOrganization: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedOrganization", required: false }] }], organizationChanged: [{ type: i0.Output, args: ["organizationChanged"] }], onOutsideClick: [{
191
- type: HostListener,
192
- args: ['document:click', ['$event']]
193
- }] } });
221
+ args: [{ selector: 'lib-sidebar-menu', standalone: true, imports: [NgClass, NgTemplateOutlet, RouterLink, RouterLinkActive], template: "<nav class=\"sidebar-menu\" aria-label=\"Sidebar menu\">\n @if (errorMessage()) {\n <div class=\"sidebar-menu__error\" role=\"alert\">\n {{ errorMessage() }}\n </div>\r\n }\r\n\r\n <ng-template #menuList let-menuItems let-level=\"level\">\r\n @for (item of menuItems; track item.id) {\r\n @if (hasChildren(item)) {\r\n <div class=\"sidebar-menu__group\">\r\n <button\r\n type=\"button\"\r\n class=\"sidebar-menu__item sidebar-menu__button\"\r\n [class.disabled]=\"item.disabled\"\r\n [class.expanded]=\"isExpanded(item)\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n [attr.aria-expanded]=\"isExpanded(item)\"\r\n (click)=\"toggle(item)\"\r\n >\r\n <span class=\"sidebar-menu__item-main\">\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </span>\r\n <svg class=\"sidebar-menu__chevron\" [class.expanded]=\"isExpanded(item)\" viewBox=\"0 0 20 20\" aria-hidden=\"true\">\r\n <path d=\"M6 8l4 4 4-4\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"1.8\" />\r\n </svg>\r\n </button>\r\n\r\n @if (isExpanded(item)) {\r\n <div class=\"sidebar-menu__children\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"menuList\"\r\n [ngTemplateOutletContext]=\"{ $implicit: sortedChildren(item), level: level + 1 }\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @else if (hasRoute(item)) {\r\n <a\r\n [routerLink]=\"item.route\"\r\n routerLinkActive=\"active\"\r\n [routerLinkActiveOptions]=\"{ exact: item.exact ?? true }\"\r\n class=\"sidebar-menu__item\"\r\n [class.disabled]=\"item.disabled\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n (click)=\"onSelect(item)\"\r\n >\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </a>\r\n } @else if (hasHref(item)) {\r\n <a\r\n [href]=\"item.href\"\r\n [target]=\"item.target || '_self'\"\r\n class=\"sidebar-menu__item\"\r\n [class.disabled]=\"item.disabled\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n (click)=\"onSelect(item)\"\r\n >\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </a>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"sidebar-menu__item sidebar-menu__button\"\r\n [class.disabled]=\"item.disabled\"\r\n [style.padding-left.rem]=\"0.75 + level * 0.75\"\r\n (click)=\"onSelect(item)\"\r\n >\r\n <span class=\"sidebar-menu__item-main\">\r\n <i class=\"bi sidebar-menu__icon\" [ngClass]=\"iconFor(item)\" aria-hidden=\"true\"></i>\r\n <span class=\"sidebar-menu__label\">{{ item.label }}</span>\r\n </span>\r\n </button>\r\n }\r\n }\r\n </ng-template>\r\n\r\n <ng-container [ngTemplateOutlet]=\"menuList\" [ngTemplateOutletContext]=\"{ $implicit: sortedItems(), level: 0 }\" />\r\n</nav>\r\n", styles: [":host{display:block;height:100%;min-width:0;min-height:0}.sidebar-menu{display:flex;flex-direction:column;gap:.25rem;height:100%;min-height:0;overflow-x:hidden;overflow-y:auto;padding:.5rem}.sidebar-menu__item{display:flex;min-height:2.5rem;width:100%;align-items:center;gap:.625rem;border:0;border-radius:.375rem;background:transparent;color:var(--bs-body-color, var(--foreground, #111827));cursor:pointer;font:inherit;padding:.625rem .75rem;text-align:left;text-decoration:none;transition:background-color .15s ease,color .15s ease}.sidebar-menu__item:hover,.sidebar-menu__item.expanded{background:var(--bs-secondary-bg, color-mix(in srgb, var(--border, #e5e7eb) 65%, transparent));color:var(--bs-body-color, var(--foreground, #111827))}.sidebar-menu__item.active{background:var(--accent-light, color-mix(in srgb, var(--accent-primary, #0067b8) 12%, transparent));color:var(--accent-primary, #0067b8)}.sidebar-menu__button{justify-content:space-between}.sidebar-menu__item-main{display:inline-flex;min-width:0;align-items:center;gap:.625rem}.sidebar-menu__icon{width:1.1rem;min-width:1.1rem;font-size:1.1rem;line-height:1;text-align:center}.sidebar-menu__label{min-width:0;overflow:hidden;font-size:.875rem;font-weight:500;text-overflow:ellipsis;white-space:nowrap}.sidebar-menu__chevron{height:1rem;width:1rem;color:var(--text-secondary, var(--secondary, #6b7280));transition:transform .2s ease}.sidebar-menu__chevron.expanded{transform:rotate(180deg)}.sidebar-menu__children{display:grid;gap:.25rem;margin-top:.25rem}.sidebar-menu__error{border-radius:.375rem;color:var(--danger, #dc2626);font-size:.875rem;padding:.5rem .75rem}.sidebar-menu__item.disabled{cursor:not-allowed;opacity:.45;pointer-events:none}\n"] }]
222
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], defaultIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultIcon", required: false }] }], menuItemSelected: [{ type: i0.Output, args: ["menuItemSelected"] }] } });
194
223
 
195
224
  class NotificationPanelComponent {
196
225
  notifications = input([], ...(ngDevMode ? [{ debugName: "notifications" }] : /* istanbul ignore next */ []));
@@ -226,11 +255,11 @@ class NotificationPanelComponent {
226
255
  return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
227
256
  }
228
257
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
229
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: NotificationPanelComponent, isStandalone: true, selector: "lib-notification-panel", inputs: { notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { notificationClick: "notificationClick", markRead: "markRead", clearAll: "clearAll" }, ngImport: i0, template: "<div class=\"notification-panel-inner flex flex-col h-full max-h-[380px] w-full text-left\">\r\n <!-- Panel Header -->\r\n <div class=\"flex items-center justify-between border-b border-[var(--border)] px-3.5 py-2\">\r\n <span class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Notifications</span>\r\n @if (notifications().length > 0) {\r\n <button\r\n type=\"button\"\r\n class=\"flex items-center gap-1 text-[9px] font-bold text-[var(--secondary)] hover:text-[var(--danger,#ef4444)] hover:underline cursor-pointer\"\r\n (click)=\"onClearAll($event)\"\r\n >\r\n <svg lucideTrash2 class=\"h-3 w-3\"></svg>\n <span>Clear All</span>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Panel Body -->\r\n <div class=\"flex-1 overflow-y-auto min-h-0 py-0.5 divide-y divide-[var(--border)]\">\r\n @if (notifications().length === 0) {\r\n <div class=\"flex flex-col items-center justify-center py-10 px-4 text-center select-none\">\r\n <div class=\"flex h-10 w-10 items-center justify-center rounded-full bg-[rgba(var(--secondary),0.06)] text-[var(--secondary)] mb-2.5\">\r\n <svg lucideBellOff class=\"h-4.5 w-4.5\"></svg>\n </div>\r\n <p class=\"text-xs font-semibold text-[var(--foreground)]\">All caught up</p>\r\n <p class=\"text-[10px] text-[var(--secondary)] mt-0.5\">No new notifications to display.</p>\r\n </div>\r\n } @else {\r\n @for (item of notifications(); track item.id) {\r\n <div\r\n (click)=\"onNotificationClick(item)\"\r\n class=\"notification-item flex gap-2.5 p-3 transition hover:bg-[rgba(var(--foreground),0.02)] cursor-pointer relative\"\r\n [class.bg-[rgba(var(--primary),0.015)]]=\"!item.read\"\r\n >\r\n <!-- Read status dot -->\r\n <div class=\"flex-shrink-0 pt-1\">\r\n @if (!item.read) {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-[var(--primary)] animate-pulse\"></span>\r\n } @else {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-transparent\"></span>\r\n }\r\n </div>\r\n\r\n <!-- Notification content -->\r\n <div class=\"flex-1 min-w-0\">\r\n <h4 class=\"text-xs font-semibold text-[var(--foreground)] truncate\" [class.font-bold]=\"!item.read\">\r\n {{ item.title }}\r\n </h4>\r\n <p class=\"text-[10.5px] text-[var(--secondary)] mt-0.5 leading-snug break-words\">\r\n {{ item.message }}\r\n </p>\r\n <span class=\"block text-[9px] text-[var(--secondary)] mt-1 font-medium\">\r\n {{ formatTime(item.createdAt) }}\r\n </span>\r\n </div>\r\n\r\n <!-- Actions -->\r\n @if (!item.read) {\r\n <div class=\"flex items-center flex-shrink-0\">\r\n <button\r\n type=\"button\"\r\n class=\"mark-read-btn grid h-6 w-6 place-items-center rounded-full text-[var(--secondary)] hover:text-[var(--primary)] hover:bg-[rgba(var(--foreground),0.05)] cursor-pointer\"\r\n [title]=\"'Mark as read'\"\r\n (click)=\"onMarkRead(item.id, $event)\"\r\n >\r\n <svg lucideCheckCheck class=\"h-3.5 w-3.5\"></svg>\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;width:100%}.notification-item{border-left:2px solid transparent}.notification-item:hover{border-left-color:var(--primary)}.mark-read-btn{opacity:.5;transition:opacity .2s,background-color .2s}.notification-item:hover .mark-read-btn{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideBellOff, selector: "svg[lucideBellOff]" }, { kind: "component", type: LucideCheckCheck, selector: "svg[lucideCheckCheck]" }, { kind: "component", type: LucideTrash2, selector: "svg[lucideTrash2]" }] });
258
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: NotificationPanelComponent, isStandalone: true, selector: "lib-notification-panel", inputs: { notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { notificationClick: "notificationClick", markRead: "markRead", clearAll: "clearAll" }, ngImport: i0, template: "<div class=\"notification-panel-inner flex flex-col h-full max-h-[380px] w-full text-left\">\r\n <!-- Panel Header -->\r\n <div class=\"flex items-center justify-between border-b border-[var(--border)] px-3.5 py-2\">\r\n <span class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Notifications</span>\r\n @if (notifications().length > 0) {\r\n <button\r\n type=\"button\"\r\n class=\"flex items-center gap-1 text-[9px] font-bold text-[var(--secondary)] hover:text-[var(--danger,#ef4444)] hover:underline cursor-pointer\"\r\n (click)=\"onClearAll($event)\"\r\n >\r\n <svg lucideTrash2 class=\"h-3 w-3\"></svg>\r\n <span>Clear All</span>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Panel Body -->\r\n <div class=\"flex-1 overflow-y-auto min-h-0 py-0.5 divide-y divide-[var(--border)]\">\r\n @if (notifications().length === 0) {\r\n <div class=\"flex flex-col items-center justify-center py-10 px-4 text-center select-none\">\r\n <div class=\"flex h-10 w-10 items-center justify-center rounded-full bg-[rgba(var(--secondary),0.06)] text-[var(--secondary)] mb-2.5\">\r\n <svg lucideBellOff class=\"h-4.5 w-4.5\"></svg>\r\n </div>\r\n <p class=\"text-xs font-semibold text-[var(--foreground)]\">All caught up</p>\r\n <p class=\"text-[10px] text-[var(--secondary)] mt-0.5\">No new notifications to display.</p>\r\n </div>\r\n } @else {\r\n @for (item of notifications(); track item.id) {\r\n <div\r\n (click)=\"onNotificationClick(item)\"\r\n class=\"notification-item flex gap-2.5 p-3 transition hover:bg-[rgba(var(--foreground),0.02)] cursor-pointer relative\"\r\n [class.bg-[rgba(var(--primary),0.015)]]=\"!item.read\"\r\n >\r\n <!-- Read status dot -->\r\n <div class=\"flex-shrink-0 pt-1\">\r\n @if (!item.read) {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-[var(--primary)] animate-pulse\"></span>\r\n } @else {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-transparent\"></span>\r\n }\r\n </div>\r\n\r\n <!-- Notification content -->\r\n <div class=\"flex-1 min-w-0\">\r\n <h4 class=\"text-xs font-semibold text-[var(--foreground)] truncate\" [class.font-bold]=\"!item.read\">\r\n {{ item.title }}\r\n </h4>\r\n <p class=\"text-[10.5px] text-[var(--secondary)] mt-0.5 leading-snug break-words\">\r\n {{ item.message }}\r\n </p>\r\n <span class=\"block text-[9px] text-[var(--secondary)] mt-1 font-medium\">\r\n {{ formatTime(item.createdAt) }}\r\n </span>\r\n </div>\r\n\r\n <!-- Actions -->\r\n @if (!item.read) {\r\n <div class=\"flex items-center flex-shrink-0\">\r\n <button\r\n type=\"button\"\r\n class=\"mark-read-btn grid h-6 w-6 place-items-center rounded-full text-[var(--secondary)] hover:text-[var(--primary)] hover:bg-[rgba(var(--foreground),0.05)] cursor-pointer\"\r\n [title]=\"'Mark as read'\"\r\n (click)=\"onMarkRead(item.id, $event)\"\r\n >\r\n <svg lucideCheckCheck class=\"h-3.5 w-3.5\"></svg>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;width:100%}.notification-item{border-left:2px solid transparent}.notification-item:hover{border-left-color:var(--primary)}.mark-read-btn{opacity:.5;transition:opacity .2s,background-color .2s}.notification-item:hover .mark-read-btn{opacity:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideBellOff, selector: "svg[lucideBellOff]" }, { kind: "component", type: LucideCheckCheck, selector: "svg[lucideCheckCheck]" }, { kind: "component", type: LucideTrash2, selector: "svg[lucideTrash2]" }] });
230
259
  }
231
260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationPanelComponent, decorators: [{
232
261
  type: Component,
233
- args: [{ selector: 'lib-notification-panel', standalone: true, imports: [CommonModule, LucideBellOff, LucideCheckCheck, LucideTrash2], template: "<div class=\"notification-panel-inner flex flex-col h-full max-h-[380px] w-full text-left\">\r\n <!-- Panel Header -->\r\n <div class=\"flex items-center justify-between border-b border-[var(--border)] px-3.5 py-2\">\r\n <span class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Notifications</span>\r\n @if (notifications().length > 0) {\r\n <button\r\n type=\"button\"\r\n class=\"flex items-center gap-1 text-[9px] font-bold text-[var(--secondary)] hover:text-[var(--danger,#ef4444)] hover:underline cursor-pointer\"\r\n (click)=\"onClearAll($event)\"\r\n >\r\n <svg lucideTrash2 class=\"h-3 w-3\"></svg>\n <span>Clear All</span>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Panel Body -->\r\n <div class=\"flex-1 overflow-y-auto min-h-0 py-0.5 divide-y divide-[var(--border)]\">\r\n @if (notifications().length === 0) {\r\n <div class=\"flex flex-col items-center justify-center py-10 px-4 text-center select-none\">\r\n <div class=\"flex h-10 w-10 items-center justify-center rounded-full bg-[rgba(var(--secondary),0.06)] text-[var(--secondary)] mb-2.5\">\r\n <svg lucideBellOff class=\"h-4.5 w-4.5\"></svg>\n </div>\r\n <p class=\"text-xs font-semibold text-[var(--foreground)]\">All caught up</p>\r\n <p class=\"text-[10px] text-[var(--secondary)] mt-0.5\">No new notifications to display.</p>\r\n </div>\r\n } @else {\r\n @for (item of notifications(); track item.id) {\r\n <div\r\n (click)=\"onNotificationClick(item)\"\r\n class=\"notification-item flex gap-2.5 p-3 transition hover:bg-[rgba(var(--foreground),0.02)] cursor-pointer relative\"\r\n [class.bg-[rgba(var(--primary),0.015)]]=\"!item.read\"\r\n >\r\n <!-- Read status dot -->\r\n <div class=\"flex-shrink-0 pt-1\">\r\n @if (!item.read) {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-[var(--primary)] animate-pulse\"></span>\r\n } @else {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-transparent\"></span>\r\n }\r\n </div>\r\n\r\n <!-- Notification content -->\r\n <div class=\"flex-1 min-w-0\">\r\n <h4 class=\"text-xs font-semibold text-[var(--foreground)] truncate\" [class.font-bold]=\"!item.read\">\r\n {{ item.title }}\r\n </h4>\r\n <p class=\"text-[10.5px] text-[var(--secondary)] mt-0.5 leading-snug break-words\">\r\n {{ item.message }}\r\n </p>\r\n <span class=\"block text-[9px] text-[var(--secondary)] mt-1 font-medium\">\r\n {{ formatTime(item.createdAt) }}\r\n </span>\r\n </div>\r\n\r\n <!-- Actions -->\r\n @if (!item.read) {\r\n <div class=\"flex items-center flex-shrink-0\">\r\n <button\r\n type=\"button\"\r\n class=\"mark-read-btn grid h-6 w-6 place-items-center rounded-full text-[var(--secondary)] hover:text-[var(--primary)] hover:bg-[rgba(var(--foreground),0.05)] cursor-pointer\"\r\n [title]=\"'Mark as read'\"\r\n (click)=\"onMarkRead(item.id, $event)\"\r\n >\r\n <svg lucideCheckCheck class=\"h-3.5 w-3.5\"></svg>\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;width:100%}.notification-item{border-left:2px solid transparent}.notification-item:hover{border-left-color:var(--primary)}.mark-read-btn{opacity:.5;transition:opacity .2s,background-color .2s}.notification-item:hover .mark-read-btn{opacity:1}\n"] }]
262
+ args: [{ selector: 'lib-notification-panel', standalone: true, imports: [CommonModule, LucideBellOff, LucideCheckCheck, LucideTrash2], template: "<div class=\"notification-panel-inner flex flex-col h-full max-h-[380px] w-full text-left\">\r\n <!-- Panel Header -->\r\n <div class=\"flex items-center justify-between border-b border-[var(--border)] px-3.5 py-2\">\r\n <span class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Notifications</span>\r\n @if (notifications().length > 0) {\r\n <button\r\n type=\"button\"\r\n class=\"flex items-center gap-1 text-[9px] font-bold text-[var(--secondary)] hover:text-[var(--danger,#ef4444)] hover:underline cursor-pointer\"\r\n (click)=\"onClearAll($event)\"\r\n >\r\n <svg lucideTrash2 class=\"h-3 w-3\"></svg>\r\n <span>Clear All</span>\r\n </button>\r\n }\r\n </div>\r\n\r\n <!-- Panel Body -->\r\n <div class=\"flex-1 overflow-y-auto min-h-0 py-0.5 divide-y divide-[var(--border)]\">\r\n @if (notifications().length === 0) {\r\n <div class=\"flex flex-col items-center justify-center py-10 px-4 text-center select-none\">\r\n <div class=\"flex h-10 w-10 items-center justify-center rounded-full bg-[rgba(var(--secondary),0.06)] text-[var(--secondary)] mb-2.5\">\r\n <svg lucideBellOff class=\"h-4.5 w-4.5\"></svg>\r\n </div>\r\n <p class=\"text-xs font-semibold text-[var(--foreground)]\">All caught up</p>\r\n <p class=\"text-[10px] text-[var(--secondary)] mt-0.5\">No new notifications to display.</p>\r\n </div>\r\n } @else {\r\n @for (item of notifications(); track item.id) {\r\n <div\r\n (click)=\"onNotificationClick(item)\"\r\n class=\"notification-item flex gap-2.5 p-3 transition hover:bg-[rgba(var(--foreground),0.02)] cursor-pointer relative\"\r\n [class.bg-[rgba(var(--primary),0.015)]]=\"!item.read\"\r\n >\r\n <!-- Read status dot -->\r\n <div class=\"flex-shrink-0 pt-1\">\r\n @if (!item.read) {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-[var(--primary)] animate-pulse\"></span>\r\n } @else {\r\n <span class=\"block h-1.5 w-1.5 rounded-full bg-transparent\"></span>\r\n }\r\n </div>\r\n\r\n <!-- Notification content -->\r\n <div class=\"flex-1 min-w-0\">\r\n <h4 class=\"text-xs font-semibold text-[var(--foreground)] truncate\" [class.font-bold]=\"!item.read\">\r\n {{ item.title }}\r\n </h4>\r\n <p class=\"text-[10.5px] text-[var(--secondary)] mt-0.5 leading-snug break-words\">\r\n {{ item.message }}\r\n </p>\r\n <span class=\"block text-[9px] text-[var(--secondary)] mt-1 font-medium\">\r\n {{ formatTime(item.createdAt) }}\r\n </span>\r\n </div>\r\n\r\n <!-- Actions -->\r\n @if (!item.read) {\r\n <div class=\"flex items-center flex-shrink-0\">\r\n <button\r\n type=\"button\"\r\n class=\"mark-read-btn grid h-6 w-6 place-items-center rounded-full text-[var(--secondary)] hover:text-[var(--primary)] hover:bg-[rgba(var(--foreground),0.05)] cursor-pointer\"\r\n [title]=\"'Mark as read'\"\r\n (click)=\"onMarkRead(item.id, $event)\"\r\n >\r\n <svg lucideCheckCheck class=\"h-3.5 w-3.5\"></svg>\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n", styles: [":host{display:block;width:100%}.notification-item{border-left:2px solid transparent}.notification-item:hover{border-left-color:var(--primary)}.mark-read-btn{opacity:.5;transition:opacity .2s,background-color .2s}.notification-item:hover .mark-read-btn{opacity:1}\n"] }]
234
263
  }], propDecorators: { notifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "notifications", required: false }] }], notificationClick: [{ type: i0.Output, args: ["notificationClick"] }], markRead: [{ type: i0.Output, args: ["markRead"] }], clearAll: [{ type: i0.Output, args: ["clearAll"] }] } });
235
264
 
236
265
  class NotificationBellComponent {
@@ -263,11 +292,11 @@ class NotificationBellComponent {
263
292
  }
264
293
  }
265
294
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationBellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
266
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: NotificationBellComponent, isStandalone: true, selector: "lib-notification-bell", inputs: { unreadCount: { classPropertyName: "unreadCount", publicName: "unreadCount", isSignal: true, isRequired: false, transformFunction: null }, notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { notificationClick: "notificationClick", markRead: "markRead", clearAll: "clearAll" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, ngImport: i0, template: "<div class=\"notification-bell-wrapper relative inline-block text-left\">\r\n <button\n type=\"button\"\n class=\"notification-trigger\"\n (click)=\"togglePanel()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"View notifications\"\r\n >\r\n <svg lucideBell class=\"h-4.5 w-4.5\"></svg>\n \r\n @if (unreadCount() > 0) {\r\n <span class=\"absolute top-1.5 right-1.5 flex h-2 w-2\">\r\n <span class=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-[var(--danger,#ef4444)] opacity-75\"></span>\r\n <span class=\"relative inline-flex rounded-full h-2 w-2 bg-[var(--danger,#ef4444)]\"></span>\r\n </span>\r\n }\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"notification-dropdown fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-0 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-80 sm:origin-top-right\">\n <lib-notification-panel\r\n [notifications]=\"notifications()\"\r\n (notificationClick)=\"onNotificationClick($event)\"\r\n (markRead)=\"onMarkRead($event)\"\r\n (clearAll)=\"onClearAll()\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.notification-trigger{position:relative;display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.notification-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.notification-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.notification-dropdown{box-shadow:0 12px 30px #0f172a24;animation:bellEnter .15s cubic-bezier(.16,1,.3,1);overflow:hidden}@keyframes bellEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: NotificationPanelComponent, selector: "lib-notification-panel", inputs: ["notifications"], outputs: ["notificationClick", "markRead", "clearAll"] }, { kind: "component", type: LucideBell, selector: "svg[lucideBell]" }] });
295
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: NotificationBellComponent, isStandalone: true, selector: "lib-notification-bell", inputs: { unreadCount: { classPropertyName: "unreadCount", publicName: "unreadCount", isSignal: true, isRequired: false, transformFunction: null }, notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { notificationClick: "notificationClick", markRead: "markRead", clearAll: "clearAll" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, ngImport: i0, template: "<div class=\"notification-bell-wrapper relative inline-block text-left\">\r\n <button\r\n type=\"button\"\r\n class=\"notification-trigger\"\r\n (click)=\"togglePanel()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"View notifications\"\r\n >\r\n <svg lucideBell class=\"h-4.5 w-4.5\"></svg>\r\n \r\n @if (unreadCount() > 0) {\r\n <span class=\"absolute top-1.5 right-1.5 flex h-2 w-2\">\r\n <span class=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-[var(--danger,#ef4444)] opacity-75\"></span>\r\n <span class=\"relative inline-flex rounded-full h-2 w-2 bg-[var(--danger,#ef4444)]\"></span>\r\n </span>\r\n }\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"notification-dropdown fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-0 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-80 sm:origin-top-right\">\r\n <lib-notification-panel\r\n [notifications]=\"notifications()\"\r\n (notificationClick)=\"onNotificationClick($event)\"\r\n (markRead)=\"onMarkRead($event)\"\r\n (clearAll)=\"onClearAll()\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.notification-trigger{position:relative;display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.notification-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.notification-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.notification-dropdown{box-shadow:0 12px 30px #0f172a24;animation:bellEnter .15s cubic-bezier(.16,1,.3,1);overflow:hidden}@keyframes bellEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: NotificationPanelComponent, selector: "lib-notification-panel", inputs: ["notifications"], outputs: ["notificationClick", "markRead", "clearAll"] }, { kind: "component", type: LucideBell, selector: "svg[lucideBell]" }] });
267
296
  }
268
297
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationBellComponent, decorators: [{
269
298
  type: Component,
270
- args: [{ selector: 'lib-notification-bell', standalone: true, imports: [CommonModule, NotificationPanelComponent, LucideBell], template: "<div class=\"notification-bell-wrapper relative inline-block text-left\">\r\n <button\n type=\"button\"\n class=\"notification-trigger\"\n (click)=\"togglePanel()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"View notifications\"\r\n >\r\n <svg lucideBell class=\"h-4.5 w-4.5\"></svg>\n \r\n @if (unreadCount() > 0) {\r\n <span class=\"absolute top-1.5 right-1.5 flex h-2 w-2\">\r\n <span class=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-[var(--danger,#ef4444)] opacity-75\"></span>\r\n <span class=\"relative inline-flex rounded-full h-2 w-2 bg-[var(--danger,#ef4444)]\"></span>\r\n </span>\r\n }\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"notification-dropdown fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-0 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-80 sm:origin-top-right\">\n <lib-notification-panel\r\n [notifications]=\"notifications()\"\r\n (notificationClick)=\"onNotificationClick($event)\"\r\n (markRead)=\"onMarkRead($event)\"\r\n (clearAll)=\"onClearAll()\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.notification-trigger{position:relative;display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.notification-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.notification-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.notification-dropdown{box-shadow:0 12px 30px #0f172a24;animation:bellEnter .15s cubic-bezier(.16,1,.3,1);overflow:hidden}@keyframes bellEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"] }]
299
+ args: [{ selector: 'lib-notification-bell', standalone: true, imports: [CommonModule, NotificationPanelComponent, LucideBell], template: "<div class=\"notification-bell-wrapper relative inline-block text-left\">\r\n <button\r\n type=\"button\"\r\n class=\"notification-trigger\"\r\n (click)=\"togglePanel()\"\r\n aria-haspopup=\"true\"\r\n [aria-expanded]=\"isOpen()\"\r\n aria-label=\"View notifications\"\r\n >\r\n <svg lucideBell class=\"h-4.5 w-4.5\"></svg>\r\n \r\n @if (unreadCount() > 0) {\r\n <span class=\"absolute top-1.5 right-1.5 flex h-2 w-2\">\r\n <span class=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-[var(--danger,#ef4444)] opacity-75\"></span>\r\n <span class=\"relative inline-flex rounded-full h-2 w-2 bg-[var(--danger,#ef4444)]\"></span>\r\n </span>\r\n }\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"notification-dropdown fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-0 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-80 sm:origin-top-right\">\r\n <lib-notification-panel\r\n [notifications]=\"notifications()\"\r\n (notificationClick)=\"onNotificationClick($event)\"\r\n (markRead)=\"onMarkRead($event)\"\r\n (clearAll)=\"onClearAll()\"\r\n />\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.notification-trigger{position:relative;display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.notification-trigger:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.notification-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.notification-dropdown{box-shadow:0 12px 30px #0f172a24;animation:bellEnter .15s cubic-bezier(.16,1,.3,1);overflow:hidden}@keyframes bellEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"] }]
271
300
  }], propDecorators: { unreadCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "unreadCount", required: false }] }], notifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "notifications", required: false }] }], notificationClick: [{ type: i0.Output, args: ["notificationClick"] }], markRead: [{ type: i0.Output, args: ["markRead"] }], clearAll: [{ type: i0.Output, args: ["clearAll"] }], onOutsideClick: [{
272
301
  type: HostListener,
273
302
  args: ['document:click', ['$event']]
@@ -295,11 +324,11 @@ class UserAvatarComponent {
295
324
  this.imageError = true;
296
325
  }
297
326
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: UserAvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
298
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: UserAvatarComponent, isStandalone: true, selector: "lib-user-avatar", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"avatar-container flex h-full w-full items-center justify-center rounded-full border border-[var(--border)] select-none overflow-hidden transition-all duration-200\">\r\n @if (user()?.avatar && !imageError) {\r\n <img [src]=\"user()?.avatar\" [alt]=\"user()?.name || 'User avatar'\" class=\"avatar-img h-full w-full object-cover\" (error)=\"onImageError()\" />\r\n } @else {\r\n <span class=\"avatar-initials text-xs font-semibold uppercase leading-none\">{{ initials() }}</span>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:inherit;height:inherit}.avatar-container{background:linear-gradient(135deg,var(--primary, #0067b8) 0%,var(--secondary, #005a9e) 100%);color:var(--background, #ffffff);box-shadow:0 1px 3px #0000000d}:host:hover .avatar-container{transform:scale(1.02);box-shadow:0 4px 6px -1px #00000014,0 2px 4px -1px #0000000a}.avatar-initials{text-shadow:0 1px 1px rgba(0,0,0,.15)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
327
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: UserAvatarComponent, isStandalone: true, selector: "lib-user-avatar", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"avatar-container\">\r\n @if (user()?.avatar && !imageError) {\r\n <img [src]=\"user()?.avatar\" [alt]=\"user()?.name || 'User avatar'\" class=\"avatar-img\" (error)=\"onImageError()\" />\r\n } @else {\r\n <span class=\"avatar-initials\">{{ initials() }}</span>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%}.avatar-container{display:grid;width:100%;height:100%;place-items:center;overflow:hidden;border:1px solid var(--border);border-radius:999px;background:linear-gradient(135deg,var(--primary, #0067b8) 0%,var(--secondary, #005a9e) 100%);color:var(--background, #ffffff);box-shadow:0 1px 3px #0000000d;-webkit-user-select:none;user-select:none;transition:box-shadow .2s ease,transform .2s ease}.avatar-img{display:block;width:100%;height:100%;object-fit:cover}:host:hover .avatar-container{transform:scale(1.02);box-shadow:0 4px 6px -1px #00000014,0 2px 4px -1px #0000000a}.avatar-initials{font-size:.75rem;font-weight:750;line-height:1;text-transform:uppercase;text-shadow:0 1px 1px rgba(0,0,0,.15)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
299
328
  }
300
329
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: UserAvatarComponent, decorators: [{
301
330
  type: Component,
302
- args: [{ selector: 'lib-user-avatar', standalone: true, imports: [CommonModule], template: "<div class=\"avatar-container flex h-full w-full items-center justify-center rounded-full border border-[var(--border)] select-none overflow-hidden transition-all duration-200\">\r\n @if (user()?.avatar && !imageError) {\r\n <img [src]=\"user()?.avatar\" [alt]=\"user()?.name || 'User avatar'\" class=\"avatar-img h-full w-full object-cover\" (error)=\"onImageError()\" />\r\n } @else {\r\n <span class=\"avatar-initials text-xs font-semibold uppercase leading-none\">{{ initials() }}</span>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:inherit;height:inherit}.avatar-container{background:linear-gradient(135deg,var(--primary, #0067b8) 0%,var(--secondary, #005a9e) 100%);color:var(--background, #ffffff);box-shadow:0 1px 3px #0000000d}:host:hover .avatar-container{transform:scale(1.02);box-shadow:0 4px 6px -1px #00000014,0 2px 4px -1px #0000000a}.avatar-initials{text-shadow:0 1px 1px rgba(0,0,0,.15)}\n"] }]
331
+ args: [{ selector: 'lib-user-avatar', standalone: true, imports: [CommonModule], template: "<div class=\"avatar-container\">\r\n @if (user()?.avatar && !imageError) {\r\n <img [src]=\"user()?.avatar\" [alt]=\"user()?.name || 'User avatar'\" class=\"avatar-img\" (error)=\"onImageError()\" />\r\n } @else {\r\n <span class=\"avatar-initials\">{{ initials() }}</span>\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%}.avatar-container{display:grid;width:100%;height:100%;place-items:center;overflow:hidden;border:1px solid var(--border);border-radius:999px;background:linear-gradient(135deg,var(--primary, #0067b8) 0%,var(--secondary, #005a9e) 100%);color:var(--background, #ffffff);box-shadow:0 1px 3px #0000000d;-webkit-user-select:none;user-select:none;transition:box-shadow .2s ease,transform .2s ease}.avatar-img{display:block;width:100%;height:100%;object-fit:cover}:host:hover .avatar-container{transform:scale(1.02);box-shadow:0 4px 6px -1px #00000014,0 2px 4px -1px #0000000a}.avatar-initials{font-size:.75rem;font-weight:750;line-height:1;text-transform:uppercase;text-shadow:0 1px 1px rgba(0,0,0,.15)}\n"] }]
303
332
  }], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }] } });
304
333
 
305
334
  class UserMenuComponent {
@@ -324,11 +353,11 @@ class UserMenuComponent {
324
353
  }
325
354
  }
326
355
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: UserMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
327
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: UserMenuComponent, isStandalone: true, selector: "lib-user-menu", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuAction: "menuAction" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, ngImport: i0, template: "<div class=\"user-menu-wrapper\">\n <button type=\"button\" class=\"user-menu-trigger\" (click)=\"toggleMenu()\" aria-haspopup=\"true\" [aria-expanded]=\"isOpen()\"\r\n aria-label=\"User profile menu\">\r\n <div class=\"user-menu-avatar\">\n <lib-user-avatar [user]=\"user()\" />\n </div>\n <svg lucideChevronDown class=\"user-menu-chevron\"\n [class.rotate-180]=\"isOpen()\"></svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"user-dropdown-panel\">\n @if (user(); as u) {\n <div class=\"user-dropdown-profile\">\n <p class=\"user-dropdown-name\" [title]=\"u.name\">{{ u.name }}</p>\n <p class=\"user-dropdown-email\" [title]=\"u.email\">{{ u.email }}</p>\n </div>\n }\n\n <div class=\"user-menu-list\">\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\n <svg lucideUser class=\"user-menu-icon\"></svg>\n <span>My Profile</span>\n </button>\n\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('settings')\">\n <svg lucideSettings class=\"user-menu-icon\"></svg>\n <span>Settings</span>\n </button>\n\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('billing')\">\n <svg lucideCreditCard class=\"user-menu-icon\"></svg>\n <span>Billing</span>\n </button>\n </div>\n\n <div class=\"user-menu-danger-zone\">\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\n <svg lucideLogOut class=\"user-menu-icon\"></svg>\n <span>Sign Out</span>\n </button>\n </div>\r\n </div>\r\n }\r\n</div>\n", styles: [":host{display:inline-block}.user-menu-wrapper{position:relative;display:inline-block;text-align:left}.user-menu-trigger{display:flex;align-items:center;gap:.375rem;border:1px solid var(--border);border-radius:999px;color:var(--foreground);background:var(--background);padding:.125rem .45rem .125rem .125rem;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.user-menu-avatar{width:1.75rem;height:1.75rem;overflow:hidden;border-radius:999px}.user-menu-chevron{width:.875rem;height:.875rem;color:var(--secondary);transition:transform .2s ease}.user-menu-chevron.rotate-180{transform:rotate(180deg)}.user-menu-trigger:hover{background:color-mix(in srgb,var(--border) 28%,transparent)}.user-menu-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.user-dropdown-panel{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.375rem;box-shadow:0 12px 30px #0f172a24;animation:dropdownEnter .15s cubic-bezier(.16,1,.3,1)}.user-dropdown-profile{border-bottom:1px solid var(--border);margin-bottom:.25rem;padding:.65rem .75rem}.user-dropdown-name,.user-dropdown-email{overflow:hidden;margin:0;text-overflow:ellipsis;white-space:nowrap}.user-dropdown-name{color:var(--foreground);font-size:.875rem;font-weight:750}.user-dropdown-email{margin-top:.125rem;color:var(--secondary);font-size:.78rem}.user-menu-list{display:grid;gap:.125rem;padding:.125rem 0}.user-menu-item{display:flex;width:100%;align-items:center;gap:.625rem;border:0;border-radius:.5rem;color:var(--foreground);background:transparent;padding:.55rem .75rem;font-size:.875rem;text-align:left;cursor:pointer;transition:background-color .15s ease,color .15s ease}.user-menu-icon{width:1rem;height:1rem;flex-shrink:0;color:var(--secondary)}.user-menu-item:hover{background:color-mix(in srgb,var(--border) 32%,transparent)}.user-menu-item.danger,.user-menu-item.danger .user-menu-icon{color:var(--danger, #ef4444)}.user-menu-item.danger:hover{background:color-mix(in srgb,var(--danger, #ef4444) 10%,transparent)}.user-menu-danger-zone{border-top:1px solid var(--border);margin-top:.25rem;padding-top:.25rem}@keyframes dropdownEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.user-dropdown-panel{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:14rem;max-width:calc(100vw - 1rem);transform-origin:top right}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UserAvatarComponent, selector: "lib-user-avatar", inputs: ["user"] }, { kind: "component", type: LucideChevronDown, selector: "svg[lucideChevronDown]" }, { kind: "component", type: LucideCreditCard, selector: "svg[lucideCreditCard]" }, { kind: "component", type: LucideLogOut, selector: "svg[lucideLogOut]" }, { kind: "component", type: LucideSettings, selector: "svg[lucideSettings]" }, { kind: "component", type: LucideUser, selector: "svg[lucideUser]" }] });
356
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: UserMenuComponent, isStandalone: true, selector: "lib-user-menu", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuAction: "menuAction" }, host: { listeners: { "document:click": "onOutsideClick($event)" } }, ngImport: i0, template: "<div class=\"user-menu-wrapper\">\r\n <button type=\"button\" class=\"user-menu-trigger\" (click)=\"toggleMenu()\" aria-haspopup=\"true\" [aria-expanded]=\"isOpen()\"\r\n aria-label=\"User profile menu\">\r\n <div class=\"user-menu-avatar\">\r\n <lib-user-avatar [user]=\"user()\" />\r\n </div>\r\n <svg lucideChevronDown class=\"user-menu-chevron\"\r\n [class.rotate-180]=\"isOpen()\"></svg>\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"user-dropdown-panel\">\r\n @if (user(); as u) {\r\n <div class=\"user-dropdown-profile\">\r\n <p class=\"user-dropdown-name\" [title]=\"u.name\">{{ u.name }}</p>\r\n <p class=\"user-dropdown-email\" [title]=\"u.email\">{{ u.email }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"user-menu-list\">\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\r\n <svg lucideUser class=\"user-menu-icon\"></svg>\r\n <span>My Profile</span>\r\n </button>\r\n\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('settings')\">\r\n <svg lucideSettings class=\"user-menu-icon\"></svg>\r\n <span>Settings</span>\r\n </button>\r\n\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('billing')\">\r\n <svg lucideCreditCard class=\"user-menu-icon\"></svg>\r\n <span>Billing</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"user-menu-danger-zone\">\r\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\r\n <svg lucideLogOut class=\"user-menu-icon\"></svg>\r\n <span>Sign Out</span>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.user-menu-wrapper{position:relative;display:inline-block;text-align:left}.user-menu-trigger{display:flex;align-items:center;justify-content:center;gap:.35rem;min-height:2.25rem;border:1px solid var(--border);border-radius:999px;color:var(--foreground);background:var(--background);padding:.2rem .5rem .2rem .2rem;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.user-menu-avatar{display:block;width:1.65rem;height:1.65rem;flex:0 0 1.65rem;overflow:hidden;border-radius:999px}.user-menu-chevron{width:.875rem;height:.875rem;color:var(--secondary);transition:transform .2s ease}.user-menu-chevron.rotate-180{transform:rotate(180deg)}.user-menu-trigger:hover{background:color-mix(in srgb,var(--border) 28%,transparent)}.user-menu-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.user-dropdown-panel{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.375rem;box-shadow:0 12px 30px #0f172a24;animation:dropdownEnter .15s cubic-bezier(.16,1,.3,1)}.user-dropdown-profile{border-bottom:1px solid var(--border);margin-bottom:.25rem;padding:.65rem .75rem}.user-dropdown-name,.user-dropdown-email{overflow:hidden;margin:0;text-overflow:ellipsis;white-space:nowrap}.user-dropdown-name{color:var(--foreground);font-size:.875rem;font-weight:750}.user-dropdown-email{margin-top:.125rem;color:var(--secondary);font-size:.78rem}.user-menu-list{display:grid;gap:.125rem;padding:.125rem 0}.user-menu-item{display:flex;width:100%;align-items:center;gap:.625rem;border:0;border-radius:.5rem;color:var(--foreground);background:transparent;padding:.55rem .75rem;font-size:.875rem;text-align:left;cursor:pointer;transition:background-color .15s ease,color .15s ease}.user-menu-icon{width:1rem;height:1rem;flex-shrink:0;color:var(--secondary)}.user-menu-item:hover{background:color-mix(in srgb,var(--border) 32%,transparent)}.user-menu-item.danger,.user-menu-item.danger .user-menu-icon{color:var(--danger, #ef4444)}.user-menu-item.danger:hover{background:color-mix(in srgb,var(--danger, #ef4444) 10%,transparent)}.user-menu-danger-zone{border-top:1px solid var(--border);margin-top:.25rem;padding-top:.25rem}@keyframes dropdownEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.user-dropdown-panel{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:14rem;max-width:calc(100vw - 1rem);transform-origin:top right}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UserAvatarComponent, selector: "lib-user-avatar", inputs: ["user"] }, { kind: "component", type: LucideChevronDown, selector: "svg[lucideChevronDown]" }, { kind: "component", type: LucideCreditCard, selector: "svg[lucideCreditCard]" }, { kind: "component", type: LucideLogOut, selector: "svg[lucideLogOut]" }, { kind: "component", type: LucideSettings, selector: "svg[lucideSettings]" }, { kind: "component", type: LucideUser, selector: "svg[lucideUser]" }] });
328
357
  }
329
358
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: UserMenuComponent, decorators: [{
330
359
  type: Component,
331
- args: [{ selector: 'lib-user-menu', standalone: true, imports: [CommonModule, UserAvatarComponent, LucideChevronDown, LucideCreditCard, LucideLogOut, LucideSettings, LucideUser], template: "<div class=\"user-menu-wrapper\">\n <button type=\"button\" class=\"user-menu-trigger\" (click)=\"toggleMenu()\" aria-haspopup=\"true\" [aria-expanded]=\"isOpen()\"\r\n aria-label=\"User profile menu\">\r\n <div class=\"user-menu-avatar\">\n <lib-user-avatar [user]=\"user()\" />\n </div>\n <svg lucideChevronDown class=\"user-menu-chevron\"\n [class.rotate-180]=\"isOpen()\"></svg>\n </button>\n\n @if (isOpen()) {\n <div class=\"user-dropdown-panel\">\n @if (user(); as u) {\n <div class=\"user-dropdown-profile\">\n <p class=\"user-dropdown-name\" [title]=\"u.name\">{{ u.name }}</p>\n <p class=\"user-dropdown-email\" [title]=\"u.email\">{{ u.email }}</p>\n </div>\n }\n\n <div class=\"user-menu-list\">\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\n <svg lucideUser class=\"user-menu-icon\"></svg>\n <span>My Profile</span>\n </button>\n\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('settings')\">\n <svg lucideSettings class=\"user-menu-icon\"></svg>\n <span>Settings</span>\n </button>\n\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('billing')\">\n <svg lucideCreditCard class=\"user-menu-icon\"></svg>\n <span>Billing</span>\n </button>\n </div>\n\n <div class=\"user-menu-danger-zone\">\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\n <svg lucideLogOut class=\"user-menu-icon\"></svg>\n <span>Sign Out</span>\n </button>\n </div>\r\n </div>\r\n }\r\n</div>\n", styles: [":host{display:inline-block}.user-menu-wrapper{position:relative;display:inline-block;text-align:left}.user-menu-trigger{display:flex;align-items:center;gap:.375rem;border:1px solid var(--border);border-radius:999px;color:var(--foreground);background:var(--background);padding:.125rem .45rem .125rem .125rem;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.user-menu-avatar{width:1.75rem;height:1.75rem;overflow:hidden;border-radius:999px}.user-menu-chevron{width:.875rem;height:.875rem;color:var(--secondary);transition:transform .2s ease}.user-menu-chevron.rotate-180{transform:rotate(180deg)}.user-menu-trigger:hover{background:color-mix(in srgb,var(--border) 28%,transparent)}.user-menu-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.user-dropdown-panel{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.375rem;box-shadow:0 12px 30px #0f172a24;animation:dropdownEnter .15s cubic-bezier(.16,1,.3,1)}.user-dropdown-profile{border-bottom:1px solid var(--border);margin-bottom:.25rem;padding:.65rem .75rem}.user-dropdown-name,.user-dropdown-email{overflow:hidden;margin:0;text-overflow:ellipsis;white-space:nowrap}.user-dropdown-name{color:var(--foreground);font-size:.875rem;font-weight:750}.user-dropdown-email{margin-top:.125rem;color:var(--secondary);font-size:.78rem}.user-menu-list{display:grid;gap:.125rem;padding:.125rem 0}.user-menu-item{display:flex;width:100%;align-items:center;gap:.625rem;border:0;border-radius:.5rem;color:var(--foreground);background:transparent;padding:.55rem .75rem;font-size:.875rem;text-align:left;cursor:pointer;transition:background-color .15s ease,color .15s ease}.user-menu-icon{width:1rem;height:1rem;flex-shrink:0;color:var(--secondary)}.user-menu-item:hover{background:color-mix(in srgb,var(--border) 32%,transparent)}.user-menu-item.danger,.user-menu-item.danger .user-menu-icon{color:var(--danger, #ef4444)}.user-menu-item.danger:hover{background:color-mix(in srgb,var(--danger, #ef4444) 10%,transparent)}.user-menu-danger-zone{border-top:1px solid var(--border);margin-top:.25rem;padding-top:.25rem}@keyframes dropdownEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.user-dropdown-panel{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:14rem;max-width:calc(100vw - 1rem);transform-origin:top right}}\n"] }]
360
+ args: [{ selector: 'lib-user-menu', standalone: true, imports: [CommonModule, UserAvatarComponent, LucideChevronDown, LucideCreditCard, LucideLogOut, LucideSettings, LucideUser], template: "<div class=\"user-menu-wrapper\">\r\n <button type=\"button\" class=\"user-menu-trigger\" (click)=\"toggleMenu()\" aria-haspopup=\"true\" [aria-expanded]=\"isOpen()\"\r\n aria-label=\"User profile menu\">\r\n <div class=\"user-menu-avatar\">\r\n <lib-user-avatar [user]=\"user()\" />\r\n </div>\r\n <svg lucideChevronDown class=\"user-menu-chevron\"\r\n [class.rotate-180]=\"isOpen()\"></svg>\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"user-dropdown-panel\">\r\n @if (user(); as u) {\r\n <div class=\"user-dropdown-profile\">\r\n <p class=\"user-dropdown-name\" [title]=\"u.name\">{{ u.name }}</p>\r\n <p class=\"user-dropdown-email\" [title]=\"u.email\">{{ u.email }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"user-menu-list\">\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\r\n <svg lucideUser class=\"user-menu-icon\"></svg>\r\n <span>My Profile</span>\r\n </button>\r\n\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('settings')\">\r\n <svg lucideSettings class=\"user-menu-icon\"></svg>\r\n <span>Settings</span>\r\n </button>\r\n\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('billing')\">\r\n <svg lucideCreditCard class=\"user-menu-icon\"></svg>\r\n <span>Billing</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"user-menu-danger-zone\">\r\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\r\n <svg lucideLogOut class=\"user-menu-icon\"></svg>\r\n <span>Sign Out</span>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:inline-block}.user-menu-wrapper{position:relative;display:inline-block;text-align:left}.user-menu-trigger{display:flex;align-items:center;justify-content:center;gap:.35rem;min-height:2.25rem;border:1px solid var(--border);border-radius:999px;color:var(--foreground);background:var(--background);padding:.2rem .5rem .2rem .2rem;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,box-shadow .15s ease}.user-menu-avatar{display:block;width:1.65rem;height:1.65rem;flex:0 0 1.65rem;overflow:hidden;border-radius:999px}.user-menu-chevron{width:.875rem;height:.875rem;color:var(--secondary);transition:transform .2s ease}.user-menu-chevron.rotate-180{transform:rotate(180deg)}.user-menu-trigger:hover{background:color-mix(in srgb,var(--border) 28%,transparent)}.user-menu-trigger:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.user-dropdown-panel{position:fixed;z-index:50;top:3.75rem;right:.5rem;left:.5rem;overflow:hidden;border:1px solid var(--border);border-radius:.875rem;background:var(--background);padding:.375rem;box-shadow:0 12px 30px #0f172a24;animation:dropdownEnter .15s cubic-bezier(.16,1,.3,1)}.user-dropdown-profile{border-bottom:1px solid var(--border);margin-bottom:.25rem;padding:.65rem .75rem}.user-dropdown-name,.user-dropdown-email{overflow:hidden;margin:0;text-overflow:ellipsis;white-space:nowrap}.user-dropdown-name{color:var(--foreground);font-size:.875rem;font-weight:750}.user-dropdown-email{margin-top:.125rem;color:var(--secondary);font-size:.78rem}.user-menu-list{display:grid;gap:.125rem;padding:.125rem 0}.user-menu-item{display:flex;width:100%;align-items:center;gap:.625rem;border:0;border-radius:.5rem;color:var(--foreground);background:transparent;padding:.55rem .75rem;font-size:.875rem;text-align:left;cursor:pointer;transition:background-color .15s ease,color .15s ease}.user-menu-icon{width:1rem;height:1rem;flex-shrink:0;color:var(--secondary)}.user-menu-item:hover{background:color-mix(in srgb,var(--border) 32%,transparent)}.user-menu-item.danger,.user-menu-item.danger .user-menu-icon{color:var(--danger, #ef4444)}.user-menu-item.danger:hover{background:color-mix(in srgb,var(--danger, #ef4444) 10%,transparent)}.user-menu-danger-zone{border-top:1px solid var(--border);margin-top:.25rem;padding-top:.25rem}@keyframes dropdownEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}@media(min-width:640px){.user-dropdown-panel{position:absolute;top:calc(100% + .5rem);right:0;left:auto;width:14rem;max-width:calc(100vw - 1rem);transform-origin:top right}}\n"] }]
332
361
  }], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }], menuAction: [{ type: i0.Output, args: ["menuAction"] }], onOutsideClick: [{
333
362
  type: HostListener,
334
363
  args: ['document:click', ['$event']]
@@ -341,39 +370,39 @@ class IconComponent {
341
370
  color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
342
371
  strokeWidth = input(undefined, ...(ngDevMode ? [{ debugName: "strokeWidth" }] : /* istanbul ignore next */ []));
343
372
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
344
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: IconComponent, isStandalone: true, selector: "lib-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
345
- @switch (name()) {
346
- @case ('menu') {
347
- <svg lucideMenu [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
348
- }
349
- @case ('x') {
350
- <svg lucideX [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
351
- }
352
- @case ('sun') {
353
- <svg lucideSun [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
354
- }
355
- @case ('moon') {
356
- <svg lucideMoon [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
357
- }
358
- @case ('monitor') {
359
- <svg lucideMonitor [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
360
- }
361
- @case ('bell') {
362
- <svg lucideBell [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
363
- }
364
- @case ('grid') {
365
- <svg lucideGrid [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
366
- }
367
- @case ('chevronDown') {
368
- <svg lucideChevronDown [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
369
- }
370
- @case ('building2') {
371
- <svg lucideBuilding2 [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
372
- }
373
- @default {
374
- <svg lucideSearch [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
375
- }
376
- }
373
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: IconComponent, isStandalone: true, selector: "lib-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
374
+ @switch (name()) {
375
+ @case ('menu') {
376
+ <svg lucideMenu [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
377
+ }
378
+ @case ('x') {
379
+ <svg lucideX [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
380
+ }
381
+ @case ('sun') {
382
+ <svg lucideSun [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
383
+ }
384
+ @case ('moon') {
385
+ <svg lucideMoon [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
386
+ }
387
+ @case ('monitor') {
388
+ <svg lucideMonitor [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
389
+ }
390
+ @case ('bell') {
391
+ <svg lucideBell [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
392
+ }
393
+ @case ('grid') {
394
+ <svg lucideGrid [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
395
+ }
396
+ @case ('chevronDown') {
397
+ <svg lucideChevronDown [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
398
+ }
399
+ @case ('building2') {
400
+ <svg lucideBuilding2 [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
401
+ }
402
+ @default {
403
+ <svg lucideSearch [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
404
+ }
405
+ }
377
406
  `, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center;color:inherit}.lib-icon{display:block;color:inherit}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideBell, selector: "svg[lucideBell]" }, { kind: "component", type: LucideBuilding2, selector: "svg[lucideBuilding2]" }, { kind: "component", type: LucideChevronDown, selector: "svg[lucideChevronDown]" }, { kind: "component", type: LucideGrid, selector: "svg[lucideGrid3x3], svg[lucideGrid], svg[lucideGrid3X3]" }, { kind: "component", type: LucideMenu, selector: "svg[lucideMenu]" }, { kind: "component", type: LucideMonitor, selector: "svg[lucideMonitor]" }, { kind: "component", type: LucideMoon, selector: "svg[lucideMoon]" }, { kind: "component", type: LucideSearch, selector: "svg[lucideSearch]" }, { kind: "component", type: LucideSun, selector: "svg[lucideSun]" }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }] });
378
407
  }
379
408
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: IconComponent, decorators: [{
@@ -390,49 +419,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
390
419
  LucideSearch,
391
420
  LucideSun,
392
421
  LucideX,
393
- ], template: `
394
- @switch (name()) {
395
- @case ('menu') {
396
- <svg lucideMenu [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
397
- }
398
- @case ('x') {
399
- <svg lucideX [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
400
- }
401
- @case ('sun') {
402
- <svg lucideSun [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
403
- }
404
- @case ('moon') {
405
- <svg lucideMoon [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
406
- }
407
- @case ('monitor') {
408
- <svg lucideMonitor [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
409
- }
410
- @case ('bell') {
411
- <svg lucideBell [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
412
- }
413
- @case ('grid') {
414
- <svg lucideGrid [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
415
- }
416
- @case ('chevronDown') {
417
- <svg lucideChevronDown [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
418
- }
419
- @case ('building2') {
420
- <svg lucideBuilding2 [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
421
- }
422
- @default {
423
- <svg lucideSearch [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
424
- }
425
- }
422
+ ], template: `
423
+ @switch (name()) {
424
+ @case ('menu') {
425
+ <svg lucideMenu [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
426
+ }
427
+ @case ('x') {
428
+ <svg lucideX [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
429
+ }
430
+ @case ('sun') {
431
+ <svg lucideSun [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
432
+ }
433
+ @case ('moon') {
434
+ <svg lucideMoon [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
435
+ }
436
+ @case ('monitor') {
437
+ <svg lucideMonitor [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
438
+ }
439
+ @case ('bell') {
440
+ <svg lucideBell [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
441
+ }
442
+ @case ('grid') {
443
+ <svg lucideGrid [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
444
+ }
445
+ @case ('chevronDown') {
446
+ <svg lucideChevronDown [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
447
+ }
448
+ @case ('building2') {
449
+ <svg lucideBuilding2 [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
450
+ }
451
+ @default {
452
+ <svg lucideSearch [size]="size()" [color]="color()" [strokeWidth]="strokeWidth()" class="lib-icon"></svg>
453
+ }
454
+ }
426
455
  `, styles: [":host{display:inline-flex;align-items:center;justify-content:center;color:inherit}.lib-icon{display:block;color:inherit}\n"] }]
427
456
  }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }] } });
428
457
 
429
458
  class HeaderComponent {
430
459
  router = inject(Router);
431
460
  themeService = inject(ThemeService);
432
- // User & Organization Inputs
433
- user = input(null, ...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
461
+ // User Inputs
462
+ user = input.required(...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
434
463
  permissions = input([], ...(ngDevMode ? [{ debugName: "permissions" }] : /* istanbul ignore next */ []));
435
- organization = input(null, ...(ngDevMode ? [{ debugName: "organization" }] : /* istanbul ignore next */ []));
436
464
  // Navigation & Integration Inputs
437
465
  navigationItems = input([], ...(ngDevMode ? [{ debugName: "navigationItems" }] : /* istanbul ignore next */ []));
438
466
  applications = input([], ...(ngDevMode ? [{ debugName: "applications" }] : /* istanbul ignore next */ []));
@@ -445,10 +473,8 @@ class HeaderComponent {
445
473
  showNotifications = input(true, ...(ngDevMode ? [{ debugName: "showNotifications" }] : /* istanbul ignore next */ []));
446
474
  showAppSwitcher = input(true, ...(ngDevMode ? [{ debugName: "showAppSwitcher" }] : /* istanbul ignore next */ []));
447
475
  showThemeSwitcher = input(true, ...(ngDevMode ? [{ debugName: "showThemeSwitcher" }] : /* istanbul ignore next */ []));
448
- showSignIn = input(true, ...(ngDevMode ? [{ debugName: "showSignIn" }] : /* istanbul ignore next */ []));
449
476
  // Outputs as decided in the architecture plan
450
477
  search = output();
451
- signIn = output();
452
478
  applicationSelected = output();
453
479
  notificationClick = output();
454
480
  markRead = output();
@@ -520,7 +546,7 @@ class HeaderComponent {
520
546
  this.menuAction.emit(action);
521
547
  }
522
548
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
523
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: HeaderComponent, isStandalone: true, selector: "lib-header", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: false, transformFunction: null }, organization: { classPropertyName: "organization", publicName: "organization", isSignal: true, isRequired: false, transformFunction: null }, navigationItems: { classPropertyName: "navigationItems", publicName: "navigationItems", isSignal: true, isRequired: false, transformFunction: null }, applications: { classPropertyName: "applications", publicName: "applications", isSignal: true, isRequired: false, transformFunction: null }, notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null }, notificationCount: { classPropertyName: "notificationCount", publicName: "notificationCount", isSignal: true, isRequired: false, transformFunction: null }, logoUrl: { classPropertyName: "logoUrl", publicName: "logoUrl", isSignal: true, isRequired: false, transformFunction: null }, appName: { classPropertyName: "appName", publicName: "appName", isSignal: true, isRequired: false, transformFunction: null }, currentAppName: { classPropertyName: "currentAppName", publicName: "currentAppName", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showNotifications: { classPropertyName: "showNotifications", publicName: "showNotifications", isSignal: true, isRequired: false, transformFunction: null }, showAppSwitcher: { classPropertyName: "showAppSwitcher", publicName: "showAppSwitcher", isSignal: true, isRequired: false, transformFunction: null }, showThemeSwitcher: { classPropertyName: "showThemeSwitcher", publicName: "showThemeSwitcher", isSignal: true, isRequired: false, transformFunction: null }, showSignIn: { classPropertyName: "showSignIn", publicName: "showSignIn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { search: "search", signIn: "signIn", applicationSelected: "applicationSelected", notificationClick: "notificationClick", markRead: "markRead", clearAll: "clearAll", menuAction: "menuAction" }, ngImport: i0, template: "<header class=\"header-container\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"header-left\">\n\n <a routerLink=\"/\" class=\"brand-identity\">\n <img [src]=\"logoUrl()\" [alt]=\"appName() + ' logo'\" width=\"26\" height=\"26\" class=\"brand-logo\" />\n <span class=\"brand-name\">{{ appName() }}</span>\n </a>\n\n @if (currentAppName()) {\n <div class=\"current-app-identity\" [attr.aria-label]=\"'Current app: ' + currentAppName()\">\n <span class=\"brand-separator\" aria-hidden=\"true\">|</span>\n <span class=\"current-app-name\">{{ currentAppName() }}</span>\n </div>\n }\n\n <!-- Desktop Navigation Links -->\n <nav class=\"desktop-nav ml-1 hidden items-center lg:flex\" aria-label=\"Desktop primary navigation\">\n @for (item of navigationItems(); track item.id) {\n @if (hasPermission(item)) {\n @if (item.route) {\n <a [routerLink]=\"item.route\" routerLinkActive=\"active\" [routerLinkActiveOptions]=\"{exact: true}\" class=\"nav-link\"\n [attr.aria-current]=\"isActive(item) ? 'page' : null\">\n {{ item.label }}\n </a>\n } @else {\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" class=\"nav-link\">\n {{ item.label }}\n </a>\n }\n }\n }\n </nav>\n </div>\n\n <!-- Middle: Search Input (Desktop) -->\n @if (showSearch()) {\n <div class=\"header-middle\">\n <div class=\"header-search-shell\">\n <lib-icon name=\"search\" [size]=\"14\"\n class=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-[var(--secondary)]\" />\n\n <input type=\"search\" placeholder=\"Search Excellore...\" #searchInput\n (keyup.enter)=\"onSearch(searchInput.value); searchInput.value = ''\" class=\"header-search\" autocomplete=\"off\"\n aria-label=\"Search\" />\n </div>\n </div>\n } @else {\n <div class=\"header-spacer\"></div>\n }\n\n <!-- Right Side Actions -->\n <div class=\"header-actions\">\n\n <!-- Mobile Search Trigger -->\n @if (showSearch()) {\n <button type=\"button\" class=\"header-action mobile-search-action\" (click)=\"toggleMobileMenu()\"\n aria-label=\"Open mobile menu\" aria-expanded=\"isMobileMenuOpen()\" #menuToggle>\n <lib-icon name=\"search\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\n </button>\n }\n\n <!-- Theme Switcher -->\n @if (showThemeSwitcher()) {\n <button type=\"button\" class=\"header-action\" (click)=\"themeService.toggleTheme()\" aria-label=\"Toggle theme\">\n @switch (themeService.theme()) {\n @case ('light') {\n <lib-icon name=\"sun\" [size]=\"16\" class=\"text-[var(--primary)]\" />\n }\n @case ('dark') {\n <lib-icon name=\"moon\" [size]=\"16\" class=\"text-[var(--primary)]\" />\n }\n @default {\n <lib-icon name=\"monitor\" [size]=\"16\" class=\"text-[var(--secondary)]\" />\n }\n }\n </button>\n }\n\n <!-- App Switcher -->\n @if (showAppSwitcher() && applications().length > 0) {\n <lib-app-switcher [applications]=\"applications()\" (applicationSelected)=\"onApplicationSelect($event)\" />\n }\n\n <!-- Notifications -->\n @if (showNotifications()) {\n <lib-notification-bell [unreadCount]=\"unreadCount()\" [notifications]=\"notifications()\"\n (notificationClick)=\"onNotificationClick($event)\" (markRead)=\"onMarkRead($event)\" (clearAll)=\"onClearAll()\" />\n }\n\n <!-- User Menu -->\n @if (user()) {\n <div class=\"user-menu-divider\">\n <lib-user-menu [user]=\"user()\" (menuAction)=\"onMenuAction($event)\" />\n </div>\n } @else if (showSignIn()) {\n <button type=\"button\" class=\"sign-in-button\" (click)=\"signIn.emit()\">\n Sign in\n </button>\n }\n\n <!-- Mobile Menu Toggle (Hamburger) -->\n @if (hasMobileMenuContent()) {\n <button type=\"button\" class=\"header-action mobile-menu-action\" (click)=\"toggleMobileMenu()\"\n aria-label=\"Toggle navigation menu\" aria-expanded=\"isMobileMenuOpen()\" #mobileMenuToggle>\n <lib-icon [name]=\"isMobileMenuOpen() ? 'x' : 'menu'\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n</header>\n\n<!-- Mobile Menu Backdrop -->\n@if (isMobileMenuOpen() && hasMobileMenuContent()) {\n<div class=\"mobile-backdrop fixed inset-0 z-30 lg:hidden\" (click)=\"closeMobileMenu()\"\n (keydown.escape)=\"closeMobileMenu()\" tabindex=\"-1\" aria-hidden=\"true\"></div>\n\n<!-- Mobile Navigation Drawer -->\n<div\n class=\"mobile-drawer fixed inset-x-2 top-16 z-40 flex max-h-[calc(100dvh-4.5rem)] flex-col rounded-2xl border border-[var(--border)] bg-[var(--background)] p-3 lg:hidden\"\n role=\"dialog\" aria-modal=\"true\" aria-label=\"Mobile navigation\" (keydown.escape)=\"closeMobileMenu()\">\n <!-- Mobile Search -->\n @if (showSearch()) {\n <div class=\"relative mb-3 w-full\">\n <lib-icon name=\"search\" [size]=\"16\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--secondary)] pointer-events-none\"\n aria-hidden=\"true\" />\n\n <input type=\"search\" placeholder=\"Search Excellore...\" #mobileSearchInput\n (keyup.enter)=\"onSearch(mobileSearchInput.value); mobileSearchInput.value = ''; closeMobileMenu()\"\n class=\"header-search mobile\" autocomplete=\"off\" aria-label=\"Search\" />\n </div>\n }\n\n <!-- Mobile Nav Links -->\n <nav class=\"flex flex-col gap-1 overflow-y-auto\" role=\"navigation\">\n @for (item of navigationItems(); track item.id) {\n @if (hasPermission(item)) {\n @if (item.route) {\n <a [routerLink]=\"item.route\" routerLinkActive=\"mobile-active\" [routerLinkActiveOptions]=\"{exact: true}\"\n (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\" [attr.aria-current]=\"isActive(item) ? 'page' : null\">\n {{ item.label }}\n </a>\n } @else {\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\">\n {{ item.label }}\n </a>\n }\n }\n }\n </nav>\n</div>\n}\n", styles: [":host{display:block}.header-container{position:fixed;z-index:40;top:0;right:0;left:0;display:flex;height:3.75rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);color:var(--foreground);background:var(--background);box-shadow:0 1px 2px #0f172a0a;padding-inline:1rem;will-change:transform}.header-left{display:flex;min-width:0;align-items:center;gap:.75rem}.brand-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem;border-radius:.5rem;color:var(--foreground);text-decoration:none}.brand-identity:hover{opacity:.9}.brand-logo{width:1.625rem;height:1.625rem;flex-shrink:0;-webkit-user-select:none;user-select:none}.brand-name{display:none;color:var(--foreground);font-size:.95rem;font-weight:750;letter-spacing:-.01em;white-space:nowrap}.current-app-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem}.brand-separator{color:var(--border);font-size:1rem;font-weight:500}.current-app-name{max-width:11rem;overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.desktop-nav{display:none;align-items:center;gap:1.25rem;margin-left:.25rem;padding:0;background:transparent}.header-middle{display:none;flex:1 1 auto;justify-content:center;padding-inline:1rem}.header-spacer{display:none;flex:1 1 auto}.nav-link{position:relative;display:inline-flex;align-items:center;min-height:2rem;color:var(--secondary);padding:0;font-size:.78rem;font-weight:600;line-height:1;text-decoration:none;transition:color .15s ease,opacity .15s ease}.nav-link:hover{color:var(--foreground)}.nav-link.active{color:var(--foreground)!important;font-weight:700}.nav-link.active:after{content:\"\";position:absolute;right:0;bottom:-.85rem;left:0;height:.125rem;background-color:var(--primary);border-radius:9999px}.header-search-shell{position:relative;width:min(100%,20rem)}.header-search{width:100%;height:2.25rem;border:1px solid var(--border);border-radius:.5rem;outline:0;color:var(--foreground);background:var(--background);padding:0 .9rem 0 2.25rem;font-size:.78rem;transition:border-color .15s ease,box-shadow .15s ease}.header-search::placeholder{color:var(--secondary)}.header-search:focus{border-color:var(--primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--primary) 16%,transparent)}.header-search.mobile{width:100%;height:2.6rem;border-radius:.625rem;font-size:.875rem}.header-search.mobile:focus{width:100%}.header-actions{display:flex;align-items:center;gap:.25rem;background:transparent}.header-action{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.header-action:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.user-menu-divider{display:flex;height:1.75rem;align-items:center;margin-left:.2rem;border-left:1px solid var(--border);padding-left:.35rem}.sign-in-button{height:2.15rem;border:1px solid var(--primary);border-radius:.5rem;color:#fff;background:var(--primary);padding:0 .85rem;font-size:.825rem;font-weight:700;cursor:pointer;transition:opacity .15s ease,box-shadow .15s ease}.sign-in-button:hover{opacity:.92;box-shadow:0 4px 10px color-mix(in srgb,var(--primary) 18%,transparent)}.sign-in-button:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.mobile-backdrop{background:#0f172a29}.mobile-drawer{box-shadow:0 12px 30px #0f172a24;animation:slideDown .2s cubic-bezier(.16,1,.3,1)}.mobile-nav-link{display:flex;align-items:center;min-height:2.75rem;border-radius:.625rem;color:var(--secondary);padding:0 .85rem;font-size:.925rem;font-weight:700;text-decoration:none;transition:background-color .15s ease,color .15s ease,transform .15s ease}.mobile-nav-link:hover{color:var(--foreground);background:color-mix(in srgb,var(--border) 35%,transparent)}.mobile-active{color:var(--foreground)!important;background:color-mix(in srgb,var(--primary) 10%,transparent);font-weight:700}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}:focus-visible{outline:2px solid var(--primary);outline-offset:2px}:focus:not(:focus-visible){outline:none}lucide-icon,svg{display:inline-flex;vertical-align:middle}*{transition-property:background-color,border-color,color;transition-duration:.15s;transition-timing-function:ease-in-out}@media(min-width:640px){.header-container{padding-inline:1.25rem}.brand-name{display:inline-block}.header-actions{gap:.25rem}.user-menu-divider{padding-left:.5rem}}@media(min-width:768px){.header-middle{display:flex}.header-spacer{display:block}.mobile-search-action{display:none}}@media(min-width:1024px){.header-container{padding-inline:2rem}.desktop-nav{display:flex}.mobile-menu-action{display:none}}@media(max-width:420px){.current-app-name{max-width:8rem}.header-actions{gap:0;padding:0;background:transparent}.header-action{width:2rem;height:2rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: AppSwitcherComponent, selector: "lib-app-switcher", inputs: ["applications"], outputs: ["applicationSelected"] }, { kind: "component", type: NotificationBellComponent, selector: "lib-notification-bell", inputs: ["unreadCount", "notifications"], outputs: ["notificationClick", "markRead", "clearAll"] }, { kind: "component", type: UserMenuComponent, selector: "lib-user-menu", inputs: ["user"], outputs: ["menuAction"] }, { kind: "component", type: IconComponent, selector: "lib-icon", inputs: ["name", "size", "color", "strokeWidth"] }] });
549
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: HeaderComponent, isStandalone: true, selector: "lib-header", inputs: { user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: true, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: false, transformFunction: null }, navigationItems: { classPropertyName: "navigationItems", publicName: "navigationItems", isSignal: true, isRequired: false, transformFunction: null }, applications: { classPropertyName: "applications", publicName: "applications", isSignal: true, isRequired: false, transformFunction: null }, notifications: { classPropertyName: "notifications", publicName: "notifications", isSignal: true, isRequired: false, transformFunction: null }, notificationCount: { classPropertyName: "notificationCount", publicName: "notificationCount", isSignal: true, isRequired: false, transformFunction: null }, logoUrl: { classPropertyName: "logoUrl", publicName: "logoUrl", isSignal: true, isRequired: false, transformFunction: null }, appName: { classPropertyName: "appName", publicName: "appName", isSignal: true, isRequired: false, transformFunction: null }, currentAppName: { classPropertyName: "currentAppName", publicName: "currentAppName", isSignal: true, isRequired: false, transformFunction: null }, showSearch: { classPropertyName: "showSearch", publicName: "showSearch", isSignal: true, isRequired: false, transformFunction: null }, showNotifications: { classPropertyName: "showNotifications", publicName: "showNotifications", isSignal: true, isRequired: false, transformFunction: null }, showAppSwitcher: { classPropertyName: "showAppSwitcher", publicName: "showAppSwitcher", isSignal: true, isRequired: false, transformFunction: null }, showThemeSwitcher: { classPropertyName: "showThemeSwitcher", publicName: "showThemeSwitcher", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { search: "search", applicationSelected: "applicationSelected", notificationClick: "notificationClick", markRead: "markRead", clearAll: "clearAll", menuAction: "menuAction" }, ngImport: i0, template: "<header class=\"header-container\">\r\n\r\n <!-- Left Side: Brand, Current App & Desktop Links -->\r\n <div class=\"header-left\">\r\n\r\n <a routerLink=\"/\" class=\"brand-identity\">\r\n <img [src]=\"logoUrl()\" [alt]=\"appName() + ' logo'\" width=\"26\" height=\"26\" class=\"brand-logo\" />\r\n <span class=\"brand-name\">{{ appName() }}</span>\r\n </a>\r\n\r\n @if (currentAppName()) {\r\n <div class=\"current-app-identity\" [attr.aria-label]=\"'Current app: ' + currentAppName()\">\r\n <span class=\"brand-separator\" aria-hidden=\"true\">|</span>\r\n <span class=\"current-app-name\">{{ currentAppName() }}</span>\r\n </div>\r\n }\r\n\r\n <!-- Desktop Navigation Links -->\r\n <nav class=\"desktop-nav ml-1 hidden items-center lg:flex\" aria-label=\"Desktop primary navigation\">\r\n @for (item of navigationItems(); track item.id) {\r\n @if (hasPermission(item)) {\r\n @if (item.route) {\r\n <a [routerLink]=\"item.route\" routerLinkActive=\"active\" [routerLinkActiveOptions]=\"{exact: true}\" class=\"nav-link\"\r\n [attr.aria-current]=\"isActive(item) ? 'page' : null\">\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" class=\"nav-link\">\r\n {{ item.label }}\r\n </a>\r\n }\r\n }\r\n }\r\n </nav>\r\n </div>\r\n\r\n <!-- Middle: Search Input (Desktop) -->\r\n @if (showSearch()) {\r\n <div class=\"header-middle\">\r\n <div class=\"header-search-shell\">\r\n <lib-icon name=\"search\" [size]=\"14\"\r\n class=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-[var(--secondary)]\" />\r\n\r\n <input type=\"search\" placeholder=\"Search Excellore...\" #searchInput\r\n (keyup.enter)=\"onSearch(searchInput.value); searchInput.value = ''\" class=\"header-search\" autocomplete=\"off\"\r\n aria-label=\"Search\" />\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"header-spacer\"></div>\r\n }\r\n\r\n <!-- Right Side Actions -->\r\n <div class=\"header-actions\">\r\n\r\n <!-- Mobile Search Trigger -->\r\n @if (showSearch()) {\r\n <button type=\"button\" class=\"header-action mobile-search-action\" (click)=\"toggleMobileMenu()\"\r\n aria-label=\"Open mobile menu\" aria-expanded=\"isMobileMenuOpen()\" #menuToggle>\r\n <lib-icon name=\"search\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\r\n </button>\r\n }\r\n\r\n <!-- Theme Switcher -->\r\n @if (showThemeSwitcher()) {\r\n <button type=\"button\" class=\"header-action\" (click)=\"themeService.toggleTheme()\" aria-label=\"Toggle theme\">\r\n @switch (themeService.theme()) {\r\n @case ('light') {\r\n <lib-icon name=\"sun\" [size]=\"16\" class=\"text-[var(--primary)]\" />\r\n }\r\n @case ('dark') {\r\n <lib-icon name=\"moon\" [size]=\"16\" class=\"text-[var(--primary)]\" />\r\n }\r\n @default {\r\n <lib-icon name=\"monitor\" [size]=\"16\" class=\"text-[var(--secondary)]\" />\r\n }\r\n }\r\n </button>\r\n }\r\n\r\n <!-- App Switcher -->\r\n @if (showAppSwitcher() && applications().length > 0) {\r\n <lib-app-switcher [applications]=\"applications()\" (applicationSelected)=\"onApplicationSelect($event)\" />\r\n }\r\n\r\n <!-- Notifications -->\r\n @if (showNotifications()) {\r\n <lib-notification-bell [unreadCount]=\"unreadCount()\" [notifications]=\"notifications()\"\r\n (notificationClick)=\"onNotificationClick($event)\" (markRead)=\"onMarkRead($event)\" (clearAll)=\"onClearAll()\" />\r\n }\r\n\r\n <!-- User Menu -->\n <div class=\"user-menu-divider\">\n <lib-user-menu [user]=\"user()\" (menuAction)=\"onMenuAction($event)\" />\n </div>\n\n <!-- Mobile Menu Toggle (Hamburger) -->\n @if (hasMobileMenuContent()) {\r\n <button type=\"button\" class=\"header-action mobile-menu-action\" (click)=\"toggleMobileMenu()\"\r\n aria-label=\"Toggle navigation menu\" aria-expanded=\"isMobileMenuOpen()\" #mobileMenuToggle>\r\n <lib-icon [name]=\"isMobileMenuOpen() ? 'x' : 'menu'\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\r\n </button>\r\n }\r\n </div>\r\n</header>\r\n\r\n<!-- Mobile Menu Backdrop -->\r\n@if (isMobileMenuOpen() && hasMobileMenuContent()) {\r\n<div class=\"mobile-backdrop fixed inset-0 z-30 lg:hidden\" (click)=\"closeMobileMenu()\"\r\n (keydown.escape)=\"closeMobileMenu()\" tabindex=\"-1\" aria-hidden=\"true\"></div>\r\n\r\n<!-- Mobile Navigation Drawer -->\r\n<div\r\n class=\"mobile-drawer fixed inset-x-2 top-16 z-40 flex max-h-[calc(100dvh-4.5rem)] flex-col rounded-2xl border border-[var(--border)] bg-[var(--background)] p-3 lg:hidden\"\r\n role=\"dialog\" aria-modal=\"true\" aria-label=\"Mobile navigation\" (keydown.escape)=\"closeMobileMenu()\">\r\n <!-- Mobile Search -->\r\n @if (showSearch()) {\r\n <div class=\"relative mb-3 w-full\">\r\n <lib-icon name=\"search\" [size]=\"16\"\r\n class=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--secondary)] pointer-events-none\"\r\n aria-hidden=\"true\" />\r\n\r\n <input type=\"search\" placeholder=\"Search Excellore...\" #mobileSearchInput\r\n (keyup.enter)=\"onSearch(mobileSearchInput.value); mobileSearchInput.value = ''; closeMobileMenu()\"\r\n class=\"header-search mobile\" autocomplete=\"off\" aria-label=\"Search\" />\r\n </div>\r\n }\r\n\r\n <!-- Mobile Nav Links -->\r\n <nav class=\"flex flex-col gap-1 overflow-y-auto\" role=\"navigation\">\r\n @for (item of navigationItems(); track item.id) {\r\n @if (hasPermission(item)) {\r\n @if (item.route) {\r\n <a [routerLink]=\"item.route\" routerLinkActive=\"mobile-active\" [routerLinkActiveOptions]=\"{exact: true}\"\r\n (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\" [attr.aria-current]=\"isActive(item) ? 'page' : null\">\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\">\r\n {{ item.label }}\r\n </a>\r\n }\r\n }\r\n }\r\n </nav>\r\n</div>\r\n}\r\n", styles: [":host{display:block}.header-container{position:fixed;z-index:40;top:0;right:0;left:0;display:flex;height:3.75rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);color:var(--foreground);background:var(--background);box-shadow:0 1px 2px #0f172a0a;padding-inline:1rem;will-change:transform}.header-left{display:flex;min-width:0;align-items:center;gap:.75rem}.brand-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem;border-radius:.5rem;color:var(--foreground);text-decoration:none}.brand-identity:hover{opacity:.9}.brand-logo{width:1.625rem;height:1.625rem;flex-shrink:0;-webkit-user-select:none;user-select:none}.brand-name{display:none;color:var(--foreground);font-size:.95rem;font-weight:750;letter-spacing:-.01em;white-space:nowrap}.current-app-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem}.brand-separator{color:var(--border);font-size:1rem;font-weight:500}.current-app-name{max-width:11rem;overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.desktop-nav{display:none;align-items:center;gap:1.25rem;margin-left:.25rem;padding:0;background:transparent}.header-middle{display:none;flex:1 1 auto;justify-content:center;padding-inline:1rem}.header-spacer{display:none;flex:1 1 auto}.nav-link{position:relative;display:inline-flex;align-items:center;min-height:2rem;color:var(--secondary);padding:0;font-size:.78rem;font-weight:600;line-height:1;text-decoration:none;transition:color .15s ease,opacity .15s ease}.nav-link:hover{color:var(--foreground)}.nav-link.active{color:var(--foreground)!important;font-weight:700}.nav-link.active:after{content:\"\";position:absolute;right:0;bottom:-.85rem;left:0;height:.125rem;background-color:var(--primary);border-radius:9999px}.header-search-shell{position:relative;width:min(100%,20rem)}.header-search{width:100%;height:2.25rem;border:1px solid var(--border);border-radius:.5rem;outline:0;color:var(--foreground);background:var(--background);padding:0 .9rem 0 2.25rem;font-size:.78rem;transition:border-color .15s ease,box-shadow .15s ease}.header-search::placeholder{color:var(--secondary)}.header-search:focus{border-color:var(--primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--primary) 16%,transparent)}.header-search.mobile{width:100%;height:2.6rem;border-radius:.625rem;font-size:.875rem}.header-search.mobile:focus{width:100%}.header-actions{display:flex;align-items:center;gap:.25rem;background:transparent}.header-action{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.header-action:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.user-menu-divider{display:flex;height:1.75rem;align-items:center;margin-left:.2rem;border-left:1px solid var(--border);padding-left:.35rem}.mobile-backdrop{background:#0f172a29}.mobile-drawer{box-shadow:0 12px 30px #0f172a24;animation:slideDown .2s cubic-bezier(.16,1,.3,1)}.mobile-nav-link{display:flex;align-items:center;min-height:2.75rem;border-radius:.625rem;color:var(--secondary);padding:0 .85rem;font-size:.925rem;font-weight:700;text-decoration:none;transition:background-color .15s ease,color .15s ease,transform .15s ease}.mobile-nav-link:hover{color:var(--foreground);background:color-mix(in srgb,var(--border) 35%,transparent)}.mobile-active{color:var(--foreground)!important;background:color-mix(in srgb,var(--primary) 10%,transparent);font-weight:700}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}:focus-visible{outline:2px solid var(--primary);outline-offset:2px}:focus:not(:focus-visible){outline:none}lucide-icon,svg{display:inline-flex;vertical-align:middle}*{transition-property:background-color,border-color,color;transition-duration:.15s;transition-timing-function:ease-in-out}@media(min-width:640px){.header-container{padding-inline:1.25rem}.brand-name{display:inline-block}.header-actions{gap:.25rem}.user-menu-divider{padding-left:.5rem}}@media(min-width:768px){.header-middle{display:flex}.header-spacer{display:block}.mobile-search-action{display:none}}@media(min-width:1024px){.header-container{padding-inline:1.5rem}.desktop-nav{display:flex}.mobile-menu-action{display:none}}@media(max-width:420px){.current-app-name{max-width:8rem}.header-actions{gap:0;padding:0;background:transparent}.header-action{width:2rem;height:2rem}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: AppSwitcherComponent, selector: "lib-app-switcher", inputs: ["applications"], outputs: ["applicationSelected"] }, { kind: "component", type: NotificationBellComponent, selector: "lib-notification-bell", inputs: ["unreadCount", "notifications"], outputs: ["notificationClick", "markRead", "clearAll"] }, { kind: "component", type: UserMenuComponent, selector: "lib-user-menu", inputs: ["user"], outputs: ["menuAction"] }, { kind: "component", type: IconComponent, selector: "lib-icon", inputs: ["name", "size", "color", "strokeWidth"] }] });
524
550
  }
525
551
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: HeaderComponent, decorators: [{
526
552
  type: Component,
@@ -532,8 +558,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
532
558
  NotificationBellComponent,
533
559
  UserMenuComponent,
534
560
  IconComponent,
535
- ], template: "<header class=\"header-container\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"header-left\">\n\n <a routerLink=\"/\" class=\"brand-identity\">\n <img [src]=\"logoUrl()\" [alt]=\"appName() + ' logo'\" width=\"26\" height=\"26\" class=\"brand-logo\" />\n <span class=\"brand-name\">{{ appName() }}</span>\n </a>\n\n @if (currentAppName()) {\n <div class=\"current-app-identity\" [attr.aria-label]=\"'Current app: ' + currentAppName()\">\n <span class=\"brand-separator\" aria-hidden=\"true\">|</span>\n <span class=\"current-app-name\">{{ currentAppName() }}</span>\n </div>\n }\n\n <!-- Desktop Navigation Links -->\n <nav class=\"desktop-nav ml-1 hidden items-center lg:flex\" aria-label=\"Desktop primary navigation\">\n @for (item of navigationItems(); track item.id) {\n @if (hasPermission(item)) {\n @if (item.route) {\n <a [routerLink]=\"item.route\" routerLinkActive=\"active\" [routerLinkActiveOptions]=\"{exact: true}\" class=\"nav-link\"\n [attr.aria-current]=\"isActive(item) ? 'page' : null\">\n {{ item.label }}\n </a>\n } @else {\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" class=\"nav-link\">\n {{ item.label }}\n </a>\n }\n }\n }\n </nav>\n </div>\n\n <!-- Middle: Search Input (Desktop) -->\n @if (showSearch()) {\n <div class=\"header-middle\">\n <div class=\"header-search-shell\">\n <lib-icon name=\"search\" [size]=\"14\"\n class=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-[var(--secondary)]\" />\n\n <input type=\"search\" placeholder=\"Search Excellore...\" #searchInput\n (keyup.enter)=\"onSearch(searchInput.value); searchInput.value = ''\" class=\"header-search\" autocomplete=\"off\"\n aria-label=\"Search\" />\n </div>\n </div>\n } @else {\n <div class=\"header-spacer\"></div>\n }\n\n <!-- Right Side Actions -->\n <div class=\"header-actions\">\n\n <!-- Mobile Search Trigger -->\n @if (showSearch()) {\n <button type=\"button\" class=\"header-action mobile-search-action\" (click)=\"toggleMobileMenu()\"\n aria-label=\"Open mobile menu\" aria-expanded=\"isMobileMenuOpen()\" #menuToggle>\n <lib-icon name=\"search\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\n </button>\n }\n\n <!-- Theme Switcher -->\n @if (showThemeSwitcher()) {\n <button type=\"button\" class=\"header-action\" (click)=\"themeService.toggleTheme()\" aria-label=\"Toggle theme\">\n @switch (themeService.theme()) {\n @case ('light') {\n <lib-icon name=\"sun\" [size]=\"16\" class=\"text-[var(--primary)]\" />\n }\n @case ('dark') {\n <lib-icon name=\"moon\" [size]=\"16\" class=\"text-[var(--primary)]\" />\n }\n @default {\n <lib-icon name=\"monitor\" [size]=\"16\" class=\"text-[var(--secondary)]\" />\n }\n }\n </button>\n }\n\n <!-- App Switcher -->\n @if (showAppSwitcher() && applications().length > 0) {\n <lib-app-switcher [applications]=\"applications()\" (applicationSelected)=\"onApplicationSelect($event)\" />\n }\n\n <!-- Notifications -->\n @if (showNotifications()) {\n <lib-notification-bell [unreadCount]=\"unreadCount()\" [notifications]=\"notifications()\"\n (notificationClick)=\"onNotificationClick($event)\" (markRead)=\"onMarkRead($event)\" (clearAll)=\"onClearAll()\" />\n }\n\n <!-- User Menu -->\n @if (user()) {\n <div class=\"user-menu-divider\">\n <lib-user-menu [user]=\"user()\" (menuAction)=\"onMenuAction($event)\" />\n </div>\n } @else if (showSignIn()) {\n <button type=\"button\" class=\"sign-in-button\" (click)=\"signIn.emit()\">\n Sign in\n </button>\n }\n\n <!-- Mobile Menu Toggle (Hamburger) -->\n @if (hasMobileMenuContent()) {\n <button type=\"button\" class=\"header-action mobile-menu-action\" (click)=\"toggleMobileMenu()\"\n aria-label=\"Toggle navigation menu\" aria-expanded=\"isMobileMenuOpen()\" #mobileMenuToggle>\n <lib-icon [name]=\"isMobileMenuOpen() ? 'x' : 'menu'\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\n </button>\n }\n </div>\n</header>\n\n<!-- Mobile Menu Backdrop -->\n@if (isMobileMenuOpen() && hasMobileMenuContent()) {\n<div class=\"mobile-backdrop fixed inset-0 z-30 lg:hidden\" (click)=\"closeMobileMenu()\"\n (keydown.escape)=\"closeMobileMenu()\" tabindex=\"-1\" aria-hidden=\"true\"></div>\n\n<!-- Mobile Navigation Drawer -->\n<div\n class=\"mobile-drawer fixed inset-x-2 top-16 z-40 flex max-h-[calc(100dvh-4.5rem)] flex-col rounded-2xl border border-[var(--border)] bg-[var(--background)] p-3 lg:hidden\"\n role=\"dialog\" aria-modal=\"true\" aria-label=\"Mobile navigation\" (keydown.escape)=\"closeMobileMenu()\">\n <!-- Mobile Search -->\n @if (showSearch()) {\n <div class=\"relative mb-3 w-full\">\n <lib-icon name=\"search\" [size]=\"16\"\n class=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--secondary)] pointer-events-none\"\n aria-hidden=\"true\" />\n\n <input type=\"search\" placeholder=\"Search Excellore...\" #mobileSearchInput\n (keyup.enter)=\"onSearch(mobileSearchInput.value); mobileSearchInput.value = ''; closeMobileMenu()\"\n class=\"header-search mobile\" autocomplete=\"off\" aria-label=\"Search\" />\n </div>\n }\n\n <!-- Mobile Nav Links -->\n <nav class=\"flex flex-col gap-1 overflow-y-auto\" role=\"navigation\">\n @for (item of navigationItems(); track item.id) {\n @if (hasPermission(item)) {\n @if (item.route) {\n <a [routerLink]=\"item.route\" routerLinkActive=\"mobile-active\" [routerLinkActiveOptions]=\"{exact: true}\"\n (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\" [attr.aria-current]=\"isActive(item) ? 'page' : null\">\n {{ item.label }}\n </a>\n } @else {\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\">\n {{ item.label }}\n </a>\n }\n }\n }\n </nav>\n</div>\n}\n", styles: [":host{display:block}.header-container{position:fixed;z-index:40;top:0;right:0;left:0;display:flex;height:3.75rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);color:var(--foreground);background:var(--background);box-shadow:0 1px 2px #0f172a0a;padding-inline:1rem;will-change:transform}.header-left{display:flex;min-width:0;align-items:center;gap:.75rem}.brand-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem;border-radius:.5rem;color:var(--foreground);text-decoration:none}.brand-identity:hover{opacity:.9}.brand-logo{width:1.625rem;height:1.625rem;flex-shrink:0;-webkit-user-select:none;user-select:none}.brand-name{display:none;color:var(--foreground);font-size:.95rem;font-weight:750;letter-spacing:-.01em;white-space:nowrap}.current-app-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem}.brand-separator{color:var(--border);font-size:1rem;font-weight:500}.current-app-name{max-width:11rem;overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.desktop-nav{display:none;align-items:center;gap:1.25rem;margin-left:.25rem;padding:0;background:transparent}.header-middle{display:none;flex:1 1 auto;justify-content:center;padding-inline:1rem}.header-spacer{display:none;flex:1 1 auto}.nav-link{position:relative;display:inline-flex;align-items:center;min-height:2rem;color:var(--secondary);padding:0;font-size:.78rem;font-weight:600;line-height:1;text-decoration:none;transition:color .15s ease,opacity .15s ease}.nav-link:hover{color:var(--foreground)}.nav-link.active{color:var(--foreground)!important;font-weight:700}.nav-link.active:after{content:\"\";position:absolute;right:0;bottom:-.85rem;left:0;height:.125rem;background-color:var(--primary);border-radius:9999px}.header-search-shell{position:relative;width:min(100%,20rem)}.header-search{width:100%;height:2.25rem;border:1px solid var(--border);border-radius:.5rem;outline:0;color:var(--foreground);background:var(--background);padding:0 .9rem 0 2.25rem;font-size:.78rem;transition:border-color .15s ease,box-shadow .15s ease}.header-search::placeholder{color:var(--secondary)}.header-search:focus{border-color:var(--primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--primary) 16%,transparent)}.header-search.mobile{width:100%;height:2.6rem;border-radius:.625rem;font-size:.875rem}.header-search.mobile:focus{width:100%}.header-actions{display:flex;align-items:center;gap:.25rem;background:transparent}.header-action{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.header-action:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.user-menu-divider{display:flex;height:1.75rem;align-items:center;margin-left:.2rem;border-left:1px solid var(--border);padding-left:.35rem}.sign-in-button{height:2.15rem;border:1px solid var(--primary);border-radius:.5rem;color:#fff;background:var(--primary);padding:0 .85rem;font-size:.825rem;font-weight:700;cursor:pointer;transition:opacity .15s ease,box-shadow .15s ease}.sign-in-button:hover{opacity:.92;box-shadow:0 4px 10px color-mix(in srgb,var(--primary) 18%,transparent)}.sign-in-button:focus-visible{outline:2px solid var(--primary);outline-offset:2px}.mobile-backdrop{background:#0f172a29}.mobile-drawer{box-shadow:0 12px 30px #0f172a24;animation:slideDown .2s cubic-bezier(.16,1,.3,1)}.mobile-nav-link{display:flex;align-items:center;min-height:2.75rem;border-radius:.625rem;color:var(--secondary);padding:0 .85rem;font-size:.925rem;font-weight:700;text-decoration:none;transition:background-color .15s ease,color .15s ease,transform .15s ease}.mobile-nav-link:hover{color:var(--foreground);background:color-mix(in srgb,var(--border) 35%,transparent)}.mobile-active{color:var(--foreground)!important;background:color-mix(in srgb,var(--primary) 10%,transparent);font-weight:700}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}:focus-visible{outline:2px solid var(--primary);outline-offset:2px}:focus:not(:focus-visible){outline:none}lucide-icon,svg{display:inline-flex;vertical-align:middle}*{transition-property:background-color,border-color,color;transition-duration:.15s;transition-timing-function:ease-in-out}@media(min-width:640px){.header-container{padding-inline:1.25rem}.brand-name{display:inline-block}.header-actions{gap:.25rem}.user-menu-divider{padding-left:.5rem}}@media(min-width:768px){.header-middle{display:flex}.header-spacer{display:block}.mobile-search-action{display:none}}@media(min-width:1024px){.header-container{padding-inline:2rem}.desktop-nav{display:flex}.mobile-menu-action{display:none}}@media(max-width:420px){.current-app-name{max-width:8rem}.header-actions{gap:0;padding:0;background:transparent}.header-action{width:2rem;height:2rem}}\n"] }]
536
- }], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }], permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: false }] }], organization: [{ type: i0.Input, args: [{ isSignal: true, alias: "organization", required: false }] }], navigationItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigationItems", required: false }] }], applications: [{ type: i0.Input, args: [{ isSignal: true, alias: "applications", required: false }] }], notifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "notifications", required: false }] }], notificationCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "notificationCount", required: false }] }], logoUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoUrl", required: false }] }], appName: [{ type: i0.Input, args: [{ isSignal: true, alias: "appName", required: false }] }], currentAppName: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentAppName", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], showNotifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNotifications", required: false }] }], showAppSwitcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAppSwitcher", required: false }] }], showThemeSwitcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThemeSwitcher", required: false }] }], showSignIn: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSignIn", required: false }] }], search: [{ type: i0.Output, args: ["search"] }], signIn: [{ type: i0.Output, args: ["signIn"] }], applicationSelected: [{ type: i0.Output, args: ["applicationSelected"] }], notificationClick: [{ type: i0.Output, args: ["notificationClick"] }], markRead: [{ type: i0.Output, args: ["markRead"] }], clearAll: [{ type: i0.Output, args: ["clearAll"] }], menuAction: [{ type: i0.Output, args: ["menuAction"] }] } });
561
+ ], template: "<header class=\"header-container\">\r\n\r\n <!-- Left Side: Brand, Current App & Desktop Links -->\r\n <div class=\"header-left\">\r\n\r\n <a routerLink=\"/\" class=\"brand-identity\">\r\n <img [src]=\"logoUrl()\" [alt]=\"appName() + ' logo'\" width=\"26\" height=\"26\" class=\"brand-logo\" />\r\n <span class=\"brand-name\">{{ appName() }}</span>\r\n </a>\r\n\r\n @if (currentAppName()) {\r\n <div class=\"current-app-identity\" [attr.aria-label]=\"'Current app: ' + currentAppName()\">\r\n <span class=\"brand-separator\" aria-hidden=\"true\">|</span>\r\n <span class=\"current-app-name\">{{ currentAppName() }}</span>\r\n </div>\r\n }\r\n\r\n <!-- Desktop Navigation Links -->\r\n <nav class=\"desktop-nav ml-1 hidden items-center lg:flex\" aria-label=\"Desktop primary navigation\">\r\n @for (item of navigationItems(); track item.id) {\r\n @if (hasPermission(item)) {\r\n @if (item.route) {\r\n <a [routerLink]=\"item.route\" routerLinkActive=\"active\" [routerLinkActiveOptions]=\"{exact: true}\" class=\"nav-link\"\r\n [attr.aria-current]=\"isActive(item) ? 'page' : null\">\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" class=\"nav-link\">\r\n {{ item.label }}\r\n </a>\r\n }\r\n }\r\n }\r\n </nav>\r\n </div>\r\n\r\n <!-- Middle: Search Input (Desktop) -->\r\n @if (showSearch()) {\r\n <div class=\"header-middle\">\r\n <div class=\"header-search-shell\">\r\n <lib-icon name=\"search\" [size]=\"14\"\r\n class=\"pointer-events-none absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-[var(--secondary)]\" />\r\n\r\n <input type=\"search\" placeholder=\"Search Excellore...\" #searchInput\r\n (keyup.enter)=\"onSearch(searchInput.value); searchInput.value = ''\" class=\"header-search\" autocomplete=\"off\"\r\n aria-label=\"Search\" />\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"header-spacer\"></div>\r\n }\r\n\r\n <!-- Right Side Actions -->\r\n <div class=\"header-actions\">\r\n\r\n <!-- Mobile Search Trigger -->\r\n @if (showSearch()) {\r\n <button type=\"button\" class=\"header-action mobile-search-action\" (click)=\"toggleMobileMenu()\"\r\n aria-label=\"Open mobile menu\" aria-expanded=\"isMobileMenuOpen()\" #menuToggle>\r\n <lib-icon name=\"search\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\r\n </button>\r\n }\r\n\r\n <!-- Theme Switcher -->\r\n @if (showThemeSwitcher()) {\r\n <button type=\"button\" class=\"header-action\" (click)=\"themeService.toggleTheme()\" aria-label=\"Toggle theme\">\r\n @switch (themeService.theme()) {\r\n @case ('light') {\r\n <lib-icon name=\"sun\" [size]=\"16\" class=\"text-[var(--primary)]\" />\r\n }\r\n @case ('dark') {\r\n <lib-icon name=\"moon\" [size]=\"16\" class=\"text-[var(--primary)]\" />\r\n }\r\n @default {\r\n <lib-icon name=\"monitor\" [size]=\"16\" class=\"text-[var(--secondary)]\" />\r\n }\r\n }\r\n </button>\r\n }\r\n\r\n <!-- App Switcher -->\r\n @if (showAppSwitcher() && applications().length > 0) {\r\n <lib-app-switcher [applications]=\"applications()\" (applicationSelected)=\"onApplicationSelect($event)\" />\r\n }\r\n\r\n <!-- Notifications -->\r\n @if (showNotifications()) {\r\n <lib-notification-bell [unreadCount]=\"unreadCount()\" [notifications]=\"notifications()\"\r\n (notificationClick)=\"onNotificationClick($event)\" (markRead)=\"onMarkRead($event)\" (clearAll)=\"onClearAll()\" />\r\n }\r\n\r\n <!-- User Menu -->\n <div class=\"user-menu-divider\">\n <lib-user-menu [user]=\"user()\" (menuAction)=\"onMenuAction($event)\" />\n </div>\n\n <!-- Mobile Menu Toggle (Hamburger) -->\n @if (hasMobileMenuContent()) {\r\n <button type=\"button\" class=\"header-action mobile-menu-action\" (click)=\"toggleMobileMenu()\"\r\n aria-label=\"Toggle navigation menu\" aria-expanded=\"isMobileMenuOpen()\" #mobileMenuToggle>\r\n <lib-icon [name]=\"isMobileMenuOpen() ? 'x' : 'menu'\" [size]=\"16\" class=\"h-4.5 w-4.5\" aria-hidden=\"true\" />\r\n </button>\r\n }\r\n </div>\r\n</header>\r\n\r\n<!-- Mobile Menu Backdrop -->\r\n@if (isMobileMenuOpen() && hasMobileMenuContent()) {\r\n<div class=\"mobile-backdrop fixed inset-0 z-30 lg:hidden\" (click)=\"closeMobileMenu()\"\r\n (keydown.escape)=\"closeMobileMenu()\" tabindex=\"-1\" aria-hidden=\"true\"></div>\r\n\r\n<!-- Mobile Navigation Drawer -->\r\n<div\r\n class=\"mobile-drawer fixed inset-x-2 top-16 z-40 flex max-h-[calc(100dvh-4.5rem)] flex-col rounded-2xl border border-[var(--border)] bg-[var(--background)] p-3 lg:hidden\"\r\n role=\"dialog\" aria-modal=\"true\" aria-label=\"Mobile navigation\" (keydown.escape)=\"closeMobileMenu()\">\r\n <!-- Mobile Search -->\r\n @if (showSearch()) {\r\n <div class=\"relative mb-3 w-full\">\r\n <lib-icon name=\"search\" [size]=\"16\"\r\n class=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-[var(--secondary)] pointer-events-none\"\r\n aria-hidden=\"true\" />\r\n\r\n <input type=\"search\" placeholder=\"Search Excellore...\" #mobileSearchInput\r\n (keyup.enter)=\"onSearch(mobileSearchInput.value); mobileSearchInput.value = ''; closeMobileMenu()\"\r\n class=\"header-search mobile\" autocomplete=\"off\" aria-label=\"Search\" />\r\n </div>\r\n }\r\n\r\n <!-- Mobile Nav Links -->\r\n <nav class=\"flex flex-col gap-1 overflow-y-auto\" role=\"navigation\">\r\n @for (item of navigationItems(); track item.id) {\r\n @if (hasPermission(item)) {\r\n @if (item.route) {\r\n <a [routerLink]=\"item.route\" routerLinkActive=\"mobile-active\" [routerLinkActiveOptions]=\"{exact: true}\"\r\n (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\" [attr.aria-current]=\"isActive(item) ? 'page' : null\">\r\n {{ item.label }}\r\n </a>\r\n } @else {\r\n <a [href]=\"item.href\" [target]=\"item.target || '_self'\" (click)=\"closeMobileMenu()\" class=\"mobile-nav-link\">\r\n {{ item.label }}\r\n </a>\r\n }\r\n }\r\n }\r\n </nav>\r\n</div>\r\n}\r\n", styles: [":host{display:block}.header-container{position:fixed;z-index:40;top:0;right:0;left:0;display:flex;height:3.75rem;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border);color:var(--foreground);background:var(--background);box-shadow:0 1px 2px #0f172a0a;padding-inline:1rem;will-change:transform}.header-left{display:flex;min-width:0;align-items:center;gap:.75rem}.brand-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem;border-radius:.5rem;color:var(--foreground);text-decoration:none}.brand-identity:hover{opacity:.9}.brand-logo{width:1.625rem;height:1.625rem;flex-shrink:0;-webkit-user-select:none;user-select:none}.brand-name{display:none;color:var(--foreground);font-size:.95rem;font-weight:750;letter-spacing:-.01em;white-space:nowrap}.current-app-identity{display:inline-flex;min-width:0;align-items:center;gap:.5rem}.brand-separator{color:var(--border);font-size:1rem;font-weight:500}.current-app-name{max-width:11rem;overflow:hidden;color:var(--foreground);font-size:.875rem;font-weight:650;text-overflow:ellipsis;white-space:nowrap}.desktop-nav{display:none;align-items:center;gap:1.25rem;margin-left:.25rem;padding:0;background:transparent}.header-middle{display:none;flex:1 1 auto;justify-content:center;padding-inline:1rem}.header-spacer{display:none;flex:1 1 auto}.nav-link{position:relative;display:inline-flex;align-items:center;min-height:2rem;color:var(--secondary);padding:0;font-size:.78rem;font-weight:600;line-height:1;text-decoration:none;transition:color .15s ease,opacity .15s ease}.nav-link:hover{color:var(--foreground)}.nav-link.active{color:var(--foreground)!important;font-weight:700}.nav-link.active:after{content:\"\";position:absolute;right:0;bottom:-.85rem;left:0;height:.125rem;background-color:var(--primary);border-radius:9999px}.header-search-shell{position:relative;width:min(100%,20rem)}.header-search{width:100%;height:2.25rem;border:1px solid var(--border);border-radius:.5rem;outline:0;color:var(--foreground);background:var(--background);padding:0 .9rem 0 2.25rem;font-size:.78rem;transition:border-color .15s ease,box-shadow .15s ease}.header-search::placeholder{color:var(--secondary)}.header-search:focus{border-color:var(--primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--primary) 16%,transparent)}.header-search.mobile{width:100%;height:2.6rem;border-radius:.625rem;font-size:.875rem}.header-search.mobile:focus{width:100%}.header-actions{display:flex;align-items:center;gap:.25rem;background:transparent}.header-action{display:grid;width:2.15rem;height:2.15rem;place-items:center;border:1px solid transparent;border-radius:.5rem;color:var(--foreground);background:transparent;cursor:pointer;transition:background-color .15s ease,border-color .15s ease,color .15s ease}.header-action:hover{border-color:var(--border);background:color-mix(in srgb,var(--border) 35%,transparent)}.user-menu-divider{display:flex;height:1.75rem;align-items:center;margin-left:.2rem;border-left:1px solid var(--border);padding-left:.35rem}.mobile-backdrop{background:#0f172a29}.mobile-drawer{box-shadow:0 12px 30px #0f172a24;animation:slideDown .2s cubic-bezier(.16,1,.3,1)}.mobile-nav-link{display:flex;align-items:center;min-height:2.75rem;border-radius:.625rem;color:var(--secondary);padding:0 .85rem;font-size:.925rem;font-weight:700;text-decoration:none;transition:background-color .15s ease,color .15s ease,transform .15s ease}.mobile-nav-link:hover{color:var(--foreground);background:color-mix(in srgb,var(--border) 35%,transparent)}.mobile-active{color:var(--foreground)!important;background:color-mix(in srgb,var(--primary) 10%,transparent);font-weight:700}@keyframes slideDown{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}:focus-visible{outline:2px solid var(--primary);outline-offset:2px}:focus:not(:focus-visible){outline:none}lucide-icon,svg{display:inline-flex;vertical-align:middle}*{transition-property:background-color,border-color,color;transition-duration:.15s;transition-timing-function:ease-in-out}@media(min-width:640px){.header-container{padding-inline:1.25rem}.brand-name{display:inline-block}.header-actions{gap:.25rem}.user-menu-divider{padding-left:.5rem}}@media(min-width:768px){.header-middle{display:flex}.header-spacer{display:block}.mobile-search-action{display:none}}@media(min-width:1024px){.header-container{padding-inline:1.5rem}.desktop-nav{display:flex}.mobile-menu-action{display:none}}@media(max-width:420px){.current-app-name{max-width:8rem}.header-actions{gap:0;padding:0;background:transparent}.header-action{width:2rem;height:2rem}}\n"] }]
562
+ }], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: true }] }], permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: false }] }], navigationItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "navigationItems", required: false }] }], applications: [{ type: i0.Input, args: [{ isSignal: true, alias: "applications", required: false }] }], notifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "notifications", required: false }] }], notificationCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "notificationCount", required: false }] }], logoUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoUrl", required: false }] }], appName: [{ type: i0.Input, args: [{ isSignal: true, alias: "appName", required: false }] }], currentAppName: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentAppName", required: false }] }], showSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearch", required: false }] }], showNotifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "showNotifications", required: false }] }], showAppSwitcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAppSwitcher", required: false }] }], showThemeSwitcher: [{ type: i0.Input, args: [{ isSignal: true, alias: "showThemeSwitcher", required: false }] }], search: [{ type: i0.Output, args: ["search"] }], applicationSelected: [{ type: i0.Output, args: ["applicationSelected"] }], notificationClick: [{ type: i0.Output, args: ["notificationClick"] }], markRead: [{ type: i0.Output, args: ["markRead"] }], clearAll: [{ type: i0.Output, args: ["clearAll"] }], menuAction: [{ type: i0.Output, args: ["menuAction"] }] } });
563
+
564
+ class SidebarComponent {
565
+ menuItems = input([], ...(ngDevMode ? [{ debugName: "menuItems" }] : /* istanbul ignore next */ []));
566
+ menuError = input(null, ...(ngDevMode ? [{ debugName: "menuError" }] : /* istanbul ignore next */ []));
567
+ showMobileToggle = input(true, ...(ngDevMode ? [{ debugName: "showMobileToggle" }] : /* istanbul ignore next */ []));
568
+ menuItemSelected = output();
569
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
570
+ toggleSidebar() {
571
+ this.isOpen.update((value) => !value);
572
+ }
573
+ closeSidebar() {
574
+ this.isOpen.set(false);
575
+ }
576
+ onMenuItemSelected(item) {
577
+ this.menuItemSelected.emit(item);
578
+ this.closeSidebar();
579
+ }
580
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
581
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: SidebarComponent, isStandalone: true, selector: "lib-sidebar", inputs: { menuItems: { classPropertyName: "menuItems", publicName: "menuItems", isSignal: true, isRequired: false, transformFunction: null }, menuError: { classPropertyName: "menuError", publicName: "menuError", isSignal: true, isRequired: false, transformFunction: null }, showMobileToggle: { classPropertyName: "showMobileToggle", publicName: "showMobileToggle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { menuItemSelected: "menuItemSelected" }, ngImport: i0, template: "@if (showMobileToggle()) {\r\n<button\r\n class=\"sidebar-toggle\"\r\n type=\"button\"\r\n title=\"Toggle sidebar menu\"\r\n aria-label=\"Toggle sidebar menu\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n (click)=\"toggleSidebar()\"\r\n>\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n</button>\r\n}\r\n\r\n@if (isOpen()) {\r\n<div class=\"sidebar-overlay\" (click)=\"closeSidebar()\" (keydown.escape)=\"closeSidebar()\" tabindex=\"-1\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<aside class=\"sidebar\" [class.open]=\"isOpen()\" aria-label=\"Application sidebar\">\n <div class=\"sidebar__middle\">\n <lib-sidebar-menu\n [items]=\"menuItems()\"\n [errorMessage]=\"menuError()\"\n (menuItemSelected)=\"onMenuItemSelected($event)\"\n />\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-toggle{position:fixed;z-index:50;top:.75rem;left:.75rem;display:grid;gap:.25rem;width:2.5rem;height:2.5rem;place-content:center;border:1px solid var(--border, #e5e7eb);border-radius:.5rem;background:var(--background, #ffffff);box-shadow:0 1px 2px #0f172a14;cursor:pointer}.sidebar-toggle span{display:block;width:1.125rem;height:.125rem;border-radius:999px;background:var(--accent-primary, var(--primary, #0067b8))}.sidebar-overlay{position:fixed;z-index:40;inset:0;background:#0000004d}.sidebar{position:fixed;z-index:45;top:0;left:0;display:flex;width:17.1875rem;height:100dvh;flex-direction:column;overflow:hidden;border-right:1px solid var(--border-primary, var(--border, #e5e7eb));background:var(--bg-primary, var(--background, #ffffff));color:var(--text-primary, var(--foreground, #111827));transform:translate(-100%);transition:transform .3s ease-in-out}.sidebar.open{transform:translate(0)}.sidebar__middle{min-height:0;flex:1 1 auto;overflow:hidden}@media(min-width:768px){.sidebar-toggle,.sidebar-overlay{display:none}.sidebar{position:sticky;z-index:auto;transform:translate(0)}}\n"], dependencies: [{ kind: "component", type: SidebarMenuComponent, selector: "lib-sidebar-menu", inputs: ["items", "errorMessage", "defaultIcon"], outputs: ["menuItemSelected"] }] });
582
+ }
583
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: SidebarComponent, decorators: [{
584
+ type: Component,
585
+ args: [{ selector: 'lib-sidebar', standalone: true, imports: [SidebarMenuComponent], template: "@if (showMobileToggle()) {\r\n<button\r\n class=\"sidebar-toggle\"\r\n type=\"button\"\r\n title=\"Toggle sidebar menu\"\r\n aria-label=\"Toggle sidebar menu\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n (click)=\"toggleSidebar()\"\r\n>\r\n <span></span>\r\n <span></span>\r\n <span></span>\r\n</button>\r\n}\r\n\r\n@if (isOpen()) {\r\n<div class=\"sidebar-overlay\" (click)=\"closeSidebar()\" (keydown.escape)=\"closeSidebar()\" tabindex=\"-1\" aria-hidden=\"true\"></div>\r\n}\r\n\r\n<aside class=\"sidebar\" [class.open]=\"isOpen()\" aria-label=\"Application sidebar\">\n <div class=\"sidebar__middle\">\n <lib-sidebar-menu\n [items]=\"menuItems()\"\n [errorMessage]=\"menuError()\"\n (menuItemSelected)=\"onMenuItemSelected($event)\"\n />\n </div>\n</aside>\n", styles: [":host{display:block}.sidebar-toggle{position:fixed;z-index:50;top:.75rem;left:.75rem;display:grid;gap:.25rem;width:2.5rem;height:2.5rem;place-content:center;border:1px solid var(--border, #e5e7eb);border-radius:.5rem;background:var(--background, #ffffff);box-shadow:0 1px 2px #0f172a14;cursor:pointer}.sidebar-toggle span{display:block;width:1.125rem;height:.125rem;border-radius:999px;background:var(--accent-primary, var(--primary, #0067b8))}.sidebar-overlay{position:fixed;z-index:40;inset:0;background:#0000004d}.sidebar{position:fixed;z-index:45;top:0;left:0;display:flex;width:17.1875rem;height:100dvh;flex-direction:column;overflow:hidden;border-right:1px solid var(--border-primary, var(--border, #e5e7eb));background:var(--bg-primary, var(--background, #ffffff));color:var(--text-primary, var(--foreground, #111827));transform:translate(-100%);transition:transform .3s ease-in-out}.sidebar.open{transform:translate(0)}.sidebar__middle{min-height:0;flex:1 1 auto;overflow:hidden}@media(min-width:768px){.sidebar-toggle,.sidebar-overlay{display:none}.sidebar{position:sticky;z-index:auto;transform:translate(0)}}\n"] }]
586
+ }], propDecorators: { menuItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuItems", required: false }] }], menuError: [{ type: i0.Input, args: [{ isSignal: true, alias: "menuError", required: false }] }], showMobileToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMobileToggle", required: false }] }], menuItemSelected: [{ type: i0.Output, args: ["menuItemSelected"] }] } });
537
587
 
538
588
  /*
539
589
  * Public API Surface of ui
@@ -543,5 +593,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
543
593
  * Generated bundle index. Do not edit.
544
594
  */
545
595
 
546
- export { AppSwitcherComponent, HeaderComponent, NotificationBellComponent, NotificationPanelComponent, OrganizationSwitcherComponent, ThemeService, UserAvatarComponent, UserMenuComponent };
596
+ export { HeaderComponent, SidebarComponent, ThemeService };
547
597
  //# sourceMappingURL=excellore-ui.mjs.map