@excellore/ui 0.0.3 → 0.0.5
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.
|
@@ -2,8 +2,7 @@ import * as i0 from '@angular/core';
|
|
|
2
2
|
import { inject, PLATFORM_ID, signal, effect, Injectable, input, output, HostListener, Component, computed } from '@angular/core';
|
|
3
3
|
import { isPlatformBrowser, CommonModule } from '@angular/common';
|
|
4
4
|
import { Router, RouterLink, RouterLinkActive } from '@angular/router';
|
|
5
|
-
import
|
|
6
|
-
import { Grid, ChevronDown, LucideAngularModule, Check, Building, CheckCheck, Trash2, BellOff, Circle, Bell, User, Settings, CreditCard, LogOut, Building2, Monitor, Moon, Sun, X, Menu, Search } from 'lucide-angular';
|
|
5
|
+
import { LucideGrid, LucideBuilding, LucideCheck, LucideChevronDown, LucideBellOff, LucideCheckCheck, LucideTrash2, LucideBell, LucideCreditCard, LucideLogOut, LucideSettings, LucideUser, LucideBuilding2, LucideMenu, LucideMonitor, LucideMoon, LucideSearch, LucideSun, LucideX } from '@lucide/angular';
|
|
7
6
|
|
|
8
7
|
const THEME_STORAGE_KEY = 'excellore-theme';
|
|
9
8
|
class ThemeService {
|
|
@@ -123,8 +122,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
123
122
|
class AppSwitcherComponent {
|
|
124
123
|
applications = input([], ...(ngDevMode ? [{ debugName: "applications" }] : /* istanbul ignore next */ []));
|
|
125
124
|
applicationSelected = output();
|
|
126
|
-
gridIcon = Grid;
|
|
127
|
-
chevronDownIcon = ChevronDown;
|
|
128
125
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
129
126
|
toggleSwitcher() {
|
|
130
127
|
this.isOpen.update((v) => !v);
|
|
@@ -153,11 +150,11 @@ class AppSwitcherComponent {
|
|
|
153
150
|
}
|
|
154
151
|
}
|
|
155
152
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AppSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
156
|
-
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 relative inline-block text-left\">\r\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 <
|
|
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 relative inline-block text-left\">\r\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=\"h-4.5 w-4.5\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"app-switcher-dropdown fixed left-2 right-2 top-14 mt-2 max-h-[calc(100dvh-4.5rem)] origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-2.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-[360px] sm:max-w-[calc(100vw-1rem)] sm:origin-top-right\">\n <div class=\"mb-1.5 flex items-center justify-between border-b border-[var(--border)] px-1 pb-2.5\">\n <div>\n <h3 class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Excellore Apps</h3>\n <p class=\"mt-0.5 text-[11px] text-[var(--secondary)]\">Switch between available workspaces</p>\n </div>\n </div>\n \n @if (applications().length === 0) {\n <div class=\"py-6 text-center text-xs text-[var(--secondary)]\">\n No other apps available\n </div>\n } @else {\n <div class=\"max-h-[calc(100dvh-10rem)] overflow-y-auto py-1 sm:max-h-[420px]\">\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 group flex items-center gap-3 rounded-lg border border-transparent px-2.5 py-2.5 no-underline transition focus:outline-none focus:ring-2 focus:ring-[var(--primary)]\"\n >\n <div class=\"app-switcher-app-mark\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\" [title]=\"app.name\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-open-pill shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide opacity-0 transition group-hover:opacity-100\">\n Open\n </span>\n </a>\n } @else {\n <div class=\"app-switcher-item flex items-center gap-3 rounded-lg px-2.5 py-2.5 opacity-55 select-none\">\n <div class=\"app-switcher-app-mark unavailable\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"shrink-0 rounded-full border border-[var(--border)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[var(--secondary)]\">\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-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-dropdown{box-shadow:0 12px 30px #0f172a24;animation:switcherEnter .15s cubic-bezier(.16,1,.3,1)}.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-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-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{color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent)}.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)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideGrid, selector: "svg[lucideGrid3x3], svg[lucideGrid], svg[lucideGrid3X3]" }] });
|
|
157
154
|
}
|
|
158
155
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: AppSwitcherComponent, decorators: [{
|
|
159
156
|
type: Component,
|
|
160
|
-
args: [{ selector: 'lib-app-switcher', standalone: true, imports: [CommonModule,
|
|
157
|
+
args: [{ selector: 'lib-app-switcher', standalone: true, imports: [CommonModule, LucideGrid], template: "<div class=\"app-switcher-wrapper relative inline-block text-left\">\r\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=\"h-4.5 w-4.5\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"app-switcher-dropdown fixed left-2 right-2 top-14 mt-2 max-h-[calc(100dvh-4.5rem)] origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-2.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-[360px] sm:max-w-[calc(100vw-1rem)] sm:origin-top-right\">\n <div class=\"mb-1.5 flex items-center justify-between border-b border-[var(--border)] px-1 pb-2.5\">\n <div>\n <h3 class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Excellore Apps</h3>\n <p class=\"mt-0.5 text-[11px] text-[var(--secondary)]\">Switch between available workspaces</p>\n </div>\n </div>\n \n @if (applications().length === 0) {\n <div class=\"py-6 text-center text-xs text-[var(--secondary)]\">\n No other apps available\n </div>\n } @else {\n <div class=\"max-h-[calc(100dvh-10rem)] overflow-y-auto py-1 sm:max-h-[420px]\">\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 group flex items-center gap-3 rounded-lg border border-transparent px-2.5 py-2.5 no-underline transition focus:outline-none focus:ring-2 focus:ring-[var(--primary)]\"\n >\n <div class=\"app-switcher-app-mark\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\" [title]=\"app.name\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-open-pill shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide opacity-0 transition group-hover:opacity-100\">\n Open\n </span>\n </a>\n } @else {\n <div class=\"app-switcher-item flex items-center gap-3 rounded-lg px-2.5 py-2.5 opacity-55 select-none\">\n <div class=\"app-switcher-app-mark unavailable\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"shrink-0 rounded-full border border-[var(--border)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[var(--secondary)]\">\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-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-dropdown{box-shadow:0 12px 30px #0f172a24;animation:switcherEnter .15s cubic-bezier(.16,1,.3,1)}.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-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-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{color:var(--primary);background:color-mix(in srgb,var(--primary) 9%,transparent)}.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)}}\n"] }]
|
|
161
158
|
}], propDecorators: { applications: [{ type: i0.Input, args: [{ isSignal: true, alias: "applications", required: false }] }], applicationSelected: [{ type: i0.Output, args: ["applicationSelected"] }], onOutsideClick: [{
|
|
162
159
|
type: HostListener,
|
|
163
160
|
args: ['document:click', ['$event']]
|
|
@@ -167,9 +164,6 @@ class OrganizationSwitcherComponent {
|
|
|
167
164
|
organizations = input([], ...(ngDevMode ? [{ debugName: "organizations" }] : /* istanbul ignore next */ []));
|
|
168
165
|
selectedOrganization = input(null, ...(ngDevMode ? [{ debugName: "selectedOrganization" }] : /* istanbul ignore next */ []));
|
|
169
166
|
organizationChanged = output();
|
|
170
|
-
chevronDownIcon = ChevronDown;
|
|
171
|
-
checkIcon = Check;
|
|
172
|
-
buildingIcon = Building;
|
|
173
167
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
174
168
|
toggleSwitcher() {
|
|
175
169
|
this.isOpen.update((v) => !v);
|
|
@@ -188,11 +182,11 @@ class OrganizationSwitcherComponent {
|
|
|
188
182
|
}
|
|
189
183
|
}
|
|
190
184
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: OrganizationSwitcherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
191
|
-
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 <
|
|
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]" }] });
|
|
192
186
|
}
|
|
193
187
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: OrganizationSwitcherComponent, decorators: [{
|
|
194
188
|
type: Component,
|
|
195
|
-
args: [{ selector: 'lib-organization-switcher', standalone: true, imports: [CommonModule,
|
|
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"] }]
|
|
196
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: [{
|
|
197
191
|
type: HostListener,
|
|
198
192
|
args: ['document:click', ['$event']]
|
|
@@ -203,10 +197,6 @@ class NotificationPanelComponent {
|
|
|
203
197
|
notificationClick = output();
|
|
204
198
|
markRead = output();
|
|
205
199
|
clearAll = output();
|
|
206
|
-
checkCheckIcon = CheckCheck;
|
|
207
|
-
trashIcon = Trash2;
|
|
208
|
-
bellOffIcon = BellOff;
|
|
209
|
-
circleIcon = Circle;
|
|
210
200
|
onNotificationClick(notification) {
|
|
211
201
|
this.notificationClick.emit(notification);
|
|
212
202
|
}
|
|
@@ -236,11 +226,11 @@ class NotificationPanelComponent {
|
|
|
236
226
|
return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
|
|
237
227
|
}
|
|
238
228
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
239
|
-
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 <
|
|
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]" }] });
|
|
240
230
|
}
|
|
241
231
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationPanelComponent, decorators: [{
|
|
242
232
|
type: Component,
|
|
243
|
-
args: [{ selector: 'lib-notification-panel', standalone: true, imports: [CommonModule,
|
|
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"] }]
|
|
244
234
|
}], 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"] }] } });
|
|
245
235
|
|
|
246
236
|
class NotificationBellComponent {
|
|
@@ -249,7 +239,6 @@ class NotificationBellComponent {
|
|
|
249
239
|
notificationClick = output();
|
|
250
240
|
markRead = output();
|
|
251
241
|
clearAll = output();
|
|
252
|
-
bellIcon = Bell;
|
|
253
242
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
254
243
|
togglePanel() {
|
|
255
244
|
this.isOpen.update((v) => !v);
|
|
@@ -274,11 +263,11 @@ class NotificationBellComponent {
|
|
|
274
263
|
}
|
|
275
264
|
}
|
|
276
265
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationBellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
277
|
-
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 <
|
|
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]" }] });
|
|
278
267
|
}
|
|
279
268
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: NotificationBellComponent, decorators: [{
|
|
280
269
|
type: Component,
|
|
281
|
-
args: [{ selector: 'lib-notification-bell', standalone: true, imports: [CommonModule, NotificationPanelComponent,
|
|
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"] }]
|
|
282
271
|
}], 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: [{
|
|
283
272
|
type: HostListener,
|
|
284
273
|
args: ['document:click', ['$event']]
|
|
@@ -316,12 +305,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
316
305
|
class UserMenuComponent {
|
|
317
306
|
user = input(null, ...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
318
307
|
menuAction = output();
|
|
319
|
-
// Lucide Icons mapping
|
|
320
|
-
userIcon = User;
|
|
321
|
-
settingsIcon = Settings;
|
|
322
|
-
creditCardIcon = CreditCard;
|
|
323
|
-
logOutIcon = LogOut;
|
|
324
|
-
chevronDownIcon = ChevronDown;
|
|
325
308
|
// Signalled open state
|
|
326
309
|
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
327
310
|
toggleMenu() {
|
|
@@ -341,60 +324,106 @@ class UserMenuComponent {
|
|
|
341
324
|
}
|
|
342
325
|
}
|
|
343
326
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: UserMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
344
|
-
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 relative inline-block text-left\">\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=\"h-7 w-7 rounded-full overflow-hidden\">\r\n <lib-user-avatar [user]=\"user()\" />\r\n </div>\r\n <
|
|
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 relative inline-block text-left\">\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=\"h-7 w-7 rounded-full overflow-hidden\">\r\n <lib-user-avatar [user]=\"user()\" />\r\n </div>\r\n <svg lucideChevronDown class=\"h-3.5 w-3.5 text-[var(--secondary)] transition-transform duration-200\"\n [class.rotate-180]=\"isOpen()\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div\r\n class=\"user-dropdown-panel fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-1.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-56 sm:origin-top-right\">\r\n @if (user(); as u) {\r\n <div class=\"px-3 py-2 border-b border-[var(--border)] mb-1\">\r\n <p class=\"text-sm font-semibold truncate text-[var(--foreground)]\" [title]=\"u.name\">{{ u.name }}</p>\r\n <p class=\"text-xs truncate text-[var(--secondary)] mt-0.5\" [title]=\"u.email\">{{ u.email }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"py-0.5 space-y-0.5\">\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\r\n <svg lucideUser class=\"h-4 w-4 text-[var(--secondary)]\"></svg>\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=\"h-4 w-4 text-[var(--secondary)]\"></svg>\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=\"h-4 w-4 text-[var(--secondary)]\"></svg>\n <span>Billing</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"border-t border-[var(--border)] mt-1 pt-1\">\r\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\r\n <svg lucideLogOut class=\"h-4 w-4 text-[var(--danger,#ef4444)]\"></svg>\n <span>Sign Out</span>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\n", styles: [":host{display:inline-block}.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-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{box-shadow:0 12px 30px #0f172a24;animation:dropdownEnter .15s cubic-bezier(.16,1,.3,1)}.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-item:hover{background:color-mix(in srgb,var(--border) 32%,transparent)}.user-menu-item.danger{color:var(--danger, #ef4444)}.user-menu-item.danger:hover{background:color-mix(in srgb,var(--danger, #ef4444) 10%,transparent)}@keyframes dropdownEnter{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: 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]" }] });
|
|
345
328
|
}
|
|
346
329
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: UserMenuComponent, decorators: [{
|
|
347
330
|
type: Component,
|
|
348
|
-
args: [{ selector: 'lib-user-menu', standalone: true, imports: [CommonModule, UserAvatarComponent,
|
|
331
|
+
args: [{ selector: 'lib-user-menu', standalone: true, imports: [CommonModule, UserAvatarComponent, LucideChevronDown, LucideCreditCard, LucideLogOut, LucideSettings, LucideUser], template: "<div class=\"user-menu-wrapper relative inline-block text-left\">\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=\"h-7 w-7 rounded-full overflow-hidden\">\r\n <lib-user-avatar [user]=\"user()\" />\r\n </div>\r\n <svg lucideChevronDown class=\"h-3.5 w-3.5 text-[var(--secondary)] transition-transform duration-200\"\n [class.rotate-180]=\"isOpen()\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div\r\n class=\"user-dropdown-panel fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-1.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-56 sm:origin-top-right\">\r\n @if (user(); as u) {\r\n <div class=\"px-3 py-2 border-b border-[var(--border)] mb-1\">\r\n <p class=\"text-sm font-semibold truncate text-[var(--foreground)]\" [title]=\"u.name\">{{ u.name }}</p>\r\n <p class=\"text-xs truncate text-[var(--secondary)] mt-0.5\" [title]=\"u.email\">{{ u.email }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"py-0.5 space-y-0.5\">\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\r\n <svg lucideUser class=\"h-4 w-4 text-[var(--secondary)]\"></svg>\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=\"h-4 w-4 text-[var(--secondary)]\"></svg>\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=\"h-4 w-4 text-[var(--secondary)]\"></svg>\n <span>Billing</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"border-t border-[var(--border)] mt-1 pt-1\">\r\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\r\n <svg lucideLogOut class=\"h-4 w-4 text-[var(--danger,#ef4444)]\"></svg>\n <span>Sign Out</span>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\n", styles: [":host{display:inline-block}.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-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{box-shadow:0 12px 30px #0f172a24;animation:dropdownEnter .15s cubic-bezier(.16,1,.3,1)}.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-item:hover{background:color-mix(in srgb,var(--border) 32%,transparent)}.user-menu-item.danger{color:var(--danger, #ef4444)}.user-menu-item.danger:hover{background:color-mix(in srgb,var(--danger, #ef4444) 10%,transparent)}@keyframes dropdownEnter{0%{opacity:0;transform:scale(.95) translateY(-4px)}to{opacity:1;transform:scale(1) translateY(0)}}\n"] }]
|
|
349
332
|
}], propDecorators: { user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }], menuAction: [{ type: i0.Output, args: ["menuAction"] }], onOutsideClick: [{
|
|
350
333
|
type: HostListener,
|
|
351
334
|
args: ['document:click', ['$event']]
|
|
352
335
|
}] } });
|
|
353
336
|
|
|
354
337
|
// lib/shared/icon/icon.component.ts
|
|
355
|
-
const ICONS = {
|
|
356
|
-
search: Search,
|
|
357
|
-
menu: Menu,
|
|
358
|
-
x: X,
|
|
359
|
-
sun: Sun,
|
|
360
|
-
moon: Moon,
|
|
361
|
-
monitor: Monitor,
|
|
362
|
-
bell: Bell,
|
|
363
|
-
grid: Grid,
|
|
364
|
-
chevronDown: ChevronDown,
|
|
365
|
-
building2: Building2
|
|
366
|
-
};
|
|
367
338
|
class IconComponent {
|
|
368
339
|
name = input.required(...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
369
340
|
size = input(24, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
370
341
|
color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
371
342
|
strokeWidth = input(undefined, ...(ngDevMode ? [{ debugName: "strokeWidth" }] : /* istanbul ignore next */ []));
|
|
372
|
-
iconName = computed(() => {
|
|
373
|
-
const name = this.name();
|
|
374
|
-
return ICONS[name] || Search;
|
|
375
|
-
}, ...(ngDevMode ? [{ debugName: "iconName" }] : /* istanbul ignore next */ []));
|
|
376
343
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: IconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
377
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
+
}
|
|
377
|
+
`, 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]" }] });
|
|
386
378
|
}
|
|
387
379
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: IconComponent, decorators: [{
|
|
388
380
|
type: Component,
|
|
389
|
-
args: [{ selector: 'lib-icon', standalone: true, imports: [
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
381
|
+
args: [{ selector: 'lib-icon', standalone: true, imports: [
|
|
382
|
+
CommonModule,
|
|
383
|
+
LucideBell,
|
|
384
|
+
LucideBuilding2,
|
|
385
|
+
LucideChevronDown,
|
|
386
|
+
LucideGrid,
|
|
387
|
+
LucideMenu,
|
|
388
|
+
LucideMonitor,
|
|
389
|
+
LucideMoon,
|
|
390
|
+
LucideSearch,
|
|
391
|
+
LucideSun,
|
|
392
|
+
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
|
+
}
|
|
426
|
+
`, styles: [":host{display:inline-flex;align-items:center;justify-content:center;color:inherit}.lib-icon{display:block;color:inherit}\n"] }]
|
|
398
427
|
}], 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 }] }] } });
|
|
399
428
|
|
|
400
429
|
class HeaderComponent {
|
|
@@ -491,7 +520,7 @@ class HeaderComponent {
|
|
|
491
520
|
this.menuAction.emit(action);
|
|
492
521
|
}
|
|
493
522
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
494
|
-
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\n class=\"header-container fixed top-0 inset-x-0 z-40 flex h-[3.75rem] items-center justify-between px-3 text-[var(--foreground)] sm:px-4 lg:px-6\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"flex min-w-0 items-center gap-3\">\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=\"hidden flex-1 justify-center px-4 md:flex\">\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=\"hidden flex-1 md:block\"></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{border-bottom:1px solid var(--border);background:var(--background);box-shadow:0 1px 2px #0f172a0a;will-change:transform}.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{gap:1.25rem;padding:0;background:transparent}.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{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){.brand-name{display:inline-block}.header-actions{gap:.25rem}.user-menu-divider{padding-left:.5rem}}@media(min-width:768px){.mobile-search-action{display:none}}@media(min-width:1024px){.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"] }] });
|
|
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\n class=\"header-container fixed top-0 inset-x-0 z-40 flex h-[3.75rem] items-center justify-between px-3 text-[var(--foreground)] sm:px-4 lg:px-6\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"flex min-w-0 items-center gap-3\">\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=\"hidden flex-1 justify-center px-4 md:flex\">\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=\"hidden flex-1 md:block\"></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{border-bottom:1px solid var(--border);background:var(--background);box-shadow:0 1px 2px #0f172a0a;padding-inline:1rem;will-change:transform}.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{gap:1.25rem;padding:0;background:transparent}.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{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){.mobile-search-action{display:none}}@media(min-width:1024px){.header-container{padding-inline:1.5rem}.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"] }] });
|
|
495
524
|
}
|
|
496
525
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: HeaderComponent, decorators: [{
|
|
497
526
|
type: Component,
|
|
@@ -503,7 +532,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
|
|
|
503
532
|
NotificationBellComponent,
|
|
504
533
|
UserMenuComponent,
|
|
505
534
|
IconComponent,
|
|
506
|
-
], template: "<header\n class=\"header-container fixed top-0 inset-x-0 z-40 flex h-[3.75rem] items-center justify-between px-3 text-[var(--foreground)] sm:px-4 lg:px-6\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"flex min-w-0 items-center gap-3\">\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=\"hidden flex-1 justify-center px-4 md:flex\">\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=\"hidden flex-1 md:block\"></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{border-bottom:1px solid var(--border);background:var(--background);box-shadow:0 1px 2px #0f172a0a;will-change:transform}.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{gap:1.25rem;padding:0;background:transparent}.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{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){.brand-name{display:inline-block}.header-actions{gap:.25rem}.user-menu-divider{padding-left:.5rem}}@media(min-width:768px){.mobile-search-action{display:none}}@media(min-width:1024px){.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"] }]
|
|
535
|
+
], template: "<header\n class=\"header-container fixed top-0 inset-x-0 z-40 flex h-[3.75rem] items-center justify-between px-3 text-[var(--foreground)] sm:px-4 lg:px-6\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"flex min-w-0 items-center gap-3\">\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=\"hidden flex-1 justify-center px-4 md:flex\">\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=\"hidden flex-1 md:block\"></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{border-bottom:1px solid var(--border);background:var(--background);box-shadow:0 1px 2px #0f172a0a;padding-inline:1rem;will-change:transform}.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{gap:1.25rem;padding:0;background:transparent}.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{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){.mobile-search-action{display:none}}@media(min-width:1024px){.header-container{padding-inline:1.5rem}.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"] }]
|
|
507
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"] }] } });
|
|
508
537
|
|
|
509
538
|
/*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"excellore-ui.mjs","sources":["../../../projects/ui/src/lib/services/theme.service.ts","../../../projects/ui/src/lib/navigation/app-switcher/app-switcher.ts","../../../projects/ui/src/lib/navigation/app-switcher/app-switcher.html","../../../projects/ui/src/lib/navigation/organization-switcher/organization-switcher.ts","../../../projects/ui/src/lib/navigation/organization-switcher/organization-switcher.html","../../../projects/ui/src/lib/notifications/notification-panel/notification-panel.ts","../../../projects/ui/src/lib/notifications/notification-panel/notification-panel.html","../../../projects/ui/src/lib/notifications/notification-bell/notification-bell.ts","../../../projects/ui/src/lib/notifications/notification-bell/notification-bell.html","../../../projects/ui/src/lib/user/user-avatar/user-avatar.ts","../../../projects/ui/src/lib/user/user-avatar/user-avatar.html","../../../projects/ui/src/lib/user/user-menu/user-menu.ts","../../../projects/ui/src/lib/user/user-menu/user-menu.html","../../../projects/ui/src/lib/shared/icon/icon.component.ts","../../../projects/ui/src/lib/layout/header/header.ts","../../../projects/ui/src/lib/layout/header/header.html","../../../projects/ui/src/public-api.ts","../../../projects/ui/src/excellore-ui.ts"],"sourcesContent":["import { Injectable, signal, effect, Inject, PLATFORM_ID, inject } from '@angular/core';\r\nimport { isPlatformBrowser } from '@angular/common';\r\nimport { Theme } from '../models/models.interface';\r\n\r\nconst THEME_STORAGE_KEY = 'excellore-theme';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ThemeService {\r\n private readonly platformId = inject(PLATFORM_ID);\r\n private readonly isBrowser = isPlatformBrowser(this.platformId);\r\n\r\n // The active theme preference ('light', 'dark', 'system')\r\n readonly theme = signal<Theme>('system');\r\n\r\n // The currently resolved actual theme applied ('light' | 'dark')\r\n readonly resolvedTheme = signal<'light' | 'dark'>('light');\r\n\r\n private mediaQueryListener?: (e: MediaQueryListEvent) => void;\r\n\r\n constructor() {\r\n this.initializeTheme();\r\n\r\n // Effect to reactively update storage, apply document classes, and set up listeners\r\n effect(() => {\r\n const activeTheme = this.theme();\r\n this.saveThemeToStorage(activeTheme);\r\n this.applyTheme(activeTheme);\r\n });\r\n }\r\n\r\n setTheme(theme: Theme): void {\r\n this.theme.set(theme);\r\n }\r\n\r\n getTheme(): Theme {\r\n return this.theme();\r\n }\r\n\r\n toggleTheme(): void {\r\n const current = this.theme();\r\n if (current === 'light') {\r\n this.setTheme('dark');\r\n } else if (current === 'dark') {\r\n this.setTheme('system');\r\n } else {\r\n this.setTheme('light');\r\n }\r\n }\r\n\r\n private initializeTheme(): void {\r\n if (!this.isBrowser) {\r\n return;\r\n }\r\n\r\n try {\r\n const savedTheme = localStorage.getItem(THEME_STORAGE_KEY) as Theme;\r\n if (savedTheme === 'light' || savedTheme === 'dark' || savedTheme === 'system') {\r\n this.theme.set(savedTheme);\r\n } else {\r\n this.theme.set('system');\r\n }\r\n } catch {\r\n this.theme.set('system');\r\n }\r\n }\r\n\r\n private saveThemeToStorage(theme: Theme): void {\r\n if (!this.isBrowser) {\r\n return;\r\n }\r\n\r\n try {\r\n localStorage.setItem(THEME_STORAGE_KEY, theme);\r\n } catch (e) {\r\n console.warn('Failed to save theme to localStorage:', e);\r\n }\r\n }\r\n\r\n private applyTheme(theme: Theme): void {\r\n if (!this.isBrowser) {\r\n return;\r\n }\r\n\r\n const doc = document.documentElement;\r\n const mediaQuery = typeof window.matchMedia === 'function' ? window.matchMedia('(prefers-color-scheme: dark)') : null;\r\n\r\n // Clean up any previous listener to avoid leaks\r\n if (this.mediaQueryListener && mediaQuery) {\r\n mediaQuery.removeEventListener('change', this.mediaQueryListener);\r\n this.mediaQueryListener = undefined;\r\n }\r\n\r\n let actualTheme: 'light' | 'dark' = 'light';\r\n\r\n if (theme === 'system') {\r\n actualTheme = mediaQuery?.matches ? 'dark' : 'light';\r\n\r\n if (mediaQuery) {\r\n // Watch for system preference changes in real-time\r\n this.mediaQueryListener = (e: MediaQueryListEvent) => {\r\n const newResolvedTheme = e.matches ? 'dark' : 'light';\r\n this.resolvedTheme.set(newResolvedTheme);\r\n this.updateDocumentClass(newResolvedTheme);\r\n };\r\n mediaQuery.addEventListener('change', this.mediaQueryListener);\r\n }\r\n } else {\r\n actualTheme = theme;\r\n }\r\n\r\n this.resolvedTheme.set(actualTheme);\r\n this.updateDocumentClass(actualTheme);\r\n }\r\n\r\n private updateDocumentClass(resolved: 'light' | 'dark'): void {\r\n const doc = document.documentElement;\r\n if (resolved === 'dark') {\r\n doc.classList.add('dark');\r\n doc.classList.remove('light');\r\n } else {\r\n doc.classList.add('light');\r\n doc.classList.remove('dark');\r\n }\r\n }\r\n}\r\n","import { Component, input, output, HostListener, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Application } from '../../models/models.interface';\r\nimport { LucideAngularModule, Grid, ChevronDown } from 'lucide-angular';\r\n\r\n@Component({\r\n selector: 'lib-app-switcher',\r\n standalone: true,\r\n imports: [CommonModule, LucideAngularModule],\r\n templateUrl: './app-switcher.html',\r\n styleUrl: './app-switcher.css',\r\n})\r\nexport class AppSwitcherComponent {\r\n readonly applications = input<Application[]>([]);\r\n readonly applicationSelected = output<Application>();\r\n\r\n readonly gridIcon = Grid;\r\n readonly chevronDownIcon = ChevronDown;\r\n\r\n readonly isOpen = signal(false);\r\n\r\n toggleSwitcher(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closeSwitcher(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onSelect(app: Application): void {\r\n if (app.available !== false) {\r\n this.applicationSelected.emit(app);\r\n this.closeSwitcher();\r\n }\r\n }\r\n\r\n getInitials(name: string): string {\r\n return name\r\n .split(/[.\\s_-]+/)\r\n .filter(Boolean)\r\n .slice(0, 2)\r\n .map((part) => part[0]?.toUpperCase())\r\n .join('') || 'AP';\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.app-switcher-wrapper')) {\r\n this.closeSwitcher();\r\n }\r\n }\r\n}\r\n","<div class=\"app-switcher-wrapper relative inline-block text-left\">\r\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 <lucide-icon [name]=\"gridIcon\" class=\"h-4.5 w-4.5\" />\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"app-switcher-dropdown fixed left-2 right-2 top-14 mt-2 max-h-[calc(100dvh-4.5rem)] origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-2.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-[360px] sm:max-w-[calc(100vw-1rem)] sm:origin-top-right\">\n <div class=\"mb-1.5 flex items-center justify-between border-b border-[var(--border)] px-1 pb-2.5\">\n <div>\n <h3 class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Excellore Apps</h3>\n <p class=\"mt-0.5 text-[11px] text-[var(--secondary)]\">Switch between available workspaces</p>\n </div>\n </div>\n \n @if (applications().length === 0) {\n <div class=\"py-6 text-center text-xs text-[var(--secondary)]\">\n No other apps available\n </div>\n } @else {\n <div class=\"max-h-[calc(100dvh-10rem)] overflow-y-auto py-1 sm:max-h-[420px]\">\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 group flex items-center gap-3 rounded-lg border border-transparent px-2.5 py-2.5 no-underline transition focus:outline-none focus:ring-2 focus:ring-[var(--primary)]\"\n >\n <div class=\"app-switcher-app-mark\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\" [title]=\"app.name\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-open-pill shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide opacity-0 transition group-hover:opacity-100\">\n Open\n </span>\n </a>\n } @else {\n <div class=\"app-switcher-item flex items-center gap-3 rounded-lg px-2.5 py-2.5 opacity-55 select-none\">\n <div class=\"app-switcher-app-mark unavailable\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"shrink-0 rounded-full border border-[var(--border)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[var(--secondary)]\">\n Soon\n </span>\n </div>\n }\n }\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n","import { Component, input, output, HostListener, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Organization } from '../../models/models.interface';\r\nimport { LucideAngularModule, ChevronDown, Check, Building } from 'lucide-angular';\r\n\r\n@Component({\r\n selector: 'lib-organization-switcher',\r\n standalone: true,\r\n imports: [CommonModule, LucideAngularModule],\r\n templateUrl: './organization-switcher.html',\r\n styleUrl: './organization-switcher.css',\r\n})\r\nexport class OrganizationSwitcherComponent {\r\n readonly organizations = input<Organization[]>([]);\r\n readonly selectedOrganization = input<Organization | null>(null);\r\n readonly organizationChanged = output<Organization>();\r\n\r\n readonly chevronDownIcon = ChevronDown;\r\n readonly checkIcon = Check;\r\n readonly buildingIcon = Building;\r\n\r\n readonly isOpen = signal(false);\r\n\r\n toggleSwitcher(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closeSwitcher(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onSelect(org: Organization): void {\r\n this.organizationChanged.emit(org);\r\n this.closeSwitcher();\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.org-switcher-wrapper')) {\r\n this.closeSwitcher();\r\n }\r\n }\r\n}\r\n","<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 <lucide-icon [name]=\"buildingIcon\" class=\"h-3.5 w-3.5 text-[var(--secondary)]\" />\r\n <span class=\"truncate max-w-[120px]\">{{ selectedOrganization()?.name || 'Select Tenant' }}</span>\r\n <lucide-icon [name]=\"chevronDownIcon\" class=\"h-3 w-3 text-[var(--secondary)] transition-transform duration-200\" [class.rotate-180]=\"isOpen()\" />\r\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 <lucide-icon [name]=\"checkIcon\" class=\"h-3.5 w-3.5 text-[var(--primary)] flex-shrink-0\" />\r\n }\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n","import { Component, input, output } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Notification } from '../../models/models.interface';\r\nimport { LucideAngularModule, CheckCheck, Trash2, BellOff, Circle } from 'lucide-angular';\r\n\r\n@Component({\r\n selector: 'lib-notification-panel',\r\n standalone: true,\r\n imports: [CommonModule, LucideAngularModule],\r\n templateUrl: './notification-panel.html',\r\n styleUrl: './notification-panel.css',\r\n})\r\nexport class NotificationPanelComponent {\r\n readonly notifications = input<Notification[]>([]);\r\n readonly notificationClick = output<Notification>();\r\n readonly markRead = output<string>();\r\n readonly clearAll = output<void>();\r\n\r\n readonly checkCheckIcon = CheckCheck;\r\n readonly trashIcon = Trash2;\r\n readonly bellOffIcon = BellOff;\r\n readonly circleIcon = Circle;\r\n\r\n onNotificationClick(notification: Notification): void {\r\n this.notificationClick.emit(notification);\r\n }\r\n\r\n onMarkRead(id: string, event: MouseEvent): void {\r\n event.stopPropagation();\r\n this.markRead.emit(id);\r\n }\r\n\r\n onClearAll(event: MouseEvent): void {\r\n event.stopPropagation();\r\n this.clearAll.emit();\r\n }\r\n\r\n formatTime(date: Date | string): string {\r\n const d = new Date(date);\r\n const now = new Date();\r\n const diffMs = now.getTime() - d.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMins / 60);\r\n const diffDays = Math.floor(diffHours / 24);\r\n\r\n if (diffMins < 1) return 'Just now';\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays === 1) return 'Yesterday';\r\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\r\n }\r\n}\r\n","<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 <lucide-icon [name]=\"trashIcon\" class=\"h-3 w-3\" />\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 <lucide-icon [name]=\"bellOffIcon\" class=\"h-4.5 w-4.5\" />\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 <lucide-icon [name]=\"checkCheckIcon\" class=\"h-3.5 w-3.5\" />\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n","import { Component, input, output, HostListener, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Notification } from '../../models/models.interface';\r\nimport { NotificationPanelComponent } from '../notification-panel/notification-panel';\r\nimport { LucideAngularModule, Bell } from 'lucide-angular';\r\n\r\n@Component({\r\n selector: 'lib-notification-bell',\r\n standalone: true,\r\n imports: [CommonModule, NotificationPanelComponent, LucideAngularModule],\r\n templateUrl: './notification-bell.html',\r\n styleUrl: './notification-bell.css',\r\n})\r\nexport class NotificationBellComponent {\r\n readonly unreadCount = input<number>(0);\r\n readonly notifications = input<Notification[]>([]);\r\n\r\n readonly notificationClick = output<Notification>();\r\n readonly markRead = output<string>();\r\n readonly clearAll = output<void>();\r\n\r\n readonly bellIcon = Bell;\r\n\r\n readonly isOpen = signal(false);\r\n\r\n togglePanel(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closePanel(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onNotificationClick(notification: Notification): void {\r\n this.notificationClick.emit(notification);\r\n this.closePanel();\r\n }\r\n\r\n onMarkRead(id: string): void {\r\n this.markRead.emit(id);\r\n }\r\n\r\n onClearAll(): void {\r\n this.clearAll.emit();\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.notification-bell-wrapper')) {\r\n this.closePanel();\r\n }\r\n }\r\n}\r\n","<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 <lucide-icon [name]=\"bellIcon\" class=\"h-4.5 w-4.5\" />\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\">\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","import { Component, input, computed } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { User } from '../../models/models.interface';\r\n\r\n@Component({\r\n selector: 'lib-user-avatar',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './user-avatar.html',\r\n styleUrl: './user-avatar.css',\r\n})\r\nexport class UserAvatarComponent {\r\n // Input using the modern Angular signal inputs\r\n readonly user = input<User | null>(null);\r\n\r\n // Computes the initials from the user's name or email\r\n readonly initials = computed(() => {\r\n const userData = this.user();\r\n if (!userData) return 'EU';\r\n\r\n const source = userData.name || userData.email || 'Excellore User';\r\n return source\r\n .split(/[.@\\s_-]+/)\r\n .filter(Boolean)\r\n .slice(0, 2)\r\n .map(part => part[0]?.toUpperCase())\r\n .join('') || 'EU';\r\n });\r\n\r\n // Check if image loading failed to dynamically switch to initials\r\n protected imageError = false;\r\n\r\n onImageError(): void {\r\n this.imageError = true;\r\n }\r\n}\r\n","<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","import { Component, input, output, HostListener, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { User } from '../../models/models.interface';\r\nimport { UserAvatarComponent } from '../user-avatar/user-avatar';\r\nimport {\r\n LucideAngularModule,\r\n User as UserIcon,\r\n Settings as SettingsIcon,\r\n CreditCard as CreditCardIcon,\r\n LogOut as LogOutIcon,\r\n ChevronDown as ChevronDownIcon,\r\n} from 'lucide-angular';\r\n\r\n@Component({\r\n selector: 'lib-user-menu',\r\n standalone: true,\r\n imports: [CommonModule, UserAvatarComponent, LucideAngularModule],\r\n templateUrl: './user-menu.html',\r\n styleUrl: './user-menu.css',\r\n})\r\nexport class UserMenuComponent {\r\n readonly user = input<User | null>(null);\r\n readonly menuAction = output<'profile' | 'settings' | 'billing' | 'logout'>();\r\n\r\n // Lucide Icons mapping\r\n readonly userIcon = UserIcon;\r\n readonly settingsIcon = SettingsIcon;\r\n readonly creditCardIcon = CreditCardIcon;\r\n readonly logOutIcon = LogOutIcon;\r\n readonly chevronDownIcon = ChevronDownIcon;\r\n\r\n // Signalled open state\r\n readonly isOpen = signal(false);\r\n\r\n toggleMenu(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closeMenu(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onAction(action: 'profile' | 'settings' | 'billing' | 'logout'): void {\r\n this.menuAction.emit(action);\r\n this.closeMenu();\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.user-menu-wrapper')) {\r\n this.closeMenu();\r\n }\r\n }\r\n}\r\n","<div class=\"user-menu-wrapper relative inline-block text-left\">\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=\"h-7 w-7 rounded-full overflow-hidden\">\r\n <lib-user-avatar [user]=\"user()\" />\r\n </div>\r\n <lucide-icon [name]=\"chevronDownIcon\" class=\"h-3.5 w-3.5 text-[var(--secondary)] transition-transform duration-200\"\r\n [class.rotate-180]=\"isOpen()\" />\r\n </button>\r\n\r\n @if (isOpen()) {\r\n <div\r\n class=\"user-dropdown-panel fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-1.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-56 sm:origin-top-right\">\r\n @if (user(); as u) {\r\n <div class=\"px-3 py-2 border-b border-[var(--border)] mb-1\">\r\n <p class=\"text-sm font-semibold truncate text-[var(--foreground)]\" [title]=\"u.name\">{{ u.name }}</p>\r\n <p class=\"text-xs truncate text-[var(--secondary)] mt-0.5\" [title]=\"u.email\">{{ u.email }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"py-0.5 space-y-0.5\">\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\r\n <lucide-icon [name]=\"userIcon\" class=\"h-4 w-4 text-[var(--secondary)]\" />\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 <lucide-icon [name]=\"settingsIcon\" class=\"h-4 w-4 text-[var(--secondary)]\" />\r\n <span>Settings</span>\r\n </button>\r\n\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('billing')\">\r\n <lucide-icon [name]=\"creditCardIcon\" class=\"h-4 w-4 text-[var(--secondary)]\" />\r\n <span>Billing</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"border-t border-[var(--border)] mt-1 pt-1\">\r\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\r\n <lucide-icon [name]=\"logOutIcon\" class=\"h-4 w-4 text-[var(--danger,#ef4444)]\" />\r\n <span>Sign Out</span>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>","// lib/shared/icon/icon.component.ts\r\nimport { Component, input, computed } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport {\r\n LucideAngularModule,\r\n Search,\r\n Menu,\r\n X,\r\n Sun,\r\n Moon,\r\n Monitor,\r\n Bell,\r\n Grid,\r\n ChevronDown,\r\n Building2\r\n} from 'lucide-angular';\r\n\r\nconst ICONS = {\r\n search: Search,\r\n menu: Menu,\r\n x: X,\r\n sun: Sun,\r\n moon: Moon,\r\n monitor: Monitor,\r\n bell: Bell,\r\n grid: Grid,\r\n chevronDown: ChevronDown,\r\n building2: Building2\r\n};\r\n\r\n@Component({\r\n selector: 'lib-icon',\r\n standalone: true,\r\n imports: [CommonModule, LucideAngularModule],\r\n template: `\r\n <lucide-icon \r\n [name]=\"iconName()\" \r\n [size]=\"size()\"\r\n [color]=\"color()\"\r\n [strokeWidth]=\"strokeWidth()\"\r\n class=\"lib-icon\"\r\n />\r\n `,\r\n styles: [`\r\n :host {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n .lib-icon {\r\n display: block;\r\n }\r\n `]\r\n})\r\nexport class IconComponent {\r\n readonly name = input.required<string>();\r\n readonly size = input<number>(24);\r\n readonly color = input<string | undefined>(undefined);\r\n readonly strokeWidth = input<number | undefined>(undefined);\r\n\r\n protected readonly iconName = computed(() => {\r\n const name = this.name();\r\n return ICONS[name as keyof typeof ICONS] || Search;\r\n });\r\n}","import { Component, inject, input, output, signal, computed } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Router, RouterLink, RouterLinkActive } from '@angular/router';\r\nimport { User, Organization, NavigationItem, Notification, Application } from '../../models/models.interface';\r\nimport { ThemeService } from '../../services/theme.service';\r\nimport { AppSwitcherComponent } from '../../navigation';\r\nimport { NotificationBellComponent } from '../../notifications';\r\nimport { UserMenuComponent } from '../../user';\r\n\r\nimport { IconComponent } from '../../shared/icon/icon.component';\r\n\r\n\r\n@Component({\r\n selector: 'lib-header',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n RouterLink,\r\n RouterLinkActive,\r\n AppSwitcherComponent,\r\n NotificationBellComponent,\r\n UserMenuComponent,\r\n IconComponent,\r\n ],\r\n templateUrl: './header.html',\r\n styleUrl: './header.css',\r\n})\r\nexport class HeaderComponent {\r\n private readonly router = inject(Router);\r\n protected readonly themeService = inject(ThemeService);\r\n\r\n // User & Organization Inputs\r\n readonly user = input<User | null>(null);\r\n readonly permissions = input<string[]>([]);\r\n readonly organization = input<Organization | null>(null);\r\n\r\n // Navigation & Integration Inputs\r\n readonly navigationItems = input<NavigationItem[]>([]);\r\n readonly applications = input<Application[]>([]);\r\n readonly notifications = input<Notification[]>([]);\r\n readonly notificationCount = input<number>(0);\r\n readonly logoUrl = input<string>('https://cdn.jsdelivr.net/gh/Excellore/excellore-static-assets@main/images/excellore-logo-origin.png');\n readonly appName = input<string>('Excellore');\n readonly currentAppName = input<string>('');\n readonly showSearch = input<boolean>(true);\n readonly showNotifications = input<boolean>(true);\n readonly showAppSwitcher = input<boolean>(true);\n readonly showThemeSwitcher = input<boolean>(true);\n readonly showSignIn = input<boolean>(true);\n\n // Outputs as decided in the architecture plan\n readonly search = output<string>();\n readonly signIn = output<void>();\n readonly applicationSelected = output<Application>();\n readonly notificationClick = output<Notification>();\r\n readonly markRead = output<string>();\r\n readonly clearAll = output<void>();\r\n readonly menuAction = output<'profile' | 'settings' | 'billing' | 'logout'>();\r\n\r\n // Lucide Icons\r\n // readonly searchIcon = Search;\r\n // readonly menuIcon = Menu;\r\n // readonly xIcon = X;\r\n // readonly sunIcon = Sun;\r\n // readonly moonIcon = Moon;\r\n // readonly monitorIcon = Monitor;\r\n\r\n // Header specific UI states\r\n readonly isMobileMenuOpen = signal(false);\r\n\r\n // Checks if the user has permission to see an item\r\n hasPermission(item: NavigationItem): boolean {\r\n if (!item.permissions || item.permissions.length === 0) {\r\n return true;\r\n }\r\n const currentPermissions = this.permissions();\r\n return item.permissions.some((p) => currentPermissions.includes(p));\r\n }\r\n\r\n // Reactive unread count selector\r\n readonly unreadCount = computed(() => {\n const overrideCount = this.notificationCount();\n if (overrideCount > 0) return overrideCount;\n return this.notifications().filter((n) => !n.read).length;\n });\n\n readonly hasMobileMenuContent = computed(() =>\n this.showSearch() || this.navigationItems().some((item) => this.hasPermission(item))\n );\n\r\n // Determines if an item's internal route is active\r\n isActive(item: NavigationItem): boolean {\r\n if (!item.route) return false;\r\n try {\r\n return this.router.isActive(item.route, {\r\n paths: 'subset',\r\n queryParams: 'ignored',\r\n fragment: 'ignored',\r\n matrixParams: 'ignored',\r\n });\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n toggleMobileMenu(): void {\r\n this.isMobileMenuOpen.update((v) => !v);\r\n }\r\n\r\n closeMobileMenu(): void {\r\n this.isMobileMenuOpen.set(false);\r\n }\r\n\r\n onSearch(query: string): void {\r\n this.search.emit(query);\r\n }\r\n\r\n onApplicationSelect(app: Application): void {\r\n this.applicationSelected.emit(app);\r\n }\r\n\r\n onNotificationClick(notification: Notification): void {\r\n this.notificationClick.emit(notification);\r\n }\r\n\r\n onMarkRead(id: string): void {\r\n this.markRead.emit(id);\r\n }\r\n\r\n onClearAll(): void {\r\n this.clearAll.emit();\r\n }\r\n\r\n onMenuAction(action: 'profile' | 'settings' | 'billing' | 'logout'): void {\r\n this.menuAction.emit(action);\r\n }\r\n}\r\n","<header\n class=\"header-container fixed top-0 inset-x-0 z-40 flex h-[3.75rem] items-center justify-between px-3 text-[var(--foreground)] sm:px-4 lg:px-6\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"flex min-w-0 items-center gap-3\">\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=\"hidden flex-1 justify-center px-4 md:flex\">\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=\"hidden flex-1 md:block\"></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","/*\r\n * Public API Surface of ui\r\n */\r\n\r\nexport * from './lib/models';\r\nexport * from './lib/services';\r\nexport * from './lib/layout';\r\nexport * from './lib/navigation';\r\nexport * from './lib/user';\r\nexport * from './lib/notifications';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["UserIcon","SettingsIcon","CreditCardIcon","LogOutIcon","ChevronDownIcon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"excellore-ui.mjs","sources":["../../../projects/ui/src/lib/services/theme.service.ts","../../../projects/ui/src/lib/navigation/app-switcher/app-switcher.ts","../../../projects/ui/src/lib/navigation/app-switcher/app-switcher.html","../../../projects/ui/src/lib/navigation/organization-switcher/organization-switcher.ts","../../../projects/ui/src/lib/navigation/organization-switcher/organization-switcher.html","../../../projects/ui/src/lib/notifications/notification-panel/notification-panel.ts","../../../projects/ui/src/lib/notifications/notification-panel/notification-panel.html","../../../projects/ui/src/lib/notifications/notification-bell/notification-bell.ts","../../../projects/ui/src/lib/notifications/notification-bell/notification-bell.html","../../../projects/ui/src/lib/user/user-avatar/user-avatar.ts","../../../projects/ui/src/lib/user/user-avatar/user-avatar.html","../../../projects/ui/src/lib/user/user-menu/user-menu.ts","../../../projects/ui/src/lib/user/user-menu/user-menu.html","../../../projects/ui/src/lib/shared/icon/icon.component.ts","../../../projects/ui/src/lib/layout/header/header.ts","../../../projects/ui/src/lib/layout/header/header.html","../../../projects/ui/src/public-api.ts","../../../projects/ui/src/excellore-ui.ts"],"sourcesContent":["import { Injectable, signal, effect, Inject, PLATFORM_ID, inject } from '@angular/core';\r\nimport { isPlatformBrowser } from '@angular/common';\r\nimport { Theme } from '../models/models.interface';\r\n\r\nconst THEME_STORAGE_KEY = 'excellore-theme';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ThemeService {\r\n private readonly platformId = inject(PLATFORM_ID);\r\n private readonly isBrowser = isPlatformBrowser(this.platformId);\r\n\r\n // The active theme preference ('light', 'dark', 'system')\r\n readonly theme = signal<Theme>('system');\r\n\r\n // The currently resolved actual theme applied ('light' | 'dark')\r\n readonly resolvedTheme = signal<'light' | 'dark'>('light');\r\n\r\n private mediaQueryListener?: (e: MediaQueryListEvent) => void;\r\n\r\n constructor() {\r\n this.initializeTheme();\r\n\r\n // Effect to reactively update storage, apply document classes, and set up listeners\r\n effect(() => {\r\n const activeTheme = this.theme();\r\n this.saveThemeToStorage(activeTheme);\r\n this.applyTheme(activeTheme);\r\n });\r\n }\r\n\r\n setTheme(theme: Theme): void {\r\n this.theme.set(theme);\r\n }\r\n\r\n getTheme(): Theme {\r\n return this.theme();\r\n }\r\n\r\n toggleTheme(): void {\r\n const current = this.theme();\r\n if (current === 'light') {\r\n this.setTheme('dark');\r\n } else if (current === 'dark') {\r\n this.setTheme('system');\r\n } else {\r\n this.setTheme('light');\r\n }\r\n }\r\n\r\n private initializeTheme(): void {\r\n if (!this.isBrowser) {\r\n return;\r\n }\r\n\r\n try {\r\n const savedTheme = localStorage.getItem(THEME_STORAGE_KEY) as Theme;\r\n if (savedTheme === 'light' || savedTheme === 'dark' || savedTheme === 'system') {\r\n this.theme.set(savedTheme);\r\n } else {\r\n this.theme.set('system');\r\n }\r\n } catch {\r\n this.theme.set('system');\r\n }\r\n }\r\n\r\n private saveThemeToStorage(theme: Theme): void {\r\n if (!this.isBrowser) {\r\n return;\r\n }\r\n\r\n try {\r\n localStorage.setItem(THEME_STORAGE_KEY, theme);\r\n } catch (e) {\r\n console.warn('Failed to save theme to localStorage:', e);\r\n }\r\n }\r\n\r\n private applyTheme(theme: Theme): void {\r\n if (!this.isBrowser) {\r\n return;\r\n }\r\n\r\n const doc = document.documentElement;\r\n const mediaQuery = typeof window.matchMedia === 'function' ? window.matchMedia('(prefers-color-scheme: dark)') : null;\r\n\r\n // Clean up any previous listener to avoid leaks\r\n if (this.mediaQueryListener && mediaQuery) {\r\n mediaQuery.removeEventListener('change', this.mediaQueryListener);\r\n this.mediaQueryListener = undefined;\r\n }\r\n\r\n let actualTheme: 'light' | 'dark' = 'light';\r\n\r\n if (theme === 'system') {\r\n actualTheme = mediaQuery?.matches ? 'dark' : 'light';\r\n\r\n if (mediaQuery) {\r\n // Watch for system preference changes in real-time\r\n this.mediaQueryListener = (e: MediaQueryListEvent) => {\r\n const newResolvedTheme = e.matches ? 'dark' : 'light';\r\n this.resolvedTheme.set(newResolvedTheme);\r\n this.updateDocumentClass(newResolvedTheme);\r\n };\r\n mediaQuery.addEventListener('change', this.mediaQueryListener);\r\n }\r\n } else {\r\n actualTheme = theme;\r\n }\r\n\r\n this.resolvedTheme.set(actualTheme);\r\n this.updateDocumentClass(actualTheme);\r\n }\r\n\r\n private updateDocumentClass(resolved: 'light' | 'dark'): void {\r\n const doc = document.documentElement;\r\n if (resolved === 'dark') {\r\n doc.classList.add('dark');\r\n doc.classList.remove('light');\r\n } else {\r\n doc.classList.add('light');\r\n doc.classList.remove('dark');\r\n }\r\n }\r\n}\r\n","import { Component, input, output, HostListener, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Application } from '../../models/models.interface';\nimport { LucideGrid } from '@lucide/angular';\n\r\n@Component({\r\n selector: 'lib-app-switcher',\n standalone: true,\n imports: [CommonModule, LucideGrid],\n templateUrl: './app-switcher.html',\n styleUrl: './app-switcher.css',\n})\nexport class AppSwitcherComponent {\n readonly applications = input<Application[]>([]);\n readonly applicationSelected = output<Application>();\n\n readonly isOpen = signal(false);\n\r\n toggleSwitcher(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closeSwitcher(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onSelect(app: Application): void {\r\n if (app.available !== false) {\r\n this.applicationSelected.emit(app);\r\n this.closeSwitcher();\r\n }\r\n }\r\n\r\n getInitials(name: string): string {\r\n return name\r\n .split(/[.\\s_-]+/)\r\n .filter(Boolean)\r\n .slice(0, 2)\r\n .map((part) => part[0]?.toUpperCase())\r\n .join('') || 'AP';\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.app-switcher-wrapper')) {\r\n this.closeSwitcher();\r\n }\r\n }\r\n}\r\n","<div class=\"app-switcher-wrapper relative inline-block text-left\">\r\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=\"h-4.5 w-4.5\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div class=\"app-switcher-dropdown fixed left-2 right-2 top-14 mt-2 max-h-[calc(100dvh-4.5rem)] origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-2.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-[360px] sm:max-w-[calc(100vw-1rem)] sm:origin-top-right\">\n <div class=\"mb-1.5 flex items-center justify-between border-b border-[var(--border)] px-1 pb-2.5\">\n <div>\n <h3 class=\"text-[10px] font-bold uppercase tracking-wider text-[var(--secondary)]\">Excellore Apps</h3>\n <p class=\"mt-0.5 text-[11px] text-[var(--secondary)]\">Switch between available workspaces</p>\n </div>\n </div>\n \n @if (applications().length === 0) {\n <div class=\"py-6 text-center text-xs text-[var(--secondary)]\">\n No other apps available\n </div>\n } @else {\n <div class=\"max-h-[calc(100dvh-10rem)] overflow-y-auto py-1 sm:max-h-[420px]\">\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 group flex items-center gap-3 rounded-lg border border-transparent px-2.5 py-2.5 no-underline transition focus:outline-none focus:ring-2 focus:ring-[var(--primary)]\"\n >\n <div class=\"app-switcher-app-mark\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\" [title]=\"app.name\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"app-switcher-open-pill shrink-0 rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide opacity-0 transition group-hover:opacity-100\">\n Open\n </span>\n </a>\n } @else {\n <div class=\"app-switcher-item flex items-center gap-3 rounded-lg px-2.5 py-2.5 opacity-55 select-none\">\n <div class=\"app-switcher-app-mark unavailable\">\n {{ app.initials || getInitials(app.name) }}\n </div>\n <div class=\"min-w-0 flex-1\">\n <div class=\"truncate text-sm font-semibold text-[var(--foreground)]\">{{ app.name }}</div>\n <div class=\"mt-0.5 truncate text-[11px] text-[var(--secondary)]\">{{ app.url }}</div>\n </div>\n <span class=\"shrink-0 rounded-full border border-[var(--border)] px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[var(--secondary)]\">\n Soon\n </span>\n </div>\n }\n }\n </div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n","import { Component, input, output, HostListener, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Organization } from '../../models/models.interface';\nimport { LucideBuilding, LucideCheck, LucideChevronDown } from '@lucide/angular';\n\r\n@Component({\r\n selector: 'lib-organization-switcher',\n standalone: true,\n imports: [CommonModule, LucideBuilding, LucideCheck, LucideChevronDown],\n templateUrl: './organization-switcher.html',\n styleUrl: './organization-switcher.css',\n})\nexport class OrganizationSwitcherComponent {\r\n readonly organizations = input<Organization[]>([]);\r\n readonly selectedOrganization = input<Organization | null>(null);\n readonly organizationChanged = output<Organization>();\n\n readonly isOpen = signal(false);\n\r\n toggleSwitcher(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closeSwitcher(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onSelect(org: Organization): void {\r\n this.organizationChanged.emit(org);\r\n this.closeSwitcher();\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.org-switcher-wrapper')) {\r\n this.closeSwitcher();\r\n }\r\n }\r\n}\r\n","<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","import { Component, input, output } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Notification } from '../../models/models.interface';\nimport { LucideBellOff, LucideCheckCheck, LucideTrash2 } from '@lucide/angular';\n\r\n@Component({\r\n selector: 'lib-notification-panel',\n standalone: true,\n imports: [CommonModule, LucideBellOff, LucideCheckCheck, LucideTrash2],\n templateUrl: './notification-panel.html',\n styleUrl: './notification-panel.css',\n})\nexport class NotificationPanelComponent {\r\n readonly notifications = input<Notification[]>([]);\r\n readonly notificationClick = output<Notification>();\r\n readonly markRead = output<string>();\n readonly clearAll = output<void>();\n\n onNotificationClick(notification: Notification): void {\n this.notificationClick.emit(notification);\r\n }\r\n\r\n onMarkRead(id: string, event: MouseEvent): void {\r\n event.stopPropagation();\r\n this.markRead.emit(id);\r\n }\r\n\r\n onClearAll(event: MouseEvent): void {\r\n event.stopPropagation();\r\n this.clearAll.emit();\r\n }\r\n\r\n formatTime(date: Date | string): string {\r\n const d = new Date(date);\r\n const now = new Date();\r\n const diffMs = now.getTime() - d.getTime();\r\n const diffMins = Math.floor(diffMs / 60000);\r\n const diffHours = Math.floor(diffMins / 60);\r\n const diffDays = Math.floor(diffHours / 24);\r\n\r\n if (diffMins < 1) return 'Just now';\r\n if (diffMins < 60) return `${diffMins}m ago`;\r\n if (diffHours < 24) return `${diffHours}h ago`;\r\n if (diffDays === 1) return 'Yesterday';\r\n return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\r\n }\r\n}\r\n","<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","import { Component, input, output, HostListener, signal } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { Notification } from '../../models/models.interface';\nimport { NotificationPanelComponent } from '../notification-panel/notification-panel';\nimport { LucideBell } from '@lucide/angular';\n\r\n@Component({\r\n selector: 'lib-notification-bell',\n standalone: true,\n imports: [CommonModule, NotificationPanelComponent, LucideBell],\n templateUrl: './notification-bell.html',\n styleUrl: './notification-bell.css',\n})\nexport class NotificationBellComponent {\r\n readonly unreadCount = input<number>(0);\r\n readonly notifications = input<Notification[]>([]);\r\n\r\n readonly notificationClick = output<Notification>();\r\n readonly markRead = output<string>();\n readonly clearAll = output<void>();\n\n readonly isOpen = signal(false);\n\r\n togglePanel(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closePanel(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onNotificationClick(notification: Notification): void {\r\n this.notificationClick.emit(notification);\r\n this.closePanel();\r\n }\r\n\r\n onMarkRead(id: string): void {\r\n this.markRead.emit(id);\r\n }\r\n\r\n onClearAll(): void {\r\n this.clearAll.emit();\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.notification-bell-wrapper')) {\r\n this.closePanel();\r\n }\r\n }\r\n}\r\n","<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","import { Component, input, computed } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { User } from '../../models/models.interface';\r\n\r\n@Component({\r\n selector: 'lib-user-avatar',\r\n standalone: true,\r\n imports: [CommonModule],\r\n templateUrl: './user-avatar.html',\r\n styleUrl: './user-avatar.css',\r\n})\r\nexport class UserAvatarComponent {\r\n // Input using the modern Angular signal inputs\r\n readonly user = input<User | null>(null);\r\n\r\n // Computes the initials from the user's name or email\r\n readonly initials = computed(() => {\r\n const userData = this.user();\r\n if (!userData) return 'EU';\r\n\r\n const source = userData.name || userData.email || 'Excellore User';\r\n return source\r\n .split(/[.@\\s_-]+/)\r\n .filter(Boolean)\r\n .slice(0, 2)\r\n .map(part => part[0]?.toUpperCase())\r\n .join('') || 'EU';\r\n });\r\n\r\n // Check if image loading failed to dynamically switch to initials\r\n protected imageError = false;\r\n\r\n onImageError(): void {\r\n this.imageError = true;\r\n }\r\n}\r\n","<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","import { Component, input, output, HostListener, signal } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\nimport { User } from '../../models/models.interface';\nimport { UserAvatarComponent } from '../user-avatar/user-avatar';\nimport {\n LucideChevronDown,\n LucideCreditCard,\n LucideLogOut,\n LucideSettings,\n LucideUser,\n} from '@lucide/angular';\n\r\n@Component({\r\n selector: 'lib-user-menu',\n standalone: true,\n imports: [CommonModule, UserAvatarComponent, LucideChevronDown, LucideCreditCard, LucideLogOut, LucideSettings, LucideUser],\n templateUrl: './user-menu.html',\n styleUrl: './user-menu.css',\n})\nexport class UserMenuComponent {\r\n readonly user = input<User | null>(null);\n readonly menuAction = output<'profile' | 'settings' | 'billing' | 'logout'>();\n\n // Signalled open state\n readonly isOpen = signal(false);\n\r\n toggleMenu(): void {\r\n this.isOpen.update((v) => !v);\r\n }\r\n\r\n closeMenu(): void {\r\n this.isOpen.set(false);\r\n }\r\n\r\n onAction(action: 'profile' | 'settings' | 'billing' | 'logout'): void {\r\n this.menuAction.emit(action);\r\n this.closeMenu();\r\n }\r\n\r\n @HostListener('document:click', ['$event'])\r\n onOutsideClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.user-menu-wrapper')) {\r\n this.closeMenu();\r\n }\r\n }\r\n}\r\n","<div class=\"user-menu-wrapper relative inline-block text-left\">\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=\"h-7 w-7 rounded-full overflow-hidden\">\r\n <lib-user-avatar [user]=\"user()\" />\r\n </div>\r\n <svg lucideChevronDown class=\"h-3.5 w-3.5 text-[var(--secondary)] transition-transform duration-200\"\n [class.rotate-180]=\"isOpen()\"></svg>\n </button>\r\n\r\n @if (isOpen()) {\r\n <div\r\n class=\"user-dropdown-panel fixed left-2 right-2 top-14 mt-2 origin-top rounded-xl border border-[var(--border)] bg-[var(--background)] p-1.5 shadow-lg focus:outline-none z-50 sm:absolute sm:left-auto sm:right-0 sm:top-auto sm:w-56 sm:origin-top-right\">\r\n @if (user(); as u) {\r\n <div class=\"px-3 py-2 border-b border-[var(--border)] mb-1\">\r\n <p class=\"text-sm font-semibold truncate text-[var(--foreground)]\" [title]=\"u.name\">{{ u.name }}</p>\r\n <p class=\"text-xs truncate text-[var(--secondary)] mt-0.5\" [title]=\"u.email\">{{ u.email }}</p>\r\n </div>\r\n }\r\n\r\n <div class=\"py-0.5 space-y-0.5\">\r\n <button type=\"button\" class=\"user-menu-item\" (click)=\"onAction('profile')\">\r\n <svg lucideUser class=\"h-4 w-4 text-[var(--secondary)]\"></svg>\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=\"h-4 w-4 text-[var(--secondary)]\"></svg>\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=\"h-4 w-4 text-[var(--secondary)]\"></svg>\n <span>Billing</span>\r\n </button>\r\n </div>\r\n\r\n <div class=\"border-t border-[var(--border)] mt-1 pt-1\">\r\n <button type=\"button\" class=\"user-menu-item danger\" (click)=\"onAction('logout')\">\r\n <svg lucideLogOut class=\"h-4 w-4 text-[var(--danger,#ef4444)]\"></svg>\n <span>Sign Out</span>\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n</div>\n","// lib/shared/icon/icon.component.ts\nimport { Component, input } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n LucideBell,\n LucideBuilding2,\n LucideChevronDown,\n LucideGrid,\n LucideMenu,\n LucideMonitor,\n LucideMoon,\n LucideSearch,\n LucideSun,\n LucideX,\n} from '@lucide/angular';\n\n@Component({\n selector: 'lib-icon',\n standalone: true,\n imports: [\n CommonModule,\n LucideBell,\n LucideBuilding2,\n LucideChevronDown,\n LucideGrid,\n LucideMenu,\n LucideMonitor,\n LucideMoon,\n LucideSearch,\n LucideSun,\n LucideX,\n ],\n template: `\n @switch (name()) {\n @case ('menu') {\n <svg lucideMenu [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('x') {\n <svg lucideX [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('sun') {\n <svg lucideSun [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('moon') {\n <svg lucideMoon [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('monitor') {\n <svg lucideMonitor [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('bell') {\n <svg lucideBell [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('grid') {\n <svg lucideGrid [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('chevronDown') {\n <svg lucideChevronDown [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @case ('building2') {\n <svg lucideBuilding2 [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n @default {\n <svg lucideSearch [size]=\"size()\" [color]=\"color()\" [strokeWidth]=\"strokeWidth()\" class=\"lib-icon\"></svg>\n }\n }\n `,\n styles: [`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: inherit;\n }\n .lib-icon {\n display: block;\n color: inherit;\n }\n `]\n})\nexport class IconComponent {\r\n readonly name = input.required<string>();\r\n readonly size = input<number>(24);\n readonly color = input<string | undefined>(undefined);\n readonly strokeWidth = input<number | undefined>(undefined);\n}\n","import { Component, inject, input, output, signal, computed } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { Router, RouterLink, RouterLinkActive } from '@angular/router';\r\nimport { User, Organization, NavigationItem, Notification, Application } from '../../models/models.interface';\r\nimport { ThemeService } from '../../services/theme.service';\r\nimport { AppSwitcherComponent } from '../../navigation';\r\nimport { NotificationBellComponent } from '../../notifications';\r\nimport { UserMenuComponent } from '../../user';\r\n\r\nimport { IconComponent } from '../../shared/icon/icon.component';\r\n\r\n\r\n@Component({\r\n selector: 'lib-header',\r\n standalone: true,\r\n imports: [\r\n CommonModule,\r\n RouterLink,\r\n RouterLinkActive,\r\n AppSwitcherComponent,\r\n NotificationBellComponent,\r\n UserMenuComponent,\r\n IconComponent,\r\n ],\r\n templateUrl: './header.html',\r\n styleUrl: './header.css',\r\n})\r\nexport class HeaderComponent {\r\n private readonly router = inject(Router);\r\n protected readonly themeService = inject(ThemeService);\r\n\r\n // User & Organization Inputs\r\n readonly user = input<User | null>(null);\r\n readonly permissions = input<string[]>([]);\r\n readonly organization = input<Organization | null>(null);\r\n\r\n // Navigation & Integration Inputs\r\n readonly navigationItems = input<NavigationItem[]>([]);\r\n readonly applications = input<Application[]>([]);\r\n readonly notifications = input<Notification[]>([]);\r\n readonly notificationCount = input<number>(0);\r\n readonly logoUrl = input<string>('https://cdn.jsdelivr.net/gh/Excellore/excellore-static-assets@main/images/excellore-logo-origin.png');\n readonly appName = input<string>('Excellore');\n readonly currentAppName = input<string>('');\n readonly showSearch = input<boolean>(true);\n readonly showNotifications = input<boolean>(true);\n readonly showAppSwitcher = input<boolean>(true);\n readonly showThemeSwitcher = input<boolean>(true);\n readonly showSignIn = input<boolean>(true);\n\n // Outputs as decided in the architecture plan\n readonly search = output<string>();\n readonly signIn = output<void>();\n readonly applicationSelected = output<Application>();\n readonly notificationClick = output<Notification>();\r\n readonly markRead = output<string>();\r\n readonly clearAll = output<void>();\r\n readonly menuAction = output<'profile' | 'settings' | 'billing' | 'logout'>();\r\n\r\n // Lucide Icons\r\n // readonly searchIcon = Search;\r\n // readonly menuIcon = Menu;\r\n // readonly xIcon = X;\r\n // readonly sunIcon = Sun;\r\n // readonly moonIcon = Moon;\r\n // readonly monitorIcon = Monitor;\r\n\r\n // Header specific UI states\r\n readonly isMobileMenuOpen = signal(false);\r\n\r\n // Checks if the user has permission to see an item\r\n hasPermission(item: NavigationItem): boolean {\r\n if (!item.permissions || item.permissions.length === 0) {\r\n return true;\r\n }\r\n const currentPermissions = this.permissions();\r\n return item.permissions.some((p) => currentPermissions.includes(p));\r\n }\r\n\r\n // Reactive unread count selector\r\n readonly unreadCount = computed(() => {\n const overrideCount = this.notificationCount();\n if (overrideCount > 0) return overrideCount;\n return this.notifications().filter((n) => !n.read).length;\n });\n\n readonly hasMobileMenuContent = computed(() =>\n this.showSearch() || this.navigationItems().some((item) => this.hasPermission(item))\n );\n\r\n // Determines if an item's internal route is active\r\n isActive(item: NavigationItem): boolean {\r\n if (!item.route) return false;\r\n try {\r\n return this.router.isActive(item.route, {\r\n paths: 'subset',\r\n queryParams: 'ignored',\r\n fragment: 'ignored',\r\n matrixParams: 'ignored',\r\n });\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n toggleMobileMenu(): void {\r\n this.isMobileMenuOpen.update((v) => !v);\r\n }\r\n\r\n closeMobileMenu(): void {\r\n this.isMobileMenuOpen.set(false);\r\n }\r\n\r\n onSearch(query: string): void {\r\n this.search.emit(query);\r\n }\r\n\r\n onApplicationSelect(app: Application): void {\r\n this.applicationSelected.emit(app);\r\n }\r\n\r\n onNotificationClick(notification: Notification): void {\r\n this.notificationClick.emit(notification);\r\n }\r\n\r\n onMarkRead(id: string): void {\r\n this.markRead.emit(id);\r\n }\r\n\r\n onClearAll(): void {\r\n this.clearAll.emit();\r\n }\r\n\r\n onMenuAction(action: 'profile' | 'settings' | 'billing' | 'logout'): void {\r\n this.menuAction.emit(action);\r\n }\r\n}\r\n","<header\n class=\"header-container fixed top-0 inset-x-0 z-40 flex h-[3.75rem] items-center justify-between px-3 text-[var(--foreground)] sm:px-4 lg:px-6\">\n\n <!-- Left Side: Brand, Current App & Desktop Links -->\n <div class=\"flex min-w-0 items-center gap-3\">\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=\"hidden flex-1 justify-center px-4 md:flex\">\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=\"hidden flex-1 md:block\"></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","/*\r\n * Public API Surface of ui\r\n */\r\n\r\nexport * from './lib/models';\r\nexport * from './lib/services';\r\nexport * from './lib/layout';\r\nexport * from './lib/navigation';\r\nexport * from './lib/user';\r\nexport * from './lib/notifications';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@excellore/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"@angular/core": "^21.0.0"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
+
"@lucide/angular": "^1.21.0",
|
|
12
13
|
"tslib": "^2.3.0"
|
|
13
14
|
},
|
|
14
15
|
"sideEffects": false,
|
package/types/excellore-ui.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import * as lucide_angular from 'lucide-angular';
|
|
3
2
|
|
|
4
3
|
interface User {
|
|
5
4
|
id: string;
|
|
@@ -102,8 +101,6 @@ declare class HeaderComponent {
|
|
|
102
101
|
declare class AppSwitcherComponent {
|
|
103
102
|
readonly applications: _angular_core.InputSignal<Application[]>;
|
|
104
103
|
readonly applicationSelected: _angular_core.OutputEmitterRef<Application>;
|
|
105
|
-
readonly gridIcon: lucide_angular.LucideIconData;
|
|
106
|
-
readonly chevronDownIcon: lucide_angular.LucideIconData;
|
|
107
104
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
108
105
|
toggleSwitcher(): void;
|
|
109
106
|
closeSwitcher(): void;
|
|
@@ -118,9 +115,6 @@ declare class OrganizationSwitcherComponent {
|
|
|
118
115
|
readonly organizations: _angular_core.InputSignal<Organization[]>;
|
|
119
116
|
readonly selectedOrganization: _angular_core.InputSignal<Organization | null>;
|
|
120
117
|
readonly organizationChanged: _angular_core.OutputEmitterRef<Organization>;
|
|
121
|
-
readonly chevronDownIcon: lucide_angular.LucideIconData;
|
|
122
|
-
readonly checkIcon: lucide_angular.LucideIconData;
|
|
123
|
-
readonly buildingIcon: lucide_angular.LucideIconData;
|
|
124
118
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
125
119
|
toggleSwitcher(): void;
|
|
126
120
|
closeSwitcher(): void;
|
|
@@ -142,11 +136,6 @@ declare class UserAvatarComponent {
|
|
|
142
136
|
declare class UserMenuComponent {
|
|
143
137
|
readonly user: _angular_core.InputSignal<User | null>;
|
|
144
138
|
readonly menuAction: _angular_core.OutputEmitterRef<"profile" | "settings" | "billing" | "logout">;
|
|
145
|
-
readonly userIcon: lucide_angular.LucideIconData;
|
|
146
|
-
readonly settingsIcon: lucide_angular.LucideIconData;
|
|
147
|
-
readonly creditCardIcon: lucide_angular.LucideIconData;
|
|
148
|
-
readonly logOutIcon: lucide_angular.LucideIconData;
|
|
149
|
-
readonly chevronDownIcon: lucide_angular.LucideIconData;
|
|
150
139
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
151
140
|
toggleMenu(): void;
|
|
152
141
|
closeMenu(): void;
|
|
@@ -162,7 +151,6 @@ declare class NotificationBellComponent {
|
|
|
162
151
|
readonly notificationClick: _angular_core.OutputEmitterRef<Notification>;
|
|
163
152
|
readonly markRead: _angular_core.OutputEmitterRef<string>;
|
|
164
153
|
readonly clearAll: _angular_core.OutputEmitterRef<void>;
|
|
165
|
-
readonly bellIcon: lucide_angular.LucideIconData;
|
|
166
154
|
readonly isOpen: _angular_core.WritableSignal<boolean>;
|
|
167
155
|
togglePanel(): void;
|
|
168
156
|
closePanel(): void;
|
|
@@ -179,10 +167,6 @@ declare class NotificationPanelComponent {
|
|
|
179
167
|
readonly notificationClick: _angular_core.OutputEmitterRef<Notification>;
|
|
180
168
|
readonly markRead: _angular_core.OutputEmitterRef<string>;
|
|
181
169
|
readonly clearAll: _angular_core.OutputEmitterRef<void>;
|
|
182
|
-
readonly checkCheckIcon: lucide_angular.LucideIconData;
|
|
183
|
-
readonly trashIcon: lucide_angular.LucideIconData;
|
|
184
|
-
readonly bellOffIcon: lucide_angular.LucideIconData;
|
|
185
|
-
readonly circleIcon: lucide_angular.LucideIconData;
|
|
186
170
|
onNotificationClick(notification: Notification): void;
|
|
187
171
|
onMarkRead(id: string, event: MouseEvent): void;
|
|
188
172
|
onClearAll(event: MouseEvent): void;
|