From d3275f451fec215dde1c2b5c50a2baf049fda368 Mon Sep 17 00:00:00 2001 From: JosephMcc Date: Wed, 24 Dec 2025 09:03:29 -0800 Subject: [PATCH] ui: Add a new placeholder object Gives a simple reusable object to show when no active items are available. Make use of this new object in menu@cinnamon.org when the recent and favorite categories are empty. --- data/theme/cinnamon-sass/widgets/_base.scss | 19 ++++ .../applets/menu@cinnamon.org/applet.js | 34 ++++--- js/ui/placeholder.js | 98 +++++++++++++++++++ 3 files changed, 137 insertions(+), 14 deletions(-) create mode 100644 js/ui/placeholder.js diff --git a/data/theme/cinnamon-sass/widgets/_base.scss b/data/theme/cinnamon-sass/widgets/_base.scss index d32b9f7c36..479f061edc 100644 --- a/data/theme/cinnamon-sass/widgets/_base.scss +++ b/data/theme/cinnamon-sass/widgets/_base.scss @@ -50,6 +50,25 @@ -pie-background-color: rgba(140, 140, 140, 0.6); } +// placeholder + +.placeholder { + spacing: 8px; + padding: $base_padding * 2; + + .placeholder-icon { color: $insensitive_fg_color; } + .placeholder-label { + @extend %title_3; + color: $insensitive_fg_color; + padding-top: 8px; + } + + .placeholder-description { + color: $insensitive_fg_color; + text-align: center; + } +} + // ripples .ripple-pointer-location { diff --git a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js index 49129d99df..97c4b2646a 100644 --- a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js @@ -26,6 +26,7 @@ const Pango = imports.gi.Pango; const SearchProviderManager = imports.ui.searchProviderManager; const SignalManager = imports.misc.signalManager; const Params = imports.misc.params; +const Placeholder = imports.ui.placeholder; const INITIAL_BUTTON_LOAD = 30; @@ -2236,14 +2237,16 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "recent"; } else { this.noRecentDocuments = true; - let button = new SimpleMenuItem(this, { name: _("No recent documents"), - type: 'no-recent', - styleClass: 'appmenu-application-button', - reactive: false, - activatable: false }); - button.addLabel(button.name, 'appmenu-application-button-label'); + let button = new SimpleMenuItem(this, { type: 'no-recent' }); + let placeHolder = new Placeholder.Placeholder({ + icon_name: 'xsi-document-open-recent-symbolic', + title: _('No Recent Documents'), + }); + button.actor.y_expand = true; + button.actor.y_align = Clutter.ActorAlign.CENTER; + button.actor.add_child(placeHolder); this._recentButtons.push(button); - this.applicationsBox.add_actor(button.actor); + this.applicationsBox.add_child(button.actor); button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "recent"; } } @@ -2284,14 +2287,17 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { }); } else { - let button = new SimpleMenuItem(this, { name: _("No favorite documents"), - type: 'no-favorites', - styleClass: 'appmenu-application-button', - reactive: false, - activatable: false }); - button.addLabel(button.name, 'appmenu-application-button-label'); + let button = new SimpleMenuItem(this, { type: 'no-favorites' }); + let placeHolder = new Placeholder.Placeholder({ + icon_name: 'xsi-user-favorites-symbolic', + title: _('No Favorite Documents'), + description: _("Files you add to Favorites in your file manager will be shown here") + }); + button.actor.y_expand = true; + button.actor.y_align = Clutter.ActorAlign.CENTER; + button.actor.add_child(placeHolder); this._favoriteDocButtons.push(button); - this.applicationsBox.add_actor(button.actor); + this.applicationsBox.add_child(button.actor); button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "favorite"; } } diff --git a/js/ui/placeholder.js b/js/ui/placeholder.js new file mode 100644 index 0000000000..bca6d839ad --- /dev/null +++ b/js/ui/placeholder.js @@ -0,0 +1,98 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const { Clutter, GObject, Pango, St } = imports.gi; + +var Placeholder = GObject.registerClass({ + Properties: { + 'icon-name': GObject.ParamSpec.string( + 'icon-name', null, null, + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + 'title': GObject.ParamSpec.string( + 'title', null, null, + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + 'description': GObject.ParamSpec.string( + 'description', null, null, + GObject.ParamFlags.READWRITE | + GObject.ParamFlags.CONSTRUCT, + null), + }, +}, class Placeholder extends St.BoxLayout { + _init(params) { + this._icon = new St.Icon({ + style_class: 'placeholder-icon', + icon_size: 64, + icon_type: St.IconType.SYMBOLIC, + x_align: Clutter.ActorAlign.CENTER, + }); + + this._title = new St.Label({ + style_class: 'placeholder-label', + x_align: Clutter.ActorAlign.CENTER, + }); + + this._description = new St.Label({ + style_class: 'placeholder-description', + x_align: Clutter.ActorAlign.CENTER, + }); + this._description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; + this._description.clutter_text.line_wrap = true; + + super._init({ + style_class: 'placeholder', + reactive: false, + vertical: true, + x_expand: true, + y_expand: true, + ...params, + }); + + this.add_child(this._icon); + this.add_child(this._title); + this.add_child(this._description); + } + + get icon_name() { + return this._icon.icon_name; + } + + set icon_name(iconName) { + if (this._icon.icon_name === iconName) + return; + + this._icon.icon_name = iconName; + this.notify('icon-name'); + } + + get title() { + return this._title.text; + } + + set title(title) { + if (this._title.text === title) + return; + + this._title.text = title; + this.notify('title'); + } + + get description() { + return this._description.text; + } + + set description(description) { + if (this._description.text === description) + return; + + if (description === null) + this._description.visible = false; + else + this._description.visible = true; + + this._description.text = description; + this.notify('description'); + } +});