pragma Singleton import QtQuick /** * The design tokens, shared with the web app's `tokens.ts`. * * Kadence reads like a well-set page rather than a dashboard: warm paper, ink * type, hairline rules instead of boxes and shadows, one warm accent. Light and * dark follow the desktop's own colour scheme. */ QtObject { id: theme property SystemPalette system: SystemPalette { colorGroup: SystemPalette.Active } // The session decides; we only read it. readonly property bool dark: system.window.hslLightness < 0.5 readonly property color paper: dark ? "#121110" : "#FAF7F2" readonly property color surface: dark ? "#1A1917" : "#FFFFFF" readonly property color sunken: dark ? "#201E1B" : "#F3EFE8" readonly property color ink: dark ? "#F4F1EA" : "#17150F" readonly property color muted: dark ? "#A79F93" : "#6E675B" readonly property color faint: dark ? "#776F64" : "#9A9388" readonly property color rule: dark ? Qt.rgba(0.96, 0.95, 0.92, 0.14) : Qt.rgba(0.09, 0.08, 0.06, 0.12) readonly property color ember: dark ? "#E0724A" : "#B4441E" readonly property color pine: dark ? "#6FB394" : "#2F6B55" readonly property color amber: dark ? "#D9A441" : "#8A6200" readonly property color clay: dark ? "#E07A6E" : "#A33A2E" // Chart colours are the validated data palette, not the brand accent — // a chart has to stay readable for colour-blind readers in both themes. readonly property color work: dark ? "#d95926" : "#eb6834" readonly property color shortBreak: dark ? "#3987e5" : "#2a78d6" readonly property color longBreak: dark ? "#199e70" : "#1baf7a" readonly property var sequential: dark ? ["#104281", "#184f95", "#256abf", "#3987e5", "#6da7ec", "#9ec5f4"] : ["#cde2fb", "#9ec5f4", "#6da7ec", "#3987e5", "#256abf", "#184f95"] // QML's `font.family` takes one name, so the preference list is resolved // once against what is actually installed on this machine. function pickFamily(candidates) { var available = Qt.fontFamilies() for (var i = 0; i < candidates.length; i++) if (available.indexOf(candidates[i]) >= 0) return candidates[i] return candidates[candidates.length - 1] } readonly property string displayFamily: pickFamily( ["Fraunces", "Noto Serif", "DejaVu Serif", "Liberation Serif", "Georgia", "serif"]) readonly property string sansFamily: pickFamily( ["Inter", "Noto Sans", "DejaVu Sans", "Liberation Sans", "sans-serif"]) readonly property string monoFamily: pickFamily( ["JetBrains Mono", "Noto Sans Mono", "DejaVu Sans Mono", "Liberation Mono", "monospace"]) readonly property int radius: 12 readonly property int gap: 12 readonly property int pad: 18 function kindColor(kind) { if (kind === "short_break") return shortBreak if (kind === "long_break") return longBreak return work } function kindLabel(kind) { if (kind === "short_break") return "Short break" if (kind === "long_break") return "Long break" return "Focus" } // Mirrors the web app's humanMinutes() in lib/format.ts, so "125m" reads // as "2h 5m" here too. function humanMinutes(minutes) { var rounded = Math.round(minutes) var hours = Math.floor(rounded / 60) var rest = rounded % 60 if (hours && rest) return hours + "h " + rest + "m" if (hours) return hours + "h" return rest + "m" } }