Author SHA1 Message Date
zach 2f6847ce0e Merge branch 'main' into fix/lockscreen-font
C++ / fmt (pull_request) Successful in 3s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 20s
Python / static (pull_request) Successful in 58s
Rust / fmt (pull_request) Successful in 55s
C++ / build (pull_request) Successful in 2m31s
Rust / build (pull_request) Successful in 2m16s
Rust / clippy (pull_request) Successful in 1m33s
Python / verify (pull_request) Successful in 2m53s
C++ / clang-tidy (pull_request) Successful in 4m5s
2026-08-31 00:13:16 +02:00
zach e5e52802de test aur 2026-08-30 23:49:53 +02:00
zach 42f02f4dd2 test aur 2026-08-30 23:33:50 +02:00
zach 9df3a64815 fix: lowercase battery device state 2026-08-30 22:20:39 +02:00
Inorishio 9370284c6b changed old appearance vars for the lockscreen + warning hunting for the polkit
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 14s
JS/TS / lint (pull_request) Successful in 16s
Python / static (pull_request) Successful in 1m14s
Rust / fmt (pull_request) Successful in 1m8s
Rust / build (pull_request) Successful in 2m14s
C++ / build (pull_request) Successful in 2m36s
Rust / clippy (pull_request) Successful in 1m15s
Python / verify (pull_request) Successful in 3m19s
C++ / clang-tidy (pull_request) Successful in 4m1s
2026-08-30 16:35:20 +02:00
zach 5598f4f435 README.md 2026-08-23 17:01:27 +02:00
zach 7e02c87b91 README.md 2026-08-23 17:00:41 +02:00
zach d3e61efd86 Merge pull request 'Feat: Dashboard media widget update + anim tokens restructure' (#151) from feat/dashboard-media-widget into main
Reviewed-on: #151
2026-08-19 11:26:23 +02:00
zach de95b6c8f9 fix rounding tokens
C++ / fmt (pull_request) Successful in 7s
JS/TS / fmt (pull_request) Successful in 12s
JS/TS / lint (pull_request) Successful in 16s
Python / static (pull_request) Successful in 53s
Rust / fmt (pull_request) Successful in 39s
Rust / build (pull_request) Successful in 1m57s
C++ / build (pull_request) Successful in 3m51s
Rust / clippy (pull_request) Successful in 1m39s
Python / verify (pull_request) Successful in 3m4s
C++ / clang-tidy (pull_request) Successful in 5m25s
2026-08-19 00:38:41 +02:00
zach 4ff4afa279 Merge branch 'main' into feat/dashboard-media-widget
C++ / fmt (pull_request) Successful in 4s
JS/TS / fmt (pull_request) Successful in 18s
JS/TS / lint (pull_request) Successful in 17s
Python / static (pull_request) Successful in 58s
Rust / fmt (pull_request) Successful in 1m4s
C++ / build (pull_request) Successful in 2m39s
Rust / build (pull_request) Successful in 2m22s
Rust / clippy (pull_request) Successful in 1m48s
Python / verify (pull_request) Successful in 3m29s
C++ / clang-tidy (pull_request) Successful in 7m7s
2026-08-19 00:36:42 +02:00
zach 8a83181f11 modular quick toggles 2026-08-19 00:34:49 +02:00
11 changed files with 261 additions and 91 deletions
@@ -40,7 +40,7 @@ Item {
anchors.centerIn: parent
sourceComponent: BatteryIcon {
devState: Battery.deviceStateString
devState: Battery.deviceStateString.toLowerCase()
percentage: Battery.currentPerc
}
}
+6 -6
View File
@@ -29,7 +29,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3secondary
font.bold: true
font.family: Appearance.font.family.clock
font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: Time.hourStr
}
@@ -38,7 +38,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3primary
font.bold: true
font.family: Appearance.font.family.clock
font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: ":"
}
@@ -47,7 +47,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignVCenter
color: Colors.palette.m3secondary
font.bold: true
font.family: Appearance.font.family.clock
font.family: Config.appearance.font.family.clock
font.pointSize: Math.floor(Tokens.font.size.extraLarge * 3 * root.centerScale)
text: Time.minuteStr
}
@@ -58,7 +58,7 @@ ColumnLayout {
Layout.topMargin: -Tokens.padding.large * 2
color: Colors.palette.m3tertiary
font.bold: true
font.family: Appearance.font.family.mono
font.family: Config.appearance.font.family.mono
font.pointSize: Math.floor(Tokens.font.size.extraLarge * root.centerScale)
text: Time.format("dddd, d MMMM yyyy")
}
@@ -226,7 +226,7 @@ ColumnLayout {
anchors.right: parent.right
animateProp: "opacity"
color: Colors.palette.m3onSurfaceVariant
font.family: Appearance.font.family.mono
font.family: Config.appearance.font.family.mono
horizontalAlignment: Qt.AlignHCenter
lineHeight: 1.2
opacity: shouldBeVisible && !message.msg ? 1 : 0
@@ -295,7 +295,7 @@ ColumnLayout {
anchors.left: parent.left
anchors.right: parent.right
color: Colors.palette.m3error
font.family: Appearance.font.family.mono
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.small
horizontalAlignment: Qt.AlignHCenter
opacity: 0
+1 -1
View File
@@ -41,7 +41,7 @@ Item {
anchors.centerIn: parent
animate: true
color: root.pam.passwd.active ? Colors.palette.m3secondary : Colors.palette.m3outline
font.family: Appearance.font.family.mono
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.normal
opacity: root.buffer ? 0 : 1
text: {
+2 -2
View File
@@ -24,7 +24,7 @@ ColumnLayout {
Layout.fillWidth: true
color: Colors.palette.m3outline
elide: Text.ElideRight
font.family: Appearance.font.family.mono
font.family: Config.appearance.font.family.mono
font.weight: 500
text: NotifServer.list.length > 0 ? qsTr("%1 notification%2").arg(NotifServer.list.length).arg(NotifServer.list.length === 1 ? "" : "s") : qsTr("Notifications")
}
@@ -66,7 +66,7 @@ ColumnLayout {
CustomText {
Layout.alignment: Qt.AlignHCenter
color: Colors.palette.m3outlineVariant
font.family: Appearance.font.family.mono
font.family: Config.appearance.font.family.mono
font.pointSize: Tokens.font.size.large
font.weight: 500
text: qsTr("No Notifications")
@@ -1,101 +1,184 @@
import Quickshell.Bluetooth
import Quickshell.Networking as QSNetwork
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Networking as QSNetwork
import ZShell.Components
import qs.Components
import ZShell.Config
import qs.Components
import qs.Services
import qs.Helpers
import qs.Daemons
import qs.Services
import qs.Modules.Settings
import qs.Modules.Bar.Popouts as BarPopouts
CustomRect {
id: root
required property Item popouts
required property var visibilities
readonly property bool needExtraRow: quickToggles.length > 6
required property BarPopouts.Wrapper popouts
readonly property var quickToggles: {
const seenIds = new Set();
return Config.utilities.quickToggles.values.filter(item => {
if (!item.enabled)
return false;
if (seenIds.has(item.id)) {
return false;
}
if (item.id === "bluetooth" && !Bluetooth.defaultAdapter)
return false;
if (item.id === "wifi" && !QSNetwork.Networking.devices.values.some(n => n.type === QSNetwork.DeviceType.Wifi))
return false;
seenIds.add(item.id);
return true;
});
}
readonly property int splitIndex: Math.ceil(quickToggles.length / 2)
required property PersistentProperties visibilities
Layout.fillWidth: true
color: Colors.tPalette.m3surfaceContainer
implicitHeight: layout.implicitHeight + 18 * 2
implicitHeight: layout.implicitHeight + Tokens.padding.extraLargeIncreased
radius: Tokens.rounding.small
ButtonRow {
ColumnLayout {
id: layout
anchors.fill: parent
anchors.margins: 18
spacing: Tokens.spacing.extraSmall
anchors.margins: Tokens.padding.large
spacing: Tokens.spacing.medium
Toggle {
checked: Network.wifiEnabled
icon: Network.wifiEnabled ? "wifi" : "wifi_off"
visible: QSNetwork.Networking.devices.values.some(n => n.type === QSNetwork.DeviceType.Wifi)
onClicked: Network.toggleWifi()
CustomText {
font.pointSize: Tokens.font.size.normal
text: qsTr("Quick Toggles")
}
Toggle {
id: toggle
checked: !NotifServer.dnd
icon: NotifServer.dnd ? "notifications_off" : "notifications"
onClicked: NotifServer.dnd = !NotifServer.dnd
QuickToggleRow {
model: root.needExtraRow ? root.quickToggles.slice(0, root.splitIndex) : root.quickToggles
}
Toggle {
checked: !Audio.sourceMuted
icon: Audio.sourceMuted ? "mic_off" : "mic"
onClicked: {
const audio = Audio.source?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
Toggle {
checked: !Audio.muted
icon: Audio.muted ? "volume_off" : "volume_up"
onClicked: {
const audio = Audio.sink?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
Toggle {
checked: Bluetooth.defaultAdapter?.enabled ?? false
icon: Bluetooth.defaultAdapter?.enabled ? "bluetooth" : "bluetooth_disabled"
visible: Bluetooth.defaultAdapter ?? false
onClicked: {
const adapter = Bluetooth.defaultAdapter;
if (adapter)
adapter.enabled = !adapter.enabled;
}
}
Toggle {
checked: GameMode.enabled
icon: GameMode.enabled ? "videogame_asset" : "videogame_asset_off"
onClicked: GameMode.enabled = !GameMode.enabled
QuickToggleRow {
model: root.needExtraRow ? root.quickToggles.slice(root.splitIndex) : []
visible: root.needExtraRow
}
}
CustomShortcut {
name: "toggle-dnd"
component QuickToggleRow: ButtonRow {
property alias model: repeater.model
onPressed: {
toggle.clicked();
Layout.fillWidth: true
spacing: Tokens.spacing.small
Repeater {
id: repeater
delegate: DelegateChooser {
role: "id"
DelegateChoice {
roleValue: "wifi"
delegate: Toggle {
checked: Network.wifiEnabled
icon: checked ? "wifi" : "wifi_off"
onClicked: Network.toggleWifi()
}
}
DelegateChoice {
roleValue: "bluetooth"
delegate: Toggle {
checked: Bluetooth.defaultAdapter?.enabled ?? false // qmllint disable unresolved-type
icon: "bluetooth"
onClicked: {
const adapter = Bluetooth.defaultAdapter; // qmllint disable unresolved-type
if (adapter)
adapter.enabled = !adapter.enabled;
}
}
}
DelegateChoice {
roleValue: "mic"
delegate: Toggle {
checked: !Audio.sourceMuted
icon: checked ? "mic" : "mic_off"
onClicked: {
const audio = Audio.source?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
}
DelegateChoice {
roleValue: "audio"
delegate: Toggle {
checked: !Audio.muted
icon: checked ? "volume_up" : "volume_off"
onClicked: {
const audio = Audio.sink?.audio;
if (audio)
audio.muted = !audio.muted;
}
}
}
DelegateChoice {
roleValue: "gameMode"
delegate: Toggle {
checked: GameMode.enabled
icon: "gamepad"
onClicked: GameMode.enabled = !GameMode.enabled
}
}
DelegateChoice {
roleValue: "dnd"
delegate: Toggle {
checked: NotifServer.dnd
icon: "notifications_off"
onClicked: NotifServer.dnd = !NotifServer.dnd
}
}
DelegateChoice {
roleValue: "settings"
delegate: Toggle {
icon: "settings"
inactiveOnColor: Colors.palette.m3onSurfaceVariant
isToggle: false
onClicked: {
root.visibilities.sidebar = false;
root.visibilities.settings = true;
}
}
}
}
}
}
component Toggle: IconButton {
fillWidth: true
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 2)
isRound: true
isToggle: true
shapeMorph: true
@@ -1,13 +1,14 @@
import Quickshell
import QtQuick
import QtQuick.Layouts
import qs.Modules.Bar.Popouts as BarPopouts
import qs.Modules.Notifications.Sidebar.Utils.Cards
import ZShell.Config
Item {
id: root
required property Item popouts
required property BarPopouts.Wrapper popouts
required property PersistentProperties props
required property var visibilities
@@ -30,6 +31,7 @@ Item {
}
Toggles {
Layout.fillWidth: true
popouts: root.popouts
visibilities: root.visibilities
}
@@ -1,15 +1,16 @@
pragma ComponentBehavior: Bound
import qs.Components
import ZShell.Config
import Quickshell
import QtQuick
import Quickshell
import ZShell.Config
import qs.Components
import qs.Modules.Bar.Popouts as BarPopouts
Item {
id: root
property real offsetScale: shouldBeActive ? 0 : 1
required property Item popouts
required property BarPopouts.Wrapper popouts
readonly property PersistentProperties props: PersistentProperties {
property string recordingConfirmDelete
property bool recordingListExpanded: false
+2 -2
View File
@@ -130,7 +130,7 @@ Scope {
Layout.preferredWidth: Math.min(600, contentWidth)
font.bold: true
font.pointSize: 16
text: polkitAgent.flow?.message
text: polkitAgent.flow?.message ?? ""
wrapMode: Text.WordWrap
}
@@ -168,7 +168,7 @@ Scope {
id: showPassCheckbox
Layout.alignment: Qt.AlignLeft
checked: polkitAgent.flow?.responseVisible
checked: polkitAgent.flow?.responseVisible ?? false
text: "Show Password"
onCheckedChanged: {
@@ -9,6 +9,16 @@ import qs.Modules.Settings.Common
PageBase {
id: root
readonly property var builtinIcons: ({
audio: qsTr("Toggle audio"),
mic: qsTr("Toggle microphone"),
settings: qsTr("Open settings"),
dnd: qsTr("Toggle Do-Not-Disturb"),
gameMode: qsTr("Toggle game mode"),
bluetooth: qsTr("Toggle bluetooth"),
wifi: qsTr("Toggle Wi-Fi")
})
isSubPage: true
title: qsTr("Sidebar")
@@ -44,5 +54,59 @@ PageBase {
onMoved: v => Config.sidebar.dragThreshold = v
}
SectionHeader {
text: qsTr("Quick toggles")
}
ListEditor {
function labelFor(item: var): string {
const prettyName = root.builtinIcons[item.id];
if (prettyName)
return prettyName;
const label = item.id.replace(/([A-Z])/g, " $1");
return label.charAt(0).toUpperCase() + label.slice(1).toLowerCase();
}
function toggledFor(item: var): bool {
return item.enabled;
}
first: true
values: Config.utilities.quickToggles.values
z: 1
onItemMoved: (from, to) => Config.utilities.quickToggles.move(from, to)
onItemRemoved: index => Config.utilities.quickToggles.remove(index)
onItemToggled: (index, checked) => Config.utilities.quickToggles.at(index).enabled = checked
}
DialogSelectButton {
id: addItemContainer
acceptLabel: qsTr("Add")
enabled: Object.keys(model).length > 0
header: qsTr("Add new entry")
icon: "add"
label: qsTr("Add entry")
model: {
const present = new Set(Config.utilities.quickToggles.values.map(item => item.id));
return Object.keys(root.builtinIcons).filter(id => !present.has(id)).map(id => ({
id: id,
label: root.builtinIcons[id]
}));
}
rootParent: root.flickable
onAccepted: {
if (!selectedItem)
return;
Config.utilities.quickToggles.insert({
id: selectedItem,
enabled: true
});
}
}
}
}
+13
View File
@@ -1,5 +1,8 @@
#pragma once
#include "configobject.hpp"
#include "configlist.hpp"
#include <QVariantList>
#include <QStringList>
#include <qqmlintegration.h>
@@ -58,6 +61,16 @@ class Utilities : public ConfigObject {
CONFIG_SUBOBJECT(UtilitiesSizes, sizes)
CONFIG_SUBOBJECT(Toasts, toasts)
CONFIG_SUBOBJECT(Vpn, vpn)
CONFIG_LIST(
EntryList,
quickToggles,
{LIST_ENTRY(dnd, true),
LIST_ENTRY(wifi, true),
LIST_ENTRY(settings, true),
LIST_ENTRY(bluetooth, true),
LIST_ENTRY(mic, true),
LIST_ENTRY(audio, true),
LIST_ENTRY(gameMode, true)})
public:
explicit Utilities(QObject* parent = nullptr)
+13 -6
View File
@@ -15,7 +15,6 @@ It includes a configurable top bar, launcher, notifications daemon + sidebar, wa
## Highlights
- Multi-window shell layout driven by `Drawers/Windows.qml` and panel/interactions wrappers
- Configurable bar entries and popouts (audio, tray, network, power, resources, clock, active window)
- Launcher with app DB frequency tracking, action commands, fuzzy search modes, and wallpaper/scheme flows
- Notification server with persistence (`~/.local/state/zshell/notifs.json`) and sidebar UI
- Dynamic Material 3 palette generation from wallpaper, optional template rendering, terminal sequence application
@@ -47,16 +46,25 @@ Core requirements:
- Hyprland (Wayland session integration)
- Python 3 for scheme/wallpaper tooling
Make sure to have the newest Quickshell version! As of writing, version `0.2.0.r136.gfb08ece-1`.
Here's a list of package dependencies, names are from arch-packages so they
might differ slightly depending on your distro.
```
python python-pillow python-materialyoucolor libnotify cava
app2unit wl-clipboard dconf cliphist python-typer qt6-canvaspainter
python-build python-installer python-hatch python-hatch-vcs cmake ninja
```
Make sure to have the newest Quickshell version! As of writing, version `0.3.1.r1.g0fed22a-1`.
Used by major features (install as needed for your setup):
- `app2unit` (launcher app execution)
- `nmcli` (network integration)
- `brightnessctl`, `ddcutil` (brightness controls)
- `wl-copy`, `swappy` (picker/screenshot flow)
- `libqalculate` (launcher calculator)
- `wl-copy` (clipboard integration)
- `PipeWire` + audio stack + `aubio`/`cava` paths for media visualization
- `libqalculate` (launcher calculator)
- `gsettings` (optional GTK dark/light mode sync)
## Build and Install
@@ -180,7 +188,7 @@ Important state/cache files:
- `~/.local/state/zshell/apps.sqlite`
- `~/.cache/zshell/`
Config is hot-reloaded and saved through `Config/Config.qml` serializers. Top-level sections include:
Config is hot-reloaded and saved through the `Config` singleton. Top-level sections include:
- `general`
- `appearance`
@@ -265,7 +273,6 @@ Note: Template rendering (Jinja2) applies generated colors to `~/.config/zshell/
### `screenshot` — area picker
- `start` — open interactive area picker
- `start-freeze` — freeze screen then pick
### `wallpaper` — wallpaper management