From 0d6a9e8a647be860b10506aecaafb4ff0f10150f Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Sun, 13 Aug 2023 23:57:34 -0400
Subject: Display extra notifications on notifications column

---
 src/components/notifications/notifications.vue | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'src/components/notifications/notifications.vue')

diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 633efca6..d40c930a 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -54,6 +54,13 @@
           class="panel-body"
           role="feed"
         >
+          <div
+            v-if="showExtraNotifications"
+            role="listitem"
+            class="notification"
+          >
+            <extra-notifications />
+          </div>
           <div
             v-for="notification in notificationsToDisplay"
             :key="notification.id"
-- 
cgit v1.2.3-70-g09d2


From 50bad0fc68dee158e1681e599c7852550f5bef31 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Fri, 18 Aug 2023 21:07:48 -0400
Subject: Display unread visuals when there are unread extra notifications

---
 src/components/interactions/interactions.vue          |  1 +
 src/components/mobile_nav/mobile_nav.js               |  7 +++++--
 src/components/notifications/notifications.js         | 18 +++++++++++++++---
 src/components/notifications/notifications.vue        |  4 ++--
 src/services/notification_utils/notification_utils.js | 14 ++++++++++++++
 5 files changed, 37 insertions(+), 7 deletions(-)

(limited to 'src/components/notifications/notifications.vue')

diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue
index b7291c02..35d03562 100644
--- a/src/components/interactions/interactions.vue
+++ b/src/components/interactions/interactions.vue
@@ -39,6 +39,7 @@
     <Notifications
       ref="notifications"
       :no-heading="true"
+      :no-extra="true"
       :minimal-mode="true"
       :filter-mode="filterMode"
     />
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
index dad1f6aa..b5325116 100644
--- a/src/components/mobile_nav/mobile_nav.js
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -1,7 +1,10 @@
 import SideDrawer from '../side_drawer/side_drawer.vue'
 import Notifications from '../notifications/notifications.vue'
 import ConfirmModal from '../confirm_modal/confirm_modal.vue'
-import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
+import {
+  unseenNotificationsFromStore,
+  countExtraNotifications
+} from '../../services/notification_utils/notification_utils'
 import GestureService from '../../services/gesture_service/gesture_service'
 import NavigationPins from 'src/components/navigation/navigation_pins.vue'
 import { mapGetters } from 'vuex'
@@ -50,7 +53,7 @@ const MobileNav = {
       return unseenNotificationsFromStore(this.$store)
     },
     unseenNotificationsCount () {
-      return this.unseenNotifications.length
+      return this.unseenNotifications.length + countExtraNotifications(this.$store)
     },
     hideSitename () { return this.$store.state.instance.hideSitename },
     sitename () { return this.$store.state.instance.name },
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 09ebc943..571df0f1 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -7,7 +7,8 @@ import notificationsFetcher from '../../services/notifications_fetcher/notificat
 import {
   notificationsFromStore,
   filteredNotificationsFromStore,
-  unseenNotificationsFromStore
+  unseenNotificationsFromStore,
+  countExtraNotifications
 } from '../../services/notification_utils/notification_utils.js'
 import FaviconService from '../../services/favicon_service/favicon_service.js'
 import { library } from '@fortawesome/fontawesome-svg-core'
@@ -33,6 +34,11 @@ const Notifications = {
     minimalMode: Boolean,
     // Custom filter mode, an array of strings, possible values 'mention', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline
     filterMode: Array,
+    // Do not show extra notifications
+    noExtra: {
+      type: Boolean,
+      default: false
+    },
     // Disable teleporting (i.e. for /users/user/notifications)
     disableTeleport: Boolean
   },
