quickshell and hyprland additions

This commit is contained in:
2026-03-15 13:56:00 +02:00
parent c9c27d1554
commit 1ad06b82a6
509 changed files with 68371 additions and 19 deletions

View File

@@ -0,0 +1,262 @@
import qs.modules.functions
import QtQuick
import Quickshell
pragma Singleton
pragma ComponentBehavior: Bound
Singleton {
id: root
property QtObject m3colors
property QtObject colors
property QtObject rounding
property QtObject font
property QtObject margin
property QtObject moduleLayouts
property QtObject animation
property string syntaxHighlightingTheme
readonly property bool darkmode: Config.runtime.appearance.theme === "dark"
readonly property bool transparentize: Config.runtime.appearance.transparency.enabled
readonly property double alpha: Config.runtime.appearance.transparency.alpha
colors: QtObject {
property color colSubtext: m3colors.m3outline
property color colLayer0: m3colors.m3background
property color colLayer0Border: ColorUtils.mix(root.m3colors.m3outlineVariant, colLayer0, 0.4)
property color colLayer1: m3colors.m3surfaceContainerLow
property color colOnLayer1: m3colors.m3onSurfaceVariant
property color colOnLayer1Inactive: ColorUtils.mix(colOnLayer1, colLayer1, 0.45)
property color colLayer1Hover: ColorUtils.mix(colLayer1, colOnLayer1, 0.92)
property color colLayer1Active: ColorUtils.mix(colLayer1, colOnLayer1, 0.85)
property color colLayer2: m3colors.m3surfaceContainer
property color colOnLayer2: m3colors.m3onSurface
property color colLayer2Hover: ColorUtils.mix(colLayer2, colOnLayer2, 0.90)
property color colLayer2Active: ColorUtils.mix(colLayer2, colOnLayer2, 0.80)
property color colPrimary: m3colors.m3primary
property color colOnPrimary: m3colors.m3onPrimary
property color colSecondary: m3colors.m3secondary
property color colSecondaryContainer: m3colors.m3secondaryContainer
property color colOnSecondaryContainer: m3colors.m3onSecondaryContainer
property color colTooltip: m3colors.m3inverseSurface
property color colOnTooltip: m3colors.m3inverseOnSurface
property color colShadow: ColorUtils.transparentize(m3colors.m3shadow, 0.7)
property color colOutline: m3colors.m3outline
}
m3colors: QtObject {
function t(c) {
return root.transparentize
? ColorUtils.transparentize(c, root.alpha)
: c
}
function tH(c) {
return root.transparentize
? ColorUtils.transparentize(c, root.alpha + 1) // Totally transparent
: c
}
readonly property color m3background: t(MaterialColors.colors.background)
readonly property color m3paddingContainer: t(Config.runtime.bar.modules.paddingColor)
readonly property color m3surface: t(MaterialColors.colors.surface)
readonly property color m3surfaceDim: t(MaterialColors.colors.surface_dim)
readonly property color m3surfaceBright: t(MaterialColors.colors.surface_bright)
readonly property color m3surfaceContainerLowest: tH(MaterialColors.colors.surface_container_lowest)
readonly property color m3surfaceContainerLow: tH(MaterialColors.colors.surface_container_low)
readonly property color m3surfaceContainer: tH(MaterialColors.colors.surface_container)
readonly property color m3surfaceContainerHigh: tH(MaterialColors.colors.surface_container_high)
readonly property color m3surfaceContainerHighest: tH(MaterialColors.colors.surface_container_highest)
readonly property color m3onSurface: t(MaterialColors.colors.on_surface)
readonly property color m3surfaceVariant: t(MaterialColors.colors.surface_variant)
readonly property color m3onSurfaceVariant: t(MaterialColors.colors.on_surface_variant)
readonly property color m3inverseSurface: t(MaterialColors.colors.inverse_surface)
readonly property color m3inverseOnSurface: t(MaterialColors.colors.inverse_on_surface)
readonly property color m3outline: t(MaterialColors.colors.outline)
readonly property color m3outlineVariant: t(MaterialColors.colors.outline_variant)
readonly property color m3shadow: t(MaterialColors.colors.shadow)
readonly property color m3scrim: t(MaterialColors.colors.scrim)
readonly property color m3surfaceTint: t(MaterialColors.colors.surface_tint)
readonly property color m3primary: t(MaterialColors.colors.primary)
readonly property color m3onPrimary: t(MaterialColors.colors.on_primary)
readonly property color m3primaryContainer: t(MaterialColors.colors.primary_container)
readonly property color m3onPrimaryContainer: t(MaterialColors.colors.on_primary_container)
readonly property color m3inversePrimary: t(MaterialColors.colors.inverse_primary)
readonly property color m3secondary: t(MaterialColors.colors.secondary)
readonly property color m3onSecondary: t(MaterialColors.colors.on_secondary)
readonly property color m3secondaryContainer: t(MaterialColors.colors.secondary_container)
readonly property color m3onSecondaryContainer: t(MaterialColors.colors.on_secondary_container)
readonly property color m3tertiary: t(MaterialColors.colors.tertiary)
readonly property color m3onTertiary: t(MaterialColors.colors.on_tertiary)
readonly property color m3tertiaryContainer: t(MaterialColors.colors.tertiary_container)
readonly property color m3onTertiaryContainer: t(MaterialColors.colors.on_tertiary_container)
readonly property color m3error: t(MaterialColors.colors.error)
readonly property color m3onError: t(MaterialColors.colors.on_error)
readonly property color m3errorContainer: t(MaterialColors.colors.error_container)
readonly property color m3onErrorContainer: t(MaterialColors.colors.on_error_container)
readonly property color m3primaryFixed: t(MaterialColors.colors.primary_fixed)
readonly property color m3primaryFixedDim: t(MaterialColors.colors.primary_fixed_dim)
readonly property color m3onPrimaryFixed: t(MaterialColors.colors.on_primary_fixed)
readonly property color m3onPrimaryFixedVariant: t(MaterialColors.colors.on_primary_fixed_variant)
readonly property color m3secondaryFixed: t(MaterialColors.colors.secondary_fixed)
readonly property color m3secondaryFixedDim: t(MaterialColors.colors.secondary_fixed_dim)
readonly property color m3onSecondaryFixed: t(MaterialColors.colors.on_secondary_fixed)
readonly property color m3onSecondaryFixedVariant: t(MaterialColors.colors.on_secondary_fixed_variant)
readonly property color m3tertiaryFixed: t(MaterialColors.colors.tertiary_fixed)
readonly property color m3tertiaryFixedDim: t(MaterialColors.colors.tertiary_fixed_dim)
readonly property color m3onTertiaryFixed: t(MaterialColors.colors.on_tertiary_fixed)
readonly property color m3onTertiaryFixedVariant: t(MaterialColors.colors.on_tertiary_fixed_variant)
}
margin: QtObject {
property int supertiny: 2
property int tinier: 3
property int tiny: 6
property int verysmall: 8
property int small: 12
property int normal: 16
property int large: 22
property int verylarge: 30
property int extraLarge: 35
}
animation: QtObject {
property var easing: Easing.OutExpo
property QtObject durations: QtObject {
property int supershort: 100
property int small: 200
property int normal: 400
property int large: 600
property int extraLarge: 1000
property int expressiveFastSpatial: 350
property int expressiveDefaultSpatial: 500
property int expressiveEffects: 200
}
property QtObject curves: QtObject {
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.90, 1, 1] // Default, 350ms
readonly property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1.00, 1, 1] // Default, 500ms
readonly property list<real> expressiveSlowSpatial: [0.39, 1.29, 0.35, 0.98, 1, 1] // Default, 650ms
readonly property list<real> expressiveEffects: [0.34, 0.80, 0.34, 1.00, 1, 1] // Default, 200ms
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
readonly property list<real> emphasizedFirstHalf: [0.05, 0, 2 / 15, 0.06, 1 / 6, 0.4, 5 / 24, 0.82]
readonly property list<real> emphasizedLastHalf: [5 / 24, 0.82, 0.25, 1, 1, 1]
readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
readonly property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1]
readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
readonly property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
readonly property real expressiveFastSpatialDuration: 350
readonly property real expressiveDefaultSpatialDuration: 500
readonly property real expressiveSlowSpatialDuration: 650
readonly property real expressiveEffectsDuration: 200
}
property QtObject elementMove: QtObject {
property int duration: animation.curves.expressiveDefaultSpatialDuration
property int type: Easing.BezierSpline
property list<real> bezierCurve: animation.curves.expressiveDefaultSpatial
property Component numberAnimation: Component {
NumberAnimation {
duration: root.animation.elementMove.duration
easing.type: root.animation.elementMove.type
easing.bezierCurve: root.animation.elementMove.bezierCurve
}
}
}
property QtObject elementMoveEnter: QtObject {
property int duration: 400
property int type: Easing.BezierSpline
property list<real> bezierCurve: animation.curves.emphasizedDecel
property Component numberAnimation: Component {
NumberAnimation {
duration: root.animation.elementMoveEnter.duration
easing.type: root.animation.elementMoveEnter.type
easing.bezierCurve: root.animation.elementMoveEnter.bezierCurve
}
}
}
property QtObject elementMoveFast: QtObject {
property int duration: animation.curves.expressiveEffectsDuration
property int type: Easing.BezierSpline
property list<real> bezierCurve: animation.curves.expressiveEffects
property Component numberAnimation: Component {
NumberAnimation {
duration: root.animation.elementMoveFast.duration
easing.type: root.animation.elementMoveFast.type
easing.bezierCurve: root.animation.elementMoveFast.bezierCurve
}
}
}
}
rounding: QtObject {
property int unsharpen: 2 * Config.runtime.appearance.rounding.factor
property int unsharpenmore: 6 * Config.runtime.appearance.rounding.factor
property int verysmall: 8 * Config.runtime.appearance.rounding.factor
property int small: 12 * Config.runtime.appearance.rounding.factor
property int normal: 17 * Config.runtime.appearance.rounding.factor
property int large: 23 * Config.runtime.appearance.rounding.factor
property int verylarge: 30 * Config.runtime.appearance.rounding.factor
property int childish: 50 * Config.runtime.appearance.rounding.factor // Idk why did I named this childish
property int full: 9999
property int screenRounding: large
property int windowRounding: 18 * Config.runtime.appearance.rounding.factor
}
font: QtObject {
property QtObject family: QtObject {
property string main: Config.runtime.appearance.font.families.main
property string title: Config.runtime.appearance.font.families.title
property string materialIcons: Config.runtime.appearance.font.families.materialIcons
property string nerdIcons: Config.runtime.appearance.font.families.nerdFonts
property string monospace: Config.runtime.appearance.font.families.monospace
property string reading: Config.runtime.appearance.font.families.reading
property string expressive: Config.runtime.appearance.font.families.expressive
}
property QtObject size: QtObject {
property int smallest: 10
property int smaller: 12
property int smallie: 13
property int small: 15
property int normal: 16
property int large: 17
property int larger: 19
property int big: 21
property int huge: 22
property int hugeass: 23
property int wildass: 40
property int title: huge
property QtObject icon: QtObject {
property int smallest: 10
property int smaller: 12
property int small: 14
property int normal: 16
property int large: 17
property int larger: 19
property int huge: 22
property int hugeass: 23
}
}
}
syntaxHighlightingTheme: darkmode ? '#f1ebeb' : "#141333"
}

