Compare commits

...
3 Commits
Author SHA1 Message Date
darmanandClaude Opus 5 b16cc93ff6 refactor(quickshell): move every color and font into a Theme singleton
The shell was running two unrelated palettes: an amber one (#FFD063 accent,
#EEEEEE text, #0F1012 panels) hardcoded as ~200 raw hex literals across the
launchers, sidebar, systray, vitals and notifications, and an orange one
(#e8722a) that only the dense bar had, tokenized as per-file properties.

This unifies on the ORANGE values under the AMBER naming scheme, and moves the
lot into widgets/theme/Theme.qml. `surface` takes the dense bar's void
(#0a0a0a) rather than the old panel background. Zero color and font literals
remain anywhere under widgets/ outside Theme.qml.

Collisions resolved, all near-duplicates that wanted to be one token:
  - #0F1012 + #0A0A0C + #0a0a0a -> surface
  - #EEEEEE + #dedede           -> text
  - #7A7B7D + #858585           -> muted
  - #292C30 + #22262C           -> raised
  - #FFD063 + #e8722a           -> accent

Two derived things rather than literals. accentSoft (the pale flash the
top/bottom bars show while a launcher is open) was a hand-picked #FFF3C0
against amber, which is simply wrong against orange; it is now
Qt.tint(accent, white 55%), a ratio checked against the original (amber tinted
55% gives #FFE9B8 vs the hand-picked #FFF3C0). And the dense bar had been
hand-encoding Qt.rgba(0.87,0.87,0.87,a) and Qt.rgba(0.91,0.45,0.16,a), which
are just text and accent at alpha -- now textAlpha(a)/accentAlpha(a), so they
track a palette change instead of silently drifting.

Fonts came along too. Digital-7 Mono is dropped for DepartureMono: it was
never packaged, relying on a manual ~/.dots/fonts/digital_7 install that does
not exist on terra, so `fc-match "Digital-7 Mono"` resolved to DejaVu Sans and
all 38 of those sites -- the launcher lists, sidebar clock, systray labels,
every vitals readout -- were silently rendering in a PROPORTIONAL fallback.
Numeric columns should visibly improve. readoutFont is an alias of displayFont
rather than a second literal so the two roles cannot drift apart.

quickshell/CLAUDE.md updated: it said "No shared theme/tokens file yet" and
told contributors to grep for the existing hex color, which would now
reintroduce exactly what this removes.

Verified: no file references Theme. without the import, none imports it
unused, and the whole shell -- launchers, sidebar, vitals, systray,
notifications, not just the harness -- hot-reloaded clean on terra.
tests/HeadlessSmoke.qml deliberately keeps its own copies; its value is having
no dependencies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx
2026-08-28 07:56:25 +02:00
darmanandClaude Opus 5 01bc169180 refactor(quickshell): rework the panel chrome, extract it as StatusBarPanel
The dense bar's panel chrome gets a squarer outline (top-right and bottom-left
chamfers only, square on the other two corners) and a second accent line in
the lower right to balance the existing upper-left one.

The chrome then moves out of DenseBarContent's inline `component
TelemetryPanel` into its own file. The call sites are unchanged apart from the
name -- children still come from the default property -- and the widgets they
pass in (RadarGauge, NetworkTrace, MetricBlock) stay declared in
DenseBarContent, so their scope is unaffected by moving only the definition.

Two things could not come along and had to be reproduced locally, because a
component in its own file has no access to the enclosing scope:

  - the palette and the two font families, previously read off `root`. They
    are properties with defaults matching DenseBarContent's, which is this
    repo's per-component convention. Duplicated on purpose for now; a shared
    theme singleton is the place to collapse it.
  - MicroText, which is an *inline* component of DenseBarContent and so
    invisible from another file. Expanded to the Text it desugars to.

Also qualified the bare offsetY/chamfer/accentLineThickness references as
panel.*; they resolved through the component scope before, but being explicit
avoids ComponentBehavior: Bound warnings in the new file.

Verified the move was verbatim by normalising the old inline block and the new
file body and diffing them -- the only differences are the relocated property
block, the panel.* qualification and the MicroText expansion. Loads clean both
headlessly and in the real layer-shell shell.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx
2026-08-28 07:55:59 +02:00
darmanandClaude Opus 5 54896033c6 feat(flake): add a quickshell hot-reload devShell
hosts/terra/home.nix ships dotfiles/quickshell via xdg.configFile, which
copies the tree into the store: ~/.config/quickshell is a read-only symlink
into /nix/store and every QML tweak costs a nixos-rebuild. quickshell does
hot-reload on file save -- but only for the files it watches, which are those
frozen store copies. `nix develop` now swaps the running shell to the working
tree (`qs -p`) and swaps it back on exit, so QML edits need no rebuild at all.

The swap starts the dev instance FIRST and kills the packaged one only once
dev is confirmed up. A QML error in the working tree then leaves you on your
normal bar instead of no bar, which matters because a broken save is exactly
when you would be running this. Liveness is "did `qs list -j` return json" --
it exits 0 whether or not it found anything, so the exit code says nothing.

Every kill is scoped to one config (`qs kill` = default, `qs kill -p` = that
path). A blanket kill would also take out unrelated instances; pkgs/rishot.nix
is one.

Three guards on the auto-swap, all learned by testing it:
  - interactive only. `nix develop --command X` EXECs X, replacing the shell
    that set the `trap ... EXIT`, so the restore never runs and you are left
    on the dev instance. Non-interactive use gets `nix develop -c qs-dev`.
  - WAYLAND_DISPLAY, so entering the shell over ssh cannot kill the desktop's
    bar and leave nothing in its place.
  - a sentinel, so a nested `nix develop` does not swap and restore twice.

Deliberately not wired to direnv (no .envrc): programs.direnv is enabled for
this user, so a `use flake` would swap the running desktop shell on every `cd`
into the checkout.

Verified end to end on terra: swap, hot-reload of a working-tree edit, and
restore, plus both the interactive and non-interactive paths.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx
2026-08-28 07:55:03 +02:00
23 changed files with 619 additions and 406 deletions
+7 -2
View File
@@ -33,8 +33,13 @@ Quickshell hot-reloads QML on file save when already running, so for most edits
- `widgets/layout/``HorizontalStack`/`VerticalStack`: `RowLayout`/`ColumnLayout` wrappers that expose `default property alias content` for terser call sites, with a trailing filler `Item` that soaks up remaining space. - `widgets/layout/``HorizontalStack`/`VerticalStack`: `RowLayout`/`ColumnLayout` wrappers that expose `default property alias content` for terser call sites, with a trailing filler `Item` that soaks up remaining space.
- `assets/` — SVG icons referenced via `file://${Quickshell.shellDir}/assets/...`. - `assets/` — SVG icons referenced via `file://${Quickshell.shellDir}/assets/...`.
**Styling**: No shared theme/tokens file yet — colors (`#FFD063` accent, `#0F1012`/`#292C30` backgrounds, `#EEEEEE` text) and metrics are hardcoded per-component. When touching visuals, grep for the existing hex color across `widgets/` to keep new elements consistent rather than introducing new values. **Styling**: All colors and font families come from the `Theme` singleton
(`widgets/theme/Theme.qml`, `import qs.widgets.theme`) — there are no color or
font literals left anywhere under `widgets/`. Add a token there rather than
hardcoding a value; alpha variants of the two main colors go through
`Theme.textAlpha(a)` / `Theme.accentAlpha(a)` instead of a hand-written
`Qt.rgba(...)`. Metrics (sizes, spacing) are still per-component.
**Component base pattern**: `BarWidget.qml` (`widgets/bar/modules/BarWidget.qml`) is a `WrapperMouseArea` + `WrapperRectangle` combo providing hover-triggered border highlight (`Behavior on border.color` animation) and `Layout.fillWidth`. Bar modules extend it via `default property alias content` rather than duplicating the hover/border chrome. **Component base pattern**: `BarWidget.qml` (`widgets/bar/modules/BarWidget.qml`) is a `WrapperMouseArea` + `WrapperRectangle` combo providing hover-triggered border highlight (`Behavior on border.color` animation) and `Layout.fillWidth`. Bar modules extend it via `default property alias content` rather than duplicating the hover/border chrome.
**Fonts**: Clock/Date use the `Digital-7 Mono` font family — expected to be installed system-wide (see sibling `~/.dots/fonts/digital_7`), not bundled in this repo. **Fonts**: Two families, both via `Theme`. `Theme.displayFont` / `Theme.readoutFont` (an alias of it) are `DepartureMono Nerd Font`, installed by `services/desktop/desktop-apps.nix`; `Theme.microFont` is `DejaVu Sans Mono`. The shell no longer uses `Digital-7 Mono`, which was never packaged and depended on a manual `~/.dots/fonts/digital_7` install.
@@ -6,6 +6,7 @@ import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.widgets.launcher import qs.widgets.launcher
import qs.widgets.theme
Scope { Scope {
id: root id: root
@@ -42,7 +43,7 @@ Scope {
implicitHeight: 12 implicitHeight: 12
// Brightens when the Dock launcher (variant 5) opens. // Brightens when the Dock launcher (variant 5) opens.
color: LauncherState.dockOpen ? "#FFF3C0" : "#FFD063" color: LauncherState.dockOpen ? Theme.accentSoft : Theme.accent
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@@ -53,7 +54,7 @@ Scope {
// Gentle "listening" pulse while the dock is open. // Gentle "listening" pulse while the dock is open.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#FFFFFF" color: Theme.highlight
opacity: 0 opacity: 0
visible: LauncherState.dockOpen visible: LauncherState.dockOpen
+3 -2
View File
@@ -5,6 +5,7 @@ import Quickshell.Widgets
import QtQuick import QtQuick
import qs.widgets.launcher import qs.widgets.launcher
import qs.widgets.theme
Scope { Scope {
id: root id: root
@@ -42,7 +43,7 @@ Scope {
implicitHeight: 6 implicitHeight: 6
// Brightens when the Console launcher (variant 4) opens. // Brightens when the Console launcher (variant 4) opens.
color: LauncherState.consoleOpen ? "#FFF3C0" : "#FFD063" color: LauncherState.consoleOpen ? Theme.accentSoft : Theme.accent
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@@ -53,7 +54,7 @@ Scope {
// Gentle "listening" pulse while the console is open. // Gentle "listening" pulse while the console is open.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#FFFFFF" color: Theme.highlight
opacity: 0 opacity: 0
visible: LauncherState.consoleOpen visible: LauncherState.consoleOpen
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// Renderable visual core for the desktop telemetry rail. Runtime services stay // Renderable visual core for the desktop telemetry rail. Runtime services stay
// in DenseBar.qml so this Item can be exercised without Wayland or Hyprland. // in DenseBar.qml so this Item can be exercised without Wayland or Hyprland.
@@ -11,14 +12,7 @@ Item {
implicitWidth: 1920 implicitWidth: 1920
implicitHeight: 164 implicitHeight: 164
readonly property color voidColor: "#0a0a0a"
readonly property color inkColor: "#dedede"
readonly property color mutedColor: "#858585"
readonly property color accentColor: "#e8722a"
readonly property color hairColor: Qt.rgba(0.87, 0.87, 0.87, 0.28)
readonly property bool compact: width <= 1400 readonly property bool compact: width <= 1400
readonly property string displayFont: "DepartureMono Nerd Font"
readonly property string microFont: "DejaVu Sans Mono"
property bool autoClock: true property bool autoClock: true
property date now: new Date() property date now: new Date()
@@ -69,11 +63,6 @@ Item {
onTriggered: root.now = new Date() onTriggered: root.now = new Date()
} }
Rectangle {
anchors.fill: parent
color: root.voidColor
}
// Faint drafting grid; no gradient and deliberately subordinate to data. // Faint drafting grid; no gradient and deliberately subordinate to data.
Repeater { Repeater {
model: Math.ceil(root.width / 40) model: Math.ceil(root.width / 40)
@@ -82,7 +71,7 @@ Item {
x: index * 40 x: index * 40
width: 1 width: 1
height: root.height height: root.height
color: root.inkColor color: Theme.text
opacity: 0.018 opacity: 0.018
} }
} }
@@ -94,7 +83,7 @@ Item {
y: index * 40 y: index * 40
width: root.width width: root.width
height: 1 height: 1
color: root.inkColor color: Theme.text
opacity: 0.018 opacity: 0.018
} }
} }
@@ -115,7 +104,7 @@ Item {
anchors.fill: parent anchors.fill: parent
spacing: 8 spacing: 8
TelemetryPanel { StatusBarPanel {
width: array.identityWidth width: array.identityWidth
height: array.height height: array.height
panelId: "001" panelId: "001"
@@ -125,8 +114,8 @@ Item {
x: 12 x: 12
y: 34 y: 34
text: root.hostName.toUpperCase() text: root.hostName.toUpperCase()
color: root.inkColor color: Theme.text
font.family: root.displayFont font.family: Theme.displayFont
font.pixelSize: root.compact ? 20 : 25 font.pixelSize: root.compact ? 20 : 25
font.bold: true font.bold: true
font.letterSpacing: 2 font.letterSpacing: 2
@@ -138,8 +127,8 @@ Item {
x: 13 x: 13
y: 63 y: 63
text: "STATUS ARRAY // " + (root.telemetryReady ? "LIVE" : "STANDBY") text: "STATUS ARRAY // " + (root.telemetryReady ? "LIVE" : "STANDBY")
color: root.accentColor color: Theme.accent
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 7 font.pixelSize: 7
font.letterSpacing: 1.4 font.letterSpacing: 1.4
} }
@@ -149,7 +138,7 @@ Item {
y: 36 y: 36
width: 1 width: 1
height: 43 height: 43
color: root.hairColor color: Theme.hair
} }
Rectangle { Rectangle {
@@ -157,7 +146,7 @@ Item {
y: 42 y: 42
width: 5 width: 5
height: 5 height: 5
color: root.accentColor color: Theme.accent
opacity: root.telemetryReady ? 1 : 0.35 opacity: root.telemetryReady ? 1 : 0.35
} }
@@ -165,8 +154,8 @@ Item {
x: parent.width - 50 x: parent.width - 50
y: 38 y: 38
text: root.telemetryReady ? "ONLINE" : "LOCAL" text: root.telemetryReady ? "ONLINE" : "LOCAL"
color: root.accentColor color: Theme.accent
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 7 font.pixelSize: 7
} }
@@ -174,8 +163,8 @@ Item {
x: parent.width - 63 x: parent.width - 63
y: 57 y: 57
text: "NODE // " + (root.hostName || "--").toUpperCase().slice(0, 7) text: "NODE // " + (root.hostName || "--").toUpperCase().slice(0, 7)
color: root.mutedColor color: Theme.muted
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 6 font.pixelSize: 6
} }
@@ -186,7 +175,7 @@ Item {
height: 10 height: 10
ShapePath { ShapePath {
fillColor: "transparent" fillColor: "transparent"
strokeColor: root.accentColor strokeColor: Theme.accent
strokeWidth: 1 strokeWidth: 1
startX: 0; startY: 6 startX: 0; startY: 6
PathLine { x: 11; y: 6 } PathLine { x: 11; y: 6 }
@@ -198,7 +187,7 @@ Item {
} }
} }
TelemetryPanel { StatusBarPanel {
width: array.flexWidth width: array.flexWidth
height: array.height height: array.height
panelId: "02" panelId: "02"
@@ -245,7 +234,7 @@ Item {
} }
} }
TelemetryPanel { StatusBarPanel {
width: array.radarWidth width: array.radarWidth
height: array.height height: array.height
panelId: "03" panelId: "03"
@@ -259,7 +248,7 @@ Item {
} }
} }
TelemetryPanel { StatusBarPanel {
width: array.flexWidth width: array.flexWidth
height: array.height height: array.height
panelId: "04" panelId: "04"
@@ -285,8 +274,8 @@ Item {
width: parent.width width: parent.width
text: root.networkRxText text: root.networkRxText
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
color: root.accentColor color: Theme.accent
font.family: root.displayFont font.family: Theme.displayFont
font.pixelSize: root.compact ? 11 : 13 font.pixelSize: root.compact ? 11 : 13
font.bold: true font.bold: true
elide: Text.ElideLeft elide: Text.ElideLeft
@@ -296,8 +285,8 @@ Item {
width: parent.width width: parent.width
text: root.networkTxText text: root.networkTxText
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
color: root.inkColor color: Theme.text
font.family: root.displayFont font.family: Theme.displayFont
font.pixelSize: root.compact ? 11 : 13 font.pixelSize: root.compact ? 11 : 13
font.bold: true font.bold: true
elide: Text.ElideLeft elide: Text.ElideLeft
@@ -306,7 +295,7 @@ Item {
} }
} }
TelemetryPanel { StatusBarPanel {
width: array.stateWidth width: array.stateWidth
height: array.height height: array.height
panelId: "05" panelId: "05"
@@ -327,7 +316,7 @@ Item {
y: 33 y: 33
width: 1 width: 1
height: 46 height: 46
color: root.hairColor color: Theme.hair
} }
Column { Column {
@@ -341,8 +330,8 @@ Item {
width: parent.width width: parent.width
text: root.timeText(root.now) text: root.timeText(root.now)
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
color: root.inkColor color: Theme.text
font.family: root.displayFont font.family: Theme.displayFont
font.pixelSize: root.compact ? 20 : 22 font.pixelSize: root.compact ? 20 : 22
font.bold: true font.bold: true
font.letterSpacing: 1 font.letterSpacing: 1
@@ -351,8 +340,8 @@ Item {
width: parent.width width: parent.width
text: root.dateText(root.now) text: root.dateText(root.now)
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
color: root.accentColor color: Theme.accent
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 6 font.pixelSize: 6
elide: Text.ElideLeft elide: Text.ElideLeft
} }
@@ -362,7 +351,7 @@ Item {
} }
} }
TelemetryPanel { StatusBarPanel {
id: rail id: rail
x: 12 x: 12
y: 108 y: 108
@@ -382,8 +371,8 @@ Item {
anchors.left: parent.left anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "06 // DESKTOP" text: "06 // DESKTOP"
color: root.accentColor color: Theme.accent
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 7 font.pixelSize: 7
font.letterSpacing: 1 font.letterSpacing: 1
} }
@@ -398,14 +387,14 @@ Item {
required property var modelData required property var modelData
width: 24 width: 24
height: 17 height: 17
color: Number(modelData) === root.activeWorkspaceId ? Qt.rgba(0.91, 0.45, 0.16, 0.18) : "transparent" color: Number(modelData) === root.activeWorkspaceId ? Theme.accentAlpha(0.18) : "transparent"
border.width: 1 border.width: 1
border.color: Number(modelData) === root.activeWorkspaceId ? root.accentColor : root.hairColor border.color: Number(modelData) === root.activeWorkspaceId ? Theme.accent : Theme.hair
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: root.two(Number(parent.modelData)) text: root.two(Number(parent.modelData))
color: Number(parent.modelData) === root.activeWorkspaceId ? root.accentColor : root.mutedColor color: Number(parent.modelData) === root.activeWorkspaceId ? Theme.accent : Theme.muted
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 7 font.pixelSize: 7
} }
MouseArea { MouseArea {
@@ -424,8 +413,8 @@ Item {
x: 76 x: 76
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "COMPOSITOR // NODE_EXPORTER // SHELL" text: "COMPOSITOR // NODE_EXPORTER // SHELL"
color: root.telemetryReady ? root.inkColor : root.mutedColor color: root.telemetryReady ? Theme.text : Theme.muted
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 7 font.pixelSize: 7
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - 84 width: parent.width - 84
@@ -439,8 +428,8 @@ Item {
x: 93 x: 93
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.storageFreeText text: root.storageFreeText
color: root.inkColor color: Theme.text
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 8 font.pixelSize: 8
} }
SegmentMeter { SegmentMeter {
@@ -463,8 +452,8 @@ Item {
x: 89 x: 89
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.audioMuted ? "MUTED" : Math.round(root.audioFraction * 100) + "%" text: root.audioMuted ? "MUTED" : Math.round(root.audioFraction * 100) + "%"
color: root.audioMuted ? root.mutedColor : root.accentColor color: root.audioMuted ? Theme.muted : Theme.accent
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 8 font.pixelSize: 8
} }
SegmentMeter { SegmentMeter {
@@ -488,8 +477,8 @@ Item {
anchors.rightMargin: 8 anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.telemetryReady ? "WARN:00 // ERR:00" : "TELEMETRY WAIT" text: root.telemetryReady ? "WARN:00 // ERR:00" : "TELEMETRY WAIT"
color: root.telemetryReady ? root.mutedColor : root.accentColor color: root.telemetryReady ? Theme.muted : Theme.accent
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 7 font.pixelSize: 7
elide: Text.ElideLeft elide: Text.ElideLeft
width: parent.width - 64 width: parent.width - 64
@@ -507,7 +496,7 @@ Item {
height: 12 height: 12
ShapePath { ShapePath {
fillColor: "transparent" fillColor: "transparent"
strokeColor: Qt.rgba(0.91, 0.45, 0.16, 0.55) strokeColor: Theme.accentAlpha(0.55)
strokeWidth: 1 strokeWidth: 1
startX: 0; startY: 1 startX: 0; startY: 1
PathLine { x: 220; y: 1 } PathLine { x: 220; y: 1 }
@@ -529,15 +518,15 @@ Item {
required property int index required property int index
width: 5 width: 5
height: 3 height: 3
color: index % 2 === 0 ? root.accentColor : "transparent" color: index % 2 === 0 ? Theme.accent : "transparent"
opacity: 0.58 opacity: 0.58
} }
} }
} }
component MicroText: Text { component MicroText: Text {
color: root.mutedColor color: Theme.muted
font.family: root.microFont font.family: Theme.microFont
font.pixelSize: 6 font.pixelSize: 6
font.letterSpacing: 0.7 font.letterSpacing: 0.7
} }
@@ -550,109 +539,11 @@ Item {
anchors.right: parent.right anchors.right: parent.right
width: 1 width: 1
height: parent.height height: parent.height
color: root.hairColor color: Theme.hair
opacity: 0.65 opacity: 0.65
} }
} }
component TelemetryPanel: Item {
id: panel
property string panelId: ""
property string title: ""
property string meta: ""
property bool showHeader: true
property int chamfer: 13
Shape {
id: panelShape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: root.voidColor
strokeColor: root.hairColor
strokeWidth: 1
startX: 1; startY: 1
PathLine { x: panelShape.width - panel.chamfer; y: 1 }
PathLine { x: panelShape.width - 1; y: panel.chamfer }
PathLine { x: panelShape.width - 1; y: panelShape.height - 8 }
PathLine { x: panelShape.width - 8; y: panelShape.height - 1 }
PathLine { x: 16; y: panelShape.height - 1 }
PathLine { x: 1; y: panelShape.height - 16 }
PathLine { x: 1; y: 1 }
}
ShapePath {
fillColor: root.accentColor
strokeWidth: 0
startX: 1; startY: 1
PathLine { x: Math.min(49, panelShape.width / 3); y: 1 }
PathLine { x: Math.min(49, panelShape.width / 3); y: 3 }
PathLine { x: 1; y: 3 }
PathLine { x: 1; y: 1 }
}
}
Rectangle {
visible: panel.showHeader
x: 1; y: 20
width: parent.width - 2
height: 1
color: root.inkColor
opacity: 0.12
}
Rectangle {
visible: panel.showHeader
x: 9; y: 5
width: panel.panelId.length > 2 ? 29 : 24
height: 11
color: root.accentColor
Text {
anchors.centerIn: parent
text: panel.panelId
color: root.voidColor
font.family: root.microFont
font.pixelSize: 7
font.bold: true
}
}
Text {
visible: panel.showHeader
x: 40; y: 5
width: parent.width - 105
text: panel.title
color: root.inkColor
font.family: root.displayFont
font.pixelSize: 9
font.bold: true
font.letterSpacing: 1.1
elide: Text.ElideRight
}
MicroText {
visible: panel.showHeader && panel.meta.length > 0
anchors.right: parent.right
anchors.rightMargin: 12
y: 6
text: panel.meta
width: Math.min(80, parent.width / 4)
horizontalAlignment: Text.AlignRight
elide: Text.ElideRight
}
Row {
visible: panel.showHeader
anchors.right: parent.right
anchors.rightMargin: 10
y: 14
spacing: 2
Repeater {
model: 5
Rectangle { required property int index; width: 3; height: 1; color: root.accentColor }
}
}
}
component MetricBlock: Item { component MetricBlock: Item {
id: metric id: metric
property string label: "" property string label: ""
@@ -668,8 +559,8 @@ Item {
anchors.right: parent.right anchors.right: parent.right
y: -3 y: -3
text: metric.readout text: metric.readout
color: root.inkColor color: Theme.text
font.family: root.displayFont font.family: Theme.displayFont
font.pixelSize: root.compact ? 14 : 17 font.pixelSize: root.compact ? 14 : 17
font.bold: true font.bold: true
} }
@@ -698,9 +589,9 @@ Item {
width: Math.max(2, (meter.width - (meter.segments - 1) * meter.spacing) / meter.segments) width: Math.max(2, (meter.width - (meter.segments - 1) * meter.spacing) / meter.segments)
height: meter.height height: meter.height
readonly property bool on: meter.ready && index < Math.round(Math.max(0, Math.min(1, meter.value)) * meter.segments) readonly property bool on: meter.ready && index < Math.round(Math.max(0, Math.min(1, meter.value)) * meter.segments)
color: on ? root.accentColor : Qt.rgba(0.87, 0.87, 0.87, 0.06) color: on ? Theme.accent : Theme.textAlpha(0.06)
border.width: 1 border.width: 1
border.color: on ? root.accentColor : Qt.rgba(0.87, 0.87, 0.87, 0.18) border.color: on ? Theme.accent : Theme.textAlpha(0.18)
} }
} }
} }
@@ -716,8 +607,8 @@ Item {
Shape { Shape {
anchors.fill: parent anchors.fill: parent
ShapePath { ShapePath {
fillColor: state.active ? Qt.rgba(0.91, 0.45, 0.16, 0.18) : "transparent" fillColor: state.active ? Theme.accentAlpha(0.18) : "transparent"
strokeColor: state.active ? root.accentColor : root.hairColor strokeColor: state.active ? Theme.accent : Theme.hair
strokeWidth: 1 strokeWidth: 1
startX: 1; startY: 1 startX: 1; startY: 1
PathLine { x: parent.width - 7; y: 1 } PathLine { x: parent.width - 7; y: 1 }
@@ -732,8 +623,8 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
y: 7 y: 7
text: state.code text: state.code
color: state.active ? root.accentColor : root.inkColor color: state.active ? Theme.accent : Theme.text
font.family: root.displayFont font.family: Theme.displayFont
font.pixelSize: 13 font.pixelSize: 13
font.bold: true font.bold: true
} }
@@ -758,27 +649,27 @@ Item {
radius: width / 2 radius: width / 2
color: "transparent" color: "transparent"
border.width: 1 border.width: 1
border.color: index === 0 ? root.accentColor : root.hairColor border.color: index === 0 ? Theme.accent : Theme.hair
} }
} }
Rectangle { x: 0; y: parent.height / 2; width: parent.width; height: 1; color: root.hairColor } Rectangle { x: 0; y: parent.height / 2; width: parent.width; height: 1; color: Theme.hair }
Rectangle { x: parent.width / 2; y: 0; width: 1; height: parent.height; color: root.hairColor } Rectangle { x: parent.width / 2; y: 0; width: 1; height: parent.height; color: Theme.hair }
Rectangle { x: 12; y: 18; width: 4; height: 4; color: root.accentColor } Rectangle { x: 12; y: 18; width: 4; height: 4; color: Theme.accent }
Rectangle { x: parent.width - 14; y: parent.height - 20; width: 4; height: 4; color: root.accentColor } Rectangle { x: parent.width - 14; y: parent.height - 20; width: 4; height: 4; color: Theme.accent }
Rectangle { x: parent.width / 2; y: parent.height - 11; width: 4; height: 4; color: root.accentColor } Rectangle { x: parent.width / 2; y: parent.height - 11; width: 4; height: 4; color: Theme.accent }
MicroText { anchors.right: parent.right; y: 3; text: "R:" + Math.round(radar.level * 99); color: root.accentColor } MicroText { anchors.right: parent.right; y: 3; text: "R:" + Math.round(radar.level * 99); color: Theme.accent }
} }
component NetworkTrace: Item { component NetworkTrace: Item {
id: trace id: trace
property real level: 0 property real level: 0
Rectangle { x: 0; y: parent.height - 1; width: parent.width; height: 1; color: root.hairColor } Rectangle { x: 0; y: parent.height - 1; width: parent.width; height: 1; color: Theme.hair }
Rectangle { x: 0; y: 0; width: 1; height: parent.height; color: root.hairColor } Rectangle { x: 0; y: 0; width: 1; height: parent.height; color: Theme.hair }
Shape { Shape {
anchors.fill: parent anchors.fill: parent
ShapePath { ShapePath {
fillColor: "transparent" fillColor: "transparent"
strokeColor: root.accentColor strokeColor: Theme.accent
strokeWidth: 1.2 strokeWidth: 1.2
startX: 0; startY: trace.height * 0.65 startX: 0; startY: trace.height * 0.65
PathLine { x: trace.width * 0.10; y: trace.height * 0.65 } PathLine { x: trace.width * 0.10; y: trace.height * 0.65 }
@@ -0,0 +1,130 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Shapes
import qs.widgets.theme
// Chamfered panel chrome for the dense status rail: outline, corner accent
// lines, and the optional header strip (id chip / title / meta / tick marks).
// Content is supplied as children by the call site.
//
// Colors and fonts both come from the Theme singleton.
Item {
id: panel
property string panelId: ""
property string title: ""
property string meta: ""
property bool showHeader: true
property int chamfer: 13
property int offsetY: 2
property int accentLineThickness: 3
Shape {
id: panelShape
anchors.fill: parent
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: Theme.surface
strokeColor: Theme.hair
strokeWidth: 1
startX: 0; startY: panel.offsetY
PathLine { x: panelShape.width - panel.chamfer; y: panel.offsetY }
PathLine { x: panelShape.width; y: panel.chamfer }
PathLine { x: panelShape.width; y: panelShape.height }
PathLine { x: panel.chamfer; y: panelShape.height }
PathLine { x: 0; y: panelShape.height - panel.chamfer }
PathLine { x: 0; y: panel.offsetY }
}
// Upper left accent line
ShapePath {
fillColor: Theme.accent
strokeWidth: 0
startX: 0; startY: 0
PathLine { x: Math.min(49, panelShape.width / 3); y: 0 }
PathLine { x: Math.min(49, panelShape.width / 3); y: panel.accentLineThickness }
PathLine { x: 0; y: panel.accentLineThickness }
PathLine { x: 0; y: 0 }
}
// Lower right accent line
ShapePath {
fillColor: Theme.accent
strokeWidth: 0
startX: panelShape.width; startY: panelShape.height
PathLine { x: panelShape.width - Math.min(49, panelShape.width / 3); y: panelShape.height }
PathLine { x: panelShape.width - Math.min(49, panelShape.width / 3); y: panelShape.height - panel.accentLineThickness }
PathLine { x: panelShape.width; y: panelShape.height - panel.accentLineThickness }
PathLine { x: panelShape.width; y: panelShape.height }
}
}
Rectangle {
visible: panel.showHeader
x: 1; y: 22
width: parent.width - 2
height: 1
color: Theme.text
opacity: 0.12
}
Rectangle {
visible: panel.showHeader
x: 5; y: 7
width: panel.panelId.length > 2 ? 29 : 24
height: 11
color: Theme.accent
Text {
anchors.centerIn: parent
text: panel.panelId
color: Theme.surface
font.family: Theme.microFont
font.pixelSize: 8
font.bold: true
}
}
Text {
visible: panel.showHeader
x: 40; y: 7
width: parent.width - 105
text: panel.title
color: Theme.text
font.family: Theme.displayFont
font.pixelSize: 9
font.bold: true
font.letterSpacing: 1.1
elide: Text.ElideRight
}
// Inlined rather than reusing DenseBarContent's MicroText, which is an
// inline component and therefore not visible from another file.
Text {
visible: panel.showHeader && panel.meta.length > 0
anchors.right: parent.right
anchors.rightMargin: 12
y: 6
text: panel.meta
width: Math.min(80, parent.width / 4)
color: Theme.muted
font.family: Theme.microFont
font.pixelSize: 6
font.letterSpacing: 0.7
horizontalAlignment: Text.AlignRight
elide: Text.ElideRight
}
Row {
visible: panel.showHeader
anchors.right: parent.right
anchors.rightMargin: 10
y: 14
spacing: 2
Repeater {
model: 5
Rectangle { required property int index; width: 4; height: 2; color: Theme.accent }
}
}
}
@@ -1,10 +1,11 @@
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
Shape { Shape {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
fillColor: "#FFD063" fillColor: Theme.accent
strokeWidth: 0 strokeWidth: 0
startX: 0 startX: 0
@@ -5,6 +5,7 @@ import QtQuick.Layouts
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.decoration import qs.widgets.decoration
import qs.widgets.theme
WrapperItem { WrapperItem {
RowLayout { RowLayout {
@@ -24,7 +25,7 @@ WrapperItem {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#0F1012" fillColor: Theme.surface
startX: 8 startX: 8
startY: 0 startY: 0
@@ -52,7 +53,7 @@ WrapperItem {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#0F1012" fillColor: Theme.surface
startX: 16 startX: 16
startY: 0 startY: 0
@@ -83,7 +84,7 @@ WrapperItem {
startY: 0 startY: 0
strokeWidth: 0 strokeWidth: 0
fillColor: "#0F1012" fillColor: Theme.surface
PathLine { PathLine {
x: shape.width x: shape.width
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.widgets.theme
// Variant 4 — "Console": a full-width command deck that unfolds down out of // Variant 4 — "Console": a full-width command deck that unfolds down out of
// the top bar, with a horizontal carousel of app cards. While open it drives // the top bar, with a horizontal carousel of app cards. While open it drives
@@ -99,7 +100,7 @@ Scope {
anchors.right: parent.right anchors.right: parent.right
clip: true clip: true
color: "#0F1012" color: Theme.surface
height: root.active ? win.openHeight : 0 height: root.active ? win.openHeight : 0
@@ -116,7 +117,7 @@ Scope {
// Accent lid — mirrors the top bar strip, reads as its extension. // Accent lid — mirrors the top bar strip, reads as its extension.
Rectangle { Rectangle {
color: "#FFD063" color: Theme.accent
implicitHeight: 4 implicitHeight: 4
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -132,8 +133,8 @@ Scope {
Text { Text {
text: ">_" text: ">_"
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 22 font.pointSize: 22
font.bold: true font.bold: true
} }
@@ -147,7 +148,7 @@ Scope {
anchors.fill: parent anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE" color: Theme.text
font.pointSize: 16 font.pointSize: 16
clip: true clip: true
@@ -182,7 +183,7 @@ Scope {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0 visible: input.text.length === 0
text: "launch application…" text: "launch application…"
color: "#7A7B7D" color: Theme.muted
font: input.font font: input.font
} }
} }
@@ -190,14 +191,14 @@ Scope {
Text { Text {
text: model.apps.length + " apps" text: model.apps.length + " apps"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 15 font.pointSize: 15
} }
} }
Rectangle { Rectangle {
color: "#292C30" color: Theme.raised
implicitHeight: 1 implicitHeight: 1
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -236,9 +237,9 @@ Scope {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: card.selected ? "#292C30" : "transparent" color: card.selected ? Theme.raised : "transparent"
border.width: 1 border.width: 1
border.color: card.selected ? "#FFD063" : "#292C30" border.color: card.selected ? Theme.accent : Theme.raised
Behavior on border.color { Behavior on border.color {
ColorAnimation { ColorAnimation {
@@ -261,7 +262,7 @@ Scope {
Text { Text {
Layout.fillWidth: true Layout.fillWidth: true
text: card.modelData.name text: card.modelData.name
color: card.selected ? "#FFD063" : "#EEEEEE" color: card.selected ? Theme.accent : Theme.text
font.pointSize: 9 font.pointSize: 9
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight elide: Text.ElideRight
@@ -277,8 +278,8 @@ Scope {
anchors.centerIn: parent anchors.centerIn: parent
visible: model.apps.length === 0 visible: model.apps.length === 0
text: "no matches" text: "no matches"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 16 font.pointSize: 16
} }
} }
@@ -7,6 +7,7 @@ import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// Variant 7 — a copy of the "Slant" (V6) launcher, plus a small floating // Variant 7 — a copy of the "Slant" (V6) launcher, plus a small floating
// power panel docked to its right with Shutdown / Reboot buttons. // power panel docked to its right with Shutdown / Reboot buttons.
@@ -77,7 +78,7 @@ Scope {
// Dim backdrop — click to dismiss. // Dim backdrop — click to dismiss.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#0A0A0C" color: Theme.surface
opacity: 0.55 opacity: 0.55
MouseArea { MouseArea {
@@ -107,8 +108,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
fillColor: "#0F1012" fillColor: Theme.surface
strokeColor: "#FFD063" strokeColor: Theme.accent
strokeWidth: 2 strokeWidth: 2
startX: frame.chamfer startX: frame.chamfer
@@ -153,7 +154,7 @@ Scope {
// run out to the top and left edges to meet the straight borders. // run out to the top and left edges to meet the straight borders.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: frame.chamfer startY: frame.chamfer
@@ -179,7 +180,7 @@ Scope {
// bottom and right edges. // bottom and right edges.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: panelShape.height - frame.chamfer startY: panelShape.height - frame.chamfer
@@ -205,7 +206,7 @@ Scope {
// detached from the panel by the width of the cut. // detached from the panel by the width of the cut.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: panelShape.height startY: panelShape.height
@@ -228,7 +229,7 @@ Scope {
// slanted end pieces on both arms. // slanted end pieces on both arms.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
// inner, right end of the bottom arm // inner, right end of the bottom arm
startX: panelShape.width / 3 startX: panelShape.width / 3
@@ -277,7 +278,7 @@ Scope {
// slanted end pieces on both arms. // slanted end pieces on both arms.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
// inner, bottom of the right arm // inner, bottom of the right arm
startX: panelShape.width startX: panelShape.width
@@ -345,7 +346,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 6 startX: 6
startY: 0 startY: 0
PathLine { PathLine {
@@ -367,7 +368,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 15 startX: 15
startY: 0 startY: 0
PathLine { PathLine {
@@ -389,7 +390,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 24 startX: 24
startY: 0 startY: 0
PathLine { PathLine {
@@ -420,8 +421,8 @@ Scope {
anchors.fill: parent anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE" color: Theme.text
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 20 font.pointSize: 20
font.letterSpacing: 1 font.letterSpacing: 1
clip: true clip: true
@@ -457,7 +458,7 @@ Scope {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0 visible: input.text.length === 0
text: "run" text: "run"
color: "#7A7B7D" color: Theme.muted
font: input.font font: input.font
} }
} }
@@ -465,8 +466,8 @@ Scope {
Text { Text {
text: model.apps.length text: model.apps.length
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 18 font.pointSize: 18
} }
} }
@@ -489,7 +490,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: divider.slant startX: divider.slant
startY: 0 startY: 0
PathLine { PathLine {
@@ -512,7 +513,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: divider.height startY: divider.height
PathLine { PathLine {
@@ -535,7 +536,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: divider.width startX: divider.width
startY: 0 startY: 0
PathLine { PathLine {
@@ -597,7 +598,7 @@ Scope {
// Body // Body
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#22262C" fillColor: Theme.raised
startX: appRow.shear startX: appRow.shear
startY: 0 startY: 0
PathLine { PathLine {
@@ -620,7 +621,7 @@ Scope {
// Left accent edge // Left accent edge
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: appRow.shear startX: appRow.shear
startY: 0 startY: 0
PathLine { PathLine {
@@ -655,7 +656,7 @@ Scope {
Text { Text {
text: appRow.modelData.name text: appRow.modelData.name
color: appRow.selected ? "#FFD063" : "#EEEEEE" color: appRow.selected ? Theme.accent : Theme.text
font.pointSize: 12 font.pointSize: 12
elide: Text.ElideRight elide: Text.ElideRight
Layout.fillWidth: true Layout.fillWidth: true
@@ -663,7 +664,7 @@ Scope {
Text { Text {
text: appRow.modelData.genericName || "" text: appRow.modelData.genericName || ""
color: "#7A7B7D" color: Theme.muted
font.pointSize: 10 font.pointSize: 10
elide: Text.ElideRight elide: Text.ElideRight
Layout.maximumWidth: 220 Layout.maximumWidth: 220
@@ -694,8 +695,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
fillColor: "#FFD063" fillColor: Theme.accent
strokeColor: "#FFD063" strokeColor: Theme.accent
strokeWidth: 2 strokeWidth: 2
startX: 0 startX: 0
@@ -732,9 +733,9 @@ Scope {
Text { Text {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: "POWER" text: "POWER"
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
color: "#0F1012" color: Theme.surface
} }
Repeater { Repeater {
@@ -762,8 +763,8 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 1 strokeWidth: 1
strokeColor: powerButton.containsMouse ? "#FFD063" : "#7A7B7D" strokeColor: powerButton.containsMouse ? Theme.accent : Theme.muted
fillColor: "#292C30" fillColor: Theme.raised
startX: powerButton.chamfer startX: powerButton.chamfer
startY: 0 startY: 0
@@ -785,8 +786,8 @@ Scope {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: powerButton.modelData.label text: powerButton.modelData.label
color: powerButton.containsMouse ? "#FFD063" : "#EEEEEE" color: powerButton.containsMouse ? Theme.accent : Theme.text
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
} }
} }
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.widgets.theme
// Variant 5 — "Dock": the Console concept mirrored to the bottom edge. A // Variant 5 — "Dock": the Console concept mirrored to the bottom edge. A
// full-width deck rises up out of the bottom bar, which energizes via // full-width deck rises up out of the bottom bar, which energizes via
@@ -98,7 +99,7 @@ Scope {
anchors.right: parent.right anchors.right: parent.right
clip: true clip: true
color: "#0F1012" color: Theme.surface
height: root.active ? win.openHeight : 0 height: root.active ? win.openHeight : 0
@@ -153,9 +154,9 @@ Scope {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: card.selected ? "#292C30" : "transparent" color: card.selected ? Theme.raised : "transparent"
border.width: 1 border.width: 1
border.color: card.selected ? "#FFD063" : "#292C30" border.color: card.selected ? Theme.accent : Theme.raised
Behavior on border.color { Behavior on border.color {
ColorAnimation { ColorAnimation {
@@ -178,7 +179,7 @@ Scope {
Text { Text {
Layout.fillWidth: true Layout.fillWidth: true
text: card.modelData.name text: card.modelData.name
color: card.selected ? "#FFD063" : "#EEEEEE" color: card.selected ? Theme.accent : Theme.text
font.pointSize: 9 font.pointSize: 9
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight elide: Text.ElideRight
@@ -194,14 +195,14 @@ Scope {
anchors.centerIn: parent anchors.centerIn: parent
visible: model.apps.length === 0 visible: model.apps.length === 0
text: "no matches" text: "no matches"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 16 font.pointSize: 16
} }
} }
Rectangle { Rectangle {
color: "#292C30" color: Theme.raised
implicitHeight: 1 implicitHeight: 1
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -217,8 +218,8 @@ Scope {
Text { Text {
text: ">_" text: ">_"
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 22 font.pointSize: 22
font.bold: true font.bold: true
} }
@@ -232,7 +233,7 @@ Scope {
anchors.fill: parent anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE" color: Theme.text
font.pointSize: 16 font.pointSize: 16
clip: true clip: true
@@ -267,7 +268,7 @@ Scope {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0 visible: input.text.length === 0
text: "launch application…" text: "launch application…"
color: "#7A7B7D" color: Theme.muted
font: input.font font: input.font
} }
} }
@@ -275,15 +276,15 @@ Scope {
Text { Text {
text: model.apps.length + " apps" text: model.apps.length + " apps"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 15 font.pointSize: 15
} }
} }
// Accent lid — mirrors the bottom bar strip. // Accent lid — mirrors the bottom bar strip.
Rectangle { Rectangle {
color: "#FFD063" color: Theme.accent
implicitHeight: 4 implicitHeight: 4
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.widgets.theme
// Variant 2 — "Grid": centered app-drawer with a dim backdrop and icon tiles. // Variant 2 — "Grid": centered app-drawer with a dim backdrop and icon tiles.
Scope { Scope {
@@ -78,7 +79,7 @@ Scope {
// Dim backdrop — click anywhere outside to dismiss. // Dim backdrop — click anywhere outside to dismiss.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#0A0A0C" color: Theme.surface
opacity: 0.55 opacity: 0.55
MouseArea { MouseArea {
@@ -93,9 +94,9 @@ Scope {
width: 760 width: 760
height: 560 height: 560
color: "#0F1012" color: Theme.surface
border.width: 1 border.width: 1
border.color: "#FFD063" border.color: Theme.accent
opacity: 0.98 opacity: 0.98
// Accent corner brackets for the cyberpunk frame. // Accent corner brackets for the cyberpunk frame.
@@ -104,14 +105,14 @@ Scope {
anchors.left: parent.left anchors.left: parent.left
width: 5 width: 5
height: 28 height: 28
color: "#FFD063" color: Theme.accent
} }
Rectangle { Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.right: parent.right anchors.right: parent.right
width: 28 width: 28
height: 5 height: 5
color: "#FFD063" color: Theme.accent
} }
ColumnLayout { ColumnLayout {
@@ -126,8 +127,8 @@ Scope {
Text { Text {
text: "APPS" text: "APPS"
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 22 font.pointSize: 22
font.letterSpacing: 3 font.letterSpacing: 3
} }
@@ -138,9 +139,9 @@ Scope {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#292C30" color: Theme.raised
border.width: 1 border.width: 1
border.color: input.activeFocus ? "#FFD063" : "#7A7B7D" border.color: input.activeFocus ? Theme.accent : Theme.muted
Behavior on border.color { Behavior on border.color {
ColorAnimation { ColorAnimation {
@@ -155,7 +156,7 @@ Scope {
anchors.rightMargin: 12 anchors.rightMargin: 12
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE" color: Theme.text
font.pointSize: 13 font.pointSize: 13
clip: true clip: true
@@ -198,7 +199,7 @@ Scope {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: input.text.length === 0 visible: input.text.length === 0
text: "Type to search…" text: "Type to search…"
color: "#7A7B7D" color: Theme.muted
font: input.font font: input.font
} }
} }
@@ -207,7 +208,7 @@ Scope {
} }
Rectangle { Rectangle {
color: "#FFD063" color: Theme.accent
implicitHeight: 3 implicitHeight: 3
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -242,9 +243,9 @@ Scope {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: 6 anchors.margins: 6
color: tile.selected ? "#292C30" : "transparent" color: tile.selected ? Theme.raised : "transparent"
border.width: 1 border.width: 1
border.color: tile.selected ? "#FFD063" : "transparent" border.color: tile.selected ? Theme.accent : "transparent"
Behavior on border.color { Behavior on border.color {
ColorAnimation { ColorAnimation {
@@ -266,7 +267,7 @@ Scope {
Text { Text {
Layout.fillWidth: true Layout.fillWidth: true
text: tile.modelData.name text: tile.modelData.name
color: tile.selected ? "#FFD063" : "#EEEEEE" color: tile.selected ? Theme.accent : Theme.text
font.pointSize: 10 font.pointSize: 10
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight elide: Text.ElideRight
@@ -7,6 +7,7 @@ import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// Variant 6 — "Slant": breaks up the rectangular layout with angled geometry — // Variant 6 — "Slant": breaks up the rectangular layout with angled geometry —
// a chamfered panel, a slanted header divider and sheared row highlights. // a chamfered panel, a slanted header divider and sheared row highlights.
@@ -77,7 +78,7 @@ Scope {
// Dim backdrop — click to dismiss. // Dim backdrop — click to dismiss.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#0A0A0C" color: Theme.surface
opacity: 0.55 opacity: 0.55
MouseArea { MouseArea {
@@ -107,8 +108,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
fillColor: "#0F1012" fillColor: Theme.surface
strokeColor: "#FFD063" strokeColor: Theme.accent
strokeWidth: 2 strokeWidth: 2
startX: frame.chamfer startX: frame.chamfer
@@ -153,7 +154,7 @@ Scope {
// run out to the top and left edges to meet the straight borders. // run out to the top and left edges to meet the straight borders.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: frame.chamfer startY: frame.chamfer
@@ -179,7 +180,7 @@ Scope {
// bottom and right edges. // bottom and right edges.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: panelShape.height - frame.chamfer startY: panelShape.height - frame.chamfer
@@ -205,7 +206,7 @@ Scope {
// detached from the panel by the width of the cut. // detached from the panel by the width of the cut.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: panelShape.height startY: panelShape.height
@@ -228,7 +229,7 @@ Scope {
// slanted end pieces on both arms. // slanted end pieces on both arms.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
// inner, right end of the bottom arm // inner, right end of the bottom arm
startX: panelShape.width / 3 startX: panelShape.width / 3
@@ -277,7 +278,7 @@ Scope {
// slanted end pieces on both arms. // slanted end pieces on both arms.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
// inner, bottom of the right arm // inner, bottom of the right arm
startX: panelShape.width startX: panelShape.width
@@ -345,7 +346,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 6 startX: 6
startY: 0 startY: 0
PathLine { PathLine {
@@ -367,7 +368,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 15 startX: 15
startY: 0 startY: 0
PathLine { PathLine {
@@ -389,7 +390,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 24 startX: 24
startY: 0 startY: 0
PathLine { PathLine {
@@ -420,8 +421,8 @@ Scope {
anchors.fill: parent anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE" color: Theme.text
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 20 font.pointSize: 20
font.letterSpacing: 1 font.letterSpacing: 1
clip: true clip: true
@@ -457,7 +458,7 @@ Scope {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0 visible: input.text.length === 0
text: "run" text: "run"
color: "#7A7B7D" color: Theme.muted
font: input.font font: input.font
} }
} }
@@ -465,8 +466,8 @@ Scope {
Text { Text {
text: model.apps.length text: model.apps.length
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 18 font.pointSize: 18
} }
} }
@@ -489,7 +490,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: divider.slant startX: divider.slant
startY: 0 startY: 0
PathLine { PathLine {
@@ -512,7 +513,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: divider.height startY: divider.height
PathLine { PathLine {
@@ -535,7 +536,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: divider.width startX: divider.width
startY: 0 startY: 0
PathLine { PathLine {
@@ -597,7 +598,7 @@ Scope {
// Body // Body
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#22262C" fillColor: Theme.raised
startX: appRow.shear startX: appRow.shear
startY: 0 startY: 0
PathLine { PathLine {
@@ -620,7 +621,7 @@ Scope {
// Left accent edge // Left accent edge
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: appRow.shear startX: appRow.shear
startY: 0 startY: 0
PathLine { PathLine {
@@ -655,7 +656,7 @@ Scope {
Text { Text {
text: appRow.modelData.name text: appRow.modelData.name
color: appRow.selected ? "#FFD063" : "#EEEEEE" color: appRow.selected ? Theme.accent : Theme.text
font.pointSize: 12 font.pointSize: 12
elide: Text.ElideRight elide: Text.ElideRight
Layout.fillWidth: true Layout.fillWidth: true
@@ -663,7 +664,7 @@ Scope {
Text { Text {
text: appRow.modelData.genericName || "" text: appRow.modelData.genericName || ""
color: "#7A7B7D" color: Theme.muted
font.pointSize: 10 font.pointSize: 10
elide: Text.ElideRight elide: Text.ElideRight
Layout.maximumWidth: 220 Layout.maximumWidth: 220
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.widgets.theme
// Variant 3 "Spotlight": top-center command bar with a compact result list. // Variant 3 "Spotlight": top-center command bar with a compact result list.
Scope { Scope {
@@ -91,9 +92,9 @@ Scope {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 60 implicitHeight: 60
color: "#0F1012" color: Theme.surface
border.width: 1 border.width: 1
border.color: "#FFD063" border.color: Theme.accent
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
@@ -103,8 +104,8 @@ Scope {
Text { Text {
text: ">" text: ">"
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 26 font.pointSize: 26
font.bold: true font.bold: true
} }
@@ -118,7 +119,7 @@ Scope {
anchors.fill: parent anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE" color: Theme.text
font.pointSize: 17 font.pointSize: 17
clip: true clip: true
@@ -153,7 +154,7 @@ Scope {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0 visible: input.text.length === 0
text: "run application" text: "run application"
color: "#7A7B7D" color: Theme.muted
font: input.font font: input.font
} }
} }
@@ -161,8 +162,8 @@ Scope {
Text { Text {
text: model.apps.length + " ▸" text: model.apps.length + " ▸"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 16 font.pointSize: 16
} }
} }
@@ -172,7 +173,7 @@ Scope {
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 3 implicitHeight: 3
color: "#FFD063" color: Theme.accent
visible: model.apps.length > 0 visible: model.apps.length > 0
} }
@@ -181,11 +182,11 @@ Scope {
Layout.fillWidth: true Layout.fillWidth: true
// Cap the visible height to maxRows; scroll beyond that. // Cap the visible height to maxRows; scroll beyond that.
implicitHeight: Math.min(model.apps.length, win.maxRows) * 44 + 2 implicitHeight: Math.min(model.apps.length, win.maxRows) * 44 + 2
color: "#0F1012" color: Theme.surface
opacity: 0.97 opacity: 0.97
visible: model.apps.length > 0 visible: model.apps.length > 0
border.width: 1 border.width: 1
border.color: "#292C30" border.color: Theme.raised
ListView { ListView {
id: list id: list
@@ -215,14 +216,14 @@ Scope {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: entry.selected ? "#1A1C1F" : "transparent" color: entry.selected ? Theme.selection : "transparent"
Rectangle { Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: 3 width: 3
color: "#FFD063" color: Theme.accent
visible: entry.selected visible: entry.selected
} }
@@ -239,7 +240,7 @@ Scope {
Text { Text {
text: entry.modelData.name text: entry.modelData.name
color: entry.selected ? "#FFD063" : "#EEEEEE" color: entry.selected ? Theme.accent : Theme.text
font.pointSize: 12 font.pointSize: 12
elide: Text.ElideRight elide: Text.ElideRight
Layout.fillWidth: true Layout.fillWidth: true
@@ -247,7 +248,7 @@ Scope {
Text { Text {
text: entry.modelData.genericName || "" text: entry.modelData.genericName || ""
color: "#7A7B7D" color: Theme.muted
font.pointSize: 10 font.pointSize: 10
elide: Text.ElideRight elide: Text.ElideRight
Layout.maximumWidth: 200 Layout.maximumWidth: 200
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.widgets.theme
// Variant 1 "Stack": left-anchored vertical list launcher. // Variant 1 "Stack": left-anchored vertical list launcher.
// Framed with the top/bottom accent strips used by the main Bar. // Framed with the top/bottom accent strips used by the main Bar.
@@ -82,7 +83,7 @@ Scope {
spacing: 0 spacing: 0
Rectangle { Rectangle {
color: "#FFD063" color: Theme.accent
implicitHeight: 5 implicitHeight: 5
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -93,8 +94,8 @@ Scope {
margin: 12 margin: 12
border.width: 1 border.width: 1
border.color: "#FFD063" border.color: Theme.accent
color: "#0F1012" color: Theme.surface
opacity: 0.95 opacity: 0.95
ColumnLayout { ColumnLayout {
@@ -107,7 +108,7 @@ Scope {
Text { Text {
text: "▚" text: "▚"
color: "#FFD063" color: Theme.accent
font.pointSize: 14 font.pointSize: 14
font.bold: true font.bold: true
} }
@@ -121,8 +122,8 @@ Scope {
anchors.fill: parent anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE" color: Theme.text
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 16 font.pointSize: 16
clip: true clip: true
@@ -158,7 +159,7 @@ Scope {
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0 visible: input.text.length === 0
text: "search" text: "search"
color: "#7A7B7D" color: Theme.muted
font: input.font font: input.font
} }
} }
@@ -166,14 +167,14 @@ Scope {
Text { Text {
text: model.apps.length text: model.apps.length
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 14 font.pointSize: 14
} }
} }
Rectangle { Rectangle {
color: "#FFD063" color: Theme.accent
implicitHeight: 2 implicitHeight: 2
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -207,7 +208,7 @@ Scope {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: appRow.selected ? "#292C30" : "transparent" color: appRow.selected ? Theme.raised : "transparent"
// Accent bar on the selected row. // Accent bar on the selected row.
Rectangle { Rectangle {
@@ -215,7 +216,7 @@ Scope {
anchors.top: parent.top anchors.top: parent.top
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: 3 width: 3
color: "#FFD063" color: Theme.accent
visible: appRow.selected visible: appRow.selected
} }
@@ -236,7 +237,7 @@ Scope {
Text { Text {
text: appRow.modelData.name text: appRow.modelData.name
color: appRow.selected ? "#FFD063" : "#EEEEEE" color: appRow.selected ? Theme.accent : Theme.text
font.pointSize: 12 font.pointSize: 12
elide: Text.ElideRight elide: Text.ElideRight
Layout.fillWidth: true Layout.fillWidth: true
@@ -245,7 +246,7 @@ Scope {
Text { Text {
visible: text.length > 0 visible: text.length > 0
text: appRow.modelData.genericName || appRow.modelData.comment || "" text: appRow.modelData.genericName || appRow.modelData.comment || ""
color: "#7A7B7D" color: Theme.muted
font.pointSize: 9 font.pointSize: 9
elide: Text.ElideRight elide: Text.ElideRight
Layout.fillWidth: true Layout.fillWidth: true
@@ -259,7 +260,7 @@ Scope {
} }
Rectangle { Rectangle {
color: "#FFD063" color: Theme.accent
implicitHeight: 5 implicitHeight: 5
Layout.fillWidth: true Layout.fillWidth: true
} }
@@ -2,6 +2,7 @@ import Quickshell.Services.Notifications
import Quickshell.Widgets import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import qs.widgets.theme
ColumnLayout { ColumnLayout {
id: root id: root
@@ -12,7 +13,7 @@ ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
Rectangle { Rectangle {
color: "#FFD063" color: Theme.accent
implicitHeight: 5 implicitHeight: 5
Layout.fillWidth: true Layout.fillWidth: true
@@ -23,8 +24,8 @@ ColumnLayout {
margin: 12 margin: 12
border.width: 1 border.width: 1
border.color: "#FFD063" border.color: Theme.accent
color: "#0F1012" color: Theme.surface
opacity: .9 opacity: .9
ColumnLayout { ColumnLayout {
@@ -45,7 +46,7 @@ ColumnLayout {
Text { Text {
text: root.modelData.summary text: root.modelData.summary
color: "#EEEEEE" color: Theme.text
font.pointSize: 14 font.pointSize: 14
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
@@ -57,7 +58,7 @@ ColumnLayout {
id: dismissButton id: dismissButton
text: "×" text: "×"
color: "#FFD063" color: Theme.accent
font.pointSize: 18 font.pointSize: 18
MouseArea { MouseArea {
@@ -71,7 +72,7 @@ ColumnLayout {
Text { Text {
visible: root.modelData.body !== "" visible: root.modelData.body !== ""
text: root.modelData.body text: root.modelData.body
color: "#EEEEEE" color: Theme.text
font.pointSize: 12 font.pointSize: 12
wrapMode: Text.Wrap wrapMode: Text.Wrap
@@ -92,9 +93,9 @@ ColumnLayout {
required property NotificationAction modelData required property NotificationAction modelData
color: "#292C30" color: Theme.raised
border.width: 1 border.width: 1
border.color: "#FFD063" border.color: Theme.accent
implicitHeight: 28 implicitHeight: 28
implicitWidth: actionText.implicitWidth + 16 implicitWidth: actionText.implicitWidth + 16
@@ -102,7 +103,7 @@ ColumnLayout {
id: actionText id: actionText
anchors.centerIn: parent anchors.centerIn: parent
text: actionButton.modelData.text text: actionButton.modelData.text
color: "#EEEEEE" color: Theme.text
font.pointSize: 12 font.pointSize: 12
} }
@@ -2,6 +2,7 @@ import Quickshell
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import Quickshell.Wayland import Quickshell.Wayland
import QtQuick import QtQuick
import qs.widgets.theme
Scope { Scope {
id: root id: root
@@ -68,7 +69,7 @@ Scope {
anchors.bottomMargin: 4 anchors.bottomMargin: 4
text: Math.round(Math.min(root.volume, root.maxVolume) * 100) + "%" text: Math.round(Math.min(root.volume, root.maxVolume) * 100) + "%"
color: !root.muted && root.volume > 1 ? "#FF6B4A" : "#FFD063" color: !root.muted && root.volume > 1 ? Theme.hot : Theme.accent
font.pointSize: 12 font.pointSize: 12
font.bold: true font.bold: true
} }
@@ -84,7 +85,7 @@ Scope {
anchors.centerIn: parent anchors.centerIn: parent
implicitHeight: 6 implicitHeight: 6
width: parent.width * Math.min(root.volume, root.maxVolume) / root.maxVolume width: parent.width * Math.min(root.volume, root.maxVolume) / root.maxVolume
color: "#FF6B4A" color: Theme.hot
visible: !root.muted && root.volume > 1 visible: !root.muted && root.volume > 1
Behavior on width { Behavior on width {
@@ -98,7 +99,7 @@ Scope {
anchors.centerIn: parent anchors.centerIn: parent
implicitHeight: 6 implicitHeight: 6
width: parent.width * Math.min(root.volume, 1) / root.maxVolume width: parent.width * Math.min(root.volume, 1) / root.maxVolume
color: root.muted ? "#7A7B7D" : "#FFD063" color: root.muted ? Theme.muted : Theme.accent
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation {
+23 -22
View File
@@ -8,6 +8,7 @@ import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// A vertical sidebar carrying the "Slant" (launcher V6) visual language // A vertical sidebar carrying the "Slant" (launcher V6) visual language
// chamfered panel, thick trapezoid bevel accents, an outward bracket, a // chamfered panel, thick trapezoid bevel accents, an outward bracket, a
@@ -81,8 +82,8 @@ Scope {
// Panel: big chamfers on top-right & bottom-left, small bevels // Panel: big chamfers on top-right & bottom-left, small bevels
// on top-left & bottom-right (mirror of the left-anchored panel). // on top-left & bottom-right (mirror of the left-anchored panel).
ShapePath { ShapePath {
fillColor: "#0F1012" fillColor: Theme.surface
strokeColor: "#FFD063" strokeColor: Theme.accent
strokeWidth: 2 strokeWidth: 2
startX: panelShape.width - frame.chamfer startX: panelShape.width - frame.chamfer
@@ -124,7 +125,7 @@ Scope {
// Thick top-right bevel accent (trapezoid to the edges). // Thick top-right bevel accent (trapezoid to the edges).
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: frame.chamfer startY: frame.chamfer
@@ -149,7 +150,7 @@ Scope {
// Thick bottom-left bevel accent. // Thick bottom-left bevel accent.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: panelShape.height - frame.chamfer startY: panelShape.height - frame.chamfer
@@ -174,7 +175,7 @@ Scope {
// Floating triangle cap in the bottom-left notch. // Floating triangle cap in the bottom-left notch.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: panelShape.height startY: panelShape.height
@@ -197,7 +198,7 @@ Scope {
// corner following the small chamfer. // corner following the small chamfer.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: frame.armSide startY: frame.armSide
@@ -245,15 +246,15 @@ Scope {
anchors.rightMargin: 8 anchors.rightMargin: 8
spacing: 10 spacing: 10
// Clock Digital-7, hh over mm // Clock readout font, hh over mm
Text { Text {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: Qt.formatDateTime(clock.date, "hh\nmm") text: Qt.formatDateTime(clock.date, "hh\nmm")
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 22 font.pointSize: 22
font.letterSpacing: 1 font.letterSpacing: 1
color: "#EEEEEE" color: Theme.text
SystemClock { SystemClock {
id: clock id: clock
@@ -266,9 +267,9 @@ Scope {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
text: Qt.formatDateTime(clock.date, "dd\nMMM").toUpperCase() text: Qt.formatDateTime(clock.date, "dd\nMMM").toUpperCase()
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 13 font.pointSize: 13
color: "#FFD063" color: Theme.accent
} }
// Slanted divider // Slanted divider
@@ -282,7 +283,7 @@ Scope {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 8 startX: 8
startY: 0 startY: 0
PathLine { x: divider.width; y: 0 } PathLine { x: divider.width; y: 0 }
@@ -301,9 +302,9 @@ Scope {
Text { Text {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: "VOL" text: "VOL"
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 10 font.pointSize: 10
color: "#7A7B7D" color: Theme.muted
} }
ColumnLayout { ColumnLayout {
@@ -336,8 +337,8 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 1 strokeWidth: 1
strokeColor: "#7A7B7D" strokeColor: Theme.muted
fillColor: "#292C30" fillColor: Theme.raised
startX: seg.chamfer startX: seg.chamfer
startY: 0 startY: 0
@@ -375,7 +376,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FF6B4A" fillColor: Theme.hot
startX: segFill.chamfer startX: segFill.chamfer
startY: 0 startY: 0
PathLine { x: segFill.width; y: 0 } PathLine { x: segFill.width; y: 0 }
@@ -407,8 +408,8 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 1 strokeWidth: 1
strokeColor: "#7A7B7D" strokeColor: Theme.muted
fillColor: "#292C30" fillColor: Theme.raised
startX: volMeter.chamfer startX: volMeter.chamfer
startY: 0 startY: 0
@@ -448,7 +449,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: root.muted ? "#7A7B7D" : "#FFD063" fillColor: root.muted ? Theme.muted : Theme.accent
startX: vol.chamfer startX: vol.chamfer
startY: 0 startY: 0
PathLine { x: vol.width; y: 0 } PathLine { x: vol.width; y: 0 }
@@ -466,9 +467,9 @@ Scope {
Text { Text {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: root.muted ? "--" : Math.round(root.volume * 100) text: root.muted ? "--" : Math.round(root.volume * 100)
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 14 font.pointSize: 14
color: root.muted ? "#7A7B7D" : "#EEEEEE" color: root.muted ? Theme.muted : Theme.text
} }
} }
} }
+14 -13
View File
@@ -6,10 +6,11 @@ import Quickshell.Widgets
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// The right bar: a compact utility strip for the SystemTray icons, styled // The right bar: a compact utility strip for the SystemTray icons, styled
// in the same family as the Launcher (V6 "Slant") and SideBar accent // in the same family as the Launcher (V6 "Slant") and SideBar accent
// color, chamfered corners, Digital-7 Mono, the slash-trio motif but with // color, chamfered corners, the readout font, the slash-trio motif but with
// its own plain, evenly-chamfered panel rather than their ornate // its own plain, evenly-chamfered panel rather than their ornate
// bracket-and-cap silhouette, since this is a secondary/utility bar rather // bracket-and-cap silhouette, since this is a secondary/utility bar rather
// than a hero surface. // than a hero surface.
@@ -54,8 +55,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
fillColor: "#0F1012" fillColor: Theme.surface
strokeColor: "#FFD063" strokeColor: Theme.accent
strokeWidth: 2 strokeWidth: 2
startX: frame.chamfer startX: frame.chamfer
@@ -114,7 +115,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 6 startX: 6
startY: 0 startY: 0
PathLine { x: 10; y: 0 } PathLine { x: 10; y: 0 }
@@ -124,7 +125,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 15 startX: 15
startY: 0 startY: 0
PathLine { x: 19; y: 0 } PathLine { x: 19; y: 0 }
@@ -134,7 +135,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 24 startX: 24
startY: 0 startY: 0
PathLine { x: 28; y: 0 } PathLine { x: 28; y: 0 }
@@ -155,7 +156,7 @@ Scope {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 8 startX: 8
startY: 0 startY: 0
PathLine { x: divider.width; y: 0 } PathLine { x: divider.width; y: 0 }
@@ -169,9 +170,9 @@ Scope {
Text { Text {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: "TRAY" text: "TRAY"
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 12 font.pointSize: 12
color: "#7A7B7D" color: Theme.muted
} }
ListView { ListView {
@@ -201,17 +202,17 @@ Scope {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
visible: SystemTray.items.values.length === 0 visible: SystemTray.items.values.length === 0
text: "--" text: "--"
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 14 font.pointSize: 14
color: "#7A7B7D" color: Theme.muted
} }
Text { Text {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
text: SystemTray.items.values.length text: SystemTray.items.values.length
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 16 font.pointSize: 16
color: "#EEEEEE" color: Theme.text
} }
} }
} }
@@ -2,6 +2,7 @@ import Quickshell
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// A single tray icon, chamfered to match the Slant (launcher V6 / SideBar) // A single tray icon, chamfered to match the Slant (launcher V6 / SideBar)
// visual language instead of a plain rectangular hit target. // visual language instead of a plain rectangular hit target.
@@ -35,8 +36,8 @@ MouseArea {
ShapePath { ShapePath {
strokeWidth: 1 strokeWidth: 1
strokeColor: root.containsMouse ? "#FFD063" : "#7A7B7D" strokeColor: root.containsMouse ? Theme.accent : Theme.muted
fillColor: "#292C30" fillColor: Theme.raised
startX: root.chamfer startX: root.chamfer
startY: 0 startY: 0
@@ -0,0 +1,61 @@
pragma Singleton
import Quickshell
import QtQuick
// Single source of truth for the shell's palette and font families.
//
// The shell previously ran two unrelated palettes: an amber one (#FFD063) used
// by the launchers, sidebar, systray, vitals and notifications, and an orange
// one (#e8722a) that only the dense bar had, tokenized as per-file properties.
// This unifies on the ORANGE values under the AMBER naming scheme.
//
// `surface` deliberately takes the dense bar's void (#0a0a0a) rather than the
// old panel background (#0F1012), which also absorbs the near-identical
// #0A0A0C scrim.
Singleton {
// ---- core ----
readonly property color accent: "#e8722a" // was #FFD063 (amber) / #e8722a (bar)
readonly property color text: "#dedede" // was #EEEEEE / #dedede
readonly property color muted: "#858585" // was #7A7B7D / #858585
readonly property color surface: "#0a0a0a" // was #0F1012 + #0A0A0C + #0a0a0a
readonly property color hot: "#ff6b4a" // alert/hot; no bar equivalent, kept
// ---- supporting darks ----
// A three-step ramp above `surface`. `raised` also absorbs #22262C, which
// differed from #292C30 by an imperceptible amount across two call sites.
readonly property color selection: "#1a1c1f" // selected row fill
readonly property color raised: "#292c30" // raised surface / border
readonly property color disabled: "#3a3d42" // unknown / disabled stroke
// ---- accents ----
// The pale "flash" the top/bottom bars show while a launcher is open. Was a
// hand-picked #FFF3C0 against amber; derived here so it tracks `accent`.
// 55% toward white reproduces the original amber relationship closely
// (#FFD063 -> #FFE9B8 vs the hand-picked #FFF3C0).
readonly property color accentSoft: Qt.tint(accent, Qt.rgba(1, 1, 1, 0.55))
readonly property color highlight: "#ffffff"
// ---- fonts ----
// Two faces. `readoutFont` is an alias rather than a second literal so the
// two roles cannot silently drift apart; point it at a different family if
// the readouts should ever diverge from the headings again.
//
// Installed by services/desktop/desktop-apps.nix (nerd-fonts.departure-mono).
// The former readout face, Digital-7 Mono, was never packaged it relied on
// a manual ~/.dots/fonts/digital_7 install, so dropping it also removes an
// undeclared external dependency.
readonly property string displayFont: "DepartureMono Nerd Font" // headings, large values
readonly property string readoutFont: displayFont // seven-segment readouts: launchers, sidebar, systray, vitals
readonly property string microFont: "DejaVu Sans Mono" // dense bar micro labels
// ---- derived alpha variants ----
// The dense bar hand-encoded these as Qt.rgba(0.87,0.87,0.87,a) = text and
// Qt.rgba(0.91,0.45,0.16,a) = accent. Expressed as functions so the
// relationship survives a palette change.
function textAlpha(a) { return Qt.rgba(text.r, text.g, text.b, a); }
function accentAlpha(a) { return Qt.rgba(accent.r, accent.g, accent.b, a); }
// Hairline rule / panel outline: text at 28%.
readonly property color hair: textAlpha(0.28)
}
@@ -1,5 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// Horizontal meter in the Slant language: a chamfered track whose fill is a // Horizontal meter in the Slant language: a chamfered track whose fill is a
// clipped copy of the SAME hexagon, so empty and full always share one // clipped copy of the SAME hexagon, so empty and full always share one
@@ -26,8 +27,8 @@ Item {
ShapePath { ShapePath {
strokeWidth: 1 strokeWidth: 1
strokeColor: bar.unknown ? "#3A3D42" : "#7A7B7D" strokeColor: bar.unknown ? Theme.disabled : Theme.muted
fillColor: "#292C30" fillColor: Theme.raised
startX: bar.chamfer startX: bar.chamfer
startY: 0 startY: 0
@@ -72,7 +73,7 @@ Item {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: bar.hot ? "#FF6B4A" : "#FFD063" fillColor: bar.hot ? Theme.hot : Theme.accent
Behavior on fillColor { Behavior on fillColor {
ColorAnimation { ColorAnimation {
+43 -42
View File
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import QtQuick import QtQuick
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Shapes import QtQuick.Shapes
import qs.widgets.theme
// Host vitals HUD the "Slant" language (chamfered panel, trapezoid bevels, // Host vitals HUD the "Slant" language (chamfered panel, trapezoid bevels,
// outward corner chunks, floating cap, slanted dividers) carried over from the // outward corner chunks, floating cap, slanted dividers) carried over from the
@@ -59,7 +60,7 @@ Scope {
// Dim backdrop click anywhere to dismiss. // Dim backdrop click anywhere to dismiss.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: "#0A0A0C" color: Theme.surface
opacity: 0.5 opacity: 0.5
MouseArea { MouseArea {
@@ -102,8 +103,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer preferredRendererType: Shape.CurveRenderer
ShapePath { ShapePath {
fillColor: "#0F1012" fillColor: Theme.surface
strokeColor: "#FFD063" strokeColor: Theme.accent
strokeWidth: 2 strokeWidth: 2
startX: frame.chamfer startX: frame.chamfer
@@ -121,7 +122,7 @@ Scope {
// Thick top-left bevel accent. // Thick top-left bevel accent.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 0 startX: 0
startY: frame.chamfer startY: frame.chamfer
@@ -134,7 +135,7 @@ Scope {
// Thick bottom-right bevel accent. // Thick bottom-right bevel accent.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: panelShape.height - frame.chamfer startY: panelShape.height - frame.chamfer
@@ -147,7 +148,7 @@ Scope {
// Floating triangle cap in the bottom-right notch. // Floating triangle cap in the bottom-right notch.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: panelShape.height startY: panelShape.height
@@ -159,7 +160,7 @@ Scope {
// Heavy outward chunk wrapping the bottom-left corner. // Heavy outward chunk wrapping the bottom-left corner.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width / 3 startX: panelShape.width / 3
startY: panelShape.height startY: panelShape.height
@@ -176,7 +177,7 @@ Scope {
// Heavy outward chunk wrapping the top-right corner. // Heavy outward chunk wrapping the top-right corner.
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: panelShape.width startX: panelShape.width
startY: panelShape.height / 3 startY: panelShape.height / 3
@@ -217,7 +218,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 6 startX: 6
startY: 0 startY: 0
PathLine { x: 10; y: 0 } PathLine { x: 10; y: 0 }
@@ -227,7 +228,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 15 startX: 15
startY: 0 startY: 0
PathLine { x: 19; y: 0 } PathLine { x: 19; y: 0 }
@@ -237,7 +238,7 @@ Scope {
} }
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 24 startX: 24
startY: 0 startY: 0
PathLine { x: 28; y: 0 } PathLine { x: 28; y: 0 }
@@ -249,8 +250,8 @@ Scope {
Text { Text {
text: (vitals.host || "vitals").toUpperCase() text: (vitals.host || "vitals").toUpperCase()
color: "#EEEEEE" color: Theme.text
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 20 font.pointSize: 20
font.letterSpacing: 2 font.letterSpacing: 2
} }
@@ -261,15 +262,15 @@ Scope {
Text { Text {
text: "UP" text: "UP"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
} }
Text { Text {
text: vitals.fmtUptime(vitals.uptime) text: vitals.fmtUptime(vitals.uptime)
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 16 font.pointSize: 16
} }
} }
@@ -281,8 +282,8 @@ Scope {
Layout.fillWidth: true Layout.fillWidth: true
visible: vitals.failed visible: vitals.failed
text: "NODE_EXPORTER UNREACHABLE ON :" + vitals.port text: "NODE_EXPORTER UNREACHABLE ON :" + vitals.port
color: "#FF6B4A" color: Theme.hot
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 13 font.pointSize: 13
} }
@@ -353,7 +354,7 @@ Scope {
Text { Text {
Layout.preferredWidth: 96 Layout.preferredWidth: 96
text: diskRow.modelData.mount text: diskRow.modelData.mount
color: "#7A7B7D" color: Theme.muted
font.pointSize: 9 font.pointSize: 9
elide: Text.ElideMiddle elide: Text.ElideMiddle
} }
@@ -369,8 +370,8 @@ Scope {
Layout.preferredWidth: 48 Layout.preferredWidth: 48
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
text: Math.round(diskRow.frac * 100) + "%" text: Math.round(diskRow.frac * 100) + "%"
color: diskRow.frac >= 0.9 ? "#FF6B4A" : "#EEEEEE" color: diskRow.frac >= 0.9 ? Theme.hot : Theme.text
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 13 font.pointSize: 13
} }
@@ -378,8 +379,8 @@ Scope {
Layout.preferredWidth: 104 Layout.preferredWidth: 104
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
text: vitals.fmtBytes(diskRow.modelData.size - diskRow.modelData.used) + " FREE" text: vitals.fmtBytes(diskRow.modelData.size - diskRow.modelData.used) + " FREE"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
} }
} }
@@ -399,21 +400,21 @@ Scope {
Text { Text {
Layout.preferredWidth: 96 Layout.preferredWidth: 96
text: vitals.netIface || "NET" text: vitals.netIface || "NET"
color: "#7A7B7D" color: Theme.muted
font.pointSize: 9 font.pointSize: 9
} }
Text { Text {
text: "RX" text: "RX"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
} }
Text { Text {
text: vitals.fmtRate(vitals.netRx) text: vitals.fmtRate(vitals.netRx)
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 14 font.pointSize: 14
} }
@@ -423,15 +424,15 @@ Scope {
Text { Text {
text: "TX" text: "TX"
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
} }
Text { Text {
text: vitals.fmtRate(vitals.netTx) text: vitals.fmtRate(vitals.netTx)
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 14 font.pointSize: 14
// Right-align the TX readout against the panel edge the // Right-align the TX readout against the panel edge the
@@ -469,8 +470,8 @@ Scope {
Text { Text {
Layout.preferredWidth: 46 Layout.preferredWidth: 46
text: metric.label text: metric.label
color: "#FFD063" color: Theme.accent
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 15 font.pointSize: 15
font.letterSpacing: 1 font.letterSpacing: 1
} }
@@ -486,8 +487,8 @@ Scope {
Layout.preferredWidth: 54 Layout.preferredWidth: 54
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
text: metric.readout text: metric.readout
color: "#EEEEEE" color: Theme.text
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 16 font.pointSize: 16
} }
} }
@@ -499,8 +500,8 @@ Scope {
Text { Text {
text: metric.detail text: metric.detail
color: "#7A7B7D" color: Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
} }
@@ -511,8 +512,8 @@ Scope {
Text { Text {
visible: metric.aside.length > 0 visible: metric.aside.length > 0
text: metric.aside text: metric.aside
color: metric.asideHot ? "#FF6B4A" : "#7A7B7D" color: metric.asideHot ? Theme.hot : Theme.muted
font.family: "Digital-7 Mono" font.family: Theme.readoutFont
font.pointSize: 11 font.pointSize: 11
} }
} }
@@ -530,7 +531,7 @@ Scope {
ShapePath { ShapePath {
strokeWidth: 0 strokeWidth: 0
fillColor: "#FFD063" fillColor: Theme.accent
startX: 6 startX: 6
startY: 0 startY: 0
PathLine { x: divider.width; y: 0 } PathLine { x: divider.width; y: 0 }
+108
View File
@@ -552,5 +552,113 @@
machine.crash() machine.crash()
''; '';
}; };
# `nix develop` — hot-reload loop for dotfiles/quickshell.
#
# hosts/terra/home.nix ships the shell via `xdg.configFile."quickshell"`,
# which COPIES the tree into the store, so ~/.config/quickshell is a
# read-only symlink into /nix/store and every QML tweak costs a
# nixos-rebuild. quickshell DOES hot-reload on file save — but only for
# the files it is watching, which are those frozen store copies. Pointing
# it at the working tree with `qs -p` restores edit-save-see, no rebuild.
#
# quickshell keys instance identity on the CONFIG PATH, so a working-tree
# instance and the store-backed one are two different instances that would
# both map layer-shell bars onto every output. Hence a swap, not a second
# instance — and the swap starts dev FIRST, killing the packaged shell
# only once dev is confirmed up, so a QML error in the working tree leaves
# you on your normal bar instead of no bar at all.
#
# Every kill is scoped to one config (`qs kill` = default only, `qs kill
# -p` = that path only). A blanket kill would also take out unrelated
# quickshell instances — pkgs/rishot.nix is one.
#
# Deliberately NOT wired to direnv (no .envrc in this repo): programs.direnv
# is enabled for this user, so a `use flake` would swap the running desktop
# shell on every `cd` into the checkout, including over ssh.
devShells.${system}.default =
let
pkgs = nixpkgs.legacyPackages.${system};
# Same nixpkgs terra's home.nix takes pkgs.quickshell from, so the dev
# instance is the identical build to the packaged one.
qs = "${nixpkgs.legacyPackages.${system}.quickshell}/bin/qs";
git = "${nixpkgs.legacyPackages.${system}.git}/bin/git";
# Resolved at RUN time, not build time: the entire point is to run the
# working tree, and `self` here is only a store snapshot of it.
preamble = ''
root="$(${git} rev-parse --show-toplevel 2>/dev/null || pwd)"
cfg="$root/dotfiles/quickshell"
if [ ! -f "$cfg/shell.qml" ]; then
echo "no shell.qml under $cfg run this from the homelab checkout" >&2
exit 1
fi
# `qs list` exits 0 whether or not it found anything, and only emits
# json when it did — so "json came back" is the liveness test.
running() { ${qs} list -p "$1" -j 2>/dev/null | grep -q '"id"'; }
prod_running() { ${qs} list -j 2>/dev/null | grep -q '"id"'; }
'';
qs-dev = pkgs.writeShellScriptBin "qs-dev" ''
set -uo pipefail
${preamble}
if [ -z "''${WAYLAND_DISPLAY:-}" ]; then
echo "qs-dev: no WAYLAND_DISPLAY refusing to swap the desktop shell" >&2
exit 1
fi
if running "$cfg"; then
echo "qs-dev: already running from $cfg"
exit 0
fi
${qs} -d -p "$cfg"
# Confirm it came up before touching the packaged shell.
for _ in $(seq 1 50); do
running "$cfg" && break
sleep 0.1
done
if ! running "$cfg"; then
echo "qs-dev: dev shell failed to start packaged shell left alone" >&2
echo "qs-dev: run 'qs -p $cfg' in the foreground to see the QML error" >&2
exit 1
fi
${qs} kill || true
echo "qs-dev: live on $cfg edits there now hot-reload"
'';
qs-prod = pkgs.writeShellScriptBin "qs-prod" ''
set -uo pipefail
${preamble}
running "$cfg" && ${qs} kill -p "$cfg" || true
prod_running || ${qs} -d
echo "qs-prod: back on ~/.config/quickshell"
'';
in
pkgs.mkShell {
packages = [ pkgs.quickshell qs-dev qs-prod ];
# Swap on entry, swap back on exit. Three guards:
# - interactive only ($- has i). `nix develop --command X` EXECs X,
# replacing the shell that set the trap, so the restore would
# never run and you'd be left on the dev instance. Non-interactive
# use gets the explicit `nix develop -c qs-dev` instead.
# - WAYLAND_DISPLAY, so entering the shell over ssh cannot kill the
# desktop's bar and leave nothing in its place.
# - a sentinel, so a nested `nix develop` does not swap (and then
# restore) a second time.
shellHook = ''
if [[ $- == *i* ]] && [ -n "''${WAYLAND_DISPLAY:-}" ] && [ -z "''${HOMELAB_QS_DEV:-}" ]; then
export HOMELAB_QS_DEV=1
qs-dev && trap qs-prod EXIT
fi
echo "homelab devshell qs-dev (working tree) / qs-prod (packaged); exit restores"
'';
};
}; };
} }