aboutsummaryrefslogtreecommitdiffstats
path: root/desktop
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-17 10:43:38 +0200
committerDanilo M. <danix@danix.xyz>2026-10-17 10:43:38 +0200
commit166d638bce081631705687501020725045920e50 (patch)
tree0f89277d6fcc34f9f4345ed75769001c023c7cd3 /desktop
parent4acf7325d8aa7e841c0059211d908d31d492f828 (diff)
downloadquickshell-166d638bce081631705687501020725045920e50.tar.gz
quickshell-166d638bce081631705687501020725045920e50.zip
settings: the sidebar is grouped
Ten pages in one flat list had stopped reading as a list. A module now names its group, and the sidebar sorts by it and draws a small heading where it changes: Account (user, git), Appearance (wallpaper, theme, icons), Desktop (HyprSunset, HyprIdle, autostart) and Assistant (the daemon, Ask presets). Groups keep the order their first page is declared in, so shell.qml's module order still decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop')
-rw-r--r--desktop/Module.qml4
-rw-r--r--desktop/README.md2
-rw-r--r--desktop/Settings.qml91
-rw-r--r--desktop/modules/appearance/IconsModule.qml1
-rw-r--r--desktop/modules/appearance/IdleModule.qml1
-rw-r--r--desktop/modules/appearance/SunsetModule.qml1
-rw-r--r--desktop/modules/appearance/ThemeModule.qml1
-rw-r--r--desktop/modules/appearance/WallpaperModule.qml1
-rw-r--r--desktop/modules/assistant/AssistantModule.qml1
-rw-r--r--desktop/modules/assistant/PresetsModule.qml1
-rw-r--r--desktop/modules/autostart/AutostartModule.qml1
-rw-r--r--desktop/modules/git/GitModule.qml1
-rw-r--r--desktop/modules/user/UserModule.qml1
13 files changed, 74 insertions, 33 deletions
diff --git a/desktop/Module.qml b/desktop/Module.qml
index a1817a4..85f924b 100644
--- a/desktop/Module.qml
+++ b/desktop/Module.qml
@@ -42,6 +42,10 @@ QtObject {
// things set once and left alone. Such a module has no tile by default.
property bool settings: false
+ // The heading a settings page is listed under in the window's sidebar.
+ // Groups appear in the order their first module is declared.
+ property string group: ""
+
// Words the settings window's search matches besides the label: the
// settings buried inside the page, which is not loaded until opened.
property list<string> keywords: []
diff --git a/desktop/README.md b/desktop/README.md
index a9d62df..59983a9 100644
--- a/desktop/README.md
+++ b/desktop/README.md
@@ -88,6 +88,8 @@ drawer needs to show it:
module has no tile.
- `keywords`: for a settings page, the words its search should find besides
the label.
+- `group`: the heading a settings page is listed under in the sidebar.
+ Groups keep the order their first page is declared in.
- `activate()`: what a tile with no page does when clicked.
- `alwaysActive`: declares whether the module's service is meant to run while
the drawer is closed. The drawer does not read it, the module implements its
diff --git a/desktop/Settings.qml b/desktop/Settings.qml
index e8895a4..dd376c7 100644
--- a/desktop/Settings.qml
+++ b/desktop/Settings.qml
@@ -24,11 +24,17 @@ Scope {
property bool open: false
property string page: ""
+ // Grouped: a group's pages together, groups in the order their first
+ // page is declared, pages in declaration order within a group.
readonly property var pages: {
const out = [];
for (let i = 0; i < root.modules.length; i++)
if (root.modules[i].settings) out.push(root.modules[i]);
- return out;
+ const order = [];
+ for (const m of out) if (!order.includes(m.group)) order.push(m.group);
+ return out.map((m, i) => ({ m, i }))
+ .sort((a, b) => order.indexOf(a.m.group) - order.indexOf(b.m.group) || a.i - b.i)
+ .map(x => x.m);
}
property string query: ""
@@ -166,48 +172,67 @@ Scope {
spacing: 4
model: root.found
- delegate: Rectangle {
- id: entry
+ // A group's heading above its first entry, then the entry.
+ delegate: Column {
+ id: slot
required property var modelData
- readonly property bool selected: root.current === modelData.mod && modelData.key === ""
+ required property int index
width: side.width
- height: modelData.hit ? 46 : 36
- radius: 8
- color: selected ? Qt.alpha(Theme.accent, 0.22)
- : area.containsMouse ? Qt.alpha(Theme.text, 0.06) : "transparent"
Text {
- id: entryIcon
- anchors { left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter }
- text: entry.modelData.mod.icon
- font { family: Theme.iconFamily; pixelSize: Theme.fontSize }
- color: Theme.text
+ visible: slot.modelData.mod.group !== ""
+ && (slot.index === 0 || root.found[slot.index - 1].mod.group !== slot.modelData.mod.group)
+ leftPadding: 10
+ topPadding: slot.index === 0 ? 4 : 14
+ bottomPadding: 4
+ text: slot.modelData.mod.group.toUpperCase()
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5; bold: true; letterSpacing: 1 }
+ color: Theme.overlay
}
- Column {
- anchors { left: entryIcon.right; leftMargin: 10; right: parent.right; rightMargin: 8
- verticalCenter: parent.verticalCenter }
+
+ Rectangle {
+ id: entry
+ readonly property var modelData: slot.modelData
+ readonly property bool selected: root.current === modelData.mod && modelData.key === ""
+ width: side.width
+ height: modelData.hit ? 46 : 36
+ radius: 8
+ color: selected ? Qt.alpha(Theme.accent, 0.22)
+ : area.containsMouse ? Qt.alpha(Theme.text, 0.06) : "transparent"
+
Text {
- text: entry.modelData.mod.label
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
+ id: entryIcon
+ anchors { left: parent.left; leftMargin: 10; verticalCenter: parent.verticalCenter }
+ text: entry.modelData.mod.icon
+ font { family: Theme.iconFamily; pixelSize: Theme.fontSize }
color: Theme.text
}
- // Which buried setting matched, when the label did not.
- Text {
- visible: entry.modelData.hit !== ""
- width: parent.width
- elide: Text.ElideRight
- text: entry.modelData.hit
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 }
- color: Theme.subtext
+ Column {
+ anchors { left: entryIcon.right; leftMargin: 10; right: parent.right; rightMargin: 8
+ verticalCenter: parent.verticalCenter }
+ Text {
+ text: entry.modelData.mod.label
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 }
+ color: Theme.text
+ }
+ // Which buried setting matched, when the label did not.
+ Text {
+ visible: entry.modelData.hit !== ""
+ width: parent.width
+ elide: Text.ElideRight
+ text: entry.modelData.hit
+ font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 }
+ color: Theme.subtext
+ }
}
- }
- MouseArea {
- id: area
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onClicked: root.go(entry.modelData)
+ MouseArea {
+ id: area
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: root.go(entry.modelData)
+ }
}
}
}
diff --git a/desktop/modules/appearance/IconsModule.qml b/desktop/modules/appearance/IconsModule.qml
index f6559d1..bf3722b 100644
--- a/desktop/modules/appearance/IconsModule.qml
+++ b/desktop/modules/appearance/IconsModule.qml
@@ -19,6 +19,7 @@ Module {
// nf-fa-mouse_pointer, present in Inconsolata Nerd Font.
icon: "\uf245"
settings: true
+ group: "Appearance"
keywords: ["cursor", "pointer", "size", "gtk", "qt", "theme"]
searchItems: Icons.iconThemes.map(n => ({ text: "icons: " + n, key: "icon:" + n }))
.concat(Icons.cursorThemes.map(n => ({ text: "cursor: " + n, key: "cursor:" + n })))
diff --git a/desktop/modules/appearance/IdleModule.qml b/desktop/modules/appearance/IdleModule.qml
index 231e192..4b27cd3 100644
--- a/desktop/modules/appearance/IdleModule.qml
+++ b/desktop/modules/appearance/IdleModule.qml
@@ -19,6 +19,7 @@ Module {
// nf-fa-hourglass, present in Inconsolata Nerd Font.
icon: "\uf254"
settings: true
+ group: "Desktop"
keywords: ["hypridle", "lock", "timeout", "screen", "dpms", "suspend", "sleep"]
function refresh() { Hypridle.refresh(); }
diff --git a/desktop/modules/appearance/SunsetModule.qml b/desktop/modules/appearance/SunsetModule.qml
index 0f7fe79..557a2a4 100644
--- a/desktop/modules/appearance/SunsetModule.qml
+++ b/desktop/modules/appearance/SunsetModule.qml
@@ -19,6 +19,7 @@ Module {
// nf-fa-moon_o, present in Inconsolata Nerd Font.
icon: "\uf186"
settings: true
+ group: "Desktop"
keywords: ["hyprsunset", "night", "light", "temperature", "gamma", "location", "profile"]
function refresh() { Hyprsunset.refresh(); }
diff --git a/desktop/modules/appearance/ThemeModule.qml b/desktop/modules/appearance/ThemeModule.qml
index 729ceb1..97ca519 100644
--- a/desktop/modules/appearance/ThemeModule.qml
+++ b/desktop/modules/appearance/ThemeModule.qml
@@ -19,6 +19,7 @@ Module {
// nf-fa-paintbrush, present in Inconsolata Nerd Font.
icon: "\uf1fc"
settings: true
+ group: "Appearance"
keywords: ["colour", "color", "scheme", "palette", "accent", "udt"]
searchItems: Array.from(Udt.names).map(n => ({ text: n, key: n }))
diff --git a/desktop/modules/appearance/WallpaperModule.qml b/desktop/modules/appearance/WallpaperModule.qml
index 246e8f5..c21d94d 100644
--- a/desktop/modules/appearance/WallpaperModule.qml
+++ b/desktop/modules/appearance/WallpaperModule.qml
@@ -20,6 +20,7 @@ Module {
// nf-fa-picture_o, present in Inconsolata Nerd Font.
icon: "\uf03e"
settings: true
+ group: "Appearance"
keywords: ["background", "screen", "monitor", "wallp", "wallhaven", "horizontal", "vertical"]
function refresh() { Wallpapers.refresh(); }
diff --git a/desktop/modules/assistant/AssistantModule.qml b/desktop/modules/assistant/AssistantModule.qml
index bd3e270..e89fe96 100644
--- a/desktop/modules/assistant/AssistantModule.qml
+++ b/desktop/modules/assistant/AssistantModule.qml
@@ -25,6 +25,7 @@ Module {
// nf-fa-comments, present in Inconsolata Nerd Font.
icon: "\uf086"
settings: true
+ group: "Assistant"
keywords: ["llm", "model", "llama", "server", "prompt", "temperature", "thinking",
"rounds", "tools", "environment", "daemon", "restart"]
diff --git a/desktop/modules/assistant/PresetsModule.qml b/desktop/modules/assistant/PresetsModule.qml
index 9490bf7..8617b02 100644
--- a/desktop/modules/assistant/PresetsModule.qml
+++ b/desktop/modules/assistant/PresetsModule.qml
@@ -22,6 +22,7 @@ Module {
// nf-fa-lightbulb_o, present in Inconsolata Nerd Font.
icon: ""
settings: true
+ group: "Assistant"
keywords: ["assistant", "canvas", "ask", "question", "prompt", "summarize", "files"]
searchItems: Presets.list(Prefs.presets).map((p, i) => ({ text: p.label + ": " + p.prompt, key: "preset:" + i }))
diff --git a/desktop/modules/autostart/AutostartModule.qml b/desktop/modules/autostart/AutostartModule.qml
index 24c69da..9bbe54b 100644
--- a/desktop/modules/autostart/AutostartModule.qml
+++ b/desktop/modules/autostart/AutostartModule.qml
@@ -24,6 +24,7 @@ Module {
// nf-fa-rocket, present in Inconsolata Nerd Font.
icon: ""
settings: true
+ group: "Desktop"
keywords: ["login", "startup", "launch", "exec", "daemon", "session",
"workspace", "silent", "scratchpad", "autostart.lua", "hyprland"]
diff --git a/desktop/modules/git/GitModule.qml b/desktop/modules/git/GitModule.qml
index 6aa0bc6..bd0be71 100644
--- a/desktop/modules/git/GitModule.qml
+++ b/desktop/modules/git/GitModule.qml
@@ -23,6 +23,7 @@ Module {
// nf-dev-git, present in Inconsolata Nerd Font.
icon: ""
settings: true
+ group: "Account"
keywords: ["gitconfig"]
// Every value, as the page lists it; key is the row's tag in GitPage.
diff --git a/desktop/modules/user/UserModule.qml b/desktop/modules/user/UserModule.qml
index 0d96050..79f1be5 100644
--- a/desktop/modules/user/UserModule.qml
+++ b/desktop/modules/user/UserModule.qml
@@ -21,6 +21,7 @@ Module {
// nf-fa-user, present in Inconsolata Nerd Font.
icon: "\uf007"
settings: true
+ group: "Account"
keywords: ["name", "email", "avatar", "picture", "photo", "language", "location",
"signing", "key", "gpg", "accountsservice"]