View File

@@ -0,0 +1,282 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import QtCore
import Quickshell
import Quickshell.Io
import qs.plugins
import qs.services
Singleton {
id: root
property string filePath: Directories.shellConfigPath
property alias runtime: configOptionsJsonAdapter
property bool initialized: false
property int readWriteDelay: 50
property bool blockWrites: false
function updateKey(nestedKey, value) {
let keys = nestedKey.split(".")
let obj = root.runtime
if (!obj) {
console.warn("Config.updateKey: adapter not available for key", nestedKey)
return
}
for (let i = 0; i < keys.length - 1; ++i) {
let k = keys[i]
if (obj[k] === undefined || obj[k] === null || typeof obj[k] !== "object") {
obj[k] = {} // Use Plain JS for serialization
}
obj = obj[k]
if (!obj) {
console.warn("Config.updateKey: failed to resolve", k)
return
}
}
let convertedValue = value
if (typeof value === "string") {
let trimmed = value.trim()
if (trimmed === "true" || trimmed === "false" || (!isNaN(Number(trimmed)) && trimmed !== "")) {
try {
convertedValue = JSON.parse(trimmed)
} catch (e) {
convertedValue = value
}
}
}
obj[keys[keys.length - 1]] = convertedValue
configFileView.adapterUpdated()
}
function loadPluginConfigs(plugins) {
console.log("Loading plugins:", plugins)
if (!root.runtime)
return
if (!root.runtime.plugins)
root.runtime.plugins = {}
function mergeDefaults(target, defaults) {
let changed = false
for (let key in defaults) {
const defVal = defaults[key]
const tgtVal = target[key]
if (tgtVal === undefined) {
target[key] = defVal
changed = true
} else if (
typeof tgtVal === "object" &&
typeof defVal === "object" &&
tgtVal !== null &&
defVal !== null
) {
if (mergeDefaults(tgtVal, defVal))
changed = true
}
}
return changed
}
let anyChange = false
for (let i = 0; i < plugins.length; i++) {
const name = plugins[i]
const path = Directories.shellConfig + "/plugins/" + name + "/PluginConfigData.qml"
const component = Qt.createComponent(path)
if (component.status === Component.Error) {
console.warn("Plugin failed:", path, component.errorString())
continue
}
if (component.status !== Component.Ready)
continue
const pluginObj = component.createObject(root)
if (!pluginObj) {
console.warn("Failed to create plugin object:", name)
component.destroy()
continue
}
if (!pluginObj.defaults)
pluginObj.defaults = { enabled: false }
if (!root.runtime.plugins[name]) {
root.runtime.plugins[name] = {}
anyChange = true
}
if (mergeDefaults(root.runtime.plugins[name], pluginObj.defaults))
anyChange = true
console.log("Plugin config injected:", name)
pluginObj.destroy()
component.destroy()
}
if (anyChange) {
console.log("Plugin defaults merged, writing config")
configFileView.adapterUpdated()
} else {
console.log("Plugin configs already up to date")
}
}
Timer { id: fileReloadTimer; interval: root.readWriteDelay; repeat: false; onTriggered: configFileView.reload() }
Timer { id: fileWriteTimer; interval: root.readWriteDelay; repeat: false; onTriggered: configFileView.writeAdapter() }
Timer { // Used to output all log/debug to the terminal
interval: 1200
running: true
repeat: false
onTriggered: {
console.log("Injecting plugin configs")
root.loadPluginConfigs(PluginLoader.plugins)
console.log("Detected Compositor:", Compositor.detectedCompositor)
}
}
FileView {
id: configFileView
path: root.filePath
watchChanges: true
blockWrites: root.blockWrites
onFileChanged: fileReloadTimer.restart()
onAdapterUpdated: fileWriteTimer.restart()
onLoaded: { root.initialized = true }
onLoadFailed: error => {
if (error == FileViewError.FileNotFound) writeAdapter()
}
JsonAdapter {
id: configOptionsJsonAdapter
property var plugins: ({}) // dynamic plugins config variable
property var monitors: ({}) // per-monitor configuration for bars and wallpapers
property JsonObject appearance: JsonObject {
property string theme: "dark"
property bool tintIcons: false
property JsonObject animations: JsonObject { property bool enabled: true; property double durationScale: 1 }
property JsonObject transparency: JsonObject { property bool enabled: false; property double alpha: 0.2 }
property JsonObject rounding: JsonObject { property double factor: 1 }
property JsonObject font: JsonObject {
property double scale: 1
property JsonObject families: JsonObject {
property string main: "JetBrains Mono"
property string title: "Gabarito"
property string materialIcons: "Material Symbols Rounded"
property string nerdFonts: "JetBrains Mono NF"
property string monospace: "JetBrains Mono NF"
property string reading: "Readex Pro"
property string expressive: "Space Grotesk"
}
}
property JsonObject colors: JsonObject {
property string scheme: "catppuccin-lavender"
property string matugenScheme: "scheme-neutral"
property bool autogenerated: true
property bool runMatugenUserWide: false
}
property JsonObject background: JsonObject {
property bool enabled: true
property url defaultPath: Directories.defaultsPath + "/default.jpg"
property JsonObject parallax: JsonObject {
property bool enabled: true
property bool enableSidebarLeft: true
property bool enableSidebarRight: true
property real zoom: 1.10
}
property JsonObject clock: JsonObject {
property bool enabled: true
property bool isAnalog: true
property bool rotatePolygonBg: false
property int rotationDuration: 18 // lower the faster
property int edgeSpacing: 50
property int shape: 1
property int xPos: 0
property int yPos: 0
property bool animateHands: false
}
property JsonObject slideshow: JsonObject {
property bool enabled: false
property bool includeSubfolders: true
property int interval: 5
property string folder: ""
}
}
}
property JsonObject misc: JsonObject {
property url pfp: Quickshell.env("HOME") + "/.face.icon"
property JsonObject intelligence: JsonObject {
property bool enabled: true
property string apiKey: ""
}
}
property JsonObject notifications: JsonObject {
property bool enabled: true
property bool doNotDisturb: false
property string position: "center"
}
property JsonObject shell: JsonObject {
property string version: "0.7.7"
property string releaseChannel: "stable"
property string qsVersion: "0.0.0"
}
property JsonObject overlays: JsonObject {
property bool enabled: true
property bool volumeOverlayEnabled: true
property bool brightnessOverlayEnabled: true
property string volumeOverlayPosition: "top"
property string brightnessOverlayPosition: "top"
}
property JsonObject launcher: JsonObject {
property bool fuzzySearchEnabled: true
property string webSearchEngine: "google"
}
property JsonObject bar: JsonObject {
property string position: "top"
property bool enabled: true
property bool merged: false
property bool floating: false
property bool gothCorners: true
property int radius: Appearance.rounding.large
property int margins: Appearance.margin.normal
property int density: 50
property JsonObject modules: JsonObject {
property color paddingColor: Appearance.m3colors.m3surfaceContainer
property int radius: Appearance.rounding.normal
property int height: 34
property JsonObject workspaces: JsonObject {
property bool enabled: true
property int workspaceIndicators: 8
property bool showAppIcons: true
property bool showJapaneseNumbers: false
}
property JsonObject statusIcons: JsonObject {
property bool enabled: true
property bool networkStatusEnabled: true
property bool bluetoothStatusEnabled: true
}
property JsonObject systemUsage: JsonObject {
property bool enabled: true
property bool cpuStatsEnabled: true
property bool memoryStatsEnabled: true
property bool tempStatsEnabled: true
}
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
pragma Singleton
pragma ComponentBehavior: Bound
import qs.modules.functions
import QtCore
import QtQuick
import Quickshell
Singleton {
// XDG Dirs, with "file://"
readonly property string home: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
readonly property string config: StandardPaths.standardLocations(StandardPaths.ConfigLocation)[0]
readonly property string state: StandardPaths.standardLocations(StandardPaths.StateLocation)[0]
readonly property string cache: StandardPaths.standardLocations(StandardPaths.CacheLocation)[0]
readonly property string genericCache: StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]
readonly property string documents: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0]
readonly property string downloads: StandardPaths.standardLocations(StandardPaths.DownloadLocation)[0]
readonly property string pictures: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
readonly property string music: StandardPaths.standardLocations(StandardPaths.MusicLocation)[0]
readonly property string videos: StandardPaths.standardLocations(StandardPaths.MoviesLocation)[0]
property string shellConfig: FileUtils.trimFileProtocol(`${Directories.config}/nucleus-shell`)
property string shellConfigName: "configuration.json"
property string shellConfigPath: `${Directories.shellConfig}/config/${Directories.shellConfigName}`
property string generatedMaterialThemePath: FileUtils.trimFileProtocol(`${Directories.config}/nucleus-shell/config/colors.json`)
property string defaultsPath: Quickshell.shellPath("defaults")
property string scriptsPath: Quickshell.shellPath("scripts")
property string assetsPath: Quickshell.shellPath("assets")
// Cleanup on init
Component.onCompleted: {
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`])
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}/config`])
Quickshell.execDetached(["mkdir", "-p", `${shellConfig}/plugins`])
Quickshell.execDetached(["mkdir", "-p", `${FileUtils.trimFileProtocol(Directories.pictures)}/Screenshots`])
// Create dirs for intelligence shit
Quickshell.execDetached(["mkdir", "-p", FileUtils.trimFileProtocol(`${config}/zenith/`), FileUtils.trimFileProtocol(`${config}/zenith/chats`)])
Quickshell.execDetached(["touch", FileUtils.trimFileProtocol(`${config}/zenith/chats/default.txt`)])
}
}

View File

@@ -0,0 +1,23 @@
import QtQuick
pragma Singleton
pragma ComponentBehavior: Bound
import Quickshell
Singleton {
id: root
property QtObject visiblility
property QtObject states
visiblility: QtObject {
property bool powermenu: false
property bool launcher: false
property bool sidebarRight: false
property bool sidebarLeft: false
}
states: QtObject {
property bool settingsOpen: false
property bool intelligenceWindowOpen: false
}
}

View File

@@ -0,0 +1,97 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.services
import qs.modules.interface.settings
Scope {
id: global
// Track if notification has already been shown
property bool themeNotificationShown: false
// Function to show notification once
function notifyPredefinedTheme() {
if (!themeNotificationShown) {
themeNotificationShown = true
Quickshell.execDetached([
"notify-send",
"Nucleus Shell",
`You are using a predefined theme ${Config.runtime.appearance.colors.scheme}. Color generation/Light Theme is not supported for this theme.`,
"--urgency=normal",
"--expire-time=5000"
])
}
}
// Handle Global IPCs
IpcHandler {
target: "global"
function toggleTheme() {
const currentTheme = Config.runtime.appearance.theme
const newTheme = currentTheme === "light" ? "dark" : "light"
// Predefined themes: validate variant BEFORE changing theme
if (!Config.runtime.appearance.colors.autogenerated) {
const scheme = Config.runtime.appearance.colors.scheme
const file = Theme.map[scheme]?.[newTheme]
if (!file) {
Theme.notifyMissingVariant(scheme, newTheme)
return
}
Config.updateKey("appearance.theme", newTheme)
Quickshell.execDetached([
"bash",
Directories.scriptsPath + "/interface/switchTheme.sh",
file
])
return
}
// Autogenerated themes: safe to toggle freely
Config.updateKey("appearance.theme", newTheme)
genThemeColors.running = true
}
function regenColors() {
if (Config.runtime.appearance.colors.autogenerated) {
genThemeColors.running = true
} else {
notifyPredefinedTheme()
}
}
}
property var genColorsCmd: Config.runtime.appearance.colors.runMatugenUserWide
? [
"bash",
Directories.scriptsPath + "/interface/gencolors.sh",
"--user-wide",
Config.runtime.appearance.background.path,
Config.runtime.appearance.colors.matugenScheme,
Config.runtime.appearance.theme,
Quickshell.shellPath("extras/matugen/config.toml")
]
: [
"bash",
Directories.scriptsPath + "/interface/gencolors.sh",
Config.runtime.appearance.background.path,
Config.runtime.appearance.colors.matugenScheme,
Config.runtime.appearance.theme,
Quickshell.shellPath("extras/matugen/config.toml")
];
// Process to generate colors
Process {
id: genThemeColors
command: genColorsCmd
}
}

View File

@@ -0,0 +1,89 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import QtCore
import Quickshell
import Quickshell.Io
Singleton {
id: m3colors
property string filePath: Directories.generatedMaterialThemePath
property alias colors: colorsJsonAdapter
property bool ready: false
FileView {
id: colorsFileView
path: m3colors.filePath
watchChanges: true
onLoaded: m3colors.ready = true
onFileChanged: colorsFileView.reload()
onLoadFailed: error => {
if (error === FileViewError.FileNotFound) {
console.warn("MaterialColors: colors.json not found, writing defaults")
writeAdapter()
} else {
console.error("MaterialColors: failed to load colors.json:", error)
}
}
JsonAdapter {
id: colorsJsonAdapter
// === Default Matugen color scheme ===
property string background: "#131313"
property string error: "#ffb4ab"
property string error_container: "#93000a"
property string inverse_on_surface: "#303030"
property string inverse_primary: "#00677f"
property string inverse_surface: "#e2e2e2"
property string on_background: "#e2e2e2"
property string on_error: "#690005"
property string on_error_container: "#ffdad6"
property string on_primary: "#003543"
property string on_primary_container: "#b7eaff"
property string on_primary_fixed: "#001f28"
property string on_primary_fixed_variant: "#004e60"
property string on_secondary: "#1e333b"
property string on_secondary_container: "#cfe6f1"
property string on_secondary_fixed: "#071e26"
property string on_secondary_fixed_variant: "#344a52"
property string on_surface: "#e2e2e2"
property string on_surface_variant: "#c6c6c6"
property string on_tertiary: "#2c2e4d"
property string on_tertiary_container: "#e0e0ff"
property string on_tertiary_fixed: "#171937"
property string on_tertiary_fixed_variant: "#424465"
property string outline: "#919191"
property string outline_variant: "#474747"
property string primary: '#a571f2'
property string primary_container: "#004e60"
property string primary_fixed: "#b7eaff"
property string primary_fixed_dim: "#5cd5fb"
property string scrim: "#000000"
property string secondary: "#b3cad4"
property string secondary_container: "#344a52"
property string secondary_fixed: "#cfe6f1"
property string secondary_fixed_dim: "#b3cad4"
property string shadow: "#000000"
property string source_color: "#829aa4"
property string surface: "#131313"
property string surface_bright: "#393939"
property string surface_container: "#1f1f1f"
property string surface_container_high: "#2a2a2a"
property string surface_container_highest: "#353535"
property string surface_container_low: "#1b1b1b"
property string surface_container_lowest: "#0e0e0e"
property string surface_dim: "#131313"
property string surface_tint: "#5cd5fb"
property string surface_variant: "#474747"
property string tertiary: "#c3c3eb"
property string tertiary_container: "#424465"
property string tertiary_fixed: "#e0e0ff"
property string tertiary_fixed_dim: "#c3c3eb"
}
}
function reload() {
colorsFileView.reload()
}
}

View File

@@ -0,0 +1,133 @@
import QtQuick
import Quickshell
pragma Singleton
pragma ComponentBehavior: Bound
Singleton {
id: root
readonly property double durationScale: Config.runtime.appearance.animations.durationScale
readonly property double roundingScale: Config.runtime.appearance.rounding.factor
readonly property double fontScale: Config.runtime.appearance.font.scale
function spacing(value) { // These will be used with a scale later on...
return value
}
function padding(value) {
return value
}
function chronoDuration(value) {
if (typeof value === "number")
return value * durationScale
switch (value) {
case "supershort": return Appearance.animation.durations.supershort * durationScale
case "small": return Appearance.animation.durations.small * durationScale
case "normal": return Appearance.animation.durations.normal * durationScale
case "large": return Appearance.animation.durations.large * durationScale
case "extraLarge": return Appearance.animation.durations.extraLarge * durationScale
case "expressiveFastSpatial": return Appearance.animation.durations.expressiveFastSpatial * durationScale
case "expressiveDefaultSpatial": return Appearance.animation.durations.expressiveDefaultSpatial * durationScale
case "expressiveEffects": return Appearance.animation.durations.expressiveEffects * durationScale
default: return 0
}
}
function margin(value) {
if (typeof value === "number")
return value
switch (value) {
case "supertiny": return Appearance.margin.supertiny
case "tinier": return Appearance.margin.tinier
case "tiny": return Appearance.margin.tiny
case "verysmall": return Appearance.margin.verysmall
case "small": return Appearance.margin.small
case "normal": return Appearance.margin.normal
case "large": return Appearance.margin.large
case "verylarge": return Appearance.margin.verylarge
case "extraLarge": return Appearance.margin.extraLarge
default: return 0
}
}
function radius(value) {
if (typeof value === "number")
return value * roundingScale
switch (value) {
case "unsharpen": return Appearance.rounding.unsharpen * roundingScale
case "unsharpenmore": return Appearance.rounding.unsharpenmore * roundingScale
case "verysmall": return Appearance.rounding.verysmall * roundingScale
case "small": return Appearance.rounding.small * roundingScale
case "normal": return Appearance.rounding.normal * roundingScale
case "large": return Appearance.rounding.large * roundingScale
case "verylarge": return Appearance.rounding.verylarge * roundingScale
case "childish": return Appearance.rounding.childish * roundingScale
case "full": return Appearance.rounding.full * roundingScale
case "screenRounding": return Appearance.rounding.screenRounding * roundingScale
case "windowRounding": return Appearance.rounding.windowRounding * roundingScale
default: return 0
}
}
function fontSize(value) {
if (typeof value === "number")
return value * fontScale
switch (value) {
case "smallest": return Appearance.font.size.smallest * fontScale
case "smaller": return Appearance.font.size.smaller * fontScale
case "smallie": return Appearance.font.size.smallie * fontScale
case "small": return Appearance.font.size.small * fontScale
case "normal": return Appearance.font.size.normal * fontScale
case "large": return Appearance.font.size.large * fontScale
case "larger": return Appearance.font.size.larger * fontScale
case "big": return Appearance.font.size.big * fontScale
case "huge": return Appearance.font.size.huge * fontScale
case "hugeass": return Appearance.font.size.hugeass * fontScale
case "wildass": return Appearance.font.size.wildass * fontScale
case "title": return Appearance.font.size.title * fontScale
default: return Appearance.font.size.normal * fontScale
}
}
function iconSize(value) {
if (typeof value === "number")
return value * fontScale
switch (value) {
case "smallest": return Appearance.font.size.icon.smallest * fontScale
case "smaller": return Appearance.font.size.icon.smaller * fontScale
case "smallie": return Appearance.font.size.icon.smallie * fontScale
case "small": return Appearance.font.size.icon.small * fontScale
case "normal": return Appearance.font.size.icon.normal * fontScale
case "large": return Appearance.font.size.icon.large * fontScale
case "larger": return Appearance.font.size.icon.larger * fontScale
case "big": return Appearance.font.size.icon.big * fontScale
case "huge": return Appearance.font.size.icon.huge * fontScale
case "hugeass": return Appearance.font.size.icon.hugeass * fontScale
case "wildass": return Appearance.font.size.icon.wildass * fontScale
case "title": return Appearance.font.size.icon.title * fontScale
default: return Appearance.font.size.icon.normal * fontScale
}
}
function fontFamily(value) {
if (typeof value === "string") {
switch (value) {
case "main": return Appearance.font.family.main
case "title": return Appearance.font.family.title
case "materialIcons": return Appearance.font.family.materialIcons
case "nerdIcons": return Appearance.font.family.nerdIcons
case "monospace": return Appearance.font.family.monospace
case "reading": return Appearance.font.family.reading
case "expressive": return Appearance.font.family.expressive
default: return value
}
}
return Appearance.font.family.main
}
}