Compare commits

..
Author SHA1 Message Date
Damocles
c3d7fa0bc5 rename bar module files and qmldir types to *Module 2026-04-17 22:12:16 +02:00
Damocles
6461b9a943 rename *Content.qml to *Applet.qml 2026-04-17 22:08:26 +02:00
Damocles
989182d603 move Theme, SystemStats, Modules to shell/services/ 2026-04-17 22:07:00 +02:00
Damocles
197f6976e0 move content/ up to shell/applets/ 2026-04-17 21:58:48 +02:00
62 changed files with 502 additions and 453 deletions

View file

@ -25,7 +25,7 @@ stdenvNoCC.mkDerivation {
runHook preInstall
mkdir -p $out/share/nova-shell
cp -r shell/shell.qml shell/modules 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
qsb --qt6 \

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

8
shell/applets/qmldir Normal file
View file

@ -0,0 +1,8 @@
module applets
HexWaveBackground 1.0 HexWaveBackground.qml
VolumeApplet 1.0 VolumeApplet.qml
MprisApplet 1.0 MprisApplet.qml
CpuApplet 1.0 CpuApplet.qml
MemoryApplet 1.0 MemoryApplet.qml
TemperatureApplet 1.0 TemperatureApplet.qml
DiskApplet 1.0 DiskApplet.qml

View file

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

View file

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

View file

@ -4,8 +4,8 @@ import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Mpris
import Quickshell.Services.Pipewire
import "../modules" as M
import "../modules/content" as C
import "../services" as M
import "../applets" as C
WlSessionLockSurface {
id: root
@ -179,7 +179,7 @@ WlSessionLockSurface {
readonly property var _mprisPlayer: _mprisPlayers[0] ?? null
readonly property bool _playing: _mprisPlayer?.playbackState === MprisPlaybackState.Playing
C.MprisContent {
C.MprisApplet {
id: _mprisContent
anchors.left: parent.left
anchors.right: parent.right
@ -209,7 +209,7 @@ WlSessionLockSurface {
objects: [Pipewire.defaultAudioSink]
}
C.VolumeContent {
C.VolumeApplet {
id: _volumeContent
anchors.left: parent.left
anchors.right: parent.right

View file

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

View file

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

View file

@ -3,6 +3,7 @@ import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import "." as M
import "../services" as S
PanelWindow {
id: bar
@ -18,13 +19,13 @@ PanelWindow {
right: true
}
implicitHeight: M.Theme.barHeight
implicitHeight: S.Theme.barHeight
exclusiveZone: implicitHeight
Rectangle {
anchors.fill: parent
color: M.Theme.base00
opacity: M.Theme.barOpacity
color: S.Theme.base00
opacity: S.Theme.barOpacity
}
Canvas {
@ -34,7 +35,7 @@ PanelWindow {
const ctx = getContext("2d");
const w = width;
const h = height;
const r = M.Theme.screenRadius;
const r = S.Theme.screenRadius;
const lw = 3;
const hw = lw / 2;
@ -42,8 +43,8 @@ PanelWindow {
// Glow wash behind the border
const glowGrad = ctx.createLinearGradient(0, 0, w, 0);
glowGrad.addColorStop(0, M.Theme.base0C.toString());
glowGrad.addColorStop(1, M.Theme.base09.toString());
glowGrad.addColorStop(0, S.Theme.base0C.toString());
glowGrad.addColorStop(1, S.Theme.base09.toString());
ctx.globalAlpha = 0.25;
ctx.fillStyle = glowGrad;
ctx.fillRect(0, 0, w, h);
@ -60,8 +61,8 @@ PanelWindow {
// Horizontal gradient for the border
const grad = ctx.createLinearGradient(0, 0, w, 0);
grad.addColorStop(0, M.Theme.base0C.toString());
grad.addColorStop(1, M.Theme.base09.toString());
grad.addColorStop(0, S.Theme.base0C.toString());
grad.addColorStop(1, S.Theme.base09.toString());
ctx.strokeStyle = grad;
ctx.lineWidth = lw;
@ -96,25 +97,25 @@ PanelWindow {
Item {
anchors.fill: parent
anchors.topMargin: M.Theme.groupSpacing
anchors.leftMargin: M.Theme.groupSpacing
anchors.rightMargin: M.Theme.groupSpacing
anchors.topMargin: S.Theme.groupSpacing
anchors.leftMargin: S.Theme.groupSpacing
anchors.rightMargin: S.Theme.groupSpacing
// ---- center (declared first so left/right can anchor to it) ----
RowLayout {
id: centerSection
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.groupSpacing
spacing: S.Theme.groupSpacing
M.BarGroup {
M.Privacy {}
M.Clock {
visible: M.Modules.clock.enable
M.PrivacyModule {}
M.ClockModule {
visible: S.Modules.clock.enable
}
M.Notifications {
M.NotificationsModule {
bar: bar
visible: M.Modules.notifications.enable
visible: S.Modules.notifications.enable
}
}
}
@ -124,19 +125,19 @@ PanelWindow {
anchors.left: parent.left
anchors.right: centerSection.left
anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.groupSpacing
spacing: S.Theme.groupSpacing
M.BarGroup {
id: workspacesGroup
leftEdge: true
M.Workspaces {
M.WorkspacesModule {
bar: bar
visible: M.Modules.workspaces.enable
visible: S.Modules.workspaces.enable
}
}
M.BarGroup {
leftEdge: !workspacesGroup.visible
M.Tray {
M.TrayModule {
bar: bar
}
}
@ -144,10 +145,10 @@ PanelWindow {
id: _windowTitleGroup
Layout.minimumWidth: 0
clip: true
visible: M.Modules.windowTitle.enable && M.NiriIpc.focusedTitle !== ""
M.WindowTitle {
visible: S.Modules.windowTitle.enable && M.NiriIpc.focusedTitle !== ""
M.WindowTitleModule {
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)
}
}
@ -161,7 +162,7 @@ PanelWindow {
anchors.left: centerSection.right
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.groupSpacing
spacing: S.Theme.groupSpacing
Item {
Layout.fillWidth: true
@ -169,63 +170,63 @@ PanelWindow {
// Media
M.BarGroup {
M.Mpris {
M.MprisModule {
bar: bar
}
M.Volume {
visible: M.Modules.volume.enable
M.VolumeModule {
visible: S.Modules.volume.enable
}
}
// Connectivity
M.BarGroup {
M.Network {
M.NetworkModule {
bar: bar
visible: M.Modules.network.enable
visible: S.Modules.network.enable
}
M.Bluetooth {
M.BluetoothModule {
bar: bar
}
}
// Controls
M.BarGroup {
M.Backlight {}
M.PowerProfile {
visible: M.Modules.powerProfile.enable
M.BacklightModule {}
M.PowerProfileModule {
visible: S.Modules.powerProfile.enable
}
M.IdleInhibitor {
visible: M.Modules.idleInhibitor.enable
M.IdleInhibitorModule {
visible: S.Modules.idleInhibitor.enable
}
}
// Stats
M.BarGroup {
M.Cpu {
visible: M.Modules.cpu.enable
M.CpuModule {
visible: S.Modules.cpu.enable
}
M.Memory {
visible: M.Modules.memory.enable
M.MemoryModule {
visible: S.Modules.memory.enable
}
M.Gpu {}
M.Temperature {
visible: M.Modules.temperature.enable
M.GpuModule {}
M.TemperatureModule {
visible: S.Modules.temperature.enable
}
M.Weather {
visible: M.Modules.weather.enable
M.WeatherModule {
visible: S.Modules.weather.enable
}
M.Disk {
visible: M.Modules.disk.enable
M.DiskModule {
visible: S.Modules.disk.enable
}
}
// Power
M.BarGroup {
rightEdge: true
M.Battery {}
M.Power {
M.BatteryModule {}
M.PowerModule {
bar: bar
visible: M.Modules.power.enable
visible: S.Modules.power.enable
}
}
}

View file

@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Effects
import Quickshell
import "." as M
import "../services" as S
Item {
id: root
@ -16,21 +17,21 @@ Item {
const gx = mapToGlobal(width / 2, 0).x - scr.x;
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 rightEdge: false
readonly property real _tlr: leftEdge ? M.Theme.screenRadius : M.Theme.radius
readonly property real _trr: rightEdge ? M.Theme.screenRadius : M.Theme.radius
readonly property real _blr: M.Theme.radius
readonly property real _brr: M.Theme.radius
readonly property real _tlr: leftEdge ? S.Theme.screenRadius : S.Theme.radius
readonly property real _trr: rightEdge ? S.Theme.screenRadius : S.Theme.radius
readonly property real _blr: S.Theme.radius
readonly property real _brr: S.Theme.radius
visible: row.visibleChildren.length > 0
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
HoverHandler {
@ -44,7 +45,7 @@ Item {
topRightRadius: root._trr
bottomLeftRadius: root._blr
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
@ -143,7 +144,7 @@ Item {
id: row
property color accentColor: root.borderColor
anchors.centerIn: parent
spacing: M.Theme.moduleSpacing + 2
spacing: S.Theme.moduleSpacing + 2
}
// Separator lines overlaid between visible row children

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,11 +2,12 @@ import QtQuick
import Quickshell
import Quickshell.Io
import "." as M
import "../services" as S
M.BarSection {
id: root
spacing: M.Theme.moduleSpacing
opacity: M.Modules.bluetooth.enable && root.state !== "unavailable" ? 1 : 0
spacing: S.Theme.moduleSpacing
opacity: S.Modules.bluetooth.enable && root.state !== "unavailable" ? 1 : 0
visible: opacity > 0
tooltip: {
if (root.state === "off")
@ -35,7 +36,7 @@ M.BarSection {
Process {
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\""]
stdout: StdioCollector {
onStreamFinished: root._parse(text)
@ -44,7 +45,7 @@ M.BarSection {
// Event-driven: watch BlueZ DBus property changes
Process {
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"]
stdout: SplitParser {
splitMarker: "\n"
@ -58,14 +59,14 @@ M.BarSection {
}
Timer {
interval: 60000
running: M.Modules.bluetooth.enable
running: S.Modules.bluetooth.enable
repeat: true
onTriggered: proc.running = true
}
M.BarIcon {
icon: "\uF294"
color: root.state === "off" ? M.Theme.base04 : root.accentColor
color: root.state === "off" ? S.Theme.base04 : root.accentColor
anchors.verticalCenter: parent.verticalCenter
TapHandler {
cursorShape: Qt.PointingHandCursor

View file

@ -1,6 +1,7 @@
import QtQuick
import Quickshell
import "." as M
import "../services" as S
M.BarLabel {
SystemClock {
@ -8,7 +9,7 @@ M.BarLabel {
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")
tooltip: Qt.formatDateTime(clock.date, "dddd, dd. MMMM yyyy\nHH:mm:ss")
}

View file

@ -1,16 +1,17 @@
import QtQuick
import Quickshell
import "." as M
import "content" as C
import "../services" as S
import "../applets" as C
M.BarSection {
id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2)
spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: ""
readonly property var _cores: M.SystemStats.cpuCores
readonly property var _coreMaxFreq: M.SystemStats.cpuCoreMaxFreq
readonly property var _coreTypes: M.SystemStats.cpuCoreTypes
readonly property var _cores: S.SystemStats.cpuCores
readonly property var _coreMaxFreq: S.SystemStats.cpuCoreMaxFreq
readonly property var _coreTypes: S.SystemStats.cpuCoreTypes
property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
@ -21,10 +22,10 @@ M.BarSection {
on_ShowPanelChanged: {
if (_showPanel && !_coreConsumerActive) {
_coreConsumerActive = true;
M.SystemStats.coreConsumers++;
S.SystemStats.coreConsumers++;
} else if (!_showPanel && _coreConsumerActive) {
_coreConsumerActive = false;
M.SystemStats.coreConsumers--;
S.SystemStats.coreConsumers--;
}
}
@ -56,7 +57,7 @@ M.BarSection {
}
}
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"
anchors.verticalCenter: parent.verticalCenter
TapHandler {
@ -75,7 +76,7 @@ M.BarSection {
panelTitle: "CPU"
contentWidth: 260
C.CpuContent {
C.CpuApplet {
width: hoverPanel.contentWidth
cores: root._cores
coreMaxFreq: root._coreMaxFreq

View file

@ -1,15 +1,16 @@
import QtQuick
import Quickshell
import "." as M
import "content" as C
import "../services" as S
import "../applets" as C
M.BarSection {
id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2)
spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: ""
property var _mounts: M.SystemStats.diskMounts
property int _rootPct: M.SystemStats.diskRootPct
property var _mounts: S.SystemStats.diskMounts
property int _rootPct: S.SystemStats.diskRootPct
property bool _pinned: false
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
@ -56,7 +57,7 @@ M.BarSection {
panelTitle: "Disk"
contentWidth: 260
C.DiskContent {
C.DiskApplet {
width: hoverPanel.contentWidth
mounts: root._mounts
accentColor: root.accentColor

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,12 +3,13 @@ import Quickshell
import Quickshell.Io
import Quickshell.Services.Mpris
import "." as M
import "content" as C
import "../services" as S
import "../applets" as C
M.BarSection {
id: root
spacing: M.Theme.moduleSpacing
opacity: M.Modules.mpris.enable && player !== null ? 1 : 0
spacing: S.Theme.moduleSpacing
opacity: S.Modules.mpris.enable && player !== null ? 1 : 0
visible: opacity > 0
tooltip: ""
@ -123,7 +124,7 @@ M.BarSection {
panelTitle: "Now Playing"
contentWidth: 280
C.MprisContent {
C.MprisApplet {
width: hoverPanel.contentWidth
player: root.player
players: root._players

View file

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

View file

@ -2,10 +2,11 @@ import QtQuick
import Quickshell
import Quickshell.Io
import "." as M
import "../services" as S
M.BarSection {
id: root
spacing: M.Theme.moduleSpacing
spacing: S.Theme.moduleSpacing
tooltip: ""
property string ifname: ""
@ -16,7 +17,7 @@ M.BarSection {
Process {
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:-}\""]
stdout: StdioCollector {
onStreamFinished: {
@ -53,7 +54,7 @@ M.BarSection {
// Event-driven: re-poll on any network change
Process {
id: monitor
running: M.Modules.network.enable
running: S.Modules.network.enable
command: ["nmcli", "monitor"]
stdout: SplitParser {
splitMarker: "\n"
@ -71,7 +72,7 @@ M.BarSection {
// Fallback poll
Timer {
interval: 60000
running: M.Modules.network.enable
running: S.Modules.network.enable
repeat: true
onTriggered: proc.running = true
}
@ -86,13 +87,13 @@ M.BarSection {
return "\uDB85\uDE16";
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
}
M.BarLabel {
visible: root.state === "wifi"
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
}

View file

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

View file

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

View file

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

View file

@ -3,6 +3,7 @@ import Quickshell
import Quickshell.Wayland
import Quickshell.Services.Notifications
import "." as M
import "../services" as S
PanelWindow {
id: root
@ -33,7 +34,7 @@ PanelWindow {
property var _knownIds: ({})
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 {
id: popupItem

View file

@ -4,6 +4,7 @@ import QtQuick
import Quickshell
import Quickshell.Services.Notifications
import "." as M
import "../services" as S
QtObject {
id: root
@ -96,7 +97,7 @@ QtObject {
});
// 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);
if (currentPopups.length > max) {
for (let i = max; i < currentPopups.length; i++)
@ -106,13 +107,13 @@ QtObject {
// Auto-expire popup (skip for critical)
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.running = true;
}
// 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) {
const old = root.list.pop();
old.finishDismiss();

View file

@ -2,10 +2,11 @@ import QtQuick
import Quickshell
import Quickshell.Services.Notifications
import "." as M
import "../services" as S
M.BarSection {
id: root
spacing: M.Theme.moduleSpacing
spacing: S.Theme.moduleSpacing
tooltip: {
const parts = [M.NotifService.count + " notification" + (M.NotifService.count !== 1 ? "s" : "")];
if (M.NotifService.dnd)
@ -23,13 +24,13 @@ M.BarSection {
return M.NotifService.count > 0 ? "\uDB80\uDCA0" : "\uDB82\uDE93";
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
}
M.BarLabel {
id: countLabel
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
transform: Scale {

View file

@ -2,7 +2,8 @@ import QtQuick
import Quickshell
import Quickshell.Wayland
import "." as M
import "content" as C
import "../services" as S
import "../applets" as C
PanelWindow {
id: root

View file

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

View file

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

View file

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

View file

@ -1,11 +1,12 @@
import QtQuick
import "." as M
import "../services" as S
M.BarIcon {
id: root
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: {
if (M.PowerProfileService.profile === "performance")

View file

@ -3,6 +3,7 @@ pragma Singleton
import QtQuick
import Quickshell.Io
import "." as M
import "../services" as S
QtObject {
id: root
@ -11,7 +12,7 @@ QtObject {
readonly property bool powerSaver: profile === "power-saver"
property var _proc: Process {
running: M.Modules.powerProfile.enable
running: S.Modules.powerProfile.enable
command: ["powerprofilesctl", "get"]
stdout: StdioCollector {
onStreamFinished: root.profile = text.trim()
@ -19,7 +20,7 @@ QtObject {
}
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"]
stdout: SplitParser {
splitMarker: "\n"
@ -34,7 +35,7 @@ QtObject {
property var _poll: Timer {
interval: 60000
running: M.Modules.powerProfile.enable
running: S.Modules.powerProfile.enable
repeat: true
onTriggered: root._proc.running = true
}

View file

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

View file

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

View file

@ -1,28 +1,29 @@
import QtQuick
import Quickshell
import "." as M
import "content" as C
import "../services" as S
import "../applets" as C
M.BarSection {
id: root
spacing: Math.max(1, M.Theme.moduleSpacing - 2)
spacing: Math.max(1, S.Theme.moduleSpacing - 2)
tooltip: ""
readonly property int _warm: M.Modules.temperature.warm || 80
readonly property int _hot: M.Modules.temperature.hot || 90
readonly property string _deviceFilter: M.Modules.temperature.device || ""
readonly property int _warm: S.Modules.temperature.warm || 80
readonly property int _hot: S.Modules.temperature.hot || 90
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
readonly property int _temp: {
if (_deviceFilter !== "") {
const dev = M.SystemStats.tempDevices.find(d => d.name === _deviceFilter);
const dev = S.SystemStats.tempDevices.find(d => d.name === _deviceFilter);
if (dev)
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 {
ColorAnimation {
duration: 300
@ -76,13 +77,13 @@ M.BarSection {
panelTitle: "Temperature"
contentWidth: 220
C.TemperatureContent {
C.TemperatureApplet {
width: hoverPanel.contentWidth
temp: root._temp
warm: root._warm
hot: root._hot
history: M.SystemStats.tempHistory
devices: M.SystemStats.tempDevices
history: S.SystemStats.tempHistory
devices: S.SystemStats.tempDevices
accentColor: root.accentColor
deviceFilter: root._deviceFilter
active: root._showPanel

View file

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

View file

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

View file

@ -2,11 +2,12 @@ import QtQuick
import Quickshell
import Quickshell.Services.Pipewire
import "." as M
import "content" as C
import "../services" as S
import "../applets" as C
M.BarSection {
id: root
spacing: M.Theme.moduleSpacing
spacing: S.Theme.moduleSpacing
tooltip: ""
PwObjectTracker {
@ -17,7 +18,7 @@ M.BarSection {
readonly property real volume: sink?.audio?.volume ?? 0
readonly property bool muted: sink?.audio?.muted ?? false
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: {
const sinks = [];
@ -114,7 +115,7 @@ M.BarSection {
panelTitle: "Sound"
contentWidth: 220
C.VolumeContent {
C.VolumeApplet {
width: hoverPanel.contentWidth
sink: root.sink
sinkList: root._sinkList

View file

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

View file

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

View file

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

View file

@ -1,8 +0,0 @@
module content
HexWaveBackground 1.0 HexWaveBackground.qml
VolumeContent 1.0 VolumeContent.qml
MprisContent 1.0 MprisContent.qml
CpuContent 1.0 CpuContent.qml
MemoryContent 1.0 MemoryContent.qml
TemperatureContent 1.0 TemperatureContent.qml
DiskContent 1.0 DiskContent.qml

View file

@ -1,46 +1,47 @@
module modules
singleton Theme 1.0 Theme.qml
singleton FlyoutState 1.0 FlyoutState.qml
singleton Modules 1.0 Modules.qml
Bar 1.0 Bar.qml
BarGroup 1.0 BarGroup.qml
BarSection 1.0 BarSection.qml
Flyout 1.0 Flyout.qml
Workspaces 1.0 Workspaces.qml
WindowTitle 1.0 WindowTitle.qml
Clock 1.0 Clock.qml
Volume 1.0 Volume.qml
Tray 1.0 Tray.qml
WorkspacesModule 1.0 WorkspacesModule.qml
WindowTitleModule 1.0 WindowTitleModule.qml
ClockModule 1.0 ClockModule.qml
VolumeModule 1.0 VolumeModule.qml
TrayModule 1.0 TrayModule.qml
TrayMenu 1.0 TrayMenu.qml
PopupBackground 1.0 PopupBackground.qml
HoverPanel 1.0 HoverPanel.qml
PowerMenu 1.0 PowerMenu.qml
ScreenCorners 1.0 ScreenCorners.qml
ThemedIcon 1.0 ThemedIcon.qml
Battery 1.0 Battery.qml
Mpris 1.0 Mpris.qml
Network 1.0 Network.qml
BatteryModule 1.0 BatteryModule.qml
MprisModule 1.0 MprisModule.qml
NetworkModule 1.0 NetworkModule.qml
NetworkMenu 1.0 NetworkMenu.qml
Bluetooth 1.0 Bluetooth.qml
BluetoothModule 1.0 BluetoothModule.qml
BluetoothMenu 1.0 BluetoothMenu.qml
Backlight 1.0 Backlight.qml
Cpu 1.0 Cpu.qml
Memory 1.0 Memory.qml
Disk 1.0 Disk.qml
Temperature 1.0 Temperature.qml
Weather 1.0 Weather.qml
PowerProfile 1.0 PowerProfile.qml
IdleInhibitor 1.0 IdleInhibitor.qml
Notifications 1.0 Notifications.qml
BacklightModule 1.0 BacklightModule.qml
CpuModule 1.0 CpuModule.qml
MemoryModule 1.0 MemoryModule.qml
DiskModule 1.0 DiskModule.qml
TemperatureModule 1.0 TemperatureModule.qml
WeatherModule 1.0 WeatherModule.qml
PowerProfileModule 1.0 PowerProfileModule.qml
IdleInhibitorModule 1.0 IdleInhibitorModule.qml
NotificationsModule 1.0 NotificationsModule.qml
singleton NiriIpc 1.0 NiriIpc.qml
singleton PowerProfileService 1.0 PowerProfileService.qml
singleton SystemStats 1.0 SystemStats.qml
ProcessList 1.0 ProcessList.qml
singleton NotifService 1.0 NotifService.qml
NotifItem 1.0 NotifItem.qml
NotifPopup 1.0 NotifPopup.qml
NotifCenter 1.0 NotifCenter.qml
Power 1.0 Power.qml
Privacy 1.0 Privacy.qml
NotifCard 1.0 NotifCard.qml
PowerModule 1.0 PowerModule.qml
PrivacyModule 1.0 PrivacyModule.qml
BackgroundOverlay 1.0 BackgroundOverlay.qml
OverviewBackdrop 1.0 OverviewBackdrop.qml
GpuModule 1.0 GpuModule.qml
BarIcon 1.0 BarIcon.qml
BarLabel 1.0 BarLabel.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

View file

@ -1,6 +1,7 @@
//@ pragma Env QS_NO_RELOAD_POPUP=1
import "modules"
import "services"
import "lock" as Lock
import Quickshell