mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-06 04:29:34 +02:00
Themes now drive typography the same way they drive colors: one [font] base-size in shell.toml is the rem root, and every Style.font.<token> (caption, bodySmall, body, subtitle, title, heading, display, displayLarge, iconSmall, icon, iconLarge) derives from it via a fixed multiplier. Themes can also pin individual tokens for stylistic emphasis. base-size is clamped 11..13 until row-height tokens exist. Bar dimensions move to the same singleton: [bar] size-horizontal / size-vertical replace the hardcoded 26/28 in Bar.qml, exposed as Style.bar.sizeHorizontal / sizeVertical. Style.qml also resolves the fontconfig 'monospace' alias via fc-match and exposes Style.font.resolvedFamily so panels can display the concrete family. Watches ~/.config/fontconfig/fonts.conf so it tracks 'omarchy font set <name>'. The qs.Ui kit (PillButton, Dropdown, Toggle, TextField, etc.) and every first-party plugin (bar widgets, settings, menu, clipboard, emoji, polkit, notifications, osd, image-picker, dev-gallery) now bind to Style.font.* instead of pixel literals. Only three deliberate display-scale outliers remain: the notification empty-state glyph and the weather flyout's hero temperature pair, all commented. Background plugin's applyTheme IPC fast-path also pushes shell.toml to Style so theme swaps update typography and bar size without waiting for inotify debounce. Dev gallery (omarchy dev ui-preview) now ships a Typography section that renders the full scale and theme tokens live, and its summon command is fixed (omarchy-shell-ipc -> omarchy-shell).
144 lines
4.4 KiB
QML
144 lines
4.4 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import Quickshell.Wayland
|
|
import qs.Commons
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property string omarchyPath: ""
|
|
property var shell: null
|
|
property var manifest: null
|
|
|
|
property bool opened: false
|
|
property string icon: ""
|
|
property string message: ""
|
|
property int value: 0
|
|
property int maxValue: 100
|
|
property bool hasProgress: true
|
|
|
|
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)) }
|
|
|
|
function iconFor(name, percent) {
|
|
var n = String(name || "").toLowerCase()
|
|
if (n === "volume-muted" || n === "volume-mute" || n === "muted" || n === "mute") return ""
|
|
if (n === "volume-low") return ""
|
|
if (n === "volume-medium") return ""
|
|
if (n === "volume-high" || n === "volume") return ""
|
|
if (n === "microphone-muted" || n === "microphone-off" || n === "mic-muted" || n === "mic-off") return ""
|
|
if (n === "microphone" || n === "mic") return ""
|
|
if (n === "keyboard") return ""
|
|
if (n === "brightness" || n === "display") return ""
|
|
if (n === "touchpad") return ""
|
|
if (n === "touch" || n === "touchscreen") return ""
|
|
if (n === "media" || n === "player") return ""
|
|
if (percent <= 0) return ""
|
|
if (percent <= 33) return ""
|
|
if (percent <= 66) return ""
|
|
return ""
|
|
}
|
|
|
|
function show(iconName, rawMessage, rawValue, rawMax, rawProgressText) {
|
|
maxValue = Math.max(1, parseInt(rawMax || "100", 10))
|
|
var parsed = parseInt(rawValue || "0", 10)
|
|
hasProgress = rawValue !== "" && !isNaN(parsed) && rawMessage === ""
|
|
value = hasProgress ? clamp(parsed, 0, maxValue) : 0
|
|
message = String(rawMessage || (hasProgress ? (rawProgressText || Math.round(value * 100 / maxValue) + "%") : ""))
|
|
icon = iconFor(iconName, hasProgress ? Math.round(value * 100 / maxValue) : -1)
|
|
opened = true
|
|
hideTimer.restart()
|
|
}
|
|
|
|
function open(payloadJson) {
|
|
try {
|
|
var p = JSON.parse(payloadJson || "{}")
|
|
show(p.icon || "", p.message || "", p.value === undefined ? "" : String(p.value), p.max === undefined ? "100" : String(p.max), p.progressText || "")
|
|
} catch (e) {}
|
|
}
|
|
|
|
function close() { opened = false }
|
|
|
|
Timer {
|
|
id: hideTimer
|
|
interval: 1200
|
|
onTriggered: root.opened = false
|
|
}
|
|
|
|
IpcHandler {
|
|
target: "osd"
|
|
function show(payloadJson: string): string {
|
|
root.open(payloadJson)
|
|
return "ok"
|
|
}
|
|
function close(): string { root.close(); return "ok" }
|
|
function state(): string { return root.opened ? "open" : "closed" }
|
|
function ping(): string { return "ok" }
|
|
}
|
|
|
|
PanelWindow {
|
|
id: panel
|
|
visible: root.opened
|
|
anchors { top: true; bottom: true; left: true; right: true }
|
|
color: "transparent"
|
|
WlrLayershell.namespace: "omarchy-osd"
|
|
WlrLayershell.layer: WlrLayer.Overlay
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
|
exclusionMode: ExclusionMode.Ignore
|
|
|
|
Rectangle {
|
|
id: card
|
|
width: 269
|
|
height: 68
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 67
|
|
color: Color.alpha(Color.background, 0.97)
|
|
border.color: Color.foreground
|
|
border.width: 2
|
|
radius: Style.cornerRadius
|
|
opacity: root.opened ? 1 : 0
|
|
|
|
Row {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 16
|
|
anchors.rightMargin: 16
|
|
spacing: 16
|
|
Text {
|
|
width: 28
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: root.icon
|
|
font.family: Style.font.family
|
|
font.pixelSize: Style.font.displayLarge
|
|
color: Color.foreground
|
|
}
|
|
Rectangle {
|
|
visible: root.hasProgress
|
|
width: visible ? 142 : 0
|
|
height: 6
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: Color.alpha(Color.foreground, 0.45)
|
|
Rectangle {
|
|
height: parent.height
|
|
width: parent.width * (root.hasProgress ? root.value / root.maxValue : 0)
|
|
color: Color.accent
|
|
}
|
|
}
|
|
Text {
|
|
width: root.hasProgress ? 41 : 190
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: root.message
|
|
font.family: Style.font.family
|
|
font.bold: true
|
|
font.pixelSize: Style.font.title
|
|
color: Color.foreground
|
|
elide: Text.ElideRight
|
|
maximumLineCount: 1
|
|
clip: true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|