From 97181a065e49fa07f07e97f13fe7e1960ebff679 Mon Sep 17 00:00:00 2001 From: Mestane Date: Wed, 24 Jun 2026 14:03:33 +0000 Subject: [PATCH 01/57] feat(nexus): add settings search (page jump) --- modules/nexus/NexusState.qml | 2 + modules/nexus/SettingsIndex.qml | 117 +++++++++++++++++++++++++ modules/nexus/SettingsSearcher.qml | 14 +++ modules/nexus/navpane/NavLocations.qml | 88 ++++++++++++++++++- modules/nexus/navpane/SearchBar.qml | 6 ++ 5 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 modules/nexus/SettingsIndex.qml create mode 100644 modules/nexus/SettingsSearcher.qml diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index 807aa756b..d3ac0bdcb 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -9,6 +9,8 @@ QtObject { property int currentPageIdx property list subPageIdxStack property bool searchOpen + property string searchText + property string searchAnchor property string selectedWallpaperCategory property BluetoothDevice selectedBtDevice diff --git a/modules/nexus/SettingsIndex.qml b/modules/nexus/SettingsIndex.qml new file mode 100644 index 000000000..3ee345a62 --- /dev/null +++ b/modules/nexus/SettingsIndex.qml @@ -0,0 +1,117 @@ +pragma Singleton + +import QtQuick +import Quickshell + +// A flat index of searchable settings. Each entry points at the page that hosts +// it (pageIdx matches PageCompRegistry.pageComps) so the search bar can jump +// straight there. keywords are extra terms that should match but aren't shown. +// +// To make a new setting searchable, add a SettingEntry here. Stage 2 will also +// use the anchor field to scroll to and highlight the exact row. +Singleton { + id: root + + readonly property list entries: [ + // Audio (pageComps[3]) + SettingEntry { + pageIdx: 3 + page: qsTr("Audio") + title: qsTr("Output volume") + description: qsTr("Speaker and headphone level") + keywords: "sound speaker headphone output loudness" + anchor: "audio-output" + }, + SettingEntry { + pageIdx: 3 + page: qsTr("Audio") + title: qsTr("Input volume") + description: qsTr("Microphone level") + keywords: "microphone mic input recording" + anchor: "audio-input" + }, + SettingEntry { + pageIdx: 3 + page: qsTr("Audio") + title: qsTr("App volumes") + description: qsTr("Per-application volume mixer") + keywords: "mixer per app application streams" + anchor: "audio-app-volumes" + }, + + // Services (pageComps[8]) + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Media refresh") + description: qsTr("How often the media position updates") + keywords: "media player position polling interval mpris" + anchor: "services-media-refresh" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("System stats refresh") + description: qsTr("CPU, memory and GPU update interval") + keywords: "cpu memory ram gpu stats resources polling interval" + anchor: "services-stats-refresh" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Wi-Fi rescan") + description: qsTr("How often available networks are rescanned") + keywords: "wifi wireless network rescan scan interval" + anchor: "services-wifi-rescan" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Lyrics backend") + description: qsTr("Source used to fetch synced lyrics") + keywords: "lyrics synced lrclib netease music" + anchor: "services-lyrics-backend" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Default player") + description: qsTr("Preferred media player when several are open") + keywords: "media player default preferred mpris" + anchor: "services-default-player" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Volume step") + description: qsTr("Amount the volume changes per scroll") + keywords: "volume step increment scroll audio" + anchor: "services-volume-step" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Brightness step") + description: qsTr("Amount the brightness changes per scroll") + keywords: "brightness step increment scroll backlight" + anchor: "services-brightness-step" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Max volume") + description: qsTr("Upper limit for output volume") + keywords: "volume max maximum limit cap audio" + anchor: "services-max-volume" + } + ] + + component SettingEntry: QtObject { + required property int pageIdx + required property string page + required property string title + property string description + property string keywords + property string anchor + } +} diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml new file mode 100644 index 000000000..540e342e9 --- /dev/null +++ b/modules/nexus/SettingsSearcher.qml @@ -0,0 +1,14 @@ +pragma Singleton + +import qs.utils +import qs.modules.nexus + +// Fuzzy searcher over the settings index. Reuses the shell's Searcher util (the +// same engine the launcher uses) so behaviour stays consistent. Title matches +// weigh heaviest, then keywords, then the description. +Searcher { + list: SettingsIndex.entries + useFuzzy: true + keys: ["title", "keywords", "description"] + weights: [0.6, 0.3, 0.1] +} diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index d559c4439..0a3422094 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -13,6 +13,10 @@ VerticalFadeFlickable { required property NexusState nState + readonly property string search: nState.searchText + readonly property bool searching: search.length > 0 + readonly property var results: searching ? SettingsSearcher.query(search) : [] + topMargin: Tokens.padding.large bottomMargin: Tokens.padding.large contentHeight: content.implicitHeight @@ -27,7 +31,7 @@ VerticalFadeFlickable { Repeater { id: list - model: PageRegistry.pages + model: root.searching ? [] : PageRegistry.pages StyledRect { id: item @@ -36,8 +40,8 @@ VerticalFadeFlickable { required property int index readonly property bool isCurrentPage: index === root.nState.currentPageIdx - readonly property bool isCategoryStart: index === 0 || PageRegistry.pages[index - 1].category !== modelData.category - readonly property bool isCategoryEnd: index === list.model.length - 1 || PageRegistry.pages[index + 1].category !== modelData.category + readonly property bool isCategoryStart: index === 0 || PageRegistry.pages[index - 1]?.category !== modelData.category + readonly property bool isCategoryEnd: index === list.model.length - 1 || PageRegistry.pages[index + 1]?.category !== modelData.category Layout.fillWidth: true Layout.topMargin: index !== 0 && isCategoryStart ? Tokens.spacing.medium : 0 @@ -120,6 +124,84 @@ VerticalFadeFlickable { } } } + + Repeater { + id: resultList + + model: root.results + + StyledRect { + id: result + + required property var modelData + required property int index + + Layout.fillWidth: true + implicitHeight: { + const h = resultLayout.implicitHeight + resultLayout.anchors.margins * 2; + return h % 2 === 0 ? h : h + 1; + } + + radius: Tokens.rounding.medium + color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + + StateLayer { + anchors.fill: parent + radius: parent.radius + + onClicked: { + root.nState.currentPageIdx = result.modelData.pageIdx; + root.nState.searchAnchor = result.modelData.anchor; + } + } + + RowLayout { + id: resultLayout + + anchors.fill: parent + anchors.margins: Tokens.padding.large + spacing: Tokens.spacing.medium + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + text: "search" + color: Colours.palette.m3onSurfaceVariant + fontStyle: Tokens.font.icon.medium + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + StyledText { + Layout.fillWidth: true + text: result.modelData.title + font: Tokens.font.body.medium + elide: Text.ElideRight + } + + StyledText { + Layout.fillWidth: true + text: `${result.modelData.page} • ${result.modelData.description}` + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.label.small + elide: Text.ElideRight + } + } + } + } + } + + StyledText { + Layout.fillWidth: true + Layout.topMargin: Tokens.padding.large + visible: root.searching && root.results.length === 0 + + text: qsTr("No matching settings") + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.body.medium + horizontalAlignment: Text.AlignHCenter + } } component RadiusBehavior: Behavior { diff --git a/modules/nexus/navpane/SearchBar.qml b/modules/nexus/navpane/SearchBar.qml index 6f35061d8..3bf390789 100644 --- a/modules/nexus/navpane/SearchBar.qml +++ b/modules/nexus/navpane/SearchBar.qml @@ -59,6 +59,12 @@ StyledRect { property: "searchOpen" value: searchField.text.length > 0 } + + Binding { + target: root.nState + property: "searchText" + value: searchField.text + } } IconButton { From bc385853e8a1d9ee2d6963b4103e3d75f434dd7d Mon Sep 17 00:00:00 2001 From: Mestane Date: Wed, 24 Jun 2026 14:26:04 +0000 Subject: [PATCH 02/57] feat(nexus): scroll to the matching setting on search --- modules/nexus/common/ConnectedRect.qml | 2 ++ modules/nexus/common/PageBase.qml | 32 ++++++++++++++++++++++++++ modules/nexus/common/ToggleRow.qml | 2 ++ modules/nexus/pages/AudioPage.qml | 2 ++ modules/nexus/pages/ServicesPage.qml | 8 +++++++ 5 files changed, 46 insertions(+) diff --git a/modules/nexus/common/ConnectedRect.qml b/modules/nexus/common/ConnectedRect.qml index df5b21ae4..8c4510842 100644 --- a/modules/nexus/common/ConnectedRect.qml +++ b/modules/nexus/common/ConnectedRect.qml @@ -6,6 +6,8 @@ import qs.services StyledRect { property bool first property bool last + // Identifier used by the settings search to scroll to this row. + property string settingAnchor color: Colours.tPalette.m3surfaceContainer topLeftRadius: first ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 4906e90a9..877446488 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -20,6 +20,38 @@ ColumnLayout { default property Item contentChild + // When the settings search jumps to this page, scroll to the matching row. + function scrollToAnchor(anchor: string): void { + if (!anchor || !contentChild) + return; + const row = findAnchor(contentChild, anchor); + if (!row) + return; + const pos = row.mapToItem(flickable.contentItem, 0, 0); + const target = Math.max(0, Math.min(pos.y - Tokens.padding.large, flickable.contentHeight - flickable.height)); + flickable.contentY = target; + } + + function findAnchor(item: Item, anchor: string): Item { + if (!item) + return null; + if (item.settingAnchor !== undefined && item.settingAnchor === anchor) // qmllint disable missing-property + return item; + const kids = item.children; + for (let i = 0; i < kids.length; i++) { + const found = findAnchor(kids[i], anchor); + if (found) + return found; + } + return null; + } + + Component.onCompleted: if (nState.searchAnchor) + Qt.callLater(() => { + root.scrollToAnchor(nState.searchAnchor); + nState.searchAnchor = ""; + }) + spacing: Tokens.spacing.extraLargeIncreased MouseArea { // Prevent clicks from reaching flickable diff --git a/modules/nexus/common/ToggleRow.qml b/modules/nexus/common/ToggleRow.qml index 95198fe8a..fd301aa76 100644 --- a/modules/nexus/common/ToggleRow.qml +++ b/modules/nexus/common/ToggleRow.qml @@ -11,6 +11,8 @@ StyledSwitch { property string subtext property alias first: bg.first property alias last: bg.last + // Identifier used by the settings search to scroll to this row. + property string settingAnchor readonly property alias bg: bg Layout.fillWidth: true diff --git a/modules/nexus/pages/AudioPage.qml b/modules/nexus/pages/AudioPage.qml index 09918df01..a5b0905ee 100644 --- a/modules/nexus/pages/AudioPage.qml +++ b/modules/nexus/pages/AudioPage.qml @@ -22,6 +22,7 @@ PageBase { // Output SliderRow { first: true + settingAnchor: "audio-output" icon: Icons.getVolumeIcon(Audio.volume, Audio.muted) label: qsTr("Output") valueLabel: Math.round(value * 100) + "%" @@ -49,6 +50,7 @@ PageBase { SliderRow { Layout.topMargin: Tokens.spacing.large - parent.spacing first: true + settingAnchor: "audio-input" icon: Icons.getMicVolumeIcon(Audio.sourceVolume, Audio.sourceMuted) label: qsTr("Input") valueLabel: Math.round(value * 100) + "%" diff --git a/modules/nexus/pages/ServicesPage.qml b/modules/nexus/pages/ServicesPage.qml index c8ea20452..5cecb6233 100644 --- a/modules/nexus/pages/ServicesPage.qml +++ b/modules/nexus/pages/ServicesPage.qml @@ -99,6 +99,7 @@ PageBase { StepperRow { first: true + settingAnchor: "services-media-refresh" label: qsTr("Media refresh") subtext: qsTr("How often the media position updates (ms)") value: GlobalConfig.dashboard.mediaUpdateInterval @@ -109,6 +110,7 @@ PageBase { } StepperRow { + settingAnchor: "services-stats-refresh" label: qsTr("System stats refresh") subtext: qsTr("CPU, memory and GPU update interval (seconds)") value: GlobalConfig.dashboard.resourceUpdateInterval / 1000 @@ -120,6 +122,7 @@ PageBase { StepperRow { last: true + settingAnchor: "services-wifi-rescan" label: qsTr("Wi-Fi rescan") subtext: qsTr("How often available networks are rescanned (seconds)") value: GlobalConfig.nexus.networkRescanInterval / 1000 @@ -136,6 +139,7 @@ PageBase { SelectRow { first: true + settingAnchor: "services-lyrics-backend" label: qsTr("Lyrics backend") subtext: qsTr("Source used to fetch synced lyrics") menuItems: root.lyricsItems @@ -145,6 +149,7 @@ PageBase { SelectRow { last: true + settingAnchor: "services-default-player" label: qsTr("Default player") subtext: qsTr("Preferred media player when several are open") menuItems: playerVariants.instances @@ -161,6 +166,7 @@ PageBase { StepperRow { first: true + settingAnchor: "services-volume-step" label: qsTr("Volume step") subtext: qsTr("Amount the volume changes per scroll (%)") value: Math.round(GlobalConfig.services.audioIncrement * 100) @@ -171,6 +177,7 @@ PageBase { } StepperRow { + settingAnchor: "services-brightness-step" label: qsTr("Brightness step") subtext: qsTr("Amount the brightness changes per scroll (%)") value: Math.round(GlobalConfig.services.brightnessIncrement * 100) @@ -182,6 +189,7 @@ PageBase { StepperRow { last: true + settingAnchor: "services-max-volume" label: qsTr("Max volume") subtext: qsTr("Upper limit for output volume (%)") value: Math.round(GlobalConfig.services.maxVolume * 100) From 604c67fcf06cf1582d9fe606c4d3871850ddc83b Mon Sep 17 00:00:00 2001 From: Mestane Date: Wed, 24 Jun 2026 19:48:35 +0000 Subject: [PATCH 03/57] feat(nexus): highlight the matching setting on search --- modules/nexus/common/ConnectedRect.qml | 38 ++++++++++++++++++++++++++ modules/nexus/common/PageBase.qml | 2 ++ modules/nexus/common/ToggleRow.qml | 5 ++++ 3 files changed, 45 insertions(+) diff --git a/modules/nexus/common/ConnectedRect.qml b/modules/nexus/common/ConnectedRect.qml index 8c4510842..e7d5e7b82 100644 --- a/modules/nexus/common/ConnectedRect.qml +++ b/modules/nexus/common/ConnectedRect.qml @@ -4,14 +4,52 @@ import qs.components import qs.services StyledRect { + id: root + property bool first property bool last // Identifier used by the settings search to scroll to this row. property string settingAnchor + // Briefly flash the row, used when the settings search jumps to it. + function flashHighlight(): void { + flash.restart(); + } + color: Colours.tPalette.m3surfaceContainer topLeftRadius: first ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall topRightRadius: first ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall bottomLeftRadius: last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall bottomRightRadius: last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall + + StyledRect { + id: highlight + + anchors.fill: parent + + radius: parent.radius + topLeftRadius: parent.topLeftRadius + topRightRadius: parent.topRightRadius + bottomLeftRadius: parent.bottomLeftRadius + bottomRightRadius: parent.bottomRightRadius + color: Colours.palette.m3primary + opacity: 0 + + SequentialAnimation { + id: flash + + Anim { + target: highlight + property: "opacity" + to: 0.12 + duration: Tokens.anim.durations.normal + } + Anim { + target: highlight + property: "opacity" + to: 0 + duration: Tokens.anim.durations.large + } + } + } } diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 877446488..4b4f4e4a1 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -30,6 +30,8 @@ ColumnLayout { const pos = row.mapToItem(flickable.contentItem, 0, 0); const target = Math.max(0, Math.min(pos.y - Tokens.padding.large, flickable.contentHeight - flickable.height)); flickable.contentY = target; + if (row.flashHighlight !== undefined) // qmllint disable missing-property + row.flashHighlight(); } function findAnchor(item: Item, anchor: string): Item { diff --git a/modules/nexus/common/ToggleRow.qml b/modules/nexus/common/ToggleRow.qml index fd301aa76..08f01f034 100644 --- a/modules/nexus/common/ToggleRow.qml +++ b/modules/nexus/common/ToggleRow.qml @@ -15,6 +15,11 @@ StyledSwitch { property string settingAnchor readonly property alias bg: bg + // Briefly flash the row, used when the settings search jumps to it. + function flashHighlight(): void { + bg.flashHighlight(); + } + Layout.fillWidth: true horizontalPadding: Tokens.padding.largeIncreased From 62e819488aed9e4867501539b65c7e506eb84429 Mon Sep 17 00:00:00 2001 From: Mestane Date: Wed, 24 Jun 2026 19:55:53 +0000 Subject: [PATCH 04/57] feat(nexus): index all settings pages for search --- modules/nexus/SettingsIndex.qml | 164 ++++++++++++++++++++++ modules/nexus/pages/AppsPage.qml | 1 + modules/nexus/pages/AudioPage.qml | 1 + modules/nexus/pages/BluetoothPage.qml | 3 + modules/nexus/pages/LanguageAndRegion.qml | 3 + modules/nexus/pages/NetworkPage.qml | 1 + modules/nexus/pages/PanelsPage.qml | 4 + modules/nexus/pages/ServicesPage.qml | 4 + modules/nexus/pages/WallpaperAndStyle.qml | 3 + 9 files changed, 184 insertions(+) diff --git a/modules/nexus/SettingsIndex.qml b/modules/nexus/SettingsIndex.qml index 3ee345a62..e86ed271e 100644 --- a/modules/nexus/SettingsIndex.qml +++ b/modules/nexus/SettingsIndex.qml @@ -103,6 +103,170 @@ Singleton { description: qsTr("Upper limit for output volume") keywords: "volume max maximum limit cap audio" anchor: "services-max-volume" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Notifications") + description: qsTr("Notification behaviour and history") + keywords: "notifications notify popup history dnd" + anchor: "services-notifications" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Visualiser bars") + description: qsTr("Number of bars in the audio visualisers") + keywords: "visualiser visualizer bars audio spectrum cava" + anchor: "services-visualiser-bars" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("Smart colour scheme") + description: qsTr("Derive theme mode and variant from the wallpaper") + keywords: "smart colour color scheme theme wallpaper auto" + anchor: "services-smart-scheme" + }, + SettingEntry { + pageIdx: 8 + page: qsTr("Services") + title: qsTr("GPU") + description: qsTr("Override for GPU type") + keywords: "gpu graphics nvidia amd intel monitoring" + anchor: "services-gpu" + }, + + // Wallpaper & style (pageComps[0]) + SettingEntry { + pageIdx: 0 + page: qsTr("Wallpaper & style") + title: qsTr("Display wallpaper") + description: qsTr("Show a wallpaper on the desktop") + keywords: "wallpaper background image display desktop" + anchor: "style-display-wallpaper" + }, + SettingEntry { + pageIdx: 0 + page: qsTr("Wallpaper & style") + title: qsTr("Transparency") + description: qsTr("Translucent panels and surfaces") + keywords: "transparency translucent opacity blur" + anchor: "style-transparency" + }, + SettingEntry { + pageIdx: 0 + page: qsTr("Wallpaper & style") + title: qsTr("Dark theme") + description: qsTr("Use a dark colour scheme") + keywords: "dark theme light mode colour scheme" + anchor: "style-dark-theme" + }, + + // Network (pageComps[1]) + SettingEntry { + pageIdx: 1 + page: qsTr("Network") + title: qsTr("Wi-Fi") + description: qsTr("Enable or disable wireless networking") + keywords: "wifi wireless network internet connection" + anchor: "network-wifi" + }, + + // Bluetooth (pageComps[2]) + SettingEntry { + pageIdx: 2 + page: qsTr("Bluetooth") + title: qsTr("Bluetooth") + description: qsTr("Enable or disable Bluetooth") + keywords: "bluetooth wireless devices pairing" + anchor: "bluetooth-enabled" + }, + SettingEntry { + pageIdx: 2 + page: qsTr("Bluetooth") + title: qsTr("Discoverable") + description: qsTr("Let other devices find this one") + keywords: "bluetooth discoverable visible find devices" + anchor: "bluetooth-discoverable" + }, + SettingEntry { + pageIdx: 2 + page: qsTr("Bluetooth") + title: qsTr("Pairable") + description: qsTr("Allow new devices to pair") + keywords: "bluetooth pairable pairing connect devices" + anchor: "bluetooth-pairable" + }, + + // Panels (pageComps[6]) + SettingEntry { + pageIdx: 6 + page: qsTr("Panels") + title: qsTr("Dashboard") + description: qsTr("Dashboard panel settings") + keywords: "dashboard panel widgets overview" + anchor: "panels-dashboard" + }, + SettingEntry { + pageIdx: 6 + page: qsTr("Panels") + title: qsTr("Taskbar") + description: qsTr("Taskbar panel settings") + keywords: "taskbar bar dock panel windows" + anchor: "panels-taskbar" + }, + SettingEntry { + pageIdx: 6 + page: qsTr("Panels") + title: qsTr("Launcher") + description: qsTr("Launcher panel settings") + keywords: "launcher search apps menu run" + anchor: "panels-launcher" + }, + SettingEntry { + pageIdx: 6 + page: qsTr("Panels") + title: qsTr("Sidebar") + description: qsTr("Sidebar panel settings") + keywords: "sidebar panel notifications tray" + anchor: "panels-sidebar" + }, + + // Apps (pageComps[7]) + SettingEntry { + pageIdx: 7 + page: qsTr("Apps") + title: qsTr("All apps") + description: qsTr("Browse every installed application") + keywords: "apps applications installed list browse all" + anchor: "apps-all" + }, + + // Language & region (pageComps[9]) + SettingEntry { + pageIdx: 9 + page: qsTr("Language & region") + title: qsTr("Temperature") + description: qsTr("Temperature unit") + keywords: "temperature unit celsius fahrenheit weather" + anchor: "lang-temperature" + }, + SettingEntry { + pageIdx: 9 + page: qsTr("Language & region") + title: qsTr("System temperatures") + description: qsTr("Unit for system sensor temperatures") + keywords: "system temperature sensor cpu gpu celsius fahrenheit" + anchor: "lang-system-temperature" + }, + SettingEntry { + pageIdx: 9 + page: qsTr("Language & region") + title: qsTr("Clock format") + description: qsTr("12 or 24 hour clock") + keywords: "clock time format 12 24 hour am pm" + anchor: "lang-clock-format" } ] diff --git a/modules/nexus/pages/AppsPage.qml b/modules/nexus/pages/AppsPage.qml index 8aa1b5f55..ab4f90014 100644 --- a/modules/nexus/pages/AppsPage.qml +++ b/modules/nexus/pages/AppsPage.qml @@ -68,6 +68,7 @@ PageBase { first: true last: true icon: "apps" + settingAnchor: "apps-all" label: qsTr("All apps") status: qsTr("Browse installed apps, set favourites and hidden") onClicked: root.nState.openSubPage(1) diff --git a/modules/nexus/pages/AudioPage.qml b/modules/nexus/pages/AudioPage.qml index a5b0905ee..4a4fbd13f 100644 --- a/modules/nexus/pages/AudioPage.qml +++ b/modules/nexus/pages/AudioPage.qml @@ -81,6 +81,7 @@ PageBase { implicitHeight: appLayout.implicitHeight + appLayout.anchors.margins * 2 first: true last: true + settingAnchor: "audio-app-volumes" StateLayer { onClicked: root.nState.openSubPage(1) diff --git a/modules/nexus/pages/BluetoothPage.qml b/modules/nexus/pages/BluetoothPage.qml index 11e2b1cf3..431690bac 100644 --- a/modules/nexus/pages/BluetoothPage.qml +++ b/modules/nexus/pages/BluetoothPage.qml @@ -27,6 +27,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "bluetooth-enabled" text: qsTr("Bluetooth") font: Tokens.font.body.medium horizontalPadding: Tokens.padding.largeIncreased @@ -210,6 +211,7 @@ PageBase { Layout.topMargin: Tokens.spacing.large - parent.spacing first: true + settingAnchor: "bluetooth-discoverable" text: qsTr("Discoverable") subtext: qsTr("Allow nearby devices to find this one") enabled: root.btEnabled @@ -227,6 +229,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "bluetooth-pairable" text: qsTr("Pairable") subtext: qsTr("Allow nearby devices to pair with this one") enabled: root.btEnabled diff --git a/modules/nexus/pages/LanguageAndRegion.qml b/modules/nexus/pages/LanguageAndRegion.qml index 9668f59ff..ff8daa0e3 100644 --- a/modules/nexus/pages/LanguageAndRegion.qml +++ b/modules/nexus/pages/LanguageAndRegion.qml @@ -138,6 +138,7 @@ PageBase { SelectRow { first: true + settingAnchor: "lang-temperature" label: qsTr("Temperature") subtext: qsTr("Units for weather temperatures") menuItems: root.tempItems @@ -147,6 +148,7 @@ PageBase { SelectRow { last: true + settingAnchor: "lang-system-temperature" label: qsTr("System temperatures") subtext: qsTr("Units for CPU and GPU temperatures") menuItems: root.tempItems @@ -162,6 +164,7 @@ PageBase { SelectRow { first: true last: true + settingAnchor: "lang-clock-format" label: qsTr("Clock format") subtext: qsTr("How times are shown across the shell") menuItems: root.clockItems diff --git a/modules/nexus/pages/NetworkPage.qml b/modules/nexus/pages/NetworkPage.qml index 4e8f413bf..208f5568e 100644 --- a/modules/nexus/pages/NetworkPage.qml +++ b/modules/nexus/pages/NetworkPage.qml @@ -62,6 +62,7 @@ PageBase { ToggleRow { Layout.topMargin: Nmcli.hasAvailableEthernet ? Tokens.spacing.large : 0 first: true + settingAnchor: "network-wifi" text: qsTr("Wi-Fi") font: Tokens.font.body.medium horizontalPadding: Tokens.padding.largeIncreased diff --git a/modules/nexus/pages/PanelsPage.qml b/modules/nexus/pages/PanelsPage.qml index d49879bec..1f7498b3e 100644 --- a/modules/nexus/pages/PanelsPage.qml +++ b/modules/nexus/pages/PanelsPage.qml @@ -16,6 +16,7 @@ PageBase { NavRow { first: true icon: "dashboard" + settingAnchor: "panels-dashboard" label: qsTr("Dashboard") status: Config.dashboard.enabled ? qsTr("Enabled") : qsTr("Disabled") onClicked: root.nState.openSubPage(1) @@ -23,6 +24,7 @@ PageBase { NavRow { icon: "dock_to_bottom" + settingAnchor: "panels-taskbar" label: qsTr("Taskbar") status: Config.bar.persistent ? qsTr("Always visible") : Config.bar.showOnHover ? qsTr("Reveal on hover") : qsTr("Reveal on drag") onClicked: root.nState.openSubPage(2) @@ -30,6 +32,7 @@ PageBase { NavRow { icon: "apps" + settingAnchor: "panels-launcher" label: qsTr("Launcher") status: Config.launcher.enabled ? qsTr("Enabled") : qsTr("Disabled") onClicked: root.nState.openSubPage(3) @@ -38,6 +41,7 @@ PageBase { NavRow { last: true icon: "dock_to_right" + settingAnchor: "panels-sidebar" label: qsTr("Sidebar") status: Config.sidebar.enabled ? qsTr("Enabled") : qsTr("Disabled") onClicked: root.nState.openSubPage(4) diff --git a/modules/nexus/pages/ServicesPage.qml b/modules/nexus/pages/ServicesPage.qml index 5cecb6233..1f6043bb7 100644 --- a/modules/nexus/pages/ServicesPage.qml +++ b/modules/nexus/pages/ServicesPage.qml @@ -87,6 +87,7 @@ PageBase { first: true last: true icon: "notifications" + settingAnchor: "services-notifications" label: qsTr("Notifications") status: qsTr("Notifications, toasts, timeouts") onClicked: root.nState.openSubPage(1) @@ -206,6 +207,7 @@ PageBase { StepperRow { first: true + settingAnchor: "services-visualiser-bars" label: qsTr("Visualiser bars") subtext: qsTr("Number of bars in the audio visualisers") value: GlobalConfig.services.visualiserBars @@ -216,6 +218,7 @@ PageBase { } ToggleRow { + settingAnchor: "services-smart-scheme" text: qsTr("Smart colour scheme") subtext: qsTr("Derive theme mode and variant from the wallpaper") checked: GlobalConfig.services.smartScheme @@ -224,6 +227,7 @@ PageBase { SelectRow { last: true + settingAnchor: "services-gpu" label: qsTr("GPU") subtext: Gpu.name ? qsTr("Monitoring: %1").arg(Gpu.name) : qsTr("Override for GPU type") menuOnTop: true diff --git a/modules/nexus/pages/WallpaperAndStyle.qml b/modules/nexus/pages/WallpaperAndStyle.qml index a02025333..652c37e11 100644 --- a/modules/nexus/pages/WallpaperAndStyle.qml +++ b/modules/nexus/pages/WallpaperAndStyle.qml @@ -172,6 +172,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "style-display-wallpaper" text: qsTr("Display wallpaper") checked: Config.background.wallpaperEnabled onToggled: GlobalConfig.background.wallpaperEnabled = checked @@ -180,6 +181,7 @@ PageBase { ToggleRow { Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing + settingAnchor: "style-transparency" text: qsTr("Transparency") subtext: qsTr("Base %1, layers %2").arg(Colours.transparency.base).arg(Colours.transparency.layers) checked: Colours.transparency.enabled @@ -190,6 +192,7 @@ PageBase { Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing last: true + settingAnchor: "style-dark-theme" text: qsTr("Dark theme") checked: !Colours.light onToggled: Colours.setMode(checked ? "dark" : "light") From 1cff469d5c47764d9d246ae7cd0f0c354bce5d5a Mon Sep 17 00:00:00 2001 From: Mestane Date: Wed, 24 Jun 2026 20:39:29 +0000 Subject: [PATCH 05/57] feat(nexus): index every settings page with breadcrumb trees and deep-link --- modules/nexus/NexusState.qml | 25 +- modules/nexus/SettingsIndex.qml | 1109 ++++++++++++++--- modules/nexus/SettingsSearcher.qml | 4 +- modules/nexus/common/PageBase.qml | 28 +- modules/nexus/navpane/NavLocations.qml | 72 +- modules/nexus/pages/AppsPage.qml | 2 +- modules/nexus/pages/AudioPage.qml | 5 +- modules/nexus/pages/BluetoothPage.qml | 2 +- modules/nexus/pages/LanguageAndRegion.qml | 2 +- modules/nexus/pages/NetworkPage.qml | 2 +- modules/nexus/pages/ServicesPage.qml | 6 +- modules/nexus/pages/panels/DashboardPanel.qml | 13 + modules/nexus/pages/panels/LauncherPanel.qml | 12 + modules/nexus/pages/panels/SidebarPanel.qml | 2 + modules/nexus/pages/panels/TaskbarPanel.qml | 11 + .../pages/panels/taskbar/BarActiveWindow.qml | 4 + .../nexus/pages/panels/taskbar/BarClock.qml | 3 + .../pages/panels/taskbar/BarStatusIcons.qml | 9 + .../nexus/pages/panels/taskbar/BarTray.qml | 4 + .../pages/panels/taskbar/BarWorkspaces.qml | 8 + .../pages/services/NotificationsPage.qml | 17 + 21 files changed, 1139 insertions(+), 201 deletions(-) diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index d3ac0bdcb..3f98f7c6a 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -8,6 +8,7 @@ QtObject { property bool animatingContainer property int currentPageIdx property list subPageIdxStack + property list _pendingSubPath property bool searchOpen property string searchText property string searchAnchor @@ -31,5 +32,27 @@ QtObject { subPageIdxStack.pop(); } - onCurrentPageIdxChanged: subPageIdxStack.length = 0 + // Jump straight to a setting from search: open the page, then any sub-pages + // along subPath, then let the page scroll to the anchor. subPageIdxStack is + // filled directly so a freshly loaded StackPage opens the whole chain at + // once (see StackPage.Component.onCompleted), which avoids the half-open + // state that firing openSubPage signals one by one would cause. + function jumpToSetting(pageIdx: int, subPath: var, anchor: string): void { + searchAnchor = anchor; + if (currentPageIdx === pageIdx) { + // Already on the page: reset and re-open the sub-page chain live. + while (subPageIdxStack.length > 0) + closeSubPage(); + for (let i = 0; i < subPath.length; i++) + openSubPage(subPath[i]); + } else { + _pendingSubPath = subPath.slice(); + currentPageIdx = pageIdx; + } + } + + onCurrentPageIdxChanged: { + subPageIdxStack = _pendingSubPath; + _pendingSubPath = []; + } } diff --git a/modules/nexus/SettingsIndex.qml b/modules/nexus/SettingsIndex.qml index e86ed271e..d6be2fa75 100644 --- a/modules/nexus/SettingsIndex.qml +++ b/modules/nexus/SettingsIndex.qml @@ -3,278 +3,1069 @@ pragma Singleton import QtQuick import Quickshell -// A flat index of searchable settings. Each entry points at the page that hosts -// it (pageIdx matches PageCompRegistry.pageComps) so the search bar can jump -// straight there. keywords are extra terms that should match but aren't shown. +// A flat index of every searchable setting. pageIdx matches +// PageCompRegistry.pageComps; subPath is the chain of sub-pages to open. The +// crumb* lists hold the icon + label for each step of the path, shown as a +// vertical breadcrumb in the search results. // -// To make a new setting searchable, add a SettingEntry here. Stage 2 will also -// use the anchor field to scroll to and highlight the exact row. +// To make a new setting searchable add a SettingEntry here and give the row a +// matching settingAnchor. Singleton { id: root readonly property list entries: [ - // Audio (pageComps[3]) + + // Wallpaper & style + SettingEntry { + pageIdx: 0 + subPath: [] + crumbIcons: ["palette"] + crumbLabels: ["Wallpaper & style"] + title: qsTr("Display wallpaper") + keywords: "display style wallpaper" + anchor: "style-display-wallpaper" + }, + SettingEntry { + pageIdx: 0 + subPath: [] + crumbIcons: ["palette"] + crumbLabels: ["Wallpaper & style"] + title: qsTr("Transparency") + keywords: "style transparency wallpaper" + anchor: "style-transparency" + }, + SettingEntry { + pageIdx: 0 + subPath: [] + crumbIcons: ["palette"] + crumbLabels: ["Wallpaper & style"] + title: qsTr("Dark theme") + keywords: "dark style theme wallpaper" + anchor: "style-dark-theme" + }, + + // Network + SettingEntry { + pageIdx: 1 + subPath: [] + crumbIcons: ["wifi"] + crumbLabels: ["Network"] + title: qsTr("Wi-Fi") + keywords: "network wi-fi" + anchor: "network-wi-fi" + }, + + // Bluetooth + SettingEntry { + pageIdx: 2 + subPath: [] + crumbIcons: ["devices_other"] + crumbLabels: ["Bluetooth"] + title: qsTr("Bluetooth") + keywords: "bluetooth" + anchor: "bluetooth-bluetooth" + }, + SettingEntry { + pageIdx: 2 + subPath: [] + crumbIcons: ["devices_other"] + crumbLabels: ["Bluetooth"] + title: qsTr("Discoverable") + keywords: "bluetooth discoverable" + anchor: "bluetooth-discoverable" + }, + SettingEntry { + pageIdx: 2 + subPath: [] + crumbIcons: ["devices_other"] + crumbLabels: ["Bluetooth"] + title: qsTr("Pairable") + keywords: "bluetooth pairable" + anchor: "bluetooth-pairable" + }, + + // Audio SettingEntry { pageIdx: 3 - page: qsTr("Audio") - title: qsTr("Output volume") - description: qsTr("Speaker and headphone level") - keywords: "sound speaker headphone output loudness" + subPath: [] + crumbIcons: ["volume_up"] + crumbLabels: ["Audio"] + title: qsTr("Output") + keywords: "audio output" anchor: "audio-output" }, SettingEntry { pageIdx: 3 - page: qsTr("Audio") - title: qsTr("Input volume") - description: qsTr("Microphone level") - keywords: "microphone mic input recording" + subPath: [] + crumbIcons: ["volume_up"] + crumbLabels: ["Audio"] + title: qsTr("Input") + keywords: "audio input" anchor: "audio-input" }, + + // Panels SettingEntry { - pageIdx: 3 - page: qsTr("Audio") - title: qsTr("App volumes") - description: qsTr("Per-application volume mixer") - keywords: "mixer per app application streams" - anchor: "audio-app-volumes" + pageIdx: 6 + subPath: [] + crumbIcons: ["dock_to_bottom"] + crumbLabels: ["Panels"] + title: qsTr("Dashboard") + keywords: "dashboard panels" + anchor: "panels-dashboard" + }, + SettingEntry { + pageIdx: 6 + subPath: [] + crumbIcons: ["dock_to_bottom"] + crumbLabels: ["Panels"] + title: qsTr("Taskbar") + keywords: "panels taskbar" + anchor: "panels-taskbar" + }, + SettingEntry { + pageIdx: 6 + subPath: [] + crumbIcons: ["dock_to_bottom"] + crumbLabels: ["Panels"] + title: qsTr("Launcher") + keywords: "launcher panels" + anchor: "panels-launcher" + }, + SettingEntry { + pageIdx: 6 + subPath: [] + crumbIcons: ["dock_to_bottom"] + crumbLabels: ["Panels"] + title: qsTr("Sidebar") + keywords: "panels sidebar" + anchor: "panels-sidebar" + }, + + // Panels > Dashboard + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Enabled") + keywords: "dashboard enabled panels" + anchor: "dash-enabled" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Show on hover") + keywords: "dashboard hover on panels show" + anchor: "dash-show-on-hover" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Dashboard") + keywords: "dashboard panels" + anchor: "dash-dashboard" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Media") + keywords: "dashboard media panels" + anchor: "dash-media" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Performance") + keywords: "dashboard panels performance" + anchor: "dash-performance" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Weather") + keywords: "dashboard panels weather" + anchor: "dash-weather" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Battery") + keywords: "battery dashboard panels" + anchor: "dash-battery" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("GPU") + keywords: "dashboard gpu panels" + anchor: "dash-gpu" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("CPU") + keywords: "cpu dashboard panels" + anchor: "dash-cpu" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Memory") + keywords: "dashboard memory panels" + anchor: "dash-memory" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Storage") + keywords: "dashboard panels storage" + anchor: "dash-storage" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Network") + keywords: "dashboard network panels" + anchor: "dash-network" + }, + SettingEntry { + pageIdx: 6 + subPath: [1] + crumbIcons: ["dock_to_bottom", "dashboard"] + crumbLabels: ["Panels", "Dashboard"] + title: qsTr("Drag threshold") + keywords: "dashboard drag panels threshold" + anchor: "dash-drag-threshold" }, - // Services (pageComps[8]) + // Panels > Taskbar + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Persistent") + keywords: "panels persistent taskbar" + anchor: "taskbar-persistent" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Show on hover") + keywords: "hover on panels show taskbar" + anchor: "taskbar-show-on-hover" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Drag threshold") + keywords: "drag panels taskbar threshold" + anchor: "taskbar-drag-threshold" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Workspaces") + keywords: "panels taskbar workspaces" + anchor: "taskbar-workspaces" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Active window") + keywords: "active panels taskbar window" + anchor: "taskbar-active-window" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Tray") + keywords: "panels taskbar tray" + anchor: "taskbar-tray" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Status icons") + keywords: "icons panels status taskbar" + anchor: "taskbar-status-icons" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Clock") + keywords: "clock panels taskbar" + anchor: "taskbar-clock" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Workspaces") + keywords: "panels taskbar workspaces" + anchor: "taskbar-workspaces-2" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Volume") + keywords: "panels taskbar volume" + anchor: "taskbar-volume" + }, + SettingEntry { + pageIdx: 6 + subPath: [2] + crumbIcons: ["dock_to_bottom", "dock_to_bottom"] + crumbLabels: ["Panels", "Taskbar"] + title: qsTr("Brightness") + keywords: "brightness panels taskbar" + anchor: "taskbar-brightness" + }, + + // Panels > Launcher + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Enabled") + keywords: "enabled launcher panels" + anchor: "launcher-enabled" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Show on hover") + keywords: "hover launcher on panels show" + anchor: "launcher-show-on-hover" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Max items shown") + keywords: "items launcher max panels shown" + anchor: "launcher-max-items-shown" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Max wallpapers") + keywords: "launcher max panels wallpapers" + anchor: "launcher-max-wallpapers" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Drag threshold") + keywords: "drag launcher panels threshold" + anchor: "launcher-drag-threshold" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Vim keybinds") + keywords: "keybinds launcher panels vim" + anchor: "launcher-vim-keybinds" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Enable dangerous actions") + keywords: "actions dangerous enable launcher panels" + anchor: "launcher-enable-dangerous-actions" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Apps") + keywords: "apps launcher panels" + anchor: "launcher-apps" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Actions") + keywords: "actions launcher panels" + anchor: "launcher-actions" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Schemes") + keywords: "launcher panels schemes" + anchor: "launcher-schemes" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Variants") + keywords: "launcher panels variants" + anchor: "launcher-variants" + }, + SettingEntry { + pageIdx: 6 + subPath: [3] + crumbIcons: ["dock_to_bottom", "apps"] + crumbLabels: ["Panels", "Launcher"] + title: qsTr("Wallpapers") + keywords: "launcher panels wallpapers" + anchor: "launcher-wallpapers" + }, + + // Panels > Sidebar + SettingEntry { + pageIdx: 6 + subPath: [4] + crumbIcons: ["dock_to_bottom", "dock_to_right"] + crumbLabels: ["Panels", "Sidebar"] + title: qsTr("Enabled") + keywords: "enabled panels sidebar" + anchor: "sidebar-enabled" + }, + SettingEntry { + pageIdx: 6 + subPath: [4] + crumbIcons: ["dock_to_bottom", "dock_to_right"] + crumbLabels: ["Panels", "Sidebar"] + title: qsTr("Drag threshold") + keywords: "drag panels sidebar threshold" + anchor: "sidebar-drag-threshold" + }, + + // Panels > Taskbar > Workspaces + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Shown") + keywords: "panels shown taskbar workspaces" + anchor: "bar-ws-shown" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Active indicator") + keywords: "active indicator panels taskbar workspaces" + anchor: "bar-ws-active-indicator" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Active trail") + keywords: "active panels taskbar trail workspaces" + anchor: "bar-ws-active-trail" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Occupied background") + keywords: "background occupied panels taskbar workspaces" + anchor: "bar-ws-occupied-background" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Show windows") + keywords: "panels show taskbar windows workspaces" + anchor: "bar-ws-show-windows" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Windows on special workspaces") + keywords: "on panels special taskbar windows workspaces" + anchor: "bar-ws-windows-on-special-workspaces" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Max window icons") + keywords: "icons max panels taskbar window workspaces" + anchor: "bar-ws-max-window-icons" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 5] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] + crumbLabels: ["Panels", "Taskbar", "Workspaces"] + title: qsTr("Per-monitor workspaces") + keywords: "panels per-monitor taskbar workspaces" + anchor: "bar-ws-per-monitor-workspaces" + }, + + // Panels > Taskbar > Active window + SettingEntry { + pageIdx: 6 + subPath: [2, 6] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] + crumbLabels: ["Panels", "Taskbar", "Active window"] + title: qsTr("Compact") + keywords: "active compact panels taskbar window" + anchor: "bar-aw-compact" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 6] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] + crumbLabels: ["Panels", "Taskbar", "Active window"] + title: qsTr("Inverted") + keywords: "active inverted panels taskbar window" + anchor: "bar-aw-inverted" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 6] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] + crumbLabels: ["Panels", "Taskbar", "Active window"] + title: qsTr("Show on hover") + keywords: "active hover on panels show taskbar window" + anchor: "bar-aw-show-on-hover" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 6] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] + crumbLabels: ["Panels", "Taskbar", "Active window"] + title: qsTr("Popout on hover") + keywords: "active hover on panels popout taskbar window" + anchor: "bar-aw-popout-on-hover" + }, + + // Panels > Taskbar > Tray + SettingEntry { + pageIdx: 6 + subPath: [2, 7] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] + crumbLabels: ["Panels", "Taskbar", "Tray"] + title: qsTr("Background") + keywords: "background panels taskbar tray" + anchor: "bar-tray-background" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 7] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] + crumbLabels: ["Panels", "Taskbar", "Tray"] + title: qsTr("Recolour icons") + keywords: "icons panels recolour taskbar tray" + anchor: "bar-tray-recolour-icons" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 7] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] + crumbLabels: ["Panels", "Taskbar", "Tray"] + title: qsTr("Compact") + keywords: "compact panels taskbar tray" + anchor: "bar-tray-compact" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 7] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] + crumbLabels: ["Panels", "Taskbar", "Tray"] + title: qsTr("Popout on hover") + keywords: "hover on panels popout taskbar tray" + anchor: "bar-tray-popout-on-hover" + }, + + // Panels > Taskbar > Status icons + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Speakers") + keywords: "icons panels speakers status taskbar" + anchor: "bar-si-speakers" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Microphone") + keywords: "icons microphone panels status taskbar" + anchor: "bar-si-microphone" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Keyboard layout") + keywords: "icons keyboard layout panels status taskbar" + anchor: "bar-si-keyboard-layout" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Network") + keywords: "icons network panels status taskbar" + anchor: "bar-si-network" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Wi-Fi") + keywords: "icons panels status taskbar wi-fi" + anchor: "bar-si-wi-fi" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Bluetooth") + keywords: "bluetooth icons panels status taskbar" + anchor: "bar-si-bluetooth" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Battery") + keywords: "battery icons panels status taskbar" + anchor: "bar-si-battery" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Caps lock") + keywords: "caps icons lock panels status taskbar" + anchor: "bar-si-caps-lock" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 8] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] + crumbLabels: ["Panels", "Taskbar", "Status icons"] + title: qsTr("Popout on hover") + keywords: "hover icons on panels popout status taskbar" + anchor: "bar-si-popout-on-hover" + }, + + // Panels > Taskbar > Clock + SettingEntry { + pageIdx: 6 + subPath: [2, 9] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "schedule"] + crumbLabels: ["Panels", "Taskbar", "Clock"] + title: qsTr("Background") + keywords: "background clock panels taskbar" + anchor: "bar-clock-background" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 9] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "schedule"] + crumbLabels: ["Panels", "Taskbar", "Clock"] + title: qsTr("Show date") + keywords: "clock date panels show taskbar" + anchor: "bar-clock-show-date" + }, + SettingEntry { + pageIdx: 6 + subPath: [2, 9] + crumbIcons: ["dock_to_bottom", "dock_to_bottom", "schedule"] + crumbLabels: ["Panels", "Taskbar", "Clock"] + title: qsTr("Show icon") + keywords: "clock icon panels show taskbar" + anchor: "bar-clock-show-icon" + }, + + // Apps + SettingEntry { + pageIdx: 7 + subPath: [] + crumbIcons: ["apps"] + crumbLabels: ["Apps"] + title: qsTr("All apps") + keywords: "all apps" + anchor: "apps-all-apps" + }, + + // Services + SettingEntry { + pageIdx: 8 + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] + title: qsTr("Notifications") + keywords: "notifications services" + anchor: "services-notifications" + }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Media refresh") - description: qsTr("How often the media position updates") - keywords: "media player position polling interval mpris" + keywords: "media refresh services" anchor: "services-media-refresh" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("System stats refresh") - description: qsTr("CPU, memory and GPU update interval") - keywords: "cpu memory ram gpu stats resources polling interval" - anchor: "services-stats-refresh" + keywords: "refresh services stats system" + anchor: "services-system-stats-refresh" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Wi-Fi rescan") - description: qsTr("How often available networks are rescanned") - keywords: "wifi wireless network rescan scan interval" - anchor: "services-wifi-rescan" + keywords: "rescan services wi-fi" + anchor: "services-wi-fi-rescan" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Lyrics backend") - description: qsTr("Source used to fetch synced lyrics") - keywords: "lyrics synced lrclib netease music" + keywords: "backend lyrics services" anchor: "services-lyrics-backend" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Default player") - description: qsTr("Preferred media player when several are open") - keywords: "media player default preferred mpris" + keywords: "default player services" anchor: "services-default-player" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Volume step") - description: qsTr("Amount the volume changes per scroll") - keywords: "volume step increment scroll audio" + keywords: "services step volume" anchor: "services-volume-step" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Brightness step") - description: qsTr("Amount the brightness changes per scroll") - keywords: "brightness step increment scroll backlight" + keywords: "brightness services step" anchor: "services-brightness-step" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Max volume") - description: qsTr("Upper limit for output volume") - keywords: "volume max maximum limit cap audio" + keywords: "max services volume" anchor: "services-max-volume" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") - title: qsTr("Notifications") - description: qsTr("Notification behaviour and history") - keywords: "notifications notify popup history dnd" - anchor: "services-notifications" - }, - SettingEntry { - pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Visualiser bars") - description: qsTr("Number of bars in the audio visualisers") - keywords: "visualiser visualizer bars audio spectrum cava" + keywords: "bars services visualiser" anchor: "services-visualiser-bars" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("Smart colour scheme") - description: qsTr("Derive theme mode and variant from the wallpaper") - keywords: "smart colour color scheme theme wallpaper auto" - anchor: "services-smart-scheme" + keywords: "colour scheme services smart" + anchor: "services-smart-colour-scheme" }, SettingEntry { pageIdx: 8 - page: qsTr("Services") + subPath: [] + crumbIcons: ["build"] + crumbLabels: ["Services"] title: qsTr("GPU") - description: qsTr("Override for GPU type") - keywords: "gpu graphics nvidia amd intel monitoring" + keywords: "gpu services" anchor: "services-gpu" }, - // Wallpaper & style (pageComps[0]) + // Services > Notifications SettingEntry { - pageIdx: 0 - page: qsTr("Wallpaper & style") - title: qsTr("Display wallpaper") - description: qsTr("Show a wallpaper on the desktop") - keywords: "wallpaper background image display desktop" - anchor: "style-display-wallpaper" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Show in fullscreen") + keywords: "fullscreen in notifications services show" + anchor: "notif-show-in-fullscreen" }, SettingEntry { - pageIdx: 0 - page: qsTr("Wallpaper & style") - title: qsTr("Transparency") - description: qsTr("Translucent panels and surfaces") - keywords: "transparency translucent opacity blur" - anchor: "style-transparency" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Expire automatically") + keywords: "automatically expire notifications services" + anchor: "notif-expire-automatically" }, SettingEntry { - pageIdx: 0 - page: qsTr("Wallpaper & style") - title: qsTr("Dark theme") - description: qsTr("Use a dark colour scheme") - keywords: "dark theme light mode colour scheme" - anchor: "style-dark-theme" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Open expanded") + keywords: "expanded notifications open services" + anchor: "notif-open-expanded" }, - - // Network (pageComps[1]) SettingEntry { - pageIdx: 1 - page: qsTr("Network") - title: qsTr("Wi-Fi") - description: qsTr("Enable or disable wireless networking") - keywords: "wifi wireless network internet connection" - anchor: "network-wifi" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Default timeout") + keywords: "default notifications services timeout" + anchor: "notif-default-timeout" }, - - // Bluetooth (pageComps[2]) SettingEntry { - pageIdx: 2 - page: qsTr("Bluetooth") - title: qsTr("Bluetooth") - description: qsTr("Enable or disable Bluetooth") - keywords: "bluetooth wireless devices pairing" - anchor: "bluetooth-enabled" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Group preview count") + keywords: "count group notifications preview services" + anchor: "notif-group-preview-count" }, SettingEntry { - pageIdx: 2 - page: qsTr("Bluetooth") - title: qsTr("Discoverable") - description: qsTr("Let other devices find this one") - keywords: "bluetooth discoverable visible find devices" - anchor: "bluetooth-discoverable" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Show in fullscreen") + keywords: "fullscreen in notifications services show" + anchor: "notif-show-in-fullscreen-2" }, SettingEntry { - pageIdx: 2 - page: qsTr("Bluetooth") - title: qsTr("Pairable") - description: qsTr("Allow new devices to pair") - keywords: "bluetooth pairable pairing connect devices" - anchor: "bluetooth-pairable" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Visible toasts") + keywords: "notifications services toasts visible" + anchor: "notif-visible-toasts" }, - - // Panels (pageComps[6]) SettingEntry { - pageIdx: 6 - page: qsTr("Panels") - title: qsTr("Dashboard") - description: qsTr("Dashboard panel settings") - keywords: "dashboard panel widgets overview" - anchor: "panels-dashboard" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Charging changes") + keywords: "changes charging notifications services" + anchor: "notif-charging-changes" }, SettingEntry { - pageIdx: 6 - page: qsTr("Panels") - title: qsTr("Taskbar") - description: qsTr("Taskbar panel settings") - keywords: "taskbar bar dock panel windows" - anchor: "panels-taskbar" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Game mode changes") + keywords: "changes game mode notifications services" + anchor: "notif-game-mode-changes" }, SettingEntry { - pageIdx: 6 - page: qsTr("Panels") - title: qsTr("Launcher") - description: qsTr("Launcher panel settings") - keywords: "launcher search apps menu run" - anchor: "panels-launcher" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Do not disturb changes") + keywords: "changes disturb do not notifications services" + anchor: "notif-do-not-disturb-changes" }, SettingEntry { - pageIdx: 6 - page: qsTr("Panels") - title: qsTr("Sidebar") - description: qsTr("Sidebar panel settings") - keywords: "sidebar panel notifications tray" - anchor: "panels-sidebar" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Audio output changes") + keywords: "audio changes notifications output services" + anchor: "notif-audio-output-changes" }, - - // Apps (pageComps[7]) SettingEntry { - pageIdx: 7 - page: qsTr("Apps") - title: qsTr("All apps") - description: qsTr("Browse every installed application") - keywords: "apps applications installed list browse all" - anchor: "apps-all" + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Audio input changes") + keywords: "audio changes input notifications services" + anchor: "notif-audio-input-changes" + }, + SettingEntry { + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Caps lock changes") + keywords: "caps changes lock notifications services" + anchor: "notif-caps-lock-changes" + }, + SettingEntry { + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Num lock changes") + keywords: "changes lock notifications num services" + anchor: "notif-num-lock-changes" + }, + SettingEntry { + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Keyboard layout changes") + keywords: "changes keyboard layout notifications services" + anchor: "notif-keyboard-layout-changes" + }, + SettingEntry { + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("VPN changes") + keywords: "changes notifications services vpn" + anchor: "notif-vpn-changes" + }, + SettingEntry { + pageIdx: 8 + subPath: [1] + crumbIcons: ["build", "notifications"] + crumbLabels: ["Services", "Notifications"] + title: qsTr("Now playing") + keywords: "notifications now playing services" + anchor: "notif-now-playing" }, - // Language & region (pageComps[9]) + // Language & region SettingEntry { pageIdx: 9 - page: qsTr("Language & region") + subPath: [] + crumbIcons: ["globe"] + crumbLabels: ["Language & region"] title: qsTr("Temperature") - description: qsTr("Temperature unit") - keywords: "temperature unit celsius fahrenheit weather" + keywords: "language region temperature" anchor: "lang-temperature" }, SettingEntry { pageIdx: 9 - page: qsTr("Language & region") + subPath: [] + crumbIcons: ["globe"] + crumbLabels: ["Language & region"] title: qsTr("System temperatures") - description: qsTr("Unit for system sensor temperatures") - keywords: "system temperature sensor cpu gpu celsius fahrenheit" - anchor: "lang-system-temperature" + keywords: "language region system temperatures" + anchor: "lang-system-temperatures" }, SettingEntry { pageIdx: 9 - page: qsTr("Language & region") + subPath: [] + crumbIcons: ["globe"] + crumbLabels: ["Language & region"] title: qsTr("Clock format") - description: qsTr("12 or 24 hour clock") - keywords: "clock time format 12 24 hour am pm" + keywords: "clock format language region" anchor: "lang-clock-format" } ] component SettingEntry: QtObject { required property int pageIdx - required property string page + property list subPath: [] + required property list crumbIcons + required property list crumbLabels required property string title - property string description property string keywords property string anchor } diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 540e342e9..a29c2fd1f 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -5,10 +5,10 @@ import qs.modules.nexus // Fuzzy searcher over the settings index. Reuses the shell's Searcher util (the // same engine the launcher uses) so behaviour stays consistent. Title matches -// weigh heaviest, then keywords, then the description. +// weigh heaviest, then keywords, then the breadcrumb path. Searcher { list: SettingsIndex.entries useFuzzy: true - keys: ["title", "keywords", "description"] + keys: ["title", "keywords", "crumbLabels"] weights: [0.6, 0.3, 0.1] } diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 4b4f4e4a1..6c7e66533 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -21,17 +21,18 @@ ColumnLayout { default property Item contentChild // When the settings search jumps to this page, scroll to the matching row. - function scrollToAnchor(anchor: string): void { + function scrollToAnchor(anchor: string): bool { if (!anchor || !contentChild) - return; + return false; const row = findAnchor(contentChild, anchor); if (!row) - return; + return false; const pos = row.mapToItem(flickable.contentItem, 0, 0); const target = Math.max(0, Math.min(pos.y - Tokens.padding.large, flickable.contentHeight - flickable.height)); flickable.contentY = target; if (row.flashHighlight !== undefined) // qmllint disable missing-property row.flashHighlight(); + return true; } function findAnchor(item: Item, anchor: string): Item { @@ -48,14 +49,27 @@ ColumnLayout { return null; } - Component.onCompleted: if (nState.searchAnchor) + function applySearchAnchor(): void { + if (!nState.searchAnchor) + return; Qt.callLater(() => { - root.scrollToAnchor(nState.searchAnchor); - nState.searchAnchor = ""; - }) + if (root.scrollToAnchor(nState.searchAnchor)) + nState.searchAnchor = ""; + }); + } spacing: Tokens.spacing.extraLargeIncreased + Component.onCompleted: applySearchAnchor() + + Connections { + function onSearchAnchorChanged(): void { + root.applySearchAnchor(); + } + + target: root.nState + } + MouseArea { // Prevent clicks from reaching flickable z: 1 implicitWidth: header.implicitWidth diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 0a3422094..cb8e810ed 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -149,42 +149,70 @@ VerticalFadeFlickable { anchors.fill: parent radius: parent.radius - onClicked: { - root.nState.currentPageIdx = result.modelData.pageIdx; - root.nState.searchAnchor = result.modelData.anchor; - } + onClicked: root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor) } - RowLayout { + ColumnLayout { id: resultLayout anchors.fill: parent anchors.margins: Tokens.padding.large - spacing: Tokens.spacing.medium - - MaterialIcon { - Layout.alignment: Qt.AlignVCenter - text: "search" - color: Colours.palette.m3onSurfaceVariant - fontStyle: Tokens.font.icon.medium + spacing: Tokens.spacing.extraSmall + + Repeater { + model: result.modelData.crumbLabels + + RowLayout { + id: crumb + + required property var modelData + required property int index + + Layout.leftMargin: index * Tokens.padding.large + spacing: Tokens.spacing.small + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + text: crumb.index > 0 ? "subdirectory_arrow_right" : "" + visible: crumb.index > 0 + color: Colours.palette.m3onSurfaceVariant + fontStyle: Tokens.font.icon.small + } + + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + text: result.modelData.crumbIcons[crumb.index] + color: Colours.palette.m3onSurfaceVariant + fontStyle: Tokens.font.icon.small + } + + StyledText { + text: crumb.modelData + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.label.small + elide: Text.ElideRight + } + } } - ColumnLayout { + RowLayout { Layout.fillWidth: true - spacing: 0 + Layout.leftMargin: result.modelData.crumbLabels.length * Tokens.padding.large + Layout.topMargin: Tokens.spacing.extraSmall + spacing: Tokens.spacing.small - StyledText { - Layout.fillWidth: true - text: result.modelData.title - font: Tokens.font.body.medium - elide: Text.ElideRight + MaterialIcon { + Layout.alignment: Qt.AlignVCenter + text: "subdirectory_arrow_right" + color: Colours.palette.m3primary + fontStyle: Tokens.font.icon.small } StyledText { Layout.fillWidth: true - text: `${result.modelData.page} • ${result.modelData.description}` - color: Colours.palette.m3onSurfaceVariant - font: Tokens.font.label.small + text: result.modelData.title + color: Colours.palette.m3primary + font: Tokens.font.body.medium elide: Text.ElideRight } } diff --git a/modules/nexus/pages/AppsPage.qml b/modules/nexus/pages/AppsPage.qml index ab4f90014..9bd2dd532 100644 --- a/modules/nexus/pages/AppsPage.qml +++ b/modules/nexus/pages/AppsPage.qml @@ -68,7 +68,7 @@ PageBase { first: true last: true icon: "apps" - settingAnchor: "apps-all" + settingAnchor: "apps-all-apps" label: qsTr("All apps") status: qsTr("Browse installed apps, set favourites and hidden") onClicked: root.nState.openSubPage(1) diff --git a/modules/nexus/pages/AudioPage.qml b/modules/nexus/pages/AudioPage.qml index 4a4fbd13f..5c70d1479 100644 --- a/modules/nexus/pages/AudioPage.qml +++ b/modules/nexus/pages/AudioPage.qml @@ -22,8 +22,8 @@ PageBase { // Output SliderRow { first: true - settingAnchor: "audio-output" icon: Icons.getVolumeIcon(Audio.volume, Audio.muted) + settingAnchor: "audio-output" label: qsTr("Output") valueLabel: Math.round(value * 100) + "%" value: Audio.volume @@ -50,8 +50,8 @@ PageBase { SliderRow { Layout.topMargin: Tokens.spacing.large - parent.spacing first: true - settingAnchor: "audio-input" icon: Icons.getMicVolumeIcon(Audio.sourceVolume, Audio.sourceMuted) + settingAnchor: "audio-input" label: qsTr("Input") valueLabel: Math.round(value * 100) + "%" value: Audio.sourceVolume @@ -81,7 +81,6 @@ PageBase { implicitHeight: appLayout.implicitHeight + appLayout.anchors.margins * 2 first: true last: true - settingAnchor: "audio-app-volumes" StateLayer { onClicked: root.nState.openSubPage(1) diff --git a/modules/nexus/pages/BluetoothPage.qml b/modules/nexus/pages/BluetoothPage.qml index 431690bac..224a12047 100644 --- a/modules/nexus/pages/BluetoothPage.qml +++ b/modules/nexus/pages/BluetoothPage.qml @@ -27,7 +27,7 @@ PageBase { ToggleRow { first: true - settingAnchor: "bluetooth-enabled" + settingAnchor: "bluetooth-bluetooth" text: qsTr("Bluetooth") font: Tokens.font.body.medium horizontalPadding: Tokens.padding.largeIncreased diff --git a/modules/nexus/pages/LanguageAndRegion.qml b/modules/nexus/pages/LanguageAndRegion.qml index ff8daa0e3..f68468d7b 100644 --- a/modules/nexus/pages/LanguageAndRegion.qml +++ b/modules/nexus/pages/LanguageAndRegion.qml @@ -148,7 +148,7 @@ PageBase { SelectRow { last: true - settingAnchor: "lang-system-temperature" + settingAnchor: "lang-system-temperatures" label: qsTr("System temperatures") subtext: qsTr("Units for CPU and GPU temperatures") menuItems: root.tempItems diff --git a/modules/nexus/pages/NetworkPage.qml b/modules/nexus/pages/NetworkPage.qml index 208f5568e..f19cee63f 100644 --- a/modules/nexus/pages/NetworkPage.qml +++ b/modules/nexus/pages/NetworkPage.qml @@ -62,7 +62,7 @@ PageBase { ToggleRow { Layout.topMargin: Nmcli.hasAvailableEthernet ? Tokens.spacing.large : 0 first: true - settingAnchor: "network-wifi" + settingAnchor: "network-wi-fi" text: qsTr("Wi-Fi") font: Tokens.font.body.medium horizontalPadding: Tokens.padding.largeIncreased diff --git a/modules/nexus/pages/ServicesPage.qml b/modules/nexus/pages/ServicesPage.qml index 1f6043bb7..8c42a7e6b 100644 --- a/modules/nexus/pages/ServicesPage.qml +++ b/modules/nexus/pages/ServicesPage.qml @@ -111,7 +111,7 @@ PageBase { } StepperRow { - settingAnchor: "services-stats-refresh" + settingAnchor: "services-system-stats-refresh" label: qsTr("System stats refresh") subtext: qsTr("CPU, memory and GPU update interval (seconds)") value: GlobalConfig.dashboard.resourceUpdateInterval / 1000 @@ -123,7 +123,7 @@ PageBase { StepperRow { last: true - settingAnchor: "services-wifi-rescan" + settingAnchor: "services-wi-fi-rescan" label: qsTr("Wi-Fi rescan") subtext: qsTr("How often available networks are rescanned (seconds)") value: GlobalConfig.nexus.networkRescanInterval / 1000 @@ -218,7 +218,7 @@ PageBase { } ToggleRow { - settingAnchor: "services-smart-scheme" + settingAnchor: "services-smart-colour-scheme" text: qsTr("Smart colour scheme") subtext: qsTr("Derive theme mode and variant from the wallpaper") checked: GlobalConfig.services.smartScheme diff --git a/modules/nexus/pages/panels/DashboardPanel.qml b/modules/nexus/pages/panels/DashboardPanel.qml index e168f124b..5ad03338e 100644 --- a/modules/nexus/pages/panels/DashboardPanel.qml +++ b/modules/nexus/pages/panels/DashboardPanel.qml @@ -25,6 +25,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "dash-enabled" text: qsTr("Enabled") checked: Config.dashboard.enabled onToggled: GlobalConfig.dashboard.enabled = checked @@ -32,6 +33,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "dash-show-on-hover" text: qsTr("Show on hover") subtext: qsTr("Reveal when the cursor reaches the screen edge") checked: Config.dashboard.showOnHover @@ -45,18 +47,21 @@ PageBase { ToggleRow { first: true + settingAnchor: "dash-dashboard" text: qsTr("Dashboard") checked: Config.dashboard.showDashboard onToggled: GlobalConfig.dashboard.showDashboard = checked } ToggleRow { + settingAnchor: "dash-media" text: qsTr("Media") checked: Config.dashboard.showMedia onToggled: GlobalConfig.dashboard.showMedia = checked } ToggleRow { + settingAnchor: "dash-performance" text: qsTr("Performance") checked: Config.dashboard.showPerformance onToggled: GlobalConfig.dashboard.showPerformance = checked @@ -64,6 +69,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "dash-weather" text: qsTr("Weather") checked: Config.dashboard.showWeather onToggled: GlobalConfig.dashboard.showWeather = checked @@ -76,30 +82,35 @@ PageBase { ToggleRow { first: true + settingAnchor: "dash-battery" text: qsTr("Battery") checked: Config.dashboard.performance.showBattery onToggled: GlobalConfig.dashboard.performance.showBattery = checked } ToggleRow { + settingAnchor: "dash-gpu" text: qsTr("GPU") checked: Config.dashboard.performance.showGpu onToggled: GlobalConfig.dashboard.performance.showGpu = checked } ToggleRow { + settingAnchor: "dash-cpu" text: qsTr("CPU") checked: Config.dashboard.performance.showCpu onToggled: GlobalConfig.dashboard.performance.showCpu = checked } ToggleRow { + settingAnchor: "dash-memory" text: qsTr("Memory") checked: Config.dashboard.performance.showMemory onToggled: GlobalConfig.dashboard.performance.showMemory = checked } ToggleRow { + settingAnchor: "dash-storage" text: qsTr("Storage") checked: Config.dashboard.performance.showStorage onToggled: GlobalConfig.dashboard.performance.showStorage = checked @@ -107,6 +118,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "dash-network" text: qsTr("Network") checked: Config.dashboard.performance.showNetwork onToggled: GlobalConfig.dashboard.performance.showNetwork = checked @@ -120,6 +132,7 @@ PageBase { StepperRow { first: true last: true + settingAnchor: "dash-drag-threshold" label: qsTr("Drag threshold") subtext: qsTr("Pixels dragged before the dashboard opens") value: Config.dashboard.dragThreshold diff --git a/modules/nexus/pages/panels/LauncherPanel.qml b/modules/nexus/pages/panels/LauncherPanel.qml index b78edcc29..14c55356f 100644 --- a/modules/nexus/pages/panels/LauncherPanel.qml +++ b/modules/nexus/pages/panels/LauncherPanel.qml @@ -25,6 +25,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "launcher-enabled" text: qsTr("Enabled") checked: Config.launcher.enabled onToggled: GlobalConfig.launcher.enabled = checked @@ -32,6 +33,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "launcher-show-on-hover" text: qsTr("Show on hover") subtext: qsTr("Reveal when the cursor reaches the screen edge") checked: Config.launcher.showOnHover @@ -45,6 +47,7 @@ PageBase { StepperRow { first: true + settingAnchor: "launcher-max-items-shown" label: qsTr("Max items shown") value: Config.launcher.maxShown from: 1 @@ -54,6 +57,7 @@ PageBase { } StepperRow { + settingAnchor: "launcher-max-wallpapers" label: qsTr("Max wallpapers") value: Config.launcher.maxWallpapers from: 1 @@ -64,6 +68,7 @@ PageBase { StepperRow { last: true + settingAnchor: "launcher-drag-threshold" label: qsTr("Drag threshold") subtext: qsTr("Pixels dragged before the launcher opens") value: Config.launcher.dragThreshold @@ -80,6 +85,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "launcher-vim-keybinds" text: qsTr("Vim keybinds") subtext: qsTr("Navigate results with Ctrl+hjkl") checked: GlobalConfig.launcher.vimKeybinds @@ -88,6 +94,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "launcher-enable-dangerous-actions" text: qsTr("Enable dangerous actions") subtext: qsTr("Allow actions that shut down or log out") checked: GlobalConfig.launcher.enableDangerousActions @@ -101,24 +108,28 @@ PageBase { ToggleRow { first: true + settingAnchor: "launcher-apps" text: qsTr("Apps") checked: GlobalConfig.launcher.useFuzzy.apps onToggled: GlobalConfig.launcher.useFuzzy.apps = checked } ToggleRow { + settingAnchor: "launcher-actions" text: qsTr("Actions") checked: GlobalConfig.launcher.useFuzzy.actions onToggled: GlobalConfig.launcher.useFuzzy.actions = checked } ToggleRow { + settingAnchor: "launcher-schemes" text: qsTr("Schemes") checked: GlobalConfig.launcher.useFuzzy.schemes onToggled: GlobalConfig.launcher.useFuzzy.schemes = checked } ToggleRow { + settingAnchor: "launcher-variants" text: qsTr("Variants") checked: GlobalConfig.launcher.useFuzzy.variants onToggled: GlobalConfig.launcher.useFuzzy.variants = checked @@ -126,6 +137,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "launcher-wallpapers" text: qsTr("Wallpapers") checked: GlobalConfig.launcher.useFuzzy.wallpapers onToggled: GlobalConfig.launcher.useFuzzy.wallpapers = checked diff --git a/modules/nexus/pages/panels/SidebarPanel.qml b/modules/nexus/pages/panels/SidebarPanel.qml index 8d6782248..53b585f0d 100644 --- a/modules/nexus/pages/panels/SidebarPanel.qml +++ b/modules/nexus/pages/panels/SidebarPanel.qml @@ -24,6 +24,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "sidebar-enabled" text: qsTr("Enabled") checked: Config.sidebar.enabled onToggled: GlobalConfig.sidebar.enabled = checked @@ -31,6 +32,7 @@ PageBase { StepperRow { last: true + settingAnchor: "sidebar-drag-threshold" label: qsTr("Drag threshold") subtext: qsTr("Pixels dragged before the sidebar opens") value: Config.sidebar.dragThreshold diff --git a/modules/nexus/pages/panels/TaskbarPanel.qml b/modules/nexus/pages/panels/TaskbarPanel.qml index 97102f686..79f4e4907 100644 --- a/modules/nexus/pages/panels/TaskbarPanel.qml +++ b/modules/nexus/pages/panels/TaskbarPanel.qml @@ -24,6 +24,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "taskbar-persistent" text: qsTr("Persistent") subtext: qsTr("Keep the bar visible at all times") checked: Config.bar.persistent @@ -31,6 +32,7 @@ PageBase { } ToggleRow { + settingAnchor: "taskbar-show-on-hover" text: qsTr("Show on hover") subtext: qsTr("Reveal the bar when the cursor reaches the screen edge") checked: Config.bar.showOnHover @@ -39,6 +41,7 @@ PageBase { StepperRow { last: true + settingAnchor: "taskbar-drag-threshold" label: qsTr("Drag threshold") subtext: qsTr("Pixels dragged before the bar reveals") value: Config.bar.dragThreshold @@ -56,6 +59,7 @@ PageBase { NavRow { first: true icon: "workspaces" + settingAnchor: "taskbar-workspaces" label: qsTr("Workspaces") status: qsTr("Indicators, window icons") onClicked: root.nState.openSubPage(5) @@ -63,6 +67,7 @@ PageBase { NavRow { icon: "web_asset" + settingAnchor: "taskbar-active-window" label: qsTr("Active window") status: qsTr("Title display, popout") onClicked: root.nState.openSubPage(6) @@ -70,6 +75,7 @@ PageBase { NavRow { icon: "widgets" + settingAnchor: "taskbar-tray" label: qsTr("Tray") status: qsTr("System tray icons") onClicked: root.nState.openSubPage(7) @@ -77,6 +83,7 @@ PageBase { NavRow { icon: "signal_cellular_alt" + settingAnchor: "taskbar-status-icons" label: qsTr("Status icons") status: qsTr("Visible indicators") onClicked: root.nState.openSubPage(8) @@ -85,6 +92,7 @@ PageBase { NavRow { last: true icon: "schedule" + settingAnchor: "taskbar-clock" label: qsTr("Clock") status: qsTr("Date, icon, background") onClicked: root.nState.openSubPage(9) @@ -97,6 +105,7 @@ PageBase { ToggleRow { first: true + settingAnchor: "taskbar-workspaces-2" text: qsTr("Workspaces") subtext: qsTr("Scroll over the workspace indicator to switch workspaces") checked: Config.bar.scrollActions.workspaces @@ -104,6 +113,7 @@ PageBase { } ToggleRow { + settingAnchor: "taskbar-volume" text: qsTr("Volume") subtext: qsTr("Scroll on the top half of the bar to adjust volume") checked: Config.bar.scrollActions.volume @@ -112,6 +122,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "taskbar-brightness" text: qsTr("Brightness") subtext: qsTr("Scroll on the bottom half of the bar to adjust brightness") checked: Config.bar.scrollActions.brightness diff --git a/modules/nexus/pages/panels/taskbar/BarActiveWindow.qml b/modules/nexus/pages/panels/taskbar/BarActiveWindow.qml index f51a1c4d5..5811bf053 100644 --- a/modules/nexus/pages/panels/taskbar/BarActiveWindow.qml +++ b/modules/nexus/pages/panels/taskbar/BarActiveWindow.qml @@ -18,18 +18,21 @@ PageBase { ToggleRow { first: true + settingAnchor: "bar-aw-compact" text: qsTr("Compact") checked: Config.bar.activeWindow.compact onToggled: GlobalConfig.bar.activeWindow.compact = checked } ToggleRow { + settingAnchor: "bar-aw-inverted" text: qsTr("Inverted") checked: Config.bar.activeWindow.inverted onToggled: GlobalConfig.bar.activeWindow.inverted = checked } ToggleRow { + settingAnchor: "bar-aw-show-on-hover" text: qsTr("Show on hover") subtext: qsTr("Only show the active window title while hovering") checked: Config.bar.activeWindow.showOnHover @@ -38,6 +41,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "bar-aw-popout-on-hover" text: qsTr("Popout on hover") subtext: qsTr("Show a window details popout when hovering") checked: Config.bar.popouts.activeWindow diff --git a/modules/nexus/pages/panels/taskbar/BarClock.qml b/modules/nexus/pages/panels/taskbar/BarClock.qml index b2b6aef17..719f2d062 100644 --- a/modules/nexus/pages/panels/taskbar/BarClock.qml +++ b/modules/nexus/pages/panels/taskbar/BarClock.qml @@ -18,12 +18,14 @@ PageBase { ToggleRow { first: true + settingAnchor: "bar-clock-background" text: qsTr("Background") checked: Config.bar.clock.background onToggled: GlobalConfig.bar.clock.background = checked } ToggleRow { + settingAnchor: "bar-clock-show-date" text: qsTr("Show date") checked: Config.bar.clock.showDate onToggled: GlobalConfig.bar.clock.showDate = checked @@ -31,6 +33,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "bar-clock-show-icon" text: qsTr("Show icon") checked: Config.bar.clock.showIcon onToggled: GlobalConfig.bar.clock.showIcon = checked diff --git a/modules/nexus/pages/panels/taskbar/BarStatusIcons.qml b/modules/nexus/pages/panels/taskbar/BarStatusIcons.qml index bd0d91fe8..a50b33735 100644 --- a/modules/nexus/pages/panels/taskbar/BarStatusIcons.qml +++ b/modules/nexus/pages/panels/taskbar/BarStatusIcons.qml @@ -24,42 +24,49 @@ PageBase { ToggleRow { first: true + settingAnchor: "bar-si-speakers" text: qsTr("Speakers") checked: Config.bar.status.showAudio onToggled: GlobalConfig.bar.status.showAudio = checked } ToggleRow { + settingAnchor: "bar-si-microphone" text: qsTr("Microphone") checked: Config.bar.status.showMicrophone onToggled: GlobalConfig.bar.status.showMicrophone = checked } ToggleRow { + settingAnchor: "bar-si-keyboard-layout" text: qsTr("Keyboard layout") checked: Config.bar.status.showKbLayout onToggled: GlobalConfig.bar.status.showKbLayout = checked } ToggleRow { + settingAnchor: "bar-si-network" text: qsTr("Network") checked: Config.bar.status.showNetwork onToggled: GlobalConfig.bar.status.showNetwork = checked } ToggleRow { + settingAnchor: "bar-si-wi-fi" text: qsTr("Wi-Fi") checked: Config.bar.status.showWifi onToggled: GlobalConfig.bar.status.showWifi = checked } ToggleRow { + settingAnchor: "bar-si-bluetooth" text: qsTr("Bluetooth") checked: Config.bar.status.showBluetooth onToggled: GlobalConfig.bar.status.showBluetooth = checked } ToggleRow { + settingAnchor: "bar-si-battery" text: qsTr("Battery") checked: Config.bar.status.showBattery onToggled: GlobalConfig.bar.status.showBattery = checked @@ -67,6 +74,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "bar-si-caps-lock" text: qsTr("Caps lock") checked: Config.bar.status.showLockStatus onToggled: GlobalConfig.bar.status.showLockStatus = checked @@ -80,6 +88,7 @@ PageBase { ToggleRow { first: true last: true + settingAnchor: "bar-si-popout-on-hover" text: qsTr("Popout on hover") subtext: qsTr("Show a details popout when hovering the status icons") checked: Config.bar.popouts.statusIcons diff --git a/modules/nexus/pages/panels/taskbar/BarTray.qml b/modules/nexus/pages/panels/taskbar/BarTray.qml index a02597fdb..b23296de5 100644 --- a/modules/nexus/pages/panels/taskbar/BarTray.qml +++ b/modules/nexus/pages/panels/taskbar/BarTray.qml @@ -18,18 +18,21 @@ PageBase { ToggleRow { first: true + settingAnchor: "bar-tray-background" text: qsTr("Background") checked: Config.bar.tray.background onToggled: GlobalConfig.bar.tray.background = checked } ToggleRow { + settingAnchor: "bar-tray-recolour-icons" text: qsTr("Recolour icons") checked: Config.bar.tray.recolour onToggled: GlobalConfig.bar.tray.recolour = checked } ToggleRow { + settingAnchor: "bar-tray-compact" text: qsTr("Compact") checked: Config.bar.tray.compact onToggled: GlobalConfig.bar.tray.compact = checked @@ -37,6 +40,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "bar-tray-popout-on-hover" text: qsTr("Popout on hover") subtext: qsTr("Show the tray menu popout when hovering") checked: Config.bar.popouts.tray diff --git a/modules/nexus/pages/panels/taskbar/BarWorkspaces.qml b/modules/nexus/pages/panels/taskbar/BarWorkspaces.qml index 814dc8626..635b3e17d 100644 --- a/modules/nexus/pages/panels/taskbar/BarWorkspaces.qml +++ b/modules/nexus/pages/panels/taskbar/BarWorkspaces.qml @@ -18,6 +18,7 @@ PageBase { StepperRow { first: true + settingAnchor: "bar-ws-shown" label: qsTr("Shown") subtext: qsTr("Number of workspaces displayed") value: Config.bar.workspaces.shown @@ -28,24 +29,28 @@ PageBase { } ToggleRow { + settingAnchor: "bar-ws-active-indicator" text: qsTr("Active indicator") checked: Config.bar.workspaces.activeIndicator onToggled: GlobalConfig.bar.workspaces.activeIndicator = checked } ToggleRow { + settingAnchor: "bar-ws-active-trail" text: qsTr("Active trail") checked: Config.bar.workspaces.activeTrail onToggled: GlobalConfig.bar.workspaces.activeTrail = checked } ToggleRow { + settingAnchor: "bar-ws-occupied-background" text: qsTr("Occupied background") checked: Config.bar.workspaces.occupiedBg onToggled: GlobalConfig.bar.workspaces.occupiedBg = checked } ToggleRow { + settingAnchor: "bar-ws-show-windows" text: qsTr("Show windows") subtext: qsTr("Show icons of open windows on each workspace") checked: Config.bar.workspaces.showWindows @@ -53,12 +58,14 @@ PageBase { } ToggleRow { + settingAnchor: "bar-ws-windows-on-special-workspaces" text: qsTr("Windows on special workspaces") checked: Config.bar.workspaces.showWindowsOnSpecialWorkspaces onToggled: GlobalConfig.bar.workspaces.showWindowsOnSpecialWorkspaces = checked } StepperRow { + settingAnchor: "bar-ws-max-window-icons" label: qsTr("Max window icons") value: Config.bar.workspaces.maxWindowIcons from: 0 @@ -69,6 +76,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "bar-ws-per-monitor-workspaces" text: qsTr("Per-monitor workspaces") subtext: qsTr("Show each monitor's workspaces independently") checked: GlobalConfig.bar.workspaces.perMonitorWorkspaces diff --git a/modules/nexus/pages/services/NotificationsPage.qml b/modules/nexus/pages/services/NotificationsPage.qml index 78a03b8c5..f581cd84f 100644 --- a/modules/nexus/pages/services/NotificationsPage.qml +++ b/modules/nexus/pages/services/NotificationsPage.qml @@ -54,6 +54,7 @@ PageBase { SelectRow { first: true + settingAnchor: "notif-show-in-fullscreen" label: qsTr("Show in fullscreen") subtext: qsTr("Whether notifications appear over fullscreen apps") menuItems: root.notifFullscreenItems @@ -62,6 +63,7 @@ PageBase { } ToggleRow { + settingAnchor: "notif-expire-automatically" text: qsTr("Expire automatically") subtext: qsTr("Dismiss notifications after their timeout") checked: GlobalConfig.notifs.expire @@ -69,6 +71,7 @@ PageBase { } ToggleRow { + settingAnchor: "notif-open-expanded" text: qsTr("Open expanded") subtext: qsTr("Show notifications expanded by default") checked: GlobalConfig.notifs.openExpanded @@ -76,6 +79,7 @@ PageBase { } StepperRow { + settingAnchor: "notif-default-timeout" label: qsTr("Default timeout") subtext: qsTr("Time before a notification dismisses (ms)") value: GlobalConfig.notifs.defaultExpireTimeout @@ -87,6 +91,7 @@ PageBase { StepperRow { last: true + settingAnchor: "notif-group-preview-count" label: qsTr("Group preview count") subtext: qsTr("Notifications shown per group before collapsing") value: GlobalConfig.notifs.groupPreviewNum @@ -103,6 +108,7 @@ PageBase { SelectRow { first: true + settingAnchor: "notif-show-in-fullscreen-2" label: qsTr("Show in fullscreen") subtext: qsTr("Whether toasts appear over fullscreen apps") menuItems: root.toastFullscreenItems @@ -112,6 +118,7 @@ PageBase { StepperRow { last: true + settingAnchor: "notif-visible-toasts" label: qsTr("Visible toasts") subtext: qsTr("Maximum number of toasts shown at once") value: GlobalConfig.utilities.maxToasts @@ -128,54 +135,63 @@ PageBase { ToggleRow { first: true + settingAnchor: "notif-charging-changes" text: qsTr("Charging changes") checked: GlobalConfig.utilities.toasts.chargingChanged onToggled: GlobalConfig.utilities.toasts.chargingChanged = checked } ToggleRow { + settingAnchor: "notif-game-mode-changes" text: qsTr("Game mode changes") checked: GlobalConfig.utilities.toasts.gameModeChanged onToggled: GlobalConfig.utilities.toasts.gameModeChanged = checked } ToggleRow { + settingAnchor: "notif-do-not-disturb-changes" text: qsTr("Do not disturb changes") checked: GlobalConfig.utilities.toasts.dndChanged onToggled: GlobalConfig.utilities.toasts.dndChanged = checked } ToggleRow { + settingAnchor: "notif-audio-output-changes" text: qsTr("Audio output changes") checked: GlobalConfig.utilities.toasts.audioOutputChanged onToggled: GlobalConfig.utilities.toasts.audioOutputChanged = checked } ToggleRow { + settingAnchor: "notif-audio-input-changes" text: qsTr("Audio input changes") checked: GlobalConfig.utilities.toasts.audioInputChanged onToggled: GlobalConfig.utilities.toasts.audioInputChanged = checked } ToggleRow { + settingAnchor: "notif-caps-lock-changes" text: qsTr("Caps lock changes") checked: GlobalConfig.utilities.toasts.capsLockChanged onToggled: GlobalConfig.utilities.toasts.capsLockChanged = checked } ToggleRow { + settingAnchor: "notif-num-lock-changes" text: qsTr("Num lock changes") checked: GlobalConfig.utilities.toasts.numLockChanged onToggled: GlobalConfig.utilities.toasts.numLockChanged = checked } ToggleRow { + settingAnchor: "notif-keyboard-layout-changes" text: qsTr("Keyboard layout changes") checked: GlobalConfig.utilities.toasts.kbLayoutChanged onToggled: GlobalConfig.utilities.toasts.kbLayoutChanged = checked } ToggleRow { + settingAnchor: "notif-vpn-changes" text: qsTr("VPN changes") checked: GlobalConfig.utilities.toasts.vpnChanged onToggled: GlobalConfig.utilities.toasts.vpnChanged = checked @@ -183,6 +199,7 @@ PageBase { ToggleRow { last: true + settingAnchor: "notif-now-playing" text: qsTr("Now playing") checked: GlobalConfig.utilities.toasts.nowPlaying onToggled: GlobalConfig.utilities.toasts.nowPlaying = checked From 9950464d9e9e92bef043bb5a1fc332a9015bab43 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 01:16:47 +0000 Subject: [PATCH 06/57] feat(nexus): generate settings index from QML at build time --- CMakeLists.txt | 17 + assets/settings-index.json | 1877 ++++++++++++++++++++++++++++ modules/nexus/SettingsIndex.qml | 1072 ---------------- modules/nexus/SettingsSearcher.qml | 51 +- scripts/build-settings-index.py | 207 +++ 5 files changed, 2145 insertions(+), 1079 deletions(-) create mode 100644 assets/settings-index.json delete mode 100644 modules/nexus/SettingsIndex.qml create mode 100644 scripts/build-settings-index.py diff --git a/CMakeLists.txt b/CMakeLists.txt index c9957f04d..dcbde778e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,23 @@ if("plugin" IN_LIST ENABLE_MODULES) endif() if("shell" IN_LIST ENABLE_MODULES) + # Generate the settings search index from the page QML at build time so it + # always matches the UI (see scripts/build-settings-index.py). + find_package(Python3 COMPONENTS Interpreter REQUIRED) + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/assets") + execute_process( + COMMAND ${Python3_EXECUTABLE} + "${CMAKE_SOURCE_DIR}/scripts/build-settings-index.py" + "${CMAKE_SOURCE_DIR}/modules/nexus" + "${CMAKE_BINARY_DIR}/assets/settings-index.json" + RESULT_VARIABLE SETTINGS_INDEX_RESULT + ) + if(NOT SETTINGS_INDEX_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to build settings search index") + endif() + install(FILES "${CMAKE_BINARY_DIR}/assets/settings-index.json" + DESTINATION "${INSTALL_QSCONFDIR}/assets") + foreach(dir assets components modules services utils) install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}") endforeach() diff --git a/assets/settings-index.json b/assets/settings-index.json new file mode 100644 index 000000000..48b3f99a1 --- /dev/null +++ b/assets/settings-index.json @@ -0,0 +1,1877 @@ +{ + "version": 1, + "entries": [ + { + "pageIdx": 0, + "subPath": [], + "crumbIcons": [ + "palette" + ], + "crumbLabels": [ + "Wallpaper & style" + ], + "title": "Display wallpaper", + "anchor": "style-display-wallpaper", + "keywords": "display style wallpaper" + }, + { + "pageIdx": 0, + "subPath": [], + "crumbIcons": [ + "palette" + ], + "crumbLabels": [ + "Wallpaper & style" + ], + "title": "Transparency", + "anchor": "style-transparency", + "keywords": "style transparency wallpaper" + }, + { + "pageIdx": 0, + "subPath": [], + "crumbIcons": [ + "palette" + ], + "crumbLabels": [ + "Wallpaper & style" + ], + "title": "Dark theme", + "anchor": "style-dark-theme", + "keywords": "dark style theme wallpaper" + }, + { + "pageIdx": 1, + "subPath": [], + "crumbIcons": [ + "wifi" + ], + "crumbLabels": [ + "Network" + ], + "title": "Wi-Fi", + "anchor": "network-wi-fi", + "keywords": "network wi-fi" + }, + { + "pageIdx": 2, + "subPath": [], + "crumbIcons": [ + "devices_other" + ], + "crumbLabels": [ + "Bluetooth" + ], + "title": "Bluetooth", + "anchor": "bluetooth-bluetooth", + "keywords": "bluetooth" + }, + { + "pageIdx": 2, + "subPath": [], + "crumbIcons": [ + "devices_other" + ], + "crumbLabels": [ + "Bluetooth" + ], + "title": "Discoverable", + "anchor": "bluetooth-discoverable", + "keywords": "bluetooth discoverable" + }, + { + "pageIdx": 2, + "subPath": [], + "crumbIcons": [ + "devices_other" + ], + "crumbLabels": [ + "Bluetooth" + ], + "title": "Pairable", + "anchor": "bluetooth-pairable", + "keywords": "bluetooth pairable" + }, + { + "pageIdx": 3, + "subPath": [], + "crumbIcons": [ + "volume_up" + ], + "crumbLabels": [ + "Audio" + ], + "title": "Output", + "anchor": "audio-output", + "keywords": "audio output" + }, + { + "pageIdx": 3, + "subPath": [], + "crumbIcons": [ + "volume_up" + ], + "crumbLabels": [ + "Audio" + ], + "title": "Input", + "anchor": "audio-input", + "keywords": "audio input" + }, + { + "pageIdx": 6, + "subPath": [], + "crumbIcons": [ + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels" + ], + "title": "Dashboard", + "anchor": "panels-dashboard", + "keywords": "dashboard panels" + }, + { + "pageIdx": 6, + "subPath": [], + "crumbIcons": [ + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels" + ], + "title": "Taskbar", + "anchor": "panels-taskbar", + "keywords": "panels taskbar" + }, + { + "pageIdx": 6, + "subPath": [], + "crumbIcons": [ + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels" + ], + "title": "Launcher", + "anchor": "panels-launcher", + "keywords": "launcher panels" + }, + { + "pageIdx": 6, + "subPath": [], + "crumbIcons": [ + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels" + ], + "title": "Sidebar", + "anchor": "panels-sidebar", + "keywords": "panels sidebar" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Enabled", + "anchor": "dash-enabled", + "keywords": "dashboard enabled panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Show on hover", + "anchor": "dash-show-on-hover", + "keywords": "dashboard hover on panels show" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Dashboard", + "anchor": "dash-dashboard", + "keywords": "dashboard panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Media", + "anchor": "dash-media", + "keywords": "dashboard media panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Performance", + "anchor": "dash-performance", + "keywords": "dashboard panels performance" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Weather", + "anchor": "dash-weather", + "keywords": "dashboard panels weather" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Battery", + "anchor": "dash-battery", + "keywords": "battery dashboard panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "GPU", + "anchor": "dash-gpu", + "keywords": "dashboard gpu panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "CPU", + "anchor": "dash-cpu", + "keywords": "cpu dashboard panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Memory", + "anchor": "dash-memory", + "keywords": "dashboard memory panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Storage", + "anchor": "dash-storage", + "keywords": "dashboard panels storage" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Network", + "anchor": "dash-network", + "keywords": "dashboard network panels" + }, + { + "pageIdx": 6, + "subPath": [ + 1 + ], + "crumbIcons": [ + "dock_to_bottom", + "dashboard" + ], + "crumbLabels": [ + "Panels", + "Dashboard" + ], + "title": "Drag threshold", + "anchor": "dash-drag-threshold", + "keywords": "dashboard drag panels threshold" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Persistent", + "anchor": "taskbar-persistent", + "keywords": "panels persistent taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Show on hover", + "anchor": "taskbar-show-on-hover", + "keywords": "hover on panels show taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Drag threshold", + "anchor": "taskbar-drag-threshold", + "keywords": "drag panels taskbar threshold" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Workspaces", + "anchor": "taskbar-workspaces", + "keywords": "panels taskbar workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Active window", + "anchor": "taskbar-active-window", + "keywords": "active panels taskbar window" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Tray", + "anchor": "taskbar-tray", + "keywords": "panels taskbar tray" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Status icons", + "anchor": "taskbar-status-icons", + "keywords": "icons panels status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Clock", + "anchor": "taskbar-clock", + "keywords": "clock panels taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Workspaces", + "anchor": "taskbar-workspaces-2", + "keywords": "panels taskbar workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Volume", + "anchor": "taskbar-volume", + "keywords": "panels taskbar volume" + }, + { + "pageIdx": 6, + "subPath": [ + 2 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom" + ], + "crumbLabels": [ + "Panels", + "Taskbar" + ], + "title": "Brightness", + "anchor": "taskbar-brightness", + "keywords": "brightness panels taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Shown", + "anchor": "bar-ws-shown", + "keywords": "panels shown taskbar workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Active indicator", + "anchor": "bar-ws-active-indicator", + "keywords": "active indicator panels taskbar workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Active trail", + "anchor": "bar-ws-active-trail", + "keywords": "active panels taskbar trail workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Occupied background", + "anchor": "bar-ws-occupied-background", + "keywords": "background occupied panels taskbar workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Show windows", + "anchor": "bar-ws-show-windows", + "keywords": "panels show taskbar windows workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Windows on special workspaces", + "anchor": "bar-ws-windows-on-special-workspaces", + "keywords": "on panels special taskbar windows workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Max window icons", + "anchor": "bar-ws-max-window-icons", + "keywords": "icons max panels taskbar window workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 5 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "workspaces" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Workspaces" + ], + "title": "Per-monitor workspaces", + "anchor": "bar-ws-per-monitor-workspaces", + "keywords": "panels per-monitor taskbar workspaces" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 6 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "web_asset" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Active window" + ], + "title": "Compact", + "anchor": "bar-aw-compact", + "keywords": "active compact panels taskbar window" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 6 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "web_asset" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Active window" + ], + "title": "Inverted", + "anchor": "bar-aw-inverted", + "keywords": "active inverted panels taskbar window" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 6 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "web_asset" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Active window" + ], + "title": "Show on hover", + "anchor": "bar-aw-show-on-hover", + "keywords": "active hover on panels show taskbar window" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 6 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "web_asset" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Active window" + ], + "title": "Popout on hover", + "anchor": "bar-aw-popout-on-hover", + "keywords": "active hover on panels popout taskbar window" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 7 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "widgets" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Tray" + ], + "title": "Background", + "anchor": "bar-tray-background", + "keywords": "background panels taskbar tray" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 7 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "widgets" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Tray" + ], + "title": "Recolour icons", + "anchor": "bar-tray-recolour-icons", + "keywords": "icons panels recolour taskbar tray" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 7 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "widgets" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Tray" + ], + "title": "Compact", + "anchor": "bar-tray-compact", + "keywords": "compact panels taskbar tray" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 7 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "widgets" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Tray" + ], + "title": "Popout on hover", + "anchor": "bar-tray-popout-on-hover", + "keywords": "hover on panels popout taskbar tray" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Speakers", + "anchor": "bar-si-speakers", + "keywords": "icons panels speakers status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Microphone", + "anchor": "bar-si-microphone", + "keywords": "icons microphone panels status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Keyboard layout", + "anchor": "bar-si-keyboard-layout", + "keywords": "icons keyboard layout panels status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Network", + "anchor": "bar-si-network", + "keywords": "icons network panels status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Wi-Fi", + "anchor": "bar-si-wi-fi", + "keywords": "icons panels status taskbar wi-fi" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Bluetooth", + "anchor": "bar-si-bluetooth", + "keywords": "bluetooth icons panels status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Battery", + "anchor": "bar-si-battery", + "keywords": "battery icons panels status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Caps lock", + "anchor": "bar-si-caps-lock", + "keywords": "caps icons lock panels status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 8 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "signal_cellular_alt" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Status icons" + ], + "title": "Popout on hover", + "anchor": "bar-si-popout-on-hover", + "keywords": "hover icons on panels popout status taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 9 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "schedule" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Clock" + ], + "title": "Background", + "anchor": "bar-clock-background", + "keywords": "background clock panels taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 9 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "schedule" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Clock" + ], + "title": "Show date", + "anchor": "bar-clock-show-date", + "keywords": "clock date panels show taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 2, + 9 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_bottom", + "schedule" + ], + "crumbLabels": [ + "Panels", + "Taskbar", + "Clock" + ], + "title": "Show icon", + "anchor": "bar-clock-show-icon", + "keywords": "clock icon panels show taskbar" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Enabled", + "anchor": "launcher-enabled", + "keywords": "enabled launcher panels" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Show on hover", + "anchor": "launcher-show-on-hover", + "keywords": "hover launcher on panels show" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Max items shown", + "anchor": "launcher-max-items-shown", + "keywords": "items launcher max panels shown" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Max wallpapers", + "anchor": "launcher-max-wallpapers", + "keywords": "launcher max panels wallpapers" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Drag threshold", + "anchor": "launcher-drag-threshold", + "keywords": "drag launcher panels threshold" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Vim keybinds", + "anchor": "launcher-vim-keybinds", + "keywords": "keybinds launcher panels vim" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Enable dangerous actions", + "anchor": "launcher-enable-dangerous-actions", + "keywords": "actions dangerous enable launcher panels" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Apps", + "anchor": "launcher-apps", + "keywords": "apps launcher panels" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Actions", + "anchor": "launcher-actions", + "keywords": "actions launcher panels" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Schemes", + "anchor": "launcher-schemes", + "keywords": "launcher panels schemes" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Variants", + "anchor": "launcher-variants", + "keywords": "launcher panels variants" + }, + { + "pageIdx": 6, + "subPath": [ + 3 + ], + "crumbIcons": [ + "dock_to_bottom", + "apps" + ], + "crumbLabels": [ + "Panels", + "Launcher" + ], + "title": "Wallpapers", + "anchor": "launcher-wallpapers", + "keywords": "launcher panels wallpapers" + }, + { + "pageIdx": 6, + "subPath": [ + 4 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_right" + ], + "crumbLabels": [ + "Panels", + "Sidebar" + ], + "title": "Enabled", + "anchor": "sidebar-enabled", + "keywords": "enabled panels sidebar" + }, + { + "pageIdx": 6, + "subPath": [ + 4 + ], + "crumbIcons": [ + "dock_to_bottom", + "dock_to_right" + ], + "crumbLabels": [ + "Panels", + "Sidebar" + ], + "title": "Drag threshold", + "anchor": "sidebar-drag-threshold", + "keywords": "drag panels sidebar threshold" + }, + { + "pageIdx": 7, + "subPath": [], + "crumbIcons": [ + "apps" + ], + "crumbLabels": [ + "Apps" + ], + "title": "All apps", + "anchor": "apps-all-apps", + "keywords": "all apps" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Notifications", + "anchor": "services-notifications", + "keywords": "notifications services" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Media refresh", + "anchor": "services-media-refresh", + "keywords": "media refresh services" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "System stats refresh", + "anchor": "services-system-stats-refresh", + "keywords": "refresh services stats system" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Wi-Fi rescan", + "anchor": "services-wi-fi-rescan", + "keywords": "rescan services wi-fi" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Lyrics backend", + "anchor": "services-lyrics-backend", + "keywords": "backend lyrics services" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Default player", + "anchor": "services-default-player", + "keywords": "default player services" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Volume step", + "anchor": "services-volume-step", + "keywords": "services step volume" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Brightness step", + "anchor": "services-brightness-step", + "keywords": "brightness services step" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Max volume", + "anchor": "services-max-volume", + "keywords": "max services volume" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Visualiser bars", + "anchor": "services-visualiser-bars", + "keywords": "bars services visualiser" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "Smart colour scheme", + "anchor": "services-smart-colour-scheme", + "keywords": "colour scheme services smart" + }, + { + "pageIdx": 8, + "subPath": [], + "crumbIcons": [ + "build" + ], + "crumbLabels": [ + "Services" + ], + "title": "GPU", + "anchor": "services-gpu", + "keywords": "gpu services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Show in fullscreen", + "anchor": "notif-show-in-fullscreen", + "keywords": "fullscreen in notifications services show" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Expire automatically", + "anchor": "notif-expire-automatically", + "keywords": "automatically expire notifications services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Open expanded", + "anchor": "notif-open-expanded", + "keywords": "expanded notifications open services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Default timeout", + "anchor": "notif-default-timeout", + "keywords": "default notifications services timeout" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Group preview count", + "anchor": "notif-group-preview-count", + "keywords": "count group notifications preview services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Show in fullscreen", + "anchor": "notif-show-in-fullscreen-2", + "keywords": "fullscreen in notifications services show" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Visible toasts", + "anchor": "notif-visible-toasts", + "keywords": "notifications services toasts visible" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Charging changes", + "anchor": "notif-charging-changes", + "keywords": "changes charging notifications services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Game mode changes", + "anchor": "notif-game-mode-changes", + "keywords": "changes game mode notifications services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Do not disturb changes", + "anchor": "notif-do-not-disturb-changes", + "keywords": "changes disturb do not notifications services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Audio output changes", + "anchor": "notif-audio-output-changes", + "keywords": "audio changes notifications output services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Audio input changes", + "anchor": "notif-audio-input-changes", + "keywords": "audio changes input notifications services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Caps lock changes", + "anchor": "notif-caps-lock-changes", + "keywords": "caps changes lock notifications services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Num lock changes", + "anchor": "notif-num-lock-changes", + "keywords": "changes lock notifications num services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Keyboard layout changes", + "anchor": "notif-keyboard-layout-changes", + "keywords": "changes keyboard layout notifications services" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "VPN changes", + "anchor": "notif-vpn-changes", + "keywords": "changes notifications services vpn" + }, + { + "pageIdx": 8, + "subPath": [ + 1 + ], + "crumbIcons": [ + "build", + "notifications" + ], + "crumbLabels": [ + "Services", + "Notifications" + ], + "title": "Now playing", + "anchor": "notif-now-playing", + "keywords": "notifications now playing services" + }, + { + "pageIdx": 9, + "subPath": [], + "crumbIcons": [ + "globe" + ], + "crumbLabels": [ + "Language & region" + ], + "title": "Temperature", + "anchor": "lang-temperature", + "keywords": "language region temperature" + }, + { + "pageIdx": 9, + "subPath": [], + "crumbIcons": [ + "globe" + ], + "crumbLabels": [ + "Language & region" + ], + "title": "System temperatures", + "anchor": "lang-system-temperatures", + "keywords": "language region system temperatures" + }, + { + "pageIdx": 9, + "subPath": [], + "crumbIcons": [ + "globe" + ], + "crumbLabels": [ + "Language & region" + ], + "title": "Clock format", + "anchor": "lang-clock-format", + "keywords": "clock format language region" + } + ] +} \ No newline at end of file diff --git a/modules/nexus/SettingsIndex.qml b/modules/nexus/SettingsIndex.qml deleted file mode 100644 index d6be2fa75..000000000 --- a/modules/nexus/SettingsIndex.qml +++ /dev/null @@ -1,1072 +0,0 @@ -pragma Singleton - -import QtQuick -import Quickshell - -// A flat index of every searchable setting. pageIdx matches -// PageCompRegistry.pageComps; subPath is the chain of sub-pages to open. The -// crumb* lists hold the icon + label for each step of the path, shown as a -// vertical breadcrumb in the search results. -// -// To make a new setting searchable add a SettingEntry here and give the row a -// matching settingAnchor. -Singleton { - id: root - - readonly property list entries: [ - - // Wallpaper & style - SettingEntry { - pageIdx: 0 - subPath: [] - crumbIcons: ["palette"] - crumbLabels: ["Wallpaper & style"] - title: qsTr("Display wallpaper") - keywords: "display style wallpaper" - anchor: "style-display-wallpaper" - }, - SettingEntry { - pageIdx: 0 - subPath: [] - crumbIcons: ["palette"] - crumbLabels: ["Wallpaper & style"] - title: qsTr("Transparency") - keywords: "style transparency wallpaper" - anchor: "style-transparency" - }, - SettingEntry { - pageIdx: 0 - subPath: [] - crumbIcons: ["palette"] - crumbLabels: ["Wallpaper & style"] - title: qsTr("Dark theme") - keywords: "dark style theme wallpaper" - anchor: "style-dark-theme" - }, - - // Network - SettingEntry { - pageIdx: 1 - subPath: [] - crumbIcons: ["wifi"] - crumbLabels: ["Network"] - title: qsTr("Wi-Fi") - keywords: "network wi-fi" - anchor: "network-wi-fi" - }, - - // Bluetooth - SettingEntry { - pageIdx: 2 - subPath: [] - crumbIcons: ["devices_other"] - crumbLabels: ["Bluetooth"] - title: qsTr("Bluetooth") - keywords: "bluetooth" - anchor: "bluetooth-bluetooth" - }, - SettingEntry { - pageIdx: 2 - subPath: [] - crumbIcons: ["devices_other"] - crumbLabels: ["Bluetooth"] - title: qsTr("Discoverable") - keywords: "bluetooth discoverable" - anchor: "bluetooth-discoverable" - }, - SettingEntry { - pageIdx: 2 - subPath: [] - crumbIcons: ["devices_other"] - crumbLabels: ["Bluetooth"] - title: qsTr("Pairable") - keywords: "bluetooth pairable" - anchor: "bluetooth-pairable" - }, - - // Audio - SettingEntry { - pageIdx: 3 - subPath: [] - crumbIcons: ["volume_up"] - crumbLabels: ["Audio"] - title: qsTr("Output") - keywords: "audio output" - anchor: "audio-output" - }, - SettingEntry { - pageIdx: 3 - subPath: [] - crumbIcons: ["volume_up"] - crumbLabels: ["Audio"] - title: qsTr("Input") - keywords: "audio input" - anchor: "audio-input" - }, - - // Panels - SettingEntry { - pageIdx: 6 - subPath: [] - crumbIcons: ["dock_to_bottom"] - crumbLabels: ["Panels"] - title: qsTr("Dashboard") - keywords: "dashboard panels" - anchor: "panels-dashboard" - }, - SettingEntry { - pageIdx: 6 - subPath: [] - crumbIcons: ["dock_to_bottom"] - crumbLabels: ["Panels"] - title: qsTr("Taskbar") - keywords: "panels taskbar" - anchor: "panels-taskbar" - }, - SettingEntry { - pageIdx: 6 - subPath: [] - crumbIcons: ["dock_to_bottom"] - crumbLabels: ["Panels"] - title: qsTr("Launcher") - keywords: "launcher panels" - anchor: "panels-launcher" - }, - SettingEntry { - pageIdx: 6 - subPath: [] - crumbIcons: ["dock_to_bottom"] - crumbLabels: ["Panels"] - title: qsTr("Sidebar") - keywords: "panels sidebar" - anchor: "panels-sidebar" - }, - - // Panels > Dashboard - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Enabled") - keywords: "dashboard enabled panels" - anchor: "dash-enabled" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Show on hover") - keywords: "dashboard hover on panels show" - anchor: "dash-show-on-hover" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Dashboard") - keywords: "dashboard panels" - anchor: "dash-dashboard" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Media") - keywords: "dashboard media panels" - anchor: "dash-media" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Performance") - keywords: "dashboard panels performance" - anchor: "dash-performance" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Weather") - keywords: "dashboard panels weather" - anchor: "dash-weather" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Battery") - keywords: "battery dashboard panels" - anchor: "dash-battery" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("GPU") - keywords: "dashboard gpu panels" - anchor: "dash-gpu" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("CPU") - keywords: "cpu dashboard panels" - anchor: "dash-cpu" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Memory") - keywords: "dashboard memory panels" - anchor: "dash-memory" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Storage") - keywords: "dashboard panels storage" - anchor: "dash-storage" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Network") - keywords: "dashboard network panels" - anchor: "dash-network" - }, - SettingEntry { - pageIdx: 6 - subPath: [1] - crumbIcons: ["dock_to_bottom", "dashboard"] - crumbLabels: ["Panels", "Dashboard"] - title: qsTr("Drag threshold") - keywords: "dashboard drag panels threshold" - anchor: "dash-drag-threshold" - }, - - // Panels > Taskbar - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Persistent") - keywords: "panels persistent taskbar" - anchor: "taskbar-persistent" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Show on hover") - keywords: "hover on panels show taskbar" - anchor: "taskbar-show-on-hover" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Drag threshold") - keywords: "drag panels taskbar threshold" - anchor: "taskbar-drag-threshold" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Workspaces") - keywords: "panels taskbar workspaces" - anchor: "taskbar-workspaces" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Active window") - keywords: "active panels taskbar window" - anchor: "taskbar-active-window" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Tray") - keywords: "panels taskbar tray" - anchor: "taskbar-tray" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Status icons") - keywords: "icons panels status taskbar" - anchor: "taskbar-status-icons" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Clock") - keywords: "clock panels taskbar" - anchor: "taskbar-clock" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Workspaces") - keywords: "panels taskbar workspaces" - anchor: "taskbar-workspaces-2" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Volume") - keywords: "panels taskbar volume" - anchor: "taskbar-volume" - }, - SettingEntry { - pageIdx: 6 - subPath: [2] - crumbIcons: ["dock_to_bottom", "dock_to_bottom"] - crumbLabels: ["Panels", "Taskbar"] - title: qsTr("Brightness") - keywords: "brightness panels taskbar" - anchor: "taskbar-brightness" - }, - - // Panels > Launcher - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Enabled") - keywords: "enabled launcher panels" - anchor: "launcher-enabled" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Show on hover") - keywords: "hover launcher on panels show" - anchor: "launcher-show-on-hover" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Max items shown") - keywords: "items launcher max panels shown" - anchor: "launcher-max-items-shown" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Max wallpapers") - keywords: "launcher max panels wallpapers" - anchor: "launcher-max-wallpapers" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Drag threshold") - keywords: "drag launcher panels threshold" - anchor: "launcher-drag-threshold" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Vim keybinds") - keywords: "keybinds launcher panels vim" - anchor: "launcher-vim-keybinds" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Enable dangerous actions") - keywords: "actions dangerous enable launcher panels" - anchor: "launcher-enable-dangerous-actions" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Apps") - keywords: "apps launcher panels" - anchor: "launcher-apps" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Actions") - keywords: "actions launcher panels" - anchor: "launcher-actions" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Schemes") - keywords: "launcher panels schemes" - anchor: "launcher-schemes" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Variants") - keywords: "launcher panels variants" - anchor: "launcher-variants" - }, - SettingEntry { - pageIdx: 6 - subPath: [3] - crumbIcons: ["dock_to_bottom", "apps"] - crumbLabels: ["Panels", "Launcher"] - title: qsTr("Wallpapers") - keywords: "launcher panels wallpapers" - anchor: "launcher-wallpapers" - }, - - // Panels > Sidebar - SettingEntry { - pageIdx: 6 - subPath: [4] - crumbIcons: ["dock_to_bottom", "dock_to_right"] - crumbLabels: ["Panels", "Sidebar"] - title: qsTr("Enabled") - keywords: "enabled panels sidebar" - anchor: "sidebar-enabled" - }, - SettingEntry { - pageIdx: 6 - subPath: [4] - crumbIcons: ["dock_to_bottom", "dock_to_right"] - crumbLabels: ["Panels", "Sidebar"] - title: qsTr("Drag threshold") - keywords: "drag panels sidebar threshold" - anchor: "sidebar-drag-threshold" - }, - - // Panels > Taskbar > Workspaces - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Shown") - keywords: "panels shown taskbar workspaces" - anchor: "bar-ws-shown" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Active indicator") - keywords: "active indicator panels taskbar workspaces" - anchor: "bar-ws-active-indicator" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Active trail") - keywords: "active panels taskbar trail workspaces" - anchor: "bar-ws-active-trail" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Occupied background") - keywords: "background occupied panels taskbar workspaces" - anchor: "bar-ws-occupied-background" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Show windows") - keywords: "panels show taskbar windows workspaces" - anchor: "bar-ws-show-windows" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Windows on special workspaces") - keywords: "on panels special taskbar windows workspaces" - anchor: "bar-ws-windows-on-special-workspaces" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Max window icons") - keywords: "icons max panels taskbar window workspaces" - anchor: "bar-ws-max-window-icons" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 5] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "workspaces"] - crumbLabels: ["Panels", "Taskbar", "Workspaces"] - title: qsTr("Per-monitor workspaces") - keywords: "panels per-monitor taskbar workspaces" - anchor: "bar-ws-per-monitor-workspaces" - }, - - // Panels > Taskbar > Active window - SettingEntry { - pageIdx: 6 - subPath: [2, 6] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] - crumbLabels: ["Panels", "Taskbar", "Active window"] - title: qsTr("Compact") - keywords: "active compact panels taskbar window" - anchor: "bar-aw-compact" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 6] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] - crumbLabels: ["Panels", "Taskbar", "Active window"] - title: qsTr("Inverted") - keywords: "active inverted panels taskbar window" - anchor: "bar-aw-inverted" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 6] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] - crumbLabels: ["Panels", "Taskbar", "Active window"] - title: qsTr("Show on hover") - keywords: "active hover on panels show taskbar window" - anchor: "bar-aw-show-on-hover" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 6] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "web_asset"] - crumbLabels: ["Panels", "Taskbar", "Active window"] - title: qsTr("Popout on hover") - keywords: "active hover on panels popout taskbar window" - anchor: "bar-aw-popout-on-hover" - }, - - // Panels > Taskbar > Tray - SettingEntry { - pageIdx: 6 - subPath: [2, 7] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] - crumbLabels: ["Panels", "Taskbar", "Tray"] - title: qsTr("Background") - keywords: "background panels taskbar tray" - anchor: "bar-tray-background" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 7] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] - crumbLabels: ["Panels", "Taskbar", "Tray"] - title: qsTr("Recolour icons") - keywords: "icons panels recolour taskbar tray" - anchor: "bar-tray-recolour-icons" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 7] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] - crumbLabels: ["Panels", "Taskbar", "Tray"] - title: qsTr("Compact") - keywords: "compact panels taskbar tray" - anchor: "bar-tray-compact" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 7] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "widgets"] - crumbLabels: ["Panels", "Taskbar", "Tray"] - title: qsTr("Popout on hover") - keywords: "hover on panels popout taskbar tray" - anchor: "bar-tray-popout-on-hover" - }, - - // Panels > Taskbar > Status icons - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Speakers") - keywords: "icons panels speakers status taskbar" - anchor: "bar-si-speakers" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Microphone") - keywords: "icons microphone panels status taskbar" - anchor: "bar-si-microphone" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Keyboard layout") - keywords: "icons keyboard layout panels status taskbar" - anchor: "bar-si-keyboard-layout" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Network") - keywords: "icons network panels status taskbar" - anchor: "bar-si-network" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Wi-Fi") - keywords: "icons panels status taskbar wi-fi" - anchor: "bar-si-wi-fi" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Bluetooth") - keywords: "bluetooth icons panels status taskbar" - anchor: "bar-si-bluetooth" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Battery") - keywords: "battery icons panels status taskbar" - anchor: "bar-si-battery" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Caps lock") - keywords: "caps icons lock panels status taskbar" - anchor: "bar-si-caps-lock" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 8] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "signal_cellular_alt"] - crumbLabels: ["Panels", "Taskbar", "Status icons"] - title: qsTr("Popout on hover") - keywords: "hover icons on panels popout status taskbar" - anchor: "bar-si-popout-on-hover" - }, - - // Panels > Taskbar > Clock - SettingEntry { - pageIdx: 6 - subPath: [2, 9] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "schedule"] - crumbLabels: ["Panels", "Taskbar", "Clock"] - title: qsTr("Background") - keywords: "background clock panels taskbar" - anchor: "bar-clock-background" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 9] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "schedule"] - crumbLabels: ["Panels", "Taskbar", "Clock"] - title: qsTr("Show date") - keywords: "clock date panels show taskbar" - anchor: "bar-clock-show-date" - }, - SettingEntry { - pageIdx: 6 - subPath: [2, 9] - crumbIcons: ["dock_to_bottom", "dock_to_bottom", "schedule"] - crumbLabels: ["Panels", "Taskbar", "Clock"] - title: qsTr("Show icon") - keywords: "clock icon panels show taskbar" - anchor: "bar-clock-show-icon" - }, - - // Apps - SettingEntry { - pageIdx: 7 - subPath: [] - crumbIcons: ["apps"] - crumbLabels: ["Apps"] - title: qsTr("All apps") - keywords: "all apps" - anchor: "apps-all-apps" - }, - - // Services - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Notifications") - keywords: "notifications services" - anchor: "services-notifications" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Media refresh") - keywords: "media refresh services" - anchor: "services-media-refresh" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("System stats refresh") - keywords: "refresh services stats system" - anchor: "services-system-stats-refresh" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Wi-Fi rescan") - keywords: "rescan services wi-fi" - anchor: "services-wi-fi-rescan" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Lyrics backend") - keywords: "backend lyrics services" - anchor: "services-lyrics-backend" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Default player") - keywords: "default player services" - anchor: "services-default-player" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Volume step") - keywords: "services step volume" - anchor: "services-volume-step" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Brightness step") - keywords: "brightness services step" - anchor: "services-brightness-step" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Max volume") - keywords: "max services volume" - anchor: "services-max-volume" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Visualiser bars") - keywords: "bars services visualiser" - anchor: "services-visualiser-bars" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("Smart colour scheme") - keywords: "colour scheme services smart" - anchor: "services-smart-colour-scheme" - }, - SettingEntry { - pageIdx: 8 - subPath: [] - crumbIcons: ["build"] - crumbLabels: ["Services"] - title: qsTr("GPU") - keywords: "gpu services" - anchor: "services-gpu" - }, - - // Services > Notifications - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Show in fullscreen") - keywords: "fullscreen in notifications services show" - anchor: "notif-show-in-fullscreen" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Expire automatically") - keywords: "automatically expire notifications services" - anchor: "notif-expire-automatically" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Open expanded") - keywords: "expanded notifications open services" - anchor: "notif-open-expanded" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Default timeout") - keywords: "default notifications services timeout" - anchor: "notif-default-timeout" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Group preview count") - keywords: "count group notifications preview services" - anchor: "notif-group-preview-count" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Show in fullscreen") - keywords: "fullscreen in notifications services show" - anchor: "notif-show-in-fullscreen-2" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Visible toasts") - keywords: "notifications services toasts visible" - anchor: "notif-visible-toasts" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Charging changes") - keywords: "changes charging notifications services" - anchor: "notif-charging-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Game mode changes") - keywords: "changes game mode notifications services" - anchor: "notif-game-mode-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Do not disturb changes") - keywords: "changes disturb do not notifications services" - anchor: "notif-do-not-disturb-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Audio output changes") - keywords: "audio changes notifications output services" - anchor: "notif-audio-output-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Audio input changes") - keywords: "audio changes input notifications services" - anchor: "notif-audio-input-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Caps lock changes") - keywords: "caps changes lock notifications services" - anchor: "notif-caps-lock-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Num lock changes") - keywords: "changes lock notifications num services" - anchor: "notif-num-lock-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Keyboard layout changes") - keywords: "changes keyboard layout notifications services" - anchor: "notif-keyboard-layout-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("VPN changes") - keywords: "changes notifications services vpn" - anchor: "notif-vpn-changes" - }, - SettingEntry { - pageIdx: 8 - subPath: [1] - crumbIcons: ["build", "notifications"] - crumbLabels: ["Services", "Notifications"] - title: qsTr("Now playing") - keywords: "notifications now playing services" - anchor: "notif-now-playing" - }, - - // Language & region - SettingEntry { - pageIdx: 9 - subPath: [] - crumbIcons: ["globe"] - crumbLabels: ["Language & region"] - title: qsTr("Temperature") - keywords: "language region temperature" - anchor: "lang-temperature" - }, - SettingEntry { - pageIdx: 9 - subPath: [] - crumbIcons: ["globe"] - crumbLabels: ["Language & region"] - title: qsTr("System temperatures") - keywords: "language region system temperatures" - anchor: "lang-system-temperatures" - }, - SettingEntry { - pageIdx: 9 - subPath: [] - crumbIcons: ["globe"] - crumbLabels: ["Language & region"] - title: qsTr("Clock format") - keywords: "clock format language region" - anchor: "lang-clock-format" - } - ] - - component SettingEntry: QtObject { - required property int pageIdx - property list subPath: [] - required property list crumbIcons - required property list crumbLabels - required property string title - property string keywords - property string anchor - } -} diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index a29c2fd1f..30e3bb345 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -1,14 +1,51 @@ pragma Singleton +import QtQuick +import Quickshell +import Quickshell.Io import qs.utils -import qs.modules.nexus -// Fuzzy searcher over the settings index. Reuses the shell's Searcher util (the -// same engine the launcher uses) so behaviour stays consistent. Title matches -// weigh heaviest, then keywords, then the breadcrumb path. +// Fuzzy searcher over the settings index. The index is generated at build time +// from the page QML files by scripts/build-settings-index.py and shipped as +// assets/settings-index.json, so it stays in sync with the UI without any +// hand-maintained entries. Loaded here into Variants instances (QObjects) so +// the Searcher util (same engine as the launcher) can query them. Breadcrumb +// words are folded into keywords by the build script, so matching on title and +// keywords also matches page/section names. Searcher { - list: SettingsIndex.entries + id: root + + list: entries.instances useFuzzy: true - keys: ["title", "keywords", "crumbLabels"] - weights: [0.6, 0.3, 0.1] + keys: ["title", "keywords"] + weights: [0.7, 0.3] + + Variants { + id: entries + + SettingEntry {} + } + + FileView { + path: Quickshell.shellPath("assets/settings-index.json") + onLoaded: { + try { + entries.model = JSON.parse(text()).entries; + } catch (e) { + entries.model = []; + } + } + } + + component SettingEntry: QtObject { + required property var modelData + + readonly property int pageIdx: modelData.pageIdx + readonly property var subPath: modelData.subPath + readonly property var crumbIcons: modelData.crumbIcons + readonly property var crumbLabels: modelData.crumbLabels + readonly property string title: modelData.title + readonly property string keywords: modelData.keywords ?? "" + readonly property string anchor: modelData.anchor ?? "" + } } diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py new file mode 100644 index 000000000..bf8be5a4c --- /dev/null +++ b/scripts/build-settings-index.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 +"""Build-time settings index extractor for the nexus settings search. + +Parses the nexus page QML files and PageCompRegistry.qml to produce a flat +settings index as JSON. Run at build time (see CMakeLists.txt); the shell loads +the result at runtime via SettingsIndex.qml. + +Usage: build-settings-index.py + nexus-dir path to modules/nexus + output-json where to write settings-index.json +""" +from __future__ import annotations + +import json +import re +import sys +from pathlib import Path + +# Rows that carry a searchable setting and the label property they expose. +ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow)\s*\{') +LABEL_RE = re.compile(r'^\s*(?:label|text):\s*qsTr\("([^"]+)"\)') +ANCHOR_RE = re.compile(r'^\s*settingAnchor:\s*"([^"]+)"') +ICON_RE = re.compile(r'^\s*icon:\s*"([^"]+)"') +# Labels that are too generic to index on their own. +SKIP_LABELS = {"Muted", "None"} + +# Page metadata: maps a page component name to its top-level pageComps index, +# icon, and human label. Pulled from PageRegistry; sub-pages add their own icon. +PAGE_META = { + "WallpaperAndStyle": ("palette", "Wallpaper & style"), + "NetworkPage": ("wifi", "Network"), + "BluetoothPage": ("devices_other", "Bluetooth"), + "AudioPage": ("volume_up", "Audio"), + "PanelsPage": ("dock_to_bottom", "Panels"), + "AppsPage": ("apps", "Apps"), + "ServicesPage": ("build", "Services"), + "LanguageAndRegion": ("globe", "Language & region"), +} + + +def parse_page_comps(path: Path) -> list[list[str]]: + """Return, per top-level pageComps entry, the ordered list of page + component names inside it (index 0 is the main page, rest are sub-pages).""" + text = path.read_text() + # Grab the pageComps array body. + start = text.index("pageComps:") + body = text[start:] + comps: list[list[str]] = [] + depth = 0 + current: list[str] | None = None + # Walk lines tracking the top-level Component blocks (8-space indent). + for line in body.splitlines(): + if re.match(r"^ Component \{", line): + current = [] + comps.append(current) + m = re.search(r"([A-Z][A-Za-z]+)\s*\{\}", line) + if m and current is not None: + current.append(m.group(1)) + return comps + + +def build_nav_map(nexus: Path) -> dict[str, dict]: + """Map each page component name -> {pageIdx, subPath, crumbIcons, + crumbLabels}. Sub-page paths are derived from openSubPage() calls in their + parent pages plus the pageComps ordering.""" + comps = parse_page_comps(nexus / "PageCompRegistry.qml") + + # Component name -> (top index, position within its StackPage) + location: dict[str, tuple[int, int]] = {} + for top_idx, names in enumerate(comps): + for pos, name in enumerate(names): + location.setdefault(name, (top_idx, pos)) + + # For the main page of each top entry, find openSubPage(N) -> which child, + # and the NavRow icon/label that triggers it, to build breadcrumbs. + # Parent page file -> list of (childPos, icon, label) + def page_file(name: str) -> Path | None: + for sub in ("", "panels", "panels/taskbar", "services", "apps", + "bluetooth", "audio", "wallandstyle"): + p = nexus / "pages" / sub / f"{name}.qml" if sub else nexus / "pages" / f"{name}.qml" + if p.exists(): + return p + return None + + # Build child nav info: parentName -> {childPos: (icon, label)} + # Scan every page file (main and sub-pages) for openSubPage() calls so deep + # chains like Taskbar -> Workspaces are captured. + nav_children: dict[str, dict[int, tuple[str, str]]] = {} + for names in comps: + for name in names: + pf = page_file(name) + if not pf: + continue + lines = pf.read_text().splitlines() + pending_icon = None + pending_label = None + for ln in lines: + mi = ICON_RE.match(ln) + if mi: + pending_icon = mi.group(1) + ml = LABEL_RE.match(ln) + if ml: + pending_label = ml.group(1) + mo = re.search(r"openSubPage\((\d+)\)", ln) + if mo: + pos = int(mo.group(1)) + nav_children.setdefault(name, {})[pos] = ( + pending_icon or "tune", pending_label or "") + pending_icon = pending_label = None + + # Now assemble nav map per component. + nav: dict[str, dict] = {} + for top_idx, names in enumerate(comps): + if not names: + continue + main = names[0] + main_icon, main_label = PAGE_META.get(main, ("tune", main)) + # main page + nav[main] = { + "pageIdx": top_idx, "subPath": [], + "crumbIcons": [main_icon], "crumbLabels": [main_label], + } + # direct children reachable from main via openSubPage + for pos, (icon, label) in nav_children.get(main, {}).items(): + if pos >= len(names): + continue + child = names[pos] + nav[child] = { + "pageIdx": top_idx, "subPath": [pos], + "crumbIcons": [main_icon, icon], "crumbLabels": [main_label, label], + } + # grandchildren: children of this child (e.g. Taskbar -> Bar*) + for gpos, (gicon, glabel) in nav_children.get(child, {}).items(): + if gpos >= len(names): + continue + gchild = names[gpos] + nav[gchild] = { + "pageIdx": top_idx, "subPath": [pos, gpos], + "crumbIcons": [main_icon, icon, gicon], + "crumbLabels": [main_label, label, glabel], + } + return nav + + +def slug(s: str) -> str: + return re.sub(r"[^a-z0-9]+", "-", s.lower()).strip("-") + + +def extract_settings(nexus: Path, nav: dict[str, dict]) -> list[dict]: + entries: list[dict] = [] + for comp, meta in nav.items(): + # find the file for this component + pf = None + for sub in ("", "panels", "panels/taskbar", "services", "apps", + "bluetooth", "audio", "wallandstyle"): + p = (nexus / "pages" / sub / f"{comp}.qml") if sub else (nexus / "pages" / f"{comp}.qml") + if p.exists(): + pf = p + break + if not pf: + continue + lines = pf.read_text().splitlines() + i = 0 + while i < len(lines): + if ROW_RE.match(lines[i]): + label = anchor = None + for j in range(i + 1, min(i + 10, len(lines))): + if label is None: + m = LABEL_RE.match(lines[j]) + if m: + label = m.group(1) + if anchor is None: + a = ANCHOR_RE.match(lines[j]) + if a: + anchor = a.group(1) + if label and label not in SKIP_LABELS and anchor: + kw = set(label.lower().split()) + for cl in meta["crumbLabels"]: + kw |= set(cl.lower().replace("&", "").split()) + entries.append({ + "pageIdx": meta["pageIdx"], + "subPath": meta["subPath"], + "crumbIcons": meta["crumbIcons"], + "crumbLabels": meta["crumbLabels"], + "title": label, + "anchor": anchor, + "keywords": " ".join(sorted(w for w in kw if w)), + }) + i += 1 + return entries + + +def main() -> int: + if len(sys.argv) != 3: + print(__doc__) + return 1 + nexus = Path(sys.argv[1]) + out = Path(sys.argv[2]) + nav = build_nav_map(nexus) + entries = extract_settings(nexus, nav) + out.write_text(json.dumps({"version": 1, "entries": entries}, ensure_ascii=False, indent=2)) + print(f"settings index: {len(entries)} entries -> {out}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 6a4fd607bfed4211c69a083776920732f1613ea3 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 02:06:02 +0000 Subject: [PATCH 07/57] fix(nexus): limit settings search to top matches to keep it responsive --- modules/nexus/SettingsSearcher.qml | 4 ++++ modules/nexus/navpane/NavLocations.qml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 30e3bb345..c99ee1b78 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -19,6 +19,10 @@ Searcher { useFuzzy: true keys: ["title", "keywords"] weights: [0.7, 0.3] + extraOpts: ({ + all: false, + limit: 12 + }) Variants { id: entries diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index cb8e810ed..ce26c54d4 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -15,7 +15,7 @@ VerticalFadeFlickable { readonly property string search: nState.searchText readonly property bool searching: search.length > 0 - readonly property var results: searching ? SettingsSearcher.query(search) : [] + readonly property var results: searching ? SettingsSearcher.query(search).slice(0, 12) : [] topMargin: Tokens.padding.large bottomMargin: Tokens.padding.large From 45fed951f9a33c2f1200afcf40205469319eb2ff Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 03:13:08 +0000 Subject: [PATCH 08/57] fix(nexus): don't reload the page when jumping within the same sub-page --- modules/nexus/NexusState.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index 3f98f7c6a..35ade0c32 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -38,9 +38,17 @@ QtObject { // once (see StackPage.Component.onCompleted), which avoids the half-open // state that firing openSubPage signals one by one would cause. function jumpToSetting(pageIdx: int, subPath: var, anchor: string): void { + const samePage = currentPageIdx === pageIdx; + const sameSub = subPageIdxStack.length === subPath.length && subPath.every((v, i) => subPageIdxStack[i] === v); + if (samePage && sameSub) { + // Already exactly here: just re-trigger the scroll/highlight. + searchAnchor = ""; + searchAnchor = anchor; + return; + } searchAnchor = anchor; - if (currentPageIdx === pageIdx) { - // Already on the page: reset and re-open the sub-page chain live. + if (samePage) { + // Same page, different sub-page: rebuild the sub-page chain live. while (subPageIdxStack.length > 0) closeSubPage(); for (let i = 0; i < subPath.length; i++) From 9934dd98e69d05a9786d12786cc1aeb04c213244 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 03:20:52 +0000 Subject: [PATCH 09/57] fix(nexus): scroll search target clear of the fade edges --- modules/nexus/common/PageBase.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 6c7e66533..5aa0f5dec 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -28,7 +28,9 @@ ColumnLayout { if (!row) return false; const pos = row.mapToItem(flickable.contentItem, 0, 0); - const target = Math.max(0, Math.min(pos.y - Tokens.padding.large, flickable.contentHeight - flickable.height)); + // Land the row below the top fade so it isn't dimmed by the edge effect. + const inset = flickable.height * flickable.fadeAmount + Tokens.padding.large; + const target = Math.max(0, Math.min(pos.y - inset, flickable.contentHeight - flickable.height)); flickable.contentY = target; if (row.flashHighlight !== undefined) // qmllint disable missing-property row.flashHighlight(); From 6bd230de67988075da647a460e5a51f89bd813ba Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 03:31:11 +0000 Subject: [PATCH 10/57] fix(nexus): correct scroll bounds and re-highlight without scrolling --- modules/nexus/NexusState.qml | 6 +++--- modules/nexus/common/PageBase.qml | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index 35ade0c32..571b1c8a9 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -21,6 +21,7 @@ QtObject { signal close signal subPageOpened(idx: int) signal subPageClosed + signal highlightSetting(anchor: string) function openSubPage(idx: int): void { subPageIdxStack.push(idx); @@ -41,9 +42,8 @@ QtObject { const samePage = currentPageIdx === pageIdx; const sameSub = subPageIdxStack.length === subPath.length && subPath.every((v, i) => subPageIdxStack[i] === v); if (samePage && sameSub) { - // Already exactly here: just re-trigger the scroll/highlight. - searchAnchor = ""; - searchAnchor = anchor; + // Already exactly here: just flash the row again, don't scroll. + highlightSetting(anchor); return; } searchAnchor = anchor; diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 5aa0f5dec..3370c1df7 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -28,9 +28,12 @@ ColumnLayout { if (!row) return false; const pos = row.mapToItem(flickable.contentItem, 0, 0); - // Land the row below the top fade so it isn't dimmed by the edge effect. + // Land the row below the top fade so it isn't dimmed by the edge effect, + // clamped to the flickable's real scroll range (which includes margins). const inset = flickable.height * flickable.fadeAmount + Tokens.padding.large; - const target = Math.max(0, Math.min(pos.y - inset, flickable.contentHeight - flickable.height)); + const minY = -flickable.topMargin; + const maxY = Math.max(minY, flickable.contentHeight + flickable.bottomMargin - flickable.height); + const target = Math.max(minY, Math.min(pos.y - inset, maxY)); flickable.contentY = target; if (row.flashHighlight !== undefined) // qmllint disable missing-property row.flashHighlight(); @@ -60,6 +63,13 @@ ColumnLayout { }); } + // Flash a row without scrolling (used when re-selecting the current setting). + function highlightAnchor(anchor: string): void { + const row = findAnchor(contentChild, anchor); + if (row && row.flashHighlight !== undefined) // qmllint disable missing-property + row.flashHighlight(); + } + spacing: Tokens.spacing.extraLargeIncreased Component.onCompleted: applySearchAnchor() @@ -69,6 +79,10 @@ ColumnLayout { root.applySearchAnchor(); } + function onHighlightSetting(anchor: string): void { + root.highlightAnchor(anchor); + } + target: root.nState } From ea4241b42c94f67a5826535dec85e8c3211c2fe1 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 03:42:36 +0000 Subject: [PATCH 11/57] fix(nexus): scroll to other settings on the same page, skip only exact re-clicks --- modules/nexus/NexusState.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index 571b1c8a9..56619e77b 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -12,6 +12,7 @@ QtObject { property bool searchOpen property string searchText property string searchAnchor + property string _lastAnchor property string selectedWallpaperCategory property BluetoothDevice selectedBtDevice @@ -41,11 +42,18 @@ QtObject { function jumpToSetting(pageIdx: int, subPath: var, anchor: string): void { const samePage = currentPageIdx === pageIdx; const sameSub = subPageIdxStack.length === subPath.length && subPath.every((v, i) => subPageIdxStack[i] === v); - if (samePage && sameSub) { - // Already exactly here: just flash the row again, don't scroll. + if (samePage && sameSub && anchor === _lastAnchor) { + // Re-clicking the exact same setting: flash it again, don't scroll. highlightSetting(anchor); return; } + _lastAnchor = anchor; + if (samePage && sameSub) { + // Same page, different setting: just scroll to it. + searchAnchor = ""; + searchAnchor = anchor; + return; + } searchAnchor = anchor; if (samePage) { // Same page, different sub-page: rebuild the sub-page chain live. From af0dae3d544f1cdc5d29b71343869b5b52424162 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 11:30:10 +0000 Subject: [PATCH 12/57] feat(nexus): build a real inverted index with ranking and auto-detected page metadata --- assets/settings-index.json | 1412 ++++++++++++++++- modules/nexus/SettingsSearcher.qml | 85 +- .../build-settings-index.cpython-312.pyc | Bin 0 -> 11879 bytes scripts/build-settings-index.py | 249 +-- 4 files changed, 1606 insertions(+), 140 deletions(-) create mode 100644 scripts/__pycache__/build-settings-index.cpython-312.pyc diff --git a/assets/settings-index.json b/assets/settings-index.json index 48b3f99a1..cf089c7e8 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -1,5 +1,5 @@ { - "version": 1, + "version": 2, "entries": [ { "pageIdx": 0, @@ -51,7 +51,7 @@ ], "title": "Wi-Fi", "anchor": "network-wi-fi", - "keywords": "network wi-fi" + "keywords": "fi network wi wifi" }, { "pageIdx": 2, @@ -60,11 +60,11 @@ "devices_other" ], "crumbLabels": [ - "Bluetooth" + "Connected devices" ], "title": "Bluetooth", "anchor": "bluetooth-bluetooth", - "keywords": "bluetooth" + "keywords": "bluetooth connected devices" }, { "pageIdx": 2, @@ -73,11 +73,11 @@ "devices_other" ], "crumbLabels": [ - "Bluetooth" + "Connected devices" ], "title": "Discoverable", "anchor": "bluetooth-discoverable", - "keywords": "bluetooth discoverable" + "keywords": "connected devices discoverable" }, { "pageIdx": 2, @@ -86,11 +86,11 @@ "devices_other" ], "crumbLabels": [ - "Bluetooth" + "Connected devices" ], "title": "Pairable", "anchor": "bluetooth-pairable", - "keywords": "bluetooth pairable" + "keywords": "connected devices pairable" }, { "pageIdx": 3, @@ -202,7 +202,7 @@ ], "title": "Show on hover", "anchor": "dash-show-on-hover", - "keywords": "dashboard hover on panels show" + "keywords": "dashboard hover panels show" }, { "pageIdx": 6, @@ -423,7 +423,7 @@ ], "title": "Show on hover", "anchor": "taskbar-show-on-hover", - "keywords": "hover on panels show taskbar" + "keywords": "hover panels show taskbar" }, { "pageIdx": 6, @@ -696,7 +696,7 @@ ], "title": "Windows on special workspaces", "anchor": "bar-ws-windows-on-special-workspaces", - "keywords": "on panels special taskbar windows workspaces" + "keywords": "panels special taskbar windows workspaces" }, { "pageIdx": 6, @@ -736,7 +736,7 @@ ], "title": "Per-monitor workspaces", "anchor": "bar-ws-per-monitor-workspaces", - "keywords": "panels per-monitor taskbar workspaces" + "keywords": "monitor panels per permonitor taskbar workspaces" }, { "pageIdx": 6, @@ -796,7 +796,7 @@ ], "title": "Show on hover", "anchor": "bar-aw-show-on-hover", - "keywords": "active hover on panels show taskbar window" + "keywords": "active hover panels show taskbar window" }, { "pageIdx": 6, @@ -816,7 +816,7 @@ ], "title": "Popout on hover", "anchor": "bar-aw-popout-on-hover", - "keywords": "active hover on panels popout taskbar window" + "keywords": "active hover panels popout taskbar window" }, { "pageIdx": 6, @@ -896,7 +896,7 @@ ], "title": "Popout on hover", "anchor": "bar-tray-popout-on-hover", - "keywords": "hover on panels popout taskbar tray" + "keywords": "hover panels popout taskbar tray" }, { "pageIdx": 6, @@ -996,7 +996,7 @@ ], "title": "Wi-Fi", "anchor": "bar-si-wi-fi", - "keywords": "icons panels status taskbar wi-fi" + "keywords": "fi icons panels status taskbar wi wifi" }, { "pageIdx": 6, @@ -1076,7 +1076,7 @@ ], "title": "Popout on hover", "anchor": "bar-si-popout-on-hover", - "keywords": "hover icons on panels popout status taskbar" + "keywords": "hover icons panels popout status taskbar" }, { "pageIdx": 6, @@ -1170,7 +1170,7 @@ ], "title": "Show on hover", "anchor": "launcher-show-on-hover", - "keywords": "hover launcher on panels show" + "keywords": "hover launcher panels show" }, { "pageIdx": 6, @@ -1439,7 +1439,7 @@ ], "title": "Wi-Fi rescan", "anchor": "services-wi-fi-rescan", - "keywords": "rescan services wi-fi" + "keywords": "fi rescan services wi wifi" }, { "pageIdx": 8, @@ -1560,7 +1560,7 @@ ], "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen", - "keywords": "fullscreen in notifications services show" + "keywords": "fullscreen notifications services show" }, { "pageIdx": 8, @@ -1645,7 +1645,7 @@ ], "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen-2", - "keywords": "fullscreen in notifications services show" + "keywords": "fullscreen notifications services show" }, { "pageIdx": 8, @@ -1873,5 +1873,1373 @@ "anchor": "lang-clock-format", "keywords": "clock format language region" } - ] + ], + "inverted": { + "display": [ + 0 + ], + "wallpaper": [ + 0, + 1, + 2 + ], + "style": [ + 0, + 1, + 2 + ], + "transparency": [ + 1 + ], + "dark": [ + 2 + ], + "theme": [ + 2 + ], + "wi": [ + 3, + 57, + 83 + ], + "fi": [ + 3, + 57, + 83 + ], + "wifi": [ + 3, + 57, + 83 + ], + "network": [ + 24, + 56, + 3 + ], + "bluetooth": [ + 4, + 58 + ], + "connected": [ + 4, + 5, + 6 + ], + "devices": [ + 4, + 5, + 6 + ], + "discoverable": [ + 5 + ], + "pairable": [ + 6 + ], + "output": [ + 7, + 102 + ], + "audio": [ + 102, + 103, + 7, + 8 + ], + "input": [ + 8, + 103 + ], + "dashboard": [ + 9, + 15, + 13, + 14, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25 + ], + "panels": [ + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78 + ], + "taskbar": [ + 10, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64 + ], + "launcher": [ + 11, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76 + ], + "sidebar": [ + 12, + 77, + 78 + ], + "enabled": [ + 13, + 65, + 77 + ], + "show": [ + 14, + 27, + 41, + 47, + 63, + 64, + 66, + 92, + 97 + ], + "hover": [ + 14, + 27, + 47, + 48, + 52, + 61, + 66 + ], + "media": [ + 16, + 81 + ], + "performance": [ + 17 + ], + "weather": [ + 18 + ], + "battery": [ + 19, + 59 + ], + "gpu": [ + 20, + 91 + ], + "cpu": [ + 21 + ], + "memory": [ + 22 + ], + "storage": [ + 23 + ], + "drag": [ + 25, + 28, + 69, + 78 + ], + "threshold": [ + 25, + 28, + 69, + 78 + ], + "persistent": [ + 26 + ], + "workspaces": [ + 29, + 34, + 42, + 44, + 37, + 38, + 39, + 40, + 41, + 43 + ], + "active": [ + 30, + 38, + 39, + 45, + 46, + 47, + 48 + ], + "window": [ + 30, + 43, + 45, + 46, + 47, + 48 + ], + "tray": [ + 31, + 49, + 50, + 51, + 52 + ], + "status": [ + 32, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61 + ], + "icons": [ + 32, + 43, + 50, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61 + ], + "clock": [ + 33, + 111, + 62, + 63, + 64 + ], + "volume": [ + 35, + 86, + 88 + ], + "brightness": [ + 36, + 87 + ], + "shown": [ + 37, + 67 + ], + "indicator": [ + 38 + ], + "trail": [ + 39 + ], + "occupied": [ + 40 + ], + "background": [ + 40, + 49, + 62 + ], + "windows": [ + 41, + 42 + ], + "special": [ + 42 + ], + "max": [ + 43, + 67, + 68, + 88 + ], + "per": [ + 44 + ], + "monitor": [ + 44 + ], + "permonitor": [ + 44 + ], + "compact": [ + 45, + 51 + ], + "inverted": [ + 46 + ], + "popout": [ + 48, + 52, + 61 + ], + "recolour": [ + 50 + ], + "speakers": [ + 53 + ], + "microphone": [ + 54 + ], + "keyboard": [ + 55, + 106 + ], + "layout": [ + 55, + 106 + ], + "caps": [ + 60, + 104 + ], + "lock": [ + 60, + 104, + 105 + ], + "date": [ + 63 + ], + "icon": [ + 64 + ], + "items": [ + 67 + ], + "wallpapers": [ + 68, + 76 + ], + "vim": [ + 70 + ], + "keybinds": [ + 70 + ], + "enable": [ + 71 + ], + "dangerous": [ + 71 + ], + "actions": [ + 71, + 73 + ], + "apps": [ + 72, + 79 + ], + "schemes": [ + 74 + ], + "variants": [ + 75 + ], + "all": [ + 79 + ], + "notifications": [ + 80, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108 + ], + "services": [ + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108 + ], + "refresh": [ + 81, + 82 + ], + "system": [ + 82, + 110 + ], + "stats": [ + 82 + ], + "rescan": [ + 83 + ], + "lyrics": [ + 84 + ], + "backend": [ + 84 + ], + "default": [ + 85, + 95 + ], + "player": [ + 85 + ], + "step": [ + 86, + 87 + ], + "visualiser": [ + 89 + ], + "bars": [ + 89 + ], + "smart": [ + 90 + ], + "colour": [ + 90 + ], + "scheme": [ + 90 + ], + "fullscreen": [ + 92, + 97 + ], + "expire": [ + 93 + ], + "automatically": [ + 93 + ], + "open": [ + 94 + ], + "expanded": [ + 94 + ], + "timeout": [ + 95 + ], + "group": [ + 96 + ], + "preview": [ + 96 + ], + "count": [ + 96 + ], + "visible": [ + 98 + ], + "toasts": [ + 98 + ], + "charging": [ + 99 + ], + "changes": [ + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107 + ], + "game": [ + 100 + ], + "mode": [ + 100 + ], + "do": [ + 101 + ], + "not": [ + 101 + ], + "disturb": [ + 101 + ], + "num": [ + 105 + ], + "vpn": [ + 107 + ], + "now": [ + 108 + ], + "playing": [ + 108 + ], + "temperature": [ + 109 + ], + "language": [ + 109, + 110, + 111 + ], + "region": [ + 109, + 110, + 111 + ], + "temperatures": [ + 110 + ], + "format": [ + 111 + ] + }, + "ranking": { + "display": { + "0": 1.0 + }, + "wallpaper": { + "0": 1.0, + "1": 0.4, + "2": 0.4 + }, + "style": { + "0": 0.4, + "1": 0.4, + "2": 0.4 + }, + "transparency": { + "1": 1.0 + }, + "dark": { + "2": 1.0 + }, + "theme": { + "2": 1.0 + }, + "wi": { + "3": 1.0, + "57": 1.0, + "83": 1.0 + }, + "fi": { + "3": 1.0, + "57": 1.0, + "83": 1.0 + }, + "wifi": { + "3": 1.0, + "57": 1.0, + "83": 1.0 + }, + "network": { + "3": 0.4, + "24": 1.0, + "56": 1.0 + }, + "bluetooth": { + "4": 1.0, + "58": 1.0 + }, + "connected": { + "4": 0.4, + "5": 0.4, + "6": 0.4 + }, + "devices": { + "4": 0.4, + "5": 0.4, + "6": 0.4 + }, + "discoverable": { + "5": 1.0 + }, + "pairable": { + "6": 1.0 + }, + "output": { + "7": 1.0, + "102": 1.0 + }, + "audio": { + "7": 0.4, + "8": 0.4, + "102": 1.0, + "103": 1.0 + }, + "input": { + "8": 1.0, + "103": 1.0 + }, + "dashboard": { + "9": 1.0, + "13": 0.4, + "14": 0.4, + "15": 1.0, + "16": 0.4, + "17": 0.4, + "18": 0.4, + "19": 0.4, + "20": 0.4, + "21": 0.4, + "22": 0.4, + "23": 0.4, + "24": 0.4, + "25": 0.4 + }, + "panels": { + "9": 0.4, + "10": 0.4, + "11": 0.4, + "12": 0.4, + "13": 0.4, + "14": 0.4, + "15": 0.4, + "16": 0.4, + "17": 0.4, + "18": 0.4, + "19": 0.4, + "20": 0.4, + "21": 0.4, + "22": 0.4, + "23": 0.4, + "24": 0.4, + "25": 0.4, + "26": 0.4, + "27": 0.4, + "28": 0.4, + "29": 0.4, + "30": 0.4, + "31": 0.4, + "32": 0.4, + "33": 0.4, + "34": 0.4, + "35": 0.4, + "36": 0.4, + "37": 0.4, + "38": 0.4, + "39": 0.4, + "40": 0.4, + "41": 0.4, + "42": 0.4, + "43": 0.4, + "44": 0.4, + "45": 0.4, + "46": 0.4, + "47": 0.4, + "48": 0.4, + "49": 0.4, + "50": 0.4, + "51": 0.4, + "52": 0.4, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4, + "69": 0.4, + "70": 0.4, + "71": 0.4, + "72": 0.4, + "73": 0.4, + "74": 0.4, + "75": 0.4, + "76": 0.4, + "77": 0.4, + "78": 0.4 + }, + "taskbar": { + "10": 1.0, + "26": 0.4, + "27": 0.4, + "28": 0.4, + "29": 0.4, + "30": 0.4, + "31": 0.4, + "32": 0.4, + "33": 0.4, + "34": 0.4, + "35": 0.4, + "36": 0.4, + "37": 0.4, + "38": 0.4, + "39": 0.4, + "40": 0.4, + "41": 0.4, + "42": 0.4, + "43": 0.4, + "44": 0.4, + "45": 0.4, + "46": 0.4, + "47": 0.4, + "48": 0.4, + "49": 0.4, + "50": 0.4, + "51": 0.4, + "52": 0.4, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4 + }, + "launcher": { + "11": 1.0, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4, + "69": 0.4, + "70": 0.4, + "71": 0.4, + "72": 0.4, + "73": 0.4, + "74": 0.4, + "75": 0.4, + "76": 0.4 + }, + "sidebar": { + "12": 1.0, + "77": 0.4, + "78": 0.4 + }, + "enabled": { + "13": 1.0, + "65": 1.0, + "77": 1.0 + }, + "show": { + "14": 1.0, + "27": 1.0, + "41": 1.0, + "47": 1.0, + "63": 1.0, + "64": 1.0, + "66": 1.0, + "92": 1.0, + "97": 1.0 + }, + "hover": { + "14": 1.0, + "27": 1.0, + "47": 1.0, + "48": 1.0, + "52": 1.0, + "61": 1.0, + "66": 1.0 + }, + "media": { + "16": 1.0, + "81": 1.0 + }, + "performance": { + "17": 1.0 + }, + "weather": { + "18": 1.0 + }, + "battery": { + "19": 1.0, + "59": 1.0 + }, + "gpu": { + "20": 1.0, + "91": 1.0 + }, + "cpu": { + "21": 1.0 + }, + "memory": { + "22": 1.0 + }, + "storage": { + "23": 1.0 + }, + "drag": { + "25": 1.0, + "28": 1.0, + "69": 1.0, + "78": 1.0 + }, + "threshold": { + "25": 1.0, + "28": 1.0, + "69": 1.0, + "78": 1.0 + }, + "persistent": { + "26": 1.0 + }, + "workspaces": { + "29": 1.0, + "34": 1.0, + "37": 0.4, + "38": 0.4, + "39": 0.4, + "40": 0.4, + "41": 0.4, + "42": 1.0, + "43": 0.4, + "44": 1.0 + }, + "active": { + "30": 1.0, + "38": 1.0, + "39": 1.0, + "45": 0.4, + "46": 0.4, + "47": 0.4, + "48": 0.4 + }, + "window": { + "30": 1.0, + "43": 1.0, + "45": 0.4, + "46": 0.4, + "47": 0.4, + "48": 0.4 + }, + "tray": { + "31": 1.0, + "49": 0.4, + "50": 0.4, + "51": 0.4, + "52": 0.4 + }, + "status": { + "32": 1.0, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "61": 0.4 + }, + "icons": { + "32": 1.0, + "43": 1.0, + "50": 1.0, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "61": 0.4 + }, + "clock": { + "33": 1.0, + "62": 0.4, + "63": 0.4, + "64": 0.4, + "111": 1.0 + }, + "volume": { + "35": 1.0, + "86": 1.0, + "88": 1.0 + }, + "brightness": { + "36": 1.0, + "87": 1.0 + }, + "shown": { + "37": 1.0, + "67": 1.0 + }, + "indicator": { + "38": 1.0 + }, + "trail": { + "39": 1.0 + }, + "occupied": { + "40": 1.0 + }, + "background": { + "40": 1.0, + "49": 1.0, + "62": 1.0 + }, + "windows": { + "41": 1.0, + "42": 1.0 + }, + "special": { + "42": 1.0 + }, + "max": { + "43": 1.0, + "67": 1.0, + "68": 1.0, + "88": 1.0 + }, + "per": { + "44": 1.0 + }, + "monitor": { + "44": 1.0 + }, + "permonitor": { + "44": 1.0 + }, + "compact": { + "45": 1.0, + "51": 1.0 + }, + "inverted": { + "46": 1.0 + }, + "popout": { + "48": 1.0, + "52": 1.0, + "61": 1.0 + }, + "recolour": { + "50": 1.0 + }, + "speakers": { + "53": 1.0 + }, + "microphone": { + "54": 1.0 + }, + "keyboard": { + "55": 1.0, + "106": 1.0 + }, + "layout": { + "55": 1.0, + "106": 1.0 + }, + "caps": { + "60": 1.0, + "104": 1.0 + }, + "lock": { + "60": 1.0, + "104": 1.0, + "105": 1.0 + }, + "date": { + "63": 1.0 + }, + "icon": { + "64": 1.0 + }, + "items": { + "67": 1.0 + }, + "wallpapers": { + "68": 1.0, + "76": 1.0 + }, + "vim": { + "70": 1.0 + }, + "keybinds": { + "70": 1.0 + }, + "enable": { + "71": 1.0 + }, + "dangerous": { + "71": 1.0 + }, + "actions": { + "71": 1.0, + "73": 1.0 + }, + "apps": { + "72": 1.0, + "79": 1.0 + }, + "schemes": { + "74": 1.0 + }, + "variants": { + "75": 1.0 + }, + "all": { + "79": 1.0 + }, + "notifications": { + "80": 1.0, + "92": 0.4, + "93": 0.4, + "94": 0.4, + "95": 0.4, + "96": 0.4, + "97": 0.4, + "98": 0.4, + "99": 0.4, + "100": 0.4, + "101": 0.4, + "102": 0.4, + "103": 0.4, + "104": 0.4, + "105": 0.4, + "106": 0.4, + "107": 0.4, + "108": 0.4 + }, + "services": { + "80": 0.4, + "81": 0.4, + "82": 0.4, + "83": 0.4, + "84": 0.4, + "85": 0.4, + "86": 0.4, + "87": 0.4, + "88": 0.4, + "89": 0.4, + "90": 0.4, + "91": 0.4, + "92": 0.4, + "93": 0.4, + "94": 0.4, + "95": 0.4, + "96": 0.4, + "97": 0.4, + "98": 0.4, + "99": 0.4, + "100": 0.4, + "101": 0.4, + "102": 0.4, + "103": 0.4, + "104": 0.4, + "105": 0.4, + "106": 0.4, + "107": 0.4, + "108": 0.4 + }, + "refresh": { + "81": 1.0, + "82": 1.0 + }, + "system": { + "82": 1.0, + "110": 1.0 + }, + "stats": { + "82": 1.0 + }, + "rescan": { + "83": 1.0 + }, + "lyrics": { + "84": 1.0 + }, + "backend": { + "84": 1.0 + }, + "default": { + "85": 1.0, + "95": 1.0 + }, + "player": { + "85": 1.0 + }, + "step": { + "86": 1.0, + "87": 1.0 + }, + "visualiser": { + "89": 1.0 + }, + "bars": { + "89": 1.0 + }, + "smart": { + "90": 1.0 + }, + "colour": { + "90": 1.0 + }, + "scheme": { + "90": 1.0 + }, + "fullscreen": { + "92": 1.0, + "97": 1.0 + }, + "expire": { + "93": 1.0 + }, + "automatically": { + "93": 1.0 + }, + "open": { + "94": 1.0 + }, + "expanded": { + "94": 1.0 + }, + "timeout": { + "95": 1.0 + }, + "group": { + "96": 1.0 + }, + "preview": { + "96": 1.0 + }, + "count": { + "96": 1.0 + }, + "visible": { + "98": 1.0 + }, + "toasts": { + "98": 1.0 + }, + "charging": { + "99": 1.0 + }, + "changes": { + "99": 1.0, + "100": 1.0, + "101": 1.0, + "102": 1.0, + "103": 1.0, + "104": 1.0, + "105": 1.0, + "106": 1.0, + "107": 1.0 + }, + "game": { + "100": 1.0 + }, + "mode": { + "100": 1.0 + }, + "do": { + "101": 1.0 + }, + "not": { + "101": 1.0 + }, + "disturb": { + "101": 1.0 + }, + "num": { + "105": 1.0 + }, + "vpn": { + "107": 1.0 + }, + "now": { + "108": 1.0 + }, + "playing": { + "108": 1.0 + }, + "temperature": { + "109": 1.0 + }, + "language": { + "109": 0.4, + "110": 0.4, + "111": 0.4 + }, + "region": { + "109": 0.4, + "110": 0.4, + "111": 0.4 + }, + "temperatures": { + "110": 1.0 + }, + "format": { + "111": 1.0 + } + } } \ No newline at end of file diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index c99ee1b78..f55809f97 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -3,26 +3,72 @@ pragma Singleton import QtQuick import Quickshell import Quickshell.Io -import qs.utils -// Fuzzy searcher over the settings index. The index is generated at build time +// Search service over the settings index. The index is generated at build time // from the page QML files by scripts/build-settings-index.py and shipped as -// assets/settings-index.json, so it stays in sync with the UI without any -// hand-maintained entries. Loaded here into Variants instances (QObjects) so -// the Searcher util (same engine as the launcher) can query them. Breadcrumb -// words are folded into keywords by the build script, so matching on title and -// keywords also matches page/section names. -Searcher { +// assets/settings-index.json (version 2), so it stays in sync with the UI +// without any hand-maintained entries. +// +// Unlike the launcher's fuzzy searcher, this uses the real inverted index + +// ranking baked into the JSON: a query is tokenised, each token is looked up in +// the inverted index (exact token or prefix), the matching entry ids are scored +// with the precomputed per-token ranking, and the best entries are returned. +// SettingEntry QObjects are produced via Variants so the result objects expose +// the same properties the result list expects. +Singleton { id: root - list: entries.instances - useFuzzy: true - keys: ["title", "keywords"] - weights: [0.7, 0.3] - extraOpts: ({ - all: false, - limit: 12 - }) + // entries: forward index (one record per setting) + // inverted: token -> [entry id...] + // ranking: token -> { entry id (string): weight } + property var inverted: ({}) + property var ranking: ({}) + + function query(search: string): list { + const tokens = root._tokenize(search); + if (tokens.length === 0) + return []; + + // Accumulate a score per entry id across all query tokens. An entry must + // match every query token (AND), and its score is the sum of the ranking + // weights of the index tokens it matched, so results stay relevant. + const scores = ({}); + const hitCounts = ({}); + for (const token of tokens) { + const matches = root._lookup(token); // { id: weight } + for (const id in matches) { + scores[id] = (scores[id] ?? 0) + matches[id]; + hitCounts[id] = (hitCounts[id] ?? 0) + 1; + } + } + + const ranked = Object.keys(scores).filter(id => hitCounts[id] === tokens.length).sort((a, b) => scores[b] - scores[a]).slice(0, 12); + + const all = entries.instances; + return ranked.map(id => all[parseInt(id)]).filter(e => e !== undefined); + } + + // Look up a query token in the inverted index: exact match first, then any + // indexed token that starts with it (prefix search, so "wif" finds "wifi"). + // Returns a map of entry id -> best ranking weight for that id. + function _lookup(token: string): var { + const result = ({}); + const exact = root.inverted[token] !== undefined; + const keys = exact ? [token] : Object.keys(root.inverted).filter(k => k.startsWith(token)); + for (const key of keys) { + const rank = root.ranking[key] ?? ({}); + for (const id of root.inverted[key]) { + const w = rank[id] ?? 0.1; + if (result[id] === undefined || w > result[id]) + result[id] = w; + } + } + return result; + } + + function _tokenize(text: string): var { + return text.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 0); + } Variants { id: entries @@ -34,9 +80,14 @@ Searcher { path: Quickshell.shellPath("assets/settings-index.json") onLoaded: { try { - entries.model = JSON.parse(text()).entries; + const data = JSON.parse(text()); + entries.model = data.entries; + root.inverted = data.inverted ?? {}; + root.ranking = data.ranking ?? {}; } catch (e) { entries.model = []; + root.inverted = {}; + root.ranking = {}; } } } diff --git a/scripts/__pycache__/build-settings-index.cpython-312.pyc b/scripts/__pycache__/build-settings-index.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b9ac67306b5415366e946be8a4481fc4c2554c3 GIT binary patch literal 11879 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 literal 0 HcmV?d00001 diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index bf8be5a4c..1db71afec 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -1,100 +1,125 @@ #!/usr/bin/env python3 """Build-time settings index extractor for the nexus settings search. -Parses the nexus page QML files and PageCompRegistry.qml to produce a flat -settings index as JSON. Run at build time (see CMakeLists.txt); the shell loads -the result at runtime via SettingsIndex.qml. +Parses the nexus page QML files, PageRegistry.qml (page icons/labels) and +PageCompRegistry.qml (page ordering and sub-page nesting) to produce a search +index as JSON. Run at build time (see CMakeLists.txt); the shell loads the +result at runtime via SettingsSearcher.qml. + +The output contains three parts: + - entries: forward index, one record per setting (title, anchor, nav path) + - inverted: token -> list of entry indices (classic inverted index) + - ranking: token -> {entry index: weight} precomputed match weights + +Nothing here is hand-maintained per page: page metadata comes from +PageRegistry, the page tree from PageCompRegistry, and the directory layout is +discovered by walking the pages folder. Usage: build-settings-index.py - nexus-dir path to modules/nexus - output-json where to write settings-index.json """ from __future__ import annotations import json import re import sys +from collections import defaultdict from pathlib import Path -# Rows that carry a searchable setting and the label property they expose. ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow)\s*\{') LABEL_RE = re.compile(r'^\s*(?:label|text):\s*qsTr\("([^"]+)"\)') ANCHOR_RE = re.compile(r'^\s*settingAnchor:\s*"([^"]+)"') ICON_RE = re.compile(r'^\s*icon:\s*"([^"]+)"') -# Labels that are too generic to index on their own. SKIP_LABELS = {"Muted", "None"} +# Field weights for ranking: a token matching the title counts more than one +# matching the keywords blob. +FIELD_WEIGHT = {"title": 1.0, "keywords": 0.4} +STOPWORDS = {"the", "a", "an", "of", "and", "or", "to", "on", "in", "for"} -# Page metadata: maps a page component name to its top-level pageComps index, -# icon, and human label. Pulled from PageRegistry; sub-pages add their own icon. -PAGE_META = { - "WallpaperAndStyle": ("palette", "Wallpaper & style"), - "NetworkPage": ("wifi", "Network"), - "BluetoothPage": ("devices_other", "Bluetooth"), - "AudioPage": ("volume_up", "Audio"), - "PanelsPage": ("dock_to_bottom", "Panels"), - "AppsPage": ("apps", "Apps"), - "ServicesPage": ("build", "Services"), - "LanguageAndRegion": ("globe", "Language & region"), -} - - -def parse_page_comps(path: Path) -> list[list[str]]: - """Return, per top-level pageComps entry, the ordered list of page - component names inside it (index 0 is the main page, rest are sub-pages).""" - text = path.read_text() - # Grab the pageComps array body. - start = text.index("pageComps:") - body = text[start:] - comps: list[list[str]] = [] + +def find_pages_dir(nexus: Path) -> Path: + return nexus / "pages" + + +def discover_files(nexus: Path) -> dict[str, Path]: + """component name -> file path, discovered by walking pages/.""" + files: dict[str, Path] = {} + for p in find_pages_dir(nexus).rglob("*.qml"): + files[p.stem] = p + return files + + +def parse_page_registry(nexus: Path) -> list[tuple[str, str]]: + """Ordered (icon, label) for each *active* page entry in PageRegistry. + Commented-out entries are ignored, matching pageComps ordering.""" + text = (nexus / "PageRegistry.qml").read_text() + out: list[tuple[str, str]] = [] + # Each entry is a { ... } block with label/icon; commented lines start //. + # Walk brace blocks at the array level. + in_array = False depth = 0 + label = icon = None + for line in text.splitlines(): + s = line.strip() + if "pages:" in s and "[" in s: + in_array = True + continue + if not in_array: + continue + if s.startswith("//"): + continue + if s.startswith("{"): + depth += 1 + label = icon = None + continue + if s.startswith("}"): + if label is not None: + out.append((icon or "tune", label)) + depth -= 1 + continue + if depth >= 1: + m = LABEL_RE.match(line) + if m and label is None: + label = m.group(1) + mi = ICON_RE.match(line) + if mi and icon is None: + icon = mi.group(1) + return out + + +def parse_page_comps(nexus: Path) -> list[list[str]]: + """Per top-level pageComps entry, ordered component names inside it.""" + text = (nexus / "PageCompRegistry.qml").read_text() + body = text[text.index("pageComps:"):] + comps: list[list[str]] = [] current: list[str] | None = None - # Walk lines tracking the top-level Component blocks (8-space indent). for line in body.splitlines(): if re.match(r"^ Component \{", line): current = [] comps.append(current) m = re.search(r"([A-Z][A-Za-z]+)\s*\{\}", line) if m and current is not None: - current.append(m.group(1)) + comps.append(current) if False else current.append(m.group(1)) return comps -def build_nav_map(nexus: Path) -> dict[str, dict]: - """Map each page component name -> {pageIdx, subPath, crumbIcons, - crumbLabels}. Sub-page paths are derived from openSubPage() calls in their - parent pages plus the pageComps ordering.""" - comps = parse_page_comps(nexus / "PageCompRegistry.qml") +def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: + comps = parse_page_comps(nexus) + registry = parse_page_registry(nexus) - # Component name -> (top index, position within its StackPage) - location: dict[str, tuple[int, int]] = {} - for top_idx, names in enumerate(comps): - for pos, name in enumerate(names): - location.setdefault(name, (top_idx, pos)) - - # For the main page of each top entry, find openSubPage(N) -> which child, - # and the NavRow icon/label that triggers it, to build breadcrumbs. - # Parent page file -> list of (childPos, icon, label) - def page_file(name: str) -> Path | None: - for sub in ("", "panels", "panels/taskbar", "services", "apps", - "bluetooth", "audio", "wallandstyle"): - p = nexus / "pages" / sub / f"{name}.qml" if sub else nexus / "pages" / f"{name}.qml" - if p.exists(): - return p - return None - - # Build child nav info: parentName -> {childPos: (icon, label)} - # Scan every page file (main and sub-pages) for openSubPage() calls so deep - # chains like Taskbar -> Workspaces are captured. + # Top-level index -> (icon, label) from PageRegistry (same order as pageComps). + top_meta: dict[int, tuple[str, str]] = {} + for i, (icon, label) in enumerate(registry): + top_meta[i] = (icon, label) + + # parentName -> {childPos: (icon, label)} from openSubPage() + nearby NavRow. nav_children: dict[str, dict[int, tuple[str, str]]] = {} for names in comps: for name in names: - pf = page_file(name) + pf = files.get(name) if not pf: continue - lines = pf.read_text().splitlines() - pending_icon = None - pending_label = None - for ln in lines: + pending_icon = pending_label = None + for ln in pf.read_text().splitlines(): mi = ICON_RE.match(ln) if mi: pending_icon = mi.group(1) @@ -108,55 +133,51 @@ def page_file(name: str) -> Path | None: pending_icon or "tune", pending_label or "") pending_icon = pending_label = None - # Now assemble nav map per component. nav: dict[str, dict] = {} for top_idx, names in enumerate(comps): if not names: continue main = names[0] - main_icon, main_label = PAGE_META.get(main, ("tune", main)) - # main page - nav[main] = { - "pageIdx": top_idx, "subPath": [], - "crumbIcons": [main_icon], "crumbLabels": [main_label], - } - # direct children reachable from main via openSubPage + main_icon, main_label = top_meta.get(top_idx, ("tune", main)) + nav[main] = {"pageIdx": top_idx, "subPath": [], + "crumbIcons": [main_icon], "crumbLabels": [main_label]} for pos, (icon, label) in nav_children.get(main, {}).items(): if pos >= len(names): continue child = names[pos] - nav[child] = { - "pageIdx": top_idx, "subPath": [pos], - "crumbIcons": [main_icon, icon], "crumbLabels": [main_label, label], - } - # grandchildren: children of this child (e.g. Taskbar -> Bar*) + nav[child] = {"pageIdx": top_idx, "subPath": [pos], + "crumbIcons": [main_icon, icon], + "crumbLabels": [main_label, label]} for gpos, (gicon, glabel) in nav_children.get(child, {}).items(): if gpos >= len(names): continue - gchild = names[gpos] - nav[gchild] = { + nav[names[gpos]] = { "pageIdx": top_idx, "subPath": [pos, gpos], "crumbIcons": [main_icon, icon, gicon], - "crumbLabels": [main_label, label, glabel], - } + "crumbLabels": [main_label, label, glabel]} return nav -def slug(s: str) -> str: - return re.sub(r"[^a-z0-9]+", "-", s.lower()).strip("-") +def tokenize(text: str) -> list[str]: + toks: list[str] = [] + # Process word by word (split on whitespace) so we only collapse separators + # inside a single word like "Wi-Fi" -> "wifi", not across a whole phrase. + for word in text.lower().split(): + parts = [p for p in re.split(r"[^a-z0-9]+", word) if p] + for p in parts: + if p not in STOPWORDS and p not in toks: + toks.append(p) + if len(parts) > 1: + joined = "".join(parts) + if joined not in toks: + toks.append(joined) + return toks -def extract_settings(nexus: Path, nav: dict[str, dict]) -> list[dict]: +def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict]: entries: list[dict] = [] for comp, meta in nav.items(): - # find the file for this component - pf = None - for sub in ("", "panels", "panels/taskbar", "services", "apps", - "bluetooth", "audio", "wallandstyle"): - p = (nexus / "pages" / sub / f"{comp}.qml") if sub else (nexus / "pages" / f"{comp}.qml") - if p.exists(): - pf = p - break + pf = files.get(comp) if not pf: continue lines = pf.read_text().splitlines() @@ -174,32 +195,58 @@ def extract_settings(nexus: Path, nav: dict[str, dict]) -> list[dict]: if a: anchor = a.group(1) if label and label not in SKIP_LABELS and anchor: - kw = set(label.lower().split()) - for cl in meta["crumbLabels"]: - kw |= set(cl.lower().replace("&", "").split()) + crumb_words = " ".join(meta["crumbLabels"]) + keywords = crumb_words entries.append({ - "pageIdx": meta["pageIdx"], - "subPath": meta["subPath"], + "pageIdx": meta["pageIdx"], "subPath": meta["subPath"], "crumbIcons": meta["crumbIcons"], "crumbLabels": meta["crumbLabels"], - "title": label, - "anchor": anchor, - "keywords": " ".join(sorted(w for w in kw if w)), + "title": label, "anchor": anchor, + "keywords": " ".join(sorted(set(tokenize(label + " " + keywords)))), }) i += 1 return entries +def build_inverted_and_ranking(entries: list[dict]): + """Classic inverted index + precomputed per-token ranking weights.""" + inverted: dict[str, list[int]] = defaultdict(list) + ranking: dict[str, dict[int, float]] = defaultdict(dict) + for idx, e in enumerate(entries): + fields = {"title": e["title"], "keywords": e["keywords"]} + seen: set[str] = set() + for field, text in fields.items(): + weight = FIELD_WEIGHT.get(field, 0.2) + for tok in tokenize(text): + if idx not in inverted[tok]: + inverted[tok].append(idx) + # accumulate the strongest field weight for this token/entry + ranking[tok][idx] = max(ranking[tok].get(idx, 0.0), weight) + seen.add(tok) + # sort each posting list by descending rank so runtime can stop early + for tok, ids in inverted.items(): + ids.sort(key=lambda i: ranking[tok][i], reverse=True) + return inverted, {t: {str(k): v for k, v in d.items()} for t, d in ranking.items()} + + def main() -> int: if len(sys.argv) != 3: print(__doc__) return 1 nexus = Path(sys.argv[1]) out = Path(sys.argv[2]) - nav = build_nav_map(nexus) - entries = extract_settings(nexus, nav) - out.write_text(json.dumps({"version": 1, "entries": entries}, ensure_ascii=False, indent=2)) - print(f"settings index: {len(entries)} entries -> {out}") + files = discover_files(nexus) + nav = build_nav_map(nexus, files) + entries = extract_settings(files, nav) + inverted, ranking = build_inverted_and_ranking(entries) + out.write_text(json.dumps({ + "version": 2, + "entries": entries, + "inverted": inverted, + "ranking": ranking, + }, ensure_ascii=False, indent=2)) + print(f"settings index: {len(entries)} entries, " + f"{len(inverted)} tokens -> {out}") return 0 From e02f734ec68b3f94005588bba47d94ba213e1374 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 12:46:51 +0000 Subject: [PATCH 13/57] feat(nexus): index setting descriptions and section headers too --- .gitignore | 2 +- assets/settings-index.json | 1416 +++++++++++++++-- .../build-settings-index.cpython-312.pyc | Bin 11879 -> 0 bytes scripts/build-settings-index.py | 26 +- 4 files changed, 1265 insertions(+), 179 deletions(-) delete mode 100644 scripts/__pycache__/build-settings-index.cpython-312.pyc diff --git a/.gitignore b/.gitignore index c30a6d926..a1c958d91 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ /.qmlls.ini build/ .cache/ -logs \ No newline at end of file +logs__pycache__/ diff --git a/assets/settings-index.json b/assets/settings-index.json index cf089c7e8..80d3a4eb0 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -25,7 +25,7 @@ ], "title": "Transparency", "anchor": "style-transparency", - "keywords": "style transparency wallpaper" + "keywords": "1 2 base layers style transparency wallpaper" }, { "pageIdx": 0, @@ -77,7 +77,7 @@ ], "title": "Discoverable", "anchor": "bluetooth-discoverable", - "keywords": "connected devices discoverable" + "keywords": "allow connected devices discoverable find nearby one this" }, { "pageIdx": 2, @@ -90,7 +90,7 @@ ], "title": "Pairable", "anchor": "bluetooth-pairable", - "keywords": "connected devices pairable" + "keywords": "allow connected devices nearby one pair pairable this with" }, { "pageIdx": 3, @@ -185,7 +185,7 @@ ], "title": "Enabled", "anchor": "dash-enabled", - "keywords": "dashboard enabled panels" + "keywords": "dashboard enabled general panels" }, { "pageIdx": 6, @@ -202,7 +202,7 @@ ], "title": "Show on hover", "anchor": "dash-show-on-hover", - "keywords": "dashboard hover panels show" + "keywords": "cursor dashboard edge general hover panels reaches reveal screen show when" }, { "pageIdx": 6, @@ -219,7 +219,7 @@ ], "title": "Dashboard", "anchor": "dash-dashboard", - "keywords": "dashboard panels" + "keywords": "dashboard panels tabs" }, { "pageIdx": 6, @@ -236,7 +236,7 @@ ], "title": "Media", "anchor": "dash-media", - "keywords": "dashboard media panels" + "keywords": "dashboard media panels tabs" }, { "pageIdx": 6, @@ -253,7 +253,7 @@ ], "title": "Performance", "anchor": "dash-performance", - "keywords": "dashboard panels performance" + "keywords": "dashboard panels performance tabs" }, { "pageIdx": 6, @@ -270,7 +270,7 @@ ], "title": "Weather", "anchor": "dash-weather", - "keywords": "dashboard panels weather" + "keywords": "dashboard panels tabs weather" }, { "pageIdx": 6, @@ -287,7 +287,7 @@ ], "title": "Battery", "anchor": "dash-battery", - "keywords": "battery dashboard panels" + "keywords": "battery dashboard panels performance widgets" }, { "pageIdx": 6, @@ -304,7 +304,7 @@ ], "title": "GPU", "anchor": "dash-gpu", - "keywords": "dashboard gpu panels" + "keywords": "dashboard gpu panels performance widgets" }, { "pageIdx": 6, @@ -321,7 +321,7 @@ ], "title": "CPU", "anchor": "dash-cpu", - "keywords": "cpu dashboard panels" + "keywords": "cpu dashboard panels performance widgets" }, { "pageIdx": 6, @@ -338,7 +338,7 @@ ], "title": "Memory", "anchor": "dash-memory", - "keywords": "dashboard memory panels" + "keywords": "dashboard memory panels performance widgets" }, { "pageIdx": 6, @@ -355,7 +355,7 @@ ], "title": "Storage", "anchor": "dash-storage", - "keywords": "dashboard panels storage" + "keywords": "dashboard panels performance storage widgets" }, { "pageIdx": 6, @@ -372,7 +372,7 @@ ], "title": "Network", "anchor": "dash-network", - "keywords": "dashboard network panels" + "keywords": "dashboard network panels performance widgets" }, { "pageIdx": 6, @@ -389,7 +389,7 @@ ], "title": "Drag threshold", "anchor": "dash-drag-threshold", - "keywords": "dashboard drag panels threshold" + "keywords": "before behaviour dashboard drag dragged opens panels pixels threshold" }, { "pageIdx": 6, @@ -406,7 +406,7 @@ ], "title": "Persistent", "anchor": "taskbar-persistent", - "keywords": "panels persistent taskbar" + "keywords": "all at bar behaviour keep panels persistent taskbar times visible" }, { "pageIdx": 6, @@ -423,7 +423,7 @@ ], "title": "Show on hover", "anchor": "taskbar-show-on-hover", - "keywords": "hover panels show taskbar" + "keywords": "bar behaviour cursor edge hover panels reaches reveal screen show taskbar when" }, { "pageIdx": 6, @@ -440,7 +440,7 @@ ], "title": "Drag threshold", "anchor": "taskbar-drag-threshold", - "keywords": "drag panels taskbar threshold" + "keywords": "bar before behaviour drag dragged panels pixels reveals taskbar threshold" }, { "pageIdx": 6, @@ -457,7 +457,7 @@ ], "title": "Workspaces", "anchor": "taskbar-workspaces", - "keywords": "panels taskbar workspaces" + "keywords": "components panels taskbar workspaces" }, { "pageIdx": 6, @@ -474,7 +474,7 @@ ], "title": "Active window", "anchor": "taskbar-active-window", - "keywords": "active panels taskbar window" + "keywords": "active components panels taskbar window" }, { "pageIdx": 6, @@ -491,7 +491,7 @@ ], "title": "Tray", "anchor": "taskbar-tray", - "keywords": "panels taskbar tray" + "keywords": "components panels taskbar tray" }, { "pageIdx": 6, @@ -508,7 +508,7 @@ ], "title": "Status icons", "anchor": "taskbar-status-icons", - "keywords": "icons panels status taskbar" + "keywords": "components icons panels status taskbar" }, { "pageIdx": 6, @@ -525,7 +525,7 @@ ], "title": "Clock", "anchor": "taskbar-clock", - "keywords": "clock panels taskbar" + "keywords": "clock components panels taskbar" }, { "pageIdx": 6, @@ -542,7 +542,7 @@ ], "title": "Workspaces", "anchor": "taskbar-workspaces-2", - "keywords": "panels taskbar workspaces" + "keywords": "actions indicator over panels scroll switch taskbar workspace workspaces" }, { "pageIdx": 6, @@ -559,7 +559,7 @@ ], "title": "Volume", "anchor": "taskbar-volume", - "keywords": "panels taskbar volume" + "keywords": "actions adjust bar half panels scroll taskbar top volume" }, { "pageIdx": 6, @@ -576,7 +576,7 @@ ], "title": "Brightness", "anchor": "taskbar-brightness", - "keywords": "brightness panels taskbar" + "keywords": "actions adjust bar bottom brightness half panels scroll taskbar" }, { "pageIdx": 6, @@ -596,7 +596,7 @@ ], "title": "Shown", "anchor": "bar-ws-shown", - "keywords": "panels shown taskbar workspaces" + "keywords": "displayed number panels shown taskbar workspaces" }, { "pageIdx": 6, @@ -656,7 +656,7 @@ ], "title": "Occupied background", "anchor": "bar-ws-occupied-background", - "keywords": "background occupied panels taskbar workspaces" + "keywords": "background each icons occupied open panels show taskbar windows workspace workspaces" }, { "pageIdx": 6, @@ -676,7 +676,7 @@ ], "title": "Show windows", "anchor": "bar-ws-show-windows", - "keywords": "panels show taskbar windows workspaces" + "keywords": "each icons open panels show taskbar windows workspace workspaces" }, { "pageIdx": 6, @@ -736,7 +736,7 @@ ], "title": "Per-monitor workspaces", "anchor": "bar-ws-per-monitor-workspaces", - "keywords": "monitor panels per permonitor taskbar workspaces" + "keywords": "each independently monitor monitors panels per permonitor s show taskbar workspaces" }, { "pageIdx": 6, @@ -776,7 +776,7 @@ ], "title": "Inverted", "anchor": "bar-aw-inverted", - "keywords": "active inverted panels taskbar window" + "keywords": "active hovering inverted only panels show taskbar title while window" }, { "pageIdx": 6, @@ -796,7 +796,7 @@ ], "title": "Show on hover", "anchor": "bar-aw-show-on-hover", - "keywords": "active hover panels show taskbar window" + "keywords": "active hover hovering only panels show taskbar title while window" }, { "pageIdx": 6, @@ -816,7 +816,7 @@ ], "title": "Popout on hover", "anchor": "bar-aw-popout-on-hover", - "keywords": "active hover panels popout taskbar window" + "keywords": "active details hover hovering panels popout show taskbar when window" }, { "pageIdx": 6, @@ -876,7 +876,7 @@ ], "title": "Compact", "anchor": "bar-tray-compact", - "keywords": "compact panels taskbar tray" + "keywords": "compact hovering menu panels popout show taskbar tray when" }, { "pageIdx": 6, @@ -896,7 +896,7 @@ ], "title": "Popout on hover", "anchor": "bar-tray-popout-on-hover", - "keywords": "hover panels popout taskbar tray" + "keywords": "hover hovering menu panels popout show taskbar tray when" }, { "pageIdx": 6, @@ -916,7 +916,7 @@ ], "title": "Speakers", "anchor": "bar-si-speakers", - "keywords": "icons panels speakers status taskbar" + "keywords": "icons panels speakers status taskbar visible" }, { "pageIdx": 6, @@ -936,7 +936,7 @@ ], "title": "Microphone", "anchor": "bar-si-microphone", - "keywords": "icons microphone panels status taskbar" + "keywords": "icons microphone panels status taskbar visible" }, { "pageIdx": 6, @@ -956,7 +956,7 @@ ], "title": "Keyboard layout", "anchor": "bar-si-keyboard-layout", - "keywords": "icons keyboard layout panels status taskbar" + "keywords": "icons keyboard layout panels status taskbar visible" }, { "pageIdx": 6, @@ -976,7 +976,7 @@ ], "title": "Network", "anchor": "bar-si-network", - "keywords": "icons network panels status taskbar" + "keywords": "icons network panels status taskbar visible" }, { "pageIdx": 6, @@ -996,7 +996,7 @@ ], "title": "Wi-Fi", "anchor": "bar-si-wi-fi", - "keywords": "fi icons panels status taskbar wi wifi" + "keywords": "fi icons panels status taskbar visible wi wifi" }, { "pageIdx": 6, @@ -1016,7 +1016,7 @@ ], "title": "Bluetooth", "anchor": "bar-si-bluetooth", - "keywords": "bluetooth icons panels status taskbar" + "keywords": "bluetooth icons panels status taskbar visible" }, { "pageIdx": 6, @@ -1036,7 +1036,7 @@ ], "title": "Battery", "anchor": "bar-si-battery", - "keywords": "battery icons panels status taskbar" + "keywords": "battery icons panels status taskbar visible" }, { "pageIdx": 6, @@ -1056,7 +1056,7 @@ ], "title": "Caps lock", "anchor": "bar-si-caps-lock", - "keywords": "caps icons lock panels status taskbar" + "keywords": "caps icons lock panels status taskbar visible" }, { "pageIdx": 6, @@ -1076,7 +1076,7 @@ ], "title": "Popout on hover", "anchor": "bar-si-popout-on-hover", - "keywords": "hover icons panels popout status taskbar" + "keywords": "behaviour details hover hovering icons panels popout show status taskbar when" }, { "pageIdx": 6, @@ -1153,7 +1153,7 @@ ], "title": "Enabled", "anchor": "launcher-enabled", - "keywords": "enabled launcher panels" + "keywords": "enabled general launcher panels" }, { "pageIdx": 6, @@ -1170,7 +1170,7 @@ ], "title": "Show on hover", "anchor": "launcher-show-on-hover", - "keywords": "hover launcher panels show" + "keywords": "cursor edge general hover launcher panels reaches reveal screen show when" }, { "pageIdx": 6, @@ -1187,7 +1187,7 @@ ], "title": "Max items shown", "anchor": "launcher-max-items-shown", - "keywords": "items launcher max panels shown" + "keywords": "display items launcher max panels shown" }, { "pageIdx": 6, @@ -1204,7 +1204,7 @@ ], "title": "Max wallpapers", "anchor": "launcher-max-wallpapers", - "keywords": "launcher max panels wallpapers" + "keywords": "display launcher max panels wallpapers" }, { "pageIdx": 6, @@ -1221,7 +1221,7 @@ ], "title": "Drag threshold", "anchor": "launcher-drag-threshold", - "keywords": "drag launcher panels threshold" + "keywords": "before display drag dragged launcher opens panels pixels threshold" }, { "pageIdx": 6, @@ -1238,7 +1238,7 @@ ], "title": "Vim keybinds", "anchor": "launcher-vim-keybinds", - "keywords": "keybinds launcher panels vim" + "keywords": "behaviour ctrl ctrlhjkl hjkl keybinds launcher navigate panels results vim with" }, { "pageIdx": 6, @@ -1255,7 +1255,7 @@ ], "title": "Enable dangerous actions", "anchor": "launcher-enable-dangerous-actions", - "keywords": "actions dangerous enable launcher panels" + "keywords": "actions allow behaviour dangerous down enable launcher log out panels shut that" }, { "pageIdx": 6, @@ -1272,7 +1272,7 @@ ], "title": "Apps", "anchor": "launcher-apps", - "keywords": "apps launcher panels" + "keywords": "apps fuzzy launcher panels search" }, { "pageIdx": 6, @@ -1289,7 +1289,7 @@ ], "title": "Actions", "anchor": "launcher-actions", - "keywords": "actions launcher panels" + "keywords": "actions fuzzy launcher panels search" }, { "pageIdx": 6, @@ -1306,7 +1306,7 @@ ], "title": "Schemes", "anchor": "launcher-schemes", - "keywords": "launcher panels schemes" + "keywords": "fuzzy launcher panels schemes search" }, { "pageIdx": 6, @@ -1323,7 +1323,7 @@ ], "title": "Variants", "anchor": "launcher-variants", - "keywords": "launcher panels variants" + "keywords": "fuzzy launcher panels search variants" }, { "pageIdx": 6, @@ -1340,7 +1340,7 @@ ], "title": "Wallpapers", "anchor": "launcher-wallpapers", - "keywords": "launcher panels wallpapers" + "keywords": "fuzzy launcher panels search wallpapers" }, { "pageIdx": 6, @@ -1357,7 +1357,7 @@ ], "title": "Enabled", "anchor": "sidebar-enabled", - "keywords": "enabled panels sidebar" + "keywords": "enabled general panels sidebar" }, { "pageIdx": 6, @@ -1374,7 +1374,7 @@ ], "title": "Drag threshold", "anchor": "sidebar-drag-threshold", - "keywords": "drag panels sidebar threshold" + "keywords": "before drag dragged general opens panels pixels sidebar threshold" }, { "pageIdx": 7, @@ -1387,7 +1387,7 @@ ], "title": "All apps", "anchor": "apps-all-apps", - "keywords": "all apps" + "keywords": "all apps library" }, { "pageIdx": 8, @@ -1413,7 +1413,7 @@ ], "title": "Media refresh", "anchor": "services-media-refresh", - "keywords": "media refresh services" + "keywords": "how media ms often polling position refresh services updates" }, { "pageIdx": 8, @@ -1426,7 +1426,7 @@ ], "title": "System stats refresh", "anchor": "services-system-stats-refresh", - "keywords": "refresh services stats system" + "keywords": "cpu gpu interval memory polling refresh seconds services stats system update" }, { "pageIdx": 8, @@ -1439,7 +1439,7 @@ ], "title": "Wi-Fi rescan", "anchor": "services-wi-fi-rescan", - "keywords": "fi rescan services wi wifi" + "keywords": "are available fi how networks often polling rescan rescanned seconds services wi wifi" }, { "pageIdx": 8, @@ -1452,7 +1452,7 @@ ], "title": "Lyrics backend", "anchor": "services-lyrics-backend", - "keywords": "backend lyrics services" + "keywords": "backend fetch lyrics media services source synced used" }, { "pageIdx": 8, @@ -1465,7 +1465,7 @@ ], "title": "Default player", "anchor": "services-default-player", - "keywords": "default player services" + "keywords": "are default lyrics media open player preferred services several when" }, { "pageIdx": 8, @@ -1478,7 +1478,7 @@ ], "title": "Volume step", "anchor": "services-volume-step", - "keywords": "services step volume" + "keywords": "amount changes increments input per scroll services step volume" }, { "pageIdx": 8, @@ -1491,7 +1491,7 @@ ], "title": "Brightness step", "anchor": "services-brightness-step", - "keywords": "brightness services step" + "keywords": "amount brightness changes increments input per scroll services step" }, { "pageIdx": 8, @@ -1504,7 +1504,7 @@ ], "title": "Max volume", "anchor": "services-max-volume", - "keywords": "max services volume" + "keywords": "increments input limit max output services upper volume" }, { "pageIdx": 8, @@ -1517,7 +1517,7 @@ ], "title": "Visualiser bars", "anchor": "services-visualiser-bars", - "keywords": "bars services visualiser" + "keywords": "audio bars number service services tuning visualiser visualisers" }, { "pageIdx": 8, @@ -1530,7 +1530,7 @@ ], "title": "Smart colour scheme", "anchor": "services-smart-colour-scheme", - "keywords": "colour scheme services smart" + "keywords": "colour derive from mode scheme service services smart theme tuning variant wallpaper" }, { "pageIdx": 8, @@ -1543,7 +1543,7 @@ ], "title": "GPU", "anchor": "services-gpu", - "keywords": "gpu services" + "keywords": "gpu service services tuning" }, { "pageIdx": 8, @@ -1560,7 +1560,7 @@ ], "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen", - "keywords": "fullscreen notifications services show" + "keywords": "appear apps fullscreen notifications over services show whether" }, { "pageIdx": 8, @@ -1577,7 +1577,7 @@ ], "title": "Expire automatically", "anchor": "notif-expire-automatically", - "keywords": "automatically expire notifications services" + "keywords": "after automatically dismiss expire notifications services their timeout" }, { "pageIdx": 8, @@ -1594,7 +1594,7 @@ ], "title": "Open expanded", "anchor": "notif-open-expanded", - "keywords": "expanded notifications open services" + "keywords": "by default expanded notifications open services show" }, { "pageIdx": 8, @@ -1611,7 +1611,7 @@ ], "title": "Default timeout", "anchor": "notif-default-timeout", - "keywords": "default notifications services timeout" + "keywords": "before default dismisses ms notification notifications services time timeout" }, { "pageIdx": 8, @@ -1628,7 +1628,7 @@ ], "title": "Group preview count", "anchor": "notif-group-preview-count", - "keywords": "count group notifications preview services" + "keywords": "before collapsing count group notifications per preview services shown" }, { "pageIdx": 8, @@ -1645,7 +1645,7 @@ ], "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen-2", - "keywords": "fullscreen notifications services show" + "keywords": "appear apps fullscreen notifications over services show toasts whether" }, { "pageIdx": 8, @@ -1662,7 +1662,7 @@ ], "title": "Visible toasts", "anchor": "notif-visible-toasts", - "keywords": "notifications services toasts visible" + "keywords": "at maximum notifications number once services shown toasts visible" }, { "pageIdx": 8, @@ -1679,7 +1679,7 @@ ], "title": "Charging changes", "anchor": "notif-charging-changes", - "keywords": "changes charging notifications services" + "keywords": "changes charging events notifications services toast" }, { "pageIdx": 8, @@ -1696,7 +1696,7 @@ ], "title": "Game mode changes", "anchor": "notif-game-mode-changes", - "keywords": "changes game mode notifications services" + "keywords": "changes events game mode notifications services toast" }, { "pageIdx": 8, @@ -1713,7 +1713,7 @@ ], "title": "Do not disturb changes", "anchor": "notif-do-not-disturb-changes", - "keywords": "changes disturb do not notifications services" + "keywords": "changes disturb do events not notifications services toast" }, { "pageIdx": 8, @@ -1730,7 +1730,7 @@ ], "title": "Audio output changes", "anchor": "notif-audio-output-changes", - "keywords": "audio changes notifications output services" + "keywords": "audio changes events notifications output services toast" }, { "pageIdx": 8, @@ -1747,7 +1747,7 @@ ], "title": "Audio input changes", "anchor": "notif-audio-input-changes", - "keywords": "audio changes input notifications services" + "keywords": "audio changes events input notifications services toast" }, { "pageIdx": 8, @@ -1764,7 +1764,7 @@ ], "title": "Caps lock changes", "anchor": "notif-caps-lock-changes", - "keywords": "caps changes lock notifications services" + "keywords": "caps changes events lock notifications services toast" }, { "pageIdx": 8, @@ -1781,7 +1781,7 @@ ], "title": "Num lock changes", "anchor": "notif-num-lock-changes", - "keywords": "changes lock notifications num services" + "keywords": "changes events lock notifications num services toast" }, { "pageIdx": 8, @@ -1798,7 +1798,7 @@ ], "title": "Keyboard layout changes", "anchor": "notif-keyboard-layout-changes", - "keywords": "changes keyboard layout notifications services" + "keywords": "changes events keyboard layout notifications services toast" }, { "pageIdx": 8, @@ -1815,7 +1815,7 @@ ], "title": "VPN changes", "anchor": "notif-vpn-changes", - "keywords": "changes notifications services vpn" + "keywords": "changes events notifications services toast vpn" }, { "pageIdx": 8, @@ -1832,7 +1832,7 @@ ], "title": "Now playing", "anchor": "notif-now-playing", - "keywords": "notifications now playing services" + "keywords": "events notifications now playing services toast" }, { "pageIdx": 9, @@ -1845,7 +1845,7 @@ ], "title": "Temperature", "anchor": "lang-temperature", - "keywords": "language region temperature" + "keywords": "language region temperature temperatures units weather" }, { "pageIdx": 9, @@ -1858,7 +1858,7 @@ ], "title": "System temperatures", "anchor": "lang-system-temperatures", - "keywords": "language region system temperatures" + "keywords": "cpu gpu language region system temperatures units" }, { "pageIdx": 9, @@ -1871,17 +1871,21 @@ ], "title": "Clock format", "anchor": "lang-clock-format", - "keywords": "clock format language region" + "keywords": "across are clock date format how language region shell shown time times" } ], "inverted": { "display": [ - 0 + 0, + 67, + 68, + 69 ], "wallpaper": [ 0, 1, - 2 + 2, + 90 ], "style": [ 0, @@ -1891,11 +1895,24 @@ "transparency": [ 1 ], + "1": [ + 1 + ], + "2": [ + 1 + ], + "base": [ + 1 + ], + "layers": [ + 1 + ], "dark": [ 2 ], "theme": [ - 2 + 2, + 90 ], "wi": [ 3, @@ -1934,22 +1951,54 @@ "discoverable": [ 5 ], + "allow": [ + 5, + 6, + 71 + ], + "find": [ + 5 + ], + "nearby": [ + 5, + 6 + ], + "one": [ + 5, + 6 + ], + "this": [ + 5, + 6 + ], "pairable": [ 6 ], + "pair": [ + 6 + ], + "with": [ + 6, + 70 + ], "output": [ 7, - 102 + 102, + 88 ], "audio": [ 102, 103, 7, - 8 + 8, + 89 ], "input": [ 8, - 103 + 103, + 86, + 87, + 88 ], "dashboard": [ 9, @@ -2106,6 +2155,14 @@ 65, 77 ], + "general": [ + 13, + 14, + 65, + 66, + 77, + 78 + ], "show": [ 14, 27, @@ -2115,7 +2172,15 @@ 64, 66, 92, - 97 + 97, + 40, + 44, + 46, + 48, + 51, + 52, + 61, + 94 ], "hover": [ 14, @@ -2126,29 +2191,92 @@ 61, 66 ], + "cursor": [ + 14, + 27, + 66 + ], + "edge": [ + 14, + 27, + 66 + ], + "reaches": [ + 14, + 27, + 66 + ], + "reveal": [ + 14, + 27, + 66 + ], + "screen": [ + 14, + 27, + 66 + ], + "when": [ + 14, + 27, + 48, + 51, + 52, + 61, + 66, + 85 + ], + "tabs": [ + 15, + 16, + 17, + 18 + ], "media": [ 16, - 81 + 81, + 84, + 85 ], "performance": [ - 17 + 17, + 19, + 20, + 21, + 22, + 23, + 24 ], "weather": [ - 18 + 18, + 109 ], "battery": [ 19, 59 ], + "widgets": [ + 19, + 20, + 21, + 22, + 23, + 24 + ], "gpu": [ 20, - 91 + 91, + 82, + 110 ], "cpu": [ - 21 + 21, + 82, + 110 ], "memory": [ - 22 + 22, + 82 ], "storage": [ 23 @@ -2165,9 +2293,80 @@ 69, 78 ], + "before": [ + 25, + 28, + 69, + 78, + 95, + 96 + ], + "behaviour": [ + 25, + 26, + 27, + 28, + 61, + 70, + 71 + ], + "dragged": [ + 25, + 28, + 69, + 78 + ], + "opens": [ + 25, + 69, + 78 + ], + "pixels": [ + 25, + 28, + 69, + 78 + ], "persistent": [ 26 ], + "all": [ + 79, + 26 + ], + "at": [ + 26, + 98 + ], + "bar": [ + 26, + 27, + 28, + 35, + 36 + ], + "keep": [ + 26 + ], + "times": [ + 26, + 111 + ], + "visible": [ + 98, + 26, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60 + ], + "reveals": [ + 28 + ], "workspaces": [ 29, 34, @@ -2180,6 +2379,13 @@ 41, 43 ], + "components": [ + 29, + 30, + 31, + 32, + 33 + ], "active": [ 30, 38, @@ -2220,6 +2426,8 @@ 32, 43, 50, + 40, + 41, 53, 54, 55, @@ -2237,21 +2445,74 @@ 63, 64 ], + "actions": [ + 71, + 73, + 34, + 35, + 36 + ], + "indicator": [ + 38, + 34 + ], + "over": [ + 34, + 92, + 97 + ], + "scroll": [ + 34, + 35, + 36, + 86, + 87 + ], + "switch": [ + 34 + ], + "workspace": [ + 34, + 40, + 41 + ], "volume": [ 35, 86, 88 ], + "adjust": [ + 35, + 36 + ], + "half": [ + 35, + 36 + ], + "top": [ + 35 + ], "brightness": [ 36, 87 ], + "bottom": [ + 36 + ], "shown": [ 37, - 67 + 67, + 96, + 98, + 111 ], - "indicator": [ - 38 + "displayed": [ + 37 + ], + "number": [ + 37, + 89, + 98 ], "trail": [ 39 @@ -2264,9 +2525,21 @@ 49, 62 ], + "each": [ + 40, + 41, + 44 + ], + "open": [ + 94, + 40, + 41, + 85 + ], "windows": [ 41, - 42 + 42, + 40 ], "special": [ 42 @@ -2278,7 +2551,10 @@ 88 ], "per": [ - 44 + 44, + 86, + 87, + 96 ], "monitor": [ 44 @@ -2286,6 +2562,15 @@ "permonitor": [ 44 ], + "independently": [ + 44 + ], + "monitors": [ + 44 + ], + "s": [ + 44 + ], "compact": [ 45, 51 @@ -2293,16 +2578,45 @@ "inverted": [ 46 ], - "popout": [ + "hovering": [ + 46, + 47, 48, + 51, 52, 61 ], - "recolour": [ - 50 + "only": [ + 46, + 47 ], - "speakers": [ - 53 + "title": [ + 46, + 47 + ], + "while": [ + 46, + 47 + ], + "popout": [ + 48, + 52, + 61, + 51 + ], + "details": [ + 48, + 61 + ], + "recolour": [ + 50 + ], + "menu": [ + 51, + 52 + ], + "speakers": [ + 53 ], "microphone": [ 54 @@ -2325,7 +2639,8 @@ 105 ], "date": [ - 63 + 63, + 111 ], "icon": [ 64 @@ -2343,19 +2658,61 @@ "keybinds": [ 70 ], + "ctrl": [ + 70 + ], + "ctrlhjkl": [ + 70 + ], + "hjkl": [ + 70 + ], + "navigate": [ + 70 + ], + "results": [ + 70 + ], "enable": [ 71 ], "dangerous": [ 71 ], - "actions": [ - 71, - 73 + "down": [ + 71 + ], + "log": [ + 71 + ], + "out": [ + 71 + ], + "shut": [ + 71 + ], + "that": [ + 71 ], "apps": [ 72, - 79 + 79, + 92, + 97 + ], + "fuzzy": [ + 72, + 73, + 74, + 75, + 76 + ], + "search": [ + 72, + 73, + 74, + 75, + 76 ], "schemes": [ 74 @@ -2363,7 +2720,7 @@ "variants": [ 75 ], - "all": [ + "library": [ 79 ], "notifications": [ @@ -2421,6 +2778,30 @@ 81, 82 ], + "how": [ + 81, + 83, + 111 + ], + "ms": [ + 81, + 95 + ], + "often": [ + 81, + 83 + ], + "polling": [ + 81, + 82, + 83 + ], + "position": [ + 81 + ], + "updates": [ + 81 + ], "system": [ 82, 110 @@ -2428,32 +2809,117 @@ "stats": [ 82 ], + "interval": [ + 82 + ], + "seconds": [ + 82, + 83 + ], + "update": [ + 82 + ], "rescan": [ 83 ], + "are": [ + 83, + 85, + 111 + ], + "available": [ + 83 + ], + "networks": [ + 83 + ], + "rescanned": [ + 83 + ], "lyrics": [ - 84 + 84, + 85 ], "backend": [ 84 ], + "fetch": [ + 84 + ], + "source": [ + 84 + ], + "synced": [ + 84 + ], + "used": [ + 84 + ], "default": [ 85, - 95 + 95, + 94 ], "player": [ 85 ], + "preferred": [ + 85 + ], + "several": [ + 85 + ], "step": [ 86, 87 ], + "amount": [ + 86, + 87 + ], + "changes": [ + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 86, + 87 + ], + "increments": [ + 86, + 87, + 88 + ], + "limit": [ + 88 + ], + "upper": [ + 88 + ], "visualiser": [ 89 ], "bars": [ 89 ], + "service": [ + 89, + 90, + 91 + ], + "tuning": [ + 89, + 90, + 91 + ], + "visualisers": [ + 89 + ], "smart": [ 90 ], @@ -2463,25 +2929,66 @@ "scheme": [ 90 ], + "derive": [ + 90 + ], + "from": [ + 90 + ], + "mode": [ + 100, + 90 + ], + "variant": [ + 90 + ], "fullscreen": [ 92, 97 ], + "appear": [ + 92, + 97 + ], + "whether": [ + 92, + 97 + ], "expire": [ 93 ], "automatically": [ 93 ], - "open": [ - 94 + "after": [ + 93 + ], + "dismiss": [ + 93 + ], + "their": [ + 93 + ], + "timeout": [ + 95, + 93 ], "expanded": [ 94 ], - "timeout": [ + "by": [ + 94 + ], + "dismisses": [ + 95 + ], + "notification": [ 95 ], + "time": [ + 95, + 111 + ], "group": [ 96 ], @@ -2491,16 +2998,23 @@ "count": [ 96 ], - "visible": [ - 98 + "collapsing": [ + 96 ], "toasts": [ + 98, + 97 + ], + "maximum": [ + 98 + ], + "once": [ 98 ], "charging": [ 99 ], - "changes": [ + "events": [ 99, 100, 101, @@ -2509,12 +3023,22 @@ 104, 105, 106, - 107 + 107, + 108 ], - "game": [ - 100 + "toast": [ + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108 ], - "mode": [ + "game": [ 100 ], "do": [ @@ -2552,20 +3076,35 @@ 111 ], "temperatures": [ + 110, + 109 + ], + "units": [ + 109, 110 ], "format": [ 111 + ], + "across": [ + 111 + ], + "shell": [ + 111 ] }, "ranking": { "display": { - "0": 1.0 + "0": 1.0, + "67": 0.4, + "68": 0.4, + "69": 0.4 }, "wallpaper": { "0": 1.0, "1": 0.4, - "2": 0.4 + "2": 0.4, + "90": 0.4 }, "style": { "0": 0.4, @@ -2575,11 +3114,24 @@ "transparency": { "1": 1.0 }, + "1": { + "1": 0.4 + }, + "2": { + "1": 0.4 + }, + "base": { + "1": 0.4 + }, + "layers": { + "1": 0.4 + }, "dark": { "2": 1.0 }, "theme": { - "2": 1.0 + "2": 1.0, + "90": 0.4 }, "wi": { "3": 1.0, @@ -2618,21 +3170,53 @@ "discoverable": { "5": 1.0 }, + "allow": { + "5": 0.4, + "6": 0.4, + "71": 0.4 + }, + "find": { + "5": 0.4 + }, + "nearby": { + "5": 0.4, + "6": 0.4 + }, + "one": { + "5": 0.4, + "6": 0.4 + }, + "this": { + "5": 0.4, + "6": 0.4 + }, "pairable": { "6": 1.0 }, + "pair": { + "6": 0.4 + }, + "with": { + "6": 0.4, + "70": 0.4 + }, "output": { "7": 1.0, + "88": 0.4, "102": 1.0 }, "audio": { "7": 0.4, "8": 0.4, + "89": 0.4, "102": 1.0, "103": 1.0 }, "input": { "8": 1.0, + "86": 0.4, + "87": 0.4, + "88": 0.4, "103": 1.0 }, "dashboard": { @@ -2790,15 +3374,31 @@ "65": 1.0, "77": 1.0 }, + "general": { + "13": 0.4, + "14": 0.4, + "65": 0.4, + "66": 0.4, + "77": 0.4, + "78": 0.4 + }, "show": { "14": 1.0, "27": 1.0, + "40": 0.4, "41": 1.0, + "44": 0.4, + "46": 0.4, "47": 1.0, - "63": 1.0, + "48": 0.4, + "51": 0.4, + "52": 0.4, + "61": 0.4, + "63": 1.0, "64": 1.0, "66": 1.0, "92": 1.0, + "94": 0.4, "97": 1.0 }, "hover": { @@ -2810,29 +3410,92 @@ "61": 1.0, "66": 1.0 }, + "cursor": { + "14": 0.4, + "27": 0.4, + "66": 0.4 + }, + "edge": { + "14": 0.4, + "27": 0.4, + "66": 0.4 + }, + "reaches": { + "14": 0.4, + "27": 0.4, + "66": 0.4 + }, + "reveal": { + "14": 0.4, + "27": 0.4, + "66": 0.4 + }, + "screen": { + "14": 0.4, + "27": 0.4, + "66": 0.4 + }, + "when": { + "14": 0.4, + "27": 0.4, + "48": 0.4, + "51": 0.4, + "52": 0.4, + "61": 0.4, + "66": 0.4, + "85": 0.4 + }, + "tabs": { + "15": 0.4, + "16": 0.4, + "17": 0.4, + "18": 0.4 + }, "media": { "16": 1.0, - "81": 1.0 + "81": 1.0, + "84": 0.4, + "85": 0.4 }, "performance": { - "17": 1.0 + "17": 1.0, + "19": 0.4, + "20": 0.4, + "21": 0.4, + "22": 0.4, + "23": 0.4, + "24": 0.4 }, "weather": { - "18": 1.0 + "18": 1.0, + "109": 0.4 }, "battery": { "19": 1.0, "59": 1.0 }, + "widgets": { + "19": 0.4, + "20": 0.4, + "21": 0.4, + "22": 0.4, + "23": 0.4, + "24": 0.4 + }, "gpu": { "20": 1.0, - "91": 1.0 + "82": 0.4, + "91": 1.0, + "110": 0.4 }, "cpu": { - "21": 1.0 + "21": 1.0, + "82": 0.4, + "110": 0.4 }, "memory": { - "22": 1.0 + "22": 1.0, + "82": 0.4 }, "storage": { "23": 1.0 @@ -2849,9 +3512,80 @@ "69": 1.0, "78": 1.0 }, + "before": { + "25": 0.4, + "28": 0.4, + "69": 0.4, + "78": 0.4, + "95": 0.4, + "96": 0.4 + }, + "behaviour": { + "25": 0.4, + "26": 0.4, + "27": 0.4, + "28": 0.4, + "61": 0.4, + "70": 0.4, + "71": 0.4 + }, + "dragged": { + "25": 0.4, + "28": 0.4, + "69": 0.4, + "78": 0.4 + }, + "opens": { + "25": 0.4, + "69": 0.4, + "78": 0.4 + }, + "pixels": { + "25": 0.4, + "28": 0.4, + "69": 0.4, + "78": 0.4 + }, "persistent": { "26": 1.0 }, + "all": { + "26": 0.4, + "79": 1.0 + }, + "at": { + "26": 0.4, + "98": 0.4 + }, + "bar": { + "26": 0.4, + "27": 0.4, + "28": 0.4, + "35": 0.4, + "36": 0.4 + }, + "keep": { + "26": 0.4 + }, + "times": { + "26": 0.4, + "111": 0.4 + }, + "visible": { + "26": 0.4, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "98": 1.0 + }, + "reveals": { + "28": 0.4 + }, "workspaces": { "29": 1.0, "34": 1.0, @@ -2864,6 +3598,13 @@ "43": 0.4, "44": 1.0 }, + "components": { + "29": 0.4, + "30": 0.4, + "31": 0.4, + "32": 0.4, + "33": 0.4 + }, "active": { "30": 1.0, "38": 1.0, @@ -2902,6 +3643,8 @@ }, "icons": { "32": 1.0, + "40": 0.4, + "41": 0.4, "43": 1.0, "50": 1.0, "53": 0.4, @@ -2921,21 +3664,74 @@ "64": 0.4, "111": 1.0 }, + "actions": { + "34": 0.4, + "35": 0.4, + "36": 0.4, + "71": 1.0, + "73": 1.0 + }, + "indicator": { + "34": 0.4, + "38": 1.0 + }, + "over": { + "34": 0.4, + "92": 0.4, + "97": 0.4 + }, + "scroll": { + "34": 0.4, + "35": 0.4, + "36": 0.4, + "86": 0.4, + "87": 0.4 + }, + "switch": { + "34": 0.4 + }, + "workspace": { + "34": 0.4, + "40": 0.4, + "41": 0.4 + }, "volume": { "35": 1.0, "86": 1.0, "88": 1.0 }, + "adjust": { + "35": 0.4, + "36": 0.4 + }, + "half": { + "35": 0.4, + "36": 0.4 + }, + "top": { + "35": 0.4 + }, "brightness": { "36": 1.0, "87": 1.0 }, + "bottom": { + "36": 0.4 + }, "shown": { "37": 1.0, - "67": 1.0 + "67": 1.0, + "96": 0.4, + "98": 0.4, + "111": 0.4 }, - "indicator": { - "38": 1.0 + "displayed": { + "37": 0.4 + }, + "number": { + "37": 0.4, + "89": 0.4, + "98": 0.4 }, "trail": { "39": 1.0 @@ -2948,7 +3744,19 @@ "49": 1.0, "62": 1.0 }, + "each": { + "40": 0.4, + "41": 0.4, + "44": 0.4 + }, + "open": { + "40": 0.4, + "41": 0.4, + "85": 0.4, + "94": 1.0 + }, "windows": { + "40": 0.4, "41": 1.0, "42": 1.0 }, @@ -2962,7 +3770,10 @@ "88": 1.0 }, "per": { - "44": 1.0 + "44": 1.0, + "86": 0.4, + "87": 0.4, + "96": 0.4 }, "monitor": { "44": 1.0 @@ -2970,6 +3781,15 @@ "permonitor": { "44": 1.0 }, + "independently": { + "44": 0.4 + }, + "monitors": { + "44": 0.4 + }, + "s": { + "44": 0.4 + }, "compact": { "45": 1.0, "51": 1.0 @@ -2977,14 +3797,43 @@ "inverted": { "46": 1.0 }, + "hovering": { + "46": 0.4, + "47": 0.4, + "48": 0.4, + "51": 0.4, + "52": 0.4, + "61": 0.4 + }, + "only": { + "46": 0.4, + "47": 0.4 + }, + "title": { + "46": 0.4, + "47": 0.4 + }, + "while": { + "46": 0.4, + "47": 0.4 + }, "popout": { "48": 1.0, + "51": 0.4, "52": 1.0, "61": 1.0 }, + "details": { + "48": 0.4, + "61": 0.4 + }, "recolour": { "50": 1.0 }, + "menu": { + "51": 0.4, + "52": 0.4 + }, "speakers": { "53": 1.0 }, @@ -3009,7 +3858,8 @@ "105": 1.0 }, "date": { - "63": 1.0 + "63": 1.0, + "111": 0.4 }, "icon": { "64": 1.0 @@ -3027,19 +3877,61 @@ "keybinds": { "70": 1.0 }, + "ctrl": { + "70": 0.4 + }, + "ctrlhjkl": { + "70": 0.4 + }, + "hjkl": { + "70": 0.4 + }, + "navigate": { + "70": 0.4 + }, + "results": { + "70": 0.4 + }, "enable": { "71": 1.0 }, "dangerous": { "71": 1.0 }, - "actions": { - "71": 1.0, - "73": 1.0 + "down": { + "71": 0.4 + }, + "log": { + "71": 0.4 + }, + "out": { + "71": 0.4 + }, + "shut": { + "71": 0.4 + }, + "that": { + "71": 0.4 }, "apps": { "72": 1.0, - "79": 1.0 + "79": 1.0, + "92": 0.4, + "97": 0.4 + }, + "fuzzy": { + "72": 0.4, + "73": 0.4, + "74": 0.4, + "75": 0.4, + "76": 0.4 + }, + "search": { + "72": 0.4, + "73": 0.4, + "74": 0.4, + "75": 0.4, + "76": 0.4 }, "schemes": { "74": 1.0 @@ -3047,8 +3939,8 @@ "variants": { "75": 1.0 }, - "all": { - "79": 1.0 + "library": { + "79": 0.4 }, "notifications": { "80": 1.0, @@ -3105,6 +3997,30 @@ "81": 1.0, "82": 1.0 }, + "how": { + "81": 0.4, + "83": 0.4, + "111": 0.4 + }, + "ms": { + "81": 0.4, + "95": 0.4 + }, + "often": { + "81": 0.4, + "83": 0.4 + }, + "polling": { + "81": 0.4, + "82": 0.4, + "83": 0.4 + }, + "position": { + "81": 0.4 + }, + "updates": { + "81": 0.4 + }, "system": { "82": 1.0, "110": 1.0 @@ -3112,32 +4028,117 @@ "stats": { "82": 1.0 }, + "interval": { + "82": 0.4 + }, + "seconds": { + "82": 0.4, + "83": 0.4 + }, + "update": { + "82": 0.4 + }, "rescan": { "83": 1.0 }, + "are": { + "83": 0.4, + "85": 0.4, + "111": 0.4 + }, + "available": { + "83": 0.4 + }, + "networks": { + "83": 0.4 + }, + "rescanned": { + "83": 0.4 + }, "lyrics": { - "84": 1.0 + "84": 1.0, + "85": 0.4 }, "backend": { "84": 1.0 }, + "fetch": { + "84": 0.4 + }, + "source": { + "84": 0.4 + }, + "synced": { + "84": 0.4 + }, + "used": { + "84": 0.4 + }, "default": { "85": 1.0, + "94": 0.4, "95": 1.0 }, "player": { "85": 1.0 }, + "preferred": { + "85": 0.4 + }, + "several": { + "85": 0.4 + }, "step": { "86": 1.0, "87": 1.0 }, + "amount": { + "86": 0.4, + "87": 0.4 + }, + "changes": { + "86": 0.4, + "87": 0.4, + "99": 1.0, + "100": 1.0, + "101": 1.0, + "102": 1.0, + "103": 1.0, + "104": 1.0, + "105": 1.0, + "106": 1.0, + "107": 1.0 + }, + "increments": { + "86": 0.4, + "87": 0.4, + "88": 0.4 + }, + "limit": { + "88": 0.4 + }, + "upper": { + "88": 0.4 + }, "visualiser": { "89": 1.0 }, "bars": { "89": 1.0 }, + "service": { + "89": 0.4, + "90": 0.4, + "91": 0.4 + }, + "tuning": { + "89": 0.4, + "90": 0.4, + "91": 0.4 + }, + "visualisers": { + "89": 0.4 + }, "smart": { "90": 1.0 }, @@ -3147,25 +4148,66 @@ "scheme": { "90": 1.0 }, + "derive": { + "90": 0.4 + }, + "from": { + "90": 0.4 + }, + "mode": { + "90": 0.4, + "100": 1.0 + }, + "variant": { + "90": 0.4 + }, "fullscreen": { "92": 1.0, "97": 1.0 }, + "appear": { + "92": 0.4, + "97": 0.4 + }, + "whether": { + "92": 0.4, + "97": 0.4 + }, "expire": { "93": 1.0 }, "automatically": { "93": 1.0 }, - "open": { - "94": 1.0 + "after": { + "93": 0.4 }, - "expanded": { - "94": 1.0 + "dismiss": { + "93": 0.4 + }, + "their": { + "93": 0.4 }, "timeout": { + "93": 0.4, "95": 1.0 }, + "expanded": { + "94": 1.0 + }, + "by": { + "94": 0.4 + }, + "dismisses": { + "95": 0.4 + }, + "notification": { + "95": 0.4 + }, + "time": { + "95": 0.4, + "111": 0.4 + }, "group": { "96": 1.0 }, @@ -3175,30 +4217,47 @@ "count": { "96": 1.0 }, - "visible": { - "98": 1.0 + "collapsing": { + "96": 0.4 }, "toasts": { + "97": 0.4, "98": 1.0 }, + "maximum": { + "98": 0.4 + }, + "once": { + "98": 0.4 + }, "charging": { "99": 1.0 }, - "changes": { - "99": 1.0, - "100": 1.0, - "101": 1.0, - "102": 1.0, - "103": 1.0, - "104": 1.0, - "105": 1.0, - "106": 1.0, - "107": 1.0 + "events": { + "99": 0.4, + "100": 0.4, + "101": 0.4, + "102": 0.4, + "103": 0.4, + "104": 0.4, + "105": 0.4, + "106": 0.4, + "107": 0.4, + "108": 0.4 }, - "game": { - "100": 1.0 + "toast": { + "99": 0.4, + "100": 0.4, + "101": 0.4, + "102": 0.4, + "103": 0.4, + "104": 0.4, + "105": 0.4, + "106": 0.4, + "107": 0.4, + "108": 0.4 }, - "mode": { + "game": { "100": 1.0 }, "do": { @@ -3236,10 +4295,21 @@ "111": 0.4 }, "temperatures": { + "109": 0.4, "110": 1.0 }, + "units": { + "109": 0.4, + "110": 0.4 + }, "format": { "111": 1.0 + }, + "across": { + "111": 0.4 + }, + "shell": { + "111": 0.4 } } } \ No newline at end of file diff --git a/scripts/__pycache__/build-settings-index.cpython-312.pyc b/scripts/__pycache__/build-settings-index.cpython-312.pyc deleted file mode 100644 index 6b9ac67306b5415366e946be8a4481fc4c2554c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11879 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 diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 1db71afec..0a4093b29 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -174,6 +174,10 @@ def tokenize(text: str) -> list[str]: return toks +SUBTEXT_RE = re.compile(r'^\s*subtext:\s*qsTr\("([^"]+)"\)') +SECTION_RE = re.compile(r'^\s*SectionHeader\s*\{') + + def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict]: entries: list[dict] = [] for comp, meta in nav.items(): @@ -181,11 +185,19 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] if not pf: continue lines = pf.read_text().splitlines() + section = "" # text of the most recent SectionHeader i = 0 while i < len(lines): + # Track the current section header so its words are searchable too. + if SECTION_RE.match(lines[i]): + for j in range(i + 1, min(i + 4, len(lines))): + m = LABEL_RE.match(lines[j]) + if m: + section = m.group(1) + break if ROW_RE.match(lines[i]): - label = anchor = None - for j in range(i + 1, min(i + 10, len(lines))): + label = anchor = subtext = None + for j in range(i + 1, min(i + 12, len(lines))): if label is None: m = LABEL_RE.match(lines[j]) if m: @@ -194,15 +206,19 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] a = ANCHOR_RE.match(lines[j]) if a: anchor = a.group(1) + if subtext is None: + st = SUBTEXT_RE.match(lines[j]) + if st: + subtext = st.group(1) if label and label not in SKIP_LABELS and anchor: - crumb_words = " ".join(meta["crumbLabels"]) - keywords = crumb_words + # keyword sources: breadcrumb path, section header, subtext. + extra = " ".join(meta["crumbLabels"]) + " " + section + " " + (subtext or "") entries.append({ "pageIdx": meta["pageIdx"], "subPath": meta["subPath"], "crumbIcons": meta["crumbIcons"], "crumbLabels": meta["crumbLabels"], "title": label, "anchor": anchor, - "keywords": " ".join(sorted(set(tokenize(label + " " + keywords)))), + "keywords": " ".join(sorted(set(tokenize(label + " " + extra)))), }) i += 1 return entries From d0b017f757315d36017212974d07c266b454a312 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 17:28:51 +0000 Subject: [PATCH 14/57] feat(nexus): animate search scroll and use a double-pulse highlight --- modules/nexus/common/ConnectedRect.qml | 16 ++++++++++++++-- modules/nexus/common/PageBase.qml | 13 +++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/modules/nexus/common/ConnectedRect.qml b/modules/nexus/common/ConnectedRect.qml index e7d5e7b82..d9dada004 100644 --- a/modules/nexus/common/ConnectedRect.qml +++ b/modules/nexus/common/ConnectedRect.qml @@ -41,14 +41,26 @@ StyledRect { Anim { target: highlight property: "opacity" - to: 0.12 + to: 0.2 + duration: Tokens.anim.durations.small + } + Anim { + target: highlight + property: "opacity" + to: 0.08 duration: Tokens.anim.durations.normal } + Anim { + target: highlight + property: "opacity" + to: 0.2 + duration: Tokens.anim.durations.small + } Anim { target: highlight property: "opacity" to: 0 - duration: Tokens.anim.durations.large + duration: Tokens.anim.durations.extraLarge } } } diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 3370c1df7..56c88b697 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -19,6 +19,9 @@ ColumnLayout { readonly property alias flickable: flickable default property Item contentChild + // Enables a smooth scroll animation only for search jumps, so normal + // flicking stays instant. + property bool animateScroll: false // When the settings search jumps to this page, scroll to the matching row. function scrollToAnchor(anchor: string): bool { @@ -34,7 +37,9 @@ ColumnLayout { const minY = -flickable.topMargin; const maxY = Math.max(minY, flickable.contentHeight + flickable.bottomMargin - flickable.height); const target = Math.max(minY, Math.min(pos.y - inset, maxY)); + root.animateScroll = true; flickable.contentY = target; + Qt.callLater(() => root.animateScroll = false); if (row.flashHighlight !== undefined) // qmllint disable missing-property row.flashHighlight(); return true; @@ -133,5 +138,13 @@ ColumnLayout { contentHeight: root.contentChild?.implicitHeight ?? 0 contentItem.children: [root.contentChild] + + Behavior on contentY { + enabled: root.animateScroll + + Anim { + type: Anim.DefaultSpatial + } + } } } From f61ff293b3a433f6baa6057dde8061ae25b5d2e4 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 17:35:33 +0000 Subject: [PATCH 15/57] fix(nexus): wait for layout before scrolling on a freshly opened page --- modules/nexus/common/PageBase.qml | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 56c88b697..2223bc111 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -62,10 +62,8 @@ ColumnLayout { function applySearchAnchor(): void { if (!nState.searchAnchor) return; - Qt.callLater(() => { - if (root.scrollToAnchor(nState.searchAnchor)) - nState.searchAnchor = ""; - }); + scrollRetry.tries = 0; + scrollRetry.restart(); } // Flash a row without scrolling (used when re-selecting the current setting). @@ -79,6 +77,27 @@ ColumnLayout { Component.onCompleted: applySearchAnchor() + Timer { + id: scrollRetry + + property int tries: 0 + + interval: 16 + repeat: true + onTriggered: { + // Wait for the page layout to settle (content taller than the + // viewport, or a few frames elapsed) before scrolling, otherwise a + // freshly loaded page reports stale positions and overshoots. + const ready = flickable.contentHeight > flickable.height || tries >= 8; + if (ready) { + if (root.scrollToAnchor(root.nState.searchAnchor)) + root.nState.searchAnchor = ""; + stop(); + } + tries++; + } + } + Connections { function onSearchAnchorChanged(): void { root.applySearchAnchor(); From e59b3153076afde93bbbd42178065180c6d9d43c Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 18:01:16 +0000 Subject: [PATCH 16/57] feat(nexus): replace highlight flash with a border chase animation --- modules/nexus/common/ConnectedRect.qml | 96 +++++++++++++++++--------- 1 file changed, 63 insertions(+), 33 deletions(-) diff --git a/modules/nexus/common/ConnectedRect.qml b/modules/nexus/common/ConnectedRect.qml index d9dada004..9e2051ee1 100644 --- a/modules/nexus/common/ConnectedRect.qml +++ b/modules/nexus/common/ConnectedRect.qml @@ -1,4 +1,5 @@ import QtQuick +import QtQuick.Shapes import Caelestia.Config import qs.components import qs.services @@ -11,9 +12,13 @@ StyledRect { // Identifier used by the settings search to scroll to this row. property string settingAnchor - // Briefly flash the row, used when the settings search jumps to it. + // Run a chase animation along the row's border, used when the settings + // search jumps to it: a short bright segment races around the outline a + // couple of times and then fades out. Drawn as a dashed stroke (one short + // dash, a long gap) whose dash offset is animated, so the bright part + // follows the rounded corners exactly. function flashHighlight(): void { - flash.restart(); + chase.restart(); } color: Colours.tPalette.m3surfaceContainer @@ -22,45 +27,70 @@ StyledRect { bottomLeftRadius: last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall bottomRightRadius: last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall - StyledRect { - id: highlight + Shape { + id: border - anchors.fill: parent + // Perimeter of the rounded rect, used to size the dash so exactly one + // bright segment travels around at a time. + readonly property real strokeWidth: 2 + readonly property real radius: root.topLeftRadius + readonly property real perimeter: 2 * (width + height) - 8 * radius + 2 * Math.PI * radius + readonly property real dashLen: Math.max(1, perimeter) + property real offset: 0 - radius: parent.radius - topLeftRadius: parent.topLeftRadius - topRightRadius: parent.topRightRadius - bottomLeftRadius: parent.bottomLeftRadius - bottomRightRadius: parent.bottomRightRadius - color: Colours.palette.m3primary + anchors.fill: parent + anchors.margins: strokeWidth / 2 + asynchronous: true + preferredRendererType: Shape.CurveRenderer opacity: 0 - SequentialAnimation { - id: flash + ShapePath { + strokeColor: Colours.palette.m3primary + strokeWidth: border.strokeWidth + fillColor: "transparent" + capStyle: ShapePath.RoundCap + strokeStyle: ShapePath.DashLine + // One short visible dash, then a gap as long as the whole border. + dashPattern: [0.18 * border.dashLen / border.strokeWidth, border.dashLen / border.strokeWidth] + dashOffset: border.offset - Anim { - target: highlight - property: "opacity" - to: 0.2 - duration: Tokens.anim.durations.small - } - Anim { - target: highlight - property: "opacity" - to: 0.08 - duration: Tokens.anim.durations.normal + PathRectangle { + x: 0 + y: 0 + width: border.width - border.strokeWidth + height: border.height - border.strokeWidth + radius: Math.max(0, border.radius - border.strokeWidth / 2) } - Anim { - target: highlight + } + + SequentialAnimation { + id: chase + + PropertyAction { + target: border property: "opacity" - to: 0.2 - duration: Tokens.anim.durations.small + value: 1 } - Anim { - target: highlight - property: "opacity" - to: 0 - duration: Tokens.anim.durations.extraLarge + ParallelAnimation { + NumberAnimation { + target: border + property: "offset" + from: 0 + to: 2 * border.dashLen / border.strokeWidth + duration: Tokens.anim.durations.extraLarge * 2 + easing.type: Easing.InOutQuad + } + SequentialAnimation { + PauseAnimation { + duration: Tokens.anim.durations.large + } + NumberAnimation { + target: border + property: "opacity" + to: 0 + duration: Tokens.anim.durations.large + } + } } } } From 9e965f112745051871e1581f96919a690cc8acc1 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 18:40:10 +0000 Subject: [PATCH 17/57] feat(nexus): redesign search results with a cleaner location, title and description layout --- assets/settings-index.json | 224 ++++++++++++++++++ modules/nexus/SettingsSearcher.qml | 2 + modules/nexus/navpane/NavLocations.qml | 75 +++--- .../build-settings-index.cpython-312.pyc | Bin 0 -> 12655 bytes scripts/build-settings-index.py | 2 + 5 files changed, 259 insertions(+), 44 deletions(-) create mode 100644 scripts/__pycache__/build-settings-index.cpython-312.pyc diff --git a/assets/settings-index.json b/assets/settings-index.json index 80d3a4eb0..bc1d911bf 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -12,6 +12,8 @@ ], "title": "Display wallpaper", "anchor": "style-display-wallpaper", + "section": "", + "subtext": "", "keywords": "display style wallpaper" }, { @@ -25,6 +27,8 @@ ], "title": "Transparency", "anchor": "style-transparency", + "section": "", + "subtext": "Base %1, layers %2", "keywords": "1 2 base layers style transparency wallpaper" }, { @@ -38,6 +42,8 @@ ], "title": "Dark theme", "anchor": "style-dark-theme", + "section": "", + "subtext": "", "keywords": "dark style theme wallpaper" }, { @@ -51,6 +57,8 @@ ], "title": "Wi-Fi", "anchor": "network-wi-fi", + "section": "", + "subtext": "", "keywords": "fi network wi wifi" }, { @@ -64,6 +72,8 @@ ], "title": "Bluetooth", "anchor": "bluetooth-bluetooth", + "section": "", + "subtext": "", "keywords": "bluetooth connected devices" }, { @@ -77,6 +87,8 @@ ], "title": "Discoverable", "anchor": "bluetooth-discoverable", + "section": "", + "subtext": "Allow nearby devices to find this one", "keywords": "allow connected devices discoverable find nearby one this" }, { @@ -90,6 +102,8 @@ ], "title": "Pairable", "anchor": "bluetooth-pairable", + "section": "", + "subtext": "Allow nearby devices to pair with this one", "keywords": "allow connected devices nearby one pair pairable this with" }, { @@ -103,6 +117,8 @@ ], "title": "Output", "anchor": "audio-output", + "section": "", + "subtext": "", "keywords": "audio output" }, { @@ -116,6 +132,8 @@ ], "title": "Input", "anchor": "audio-input", + "section": "", + "subtext": "", "keywords": "audio input" }, { @@ -129,6 +147,8 @@ ], "title": "Dashboard", "anchor": "panels-dashboard", + "section": "", + "subtext": "", "keywords": "dashboard panels" }, { @@ -142,6 +162,8 @@ ], "title": "Taskbar", "anchor": "panels-taskbar", + "section": "", + "subtext": "", "keywords": "panels taskbar" }, { @@ -155,6 +177,8 @@ ], "title": "Launcher", "anchor": "panels-launcher", + "section": "", + "subtext": "", "keywords": "launcher panels" }, { @@ -168,6 +192,8 @@ ], "title": "Sidebar", "anchor": "panels-sidebar", + "section": "", + "subtext": "", "keywords": "panels sidebar" }, { @@ -185,6 +211,8 @@ ], "title": "Enabled", "anchor": "dash-enabled", + "section": "General", + "subtext": "", "keywords": "dashboard enabled general panels" }, { @@ -202,6 +230,8 @@ ], "title": "Show on hover", "anchor": "dash-show-on-hover", + "section": "General", + "subtext": "Reveal when the cursor reaches the screen edge", "keywords": "cursor dashboard edge general hover panels reaches reveal screen show when" }, { @@ -219,6 +249,8 @@ ], "title": "Dashboard", "anchor": "dash-dashboard", + "section": "Tabs", + "subtext": "", "keywords": "dashboard panels tabs" }, { @@ -236,6 +268,8 @@ ], "title": "Media", "anchor": "dash-media", + "section": "Tabs", + "subtext": "", "keywords": "dashboard media panels tabs" }, { @@ -253,6 +287,8 @@ ], "title": "Performance", "anchor": "dash-performance", + "section": "Tabs", + "subtext": "", "keywords": "dashboard panels performance tabs" }, { @@ -270,6 +306,8 @@ ], "title": "Weather", "anchor": "dash-weather", + "section": "Tabs", + "subtext": "", "keywords": "dashboard panels tabs weather" }, { @@ -287,6 +325,8 @@ ], "title": "Battery", "anchor": "dash-battery", + "section": "Performance widgets", + "subtext": "", "keywords": "battery dashboard panels performance widgets" }, { @@ -304,6 +344,8 @@ ], "title": "GPU", "anchor": "dash-gpu", + "section": "Performance widgets", + "subtext": "", "keywords": "dashboard gpu panels performance widgets" }, { @@ -321,6 +363,8 @@ ], "title": "CPU", "anchor": "dash-cpu", + "section": "Performance widgets", + "subtext": "", "keywords": "cpu dashboard panels performance widgets" }, { @@ -338,6 +382,8 @@ ], "title": "Memory", "anchor": "dash-memory", + "section": "Performance widgets", + "subtext": "", "keywords": "dashboard memory panels performance widgets" }, { @@ -355,6 +401,8 @@ ], "title": "Storage", "anchor": "dash-storage", + "section": "Performance widgets", + "subtext": "", "keywords": "dashboard panels performance storage widgets" }, { @@ -372,6 +420,8 @@ ], "title": "Network", "anchor": "dash-network", + "section": "Performance widgets", + "subtext": "", "keywords": "dashboard network panels performance widgets" }, { @@ -389,6 +439,8 @@ ], "title": "Drag threshold", "anchor": "dash-drag-threshold", + "section": "Behaviour", + "subtext": "Pixels dragged before the dashboard opens", "keywords": "before behaviour dashboard drag dragged opens panels pixels threshold" }, { @@ -406,6 +458,8 @@ ], "title": "Persistent", "anchor": "taskbar-persistent", + "section": "Behaviour", + "subtext": "Keep the bar visible at all times", "keywords": "all at bar behaviour keep panels persistent taskbar times visible" }, { @@ -423,6 +477,8 @@ ], "title": "Show on hover", "anchor": "taskbar-show-on-hover", + "section": "Behaviour", + "subtext": "Reveal the bar when the cursor reaches the screen edge", "keywords": "bar behaviour cursor edge hover panels reaches reveal screen show taskbar when" }, { @@ -440,6 +496,8 @@ ], "title": "Drag threshold", "anchor": "taskbar-drag-threshold", + "section": "Behaviour", + "subtext": "Pixels dragged before the bar reveals", "keywords": "bar before behaviour drag dragged panels pixels reveals taskbar threshold" }, { @@ -457,6 +515,8 @@ ], "title": "Workspaces", "anchor": "taskbar-workspaces", + "section": "Components", + "subtext": "", "keywords": "components panels taskbar workspaces" }, { @@ -474,6 +534,8 @@ ], "title": "Active window", "anchor": "taskbar-active-window", + "section": "Components", + "subtext": "", "keywords": "active components panels taskbar window" }, { @@ -491,6 +553,8 @@ ], "title": "Tray", "anchor": "taskbar-tray", + "section": "Components", + "subtext": "", "keywords": "components panels taskbar tray" }, { @@ -508,6 +572,8 @@ ], "title": "Status icons", "anchor": "taskbar-status-icons", + "section": "Components", + "subtext": "", "keywords": "components icons panels status taskbar" }, { @@ -525,6 +591,8 @@ ], "title": "Clock", "anchor": "taskbar-clock", + "section": "Components", + "subtext": "", "keywords": "clock components panels taskbar" }, { @@ -542,6 +610,8 @@ ], "title": "Workspaces", "anchor": "taskbar-workspaces-2", + "section": "Scroll actions", + "subtext": "Scroll over the workspace indicator to switch workspaces", "keywords": "actions indicator over panels scroll switch taskbar workspace workspaces" }, { @@ -559,6 +629,8 @@ ], "title": "Volume", "anchor": "taskbar-volume", + "section": "Scroll actions", + "subtext": "Scroll on the top half of the bar to adjust volume", "keywords": "actions adjust bar half panels scroll taskbar top volume" }, { @@ -576,6 +648,8 @@ ], "title": "Brightness", "anchor": "taskbar-brightness", + "section": "Scroll actions", + "subtext": "Scroll on the bottom half of the bar to adjust brightness", "keywords": "actions adjust bar bottom brightness half panels scroll taskbar" }, { @@ -596,6 +670,8 @@ ], "title": "Shown", "anchor": "bar-ws-shown", + "section": "", + "subtext": "Number of workspaces displayed", "keywords": "displayed number panels shown taskbar workspaces" }, { @@ -616,6 +692,8 @@ ], "title": "Active indicator", "anchor": "bar-ws-active-indicator", + "section": "", + "subtext": "", "keywords": "active indicator panels taskbar workspaces" }, { @@ -636,6 +714,8 @@ ], "title": "Active trail", "anchor": "bar-ws-active-trail", + "section": "", + "subtext": "", "keywords": "active panels taskbar trail workspaces" }, { @@ -656,6 +736,8 @@ ], "title": "Occupied background", "anchor": "bar-ws-occupied-background", + "section": "", + "subtext": "Show icons of open windows on each workspace", "keywords": "background each icons occupied open panels show taskbar windows workspace workspaces" }, { @@ -676,6 +758,8 @@ ], "title": "Show windows", "anchor": "bar-ws-show-windows", + "section": "", + "subtext": "Show icons of open windows on each workspace", "keywords": "each icons open panels show taskbar windows workspace workspaces" }, { @@ -696,6 +780,8 @@ ], "title": "Windows on special workspaces", "anchor": "bar-ws-windows-on-special-workspaces", + "section": "", + "subtext": "", "keywords": "panels special taskbar windows workspaces" }, { @@ -716,6 +802,8 @@ ], "title": "Max window icons", "anchor": "bar-ws-max-window-icons", + "section": "", + "subtext": "", "keywords": "icons max panels taskbar window workspaces" }, { @@ -736,6 +824,8 @@ ], "title": "Per-monitor workspaces", "anchor": "bar-ws-per-monitor-workspaces", + "section": "", + "subtext": "Show each monitor's workspaces independently", "keywords": "each independently monitor monitors panels per permonitor s show taskbar workspaces" }, { @@ -756,6 +846,8 @@ ], "title": "Compact", "anchor": "bar-aw-compact", + "section": "", + "subtext": "", "keywords": "active compact panels taskbar window" }, { @@ -776,6 +868,8 @@ ], "title": "Inverted", "anchor": "bar-aw-inverted", + "section": "", + "subtext": "Only show the active window title while hovering", "keywords": "active hovering inverted only panels show taskbar title while window" }, { @@ -796,6 +890,8 @@ ], "title": "Show on hover", "anchor": "bar-aw-show-on-hover", + "section": "", + "subtext": "Only show the active window title while hovering", "keywords": "active hover hovering only panels show taskbar title while window" }, { @@ -816,6 +912,8 @@ ], "title": "Popout on hover", "anchor": "bar-aw-popout-on-hover", + "section": "", + "subtext": "Show a window details popout when hovering", "keywords": "active details hover hovering panels popout show taskbar when window" }, { @@ -836,6 +934,8 @@ ], "title": "Background", "anchor": "bar-tray-background", + "section": "", + "subtext": "", "keywords": "background panels taskbar tray" }, { @@ -856,6 +956,8 @@ ], "title": "Recolour icons", "anchor": "bar-tray-recolour-icons", + "section": "", + "subtext": "", "keywords": "icons panels recolour taskbar tray" }, { @@ -876,6 +978,8 @@ ], "title": "Compact", "anchor": "bar-tray-compact", + "section": "", + "subtext": "Show the tray menu popout when hovering", "keywords": "compact hovering menu panels popout show taskbar tray when" }, { @@ -896,6 +1000,8 @@ ], "title": "Popout on hover", "anchor": "bar-tray-popout-on-hover", + "section": "", + "subtext": "Show the tray menu popout when hovering", "keywords": "hover hovering menu panels popout show taskbar tray when" }, { @@ -916,6 +1022,8 @@ ], "title": "Speakers", "anchor": "bar-si-speakers", + "section": "Visible icons", + "subtext": "", "keywords": "icons panels speakers status taskbar visible" }, { @@ -936,6 +1044,8 @@ ], "title": "Microphone", "anchor": "bar-si-microphone", + "section": "Visible icons", + "subtext": "", "keywords": "icons microphone panels status taskbar visible" }, { @@ -956,6 +1066,8 @@ ], "title": "Keyboard layout", "anchor": "bar-si-keyboard-layout", + "section": "Visible icons", + "subtext": "", "keywords": "icons keyboard layout panels status taskbar visible" }, { @@ -976,6 +1088,8 @@ ], "title": "Network", "anchor": "bar-si-network", + "section": "Visible icons", + "subtext": "", "keywords": "icons network panels status taskbar visible" }, { @@ -996,6 +1110,8 @@ ], "title": "Wi-Fi", "anchor": "bar-si-wi-fi", + "section": "Visible icons", + "subtext": "", "keywords": "fi icons panels status taskbar visible wi wifi" }, { @@ -1016,6 +1132,8 @@ ], "title": "Bluetooth", "anchor": "bar-si-bluetooth", + "section": "Visible icons", + "subtext": "", "keywords": "bluetooth icons panels status taskbar visible" }, { @@ -1036,6 +1154,8 @@ ], "title": "Battery", "anchor": "bar-si-battery", + "section": "Visible icons", + "subtext": "", "keywords": "battery icons panels status taskbar visible" }, { @@ -1056,6 +1176,8 @@ ], "title": "Caps lock", "anchor": "bar-si-caps-lock", + "section": "Visible icons", + "subtext": "", "keywords": "caps icons lock panels status taskbar visible" }, { @@ -1076,6 +1198,8 @@ ], "title": "Popout on hover", "anchor": "bar-si-popout-on-hover", + "section": "Behaviour", + "subtext": "Show a details popout when hovering the status icons", "keywords": "behaviour details hover hovering icons panels popout show status taskbar when" }, { @@ -1096,6 +1220,8 @@ ], "title": "Background", "anchor": "bar-clock-background", + "section": "", + "subtext": "", "keywords": "background clock panels taskbar" }, { @@ -1116,6 +1242,8 @@ ], "title": "Show date", "anchor": "bar-clock-show-date", + "section": "", + "subtext": "", "keywords": "clock date panels show taskbar" }, { @@ -1136,6 +1264,8 @@ ], "title": "Show icon", "anchor": "bar-clock-show-icon", + "section": "", + "subtext": "", "keywords": "clock icon panels show taskbar" }, { @@ -1153,6 +1283,8 @@ ], "title": "Enabled", "anchor": "launcher-enabled", + "section": "General", + "subtext": "", "keywords": "enabled general launcher panels" }, { @@ -1170,6 +1302,8 @@ ], "title": "Show on hover", "anchor": "launcher-show-on-hover", + "section": "General", + "subtext": "Reveal when the cursor reaches the screen edge", "keywords": "cursor edge general hover launcher panels reaches reveal screen show when" }, { @@ -1187,6 +1321,8 @@ ], "title": "Max items shown", "anchor": "launcher-max-items-shown", + "section": "Display", + "subtext": "", "keywords": "display items launcher max panels shown" }, { @@ -1204,6 +1340,8 @@ ], "title": "Max wallpapers", "anchor": "launcher-max-wallpapers", + "section": "Display", + "subtext": "", "keywords": "display launcher max panels wallpapers" }, { @@ -1221,6 +1359,8 @@ ], "title": "Drag threshold", "anchor": "launcher-drag-threshold", + "section": "Display", + "subtext": "Pixels dragged before the launcher opens", "keywords": "before display drag dragged launcher opens panels pixels threshold" }, { @@ -1238,6 +1378,8 @@ ], "title": "Vim keybinds", "anchor": "launcher-vim-keybinds", + "section": "Behaviour", + "subtext": "Navigate results with Ctrl+hjkl", "keywords": "behaviour ctrl ctrlhjkl hjkl keybinds launcher navigate panels results vim with" }, { @@ -1255,6 +1397,8 @@ ], "title": "Enable dangerous actions", "anchor": "launcher-enable-dangerous-actions", + "section": "Behaviour", + "subtext": "Allow actions that shut down or log out", "keywords": "actions allow behaviour dangerous down enable launcher log out panels shut that" }, { @@ -1272,6 +1416,8 @@ ], "title": "Apps", "anchor": "launcher-apps", + "section": "Fuzzy search", + "subtext": "", "keywords": "apps fuzzy launcher panels search" }, { @@ -1289,6 +1435,8 @@ ], "title": "Actions", "anchor": "launcher-actions", + "section": "Fuzzy search", + "subtext": "", "keywords": "actions fuzzy launcher panels search" }, { @@ -1306,6 +1454,8 @@ ], "title": "Schemes", "anchor": "launcher-schemes", + "section": "Fuzzy search", + "subtext": "", "keywords": "fuzzy launcher panels schemes search" }, { @@ -1323,6 +1473,8 @@ ], "title": "Variants", "anchor": "launcher-variants", + "section": "Fuzzy search", + "subtext": "", "keywords": "fuzzy launcher panels search variants" }, { @@ -1340,6 +1492,8 @@ ], "title": "Wallpapers", "anchor": "launcher-wallpapers", + "section": "Fuzzy search", + "subtext": "", "keywords": "fuzzy launcher panels search wallpapers" }, { @@ -1357,6 +1511,8 @@ ], "title": "Enabled", "anchor": "sidebar-enabled", + "section": "General", + "subtext": "", "keywords": "enabled general panels sidebar" }, { @@ -1374,6 +1530,8 @@ ], "title": "Drag threshold", "anchor": "sidebar-drag-threshold", + "section": "General", + "subtext": "Pixels dragged before the sidebar opens", "keywords": "before drag dragged general opens panels pixels sidebar threshold" }, { @@ -1387,6 +1545,8 @@ ], "title": "All apps", "anchor": "apps-all-apps", + "section": "Library", + "subtext": "", "keywords": "all apps library" }, { @@ -1400,6 +1560,8 @@ ], "title": "Notifications", "anchor": "services-notifications", + "section": "Notifications", + "subtext": "", "keywords": "notifications services" }, { @@ -1413,6 +1575,8 @@ ], "title": "Media refresh", "anchor": "services-media-refresh", + "section": "Polling", + "subtext": "How often the media position updates (ms)", "keywords": "how media ms often polling position refresh services updates" }, { @@ -1426,6 +1590,8 @@ ], "title": "System stats refresh", "anchor": "services-system-stats-refresh", + "section": "Polling", + "subtext": "CPU, memory and GPU update interval (seconds)", "keywords": "cpu gpu interval memory polling refresh seconds services stats system update" }, { @@ -1439,6 +1605,8 @@ ], "title": "Wi-Fi rescan", "anchor": "services-wi-fi-rescan", + "section": "Polling", + "subtext": "How often available networks are rescanned (seconds)", "keywords": "are available fi how networks often polling rescan rescanned seconds services wi wifi" }, { @@ -1452,6 +1620,8 @@ ], "title": "Lyrics backend", "anchor": "services-lyrics-backend", + "section": "Media & lyrics", + "subtext": "Source used to fetch synced lyrics", "keywords": "backend fetch lyrics media services source synced used" }, { @@ -1465,6 +1635,8 @@ ], "title": "Default player", "anchor": "services-default-player", + "section": "Media & lyrics", + "subtext": "Preferred media player when several are open", "keywords": "are default lyrics media open player preferred services several when" }, { @@ -1478,6 +1650,8 @@ ], "title": "Volume step", "anchor": "services-volume-step", + "section": "Input increments", + "subtext": "Amount the volume changes per scroll (%)", "keywords": "amount changes increments input per scroll services step volume" }, { @@ -1491,6 +1665,8 @@ ], "title": "Brightness step", "anchor": "services-brightness-step", + "section": "Input increments", + "subtext": "Amount the brightness changes per scroll (%)", "keywords": "amount brightness changes increments input per scroll services step" }, { @@ -1504,6 +1680,8 @@ ], "title": "Max volume", "anchor": "services-max-volume", + "section": "Input increments", + "subtext": "Upper limit for output volume (%)", "keywords": "increments input limit max output services upper volume" }, { @@ -1517,6 +1695,8 @@ ], "title": "Visualiser bars", "anchor": "services-visualiser-bars", + "section": "Service tuning", + "subtext": "Number of bars in the audio visualisers", "keywords": "audio bars number service services tuning visualiser visualisers" }, { @@ -1530,6 +1710,8 @@ ], "title": "Smart colour scheme", "anchor": "services-smart-colour-scheme", + "section": "Service tuning", + "subtext": "Derive theme mode and variant from the wallpaper", "keywords": "colour derive from mode scheme service services smart theme tuning variant wallpaper" }, { @@ -1543,6 +1725,8 @@ ], "title": "GPU", "anchor": "services-gpu", + "section": "Service tuning", + "subtext": "", "keywords": "gpu service services tuning" }, { @@ -1560,6 +1744,8 @@ ], "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen", + "section": "Notifications", + "subtext": "Whether notifications appear over fullscreen apps", "keywords": "appear apps fullscreen notifications over services show whether" }, { @@ -1577,6 +1763,8 @@ ], "title": "Expire automatically", "anchor": "notif-expire-automatically", + "section": "Notifications", + "subtext": "Dismiss notifications after their timeout", "keywords": "after automatically dismiss expire notifications services their timeout" }, { @@ -1594,6 +1782,8 @@ ], "title": "Open expanded", "anchor": "notif-open-expanded", + "section": "Notifications", + "subtext": "Show notifications expanded by default", "keywords": "by default expanded notifications open services show" }, { @@ -1611,6 +1801,8 @@ ], "title": "Default timeout", "anchor": "notif-default-timeout", + "section": "Notifications", + "subtext": "Time before a notification dismisses (ms)", "keywords": "before default dismisses ms notification notifications services time timeout" }, { @@ -1628,6 +1820,8 @@ ], "title": "Group preview count", "anchor": "notif-group-preview-count", + "section": "Notifications", + "subtext": "Notifications shown per group before collapsing", "keywords": "before collapsing count group notifications per preview services shown" }, { @@ -1645,6 +1839,8 @@ ], "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen-2", + "section": "Toasts", + "subtext": "Whether toasts appear over fullscreen apps", "keywords": "appear apps fullscreen notifications over services show toasts whether" }, { @@ -1662,6 +1858,8 @@ ], "title": "Visible toasts", "anchor": "notif-visible-toasts", + "section": "Toasts", + "subtext": "Maximum number of toasts shown at once", "keywords": "at maximum notifications number once services shown toasts visible" }, { @@ -1679,6 +1877,8 @@ ], "title": "Charging changes", "anchor": "notif-charging-changes", + "section": "Toast events", + "subtext": "", "keywords": "changes charging events notifications services toast" }, { @@ -1696,6 +1896,8 @@ ], "title": "Game mode changes", "anchor": "notif-game-mode-changes", + "section": "Toast events", + "subtext": "", "keywords": "changes events game mode notifications services toast" }, { @@ -1713,6 +1915,8 @@ ], "title": "Do not disturb changes", "anchor": "notif-do-not-disturb-changes", + "section": "Toast events", + "subtext": "", "keywords": "changes disturb do events not notifications services toast" }, { @@ -1730,6 +1934,8 @@ ], "title": "Audio output changes", "anchor": "notif-audio-output-changes", + "section": "Toast events", + "subtext": "", "keywords": "audio changes events notifications output services toast" }, { @@ -1747,6 +1953,8 @@ ], "title": "Audio input changes", "anchor": "notif-audio-input-changes", + "section": "Toast events", + "subtext": "", "keywords": "audio changes events input notifications services toast" }, { @@ -1764,6 +1972,8 @@ ], "title": "Caps lock changes", "anchor": "notif-caps-lock-changes", + "section": "Toast events", + "subtext": "", "keywords": "caps changes events lock notifications services toast" }, { @@ -1781,6 +1991,8 @@ ], "title": "Num lock changes", "anchor": "notif-num-lock-changes", + "section": "Toast events", + "subtext": "", "keywords": "changes events lock notifications num services toast" }, { @@ -1798,6 +2010,8 @@ ], "title": "Keyboard layout changes", "anchor": "notif-keyboard-layout-changes", + "section": "Toast events", + "subtext": "", "keywords": "changes events keyboard layout notifications services toast" }, { @@ -1815,6 +2029,8 @@ ], "title": "VPN changes", "anchor": "notif-vpn-changes", + "section": "Toast events", + "subtext": "", "keywords": "changes events notifications services toast vpn" }, { @@ -1832,6 +2048,8 @@ ], "title": "Now playing", "anchor": "notif-now-playing", + "section": "Toast events", + "subtext": "", "keywords": "events notifications now playing services toast" }, { @@ -1845,6 +2063,8 @@ ], "title": "Temperature", "anchor": "lang-temperature", + "section": "Units", + "subtext": "Units for weather temperatures", "keywords": "language region temperature temperatures units weather" }, { @@ -1858,6 +2078,8 @@ ], "title": "System temperatures", "anchor": "lang-system-temperatures", + "section": "Units", + "subtext": "Units for CPU and GPU temperatures", "keywords": "cpu gpu language region system temperatures units" }, { @@ -1871,6 +2093,8 @@ ], "title": "Clock format", "anchor": "lang-clock-format", + "section": "Time & date", + "subtext": "How times are shown across the shell", "keywords": "across are clock date format how language region shell shown time times" } ], diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index f55809f97..89a639cac 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -100,6 +100,8 @@ Singleton { readonly property var crumbIcons: modelData.crumbIcons readonly property var crumbLabels: modelData.crumbLabels readonly property string title: modelData.title + readonly property string section: modelData.section ?? "" + readonly property string subtext: modelData.subtext ?? "" readonly property string keywords: modelData.keywords ?? "" readonly property string anchor: modelData.anchor ?? "" } diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index ce26c54d4..9e3dd60a6 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -157,65 +157,52 @@ VerticalFadeFlickable { anchors.fill: parent anchors.margins: Tokens.padding.large - spacing: Tokens.spacing.extraSmall - - Repeater { - model: result.modelData.crumbLabels - - RowLayout { - id: crumb - - required property var modelData - required property int index - - Layout.leftMargin: index * Tokens.padding.large - spacing: Tokens.spacing.small - - MaterialIcon { - Layout.alignment: Qt.AlignVCenter - text: crumb.index > 0 ? "subdirectory_arrow_right" : "" - visible: crumb.index > 0 - color: Colours.palette.m3onSurfaceVariant - fontStyle: Tokens.font.icon.small - } - - MaterialIcon { - Layout.alignment: Qt.AlignVCenter - text: result.modelData.crumbIcons[crumb.index] - color: Colours.palette.m3onSurfaceVariant - fontStyle: Tokens.font.icon.small - } - - StyledText { - text: crumb.modelData - color: Colours.palette.m3onSurfaceVariant - font: Tokens.font.label.small - elide: Text.ElideRight - } - } - } + spacing: Tokens.spacing.small / 2 + // Location line: page icon + "Page › Section", faint. RowLayout { Layout.fillWidth: true - Layout.leftMargin: result.modelData.crumbLabels.length * Tokens.padding.large - Layout.topMargin: Tokens.spacing.extraSmall spacing: Tokens.spacing.small MaterialIcon { Layout.alignment: Qt.AlignVCenter - text: "subdirectory_arrow_right" - color: Colours.palette.m3primary + text: result.modelData.crumbIcons[result.modelData.crumbIcons.length - 1] + color: Colours.palette.m3onSurfaceVariant fontStyle: Tokens.font.icon.small } StyledText { Layout.fillWidth: true - text: result.modelData.title - color: Colours.palette.m3primary - font: Tokens.font.body.medium + text: { + const crumbs = result.modelData.crumbLabels.join(" › "); + const section = result.modelData.section; + return section ? `${crumbs} › ${section}` : crumbs; + } + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.label.small elide: Text.ElideRight } } + + // The setting itself, most prominent. + StyledText { + Layout.fillWidth: true + Layout.topMargin: Tokens.spacing.small / 2 + text: result.modelData.title + color: Colours.palette.m3primary + font: Tokens.font.body.medium + elide: Text.ElideRight + } + + // Optional description, faintest and smallest. + StyledText { + Layout.fillWidth: true + visible: result.modelData.subtext.length > 0 + text: result.modelData.subtext + color: Colours.palette.m3outline + font: Tokens.font.label.small + elide: Text.ElideRight + } } } } diff --git a/scripts/__pycache__/build-settings-index.cpython-312.pyc b/scripts/__pycache__/build-settings-index.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6b11ff7712102540f0da6956e7ccc88ee85a603 GIT binary patch literal 12655 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 literal 0 HcmV?d00001 diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 0a4093b29..44a2da61f 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -218,6 +218,8 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] "crumbIcons": meta["crumbIcons"], "crumbLabels": meta["crumbLabels"], "title": label, "anchor": anchor, + "section": section, + "subtext": subtext or "", "keywords": " ".join(sorted(set(tokenize(label + " " + extra)))), }) i += 1 From 68715e17af2224c9b561a2ba8ddd05845669903d Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 20:59:16 +0000 Subject: [PATCH 18/57] feat(nexus): animate search results with a ListView and diffed model --- modules/nexus/navpane/NavLocations.qml | 71 +++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 9e3dd60a6..c809399f8 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts +import Quickshell import Caelestia.Config import qs.components import qs.components.containers @@ -15,7 +16,7 @@ VerticalFadeFlickable { readonly property string search: nState.searchText readonly property bool searching: search.length > 0 - readonly property var results: searching ? SettingsSearcher.query(search).slice(0, 12) : [] + readonly property var results: searching ? SettingsSearcher.query(search) : [] topMargin: Tokens.padding.large bottomMargin: Tokens.padding.large @@ -125,18 +126,72 @@ VerticalFadeFlickable { } } - Repeater { + ListView { id: resultList - model: root.results + // A ListView fed by a ScriptModel (same approach as the launcher): + // when the query changes the model diffs the result list, so only + // entries that actually appear/disappear/move are animated. The + // rest stay put, which avoids re-animating the whole list on every + // keystroke. Scrolling is delegated to the outer flickable. + Layout.fillWidth: true + implicitHeight: contentHeight + interactive: false + spacing: Tokens.spacing.extraSmall - StyledRect { + model: ScriptModel { + values: root.results + } + + add: Transition { + Anim { + type: Anim.DefaultEffects + property: "opacity" + from: 0 + to: 1 + } + } + + remove: Transition { + Anim { + type: Anim.DefaultEffects + property: "opacity" + from: 1 + to: 0 + } + } + + displaced: Transition { + Anim { + type: Anim.StandardSmall + property: "y" + } + Anim { + type: Anim.DefaultEffects + property: "opacity" + to: 1 + } + } + + addDisplaced: Transition { + Anim { + type: Anim.StandardSmall + property: "y" + } + Anim { + type: Anim.DefaultEffects + property: "opacity" + to: 1 + } + } + + delegate: StyledRect { id: result required property var modelData required property int index - Layout.fillWidth: true + width: resultList.width implicitHeight: { const h = resultLayout.implicitHeight + resultLayout.anchors.margins * 2; return h % 2 === 0 ? h : h + 1; @@ -159,7 +214,7 @@ VerticalFadeFlickable { anchors.margins: Tokens.padding.large spacing: Tokens.spacing.small / 2 - // Location line: page icon + "Page › Section", faint. + // Location line: page icon + "Page \u203a Section", faint. RowLayout { Layout.fillWidth: true spacing: Tokens.spacing.small @@ -174,9 +229,9 @@ VerticalFadeFlickable { StyledText { Layout.fillWidth: true text: { - const crumbs = result.modelData.crumbLabels.join(" › "); + const crumbs = result.modelData.crumbLabels.join(" \u203a "); const section = result.modelData.section; - return section ? `${crumbs} › ${section}` : crumbs; + return section ? `${crumbs} \u203a ${section}` : crumbs; } color: Colours.palette.m3onSurfaceVariant font: Tokens.font.label.small From 7fa2a58676fbbff1b0e9d5f7ea108d2c1329b050 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 23:31:05 +0000 Subject: [PATCH 19/57] perf(nexus): cache file reads, drop unused keywords from the index and runtime --- assets/settings-index.json | 336 ++++++++++------------------- modules/nexus/SettingsSearcher.qml | 1 - scripts/build-settings-index.py | 15 +- 3 files changed, 125 insertions(+), 227 deletions(-) diff --git a/assets/settings-index.json b/assets/settings-index.json index bc1d911bf..1a623465f 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -13,8 +13,7 @@ "title": "Display wallpaper", "anchor": "style-display-wallpaper", "section": "", - "subtext": "", - "keywords": "display style wallpaper" + "subtext": "" }, { "pageIdx": 0, @@ -28,8 +27,7 @@ "title": "Transparency", "anchor": "style-transparency", "section": "", - "subtext": "Base %1, layers %2", - "keywords": "1 2 base layers style transparency wallpaper" + "subtext": "Base %1, layers %2" }, { "pageIdx": 0, @@ -43,8 +41,7 @@ "title": "Dark theme", "anchor": "style-dark-theme", "section": "", - "subtext": "", - "keywords": "dark style theme wallpaper" + "subtext": "" }, { "pageIdx": 1, @@ -58,8 +55,7 @@ "title": "Wi-Fi", "anchor": "network-wi-fi", "section": "", - "subtext": "", - "keywords": "fi network wi wifi" + "subtext": "" }, { "pageIdx": 2, @@ -73,8 +69,7 @@ "title": "Bluetooth", "anchor": "bluetooth-bluetooth", "section": "", - "subtext": "", - "keywords": "bluetooth connected devices" + "subtext": "" }, { "pageIdx": 2, @@ -88,8 +83,7 @@ "title": "Discoverable", "anchor": "bluetooth-discoverable", "section": "", - "subtext": "Allow nearby devices to find this one", - "keywords": "allow connected devices discoverable find nearby one this" + "subtext": "Allow nearby devices to find this one" }, { "pageIdx": 2, @@ -103,8 +97,7 @@ "title": "Pairable", "anchor": "bluetooth-pairable", "section": "", - "subtext": "Allow nearby devices to pair with this one", - "keywords": "allow connected devices nearby one pair pairable this with" + "subtext": "Allow nearby devices to pair with this one" }, { "pageIdx": 3, @@ -118,8 +111,7 @@ "title": "Output", "anchor": "audio-output", "section": "", - "subtext": "", - "keywords": "audio output" + "subtext": "" }, { "pageIdx": 3, @@ -133,8 +125,7 @@ "title": "Input", "anchor": "audio-input", "section": "", - "subtext": "", - "keywords": "audio input" + "subtext": "" }, { "pageIdx": 6, @@ -148,8 +139,7 @@ "title": "Dashboard", "anchor": "panels-dashboard", "section": "", - "subtext": "", - "keywords": "dashboard panels" + "subtext": "" }, { "pageIdx": 6, @@ -163,8 +153,7 @@ "title": "Taskbar", "anchor": "panels-taskbar", "section": "", - "subtext": "", - "keywords": "panels taskbar" + "subtext": "" }, { "pageIdx": 6, @@ -178,8 +167,7 @@ "title": "Launcher", "anchor": "panels-launcher", "section": "", - "subtext": "", - "keywords": "launcher panels" + "subtext": "" }, { "pageIdx": 6, @@ -193,8 +181,7 @@ "title": "Sidebar", "anchor": "panels-sidebar", "section": "", - "subtext": "", - "keywords": "panels sidebar" + "subtext": "" }, { "pageIdx": 6, @@ -212,8 +199,7 @@ "title": "Enabled", "anchor": "dash-enabled", "section": "General", - "subtext": "", - "keywords": "dashboard enabled general panels" + "subtext": "" }, { "pageIdx": 6, @@ -231,8 +217,7 @@ "title": "Show on hover", "anchor": "dash-show-on-hover", "section": "General", - "subtext": "Reveal when the cursor reaches the screen edge", - "keywords": "cursor dashboard edge general hover panels reaches reveal screen show when" + "subtext": "Reveal when the cursor reaches the screen edge" }, { "pageIdx": 6, @@ -250,8 +235,7 @@ "title": "Dashboard", "anchor": "dash-dashboard", "section": "Tabs", - "subtext": "", - "keywords": "dashboard panels tabs" + "subtext": "" }, { "pageIdx": 6, @@ -269,8 +253,7 @@ "title": "Media", "anchor": "dash-media", "section": "Tabs", - "subtext": "", - "keywords": "dashboard media panels tabs" + "subtext": "" }, { "pageIdx": 6, @@ -288,8 +271,7 @@ "title": "Performance", "anchor": "dash-performance", "section": "Tabs", - "subtext": "", - "keywords": "dashboard panels performance tabs" + "subtext": "" }, { "pageIdx": 6, @@ -307,8 +289,7 @@ "title": "Weather", "anchor": "dash-weather", "section": "Tabs", - "subtext": "", - "keywords": "dashboard panels tabs weather" + "subtext": "" }, { "pageIdx": 6, @@ -326,8 +307,7 @@ "title": "Battery", "anchor": "dash-battery", "section": "Performance widgets", - "subtext": "", - "keywords": "battery dashboard panels performance widgets" + "subtext": "" }, { "pageIdx": 6, @@ -345,8 +325,7 @@ "title": "GPU", "anchor": "dash-gpu", "section": "Performance widgets", - "subtext": "", - "keywords": "dashboard gpu panels performance widgets" + "subtext": "" }, { "pageIdx": 6, @@ -364,8 +343,7 @@ "title": "CPU", "anchor": "dash-cpu", "section": "Performance widgets", - "subtext": "", - "keywords": "cpu dashboard panels performance widgets" + "subtext": "" }, { "pageIdx": 6, @@ -383,8 +361,7 @@ "title": "Memory", "anchor": "dash-memory", "section": "Performance widgets", - "subtext": "", - "keywords": "dashboard memory panels performance widgets" + "subtext": "" }, { "pageIdx": 6, @@ -402,8 +379,7 @@ "title": "Storage", "anchor": "dash-storage", "section": "Performance widgets", - "subtext": "", - "keywords": "dashboard panels performance storage widgets" + "subtext": "" }, { "pageIdx": 6, @@ -421,8 +397,7 @@ "title": "Network", "anchor": "dash-network", "section": "Performance widgets", - "subtext": "", - "keywords": "dashboard network panels performance widgets" + "subtext": "" }, { "pageIdx": 6, @@ -440,8 +415,7 @@ "title": "Drag threshold", "anchor": "dash-drag-threshold", "section": "Behaviour", - "subtext": "Pixels dragged before the dashboard opens", - "keywords": "before behaviour dashboard drag dragged opens panels pixels threshold" + "subtext": "Pixels dragged before the dashboard opens" }, { "pageIdx": 6, @@ -459,8 +433,7 @@ "title": "Persistent", "anchor": "taskbar-persistent", "section": "Behaviour", - "subtext": "Keep the bar visible at all times", - "keywords": "all at bar behaviour keep panels persistent taskbar times visible" + "subtext": "Keep the bar visible at all times" }, { "pageIdx": 6, @@ -478,8 +451,7 @@ "title": "Show on hover", "anchor": "taskbar-show-on-hover", "section": "Behaviour", - "subtext": "Reveal the bar when the cursor reaches the screen edge", - "keywords": "bar behaviour cursor edge hover panels reaches reveal screen show taskbar when" + "subtext": "Reveal the bar when the cursor reaches the screen edge" }, { "pageIdx": 6, @@ -497,8 +469,7 @@ "title": "Drag threshold", "anchor": "taskbar-drag-threshold", "section": "Behaviour", - "subtext": "Pixels dragged before the bar reveals", - "keywords": "bar before behaviour drag dragged panels pixels reveals taskbar threshold" + "subtext": "Pixels dragged before the bar reveals" }, { "pageIdx": 6, @@ -516,8 +487,7 @@ "title": "Workspaces", "anchor": "taskbar-workspaces", "section": "Components", - "subtext": "", - "keywords": "components panels taskbar workspaces" + "subtext": "" }, { "pageIdx": 6, @@ -535,8 +505,7 @@ "title": "Active window", "anchor": "taskbar-active-window", "section": "Components", - "subtext": "", - "keywords": "active components panels taskbar window" + "subtext": "" }, { "pageIdx": 6, @@ -554,8 +523,7 @@ "title": "Tray", "anchor": "taskbar-tray", "section": "Components", - "subtext": "", - "keywords": "components panels taskbar tray" + "subtext": "" }, { "pageIdx": 6, @@ -573,8 +541,7 @@ "title": "Status icons", "anchor": "taskbar-status-icons", "section": "Components", - "subtext": "", - "keywords": "components icons panels status taskbar" + "subtext": "" }, { "pageIdx": 6, @@ -592,8 +559,7 @@ "title": "Clock", "anchor": "taskbar-clock", "section": "Components", - "subtext": "", - "keywords": "clock components panels taskbar" + "subtext": "" }, { "pageIdx": 6, @@ -611,8 +577,7 @@ "title": "Workspaces", "anchor": "taskbar-workspaces-2", "section": "Scroll actions", - "subtext": "Scroll over the workspace indicator to switch workspaces", - "keywords": "actions indicator over panels scroll switch taskbar workspace workspaces" + "subtext": "Scroll over the workspace indicator to switch workspaces" }, { "pageIdx": 6, @@ -630,8 +595,7 @@ "title": "Volume", "anchor": "taskbar-volume", "section": "Scroll actions", - "subtext": "Scroll on the top half of the bar to adjust volume", - "keywords": "actions adjust bar half panels scroll taskbar top volume" + "subtext": "Scroll on the top half of the bar to adjust volume" }, { "pageIdx": 6, @@ -649,8 +613,7 @@ "title": "Brightness", "anchor": "taskbar-brightness", "section": "Scroll actions", - "subtext": "Scroll on the bottom half of the bar to adjust brightness", - "keywords": "actions adjust bar bottom brightness half panels scroll taskbar" + "subtext": "Scroll on the bottom half of the bar to adjust brightness" }, { "pageIdx": 6, @@ -671,8 +634,7 @@ "title": "Shown", "anchor": "bar-ws-shown", "section": "", - "subtext": "Number of workspaces displayed", - "keywords": "displayed number panels shown taskbar workspaces" + "subtext": "Number of workspaces displayed" }, { "pageIdx": 6, @@ -693,8 +655,7 @@ "title": "Active indicator", "anchor": "bar-ws-active-indicator", "section": "", - "subtext": "", - "keywords": "active indicator panels taskbar workspaces" + "subtext": "" }, { "pageIdx": 6, @@ -715,8 +676,7 @@ "title": "Active trail", "anchor": "bar-ws-active-trail", "section": "", - "subtext": "", - "keywords": "active panels taskbar trail workspaces" + "subtext": "" }, { "pageIdx": 6, @@ -737,8 +697,7 @@ "title": "Occupied background", "anchor": "bar-ws-occupied-background", "section": "", - "subtext": "Show icons of open windows on each workspace", - "keywords": "background each icons occupied open panels show taskbar windows workspace workspaces" + "subtext": "Show icons of open windows on each workspace" }, { "pageIdx": 6, @@ -759,8 +718,7 @@ "title": "Show windows", "anchor": "bar-ws-show-windows", "section": "", - "subtext": "Show icons of open windows on each workspace", - "keywords": "each icons open panels show taskbar windows workspace workspaces" + "subtext": "Show icons of open windows on each workspace" }, { "pageIdx": 6, @@ -781,8 +739,7 @@ "title": "Windows on special workspaces", "anchor": "bar-ws-windows-on-special-workspaces", "section": "", - "subtext": "", - "keywords": "panels special taskbar windows workspaces" + "subtext": "" }, { "pageIdx": 6, @@ -803,8 +760,7 @@ "title": "Max window icons", "anchor": "bar-ws-max-window-icons", "section": "", - "subtext": "", - "keywords": "icons max panels taskbar window workspaces" + "subtext": "" }, { "pageIdx": 6, @@ -825,8 +781,7 @@ "title": "Per-monitor workspaces", "anchor": "bar-ws-per-monitor-workspaces", "section": "", - "subtext": "Show each monitor's workspaces independently", - "keywords": "each independently monitor monitors panels per permonitor s show taskbar workspaces" + "subtext": "Show each monitor's workspaces independently" }, { "pageIdx": 6, @@ -847,8 +802,7 @@ "title": "Compact", "anchor": "bar-aw-compact", "section": "", - "subtext": "", - "keywords": "active compact panels taskbar window" + "subtext": "" }, { "pageIdx": 6, @@ -869,8 +823,7 @@ "title": "Inverted", "anchor": "bar-aw-inverted", "section": "", - "subtext": "Only show the active window title while hovering", - "keywords": "active hovering inverted only panels show taskbar title while window" + "subtext": "Only show the active window title while hovering" }, { "pageIdx": 6, @@ -891,8 +844,7 @@ "title": "Show on hover", "anchor": "bar-aw-show-on-hover", "section": "", - "subtext": "Only show the active window title while hovering", - "keywords": "active hover hovering only panels show taskbar title while window" + "subtext": "Only show the active window title while hovering" }, { "pageIdx": 6, @@ -913,8 +865,7 @@ "title": "Popout on hover", "anchor": "bar-aw-popout-on-hover", "section": "", - "subtext": "Show a window details popout when hovering", - "keywords": "active details hover hovering panels popout show taskbar when window" + "subtext": "Show a window details popout when hovering" }, { "pageIdx": 6, @@ -935,8 +886,7 @@ "title": "Background", "anchor": "bar-tray-background", "section": "", - "subtext": "", - "keywords": "background panels taskbar tray" + "subtext": "" }, { "pageIdx": 6, @@ -957,8 +907,7 @@ "title": "Recolour icons", "anchor": "bar-tray-recolour-icons", "section": "", - "subtext": "", - "keywords": "icons panels recolour taskbar tray" + "subtext": "" }, { "pageIdx": 6, @@ -979,8 +928,7 @@ "title": "Compact", "anchor": "bar-tray-compact", "section": "", - "subtext": "Show the tray menu popout when hovering", - "keywords": "compact hovering menu panels popout show taskbar tray when" + "subtext": "Show the tray menu popout when hovering" }, { "pageIdx": 6, @@ -1001,8 +949,7 @@ "title": "Popout on hover", "anchor": "bar-tray-popout-on-hover", "section": "", - "subtext": "Show the tray menu popout when hovering", - "keywords": "hover hovering menu panels popout show taskbar tray when" + "subtext": "Show the tray menu popout when hovering" }, { "pageIdx": 6, @@ -1023,8 +970,7 @@ "title": "Speakers", "anchor": "bar-si-speakers", "section": "Visible icons", - "subtext": "", - "keywords": "icons panels speakers status taskbar visible" + "subtext": "" }, { "pageIdx": 6, @@ -1045,8 +991,7 @@ "title": "Microphone", "anchor": "bar-si-microphone", "section": "Visible icons", - "subtext": "", - "keywords": "icons microphone panels status taskbar visible" + "subtext": "" }, { "pageIdx": 6, @@ -1067,8 +1012,7 @@ "title": "Keyboard layout", "anchor": "bar-si-keyboard-layout", "section": "Visible icons", - "subtext": "", - "keywords": "icons keyboard layout panels status taskbar visible" + "subtext": "" }, { "pageIdx": 6, @@ -1089,8 +1033,7 @@ "title": "Network", "anchor": "bar-si-network", "section": "Visible icons", - "subtext": "", - "keywords": "icons network panels status taskbar visible" + "subtext": "" }, { "pageIdx": 6, @@ -1111,8 +1054,7 @@ "title": "Wi-Fi", "anchor": "bar-si-wi-fi", "section": "Visible icons", - "subtext": "", - "keywords": "fi icons panels status taskbar visible wi wifi" + "subtext": "" }, { "pageIdx": 6, @@ -1133,8 +1075,7 @@ "title": "Bluetooth", "anchor": "bar-si-bluetooth", "section": "Visible icons", - "subtext": "", - "keywords": "bluetooth icons panels status taskbar visible" + "subtext": "" }, { "pageIdx": 6, @@ -1155,8 +1096,7 @@ "title": "Battery", "anchor": "bar-si-battery", "section": "Visible icons", - "subtext": "", - "keywords": "battery icons panels status taskbar visible" + "subtext": "" }, { "pageIdx": 6, @@ -1177,8 +1117,7 @@ "title": "Caps lock", "anchor": "bar-si-caps-lock", "section": "Visible icons", - "subtext": "", - "keywords": "caps icons lock panels status taskbar visible" + "subtext": "" }, { "pageIdx": 6, @@ -1199,8 +1138,7 @@ "title": "Popout on hover", "anchor": "bar-si-popout-on-hover", "section": "Behaviour", - "subtext": "Show a details popout when hovering the status icons", - "keywords": "behaviour details hover hovering icons panels popout show status taskbar when" + "subtext": "Show a details popout when hovering the status icons" }, { "pageIdx": 6, @@ -1221,8 +1159,7 @@ "title": "Background", "anchor": "bar-clock-background", "section": "", - "subtext": "", - "keywords": "background clock panels taskbar" + "subtext": "" }, { "pageIdx": 6, @@ -1243,8 +1180,7 @@ "title": "Show date", "anchor": "bar-clock-show-date", "section": "", - "subtext": "", - "keywords": "clock date panels show taskbar" + "subtext": "" }, { "pageIdx": 6, @@ -1265,8 +1201,7 @@ "title": "Show icon", "anchor": "bar-clock-show-icon", "section": "", - "subtext": "", - "keywords": "clock icon panels show taskbar" + "subtext": "" }, { "pageIdx": 6, @@ -1284,8 +1219,7 @@ "title": "Enabled", "anchor": "launcher-enabled", "section": "General", - "subtext": "", - "keywords": "enabled general launcher panels" + "subtext": "" }, { "pageIdx": 6, @@ -1303,8 +1237,7 @@ "title": "Show on hover", "anchor": "launcher-show-on-hover", "section": "General", - "subtext": "Reveal when the cursor reaches the screen edge", - "keywords": "cursor edge general hover launcher panels reaches reveal screen show when" + "subtext": "Reveal when the cursor reaches the screen edge" }, { "pageIdx": 6, @@ -1322,8 +1255,7 @@ "title": "Max items shown", "anchor": "launcher-max-items-shown", "section": "Display", - "subtext": "", - "keywords": "display items launcher max panels shown" + "subtext": "" }, { "pageIdx": 6, @@ -1341,8 +1273,7 @@ "title": "Max wallpapers", "anchor": "launcher-max-wallpapers", "section": "Display", - "subtext": "", - "keywords": "display launcher max panels wallpapers" + "subtext": "" }, { "pageIdx": 6, @@ -1360,8 +1291,7 @@ "title": "Drag threshold", "anchor": "launcher-drag-threshold", "section": "Display", - "subtext": "Pixels dragged before the launcher opens", - "keywords": "before display drag dragged launcher opens panels pixels threshold" + "subtext": "Pixels dragged before the launcher opens" }, { "pageIdx": 6, @@ -1379,8 +1309,7 @@ "title": "Vim keybinds", "anchor": "launcher-vim-keybinds", "section": "Behaviour", - "subtext": "Navigate results with Ctrl+hjkl", - "keywords": "behaviour ctrl ctrlhjkl hjkl keybinds launcher navigate panels results vim with" + "subtext": "Navigate results with Ctrl+hjkl" }, { "pageIdx": 6, @@ -1398,8 +1327,7 @@ "title": "Enable dangerous actions", "anchor": "launcher-enable-dangerous-actions", "section": "Behaviour", - "subtext": "Allow actions that shut down or log out", - "keywords": "actions allow behaviour dangerous down enable launcher log out panels shut that" + "subtext": "Allow actions that shut down or log out" }, { "pageIdx": 6, @@ -1417,8 +1345,7 @@ "title": "Apps", "anchor": "launcher-apps", "section": "Fuzzy search", - "subtext": "", - "keywords": "apps fuzzy launcher panels search" + "subtext": "" }, { "pageIdx": 6, @@ -1436,8 +1363,7 @@ "title": "Actions", "anchor": "launcher-actions", "section": "Fuzzy search", - "subtext": "", - "keywords": "actions fuzzy launcher panels search" + "subtext": "" }, { "pageIdx": 6, @@ -1455,8 +1381,7 @@ "title": "Schemes", "anchor": "launcher-schemes", "section": "Fuzzy search", - "subtext": "", - "keywords": "fuzzy launcher panels schemes search" + "subtext": "" }, { "pageIdx": 6, @@ -1474,8 +1399,7 @@ "title": "Variants", "anchor": "launcher-variants", "section": "Fuzzy search", - "subtext": "", - "keywords": "fuzzy launcher panels search variants" + "subtext": "" }, { "pageIdx": 6, @@ -1493,8 +1417,7 @@ "title": "Wallpapers", "anchor": "launcher-wallpapers", "section": "Fuzzy search", - "subtext": "", - "keywords": "fuzzy launcher panels search wallpapers" + "subtext": "" }, { "pageIdx": 6, @@ -1512,8 +1435,7 @@ "title": "Enabled", "anchor": "sidebar-enabled", "section": "General", - "subtext": "", - "keywords": "enabled general panels sidebar" + "subtext": "" }, { "pageIdx": 6, @@ -1531,8 +1453,7 @@ "title": "Drag threshold", "anchor": "sidebar-drag-threshold", "section": "General", - "subtext": "Pixels dragged before the sidebar opens", - "keywords": "before drag dragged general opens panels pixels sidebar threshold" + "subtext": "Pixels dragged before the sidebar opens" }, { "pageIdx": 7, @@ -1546,8 +1467,7 @@ "title": "All apps", "anchor": "apps-all-apps", "section": "Library", - "subtext": "", - "keywords": "all apps library" + "subtext": "" }, { "pageIdx": 8, @@ -1561,8 +1481,7 @@ "title": "Notifications", "anchor": "services-notifications", "section": "Notifications", - "subtext": "", - "keywords": "notifications services" + "subtext": "" }, { "pageIdx": 8, @@ -1576,8 +1495,7 @@ "title": "Media refresh", "anchor": "services-media-refresh", "section": "Polling", - "subtext": "How often the media position updates (ms)", - "keywords": "how media ms often polling position refresh services updates" + "subtext": "How often the media position updates (ms)" }, { "pageIdx": 8, @@ -1591,8 +1509,7 @@ "title": "System stats refresh", "anchor": "services-system-stats-refresh", "section": "Polling", - "subtext": "CPU, memory and GPU update interval (seconds)", - "keywords": "cpu gpu interval memory polling refresh seconds services stats system update" + "subtext": "CPU, memory and GPU update interval (seconds)" }, { "pageIdx": 8, @@ -1606,8 +1523,7 @@ "title": "Wi-Fi rescan", "anchor": "services-wi-fi-rescan", "section": "Polling", - "subtext": "How often available networks are rescanned (seconds)", - "keywords": "are available fi how networks often polling rescan rescanned seconds services wi wifi" + "subtext": "How often available networks are rescanned (seconds)" }, { "pageIdx": 8, @@ -1621,8 +1537,7 @@ "title": "Lyrics backend", "anchor": "services-lyrics-backend", "section": "Media & lyrics", - "subtext": "Source used to fetch synced lyrics", - "keywords": "backend fetch lyrics media services source synced used" + "subtext": "Source used to fetch synced lyrics" }, { "pageIdx": 8, @@ -1636,8 +1551,7 @@ "title": "Default player", "anchor": "services-default-player", "section": "Media & lyrics", - "subtext": "Preferred media player when several are open", - "keywords": "are default lyrics media open player preferred services several when" + "subtext": "Preferred media player when several are open" }, { "pageIdx": 8, @@ -1651,8 +1565,7 @@ "title": "Volume step", "anchor": "services-volume-step", "section": "Input increments", - "subtext": "Amount the volume changes per scroll (%)", - "keywords": "amount changes increments input per scroll services step volume" + "subtext": "Amount the volume changes per scroll (%)" }, { "pageIdx": 8, @@ -1666,8 +1579,7 @@ "title": "Brightness step", "anchor": "services-brightness-step", "section": "Input increments", - "subtext": "Amount the brightness changes per scroll (%)", - "keywords": "amount brightness changes increments input per scroll services step" + "subtext": "Amount the brightness changes per scroll (%)" }, { "pageIdx": 8, @@ -1681,8 +1593,7 @@ "title": "Max volume", "anchor": "services-max-volume", "section": "Input increments", - "subtext": "Upper limit for output volume (%)", - "keywords": "increments input limit max output services upper volume" + "subtext": "Upper limit for output volume (%)" }, { "pageIdx": 8, @@ -1696,8 +1607,7 @@ "title": "Visualiser bars", "anchor": "services-visualiser-bars", "section": "Service tuning", - "subtext": "Number of bars in the audio visualisers", - "keywords": "audio bars number service services tuning visualiser visualisers" + "subtext": "Number of bars in the audio visualisers" }, { "pageIdx": 8, @@ -1711,8 +1621,7 @@ "title": "Smart colour scheme", "anchor": "services-smart-colour-scheme", "section": "Service tuning", - "subtext": "Derive theme mode and variant from the wallpaper", - "keywords": "colour derive from mode scheme service services smart theme tuning variant wallpaper" + "subtext": "Derive theme mode and variant from the wallpaper" }, { "pageIdx": 8, @@ -1726,8 +1635,7 @@ "title": "GPU", "anchor": "services-gpu", "section": "Service tuning", - "subtext": "", - "keywords": "gpu service services tuning" + "subtext": "" }, { "pageIdx": 8, @@ -1745,8 +1653,7 @@ "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen", "section": "Notifications", - "subtext": "Whether notifications appear over fullscreen apps", - "keywords": "appear apps fullscreen notifications over services show whether" + "subtext": "Whether notifications appear over fullscreen apps" }, { "pageIdx": 8, @@ -1764,8 +1671,7 @@ "title": "Expire automatically", "anchor": "notif-expire-automatically", "section": "Notifications", - "subtext": "Dismiss notifications after their timeout", - "keywords": "after automatically dismiss expire notifications services their timeout" + "subtext": "Dismiss notifications after their timeout" }, { "pageIdx": 8, @@ -1783,8 +1689,7 @@ "title": "Open expanded", "anchor": "notif-open-expanded", "section": "Notifications", - "subtext": "Show notifications expanded by default", - "keywords": "by default expanded notifications open services show" + "subtext": "Show notifications expanded by default" }, { "pageIdx": 8, @@ -1802,8 +1707,7 @@ "title": "Default timeout", "anchor": "notif-default-timeout", "section": "Notifications", - "subtext": "Time before a notification dismisses (ms)", - "keywords": "before default dismisses ms notification notifications services time timeout" + "subtext": "Time before a notification dismisses (ms)" }, { "pageIdx": 8, @@ -1821,8 +1725,7 @@ "title": "Group preview count", "anchor": "notif-group-preview-count", "section": "Notifications", - "subtext": "Notifications shown per group before collapsing", - "keywords": "before collapsing count group notifications per preview services shown" + "subtext": "Notifications shown per group before collapsing" }, { "pageIdx": 8, @@ -1840,8 +1743,7 @@ "title": "Show in fullscreen", "anchor": "notif-show-in-fullscreen-2", "section": "Toasts", - "subtext": "Whether toasts appear over fullscreen apps", - "keywords": "appear apps fullscreen notifications over services show toasts whether" + "subtext": "Whether toasts appear over fullscreen apps" }, { "pageIdx": 8, @@ -1859,8 +1761,7 @@ "title": "Visible toasts", "anchor": "notif-visible-toasts", "section": "Toasts", - "subtext": "Maximum number of toasts shown at once", - "keywords": "at maximum notifications number once services shown toasts visible" + "subtext": "Maximum number of toasts shown at once" }, { "pageIdx": 8, @@ -1878,8 +1779,7 @@ "title": "Charging changes", "anchor": "notif-charging-changes", "section": "Toast events", - "subtext": "", - "keywords": "changes charging events notifications services toast" + "subtext": "" }, { "pageIdx": 8, @@ -1897,8 +1797,7 @@ "title": "Game mode changes", "anchor": "notif-game-mode-changes", "section": "Toast events", - "subtext": "", - "keywords": "changes events game mode notifications services toast" + "subtext": "" }, { "pageIdx": 8, @@ -1916,8 +1815,7 @@ "title": "Do not disturb changes", "anchor": "notif-do-not-disturb-changes", "section": "Toast events", - "subtext": "", - "keywords": "changes disturb do events not notifications services toast" + "subtext": "" }, { "pageIdx": 8, @@ -1935,8 +1833,7 @@ "title": "Audio output changes", "anchor": "notif-audio-output-changes", "section": "Toast events", - "subtext": "", - "keywords": "audio changes events notifications output services toast" + "subtext": "" }, { "pageIdx": 8, @@ -1954,8 +1851,7 @@ "title": "Audio input changes", "anchor": "notif-audio-input-changes", "section": "Toast events", - "subtext": "", - "keywords": "audio changes events input notifications services toast" + "subtext": "" }, { "pageIdx": 8, @@ -1973,8 +1869,7 @@ "title": "Caps lock changes", "anchor": "notif-caps-lock-changes", "section": "Toast events", - "subtext": "", - "keywords": "caps changes events lock notifications services toast" + "subtext": "" }, { "pageIdx": 8, @@ -1992,8 +1887,7 @@ "title": "Num lock changes", "anchor": "notif-num-lock-changes", "section": "Toast events", - "subtext": "", - "keywords": "changes events lock notifications num services toast" + "subtext": "" }, { "pageIdx": 8, @@ -2011,8 +1905,7 @@ "title": "Keyboard layout changes", "anchor": "notif-keyboard-layout-changes", "section": "Toast events", - "subtext": "", - "keywords": "changes events keyboard layout notifications services toast" + "subtext": "" }, { "pageIdx": 8, @@ -2030,8 +1923,7 @@ "title": "VPN changes", "anchor": "notif-vpn-changes", "section": "Toast events", - "subtext": "", - "keywords": "changes events notifications services toast vpn" + "subtext": "" }, { "pageIdx": 8, @@ -2049,8 +1941,7 @@ "title": "Now playing", "anchor": "notif-now-playing", "section": "Toast events", - "subtext": "", - "keywords": "events notifications now playing services toast" + "subtext": "" }, { "pageIdx": 9, @@ -2064,8 +1955,7 @@ "title": "Temperature", "anchor": "lang-temperature", "section": "Units", - "subtext": "Units for weather temperatures", - "keywords": "language region temperature temperatures units weather" + "subtext": "Units for weather temperatures" }, { "pageIdx": 9, @@ -2079,8 +1969,7 @@ "title": "System temperatures", "anchor": "lang-system-temperatures", "section": "Units", - "subtext": "Units for CPU and GPU temperatures", - "keywords": "cpu gpu language region system temperatures units" + "subtext": "Units for CPU and GPU temperatures" }, { "pageIdx": 9, @@ -2094,8 +1983,7 @@ "title": "Clock format", "anchor": "lang-clock-format", "section": "Time & date", - "subtext": "How times are shown across the shell", - "keywords": "across are clock date format how language region shell shown time times" + "subtext": "How times are shown across the shell" } ], "inverted": { diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 89a639cac..54edf42c6 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -102,7 +102,6 @@ Singleton { readonly property string title: modelData.title readonly property string section: modelData.section ?? "" readonly property string subtext: modelData.subtext ?? "" - readonly property string keywords: modelData.keywords ?? "" readonly property string anchor: modelData.anchor ?? "" } } diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 44a2da61f..3f775acb1 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -23,8 +23,15 @@ import re import sys from collections import defaultdict +from functools import lru_cache from pathlib import Path + +@lru_cache(maxsize=None) +def read_lines(path: Path) -> tuple[str, ...]: + """Read a file's lines, cached so each page file is only read once.""" + return tuple(path.read_text().splitlines()) + ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow)\s*\{') LABEL_RE = re.compile(r'^\s*(?:label|text):\s*qsTr\("([^"]+)"\)') ANCHOR_RE = re.compile(r'^\s*settingAnchor:\s*"([^"]+)"') @@ -119,7 +126,7 @@ def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: if not pf: continue pending_icon = pending_label = None - for ln in pf.read_text().splitlines(): + for ln in read_lines(pf): mi = ICON_RE.match(ln) if mi: pending_icon = mi.group(1) @@ -184,7 +191,7 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] pf = files.get(comp) if not pf: continue - lines = pf.read_text().splitlines() + lines = read_lines(pf) section = "" # text of the most recent SectionHeader i = 0 while i < len(lines): @@ -257,6 +264,10 @@ def main() -> int: nav = build_nav_map(nexus, files) entries = extract_settings(files, nav) inverted, ranking = build_inverted_and_ranking(entries) + # keywords were only needed to build the inverted index; the runtime reads + # the index, not the per-entry keyword blob, so drop it to shrink the JSON. + for e in entries: + e.pop("keywords", None) out.write_text(json.dumps({ "version": 2, "entries": entries, From f5183310dc971178552fcef7d34a54637bdf15a3 Mon Sep 17 00:00:00 2001 From: Mestane Date: Thu, 25 Jun 2026 23:31:40 +0000 Subject: [PATCH 20/57] chore: stop tracking __pycache__ --- .../build-settings-index.cpython-312.pyc | Bin 12655 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 scripts/__pycache__/build-settings-index.cpython-312.pyc diff --git a/scripts/__pycache__/build-settings-index.cpython-312.pyc b/scripts/__pycache__/build-settings-index.cpython-312.pyc deleted file mode 100644 index d6b11ff7712102540f0da6956e7ccc88ee85a603..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12655 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 From 0450d986eacb9af9cb4d324641b380ebd0162901 Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 11:21:29 +0000 Subject: [PATCH 21/57] feat(nexus): use a double-pulse highlight instead of the border chase --- modules/nexus/common/ConnectedRect.qml | 96 +++++++++----------------- 1 file changed, 33 insertions(+), 63 deletions(-) diff --git a/modules/nexus/common/ConnectedRect.qml b/modules/nexus/common/ConnectedRect.qml index 9e2051ee1..d9dada004 100644 --- a/modules/nexus/common/ConnectedRect.qml +++ b/modules/nexus/common/ConnectedRect.qml @@ -1,5 +1,4 @@ import QtQuick -import QtQuick.Shapes import Caelestia.Config import qs.components import qs.services @@ -12,13 +11,9 @@ StyledRect { // Identifier used by the settings search to scroll to this row. property string settingAnchor - // Run a chase animation along the row's border, used when the settings - // search jumps to it: a short bright segment races around the outline a - // couple of times and then fades out. Drawn as a dashed stroke (one short - // dash, a long gap) whose dash offset is animated, so the bright part - // follows the rounded corners exactly. + // Briefly flash the row, used when the settings search jumps to it. function flashHighlight(): void { - chase.restart(); + flash.restart(); } color: Colours.tPalette.m3surfaceContainer @@ -27,70 +22,45 @@ StyledRect { bottomLeftRadius: last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall bottomRightRadius: last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall - Shape { - id: border - - // Perimeter of the rounded rect, used to size the dash so exactly one - // bright segment travels around at a time. - readonly property real strokeWidth: 2 - readonly property real radius: root.topLeftRadius - readonly property real perimeter: 2 * (width + height) - 8 * radius + 2 * Math.PI * radius - readonly property real dashLen: Math.max(1, perimeter) - property real offset: 0 + StyledRect { + id: highlight anchors.fill: parent - anchors.margins: strokeWidth / 2 - asynchronous: true - preferredRendererType: Shape.CurveRenderer - opacity: 0 - - ShapePath { - strokeColor: Colours.palette.m3primary - strokeWidth: border.strokeWidth - fillColor: "transparent" - capStyle: ShapePath.RoundCap - strokeStyle: ShapePath.DashLine - // One short visible dash, then a gap as long as the whole border. - dashPattern: [0.18 * border.dashLen / border.strokeWidth, border.dashLen / border.strokeWidth] - dashOffset: border.offset - PathRectangle { - x: 0 - y: 0 - width: border.width - border.strokeWidth - height: border.height - border.strokeWidth - radius: Math.max(0, border.radius - border.strokeWidth / 2) - } - } + radius: parent.radius + topLeftRadius: parent.topLeftRadius + topRightRadius: parent.topRightRadius + bottomLeftRadius: parent.bottomLeftRadius + bottomRightRadius: parent.bottomRightRadius + color: Colours.palette.m3primary + opacity: 0 SequentialAnimation { - id: chase + id: flash - PropertyAction { - target: border + Anim { + target: highlight property: "opacity" - value: 1 + to: 0.2 + duration: Tokens.anim.durations.small } - ParallelAnimation { - NumberAnimation { - target: border - property: "offset" - from: 0 - to: 2 * border.dashLen / border.strokeWidth - duration: Tokens.anim.durations.extraLarge * 2 - easing.type: Easing.InOutQuad - } - SequentialAnimation { - PauseAnimation { - duration: Tokens.anim.durations.large - } - NumberAnimation { - target: border - property: "opacity" - to: 0 - duration: Tokens.anim.durations.large - } - } + Anim { + target: highlight + property: "opacity" + to: 0.08 + duration: Tokens.anim.durations.normal + } + Anim { + target: highlight + property: "opacity" + to: 0.2 + duration: Tokens.anim.durations.small + } + Anim { + target: highlight + property: "opacity" + to: 0 + duration: Tokens.anim.durations.extraLarge } } } From 154e82372705fecb64838f056638d9baa47552e9 Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 11:53:32 +0000 Subject: [PATCH 22/57] feat(nexus): show the section header in sub-page result breadcrumbs --- assets/settings-index.json | 150 +++++++++++++++++++++++++++++++- scripts/build-settings-index.py | 41 ++++++--- 2 files changed, 177 insertions(+), 14 deletions(-) diff --git a/assets/settings-index.json b/assets/settings-index.json index 1a623465f..eaa8dfe22 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -624,11 +624,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Shown", @@ -645,11 +647,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Active indicator", @@ -666,11 +670,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Active trail", @@ -687,11 +693,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Occupied background", @@ -708,11 +716,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Show windows", @@ -729,11 +739,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Windows on special workspaces", @@ -750,11 +762,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Max window icons", @@ -771,11 +785,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "workspaces", "workspaces" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Workspaces" ], "title": "Per-monitor workspaces", @@ -792,11 +808,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "web_asset", "web_asset" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Active window" ], "title": "Compact", @@ -813,11 +831,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "web_asset", "web_asset" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Active window" ], "title": "Inverted", @@ -834,11 +854,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "web_asset", "web_asset" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Active window" ], "title": "Show on hover", @@ -855,11 +877,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "web_asset", "web_asset" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Active window" ], "title": "Popout on hover", @@ -876,11 +900,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "widgets", "widgets" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Tray" ], "title": "Background", @@ -897,11 +923,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "widgets", "widgets" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Tray" ], "title": "Recolour icons", @@ -918,11 +946,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "widgets", "widgets" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Tray" ], "title": "Compact", @@ -939,11 +969,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "widgets", "widgets" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Tray" ], "title": "Popout on hover", @@ -960,11 +992,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Speakers", @@ -981,11 +1015,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Microphone", @@ -1002,11 +1038,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Keyboard layout", @@ -1023,11 +1061,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Network", @@ -1044,11 +1084,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Wi-Fi", @@ -1065,11 +1107,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Bluetooth", @@ -1086,11 +1130,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Battery", @@ -1107,11 +1153,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Caps lock", @@ -1128,11 +1176,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "signal_cellular_alt", "signal_cellular_alt" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Status icons" ], "title": "Popout on hover", @@ -1149,11 +1199,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "schedule", "schedule" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Clock" ], "title": "Background", @@ -1170,11 +1222,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "schedule", "schedule" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Clock" ], "title": "Show date", @@ -1191,11 +1245,13 @@ "crumbIcons": [ "dock_to_bottom", "dock_to_bottom", + "schedule", "schedule" ], "crumbLabels": [ "Panels", "Taskbar", + "Components", "Clock" ], "title": "Show icon", @@ -1644,10 +1700,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Show in fullscreen", @@ -1662,10 +1720,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Expire automatically", @@ -1680,10 +1740,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Open expanded", @@ -1698,10 +1760,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Default timeout", @@ -1716,10 +1780,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Group preview count", @@ -1734,10 +1800,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Show in fullscreen", @@ -1752,10 +1820,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Visible toasts", @@ -1770,10 +1840,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Charging changes", @@ -1788,10 +1860,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Game mode changes", @@ -1806,10 +1880,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Do not disturb changes", @@ -1824,10 +1900,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Audio output changes", @@ -1842,10 +1920,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Audio input changes", @@ -1860,10 +1940,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Caps lock changes", @@ -1878,10 +1960,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Num lock changes", @@ -1896,10 +1980,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Keyboard layout changes", @@ -1914,10 +2000,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "VPN changes", @@ -1932,10 +2020,12 @@ ], "crumbIcons": [ "build", + "notifications", "notifications" ], "crumbLabels": [ "Services", + "Notifications", "Notifications" ], "title": "Now playing", @@ -2496,7 +2586,35 @@ 30, 31, 32, - 33 + 33, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64 ], "active": [ 30, @@ -3715,7 +3833,35 @@ "30": 0.4, "31": 0.4, "32": 0.4, - "33": 0.4 + "33": 0.4, + "37": 0.4, + "38": 0.4, + "39": 0.4, + "40": 0.4, + "41": 0.4, + "42": 0.4, + "43": 0.4, + "44": 0.4, + "45": 0.4, + "46": 0.4, + "47": 0.4, + "48": 0.4, + "49": 0.4, + "50": 0.4, + "51": 0.4, + "52": 0.4, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4 }, "active": { "30": 1.0, diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 3f775acb1..acdb1b96e 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -118,26 +118,37 @@ def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: for i, (icon, label) in enumerate(registry): top_meta[i] = (icon, label) - # parentName -> {childPos: (icon, label)} from openSubPage() + nearby NavRow. - nav_children: dict[str, dict[int, tuple[str, str]]] = {} + # parentName -> {childPos: (icon, label, section)} from openSubPage() + + # nearby NavRow, remembering the section header the NavRow sits under. + nav_children: dict[str, dict[int, tuple[str, str, str]]] = {} for names in comps: for name in names: pf = files.get(name) if not pf: continue pending_icon = pending_label = None + section = "" # text of the most recent SectionHeader + expect_section = False # next label line is that header's text for ln in read_lines(pf): + if SECTION_RE.match(ln): + expect_section = True + continue + ml = LABEL_RE.match(ln) + if ml: + if expect_section: + section = ml.group(1) + expect_section = False + else: + pending_label = ml.group(1) + continue mi = ICON_RE.match(ln) if mi: pending_icon = mi.group(1) - ml = LABEL_RE.match(ln) - if ml: - pending_label = ml.group(1) mo = re.search(r"openSubPage\((\d+)\)", ln) if mo: pos = int(mo.group(1)) nav_children.setdefault(name, {})[pos] = ( - pending_icon or "tune", pending_label or "") + pending_icon or "tune", pending_label or "", section) pending_icon = pending_label = None nav: dict[str, dict] = {} @@ -148,20 +159,26 @@ def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: main_icon, main_label = top_meta.get(top_idx, ("tune", main)) nav[main] = {"pageIdx": top_idx, "subPath": [], "crumbIcons": [main_icon], "crumbLabels": [main_label]} - for pos, (icon, label) in nav_children.get(main, {}).items(): + for pos, (icon, label, section) in nav_children.get(main, {}).items(): if pos >= len(names): continue child = names[pos] + # Insert the section header (e.g. "Components") as a breadcrumb step + # between the parent page and the sub-page, when present. + labels = [main_label] + ([section] if section else []) + [label] + icons = [main_icon] + ([icon] if section else []) + [icon] nav[child] = {"pageIdx": top_idx, "subPath": [pos], - "crumbIcons": [main_icon, icon], - "crumbLabels": [main_label, label]} - for gpos, (gicon, glabel) in nav_children.get(child, {}).items(): + "crumbIcons": icons, + "crumbLabels": labels} + for gpos, (gicon, glabel, gsection) in nav_children.get(child, {}).items(): if gpos >= len(names): continue + glabels = labels + ([gsection] if gsection else []) + [glabel] + gicons = icons + ([gicon] if gsection else []) + [gicon] nav[names[gpos]] = { "pageIdx": top_idx, "subPath": [pos, gpos], - "crumbIcons": [main_icon, icon, gicon], - "crumbLabels": [main_label, label, glabel]} + "crumbIcons": gicons, + "crumbLabels": glabels} return nav From c27b1bf8a6b4d7336038c93969f2cd0e5698fd2a Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 11:53:32 +0000 Subject: [PATCH 23/57] fix(nexus): highlight the setting when jumping to a different sub-page --- modules/nexus/NexusState.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index 56619e77b..43e71599f 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -54,14 +54,17 @@ QtObject { searchAnchor = anchor; return; } - searchAnchor = anchor; if (samePage) { - // Same page, different sub-page: rebuild the sub-page chain live. + // Same page, different sub-page: rebuild the sub-page chain first, + // then set the anchor so the now-current page picks it up. while (subPageIdxStack.length > 0) closeSubPage(); for (let i = 0; i < subPath.length; i++) openSubPage(subPath[i]); + searchAnchor = ""; + searchAnchor = anchor; } else { + searchAnchor = anchor; _pendingSubPath = subPath.slice(); currentPageIdx = pageIdx; } From ff143bf2a6ff875d87a03a66c9d9cf3f163e5a0c Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 12:17:31 +0000 Subject: [PATCH 24/57] feat(nexus): collapse repeated names in result breadcrumbs --- assets/settings-index.json | 34 -------------------------- modules/nexus/navpane/NavLocations.qml | 7 ++++-- scripts/build-settings-index.py | 15 ++++++++++++ 3 files changed, 20 insertions(+), 36 deletions(-) diff --git a/assets/settings-index.json b/assets/settings-index.json index eaa8dfe22..fccd9a082 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -1700,12 +1700,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Show in fullscreen", @@ -1720,12 +1718,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Expire automatically", @@ -1740,12 +1736,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Open expanded", @@ -1760,12 +1754,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Default timeout", @@ -1780,12 +1772,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Group preview count", @@ -1800,12 +1790,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Show in fullscreen", @@ -1820,12 +1808,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Visible toasts", @@ -1840,12 +1826,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Charging changes", @@ -1860,12 +1844,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Game mode changes", @@ -1880,12 +1862,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Do not disturb changes", @@ -1900,12 +1880,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Audio output changes", @@ -1920,12 +1898,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Audio input changes", @@ -1940,12 +1916,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Caps lock changes", @@ -1960,12 +1934,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Num lock changes", @@ -1980,12 +1952,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Keyboard layout changes", @@ -2000,12 +1970,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "VPN changes", @@ -2020,12 +1988,10 @@ ], "crumbIcons": [ "build", - "notifications", "notifications" ], "crumbLabels": [ "Services", - "Notifications", "Notifications" ], "title": "Now playing", diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index c809399f8..dd5bfe2e7 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -229,9 +229,12 @@ VerticalFadeFlickable { StyledText { Layout.fillWidth: true text: { - const crumbs = result.modelData.crumbLabels.join(" \u203a "); + const labels = result.modelData.crumbLabels; const section = result.modelData.section; - return section ? `${crumbs} \u203a ${section}` : crumbs; + // Skip the section if it just repeats the last + // breadcrumb label (e.g. page and section share a name). + const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels; + return parts.join(" \u203a "); } color: Colours.palette.m3onSurfaceVariant font: Tokens.font.label.small diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index acdb1b96e..2eb184567 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -109,6 +109,19 @@ def parse_page_comps(nexus: Path) -> list[list[str]]: return comps +def dedup_crumbs(labels: list[str], icons: list[str]) -> tuple[list[str], list[str]]: + """Drop consecutive duplicate labels (e.g. a section header that repeats the + page name), keeping icons aligned.""" + out_labels: list[str] = [] + out_icons: list[str] = [] + for lbl, ico in zip(labels, icons): + if out_labels and out_labels[-1] == lbl: + continue + out_labels.append(lbl) + out_icons.append(ico) + return out_labels, out_icons + + def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: comps = parse_page_comps(nexus) registry = parse_page_registry(nexus) @@ -167,6 +180,7 @@ def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: # between the parent page and the sub-page, when present. labels = [main_label] + ([section] if section else []) + [label] icons = [main_icon] + ([icon] if section else []) + [icon] + labels, icons = dedup_crumbs(labels, icons) nav[child] = {"pageIdx": top_idx, "subPath": [pos], "crumbIcons": icons, "crumbLabels": labels} @@ -175,6 +189,7 @@ def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: continue glabels = labels + ([gsection] if gsection else []) + [glabel] gicons = icons + ([gicon] if gsection else []) + [gicon] + glabels, gicons = dedup_crumbs(glabels, gicons) nav[names[gpos]] = { "pageIdx": top_idx, "subPath": [pos, gpos], "crumbIcons": gicons, From ce760c9fc3f1b20547e77994d4afc7371e389b7a Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 12:17:31 +0000 Subject: [PATCH 25/57] fix(nexus): rebuild the sub-page chain when jumping within the same page --- modules/nexus/NexusState.qml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index 43e71599f..34ae13e44 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -54,19 +54,19 @@ QtObject { searchAnchor = anchor; return; } - if (samePage) { - // Same page, different sub-page: rebuild the sub-page chain first, - // then set the anchor so the now-current page picks it up. + // Different page, or same page but different sub-page: point at the + // target sub-page chain and load the destination page, which scrolls to + // the anchor once it's ready. + searchAnchor = anchor; + if (!samePage) { + _pendingSubPath = subPath.slice(); + currentPageIdx = pageIdx; + } else { + // Same page: close back to the page root, then open the chain. while (subPageIdxStack.length > 0) closeSubPage(); for (let i = 0; i < subPath.length; i++) openSubPage(subPath[i]); - searchAnchor = ""; - searchAnchor = anchor; - } else { - searchAnchor = anchor; - _pendingSubPath = subPath.slice(); - currentPageIdx = pageIdx; } } From 1dcd0c0c50db976c88c66d133611732787f413c7 Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 16:35:54 +0000 Subject: [PATCH 26/57] feat(nexus): index the ethernet detail page settings --- assets/settings-index.json | 2920 +++++++++-------- .../pages/network/EthernetDetailPage.qml | 7 + scripts/build-settings-index.py | 14 +- 3 files changed, 1495 insertions(+), 1446 deletions(-) diff --git a/assets/settings-index.json b/assets/settings-index.json index fccd9a082..61c73fdc3 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -57,6 +57,132 @@ "section": "", "subtext": "" }, + { + "pageIdx": 1, + "subPath": [ + 1 + ], + "crumbIcons": [ + "wifi", + "wifi" + ], + "crumbLabels": [ + "Network", + "Ethernet" + ], + "title": "Status", + "anchor": "ethernet-status", + "section": "Connection", + "subtext": "" + }, + { + "pageIdx": 1, + "subPath": [ + 1 + ], + "crumbIcons": [ + "wifi", + "wifi" + ], + "crumbLabels": [ + "Network", + "Ethernet" + ], + "title": "Interface", + "anchor": "ethernet-interface", + "section": "Connection", + "subtext": "" + }, + { + "pageIdx": 1, + "subPath": [ + 1 + ], + "crumbIcons": [ + "wifi", + "wifi" + ], + "crumbLabels": [ + "Network", + "Ethernet" + ], + "title": "Speed", + "anchor": "ethernet-speed", + "section": "Connection", + "subtext": "" + }, + { + "pageIdx": 1, + "subPath": [ + 1 + ], + "crumbIcons": [ + "wifi", + "wifi" + ], + "crumbLabels": [ + "Network", + "Ethernet" + ], + "title": "IP address", + "anchor": "ethernet-ip-address", + "section": "Connection", + "subtext": "" + }, + { + "pageIdx": 1, + "subPath": [ + 1 + ], + "crumbIcons": [ + "wifi", + "wifi" + ], + "crumbLabels": [ + "Network", + "Ethernet" + ], + "title": "Gateway", + "anchor": "ethernet-gateway", + "section": "Connection", + "subtext": "" + }, + { + "pageIdx": 1, + "subPath": [ + 1 + ], + "crumbIcons": [ + "wifi", + "wifi" + ], + "crumbLabels": [ + "Network", + "Ethernet" + ], + "title": "MAC address", + "anchor": "ethernet-mac-address", + "section": "Connection", + "subtext": "" + }, + { + "pageIdx": 1, + "subPath": [ + 1 + ], + "crumbIcons": [ + "wifi", + "wifi" + ], + "crumbLabels": [ + "Network", + "Ethernet" + ], + "title": "IP assignment", + "anchor": "ethernet-ip-assignment", + "section": "IPv4", + "subtext": "" + }, { "pageIdx": 2, "subPath": [], @@ -618,20 +744,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Shown", "anchor": "bar-ws-shown", @@ -641,20 +762,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Active indicator", "anchor": "bar-ws-active-indicator", @@ -664,20 +780,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Active trail", "anchor": "bar-ws-active-trail", @@ -687,20 +798,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Occupied background", "anchor": "bar-ws-occupied-background", @@ -710,20 +816,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Show windows", "anchor": "bar-ws-show-windows", @@ -733,20 +834,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Windows on special workspaces", "anchor": "bar-ws-windows-on-special-workspaces", @@ -756,20 +852,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Max window icons", "anchor": "bar-ws-max-window-icons", @@ -779,20 +870,15 @@ { "pageIdx": 6, "subPath": [ - 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Workspaces" + "Bar Workspaces" ], "title": "Per-monitor workspaces", "anchor": "bar-ws-per-monitor-workspaces", @@ -802,20 +888,15 @@ { "pageIdx": 6, "subPath": [ - 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Active window" + "Bar Active Window" ], "title": "Compact", "anchor": "bar-aw-compact", @@ -825,20 +906,15 @@ { "pageIdx": 6, "subPath": [ - 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Active window" + "Bar Active Window" ], "title": "Inverted", "anchor": "bar-aw-inverted", @@ -848,20 +924,15 @@ { "pageIdx": 6, "subPath": [ - 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Active window" + "Bar Active Window" ], "title": "Show on hover", "anchor": "bar-aw-show-on-hover", @@ -871,20 +942,15 @@ { "pageIdx": 6, "subPath": [ - 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Active window" + "Bar Active Window" ], "title": "Popout on hover", "anchor": "bar-aw-popout-on-hover", @@ -894,20 +960,15 @@ { "pageIdx": 6, "subPath": [ - 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Tray" + "Bar Tray" ], "title": "Background", "anchor": "bar-tray-background", @@ -917,20 +978,15 @@ { "pageIdx": 6, "subPath": [ - 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Tray" + "Bar Tray" ], "title": "Recolour icons", "anchor": "bar-tray-recolour-icons", @@ -940,20 +996,15 @@ { "pageIdx": 6, "subPath": [ - 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Tray" + "Bar Tray" ], "title": "Compact", "anchor": "bar-tray-compact", @@ -963,20 +1014,15 @@ { "pageIdx": 6, "subPath": [ - 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Tray" + "Bar Tray" ], "title": "Popout on hover", "anchor": "bar-tray-popout-on-hover", @@ -986,20 +1032,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Speakers", "anchor": "bar-si-speakers", @@ -1009,20 +1050,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Microphone", "anchor": "bar-si-microphone", @@ -1032,20 +1068,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Keyboard layout", "anchor": "bar-si-keyboard-layout", @@ -1055,20 +1086,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Network", "anchor": "bar-si-network", @@ -1078,20 +1104,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Wi-Fi", "anchor": "bar-si-wi-fi", @@ -1101,20 +1122,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Bluetooth", "anchor": "bar-si-bluetooth", @@ -1124,20 +1140,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Battery", "anchor": "bar-si-battery", @@ -1147,20 +1158,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Caps lock", "anchor": "bar-si-caps-lock", @@ -1170,20 +1176,15 @@ { "pageIdx": 6, "subPath": [ - 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Status icons" + "Bar Status Icons" ], "title": "Popout on hover", "anchor": "bar-si-popout-on-hover", @@ -1193,20 +1194,15 @@ { "pageIdx": 6, "subPath": [ - 2, 9 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "schedule", - "schedule" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Clock" + "Bar Clock" ], "title": "Background", "anchor": "bar-clock-background", @@ -1216,20 +1212,15 @@ { "pageIdx": 6, "subPath": [ - 2, 9 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "schedule", - "schedule" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Clock" + "Bar Clock" ], "title": "Show date", "anchor": "bar-clock-show-date", @@ -1239,20 +1230,15 @@ { "pageIdx": 6, "subPath": [ - 2, 9 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom", - "schedule", - "schedule" + "dock_to_bottom" ], "crumbLabels": [ "Panels", - "Taskbar", - "Components", - "Clock" + "Bar Clock" ], "title": "Show icon", "anchor": "bar-clock-show-icon", @@ -2045,15 +2031,15 @@ "inverted": { "display": [ 0, - 67, - 68, - 69 + 74, + 75, + 76 ], "wallpaper": [ 0, 1, 2, - 90 + 97 ], "style": [ 0, @@ -2080,118 +2066,174 @@ ], "theme": [ 2, - 90 + 97 ], "wi": [ 3, - 57, - 83 + 64, + 90 ], "fi": [ 3, - 57, - 83 + 64, + 90 ], "wifi": [ 3, - 57, - 83 + 64, + 90 ], "network": [ - 24, - 56, - 3 + 31, + 63, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 ], - "bluetooth": [ + "status": [ 4, - 58 + 39, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68 ], - "connected": [ + "connection": [ 4, 5, - 6 + 6, + 7, + 8, + 9 ], - "devices": [ + "ethernet": [ 4, 5, + 6, + 7, + 8, + 9, + 10 + ], + "interface": [ + 5 + ], + "speed": [ 6 ], + "ip": [ + 7, + 10 + ], + "address": [ + 7, + 9 + ], + "gateway": [ + 8 + ], + "mac": [ + 9 + ], + "assignment": [ + 10 + ], + "ipv4": [ + 10 + ], + "bluetooth": [ + 11, + 65 + ], + "connected": [ + 11, + 12, + 13 + ], + "devices": [ + 11, + 12, + 13 + ], "discoverable": [ - 5 + 12 ], "allow": [ - 5, - 6, - 71 + 12, + 13, + 78 ], "find": [ - 5 + 12 ], "nearby": [ - 5, - 6 + 12, + 13 ], "one": [ - 5, - 6 + 12, + 13 ], "this": [ - 5, - 6 + 12, + 13 ], "pairable": [ - 6 + 13 ], "pair": [ - 6 + 13 ], "with": [ - 6, - 70 + 13, + 77 ], "output": [ - 7, - 102, - 88 + 14, + 109, + 95 ], "audio": [ - 102, - 103, - 7, - 8, - 89 + 109, + 110, + 14, + 15, + 96 ], "input": [ - 8, - 103, - 86, - 87, - 88 + 15, + 110, + 93, + 94, + 95 ], "dashboard": [ - 9, - 15, - 13, - 14, 16, - 17, - 18, - 19, + 22, 20, 21, - 22, 23, 24, - 25 + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32 ], "panels": [ - 9, - 10, - 11, - 12, - 13, - 14, - 15, 16, 17, 18, @@ -2254,17 +2296,17 @@ 75, 76, 77, - 78 + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85 ], "taskbar": [ - 10, - 26, - 27, - 28, - 29, - 30, - 31, - 32, + 17, 33, 34, 35, @@ -2275,289 +2317,220 @@ 40, 41, 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64 + 43 ], "launcher": [ - 11, - 65, - 66, - 67, - 68, - 69, - 70, - 71, + 18, 72, 73, 74, 75, - 76 + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83 ], "sidebar": [ - 12, - 77, - 78 + 19, + 84, + 85 ], "enabled": [ - 13, - 65, - 77 + 20, + 72, + 84 ], "general": [ - 13, - 14, - 65, - 66, - 77, - 78 + 20, + 21, + 72, + 73, + 84, + 85 ], "show": [ - 14, - 27, - 41, - 47, - 63, - 64, - 66, - 92, - 97, - 40, - 44, - 46, + 21, + 34, 48, + 54, + 70, + 71, + 73, + 99, + 104, + 47, 51, - 52, - 61, - 94 + 53, + 55, + 58, + 59, + 68, + 101 ], "hover": [ - 14, - 27, - 47, - 48, - 52, - 61, - 66 + 21, + 34, + 54, + 55, + 59, + 68, + 73 ], "cursor": [ - 14, - 27, - 66 + 21, + 34, + 73 ], "edge": [ - 14, - 27, - 66 + 21, + 34, + 73 ], "reaches": [ - 14, - 27, - 66 + 21, + 34, + 73 ], "reveal": [ - 14, - 27, - 66 + 21, + 34, + 73 ], "screen": [ - 14, - 27, - 66 + 21, + 34, + 73 ], "when": [ - 14, - 27, - 48, - 51, - 52, - 61, - 66, - 85 + 21, + 34, + 55, + 58, + 59, + 68, + 73, + 92 ], "tabs": [ - 15, - 16, - 17, - 18 + 22, + 23, + 24, + 25 ], "media": [ - 16, - 81, - 84, - 85 + 23, + 88, + 91, + 92 ], "performance": [ - 17, - 19, - 20, - 21, - 22, - 23, - 24 + 24, + 26, + 27, + 28, + 29, + 30, + 31 ], "weather": [ - 18, - 109 + 25, + 116 ], "battery": [ - 19, - 59 + 26, + 66 ], "widgets": [ - 19, - 20, - 21, - 22, - 23, - 24 + 26, + 27, + 28, + 29, + 30, + 31 ], "gpu": [ - 20, - 91, - 82, - 110 + 27, + 98, + 89, + 117 ], "cpu": [ - 21, - 82, - 110 + 28, + 89, + 117 ], "memory": [ - 22, - 82 + 29, + 89 ], "storage": [ - 23 + 30 ], "drag": [ - 25, - 28, - 69, - 78 + 32, + 35, + 76, + 85 ], "threshold": [ - 25, - 28, - 69, - 78 + 32, + 35, + 76, + 85 ], "before": [ - 25, - 28, - 69, - 78, - 95, - 96 + 32, + 35, + 76, + 85, + 102, + 103 ], "behaviour": [ - 25, - 26, - 27, - 28, - 61, - 70, - 71 + 32, + 33, + 34, + 35, + 68, + 77, + 78 ], "dragged": [ - 25, - 28, - 69, - 78 + 32, + 35, + 76, + 85 ], "opens": [ - 25, - 69, - 78 + 32, + 76, + 85 ], "pixels": [ - 25, - 28, - 69, - 78 + 32, + 35, + 76, + 85 ], "persistent": [ - 26 + 33 ], "all": [ - 79, - 26 + 86, + 33 ], "at": [ - 26, - 98 + 33, + 105 ], "bar": [ - 26, - 27, - 28, - 35, - 36 - ], - "keep": [ - 26 - ], - "times": [ - 26, - 111 - ], - "visible": [ - 98, - 26, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60 - ], - "reveals": [ - 28 - ], - "workspaces": [ - 29, - 34, - 42, - 44, - 37, - 38, - 39, - 40, - 41, - 43 - ], - "components": [ - 29, - 30, - 31, - 32, 33, - 37, - 38, - 39, - 40, - 41, + 34, + 35, 42, 43, 44, @@ -2580,354 +2553,383 @@ 61, 62, 63, - 64 + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71 ], - "active": [ - 30, - 38, - 39, + "keep": [ + 33 + ], + "times": [ + 33, + 118 + ], + "visible": [ + 105, + 33, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67 + ], + "reveals": [ + 35 + ], + "workspaces": [ + 36, + 41, + 49, + 51, + 44, 45, 46, 47, - 48 + 48, + 50 ], - "window": [ - 30, - 43, + "components": [ + 36, + 37, + 38, + 39, + 40 + ], + "active": [ + 37, 45, 46, - 47, - 48 + 52, + 53, + 54, + 55 ], - "tray": [ - 31, - 49, + "window": [ + 37, 50, - 51, - 52 - ], - "status": [ - 32, + 52, 53, 54, - 55, + 55 + ], + "tray": [ + 38, 56, 57, 58, - 59, - 60, - 61 + 59 ], "icons": [ - 32, - 43, + 39, 50, - 40, - 41, - 53, - 54, - 55, - 56, 57, - 58, - 59, + 47, + 48, 60, - 61 - ], - "clock": [ - 33, - 111, + 61, 62, 63, - 64 + 64, + 65, + 66, + 67, + 68 + ], + "clock": [ + 40, + 118, + 69, + 70, + 71 ], "actions": [ - 71, - 73, - 34, - 35, - 36 + 78, + 80, + 41, + 42, + 43 ], "indicator": [ - 38, - 34 + 45, + 41 ], "over": [ - 34, - 92, - 97 + 41, + 99, + 104 ], "scroll": [ - 34, - 35, - 36, - 86, - 87 + 41, + 42, + 43, + 93, + 94 ], "switch": [ - 34 + 41 ], "workspace": [ - 34, - 40, - 41 + 41, + 47, + 48 ], "volume": [ - 35, - 86, - 88 + 42, + 93, + 95 ], "adjust": [ - 35, - 36 + 42, + 43 ], "half": [ - 35, - 36 + 42, + 43 ], "top": [ - 35 + 42 ], "brightness": [ - 36, - 87 + 43, + 94 ], "bottom": [ - 36 + 43 ], "shown": [ - 37, - 67, - 96, - 98, - 111 + 44, + 74, + 103, + 105, + 118 ], "displayed": [ - 37 + 44 ], "number": [ - 37, - 89, - 98 + 44, + 96, + 105 ], "trail": [ - 39 + 46 ], "occupied": [ - 40 + 47 ], "background": [ - 40, - 49, - 62 + 47, + 56, + 69 ], "each": [ - 40, - 41, - 44 + 47, + 48, + 51 ], "open": [ - 94, - 40, - 41, - 85 + 101, + 47, + 48, + 92 ], "windows": [ - 41, - 42, - 40 + 48, + 49, + 47 ], "special": [ - 42 + 49 ], "max": [ - 43, - 67, - 68, - 88 + 50, + 74, + 75, + 95 ], "per": [ - 44, - 86, - 87, - 96 + 51, + 93, + 94, + 103 ], "monitor": [ - 44 + 51 ], "permonitor": [ - 44 + 51 ], "independently": [ - 44 + 51 ], "monitors": [ - 44 + 51 ], "s": [ - 44 + 51 ], "compact": [ - 45, - 51 + 52, + 58 ], "inverted": [ - 46 + 53 ], "hovering": [ - 46, - 47, - 48, - 51, - 52, - 61 + 53, + 54, + 55, + 58, + 59, + 68 ], "only": [ - 46, - 47 + 53, + 54 ], "title": [ - 46, - 47 + 53, + 54 ], "while": [ - 46, - 47 + 53, + 54 ], "popout": [ - 48, - 52, - 61, - 51 + 55, + 59, + 68, + 58 ], "details": [ - 48, - 61 + 55, + 68 ], "recolour": [ - 50 + 57 ], "menu": [ - 51, - 52 + 58, + 59 ], "speakers": [ - 53 + 60 ], "microphone": [ - 54 + 61 ], "keyboard": [ - 55, - 106 + 62, + 113 ], "layout": [ - 55, - 106 + 62, + 113 ], "caps": [ - 60, - 104 + 67, + 111 ], "lock": [ - 60, - 104, - 105 + 67, + 111, + 112 ], "date": [ - 63, - 111 + 70, + 118 ], "icon": [ - 64 + 71 ], "items": [ - 67 + 74 ], "wallpapers": [ - 68, - 76 + 75, + 83 ], "vim": [ - 70 + 77 ], "keybinds": [ - 70 + 77 ], "ctrl": [ - 70 + 77 ], "ctrlhjkl": [ - 70 + 77 ], "hjkl": [ - 70 + 77 ], "navigate": [ - 70 + 77 ], "results": [ - 70 + 77 ], "enable": [ - 71 + 78 ], "dangerous": [ - 71 + 78 ], "down": [ - 71 + 78 ], "log": [ - 71 + 78 ], "out": [ - 71 + 78 ], "shut": [ - 71 + 78 ], "that": [ - 71 + 78 ], "apps": [ - 72, 79, - 92, - 97 + 86, + 99, + 104 ], "fuzzy": [ - 72, - 73, - 74, - 75, - 76 + 79, + 80, + 81, + 82, + 83 ], "search": [ - 72, - 73, - 74, - 75, - 76 + 79, + 80, + 81, + 82, + 83 ], "schemes": [ - 74 + 81 ], "variants": [ - 75 + 82 ], "library": [ - 79 + 86 ], "notifications": [ - 80, - 92, - 93, - 94, - 95, - 96, - 97, - 98, + 87, 99, 100, 101, @@ -2937,16 +2939,16 @@ 105, 106, 107, - 108 + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115 ], "services": [ - 80, - 81, - 82, - 83, - 84, - 85, - 86, 87, 88, 89, @@ -2968,339 +2970,346 @@ 105, 106, 107, - 108 + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115 ], "refresh": [ - 81, - 82 + 88, + 89 ], "how": [ - 81, - 83, - 111 + 88, + 90, + 118 ], "ms": [ - 81, - 95 + 88, + 102 ], "often": [ - 81, - 83 + 88, + 90 ], "polling": [ - 81, - 82, - 83 + 88, + 89, + 90 ], "position": [ - 81 + 88 ], "updates": [ - 81 + 88 ], "system": [ - 82, - 110 + 89, + 117 ], "stats": [ - 82 + 89 ], "interval": [ - 82 + 89 ], "seconds": [ - 82, - 83 + 89, + 90 ], "update": [ - 82 + 89 ], "rescan": [ - 83 + 90 ], "are": [ - 83, - 85, - 111 + 90, + 92, + 118 ], "available": [ - 83 + 90 ], "networks": [ - 83 + 90 ], "rescanned": [ - 83 + 90 ], "lyrics": [ - 84, - 85 + 91, + 92 ], "backend": [ - 84 + 91 ], "fetch": [ - 84 + 91 ], "source": [ - 84 + 91 ], "synced": [ - 84 + 91 ], "used": [ - 84 + 91 ], "default": [ - 85, - 95, - 94 + 92, + 102, + 101 ], "player": [ - 85 + 92 ], "preferred": [ - 85 + 92 ], "several": [ - 85 + 92 ], "step": [ - 86, - 87 + 93, + 94 ], "amount": [ - 86, - 87 + 93, + 94 ], "changes": [ - 99, - 100, - 101, - 102, - 103, - 104, - 105, 106, 107, - 86, - 87 + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 93, + 94 ], "increments": [ - 86, - 87, - 88 + 93, + 94, + 95 ], "limit": [ - 88 + 95 ], "upper": [ - 88 + 95 ], "visualiser": [ - 89 + 96 ], "bars": [ - 89 + 96 ], "service": [ - 89, - 90, - 91 + 96, + 97, + 98 ], "tuning": [ - 89, - 90, - 91 + 96, + 97, + 98 ], "visualisers": [ - 89 + 96 ], "smart": [ - 90 + 97 ], "colour": [ - 90 + 97 ], "scheme": [ - 90 + 97 ], "derive": [ - 90 + 97 ], "from": [ - 90 + 97 ], "mode": [ - 100, - 90 + 107, + 97 ], "variant": [ - 90 + 97 ], "fullscreen": [ - 92, - 97 + 99, + 104 ], "appear": [ - 92, - 97 + 99, + 104 ], "whether": [ - 92, - 97 + 99, + 104 ], "expire": [ - 93 + 100 ], "automatically": [ - 93 + 100 ], "after": [ - 93 + 100 ], "dismiss": [ - 93 + 100 ], "their": [ - 93 + 100 ], "timeout": [ - 95, - 93 + 102, + 100 ], "expanded": [ - 94 + 101 ], "by": [ - 94 + 101 ], "dismisses": [ - 95 + 102 ], "notification": [ - 95 + 102 ], "time": [ - 95, - 111 + 102, + 118 ], "group": [ - 96 + 103 ], "preview": [ - 96 + 103 ], "count": [ - 96 + 103 ], "collapsing": [ - 96 + 103 ], "toasts": [ - 98, - 97 + 105, + 104 ], "maximum": [ - 98 + 105 ], "once": [ - 98 + 105 ], "charging": [ - 99 + 106 ], "events": [ - 99, - 100, - 101, - 102, - 103, - 104, - 105, 106, 107, - 108 + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115 ], "toast": [ - 99, - 100, - 101, - 102, - 103, - 104, - 105, 106, 107, - 108 + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115 ], "game": [ - 100 + 107 ], "do": [ - 101 + 108 ], "not": [ - 101 + 108 ], "disturb": [ - 101 + 108 ], "num": [ - 105 + 112 ], "vpn": [ - 107 + 114 ], "now": [ - 108 + 115 ], "playing": [ - 108 + 115 ], "temperature": [ - 109 + 116 ], "language": [ - 109, - 110, - 111 + 116, + 117, + 118 ], "region": [ - 109, - 110, - 111 + 116, + 117, + 118 ], "temperatures": [ - 110, - 109 + 117, + 116 ], "units": [ - 109, - 110 + 116, + 117 ], "format": [ - 111 + 118 ], "across": [ - 111 + 118 ], "shell": [ - 111 + 118 ] }, "ranking": { "display": { "0": 1.0, - "67": 0.4, - "68": 0.4, - "69": 0.4 + "74": 0.4, + "75": 0.4, + "76": 0.4 }, "wallpaper": { "0": 1.0, "1": 0.4, "2": 0.4, - "90": 0.4 + "97": 0.4 }, "style": { "0": 0.4, @@ -3327,118 +3336,174 @@ }, "theme": { "2": 1.0, - "90": 0.4 + "97": 0.4 }, "wi": { "3": 1.0, - "57": 1.0, - "83": 1.0 + "64": 1.0, + "90": 1.0 }, "fi": { "3": 1.0, - "57": 1.0, - "83": 1.0 + "64": 1.0, + "90": 1.0 }, "wifi": { "3": 1.0, - "57": 1.0, - "83": 1.0 + "64": 1.0, + "90": 1.0 }, "network": { "3": 0.4, - "24": 1.0, - "56": 1.0 + "4": 0.4, + "5": 0.4, + "6": 0.4, + "7": 0.4, + "8": 0.4, + "9": 0.4, + "10": 0.4, + "31": 1.0, + "63": 1.0 }, - "bluetooth": { + "status": { "4": 1.0, - "58": 1.0 + "39": 1.0, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4 }, - "connected": { + "connection": { "4": 0.4, "5": 0.4, - "6": 0.4 + "6": 0.4, + "7": 0.4, + "8": 0.4, + "9": 0.4 }, - "devices": { + "ethernet": { "4": 0.4, "5": 0.4, - "6": 0.4 + "6": 0.4, + "7": 0.4, + "8": 0.4, + "9": 0.4, + "10": 0.4 }, - "discoverable": { + "interface": { "5": 1.0 }, - "allow": { - "5": 0.4, - "6": 0.4, - "71": 0.4 + "speed": { + "6": 1.0 }, - "find": { - "5": 0.4 + "ip": { + "7": 1.0, + "10": 1.0 + }, + "address": { + "7": 1.0, + "9": 1.0 + }, + "gateway": { + "8": 1.0 + }, + "mac": { + "9": 1.0 + }, + "assignment": { + "10": 1.0 + }, + "ipv4": { + "10": 0.4 + }, + "bluetooth": { + "11": 1.0, + "65": 1.0 + }, + "connected": { + "11": 0.4, + "12": 0.4, + "13": 0.4 + }, + "devices": { + "11": 0.4, + "12": 0.4, + "13": 0.4 + }, + "discoverable": { + "12": 1.0 + }, + "allow": { + "12": 0.4, + "13": 0.4, + "78": 0.4 + }, + "find": { + "12": 0.4 }, "nearby": { - "5": 0.4, - "6": 0.4 + "12": 0.4, + "13": 0.4 }, "one": { - "5": 0.4, - "6": 0.4 + "12": 0.4, + "13": 0.4 }, "this": { - "5": 0.4, - "6": 0.4 + "12": 0.4, + "13": 0.4 }, "pairable": { - "6": 1.0 + "13": 1.0 }, "pair": { - "6": 0.4 + "13": 0.4 }, "with": { - "6": 0.4, - "70": 0.4 + "13": 0.4, + "77": 0.4 }, "output": { - "7": 1.0, - "88": 0.4, - "102": 1.0 + "14": 1.0, + "95": 0.4, + "109": 1.0 }, "audio": { - "7": 0.4, - "8": 0.4, - "89": 0.4, - "102": 1.0, - "103": 1.0 + "14": 0.4, + "15": 0.4, + "96": 0.4, + "109": 1.0, + "110": 1.0 }, "input": { - "8": 1.0, - "86": 0.4, - "87": 0.4, - "88": 0.4, - "103": 1.0 + "15": 1.0, + "93": 0.4, + "94": 0.4, + "95": 0.4, + "110": 1.0 }, "dashboard": { - "9": 1.0, - "13": 0.4, - "14": 0.4, - "15": 1.0, - "16": 0.4, - "17": 0.4, - "18": 0.4, - "19": 0.4, + "16": 1.0, "20": 0.4, "21": 0.4, - "22": 0.4, + "22": 1.0, "23": 0.4, "24": 0.4, - "25": 0.4 + "25": 0.4, + "26": 0.4, + "27": 0.4, + "28": 0.4, + "29": 0.4, + "30": 0.4, + "31": 0.4, + "32": 0.4 }, "panels": { - "9": 0.4, - "10": 0.4, - "11": 0.4, - "12": 0.4, - "13": 0.4, - "14": 0.4, - "15": 0.4, "16": 0.4, "17": 0.4, "18": 0.4, @@ -3501,17 +3566,17 @@ "75": 0.4, "76": 0.4, "77": 0.4, - "78": 0.4 + "78": 0.4, + "79": 0.4, + "80": 0.4, + "81": 0.4, + "82": 0.4, + "83": 0.4, + "84": 0.4, + "85": 0.4 }, "taskbar": { - "10": 1.0, - "26": 0.4, - "27": 0.4, - "28": 0.4, - "29": 0.4, - "30": 0.4, - "31": 0.4, - "32": 0.4, + "17": 1.0, "33": 0.4, "34": 0.4, "35": 0.4, @@ -3522,289 +3587,220 @@ "40": 0.4, "41": 0.4, "42": 0.4, - "43": 0.4, - "44": 0.4, - "45": 0.4, - "46": 0.4, - "47": 0.4, - "48": 0.4, - "49": 0.4, - "50": 0.4, - "51": 0.4, - "52": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4 + "43": 0.4 }, "launcher": { - "11": 1.0, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4, - "69": 0.4, - "70": 0.4, - "71": 0.4, + "18": 1.0, "72": 0.4, "73": 0.4, "74": 0.4, "75": 0.4, - "76": 0.4 + "76": 0.4, + "77": 0.4, + "78": 0.4, + "79": 0.4, + "80": 0.4, + "81": 0.4, + "82": 0.4, + "83": 0.4 }, "sidebar": { - "12": 1.0, - "77": 0.4, - "78": 0.4 + "19": 1.0, + "84": 0.4, + "85": 0.4 }, "enabled": { - "13": 1.0, - "65": 1.0, - "77": 1.0 + "20": 1.0, + "72": 1.0, + "84": 1.0 }, "general": { - "13": 0.4, - "14": 0.4, - "65": 0.4, - "66": 0.4, - "77": 0.4, - "78": 0.4 + "20": 0.4, + "21": 0.4, + "72": 0.4, + "73": 0.4, + "84": 0.4, + "85": 0.4 }, "show": { - "14": 1.0, - "27": 1.0, - "40": 0.4, - "41": 1.0, - "44": 0.4, - "46": 0.4, - "47": 1.0, - "48": 0.4, + "21": 1.0, + "34": 1.0, + "47": 0.4, + "48": 1.0, "51": 0.4, - "52": 0.4, - "61": 0.4, - "63": 1.0, - "64": 1.0, - "66": 1.0, - "92": 1.0, - "94": 0.4, - "97": 1.0 + "53": 0.4, + "54": 1.0, + "55": 0.4, + "58": 0.4, + "59": 0.4, + "68": 0.4, + "70": 1.0, + "71": 1.0, + "73": 1.0, + "99": 1.0, + "101": 0.4, + "104": 1.0 }, "hover": { - "14": 1.0, - "27": 1.0, - "47": 1.0, - "48": 1.0, - "52": 1.0, - "61": 1.0, - "66": 1.0 + "21": 1.0, + "34": 1.0, + "54": 1.0, + "55": 1.0, + "59": 1.0, + "68": 1.0, + "73": 1.0 }, "cursor": { - "14": 0.4, - "27": 0.4, - "66": 0.4 + "21": 0.4, + "34": 0.4, + "73": 0.4 }, "edge": { - "14": 0.4, - "27": 0.4, - "66": 0.4 + "21": 0.4, + "34": 0.4, + "73": 0.4 }, "reaches": { - "14": 0.4, - "27": 0.4, - "66": 0.4 + "21": 0.4, + "34": 0.4, + "73": 0.4 }, "reveal": { - "14": 0.4, - "27": 0.4, - "66": 0.4 + "21": 0.4, + "34": 0.4, + "73": 0.4 }, "screen": { - "14": 0.4, - "27": 0.4, - "66": 0.4 + "21": 0.4, + "34": 0.4, + "73": 0.4 }, "when": { - "14": 0.4, - "27": 0.4, - "48": 0.4, - "51": 0.4, - "52": 0.4, - "61": 0.4, - "66": 0.4, - "85": 0.4 + "21": 0.4, + "34": 0.4, + "55": 0.4, + "58": 0.4, + "59": 0.4, + "68": 0.4, + "73": 0.4, + "92": 0.4 }, "tabs": { - "15": 0.4, - "16": 0.4, - "17": 0.4, - "18": 0.4 + "22": 0.4, + "23": 0.4, + "24": 0.4, + "25": 0.4 }, "media": { - "16": 1.0, - "81": 1.0, - "84": 0.4, - "85": 0.4 + "23": 1.0, + "88": 1.0, + "91": 0.4, + "92": 0.4 }, "performance": { - "17": 1.0, - "19": 0.4, - "20": 0.4, - "21": 0.4, - "22": 0.4, - "23": 0.4, - "24": 0.4 + "24": 1.0, + "26": 0.4, + "27": 0.4, + "28": 0.4, + "29": 0.4, + "30": 0.4, + "31": 0.4 }, "weather": { - "18": 1.0, - "109": 0.4 + "25": 1.0, + "116": 0.4 }, "battery": { - "19": 1.0, - "59": 1.0 + "26": 1.0, + "66": 1.0 }, "widgets": { - "19": 0.4, - "20": 0.4, - "21": 0.4, - "22": 0.4, - "23": 0.4, - "24": 0.4 + "26": 0.4, + "27": 0.4, + "28": 0.4, + "29": 0.4, + "30": 0.4, + "31": 0.4 }, "gpu": { - "20": 1.0, - "82": 0.4, - "91": 1.0, - "110": 0.4 + "27": 1.0, + "89": 0.4, + "98": 1.0, + "117": 0.4 }, "cpu": { - "21": 1.0, - "82": 0.4, - "110": 0.4 + "28": 1.0, + "89": 0.4, + "117": 0.4 }, "memory": { - "22": 1.0, - "82": 0.4 + "29": 1.0, + "89": 0.4 }, "storage": { - "23": 1.0 + "30": 1.0 }, "drag": { - "25": 1.0, - "28": 1.0, - "69": 1.0, - "78": 1.0 + "32": 1.0, + "35": 1.0, + "76": 1.0, + "85": 1.0 }, "threshold": { - "25": 1.0, - "28": 1.0, - "69": 1.0, - "78": 1.0 + "32": 1.0, + "35": 1.0, + "76": 1.0, + "85": 1.0 }, "before": { - "25": 0.4, - "28": 0.4, - "69": 0.4, - "78": 0.4, - "95": 0.4, - "96": 0.4 + "32": 0.4, + "35": 0.4, + "76": 0.4, + "85": 0.4, + "102": 0.4, + "103": 0.4 }, "behaviour": { - "25": 0.4, - "26": 0.4, - "27": 0.4, - "28": 0.4, - "61": 0.4, - "70": 0.4, - "71": 0.4 + "32": 0.4, + "33": 0.4, + "34": 0.4, + "35": 0.4, + "68": 0.4, + "77": 0.4, + "78": 0.4 }, "dragged": { - "25": 0.4, - "28": 0.4, - "69": 0.4, - "78": 0.4 + "32": 0.4, + "35": 0.4, + "76": 0.4, + "85": 0.4 }, "opens": { - "25": 0.4, - "69": 0.4, - "78": 0.4 + "32": 0.4, + "76": 0.4, + "85": 0.4 }, "pixels": { - "25": 0.4, - "28": 0.4, - "69": 0.4, - "78": 0.4 - }, - "persistent": { - "26": 1.0 - }, - "all": { - "26": 0.4, - "79": 1.0 - }, - "at": { - "26": 0.4, - "98": 0.4 - }, - "bar": { - "26": 0.4, - "27": 0.4, - "28": 0.4, + "32": 0.4, "35": 0.4, - "36": 0.4 - }, - "keep": { - "26": 0.4 - }, - "times": { - "26": 0.4, - "111": 0.4 - }, - "visible": { - "26": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4, - "60": 0.4, - "98": 1.0 + "76": 0.4, + "85": 0.4 }, - "reveals": { - "28": 0.4 + "persistent": { + "33": 1.0 }, - "workspaces": { - "29": 1.0, - "34": 1.0, - "37": 0.4, - "38": 0.4, - "39": 0.4, - "40": 0.4, - "41": 0.4, - "42": 1.0, - "43": 0.4, - "44": 1.0 + "all": { + "33": 0.4, + "86": 1.0 }, - "components": { - "29": 0.4, - "30": 0.4, - "31": 0.4, - "32": 0.4, + "at": { "33": 0.4, - "37": 0.4, - "38": 0.4, - "39": 0.4, - "40": 0.4, - "41": 0.4, + "105": 0.4 + }, + "bar": { + "33": 0.4, + "34": 0.4, + "35": 0.4, "42": 0.4, "43": 0.4, "44": 0.4, @@ -3827,354 +3823,383 @@ "61": 0.4, "62": 0.4, "63": 0.4, - "64": 0.4 + "64": 0.4, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4, + "69": 0.4, + "70": 0.4, + "71": 0.4 }, - "active": { - "30": 1.0, - "38": 1.0, - "39": 1.0, - "45": 0.4, - "46": 0.4, - "47": 0.4, - "48": 0.4 + "keep": { + "33": 0.4 }, - "window": { - "30": 1.0, - "43": 1.0, + "times": { + "33": 0.4, + "118": 0.4 + }, + "visible": { + "33": 0.4, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "105": 1.0 + }, + "reveals": { + "35": 0.4 + }, + "workspaces": { + "36": 1.0, + "41": 1.0, + "44": 0.4, "45": 0.4, "46": 0.4, "47": 0.4, - "48": 0.4 - }, - "tray": { - "31": 1.0, - "49": 0.4, + "48": 0.4, + "49": 1.0, "50": 0.4, - "51": 0.4, - "52": 0.4 + "51": 1.0 }, - "status": { - "32": 1.0, + "components": { + "36": 0.4, + "37": 0.4, + "38": 0.4, + "39": 0.4, + "40": 0.4 + }, + "active": { + "37": 1.0, + "45": 1.0, + "46": 1.0, + "52": 0.4, "53": 0.4, "54": 0.4, - "55": 0.4, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4, - "60": 0.4, - "61": 0.4 + "55": 0.4 }, - "icons": { - "32": 1.0, - "40": 0.4, - "41": 0.4, - "43": 1.0, + "window": { + "37": 1.0, "50": 1.0, + "52": 0.4, "53": 0.4, "54": 0.4, - "55": 0.4, + "55": 0.4 + }, + "tray": { + "38": 1.0, "56": 0.4, "57": 0.4, "58": 0.4, - "59": 0.4, - "60": 0.4, - "61": 0.4 + "59": 0.4 }, - "clock": { - "33": 1.0, + "icons": { + "39": 1.0, + "47": 0.4, + "48": 0.4, + "50": 1.0, + "57": 1.0, + "60": 0.4, + "61": 0.4, "62": 0.4, "63": 0.4, "64": 0.4, - "111": 1.0 + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4 + }, + "clock": { + "40": 1.0, + "69": 0.4, + "70": 0.4, + "71": 0.4, + "118": 1.0 }, "actions": { - "34": 0.4, - "35": 0.4, - "36": 0.4, - "71": 1.0, - "73": 1.0 + "41": 0.4, + "42": 0.4, + "43": 0.4, + "78": 1.0, + "80": 1.0 }, "indicator": { - "34": 0.4, - "38": 1.0 + "41": 0.4, + "45": 1.0 }, "over": { - "34": 0.4, - "92": 0.4, - "97": 0.4 + "41": 0.4, + "99": 0.4, + "104": 0.4 }, "scroll": { - "34": 0.4, - "35": 0.4, - "36": 0.4, - "86": 0.4, - "87": 0.4 + "41": 0.4, + "42": 0.4, + "43": 0.4, + "93": 0.4, + "94": 0.4 }, "switch": { - "34": 0.4 + "41": 0.4 }, "workspace": { - "34": 0.4, - "40": 0.4, - "41": 0.4 + "41": 0.4, + "47": 0.4, + "48": 0.4 }, "volume": { - "35": 1.0, - "86": 1.0, - "88": 1.0 + "42": 1.0, + "93": 1.0, + "95": 1.0 }, "adjust": { - "35": 0.4, - "36": 0.4 + "42": 0.4, + "43": 0.4 }, "half": { - "35": 0.4, - "36": 0.4 + "42": 0.4, + "43": 0.4 }, "top": { - "35": 0.4 + "42": 0.4 }, "brightness": { - "36": 1.0, - "87": 1.0 + "43": 1.0, + "94": 1.0 }, "bottom": { - "36": 0.4 + "43": 0.4 }, "shown": { - "37": 1.0, - "67": 1.0, - "96": 0.4, - "98": 0.4, - "111": 0.4 + "44": 1.0, + "74": 1.0, + "103": 0.4, + "105": 0.4, + "118": 0.4 }, "displayed": { - "37": 0.4 + "44": 0.4 }, "number": { - "37": 0.4, - "89": 0.4, - "98": 0.4 + "44": 0.4, + "96": 0.4, + "105": 0.4 }, "trail": { - "39": 1.0 + "46": 1.0 }, "occupied": { - "40": 1.0 + "47": 1.0 }, "background": { - "40": 1.0, - "49": 1.0, - "62": 1.0 + "47": 1.0, + "56": 1.0, + "69": 1.0 }, "each": { - "40": 0.4, - "41": 0.4, - "44": 0.4 + "47": 0.4, + "48": 0.4, + "51": 0.4 }, "open": { - "40": 0.4, - "41": 0.4, - "85": 0.4, - "94": 1.0 + "47": 0.4, + "48": 0.4, + "92": 0.4, + "101": 1.0 }, "windows": { - "40": 0.4, - "41": 1.0, - "42": 1.0 + "47": 0.4, + "48": 1.0, + "49": 1.0 }, "special": { - "42": 1.0 + "49": 1.0 }, "max": { - "43": 1.0, - "67": 1.0, - "68": 1.0, - "88": 1.0 + "50": 1.0, + "74": 1.0, + "75": 1.0, + "95": 1.0 }, "per": { - "44": 1.0, - "86": 0.4, - "87": 0.4, - "96": 0.4 + "51": 1.0, + "93": 0.4, + "94": 0.4, + "103": 0.4 }, "monitor": { - "44": 1.0 + "51": 1.0 }, "permonitor": { - "44": 1.0 + "51": 1.0 }, "independently": { - "44": 0.4 + "51": 0.4 }, "monitors": { - "44": 0.4 + "51": 0.4 }, "s": { - "44": 0.4 + "51": 0.4 }, "compact": { - "45": 1.0, - "51": 1.0 + "52": 1.0, + "58": 1.0 }, "inverted": { - "46": 1.0 + "53": 1.0 }, "hovering": { - "46": 0.4, - "47": 0.4, - "48": 0.4, - "51": 0.4, - "52": 0.4, - "61": 0.4 + "53": 0.4, + "54": 0.4, + "55": 0.4, + "58": 0.4, + "59": 0.4, + "68": 0.4 }, "only": { - "46": 0.4, - "47": 0.4 + "53": 0.4, + "54": 0.4 }, "title": { - "46": 0.4, - "47": 0.4 + "53": 0.4, + "54": 0.4 }, "while": { - "46": 0.4, - "47": 0.4 + "53": 0.4, + "54": 0.4 }, "popout": { - "48": 1.0, - "51": 0.4, - "52": 1.0, - "61": 1.0 + "55": 1.0, + "58": 0.4, + "59": 1.0, + "68": 1.0 }, "details": { - "48": 0.4, - "61": 0.4 + "55": 0.4, + "68": 0.4 }, "recolour": { - "50": 1.0 + "57": 1.0 }, "menu": { - "51": 0.4, - "52": 0.4 + "58": 0.4, + "59": 0.4 }, "speakers": { - "53": 1.0 + "60": 1.0 }, "microphone": { - "54": 1.0 + "61": 1.0 }, "keyboard": { - "55": 1.0, - "106": 1.0 + "62": 1.0, + "113": 1.0 }, "layout": { - "55": 1.0, - "106": 1.0 + "62": 1.0, + "113": 1.0 }, "caps": { - "60": 1.0, - "104": 1.0 + "67": 1.0, + "111": 1.0 }, "lock": { - "60": 1.0, - "104": 1.0, - "105": 1.0 + "67": 1.0, + "111": 1.0, + "112": 1.0 }, "date": { - "63": 1.0, - "111": 0.4 + "70": 1.0, + "118": 0.4 }, "icon": { - "64": 1.0 + "71": 1.0 }, "items": { - "67": 1.0 + "74": 1.0 }, "wallpapers": { - "68": 1.0, - "76": 1.0 + "75": 1.0, + "83": 1.0 }, "vim": { - "70": 1.0 + "77": 1.0 }, "keybinds": { - "70": 1.0 + "77": 1.0 }, "ctrl": { - "70": 0.4 + "77": 0.4 }, "ctrlhjkl": { - "70": 0.4 + "77": 0.4 }, "hjkl": { - "70": 0.4 + "77": 0.4 }, "navigate": { - "70": 0.4 + "77": 0.4 }, "results": { - "70": 0.4 + "77": 0.4 }, "enable": { - "71": 1.0 + "78": 1.0 }, "dangerous": { - "71": 1.0 + "78": 1.0 }, "down": { - "71": 0.4 + "78": 0.4 }, "log": { - "71": 0.4 + "78": 0.4 }, "out": { - "71": 0.4 + "78": 0.4 }, "shut": { - "71": 0.4 + "78": 0.4 }, "that": { - "71": 0.4 + "78": 0.4 }, "apps": { - "72": 1.0, "79": 1.0, - "92": 0.4, - "97": 0.4 + "86": 1.0, + "99": 0.4, + "104": 0.4 }, "fuzzy": { - "72": 0.4, - "73": 0.4, - "74": 0.4, - "75": 0.4, - "76": 0.4 + "79": 0.4, + "80": 0.4, + "81": 0.4, + "82": 0.4, + "83": 0.4 }, "search": { - "72": 0.4, - "73": 0.4, - "74": 0.4, - "75": 0.4, - "76": 0.4 + "79": 0.4, + "80": 0.4, + "81": 0.4, + "82": 0.4, + "83": 0.4 }, "schemes": { - "74": 1.0 + "81": 1.0 }, "variants": { - "75": 1.0 + "82": 1.0 }, "library": { - "79": 0.4 + "86": 0.4 }, "notifications": { - "80": 1.0, - "92": 0.4, - "93": 0.4, - "94": 0.4, - "95": 0.4, - "96": 0.4, - "97": 0.4, - "98": 0.4, + "87": 1.0, "99": 0.4, "100": 0.4, "101": 0.4, @@ -4184,16 +4209,16 @@ "105": 0.4, "106": 0.4, "107": 0.4, - "108": 0.4 + "108": 0.4, + "109": 0.4, + "110": 0.4, + "111": 0.4, + "112": 0.4, + "113": 0.4, + "114": 0.4, + "115": 0.4 }, "services": { - "80": 0.4, - "81": 0.4, - "82": 0.4, - "83": 0.4, - "84": 0.4, - "85": 0.4, - "86": 0.4, "87": 0.4, "88": 0.4, "89": 0.4, @@ -4215,325 +4240,332 @@ "105": 0.4, "106": 0.4, "107": 0.4, - "108": 0.4 + "108": 0.4, + "109": 0.4, + "110": 0.4, + "111": 0.4, + "112": 0.4, + "113": 0.4, + "114": 0.4, + "115": 0.4 }, "refresh": { - "81": 1.0, - "82": 1.0 + "88": 1.0, + "89": 1.0 }, "how": { - "81": 0.4, - "83": 0.4, - "111": 0.4 + "88": 0.4, + "90": 0.4, + "118": 0.4 }, "ms": { - "81": 0.4, - "95": 0.4 + "88": 0.4, + "102": 0.4 }, "often": { - "81": 0.4, - "83": 0.4 + "88": 0.4, + "90": 0.4 }, "polling": { - "81": 0.4, - "82": 0.4, - "83": 0.4 + "88": 0.4, + "89": 0.4, + "90": 0.4 }, "position": { - "81": 0.4 + "88": 0.4 }, "updates": { - "81": 0.4 + "88": 0.4 }, "system": { - "82": 1.0, - "110": 1.0 + "89": 1.0, + "117": 1.0 }, "stats": { - "82": 1.0 + "89": 1.0 }, "interval": { - "82": 0.4 + "89": 0.4 }, "seconds": { - "82": 0.4, - "83": 0.4 + "89": 0.4, + "90": 0.4 }, "update": { - "82": 0.4 + "89": 0.4 }, "rescan": { - "83": 1.0 + "90": 1.0 }, "are": { - "83": 0.4, - "85": 0.4, - "111": 0.4 + "90": 0.4, + "92": 0.4, + "118": 0.4 }, "available": { - "83": 0.4 + "90": 0.4 }, "networks": { - "83": 0.4 + "90": 0.4 }, "rescanned": { - "83": 0.4 + "90": 0.4 }, "lyrics": { - "84": 1.0, - "85": 0.4 + "91": 1.0, + "92": 0.4 }, "backend": { - "84": 1.0 + "91": 1.0 }, "fetch": { - "84": 0.4 + "91": 0.4 }, "source": { - "84": 0.4 + "91": 0.4 }, "synced": { - "84": 0.4 + "91": 0.4 }, "used": { - "84": 0.4 + "91": 0.4 }, "default": { - "85": 1.0, - "94": 0.4, - "95": 1.0 + "92": 1.0, + "101": 0.4, + "102": 1.0 }, "player": { - "85": 1.0 + "92": 1.0 }, "preferred": { - "85": 0.4 + "92": 0.4 }, "several": { - "85": 0.4 + "92": 0.4 }, "step": { - "86": 1.0, - "87": 1.0 + "93": 1.0, + "94": 1.0 }, "amount": { - "86": 0.4, - "87": 0.4 + "93": 0.4, + "94": 0.4 }, "changes": { - "86": 0.4, - "87": 0.4, - "99": 1.0, - "100": 1.0, - "101": 1.0, - "102": 1.0, - "103": 1.0, - "104": 1.0, - "105": 1.0, + "93": 0.4, + "94": 0.4, "106": 1.0, - "107": 1.0 + "107": 1.0, + "108": 1.0, + "109": 1.0, + "110": 1.0, + "111": 1.0, + "112": 1.0, + "113": 1.0, + "114": 1.0 }, "increments": { - "86": 0.4, - "87": 0.4, - "88": 0.4 + "93": 0.4, + "94": 0.4, + "95": 0.4 }, "limit": { - "88": 0.4 + "95": 0.4 }, "upper": { - "88": 0.4 + "95": 0.4 }, "visualiser": { - "89": 1.0 + "96": 1.0 }, "bars": { - "89": 1.0 + "96": 1.0 }, "service": { - "89": 0.4, - "90": 0.4, - "91": 0.4 + "96": 0.4, + "97": 0.4, + "98": 0.4 }, "tuning": { - "89": 0.4, - "90": 0.4, - "91": 0.4 + "96": 0.4, + "97": 0.4, + "98": 0.4 }, "visualisers": { - "89": 0.4 + "96": 0.4 }, "smart": { - "90": 1.0 + "97": 1.0 }, "colour": { - "90": 1.0 + "97": 1.0 }, "scheme": { - "90": 1.0 + "97": 1.0 }, "derive": { - "90": 0.4 + "97": 0.4 }, "from": { - "90": 0.4 + "97": 0.4 }, "mode": { - "90": 0.4, - "100": 1.0 + "97": 0.4, + "107": 1.0 }, "variant": { - "90": 0.4 + "97": 0.4 }, "fullscreen": { - "92": 1.0, - "97": 1.0 + "99": 1.0, + "104": 1.0 }, "appear": { - "92": 0.4, - "97": 0.4 + "99": 0.4, + "104": 0.4 }, "whether": { - "92": 0.4, - "97": 0.4 + "99": 0.4, + "104": 0.4 }, "expire": { - "93": 1.0 + "100": 1.0 }, "automatically": { - "93": 1.0 + "100": 1.0 }, "after": { - "93": 0.4 + "100": 0.4 }, "dismiss": { - "93": 0.4 + "100": 0.4 }, "their": { - "93": 0.4 + "100": 0.4 }, "timeout": { - "93": 0.4, - "95": 1.0 + "100": 0.4, + "102": 1.0 }, "expanded": { - "94": 1.0 + "101": 1.0 }, "by": { - "94": 0.4 + "101": 0.4 }, "dismisses": { - "95": 0.4 + "102": 0.4 }, "notification": { - "95": 0.4 + "102": 0.4 }, "time": { - "95": 0.4, - "111": 0.4 + "102": 0.4, + "118": 0.4 }, "group": { - "96": 1.0 + "103": 1.0 }, "preview": { - "96": 1.0 + "103": 1.0 }, "count": { - "96": 1.0 + "103": 1.0 }, "collapsing": { - "96": 0.4 + "103": 0.4 }, "toasts": { - "97": 0.4, - "98": 1.0 + "104": 0.4, + "105": 1.0 }, "maximum": { - "98": 0.4 + "105": 0.4 }, "once": { - "98": 0.4 + "105": 0.4 }, "charging": { - "99": 1.0 + "106": 1.0 }, "events": { - "99": 0.4, - "100": 0.4, - "101": 0.4, - "102": 0.4, - "103": 0.4, - "104": 0.4, - "105": 0.4, "106": 0.4, "107": 0.4, - "108": 0.4 + "108": 0.4, + "109": 0.4, + "110": 0.4, + "111": 0.4, + "112": 0.4, + "113": 0.4, + "114": 0.4, + "115": 0.4 }, "toast": { - "99": 0.4, - "100": 0.4, - "101": 0.4, - "102": 0.4, - "103": 0.4, - "104": 0.4, - "105": 0.4, "106": 0.4, "107": 0.4, - "108": 0.4 + "108": 0.4, + "109": 0.4, + "110": 0.4, + "111": 0.4, + "112": 0.4, + "113": 0.4, + "114": 0.4, + "115": 0.4 }, "game": { - "100": 1.0 + "107": 1.0 }, "do": { - "101": 1.0 + "108": 1.0 }, "not": { - "101": 1.0 + "108": 1.0 }, "disturb": { - "101": 1.0 + "108": 1.0 }, "num": { - "105": 1.0 + "112": 1.0 }, "vpn": { - "107": 1.0 + "114": 1.0 }, "now": { - "108": 1.0 + "115": 1.0 }, "playing": { - "108": 1.0 + "115": 1.0 }, "temperature": { - "109": 1.0 + "116": 1.0 }, "language": { - "109": 0.4, - "110": 0.4, - "111": 0.4 + "116": 0.4, + "117": 0.4, + "118": 0.4 }, "region": { - "109": 0.4, - "110": 0.4, - "111": 0.4 + "116": 0.4, + "117": 0.4, + "118": 0.4 }, "temperatures": { - "109": 0.4, - "110": 1.0 + "116": 0.4, + "117": 1.0 }, "units": { - "109": 0.4, - "110": 0.4 + "116": 0.4, + "117": 0.4 }, "format": { - "111": 1.0 + "118": 1.0 }, "across": { - "111": 0.4 + "118": 0.4 }, "shell": { - "111": 0.4 + "118": 0.4 } } } \ No newline at end of file diff --git a/modules/nexus/pages/network/EthernetDetailPage.qml b/modules/nexus/pages/network/EthernetDetailPage.qml index 4591a7ba0..44279be60 100644 --- a/modules/nexus/pages/network/EthernetDetailPage.qml +++ b/modules/nexus/pages/network/EthernetDetailPage.qml @@ -150,18 +150,21 @@ PageBase { InfoRow { first: true icon: "link" + settingAnchor: "ethernet-status" label: qsTr("Status") value: root.device?.connected ? qsTr("Connected") : qsTr("Not connected") } InfoRow { icon: "settings_ethernet" + settingAnchor: "ethernet-interface" label: qsTr("Interface") value: root.ifaceName || qsTr("—") } InfoRow { icon: "speed" + settingAnchor: "ethernet-speed" label: qsTr("Speed") visible: Nmcli.ethernetSpeed.length > 0 value: Nmcli.ethernetSpeed @@ -169,12 +172,14 @@ PageBase { InfoRow { icon: "lan" + settingAnchor: "ethernet-ip-address" label: qsTr("IP address") value: root.details?.ipAddress || qsTr("—") } InfoRow { icon: "router" + settingAnchor: "ethernet-gateway" label: qsTr("Gateway") value: root.details?.gateway || qsTr("—") } @@ -182,6 +187,7 @@ PageBase { InfoRow { last: true icon: "memory" + settingAnchor: "ethernet-mac-address" label: qsTr("MAC address") value: root.details?.macAddress || qsTr("—") } @@ -197,6 +203,7 @@ PageBase { Layout.fillWidth: true first: true last: root.ipMethod === "auto" + settingAnchor: "ethernet-ip-assignment" label: qsTr("IP assignment") fallbackText: qsTr("Automatic (DHCP)") fallbackIcon: "lan" diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 2eb184567..61eedad4b 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -32,7 +32,7 @@ def read_lines(path: Path) -> tuple[str, ...]: """Read a file's lines, cached so each page file is only read once.""" return tuple(path.read_text().splitlines()) -ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow)\s*\{') +ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow|InfoRow)\s*\{') LABEL_RE = re.compile(r'^\s*(?:label|text):\s*qsTr\("([^"]+)"\)') ANCHOR_RE = re.compile(r'^\s*settingAnchor:\s*"([^"]+)"') ICON_RE = re.compile(r'^\s*icon:\s*"([^"]+)"') @@ -172,7 +172,17 @@ def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: main_icon, main_label = top_meta.get(top_idx, ("tune", main)) nav[main] = {"pageIdx": top_idx, "subPath": [], "crumbIcons": [main_icon], "crumbLabels": [main_label]} - for pos, (icon, label, section) in nav_children.get(main, {}).items(): + children = dict(nav_children.get(main, {})) + # Fallback: a StackPage may list sub-pages (pos > 0) whose openSubPage() + # call lives in a separate component file we don't scan (e.g. the + # Ethernet detail page is opened from EthernetSection.qml). Link any such + # sub-page by its position, deriving a label from its component name. + for pos in range(1, len(names)): + if pos not in children: + label = re.sub(r"(Detail)?Page$", "", names[pos]) + label = re.sub(r"(?= len(names): continue child = names[pos] From 3fae2df1173b9d12af52646f7c1441613a8b787d Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 16:49:54 +0000 Subject: [PATCH 27/57] fix(nexus): select the ethernet device when deep-linking to its settings --- modules/nexus/navpane/NavLocations.qml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index dd5bfe2e7..a080df8ac 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -204,7 +204,17 @@ VerticalFadeFlickable { anchors.fill: parent radius: parent.radius - onClicked: root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor) + onClicked: { + // Ethernet detail settings need a selected interface to + // show the right device; a search deep-link has none, so + // point it at the connected (or first) ethernet device. + if (result.modelData.anchor.startsWith("ethernet-")) { + const active = Nmcli.activeEthernet ?? Nmcli.ethernetDevices[0] ?? null; + if (active) + root.nState.selectedEthernetInterface = active.iface; + } + root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor); + } } ColumnLayout { From f52cf3ac397587bc5576e580c1e34bd1e1f733ee Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 16:49:54 +0000 Subject: [PATCH 28/57] fix(nexus): wait for async content to settle before scrolling --- modules/nexus/common/PageBase.qml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 2223bc111..579c7a0cf 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -63,6 +63,8 @@ ColumnLayout { if (!nState.searchAnchor) return; scrollRetry.tries = 0; + scrollRetry.lastHeight = -1; + scrollRetry.stableFrames = 0; scrollRetry.restart(); } @@ -81,14 +83,24 @@ ColumnLayout { id: scrollRetry property int tries: 0 + property real lastHeight: -1 + property int stableFrames: 0 interval: 16 repeat: true onTriggered: { - // Wait for the page layout to settle (content taller than the - // viewport, or a few frames elapsed) before scrolling, otherwise a - // freshly loaded page reports stale positions and overshoots. - const ready = flickable.contentHeight > flickable.height || tries >= 8; + // Pages like the ethernet detail load their content asynchronously + // (device info, IP config), so the layout keeps growing for a while. + // Wait until contentHeight has held steady for a few frames (or we've + // waited long enough) before scrolling, so the target doesn't drift. + const h = flickable.contentHeight; + if (h === lastHeight && h > flickable.height) + stableFrames++; + else + stableFrames = 0; + lastHeight = h; + + const ready = stableFrames >= 3 || tries >= 30; if (ready) { if (root.scrollToAnchor(root.nState.searchAnchor)) root.nState.searchAnchor = ""; From 954dc8a3120f56df3c11d78c60a6cb0567990aeb Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 17:17:23 +0000 Subject: [PATCH 29/57] fix(nexus): hide ethernet results from search when no ethernet is available --- modules/nexus/navpane/NavLocations.qml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index a080df8ac..2db001ce9 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -16,7 +16,17 @@ VerticalFadeFlickable { readonly property string search: nState.searchText readonly property bool searching: search.length > 0 - readonly property var results: searching ? SettingsSearcher.query(search) : [] + readonly property var results: { + if (!searching) + return []; + const all = SettingsSearcher.query(search); + // The ethernet section hides itself when no ethernet device is available + // (e.g. the cable is unplugged), so drop its settings from the results + // too, otherwise the search would link to a page that isn't reachable. + if (Nmcli.hasAvailableEthernet) + return all; + return all.filter(e => !e.anchor.startsWith("ethernet-")); + } topMargin: Tokens.padding.large bottomMargin: Tokens.padding.large From 79e796166ab2df25b71b079ba407f7964e9d4a41 Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 19:35:46 +0000 Subject: [PATCH 30/57] fix(nexus): keep result ordering stable and show more matches --- modules/nexus/SettingsSearcher.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 54edf42c6..e411f72ff 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -42,7 +42,9 @@ Singleton { } } - const ranked = Object.keys(scores).filter(id => hitCounts[id] === tokens.length).sort((a, b) => scores[b] - scores[a]).slice(0, 12); + // Sort by score, breaking ties by id so the order is stable (otherwise + // entries with equal scores can be dropped arbitrarily by the limit). + const ranked = Object.keys(scores).filter(id => hitCounts[id] === tokens.length).sort((a, b) => scores[b] - scores[a] || (parseInt(a) - parseInt(b))).slice(0, 25); const all = entries.instances; return ranked.map(id => all[parseInt(id)]).filter(e => e !== undefined); From b4baf958a6bf4d02bb41829ce97e65b079237adf Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 19:35:46 +0000 Subject: [PATCH 31/57] feat(nexus): index NavRow status text so descriptions are searchable --- assets/settings-index.json | 282 ++++++++++++++++++++------------ scripts/build-settings-index.py | 2 +- 2 files changed, 176 insertions(+), 108 deletions(-) diff --git a/assets/settings-index.json b/assets/settings-index.json index 61c73fdc3..6610893aa 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -613,7 +613,7 @@ "title": "Workspaces", "anchor": "taskbar-workspaces", "section": "Components", - "subtext": "" + "subtext": "Indicators, window icons" }, { "pageIdx": 6, @@ -631,7 +631,7 @@ "title": "Active window", "anchor": "taskbar-active-window", "section": "Components", - "subtext": "" + "subtext": "Title display, popout" }, { "pageIdx": 6, @@ -649,7 +649,7 @@ "title": "Tray", "anchor": "taskbar-tray", "section": "Components", - "subtext": "" + "subtext": "System tray icons" }, { "pageIdx": 6, @@ -667,7 +667,7 @@ "title": "Status icons", "anchor": "taskbar-status-icons", "section": "Components", - "subtext": "" + "subtext": "Visible indicators" }, { "pageIdx": 6, @@ -685,7 +685,7 @@ "title": "Clock", "anchor": "taskbar-clock", "section": "Components", - "subtext": "" + "subtext": "Date, icon, background" }, { "pageIdx": 6, @@ -1509,7 +1509,7 @@ "title": "All apps", "anchor": "apps-all-apps", "section": "Library", - "subtext": "" + "subtext": "Browse installed apps, set favourites and hidden" }, { "pageIdx": 8, @@ -1523,7 +1523,7 @@ "title": "Notifications", "anchor": "services-notifications", "section": "Notifications", - "subtext": "" + "subtext": "Notifications, toasts, timeouts" }, { "pageIdx": 8, @@ -2031,6 +2031,7 @@ "inverted": { "display": [ 0, + 37, 74, 75, 76 @@ -2572,6 +2573,7 @@ "visible": [ 105, 33, + 39, 60, 61, 62, @@ -2603,23 +2605,58 @@ 39, 40 ], - "active": [ + "icons": [ + 39, + 50, + 57, + 36, + 38, + 47, + 48, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68 + ], + "indicators": [ + 36, + 39 + ], + "window": [ 37, - 45, - 46, + 50, + 36, 52, 53, 54, 55 ], - "window": [ + "active": [ 37, - 50, + 45, + 46, 52, 53, 54, 55 ], + "popout": [ + 55, + 59, + 68, + 37, + 58 + ], + "title": [ + 37, + 53, + 54 + ], "tray": [ 38, 56, @@ -2627,21 +2664,10 @@ 58, 59 ], - "icons": [ - 39, - 50, - 57, - 47, - 48, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68 + "system": [ + 89, + 117, + 38 ], "clock": [ 40, @@ -2650,6 +2676,21 @@ 70, 71 ], + "background": [ + 47, + 56, + 69, + 40 + ], + "date": [ + 70, + 40, + 118 + ], + "icon": [ + 71, + 40 + ], "actions": [ 78, 80, @@ -2725,11 +2766,6 @@ "occupied": [ 47 ], - "background": [ - 47, - 56, - 69 - ], "each": [ 47, 48, @@ -2795,20 +2831,10 @@ 53, 54 ], - "title": [ - 53, - 54 - ], "while": [ 53, 54 ], - "popout": [ - 55, - 59, - 68, - 58 - ], "details": [ 55, 68 @@ -2843,13 +2869,6 @@ 111, 112 ], - "date": [ - 70, - 118 - ], - "icon": [ - 71 - ], "items": [ 74 ], @@ -2925,9 +2944,24 @@ "variants": [ 82 ], + "browse": [ + 86 + ], + "favourites": [ + 86 + ], + "hidden": [ + 86 + ], + "installed": [ + 86 + ], "library": [ 86 ], + "set": [ + 86 + ], "notifications": [ 87, 99, @@ -2979,6 +3013,14 @@ 114, 115 ], + "timeouts": [ + 87 + ], + "toasts": [ + 105, + 87, + 104 + ], "refresh": [ 88, 89 @@ -3007,10 +3049,6 @@ "updates": [ 88 ], - "system": [ - 89, - 117 - ], "stats": [ 89 ], @@ -3206,10 +3244,6 @@ "collapsing": [ 103 ], - "toasts": [ - 105, - 104 - ], "maximum": [ 105 ], @@ -3301,6 +3335,7 @@ "ranking": { "display": { "0": 1.0, + "37": 0.4, "74": 0.4, "75": 0.4, "76": 0.4 @@ -3841,6 +3876,7 @@ }, "visible": { "33": 0.4, + "39": 0.4, "60": 0.4, "61": 0.4, "62": 0.4, @@ -3873,23 +3909,58 @@ "39": 0.4, "40": 0.4 }, - "active": { + "icons": { + "36": 0.4, + "38": 0.4, + "39": 1.0, + "47": 0.4, + "48": 0.4, + "50": 1.0, + "57": 1.0, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4 + }, + "indicators": { + "36": 0.4, + "39": 0.4 + }, + "window": { + "36": 0.4, "37": 1.0, - "45": 1.0, - "46": 1.0, + "50": 1.0, "52": 0.4, "53": 0.4, "54": 0.4, "55": 0.4 }, - "window": { + "active": { "37": 1.0, - "50": 1.0, + "45": 1.0, + "46": 1.0, "52": 0.4, "53": 0.4, "54": 0.4, "55": 0.4 }, + "popout": { + "37": 0.4, + "55": 1.0, + "58": 0.4, + "59": 1.0, + "68": 1.0 + }, + "title": { + "37": 0.4, + "53": 0.4, + "54": 0.4 + }, "tray": { "38": 1.0, "56": 0.4, @@ -3897,21 +3968,10 @@ "58": 0.4, "59": 0.4 }, - "icons": { - "39": 1.0, - "47": 0.4, - "48": 0.4, - "50": 1.0, - "57": 1.0, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4 + "system": { + "38": 0.4, + "89": 1.0, + "117": 1.0 }, "clock": { "40": 1.0, @@ -3920,6 +3980,21 @@ "71": 0.4, "118": 1.0 }, + "background": { + "40": 0.4, + "47": 1.0, + "56": 1.0, + "69": 1.0 + }, + "date": { + "40": 0.4, + "70": 1.0, + "118": 0.4 + }, + "icon": { + "40": 0.4, + "71": 1.0 + }, "actions": { "41": 0.4, "42": 0.4, @@ -3995,11 +4070,6 @@ "occupied": { "47": 1.0 }, - "background": { - "47": 1.0, - "56": 1.0, - "69": 1.0 - }, "each": { "47": 0.4, "48": 0.4, @@ -4065,20 +4135,10 @@ "53": 0.4, "54": 0.4 }, - "title": { - "53": 0.4, - "54": 0.4 - }, "while": { "53": 0.4, "54": 0.4 }, - "popout": { - "55": 1.0, - "58": 0.4, - "59": 1.0, - "68": 1.0 - }, "details": { "55": 0.4, "68": 0.4 @@ -4113,13 +4173,6 @@ "111": 1.0, "112": 1.0 }, - "date": { - "70": 1.0, - "118": 0.4 - }, - "icon": { - "71": 1.0 - }, "items": { "74": 1.0 }, @@ -4195,9 +4248,24 @@ "variants": { "82": 1.0 }, + "browse": { + "86": 0.4 + }, + "favourites": { + "86": 0.4 + }, + "hidden": { + "86": 0.4 + }, + "installed": { + "86": 0.4 + }, "library": { "86": 0.4 }, + "set": { + "86": 0.4 + }, "notifications": { "87": 1.0, "99": 0.4, @@ -4249,6 +4317,14 @@ "114": 0.4, "115": 0.4 }, + "timeouts": { + "87": 0.4 + }, + "toasts": { + "87": 0.4, + "104": 0.4, + "105": 1.0 + }, "refresh": { "88": 1.0, "89": 1.0 @@ -4277,10 +4353,6 @@ "updates": { "88": 0.4 }, - "system": { - "89": 1.0, - "117": 1.0 - }, "stats": { "89": 1.0 }, @@ -4476,10 +4548,6 @@ "collapsing": { "103": 0.4 }, - "toasts": { - "104": 0.4, - "105": 1.0 - }, "maximum": { "105": 0.4 }, diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 61eedad4b..e3a05269f 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -223,7 +223,7 @@ def tokenize(text: str) -> list[str]: return toks -SUBTEXT_RE = re.compile(r'^\s*subtext:\s*qsTr\("([^"]+)"\)') +SUBTEXT_RE = re.compile(r'^\s*(?:subtext|status):\s*qsTr\("([^"]+)"\)') SECTION_RE = re.compile(r'^\s*SectionHeader\s*\{') From 48636c8193eb4ee2f4dac09f2b19d27dd09a0c08 Mon Sep 17 00:00:00 2001 From: Mestane Date: Fri, 26 Jun 2026 19:42:33 +0000 Subject: [PATCH 32/57] fix(nexus): render all search results so no gap appears in the list --- modules/nexus/navpane/NavLocations.qml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 2db001ce9..d50547cc8 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -147,6 +147,7 @@ VerticalFadeFlickable { Layout.fillWidth: true implicitHeight: contentHeight interactive: false + cacheBuffer: 10000 spacing: Tokens.spacing.extraSmall model: ScriptModel { @@ -171,6 +172,18 @@ VerticalFadeFlickable { } } + move: Transition { + Anim { + property: "y" + type: Anim.StandardSmall + } + Anim { + type: Anim.DefaultEffects + property: "opacity" + to: 1 + } + } + displaced: Transition { Anim { type: Anim.StandardSmall From cc03713efb1affbfc33ab979fa3a6d8d04996391 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sat, 27 Jun 2026 08:49:12 +0000 Subject: [PATCH 33/57] feat(nexus): group search results by page with joined cards and dividers --- modules/nexus/navpane/NavLocations.qml | 222 +++++++++++++++---------- 1 file changed, 137 insertions(+), 85 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index d50547cc8..3a5a7314b 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -8,6 +8,7 @@ import qs.components import qs.components.containers import qs.services import qs.modules.nexus +import qs.modules.nexus.common VerticalFadeFlickable { id: root @@ -27,6 +28,26 @@ VerticalFadeFlickable { return all; return all.filter(e => !e.anchor.startsWith("ethernet-")); } + // Results grouped by their top-level page, so the list can show one heading + // per page with the matching settings joined underneath it (like the + // Android settings search). Each group: { page, entries: [...] }. + readonly property var groups: { + const out = []; + const byPage = ({}); + for (const e of results) { + const key = e.pageIdx; + if (byPage[key] === undefined) { + byPage[key] = { + "page": e.crumbLabels[0], + "icon": e.crumbIcons[0], + "entries": [] + }; + out.push(byPage[key]); + } + byPage[key].entries.push(e); + } + return out; + } topMargin: Tokens.padding.large bottomMargin: Tokens.padding.large @@ -139,19 +160,20 @@ VerticalFadeFlickable { ListView { id: resultList - // A ListView fed by a ScriptModel (same approach as the launcher): - // when the query changes the model diffs the result list, so only - // entries that actually appear/disappear/move are animated. The - // rest stay put, which avoids re-animating the whole list on every - // keystroke. Scrolling is delegated to the outer flickable. + // Grouped results: the model is one entry per top-level page, and + // each delegate renders that page's heading plus the matching + // settings joined into a single rounded card (first/last rounded, + // middles square, thin dividers between them), like the Android + // settings search. A ScriptModel diffs the groups so only changed + // ones animate. Scrolling is delegated to the outer flickable. Layout.fillWidth: true implicitHeight: contentHeight interactive: false cacheBuffer: 10000 - spacing: Tokens.spacing.extraSmall + spacing: Tokens.spacing.larger model: ScriptModel { - values: root.results + values: root.groups } add: Transition { @@ -172,18 +194,6 @@ VerticalFadeFlickable { } } - move: Transition { - Anim { - property: "y" - type: Anim.StandardSmall - } - Anim { - type: Anim.DefaultEffects - property: "opacity" - to: 1 - } - } - displaced: Transition { Anim { type: Anim.StandardSmall @@ -208,91 +218,133 @@ VerticalFadeFlickable { } } - delegate: StyledRect { - id: result + delegate: ColumnLayout { + id: group required property var modelData required property int index width: resultList.width - implicitHeight: { - const h = resultLayout.implicitHeight + resultLayout.anchors.margins * 2; - return h % 2 === 0 ? h : h + 1; - } + spacing: Tokens.spacing.small - radius: Tokens.rounding.medium - color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + // Group heading: the top-level page name, shown once. + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: Tokens.padding.small + spacing: Tokens.spacing.small - StateLayer { - anchors.fill: parent - radius: parent.radius - - onClicked: { - // Ethernet detail settings need a selected interface to - // show the right device; a search deep-link has none, so - // point it at the connected (or first) ethernet device. - if (result.modelData.anchor.startsWith("ethernet-")) { - const active = Nmcli.activeEthernet ?? Nmcli.ethernetDevices[0] ?? null; - if (active) - root.nState.selectedEthernetInterface = active.iface; - } - root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor); + MaterialIcon { + text: group.modelData.icon + color: Colours.palette.m3primary + fontStyle: Tokens.font.icon.small + } + + StyledText { + Layout.fillWidth: true + text: group.modelData.page + color: Colours.palette.m3primary + font: Tokens.font.label.large + elide: Text.ElideRight } } + // The matching settings, joined into one card. ColumnLayout { - id: resultLayout + Layout.fillWidth: true + spacing: 0 - anchors.fill: parent - anchors.margins: Tokens.padding.large - spacing: Tokens.spacing.small / 2 + Repeater { + model: group.modelData.entries - // Location line: page icon + "Page \u203a Section", faint. - RowLayout { - Layout.fillWidth: true - spacing: Tokens.spacing.small + ConnectedRect { + id: result - MaterialIcon { - Layout.alignment: Qt.AlignVCenter - text: result.modelData.crumbIcons[result.modelData.crumbIcons.length - 1] - color: Colours.palette.m3onSurfaceVariant - fontStyle: Tokens.font.icon.small - } + required property var modelData + required property int index + + readonly property bool isFirst: index === 0 + readonly property bool isLast: index === group.modelData.entries.length - 1 - StyledText { Layout.fillWidth: true - text: { - const labels = result.modelData.crumbLabels; - const section = result.modelData.section; - // Skip the section if it just repeats the last - // breadcrumb label (e.g. page and section share a name). - const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels; - return parts.join(" \u203a "); + implicitHeight: { + const h = resultLayout.implicitHeight + resultLayout.anchors.margins * 2; + return h % 2 === 0 ? h : h + 1; + } + first: isFirst + last: isLast + color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) + + StateLayer { + anchors.fill: parent + radius: 0 + + onClicked: { + // Ethernet detail settings need a selected interface + // to show the right device; a search deep-link has + // none, so point it at the connected (or first) one. + if (result.modelData.anchor.startsWith("ethernet-")) { + const active = Nmcli.activeEthernet ?? Nmcli.ethernetDevices[0] ?? null; + if (active) + root.nState.selectedEthernetInterface = active.iface; + } + root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor); + } } - color: Colours.palette.m3onSurfaceVariant - font: Tokens.font.label.small - elide: Text.ElideRight - } - } - // The setting itself, most prominent. - StyledText { - Layout.fillWidth: true - Layout.topMargin: Tokens.spacing.small / 2 - text: result.modelData.title - color: Colours.palette.m3primary - font: Tokens.font.body.medium - elide: Text.ElideRight - } + // Thin divider between joined rows (not under the last one). + StyledRect { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: Tokens.padding.large + anchors.rightMargin: Tokens.padding.large + implicitHeight: 1 + visible: !result.isLast + color: Colours.palette.m3outlineVariant + } - // Optional description, faintest and smallest. - StyledText { - Layout.fillWidth: true - visible: result.modelData.subtext.length > 0 - text: result.modelData.subtext - color: Colours.palette.m3outline - font: Tokens.font.label.small - elide: Text.ElideRight + ColumnLayout { + id: resultLayout + + anchors.fill: parent + anchors.margins: Tokens.padding.large + spacing: Tokens.spacing.small / 2 + + // Location line: deepest icon + "Section > sub", faint. + StyledText { + Layout.fillWidth: true + text: { + const labels = result.modelData.crumbLabels.slice(1); + const section = result.modelData.section; + const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels; + return parts.join(" \u203a "); + } + visible: text.length > 0 + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.label.small + elide: Text.ElideRight + } + + // The setting itself, most prominent. + StyledText { + Layout.fillWidth: true + text: result.modelData.title + color: Colours.palette.m3onSurface + font: Tokens.font.body.medium + elide: Text.ElideRight + } + + // Optional description, faintest and smallest. + StyledText { + Layout.fillWidth: true + visible: result.modelData.subtext.length > 0 + text: result.modelData.subtext + color: Colours.palette.m3outline + font: Tokens.font.label.small + elide: Text.ElideRight + } + } + } } } } From d2ce16551b2fb73856f8f20711fb8080a22668e1 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sat, 27 Jun 2026 09:00:40 +0000 Subject: [PATCH 34/57] fix(nexus): square the joined corners and space group headings evenly --- modules/nexus/navpane/NavLocations.qml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 3a5a7314b..708cd2c5e 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -8,7 +8,6 @@ import qs.components import qs.components.containers import qs.services import qs.modules.nexus -import qs.modules.nexus.common VerticalFadeFlickable { id: root @@ -170,7 +169,7 @@ VerticalFadeFlickable { implicitHeight: contentHeight interactive: false cacheBuffer: 10000 - spacing: Tokens.spacing.larger + spacing: Tokens.spacing.extraLargeIncreased model: ScriptModel { values: root.groups @@ -256,7 +255,7 @@ VerticalFadeFlickable { Repeater { model: group.modelData.entries - ConnectedRect { + StyledRect { id: result required property var modelData @@ -270,8 +269,12 @@ VerticalFadeFlickable { const h = resultLayout.implicitHeight + resultLayout.anchors.margins * 2; return h % 2 === 0 ? h : h + 1; } - first: isFirst - last: isLast + // Joined card: round only the outer corners so the + // rows read as one block (square where they meet). + topLeftRadius: isFirst ? Tokens.rounding.large : 0 + topRightRadius: isFirst ? Tokens.rounding.large : 0 + bottomLeftRadius: isLast ? Tokens.rounding.large : 0 + bottomRightRadius: isLast ? Tokens.rounding.large : 0 color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) StateLayer { From 491122394804759afd26e32da52bbacc5296af1f Mon Sep 17 00:00:00 2001 From: Mestane Date: Sat, 27 Jun 2026 09:07:05 +0000 Subject: [PATCH 35/57] fix(nexus): match the gap between result groups to the top margin --- modules/nexus/navpane/NavLocations.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 708cd2c5e..1ddc21294 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -169,7 +169,7 @@ VerticalFadeFlickable { implicitHeight: contentHeight interactive: false cacheBuffer: 10000 - spacing: Tokens.spacing.extraLargeIncreased + spacing: Tokens.padding.large model: ScriptModel { values: root.groups From 34677f53ccdbdbb3047ff12bb083bf8c56db38d2 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sat, 27 Jun 2026 13:18:48 +0000 Subject: [PATCH 36/57] fix(nexus): give bar sub-pages their full path through taskbar components --- assets/settings-index.json | 432 +++++++++++++++++++++++--------- scripts/build-settings-index.py | 18 +- 2 files changed, 330 insertions(+), 120 deletions(-) diff --git a/assets/settings-index.json b/assets/settings-index.json index 6610893aa..abbedc79c 100644 --- a/assets/settings-index.json +++ b/assets/settings-index.json @@ -744,15 +744,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Shown", "anchor": "bar-ws-shown", @@ -762,15 +767,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Active indicator", "anchor": "bar-ws-active-indicator", @@ -780,15 +790,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Active trail", "anchor": "bar-ws-active-trail", @@ -798,15 +813,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Occupied background", "anchor": "bar-ws-occupied-background", @@ -816,15 +836,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Show windows", "anchor": "bar-ws-show-windows", @@ -834,15 +859,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Windows on special workspaces", "anchor": "bar-ws-windows-on-special-workspaces", @@ -852,15 +882,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Max window icons", "anchor": "bar-ws-max-window-icons", @@ -870,15 +905,20 @@ { "pageIdx": 6, "subPath": [ + 2, 5 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "workspaces", + "workspaces" ], "crumbLabels": [ "Panels", - "Bar Workspaces" + "Taskbar", + "Components", + "Workspaces" ], "title": "Per-monitor workspaces", "anchor": "bar-ws-per-monitor-workspaces", @@ -888,15 +928,20 @@ { "pageIdx": 6, "subPath": [ + 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "web_asset", + "web_asset" ], "crumbLabels": [ "Panels", - "Bar Active Window" + "Taskbar", + "Components", + "Active window" ], "title": "Compact", "anchor": "bar-aw-compact", @@ -906,15 +951,20 @@ { "pageIdx": 6, "subPath": [ + 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "web_asset", + "web_asset" ], "crumbLabels": [ "Panels", - "Bar Active Window" + "Taskbar", + "Components", + "Active window" ], "title": "Inverted", "anchor": "bar-aw-inverted", @@ -924,15 +974,20 @@ { "pageIdx": 6, "subPath": [ + 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "web_asset", + "web_asset" ], "crumbLabels": [ "Panels", - "Bar Active Window" + "Taskbar", + "Components", + "Active window" ], "title": "Show on hover", "anchor": "bar-aw-show-on-hover", @@ -942,15 +997,20 @@ { "pageIdx": 6, "subPath": [ + 2, 6 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "web_asset", + "web_asset" ], "crumbLabels": [ "Panels", - "Bar Active Window" + "Taskbar", + "Components", + "Active window" ], "title": "Popout on hover", "anchor": "bar-aw-popout-on-hover", @@ -960,15 +1020,20 @@ { "pageIdx": 6, "subPath": [ + 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "widgets", + "widgets" ], "crumbLabels": [ "Panels", - "Bar Tray" + "Taskbar", + "Components", + "Tray" ], "title": "Background", "anchor": "bar-tray-background", @@ -978,15 +1043,20 @@ { "pageIdx": 6, "subPath": [ + 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "widgets", + "widgets" ], "crumbLabels": [ "Panels", - "Bar Tray" + "Taskbar", + "Components", + "Tray" ], "title": "Recolour icons", "anchor": "bar-tray-recolour-icons", @@ -996,15 +1066,20 @@ { "pageIdx": 6, "subPath": [ + 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "widgets", + "widgets" ], "crumbLabels": [ "Panels", - "Bar Tray" + "Taskbar", + "Components", + "Tray" ], "title": "Compact", "anchor": "bar-tray-compact", @@ -1014,15 +1089,20 @@ { "pageIdx": 6, "subPath": [ + 2, 7 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "widgets", + "widgets" ], "crumbLabels": [ "Panels", - "Bar Tray" + "Taskbar", + "Components", + "Tray" ], "title": "Popout on hover", "anchor": "bar-tray-popout-on-hover", @@ -1032,15 +1112,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Speakers", "anchor": "bar-si-speakers", @@ -1050,15 +1135,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Microphone", "anchor": "bar-si-microphone", @@ -1068,15 +1158,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Keyboard layout", "anchor": "bar-si-keyboard-layout", @@ -1086,15 +1181,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Network", "anchor": "bar-si-network", @@ -1104,15 +1204,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Wi-Fi", "anchor": "bar-si-wi-fi", @@ -1122,15 +1227,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Bluetooth", "anchor": "bar-si-bluetooth", @@ -1140,15 +1250,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Battery", "anchor": "bar-si-battery", @@ -1158,15 +1273,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Caps lock", "anchor": "bar-si-caps-lock", @@ -1176,15 +1296,20 @@ { "pageIdx": 6, "subPath": [ + 2, 8 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "signal_cellular_alt", + "signal_cellular_alt" ], "crumbLabels": [ "Panels", - "Bar Status Icons" + "Taskbar", + "Components", + "Status icons" ], "title": "Popout on hover", "anchor": "bar-si-popout-on-hover", @@ -1194,15 +1319,20 @@ { "pageIdx": 6, "subPath": [ + 2, 9 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "schedule", + "schedule" ], "crumbLabels": [ "Panels", - "Bar Clock" + "Taskbar", + "Components", + "Clock" ], "title": "Background", "anchor": "bar-clock-background", @@ -1212,15 +1342,20 @@ { "pageIdx": 6, "subPath": [ + 2, 9 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "schedule", + "schedule" ], "crumbLabels": [ "Panels", - "Bar Clock" + "Taskbar", + "Components", + "Clock" ], "title": "Show date", "anchor": "bar-clock-show-date", @@ -1230,15 +1365,20 @@ { "pageIdx": 6, "subPath": [ + 2, 9 ], "crumbIcons": [ "dock_to_bottom", - "dock_to_bottom" + "dock_to_bottom", + "schedule", + "schedule" ], "crumbLabels": [ "Panels", - "Bar Clock" + "Taskbar", + "Components", + "Clock" ], "title": "Show icon", "anchor": "bar-clock-show-icon", @@ -2318,7 +2458,35 @@ 40, 41, 42, - 43 + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71 ], "launcher": [ 18, @@ -2533,35 +2701,7 @@ 34, 35, 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71 + 43 ], "keep": [ 33 @@ -2603,7 +2743,35 @@ 37, 38, 39, - 40 + 40, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71 ], "icons": [ 39, @@ -3622,7 +3790,35 @@ "40": 0.4, "41": 0.4, "42": 0.4, - "43": 0.4 + "43": 0.4, + "44": 0.4, + "45": 0.4, + "46": 0.4, + "47": 0.4, + "48": 0.4, + "49": 0.4, + "50": 0.4, + "51": 0.4, + "52": 0.4, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4, + "69": 0.4, + "70": 0.4, + "71": 0.4 }, "launcher": { "18": 1.0, @@ -3837,35 +4033,7 @@ "34": 0.4, "35": 0.4, "42": 0.4, - "43": 0.4, - "44": 0.4, - "45": 0.4, - "46": 0.4, - "47": 0.4, - "48": 0.4, - "49": 0.4, - "50": 0.4, - "51": 0.4, - "52": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4, - "69": 0.4, - "70": 0.4, - "71": 0.4 + "43": 0.4 }, "keep": { "33": 0.4 @@ -3907,7 +4075,35 @@ "37": 0.4, "38": 0.4, "39": 0.4, - "40": 0.4 + "40": 0.4, + "44": 0.4, + "45": 0.4, + "46": 0.4, + "47": 0.4, + "48": 0.4, + "49": 0.4, + "50": 0.4, + "51": 0.4, + "52": 0.4, + "53": 0.4, + "54": 0.4, + "55": 0.4, + "56": 0.4, + "57": 0.4, + "58": 0.4, + "59": 0.4, + "60": 0.4, + "61": 0.4, + "62": 0.4, + "63": 0.4, + "64": 0.4, + "65": 0.4, + "66": 0.4, + "67": 0.4, + "68": 0.4, + "69": 0.4, + "70": 0.4, + "71": 0.4 }, "icons": { "36": 0.4, diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index e3a05269f..e7ddcc8cd 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -173,12 +173,26 @@ def build_nav_map(nexus: Path, files: dict[str, Path]) -> dict[str, dict]: nav[main] = {"pageIdx": top_idx, "subPath": [], "crumbIcons": [main_icon], "crumbLabels": [main_label]} children = dict(nav_children.get(main, {})) + # Components that some other page opens via openSubPage. Those are reached + # through that page (e.g. the bar pages are opened from inside Taskbar's + # "Components" section), so they must not be linked directly here, which + # would give them a wrong, shorter breadcrumb and navigation path. + opened_via_subpage = set() + for owner, kids in nav_children.items(): + # Find the group this owner component belongs to. + owner_group = next((ns for ns in comps if owner in ns), None) + if not owner_group: + continue + for kpos in kids: + if kpos < len(owner_group): + opened_via_subpage.add(owner_group[kpos]) # Fallback: a StackPage may list sub-pages (pos > 0) whose openSubPage() # call lives in a separate component file we don't scan (e.g. the # Ethernet detail page is opened from EthernetSection.qml). Link any such - # sub-page by its position, deriving a label from its component name. + # sub-page by its position, deriving a label from its component name - + # but skip ones already reached through another page. for pos in range(1, len(names)): - if pos not in children: + if pos not in children and names[pos] not in opened_via_subpage: label = re.sub(r"(Detail)?Page$", "", names[pos]) label = re.sub(r"(? Date: Sat, 27 Jun 2026 13:18:48 +0000 Subject: [PATCH 37/57] fix(nexus): match result card corners to the page tab radius --- modules/nexus/navpane/NavLocations.qml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 1ddc21294..0e1e2e4b4 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -270,11 +270,12 @@ VerticalFadeFlickable { return h % 2 === 0 ? h : h + 1; } // Joined card: round only the outer corners so the - // rows read as one block (square where they meet). - topLeftRadius: isFirst ? Tokens.rounding.large : 0 - topRightRadius: isFirst ? Tokens.rounding.large : 0 - bottomLeftRadius: isLast ? Tokens.rounding.large : 0 - bottomRightRadius: isLast ? Tokens.rounding.large : 0 + // rows read as one block (square where they meet), + // matching the page tabs' corner radius. + topLeftRadius: isFirst ? Tokens.rounding.extraLarge : 0 + topRightRadius: isFirst ? Tokens.rounding.extraLarge : 0 + bottomLeftRadius: isLast ? Tokens.rounding.extraLarge : 0 + bottomRightRadius: isLast ? Tokens.rounding.extraLarge : 0 color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) StateLayer { From 7b8d84b0fd071a908865824b46a73c956da3c76a Mon Sep 17 00:00:00 2001 From: Mestane Date: Sat, 27 Jun 2026 21:09:05 +0000 Subject: [PATCH 38/57] fix(nexus): match result groups by page so reordering animates instead of flickering --- modules/nexus/navpane/NavLocations.qml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 0e1e2e4b4..d076d7fd1 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -37,6 +37,7 @@ VerticalFadeFlickable { const key = e.pageIdx; if (byPage[key] === undefined) { byPage[key] = { + "pageIdx": e.pageIdx, "page": e.crumbLabels[0], "icon": e.crumbIcons[0], "entries": [] @@ -172,6 +173,12 @@ VerticalFadeFlickable { spacing: Tokens.padding.large model: ScriptModel { + // Match groups by their page so that when result ranking changes + // the group order, the model emits a move (which animates + // smoothly) instead of a remove+add (which flickered). Group + // contents updating in place becomes a dataChanged, not a + // rebuild. This keeps the One UI-style reordering behaviour. + objectProp: "pageIdx" values: root.groups } @@ -193,6 +200,13 @@ VerticalFadeFlickable { } } + move: Transition { + Anim { + property: "y" + type: Anim.StandardSmall + } + } + displaced: Transition { Anim { type: Anim.StandardSmall From 3e3998bb2778a0ccf404f8e80bc10a231e62a294 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sat, 27 Jun 2026 21:49:35 +0000 Subject: [PATCH 39/57] fix(nexus): drop add/remove fades so the result list stops flickering and gapping --- modules/nexus/navpane/NavLocations.qml | 33 ++++---------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index d076d7fd1..e45f9fba8 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -182,24 +182,11 @@ VerticalFadeFlickable { values: root.groups } - add: Transition { - Anim { - type: Anim.DefaultEffects - property: "opacity" - from: 0 - to: 1 - } - } - - remove: Transition { - Anim { - type: Anim.DefaultEffects - property: "opacity" - from: 1 - to: 0 - } - } - + // No add/remove fade: the list's implicitHeight tracks contentHeight, + // and fading items still occupy space while animating, which made the + // list flicker and leave gaps on fast typing. Additions and removals + // are instant; only reordering animates (via objectProp + move), which + // keeps the One UI-style smooth shuffle without the layout jitter. move: Transition { Anim { property: "y" @@ -212,11 +199,6 @@ VerticalFadeFlickable { type: Anim.StandardSmall property: "y" } - Anim { - type: Anim.DefaultEffects - property: "opacity" - to: 1 - } } addDisplaced: Transition { @@ -224,11 +206,6 @@ VerticalFadeFlickable { type: Anim.StandardSmall property: "y" } - Anim { - type: Anim.DefaultEffects - property: "opacity" - to: 1 - } } delegate: ColumnLayout { From 44d89d67e9a9c113607e03fbe8149e3d3253ed2b Mon Sep 17 00:00:00 2001 From: Mestane Date: Sat, 27 Jun 2026 21:52:31 +0000 Subject: [PATCH 40/57] fix(nexus): make the result list fully static so fast typing leaves no gaps --- modules/nexus/navpane/NavLocations.qml | 38 +++++--------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index e45f9fba8..7c0096078 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -172,42 +172,18 @@ VerticalFadeFlickable { cacheBuffer: 10000 spacing: Tokens.padding.large + // The list's implicitHeight tracks contentHeight; while items animate + // their position the reported height fluctuates, which left gaps in + // the surrounding layout on fast typing. So additions, removals and + // reordering are all instant - no transitions - keeping the height + // correct at every frame. model: ScriptModel { - // Match groups by their page so that when result ranking changes - // the group order, the model emits a move (which animates - // smoothly) instead of a remove+add (which flickered). Group - // contents updating in place becomes a dataChanged, not a - // rebuild. This keeps the One UI-style reordering behaviour. + // Match groups by their page so content updates in place rather + // than rebuilding the delegate when ranking shifts the order. objectProp: "pageIdx" values: root.groups } - // No add/remove fade: the list's implicitHeight tracks contentHeight, - // and fading items still occupy space while animating, which made the - // list flicker and leave gaps on fast typing. Additions and removals - // are instant; only reordering animates (via objectProp + move), which - // keeps the One UI-style smooth shuffle without the layout jitter. - move: Transition { - Anim { - property: "y" - type: Anim.StandardSmall - } - } - - displaced: Transition { - Anim { - type: Anim.StandardSmall - property: "y" - } - } - - addDisplaced: Transition { - Anim { - type: Anim.StandardSmall - property: "y" - } - } - delegate: ColumnLayout { id: group From 67df3138246652358848b344020fd69804f5392a Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 02:32:21 +0000 Subject: [PATCH 41/57] feat(nexus): highlight the matched search terms in result titles and descriptions --- modules/nexus/SettingsSearcher.qml | 15 +++++++++++++++ modules/nexus/navpane/NavLocations.qml | 6 ++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index e411f72ff..f7e1d4154 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -72,6 +72,21 @@ Singleton { return text.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 0); } + // Wrap the parts of `text` that match the search in bold, for use with a + // StyledText in Text.StyledText format. Matches each query token as a prefix + // at a word boundary (mirroring how _lookup matches), so "wall" bolds the + // start of "wallpaper". HTML-significant characters are escaped first so the + // rich-text parser doesn't choke on names containing & < or >. + function highlight(text: string, search: string): string { + const escaped = text.replace(/&/g, "&").replace(//g, ">"); + const tokens = _tokenize(search); + if (tokens.length === 0) + return escaped; + const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); + const pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi"); + return escaped.replace(pattern, "$1"); + } + Variants { id: entries diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 7c0096078..9b6cff6ce 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -299,7 +299,8 @@ VerticalFadeFlickable { // The setting itself, most prominent. StyledText { Layout.fillWidth: true - text: result.modelData.title + text: SettingsSearcher.highlight(result.modelData.title, root.search) + textFormat: Text.StyledText color: Colours.palette.m3onSurface font: Tokens.font.body.medium elide: Text.ElideRight @@ -309,7 +310,8 @@ VerticalFadeFlickable { StyledText { Layout.fillWidth: true visible: result.modelData.subtext.length > 0 - text: result.modelData.subtext + text: SettingsSearcher.highlight(result.modelData.subtext, root.search) + textFormat: Text.StyledText color: Colours.palette.m3outline font: Tokens.font.label.small elide: Text.ElideRight From aac9e3928864c3ed3a09e1f83843eba0665ba6a6 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 02:37:09 +0000 Subject: [PATCH 42/57] feat(nexus): colour the highlighted search matches as well as bolding them --- modules/nexus/SettingsSearcher.qml | 14 +++++++------- modules/nexus/navpane/NavLocations.qml | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index f7e1d4154..52ca5e63d 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -72,19 +72,19 @@ Singleton { return text.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 0); } - // Wrap the parts of `text` that match the search in bold, for use with a - // StyledText in Text.StyledText format. Matches each query token as a prefix - // at a word boundary (mirroring how _lookup matches), so "wall" bolds the - // start of "wallpaper". HTML-significant characters are escaped first so the - // rich-text parser doesn't choke on names containing & < or >. - function highlight(text: string, search: string): string { + // Wrap the parts of `text` that match the search in bold and the given + // colour, for use with a StyledText in Text.StyledText format. Matches each + // query token as a prefix at a word boundary (mirroring how _lookup matches), + // so "wall" highlights the start of "wallpaper". HTML-significant characters + // are escaped first so the rich-text parser doesn't choke on names with & < >. + function highlight(text: string, search: string, colour: color): string { const escaped = text.replace(/&/g, "&").replace(//g, ">"); const tokens = _tokenize(search); if (tokens.length === 0) return escaped; const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); const pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi"); - return escaped.replace(pattern, "$1"); + return escaped.replace(pattern, `$1`); } Variants { diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 9b6cff6ce..a7e1fc76c 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -299,7 +299,7 @@ VerticalFadeFlickable { // The setting itself, most prominent. StyledText { Layout.fillWidth: true - text: SettingsSearcher.highlight(result.modelData.title, root.search) + text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3primary) textFormat: Text.StyledText color: Colours.palette.m3onSurface font: Tokens.font.body.medium @@ -310,7 +310,7 @@ VerticalFadeFlickable { StyledText { Layout.fillWidth: true visible: result.modelData.subtext.length > 0 - text: SettingsSearcher.highlight(result.modelData.subtext, root.search) + text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) textFormat: Text.StyledText color: Colours.palette.m3outline font: Tokens.font.label.small From 50c945740c955fa2ada145b6d09911957ccc350d Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 02:45:27 +0000 Subject: [PATCH 43/57] feat(nexus): colour search matches with the tertiary accent and drop the bold --- modules/nexus/SettingsSearcher.qml | 12 ++++++------ modules/nexus/navpane/NavLocations.qml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 52ca5e63d..7a8af3387 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -72,11 +72,11 @@ Singleton { return text.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 0); } - // Wrap the parts of `text` that match the search in bold and the given - // colour, for use with a StyledText in Text.StyledText format. Matches each - // query token as a prefix at a word boundary (mirroring how _lookup matches), - // so "wall" highlights the start of "wallpaper". HTML-significant characters - // are escaped first so the rich-text parser doesn't choke on names with & < >. + // Wrap the parts of `text` that match the search in the given colour, for use + // with a StyledText in Text.StyledText format. Matches each query token as a + // prefix at a word boundary (mirroring how _lookup matches), so "wall" + // highlights the start of "wallpaper". HTML-significant characters are escaped + // first so the rich-text parser doesn't choke on names with & < or >. function highlight(text: string, search: string, colour: color): string { const escaped = text.replace(/&/g, "&").replace(//g, ">"); const tokens = _tokenize(search); @@ -84,7 +84,7 @@ Singleton { return escaped; const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); const pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi"); - return escaped.replace(pattern, `$1`); + return escaped.replace(pattern, `$1`); } Variants { diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index a7e1fc76c..2989ce92b 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -299,7 +299,7 @@ VerticalFadeFlickable { // The setting itself, most prominent. StyledText { Layout.fillWidth: true - text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3primary) + text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3tertiary) textFormat: Text.StyledText color: Colours.palette.m3onSurface font: Tokens.font.body.medium @@ -310,7 +310,7 @@ VerticalFadeFlickable { StyledText { Layout.fillWidth: true visible: result.modelData.subtext.length > 0 - text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) + text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3tertiary) textFormat: Text.StyledText color: Colours.palette.m3outline font: Tokens.font.label.small From 79633b38dab069d38db4d6176fa469988ee05735 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 09:38:20 +0000 Subject: [PATCH 44/57] fix(nexus): use a font colour tag so the highlight actually renders in StyledText --- modules/nexus/SettingsSearcher.qml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 7a8af3387..6e88c49d5 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -75,8 +75,9 @@ Singleton { // Wrap the parts of `text` that match the search in the given colour, for use // with a StyledText in Text.StyledText format. Matches each query token as a // prefix at a word boundary (mirroring how _lookup matches), so "wall" - // highlights the start of "wallpaper". HTML-significant characters are escaped - // first so the rich-text parser doesn't choke on names with & < or >. + // highlights the start of "wallpaper". StyledText supports but + // not CSS . HTML-significant characters are escaped first so the + // rich-text parser doesn't choke on names with & < or >. function highlight(text: string, search: string, colour: color): string { const escaped = text.replace(/&/g, "&").replace(//g, ">"); const tokens = _tokenize(search); @@ -84,7 +85,7 @@ Singleton { return escaped; const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); const pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi"); - return escaped.replace(pattern, `$1`); + return escaped.replace(pattern, `$1`); } Variants { From ba12dfa88a49fa966b8933007f2d201b350fd76b Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 10:41:34 +0000 Subject: [PATCH 45/57] fix(nexus): keep the hover layer above the labels so hover stops flickering --- modules/nexus/navpane/NavLocations.qml | 40 +++++++++++++++----------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 2989ce92b..b89b02a6f 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -245,23 +245,6 @@ VerticalFadeFlickable { bottomRightRadius: isLast ? Tokens.rounding.extraLarge : 0 color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) - StateLayer { - anchors.fill: parent - radius: 0 - - onClicked: { - // Ethernet detail settings need a selected interface - // to show the right device; a search deep-link has - // none, so point it at the connected (or first) one. - if (result.modelData.anchor.startsWith("ethernet-")) { - const active = Nmcli.activeEthernet ?? Nmcli.ethernetDevices[0] ?? null; - if (active) - root.nState.selectedEthernetInterface = active.iface; - } - root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor); - } - } - // Thin divider between joined rows (not under the last one). StyledRect { anchors.bottom: parent.bottom @@ -317,6 +300,29 @@ VerticalFadeFlickable { elide: Text.ElideRight } } + + // Hover/click layer on top of the content so the + // rich-text labels underneath can't intercept pointer + // events (which made the hover flicker as the mouse + // moved over them). It's transparent apart from the + // hover tint, so the text still shows through. + StateLayer { + anchors.fill: parent + z: 1 + radius: 0 + + onClicked: { + // Ethernet detail settings need a selected interface + // to show the right device; a search deep-link has + // none, so point it at the connected (or first) one. + if (result.modelData.anchor.startsWith("ethernet-")) { + const active = Nmcli.activeEthernet ?? Nmcli.ethernetDevices[0] ?? null; + if (active) + root.nState.selectedEthernetInterface = active.iface; + } + root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor); + } + } } } } From de56273f691bda9fa8d6d2ecd493e44f9e41fb96 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 11:23:57 +0000 Subject: [PATCH 46/57] feat(nexus): use the primary accent for search match highlights --- assets/settings-index.json | 4835 ------------------------ modules/nexus/navpane/NavLocations.qml | 4 +- 2 files changed, 2 insertions(+), 4837 deletions(-) delete mode 100644 assets/settings-index.json diff --git a/assets/settings-index.json b/assets/settings-index.json deleted file mode 100644 index abbedc79c..000000000 --- a/assets/settings-index.json +++ /dev/null @@ -1,4835 +0,0 @@ -{ - "version": 2, - "entries": [ - { - "pageIdx": 0, - "subPath": [], - "crumbIcons": [ - "palette" - ], - "crumbLabels": [ - "Wallpaper & style" - ], - "title": "Display wallpaper", - "anchor": "style-display-wallpaper", - "section": "", - "subtext": "" - }, - { - "pageIdx": 0, - "subPath": [], - "crumbIcons": [ - "palette" - ], - "crumbLabels": [ - "Wallpaper & style" - ], - "title": "Transparency", - "anchor": "style-transparency", - "section": "", - "subtext": "Base %1, layers %2" - }, - { - "pageIdx": 0, - "subPath": [], - "crumbIcons": [ - "palette" - ], - "crumbLabels": [ - "Wallpaper & style" - ], - "title": "Dark theme", - "anchor": "style-dark-theme", - "section": "", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [], - "crumbIcons": [ - "wifi" - ], - "crumbLabels": [ - "Network" - ], - "title": "Wi-Fi", - "anchor": "network-wi-fi", - "section": "", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [ - 1 - ], - "crumbIcons": [ - "wifi", - "wifi" - ], - "crumbLabels": [ - "Network", - "Ethernet" - ], - "title": "Status", - "anchor": "ethernet-status", - "section": "Connection", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [ - 1 - ], - "crumbIcons": [ - "wifi", - "wifi" - ], - "crumbLabels": [ - "Network", - "Ethernet" - ], - "title": "Interface", - "anchor": "ethernet-interface", - "section": "Connection", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [ - 1 - ], - "crumbIcons": [ - "wifi", - "wifi" - ], - "crumbLabels": [ - "Network", - "Ethernet" - ], - "title": "Speed", - "anchor": "ethernet-speed", - "section": "Connection", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [ - 1 - ], - "crumbIcons": [ - "wifi", - "wifi" - ], - "crumbLabels": [ - "Network", - "Ethernet" - ], - "title": "IP address", - "anchor": "ethernet-ip-address", - "section": "Connection", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [ - 1 - ], - "crumbIcons": [ - "wifi", - "wifi" - ], - "crumbLabels": [ - "Network", - "Ethernet" - ], - "title": "Gateway", - "anchor": "ethernet-gateway", - "section": "Connection", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [ - 1 - ], - "crumbIcons": [ - "wifi", - "wifi" - ], - "crumbLabels": [ - "Network", - "Ethernet" - ], - "title": "MAC address", - "anchor": "ethernet-mac-address", - "section": "Connection", - "subtext": "" - }, - { - "pageIdx": 1, - "subPath": [ - 1 - ], - "crumbIcons": [ - "wifi", - "wifi" - ], - "crumbLabels": [ - "Network", - "Ethernet" - ], - "title": "IP assignment", - "anchor": "ethernet-ip-assignment", - "section": "IPv4", - "subtext": "" - }, - { - "pageIdx": 2, - "subPath": [], - "crumbIcons": [ - "devices_other" - ], - "crumbLabels": [ - "Connected devices" - ], - "title": "Bluetooth", - "anchor": "bluetooth-bluetooth", - "section": "", - "subtext": "" - }, - { - "pageIdx": 2, - "subPath": [], - "crumbIcons": [ - "devices_other" - ], - "crumbLabels": [ - "Connected devices" - ], - "title": "Discoverable", - "anchor": "bluetooth-discoverable", - "section": "", - "subtext": "Allow nearby devices to find this one" - }, - { - "pageIdx": 2, - "subPath": [], - "crumbIcons": [ - "devices_other" - ], - "crumbLabels": [ - "Connected devices" - ], - "title": "Pairable", - "anchor": "bluetooth-pairable", - "section": "", - "subtext": "Allow nearby devices to pair with this one" - }, - { - "pageIdx": 3, - "subPath": [], - "crumbIcons": [ - "volume_up" - ], - "crumbLabels": [ - "Audio" - ], - "title": "Output", - "anchor": "audio-output", - "section": "", - "subtext": "" - }, - { - "pageIdx": 3, - "subPath": [], - "crumbIcons": [ - "volume_up" - ], - "crumbLabels": [ - "Audio" - ], - "title": "Input", - "anchor": "audio-input", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [], - "crumbIcons": [ - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels" - ], - "title": "Dashboard", - "anchor": "panels-dashboard", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [], - "crumbIcons": [ - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels" - ], - "title": "Taskbar", - "anchor": "panels-taskbar", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [], - "crumbIcons": [ - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels" - ], - "title": "Launcher", - "anchor": "panels-launcher", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [], - "crumbIcons": [ - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels" - ], - "title": "Sidebar", - "anchor": "panels-sidebar", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Enabled", - "anchor": "dash-enabled", - "section": "General", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Show on hover", - "anchor": "dash-show-on-hover", - "section": "General", - "subtext": "Reveal when the cursor reaches the screen edge" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Dashboard", - "anchor": "dash-dashboard", - "section": "Tabs", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Media", - "anchor": "dash-media", - "section": "Tabs", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Performance", - "anchor": "dash-performance", - "section": "Tabs", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Weather", - "anchor": "dash-weather", - "section": "Tabs", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Battery", - "anchor": "dash-battery", - "section": "Performance widgets", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "GPU", - "anchor": "dash-gpu", - "section": "Performance widgets", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "CPU", - "anchor": "dash-cpu", - "section": "Performance widgets", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Memory", - "anchor": "dash-memory", - "section": "Performance widgets", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Storage", - "anchor": "dash-storage", - "section": "Performance widgets", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Network", - "anchor": "dash-network", - "section": "Performance widgets", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 1 - ], - "crumbIcons": [ - "dock_to_bottom", - "dashboard" - ], - "crumbLabels": [ - "Panels", - "Dashboard" - ], - "title": "Drag threshold", - "anchor": "dash-drag-threshold", - "section": "Behaviour", - "subtext": "Pixels dragged before the dashboard opens" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Persistent", - "anchor": "taskbar-persistent", - "section": "Behaviour", - "subtext": "Keep the bar visible at all times" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Show on hover", - "anchor": "taskbar-show-on-hover", - "section": "Behaviour", - "subtext": "Reveal the bar when the cursor reaches the screen edge" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Drag threshold", - "anchor": "taskbar-drag-threshold", - "section": "Behaviour", - "subtext": "Pixels dragged before the bar reveals" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Workspaces", - "anchor": "taskbar-workspaces", - "section": "Components", - "subtext": "Indicators, window icons" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Active window", - "anchor": "taskbar-active-window", - "section": "Components", - "subtext": "Title display, popout" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Tray", - "anchor": "taskbar-tray", - "section": "Components", - "subtext": "System tray icons" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Status icons", - "anchor": "taskbar-status-icons", - "section": "Components", - "subtext": "Visible indicators" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Clock", - "anchor": "taskbar-clock", - "section": "Components", - "subtext": "Date, icon, background" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Workspaces", - "anchor": "taskbar-workspaces-2", - "section": "Scroll actions", - "subtext": "Scroll over the workspace indicator to switch workspaces" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Volume", - "anchor": "taskbar-volume", - "section": "Scroll actions", - "subtext": "Scroll on the top half of the bar to adjust volume" - }, - { - "pageIdx": 6, - "subPath": [ - 2 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom" - ], - "crumbLabels": [ - "Panels", - "Taskbar" - ], - "title": "Brightness", - "anchor": "taskbar-brightness", - "section": "Scroll actions", - "subtext": "Scroll on the bottom half of the bar to adjust brightness" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Shown", - "anchor": "bar-ws-shown", - "section": "", - "subtext": "Number of workspaces displayed" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Active indicator", - "anchor": "bar-ws-active-indicator", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Active trail", - "anchor": "bar-ws-active-trail", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Occupied background", - "anchor": "bar-ws-occupied-background", - "section": "", - "subtext": "Show icons of open windows on each workspace" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Show windows", - "anchor": "bar-ws-show-windows", - "section": "", - "subtext": "Show icons of open windows on each workspace" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Windows on special workspaces", - "anchor": "bar-ws-windows-on-special-workspaces", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Max window icons", - "anchor": "bar-ws-max-window-icons", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 5 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "workspaces", - "workspaces" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Workspaces" - ], - "title": "Per-monitor workspaces", - "anchor": "bar-ws-per-monitor-workspaces", - "section": "", - "subtext": "Show each monitor's workspaces independently" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 6 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Active window" - ], - "title": "Compact", - "anchor": "bar-aw-compact", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 6 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Active window" - ], - "title": "Inverted", - "anchor": "bar-aw-inverted", - "section": "", - "subtext": "Only show the active window title while hovering" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 6 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Active window" - ], - "title": "Show on hover", - "anchor": "bar-aw-show-on-hover", - "section": "", - "subtext": "Only show the active window title while hovering" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 6 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "web_asset", - "web_asset" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Active window" - ], - "title": "Popout on hover", - "anchor": "bar-aw-popout-on-hover", - "section": "", - "subtext": "Show a window details popout when hovering" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 7 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Tray" - ], - "title": "Background", - "anchor": "bar-tray-background", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 7 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Tray" - ], - "title": "Recolour icons", - "anchor": "bar-tray-recolour-icons", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 7 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Tray" - ], - "title": "Compact", - "anchor": "bar-tray-compact", - "section": "", - "subtext": "Show the tray menu popout when hovering" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 7 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "widgets", - "widgets" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Tray" - ], - "title": "Popout on hover", - "anchor": "bar-tray-popout-on-hover", - "section": "", - "subtext": "Show the tray menu popout when hovering" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Speakers", - "anchor": "bar-si-speakers", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Microphone", - "anchor": "bar-si-microphone", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Keyboard layout", - "anchor": "bar-si-keyboard-layout", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Network", - "anchor": "bar-si-network", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Wi-Fi", - "anchor": "bar-si-wi-fi", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Bluetooth", - "anchor": "bar-si-bluetooth", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Battery", - "anchor": "bar-si-battery", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Caps lock", - "anchor": "bar-si-caps-lock", - "section": "Visible icons", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 8 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "signal_cellular_alt", - "signal_cellular_alt" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Status icons" - ], - "title": "Popout on hover", - "anchor": "bar-si-popout-on-hover", - "section": "Behaviour", - "subtext": "Show a details popout when hovering the status icons" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 9 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "schedule", - "schedule" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Clock" - ], - "title": "Background", - "anchor": "bar-clock-background", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 9 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "schedule", - "schedule" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Clock" - ], - "title": "Show date", - "anchor": "bar-clock-show-date", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 2, - 9 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_bottom", - "schedule", - "schedule" - ], - "crumbLabels": [ - "Panels", - "Taskbar", - "Components", - "Clock" - ], - "title": "Show icon", - "anchor": "bar-clock-show-icon", - "section": "", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Enabled", - "anchor": "launcher-enabled", - "section": "General", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Show on hover", - "anchor": "launcher-show-on-hover", - "section": "General", - "subtext": "Reveal when the cursor reaches the screen edge" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Max items shown", - "anchor": "launcher-max-items-shown", - "section": "Display", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Max wallpapers", - "anchor": "launcher-max-wallpapers", - "section": "Display", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Drag threshold", - "anchor": "launcher-drag-threshold", - "section": "Display", - "subtext": "Pixels dragged before the launcher opens" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Vim keybinds", - "anchor": "launcher-vim-keybinds", - "section": "Behaviour", - "subtext": "Navigate results with Ctrl+hjkl" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Enable dangerous actions", - "anchor": "launcher-enable-dangerous-actions", - "section": "Behaviour", - "subtext": "Allow actions that shut down or log out" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Apps", - "anchor": "launcher-apps", - "section": "Fuzzy search", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Actions", - "anchor": "launcher-actions", - "section": "Fuzzy search", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Schemes", - "anchor": "launcher-schemes", - "section": "Fuzzy search", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Variants", - "anchor": "launcher-variants", - "section": "Fuzzy search", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 3 - ], - "crumbIcons": [ - "dock_to_bottom", - "apps" - ], - "crumbLabels": [ - "Panels", - "Launcher" - ], - "title": "Wallpapers", - "anchor": "launcher-wallpapers", - "section": "Fuzzy search", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 4 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_right" - ], - "crumbLabels": [ - "Panels", - "Sidebar" - ], - "title": "Enabled", - "anchor": "sidebar-enabled", - "section": "General", - "subtext": "" - }, - { - "pageIdx": 6, - "subPath": [ - 4 - ], - "crumbIcons": [ - "dock_to_bottom", - "dock_to_right" - ], - "crumbLabels": [ - "Panels", - "Sidebar" - ], - "title": "Drag threshold", - "anchor": "sidebar-drag-threshold", - "section": "General", - "subtext": "Pixels dragged before the sidebar opens" - }, - { - "pageIdx": 7, - "subPath": [], - "crumbIcons": [ - "apps" - ], - "crumbLabels": [ - "Apps" - ], - "title": "All apps", - "anchor": "apps-all-apps", - "section": "Library", - "subtext": "Browse installed apps, set favourites and hidden" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Notifications", - "anchor": "services-notifications", - "section": "Notifications", - "subtext": "Notifications, toasts, timeouts" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Media refresh", - "anchor": "services-media-refresh", - "section": "Polling", - "subtext": "How often the media position updates (ms)" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "System stats refresh", - "anchor": "services-system-stats-refresh", - "section": "Polling", - "subtext": "CPU, memory and GPU update interval (seconds)" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Wi-Fi rescan", - "anchor": "services-wi-fi-rescan", - "section": "Polling", - "subtext": "How often available networks are rescanned (seconds)" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Lyrics backend", - "anchor": "services-lyrics-backend", - "section": "Media & lyrics", - "subtext": "Source used to fetch synced lyrics" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Default player", - "anchor": "services-default-player", - "section": "Media & lyrics", - "subtext": "Preferred media player when several are open" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Volume step", - "anchor": "services-volume-step", - "section": "Input increments", - "subtext": "Amount the volume changes per scroll (%)" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Brightness step", - "anchor": "services-brightness-step", - "section": "Input increments", - "subtext": "Amount the brightness changes per scroll (%)" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Max volume", - "anchor": "services-max-volume", - "section": "Input increments", - "subtext": "Upper limit for output volume (%)" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Visualiser bars", - "anchor": "services-visualiser-bars", - "section": "Service tuning", - "subtext": "Number of bars in the audio visualisers" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "Smart colour scheme", - "anchor": "services-smart-colour-scheme", - "section": "Service tuning", - "subtext": "Derive theme mode and variant from the wallpaper" - }, - { - "pageIdx": 8, - "subPath": [], - "crumbIcons": [ - "build" - ], - "crumbLabels": [ - "Services" - ], - "title": "GPU", - "anchor": "services-gpu", - "section": "Service tuning", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Show in fullscreen", - "anchor": "notif-show-in-fullscreen", - "section": "Notifications", - "subtext": "Whether notifications appear over fullscreen apps" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Expire automatically", - "anchor": "notif-expire-automatically", - "section": "Notifications", - "subtext": "Dismiss notifications after their timeout" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Open expanded", - "anchor": "notif-open-expanded", - "section": "Notifications", - "subtext": "Show notifications expanded by default" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Default timeout", - "anchor": "notif-default-timeout", - "section": "Notifications", - "subtext": "Time before a notification dismisses (ms)" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Group preview count", - "anchor": "notif-group-preview-count", - "section": "Notifications", - "subtext": "Notifications shown per group before collapsing" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Show in fullscreen", - "anchor": "notif-show-in-fullscreen-2", - "section": "Toasts", - "subtext": "Whether toasts appear over fullscreen apps" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Visible toasts", - "anchor": "notif-visible-toasts", - "section": "Toasts", - "subtext": "Maximum number of toasts shown at once" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Charging changes", - "anchor": "notif-charging-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Game mode changes", - "anchor": "notif-game-mode-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Do not disturb changes", - "anchor": "notif-do-not-disturb-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Audio output changes", - "anchor": "notif-audio-output-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Audio input changes", - "anchor": "notif-audio-input-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Caps lock changes", - "anchor": "notif-caps-lock-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Num lock changes", - "anchor": "notif-num-lock-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Keyboard layout changes", - "anchor": "notif-keyboard-layout-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "VPN changes", - "anchor": "notif-vpn-changes", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 8, - "subPath": [ - 1 - ], - "crumbIcons": [ - "build", - "notifications" - ], - "crumbLabels": [ - "Services", - "Notifications" - ], - "title": "Now playing", - "anchor": "notif-now-playing", - "section": "Toast events", - "subtext": "" - }, - { - "pageIdx": 9, - "subPath": [], - "crumbIcons": [ - "globe" - ], - "crumbLabels": [ - "Language & region" - ], - "title": "Temperature", - "anchor": "lang-temperature", - "section": "Units", - "subtext": "Units for weather temperatures" - }, - { - "pageIdx": 9, - "subPath": [], - "crumbIcons": [ - "globe" - ], - "crumbLabels": [ - "Language & region" - ], - "title": "System temperatures", - "anchor": "lang-system-temperatures", - "section": "Units", - "subtext": "Units for CPU and GPU temperatures" - }, - { - "pageIdx": 9, - "subPath": [], - "crumbIcons": [ - "globe" - ], - "crumbLabels": [ - "Language & region" - ], - "title": "Clock format", - "anchor": "lang-clock-format", - "section": "Time & date", - "subtext": "How times are shown across the shell" - } - ], - "inverted": { - "display": [ - 0, - 37, - 74, - 75, - 76 - ], - "wallpaper": [ - 0, - 1, - 2, - 97 - ], - "style": [ - 0, - 1, - 2 - ], - "transparency": [ - 1 - ], - "1": [ - 1 - ], - "2": [ - 1 - ], - "base": [ - 1 - ], - "layers": [ - 1 - ], - "dark": [ - 2 - ], - "theme": [ - 2, - 97 - ], - "wi": [ - 3, - 64, - 90 - ], - "fi": [ - 3, - 64, - 90 - ], - "wifi": [ - 3, - 64, - 90 - ], - "network": [ - 31, - 63, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10 - ], - "status": [ - 4, - 39, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68 - ], - "connection": [ - 4, - 5, - 6, - 7, - 8, - 9 - ], - "ethernet": [ - 4, - 5, - 6, - 7, - 8, - 9, - 10 - ], - "interface": [ - 5 - ], - "speed": [ - 6 - ], - "ip": [ - 7, - 10 - ], - "address": [ - 7, - 9 - ], - "gateway": [ - 8 - ], - "mac": [ - 9 - ], - "assignment": [ - 10 - ], - "ipv4": [ - 10 - ], - "bluetooth": [ - 11, - 65 - ], - "connected": [ - 11, - 12, - 13 - ], - "devices": [ - 11, - 12, - 13 - ], - "discoverable": [ - 12 - ], - "allow": [ - 12, - 13, - 78 - ], - "find": [ - 12 - ], - "nearby": [ - 12, - 13 - ], - "one": [ - 12, - 13 - ], - "this": [ - 12, - 13 - ], - "pairable": [ - 13 - ], - "pair": [ - 13 - ], - "with": [ - 13, - 77 - ], - "output": [ - 14, - 109, - 95 - ], - "audio": [ - 109, - 110, - 14, - 15, - 96 - ], - "input": [ - 15, - 110, - 93, - 94, - 95 - ], - "dashboard": [ - 16, - 22, - 20, - 21, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32 - ], - "panels": [ - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 85 - ], - "taskbar": [ - 17, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71 - ], - "launcher": [ - 18, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83 - ], - "sidebar": [ - 19, - 84, - 85 - ], - "enabled": [ - 20, - 72, - 84 - ], - "general": [ - 20, - 21, - 72, - 73, - 84, - 85 - ], - "show": [ - 21, - 34, - 48, - 54, - 70, - 71, - 73, - 99, - 104, - 47, - 51, - 53, - 55, - 58, - 59, - 68, - 101 - ], - "hover": [ - 21, - 34, - 54, - 55, - 59, - 68, - 73 - ], - "cursor": [ - 21, - 34, - 73 - ], - "edge": [ - 21, - 34, - 73 - ], - "reaches": [ - 21, - 34, - 73 - ], - "reveal": [ - 21, - 34, - 73 - ], - "screen": [ - 21, - 34, - 73 - ], - "when": [ - 21, - 34, - 55, - 58, - 59, - 68, - 73, - 92 - ], - "tabs": [ - 22, - 23, - 24, - 25 - ], - "media": [ - 23, - 88, - 91, - 92 - ], - "performance": [ - 24, - 26, - 27, - 28, - 29, - 30, - 31 - ], - "weather": [ - 25, - 116 - ], - "battery": [ - 26, - 66 - ], - "widgets": [ - 26, - 27, - 28, - 29, - 30, - 31 - ], - "gpu": [ - 27, - 98, - 89, - 117 - ], - "cpu": [ - 28, - 89, - 117 - ], - "memory": [ - 29, - 89 - ], - "storage": [ - 30 - ], - "drag": [ - 32, - 35, - 76, - 85 - ], - "threshold": [ - 32, - 35, - 76, - 85 - ], - "before": [ - 32, - 35, - 76, - 85, - 102, - 103 - ], - "behaviour": [ - 32, - 33, - 34, - 35, - 68, - 77, - 78 - ], - "dragged": [ - 32, - 35, - 76, - 85 - ], - "opens": [ - 32, - 76, - 85 - ], - "pixels": [ - 32, - 35, - 76, - 85 - ], - "persistent": [ - 33 - ], - "all": [ - 86, - 33 - ], - "at": [ - 33, - 105 - ], - "bar": [ - 33, - 34, - 35, - 42, - 43 - ], - "keep": [ - 33 - ], - "times": [ - 33, - 118 - ], - "visible": [ - 105, - 33, - 39, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67 - ], - "reveals": [ - 35 - ], - "workspaces": [ - 36, - 41, - 49, - 51, - 44, - 45, - 46, - 47, - 48, - 50 - ], - "components": [ - 36, - 37, - 38, - 39, - 40, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71 - ], - "icons": [ - 39, - 50, - 57, - 36, - 38, - 47, - 48, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68 - ], - "indicators": [ - 36, - 39 - ], - "window": [ - 37, - 50, - 36, - 52, - 53, - 54, - 55 - ], - "active": [ - 37, - 45, - 46, - 52, - 53, - 54, - 55 - ], - "popout": [ - 55, - 59, - 68, - 37, - 58 - ], - "title": [ - 37, - 53, - 54 - ], - "tray": [ - 38, - 56, - 57, - 58, - 59 - ], - "system": [ - 89, - 117, - 38 - ], - "clock": [ - 40, - 118, - 69, - 70, - 71 - ], - "background": [ - 47, - 56, - 69, - 40 - ], - "date": [ - 70, - 40, - 118 - ], - "icon": [ - 71, - 40 - ], - "actions": [ - 78, - 80, - 41, - 42, - 43 - ], - "indicator": [ - 45, - 41 - ], - "over": [ - 41, - 99, - 104 - ], - "scroll": [ - 41, - 42, - 43, - 93, - 94 - ], - "switch": [ - 41 - ], - "workspace": [ - 41, - 47, - 48 - ], - "volume": [ - 42, - 93, - 95 - ], - "adjust": [ - 42, - 43 - ], - "half": [ - 42, - 43 - ], - "top": [ - 42 - ], - "brightness": [ - 43, - 94 - ], - "bottom": [ - 43 - ], - "shown": [ - 44, - 74, - 103, - 105, - 118 - ], - "displayed": [ - 44 - ], - "number": [ - 44, - 96, - 105 - ], - "trail": [ - 46 - ], - "occupied": [ - 47 - ], - "each": [ - 47, - 48, - 51 - ], - "open": [ - 101, - 47, - 48, - 92 - ], - "windows": [ - 48, - 49, - 47 - ], - "special": [ - 49 - ], - "max": [ - 50, - 74, - 75, - 95 - ], - "per": [ - 51, - 93, - 94, - 103 - ], - "monitor": [ - 51 - ], - "permonitor": [ - 51 - ], - "independently": [ - 51 - ], - "monitors": [ - 51 - ], - "s": [ - 51 - ], - "compact": [ - 52, - 58 - ], - "inverted": [ - 53 - ], - "hovering": [ - 53, - 54, - 55, - 58, - 59, - 68 - ], - "only": [ - 53, - 54 - ], - "while": [ - 53, - 54 - ], - "details": [ - 55, - 68 - ], - "recolour": [ - 57 - ], - "menu": [ - 58, - 59 - ], - "speakers": [ - 60 - ], - "microphone": [ - 61 - ], - "keyboard": [ - 62, - 113 - ], - "layout": [ - 62, - 113 - ], - "caps": [ - 67, - 111 - ], - "lock": [ - 67, - 111, - 112 - ], - "items": [ - 74 - ], - "wallpapers": [ - 75, - 83 - ], - "vim": [ - 77 - ], - "keybinds": [ - 77 - ], - "ctrl": [ - 77 - ], - "ctrlhjkl": [ - 77 - ], - "hjkl": [ - 77 - ], - "navigate": [ - 77 - ], - "results": [ - 77 - ], - "enable": [ - 78 - ], - "dangerous": [ - 78 - ], - "down": [ - 78 - ], - "log": [ - 78 - ], - "out": [ - 78 - ], - "shut": [ - 78 - ], - "that": [ - 78 - ], - "apps": [ - 79, - 86, - 99, - 104 - ], - "fuzzy": [ - 79, - 80, - 81, - 82, - 83 - ], - "search": [ - 79, - 80, - 81, - 82, - 83 - ], - "schemes": [ - 81 - ], - "variants": [ - 82 - ], - "browse": [ - 86 - ], - "favourites": [ - 86 - ], - "hidden": [ - 86 - ], - "installed": [ - 86 - ], - "library": [ - 86 - ], - "set": [ - 86 - ], - "notifications": [ - 87, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115 - ], - "services": [ - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115 - ], - "timeouts": [ - 87 - ], - "toasts": [ - 105, - 87, - 104 - ], - "refresh": [ - 88, - 89 - ], - "how": [ - 88, - 90, - 118 - ], - "ms": [ - 88, - 102 - ], - "often": [ - 88, - 90 - ], - "polling": [ - 88, - 89, - 90 - ], - "position": [ - 88 - ], - "updates": [ - 88 - ], - "stats": [ - 89 - ], - "interval": [ - 89 - ], - "seconds": [ - 89, - 90 - ], - "update": [ - 89 - ], - "rescan": [ - 90 - ], - "are": [ - 90, - 92, - 118 - ], - "available": [ - 90 - ], - "networks": [ - 90 - ], - "rescanned": [ - 90 - ], - "lyrics": [ - 91, - 92 - ], - "backend": [ - 91 - ], - "fetch": [ - 91 - ], - "source": [ - 91 - ], - "synced": [ - 91 - ], - "used": [ - 91 - ], - "default": [ - 92, - 102, - 101 - ], - "player": [ - 92 - ], - "preferred": [ - 92 - ], - "several": [ - 92 - ], - "step": [ - 93, - 94 - ], - "amount": [ - 93, - 94 - ], - "changes": [ - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 93, - 94 - ], - "increments": [ - 93, - 94, - 95 - ], - "limit": [ - 95 - ], - "upper": [ - 95 - ], - "visualiser": [ - 96 - ], - "bars": [ - 96 - ], - "service": [ - 96, - 97, - 98 - ], - "tuning": [ - 96, - 97, - 98 - ], - "visualisers": [ - 96 - ], - "smart": [ - 97 - ], - "colour": [ - 97 - ], - "scheme": [ - 97 - ], - "derive": [ - 97 - ], - "from": [ - 97 - ], - "mode": [ - 107, - 97 - ], - "variant": [ - 97 - ], - "fullscreen": [ - 99, - 104 - ], - "appear": [ - 99, - 104 - ], - "whether": [ - 99, - 104 - ], - "expire": [ - 100 - ], - "automatically": [ - 100 - ], - "after": [ - 100 - ], - "dismiss": [ - 100 - ], - "their": [ - 100 - ], - "timeout": [ - 102, - 100 - ], - "expanded": [ - 101 - ], - "by": [ - 101 - ], - "dismisses": [ - 102 - ], - "notification": [ - 102 - ], - "time": [ - 102, - 118 - ], - "group": [ - 103 - ], - "preview": [ - 103 - ], - "count": [ - 103 - ], - "collapsing": [ - 103 - ], - "maximum": [ - 105 - ], - "once": [ - 105 - ], - "charging": [ - 106 - ], - "events": [ - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115 - ], - "toast": [ - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115 - ], - "game": [ - 107 - ], - "do": [ - 108 - ], - "not": [ - 108 - ], - "disturb": [ - 108 - ], - "num": [ - 112 - ], - "vpn": [ - 114 - ], - "now": [ - 115 - ], - "playing": [ - 115 - ], - "temperature": [ - 116 - ], - "language": [ - 116, - 117, - 118 - ], - "region": [ - 116, - 117, - 118 - ], - "temperatures": [ - 117, - 116 - ], - "units": [ - 116, - 117 - ], - "format": [ - 118 - ], - "across": [ - 118 - ], - "shell": [ - 118 - ] - }, - "ranking": { - "display": { - "0": 1.0, - "37": 0.4, - "74": 0.4, - "75": 0.4, - "76": 0.4 - }, - "wallpaper": { - "0": 1.0, - "1": 0.4, - "2": 0.4, - "97": 0.4 - }, - "style": { - "0": 0.4, - "1": 0.4, - "2": 0.4 - }, - "transparency": { - "1": 1.0 - }, - "1": { - "1": 0.4 - }, - "2": { - "1": 0.4 - }, - "base": { - "1": 0.4 - }, - "layers": { - "1": 0.4 - }, - "dark": { - "2": 1.0 - }, - "theme": { - "2": 1.0, - "97": 0.4 - }, - "wi": { - "3": 1.0, - "64": 1.0, - "90": 1.0 - }, - "fi": { - "3": 1.0, - "64": 1.0, - "90": 1.0 - }, - "wifi": { - "3": 1.0, - "64": 1.0, - "90": 1.0 - }, - "network": { - "3": 0.4, - "4": 0.4, - "5": 0.4, - "6": 0.4, - "7": 0.4, - "8": 0.4, - "9": 0.4, - "10": 0.4, - "31": 1.0, - "63": 1.0 - }, - "status": { - "4": 1.0, - "39": 1.0, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4 - }, - "connection": { - "4": 0.4, - "5": 0.4, - "6": 0.4, - "7": 0.4, - "8": 0.4, - "9": 0.4 - }, - "ethernet": { - "4": 0.4, - "5": 0.4, - "6": 0.4, - "7": 0.4, - "8": 0.4, - "9": 0.4, - "10": 0.4 - }, - "interface": { - "5": 1.0 - }, - "speed": { - "6": 1.0 - }, - "ip": { - "7": 1.0, - "10": 1.0 - }, - "address": { - "7": 1.0, - "9": 1.0 - }, - "gateway": { - "8": 1.0 - }, - "mac": { - "9": 1.0 - }, - "assignment": { - "10": 1.0 - }, - "ipv4": { - "10": 0.4 - }, - "bluetooth": { - "11": 1.0, - "65": 1.0 - }, - "connected": { - "11": 0.4, - "12": 0.4, - "13": 0.4 - }, - "devices": { - "11": 0.4, - "12": 0.4, - "13": 0.4 - }, - "discoverable": { - "12": 1.0 - }, - "allow": { - "12": 0.4, - "13": 0.4, - "78": 0.4 - }, - "find": { - "12": 0.4 - }, - "nearby": { - "12": 0.4, - "13": 0.4 - }, - "one": { - "12": 0.4, - "13": 0.4 - }, - "this": { - "12": 0.4, - "13": 0.4 - }, - "pairable": { - "13": 1.0 - }, - "pair": { - "13": 0.4 - }, - "with": { - "13": 0.4, - "77": 0.4 - }, - "output": { - "14": 1.0, - "95": 0.4, - "109": 1.0 - }, - "audio": { - "14": 0.4, - "15": 0.4, - "96": 0.4, - "109": 1.0, - "110": 1.0 - }, - "input": { - "15": 1.0, - "93": 0.4, - "94": 0.4, - "95": 0.4, - "110": 1.0 - }, - "dashboard": { - "16": 1.0, - "20": 0.4, - "21": 0.4, - "22": 1.0, - "23": 0.4, - "24": 0.4, - "25": 0.4, - "26": 0.4, - "27": 0.4, - "28": 0.4, - "29": 0.4, - "30": 0.4, - "31": 0.4, - "32": 0.4 - }, - "panels": { - "16": 0.4, - "17": 0.4, - "18": 0.4, - "19": 0.4, - "20": 0.4, - "21": 0.4, - "22": 0.4, - "23": 0.4, - "24": 0.4, - "25": 0.4, - "26": 0.4, - "27": 0.4, - "28": 0.4, - "29": 0.4, - "30": 0.4, - "31": 0.4, - "32": 0.4, - "33": 0.4, - "34": 0.4, - "35": 0.4, - "36": 0.4, - "37": 0.4, - "38": 0.4, - "39": 0.4, - "40": 0.4, - "41": 0.4, - "42": 0.4, - "43": 0.4, - "44": 0.4, - "45": 0.4, - "46": 0.4, - "47": 0.4, - "48": 0.4, - "49": 0.4, - "50": 0.4, - "51": 0.4, - "52": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4, - "69": 0.4, - "70": 0.4, - "71": 0.4, - "72": 0.4, - "73": 0.4, - "74": 0.4, - "75": 0.4, - "76": 0.4, - "77": 0.4, - "78": 0.4, - "79": 0.4, - "80": 0.4, - "81": 0.4, - "82": 0.4, - "83": 0.4, - "84": 0.4, - "85": 0.4 - }, - "taskbar": { - "17": 1.0, - "33": 0.4, - "34": 0.4, - "35": 0.4, - "36": 0.4, - "37": 0.4, - "38": 0.4, - "39": 0.4, - "40": 0.4, - "41": 0.4, - "42": 0.4, - "43": 0.4, - "44": 0.4, - "45": 0.4, - "46": 0.4, - "47": 0.4, - "48": 0.4, - "49": 0.4, - "50": 0.4, - "51": 0.4, - "52": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4, - "69": 0.4, - "70": 0.4, - "71": 0.4 - }, - "launcher": { - "18": 1.0, - "72": 0.4, - "73": 0.4, - "74": 0.4, - "75": 0.4, - "76": 0.4, - "77": 0.4, - "78": 0.4, - "79": 0.4, - "80": 0.4, - "81": 0.4, - "82": 0.4, - "83": 0.4 - }, - "sidebar": { - "19": 1.0, - "84": 0.4, - "85": 0.4 - }, - "enabled": { - "20": 1.0, - "72": 1.0, - "84": 1.0 - }, - "general": { - "20": 0.4, - "21": 0.4, - "72": 0.4, - "73": 0.4, - "84": 0.4, - "85": 0.4 - }, - "show": { - "21": 1.0, - "34": 1.0, - "47": 0.4, - "48": 1.0, - "51": 0.4, - "53": 0.4, - "54": 1.0, - "55": 0.4, - "58": 0.4, - "59": 0.4, - "68": 0.4, - "70": 1.0, - "71": 1.0, - "73": 1.0, - "99": 1.0, - "101": 0.4, - "104": 1.0 - }, - "hover": { - "21": 1.0, - "34": 1.0, - "54": 1.0, - "55": 1.0, - "59": 1.0, - "68": 1.0, - "73": 1.0 - }, - "cursor": { - "21": 0.4, - "34": 0.4, - "73": 0.4 - }, - "edge": { - "21": 0.4, - "34": 0.4, - "73": 0.4 - }, - "reaches": { - "21": 0.4, - "34": 0.4, - "73": 0.4 - }, - "reveal": { - "21": 0.4, - "34": 0.4, - "73": 0.4 - }, - "screen": { - "21": 0.4, - "34": 0.4, - "73": 0.4 - }, - "when": { - "21": 0.4, - "34": 0.4, - "55": 0.4, - "58": 0.4, - "59": 0.4, - "68": 0.4, - "73": 0.4, - "92": 0.4 - }, - "tabs": { - "22": 0.4, - "23": 0.4, - "24": 0.4, - "25": 0.4 - }, - "media": { - "23": 1.0, - "88": 1.0, - "91": 0.4, - "92": 0.4 - }, - "performance": { - "24": 1.0, - "26": 0.4, - "27": 0.4, - "28": 0.4, - "29": 0.4, - "30": 0.4, - "31": 0.4 - }, - "weather": { - "25": 1.0, - "116": 0.4 - }, - "battery": { - "26": 1.0, - "66": 1.0 - }, - "widgets": { - "26": 0.4, - "27": 0.4, - "28": 0.4, - "29": 0.4, - "30": 0.4, - "31": 0.4 - }, - "gpu": { - "27": 1.0, - "89": 0.4, - "98": 1.0, - "117": 0.4 - }, - "cpu": { - "28": 1.0, - "89": 0.4, - "117": 0.4 - }, - "memory": { - "29": 1.0, - "89": 0.4 - }, - "storage": { - "30": 1.0 - }, - "drag": { - "32": 1.0, - "35": 1.0, - "76": 1.0, - "85": 1.0 - }, - "threshold": { - "32": 1.0, - "35": 1.0, - "76": 1.0, - "85": 1.0 - }, - "before": { - "32": 0.4, - "35": 0.4, - "76": 0.4, - "85": 0.4, - "102": 0.4, - "103": 0.4 - }, - "behaviour": { - "32": 0.4, - "33": 0.4, - "34": 0.4, - "35": 0.4, - "68": 0.4, - "77": 0.4, - "78": 0.4 - }, - "dragged": { - "32": 0.4, - "35": 0.4, - "76": 0.4, - "85": 0.4 - }, - "opens": { - "32": 0.4, - "76": 0.4, - "85": 0.4 - }, - "pixels": { - "32": 0.4, - "35": 0.4, - "76": 0.4, - "85": 0.4 - }, - "persistent": { - "33": 1.0 - }, - "all": { - "33": 0.4, - "86": 1.0 - }, - "at": { - "33": 0.4, - "105": 0.4 - }, - "bar": { - "33": 0.4, - "34": 0.4, - "35": 0.4, - "42": 0.4, - "43": 0.4 - }, - "keep": { - "33": 0.4 - }, - "times": { - "33": 0.4, - "118": 0.4 - }, - "visible": { - "33": 0.4, - "39": 0.4, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "105": 1.0 - }, - "reveals": { - "35": 0.4 - }, - "workspaces": { - "36": 1.0, - "41": 1.0, - "44": 0.4, - "45": 0.4, - "46": 0.4, - "47": 0.4, - "48": 0.4, - "49": 1.0, - "50": 0.4, - "51": 1.0 - }, - "components": { - "36": 0.4, - "37": 0.4, - "38": 0.4, - "39": 0.4, - "40": 0.4, - "44": 0.4, - "45": 0.4, - "46": 0.4, - "47": 0.4, - "48": 0.4, - "49": 0.4, - "50": 0.4, - "51": 0.4, - "52": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4, - "69": 0.4, - "70": 0.4, - "71": 0.4 - }, - "icons": { - "36": 0.4, - "38": 0.4, - "39": 1.0, - "47": 0.4, - "48": 0.4, - "50": 1.0, - "57": 1.0, - "60": 0.4, - "61": 0.4, - "62": 0.4, - "63": 0.4, - "64": 0.4, - "65": 0.4, - "66": 0.4, - "67": 0.4, - "68": 0.4 - }, - "indicators": { - "36": 0.4, - "39": 0.4 - }, - "window": { - "36": 0.4, - "37": 1.0, - "50": 1.0, - "52": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4 - }, - "active": { - "37": 1.0, - "45": 1.0, - "46": 1.0, - "52": 0.4, - "53": 0.4, - "54": 0.4, - "55": 0.4 - }, - "popout": { - "37": 0.4, - "55": 1.0, - "58": 0.4, - "59": 1.0, - "68": 1.0 - }, - "title": { - "37": 0.4, - "53": 0.4, - "54": 0.4 - }, - "tray": { - "38": 1.0, - "56": 0.4, - "57": 0.4, - "58": 0.4, - "59": 0.4 - }, - "system": { - "38": 0.4, - "89": 1.0, - "117": 1.0 - }, - "clock": { - "40": 1.0, - "69": 0.4, - "70": 0.4, - "71": 0.4, - "118": 1.0 - }, - "background": { - "40": 0.4, - "47": 1.0, - "56": 1.0, - "69": 1.0 - }, - "date": { - "40": 0.4, - "70": 1.0, - "118": 0.4 - }, - "icon": { - "40": 0.4, - "71": 1.0 - }, - "actions": { - "41": 0.4, - "42": 0.4, - "43": 0.4, - "78": 1.0, - "80": 1.0 - }, - "indicator": { - "41": 0.4, - "45": 1.0 - }, - "over": { - "41": 0.4, - "99": 0.4, - "104": 0.4 - }, - "scroll": { - "41": 0.4, - "42": 0.4, - "43": 0.4, - "93": 0.4, - "94": 0.4 - }, - "switch": { - "41": 0.4 - }, - "workspace": { - "41": 0.4, - "47": 0.4, - "48": 0.4 - }, - "volume": { - "42": 1.0, - "93": 1.0, - "95": 1.0 - }, - "adjust": { - "42": 0.4, - "43": 0.4 - }, - "half": { - "42": 0.4, - "43": 0.4 - }, - "top": { - "42": 0.4 - }, - "brightness": { - "43": 1.0, - "94": 1.0 - }, - "bottom": { - "43": 0.4 - }, - "shown": { - "44": 1.0, - "74": 1.0, - "103": 0.4, - "105": 0.4, - "118": 0.4 - }, - "displayed": { - "44": 0.4 - }, - "number": { - "44": 0.4, - "96": 0.4, - "105": 0.4 - }, - "trail": { - "46": 1.0 - }, - "occupied": { - "47": 1.0 - }, - "each": { - "47": 0.4, - "48": 0.4, - "51": 0.4 - }, - "open": { - "47": 0.4, - "48": 0.4, - "92": 0.4, - "101": 1.0 - }, - "windows": { - "47": 0.4, - "48": 1.0, - "49": 1.0 - }, - "special": { - "49": 1.0 - }, - "max": { - "50": 1.0, - "74": 1.0, - "75": 1.0, - "95": 1.0 - }, - "per": { - "51": 1.0, - "93": 0.4, - "94": 0.4, - "103": 0.4 - }, - "monitor": { - "51": 1.0 - }, - "permonitor": { - "51": 1.0 - }, - "independently": { - "51": 0.4 - }, - "monitors": { - "51": 0.4 - }, - "s": { - "51": 0.4 - }, - "compact": { - "52": 1.0, - "58": 1.0 - }, - "inverted": { - "53": 1.0 - }, - "hovering": { - "53": 0.4, - "54": 0.4, - "55": 0.4, - "58": 0.4, - "59": 0.4, - "68": 0.4 - }, - "only": { - "53": 0.4, - "54": 0.4 - }, - "while": { - "53": 0.4, - "54": 0.4 - }, - "details": { - "55": 0.4, - "68": 0.4 - }, - "recolour": { - "57": 1.0 - }, - "menu": { - "58": 0.4, - "59": 0.4 - }, - "speakers": { - "60": 1.0 - }, - "microphone": { - "61": 1.0 - }, - "keyboard": { - "62": 1.0, - "113": 1.0 - }, - "layout": { - "62": 1.0, - "113": 1.0 - }, - "caps": { - "67": 1.0, - "111": 1.0 - }, - "lock": { - "67": 1.0, - "111": 1.0, - "112": 1.0 - }, - "items": { - "74": 1.0 - }, - "wallpapers": { - "75": 1.0, - "83": 1.0 - }, - "vim": { - "77": 1.0 - }, - "keybinds": { - "77": 1.0 - }, - "ctrl": { - "77": 0.4 - }, - "ctrlhjkl": { - "77": 0.4 - }, - "hjkl": { - "77": 0.4 - }, - "navigate": { - "77": 0.4 - }, - "results": { - "77": 0.4 - }, - "enable": { - "78": 1.0 - }, - "dangerous": { - "78": 1.0 - }, - "down": { - "78": 0.4 - }, - "log": { - "78": 0.4 - }, - "out": { - "78": 0.4 - }, - "shut": { - "78": 0.4 - }, - "that": { - "78": 0.4 - }, - "apps": { - "79": 1.0, - "86": 1.0, - "99": 0.4, - "104": 0.4 - }, - "fuzzy": { - "79": 0.4, - "80": 0.4, - "81": 0.4, - "82": 0.4, - "83": 0.4 - }, - "search": { - "79": 0.4, - "80": 0.4, - "81": 0.4, - "82": 0.4, - "83": 0.4 - }, - "schemes": { - "81": 1.0 - }, - "variants": { - "82": 1.0 - }, - "browse": { - "86": 0.4 - }, - "favourites": { - "86": 0.4 - }, - "hidden": { - "86": 0.4 - }, - "installed": { - "86": 0.4 - }, - "library": { - "86": 0.4 - }, - "set": { - "86": 0.4 - }, - "notifications": { - "87": 1.0, - "99": 0.4, - "100": 0.4, - "101": 0.4, - "102": 0.4, - "103": 0.4, - "104": 0.4, - "105": 0.4, - "106": 0.4, - "107": 0.4, - "108": 0.4, - "109": 0.4, - "110": 0.4, - "111": 0.4, - "112": 0.4, - "113": 0.4, - "114": 0.4, - "115": 0.4 - }, - "services": { - "87": 0.4, - "88": 0.4, - "89": 0.4, - "90": 0.4, - "91": 0.4, - "92": 0.4, - "93": 0.4, - "94": 0.4, - "95": 0.4, - "96": 0.4, - "97": 0.4, - "98": 0.4, - "99": 0.4, - "100": 0.4, - "101": 0.4, - "102": 0.4, - "103": 0.4, - "104": 0.4, - "105": 0.4, - "106": 0.4, - "107": 0.4, - "108": 0.4, - "109": 0.4, - "110": 0.4, - "111": 0.4, - "112": 0.4, - "113": 0.4, - "114": 0.4, - "115": 0.4 - }, - "timeouts": { - "87": 0.4 - }, - "toasts": { - "87": 0.4, - "104": 0.4, - "105": 1.0 - }, - "refresh": { - "88": 1.0, - "89": 1.0 - }, - "how": { - "88": 0.4, - "90": 0.4, - "118": 0.4 - }, - "ms": { - "88": 0.4, - "102": 0.4 - }, - "often": { - "88": 0.4, - "90": 0.4 - }, - "polling": { - "88": 0.4, - "89": 0.4, - "90": 0.4 - }, - "position": { - "88": 0.4 - }, - "updates": { - "88": 0.4 - }, - "stats": { - "89": 1.0 - }, - "interval": { - "89": 0.4 - }, - "seconds": { - "89": 0.4, - "90": 0.4 - }, - "update": { - "89": 0.4 - }, - "rescan": { - "90": 1.0 - }, - "are": { - "90": 0.4, - "92": 0.4, - "118": 0.4 - }, - "available": { - "90": 0.4 - }, - "networks": { - "90": 0.4 - }, - "rescanned": { - "90": 0.4 - }, - "lyrics": { - "91": 1.0, - "92": 0.4 - }, - "backend": { - "91": 1.0 - }, - "fetch": { - "91": 0.4 - }, - "source": { - "91": 0.4 - }, - "synced": { - "91": 0.4 - }, - "used": { - "91": 0.4 - }, - "default": { - "92": 1.0, - "101": 0.4, - "102": 1.0 - }, - "player": { - "92": 1.0 - }, - "preferred": { - "92": 0.4 - }, - "several": { - "92": 0.4 - }, - "step": { - "93": 1.0, - "94": 1.0 - }, - "amount": { - "93": 0.4, - "94": 0.4 - }, - "changes": { - "93": 0.4, - "94": 0.4, - "106": 1.0, - "107": 1.0, - "108": 1.0, - "109": 1.0, - "110": 1.0, - "111": 1.0, - "112": 1.0, - "113": 1.0, - "114": 1.0 - }, - "increments": { - "93": 0.4, - "94": 0.4, - "95": 0.4 - }, - "limit": { - "95": 0.4 - }, - "upper": { - "95": 0.4 - }, - "visualiser": { - "96": 1.0 - }, - "bars": { - "96": 1.0 - }, - "service": { - "96": 0.4, - "97": 0.4, - "98": 0.4 - }, - "tuning": { - "96": 0.4, - "97": 0.4, - "98": 0.4 - }, - "visualisers": { - "96": 0.4 - }, - "smart": { - "97": 1.0 - }, - "colour": { - "97": 1.0 - }, - "scheme": { - "97": 1.0 - }, - "derive": { - "97": 0.4 - }, - "from": { - "97": 0.4 - }, - "mode": { - "97": 0.4, - "107": 1.0 - }, - "variant": { - "97": 0.4 - }, - "fullscreen": { - "99": 1.0, - "104": 1.0 - }, - "appear": { - "99": 0.4, - "104": 0.4 - }, - "whether": { - "99": 0.4, - "104": 0.4 - }, - "expire": { - "100": 1.0 - }, - "automatically": { - "100": 1.0 - }, - "after": { - "100": 0.4 - }, - "dismiss": { - "100": 0.4 - }, - "their": { - "100": 0.4 - }, - "timeout": { - "100": 0.4, - "102": 1.0 - }, - "expanded": { - "101": 1.0 - }, - "by": { - "101": 0.4 - }, - "dismisses": { - "102": 0.4 - }, - "notification": { - "102": 0.4 - }, - "time": { - "102": 0.4, - "118": 0.4 - }, - "group": { - "103": 1.0 - }, - "preview": { - "103": 1.0 - }, - "count": { - "103": 1.0 - }, - "collapsing": { - "103": 0.4 - }, - "maximum": { - "105": 0.4 - }, - "once": { - "105": 0.4 - }, - "charging": { - "106": 1.0 - }, - "events": { - "106": 0.4, - "107": 0.4, - "108": 0.4, - "109": 0.4, - "110": 0.4, - "111": 0.4, - "112": 0.4, - "113": 0.4, - "114": 0.4, - "115": 0.4 - }, - "toast": { - "106": 0.4, - "107": 0.4, - "108": 0.4, - "109": 0.4, - "110": 0.4, - "111": 0.4, - "112": 0.4, - "113": 0.4, - "114": 0.4, - "115": 0.4 - }, - "game": { - "107": 1.0 - }, - "do": { - "108": 1.0 - }, - "not": { - "108": 1.0 - }, - "disturb": { - "108": 1.0 - }, - "num": { - "112": 1.0 - }, - "vpn": { - "114": 1.0 - }, - "now": { - "115": 1.0 - }, - "playing": { - "115": 1.0 - }, - "temperature": { - "116": 1.0 - }, - "language": { - "116": 0.4, - "117": 0.4, - "118": 0.4 - }, - "region": { - "116": 0.4, - "117": 0.4, - "118": 0.4 - }, - "temperatures": { - "116": 0.4, - "117": 1.0 - }, - "units": { - "116": 0.4, - "117": 0.4 - }, - "format": { - "118": 1.0 - }, - "across": { - "118": 0.4 - }, - "shell": { - "118": 0.4 - } - } -} \ No newline at end of file diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index b89b02a6f..2aef66d73 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -282,7 +282,7 @@ VerticalFadeFlickable { // The setting itself, most prominent. StyledText { Layout.fillWidth: true - text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3tertiary) + text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3primary) textFormat: Text.StyledText color: Colours.palette.m3onSurface font: Tokens.font.body.medium @@ -293,7 +293,7 @@ VerticalFadeFlickable { StyledText { Layout.fillWidth: true visible: result.modelData.subtext.length > 0 - text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3tertiary) + text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) textFormat: Text.StyledText color: Colours.palette.m3outline font: Tokens.font.label.small From e5e0c07d979e5698874f57206766b7eb7d129901 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 11:24:09 +0000 Subject: [PATCH 47/57] feat(nexus): bake the settings index into the plugin instead of a config asset --- CMakeLists.txt | 32 ++++++++++++------------ modules/nexus/SettingsSearcher.qml | 38 +++++++++++++---------------- plugin/cmake/qml-module.cmake | 3 ++- plugin/src/Caelestia/CMakeLists.txt | 7 ++++++ plugin/src/Caelestia/cutils.cpp | 10 ++++++++ plugin/src/Caelestia/cutils.hpp | 5 ++++ 6 files changed, 58 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dcbde778e..a2badf685 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,32 +51,34 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wunused-lambda-capture) endif() -if("extras" IN_LIST ENABLE_MODULES) - add_subdirectory(extras) -endif() - -if("plugin" IN_LIST ENABLE_MODULES) - add_subdirectory(plugin) -endif() - -if("shell" IN_LIST ENABLE_MODULES) - # Generate the settings search index from the page QML at build time so it - # always matches the UI (see scripts/build-settings-index.py). +# Generate the settings search index from the page QML at build time so it always +# matches the UI (see scripts/build-settings-index.py). Done up front so the +# plugin can bake it into its binary as a resource (kept out of user-editable +# config). Only needed when either the plugin or shell module is being built. +if("plugin" IN_LIST ENABLE_MODULES OR "shell" IN_LIST ENABLE_MODULES) find_package(Python3 COMPONENTS Interpreter REQUIRED) - file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/assets") + set(SETTINGS_INDEX_JSON "${CMAKE_BINARY_DIR}/settings-index.json") execute_process( COMMAND ${Python3_EXECUTABLE} "${CMAKE_SOURCE_DIR}/scripts/build-settings-index.py" "${CMAKE_SOURCE_DIR}/modules/nexus" - "${CMAKE_BINARY_DIR}/assets/settings-index.json" + "${SETTINGS_INDEX_JSON}" RESULT_VARIABLE SETTINGS_INDEX_RESULT ) if(NOT SETTINGS_INDEX_RESULT EQUAL 0) message(FATAL_ERROR "Failed to build settings search index") endif() - install(FILES "${CMAKE_BINARY_DIR}/assets/settings-index.json" - DESTINATION "${INSTALL_QSCONFDIR}/assets") +endif() +if("extras" IN_LIST ENABLE_MODULES) + add_subdirectory(extras) +endif() + +if("plugin" IN_LIST ENABLE_MODULES) + add_subdirectory(plugin) +endif() + +if("shell" IN_LIST ENABLE_MODULES) foreach(dir assets components modules services utils) install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}") endforeach() diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 6e88c49d5..141e0d715 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -1,13 +1,12 @@ pragma Singleton import QtQuick -import Quickshell -import Quickshell.Io +import Caelestia // Search service over the settings index. The index is generated at build time -// from the page QML files by scripts/build-settings-index.py and shipped as -// assets/settings-index.json (version 2), so it stays in sync with the UI -// without any hand-maintained entries. +// from the page QML files by scripts/build-settings-index.py and baked into the +// plugin binary (read via CUtils.settingsIndex), so it stays in sync with the UI +// without any hand-maintained entries and without a user-editable data file. // // Unlike the launcher's fuzzy searcher, this uses the real inverted index + // ranking baked into the JSON: a query is tokenised, each token is looked up in @@ -88,28 +87,25 @@ Singleton { return escaped.replace(pattern, `$1`); } + Component.onCompleted: { + try { + const data = JSON.parse(CUtils.settingsIndex()); + entries.model = data.entries; + root.inverted = data.inverted ?? {}; + root.ranking = data.ranking ?? {}; + } catch (e) { + entries.model = []; + root.inverted = {}; + root.ranking = {}; + } + } + Variants { id: entries SettingEntry {} } - FileView { - path: Quickshell.shellPath("assets/settings-index.json") - onLoaded: { - try { - const data = JSON.parse(text()); - entries.model = data.entries; - root.inverted = data.inverted ?? {}; - root.ranking = data.ranking ?? {}; - } catch (e) { - entries.model = []; - root.inverted = {}; - root.ranking = {}; - } - } - } - component SettingEntry: QtObject { required property var modelData diff --git a/plugin/cmake/qml-module.cmake b/plugin/cmake/qml-module.cmake index 29dc5fc22..c01c350db 100644 --- a/plugin/cmake/qml-module.cmake +++ b/plugin/cmake/qml-module.cmake @@ -1,7 +1,7 @@ message(STATUS "QML install dir: ${CMAKE_INSTALL_PREFIX}/${INSTALL_QMLDIR}") function(qml_module arg_TARGET) - cmake_parse_arguments(PARSE_ARGV 1 arg "" "URI" "SOURCES;QML_FILES;QML_SINGLETONS;DEPENDENCIES;IMPORTS;OPTIONAL_IMPORTS;DEFAULT_IMPORTS;LIBRARIES") + cmake_parse_arguments(PARSE_ARGV 1 arg "" "URI" "SOURCES;QML_FILES;QML_SINGLETONS;DEPENDENCIES;IMPORTS;OPTIONAL_IMPORTS;DEFAULT_IMPORTS;LIBRARIES;RESOURCES") set_source_files_properties(${arg_QML_SINGLETONS} PROPERTIES QT_QML_SINGLETON_TYPE TRUE) @@ -9,6 +9,7 @@ function(qml_module arg_TARGET) URI ${arg_URI} SOURCES ${arg_SOURCES} QML_FILES ${arg_QML_FILES} ${arg_QML_SINGLETONS} + RESOURCES ${arg_RESOURCES} DEPENDENCIES ${arg_DEPENDENCIES} IMPORTS ${arg_IMPORTS} OPTIONAL_IMPORTS ${arg_OPTIONAL_IMPORTS} diff --git a/plugin/src/Caelestia/CMakeLists.txt b/plugin/src/Caelestia/CMakeLists.txt index f4a7399d2..cd96e04d2 100644 --- a/plugin/src/Caelestia/CMakeLists.txt +++ b/plugin/src/Caelestia/CMakeLists.txt @@ -1,3 +1,8 @@ +# The settings index is generated into the build dir; map it to a stable resource +# path (qrc:/qt/qml/Caelestia/settings-index.json) regardless of its source path. +set_source_files_properties("${SETTINGS_INDEX_JSON}" PROPERTIES + QT_RESOURCE_ALIAS "settings-index.json") + qml_module(caelestia-core URI Caelestia SOURCES @@ -7,6 +12,8 @@ qml_module(caelestia-core requests.cpp toaster.cpp imageanalyser.cpp + RESOURCES + "${SETTINGS_INDEX_JSON}" LIBRARIES Qt::Gui Qt::Quick diff --git a/plugin/src/Caelestia/cutils.cpp b/plugin/src/Caelestia/cutils.cpp index b6080f6ea..2dfb46342 100644 --- a/plugin/src/Caelestia/cutils.cpp +++ b/plugin/src/Caelestia/cutils.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +143,15 @@ qreal CUtils::clamp(qreal value, qreal min, qreal max) { return qBound(min, value, max); } +QString CUtils::settingsIndex() { + QFile file(QStringLiteral(":/qt/qml/Caelestia/settings-index.json")); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qCWarning(lcCUtils) << "Failed to open embedded settings index"; + return QString(); + } + return QString::fromUtf8(file.readAll()); +} + #ifndef CAELESTIA_VERSION #define CAELESTIA_VERSION "" #endif diff --git a/plugin/src/Caelestia/cutils.hpp b/plugin/src/Caelestia/cutils.hpp index 7fb4163a9..e24ac5c48 100644 --- a/plugin/src/Caelestia/cutils.hpp +++ b/plugin/src/Caelestia/cutils.hpp @@ -30,6 +30,11 @@ class CUtils : public QObject { Q_INVOKABLE static qreal clamp(qreal value, qreal min, qreal max); + // Returns the settings search index JSON, baked into the plugin binary at + // build time so it lives with the compiled module rather than in a + // user-editable config file. + Q_INVOKABLE static QString settingsIndex(); + [[nodiscard]] QString version() const; [[nodiscard]] QString qtVersion() const; }; From 3d4a4c9dd60ba39690d8f6b0bcfcf48c43d53dc9 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 14:38:58 +0000 Subject: [PATCH 48/57] fix(nexus): restore the Quickshell import for the Variants type --- modules/nexus/SettingsSearcher.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 141e0d715..04bdd016d 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -1,6 +1,7 @@ pragma Singleton import QtQuick +import Quickshell import Caelestia // Search service over the settings index. The index is generated at build time From 763e99e8d8ebf5d43e31962cefab37e24869da56 Mon Sep 17 00:00:00 2001 From: Mestane Date: Sun, 28 Jun 2026 14:43:23 +0000 Subject: [PATCH 49/57] refactor(nexus): drop the underscore prefix from internal state and helpers --- modules/nexus/NexusState.qml | 14 +++++++------- modules/nexus/SettingsSearcher.qml | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/nexus/NexusState.qml b/modules/nexus/NexusState.qml index 34ae13e44..8dd4b0393 100644 --- a/modules/nexus/NexusState.qml +++ b/modules/nexus/NexusState.qml @@ -8,11 +8,11 @@ QtObject { property bool animatingContainer property int currentPageIdx property list subPageIdxStack - property list _pendingSubPath + property list pendingSubPath property bool searchOpen property string searchText property string searchAnchor - property string _lastAnchor + property string lastAnchor property string selectedWallpaperCategory property BluetoothDevice selectedBtDevice @@ -42,12 +42,12 @@ QtObject { function jumpToSetting(pageIdx: int, subPath: var, anchor: string): void { const samePage = currentPageIdx === pageIdx; const sameSub = subPageIdxStack.length === subPath.length && subPath.every((v, i) => subPageIdxStack[i] === v); - if (samePage && sameSub && anchor === _lastAnchor) { + if (samePage && sameSub && anchor === lastAnchor) { // Re-clicking the exact same setting: flash it again, don't scroll. highlightSetting(anchor); return; } - _lastAnchor = anchor; + lastAnchor = anchor; if (samePage && sameSub) { // Same page, different setting: just scroll to it. searchAnchor = ""; @@ -59,7 +59,7 @@ QtObject { // the anchor once it's ready. searchAnchor = anchor; if (!samePage) { - _pendingSubPath = subPath.slice(); + pendingSubPath = subPath.slice(); currentPageIdx = pageIdx; } else { // Same page: close back to the page root, then open the chain. @@ -71,7 +71,7 @@ QtObject { } onCurrentPageIdxChanged: { - subPageIdxStack = _pendingSubPath; - _pendingSubPath = []; + subPageIdxStack = pendingSubPath; + pendingSubPath = []; } } diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 04bdd016d..504e66290 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -25,7 +25,7 @@ Singleton { property var ranking: ({}) function query(search: string): list { - const tokens = root._tokenize(search); + const tokens = root.tokenize(search); if (tokens.length === 0) return []; @@ -35,7 +35,7 @@ Singleton { const scores = ({}); const hitCounts = ({}); for (const token of tokens) { - const matches = root._lookup(token); // { id: weight } + const matches = root.lookup(token); // { id: weight } for (const id in matches) { scores[id] = (scores[id] ?? 0) + matches[id]; hitCounts[id] = (hitCounts[id] ?? 0) + 1; @@ -53,7 +53,7 @@ Singleton { // Look up a query token in the inverted index: exact match first, then any // indexed token that starts with it (prefix search, so "wif" finds "wifi"). // Returns a map of entry id -> best ranking weight for that id. - function _lookup(token: string): var { + function lookup(token: string): var { const result = ({}); const exact = root.inverted[token] !== undefined; const keys = exact ? [token] : Object.keys(root.inverted).filter(k => k.startsWith(token)); @@ -68,19 +68,19 @@ Singleton { return result; } - function _tokenize(text: string): var { + function tokenize(text: string): var { return text.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 0); } // Wrap the parts of `text` that match the search in the given colour, for use // with a StyledText in Text.StyledText format. Matches each query token as a - // prefix at a word boundary (mirroring how _lookup matches), so "wall" + // prefix at a word boundary (mirroring how lookup matches), so "wall" // highlights the start of "wallpaper". StyledText supports but // not CSS . HTML-significant characters are escaped first so the // rich-text parser doesn't choke on names with & < or >. function highlight(text: string, search: string, colour: color): string { const escaped = text.replace(/&/g, "&").replace(//g, ">"); - const tokens = _tokenize(search); + const tokens = tokenize(search); if (tokens.length === 0) return escaped; const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); From 9bec5fa6a8d605a0977c8b695f2db46e2aeed5e9 Mon Sep 17 00:00:00 2001 From: Mestane <67807483+Mestane@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:59:15 +0300 Subject: [PATCH 50/57] feat(nexus): Default applications and DefaultRow have been added to indexing. --- modules/nexus/pages/AppsPage.qml | 4 ++++ scripts/build-settings-index.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/nexus/pages/AppsPage.qml b/modules/nexus/pages/AppsPage.qml index 9bd2dd532..e969b57c5 100644 --- a/modules/nexus/pages/AppsPage.qml +++ b/modules/nexus/pages/AppsPage.qml @@ -32,6 +32,7 @@ PageBase { DefaultRow { first: true icon: "terminal" + settingAnchor: "apps-default-terminal" label: qsTr("Terminal") status: GlobalConfig.general.apps.terminal.join(" ") onSelected: app => GlobalConfig.general.apps.terminal = app.command @@ -39,6 +40,7 @@ PageBase { DefaultRow { icon: "volume_up" + settingAnchor: "apps-default-audio" label: qsTr("Audio") status: GlobalConfig.general.apps.audio.join(" ") onSelected: app => GlobalConfig.general.apps.audio = app.command @@ -46,6 +48,7 @@ PageBase { DefaultRow { icon: "play_circle" + settingAnchor: "apps-default-playback" label: qsTr("Media playback") status: GlobalConfig.general.apps.playback.join(" ") onSelected: app => GlobalConfig.general.apps.playback = app.command @@ -54,6 +57,7 @@ PageBase { DefaultRow { last: true icon: "folder" + settingAnchor: "apps-default-file-manager" label: qsTr("File manager") status: GlobalConfig.general.apps.explorer.join(" ") onSelected: app => GlobalConfig.general.apps.explorer = app.command diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index e7ddcc8cd..79e295d90 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -32,7 +32,7 @@ def read_lines(path: Path) -> tuple[str, ...]: """Read a file's lines, cached so each page file is only read once.""" return tuple(path.read_text().splitlines()) -ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow|InfoRow)\s*\{') +ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow|InfoRow|PopupRow|DefaultRow)\s*\{') LABEL_RE = re.compile(r'^\s*(?:label|text):\s*qsTr\("([^"]+)"\)') ANCHOR_RE = re.compile(r'^\s*settingAnchor:\s*"([^"]+)"') ICON_RE = re.compile(r'^\s*icon:\s*"([^"]+)"') From 00b25d1f1c71129f202b7544837682c11d7844fd Mon Sep 17 00:00:00 2001 From: Mestane <67807483+Mestane@users.noreply.github.com> Date: Sun, 28 Jun 2026 19:19:15 +0300 Subject: [PATCH 51/57] feat(nexus): readme for indexing --- .gitignore | 3 +- README.md | 208 ++++++++++++++++++++++++++++++ modules/nexus/common/PageBase.qml | 4 +- 3 files changed, 212 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a1c958d91..765a602fc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ /.qmlls.ini build/ .cache/ -logs__pycache__/ +logs +__pycache__/ diff --git a/README.md b/README.md index 13c274d3d..889cb2e3c 100644 --- a/README.md +++ b/README.md @@ -901,6 +901,214 @@ The launcher pulls wallpapers from `~/Pictures/Wallpapers` by default. You can c the launcher only shows an odd number of wallpapers at one time. If you only have 2 wallpapers, consider getting more (or just putting one). +## Settings search + +The settings panel (nexus) has a full-text search that lets users jump straight to any setting by name, description, or +the section/page it lives under. The index is generated from the page QML at build time and baked into the plugin binary, +so it always matches the UI and ships with the compiled module rather than as a user-editable file. + +
Developer guide: how it works, and how to add or remove settings + +### How it works at a glance + +``` + page QML files build-settings-index.py plugin binary + (ToggleRow, NavRow, …) ──► (parses QML, builds index) ──► (JSON embedded + + settingAnchor as a qrc resource) + │ + ▼ + SettingsSearcher.qml reads it + via CUtils.settingsIndex() + │ + ▼ + query() → grouped results → + NexusState.jumpToSetting() +``` + +The index is **generated, not hand-written**. The build script reads the page QML, finds every indexable row, and emits a +JSON file. CMake bakes that JSON into the plugin binary so it ships with the compiled module rather than as a +user-editable file. At runtime the search service reads it back out and serves queries from an inverted index. + +### Adding a setting to the search + +A row is indexed when two things are true: + +1. It is one of the indexable row types listed in `ROW_RE` in `scripts/build-settings-index.py` — currently `ToggleRow`, + `SliderRow`, `SelectRow`, `StepperRow`, `NavRow`, `InfoRow`, `PopupRow` (and its `DefaultRow` alias). These all derive + from `ConnectedRect`, which is what makes the deep-link scroll/flash work. +2. It has a `settingAnchor` property set to a unique kebab-case id. + +So to make a setting searchable, add a `settingAnchor` to its row: + +```qml +ToggleRow { + icon: "notifications" + label: qsTr("Show in fullscreen") + status: qsTr("Keep showing notifications over fullscreen apps") + settingAnchor: "notif-show-in-fullscreen" // ← add this + // … +} +``` + +Then regenerate the index (see "Regenerating the index" below) and commit. That's it — everything else is automatic: + +- **Page, sub-pages, breadcrumbs** are discovered from the page tree (`PageRegistry.qml` for icons/labels, + `PageCompRegistry.qml` for the hierarchy), so you don't list them anywhere. +- **The title** comes from the row's `label`. +- **The description** comes from the row's `subtext` or `status`. +- **The section** comes from the nearest `SectionHeader` above the row. +- **Search tokens** (the inverted index) are built from all of the above. + +#### Choosing a good anchor + +The anchor is a stable id used for deep-linking, not shown to the user. Keep it kebab-case and prefix it with the page so +ids stay unique and readable, e.g. `notif-default-timeout`, `apps-all-apps`, `ethernet-ip-address`. Once an anchor ships, +avoid renaming it gratuitously — it's the durable handle for that setting. + +#### Indexing a new or different row type + +The generator only looks at the row types listed in `ROW_RE`. If a setting uses a component that isn't in that list, +**it won't be indexed even if you add a `settingAnchor`** — the generator simply never sees it. This is an easy thing to +miss: the setting works fine in the UI but never shows up in search. + +This is exactly what happened with the "Default applications" rows (Terminal, Audio, Media playback, File manager) on the +Apps page. They use a `PopupRow` (via its `DefaultRow` alias) rather than a `ToggleRow`/`NavRow`, so they were invisible to +search until `PopupRow`/`DefaultRow` were added to `ROW_RE`. + +To make a new row type indexable: + +1. **Confirm it derives from `ConnectedRect`.** This is required — the deep-link scroll-and-flash relies on + `ConnectedRect`'s `settingAnchor` and `flashHighlight()`. A component that isn't a `ConnectedRect` (e.g. a bare + `M3TextField`) can't be deep-linked and shouldn't be added. +2. **Add the component name to `ROW_RE`** in `scripts/build-settings-index.py`. The generator matches on the literal name + as written in the QML, so if a page uses a local alias (like `DefaultRow` for `PopupRow`), add the alias too — or + better, add the underlying type and prefer using it directly. +3. **Make sure its title/description come from the expected properties.** The generator reads the title from `label` or + `text`, and the description from `subtext` or `status` (see `LABEL_RE` and `SUBTEXT_RE`). If your component exposes + those under different names, either alias them or extend the regexes. +4. Add `settingAnchor`s, regenerate, and commit. + +If you find yourself adding lots of one-off aliases, that's a sign the underlying row type (e.g. `PopupRow`) should be in +`ROW_RE` directly so future pages using it are indexed automatically. + +### Removing a setting from the search + +There are four ways, depending on how broadly you want to exclude: + +1. **One setting** — delete its `settingAnchor`. The row stays in the UI but drops out of search. This is the usual case. +2. **A title everywhere** — add the title to `SKIP_LABELS` in `scripts/build-settings-index.py`. Useful for generic labels + like `Muted` or `None` that would otherwise produce noise. +3. **A whole page** — remove the `settingAnchor` from every row on that page. +4. **Conditionally / at runtime** — filter in `NavLocations.qml`. This is how ethernet settings are hidden when no ethernet + is available: the results list drops entries whose anchor starts with `ethernet-` unless a wired connection exists. Use + this when "should it be searchable" depends on runtime state, not on the source. + +After options 1–3, regenerate the index and commit. Option 4 is pure QML and needs no regeneration. + +### Regenerating the index + +The build runs the generator automatically, so a normal `cmake --build` produces a fresh index. But `qs -c caelestia` +(used for quick iteration) does **not** run CMake, so after any change that affects the index you must regenerate it +manually before testing: + +```sh +python3 scripts/build-settings-index.py modules/nexus +``` + +During development the simplest flow is to point it at a temporary file and rebuild the plugin once, or just run a full +`cmake --build`. The committed source of truth is the generator and the page QML — there is no checked-in JSON to keep in +sync (the index lives inside the plugin binary, see below). + +> **Note:** changes that affect the index — adding/removing a `settingAnchor`, editing a `label`/`subtext`/`status`/ +> `SectionHeader`, or restructuring pages — only show up after the index is regenerated. Pure styling or behaviour changes +> to the search UI (`NavLocations.qml`, `SettingsSearcher.qml`) take effect with a plain `qs -c caelestia`. + +### Where the index lives + +The generated JSON is **embedded into the plugin binary as a Qt resource**, not installed as a config file. This keeps it +out of the user-editable config tree (it can't be accidentally edited or deleted), and means it ships wherever the module +is installed — manual build, AUR, Nix, all the same. + +The flow in CMake: + +1. `CMakeLists.txt` runs `build-settings-index.py` at configure time, before the plugin subdirectory, writing to + `${CMAKE_BINARY_DIR}/settings-index.json` (the `SETTINGS_INDEX_JSON` variable). +2. `plugin/src/Caelestia/CMakeLists.txt` adds that file to the `caelestia-core` module as a `RESOURCES` entry, with + `QT_RESOURCE_ALIAS` mapping it to the stable path `settings-index.json` regardless of the build-dir layout. +3. At runtime it is available at the qrc path `:/qt/qml/Caelestia/settings-index.json` (Qt's `qt_add_qml_module` prefixes + resources with `:/qt/qml//`). + +`CUtils::settingsIndex()` (in `plugin/src/Caelestia/cutils.{hpp,cpp}`) reads that resource and returns it as a string to +QML. + +> Because `rcc` compresses embedded resources, you won't see the JSON text with `strings` on the `.so` — that's expected, +> the data is there but zlib-compressed. To verify, log `CUtils.settingsIndex().length` from QML instead. + +### The generated JSON + +Schema (version 2): + +```jsonc +{ + "version": 2, + "entries": [ + { + "pageIdx": 0, // index of the owning top-level page + "subPath": [2, 9], // sub-page navigation path (empty = main page) + "crumbIcons": ["palette", "…"], // breadcrumb icons, page → setting + "crumbLabels": ["Wallpaper", "…"], // breadcrumb labels + "title": "Display wallpaper", // the setting label + "section": "Wallpaper", // nearest SectionHeader, if any + "subtext": "…", // description (subtext/status) + "anchor": "wallpaper-display" // settingAnchor, used for deep-linking + } + // … + ], + "inverted": { "token": [entryIdx, …] }, // inverted index: token → matching entries + "ranking": { "token": { "entryIdx": weight } } // per-token relevance weights +} +``` + +`title` weighs more than keyword tokens in ranking, so a query that hits a setting's name ranks above one that only hits +its description. + +### Runtime pieces + +| File | Role | +| --- | --- | +| `scripts/build-settings-index.py` | Parses page QML, builds the index JSON. | +| `SettingsSearcher.qml` | Singleton search service. Loads the index via `CUtils.settingsIndex()`, exposes `query(search)` over the inverted index, plus `highlight()` for match emphasis. | +| `NavLocations.qml` | Renders grouped result cards, runtime filtering (e.g. ethernet), click-to-navigate. | +| `NexusState.qml` | `jumpToSetting(pageIdx, subPath, anchor)` drives navigation + deferred scroll target. | +| `common/PageBase.qml` | `scrollToAnchor()` scrolls to and flashes the target row once the page is ready (handles async-loaded content). | +| `common/ConnectedRect.qml` | Base of the indexable rows; provides `settingAnchor` and the flash highlight. | +| `plugin/src/Caelestia/cutils.{hpp,cpp}` | `settingsIndex()` returns the embedded JSON to QML. | + +#### Search internals + +`query(search)` tokenizes the input, looks up each token in the inverted index (exact match first, then prefix — so `wall` +matches `wallpaper`), keeps only entries that match **all** tokens (AND semantics), sorts by summed relevance weight (ties +broken by entry id for stability), and caps the result count. Each result is exposed as a `SettingEntry` QObject so the UI +can bind to its fields. + +`highlight(text, search, colour)` wraps query-matched prefixes in a `` tag for display with `Text.StyledText`. +(StyledText supports `` but not CSS ``, which is a common gotcha.) + +### Gotchas + +- **`qs -c` won't regenerate the index.** Always rerun the generator after index-affecting edits, or do a full build. +- **Only `ConnectedRect`-derived rows can take a `settingAnchor`.** Plain `M3TextField`s and other non-`ConnectedRect` + components can't be deep-linked, so they can't be indexed this way. +- **A `settingAnchor` does nothing if the row type isn't in `ROW_RE`.** The generator only sees the row types it's told + about, so a new component (or a page-local alias) needs adding to `ROW_RE` first — otherwise the setting works in the UI + but silently never appears in search. See "Indexing a new or different row type" above. +- **Tokenization splits on non-alphanumerics.** A single query word won't match across a hyphen boundary in a hyphenated + name (e.g. `wifi` vs `Wi-Fi`): the result still appears via the index, but that exact word may not be highlighted. +- **Anchors are forever-ish.** They're the deep-link handle; renaming one is a breaking change for anything that linked to + it. + +
+ ## Credits Thanks to the Hyprland discord community (especially the homies in #rice-discussion) for all the help and suggestions diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml index 579c7a0cf..e0d2761c5 100644 --- a/modules/nexus/common/PageBase.qml +++ b/modules/nexus/common/PageBase.qml @@ -41,7 +41,7 @@ ColumnLayout { flickable.contentY = target; Qt.callLater(() => root.animateScroll = false); if (row.flashHighlight !== undefined) // qmllint disable missing-property - row.flashHighlight(); + row.flashHighlight(); // qmllint disable missing-property return true; } @@ -72,7 +72,7 @@ ColumnLayout { function highlightAnchor(anchor: string): void { const row = findAnchor(contentChild, anchor); if (row && row.flashHighlight !== undefined) // qmllint disable missing-property - row.flashHighlight(); + row.flashHighlight(); // qmllint disable missing-property } spacing: Tokens.spacing.extraLargeIncreased From c555a927de681071dc7d154d5168cd3412133bec Mon Sep 17 00:00:00 2001 From: Mestane <67807483+Mestane@users.noreply.github.com> Date: Mon, 29 Jun 2026 17:46:45 +0300 Subject: [PATCH 52/57] Move unavailable toggle settings (QuickToggle + Launcher) into cards --- modules/nexus/SettingsSearcher.qml | 35 ++++++++++++++++++++++++++ modules/nexus/navpane/NavLocations.qml | 26 +++++++++++++++++++ scripts/build-settings-index.py | 28 ++++++++++++++++++++- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 504e66290..92ba5475f 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -3,6 +3,7 @@ pragma Singleton import QtQuick import Quickshell import Caelestia +import Caelestia.Config // Search service over the settings index. The index is generated at build time // from the page QML files by scripts/build-settings-index.py and baked into the @@ -118,5 +119,39 @@ Singleton { readonly property string section: modelData.section ?? "" readonly property string subtext: modelData.subtext ?? "" readonly property string anchor: modelData.anchor ?? "" + + // A non-empty togglePath means this is a plain on/off setting that can be + // flipped straight from the results (e.g. "background.wallpaperEnabled"). + readonly property string togglePath: modelData.togglePath ?? "" + readonly property bool isToggle: togglePath.length > 0 + // Live value of the config property, read by walking the path on + // GlobalConfig. Re-evaluates when that property changes. + readonly property bool toggleValue: { + if (!isToggle) + return false; + let obj = GlobalConfig; + const parts = togglePath.split("."); + for (const part of parts) { + if (obj === undefined || obj === null) + return false; + obj = obj[part]; + } + return obj ?? false; + } + + // Write `value` back to the config property the path points at. + function setToggle(value: bool): void { + if (!isToggle) + return; + const parts = togglePath.split("."); + let obj = GlobalConfig; + for (let k = 0; k < parts.length - 1; k++) { + if (obj === undefined || obj === null) + return; + obj = obj[parts[k]]; + } + if (obj !== undefined && obj !== null) + obj[parts[parts.length - 1]] = value; + } } } diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 2aef66d73..481c6ea15 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -6,6 +6,7 @@ import Quickshell import Caelestia.Config import qs.components import qs.components.containers +import qs.components.controls import qs.services import qs.modules.nexus @@ -262,6 +263,8 @@ VerticalFadeFlickable { anchors.fill: parent anchors.margins: Tokens.padding.large + // Leave room on the right for the toggle switch. + anchors.rightMargin: result.modelData.togglePath ? toggle.width + Tokens.padding.large * 2 : Tokens.padding.large spacing: Tokens.spacing.small / 2 // Location line: deepest icon + "Section > sub", faint. @@ -323,6 +326,29 @@ VerticalFadeFlickable { root.nState.jumpToSetting(result.modelData.pageIdx, result.modelData.subPath, result.modelData.anchor); } } + + // For plain on/off settings, a switch on the right + // flips the value straight from the results (One UI + // style). It sits above the click layer (higher z) so + // tapping it toggles without also opening the page; + // tapping anywhere else still deep-links. + StyledSwitch { + id: toggle + + anchors.right: parent.right + anchors.rightMargin: Tokens.padding.large + anchors.verticalCenter: parent.verticalCenter + z: 2 + visible: result.modelData.togglePath + checked: result.modelData.toggleValue + cLayer: 3 + // A touch smaller than the in-page switches since + // the result rows are denser. + scale: 0.85 + transformOrigin: Item.Right + + onToggled: result.modelData.setToggle(checked) + } } } } diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 79e295d90..29f8ae64d 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -35,6 +35,13 @@ def read_lines(path: Path) -> tuple[str, ...]: ROW_RE = re.compile(r'^\s*(ToggleRow|SliderRow|SelectRow|StepperRow|NavRow|InfoRow|PopupRow|DefaultRow)\s*\{') LABEL_RE = re.compile(r'^\s*(?:label|text):\s*qsTr\("([^"]+)"\)') ANCHOR_RE = re.compile(r'^\s*settingAnchor:\s*"([^"]+)"') +# A ToggleRow whose value is a plain config property can be flipped straight from +# the search results. We capture the property path from `checked:` and require +# `onToggled:` to write the same path back (a symmetric binding), so reading and +# writing go through one path. Toggles bound to functions or multi-line handlers +# are left without a path and just deep-link as usual. +CHECKED_RE = re.compile(r'^\s*checked:\s*(?:GlobalConfig|Config)\.([\w.]+)\s*$') +ONTOGGLED_RE = re.compile(r'^\s*onToggled:\s*(?:GlobalConfig|Config)\.([\w.]+)\s*=\s*checked\s*$') ICON_RE = re.compile(r'^\s*icon:\s*"([^"]+)"') SKIP_LABELS = {"Muted", "None"} # Field weights for ranking: a token matching the title counts more than one @@ -258,8 +265,11 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] if m: section = m.group(1) break - if ROW_RE.match(lines[i]): + row_match = ROW_RE.match(lines[i]) + if row_match: + row_type = row_match.group(1) label = anchor = subtext = None + checked_path = toggled_path = None for j in range(i + 1, min(i + 12, len(lines))): if label is None: m = LABEL_RE.match(lines[j]) @@ -273,6 +283,21 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] st = SUBTEXT_RE.match(lines[j]) if st: subtext = st.group(1) + if checked_path is None: + ch = CHECKED_RE.match(lines[j]) + if ch: + checked_path = ch.group(1) + if toggled_path is None: + tg = ONTOGGLED_RE.match(lines[j]) + if tg: + toggled_path = tg.group(1) + # Only expose a toggle path when read and write target the same + # property (symmetric), so flipping from search is safe. + toggle_path = ( + checked_path + if row_type == "ToggleRow" and checked_path and checked_path == toggled_path + else "" + ) if label and label not in SKIP_LABELS and anchor: # keyword sources: breadcrumb path, section header, subtext. extra = " ".join(meta["crumbLabels"]) + " " + section + " " + (subtext or "") @@ -283,6 +308,7 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] "title": label, "anchor": anchor, "section": section, "subtext": subtext or "", + "togglePath": toggle_path, "keywords": " ".join(sorted(set(tokenize(label + " " + extra)))), }) i += 1 From 0f141e2bc51724b7aed4ae4059e7e2c11fe7753e Mon Sep 17 00:00:00 2001 From: Mestane <67807483+Mestane@users.noreply.github.com> Date: Mon, 29 Jun 2026 23:56:35 +0300 Subject: [PATCH 53/57] feat(nexus): add fuzzy fallback to settings search Fall back to the project's fzf over entry titles when the inverted index has no exact or prefix match, so typos still find settings. Index results lead; fzf only fills the gaps. --- README.md | 2 +- modules/nexus/SettingsSearcher.qml | 45 +++++++++++++++++++++++++- modules/nexus/navpane/NavLocations.qml | 3 +- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 889cb2e3c..411353837 100644 --- a/README.md +++ b/README.md @@ -901,7 +901,7 @@ The launcher pulls wallpapers from `~/Pictures/Wallpapers` by default. You can c the launcher only shows an odd number of wallpapers at one time. If you only have 2 wallpapers, consider getting more (or just putting one). -## Settings search +## Indexing settings The settings panel (nexus) has a full-text search that lets users jump straight to any setting by name, description, or the section/page it lives under. The index is generated from the page QML at build time and baked into the plugin binary, diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 92ba5475f..0165a2691 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -1,5 +1,6 @@ pragma Singleton +import "../../utils/scripts/fzf.js" as Fzf import QtQuick import Quickshell import Caelestia @@ -24,6 +25,10 @@ Singleton { // ranking: token -> { entry id (string): weight } property var inverted: ({}) property var ranking: ({}) + // fzf finder over the entries (title + keywords), used as a fuzzy fallback + // when the exact/prefix index lookup comes up short. fzf is the same matcher + // the launcher uses, so typo and mid-word matching behave consistently. + property var fzfFinder: null function query(search: string): list { const tokens = root.tokenize(search); @@ -48,7 +53,32 @@ Singleton { const ranked = Object.keys(scores).filter(id => hitCounts[id] === tokens.length).sort((a, b) => scores[b] - scores[a] || (parseInt(a) - parseInt(b))).slice(0, 25); const all = entries.instances; - return ranked.map(id => all[parseInt(id)]).filter(e => e !== undefined); + const out = ranked.map(id => all[parseInt(id)]).filter(e => e !== undefined); + + // The inverted index only does exact/prefix matches. When it finds little + // or nothing - a typo ("trasparency") or a mid-word query ("paper") - fall + // back to fzf over the same entries. fzf hits that the index already + // returned are skipped, and the rest are appended after the (stronger) + // index results, so precise matches always lead. + if (out.length < 5 && root.fzfFinder) { + const seen = ({}); + for (const id of ranked) + seen[id] = true; + const fuzzy = root.fzfFinder.find(search); + for (const r of fuzzy) { + const idx = r.item.idx; + if (seen[idx]) + continue; + seen[idx] = true; + const entry = all[idx]; + if (entry !== undefined) + out.push(entry); + if (out.length >= 25) + break; + } + } + + return out; } // Look up a query token in the inverted index: exact match first, then any @@ -66,6 +96,7 @@ Singleton { result[id] = w; } } + return result; } @@ -95,10 +126,22 @@ Singleton { entries.model = data.entries; root.inverted = data.inverted ?? {}; root.ranking = data.ranking ?? {}; + // One searchable string per entry: the title. fzf provides typo and + // mid-word matching over titles as a fallback when the exact/prefix + // index lookup comes up short. + const docs = data.entries.map((e, i) => ({ + idx: i, + text: e.title + })); + root.fzfFinder = new Fzf.Finder(docs, { + selector: d => d.text, + limit: 25 + }); } catch (e) { entries.model = []; root.inverted = {}; root.ranking = {}; + root.fzfFinder = null; } } diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 481c6ea15..3375d5260 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -246,7 +246,6 @@ VerticalFadeFlickable { bottomRightRadius: isLast ? Tokens.rounding.extraLarge : 0 color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) - // Thin divider between joined rows (not under the last one). StyledRect { anchors.bottom: parent.bottom anchors.left: parent.left @@ -255,7 +254,7 @@ VerticalFadeFlickable { anchors.rightMargin: Tokens.padding.large implicitHeight: 1 visible: !result.isLast - color: Colours.palette.m3outlineVariant + color: Qt.alpha(Colours.palette.m3outlineVariant, 0.5) } ColumnLayout { From d79186272a44684dfd6e7410b0d5040ce425458c Mon Sep 17 00:00:00 2001 From: Mestane <67807483+Mestane@users.noreply.github.com> Date: Tue, 30 Jun 2026 21:27:57 +0300 Subject: [PATCH 54/57] fix: stopwords indexing are,not,out and notification --- scripts/build-settings-index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build-settings-index.py b/scripts/build-settings-index.py index 29f8ae64d..1e8a3ba1d 100644 --- a/scripts/build-settings-index.py +++ b/scripts/build-settings-index.py @@ -47,7 +47,7 @@ def read_lines(path: Path) -> tuple[str, ...]: # Field weights for ranking: a token matching the title counts more than one # matching the keywords blob. FIELD_WEIGHT = {"title": 1.0, "keywords": 0.4} -STOPWORDS = {"the", "a", "an", "of", "and", "or", "to", "on", "in", "for"} +STOPWORDS = {"the", "a", "an", "of", "notification", "are", "not", "out", "and", "or", "to", "on", "in", "for"} def find_pages_dir(nexus: Path) -> Path: From 15a5ff0f28c9349c2d5059bf6728454c2c44bbfa Mon Sep 17 00:00:00 2001 From: Mestane <67807483+Mestane@users.noreply.github.com> Date: Thu, 2 Jul 2026 20:27:44 +0300 Subject: [PATCH 55/57] highlight has been rewritten and optimized --- modules/nexus/SettingsSearcher.qml | 51 ++++++++++++++++---------- modules/nexus/navpane/NavLocations.qml | 8 +++- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 0165a2691..6820057b4 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -20,11 +20,12 @@ import Caelestia.Config Singleton { id: root - // entries: forward index (one record per setting) - // inverted: token -> [entry id...] - // ranking: token -> { entry id (string): weight } property var inverted: ({}) property var ranking: ({}) + readonly property var highlightCache: ({ + "search": "", + "pattern": null + }) // fzf finder over the entries (title + keywords), used as a fuzzy fallback // when the exact/prefix index lookup comes up short. fzf is the same matcher // the launcher uses, so typo and mid-word matching behave consistently. @@ -48,18 +49,11 @@ Singleton { } } - // Sort by score, breaking ties by id so the order is stable (otherwise - // entries with equal scores can be dropped arbitrarily by the limit). const ranked = Object.keys(scores).filter(id => hitCounts[id] === tokens.length).sort((a, b) => scores[b] - scores[a] || (parseInt(a) - parseInt(b))).slice(0, 25); const all = entries.instances; const out = ranked.map(id => all[parseInt(id)]).filter(e => e !== undefined); - // The inverted index only does exact/prefix matches. When it finds little - // or nothing - a typo ("trasparency") or a mid-word query ("paper") - fall - // back to fzf over the same entries. fzf hits that the index already - // returned are skipped, and the rest are appended after the (stronger) - // index results, so precise matches always lead. if (out.length < 5 && root.fzfFinder) { const seen = ({}); for (const id of ranked) @@ -104,19 +98,36 @@ Singleton { return text.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 0); } - // Wrap the parts of `text` that match the search in the given colour, for use - // with a StyledText in Text.StyledText format. Matches each query token as a - // prefix at a word boundary (mirroring how lookup matches), so "wall" - // highlights the start of "wallpaper". StyledText supports but - // not CSS . HTML-significant characters are escaped first so the - // rich-text parser doesn't choke on names with & < or >. function highlight(text: string, search: string, colour: color): string { const escaped = text.replace(/&/g, "&").replace(//g, ">"); - const tokens = tokenize(search); - if (tokens.length === 0) + if (search.length === 0) return escaped; - const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); - const pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi"); + + // Rebuild the regex only when the search changes; every card reuses it. + const cache = root.highlightCache; + if (search !== cache.search) { + const tokens = root.tokenize(search); + cache.search = search; + if (tokens.length === 0) { + cache.pattern = null; + } else { + const escapedTokens = tokens.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); + cache.pattern = new RegExp("\\b(" + escapedTokens.join("|") + ")", "gi"); + } + } + + const pattern = cache.pattern; + if (!pattern) + return escaped; + + // Skip building (and later rich-text parsing) an HTML string when this + // text has no match - which is most subtexts. The caller checks for a + // "$1`); } diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index a3d1f706a..398f56509 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -289,7 +289,9 @@ VerticalFadeFlickable { StyledText { Layout.fillWidth: true text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3primary) - textFormat: Text.StyledText + // Only pay for rich-text parsing when the + // string actually carries a highlight tag. + textFormat: text.includes(" 0 text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) - textFormat: Text.StyledText + // Most subtexts have no match, so skip the + // rich-text parse unless there's a highlight. + textFormat: text.includes(" Date: Thu, 2 Jul 2026 23:54:32 +0300 Subject: [PATCH 56/57] feat(nexus): add animations for resultList --- modules/nexus/navpane/NavLocations.qml | 346 +++++++++++++------------ scripts/build-settings-index.py | 2 +- 2 files changed, 186 insertions(+), 162 deletions(-) diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 398f56509..352ab0681 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -162,199 +162,223 @@ VerticalFadeFlickable { } } - ListView { + Column { id: resultList - // Grouped results: the model is one entry per top-level page, and - // each delegate renders that page's heading plus the matching - // settings joined into a single rounded card (first/last rounded, - // middles square, thin dividers between them), like the Android - // settings search. A ScriptModel diffs the groups so only changed - // ones animate. Scrolling is delegated to the outer flickable. Layout.fillWidth: true - implicitHeight: contentHeight - interactive: false - cacheBuffer: 10000 spacing: Tokens.padding.large - // The list's implicitHeight tracks contentHeight; while items animate - // their position the reported height fluctuates, which left gaps in - // the surrounding layout on fast typing. So additions, removals and - // reordering are all instant - no transitions - keeping the height - // correct at every frame. - model: ScriptModel { - // Match groups by their page so content updates in place rather - // than rebuilding the delegate when ranking shifts the order. - objectProp: "pageIdx" - values: root.groups + add: Transition { + Anim { + type: Anim.DefaultEffects + property: "opacity" + from: 0 + to: 1 + } } - delegate: ColumnLayout { - id: group + move: Transition { + Anim { + properties: "x,y" + } - required property var modelData - required property int index + // A move may interrupt an in-flight add; drive opacity back to 1 + // so the interrupted fade doesn't leave the group half-visible. + Anim { + type: Anim.DefaultEffects + property: "opacity" + to: 1 + } + } - width: resultList.width - spacing: Tokens.spacing.small + Repeater { + model: ScriptModel { + objectProp: "pageIdx" + values: root.groups + } - // Group heading: the top-level page name, shown once. - RowLayout { - Layout.fillWidth: true - Layout.leftMargin: Tokens.padding.small - spacing: Tokens.spacing.small + ColumnLayout { + id: group - MaterialIcon { - text: group.modelData.icon - color: Colours.palette.m3primary - fontStyle: Tokens.font.icon.small - } + required property var modelData + required property int index - StyledText { + width: resultList.width + spacing: Tokens.spacing.small + + // Group heading: the top-level page name, shown once. + RowLayout { Layout.fillWidth: true - text: group.modelData.page - color: Colours.palette.m3primary - font: Tokens.font.label.large - elide: Text.ElideRight + Layout.leftMargin: Tokens.padding.small + spacing: Tokens.spacing.small + + MaterialIcon { + text: group.modelData.icon + color: Colours.palette.m3primary + fontStyle: Tokens.font.icon.small + } + + StyledText { + Layout.fillWidth: true + text: group.modelData.page + color: Colours.palette.m3primary + font: Tokens.font.label.large + elide: Text.ElideRight + } } - } - // The matching settings, joined into one card. - ColumnLayout { - Layout.fillWidth: true - spacing: 0 + Column { + id: cardList - Repeater { - model: group.modelData.entries + Layout.fillWidth: true + spacing: 0 - StyledRect { - id: result + add: Transition { + Anim { + type: Anim.DefaultEffects + property: "opacity" + from: 0 + to: 1 + } + } - required property var modelData - required property int index + move: Transition { + Anim { + properties: "x,y" + } - readonly property bool isFirst: index === 0 - readonly property bool isLast: index === group.modelData.entries.length - 1 + Anim { + type: Anim.DefaultEffects + property: "opacity" + to: 1 + } + } - Layout.fillWidth: true - implicitHeight: { - const h = resultLayout.implicitHeight + resultLayout.anchors.margins * 2; - return h % 2 === 0 ? h : h + 1; + Repeater { + model: ScriptModel { + objectProp: "anchor" + values: group.modelData.entries } - // Joined card: round only the outer corners so the - // rows read as one block (square where they meet), - // matching the page tabs' corner radius. - topLeftRadius: isFirst ? Tokens.rounding.extraLarge : 0 - topRightRadius: isFirst ? Tokens.rounding.extraLarge : 0 - bottomLeftRadius: isLast ? Tokens.rounding.extraLarge : 0 - bottomRightRadius: isLast ? Tokens.rounding.extraLarge : 0 - color: Colours.layer(Colours.palette.m3surfaceContainerHigh, 2) StyledRect { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Tokens.padding.large - anchors.rightMargin: Tokens.padding.large - implicitHeight: 1 - visible: !result.isLast - color: Qt.alpha(Colours.palette.m3outlineVariant, 0.5) - } + id: result - ColumnLayout { - id: resultLayout - - anchors.fill: parent - anchors.margins: Tokens.padding.large - // Leave room on the right for the toggle switch. - anchors.rightMargin: result.modelData.togglePath ? toggle.width + Tokens.padding.large * 2 : Tokens.padding.large - spacing: Tokens.spacing.small / 2 - - // Location line: deepest icon + "Section > sub", faint. - StyledText { - Layout.fillWidth: true - text: { - const labels = result.modelData.crumbLabels.slice(1); - const section = result.modelData.section; - const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels; - return parts.join(" \u203a "); - } - visible: text.length > 0 - color: Colours.palette.m3onSurfaceVariant - font: Tokens.font.label.small - elide: Text.ElideRight - } + required property var modelData + required property int index + + readonly property bool isFirst: index === 0 + readonly property bool isLast: index === group.modelData.entries.length - 1 - // The setting itself, most prominent. - StyledText { - Layout.fillWidth: true - text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3primary) - // Only pay for rich-text parsing when the - // string actually carries a highlight tag. - textFormat: text.includes(" 0 - text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) - // Most subtexts have no match, so skip the - // rich-text parse unless there's a highlight. - textFormat: text.includes(" sub", faint. + StyledText { + Layout.fillWidth: true + text: { + const labels = result.modelData.crumbLabels.slice(1); + const section = result.modelData.section; + const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels; + return parts.join(" \u203a "); + } + visible: text.length > 0 + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.label.small + elide: Text.ElideRight + } + + // The setting itself, most prominent. + StyledText { + Layout.fillWidth: true + text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3primary) + // Only pay for rich-text parsing when the + // string actually carries a highlight tag. + textFormat: text.includes(" 0 + text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) + // Most subtexts have no match, so skip the + // rich-text parse unless there's a highlight. + textFormat: text.includes(" tuple[str, ...]: # Field weights for ranking: a token matching the title counts more than one # matching the keywords blob. FIELD_WEIGHT = {"title": 1.0, "keywords": 0.4} -STOPWORDS = {"the", "a", "an", "of", "notification", "are", "not", "out", "and", "or", "to", "on", "in", "for"} +STOPWORDS = {"the", "a", "an", "of", "notification", "service", "are", "not", "out", "and", "or", "to", "on", "in", "for"} def find_pages_dir(nexus: Path) -> Path: From 26997a0e6c88bccfcb2fab46cc5acf30c71824ba Mon Sep 17 00:00:00 2001 From: Mestane <67807483+Mestane@users.noreply.github.com> Date: Fri, 3 Jul 2026 16:18:49 +0300 Subject: [PATCH 57/57] added Per-card icons --- modules/nexus/SettingsSearcher.qml | 23 +++++ modules/nexus/navpane/NavLocations.qml | 108 +++++++++++++------- scripts/build-settings-index.py | 134 ++++++++++++++++++++++++- 3 files changed, 229 insertions(+), 36 deletions(-) diff --git a/modules/nexus/SettingsSearcher.qml b/modules/nexus/SettingsSearcher.qml index 6820057b4..0ab9f509f 100644 --- a/modules/nexus/SettingsSearcher.qml +++ b/modules/nexus/SettingsSearcher.qml @@ -20,8 +20,16 @@ import Caelestia.Config Singleton { id: root + // entries: forward index (one record per setting) + // inverted: token -> [entry id...] + // ranking: token -> { entry id (string): weight } property var inverted: ({}) property var ranking: ({}) + // Cache the highlight regex so it's compiled once per search rather than + // once per card per keystroke. Held inside a plain JS object (never + // reassigned) because highlight() runs inside text bindings: writing to a + // real property from there would notify and re-trigger the binding - a + // binding loop. Mutating an object's fields emits no change signals. readonly property var highlightCache: ({ "search": "", "pattern": null @@ -49,11 +57,18 @@ Singleton { } } + // Sort by score, breaking ties by id so the order is stable (otherwise + // entries with equal scores can be dropped arbitrarily by the limit). const ranked = Object.keys(scores).filter(id => hitCounts[id] === tokens.length).sort((a, b) => scores[b] - scores[a] || (parseInt(a) - parseInt(b))).slice(0, 25); const all = entries.instances; const out = ranked.map(id => all[parseInt(id)]).filter(e => e !== undefined); + // The inverted index only does exact/prefix matches. When it finds little + // or nothing - a typo ("trasparency") or a mid-word query ("paper") - fall + // back to fzf over the same entries. fzf hits that the index already + // returned are skipped, and the rest are appended after the (stronger) + // index results, so precise matches always lead. if (out.length < 5 && root.fzfFinder) { const seen = ({}); for (const id of ranked) @@ -98,6 +113,12 @@ Singleton { return text.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 0); } + // Wrap the parts of `text` that match the search in the given colour, for use + // with a StyledText in Text.StyledText format. Matches each query token as a + // prefix at a word boundary (mirroring how lookup matches), so "wall" + // highlights the start of "wallpaper". StyledText supports but + // not CSS . HTML-significant characters are escaped first so the + // rich-text parser doesn't choke on names with & < or >. function highlight(text: string, search: string, colour: color): string { const escaped = text.replace(/&/g, "&").replace(//g, ">"); if (search.length === 0) @@ -173,6 +194,8 @@ Singleton { readonly property string section: modelData.section ?? "" readonly property string subtext: modelData.subtext ?? "" readonly property string anchor: modelData.anchor ?? "" + // The setting's own icon for the result card, baked by the index script. + readonly property string icon: modelData.icon ?? "" // A non-empty togglePath means this is a plain on/off setting that can be // flipped straight from the results (e.g. "background.wallpaperEnabled"). diff --git a/modules/nexus/navpane/NavLocations.qml b/modules/nexus/navpane/NavLocations.qml index 352ab0681..31a7fe341 100644 --- a/modules/nexus/navpane/NavLocations.qml +++ b/modules/nexus/navpane/NavLocations.qml @@ -165,6 +165,16 @@ VerticalFadeFlickable { Column { id: resultList + // Grouped results: one heading per top-level page with the matching + // settings joined into a rounded card underneath, like the Android + // settings search. A Column positioner instead of a ListView: its + // heights settle instantly (so new content is never hidden behind an + // animating clip and no hole opens where content left), while its + // `move` transition slides children whenever they reposition - which, + // unlike a ListView, includes repositioning caused by a sibling group + // growing or shrinking. The ScriptModel keyed by pageIdx keeps a + // surviving group's delegate alive so it slides rather than rebuilds; + // removed groups vanish and the move transition closes the space. Layout.fillWidth: true spacing: Tokens.padding.large @@ -227,6 +237,11 @@ VerticalFadeFlickable { } } + // The matching settings, joined into one card. Same Column + + // keyed-ScriptModel arrangement as the group list, for the same + // reasons: rows appear at their final spot immediately (fading + // in), removed rows vanish and the move transition slides the + // rest closed - no animated bounds to hide behind or lag behind. Column { id: cardList @@ -294,56 +309,74 @@ VerticalFadeFlickable { color: Qt.alpha(Colours.palette.m3outlineVariant, 0.5) } - ColumnLayout { + RowLayout { id: resultLayout anchors.fill: parent anchors.margins: Tokens.padding.large // Leave room on the right for the toggle switch. anchors.rightMargin: result.modelData.togglePath ? toggle.width + Tokens.padding.large * 2 : Tokens.padding.large - spacing: Tokens.spacing.small / 2 + spacing: Tokens.spacing.medium - // Location line: deepest icon + "Section > sub", faint. - StyledText { - Layout.fillWidth: true - text: { - const labels = result.modelData.crumbLabels.slice(1); - const section = result.modelData.section; - const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels; - return parts.join(" \u203a "); - } - visible: text.length > 0 + // The setting's own icon, baked into the + // index per anchor. + MaterialIcon { + text: result.modelData.icon color: Colours.palette.m3onSurfaceVariant - font: Tokens.font.label.small - elide: Text.ElideRight + fontStyle: Tokens.font.icon.medium } - // The setting itself, most prominent. - StyledText { + ColumnLayout { Layout.fillWidth: true - text: SettingsSearcher.highlight(result.modelData.title, root.search, Colours.palette.m3primary) - // Only pay for rich-text parsing when the - // string actually carries a highlight tag. - textFormat: text.includes(" sub", faint. + StyledText { + Layout.fillWidth: true + text: { + const labels = result.modelData.crumbLabels.slice(1); + const section = result.modelData.section; + const parts = section && section !== labels[labels.length - 1] ? labels.concat(section) : labels; + return parts.join(" \u203a "); + } + visible: text.length > 0 + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.label.small + elide: Text.ElideRight + } - // Optional description, faintest and smallest. - StyledText { - Layout.fillWidth: true - visible: result.modelData.subtext.length > 0 - text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) - // Most subtexts have no match, so skip the - // rich-text parse unless there's a highlight. - textFormat: text.includes(" 0 + text: SettingsSearcher.highlight(result.modelData.subtext, root.search, Colours.palette.m3primary) + // Most subtexts have no match, so skip the + // rich-text parse unless there's a highlight. + textFormat: text.includes(" tuple[str, ...]: # Field weights for ranking: a token matching the title counts more than one # matching the keywords blob. FIELD_WEIGHT = {"title": 1.0, "keywords": 0.4} -STOPWORDS = {"the", "a", "an", "of", "notification", "service", "are", "not", "out", "and", "or", "to", "on", "in", "for"} +STOPWORDS = {"the", "a", "an", "of", "notification", "are", "not", "out", "and", "or", "to", "on", "in", "for"} + +# The Material Symbols icon shown on each setting's search-result card, keyed +# by its anchor. Hand-picked so every setting reads at a glance and none just +# repeats its page's icon; anything unmapped (e.g. a newly added setting) +# falls back to the deepest breadcrumb icon. +SETTING_ICONS = { + "style-display-wallpaper": "wallpaper", + "style-transparency": "opacity", + "style-dark-theme": "dark_mode", + "network-wi-fi": "network_wifi", + "ethernet-status": "link", + "ethernet-interface": "settings_ethernet", + "ethernet-speed": "speed", + "ethernet-ip-address": "tag", + "ethernet-gateway": "router", + "ethernet-mac-address": "fingerprint", + "ethernet-ip-assignment": "tune", + "bluetooth-bluetooth": "bluetooth_connected", + "bluetooth-discoverable": "visibility", + "bluetooth-pairable": "add_link", + "audio-output": "speaker", + "audio-input": "mic", + "panels-dashboard": "space_dashboard", + "panels-taskbar": "toolbar", + "panels-launcher": "apps", + "panels-sidebar": "view_sidebar", + "dash-enabled": "toggle_on", + "dash-show-on-hover": "mouse", + "dash-dashboard": "tab", + "dash-media": "play_circle", + "dash-performance": "speed", + "dash-weather": "partly_cloudy_day", + "dash-battery": "battery_full", + "dash-gpu": "developer_board", + "dash-cpu": "memory", + "dash-memory": "memory_alt", + "dash-storage": "hard_drive", + "dash-network": "network_check", + "dash-drag-threshold": "drag_pan", + "taskbar-persistent": "push_pin", + "taskbar-show-on-hover": "mouse", + "taskbar-drag-threshold": "drag_pan", + "taskbar-workspaces": "workspaces", + "taskbar-active-window": "select_window", + "taskbar-tray": "widgets", + "taskbar-status-icons": "instant_mix", + "taskbar-clock": "schedule", + "taskbar-workspaces-2": "swipe", + "taskbar-volume": "volume_up", + "taskbar-brightness": "brightness_6", + "bar-ws-shown": "format_list_numbered", + "bar-ws-active-indicator": "radio_button_checked", + "bar-ws-active-trail": "gesture", + "bar-ws-occupied-background": "layers", + "bar-ws-show-windows": "grid_view", + "bar-ws-windows-on-special-workspaces": "star", + "bar-ws-max-window-icons": "filter_9_plus", + "bar-ws-per-monitor-workspaces": "desktop_windows", + "bar-aw-compact": "compress", + "bar-aw-inverted": "invert_colors", + "bar-aw-show-on-hover": "mouse", + "bar-aw-popout-on-hover": "open_in_new", + "bar-tray-background": "format_color_fill", + "bar-tray-recolour-icons": "format_paint", + "bar-tray-compact": "compress", + "bar-tray-popout-on-hover": "open_in_new", + "bar-si-speakers": "speaker", + "bar-si-microphone": "mic", + "bar-si-keyboard-layout": "keyboard", + "bar-si-network": "lan", + "bar-si-wi-fi": "network_wifi", + "bar-si-bluetooth": "bluetooth", + "bar-si-battery": "battery_full", + "bar-si-caps-lock": "keyboard_capslock_badge", + "bar-si-popout-on-hover": "open_in_new", + "bar-clock-background": "format_color_fill", + "bar-clock-show-date": "calendar_month", + "bar-clock-show-icon": "visibility", + "launcher-enabled": "toggle_on", + "launcher-show-on-hover": "mouse", + "launcher-max-items-shown": "format_list_numbered", + "launcher-max-wallpapers": "photo_library", + "launcher-drag-threshold": "drag_pan", + "launcher-vim-keybinds": "keyboard_command_key", + "launcher-enable-dangerous-actions": "warning", + "launcher-apps": "grid_view", + "launcher-actions": "bolt", + "launcher-schemes": "palette", + "launcher-variants": "contrast", + "launcher-wallpapers": "wallpaper", + "sidebar-enabled": "toggle_on", + "sidebar-drag-threshold": "drag_pan", + "apps-default-terminal": "terminal", + "apps-default-audio": "music_note", + "apps-default-playback": "play_circle", + "apps-default-file-manager": "folder", + "apps-all-apps": "view_apps", + "services-notifications": "notifications", + "services-media-refresh": "autorenew", + "services-system-stats-refresh": "monitoring", + "services-wi-fi-rescan": "wifi_find", + "services-lyrics-backend": "lyrics", + "services-default-player": "queue_music", + "services-volume-step": "volume_up", + "services-brightness-step": "brightness_6", + "services-max-volume": "vertical_align_top", + "services-visualiser-bars": "graphic_eq", + "services-smart-colour-scheme": "auto_awesome", + "services-gpu": "developer_board", + "notif-show-in-fullscreen": "fullscreen", + "notif-expire-automatically": "auto_delete", + "notif-open-expanded": "unfold_more", + "notif-default-timeout": "timer", + "notif-group-preview-count": "stacks", + "notif-show-in-fullscreen-2": "fullscreen", + "notif-visible-toasts": "filter_9_plus", + "notif-charging-changes": "battery_charging_full", + "notif-game-mode-changes": "sports_esports", + "notif-do-not-disturb-changes": "do_not_disturb_on", + "notif-audio-output-changes": "speaker", + "notif-audio-input-changes": "mic", + "notif-caps-lock-changes": "keyboard_capslock_badge", + "notif-num-lock-changes": "looks_one", + "notif-keyboard-layout-changes": "keyboard", + "notif-vpn-changes": "vpn_key", + "notif-now-playing": "play_circle", + "lang-temperature": "thermostat", + "lang-system-temperatures": "device_thermostat", + "lang-clock-format": "schedule", +} def find_pages_dir(nexus: Path) -> Path: @@ -309,6 +439,8 @@ def extract_settings(files: dict[str, Path], nav: dict[str, dict]) -> list[dict] "section": section, "subtext": subtext or "", "togglePath": toggle_path, + "icon": SETTING_ICONS.get(anchor) + or (meta["crumbIcons"][-1] if meta["crumbIcons"] else ""), "keywords": " ".join(sorted(set(tokenize(label + " " + extra)))), }) i += 1