Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions ryoku/hub/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@
upgrade, kernel included, rides along with the Ryoku packages
(`backend/config.go`, `quickshell/pages/UpdatesPage.qml`,
`quickshell/schema/UpdatesPage.js`).
- **The settings search is navigable by keyboard.** Typing in the rail search
now keeps a cursor over its results: Up and Down walk the hits (wrapping at
the ends), Enter opens the selected one instead of always the top hit, and
the header shows `N / TOTAL` so a long list is legible. The cursor resets on
every edit and on dismissal, so refining a query or reopening the field
never leaves a stale row selected. Moving the pointer over a row also moves
the cursor, and the keyboard and pointer highlights share one state, so a
click after a key press looks like a continuation rather than a jump
(`quickshell/Hub.ml`).
- **`Ctrl + F` also opens the settings search.** The rail finder answered only
to `Ctrl + K`; it now accepts `Ctrl + F` as well, the shortcut a user
instinctively reaches for in a settings app (`quickshell/Hub.ml`).
- **General manages people on this computer.** The Users tab lists local
accounts, sign-in state, roles, permissions and home storage, and lets an
administrator add or remove people, reset passwords and set storage limits
Expand Down
3 changes: 2 additions & 1 deletion ryoku/hub/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ edits stage in the canvas and only touch the live screens on Apply.

## Search

A global fuzzy finder lives in the sidebar (focus it with `Ctrl + K`). Typing
A global fuzzy finder lives in the sidebar (focus it with `Ctrl + K`, or the
more familiar `Ctrl + F`). Typing
searches content across every section: it ranks matching keybinds (each tagged
with its category) and lists matching section names you can jump to. The matcher
is a small subsequence scorer in `quickshell/fuzzy.js`.
Expand Down
43 changes: 35 additions & 8 deletions ryoku/hub/quickshell/Hub.qml
Original file line number Diff line number Diff line change
Expand Up @@ -1080,11 +1080,11 @@ Rectangle {

Keys.onEscapePressed: {
if (diffPop.open) diffPop.open = false;
else if (hub.query !== "") { hub.query = ""; searchField.clear(); }
else if (hub.query !== "") { hub.query = ""; searchField.clear(); hub.searchCursor = 0; }
else hub.requestQuit();
}
Keys.onPressed: (e) => {
if (e.key === Qt.Key_K && (e.modifiers & Qt.ControlModifier)) {
if ((e.key === Qt.Key_K || e.key === Qt.Key_F) && (e.modifiers & Qt.ControlModifier)) {
searchField.grabFocus();
e.accepted = true;
}
Expand Down Expand Up @@ -1139,8 +1139,20 @@ Rectangle {
width: parent.width
toolbar: true
placeholder: I18n.tr("Search settings…")
onEdited: (t) => hub.query = t
onAccepted: hub.activateSearch(0)
onEdited: (t) => { hub.query = t; hub.searchCursor = 0 }
onAccepted: hub.activateSearch(hub.searchCursor)
Keys.onUpPressed: (e) => {
if (hub.searchResults.length === 0) return;
hub.searchCursor = (hub.searchCursor - 1 + hub.searchResults.length) % hub.searchResults.length;
searchList.positionViewAtIndex(hub.searchCursor, ListView.Contain);
e.accepted = true;
}
Keys.onDownPressed: (e) => {
if (hub.searchResults.length === 0) return;
hub.searchCursor = (hub.searchCursor + 1) % hub.searchResults.length;
searchList.positionViewAtIndex(hub.searchCursor, ListView.Contain);
e.accepted = true;
}
}
}

Expand Down Expand Up @@ -1688,8 +1700,12 @@ Rectangle {
// The rail search opens a results card under the field (not a cramped rail
// list). Picking a result navigates to its page and, for a real setting,
// scrolls it into view and flashes it -- the jump-to-setting the old search
// never did. Enter takes the top hit; Escape (the field clears) dismisses.
// never did. Enter takes the selected hit; Escape (the field clears)
// dismisses; Up/Down walk the hits while the field keeps focus.
property string pendingFocusKey: ""
// Which hit the keyboard is on. Resets to 0 on every edit and on dismissal,
// so a refined query or a reopened search never selects a stale row.
property int searchCursor: 0
function activateSearch(i) {
var r = hub.searchResults[i];
if (!r) return;
Expand All @@ -1700,6 +1716,7 @@ Rectangle {
hub.pendingFocusKey = (r.isPage || !r.key) ? "" : r.key;
hub.query = "";
searchField.clear();
hub.searchCursor = 0;
if (hub.pendingFocusKey !== "") { focusTimer.tries = 0; focusTimer.restart(); }
}
// bold the matched run in a result label (StyledText).
Expand Down Expand Up @@ -1749,15 +1766,20 @@ Rectangle {
font.family: Tokens.mono; font.pixelSize: 9; font.letterSpacing: 1.2
anchors.verticalCenter: parent.verticalCenter
}
Item { width: Math.max(0, parent.width - 170); height: 1 }
Item { width: Math.max(0, parent.width - 210); height: 1 }
Text {
text: (hub.searchCursor + 1) + " / " + hub.searchResults.length
color: Tokens.ink; font.family: Tokens.mono; font.pixelSize: 9; font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: hub.searchResults.length + (hub.searchResults.length === 1 ? I18n.tr(" HIT") : I18n.tr(" HITS"))
color: Tokens.inkFaint; font.family: Tokens.mono; font.pixelSize: 9
anchors.verticalCenter: parent.verticalCenter
}
}
ListView {
id: list
id: searchList
anchors { left: parent.left; right: parent.right; top: head.bottom; bottom: parent.bottom }
anchors.margins: Tokens.s2; anchors.topMargin: Tokens.s1
clip: true
Expand All @@ -1772,7 +1794,11 @@ Rectangle {
width: ListView.view.width
height: 46
radius: Tokens.radius
color: rrh.containsMouse ? Tokens.tint10 : "transparent"
// the keyboard cursor and the pointer hover share one highlight:
// a result is active when either of them is on it, and the
// behavior eases between the two so a click after a key press
// looks like a continuation, not a jump.
color: (rrh.containsMouse || rr.index === hub.searchCursor) ? Tokens.tint10 : "transparent"
Behavior on color { ColorAnimation { duration: Tokens.snap } }
Column {
anchors { left: parent.left; right: kseal.left; verticalCenter: parent.verticalCenter }
Expand Down Expand Up @@ -1803,6 +1829,7 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: hub.searchCursor = rr.index
onClicked: hub.activateSearch(rr.index)
}
}
Expand Down
Loading