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.
- `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.
**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 qs.widgets.launcher
import qs.widgets.theme
Scope {
id: root
@@ -42,7 +43,7 @@ Scope {
implicitHeight: 12
// Brightens when the Dock launcher (variant 5) opens.
color: LauncherState.dockOpen ? "#FFF3C0" : "#FFD063"
color: LauncherState.dockOpen ? Theme.accentSoft : Theme.accent
Behavior on color {
ColorAnimation {
@@ -53,7 +54,7 @@ Scope {
// Gentle "listening" pulse while the dock is open.
Rectangle {
anchors.fill: parent
color: "#FFFFFF"
color: Theme.highlight
opacity: 0
visible: LauncherState.dockOpen
+3 -2
View File
@@ -5,6 +5,7 @@ import Quickshell.Widgets
import QtQuick
import qs.widgets.launcher
import qs.widgets.theme
Scope {
id: root
@@ -42,7 +43,7 @@ Scope {
implicitHeight: 6
// Brightens when the Console launcher (variant 4) opens.
color: LauncherState.consoleOpen ? "#FFF3C0" : "#FFD063"
color: LauncherState.consoleOpen ? Theme.accentSoft : Theme.accent
Behavior on color {
ColorAnimation {
@@ -53,7 +54,7 @@ Scope {
// Gentle "listening" pulse while the console is open.
Rectangle {
anchors.fill: parent
color: "#FFFFFF"
color: Theme.highlight
opacity: 0
visible: LauncherState.consoleOpen
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Shapes
import qs.widgets.theme
// Renderable visual core for the desktop telemetry rail. Runtime services stay
// in DenseBar.qml so this Item can be exercised without Wayland or Hyprland.
@@ -11,14 +12,7 @@ Item {
implicitWidth: 1920
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 string displayFont: "DepartureMono Nerd Font"
readonly property string microFont: "DejaVu Sans Mono"
property bool autoClock: true
property date now: new Date()
@@ -69,11 +63,6 @@ Item {
onTriggered: root.now = new Date()
}
Rectangle {
anchors.fill: parent
color: root.voidColor
}
// Faint drafting grid; no gradient and deliberately subordinate to data.
Repeater {
model: Math.ceil(root.width / 40)
@@ -82,7 +71,7 @@ Item {
x: index * 40
width: 1
height: root.height
color: root.inkColor
color: Theme.text
opacity: 0.018
}
}
@@ -94,7 +83,7 @@ Item {
y: index * 40
width: root.width
height: 1
color: root.inkColor
color: Theme.text
opacity: 0.018
}
}
@@ -115,7 +104,7 @@ Item {
anchors.fill: parent
spacing: 8
TelemetryPanel {
StatusBarPanel {
width: array.identityWidth
height: array.height
panelId: "001"
@@ -125,8 +114,8 @@ Item {
x: 12
y: 34
text: root.hostName.toUpperCase()
color: root.inkColor
font.family: root.displayFont
color: Theme.text
font.family: Theme.displayFont
font.pixelSize: root.compact ? 20 : 25
font.bold: true
font.letterSpacing: 2
@@ -138,8 +127,8 @@ Item {
x: 13
y: 63
text: "STATUS ARRAY // " + (root.telemetryReady ? "LIVE" : "STANDBY")
color: root.accentColor
font.family: root.microFont
color: Theme.accent
font.family: Theme.microFont
font.pixelSize: 7
font.letterSpacing: 1.4
}
@@ -149,7 +138,7 @@ Item {
y: 36
width: 1
height: 43
color: root.hairColor
color: Theme.hair
}
Rectangle {
@@ -157,7 +146,7 @@ Item {
y: 42
width: 5
height: 5
color: root.accentColor
color: Theme.accent
opacity: root.telemetryReady ? 1 : 0.35
}
@@ -165,8 +154,8 @@ Item {
x: parent.width - 50
y: 38
text: root.telemetryReady ? "ONLINE" : "LOCAL"
color: root.accentColor
font.family: root.microFont
color: Theme.accent
font.family: Theme.microFont
font.pixelSize: 7
}
@@ -174,8 +163,8 @@ Item {
x: parent.width - 63
y: 57
text: "NODE // " + (root.hostName || "--").toUpperCase().slice(0, 7)
color: root.mutedColor
font.family: root.microFont
color: Theme.muted
font.family: Theme.microFont
font.pixelSize: 6
}
@@ -186,7 +175,7 @@ Item {
height: 10
ShapePath {
fillColor: "transparent"
strokeColor: root.accentColor
strokeColor: Theme.accent
strokeWidth: 1
startX: 0; startY: 6
PathLine { x: 11; y: 6 }
@@ -198,7 +187,7 @@ Item {
}
}
TelemetryPanel {
StatusBarPanel {
width: array.flexWidth
height: array.height
panelId: "02"
@@ -245,7 +234,7 @@ Item {
}
}
TelemetryPanel {
StatusBarPanel {
width: array.radarWidth
height: array.height
panelId: "03"
@@ -259,7 +248,7 @@ Item {
}
}
TelemetryPanel {
StatusBarPanel {
width: array.flexWidth
height: array.height
panelId: "04"
@@ -285,8 +274,8 @@ Item {
width: parent.width
text: root.networkRxText
horizontalAlignment: Text.AlignRight
color: root.accentColor
font.family: root.displayFont
color: Theme.accent
font.family: Theme.displayFont
font.pixelSize: root.compact ? 11 : 13
font.bold: true
elide: Text.ElideLeft
@@ -296,8 +285,8 @@ Item {
width: parent.width
text: root.networkTxText
horizontalAlignment: Text.AlignRight
color: root.inkColor
font.family: root.displayFont
color: Theme.text
font.family: Theme.displayFont
font.pixelSize: root.compact ? 11 : 13
font.bold: true
elide: Text.ElideLeft
@@ -306,7 +295,7 @@ Item {
}
}
TelemetryPanel {
StatusBarPanel {
width: array.stateWidth
height: array.height
panelId: "05"
@@ -327,7 +316,7 @@ Item {
y: 33
width: 1
height: 46
color: root.hairColor
color: Theme.hair
}
Column {
@@ -341,8 +330,8 @@ Item {
width: parent.width
text: root.timeText(root.now)
horizontalAlignment: Text.AlignRight
color: root.inkColor
font.family: root.displayFont
color: Theme.text
font.family: Theme.displayFont
font.pixelSize: root.compact ? 20 : 22
font.bold: true
font.letterSpacing: 1
@@ -351,8 +340,8 @@ Item {
width: parent.width
text: root.dateText(root.now)
horizontalAlignment: Text.AlignRight
color: root.accentColor
font.family: root.microFont
color: Theme.accent
font.family: Theme.microFont
font.pixelSize: 6
elide: Text.ElideLeft
}
@@ -362,7 +351,7 @@ Item {
}
}
TelemetryPanel {
StatusBarPanel {
id: rail
x: 12
y: 108
@@ -382,8 +371,8 @@ Item {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
text: "06 // DESKTOP"
color: root.accentColor
font.family: root.microFont
color: Theme.accent
font.family: Theme.microFont
font.pixelSize: 7
font.letterSpacing: 1
}
@@ -398,14 +387,14 @@ Item {
required property var modelData
width: 24
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.color: Number(modelData) === root.activeWorkspaceId ? root.accentColor : root.hairColor
border.color: Number(modelData) === root.activeWorkspaceId ? Theme.accent : Theme.hair
Text {
anchors.centerIn: parent
text: root.two(Number(parent.modelData))
color: Number(parent.modelData) === root.activeWorkspaceId ? root.accentColor : root.mutedColor
font.family: root.microFont
color: Number(parent.modelData) === root.activeWorkspaceId ? Theme.accent : Theme.muted
font.family: Theme.microFont
font.pixelSize: 7
}
MouseArea {
@@ -424,8 +413,8 @@ Item {
x: 76
anchors.verticalCenter: parent.verticalCenter
text: "COMPOSITOR // NODE_EXPORTER // SHELL"
color: root.telemetryReady ? root.inkColor : root.mutedColor
font.family: root.microFont
color: root.telemetryReady ? Theme.text : Theme.muted
font.family: Theme.microFont
font.pixelSize: 7
elide: Text.ElideRight
width: parent.width - 84
@@ -439,8 +428,8 @@ Item {
x: 93
anchors.verticalCenter: parent.verticalCenter
text: root.storageFreeText
color: root.inkColor
font.family: root.microFont
color: Theme.text
font.family: Theme.microFont
font.pixelSize: 8
}
SegmentMeter {
@@ -463,8 +452,8 @@ Item {
x: 89
anchors.verticalCenter: parent.verticalCenter
text: root.audioMuted ? "MUTED" : Math.round(root.audioFraction * 100) + "%"
color: root.audioMuted ? root.mutedColor : root.accentColor
font.family: root.microFont
color: root.audioMuted ? Theme.muted : Theme.accent
font.family: Theme.microFont
font.pixelSize: 8
}
SegmentMeter {
@@ -488,8 +477,8 @@ Item {
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
text: root.telemetryReady ? "WARN:00 // ERR:00" : "TELEMETRY WAIT"
color: root.telemetryReady ? root.mutedColor : root.accentColor
font.family: root.microFont
color: root.telemetryReady ? Theme.muted : Theme.accent
font.family: Theme.microFont
font.pixelSize: 7
elide: Text.ElideLeft
width: parent.width - 64
@@ -507,7 +496,7 @@ Item {
height: 12
ShapePath {
fillColor: "transparent"
strokeColor: Qt.rgba(0.91, 0.45, 0.16, 0.55)
strokeColor: Theme.accentAlpha(0.55)
strokeWidth: 1
startX: 0; startY: 1
PathLine { x: 220; y: 1 }
@@ -529,15 +518,15 @@ Item {
required property int index
width: 5
height: 3
color: index % 2 === 0 ? root.accentColor : "transparent"
color: index % 2 === 0 ? Theme.accent : "transparent"
opacity: 0.58
}
}
}
component MicroText: Text {
color: root.mutedColor
font.family: root.microFont
color: Theme.muted
font.family: Theme.microFont
font.pixelSize: 6
font.letterSpacing: 0.7
}
@@ -550,109 +539,11 @@ Item {
anchors.right: parent.right
width: 1
height: parent.height
color: root.hairColor
color: Theme.hair
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 {
id: metric
property string label: ""
@@ -668,8 +559,8 @@ Item {
anchors.right: parent.right
y: -3
text: metric.readout
color: root.inkColor
font.family: root.displayFont
color: Theme.text
font.family: Theme.displayFont
font.pixelSize: root.compact ? 14 : 17
font.bold: true
}
@@ -698,9 +589,9 @@ Item {
width: Math.max(2, (meter.width - (meter.segments - 1) * meter.spacing) / meter.segments)
height: meter.height
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.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 {
anchors.fill: parent
ShapePath {
fillColor: state.active ? Qt.rgba(0.91, 0.45, 0.16, 0.18) : "transparent"
strokeColor: state.active ? root.accentColor : root.hairColor
fillColor: state.active ? Theme.accentAlpha(0.18) : "transparent"
strokeColor: state.active ? Theme.accent : Theme.hair
strokeWidth: 1
startX: 1; startY: 1
PathLine { x: parent.width - 7; y: 1 }
@@ -732,8 +623,8 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
y: 7
text: state.code
color: state.active ? root.accentColor : root.inkColor
font.family: root.displayFont
color: state.active ? Theme.accent : Theme.text
font.family: Theme.displayFont
font.pixelSize: 13
font.bold: true
}
@@ -758,27 +649,27 @@ Item {
radius: width / 2
color: "transparent"
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: parent.width / 2; y: 0; width: 1; height: parent.height; color: root.hairColor }
Rectangle { x: 12; y: 18; width: 4; height: 4; color: root.accentColor }
Rectangle { x: parent.width - 14; y: parent.height - 20; width: 4; height: 4; color: root.accentColor }
Rectangle { x: parent.width / 2; y: parent.height - 11; width: 4; height: 4; color: root.accentColor }
MicroText { anchors.right: parent.right; y: 3; text: "R:" + Math.round(radar.level * 99); color: root.accentColor }
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: Theme.hair }
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: Theme.accent }
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: Theme.accent }
}
component NetworkTrace: Item {
id: trace
property real level: 0
Rectangle { x: 0; y: parent.height - 1; width: parent.width; height: 1; color: root.hairColor }
Rectangle { x: 0; y: 0; width: 1; height: parent.height; 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: Theme.hair }
Shape {
anchors.fill: parent
ShapePath {
fillColor: "transparent"
strokeColor: root.accentColor
strokeColor: Theme.accent
strokeWidth: 1.2
startX: 0; startY: 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.Shapes
import qs.widgets.theme
Shape {
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "#FFD063"
fillColor: Theme.accent
strokeWidth: 0
startX: 0
@@ -5,6 +5,7 @@ import QtQuick.Layouts
import QtQuick.Shapes
import qs.widgets.decoration
import qs.widgets.theme
WrapperItem {
RowLayout {
@@ -24,7 +25,7 @@ WrapperItem {
ShapePath {
strokeWidth: 0
fillColor: "#0F1012"
fillColor: Theme.surface
startX: 8
startY: 0
@@ -52,7 +53,7 @@ WrapperItem {
ShapePath {
strokeWidth: 0
fillColor: "#0F1012"
fillColor: Theme.surface
startX: 16
startY: 0
@@ -83,7 +84,7 @@ WrapperItem {
startY: 0
strokeWidth: 0
fillColor: "#0F1012"
fillColor: Theme.surface
PathLine {
x: shape.width
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.widgets.theme
// 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
@@ -99,7 +100,7 @@ Scope {
anchors.right: parent.right
clip: true
color: "#0F1012"
color: Theme.surface
height: root.active ? win.openHeight : 0
@@ -116,7 +117,7 @@ Scope {
// Accent lid — mirrors the top bar strip, reads as its extension.
Rectangle {
color: "#FFD063"
color: Theme.accent
implicitHeight: 4
Layout.fillWidth: true
}
@@ -132,8 +133,8 @@ Scope {
Text {
text: ">_"
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 22
font.bold: true
}
@@ -147,7 +148,7 @@ Scope {
anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE"
color: Theme.text
font.pointSize: 16
clip: true
@@ -182,7 +183,7 @@ Scope {
verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0
text: "launch application…"
color: "#7A7B7D"
color: Theme.muted
font: input.font
}
}
@@ -190,14 +191,14 @@ Scope {
Text {
text: model.apps.length + " apps"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 15
}
}
Rectangle {
color: "#292C30"
color: Theme.raised
implicitHeight: 1
Layout.fillWidth: true
}
@@ -236,9 +237,9 @@ Scope {
Rectangle {
anchors.fill: parent
color: card.selected ? "#292C30" : "transparent"
color: card.selected ? Theme.raised : "transparent"
border.width: 1
border.color: card.selected ? "#FFD063" : "#292C30"
border.color: card.selected ? Theme.accent : Theme.raised
Behavior on border.color {
ColorAnimation {
@@ -261,7 +262,7 @@ Scope {
Text {
Layout.fillWidth: true
text: card.modelData.name
color: card.selected ? "#FFD063" : "#EEEEEE"
color: card.selected ? Theme.accent : Theme.text
font.pointSize: 9
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
@@ -277,8 +278,8 @@ Scope {
anchors.centerIn: parent
visible: model.apps.length === 0
text: "no matches"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 16
}
}
@@ -7,6 +7,7 @@ import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes
import qs.widgets.theme
// Variant 7 — a copy of the "Slant" (V6) launcher, plus a small floating
// power panel docked to its right with Shutdown / Reboot buttons.
@@ -77,7 +78,7 @@ Scope {
// Dim backdrop — click to dismiss.
Rectangle {
anchors.fill: parent
color: "#0A0A0C"
color: Theme.surface
opacity: 0.55
MouseArea {
@@ -107,8 +108,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "#0F1012"
strokeColor: "#FFD063"
fillColor: Theme.surface
strokeColor: Theme.accent
strokeWidth: 2
startX: frame.chamfer
@@ -153,7 +154,7 @@ Scope {
// run out to the top and left edges to meet the straight borders.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: frame.chamfer
@@ -179,7 +180,7 @@ Scope {
// bottom and right edges.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: panelShape.height - frame.chamfer
@@ -205,7 +206,7 @@ Scope {
// detached from the panel by the width of the cut.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: panelShape.height
@@ -228,7 +229,7 @@ Scope {
// slanted end pieces on both arms.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
// inner, right end of the bottom arm
startX: panelShape.width / 3
@@ -277,7 +278,7 @@ Scope {
// slanted end pieces on both arms.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
// inner, bottom of the right arm
startX: panelShape.width
@@ -345,7 +346,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 6
startY: 0
PathLine {
@@ -367,7 +368,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 15
startY: 0
PathLine {
@@ -389,7 +390,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 24
startY: 0
PathLine {
@@ -420,8 +421,8 @@ Scope {
anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE"
font.family: "Digital-7 Mono"
color: Theme.text
font.family: Theme.readoutFont
font.pointSize: 20
font.letterSpacing: 1
clip: true
@@ -457,7 +458,7 @@ Scope {
verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0
text: "run"
color: "#7A7B7D"
color: Theme.muted
font: input.font
}
}
@@ -465,8 +466,8 @@ Scope {
Text {
text: model.apps.length
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 18
}
}
@@ -489,7 +490,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: divider.slant
startY: 0
PathLine {
@@ -512,7 +513,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: divider.height
PathLine {
@@ -535,7 +536,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: divider.width
startY: 0
PathLine {
@@ -597,7 +598,7 @@ Scope {
// Body
ShapePath {
strokeWidth: 0
fillColor: "#22262C"
fillColor: Theme.raised
startX: appRow.shear
startY: 0
PathLine {
@@ -620,7 +621,7 @@ Scope {
// Left accent edge
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: appRow.shear
startY: 0
PathLine {
@@ -655,7 +656,7 @@ Scope {
Text {
text: appRow.modelData.name
color: appRow.selected ? "#FFD063" : "#EEEEEE"
color: appRow.selected ? Theme.accent : Theme.text
font.pointSize: 12
elide: Text.ElideRight
Layout.fillWidth: true
@@ -663,7 +664,7 @@ Scope {
Text {
text: appRow.modelData.genericName || ""
color: "#7A7B7D"
color: Theme.muted
font.pointSize: 10
elide: Text.ElideRight
Layout.maximumWidth: 220
@@ -694,8 +695,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "#FFD063"
strokeColor: "#FFD063"
fillColor: Theme.accent
strokeColor: Theme.accent
strokeWidth: 2
startX: 0
@@ -732,9 +733,9 @@ Scope {
Text {
Layout.alignment: Qt.AlignHCenter
text: "POWER"
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
font.pointSize: 11
color: "#0F1012"
color: Theme.surface
}
Repeater {
@@ -762,8 +763,8 @@ Scope {
ShapePath {
strokeWidth: 1
strokeColor: powerButton.containsMouse ? "#FFD063" : "#7A7B7D"
fillColor: "#292C30"
strokeColor: powerButton.containsMouse ? Theme.accent : Theme.muted
fillColor: Theme.raised
startX: powerButton.chamfer
startY: 0
@@ -785,8 +786,8 @@ Scope {
Text {
anchors.centerIn: parent
text: powerButton.modelData.label
color: powerButton.containsMouse ? "#FFD063" : "#EEEEEE"
font.family: "Digital-7 Mono"
color: powerButton.containsMouse ? Theme.accent : Theme.text
font.family: Theme.readoutFont
font.pointSize: 11
}
}
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.widgets.theme
// 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
@@ -98,7 +99,7 @@ Scope {
anchors.right: parent.right
clip: true
color: "#0F1012"
color: Theme.surface
height: root.active ? win.openHeight : 0
@@ -153,9 +154,9 @@ Scope {
Rectangle {
anchors.fill: parent
color: card.selected ? "#292C30" : "transparent"
color: card.selected ? Theme.raised : "transparent"
border.width: 1
border.color: card.selected ? "#FFD063" : "#292C30"
border.color: card.selected ? Theme.accent : Theme.raised
Behavior on border.color {
ColorAnimation {
@@ -178,7 +179,7 @@ Scope {
Text {
Layout.fillWidth: true
text: card.modelData.name
color: card.selected ? "#FFD063" : "#EEEEEE"
color: card.selected ? Theme.accent : Theme.text
font.pointSize: 9
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
@@ -194,14 +195,14 @@ Scope {
anchors.centerIn: parent
visible: model.apps.length === 0
text: "no matches"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 16
}
}
Rectangle {
color: "#292C30"
color: Theme.raised
implicitHeight: 1
Layout.fillWidth: true
}
@@ -217,8 +218,8 @@ Scope {
Text {
text: ">_"
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 22
font.bold: true
}
@@ -232,7 +233,7 @@ Scope {
anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE"
color: Theme.text
font.pointSize: 16
clip: true
@@ -267,7 +268,7 @@ Scope {
verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0
text: "launch application…"
color: "#7A7B7D"
color: Theme.muted
font: input.font
}
}
@@ -275,15 +276,15 @@ Scope {
Text {
text: model.apps.length + " apps"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 15
}
}
// Accent lid — mirrors the bottom bar strip.
Rectangle {
color: "#FFD063"
color: Theme.accent
implicitHeight: 4
Layout.fillWidth: true
}
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.widgets.theme
// Variant 2 — "Grid": centered app-drawer with a dim backdrop and icon tiles.
Scope {
@@ -78,7 +79,7 @@ Scope {
// Dim backdrop — click anywhere outside to dismiss.
Rectangle {
anchors.fill: parent
color: "#0A0A0C"
color: Theme.surface
opacity: 0.55
MouseArea {
@@ -93,9 +94,9 @@ Scope {
width: 760
height: 560
color: "#0F1012"
color: Theme.surface
border.width: 1
border.color: "#FFD063"
border.color: Theme.accent
opacity: 0.98
// Accent corner brackets for the cyberpunk frame.
@@ -104,14 +105,14 @@ Scope {
anchors.left: parent.left
width: 5
height: 28
color: "#FFD063"
color: Theme.accent
}
Rectangle {
anchors.top: parent.top
anchors.right: parent.right
width: 28
height: 5
color: "#FFD063"
color: Theme.accent
}
ColumnLayout {
@@ -126,8 +127,8 @@ Scope {
Text {
text: "APPS"
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 22
font.letterSpacing: 3
}
@@ -138,9 +139,9 @@ Scope {
Rectangle {
anchors.fill: parent
color: "#292C30"
color: Theme.raised
border.width: 1
border.color: input.activeFocus ? "#FFD063" : "#7A7B7D"
border.color: input.activeFocus ? Theme.accent : Theme.muted
Behavior on border.color {
ColorAnimation {
@@ -155,7 +156,7 @@ Scope {
anchors.rightMargin: 12
verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE"
color: Theme.text
font.pointSize: 13
clip: true
@@ -198,7 +199,7 @@ Scope {
anchors.verticalCenter: parent.verticalCenter
visible: input.text.length === 0
text: "Type to search…"
color: "#7A7B7D"
color: Theme.muted
font: input.font
}
}
@@ -207,7 +208,7 @@ Scope {
}
Rectangle {
color: "#FFD063"
color: Theme.accent
implicitHeight: 3
Layout.fillWidth: true
}
@@ -242,9 +243,9 @@ Scope {
Rectangle {
anchors.fill: parent
anchors.margins: 6
color: tile.selected ? "#292C30" : "transparent"
color: tile.selected ? Theme.raised : "transparent"
border.width: 1
border.color: tile.selected ? "#FFD063" : "transparent"
border.color: tile.selected ? Theme.accent : "transparent"
Behavior on border.color {
ColorAnimation {
@@ -266,7 +267,7 @@ Scope {
Text {
Layout.fillWidth: true
text: tile.modelData.name
color: tile.selected ? "#FFD063" : "#EEEEEE"
color: tile.selected ? Theme.accent : Theme.text
font.pointSize: 10
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
@@ -7,6 +7,7 @@ import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes
import qs.widgets.theme
// Variant 6 — "Slant": breaks up the rectangular layout with angled geometry —
// a chamfered panel, a slanted header divider and sheared row highlights.
@@ -77,7 +78,7 @@ Scope {
// Dim backdrop — click to dismiss.
Rectangle {
anchors.fill: parent
color: "#0A0A0C"
color: Theme.surface
opacity: 0.55
MouseArea {
@@ -107,8 +108,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "#0F1012"
strokeColor: "#FFD063"
fillColor: Theme.surface
strokeColor: Theme.accent
strokeWidth: 2
startX: frame.chamfer
@@ -153,7 +154,7 @@ Scope {
// run out to the top and left edges to meet the straight borders.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: frame.chamfer
@@ -179,7 +180,7 @@ Scope {
// bottom and right edges.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: panelShape.height - frame.chamfer
@@ -205,7 +206,7 @@ Scope {
// detached from the panel by the width of the cut.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: panelShape.height
@@ -228,7 +229,7 @@ Scope {
// slanted end pieces on both arms.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
// inner, right end of the bottom arm
startX: panelShape.width / 3
@@ -277,7 +278,7 @@ Scope {
// slanted end pieces on both arms.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
// inner, bottom of the right arm
startX: panelShape.width
@@ -345,7 +346,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 6
startY: 0
PathLine {
@@ -367,7 +368,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 15
startY: 0
PathLine {
@@ -389,7 +390,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 24
startY: 0
PathLine {
@@ -420,8 +421,8 @@ Scope {
anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE"
font.family: "Digital-7 Mono"
color: Theme.text
font.family: Theme.readoutFont
font.pointSize: 20
font.letterSpacing: 1
clip: true
@@ -457,7 +458,7 @@ Scope {
verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0
text: "run"
color: "#7A7B7D"
color: Theme.muted
font: input.font
}
}
@@ -465,8 +466,8 @@ Scope {
Text {
text: model.apps.length
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 18
}
}
@@ -489,7 +490,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: divider.slant
startY: 0
PathLine {
@@ -512,7 +513,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: divider.height
PathLine {
@@ -535,7 +536,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: divider.width
startY: 0
PathLine {
@@ -597,7 +598,7 @@ Scope {
// Body
ShapePath {
strokeWidth: 0
fillColor: "#22262C"
fillColor: Theme.raised
startX: appRow.shear
startY: 0
PathLine {
@@ -620,7 +621,7 @@ Scope {
// Left accent edge
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: appRow.shear
startY: 0
PathLine {
@@ -655,7 +656,7 @@ Scope {
Text {
text: appRow.modelData.name
color: appRow.selected ? "#FFD063" : "#EEEEEE"
color: appRow.selected ? Theme.accent : Theme.text
font.pointSize: 12
elide: Text.ElideRight
Layout.fillWidth: true
@@ -663,7 +664,7 @@ Scope {
Text {
text: appRow.modelData.genericName || ""
color: "#7A7B7D"
color: Theme.muted
font.pointSize: 10
elide: Text.ElideRight
Layout.maximumWidth: 220
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.widgets.theme
// Variant 3 — "Spotlight": top-center command bar with a compact result list.
Scope {
@@ -91,9 +92,9 @@ Scope {
Rectangle {
Layout.fillWidth: true
implicitHeight: 60
color: "#0F1012"
color: Theme.surface
border.width: 1
border.color: "#FFD063"
border.color: Theme.accent
RowLayout {
anchors.fill: parent
@@ -103,8 +104,8 @@ Scope {
Text {
text: ">"
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 26
font.bold: true
}
@@ -118,7 +119,7 @@ Scope {
anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE"
color: Theme.text
font.pointSize: 17
clip: true
@@ -153,7 +154,7 @@ Scope {
verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0
text: "run application"
color: "#7A7B7D"
color: Theme.muted
font: input.font
}
}
@@ -161,8 +162,8 @@ Scope {
Text {
text: model.apps.length + " ▸"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 16
}
}
@@ -172,7 +173,7 @@ Scope {
Rectangle {
Layout.fillWidth: true
implicitHeight: 3
color: "#FFD063"
color: Theme.accent
visible: model.apps.length > 0
}
@@ -181,11 +182,11 @@ Scope {
Layout.fillWidth: true
// Cap the visible height to maxRows; scroll beyond that.
implicitHeight: Math.min(model.apps.length, win.maxRows) * 44 + 2
color: "#0F1012"
color: Theme.surface
opacity: 0.97
visible: model.apps.length > 0
border.width: 1
border.color: "#292C30"
border.color: Theme.raised
ListView {
id: list
@@ -215,14 +216,14 @@ Scope {
Rectangle {
anchors.fill: parent
color: entry.selected ? "#1A1C1F" : "transparent"
color: entry.selected ? Theme.selection : "transparent"
Rectangle {
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 3
color: "#FFD063"
color: Theme.accent
visible: entry.selected
}
@@ -239,7 +240,7 @@ Scope {
Text {
text: entry.modelData.name
color: entry.selected ? "#FFD063" : "#EEEEEE"
color: entry.selected ? Theme.accent : Theme.text
font.pointSize: 12
elide: Text.ElideRight
Layout.fillWidth: true
@@ -247,7 +248,7 @@ Scope {
Text {
text: entry.modelData.genericName || ""
color: "#7A7B7D"
color: Theme.muted
font.pointSize: 10
elide: Text.ElideRight
Layout.maximumWidth: 200
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.widgets.theme
// Variant 1 — "Stack": left-anchored vertical list launcher.
// Framed with the top/bottom accent strips used by the main Bar.
@@ -82,7 +83,7 @@ Scope {
spacing: 0
Rectangle {
color: "#FFD063"
color: Theme.accent
implicitHeight: 5
Layout.fillWidth: true
}
@@ -93,8 +94,8 @@ Scope {
margin: 12
border.width: 1
border.color: "#FFD063"
color: "#0F1012"
border.color: Theme.accent
color: Theme.surface
opacity: 0.95
ColumnLayout {
@@ -107,7 +108,7 @@ Scope {
Text {
text: "▚"
color: "#FFD063"
color: Theme.accent
font.pointSize: 14
font.bold: true
}
@@ -121,8 +122,8 @@ Scope {
anchors.fill: parent
verticalAlignment: TextInput.AlignVCenter
color: "#EEEEEE"
font.family: "Digital-7 Mono"
color: Theme.text
font.family: Theme.readoutFont
font.pointSize: 16
clip: true
@@ -158,7 +159,7 @@ Scope {
verticalAlignment: Text.AlignVCenter
visible: input.text.length === 0
text: "search"
color: "#7A7B7D"
color: Theme.muted
font: input.font
}
}
@@ -166,14 +167,14 @@ Scope {
Text {
text: model.apps.length
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 14
}
}
Rectangle {
color: "#FFD063"
color: Theme.accent
implicitHeight: 2
Layout.fillWidth: true
}
@@ -207,7 +208,7 @@ Scope {
Rectangle {
anchors.fill: parent
color: appRow.selected ? "#292C30" : "transparent"
color: appRow.selected ? Theme.raised : "transparent"
// Accent bar on the selected row.
Rectangle {
@@ -215,7 +216,7 @@ Scope {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 3
color: "#FFD063"
color: Theme.accent
visible: appRow.selected
}
@@ -236,7 +237,7 @@ Scope {
Text {
text: appRow.modelData.name
color: appRow.selected ? "#FFD063" : "#EEEEEE"
color: appRow.selected ? Theme.accent : Theme.text
font.pointSize: 12
elide: Text.ElideRight
Layout.fillWidth: true
@@ -245,7 +246,7 @@ Scope {
Text {
visible: text.length > 0
text: appRow.modelData.genericName || appRow.modelData.comment || ""
color: "#7A7B7D"
color: Theme.muted
font.pointSize: 9
elide: Text.ElideRight
Layout.fillWidth: true
@@ -259,7 +260,7 @@ Scope {
}
Rectangle {
color: "#FFD063"
color: Theme.accent
implicitHeight: 5
Layout.fillWidth: true
}
@@ -2,6 +2,7 @@ import Quickshell.Services.Notifications
import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import qs.widgets.theme
ColumnLayout {
id: root
@@ -12,7 +13,7 @@ ColumnLayout {
Layout.fillWidth: true
Rectangle {
color: "#FFD063"
color: Theme.accent
implicitHeight: 5
Layout.fillWidth: true
@@ -23,8 +24,8 @@ ColumnLayout {
margin: 12
border.width: 1
border.color: "#FFD063"
color: "#0F1012"
border.color: Theme.accent
color: Theme.surface
opacity: .9
ColumnLayout {
@@ -45,7 +46,7 @@ ColumnLayout {
Text {
text: root.modelData.summary
color: "#EEEEEE"
color: Theme.text
font.pointSize: 14
font.bold: true
elide: Text.ElideRight
@@ -57,7 +58,7 @@ ColumnLayout {
id: dismissButton
text: "×"
color: "#FFD063"
color: Theme.accent
font.pointSize: 18
MouseArea {
@@ -71,7 +72,7 @@ ColumnLayout {
Text {
visible: root.modelData.body !== ""
text: root.modelData.body
color: "#EEEEEE"
color: Theme.text
font.pointSize: 12
wrapMode: Text.Wrap
@@ -92,9 +93,9 @@ ColumnLayout {
required property NotificationAction modelData
color: "#292C30"
color: Theme.raised
border.width: 1
border.color: "#FFD063"
border.color: Theme.accent
implicitHeight: 28
implicitWidth: actionText.implicitWidth + 16
@@ -102,7 +103,7 @@ ColumnLayout {
id: actionText
anchors.centerIn: parent
text: actionButton.modelData.text
color: "#EEEEEE"
color: Theme.text
font.pointSize: 12
}
@@ -2,6 +2,7 @@ import Quickshell
import Quickshell.Services.Pipewire
import Quickshell.Wayland
import QtQuick
import qs.widgets.theme
Scope {
id: root
@@ -68,7 +69,7 @@ Scope {
anchors.bottomMargin: 4
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.bold: true
}
@@ -84,7 +85,7 @@ Scope {
anchors.centerIn: parent
implicitHeight: 6
width: parent.width * Math.min(root.volume, root.maxVolume) / root.maxVolume
color: "#FF6B4A"
color: Theme.hot
visible: !root.muted && root.volume > 1
Behavior on width {
@@ -98,7 +99,7 @@ Scope {
anchors.centerIn: parent
implicitHeight: 6
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 {
NumberAnimation {
+23 -22
View File
@@ -8,6 +8,7 @@ import Quickshell.Widgets
import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes
import qs.widgets.theme
// A vertical sidebar carrying the "Slant" (launcher V6) visual language —
// 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
// on top-left & bottom-right (mirror of the left-anchored panel).
ShapePath {
fillColor: "#0F1012"
strokeColor: "#FFD063"
fillColor: Theme.surface
strokeColor: Theme.accent
strokeWidth: 2
startX: panelShape.width - frame.chamfer
@@ -124,7 +125,7 @@ Scope {
// Thick top-right bevel accent (trapezoid to the edges).
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: frame.chamfer
@@ -149,7 +150,7 @@ Scope {
// Thick bottom-left bevel accent.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: panelShape.height - frame.chamfer
@@ -174,7 +175,7 @@ Scope {
// Floating triangle cap in the bottom-left notch.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: panelShape.height
@@ -197,7 +198,7 @@ Scope {
// corner following the small chamfer.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: frame.armSide
@@ -245,15 +246,15 @@ Scope {
anchors.rightMargin: 8
spacing: 10
// Clock — Digital-7, hh over mm
// Clock — readout font, hh over mm
Text {
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
text: Qt.formatDateTime(clock.date, "hh\nmm")
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
font.pointSize: 22
font.letterSpacing: 1
color: "#EEEEEE"
color: Theme.text
SystemClock {
id: clock
@@ -266,9 +267,9 @@ Scope {
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
text: Qt.formatDateTime(clock.date, "dd\nMMM").toUpperCase()
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
font.pointSize: 13
color: "#FFD063"
color: Theme.accent
}
// Slanted divider
@@ -282,7 +283,7 @@ Scope {
preferredRendererType: Shape.CurveRenderer
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 8
startY: 0
PathLine { x: divider.width; y: 0 }
@@ -301,9 +302,9 @@ Scope {
Text {
Layout.alignment: Qt.AlignHCenter
text: "VOL"
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
font.pointSize: 10
color: "#7A7B7D"
color: Theme.muted
}
ColumnLayout {
@@ -336,8 +337,8 @@ Scope {
ShapePath {
strokeWidth: 1
strokeColor: "#7A7B7D"
fillColor: "#292C30"
strokeColor: Theme.muted
fillColor: Theme.raised
startX: seg.chamfer
startY: 0
@@ -375,7 +376,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FF6B4A"
fillColor: Theme.hot
startX: segFill.chamfer
startY: 0
PathLine { x: segFill.width; y: 0 }
@@ -407,8 +408,8 @@ Scope {
ShapePath {
strokeWidth: 1
strokeColor: "#7A7B7D"
fillColor: "#292C30"
strokeColor: Theme.muted
fillColor: Theme.raised
startX: volMeter.chamfer
startY: 0
@@ -448,7 +449,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: root.muted ? "#7A7B7D" : "#FFD063"
fillColor: root.muted ? Theme.muted : Theme.accent
startX: vol.chamfer
startY: 0
PathLine { x: vol.width; y: 0 }
@@ -466,9 +467,9 @@ Scope {
Text {
Layout.alignment: Qt.AlignHCenter
text: root.muted ? "--" : Math.round(root.volume * 100)
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
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.Layouts
import QtQuick.Shapes
import qs.widgets.theme
// The right bar: a compact utility strip for the SystemTray icons, styled
// 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
// bracket-and-cap silhouette, since this is a secondary/utility bar rather
// than a hero surface.
@@ -54,8 +55,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "#0F1012"
strokeColor: "#FFD063"
fillColor: Theme.surface
strokeColor: Theme.accent
strokeWidth: 2
startX: frame.chamfer
@@ -114,7 +115,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 6
startY: 0
PathLine { x: 10; y: 0 }
@@ -124,7 +125,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 15
startY: 0
PathLine { x: 19; y: 0 }
@@ -134,7 +135,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 24
startY: 0
PathLine { x: 28; y: 0 }
@@ -155,7 +156,7 @@ Scope {
preferredRendererType: Shape.CurveRenderer
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 8
startY: 0
PathLine { x: divider.width; y: 0 }
@@ -169,9 +170,9 @@ Scope {
Text {
Layout.alignment: Qt.AlignHCenter
text: "TRAY"
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
font.pointSize: 12
color: "#7A7B7D"
color: Theme.muted
}
ListView {
@@ -201,17 +202,17 @@ Scope {
Layout.alignment: Qt.AlignHCenter
visible: SystemTray.items.values.length === 0
text: "--"
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
font.pointSize: 14
color: "#7A7B7D"
color: Theme.muted
}
Text {
Layout.alignment: Qt.AlignHCenter
text: SystemTray.items.values.length
font.family: "Digital-7 Mono"
font.family: Theme.readoutFont
font.pointSize: 16
color: "#EEEEEE"
color: Theme.text
}
}
}
@@ -2,6 +2,7 @@ import Quickshell
import Quickshell.Services.SystemTray
import QtQuick
import QtQuick.Shapes
import qs.widgets.theme
// A single tray icon, chamfered to match the Slant (launcher V6 / SideBar)
// visual language instead of a plain rectangular hit target.
@@ -35,8 +36,8 @@ MouseArea {
ShapePath {
strokeWidth: 1
strokeColor: root.containsMouse ? "#FFD063" : "#7A7B7D"
fillColor: "#292C30"
strokeColor: root.containsMouse ? Theme.accent : Theme.muted
fillColor: Theme.raised
startX: root.chamfer
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.Shapes
import qs.widgets.theme
// 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
@@ -26,8 +27,8 @@ Item {
ShapePath {
strokeWidth: 1
strokeColor: bar.unknown ? "#3A3D42" : "#7A7B7D"
fillColor: "#292C30"
strokeColor: bar.unknown ? Theme.disabled : Theme.muted
fillColor: Theme.raised
startX: bar.chamfer
startY: 0
@@ -72,7 +73,7 @@ Item {
ShapePath {
strokeWidth: 0
fillColor: bar.hot ? "#FF6B4A" : "#FFD063"
fillColor: bar.hot ? Theme.hot : Theme.accent
Behavior on fillColor {
ColorAnimation {
+43 -42
View File
@@ -6,6 +6,7 @@ import Quickshell.Wayland
import QtQuick
import QtQuick.Layouts
import QtQuick.Shapes
import qs.widgets.theme
// Host vitals HUD — the "Slant" language (chamfered panel, trapezoid bevels,
// outward corner chunks, floating cap, slanted dividers) carried over from the
@@ -59,7 +60,7 @@ Scope {
// Dim backdrop — click anywhere to dismiss.
Rectangle {
anchors.fill: parent
color: "#0A0A0C"
color: Theme.surface
opacity: 0.5
MouseArea {
@@ -102,8 +103,8 @@ Scope {
preferredRendererType: Shape.CurveRenderer
ShapePath {
fillColor: "#0F1012"
strokeColor: "#FFD063"
fillColor: Theme.surface
strokeColor: Theme.accent
strokeWidth: 2
startX: frame.chamfer
@@ -121,7 +122,7 @@ Scope {
// Thick top-left bevel accent.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 0
startY: frame.chamfer
@@ -134,7 +135,7 @@ Scope {
// Thick bottom-right bevel accent.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: panelShape.height - frame.chamfer
@@ -147,7 +148,7 @@ Scope {
// Floating triangle cap in the bottom-right notch.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: panelShape.height
@@ -159,7 +160,7 @@ Scope {
// Heavy outward chunk wrapping the bottom-left corner.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width / 3
startY: panelShape.height
@@ -176,7 +177,7 @@ Scope {
// Heavy outward chunk wrapping the top-right corner.
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: panelShape.width
startY: panelShape.height / 3
@@ -217,7 +218,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 6
startY: 0
PathLine { x: 10; y: 0 }
@@ -227,7 +228,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 15
startY: 0
PathLine { x: 19; y: 0 }
@@ -237,7 +238,7 @@ Scope {
}
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 24
startY: 0
PathLine { x: 28; y: 0 }
@@ -249,8 +250,8 @@ Scope {
Text {
text: (vitals.host || "vitals").toUpperCase()
color: "#EEEEEE"
font.family: "Digital-7 Mono"
color: Theme.text
font.family: Theme.readoutFont
font.pointSize: 20
font.letterSpacing: 2
}
@@ -261,15 +262,15 @@ Scope {
Text {
text: "UP"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 11
}
Text {
text: vitals.fmtUptime(vitals.uptime)
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 16
}
}
@@ -281,8 +282,8 @@ Scope {
Layout.fillWidth: true
visible: vitals.failed
text: "NODE_EXPORTER UNREACHABLE ON :" + vitals.port
color: "#FF6B4A"
font.family: "Digital-7 Mono"
color: Theme.hot
font.family: Theme.readoutFont
font.pointSize: 13
}
@@ -353,7 +354,7 @@ Scope {
Text {
Layout.preferredWidth: 96
text: diskRow.modelData.mount
color: "#7A7B7D"
color: Theme.muted
font.pointSize: 9
elide: Text.ElideMiddle
}
@@ -369,8 +370,8 @@ Scope {
Layout.preferredWidth: 48
horizontalAlignment: Text.AlignRight
text: Math.round(diskRow.frac * 100) + "%"
color: diskRow.frac >= 0.9 ? "#FF6B4A" : "#EEEEEE"
font.family: "Digital-7 Mono"
color: diskRow.frac >= 0.9 ? Theme.hot : Theme.text
font.family: Theme.readoutFont
font.pointSize: 13
}
@@ -378,8 +379,8 @@ Scope {
Layout.preferredWidth: 104
horizontalAlignment: Text.AlignRight
text: vitals.fmtBytes(diskRow.modelData.size - diskRow.modelData.used) + " FREE"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 11
}
}
@@ -399,21 +400,21 @@ Scope {
Text {
Layout.preferredWidth: 96
text: vitals.netIface || "NET"
color: "#7A7B7D"
color: Theme.muted
font.pointSize: 9
}
Text {
text: "RX"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 11
}
Text {
text: vitals.fmtRate(vitals.netRx)
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 14
}
@@ -423,15 +424,15 @@ Scope {
Text {
text: "TX"
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 11
}
Text {
text: vitals.fmtRate(vitals.netTx)
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 14
// Right-align the TX readout against the panel edge the
@@ -469,8 +470,8 @@ Scope {
Text {
Layout.preferredWidth: 46
text: metric.label
color: "#FFD063"
font.family: "Digital-7 Mono"
color: Theme.accent
font.family: Theme.readoutFont
font.pointSize: 15
font.letterSpacing: 1
}
@@ -486,8 +487,8 @@ Scope {
Layout.preferredWidth: 54
horizontalAlignment: Text.AlignRight
text: metric.readout
color: "#EEEEEE"
font.family: "Digital-7 Mono"
color: Theme.text
font.family: Theme.readoutFont
font.pointSize: 16
}
}
@@ -499,8 +500,8 @@ Scope {
Text {
text: metric.detail
color: "#7A7B7D"
font.family: "Digital-7 Mono"
color: Theme.muted
font.family: Theme.readoutFont
font.pointSize: 11
}
@@ -511,8 +512,8 @@ Scope {
Text {
visible: metric.aside.length > 0
text: metric.aside
color: metric.asideHot ? "#FF6B4A" : "#7A7B7D"
font.family: "Digital-7 Mono"
color: metric.asideHot ? Theme.hot : Theme.muted
font.family: Theme.readoutFont
font.pointSize: 11
}
}
@@ -530,7 +531,7 @@ Scope {
ShapePath {
strokeWidth: 0
fillColor: "#FFD063"
fillColor: Theme.accent
startX: 6
startY: 0
PathLine { x: divider.width; y: 0 }
+108
View File
@@ -552,5 +552,113 @@
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"
'';
};
};
}