diff --git a/src/Components/NotificationItem.vue b/src/Components/NotificationItem.vue
index 4cfc85060..fbce483d5 100644
--- a/src/Components/NotificationItem.vue
+++ b/src/Components/NotificationItem.vue
@@ -16,6 +16,27 @@
ignoreSeconds
:format="{ timeStyle: 'short', dateStyle: 'long' }"
:timestamp="timestamp" />
+
+
+
+
+
+
+ {{ t('notifications', '1 hour') }}
+
+
+
+ {{ t('notifications', '4 hours') }}
+
+
+
+ {{ t('notifications', 'Tomorrow') }}
+
+
@@ -23,7 +23,7 @@
@@ -32,10 +32,11 @@
:key="-2016"
:notification="fairUsePolicyNotification" />
+ @remove="onRemove(notification)"
+ @snooze="onSnooze" />
@@ -187,6 +188,9 @@ export default {
pushEndpoints: null,
open: false,
+
+ /** Map of notificationId → timestamp when the snooze expires */
+ snoozed: JSON.parse(localStorage.getItem('notifications:snoozed') ?? '{}'),
}
},
@@ -217,6 +221,11 @@ export default {
return ''
},
+
+ visibleNotifications() {
+ const now = Date.now()
+ return this.notifications.filter(n => (this.snoozed[n.notificationId] ?? 0) <= now)
+ },
},
mounted() {
@@ -342,11 +351,31 @@ export default {
})
},
- onRemove(index) {
- this.notifications.splice(index, 1)
+ onRemove(notification) {
+ const idx = this.notifications.findIndex(n => n.notificationId === notification.notificationId)
+ if (idx !== -1) {
+ this.notifications.splice(idx, 1)
+ }
setCurrentTabAsActive(this.tabId)
},
+ onSnooze({ notification, minutes }) {
+ const wakeAt = Date.now() + minutes * 60 * 1000
+ this.snoozed = { ...this.snoozed, [notification.notificationId]: wakeAt }
+ localStorage.setItem('notifications:snoozed', JSON.stringify(this.snoozed))
+ },
+
+ _clearExpiredSnooze() {
+ const now = Date.now()
+ const active = Object.fromEntries(
+ Object.entries(this.snoozed).filter(([, wakeAt]) => wakeAt > now),
+ )
+ if (Object.keys(active).length !== Object.keys(this.snoozed).length) {
+ this.snoozed = active
+ localStorage.setItem('notifications:snoozed', JSON.stringify(active))
+ }
+ },
+
/**
* Update the title to show * if there are new notifications
*
@@ -408,6 +437,8 @@ export default {
* Performs the AJAX request to retrieve the notifications
*/
async _fetch(force = false) {
+ this._clearExpiredSnooze()
+
if (this.notifications.length && this.notifications[0].notificationId > this.webNotificationsThresholdId) {
this.webNotificationsThresholdId = this.notifications[0].notificationId
}
diff --git a/src/styles/styles.scss b/src/styles/styles.scss
index 96524b4a9..40d889a1b 100644
--- a/src/styles/styles.scss
+++ b/src/styles/styles.scss
@@ -123,3 +123,8 @@ svg {
}
}
}
+
+// Snooze action menu — keep the clock button subtle and compact
+.notification-snooze-button {
+ margin-inline-end: 2px;
+}