Add Plugin Library panel (SUPER+SHIFT+I), registry.json with 10 plugins, browse+install UI
swadhinbiswas committed 2 months ago
3f06578
1 parent 4735209
commit 3f06578
4 files changed
+442 -0
Showing 4 changed files+442-0
▼bin/omarchy-plugins
+87-0
| @@ -0,0 +1,87 @@ | ||
1 | +#!/bin/bash | |
2 | +# omarchy-plugins — browse and install plugins from the de-omarchy registry | |
3 | +# Usage: omarchy-plugins [list|install|search|info] [plugin-name] | |
4 | +set -euo pipefail | |
5 | + | |
6 | +REGISTRY="${OMARCHY_PATH:-/usr/share/de-omarchy}/registry.json" | |
7 | +PLUGIN_DIR="$HOME/.config/omarchy/plugins" | |
8 | + | |
9 | +ACTION="${1:-list}" | |
10 | +QUERY="${2:-}" | |
11 | + | |
12 | +log() { printf '\033[1;36m==>\033[0m %s\n' "$*"; } | |
13 | +err() { printf '\033[1;31mERR:\033[0m %s\n' "$*" >&2; exit 1; } | |
14 | + | |
15 | +[[ -f "$REGISTRY" ]] || err "Registry not found at $REGISTRY" | |
16 | + | |
17 | +list_plugins() { | |
18 | + python3 -c " | |
19 | +import json, sys | |
20 | +with open('$REGISTRY') as f: r = json.load(f) | |
21 | +for p in r.get('plugins', []): | |
22 | + installed = '$PLUGIN_DIR/' + p['id'].split('.')[-1] | |
23 | + import os | |
24 | + status = 'installed' if os.path.isdir(installed) else 'available' | |
25 | + print(f\" {p['id']:40s} {p['category']:12s} {p['status']:8s} [{status}]\") | |
26 | +" | |
27 | +} | |
28 | + | |
29 | +search_plugins() { | |
30 | + python3 -c " | |
31 | +import json, sys | |
32 | +with open('$REGISTRY') as f: r = json.load(f) | |
33 | +q = '$QUERY'.lower() | |
34 | +for p in r.get('plugins', []): | |
35 | + searchable = (p['name'] + ' ' + p['description'] + ' ' + ' '.join(p.get('tags', []))).lower() | |
36 | + if q in searchable: | |
37 | + print(f\" {p['id']:40s} {p['name']}\") | |
38 | + print(f\" {p['description']}\") | |
39 | + print() | |
40 | +" | |
41 | +} | |
42 | + | |
43 | +show_info() { | |
44 | + python3 -c " | |
45 | +import json | |
46 | +with open('$REGISTRY') as f: r = json.load(f) | |
47 | +for p in r.get('plugins', []): | |
48 | + if p['id'] == '$QUERY' or p['name'].lower() == '$QUERY'.lower(): | |
49 | + print(f\"Name: {p['name']}\") | |
50 | + print(f\"ID: {p['id']}\") | |
51 | + print(f\"Description: {p['description']}\") | |
52 | + print(f\"Author: {p['author']}\") | |
53 | + print(f\"Category: {p['category']}\") | |
54 | + print(f\"Tags: {', '.join(p.get('tags', []))}\") | |
55 | + print(f\"Status: {p['status']}\") | |
56 | + print(f\"Kind: {p['kind']}\") | |
57 | + print(f\"Install: {p['installCommand']}\") | |
58 | + exit(0) | |
59 | +print('Plugin not found: $QUERY') | |
60 | +" | |
61 | +} | |
62 | + | |
63 | +install_plugin() { | |
64 | + local cmd | |
65 | + cmd=$(python3 -c " | |
66 | +import json | |
67 | +with open('$REGISTRY') as f: r = json.load(f) | |
68 | +for p in r.get('plugins', []): | |
69 | + if p['id'] == '$QUERY' or p['name'].lower() == '$QUERY'.lower(): | |
70 | + print(p['installCommand']) | |
71 | + exit(0) | |
72 | +print('NOT_FOUND') | |
73 | +") | |
74 | + [[ "$cmd" == "NOT_FOUND" ]] && err "Plugin not found: $QUERY" | |
75 | + log "Installing: $QUERY" | |
76 | + mkdir -p "$PLUGIN_DIR" | |
77 | + eval "$cmd" | |
78 | + log "Done. Restart the shell to load: pkill -x quickshell" | |
79 | +} | |
80 | + | |
81 | +case "$ACTION" in | |
82 | + list) list_plugins ;; | |
83 | + search) [[ -z $QUERY ]] && err "Usage: omarchy-plugins search <query>"; search_plugins ;; | |
84 | + info) [[ -z $QUERY ]] && err "Usage: omarchy-plugins info <plugin-id>"; show_info ;; | |
85 | + install) [[ -z $QUERY ]] && err "Usage: omarchy-plugins install <plugin-id>"; install_plugin ;; | |
86 | + *) echo "Usage: omarchy-plugins [list|install|search|info] [plugin-name]" ;; | |
87 | +esac | |
0 | 88 | |
▼registry.json
+116-0
| @@ -0,0 +1,116 @@ | ||
1 | +{ | |
2 | + "name": "de-omarchy plugins", | |
3 | + "version": "1.0.0", | |
4 | + "plugins": [ | |
5 | + { | |
6 | + "id": "deomarchy.sysmon", | |
7 | + "name": "System Monitor", | |
8 | + "description": "CPU, RAM, disk, GPU temp, network in bar", | |
9 | + "author": "de-omarchy", | |
10 | + "category": "System", | |
11 | + "tags": ["monitoring", "bar-widget"], | |
12 | + "kind": "bar-widget", | |
13 | + "status": "stable", | |
14 | + "installCommand": "cp -r shell/plugins/sysmon ~/.config/omarchy/plugins/" | |
15 | + }, | |
16 | + { | |
17 | + "id": "deomarchy.docker-status", | |
18 | + "name": "Docker Status", | |
19 | + "description": "Running container count, click to open lazydocker", | |
20 | + "author": "de-omarchy", | |
21 | + "category": "System", | |
22 | + "tags": ["docker", "containers", "bar-widget"], | |
23 | + "kind": "bar-widget", | |
24 | + "status": "stable", | |
25 | + "installCommand": "cp -r shell/plugins/docker-status ~/.config/omarchy/plugins/" | |
26 | + }, | |
27 | + { | |
28 | + "id": "deomarchy.power-profile", | |
29 | + "name": "Power Profile", | |
30 | + "description": "Toggle performance/balanced/powersave", | |
31 | + "author": "de-omarchy", | |
32 | + "category": "System", | |
33 | + "tags": ["power", "battery", "bar-widget"], | |
34 | + "kind": "bar-widget", | |
35 | + "status": "stable", | |
36 | + "installCommand": "cp -r shell/plugins/power-profile ~/.config/omarchy/plugins/" | |
37 | + }, | |
38 | + { | |
39 | + "id": "deomarchy.wallpaper-manager", | |
40 | + "name": "Wallpaper Manager", | |
41 | + "description": "Per-monitor wallpaper selection from theme backgrounds", | |
42 | + "author": "de-omarchy", | |
43 | + "category": "Desktop", | |
44 | + "tags": ["wallpaper", "panel"], | |
45 | + "kind": "panel", | |
46 | + "status": "stable", | |
47 | + "installCommand": "cp -r shell/plugins/wallpaper-manager ~/.config/omarchy/plugins/" | |
48 | + }, | |
49 | + { | |
50 | + "id": "deomarchy.system-overview", | |
51 | + "name": "System Overview", | |
52 | + "description": "Full system stats panel (CPU/RAM/disk/GPU/network/uptime)", | |
53 | + "author": "de-omarchy", | |
54 | + "category": "System", | |
55 | + "tags": ["monitoring", "panel"], | |
56 | + "kind": "panel", | |
57 | + "status": "stable", | |
58 | + "installCommand": "cp -r shell/plugins/system-overview ~/.config/omarchy/plugins/" | |
59 | + }, | |
60 | + { | |
61 | + "id": "deomarchy.monitor-manager", | |
62 | + "name": "Monitor Manager", | |
63 | + "description": "Visual multi-monitor arrangement (drag, rotate, scale)", | |
64 | + "author": "de-omarchy", | |
65 | + "category": "Desktop", | |
66 | + "tags": ["monitor", "display", "panel"], | |
67 | + "kind": "panel", | |
68 | + "status": "stable", | |
69 | + "installCommand": "cp -r monitor-manager ~/.config/omarchy/plugins/ && ln -sf ~/.config/omarchy/plugins/monitor-manager/shell.qml ~/.config/omarchy/plugins/monitor-manager/main.qml" | |
70 | + }, | |
71 | + { | |
72 | + "id": "lacuna.shell-suite", | |
73 | + "name": "Lacuna", | |
74 | + "description": "Complete visual shell with custom bar, sidebar, system controls", | |
75 | + "author": "OldJobobo", | |
76 | + "category": "Desktop", | |
77 | + "tags": ["bar", "quickshell", "suite"], | |
78 | + "kind": "suite", | |
79 | + "status": "beta", | |
80 | + "installCommand": "git clone https://github.com/OldJobobo/lacuna-omarchy-plugins.git \"$HOME/lacuna\" && cd \"$HOME/lacuna\" && ./scripts/lacuna" | |
81 | + }, | |
82 | + { | |
83 | + "id": "omarchy.omni", | |
84 | + "name": "Omni", | |
85 | + "description": "AI-powered launcher and productivity tools", | |
86 | + "author": "bjarneo", | |
87 | + "category": "Productivity", | |
88 | + "tags": ["launcher", "ai"], | |
89 | + "kind": "plugin", | |
90 | + "status": "stable", | |
91 | + "installCommand": "git clone https://github.com/bjarneo/omarchy-shell-plugins.git \"$HOME/omarchy-plugins\" && cd \"$HOME/omarchy-plugins\" && ./install.sh omni" | |
92 | + }, | |
93 | + { | |
94 | + "id": "omarchy.quickapps-hud", | |
95 | + "name": "QuickApps HUD", | |
96 | + "description": "Quick application launcher with HUD overlay", | |
97 | + "author": "bjarneo", | |
98 | + "category": "Desktop", | |
99 | + "tags": ["launcher", "quickshell"], | |
100 | + "kind": "plugin", | |
101 | + "status": "stable", | |
102 | + "installCommand": "git clone https://github.com/bjarneo/omarchy-shell-plugins.git \"$HOME/omarchy-plugins\" && cd \"$HOME/omarchy-plugins\" && ./install.sh quickapps-hud" | |
103 | + }, | |
104 | + { | |
105 | + "id": "omarchy.overview", | |
106 | + "name": "System Overview", | |
107 | + "description": "System resource monitor with process list", | |
108 | + "author": "AyushKr2003", | |
109 | + "category": "System", | |
110 | + "tags": ["monitoring", "system"], | |
111 | + "kind": "plugin", | |
112 | + "status": "stable", | |
113 | + "installCommand": "git clone https://github.com/AyushKr2003/omarchy-overview.git \"$HOME/omarchy-overview\" && cd \"$HOME/omarchy-overview\" && ./install.sh" | |
114 | + } | |
115 | + ] | |
116 | +} | |
0 | 117 | |
▼shell/plugins/plugin-library/Panel.qml
+226-0
| @@ -0,0 +1,226 @@ | ||
1 | +import QtQuick | |
2 | +import Quickshell | |
3 | +import Quickshell.Io | |
4 | +import qs.Commons | |
5 | +import qs.Ui | |
6 | + | |
7 | +Panel { | |
8 | + id: root | |
9 | + moduleName: "deomarchy.plugin-library" | |
10 | + | |
11 | + property var plugins: [] | |
12 | + property int selectedIndex: -1 | |
13 | + property string statusText: "" | |
14 | + property bool installing: false | |
15 | + | |
16 | + implicitWidth: 520 | |
17 | + implicitHeight: 600 | |
18 | + | |
19 | + Component.onCompleted: loadRegistry() | |
20 | + | |
21 | + function loadRegistry() { | |
22 | + var path = Quickshell.env("HOME") + "/.config/omarchy/plugins/registry.json" | |
23 | + var fallback = (Quickshell.env("OMARCHY_PATH") || "/usr/share/de-omarchy") + "/registry.json" | |
24 | + registryProc.command = ["bash", "-c", "cat " + path + " 2>/dev/null || cat " + fallback + " 2>/dev/null || echo '{\"plugins\":[]}'"] | |
25 | + registryProc.running = true | |
26 | + } | |
27 | + | |
28 | + Process { | |
29 | + id: registryProc | |
30 | + running: false | |
31 | + stdout: SplitParser { | |
32 | + onRead: function(line) { | |
33 | + try { | |
34 | + var data = JSON.parse(String(line).trim()) | |
35 | + if (data && data.plugins) root.plugins = data.plugins | |
36 | + } catch(e) {} | |
37 | + } | |
38 | + } | |
39 | + } | |
40 | + | |
41 | + Process { | |
42 | + id: installProc | |
43 | + running: false | |
44 | + onRunningChanged: { | |
45 | + if (!running) { | |
46 | + root.installing = false | |
47 | + root.statusText = root.installExitCode === 0 ? "Installed!" : "Install failed" | |
48 | + timer.restart() | |
49 | + } | |
50 | + } | |
51 | + property int installExitCode: 0 | |
52 | + onExited: function(code) { installExitCode = code } | |
53 | + } | |
54 | + | |
55 | + Timer { | |
56 | + id: timer | |
57 | + interval: 3000 | |
58 | + onTriggered: root.statusText = "" | |
59 | + } | |
60 | + | |
61 | + function installPlugin(plugin) { | |
62 | + if (root.installing) return | |
63 | + root.installing = true | |
64 | + root.statusText = "Installing " + plugin.name + "..." | |
65 | + var pluginDir = Quickshell.env("HOME") + "/.config/omarchy/plugins" | |
66 | + installProc.command = ["bash", "-c", "mkdir -p " + pluginDir + " && " + plugin.installCommand] | |
67 | + installProc.running = true | |
68 | + } | |
69 | + | |
70 | + Column { | |
71 | + anchors.fill: parent | |
72 | + anchors.margins: 16 | |
73 | + spacing: 12 | |
74 | + | |
75 | + Row { | |
76 | + width: parent.width | |
77 | + spacing: 12 | |
78 | + | |
79 | + Text { | |
80 | + text: "Plugin Library" | |
81 | + color: Color.foreground | |
82 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
83 | + font.pixelSize: 20 | |
84 | + font.bold: true | |
85 | + anchors.verticalCenter: parent.verticalCenter | |
86 | + } | |
87 | + | |
88 | + Item { width: 1; height: 1 } | |
89 | + | |
90 | + Rectangle { | |
91 | + width: statusText.length > 0 ? statusLabel.implicitWidth + 20 : 0 | |
92 | + height: 24 | |
93 | + radius: 12 | |
94 | + color: installing ? Qt.rgba(0.2, 0.5, 0.9, 0.3) : Qt.rgba(0.2, 0.8, 0.3, 0.3) | |
95 | + visible: statusText.length > 0 | |
96 | + anchors.verticalCenter: parent.verticalCenter | |
97 | + | |
98 | + Text { | |
99 | + id: statusLabel | |
100 | + anchors.centerIn: parent | |
101 | + text: root.statusText | |
102 | + color: Color.foreground | |
103 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
104 | + font.pixelSize: 11 | |
105 | + } | |
106 | + } | |
107 | + } | |
108 | + | |
109 | + Text { | |
110 | + text: plugins.length + " plugins available" | |
111 | + color: Color.subtext | |
112 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
113 | + font.pixelSize: 12 | |
114 | + } | |
115 | + | |
116 | + ListView { | |
117 | + id: listView | |
118 | + width: parent.width | |
119 | + height: parent.height - 80 | |
120 | + clip: true | |
121 | + spacing: 8 | |
122 | + model: root.plugins | |
123 | + | |
124 | + delegate: Rectangle { | |
125 | + required property var modelData | |
126 | + required property int index | |
127 | + width: listView.width | |
128 | + height: 90 | |
129 | + radius: 8 | |
130 | + color: index === root.selected ? Qt.rgba(Color.accent.r, Color.accent.g, Color.accent.b, 0.15) : Qt.rgba(1, 1, 1, 0.05) | |
131 | + border.color: index === root.selected ? Color.accent : Qt.rgba(1, 1, 1, 0.1) | |
132 | + border.width: index === root.selected ? 1 : 0 | |
133 | + | |
134 | + Column { | |
135 | + anchors.fill: parent | |
136 | + anchors.margins: 10 | |
137 | + spacing: 4 | |
138 | + | |
139 | + Row { | |
140 | + width: parent.width | |
141 | + spacing: 8 | |
142 | + | |
143 | + Rectangle { | |
144 | + width: 36; height: 36; radius: 8 | |
145 | + color: Qt.rgba(0.4, 0.5, 0.9, 0.2) | |
146 | + Text { | |
147 | + anchors.centerIn: parent | |
148 | + text: modelData.name ? modelData.name.charAt(0) : "?" | |
149 | + color: Color.foreground | |
150 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
151 | + font.pixelSize: 16 | |
152 | + font.bold: true | |
153 | + } | |
154 | + } | |
155 | + | |
156 | + Column { | |
157 | + width: parent.width - 120 | |
158 | + spacing: 2 | |
159 | + | |
160 | + Text { | |
161 | + text: modelData.name || "Unknown" | |
162 | + color: Color.foreground | |
163 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
164 | + font.pixelSize: 13 | |
165 | + font.bold: true | |
166 | + elide: Text.ElideRight | |
167 | + } | |
168 | + | |
169 | + Text { | |
170 | + text: modelData.description || "" | |
171 | + color: Color.subtext | |
172 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
173 | + font.pixelSize: 11 | |
174 | + elide: Text.ElideRight | |
175 | + width: parent.width | |
176 | + } | |
177 | + | |
178 | + Row { | |
179 | + spacing: 6 | |
180 | + Text { | |
181 | + text: modelData.author || "" | |
182 | + color: Color.subtext | |
183 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
184 | + font.pixelSize: 10 | |
185 | + } | |
186 | + Text { | |
187 | + text: (modelData.tags || []).join(", ") | |
188 | + color: Color.subtext | |
189 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
190 | + font.pixelSize: 10 | |
191 | + } | |
192 | + } | |
193 | + } | |
194 | + | |
195 | + Rectangle { | |
196 | + width: 60; height: 28; radius: 6 | |
197 | + color: root.installing ? Qt.rgba(1,1,1,0.05) : Qt.rgba(0.3, 0.7, 0.3, 0.3) | |
198 | + anchors.verticalCenter: parent.verticalCenter | |
199 | + | |
200 | + Text { | |
201 | + anchors.centerIn: parent | |
202 | + text: root.installing ? "..." : "Install" | |
203 | + color: root.installing ? Color.subtext : Color.foreground | |
204 | + font.family: root.bar ? root.bar.fontFamily : Style.font.family | |
205 | + font.pixelSize: 11 | |
206 | + font.bold: true | |
207 | + } | |
208 | + | |
209 | + MouseArea { | |
210 | + anchors.fill: parent | |
211 | + cursorShape: Qt.PointingHandCursor | |
212 | + enabled: !root.installing | |
213 | + onClicked: root.installPlugin(modelData) | |
214 | + } | |
215 | + } | |
216 | + } | |
217 | + } | |
218 | + | |
219 | + MouseArea { | |
220 | + anchors.fill: parent | |
221 | + onClicked: root.selectedIndex = index | |
222 | + } | |
223 | + } | |
224 | + } | |
225 | + } | |
226 | +} | |
0 | 227 | |
▼shell/plugins/plugin-library/manifest.json
+13-0
| @@ -0,0 +1,13 @@ | ||
1 | +{ | |
2 | + "schemaVersion": 1, | |
3 | + "id": "deomarchy.plugin-library", | |
4 | + "name": "Plugin Library", | |
5 | + "version": "1.0.0", | |
6 | + "author": "de-omarchy", | |
7 | + "description": "Browse and install plugins from the de-omarchy registry", | |
8 | + "kinds": ["panel"], | |
9 | + "entryPoints": { | |
10 | + "panel": "Panel.qml" | |
11 | + }, | |
12 | + "keepLoaded": false | |
13 | +} | |
0 | 14 | |