quickshell: fuzzy launcher search; content reveals/wipes with the chrome morph
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
21db9825d5
commit
f2cf842ace
1 changed files with 37 additions and 15 deletions
|
|
@ -230,10 +230,21 @@ in
|
|||
|
||||
function score(name, extra, q) {
|
||||
let n = name.toLowerCase();
|
||||
if (n.startsWith(q)) return 3;
|
||||
if (n.includes(" " + q)) return 2;
|
||||
if (n.includes(q)) return 1;
|
||||
if (extra && extra.toLowerCase().includes(q)) return 1;
|
||||
if (n.startsWith(q)) return 5;
|
||||
if (n.includes(" " + q)) return 4;
|
||||
if (n.includes(q)) return 3;
|
||||
if (extra && extra.toLowerCase().includes(q)) return 2;
|
||||
// Fuzzy: q as an in-order subsequence of n (vktop →
|
||||
// vesktop); fewer skipped characters scores higher.
|
||||
let qi = 0, gaps = 0, last = -1;
|
||||
for (let i = 0; i < n.length && qi < q.length; i++) {
|
||||
if (n[i] === q[qi]) {
|
||||
if (last >= 0) gaps += i - last - 1;
|
||||
last = i;
|
||||
qi++;
|
||||
}
|
||||
}
|
||||
if (qi === q.length) return 1 / (1 + gaps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -575,8 +586,12 @@ in
|
|||
if (dd.visible && !dd.closing) {
|
||||
dd.animateClose();
|
||||
} else {
|
||||
if (activeDropdown && activeDropdown !== dd && activeDropdown.visible) {
|
||||
activeDropdown.animateClose();
|
||||
// Retarget the chrome before closing the previous
|
||||
// dropdown so it morphs instead of dipping closed.
|
||||
const prev = activeDropdown;
|
||||
activeDropdown = dd;
|
||||
if (prev && prev !== dd && prev.visible) {
|
||||
prev.animateClose();
|
||||
}
|
||||
if (setupFn) setupFn();
|
||||
if (dd.closing) {
|
||||
|
|
@ -584,7 +599,6 @@ in
|
|||
} else {
|
||||
dd.visible = true;
|
||||
}
|
||||
activeDropdown = dd;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1080,6 +1094,11 @@ in
|
|||
if (!visible || closing) return;
|
||||
closing = true;
|
||||
open = false;
|
||||
// Collapse the chrome immediately so the content fade
|
||||
// and the panel animation run together (when switching
|
||||
// dropdowns, toggleDropdown retargets activeDropdown
|
||||
// first, so this doesn't fire and the chrome morphs).
|
||||
if (bar.activeDropdown === dropdown) bar.activeDropdown = null;
|
||||
_autoClose.stop();
|
||||
_closeDelay.start();
|
||||
}
|
||||
|
|
@ -1126,7 +1145,7 @@ in
|
|||
|
||||
Timer {
|
||||
id: _closeDelay
|
||||
interval: 230
|
||||
interval: 300
|
||||
onTriggered: { dropdown.visible = false; dropdown.closing = false; if (bar.activeDropdown === dropdown) bar.activeDropdown = null; }
|
||||
}
|
||||
|
||||
|
|
@ -1137,23 +1156,26 @@ in
|
|||
}
|
||||
}
|
||||
|
||||
// Content clipped to the chrome's animated height so it
|
||||
// reveals/hides with the morph; fades on open/close.
|
||||
// Content is clipped to the chrome's ANIMATED geometry —
|
||||
// revealed as the panel slides/grows over it and wiped as
|
||||
// the panel leaves, instead of popping in place. The inner
|
||||
// item counter-offsets so content stays put while the clip
|
||||
// window moves across it.
|
||||
Item {
|
||||
id: _dropdownRect
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
anchors.top: parent.top
|
||||
width: dropdown.fullWidth
|
||||
x: (chrome.x + 8) - dropdown.x
|
||||
y: 0
|
||||
width: Math.max(0, chrome.width - (chrome.flushRight ? 8 : 16))
|
||||
height: Math.min(dropdown.fullHeight, chrome.height)
|
||||
clip: true
|
||||
opacity: dropdown.open ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 150; easing.type: Easing.OutCubic }
|
||||
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
Item {
|
||||
id: dropdownContent
|
||||
x: 8 - _dropdownRect.x
|
||||
width: dropdown.fullWidth
|
||||
height: dropdown.fullHeight
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue