diff --git a/omarchy/README.md b/omarchy/README.md index 40eaa09..e031ef6 100644 --- a/omarchy/README.md +++ b/omarchy/README.md @@ -87,11 +87,14 @@ and the root menu (Super + Alt + Space) are both wider. The two oversized menus `clonedFrom`, and the shell routes those calls here. `BarWidget.qml` swaps the stock `\ue900` glyph from the `omarchy` icon font for -`branding/blob_icon.svg`. Qt renders SVG through `qt6-svg`, but an `Image` -cannot be recolored, so the icon is used as an alpha mask over a rectangle -filled with the bar foreground. That keeps it following the theme and the bar's -own color animation the way a glyph did, and it means the black fill in the -source file never matters. +`branding/blob_icon.svg`. An SVG is text, so the fill is rewritten to the bar +foreground in QML and the result handed to `Image` as a base64 `data:` URL - +the same trick the `theme-set` hook uses with `sed` for the fastfetch logo, so +both consumers of the icon work the same way. The color is read off +`button.foreground` rather than the theme, which keeps the icon on the bar's own +foreground animation, and rebuilding the URL is what reloads the image, so there +is no image cache to bust. The glyph stays as the `text` fallback and is shown +whenever the SVG cannot be read or decoded, so the button is never blank. `mergeMenuSources` in `MenuModel.js` reads the default menu first and the user extension second, so a row that only exists in `extensions/omarchy-menu.jsonc` diff --git a/omarchy/plugins/blob.menu/BarWidget.qml b/omarchy/plugins/blob.menu/BarWidget.qml index 5d1195e..c34063c 100644 --- a/omarchy/plugins/blob.menu/BarWidget.qml +++ b/omarchy/plugins/blob.menu/BarWidget.qml @@ -1,6 +1,6 @@ import QtQuick -import QtQuick.Effects import Quickshell +import Quickshell.Io import qs.Commons import qs.Ui @@ -8,19 +8,43 @@ BarWidget { id: root moduleName: "omarchy.menu" - readonly property string iconPath: "file://" + Quickshell.env("HOME") + "/.config/omarchy/branding/blob_icon.svg" + readonly property string iconPath: Quickshell.env("HOME") + "/.config/omarchy/branding/blob_icon.svg" readonly property int iconSize: Math.round(Style.font.body * 1.35) + property string iconSvg: "" + + readonly property string iconColor: hexColor(button.foreground) + readonly property string tintedSvg: iconSvg.replace(/fill="#000000"/g, 'fill="' + iconColor + '"') + readonly property string iconUrl: iconSvg.length > 0 ? "data:image/svg+xml;base64," + Qt.btoa(tintedSvg) : "" + readonly property bool iconReady: icon.status === Image.Ready + + function hexColor(value) { + function channel(fraction) { + return ("0" + Math.round(fraction * 255).toString(16)).slice(-2) + } + return "#" + channel(value.r) + channel(value.g) + channel(value.b) + } + implicitWidth: button.implicitWidth implicitHeight: button.implicitHeight + FileView { + path: root.iconPath + watchChanges: true + printErrors: false + onLoaded: root.iconSvg = text() + onLoadFailed: root.iconSvg = "" + onFileChanged: reload() + } + WidgetButton { id: button anchors.fill: parent bar: root.bar - labelVisible: false - hasVisualContent: true - fixedWidth: root.iconSize + Style.spaceReal(15) + text: "\ue900" + fontFamily: "omarchy" + labelVisible: !root.iconReady + fixedWidth: root.iconReady ? root.iconSize + Style.spaceReal(15) : -1 horizontalMargin: 7.5 onPressed: function(button) { if (!root.bar) return @@ -29,30 +53,15 @@ BarWidget { } Image { - id: iconMask - source: root.iconPath - visible: false - smooth: true - sourceSize.width: root.iconSize * 2 - sourceSize.height: root.iconSize * 2 - } - - Rectangle { + id: icon anchors.centerIn: parent width: root.iconSize height: root.iconSize - color: button.foreground - visible: iconMask.status === Image.Ready - layer.enabled: true - layer.effect: MultiEffect { - maskEnabled: true - maskSource: iconMask - } - - Behavior on color { - enabled: !root.bar || root.bar.foregroundAnimationEnabled - ColorAnimation { duration: 160 } - } + source: root.iconUrl + sourceSize.width: root.iconSize * 2 + sourceSize.height: root.iconSize * 2 + smooth: true + visible: root.iconReady } } }