@@ -67,11 +73,17 @@ const Notifications = {
     filteredNotifications () {
       return filteredNotificationsFromStore(this.$store, this.filterMode)
     },
+    unseenCountBadgeText () {
+      return `${this.unseenCount ? this.unseenCount : ''}${this.extraNotificationsCount ? '*' : ''}`
+    },
     unseenCount () {
       return this.unseenNotifications.length
     },
+    extraNotificationsCount () {
+      return countExtraNotifications(this.$store)
+    },
     unseenCountTitle () {
-      return this.unseenCount + (this.unreadChatCount) + this.unreadAnnouncementCount
+      return this.unseenNotifications.length + (this.unreadChatCount) + this.unreadAnnouncementCount
     },
     loading () {
       return this.$store.state.statuses.notifications.loading
@@ -97,7 +109,7 @@ const Notifications = {
     },
     noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
     showExtraNotifications () {
-      return !this.noHeading
+      return !this.noExtra
     },
     ...mapGetters(['unreadChatCount', 'unreadAnnouncementCount'])
   },
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index d40c930a..999f8e9c 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -17,9 +17,9 @@
           <div class="title">
             {{ $t('notifications.notifications') }}
             <span
-              v-if="unseenCount"
+              v-if="unseenCountBadgeText"
               class="badge badge-notification unseen-count"
-            >{{ unseenCount }}</span>
+            >{{ unseenCountBadgeText }}</span>
           </div>
           <div
             v-if="showScrollTop"
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index 0f8b9b02..815e792d 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -124,3 +124,17 @@ export const prepareNotificationObject = (notification, i18n) => {
 
   return notifObj
 }
+
+export const countExtraNotifications = (store) => {
+  const mergedConfig = store.getters.mergedConfig
+
+  if (!mergedConfig.showExtraNotifications) {
+    return 0
+  }
+
+  return [
+    mergedConfig.showChatsInExtraNotifications ? store.getters.unreadChatCount : 0,
+    mergedConfig.showAnnouncementsInExtraNotifications ? store.getters.unreadAnnouncementCount : 0,
+    mergedConfig.showFollowRequestsInExtraNotifications ? store.getters.followRequestCount : 0
+  ].reduce((a, c) => a + c, 0)
+}
-- 
cgit v1.2.3-70-g09d2


From ec2937ec1f3b0ae153f79604eb35b57ffe0f9af2 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Nov 2023 17:29:25 +0200
Subject: add options for marking single notification as read

---
 src/components/notification/notification.js        |  6 ++++++
 src/components/notification/notification.vue       |  1 +
 src/components/notifications/notifications.js      | 20 ++++++++++++++++++++
 src/components/notifications/notifications.vue     |  6 +++++-
 src/components/status/status.js                    |  3 +++
 src/components/status/status.vue                   |  3 +++
 src/modules/statuses.js                            |  8 ++++++++
 .../desktop_notification_utils.js                  | 22 +++++++++++++++++++++-
 .../notification_utils/notification_utils.js       |  5 +++--
 src/services/sw/sw.js                              |  9 +++++++++
 src/sw.js                                          |  6 ++++++
 11 files changed, 85 insertions(+), 4 deletions(-)

(limited to 'src/components/notifications/notifications.vue')

diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index 420db4f0..0e938c42 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -50,6 +50,7 @@ const Notification = {
     }
   },
   props: ['notification'],
+  emits: ['interacted'],
   components: {
     StatusContent,
     UserAvatar,
@@ -72,6 +73,9 @@ const Notification = {
     getUser (notification) {
       return this.$store.state.users.usersObject[notification.from_profile.id]
     },
+    interacted () {
+      this.$emit('interacted')
+    },
     toggleMute () {
       this.unmuted = !this.unmuted
     },
@@ -95,6 +99,7 @@ const Notification = {
       }
     },
     doApprove () {
+      this.$emit('interacted')
       this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
       this.$store.dispatch('removeFollowRequest', this.user)
       this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id })
