diff --git a/frappe/desk/page/desktop/desktop.html b/frappe/desk/page/desktop/desktop.html
index cea2cdef60f9..f9a82768734e 100644
--- a/frappe/desk/page/desktop/desktop.html
+++ b/frappe/desk/page/desktop/desktop.html
@@ -32,6 +32,7 @@
>
+
0) {
- $suffix
+ $count
.text(count > 99 ? "99+" : count)
.attr("aria-label", __("{0} unread notifications", [count]))
.removeClass("hidden");
} else {
- $suffix.removeAttr("aria-label").addClass("hidden");
+ $count.removeAttr("aria-label").addClass("hidden");
}
}
@@ -418,14 +405,12 @@ class NotificationsView extends BaseNotificationsView {
setup_notification_listeners() {
frappe.realtime.on("notification", () => {
this.settings.seen = 0;
- this.toggle_notification_icon(false);
this.update_count_badge(this.unread_count + 1);
this.update_dropdown();
});
frappe.realtime.on("indicator_hide", () => {
this.settings.seen = 1;
- this.toggle_notification_icon(true);
});
this.parent.on("show.bs.dropdown", () => {
@@ -448,8 +433,9 @@ class NotificationsView extends BaseNotificationsView {
}
this.toggle_seen(true);
- if (this.get_bell_icons().hasClass("indicator")) {
- this.toggle_notification_icon(true);
+ // opening the panel counts as seeing what's in it -- let the other sessions know
+ if (this.settings?.seen == 0) {
+ this.settings.seen = 1;
frappe.call(
"frappe.desk.doctype.notification_log.notification_log.trigger_indicator_hide"
);
diff --git a/frappe/public/js/frappe/ui/sidebar/sidebar.js b/frappe/public/js/frappe/ui/sidebar/sidebar.js
index 9f2a16eae30b..bc06848a38d9 100644
--- a/frappe/public/js/frappe/ui/sidebar/sidebar.js
+++ b/frappe/public/js/frappe/ui/sidebar/sidebar.js
@@ -727,7 +727,7 @@ frappe.ui.Sidebar = class Sidebar {
standard: true,
type: "Button",
class: "sidebar-notification hidden",
- suffix: "",
+ suffix: "",
onClick: () => {
const $dropdown = this.wrapper.find(".dropdown-notifications");
$dropdown.toggleClass("hidden");
diff --git a/frappe/public/js/frappe/ui/sidebar/sidebar_item.js b/frappe/public/js/frappe/ui/sidebar/sidebar_item.js
index 2eaa94e75055..72b872cd318f 100644
--- a/frappe/public/js/frappe/ui/sidebar/sidebar_item.js
+++ b/frappe/public/js/frappe/ui/sidebar/sidebar_item.js
@@ -116,6 +116,16 @@ frappe.ui.sidebar_item.TypeLink = class SidebarItem {
})
);
$(this.container).append(this.wrapper);
+ this.setup_click();
+ }
+
+ setup_click() {
+ if (!this.path) return;
+ this.wrapper.find(".item-anchor").on("click", () => {
+ if (frappe.is_mobile()) {
+ frappe.app.sidebar.close();
+ }
+ });
}
set_suffix() {
if (this.item.suffix) {
@@ -292,9 +302,9 @@ frappe.ui.sidebar_item.TypeSidebarItemGroup = class SpacerItem extends (
constructor(item, items) {
super(item);
this.title = frappe.app.sidebar.workspace_title;
- this.setup_click();
}
+ // overrides TypeLink.setup_click(), invoked once via the base class's make()
setup_click() {
const me = this;
this.wrapper.on("click", function () {
@@ -344,9 +354,9 @@ frappe.ui.sidebar_item.TypeButton = class SidebarButton extends frappe.ui.sideba
this.item.id && this.wrapper.attr("id", this.item.id);
this.item.class && this.wrapper.attr("class", this.item.class);
this.wrapper.attr("title", this.item.label);
- this.setup_click();
}
+ // overrides TypeLink.setup_click(), invoked once via the base class's make()
setup_click() {
const me = this;
if (this.item.onClick) {
diff --git a/frappe/public/js/frappe/ui/sidebar/workspace_dock.js b/frappe/public/js/frappe/ui/sidebar/workspace_dock.js
index 83c640127fc9..ae25d64e4629 100644
--- a/frappe/public/js/frappe/ui/sidebar/workspace_dock.js
+++ b/frappe/public/js/frappe/ui/sidebar/workspace_dock.js
@@ -86,11 +86,11 @@ frappe.ui.WorkspaceDock = class WorkspaceDock {
name: "notifications",
icon: "bell",
label: __("Notifications"),
- // the Notifications view keeps the unread count and unseen dot in sync off these
- // classes (see notifications.js), and toggles the same dropdown the sidebar bell does.
+ // the Notifications view keeps the unread count in sync off these classes (see
+ // notifications.js), and toggles the same dropdown the sidebar bell does.
css_class: "sidebar-notification",
condition: () => frappe.boot.desk_settings.notifications,
- badge: ``,
+ badge: ``,
on_click: () => this.toggle_notifications(),
setup: ($item) => {
// seed the badge from boot; the Notifications view keeps it live from here on
@@ -98,12 +98,6 @@ frappe.ui.WorkspaceDock = class WorkspaceDock {
$item,
frappe.boot.notification_unread_count || 0
);
- if (
- frappe.boot.notification_settings &&
- frappe.boot.notification_settings.seen == 0
- ) {
- $item.find(".sidebar-item-icon").addClass("indicator blue");
- }
},
},
];
@@ -147,7 +141,7 @@ frappe.ui.WorkspaceDock = class WorkspaceDock {
// The dock shows unread as a small dot, not a number -- just toggle it on whether any exist.
sync_notification_count($bell, count) {
- $bell.find(".sidebar-notification-count").toggleClass("hidden", count <= 0);
+ $bell.find(".notification-count").toggleClass("hidden", count <= 0);
}
// Toggle the shared notifications panel (lives in the sidebar), mirroring the sidebar bell.
diff --git a/frappe/public/scss/desk/notification.scss b/frappe/public/scss/desk/notification.scss
index 73b00ced9734..3c18a047ab83 100644
--- a/frappe/public/scss/desk/notification.scss
+++ b/frappe/public/scss/desk/notification.scss
@@ -35,38 +35,10 @@
display: none;
}
-.sidebar-notification .sidebar-item-icon.indicator,
-.desktop-notification-icon.indicator {
- position: relative;
-
- &::before {
- position: absolute;
- left: auto;
- height: 6px;
- width: 6px;
- margin: 0;
- z-index: 1;
- }
-}
-
-.desktop-notification-icon.indicator::before {
- top: 0;
- right: 0;
-}
-
-.sidebar-notification .sidebar-item-icon.indicator::before {
- top: 5px;
- right: 6px;
- height: 5.5px;
- width: 5.5px;
- transition: opacity 0.2s ease-in-out;
-}
-
-.sidebar-notification:hover .sidebar-item-icon.indicator::before {
- opacity: 0;
-}
-
-.sidebar-notification-count {
+// The unread count is the only unread affordance a bell gets. Where the bell has a label (the
+// sidebar) it reads as a pill next to it; on icon-only bells (desktop navbar, workspace dock) there
+// is no room for a number, so the same element is drawn as a dot on the icon's corner.
+.notification-count {
padding: 1px 7px;
background-color: var(--bg-gray-100);
color: var(--text-muted);
@@ -76,8 +48,24 @@
border-radius: 10px;
}
-.sidebar-notification .standard-sidebar-item .item-anchor {
- overflow: visible;
+.desktop-notification-icon {
+ position: relative;
+
+ .notification-count {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 8px;
+ height: 8px;
+ padding: 0;
+ border-radius: 50%;
+ border: 1px solid var(--bg-color);
+ background-color: var(--surface-blue-5);
+ // dot only — hide the count text the shared notifications view sets on it
+ font-size: 0;
+ color: transparent;
+ overflow: hidden;
+ }
}
.mark-read {
diff --git a/frappe/public/scss/desk/workspace_dock.scss b/frappe/public/scss/desk/workspace_dock.scss
index fb9e3e581311..235488001054 100644
--- a/frappe/public/scss/desk/workspace_dock.scss
+++ b/frappe/public/scss/desk/workspace_dock.scss
@@ -170,7 +170,7 @@
}
// unread indicator — a small dot on the bell's top-right corner (mirrors dot)
- .sidebar-notification-count {
+ .notification-count {
position: absolute;
top: 5px;
right: 5px;
@@ -189,15 +189,6 @@
display: none;
}
}
-
- // re-place the shared unseen dot on the bell's top-right corner for the 16px icon
- .sidebar-item-icon.indicator::before {
- top: -1px;
- right: -1px;
- height: 8px;
- width: 8px;
- border-radius: 50%;
- }
}
// Search / notification shortcuts are not workspaces — mirror :