From 01bc16918084a0cb5cd0ac8f0456f92b4b042dff Mon Sep 17 00:00:00 2001 From: Erik Simon Date: Fri, 28 Aug 2026 07:55:59 +0200 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_01SgcWkm3t6BDQktYHQvb8Hx --- .../widgets/bar/DenseBarContent.qml | 115 +------------- .../quickshell/widgets/bar/StatusBarPanel.qml | 141 ++++++++++++++++++ 2 files changed, 147 insertions(+), 109 deletions(-) create mode 100644 dotfiles/quickshell/widgets/bar/StatusBarPanel.qml diff --git a/dotfiles/quickshell/widgets/bar/DenseBarContent.qml b/dotfiles/quickshell/widgets/bar/DenseBarContent.qml index dd8d28c..38e598d 100644 --- a/dotfiles/quickshell/widgets/bar/DenseBarContent.qml +++ b/dotfiles/quickshell/widgets/bar/DenseBarContent.qml @@ -69,11 +69,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) @@ -115,7 +110,7 @@ Item { anchors.fill: parent spacing: 8 - TelemetryPanel { + StatusBarPanel { width: array.identityWidth height: array.height panelId: "001" @@ -198,7 +193,7 @@ Item { } } - TelemetryPanel { + StatusBarPanel { width: array.flexWidth height: array.height panelId: "02" @@ -245,7 +240,7 @@ Item { } } - TelemetryPanel { + StatusBarPanel { width: array.radarWidth height: array.height panelId: "03" @@ -259,7 +254,7 @@ Item { } } - TelemetryPanel { + StatusBarPanel { width: array.flexWidth height: array.height panelId: "04" @@ -306,7 +301,7 @@ Item { } } - TelemetryPanel { + StatusBarPanel { width: array.stateWidth height: array.height panelId: "05" @@ -362,7 +357,7 @@ Item { } } - TelemetryPanel { + StatusBarPanel { id: rail x: 12 y: 108 @@ -555,104 +550,6 @@ Item { } } - 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: "" diff --git a/dotfiles/quickshell/widgets/bar/StatusBarPanel.qml b/dotfiles/quickshell/widgets/bar/StatusBarPanel.qml new file mode 100644 index 0000000..2da2200 --- /dev/null +++ b/dotfiles/quickshell/widgets/bar/StatusBarPanel.qml @@ -0,0 +1,141 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Shapes + +// 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. +// +// Palette and fonts are properties with defaults rather than references to the +// parent, because a component in its own file has no access to the enclosing +// scope. The defaults match DenseBarContent's, which is the repo's existing +// per-component convention (see quickshell/CLAUDE.md) — a shared theme +// singleton would be the place to collapse the duplication. +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 + + property color voidColor: "#0a0a0a" + property color inkColor: "#dedede" + property color mutedColor: "#858585" + property color accentColor: "#e8722a" + property color hairColor: Qt.rgba(0.87, 0.87, 0.87, 0.28) + property string displayFont: "DepartureMono Nerd Font" + property string microFont: "DejaVu Sans Mono" + + Shape { + id: panelShape + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + + ShapePath { + fillColor: panel.voidColor + strokeColor: panel.hairColor + 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: panel.accentColor + 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: panel.accentColor + 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: panel.inkColor + opacity: 0.12 + } + + Rectangle { + visible: panel.showHeader + x: 5; y: 7 + width: panel.panelId.length > 2 ? 29 : 24 + height: 11 + color: panel.accentColor + Text { + anchors.centerIn: parent + text: panel.panelId + color: panel.voidColor + font.family: panel.microFont + font.pixelSize: 8 + font.bold: true + } + } + + Text { + visible: panel.showHeader + x: 40; y: 7 + width: parent.width - 105 + text: panel.title + color: panel.inkColor + font.family: panel.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: panel.mutedColor + font.family: panel.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: panel.accentColor } + } + } +}