| 1 | pragma Singleton |
| 2 | import QtQuick |
| 3 | import Quickshell |
| 4 | import Quickshell.Io |
| 5 | |
| 6 | // The design system: Nothing OS's shapes, dots and type (after glyph-rice) in Android Material You colours from matugen |
| 7 | // (~/.cache/matugen/aurora.json, written by Wall.apply/recolor, hot-reloaded), plus fonts, motion and all icon glyphs. |
| 8 | Singleton { |
| 9 | id: root |
| 10 | |
| 11 | // ---- fonts ---- |
| 12 | readonly property string dot: "Doto" // numbers and short words (Num), never under 26px |
| 13 | readonly property string ui: "Space Grotesk" // UI text: titles DemiBold, body Regular, greeting Light |
| 14 | readonly property string mono: "Space Mono" // caps labels (Lb) |
| 15 | readonly property string nf: "JetBrainsMono Nerd Font" // icons only (Icon) |
| 16 | |
| 17 | // ---- knobs (persisted in ~/.config/aurora/settings.json, edited in the settings app) ---- |
| 18 | readonly property real panelAlpha: Settings.panelAlpha |
| 19 | readonly property bool barVertical: Settings.barLayout === "vertical" // docked at the left edge instead of the top |
| 20 | readonly property int barSize: barVertical ? Math.max(48, Settings.barWidth) : Math.max(32, Settings.barSize) // its thickness |
| 21 | readonly property bool barFloat: Settings.barFloat // a floating pill instead of a strip along the edge |
| 22 | readonly property int barGap: barFloat ? 14 : 0 // the pill's distance from the screen edges (glyph-rice) |
| 23 | // ... and from the windows: glyph's 14 too, there it is Hyprland's gaps_out; here only the part gaps_out doesn't cover |
| 24 | readonly property int barInner: barFloat ? Math.max(0, barGap - (HyprConf.values["general:gaps_out"] || 0)) : 0 |
| 25 | readonly property int barSpan: barSize + barGap + barInner // the bar window, across the bar |
| 26 | readonly property int barTop: barVertical ? 0 : barSpan // what the bar reserves at the top |
| 27 | readonly property int barLeft: barVertical ? barSpan : 0 // ... and at the left |
| 28 | readonly property real barAlpha: Settings.barAlpha |
| 29 | |
| 30 | // ---- motion: ease-out-quart without overshoot (glyph's "glide"); Settings.motion off = instant ---- |
| 31 | readonly property bool motion: Settings.motion |
| 32 | readonly property int t: motion ? 350 : 0 |
| 33 | readonly property var glide: [0.25, 1, 0.5, 1, 1, 1] |
| 34 | |
| 35 | readonly property string matFile: Quickshell.env("HOME") + "/.cache/matugen/aurora.json" |
| 36 | |
| 37 | // Material 3 roles from ~/.config/matugen/templates/aurora.json ("on_x" is spelled "xFg": JsonAdapter keys must not |
| 38 | // start with "on" + uppercase or be "error"). Defaults = a dark teal scheme for a fresh install. |
| 39 | FileView { |
| 40 | path: root.matFile |
| 41 | watchChanges: true |
| 42 | onFileChanged: reload() |
| 43 | adapter: JsonAdapter { |
| 44 | id: mat |
| 45 | property string primary: "#80d5cb" |
| 46 | property string primaryFg: "#003733" |
| 47 | property string primaryContainer: "#00504a" |
| 48 | property string primaryContainerFg: "#9cf2e7" |
| 49 | property string secondary: "#b1ccc7" |
| 50 | property string secondaryFg: "#1c3532" |
| 51 | property string secondaryContainer: "#334b48" |
| 52 | property string secondaryContainerFg: "#cce8e3" |
| 53 | property string tertiary: "#adcae6" |
| 54 | property string tertiaryFg: "#153349" |
| 55 | property string tertiaryContainer: "#2d4961" |
| 56 | property string tertiaryContainerFg: "#cce5ff" |
| 57 | property string surface: "#0e1514" |
| 58 | property string surfaceLowest: "#090f0f" |
| 59 | property string surfaceLow: "#161d1c" |
| 60 | property string surfaceContainer: "#1a2120" |
| 61 | property string surfaceHigh: "#252b2a" |
| 62 | property string surfaceHighest: "#2f3635" |
| 63 | property string surfaceFg: "#dde4e2" |
| 64 | property string surfaceVariantFg: "#bec9c6" |
| 65 | property string outline: "#889391" |
| 66 | property string outlineVariant: "#3f4947" |
| 67 | property string err: "#ffb4ab" |
| 68 | property string errFg: "#690005" |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | // ---- palette ------------------------------------------------------ |
| 73 | // Nothing's ladder of steps, filled with Material roles, so every wallpaper re-themes everything. |
| 74 | readonly property color bg: mat.surfaceLowest // wallpaper backdrop, fullscreen overlays |
| 75 | readonly property color s1: mat.surfaceLow // bar, panels, cards |
| 76 | readonly property color s2: mat.surfaceHigh // tiles, rows, "off" fills, inputs |
| 77 | readonly property color s3: mat.surfaceHighest // lines, unlit dots, hover |
| 78 | readonly property color mute: mat.outlineVariant // inactive |
| 79 | readonly property color grey: mat.outline // caps labels |
| 80 | readonly property color fg: mat.surfaceFg // text |
| 81 | readonly property color fgDim: mat.surfaceVariantFg // secondary text (artist, notification body) |
| 82 | // "on" states, Material You style: active tiles/pills, slider fills, selected chips/rows, lit dots and segments |
| 83 | readonly property color fill: mat.primary |
| 84 | readonly property color fillFg: mat.primaryFg |
| 85 | readonly property color container: mat.primaryContainer // tonal emphasis |
| 86 | readonly property color containerFg: mat.primaryContainerFg |
| 87 | // live things (Nothing's one red thing): play button, recording, mic/cam/share, caret, selected dot, newest notification |
| 88 | readonly property color live: mat.tertiary |
| 89 | readonly property color liveFg: mat.tertiaryFg |
| 90 | readonly property color err: mat.err // failures, critical, destructive confirms |
| 91 | readonly property color errFg: mat.errFg |
| 92 | readonly property color glow: fade(fill, 0.6) // glow on lit segments, the only "shadow" |
| 93 | readonly property color scrim: fade(bg, 0.74) // dim behind fullscreen overlays |
| 94 | |
| 95 | function fade(c, a) { return Qt.rgba(c.r, c.g, c.b, a) } |
| 96 | function hex(c) { return c.toString().slice(1, 7).toUpperCase() } |
| 97 | // slurp in the theme: the screen dims, the selection gets a 1px primary outline (Rec, Shot's OCR) |
| 98 | readonly property var slurpArgs: ["-b", "#" + hex(bg) + "88", "-c", "#" + hex(fill) + "ff", "-s", "#00000000", "-w", "1"] |
| 99 | // hours for the 12/24h setting: "09" or "9" |
| 100 | function hh(d) { |
| 101 | var h = d.getHours() |
| 102 | return Settings.clock24 ? (h < 10 ? "0" : "") + h : String(h % 12 || 12) |
| 103 | } |
| 104 | |
| 105 | // ---- hyprlock ----------------------------------------------------- |
| 106 | // hyprlock stays a separate process (crash safety); it sources ~/.config/aurora/hyprlock-colors.conf, |
| 107 | // written here so the lock uses the resolved palette (incl. the settings-picked accent). `$xHex` = "##rrggbb" for |
| 108 | // Pango markup (hyprlang reads "##" as "#"), plus the clock/battery settings its labels need (~/.local/bin/hypr/lockinfo). |
| 109 | // Its pictures (the wallpaper as drawn here, the avatar ring) are LockArt's. |
| 110 | readonly property string lockFile: Quickshell.env("HOME") + "/.config/aurora/hyprlock-colors.conf" |
| 111 | readonly property string lockConf: { |
| 112 | function c(v) { |
| 113 | var h = n => ("0" + Math.round(n * 255).toString(16)).slice(-2) |
| 114 | return "rgba(" + h(v.r) + h(v.g) + h(v.b) + h(v.a) + ")" |
| 115 | } |
| 116 | function x(v) { return "##" + hex(v).toLowerCase() } |
| 117 | return ["# generated by aurora (Theme.qml); edit the palette there, not here", |
| 118 | "$bg = " + c(bg), "$fg = " + c(fg), "$fgDim = " + c(fgDim), "$s1 = " + c(s1), "$s2 = " + c(s2), "$s3 = " + c(s3), |
| 119 | "$mute = " + c(mute), "$grey = " + c(grey), "$fill = " + c(fill), "$fillFg = " + c(fillFg), "$live = " + c(live), |
| 120 | "$err = " + c(err), "$dot = " + dot + " Black", "$ui = " + ui, "$mono = " + mono, |
| 121 | "$fgHex = " + x(fg), "$s3Hex = " + x(s3), "$greyHex = " + x(grey), "$liveHex = " + x(live), "$errHex = " + x(err), |
| 122 | "$hourFmt = " + (Settings.clock24 ? "%H" : "%-I"), "$blink = " + (Settings.blink ? 1 : 0), |
| 123 | "$batLow = " + Settings.batLow, |
| 124 | ""].join("\n") |
| 125 | } |
| 126 | onLockConfChanged: lockTimer.restart() |
| 127 | Timer { id: lockTimer; interval: 500; onTriggered: lockFv.setText(root.lockConf) } |
| 128 | FileView { id: lockFv; path: root.lockFile; printErrors: false } |
| 129 | Component.onCompleted: lockTimer.restart() |
| 130 | |
| 131 | // ---- Nerd Font (Material Design) glyphs --------------------------- |
| 132 | function cp(c) { |
| 133 | c -= 0x10000 |
| 134 | return String.fromCharCode(0xD800 + (c >> 10), 0xDC00 + (c & 0x3FF)) |
| 135 | } |
| 136 | readonly property string iHome: cp(0xF02DC) |
| 137 | readonly property string iVolHigh: cp(0xF057E) |
| 138 | readonly property string iVolMed: cp(0xF0580) |
| 139 | readonly property string iVolLow: cp(0xF057F) |
| 140 | readonly property string iVolOff: cp(0xF0581) |
| 141 | readonly property string iMic: cp(0xF036C) |
| 142 | readonly property string iMicOff: cp(0xF036D) |
| 143 | readonly property string iWifi: cp(0xF05A9) |
| 144 | readonly property string iWifiOff: cp(0xF05AA) |
| 145 | readonly property string iBt: cp(0xF00AF) |
| 146 | readonly property string iBtOff: cp(0xF00B2) |
| 147 | readonly property string iBtConn: cp(0xF00B1) |
| 148 | readonly property string iPower: cp(0xF0425) |
| 149 | readonly property string iClose: cp(0xF0156) |
| 150 | readonly property string iPrev: cp(0xF04AE) |
| 151 | readonly property string iNext: cp(0xF04AD) |
| 152 | readonly property string iPlay: cp(0xF040A) |
| 153 | readonly property string iPause: cp(0xF03E4) |
| 154 | readonly property string iBright: cp(0xF00DF) |
| 155 | readonly property string iLock: cp(0xF033E) |
| 156 | readonly property string iLogout: cp(0xF0343) |
| 157 | readonly property string iSleep: cp(0xF04B2) |
| 158 | readonly property string iReboot: cp(0xF0709) |
| 159 | readonly property string iRefresh: cp(0xF0450) |
| 160 | readonly property string iHeadphones: cp(0xF02CB) |
| 161 | readonly property string iSpeaker: cp(0xF04C3) |
| 162 | readonly property string iMusic: cp(0xF075A) |
| 163 | readonly property string iTrash: cp(0xF01B4) |
| 164 | readonly property string iCheck: cp(0xF012C) |
| 165 | readonly property string iLogin: cp(0xF0342) |
| 166 | readonly property string iMouse: cp(0xF037D) |
| 167 | readonly property string iKeyboard: cp(0xF030C) |
| 168 | readonly property string iPhone: cp(0xF011C) |
| 169 | readonly property string iGamepad: cp(0xF0297) |
| 170 | readonly property string iSearch: cp(0xF0349) |
| 171 | // glyph picker sections |
| 172 | readonly property string iGrid: cp(0xF11D9) |
| 173 | readonly property string iHistory: cp(0xF02DA) |
| 174 | readonly property string iEmoji: cp(0xF01F5) |
| 175 | readonly property string iFontGlyph: cp(0xF06D6) |
| 176 | readonly property string iSigma: cp(0xF04A0) |
| 177 | readonly property string iKaomoji: cp(0xF01F3) |
| 178 | readonly property string iFancy: cp(0xF0B34) |
| 179 | readonly property string iBuffer: cp(0xF1296) |
| 180 | |
| 181 | readonly property string iHeadset: cp(0xF02CE) |
| 182 | readonly property string iCamera: cp(0xF0100) |
| 183 | readonly property string iWebcam: cp(0xF05A0) |
| 184 | readonly property string iCast: cp(0xF0118) |
| 185 | readonly property string iCrop: cp(0xF019E) |
| 186 | readonly property string iWindow: cp(0xF05B0) |
| 187 | readonly property string iMonitor: cp(0xF0379) |
| 188 | readonly property string iSave: cp(0xF0193) |
| 189 | readonly property string iClipboard: cp(0xF0147) |
| 190 | readonly property string iBell: cp(0xF009A) |
| 191 | readonly property string iBellOff: cp(0xF009B) |
| 192 | readonly property string iChip: cp(0xF061A) |
| 193 | readonly property string iMem: cp(0xF035B) |
| 194 | readonly property string iDisk: cp(0xF02CA) |
| 195 | readonly property string iUsb: cp(0xF129B) |
| 196 | readonly property string iEject: cp(0xF01EA) |
| 197 | readonly property string iUpdate: cp(0xF03D5) // package up |
| 198 | readonly property string iFolderOpen: cp(0xF0770) |
| 199 | readonly property string iGpu: cp(0xF08AE) |
| 200 | readonly property string iLeaf: cp(0xF032A) |
| 201 | readonly property string iBalance: cp(0xF05D1) |
| 202 | readonly property string iSpeed: cp(0xF04C5) |
| 203 | readonly property string iAuto: cp(0xF006A) // autorenew |
| 204 | readonly property string iCal: cp(0xF00ED) |
| 205 | readonly property string iClock: cp(0xF0954) |
| 206 | readonly property string iArch: cp(0xF08C7) |
| 207 | readonly property string iEthernet: cp(0xF0200) |
| 208 | readonly property string iPlug: cp(0xF06A5) |
| 209 | readonly property string iBatCharge: cp(0xF0084) |
| 210 | readonly property string iShuffle: cp(0xF049D) |
| 211 | readonly property string iImage: cp(0xF02E9) |
| 212 | readonly property string iCoffee: cp(0xF0176) |
| 213 | readonly property string iPlane: cp(0xF001D) |
| 214 | readonly property string iPicker: cp(0xF020A) |
| 215 | readonly property string iRec: cp(0xF044A) |
| 216 | readonly property string iStop: cp(0xF04DB) |
| 217 | readonly property string iDock: cp(0xF10A9) |
| 218 | readonly property string iCog: cp(0xF0493) |
| 219 | readonly property string iApps: cp(0xF003B) |
| 220 | readonly property string iApp: cp(0xF08C6) |
| 221 | readonly property string iConsole: cp(0xF018D) |
| 222 | readonly property string iShell: cp(0xF07B7) |
| 223 | readonly property string iCalc: cp(0xF00EC) |
| 224 | readonly property string iPalette: cp(0xF03D8) |
| 225 | readonly property string iChevron: cp(0xF0142) // right |
| 226 | readonly property string iChevronLeft: cp(0xF0141) |
| 227 | readonly property string iChevronDown: cp(0xF0140) |
| 228 | readonly property string iChevronUp: cp(0xF0143) |
| 229 | readonly property string iNight: cp(0xF0594) // weather-night (night light) |
| 230 | readonly property string iShot: cp(0xF0E51) // monitor-screenshot |
| 231 | readonly property string iOcr: cp(0xF113D) // text-recognition |
| 232 | readonly property string iBolt: cp(0xF140B) // lightning-bolt (charging) |
| 233 | readonly property string iDots: cp(0xF01D8) // dots-horizontal |
| 234 | readonly property string iDashboard: cp(0xF056E) // view-dashboard (overview) |
| 235 | readonly property string iText: cp(0xF0262) // format-align-left |
| 236 | readonly property string iLink: cp(0xF0339) // link-variant |
| 237 | readonly property string iCode: cp(0xF0169) // code-braces |
| 238 | // weather (Weather.icon picks one per WMO code) |
| 239 | readonly property string iSunny: cp(0xF0599) |
| 240 | readonly property string iPartlyCloudy: cp(0xF0595) |
| 241 | readonly property string iNightCloudy: cp(0xF0F31) // weather-night-partly-cloudy |
| 242 | readonly property string iCloudy: cp(0xF0590) |
| 243 | readonly property string iFog: cp(0xF0591) |
| 244 | readonly property string iRain: cp(0xF0597) |
| 245 | readonly property string iPouring: cp(0xF0596) |
| 246 | readonly property string iSnow: cp(0xF0598) |
| 247 | readonly property string iThunder: cp(0xF0593) |
| 248 | readonly property string iSunrise: cp(0xF059C) // weather-sunset-up |
| 249 | readonly property string iSunset: cp(0xF059B) // weather-sunset-down |
| 250 | readonly property string iArrowDown: cp(0xF0045) |
| 251 | readonly property string iArrowUp: cp(0xF005D) |
| 252 | |
| 253 | readonly property var batLevels: [0xF007A, 0xF007B, 0xF007C, 0xF007D, 0xF007E, |
| 254 | 0xF007F, 0xF0080, 0xF0081, 0xF0082, 0xF0079] |
| 255 | function batIcon(p, charging, plugged) { |
| 256 | if (charging) return iBatCharge |
| 257 | if (plugged) return iPlug |
| 258 | return cp(batLevels[Math.max(0, Math.min(9, Math.floor(p * 10)))]) |
| 259 | } |
| 260 | function fmtTime(s) { |
| 261 | if (!s || s <= 0) return "-" |
| 262 | var h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60) |
| 263 | return h > 0 ? h + "h " + m + "m" : m + "m" |
| 264 | } |
| 265 | |
| 266 | function fmtClock(s) { // 75 -> "1:15" |
| 267 | var m = Math.floor(s / 60), r = s % 60 |
| 268 | return m + ":" + (r < 10 ? "0" : "") + r |
| 269 | } |
| 270 | function volIcon(v, muted) { |
| 271 | if (muted || v <= 0) return iVolOff |
| 272 | return v < 0.34 ? iVolLow : (v < 0.67 ? iVolMed : iVolHigh) |
| 273 | } |
| 274 | function wifiIcon(sig) { |
| 275 | return cp(sig >= 75 ? 0xF0928 : sig >= 50 ? 0xF0925 : sig >= 25 ? 0xF0922 : 0xF091F) |
| 276 | } |
| 277 | } |