diff --git a/dot_config/omarchy/plugins/private_joe.workspaces/Workspaces.qml b/dot_config/omarchy/plugins/private_joe.workspaces/Workspaces.qml new file mode 100644 index 0000000..cd3d168 --- /dev/null +++ b/dot_config/omarchy/plugins/private_joe.workspaces/Workspaces.qml @@ -0,0 +1,121 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Hyprland +import qs.Commons +import qs.Ui + +BarWidget { + id: root + moduleName: "joe.workspaces" + + // The Hyprland monitor this bar surface lives on. One bar is built per + // screen, so each instance filters to its own monitor's workspaces. + readonly property var screen: root.QsWindow.window ? root.QsWindow.window.screen : null + readonly property var monitor: screen ? Hyprland.monitorFor(screen) : null + + // Green from the current theme's colors.toml. The shell's Color singleton + // doesn't expose it, so read it here; `activeColor` in shell.json overrides. + property color themeGreen: "#9ece6a" + readonly property color activeColor: root.setting("activeColor", root.themeGreen) + + FileView { + id: colorsFile + path: Color.currentThemePath + "/colors.toml" + printErrors: false + onLoaded: { + var match = text().match(/^\s*(?:green|color2)\s*=\s*["']?(#[0-9A-Fa-f]{6})/m) + if (match) root.themeGreen = match[1] + } + } + + // Theme switches push new colors into Color; re-read ours alongside. + Connections { + target: Color + function onAccentChanged() { colorsFile.reload() } + } + + function workspaceById(id) { + var values = Hyprland.workspaces.values + for (var i = 0; i < values.length; i++) { + if (values[i].id === id) return values[i] + } + + return null + } + + function workspaceIds() { + var ids = [] + var values = Hyprland.workspaces.values + + for (var i = 0; i < values.length; i++) { + var ws = values[i] + if (ws.id <= 0 || ws.id > 10) continue + if (root.monitor && ws.monitor !== root.monitor) continue + ids.push(ws.id) + } + + ids.sort(function(left, right) { return left - right }) + return ids + } + + function focusWorkspace(id) { + if (!root.bar) return + root.bar.run("hyprctl dispatch " + Util.shellQuote("hl.dsp.focus({ workspace = \"" + id + "\" })")) + } + + readonly property real trailingGap: root.vertical ? 0 : Style.spaceReal(1.5) + + implicitWidth: grid.implicitWidth + trailingGap + implicitHeight: grid.implicitHeight + + GridLayout { + id: grid + anchors.fill: parent + anchors.rightMargin: root.trailingGap + columns: root.vertical ? 1 : Math.max(1, root.workspaceIds().length) + columnSpacing: root.vertical ? 0 : Style.space(1) + rowSpacing: root.vertical ? Style.space(2) : 0 + + Repeater { + model: root.workspaceIds() + + WidgetButton { + required property int modelData + + readonly property var workspace: root.workspaceById(modelData) + readonly property bool occupied: workspace !== null && workspace.toplevels.values.length > 0 + // The workspace shown on this bar's monitor (each monitor has one). + readonly property bool focused: root.monitor !== null && root.monitor.activeWorkspace !== null + && root.monitor.activeWorkspace.id === modelData + + id: button + bar: root.bar + text: modelData === 10 ? "0" : String(modelData) + // WidgetButton's own label can't be bolded, so draw our own instead. + labelVisible: false + opacity: occupied || focused ? 1 : 0.5 + horizontalMargin: 6 + verticalPadding: 6 + fixedWidth: root.vertical ? root.barSize : Style.space(20) + fixedHeight: root.barSize + onPressed: function() { root.focusWorkspace(modelData) } + + Text { + anchors.centerIn: parent + textFormat: Text.PlainText + text: button.text + color: button.focused ? root.activeColor : button.foreground + font.family: button.fontFamily + font.pixelSize: button.fontSize + font.bold: button.focused + font.underline: button.focused + renderType: Text.NativeRendering + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + } + } +} diff --git a/dot_config/omarchy/plugins/private_joe.workspaces/manifest.json b/dot_config/omarchy/plugins/private_joe.workspaces/manifest.json new file mode 100644 index 0000000..e8093d3 --- /dev/null +++ b/dot_config/omarchy/plugins/private_joe.workspaces/manifest.json @@ -0,0 +1,23 @@ +{ + "schemaVersion": 1, + "id": "joe.workspaces", + "name": "My Workspaces", + "version": "1.0.0", + "author": "Omarchy", + "description": "Workspace number indicators", + "kinds": [ + "bar-widget" + ], + "entryPoints": { + "barWidget": "Workspaces.qml" + }, + "barWidget": { + "displayName": "My Workspaces", + "description": "Workspace number indicators", + "category": "Compositor", + "allowMultiple": false + }, + "omarchy": { + "clonedFrom": "omarchy.workspaces" + } +} diff --git a/dot_config/omarchy/shell.json b/dot_config/omarchy/shell.json new file mode 100644 index 0000000..8c5b8c6 --- /dev/null +++ b/dot_config/omarchy/shell.json @@ -0,0 +1,69 @@ +{ + "version": 1, + "idle": { + "screensaver": 150, + "lock": 300 + }, + "bar": { + "position": "top", + "transparent": false, + "centerAnchor": "omarchy.clock", + "layout": { + "left": [ + { + "id": "omarchy.menu" + }, + { + "id": "joe.workspaces" + } + ], + "center": [ + { + "id": "omarchy.indicators" + }, + { + "id": "omarchy.clock", + "format": "dddd HH:mm", + "formatAlt": "d MMMM 'W'ww yyyy", + "verticalFormat": "HH\n—\nmm" + }, + { + "id": "omarchy.keyboard-layout" + }, + { + "id": "omarchy.weather" + }, + { + "id": "omarchy.system-update" + } + ], + "right": [ + { + "id": "omarchy.tray" + }, + { + "id": "omarchy.tailscale" + }, + { + "id": "omarchy.agents" + }, + { + "id": "omarchy.bluetooth" + }, + { + "id": "omarchy.network" + }, + { + "id": "omarchy.audio" + }, + { + "id": "omarchy.monitor" + }, + { + "id": "omarchy.power" + } + ] + } + }, + "plugins": [] +}