move Theme, SystemStats, Modules to shell/services/

This commit is contained in:
Damocles 2026-04-17 22:07:00 +02:00
parent 197f6976e0
commit 989182d603
59 changed files with 432 additions and 388 deletions

View file

@ -25,7 +25,7 @@ stdenvNoCC.mkDerivation {
runHook preInstall runHook preInstall
mkdir -p $out/share/nova-shell mkdir -p $out/share/nova-shell
cp -r shell/shell.qml shell/modules shell/applets shell/lock shell/assets $out/share/nova-shell/ cp -r shell/shell.qml shell/modules shell/services shell/applets shell/lock shell/assets $out/share/nova-shell/
# Compile fragment shader to Qt RHI format # Compile fragment shader to Qt RHI format
qsb --qt6 \ qsb --qt6 \

View file

@ -1,5 +1,5 @@
import QtQuick import QtQuick
import "../modules" as M import "../services" as M
Column { Column {
id: root id: root

View file

@ -1,5 +1,5 @@
import QtQuick import QtQuick
import "../modules" as M import "../services" as M
Column { Column {
id: root id: root

View file

@ -1,6 +1,6 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "../modules" as M import "../services" as M
Item { Item {
id: root id: root

View file

@ -1,5 +1,5 @@
import QtQuick import QtQuick
import "../modules" as M import "../services" as M
Column { Column {
id: root id: root

View file

@ -1,6 +1,6 @@
import QtQuick import QtQuick
import Quickshell.Services.Mpris import Quickshell.Services.Mpris
import "../modules" as M import "../services" as M
Column { Column {
id: root id: root

View file

@ -1,5 +1,5 @@
import QtQuick import QtQuick
import "../modules" as M import "../services" as M
Column { Column {
id: root id: root

View file

@ -1,6 +1,6 @@
import QtQuick import QtQuick
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import "../modules" as M import "../services" as M
Column { Column {
id: root id: root

View file

@ -2,7 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Wayland import Quickshell.Wayland
import "../modules" as M import "../services" as M
Scope { Scope {
id: root id: root

View file

@ -1,5 +1,5 @@
import QtQuick import QtQuick
import "../modules" as M import "../services" as M
Item { Item {
id: root id: root

View file

@ -4,7 +4,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Services.Mpris import Quickshell.Services.Mpris
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import "../modules" as M import "../services" as M
import "../applets" as C import "../applets" as C
WlSessionLockSurface { WlSessionLockSurface {

View file

@ -3,6 +3,7 @@ import QtQuick.Effects
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S
PanelWindow { PanelWindow {
id: root id: root
@ -44,9 +45,9 @@ PanelWindow {
Text { Text {
text: Qt.formatDateTime(clock.date, "HH") text: Qt.formatDateTime(clock.date, "HH")
color: M.Theme.base0D color: S.Theme.base0D
font.pixelSize: 72 font.pixelSize: 72
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -54,22 +55,22 @@ PanelWindow {
text: ":" text: ":"
color: colon._colors[colon._colorIdx % colon._colors.length] color: colon._colors[colon._colorIdx % colon._colors.length]
Behavior on color { Behavior on color {
enabled: !M.Theme.reducedMotion enabled: !S.Theme.reducedMotion
ColorAnimation { ColorAnimation {
duration: 500 duration: 500
} }
} }
font.pixelSize: 72 font.pixelSize: 72
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
opacity: colon.opacity opacity: colon.opacity
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
Text { Text {
text: Qt.formatDateTime(clock.date, "mm") text: Qt.formatDateTime(clock.date, "mm")
color: M.Theme.base0E color: S.Theme.base0E
font.pixelSize: 72 font.pixelSize: 72
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -79,7 +80,7 @@ PanelWindow {
source: glowSource source: glowSource
anchors.fill: glowSource anchors.fill: glowSource
shadowEnabled: true shadowEnabled: true
shadowColor: M.Theme.base0D shadowColor: S.Theme.base0D
shadowBlur: 1.0 shadowBlur: 1.0
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@ -92,10 +93,10 @@ PanelWindow {
Text { Text {
text: Qt.formatDateTime(clock.date, "HH") text: Qt.formatDateTime(clock.date, "HH")
color: M.Theme.base0D color: S.Theme.base0D
opacity: 0.85 opacity: 0.85
font.pixelSize: 72 font.pixelSize: 72
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -103,16 +104,16 @@ PanelWindow {
id: colon id: colon
text: ":" text: ":"
font.pixelSize: 72 font.pixelSize: 72
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
opacity: 0.85 opacity: 0.85
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
property int _colorIdx: 0 property int _colorIdx: 0
readonly property var _colors: [M.Theme.base08, M.Theme.base09, M.Theme.base0A, M.Theme.base0B, M.Theme.base0C, M.Theme.base0D, M.Theme.base0E, M.Theme.base05] readonly property var _colors: [S.Theme.base08, S.Theme.base09, S.Theme.base0A, S.Theme.base0B, S.Theme.base0C, S.Theme.base0D, S.Theme.base0E, S.Theme.base05]
color: _colors[_colorIdx % _colors.length] color: _colors[_colorIdx % _colors.length]
Behavior on color { Behavior on color {
enabled: !M.Theme.reducedMotion enabled: !S.Theme.reducedMotion
ColorAnimation { ColorAnimation {
duration: 500 duration: 500
} }
@ -140,7 +141,7 @@ PanelWindow {
Connections { Connections {
target: clock target: clock
function onDateChanged() { function onDateChanged() {
if (M.Theme.reducedMotion) if (S.Theme.reducedMotion)
return; return;
colon._colorIdx++; colon._colorIdx++;
colonAnim.restart(); colonAnim.restart();
@ -149,10 +150,10 @@ PanelWindow {
} }
Text { Text {
text: Qt.formatDateTime(clock.date, "mm") text: Qt.formatDateTime(clock.date, "mm")
color: M.Theme.base0E color: S.Theme.base0E
opacity: 0.85 opacity: 0.85
font.pixelSize: 72 font.pixelSize: 72
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@ -164,16 +165,16 @@ PanelWindow {
id: dateText id: dateText
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
text: Qt.formatDateTime(clock.date, "dddd, dd MMMM yyyy") text: Qt.formatDateTime(clock.date, "dddd, dd MMMM yyyy")
color: M.Theme.base05 color: S.Theme.base05
opacity: 0.5 opacity: 0.5
font.pixelSize: 18 font.pixelSize: 18
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.letterSpacing: 4 font.letterSpacing: 4
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: M.Theme.base0D shadowColor: S.Theme.base0D
shadowBlur: 0.4 shadowBlur: 0.4
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@ -188,7 +189,7 @@ PanelWindow {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: M.Theme.base02 color: S.Theme.base02
radius: 1 radius: 1
opacity: 0.3 opacity: 0.3
} }
@ -197,7 +198,7 @@ PanelWindow {
height: parent.height height: parent.height
color: colon._colors[colon._colorIdx % colon._colors.length] color: colon._colors[colon._colorIdx % colon._colors.length]
Behavior on color { Behavior on color {
enabled: !M.Theme.reducedMotion enabled: !S.Theme.reducedMotion
ColorAnimation { ColorAnimation {
duration: 500 duration: 500
} }
@ -206,7 +207,7 @@ PanelWindow {
opacity: 0.6 opacity: 0.6
Behavior on width { Behavior on width {
enabled: !M.Theme.reducedMotion enabled: !S.Theme.reducedMotion
NumberAnimation { NumberAnimation {
duration: 50 duration: 50
} }

View file

@ -2,11 +2,12 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
opacity: M.Modules.backlight.enable && percent > 0 ? 1 : 0 opacity: S.Modules.backlight.enable && percent > 0 ? 1 : 0
visible: opacity > 0 visible: opacity > 0
tooltip: "" tooltip: ""
@ -44,7 +45,7 @@ M.BarSection {
} }
function adjust(delta) { function adjust(delta) {
const step = M.Modules.backlight.step || 5; const step = S.Modules.backlight.step || 5;
adjProc.cmd = delta > 0 ? "light -A " + step : "light -U " + step; adjProc.cmd = delta > 0 ? "light -A " + step : "light -U " + step;
adjProc.running = true; adjProc.running = true;
} }
@ -123,8 +124,8 @@ M.BarSection {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "\uF185" text: "\uF185"
color: root.accentColor color: root.accentColor
font.pixelSize: M.Theme.fontSize + 2 font.pixelSize: S.Theme.fontSize + 2
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
} }
Item { Item {
@ -138,7 +139,7 @@ M.BarSection {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: M.Theme.base02 color: S.Theme.base02
radius: 3 radius: 3
} }
@ -176,9 +177,9 @@ M.BarSection {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.percent + "%" text: root.percent + "%"
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
width: 30 width: 30
} }
} }

View file

@ -3,6 +3,7 @@ import QtQuick.Layouts
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S
PanelWindow { PanelWindow {
id: bar id: bar
@ -18,13 +19,13 @@ PanelWindow {
right: true right: true
} }
implicitHeight: M.Theme.barHeight implicitHeight: S.Theme.barHeight
exclusiveZone: implicitHeight exclusiveZone: implicitHeight
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: M.Theme.base00 color: S.Theme.base00
opacity: M.Theme.barOpacity opacity: S.Theme.barOpacity
} }
Canvas { Canvas {
@ -34,7 +35,7 @@ PanelWindow {
const ctx = getContext("2d"); const ctx = getContext("2d");
const w = width; const w = width;
const h = height; const h = height;
const r = M.Theme.screenRadius; const r = S.Theme.screenRadius;
const lw = 3; const lw = 3;
const hw = lw / 2; const hw = lw / 2;
@ -42,8 +43,8 @@ PanelWindow {
// Glow wash behind the border // Glow wash behind the border
const glowGrad = ctx.createLinearGradient(0, 0, w, 0); const glowGrad = ctx.createLinearGradient(0, 0, w, 0);
glowGrad.addColorStop(0, M.Theme.base0C.toString()); glowGrad.addColorStop(0, S.Theme.base0C.toString());
glowGrad.addColorStop(1, M.Theme.base09.toString()); glowGrad.addColorStop(1, S.Theme.base09.toString());
ctx.globalAlpha = 0.25; ctx.globalAlpha = 0.25;
ctx.fillStyle = glowGrad; ctx.fillStyle = glowGrad;
ctx.fillRect(0, 0, w, h); ctx.fillRect(0, 0, w, h);
@ -60,8 +61,8 @@ PanelWindow {
// Horizontal gradient for the border // Horizontal gradient for the border
const grad = ctx.createLinearGradient(0, 0, w, 0); const grad = ctx.createLinearGradient(0, 0, w, 0);
grad.addColorStop(0, M.Theme.base0C.toString()); grad.addColorStop(0, S.Theme.base0C.toString());
grad.addColorStop(1, M.Theme.base09.toString()); grad.addColorStop(1, S.Theme.base09.toString());
ctx.strokeStyle = grad; ctx.strokeStyle = grad;
ctx.lineWidth = lw; ctx.lineWidth = lw;
@ -96,25 +97,25 @@ PanelWindow {
Item { Item {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: M.Theme.groupSpacing anchors.topMargin: S.Theme.groupSpacing
anchors.leftMargin: M.Theme.groupSpacing anchors.leftMargin: S.Theme.groupSpacing
anchors.rightMargin: M.Theme.groupSpacing anchors.rightMargin: S.Theme.groupSpacing
// ---- center (declared first so left/right can anchor to it) ---- // ---- center (declared first so left/right can anchor to it) ----
RowLayout { RowLayout {
id: centerSection id: centerSection
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.groupSpacing spacing: S.Theme.groupSpacing
M.BarGroup { M.BarGroup {
M.Privacy {} M.Privacy {}
M.Clock { M.Clock {
visible: M.Modules.clock.enable visible: S.Modules.clock.enable
} }
M.Notifications { M.Notifications {
bar: bar bar: bar
visible: M.Modules.notifications.enable visible: S.Modules.notifications.enable
} }
} }
} }
@ -124,14 +125,14 @@ PanelWindow {
anchors.left: parent.left anchors.left: parent.left
anchors.right: centerSection.left anchors.right: centerSection.left
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.groupSpacing spacing: S.Theme.groupSpacing
M.BarGroup { M.BarGroup {
id: workspacesGroup id: workspacesGroup
leftEdge: true leftEdge: true
M.Workspaces { M.Workspaces {
bar: bar bar: bar
visible: M.Modules.workspaces.enable visible: S.Modules.workspaces.enable
} }
} }
M.BarGroup { M.BarGroup {
@ -144,10 +145,10 @@ PanelWindow {
id: _windowTitleGroup id: _windowTitleGroup
Layout.minimumWidth: 0 Layout.minimumWidth: 0
clip: true clip: true
visible: M.Modules.windowTitle.enable && M.NiriIpc.focusedTitle !== "" visible: S.Modules.windowTitle.enable && M.NiriIpc.focusedTitle !== ""
M.WindowTitle { M.WindowTitle {
id: _windowTitle id: _windowTitle
readonly property real _maxWidth: Math.max(0, centerSection.x - _windowTitleGroup.x - 2 * M.Theme.groupPadding - M.Theme.groupSpacing) readonly property real _maxWidth: Math.max(0, centerSection.x - _windowTitleGroup.x - 2 * S.Theme.groupPadding - S.Theme.groupSpacing)
width: Math.min(naturalWidth, _maxWidth) width: Math.min(naturalWidth, _maxWidth)
} }
} }
@ -161,7 +162,7 @@ PanelWindow {
anchors.left: centerSection.right anchors.left: centerSection.right
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.groupSpacing spacing: S.Theme.groupSpacing
Item { Item {
Layout.fillWidth: true Layout.fillWidth: true
@ -173,7 +174,7 @@ PanelWindow {
bar: bar bar: bar
} }
M.Volume { M.Volume {
visible: M.Modules.volume.enable visible: S.Modules.volume.enable
} }
} }
@ -181,7 +182,7 @@ PanelWindow {
M.BarGroup { M.BarGroup {
M.Network { M.Network {
bar: bar bar: bar
visible: M.Modules.network.enable visible: S.Modules.network.enable
} }
M.Bluetooth { M.Bluetooth {
bar: bar bar: bar
@ -192,30 +193,30 @@ PanelWindow {
M.BarGroup { M.BarGroup {
M.Backlight {} M.Backlight {}
M.PowerProfile { M.PowerProfile {
visible: M.Modules.powerProfile.enable visible: S.Modules.powerProfile.enable
} }
M.IdleInhibitor { M.IdleInhibitor {
visible: M.Modules.idleInhibitor.enable visible: S.Modules.idleInhibitor.enable
} }
} }
// Stats // Stats
M.BarGroup { M.BarGroup {
M.Cpu { M.Cpu {
visible: M.Modules.cpu.enable visible: S.Modules.cpu.enable
} }
M.Memory { M.Memory {
visible: M.Modules.memory.enable visible: S.Modules.memory.enable
} }
M.Gpu {} M.Gpu {}
M.Temperature { M.Temperature {
visible: M.Modules.temperature.enable visible: S.Modules.temperature.enable
} }
M.Weather { M.Weather {
visible: M.Modules.weather.enable visible: S.Modules.weather.enable
} }
M.Disk { M.Disk {
visible: M.Modules.disk.enable visible: S.Modules.disk.enable
} }
} }
@ -225,7 +226,7 @@ PanelWindow {
M.Battery {} M.Battery {}
M.Power { M.Power {
bar: bar bar: bar
visible: M.Modules.power.enable visible: S.Modules.power.enable
} }
} }
} }

View file

@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Effects import QtQuick.Effects
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
Item { Item {
id: root id: root
@ -16,21 +17,21 @@ Item {
const gx = mapToGlobal(width / 2, 0).x - scr.x; const gx = mapToGlobal(width / 2, 0).x - scr.x;
return Math.max(0, Math.min(1, gx / scr.width)); return Math.max(0, Math.min(1, gx / scr.width));
} }
property color borderColor: Qt.rgba(M.Theme.base0C.r + (M.Theme.base09.r - M.Theme.base0C.r) * _posFrac, M.Theme.base0C.g + (M.Theme.base09.g - M.Theme.base0C.g) * _posFrac, M.Theme.base0C.b + (M.Theme.base09.b - M.Theme.base0C.b) * _posFrac, 1) property color borderColor: Qt.rgba(S.Theme.base0C.r + (S.Theme.base09.r - S.Theme.base0C.r) * _posFrac, S.Theme.base0C.g + (S.Theme.base09.g - S.Theme.base0C.g) * _posFrac, S.Theme.base0C.b + (S.Theme.base09.b - S.Theme.base0C.b) * _posFrac, 1)
property bool leftEdge: false property bool leftEdge: false
property bool rightEdge: false property bool rightEdge: false
readonly property real _tlr: leftEdge ? M.Theme.screenRadius : M.Theme.radius readonly property real _tlr: leftEdge ? S.Theme.screenRadius : S.Theme.radius
readonly property real _trr: rightEdge ? M.Theme.screenRadius : M.Theme.radius readonly property real _trr: rightEdge ? S.Theme.screenRadius : S.Theme.radius
readonly property real _blr: M.Theme.radius readonly property real _blr: S.Theme.radius
readonly property real _brr: M.Theme.radius readonly property real _brr: S.Theme.radius
visible: row.visibleChildren.length > 0 visible: row.visibleChildren.length > 0
implicitWidth: row.implicitWidth + _pad * 2 implicitWidth: row.implicitWidth + _pad * 2
implicitHeight: M.Theme.barHeight - 3 - _pad implicitHeight: S.Theme.barHeight - 3 - _pad
readonly property int _pad: M.Theme.groupPadding readonly property int _pad: S.Theme.groupPadding
property bool _hovered: false property bool _hovered: false
HoverHandler { HoverHandler {
@ -44,7 +45,7 @@ Item {
topRightRadius: root._trr topRightRadius: root._trr
bottomLeftRadius: root._blr bottomLeftRadius: root._blr
bottomRightRadius: root._brr bottomRightRadius: root._brr
color: Qt.rgba(M.Theme.base01.r, M.Theme.base01.g, M.Theme.base01.b, 0.55) color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.55)
} }
// Frost sheen subtle white highlight, top-heavy // Frost sheen subtle white highlight, top-heavy
@ -143,7 +144,7 @@ Item {
id: row id: row
property color accentColor: root.borderColor property color accentColor: root.borderColor
anchors.centerIn: parent anchors.centerIn: parent
spacing: M.Theme.moduleSpacing + 2 spacing: S.Theme.moduleSpacing + 2
} }
// Separator lines overlaid between visible row children // Separator lines overlaid between visible row children

View file

@ -1,13 +1,14 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
Text { Text {
id: root id: root
property string icon: "" property string icon: ""
property string tooltip: "" property string tooltip: ""
property string minIcon: "" property string minIcon: ""
property color accentColor: parent?.accentColor ?? M.Theme.base05 property color accentColor: parent?.accentColor ?? S.Theme.base05
property bool _hovered: false property bool _hovered: false
property string _displayIcon: icon property string _displayIcon: icon
property string _pendingIcon: "" property string _pendingIcon: ""
@ -43,8 +44,8 @@ Text {
width: minIcon ? Math.max(implicitWidth, _minIconMetrics.width) : implicitWidth width: minIcon ? Math.max(implicitWidth, _minIconMetrics.width) : implicitWidth
horizontalAlignment: minIcon ? Text.AlignHCenter : Text.AlignLeft horizontalAlignment: minIcon ? Text.AlignHCenter : Text.AlignLeft
color: root.accentColor color: root.accentColor
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: S.Theme.fontSize + 1
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
TextMetrics { TextMetrics {

View file

@ -1,21 +1,22 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
Text { Text {
id: root id: root
property string label: "" property string label: ""
property string tooltip: "" property string tooltip: ""
property string minText: "" property string minText: ""
property color accentColor: parent?.accentColor ?? M.Theme.base05 property color accentColor: parent?.accentColor ?? S.Theme.base05
property bool _hovered: false property bool _hovered: false
text: label text: label
width: minText ? Math.max(implicitWidth, _minMetrics.width) : implicitWidth width: minText ? Math.max(implicitWidth, _minMetrics.width) : implicitWidth
horizontalAlignment: minText ? Text.AlignHCenter : Text.AlignLeft horizontalAlignment: minText ? Text.AlignHCenter : Text.AlignLeft
color: root.accentColor color: root.accentColor
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
TextMetrics { TextMetrics {

View file

@ -1,12 +1,13 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
Row { Row {
id: root id: root
property string tooltip: "" property string tooltip: ""
property bool _hovered: false property bool _hovered: false
property color accentColor: parent?.accentColor ?? M.Theme.base05 property color accentColor: parent?.accentColor ?? S.Theme.base05
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {

View file

@ -3,21 +3,22 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Services.UPower import Quickshell.Services.UPower
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
opacity: M.Modules.battery.enable && (UPower.displayDevice?.isLaptopBattery ?? false) ? 1 : 0 opacity: S.Modules.battery.enable && (UPower.displayDevice?.isLaptopBattery ?? false) ? 1 : 0
visible: opacity > 0 visible: opacity > 0
tooltip: "" tooltip: ""
readonly property var dev: UPower.displayDevice readonly property var dev: UPower.displayDevice
readonly property real pct: (dev?.percentage ?? 0) * 100 readonly property real pct: (dev?.percentage ?? 0) * 100
readonly property bool charging: dev?.state === UPowerDeviceState.Charging readonly property bool charging: dev?.state === UPowerDeviceState.Charging
readonly property int _critThresh: M.Modules.battery.critical || 15 readonly property int _critThresh: S.Modules.battery.critical || 15
readonly property int _warnThresh: M.Modules.battery.warning || 25 readonly property int _warnThresh: S.Modules.battery.warning || 25
readonly property bool _critical: pct < _critThresh && !charging readonly property bool _critical: pct < _critThresh && !charging
property color _stateColor: charging ? M.Theme.base0B : _critical ? M.Theme.base09 : pct < _warnThresh ? M.Theme.base0A : root.accentColor property color _stateColor: charging ? S.Theme.base0B : _critical ? S.Theme.base09 : pct < _warnThresh ? S.Theme.base0A : root.accentColor
property real _blinkOpacity: 1 property real _blinkOpacity: 1
SequentialAnimation { SequentialAnimation {
@ -118,7 +119,7 @@ M.BarSection {
} }
color: root._stateColor color: root._stateColor
opacity: root._blinkOpacity opacity: root._blinkOpacity
font.pixelSize: M.Theme.fontSize + 2 font.pixelSize: S.Theme.fontSize + 2
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TapHandler { TapHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -163,8 +164,8 @@ M.BarSection {
return Math.round(root.pct) + "%" + (ts ? " " + ts : ""); return Math.round(root.pct) + "%" + (ts ? " " + ts : "");
} }
color: root._stateColor color: root._stateColor
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
} }
} }
@ -184,7 +185,7 @@ M.BarSection {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: M.Theme.base02 color: S.Theme.base02
radius: 3 radius: 3
} }
@ -208,7 +209,7 @@ M.BarSection {
width: 1 width: 1
height: parent.height + 4 height: parent.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: M.Theme.base0A color: S.Theme.base0A
opacity: 0.6 opacity: 0.6
} }
@ -218,7 +219,7 @@ M.BarSection {
width: 1 width: 1
height: parent.height + 4 height: parent.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: M.Theme.base08 color: S.Theme.base08
opacity: 0.6 opacity: 0.6
} }
} }
@ -268,7 +269,7 @@ M.BarSection {
// Warning threshold line // Warning threshold line
const warnY = height - height * (root._warnThresh / 100); const warnY = height - height * (root._warnThresh / 100);
ctx.strokeStyle = M.Theme.base0A.toString(); ctx.strokeStyle = S.Theme.base0A.toString();
ctx.globalAlpha = 0.3; ctx.globalAlpha = 0.3;
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.setLineDash([3, 3]); ctx.setLineDash([3, 3]);
@ -279,7 +280,7 @@ M.BarSection {
// Critical threshold line // Critical threshold line
const critY = height - height * (root._critThresh / 100); const critY = height - height * (root._critThresh / 100);
ctx.strokeStyle = M.Theme.base08.toString(); ctx.strokeStyle = S.Theme.base08.toString();
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(0, critY); ctx.moveTo(0, critY);
ctx.lineTo(width, critY); ctx.lineTo(width, critY);
@ -327,9 +328,9 @@ M.BarSection {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "warn " + root._warnThresh + "% crit " + root._critThresh + "%" text: "warn " + root._warnThresh + "% crit " + root._critThresh + "%"
color: M.Theme.base03 color: S.Theme.base03
font.pixelSize: M.Theme.fontSize - 3 font.pixelSize: S.Theme.fontSize - 3
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.letterSpacing: 0.5 font.letterSpacing: 0.5
} }
@ -338,9 +339,9 @@ M.BarSection {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "24h" text: "24h"
color: M.Theme.base03 color: S.Theme.base03
font.pixelSize: M.Theme.fontSize - 3 font.pixelSize: S.Theme.fontSize - 3
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }
@ -349,7 +350,7 @@ M.BarSection {
width: parent.width - 16 width: parent.width - 16
height: 1 height: 1
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
color: M.Theme.base03 color: S.Theme.base03
} }
// Rate + health rows // Rate + health rows
@ -363,9 +364,9 @@ M.BarSection {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.charging ? "Charging" : "Discharging" text: root.charging ? "Charging" : "Discharging"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
Text { Text {
@ -377,8 +378,8 @@ M.BarSection {
return r > 0 ? r.toFixed(1) + " W" : ""; return r > 0 ? r.toFixed(1) + " W" : "";
} }
color: root._stateColor color: root._stateColor
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }
@ -392,9 +393,9 @@ M.BarSection {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Health" text: "Health"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
Text { Text {
@ -404,10 +405,10 @@ M.BarSection {
text: Math.round((root.dev?.healthPercentage ?? 0) * 100) + "%" text: Math.round((root.dev?.healthPercentage ?? 0) * 100) + "%"
color: { color: {
const h = (root.dev?.healthPercentage ?? 1) * 100; const h = (root.dev?.healthPercentage ?? 1) * 100;
return h < 50 ? M.Theme.base08 : h < 75 ? M.Theme.base0A : M.Theme.base0B; return h < 50 ? S.Theme.base08 : h < 75 ? S.Theme.base0A : S.Theme.base0B;
} }
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }

View file

@ -2,11 +2,12 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
opacity: M.Modules.bluetooth.enable && root.state !== "unavailable" ? 1 : 0 opacity: S.Modules.bluetooth.enable && root.state !== "unavailable" ? 1 : 0
visible: opacity > 0 visible: opacity > 0
tooltip: { tooltip: {
if (root.state === "off") if (root.state === "off")
@ -35,7 +36,7 @@ M.BarSection {
Process { Process {
id: proc id: proc
running: M.Modules.bluetooth.enable running: S.Modules.bluetooth.enable
command: ["sh", "-c", "s=$(bluetoothctl show 2>/dev/null); " + "[ -z \"$s\" ] && echo unavailable && exit; " + "echo \"$s\" | grep -q 'Powered: yes' || { echo off:; exit; }; " + "info=$(bluetoothctl info 2>/dev/null); " + "d=$(echo \"$info\" | awk -F': ' '/\\tName:/{n=$2}/Connected: yes/{c=1}END{if(c)print n}'); " + "[ -n \"$d\" ] && echo \"connected:$d\" || { echo on:; exit; }; " + "bat=$(echo \"$info\" | awk -F': ' '/Battery Percentage.*\\(/{gsub(/[^0-9]/,\"\",$2);print $2}'); " + "[ -n \"$bat\" ] && echo \"bat:$bat\""] command: ["sh", "-c", "s=$(bluetoothctl show 2>/dev/null); " + "[ -z \"$s\" ] && echo unavailable && exit; " + "echo \"$s\" | grep -q 'Powered: yes' || { echo off:; exit; }; " + "info=$(bluetoothctl info 2>/dev/null); " + "d=$(echo \"$info\" | awk -F': ' '/\\tName:/{n=$2}/Connected: yes/{c=1}END{if(c)print n}'); " + "[ -n \"$d\" ] && echo \"connected:$d\" || { echo on:; exit; }; " + "bat=$(echo \"$info\" | awk -F': ' '/Battery Percentage.*\\(/{gsub(/[^0-9]/,\"\",$2);print $2}'); " + "[ -n \"$bat\" ] && echo \"bat:$bat\""]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: root._parse(text) onStreamFinished: root._parse(text)
@ -44,7 +45,7 @@ M.BarSection {
// Event-driven: watch BlueZ DBus property changes // Event-driven: watch BlueZ DBus property changes
Process { Process {
id: btMonitor id: btMonitor
running: M.Modules.bluetooth.enable running: S.Modules.bluetooth.enable
command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path_namespace='/org/bluez'\" 2>/dev/null"] command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path_namespace='/org/bluez'\" 2>/dev/null"]
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
@ -58,14 +59,14 @@ M.BarSection {
} }
Timer { Timer {
interval: 60000 interval: 60000
running: M.Modules.bluetooth.enable running: S.Modules.bluetooth.enable
repeat: true repeat: true
onTriggered: proc.running = true onTriggered: proc.running = true
} }
M.BarIcon { M.BarIcon {
icon: "\uF294" icon: "\uF294"
color: root.state === "off" ? M.Theme.base04 : root.accentColor color: root.state === "off" ? S.Theme.base04 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TapHandler { TapHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.HoverPanel { M.HoverPanel {
id: menuWindow id: menuWindow
@ -18,9 +19,9 @@ M.HoverPanel {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "\uF011" text: "\uF011"
color: menuWindow._btEnabled ? menuWindow.accentColor : M.Theme.base04 color: menuWindow._btEnabled ? menuWindow.accentColor : S.Theme.base04
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@ -119,8 +120,8 @@ M.HoverPanel {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: entryHover.hovered ? M.Theme.base02 : "transparent" color: entryHover.hovered ? S.Theme.base02 : "transparent"
radius: M.Theme.radius radius: S.Theme.radius
} }
Text { Text {
@ -129,9 +130,9 @@ M.HoverPanel {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "\uF294" text: "\uF294"
color: entry.modelData.connected ? menuWindow.accentColor : M.Theme.base04 color: entry.modelData.connected ? menuWindow.accentColor : S.Theme.base04
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: S.Theme.fontSize + 1
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
} }
Text { Text {
@ -141,9 +142,9 @@ M.HoverPanel {
anchors.rightMargin: 4 anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.name text: entry.modelData.name
color: entry.modelData.connected ? menuWindow.accentColor : M.Theme.base05 color: entry.modelData.connected ? menuWindow.accentColor : S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: entry.modelData.connected font.bold: entry.modelData.connected
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -154,9 +155,9 @@ M.HoverPanel {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.battery >= 0 ? entry.modelData.battery + "%" : "" text: entry.modelData.battery >= 0 ? entry.modelData.battery + "%" : ""
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
width: entry.modelData.battery >= 0 ? implicitWidth : 0 width: entry.modelData.battery >= 0 ? implicitWidth : 0
} }
@ -181,8 +182,8 @@ M.HoverPanel {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: menuWindow._btEnabled ? "No paired devices" : "Bluetooth is off" text: menuWindow._btEnabled ? "No paired devices" : "Bluetooth is off"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
M.BarLabel { M.BarLabel {
SystemClock { SystemClock {
@ -8,7 +9,7 @@ M.BarLabel {
precision: SystemClock.Seconds precision: SystemClock.Seconds
} }
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: S.Theme.fontSize + 1
label: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm") label: Qt.formatDateTime(clock.date, "ddd, dd. MMM HH:mm")
tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy\nHH:mm:ss") tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy\nHH:mm:ss")
} }

View file

@ -1,16 +1,17 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
import "../applets" as C import "../applets" as C
M.BarSection { M.BarSection {
id: root id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2) spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: "" tooltip: ""
readonly property var _cores: M.SystemStats.cpuCores readonly property var _cores: S.SystemStats.cpuCores
readonly property var _coreMaxFreq: M.SystemStats.cpuCoreMaxFreq readonly property var _coreMaxFreq: S.SystemStats.cpuCoreMaxFreq
readonly property var _coreTypes: M.SystemStats.cpuCoreTypes readonly property var _coreTypes: S.SystemStats.cpuCoreTypes
property bool _pinned: false property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
@ -21,10 +22,10 @@ M.BarSection {
on_ShowPanelChanged: { on_ShowPanelChanged: {
if (_showPanel && !_coreConsumerActive) { if (_showPanel && !_coreConsumerActive) {
_coreConsumerActive = true; _coreConsumerActive = true;
M.SystemStats.coreConsumers++; S.SystemStats.coreConsumers++;
} else if (!_showPanel && _coreConsumerActive) { } else if (!_showPanel && _coreConsumerActive) {
_coreConsumerActive = false; _coreConsumerActive = false;
M.SystemStats.coreConsumers--; S.SystemStats.coreConsumers--;
} }
} }
@ -56,7 +57,7 @@ M.BarSection {
} }
} }
M.BarLabel { M.BarLabel {
label: M.SystemStats.cpuUsage.toString().padStart(2) + "%@" + M.SystemStats.cpuFreqGhz.toFixed(2) label: S.SystemStats.cpuUsage.toString().padStart(2) + "%@" + S.SystemStats.cpuFreqGhz.toFixed(2)
minText: "99%@9.99" minText: "99%@9.99"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TapHandler { TapHandler {

View file

@ -1,15 +1,16 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
import "../applets" as C import "../applets" as C
M.BarSection { M.BarSection {
id: root id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2) spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: "" tooltip: ""
property var _mounts: M.SystemStats.diskMounts property var _mounts: S.SystemStats.diskMounts
property int _rootPct: M.SystemStats.diskRootPct property int _rootPct: S.SystemStats.diskRootPct
property bool _pinned: false property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S
PanelWindow { PanelWindow {
id: root id: root
@ -35,8 +36,8 @@ PanelWindow {
margins.top: 0 margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(M.FlyoutState.itemX - implicitWidth / 2), screen.width - implicitWidth)) margins.left: Math.max(0, Math.min(Math.round(M.FlyoutState.itemX - implicitWidth / 2), screen.width - implicitWidth))
implicitWidth: label.implicitWidth + M.Theme.barPadding * 2 implicitWidth: label.implicitWidth + S.Theme.barPadding * 2
implicitHeight: label.implicitHeight + M.Theme.barPadding * 2 implicitHeight: label.implicitHeight + S.Theme.barPadding * 2
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
@ -93,9 +94,9 @@ PanelWindow {
anchors.centerIn: parent anchors.centerIn: parent
text: M.FlyoutState.text.replace(/\n/g, "<br>") text: M.FlyoutState.text.replace(/\n/g, "<br>")
textFormat: Text.RichText textFormat: Text.RichText
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }
} }

View file

@ -1,11 +1,12 @@
pragma Singleton pragma Singleton
import QtQuick import QtQuick
import "." as M import "." as M
import "../services" as S
QtObject { QtObject {
property bool visible: false property bool visible: false
property string text: "" property string text: ""
property real itemX: 0 property real itemX: 0
property var screen: null property var screen: null
property color accentColor: M.Theme.base05 property color accentColor: S.Theme.base05
} }

View file

@ -1,12 +1,13 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2) spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: "" tooltip: ""
visible: M.Modules.gpu.enable && M.SystemStats.gpuAvailable visible: S.Modules.gpu.enable && S.SystemStats.gpuAvailable
property bool _pinned: false property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
@ -27,8 +28,8 @@ M.BarSection {
function _loadColor(pct) { function _loadColor(pct) {
const t = Math.max(0, Math.min(100, pct)) / 100; const t = Math.max(0, Math.min(100, pct)) / 100;
const a = t < 0.5 ? M.Theme.base0B : M.Theme.base0A; const a = t < 0.5 ? S.Theme.base0B : S.Theme.base0A;
const b = t < 0.5 ? M.Theme.base0A : M.Theme.base08; const b = t < 0.5 ? S.Theme.base0A : S.Theme.base08;
const u = t < 0.5 ? t * 2 : (t - 0.5) * 2; const u = t < 0.5 ? t * 2 : (t - 0.5) * 2;
return Qt.rgba(a.r + (b.r - a.r) * u, a.g + (b.g - a.g) * u, a.b + (b.b - a.b) * u, 1); return Qt.rgba(a.r + (b.r - a.r) * u, a.g + (b.g - a.g) * u, a.b + (b.b - a.b) * u, 1);
} }
@ -39,7 +40,7 @@ M.BarSection {
M.BarIcon { M.BarIcon {
icon: "\uDB84\uDCB0" icon: "\uDB84\uDCB0"
color: root._loadColor(M.SystemStats.gpuUsage) color: root._loadColor(S.SystemStats.gpuUsage)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TapHandler { TapHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -47,9 +48,9 @@ M.BarSection {
} }
} }
M.BarLabel { M.BarLabel {
label: M.SystemStats.gpuUsage + "%" label: S.SystemStats.gpuUsage + "%"
minText: "100%" minText: "100%"
color: root._loadColor(M.SystemStats.gpuUsage) color: root._loadColor(S.SystemStats.gpuUsage)
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TapHandler { TapHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@ -76,10 +77,10 @@ M.BarSection {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: M.SystemStats.gpuVendor.toUpperCase() text: S.SystemStats.gpuVendor.toUpperCase()
color: M.Theme.base03 color: S.Theme.base03
font.pixelSize: M.Theme.fontSize - 3 font.pixelSize: S.Theme.fontSize - 3
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -87,10 +88,10 @@ M.BarSection {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: M.SystemStats.gpuUsage + "%" text: S.SystemStats.gpuUsage + "%"
color: root._loadColor(M.SystemStats.gpuUsage) color: root._loadColor(S.SystemStats.gpuUsage)
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
} }
} }
@ -110,14 +111,14 @@ M.BarSection {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: M.Theme.base02 color: S.Theme.base02
radius: 3 radius: 3
} }
Rectangle { Rectangle {
width: parent.width * Math.min(1, M.SystemStats.gpuUsage / 100) width: parent.width * Math.min(1, S.SystemStats.gpuUsage / 100)
height: parent.height height: parent.height
color: root._loadColor(M.SystemStats.gpuUsage) color: root._loadColor(S.SystemStats.gpuUsage)
radius: 3 radius: 3
Behavior on width { Behavior on width {
enabled: root._showPanel enabled: root._showPanel
@ -139,7 +140,7 @@ M.BarSection {
anchors.rightMargin: 12 anchors.rightMargin: 12
height: 36 height: 36
property var _hist: M.SystemStats.gpuHistory property var _hist: S.SystemStats.gpuHistory
on_HistChanged: if (root._showPanel) on_HistChanged: if (root._showPanel)
requestPaint() requestPaint()
@ -177,7 +178,7 @@ M.BarSection {
width: parent.width - 16 width: parent.width - 16
height: 1 height: 1
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
color: M.Theme.base03 color: S.Theme.base03
} }
Item { Item {
@ -189,9 +190,9 @@ M.BarSection {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "VRAM" text: "VRAM"
color: M.Theme.base03 color: S.Theme.base03
font.pixelSize: M.Theme.fontSize - 3 font.pixelSize: S.Theme.fontSize - 3
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.letterSpacing: 1 font.letterSpacing: 1
} }
@ -199,10 +200,10 @@ M.BarSection {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root._fmt(M.SystemStats.gpuVramUsedGb) + " / " + root._fmt(M.SystemStats.gpuVramTotalGb) text: root._fmt(S.SystemStats.gpuVramUsedGb) + " / " + root._fmt(S.SystemStats.gpuVramTotalGb)
color: root.accentColor color: root.accentColor
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
} }
} }
@ -221,12 +222,12 @@ M.BarSection {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: M.Theme.base02 color: S.Theme.base02
radius: 2 radius: 2
} }
Rectangle { Rectangle {
width: M.SystemStats.gpuVramTotalGb > 0 ? parent.width * Math.min(1, M.SystemStats.gpuVramUsedGb / M.SystemStats.gpuVramTotalGb) : 0 width: S.SystemStats.gpuVramTotalGb > 0 ? parent.width * Math.min(1, S.SystemStats.gpuVramUsedGb / S.SystemStats.gpuVramTotalGb) : 0
height: parent.height height: parent.height
color: root.accentColor color: root.accentColor
radius: 2 radius: 2
@ -245,26 +246,26 @@ M.BarSection {
Item { Item {
width: parent.width width: parent.width
height: 22 height: 22
visible: M.SystemStats.gpuTempC > 0 visible: S.SystemStats.gpuTempC > 0
Text { Text {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Temp" text: "Temp"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
Text { Text {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: M.SystemStats.gpuTempC + "\u00B0C" text: S.SystemStats.gpuTempC + "\u00B0C"
color: M.SystemStats.gpuTempC > 85 ? M.Theme.base08 : M.SystemStats.gpuTempC > 70 ? M.Theme.base0A : M.Theme.base05 color: S.SystemStats.gpuTempC > 85 ? S.Theme.base08 : S.SystemStats.gpuTempC > 70 ? S.Theme.base0A : S.Theme.base05
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S
// Unified bar panel fullscreen transparent window so content can resize // Unified bar panel fullscreen transparent window so content can resize
// freely without triggering Wayland surface resizes. // freely without triggering Wayland surface resizes.
@ -236,7 +237,7 @@ PanelWindow {
y: panelContainer.y y: panelContainer.y
width: panelContainer.width width: panelContainer.width
height: panelContainer.height height: panelContainer.height
opacity: panelContainer.opacity * Math.max(M.Theme.barOpacity, 0.85) opacity: panelContainer.opacity * Math.max(S.Theme.barOpacity, 0.85)
accentColor: root.accentColor accentColor: root.accentColor
} }
@ -301,9 +302,9 @@ PanelWindow {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: root.panelTitle text: root.panelTitle
color: root.accentColor color: root.accentColor
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.bold: true font.bold: true
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
// Action buttons anchored left of pin button slot // Action buttons anchored left of pin button slot
@ -337,9 +338,9 @@ PanelWindow {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: root._pinned ? "\uDB81\uDC03" : "\uDB82\uDD31" text: root._pinned ? "\uDB81\uDC03" : "\uDB82\uDD31"
color: root._pinned ? root.accentColor : M.Theme.base04 color: root._pinned ? root.accentColor : S.Theme.base04
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@ -355,7 +356,7 @@ PanelWindow {
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
height: 1 height: 1
color: M.Theme.base03 color: S.Theme.base03
} }
} }
@ -375,7 +376,7 @@ PanelWindow {
color: "transparent" color: "transparent"
border.color: root.accentColor border.color: root.accentColor
border.width: 1 border.width: 1
radius: M.Theme.radius radius: S.Theme.radius
opacity: panelContainer.opacity opacity: panelContainer.opacity
} }
} }

View file

@ -2,10 +2,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.BarIcon { M.BarIcon {
id: root id: root
color: root.active ? M.Theme.base09 : root.accentColor color: root.active ? S.Theme.base09 : root.accentColor
tooltip: { tooltip: {
const parts = ["Idle inhibition: " + (root.active ? "active" : "inactive")]; const parts = ["Idle inhibition: " + (root.active ? "active" : "inactive")];
if (root._inhibitors) if (root._inhibitors)

View file

@ -1,19 +1,20 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
import "../applets" as C import "../applets" as C
M.BarSection { M.BarSection {
id: root id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2) spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: "" tooltip: ""
property int percent: M.SystemStats.memPercent property int percent: S.SystemStats.memPercent
property real usedGb: M.SystemStats.memUsedGb property real usedGb: S.SystemStats.memUsedGb
property real totalGb: M.SystemStats.memTotalGb property real totalGb: S.SystemStats.memTotalGb
property real availGb: M.SystemStats.memAvailGb property real availGb: S.SystemStats.memAvailGb
property real cachedGb: M.SystemStats.memCachedGb property real cachedGb: S.SystemStats.memCachedGb
property real buffersGb: M.SystemStats.memBuffersGb property real buffersGb: S.SystemStats.memBuffersGb
property bool _pinned: false property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered

View file

@ -3,12 +3,13 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Services.Mpris import Quickshell.Services.Mpris
import "." as M import "." as M
import "../services" as S
import "../applets" as C import "../applets" as C
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
opacity: M.Modules.mpris.enable && player !== null ? 1 : 0 opacity: S.Modules.mpris.enable && player !== null ? 1 : 0
visible: opacity > 0 visible: opacity > 0
tooltip: "" tooltip: ""

View file

@ -2,10 +2,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
tooltip: "" tooltip: ""
property string ifname: "" property string ifname: ""
@ -16,7 +17,7 @@ M.BarSection {
Process { Process {
id: proc id: proc
running: M.Modules.network.enable running: S.Modules.network.enable
command: ["sh", "-c", "line=$(nmcli -t -f NAME,TYPE,DEVICE connection show --active 2>/dev/null | head -1); if [ -z \"$line\" ]; then dev=$(nmcli -t -f DEVICE,STATE device 2>/dev/null | grep ':connected' | grep -v ':unmanaged\\|:unavailable\\|:disconnected\\|:connecting' | head -1 | cut -d: -f1); [ -n \"$dev\" ] && line=\"linked:linked:$dev\"; fi; [ -z \"$line\" ] && exit 0; echo \"$line\"; dev=$(echo \"$line\" | cut -d: -f3); ip=$(nmcli -t -f IP4.ADDRESS device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"ip:${ip:-}\"; sig=$(nmcli -t -f GENERAL.SIGNAL device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"sig:${sig:-}\""] command: ["sh", "-c", "line=$(nmcli -t -f NAME,TYPE,DEVICE connection show --active 2>/dev/null | head -1); if [ -z \"$line\" ]; then dev=$(nmcli -t -f DEVICE,STATE device 2>/dev/null | grep ':connected' | grep -v ':unmanaged\\|:unavailable\\|:disconnected\\|:connecting' | head -1 | cut -d: -f1); [ -n \"$dev\" ] && line=\"linked:linked:$dev\"; fi; [ -z \"$line\" ] && exit 0; echo \"$line\"; dev=$(echo \"$line\" | cut -d: -f3); ip=$(nmcli -t -f IP4.ADDRESS device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"ip:${ip:-}\"; sig=$(nmcli -t -f GENERAL.SIGNAL device show \"$dev\" 2>/dev/null | head -1 | cut -d: -f2); echo \"sig:${sig:-}\""]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
@ -53,7 +54,7 @@ M.BarSection {
// Event-driven: re-poll on any network change // Event-driven: re-poll on any network change
Process { Process {
id: monitor id: monitor
running: M.Modules.network.enable running: S.Modules.network.enable
command: ["nmcli", "monitor"] command: ["nmcli", "monitor"]
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
@ -71,7 +72,7 @@ M.BarSection {
// Fallback poll // Fallback poll
Timer { Timer {
interval: 60000 interval: 60000
running: M.Modules.network.enable running: S.Modules.network.enable
repeat: true repeat: true
onTriggered: proc.running = true onTriggered: proc.running = true
} }
@ -86,13 +87,13 @@ M.BarSection {
return "\uDB85\uDE16"; return "\uDB85\uDE16";
return "\uDB82\uDCFD"; return "\uDB82\uDCFD";
} }
color: root.state === "disconnected" ? M.Theme.base08 : root.accentColor color: root.state === "disconnected" ? S.Theme.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
M.BarLabel { M.BarLabel {
visible: root.state === "wifi" visible: root.state === "wifi"
label: root.essid label: root.essid
color: root.state === "disconnected" ? M.Theme.base08 : root.accentColor color: root.state === "disconnected" ? S.Theme.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.HoverPanel { M.HoverPanel {
id: menuWindow id: menuWindow
@ -17,9 +18,9 @@ M.HoverPanel {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "\uF011" text: "\uF011"
color: menuWindow._wifiEnabled ? menuWindow.accentColor : M.Theme.base04 color: menuWindow._wifiEnabled ? menuWindow.accentColor : S.Theme.base04
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@ -156,8 +157,8 @@ M.HoverPanel {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: entryHover.hovered ? M.Theme.base02 : "transparent" color: entryHover.hovered ? S.Theme.base02 : "transparent"
radius: M.Theme.radius radius: S.Theme.radius
} }
Text { Text {
@ -166,9 +167,9 @@ M.HoverPanel {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.isWifi ? "\uF1EB" : "\uDB80\uDE00" text: entry.modelData.isWifi ? "\uF1EB" : "\uDB80\uDE00"
color: entry.modelData.active ? menuWindow.accentColor : M.Theme.base05 color: entry.modelData.active ? menuWindow.accentColor : S.Theme.base05
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: S.Theme.fontSize + 1
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
} }
Text { Text {
@ -178,9 +179,9 @@ M.HoverPanel {
anchors.rightMargin: 4 anchors.rightMargin: 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.name text: entry.modelData.name
color: entry.modelData.active ? menuWindow.accentColor : M.Theme.base05 color: entry.modelData.active ? menuWindow.accentColor : S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: entry.modelData.active font.bold: entry.modelData.active
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -191,9 +192,9 @@ M.HoverPanel {
anchors.rightMargin: 12 anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: entry.modelData.signal >= 0 ? entry.modelData.signal + "%" : "" text: entry.modelData.signal >= 0 ? entry.modelData.signal + "%" : ""
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
width: entry.modelData.signal >= 0 ? implicitWidth : 0 width: entry.modelData.signal >= 0 ? implicitWidth : 0
} }
@ -222,8 +223,8 @@ M.HoverPanel {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: menuWindow._wifiEnabled ? "No networks available" : "Wi-Fi is off" text: menuWindow._wifiEnabled ? "No networks available" : "Wi-Fi is off"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S
// Shared notification card: background, progress bar, urgency bar, icon, text, dismiss button. // Shared notification card: background, progress bar, urgency bar, icon, text, dismiss button.
// Does NOT include dismiss animation or dismiss logic emits dismissRequested() instead. // Does NOT include dismiss animation or dismiss logic emits dismissRequested() instead.
@ -14,7 +15,7 @@ Item {
property bool dismissOnAction: true property bool dismissOnAction: true
property int iconSize: 32 property int iconSize: 32
property int bodyMaxLines: 3 property int bodyMaxLines: 3
property color accentColor: M.Theme.base0D property color accentColor: S.Theme.base0D
signal dismissRequested signal dismissRequested
@ -34,9 +35,9 @@ Item {
// Background: base01, base02 on hover // Background: base01, base02 on hover
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: _hover.hovered ? M.Theme.base02 : M.Theme.base01 color: _hover.hovered ? S.Theme.base02 : S.Theme.base01
opacity: _hover.hovered ? 1.0 : Math.max(M.Theme.barOpacity, 0.9) opacity: _hover.hovered ? 1.0 : Math.max(S.Theme.barOpacity, 0.9)
radius: M.Theme.radius radius: S.Theme.radius
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
@ -51,7 +52,7 @@ Item {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
width: parent.width * Math.min(1, Math.max(0, (root.notif?.hints?.value ?? 0) / 100)) width: parent.width * Math.min(1, Math.max(0, (root.notif?.hints?.value ?? 0) / 100))
color: M.Theme.base03 color: S.Theme.base03
radius: parent.radius radius: parent.radius
Behavior on width { Behavior on width {
@ -71,7 +72,7 @@ Item {
radius: 1 radius: 1
color: { color: {
const u = root.notif?.urgency ?? NotificationUrgency.Normal; const u = root.notif?.urgency ?? NotificationUrgency.Normal;
return u === NotificationUrgency.Critical ? M.Theme.base08 : u === NotificationUrgency.Low ? M.Theme.base04 : M.Theme.base0D; return u === NotificationUrgency.Critical ? S.Theme.base08 : u === NotificationUrgency.Low ? S.Theme.base04 : S.Theme.base0D;
} }
} }
@ -107,9 +108,9 @@ Item {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 8 anchors.topMargin: 8
text: "\uF00D" text: "\uF00D"
color: _dismissHover.hovered ? M.Theme.base08 : M.Theme.base03 color: _dismissHover.hovered ? S.Theme.base08 : S.Theme.base03
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
opacity: _hover.hovered ? 1 : 0 opacity: _hover.hovered ? 1 : 0
HoverHandler { HoverHandler {
@ -163,9 +164,9 @@ Item {
Text { Text {
text: root.notif?.appName ?? "Notification" text: root.notif?.appName ?? "Notification"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
width: parent.width - _timeText.implicitWidth - 4 width: parent.width - _timeText.implicitWidth - 4
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -173,9 +174,9 @@ Item {
Text { Text {
id: _timeText id: _timeText
text: root.notif?.timeStr ?? "" text: root.notif?.timeStr ?? ""
color: M.Theme.base03 color: S.Theme.base03
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }
@ -186,9 +187,9 @@ Item {
Text { Text {
text: root.notif?.summary ?? "" text: root.notif?.summary ?? ""
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
width: parent.width - _inlineTime.implicitWidth - 4 width: parent.width - _inlineTime.implicitWidth - 4
@ -197,9 +198,9 @@ Item {
Text { Text {
id: _inlineTime id: _inlineTime
text: root.notif?.timeStr ?? "" text: root.notif?.timeStr ?? ""
color: M.Theme.base03 color: S.Theme.base03
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
@ -208,9 +209,9 @@ Item {
visible: root.showAppName visible: root.showAppName
width: parent.width width: parent.width
text: root.notif?.summary ?? "" text: root.notif?.summary ?? ""
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
@ -220,9 +221,9 @@ Item {
Text { Text {
width: parent.width width: parent.width
text: root.notif?.body ?? "" text: root.notif?.body ?? ""
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
maximumLineCount: root.bodyMaxLines maximumLineCount: root.bodyMaxLines
@ -243,9 +244,9 @@ Item {
required property var modelData required property var modelData
width: _actText.implicitWidth + 12 width: _actText.implicitWidth + 12
height: _actText.implicitHeight + 6 height: _actText.implicitHeight + 6
radius: M.Theme.radius radius: S.Theme.radius
color: _actHover.hovered ? M.Theme.base03 : "transparent" color: _actHover.hovered ? S.Theme.base03 : "transparent"
border.color: M.Theme.base03 border.color: S.Theme.base03
border.width: 1 border.width: 1
Text { Text {
@ -253,8 +254,8 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
text: parent.modelData.text text: parent.modelData.text
color: root.accentColor color: root.accentColor
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
HoverHandler { HoverHandler {

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
M.HoverPanel { M.HoverPanel {
id: menuWindow id: menuWindow
@ -18,9 +19,9 @@ M.HoverPanel {
anchors.leftMargin: 12 anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Notifications" text: "Notifications"
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: S.Theme.fontSize + 1
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
} }
@ -33,9 +34,9 @@ M.HoverPanel {
// DND toggle // DND toggle
Text { Text {
text: M.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C" text: M.NotifService.dnd ? "\uDB82\uDE93" : "\uDB80\uDC9C"
color: M.NotifService.dnd ? M.Theme.base09 : M.Theme.base04 color: M.NotifService.dnd ? S.Theme.base09 : S.Theme.base04
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
MouseArea { MouseArea {
@ -48,9 +49,9 @@ M.HoverPanel {
// Clear all // Clear all
Text { Text {
text: "\uF1F8" text: "\uF1F8"
color: clearArea.containsMouse ? M.Theme.base08 : M.Theme.base04 color: clearArea.containsMouse ? S.Theme.base08 : S.Theme.base04
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: M.NotifService.count > 0 visible: M.NotifService.count > 0
@ -219,14 +220,14 @@ M.HoverPanel {
width: menuWindow.contentWidth - 16 width: menuWindow.contentWidth - 16
height: 1 height: 1
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
color: M.Theme.base03 color: S.Theme.base03
} }
// Notification list (scrollable) // Notification list (scrollable)
ListView { ListView {
id: notifList id: notifList
width: menuWindow.contentWidth width: menuWindow.contentWidth
height: Math.min(contentHeight, 60 * (M.Modules.notifications.maxVisible || 10)) height: Math.min(contentHeight, 60 * (S.Modules.notifications.maxVisible || 10))
clip: true clip: true
boundsBehavior: Flickable.StopAtBounds boundsBehavior: Flickable.StopAtBounds
model: menuWindow._flatModel model: menuWindow._flatModel
@ -253,7 +254,7 @@ M.HoverPanel {
readonly property real _targetHeight: { readonly property real _targetHeight: {
if (_type === "header") if (_type === "header")
return modelData.collapsed ? (28 + modelData.count * (M.Theme.fontSize + 4)) : 28; return modelData.collapsed ? (28 + modelData.count * (S.Theme.fontSize + 4)) : 28;
return _notifCard.implicitHeight; return _notifCard.implicitHeight;
} }
@ -323,8 +324,8 @@ M.HoverPanel {
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: (28 - height) / 2 anchors.topMargin: (28 - height) / 2
width: M.Theme.fontSize + 2 width: S.Theme.fontSize + 2
height: M.Theme.fontSize + 2 height: S.Theme.fontSize + 2
source: { source: {
if (notifDelegate._type !== "header") if (notifDelegate._type !== "header")
return ""; return "";
@ -335,7 +336,7 @@ M.HoverPanel {
} }
visible: status === Image.Ready visible: status === Image.Ready
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
sourceSize: Qt.size(M.Theme.fontSize + 2, M.Theme.fontSize + 2) sourceSize: Qt.size(S.Theme.fontSize + 2, S.Theme.fontSize + 2)
asynchronous: true asynchronous: true
} }
@ -348,9 +349,9 @@ M.HoverPanel {
height: 28 height: 28
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: notifDelegate._type === "header" && notifDelegate.modelData.collapsed ? "\u25B8" : "\u25BE" text: notifDelegate._type === "header" && notifDelegate.modelData.collapsed ? "\u25B8" : "\u25BE"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
opacity: _headerHover.hovered ? 1 : 0 opacity: _headerHover.hovered ? 1 : 0
} }
@ -364,9 +365,9 @@ M.HoverPanel {
height: 28 height: 28
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: notifDelegate._type === "header" ? (notifDelegate.modelData.appName || "Unknown") : "" text: notifDelegate._type === "header" ? (notifDelegate.modelData.appName || "Unknown") : ""
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: true font.bold: true
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -380,9 +381,9 @@ M.HoverPanel {
height: 28 height: 28
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: "\uF1F8" text: "\uF1F8"
color: _groupDismissHover.hovered ? M.Theme.base08 : M.Theme.base04 color: _groupDismissHover.hovered ? S.Theme.base08 : S.Theme.base04
font.pixelSize: M.Theme.fontSize - 1 font.pixelSize: S.Theme.fontSize - 1
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
opacity: _headerHover.hovered ? 1 : 0 opacity: _headerHover.hovered ? 1 : 0
HoverHandler { HoverHandler {
@ -409,14 +410,14 @@ M.HoverPanel {
anchors.leftMargin: 10 anchors.leftMargin: 10
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 10 anchors.rightMargin: 10
y: 28 + index * (M.Theme.fontSize + 4) y: 28 + index * (S.Theme.fontSize + 4)
height: M.Theme.fontSize + 4 height: S.Theme.fontSize + 4
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: modelData text: modelData
elide: Text.ElideRight elide: Text.ElideRight
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
color: M.Theme.base04 color: S.Theme.base04
} }
} }
} }
@ -479,8 +480,8 @@ M.HoverPanel {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: "No notifications" text: "No notifications"
color: M.Theme.base04 color: S.Theme.base04
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
} }

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S
QtObject { QtObject {
id: root id: root

View file

@ -3,6 +3,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S
PanelWindow { PanelWindow {
id: root id: root
@ -33,7 +34,7 @@ PanelWindow {
property var _knownIds: ({}) property var _knownIds: ({})
Repeater { Repeater {
model: M.NotifService.popups.slice(0, M.Modules.notifications.maxPopups || 4) model: M.NotifService.popups.slice(0, S.Modules.notifications.maxPopups || 4)
delegate: Item { delegate: Item {
id: popupItem id: popupItem

View file

@ -4,6 +4,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S
QtObject { QtObject {
id: root id: root
@ -96,7 +97,7 @@ QtObject {
}); });
// Trim excess popups // Trim excess popups
const max = M.Modules.notifications.maxPopups || 4; const max = S.Modules.notifications.maxPopups || 4;
const currentPopups = root.list.filter(n => n.popup); const currentPopups = root.list.filter(n => n.popup);
if (currentPopups.length > max) { if (currentPopups.length > max) {
for (let i = max; i < currentPopups.length; i++) for (let i = max; i < currentPopups.length; i++)
@ -106,13 +107,13 @@ QtObject {
// Auto-expire popup (skip for critical) // Auto-expire popup (skip for critical)
if (item.popup && !isCritical) { if (item.popup && !isCritical) {
const timeout = notif.expireTimeout > 0 ? notif.expireTimeout : (M.Modules.notifications.timeout || 3000); const timeout = notif.expireTimeout > 0 ? notif.expireTimeout : (S.Modules.notifications.timeout || 3000);
item._expireTimer.interval = timeout; item._expireTimer.interval = timeout;
item._expireTimer.running = true; item._expireTimer.running = true;
} }
// Trim history (-1 = unlimited) // Trim history (-1 = unlimited)
const maxHistory = M.Modules.notifications.maxHistory ?? -1; const maxHistory = S.Modules.notifications.maxHistory ?? -1;
while (maxHistory > 0 && root.list.length > maxHistory) { while (maxHistory > 0 && root.list.length > maxHistory) {
const old = root.list.pop(); const old = root.list.pop();
old.finishDismiss(); old.finishDismiss();

View file

@ -2,10 +2,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
tooltip: { tooltip: {
const parts = [M.NotifService.count + " notification" + (M.NotifService.count !== 1 ? "s" : "")]; const parts = [M.NotifService.count + " notification" + (M.NotifService.count !== 1 ? "s" : "")];
if (M.NotifService.dnd) if (M.NotifService.dnd)
@ -23,13 +24,13 @@ M.BarSection {
return M.NotifService.count > 0 ? "\uDB80\uDCA0" : "\uDB82\uDE93"; return M.NotifService.count > 0 ? "\uDB80\uDCA0" : "\uDB82\uDE93";
return M.NotifService.count > 0 ? "\uDB84\uDD6B" : "\uDB80\uDC9C"; return M.NotifService.count > 0 ? "\uDB84\uDD6B" : "\uDB80\uDC9C";
} }
color: M.NotifService.dnd ? M.Theme.base04 : root.accentColor color: M.NotifService.dnd ? S.Theme.base04 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
M.BarLabel { M.BarLabel {
id: countLabel id: countLabel
label: M.NotifService.count > 0 ? String(M.NotifService.count) + (root.hasUrgent ? "!" : "") : "" label: M.NotifService.count > 0 ? String(M.NotifService.count) + (root.hasUrgent ? "!" : "") : ""
color: root.hasUrgent ? M.Theme.base08 : root.accentColor color: root.hasUrgent ? S.Theme.base08 : root.accentColor
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
transform: Scale { transform: Scale {

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S
import "../applets" as C import "../applets" as C
PanelWindow { PanelWindow {

View file

@ -1,12 +1,13 @@
import QtQuick import QtQuick
import "." as M import "." as M
import "../services" as S
Rectangle { Rectangle {
property color accentColor: M.Theme.base05 property color accentColor: S.Theme.base05
color: M.Theme.base01 color: S.Theme.base01
opacity: Math.max(M.Theme.barOpacity, 0.85) opacity: Math.max(S.Theme.barOpacity, 0.85)
radius: M.Theme.radius radius: S.Theme.radius
border.color: accentColor border.color: accentColor
border.width: 1 border.width: 1
} }

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.BarIcon { M.BarIcon {
id: root id: root

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
M.HoverPanel { M.HoverPanel {
id: menuWindow id: menuWindow
@ -23,31 +24,31 @@ M.HoverPanel {
label: "Lock", label: "Lock",
icon: "\uF023", icon: "\uF023",
cmd: ["loginctl", "lock-session"], cmd: ["loginctl", "lock-session"],
color: M.Theme.base0D color: S.Theme.base0D
}, },
{ {
label: "Suspend", label: "Suspend",
icon: "\uF186", icon: "\uF186",
cmd: ["systemctl", "suspend"], cmd: ["systemctl", "suspend"],
color: M.Theme.base0E color: S.Theme.base0E
}, },
{ {
label: "Logout", label: "Logout",
icon: "\uF2F5", icon: "\uF2F5",
cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""], cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""],
color: M.Theme.base0A color: S.Theme.base0A
}, },
{ {
label: "Reboot", label: "Reboot",
icon: "\uF021", icon: "\uF021",
cmd: ["systemctl", "reboot"], cmd: ["systemctl", "reboot"],
color: M.Theme.base09 color: S.Theme.base09
}, },
{ {
label: "Shutdown", label: "Shutdown",
icon: "\uF011", icon: "\uF011",
cmd: ["systemctl", "poweroff"], cmd: ["systemctl", "poweroff"],
color: M.Theme.base08 color: S.Theme.base08
} }
] ]
@ -64,8 +65,8 @@ M.HoverPanel {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: entryArea.containsMouse ? M.Theme.base02 : "transparent" color: entryArea.containsMouse ? S.Theme.base02 : "transparent"
radius: M.Theme.radius radius: S.Theme.radius
} }
Text { Text {
@ -75,8 +76,8 @@ M.HoverPanel {
anchors.leftMargin: 12 anchors.leftMargin: 12
text: entry.modelData.icon text: entry.modelData.icon
color: entry.modelData.color color: entry.modelData.color
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: S.Theme.fontSize + 1
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
} }
Text { Text {
@ -84,9 +85,9 @@ M.HoverPanel {
anchors.left: entryIcon.right anchors.left: entryIcon.right
anchors.leftMargin: 10 anchors.leftMargin: 10
text: entry.modelData.label text: entry.modelData.label
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
MouseArea { MouseArea {

View file

@ -1,11 +1,12 @@
import QtQuick import QtQuick
import "." as M import "." as M
import "../services" as S
M.BarIcon { M.BarIcon {
id: root id: root
tooltip: "Power profile: " + (M.PowerProfileService.profile || "unknown") tooltip: "Power profile: " + (M.PowerProfileService.profile || "unknown")
color: M.PowerProfileService.profile === "performance" ? M.Theme.base09 : M.PowerProfileService.profile === "power-saver" ? M.Theme.base0B : root.accentColor color: M.PowerProfileService.profile === "performance" ? S.Theme.base09 : M.PowerProfileService.profile === "power-saver" ? S.Theme.base0B : root.accentColor
icon: { icon: {
if (M.PowerProfileService.profile === "performance") if (M.PowerProfileService.profile === "performance")

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
QtObject { QtObject {
id: root id: root
@ -11,7 +12,7 @@ QtObject {
readonly property bool powerSaver: profile === "power-saver" readonly property bool powerSaver: profile === "power-saver"
property var _proc: Process { property var _proc: Process {
running: M.Modules.powerProfile.enable running: S.Modules.powerProfile.enable
command: ["powerprofilesctl", "get"] command: ["powerprofilesctl", "get"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: root.profile = text.trim() onStreamFinished: root.profile = text.trim()
@ -19,7 +20,7 @@ QtObject {
} }
property var _monitor: Process { property var _monitor: Process {
running: M.Modules.powerProfile.enable running: S.Modules.powerProfile.enable
command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/net/hadess/PowerProfiles'\" 2>/dev/null"] command: ["sh", "-c", "dbus-monitor --system \"interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/net/hadess/PowerProfiles'\" 2>/dev/null"]
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
@ -34,7 +35,7 @@ QtObject {
property var _poll: Timer { property var _poll: Timer {
interval: 60000 interval: 60000
running: M.Modules.powerProfile.enable running: S.Modules.powerProfile.enable
repeat: true repeat: true
onTriggered: root._proc.running = true onTriggered: root._proc.running = true
} }

View file

@ -2,10 +2,11 @@ import QtQuick
import QtQuick.Effects import QtQuick.Effects
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import "." as M import "." as M
import "../services" as S
Row { Row {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
// Only detect active client streams, not hardware sources/devices // Only detect active client streams, not hardware sources/devices
readonly property bool _videoCapture: { readonly property bool _videoCapture: {
@ -34,21 +35,21 @@ Row {
return false; return false;
} }
visible: M.Modules.privacy.enable && (root._videoCapture || root._audioIn) visible: S.Modules.privacy.enable && (root._videoCapture || root._audioIn)
// Screenshare indicator // Screenshare indicator
Text { Text {
visible: root._videoCapture visible: root._videoCapture
text: "\uF03D" text: "\uF03D"
color: M.Theme.base08 color: S.Theme.base08
font.pixelSize: M.Theme.fontSize + 2 font.pixelSize: S.Theme.fontSize + 2
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: M.Theme.base08 shadowColor: S.Theme.base08
shadowBlur: 0.8 shadowBlur: 0.8
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@ -74,15 +75,15 @@ Row {
Text { Text {
visible: root._audioIn visible: root._audioIn
text: "\uF130" text: "\uF130"
color: M.Theme.base0B color: S.Theme.base0B
font.pixelSize: M.Theme.fontSize + 2 font.pixelSize: S.Theme.fontSize + 2
font.family: M.Theme.iconFontFamily font.family: S.Theme.iconFontFamily
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: M.Theme.base0B shadowColor: S.Theme.base0B
shadowBlur: 0.8 shadowBlur: 0.8
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import "." as M import "." as M
import "../services" as S
// Draws rounded black corners at the edges of each screen. // Draws rounded black corners at the edges of each screen.
// Disabled when screenRadius is 0. // Disabled when screenRadius is 0.
@ -10,7 +11,7 @@ Item {
required property var screen required property var screen
readonly property int _r: M.Theme.screenRadius readonly property int _r: S.Theme.screenRadius
component Corner: PanelWindow { component Corner: PanelWindow {
id: win id: win

View file

@ -1,28 +1,29 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
import "../applets" as C import "../applets" as C
M.BarSection { M.BarSection {
id: root id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2) spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: "" tooltip: ""
readonly property int _warm: M.Modules.temperature.warm || 80 readonly property int _warm: S.Modules.temperature.warm || 80
readonly property int _hot: M.Modules.temperature.hot || 90 readonly property int _hot: S.Modules.temperature.hot || 90
readonly property string _deviceFilter: M.Modules.temperature.device || "" readonly property string _deviceFilter: S.Modules.temperature.device || ""
// If a device filter is set, use that device's temp; otherwise fall back to system max // If a device filter is set, use that device's temp; otherwise fall back to system max
readonly property int _temp: { readonly property int _temp: {
if (_deviceFilter !== "") { if (_deviceFilter !== "") {
const dev = M.SystemStats.tempDevices.find(d => d.name === _deviceFilter); const dev = S.SystemStats.tempDevices.find(d => d.name === _deviceFilter);
if (dev) if (dev)
return dev.celsius; return dev.celsius;
} }
return M.SystemStats.tempCelsius; return S.SystemStats.tempCelsius;
} }
property color _stateColor: _temp > _hot ? M.Theme.base08 : _temp > _warm ? M.Theme.base0A : root.accentColor property color _stateColor: _temp > _hot ? S.Theme.base08 : _temp > _warm ? S.Theme.base0A : root.accentColor
Behavior on _stateColor { Behavior on _stateColor {
ColorAnimation { ColorAnimation {
duration: 300 duration: 300
@ -81,8 +82,8 @@ M.BarSection {
temp: root._temp temp: root._temp
warm: root._warm warm: root._warm
hot: root._hot hot: root._hot
history: M.SystemStats.tempHistory history: S.SystemStats.tempHistory
devices: M.SystemStats.tempDevices devices: S.SystemStats.tempDevices
accentColor: root.accentColor accentColor: root.accentColor
deviceFilter: root._deviceFilter deviceFilter: root._deviceFilter
active: root._showPanel active: root._showPanel

View file

@ -5,11 +5,12 @@ import Quickshell
import Quickshell.Services.SystemTray import Quickshell.Services.SystemTray
import "." as M import "." as M
import "../services" as S
RowLayout { RowLayout {
id: root id: root
spacing: M.Theme.moduleSpacing + 2 spacing: S.Theme.moduleSpacing + 2
visible: M.Modules.tray.enable && SystemTray.items.length > 0 visible: S.Modules.tray.enable && SystemTray.items.length > 0
required property var bar required property var bar
property var _activeMenu: null property var _activeMenu: null
@ -25,8 +26,8 @@ RowLayout {
property bool _hovered: false property bool _hovered: false
property real _pulseOpacity: 1 property real _pulseOpacity: 1
implicitWidth: M.Theme.fontSize + 4 implicitWidth: S.Theme.fontSize + 4
implicitHeight: M.Theme.fontSize + 4 implicitHeight: S.Theme.fontSize + 4
SequentialAnimation { SequentialAnimation {
running: iconItem._needsAttention running: iconItem._needsAttention
@ -56,16 +57,16 @@ RowLayout {
layer.enabled: iconItem._needsAttention || iconItem._hovered layer.enabled: iconItem._needsAttention || iconItem._hovered
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowColor: iconItem._needsAttention ? M.Theme.base08 : M.Theme.base05 shadowColor: iconItem._needsAttention ? S.Theme.base08 : S.Theme.base05
shadowBlur: iconItem._needsAttention ? 0.8 : 0.5 shadowBlur: iconItem._needsAttention ? 0.8 : 0.5
shadowVerticalOffset: 0 shadowVerticalOffset: 0
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
} }
M.ThemedIcon { S.ThemedIcon {
anchors.fill: parent anchors.fill: parent
source: iconItem.modelData.icon source: iconItem.modelData.icon
tint: iconItem._needsAttention ? M.Theme.base08 : (root.parent?.accentColor ?? M.Theme.base05) tint: iconItem._needsAttention ? S.Theme.base08 : (root.parent?.accentColor ?? S.Theme.base05)
} }
} }
@ -77,7 +78,7 @@ RowLayout {
M.FlyoutState.text = tip; M.FlyoutState.text = tip;
M.FlyoutState.itemX = iconItem.mapToGlobal(iconItem.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0); M.FlyoutState.itemX = iconItem.mapToGlobal(iconItem.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0);
M.FlyoutState.screen = QsWindow.window?.screen ?? null; M.FlyoutState.screen = QsWindow.window?.screen ?? null;
M.FlyoutState.accentColor = root.parent?.accentColor ?? M.Theme.base05; M.FlyoutState.accentColor = root.parent?.accentColor ?? S.Theme.base05;
M.FlyoutState.visible = true; M.FlyoutState.visible = true;
} else if (!hovered) { } else if (!hovered) {
M.FlyoutState.visible = false; M.FlyoutState.visible = false;
@ -110,7 +111,7 @@ RowLayout {
id: menuLoader id: menuLoader
active: false active: false
M.TrayMenu { M.TrayMenu {
accentColor: root.parent?.accentColor ?? M.Theme.base05 accentColor: root.parent?.accentColor ?? S.Theme.base05
handle: iconItem.modelData.menu handle: iconItem.modelData.menu
screen: root.bar.screen screen: root.bar.screen
anchorX: iconItem.mapToGlobal(iconItem.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) anchorX: iconItem.mapToGlobal(iconItem.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0)

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import "." as M import "." as M
import "../services" as S
M.HoverPanel { M.HoverPanel {
id: menuWindow id: menuWindow
@ -26,8 +27,8 @@ M.HoverPanel {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: backArea.containsMouse ? M.Theme.base02 : "transparent" color: backArea.containsMouse ? S.Theme.base02 : "transparent"
radius: M.Theme.radius radius: S.Theme.radius
} }
Text { Text {
@ -35,9 +36,9 @@ M.HoverPanel {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 12 anchors.leftMargin: 12
text: "\u2039 Back" text: "\u2039 Back"
color: M.Theme.base05 color: S.Theme.base05
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
MouseArea { MouseArea {
@ -71,7 +72,7 @@ M.HoverPanel {
anchors.leftMargin: 8 anchors.leftMargin: 8
anchors.rightMargin: 8 anchors.rightMargin: 8
height: 1 height: 1
color: M.Theme.base03 color: S.Theme.base03
} }
Rectangle { Rectangle {
@ -79,18 +80,18 @@ M.HoverPanel {
anchors.fill: parent anchors.fill: parent
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.rightMargin: 4 anchors.rightMargin: 4
color: rowArea.containsMouse && entryItem.modelData.enabled ? M.Theme.base02 : "transparent" color: rowArea.containsMouse && entryItem.modelData.enabled ? S.Theme.base02 : "transparent"
radius: M.Theme.radius radius: S.Theme.radius
} }
M.ThemedIcon { S.ThemedIcon {
id: entryIcon id: entryIcon
visible: !entryItem.modelData.isSeparator && entryItem.modelData.icon !== "" visible: !entryItem.modelData.isSeparator && entryItem.modelData.icon !== ""
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 12 anchors.leftMargin: 12
width: M.Theme.fontSize width: S.Theme.fontSize
height: M.Theme.fontSize height: S.Theme.fontSize
source: entryItem.modelData.icon source: entryItem.modelData.icon
tint: menuWindow.accentColor tint: menuWindow.accentColor
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
@ -104,9 +105,9 @@ M.HoverPanel {
anchors.right: entryChevron.visible ? entryChevron.left : parent.right anchors.right: entryChevron.visible ? entryChevron.left : parent.right
anchors.rightMargin: entryChevron.visible ? 4 : 12 anchors.rightMargin: entryChevron.visible ? 4 : 12
text: entryItem.modelData.text text: entryItem.modelData.text
color: entryItem.modelData.enabled ? M.Theme.base05 : M.Theme.base03 color: entryItem.modelData.enabled ? S.Theme.base05 : S.Theme.base03
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
elide: Text.ElideRight elide: Text.ElideRight
} }
@ -117,9 +118,9 @@ M.HoverPanel {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 12 anchors.rightMargin: 12
text: "\u203A" text: "\u203A"
color: entryItem.modelData.enabled ? M.Theme.base05 : M.Theme.base03 color: entryItem.modelData.enabled ? S.Theme.base05 : S.Theme.base03
font.pixelSize: M.Theme.fontSize font.pixelSize: S.Theme.fontSize
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
} }
MouseArea { MouseArea {

View file

@ -2,11 +2,12 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Services.Pipewire import Quickshell.Services.Pipewire
import "." as M import "." as M
import "../services" as S
import "../applets" as C import "../applets" as C
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
tooltip: "" tooltip: ""
PwObjectTracker { PwObjectTracker {
@ -17,7 +18,7 @@ M.BarSection {
readonly property real volume: sink?.audio?.volume ?? 0 readonly property real volume: sink?.audio?.volume ?? 0
readonly property bool muted: sink?.audio?.muted ?? false readonly property bool muted: sink?.audio?.muted ?? false
readonly property string _volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026")) readonly property string _volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
readonly property color _volumeColor: muted ? M.Theme.base04 : root.accentColor readonly property color _volumeColor: muted ? S.Theme.base04 : root.accentColor
readonly property var _sinkList: { readonly property var _sinkList: {
const sinks = []; const sinks = [];

View file

@ -1,10 +1,11 @@
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
tooltip: root.weatherTooltip tooltip: root.weatherTooltip
property string weatherTooltip: "" property string weatherTooltip: ""
@ -12,7 +13,7 @@ M.BarSection {
Process { Process {
id: proc id: proc
running: true running: true
command: ["wttrbar"].concat(M.Modules.weather.args) command: ["wttrbar"].concat(S.Modules.weather.args)
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
try { try {
@ -27,7 +28,7 @@ M.BarSection {
} }
} }
Timer { Timer {
interval: M.Modules.weather.interval || 3600000 interval: S.Modules.weather.interval || 3600000
running: true running: true
repeat: true repeat: true
onTriggered: proc.running = true onTriggered: proc.running = true

View file

@ -3,10 +3,11 @@ import QtQuick.Effects
import Quickshell import Quickshell
import Quickshell.Widgets import Quickshell.Widgets
import "." as M import "." as M
import "../services" as S
M.BarSection { M.BarSection {
id: root id: root
spacing: M.Theme.moduleSpacing spacing: S.Theme.moduleSpacing
tooltip: M.NiriIpc.focusedAppId ? M.NiriIpc.focusedAppId + "\n" + M.NiriIpc.focusedTitle : M.NiriIpc.focusedTitle tooltip: M.NiriIpc.focusedAppId ? M.NiriIpc.focusedAppId + "\n" + M.NiriIpc.focusedTitle : M.NiriIpc.focusedTitle
readonly property string _iconSource: { readonly property string _iconSource: {
@ -25,7 +26,7 @@ M.BarSection {
id: _icon id: _icon
visible: root._iconSource !== "" visible: root._iconSource !== ""
source: root._iconSource source: root._iconSource
implicitSize: M.Theme.fontSize + 2 implicitSize: S.Theme.fontSize + 2
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {

View file

@ -2,6 +2,7 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "." as M import "." as M
import "../services" as S
Row { Row {
id: root id: root
@ -70,7 +71,7 @@ Row {
M.FlyoutState.text = name; M.FlyoutState.text = name;
M.FlyoutState.itemX = pill.mapToGlobal(pill.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0); M.FlyoutState.itemX = pill.mapToGlobal(pill.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0);
M.FlyoutState.screen = QsWindow.window?.screen ?? null; M.FlyoutState.screen = QsWindow.window?.screen ?? null;
M.FlyoutState.accentColor = root.parent?.accentColor ?? M.Theme.base05; M.FlyoutState.accentColor = root.parent?.accentColor ?? S.Theme.base05;
M.FlyoutState.visible = true; M.FlyoutState.visible = true;
} else { } else {
M.FlyoutState.visible = false; M.FlyoutState.visible = false;
@ -78,10 +79,10 @@ Row {
} }
} }
width: M.Theme.fontSize + 4 width: S.Theme.fontSize + 4
height: M.Theme.fontSize + 4 height: S.Theme.fontSize + 4
radius: width / 2 radius: width / 2
color: pill.active ? (root.parent?.accentColor ?? M.Theme.base0D) : (pill._hovered ? M.Theme.base03 : M.Theme.base02) color: pill.active ? (root.parent?.accentColor ?? S.Theme.base0D) : (pill._hovered ? S.Theme.base03 : S.Theme.base02)
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: 150 duration: 150
@ -91,9 +92,9 @@ Row {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: pill.modelData.idx text: pill.modelData.idx
color: pill.active ? M.Theme.base00 : (root.parent?.accentColor ?? M.Theme.base05) color: pill.active ? S.Theme.base00 : (root.parent?.accentColor ?? S.Theme.base05)
font.pixelSize: M.Theme.fontSize - 2 font.pixelSize: S.Theme.fontSize - 2
font.family: M.Theme.fontFamily font.family: S.Theme.fontFamily
font.bold: pill.active font.bold: pill.active
} }

View file

@ -1,7 +1,5 @@
module modules module modules
singleton Theme 1.0 Theme.qml
singleton FlyoutState 1.0 FlyoutState.qml singleton FlyoutState 1.0 FlyoutState.qml
singleton Modules 1.0 Modules.qml
Bar 1.0 Bar.qml Bar 1.0 Bar.qml
BarGroup 1.0 BarGroup.qml BarGroup 1.0 BarGroup.qml
BarSection 1.0 BarSection.qml BarSection 1.0 BarSection.qml
@ -34,7 +32,6 @@ IdleInhibitor 1.0 IdleInhibitor.qml
Notifications 1.0 Notifications.qml Notifications 1.0 Notifications.qml
singleton NiriIpc 1.0 NiriIpc.qml singleton NiriIpc 1.0 NiriIpc.qml
singleton PowerProfileService 1.0 PowerProfileService.qml singleton PowerProfileService 1.0 PowerProfileService.qml
singleton SystemStats 1.0 SystemStats.qml
ProcessList 1.0 ProcessList.qml ProcessList 1.0 ProcessList.qml
singleton NotifService 1.0 NotifService.qml singleton NotifService 1.0 NotifService.qml
NotifItem 1.0 NotifItem.qml NotifItem 1.0 NotifItem.qml

4
shell/services/qmldir Normal file
View file

@ -0,0 +1,4 @@
module services
singleton Theme 1.0 Theme.qml
singleton SystemStats 1.0 SystemStats.qml
singleton Modules 1.0 Modules.qml