@@ -114,6 +119,7 @@ const Notification = {
       }
     },
     doDeny () {
+      this.$emit('interacted')
       this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
         .then(() => {
           this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id })
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 6b3315f9..01ad395f 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -6,6 +6,7 @@
       class="Notification"
       :compact="true"
       :statusoid="notification.status"
+      @interacted="interacted"
     />
   </article>
   <article v-else>
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 571df0f1..4cbe8093 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -159,6 +159,26 @@ const Notifications = {
     updateScrollPosition () {
       this.showScrollTop = this.$refs.root.offsetTop < this.scrollerRef.scrollTop
     },
+    notificationClicked (notification) {
+      const { type, id, seen } = notification
+      if (!seen) {
+        switch (type) {
+          case 'mention':
+          case 'pleroma:report':
+          case 'follow_request':
+            break
+          default:
+            this.markOneAsSeen(id)
+        }
+      }
+    },
+    notificationInteracted (notification) {
+      const { id, seen } = notification
+      if (!seen) this.markOneAsSeen(id)
+    },
+    markOneAsSeen (id) {
+      this.$store.dispatch('markSingleNotificationAsSeen', { id })
+    },
     markAsSeen () {
       this.$store.dispatch('markNotificationsAsSeen')
       this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 999f8e9c..27ae23cf 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -67,9 +67,13 @@
             role="listitem"
             class="notification"
             :class="{unseen: !minimalMode && !notification.seen}"
+            @click="e => notificationClicked(notification)"
           >
             <div class="notification-overlay" />
-            <notification :notification="notification" />
+            <notification
+              :notification="notification"
+              @interacted="e => notificationInteracted(notification)"
+            />
           </div>
         </div>
         <div class="panel-footer">
diff --git a/src/components/status/status.js b/src/components/status/status.js
index a339694d..129929a3 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -154,6 +154,7 @@ const Status = {
     'controlledSetMediaPlaying',
     'dive'
   ],
+  emits: ['interacted'],
   data () {
     return {
       uncontrolledReplying: false,
@@ -442,9 +443,11 @@ const Status = {
       this.error = error
     },
     clearError () {
+      this.$emit('interacted')
       this.error = undefined
     },
     toggleReplying () {
+      this.$emit('interacted')
       controlledOrUncontrolledToggle(this, 'replying')
     },
     gotoOriginal (id) {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index d66de562..a8477fa3 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -508,14 +508,17 @@
               :visibility="status.visibility"
               :logged-in="loggedIn"
               :status="status"
+              @click="$emit('interacted')"
             />
             <favorite-button
               :logged-in="loggedIn"
               :status="status"
+              @click="$emit('interacted')"
             />
             <ReactButton
               v-if="loggedIn"
               :status="status"
+              @click="$emit('interacted')"
             />
             <extra-buttons
               :status="status"
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index 9b4cd175..6e331d16 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -17,6 +17,10 @@ import {
   isValidNotification,
   maybeShowNotification
 } from '../services/notification_utils/notification_utils.js'
+import {
+  closeDesktopNotification,
+  closeAllDesktopNotifications
+} from '../services/desktop_notification_utils/desktop_notification_utils.js'
 import apiService from '../services/api/api.service.js'
 
 const emptyTl = (userId = 0) => ({
@@ -726,6 +730,8 @@ const statuses = {
       apiService.markNotificationsAsSeen({
         id: rootState.statuses.notifications.maxId,
         credentials: rootState.users.currentUser.credentials
+      }).then(() => {
+        closeAllDesktopNotifications(rootState)
       })
     },
     markSingleNotificationAsSeen ({ rootState, commit }, { id }) {
@@ -734,6 +740,8 @@ const statuses = {
         single: true,
         id,
         credentials: rootState.users.currentUser.credentials
+      }).then(() => {
+        closeDesktopNotification(rootState, id)
       })
     },
     dismissNotificationLocal ({ rootState, commit }, { id }) {
diff --git a/src/services/desktop_notification_utils/desktop_notification_utils.js b/src/services/desktop_notification_utils/desktop_notification_utils.js
index eb58f39b..dbca4173 100644
--- a/src/services/desktop_notification_utils/desktop_notification_utils.js
+++ b/src/services/desktop_notification_utils/desktop_notification_utils.js
@@ -1,4 +1,8 @@
-import { showDesktopNotification as swDesktopNotification, isSWSupported } from '../sw/sw.js'
+import {
+  showDesktopNotification as swDesktopNotification,
+  closeDesktopNotification as swCloseDesktopNotification,
+  isSWSupported
+} from '../sw/sw.js'
 const state = { failCreateNotif: false }
 
 export const showDesktopNotification = (rootState, desktopNotificationOpts) => {
@@ -16,3 +20,19 @@ export const showDesktopNotification = (rootState, desktopNotificationOpts) => {
     }
   }
 }
+
+export const closeDesktopNotification = (rootState, id) => {
+  if (!('Notification' in window && window.Notification.permission === 'granted')) return
+
+  if (isSWSupported()) {
+    swCloseDesktopNotification({ id })
+  }
+}
+
+export const closeAllDesktopNotifications = (rootState) => {
+  if (!('Notification' in window && window.Notification.permission === 'granted')) return
+
+  if (isSWSupported()) {
+    swCloseDesktopNotification()
+  }
+}
diff --git a/src/services/notification_utils/notification_utils.js b/src/services/notification_utils/notification_utils.js
index fbd5c014..22ef6098 100644
--- a/src/services/notification_utils/notification_utils.js
+++ b/src/services/notification_utils/notification_utils.js
@@ -1,6 +1,7 @@
 import { filter, sortBy, includes } from 'lodash'
 import { muteWordHits } from '../status_parser/status_parser.js'
 import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
+
 import FaviconService from 'src/services/favicon_service/favicon_service.js'
 
 let cachedBadgeUrl = null
@@ -68,8 +69,8 @@ export const maybeShowNotification = (store, notification) => {
 
 export const filteredNotificationsFromStore = (store, types) => {
   // map is just to clone the array since sort mutates it and it causes some issues
-  let sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
-  sortedNotifications = sortBy(sortedNotifications, 'seen')
+  const sortedNotifications = notificationsFromStore(store).map(_ => _).sort(sortById)
+  // TODO implement sorting elsewhere and make it optional
   return sortedNotifications.filter(
     (notification) => (types || visibleTypes(store)).includes(notification.type)
   )
diff --git a/src/services/sw/sw.js b/src/services/sw/sw.js
index 2875d36e..d4ae8f4f 100644
--- a/src/services/sw/sw.js
+++ b/src/services/sw/sw.js
@@ -96,6 +96,15 @@ export async function showDesktopNotification (content) {
   sw.postMessage({ type: 'desktopNotification', content })
 }
 
+export async function closeDesktopNotification ({ id }) {
+  const { active: sw } = await window.navigator.serviceWorker.getRegistration()
+  if (id >= 0) {
+    sw.postMessage({ type: 'desktopNotificationClose', content: { id } })
+  } else {
+    sw.postMessage({ type: 'desktopNotificationClose', content: { all: true } })
+  }
+}
+
 export async function updateFocus () {
   const { active: sw } = await window.navigator.serviceWorker.getRegistration()
   sw.postMessage({ type: 'updateFocus' })
diff --git a/src/sw.js b/src/sw.js
index b95d56a4..43c1c2e2 100644
--- a/src/sw.js
+++ b/src/sw.js
@@ -66,6 +66,12 @@ self.addEventListener('message', async (event) => {
     self.registration.showNotification(title, rest)
   }
 
+  if (type === 'desktopNotificationClose') {
+    const { id, all } = content
+    const search = all ? null : { tag: id }
+    self.registration.getNotifications(search).forEach(n => n.close())
+  }
+
   if (type === 'updateFocus') {
     state.lastFocused = event.source.id
 
-- 
cgit v1.2.3-70-g09d2


From e3ee3eaccae6a9ece674d7d76db8e67da499d6c3 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 19 Nov 2023 15:24:34 +0200
Subject: added some settings for notifications

---
 src/components/mobile_nav/mobile_nav.js            |  9 ++++++--
 src/components/mobile_nav/mobile_nav.vue           | 11 ++++++++++
 src/components/notifications/notifications.js      | 25 +++++++++++++++++++---
 src/components/notifications/notifications.vue     |  2 +-
 .../settings_modal/tabs/notifications_tab.vue      | 23 ++++++++++++++++++++
 src/i18n/en.json                                   |  5 +++++
 src/modules/config.js                              |  5 ++++-
 src/modules/instance.js                            |  3 +++
 8 files changed, 76 insertions(+), 7 deletions(-)

(limited to 'src/components/notifications/notifications.vue')

diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
index b5325116..6f4e35e5 100644
--- a/src/components/mobile_nav/mobile_nav.js
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -14,7 +14,8 @@ import {
   faBell,
   faBars,
   faArrowUp,
-  faMinus
+  faMinus,
+  faCheckDouble
 } from '@fortawesome/free-solid-svg-icons'
 
 library.add(
@@ -22,7 +23,8 @@ library.add(
   faBell,
   faBars,
   faArrowUp,
-  faMinus
+  faMinus,
+  faCheckDouble
 )
 
 const MobileNav = {
@@ -67,6 +69,9 @@ const MobileNav = {
     shouldConfirmLogout () {
       return this.$store.getters.mergedConfig.modalOnLogout
     },
+    closingDrawerMarksAsSeen () {
+      return this.$store.getters.mergedConfig.closingDrawerMarksAsSeen
+    },
     ...mapGetters(['unreadChatCount'])
   },
   methods: {
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index c2746abe..ecd8290a 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -66,6 +66,17 @@
             />
           </FALayers>
         </button>
+        <button
+          v-if="!closingDrawerMarksAsSeen"
+          class="button-unstyled mobile-nav-button"
+          :title="$t('nav.mobile_notifications_close')"
+          @click.stop.prevent="markNotificationsAsSeen()"
+        >
+          <FAIcon
+            class="fa-scale-110 fa-old-padding"
+            icon="check-double"
+          />
+        </button>
         <button
           class="button-unstyled mobile-nav-button"
           :title="$t('nav.mobile_notifications_close')"
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index a210e19d..00d3a511 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -21,6 +21,7 @@ library.add(
 )
 
 const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30
+const ACTIONABLE_NOTIFICATION_TYPES = new Set(['mention', 'pleroma:report', 'follow_request'])
 
 const Notifications = {
   components: {
@@ -71,14 +72,26 @@ const Notifications = {
       return unseenNotificationsFromStore(this.$store)
     },
     filteredNotifications () {
-      return filteredNotificationsFromStore(this.$store, this.filterMode)
+      if (this.unseenAtTop) {
+        return [
+          ...filteredNotificationsFromStore(this.$store).filter(n => this.shouldShowUnseen(n)),
+          ...filteredNotificationsFromStore(this.$store).filter(n => !this.shouldShowUnseen(n))
+        ]
+      } else {
+        return filteredNotificationsFromStore(this.$store, this.filterMode)
+      }
     },
     unseenCountBadgeText () {
       return `${this.unseenCount ? this.unseenCount : ''}${this.extraNotificationsCount ? '*' : ''}`
     },
     unseenCount () {
-      return this.unseenNotifications.length
+      if (this.ignoreInactionableSeen) {
+        return this.unseenNotifications.filter(n => ACTIONABLE_NOTIFICATION_TYPES.has(n.type)).length
+      } else {
+        return this.unseenNotifications.length
+      }
     },
+    ignoreInactionableSeen () { return this.$store.getters.mergedConfig.ignoreInactionableSeen },
     extraNotificationsCount () {
       return countExtraNotifications(this.$store)
     },
@@ -108,6 +121,7 @@ const Notifications = {
       return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount)
     },
     noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
+    unseenAtTop () { return this.$store.getters.mergedConfig.unseenAtTop },
     showExtraNotifications () {
       return !this.noExtra
     },
@@ -154,11 +168,16 @@ const Notifications = {
     scrollToTop () {
       const scrollable = this.scrollerRef
       scrollable.scrollTo({ top: this.$refs.root.offsetTop })
-      // this.$refs.root.scrollIntoView({ behavior: 'smooth', block: 'start' })
     },
     updateScrollPosition () {
       this.showScrollTop = this.$refs.root.offsetTop < this.scrollerRef.scrollTop
     },
+    shouldShowUnseen (notification) {
+      if (notification.seen) return false
+
+      const actionable = ACTIONABLE_NOTIFICATION_TYPES.has(notification.type)
+      return this.ignoreInactionableSeen ? actionable : true
+    },
     /* "Interacted" really refers to "actionable" notifications that require user input,
      * everything else (likes/repeats/reacts) cannot be acted and therefore we just clear
      * the "seen" status upon any clicks on them
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 27ae23cf..a0025182 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -66,7 +66,7 @@
             :key="notification.id"
             role="listitem"
             class="notification"
-            :class="{unseen: !minimalMode && !notification.seen}"
+            :class="{unseen: !minimalMode && shouldShowUnseen(notification)}"
             @click="e => notificationClicked(notification)"
           >
             <div class="notification-overlay" />
diff --git a/src/components/settings_modal/tabs/notifications_tab.vue b/src/components/settings_modal/tabs/notifications_tab.vue
index 4dfba444..fcee85a0 100644
--- a/src/components/settings_modal/tabs/notifications_tab.vue
+++ b/src/components/settings_modal/tabs/notifications_tab.vue
@@ -1,5 +1,28 @@
 <template>
   <div :label="$t('settings.notifications')">
+    <div class="setting-item">
+      <h2>{{ $t('settings.notification_setting_annoyance') }}</h2>
+      <ul class="setting-list">
+        <li>
+          <BooleanSetting path="closingDrawerMarksAsSeen">
+            {{ $t('settings.notification_setting_drawer_marks_as_seen') }}
+          </BooleanSetting>
+        </li>
+        <li>
+          <BooleanSetting path="ignoreInactionableSeen">
+            {{ $t('settings.notification_setting_ignore_inactionable_seen') }}
+          </BooleanSetting>
+          <p>
+            {{ $t('settings.notification_setting_ignore_inactionable_seen_tip') }}
+          </p>
+        </li>
+        <li>
+          <BooleanSetting path="unseenAtTop">
+            {{ $t('settings.notification_setting_unseen_at_top') }}
+          </BooleanSetting>
+        </li>
+      </ul>
+    </div>
     <div class="setting-item">
       <h2>{{ $t('settings.notification_setting_filters') }}</h2>
       <ul class="setting-list">
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 034022cb..b31793cb 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -688,6 +688,11 @@
     "greentext": "Meme arrows",
     "show_yous": "Show (You)s",
     "notifications": "Notifications",
+    "notification_setting_annoyance": "Annoyance",
+    "notification_setting_drawer_marks_as_seen": "Closing drawer (mobile) marks all notifications as read",
+    "notification_setting_ignore_inactionable_seen": "Ignore read state of inactionable notifications (likes, repeats etc)",
+    "notification_setting_ignore_inactionable_seen_tip": "This will not actually mark those notifications as read, and you'll still get desktop notifications about them if you chose so",
+    "notification_setting_unseen_at_top": "Show unread notifications above others",
     "notification_setting_filters": "Filters",
     "notification_setting_block_from_strangers": "Block notifications from users who you do not follow",
     "notification_setting_privacy": "Privacy",
diff --git a/src/modules/config.js b/src/modules/config.js
index 05c15998..a3f7bcaf 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -127,7 +127,10 @@ export const defaultState = {
   showAnnouncementsInExtraNotifications: undefined, // instance default
   showFollowRequestsInExtraNotifications: undefined, // instance default
   maxDepthInThread: undefined, // instance default
-  autocompleteSelect: undefined // instance default
+  autocompleteSelect: undefined, // instance default
+  closingDrawerMarksAsSeen: undefined, // instance default
+  unseenAtTop: undefined, // instance default
+  ignoreInactionableSeen: undefined // instance default
 }
 
 // caching the instance default properties
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 034348ff..3022a41a 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -110,6 +110,9 @@ const defaultState = {
   showFollowRequestsInExtraNotifications: true,
   maxDepthInThread: 6,
   autocompleteSelect: false,
+  closingDrawerMarksAsSeen: true,
+  unseenAtTop: false,
+  ignoreInactionableSeen: false,
 
   // Nasty stuff
   customEmoji: [],
-- 
cgit v1.2.3-70-g09d2


From 7c77809ff9a4d365ec17fb2ed43f3795382940a9 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 16 Feb 2024 00:29:16 +0200
Subject: badge, alert(dot) improvements

---
 src/App.scss                                       | 54 +++++++---------------
 src/components/alert.style.js                      |  9 +++-
 src/components/badge.style.js                      |  3 +-
 src/components/chat/chat.vue                       |  2 +-
 src/components/chat_list_item/chat_list_item.vue   |  2 +-
 src/components/menu_item.style.js                  |  3 +-
 src/components/mobile_nav/mobile_nav.vue           | 25 ++--------
 src/components/navigation/navigation_entry.vue     |  6 ++-
 src/components/navigation/navigation_pins.vue      | 13 +-----
 src/components/notifications/notifications.vue     |  2 +-
 .../settings_modal/tabs/theme_tab/preview.vue      |  2 +-
 src/components/side_drawer/side_drawer.vue         |  6 +--
 src/components/timeline/timeline.scss              | 11 -----
 src/services/style_setter/style_setter.js          |  3 --
 14 files changed, 44 insertions(+), 97 deletions(-)

(limited to 'src/components/notifications/notifications.vue')

diff --git a/src/App.scss b/src/App.scss
index 6080b0e5..0af05a54 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -634,11 +634,21 @@ option {
   overflow: hidden;
   text-overflow: ellipsis;
 
-  &.badge-notification {
-    background-color: $fallback--cRed;
-    background-color: var(--badgeNotification, $fallback--cRed);
-    color: white;
-    color: var(--badgeNotificationText, white);
+  &.-dot {
+    border-radius: 100%;
+    min-height: 8px;
+    max-height: 8px;
+    min-width: 8px;
+    max-width: 8px;
+    padding: 0;
+    line-height: 0;
+    margin: 0;
+    font-size: 0;
+    position: absolute;
+    left: calc(50% - 4px);
+    top: calc(50% - 4px);
+    margin-left: 6px;
+    margin-top: -6px;
   }
 }
 
@@ -646,39 +656,7 @@ option {
   margin: 0 0.35em;
   padding: 0 0.25em;
   border-radius: var(--roundness);
-
-  &.error {
-    background-color: $fallback--alertError;
-    background-color: var(--alertError, $fallback--alertError);
-    color: $fallback--text;
-    color: var(--alertErrorText, $fallback--text);
-
-    .panel-heading & {
-      color: $fallback--text;
-      color: var(--alertErrorPanelText, $fallback--text);
-    }
-  }
-
-  &.warning {
-    background-color: $fallback--alertWarning;
-    background-color: var(--alertWarning, $fallback--alertWarning);
-    color: $fallback--text;
-    color: var(--alertWarningText, $fallback--text);
-
-    .panel-heading & {
-      color: $fallback--text;
-      color: var(--alertWarningPanelText, $fallback--text);
-    }
-  }
-
-  &.success {
-    background-color: var(--alertSuccess, $fallback--alertWarning);
-    color: var(--alertSuccessText, $fallback--text);
-
-    .panel-heading & {
-      color: var(--alertSuccessPanelText, $fallback--text);
-    }
-  }
+  border: 1px solid var(--border);
 }
 
 .faint {
diff --git a/src/components/alert.style.js b/src/components/alert.style.js
index 081031d7..5881e833 100644
--- a/src/components/alert.style.js
+++ b/src/components/alert.style.js
@@ -17,9 +17,16 @@ export default {
     {
       directives: {
         background: '--text',
-        opacity: 0.8
+        opacity: 0.5
       }
     },
+    {
+      parent: {
+        component: 'Alert'
+      },
+      component: 'Border',
+      textColor: '--parent'
+    },
     {
       variant: 'error',
       directives: {
diff --git a/src/components/badge.style.js b/src/components/badge.style.js
index 3ac7d8c0..37833cdb 100644
--- a/src/components/badge.style.js
+++ b/src/components/badge.style.js
@@ -6,8 +6,7 @@ export default {
     'Icon'
   ],
   variants: {
-    normal: '.neutral',
-    notification: '.notification'
+    notification: '.-notification'
   },
   defaultRules: [
     {
diff --git a/src/components/chat/chat.vue b/src/components/chat/chat.vue
index b1e5468c..fc94cc71 100644
--- a/src/components/chat/chat.vue
+++ b/src/components/chat/chat.vue
@@ -61,7 +61,7 @@
               <FAIcon icon="chevron-down" />
               <div
                 v-if="newMessageCount"
-                class="badge badge-notification unread-chat-count unread-message-count"
+                class="badge -notification unread-chat-count unread-message-count"
               >
                 {{ newMessageCount }}
               </div>
diff --git a/src/components/chat_list_item/chat_list_item.vue b/src/components/chat_list_item/chat_list_item.vue
index 69ad609b..cbae2d11 100644
--- a/src/components/chat_list_item/chat_list_item.vue
+++ b/src/components/chat_list_item/chat_list_item.vue
@@ -36,7 +36,7 @@
         />
         <div
           v-if="chat.unread > 0"
-          class="badge badge-notification unread-chat-count"
+          class="badge -notification unread-chat-count"
         >
           {{ chat.unread }}
         </div>
diff --git a/src/components/menu_item.style.js b/src/components/menu_item.style.js
index 6475395a..3c70bd9f 100644
--- a/src/components/menu_item.style.js
+++ b/src/components/menu_item.style.js
@@ -6,7 +6,8 @@ export default {
     'Icon',
     'Input',
     'Border',
-    'ButtonUnstyled'
+    'ButtonUnstyled',
+    'Badge'
   ],
   states: {
     hover: ':hover',
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index 489f3866..2e7590b9 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -20,7 +20,7 @@
           />
           <div
             v-if="(unreadChatCount && !chatsPinned) || unreadAnnouncementCount"
-            class="badge alert-dot"
+            class="badge -dot -notification"
           />
         </button>
         <NavigationPins class="pins" />
@@ -37,14 +37,14 @@
           />
           <div
             v-if="unseenNotificationsCount"
-            class="badge alert-dot"
+            class="badge -dot -notification"
           />
         </button>
       </div>
     </nav>
     <aside
       v-if="currentUser"
-      class="mobile-notifications-drawer"
+      class="panel mobile-notifications-drawer"
       :class="{ '-closed': !notificationsOpen }"
       @touchstart.stop="notificationsTouchStart"
       @touchmove.stop="notificationsTouchMove"
@@ -54,7 +54,7 @@
           {{ $t('notifications.notifications') }}
           <span
             v-if="unseenCountBadgeText"
-            class="badge badge-notification unseen-count"
+            class="badge -notification unseen-count"
           >{{ unseenCountBadgeText }}</span>
         </span>
         <span class="spacer" />
@@ -165,19 +165,6 @@
     display: flex;
   }
 
-  .alert-dot {
-    border-radius: 100%;
-    height: 8px;
-    width: 8px;
-    position: absolute;
-    left: calc(50% - 4px);
-    top: calc(50% - 4px);
-    margin-left: 6px;
-    margin-top: -6px;
-    background-color: $fallback--cRed;
-    background-color: var(--badgeNotification, $fallback--cRed);
-  }
-
   .mobile-notifications-drawer {
     width: 100%;
     height: 100vh;
@@ -238,10 +225,6 @@
     height: calc(100vh - var(--navbar-height));
     overflow-x: hidden;
     overflow-y: scroll;
-    color: $fallback--text;
-    color: var(--text, $fallback--text);
-    background-color: $fallback--bg;
-    background-color: var(--bg, $fallback--bg);
 
     .notifications {
       padding: 0;
diff --git a/src/components/navigation/navigation_entry.vue b/src/components/navigation/navigation_entry.vue
index ed805944..1189f76d 100644
--- a/src/components/navigation/navigation_entry.vue
+++ b/src/components/navigation/navigation_entry.vue
@@ -34,7 +34,7 @@
       <slot />
       <div
         v-if="item.badgeGetter && getters[item.badgeGetter]"
-        class="badge badge-notification"
+        class="badge -notification"
       >
         {{ getters[item.badgeGetter] }}
       </div>
@@ -100,5 +100,9 @@
       margin-right: -0.8em;
     }
   }
+
+  .badge {
+     margin: 0 0.8em;
+  }
 }
 </style>
diff --git a/src/components/navigation/navigation_pins.vue b/src/components/navigation/navigation_pins.vue
index 48a4dcbd..931d5325 100644
--- a/src/components/navigation/navigation_pins.vue
+++ b/src/components/navigation/navigation_pins.vue
@@ -19,7 +19,7 @@
       >{{ item.iconLetter }}</span>
       <div
         v-if="item.badgeGetter && getters[item.badgeGetter]"
-        class="badge alert-dot"
+        class="badge -dot -notification"
       />
     </router-link>
   </span>
@@ -36,17 +36,6 @@
   overflow: hidden;
   height: 100%;
 
-  .alert-dot {
-    border-radius: 100%;
-    height: 0.5em;
-    width: 0.5em;
-    position: absolute;
-    right: calc(50% - 0.75em);
-    top: calc(50% - 0.5em);
-    background-color: $fallback--cRed;
-    background-color: var(--badgeNotification, $fallback--cRed);
-  }
-
   .pinned-item {
     position: relative;
     flex: 1 0 3em;
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index a0025182..eb128450 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -18,7 +18,7 @@
             {{ $t('notifications.notifications') }}
             <span
               v-if="unseenCountBadgeText"
-              class="badge badge-notification unseen-count"
+              class="badge -notification unseen-count"
             >{{ unseenCountBadgeText }}</span>
           </div>
           <div
diff --git a/src/components/settings_modal/tabs/theme_tab/preview.vue b/src/components/settings_modal/tabs/theme_tab/preview.vue
index 5230f3e9..4054a440 100644
--- a/src/components/settings_modal/tabs/theme_tab/preview.vue
+++ b/src/components/settings_modal/tabs/theme_tab/preview.vue
@@ -5,7 +5,7 @@
       <div class="panel-heading">
         <div class="title">
           {{ $t('settings.style.preview.header') }}
-          <span class="badge badge-notification">
+          <span class="badge -notification">
             99
           </span>
         </div>
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index 09588767..1c6e5802 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -82,7 +82,7 @@
             /> {{ $t("nav.chats") }}
             <span
               v-if="unreadChatCount"
-              class="badge badge-notification"
+              class="badge -notification"
             >
               {{ unreadChatCount }}
             </span>
@@ -111,7 +111,7 @@
             /> {{ $t("nav.friend_requests") }}
             <span
               v-if="followRequestCount > 0"
-              class="badge badge-notification"
+              class="badge -notification"
             >
               {{ followRequestCount }}
             </span>
@@ -205,7 +205,7 @@
             /> {{ $t("nav.announcements") }}
             <span
               v-if="unreadAnnouncementCount"
-              class="badge badge-notification"
+              class="badge -notification"
             >
               {{ unreadAnnouncementCount }}
             </span>
diff --git a/src/components/timeline/timeline.scss b/src/components/timeline/timeline.scss
index 64c7de76..7f886dc3 100644
--- a/src/components/timeline/timeline.scss
+++ b/src/components/timeline/timeline.scss
@@ -1,17 +1,6 @@
 @import "../../variables";
 
 .Timeline {
-  .alert-dot {
-    border-radius: 100%;
-    height: 8px;
-    width: 8px;
-    position: absolute;
-    left: calc(50% - 4px);
-    top: calc(50% - 4px);
-    margin-left: 6px;
-    margin-top: -6px;
-  }
-
   .alert-badge {
     font-size: 0.75em;
     line-height: 1;
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index f9608680..3e420017 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -24,9 +24,6 @@ export const applyTheme = (input) => {
   const styleSheet = styleEl.sheet
 
   styleSheet.toString()
-  // styleSheet.insertRule(`:root { ${rules.radii} }`, 'index-max')
-  // styleSheet.insertRule(`:root { ${rules.colors} }`, 'index-max')
-  // styleSheet.insertRule(`:root { ${rules.shadows} }`, 'index-max')
   styleSheet.insertRule(`:root { ${rules.fonts} }`, 'index-max')
   themes3.css(themes3.eager).forEach(rule => {
     styleSheet.insertRule(rule, 'index-max')
-- 
cgit v1.2.3-70-g09d2


From 73f6ecb21e9a705caac0d1ce6b38b3aa75e4345b Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 29 Feb 2024 18:07:15 +0200
Subject: clean up some variables, fixing search footer

---
 src/components/lists_card/lists_card.vue           | 16 +------------
 src/components/notifications/notifications.vue     |  2 +-
 src/components/search/search.vue                   | 26 +++++-----------------
 .../user_list_popover/user_list_popover.vue        |  2 --
 4 files changed, 8 insertions(+), 38 deletions(-)

(limited to 'src/components/notifications/notifications.vue')

diff --git a/src/components/lists_card/lists_card.vue b/src/components/lists_card/lists_card.vue
index 925da3a5..a5dc6371 100644
--- a/src/components/lists_card/lists_card.vue
+++ b/src/components/lists_card/lists_card.vue
@@ -21,8 +21,6 @@
 <script src="./lists_card.js"></script>
 
 <style lang="scss">
-@import "../../variables";
-
 .list-card {
   display: flex;
 }
@@ -35,18 +33,6 @@
 .button-list-edit {
   margin: 0;
   padding: 1em;
-  color: $fallback--link;
-  color: var(--link, $fallback--link);
-
-  &:hover {
-    background-color: $fallback--lightBg;
-    background-color: var(--selectedMenu, $fallback--lightBg);
-    color: $fallback--link;
-    color: var(--selectedMenuText, $fallback--link);
-
-    --faint: var(--selectedMenuFaintText, $fallback--faint);
-    --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
-    --lightText: var(--selectedMenuLightText, $fallback--lightText);
-  }
+  color: var(--link);
 }
 </style>
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index eb128450..87e7b68d 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -85,7 +85,7 @@
           </div>
           <button
             v-else-if="!loading"
-            class="button-unstyled -link -fullwidth"
+            class="button-unstyled -link text-center"
             @click.prevent="fetchOlderNotifications()"
           >
             <div class="new-status-notification text-center">
diff --git a/src/components/search/search.vue b/src/components/search/search.vue
index bab91f3f..643c2cad 100644
--- a/src/components/search/search.vue
+++ b/src/components/search/search.vue
@@ -67,7 +67,7 @@
         />
         <button
           v-if="!loading && loaded && lastStatusFetchCount > 0"
-          class="more-statuses-button button-unstyled -link -fullwidth"
+          class="more-statuses-button button-unstyled -link"
           @click.prevent="search(searchTerm, 'statuses')"
         >
           <div class="new-status-notification text-center">
@@ -148,11 +148,8 @@
 <script src="./search.js"></script>
 
 <style lang="scss">
-@import "../../variables";
-
 .search-result-heading {
-  color: $fallback--faint;
-  color: var(--faint, $fallback--faint);
+  color: var(--faint);
   padding: 0.75rem;
   text-align: center;
 }
@@ -171,17 +168,7 @@
 .search-result {
   box-sizing: border-box;
   border-bottom: 1px solid;
-  border-color: $fallback--border;
-  border-color: var(--border, $fallback--border);
-}
-
-.search-result-footer {
-  border-width: 1px 0 0;
-  border-style: solid;
-  border-color: var(--border, $fallback--border);
-  padding: 10px;
-  background-color: $fallback--fg;
-  background-color: var(--panel, $fallback--fg);
+  border-color: var(--border);
 }
 
 .search-input-container {
@@ -212,8 +199,7 @@
 
   .hashtag {
     flex: 1 1 auto;
-    color: $fallback--text;
-    color: var(--text, $fallback--text);
+    color: var(--text);
     overflow: hidden;
     text-overflow: ellipsis;
     white-space: nowrap;
@@ -226,14 +212,14 @@
     line-height: 2.25rem;
     font-weight: 500;
     text-align: center;
-    color: $fallback--text;
-    color: var(--text, $fallback--text);
+    color: var(--text);
   }
 }
 
 .more-statuses-button {
   height: 3.5em;
   line-height: 3.5em;
+  width: 100%;
 }
 
 </style>
diff --git a/src/components/user_list_popover/user_list_popover.vue b/src/components/user_list_popover/user_list_popover.vue
index 8307cc8a..cd134453 100644
--- a/src/components/user_list_popover/user_list_popover.vue
+++ b/src/components/user_list_popover/user_list_popover.vue
@@ -48,8 +48,6 @@
 <script src="./user_list_popover.js"></script>
 
 <style lang="scss">
-@import "../../variables";
-
 .user-list-popover {
   padding: 0.5em;
 
-- 
cgit v1.2.3-70-g09d2

