@apptegy/nuxt-navigation 0.1.111 → 1.0.0-alpha.0

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.
Files changed (28) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +3 -2
  3. package/dist/runtime/components/Nav/Header.vue +108 -321
  4. package/dist/runtime/components/Nav/Header.vue.d.ts +12 -39
  5. package/dist/runtime/components/Nav/OrgSelect.vue +8 -8
  6. package/dist/runtime/components/Nav/Sidebar.vue +118 -207
  7. package/dist/runtime/components/Nav/Sidebar.vue.d.ts +7 -15
  8. package/dist/runtime/components/Nav/SidebarItem.vue +19 -22
  9. package/dist/runtime/components/Nav/SidebarSection.vue +28 -35
  10. package/dist/runtime/components/Nav/SidebarSection.vue.d.ts +2 -2
  11. package/dist/runtime/components/Nav/SubMenuItem.vue +1 -1
  12. package/dist/runtime/types/index.d.ts +0 -1
  13. package/locale/en.json +1 -22
  14. package/package.json +6 -9
  15. package/dist/runtime/components/Nav/NotificationItem.vue +0 -337
  16. package/dist/runtime/components/Nav/NotificationItem.vue.d.ts +0 -12
  17. package/dist/runtime/components/Nav/NotificationsPanel.vue +0 -513
  18. package/dist/runtime/components/Nav/NotificationsPanel.vue.d.ts +0 -53
  19. package/dist/runtime/constants/notification-types.d.ts +0 -19
  20. package/dist/runtime/constants/notification-types.js +0 -48
  21. package/dist/runtime/types/notifications.d.ts +0 -79
  22. package/dist/runtime/types/notifications.js +0 -0
  23. package/dist/runtime/utils/notification-api.d.ts +0 -26
  24. package/dist/runtime/utils/notification-api.js +0 -84
  25. package/dist/runtime/utils/notification-dates.d.ts +0 -15
  26. package/dist/runtime/utils/notification-dates.js +0 -81
  27. package/dist/runtime/utils/notifications.d.ts +0 -21
  28. package/dist/runtime/utils/notifications.js +0 -117
