quickshell: Super+C keybind cheat sheet; spotify-player visualizer

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rope 2026-07-31 12:22:11 +01:00
parent a7a9ac6198
commit 4a38a2f0d9
3 changed files with 169 additions and 1 deletions

View file

@ -54,9 +54,10 @@ in
# spotify-player — native librespot TUI replacing the Electron Spotify app.
# stylix's spotify-player target writes the colour theme.
# MPRIS (quickshell's media card), notifications and streaming are all on by
# default on Linux, so no settings needed here.
# default on Linux, so only the off-by-default visualiser needs setting.
programs.spotify-player = lib.mkIf isDesktop {
enable = true;
settings.enable_audio_visualization = true;
};
# Upstream ships no .desktop file (TUI only), so the launcher can't find it.

View file

@ -360,6 +360,9 @@ in
-- Color picker copies hex to clipboard
hl.bind(mod .. " + A", hl.dsp.exec_cmd("hyprpicker -a"))
-- Keybind cheat sheet (quickshell overlay)
hl.bind(mod .. " + C", hl.dsp.exec_cmd("${qs} ipc call cheatsheet toggle"))
-- Mouse window manipulation
hl.bind(mod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
hl.bind(mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })

View file

@ -254,6 +254,7 @@ in
singleton Commands 1.0 Commands.qml
Bar 1.0 Bar.qml
Lock 1.0 Lock.qml
Cheatsheet 1.0 Cheatsheet.qml
'';
};
@ -523,6 +524,162 @@ in
'';
};
"quickshell/Cheatsheet.qml" = {
onChange = qsRestart;
text = ''
import Quickshell
import Quickshell.Wayland
import QtQuick
// Keybind cheat sheet Super+C routes here via shell.qml's
// "cheatsheet" IpcHandler. The list is hand-maintained: the real
// binds live in settings/hyprland.nix's Lua config and the
// spotify-player ones are that app's built-in defaults, so both
// need updating here too when they change.
Scope {
id: root
property bool open: false
readonly property var sections: [
{ title: "Apps", binds: [
["Super + T", "Terminal"],
["Super + E", "Files"],
["Super + Z", "Zen browser"],
["Super + R", "Launcher"],
["Super + I", "Audio settings"],
["Super + A", "Colour picker"],
["Super + C", "This cheat sheet"],
]},
{ title: "Windows", binds: [
["Super + Q", "Close window"],
["Super + V", "Toggle floating"],
["Super + F", "Fullscreen"],
["Super + P", "Pseudo tile"],
["Super + S", "Toggle split"],
["Super + drag", "Move window"],
["Super + right-drag", "Resize window"],
]},
{ title: "Focus & workspaces", binds: [
["Super + ", "Focus window"],
["Super + H/J/K", "Focus left/down/up"],
["Super + Shift + ", "Move window"],
["Super + 0-9", "Go to workspace"],
["Super + Shift + 0-9", "Send to workspace"],
["Super + scroll", "Cycle workspaces"],
]},
{ title: "Session", binds: [
["Super + L", "Power menu"],
["Super + Shift + E", "Exit Hyprland"],
["Super + Shift + S", "Screenshot region"],
["Print", "Screenshot screen"],
]},
{ title: "Spotify Player", binds: [
["?", "Built-in help"],
["space", "Play / pause"],
["n / p", "Next / previous"],
["+ / -", "Volume"],
["< / >", "Seek"],
["D", "Switch device"],
["/", "Search"],
["z", "Queue"],
["l", "Lyrics"],
["g l", "Library"],
["tab", "Next pane"],
["q", "Quit"],
]},
]
PanelWindow {
visible: root.open
WlrLayershell.namespace: "quickshell-cheatsheet"
WlrLayershell.layer: WlrLayer.Overlay
// Exclusive works here (unlike the bar): this window uses no
// HyprlandFocusGrab, so nothing fights it for focus.
WlrLayershell.keyboardFocus: root.open
? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
exclusionMode: ExclusionMode.Ignore
anchors { top: true; left: true; right: true; bottom: true }
color: "transparent"
// Click anywhere outside the card to dismiss.
MouseArea {
anchors.fill: parent
onClicked: root.open = false
Rectangle { anchors.fill: parent; color: "#99000000" }
}
Item {
anchors.fill: parent
focus: true
Keys.onPressed: e => {
if (e.key === Qt.Key_Escape || e.key === Qt.Key_C
|| e.key === Qt.Key_Q)
root.open = false;
}
Rectangle {
anchors.centerIn: parent
width: grid.width + Theme.panelGap * 6
height: grid.height + Theme.panelGap * 6
radius: Theme.radius
color: Theme.cardBg
border.width: Theme.borderWidth
border.color: Theme.base02
// Swallow clicks on the card so it doesn't close.
MouseArea { anchors.fill: parent }
Row {
id: grid
anchors.centerIn: parent
spacing: Theme.panelGap * 4
Repeater {
model: root.sections
Column {
required property var modelData
spacing: 4
Text {
text: modelData.title
font.family: Theme.fontFamily
font.pixelSize: 15
font.bold: true
color: Theme.base0D
bottomPadding: 4
}
Repeater {
model: modelData.binds
Row {
required property var modelData
spacing: 10
Text {
width: 150
text: modelData[0]
font.family: Theme.fontFamily
font.pixelSize: 13
color: Theme.base0A
}
Text {
text: modelData[1]
font.family: Theme.fontFamily
font.pixelSize: 13
color: Theme.base05
}
}
}
}
}
}
}
}
}
}
'';
};
"quickshell/Commands.qml" = {
onChange = qsRestart;
text = ''
@ -574,6 +731,13 @@ in
function powermenu(): void { if (root.mainBar) root.mainBar.toggleSession(); }
}
// Keybind cheat sheet Super+C in hyprland.nix.
Cheatsheet { id: cheatsheet }
IpcHandler {
target: "cheatsheet"
function toggle(): void { cheatsheet.open = !cheatsheet.open; }
}
// Soft reload, used by the nix onChange hook keeps the
// process and its DBus services (tray host) alive.
IpcHandler {