@unopsitg/ux 21.0.20 → 21.0.21

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.
@@ -377,6 +377,9 @@ const TOPBAR_MOBILE_LOGO = new InjectionToken('UNOPS_UX_TOPBAR_MOBILE_LOGO', {
377
377
  alt: 'UNOPS'
378
378
  })
379
379
  });
380
+ const TOPBAR_LANGUAGE_CONFIG = new InjectionToken('UNOPS_UX_TOPBAR_LANGUAGE_CONFIG');
381
+ const TOPBAR_PROFILE_MENU_CONFIG = new InjectionToken('UNOPS_UX_TOPBAR_PROFILE_MENU_CONFIG');
382
+ const TOPBAR_NOTIFICATION_CONFIG = new InjectionToken('UNOPS_UX_TOPBAR_NOTIFICATION_CONFIG');
380
383
 
381
384
  class LayoutService {
382
385
  layoutConfig = signal({
@@ -1716,12 +1719,15 @@ class AppTopbar {
1716
1719
  ]
1717
1720
  }
1718
1721
  ], ...(ngDevMode ? [{ debugName: "notifications" }] : []));
1719
- languages = signal([
1722
+ langConfig = inject(TOPBAR_LANGUAGE_CONFIG, { optional: true });
1723
+ profileMenuConfig = inject(TOPBAR_PROFILE_MENU_CONFIG, { optional: true });
1724
+ notifConfig = inject(TOPBAR_NOTIFICATION_CONFIG, { optional: true });
1725
+ languages = signal(this.langConfig?.languages ?? [
1720
1726
  { code: 'en', label: 'English', flag: '\u{1F1EC}\u{1F1E7}' },
1721
1727
  { code: 'fr', label: 'French', flag: '\u{1F1EB}\u{1F1F7}' },
1722
1728
  { code: 'es', label: 'Spanish', flag: '\u{1F1EA}\u{1F1F8}' }
1723
1729
  ], ...(ngDevMode ? [{ debugName: "languages" }] : []));
1724
- selectedLanguage = signal('en', ...(ngDevMode ? [{ debugName: "selectedLanguage" }] : []));
1730
+ selectedLanguage = signal(this.langConfig?.defaultLanguage ?? 'en', ...(ngDevMode ? [{ debugName: "selectedLanguage" }] : []));
1725
1731
  selectedNotificationBar = model(this.notificationsBars()[0].id ?? 'inbox', ...(ngDevMode ? [{ debugName: "selectedNotificationBar" }] : []));
1726
1732
  selectedNotificationsBarData = computed(() => this.notifications().find((f) => f.id === this.selectedNotificationBar()).data, ...(ngDevMode ? [{ debugName: "selectedNotificationsBarData" }] : []));
1727
1733
  onMenuButtonClick() {
@@ -1744,8 +1750,12 @@ class AppTopbar {
1744
1750
  }
1745
1751
  selectLanguage(code) {
1746
1752
  this.selectedLanguage.set(code);
1753
+ this.langConfig?.onLanguageChange?.(code);
1747
1754
  this.closeDropdown();
1748
1755
  }
1756
+ onNotificationBellClick() {
1757
+ this.notifConfig?.onPanelOpen?.();
1758
+ }
1749
1759
  toggleDropdown(id, event) {
1750
1760
  event.stopPropagation();
1751
1761
  this.activeDropdown.update((current) => (current === id ? null : id));
@@ -1836,50 +1846,100 @@ class AppTopbar {
1836
1846
  </a>
1837
1847
  </li>
1838
1848
  <li class="right-sidebar-item static sm:relative z-50" #notificationsItem>
1839
- <a class="right-sidebar-button" aria-label="Notifications" (click)="toggleDropdown('notifications', $event)">
1840
- <span class="w-2 h-2 rounded-full bg-red-500 absolute top-2 right-2.5"></span>
1849
+ <a class="right-sidebar-button" aria-label="Notifications" (click)="toggleDropdown('notifications', $event); onNotificationBellClick()">
1850
+ @if (notifConfig && notifConfig.unreadCount() > 0) {
1851
+ <span class="w-2 h-2 rounded-full bg-red-500 absolute top-2 right-2.5"></span>
1852
+ } @else if (!notifConfig) {
1853
+ <span class="w-2 h-2 rounded-full bg-red-500 absolute top-2 right-2.5"></span>
1854
+ }
1841
1855
  <i class="pi pi-bell"></i>
1842
1856
  </a>
1843
1857
  @if (activeDropdown() === 'notifications') {
1844
1858
  <div
1845
1859
  class="list-none m-0 rounded-2xl border border-surface fixed sm:absolute bg-surface-0 dark:bg-surface-900 overflow-hidden origin-top w-[calc(100vw-2rem)] sm:w-88 mt-2 z-50 top-auto left-4 sm:left-auto sm:right-0 shadow-flyout animate-scalein"
1846
1860
  >
1847
- <div class="p-4 flex items-center justify-between border-b border-surface">
1848
- <span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
1849
- <button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all">Mark all as read</button>
1850
- </div>
1851
- <div class="flex items-center border-b border-surface">
1852
- @for (item of notificationsBars(); track item.id; let i = $index) {
1853
- <button
1854
- [ngClass]="{ 'border-surface-950 dark:border-surface-0': selectedNotificationBar() === item.id, 'border-transparent': selectedNotificationBar() !== item.id }"
1855
- class="px-3.5 py-2 inline-flex items-center border-b gap-2"
1856
- (click)="selectedNotificationBar.set(item.id)"
1857
- >
1858
- <span [ngClass]="{ 'text-surface-950 dark:text-surface-0': selectedNotificationBar() === item.id }" class="label-small">{{ item.label }}</span>
1859
- <p-badge *ngIf="item?.badge" [value]="item.badge" severity="success" size="small" class="rounded-md!" />
1860
- </button>
1861
- }
1862
- </div>
1863
- <ul class="flex flex-col divide-y divide-(--surface-border) max-h-80 overflow-auto">
1864
- @for (item of selectedNotificationsBarData(); track item.name; let i = $index) {
1865
- <li>
1866
- <div class="flex items-center gap-3 px-4 sm:px-6 py-3.5 cursor-pointer hover:bg-emphasis transition-all">
1867
- <p-overlay-badge value="" severity="danger" class="inline-flex">
1868
- <p-avatar [label]="item.initials" size="large" styleClass="rounded-lg" />
1869
- </p-overlay-badge>
1870
- <div class="flex items-center gap-3">
1871
- <div class="flex flex-col">
1872
- <span class="label-small text-left text-surface-950 dark:text-surface-0">{{ item.name }}</span>
1873
- <span class="label-xsmall text-left line-clamp-1">{{ item.description }}</span>
1874
- <span class="label-xsmall text-left">{{ item.time }}</span>
1861
+ @if (notifConfig) {
1862
+ <div class="p-4 flex items-center justify-between border-b border-surface">
1863
+ <span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
1864
+ <button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all" (click)="notifConfig.onMarkAllAsRead()">Mark all as read</button>
1865
+ </div>
1866
+ <div class="flex items-center border-b border-surface">
1867
+ @for (tab of notifConfig.tabs(); track tab.id) {
1868
+ <button
1869
+ [ngClass]="{ 'border-surface-950 dark:border-surface-0': notifConfig.selectedTab() === tab.id, 'border-transparent': notifConfig.selectedTab() !== tab.id }"
1870
+ class="px-3.5 py-2 inline-flex items-center border-b gap-2"
1871
+ (click)="notifConfig.onTabChange(tab.id)"
1872
+ >
1873
+ <span [ngClass]="{ 'text-surface-950 dark:text-surface-0': notifConfig.selectedTab() === tab.id }" class="label-small">{{ tab.label }}</span>
1874
+ <p-badge *ngIf="tab.badge" [value]="tab.badge" severity="success" size="small" class="rounded-md!" />
1875
+ </button>
1876
+ }
1877
+ </div>
1878
+ <ul class="flex flex-col divide-y divide-(--surface-border) max-h-80 overflow-auto">
1879
+ @if (notifConfig.items().length === 0) {
1880
+ <li class="px-4 sm:px-6 py-8 text-center">
1881
+ <i class="pi pi-bell-slash text-2xl text-surface-400 mb-2"></i>
1882
+ <p class="label-small text-surface-400">No {{ notifConfig.selectedTab() === 'unread' ? 'unread ' : '' }}notifications</p>
1883
+ </li>
1884
+ } @else {
1885
+ @for (item of notifConfig.items(); track item.id) {
1886
+ <li>
1887
+ <div class="flex items-center gap-3 px-4 sm:px-6 py-3.5 cursor-pointer hover:bg-emphasis transition-all" (click)="notifConfig.onItemClick(item)">
1888
+ <div class="flex items-center justify-center w-10 h-10 rounded-lg flex-shrink-0" [ngClass]="item.isRead ? 'bg-surface-100 dark:bg-surface-800' : 'bg-primary/10'">
1889
+ <i [class]="item.icon || 'pi pi-bell'" [ngClass]="item.isRead ? 'text-surface-500' : 'text-primary'"></i>
1890
+ </div>
1891
+ <div class="flex items-center gap-3 flex-1 min-w-0">
1892
+ <div class="flex flex-col flex-1 min-w-0">
1893
+ <span class="label-small text-left line-clamp-2" [ngClass]="item.isRead ? '' : 'text-surface-950 dark:text-surface-0 font-semibold'">{{ item.message }}</span>
1894
+ <span class="label-xsmall text-left">{{ item.time }}</span>
1895
+ </div>
1896
+ @if (!item.isRead) {
1897
+ <span class="w-2 h-2 rounded-full bg-primary flex-shrink-0"></span>
1898
+ }
1899
+ </div>
1900
+ </div>
1901
+ </li>
1902
+ }
1903
+ }
1904
+ </ul>
1905
+ } @else {
1906
+ <div class="p-4 flex items-center justify-between border-b border-surface">
1907
+ <span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
1908
+ <button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all">Mark all as read</button>
1909
+ </div>
1910
+ <div class="flex items-center border-b border-surface">
1911
+ @for (item of notificationsBars(); track item.id; let i = $index) {
1912
+ <button
1913
+ [ngClass]="{ 'border-surface-950 dark:border-surface-0': selectedNotificationBar() === item.id, 'border-transparent': selectedNotificationBar() !== item.id }"
1914
+ class="px-3.5 py-2 inline-flex items-center border-b gap-2"
1915
+ (click)="selectedNotificationBar.set(item.id)"
1916
+ >
1917
+ <span [ngClass]="{ 'text-surface-950 dark:text-surface-0': selectedNotificationBar() === item.id }" class="label-small">{{ item.label }}</span>
1918
+ <p-badge *ngIf="item?.badge" [value]="item.badge" severity="success" size="small" class="rounded-md!" />
1919
+ </button>
1920
+ }
1921
+ </div>
1922
+ <ul class="flex flex-col divide-y divide-(--surface-border) max-h-80 overflow-auto">
1923
+ @for (item of selectedNotificationsBarData(); track item.name; let i = $index) {
1924
+ <li>
1925
+ <div class="flex items-center gap-3 px-4 sm:px-6 py-3.5 cursor-pointer hover:bg-emphasis transition-all">
1926
+ <p-overlay-badge value="" severity="danger" class="inline-flex">
1927
+ <p-avatar [label]="item.initials" size="large" styleClass="rounded-lg" />
1928
+ </p-overlay-badge>
1929
+ <div class="flex items-center gap-3">
1930
+ <div class="flex flex-col">
1931
+ <span class="label-small text-left text-surface-950 dark:text-surface-0">{{ item.name }}</span>
1932
+ <span class="label-xsmall text-left line-clamp-1">{{ item.description }}</span>
1933
+ <span class="label-xsmall text-left">{{ item.time }}</span>
1934
+ </div>
1935
+ <p-badge *ngIf="item.new" value="" severity="success" />
1875
1936
  </div>
1876
- <p-badge *ngIf="item.new" value="" severity="success" />
1877
1937
  </div>
1878
- </div>
1879
- <span *ngIf="i !== notifications().length - 1"></span>
1880
- </li>
1881
- }
1882
- </ul>
1938
+ <span *ngIf="i !== notifications().length - 1"></span>
1939
+ </li>
1940
+ }
1941
+ </ul>
1942
+ }
1883
1943
  </div>
1884
1944
  }
1885
1945
  </li>
@@ -1966,36 +2026,35 @@ class AppTopbar {
1966
2026
  }
1967
2027
  </li>
1968
2028
  </div>
1969
- <li>
1970
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
1971
- <i class="pi pi-user"></i>
1972
- <span>Profile</span>
1973
- </a>
1974
- </li>
1975
- <li>
1976
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown(); onConfigButtonClick()">
1977
- <i class="pi pi-cog"></i>
1978
- <span>Settings</span>
1979
- </a>
1980
- </li>
1981
- <li>
1982
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
1983
- <i class="pi pi-calendar"></i>
1984
- <span>Calendar</span>
1985
- </a>
1986
- </li>
1987
- <li>
1988
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
1989
- <i class="pi pi-inbox"></i>
1990
- <span>Inbox</span>
1991
- </a>
1992
- </li>
1993
- <li class="border-t border-surface mt-1 pt-1">
1994
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
1995
- <i class="pi pi-power-off"></i>
1996
- <span>Log out</span>
1997
- </a>
1998
- </li>
2029
+ @if (profileMenuConfig) {
2030
+ @for (item of profileMenuConfig.items; track item.id) {
2031
+ <li [class.border-t]="item.separator" [class.border-surface]="item.separator" [class.mt-1]="item.separator" [class.pt-1]="item.separator">
2032
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown(); item.command()">
2033
+ <i [class]="item.icon"></i>
2034
+ <span>{{ item.label }}</span>
2035
+ </a>
2036
+ </li>
2037
+ }
2038
+ } @else {
2039
+ <li>
2040
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2041
+ <i class="pi pi-user"></i>
2042
+ <span>Profile</span>
2043
+ </a>
2044
+ </li>
2045
+ <li>
2046
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown(); onConfigButtonClick()">
2047
+ <i class="pi pi-cog"></i>
2048
+ <span>Settings</span>
2049
+ </a>
2050
+ </li>
2051
+ <li class="border-t border-surface mt-1 pt-1">
2052
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2053
+ <i class="pi pi-power-off"></i>
2054
+ <span>Log out</span>
2055
+ </a>
2056
+ </li>
2057
+ }
1999
2058
  </ul>
2000
2059
  </div>
2001
2060
  }
@@ -2066,50 +2125,100 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
2066
2125
  </a>
2067
2126
  </li>
2068
2127
  <li class="right-sidebar-item static sm:relative z-50" #notificationsItem>
2069
- <a class="right-sidebar-button" aria-label="Notifications" (click)="toggleDropdown('notifications', $event)">
2070
- <span class="w-2 h-2 rounded-full bg-red-500 absolute top-2 right-2.5"></span>
2128
+ <a class="right-sidebar-button" aria-label="Notifications" (click)="toggleDropdown('notifications', $event); onNotificationBellClick()">
2129
+ @if (notifConfig && notifConfig.unreadCount() > 0) {
2130
+ <span class="w-2 h-2 rounded-full bg-red-500 absolute top-2 right-2.5"></span>
2131
+ } @else if (!notifConfig) {
2132
+ <span class="w-2 h-2 rounded-full bg-red-500 absolute top-2 right-2.5"></span>
2133
+ }
2071
2134
  <i class="pi pi-bell"></i>
2072
2135
  </a>
2073
2136
  @if (activeDropdown() === 'notifications') {
2074
2137
  <div
2075
2138
  class="list-none m-0 rounded-2xl border border-surface fixed sm:absolute bg-surface-0 dark:bg-surface-900 overflow-hidden origin-top w-[calc(100vw-2rem)] sm:w-88 mt-2 z-50 top-auto left-4 sm:left-auto sm:right-0 shadow-flyout animate-scalein"
2076
2139
  >
2077
- <div class="p-4 flex items-center justify-between border-b border-surface">
2078
- <span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
2079
- <button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all">Mark all as read</button>
2080
- </div>
2081
- <div class="flex items-center border-b border-surface">
2082
- @for (item of notificationsBars(); track item.id; let i = $index) {
2083
- <button
2084
- [ngClass]="{ 'border-surface-950 dark:border-surface-0': selectedNotificationBar() === item.id, 'border-transparent': selectedNotificationBar() !== item.id }"
2085
- class="px-3.5 py-2 inline-flex items-center border-b gap-2"
2086
- (click)="selectedNotificationBar.set(item.id)"
2087
- >
2088
- <span [ngClass]="{ 'text-surface-950 dark:text-surface-0': selectedNotificationBar() === item.id }" class="label-small">{{ item.label }}</span>
2089
- <p-badge *ngIf="item?.badge" [value]="item.badge" severity="success" size="small" class="rounded-md!" />
2090
- </button>
2091
- }
2092
- </div>
2093
- <ul class="flex flex-col divide-y divide-(--surface-border) max-h-80 overflow-auto">
2094
- @for (item of selectedNotificationsBarData(); track item.name; let i = $index) {
2095
- <li>
2096
- <div class="flex items-center gap-3 px-4 sm:px-6 py-3.5 cursor-pointer hover:bg-emphasis transition-all">
2097
- <p-overlay-badge value="" severity="danger" class="inline-flex">
2098
- <p-avatar [label]="item.initials" size="large" styleClass="rounded-lg" />
2099
- </p-overlay-badge>
2100
- <div class="flex items-center gap-3">
2101
- <div class="flex flex-col">
2102
- <span class="label-small text-left text-surface-950 dark:text-surface-0">{{ item.name }}</span>
2103
- <span class="label-xsmall text-left line-clamp-1">{{ item.description }}</span>
2104
- <span class="label-xsmall text-left">{{ item.time }}</span>
2140
+ @if (notifConfig) {
2141
+ <div class="p-4 flex items-center justify-between border-b border-surface">
2142
+ <span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
2143
+ <button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all" (click)="notifConfig.onMarkAllAsRead()">Mark all as read</button>
2144
+ </div>
2145
+ <div class="flex items-center border-b border-surface">
2146
+ @for (tab of notifConfig.tabs(); track tab.id) {
2147
+ <button
2148
+ [ngClass]="{ 'border-surface-950 dark:border-surface-0': notifConfig.selectedTab() === tab.id, 'border-transparent': notifConfig.selectedTab() !== tab.id }"
2149
+ class="px-3.5 py-2 inline-flex items-center border-b gap-2"
2150
+ (click)="notifConfig.onTabChange(tab.id)"
2151
+ >
2152
+ <span [ngClass]="{ 'text-surface-950 dark:text-surface-0': notifConfig.selectedTab() === tab.id }" class="label-small">{{ tab.label }}</span>
2153
+ <p-badge *ngIf="tab.badge" [value]="tab.badge" severity="success" size="small" class="rounded-md!" />
2154
+ </button>
2155
+ }
2156
+ </div>
2157
+ <ul class="flex flex-col divide-y divide-(--surface-border) max-h-80 overflow-auto">
2158
+ @if (notifConfig.items().length === 0) {
2159
+ <li class="px-4 sm:px-6 py-8 text-center">
2160
+ <i class="pi pi-bell-slash text-2xl text-surface-400 mb-2"></i>
2161
+ <p class="label-small text-surface-400">No {{ notifConfig.selectedTab() === 'unread' ? 'unread ' : '' }}notifications</p>
2162
+ </li>
2163
+ } @else {
2164
+ @for (item of notifConfig.items(); track item.id) {
2165
+ <li>
2166
+ <div class="flex items-center gap-3 px-4 sm:px-6 py-3.5 cursor-pointer hover:bg-emphasis transition-all" (click)="notifConfig.onItemClick(item)">
2167
+ <div class="flex items-center justify-center w-10 h-10 rounded-lg flex-shrink-0" [ngClass]="item.isRead ? 'bg-surface-100 dark:bg-surface-800' : 'bg-primary/10'">
2168
+ <i [class]="item.icon || 'pi pi-bell'" [ngClass]="item.isRead ? 'text-surface-500' : 'text-primary'"></i>
2169
+ </div>
2170
+ <div class="flex items-center gap-3 flex-1 min-w-0">
2171
+ <div class="flex flex-col flex-1 min-w-0">
2172
+ <span class="label-small text-left line-clamp-2" [ngClass]="item.isRead ? '' : 'text-surface-950 dark:text-surface-0 font-semibold'">{{ item.message }}</span>
2173
+ <span class="label-xsmall text-left">{{ item.time }}</span>
2174
+ </div>
2175
+ @if (!item.isRead) {
2176
+ <span class="w-2 h-2 rounded-full bg-primary flex-shrink-0"></span>
2177
+ }
2178
+ </div>
2179
+ </div>
2180
+ </li>
2181
+ }
2182
+ }
2183
+ </ul>
2184
+ } @else {
2185
+ <div class="p-4 flex items-center justify-between border-b border-surface">
2186
+ <span class="label-small text-surface-950 dark:text-surface-0">Notifications</span>
2187
+ <button pRipple class="py-1 px-2 text-surface-950 dark:text-surface-0 label-x-small hover:bg-emphasis border border-surface rounded-lg shadow-subtle transition-all">Mark all as read</button>
2188
+ </div>
2189
+ <div class="flex items-center border-b border-surface">
2190
+ @for (item of notificationsBars(); track item.id; let i = $index) {
2191
+ <button
2192
+ [ngClass]="{ 'border-surface-950 dark:border-surface-0': selectedNotificationBar() === item.id, 'border-transparent': selectedNotificationBar() !== item.id }"
2193
+ class="px-3.5 py-2 inline-flex items-center border-b gap-2"
2194
+ (click)="selectedNotificationBar.set(item.id)"
2195
+ >
2196
+ <span [ngClass]="{ 'text-surface-950 dark:text-surface-0': selectedNotificationBar() === item.id }" class="label-small">{{ item.label }}</span>
2197
+ <p-badge *ngIf="item?.badge" [value]="item.badge" severity="success" size="small" class="rounded-md!" />
2198
+ </button>
2199
+ }
2200
+ </div>
2201
+ <ul class="flex flex-col divide-y divide-(--surface-border) max-h-80 overflow-auto">
2202
+ @for (item of selectedNotificationsBarData(); track item.name; let i = $index) {
2203
+ <li>
2204
+ <div class="flex items-center gap-3 px-4 sm:px-6 py-3.5 cursor-pointer hover:bg-emphasis transition-all">
2205
+ <p-overlay-badge value="" severity="danger" class="inline-flex">
2206
+ <p-avatar [label]="item.initials" size="large" styleClass="rounded-lg" />
2207
+ </p-overlay-badge>
2208
+ <div class="flex items-center gap-3">
2209
+ <div class="flex flex-col">
2210
+ <span class="label-small text-left text-surface-950 dark:text-surface-0">{{ item.name }}</span>
2211
+ <span class="label-xsmall text-left line-clamp-1">{{ item.description }}</span>
2212
+ <span class="label-xsmall text-left">{{ item.time }}</span>
2213
+ </div>
2214
+ <p-badge *ngIf="item.new" value="" severity="success" />
2105
2215
  </div>
2106
- <p-badge *ngIf="item.new" value="" severity="success" />
2107
2216
  </div>
2108
- </div>
2109
- <span *ngIf="i !== notifications().length - 1"></span>
2110
- </li>
2111
- }
2112
- </ul>
2217
+ <span *ngIf="i !== notifications().length - 1"></span>
2218
+ </li>
2219
+ }
2220
+ </ul>
2221
+ }
2113
2222
  </div>
2114
2223
  }
2115
2224
  </li>
@@ -2196,36 +2305,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
2196
2305
  }
2197
2306
  </li>
2198
2307
  </div>
2199
- <li>
2200
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2201
- <i class="pi pi-user"></i>
2202
- <span>Profile</span>
2203
- </a>
2204
- </li>
2205
- <li>
2206
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown(); onConfigButtonClick()">
2207
- <i class="pi pi-cog"></i>
2208
- <span>Settings</span>
2209
- </a>
2210
- </li>
2211
- <li>
2212
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2213
- <i class="pi pi-calendar"></i>
2214
- <span>Calendar</span>
2215
- </a>
2216
- </li>
2217
- <li>
2218
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2219
- <i class="pi pi-inbox"></i>
2220
- <span>Inbox</span>
2221
- </a>
2222
- </li>
2223
- <li class="border-t border-surface mt-1 pt-1">
2224
- <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2225
- <i class="pi pi-power-off"></i>
2226
- <span>Log out</span>
2227
- </a>
2228
- </li>
2308
+ @if (profileMenuConfig) {
2309
+ @for (item of profileMenuConfig.items; track item.id) {
2310
+ <li [class.border-t]="item.separator" [class.border-surface]="item.separator" [class.mt-1]="item.separator" [class.pt-1]="item.separator">
2311
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown(); item.command()">
2312
+ <i [class]="item.icon"></i>
2313
+ <span>{{ item.label }}</span>
2314
+ </a>
2315
+ </li>
2316
+ }
2317
+ } @else {
2318
+ <li>
2319
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2320
+ <i class="pi pi-user"></i>
2321
+ <span>Profile</span>
2322
+ </a>
2323
+ </li>
2324
+ <li>
2325
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown(); onConfigButtonClick()">
2326
+ <i class="pi pi-cog"></i>
2327
+ <span>Settings</span>
2328
+ </a>
2329
+ </li>
2330
+ <li class="border-t border-surface mt-1 pt-1">
2331
+ <a class="label-small dark:text-surface-400 flex gap-2 py-2 px-2.5 rounded-lg items-center hover:bg-emphasis transition-colors duration-150 cursor-pointer" (click)="closeDropdown()">
2332
+ <i class="pi pi-power-off"></i>
2333
+ <span>Log out</span>
2334
+ </a>
2335
+ </li>
2336
+ }
2229
2337
  </ul>
2230
2338
  </div>
2231
2339
  }
@@ -3968,5 +4076,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
3968
4076
  * Generated bundle index. Do not edit.
3969
4077
  */
3970
4078
 
3971
- export { AiCardBgComponent, AiInsightsCardComponent, AppBreadcrumb, AppConfigurator, AppFooter, AppLayout, AppMenu, AppMenuitem, AppRightMenu, AppSearch, AppSidebar, AppTopbar, AuthLayout, BrandContrast, BrandCrisp, BrandSoft, CompletionStepsComponent, DetailLayoutComponent, DetailTabDirective, DocumentsCardComponent, FooterMainComponent, FooterService, LayoutService, MENU_MODEL, PillTabsComponent, SIDEBAR_LOGO, TOPBAR_MOBILE_LOGO, TaskDrawerComponent, UxSelectComponent, brandPresets, brandPrimitives };
4079
+ export { AiCardBgComponent, AiInsightsCardComponent, AppBreadcrumb, AppConfigurator, AppFooter, AppLayout, AppMenu, AppMenuitem, AppRightMenu, AppSearch, AppSidebar, AppTopbar, AuthLayout, BrandContrast, BrandCrisp, BrandSoft, CompletionStepsComponent, DetailLayoutComponent, DetailTabDirective, DocumentsCardComponent, FooterMainComponent, FooterService, LayoutService, MENU_MODEL, PillTabsComponent, SIDEBAR_LOGO, TOPBAR_LANGUAGE_CONFIG, TOPBAR_MOBILE_LOGO, TOPBAR_NOTIFICATION_CONFIG, TOPBAR_PROFILE_MENU_CONFIG, TaskDrawerComponent, UxSelectComponent, brandPresets, brandPrimitives };
3972
4080
  //# sourceMappingURL=unopsitg-ux.mjs.map