@@ -1,513 +0,0 @@
1
- <template>
2
- <div
3
- class="notifications-panel"
4
- :class="{
5
- 'notifications-panel--embedded': embedded,
6
- 'notifications-panel--mobile': mobile
7
- }"
8
- role="dialog"
9
- :aria-label="$t('navigation.notifications')"
10
- >
11
- <div class="notifications-panel__header">
12
- <div class="notifications-panel__title-row">
13
- <h2
14
- v-if="!mobile"
15
- class="notifications-panel__title"
16
- >
17
- {{ $t("navigation.notifications") }}
18
- </h2>
19
- <span
20
- v-if="data.retentionLabel && !mobile"
21
- class="notifications-panel__retention"
22
- >
23
- {{ data.retentionLabel }}
24
- </span>
25
- <Button
26
- v-if="mobile"
27
- type="button"
28
- severity="secondary"
29
- text
30
- rounded
31
- class="notifications-panel__close"
32
- :aria-label="$t('navigation.notificationsPanel.close')"
33
- @click="$emit('close')"
34
- >
35
- <Icon
36
- name="lucide:x"
37
- size="20"
38
- aria-hidden="true"
39
- />
40
- </Button>
41
- </div>
42
-
43
- <Tabs
44
- :value="activeTabId"
45
- class="notifications-panel__tabs"
46
- @update:value="selectTab"
47
- >
48
- <TabList>
49
- <Tab
50
- v-for="tab in data.tabs"
51
- :key="tab.id"
52
- :value="tab.id"
53
- class="notifications-panel__tab-item"
54
- >
55
- <span>{{ tab.label }}</span>
56
- <Badge
57
- v-if="getTabBadgeCount(tab) > 0"
58
- :value="formatCount(getTabBadgeCount(tab))"
59
- severity="danger"
60
- class="notifications-panel__tab-badge"
61
- />
62
- </Tab>
63
- </TabList>
64
- </Tabs>
65
- </div>
66
-
67
- <div
68
- v-if="showFilterChips"
69
- class="notifications-panel__filters"
70
- >
71
- <div
72
- ref="filtersRef"
73
- class="notifications-panel__filters-scroll"
74
- >
75
- <Button
76
- v-for="filter in visibleFilters"
77
- :key="filter.id"
78
- type="button"
79
- size="small"
80
- rounded
81
- :severity="filter.id === activeFilterId ? 'primary' : 'secondary'"
82
- :outlined="filter.id !== activeFilterId"
83
- class="notifications-panel__filter"
84
- @click="selectFilter(filter.id)"
85
- >
86
- <span class="notifications-panel__filter-option">
87
- <span>{{ filter.label }}</span>
88
- <Badge
89
- v-if="getFilterBadgeCount(filter) > 0"
90
- :value="formatCount(getFilterBadgeCount(filter))"
91
- severity="secondary"
92
- />
93
- </span>
94
- </Button>
95
- </div>
96
- <Button
97
- type="button"
98
- severity="secondary"
99
- outlined
100
- rounded
101
- class="notifications-panel__filters-next"
102
- :aria-label="$t('navigation.notificationsPanel.scrollFilters')"
103
- @click="scrollFilters"
104
- >
105
- <Icon
106
- name="lucide:chevron-right"
107
- size="16"
108
- aria-hidden="true"
109
- />
110
- </Button>
111
- </div>
112
-
113
- <div class="notifications-panel__body">
114
- <div
115
- v-if="loading"
116
- class="notifications-panel__loading"
117
- >
118
- <Skeleton
119
- v-for="index in 3"
120
- :key="index"
121
- height="4.5rem"
122
- class="notifications-panel__skeleton"
123
- />
124
- </div>
125
-
126
- <template v-else>
127
- <section
128
- v-for="(group, groupIndex) in filteredGroups"
129
- :key="group.id"
130
- class="notifications-panel__group"
131
- >
132
- <div class="notifications-panel__group-header">
133
- <h3 class="notifications-panel__group-label">
134
- {{ group.label }}
135
- </h3>
136
- <Button
137
- v-if="showClearAll(groupIndex)"
138
- type="button"
139
- link
140
- size="small"
141
- class="notifications-panel__clear-all"
142
- :label="$t('navigation.notificationsPanel.clearAll')"
143
- @click="$emit('clear-all', { groupId: group.id, tabId: activeTabId, filterId: activeFilterId })"
144
- />
145
- </div>
146
-
147
- <div class="notifications-panel__list">
148
- <NavNotificationItem
149
- v-for="notification in group.notifications"
150
- :key="notification.id"
151
- :item="notification"
152
- @dismiss="(id) => $emit('dismiss', { id, tabId: activeTabId, filterId: activeFilterId })"
153
- @select="(item) => $emit('select', { item, tabId: activeTabId, filterId: activeFilterId })"
154
- />
155
- </div>
156
- </section>
157
-
158
- <Message
159
- v-if="isEmpty"
160
- severity="secondary"
161
- variant="simple"
162
- class="notifications-panel__empty"
163
- >
164
- {{ $t("navigation.notificationsPanel.empty") }}
165
- </Message>
166
- </template>
167
- </div>
168
- </div>
169
- </template>
170
-
171
- <script setup>
172
- import { computed, ref, watch } from "vue";
173
- import Badge from "primevue/badge";
174
- import Button from "primevue/button";
175
- import Message from "primevue/message";
176
- import Skeleton from "primevue/skeleton";
177
- import Tab from "primevue/tab";
178
- import TabList from "primevue/tablist";
179
- import Tabs from "primevue/tabs";
180
- import {
181
- flattenNotifications,
182
- formatNotificationCount,
183
- getFilterBadgeCount as resolveFilterBadgeCount,
184
- getTabBadgeCount as resolveTabBadgeCount,
185
- getVisibleFilters,
186
- isInBadge,
187
- notificationMatchesFilter,
188
- resolveNotificationFilters,
189
- shouldShowFilterChips
190
- } from "../../utils/notifications";
191
- const props = defineProps({
192
- data: { type: Object, required: true },
193
- loading: { type: Boolean, required: false, default: false },
194
- activeTabId: { type: String, required: false },
195
- activeFilterId: { type: String, required: false },
196
- embedded: { type: Boolean, required: false, default: false },
197
- mobile: { type: Boolean, required: false, default: false }
198
- });
199
- const emit = defineEmits(["update:activeTabId", "update:activeFilterId", "clear-all", "dismiss", "select", "close"]);
200
- const filtersRef = ref();
201
- const activeTabId = ref(props.activeTabId || props.data.tabs[0]?.id || "");
202
- const activeFilterId = ref(props.activeFilterId || props.data.filters?.[0]?.id || "all-types");
203
- watch(
204
- () => props.activeTabId,
205
- (value) => {
206
- if (value) {
207
- activeTabId.value = value;
208
- }
209
- }
210
- );
211
- watch(
212
- () => props.activeFilterId,
213
- (value) => {
214
- if (value) {
215
- activeFilterId.value = value;
216
- }
217
- }
218
- );
219
- watch(
220
- () => props.data.tabs,
221
- (tabs) => {
222
- if (!tabs.some((tab) => tab.id === activeTabId.value)) {
223
- activeTabId.value = tabs[0]?.id || "";
224
- }
225
- },
226
- { deep: true }
227
- );
228
- const allNotifications = computed(() => flattenNotifications(props.data.groups));
229
- const usesDynamicFilters = computed(() => !props.data.filters?.length);
230
- const activeTab = computed(
231
- () => props.data.tabs.find((tab) => tab.id === activeTabId.value)
232
- );
233
- const resolvedFilters = computed(
234
- () => resolveNotificationFilters(allNotifications.value, activeTab.value, props.data.filters)
235
- );
236
- const visibleFilters = computed(() => {
237
- if (usesDynamicFilters.value) {
238
- return resolvedFilters.value;
239
- }
240
- return getVisibleFilters(allNotifications.value, resolvedFilters.value, activeTab.value);
241
- });
242
- const showFilterChips = computed(
243
- () => shouldShowFilterChips(
244
- allNotifications.value,
245
- resolvedFilters.value,
246
- activeTab.value,
247
- usesDynamicFilters.value
248
- )
249
- );
250
- watch(
251
- visibleFilters,
252
- (filters) => {
253
- if (filters.length && !filters.some((filter) => filter.id === activeFilterId.value)) {
254
- activeFilterId.value = filters[0]?.id || "all-types";
255
- }
256
- if (!filters.length && activeFilterId.value !== "all-types") {
257
- activeFilterId.value = "all-types";
258
- }
259
- },
260
- { deep: true }
261
- );
262
- function getTabBadgeCount(tab) {
263
- return resolveTabBadgeCount(allNotifications.value, tab);
264
- }
265
- function getFilterBadgeCount(filter) {
266
- return resolveFilterBadgeCount(allNotifications.value, filter);
267
- }
268
- function formatCount(count) {
269
- return formatNotificationCount(count);
270
- }
271
- const activeFilter = computed(
272
- () => visibleFilters.value.find((filter) => filter.id === activeFilterId.value) || resolvedFilters.value.find((filter) => filter.id === activeFilterId.value)
273
- );
274
- function showClearAll(groupIndex) {
275
- return groupIndex === 0 && (activeTabId.value === "new" || activeTab.value?.unreadOnly);
276
- }
277
- function matchesTab(notification) {
278
- const tab = activeTab.value;
279
- if (!tab) {
280
- return true;
281
- }
282
- if (tab.unreadOnly || tab.id === "new") {
283
- return isInBadge(notification);
284
- }
285
- return true;
286
- }
287
- function matchesFilter(notification) {
288
- const filter = activeFilter.value;
289
- if (!filter) {
290
- return true;
291
- }
292
- return notificationMatchesFilter(notification, filter);
293
- }
294
- const filteredGroups = computed(
295
- () => props.data.groups.map((group) => ({
296
- ...group,
297
- notifications: group.notifications.filter(
298
- (notification) => matchesTab(notification) && matchesFilter(notification)
299
- )
300
- })).filter((group) => group.notifications.length > 0)
301
- );
302
- const isEmpty = computed(
303
- () => !props.loading && filteredGroups.value.length === 0
304
- );
305
- function selectTab(id) {
306
- const tabId = String(id);
307
- activeTabId.value = tabId;
308
- emit("update:activeTabId", tabId);
309
- if (tabId === "all") {
310
- activeFilterId.value = "all-types";
311
- emit("update:activeFilterId", "all-types");
312
- }
313
- }
314
- function selectFilter(id) {
315
- activeFilterId.value = id;
316
- emit("update:activeFilterId", id);
317
- }
318
- function scrollFilters() {
319
- filtersRef.value?.scrollBy({ left: 160, behavior: "smooth" });
320
- }
321
- </script>
322
-
323
- <style scoped>
324
- .notifications-panel {
325
- position: absolute;
326
- top: calc(100% + 8px);
327
- right: 0;
328
- z-index: 100;
329
- display: flex;
330
- flex-direction: column;
331
- width: min(480px, 100vw - 32px);
332
- max-height: calc(100vh - 130px);
333
- border: 1px solid var(--grey-20, #e5e7eb);
334
- border-radius: 12px;
335
- background: var(--primary-white, #fff);
336
- box-shadow: 0 20px 48px rgba(0, 0, 0, 0.16);
337
- overflow: hidden;
338
- }
339
- .notifications-panel--embedded {
340
- position: static;
341
- top: auto;
342
- right: auto;
343
- z-index: auto;
344
- width: 100%;
345
- max-height: calc(100vh - 130px);
346
- border: none;
347
- border-radius: 0;
348
- box-shadow: none;
349
- }
350
- .notifications-panel--mobile {
351
- position: fixed;
352
- inset: 0;
353
- z-index: 10000;
354
- width: 100%;
355
- max-width: none;
356
- height: 100dvh;
357
- max-height: none;
358
- border: none;
359
- border-radius: 0;
360
- box-shadow: none;
361
- }
362
- .notifications-panel--mobile .notifications-panel__body {
363
- flex: 1;
364
- min-height: 0;
365
- }
366
- .notifications-panel__header {
367
- padding: 16px 16px 0;
368
- }
369
- .notifications-panel__title-row {
370
- display: flex;
371
- align-items: center;
372
- justify-content: space-between;
373
- gap: 12px;
374
- margin-bottom: 12px;
375
- }
376
- .notifications-panel__title {
377
- margin: 0;
378
- font-size: 18px;
379
- font-weight: 600;
380
- line-height: 24px;
381
- color: var(--grey-90, #111827);
382
- }
383
- .notifications-panel__retention {
384
- font-size: 12px;
385
- line-height: 16px;
386
- color: var(--grey-60, #6b7280);
387
- white-space: nowrap;
388
- }
389
- .notifications-panel__tabs :deep(.p-tablist-tab-list) {
390
- gap: 20px;
391
- border-bottom: 1px solid var(--grey-20, #e5e7eb);
392
- background: transparent;
393
- }
394
- .notifications-panel__tabs :deep(.p-tablist-active-bar) {
395
- display: none;
396
- }
397
- .notifications-panel__tabs :deep(.p-tab) {
398
- padding: 0 0 12px;
399
- border: none;
400
- border-bottom: 2px solid transparent;
401
- background: transparent;
402
- color: var(--grey-60, #6b7280);
403
- font-size: 13px;
404
- font-weight: 700;
405
- line-height: 20px;
406
- }
407
- .notifications-panel__tabs :deep(.p-tab.p-tab-active) {
408
- border-bottom-color: #662e80;
409
- color: #662e80;
410
- }
411
- .notifications-panel__tab-item {
412
- display: inline-flex;
413
- align-items: center;
414
- gap: 8px;
415
- }
416
- .notifications-panel__tab-badge :deep(.p-badge) {
417
- min-width: 16px;
418
- height: 16px;
419
- padding: 0 4px;
420
- font-size: 10px;
421
- font-weight: 800;
422
- line-height: 12px;
423
- }
424
- .notifications-panel__filters {
425
- display: flex;
426
- align-items: center;
427
- gap: 8px;
428
- padding: 12px 16px;
429
- border-bottom: 1px solid var(--grey-20, #e5e7eb);
430
- }
431
- .notifications-panel__filters-scroll {
432
- display: flex;
433
- gap: 8px;
434
- flex: 1;
435
- min-width: 0;
436
- overflow-x: auto;
437
- scrollbar-width: none;
438
- }
439
- .notifications-panel__filters-scroll::-webkit-scrollbar {
440
- display: none;
441
- }
442
- .notifications-panel__filter {
443
- flex-shrink: 0;
444
- font-size: 11.5px;
445
- line-height: 16px;
446
- white-space: nowrap;
447
- }
448
- .notifications-panel__filter-option {
449
- display: inline-flex;
450
- align-items: center;
451
- gap: 6px;
452
- }
453
- .notifications-panel__filters-next {
454
- flex-shrink: 0;
455
- width: 28px;
456
- height: 28px;
457
- padding: 0;
458
- }
459
- .notifications-panel__body {
460
- overflow-y: auto;
461
- padding: 16px;
462
- background: #f7f7f8;
463
- flex: 1;
464
- min-height: 0;
465
- }
466
- .notifications-panel__loading {
467
- display: flex;
468
- flex-direction: column;
469
- gap: 8px;
470
- }
471
- .notifications-panel__skeleton {
472
- border-radius: 8px;
473
- }
474
- .notifications-panel__empty {
475
- justify-content: center;
476
- width: 100%;
477
- background: transparent;
478
- }
479
- .notifications-panel__group + .notifications-panel__group {
480
- margin-top: 20px;
481
- }
482
- .notifications-panel__group-header {
483
- display: flex;
484
- align-items: center;
485
- justify-content: space-between;
486
- gap: 12px;
487
- margin-bottom: 12px;
488
- }
489
- .notifications-panel__group-label {
490
- margin: 0;
491
- font-size: 10.5px;
492
- font-weight: 800;
493
- line-height: 16px;
494
- letter-spacing: 0.04em;
495
- text-transform: uppercase;
496
- color: var(--grey-40, #adadad);
497
- }
498
- .notifications-panel__clear-all {
499
- padding: 0;
500
- color: #662e80;
501
- font-size: 12px;
502
- font-weight: 600;
503
- line-height: 18px;
504
- }
505
- .notifications-panel__list {
506
- display: flex;
507
- flex-direction: column;
508
- gap: 8px;
509
- }
510
- .notifications-panel__close {
511
- margin-left: auto;
512
- }
513
- </style>
@@ -1,53 +0,0 @@
1
- import type { INotificationsPanelData } from '../../types/index.js';
2
- type __VLS_Props = {
3
- data: INotificationsPanelData;
4
- loading?: boolean;
5
- activeTabId?: string;
6
- activeFilterId?: string;
7
- embedded?: boolean;
8
- mobile?: boolean;
9
- };
10
- declare const _default: import("vue").DefineComponent<__VLS_Props, void, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
11
- select: (payload: {
12
- item: INotificationsPanelData["groups"][number]["notifications"][number];
13
- tabId: string;
14
- filterId: string;
15
- }) => any;
16
- "update:activeTabId": (id: string) => any;
17
- "update:activeFilterId": (id: string) => any;
18
- "clear-all": (payload: {
19
- groupId: string;
20
- tabId: string;
21
- filterId: string;
22
- }) => any;
23
- dismiss: (payload: {
24
- id: string;
25
- tabId: string;
26
- filterId: string;
27
- }) => any;
28
- close: () => any;
29
- }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
30
- onSelect?: ((payload: {
31
- item: INotificationsPanelData["groups"][number]["notifications"][number];
32
- tabId: string;
33
- filterId: string;
34
- }) => any) | undefined;
35
- "onUpdate:activeTabId"?: ((id: string) => any) | undefined;
36
- "onUpdate:activeFilterId"?: ((id: string) => any) | undefined;
37
- "onClear-all"?: ((payload: {
38
- groupId: string;
39
- tabId: string;
40
- filterId: string;
41
- }) => any) | undefined;
42
- onDismiss?: ((payload: {
43
- id: string;
44
- tabId: string;
45
- filterId: string;
46
- }) => any) | undefined;
47
- onClose?: (() => any) | undefined;
48
- }>, {
49
- loading: boolean;
50
- embedded: boolean;
51
- mobile: boolean;
52
- }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
53
- export default _default;
@@ -1,19 +0,0 @@
1
- import type { NotificationType } from '../types/index.js';
2
- /** Type accent colors from NC v2 Visual Spec (section 3). */
3
- export declare const NOTIFICATION_TYPE_ACCENTS: Record<NotificationType, string>;
4
- export declare const NOTIFICATION_BADGE_COLOR = "#C84B31";
5
- /** Category definitions used to derive filter pills from notification data. */
6
- export declare const NOTIFICATION_FILTER_CATEGORIES: Array<{
7
- id: string;
8
- label: string;
9
- types: NotificationType[];
10
- }>;
11
- /** @deprecated Use NOTIFICATION_FILTER_CATEGORIES */
12
- export declare const DEFAULT_NOTIFICATION_FILTERS: ({
13
- id: string;
14
- label: string;
15
- types: NotificationType[];
16
- } | {
17
- id: string;
18
- label: string;
19
- })[];
@@ -1,48 +0,0 @@
1
- export const NOTIFICATION_TYPE_ACCENTS = {
2
- announcement: "#D67A11",
3
- message: "#1372B3",
4
- comment: "#139A4F",
5
- mention: "#5A2496",
6
- reply: "#1372B3",
7
- reaction: "#62626E",
8
- "school-post": "#1E3FBA",
9
- system: "#62626E",
10
- unknown: "#62626E"
11
- };
12
- export const NOTIFICATION_BADGE_COLOR = "#C84B31";
13
- export const NOTIFICATION_FILTER_CATEGORIES = [
14
- {
15
- id: "announcements",
16
- label: "Announcements",
17
- types: ["announcement"]
18
- },
19
- {
20
- id: "messages",
21
- label: "Messages",
22
- types: ["message"]
23
- },
24
- {
25
- id: "comments-mentions",
26
- label: "Comments & Mentions",
27
- types: ["comment", "mention", "reply", "reaction"]
28
- },
29
- {
30
- id: "school-posts",
31
- label: "School Posts",
32
- types: ["school-post"]
33
- },
34
- {
35
- id: "system",
36
- label: "System",
37
- types: ["system"]
38
- },
39
- {
40
- id: "other",
41
- label: "Other",
42
- types: ["unknown"]
43
- }
44
- ];
45
- export const DEFAULT_NOTIFICATION_FILTERS = [
46
- { id: "all-types", label: "All types" },
47
- ...NOTIFICATION_FILTER_CATEGORIES
48
- ];
@@ -1,79 +0,0 @@
1
- export type NotificationType = 'announcement' | 'message' | 'comment' | 'mention' | 'reply' | 'reaction' | 'school-post' | 'system' | 'unknown';
2
- export type NotificationApiState = 'unread' | 'read' | 'dismissed';
3
- export interface INotificationApiActor {
4
- avatar_url?: string;
5
- first_name: string;
6
- last_name: string;
7
- }
8
- export interface INotificationApiRecord {
9
- id: number | string;
10
- source_record_type: string;
11
- title: string;
12
- summary?: string;
13
- actors?: INotificationApiActor[] | null;
14
- detail_link?: string | null;
15
- notification_state: NotificationApiState | string;
16
- created_at: string;
17
- }
18
- export interface INotificationsPagination {
19
- page: number;
20
- per_page: number;
21
- total_count: number;
22
- total_pages: number;
23
- }
24
- export interface INotificationsApiResponse {
25
- data: INotificationApiRecord[];
26
- errors: unknown[];
27
- warnings: unknown[];
28
- pagination: INotificationsPagination;
29
- }
30
- export interface INotificationActor {
31
- name: string;
32
- avatarUrl?: string;
33
- }
34
- export interface INotificationItem {
35
- id: string;
36
- type: NotificationType;
37
- actors: INotificationActor[];
38
- actionText: string;
39
- timestampLabel: string;
40
- /** ISO-8601 timestamp from the API — used to derive group labels and relative time. */
41
- createdAt?: string;
42
- contextLabel?: string;
43
- /** When false, the notification counts toward the bell badge and appears in the New tab. */
44
- dismissed?: boolean;
45
- /** Read receipt — announcement and message types only. */
46
- read?: boolean;
47
- /** Optional edge-case state chip shown at the bottom of the card. */
48
- stateLabel?: string;
49
- href?: string;
50
- groupCount?: number;
51
- /** @deprecated Use dismissed instead. Kept for backward compatibility. */
52
- unread?: boolean;
53
- }
54
- export interface INotificationGroup {
55
- id: string;
56
- label: string;
57
- notifications: INotificationItem[];
58
- }
59
- export interface INotificationTab {
60
- id: string;
61
- label: string;
62
- count?: number;
63
- /** When true, only in-badge notifications are shown for this tab. */
64
- unreadOnly?: boolean;
65
- }
66
- export interface INotificationFilter {
67
- id: string;
68
- label: string;
69
- count?: number;
70
- /** Notification types included in this filter. Omit or leave empty to include all types. */
71
- types?: NotificationType[];
72
- }
73
- export interface INotificationsPanelData {
74
- retentionLabel?: string;
75
- tabs: INotificationTab[];
76
- /** Optional — when omitted, filter pills are derived from notification results. */
77
- filters?: INotificationFilter[];
78
- groups: INotificationGroup[];
79
- }
File without changes