@apptegy/nuxt-navigation 0.1.111 → 1.0.0-alpha.1
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.
- package/dist/module.json +1 -1
- package/dist/module.mjs +3 -2
- package/dist/runtime/components/Nav/Header.vue +108 -321
- package/dist/runtime/components/Nav/Header.vue.d.ts +12 -39
- package/dist/runtime/components/Nav/OrgSelect.vue +8 -8
- package/dist/runtime/components/Nav/Sidebar.vue +118 -207
- package/dist/runtime/components/Nav/Sidebar.vue.d.ts +7 -15
- package/dist/runtime/components/Nav/SidebarItem.vue +19 -22
- package/dist/runtime/components/Nav/SidebarSection.vue +28 -35
- package/dist/runtime/components/Nav/SidebarSection.vue.d.ts +2 -2
- package/dist/runtime/components/Nav/SubMenuItem.vue +1 -1
- package/dist/runtime/types/index.d.ts +0 -1
- package/locale/en.json +1 -22
- package/package.json +25 -29
- package/dist/runtime/components/Nav/NotificationItem.vue +0 -337
- package/dist/runtime/components/Nav/NotificationItem.vue.d.ts +0 -12
- package/dist/runtime/components/Nav/NotificationsPanel.vue +0 -513
- package/dist/runtime/components/Nav/NotificationsPanel.vue.d.ts +0 -53
- package/dist/runtime/constants/notification-types.d.ts +0 -19
- package/dist/runtime/constants/notification-types.js +0 -48
- package/dist/runtime/types/notifications.d.ts +0 -79
- package/dist/runtime/types/notifications.js +0 -0
- package/dist/runtime/utils/notification-api.d.ts +0 -26
- package/dist/runtime/utils/notification-api.js +0 -84
- package/dist/runtime/utils/notification-dates.d.ts +0 -15
- package/dist/runtime/utils/notification-dates.js +0 -81
- package/dist/runtime/utils/notifications.d.ts +0 -21
- 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
|