diff --git a/dots/.config/hypr/hyprland.lua b/dots/.config/hypr/hyprland.lua index f027f80e1..9e87ce3fb 100644 --- a/dots/.config/hypr/hyprland.lua +++ b/dots/.config/hypr/hyprland.lua @@ -1,26 +1,40 @@ -- This file sources other files in `hyprland` and `custom` folders -- You wanna add your stuff in files in `custom` +-- Internal stuff -- +require("hyprland.lib") +require("hyprland.services") + -- Environment variables -- -require("hyprland/env") -require("custom/env") +require("hyprland.env") +if is_file_exists(HOME .. "/.config/hypr/custom/env.lua") then + require("custom.env") +end --- Defaults -- -require("hyprland/execs") -require("hyprland/general") -require("hyprland/rules") -require("hyprland/colors") -require("hyprland/keybinds") +-- Default configurations -- +require("hyprland.execs") +require("hyprland.general") +require("hyprland.rules") +require("hyprland.colors") +require("hyprland.keybinds") --- Custom -- -require("custom/execs") -require("custom/general") -require("custom/rules") -require("custom/keybinds") +-- Custom configurations -- +if is_file_exists(HOME .. "/.config/hypr/custom/execs.lua") then + require("custom.execs") +end +if is_file_exists(HOME .. "/.config/hypr/custom/general.lua") then + require("custom.general") +end +if is_file_exists(HOME .. "/.config/hypr/custom/rules.lua") then + require("custom.rules") +end +if is_file_exists(HOME .. "/.config/hypr/custom/keybinds.lua") then + require("custom.keybinds") +end -- nwg-displays support: re-add the files if it updates later -- require("workspaces") -- require("monitors") -- Shell overrides -- -require("hyprland/shellOverrides/main") +require("hyprland.shellOverrides.main") diff --git a/dots/.config/hypr/hyprland/keybinds.lua b/dots/.config/hypr/hyprland/keybinds.lua index e043f9794..d6fec3485 100644 --- a/dots/.config/hypr/hyprland/keybinds.lua +++ b/dots/.config/hypr/hyprland/keybinds.lua @@ -1,18 +1,17 @@ +require("hyprland.lib") require("hyprland.variables") -require("custom.variables") +if is_file_exists(HOME .. "/.config/hypr/custom/variables.lua") then + require("custom.variables") +end +if is_file_exists(HOME .. "/.config/hypr/custom/keybinds.lua") then + require("custom.keybinds") +end local qsScripts = "$HOME/.config/quickshell/$qsConfig/scripts" local hyprScripts = "$HOME/.config/hypr/hyprland/scripts" local qsIpcCall = "qs -c $qsConfig ipc call" local qsIsAlive = qsIpcCall .. " TEST_ALIVE" -function WorkspaceInGroup(i) - local curr = hl.get_active_workspace().id - local newVal = math.floor((curr - 1) / workspaceGroupSize) * workspaceGroupSize + i - -- hl.notification.create({ text = "curr " .. curr .. " floor " .. math.floor(curr / 10) .. " new " .. newVal, duration = 5000 }) - return newVal -end - hl.bind("SUPER + SUPER_L", hl.dsp.global("quickshell:searchToggleRelease"), { description = "Shell: Toggle search" }) hl.bind("SUPER + SUPER_R", hl.dsp.global("quickshell:searchToggleRelease")) hl.bind("SUPER + SUPER_L", hl.dsp.exec_cmd(qsIsAlive .. " || pkill fuzzel || fuzzel")) @@ -23,9 +22,8 @@ hl.bind("SUPER_R", hl.dsp.global("quickshell:workspaceNumber"), { ignore_mods = hl.bind("SUPER_L", hl.dsp.global("quickshell:workspaceNumber"), { ignore_mods = true, transparent = true, release = true }) hl.bind("SUPER_R", hl.dsp.global("quickshell:workspaceNumber"), { ignore_mods = true, transparent = true, release = true }) hl.bind("SUPER + Tab", hl.dsp.global("quickshell:overviewWorkspacesToggle"), { description = "Shell: Toggle overview" }) -hl.bind("SUPER + V", hl.dsp.global("quickshell:overviewClipboardToggle"), - { description = "Shell: Clipboard history >> clipboard" }) -hl.bind("SUPER + Period", hl.dsp.global("quickshell:overviewEmojiToggle"), { description = "Shell: Emoji >> clipboard" }) +hl.bind("SUPER + V", hl.dsp.global("quickshell:overviewClipboardToggle")) +hl.bind("SUPER + Period", hl.dsp.global("quickshell:overviewEmojiToggle")) hl.bind("SUPER + A", hl.dsp.global("quickshell:sidebarLeftToggle"), { description = "Shell: Toggle left sidebar" }) hl.bind("SUPER + ALT + A", hl.dsp.global("quickshell:sidebarLeftToggleDetach")) hl.bind("SUPER + B", hl.dsp.global("quickshell:sidebarLeftToggle")) @@ -53,6 +51,8 @@ hl.bind("CTRL + SUPER + T", hl.dsp.global("quickshell:wallpaperSelectorToggle"), { description = "Shell: Toggle wallpaper selector" }) hl.bind("CTRL + SUPER + ALT + T", hl.dsp.global("quickshell:wallpaperSelectorRandom"), { description = "Shell: Select random wallpaper" }) +hl.bind("CTRL + SUPER + SHIFT + D", hl.dsp.global("quickshell:toggleLightDark"), + { description = "Shell: Toggle light/dark mode" }) hl.bind("CTRL + SUPER + T", hl.dsp.exec_cmd(qsIsAlive .. " || " .. qsScripts .. "/colors/switchwall.sh")) hl.bind("CTRL + SUPER + R", hl.dsp.exec_cmd("killall ydotool qs quickshell; qs -c $qsConfig &"), { description = "Shell: Restart widgets" }) @@ -151,14 +151,14 @@ hl.bind("SUPER + P", hl.dsp.window.pin(), { description = "Window: Pin" }) for i = 1, 10 do local numberkey = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 } hl.bind("SUPER + ALT + code:" .. numberkey[i], function() - hl.dispatch(hl.dsp.window.move({ workspace = WorkspaceInGroup(i), follow = false })) + hl.dispatch(hl.dsp.window.move({ workspace = workspace_in_group(i), follow = false })) end) end --# keypad numbers for i = 1, 10 do local numpadkey = { 87, 88, 89, 83, 84, 85, 79, 80, 81, 90 } hl.bind("SUPER + ALT + code:" .. numpadkey[i], function() - hl.dispatch(hl.dsp.window.move({ workspace = WorkspaceInGroup(i), follow = false })) + hl.dispatch(hl.dsp.window.move({ workspace = workspace_in_group(i), follow = false })) end) end @@ -180,7 +180,7 @@ for i = 1, 6 do end hl.bind("SUPER + ALT + S", - hl.dsp.window.move({ workspace = "special:special", follow = false, description = "Window: Send to scratchpad" })) + hl.dsp.window.move({ workspace = "special:special", follow = false }), {description = "Window: Send to scratchpad"}) hl.bind("CTRL + SUPER + S", hl.dsp.workspace.toggle_special("special")) --##! Workspace @@ -190,14 +190,14 @@ hl.bind("CTRL + SUPER + S", hl.dsp.workspace.toggle_special("special")) for i = 1, 10 do local numberkey = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 } hl.bind("SUPER + code:" .. numberkey[i], function() - hl.dispatch(hl.dsp.focus({ workspace = WorkspaceInGroup(i) })) + hl.dispatch(hl.dsp.focus({ workspace = workspace_in_group(i) })) end) end --# keypad numbers for i = 1, 10 do local numpadkey = { 87, 88, 89, 83, 84, 85, 79, 80, 81, 90 } hl.bind("SUPER + code:" .. numpadkey[i], function() - hl.dispatch(hl.dsp.focus({ workspace = WorkspaceInGroup(i) })) + hl.dispatch(hl.dsp.focus({ workspace = workspace_in_group(i) })) end) end diff --git a/dots/.config/hypr/hyprland/lib/init.lua b/dots/.config/hypr/hyprland/lib/init.lua new file mode 100644 index 000000000..a82154290 --- /dev/null +++ b/dots/.config/hypr/hyprland/lib/init.lua @@ -0,0 +1,27 @@ +HOME = os.getenv("HOME") + +function is_file_exists(name) + local f = io.open(name, "r") + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +function create_if_not_exists(path) + if not is_file_exists(path) then + os.execute("mkdir -p \"$(dirname \"" .. path .. "\")\"") + os.execute("echo '-- This file will not be overwritten across dots-hyprland updates.\n-- The file name is for the sake of organization and does not matter\n-- See the corresponding files in ~/.config/hypr/hyprland for examples' > \"" .. path .. "\"") + return true + end + return false +end + +function workspace_in_group(i) + local curr = hl.get_active_workspace().id + local newVal = math.floor((curr - 1) / workspaceGroupSize) * workspaceGroupSize + i + -- hl.notification.create({ text = "curr " .. curr .. " floor " .. math.floor(curr / 10) .. " new " .. newVal, duration = 5000 }) + return newVal +end diff --git a/dots/.config/hypr/hyprland/rules.lua b/dots/.config/hypr/hyprland/rules.lua index ed80b0082..14611d5a6 100644 --- a/dots/.config/hypr/hyprland/rules.lua +++ b/dots/.config/hypr/hyprland/rules.lua @@ -77,9 +77,6 @@ hl.window_rule({match = {title = ".*\\.exe" }, immediate = true}) hl.window_rule({match = {title = ".*minecraft.*" }, immediate = true}) hl.window_rule({match = {class = "^(steam_app).*" }, immediate = true}) --- Fix Jetbrain IDEs focus/rerendering problem -hl.window_rule({match = {class = "^jetbrains-.*$", float = 1, title = "^$|^\\s$|^win\\d+$" }, no_initial_focus = true}) - -- No shadow for tiled windows hl.window_rule({match = {float = 0 }, no_shadow = true}) diff --git a/dots/.config/hypr/hyprland/services/create_custom_config.lua b/dots/.config/hypr/hyprland/services/create_custom_config.lua new file mode 100644 index 000000000..119c8f46c --- /dev/null +++ b/dots/.config/hypr/hyprland/services/create_custom_config.lua @@ -0,0 +1,29 @@ +require("hyprland/lib") + +hl.on("hyprland.start", function() + local homeDir = os.getenv("HOME") + if string.len(homeDir) == 0 then + return + end + local baseCustomDir = homeDir .. "/.config/hypr/custom" + local files = { + baseCustomDir .. "/env.lua", + baseCustomDir .. "/execs.lua", + baseCustomDir .. "/general.lua", + baseCustomDir .. "/keybinds.lua", + baseCustomDir .. "/rules.lua", + baseCustomDir .. "/variables.lua" + } + local createdFiles = 0 + for _, file in ipairs(files) do + if not is_file_exists(file) then + create_if_not_exists(file) + createdFiles = createdFiles + 1 + end + end + + if createdFiles > 0 then + -- hl.exec_cmd("notify-send 'Hyprland config' 'Created " .. createdFiles .. " custom Hyprland config files in " .. baseCustomDir .. "' -a 'Hyprland'") + -- hl.exec_cmd("hyprctl reload") + end +end) diff --git a/dots/.config/hypr/hyprland/services/init.lua b/dots/.config/hypr/hyprland/services/init.lua new file mode 100644 index 000000000..e93a3035f --- /dev/null +++ b/dots/.config/hypr/hyprland/services/init.lua @@ -0,0 +1 @@ +require("hyprland/services/create_custom_config") diff --git a/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml index ff194e562..aab5a993f 100644 --- a/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml +++ b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybinds.qml @@ -10,76 +10,9 @@ import Quickshell Item { id: root - readonly property var keybinds: HyprlandKeybinds.keybinds.filter(function(keybind) { - return keybind.has_description; - }) - property real columnSpacing: 40 - property real titleSpacing: 7 property real padding: 4 - implicitWidth: QsWindow.window.screen.width * 0.7 - implicitHeight: QsWindow.window.screen.height * 0.7 - // Excellent symbol explaination and source : - // http://xahlee.info/comp/unicode_computing_symbols.html - // https://www.nerdfonts.com/cheat-sheet - property var macSymbolMap: ({ - "Ctrl": "󰘴", - "Alt": "󰘵", - "Shift": "󰘶", - "Space": "󱁐", - "Tab": "↹", - "Equal": "󰇼", - "Minus": "", - "Print": "", - "BackSpace": "󰭜", - "Delete": "⌦", - "Return": "󰌑", - "Period": ".", - "Escape": "⎋" - }) - property var functionSymbolMap: ({ - "F1": "󱊫", - "F2": "󱊬", - "F3": "󱊭", - "F4": "󱊮", - "F5": "󱊯", - "F6": "󱊰", - "F7": "󱊱", - "F8": "󱊲", - "F9": "󱊳", - "F10": "󱊴", - "F11": "󱊵", - "F12": "󱊶", - }) - - property var mouseSymbolMap: ({ - "mouse_up": "󱕐", - "mouse_down": "󱕑", - "mouse:272": "L󰍽", - "mouse:273": "R󰍽", - "Scroll ↑/↓": "󱕒", - "Page_↑/↓": "⇞/⇟", - }) - - property var keyBlacklist: ["SUPER_L", "SUPER_R"] - property var keySubstitutions: Object.assign({ - "Super": "", - "mouse_up": "Scroll ↓", // ikr, weird - "mouse_down": "Scroll ↑", // trust me bro - "mouse:272": "LMB", - "mouse:273": "RMB", - "mouse:275": "MouseBack", - "Slash": "/", - "Hash": "#", - "Return": "Enter", - // "Shift": "", - }, - !!Config.options.cheatsheet.superKey ? { - "Super": Config.options.cheatsheet.superKey, - }: {}, - Config.options.cheatsheet.useMacSymbol ? macSymbolMap : {}, - Config.options.cheatsheet.useFnSymbol ? functionSymbolMap : {}, - Config.options.cheatsheet.useMouseSymbol ? mouseSymbolMap : {}, - ) + implicitWidth: QsWindow?.window?.screen.width * 0.7 ?? 0 + implicitHeight: QsWindow?.window?.screen.height * 0.7 ?? 0 StyledFlickable { id: flickable @@ -91,79 +24,12 @@ Item { id: flow height: flickable.height flow: Flow.TopToBottom - spacing: 4 + spacing: 12 Repeater { - model: root.keybinds - delegate: BindLine { + model: [...HyprlandKeybinds.keybindCategories, ""] + delegate: CheatsheetKeybindsCategory { required property var modelData - keyData: modelData - } - } - } - } - - function modMaskToStringList(modMask: int): list { - var list = []; - if (modMask & (1 << 0)) { list.push("Shift"); } - if (modMask & (1 << 1)) { list.push("Caps"); } - if (modMask & (1 << 2)) { list.push("Ctrl"); } - if (modMask & (1 << 3)) { list.push("Alt"); } - if (modMask & (1 << 4)) { list.push("Mod2"); } - if (modMask & (1 << 5)) { list.push("Mod3"); } - if (modMask & (1 << 6)) { list.push("Super"); } - if (modMask & (1 << 7)) { list.push("Mod5"); } - return list; - } - - property int maxBindWidth: 0 - - component BindLine: Row { - required property var keyData - Row { - spacing: 16 - Row { - id: modRow - Component.onCompleted: root.maxBindWidth = Math.max(root.maxBindWidth, implicitWidth) - width: root.maxBindWidth - spacing: 4 - Repeater { - model: { - const modList = root.modMaskToStringList(keyData.modmask) - if (modList.length == 0) return [] - if (Config.options.cheatsheet.splitButtons) return modList; - return [modList.join(" ")] - } - delegate: KeyboardKey { - required property var modelData - key: root.keySubstitutions[modelData] || modelData - pixelSize: Config.options.cheatsheet.fontSize.key - } - } - StyledText { - id: keybindPlus - anchors.verticalCenter: parent.verticalCenter - visible: !keyBlacklist.includes(keyData.key) && keyData.modmask > 0 - text: "+" - } - KeyboardKey { - id: keybindKey - anchors.verticalCenter: parent.verticalCenter - visible: !keyBlacklist.includes(keyData.key) - key: StringUtils.toTitleCase(root.keySubstitutions[keyData.key] || keyData.key) - pixelSize: Config.options.cheatsheet.fontSize.key - color: Appearance.colors.colOnLayer0 - } - } - Item { - anchors.verticalCenter: parent.verticalCenter - implicitWidth: commentText.implicitWidth + root.columnSpacing - implicitHeight: commentText.implicitHeight - StyledText { - id: commentText - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - font.pixelSize: Config.options.cheatsheet.fontSize.comment || Appearance.font.pixelSize.smaller - text: keyData.description + categoryName: modelData } } } diff --git a/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybindsCategory.qml b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybindsCategory.qml new file mode 100644 index 000000000..7189837dd --- /dev/null +++ b/dots/.config/quickshell/ii/modules/ii/cheatsheet/CheatsheetKeybindsCategory.qml @@ -0,0 +1,177 @@ +pragma ComponentBehavior: Bound + +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import QtQuick +import QtQuick.Layouts +import Quickshell + +Column { + id: root + required property string categoryName + readonly property bool isCategorized: categoryName?.length > 0 + property int maxBindWidth: 0 + property real columnSpacing: 40 + property real titleSpacing: 7 + + // Excellent symbol explaination and source : + // http://xahlee.info/comp/unicode_computing_symbols.html + // https://www.nerdfonts.com/cheat-sheet + property var macSymbolMap: ({ + "Ctrl": "󰘴", + "Alt": "󰘵", + "Shift": "󰘶", + "Space": "󱁐", + "Tab": "↹", + "Equal": "󰇼", + "Minus": "", + "Print": "", + "BackSpace": "󰭜", + "Delete": "⌦", + "Return": "󰌑", + "Period": ".", + "Escape": "⎋" + }) + property var functionSymbolMap: ({ + "F1": "󱊫", + "F2": "󱊬", + "F3": "󱊭", + "F4": "󱊮", + "F5": "󱊯", + "F6": "󱊰", + "F7": "󱊱", + "F8": "󱊲", + "F9": "󱊳", + "F10": "󱊴", + "F11": "󱊵", + "F12": "󱊶", + }) + + property var mouseSymbolMap: ({ + "mouse_up": "󱕐", + "mouse_down": "󱕑", + "mouse:272": "L󰍽", + "mouse:273": "R󰍽", + "Scroll ↑/↓": "󱕒", + "Page_↑/↓": "⇞/⇟", + }) + + property var keyBlacklist: ["SUPER_L", "SUPER_R"] + property var keySubstitutions: Object.assign({ + "Super": "", + "mouse_up": "Scroll ↓", // ikr, weird + "mouse_down": "Scroll ↑", // trust me bro + "mouse:272": "LMB", + "mouse:273": "RMB", + "mouse:275": "MouseBack", + "Slash": "/", + "Hash": "#", + "Return": "Enter", + // "Shift": "", + }, + !!Config.options.cheatsheet.superKey ? { + "Super": Config.options.cheatsheet.superKey, + }: {}, + Config.options.cheatsheet.useMacSymbol ? macSymbolMap : {}, + Config.options.cheatsheet.useFnSymbol ? functionSymbolMap : {}, + Config.options.cheatsheet.useMouseSymbol ? mouseSymbolMap : {}, + ) + + function modMaskToStringList(modMask: int): list { + var list = []; + // Funny mathematical order but we wanna have this natural user-facing order + if (modMask & (1 << 2)) { list.push("Ctrl"); } + if (modMask & (1 << 6)) { list.push("Super"); } + if (modMask & (1 << 0)) { list.push("Shift"); } + if (modMask & (1 << 3)) { list.push("Alt"); } + if (modMask & (1 << 1)) { list.push("Caps"); } + if (modMask & (1 << 4)) { list.push("Mod2"); } + if (modMask & (1 << 5)) { list.push("Mod3"); } + if (modMask & (1 << 7)) { list.push("Mod5"); } + return list; + } + + spacing: titleSpacing + + StyledText { + text: root.isCategorized ? root.categoryName : "Uncategorized" + font.pixelSize: Appearance.font.pixelSize.title + } + + Column { + spacing: 4 + Repeater { + model: { + if (!root.isCategorized) { + return HyprlandKeybinds.keybinds.filter(bind => bind.description?.length > 0 && bind.description.indexOf(":") === -1); + } + return HyprlandKeybinds.keybinds.filter(bind => bind.description?.length > 0 && bind.description.substring(0, bind.description.indexOf(":")) === root.categoryName); + } + delegate: BindLine { + required property var modelData + keyData: modelData + categoryName: root.categoryName + } + } + } + + component BindLine: Row { + id: bindLine + required property var keyData + property string categoryName: "" + + Row { + spacing: 16 + Row { + id: modRow + Component.onCompleted: root.maxBindWidth = Math.max(root.maxBindWidth, implicitWidth) + width: root.maxBindWidth + spacing: 4 + Repeater { + model: { + const modList = root.modMaskToStringList(bindLine.keyData.modmask).map(mod => root.keySubstitutions[mod] || mod) + if (modList.length == 0) return [] + if (Config.options.cheatsheet.splitButtons) return modList; + return [modList.join(" ")] + } + delegate: KeyboardKey { + required property var modelData + key: modelData + pixelSize: Config.options.cheatsheet.fontSize.key + } + } + StyledText { + id: keybindPlus + anchors.verticalCenter: parent.verticalCenter + visible: !keyBlacklist.includes(bindLine.keyData.key) && bindLine.keyData.modmask > 0 + text: "+" + } + KeyboardKey { + id: keybindKey + anchors.verticalCenter: parent.verticalCenter + visible: !keyBlacklist.includes(bindLine.keyData.key) + key: StringUtils.toTitleCase(root.keySubstitutions[bindLine.keyData.key] || bindLine.keyData.key) + pixelSize: Config.options.cheatsheet.fontSize.key + color: Appearance.colors.colOnLayer0 + } + } + Item { + anchors.verticalCenter: parent.verticalCenter + implicitWidth: commentText.implicitWidth + root.columnSpacing + implicitHeight: commentText.implicitHeight + StyledText { + id: commentText + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + font.pixelSize: Config.options.cheatsheet.fontSize.comment || Appearance.font.pixelSize.smaller + text: { + const regex = new RegExp("\\s*" + bindLine.categoryName + "\\s*:\\s*"); + return bindLine.keyData.description.replace(regex, ""); + } + } + } + } + } +} \ No newline at end of file diff --git a/dots/.config/quickshell/ii/services/HyprlandKeybinds.qml b/dots/.config/quickshell/ii/services/HyprlandKeybinds.qml index f24c6e055..4c3e73bf3 100644 --- a/dots/.config/quickshell/ii/services/HyprlandKeybinds.qml +++ b/dots/.config/quickshell/ii/services/HyprlandKeybinds.qml @@ -15,6 +15,7 @@ import Quickshell.Hyprland Singleton { id: root property var keybinds: [] + property var keybindCategories: [] Connections { target: Hyprland @@ -35,6 +36,15 @@ Singleton { onStreamFinished: { try { root.keybinds = JSON.parse(text) + var groups = [] + for (var i = 0; i < root.keybinds.length; i++) { + var bind = root.keybinds[i].description + var group = bind.substring(0, bind.indexOf(":")) + if (!groups.includes(group) && group.length > 0) { + groups.push(group) + } + } + root.keybindCategories = groups } catch (e) { console.error("[CheatsheetKeybinds] Error parsing keybinds:", e) } diff --git a/dots/.config/quickshell/ii/services/MaterialThemeLoader.qml b/dots/.config/quickshell/ii/services/MaterialThemeLoader.qml index cd81ca07e..6012566d3 100644 --- a/dots/.config/quickshell/ii/services/MaterialThemeLoader.qml +++ b/dots/.config/quickshell/ii/services/MaterialThemeLoader.qml @@ -5,6 +5,7 @@ import qs.modules.common import QtQuick import Quickshell import Quickshell.Io +import Quickshell.Hyprland /** * Automatically reloads generated material colors. @@ -71,4 +72,26 @@ Singleton { } onLoadFailed: root.resetFilePathNextTime(); } + + function toggleLightDark() { + const currentlyDark = Appearance.m3colors.darkmode; + Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", currentlyDark ? "light" : "dark", "--noswitch"]); + } + + GlobalShortcut { + name: "toggleLightDark" + description: "Toggles between dark theme and light theme" + + onPressed: { + root.toggleLightDark(); + } + } + + IpcHandler { + target: "theme" + + function toggleLightDark(): void { + root.toggleLightDark(); + } + } }