Reworked the bar display colors/capsule, etc...

This commit is contained in:
quadbyte 2025-08-18 16:10:29 -04:00
parent 7d3dc9c815
commit 81eff0d234
22 changed files with 156 additions and 108 deletions

View file

@ -12,7 +12,7 @@
"mOnSurface": "#fbf1c7",
"mSurfaceVariant": "#3c3836",
"mOnSurfaceVariant": "#ebdbb2",
"mOutline": "#504945",
"mOutline": "#57514e",
"mShadow": "#282828"
},
"light": {

View file

@ -6,9 +6,10 @@ import Quickshell.Io
import qs.Commons
import qs.Services
/*
Although Noctalia is not strictly a Material Design project, it supports both a predefined
color scheme and dynamic color generation from the wallpaper (using Matugen).
Noctalia is not strictly a Material Design project, it supports both some predefined
color schemes and dynamic color generation from the wallpaper (using Matugen).
We ultimately decided to use a restricted set of colors that follows the
Material Design 3 naming convention.
@ -16,7 +17,6 @@ import qs.Services
NOTE: All color names are prefixed with 'm' (e.g., mPrimary) to prevent QML from
misinterpreting them as signals (e.g., the 'onPrimary' property name).
*/
Singleton {
id: root
@ -88,7 +88,7 @@ Singleton {
property color mSecondary: customColorsData.mSecondary
property color mOnSecondary: customColorsData.mOnSecondary
property color mTertiary: customColorsData.mTertiary
property color mOnTertiary: customColorsData.mOnTertiary
@ -97,7 +97,7 @@ Singleton {
property color mSurface: customColorsData.mSurface
property color mOnSurface: customColorsData.mOnSurface
property color mSurfaceVariant: customColorsData.mSurfaceVariant
property color mOnSurfaceVariant: customColorsData.mOnSurfaceVariant

View file

@ -61,6 +61,7 @@ Singleton {
// Dimensions
property int barHeight: 36
property int capsuleHeight: (barHeight * 0.73)
property int baseWidgetSize: 32
property int sliderWidth: 200

View file

@ -54,11 +54,9 @@ Row {
Rectangle {
// Let the Rectangle size itself based on its content (the Row)
width: row.width + Style.marginM * scaling * 2
height: Math.round(Style.barHeight * 0.75 * scaling)
height: Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
color: Color.mSurfaceVariant
border.color: Color.mOutline
border.width: Math.max(1, Math.round(Style.borderS * scaling))
anchors.verticalCenter: parent.verticalCenter

View file

@ -82,19 +82,8 @@ Variants {
anchors.verticalCenter: bar.verticalCenter
spacing: Style.marginS * scaling
// Screen Recording Indicator
NIconButton {
id: screenRecordingIndicator
icon: "videocam"
tooltipText: "Screen Recording Active"
sizeMultiplier: 0.8
showBorder: false
showFilled: ScreenRecorderService.isRecording
visible: ScreenRecorderService.isRecording
ScreenRecorderIndicator {
anchors.verticalCenter: parent.verticalCenter
onClicked: {
ScreenRecorderService.toggleRecording()
}
}
Tray {
@ -112,6 +101,7 @@ Variants {
Bluetooth {
anchors.verticalCenter: parent.verticalCenter
}
Battery {
anchors.verticalCenter: parent.verticalCenter
}
@ -139,33 +129,7 @@ Variants {
// demoPanel.isLoaded = !demoPanel.isLoaded
// }
// }
NIconButton {
id: sidePanelToggle
icon: "widgets"
tooltipText: "Open Side Panel"
sizeMultiplier: 0.8
showBorder: false
anchors.verticalCenter: parent.verticalCenter
onClicked: {
// Map this button's center to the screen and open the side panel below it
const localCenterX = width / 2
const localCenterY = height / 2
const globalPoint = mapToItem(null, localCenterX, localCenterY)
if (sidePanel.isLoaded) {
// Call hide() instead of directly setting isLoaded to false
if (sidePanel.item && sidePanel.item.hide) {
sidePanel.item.hide()
} else {
sidePanel.isLoaded = false
}
} else if (sidePanel.openAt) {
sidePanel.openAt(globalPoint.x, screen)
} else {
// Fallback: toggle if API unavailable
sidePanel.isLoaded = true
}
}
}
SidePanelToggle {}
}
}
}

View file

@ -10,7 +10,7 @@ NPill {
id: root
// Test mode
property bool testMode: false
property bool testMode: true
property int testPercent: 49
property bool testCharging: false
@ -52,9 +52,6 @@ NPill {
icon: root.batteryIcon()
text: Math.round(root.percent) + "%"
pillColor: Color.mSurfaceVariant
iconCircleColor: Color.mPrimary
iconTextColor: Color.mSurface
textColor: charging ? Color.mPrimary : Color.mOnSurface
tooltipText: {
let lines = []

View file

@ -12,7 +12,6 @@ NIconButton {
readonly property bool bluetoothEnabled: Settings.data.network.bluetoothEnabled
sizeMultiplier: 0.8
showBorder: false
visible: bluetoothEnabled
icon: {

View file

@ -4,25 +4,35 @@ import qs.Services
import qs.Widgets
// Clock Icon with attached calendar
NClock {
Rectangle {
id: root
width: clock.width + Style.marginM * 2 * scaling
height: Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
color: Color.mSurfaceVariant
NTooltip {
id: tooltip
text: Time.dateString
target: root
}
NClock {
id: clock
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
onEntered: {
if (!calendarPanel.isLoaded) {
tooltip.show()
NTooltip {
id: tooltip
text: Time.dateString
target: clock
}
onEntered: {
if (!calendarPanel.isLoaded) {
tooltip.show()
}
}
onExited: {
tooltip.hide()
}
onClicked: {
tooltip.hide()
calendarPanel.isLoaded = !calendarPanel.isLoaded
}
}
onExited: {
tooltip.hide()
}
onClicked: {
tooltip.hide()
calendarPanel.isLoaded = !calendarPanel.isLoaded
}
}

View file

@ -28,7 +28,7 @@ Row {
// Let the Rectangle size itself based on its content (the Row)
width: row.width + Style.marginM * scaling * 2
height: Math.round(Style.barHeight * 0.75 * scaling)
height: Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
color: Color.mSurfaceVariant
border.color: Color.mOutline

View file

@ -12,9 +12,13 @@ NIconButton {
visible: Settings.data.bar.showNotificationsHistory
sizeMultiplier: 0.8
showBorder: false
icon: "notifications"
tooltipText: "Notification History"
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
onClicked: {
if (!notificationHistoryPanel.active) {
notificationHistoryPanel.isLoaded = true

View file

@ -0,0 +1,18 @@
import qs.Commons
import qs.Services
import qs.Widgets
// Screen Recording Indicator
NIconButton {
id: screenRecordingIndicator
icon: "videocam"
tooltipText: "Screen Recording Active\nClick To Stop Recording"
sizeMultiplier: 0.8
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
visible: ScreenRecorderService.isRecording
anchors.verticalCenter: parent.verticalCenter
onClicked: {
ScreenRecorderService.toggleRecording()
}
}

View file

@ -0,0 +1,36 @@
import Quickshell
import qs.Commons
import qs.Widgets
NIconButton {
id: sidePanelToggle
icon: "widgets"
tooltipText: "Open Side Panel"
sizeMultiplier: 0.8
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
anchors.verticalCenter: parent.verticalCenter
onClicked: {
// Map this button's center to the screen and open the side panel below it
const localCenterX = width / 2
const localCenterY = height / 2
const globalPoint = mapToItem(null, localCenterX, localCenterY)
if (sidePanel.isLoaded) {
// Call hide() instead of directly setting isLoaded to false
if (sidePanel.item && sidePanel.item.hide) {
sidePanel.item.hide()
} else {
sidePanel.isLoaded = false
}
} else if (sidePanel.openAt) {
sidePanel.openAt(globalPoint.x, screen)
} else {
// Fallback: toggle if API unavailable
sidePanel.isLoaded = true
}
}
}

View file

@ -14,11 +14,9 @@ Row {
// Let the Rectangle size itself based on its content (the Row)
width: row.width + Style.marginM * scaling * 2
height: Math.round(Style.barHeight * 0.75 * scaling)
height: Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
color: Color.mSurfaceVariant
border.color: Color.mOutline
border.width: Math.max(1, Math.round(Style.borderS * scaling))
anchors.verticalCenter: parent.verticalCenter

View file

@ -9,18 +9,24 @@ import qs.Commons
import qs.Services
import qs.Widgets
Item {
Rectangle {
readonly property real itemSize: 24 * scaling
visible: Settings.data.bar.showTray
width: tray.width
height: itemSize
width: tray.width + Style.marginM * scaling * 2
height: Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
color: Color.mSurfaceVariant
Layout.alignment: Qt.AlignVCenter
Row {
id: tray
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
spacing: Style.marginS * scaling
Layout.alignment: Qt.AlignVCenter
Repeater {
id: repeater

View file

@ -11,9 +11,15 @@ NIconButton {
id: root
readonly property bool wifiEnabled: Settings.data.network.wifiEnabled
sizeMultiplier: 0.8
showBorder: false
visible: wifiEnabled
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
icon: {
let connected = false
let signalStrength = 0

View file

@ -116,11 +116,9 @@ Item {
id: workspaceBackground
width: parent.width - Style.marginS * scaling * 2
height: Math.round(Style.barHeight * 0.75 * scaling)
height: Math.round(Style.capsuleHeight * scaling)
radius: Math.round(Style.radiusM * scaling)
color: Color.mSurfaceVariant
border.color: Color.mOutline
border.width: Math.max(1, Math.round(Style.borderS * scaling))
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter

View file

@ -187,7 +187,6 @@ Variants {
icon: "close"
tooltipText: "Close"
sizeMultiplier: 0.8
showBorder: false
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Style.marginS * scaling

View file

@ -31,8 +31,8 @@ NBox {
tooltipText: "Set Performance Power Profile"
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
showFilled: enabled && powerProfiles.profile === PowerProfile.Performance
showBorder: !enabled || powerProfiles.profile !== PowerProfile.Performance
colorBg: (enabled && powerProfiles.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
colorFg: (enabled && powerProfiles.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary
onClicked: {
if (enabled) {
powerProfiles.profile = PowerProfile.Performance
@ -45,8 +45,8 @@ NBox {
tooltipText: "Set Balanced Power Profile"
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
showFilled: enabled && powerProfiles.profile === PowerProfile.Balanced
showBorder: !enabled || powerProfiles.profile !== PowerProfile.Balanced
colorBg: (enabled && powerProfiles.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
colorFg: (enabled && powerProfiles.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary
onClicked: {
if (enabled) {
powerProfiles.profile = PowerProfile.Balanced
@ -59,8 +59,8 @@ NBox {
tooltipText: "Set Eco Power Profile"
enabled: hasPP
opacity: enabled ? Style.opacityFull : Style.opacityMedium
showFilled: enabled && powerProfiles.profile === PowerProfile.PowerSaver
showBorder: !enabled || powerProfiles.profile !== PowerProfile.PowerSaver
colorBg: (enabled && powerProfiles.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant
colorFg: (enabled && powerProfiles.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary
onClicked: {
if (enabled) {
powerProfiles.profile = PowerProfile.PowerSaver

View file

@ -24,7 +24,8 @@ NBox {
NIconButton {
icon: "videocam"
tooltipText: ScreenRecorderService.isRecording ? "Stop Screen Recording" : "Start Screen Recording"
showFilled: ScreenRecorderService.isRecording
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
onClicked: {
ScreenRecorderService.toggleRecording()
}

View file

@ -13,6 +13,9 @@ NPanel {
id: powerMenu
visible: false
property var entriesCount: 5
property var entryHeight: Style.baseWidgetSize * scaling
// Anchors will be set by the parent component
function show() {
visible = true
@ -24,7 +27,7 @@ NPanel {
Rectangle {
width: 160 * scaling
height: 220 * scaling
height: (entryHeight * entriesCount) + (Style.marginS * entriesCount * scaling)
radius: Style.radiusM * scaling
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
@ -55,7 +58,7 @@ NPanel {
// Lock
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: Style.barHeight * scaling
Layout.preferredHeight: entryHeight
radius: Style.radiusS * scaling
color: lockButtonArea.containsMouse ? Color.mTertiary : Color.transparent
@ -80,9 +83,10 @@ NPanel {
anchors.verticalCenterOffset: 1 * scaling
}
Text {
NText {
text: "Lock Screen"
color: lockButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface
font.pointSize: Style.fontSizeS * scaling
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
@ -109,7 +113,7 @@ NPanel {
// Suspend
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: Style.barHeight * scaling
Layout.preferredHeight: entryHeight
radius: Style.radiusS * scaling
color: suspendButtonArea.containsMouse ? Color.mTertiary : Color.transparent
@ -134,9 +138,10 @@ NPanel {
anchors.verticalCenterOffset: 1 * scaling
}
Text {
NText {
text: "Suspend"
color: suspendButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface
font.pointSize: Style.fontSizeS * scaling
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
@ -161,7 +166,7 @@ NPanel {
// Reboot
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: Style.barHeight * scaling
Layout.preferredHeight: entryHeight
radius: Style.radiusS * scaling
color: rebootButtonArea.containsMouse ? Color.mTertiary : Color.transparent
@ -186,9 +191,10 @@ NPanel {
anchors.verticalCenterOffset: 1 * scaling
}
Text {
NText {
text: "Reboot"
color: rebootButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface
font.pointSize: Style.fontSizeS * scaling
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
@ -213,7 +219,7 @@ NPanel {
// Logout
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: Style.barHeight * scaling
Layout.preferredHeight: entryHeight
radius: Style.radiusS * scaling
color: logoutButtonArea.containsMouse ? Color.mTertiary : Color.transparent
@ -238,9 +244,10 @@ NPanel {
anchors.verticalCenterOffset: 1 * scaling
}
Text {
NText {
text: "Logout"
color: logoutButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface
font.pointSize: Style.fontSizeS * scaling
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling
@ -265,7 +272,7 @@ NPanel {
// Shutdown
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: Style.barHeight * scaling
Layout.preferredHeight: entryHeight
radius: Style.radiusS * scaling
color: shutdownButtonArea.containsMouse ? Color.mTertiary : Color.transparent
@ -290,9 +297,10 @@ NPanel {
anchors.verticalCenterOffset: 1 * scaling
}
Text {
NText {
text: "Shutdown"
color: shutdownButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface
font.pointSize: Style.fontSizeS * scaling
verticalAlignment: Text.AlignVCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 1 * scaling

View file

@ -12,12 +12,17 @@ Rectangle {
property real size: Style.baseWidgetSize * sizeMultiplier * scaling
property string icon
property string tooltipText
property bool showBorder: true
property bool showFilled: false
property bool enabled: true
property bool hovering: false
property real fontPointSize: Style.fontSizeM
property color colorBg: Color.mSurfaceVariant
property color colorFg: Color.mPrimary
property color colorBgHover: Color.mPrimary
property color colorFgHover: Color.mOnPrimary
property color colorBorder: Color.mOutline
property color colorBorderHover: Color.mOutline
signal entered
signal exited
signal clicked
@ -25,9 +30,9 @@ Rectangle {
implicitWidth: size
implicitHeight: size
color: (root.hovering || showFilled) ? Color.mPrimary : Color.transparent
color: root.hovering ? colorBgHover : colorBg
radius: width * 0.5
border.color: showBorder ? Color.mPrimary : Color.transparent
border.color: root.hovering ? colorBorderHover : colorBorder
border.width: Math.max(1, Style.borderS * scaling)
NIcon {
@ -37,7 +42,7 @@ Rectangle {
anchors.verticalCenterOffset: 0
text: root.icon
font.pointSize: root.fontPointSize * scaling
color: (root.hovering || showFilled) ? Color.mOnPrimary : showBorder ? Color.mPrimary : Color.mOnSurface
color: root.hovering ? colorFgHover : colorFg
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
opacity: root.enabled ? Style.opacityFull : Style.opacityMedium

View file

@ -80,7 +80,7 @@ Item {
width: iconSize
height: iconSize
radius: width * 0.5
color: showPill ? iconCircleColor : Color.transparent
color: showPill ? iconCircleColor : Color.mSurfaceVariant
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
@ -94,7 +94,7 @@ Item {
NIcon {
text: root.icon
font.pointSize: Style.fontSizeM * scaling
color: showPill ? iconTextColor : collapsedIconColor
color: showPill ? iconTextColor : Color.mOnSurface
anchors.centerIn: parent
}
}