From 53ff6cc21a29a215202ab7e638f9a3eeb116bbf7 Mon Sep 17 00:00:00 2001
From: "M.Silva"
Date: Sun, 7 Sep 2025 18:48:50 +0100
Subject: [PATCH 001/118] fix: message when no items on clipboard
---
Modules/Launcher/Plugins/ClipboardPlugin.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/Launcher/Plugins/ClipboardPlugin.qml b/Modules/Launcher/Plugins/ClipboardPlugin.qml
index a196c13..60a4348 100644
--- a/Modules/Launcher/Plugins/ClipboardPlugin.qml
+++ b/Modules/Launcher/Plugins/ClipboardPlugin.qml
@@ -136,7 +136,7 @@ Item {
const items = ClipboardService.items || []
// If no items and we haven't tried loading yet, trigger a load
- if (items.length === 0 && !ClipboardService.loading) {
+ if (items.count === 0 && !ClipboardService.loading) {
isWaitingForData = true
ClipboardService.list(100)
return [{
From b43b065cf2f62394b731f1b6c03eebf01d156587 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 07:51:01 -0400
Subject: [PATCH 002/118] Wallpaper: minor optimizations/simplification
---
Commons/Settings.qml | 3 +--
Modules/Background/Background.qml | 11 +----------
Services/WallpaperService.qml | 6 +-----
3 files changed, 3 insertions(+), 17 deletions(-)
diff --git a/Commons/Settings.qml b/Commons/Settings.qml
index 3072636..c6dbe3c 100644
--- a/Commons/Settings.qml
+++ b/Commons/Settings.qml
@@ -23,9 +23,9 @@ Singleton {
property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json")
property string defaultAvatar: Quickshell.env("HOME") + "/.face"
- property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers"
property string defaultVideosDirectory: Quickshell.env("HOME") + "/Videos"
property string defaultLocation: "Tokyo"
+ property string defaultWallpapersDirectory: Quickshell.env("HOME") + "/Pictures/Wallpapers"
property string defaultWallpaper: Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png"
// Used to access via Settings.data.xxx.yyy
@@ -335,7 +335,6 @@ Singleton {
property int transitionDuration: 1500 // 1500 ms
property string transitionType: "random"
property real transitionEdgeSmoothness: 0.05
- property string defaultWallpaper: root.defaultWallpaper
property list monitors: []
}
diff --git a/Modules/Background/Background.qml b/Modules/Background/Background.qml
index 3730838..bf0ede5 100644
--- a/Modules/Background/Background.qml
+++ b/Modules/Background/Background.qml
@@ -22,8 +22,6 @@ Variants {
// Internal state management
property string transitionType: "fade"
property real transitionProgress: 0
- // Scaling support for widgets that rely on it
- property real scaling: ScalingService.getScreenScale(screen)
readonly property real edgeSmoothness: Settings.data.wallpaper.transitionEdgeSmoothness
readonly property var allTransitions: WallpaperService.allTransitions
@@ -91,14 +89,7 @@ Variants {
left: true
}
- Connections {
- target: ScalingService
- function onScaleChanged(screenName, scale) {
- if ((screen !== null) && (screenName === screen.name)) {
- scaling = scale
- }
- }
- }
+
Timer {
id: debounceTimer
diff --git a/Services/WallpaperService.qml b/Services/WallpaperService.qml
index 311bdae..c1eba0a 100644
--- a/Services/WallpaperService.qml
+++ b/Services/WallpaperService.qml
@@ -216,11 +216,7 @@ Singleton {
// -------------------------------------------------------------------
// Get specific monitor wallpaper - now from cache
function getWallpaper(screenName) {
- var path = currentWallpapers[screenName] || ""
- if (path === "") {
- return Settings.data.wallpaper.defaultWallpaper || ""
- }
- return path
+ return currentWallpapers[screenName] || Settings.defaultWallpaper
}
// -------------------------------------------------------------------
From 3271fa1d23710c8a45cea3ebdc54c88f1e96b081 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 08:39:56 -0400
Subject: [PATCH 003/118] Init: better widget upgrading process + less warnings
when starting up without config or cache
---
Commons/Color.qml | 5 ++--
Commons/Settings.qml | 49 ++++++++++++++++---------------
Modules/Background/Background.qml | 2 --
Services/LocationService.qml | 1 +
Services/NetworkService.qml | 1 +
Services/NotificationService.qml | 1 +
6 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/Commons/Color.qml b/Commons/Color.qml
index 7abc21f..7d1dc68 100644
--- a/Commons/Color.qml
+++ b/Commons/Color.qml
@@ -102,7 +102,8 @@ Singleton {
// FileView to load custom colors data from colors.json
FileView {
id: customColorsFile
- path: Settings.directoriesCreated ? (Settings.configDir + "colors.json") : ""
+ path: Settings.directoriesCreated ? (Settings.configDir + "colors.json") : undefined
+ printErrors: false
watchChanges: true
onFileChanged: {
Logger.log("Color", "Reloading colors from disk")
@@ -115,7 +116,7 @@ Singleton {
// Trigger initial load when path changes from empty to actual path
onPathChanged: {
- if (path === Settings.configDir + "colors.json") {
+ if (path !== undefined) {
reload()
}
}
diff --git a/Commons/Settings.qml b/Commons/Settings.qml
index c6dbe3c..ba90c45 100644
--- a/Commons/Settings.qml
+++ b/Commons/Settings.qml
@@ -105,22 +105,19 @@ Singleton {
continue
}
- // Check that the widget was not previously migrated and skip if necessary
- const keys = Object.keys(widget)
- if (keys.length > 1) {
- continue
+ if (upgradeWidget(widget)) {
+ Logger.log("Settings", `Upgraded ${widget.id} widget:`, JSON.stringify(widget))
}
-
- migrateWidget(widget)
- Logger.log("Settings", JSON.stringify(widget))
}
}
}
// -----------------------------------------------------
- function migrateWidget(widget) {
- Logger.log("Settings", `Migrating '${widget.id}' widget`)
+ function upgradeWidget(widget) {
+ // Backup the widget definition before altering
+ const widgetBefore = JSON.stringify(widget)
+ // Migrate old bar settings to proper per widget settings
switch (widget.id) {
case "ActiveWindow":
widget.showIcon = adapter.bar.showActiveWindowIcon
@@ -128,23 +125,14 @@ Singleton {
case "Battery":
widget.alwaysShowPercentage = adapter.bar.alwaysShowBatteryPercentage
break
- case "Brightness":
- widget.alwaysShowPercentage = BarWidgetRegistry.widgetMetadata[widget.id].alwaysShowPercentage
- break
case "Clock":
widget.showDate = adapter.location.showDateWithClock
widget.use12HourClock = adapter.location.use12HourClock
widget.reverseDayMonth = adapter.location.reverseDayMonth
- widget.showSeconds = BarWidgetRegistry.widgetMetadata[widget.id].showSeconds
break
case "MediaMini":
widget.showAlbumArt = adapter.audio.showMiniplayerAlbumArt
widget.showVisualizer = adapter.audio.showMiniplayerCava
- widget.visualizerType = BarWidgetRegistry.widgetMetadata[widget.id].visualizerType
- break
- case "NotificationHistory":
- widget.showUnreadBadge = BarWidgetRegistry.widgetMetadata[widget.id].showUnreadBadge
- widget.hideWhenZero = BarWidgetRegistry.widgetMetadata[widget.id].hideWhenZero
break
case "SidePanelToggle":
widget.useDistroLogo = adapter.bar.useDistroLogo
@@ -152,13 +140,27 @@ Singleton {
case "SystemMonitor":
widget.showNetworkStats = adapter.bar.showNetworkStats
break
- case "Volume":
- widget.alwaysShowPercentage = BarWidgetRegistry.widgetMetadata[widget.id].alwaysShowPercentage
- break
case "Workspace":
widget.labelMode = adapter.bar.showWorkspaceLabel
break
}
+
+ // Inject missing default setting (metaData) from BarWidgetRegistry
+ const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id])
+ for (let i=0; i
Date: Mon, 8 Sep 2025 08:59:30 -0400
Subject: [PATCH 004/118] Settings: fixed faulty widget upgrade
---
Commons/Settings.qml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Commons/Settings.qml b/Commons/Settings.qml
index ba90c45..23e1b3d 100644
--- a/Commons/Settings.qml
+++ b/Commons/Settings.qml
@@ -105,9 +105,9 @@ Singleton {
continue
}
- if (upgradeWidget(widget)) {
- Logger.log("Settings", `Upgraded ${widget.id} widget:`, JSON.stringify(widget))
- }
+ // if (upgradeWidget(widget)) {
+ // Logger.log("Settings", `Upgraded ${widget.id} widget:`, JSON.stringify(widget))
+ // }
}
}
}
@@ -153,7 +153,7 @@ Singleton {
continue
}
- if (!widget.hasOwnProperty(k)) {
+ if (widget[k] === undefined) {
widget[k] = BarWidgetRegistry.widgetMetadata[widget.id][k]
}
}
From 33c6ade8f8e9afe95047720460373860f6276fdc Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 09:01:27 -0400
Subject: [PATCH 005/118] Cava: runs only when MediaService is playing
---
Services/CavaService.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Services/CavaService.qml b/Services/CavaService.qml
index 12f39e7..d31d3e9 100644
--- a/Services/CavaService.qml
+++ b/Services/CavaService.qml
@@ -37,7 +37,7 @@ Singleton {
Process {
id: process
stdinEnabled: true
- running: true
+ running: MediaService.isPlaying
command: ["cava", "-p", "/dev/stdin"]
onExited: {
stdinEnabled = true
From d05255c15b1486dc7f931cf35504f55a1317f777 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Mon, 8 Sep 2025 15:38:29 +0200
Subject: [PATCH 006/118] Notification: show resolved app name instead of id
(possibly fixes #230)
---
Commons/Settings.qml | 2 +-
Services/NotificationService.qml | 42 ++++++++++++++++++++++++++++++--
2 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/Commons/Settings.qml b/Commons/Settings.qml
index 23e1b3d..8c0bd48 100644
--- a/Commons/Settings.qml
+++ b/Commons/Settings.qml
@@ -147,7 +147,7 @@ Singleton {
// Inject missing default setting (metaData) from BarWidgetRegistry
const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id])
- for (let i=0; i 0) {
+ const entry = desktopEntries[0]
+ // Prefer name over genericName, fallback to original appName
+ return entry.name || entry.genericName || appName
+ }
+
+ // If no desktop entry found, try to clean up the app ID
+ // Convert "org.gnome.Nautilus" to "Nautilus"
+ const parts = appName.split(".")
+ if (parts.length > 1) {
+ // Take the last part and capitalize it
+ const lastPart = parts[parts.length - 1]
+ return lastPart.charAt(0).toUpperCase() + lastPart.slice(1)
+ }
+
+ return appName
+ } catch (e) {
+ // Fallback to original app name on any error
+ return notification.appName || ""
+ }
+ }
+
// Function to add notification to model
function addNotification(notification) {
const resolvedImage = resolveNotificationImage(notification)
+ const resolvedAppName = resolveAppName(notification)
+
notificationModel.insert(0, {
"rawNotification": notification,
"summary": notification.summary,
"body": notification.body,
- "appName": notification.appName,
+ "appName": resolvedAppName,
"image": resolvedImage,
"appIcon": notification.appIcon,
"urgency": notification.urgency,
@@ -177,10 +213,12 @@ Singleton {
// Add a simplified copy into persistent history
function addToHistory(notification) {
+ const resolvedAppName = resolveAppName(notification)
+
historyModel.insert(0, {
"summary": notification.summary,
"body": notification.body,
- "appName": notification.appName,
+ "appName": resolvedAppName,
"urgency": notification.urgency,
"timestamp": new Date()
})
From 6c93b1b768e213a336c8cb97fcd7b6888cb52509 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 10:32:26 -0400
Subject: [PATCH 007/118] Settings: Fix widget settings upgrade on startup, to
never overwrite an existing setting with default value.
---
Commons/Settings.qml | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/Commons/Settings.qml b/Commons/Settings.qml
index 8c0bd48..6275b08 100644
--- a/Commons/Settings.qml
+++ b/Commons/Settings.qml
@@ -105,9 +105,9 @@ Singleton {
continue
}
- // if (upgradeWidget(widget)) {
- // Logger.log("Settings", `Upgraded ${widget.id} widget:`, JSON.stringify(widget))
- // }
+ if (upgradeWidget(widget)) {
+ Logger.log("Settings", `Upgraded ${widget.id} widget:`, JSON.stringify(widget))
+ }
}
}
}
@@ -120,28 +120,28 @@ Singleton {
// Migrate old bar settings to proper per widget settings
switch (widget.id) {
case "ActiveWindow":
- widget.showIcon = adapter.bar.showActiveWindowIcon
+ widget.showIcon = widget.showIcon !== undefined ? widget.showIcon : adapter.bar.showActiveWindowIcon
break
case "Battery":
- widget.alwaysShowPercentage = adapter.bar.alwaysShowBatteryPercentage
+ widget.alwaysShowPercentage = widget.alwaysShowPercentage!== undefined ? widget.alwaysShowPercentage : adapter.bar.alwaysShowBatteryPercentage
break
case "Clock":
- widget.showDate = adapter.location.showDateWithClock
- widget.use12HourClock = adapter.location.use12HourClock
- widget.reverseDayMonth = adapter.location.reverseDayMonth
+ widget.showDate = widget.showDate !== undefined ? widget.showDate : adapter.location.showDateWithClock
+ widget.use12HourClock = widget.use12HourClock !== undefined ? widget.use12HourClock : adapter.location.use12HourClock
+ widget.reverseDayMonth = widget.reverseDayMonth !== undefined ? widget.reverseDayMonth : adapter.location.reverseDayMonth
break
case "MediaMini":
- widget.showAlbumArt = adapter.audio.showMiniplayerAlbumArt
- widget.showVisualizer = adapter.audio.showMiniplayerCava
+ widget.showAlbumArt = widget.showAlbumArt !== undefined ? widget.showAlbumArt : adapter.audio.showMiniplayerAlbumArt
+ widget.showVisualizer = widget.showVisualizer !== undefined ? widget.showVisualizer : adapter.audio.showMiniplayerCava
break
case "SidePanelToggle":
- widget.useDistroLogo = adapter.bar.useDistroLogo
+ widget.useDistroLogo = widget.useDistroLogo !== undefined ? widget.useDistroLogo : adapter.bar.useDistroLogo
break
case "SystemMonitor":
- widget.showNetworkStats = adapter.bar.showNetworkStats
+ widget.showNetworkStats = widget.showNetworkStats !== undefined ? widget.showNetworkStats : adapter.bar.showNetworkStats
break
case "Workspace":
- widget.labelMode = adapter.bar.showWorkspaceLabel
+ widget.labelMode = widget.labelMode !== undefined ? widget.labelMode : adapter.bar.showWorkspaceLabel
break
}
From b639c3632d61a1b8490f4e4f19811f445e9ca2e8 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 11:51:32 -0400
Subject: [PATCH 008/118] autoformatting
---
Commons/Settings.qml | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/Commons/Settings.qml b/Commons/Settings.qml
index 6275b08..9e977ec 100644
--- a/Commons/Settings.qml
+++ b/Commons/Settings.qml
@@ -123,11 +123,12 @@ Singleton {
widget.showIcon = widget.showIcon !== undefined ? widget.showIcon : adapter.bar.showActiveWindowIcon
break
case "Battery":
- widget.alwaysShowPercentage = widget.alwaysShowPercentage!== undefined ? widget.alwaysShowPercentage : adapter.bar.alwaysShowBatteryPercentage
+ widget.alwaysShowPercentage = widget.alwaysShowPercentage
+ !== undefined ? widget.alwaysShowPercentage : adapter.bar.alwaysShowBatteryPercentage
break
case "Clock":
widget.showDate = widget.showDate !== undefined ? widget.showDate : adapter.location.showDateWithClock
- widget.use12HourClock = widget.use12HourClock !== undefined ? widget.use12HourClock : adapter.location.use12HourClock
+ widget.use12HourClock = widget.use12HourClock !== undefined ? widget.use12HourClock : adapter.location.use12HourClock
widget.reverseDayMonth = widget.reverseDayMonth !== undefined ? widget.reverseDayMonth : adapter.location.reverseDayMonth
break
case "MediaMini":
@@ -141,7 +142,7 @@ Singleton {
widget.showNetworkStats = widget.showNetworkStats !== undefined ? widget.showNetworkStats : adapter.bar.showNetworkStats
break
case "Workspace":
- widget.labelMode = widget.labelMode !== undefined ? widget.labelMode : adapter.bar.showWorkspaceLabel
+ widget.labelMode = widget.labelMode !== undefined ? widget.labelMode : adapter.bar.showWorkspaceLabel
break
}
From 1c0c4e955ae87a3150089f4bf0dafb25b9546fc4 Mon Sep 17 00:00:00 2001
From: Kainoa Kanter
Date: Mon, 8 Sep 2025 09:22:21 -0700
Subject: [PATCH 009/118] divide instead of multiply animation speed
---
Commons/Style.qml | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Commons/Style.qml b/Commons/Style.qml
index a3a7d0f..61f243c 100644
--- a/Commons/Style.qml
+++ b/Commons/Style.qml
@@ -57,10 +57,10 @@ Singleton {
property real opacityFull: 1.0
// Animation duration (ms)
- property int animationFast: Math.round(150 * Settings.data.general.animationSpeed)
- property int animationNormal: Math.round(300 * Settings.data.general.animationSpeed)
- property int animationSlow: Math.round(450 * Settings.data.general.animationSpeed)
- property int animationSlowest: Math.round(750 * Settings.data.general.animationSpeed)
+ property int animationFast: Math.round(150 / Settings.data.general.animationSpeed)
+ property int animationNormal: Math.round(300 / Settings.data.general.animationSpeed)
+ property int animationSlow: Math.round(450 / Settings.data.general.animationSpeed)
+ property int animationSlowest: Math.round(750 / Settings.data.general.animationSpeed)
// Dimensions
property int barHeight: 36
From ed78b6b3f5b270e66b8ecd1e8209cbbeb9ca3d76 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 12:35:29 -0400
Subject: [PATCH 010/118] Basic bootstrap icons test
---
Modules/Bar/Widgets/SidePanelToggle.qml | 2 +-
Services/FontService.qml | 11 +++++++++++
Services/LocationService.qml | 18 +++++++++---------
Widgets/NIcon.qml | 2 +-
4 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml
index 14a8c6f..9680f8b 100644
--- a/Modules/Bar/Widgets/SidePanelToggle.qml
+++ b/Modules/Bar/Widgets/SidePanelToggle.qml
@@ -33,7 +33,7 @@ NIconButton {
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo
!== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
- icon: useDistroLogo ? "" : "widgets"
+ icon: useDistroLogo ? "" : "\ue30d"
tooltipText: "Open side panel."
sizeRatio: 0.8
diff --git a/Services/FontService.qml b/Services/FontService.qml
index a030452..0fa57a2 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -13,6 +13,17 @@ Singleton {
property ListModel displayFonts: ListModel {}
property bool fontsLoaded: false
+ property var icons: {
+ "sunny": "\ue30d",
+ "partly_cloudy": "\ue302",
+ "cloud": "\ue312",
+ "foggy": "\ue311",
+ "rainy": "\ue318"
+ }
+
+
+ // -------------------------------------------
+
function init() {
Logger.log("Font", "Service started")
loadSystemFonts()
diff --git a/Services/LocationService.qml b/Services/LocationService.qml
index fef295c..117c414 100644
--- a/Services/LocationService.qml
+++ b/Services/LocationService.qml
@@ -231,22 +231,22 @@ Singleton {
// --------------------------------
function weatherSymbolFromCode(code) {
if (code === 0)
- return "sunny"
+ return FontService.icons["sunny"]
if (code === 1 || code === 2)
- return "partly_cloudy_day"
+ return FontService.icons["partly_cloudy"]
if (code === 3)
- return "cloud"
+ return FontService.icons["cloud"]
if (code >= 45 && code <= 48)
- return "foggy"
+ return FontService.icons["foggy"]
if (code >= 51 && code <= 67)
- return "rainy"
+ return FontService.icons["rainy"]
if (code >= 71 && code <= 77)
- return "weather_snowy"
+ return FontService.icons["weather_snowy"]
if (code >= 80 && code <= 82)
- return "rainy"
+ return FontService.icons["rainy"]
if (code >= 95 && code <= 99)
- return "thunderstorm"
- return "cloud"
+ return FontService.icons["thunderstorm"]
+ return FontService.icons["cloud"]
}
// --------------------------------
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index ac5a0ec..9ee76ad 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -7,7 +7,7 @@ Text {
// Optional layout nudge for optical alignment when used inside Layouts
property real layoutTopMargin: 0
text: "question_mark"
- font.family: "Material Symbols Rounded"
+ font.family: "bootstrap-icons"
font.pointSize: Style.fontSizeL * scaling
font.variableAxes: {
"wght"// slightly bold to ensure all lines looks good
From 736979c4dc21c991000fff65598eeeb0ee6c6002 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 13:25:03 -0400
Subject: [PATCH 011/118] more icons
---
Modules/SidePanel/Cards/ProfileCard.qml | 6 +++---
Services/FontService.qml | 9 ++++++++-
Services/LocationService.qml | 2 +-
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/Modules/SidePanel/Cards/ProfileCard.qml b/Modules/SidePanel/Cards/ProfileCard.qml
index 4c2d1ce..675d67b 100644
--- a/Modules/SidePanel/Cards/ProfileCard.qml
+++ b/Modules/SidePanel/Cards/ProfileCard.qml
@@ -58,7 +58,7 @@ NBox {
Layout.fillWidth: true
}
NIconButton {
- icon: "settings"
+ icon: FontService.icons["gear"]
tooltipText: "Open settings."
onClicked: {
settingsPanel.requestedTab = SettingsPanel.Tab.General
@@ -68,7 +68,7 @@ NBox {
NIconButton {
id: powerButton
- icon: "power_settings_new"
+ icon: FontService.icons["power"]
tooltipText: "Power menu."
onClicked: {
powerPanel.open(screen)
@@ -78,7 +78,7 @@ NBox {
NIconButton {
id: closeButton
- icon: "close"
+ icon: FontService.icons["close"]
tooltipText: "Close side panel."
onClicked: {
sidePanel.close()
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 0fa57a2..1076ae5 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -14,11 +14,18 @@ Singleton {
property bool fontsLoaded: false
property var icons: {
+ // weather
"sunny": "\ue30d",
"partly_cloudy": "\ue302",
"cloud": "\ue312",
"foggy": "\ue311",
- "rainy": "\ue318"
+ "rainy": "\ue318",
+ "snowy": "\ue319",
+ "thunderstom": "\ue31d",
+
+ "power": "\uf011",
+ "gear": "\uf013",
+ "close": "\uf00D"
}
diff --git a/Services/LocationService.qml b/Services/LocationService.qml
index 117c414..935ab04 100644
--- a/Services/LocationService.qml
+++ b/Services/LocationService.qml
@@ -241,7 +241,7 @@ Singleton {
if (code >= 51 && code <= 67)
return FontService.icons["rainy"]
if (code >= 71 && code <= 77)
- return FontService.icons["weather_snowy"]
+ return FontService.icons["snowy"]
if (code >= 80 && code <= 82)
return FontService.icons["rainy"]
if (code >= 95 && code <= 99)
From 242ae17d0afca9604f93bb58e312d3df3328f8c5 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 13:29:17 -0400
Subject: [PATCH 012/118] panel icon
---
Modules/Bar/Widgets/SidePanelToggle.qml | 2 +-
Services/FontService.qml | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml
index 9680f8b..39cc752 100644
--- a/Modules/Bar/Widgets/SidePanelToggle.qml
+++ b/Modules/Bar/Widgets/SidePanelToggle.qml
@@ -33,7 +33,7 @@ NIconButton {
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo
!== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
- icon: useDistroLogo ? "" : "\ue30d"
+ icon: useDistroLogo ? "" : FontService.icons["panel"]
tooltipText: "Open side panel."
sizeRatio: 0.8
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 1076ae5..db1db91 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -25,7 +25,9 @@ Singleton {
"power": "\uf011",
"gear": "\uf013",
- "close": "\uf00D"
+ "close": "\uf00D",
+ "check": "\uf00C",
+ "panel": "\uF00B"
}
From 6f4a4bb764649bdcc4a399bda14cdd0fb7bcaa1b Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 13:55:48 -0400
Subject: [PATCH 013/118] volume icons
---
Modules/Bar/Widgets/NotificationHistory.qml | 2 +-
Modules/Bar/Widgets/Volume.qml | 4 ++--
Modules/SidePanel/Cards/PowerProfilesCard.qml | 6 ++---
Modules/SidePanel/Cards/UtilitiesCard.qml | 6 ++---
Services/FontService.qml | 23 +++++++++++++------
5 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml
index 31657f1..2bb92cf 100644
--- a/Modules/Bar/Widgets/NotificationHistory.qml
+++ b/Modules/Bar/Widgets/NotificationHistory.qml
@@ -53,7 +53,7 @@ NIconButton {
}
sizeRatio: 0.8
- icon: Settings.data.notifications.doNotDisturb ? "notifications_off" : "notifications"
+ icon: Settings.data.notifications.doNotDisturb ? FontService.icons["bell_striked"] : FontService.icons["bell"]
tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'."
colorBg: Color.mSurfaceVariant
colorFg: Settings.data.notifications.doNotDisturb ? Color.mError : Color.mOnSurface
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 80e79db..2458ce3 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -43,9 +43,9 @@ Item {
function getIcon() {
if (AudioService.muted) {
- return "volume_off"
+ return FontService.icons["volume_off"] // TODO disabled icon ?
}
- return AudioService.volume <= Number.EPSILON ? "volume_off" : (AudioService.volume < 0.33 ? "volume_down" : "volume_up")
+ return AudioService.volume <= Number.EPSILON ? FontService.icons["volume_off"] : (AudioService.volume < 0.5 ? FontService.icons["volume_half"]: FontService.icons["volume_full"])
}
// Connection used to open the pill when volume changes
diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml
index 8eb28e8..1487bfd 100644
--- a/Modules/SidePanel/Cards/PowerProfilesCard.qml
+++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml
@@ -28,7 +28,7 @@ NBox {
}
// Performance
NIconButton {
- icon: "speed"
+ icon: FontService.icons["speed"]
tooltipText: "Set performance power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
@@ -42,7 +42,7 @@ NBox {
}
// Balanced
NIconButton {
- icon: "balance"
+ icon: FontService.icons["scale"]
tooltipText: "Set balanced power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
@@ -56,7 +56,7 @@ NBox {
}
// Eco
NIconButton {
- icon: "eco"
+ icon: FontService.icons["leaf"]
tooltipText: "Set eco power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
diff --git a/Modules/SidePanel/Cards/UtilitiesCard.qml b/Modules/SidePanel/Cards/UtilitiesCard.qml
index 78fc702..27f0dce 100644
--- a/Modules/SidePanel/Cards/UtilitiesCard.qml
+++ b/Modules/SidePanel/Cards/UtilitiesCard.qml
@@ -25,7 +25,7 @@ NBox {
}
// Screen Recorder
NIconButton {
- icon: "videocam"
+ icon: FontService.icons["video_camera"]
tooltipText: ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording."
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
@@ -41,7 +41,7 @@ NBox {
// Idle Inhibitor
NIconButton {
- icon: "coffee"
+ icon: FontService.icons["coffee"]
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake." : "Enable keep awake."
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
@@ -53,7 +53,7 @@ NBox {
// Wallpaper
NIconButton {
visible: Settings.data.wallpaper.enabled
- icon: "image"
+ icon: FontService.icons["image"]
tooltipText: "Left click: Open wallpaper selector.\nRight click: Set random wallpaper."
onClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
diff --git a/Services/FontService.qml b/Services/FontService.qml
index db1db91..7bf4839 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -14,7 +14,6 @@ Singleton {
property bool fontsLoaded: false
property var icons: {
- // weather
"sunny": "\ue30d",
"partly_cloudy": "\ue302",
"cloud": "\ue312",
@@ -22,17 +21,27 @@ Singleton {
"rainy": "\ue318",
"snowy": "\ue319",
"thunderstom": "\ue31d",
-
- "power": "\uf011",
- "gear": "\uf013",
+ "battery_empty": "\uF188",
+ "battery_low": "\uF187",
+ "battery_full": "\uF186",
+ "battery_charging": "\uF185",
+ "volume_off": "\uF026",
+ "volume_half": "\uF027",
+ "volume_full": "\uF028",
+ "power": "\uf011",
+ "gear": "\uf013",
"close": "\uf00D",
"check": "\uf00C",
- "panel": "\uF00B"
+ "panel": "\uF28C",
+ "memory": "\uF2D6",
+ "bell": "\uF189",
+ "trash": "\uF014",
+ "image": "\uF03E",
+ "refresh": "\uF021",
+ "video_camera": "\uF03D",
}
-
// -------------------------------------------
-
function init() {
Logger.log("Font", "Service started")
loadSystemFonts()
From 6169f88d9099d04dbd5edf4e6f65af772c0a254e Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 14:33:20 -0400
Subject: [PATCH 014/118] Default skull icon
---
Modules/Bar/Widgets/DarkModeToggle.qml | 2 +-
Modules/Bar/Widgets/KeepAwake.qml | 2 +-
Modules/Bar/Widgets/SystemMonitor.qml | 10 +++----
Modules/Bar/Widgets/Volume.qml | 6 ++--
Modules/Bar/Widgets/WiFi.qml | 2 +-
Modules/SettingsPanel/SettingsPanel.qml | 28 +++++++++----------
Modules/SidePanel/Cards/SystemMonitorCard.qml | 8 +++---
Services/FontService.qml | 10 ++++++-
Widgets/NIcon.qml | 5 ++--
9 files changed, 42 insertions(+), 31 deletions(-)
diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml
index ae7d933..3ba55f3 100644
--- a/Modules/Bar/Widgets/DarkModeToggle.qml
+++ b/Modules/Bar/Widgets/DarkModeToggle.qml
@@ -9,7 +9,7 @@ NIconButton {
property ShellScreen screen
property real scaling: 1.0
- icon: "contrast"
+ icon: FontService.icons["contrast"]
tooltipText: "Toggle light/dark mode"
sizeRatio: 0.8
diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml
index 31c6525..d13612a 100644
--- a/Modules/Bar/Widgets/KeepAwake.qml
+++ b/Modules/Bar/Widgets/KeepAwake.qml
@@ -13,7 +13,7 @@ NIconButton {
sizeRatio: 0.8
- icon: "coffee"
+ icon: FontService.icons["coffee"]
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake"
colorBg: Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mOnSurface
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index 91f3fd8..d8fe84a 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -66,7 +66,7 @@ RowLayout {
NIcon {
id: cpuUsageIcon
- text: "speed"
+ text: FontService.icons["speed"]
Layout.alignment: Qt.AlignVCenter
}
@@ -91,7 +91,7 @@ RowLayout {
visible: showCpuTemp
NIcon {
- text: "thermometer"
+ text: FontService.icons["thermometer"]
Layout.alignment: Qt.AlignVCenter
}
@@ -114,7 +114,7 @@ RowLayout {
visible: showMemoryUsage
NIcon {
- text: "memory"
+ text: FontService.icons["memory"]
Layout.alignment: Qt.AlignVCenter
}
@@ -137,7 +137,7 @@ RowLayout {
visible: showNetworkStats
NIcon {
- text: "download"
+ text: FontService.icons["download"]
Layout.alignment: Qt.AlignVCenter
}
@@ -160,7 +160,7 @@ RowLayout {
visible: showNetworkStats
NIcon {
- text: "upload"
+ text: FontService.icons["upload"]
Layout.alignment: Qt.AlignVCenter
}
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 2458ce3..3f2a76c 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -43,9 +43,11 @@ Item {
function getIcon() {
if (AudioService.muted) {
- return FontService.icons["volume_off"] // TODO disabled icon ?
+ return FontService.icons["volume_off"] // TODO disabled icon ?
}
- return AudioService.volume <= Number.EPSILON ? FontService.icons["volume_off"] : (AudioService.volume < 0.5 ? FontService.icons["volume_half"]: FontService.icons["volume_full"])
+ return AudioService.volume
+ <= Number.EPSILON ? FontService.icons["volume_off"] : (AudioService.volume
+ < 0.5 ? FontService.icons["volume_half"] : FontService.icons["volume_full"])
}
// Connection used to open the pill when volume changes
diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml
index fe8ff75..80120a4 100644
--- a/Modules/Bar/Widgets/WiFi.qml
+++ b/Modules/Bar/Widgets/WiFi.qml
@@ -23,7 +23,7 @@ NIconButton {
icon: {
try {
if (NetworkService.ethernetConnected) {
- return "lan"
+ return FontService.icons["ethernet"]
}
let connected = false
let signalStrength = 0
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index ea8c701..7b545a5 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -123,52 +123,52 @@ NPanel {
let newTabs = [{
"id": SettingsPanel.Tab.General,
"label": "General",
- "icon": "tune",
+ "icon": FontService.icons["general"],
"source": generalTab
}, {
"id": SettingsPanel.Tab.Bar,
"label": "Bar",
- "icon": "web_asset",
+ "icon": FontService.icons["bar"],
"source": barTab
}, {
"id": SettingsPanel.Tab.Launcher,
"label": "Launcher",
- "icon": "apps",
+ "icon": FontService.icons["apps"],
"source": launcherTab
}, {
"id": SettingsPanel.Tab.Audio,
"label": "Audio",
- "icon": "volume_up",
+ "icon": FontService.icons["volume_full"],
"source": audioTab
}, {
"id": SettingsPanel.Tab.Display,
"label": "Display",
- "icon": "monitor",
+ "icon": FontService.icons["monitor"],
"source": displayTab
}, {
"id": SettingsPanel.Tab.Network,
"label": "Network",
- "icon": "lan",
+ "icon": FontService.icons["ethernet"],
"source": networkTab
}, {
"id": SettingsPanel.Tab.Brightness,
"label": "Brightness",
- "icon": "brightness_6",
+ "icon": FontService.icons["brightness"],
"source": brightnessTab
}, {
"id": SettingsPanel.Tab.Weather,
"label": "Weather",
- "icon": "partly_cloudy_day",
+ "icon": FontService.icons["partly_cloudy"],
"source": weatherTab
}, {
"id": SettingsPanel.Tab.ColorScheme,
"label": "Color Scheme",
- "icon": "palette",
+ "icon": FontService.icons["palette"],
"source": colorSchemeTab
}, {
"id": SettingsPanel.Tab.Wallpaper,
"label": "Wallpaper",
- "icon": "image",
+ "icon": FontService.icons["image"],
"source": wallpaperTab
}]
@@ -177,7 +177,7 @@ NPanel {
newTabs.push({
"id": SettingsPanel.Tab.WallpaperSelector,
"label": "Wallpaper Selector",
- "icon": "wallpaper_slideshow",
+ "icon": FontService.icons["image"],
"source": wallpaperSelectorTab
})
}
@@ -185,17 +185,17 @@ NPanel {
newTabs.push({
"id": SettingsPanel.Tab.ScreenRecorder,
"label": "Screen Recorder",
- "icon": "videocam",
+ "icon": FontService.icons["video_camera"],
"source": screenRecorderTab
}, {
"id": SettingsPanel.Tab.Hooks,
"label": "Hooks",
- "icon": "cable",
+ "icon": FontService.icons["cable"],
"source": hooksTab
}, {
"id": SettingsPanel.Tab.About,
"label": "About",
- "icon": "info",
+ "icon": FontService.icons["info"],
"source": aboutTab
})
diff --git a/Modules/SidePanel/Cards/SystemMonitorCard.qml b/Modules/SidePanel/Cards/SystemMonitorCard.qml
index 9d3154d..199960c 100644
--- a/Modules/SidePanel/Cards/SystemMonitorCard.qml
+++ b/Modules/SidePanel/Cards/SystemMonitorCard.qml
@@ -24,7 +24,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuUsage
- icon: "speed"
+ icon: FontService.icons["speed"]
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -33,7 +33,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuTemp
suffix: "°C"
- icon: "device_thermostat"
+ icon: FontService.icons["thermometer"]
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -41,7 +41,7 @@ NBox {
}
NCircleStat {
value: SystemStatService.memPercent
- icon: "memory"
+ icon: FontService.icons["memory"]
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -49,7 +49,7 @@ NBox {
}
NCircleStat {
value: SystemStatService.diskPercent
- icon: "hard_drive"
+ icon: FontService.icons["drive"]
flat: true
contentScale: 0.8
width: 72 * scaling
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 7bf4839..8bee60d 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -29,7 +29,7 @@ Singleton {
"volume_half": "\uF027",
"volume_full": "\uF028",
"power": "\uf011",
- "gear": "\uf013",
+ "gear": "\ue615",
"close": "\uf00D",
"check": "\uf00C",
"panel": "\uF28C",
@@ -39,6 +39,14 @@ Singleton {
"image": "\uF03E",
"refresh": "\uF021",
"video_camera": "\uF03D",
+ "ethernet": "\uEF09",
+ "speed": "\uEEB2",
+ "leaf": "\uEE34",
+ "microphone": "\uED03",
+ "coffee": "\uef59",
+ "thermometer": "\uE350",
+ "contrast": "\uF042",
+ "skull": "\uEE15"
}
// -------------------------------------------
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index 9ee76ad..adfb22f 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -1,12 +1,13 @@
import QtQuick
+import QtQuick.Layouts
import qs.Commons
import qs.Widgets
-import QtQuick.Layouts
+
Text {
// Optional layout nudge for optical alignment when used inside Layouts
property real layoutTopMargin: 0
- text: "question_mark"
+ text: "\uEE15" // default skull icon
font.family: "bootstrap-icons"
font.pointSize: Style.fontSizeL * scaling
font.variableAxes: {
From 6f1b88e76de85405b5c2214bbaeea6e71920aef3 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 14:44:28 -0400
Subject: [PATCH 015/118] more icons
---
Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml | 2 +-
Modules/Bar/Widgets/Volume.qml | 2 +-
Modules/BluetoothPanel/BluetoothPanel.qml | 2 +-
Modules/Notification/Notification.qml | 2 +-
Modules/Notification/NotificationHistoryPanel.qml | 2 +-
Modules/SettingsPanel/Bar/BarSectionEditor.qml | 2 +-
Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml | 2 +-
Modules/SettingsPanel/SettingsPanel.qml | 6 +++---
Modules/SettingsPanel/Tabs/AudioTab.qml | 2 +-
Modules/SidePanel/Cards/PowerProfilesCard.qml | 2 +-
Modules/WiFiPanel/WiFiPanel.qml | 8 ++++----
Services/FontService.qml | 6 +++++-
Widgets/NColorPickerDialog.qml | 4 ++--
Widgets/NToast.qml | 2 +-
14 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
index c282e11..9e4ec6a 100644
--- a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
+++ b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
@@ -55,7 +55,7 @@ NPanel {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 3f2a76c..cde2693 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -43,7 +43,7 @@ Item {
function getIcon() {
if (AudioService.muted) {
- return FontService.icons["volume_off"] // TODO disabled icon ?
+ return FontService.icons["volume_muted"]
}
return AudioService.volume
<= Number.EPSILON ? FontService.icons["volume_off"] : (AudioService.volume
diff --git a/Modules/BluetoothPanel/BluetoothPanel.qml b/Modules/BluetoothPanel/BluetoothPanel.qml
index 751a0c4..312ddc3 100644
--- a/Modules/BluetoothPanel/BluetoothPanel.qml
+++ b/Modules/BluetoothPanel/BluetoothPanel.qml
@@ -53,7 +53,7 @@ NPanel {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml
index fdbe0d2..f6b1510 100644
--- a/Modules/Notification/Notification.qml
+++ b/Modules/Notification/Notification.qml
@@ -294,7 +294,7 @@ Variants {
// Close button positioned absolutely
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
tooltipText: "Close"
sizeRatio: 0.6
anchors.top: parent.top
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index 39686df..0278ab9 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -59,7 +59,7 @@ NPanel {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index 7a1684a..3d32950 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -210,7 +210,7 @@ NBox {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
sizeRatio: 0.6
colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
colorBg: Color.mOnSurface
diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
index 9ba0045..c354b7b 100644
--- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
@@ -84,7 +84,7 @@ Popup {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
onClicked: settingsPopup.close()
}
}
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index 7b545a5..622b2c7 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -163,7 +163,7 @@ NPanel {
}, {
"id": SettingsPanel.Tab.ColorScheme,
"label": "Color Scheme",
- "icon": FontService.icons["palette"],
+ "icon": FontService.icons["paint_bucket"],
"source": colorSchemeTab
}, {
"id": SettingsPanel.Tab.Wallpaper,
@@ -177,7 +177,7 @@ NPanel {
newTabs.push({
"id": SettingsPanel.Tab.WallpaperSelector,
"label": "Wallpaper Selector",
- "icon": FontService.icons["image"],
+ "icon": FontService.icons["paint_brush"],
"source": wallpaperSelectorTab
})
}
@@ -473,7 +473,7 @@ NPanel {
// Close button
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
tooltipText: "Close"
Layout.alignment: Qt.AlignVCenter
onClicked: root.close()
diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml
index d60ae38..b72047a 100644
--- a/Modules/SettingsPanel/Tabs/AudioTab.qml
+++ b/Modules/SettingsPanel/Tabs/AudioTab.qml
@@ -322,7 +322,7 @@ ColumnLayout {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
sizeRatio: 0.8
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Style.marginXS * scaling
diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml
index 1487bfd..9af102b 100644
--- a/Modules/SidePanel/Cards/PowerProfilesCard.qml
+++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml
@@ -42,7 +42,7 @@ NBox {
}
// Balanced
NIconButton {
- icon: FontService.icons["scale"]
+ icon: FontService.icons["yin_yang"]
tooltipText: "Set balanced power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index 627be65..db4e21a 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -63,7 +63,7 @@ NPanel {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
@@ -105,7 +105,7 @@ NPanel {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
sizeRatio: 0.6
onClicked: NetworkService.lastError = ""
}
@@ -492,7 +492,7 @@ NPanel {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
sizeRatio: 0.8
onClicked: {
passwordSsid = ""
@@ -547,7 +547,7 @@ NPanel {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
sizeRatio: 0.8
onClicked: expandedSsid = ""
}
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 8bee60d..d1a5cf3 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -25,6 +25,7 @@ Singleton {
"battery_low": "\uF187",
"battery_full": "\uF186",
"battery_charging": "\uF185",
+ "volume_muted": "\uEEE8",
"volume_off": "\uF026",
"volume_half": "\uF027",
"volume_full": "\uF028",
@@ -46,7 +47,10 @@ Singleton {
"coffee": "\uef59",
"thermometer": "\uE350",
"contrast": "\uF042",
- "skull": "\uEE15"
+ "skull": "\uEE15",
+ "paint_brush": "\uEE26",
+ "paint_bucket": "\uEE3F",
+ "yin_yang": "\uEEE9"
}
// -------------------------------------------
diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml
index 324e5b6..07b9647 100644
--- a/Widgets/NColorPickerDialog.qml
+++ b/Widgets/NColorPickerDialog.qml
@@ -147,7 +147,7 @@ Popup {
}
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
onClicked: root.close()
}
}
@@ -491,7 +491,7 @@ Popup {
NButton {
id: cancelButton
text: "Cancel"
- icon: "close"
+ icon: FontService.icons["close"]
outlined: cancelButton.hovered ? false : true
customHeight: 36 * scaling
customWidth: 100 * scaling
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index 7a60c6c..8e279b3 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -172,7 +172,7 @@ Item {
// Close button (only if persistent or manual dismiss needed)
NIconButton {
- icon: "close"
+ icon: FontService.icons["close"]
visible: root.persistent || root.duration === 0
colorBg: Color.mSurfaceVariant
From 404a1d3e8bfacc84fe9d2e90f77422e1c8b22db9 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 15:22:43 -0400
Subject: [PATCH 016/118] New icons + some warning fixes
---
Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml | 8 ++---
Modules/Bar/Widgets/MediaMini.qml | 5 ++--
.../Notification/NotificationHistoryPanel.qml | 8 ++---
.../SettingsPanel/Bar/BarSectionEditor.qml | 2 +-
Modules/SettingsPanel/SettingsPanel.qml | 30 +++++++++----------
Modules/SettingsPanel/Tabs/DisplayTab.qml | 2 +-
.../Tabs/WallpaperSelectorTab.qml | 2 +-
Modules/SidePanel/Cards/MediaCard.qml | 2 +-
Modules/WiFiPanel/WiFiPanel.qml | 6 ++--
Services/FontService.qml | 24 +++++++++++++--
Widgets/NComboBox.qml | 2 +-
Widgets/NImageCircled.qml | 5 ++--
Widgets/NImageRounded.qml | 5 ++--
Widgets/NInputAction.qml | 3 +-
14 files changed, 63 insertions(+), 41 deletions(-)
diff --git a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
index 9e4ec6a..cbe3886 100644
--- a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
+++ b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
@@ -44,7 +44,7 @@ NPanel {
// Reset button (only show if update failed)
NIconButton {
visible: ArchUpdaterService.updateFailed
- icon: "refresh"
+ icon: FontService.icons["refresh"]
tooltipText: "Reset update state"
sizeRatio: 0.8
colorBg: Color.mError
@@ -245,7 +245,7 @@ NPanel {
// Prominent refresh button
NIconButton {
- icon: "refresh"
+ icon: FontService.icons["refresh"]
tooltipText: "Try checking again"
sizeRatio: 1.2
colorBg: Color.mPrimary
@@ -295,7 +295,7 @@ NPanel {
// Prominent refresh button
NIconButton {
- icon: "refresh"
+ icon: FontService.icons["refresh"]
tooltipText: "Refresh and try again"
sizeRatio: 1.2
colorBg: Color.mPrimary
@@ -483,7 +483,7 @@ NPanel {
spacing: Style.marginL * scaling
NIconButton {
- icon: "refresh"
+ icon: FontService.icons["refresh"]
tooltipText: ArchUpdaterService.aurBusy ? "Checking for updates..." : (!ArchUpdaterService.canPoll ? "Refresh available soon" : "Refresh package lists")
onClicked: {
ArchUpdaterService.forceRefresh()
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index 141698a..9649a9a 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -134,7 +134,7 @@ RowLayout {
NIcon {
id: windowIcon
- text: MediaService.isPlaying ? "pause" : "play_arrow"
+ text: MediaService.isPlaying ? FontService.icons["pause"]: FontService.icons["play"]
font.pointSize: Style.fontSizeL * scaling
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignVCenter
@@ -154,7 +154,8 @@ RowLayout {
id: trackArt
anchors.fill: parent
imagePath: MediaService.trackArtUrl
- fallbackIcon: MediaService.isPlaying ? "pause" : "play_arrow"
+ fallbackIcon: MediaService.isPlaying ? FontService.icons["pause"]: FontService.icons["play"]
+ fallbackIconSize: 10 * scaling
borderWidth: 0
border.color: Color.transparent
}
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index 0278ab9..d54cfb2 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -31,7 +31,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: "notifications"
+ text: FontService.icons["bell"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -45,14 +45,14 @@ NPanel {
}
NIconButton {
- icon: Settings.data.notifications.doNotDisturb ? "notifications_off" : "notifications_active"
+ icon: Settings.data.notifications.doNotDisturb ? FontService.icons["bell"] : FontService.icons["bell_striked"]
tooltipText: Settings.data.notifications.doNotDisturb ? "'Do Not Disturb' is enabled." : "'Do Not Disturb' is disabled."
sizeRatio: 0.8
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
}
NIconButton {
- icon: "delete"
+ icon: FontService.icons["trash"]
tooltipText: "Clear history"
sizeRatio: 0.8
onClicked: NotificationService.clearHistory()
@@ -175,7 +175,7 @@ NPanel {
// Delete button
NIconButton {
- icon: "delete"
+ icon: FontService.icons["trash"]
tooltipText: "Delete notification"
sizeRatio: 0.7
Layout.alignment: Qt.AlignTop
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index 3d32950..c2a2631 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -170,7 +170,7 @@ NBox {
Loader {
active: BarWidgetRegistry.widgetHasUserSettings(modelData.id)
sourceComponent: NIconButton {
- icon: "settings"
+ icon: FontService.icons["gear"]
sizeRatio: 0.6
colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
colorBg: Color.mOnSurface
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index 622b2c7..7de6a1b 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -123,52 +123,52 @@ NPanel {
let newTabs = [{
"id": SettingsPanel.Tab.General,
"label": "General",
- "icon": FontService.icons["general"],
+ "icon": "general",
"source": generalTab
}, {
"id": SettingsPanel.Tab.Bar,
"label": "Bar",
- "icon": FontService.icons["bar"],
+ "icon": "bar",
"source": barTab
}, {
"id": SettingsPanel.Tab.Launcher,
"label": "Launcher",
- "icon": FontService.icons["apps"],
+ "icon": "apps",
"source": launcherTab
}, {
"id": SettingsPanel.Tab.Audio,
"label": "Audio",
- "icon": FontService.icons["volume_full"],
+ "icon": "volume_full",
"source": audioTab
}, {
"id": SettingsPanel.Tab.Display,
"label": "Display",
- "icon": FontService.icons["monitor"],
+ "icon": "monitor",
"source": displayTab
}, {
"id": SettingsPanel.Tab.Network,
"label": "Network",
- "icon": FontService.icons["ethernet"],
+ "icon": "ethernet",
"source": networkTab
}, {
"id": SettingsPanel.Tab.Brightness,
"label": "Brightness",
- "icon": FontService.icons["brightness"],
+ "icon": "brightness",
"source": brightnessTab
}, {
"id": SettingsPanel.Tab.Weather,
"label": "Weather",
- "icon": FontService.icons["partly_cloudy"],
+ "icon": "partly_cloudy",
"source": weatherTab
}, {
"id": SettingsPanel.Tab.ColorScheme,
"label": "Color Scheme",
- "icon": FontService.icons["paint_bucket"],
+ "icon": "paint_bucket",
"source": colorSchemeTab
}, {
"id": SettingsPanel.Tab.Wallpaper,
"label": "Wallpaper",
- "icon": FontService.icons["image"],
+ "icon": "image",
"source": wallpaperTab
}]
@@ -177,7 +177,7 @@ NPanel {
newTabs.push({
"id": SettingsPanel.Tab.WallpaperSelector,
"label": "Wallpaper Selector",
- "icon": FontService.icons["paint_brush"],
+ "icon": "paint_brush",
"source": wallpaperSelectorTab
})
}
@@ -185,17 +185,17 @@ NPanel {
newTabs.push({
"id": SettingsPanel.Tab.ScreenRecorder,
"label": "Screen Recorder",
- "icon": FontService.icons["video_camera"],
+ "icon": "video_camera",
"source": screenRecorderTab
}, {
"id": SettingsPanel.Tab.Hooks,
"label": "Hooks",
- "icon": FontService.icons["cable"],
+ "icon": "cable",
"source": hooksTab
}, {
"id": SettingsPanel.Tab.About,
"label": "About",
- "icon": FontService.icons["info"],
+ "icon": "info",
"source": aboutTab
})
@@ -404,7 +404,7 @@ NPanel {
// Tab icon
NIcon {
- text: modelData.icon
+ text: FontService.icons[modelData.icon]
color: tabTextColor
font.pointSize: Style.fontSizeL * scaling
}
diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml
index 9a5c4e3..36f6643 100644
--- a/Modules/SettingsPanel/Tabs/DisplayTab.qml
+++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml
@@ -181,7 +181,7 @@ ColumnLayout {
}
NIconButton {
- icon: "refresh"
+ icon: FontService.icons["refresh"]
tooltipText: "Reset scaling"
onClicked: ScalingService.setScreenScale(modelData, 1.0)
}
diff --git a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
index 6952c71..0036a64 100644
--- a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
+++ b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
@@ -96,7 +96,7 @@ ColumnLayout {
}
NIconButton {
- icon: "refresh"
+ icon: FontService.icons["refresh"]
tooltipText: "Refresh wallpaper list"
onClicked: {
WallpaperService.refreshWallpapersList()
diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml
index 65f7211..a28f83a 100644
--- a/Modules/SidePanel/Cards/MediaCard.qml
+++ b/Modules/SidePanel/Cards/MediaCard.qml
@@ -315,7 +315,7 @@ NBox {
// Play/Pause button
NIconButton {
- icon: MediaService.isPlaying ? "pause" : "play_arrow"
+ icon: MediaService.isPlaying ? FontService.icons["pause"] : FontService.icons["play"]
tooltipText: MediaService.isPlaying ? "Pause" : "Play"
visible: (MediaService.canPlay || MediaService.canPause)
onClicked: (MediaService.canPlay || MediaService.canPause) ? MediaService.playPause() : {}
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index db4e21a..e4fccc8 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -55,7 +55,7 @@ NPanel {
}
NIconButton {
- icon: "refresh"
+ icon: FontService.icons["refresh"]
tooltipText: "Refresh"
sizeRatio: 0.8
enabled: Settings.data.network.wifiEnabled && !NetworkService.scanning
@@ -377,7 +377,7 @@ NPanel {
&& NetworkService.connectingTo !== modelData.ssid
&& NetworkService.forgettingNetwork !== modelData.ssid
&& NetworkService.disconnectingFrom !== modelData.ssid
- icon: "delete"
+ icon: FontService.icons["trash"]
tooltipText: "Forget network"
sizeRatio: 0.7
onClicked: expandedSsid = expandedSsid === modelData.ssid ? "" : modelData.ssid
@@ -586,7 +586,7 @@ NPanel {
NButton {
text: "Scan again"
- icon: "refresh"
+ icon: FontService.icons["refresh"]
Layout.alignment: Qt.AlignHCenter
onClicked: NetworkService.scan()
}
diff --git a/Services/FontService.qml b/Services/FontService.qml
index d1a5cf3..46ef26c 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -35,14 +35,14 @@ Singleton {
"check": "\uf00C",
"panel": "\uF28C",
"memory": "\uF2D6",
- "bell": "\uF189",
+
"trash": "\uF014",
"image": "\uF03E",
"refresh": "\uF021",
"video_camera": "\uF03D",
"ethernet": "\uEF09",
"speed": "\uEEB2",
- "leaf": "\uEE34",
+ "leaf": "\uF06C",
"microphone": "\uED03",
"coffee": "\uef59",
"thermometer": "\uE350",
@@ -50,7 +50,25 @@ Singleton {
"skull": "\uEE15",
"paint_brush": "\uEE26",
"paint_bucket": "\uEE3F",
- "yin_yang": "\uEEE9"
+ "yin_yang": "\uEEE9",
+ "record": "\uEFFA",
+ "pause": "\uF04C",
+ "play": "\uF04B",
+ "stop": "\uEFFB",
+ "next": "\uF051",
+ "prev": "\uF048",
+ "paint_drop": "\uF043",
+ "lightning": "\uF0E7",
+ "brightness": "\uF0A3",
+ "arrow_drop_down": "\uF0D7",
+
+ "vinyl": "\uEFBD",
+ "bell": "\uF189",
+ "bell_striked": "\uEE15", // FIXME
+ "drive": "\uEE15", // FIXME
+ "upload": "\uEE15", // FIXME
+ "download": "\uEE15", // FIXME
+
}
// -------------------------------------------
diff --git a/Widgets/NComboBox.qml b/Widgets/NComboBox.qml
index 57bc0bb..842479c 100644
--- a/Widgets/NComboBox.qml
+++ b/Widgets/NComboBox.qml
@@ -85,7 +85,7 @@ RowLayout {
indicator: NIcon {
x: combo.width - width - Style.marginM * scaling
y: combo.topPadding + (combo.availableHeight - height) / 2
- text: "arrow_drop_down"
+ text: FontService.icons["arrow_drop_down"]
font.pointSize: Style.fontSizeXXL * scaling
}
diff --git a/Widgets/NImageCircled.qml b/Widgets/NImageCircled.qml
index 7279c08..0c95178 100644
--- a/Widgets/NImageCircled.qml
+++ b/Widgets/NImageCircled.qml
@@ -9,9 +9,10 @@ Rectangle {
id: root
property string imagePath: ""
- property string fallbackIcon: ""
property color borderColor: Color.transparent
property real borderWidth: 0
+ property string fallbackIcon: ""
+ property real fallbackIconSize: Style.fontSizeXXL * scaling
color: Color.transparent
radius: parent.width * 0.5
@@ -54,7 +55,7 @@ Rectangle {
NIcon {
anchors.centerIn: parent
text: fallbackIcon
- font.pointSize: Style.fontSizeXXL * scaling
+ font.pointSize: fallbackIconSize
visible: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
z: 0
}
diff --git a/Widgets/NImageRounded.qml b/Widgets/NImageRounded.qml
index 76654fc..c2c8b94 100644
--- a/Widgets/NImageRounded.qml
+++ b/Widgets/NImageRounded.qml
@@ -9,10 +9,11 @@ Rectangle {
id: root
property string imagePath: ""
- property string fallbackIcon: ""
property color borderColor: Color.transparent
property real borderWidth: 0
property real imageRadius: width * 0.5
+ property string fallbackIcon: ""
+ property real fallbackIconSize: Style.fontSizeXXL * scaling
property real scaledRadius: imageRadius * Settings.data.general.radiusRatio
@@ -74,7 +75,7 @@ Rectangle {
NIcon {
anchors.centerIn: parent
text: fallbackIcon
- font.pointSize: Style.fontSizeXXL * scaling
+ font.pointSize: fallbackIconSize
visible: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
z: 0
}
diff --git a/Widgets/NInputAction.qml b/Widgets/NInputAction.qml
index 785b5b0..b48264b 100644
--- a/Widgets/NInputAction.qml
+++ b/Widgets/NInputAction.qml
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
+import qs.Services
// Input and button row
RowLayout {
@@ -13,7 +14,7 @@ RowLayout {
property string placeholderText: ""
property string text: ""
property string actionButtonText: "Test"
- property string actionButtonIcon: "play_arrow"
+ property string actionButtonIcon: FontService.icons["play"]
property bool actionButtonEnabled: text !== ""
// Signals
From ea6b8e0c02014d97ec1e6e39e4bbe1e8da872ed3 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 15:53:50 -0400
Subject: [PATCH 017/118] Icons: Brightness and battery
---
Modules/Bar/Widgets/Battery.qml | 5 ++-
Modules/Bar/Widgets/Brightness.qml | 3 +-
Modules/LockScreen/LockScreen.qml | 2 +-
.../SettingsPanel/Bar/BarSectionEditor.qml | 2 +-
.../Bar/BarWidgetSettingsDialog.qml | 2 +-
.../WidgetSettings/SystemMonitorSettings.qml | 2 +-
Modules/SettingsPanel/SettingsPanel.qml | 4 +--
Modules/SettingsPanel/Tabs/AboutTab.qml | 2 +-
Modules/SettingsPanel/Tabs/AudioTab.qml | 2 +-
Modules/SettingsPanel/Tabs/GeneralTab.qml | 2 +-
.../Tabs/WallpaperSelectorTab.qml | 2 +-
Modules/SidePanel/Cards/MediaCard.qml | 6 ++--
Modules/SidePanel/Cards/ProfileCard.qml | 2 +-
Services/BatteryService.qml | 34 ++++---------------
Services/FontService.qml | 16 ++++++---
Widgets/NColorPickerDialog.qml | 2 +-
Widgets/NPill.qml | 2 --
Widgets/NToast.qml | 12 +------
18 files changed, 36 insertions(+), 66 deletions(-)
diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml
index 9b8aef5..078d7f4 100644
--- a/Modules/Bar/Widgets/Battery.qml
+++ b/Modules/Bar/Widgets/Battery.qml
@@ -39,7 +39,7 @@ Item {
// Test mode
readonly property bool testMode: false
readonly property int testPercent: 50
- readonly property bool testCharging: true
+ readonly property bool testCharging: false
// Main properties
readonly property var battery: UPower.displayDevice
@@ -87,8 +87,7 @@ Item {
rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent,
charging, isReady)
- iconRotation: -90
- text: ((isReady && battery.isLaptopBattery) || testMode) ? Math.round(percent) + "%" : "-"
+ text: (isReady || testMode) ? Math.round(percent) + "%" : "-"
textColor: charging ? Color.mPrimary : Color.mOnSurface
iconCircleColor: Color.mPrimary
collapsedIconColor: Color.mOnSurface
diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml
index 30948c3..4c3cb0e 100644
--- a/Modules/Bar/Widgets/Brightness.qml
+++ b/Modules/Bar/Widgets/Brightness.qml
@@ -46,8 +46,7 @@ Item {
function getIcon() {
var monitor = getMonitor()
var brightness = monitor ? monitor.brightness : 0
- return brightness <= 0 ? "brightness_1" : brightness < 0.33 ? "brightness_low" : brightness
- < 0.66 ? "brightness_medium" : "brightness_high"
+ return brightness <= 0.5 ? FontService.icons["brightness_low"] : FontService.icons["brightness_high"]
}
// Connection used to open the pill when brightness changes
diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml
index 25b69b1..dfe77a6 100644
--- a/Modules/LockScreen/LockScreen.qml
+++ b/Modules/LockScreen/LockScreen.qml
@@ -328,7 +328,7 @@ Loader {
width: 100 * scaling
height: 100 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: "person"
+ fallbackIcon: FontService.icons["person"]
}
MouseArea {
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index c2a2631..4f0bba4 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -85,7 +85,7 @@ NBox {
}
NIconButton {
- icon: "add"
+ icon: FontService.icons["add"]
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
index c354b7b..e0cf418 100644
--- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
@@ -120,7 +120,7 @@ Popup {
NButton {
text: "Apply"
- icon: "check"
+ icon: FontService.icons["check"]
onClicked: {
if (settingsLoader.item && settingsLoader.item.saveSettings) {
var newSettings = settingsLoader.item.saveSettings()
diff --git a/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml b/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
index 4f2459b..21d0d4c 100644
--- a/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
+++ b/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
@@ -59,7 +59,7 @@ ColumnLayout {
NToggle {
id: showMemoryAsPercent
Layout.fillWidth: true
- label: "Show memory as percentage"
+ label: "Memory as percentage"
checked: valueShowMemoryAsPercent
onToggled: checked => valueShowMemoryAsPercent = checked
}
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index 7de6a1b..69908f5 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -163,7 +163,7 @@ NPanel {
}, {
"id": SettingsPanel.Tab.ColorScheme,
"label": "Color Scheme",
- "icon": "paint_bucket",
+ "icon": "paint_drop",
"source": colorSchemeTab
}, {
"id": SettingsPanel.Tab.Wallpaper,
@@ -190,7 +190,7 @@ NPanel {
}, {
"id": SettingsPanel.Tab.Hooks,
"label": "Hooks",
- "icon": "cable",
+ "icon": "link",
"source": hooksTab
}, {
"id": SettingsPanel.Tab.About,
diff --git a/Modules/SettingsPanel/Tabs/AboutTab.qml b/Modules/SettingsPanel/Tabs/AboutTab.qml
index 1fffadb..3dc3f2d 100644
--- a/Modules/SettingsPanel/Tabs/AboutTab.qml
+++ b/Modules/SettingsPanel/Tabs/AboutTab.qml
@@ -172,7 +172,7 @@ ColumnLayout {
imagePath: modelData.avatar_url || ""
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
- fallbackIcon: "person"
+ fallbackIcon: FontService.icons["person"]
borderColor: contributorArea.containsMouse ? Color.mOnTertiary : Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml
index b72047a..3473a43 100644
--- a/Modules/SettingsPanel/Tabs/AudioTab.qml
+++ b/Modules/SettingsPanel/Tabs/AudioTab.qml
@@ -272,7 +272,7 @@ ColumnLayout {
// Button aligned to the center of the actual input field
NIconButton {
- icon: "add"
+ icon: FontService.icons["add"]
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: blacklistInput.description ? Style.marginS * scaling : 0
onClicked: {
diff --git a/Modules/SettingsPanel/Tabs/GeneralTab.qml b/Modules/SettingsPanel/Tabs/GeneralTab.qml
index fe4dbcd..c302217 100644
--- a/Modules/SettingsPanel/Tabs/GeneralTab.qml
+++ b/Modules/SettingsPanel/Tabs/GeneralTab.qml
@@ -19,7 +19,7 @@ ColumnLayout {
width: 108 * scaling
height: 108 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: "person"
+ fallbackIcon: FontService.icons["person"]
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
Layout.alignment: Qt.AlignTop
diff --git a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
index 0036a64..d267803 100644
--- a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
+++ b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
@@ -59,7 +59,7 @@ ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: currentWallpaper
- fallbackIcon: "image"
+ fallbackIcon: FontService.icons["image"]
imageRadius: Style.radiusM * scaling
borderColor: Color.mSecondary
borderWidth: Style.borderL * 2 * scaling
diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml
index a28f83a..369dcf5 100644
--- a/Modules/SidePanel/Cards/MediaCard.qml
+++ b/Modules/SidePanel/Cards/MediaCard.qml
@@ -162,7 +162,7 @@ NBox {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: MediaService.trackArtUrl
- fallbackIcon: "music_note"
+ fallbackIcon: FontService.icons["vinyl"]
borderColor: Color.mOutline
borderWidth: Math.max(1, Style.borderS * scaling)
}
@@ -307,7 +307,7 @@ NBox {
// Previous button
NIconButton {
- icon: "skip_previous"
+ icon: FontService.icons["previous"]
tooltipText: "Previous Media"
visible: MediaService.canGoPrevious
onClicked: MediaService.canGoPrevious ? MediaService.previous() : {}
@@ -323,7 +323,7 @@ NBox {
// Next button
NIconButton {
- icon: "skip_next"
+ icon: FontService.icons["next"]
tooltipText: "Next media"
visible: MediaService.canGoNext
onClicked: MediaService.canGoNext ? MediaService.next() : {}
diff --git a/Modules/SidePanel/Cards/ProfileCard.qml b/Modules/SidePanel/Cards/ProfileCard.qml
index 675d67b..42a3198 100644
--- a/Modules/SidePanel/Cards/ProfileCard.qml
+++ b/Modules/SidePanel/Cards/ProfileCard.qml
@@ -32,7 +32,7 @@ NBox {
width: Style.baseWidgetSize * 1.25 * scaling
height: Style.baseWidgetSize * 1.25 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: "person"
+ fallbackIcon: FontService.icons["person"]
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
}
diff --git a/Services/BatteryService.qml b/Services/BatteryService.qml
index 6ceb872..2a9dfbb 100644
--- a/Services/BatteryService.qml
+++ b/Services/BatteryService.qml
@@ -2,6 +2,7 @@ pragma Singleton
import Quickshell
import Quickshell.Services.UPower
+import qs.Services
Singleton {
id: root
@@ -9,41 +10,18 @@ Singleton {
// Choose icon based on charge and charging state
function getIcon(percent, charging, isReady) {
if (!isReady) {
- return "battery_error"
+ return FontService.icons["battery_empty"] // FIXME: find battery error ?
}
if (charging) {
- if (percent >= 95)
- return "battery_full"
- if (percent >= 85)
- return "battery_charging_90"
- if (percent >= 65)
- return "battery_charging_80"
- if (percent >= 55)
- return "battery_charging_60"
- if (percent >= 45)
- return "battery_charging_50"
- if (percent >= 25)
- return "battery_charging_30"
- if (percent >= 0)
- return "battery_charging_20"
+ return FontService.icons["battery_charging"]
} else {
- if (percent >= 95)
- return "battery_full"
if (percent >= 85)
- return "battery_6_bar"
- if (percent >= 70)
- return "battery_5_bar"
- if (percent >= 55)
- return "battery_4_bar"
- if (percent >= 40)
- return "battery_3_bar"
+ return FontService.icons["battery_full"]
if (percent >= 25)
- return "battery_2_bar"
- if (percent >= 10)
- return "battery_1_bar"
+ return FontService.icons["battery_low"]
if (percent >= 0)
- return "battery_0_bar"
+ return FontService.icons["battery_empty"]
}
}
}
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 46ef26c..ceccb30 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -29,13 +29,14 @@ Singleton {
"volume_off": "\uF026",
"volume_half": "\uF027",
"volume_full": "\uF028",
+ "brightness_low": "\uF1CF",
+ "brightness_high": "\uF1CD",
"power": "\uf011",
"gear": "\ue615",
"close": "\uf00D",
"check": "\uf00C",
"panel": "\uF28C",
"memory": "\uF2D6",
-
"trash": "\uF014",
"image": "\uF03E",
"refresh": "\uF021",
@@ -57,17 +58,22 @@ Singleton {
"stop": "\uEFFB",
"next": "\uF051",
"prev": "\uF048",
- "paint_drop": "\uF043",
+ "paint_drop": "\uF30C",
"lightning": "\uF0E7",
"brightness": "\uF0A3",
"arrow_drop_down": "\uF0D7",
-
+ "warning": "\uF334",
+ "info": "\uF26A",
+ "upload": "\uF01B",
+ "download": "\uF01A",
"vinyl": "\uEFBD",
+ "link": "\uF0C1",
+ "add": "\uF055", // FIXME UGLY
"bell": "\uF189",
"bell_striked": "\uEE15", // FIXME
"drive": "\uEE15", // FIXME
- "upload": "\uEE15", // FIXME
- "download": "\uEE15", // FIXME
+ "person": "\uEE15", // FIXME
+
}
diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml
index 07b9647..2bcb395 100644
--- a/Widgets/NColorPickerDialog.qml
+++ b/Widgets/NColorPickerDialog.qml
@@ -502,7 +502,7 @@ Popup {
NButton {
text: "Apply"
- icon: "check"
+ icon: FontService.icons["check"]
customHeight: 36 * scaling
customWidth: 100 * scaling
onClicked: {
diff --git a/Widgets/NPill.qml b/Widgets/NPill.qml
index 2011c9d..a30e2c7 100644
--- a/Widgets/NPill.qml
+++ b/Widgets/NPill.qml
@@ -15,7 +15,6 @@ Item {
property color iconTextColor: Color.mSurface
property color collapsedIconColor: Color.mOnSurface
- property real iconRotation: 0
property real sizeRatio: 0.8
property bool autoHide: false
property bool forceOpen: false
@@ -119,7 +118,6 @@ Item {
NIcon {
text: root.icon
- rotation: root.iconRotation
font.pointSize: Style.fontSizeM * scaling
// When forced shown, use pill text color; otherwise accent color when hovered
color: forceOpen ? textColor : (showPill ? iconTextColor : Color.mOnSurface)
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index 8e279b3..8fc882d 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -118,17 +118,7 @@ Item {
// Icon
NIcon {
id: icon
- text: {
- switch (root.type) {
- case "warning":
- return "warning"
- case "notice":
- return "info"
- default:
- return "info"
- }
- }
-
+ text: (root.type == "warning") ? FontService.icons["warning"] : FontService.icons["info"]
color: {
switch (root.type) {
case "warning":
From b91112fc7a2f95499d4f341f266b254fe3cc4b5b Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 16:02:21 -0400
Subject: [PATCH 018/118] Icons: Plus and Minus
+ removed vertical hack in NIcon
---
Modules/SettingsPanel/Bar/BarSectionEditor.qml | 2 +-
Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml | 3 ++-
Modules/SettingsPanel/Tabs/AudioTab.qml | 2 +-
Services/FontService.qml | 3 ++-
Widgets/NButton.qml | 1 -
Widgets/NIcon.qml | 10 +---------
Widgets/NSpinBox.qml | 4 ++--
7 files changed, 9 insertions(+), 16 deletions(-)
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index 4f0bba4..42b259d 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -85,7 +85,7 @@ NBox {
}
NIconButton {
- icon: FontService.icons["add"]
+ icon: FontService.icons["plus"]
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
index e0cf418..51ebc09 100644
--- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
@@ -107,7 +107,8 @@ Popup {
RowLayout {
Layout.fillWidth: true
Layout.topMargin: Style.marginM * scaling
-
+ spacing: Style.marginM * scaling
+
Item {
Layout.fillWidth: true
}
diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml
index 3473a43..e5509ea 100644
--- a/Modules/SettingsPanel/Tabs/AudioTab.qml
+++ b/Modules/SettingsPanel/Tabs/AudioTab.qml
@@ -272,7 +272,7 @@ ColumnLayout {
// Button aligned to the center of the actual input field
NIconButton {
- icon: FontService.icons["add"]
+ icon: FontService.icons["plus"]
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: blacklistInput.description ? Style.marginS * scaling : 0
onClicked: {
diff --git a/Services/FontService.qml b/Services/FontService.qml
index ceccb30..1049adf 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -68,7 +68,8 @@ Singleton {
"download": "\uF01A",
"vinyl": "\uEFBD",
"link": "\uF0C1",
- "add": "\uF055", // FIXME UGLY
+ "plus": "\uF067",
+ "minus": "\uF068",
"bell": "\uF189",
"bell_striked": "\uEE15", // FIXME
"drive": "\uEE15", // FIXME
diff --git a/Widgets/NButton.qml b/Widgets/NButton.qml
index 75c9bc5..8d8425c 100644
--- a/Widgets/NButton.qml
+++ b/Widgets/NButton.qml
@@ -82,7 +82,6 @@ Rectangle {
// Icon (optional)
NIcon {
Layout.alignment: Qt.AlignVCenter
- layoutTopMargin: 1 * scaling
visible: root.icon !== ""
text: root.icon
font.pointSize: root.iconSize
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index adfb22f..48b19eb 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -3,18 +3,10 @@ import QtQuick.Layouts
import qs.Commons
import qs.Widgets
-
Text {
- // Optional layout nudge for optical alignment when used inside Layouts
- property real layoutTopMargin: 0
- text: "\uEE15" // default skull icon
+ text: "\uEE15" // fallback/default to skull icon
font.family: "bootstrap-icons"
font.pointSize: Style.fontSizeL * scaling
- font.variableAxes: {
- "wght"// slightly bold to ensure all lines looks good
- : (Font.Normal + Font.Bold) / 2.5
- }
color: Color.mOnSurface
verticalAlignment: Text.AlignVCenter
- Layout.topMargin: layoutTopMargin
}
diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml
index 8049cf6..77693b7 100644
--- a/Widgets/NSpinBox.qml
+++ b/Widgets/NSpinBox.qml
@@ -95,7 +95,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: "remove"
+ text: FontService.icons["minus"]
font.pointSize: Style.fontSizeS * scaling
color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -130,7 +130,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: "add"
+ text: FontService.icons["plus"]
font.pointSize: Style.fontSizeS * scaling
color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
From 08d2747f1ef63a0dd2d2ea5d32e7b1474ef42313 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 16:08:36 -0400
Subject: [PATCH 019/118] Icons: color picker + better tab alignment in
settings + autoformatting
---
Modules/Bar/Widgets/MediaMini.qml | 4 ++--
.../SettingsPanel/Bar/BarWidgetSettingsDialog.qml | 2 +-
Modules/SettingsPanel/SettingsPanel.qml | 15 +++++++++++----
Services/FontService.qml | 12 +++++++-----
Widgets/NColorPicker.qml | 3 ++-
Widgets/NColorPickerDialog.qml | 3 ++-
Widgets/NSpinBox.qml | 4 ++--
Widgets/NToast.qml | 2 +-
8 files changed, 28 insertions(+), 17 deletions(-)
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index 9649a9a..a620f32 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -134,7 +134,7 @@ RowLayout {
NIcon {
id: windowIcon
- text: MediaService.isPlaying ? FontService.icons["pause"]: FontService.icons["play"]
+ text: MediaService.isPlaying ? FontService.icons["pause"] : FontService.icons["play"]
font.pointSize: Style.fontSizeL * scaling
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignVCenter
@@ -154,7 +154,7 @@ RowLayout {
id: trackArt
anchors.fill: parent
imagePath: MediaService.trackArtUrl
- fallbackIcon: MediaService.isPlaying ? FontService.icons["pause"]: FontService.icons["play"]
+ fallbackIcon: MediaService.isPlaying ? FontService.icons["pause"] : FontService.icons["play"]
fallbackIconSize: 10 * scaling
borderWidth: 0
border.color: Color.transparent
diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
index 51ebc09..d7753e8 100644
--- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
@@ -108,7 +108,7 @@ Popup {
Layout.fillWidth: true
Layout.topMargin: Style.marginM * scaling
spacing: Style.marginM * scaling
-
+
Item {
Layout.fillWidth: true
}
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index 69908f5..af8a524 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -403,10 +403,17 @@ NPanel {
spacing: Style.marginS * scaling
// Tab icon
- NIcon {
- text: FontService.icons[modelData.icon]
- color: tabTextColor
- font.pointSize: Style.fontSizeL * scaling
+ Rectangle {
+ color: Color.transparent
+ width: 20 * scaling
+ height: 20 * scaling
+
+ NIcon {
+ text: FontService.icons[modelData.icon]
+ color: tabTextColor
+ font.pointSize: Style.fontSizeL * scaling
+ anchors.fill: parent
+ }
}
// Tab label
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 1049adf..9d228bc 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -70,12 +70,14 @@ Singleton {
"link": "\uF0C1",
"plus": "\uF067",
"minus": "\uF068",
+ "eyedropper": "\uF342",
"bell": "\uF189",
- "bell_striked": "\uEE15", // FIXME
- "drive": "\uEE15", // FIXME
- "person": "\uEE15", // FIXME
-
-
+ "bell_striked": "\uEE15",
+ "drive"// FIXME
+ : "\uEE15",
+ "person"// FIXME
+ : "\uEE15"
+ // FIXME
}
// -------------------------------------------
diff --git a/Widgets/NColorPicker.qml b/Widgets/NColorPicker.qml
index 830ba84..a4a4aad 100644
--- a/Widgets/NColorPicker.qml
+++ b/Widgets/NColorPicker.qml
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
+import qs.Services
import qs.Widgets
Rectangle {
@@ -58,7 +59,7 @@ Rectangle {
}
NIcon {
- text: "palette"
+ text: FontService.icons["eyedropper"]
color: Color.mOnSurfaceVariant
}
}
diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml
index 2bcb395..cb8db1c 100644
--- a/Widgets/NColorPickerDialog.qml
+++ b/Widgets/NColorPickerDialog.qml
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
+import qs.Services
import qs.Widgets
Popup {
@@ -129,7 +130,7 @@ Popup {
spacing: Style.marginS * scaling
NIcon {
- text: "palette"
+ text: FontService.icons["eyedropper"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml
index 77693b7..a3cb3e3 100644
--- a/Widgets/NSpinBox.qml
+++ b/Widgets/NSpinBox.qml
@@ -95,7 +95,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: FontService.icons["minus"]
+ text: FontService.icons["minus"]
font.pointSize: Style.fontSizeS * scaling
color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -130,7 +130,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: FontService.icons["plus"]
+ text: FontService.icons["plus"]
font.pointSize: Style.fontSizeS * scaling
color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index 8fc882d..4a544d1 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -118,7 +118,7 @@ Item {
// Icon
NIcon {
id: icon
- text: (root.type == "warning") ? FontService.icons["warning"] : FontService.icons["info"]
+ text: (root.type == "warning") ? FontService.icons["warning"] : FontService.icons["info"]
color: {
switch (root.type) {
case "warning":
From 170fbea7a46b77dd4e82f57b0fe49222482199f0 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 16:17:34 -0400
Subject: [PATCH 020/118] Settings: better alignment with new icons + check
icon on wallpaper selector
---
Modules/SettingsPanel/SettingsPanel.qml | 8 ++++----
Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml | 2 +-
Services/FontService.qml | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index af8a524..415da37 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -403,16 +403,15 @@ NPanel {
spacing: Style.marginS * scaling
// Tab icon
- Rectangle {
- color: Color.transparent
+ Item {
width: 20 * scaling
- height: 20 * scaling
+ height: width
NIcon {
text: FontService.icons[modelData.icon]
color: tabTextColor
font.pointSize: Style.fontSizeL * scaling
- anchors.fill: parent
+ anchors.centerIn: parent
}
}
@@ -423,6 +422,7 @@ NPanel {
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
}
}
diff --git a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
index d267803..88433d5 100644
--- a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
+++ b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
@@ -181,7 +181,7 @@ ColumnLayout {
visible: isSelected
NIcon {
- text: "check"
+ text: FontService.icons["check"]
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 9d228bc..a5403da 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -36,7 +36,7 @@ Singleton {
"close": "\uf00D",
"check": "\uf00C",
"panel": "\uF28C",
- "memory": "\uF2D6",
+ "memory": "\uF2D5",
"trash": "\uF014",
"image": "\uF03E",
"refresh": "\uF021",
From b13c40e238f7eb10ed0c348586bd615b1bb5738c Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 16:46:42 -0400
Subject: [PATCH 021/118] Icon: new speed icon
---
Modules/SidePanel/Cards/MediaCard.qml | 10 +++++-----
Services/FontService.qml | 4 ++--
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml
index 369dcf5..8fb937a 100644
--- a/Modules/SidePanel/Cards/MediaCard.qml
+++ b/Modules/SidePanel/Cards/MediaCard.qml
@@ -31,7 +31,7 @@ NBox {
}
NIcon {
- text: "album"
+ text: FontService.icons["album"]
font.pointSize: Style.fontSizeXXXL * 2.5 * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -89,7 +89,7 @@ NBox {
indicator: NIcon {
x: playerSelector.width - width
y: playerSelector.topPadding + (playerSelector.availableHeight - height) / 2
- text: "arrow_drop_down"
+ text: FontService.icons["arrow_drop_down"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mOnSurface
horizontalAlignment: Text.AlignRight
@@ -162,14 +162,14 @@ NBox {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: MediaService.trackArtUrl
- fallbackIcon: FontService.icons["vinyl"]
+ fallbackIcon: FontService.icons["album"]
borderColor: Color.mOutline
borderWidth: Math.max(1, Style.borderS * scaling)
}
// Fallback icon when no album art available
NIcon {
- text: "album"
+ text: FontService.icons["album"]
color: Color.mPrimary
font.pointSize: Style.fontSizeL * 12 * scaling
visible: !trackArt.visible
@@ -307,7 +307,7 @@ NBox {
// Previous button
NIconButton {
- icon: FontService.icons["previous"]
+ icon: FontService.icons["prev"]
tooltipText: "Previous Media"
visible: MediaService.canGoPrevious
onClicked: MediaService.canGoPrevious ? MediaService.previous() : {}
diff --git a/Services/FontService.qml b/Services/FontService.qml
index a5403da..33f9616 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -42,7 +42,7 @@ Singleton {
"refresh": "\uF021",
"video_camera": "\uF03D",
"ethernet": "\uEF09",
- "speed": "\uEEB2",
+ "speed": "\uF06D",
"leaf": "\uF06C",
"microphone": "\uED03",
"coffee": "\uef59",
@@ -66,7 +66,7 @@ Singleton {
"info": "\uF26A",
"upload": "\uF01B",
"download": "\uF01A",
- "vinyl": "\uEFBD",
+ "album": "\uEFBD",
"link": "\uF0C1",
"plus": "\uF067",
"minus": "\uF068",
From d6f629d4bb50e8a7bd0f14b091ee8eb0c1b37319 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 16:50:13 -0400
Subject: [PATCH 022/118] Icon test
---
Services/FontService.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 33f9616..143d6e8 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -42,7 +42,7 @@ Singleton {
"refresh": "\uF021",
"video_camera": "\uF03D",
"ethernet": "\uEF09",
- "speed": "\uF06D",
+ "speed": "\uF153",
"leaf": "\uF06C",
"microphone": "\uED03",
"coffee": "\uef59",
From 29167de546daba7653e774e7c124cac4bc1d8960 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 17:11:24 -0400
Subject: [PATCH 023/118] Icons: picking from the right range
---
Services/FontService.qml | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 143d6e8..b33d078 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -15,12 +15,12 @@ Singleton {
property var icons: {
"sunny": "\ue30d",
- "partly_cloudy": "\ue302",
- "cloud": "\ue312",
- "foggy": "\ue311",
- "rainy": "\ue318",
- "snowy": "\ue319",
- "thunderstom": "\ue31d",
+ "partly_cloudy": "\uF2BE",
+ "cloud": "\uF2C3",
+ "foggy": "\uF2A7",
+ "rainy": "\uf29c",
+ "snowy": "\uF2BC",
+ "thunderstom": "\uF2AC",
"battery_empty": "\uF188",
"battery_low": "\uF187",
"battery_full": "\uF186",
@@ -31,9 +31,13 @@ Singleton {
"volume_full": "\uF028",
"brightness_low": "\uF1CF",
"brightness_high": "\uF1CD",
+ "wifi_disable": "\uF61B",
+ "wifi_low": "\uF619",
+ "wifi_half": "\uF61A",
+ "wifi_full": "\uF61C",
"power": "\uf011",
"gear": "\ue615",
- "close": "\uf00D",
+ "close": "\uF62A",
"check": "\uf00C",
"panel": "\uF28C",
"memory": "\uF2D5",
@@ -41,16 +45,17 @@ Singleton {
"image": "\uF03E",
"refresh": "\uF021",
"video_camera": "\uF03D",
- "ethernet": "\uEF09",
- "speed": "\uF153",
+ "ethernet": "\uF2EB",
+ "speed": "\uF608",
"leaf": "\uF06C",
"microphone": "\uED03",
- "coffee": "\uef59",
+ "coffee": "\uF7EA",
"thermometer": "\uE350",
"contrast": "\uF042",
"skull": "\uEE15",
"paint_brush": "\uEE26",
"paint_bucket": "\uEE3F",
+ "paint_drop": "\uF30C",
"yin_yang": "\uEEE9",
"record": "\uEFFA",
"pause": "\uF04C",
@@ -58,7 +63,6 @@ Singleton {
"stop": "\uEFFB",
"next": "\uF051",
"prev": "\uF048",
- "paint_drop": "\uF30C",
"lightning": "\uF0E7",
"brightness": "\uF0A3",
"arrow_drop_down": "\uF0D7",
@@ -66,15 +70,15 @@ Singleton {
"info": "\uF26A",
"upload": "\uF01B",
"download": "\uF01A",
- "album": "\uEFBD",
+ "album": "\uF2FE",
"link": "\uF0C1",
"plus": "\uF067",
"minus": "\uF068",
"eyedropper": "\uF342",
"bell": "\uF189",
"bell_striked": "\uEE15",
- "drive"// FIXME
- : "\uEE15",
+ "drive"
+ : "\uF410",
"person"// FIXME
: "\uEE15"
// FIXME
From 97c7fd80733e1c32e1bd0e4276fd0eb122565719 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 17:26:21 -0400
Subject: [PATCH 024/118] Icons: more icons
---
Modules/SettingsPanel/SettingsPanel.qml | 2 +-
Services/FontService.qml | 40 ++++++++++++-------------
2 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index 415da37..66a2315 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -133,7 +133,7 @@ NPanel {
}, {
"id": SettingsPanel.Tab.Launcher,
"label": "Launcher",
- "icon": "apps",
+ "icon": "launcher",
"source": launcherTab
}, {
"id": SettingsPanel.Tab.Audio,
diff --git a/Services/FontService.qml b/Services/FontService.qml
index b33d078..7c773e4 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -22,13 +22,14 @@ Singleton {
"snowy": "\uF2BC",
"thunderstom": "\uF2AC",
"battery_empty": "\uF188",
- "battery_low": "\uF187",
+ "battery_low": "\uF911",
+ "battery_half": "\uF187",
"battery_full": "\uF186",
"battery_charging": "\uF185",
- "volume_muted": "\uEEE8",
- "volume_off": "\uF026",
- "volume_half": "\uF027",
- "volume_full": "\uF028",
+ "volume_muted": "\uF60D",
+ "volume_off": "\uF60F",
+ "volume_half": "\uF60B",
+ "volume_full": "\uF611",
"brightness_low": "\uF1CF",
"brightness_high": "\uF1CD",
"wifi_disable": "\uF61B",
@@ -36,18 +37,18 @@ Singleton {
"wifi_half": "\uF61A",
"wifi_full": "\uF61C",
"power": "\uf011",
- "gear": "\ue615",
+ "gear": "\uF3E2",
"close": "\uF62A",
- "check": "\uf00C",
+ "check": "\uF272",
"panel": "\uF28C",
"memory": "\uF2D5",
"trash": "\uF014",
"image": "\uF03E",
"refresh": "\uF021",
- "video_camera": "\uF03D",
+ "video_camera": "\uF21C",
"ethernet": "\uF2EB",
- "speed": "\uF608",
- "leaf": "\uF06C",
+ "speed": "\uF66B",
+ "leaf": "\uF90B",
"microphone": "\uED03",
"coffee": "\uF7EA",
"thermometer": "\uE350",
@@ -64,24 +65,23 @@ Singleton {
"next": "\uF051",
"prev": "\uF048",
"lightning": "\uF0E7",
- "brightness": "\uF0A3",
- "arrow_drop_down": "\uF0D7",
+ "arrow_drop_down": "\uF229",
"warning": "\uF334",
"info": "\uF26A",
- "upload": "\uF01B",
- "download": "\uF01A",
+ "upload": "\uF296",
+ "download": "\uF294",
"album": "\uF2FE",
"link": "\uF0C1",
"plus": "\uF067",
"minus": "\uF068",
"eyedropper": "\uF342",
"bell": "\uF189",
- "bell_striked": "\uEE15",
- "drive"
- : "\uF410",
- "person"// FIXME
- : "\uEE15"
- // FIXME
+ "bell_striked": "\uF631",
+ "drive": "\uF410",
+ "bluetooth": "\uF682",
+ "person": "\uEE15",
+ "bar": "\uF52B",
+ "launcher": "\uF843"
}
// -------------------------------------------
From 4c9e89915e27dd7c2783f587cd2bf3344526bb13 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 17:53:55 -0400
Subject: [PATCH 025/118] Icons: more icons
---
Modules/Bar/Widgets/KeyboardLayout.qml | 2 +-
Services/FontService.qml | 63 ++++++++++++++------------
Widgets/NIcon.qml | 2 +-
3 files changed, 36 insertions(+), 31 deletions(-)
diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml
index 7de3a6d..de31920 100644
--- a/Modules/Bar/Widgets/KeyboardLayout.qml
+++ b/Modules/Bar/Widgets/KeyboardLayout.qml
@@ -24,7 +24,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
rightOpen: BarWidgetRegistry.getNPillDirection(root)
- icon: "keyboard_alt"
+ icon: FontService.icons["keyboard"]
iconCircleColor: Color.mPrimary
collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 7c773e4..5b720f3 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -14,11 +14,11 @@ Singleton {
property bool fontsLoaded: false
property var icons: {
- "sunny": "\ue30d",
+ "sunny": "\uF1D2",
"partly_cloudy": "\uF2BE",
"cloud": "\uF2C3",
"foggy": "\uF2A7",
- "rainy": "\uf29c",
+ "rainy": "\uF29C",
"snowy": "\uF2BC",
"thunderstom": "\uF2AC",
"battery_empty": "\uF188",
@@ -36,52 +36,57 @@ Singleton {
"wifi_low": "\uF619",
"wifi_half": "\uF61A",
"wifi_full": "\uF61C",
- "power": "\uf011",
- "gear": "\uF3E2",
- "close": "\uF62A",
+ "power": "\uF4FF",
+ "gear": "\uF3E5",
+ "close": "\uF659",
"check": "\uF272",
- "panel": "\uF28C",
+ "panel": "\uF2CD",
"memory": "\uF2D5",
- "trash": "\uF014",
- "image": "\uF03E",
- "refresh": "\uF021",
+ "trash": "\uF78B",
"video_camera": "\uF21C",
"ethernet": "\uF2EB",
"speed": "\uF66B",
"leaf": "\uF90B",
- "microphone": "\uED03",
+ "microphone": "\uF490",
+ "microphone_muted": "\uF48F",
"coffee": "\uF7EA",
- "thermometer": "\uE350",
- "contrast": "\uF042",
- "skull": "\uEE15",
- "paint_brush": "\uEE26",
- "paint_bucket": "\uEE3F",
+ "refresh": "\uF130",
+ "image": "\uF429",
+ "contrast": "\uF288",
+ "thermometer": "\uF908", // FIXME
+ "paint_brush": "\uEE26",
"paint_drop": "\uF30C",
- "yin_yang": "\uEEE9",
- "record": "\uEFFA",
- "pause": "\uF04C",
- "play": "\uF04B",
- "stop": "\uEFFB",
- "next": "\uF051",
- "prev": "\uF048",
- "lightning": "\uF0E7",
+ "yin_yang": "\uF8E7",
+ "record": "\uF518",
+ "pause": "\uF4C1",
+ "play": "\uF4F2",
+ "stop": "\uF590",
+ "prev": "\uF561",
+ "next": "\uF55B",
"arrow_drop_down": "\uF229",
"warning": "\uF334",
"info": "\uF26A",
"upload": "\uF296",
"download": "\uF294",
"album": "\uF2FE",
- "link": "\uF0C1",
- "plus": "\uF067",
- "minus": "\uF068",
+ "link": "\uF0C1",
+ "plus": "\uF64D",
+ "minus": "\uF63B",
"eyedropper": "\uF342",
"bell": "\uF189",
"bell_striked": "\uF631",
- "drive": "\uF410",
+ "drive": "\uF412",
"bluetooth": "\uF682",
- "person": "\uEE15",
+ "person": "\uF4DA",
"bar": "\uF52B",
- "launcher": "\uF843"
+ "launcher": "\uF843",
+ "palette": "\uF4B1",
+ "moon": "\uF494",
+ "gauge": "\uF580",
+ "lightning": "\uF46C",
+ "keyboard": "\uF451",
+
+ // another contrast \uF8F3 \uF8DA
}
// -------------------------------------------
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index 48b19eb..2f5a330 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -4,7 +4,7 @@ import qs.Commons
import qs.Widgets
Text {
- text: "\uEE15" // fallback/default to skull icon
+ text: "\uF706" // fallback/default to balloon icon
font.family: "bootstrap-icons"
font.pointSize: Style.fontSizeL * scaling
color: Color.mOnSurface
From fa970986dcbfd6e70e5da28f4b7314f669fe0d0b Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 18:45:09 -0400
Subject: [PATCH 026/118] Icons: more icons
---
Modules/Bar/Widgets/NightLight.qml | 4 ++--
Modules/SettingsPanel/SettingsPanel.qml | 6 ++---
Services/BatteryService.qml | 2 ++
Services/FontService.qml | 32 +++++++++++++------------
Widgets/NComboBox.qml | 2 +-
5 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml
index c9f302e..d3896a1 100644
--- a/Modules/Bar/Widgets/NightLight.qml
+++ b/Modules/Bar/Widgets/NightLight.qml
@@ -16,11 +16,11 @@ NIconButton {
sizeRatio: 0.8
colorBg: Color.mSurfaceVariant
- colorFg: Color.mOnSurface
+ colorFg: Settings.data.nightLight.enabled ? Color.mOnSurface : Color.mError
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: Settings.data.nightLight.enabled ? "bedtime" : "bedtime_off"
+ icon: FontService.icons["moon"]
tooltipText: `Night light: ${Settings.data.nightLight.enabled ? "enabled." : "disabled."}\nLeft click to toggle.\nRight click to access settings.`
onClicked: Settings.data.nightLight.enabled = !Settings.data.nightLight.enabled
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index 66a2315..d68db3c 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -123,7 +123,7 @@ NPanel {
let newTabs = [{
"id": SettingsPanel.Tab.General,
"label": "General",
- "icon": "general",
+ "icon": "box",
"source": generalTab
}, {
"id": SettingsPanel.Tab.Bar,
@@ -153,7 +153,7 @@ NPanel {
}, {
"id": SettingsPanel.Tab.Brightness,
"label": "Brightness",
- "icon": "brightness",
+ "icon": "brightness_high",
"source": brightnessTab
}, {
"id": SettingsPanel.Tab.Weather,
@@ -195,7 +195,7 @@ NPanel {
}, {
"id": SettingsPanel.Tab.About,
"label": "About",
- "icon": "info",
+ "icon": "macaron",
"source": aboutTab
})
diff --git a/Services/BatteryService.qml b/Services/BatteryService.qml
index 2a9dfbb..688d3eb 100644
--- a/Services/BatteryService.qml
+++ b/Services/BatteryService.qml
@@ -18,6 +18,8 @@ Singleton {
} else {
if (percent >= 85)
return FontService.icons["battery_full"]
+ if (percent >= 45)
+ return FontService.icons["battery_half"]
if (percent >= 25)
return FontService.icons["battery_low"]
if (percent >= 0)
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 5b720f3..f407732 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -30,8 +30,8 @@ Singleton {
"volume_off": "\uF60F",
"volume_half": "\uF60B",
"volume_full": "\uF611",
- "brightness_low": "\uF1CF",
- "brightness_high": "\uF1CD",
+ "brightness_low": "\uF1D4",
+ "brightness_high": "\uF1D2",
"wifi_disable": "\uF61B",
"wifi_low": "\uF619",
"wifi_half": "\uF61A",
@@ -41,20 +41,19 @@ Singleton {
"close": "\uF659",
"check": "\uF272",
"panel": "\uF2CD",
- "memory": "\uF2D5",
+ "memory": "\uF2D6",
"trash": "\uF78B",
- "video_camera": "\uF21C",
+ "video_camera": "\uF21F",
"ethernet": "\uF2EB",
"speed": "\uF66B",
- "leaf": "\uF90B",
+ "leaf": "\uF90C",
"microphone": "\uF490",
"microphone_muted": "\uF48F",
- "coffee": "\uF7EA",
+ "coffee": "\uF2E0",
"refresh": "\uF130",
- "image": "\uF429",
+ "image": "\uF226",
"contrast": "\uF288",
- "thermometer": "\uF908", // FIXME
- "paint_brush": "\uEE26",
+ "thermometer": "\uF5CD",
"paint_drop": "\uF30C",
"yin_yang": "\uF8E7",
"record": "\uF518",
@@ -63,17 +62,16 @@ Singleton {
"stop": "\uF590",
"prev": "\uF561",
"next": "\uF55B",
- "arrow_drop_down": "\uF229",
+ "arrow_drop_down": "\uF282",
"warning": "\uF334",
"info": "\uF26A",
"upload": "\uF296",
"download": "\uF294",
- "album": "\uF2FE",
- "link": "\uF0C1",
+ "album": "\uF2FF",
"plus": "\uF64D",
"minus": "\uF63B",
"eyedropper": "\uF342",
- "bell": "\uF189",
+ "bell": "\uF18A",
"bell_striked": "\uF631",
"drive": "\uF412",
"bluetooth": "\uF682",
@@ -81,11 +79,15 @@ Singleton {
"bar": "\uF52B",
"launcher": "\uF843",
"palette": "\uF4B1",
- "moon": "\uF494",
+ "moon": "\uF497",
"gauge": "\uF580",
"lightning": "\uF46C",
"keyboard": "\uF451",
-
+ "paint_brush": "\uEE26",
+ "link": "\uF470",
+ "macaron": "\uF154",
+ "box": "\uF1C8",
+ "monitor": "\uF302",
// another contrast \uF8F3 \uF8DA
}
diff --git a/Widgets/NComboBox.qml b/Widgets/NComboBox.qml
index 842479c..769602d 100644
--- a/Widgets/NComboBox.qml
+++ b/Widgets/NComboBox.qml
@@ -86,7 +86,7 @@ RowLayout {
x: combo.width - width - Style.marginM * scaling
y: combo.topPadding + (combo.availableHeight - height) / 2
text: FontService.icons["arrow_drop_down"]
- font.pointSize: Style.fontSizeXXL * scaling
+ font.pointSize: Style.fontSizeL * scaling
}
popup: Popup {
From d086d64d5fedc01db5c5463c97c79d952a355c0e Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 18:51:05 -0400
Subject: [PATCH 027/118] Icons: half of BT
---
Modules/Bar/Widgets/Bluetooth.qml | 2 +-
Modules/BluetoothPanel/BluetoothPanel.qml | 4 ++--
Services/BluetoothService.qml | 1 +
Services/FontService.qml | 4 ++--
4 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml
index 760745c..a993aec 100644
--- a/Modules/Bar/Widgets/Bluetooth.qml
+++ b/Modules/Bar/Widgets/Bluetooth.qml
@@ -20,7 +20,7 @@ NIconButton {
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: "bluetooth"
+ icon: FontService.icons["bluetooth"]
tooltipText: "Bluetooth"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this)
}
diff --git a/Modules/BluetoothPanel/BluetoothPanel.qml b/Modules/BluetoothPanel/BluetoothPanel.qml
index 312ddc3..91377df 100644
--- a/Modules/BluetoothPanel/BluetoothPanel.qml
+++ b/Modules/BluetoothPanel/BluetoothPanel.qml
@@ -28,7 +28,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: "bluetooth"
+ text: FontService.icons["bluetooth"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -42,7 +42,7 @@ NPanel {
}
NIconButton {
- icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop_circle" : "refresh"
+ icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? FontService.icons["stop"] : FontService.icons["refresh"]
tooltipText: "Refresh Devices"
sizeRatio: 0.8
onClicked: {
diff --git a/Services/BluetoothService.qml b/Services/BluetoothService.qml
index d5e2d51..bb071a8 100644
--- a/Services/BluetoothService.qml
+++ b/Services/BluetoothService.qml
@@ -49,6 +49,7 @@ Singleton {
})
}
+ // FIXME
function getDeviceIcon(device) {
if (!device) {
return "bluetooth"
diff --git a/Services/FontService.qml b/Services/FontService.qml
index f407732..67a38b4 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -40,7 +40,7 @@ Singleton {
"gear": "\uF3E5",
"close": "\uF659",
"check": "\uF272",
- "panel": "\uF2CD",
+ "panel": "\uF290",
"memory": "\uF2D6",
"trash": "\uF78B",
"video_camera": "\uF21F",
@@ -62,7 +62,7 @@ Singleton {
"stop": "\uF590",
"prev": "\uF561",
"next": "\uF55B",
- "arrow_drop_down": "\uF282",
+ "arrow_drop_down": "\uF22C",
"warning": "\uF334",
"info": "\uF26A",
"upload": "\uF296",
From b2e11137d418e6903bb7b55eaff9c72525113fa2 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 20:11:26 -0400
Subject: [PATCH 028/118] Weather icon: fix thunderstorm
---
Services/FontService.qml | 4 ++--
Services/LocationService.qml | 6 ++++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 67a38b4..1d88816 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -18,9 +18,9 @@ Singleton {
"partly_cloudy": "\uF2BE",
"cloud": "\uF2C3",
"foggy": "\uF2A7",
- "rainy": "\uF29C",
+ "rainy": "\uF29D",
"snowy": "\uF2BC",
- "thunderstom": "\uF2AC",
+ "thunderstorm": "\uF2AC",
"battery_empty": "\uF188",
"battery_low": "\uF911",
"battery_half": "\uF187",
diff --git a/Services/LocationService.qml b/Services/LocationService.qml
index 935ab04..8d5344d 100644
--- a/Services/LocationService.qml
+++ b/Services/LocationService.qml
@@ -242,8 +242,10 @@ Singleton {
return FontService.icons["rainy"]
if (code >= 71 && code <= 77)
return FontService.icons["snowy"]
- if (code >= 80 && code <= 82)
- return FontService.icons["rainy"]
+ if (code >= 71 && code <= 77)
+ return FontService.icons["snowy"]
+ if (code >= 85 && code <= 86)
+ return FontService.icons["snowy"]
if (code >= 95 && code <= 99)
return FontService.icons["thunderstorm"]
return FontService.icons["cloud"]
From 7e93e29f66b749291fea875d068ec23089f6f6c6 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 20:20:40 -0400
Subject: [PATCH 029/118] Icons: duo for nightlight
---
Modules/Bar/Widgets/NightLight.qml | 4 ++--
Services/FontService.qml | 5 +++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml
index d3896a1..a88a573 100644
--- a/Modules/Bar/Widgets/NightLight.qml
+++ b/Modules/Bar/Widgets/NightLight.qml
@@ -16,11 +16,11 @@ NIconButton {
sizeRatio: 0.8
colorBg: Color.mSurfaceVariant
- colorFg: Settings.data.nightLight.enabled ? Color.mOnSurface : Color.mError
+ colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: FontService.icons["moon"]
+ icon: Settings.data.nightLight.enabled ? FontService.icons["moon_stars"] : FontService.icons["sunrise"]
tooltipText: `Night light: ${Settings.data.nightLight.enabled ? "enabled." : "disabled."}\nLeft click to toggle.\nRight click to access settings.`
onClicked: Settings.data.nightLight.enabled = !Settings.data.nightLight.enabled
diff --git a/Services/FontService.qml b/Services/FontService.qml
index 1d88816..aa27956 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -79,9 +79,10 @@ Singleton {
"bar": "\uF52B",
"launcher": "\uF843",
"palette": "\uF4B1",
- "moon": "\uF497",
+ "sunrise": "\uF5A5",
+ "moon_stars": "\uF496",
"gauge": "\uF580",
- "lightning": "\uF46C",
+ "lightning": "\uF46D",
"keyboard": "\uF451",
"paint_brush": "\uEE26",
"link": "\uF470",
From 8da2cdf430c8cc8642570c53678028fb723f2e46 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 20:29:11 -0400
Subject: [PATCH 030/118] Icons: better nightlight and notification history
---
Modules/Bar/Widgets/NightLight.qml | 6 +++---
Modules/Bar/Widgets/NotificationHistory.qml | 2 +-
Modules/Notification/NotificationHistoryPanel.qml | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml
index a88a573..4ffeb97 100644
--- a/Modules/Bar/Widgets/NightLight.qml
+++ b/Modules/Bar/Widgets/NightLight.qml
@@ -15,12 +15,12 @@ NIconButton {
property real scaling: 1.0
sizeRatio: 0.8
- colorBg: Color.mSurfaceVariant
- colorFg: Color.mOnSurface
+ colorBg: Settings.data.nightLight.enabled ? Color.mPrimary : Color.mSurfaceVariant
+ colorFg: Settings.data.nightLight.enabled ? Color.mOnPrimary : Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: Settings.data.nightLight.enabled ? FontService.icons["moon_stars"] : FontService.icons["sunrise"]
+ icon: FontService.icons["moon_stars"]
tooltipText: `Night light: ${Settings.data.nightLight.enabled ? "enabled." : "disabled."}\nLeft click to toggle.\nRight click to access settings.`
onClicked: Settings.data.nightLight.enabled = !Settings.data.nightLight.enabled
diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml
index 2bb92cf..e223fa9 100644
--- a/Modules/Bar/Widgets/NotificationHistory.qml
+++ b/Modules/Bar/Widgets/NotificationHistory.qml
@@ -56,7 +56,7 @@ NIconButton {
icon: Settings.data.notifications.doNotDisturb ? FontService.icons["bell_striked"] : FontService.icons["bell"]
tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'."
colorBg: Color.mSurfaceVariant
- colorFg: Settings.data.notifications.doNotDisturb ? Color.mError : Color.mOnSurface
+ colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index d54cfb2..d2c1526 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -45,7 +45,7 @@ NPanel {
}
NIconButton {
- icon: Settings.data.notifications.doNotDisturb ? FontService.icons["bell"] : FontService.icons["bell_striked"]
+ icon: Settings.data.notifications.doNotDisturb ? FontService.icons["bell_striked"] : FontService.icons["bell"]
tooltipText: Settings.data.notifications.doNotDisturb ? "'Do Not Disturb' is enabled." : "'Do Not Disturb' is disabled."
sizeRatio: 0.8
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
From a4107c87c037762f4a8b7a497ac0f037d343feb8 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 21:05:48 -0400
Subject: [PATCH 031/118] Icons: WIP using a proper mapping table
---
Commons/Bootstrap.qml | 2172 +++++++++++++++++
Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml | 10 +-
Modules/Bar/Widgets/Bluetooth.qml | 2 +-
Modules/Bar/Widgets/Brightness.qml | 2 +-
Modules/Bar/Widgets/DarkModeToggle.qml | 2 +-
Modules/Bar/Widgets/KeepAwake.qml | 2 +-
Modules/Bar/Widgets/KeyboardLayout.qml | 2 +-
Modules/Bar/Widgets/MediaMini.qml | 4 +-
Modules/Bar/Widgets/NightLight.qml | 2 +-
Modules/Bar/Widgets/NotificationHistory.qml | 2 +-
Modules/Bar/Widgets/SidePanelToggle.qml | 2 +-
Modules/Bar/Widgets/SystemMonitor.qml | 10 +-
Modules/Bar/Widgets/Volume.qml | 6 +-
Modules/Bar/Widgets/WiFi.qml | 2 +-
Modules/BluetoothPanel/BluetoothPanel.qml | 7 +-
Modules/LockScreen/LockScreen.qml | 2 +-
Modules/Notification/Notification.qml | 2 +-
.../Notification/NotificationHistoryPanel.qml | 10 +-
.../SettingsPanel/Bar/BarSectionEditor.qml | 6 +-
.../Bar/BarWidgetSettingsDialog.qml | 4 +-
Modules/SettingsPanel/SettingsPanel.qml | 4 +-
Modules/SettingsPanel/Tabs/AboutTab.qml | 2 +-
Modules/SettingsPanel/Tabs/AudioTab.qml | 4 +-
Modules/SettingsPanel/Tabs/DisplayTab.qml | 2 +-
Modules/SettingsPanel/Tabs/GeneralTab.qml | 2 +-
.../Tabs/WallpaperSelectorTab.qml | 6 +-
Modules/SidePanel/Cards/MediaCard.qml | 14 +-
Modules/SidePanel/Cards/PowerProfilesCard.qml | 6 +-
Modules/SidePanel/Cards/ProfileCard.qml | 8 +-
Modules/SidePanel/Cards/SystemMonitorCard.qml | 8 +-
Modules/SidePanel/Cards/UtilitiesCard.qml | 6 +-
Modules/WiFiPanel/WiFiPanel.qml | 14 +-
Services/BatteryService.qml | 12 +-
Services/FontService.qml | 79 -
Services/LocationService.qml | 20 +-
Widgets/NColorPicker.qml | 2 +-
Widgets/NColorPickerDialog.qml | 8 +-
Widgets/NComboBox.qml | 2 +-
Widgets/NInputAction.qml | 2 +-
Widgets/NSpinBox.qml | 4 +-
Widgets/NToast.qml | 4 +-
41 files changed, 2277 insertions(+), 183 deletions(-)
create mode 100644 Commons/Bootstrap.qml
diff --git a/Commons/Bootstrap.qml b/Commons/Bootstrap.qml
new file mode 100644
index 0000000..bf55111
--- /dev/null
+++ b/Commons/Bootstrap.qml
@@ -0,0 +1,2172 @@
+pragma Singleton
+
+import QtQuick
+import QtQuick.Controls
+import Quickshell
+import qs.Commons
+
+Singleton {
+ id: root
+
+
+ // property var icons: {
+ // "sunny": "\uF1D2",
+ // "partly_cloudy": "\uF2BE",
+ // "cloud": "\uF2C3",
+ // "foggy": "\uF2A7",
+ // "rainy": "\uF29D",
+ // "snowy": "\uF2BC",
+ // "thunderstorm": "\uF2AC",
+ // "battery_empty": "\uF188",
+ // "battery_low": "\uF911",
+ // "battery_half": "\uF187",
+ // "battery_full": "\uF186",
+ // "battery_charging": "\uF185",
+ // "volume_muted": "\uF60D",
+ // "volume_off": "\uF60F",
+ // "volume_half": "\uF60B",
+ // "volume_full": "\uF611",
+ // "brightness_low": "\uF1D4",
+ // "brightness_high": "\uF1D2",
+ // "wifi_disable": "\uF61B",
+ // "wifi_low": "\uF619",
+ // "wifi_half": "\uF61A",
+ // "wifi_full": "\uF61C",
+ // "power": "\uF4FF",
+ // "gear": "\uF3E5",
+ // "close": "\uF659",
+ // "check": "\uF272",
+ // "panel": "\uF290",
+ // "memory": "\uF2D6",
+ // "trash": "\uF78B",
+ // "video_camera": "\uF21F",
+ // "ethernet": "\uF2EB",
+ // "speed": "\uF66B",
+ // "leaf": "\uF90C",
+ // "microphone": "\uF490",
+ // "microphone_muted": "\uF48F",
+ // "coffee": "\uF2E0",
+ // "refresh": "\uF130",
+ // "image": "\uF226",
+ // "contrast": "\uF288",
+ // "thermometer": "\uF5CD",
+ // "paint_drop": "\uF30C",
+ // "yin_yang": "\uF8E7",
+ // "record": "\uF518",
+ // "pause": "\uF4C1",
+ // "play": "\uF4F2",
+ // "stop": "\uF590",
+ // "prev": "\uF561",
+ // "next": "\uF55B",
+ // "arrow_drop_down": "\uF22C",
+ // "warning": "\uF334",
+ // "info": "\uF26A",
+ // "upload": "\uF296",
+ // "download": "\uF294",
+ // "album": "\uF2FF",
+ // "plus": "\uF64D",
+ // "minus": "\uF63B",
+ // "eyedropper": "\uF342",
+ // "bell": "\uF18A",
+ // "bell_striked": "\uF631",
+ // "drive": "\uF412",
+ // "bluetooth": "\uF682",
+ // "person": "\uF4DA",
+ // "bar": "\uF52B",
+ // "launcher": "\uF843",
+ // "palette": "\uF4B1",
+ // "sunrise": "\uF5A5",
+ // "moon_stars": "\uF496",
+ // "gauge": "\uF580",
+ // "lightning": "\uF46D",
+ // "keyboard": "\uF451",
+ // "paint_brush": "\uEE26",
+ // "link": "\uF470",
+ // "macaron": "\uF154",
+ // "box": "\uF1C8",
+ // "monitor": "\uF302"
+ // // another contrast \uF8F3 \uF8DA
+ // }
+
+
+
+ property var icons: {
+ "alarm-fill": "\uF101",
+ "alarm": "\uF102",
+ "align-bottom": "\uF103",
+ "align-center": "\uF104",
+ "align-end": "\uF105",
+ "align-middle": "\uF106",
+ "align-start": "\uF107",
+ "align-top": "\uF108",
+ "alt": "\uF109",
+ "app-indicator": "\uF10A",
+ "app": "\uF10B",
+ "archive-fill": "\uF10C",
+ "archive": "\uF10D",
+ "arrow-90deg-down": "\uF10E",
+ "arrow-90deg-left": "\uF10F",
+ "arrow-90deg-right": "\uF110",
+ "arrow-90deg-up": "\uF111",
+ "arrow-bar-down": "\uF112",
+ "arrow-bar-left": "\uF113",
+ "arrow-bar-right": "\uF114",
+ "arrow-bar-up": "\uF115",
+ "arrow-clockwise": "\uF116",
+ "arrow-counterclockwise": "\uF117",
+ "arrow-down-circle-fill": "\uF118",
+ "arrow-down-circle": "\uF119",
+ "arrow-down-left-circle-fill": "\uF11A",
+ "arrow-down-left-circle": "\uF11B",
+ "arrow-down-left-square-fill": "\uF11C",
+ "arrow-down-left-square": "\uF11D",
+ "arrow-down-left": "\uF11E",
+ "arrow-down-right-circle-fill": "\uF11F",
+ "arrow-down-right-circle": "\uF120",
+ "arrow-down-right-square-fill": "\uF121",
+ "arrow-down-right-square": "\uF122",
+ "arrow-down-right": "\uF123",
+ "arrow-down-short": "\uF124",
+ "arrow-down-square-fill": "\uF125",
+ "arrow-down-square": "\uF126",
+ "arrow-down-up": "\uF127",
+ "arrow-down": "\uF128",
+ "arrow-left-circle-fill": "\uF129",
+ "arrow-left-circle": "\uF12A",
+ "arrow-left-right": "\uF12B",
+ "arrow-left-short": "\uF12C",
+ "arrow-left-square-fill": "\uF12D",
+ "arrow-left-square": "\uF12E",
+ "arrow-left": "\uF12F",
+ "arrow-repeat": "\uF130",
+ "arrow-return-left": "\uF131",
+ "arrow-return-right": "\uF132",
+ "arrow-right-circle-fill": "\uF133",
+ "arrow-right-circle": "\uF134",
+ "arrow-right-short": "\uF135",
+ "arrow-right-square-fill": "\uF136",
+ "arrow-right-square": "\uF137",
+ "arrow-right": "\uF138",
+ "arrow-up-circle-fill": "\uF139",
+ "arrow-up-circle": "\uF13A",
+ "arrow-up-left-circle-fill": "\uF13B",
+ "arrow-up-left-circle": "\uF13C",
+ "arrow-up-left-square-fill": "\uF13D",
+ "arrow-up-left-square": "\uF13E",
+ "arrow-up-left": "\uF13F",
+ "arrow-up-right-circle-fill": "\uF140",
+ "arrow-up-right-circle": "\uF141",
+ "arrow-up-right-square-fill": "\uF142",
+ "arrow-up-right-square": "\uF143",
+ "arrow-up-right": "\uF144",
+ "arrow-up-short": "\uF145",
+ "arrow-up-square-fill": "\uF146",
+ "arrow-up-square": "\uF147",
+ "arrow-up": "\uF148",
+ "arrows-angle-contract": "\uF149",
+ "arrows-angle-expand": "\uF14A",
+ "arrows-collapse": "\uF14B",
+ "arrows-expand": "\uF14C",
+ "arrows-fullscreen": "\uF14D",
+ "arrows-move": "\uF14E",
+ "aspect-ratio-fill": "\uF14F",
+ "aspect-ratio": "\uF150",
+ "asterisk": "\uF151",
+ "at": "\uF152",
+ "award-fill": "\uF153",
+ "award": "\uF154",
+ "back": "\uF155",
+ "backspace-fill": "\uF156",
+ "backspace-reverse-fill": "\uF157",
+ "backspace-reverse": "\uF158",
+ "backspace": "\uF159",
+ "badge-3d-fill": "\uF15A",
+ "badge-3d": "\uF15B",
+ "badge-4k-fill": "\uF15C",
+ "badge-4k": "\uF15D",
+ "badge-8k-fill": "\uF15E",
+ "badge-8k": "\uF15F",
+ "badge-ad-fill": "\uF160",
+ "badge-ad": "\uF161",
+ "badge-ar-fill": "\uF162",
+ "badge-ar": "\uF163",
+ "badge-cc-fill": "\uF164",
+ "badge-cc": "\uF165",
+ "badge-hd-fill": "\uF166",
+ "badge-hd": "\uF167",
+ "badge-tm-fill": "\uF168",
+ "badge-tm": "\uF169",
+ "badge-vo-fill": "\uF16A",
+ "badge-vo": "\uF16B",
+ "badge-vr-fill": "\uF16C",
+ "badge-vr": "\uF16D",
+ "badge-wc-fill": "\uF16E",
+ "badge-wc": "\uF16F",
+ "bag-check-fill": "\uF170",
+ "bag-check": "\uF171",
+ "bag-dash-fill": "\uF172",
+ "bag-dash": "\uF173",
+ "bag-fill": "\uF174",
+ "bag-plus-fill": "\uF175",
+ "bag-plus": "\uF176",
+ "bag-x-fill": "\uF177",
+ "bag-x": "\uF178",
+ "bag": "\uF179",
+ "bar-chart-fill": "\uF17A",
+ "bar-chart-line-fill": "\uF17B",
+ "bar-chart-line": "\uF17C",
+ "bar-chart-steps": "\uF17D",
+ "bar-chart": "\uF17E",
+ "basket-fill": "\uF17F",
+ "basket": "\uF180",
+ "basket2-fill": "\uF181",
+ "basket2": "\uF182",
+ "basket3-fill": "\uF183",
+ "basket3": "\uF184",
+ "battery-charging": "\uF185",
+ "battery-full": "\uF186",
+ "battery-half": "\uF187",
+ "battery": "\uF188",
+ "bell-fill": "\uF189",
+ "bell": "\uF18A",
+ "bezier": "\uF18B",
+ "bezier2": "\uF18C",
+ "bicycle": "\uF18D",
+ "binoculars-fill": "\uF18E",
+ "binoculars": "\uF18F",
+ "blockquote-left": "\uF190",
+ "blockquote-right": "\uF191",
+ "book-fill": "\uF192",
+ "book-half": "\uF193",
+ "book": "\uF194",
+ "bookmark-check-fill": "\uF195",
+ "bookmark-check": "\uF196",
+ "bookmark-dash-fill": "\uF197",
+ "bookmark-dash": "\uF198",
+ "bookmark-fill": "\uF199",
+ "bookmark-heart-fill": "\uF19A",
+ "bookmark-heart": "\uF19B",
+ "bookmark-plus-fill": "\uF19C",
+ "bookmark-plus": "\uF19D",
+ "bookmark-star-fill": "\uF19E",
+ "bookmark-star": "\uF19F",
+ "bookmark-x-fill": "\uF1A0",
+ "bookmark-x": "\uF1A1",
+ "bookmark": "\uF1A2",
+ "bookmarks-fill": "\uF1A3",
+ "bookmarks": "\uF1A4",
+ "bookshelf": "\uF1A5",
+ "bootstrap-fill": "\uF1A6",
+ "bootstrap-reboot": "\uF1A7",
+ "bootstrap": "\uF1A8",
+ "border-all": "\uF1A9",
+ "border-bottom": "\uF1AA",
+ "border-center": "\uF1AB",
+ "border-inner": "\uF1AC",
+ "border-left": "\uF1AD",
+ "border-middle": "\uF1AE",
+ "border-outer": "\uF1AF",
+ "border-right": "\uF1B0",
+ "border-style": "\uF1B1",
+ "border-top": "\uF1B2",
+ "border-width": "\uF1B3",
+ "border": "\uF1B4",
+ "bounding-box-circles": "\uF1B5",
+ "bounding-box": "\uF1B6",
+ "box-arrow-down-left": "\uF1B7",
+ "box-arrow-down-right": "\uF1B8",
+ "box-arrow-down": "\uF1B9",
+ "box-arrow-in-down-left": "\uF1BA",
+ "box-arrow-in-down-right": "\uF1BB",
+ "box-arrow-in-down": "\uF1BC",
+ "box-arrow-in-left": "\uF1BD",
+ "box-arrow-in-right": "\uF1BE",
+ "box-arrow-in-up-left": "\uF1BF",
+ "box-arrow-in-up-right": "\uF1C0",
+ "box-arrow-in-up": "\uF1C1",
+ "box-arrow-left": "\uF1C2",
+ "box-arrow-right": "\uF1C3",
+ "box-arrow-up-left": "\uF1C4",
+ "box-arrow-up-right": "\uF1C5",
+ "box-arrow-up": "\uF1C6",
+ "box-seam": "\uF1C7",
+ "box": "\uF1C8",
+ "braces": "\uF1C9",
+ "bricks": "\uF1CA",
+ "briefcase-fill": "\uF1CB",
+ "briefcase": "\uF1CC",
+ "brightness-alt-high-fill": "\uF1CD",
+ "brightness-alt-high": "\uF1CE",
+ "brightness-alt-low-fill": "\uF1CF",
+ "brightness-alt-low": "\uF1D0",
+ "brightness-high-fill": "\uF1D1",
+ "brightness-high": "\uF1D2",
+ "brightness-low-fill": "\uF1D3",
+ "brightness-low": "\uF1D4",
+ "broadcast-pin": "\uF1D5",
+ "broadcast": "\uF1D6",
+ "brush-fill": "\uF1D7",
+ "brush": "\uF1D8",
+ "bucket-fill": "\uF1D9",
+ "bucket": "\uF1DA",
+ "bug-fill": "\uF1DB",
+ "bug": "\uF1DC",
+ "building": "\uF1DD",
+ "bullseye": "\uF1DE",
+ "calculator-fill": "\uF1DF",
+ "calculator": "\uF1E0",
+ "calendar-check-fill": "\uF1E1",
+ "calendar-check": "\uF1E2",
+ "calendar-date-fill": "\uF1E3",
+ "calendar-date": "\uF1E4",
+ "calendar-day-fill": "\uF1E5",
+ "calendar-day": "\uF1E6",
+ "calendar-event-fill": "\uF1E7",
+ "calendar-event": "\uF1E8",
+ "calendar-fill": "\uF1E9",
+ "calendar-minus-fill": "\uF1EA",
+ "calendar-minus": "\uF1EB",
+ "calendar-month-fill": "\uF1EC",
+ "calendar-month": "\uF1ED",
+ "calendar-plus-fill": "\uF1EE",
+ "calendar-plus": "\uF1EF",
+ "calendar-range-fill": "\uF1F0",
+ "calendar-range": "\uF1F1",
+ "calendar-week-fill": "\uF1F2",
+ "calendar-week": "\uF1F3",
+ "calendar-x-fill": "\uF1F4",
+ "calendar-x": "\uF1F5",
+ "calendar": "\uF1F6",
+ "calendar2-check-fill": "\uF1F7",
+ "calendar2-check": "\uF1F8",
+ "calendar2-date-fill": "\uF1F9",
+ "calendar2-date": "\uF1FA",
+ "calendar2-day-fill": "\uF1FB",
+ "calendar2-day": "\uF1FC",
+ "calendar2-event-fill": "\uF1FD",
+ "calendar2-event": "\uF1FE",
+ "calendar2-fill": "\uF1FF",
+ "calendar2-minus-fill": "\uF200",
+ "calendar2-minus": "\uF201",
+ "calendar2-month-fill": "\uF202",
+ "calendar2-month": "\uF203",
+ "calendar2-plus-fill": "\uF204",
+ "calendar2-plus": "\uF205",
+ "calendar2-range-fill": "\uF206",
+ "calendar2-range": "\uF207",
+ "calendar2-week-fill": "\uF208",
+ "calendar2-week": "\uF209",
+ "calendar2-x-fill": "\uF20A",
+ "calendar2-x": "\uF20B",
+ "calendar2": "\uF20C",
+ "calendar3-event-fill": "\uF20D",
+ "calendar3-event": "\uF20E",
+ "calendar3-fill": "\uF20F",
+ "calendar3-range-fill": "\uF210",
+ "calendar3-range": "\uF211",
+ "calendar3-week-fill": "\uF212",
+ "calendar3-week": "\uF213",
+ "calendar3": "\uF214",
+ "calendar4-event": "\uF215",
+ "calendar4-range": "\uF216",
+ "calendar4-week": "\uF217",
+ "calendar4": "\uF218",
+ "camera-fill": "\uF219",
+ "camera-reels-fill": "\uF21A",
+ "camera-reels": "\uF21B",
+ "camera-video-fill": "\uF21C",
+ "camera-video-off-fill": "\uF21D",
+ "camera-video-off": "\uF21E",
+ "camera-video": "\uF21F",
+ "camera": "\uF220",
+ "camera2": "\uF221",
+ "capslock-fill": "\uF222",
+ "capslock": "\uF223",
+ "card-checklist": "\uF224",
+ "card-heading": "\uF225",
+ "card-image": "\uF226",
+ "card-list": "\uF227",
+ "card-text": "\uF228",
+ "caret-down-fill": "\uF229",
+ "caret-down-square-fill": "\uF22A",
+ "caret-down-square": "\uF22B",
+ "caret-down": "\uF22C",
+ "caret-left-fill": "\uF22D",
+ "caret-left-square-fill": "\uF22E",
+ "caret-left-square": "\uF22F",
+ "caret-left": "\uF230",
+ "caret-right-fill": "\uF231",
+ "caret-right-square-fill": "\uF232",
+ "caret-right-square": "\uF233",
+ "caret-right": "\uF234",
+ "caret-up-fill": "\uF235",
+ "caret-up-square-fill": "\uF236",
+ "caret-up-square": "\uF237",
+ "caret-up": "\uF238",
+ "cart-check-fill": "\uF239",
+ "cart-check": "\uF23A",
+ "cart-dash-fill": "\uF23B",
+ "cart-dash": "\uF23C",
+ "cart-fill": "\uF23D",
+ "cart-plus-fill": "\uF23E",
+ "cart-plus": "\uF23F",
+ "cart-x-fill": "\uF240",
+ "cart-x": "\uF241",
+ "cart": "\uF242",
+ "cart2": "\uF243",
+ "cart3": "\uF244",
+ "cart4": "\uF245",
+ "cash-stack": "\uF246",
+ "cash": "\uF247",
+ "cast": "\uF248",
+ "chat-dots-fill": "\uF249",
+ "chat-dots": "\uF24A",
+ "chat-fill": "\uF24B",
+ "chat-left-dots-fill": "\uF24C",
+ "chat-left-dots": "\uF24D",
+ "chat-left-fill": "\uF24E",
+ "chat-left-quote-fill": "\uF24F",
+ "chat-left-quote": "\uF250",
+ "chat-left-text-fill": "\uF251",
+ "chat-left-text": "\uF252",
+ "chat-left": "\uF253",
+ "chat-quote-fill": "\uF254",
+ "chat-quote": "\uF255",
+ "chat-right-dots-fill": "\uF256",
+ "chat-right-dots": "\uF257",
+ "chat-right-fill": "\uF258",
+ "chat-right-quote-fill": "\uF259",
+ "chat-right-quote": "\uF25A",
+ "chat-right-text-fill": "\uF25B",
+ "chat-right-text": "\uF25C",
+ "chat-right": "\uF25D",
+ "chat-square-dots-fill": "\uF25E",
+ "chat-square-dots": "\uF25F",
+ "chat-square-fill": "\uF260",
+ "chat-square-quote-fill": "\uF261",
+ "chat-square-quote": "\uF262",
+ "chat-square-text-fill": "\uF263",
+ "chat-square-text": "\uF264",
+ "chat-square": "\uF265",
+ "chat-text-fill": "\uF266",
+ "chat-text": "\uF267",
+ "chat": "\uF268",
+ "check-all": "\uF269",
+ "check-circle-fill": "\uF26A",
+ "check-circle": "\uF26B",
+ "check-square-fill": "\uF26C",
+ "check-square": "\uF26D",
+ "check": "\uF26E",
+ "check2-all": "\uF26F",
+ "check2-circle": "\uF270",
+ "check2-square": "\uF271",
+ "check2": "\uF272",
+ "chevron-bar-contract": "\uF273",
+ "chevron-bar-down": "\uF274",
+ "chevron-bar-expand": "\uF275",
+ "chevron-bar-left": "\uF276",
+ "chevron-bar-right": "\uF277",
+ "chevron-bar-up": "\uF278",
+ "chevron-compact-down": "\uF279",
+ "chevron-compact-left": "\uF27A",
+ "chevron-compact-right": "\uF27B",
+ "chevron-compact-up": "\uF27C",
+ "chevron-contract": "\uF27D",
+ "chevron-double-down": "\uF27E",
+ "chevron-double-left": "\uF27F",
+ "chevron-double-right": "\uF280",
+ "chevron-double-up": "\uF281",
+ "chevron-down": "\uF282",
+ "chevron-expand": "\uF283",
+ "chevron-left": "\uF284",
+ "chevron-right": "\uF285",
+ "chevron-up": "\uF286",
+ "circle-fill": "\uF287",
+ "circle-half": "\uF288",
+ "circle-square": "\uF289",
+ "circle": "\uF28A",
+ "clipboard-check": "\uF28B",
+ "clipboard-data": "\uF28C",
+ "clipboard-minus": "\uF28D",
+ "clipboard-plus": "\uF28E",
+ "clipboard-x": "\uF28F",
+ "clipboard": "\uF290",
+ "clock-fill": "\uF291",
+ "clock-history": "\uF292",
+ "clock": "\uF293",
+ "cloud-arrow-down-fill": "\uF294",
+ "cloud-arrow-down": "\uF295",
+ "cloud-arrow-up-fill": "\uF296",
+ "cloud-arrow-up": "\uF297",
+ "cloud-check-fill": "\uF298",
+ "cloud-check": "\uF299",
+ "cloud-download-fill": "\uF29A",
+ "cloud-download": "\uF29B",
+ "cloud-drizzle-fill": "\uF29C",
+ "cloud-drizzle": "\uF29D",
+ "cloud-fill": "\uF29E",
+ "cloud-fog-fill": "\uF29F",
+ "cloud-fog": "\uF2A0",
+ "cloud-fog2-fill": "\uF2A1",
+ "cloud-fog2": "\uF2A2",
+ "cloud-hail-fill": "\uF2A3",
+ "cloud-hail": "\uF2A4",
+ "cloud-haze-fill": "\uF2A6",
+ "cloud-haze": "\uF2A7",
+ "cloud-haze2-fill": "\uF2A8",
+ "cloud-lightning-fill": "\uF2A9",
+ "cloud-lightning-rain-fill": "\uF2AA",
+ "cloud-lightning-rain": "\uF2AB",
+ "cloud-lightning": "\uF2AC",
+ "cloud-minus-fill": "\uF2AD",
+ "cloud-minus": "\uF2AE",
+ "cloud-moon-fill": "\uF2AF",
+ "cloud-moon": "\uF2B0",
+ "cloud-plus-fill": "\uF2B1",
+ "cloud-plus": "\uF2B2",
+ "cloud-rain-fill": "\uF2B3",
+ "cloud-rain-heavy-fill": "\uF2B4",
+ "cloud-rain-heavy": "\uF2B5",
+ "cloud-rain": "\uF2B6",
+ "cloud-slash-fill": "\uF2B7",
+ "cloud-slash": "\uF2B8",
+ "cloud-sleet-fill": "\uF2B9",
+ "cloud-sleet": "\uF2BA",
+ "cloud-snow-fill": "\uF2BB",
+ "cloud-snow": "\uF2BC",
+ "cloud-sun-fill": "\uF2BD",
+ "cloud-sun": "\uF2BE",
+ "cloud-upload-fill": "\uF2BF",
+ "cloud-upload": "\uF2C0",
+ "cloud": "\uF2C1",
+ "clouds-fill": "\uF2C2",
+ "clouds": "\uF2C3",
+ "cloudy-fill": "\uF2C4",
+ "cloudy": "\uF2C5",
+ "code-slash": "\uF2C6",
+ "code-square": "\uF2C7",
+ "code": "\uF2C8",
+ "collection-fill": "\uF2C9",
+ "collection-play-fill": "\uF2CA",
+ "collection-play": "\uF2CB",
+ "collection": "\uF2CC",
+ "columns-gap": "\uF2CD",
+ "columns": "\uF2CE",
+ "command": "\uF2CF",
+ "compass-fill": "\uF2D0",
+ "compass": "\uF2D1",
+ "cone-striped": "\uF2D2",
+ "cone": "\uF2D3",
+ "controller": "\uF2D4",
+ "cpu-fill": "\uF2D5",
+ "cpu": "\uF2D6",
+ "credit-card-2-back-fill": "\uF2D7",
+ "credit-card-2-back": "\uF2D8",
+ "credit-card-2-front-fill": "\uF2D9",
+ "credit-card-2-front": "\uF2DA",
+ "credit-card-fill": "\uF2DB",
+ "credit-card": "\uF2DC",
+ "crop": "\uF2DD",
+ "cup-fill": "\uF2DE",
+ "cup-straw": "\uF2DF",
+ "cup": "\uF2E0",
+ "cursor-fill": "\uF2E1",
+ "cursor-text": "\uF2E2",
+ "cursor": "\uF2E3",
+ "dash-circle-dotted": "\uF2E4",
+ "dash-circle-fill": "\uF2E5",
+ "dash-circle": "\uF2E6",
+ "dash-square-dotted": "\uF2E7",
+ "dash-square-fill": "\uF2E8",
+ "dash-square": "\uF2E9",
+ "dash": "\uF2EA",
+ "diagram-2-fill": "\uF2EB",
+ "diagram-2": "\uF2EC",
+ "diagram-3-fill": "\uF2ED",
+ "diagram-3": "\uF2EE",
+ "diamond-fill": "\uF2EF",
+ "diamond-half": "\uF2F0",
+ "diamond": "\uF2F1",
+ "dice-1-fill": "\uF2F2",
+ "dice-1": "\uF2F3",
+ "dice-2-fill": "\uF2F4",
+ "dice-2": "\uF2F5",
+ "dice-3-fill": "\uF2F6",
+ "dice-3": "\uF2F7",
+ "dice-4-fill": "\uF2F8",
+ "dice-4": "\uF2F9",
+ "dice-5-fill": "\uF2FA",
+ "dice-5": "\uF2FB",
+ "dice-6-fill": "\uF2FC",
+ "dice-6": "\uF2FD",
+ "disc-fill": "\uF2FE",
+ "disc": "\uF2FF",
+ "discord": "\uF300",
+ "display-fill": "\uF301",
+ "display": "\uF302",
+ "distribute-horizontal": "\uF303",
+ "distribute-vertical": "\uF304",
+ "door-closed-fill": "\uF305",
+ "door-closed": "\uF306",
+ "door-open-fill": "\uF307",
+ "door-open": "\uF308",
+ "dot": "\uF309",
+ "download": "\uF30A",
+ "droplet-fill": "\uF30B",
+ "droplet-half": "\uF30C",
+ "droplet": "\uF30D",
+ "earbuds": "\uF30E",
+ "easel-fill": "\uF30F",
+ "easel": "\uF310",
+ "egg-fill": "\uF311",
+ "egg-fried": "\uF312",
+ "egg": "\uF313",
+ "eject-fill": "\uF314",
+ "eject": "\uF315",
+ "emoji-angry-fill": "\uF316",
+ "emoji-angry": "\uF317",
+ "emoji-dizzy-fill": "\uF318",
+ "emoji-dizzy": "\uF319",
+ "emoji-expressionless-fill": "\uF31A",
+ "emoji-expressionless": "\uF31B",
+ "emoji-frown-fill": "\uF31C",
+ "emoji-frown": "\uF31D",
+ "emoji-heart-eyes-fill": "\uF31E",
+ "emoji-heart-eyes": "\uF31F",
+ "emoji-laughing-fill": "\uF320",
+ "emoji-laughing": "\uF321",
+ "emoji-neutral-fill": "\uF322",
+ "emoji-neutral": "\uF323",
+ "emoji-smile-fill": "\uF324",
+ "emoji-smile-upside-down-fill": "\uF325",
+ "emoji-smile-upside-down": "\uF326",
+ "emoji-smile": "\uF327",
+ "emoji-sunglasses-fill": "\uF328",
+ "emoji-sunglasses": "\uF329",
+ "emoji-wink-fill": "\uF32A",
+ "emoji-wink": "\uF32B",
+ "envelope-fill": "\uF32C",
+ "envelope-open-fill": "\uF32D",
+ "envelope-open": "\uF32E",
+ "envelope": "\uF32F",
+ "eraser-fill": "\uF330",
+ "eraser": "\uF331",
+ "exclamation-circle-fill": "\uF332",
+ "exclamation-circle": "\uF333",
+ "exclamation-diamond-fill": "\uF334",
+ "exclamation-diamond": "\uF335",
+ "exclamation-octagon-fill": "\uF336",
+ "exclamation-octagon": "\uF337",
+ "exclamation-square-fill": "\uF338",
+ "exclamation-square": "\uF339",
+ "exclamation-triangle-fill": "\uF33A",
+ "exclamation-triangle": "\uF33B",
+ "exclamation": "\uF33C",
+ "exclude": "\uF33D",
+ "eye-fill": "\uF33E",
+ "eye-slash-fill": "\uF33F",
+ "eye-slash": "\uF340",
+ "eye": "\uF341",
+ "eyedropper": "\uF342",
+ "eyeglasses": "\uF343",
+ "facebook": "\uF344",
+ "file-arrow-down-fill": "\uF345",
+ "file-arrow-down": "\uF346",
+ "file-arrow-up-fill": "\uF347",
+ "file-arrow-up": "\uF348",
+ "file-bar-graph-fill": "\uF349",
+ "file-bar-graph": "\uF34A",
+ "file-binary-fill": "\uF34B",
+ "file-binary": "\uF34C",
+ "file-break-fill": "\uF34D",
+ "file-break": "\uF34E",
+ "file-check-fill": "\uF34F",
+ "file-check": "\uF350",
+ "file-code-fill": "\uF351",
+ "file-code": "\uF352",
+ "file-diff-fill": "\uF353",
+ "file-diff": "\uF354",
+ "file-earmark-arrow-down-fill": "\uF355",
+ "file-earmark-arrow-down": "\uF356",
+ "file-earmark-arrow-up-fill": "\uF357",
+ "file-earmark-arrow-up": "\uF358",
+ "file-earmark-bar-graph-fill": "\uF359",
+ "file-earmark-bar-graph": "\uF35A",
+ "file-earmark-binary-fill": "\uF35B",
+ "file-earmark-binary": "\uF35C",
+ "file-earmark-break-fill": "\uF35D",
+ "file-earmark-break": "\uF35E",
+ "file-earmark-check-fill": "\uF35F",
+ "file-earmark-check": "\uF360",
+ "file-earmark-code-fill": "\uF361",
+ "file-earmark-code": "\uF362",
+ "file-earmark-diff-fill": "\uF363",
+ "file-earmark-diff": "\uF364",
+ "file-earmark-easel-fill": "\uF365",
+ "file-earmark-easel": "\uF366",
+ "file-earmark-excel-fill": "\uF367",
+ "file-earmark-excel": "\uF368",
+ "file-earmark-fill": "\uF369",
+ "file-earmark-font-fill": "\uF36A",
+ "file-earmark-font": "\uF36B",
+ "file-earmark-image-fill": "\uF36C",
+ "file-earmark-image": "\uF36D",
+ "file-earmark-lock-fill": "\uF36E",
+ "file-earmark-lock": "\uF36F",
+ "file-earmark-lock2-fill": "\uF370",
+ "file-earmark-lock2": "\uF371",
+ "file-earmark-medical-fill": "\uF372",
+ "file-earmark-medical": "\uF373",
+ "file-earmark-minus-fill": "\uF374",
+ "file-earmark-minus": "\uF375",
+ "file-earmark-music-fill": "\uF376",
+ "file-earmark-music": "\uF377",
+ "file-earmark-person-fill": "\uF378",
+ "file-earmark-person": "\uF379",
+ "file-earmark-play-fill": "\uF37A",
+ "file-earmark-play": "\uF37B",
+ "file-earmark-plus-fill": "\uF37C",
+ "file-earmark-plus": "\uF37D",
+ "file-earmark-post-fill": "\uF37E",
+ "file-earmark-post": "\uF37F",
+ "file-earmark-ppt-fill": "\uF380",
+ "file-earmark-ppt": "\uF381",
+ "file-earmark-richtext-fill": "\uF382",
+ "file-earmark-richtext": "\uF383",
+ "file-earmark-ruled-fill": "\uF384",
+ "file-earmark-ruled": "\uF385",
+ "file-earmark-slides-fill": "\uF386",
+ "file-earmark-slides": "\uF387",
+ "file-earmark-spreadsheet-fill": "\uF388",
+ "file-earmark-spreadsheet": "\uF389",
+ "file-earmark-text-fill": "\uF38A",
+ "file-earmark-text": "\uF38B",
+ "file-earmark-word-fill": "\uF38C",
+ "file-earmark-word": "\uF38D",
+ "file-earmark-x-fill": "\uF38E",
+ "file-earmark-x": "\uF38F",
+ "file-earmark-zip-fill": "\uF390",
+ "file-earmark-zip": "\uF391",
+ "file-earmark": "\uF392",
+ "file-easel-fill": "\uF393",
+ "file-easel": "\uF394",
+ "file-excel-fill": "\uF395",
+ "file-excel": "\uF396",
+ "file-fill": "\uF397",
+ "file-font-fill": "\uF398",
+ "file-font": "\uF399",
+ "file-image-fill": "\uF39A",
+ "file-image": "\uF39B",
+ "file-lock-fill": "\uF39C",
+ "file-lock": "\uF39D",
+ "file-lock2-fill": "\uF39E",
+ "file-lock2": "\uF39F",
+ "file-medical-fill": "\uF3A0",
+ "file-medical": "\uF3A1",
+ "file-minus-fill": "\uF3A2",
+ "file-minus": "\uF3A3",
+ "file-music-fill": "\uF3A4",
+ "file-music": "\uF3A5",
+ "file-person-fill": "\uF3A6",
+ "file-person": "\uF3A7",
+ "file-play-fill": "\uF3A8",
+ "file-play": "\uF3A9",
+ "file-plus-fill": "\uF3AA",
+ "file-plus": "\uF3AB",
+ "file-post-fill": "\uF3AC",
+ "file-post": "\uF3AD",
+ "file-ppt-fill": "\uF3AE",
+ "file-ppt": "\uF3AF",
+ "file-richtext-fill": "\uF3B0",
+ "file-richtext": "\uF3B1",
+ "file-ruled-fill": "\uF3B2",
+ "file-ruled": "\uF3B3",
+ "file-slides-fill": "\uF3B4",
+ "file-slides": "\uF3B5",
+ "file-spreadsheet-fill": "\uF3B6",
+ "file-spreadsheet": "\uF3B7",
+ "file-text-fill": "\uF3B8",
+ "file-text": "\uF3B9",
+ "file-word-fill": "\uF3BA",
+ "file-word": "\uF3BB",
+ "file-x-fill": "\uF3BC",
+ "file-x": "\uF3BD",
+ "file-zip-fill": "\uF3BE",
+ "file-zip": "\uF3BF",
+ "file": "\uF3C0",
+ "files-alt": "\uF3C1",
+ "files": "\uF3C2",
+ "film": "\uF3C3",
+ "filter-circle-fill": "\uF3C4",
+ "filter-circle": "\uF3C5",
+ "filter-left": "\uF3C6",
+ "filter-right": "\uF3C7",
+ "filter-square-fill": "\uF3C8",
+ "filter-square": "\uF3C9",
+ "filter": "\uF3CA",
+ "flag-fill": "\uF3CB",
+ "flag": "\uF3CC",
+ "flower1": "\uF3CD",
+ "flower2": "\uF3CE",
+ "flower3": "\uF3CF",
+ "folder-check": "\uF3D0",
+ "folder-fill": "\uF3D1",
+ "folder-minus": "\uF3D2",
+ "folder-plus": "\uF3D3",
+ "folder-symlink-fill": "\uF3D4",
+ "folder-symlink": "\uF3D5",
+ "folder-x": "\uF3D6",
+ "folder": "\uF3D7",
+ "folder2-open": "\uF3D8",
+ "folder2": "\uF3D9",
+ "fonts": "\uF3DA",
+ "forward-fill": "\uF3DB",
+ "forward": "\uF3DC",
+ "front": "\uF3DD",
+ "fullscreen-exit": "\uF3DE",
+ "fullscreen": "\uF3DF",
+ "funnel-fill": "\uF3E0",
+ "funnel": "\uF3E1",
+ "gear-fill": "\uF3E2",
+ "gear-wide-connected": "\uF3E3",
+ "gear-wide": "\uF3E4",
+ "gear": "\uF3E5",
+ "gem": "\uF3E6",
+ "geo-alt-fill": "\uF3E7",
+ "geo-alt": "\uF3E8",
+ "geo-fill": "\uF3E9",
+ "geo": "\uF3EA",
+ "gift-fill": "\uF3EB",
+ "gift": "\uF3EC",
+ "github": "\uF3ED",
+ "globe": "\uF3EE",
+ "globe2": "\uF3EF",
+ "google": "\uF3F0",
+ "graph-down": "\uF3F1",
+ "graph-up": "\uF3F2",
+ "grid-1x2-fill": "\uF3F3",
+ "grid-1x2": "\uF3F4",
+ "grid-3x2-gap-fill": "\uF3F5",
+ "grid-3x2-gap": "\uF3F6",
+ "grid-3x2": "\uF3F7",
+ "grid-3x3-gap-fill": "\uF3F8",
+ "grid-3x3-gap": "\uF3F9",
+ "grid-3x3": "\uF3FA",
+ "grid-fill": "\uF3FB",
+ "grid": "\uF3FC",
+ "grip-horizontal": "\uF3FD",
+ "grip-vertical": "\uF3FE",
+ "hammer": "\uF3FF",
+ "hand-index-fill": "\uF400",
+ "hand-index-thumb-fill": "\uF401",
+ "hand-index-thumb": "\uF402",
+ "hand-index": "\uF403",
+ "hand-thumbs-down-fill": "\uF404",
+ "hand-thumbs-down": "\uF405",
+ "hand-thumbs-up-fill": "\uF406",
+ "hand-thumbs-up": "\uF407",
+ "handbag-fill": "\uF408",
+ "handbag": "\uF409",
+ "hash": "\uF40A",
+ "hdd-fill": "\uF40B",
+ "hdd-network-fill": "\uF40C",
+ "hdd-network": "\uF40D",
+ "hdd-rack-fill": "\uF40E",
+ "hdd-rack": "\uF40F",
+ "hdd-stack-fill": "\uF410",
+ "hdd-stack": "\uF411",
+ "hdd": "\uF412",
+ "headphones": "\uF413",
+ "headset": "\uF414",
+ "heart-fill": "\uF415",
+ "heart-half": "\uF416",
+ "heart": "\uF417",
+ "heptagon-fill": "\uF418",
+ "heptagon-half": "\uF419",
+ "heptagon": "\uF41A",
+ "hexagon-fill": "\uF41B",
+ "hexagon-half": "\uF41C",
+ "hexagon": "\uF41D",
+ "hourglass-bottom": "\uF41E",
+ "hourglass-split": "\uF41F",
+ "hourglass-top": "\uF420",
+ "hourglass": "\uF421",
+ "house-door-fill": "\uF422",
+ "house-door": "\uF423",
+ "house-fill": "\uF424",
+ "house": "\uF425",
+ "hr": "\uF426",
+ "hurricane": "\uF427",
+ "image-alt": "\uF428",
+ "image-fill": "\uF429",
+ "image": "\uF42A",
+ "images": "\uF42B",
+ "inbox-fill": "\uF42C",
+ "inbox": "\uF42D",
+ "inboxes-fill": "\uF42E",
+ "inboxes": "\uF42F",
+ "info-circle-fill": "\uF430",
+ "info-circle": "\uF431",
+ "info-square-fill": "\uF432",
+ "info-square": "\uF433",
+ "info": "\uF434",
+ "input-cursor-text": "\uF435",
+ "input-cursor": "\uF436",
+ "instagram": "\uF437",
+ "intersect": "\uF438",
+ "journal-album": "\uF439",
+ "journal-arrow-down": "\uF43A",
+ "journal-arrow-up": "\uF43B",
+ "journal-bookmark-fill": "\uF43C",
+ "journal-bookmark": "\uF43D",
+ "journal-check": "\uF43E",
+ "journal-code": "\uF43F",
+ "journal-medical": "\uF440",
+ "journal-minus": "\uF441",
+ "journal-plus": "\uF442",
+ "journal-richtext": "\uF443",
+ "journal-text": "\uF444",
+ "journal-x": "\uF445",
+ "journal": "\uF446",
+ "journals": "\uF447",
+ "joystick": "\uF448",
+ "justify-left": "\uF449",
+ "justify-right": "\uF44A",
+ "justify": "\uF44B",
+ "kanban-fill": "\uF44C",
+ "kanban": "\uF44D",
+ "key-fill": "\uF44E",
+ "key": "\uF44F",
+ "keyboard-fill": "\uF450",
+ "keyboard": "\uF451",
+ "ladder": "\uF452",
+ "lamp-fill": "\uF453",
+ "lamp": "\uF454",
+ "laptop-fill": "\uF455",
+ "laptop": "\uF456",
+ "layer-backward": "\uF457",
+ "layer-forward": "\uF458",
+ "layers-fill": "\uF459",
+ "layers-half": "\uF45A",
+ "layers": "\uF45B",
+ "layout-sidebar-inset-reverse": "\uF45C",
+ "layout-sidebar-inset": "\uF45D",
+ "layout-sidebar-reverse": "\uF45E",
+ "layout-sidebar": "\uF45F",
+ "layout-split": "\uF460",
+ "layout-text-sidebar-reverse": "\uF461",
+ "layout-text-sidebar": "\uF462",
+ "layout-text-window-reverse": "\uF463",
+ "layout-text-window": "\uF464",
+ "layout-three-columns": "\uF465",
+ "layout-wtf": "\uF466",
+ "life-preserver": "\uF467",
+ "lightbulb-fill": "\uF468",
+ "lightbulb-off-fill": "\uF469",
+ "lightbulb-off": "\uF46A",
+ "lightbulb": "\uF46B",
+ "lightning-charge-fill": "\uF46C",
+ "lightning-charge": "\uF46D",
+ "lightning-fill": "\uF46E",
+ "lightning": "\uF46F",
+ "link-45deg": "\uF470",
+ "link": "\uF471",
+ "linkedin": "\uF472",
+ "list-check": "\uF473",
+ "list-nested": "\uF474",
+ "list-ol": "\uF475",
+ "list-stars": "\uF476",
+ "list-task": "\uF477",
+ "list-ul": "\uF478",
+ "list": "\uF479",
+ "lock-fill": "\uF47A",
+ "lock": "\uF47B",
+ "mailbox": "\uF47C",
+ "mailbox2": "\uF47D",
+ "map-fill": "\uF47E",
+ "map": "\uF47F",
+ "markdown-fill": "\uF480",
+ "markdown": "\uF481",
+ "mask": "\uF482",
+ "megaphone-fill": "\uF483",
+ "megaphone": "\uF484",
+ "menu-app-fill": "\uF485",
+ "menu-app": "\uF486",
+ "menu-button-fill": "\uF487",
+ "menu-button-wide-fill": "\uF488",
+ "menu-button-wide": "\uF489",
+ "menu-button": "\uF48A",
+ "menu-down": "\uF48B",
+ "menu-up": "\uF48C",
+ "mic-fill": "\uF48D",
+ "mic-mute-fill": "\uF48E",
+ "mic-mute": "\uF48F",
+ "mic": "\uF490",
+ "minecart-loaded": "\uF491",
+ "minecart": "\uF492",
+ "moisture": "\uF493",
+ "moon-fill": "\uF494",
+ "moon-stars-fill": "\uF495",
+ "moon-stars": "\uF496",
+ "moon": "\uF497",
+ "mouse-fill": "\uF498",
+ "mouse": "\uF499",
+ "mouse2-fill": "\uF49A",
+ "mouse2": "\uF49B",
+ "mouse3-fill": "\uF49C",
+ "mouse3": "\uF49D",
+ "music-note-beamed": "\uF49E",
+ "music-note-list": "\uF49F",
+ "music-note": "\uF4A0",
+ "music-player-fill": "\uF4A1",
+ "music-player": "\uF4A2",
+ "newspaper": "\uF4A3",
+ "node-minus-fill": "\uF4A4",
+ "node-minus": "\uF4A5",
+ "node-plus-fill": "\uF4A6",
+ "node-plus": "\uF4A7",
+ "nut-fill": "\uF4A8",
+ "nut": "\uF4A9",
+ "octagon-fill": "\uF4AA",
+ "octagon-half": "\uF4AB",
+ "octagon": "\uF4AC",
+ "option": "\uF4AD",
+ "outlet": "\uF4AE",
+ "paint-bucket": "\uF4AF",
+ "palette-fill": "\uF4B0",
+ "palette": "\uF4B1",
+ "palette2": "\uF4B2",
+ "paperclip": "\uF4B3",
+ "paragraph": "\uF4B4",
+ "patch-check-fill": "\uF4B5",
+ "patch-check": "\uF4B6",
+ "patch-exclamation-fill": "\uF4B7",
+ "patch-exclamation": "\uF4B8",
+ "patch-minus-fill": "\uF4B9",
+ "patch-minus": "\uF4BA",
+ "patch-plus-fill": "\uF4BB",
+ "patch-plus": "\uF4BC",
+ "patch-question-fill": "\uF4BD",
+ "patch-question": "\uF4BE",
+ "pause-btn-fill": "\uF4BF",
+ "pause-btn": "\uF4C0",
+ "pause-circle-fill": "\uF4C1",
+ "pause-circle": "\uF4C2",
+ "pause-fill": "\uF4C3",
+ "pause": "\uF4C4",
+ "peace-fill": "\uF4C5",
+ "peace": "\uF4C6",
+ "pen-fill": "\uF4C7",
+ "pen": "\uF4C8",
+ "pencil-fill": "\uF4C9",
+ "pencil-square": "\uF4CA",
+ "pencil": "\uF4CB",
+ "pentagon-fill": "\uF4CC",
+ "pentagon-half": "\uF4CD",
+ "pentagon": "\uF4CE",
+ "people-fill": "\uF4CF",
+ "people": "\uF4D0",
+ "percent": "\uF4D1",
+ "person-badge-fill": "\uF4D2",
+ "person-badge": "\uF4D3",
+ "person-bounding-box": "\uF4D4",
+ "person-check-fill": "\uF4D5",
+ "person-check": "\uF4D6",
+ "person-circle": "\uF4D7",
+ "person-dash-fill": "\uF4D8",
+ "person-dash": "\uF4D9",
+ "person-fill": "\uF4DA",
+ "person-lines-fill": "\uF4DB",
+ "person-plus-fill": "\uF4DC",
+ "person-plus": "\uF4DD",
+ "person-square": "\uF4DE",
+ "person-x-fill": "\uF4DF",
+ "person-x": "\uF4E0",
+ "person": "\uF4E1",
+ "phone-fill": "\uF4E2",
+ "phone-landscape-fill": "\uF4E3",
+ "phone-landscape": "\uF4E4",
+ "phone-vibrate-fill": "\uF4E5",
+ "phone-vibrate": "\uF4E6",
+ "phone": "\uF4E7",
+ "pie-chart-fill": "\uF4E8",
+ "pie-chart": "\uF4E9",
+ "pin-angle-fill": "\uF4EA",
+ "pin-angle": "\uF4EB",
+ "pin-fill": "\uF4EC",
+ "pin": "\uF4ED",
+ "pip-fill": "\uF4EE",
+ "pip": "\uF4EF",
+ "play-btn-fill": "\uF4F0",
+ "play-btn": "\uF4F1",
+ "play-circle-fill": "\uF4F2",
+ "play-circle": "\uF4F3",
+ "play-fill": "\uF4F4",
+ "play": "\uF4F5",
+ "plug-fill": "\uF4F6",
+ "plug": "\uF4F7",
+ "plus-circle-dotted": "\uF4F8",
+ "plus-circle-fill": "\uF4F9",
+ "plus-circle": "\uF4FA",
+ "plus-square-dotted": "\uF4FB",
+ "plus-square-fill": "\uF4FC",
+ "plus-square": "\uF4FD",
+ "plus": "\uF4FE",
+ "power": "\uF4FF",
+ "printer-fill": "\uF500",
+ "printer": "\uF501",
+ "puzzle-fill": "\uF502",
+ "puzzle": "\uF503",
+ "question-circle-fill": "\uF504",
+ "question-circle": "\uF505",
+ "question-diamond-fill": "\uF506",
+ "question-diamond": "\uF507",
+ "question-octagon-fill": "\uF508",
+ "question-octagon": "\uF509",
+ "question-square-fill": "\uF50A",
+ "question-square": "\uF50B",
+ "question": "\uF50C",
+ "rainbow": "\uF50D",
+ "receipt-cutoff": "\uF50E",
+ "receipt": "\uF50F",
+ "reception-0": "\uF510",
+ "reception-1": "\uF511",
+ "reception-2": "\uF512",
+ "reception-3": "\uF513",
+ "reception-4": "\uF514",
+ "record-btn-fill": "\uF515",
+ "record-btn": "\uF516",
+ "record-circle-fill": "\uF517",
+ "record-circle": "\uF518",
+ "record-fill": "\uF519",
+ "record": "\uF51A",
+ "record2-fill": "\uF51B",
+ "record2": "\uF51C",
+ "reply-all-fill": "\uF51D",
+ "reply-all": "\uF51E",
+ "reply-fill": "\uF51F",
+ "reply": "\uF520",
+ "rss-fill": "\uF521",
+ "rss": "\uF522",
+ "rulers": "\uF523",
+ "save-fill": "\uF524",
+ "save": "\uF525",
+ "save2-fill": "\uF526",
+ "save2": "\uF527",
+ "scissors": "\uF528",
+ "screwdriver": "\uF529",
+ "search": "\uF52A",
+ "segmented-nav": "\uF52B",
+ "server": "\uF52C",
+ "share-fill": "\uF52D",
+ "share": "\uF52E",
+ "shield-check": "\uF52F",
+ "shield-exclamation": "\uF530",
+ "shield-fill-check": "\uF531",
+ "shield-fill-exclamation": "\uF532",
+ "shield-fill-minus": "\uF533",
+ "shield-fill-plus": "\uF534",
+ "shield-fill-x": "\uF535",
+ "shield-fill": "\uF536",
+ "shield-lock-fill": "\uF537",
+ "shield-lock": "\uF538",
+ "shield-minus": "\uF539",
+ "shield-plus": "\uF53A",
+ "shield-shaded": "\uF53B",
+ "shield-slash-fill": "\uF53C",
+ "shield-slash": "\uF53D",
+ "shield-x": "\uF53E",
+ "shield": "\uF53F",
+ "shift-fill": "\uF540",
+ "shift": "\uF541",
+ "shop-window": "\uF542",
+ "shop": "\uF543",
+ "shuffle": "\uF544",
+ "signpost-2-fill": "\uF545",
+ "signpost-2": "\uF546",
+ "signpost-fill": "\uF547",
+ "signpost-split-fill": "\uF548",
+ "signpost-split": "\uF549",
+ "signpost": "\uF54A",
+ "sim-fill": "\uF54B",
+ "sim": "\uF54C",
+ "skip-backward-btn-fill": "\uF54D",
+ "skip-backward-btn": "\uF54E",
+ "skip-backward-circle-fill": "\uF54F",
+ "skip-backward-circle": "\uF550",
+ "skip-backward-fill": "\uF551",
+ "skip-backward": "\uF552",
+ "skip-end-btn-fill": "\uF553",
+ "skip-end-btn": "\uF554",
+ "skip-end-circle-fill": "\uF555",
+ "skip-end-circle": "\uF556",
+ "skip-end-fill": "\uF557",
+ "skip-end": "\uF558",
+ "skip-forward-btn-fill": "\uF559",
+ "skip-forward-btn": "\uF55A",
+ "skip-forward-circle-fill": "\uF55B",
+ "skip-forward-circle": "\uF55C",
+ "skip-forward-fill": "\uF55D",
+ "skip-forward": "\uF55E",
+ "skip-start-btn-fill": "\uF55F",
+ "skip-start-btn": "\uF560",
+ "skip-start-circle-fill": "\uF561",
+ "skip-start-circle": "\uF562",
+ "skip-start-fill": "\uF563",
+ "skip-start": "\uF564",
+ "slack": "\uF565",
+ "slash-circle-fill": "\uF566",
+ "slash-circle": "\uF567",
+ "slash-square-fill": "\uF568",
+ "slash-square": "\uF569",
+ "slash": "\uF56A",
+ "sliders": "\uF56B",
+ "smartwatch": "\uF56C",
+ "snow": "\uF56D",
+ "snow2": "\uF56E",
+ "snow3": "\uF56F",
+ "sort-alpha-down-alt": "\uF570",
+ "sort-alpha-down": "\uF571",
+ "sort-alpha-up-alt": "\uF572",
+ "sort-alpha-up": "\uF573",
+ "sort-down-alt": "\uF574",
+ "sort-down": "\uF575",
+ "sort-numeric-down-alt": "\uF576",
+ "sort-numeric-down": "\uF577",
+ "sort-numeric-up-alt": "\uF578",
+ "sort-numeric-up": "\uF579",
+ "sort-up-alt": "\uF57A",
+ "sort-up": "\uF57B",
+ "soundwave": "\uF57C",
+ "speaker-fill": "\uF57D",
+ "speaker": "\uF57E",
+ "speedometer": "\uF57F",
+ "speedometer2": "\uF580",
+ "spellcheck": "\uF581",
+ "square-fill": "\uF582",
+ "square-half": "\uF583",
+ "square": "\uF584",
+ "stack": "\uF585",
+ "star-fill": "\uF586",
+ "star-half": "\uF587",
+ "star": "\uF588",
+ "stars": "\uF589",
+ "stickies-fill": "\uF58A",
+ "stickies": "\uF58B",
+ "sticky-fill": "\uF58C",
+ "sticky": "\uF58D",
+ "stop-btn-fill": "\uF58E",
+ "stop-btn": "\uF58F",
+ "stop-circle-fill": "\uF590",
+ "stop-circle": "\uF591",
+ "stop-fill": "\uF592",
+ "stop": "\uF593",
+ "stoplights-fill": "\uF594",
+ "stoplights": "\uF595",
+ "stopwatch-fill": "\uF596",
+ "stopwatch": "\uF597",
+ "subtract": "\uF598",
+ "suit-club-fill": "\uF599",
+ "suit-club": "\uF59A",
+ "suit-diamond-fill": "\uF59B",
+ "suit-diamond": "\uF59C",
+ "suit-heart-fill": "\uF59D",
+ "suit-heart": "\uF59E",
+ "suit-spade-fill": "\uF59F",
+ "suit-spade": "\uF5A0",
+ "sun-fill": "\uF5A1",
+ "sun": "\uF5A2",
+ "sunglasses": "\uF5A3",
+ "sunrise-fill": "\uF5A4",
+ "sunrise": "\uF5A5",
+ "sunset-fill": "\uF5A6",
+ "sunset": "\uF5A7",
+ "symmetry-horizontal": "\uF5A8",
+ "symmetry-vertical": "\uF5A9",
+ "table": "\uF5AA",
+ "tablet-fill": "\uF5AB",
+ "tablet-landscape-fill": "\uF5AC",
+ "tablet-landscape": "\uF5AD",
+ "tablet": "\uF5AE",
+ "tag-fill": "\uF5AF",
+ "tag": "\uF5B0",
+ "tags-fill": "\uF5B1",
+ "tags": "\uF5B2",
+ "telegram": "\uF5B3",
+ "telephone-fill": "\uF5B4",
+ "telephone-forward-fill": "\uF5B5",
+ "telephone-forward": "\uF5B6",
+ "telephone-inbound-fill": "\uF5B7",
+ "telephone-inbound": "\uF5B8",
+ "telephone-minus-fill": "\uF5B9",
+ "telephone-minus": "\uF5BA",
+ "telephone-outbound-fill": "\uF5BB",
+ "telephone-outbound": "\uF5BC",
+ "telephone-plus-fill": "\uF5BD",
+ "telephone-plus": "\uF5BE",
+ "telephone-x-fill": "\uF5BF",
+ "telephone-x": "\uF5C0",
+ "telephone": "\uF5C1",
+ "terminal-fill": "\uF5C2",
+ "terminal": "\uF5C3",
+ "text-center": "\uF5C4",
+ "text-indent-left": "\uF5C5",
+ "text-indent-right": "\uF5C6",
+ "text-left": "\uF5C7",
+ "text-paragraph": "\uF5C8",
+ "text-right": "\uF5C9",
+ "textarea-resize": "\uF5CA",
+ "textarea-t": "\uF5CB",
+ "textarea": "\uF5CC",
+ "thermometer-half": "\uF5CD",
+ "thermometer-high": "\uF5CE",
+ "thermometer-low": "\uF5CF",
+ "thermometer-snow": "\uF5D0",
+ "thermometer-sun": "\uF5D1",
+ "thermometer": "\uF5D2",
+ "three-dots-vertical": "\uF5D3",
+ "three-dots": "\uF5D4",
+ "toggle-off": "\uF5D5",
+ "toggle-on": "\uF5D6",
+ "toggle2-off": "\uF5D7",
+ "toggle2-on": "\uF5D8",
+ "toggles": "\uF5D9",
+ "toggles2": "\uF5DA",
+ "tools": "\uF5DB",
+ "tornado": "\uF5DC",
+ "trash-fill": "\uF5DD",
+ "trash": "\uF5DE",
+ "trash2-fill": "\uF5DF",
+ "trash2": "\uF5E0",
+ "tree-fill": "\uF5E1",
+ "tree": "\uF5E2",
+ "triangle-fill": "\uF5E3",
+ "triangle-half": "\uF5E4",
+ "triangle": "\uF5E5",
+ "trophy-fill": "\uF5E6",
+ "trophy": "\uF5E7",
+ "tropical-storm": "\uF5E8",
+ "truck-flatbed": "\uF5E9",
+ "truck": "\uF5EA",
+ "tsunami": "\uF5EB",
+ "tv-fill": "\uF5EC",
+ "tv": "\uF5ED",
+ "twitch": "\uF5EE",
+ "twitter": "\uF5EF",
+ "type-bold": "\uF5F0",
+ "type-h1": "\uF5F1",
+ "type-h2": "\uF5F2",
+ "type-h3": "\uF5F3",
+ "type-italic": "\uF5F4",
+ "type-strikethrough": "\uF5F5",
+ "type-underline": "\uF5F6",
+ "type": "\uF5F7",
+ "ui-checks-grid": "\uF5F8",
+ "ui-checks": "\uF5F9",
+ "ui-radios-grid": "\uF5FA",
+ "ui-radios": "\uF5FB",
+ "umbrella-fill": "\uF5FC",
+ "umbrella": "\uF5FD",
+ "union": "\uF5FE",
+ "unlock-fill": "\uF5FF",
+ "unlock": "\uF600",
+ "upc-scan": "\uF601",
+ "upc": "\uF602",
+ "upload": "\uF603",
+ "vector-pen": "\uF604",
+ "view-list": "\uF605",
+ "view-stacked": "\uF606",
+ "vinyl-fill": "\uF607",
+ "vinyl": "\uF608",
+ "voicemail": "\uF609",
+ "volume-down-fill": "\uF60A",
+ "volume-down": "\uF60B",
+ "volume-mute-fill": "\uF60C",
+ "volume-mute": "\uF60D",
+ "volume-off-fill": "\uF60E",
+ "volume-off": "\uF60F",
+ "volume-up-fill": "\uF610",
+ "volume-up": "\uF611",
+ "vr": "\uF612",
+ "wallet-fill": "\uF613",
+ "wallet": "\uF614",
+ "wallet2": "\uF615",
+ "watch": "\uF616",
+ "water": "\uF617",
+ "whatsapp": "\uF618",
+ "wifi-1": "\uF619",
+ "wifi-2": "\uF61A",
+ "wifi-off": "\uF61B",
+ "wifi": "\uF61C",
+ "wind": "\uF61D",
+ "window-dock": "\uF61E",
+ "window-sidebar": "\uF61F",
+ "window": "\uF620",
+ "wrench": "\uF621",
+ "x-circle-fill": "\uF622",
+ "x-circle": "\uF623",
+ "x-diamond-fill": "\uF624",
+ "x-diamond": "\uF625",
+ "x-octagon-fill": "\uF626",
+ "x-octagon": "\uF627",
+ "x-square-fill": "\uF628",
+ "x-square": "\uF629",
+ "x": "\uF62A",
+ "youtube": "\uF62B",
+ "zoom-in": "\uF62C",
+ "zoom-out": "\uF62D",
+ "bank": "\uF62E",
+ "bank2": "\uF62F",
+ "bell-slash-fill": "\uF630",
+ "bell-slash": "\uF631",
+ "cash-coin": "\uF632",
+ "check-lg": "\uF633",
+ "coin": "\uF634",
+ "currency-bitcoin": "\uF635",
+ "currency-dollar": "\uF636",
+ "currency-euro": "\uF637",
+ "currency-exchange": "\uF638",
+ "currency-pound": "\uF639",
+ "currency-yen": "\uF63A",
+ "dash-lg": "\uF63B",
+ "exclamation-lg": "\uF63C",
+ "file-earmark-pdf-fill": "\uF63D",
+ "file-earmark-pdf": "\uF63E",
+ "file-pdf-fill": "\uF63F",
+ "file-pdf": "\uF640",
+ "gender-ambiguous": "\uF641",
+ "gender-female": "\uF642",
+ "gender-male": "\uF643",
+ "gender-trans": "\uF644",
+ "headset-vr": "\uF645",
+ "info-lg": "\uF646",
+ "mastodon": "\uF647",
+ "messenger": "\uF648",
+ "piggy-bank-fill": "\uF649",
+ "piggy-bank": "\uF64A",
+ "pin-map-fill": "\uF64B",
+ "pin-map": "\uF64C",
+ "plus-lg": "\uF64D",
+ "question-lg": "\uF64E",
+ "recycle": "\uF64F",
+ "reddit": "\uF650",
+ "safe-fill": "\uF651",
+ "safe2-fill": "\uF652",
+ "safe2": "\uF653",
+ "sd-card-fill": "\uF654",
+ "sd-card": "\uF655",
+ "skype": "\uF656",
+ "slash-lg": "\uF657",
+ "translate": "\uF658",
+ "x-lg": "\uF659",
+ "safe": "\uF65A",
+ "apple": "\uF65B",
+ "microsoft": "\uF65D",
+ "windows": "\uF65E",
+ "behance": "\uF65C",
+ "dribbble": "\uF65F",
+ "line": "\uF660",
+ "medium": "\uF661",
+ "paypal": "\uF662",
+ "pinterest": "\uF663",
+ "signal": "\uF664",
+ "snapchat": "\uF665",
+ "spotify": "\uF666",
+ "stack-overflow": "\uF667",
+ "strava": "\uF668",
+ "wordpress": "\uF669",
+ "vimeo": "\uF66A",
+ "activity": "\uF66B",
+ "easel2-fill": "\uF66C",
+ "easel2": "\uF66D",
+ "easel3-fill": "\uF66E",
+ "easel3": "\uF66F",
+ "fan": "\uF670",
+ "fingerprint": "\uF671",
+ "graph-down-arrow": "\uF672",
+ "graph-up-arrow": "\uF673",
+ "hypnotize": "\uF674",
+ "magic": "\uF675",
+ "person-rolodex": "\uF676",
+ "person-video": "\uF677",
+ "person-video2": "\uF678",
+ "person-video3": "\uF679",
+ "person-workspace": "\uF67A",
+ "radioactive": "\uF67B",
+ "webcam-fill": "\uF67C",
+ "webcam": "\uF67D",
+ "yin-yang": "\uF67E",
+ "bandaid-fill": "\uF680",
+ "bandaid": "\uF681",
+ "bluetooth": "\uF682",
+ "body-text": "\uF683",
+ "boombox": "\uF684",
+ "boxes": "\uF685",
+ "dpad-fill": "\uF686",
+ "dpad": "\uF687",
+ "ear-fill": "\uF688",
+ "ear": "\uF689",
+ "envelope-check-fill": "\uF68B",
+ "envelope-check": "\uF68C",
+ "envelope-dash-fill": "\uF68E",
+ "envelope-dash": "\uF68F",
+ "envelope-exclamation-fill": "\uF691",
+ "envelope-exclamation": "\uF692",
+ "envelope-plus-fill": "\uF693",
+ "envelope-plus": "\uF694",
+ "envelope-slash-fill": "\uF696",
+ "envelope-slash": "\uF697",
+ "envelope-x-fill": "\uF699",
+ "envelope-x": "\uF69A",
+ "explicit-fill": "\uF69B",
+ "explicit": "\uF69C",
+ "git": "\uF69D",
+ "infinity": "\uF69E",
+ "list-columns-reverse": "\uF69F",
+ "list-columns": "\uF6A0",
+ "meta": "\uF6A1",
+ "nintendo-switch": "\uF6A4",
+ "pc-display-horizontal": "\uF6A5",
+ "pc-display": "\uF6A6",
+ "pc-horizontal": "\uF6A7",
+ "pc": "\uF6A8",
+ "playstation": "\uF6A9",
+ "plus-slash-minus": "\uF6AA",
+ "projector-fill": "\uF6AB",
+ "projector": "\uF6AC",
+ "qr-code-scan": "\uF6AD",
+ "qr-code": "\uF6AE",
+ "quora": "\uF6AF",
+ "quote": "\uF6B0",
+ "robot": "\uF6B1",
+ "send-check-fill": "\uF6B2",
+ "send-check": "\uF6B3",
+ "send-dash-fill": "\uF6B4",
+ "send-dash": "\uF6B5",
+ "send-exclamation-fill": "\uF6B7",
+ "send-exclamation": "\uF6B8",
+ "send-fill": "\uF6B9",
+ "send-plus-fill": "\uF6BA",
+ "send-plus": "\uF6BB",
+ "send-slash-fill": "\uF6BC",
+ "send-slash": "\uF6BD",
+ "send-x-fill": "\uF6BE",
+ "send-x": "\uF6BF",
+ "send": "\uF6C0",
+ "steam": "\uF6C1",
+ "terminal-dash": "\uF6C3",
+ "terminal-plus": "\uF6C4",
+ "terminal-split": "\uF6C5",
+ "ticket-detailed-fill": "\uF6C6",
+ "ticket-detailed": "\uF6C7",
+ "ticket-fill": "\uF6C8",
+ "ticket-perforated-fill": "\uF6C9",
+ "ticket-perforated": "\uF6CA",
+ "ticket": "\uF6CB",
+ "tiktok": "\uF6CC",
+ "window-dash": "\uF6CD",
+ "window-desktop": "\uF6CE",
+ "window-fullscreen": "\uF6CF",
+ "window-plus": "\uF6D0",
+ "window-split": "\uF6D1",
+ "window-stack": "\uF6D2",
+ "window-x": "\uF6D3",
+ "xbox": "\uF6D4",
+ "ethernet": "\uF6D5",
+ "hdmi-fill": "\uF6D6",
+ "hdmi": "\uF6D7",
+ "usb-c-fill": "\uF6D8",
+ "usb-c": "\uF6D9",
+ "usb-fill": "\uF6DA",
+ "usb-plug-fill": "\uF6DB",
+ "usb-plug": "\uF6DC",
+ "usb-symbol": "\uF6DD",
+ "usb": "\uF6DE",
+ "boombox-fill": "\uF6DF",
+ "displayport": "\uF6E1",
+ "gpu-card": "\uF6E2",
+ "memory": "\uF6E3",
+ "modem-fill": "\uF6E4",
+ "modem": "\uF6E5",
+ "motherboard-fill": "\uF6E6",
+ "motherboard": "\uF6E7",
+ "optical-audio-fill": "\uF6E8",
+ "optical-audio": "\uF6E9",
+ "pci-card": "\uF6EA",
+ "router-fill": "\uF6EB",
+ "router": "\uF6EC",
+ "thunderbolt-fill": "\uF6EF",
+ "thunderbolt": "\uF6F0",
+ "usb-drive-fill": "\uF6F1",
+ "usb-drive": "\uF6F2",
+ "usb-micro-fill": "\uF6F3",
+ "usb-micro": "\uF6F4",
+ "usb-mini-fill": "\uF6F5",
+ "usb-mini": "\uF6F6",
+ "cloud-haze2": "\uF6F7",
+ "device-hdd-fill": "\uF6F8",
+ "device-hdd": "\uF6F9",
+ "device-ssd-fill": "\uF6FA",
+ "device-ssd": "\uF6FB",
+ "displayport-fill": "\uF6FC",
+ "mortarboard-fill": "\uF6FD",
+ "mortarboard": "\uF6FE",
+ "terminal-x": "\uF6FF",
+ "arrow-through-heart-fill": "\uF700",
+ "arrow-through-heart": "\uF701",
+ "badge-sd-fill": "\uF702",
+ "badge-sd": "\uF703",
+ "bag-heart-fill": "\uF704",
+ "bag-heart": "\uF705",
+ "balloon-fill": "\uF706",
+ "balloon-heart-fill": "\uF707",
+ "balloon-heart": "\uF708",
+ "balloon": "\uF709",
+ "box2-fill": "\uF70A",
+ "box2-heart-fill": "\uF70B",
+ "box2-heart": "\uF70C",
+ "box2": "\uF70D",
+ "braces-asterisk": "\uF70E",
+ "calendar-heart-fill": "\uF70F",
+ "calendar-heart": "\uF710",
+ "calendar2-heart-fill": "\uF711",
+ "calendar2-heart": "\uF712",
+ "chat-heart-fill": "\uF713",
+ "chat-heart": "\uF714",
+ "chat-left-heart-fill": "\uF715",
+ "chat-left-heart": "\uF716",
+ "chat-right-heart-fill": "\uF717",
+ "chat-right-heart": "\uF718",
+ "chat-square-heart-fill": "\uF719",
+ "chat-square-heart": "\uF71A",
+ "clipboard-check-fill": "\uF71B",
+ "clipboard-data-fill": "\uF71C",
+ "clipboard-fill": "\uF71D",
+ "clipboard-heart-fill": "\uF71E",
+ "clipboard-heart": "\uF71F",
+ "clipboard-minus-fill": "\uF720",
+ "clipboard-plus-fill": "\uF721",
+ "clipboard-pulse": "\uF722",
+ "clipboard-x-fill": "\uF723",
+ "clipboard2-check-fill": "\uF724",
+ "clipboard2-check": "\uF725",
+ "clipboard2-data-fill": "\uF726",
+ "clipboard2-data": "\uF727",
+ "clipboard2-fill": "\uF728",
+ "clipboard2-heart-fill": "\uF729",
+ "clipboard2-heart": "\uF72A",
+ "clipboard2-minus-fill": "\uF72B",
+ "clipboard2-minus": "\uF72C",
+ "clipboard2-plus-fill": "\uF72D",
+ "clipboard2-plus": "\uF72E",
+ "clipboard2-pulse-fill": "\uF72F",
+ "clipboard2-pulse": "\uF730",
+ "clipboard2-x-fill": "\uF731",
+ "clipboard2-x": "\uF732",
+ "clipboard2": "\uF733",
+ "emoji-kiss-fill": "\uF734",
+ "emoji-kiss": "\uF735",
+ "envelope-heart-fill": "\uF736",
+ "envelope-heart": "\uF737",
+ "envelope-open-heart-fill": "\uF738",
+ "envelope-open-heart": "\uF739",
+ "envelope-paper-fill": "\uF73A",
+ "envelope-paper-heart-fill": "\uF73B",
+ "envelope-paper-heart": "\uF73C",
+ "envelope-paper": "\uF73D",
+ "filetype-aac": "\uF73E",
+ "filetype-ai": "\uF73F",
+ "filetype-bmp": "\uF740",
+ "filetype-cs": "\uF741",
+ "filetype-css": "\uF742",
+ "filetype-csv": "\uF743",
+ "filetype-doc": "\uF744",
+ "filetype-docx": "\uF745",
+ "filetype-exe": "\uF746",
+ "filetype-gif": "\uF747",
+ "filetype-heic": "\uF748",
+ "filetype-html": "\uF749",
+ "filetype-java": "\uF74A",
+ "filetype-jpg": "\uF74B",
+ "filetype-js": "\uF74C",
+ "filetype-jsx": "\uF74D",
+ "filetype-key": "\uF74E",
+ "filetype-m4p": "\uF74F",
+ "filetype-md": "\uF750",
+ "filetype-mdx": "\uF751",
+ "filetype-mov": "\uF752",
+ "filetype-mp3": "\uF753",
+ "filetype-mp4": "\uF754",
+ "filetype-otf": "\uF755",
+ "filetype-pdf": "\uF756",
+ "filetype-php": "\uF757",
+ "filetype-png": "\uF758",
+ "filetype-ppt": "\uF75A",
+ "filetype-psd": "\uF75B",
+ "filetype-py": "\uF75C",
+ "filetype-raw": "\uF75D",
+ "filetype-rb": "\uF75E",
+ "filetype-sass": "\uF75F",
+ "filetype-scss": "\uF760",
+ "filetype-sh": "\uF761",
+ "filetype-svg": "\uF762",
+ "filetype-tiff": "\uF763",
+ "filetype-tsx": "\uF764",
+ "filetype-ttf": "\uF765",
+ "filetype-txt": "\uF766",
+ "filetype-wav": "\uF767",
+ "filetype-woff": "\uF768",
+ "filetype-xls": "\uF76A",
+ "filetype-xml": "\uF76B",
+ "filetype-yml": "\uF76C",
+ "heart-arrow": "\uF76D",
+ "heart-pulse-fill": "\uF76E",
+ "heart-pulse": "\uF76F",
+ "heartbreak-fill": "\uF770",
+ "heartbreak": "\uF771",
+ "hearts": "\uF772",
+ "hospital-fill": "\uF773",
+ "hospital": "\uF774",
+ "house-heart-fill": "\uF775",
+ "house-heart": "\uF776",
+ "incognito": "\uF777",
+ "magnet-fill": "\uF778",
+ "magnet": "\uF779",
+ "person-heart": "\uF77A",
+ "person-hearts": "\uF77B",
+ "phone-flip": "\uF77C",
+ "plugin": "\uF77D",
+ "postage-fill": "\uF77E",
+ "postage-heart-fill": "\uF77F",
+ "postage-heart": "\uF780",
+ "postage": "\uF781",
+ "postcard-fill": "\uF782",
+ "postcard-heart-fill": "\uF783",
+ "postcard-heart": "\uF784",
+ "postcard": "\uF785",
+ "search-heart-fill": "\uF786",
+ "search-heart": "\uF787",
+ "sliders2-vertical": "\uF788",
+ "sliders2": "\uF789",
+ "trash3-fill": "\uF78A",
+ "trash3": "\uF78B",
+ "valentine": "\uF78C",
+ "valentine2": "\uF78D",
+ "wrench-adjustable-circle-fill": "\uF78E",
+ "wrench-adjustable-circle": "\uF78F",
+ "wrench-adjustable": "\uF790",
+ "filetype-json": "\uF791",
+ "filetype-pptx": "\uF792",
+ "filetype-xlsx": "\uF793",
+ "1-circle-fill": "\uF796",
+ "1-circle": "\uF797",
+ "1-square-fill": "\uF798",
+ "1-square": "\uF799",
+ "2-circle-fill": "\uF79C",
+ "2-circle": "\uF79D",
+ "2-square-fill": "\uF79E",
+ "2-square": "\uF79F",
+ "3-circle-fill": "\uF7A2",
+ "3-circle": "\uF7A3",
+ "3-square-fill": "\uF7A4",
+ "3-square": "\uF7A5",
+ "4-circle-fill": "\uF7A8",
+ "4-circle": "\uF7A9",
+ "4-square-fill": "\uF7AA",
+ "4-square": "\uF7AB",
+ "5-circle-fill": "\uF7AE",
+ "5-circle": "\uF7AF",
+ "5-square-fill": "\uF7B0",
+ "5-square": "\uF7B1",
+ "6-circle-fill": "\uF7B4",
+ "6-circle": "\uF7B5",
+ "6-square-fill": "\uF7B6",
+ "6-square": "\uF7B7",
+ "7-circle-fill": "\uF7BA",
+ "7-circle": "\uF7BB",
+ "7-square-fill": "\uF7BC",
+ "7-square": "\uF7BD",
+ "8-circle-fill": "\uF7C0",
+ "8-circle": "\uF7C1",
+ "8-square-fill": "\uF7C2",
+ "8-square": "\uF7C3",
+ "9-circle-fill": "\uF7C6",
+ "9-circle": "\uF7C7",
+ "9-square-fill": "\uF7C8",
+ "9-square": "\uF7C9",
+ "airplane-engines-fill": "\uF7CA",
+ "airplane-engines": "\uF7CB",
+ "airplane-fill": "\uF7CC",
+ "airplane": "\uF7CD",
+ "alexa": "\uF7CE",
+ "alipay": "\uF7CF",
+ "android": "\uF7D0",
+ "android2": "\uF7D1",
+ "box-fill": "\uF7D2",
+ "box-seam-fill": "\uF7D3",
+ "browser-chrome": "\uF7D4",
+ "browser-edge": "\uF7D5",
+ "browser-firefox": "\uF7D6",
+ "browser-safari": "\uF7D7",
+ "c-circle-fill": "\uF7DA",
+ "c-circle": "\uF7DB",
+ "c-square-fill": "\uF7DC",
+ "c-square": "\uF7DD",
+ "capsule-pill": "\uF7DE",
+ "capsule": "\uF7DF",
+ "car-front-fill": "\uF7E0",
+ "car-front": "\uF7E1",
+ "cassette-fill": "\uF7E2",
+ "cassette": "\uF7E3",
+ "cc-circle-fill": "\uF7E6",
+ "cc-circle": "\uF7E7",
+ "cc-square-fill": "\uF7E8",
+ "cc-square": "\uF7E9",
+ "cup-hot-fill": "\uF7EA",
+ "cup-hot": "\uF7EB",
+ "currency-rupee": "\uF7EC",
+ "dropbox": "\uF7ED",
+ "escape": "\uF7EE",
+ "fast-forward-btn-fill": "\uF7EF",
+ "fast-forward-btn": "\uF7F0",
+ "fast-forward-circle-fill": "\uF7F1",
+ "fast-forward-circle": "\uF7F2",
+ "fast-forward-fill": "\uF7F3",
+ "fast-forward": "\uF7F4",
+ "filetype-sql": "\uF7F5",
+ "fire": "\uF7F6",
+ "google-play": "\uF7F7",
+ "h-circle-fill": "\uF7FA",
+ "h-circle": "\uF7FB",
+ "h-square-fill": "\uF7FC",
+ "h-square": "\uF7FD",
+ "indent": "\uF7FE",
+ "lungs-fill": "\uF7FF",
+ "lungs": "\uF800",
+ "microsoft-teams": "\uF801",
+ "p-circle-fill": "\uF804",
+ "p-circle": "\uF805",
+ "p-square-fill": "\uF806",
+ "p-square": "\uF807",
+ "pass-fill": "\uF808",
+ "pass": "\uF809",
+ "prescription": "\uF80A",
+ "prescription2": "\uF80B",
+ "r-circle-fill": "\uF80E",
+ "r-circle": "\uF80F",
+ "r-square-fill": "\uF810",
+ "r-square": "\uF811",
+ "repeat-1": "\uF812",
+ "repeat": "\uF813",
+ "rewind-btn-fill": "\uF814",
+ "rewind-btn": "\uF815",
+ "rewind-circle-fill": "\uF816",
+ "rewind-circle": "\uF817",
+ "rewind-fill": "\uF818",
+ "rewind": "\uF819",
+ "train-freight-front-fill": "\uF81A",
+ "train-freight-front": "\uF81B",
+ "train-front-fill": "\uF81C",
+ "train-front": "\uF81D",
+ "train-lightrail-front-fill": "\uF81E",
+ "train-lightrail-front": "\uF81F",
+ "truck-front-fill": "\uF820",
+ "truck-front": "\uF821",
+ "ubuntu": "\uF822",
+ "unindent": "\uF823",
+ "unity": "\uF824",
+ "universal-access-circle": "\uF825",
+ "universal-access": "\uF826",
+ "virus": "\uF827",
+ "virus2": "\uF828",
+ "wechat": "\uF829",
+ "yelp": "\uF82A",
+ "sign-stop-fill": "\uF82B",
+ "sign-stop-lights-fill": "\uF82C",
+ "sign-stop-lights": "\uF82D",
+ "sign-stop": "\uF82E",
+ "sign-turn-left-fill": "\uF82F",
+ "sign-turn-left": "\uF830",
+ "sign-turn-right-fill": "\uF831",
+ "sign-turn-right": "\uF832",
+ "sign-turn-slight-left-fill": "\uF833",
+ "sign-turn-slight-left": "\uF834",
+ "sign-turn-slight-right-fill": "\uF835",
+ "sign-turn-slight-right": "\uF836",
+ "sign-yield-fill": "\uF837",
+ "sign-yield": "\uF838",
+ "ev-station-fill": "\uF839",
+ "ev-station": "\uF83A",
+ "fuel-pump-diesel-fill": "\uF83B",
+ "fuel-pump-diesel": "\uF83C",
+ "fuel-pump-fill": "\uF83D",
+ "fuel-pump": "\uF83E",
+ "0-circle-fill": "\uF83F",
+ "0-circle": "\uF840",
+ "0-square-fill": "\uF841",
+ "0-square": "\uF842",
+ "rocket-fill": "\uF843",
+ "rocket-takeoff-fill": "\uF844",
+ "rocket-takeoff": "\uF845",
+ "rocket": "\uF846",
+ "stripe": "\uF847",
+ "subscript": "\uF848",
+ "superscript": "\uF849",
+ "trello": "\uF84A",
+ "envelope-at-fill": "\uF84B",
+ "envelope-at": "\uF84C",
+ "regex": "\uF84D",
+ "text-wrap": "\uF84E",
+ "sign-dead-end-fill": "\uF84F",
+ "sign-dead-end": "\uF850",
+ "sign-do-not-enter-fill": "\uF851",
+ "sign-do-not-enter": "\uF852",
+ "sign-intersection-fill": "\uF853",
+ "sign-intersection-side-fill": "\uF854",
+ "sign-intersection-side": "\uF855",
+ "sign-intersection-t-fill": "\uF856",
+ "sign-intersection-t": "\uF857",
+ "sign-intersection-y-fill": "\uF858",
+ "sign-intersection-y": "\uF859",
+ "sign-intersection": "\uF85A",
+ "sign-merge-left-fill": "\uF85B",
+ "sign-merge-left": "\uF85C",
+ "sign-merge-right-fill": "\uF85D",
+ "sign-merge-right": "\uF85E",
+ "sign-no-left-turn-fill": "\uF85F",
+ "sign-no-left-turn": "\uF860",
+ "sign-no-parking-fill": "\uF861",
+ "sign-no-parking": "\uF862",
+ "sign-no-right-turn-fill": "\uF863",
+ "sign-no-right-turn": "\uF864",
+ "sign-railroad-fill": "\uF865",
+ "sign-railroad": "\uF866",
+ "building-add": "\uF867",
+ "building-check": "\uF868",
+ "building-dash": "\uF869",
+ "building-down": "\uF86A",
+ "building-exclamation": "\uF86B",
+ "building-fill-add": "\uF86C",
+ "building-fill-check": "\uF86D",
+ "building-fill-dash": "\uF86E",
+ "building-fill-down": "\uF86F",
+ "building-fill-exclamation": "\uF870",
+ "building-fill-gear": "\uF871",
+ "building-fill-lock": "\uF872",
+ "building-fill-slash": "\uF873",
+ "building-fill-up": "\uF874",
+ "building-fill-x": "\uF875",
+ "building-fill": "\uF876",
+ "building-gear": "\uF877",
+ "building-lock": "\uF878",
+ "building-slash": "\uF879",
+ "building-up": "\uF87A",
+ "building-x": "\uF87B",
+ "buildings-fill": "\uF87C",
+ "buildings": "\uF87D",
+ "bus-front-fill": "\uF87E",
+ "bus-front": "\uF87F",
+ "ev-front-fill": "\uF880",
+ "ev-front": "\uF881",
+ "globe-americas": "\uF882",
+ "globe-asia-australia": "\uF883",
+ "globe-central-south-asia": "\uF884",
+ "globe-europe-africa": "\uF885",
+ "house-add-fill": "\uF886",
+ "house-add": "\uF887",
+ "house-check-fill": "\uF888",
+ "house-check": "\uF889",
+ "house-dash-fill": "\uF88A",
+ "house-dash": "\uF88B",
+ "house-down-fill": "\uF88C",
+ "house-down": "\uF88D",
+ "house-exclamation-fill": "\uF88E",
+ "house-exclamation": "\uF88F",
+ "house-gear-fill": "\uF890",
+ "house-gear": "\uF891",
+ "house-lock-fill": "\uF892",
+ "house-lock": "\uF893",
+ "house-slash-fill": "\uF894",
+ "house-slash": "\uF895",
+ "house-up-fill": "\uF896",
+ "house-up": "\uF897",
+ "house-x-fill": "\uF898",
+ "house-x": "\uF899",
+ "person-add": "\uF89A",
+ "person-down": "\uF89B",
+ "person-exclamation": "\uF89C",
+ "person-fill-add": "\uF89D",
+ "person-fill-check": "\uF89E",
+ "person-fill-dash": "\uF89F",
+ "person-fill-down": "\uF8A0",
+ "person-fill-exclamation": "\uF8A1",
+ "person-fill-gear": "\uF8A2",
+ "person-fill-lock": "\uF8A3",
+ "person-fill-slash": "\uF8A4",
+ "person-fill-up": "\uF8A5",
+ "person-fill-x": "\uF8A6",
+ "person-gear": "\uF8A7",
+ "person-lock": "\uF8A8",
+ "person-slash": "\uF8A9",
+ "person-up": "\uF8AA",
+ "scooter": "\uF8AB",
+ "taxi-front-fill": "\uF8AC",
+ "taxi-front": "\uF8AD",
+ "amd": "\uF8AE",
+ "database-add": "\uF8AF",
+ "database-check": "\uF8B0",
+ "database-dash": "\uF8B1",
+ "database-down": "\uF8B2",
+ "database-exclamation": "\uF8B3",
+ "database-fill-add": "\uF8B4",
+ "database-fill-check": "\uF8B5",
+ "database-fill-dash": "\uF8B6",
+ "database-fill-down": "\uF8B7",
+ "database-fill-exclamation": "\uF8B8",
+ "database-fill-gear": "\uF8B9",
+ "database-fill-lock": "\uF8BA",
+ "database-fill-slash": "\uF8BB",
+ "database-fill-up": "\uF8BC",
+ "database-fill-x": "\uF8BD",
+ "database-fill": "\uF8BE",
+ "database-gear": "\uF8BF",
+ "database-lock": "\uF8C0",
+ "database-slash": "\uF8C1",
+ "database-up": "\uF8C2",
+ "database-x": "\uF8C3",
+ "database": "\uF8C4",
+ "houses-fill": "\uF8C5",
+ "houses": "\uF8C6",
+ "nvidia": "\uF8C7",
+ "person-vcard-fill": "\uF8C8",
+ "person-vcard": "\uF8C9",
+ "sina-weibo": "\uF8CA",
+ "tencent-qq": "\uF8CB",
+ "wikipedia": "\uF8CC",
+ "alphabet-uppercase": "\uF2A5",
+ "alphabet": "\uF68A",
+ "amazon": "\uF695",
+ "arrows-collapse-vertical": "\uF698",
+ "arrows-expand-vertical": "\uF69D",
+ "arrows-vertical": "\uF6A0",
+ "arrows": "\uF6A2",
+ "ban-fill": "\uF6A3",
+ "ban": "\uF6B6",
+ "bing": "\uF6C2",
+ "cake": "\uF6E0",
+ "cake2": "\uF6ED",
+ "cookie": "\uF6EE",
+ "copy": "\uF759",
+ "crosshair": "\uF769",
+ "crosshair2": "\uF794",
+ "emoji-astonished-fill": "\uF795",
+ "emoji-astonished": "\uF79A",
+ "emoji-grimace-fill": "\uF79B",
+ "emoji-grimace": "\uF7A0",
+ "emoji-grin-fill": "\uF7A1",
+ "emoji-grin": "\uF7A6",
+ "emoji-surprise-fill": "\uF7A7",
+ "emoji-surprise": "\uF7AC",
+ "emoji-tear-fill": "\uF7AD",
+ "emoji-tear": "\uF7B2",
+ "envelope-arrow-down-fill": "\uF7B3",
+ "envelope-arrow-down": "\uF7B8",
+ "envelope-arrow-up-fill": "\uF7B9",
+ "envelope-arrow-up": "\uF7BE",
+ "feather": "\uF7BF",
+ "feather2": "\uF7C4",
+ "floppy-fill": "\uF7C5",
+ "floppy": "\uF7D8",
+ "floppy2-fill": "\uF7D9",
+ "floppy2": "\uF7E4",
+ "gitlab": "\uF7E5",
+ "highlighter": "\uF7F8",
+ "marker-tip": "\uF802",
+ "nvme-fill": "\uF803",
+ "nvme": "\uF80C",
+ "opencollective": "\uF80D",
+ "pci-card-network": "\uF8CD",
+ "pci-card-sound": "\uF8CE",
+ "radar": "\uF8CF",
+ "send-arrow-down-fill": "\uF8D0",
+ "send-arrow-down": "\uF8D1",
+ "send-arrow-up-fill": "\uF8D2",
+ "send-arrow-up": "\uF8D3",
+ "sim-slash-fill": "\uF8D4",
+ "sim-slash": "\uF8D5",
+ "sourceforge": "\uF8D6",
+ "substack": "\uF8D7",
+ "threads-fill": "\uF8D8",
+ "threads": "\uF8D9",
+ "transparency": "\uF8DA",
+ "twitter-x": "\uF8DB",
+ "type-h4": "\uF8DC",
+ "type-h5": "\uF8DD",
+ "type-h6": "\uF8DE",
+ "backpack-fill": "\uF8DF",
+ "backpack": "\uF8E0",
+ "backpack2-fill": "\uF8E1",
+ "backpack2": "\uF8E2",
+ "backpack3-fill": "\uF8E3",
+ "backpack3": "\uF8E4",
+ "backpack4-fill": "\uF8E5",
+ "backpack4": "\uF8E6",
+ "brilliance": "\uF8E7",
+ "cake-fill": "\uF8E8",
+ "cake2-fill": "\uF8E9",
+ "duffle-fill": "\uF8EA",
+ "duffle": "\uF8EB",
+ "exposure": "\uF8EC",
+ "gender-neuter": "\uF8ED",
+ "highlights": "\uF8EE",
+ "luggage-fill": "\uF8EF",
+ "luggage": "\uF8F0",
+ "mailbox-flag": "\uF8F1",
+ "mailbox2-flag": "\uF8F2",
+ "noise-reduction": "\uF8F3",
+ "passport-fill": "\uF8F4",
+ "passport": "\uF8F5",
+ "person-arms-up": "\uF8F6",
+ "person-raised-hand": "\uF8F7",
+ "person-standing-dress": "\uF8F8",
+ "person-standing": "\uF8F9",
+ "person-walking": "\uF8FA",
+ "person-wheelchair": "\uF8FB",
+ "shadows": "\uF8FC",
+ "suitcase-fill": "\uF8FD",
+ "suitcase-lg-fill": "\uF8FE",
+ "suitcase-lg": "\uF8FF",
+ "suitcase": "\uF900",
+ "suitcase2-fill": "\uF901",
+ "suitcase2": "\uF902",
+ "vignette": "\uF903",
+ "bluesky": "\uF7F9",
+ "tux": "\uF904",
+ "beaker-fill": "\uF905",
+ "beaker": "\uF906",
+ "flask-fill": "\uF907",
+ "flask-florence-fill": "\uF908",
+ "flask-florence": "\uF909",
+ "flask": "\uF90A",
+ "leaf-fill": "\uF90B",
+ "leaf": "\uF90C",
+ "measuring-cup-fill": "\uF90D",
+ "measuring-cup": "\uF90E",
+ "unlock2-fill": "\uF90F",
+ "unlock2": "\uF910",
+ "battery-low": "\uF911",
+ "anthropic": "\uF912",
+ "apple-music": "\uF913",
+ "claude": "\uF914",
+ "openai": "\uF915",
+ "perplexity": "\uF916",
+ "css": "\uF917",
+ "javascript": "\uF918",
+ "typescript": "\uF919",
+ "fork-knife": "\uF91A",
+ "globe-americas-fill": "\uF91B",
+ "globe-asia-australia-fill": "\uF91C",
+ "globe-central-south-asia-fill": "\uF91D",
+ "globe-europe-africa-fill": "\uF91E"
+ }
+}
diff --git a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
index cbe3886..e5b798c 100644
--- a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
+++ b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
@@ -44,7 +44,7 @@ NPanel {
// Reset button (only show if update failed)
NIconButton {
visible: ArchUpdaterService.updateFailed
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
tooltipText: "Reset update state"
sizeRatio: 0.8
colorBg: Color.mError
@@ -55,7 +55,7 @@ NPanel {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
@@ -245,7 +245,7 @@ NPanel {
// Prominent refresh button
NIconButton {
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
tooltipText: "Try checking again"
sizeRatio: 1.2
colorBg: Color.mPrimary
@@ -295,7 +295,7 @@ NPanel {
// Prominent refresh button
NIconButton {
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
tooltipText: "Refresh and try again"
sizeRatio: 1.2
colorBg: Color.mPrimary
@@ -483,7 +483,7 @@ NPanel {
spacing: Style.marginL * scaling
NIconButton {
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
tooltipText: ArchUpdaterService.aurBusy ? "Checking for updates..." : (!ArchUpdaterService.canPoll ? "Refresh available soon" : "Refresh package lists")
onClicked: {
ArchUpdaterService.forceRefresh()
diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml
index a993aec..599e40d 100644
--- a/Modules/Bar/Widgets/Bluetooth.qml
+++ b/Modules/Bar/Widgets/Bluetooth.qml
@@ -20,7 +20,7 @@ NIconButton {
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: FontService.icons["bluetooth"]
+ icon: Bootstrap.icons["bluetooth"]
tooltipText: "Bluetooth"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this)
}
diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml
index 4c3cb0e..a1ed557 100644
--- a/Modules/Bar/Widgets/Brightness.qml
+++ b/Modules/Bar/Widgets/Brightness.qml
@@ -46,7 +46,7 @@ Item {
function getIcon() {
var monitor = getMonitor()
var brightness = monitor ? monitor.brightness : 0
- return brightness <= 0.5 ? FontService.icons["brightness_low"] : FontService.icons["brightness_high"]
+ return brightness <= 0.5 ? Bootstrap.icons["brightness_low"] : Bootstrap.icons["brightness_high"]
}
// Connection used to open the pill when brightness changes
diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml
index 3ba55f3..53f60f9 100644
--- a/Modules/Bar/Widgets/DarkModeToggle.qml
+++ b/Modules/Bar/Widgets/DarkModeToggle.qml
@@ -9,7 +9,7 @@ NIconButton {
property ShellScreen screen
property real scaling: 1.0
- icon: FontService.icons["contrast"]
+ icon: Bootstrap.icons["contrast"]
tooltipText: "Toggle light/dark mode"
sizeRatio: 0.8
diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml
index d13612a..ae588f5 100644
--- a/Modules/Bar/Widgets/KeepAwake.qml
+++ b/Modules/Bar/Widgets/KeepAwake.qml
@@ -13,7 +13,7 @@ NIconButton {
sizeRatio: 0.8
- icon: FontService.icons["coffee"]
+ icon: Bootstrap.icons["coffee"]
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake"
colorBg: Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mOnSurface
diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml
index de31920..387316e 100644
--- a/Modules/Bar/Widgets/KeyboardLayout.qml
+++ b/Modules/Bar/Widgets/KeyboardLayout.qml
@@ -24,7 +24,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
rightOpen: BarWidgetRegistry.getNPillDirection(root)
- icon: FontService.icons["keyboard"]
+ icon: Bootstrap.icons["keyboard"]
iconCircleColor: Color.mPrimary
collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index a620f32..f7a42b5 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -134,7 +134,7 @@ RowLayout {
NIcon {
id: windowIcon
- text: MediaService.isPlaying ? FontService.icons["pause"] : FontService.icons["play"]
+ text: MediaService.isPlaying ? Bootstrap.icons["pause"] : Bootstrap.icons["play"]
font.pointSize: Style.fontSizeL * scaling
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignVCenter
@@ -154,7 +154,7 @@ RowLayout {
id: trackArt
anchors.fill: parent
imagePath: MediaService.trackArtUrl
- fallbackIcon: MediaService.isPlaying ? FontService.icons["pause"] : FontService.icons["play"]
+ fallbackIcon: MediaService.isPlaying ? Bootstrap.icons["pause"] : Bootstrap.icons["play"]
fallbackIconSize: 10 * scaling
borderWidth: 0
border.color: Color.transparent
diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml
index 4ffeb97..0de4f72 100644
--- a/Modules/Bar/Widgets/NightLight.qml
+++ b/Modules/Bar/Widgets/NightLight.qml
@@ -20,7 +20,7 @@ NIconButton {
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: FontService.icons["moon_stars"]
+ icon: Bootstrap.icons["moon-stars"]
tooltipText: `Night light: ${Settings.data.nightLight.enabled ? "enabled." : "disabled."}\nLeft click to toggle.\nRight click to access settings.`
onClicked: Settings.data.nightLight.enabled = !Settings.data.nightLight.enabled
diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml
index e223fa9..a0836c3 100644
--- a/Modules/Bar/Widgets/NotificationHistory.qml
+++ b/Modules/Bar/Widgets/NotificationHistory.qml
@@ -53,7 +53,7 @@ NIconButton {
}
sizeRatio: 0.8
- icon: Settings.data.notifications.doNotDisturb ? FontService.icons["bell_striked"] : FontService.icons["bell"]
+ icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell_striked"] : Bootstrap.icons["bell"]
tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'."
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml
index 39cc752..ada2796 100644
--- a/Modules/Bar/Widgets/SidePanelToggle.qml
+++ b/Modules/Bar/Widgets/SidePanelToggle.qml
@@ -33,7 +33,7 @@ NIconButton {
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo
!== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
- icon: useDistroLogo ? "" : FontService.icons["panel"]
+ icon: useDistroLogo ? "" : Bootstrap.icons["panel"]
tooltipText: "Open side panel."
sizeRatio: 0.8
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index d8fe84a..58cfc90 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -66,7 +66,7 @@ RowLayout {
NIcon {
id: cpuUsageIcon
- text: FontService.icons["speed"]
+ text: Bootstrap.icons["speed"]
Layout.alignment: Qt.AlignVCenter
}
@@ -91,7 +91,7 @@ RowLayout {
visible: showCpuTemp
NIcon {
- text: FontService.icons["thermometer"]
+ text: Bootstrap.icons["thermometer"]
Layout.alignment: Qt.AlignVCenter
}
@@ -114,7 +114,7 @@ RowLayout {
visible: showMemoryUsage
NIcon {
- text: FontService.icons["memory"]
+ text: Bootstrap.icons["memory"]
Layout.alignment: Qt.AlignVCenter
}
@@ -137,7 +137,7 @@ RowLayout {
visible: showNetworkStats
NIcon {
- text: FontService.icons["download"]
+ text: Bootstrap.icons["download"]
Layout.alignment: Qt.AlignVCenter
}
@@ -160,7 +160,7 @@ RowLayout {
visible: showNetworkStats
NIcon {
- text: FontService.icons["upload"]
+ text: Bootstrap.icons["upload"]
Layout.alignment: Qt.AlignVCenter
}
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index cde2693..1db94ec 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -43,11 +43,11 @@ Item {
function getIcon() {
if (AudioService.muted) {
- return FontService.icons["volume_muted"]
+ return Bootstrap.icons["volume_muted"]
}
return AudioService.volume
- <= Number.EPSILON ? FontService.icons["volume_off"] : (AudioService.volume
- < 0.5 ? FontService.icons["volume_half"] : FontService.icons["volume_full"])
+ <= Number.EPSILON ? Bootstrap.icons["volume_off"] : (AudioService.volume
+ < 0.5 ? Bootstrap.icons["volume_half"] : Bootstrap.icons["volume_full"])
}
// Connection used to open the pill when volume changes
diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml
index 80120a4..bcbde44 100644
--- a/Modules/Bar/Widgets/WiFi.qml
+++ b/Modules/Bar/Widgets/WiFi.qml
@@ -23,7 +23,7 @@ NIconButton {
icon: {
try {
if (NetworkService.ethernetConnected) {
- return FontService.icons["ethernet"]
+ return Bootstrap.icons["ethernet"]
}
let connected = false
let signalStrength = 0
diff --git a/Modules/BluetoothPanel/BluetoothPanel.qml b/Modules/BluetoothPanel/BluetoothPanel.qml
index 91377df..958a293 100644
--- a/Modules/BluetoothPanel/BluetoothPanel.qml
+++ b/Modules/BluetoothPanel/BluetoothPanel.qml
@@ -28,7 +28,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: FontService.icons["bluetooth"]
+ text: Bootstrap.icons["bluetooth"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -42,7 +42,8 @@ NPanel {
}
NIconButton {
- icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? FontService.icons["stop"] : FontService.icons["refresh"]
+ icon: BluetoothService.adapter
+ && BluetoothService.adapter.discovering ? Bootstrap.icons["stop"] : Bootstrap.icons["arrow-repeat"]
tooltipText: "Refresh Devices"
sizeRatio: 0.8
onClicked: {
@@ -53,7 +54,7 @@ NPanel {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml
index dfe77a6..ee048a1 100644
--- a/Modules/LockScreen/LockScreen.qml
+++ b/Modules/LockScreen/LockScreen.qml
@@ -328,7 +328,7 @@ Loader {
width: 100 * scaling
height: 100 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: FontService.icons["person"]
+ fallbackIcon: Bootstrap.icons["person"]
}
MouseArea {
diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml
index f6b1510..e699d85 100644
--- a/Modules/Notification/Notification.qml
+++ b/Modules/Notification/Notification.qml
@@ -294,7 +294,7 @@ Variants {
// Close button positioned absolutely
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
tooltipText: "Close"
sizeRatio: 0.6
anchors.top: parent.top
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index d2c1526..7d2c1f0 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -31,7 +31,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: FontService.icons["bell"]
+ text: Bootstrap.icons["bell"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -45,21 +45,21 @@ NPanel {
}
NIconButton {
- icon: Settings.data.notifications.doNotDisturb ? FontService.icons["bell_striked"] : FontService.icons["bell"]
+ icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell_striked"] : Bootstrap.icons["bell"]
tooltipText: Settings.data.notifications.doNotDisturb ? "'Do Not Disturb' is enabled." : "'Do Not Disturb' is disabled."
sizeRatio: 0.8
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
}
NIconButton {
- icon: FontService.icons["trash"]
+ icon: Bootstrap.icons["trash"]
tooltipText: "Clear history"
sizeRatio: 0.8
onClicked: NotificationService.clearHistory()
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
@@ -175,7 +175,7 @@ NPanel {
// Delete button
NIconButton {
- icon: FontService.icons["trash"]
+ icon: Bootstrap.icons["trash"]
tooltipText: "Delete notification"
sizeRatio: 0.7
Layout.alignment: Qt.AlignTop
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index 42b259d..86c0863 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -85,7 +85,7 @@ NBox {
}
NIconButton {
- icon: FontService.icons["plus"]
+ icon: Bootstrap.icons["plus"]
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
@@ -170,7 +170,7 @@ NBox {
Loader {
active: BarWidgetRegistry.widgetHasUserSettings(modelData.id)
sourceComponent: NIconButton {
- icon: FontService.icons["gear"]
+ icon: Bootstrap.icons["gear"]
sizeRatio: 0.6
colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
colorBg: Color.mOnSurface
@@ -210,7 +210,7 @@ NBox {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
sizeRatio: 0.6
colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
colorBg: Color.mOnSurface
diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
index d7753e8..1d806b2 100644
--- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
@@ -84,7 +84,7 @@ Popup {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
onClicked: settingsPopup.close()
}
}
@@ -121,7 +121,7 @@ Popup {
NButton {
text: "Apply"
- icon: FontService.icons["check"]
+ icon: Bootstrap.icons["check"]
onClicked: {
if (settingsLoader.item && settingsLoader.item.saveSettings) {
var newSettings = settingsLoader.item.saveSettings()
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index d68db3c..47b431b 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -408,7 +408,7 @@ NPanel {
height: width
NIcon {
- text: FontService.icons[modelData.icon]
+ text: Bootstrap.icons[modelData.icon]
color: tabTextColor
font.pointSize: Style.fontSizeL * scaling
anchors.centerIn: parent
@@ -480,7 +480,7 @@ NPanel {
// Close button
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
tooltipText: "Close"
Layout.alignment: Qt.AlignVCenter
onClicked: root.close()
diff --git a/Modules/SettingsPanel/Tabs/AboutTab.qml b/Modules/SettingsPanel/Tabs/AboutTab.qml
index 3dc3f2d..7c0b28e 100644
--- a/Modules/SettingsPanel/Tabs/AboutTab.qml
+++ b/Modules/SettingsPanel/Tabs/AboutTab.qml
@@ -172,7 +172,7 @@ ColumnLayout {
imagePath: modelData.avatar_url || ""
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
- fallbackIcon: FontService.icons["person"]
+ fallbackIcon: Bootstrap.icons["person"]
borderColor: contributorArea.containsMouse ? Color.mOnTertiary : Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml
index e5509ea..aaf739c 100644
--- a/Modules/SettingsPanel/Tabs/AudioTab.qml
+++ b/Modules/SettingsPanel/Tabs/AudioTab.qml
@@ -272,7 +272,7 @@ ColumnLayout {
// Button aligned to the center of the actual input field
NIconButton {
- icon: FontService.icons["plus"]
+ icon: Bootstrap.icons["plus"]
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: blacklistInput.description ? Style.marginS * scaling : 0
onClicked: {
@@ -322,7 +322,7 @@ ColumnLayout {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
sizeRatio: 0.8
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Style.marginXS * scaling
diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml
index 36f6643..03475d0 100644
--- a/Modules/SettingsPanel/Tabs/DisplayTab.qml
+++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml
@@ -181,7 +181,7 @@ ColumnLayout {
}
NIconButton {
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
tooltipText: "Reset scaling"
onClicked: ScalingService.setScreenScale(modelData, 1.0)
}
diff --git a/Modules/SettingsPanel/Tabs/GeneralTab.qml b/Modules/SettingsPanel/Tabs/GeneralTab.qml
index c302217..6b75b9b 100644
--- a/Modules/SettingsPanel/Tabs/GeneralTab.qml
+++ b/Modules/SettingsPanel/Tabs/GeneralTab.qml
@@ -19,7 +19,7 @@ ColumnLayout {
width: 108 * scaling
height: 108 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: FontService.icons["person"]
+ fallbackIcon: Bootstrap.icons["person"]
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
Layout.alignment: Qt.AlignTop
diff --git a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
index 88433d5..df3556e 100644
--- a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
+++ b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
@@ -59,7 +59,7 @@ ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: currentWallpaper
- fallbackIcon: FontService.icons["image"]
+ fallbackIcon: Bootstrap.icons["image"]
imageRadius: Style.radiusM * scaling
borderColor: Color.mSecondary
borderWidth: Style.borderL * 2 * scaling
@@ -96,7 +96,7 @@ ColumnLayout {
}
NIconButton {
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
tooltipText: "Refresh wallpaper list"
onClicked: {
WallpaperService.refreshWallpapersList()
@@ -181,7 +181,7 @@ ColumnLayout {
visible: isSelected
NIcon {
- text: FontService.icons["check"]
+ text: Bootstrap.icons["check"]
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml
index 8fb937a..17716d7 100644
--- a/Modules/SidePanel/Cards/MediaCard.qml
+++ b/Modules/SidePanel/Cards/MediaCard.qml
@@ -31,7 +31,7 @@ NBox {
}
NIcon {
- text: FontService.icons["album"]
+ text: Bootstrap.icons["album"]
font.pointSize: Style.fontSizeXXXL * 2.5 * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -89,7 +89,7 @@ NBox {
indicator: NIcon {
x: playerSelector.width - width
y: playerSelector.topPadding + (playerSelector.availableHeight - height) / 2
- text: FontService.icons["arrow_drop_down"]
+ text: Bootstrap.icons["arrow_drop_down"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mOnSurface
horizontalAlignment: Text.AlignRight
@@ -162,14 +162,14 @@ NBox {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: MediaService.trackArtUrl
- fallbackIcon: FontService.icons["album"]
+ fallbackIcon: Bootstrap.icons["album"]
borderColor: Color.mOutline
borderWidth: Math.max(1, Style.borderS * scaling)
}
// Fallback icon when no album art available
NIcon {
- text: FontService.icons["album"]
+ text: Bootstrap.icons["album"]
color: Color.mPrimary
font.pointSize: Style.fontSizeL * 12 * scaling
visible: !trackArt.visible
@@ -307,7 +307,7 @@ NBox {
// Previous button
NIconButton {
- icon: FontService.icons["prev"]
+ icon: Bootstrap.icons["prev"]
tooltipText: "Previous Media"
visible: MediaService.canGoPrevious
onClicked: MediaService.canGoPrevious ? MediaService.previous() : {}
@@ -315,7 +315,7 @@ NBox {
// Play/Pause button
NIconButton {
- icon: MediaService.isPlaying ? FontService.icons["pause"] : FontService.icons["play"]
+ icon: MediaService.isPlaying ? Bootstrap.icons["pause"] : Bootstrap.icons["play"]
tooltipText: MediaService.isPlaying ? "Pause" : "Play"
visible: (MediaService.canPlay || MediaService.canPause)
onClicked: (MediaService.canPlay || MediaService.canPause) ? MediaService.playPause() : {}
@@ -323,7 +323,7 @@ NBox {
// Next button
NIconButton {
- icon: FontService.icons["next"]
+ icon: Bootstrap.icons["next"]
tooltipText: "Next media"
visible: MediaService.canGoNext
onClicked: MediaService.canGoNext ? MediaService.next() : {}
diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml
index 9af102b..3f7eb8d 100644
--- a/Modules/SidePanel/Cards/PowerProfilesCard.qml
+++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml
@@ -28,7 +28,7 @@ NBox {
}
// Performance
NIconButton {
- icon: FontService.icons["speed"]
+ icon: Bootstrap.icons["speed"]
tooltipText: "Set performance power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
@@ -42,7 +42,7 @@ NBox {
}
// Balanced
NIconButton {
- icon: FontService.icons["yin_yang"]
+ icon: Bootstrap.icons["yin_yang"]
tooltipText: "Set balanced power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
@@ -56,7 +56,7 @@ NBox {
}
// Eco
NIconButton {
- icon: FontService.icons["leaf"]
+ icon: Bootstrap.icons["leaf"]
tooltipText: "Set eco power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
diff --git a/Modules/SidePanel/Cards/ProfileCard.qml b/Modules/SidePanel/Cards/ProfileCard.qml
index 42a3198..96521df 100644
--- a/Modules/SidePanel/Cards/ProfileCard.qml
+++ b/Modules/SidePanel/Cards/ProfileCard.qml
@@ -32,7 +32,7 @@ NBox {
width: Style.baseWidgetSize * 1.25 * scaling
height: Style.baseWidgetSize * 1.25 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: FontService.icons["person"]
+ fallbackIcon: Bootstrap.icons["person"]
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
}
@@ -58,7 +58,7 @@ NBox {
Layout.fillWidth: true
}
NIconButton {
- icon: FontService.icons["gear"]
+ icon: Bootstrap.icons["gear"]
tooltipText: "Open settings."
onClicked: {
settingsPanel.requestedTab = SettingsPanel.Tab.General
@@ -68,7 +68,7 @@ NBox {
NIconButton {
id: powerButton
- icon: FontService.icons["power"]
+ icon: Bootstrap.icons["power"]
tooltipText: "Power menu."
onClicked: {
powerPanel.open(screen)
@@ -78,7 +78,7 @@ NBox {
NIconButton {
id: closeButton
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
tooltipText: "Close side panel."
onClicked: {
sidePanel.close()
diff --git a/Modules/SidePanel/Cards/SystemMonitorCard.qml b/Modules/SidePanel/Cards/SystemMonitorCard.qml
index 199960c..21f246e 100644
--- a/Modules/SidePanel/Cards/SystemMonitorCard.qml
+++ b/Modules/SidePanel/Cards/SystemMonitorCard.qml
@@ -24,7 +24,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuUsage
- icon: FontService.icons["speed"]
+ icon: Bootstrap.icons["speed"]
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -33,7 +33,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuTemp
suffix: "°C"
- icon: FontService.icons["thermometer"]
+ icon: Bootstrap.icons["thermometer"]
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -41,7 +41,7 @@ NBox {
}
NCircleStat {
value: SystemStatService.memPercent
- icon: FontService.icons["memory"]
+ icon: Bootstrap.icons["memory"]
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -49,7 +49,7 @@ NBox {
}
NCircleStat {
value: SystemStatService.diskPercent
- icon: FontService.icons["drive"]
+ icon: Bootstrap.icons["drive"]
flat: true
contentScale: 0.8
width: 72 * scaling
diff --git a/Modules/SidePanel/Cards/UtilitiesCard.qml b/Modules/SidePanel/Cards/UtilitiesCard.qml
index 27f0dce..3900dc9 100644
--- a/Modules/SidePanel/Cards/UtilitiesCard.qml
+++ b/Modules/SidePanel/Cards/UtilitiesCard.qml
@@ -25,7 +25,7 @@ NBox {
}
// Screen Recorder
NIconButton {
- icon: FontService.icons["video_camera"]
+ icon: Bootstrap.icons["video_camera"]
tooltipText: ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording."
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
@@ -41,7 +41,7 @@ NBox {
// Idle Inhibitor
NIconButton {
- icon: FontService.icons["coffee"]
+ icon: Bootstrap.icons["coffee"]
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake." : "Enable keep awake."
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
@@ -53,7 +53,7 @@ NBox {
// Wallpaper
NIconButton {
visible: Settings.data.wallpaper.enabled
- icon: FontService.icons["image"]
+ icon: Bootstrap.icons["image"]
tooltipText: "Left click: Open wallpaper selector.\nRight click: Set random wallpaper."
onClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index e4fccc8..e39cdf9 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -55,7 +55,7 @@ NPanel {
}
NIconButton {
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
tooltipText: "Refresh"
sizeRatio: 0.8
enabled: Settings.data.network.wifiEnabled && !NetworkService.scanning
@@ -63,7 +63,7 @@ NPanel {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
@@ -105,7 +105,7 @@ NPanel {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
sizeRatio: 0.6
onClicked: NetworkService.lastError = ""
}
@@ -377,7 +377,7 @@ NPanel {
&& NetworkService.connectingTo !== modelData.ssid
&& NetworkService.forgettingNetwork !== modelData.ssid
&& NetworkService.disconnectingFrom !== modelData.ssid
- icon: FontService.icons["trash"]
+ icon: Bootstrap.icons["trash"]
tooltipText: "Forget network"
sizeRatio: 0.7
onClicked: expandedSsid = expandedSsid === modelData.ssid ? "" : modelData.ssid
@@ -492,7 +492,7 @@ NPanel {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
sizeRatio: 0.8
onClicked: {
passwordSsid = ""
@@ -547,7 +547,7 @@ NPanel {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
sizeRatio: 0.8
onClicked: expandedSsid = ""
}
@@ -586,7 +586,7 @@ NPanel {
NButton {
text: "Scan again"
- icon: FontService.icons["refresh"]
+ icon: Bootstrap.icons["arrow-repeat"]
Layout.alignment: Qt.AlignHCenter
onClicked: NetworkService.scan()
}
diff --git a/Services/BatteryService.qml b/Services/BatteryService.qml
index 688d3eb..5b1c478 100644
--- a/Services/BatteryService.qml
+++ b/Services/BatteryService.qml
@@ -10,20 +10,20 @@ Singleton {
// Choose icon based on charge and charging state
function getIcon(percent, charging, isReady) {
if (!isReady) {
- return FontService.icons["battery_empty"] // FIXME: find battery error ?
+ return Bootstrap.icons["battery_empty"] // FIXME: find battery error ?
}
if (charging) {
- return FontService.icons["battery_charging"]
+ return Bootstrap.icons["battery_charging"]
} else {
if (percent >= 85)
- return FontService.icons["battery_full"]
+ return Bootstrap.icons["battery_full"]
if (percent >= 45)
- return FontService.icons["battery_half"]
+ return Bootstrap.icons["battery_half"]
if (percent >= 25)
- return FontService.icons["battery_low"]
+ return Bootstrap.icons["battery_low"]
if (percent >= 0)
- return FontService.icons["battery_empty"]
+ return Bootstrap.icons["battery_empty"]
}
}
}
diff --git a/Services/FontService.qml b/Services/FontService.qml
index aa27956..ebf03e3 100644
--- a/Services/FontService.qml
+++ b/Services/FontService.qml
@@ -13,85 +13,6 @@ Singleton {
property ListModel displayFonts: ListModel {}
property bool fontsLoaded: false
- property var icons: {
- "sunny": "\uF1D2",
- "partly_cloudy": "\uF2BE",
- "cloud": "\uF2C3",
- "foggy": "\uF2A7",
- "rainy": "\uF29D",
- "snowy": "\uF2BC",
- "thunderstorm": "\uF2AC",
- "battery_empty": "\uF188",
- "battery_low": "\uF911",
- "battery_half": "\uF187",
- "battery_full": "\uF186",
- "battery_charging": "\uF185",
- "volume_muted": "\uF60D",
- "volume_off": "\uF60F",
- "volume_half": "\uF60B",
- "volume_full": "\uF611",
- "brightness_low": "\uF1D4",
- "brightness_high": "\uF1D2",
- "wifi_disable": "\uF61B",
- "wifi_low": "\uF619",
- "wifi_half": "\uF61A",
- "wifi_full": "\uF61C",
- "power": "\uF4FF",
- "gear": "\uF3E5",
- "close": "\uF659",
- "check": "\uF272",
- "panel": "\uF290",
- "memory": "\uF2D6",
- "trash": "\uF78B",
- "video_camera": "\uF21F",
- "ethernet": "\uF2EB",
- "speed": "\uF66B",
- "leaf": "\uF90C",
- "microphone": "\uF490",
- "microphone_muted": "\uF48F",
- "coffee": "\uF2E0",
- "refresh": "\uF130",
- "image": "\uF226",
- "contrast": "\uF288",
- "thermometer": "\uF5CD",
- "paint_drop": "\uF30C",
- "yin_yang": "\uF8E7",
- "record": "\uF518",
- "pause": "\uF4C1",
- "play": "\uF4F2",
- "stop": "\uF590",
- "prev": "\uF561",
- "next": "\uF55B",
- "arrow_drop_down": "\uF22C",
- "warning": "\uF334",
- "info": "\uF26A",
- "upload": "\uF296",
- "download": "\uF294",
- "album": "\uF2FF",
- "plus": "\uF64D",
- "minus": "\uF63B",
- "eyedropper": "\uF342",
- "bell": "\uF18A",
- "bell_striked": "\uF631",
- "drive": "\uF412",
- "bluetooth": "\uF682",
- "person": "\uF4DA",
- "bar": "\uF52B",
- "launcher": "\uF843",
- "palette": "\uF4B1",
- "sunrise": "\uF5A5",
- "moon_stars": "\uF496",
- "gauge": "\uF580",
- "lightning": "\uF46D",
- "keyboard": "\uF451",
- "paint_brush": "\uEE26",
- "link": "\uF470",
- "macaron": "\uF154",
- "box": "\uF1C8",
- "monitor": "\uF302",
- // another contrast \uF8F3 \uF8DA
- }
-
// -------------------------------------------
function init() {
Logger.log("Font", "Service started")
diff --git a/Services/LocationService.qml b/Services/LocationService.qml
index 8d5344d..7575cc5 100644
--- a/Services/LocationService.qml
+++ b/Services/LocationService.qml
@@ -231,24 +231,24 @@ Singleton {
// --------------------------------
function weatherSymbolFromCode(code) {
if (code === 0)
- return FontService.icons["sunny"]
+ return Bootstrap.icons["sun"]
if (code === 1 || code === 2)
- return FontService.icons["partly_cloudy"]
+ return Bootstrap.icons["cloud-sun"]
if (code === 3)
- return FontService.icons["cloud"]
+ return Bootstrap.icons["cloud"]
if (code >= 45 && code <= 48)
- return FontService.icons["foggy"]
+ return Bootstrap.icons["cloud-haze"]
if (code >= 51 && code <= 67)
- return FontService.icons["rainy"]
+ return Bootstrap.icons["cloud-rain"]
if (code >= 71 && code <= 77)
- return FontService.icons["snowy"]
+ return Bootstrap.icons["cloud-snow"]
if (code >= 71 && code <= 77)
- return FontService.icons["snowy"]
+ return Bootstrap.icons["cloud-snow"]
if (code >= 85 && code <= 86)
- return FontService.icons["snowy"]
+ return Bootstrap.icons["cloud-snow"]
if (code >= 95 && code <= 99)
- return FontService.icons["thunderstorm"]
- return FontService.icons["cloud"]
+ return Bootstrap.icons["cloud-lightning"]
+ return Bootstrap.icons["cloud"]
}
// --------------------------------
diff --git a/Widgets/NColorPicker.qml b/Widgets/NColorPicker.qml
index a4a4aad..7cbeaad 100644
--- a/Widgets/NColorPicker.qml
+++ b/Widgets/NColorPicker.qml
@@ -59,7 +59,7 @@ Rectangle {
}
NIcon {
- text: FontService.icons["eyedropper"]
+ text: Bootstrap.icons["eyedropper"]
color: Color.mOnSurfaceVariant
}
}
diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml
index cb8db1c..f78cc2f 100644
--- a/Widgets/NColorPickerDialog.qml
+++ b/Widgets/NColorPickerDialog.qml
@@ -130,7 +130,7 @@ Popup {
spacing: Style.marginS * scaling
NIcon {
- text: FontService.icons["eyedropper"]
+ text: Bootstrap.icons["eyedropper"]
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -148,7 +148,7 @@ Popup {
}
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
onClicked: root.close()
}
}
@@ -492,7 +492,7 @@ Popup {
NButton {
id: cancelButton
text: "Cancel"
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
outlined: cancelButton.hovered ? false : true
customHeight: 36 * scaling
customWidth: 100 * scaling
@@ -503,7 +503,7 @@ Popup {
NButton {
text: "Apply"
- icon: FontService.icons["check"]
+ icon: Bootstrap.icons["check"]
customHeight: 36 * scaling
customWidth: 100 * scaling
onClicked: {
diff --git a/Widgets/NComboBox.qml b/Widgets/NComboBox.qml
index 769602d..4a59df9 100644
--- a/Widgets/NComboBox.qml
+++ b/Widgets/NComboBox.qml
@@ -85,7 +85,7 @@ RowLayout {
indicator: NIcon {
x: combo.width - width - Style.marginM * scaling
y: combo.topPadding + (combo.availableHeight - height) / 2
- text: FontService.icons["arrow_drop_down"]
+ text: Bootstrap.icons["arrow_drop_down"]
font.pointSize: Style.fontSizeL * scaling
}
diff --git a/Widgets/NInputAction.qml b/Widgets/NInputAction.qml
index b48264b..cc86c03 100644
--- a/Widgets/NInputAction.qml
+++ b/Widgets/NInputAction.qml
@@ -14,7 +14,7 @@ RowLayout {
property string placeholderText: ""
property string text: ""
property string actionButtonText: "Test"
- property string actionButtonIcon: FontService.icons["play"]
+ property string actionButtonIcon: Bootstrap.icons["play"]
property bool actionButtonEnabled: text !== ""
// Signals
diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml
index a3cb3e3..ed13961 100644
--- a/Widgets/NSpinBox.qml
+++ b/Widgets/NSpinBox.qml
@@ -95,7 +95,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: FontService.icons["minus"]
+ text: Bootstrap.icons["minus"]
font.pointSize: Style.fontSizeS * scaling
color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -130,7 +130,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: FontService.icons["plus"]
+ text: Bootstrap.icons["plus"]
font.pointSize: Style.fontSizeS * scaling
color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index 4a544d1..4a52ab3 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -118,7 +118,7 @@ Item {
// Icon
NIcon {
id: icon
- text: (root.type == "warning") ? FontService.icons["warning"] : FontService.icons["info"]
+ text: (root.type == "warning") ? Bootstrap.icons["warning"] : Bootstrap.icons["info"]
color: {
switch (root.type) {
case "warning":
@@ -162,7 +162,7 @@ Item {
// Close button (only if persistent or manual dismiss needed)
NIconButton {
- icon: FontService.icons["close"]
+ icon: Bootstrap.icons["close"]
visible: root.persistent || root.duration === 0
colorBg: Color.mSurfaceVariant
From 74cf71755b16dd2659b4e4ec1aed8356e0e7b48f Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 21:10:03 -0400
Subject: [PATCH 032/118] Icons: battery + bt
---
Services/BatteryService.qml | 12 ++++++------
Services/BluetoothService.qml | 19 +++++++++----------
2 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/Services/BatteryService.qml b/Services/BatteryService.qml
index 5b1c478..ce36be2 100644
--- a/Services/BatteryService.qml
+++ b/Services/BatteryService.qml
@@ -10,20 +10,20 @@ Singleton {
// Choose icon based on charge and charging state
function getIcon(percent, charging, isReady) {
if (!isReady) {
- return Bootstrap.icons["battery_empty"] // FIXME: find battery error ?
+ return Bootstrap.icons["battery"] // FIXME: find battery error ?
}
if (charging) {
- return Bootstrap.icons["battery_charging"]
+ return Bootstrap.icons["battery-charging"]
} else {
if (percent >= 85)
- return Bootstrap.icons["battery_full"]
+ return Bootstrap.icons["battery-full"]
if (percent >= 45)
- return Bootstrap.icons["battery_half"]
+ return Bootstrap.icons["battery-half"]
if (percent >= 25)
- return Bootstrap.icons["battery_low"]
+ return Bootstrap.icons["battery-low"]
if (percent >= 0)
- return Bootstrap.icons["battery_empty"]
+ return Bootstrap.icons["battery"]
}
}
}
diff --git a/Services/BluetoothService.qml b/Services/BluetoothService.qml
index bb071a8..9b12ebc 100644
--- a/Services/BluetoothService.qml
+++ b/Services/BluetoothService.qml
@@ -49,39 +49,38 @@ Singleton {
})
}
- // FIXME
function getDeviceIcon(device) {
if (!device) {
- return "bluetooth"
+ return Bootstrap.icons["bluetooth"]
}
var name = (device.name || device.deviceName || "").toLowerCase()
var icon = (device.icon || "").toLowerCase()
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") || name.includes("airpod")
|| name.includes("headset") || name.includes("arctis")) {
- return "headset"
+ return Bootstrap.icons["headset"]
}
if (icon.includes("mouse") || name.includes("mouse")) {
- return "mouse"
+ return Bootstrap.icons["mouse-2"]
}
if (icon.includes("keyboard") || name.includes("keyboard")) {
- return "keyboard"
+ return Bootstrap.icons["keyboard"]
}
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android")
|| name.includes("samsung")) {
- return "smartphone"
+ return Bootstrap.icons["phone"]
}
if (icon.includes("watch") || name.includes("watch")) {
- return "watch"
+ return Bootstrap.icons["smartwatch"]
}
if (icon.includes("speaker") || name.includes("speaker")) {
- return "speaker"
+ return Bootstrap.icons["speaker"]
}
if (icon.includes("display") || name.includes("tv")) {
- return "tv"
+ return Bootstrap.icons["tv"]
}
- return "bluetooth"
+ return Bootstrap.icons["bluetooth"]
}
function canConnect(device) {
From c77784b5c10ce93e798afca0b90df7606421d553 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 21:23:57 -0400
Subject: [PATCH 033/118] Icons: most settings tabs
---
Commons/Bootstrap.qml | 22 ++--------------
Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml | 2 +-
Modules/Bar/Widgets/NotificationHistory.qml | 2 +-
Modules/Bar/Widgets/SystemMonitor.qml | 7 +++--
Modules/Bar/Widgets/Volume.qml | 6 ++---
Modules/BluetoothPanel/BluetoothPanel.qml | 2 +-
Modules/Notification/Notification.qml | 2 +-
.../Notification/NotificationHistoryPanel.qml | 4 +--
.../SettingsPanel/Bar/BarSectionEditor.qml | 2 +-
.../Bar/BarWidgetSettingsDialog.qml | 2 +-
Modules/SettingsPanel/SettingsPanel.qml | 26 +++++++++----------
Modules/SettingsPanel/Tabs/AudioTab.qml | 2 +-
Modules/SidePanel/Cards/ProfileCard.qml | 2 +-
Modules/WiFiPanel/WiFiPanel.qml | 8 +++---
Widgets/NColorPickerDialog.qml | 4 +--
Widgets/NIcon.qml | 1 -
Widgets/NToast.qml | 2 +-
17 files changed, 38 insertions(+), 58 deletions(-)
diff --git a/Commons/Bootstrap.qml b/Commons/Bootstrap.qml
index bf55111..eba39e4 100644
--- a/Commons/Bootstrap.qml
+++ b/Commons/Bootstrap.qml
@@ -8,24 +8,6 @@ import qs.Commons
Singleton {
id: root
-
- // property var icons: {
- // "sunny": "\uF1D2",
- // "partly_cloudy": "\uF2BE",
- // "cloud": "\uF2C3",
- // "foggy": "\uF2A7",
- // "rainy": "\uF29D",
- // "snowy": "\uF2BC",
- // "thunderstorm": "\uF2AC",
- // "battery_empty": "\uF188",
- // "battery_low": "\uF911",
- // "battery_half": "\uF187",
- // "battery_full": "\uF186",
- // "battery_charging": "\uF185",
- // "volume_muted": "\uF60D",
- // "volume_off": "\uF60F",
- // "volume_half": "\uF60B",
- // "volume_full": "\uF611",
// "brightness_low": "\uF1D4",
// "brightness_high": "\uF1D2",
// "wifi_disable": "\uF61B",
@@ -33,7 +15,7 @@ Singleton {
// "wifi_half": "\uF61A",
// "wifi_full": "\uF61C",
// "power": "\uF4FF",
- // "gear": "\uF3E5",
+
// "close": "\uF659",
// "check": "\uF272",
// "panel": "\uF290",
@@ -70,7 +52,7 @@ Singleton {
// "bell": "\uF18A",
// "bell_striked": "\uF631",
// "drive": "\uF412",
- // "bluetooth": "\uF682",
+
// "person": "\uF4DA",
// "bar": "\uF52B",
// "launcher": "\uF843",
diff --git a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
index e5b798c..dacaf9a 100644
--- a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
+++ b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
@@ -55,7 +55,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml
index a0836c3..4a64d36 100644
--- a/Modules/Bar/Widgets/NotificationHistory.qml
+++ b/Modules/Bar/Widgets/NotificationHistory.qml
@@ -53,7 +53,7 @@ NIconButton {
}
sizeRatio: 0.8
- icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell_striked"] : Bootstrap.icons["bell"]
+ icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell-slash"] : Bootstrap.icons["bell"]
tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'."
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index 58cfc90..e749116 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -66,7 +66,7 @@ RowLayout {
NIcon {
id: cpuUsageIcon
- text: Bootstrap.icons["speed"]
+ text: Bootstrap.icons["speedometer2"]
Layout.alignment: Qt.AlignVCenter
}
@@ -85,13 +85,12 @@ RowLayout {
// CPU Temperature Component
RowLayout {
id: cpuTempLayout
- // spacing is thin here to compensate for the vertical thermometer icon
- spacing: Style.marginXXS * scaling
+ spacing: Style.marginXS * scaling
Layout.alignment: Qt.AlignVCenter
visible: showCpuTemp
NIcon {
- text: Bootstrap.icons["thermometer"]
+ text: Bootstrap.icons["fire"]
Layout.alignment: Qt.AlignVCenter
}
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 1db94ec..286bdcb 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -43,11 +43,11 @@ Item {
function getIcon() {
if (AudioService.muted) {
- return Bootstrap.icons["volume_muted"]
+ return Bootstrap.icons["volume-mute"]
}
return AudioService.volume
- <= Number.EPSILON ? Bootstrap.icons["volume_off"] : (AudioService.volume
- < 0.5 ? Bootstrap.icons["volume_half"] : Bootstrap.icons["volume_full"])
+ <= Number.EPSILON ? Bootstrap.icons["volume-off"] : (AudioService.volume
+ < 0.5 ? Bootstrap.icons["volume-down"] : Bootstrap.icons["volume-up"])
}
// Connection used to open the pill when volume changes
diff --git a/Modules/BluetoothPanel/BluetoothPanel.qml b/Modules/BluetoothPanel/BluetoothPanel.qml
index 958a293..9c26adc 100644
--- a/Modules/BluetoothPanel/BluetoothPanel.qml
+++ b/Modules/BluetoothPanel/BluetoothPanel.qml
@@ -54,7 +54,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml
index e699d85..c78ed0d 100644
--- a/Modules/Notification/Notification.qml
+++ b/Modules/Notification/Notification.qml
@@ -294,7 +294,7 @@ Variants {
// Close button positioned absolutely
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
tooltipText: "Close"
sizeRatio: 0.6
anchors.top: parent.top
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index 7d2c1f0..06b8bd7 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -45,7 +45,7 @@ NPanel {
}
NIconButton {
- icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell_striked"] : Bootstrap.icons["bell"]
+ icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell-slash"] : Bootstrap.icons["bell"]
tooltipText: Settings.data.notifications.doNotDisturb ? "'Do Not Disturb' is enabled." : "'Do Not Disturb' is disabled."
sizeRatio: 0.8
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
@@ -59,7 +59,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index 86c0863..3d206c7 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -210,7 +210,7 @@ NBox {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
sizeRatio: 0.6
colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
colorBg: Color.mOnSurface
diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
index 1d806b2..5cc8e0e 100644
--- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
@@ -84,7 +84,7 @@ Popup {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
onClicked: settingsPopup.close()
}
}
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index 47b431b..d7ab9eb 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -128,22 +128,22 @@ NPanel {
}, {
"id": SettingsPanel.Tab.Bar,
"label": "Bar",
- "icon": "bar",
+ "icon": "segmented-nav",
"source": barTab
}, {
"id": SettingsPanel.Tab.Launcher,
"label": "Launcher",
- "icon": "launcher",
+ "icon": "rocket",
"source": launcherTab
}, {
"id": SettingsPanel.Tab.Audio,
"label": "Audio",
- "icon": "volume_full",
+ "icon": "speaker",
"source": audioTab
}, {
"id": SettingsPanel.Tab.Display,
"label": "Display",
- "icon": "monitor",
+ "icon": "display",
"source": displayTab
}, {
"id": SettingsPanel.Tab.Network,
@@ -153,22 +153,22 @@ NPanel {
}, {
"id": SettingsPanel.Tab.Brightness,
"label": "Brightness",
- "icon": "brightness_high",
+ "icon": "brightness-high",
"source": brightnessTab
}, {
"id": SettingsPanel.Tab.Weather,
"label": "Weather",
- "icon": "partly_cloudy",
+ "icon": "cloud-sun",
"source": weatherTab
}, {
"id": SettingsPanel.Tab.ColorScheme,
"label": "Color Scheme",
- "icon": "paint_drop",
+ "icon": "palette",
"source": colorSchemeTab
}, {
"id": SettingsPanel.Tab.Wallpaper,
"label": "Wallpaper",
- "icon": "image",
+ "icon": "easel",
"source": wallpaperTab
}]
@@ -177,7 +177,7 @@ NPanel {
newTabs.push({
"id": SettingsPanel.Tab.WallpaperSelector,
"label": "Wallpaper Selector",
- "icon": "paint_brush",
+ "icon": "image",
"source": wallpaperSelectorTab
})
}
@@ -185,17 +185,17 @@ NPanel {
newTabs.push({
"id": SettingsPanel.Tab.ScreenRecorder,
"label": "Screen Recorder",
- "icon": "video_camera",
+ "icon": "camera-video",
"source": screenRecorderTab
}, {
"id": SettingsPanel.Tab.Hooks,
"label": "Hooks",
- "icon": "link",
+ "icon": "link-45deg",
"source": hooksTab
}, {
"id": SettingsPanel.Tab.About,
"label": "About",
- "icon": "macaron",
+ "icon": "person",
"source": aboutTab
})
@@ -480,7 +480,7 @@ NPanel {
// Close button
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
tooltipText: "Close"
Layout.alignment: Qt.AlignVCenter
onClicked: root.close()
diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml
index aaf739c..20ece47 100644
--- a/Modules/SettingsPanel/Tabs/AudioTab.qml
+++ b/Modules/SettingsPanel/Tabs/AudioTab.qml
@@ -322,7 +322,7 @@ ColumnLayout {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
sizeRatio: 0.8
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Style.marginXS * scaling
diff --git a/Modules/SidePanel/Cards/ProfileCard.qml b/Modules/SidePanel/Cards/ProfileCard.qml
index 96521df..d85a432 100644
--- a/Modules/SidePanel/Cards/ProfileCard.qml
+++ b/Modules/SidePanel/Cards/ProfileCard.qml
@@ -78,7 +78,7 @@ NBox {
NIconButton {
id: closeButton
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
tooltipText: "Close side panel."
onClicked: {
sidePanel.close()
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index e39cdf9..59698ea 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -63,7 +63,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
@@ -105,7 +105,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
sizeRatio: 0.6
onClicked: NetworkService.lastError = ""
}
@@ -492,7 +492,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
sizeRatio: 0.8
onClicked: {
passwordSsid = ""
@@ -547,7 +547,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
sizeRatio: 0.8
onClicked: expandedSsid = ""
}
diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml
index f78cc2f..7fe60bc 100644
--- a/Widgets/NColorPickerDialog.qml
+++ b/Widgets/NColorPickerDialog.qml
@@ -148,7 +148,7 @@ Popup {
}
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
onClicked: root.close()
}
}
@@ -492,7 +492,7 @@ Popup {
NButton {
id: cancelButton
text: "Cancel"
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
outlined: cancelButton.hovered ? false : true
customHeight: 36 * scaling
customWidth: 100 * scaling
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index 2f5a330..0dc6f7b 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -4,7 +4,6 @@ import qs.Commons
import qs.Widgets
Text {
- text: "\uF706" // fallback/default to balloon icon
font.family: "bootstrap-icons"
font.pointSize: Style.fontSizeL * scaling
color: Color.mOnSurface
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index 4a52ab3..00cb81b 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -162,7 +162,7 @@ Item {
// Close button (only if persistent or manual dismiss needed)
NIconButton {
- icon: Bootstrap.icons["close"]
+ icon: Bootstrap.icons["x-lg"]
visible: root.persistent || root.duration === 0
colorBg: Color.mSurfaceVariant
From ccdb4e0664376e31c865246c9556d6bd7909e9a3 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 21:37:01 -0400
Subject: [PATCH 034/118] Icons: more icons
---
Commons/Bootstrap.qml | 5 -----
Modules/Bar/Widgets/PowerProfile.qml | 10 +++++-----
Modules/Bar/Widgets/SidePanelToggle.qml | 2 +-
Modules/Bar/Widgets/Volume.qml | 2 +-
.../Notification/NotificationHistoryPanel.qml | 2 +-
.../SettingsPanel/Bar/BarSectionEditor.qml | 2 +-
Modules/SettingsPanel/SettingsPanel.qml | 20 ++++++-------------
Modules/SettingsPanel/Tabs/AudioTab.qml | 2 +-
Modules/SidePanel/Cards/PowerProfilesCard.qml | 4 ++--
Modules/SidePanel/Cards/SystemMonitorCard.qml | 4 ++--
Modules/SidePanel/Cards/UtilitiesCard.qml | 4 ++--
Services/BatteryService.qml | 3 ++-
Widgets/NComboBox.qml | 2 +-
Widgets/NSpinBox.qml | 4 ++--
14 files changed, 27 insertions(+), 39 deletions(-)
diff --git a/Commons/Bootstrap.qml b/Commons/Bootstrap.qml
index eba39e4..e4ddb04 100644
--- a/Commons/Bootstrap.qml
+++ b/Commons/Bootstrap.qml
@@ -46,7 +46,6 @@ Singleton {
// "upload": "\uF296",
// "download": "\uF294",
// "album": "\uF2FF",
- // "plus": "\uF64D",
// "minus": "\uF63B",
// "eyedropper": "\uF342",
// "bell": "\uF18A",
@@ -62,16 +61,12 @@ Singleton {
// "gauge": "\uF580",
// "lightning": "\uF46D",
// "keyboard": "\uF451",
- // "paint_brush": "\uEE26",
// "link": "\uF470",
// "macaron": "\uF154",
// "box": "\uF1C8",
// "monitor": "\uF302"
// // another contrast \uF8F3 \uF8DA
// }
-
-
-
property var icons: {
"alarm-fill": "\uF101",
"alarm": "\uF102",
diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml
index d29b180..43bff33 100644
--- a/Modules/Bar/Widgets/PowerProfile.qml
+++ b/Modules/Bar/Widgets/PowerProfile.qml
@@ -19,13 +19,13 @@ NIconButton {
function profileIcon() {
if (!hasPP)
- return "balance"
+ return Bootstrap.icons["yin-yang"]
if (powerProfiles.profile === PowerProfile.Performance)
- return "speed"
+ return Bootstrap.icons["speedometer2"]
if (powerProfiles.profile === PowerProfile.Balanced)
- return "balance"
+ return Bootstrap.icons["yin-yang"]
if (powerProfiles.profile === PowerProfile.PowerSaver)
- return "eco"
+ return Bootstrap.icons["leaf"]
}
function profileName() {
@@ -57,4 +57,4 @@ NIconButton {
colorBorder: Color.transparent
colorBorderHover: Color.transparent
onClicked: root.changeProfile()
-}
+}
\ No newline at end of file
diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml
index ada2796..56f3376 100644
--- a/Modules/Bar/Widgets/SidePanelToggle.qml
+++ b/Modules/Bar/Widgets/SidePanelToggle.qml
@@ -33,7 +33,7 @@ NIconButton {
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo
!== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
- icon: useDistroLogo ? "" : Bootstrap.icons["panel"]
+ icon: useDistroLogo ? "" : Bootstrap.icons["layout-sidebar-inset-reverse"]
tooltipText: "Open side panel."
sizeRatio: 0.8
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 286bdcb..71fe1f3 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -47,7 +47,7 @@ Item {
}
return AudioService.volume
<= Number.EPSILON ? Bootstrap.icons["volume-off"] : (AudioService.volume
- < 0.5 ? Bootstrap.icons["volume-down"] : Bootstrap.icons["volume-up"])
+ < 0.5 ? Bootstrap.icons["volume-down"] : Bootstrap.icons["volume-up"])
}
// Connection used to open the pill when volume changes
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index 06b8bd7..bf22c19 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -85,7 +85,7 @@ NPanel {
}
NIcon {
- text: "notifications_off"
+ text: Bootstrap.icons["bell-slash"]
font.pointSize: 64 * scaling
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index 3d206c7..919deb8 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -85,7 +85,7 @@ NBox {
}
NIconButton {
- icon: Bootstrap.icons["plus"]
+ icon: Bootstrap.icons["plus-lg"]
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index d7ab9eb..d07db79 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -195,7 +195,7 @@ NPanel {
}, {
"id": SettingsPanel.Tab.About,
"label": "About",
- "icon": "person",
+ "icon": "info-circle",
"source": aboutTab
})
@@ -400,21 +400,13 @@ NPanel {
anchors.fill: parent
anchors.leftMargin: Style.marginS * scaling
anchors.rightMargin: Style.marginS * scaling
- spacing: Style.marginS * scaling
+ spacing: Style.marginM * scaling
- // Tab icon
- Item {
- width: 20 * scaling
- height: width
-
- NIcon {
- text: Bootstrap.icons[modelData.icon]
- color: tabTextColor
- font.pointSize: Style.fontSizeL * scaling
- anchors.centerIn: parent
- }
+ NIcon {
+ text: Bootstrap.icons[modelData.icon]
+ color: tabTextColor
+ font.pointSize: Style.fontSizeL * scaling
}
-
// Tab label
NText {
text: modelData.label
diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml
index 20ece47..dba15ca 100644
--- a/Modules/SettingsPanel/Tabs/AudioTab.qml
+++ b/Modules/SettingsPanel/Tabs/AudioTab.qml
@@ -272,7 +272,7 @@ ColumnLayout {
// Button aligned to the center of the actual input field
NIconButton {
- icon: Bootstrap.icons["plus"]
+ icon: Bootstrap.icons["plus-lg"]
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: blacklistInput.description ? Style.marginS * scaling : 0
onClicked: {
diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml
index 3f7eb8d..1cc7732 100644
--- a/Modules/SidePanel/Cards/PowerProfilesCard.qml
+++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml
@@ -28,7 +28,7 @@ NBox {
}
// Performance
NIconButton {
- icon: Bootstrap.icons["speed"]
+ icon: Bootstrap.icons["speedometer2"]
tooltipText: "Set performance power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
@@ -42,7 +42,7 @@ NBox {
}
// Balanced
NIconButton {
- icon: Bootstrap.icons["yin_yang"]
+ icon: Bootstrap.icons["yin-yang"]
tooltipText: "Set balanced power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
diff --git a/Modules/SidePanel/Cards/SystemMonitorCard.qml b/Modules/SidePanel/Cards/SystemMonitorCard.qml
index 21f246e..c8515fa 100644
--- a/Modules/SidePanel/Cards/SystemMonitorCard.qml
+++ b/Modules/SidePanel/Cards/SystemMonitorCard.qml
@@ -24,7 +24,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuUsage
- icon: Bootstrap.icons["speed"]
+ icon: Bootstrap.icons["speedometer2"]
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -33,7 +33,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuTemp
suffix: "°C"
- icon: Bootstrap.icons["thermometer"]
+ icon: Bootstrap.icons["fire"]
flat: true
contentScale: 0.8
width: 72 * scaling
diff --git a/Modules/SidePanel/Cards/UtilitiesCard.qml b/Modules/SidePanel/Cards/UtilitiesCard.qml
index 3900dc9..c34a7f3 100644
--- a/Modules/SidePanel/Cards/UtilitiesCard.qml
+++ b/Modules/SidePanel/Cards/UtilitiesCard.qml
@@ -25,7 +25,7 @@ NBox {
}
// Screen Recorder
NIconButton {
- icon: Bootstrap.icons["video_camera"]
+ icon: Bootstrap.icons["camera-video"]
tooltipText: ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording."
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
@@ -41,7 +41,7 @@ NBox {
// Idle Inhibitor
NIconButton {
- icon: Bootstrap.icons["coffee"]
+ icon: Bootstrap.icons["cup-hot"]
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake." : "Enable keep awake."
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
diff --git a/Services/BatteryService.qml b/Services/BatteryService.qml
index ce36be2..3bad2cc 100644
--- a/Services/BatteryService.qml
+++ b/Services/BatteryService.qml
@@ -2,6 +2,7 @@ pragma Singleton
import Quickshell
import Quickshell.Services.UPower
+import qs.Commons
import qs.Services
Singleton {
@@ -10,7 +11,7 @@ Singleton {
// Choose icon based on charge and charging state
function getIcon(percent, charging, isReady) {
if (!isReady) {
- return Bootstrap.icons["battery"] // FIXME: find battery error ?
+ return Bootstrap.icons["exclamation-diamond"]
}
if (charging) {
diff --git a/Widgets/NComboBox.qml b/Widgets/NComboBox.qml
index 4a59df9..538de23 100644
--- a/Widgets/NComboBox.qml
+++ b/Widgets/NComboBox.qml
@@ -85,7 +85,7 @@ RowLayout {
indicator: NIcon {
x: combo.width - width - Style.marginM * scaling
y: combo.topPadding + (combo.availableHeight - height) / 2
- text: Bootstrap.icons["arrow_drop_down"]
+ text: Bootstrap.icons["chevron-down"]
font.pointSize: Style.fontSizeL * scaling
}
diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml
index ed13961..27d1e0f 100644
--- a/Widgets/NSpinBox.qml
+++ b/Widgets/NSpinBox.qml
@@ -95,7 +95,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: Bootstrap.icons["minus"]
+ text: Bootstrap.icons["dash-lg"]
font.pointSize: Style.fontSizeS * scaling
color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -130,7 +130,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: Bootstrap.icons["plus"]
+ text: Bootstrap.icons["plus-lg"]
font.pointSize: Style.fontSizeS * scaling
color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
From 1f8c55d581d45ebeab5e8f7eb99e23682333f11a Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 22:05:57 -0400
Subject: [PATCH 035/118] Icons: huge cleanup
---
Commons/Bootstrap.qml | 15 ++---------
Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml | 26 +++++++++----------
Modules/Bar/Widgets/Bluetooth.qml | 2 +-
Modules/Bar/Widgets/Brightness.qml | 2 +-
Modules/Bar/Widgets/DarkModeToggle.qml | 2 +-
Modules/Bar/Widgets/KeepAwake.qml | 2 +-
Modules/Bar/Widgets/KeyboardLayout.qml | 2 +-
Modules/Bar/Widgets/MediaMini.qml | 4 +--
Modules/Bar/Widgets/Microphone.qml | 4 +--
Modules/Bar/Widgets/NightLight.qml | 2 +-
Modules/Bar/Widgets/NotificationHistory.qml | 2 +-
Modules/Bar/Widgets/PowerProfile.qml | 10 +++----
.../Bar/Widgets/ScreenRecorderIndicator.qml | 2 +-
Modules/Bar/Widgets/SidePanelToggle.qml | 2 +-
Modules/Bar/Widgets/SystemMonitor.qml | 22 +++++++---------
Modules/Bar/Widgets/Volume.qml | 6 ++---
Modules/Bar/Widgets/WiFi.qml | 4 +--
.../BluetoothPanel/BluetoothDevicesList.qml | 3 +--
Modules/BluetoothPanel/BluetoothPanel.qml | 7 +++--
Modules/LockScreen/LockScreen.qml | 2 +-
Modules/Notification/Notification.qml | 2 +-
.../Notification/NotificationHistoryPanel.qml | 14 +++++-----
.../SettingsPanel/Bar/BarSectionEditor.qml | 6 ++---
.../Bar/BarWidgetSettingsDialog.qml | 4 +--
Modules/SettingsPanel/SettingsPanel.qml | 2 +-
Modules/SettingsPanel/Tabs/AboutTab.qml | 2 +-
Modules/SettingsPanel/Tabs/AudioTab.qml | 4 +--
Modules/SettingsPanel/Tabs/DisplayTab.qml | 2 +-
Modules/SettingsPanel/Tabs/GeneralTab.qml | 2 +-
.../Tabs/WallpaperSelectorTab.qml | 6 ++---
Modules/SidePanel/Cards/MediaCard.qml | 14 +++++-----
Modules/SidePanel/Cards/PowerProfilesCard.qml | 6 ++---
Modules/SidePanel/Cards/ProfileCard.qml | 8 +++---
Modules/SidePanel/Cards/SystemMonitorCard.qml | 8 +++---
Modules/SidePanel/Cards/UtilitiesCard.qml | 6 ++---
Modules/SidePanel/Cards/WeatherCard.qml | 2 +-
Modules/WiFiPanel/WiFiPanel.qml | 23 ++++++++--------
Services/BatteryService.qml | 12 ++++-----
Services/BluetoothService.qml | 18 ++++++-------
Services/LocationService.qml | 20 +++++++-------
Services/NetworkService.qml | 12 ++++-----
Widgets/NButton.qml | 2 +-
Widgets/NCheckbox.qml | 2 +-
Widgets/NCircleStat.qml | 2 +-
Widgets/NColorPicker.qml | 2 +-
Widgets/NColorPickerDialog.qml | 8 +++---
Widgets/NComboBox.qml | 2 +-
Widgets/NIcon.qml | 3 +++
Widgets/NIconButton.qml | 2 +-
Widgets/NInputAction.qml | 2 +-
Widgets/NPill.qml | 2 +-
Widgets/NSpinBox.qml | 4 +--
Widgets/NToast.qml | 4 +--
53 files changed, 155 insertions(+), 174 deletions(-)
diff --git a/Commons/Bootstrap.qml b/Commons/Bootstrap.qml
index e4ddb04..1cb2ff5 100644
--- a/Commons/Bootstrap.qml
+++ b/Commons/Bootstrap.qml
@@ -8,8 +8,6 @@ import qs.Commons
Singleton {
id: root
- // "brightness_low": "\uF1D4",
- // "brightness_high": "\uF1D2",
// "wifi_disable": "\uF61B",
// "wifi_low": "\uF619",
// "wifi_half": "\uF61A",
@@ -31,9 +29,6 @@ Singleton {
// "refresh": "\uF130",
// "image": "\uF226",
// "contrast": "\uF288",
- // "thermometer": "\uF5CD",
- // "paint_drop": "\uF30C",
- // "yin_yang": "\uF8E7",
// "record": "\uF518",
// "pause": "\uF4C1",
// "play": "\uF4F2",
@@ -46,10 +41,8 @@ Singleton {
// "upload": "\uF296",
// "download": "\uF294",
// "album": "\uF2FF",
- // "minus": "\uF63B",
+
// "eyedropper": "\uF342",
- // "bell": "\uF18A",
- // "bell_striked": "\uF631",
// "drive": "\uF412",
// "person": "\uF4DA",
@@ -60,11 +53,7 @@ Singleton {
// "moon_stars": "\uF496",
// "gauge": "\uF580",
// "lightning": "\uF46D",
- // "keyboard": "\uF451",
- // "link": "\uF470",
- // "macaron": "\uF154",
- // "box": "\uF1C8",
- // "monitor": "\uF302"
+
// // another contrast \uF8F3 \uF8DA
// }
property var icons: {
diff --git a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
index dacaf9a..accde47 100644
--- a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
+++ b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
@@ -27,8 +27,7 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon {
- text: "system_update_alt"
+ NIcon { icon: "system_update_alt"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -44,7 +43,7 @@ NPanel {
// Reset button (only show if update failed)
NIconButton {
visible: ArchUpdaterService.updateFailed
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
tooltipText: "Reset update state"
sizeRatio: 0.8
colorBg: Color.mError
@@ -55,7 +54,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
@@ -102,8 +101,7 @@ NPanel {
Layout.fillHeight: true
} // Spacer
- NIcon {
- text: "hourglass_empty"
+ NIcon { icon: "hourglass_empty"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -143,7 +141,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: "terminal"
+ icon: "terminal"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -181,7 +179,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: "package"
+ icon: "package"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -219,7 +217,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: "error"
+ icon: "error"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -245,7 +243,7 @@ NPanel {
// Prominent refresh button
NIconButton {
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
tooltipText: "Try checking again"
sizeRatio: 1.2
colorBg: Color.mPrimary
@@ -270,7 +268,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: "error_outline"
+ icon: "error_outline"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -295,7 +293,7 @@ NPanel {
// Prominent refresh button
NIconButton {
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
tooltipText: "Refresh and try again"
sizeRatio: 1.2
colorBg: Color.mPrimary
@@ -323,7 +321,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- text: "check_circle"
+ icon: "check_circle"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -483,7 +481,7 @@ NPanel {
spacing: Style.marginL * scaling
NIconButton {
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
tooltipText: ArchUpdaterService.aurBusy ? "Checking for updates..." : (!ArchUpdaterService.canPoll ? "Refresh available soon" : "Refresh package lists")
onClicked: {
ArchUpdaterService.forceRefresh()
diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml
index 599e40d..760745c 100644
--- a/Modules/Bar/Widgets/Bluetooth.qml
+++ b/Modules/Bar/Widgets/Bluetooth.qml
@@ -20,7 +20,7 @@ NIconButton {
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: Bootstrap.icons["bluetooth"]
+ icon: "bluetooth"
tooltipText: "Bluetooth"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this)
}
diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml
index a1ed557..feafbcc 100644
--- a/Modules/Bar/Widgets/Brightness.qml
+++ b/Modules/Bar/Widgets/Brightness.qml
@@ -46,7 +46,7 @@ Item {
function getIcon() {
var monitor = getMonitor()
var brightness = monitor ? monitor.brightness : 0
- return brightness <= 0.5 ? Bootstrap.icons["brightness_low"] : Bootstrap.icons["brightness_high"]
+ return brightness <= 0.5 ? "brightness-low" : "brightness-high"
}
// Connection used to open the pill when brightness changes
diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml
index 53f60f9..ae7d933 100644
--- a/Modules/Bar/Widgets/DarkModeToggle.qml
+++ b/Modules/Bar/Widgets/DarkModeToggle.qml
@@ -9,7 +9,7 @@ NIconButton {
property ShellScreen screen
property real scaling: 1.0
- icon: Bootstrap.icons["contrast"]
+ icon: "contrast"
tooltipText: "Toggle light/dark mode"
sizeRatio: 0.8
diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml
index ae588f5..31c6525 100644
--- a/Modules/Bar/Widgets/KeepAwake.qml
+++ b/Modules/Bar/Widgets/KeepAwake.qml
@@ -13,7 +13,7 @@ NIconButton {
sizeRatio: 0.8
- icon: Bootstrap.icons["coffee"]
+ icon: "coffee"
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake"
colorBg: Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mOnSurface
diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml
index 387316e..60ea83e 100644
--- a/Modules/Bar/Widgets/KeyboardLayout.qml
+++ b/Modules/Bar/Widgets/KeyboardLayout.qml
@@ -24,7 +24,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
rightOpen: BarWidgetRegistry.getNPillDirection(root)
- icon: Bootstrap.icons["keyboard"]
+ icon: "keyboard"
iconCircleColor: Color.mPrimary
collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index f7a42b5..28badc6 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -134,7 +134,7 @@ RowLayout {
NIcon {
id: windowIcon
- text: MediaService.isPlaying ? Bootstrap.icons["pause"] : Bootstrap.icons["play"]
+ text: MediaService.isPlaying ? "pause" : "play"
font.pointSize: Style.fontSizeL * scaling
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignVCenter
@@ -154,7 +154,7 @@ RowLayout {
id: trackArt
anchors.fill: parent
imagePath: MediaService.trackArtUrl
- fallbackIcon: MediaService.isPlaying ? Bootstrap.icons["pause"] : Bootstrap.icons["play"]
+ fallbackIcon: MediaService.isPlaying ? "pause" : "play"
fallbackIconSize: 10 * scaling
borderWidth: 0
border.color: Color.transparent
diff --git a/Modules/Bar/Widgets/Microphone.qml b/Modules/Bar/Widgets/Microphone.qml
index 15f4437..ed0a54c 100644
--- a/Modules/Bar/Widgets/Microphone.qml
+++ b/Modules/Bar/Widgets/Microphone.qml
@@ -43,9 +43,9 @@ Item {
function getIcon() {
if (AudioService.inputMuted) {
- return "mic_off"
+ return "mic-mute"
}
- return AudioService.inputVolume <= Number.EPSILON ? "mic_off" : (AudioService.inputVolume < 0.33 ? "mic" : "mic")
+ return AudioService.inputVolume <= Number.EPSILON ? "mic-mute" : (AudioService.inputVolume < 0.33 ? "mic" : "mic")
}
// Connection used to open the pill when input volume changes
diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml
index 0de4f72..3712f76 100644
--- a/Modules/Bar/Widgets/NightLight.qml
+++ b/Modules/Bar/Widgets/NightLight.qml
@@ -20,7 +20,7 @@ NIconButton {
colorBorder: Color.transparent
colorBorderHover: Color.transparent
- icon: Bootstrap.icons["moon-stars"]
+ icon: "moon-stars"
tooltipText: `Night light: ${Settings.data.nightLight.enabled ? "enabled." : "disabled."}\nLeft click to toggle.\nRight click to access settings.`
onClicked: Settings.data.nightLight.enabled = !Settings.data.nightLight.enabled
diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml
index 4a64d36..39b8c8f 100644
--- a/Modules/Bar/Widgets/NotificationHistory.qml
+++ b/Modules/Bar/Widgets/NotificationHistory.qml
@@ -53,7 +53,7 @@ NIconButton {
}
sizeRatio: 0.8
- icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell-slash"] : Bootstrap.icons["bell"]
+ icon: Settings.data.notifications.doNotDisturb ? "bell-slash" : "bell"
tooltipText: Settings.data.notifications.doNotDisturb ? "Notification history.\nRight-click to disable 'Do Not Disturb'." : "Notification history.\nRight-click to enable 'Do Not Disturb'."
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml
index 43bff33..6968413 100644
--- a/Modules/Bar/Widgets/PowerProfile.qml
+++ b/Modules/Bar/Widgets/PowerProfile.qml
@@ -19,13 +19,13 @@ NIconButton {
function profileIcon() {
if (!hasPP)
- return Bootstrap.icons["yin-yang"]
+ return "yin-yang"
if (powerProfiles.profile === PowerProfile.Performance)
- return Bootstrap.icons["speedometer2"]
+ return "speedometer2"
if (powerProfiles.profile === PowerProfile.Balanced)
- return Bootstrap.icons["yin-yang"]
+ return "yin-yang"
if (powerProfiles.profile === PowerProfile.PowerSaver)
- return Bootstrap.icons["leaf"]
+ return "leaf"
}
function profileName() {
@@ -57,4 +57,4 @@ NIconButton {
colorBorder: Color.transparent
colorBorderHover: Color.transparent
onClicked: root.changeProfile()
-}
\ No newline at end of file
+}
diff --git a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml
index 58c1208..00a785b 100644
--- a/Modules/Bar/Widgets/ScreenRecorderIndicator.qml
+++ b/Modules/Bar/Widgets/ScreenRecorderIndicator.qml
@@ -11,7 +11,7 @@ NIconButton {
property real scaling: 1.0
visible: ScreenRecorderService.isRecording
- icon: "videocam"
+ icon: "camera-video"
tooltipText: "Screen recording is active\nClick to stop recording"
sizeRatio: 0.8
colorBg: Color.mPrimary
diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml
index 56f3376..3d8b5bc 100644
--- a/Modules/Bar/Widgets/SidePanelToggle.qml
+++ b/Modules/Bar/Widgets/SidePanelToggle.qml
@@ -33,7 +33,7 @@ NIconButton {
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo
!== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
- icon: useDistroLogo ? "" : Bootstrap.icons["layout-sidebar-inset-reverse"]
+ icon: useDistroLogo ? "" :"layout-sidebar-inset-reverse"
tooltipText: "Open side panel."
sizeRatio: 0.8
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index e749116..b24edb0 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -64,14 +64,12 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showCpuUsage
- NIcon {
- id: cpuUsageIcon
- text: Bootstrap.icons["speedometer2"]
+ NIcon { icon: "speedometer2"
+ font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
NText {
- id: cpuUsageText
text: `${SystemStatService.cpuUsage}%`
font.family: Settings.data.ui.fontFixed
font.pointSize: Style.fontSizeS * scaling
@@ -89,8 +87,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showCpuTemp
- NIcon {
- text: Bootstrap.icons["fire"]
+ NIcon { icon: "fire"
+ font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
@@ -112,8 +110,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showMemoryUsage
- NIcon {
- text: Bootstrap.icons["memory"]
+ NIcon { icon: "memory"
+ font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
@@ -135,8 +133,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showNetworkStats
- NIcon {
- text: Bootstrap.icons["download"]
+ NIcon { icon: "download"
+ font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
@@ -158,8 +156,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showNetworkStats
- NIcon {
- text: Bootstrap.icons["upload"]
+ NIcon { icon: "upload"
+ font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 71fe1f3..677cdba 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -43,11 +43,11 @@ Item {
function getIcon() {
if (AudioService.muted) {
- return Bootstrap.icons["volume-mute"]
+ return "volume-mute"
}
return AudioService.volume
- <= Number.EPSILON ? Bootstrap.icons["volume-off"] : (AudioService.volume
- < 0.5 ? Bootstrap.icons["volume-down"] : Bootstrap.icons["volume-up"])
+ <= Number.EPSILON ? "volume-off" : (AudioService.volume
+ < 0.5 ? "volume-down" : "volume-up")
}
// Connection used to open the pill when volume changes
diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml
index bcbde44..4148f0a 100644
--- a/Modules/Bar/Widgets/WiFi.qml
+++ b/Modules/Bar/Widgets/WiFi.qml
@@ -23,7 +23,7 @@ NIconButton {
icon: {
try {
if (NetworkService.ethernetConnected) {
- return Bootstrap.icons["ethernet"]
+ return "ethernet"
}
let connected = false
let signalStrength = 0
@@ -34,7 +34,7 @@ NIconButton {
break
}
}
- return connected ? NetworkService.signalIcon(signalStrength) : "wifi_find"
+ return connected ? NetworkService.signalIcon(signalStrength) : "wifi-off"
} catch (error) {
Logger.error("Wi-Fi", "Error getting icon:", error)
return "signal_wifi_bad"
diff --git a/Modules/BluetoothPanel/BluetoothDevicesList.qml b/Modules/BluetoothPanel/BluetoothDevicesList.qml
index 390b709..4b79518 100644
--- a/Modules/BluetoothPanel/BluetoothDevicesList.qml
+++ b/Modules/BluetoothPanel/BluetoothDevicesList.qml
@@ -65,8 +65,7 @@ ColumnLayout {
Layout.alignment: Qt.AlignVCenter
// One device BT icon
- NIcon {
- text: BluetoothService.getDeviceIcon(modelData)
+ NIcon { icon: BluetoothService.getDeviceIcon(modelData)
font.pointSize: Style.fontSizeXXL * scaling
color: getContentColor(Color.mOnSurface)
Layout.alignment: Qt.AlignVCenter
diff --git a/Modules/BluetoothPanel/BluetoothPanel.qml b/Modules/BluetoothPanel/BluetoothPanel.qml
index 9c26adc..d9e8ac9 100644
--- a/Modules/BluetoothPanel/BluetoothPanel.qml
+++ b/Modules/BluetoothPanel/BluetoothPanel.qml
@@ -27,8 +27,7 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon {
- text: Bootstrap.icons["bluetooth"]
+ NIcon { icon: "bluetooth"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -43,7 +42,7 @@ NPanel {
NIconButton {
icon: BluetoothService.adapter
- && BluetoothService.adapter.discovering ? Bootstrap.icons["stop"] : Bootstrap.icons["arrow-repeat"]
+ && BluetoothService.adapter.discovering ? "stop" : "arrow-repeat"
tooltipText: "Refresh Devices"
sizeRatio: 0.8
onClicked: {
@@ -54,7 +53,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml
index ee048a1..25b69b1 100644
--- a/Modules/LockScreen/LockScreen.qml
+++ b/Modules/LockScreen/LockScreen.qml
@@ -328,7 +328,7 @@ Loader {
width: 100 * scaling
height: 100 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: Bootstrap.icons["person"]
+ fallbackIcon: "person"
}
MouseArea {
diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml
index c78ed0d..96c719a 100644
--- a/Modules/Notification/Notification.qml
+++ b/Modules/Notification/Notification.qml
@@ -294,7 +294,7 @@ Variants {
// Close button positioned absolutely
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
tooltipText: "Close"
sizeRatio: 0.6
anchors.top: parent.top
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index bf22c19..4b17797 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -30,8 +30,7 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon {
- text: Bootstrap.icons["bell"]
+ NIcon { icon: "bell"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -45,21 +44,21 @@ NPanel {
}
NIconButton {
- icon: Settings.data.notifications.doNotDisturb ? Bootstrap.icons["bell-slash"] : Bootstrap.icons["bell"]
+ icon: Settings.data.notifications.doNotDisturb ? "bell-slash" : "bell"
tooltipText: Settings.data.notifications.doNotDisturb ? "'Do Not Disturb' is enabled." : "'Do Not Disturb' is disabled."
sizeRatio: 0.8
onClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
}
NIconButton {
- icon: Bootstrap.icons["trash"]
+ icon: "trash"
tooltipText: "Clear history"
sizeRatio: 0.8
onClicked: NotificationService.clearHistory()
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
tooltipText: "Close"
sizeRatio: 0.8
onClicked: {
@@ -84,8 +83,7 @@ NPanel {
Layout.fillHeight: true
}
- NIcon {
- text: Bootstrap.icons["bell-slash"]
+ NIcon { icon: "bell-slash"
font.pointSize: 64 * scaling
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
@@ -175,7 +173,7 @@ NPanel {
// Delete button
NIconButton {
- icon: Bootstrap.icons["trash"]
+ icon: "trash"
tooltipText: "Delete notification"
sizeRatio: 0.7
Layout.alignment: Qt.AlignTop
diff --git a/Modules/SettingsPanel/Bar/BarSectionEditor.qml b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
index 919deb8..7e27096 100644
--- a/Modules/SettingsPanel/Bar/BarSectionEditor.qml
+++ b/Modules/SettingsPanel/Bar/BarSectionEditor.qml
@@ -85,7 +85,7 @@ NBox {
}
NIconButton {
- icon: Bootstrap.icons["plus-lg"]
+ icon: "plus-lg"
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
@@ -170,7 +170,7 @@ NBox {
Loader {
active: BarWidgetRegistry.widgetHasUserSettings(modelData.id)
sourceComponent: NIconButton {
- icon: Bootstrap.icons["gear"]
+ icon: "gear"
sizeRatio: 0.6
colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
colorBg: Color.mOnSurface
@@ -210,7 +210,7 @@ NBox {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
sizeRatio: 0.6
colorBorder: Qt.alpha(Color.mOutline, Style.opacityLight)
colorBg: Color.mOnSurface
diff --git a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
index 5cc8e0e..b80c156 100644
--- a/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
+++ b/Modules/SettingsPanel/Bar/BarWidgetSettingsDialog.qml
@@ -84,7 +84,7 @@ Popup {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
onClicked: settingsPopup.close()
}
}
@@ -121,7 +121,7 @@ Popup {
NButton {
text: "Apply"
- icon: Bootstrap.icons["check"]
+ icon: "check-lg"
onClicked: {
if (settingsLoader.item && settingsLoader.item.saveSettings) {
var newSettings = settingsLoader.item.saveSettings()
diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml
index d07db79..6b5e4bd 100644
--- a/Modules/SettingsPanel/SettingsPanel.qml
+++ b/Modules/SettingsPanel/SettingsPanel.qml
@@ -472,7 +472,7 @@ NPanel {
// Close button
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
tooltipText: "Close"
Layout.alignment: Qt.AlignVCenter
onClicked: root.close()
diff --git a/Modules/SettingsPanel/Tabs/AboutTab.qml b/Modules/SettingsPanel/Tabs/AboutTab.qml
index 7c0b28e..1fffadb 100644
--- a/Modules/SettingsPanel/Tabs/AboutTab.qml
+++ b/Modules/SettingsPanel/Tabs/AboutTab.qml
@@ -172,7 +172,7 @@ ColumnLayout {
imagePath: modelData.avatar_url || ""
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
- fallbackIcon: Bootstrap.icons["person"]
+ fallbackIcon: "person"
borderColor: contributorArea.containsMouse ? Color.mOnTertiary : Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml
index dba15ca..16e6781 100644
--- a/Modules/SettingsPanel/Tabs/AudioTab.qml
+++ b/Modules/SettingsPanel/Tabs/AudioTab.qml
@@ -272,7 +272,7 @@ ColumnLayout {
// Button aligned to the center of the actual input field
NIconButton {
- icon: Bootstrap.icons["plus-lg"]
+ icon: "plus-lg"
Layout.alignment: Qt.AlignBottom
Layout.bottomMargin: blacklistInput.description ? Style.marginS * scaling : 0
onClicked: {
@@ -322,7 +322,7 @@ ColumnLayout {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
sizeRatio: 0.8
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Style.marginXS * scaling
diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml
index 03475d0..534b62c 100644
--- a/Modules/SettingsPanel/Tabs/DisplayTab.qml
+++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml
@@ -181,7 +181,7 @@ ColumnLayout {
}
NIconButton {
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
tooltipText: "Reset scaling"
onClicked: ScalingService.setScreenScale(modelData, 1.0)
}
diff --git a/Modules/SettingsPanel/Tabs/GeneralTab.qml b/Modules/SettingsPanel/Tabs/GeneralTab.qml
index 6b75b9b..fe4dbcd 100644
--- a/Modules/SettingsPanel/Tabs/GeneralTab.qml
+++ b/Modules/SettingsPanel/Tabs/GeneralTab.qml
@@ -19,7 +19,7 @@ ColumnLayout {
width: 108 * scaling
height: 108 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: Bootstrap.icons["person"]
+ fallbackIcon: "person"
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
Layout.alignment: Qt.AlignTop
diff --git a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
index df3556e..8d3e77b 100644
--- a/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
+++ b/Modules/SettingsPanel/Tabs/WallpaperSelectorTab.qml
@@ -59,7 +59,7 @@ ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: currentWallpaper
- fallbackIcon: Bootstrap.icons["image"]
+ fallbackIcon: "image"
imageRadius: Style.radiusM * scaling
borderColor: Color.mSecondary
borderWidth: Style.borderL * 2 * scaling
@@ -96,7 +96,7 @@ ColumnLayout {
}
NIconButton {
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
tooltipText: "Refresh wallpaper list"
onClicked: {
WallpaperService.refreshWallpapersList()
@@ -181,7 +181,7 @@ ColumnLayout {
visible: isSelected
NIcon {
- text: Bootstrap.icons["check"]
+ icon: "check-lg"
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml
index 17716d7..bc786d5 100644
--- a/Modules/SidePanel/Cards/MediaCard.qml
+++ b/Modules/SidePanel/Cards/MediaCard.qml
@@ -31,7 +31,7 @@ NBox {
}
NIcon {
- text: Bootstrap.icons["album"]
+ text: "album"
font.pointSize: Style.fontSizeXXXL * 2.5 * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -89,7 +89,7 @@ NBox {
indicator: NIcon {
x: playerSelector.width - width
y: playerSelector.topPadding + (playerSelector.availableHeight - height) / 2
- text: Bootstrap.icons["arrow_drop_down"]
+ text: "arrow_drop_down"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mOnSurface
horizontalAlignment: Text.AlignRight
@@ -162,14 +162,14 @@ NBox {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: MediaService.trackArtUrl
- fallbackIcon: Bootstrap.icons["album"]
+ fallbackIcon: "album"
borderColor: Color.mOutline
borderWidth: Math.max(1, Style.borderS * scaling)
}
// Fallback icon when no album art available
NIcon {
- text: Bootstrap.icons["album"]
+ icon: "album"
color: Color.mPrimary
font.pointSize: Style.fontSizeL * 12 * scaling
visible: !trackArt.visible
@@ -307,7 +307,7 @@ NBox {
// Previous button
NIconButton {
- icon: Bootstrap.icons["prev"]
+ icon: "skip-start"
tooltipText: "Previous Media"
visible: MediaService.canGoPrevious
onClicked: MediaService.canGoPrevious ? MediaService.previous() : {}
@@ -315,7 +315,7 @@ NBox {
// Play/Pause button
NIconButton {
- icon: MediaService.isPlaying ? Bootstrap.icons["pause"] : Bootstrap.icons["play"]
+ icon: MediaService.isPlaying ? "pause" : "play"
tooltipText: MediaService.isPlaying ? "Pause" : "Play"
visible: (MediaService.canPlay || MediaService.canPause)
onClicked: (MediaService.canPlay || MediaService.canPause) ? MediaService.playPause() : {}
@@ -323,7 +323,7 @@ NBox {
// Next button
NIconButton {
- icon: Bootstrap.icons["next"]
+ icon: "skip-end"
tooltipText: "Next media"
visible: MediaService.canGoNext
onClicked: MediaService.canGoNext ? MediaService.next() : {}
diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml
index 1cc7732..3892c7f 100644
--- a/Modules/SidePanel/Cards/PowerProfilesCard.qml
+++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml
@@ -28,7 +28,7 @@ NBox {
}
// Performance
NIconButton {
- icon: Bootstrap.icons["speedometer2"]
+ icon: "speedometer2"
tooltipText: "Set performance power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
@@ -42,7 +42,7 @@ NBox {
}
// Balanced
NIconButton {
- icon: Bootstrap.icons["yin-yang"]
+ icon: "yin-yang"
tooltipText: "Set balanced power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
@@ -56,7 +56,7 @@ NBox {
}
// Eco
NIconButton {
- icon: Bootstrap.icons["leaf"]
+ icon: "leaf"
tooltipText: "Set eco power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
diff --git a/Modules/SidePanel/Cards/ProfileCard.qml b/Modules/SidePanel/Cards/ProfileCard.qml
index d85a432..a9ef68b 100644
--- a/Modules/SidePanel/Cards/ProfileCard.qml
+++ b/Modules/SidePanel/Cards/ProfileCard.qml
@@ -32,7 +32,7 @@ NBox {
width: Style.baseWidgetSize * 1.25 * scaling
height: Style.baseWidgetSize * 1.25 * scaling
imagePath: Settings.data.general.avatarImage
- fallbackIcon: Bootstrap.icons["person"]
+ fallbackIcon: "person"
borderColor: Color.mPrimary
borderWidth: Math.max(1, Style.borderM * scaling)
}
@@ -58,7 +58,7 @@ NBox {
Layout.fillWidth: true
}
NIconButton {
- icon: Bootstrap.icons["gear"]
+ icon: "gear"
tooltipText: "Open settings."
onClicked: {
settingsPanel.requestedTab = SettingsPanel.Tab.General
@@ -68,7 +68,7 @@ NBox {
NIconButton {
id: powerButton
- icon: Bootstrap.icons["power"]
+ icon: "power"
tooltipText: "Power menu."
onClicked: {
powerPanel.open(screen)
@@ -78,7 +78,7 @@ NBox {
NIconButton {
id: closeButton
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
tooltipText: "Close side panel."
onClicked: {
sidePanel.close()
diff --git a/Modules/SidePanel/Cards/SystemMonitorCard.qml b/Modules/SidePanel/Cards/SystemMonitorCard.qml
index c8515fa..f5cda28 100644
--- a/Modules/SidePanel/Cards/SystemMonitorCard.qml
+++ b/Modules/SidePanel/Cards/SystemMonitorCard.qml
@@ -24,7 +24,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuUsage
- icon: Bootstrap.icons["speedometer2"]
+ icon: "speedometer2"
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -33,7 +33,7 @@ NBox {
NCircleStat {
value: SystemStatService.cpuTemp
suffix: "°C"
- icon: Bootstrap.icons["fire"]
+ icon: "fire"
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -41,7 +41,7 @@ NBox {
}
NCircleStat {
value: SystemStatService.memPercent
- icon: Bootstrap.icons["memory"]
+ icon: "memory"
flat: true
contentScale: 0.8
width: 72 * scaling
@@ -49,7 +49,7 @@ NBox {
}
NCircleStat {
value: SystemStatService.diskPercent
- icon: Bootstrap.icons["drive"]
+ icon: "hdd"
flat: true
contentScale: 0.8
width: 72 * scaling
diff --git a/Modules/SidePanel/Cards/UtilitiesCard.qml b/Modules/SidePanel/Cards/UtilitiesCard.qml
index c34a7f3..7c00eac 100644
--- a/Modules/SidePanel/Cards/UtilitiesCard.qml
+++ b/Modules/SidePanel/Cards/UtilitiesCard.qml
@@ -25,7 +25,7 @@ NBox {
}
// Screen Recorder
NIconButton {
- icon: Bootstrap.icons["camera-video"]
+ icon: "camera-video"
tooltipText: ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording."
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
@@ -41,7 +41,7 @@ NBox {
// Idle Inhibitor
NIconButton {
- icon: Bootstrap.icons["cup-hot"]
+ icon: "cup-hot"
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake." : "Enable keep awake."
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
@@ -53,7 +53,7 @@ NBox {
// Wallpaper
NIconButton {
visible: Settings.data.wallpaper.enabled
- icon: Bootstrap.icons["image"]
+ icon: "image"
tooltipText: "Left click: Open wallpaper selector.\nRight click: Set random wallpaper."
onClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
diff --git a/Modules/SidePanel/Cards/WeatherCard.qml b/Modules/SidePanel/Cards/WeatherCard.qml
index 3751478..eab4f16 100644
--- a/Modules/SidePanel/Cards/WeatherCard.qml
+++ b/Modules/SidePanel/Cards/WeatherCard.qml
@@ -98,7 +98,7 @@ NBox {
color: Color.mOnSurface
}
NIcon {
- text: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
+ icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index 59698ea..bb5ca7c 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -33,8 +33,7 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon {
- text: Settings.data.network.wifiEnabled ? "wifi" : "wifi_off"
+ NIcon { icon: Settings.data.network.wifiEnabled ? "wifi" : "wifi-off"
font.pointSize: Style.fontSizeXXL * scaling
color: Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant
}
@@ -55,7 +54,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
tooltipText: "Refresh"
sizeRatio: 0.8
enabled: Settings.data.network.wifiEnabled && !NetworkService.scanning
@@ -63,7 +62,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
tooltipText: "Close"
sizeRatio: 0.8
onClicked: root.close()
@@ -91,7 +90,7 @@ NPanel {
spacing: Style.marginS * scaling
NIcon {
- text: "error"
+ icon: "error"
font.pointSize: Style.fontSizeL * scaling
color: Color.mError
}
@@ -105,7 +104,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
sizeRatio: 0.6
onClicked: NetworkService.lastError = ""
}
@@ -129,7 +128,7 @@ NPanel {
}
NIcon {
- text: "wifi_off"
+ icon: "wifi-off"
font.pointSize: 64 * scaling
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
@@ -377,7 +376,7 @@ NPanel {
&& NetworkService.connectingTo !== modelData.ssid
&& NetworkService.forgettingNetwork !== modelData.ssid
&& NetworkService.disconnectingFrom !== modelData.ssid
- icon: Bootstrap.icons["trash"]
+ icon: "trash"
tooltipText: "Forget network"
sizeRatio: 0.7
onClicked: expandedSsid = expandedSsid === modelData.ssid ? "" : modelData.ssid
@@ -492,7 +491,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
sizeRatio: 0.8
onClicked: {
passwordSsid = ""
@@ -547,7 +546,7 @@ NPanel {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
sizeRatio: 0.8
onClicked: expandedSsid = ""
}
@@ -571,7 +570,7 @@ NPanel {
}
NIcon {
- text: "wifi_find"
+ icon: "search"
font.pointSize: 64 * scaling
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
@@ -586,7 +585,7 @@ NPanel {
NButton {
text: "Scan again"
- icon: Bootstrap.icons["arrow-repeat"]
+ icon: "arrow-repeat"
Layout.alignment: Qt.AlignHCenter
onClicked: NetworkService.scan()
}
diff --git a/Services/BatteryService.qml b/Services/BatteryService.qml
index 3bad2cc..e68a239 100644
--- a/Services/BatteryService.qml
+++ b/Services/BatteryService.qml
@@ -11,20 +11,20 @@ Singleton {
// Choose icon based on charge and charging state
function getIcon(percent, charging, isReady) {
if (!isReady) {
- return Bootstrap.icons["exclamation-diamond"]
+ return "exclamation-diamond"
}
if (charging) {
- return Bootstrap.icons["battery-charging"]
+ return "battery-charging"
} else {
if (percent >= 85)
- return Bootstrap.icons["battery-full"]
+ return "battery-full"
if (percent >= 45)
- return Bootstrap.icons["battery-half"]
+ return "battery-half"
if (percent >= 25)
- return Bootstrap.icons["battery-low"]
+ return "battery-low"
if (percent >= 0)
- return Bootstrap.icons["battery"]
+ return "battery"
}
}
}
diff --git a/Services/BluetoothService.qml b/Services/BluetoothService.qml
index 9b12ebc..b029b70 100644
--- a/Services/BluetoothService.qml
+++ b/Services/BluetoothService.qml
@@ -51,36 +51,36 @@ Singleton {
function getDeviceIcon(device) {
if (!device) {
- return Bootstrap.icons["bluetooth"]
+ return "bluetooth"
}
var name = (device.name || device.deviceName || "").toLowerCase()
var icon = (device.icon || "").toLowerCase()
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") || name.includes("airpod")
|| name.includes("headset") || name.includes("arctis")) {
- return Bootstrap.icons["headset"]
+ return "headset"
}
if (icon.includes("mouse") || name.includes("mouse")) {
- return Bootstrap.icons["mouse-2"]
+ return "mouse-2"
}
if (icon.includes("keyboard") || name.includes("keyboard")) {
- return Bootstrap.icons["keyboard"]
+ return "keyboard"
}
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android")
|| name.includes("samsung")) {
- return Bootstrap.icons["phone"]
+ return "phone"
}
if (icon.includes("watch") || name.includes("watch")) {
- return Bootstrap.icons["smartwatch"]
+ return "smartwatch"
}
if (icon.includes("speaker") || name.includes("speaker")) {
- return Bootstrap.icons["speaker"]
+ return "speaker"
}
if (icon.includes("display") || name.includes("tv")) {
- return Bootstrap.icons["tv"]
+ return "tv"
}
- return Bootstrap.icons["bluetooth"]
+ return "bluetooth"
}
function canConnect(device) {
diff --git a/Services/LocationService.qml b/Services/LocationService.qml
index 7575cc5..0cbdbd5 100644
--- a/Services/LocationService.qml
+++ b/Services/LocationService.qml
@@ -231,24 +231,24 @@ Singleton {
// --------------------------------
function weatherSymbolFromCode(code) {
if (code === 0)
- return Bootstrap.icons["sun"]
+ return "sun"
if (code === 1 || code === 2)
- return Bootstrap.icons["cloud-sun"]
+ return "cloud-sun"
if (code === 3)
- return Bootstrap.icons["cloud"]
+ return "cloud"
if (code >= 45 && code <= 48)
- return Bootstrap.icons["cloud-haze"]
+ return "cloud-haze"
if (code >= 51 && code <= 67)
- return Bootstrap.icons["cloud-rain"]
+ return "cloud-rain"
if (code >= 71 && code <= 77)
- return Bootstrap.icons["cloud-snow"]
+ return "cloud-snow"
if (code >= 71 && code <= 77)
- return Bootstrap.icons["cloud-snow"]
+ return "cloud-snow"
if (code >= 85 && code <= 86)
- return Bootstrap.icons["cloud-snow"]
+ return "cloud-snow"
if (code >= 95 && code <= 99)
- return Bootstrap.icons["cloud-lightning"]
- return Bootstrap.icons["cloud"]
+ return "cloud-lightning"
+ return "cloud"
}
// --------------------------------
diff --git a/Services/NetworkService.qml b/Services/NetworkService.qml
index 6bf7ac5..97304c1 100644
--- a/Services/NetworkService.qml
+++ b/Services/NetworkService.qml
@@ -202,14 +202,12 @@ Singleton {
// Helper functions
function signalIcon(signal) {
if (signal >= 80)
- return "network_wifi"
- if (signal >= 60)
- return "network_wifi_3_bar"
- if (signal >= 40)
- return "network_wifi_2_bar"
+ return "wifi"
+ if (signal >= 50)
+ return "wifi-2"
if (signal >= 20)
- return "network_wifi_1_bar"
- return "signal_wifi_0_bar"
+ return "wifi-1"
+ return "dot"
}
function isSecured(security) {
diff --git a/Widgets/NButton.qml b/Widgets/NButton.qml
index 8d8425c..186d474 100644
--- a/Widgets/NButton.qml
+++ b/Widgets/NButton.qml
@@ -83,7 +83,7 @@ Rectangle {
NIcon {
Layout.alignment: Qt.AlignVCenter
visible: root.icon !== ""
- text: root.icon
+ icon: root.icon
font.pointSize: root.iconSize
color: {
if (!root.enabled)
diff --git a/Widgets/NCheckbox.qml b/Widgets/NCheckbox.qml
index 4b5962d..3dd9783 100644
--- a/Widgets/NCheckbox.qml
+++ b/Widgets/NCheckbox.qml
@@ -57,7 +57,7 @@ RowLayout {
NIcon {
visible: root.checked
anchors.centerIn: parent
- text: "check"
+ icon: "check-lg"
color: root.activeOnColor
font.pointSize: Math.max(Style.fontSizeS, root.baseSize * 0.7) * scaling
}
diff --git a/Widgets/NCircleStat.qml b/Widgets/NCircleStat.qml
index e16cb12..997a99c 100644
--- a/Widgets/NCircleStat.qml
+++ b/Widgets/NCircleStat.qml
@@ -99,7 +99,7 @@ Rectangle {
NIcon {
anchors.centerIn: parent
- text: root.icon
+ icon: root.icon
font.pointSize: Style.fontSizeLargeXL * scaling * contentScale
color: Color.mOnSurface
horizontalAlignment: Text.AlignHCenter
diff --git a/Widgets/NColorPicker.qml b/Widgets/NColorPicker.qml
index 7cbeaad..0e80080 100644
--- a/Widgets/NColorPicker.qml
+++ b/Widgets/NColorPicker.qml
@@ -59,7 +59,7 @@ Rectangle {
}
NIcon {
- text: Bootstrap.icons["eyedropper"]
+ icon: "paint-bucket"
color: Color.mOnSurfaceVariant
}
}
diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml
index 7fe60bc..60f5fd1 100644
--- a/Widgets/NColorPickerDialog.qml
+++ b/Widgets/NColorPickerDialog.qml
@@ -130,7 +130,7 @@ Popup {
spacing: Style.marginS * scaling
NIcon {
- text: Bootstrap.icons["eyedropper"]
+ icon: "eyedropper"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -148,7 +148,7 @@ Popup {
}
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
onClicked: root.close()
}
}
@@ -492,7 +492,7 @@ Popup {
NButton {
id: cancelButton
text: "Cancel"
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
outlined: cancelButton.hovered ? false : true
customHeight: 36 * scaling
customWidth: 100 * scaling
@@ -503,7 +503,7 @@ Popup {
NButton {
text: "Apply"
- icon: Bootstrap.icons["check"]
+ icon: "check-lg"
customHeight: 36 * scaling
customWidth: 100 * scaling
onClicked: {
diff --git a/Widgets/NComboBox.qml b/Widgets/NComboBox.qml
index 538de23..ab3e708 100644
--- a/Widgets/NComboBox.qml
+++ b/Widgets/NComboBox.qml
@@ -85,7 +85,7 @@ RowLayout {
indicator: NIcon {
x: combo.width - width - Style.marginM * scaling
y: combo.topPadding + (combo.availableHeight - height) / 2
- text: Bootstrap.icons["chevron-down"]
+ icon: "chevron-down"
font.pointSize: Style.fontSizeL * scaling
}
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index 0dc6f7b..6d70c6f 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -4,6 +4,9 @@ import qs.Commons
import qs.Widgets
Text {
+ property string icon: "balloon"
+
+ text: Bootstrap.icons[icon]
font.family: "bootstrap-icons"
font.pointSize: Style.fontSizeL * scaling
color: Color.mOnSurface
diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml
index c9755b3..d787880 100644
--- a/Widgets/NIconButton.qml
+++ b/Widgets/NIconButton.qml
@@ -39,7 +39,7 @@ Rectangle {
border.width: Math.max(1, Style.borderS * scaling)
NIcon {
- text: root.icon
+ icon: root.icon
font.pointSize: Style.fontSizeM * scaling
color: root.hovering ? colorFgHover : colorFg
// Center horizontally
diff --git a/Widgets/NInputAction.qml b/Widgets/NInputAction.qml
index cc86c03..1ae0629 100644
--- a/Widgets/NInputAction.qml
+++ b/Widgets/NInputAction.qml
@@ -14,7 +14,7 @@ RowLayout {
property string placeholderText: ""
property string text: ""
property string actionButtonText: "Test"
- property string actionButtonIcon: Bootstrap.icons["play"]
+ property string actionButtonIcon: "play"
property bool actionButtonEnabled: text !== ""
// Signals
diff --git a/Widgets/NPill.qml b/Widgets/NPill.qml
index a30e2c7..a64332f 100644
--- a/Widgets/NPill.qml
+++ b/Widgets/NPill.qml
@@ -117,7 +117,7 @@ Item {
}
NIcon {
- text: root.icon
+ icon: root.icon
font.pointSize: Style.fontSizeM * scaling
// When forced shown, use pill text color; otherwise accent color when hovered
color: forceOpen ? textColor : (showPill ? iconTextColor : Color.mOnSurface)
diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml
index 27d1e0f..a2f2d5c 100644
--- a/Widgets/NSpinBox.qml
+++ b/Widgets/NSpinBox.qml
@@ -95,7 +95,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: Bootstrap.icons["dash-lg"]
+ text: "dash-lg"
font.pointSize: Style.fontSizeS * scaling
color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -130,7 +130,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: Bootstrap.icons["plus-lg"]
+ text: "plus-lg"
font.pointSize: Style.fontSizeS * scaling
color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index 00cb81b..bd13f38 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -118,7 +118,7 @@ Item {
// Icon
NIcon {
id: icon
- text: (root.type == "warning") ? Bootstrap.icons["warning"] : Bootstrap.icons["info"]
+ text: (root.type == "warning") ? "warning" : "info"
color: {
switch (root.type) {
case "warning":
@@ -162,7 +162,7 @@ Item {
// Close button (only if persistent or manual dismiss needed)
NIconButton {
- icon: Bootstrap.icons["x-lg"]
+ icon: "x-lg"
visible: root.persistent || root.duration === 0
colorBg: Color.mSurfaceVariant
From bacd65b274571b01e72af1ee9424ba55cf438082 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 22:21:18 -0400
Subject: [PATCH 036/118] Icons: 99% done
---
Commons/Bootstrap.qml | 48 -------------------
Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml | 16 ++++---
Modules/Bar/Widgets/ArchUpdater.qml | 8 ++--
Modules/Bar/Widgets/DarkModeToggle.qml | 6 +--
Modules/Bar/Widgets/KeepAwake.qml | 6 +--
Modules/Bar/Widgets/PowerToggle.qml | 2 +-
Modules/Bar/Widgets/SidePanelToggle.qml | 2 +-
Modules/Bar/Widgets/SystemMonitor.qml | 15 ++++--
Modules/Bar/Widgets/Volume.qml | 4 +-
.../BluetoothPanel/BluetoothDevicesList.qml | 3 +-
Modules/BluetoothPanel/BluetoothPanel.qml | 6 +--
.../Notification/NotificationHistoryPanel.qml | 6 ++-
Modules/SidePanel/Cards/MediaCard.qml | 6 +--
Modules/SidePanel/Cards/UtilitiesCard.qml | 2 +-
Modules/SidePanel/Cards/WeatherCard.qml | 2 +-
Modules/WiFiPanel/WiFiPanel.qml | 3 +-
Widgets/NImageCircled.qml | 2 +-
Widgets/NImageRounded.qml | 2 +-
Widgets/NToast.qml | 2 +-
19 files changed, 51 insertions(+), 90 deletions(-)
diff --git a/Commons/Bootstrap.qml b/Commons/Bootstrap.qml
index 1cb2ff5..efbac74 100644
--- a/Commons/Bootstrap.qml
+++ b/Commons/Bootstrap.qml
@@ -8,54 +8,6 @@ import qs.Commons
Singleton {
id: root
- // "wifi_disable": "\uF61B",
- // "wifi_low": "\uF619",
- // "wifi_half": "\uF61A",
- // "wifi_full": "\uF61C",
- // "power": "\uF4FF",
-
- // "close": "\uF659",
- // "check": "\uF272",
- // "panel": "\uF290",
- // "memory": "\uF2D6",
- // "trash": "\uF78B",
- // "video_camera": "\uF21F",
- // "ethernet": "\uF2EB",
- // "speed": "\uF66B",
- // "leaf": "\uF90C",
- // "microphone": "\uF490",
- // "microphone_muted": "\uF48F",
- // "coffee": "\uF2E0",
- // "refresh": "\uF130",
- // "image": "\uF226",
- // "contrast": "\uF288",
- // "record": "\uF518",
- // "pause": "\uF4C1",
- // "play": "\uF4F2",
- // "stop": "\uF590",
- // "prev": "\uF561",
- // "next": "\uF55B",
- // "arrow_drop_down": "\uF22C",
- // "warning": "\uF334",
- // "info": "\uF26A",
- // "upload": "\uF296",
- // "download": "\uF294",
- // "album": "\uF2FF",
-
- // "eyedropper": "\uF342",
- // "drive": "\uF412",
-
- // "person": "\uF4DA",
- // "bar": "\uF52B",
- // "launcher": "\uF843",
- // "palette": "\uF4B1",
- // "sunrise": "\uF5A5",
- // "moon_stars": "\uF496",
- // "gauge": "\uF580",
- // "lightning": "\uF46D",
-
- // // another contrast \uF8F3 \uF8DA
- // }
property var icons: {
"alarm-fill": "\uF101",
"alarm": "\uF102",
diff --git a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
index accde47..b1d1443 100644
--- a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
+++ b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
@@ -27,7 +27,8 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon { icon: "system_update_alt"
+ NIcon {
+ icon: "system_update_alt"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -101,7 +102,8 @@ NPanel {
Layout.fillHeight: true
} // Spacer
- NIcon { icon: "hourglass_empty"
+ NIcon {
+ icon: "hourglass_empty"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -217,7 +219,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- icon: "error"
+ icon: "exclamation"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -268,7 +270,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- icon: "error_outline"
+ icon: "exclamation"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -321,7 +323,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- icon: "check_circle"
+ icon: "check-lg"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -493,7 +495,7 @@ NPanel {
}
NIconButton {
- icon: "system_update_alt"
+ icon: "box-fill"
tooltipText: "Update all packages"
enabled: ArchUpdaterService.totalUpdates > 0
onClicked: {
@@ -506,7 +508,7 @@ NPanel {
}
NIconButton {
- icon: "check_box"
+ icon: "box"
tooltipText: "Update selected packages"
enabled: ArchUpdaterService.selectedPackagesCount > 0
onClicked: {
diff --git a/Modules/Bar/Widgets/ArchUpdater.qml b/Modules/Bar/Widgets/ArchUpdater.qml
index 3fb7c85..7a1d888 100644
--- a/Modules/Bar/Widgets/ArchUpdater.qml
+++ b/Modules/Bar/Widgets/ArchUpdater.qml
@@ -29,15 +29,15 @@ NIconButton {
return "terminal"
}
if (!ArchUpdaterService.aurHelperAvailable) {
- return "package"
+ return "box"
}
if (ArchUpdaterService.aurBusy) {
- return "sync"
+ return "arrow-repeat"
}
if (ArchUpdaterService.totalUpdates > 0) {
- return "system_update_alt"
+ return "box-fill"
}
- return "task_alt"
+ return "box"
}
// Tooltip with repo vs AUR breakdown and sample lists
diff --git a/Modules/Bar/Widgets/DarkModeToggle.qml b/Modules/Bar/Widgets/DarkModeToggle.qml
index ae7d933..4c3ec1e 100644
--- a/Modules/Bar/Widgets/DarkModeToggle.qml
+++ b/Modules/Bar/Widgets/DarkModeToggle.qml
@@ -9,12 +9,12 @@ NIconButton {
property ShellScreen screen
property real scaling: 1.0
- icon: "contrast"
+ icon: "transparency"
tooltipText: "Toggle light/dark mode"
sizeRatio: 0.8
- colorBg: Color.mSurfaceVariant
- colorFg: Color.mOnSurface
+ colorBg: Settings.data.colorSchemes.darkMode ? Color.mSurfaceVariant : Color.mPrimary
+ colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
colorBorder: Color.transparent
colorBorderHover: Color.transparent
diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml
index 31c6525..ebd880c 100644
--- a/Modules/Bar/Widgets/KeepAwake.qml
+++ b/Modules/Bar/Widgets/KeepAwake.qml
@@ -13,10 +13,10 @@ NIconButton {
sizeRatio: 0.8
- icon: "coffee"
+ icon: "cup"
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake" : "Enable keep awake"
- colorBg: Color.mSurfaceVariant
- colorFg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mOnSurface
+ colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
+ colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mOnSurface
colorBorder: Color.transparent
onClicked: {
IdleInhibitorService.manualToggle()
diff --git a/Modules/Bar/Widgets/PowerToggle.qml b/Modules/Bar/Widgets/PowerToggle.qml
index 219202a..25e380c 100644
--- a/Modules/Bar/Widgets/PowerToggle.qml
+++ b/Modules/Bar/Widgets/PowerToggle.qml
@@ -13,7 +13,7 @@ NIconButton {
sizeRatio: 0.8
- icon: "power_settings_new"
+ icon: "power"
tooltipText: "Power Settings"
colorBg: Color.mSurfaceVariant
colorFg: Color.mError
diff --git a/Modules/Bar/Widgets/SidePanelToggle.qml b/Modules/Bar/Widgets/SidePanelToggle.qml
index 3d8b5bc..326d7b1 100644
--- a/Modules/Bar/Widgets/SidePanelToggle.qml
+++ b/Modules/Bar/Widgets/SidePanelToggle.qml
@@ -33,7 +33,7 @@ NIconButton {
readonly property bool useDistroLogo: (widgetSettings.useDistroLogo
!== undefined) ? widgetSettings.useDistroLogo : widgetMetadata.useDistroLogo
- icon: useDistroLogo ? "" :"layout-sidebar-inset-reverse"
+ icon: useDistroLogo ? "" : "layout-sidebar-inset-reverse"
tooltipText: "Open side panel."
sizeRatio: 0.8
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index b24edb0..b89a391 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -64,7 +64,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showCpuUsage
- NIcon { icon: "speedometer2"
+ NIcon {
+ icon: "speedometer2"
font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
@@ -87,7 +88,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showCpuTemp
- NIcon { icon: "fire"
+ NIcon {
+ icon: "fire"
font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
@@ -110,7 +112,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showMemoryUsage
- NIcon { icon: "memory"
+ NIcon {
+ icon: "memory"
font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
@@ -133,7 +136,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showNetworkStats
- NIcon { icon: "download"
+ NIcon {
+ icon: "download"
font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
@@ -156,7 +160,8 @@ RowLayout {
Layout.alignment: Qt.AlignVCenter
visible: showNetworkStats
- NIcon { icon: "upload"
+ NIcon {
+ icon: "upload"
font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 677cdba..690a92e 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -45,9 +45,7 @@ Item {
if (AudioService.muted) {
return "volume-mute"
}
- return AudioService.volume
- <= Number.EPSILON ? "volume-off" : (AudioService.volume
- < 0.5 ? "volume-down" : "volume-up")
+ return AudioService.volume <= Number.EPSILON ? "volume-off" : (AudioService.volume < 0.5 ? "volume-down" : "volume-up")
}
// Connection used to open the pill when volume changes
diff --git a/Modules/BluetoothPanel/BluetoothDevicesList.qml b/Modules/BluetoothPanel/BluetoothDevicesList.qml
index 4b79518..efa5c8f 100644
--- a/Modules/BluetoothPanel/BluetoothDevicesList.qml
+++ b/Modules/BluetoothPanel/BluetoothDevicesList.qml
@@ -65,7 +65,8 @@ ColumnLayout {
Layout.alignment: Qt.AlignVCenter
// One device BT icon
- NIcon { icon: BluetoothService.getDeviceIcon(modelData)
+ NIcon {
+ icon: BluetoothService.getDeviceIcon(modelData)
font.pointSize: Style.fontSizeXXL * scaling
color: getContentColor(Color.mOnSurface)
Layout.alignment: Qt.AlignVCenter
diff --git a/Modules/BluetoothPanel/BluetoothPanel.qml b/Modules/BluetoothPanel/BluetoothPanel.qml
index d9e8ac9..12d1b50 100644
--- a/Modules/BluetoothPanel/BluetoothPanel.qml
+++ b/Modules/BluetoothPanel/BluetoothPanel.qml
@@ -27,7 +27,8 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon { icon: "bluetooth"
+ NIcon {
+ icon: "bluetooth"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -41,8 +42,7 @@ NPanel {
}
NIconButton {
- icon: BluetoothService.adapter
- && BluetoothService.adapter.discovering ? "stop" : "arrow-repeat"
+ icon: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "arrow-repeat"
tooltipText: "Refresh Devices"
sizeRatio: 0.8
onClicked: {
diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml
index 4b17797..bb97b84 100644
--- a/Modules/Notification/NotificationHistoryPanel.qml
+++ b/Modules/Notification/NotificationHistoryPanel.qml
@@ -30,7 +30,8 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon { icon: "bell"
+ NIcon {
+ icon: "bell"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -83,7 +84,8 @@ NPanel {
Layout.fillHeight: true
}
- NIcon { icon: "bell-slash"
+ NIcon {
+ icon: "bell-slash"
font.pointSize: 64 * scaling
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
diff --git a/Modules/SidePanel/Cards/MediaCard.qml b/Modules/SidePanel/Cards/MediaCard.qml
index bc786d5..7d3f5cf 100644
--- a/Modules/SidePanel/Cards/MediaCard.qml
+++ b/Modules/SidePanel/Cards/MediaCard.qml
@@ -31,7 +31,7 @@ NBox {
}
NIcon {
- text: "album"
+ icon: "disc"
font.pointSize: Style.fontSizeXXXL * 2.5 * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -162,14 +162,14 @@ NBox {
anchors.fill: parent
anchors.margins: Style.marginXS * scaling
imagePath: MediaService.trackArtUrl
- fallbackIcon: "album"
+ fallbackIcon: "disc"
borderColor: Color.mOutline
borderWidth: Math.max(1, Style.borderS * scaling)
}
// Fallback icon when no album art available
NIcon {
- icon: "album"
+ icon: "disc"
color: Color.mPrimary
font.pointSize: Style.fontSizeL * 12 * scaling
visible: !trackArt.visible
diff --git a/Modules/SidePanel/Cards/UtilitiesCard.qml b/Modules/SidePanel/Cards/UtilitiesCard.qml
index 7c00eac..1542521 100644
--- a/Modules/SidePanel/Cards/UtilitiesCard.qml
+++ b/Modules/SidePanel/Cards/UtilitiesCard.qml
@@ -41,7 +41,7 @@ NBox {
// Idle Inhibitor
NIconButton {
- icon: "cup-hot"
+ icon: "cup"
tooltipText: IdleInhibitorService.isInhibited ? "Disable keep awake." : "Enable keep awake."
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
diff --git a/Modules/SidePanel/Cards/WeatherCard.qml b/Modules/SidePanel/Cards/WeatherCard.qml
index eab4f16..baa04c8 100644
--- a/Modules/SidePanel/Cards/WeatherCard.qml
+++ b/Modules/SidePanel/Cards/WeatherCard.qml
@@ -27,7 +27,7 @@ NBox {
RowLayout {
spacing: Style.marginS * scaling
NIcon {
- text: weatherReady ? LocationService.weatherSymbolFromCode(
+ icon: weatherReady ? LocationService.weatherSymbolFromCode(
LocationService.data.weather.current_weather.weathercode) : ""
font.pointSize: Style.fontSizeXXXL * 1.75 * scaling
color: Color.mPrimary
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index bb5ca7c..e64d0f6 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -33,7 +33,8 @@ NPanel {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- NIcon { icon: Settings.data.network.wifiEnabled ? "wifi" : "wifi-off"
+ NIcon {
+ icon: Settings.data.network.wifiEnabled ? "wifi" : "wifi-off"
font.pointSize: Style.fontSizeXXL * scaling
color: Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant
}
diff --git a/Widgets/NImageCircled.qml b/Widgets/NImageCircled.qml
index 0c95178..c93f6c4 100644
--- a/Widgets/NImageCircled.qml
+++ b/Widgets/NImageCircled.qml
@@ -54,7 +54,7 @@ Rectangle {
// Fallback icon
NIcon {
anchors.centerIn: parent
- text: fallbackIcon
+ icon: fallbackIcon
font.pointSize: fallbackIconSize
visible: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
z: 0
diff --git a/Widgets/NImageRounded.qml b/Widgets/NImageRounded.qml
index c2c8b94..60c0160 100644
--- a/Widgets/NImageRounded.qml
+++ b/Widgets/NImageRounded.qml
@@ -74,7 +74,7 @@ Rectangle {
// Fallback icon
NIcon {
anchors.centerIn: parent
- text: fallbackIcon
+ icon: fallbackIcon
font.pointSize: fallbackIconSize
visible: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
z: 0
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index bd13f38..ffb7a80 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -118,7 +118,7 @@ Item {
// Icon
NIcon {
id: icon
- text: (root.type == "warning") ? "warning" : "info"
+ icon: (root.type == "warning") ? "exclamation-triangle" : "check-circle"
color: {
switch (root.type) {
case "warning":
From ad73f11b6957463d0483a092f24a473d5fe82bf8 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 22:23:02 -0400
Subject: [PATCH 037/118] Removed: old system-stats script
---
Bin/system-stats.sh | 270 --------------------------------------------
1 file changed, 270 deletions(-)
delete mode 100755 Bin/system-stats.sh
diff --git a/Bin/system-stats.sh b/Bin/system-stats.sh
deleted file mode 100755
index 8cf7133..0000000
--- a/Bin/system-stats.sh
+++ /dev/null
@@ -1,270 +0,0 @@
-#!/usr/bin/env -S bash
-
-# A Bash script to monitor system stats and output them in JSON format.
-
-# --- Configuration ---
-# Default sleep duration in seconds. Can be overridden by the first argument.
-SLEEP_DURATION=3
-
-# --- Argument Parsing ---
-# Check if a command-line argument is provided for the sleep duration.
-if [[ -n "$1" ]]; then
- # Basic validation to ensure the argument is a number (integer or float).
- if [[ "$1" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
- SLEEP_DURATION=$1
- else
- # Output to stderr if the format is invalid.
- echo "Warning: Invalid duration format '$1'. Using default of ${SLEEP_DURATION}s." >&2
- fi
-fi
-
-# --- Global Cache Variables ---
-# These variables will store the discovered CPU temperature sensor path and type
-# to avoid searching for it on every loop iteration.
-TEMP_SENSOR_PATH=""
-TEMP_SENSOR_TYPE=""
-
-# Network speed monitoring variables
-PREV_RX_BYTES=0
-PREV_TX_BYTES=0
-PREV_TIME=0
-
-# --- Data Collection Functions ---
-
-#
-# Gets memory usage in GB, MB, and as a percentage.
-#
-get_memory_info() {
- awk '
- /MemTotal/ {total=$2}
- /MemAvailable/ {available=$2}
- END {
- if (total > 0) {
- usage_kb = total - available
- usage_gb = usage_kb / 1000000
- usage_percent = (usage_kb / total) * 100
- printf "%.1f %.0f\n", usage_gb, usage_percent
- } else {
- # Fallback if /proc/meminfo is unreadable or empty.
- print "0.0 0 0"
- }
- }
- ' /proc/meminfo
-}
-
-#
-# Gets the usage percentage of the root filesystem ("/").
-#
-get_disk_usage() {
- # df gets disk usage. --output=pcent shows only the percentage for the root path.
- # tail -1 gets the data line, and tr removes the '%' sign and whitespace.
- df --output=pcent / | tail -1 | tr -d ' %'
-}
-
-#
-# Calculates current CPU usage over a short interval.
-#
-get_cpu_usage() {
- # Read all 10 CPU time fields to prevent errors on newer kernels.
- read -r cpu prev_user prev_nice prev_system prev_idle prev_iowait prev_irq prev_softirq prev_steal prev_guest prev_guest_nice < /proc/stat
-
- # Calculate previous total and idle times.
- local prev_total_idle=$((prev_idle + prev_iowait))
- local prev_total=$((prev_user + prev_nice + prev_system + prev_idle + prev_iowait + prev_irq + prev_softirq + prev_steal + prev_guest + prev_guest_nice))
-
- # Wait for a short period.
- sleep 0.05
-
- # Read all 10 CPU time fields again for the second measurement.
- read -r cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat
-
- # Calculate new total and idle times.
- local total_idle=$((idle + iowait))
- local total=$((user + nice + system + idle + iowait + irq + softirq + steal + guest + guest_nice))
-
- # Add a check to prevent division by zero if total hasn't changed.
- if (( total <= prev_total )); then
- echo "0.0"
- return
- fi
-
- # Calculate the difference over the interval.
- local diff_total=$((total - prev_total))
- local diff_idle=$((total_idle - prev_total_idle))
-
- # Use awk for floating-point calculation and print the percentage.
- awk -v total="$diff_total" -v idle="$diff_idle" '
- BEGIN {
- if (total > 0) {
- # Formula: 100 * (Total - Idle) / Total
- usage = 100 * (total - idle) / total
- printf "%.1f\n", usage
- } else {
- print "0.0"
- }
- }'
-}
-
-#
-# Finds and returns the CPU temperature in degrees Celsius.
-# Caches the sensor path for efficiency.
-#
-get_cpu_temp() {
- # If the sensor path hasn't been found yet, search for it.
- if [[ -z "$TEMP_SENSOR_PATH" ]]; then
- for dir in /sys/class/hwmon/hwmon*; do
- # Check if the 'name' file exists and read it.
- if [[ -f "$dir/name" ]]; then
- local name
- name=$(<"$dir/name")
- # Check for supported sensor types.
- if [[ "$name" == "coretemp" || "$name" == "k10temp" || "$name" == "zenpower" ]]; then
- TEMP_SENSOR_PATH=$dir
- TEMP_SENSOR_TYPE=$name
- break # Found it, no need to keep searching.
- fi
- fi
- done
- fi
-
- # If after searching no sensor was found, return 0.
- if [[ -z "$TEMP_SENSOR_PATH" ]]; then
- echo 0
- return
- fi
-
- # --- Get temp based on sensor type ---
- if [[ "$TEMP_SENSOR_TYPE" == "coretemp" ]]; then
- # For Intel 'coretemp', average all available temperature sensors.
- local total_temp=0
- local sensor_count=0
-
- # Use a for loop with a glob to iterate over all temp input files.
- # This is more efficient than 'find' for this simple case.
- for temp_file in "$TEMP_SENSOR_PATH"/temp*_input; do
- # The glob returns the pattern itself if no files match,
- # so we must check if the file actually exists.
- if [[ -f "$temp_file" ]]; then
- total_temp=$((total_temp + $(<"$temp_file")))
- sensor_count=$((sensor_count + 1))
- fi
- done
-
- if (( sensor_count > 0 )); then
- # Use awk for the final division to handle potential floating point numbers
- # and convert from millidegrees to integer degrees Celsius.
- awk -v total="$total_temp" -v count="$sensor_count" 'BEGIN { print int(total / count / 1000) }'
- else
- # If no sensor files were found, return 0.
- echo 0
- fi
-
- elif [[ "$TEMP_SENSOR_TYPE" == "k10temp" ]]; then
- # For AMD 'k10temp', find the 'Tctl' sensor, which is the control temperature.
- local tctl_input=""
- for label_file in "$TEMP_SENSOR_PATH"/temp*_label; do
- if [[ -f "$label_file" ]] && [[ $(<"$label_file") == "Tctl" ]]; then
- # The input file has the same name but with '_input' instead of '_label'.
- tctl_input="${label_file%_label}_input"
- break
- fi
- done
-
- if [[ -f "$tctl_input" ]]; then
- # Read the temperature and convert from millidegrees to degrees.
- echo "$(( $(<"$tctl_input") / 1000 ))"
- else
- echo 0 # Fallback
- fi
- elif [[ "$TEMP_SENSOR_TYPE" == "zenpower" ]]; then
- # For zenpower, read the first available temp sensor
- for temp_file in "$TEMP_SENSOR_PATH"/temp*_input; do
- if [[ -f "$temp_file" ]]; then
- local temp_value
- temp_value=$(cat "$temp_file" | tr -d '\n\r') # Remove any newlines
- echo "$((temp_value / 1000))"
- return
- fi
- done
- echo 0
-
- if [[ -f "$tctl_input" ]]; then
- # Read the temperature and convert from millidegrees to degrees.
- echo "$(($(<"$tctl_input") / 1000))"
- else
- echo 0 # Fallback
- fi
- else
- echo 0 # Should not happen if cache logic is correct.
- fi
-}
-
-
-
-# --- Main Loop ---
-# This loop runs indefinitely, gathering and printing stats.
-while true; do
- # Call the functions to gather all the data.
- # get_memory_info
- read -r mem_gb mem_per <<< "$(get_memory_info)"
-
- # Command substitution captures the single output from the other functions.
- disk_per=$(get_disk_usage)
- cpu_usage=$(get_cpu_usage)
- cpu_temp=$(get_cpu_temp)
-
- # Get network speeds
- current_time=$(date +%s.%N)
- total_rx=0
- total_tx=0
-
- # Read total bytes from /proc/net/dev for all interfaces
- while IFS=: read -r interface stats; do
- # Skip only loopback interface, allow other interfaces
- if [[ "$interface" =~ ^lo[[:space:]]*$ ]]; then
- continue
- fi
-
- # Extract rx and tx bytes (fields 1 and 9 in the stats part)
- rx_bytes=$(echo "$stats" | awk '{print $1}')
- tx_bytes=$(echo "$stats" | awk '{print $9}')
-
- # Add to totals if they are valid numbers
- if [[ "$rx_bytes" =~ ^[0-9]+$ ]] && [[ "$tx_bytes" =~ ^[0-9]+$ ]]; then
- total_rx=$((total_rx + rx_bytes))
- total_tx=$((total_tx + tx_bytes))
- fi
- done < <(tail -n +3 /proc/net/dev)
-
- # Calculate speeds if we have previous data
- rx_speed=0
- tx_speed=0
-
- if [[ "$PREV_TIME" != "0" ]]; then
- time_diff=$(awk -v current="$current_time" -v prev="$PREV_TIME" 'BEGIN { printf "%.3f", current - prev }')
- rx_diff=$((total_rx - PREV_RX_BYTES))
- tx_diff=$((total_tx - PREV_TX_BYTES))
-
- # Calculate speeds in bytes per second using awk
- rx_speed=$(awk -v rx="$rx_diff" -v time="$time_diff" 'BEGIN { printf "%.0f", rx / time }')
- tx_speed=$(awk -v tx="$tx_diff" -v time="$time_diff" 'BEGIN { printf "%.0f", tx / time }')
- fi
-
- # Update previous values for next iteration
- PREV_RX_BYTES=$total_rx
- PREV_TX_BYTES=$total_tx
- PREV_TIME=$current_time
-
- # Use printf to format the final JSON output string, adding the mem_mb key.
- printf '{"cpu": "%s", "cputemp": "%s", "memgb":"%s", "memper": "%s", "diskper": "%s", "rx_speed": "%s", "tx_speed": "%s"}\n' \
- "$cpu_usage" \
- "$cpu_temp" \
- "$mem_gb" \
- "$mem_per" \
- "$disk_per" \
- "$rx_speed" \
- "$tx_speed"
-
- # Wait for the specified duration before the next update.
- sleep "$SLEEP_DURATION"
-done
From 0e4b79fd16b861253839bca8fa3a743202f43eee Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 22:34:56 -0400
Subject: [PATCH 038/118] SystemStats / network: dont show bytes
---
Services/SystemStatService.qml | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/Services/SystemStatService.qml b/Services/SystemStatService.qml
index 7328f71..11a62cf 100644
--- a/Services/SystemStatService.qml
+++ b/Services/SystemStatService.qml
@@ -321,10 +321,8 @@ Singleton {
// -------------------------------------------------------
// Helper function to format network speeds
function formatSpeed(bytesPerSecond) {
- if (bytesPerSecond < 1024) {
- return bytesPerSecond.toFixed(0) + "B/s"
- } else if (bytesPerSecond < 1024 * 1024) {
- return (bytesPerSecond / 1024).toFixed(0) + "KB/s"
+ if (bytesPerSecond < 1024 * 1024) {
+ return (bytesPerSecond / 1024).toFixed(1) + "KB/s"
} else if (bytesPerSecond < 1024 * 1024 * 1024) {
return (bytesPerSecond / (1024 * 1024)).toFixed(1) + "MB/s"
} else {
From 16bd4b41dca585271f242b34138669ef37f6c043 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Mon, 8 Sep 2025 23:32:35 -0400
Subject: [PATCH 039/118] Icons: ArchUpdater, LockScreen, PowerMenu, BT Device
List
---
Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml | 10 +-
Modules/Bar/Widgets/SystemMonitor.qml | 196 ++++++++++--------
.../BluetoothPanel/BluetoothDevicesList.qml | 2 +-
Modules/LockScreen/LockScreen.qml | 34 +--
Modules/PowerPanel/PowerPanel.qml | 14 +-
Modules/WiFiPanel/WiFiPanel.qml | 2 +-
Services/BatteryService.qml | 2 +-
Widgets/NButton.qml | 41 ++--
Widgets/NCircleStat.qml | 13 +-
Widgets/NIcon.qml | 12 +-
10 files changed, 187 insertions(+), 139 deletions(-)
diff --git a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
index b1d1443..f8a65ce 100644
--- a/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
+++ b/Modules/ArchUpdaterPanel/ArchUpdaterPanel.qml
@@ -28,7 +28,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- icon: "system_update_alt"
+ icon: "box"
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
}
@@ -103,7 +103,7 @@ NPanel {
} // Spacer
NIcon {
- icon: "hourglass_empty"
+ icon: "hourglass"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mPrimary
Layout.alignment: Qt.AlignHCenter
@@ -181,7 +181,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- icon: "package"
+ icon: "box"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -219,7 +219,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- icon: "exclamation"
+ icon: "exclamation-triangle"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
@@ -270,7 +270,7 @@ NPanel {
spacing: Style.marginM * scaling
NIcon {
- icon: "exclamation"
+ icon: "exclamation-triangle"
font.pointSize: Style.fontSizeXXXL * scaling
color: Color.mError
Layout.alignment: Qt.AlignHCenter
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index b89a391..9641998 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -52,128 +52,158 @@ RowLayout {
RowLayout {
id: mainLayout
- anchors.fill: parent
- anchors.leftMargin: Style.marginS * scaling
- anchors.rightMargin: Style.marginS * scaling
+ anchors.centerIn: parent // Better centering than margins
+ width: parent.width - Style.marginM * scaling * 2
spacing: Style.marginS * scaling
// CPU Usage Component
- RowLayout {
- id: cpuUsageLayout
- spacing: Style.marginXS * scaling
+ Item {
+ Layout.preferredWidth: cpuUsageRow.implicitWidth
+ Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: Qt.AlignVCenter
visible: showCpuUsage
- NIcon {
- icon: "speedometer2"
- font.pointSize: Style.fontSizeM * scaling
- Layout.alignment: Qt.AlignVCenter
- }
+ RowLayout {
+ id: cpuUsageRow
+ anchors.centerIn: parent
+ spacing: Style.marginXS * scaling
- NText {
- text: `${SystemStatService.cpuUsage}%`
- font.family: Settings.data.ui.fontFixed
- font.pointSize: Style.fontSizeS * scaling
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignVCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
+ NIcon {
+ icon: "speedometer2"
+ font.pointSize: Style.fontSizeM * scaling
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ NText {
+ text: `${SystemStatService.cpuUsage}%`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: Style.fontSizeS * scaling
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignVCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ }
}
}
// CPU Temperature Component
- RowLayout {
- id: cpuTempLayout
- spacing: Style.marginXS * scaling
+ Item {
+ Layout.preferredWidth: cpuTempRow.implicitWidth
+ Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: Qt.AlignVCenter
visible: showCpuTemp
- NIcon {
- icon: "fire"
- font.pointSize: Style.fontSizeM * scaling
- Layout.alignment: Qt.AlignVCenter
- }
+ RowLayout {
+ id: cpuTempRow
+ anchors.centerIn: parent
+ spacing: Style.marginXS * scaling
- NText {
- text: `${SystemStatService.cpuTemp}°C`
- font.family: Settings.data.ui.fontFixed
- font.pointSize: Style.fontSizeS * scaling
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignVCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
+ NIcon {
+ icon: "fire"
+ // Fire is so tall, we need to make it smaller
+ font.pointSize: Style.fontSizeS * scaling
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ NText {
+ text: `${SystemStatService.cpuTemp}°C`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: Style.fontSizeS * scaling
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignVCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ }
}
}
// Memory Usage Component
- RowLayout {
- id: memoryUsageLayout
- spacing: Style.marginXS * scaling
+ Item {
+ Layout.preferredWidth: memoryUsageRow.implicitWidth
+ Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: Qt.AlignVCenter
visible: showMemoryUsage
- NIcon {
- icon: "memory"
- font.pointSize: Style.fontSizeM * scaling
- Layout.alignment: Qt.AlignVCenter
- }
+ RowLayout {
+ id: memoryUsageRow
+ anchors.centerIn: parent
+ spacing: Style.marginXS * scaling
- NText {
- text: showMemoryAsPercent ? `${SystemStatService.memPercent}%` : `${SystemStatService.memGb}G`
- font.family: Settings.data.ui.fontFixed
- font.pointSize: Style.fontSizeS * scaling
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignVCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
+ NIcon {
+ icon: "memory"
+ font.pointSize: Style.fontSizeM * scaling
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ NText {
+ text: showMemoryAsPercent ? `${SystemStatService.memPercent}%` : `${SystemStatService.memGb}G`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: Style.fontSizeS * scaling
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignVCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ }
}
}
// Network Download Speed Component
- RowLayout {
- id: networkDownloadLayout
- spacing: Style.marginXS * scaling
+ Item {
+ Layout.preferredWidth: networkDownloadRow.implicitWidth
+ Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: Qt.AlignVCenter
visible: showNetworkStats
- NIcon {
- icon: "download"
- font.pointSize: Style.fontSizeM * scaling
- Layout.alignment: Qt.AlignVCenter
- }
+ RowLayout {
+ id: networkDownloadRow
+ anchors.centerIn: parent
+ spacing: Style.marginXS * scaling
- NText {
- text: SystemStatService.formatSpeed(SystemStatService.rxSpeed)
- font.family: Settings.data.ui.fontFixed
- font.pointSize: Style.fontSizeS * scaling
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignVCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
+ NIcon {
+ icon: "cloud-arrow-down"
+ font.pointSize: Style.fontSizeM * scaling
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ NText {
+ text: SystemStatService.formatSpeed(SystemStatService.rxSpeed)
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: Style.fontSizeS * scaling
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignVCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ }
}
}
// Network Upload Speed Component
- RowLayout {
- id: networkUploadLayout
- spacing: Style.marginXS * scaling
+ Item {
+ Layout.preferredWidth: networkUploadRow.implicitWidth
+ Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
Layout.alignment: Qt.AlignVCenter
visible: showNetworkStats
- NIcon {
- icon: "upload"
- font.pointSize: Style.fontSizeM * scaling
- Layout.alignment: Qt.AlignVCenter
- }
+ RowLayout {
+ id: networkUploadRow
+ anchors.centerIn: parent
+ spacing: Style.marginXS * scaling
- NText {
- text: SystemStatService.formatSpeed(SystemStatService.txSpeed)
- font.family: Settings.data.ui.fontFixed
- font.pointSize: Style.fontSizeS * scaling
- font.weight: Style.fontWeightMedium
- Layout.alignment: Qt.AlignVCenter
- verticalAlignment: Text.AlignVCenter
- color: Color.mPrimary
+ NIcon {
+ icon: "cloud-arrow-up"
+ font.pointSize: Style.fontSizeM * scaling
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ NText {
+ text: SystemStatService.formatSpeed(SystemStatService.txSpeed)
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: Style.fontSizeS * scaling
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignVCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ }
}
}
}
diff --git a/Modules/BluetoothPanel/BluetoothDevicesList.qml b/Modules/BluetoothPanel/BluetoothDevicesList.qml
index efa5c8f..05fd4d6 100644
--- a/Modules/BluetoothPanel/BluetoothDevicesList.qml
+++ b/Modules/BluetoothPanel/BluetoothDevicesList.qml
@@ -164,7 +164,7 @@ ColumnLayout {
}
return "Connect"
}
- icon: (isBusy ? "hourglass_full" : null)
+ icon: (isBusy ? "hourglass-split" : null)
onClicked: {
if (modelData.connected) {
BluetoothService.disconnectDevice(modelData)
diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml
index 25b69b1..2f96157 100644
--- a/Modules/LockScreen/LockScreen.qml
+++ b/Modules/LockScreen/LockScreen.qml
@@ -418,7 +418,7 @@ Loader {
font.weight: Style.fontWeightBold
}
NIcon {
- text: "keyboard_alt"
+ icon: "keyboard"
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurface
}
@@ -428,7 +428,7 @@ Loader {
spacing: Style.marginS * scaling
visible: batteryIndicator.batteryVisible
NIcon {
- text: BatteryService.getIcon(batteryIndicator.percent, batteryIndicator.charging,
+ icon: BatteryService.getIcon(batteryIndicator.percent, batteryIndicator.charging,
batteryIndicator.isReady)
font.pointSize: Style.fontSizeM * scaling
color: batteryIndicator.charging ? Color.mPrimary : Color.mOnSurface
@@ -718,18 +718,20 @@ Loader {
anchors.margins: 50 * scaling
spacing: 20 * scaling
+ // Shutdown
Rectangle {
- Layout.preferredWidth: 60 * scaling
- Layout.preferredHeight: 60 * scaling
+ Layout.preferredWidth: iconPower.implicitWidth + Style.marginXL * scaling
+ Layout.preferredHeight: Layout.preferredWidth
radius: width * 0.5
color: powerButtonArea.containsMouse ? Color.mError : Qt.alpha(Color.mError, 0.2)
border.color: Color.mError
border.width: Math.max(1, Style.borderM * scaling)
NIcon {
+ id: iconPower
anchors.centerIn: parent
- text: "power_settings_new"
- font.pointSize: Style.fontSizeXL * scaling
+ icon: "power"
+ font.pointSize: Style.fontSizeXXXL * scaling
color: powerButtonArea.containsMouse ? Color.mOnError : Color.mError
}
@@ -743,18 +745,20 @@ Loader {
}
}
+ // Reboot
Rectangle {
- Layout.preferredWidth: 60 * scaling
- Layout.preferredHeight: 60 * scaling
+ Layout.preferredWidth: iconReboot.implicitWidth + Style.marginXL * scaling
+ Layout.preferredHeight: Layout.preferredWidth
radius: width * 0.5
color: restartButtonArea.containsMouse ? Color.mPrimary : Qt.alpha(Color.mPrimary, Style.opacityLight)
border.color: Color.mPrimary
border.width: Math.max(1, Style.borderM * scaling)
NIcon {
+ id: iconReboot
anchors.centerIn: parent
- text: "restart_alt"
- font.pointSize: Style.fontSizeXL * scaling
+ icon: "arrow-repeat"
+ font.pointSize: Style.fontSizeXXXL * scaling
color: restartButtonArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -768,18 +772,20 @@ Loader {
}
}
+ // Suspend
Rectangle {
- Layout.preferredWidth: 60 * scaling
- Layout.preferredHeight: 60 * scaling
+ Layout.preferredWidth: iconSuspend.implicitWidth + Style.marginXL * scaling
+ Layout.preferredHeight: Layout.preferredWidth
radius: width * 0.5
color: suspendButtonArea.containsMouse ? Color.mSecondary : Qt.alpha(Color.mSecondary, 0.2)
border.color: Color.mSecondary
border.width: Math.max(1, Style.borderM * scaling)
NIcon {
+ id: iconSuspend
anchors.centerIn: parent
- text: "bedtime"
- font.pointSize: Style.fontSizeXL * scaling
+ icon: "pause-fill"
+ font.pointSize: Style.fontSizeXXXL * scaling
color: suspendButtonArea.containsMouse ? Color.mOnSecondary : Color.mSecondary
}
diff --git a/Modules/PowerPanel/PowerPanel.qml b/Modules/PowerPanel/PowerPanel.qml
index efb475e..f4f5758 100644
--- a/Modules/PowerPanel/PowerPanel.qml
+++ b/Modules/PowerPanel/PowerPanel.qml
@@ -29,27 +29,27 @@ NPanel {
property int selectedIndex: 0
readonly property var powerOptions: [{
"action": "lock",
- "icon": "lock_outline",
+ "icon": "lock",
"title": "Lock",
"subtitle": "Lock your session"
}, {
"action": "suspend",
- "icon": "bedtime",
+ "icon": "pause-circle",
"title": "Suspend",
"subtitle": "Put the system to sleep"
}, {
"action": "reboot",
- "icon": "refresh",
+ "icon": "arrow-repeat",
"title": "Reboot",
"subtitle": "Restart the system"
}, {
"action": "logout",
- "icon": "exit_to_app",
+ "icon": "escape",
"title": "Logout",
"subtitle": "End your session"
}, {
"action": "shutdown",
- "icon": "power_settings_new",
+ "icon": "power",
"title": "Shutdown",
"subtitle": "Turn off the system",
"isShutdown": true
@@ -276,7 +276,7 @@ NPanel {
}
NIconButton {
- icon: timerActive ? "back_hand" : "close"
+ icon: timerActive ? "x-square" : "x-lg"
tooltipText: timerActive ? "Cancel Timer" : "Close"
Layout.alignment: Qt.AlignVCenter
colorBg: timerActive ? Qt.alpha(Color.mError, 0.08) : Color.transparent
@@ -360,7 +360,7 @@ NPanel {
id: iconElement
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
- text: buttonRoot.icon
+ icon: buttonRoot.icon
color: {
if (buttonRoot.pending)
return Color.mPrimary
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index e64d0f6..2a684c2 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -91,7 +91,7 @@ NPanel {
spacing: Style.marginS * scaling
NIcon {
- icon: "error"
+ icon: "exclamation-triangle"
font.pointSize: Style.fontSizeL * scaling
color: Color.mError
}
diff --git a/Services/BatteryService.qml b/Services/BatteryService.qml
index e68a239..4a4b606 100644
--- a/Services/BatteryService.qml
+++ b/Services/BatteryService.qml
@@ -11,7 +11,7 @@ Singleton {
// Choose icon based on charge and charging state
function getIcon(percent, charging, isReady) {
if (!isReady) {
- return "exclamation-diamond"
+ return "exclamation-triangle"
}
if (charging) {
diff --git a/Widgets/NButton.qml b/Widgets/NButton.qml
index 186d474..1bf82b0 100644
--- a/Widgets/NButton.qml
+++ b/Widgets/NButton.qml
@@ -80,26 +80,29 @@ Rectangle {
spacing: Style.marginXS * scaling
// Icon (optional)
- NIcon {
- Layout.alignment: Qt.AlignVCenter
- visible: root.icon !== ""
- icon: root.icon
- font.pointSize: root.iconSize
- color: {
- if (!root.enabled)
- return Color.mOnSurfaceVariant
- if (root.outlined) {
- if (root.pressed || root.hovered)
- return root.backgroundColor
- return root.backgroundColor
- }
- return root.textColor
- }
+ Loader {
+ active: root.icon !== ""
+ sourceComponent: NIcon {
+ Layout.alignment: Qt.AlignVCenter
- Behavior on color {
- ColorAnimation {
- duration: Style.animationFast
- easing.type: Easing.OutCubic
+ icon: root.icon
+ font.pointSize: root.iconSize
+ color: {
+ if (!root.enabled)
+ return Color.mOnSurfaceVariant
+ if (root.outlined) {
+ if (root.pressed || root.hovered)
+ return root.backgroundColor
+ return root.backgroundColor
+ }
+ return root.textColor
+ }
+
+ Behavior on color {
+ ColorAnimation {
+ duration: Style.animationFast
+ easing.type: Easing.OutCubic
+ }
}
}
}
diff --git a/Widgets/NCircleStat.qml b/Widgets/NCircleStat.qml
index 997a99c..211acdf 100644
--- a/Widgets/NCircleStat.qml
+++ b/Widgets/NCircleStat.qml
@@ -88,20 +88,21 @@ Rectangle {
// Tiny circular badge for the icon, positioned using anchors within the gauge
Rectangle {
id: iconBadge
- width: 28 * scaling * contentScale
+ width: iconText.implicitWidth + Style.marginXS * scaling
height: width
radius: width / 2
- color: Color.mSurface
+ color: Color.mPrimary
anchors.right: parent.right
anchors.top: parent.top
- anchors.rightMargin: -6 * scaling * contentScale
- anchors.topMargin: Style.marginXXS * scaling * contentScale
+ anchors.rightMargin: Style.marginXXS * scaling * contentScale
+ anchors.topMargin: Style.marginXS * scaling * contentScale
NIcon {
+ id: iconText
anchors.centerIn: parent
icon: root.icon
- font.pointSize: Style.fontSizeLargeXL * scaling * contentScale
- color: Color.mOnSurface
+ font.pointSize: Style.fontSizeS * scaling * contentScale
+ color: Color.mOnPrimary
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index 6d70c6f..a459e74 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -4,9 +4,17 @@ import qs.Commons
import qs.Widgets
Text {
- property string icon: "balloon"
+ readonly property string defaultIcon: "balloon"
+ property string icon: defaultIcon
- text: Bootstrap.icons[icon]
+ text: {
+ if (Bootstrap.icons[icon] === undefined) {
+ Logger.warn("Icon", `"${icon}"`, "doesn't exist in the bootstrap font")
+ Logger.callStack()
+ return Bootstrap.icons[defaultIcon]
+ }
+ return Bootstrap.icons[icon]
+ }
font.family: "bootstrap-icons"
font.pointSize: Style.fontSizeL * scaling
color: Color.mOnSurface
From 76ef2469e876d6036c6a3bff2d9cdec2468db3cf Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 00:35:12 -0400
Subject: [PATCH 040/118] Shaders: path from root for easier maintenance +
cleanup fallback icons
---
Modules/Background/Background.qml | 8 ++++----
Modules/LockScreen/LockScreen.qml | 2 +-
Modules/Notification/Notification.qml | 4 +---
Widgets/NIcon.qml | 2 +-
Widgets/NImageCircled.qml | 16 +++++++++-------
Widgets/NImageRounded.qml | 16 +++++++++-------
6 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/Modules/Background/Background.qml b/Modules/Background/Background.qml
index 56d184a..61d4fa4 100644
--- a/Modules/Background/Background.qml
+++ b/Modules/Background/Background.qml
@@ -139,7 +139,7 @@ Variants {
property real screenWidth: width
property real screenHeight: height
- fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_fade.frag.qsb")
+ fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_fade.frag.qsb")
}
// Wipe transition shader
@@ -164,7 +164,7 @@ Variants {
property real screenWidth: width
property real screenHeight: height
- fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_wipe.frag.qsb")
+ fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_wipe.frag.qsb")
}
// Disc reveal transition shader
@@ -191,7 +191,7 @@ Variants {
property real screenWidth: width
property real screenHeight: height
- fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_disc.frag.qsb")
+ fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_disc.frag.qsb")
}
// Diagonal stripes transition shader
@@ -218,7 +218,7 @@ Variants {
property real screenWidth: width
property real screenHeight: height
- fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_stripes.frag.qsb")
+ fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/wp_stripes.frag.qsb")
}
// Animation for the transition progress
diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml
index 2f96157..528736f 100644
--- a/Modules/LockScreen/LockScreen.qml
+++ b/Modules/LockScreen/LockScreen.qml
@@ -728,7 +728,7 @@ Loader {
border.width: Math.max(1, Style.borderM * scaling)
NIcon {
- id: iconPower
+ id: iconPower
anchors.centerIn: parent
icon: "power"
font.pointSize: Style.fontSizeXXXL * scaling
diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml
index 96c719a..ab16610 100644
--- a/Modules/Notification/Notification.qml
+++ b/Modules/Notification/Notification.qml
@@ -205,14 +205,12 @@ Variants {
Layout.fillWidth: true
spacing: Style.marginM * scaling
- // Avatar
+ // Image
NImageCircled {
- id: appAvatar
Layout.preferredWidth: 40 * scaling
Layout.preferredHeight: 40 * scaling
Layout.alignment: Qt.AlignTop
imagePath: model.image && model.image !== "" ? model.image : ""
- fallbackIcon: ""
borderColor: Color.transparent
borderWidth: 0
visible: (model.image && model.image !== "")
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index a459e74..fedbaa0 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -8,7 +8,7 @@ Text {
property string icon: defaultIcon
text: {
- if (Bootstrap.icons[icon] === undefined) {
+ if (icon === undefined || Bootstrap.icons[icon] === undefined) {
Logger.warn("Icon", `"${icon}"`, "doesn't exist in the bootstrap font")
Logger.callStack()
return Bootstrap.icons[defaultIcon]
diff --git a/Widgets/NImageCircled.qml b/Widgets/NImageCircled.qml
index c93f6c4..61190ea 100644
--- a/Widgets/NImageCircled.qml
+++ b/Widgets/NImageCircled.qml
@@ -46,18 +46,20 @@ Rectangle {
}
property real imageOpacity: root.opacity
- fragmentShader: Qt.resolvedUrl("../Shaders/qsb/circled_image.frag.qsb")
+ fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/circled_image.frag.qsb")
supportsAtlasTextures: false
blending: true
}
// Fallback icon
- NIcon {
- anchors.centerIn: parent
- icon: fallbackIcon
- font.pointSize: fallbackIconSize
- visible: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
- z: 0
+ Loader {
+ active: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
+ sourceComponent: NIcon {
+ anchors.centerIn: parent
+ icon: fallbackIcon
+ font.pointSize: fallbackIconSize
+ z: 0
+ }
}
}
diff --git a/Widgets/NImageRounded.qml b/Widgets/NImageRounded.qml
index 60c0160..b1950f3 100644
--- a/Widgets/NImageRounded.qml
+++ b/Widgets/NImageRounded.qml
@@ -57,7 +57,7 @@ Rectangle {
property real itemHeight: root.height
property real cornerRadius: root.radius
property real imageOpacity: root.opacity
- fragmentShader: Qt.resolvedUrl("../Shaders/qsb/rounded_image.frag.qsb")
+ fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/rounded_image.frag.qsb")
// Qt6 specific properties - ensure proper blending
supportsAtlasTextures: false
@@ -72,12 +72,14 @@ Rectangle {
}
// Fallback icon
- NIcon {
- anchors.centerIn: parent
- icon: fallbackIcon
- font.pointSize: fallbackIconSize
- visible: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
- z: 0
+ Loader {
+ active: fallbackIcon !== undefined && fallbackIcon !== "" && (imagePath === undefined || imagePath === "")
+ sourceComponent: NIcon {
+ anchors.centerIn: parent
+ icon: fallbackIcon
+ font.pointSize: fallbackIconSize
+ z: 0
+ }
}
}
From 56d87ecfcf0dc8dbe4195d6193b5fa9992d90679 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 01:02:53 -0400
Subject: [PATCH 041/118] Polishing
- Volume: better spread/usage of the 3 icons
- Rosepine colors: more contrast to compare to matugen
- NPill: different look when pile is always opened
---
Assets/ColorScheme/Rosepine.json | 12 ++++++------
Modules/Bar/Widgets/Volume.qml | 2 +-
Widgets/NPill.qml | 4 +---
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/Assets/ColorScheme/Rosepine.json b/Assets/ColorScheme/Rosepine.json
index 37e9b3a..547bb73 100644
--- a/Assets/ColorScheme/Rosepine.json
+++ b/Assets/ColorScheme/Rosepine.json
@@ -1,19 +1,19 @@
{
"dark": {
"mPrimary": "#ebbcba",
- "mOnPrimary": "#1f1d2e",
+ "mOnPrimary": "#191724",
"mSecondary": "#9ccfd8",
- "mOnSecondary": "#1f1d2e",
+ "mOnSecondary": "#191724",
"mTertiary": "#f6c177",
- "mOnTertiary": "#1f1d2e",
+ "mOnTertiary": "#191724",
"mError": "#eb6f92",
- "mOnError": "#1f1d2e",
- "mSurface": "#1f1d2e",
+ "mOnError": "#191724",
+ "mSurface": "#191724",
"mOnSurface": "#e0def4",
"mSurfaceVariant": "#26233a",
"mOnSurfaceVariant": "#908caa",
"mOutline": "#403d52",
- "mShadow": "#1f1d2e"
+ "mShadow": "#191724"
},
"light": {
"mPrimary": "#d46e6b",
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 690a92e..928f839 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -45,7 +45,7 @@ Item {
if (AudioService.muted) {
return "volume-mute"
}
- return AudioService.volume <= Number.EPSILON ? "volume-off" : (AudioService.volume < 0.5 ? "volume-down" : "volume-up")
+ return AudioService.volume <= 0.2? "volume-off" : (AudioService.volume < 0.6 ? "volume-down" : "volume-up")
}
// Connection used to open the pill when volume changes
diff --git a/Widgets/NPill.qml b/Widgets/NPill.qml
index a64332f..18987a3 100644
--- a/Widgets/NPill.qml
+++ b/Widgets/NPill.qml
@@ -102,10 +102,8 @@ Item {
height: iconSize
radius: width * 0.5
// When forced shown, match pill background; otherwise use accent when hovered
- color: forceOpen ? pillColor : (showPill ? iconCircleColor : Color.mSurfaceVariant)
+ color: forceOpen ? Color.mSurface : (showPill ? iconCircleColor : Color.mSurfaceVariant)
anchors.verticalCenter: parent.verticalCenter
- border.width: Math.max(1, Style.borderS * scaling)
- border.color: forceOpen ? Qt.alpha(Color.mOutline, 0.5) : Color.transparent
x: rightOpen ? 0 : (parent.width - width)
From d4d7b06b64c1103faa00a681284e2c14e3a3b5a3 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 01:44:14 -0400
Subject: [PATCH 042/118] NPill + Clock color uniformisation
---
Modules/Bar/Widgets/Battery.qml | 6 +-----
Modules/Bar/Widgets/Brightness.qml | 2 --
Modules/Bar/Widgets/Clock.qml | 1 +
Modules/Bar/Widgets/KeyboardLayout.qml | 2 --
Modules/Bar/Widgets/Microphone.qml | 2 --
Modules/Bar/Widgets/Volume.qml | 2 --
Widgets/NPill.qml | 29 +++++++++++---------------
7 files changed, 14 insertions(+), 30 deletions(-)
diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml
index 078d7f4..bd1be8d 100644
--- a/Modules/Bar/Widgets/Battery.qml
+++ b/Modules/Bar/Widgets/Battery.qml
@@ -85,12 +85,8 @@ Item {
id: pill
rightOpen: BarWidgetRegistry.getNPillDirection(root)
- icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent,
- charging, isReady)
+ icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady)
text: (isReady || testMode) ? Math.round(percent) + "%" : "-"
- textColor: charging ? Color.mPrimary : Color.mOnSurface
- iconCircleColor: Color.mPrimary
- collapsedIconColor: Color.mOnSurface
autoHide: false
forceOpen: isReady && (testMode || battery.isLaptopBattery) && alwaysShowPercentage
disableOpen: (!isReady || (!testMode && !battery.isLaptopBattery))
diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml
index feafbcc..477cf19 100644
--- a/Modules/Bar/Widgets/Brightness.qml
+++ b/Modules/Bar/Widgets/Brightness.qml
@@ -79,8 +79,6 @@ Item {
rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: getIcon()
- iconCircleColor: Color.mPrimary
- collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
text: {
var monitor = getMonitor()
diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml
index 3b472d9..71526e2 100644
--- a/Modules/Bar/Widgets/Clock.qml
+++ b/Modules/Bar/Widgets/Clock.qml
@@ -60,6 +60,7 @@ Rectangle {
anchors.centerIn: parent
font.pointSize: Style.fontSizeS * scaling
font.weight: Style.fontWeightBold
+ color: Color.mPrimary
}
NTooltip {
diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml
index 60ea83e..a09d1e6 100644
--- a/Modules/Bar/Widgets/KeyboardLayout.qml
+++ b/Modules/Bar/Widgets/KeyboardLayout.qml
@@ -25,8 +25,6 @@ Item {
anchors.verticalCenter: parent.verticalCenter
rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: "keyboard"
- iconCircleColor: Color.mPrimary
- collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
text: currentLayout
tooltipText: "Keyboard layout: " + currentLayout
diff --git a/Modules/Bar/Widgets/Microphone.qml b/Modules/Bar/Widgets/Microphone.qml
index ed0a54c..3851785 100644
--- a/Modules/Bar/Widgets/Microphone.qml
+++ b/Modules/Bar/Widgets/Microphone.qml
@@ -92,8 +92,6 @@ Item {
rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: getIcon()
- iconCircleColor: Color.mPrimary
- collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
text: Math.floor(AudioService.inputVolume * 100) + "%"
forceOpen: alwaysShowPercentage
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index 928f839..ccc40f9 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -77,8 +77,6 @@ Item {
rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: getIcon()
- iconCircleColor: Color.mPrimary
- collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
text: Math.floor(AudioService.volume * 100) + "%"
forceOpen: alwaysShowPercentage
diff --git a/Widgets/NPill.qml b/Widgets/NPill.qml
index 18987a3..1d9bfba 100644
--- a/Widgets/NPill.qml
+++ b/Widgets/NPill.qml
@@ -9,20 +9,15 @@ Item {
property string icon: ""
property string text: ""
property string tooltipText: ""
- property color pillColor: Color.mSurfaceVariant
- property color textColor: Color.mOnSurface
- property color iconCircleColor: Color.mPrimary
- property color iconTextColor: Color.mSurface
- property color collapsedIconColor: Color.mOnSurface
-
property real sizeRatio: 0.8
property bool autoHide: false
property bool forceOpen: false
property bool disableOpen: false
property bool rightOpen: false
+ property bool hovered: false
// Effective shown state (true if hovered/animated open or forced)
- readonly property bool effectiveShown: forceOpen || showPill
+ readonly property bool revealed: forceOpen || showPill
signal shown
signal hidden
@@ -49,14 +44,14 @@ Item {
Rectangle {
id: pill
- width: effectiveShown ? maxPillWidth : 1
+ width: revealed ? maxPillWidth : 1
height: pillHeight
x: rightOpen ? (iconCircle.x + iconCircle.width / 2) : // Opens right
(iconCircle.x + iconCircle.width / 2) - width // Opens left
- opacity: effectiveShown ? Style.opacityFull : Style.opacityNone
- color: pillColor
+ opacity: revealed ? Style.opacityFull : Style.opacityNone
+ color: Color.mSurfaceVariant
topLeftRadius: rightOpen ? 0 : pillHeight * 0.5
bottomLeftRadius: rightOpen ? 0 : pillHeight * 0.5
@@ -76,8 +71,8 @@ Item {
text: root.text
font.pointSize: Style.fontSizeXS * scaling
font.weight: Style.fontWeightBold
- color: textColor
- visible: effectiveShown
+ color: Color.mPrimary
+ visible: revealed
}
Behavior on width {
@@ -101,8 +96,7 @@ Item {
width: iconSize
height: iconSize
radius: width * 0.5
- // When forced shown, match pill background; otherwise use accent when hovered
- color: forceOpen ? Color.mSurface : (showPill ? iconCircleColor : Color.mSurfaceVariant)
+ color: hovered && !forceOpen? Color.mPrimary : Color.mSurfaceVariant
anchors.verticalCenter: parent.verticalCenter
x: rightOpen ? 0 : (parent.width - width)
@@ -117,9 +111,8 @@ Item {
NIcon {
icon: root.icon
font.pointSize: Style.fontSizeM * scaling
- // When forced shown, use pill text color; otherwise accent color when hovered
- color: forceOpen ? textColor : (showPill ? iconTextColor : Color.mOnSurface)
- // Center horizontally
+ color: hovered && !forceOpen? Color.mOnPrimary : Color.mOnSurface
+ // Center horizontally
x: (iconCircle.width - width) / 2
// Center vertically accounting for font metrics
y: (iconCircle.height - height) / 2 + (height - contentHeight) / 2
@@ -216,6 +209,7 @@ Item {
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onEntered: {
+ hovered = true
root.entered()
tooltip.show()
if (disableOpen) {
@@ -226,6 +220,7 @@ Item {
}
}
onExited: {
+ hovered = false
root.exited()
if (!forceOpen) {
hide()
From fdfe9ea2e125f4599e7cbb1090ee9a50b93dafee Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 01:45:32 -0400
Subject: [PATCH 043/118] WifiPanel: fix missing device icon
---
Modules/WiFiPanel/WiFiPanel.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/WiFiPanel/WiFiPanel.qml b/Modules/WiFiPanel/WiFiPanel.qml
index 2a684c2..25ea245 100644
--- a/Modules/WiFiPanel/WiFiPanel.qml
+++ b/Modules/WiFiPanel/WiFiPanel.qml
@@ -245,7 +245,7 @@ NPanel {
spacing: Style.marginS * scaling
NIcon {
- text: NetworkService.signalIcon(modelData.signal)
+ icon: NetworkService.signalIcon(modelData.signal)
font.pointSize: Style.fontSizeXXL * scaling
color: modelData.connected ? Color.mPrimary : Color.mOnSurface
}
From 94d64a91b84d85cb9d06bc93d3fcb26c029598f8 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 13:08:48 +0200
Subject: [PATCH 044/118] Add toasts & tooltips to a lot of things, add Disk
Usage
---
Modules/Bar/Widgets/Battery.qml | 3 +-
Modules/Bar/Widgets/SystemMonitor.qml | 33 +++++++++++++++++++
Modules/Bar/Widgets/Volume.qml | 2 +-
Modules/LockScreen/LockScreen.qml | 30 +++++++++++++++++
.../WidgetSettings/SystemMonitorSettings.qml | 11 +++++++
Modules/SidePanel/Cards/PowerProfilesCard.qml | 3 ++
Services/AudioService.qml | 4 +++
Services/BarWidgetRegistry.qml | 3 +-
Services/ColorSchemeService.qml | 5 +++
Services/NightLightService.qml | 3 ++
Services/ToastService.qml | 5 +++
Widgets/NPill.qml | 6 ++--
12 files changed, 102 insertions(+), 6 deletions(-)
diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml
index bd1be8d..e191c44 100644
--- a/Modules/Bar/Widgets/Battery.qml
+++ b/Modules/Bar/Widgets/Battery.qml
@@ -85,7 +85,8 @@ Item {
id: pill
rightOpen: BarWidgetRegistry.getNPillDirection(root)
- icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady)
+ icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent,
+ charging, isReady)
text: (isReady || testMode) ? Math.round(percent) + "%" : "-"
autoHide: false
forceOpen: isReady && (testMode || battery.isLaptopBattery) && alwaysShowPercentage
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index 9641998..fbfaed1 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -38,6 +38,9 @@ RowLayout {
!== undefined) ? widgetSettings.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent
readonly property bool showNetworkStats: (widgetSettings.showNetworkStats
!== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats
+ readonly property bool showDiskUsage: (widgetSettings.showDiskUsage
+ !== undefined) ? widgetSettings.showDiskUsage : (widgetMetadata.showDiskUsage
+ || false)
Layout.alignment: Qt.AlignVCenter
spacing: Style.marginS * scaling
@@ -206,6 +209,36 @@ RowLayout {
}
}
}
+
+ // Disk Usage Component (primary drive)
+ Item {
+ Layout.preferredWidth: diskUsageRow.implicitWidth
+ Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling)
+ Layout.alignment: Qt.AlignVCenter
+ visible: showDiskUsage
+
+ RowLayout {
+ id: diskUsageRow
+ anchors.centerIn: parent
+ spacing: Style.marginXS * scaling
+
+ NIcon {
+ icon: "hdd"
+ font.pointSize: Style.fontSizeM * scaling
+ Layout.alignment: Qt.AlignVCenter
+ }
+
+ NText {
+ text: `${SystemStatService.diskPercent}%`
+ font.family: Settings.data.ui.fontFixed
+ font.pointSize: Style.fontSizeS * scaling
+ font.weight: Style.fontWeightMedium
+ Layout.alignment: Qt.AlignVCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.mPrimary
+ }
+ }
+ }
}
}
}
diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml
index ccc40f9..b61554c 100644
--- a/Modules/Bar/Widgets/Volume.qml
+++ b/Modules/Bar/Widgets/Volume.qml
@@ -45,7 +45,7 @@ Item {
if (AudioService.muted) {
return "volume-mute"
}
- return AudioService.volume <= 0.2? "volume-off" : (AudioService.volume < 0.6 ? "volume-down" : "volume-up")
+ return AudioService.volume <= 0.2 ? "volume-off" : (AudioService.volume < 0.6 ? "volume-down" : "volume-up")
}
// Connection used to open the pill when volume changes
diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml
index 528736f..beeccc6 100644
--- a/Modules/LockScreen/LockScreen.qml
+++ b/Modules/LockScreen/LockScreen.qml
@@ -735,6 +735,14 @@ Loader {
color: powerButtonArea.containsMouse ? Color.mOnError : Color.mError
}
+ // Tooltip
+ NTooltip {
+ id: tooltipShutdown
+ target: parent
+ positionAbove: true
+ text: "Shut down"
+ }
+
MouseArea {
id: powerButtonArea
anchors.fill: parent
@@ -742,6 +750,8 @@ Loader {
onClicked: {
CompositorService.shutdown()
}
+ onEntered: tooltipShutdown.show()
+ onExited: tooltipShutdown.hide()
}
}
@@ -762,6 +772,14 @@ Loader {
color: restartButtonArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
+ // Tooltip
+ NTooltip {
+ id: tooltipRestart
+ target: parent
+ positionAbove: true
+ text: "Restart"
+ }
+
MouseArea {
id: restartButtonArea
anchors.fill: parent
@@ -769,6 +787,8 @@ Loader {
onClicked: {
CompositorService.reboot()
}
+ onEntered: tooltipRestart.show()
+ onExited: tooltipRestart.hide()
}
}
@@ -789,6 +809,14 @@ Loader {
color: suspendButtonArea.containsMouse ? Color.mOnSecondary : Color.mSecondary
}
+ // Tooltip
+ NTooltip {
+ id: tooltipSuspend
+ target: parent
+ positionAbove: true
+ text: "Suspend"
+ }
+
MouseArea {
id: suspendButtonArea
anchors.fill: parent
@@ -796,6 +824,8 @@ Loader {
onClicked: {
CompositorService.suspend()
}
+ onEntered: tooltipSuspend.show()
+ onExited: tooltipSuspend.hide()
}
}
}
diff --git a/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml b/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
index 21d0d4c..4b2807b 100644
--- a/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
+++ b/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
@@ -21,6 +21,8 @@ ColumnLayout {
!== undefined ? widgetData.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent
property bool valueShowNetworkStats: widgetData.showNetworkStats
!== undefined ? widgetData.showNetworkStats : widgetMetadata.showNetworkStats
+ property bool valueShowDiskUsage: widgetData.showDiskUsage !== undefined ? widgetData.showDiskUsage : (widgetMetadata.showDiskUsage
+ || false)
function saveSettings() {
var settings = Object.assign({}, widgetData || {})
@@ -29,6 +31,7 @@ ColumnLayout {
settings.showMemoryUsage = valueShowMemoryUsage
settings.showMemoryAsPercent = valueShowMemoryAsPercent
settings.showNetworkStats = valueShowNetworkStats
+ settings.showDiskUsage = valueShowDiskUsage
return settings
}
@@ -71,4 +74,12 @@ ColumnLayout {
checked: valueShowNetworkStats
onToggled: checked => valueShowNetworkStats = checked
}
+
+ NToggle {
+ id: showDiskUsage
+ Layout.fillWidth: true
+ label: "Storage usage"
+ checked: valueShowDiskUsage
+ onToggled: checked => valueShowDiskUsage = checked
+ }
}
diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml
index 3892c7f..842d432 100644
--- a/Modules/SidePanel/Cards/PowerProfilesCard.qml
+++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml
@@ -37,6 +37,7 @@ NBox {
onClicked: {
if (enabled) {
powerProfiles.profile = PowerProfile.Performance
+ ToastService.showNotice("Power Profile", "Performance")
}
}
}
@@ -51,6 +52,7 @@ NBox {
onClicked: {
if (enabled) {
powerProfiles.profile = PowerProfile.Balanced
+ ToastService.showNotice("Power Profile", "Balanced")
}
}
}
@@ -65,6 +67,7 @@ NBox {
onClicked: {
if (enabled) {
powerProfiles.profile = PowerProfile.PowerSaver
+ ToastService.showNotice("Power Profile", "Power Saver")
}
}
}
diff --git a/Services/AudioService.qml b/Services/AudioService.qml
index c6ec05c..9f526ea 100644
--- a/Services/AudioService.qml
+++ b/Services/AudioService.qml
@@ -62,6 +62,8 @@ Singleton {
function onMutedChanged() {
root._muted = (sink?.audio.muted ?? true)
Logger.log("AudioService", "OnMuteChanged:", root._muted)
+ // Toast: audio output mute toggle
+ ToastService.showNotice("Audio Output", root._muted ? "Muted" : "Unmuted")
}
}
@@ -79,6 +81,8 @@ Singleton {
function onMutedChanged() {
root._inputMuted = (source?.audio.muted ?? true)
Logger.log("AudioService", "OnInputMuteChanged:", root._inputMuted)
+ // Toast: microphone mute toggle
+ ToastService.showNotice("Microphone", root._inputMuted ? "Muted" : "Unmuted")
}
}
diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml
index b82a3e1..fc99a0e 100644
--- a/Services/BarWidgetRegistry.qml
+++ b/Services/BarWidgetRegistry.qml
@@ -84,7 +84,8 @@ Singleton {
"showCpuTemp": true,
"showMemoryUsage": true,
"showMemoryAsPercent": false,
- "showNetworkStats": false
+ "showNetworkStats": false,
+ "showDiskUsage": false
},
"Workspace": {
"allowUserSettings": true,
diff --git a/Services/ColorSchemeService.qml b/Services/ColorSchemeService.qml
index 096f8f9..ade585f 100644
--- a/Services/ColorSchemeService.qml
+++ b/Services/ColorSchemeService.qml
@@ -23,6 +23,11 @@ Singleton {
// Re-apply current scheme to pick the right variant
applyScheme(Settings.data.colorSchemes.predefinedScheme)
}
+ // Toast: dark/light mode switched
+ const enabled = !!Settings.data.colorSchemes.darkMode
+ const label = enabled ? "Dark Mode" : "Light Mode"
+ const description = enabled ? "Enabled" : "Enabled"
+ ToastService.showNotice(label, description)
}
}
diff --git a/Services/NightLightService.qml b/Services/NightLightService.qml
index 3719a29..77084f2 100644
--- a/Services/NightLightService.qml
+++ b/Services/NightLightService.qml
@@ -50,6 +50,9 @@ Singleton {
target: Settings.data.nightLight
function onEnabledChanged() {
apply()
+ // Toast: night light toggled
+ const enabled = !!Settings.data.nightLight.enabled
+ ToastService.showNotice("Night Light", enabled ? "Enabled" : "Disabled")
}
function onNightTempChanged() {
apply()
diff --git a/Services/ToastService.qml b/Services/ToastService.qml
index edff04b..ee9fb24 100644
--- a/Services/ToastService.qml
+++ b/Services/ToastService.qml
@@ -185,6 +185,11 @@ Singleton {
// Process the message queue
function processQueue() {
if (messageQueue.length === 0 || allToasts.length === 0) {
+ // Added this so we don't accidentally get duplicate toasts
+ // if it causes issues, remove it and we'll find a different solution
+ if (allToasts.length === 0 && messageQueue.length > 0) {
+ messageQueue = []
+ }
isShowingToast = false
return
}
diff --git a/Widgets/NPill.qml b/Widgets/NPill.qml
index 1d9bfba..7b57ad8 100644
--- a/Widgets/NPill.qml
+++ b/Widgets/NPill.qml
@@ -96,7 +96,7 @@ Item {
width: iconSize
height: iconSize
radius: width * 0.5
- color: hovered && !forceOpen? Color.mPrimary : Color.mSurfaceVariant
+ color: hovered && !forceOpen ? Color.mPrimary : Color.mSurfaceVariant
anchors.verticalCenter: parent.verticalCenter
x: rightOpen ? 0 : (parent.width - width)
@@ -111,8 +111,8 @@ Item {
NIcon {
icon: root.icon
font.pointSize: Style.fontSizeM * scaling
- color: hovered && !forceOpen? Color.mOnPrimary : Color.mOnSurface
- // Center horizontally
+ color: hovered && !forceOpen ? Color.mOnPrimary : Color.mOnSurface
+ // Center horizontally
x: (iconCircle.width - width) / 2
// Center vertically accounting for font metrics
y: (iconCircle.height - height) / 2 + (height - contentHeight) / 2
From e8f356f5ac9a808b84b1ced8696db9e5e014cd11 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 07:17:50 -0400
Subject: [PATCH 045/118] ActiveWindow+MediaMini: Shifted one color each:
mPrimary, mSecondary
---
Modules/Bar/Widgets/ActiveWindow.qml | 2 +-
Modules/Bar/Widgets/MediaMini.qml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml
index 8fb5961..7ce8e3f 100644
--- a/Modules/Bar/Widgets/ActiveWindow.qml
+++ b/Modules/Bar/Widgets/ActiveWindow.qml
@@ -123,7 +123,7 @@ RowLayout {
font.weight: Style.fontWeightMedium
elide: mouseArea.containsMouse ? Text.ElideNone : Text.ElideRight
verticalAlignment: Text.AlignVCenter
- color: Color.mSecondary
+ color: Color.mPrimary
clip: true
Behavior on Layout.preferredWidth {
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index 28badc6..dafa9a6 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -179,7 +179,7 @@ RowLayout {
font.weight: Style.fontWeightMedium
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
- color: Color.mTertiary
+ color: Color.mSecondary
Behavior on Layout.preferredWidth {
NumberAnimation {
From 3c9ce6f8b59a5d9bf0ae2b288396494ed1738c80 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 13:20:46 +0200
Subject: [PATCH 046/118] ScreenRecorder: check for availability
---
Modules/IPC/IPCManager.qml | 4 +-
Modules/LockScreen/LockScreen.qml | 88 +++++++++++++++++------
Modules/SidePanel/Cards/UtilitiesCard.qml | 5 +-
Services/ScreenRecorderService.qml | 26 +++++++
Widgets/NIconButton.qml | 12 ++--
5 files changed, 107 insertions(+), 28 deletions(-)
diff --git a/Modules/IPC/IPCManager.qml b/Modules/IPC/IPCManager.qml
index 8c541a3..204dbbe 100644
--- a/Modules/IPC/IPCManager.qml
+++ b/Modules/IPC/IPCManager.qml
@@ -22,7 +22,9 @@ Item {
IpcHandler {
target: "screenRecorder"
function toggle() {
- ScreenRecorderService.toggleRecording()
+ if (ScreenRecorderService.isAvailable) {
+ ScreenRecorderService.toggleRecording()
+ }
}
}
diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml
index beeccc6..725a30b 100644
--- a/Modules/LockScreen/LockScreen.qml
+++ b/Modules/LockScreen/LockScreen.qml
@@ -735,12 +735,28 @@ Loader {
color: powerButtonArea.containsMouse ? Color.mOnError : Color.mError
}
- // Tooltip
- NTooltip {
- id: tooltipShutdown
- target: parent
- positionAbove: true
- text: "Shut down"
+ // Tooltip (inline rectangle to avoid separate Window during lock)
+ Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.top
+ anchors.bottomMargin: 12 * scaling
+ radius: Style.radiusM * scaling
+ color: Color.mSurface
+ border.color: Color.mOutline
+ border.width: Math.max(1, Style.borderS * scaling)
+ visible: powerButtonArea.containsMouse
+ z: 1
+ NText {
+ id: shutdownTooltipText
+ anchors.margins: Style.marginM * scaling
+ anchors.fill: parent
+ text: "Shut down the computer."
+ font.pointSize: Style.fontSizeM * scaling
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ implicitWidth: shutdownTooltipText.implicitWidth + Style.marginM * 2 * scaling
+ implicitHeight: shutdownTooltipText.implicitHeight + Style.marginM * 2 * scaling
}
MouseArea {
@@ -750,8 +766,6 @@ Loader {
onClicked: {
CompositorService.shutdown()
}
- onEntered: tooltipShutdown.show()
- onExited: tooltipShutdown.hide()
}
}
@@ -773,11 +787,27 @@ Loader {
}
// Tooltip
- NTooltip {
- id: tooltipRestart
- target: parent
- positionAbove: true
- text: "Restart"
+ Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.top
+ anchors.bottomMargin: 12 * scaling
+ radius: Style.radiusM * scaling
+ color: Color.mSurface
+ border.color: Color.mOutline
+ border.width: Math.max(1, Style.borderS * scaling)
+ visible: restartButtonArea.containsMouse
+ z: 1
+ NText {
+ id: restartTooltipText
+ anchors.margins: Style.marginM * scaling
+ anchors.fill: parent
+ text: "Restart the computer."
+ font.pointSize: Style.fontSizeM * scaling
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ implicitWidth: restartTooltipText.implicitWidth + Style.marginM * 2 * scaling
+ implicitHeight: restartTooltipText.implicitHeight + Style.marginM * 2 * scaling
}
MouseArea {
@@ -787,8 +817,7 @@ Loader {
onClicked: {
CompositorService.reboot()
}
- onEntered: tooltipRestart.show()
- onExited: tooltipRestart.hide()
+ // Tooltip handled via inline rectangle visibility
}
}
@@ -810,11 +839,27 @@ Loader {
}
// Tooltip
- NTooltip {
- id: tooltipSuspend
- target: parent
- positionAbove: true
- text: "Suspend"
+ Rectangle {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.top
+ anchors.bottomMargin: 12 * scaling
+ radius: Style.radiusM * scaling
+ color: Color.mSurface
+ border.color: Color.mOutline
+ border.width: Math.max(1, Style.borderS * scaling)
+ visible: suspendButtonArea.containsMouse
+ z: 1
+ NText {
+ id: suspendTooltipText
+ anchors.margins: Style.marginM * scaling
+ anchors.fill: parent
+ text: "Suspend the system."
+ font.pointSize: Style.fontSizeM * scaling
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ implicitWidth: suspendTooltipText.implicitWidth + Style.marginM * 2 * scaling
+ implicitHeight: suspendTooltipText.implicitHeight + Style.marginM * 2 * scaling
}
MouseArea {
@@ -824,8 +869,7 @@ Loader {
onClicked: {
CompositorService.suspend()
}
- onEntered: tooltipSuspend.show()
- onExited: tooltipSuspend.hide()
+ // Tooltip handled via inline rectangle visibility
}
}
}
diff --git a/Modules/SidePanel/Cards/UtilitiesCard.qml b/Modules/SidePanel/Cards/UtilitiesCard.qml
index 1542521..f4bde37 100644
--- a/Modules/SidePanel/Cards/UtilitiesCard.qml
+++ b/Modules/SidePanel/Cards/UtilitiesCard.qml
@@ -26,10 +26,13 @@ NBox {
// Screen Recorder
NIconButton {
icon: "camera-video"
- tooltipText: ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording."
+ enabled: ScreenRecorderService.isAvailable
+ tooltipText: ScreenRecorderService.isAvailable ? (ScreenRecorderService.isRecording ? "Stop screen recording." : "Start screen recording.") : "Screen recorder not installed."
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
onClicked: {
+ if (!ScreenRecorderService.isAvailable)
+ return
ScreenRecorderService.toggleRecording()
// If we were not recording and we just initiated a start, close the panel
if (!ScreenRecorderService.isRecording) {
diff --git a/Services/ScreenRecorderService.qml b/Services/ScreenRecorderService.qml
index 08d6503..7642542 100644
--- a/Services/ScreenRecorderService.qml
+++ b/Services/ScreenRecorderService.qml
@@ -13,6 +13,17 @@ Singleton {
property bool isRecording: false
property bool isPending: false
property string outputPath: ""
+ property bool isAvailable: false
+
+ Component.onCompleted: {
+ checkAvailability()
+ }
+
+ function checkAvailability() {
+ // Detect native or Flatpak gpu-screen-recorder
+ availabilityCheckProcess.command = ["sh", "-c", "command -v gpu-screen-recorder >/dev/null 2>&1 || (command -v flatpak >/dev/null 2>&1 && flatpak list --app | grep -q 'com.dec05eba.gpu_screen_recorder')"]
+ availabilityCheckProcess.running = true
+ }
// Start or Stop recording
function toggleRecording() {
@@ -21,6 +32,9 @@ Singleton {
// Start screen recording using Quickshell.execDetached
function startRecording() {
+ if (!isAvailable) {
+ return
+ }
if (isRecording || isPending) {
return
}
@@ -88,6 +102,18 @@ Singleton {
}
}
+ // Availability check process
+ Process {
+ id: availabilityCheckProcess
+ command: ["sh", "-c", "true"]
+ onExited: function (exitCode, exitStatus) {
+ // exitCode 0 means available, non-zero means unavailable
+ root.isAvailable = (exitCode === 0)
+ }
+ stdout: StdioCollector {}
+ stderr: StdioCollector {}
+ }
+
Timer {
id: pendingTimer
interval: 2000 // Wait 2 seconds to see if process stays alive
diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml
index d787880..bb37444 100644
--- a/Widgets/NIconButton.qml
+++ b/Widgets/NIconButton.qml
@@ -35,13 +35,13 @@ Rectangle {
opacity: root.enabled ? Style.opacityFull : Style.opacityMedium
color: root.enabled && root.hovering ? colorBgHover : colorBg
radius: width * 0.5
- border.color: root.hovering ? colorBorderHover : colorBorder
+ border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder
border.width: Math.max(1, Style.borderS * scaling)
NIcon {
icon: root.icon
font.pointSize: Style.fontSizeM * scaling
- color: root.hovering ? colorFgHover : colorFg
+ color: root.enabled && root.hovering ? colorFgHover : colorFg
// Center horizontally
x: (root.width - width) / 2
// Center vertically accounting for font metrics
@@ -56,13 +56,14 @@ Rectangle {
}
MouseArea {
- enabled: root.enabled
+ // Always enabled to allow hover/tooltip even when the button is disabled
+ enabled: true
anchors.fill: parent
cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
hoverEnabled: true
onEntered: {
- hovering = true
+ hovering = root.enabled ? true : false
if (tooltipText) {
tooltip.show()
}
@@ -79,6 +80,9 @@ Rectangle {
if (tooltipText) {
tooltip.hide()
}
+ if (!root.enabled) {
+ return
+ }
if (mouse.button === Qt.LeftButton) {
root.clicked()
} else if (mouse.button === Qt.RightButton) {
From b422a419cd8e6dfb35e5f6a6f1f18050b85960c8 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 13:26:15 +0200
Subject: [PATCH 047/118] BatteryWidget: add low battery threshold NSpinBox:
add bootstrap icons
---
Modules/Bar/Widgets/Battery.qml | 4 +---
.../Bar/WidgetSettings/BatterySettings.qml | 13 +++++++++++++
Widgets/NSpinBox.qml | 4 ++--
3 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml
index e191c44..bb112e0 100644
--- a/Modules/Bar/Widgets/Battery.qml
+++ b/Modules/Bar/Widgets/Battery.qml
@@ -57,9 +57,7 @@ Item {
// Only notify once we are a below threshold
if (!charging && !root.hasNotifiedLowBattery && percent <= warningThreshold) {
root.hasNotifiedLowBattery = true
- // Maybe go with toast ?
- Quickshell.execDetached(
- ["notify-send", "-u", "critical", "-i", "battery-caution", "Low Battery", `Battery is at ${p}%. Please connect charger.`])
+ ToastService.showWarning("Low Battery", `Battery is at ${Math.round(percent)}%. Please connect the charger.`)
} else if (root.hasNotifiedLowBattery && (charging || percent > warningThreshold + 5)) {
// Reset when charging starts or when battery recovers 5% above threshold
root.hasNotifiedLowBattery = false
diff --git a/Modules/SettingsPanel/Bar/WidgetSettings/BatterySettings.qml b/Modules/SettingsPanel/Bar/WidgetSettings/BatterySettings.qml
index 54b589a..4e66f65 100644
--- a/Modules/SettingsPanel/Bar/WidgetSettings/BatterySettings.qml
+++ b/Modules/SettingsPanel/Bar/WidgetSettings/BatterySettings.qml
@@ -16,10 +16,13 @@ ColumnLayout {
// Local state
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage
!== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage
+ property int valueWarningThreshold: widgetData.warningThreshold
+ !== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold
function saveSettings() {
var settings = Object.assign({}, widgetData || {})
settings.alwaysShowPercentage = valueAlwaysShowPercentage
+ settings.warningThreshold = valueWarningThreshold
return settings
}
@@ -28,4 +31,14 @@ ColumnLayout {
checked: root.valueAlwaysShowPercentage
onToggled: checked => root.valueAlwaysShowPercentage = checked
}
+
+ NSpinBox {
+ label: "Low battery warning threshold"
+ description: "Show a warning when battery falls below this percentage."
+ value: valueWarningThreshold
+ suffix: "%"
+ minimum: 5
+ maximum: 50
+ onValueChanged: valueWarningThreshold = value
+ }
}
diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml
index a2f2d5c..8e8d630 100644
--- a/Widgets/NSpinBox.qml
+++ b/Widgets/NSpinBox.qml
@@ -95,7 +95,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: "dash-lg"
+ text: "\uF2E6"
font.pointSize: Style.fontSizeS * scaling
color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -130,7 +130,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: "plus-lg"
+ text: "\uF4FA"
font.pointSize: Style.fontSizeS * scaling
color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
From f7b0a28b1ece9ad2e0baa923f9ce23c160a545c5 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:06:14 -0400
Subject: [PATCH 048/118] Icon: different memory usage icon (cpu)
---
Modules/Bar/Widgets/SystemMonitor.qml | 2 +-
Modules/SidePanel/Cards/SystemMonitorCard.qml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index fbfaed1..93df904 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -133,7 +133,7 @@ RowLayout {
spacing: Style.marginXS * scaling
NIcon {
- icon: "memory"
+ icon: "cpu"
font.pointSize: Style.fontSizeM * scaling
Layout.alignment: Qt.AlignVCenter
}
diff --git a/Modules/SidePanel/Cards/SystemMonitorCard.qml b/Modules/SidePanel/Cards/SystemMonitorCard.qml
index f5cda28..d9af228 100644
--- a/Modules/SidePanel/Cards/SystemMonitorCard.qml
+++ b/Modules/SidePanel/Cards/SystemMonitorCard.qml
@@ -41,7 +41,7 @@ NBox {
}
NCircleStat {
value: SystemStatService.memPercent
- icon: "memory"
+ icon: "cpu"
flat: true
contentScale: 0.8
width: 72 * scaling
From bc7fe21d27e6a1a4150c490e2a779b8a86d5f981 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:09:22 -0400
Subject: [PATCH 049/118] Widget Settings: always use MetaData as default +
Removed non existing settting from space (debugMode leftovers)
---
Modules/Bar/Widgets/Spacer.qml | 8 --------
Modules/Bar/Widgets/SystemMonitor.qml | 3 +--
.../Bar/WidgetSettings/SystemMonitorSettings.qml | 3 +--
3 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/Modules/Bar/Widgets/Spacer.qml b/Modules/Bar/Widgets/Spacer.qml
index dc2651c..fcb8cfe 100644
--- a/Modules/Bar/Widgets/Spacer.qml
+++ b/Modules/Bar/Widgets/Spacer.qml
@@ -38,12 +38,4 @@ Item {
implicitHeight: Style.barHeight * scaling
width: implicitWidth
height: implicitHeight
-
- // Optional: Add a subtle visual indicator in debug mode
- Rectangle {
- anchors.fill: parent
- color: Qt.rgba(1, 0, 0, 0.1) // Very subtle red tint
- visible: Settings.data.general.debugMode || false
- radius: Style.radiusXXS * scaling
- }
}
diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml
index 93df904..f6e0968 100644
--- a/Modules/Bar/Widgets/SystemMonitor.qml
+++ b/Modules/Bar/Widgets/SystemMonitor.qml
@@ -39,8 +39,7 @@ RowLayout {
readonly property bool showNetworkStats: (widgetSettings.showNetworkStats
!== undefined) ? widgetSettings.showNetworkStats : widgetMetadata.showNetworkStats
readonly property bool showDiskUsage: (widgetSettings.showDiskUsage
- !== undefined) ? widgetSettings.showDiskUsage : (widgetMetadata.showDiskUsage
- || false)
+ !== undefined) ? widgetSettings.showDiskUsage : widgetMetadata.showDiskUsage
Layout.alignment: Qt.AlignVCenter
spacing: Style.marginS * scaling
diff --git a/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml b/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
index 4b2807b..39e4614 100644
--- a/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
+++ b/Modules/SettingsPanel/Bar/WidgetSettings/SystemMonitorSettings.qml
@@ -21,8 +21,7 @@ ColumnLayout {
!== undefined ? widgetData.showMemoryAsPercent : widgetMetadata.showMemoryAsPercent
property bool valueShowNetworkStats: widgetData.showNetworkStats
!== undefined ? widgetData.showNetworkStats : widgetMetadata.showNetworkStats
- property bool valueShowDiskUsage: widgetData.showDiskUsage !== undefined ? widgetData.showDiskUsage : (widgetMetadata.showDiskUsage
- || false)
+ property bool valueShowDiskUsage: widgetData.showDiskUsage !== undefined ? widgetData.showDiskUsage : widgetMetadata.showDiskUsage
function saveSettings() {
var settings = Object.assign({}, widgetData || {})
From ed9ee658854eac5c79f72d779d38d6a5ac2a257f Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 14:11:18 +0200
Subject: [PATCH 050/118] ActiveWindow: add guarding for null title/icon
(Hyprland) CompositorService: turn title, appId and id into strings to
perhaps prevent crashing (Hyprland)
---
Modules/Bar/Widgets/ActiveWindow.qml | 8 ++++++--
Services/CompositorService.qml | 6 +++---
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml
index 7ce8e3f..d1c6c2c 100644
--- a/Modules/Bar/Widgets/ActiveWindow.qml
+++ b/Modules/Bar/Widgets/ActiveWindow.qml
@@ -47,14 +47,18 @@ RowLayout {
// Try CompositorService first
const focusedWindow = CompositorService.getFocusedWindow()
if (focusedWindow && focusedWindow.appId) {
- return Icons.iconForAppId(focusedWindow.appId.toLowerCase())
+ const idValue = focusedWindow.appId
+ const normalizedId = (typeof idValue === 'string') ? idValue : String(idValue)
+ return Icons.iconForAppId(normalizedId.toLowerCase())
}
// Fallback to ToplevelManager
if (ToplevelManager && ToplevelManager.activeToplevel) {
const activeToplevel = ToplevelManager.activeToplevel
if (activeToplevel.appId) {
- return Icons.iconForAppId(activeToplevel.appId.toLowerCase())
+ const idValue2 = activeToplevel.appId
+ const normalizedId2 = (typeof idValue2 === 'string') ? idValue2 : String(idValue2)
+ return Icons.iconForAppId(normalizedId2.toLowerCase())
}
}
diff --git a/Services/CompositorService.qml b/Services/CompositorService.qml
index 173d3d6..3a5545f 100644
--- a/Services/CompositorService.qml
+++ b/Services/CompositorService.qml
@@ -192,9 +192,9 @@ Singleton {
}
windowsList.push({
- "id": toplevel.address || "",
- "title": toplevel.title || "",
- "appId": appId,
+ "id": (toplevel.address !== undefined && toplevel.address !== null) ? String(toplevel.address) : "",
+ "title": (toplevel.title !== undefined && toplevel.title !== null) ? String(toplevel.title) : "",
+ "appId": (appId !== undefined && appId !== null) ? String(appId) : "",
"workspaceId": toplevel.workspace?.id || null,
"isFocused": toplevel.activated === true
})
From 5e23476089839c2708170faf08824028cf3fa9db Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:17:00 -0400
Subject: [PATCH 051/118] NIconButton: font size auto determined by button size
---
Widgets/NIconButton.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml
index bb37444..e5576ed 100644
--- a/Widgets/NIconButton.qml
+++ b/Widgets/NIconButton.qml
@@ -40,7 +40,7 @@ Rectangle {
NIcon {
icon: root.icon
- font.pointSize: Style.fontSizeM * scaling
+ font.pointSize: Math.max(1, root.width * 0.4)
color: root.enabled && root.hovering ? colorFgHover : colorFg
// Center horizontally
x: (root.width - width) / 2
From 4455074493e180a6136ca65104d638c06e487047 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:23:34 -0400
Subject: [PATCH 052/118] ActiveWindow+MediaMini: auto min & max width
---
Modules/Bar/Widgets/ActiveWindow.qml | 5 +++--
Modules/Bar/Widgets/MediaMini.qml | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml
index 7ce8e3f..e55086e 100644
--- a/Modules/Bar/Widgets/ActiveWindow.qml
+++ b/Modules/Bar/Widgets/ActiveWindow.qml
@@ -33,8 +33,9 @@ RowLayout {
readonly property bool showIcon: (widgetSettings.showIcon !== undefined) ? widgetSettings.showIcon : widgetMetadata.showIcon
- readonly property real minWidth: 160
- readonly property real maxWidth: 400
+ // 5% of total width
+ readonly property real minWidth: Math.max(1, screen.width * 0.05)
+ readonly property real maxWidth: minWidth * 2
Layout.alignment: Qt.AlignVCenter
spacing: Style.marginS * scaling
visible: getTitle() !== ""
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index dafa9a6..213d963 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -38,8 +38,9 @@ RowLayout {
readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType
!== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType
- readonly property real minWidth: 160
- readonly property real maxWidth: 400
+ // 5% of total width
+ readonly property real minWidth: Math.max(1, screen.width * 0.05)
+ readonly property real maxWidth: minWidth * 2
function getTitle() {
return MediaService.trackTitle + (MediaService.trackArtist !== "" ? ` - ${MediaService.trackArtist}` : "")
From 73541eec49ad6467d1459de81c269f1c79a22f51 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:25:25 -0400
Subject: [PATCH 053/118] ActiveWindow + MediaMini: width boosted to 6%
---
Modules/Bar/Widgets/ActiveWindow.qml | 11 ++++++-----
Modules/Bar/Widgets/MediaMini.qml | 4 ++--
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml
index 5291991..473bdfe 100644
--- a/Modules/Bar/Widgets/ActiveWindow.qml
+++ b/Modules/Bar/Widgets/ActiveWindow.qml
@@ -33,17 +33,18 @@ RowLayout {
readonly property bool showIcon: (widgetSettings.showIcon !== undefined) ? widgetSettings.showIcon : widgetMetadata.showIcon
- // 5% of total width
- readonly property real minWidth: Math.max(1, screen.width * 0.05)
+ // 6% of total width
+ readonly property real minWidth: Math.max(1, screen.width * 0.06)
readonly property real maxWidth: minWidth * 2
- Layout.alignment: Qt.AlignVCenter
- spacing: Style.marginS * scaling
- visible: getTitle() !== ""
function getTitle() {
return CompositorService.focusedWindowTitle !== "(No active window)" ? CompositorService.focusedWindowTitle : ""
}
+ Layout.alignment: Qt.AlignVCenter
+ spacing: Style.marginS * scaling
+ visible: getTitle() !== ""
+
function getAppIcon() {
// Try CompositorService first
const focusedWindow = CompositorService.getFocusedWindow()
diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml
index 213d963..aa00cb9 100644
--- a/Modules/Bar/Widgets/MediaMini.qml
+++ b/Modules/Bar/Widgets/MediaMini.qml
@@ -38,8 +38,8 @@ RowLayout {
readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType
!== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType
- // 5% of total width
- readonly property real minWidth: Math.max(1, screen.width * 0.05)
+ // 6% of total width
+ readonly property real minWidth: Math.max(1, screen.width * 0.06)
readonly property real maxWidth: minWidth * 2
function getTitle() {
From 864cbfcfabb4834fa0a783fe87fb8ea8abc40fb0 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 14:26:27 +0200
Subject: [PATCH 054/118] NSpinBox: remove unicode, use Bootstrap.qml
---
Widgets/NSpinBox.qml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml
index 8e8d630..cbc1561 100644
--- a/Widgets/NSpinBox.qml
+++ b/Widgets/NSpinBox.qml
@@ -95,7 +95,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: "\uF2E6"
+ icon: "chevron-left"
font.pointSize: Style.fontSizeS * scaling
color: decreaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
@@ -130,7 +130,7 @@ RowLayout {
NIcon {
anchors.centerIn: parent
- text: "\uF4FA"
+ icon: "chevron-right"
font.pointSize: Style.fontSizeS * scaling
color: increaseArea.containsMouse ? Color.mOnPrimary : Color.mPrimary
}
From ecd6141739023d006c734ec1d9fa6b5075e6cfd6 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:27:44 -0400
Subject: [PATCH 055/118] Toast: better spacing/margin
---
Services/CompositorService.qml | 6 ++++--
Widgets/NToast.qml | 4 ++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/Services/CompositorService.qml b/Services/CompositorService.qml
index 3a5545f..7e46e31 100644
--- a/Services/CompositorService.qml
+++ b/Services/CompositorService.qml
@@ -192,8 +192,10 @@ Singleton {
}
windowsList.push({
- "id": (toplevel.address !== undefined && toplevel.address !== null) ? String(toplevel.address) : "",
- "title": (toplevel.title !== undefined && toplevel.title !== null) ? String(toplevel.title) : "",
+ "id": (toplevel.address !== undefined
+ && toplevel.address !== null) ? String(toplevel.address) : "",
+ "title": (toplevel.title !== undefined && toplevel.title !== null) ? String(
+ toplevel.title) : "",
"appId": (appId !== undefined && appId !== null) ? String(appId) : "",
"workspaceId": toplevel.workspace?.id || null,
"isFocused": toplevel.activated === true
diff --git a/Widgets/NToast.qml b/Widgets/NToast.qml
index ffb7a80..c6ccbbc 100644
--- a/Widgets/NToast.qml
+++ b/Widgets/NToast.qml
@@ -112,8 +112,8 @@ Item {
RowLayout {
id: contentLayout
anchors.fill: parent
- anchors.margins: Style.marginM * scaling
- spacing: Style.marginS * scaling
+ anchors.margins: Style.marginL * scaling
+ spacing: Style.marginL * scaling
// Icon
NIcon {
From f6b3f6d2ec1c85b6594c757e253bc8dc40aed9b2 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:49:08 -0400
Subject: [PATCH 056/118] ProfileCard: more discrete System uptime
---
Modules/SidePanel/Cards/ProfileCard.qml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Modules/SidePanel/Cards/ProfileCard.qml b/Modules/SidePanel/Cards/ProfileCard.qml
index a9ef68b..66ecaa2 100644
--- a/Modules/SidePanel/Cards/ProfileCard.qml
+++ b/Modules/SidePanel/Cards/ProfileCard.qml
@@ -47,7 +47,8 @@ NBox {
}
NText {
text: `System uptime: ${uptimeText}`
- color: Color.mOnSurface
+ font.pointSize: Style.fontSizeS * scaling
+ color: Color.mOnSurfaceVariant
}
}
From d76d1c628afb6193191390c9c82ea75f99464f5f Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 08:56:30 -0400
Subject: [PATCH 057/118] NIconButton: animation on color (bg+fg)
---
Widgets/NIconButton.qml | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml
index e5576ed..296279e 100644
--- a/Widgets/NIconButton.qml
+++ b/Widgets/NIconButton.qml
@@ -38,6 +38,13 @@ Rectangle {
border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder
border.width: Math.max(1, Style.borderS * scaling)
+ Behavior on color {
+ ColorAnimation {
+ duration: Style.animationNormal
+ easing.type: Easing.InOutQuad
+ }
+ }
+
NIcon {
icon: root.icon
font.pointSize: Math.max(1, root.width * 0.4)
@@ -46,6 +53,13 @@ Rectangle {
x: (root.width - width) / 2
// Center vertically accounting for font metrics
y: (root.height - height) / 2 + (height - contentHeight) / 2
+
+ Behavior on color {
+ ColorAnimation {
+ duration: Style.animationFast
+ easing.type: Easing.InOutQuad
+ }
+ }
}
NTooltip {
From 61cf7ab843f332a3a6a47d89254bcbdf9dce1665 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 15:12:46 +0200
Subject: [PATCH 058/118] CustomButtonWidget: add icon picker to improve
usability
---
.../WidgetSettings/CustomButtonSettings.qml | 182 +++++++++++++++++-
Services/CompositorService.qml | 6 +-
2 files changed, 182 insertions(+), 6 deletions(-)
diff --git a/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml b/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml
index b7c896f..7e5c78a 100644
--- a/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml
+++ b/Modules/SettingsPanel/Bar/WidgetSettings/CustomButtonSettings.qml
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
+import QtQuick.Window
import qs.Commons
import qs.Widgets
import qs.Services
@@ -9,7 +10,6 @@ ColumnLayout {
id: root
spacing: Style.marginM * scaling
- // Properties to receive data from parent
property var widgetData: null
property var widgetMetadata: null
@@ -22,16 +22,190 @@ ColumnLayout {
return settings
}
- // Icon setting
NTextInput {
id: iconInput
Layout.fillWidth: true
label: "Icon Name"
- description: "Choose a name from the Material Icon set."
- placeholderText: "Enter icon name (e.g., favorite, home, settings)"
+ description: "Pick from Bootstrap Icons or type a name."
+ placeholderText: "Enter icon name (e.g., speedometer2, gear, house)"
text: widgetData?.icon || widgetMetadata.icon
}
+ RowLayout {
+ spacing: Style.marginS * scaling
+ Layout.alignment: Qt.AlignLeft
+ NIcon {
+ Layout.alignment: Qt.AlignVCenter
+ icon: iconInput.text
+ visible: iconInput.text !== ""
+ }
+ NButton {
+ text: "Browse"
+ onClicked: iconPicker.open()
+ }
+ }
+
+ Popup {
+ id: iconPicker
+ modal: true
+ property real panelWidth: {
+ var w = Math.round(Math.max(Screen.width * 0.35, 900) * scaling)
+ w = Math.min(w, Screen.width - Style.marginL * 2)
+ return w
+ }
+ property real panelHeight: {
+ var h = Math.round(Math.max(Screen.height * 0.65, 700) * scaling)
+ h = Math.min(h, Screen.height - Style.barHeight * scaling - Style.marginL * 2)
+ return h
+ }
+ width: panelWidth
+ height: panelHeight
+ anchors.centerIn: Overlay.overlay
+ padding: Style.marginXL * scaling
+
+ property string query: ""
+ property string selectedIcon: ""
+ property var allIcons: Object.keys(Bootstrap.icons)
+ property var filteredIcons: allIcons.filter(function (name) {
+ return query === "" || name.toLowerCase().indexOf(query.toLowerCase()) !== -1
+ })
+ readonly property int tileBase: Math.round(112 * scaling)
+ readonly property int columns: Math.max(3, Math.floor(grid.width / (tileBase + Style.marginS * 2)))
+ readonly property int cellW: Math.floor(grid.width / columns)
+ readonly property int cellH: Math.round(cellW * 0.7 + 36 * scaling)
+
+ background: Rectangle {
+ color: Color.mSurface
+ radius: Style.radiusL * scaling
+ border.color: Color.mPrimary
+ border.width: Style.borderM * scaling
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: Style.marginM * scaling
+
+ // Title row
+ RowLayout {
+ Layout.fillWidth: true
+ NText {
+ text: "Icon Picker"
+ font.pointSize: Style.fontSizeL * scaling
+ font.weight: Style.fontWeightBold
+ color: Color.mPrimary
+ Layout.fillWidth: true
+ }
+ NIconButton {
+ icon: "x-lg"
+ onClicked: iconPicker.close()
+ }
+ }
+
+ NDivider {
+ Layout.fillWidth: true
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Style.marginS * scaling
+ NTextInput {
+ Layout.fillWidth: true
+ label: "Search"
+ placeholderText: "Search (e.g., arrow, battery, cloud)"
+ text: iconPicker.query
+ onTextChanged: iconPicker.query = text.trim().toLowerCase()
+ }
+ }
+
+ // Icon grid
+ ScrollView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ clip: true
+
+ GridView {
+ id: grid
+ anchors.fill: parent
+ anchors.margins: Style.marginM * scaling
+ cellWidth: iconPicker.cellW
+ cellHeight: iconPicker.cellH
+ model: iconPicker.filteredIcons
+ delegate: Rectangle {
+ width: grid.cellWidth
+ height: grid.cellHeight
+ radius: Style.radiusS * scaling
+ clip: true
+ color: (iconPicker.selectedIcon === modelData) ? Qt.alpha(Color.mPrimary, 0.15) : "transparent"
+ border.color: (iconPicker.selectedIcon === modelData) ? Color.mPrimary : Qt.rgba(0, 0, 0, 0)
+ border.width: (iconPicker.selectedIcon === modelData) ? Style.borderS * scaling : 0
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: iconPicker.selectedIcon = modelData
+ onDoubleClicked: {
+ iconPicker.selectedIcon = modelData
+ iconInput.text = iconPicker.selectedIcon
+ iconPicker.close()
+ }
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.margins: Style.marginS * scaling
+ spacing: Style.marginS * scaling
+ Item {
+ Layout.fillHeight: true
+ Layout.preferredHeight: 4 * scaling
+ }
+ NIcon {
+ Layout.alignment: Qt.AlignHCenter
+ icon: modelData
+ font.pointSize: Style.fontSizeXXXL * scaling
+ }
+ NText {
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ Layout.topMargin: Style.marginXS * scaling
+ elide: Text.ElideRight
+ wrapMode: Text.NoWrap
+ maximumLineCount: 1
+ horizontalAlignment: Text.AlignHCenter
+ color: Color.mOnSurfaceVariant
+ font.pointSize: Style.fontSizeXS * scaling
+ text: modelData
+ }
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: Style.marginM * scaling
+ Item {
+ Layout.fillWidth: true
+ }
+ NButton {
+ text: "Cancel"
+ outlined: true
+ onClicked: iconPicker.close()
+ }
+ NButton {
+ text: "Apply"
+ icon: "check-lg"
+ enabled: iconPicker.selectedIcon !== ""
+ onClicked: {
+ iconInput.text = iconPicker.selectedIcon
+ iconPicker.close()
+ }
+ }
+ }
+ }
+ }
+
NTextInput {
id: leftClickExecInput
Layout.fillWidth: true
diff --git a/Services/CompositorService.qml b/Services/CompositorService.qml
index 3a5545f..7e46e31 100644
--- a/Services/CompositorService.qml
+++ b/Services/CompositorService.qml
@@ -192,8 +192,10 @@ Singleton {
}
windowsList.push({
- "id": (toplevel.address !== undefined && toplevel.address !== null) ? String(toplevel.address) : "",
- "title": (toplevel.title !== undefined && toplevel.title !== null) ? String(toplevel.title) : "",
+ "id": (toplevel.address !== undefined
+ && toplevel.address !== null) ? String(toplevel.address) : "",
+ "title": (toplevel.title !== undefined && toplevel.title !== null) ? String(
+ toplevel.title) : "",
"appId": (appId !== undefined && appId !== null) ? String(appId) : "",
"workspaceId": toplevel.workspace?.id || null,
"isFocused": toplevel.activated === true
From cfd7dec04dce855910fe39a638d24974da6c00b7 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 09:13:27 -0400
Subject: [PATCH 059/118] WeatherCard: Vertical centering of icons
---
Modules/SidePanel/Cards/WeatherCard.qml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Modules/SidePanel/Cards/WeatherCard.qml b/Modules/SidePanel/Cards/WeatherCard.qml
index baa04c8..63c7b47 100644
--- a/Modules/SidePanel/Cards/WeatherCard.qml
+++ b/Modules/SidePanel/Cards/WeatherCard.qml
@@ -27,6 +27,7 @@ NBox {
RowLayout {
spacing: Style.marginS * scaling
NIcon {
+ Layout.alignment: Qt.AlignVCenter
icon: weatherReady ? LocationService.weatherSymbolFromCode(
LocationService.data.weather.current_weather.weathercode) : ""
font.pointSize: Style.fontSizeXXXL * 1.75 * scaling
@@ -98,6 +99,7 @@ NBox {
color: Color.mOnSurface
}
NIcon {
+ Layout.alignment: Qt.AlignVCenter
icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
font.pointSize: Style.fontSizeXXL * scaling
color: Color.mPrimary
@@ -128,4 +130,4 @@ NBox {
NBusyIndicator {}
}
}
-}
+}
\ No newline at end of file
From fe139c208a98d90550779cc2f19071a04dca14d7 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 09:16:48 -0400
Subject: [PATCH 060/118] CustomIcomButton: changed default icon to "heart"
---
Services/BarWidgetRegistry.qml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml
index fc99a0e..6005842 100644
--- a/Services/BarWidgetRegistry.qml
+++ b/Services/BarWidgetRegistry.qml
@@ -60,7 +60,7 @@ Singleton {
},
"CustomButton": {
"allowUserSettings": true,
- "icon": "favorite",
+ "icon": "heart",
"leftClickExec": "",
"rightClickExec": "",
"middleClickExec": ""
From a6ccc8b0da91fc22b8928f57dad9a47fc54f1076 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 09:22:05 -0400
Subject: [PATCH 061/118] NButton: fix issue when no icon defined
---
Modules/SidePanel/Cards/WeatherCard.qml | 2 +-
Widgets/NButton.qml | 36 ++++++++++++-------------
Widgets/NIcon.qml | 6 ++++-
3 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/Modules/SidePanel/Cards/WeatherCard.qml b/Modules/SidePanel/Cards/WeatherCard.qml
index 63c7b47..d0b55cb 100644
--- a/Modules/SidePanel/Cards/WeatherCard.qml
+++ b/Modules/SidePanel/Cards/WeatherCard.qml
@@ -130,4 +130,4 @@ NBox {
NBusyIndicator {}
}
}
-}
\ No newline at end of file
+}
diff --git a/Widgets/NButton.qml b/Widgets/NButton.qml
index 1bf82b0..000eb43 100644
--- a/Widgets/NButton.qml
+++ b/Widgets/NButton.qml
@@ -80,29 +80,27 @@ Rectangle {
spacing: Style.marginXS * scaling
// Icon (optional)
- Loader {
- active: root.icon !== ""
- sourceComponent: NIcon {
- Layout.alignment: Qt.AlignVCenter
+ NIcon {
+ Layout.alignment: Qt.AlignVCenter
+ visible: root.icon !== ""
- icon: root.icon
- font.pointSize: root.iconSize
- color: {
- if (!root.enabled)
- return Color.mOnSurfaceVariant
- if (root.outlined) {
- if (root.pressed || root.hovered)
- return root.backgroundColor
+ icon: root.icon
+ font.pointSize: root.iconSize
+ color: {
+ if (!root.enabled)
+ return Color.mOnSurfaceVariant
+ if (root.outlined) {
+ if (root.pressed || root.hovered)
return root.backgroundColor
- }
- return root.textColor
+ return root.backgroundColor
}
+ return root.textColor
+ }
- Behavior on color {
- ColorAnimation {
- duration: Style.animationFast
- easing.type: Easing.OutCubic
- }
+ Behavior on color {
+ ColorAnimation {
+ duration: Style.animationFast
+ easing.type: Easing.OutCubic
}
}
}
diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml
index fedbaa0..d253730 100644
--- a/Widgets/NIcon.qml
+++ b/Widgets/NIcon.qml
@@ -7,8 +7,12 @@ Text {
readonly property string defaultIcon: "balloon"
property string icon: defaultIcon
+ visible: (icon !== undefined) && (icon !== "")
text: {
- if (icon === undefined || Bootstrap.icons[icon] === undefined) {
+ if ((icon === undefined) || (icon === "")) {
+ return ""
+ }
+ if (Bootstrap.icons[icon] === undefined) {
Logger.warn("Icon", `"${icon}"`, "doesn't exist in the bootstrap font")
Logger.callStack()
return Bootstrap.icons[defaultIcon]
From 5f1cfb907296d0e1a1885c16ede3ce663cd7c4c8 Mon Sep 17 00:00:00 2001
From: LemmyCook
Date: Tue, 9 Sep 2025 09:27:46 -0400
Subject: [PATCH 062/118] CustomButton: no border
---
Modules/Bar/Widgets/CustomButton.qml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Modules/Bar/Widgets/CustomButton.qml b/Modules/Bar/Widgets/CustomButton.qml
index 08d3dc8..ab1868b 100644
--- a/Modules/Bar/Widgets/CustomButton.qml
+++ b/Modules/Bar/Widgets/CustomButton.qml
@@ -38,6 +38,8 @@ NIconButton {
readonly property string middleClickExec: widgetSettings.middleClickExec || widgetMetadata.middleClickExec
readonly property bool hasExec: (leftClickExec || rightClickExec || middleClickExec)
+ colorBorder: Color.transparent
+ colorBorderHover: Color.transparent
sizeRatio: 0.8
icon: customIcon
tooltipText: {
From e4cad6ed200f80fbebe930e50294f0669d0ee63b Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 15:44:11 +0200
Subject: [PATCH 063/118] Update README and flake.nix README: inform users
about breaking changes (due to the font change) flake: attempt to install the
bootstrap-icons font
---
README.md | 7 ++++++-
flake.nix | 44 ++++++++++++++++++++++++++++++++------------
2 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index dcdcd20..5212782 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,11 @@
+
+> ⚠️ **BREAKING CHANGE:**
+> We transitioned from using Material Symbols to Bootstrap Icons, that means you will have to install the new font.
+---
+
A sleek and minimal desktop shell thoughtfully crafted for Wayland, built with Quickshell.
Features a modern modular architecture with a status bar, notification system, control panel, comprehensive system integration, and more — all styled with a warm lavender palette, or your favorite color scheme!
@@ -66,7 +71,7 @@ Features a modern modular architecture with a status bar, notification system, c
- `quickshell-git` - Core shell framework
- `ttf-roboto` - The default font used for most of the UI
- `inter-font` - The default font used for Headers (ex: clock on the LockScreen)
-- `ttf-material-symbols-variable-git` - Icon font for UI elements
+- `ttf-bootstrap-icons` - Icon font for UI elements
- `gpu-screen-recorder` - Screen recording functionality
- `brightnessctl` - For internal/laptop monitor brightness
- `ddcutil` - For desktop monitor brightness (might introduce some system instability with certain monitors)
diff --git a/flake.nix b/flake.nix
index b61342f..bb16caa 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,16 +1,13 @@
{
description = "Noctalia shell - a Wayland desktop shell built with Quickshell";
-
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
systems.url = "github:nix-systems/default";
-
quickshell = {
url = "git+https://git.outfoxxed.me/outfoxxed/quickshell";
inputs.nixpkgs.follows = "nixpkgs";
};
};
-
outputs = {
self,
nixpkgs,
@@ -24,7 +21,6 @@
system:
nixpkgs.legacyPackages.${system}.alejandra
);
-
packages = eachSystem (
system: let
pkgs = nixpkgs.legacyPackages.${system};
@@ -32,7 +28,33 @@
withX11 = false;
withI3 = false;
};
-
+
+ # Custom ttf-bootstrap-icons package
+ ttf-bootstrap-icons = pkgs.stdenvNoCC.mkDerivation rec {
+ pname = "ttf-bootstrap-icons";
+ version = "1.13.1";
+
+ src = pkgs.fetchzip {
+ url = "https://github.com/twbs/icons/releases/download/v${version}/bootstrap-icons-${version}.zip";
+ sha256 = "999021e12fab5c9ede5e4e7072eb176122be798b2f99195acf5dda47aef8fc93";
+ stripRoot = false;
+ };
+
+ installPhase = ''
+ runHook preInstall
+ install -Dm644 fonts/bootstrap-icons.ttf $out/share/fonts/truetype/bootstrap-icons.ttf
+ runHook postInstall
+ '';
+
+ meta = with pkgs.lib; {
+ description = "Official open source SVG icon library for Bootstrap";
+ homepage = "https://icons.getbootstrap.com/";
+ license = licenses.mit;
+ platforms = platforms.all;
+ maintainers = [];
+ };
+ };
+
runtimeDeps = with pkgs; [
bash
bluez
@@ -49,12 +71,12 @@
networkmanager
wl-clipboard
];
-
fontconfig = pkgs.makeFontsConf {
fontDirectories = [
pkgs.material-symbols
pkgs.roboto
pkgs.inter-nerdfont
+ ttf-bootstrap-icons # Add the custom font package here
];
};
in {
@@ -62,21 +84,17 @@
pname = "noctalia-shell";
version = self.rev or self.dirtyRev or "dirty";
src = ./.;
-
nativeBuildInputs = [pkgs.gcc pkgs.makeWrapper pkgs.qt6.wrapQtAppsHook];
buildInputs = [qs pkgs.xkeyboard-config pkgs.qt6.qtbase];
propagatedBuildInputs = runtimeDeps;
-
installPhase = ''
mkdir -p $out/share/noctalia-shell
cp -r ./* $out/share/noctalia-shell
-
makeWrapper ${qs}/bin/qs $out/bin/noctalia-shell \
--prefix PATH : "${pkgs.lib.makeBinPath runtimeDeps}" \
--set FONTCONFIG_FILE "${fontconfig}" \
--add-flags "-p $out/share/noctalia-shell"
'';
-
meta = {
description = "A sleek and minimal desktop shell thoughtfully crafted for Wayland, built with Quickshell.";
homepage = "https://github.com/noctalia-dev/noctalia-shell";
@@ -84,9 +102,11 @@
mainProgram = "noctalia-shell";
};
};
+
+ # Expose the custom font as a separate package (optional)
+ ttf-bootstrap-icons = ttf-bootstrap-icons;
}
);
-
defaultPackage = eachSystem (system: self.packages.${system}.default);
};
-}
+}
\ No newline at end of file
From 9c3726bdb14e89e819b9e2401b4a8cbff6878572 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 16:28:47 +0200
Subject: [PATCH 064/118] README: Update breaking changes text
---
Modules/Launcher/Plugins/ClipboardPlugin.qml | 561 +++++++++++--------
1 file changed, 329 insertions(+), 232 deletions(-)
diff --git a/Modules/Launcher/Plugins/ClipboardPlugin.qml b/Modules/Launcher/Plugins/ClipboardPlugin.qml
index 60a4348..df3bea6 100644
--- a/Modules/Launcher/Plugins/ClipboardPlugin.qml
+++ b/Modules/Launcher/Plugins/ClipboardPlugin.qml
@@ -1,268 +1,365 @@
-import QtQuick
-import Quickshell
-import qs.Commons
-import qs.Services
+
+
+
-Item {
- id: root
+# Noctalia
- // Plugin metadata
- property string name: "Clipboard History"
- property var launcher: null
+**_quiet by design_**
- // Plugin capabilities
- property bool handleSearch: false // Don't handle regular search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- // Internal state
- property bool isWaitingForData: false
- property bool gotResults: false
- property string lastSearchText: ""
- // Listen for clipboard data updates
- Connections {
- target: ClipboardService
- function onListCompleted() {
- if (gotResults && (lastSearchText === searchText)) {
- // Do not update results after the first fetch.
- // This will avoid the list resetting every 2seconds when the service updates.
- return
- }
- // Refresh results if we're waiting for data or if clipboard plugin is active
- if (isWaitingForData || (launcher && launcher.searchText.startsWith(">clip"))) {
- isWaitingForData = false
- gotResults = true
- if (launcher) {
- launcher.updateResults()
- }
- }
- }
- }
+> ⚠️ **BREAKING CHANGE:**
+> We're switching our icon set from Material Symbols to Bootstrap Icons!
+> - Arch Users: if using the AUR version, the font will be installed automatically. If installed manually you will need to install `ttf-bootstrap-icons` from the AUR.
+> - NixOS Users: I've attempted to add the new font to the flake, but it's untested. Feedback would be greatly appreciated!
+> - All Other Users: Please check your package manager for a Bootstrap Icons font. If it's not available, you may need to download it and copy it to `~/.local/share/fonts` or `/usr/share/fonts`.
+---
- // Initialize plugin
- function init() {
- Logger.log("ClipboardPlugin", "Initialized")
- // Pre-load clipboard data if service is active
- if (ClipboardService.active) {
- ClipboardService.list(100)
- }
- }
+A sleek and minimal desktop shell thoughtfully crafted for Wayland, built with Quickshell.
- // Called when launcher opens
- function onOpened() {
- isWaitingForData = true
- gotResults = false
- lastSearchText = ""
+Features a modern modular architecture with a status bar, notification system, control panel, comprehensive system integration, and more — all styled with a warm lavender palette, or your favorite color scheme!
- // Refresh clipboard history when launcher opens
- if (ClipboardService.active) {
- ClipboardService.list(100)
- }
- }
+## Preview
- // Check if this plugin handles the command
- function handleCommand(searchText) {
- return searchText.startsWith(">clip")
- }
+
- // Return available commands when user types ">"
- function commands() {
- return [{
- "name": ">clip",
- "description": "Search clipboard history",
- "icon": "text-x-generic",
- "isImage": false,
- "onActivate": function () {
- launcher.setSearchText(">clip ")
- }
- }, {
- "name": ">clip clear",
- "description": "Clear all clipboard history",
- "icon": "text-x-generic",
- "isImage": false,
- "onActivate": function () {
- ClipboardService.wipeAll()
- launcher.close()
- }
- }]
- }
+
- // Get search results
- function getResults(searchText) {
- if (!searchText.startsWith(">clip")) {
- return []
- }
+
- lastSearchText = searchText
- const results = []
- const query = searchText.slice(5).trim()
+---
- // Check if clipboard service is not active
- if (!ClipboardService.active) {
- return [{
- "name": "Clipboard History Disabled",
- "description": "Enable clipboard history in settings or install cliphist",
- "icon": "view-refresh",
- "isImage": false,
- "onActivate": function () {}
- }]
- }
+> ⚠️ **Note:**
+> This shell currently supports **Niri** and **Hyprland** compositors. For other compositors, you will need to implement custom workspace logic in the CompositorService.
- // Special command: clear
- if (query === "clear") {
- return [{
- "name": "Clear Clipboard History",
- "description": "Remove all items from clipboard history",
- "icon": "delete_sweep",
- "isImage": false,
- "onActivate": function () {
- ClipboardService.wipeAll()
- launcher.close()
- }
- }]
- }
+---
- // Show loading state if data is being loaded
- if (ClipboardService.loading || isWaitingForData) {
- return [{
- "name": "Loading clipboard history...",
- "description": "Please wait",
- "icon": "view-refresh",
- "isImage": false,
- "onActivate": function () {}
- }]
- }
+## Features
- // Get clipboard items
- const items = ClipboardService.items || []
+- **Status Bar:** Modular bar with workspace indicators, system monitors, clock, and quick access controls.
+- **Workspace Management:** Dynamic workspace switching with visual indicators and active window tracking.
+- **Notifications:** Rich notification system with history panel.
+- **Application Launcher:** Stylized launcher with favorites, recent apps, and special commands (calc, clipboard).
+- **Side Panel:** Quick access panel with media controls, weather, power profiles, and system utilities.
+- **Settings Panel:** Comprehensive configuration interface for all shell components and preferences.
+- **Lock Screen:** Secure lock experience with PAM authentication, time display, and animated background.
+- **Audio Integration:** Volume controls, media playback, and audio visualizer (cava-based).
+- **Connectivity:** WiFi and Bluetooth management with device pairing and network status.
+- **Power Management:** Battery monitoring, brightness control, power profile switching, power menu, and idle inhibition.
+- **System Monitoring:** CPU, memory, and network usage monitoring with visual indicators.
+- **Tray System:** Application tray with menu support and system integration.
+- **Background Management:** Wallpaper management with effects and dynamic theming support.
+- **Color Schemes:** Catppuccin, Dracula, Gruvbox, Noctalia, Nord, Rosépine, Solarized, Tokyo night or generated from your wallpaper.
+- **Scaling:** Per monitor scaling for maximum control.
+---
- // If no items and we haven't tried loading yet, trigger a load
- if (items.count === 0 && !ClipboardService.loading) {
- isWaitingForData = true
- ClipboardService.list(100)
- return [{
- "name": "Loading clipboard history...",
- "description": "Please wait",
- "icon": "view-refresh",
- "isImage": false,
- "onActivate": function () {}
- }]
- }
+## Dependencies
- // Search clipboard items
- const searchTerm = query.toLowerCase()
+### Required
- // Filter and format results
- items.forEach(function (item) {
- const preview = (item.preview || "").toLowerCase()
+- `quickshell-git` - Core shell framework
+- `ttf-roboto` - The default font used for most of the UI
+- `inter-font` - The default font used for Headers (ex: clock on the LockScreen)
+- `ttf-bootstrap-icons` - Icon font for UI elements
+- `gpu-screen-recorder` - Screen recording functionality
+- `brightnessctl` - For internal/laptop monitor brightness
+- `ddcutil` - For desktop monitor brightness (might introduce some system instability with certain monitors)
- // Skip if search term doesn't match
- if (searchTerm && preview.indexOf(searchTerm) === -1) {
- return
- }
- // Format the result based on type
- let entry
- if (item.isImage) {
- entry = formatImageEntry(item)
- } else {
- entry = formatTextEntry(item)
- }
+### Optional
- // Add activation handler
- entry.onActivate = function () {
- ClipboardService.copyToClipboard(item.id)
- launcher.close()
- }
+- `cliphist` - For clipboard history support
+- `matugen` - Material You color scheme generation
+- `cava` - Audio visualizer component
+- `wlsunset` - To be able to use NightLight
- results.push(entry)
- })
+> There is one more optional dependency.
+> `xdg-desktop-portal` to be able to use the "Portal" option from the screenRecorder.
- // Show empty state if no results
- if (results.length === 0) {
- results.push({
- "name": searchTerm ? "No matching clipboard items" : "Clipboard is empty",
- "description": searchTerm ? `No items containing "${query}"` : "Copy something to see it here",
- "icon": "text-x-generic",
- "isImage": false,
- "onActivate": function () {// Do nothing
- }
- })
- }
+If you want to use the `ArchUpdater` widget, you will have to set your `TERMINAL` environment variable.
- //Logger.log("ClipboardPlugin", `Returning ${results.length} results for query: "${query}"`)
- return results
- }
+Example command (you can edit the /etc/environment file manually too):
- // Helper: Format image clipboard entry
- function formatImageEntry(item) {
- const meta = parseImageMeta(item.preview)
+`sudo sed -i '/^TERMINAL=/d' /etc/environment && echo 'TERMINAL=/usr/bin/kitty' | sudo tee -a /etc/environment
+`
- // The launcher's delegate will now be responsible for fetching the image data.
- // This function's role is to provide the necessary metadata for that request.
- return {
- "name": meta ? `Image ${meta.w}×${meta.h}` : "Image",
- "description": meta ? `${meta.fmt} • ${meta.size}` : item.mime || "Image data",
- "icon": "image",
- "isImage": true,
- "imageWidth": meta ? meta.w : 0,
- "imageHeight": meta ? meta.h : 0,
- "clipboardId": item.id,
- "mime": item.mime
- }
- }
+Please do not forget to edit `TERMINAL=/usr/bin/kitty` to match your terminal.
- // Helper: Format text clipboard entry with preview
- function formatTextEntry(item) {
- const preview = (item.preview || "").trim()
- const lines = preview.split('\n').filter(l => l.trim())
+---
- // Use first line as title, limit length
- let title = lines[0] || "Empty text"
- if (title.length > 60) {
- title = title.substring(0, 57) + "..."
- }
+## Quick Start
- // Use second line or character count as description
- let description = ""
- if (lines.length > 1) {
- description = lines[1]
- if (description.length > 80) {
- description = description.substring(0, 77) + "..."
- }
- } else {
- const chars = preview.length
- const words = preview.split(/\s+/).length
- description = `${chars} characters, ${words} word${words !== 1 ? 's' : ''}`
- }
+### Installation
- return {
- "name": title,
- "description": description,
- "icon": "text-x-generic",
- "isImage": false
- }
- }
+#### Arch Linux
- // Helper: Parse image metadata from preview string
- function parseImageMeta(preview) {
- const re = /\[\[\s*binary data\s+([\d\.]+\s*(?:KiB|MiB|GiB|B))\s+(\w+)\s+(\d+)x(\d+)\s*\]\]/i
- const match = (preview || "").match(re)
+
+AUR
- if (!match) {
- return null
- }
+You can install Noctalia from the [AUR](https://aur.archlinux.org/packages/noctalia-shell). This method will install the shell system-wide.
- return {
- "size": match[1],
- "fmt": (match[2] || "").toUpperCase(),
- "w": Number(match[3]),
- "h": Number(match[4])
- }
- }
+```bash
+paru -S noctalia-shell
+```
- // Public method to get image data for a clipboard item
- // This can be called by the launcher when rendering
- function getImageForItem(clipboardId) {
- return ClipboardService.getImageData ? ClipboardService.getImageData(clipboardId) : null
- }
+If you want the latest development version directly from the git repository, you can use the `noctalia-shell-git` package:
+
+```bash
+paru -S noctalia-shell-git
+```
+This will always pull the most recent commit from the Noctalia repository. Note that it may be less stable than the release version.
+
+
+
+
+Manual Installation
+
+This method installs the shell to your local user configuration.
+
+Make sure you have Quickshell installed:
+```bash
+paru -S quickshell-git
+```
+
+Download and install Noctalia (latest release):
+```bash
+mkdir -p ~/.config/quickshell/noctalia-shell && curl -sL https://github.com/noctalia-dev/noctalia-shell/releases/latest/download/noctalia-latest.tar.gz | tar -xz --strip-components=1 -C ~/.config/quickshell/noctalia-shell
+```
+
+
+
+#### Nix
+
+
+Nix Installation
+
+You can run Noctalia directly using the `nix run` command:
+```bash
+nix run github:noctalia-dev/noctalia-shell
+```
+
+Alternatively, you can add it to your NixOS configuration or flake:
+
+**Step 1**: Add Quickshell and Noctalia flakes to your `flake.nix`:
+```nix
+{
+ description = "Example Nix flake with Noctalia + Quickshell";
+
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
+
+ noctalia = {
+ url = "github:noctalia-dev/noctalia-shell";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ quickshell = {
+ url = "github:outfoxxed/quickshell";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.quickshell.follows = "quickshell"
+ };
+ };
+
+ outputs = { self, nixpkgs, noctalia, quickshell, ... }:
+ {
+ nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
+ modules = [
+ ./configuration.nix
+ ];
+ };
+ };
}
+```
+
+**Step 2**: Add the packages to your `configuration.nix`:
+```nix
+{
+ environment.systemPackages = with pkgs; [
+ inputs.noctalia.packages.${system}.default
+ inputs.quickshell.packages.${system}.default
+ ];
+}
+```
+
+
+
+### Usage
+
+`noctalia-shell` offers many IPC calls for your convenience, so you can add them to your favorite keybinds or scripts.
+
+*If you're using the Flake installation on NixOS, replace `qs -c noctalia-shell` with `noctalia-shell`*
+
+*If you're using the manual install (`git clone...` and have it in `~/.config/quickshell/`) you can just use `qs ipc call...`*
+
+| Action | Command* |
+| --------------------------- | -------------------------------------------------------------- |
+| Start the Shell | `qs -c noctalia-shell` |
+| Toggle Application Launcher | `qs -c noctalia-shell ipc call launcher toggle` |
+| Toggle Side Panel | `qs -c noctalia-shell ipc call sidePanel toggle` |
+| Open Clipboard History | `qs -c noctalia-shell ipc call launcher clipboard` |
+| Open Calculator | `qs -c noctalia-shell ipc call launcher calculator` |
+| Increase Brightness | `qs -c noctalia-shell ipc call brightness increase` |
+| Decrease Brightness | `qs -c noctalia-shell ipc call brightness decrease` |
+| Increase Output Volume | `qs -c noctalia-shell ipc call volume increase` |
+| Decrease Output Volume | `qs -c noctalia-shell ipc call volume decrease` |
+| Toggle Mute Audio Output | `qs -c noctalia-shell ipc call volume muteOutput` |
+| Toggle Mute Audio Input | `qs -c noctalia-shell ipc call volume muteInput` |
+| Toggle Power Panel | `qs -c noctalia-shell ipc call powerPanel toggle` |
+| Toggle Idle Inhibitor | `qs -c noctalia-shell ipc call idleInhibitor toggle` |
+| Toggle Settings Window | `qs -c noctalia-shell ipc call settings toggle` |
+| Toggle Lock Screen | `qs -c noctalia-shell ipc call lockScreen toggle` |
+| Toggle Notification History | `qs -c noctalia-shell ipc call notifications toggleHistory` |
+| Toggle Notification DND | `qs -c noctalia-shell ipc call notifications toggleDND` |
+| Change Wallpaper | `qs -c noctalia-shell ipc call wallpaper set $path $monitor` |
+| Assign a Random Wallpaper | `qs -c noctalia-shell ipc call wallpaper random` |
+| Toggle Dark Mode | `qs -c noctalia-shell ipc call darkMode toggle` |
+| Set Dark Mode | `qs -c noctalia-shell ipc call darkMode setDark` |
+| Set Light Mode | `qs -c noctalia-shell ipc call darkMode setLight` |
+
+### Configuration
+
+Access settings through the side panel (top right button) to configure weather, wallpapers, screen recording, audio, network, and theme options.
+Configuration is usually stored in ~/.config/noctalia.
+
+### Application Launcher
+
+The launcher supports special commands for enhanced functionality:
+- `>calc` - Simple mathematical calculations
+- `>clip` - Clipboard history management
+
+---
+
+
+Theme Colors
+
+| Color Role | Color | Description |
+| -------------------- | ----------- | -------------------------- |
+| Primary | `#c7a1d8` | Soft lavender purple |
+| On Primary | `#1a151f` | Dark text on primary |
+| Secondary | `#a984c4` | Muted lavender |
+| On Secondary | `#f3edf7` | Light text on secondary |
+| Tertiary | `#e0b7c9` | Warm pink-lavender |
+| On Tertiary | `#20161f` | Dark text on tertiary |
+| Surface | `#1c1822` | Dark purple-tinted surface |
+| On Surface | `#e9e4f0` | Light text on surface |
+| Surface Variant | `#262130` | Elevated surface variant |
+| On Surface Variant | `#a79ab0` | Muted text on surface variant |
+| Error | `#e9899d` | Soft rose red |
+| On Error | `#1e1418` | Dark text on error |
+| Outline | `#4d445a` | Purple-tinted outline |
+| Shadow | `#120f18` | Deep purple-tinted shadow |
+
+
+
+---
+
+## Advanced Configuration
+
+### Recommended Compositor Settings
+
+For Niri:
+
+```
+debug {
+ honor-xdg-activation-with-invalid-serial
+}
+
+window-rule {
+ geometry-corner-radius 20
+ clip-to-geometry true
+}
+
+layer-rule {
+ match namespace="^quickshell-wallpaper$"
+}
+
+layer-rule {
+ match namespace="^quickshell-overview$"
+ place-within-backdrop true
+}
+```
+`honor-xdg-activation-with-invalid-serial` allows notification actions (like view etc) to work.
+
+
+---
+
+
+## Development
+
+### Project Structure
+
+```
+Noctalia/
+├── shell.qml # Main shell entry point
+├── Modules/ # UI components
+│ ├── Bar/ # Status bar components
+│ ├── Dock/ # Application launcher
+│ ├── SidePanel/ # Quick access panel
+│ ├── SettingsPanel/ # Configuration interface
+│ └── ...
+├── Services/ # Backend services
+│ ├── CompositorService.qml
+│ ├── WorkspacesService.qml
+│ ├── AudioService.qml
+│ └── ...
+├── Widgets/ # Reusable UI components
+├── Commons/ # Shared utilities
+├── Assets/ # Static assets
+└── Bin/ # Utility scripts
+```
+
+### Contributing
+
+1. Follow the existing code style and patterns
+2. Use the modular architecture for new features
+3. Implement proper error handling and logging
+4. Test with both Hyprland and Niri compositors (if applicable)
+
+Contributions are welcome! Don't worry about being perfect - every contribution helps! Whether it's fixing a small bug, adding a new feature, or improving documentation, we welcome all contributions. Feel free to open an issue to discuss ideas or ask questions before diving in. For feature requests and ideas, you can also use our discussions page.
+
+---
+
+## 💜 Credits
+
+A heartfelt thank you to our incredible community of [**contributors**](https://github.com/noctalia-dev/noctalia-shell/graphs/contributors). We are immensely grateful for your dedicated participation and the constructive feedback you've provided, which continue to shape and improve our project for everyone.
+
+---
+
+## Acknowledgment
+
+Special thanks to the creators of [**Caelestia**](https://github.com/caelestia-dots/shell) and [**DankMaterialShell**](https://github.com/AvengeMedia/DankMaterialShell) for their inspirational designs and clever implementation techniques.
+
+---
+
+#### Donation
+
+While all donations are greatly appreciated, they are completely voluntary.
+
+
+
+
+
+#### Thank you to everyone who supports the project 💜!
+* Gohma
+* PikaOS
+* DiscoCevapi
+
+---
+
+## License
+
+This project is licensed under the terms of the [MIT License](./LICENSE).
From e4d499b550897cd15808981347fb5755da460d93 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 16:30:36 +0200
Subject: [PATCH 065/118] Revert "README: Update breaking changes text"
This reverts commit 9c3726bdb14e89e819b9e2401b4a8cbff6878572.
---
Modules/Launcher/Plugins/ClipboardPlugin.qml | 561 ++++++++-----------
1 file changed, 232 insertions(+), 329 deletions(-)
diff --git a/Modules/Launcher/Plugins/ClipboardPlugin.qml b/Modules/Launcher/Plugins/ClipboardPlugin.qml
index df3bea6..60a4348 100644
--- a/Modules/Launcher/Plugins/ClipboardPlugin.qml
+++ b/Modules/Launcher/Plugins/ClipboardPlugin.qml
@@ -1,365 +1,268 @@
-
-
-
+import QtQuick
+import Quickshell
+import qs.Commons
+import qs.Services
-# Noctalia
+Item {
+ id: root
-**_quiet by design_**
+ // Plugin metadata
+ property string name: "Clipboard History"
+ property var launcher: null
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ // Plugin capabilities
+ property bool handleSearch: false // Don't handle regular search
+ // Internal state
+ property bool isWaitingForData: false
+ property bool gotResults: false
+ property string lastSearchText: ""
-> ⚠️ **BREAKING CHANGE:**
-> We're switching our icon set from Material Symbols to Bootstrap Icons!
-> - Arch Users: if using the AUR version, the font will be installed automatically. If installed manually you will need to install `ttf-bootstrap-icons` from the AUR.
-> - NixOS Users: I've attempted to add the new font to the flake, but it's untested. Feedback would be greatly appreciated!
-> - All Other Users: Please check your package manager for a Bootstrap Icons font. If it's not available, you may need to download it and copy it to `~/.local/share/fonts` or `/usr/share/fonts`.
----
+ // Listen for clipboard data updates
+ Connections {
+ target: ClipboardService
+ function onListCompleted() {
+ if (gotResults && (lastSearchText === searchText)) {
+ // Do not update results after the first fetch.
+ // This will avoid the list resetting every 2seconds when the service updates.
+ return
+ }
+ // Refresh results if we're waiting for data or if clipboard plugin is active
+ if (isWaitingForData || (launcher && launcher.searchText.startsWith(">clip"))) {
+ isWaitingForData = false
+ gotResults = true
+ if (launcher) {
+ launcher.updateResults()
+ }
+ }
+ }
+ }
-A sleek and minimal desktop shell thoughtfully crafted for Wayland, built with Quickshell.
+ // Initialize plugin
+ function init() {
+ Logger.log("ClipboardPlugin", "Initialized")
+ // Pre-load clipboard data if service is active
+ if (ClipboardService.active) {
+ ClipboardService.list(100)
+ }
+ }
-Features a modern modular architecture with a status bar, notification system, control panel, comprehensive system integration, and more — all styled with a warm lavender palette, or your favorite color scheme!
+ // Called when launcher opens
+ function onOpened() {
+ isWaitingForData = true
+ gotResults = false
+ lastSearchText = ""
-## Preview
+ // Refresh clipboard history when launcher opens
+ if (ClipboardService.active) {
+ ClipboardService.list(100)
+ }
+ }
-
+ // Check if this plugin handles the command
+ function handleCommand(searchText) {
+ return searchText.startsWith(">clip")
+ }
-
+ // Return available commands when user types ">"
+ function commands() {
+ return [{
+ "name": ">clip",
+ "description": "Search clipboard history",
+ "icon": "text-x-generic",
+ "isImage": false,
+ "onActivate": function () {
+ launcher.setSearchText(">clip ")
+ }
+ }, {
+ "name": ">clip clear",
+ "description": "Clear all clipboard history",
+ "icon": "text-x-generic",
+ "isImage": false,
+ "onActivate": function () {
+ ClipboardService.wipeAll()
+ launcher.close()
+ }
+ }]
+ }
-
+ // Get search results
+ function getResults(searchText) {
+ if (!searchText.startsWith(">clip")) {
+ return []
+ }
----
+ lastSearchText = searchText
+ const results = []
+ const query = searchText.slice(5).trim()
-> ⚠️ **Note:**
-> This shell currently supports **Niri** and **Hyprland** compositors. For other compositors, you will need to implement custom workspace logic in the CompositorService.
+ // Check if clipboard service is not active
+ if (!ClipboardService.active) {
+ return [{
+ "name": "Clipboard History Disabled",
+ "description": "Enable clipboard history in settings or install cliphist",
+ "icon": "view-refresh",
+ "isImage": false,
+ "onActivate": function () {}
+ }]
+ }
----
+ // Special command: clear
+ if (query === "clear") {
+ return [{
+ "name": "Clear Clipboard History",
+ "description": "Remove all items from clipboard history",
+ "icon": "delete_sweep",
+ "isImage": false,
+ "onActivate": function () {
+ ClipboardService.wipeAll()
+ launcher.close()
+ }
+ }]
+ }
-## Features
+ // Show loading state if data is being loaded
+ if (ClipboardService.loading || isWaitingForData) {
+ return [{
+ "name": "Loading clipboard history...",
+ "description": "Please wait",
+ "icon": "view-refresh",
+ "isImage": false,
+ "onActivate": function () {}
+ }]
+ }
-- **Status Bar:** Modular bar with workspace indicators, system monitors, clock, and quick access controls.
-- **Workspace Management:** Dynamic workspace switching with visual indicators and active window tracking.
-- **Notifications:** Rich notification system with history panel.
-- **Application Launcher:** Stylized launcher with favorites, recent apps, and special commands (calc, clipboard).
-- **Side Panel:** Quick access panel with media controls, weather, power profiles, and system utilities.
-- **Settings Panel:** Comprehensive configuration interface for all shell components and preferences.
-- **Lock Screen:** Secure lock experience with PAM authentication, time display, and animated background.
-- **Audio Integration:** Volume controls, media playback, and audio visualizer (cava-based).
-- **Connectivity:** WiFi and Bluetooth management with device pairing and network status.
-- **Power Management:** Battery monitoring, brightness control, power profile switching, power menu, and idle inhibition.
-- **System Monitoring:** CPU, memory, and network usage monitoring with visual indicators.
-- **Tray System:** Application tray with menu support and system integration.
-- **Background Management:** Wallpaper management with effects and dynamic theming support.
-- **Color Schemes:** Catppuccin, Dracula, Gruvbox, Noctalia, Nord, Rosépine, Solarized, Tokyo night or generated from your wallpaper.
-- **Scaling:** Per monitor scaling for maximum control.
----
+ // Get clipboard items
+ const items = ClipboardService.items || []
-## Dependencies
+ // If no items and we haven't tried loading yet, trigger a load
+ if (items.count === 0 && !ClipboardService.loading) {
+ isWaitingForData = true
+ ClipboardService.list(100)
+ return [{
+ "name": "Loading clipboard history...",
+ "description": "Please wait",
+ "icon": "view-refresh",
+ "isImage": false,
+ "onActivate": function () {}
+ }]
+ }
-### Required
+ // Search clipboard items
+ const searchTerm = query.toLowerCase()
-- `quickshell-git` - Core shell framework
-- `ttf-roboto` - The default font used for most of the UI
-- `inter-font` - The default font used for Headers (ex: clock on the LockScreen)
-- `ttf-bootstrap-icons` - Icon font for UI elements
-- `gpu-screen-recorder` - Screen recording functionality
-- `brightnessctl` - For internal/laptop monitor brightness
-- `ddcutil` - For desktop monitor brightness (might introduce some system instability with certain monitors)
+ // Filter and format results
+ items.forEach(function (item) {
+ const preview = (item.preview || "").toLowerCase()
+ // Skip if search term doesn't match
+ if (searchTerm && preview.indexOf(searchTerm) === -1) {
+ return
+ }
-### Optional
+ // Format the result based on type
+ let entry
+ if (item.isImage) {
+ entry = formatImageEntry(item)
+ } else {
+ entry = formatTextEntry(item)
+ }
-- `cliphist` - For clipboard history support
-- `matugen` - Material You color scheme generation
-- `cava` - Audio visualizer component
-- `wlsunset` - To be able to use NightLight
+ // Add activation handler
+ entry.onActivate = function () {
+ ClipboardService.copyToClipboard(item.id)
+ launcher.close()
+ }
-> There is one more optional dependency.
-> `xdg-desktop-portal` to be able to use the "Portal" option from the screenRecorder.
+ results.push(entry)
+ })
-If you want to use the `ArchUpdater` widget, you will have to set your `TERMINAL` environment variable.
+ // Show empty state if no results
+ if (results.length === 0) {
+ results.push({
+ "name": searchTerm ? "No matching clipboard items" : "Clipboard is empty",
+ "description": searchTerm ? `No items containing "${query}"` : "Copy something to see it here",
+ "icon": "text-x-generic",
+ "isImage": false,
+ "onActivate": function () {// Do nothing
+ }
+ })
+ }
-Example command (you can edit the /etc/environment file manually too):
+ //Logger.log("ClipboardPlugin", `Returning ${results.length} results for query: "${query}"`)
+ return results
+ }
-`sudo sed -i '/^TERMINAL=/d' /etc/environment && echo 'TERMINAL=/usr/bin/kitty' | sudo tee -a /etc/environment
-`
+ // Helper: Format image clipboard entry
+ function formatImageEntry(item) {
+ const meta = parseImageMeta(item.preview)
-Please do not forget to edit `TERMINAL=/usr/bin/kitty` to match your terminal.
+ // The launcher's delegate will now be responsible for fetching the image data.
+ // This function's role is to provide the necessary metadata for that request.
+ return {
+ "name": meta ? `Image ${meta.w}×${meta.h}` : "Image",
+ "description": meta ? `${meta.fmt} • ${meta.size}` : item.mime || "Image data",
+ "icon": "image",
+ "isImage": true,
+ "imageWidth": meta ? meta.w : 0,
+ "imageHeight": meta ? meta.h : 0,
+ "clipboardId": item.id,
+ "mime": item.mime
+ }
+ }
----
+ // Helper: Format text clipboard entry with preview
+ function formatTextEntry(item) {
+ const preview = (item.preview || "").trim()
+ const lines = preview.split('\n').filter(l => l.trim())
-## Quick Start
+ // Use first line as title, limit length
+ let title = lines[0] || "Empty text"
+ if (title.length > 60) {
+ title = title.substring(0, 57) + "..."
+ }
-### Installation
+ // Use second line or character count as description
+ let description = ""
+ if (lines.length > 1) {
+ description = lines[1]
+ if (description.length > 80) {
+ description = description.substring(0, 77) + "..."
+ }
+ } else {
+ const chars = preview.length
+ const words = preview.split(/\s+/).length
+ description = `${chars} characters, ${words} word${words !== 1 ? 's' : ''}`
+ }
-#### Arch Linux
+ return {
+ "name": title,
+ "description": description,
+ "icon": "text-x-generic",
+ "isImage": false
+ }
+ }
-
-AUR
+ // Helper: Parse image metadata from preview string
+ function parseImageMeta(preview) {
+ const re = /\[\[\s*binary data\s+([\d\.]+\s*(?:KiB|MiB|GiB|B))\s+(\w+)\s+(\d+)x(\d+)\s*\]\]/i
+ const match = (preview || "").match(re)
-You can install Noctalia from the [AUR](https://aur.archlinux.org/packages/noctalia-shell). This method will install the shell system-wide.
+ if (!match) {
+ return null
+ }
-```bash
-paru -S noctalia-shell
-```
+ return {
+ "size": match[1],
+ "fmt": (match[2] || "").toUpperCase(),
+ "w": Number(match[3]),
+ "h": Number(match[4])
+ }
+ }
-If you want the latest development version directly from the git repository, you can use the `noctalia-shell-git` package:
-
-```bash
-paru -S noctalia-shell-git
-```
-This will always pull the most recent commit from the Noctalia repository. Note that it may be less stable than the release version.
-
-
-
-
-Manual Installation
-
-This method installs the shell to your local user configuration.
-
-Make sure you have Quickshell installed:
-```bash
-paru -S quickshell-git
-```
-
-Download and install Noctalia (latest release):
-```bash
-mkdir -p ~/.config/quickshell/noctalia-shell && curl -sL https://github.com/noctalia-dev/noctalia-shell/releases/latest/download/noctalia-latest.tar.gz | tar -xz --strip-components=1 -C ~/.config/quickshell/noctalia-shell
-```
-
-
-
-#### Nix
-
-
-Nix Installation
-
-You can run Noctalia directly using the `nix run` command:
-```bash
-nix run github:noctalia-dev/noctalia-shell
-```
-
-Alternatively, you can add it to your NixOS configuration or flake:
-
-**Step 1**: Add Quickshell and Noctalia flakes to your `flake.nix`:
-```nix
-{
- description = "Example Nix flake with Noctalia + Quickshell";
-
- inputs = {
- nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
-
- noctalia = {
- url = "github:noctalia-dev/noctalia-shell";
- inputs.nixpkgs.follows = "nixpkgs";
- };
-
- quickshell = {
- url = "github:outfoxxed/quickshell";
- inputs.nixpkgs.follows = "nixpkgs";
- inputs.quickshell.follows = "quickshell"
- };
- };
-
- outputs = { self, nixpkgs, noctalia, quickshell, ... }:
- {
- nixosConfigurations.my-host = nixpkgs.lib.nixosSystem {
- modules = [
- ./configuration.nix
- ];
- };
- };
+ // Public method to get image data for a clipboard item
+ // This can be called by the launcher when rendering
+ function getImageForItem(clipboardId) {
+ return ClipboardService.getImageData ? ClipboardService.getImageData(clipboardId) : null
+ }
}
-```
-
-**Step 2**: Add the packages to your `configuration.nix`:
-```nix
-{
- environment.systemPackages = with pkgs; [
- inputs.noctalia.packages.${system}.default
- inputs.quickshell.packages.${system}.default
- ];
-}
-```
-
-
-
-### Usage
-
-`noctalia-shell` offers many IPC calls for your convenience, so you can add them to your favorite keybinds or scripts.
-
-*If you're using the Flake installation on NixOS, replace `qs -c noctalia-shell` with `noctalia-shell`*
-
-*If you're using the manual install (`git clone...` and have it in `~/.config/quickshell/`) you can just use `qs ipc call...`*
-
-| Action | Command* |
-| --------------------------- | -------------------------------------------------------------- |
-| Start the Shell | `qs -c noctalia-shell` |
-| Toggle Application Launcher | `qs -c noctalia-shell ipc call launcher toggle` |
-| Toggle Side Panel | `qs -c noctalia-shell ipc call sidePanel toggle` |
-| Open Clipboard History | `qs -c noctalia-shell ipc call launcher clipboard` |
-| Open Calculator | `qs -c noctalia-shell ipc call launcher calculator` |
-| Increase Brightness | `qs -c noctalia-shell ipc call brightness increase` |
-| Decrease Brightness | `qs -c noctalia-shell ipc call brightness decrease` |
-| Increase Output Volume | `qs -c noctalia-shell ipc call volume increase` |
-| Decrease Output Volume | `qs -c noctalia-shell ipc call volume decrease` |
-| Toggle Mute Audio Output | `qs -c noctalia-shell ipc call volume muteOutput` |
-| Toggle Mute Audio Input | `qs -c noctalia-shell ipc call volume muteInput` |
-| Toggle Power Panel | `qs -c noctalia-shell ipc call powerPanel toggle` |
-| Toggle Idle Inhibitor | `qs -c noctalia-shell ipc call idleInhibitor toggle` |
-| Toggle Settings Window | `qs -c noctalia-shell ipc call settings toggle` |
-| Toggle Lock Screen | `qs -c noctalia-shell ipc call lockScreen toggle` |
-| Toggle Notification History | `qs -c noctalia-shell ipc call notifications toggleHistory` |
-| Toggle Notification DND | `qs -c noctalia-shell ipc call notifications toggleDND` |
-| Change Wallpaper | `qs -c noctalia-shell ipc call wallpaper set $path $monitor` |
-| Assign a Random Wallpaper | `qs -c noctalia-shell ipc call wallpaper random` |
-| Toggle Dark Mode | `qs -c noctalia-shell ipc call darkMode toggle` |
-| Set Dark Mode | `qs -c noctalia-shell ipc call darkMode setDark` |
-| Set Light Mode | `qs -c noctalia-shell ipc call darkMode setLight` |
-
-### Configuration
-
-Access settings through the side panel (top right button) to configure weather, wallpapers, screen recording, audio, network, and theme options.
-Configuration is usually stored in ~/.config/noctalia.
-
-### Application Launcher
-
-The launcher supports special commands for enhanced functionality:
-- `>calc` - Simple mathematical calculations
-- `>clip` - Clipboard history management
-
----
-
-
-Theme Colors
-
-| Color Role | Color | Description |
-| -------------------- | ----------- | -------------------------- |
-| Primary | `#c7a1d8` | Soft lavender purple |
-| On Primary | `#1a151f` | Dark text on primary |
-| Secondary | `#a984c4` | Muted lavender |
-| On Secondary | `#f3edf7` | Light text on secondary |
-| Tertiary | `#e0b7c9` | Warm pink-lavender |
-| On Tertiary | `#20161f` | Dark text on tertiary |
-| Surface | `#1c1822` | Dark purple-tinted surface |
-| On Surface | `#e9e4f0` | Light text on surface |
-| Surface Variant | `#262130` | Elevated surface variant |
-| On Surface Variant | `#a79ab0` | Muted text on surface variant |
-| Error | `#e9899d` | Soft rose red |
-| On Error | `#1e1418` | Dark text on error |
-| Outline | `#4d445a` | Purple-tinted outline |
-| Shadow | `#120f18` | Deep purple-tinted shadow |
-
-
-
----
-
-## Advanced Configuration
-
-### Recommended Compositor Settings
-
-For Niri:
-
-```
-debug {
- honor-xdg-activation-with-invalid-serial
-}
-
-window-rule {
- geometry-corner-radius 20
- clip-to-geometry true
-}
-
-layer-rule {
- match namespace="^quickshell-wallpaper$"
-}
-
-layer-rule {
- match namespace="^quickshell-overview$"
- place-within-backdrop true
-}
-```
-`honor-xdg-activation-with-invalid-serial` allows notification actions (like view etc) to work.
-
-
----
-
-
-## Development
-
-### Project Structure
-
-```
-Noctalia/
-├── shell.qml # Main shell entry point
-├── Modules/ # UI components
-│ ├── Bar/ # Status bar components
-│ ├── Dock/ # Application launcher
-│ ├── SidePanel/ # Quick access panel
-│ ├── SettingsPanel/ # Configuration interface
-│ └── ...
-├── Services/ # Backend services
-│ ├── CompositorService.qml
-│ ├── WorkspacesService.qml
-│ ├── AudioService.qml
-│ └── ...
-├── Widgets/ # Reusable UI components
-├── Commons/ # Shared utilities
-├── Assets/ # Static assets
-└── Bin/ # Utility scripts
-```
-
-### Contributing
-
-1. Follow the existing code style and patterns
-2. Use the modular architecture for new features
-3. Implement proper error handling and logging
-4. Test with both Hyprland and Niri compositors (if applicable)
-
-Contributions are welcome! Don't worry about being perfect - every contribution helps! Whether it's fixing a small bug, adding a new feature, or improving documentation, we welcome all contributions. Feel free to open an issue to discuss ideas or ask questions before diving in. For feature requests and ideas, you can also use our discussions page.
-
----
-
-## 💜 Credits
-
-A heartfelt thank you to our incredible community of [**contributors**](https://github.com/noctalia-dev/noctalia-shell/graphs/contributors). We are immensely grateful for your dedicated participation and the constructive feedback you've provided, which continue to shape and improve our project for everyone.
-
----
-
-## Acknowledgment
-
-Special thanks to the creators of [**Caelestia**](https://github.com/caelestia-dots/shell) and [**DankMaterialShell**](https://github.com/AvengeMedia/DankMaterialShell) for their inspirational designs and clever implementation techniques.
-
----
-
-#### Donation
-
-While all donations are greatly appreciated, they are completely voluntary.
-
-
-
-
-
-#### Thank you to everyone who supports the project 💜!
-* Gohma
-* PikaOS
-* DiscoCevapi
-
----
-
-## License
-
-This project is licensed under the terms of the [MIT License](./LICENSE).
From 107f6fdfce961560001453c34a114bfc8a37c075 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 16:31:19 +0200
Subject: [PATCH 066/118] README: Update breaking changes text
---
README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5212782..df3bea6 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,10 @@
> ⚠️ **BREAKING CHANGE:**
-> We transitioned from using Material Symbols to Bootstrap Icons, that means you will have to install the new font.
+> We're switching our icon set from Material Symbols to Bootstrap Icons!
+> - Arch Users: if using the AUR version, the font will be installed automatically. If installed manually you will need to install `ttf-bootstrap-icons` from the AUR.
+> - NixOS Users: I've attempted to add the new font to the flake, but it's untested. Feedback would be greatly appreciated!
+> - All Other Users: Please check your package manager for a Bootstrap Icons font. If it's not available, you may need to download it and copy it to `~/.local/share/fonts` or `/usr/share/fonts`.
---
A sleek and minimal desktop shell thoughtfully crafted for Wayland, built with Quickshell.
From 3d51f758f8baee3948ccabc7aec0cded61157996 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 17:03:28 +0200
Subject: [PATCH 067/118] README: small change
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index df3bea6..d8910cc 100644
--- a/README.md
+++ b/README.md
@@ -349,7 +349,7 @@ Special thanks to the creators of [**Caelestia**](https://github.com/caelestia-d
While all donations are greatly appreciated, they are completely voluntary.
-
+
From 144406ae0e86daab7a12184cfd362f43d8ccbfc1 Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 17:12:56 +0200
Subject: [PATCH 068/118] PowerProfile: create PowerProfileService, use it for
the BarWidget and PowerProfilesCard
---
Modules/Bar/Widgets/PowerProfile.qml | 22 +++----
Modules/SidePanel/Cards/PowerProfilesCard.qml | 29 +++++-----
Services/PowerProfileService.qml | 58 +++++++++++++++++++
3 files changed, 80 insertions(+), 29 deletions(-)
create mode 100644 Services/PowerProfileService.qml
diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml
index 6968413..eb1eff5 100644
--- a/Modules/Bar/Widgets/PowerProfile.qml
+++ b/Modules/Bar/Widgets/PowerProfile.qml
@@ -11,8 +11,7 @@ NIconButton {
property ShellScreen screen
property real scaling: 1.0
- property var powerProfiles: PowerProfiles
- readonly property bool hasPP: powerProfiles.hasPerformanceProfile
+ readonly property bool hasPP: PowerProfileService.available
sizeRatio: 0.8
visible: hasPP
@@ -20,34 +19,29 @@ NIconButton {
function profileIcon() {
if (!hasPP)
return "yin-yang"
- if (powerProfiles.profile === PowerProfile.Performance)
+ if (PowerProfileService.profile === PowerProfile.Performance)
return "speedometer2"
- if (powerProfiles.profile === PowerProfile.Balanced)
+ if (PowerProfileService.profile === PowerProfile.Balanced)
return "yin-yang"
- if (powerProfiles.profile === PowerProfile.PowerSaver)
+ if (PowerProfileService.profile === PowerProfile.PowerSaver)
return "leaf"
}
function profileName() {
if (!hasPP)
return "Unknown"
- if (powerProfiles.profile === PowerProfile.Performance)
+ if (PowerProfileService.profile === PowerProfile.Performance)
return "Performance"
- if (powerProfiles.profile === PowerProfile.Balanced)
+ if (PowerProfileService.profile === PowerProfile.Balanced)
return "Balanced"
- if (powerProfiles.profile === PowerProfile.PowerSaver)
+ if (PowerProfileService.profile === PowerProfile.PowerSaver)
return "Power Saver"
}
function changeProfile() {
if (!hasPP)
return
- if (powerProfiles.profile === PowerProfile.Performance)
- powerProfiles.profile = PowerProfile.PowerSaver
- else if (powerProfiles.profile === PowerProfile.Balanced)
- powerProfiles.profile = PowerProfile.Performance
- else if (powerProfiles.profile === PowerProfile.PowerSaver)
- powerProfiles.profile = PowerProfile.Balanced
+ PowerProfileService.cycleProfile()
}
icon: root.profileIcon()
diff --git a/Modules/SidePanel/Cards/PowerProfilesCard.qml b/Modules/SidePanel/Cards/PowerProfilesCard.qml
index 842d432..0d4ae21 100644
--- a/Modules/SidePanel/Cards/PowerProfilesCard.qml
+++ b/Modules/SidePanel/Cards/PowerProfilesCard.qml
@@ -13,9 +13,8 @@ NBox {
Layout.preferredWidth: 1
implicitHeight: powerRow.implicitHeight + Style.marginM * 2 * scaling
- // PowerProfiles service
- property var powerProfiles: PowerProfiles
- readonly property bool hasPP: powerProfiles.hasPerformanceProfile
+ // Centralized service
+ readonly property bool hasPP: PowerProfileService.available
property real spacing: 0
RowLayout {
@@ -32,12 +31,12 @@ NBox {
tooltipText: "Set performance power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
- colorBg: (enabled && powerProfiles.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
- colorFg: (enabled && powerProfiles.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary
+ colorBg: (enabled
+ && PowerProfileService.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
+ colorFg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary
onClicked: {
if (enabled) {
- powerProfiles.profile = PowerProfile.Performance
- ToastService.showNotice("Power Profile", "Performance")
+ PowerProfileService.setProfile(PowerProfile.Performance)
}
}
}
@@ -47,12 +46,12 @@ NBox {
tooltipText: "Set balanced power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
- colorBg: (enabled && powerProfiles.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
- colorFg: (enabled && powerProfiles.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary
+ colorBg: (enabled
+ && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
+ colorFg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary
onClicked: {
if (enabled) {
- powerProfiles.profile = PowerProfile.Balanced
- ToastService.showNotice("Power Profile", "Balanced")
+ PowerProfileService.setProfile(PowerProfile.Balanced)
}
}
}
@@ -62,12 +61,12 @@ NBox {
tooltipText: "Set eco power profile."
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
- colorBg: (enabled && powerProfiles.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant
- colorFg: (enabled && powerProfiles.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary
+ colorBg: (enabled
+ && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant
+ colorFg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary
onClicked: {
if (enabled) {
- powerProfiles.profile = PowerProfile.PowerSaver
- ToastService.showNotice("Power Profile", "Power Saver")
+ PowerProfileService.setProfile(PowerProfile.PowerSaver)
}
}
}
diff --git a/Services/PowerProfileService.qml b/Services/PowerProfileService.qml
new file mode 100644
index 0000000..950e4ee
--- /dev/null
+++ b/Services/PowerProfileService.qml
@@ -0,0 +1,58 @@
+pragma Singleton
+
+import QtQuick
+import Quickshell
+import Quickshell.Services.UPower
+import qs.Commons
+import qs.Services
+
+Singleton {
+ id: root
+
+ readonly property var powerProfiles: PowerProfiles
+ readonly property bool available: powerProfiles && powerProfiles.hasPerformanceProfile
+ property int profile: powerProfiles ? powerProfiles.profile : PowerProfile.Balanced
+
+ function profileName(p) {
+ const prof = (p !== undefined) ? p : profile
+ if (!available)
+ return "Unknown"
+ if (prof === PowerProfile.Performance)
+ return "Performance"
+ if (prof === PowerProfile.Balanced)
+ return "Balanced"
+ if (prof === PowerProfile.PowerSaver)
+ return "Power Saver"
+ return "Unknown"
+ }
+
+ function setProfile(p) {
+ if (!available)
+ return
+ try {
+ powerProfiles.profile = p
+ } catch (e) {
+ Logger.error("PowerProfileService", "Failed to set profile:", e)
+ }
+ }
+
+ function cycleProfile() {
+ if (!available)
+ return
+ const current = powerProfiles.profile
+ if (current === PowerProfile.Performance)
+ setProfile(PowerProfile.PowerSaver)
+ else if (current === PowerProfile.Balanced)
+ setProfile(PowerProfile.Performance)
+ else if (current === PowerProfile.PowerSaver)
+ setProfile(PowerProfile.Balanced)
+ }
+
+ Connections {
+ target: powerProfiles
+ function onProfileChanged() {
+ root.profile = powerProfiles.profile
+ ToastService.showNotice("Power Profile", root.profileName())
+ }
+ }
+}
From 5042d4d747de78bcd82018cf18c6a5cb2ce26dac Mon Sep 17 00:00:00 2001
From: Ly-sec
Date: Tue, 9 Sep 2025 17:41:16 +0200
Subject: [PATCH 069/118] BootstrapIcons: bundle font with noctalia, use
fontloader
---
Assets/Bootstrap/LICENSE | 21 ++++++++++++++++
Assets/Bootstrap/bootstrap-icons.woff2 | Bin 0 -> 134044 bytes
Commons/Bootstrap.qml | 33 +++++++++++++++++++++++++
Widgets/NIcon.qml | 2 +-
4 files changed, 55 insertions(+), 1 deletion(-)
create mode 100644 Assets/Bootstrap/LICENSE
create mode 100644 Assets/Bootstrap/bootstrap-icons.woff2
diff --git a/Assets/Bootstrap/LICENSE b/Assets/Bootstrap/LICENSE
new file mode 100644
index 0000000..7048e17
--- /dev/null
+++ b/Assets/Bootstrap/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2019-2024 The Bootstrap Authors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/Assets/Bootstrap/bootstrap-icons.woff2 b/Assets/Bootstrap/bootstrap-icons.woff2
new file mode 100644
index 0000000000000000000000000000000000000000..4d8c490e1ec1153df2a4d80d1342f1d8820e792d
GIT binary patch
literal 134044
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