feat(nosignal): Nerd Font icon remap — bar + popouts
Route the redesign's icons through JetBrains Mono Nerd Font instead of Material Symbols, for visual consistency with the JetBrains Mono text. - services/Glyphs.qml: Material-Symbol-name -> Nerd Font (Font Awesome range) codepoint map (via String.fromCharCode), covering bar/panel icons + the dynamic Icons.getX() returns; get() falls back to a "?" glyph. - components/NsIcon.qml: reactive icon component (input `icon` = name -> mapped glyph), so dynamic icons (volume/battery/play-pause) stay live. Uses the "Mono" NF variant so glyphs center in a fixed cell. - Converted all MaterialIcon usages in NsBar + the 9 panels to NsIcon. caelestia core (nexus/launcher/osd/lock) still uses Material Symbols — no breakage (mixed), to be converted next with an expanded Glyphs map. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
36f6f5a157
commit
6a933aa260
11 changed files with 177 additions and 42 deletions
27
components/NsIcon.qml
Normal file
27
components/NsIcon.qml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
// NoSignal icon: renders a Nerd Font (JetBrainsMono NF) glyph from a Material
|
||||||
|
// Symbol name via the Glyphs map. Drop-in for MaterialIcon but the input is
|
||||||
|
// `icon` (the name) instead of `text`, so dynamic bindings stay reactive.
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string icon: ""
|
||||||
|
property int size: 16
|
||||||
|
property real fill: 0 // API parity with MaterialIcon (unused for Nerd Font)
|
||||||
|
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
textFormat: Text.PlainText
|
||||||
|
text: Glyphs.get(root.icon)
|
||||||
|
// "Mono" variant centers each icon glyph in a fixed cell (the plain NF
|
||||||
|
// variant uses a wide advance, which left/right-shifts centered icons).
|
||||||
|
font.family: "JetBrainsMono Nerd Font Mono"
|
||||||
|
font.pixelSize: root.size
|
||||||
|
color: Theme.text
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
@ -80,8 +80,8 @@ Variants {
|
||||||
active: NsShell.open === "overview"
|
active: NsShell.open === "overview"
|
||||||
onTriggered: NsShell.toggle("overview", mapToItem(null, width / 2, 0).x)
|
onTriggered: NsShell.toggle("overview", mapToItem(null, width / 2, 0).x)
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: "desktop_windows"
|
icon: "desktop_windows"
|
||||||
color: titlePill.active ? Theme.accent : Theme.textMuted
|
color: titlePill.active ? Theme.accent : Theme.textMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,8 +123,8 @@ Variants {
|
||||||
active: NsShell.open === "quicksettings"
|
active: NsShell.open === "quicksettings"
|
||||||
onTriggered: NsShell.toggle("quicksettings", mapToItem(null, width / 2, 0).x)
|
onTriggered: NsShell.toggle("quicksettings", mapToItem(null, width / 2, 0).x)
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: Players.active?.isPlaying ? "pause" : "music_note"
|
icon: Players.active?.isPlaying ? "pause" : "music_note"
|
||||||
color: mediaPill.active ? Theme.accent : Theme.green
|
color: mediaPill.active ? Theme.accent : Theme.green
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,8 +152,8 @@ Variants {
|
||||||
active: NsShell.open === "notifications"
|
active: NsShell.open === "notifications"
|
||||||
onTriggered: NsShell.toggle("notifications", mapToItem(null, width / 2, 0).x)
|
onTriggered: NsShell.toggle("notifications", mapToItem(null, width / 2, 0).x)
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: Notifs.notClosed.length > 0 ? "notifications" : "notifications_none"
|
icon: Notifs.notClosed.length > 0 ? "notifications" : "notifications_none"
|
||||||
color: bellPill.active ? Theme.accent : Theme.text
|
color: bellPill.active ? Theme.accent : Theme.text
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|
@ -203,8 +203,8 @@ Variants {
|
||||||
active: NsShell.open === "quicksettings"
|
active: NsShell.open === "quicksettings"
|
||||||
onTriggered: NsShell.toggle("quicksettings", mapToItem(null, width / 2, 0).x)
|
onTriggered: NsShell.toggle("quicksettings", mapToItem(null, width / 2, 0).x)
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: batteryPill.laptop ? Icons.getBatteryIcon(UPower.displayDevice.percentage, [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state)) : "tune"
|
icon: batteryPill.laptop ? Icons.getBatteryIcon(UPower.displayDevice.percentage, [UPowerDeviceState.Charging, UPowerDeviceState.FullyCharged, UPowerDeviceState.PendingCharge].includes(UPower.displayDevice.state)) : "tune"
|
||||||
color: batteryPill.active ? Theme.accent : !batteryPill.laptop || !UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? Theme.text : Theme.danger
|
color: batteryPill.active ? Theme.accent : !batteryPill.laptop || !UPower.onBattery || UPower.displayDevice.percentage > 0.2 ? Theme.text : Theme.danger
|
||||||
fill: 1
|
fill: 1
|
||||||
}
|
}
|
||||||
|
|
@ -248,8 +248,8 @@ Variants {
|
||||||
active: NsShell.open === panel
|
active: NsShell.open === panel
|
||||||
onTriggered: NsShell.toggle(panel, mapToItem(null, width / 2, 0).x)
|
onTriggered: NsShell.toggle(panel, mapToItem(null, width / 2, 0).x)
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: p.icon
|
icon: p.icon
|
||||||
color: p.active ? Theme.accent : p.iconColour
|
color: p.active ? Theme.accent : p.iconColour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ NsPanel {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: "speaker"
|
icon: "speaker"
|
||||||
color: Theme.textMuted
|
color: Theme.textMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,8 +34,8 @@ NsPanel {
|
||||||
font.pixelSize: Theme.font.bodySmall
|
font.pixelSize: Theme.font.bodySmall
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: "expand_more"
|
icon: "expand_more"
|
||||||
color: Theme.textFaint
|
color: Theme.textFaint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,8 +114,8 @@ NsPanel {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: s.icon
|
icon: s.icon
|
||||||
color: Theme.textMuted
|
color: Theme.textMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,9 +72,9 @@ NsPanel {
|
||||||
radius: 0
|
radius: 0
|
||||||
color: row.connected ? Theme.accentSoft : Theme.fillSubtle
|
color: row.connected ? Theme.accentSoft : Theme.fillSubtle
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: Icons.getBluetoothIcon(row.modelData?.icon ?? "")
|
icon: Icons.getBluetoothIcon(row.modelData?.icon ?? "")
|
||||||
color: row.connected ? Theme.accent : Theme.text
|
color: row.connected ? Theme.accent : Theme.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -157,9 +157,9 @@ NsPanel {
|
||||||
radius: Theme.radius.button
|
radius: Theme.radius.button
|
||||||
color: ma.containsMouse ? Theme.hover : "transparent"
|
color: ma.containsMouse ? Theme.hover : "transparent"
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: parent.icon
|
icon: parent.icon
|
||||||
color: Theme.textMuted
|
color: Theme.textMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ NsPanel {
|
||||||
anchors.rightMargin: 10
|
anchors.rightMargin: 10
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: Icons.getNetworkIcon(row.modelData?.strength ?? 0)
|
icon: Icons.getNetworkIcon(row.modelData?.strength ?? 0)
|
||||||
color: row.connected ? Theme.accent : Theme.text
|
color: row.connected ? Theme.accent : Theme.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,9 +89,9 @@ NsPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
visible: row.modelData?.isSecure ?? false
|
visible: row.modelData?.isSecure ?? false
|
||||||
text: "lock"
|
icon: "lock"
|
||||||
color: Theme.textFaint
|
color: Theme.textFaint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,9 @@ NsPanel {
|
||||||
radius: 13
|
radius: 13
|
||||||
color: Notifs.dnd ? Theme.accentSoft : dndMa.containsMouse ? Theme.hover : "transparent"
|
color: Notifs.dnd ? Theme.accentSoft : dndMa.containsMouse ? Theme.hover : "transparent"
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: Notifs.dnd ? "do_not_disturb_on" : "dark_mode"
|
icon: Notifs.dnd ? "do_not_disturb_on" : "dark_mode"
|
||||||
color: Notifs.dnd ? Theme.accent : Theme.textMuted
|
color: Notifs.dnd ? Theme.accent : Theme.textMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,9 +113,9 @@ NsPanel {
|
||||||
radius: 0
|
radius: 0
|
||||||
color: Theme.accentSoft
|
color: Theme.accentSoft
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: Icons.getNotifIcon(card.modelData?.summary ?? "", card.modelData?.urgency ?? 1)
|
icon: Icons.getNotifIcon(card.modelData?.summary ?? "", card.modelData?.urgency ?? 1)
|
||||||
color: Theme.accent
|
color: Theme.accent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,10 @@ NsPanel {
|
||||||
border.width: cell.active ? 2 : 1
|
border.width: cell.active ? 2 : 1
|
||||||
border.color: cell.active ? Theme.accent : Theme.panelBorder
|
border.color: cell.active ? Theme.accent : Theme.panelBorder
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: cell.occupied
|
visible: cell.occupied
|
||||||
text: "web_asset"
|
icon: "web_asset"
|
||||||
color: Theme.textFaint
|
color: Theme.textFaint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,9 +117,9 @@ Item {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: tile.icon
|
icon: tile.icon
|
||||||
color: tile.danger ? Theme.danger : Theme.text
|
color: tile.danger ? Theme.danger : Theme.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,9 +78,9 @@ NsPanel {
|
||||||
radius: 17
|
radius: 17
|
||||||
color: pwrMa.containsMouse ? Theme.accentSoft : Theme.fillSubtle
|
color: pwrMa.containsMouse ? Theme.accentSoft : Theme.fillSubtle
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "power_settings_new"
|
icon: "power_settings_new"
|
||||||
color: Theme.danger
|
color: Theme.danger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,9 +189,9 @@ NsPanel {
|
||||||
color: Theme.blue
|
color: Theme.blue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "music_note"
|
icon: "music_note"
|
||||||
color: Theme.onAccent
|
color: Theme.onAccent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -267,9 +267,9 @@ NsPanel {
|
||||||
radius: 15
|
radius: 15
|
||||||
color: tile.on ? Theme.accent : Qt.rgba(1, 1, 1, 0.06)
|
color: tile.on ? Theme.accent : Qt.rgba(1, 1, 1, 0.06)
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: tile.icon
|
icon: tile.icon
|
||||||
color: tile.on ? Theme.onAccent : Theme.text
|
color: tile.on ? Theme.onAccent : Theme.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -309,8 +309,8 @@ NsPanel {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
text: s.icon
|
icon: s.icon
|
||||||
color: Theme.textMuted
|
color: Theme.textMuted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -365,9 +365,9 @@ NsPanel {
|
||||||
radius: 14
|
radius: 14
|
||||||
color: mbm.containsMouse ? Theme.hover : "transparent"
|
color: mbm.containsMouse ? Theme.hover : "transparent"
|
||||||
|
|
||||||
MaterialIcon {
|
NsIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: parent.icon
|
icon: parent.icon
|
||||||
color: Theme.text
|
color: Theme.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
108
services/Glyphs.qml
Normal file
108
services/Glyphs.qml
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
// NoSignal icon remap: Material Symbol name -> Nerd Font (JetBrainsMono NF)
|
||||||
|
// codepoint (Font Awesome range), via String.fromCharCode so the source stays
|
||||||
|
// pure ASCII. Used by components/NsIcon. Covers bar/panel icons + the dynamic
|
||||||
|
// Icons.getX() returns. get() falls back to a question glyph so anything
|
||||||
|
// unmapped is visible (easy to spot + add a mapping).
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
function cp(code: int): string {
|
||||||
|
return String.fromCharCode(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property var map: {
|
||||||
|
// network (no per-strength glyphs in FA range -> all wifi)
|
||||||
|
"wifi": root.cp(0xf1eb),
|
||||||
|
"wifi_off": root.cp(0xf1eb),
|
||||||
|
"network_wifi": root.cp(0xf1eb),
|
||||||
|
"network_wifi_1_bar": root.cp(0xf1eb),
|
||||||
|
"network_wifi_2_bar": root.cp(0xf1eb),
|
||||||
|
"network_wifi_3_bar": root.cp(0xf1eb),
|
||||||
|
"network_wifi_locked": root.cp(0xf023),
|
||||||
|
"network_wifi_1_bar_locked": root.cp(0xf023),
|
||||||
|
"network_wifi_2_bar_locked": root.cp(0xf023),
|
||||||
|
"network_wifi_3_bar_locked": root.cp(0xf023),
|
||||||
|
"signal_wifi_0_bar": root.cp(0xf1eb),
|
||||||
|
"cable": root.cp(0xf0e8),
|
||||||
|
// bluetooth
|
||||||
|
"bluetooth": root.cp(0xf293),
|
||||||
|
"bluetooth_connected": root.cp(0xf293),
|
||||||
|
"bluetooth_disabled": root.cp(0xf294),
|
||||||
|
// audio
|
||||||
|
"volume_up": root.cp(0xf028),
|
||||||
|
"volume_down": root.cp(0xf027),
|
||||||
|
"volume_mute": root.cp(0xf6a9),
|
||||||
|
"volume_off": root.cp(0xf026),
|
||||||
|
"no_sound": root.cp(0xf026),
|
||||||
|
"speaker": root.cp(0xf028),
|
||||||
|
"mic": root.cp(0xf130),
|
||||||
|
"mic_off": root.cp(0xf131),
|
||||||
|
"graphic_eq": root.cp(0xf001),
|
||||||
|
"headphones": root.cp(0xf025),
|
||||||
|
"headset": root.cp(0xf025),
|
||||||
|
"audio": root.cp(0xf025),
|
||||||
|
"keyboard": root.cp(0xf11c),
|
||||||
|
"mouse": root.cp(0xf109),
|
||||||
|
"phone": root.cp(0xf095),
|
||||||
|
"smartphone": root.cp(0xf10b),
|
||||||
|
// battery
|
||||||
|
"battery_full": root.cp(0xf240),
|
||||||
|
"battery_charging_full": root.cp(0xf240),
|
||||||
|
"battery": root.cp(0xf242),
|
||||||
|
"tune": root.cp(0xf1de),
|
||||||
|
// notifications / toggles
|
||||||
|
"notifications": root.cp(0xf0f3),
|
||||||
|
"notifications_none": root.cp(0xf0a2),
|
||||||
|
"do_not_disturb_on": root.cp(0xf05e),
|
||||||
|
"dark_mode": root.cp(0xf186),
|
||||||
|
"nightlight": root.cp(0xf186),
|
||||||
|
"bedtime": root.cp(0xf186),
|
||||||
|
"airplanemode_active": root.cp(0xf072),
|
||||||
|
"vpn_key": root.cp(0xf084),
|
||||||
|
// media
|
||||||
|
"music_note": root.cp(0xf001),
|
||||||
|
"music": root.cp(0xf001),
|
||||||
|
"pause": root.cp(0xf04c),
|
||||||
|
"play_arrow": root.cp(0xf04b),
|
||||||
|
"skip_next": root.cp(0xf051),
|
||||||
|
"skip_previous": root.cp(0xf048),
|
||||||
|
// power / session
|
||||||
|
"power_settings_new": root.cp(0xf011),
|
||||||
|
"power": root.cp(0xf011),
|
||||||
|
"lock": root.cp(0xf023),
|
||||||
|
"logout": root.cp(0xf08b),
|
||||||
|
"restart_alt": root.cp(0xf021),
|
||||||
|
"reboot": root.cp(0xf021),
|
||||||
|
// chrome / nav
|
||||||
|
"desktop_windows": root.cp(0xf108),
|
||||||
|
"web_asset": root.cp(0xf2d0),
|
||||||
|
"widgets": root.cp(0xf009),
|
||||||
|
"settings": root.cp(0xf013),
|
||||||
|
"expand_more": root.cp(0xf078),
|
||||||
|
"chevron_left": root.cp(0xf053),
|
||||||
|
"chevron_right": root.cp(0xf054),
|
||||||
|
"calendar_month": root.cp(0xf073),
|
||||||
|
"schedule": root.cp(0xf017),
|
||||||
|
"brightness_6": root.cp(0xf185),
|
||||||
|
// notif category icons
|
||||||
|
"chat": root.cp(0xf075),
|
||||||
|
"file": root.cp(0xf15b),
|
||||||
|
"folder_copy": root.cp(0xf07b),
|
||||||
|
"download": root.cp(0xf019),
|
||||||
|
"person": root.cp(0xf007),
|
||||||
|
"profile": root.cp(0xf007),
|
||||||
|
"installed": root.cp(0xf058),
|
||||||
|
"deployed_code_alert": root.cp(0xf071)
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(name: string): string {
|
||||||
|
return root.map[name] ?? root.cp(0xf128);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue