feat(quickshell): add dense telemetry bar #4
@@ -17,7 +17,7 @@ Scope {
|
||||
SideBar {}
|
||||
BarBottom {}
|
||||
|
||||
// App launcher variants — SUPER CTRL 1–8; variant 8 is the primary HUD.
|
||||
// App launcher variants — SUPER CTRL 1–9; variant 8 remains the primary HUD.
|
||||
LauncherStack {} // 1 — left vertical list
|
||||
LauncherGrid {} // 2 — centered icon grid
|
||||
LauncherSpotlight {} // 3 — top-center command bar
|
||||
@@ -26,6 +26,7 @@ Scope {
|
||||
LauncherSlant {} // 6 — angular / sheared panel
|
||||
LauncherCorner {} // 7 — Slant (V6) copy + floating power panel (shutdown/reboot)
|
||||
ApplicationLauncher {} // 8 — dense HUD command index (primary)
|
||||
BladeLauncher {} // 9 — asymmetric blade matrix
|
||||
|
||||
Notifications {}
|
||||
VolumeOsd {}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import QtQuick
|
||||
import qs.widgets.launcher
|
||||
|
||||
BladeLauncherContent {
|
||||
width: 1120
|
||||
height: 640
|
||||
query: "dev"
|
||||
selectedIndex: 2
|
||||
showIcons: false
|
||||
apps: [
|
||||
{ name: "Visual Studio Code", genericName: "Code Editor", comment: "Edit and debug software projects", icon: "visual-studio-code", categories: ["Development"] },
|
||||
{ name: "GitKraken", genericName: "Git Client", comment: "Inspect branches and repository history", icon: "gitkraken", categories: ["Development"] },
|
||||
{ name: "OpenCode", genericName: "AI Development", comment: "Agentic terminal coding environment", icon: "utilities-terminal", categories: ["Development", "Utility"] },
|
||||
{ name: "Alacritty", genericName: "Terminal Emulator", comment: "GPU accelerated command interface", icon: "utilities-terminal", categories: ["System"] },
|
||||
{ name: "Vivaldi", genericName: "Web Browser", comment: "Access network and web applications", icon: "vivaldi", categories: ["Network"] },
|
||||
{ name: "Obsidian", genericName: "Knowledge Base", comment: "Local-first markdown workspace", icon: "obsidian", categories: ["Office"] },
|
||||
{ name: "Blender", genericName: "3D Creation", comment: "Model, animate and render 3D scenes", icon: "blender", categories: ["Graphics"] },
|
||||
{ name: "Steam", genericName: "Game Platform", comment: "Launch and manage games", icon: "steam", categories: ["Game"] }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import qs.widgets.theme
|
||||
|
||||
// Variant 9 — asymmetric Blade application launcher.
|
||||
Scope {
|
||||
id: root
|
||||
|
||||
property bool active: false
|
||||
function toggle() { root.active = !root.active; }
|
||||
|
||||
GlobalShortcut {
|
||||
name: "launcher9"
|
||||
description: "Toggle app launcher (Blade matrix)"
|
||||
onPressed: root.toggle()
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: win
|
||||
visible: root.active
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
color: Theme.textAlpha(0)
|
||||
|
||||
anchors { top: true; left: true; right: true; bottom: true }
|
||||
|
||||
property int selectedIndex: 0
|
||||
|
||||
function clampSelection(index) {
|
||||
return model.apps.length === 0 ? 0 : Math.max(0, Math.min(model.apps.length - 1, index));
|
||||
}
|
||||
function move(delta) {
|
||||
const count = model.apps.length;
|
||||
if (count === 0)
|
||||
return;
|
||||
selectedIndex = ((selectedIndex + delta) % count + count) % count;
|
||||
}
|
||||
function launch(index) {
|
||||
if (model.launch(index))
|
||||
root.active = false;
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
content.clearSearch();
|
||||
selectedIndex = 0;
|
||||
content.focusSearch();
|
||||
}
|
||||
}
|
||||
|
||||
AppModel { id: model; search: content.query }
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Theme.surface
|
||||
opacity: 0.78
|
||||
MouseArea { anchors.fill: parent; onClicked: root.active = false }
|
||||
}
|
||||
|
||||
BladeLauncherContent {
|
||||
id: content
|
||||
anchors.centerIn: parent
|
||||
width: 1120
|
||||
height: 640
|
||||
scale: Math.min(1, (parent.width - 56) / width, (parent.height - 56) / height)
|
||||
transformOrigin: Item.Center
|
||||
apps: model.apps
|
||||
selectedIndex: win.selectedIndex
|
||||
onSelectionRequested: index => win.selectedIndex = win.clampSelection(index)
|
||||
onMoveRequested: delta => win.move(delta)
|
||||
onLaunchRequested: index => win.launch(index)
|
||||
onDismissRequested: root.active = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,473 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Shapes
|
||||
import qs.widgets.theme
|
||||
|
||||
// Variant 9 visual core: asymmetric "Blade" composition. It shares the shell
|
||||
// Theme and AppModel contract, but intentionally does not reuse StatusBarPanel
|
||||
// or the nested-panel structure of ApplicationLauncherContent.
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var apps: []
|
||||
property int selectedIndex: 0
|
||||
property bool showIcons: true
|
||||
property alias query: commandInput.text
|
||||
|
||||
readonly property var selectedApp: apps.length > 0 && selectedIndex >= 0 && selectedIndex < apps.length
|
||||
? apps[selectedIndex] : null
|
||||
|
||||
signal selectionRequested(int index)
|
||||
signal moveRequested(int delta)
|
||||
signal launchRequested(int index)
|
||||
signal dismissRequested
|
||||
|
||||
function focusSearch() { commandInput.forceActiveFocus(); }
|
||||
function clearSearch() { commandInput.text = ""; }
|
||||
|
||||
implicitWidth: 1120
|
||||
implicitHeight: 640
|
||||
|
||||
component MicroText: Text {
|
||||
color: Theme.muted
|
||||
font.family: Theme.microFont
|
||||
font.pixelSize: 7
|
||||
font.letterSpacing: 0.9
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
Rectangle { anchors.fill: parent; color: Theme.surface }
|
||||
|
||||
// Sparse circuit traces behind the active surfaces.
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0)
|
||||
strokeColor: Theme.accentAlpha(0.24)
|
||||
strokeWidth: 1
|
||||
startX: 24; startY: 92
|
||||
PathLine { x: 115; y: 92 }
|
||||
PathLine { x: 138; y: 69 }
|
||||
PathLine { x: 480; y: 69 }
|
||||
PathLine { x: 494; y: 55 }
|
||||
PathLine { x: 840; y: 55 }
|
||||
}
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0)
|
||||
strokeColor: Theme.hair
|
||||
strokeWidth: 1
|
||||
startX: 115; startY: 570
|
||||
PathLine { x: 146; y: 601 }
|
||||
PathLine { x: 775; y: 601 }
|
||||
PathLine { x: 801; y: 575 }
|
||||
PathLine { x: 1095; y: 575 }
|
||||
}
|
||||
}
|
||||
|
||||
// Top command mast — an open angular frame rather than panel chrome.
|
||||
Shape {
|
||||
id: mast
|
||||
x: 26; y: 18
|
||||
width: parent.width - 52; height: 72
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0.018)
|
||||
strokeColor: Theme.hair
|
||||
strokeWidth: 1
|
||||
startX: 0; startY: 17
|
||||
PathLine { x: 17; y: 0 }
|
||||
PathLine { x: mast.width - 110; y: 0 }
|
||||
PathLine { x: mast.width - 88; y: 22 }
|
||||
PathLine { x: mast.width; y: 22 }
|
||||
PathLine { x: mast.width; y: mast.height }
|
||||
PathLine { x: 0; y: mast.height }
|
||||
PathLine { x: 0; y: 17 }
|
||||
}
|
||||
ShapePath {
|
||||
fillColor: Theme.accent
|
||||
strokeWidth: 0
|
||||
startX: 0; startY: 17
|
||||
PathLine { x: 17; y: 0 }
|
||||
PathLine { x: 122; y: 0 }
|
||||
PathLine { x: 116; y: 4 }
|
||||
PathLine { x: 20; y: 4 }
|
||||
PathLine { x: 4; y: 20 }
|
||||
PathLine { x: 4; y: mast.height }
|
||||
PathLine { x: 0; y: mast.height }
|
||||
PathLine { x: 0; y: 17 }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
x: 54; y: 31
|
||||
text: "BLADE // EXECUTION MATRIX"
|
||||
color: Theme.text
|
||||
font.family: Theme.displayFont
|
||||
font.pixelSize: 16
|
||||
font.bold: true
|
||||
font.letterSpacing: 1.4
|
||||
}
|
||||
MicroText { x: 56; y: 57; text: "09 / APPLICATION ROUTER / LOCAL DESKTOP ENTRIES"; color: Theme.accent }
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 48
|
||||
y: 37
|
||||
spacing: 4
|
||||
Repeater {
|
||||
model: 16
|
||||
Rectangle {
|
||||
required property int index
|
||||
width: 9; height: index % 4 === 0 ? 16 : 8
|
||||
y: index % 4 === 0 ? 0 : 8
|
||||
color: index < Math.min(16, root.apps.length + 6) ? Theme.accent : Theme.hair
|
||||
transform: Rotation { angle: -28 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Left category rotor and mode spine.
|
||||
Item {
|
||||
id: rotorZone
|
||||
x: 26; y: 108
|
||||
width: 188; height: 444
|
||||
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0.018)
|
||||
strokeColor: Theme.hair
|
||||
strokeWidth: 1
|
||||
startX: 0; startY: 0
|
||||
PathLine { x: 154; y: 0 }
|
||||
PathLine { x: 188; y: 34 }
|
||||
PathLine { x: 188; y: 408 }
|
||||
PathLine { x: 152; y: 444 }
|
||||
PathLine { x: 0; y: 444 }
|
||||
PathLine { x: 0; y: 0 }
|
||||
}
|
||||
ShapePath {
|
||||
fillColor: Theme.accent
|
||||
strokeWidth: 0
|
||||
startX: 0; startY: 0
|
||||
PathLine { x: 7; y: 0 }
|
||||
PathLine { x: 7; y: 444 }
|
||||
PathLine { x: 0; y: 444 }
|
||||
PathLine { x: 0; y: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
x: 20; y: 18
|
||||
text: "VECTOR"
|
||||
color: Theme.accent
|
||||
font.family: Theme.displayFont
|
||||
font.pixelSize: 11
|
||||
font.bold: true
|
||||
font.letterSpacing: 1.4
|
||||
}
|
||||
MicroText { x: 20; y: 38; text: "CATEGORY BUS" }
|
||||
|
||||
Item {
|
||||
id: rotor
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: 70; width: 126; height: 126
|
||||
Rectangle { anchors.centerIn: parent; width: 116; height: 116; radius: 58; color: Theme.textAlpha(0); border.width: 1; border.color: Theme.accentAlpha(0.55) }
|
||||
Rectangle { anchors.centerIn: parent; width: 82; height: 82; radius: 41; color: Theme.textAlpha(0); border.width: 1; border.color: Theme.hair }
|
||||
Rectangle { anchors.centerIn: parent; width: 126; height: 1; color: Theme.hair }
|
||||
Rectangle { anchors.centerIn: parent; width: 1; height: 126; color: Theme.hair }
|
||||
Rectangle { anchors.centerIn: parent; width: 32; height: 32; color: Theme.accentAlpha(0.18); border.width: 1; border.color: Theme.accent; transform: Rotation { angle: 45 } }
|
||||
Text { anchors.centerIn: parent; text: "A"; color: Theme.accent; font.family: Theme.displayFont; font.pixelSize: 16; font.bold: true }
|
||||
Repeater {
|
||||
model: 4
|
||||
Rectangle {
|
||||
required property int index
|
||||
width: 6; height: 6; radius: 3
|
||||
x: [16, 101, 101, 16][index]
|
||||
y: [16, 16, 101, 101][index]
|
||||
color: Theme.accent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
x: 18; y: 218
|
||||
width: parent.width - 38
|
||||
spacing: 7
|
||||
Repeater {
|
||||
model: ["ALL TARGETS", "SYSTEM", "DEVELOP", "NETWORK", "MEDIA"]
|
||||
Rectangle {
|
||||
required property int index
|
||||
required property string modelData
|
||||
width: parent.width - index * 5
|
||||
height: 31
|
||||
x: index * 5
|
||||
color: index === 0 ? Theme.accentAlpha(0.14) : Theme.textAlpha(0.025)
|
||||
border.width: 1
|
||||
border.color: index === 0 ? Theme.accent : Theme.hair
|
||||
Text {
|
||||
x: 9; anchors.verticalCenter: parent.verticalCenter
|
||||
text: String(index).padStart(2, "0") + " " + modelData
|
||||
color: index === 0 ? Theme.accent : Theme.muted
|
||||
font.family: Theme.microFont
|
||||
font.pixelSize: 7
|
||||
font.bold: index === 0
|
||||
font.letterSpacing: 0.7
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MicroText { x: 18; anchors.bottom: parent.bottom; anchors.bottomMargin: 14; text: "BUS // UNFILTERED"; color: Theme.accent }
|
||||
}
|
||||
|
||||
// Central command spine.
|
||||
Item {
|
||||
id: commandZone
|
||||
x: 230; y: 108
|
||||
width: 594; height: 486
|
||||
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0.012)
|
||||
strokeColor: Theme.hair
|
||||
strokeWidth: 1
|
||||
startX: 20; startY: 0
|
||||
PathLine { x: commandZone.width; y: 0 }
|
||||
PathLine { x: commandZone.width - 20; y: commandZone.height }
|
||||
PathLine { x: 0; y: commandZone.height }
|
||||
PathLine { x: 20; y: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
// Search blade.
|
||||
Shape {
|
||||
id: searchBlade
|
||||
x: 12; y: 12; width: parent.width - 32; height: 58
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: Theme.accentAlpha(0.10)
|
||||
strokeColor: Theme.accent
|
||||
strokeWidth: 1
|
||||
startX: 18; startY: 0
|
||||
PathLine { x: searchBlade.width; y: 0 }
|
||||
PathLine { x: searchBlade.width - 18; y: searchBlade.height }
|
||||
PathLine { x: 0; y: searchBlade.height }
|
||||
PathLine { x: 18; y: 0 }
|
||||
}
|
||||
}
|
||||
Text { x: 32; y: 28; text: ">"; color: Theme.accent; font.family: Theme.displayFont; font.pixelSize: 20; font.bold: true }
|
||||
TextInput {
|
||||
id: commandInput
|
||||
x: 62; y: 22; width: 430; height: 38
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
color: Theme.text
|
||||
selectionColor: Theme.accent
|
||||
selectedTextColor: Theme.surface
|
||||
font.family: Theme.displayFont
|
||||
font.pixelSize: 17
|
||||
font.letterSpacing: 1
|
||||
clip: true
|
||||
onTextChanged: root.selectionRequested(0)
|
||||
Keys.onPressed: event => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Down: case Qt.Key_Tab: root.moveRequested(1); event.accepted = true; break;
|
||||
case Qt.Key_Up: case Qt.Key_Backtab: root.moveRequested(-1); event.accepted = true; break;
|
||||
case Qt.Key_PageDown: root.moveRequested(5); event.accepted = true; break;
|
||||
case Qt.Key_PageUp: root.moveRequested(-5); event.accepted = true; break;
|
||||
case Qt.Key_Return: case Qt.Key_Enter: root.launchRequested(root.selectedIndex); event.accepted = true; break;
|
||||
case Qt.Key_Escape: root.dismissRequested(); event.accepted = true; break;
|
||||
}
|
||||
}
|
||||
Text { anchors.fill: parent; verticalAlignment: Text.AlignVCenter; visible: commandInput.text.length === 0; text: "ACQUIRE TARGET"; color: Theme.muted; font: commandInput.font }
|
||||
}
|
||||
MicroText { anchors.right: parent.right; anchors.rightMargin: 38; y: 35; text: root.apps.length + " HIT"; color: Theme.accent }
|
||||
|
||||
ListView {
|
||||
id: bladeList
|
||||
x: 10; y: 84; width: parent.width - 26; height: 382
|
||||
model: root.apps
|
||||
currentIndex: root.selectedIndex
|
||||
clip: true
|
||||
spacing: 4
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
onCurrentIndexChanged: positionViewAtIndex(currentIndex, ListView.Contain)
|
||||
|
||||
delegate: MouseArea {
|
||||
id: blade
|
||||
required property int index
|
||||
required property var modelData
|
||||
readonly property bool selected: index === root.selectedIndex
|
||||
width: ListView.view.width - (index % 2 === 0 ? 0 : 16)
|
||||
height: 43
|
||||
x: index % 2 === 0 ? 0 : 16
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onEntered: root.selectionRequested(index)
|
||||
onClicked: root.launchRequested(index)
|
||||
|
||||
Shape {
|
||||
id: bladeShape
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: blade.selected ? Theme.selection : Theme.textAlpha(0.025)
|
||||
strokeColor: blade.selected ? Theme.accent : Theme.textAlpha(0.12)
|
||||
strokeWidth: 1
|
||||
startX: 16; startY: 0
|
||||
PathLine { x: bladeShape.width; y: 0 }
|
||||
PathLine { x: bladeShape.width - 24; y: bladeShape.height }
|
||||
PathLine { x: 0; y: bladeShape.height }
|
||||
PathLine { x: 16; y: 0 }
|
||||
}
|
||||
ShapePath {
|
||||
fillColor: blade.selected ? Theme.accent : Theme.textAlpha(0.12)
|
||||
strokeWidth: 0
|
||||
startX: 16; startY: 0
|
||||
PathLine { x: 22; y: 0 }
|
||||
PathLine { x: 6; y: bladeShape.height }
|
||||
PathLine { x: 0; y: bladeShape.height }
|
||||
PathLine { x: 16; y: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 26
|
||||
anchors.rightMargin: 28
|
||||
spacing: 10
|
||||
Text { Layout.preferredWidth: 26; text: String(blade.index + 1).padStart(2, "0"); color: blade.selected ? Theme.accent : Theme.muted; font.family: Theme.microFont; font.pixelSize: 7 }
|
||||
Rectangle {
|
||||
Layout.preferredWidth: 28; Layout.preferredHeight: 28
|
||||
color: blade.selected ? Theme.accentAlpha(0.14) : Theme.textAlpha(0.025)
|
||||
border.width: 1; border.color: blade.selected ? Theme.accent : Theme.hair
|
||||
IconImage { visible: root.showIcons; anchors.centerIn: parent; implicitSize: 20; source: root.showIcons ? Quickshell.iconPath(blade.modelData.icon || "application-x-executable", "application-x-executable") : "" }
|
||||
Text { visible: !root.showIcons; anchors.centerIn: parent; text: String(blade.modelData.name || "?").charAt(0).toUpperCase(); color: blade.selected ? Theme.accent : Theme.text; font.family: Theme.displayFont; font.pixelSize: 11; font.bold: true }
|
||||
}
|
||||
Text { Layout.fillWidth: true; text: blade.modelData.name || "UNKNOWN"; color: blade.selected ? Theme.accent : Theme.text; font.family: Theme.displayFont; font.pixelSize: 10; font.bold: blade.selected; elide: Text.ElideRight }
|
||||
MicroText { Layout.preferredWidth: 125; horizontalAlignment: Text.AlignRight; text: blade.modelData.genericName || "APPLICATION" }
|
||||
Rectangle { Layout.preferredWidth: blade.selected ? 32 : 12; Layout.preferredHeight: 3; color: blade.selected ? Theme.accent : Theme.hair }
|
||||
}
|
||||
}
|
||||
|
||||
Text { anchors.centerIn: parent; visible: root.apps.length === 0; text: "NO TARGET VECTOR"; color: Theme.muted; font.family: Theme.microFont; font.pixelSize: 9; font.letterSpacing: 1.2 }
|
||||
}
|
||||
}
|
||||
|
||||
// Right dossier: open brackets and data lines, deliberately not a panel.
|
||||
Item {
|
||||
id: dossier
|
||||
x: 842; y: 108
|
||||
width: 252; height: 444
|
||||
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0)
|
||||
strokeColor: Theme.accent
|
||||
strokeWidth: 2
|
||||
startX: 36; startY: 0
|
||||
PathLine { x: 0; y: 0 }
|
||||
PathLine { x: 0; y: 86 }
|
||||
}
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0)
|
||||
strokeColor: Theme.accent
|
||||
strokeWidth: 2
|
||||
startX: dossier.width - 36; startY: dossier.height
|
||||
PathLine { x: dossier.width; y: dossier.height }
|
||||
PathLine { x: dossier.width; y: dossier.height - 86 }
|
||||
}
|
||||
ShapePath {
|
||||
fillColor: Theme.textAlpha(0)
|
||||
strokeColor: Theme.hair
|
||||
strokeWidth: 1
|
||||
startX: 20; startY: 20
|
||||
PathLine { x: dossier.width; y: 20 }
|
||||
PathLine { x: dossier.width; y: dossier.height - 20 }
|
||||
PathLine { x: 0; y: dossier.height - 20 }
|
||||
PathLine { x: 0; y: 104 }
|
||||
}
|
||||
}
|
||||
|
||||
MicroText { x: 18; y: 12; text: "ACTIVE DOSSIER"; color: Theme.accent }
|
||||
Text {
|
||||
x: 18; y: 45; width: parent.width - 36
|
||||
text: root.selectedApp ? root.selectedApp.name : "NO TARGET"
|
||||
color: Theme.text
|
||||
font.family: Theme.displayFont
|
||||
font.pixelSize: 18
|
||||
font.bold: true
|
||||
font.letterSpacing: 0.8
|
||||
wrapMode: Text.Wrap
|
||||
maximumLineCount: 2
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
MicroText { x: 18; y: 94; width: parent.width - 36; text: root.selectedApp ? (root.selectedApp.genericName || "DESKTOP APPLICATION") : "AWAITING ACQUISITION"; color: Theme.accent }
|
||||
|
||||
Rectangle { x: 18; y: 119; width: parent.width - 36; height: 1; color: Theme.hair }
|
||||
MicroText { x: 18; y: 137; width: parent.width - 36; height: 52; wrapMode: Text.Wrap; maximumLineCount: 4; text: root.selectedApp ? (root.selectedApp.comment || "No metadata supplied by desktop entry.") : "Enter a search vector and select an executable target." }
|
||||
|
||||
Column {
|
||||
x: 18; y: 210; width: parent.width - 36; spacing: 8
|
||||
Repeater {
|
||||
model: [
|
||||
{ k: "INDEX", v: String(Math.max(0, root.selectedIndex + 1)).padStart(3, "0") },
|
||||
{ k: "TYPE", v: "DESKTOP ENTRY" },
|
||||
{ k: "ROUTE", v: "DETACHED" },
|
||||
{ k: "STATE", v: root.selectedApp ? "ARMED" : "IDLE" }
|
||||
]
|
||||
Item {
|
||||
required property var modelData
|
||||
width: parent.width; height: 27
|
||||
Rectangle { x: 0; y: parent.height - 1; width: parent.width; height: 1; color: Theme.hair }
|
||||
MicroText { x: 0; anchors.verticalCenter: parent.verticalCenter; text: modelData.k }
|
||||
Text { anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter; text: modelData.v; color: modelData.k === "STATE" ? Theme.accent : Theme.text; font.family: Theme.displayFont; font.pixelSize: 8; font.bold: true; font.letterSpacing: 0.5 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: fire
|
||||
x: 18; anchors.bottom: parent.bottom; anchors.bottomMargin: 34
|
||||
width: parent.width - 36; height: 44
|
||||
enabled: root.selectedApp !== null
|
||||
hoverEnabled: true
|
||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
onClicked: root.launchRequested(root.selectedIndex)
|
||||
Shape {
|
||||
id: fireShape
|
||||
anchors.fill: parent
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
fillColor: fire.containsMouse ? Theme.accent : Theme.accentAlpha(0.16)
|
||||
strokeColor: Theme.accent
|
||||
strokeWidth: 1
|
||||
startX: 14; startY: 0
|
||||
PathLine { x: fireShape.width; y: 0 }
|
||||
PathLine { x: fireShape.width - 14; y: fireShape.height }
|
||||
PathLine { x: 0; y: fireShape.height }
|
||||
PathLine { x: 14; y: 0 }
|
||||
}
|
||||
}
|
||||
Text { anchors.centerIn: parent; text: "LAUNCH VECTOR"; color: fire.containsMouse ? Theme.surface : Theme.accent; font.family: Theme.displayFont; font.pixelSize: 10; font.bold: true; font.letterSpacing: 1.2 }
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom caution lane and key map.
|
||||
Row {
|
||||
x: 28; y: 612; spacing: 4
|
||||
Repeater { model: 30; Rectangle { required property int index; width: 12; height: 4; color: index % 3 === 0 ? Theme.accent : Theme.hair; transform: Rotation { angle: -32 } } }
|
||||
}
|
||||
MicroText { x: 420; y: 606; text: "↑↓ SELECT // ENTER LAUNCH // ESC ABORT // PGUP/PGDN STEP"; color: Theme.accent }
|
||||
MicroText { anchors.right: parent.right; anchors.rightMargin: 28; y: 606; text: "BLADE-09 / CRC A7F2" }
|
||||
}
|
||||
@@ -198,7 +198,7 @@ in
|
||||
|
||||
# quickshell app-launcher variants (evaluating — pick one)
|
||||
]
|
||||
++ (map (n: bind "SUPER + CTRL + ${toString n}" (dsp.global "quickshell:launcher${toString n}")) (lib.range 1 8))
|
||||
++ (map (n: bind "SUPER + CTRL + ${toString n}" (dsp.global "quickshell:launcher${toString n}")) (lib.range 1 9))
|
||||
++ [
|
||||
# restart quickshell (also starts it if not running)
|
||||
(bind "SUPER + CTRL + 0" (dsp.exec "qs kill; sleep 0.3; qs"))
|
||||
|
||||
Reference in New Issue
Block a user