885 lines
39 KiB
Nix
885 lines
39 KiB
Nix
{ inputs, lib, pkgs, ... }:
|
|
let
|
|
assets = "${inputs.self}/assets";
|
|
upstream = "${inputs.arch-hyprland}/.config";
|
|
dots = "${inputs.dots-hyprland}/dots";
|
|
wallpaper = "${assets}/wallpaper/wallpaper.png";
|
|
iconDataDirs = lib.makeSearchPath "share" [
|
|
pkgs.kdePackages.breeze-icons
|
|
pkgs.adwaita-icon-theme
|
|
pkgs.hicolor-icon-theme
|
|
];
|
|
|
|
# end-4's shell is distributed as a Quickshell config, not a Waybar theme.
|
|
# Keep the launcher wrapped so the extra QML modules used by the upstream
|
|
# config are visible to Nixpkgs' Quickshell package.
|
|
qsWrapper = pkgs.writeShellScriptBin "qs" ''
|
|
export XDG_DATA_DIRS="${iconDataDirs}''${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"
|
|
export QML2_IMPORT_PATH="${lib.makeSearchPath "lib/qt-6/qml" [
|
|
pkgs.qt6Packages.qt5compat
|
|
pkgs.qt6Packages.qtimageformats
|
|
pkgs.qt6Packages.qtmultimedia
|
|
pkgs.qt6Packages.qtpositioning
|
|
pkgs.qt6Packages.qtquicktimeline
|
|
pkgs.qt6Packages.qtsensors
|
|
pkgs.qt6Packages.qtvirtualkeyboard
|
|
# kirigami is a wrapped package in Nixpkgs; its wrapper has no QML
|
|
# files. Quickshell needs the unwrapped runtime output here.
|
|
pkgs.kdePackages.kirigami.unwrapped
|
|
pkgs.kdePackages.qqc2-desktop-style
|
|
pkgs.kdePackages.syntax-highlighting
|
|
pkgs.quickshell
|
|
]}''${QML2_IMPORT_PATH:+:$QML2_IMPORT_PATH}"
|
|
exec ${pkgs.quickshell}/bin/qs "$@"
|
|
'';
|
|
|
|
quickshellPython = pkgs.python3.withPackages (pythonPackages: with pythonPackages; [
|
|
materialyoucolor
|
|
pillow
|
|
]);
|
|
|
|
quickshellConfig = pkgs.runCommand "ena-quickshell-config" {} ''
|
|
mkdir -p "$out"
|
|
cp -R ${dots}/.config/quickshell/ii/. "$out/"
|
|
chmod -R u+w "$out"
|
|
mkdir -p "$out/defaults/ai/prompts"
|
|
ln -s ${assets}/prompt/mizuki.md "$out/defaults/ai/prompts/mizuki.md"
|
|
cp ${./quickshell/OpenAiApiStrategy.qml} "$out/services/ai/OpenAiApiStrategy.qml"
|
|
rm -rf "$out/modules/common/widgets/shapes"
|
|
mkdir -p "$out/modules/common/widgets/shapes"
|
|
cp -R ${inputs.rounded-polygon-qmljs}/. "$out/modules/common/widgets/shapes/"
|
|
substituteInPlace "$out/modules/common/Config.qml" \
|
|
--replace-fail 'property string wallpaperPath: ""' 'property string wallpaperPath: "${wallpaper}"'
|
|
substituteInPlace "$out/services/Wallpapers.qml" \
|
|
--replace-fail '`''${Directories.pictures}/Wallpapers`' '`''${Directories.pictures}/wallpapers`'
|
|
substituteInPlace "$out/services/Ai.qml" \
|
|
--replace-fail ' root.addUserModels() // Config onReadyChanged above might not fire if config is loaded before this service' \
|
|
' root.addUserModels() // Config onReadyChanged above might not fire if config is loaded before this service
|
|
root.loadPrompt(`''${Directories.defaultAiPrompts}/mizuki.md`);
|
|
KeyringStorage.fetchKeyringData();'
|
|
substituteInPlace "$out/services/Ai.qml" \
|
|
--replace-fail ' root.addMessage(Translation.tr("Loaded the following system prompt\n\n---\n\n%1").arg(Config.options.ai.systemPrompt), root.interfaceRole);' \
|
|
' // Keep the system prompt internal; do not render it in the chat.'
|
|
substituteInPlace "$out/services/Ai.qml" \
|
|
--replace-fail ' if (requester.message.thinking) requester.message.thinking = false;' \
|
|
' // Responses emits metadata events before visible text. Keep the loading indicator
|
|
// until the parser has actually appended content or finished the response.'
|
|
substituteInPlace "$out/services/Ai.qml" \
|
|
--replace-fail ' const result = requester.currentStrategy.parseResponseLine(data, requester.message);' \
|
|
' const result = requester.currentStrategy.parseResponseLine(data, requester.message);
|
|
if (requester.message.thinking && (requester.message.content.length > 0 || result.functionCall || result.finished)) requester.message.thinking = false;'
|
|
substituteInPlace "$out/services/Ai.qml" \
|
|
--replace-fail ' // Fetch API keys if needed' \
|
|
' if (model?.requires_key && !KeyringStorage.loaded) {
|
|
KeyringStorage.fetchKeyringData();
|
|
root.addMessage(Translation.tr("API key is still loading. Please try again in a moment."), root.interfaceRole);
|
|
return;
|
|
}
|
|
if (model?.requires_key && !root.currentModelHasApiKey) {
|
|
root.addApiKeyAdvice(model);
|
|
return;
|
|
}
|
|
|
|
// Fetch API keys if needed'
|
|
substituteInPlace "$out/services/Ai.qml" \
|
|
--replace-fail ' const result = requester.currentStrategy.onRequestFinished(requester.message);' \
|
|
' if (!requester.message.done && requester.message.content.length === 0) {
|
|
const reason = exitCode === 0
|
|
? Translation.tr("The API returned no visible text. Check the API key and endpoint.")
|
|
: Translation.tr("The API request exited with code %1.").arg(exitCode);
|
|
requester.message.rawContent = "**Error**: " + reason;
|
|
requester.message.content = requester.message.rawContent;
|
|
}
|
|
const result = requester.currentStrategy.onRequestFinished(requester.message);'
|
|
substituteInPlace "$out/services/Ai.qml" \
|
|
--replace-fail ' property list<var> availableTools: Object.keys(root.tools[models[currentModelId]?.api_format])' \
|
|
' property list<var> availableTools: Object.keys(root.tools[models[currentModelId]?.api_format] ?? {})'
|
|
substituteInPlace "$out/modules/ii/sidebarLeft/AiChat.qml" \
|
|
--replace-fail ' text: Ai.getModel().name' ' text: Ai.getModel()?.name ?? Translation.tr("Loading model")' \
|
|
--replace-fail ' tooltipText: Translation.tr("Current model: %1\nSet it with %2model MODEL").arg(Ai.getModel().name).arg(root.commandPrefix)' ' tooltipText: Translation.tr("Current model: %1\nSet it with %2model MODEL").arg(Ai.getModel()?.name ?? Translation.tr("Loading model")).arg(root.commandPrefix ?? "/")'
|
|
substituteInPlace "$out/modules/ii/sidebarLeft/aiChat/AiMessage.qml" \
|
|
--replace-fail " visible: messageData?.role == 'assistant' && Ai.models[messageData?.model].icon" " visible: messageData?.role == 'assistant' && Ai.models[messageData?.model]?.icon" \
|
|
--replace-fail " source: messageData?.role == 'assistant' ? Ai.models[messageData?.model].icon :" " source: messageData?.role == 'assistant' ? (Ai.models[messageData?.model]?.icon ?? String()) :" \
|
|
--replace-fail " text: messageData?.role == 'assistant' ? Ai.models[messageData?.model].name :" " text: messageData?.role == 'assistant' ? (Ai.models[messageData?.model]?.name ?? messageData?.model ?? Translation.tr('Assistant')) :"
|
|
substituteInPlace "$out/modules/common/Config.qml" \
|
|
--replace-fail 'property string terminal: "kitty -1"' 'property string terminal: "ghostty"' \
|
|
--replace-fail 'property string volumeMixer: `~/.config/hypr/hyprland/scripts/launch_first_available.sh "pavucontrol-qt" "pavucontrol"`' 'property string volumeMixer: "pavucontrol"'
|
|
sed -i '/ property list<var> extraModels: \[/,/ \]/c\
|
|
property list<var> extraModels: []' "$out/modules/common/Config.qml"
|
|
sed -i '/ property var models: Config.options.policies.ai === 2 ? {} : {/,/ property var modelList: Object.keys(root.models)/c\
|
|
property var models: Config.options.policies.ai === 2 ? {} : {\
|
|
"gpt-5.6-luna": aiModelComponent.createObject(this, {\
|
|
"name": "GPT-5.6 Luna",\
|
|
"icon": "spark-symbolic",\
|
|
"description": Translation.tr("OpenAI model optimized for cost-sensitive workloads"),\
|
|
"homepage": "https://developers.openai.com/api/docs/models/gpt-5.6-luna",\
|
|
"endpoint": "https://api.openai.com/v1/responses",\
|
|
"model": "gpt-5.6-luna",\
|
|
"requires_key": true,\
|
|
"key_id": "openai",\
|
|
"key_get_link": "https://platform.openai.com/api-keys",\
|
|
"key_get_description": Translation.tr("Use an OpenAI API key. API usage is billed separately from ChatGPT."),\
|
|
"api_format": "openai",\
|
|
}),\
|
|
}\
|
|
property var modelList: Object.keys(root.models)' "$out/services/Ai.qml"
|
|
sed -i '/ function addUserModels() {/,/^ }$/c\
|
|
function addUserModels() {\
|
|
}' "$out/services/Ai.qml"
|
|
sed -i '/ id: getOllamaModels/{n;s/running: true/running: false/;}' "$out/services/Ai.qml"
|
|
substituteInPlace "$out/scripts/colors/switchwall.sh" \
|
|
--replace-fail 'source "$(eval echo $ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate"' ':' \
|
|
--replace-fail 'deactivate' ':'
|
|
'';
|
|
|
|
quickshellStart = pkgs.writeShellScript "ena-quickshell-start" ''
|
|
set -eu
|
|
export XDG_DATA_DIRS="${iconDataDirs}''${XDG_DATA_DIRS:+:$XDG_DATA_DIRS}"
|
|
state_home="''${XDG_STATE_HOME:-$HOME/.local/state}"
|
|
mkdir -p "$state_home/quickshell/user"
|
|
generated_dir="$state_home/quickshell/user/generated"
|
|
mkdir -p "$generated_dir"
|
|
cat > "$generated_dir/colors.json" <<'EOF'
|
|
${quickshellColorsJson}
|
|
EOF
|
|
if [ ! -e "$state_home/quickshell/user/first_run.txt" ]; then
|
|
printf '%s\n' 'Managed by NixOS' > "$state_home/quickshell/user/first_run.txt"
|
|
fi
|
|
export PATH="${quickshellPython}/bin:$PATH"
|
|
exec ${qsWrapper}/bin/qs -n -c ii
|
|
'';
|
|
|
|
quickshellToggleSearch = pkgs.writeShellScript "ena-quickshell-toggle-search" ''
|
|
set -eu
|
|
export PATH="${quickshellPython}/bin:$PATH"
|
|
|
|
if ${qsWrapper}/bin/qs -c ii ipc call search toggle >/dev/null 2>&1; then
|
|
exit 0
|
|
fi
|
|
|
|
${pkgs.systemd}/bin/systemctl --user start ena-quickshell.service
|
|
for attempt in $(${pkgs.coreutils}/bin/seq 1 50); do
|
|
if ${qsWrapper}/bin/qs -c ii ipc call search toggle >/dev/null 2>&1; then
|
|
exit 0
|
|
fi
|
|
${pkgs.coreutils}/bin/sleep 0.1
|
|
done
|
|
exit 1
|
|
'';
|
|
|
|
selectHangul = pkgs.writeShellScript "ena-select-hangul" ''
|
|
for attempt in $(${pkgs.coreutils}/bin/seq 1 20); do
|
|
if ${pkgs.fcitx5}/bin/fcitx5-remote --check; then
|
|
${pkgs.fcitx5}/bin/fcitx5-remote -s hangul
|
|
exit 0
|
|
fi
|
|
${pkgs.coreutils}/bin/sleep 0.5
|
|
done
|
|
exit 0
|
|
'';
|
|
|
|
screenshotArea = pkgs.writeShellScript "ena-screenshot-area" ''
|
|
set -eu
|
|
geometry="$(${pkgs.slurp}/bin/slurp -d)" || exit 0
|
|
[ -n "$geometry" ] || exit 0
|
|
${pkgs.grim}/bin/grim -g "$geometry" - | ${pkgs.satty}/bin/satty --filename -
|
|
'';
|
|
|
|
screenshotScreen = pkgs.writeShellScript "ena-screenshot-screen" ''
|
|
set -eu
|
|
${pkgs.grim}/bin/grim - | ${pkgs.satty}/bin/satty --filename -
|
|
'';
|
|
|
|
scratchpad = pkgs.writeShellScript "ena-scratchpad" ''
|
|
hyprctl="${pkgs.hyprland}/bin/hyprctl"
|
|
if "$hyprctl" clients -j | ${pkgs.jq}/bin/jq -e 'any(.[]; .class == "org.imnyang.scratchpad")' >/dev/null; then
|
|
"$hyprctl" dispatch togglespecialworkspace scratchpad
|
|
else
|
|
"$hyprctl" dispatch exec "[workspace special:scratchpad;float;size 80% 70%;center] ${pkgs.ghostty}/bin/ghostty --gtk-single-instance=false --class=org.imnyang.scratchpad"
|
|
fi
|
|
'';
|
|
|
|
# Shared Mizuki Dark palette. The UI colors follow Zed's One Dark theme,
|
|
# while the foreground and terminal colors follow Ghostty's dark theme.
|
|
lightColors = {
|
|
background = "191017";
|
|
foreground = "fafafa";
|
|
cursor = "fafafa";
|
|
selection = "2c1f2d";
|
|
primary = "f5c2e7";
|
|
primaryContainer = "4a354c";
|
|
primaryFixedDim = "f5c2e7";
|
|
secondary = "bac2de";
|
|
secondaryContainer = "2c1f2d";
|
|
secondaryFixedDim = "bac2de";
|
|
tertiary = "89b4fa";
|
|
tertiaryContainer = "4a354c";
|
|
outline = "a38f96";
|
|
outlineVariant = "2c1f2d";
|
|
surfaceBright = "4a354c";
|
|
surfaceContainer = "2c1f2d";
|
|
surfaceContainerHigh = "4a354c";
|
|
surfaceContainerHighest = "604562";
|
|
surfaceContainerLow = "191017";
|
|
surfaceDim = "191017";
|
|
error = "f38ba8";
|
|
errorContainer = "4a354c";
|
|
};
|
|
rgba = color: "rgba(${color}ff)";
|
|
# Qt/QML colors use #AARRGGBB, unlike Hyprland's rgba(RRGGBBAA).
|
|
hex = color: "#ff${color}";
|
|
|
|
# MaterialThemeLoader reads this file at startup and applies its keys to
|
|
# Appearance.m3colors. Keep it sourced from the same palette as Hyprland,
|
|
# Zed, and Ghostty so the shell does not fall back to upstream defaults.
|
|
quickshellColorsJson = builtins.toJSON {
|
|
background = hex lightColors.background;
|
|
on_background = hex lightColors.foreground;
|
|
surface = hex lightColors.background;
|
|
surface_dim = hex lightColors.surfaceDim;
|
|
surface_bright = hex lightColors.surfaceBright;
|
|
surface_container_lowest = hex lightColors.surfaceBright;
|
|
surface_container_low = hex lightColors.surfaceContainerLow;
|
|
surface_container = hex lightColors.surfaceContainer;
|
|
surface_container_high = hex lightColors.surfaceContainerHigh;
|
|
surface_container_highest = hex lightColors.surfaceContainerHighest;
|
|
on_surface = hex lightColors.foreground;
|
|
surface_variant = hex lightColors.outlineVariant;
|
|
on_surface_variant = hex lightColors.outline;
|
|
inverse_surface = hex lightColors.foreground;
|
|
inverse_on_surface = hex lightColors.surfaceBright;
|
|
outline = hex lightColors.outline;
|
|
outline_variant = hex lightColors.outlineVariant;
|
|
shadow = hex lightColors.foreground;
|
|
scrim = "#ff000000";
|
|
surface_tint = hex lightColors.primary;
|
|
|
|
primary = hex lightColors.primary;
|
|
on_primary = hex lightColors.surfaceBright;
|
|
primary_container = hex lightColors.primaryContainer;
|
|
on_primary_container = hex lightColors.cursor;
|
|
inverse_primary = hex lightColors.primaryFixedDim;
|
|
secondary = hex lightColors.secondary;
|
|
on_secondary = hex lightColors.surfaceBright;
|
|
secondary_container = hex lightColors.secondaryContainer;
|
|
on_secondary_container = hex lightColors.foreground;
|
|
tertiary = hex lightColors.tertiary;
|
|
on_tertiary = hex lightColors.surfaceBright;
|
|
tertiary_container = hex lightColors.tertiaryContainer;
|
|
on_tertiary_container = hex lightColors.foreground;
|
|
error = hex lightColors.error;
|
|
on_error = hex lightColors.surfaceBright;
|
|
error_container = hex lightColors.errorContainer;
|
|
on_error_container = hex lightColors.foreground;
|
|
|
|
primary_fixed = hex lightColors.primaryContainer;
|
|
primary_fixed_dim = hex lightColors.primaryFixedDim;
|
|
on_primary_fixed = hex lightColors.cursor;
|
|
on_primary_fixed_variant = hex lightColors.primary;
|
|
secondary_fixed = hex lightColors.secondaryContainer;
|
|
secondary_fixed_dim = hex lightColors.secondaryFixedDim;
|
|
on_secondary_fixed = hex lightColors.foreground;
|
|
on_secondary_fixed_variant = hex lightColors.secondary;
|
|
tertiary_fixed = hex lightColors.tertiaryContainer;
|
|
tertiary_fixed_dim = hex lightColors.tertiary;
|
|
on_tertiary_fixed = hex lightColors.foreground;
|
|
on_tertiary_fixed_variant = hex lightColors.tertiary;
|
|
|
|
success = hex "a6e3a1";
|
|
on_success = hex lightColors.background;
|
|
success_container = hex lightColors.secondaryContainer;
|
|
on_success_container = hex "a6e3a1";
|
|
};
|
|
|
|
colorsConfig = ''
|
|
# Mizuki Dark: Zed One Dark surfaces + Ghostty Mizuki Dark accents.
|
|
$background = ${rgba lightColors.background}
|
|
$on_background = ${rgba lightColors.foreground}
|
|
$surface = ${rgba lightColors.background}
|
|
$surface_bright = ${rgba lightColors.surfaceBright}
|
|
$surface_container = ${rgba lightColors.surfaceContainer}
|
|
$surface_container_high = ${rgba lightColors.surfaceContainerHigh}
|
|
$surface_container_highest = ${rgba lightColors.surfaceContainerHighest}
|
|
$surface_container_low = ${rgba lightColors.surfaceContainerLow}
|
|
$surface_container_lowest = ${rgba lightColors.surfaceBright}
|
|
$surface_dim = ${rgba lightColors.surfaceDim}
|
|
$surface_tint = ${rgba lightColors.primary}
|
|
$surface_variant = ${rgba lightColors.outlineVariant}
|
|
$on_surface = ${rgba lightColors.foreground}
|
|
$on_surface_variant = ${rgba lightColors.outline}
|
|
|
|
$primary = ${rgba lightColors.primary}
|
|
$primary_container = ${rgba lightColors.primaryContainer}
|
|
$primary_fixed = ${rgba lightColors.primaryContainer}
|
|
$primary_fixed_dim = ${rgba lightColors.primaryFixedDim}
|
|
$on_primary = ${rgba lightColors.surfaceBright}
|
|
$on_primary_container = ${rgba lightColors.cursor}
|
|
$on_primary_fixed = ${rgba lightColors.cursor}
|
|
$on_primary_fixed_variant = ${rgba lightColors.primary}
|
|
|
|
$secondary = ${rgba lightColors.secondary}
|
|
$secondary_container = ${rgba lightColors.secondaryContainer}
|
|
$secondary_fixed = ${rgba lightColors.secondaryContainer}
|
|
$secondary_fixed_dim = ${rgba lightColors.secondaryFixedDim}
|
|
$on_secondary = ${rgba lightColors.surfaceBright}
|
|
$on_secondary_container = ${rgba lightColors.foreground}
|
|
$on_secondary_fixed = ${rgba lightColors.foreground}
|
|
$on_secondary_fixed_variant = ${rgba lightColors.secondary}
|
|
|
|
$tertiary = ${rgba lightColors.tertiary}
|
|
$tertiary_container = ${rgba lightColors.tertiaryContainer}
|
|
$tertiary_fixed = ${rgba lightColors.tertiaryContainer}
|
|
$tertiary_fixed_dim = ${rgba lightColors.tertiary}
|
|
$on_tertiary = ${rgba lightColors.surfaceBright}
|
|
$on_tertiary_container = ${rgba lightColors.foreground}
|
|
$on_tertiary_fixed = ${rgba lightColors.foreground}
|
|
$on_tertiary_fixed_variant = ${rgba lightColors.tertiary}
|
|
|
|
$outline = ${rgba lightColors.outline}
|
|
$outline_variant = ${rgba lightColors.outlineVariant}
|
|
$error = ${rgba lightColors.error}
|
|
$error_container = ${rgba lightColors.errorContainer}
|
|
$on_error = ${rgba lightColors.surfaceBright}
|
|
$on_error_container = ${rgba lightColors.foreground}
|
|
$inverse_surface = ${rgba lightColors.foreground}
|
|
$inverse_on_surface = ${rgba lightColors.surfaceBright}
|
|
$inverse_primary = ${rgba lightColors.primaryFixedDim}
|
|
$shadow = ${rgba lightColors.foreground}
|
|
$scrim = rgba(000000ff)
|
|
$source_color = ${rgba lightColors.primary}
|
|
|
|
# Ghostty Mizuki Dark ANSI palette, used by hyprlock and related widgets.
|
|
$color0 = rgba(5c5f77ff)
|
|
$color1 = rgba(f38ba8ff)
|
|
$color2 = rgba(a6e3a1ff)
|
|
$color3 = rgba(f9e2afff)
|
|
$color4 = rgba(89b4faff)
|
|
$color5 = rgba(f5c2e7ff)
|
|
$color6 = rgba(94e2d5ff)
|
|
$color7 = rgba(bac2deff)
|
|
$color8 = rgba(6c7086ff)
|
|
$color9 = rgba(f38ba8ff)
|
|
$color10 = rgba(a6e3a1ff)
|
|
$color11 = rgba(f9e2afff)
|
|
$color12 = rgba(89b4faff)
|
|
$color13 = rgba(f5c2e7ff)
|
|
$color14 = rgba(94e2d5ff)
|
|
$color15 = rgba(cdd6f4ff)
|
|
'';
|
|
|
|
sattyConfig = ''
|
|
[general]
|
|
fullscreen = "current-screen"
|
|
resize = { mode = "smart" }
|
|
floating-hack = true
|
|
corner-roundness = 12
|
|
initial-tool = "pointer"
|
|
copy-command = "${pkgs.wl-clipboard}/bin/wl-copy"
|
|
annotation-size-factor = 2
|
|
output-filename = "~/Pictures/Screenshots/%Y-%m-%d_%H-%M-%S.png"
|
|
early-exit = ["all"]
|
|
actions-on-enter = ["save-to-file", "save-to-clipboard"]
|
|
actions-on-escape = ["exit"]
|
|
no-window-decoration = true
|
|
primary-highlighter = "block"
|
|
notification-thumbnail = "screenshot"
|
|
|
|
[font]
|
|
family = "JetBrainsMono NFM"
|
|
style = "Regular"
|
|
fallback = ["Noto Sans CJK KR"]
|
|
|
|
[color-palette]
|
|
palette = [
|
|
"#f5c2e7ff",
|
|
"#89b4faff",
|
|
"#f38ba8ff",
|
|
"#a6e3a1ff",
|
|
"#f9e2afff",
|
|
"#94e2d5ff",
|
|
"#f5c2e7ff",
|
|
"#fafafaff",
|
|
]
|
|
'';
|
|
|
|
hyprlockConfig = builtins.replaceStrings
|
|
[
|
|
"color = $on_secondary_container"
|
|
"color = $secondary"
|
|
"font_color = $secondary"
|
|
"color = rgb(0,0,0) # color will be rendered initially until path is available"
|
|
]
|
|
[
|
|
"color = ${rgba lightColors.cursor}"
|
|
"color = ${rgba lightColors.primaryFixedDim}"
|
|
"font_color = ${rgba lightColors.primaryFixedDim}"
|
|
"color = ${rgba lightColors.background}"
|
|
]
|
|
(builtins.readFile "${upstream}/hypr/hyprlock.conf");
|
|
|
|
keybindHelpText = ''
|
|
APPLICATIONS
|
|
SUPER + Enter Terminal
|
|
SUPER + Shift + Enter Browser
|
|
SUPER + Alt + Enter Floating terminal
|
|
SUPER + Space Vicinae launcher
|
|
SUPER + E File manager
|
|
SUPER + Shift + F File manager
|
|
SUPER + Shift + E Yazi file manager
|
|
SUPER + V Clipboard history
|
|
SUPER + Ctrl + V Clipboard history
|
|
SUPER + Grave Scratchpad terminal
|
|
SUPER + K Show this keybinding list
|
|
|
|
WINDOWS
|
|
SUPER + Q Close active window gracefully
|
|
SUPER + W Close active window gracefully
|
|
SUPER + T Toggle floating
|
|
SUPER + F Toggle fullscreen
|
|
SUPER + P Toggle pseudo-tile
|
|
SUPER + J Toggle split direction
|
|
SUPER + L Lock screen
|
|
SUPER + Ctrl + L Lock screen (compatibility)
|
|
SUPER + F1 Toggle Quickshell overview
|
|
SUPER + H Toggle Quickshell bar
|
|
SUPER + Alt + Space Hyprland settings
|
|
|
|
NAVIGATION
|
|
SUPER + Arrow Focus window in that direction
|
|
SUPER + Ctrl + Arrow Move window in that direction
|
|
SUPER + Shift + Arrow Swap window in that direction
|
|
SUPER + Alt + Arrow Resize active window
|
|
SUPER + 1..0 Switch to workspace 1..10
|
|
SUPER + Shift + 1..0 Move window to workspace 1..10
|
|
SUPER + Tab Next workspace
|
|
SUPER + Shift + Tab Previous workspace
|
|
SUPER + Mouse wheel Switch workspace
|
|
SUPER + Left click Move window
|
|
SUPER + Right click Resize window
|
|
|
|
SCREENSHOTS AND INPUT
|
|
SUPER + Shift + S Select an area and annotate screenshot
|
|
Print Screenshot the whole screen
|
|
Right Alt Toggle Korean/English input
|
|
|
|
ZOOM
|
|
SUPER + + / KP_ADD Zoom in around cursor
|
|
SUPER + - / KP_SUBTRACT Zoom out around cursor
|
|
|
|
HARDWARE
|
|
Volume keys Change or mute audio
|
|
Mic mute key Mute microphone
|
|
Brightness keys Change screen brightness
|
|
Media keys Previous / play-pause / next
|
|
|
|
OTHER
|
|
Ctrl + Alt + Delete Exit Hyprland
|
|
'';
|
|
|
|
keybindHelp = pkgs.writeShellScript "ena-keybind-help" ''
|
|
${lib.getExe pkgs.rofi} -dmenu -i -no-sort -no-custom -p "Keybindings" <<'EOF'
|
|
${keybindHelpText}
|
|
EOF
|
|
'';
|
|
|
|
hyprlandLuaConfig = ''
|
|
local terminal = "${pkgs.ghostty}/bin/ghostty"
|
|
local browser = "${pkgs.firefox-devedition}/bin/firefox-devedition"
|
|
local fileManager = "${pkgs.nautilus}/bin/nautilus"
|
|
local menu = "${pkgs.vicinae}/bin/vicinae toggle"
|
|
local mainMod = "SUPER"
|
|
|
|
-- Hyprland 0.55+ Lua configuration.
|
|
hl.monitor({
|
|
output = "",
|
|
mode = "preferred",
|
|
position = "auto",
|
|
scale = 1.33,
|
|
})
|
|
|
|
hl.env("XCURSOR_SIZE", "32")
|
|
hl.env("HYPRCURSOR_SIZE", "32")
|
|
hl.env("XCURSOR_THEME", "pjsk-cursor-n25-ena-ani")
|
|
|
|
hl.config({
|
|
general = {
|
|
gaps_in = 5,
|
|
gaps_out = 10,
|
|
border_size = 2,
|
|
col = {
|
|
active_border = "${rgba lightColors.outline}",
|
|
inactive_border = "${rgba lightColors.outlineVariant}",
|
|
},
|
|
resize_on_border = false,
|
|
allow_tearing = false,
|
|
layout = "dwindle",
|
|
},
|
|
decoration = {
|
|
rounding = 10,
|
|
rounding_power = 2,
|
|
active_opacity = 1.0,
|
|
inactive_opacity = 0.8,
|
|
shadow = {
|
|
enabled = false,
|
|
range = 4,
|
|
render_power = 3,
|
|
color = "rgba(1a1a1aee)",
|
|
},
|
|
blur = {
|
|
enabled = true,
|
|
size = 5,
|
|
passes = 3,
|
|
ignore_opacity = true,
|
|
new_optimizations = true,
|
|
special = false,
|
|
popups = true,
|
|
xray = true,
|
|
vibrancy = 0.1696,
|
|
},
|
|
},
|
|
animations = { enabled = true },
|
|
dwindle = { preserve_split = true },
|
|
master = { new_status = "master" },
|
|
misc = {
|
|
force_default_wallpaper = 0,
|
|
disable_hyprland_logo = true,
|
|
},
|
|
render = { new_render_scheduling = true },
|
|
input = {
|
|
kb_layout = "us",
|
|
kb_variant = "",
|
|
kb_model = "",
|
|
kb_options = "",
|
|
kb_rules = "",
|
|
follow_mouse = 1,
|
|
sensitivity = 0,
|
|
accel_profile = "flat",
|
|
force_no_accel = true,
|
|
touchpad = {
|
|
natural_scroll = true,
|
|
tap_to_click = true,
|
|
tap_and_drag = true,
|
|
drag_lock = true,
|
|
disable_while_typing = true,
|
|
clickfinger_behavior = true,
|
|
middle_button_emulation = true,
|
|
},
|
|
touchdevice = {
|
|
enabled = true,
|
|
transform = 0,
|
|
},
|
|
},
|
|
gestures = {
|
|
workspace_swipe_touch = true,
|
|
workspace_swipe_touch_invert = false,
|
|
workspace_swipe_distance = 300,
|
|
},
|
|
})
|
|
|
|
hl.gesture({ fingers = 4, direction = "horizontal", action = "workspace" })
|
|
hl.device({ name = "epic-mouse-v1", sensitivity = -0.5 })
|
|
|
|
-- Animations from the existing Hyprland setup.
|
|
hl.curve("myBezier", { type = "bezier", points = {{0.05, 0.9}, {0.1, 1.05}} })
|
|
hl.curve("been", { type = "bezier", points = {{0.24, 0.9}, {0.25, 0.91}} })
|
|
hl.curve("been2", { type = "bezier", points = {{0, 0.94}, {0.5, 0.99}} })
|
|
hl.curve("menu_decel", { type = "bezier", points = {{0.1, 1}, {0, 1}} })
|
|
hl.curve("linear", { type = "bezier", points = {{0, 0}, {1, 1}} })
|
|
hl.curve("wind", { type = "bezier", points = {{0.05, 0.9}, {0.1, 1.05}} })
|
|
hl.curve("winIn", { type = "bezier", points = {{0.1, 1.1}, {0.1, 1.1}} })
|
|
hl.curve("winOut", { type = "bezier", points = {{0.3, -0.3}, {0, 1}} })
|
|
hl.curve("slow", { type = "bezier", points = {{0, 0.85}, {0.3, 1}} })
|
|
hl.curve("overshot", { type = "bezier", points = {{0.7, 0.6}, {0.1, 1.1}} })
|
|
hl.curve("bounce", { type = "bezier", points = {{1.1, 1.6}, {0.1, 0.85}} })
|
|
hl.curve("sligshot", { type = "bezier", points = {{1, -1}, {0.15, 1.25}} })
|
|
hl.animation({ leaf = "windowsIn", enabled = true, speed = 5, bezier = "slow", style = "popin" })
|
|
hl.animation({ leaf = "windowsOut", enabled = true, speed = 7, bezier = "been", style = "popin 70%" })
|
|
hl.animation({ leaf = "windowsMove", enabled = true, speed = 5, bezier = "wind", style = "slide" })
|
|
hl.animation({ leaf = "border", enabled = true, speed = 1, bezier = "linear" })
|
|
hl.animation({ leaf = "fade", enabled = true, speed = 5, bezier = "overshot" })
|
|
hl.animation({ leaf = "workspaces", enabled = true, speed = 5, bezier = "wind" })
|
|
hl.animation({ leaf = "windows", enabled = true, speed = 5, bezier = "bounce", style = "popin" })
|
|
|
|
-- Tags used by the blur and floating rules below.
|
|
hl.window_rule({ match = { class = "^([Mm]pv|vlc)$" }, tag = "+multimedia_video" })
|
|
hl.window_rule({ match = { class = "^(nm-applet|nm-connection-editor|blueman-manager|org.gnome.FileRoller)$" }, tag = "+settings" })
|
|
hl.window_rule({ match = { class = "^(org.gnome.DiskUtility|wihotspot(-gui)?)$" }, tag = "+settings" })
|
|
hl.window_rule({ match = { class = "^(org.gnome.SystemMonitor)$" }, tag = "+viewer" })
|
|
hl.window_rule({ match = { class = "^(org.gnome.Evince)$" }, tag = "+viewer" })
|
|
hl.window_rule({ match = { class = "^(eog|org.gnome.Loupe)$" }, tag = "+viewer" })
|
|
|
|
-- Application window rules.
|
|
hl.window_rule({ match = { tag = "multimedia_video*" }, no_blur = true, opacity = "1.0" })
|
|
hl.window_rule({ match = { tag = "settings*" }, opacity = "0.8", float = true })
|
|
hl.window_rule({ match = { tag = "viewer*" }, float = true })
|
|
hl.window_rule({ match = { class = "^(org.gnome.Nautilus)$" }, opacity = "0.8" })
|
|
hl.window_rule({ match = { class = "^(gedit|org.gnome.TextEditor|mousepad)$" }, opacity = "0.9" })
|
|
hl.window_rule({ match = { class = "^(org.pulseaudio.pavucontrol)$" }, opacity = "0.9", float = true, size = {"monitor_w*0.5", "monitor_h*0.6"} })
|
|
hl.window_rule({ match = { class = "^(kitty)$" }, opacity = "0.9" })
|
|
hl.window_rule({ match = { class = "^(discord|vesktop|org.telegram.desktop)$" }, opacity = "0.85 override 0.7 override 1 override" })
|
|
hl.window_rule({ match = { class = "^(Spotify)$" }, opacity = "0.8 override 0.6 override 1 override" })
|
|
hl.window_rule({ match = { class = "^(zen)$" }, opacity = "0.9 override 0.7 override 1 override" })
|
|
hl.window_rule({ match = { tag = "multimedia_video*" }, float = true, size = {900, 506} })
|
|
hl.window_rule({ match = { class = "^(org.imnyang.clipse)$" }, float = true, size = {"monitor_w*0.7", "monitor_h*0.75"}, center = true })
|
|
hl.window_rule({ match = { class = "^(org.imnyang.scratchpad)$" }, float = true, size = {"monitor_w*0.8", "monitor_h*0.7"}, center = true })
|
|
hl.window_rule({ match = { class = ".*" }, suppress_event = "maximize" })
|
|
hl.window_rule({
|
|
match = { class = "^$", title = "^$", xwayland = true, float = true, fullscreen = false, pin = false },
|
|
no_focus = true,
|
|
})
|
|
hl.window_rule({ match = { title = "^(Save As|Save a File|Pick Files)$" }, float = true, size = {"monitor_w*0.5", "monitor_h*0.6"}, center = true })
|
|
hl.window_rule({ match = { initial_title = "^(Open Files)$" }, float = true, size = {"monitor_w*0.7", "monitor_h*0.6"} })
|
|
|
|
-- Layer rules.
|
|
hl.layer_rule({ match = { namespace = "quickshell:bar" }, blur = true, ignore_alpha = 0.5 })
|
|
hl.layer_rule({ match = { namespace = "logout_dialog" }, blur = true })
|
|
|
|
-- Startup processes replace the old exec-once entries.
|
|
hl.on("hyprland.start", function()
|
|
hl.exec_cmd("${pkgs.networkmanagerapplet}/bin/nm-applet --indicator")
|
|
hl.exec_cmd("${pkgs.awww}/bin/awww-daemon")
|
|
hl.exec_cmd("${pkgs.clipse}/bin/clipse -listen")
|
|
hl.exec_cmd("${pkgs.blueman}/bin/blueman-applet")
|
|
hl.exec_cmd("${pkgs.hyprpolkitagent}/bin/hyprpolkitagent")
|
|
hl.exec_cmd("${selectHangul}")
|
|
hl.exec_cmd("ln -sfn ${wallpaper} ~/.config/hypr/current_wallpaper")
|
|
hl.exec_cmd("sleep 1 && ${pkgs.awww}/bin/awww img ${wallpaper} --transition-type any")
|
|
end)
|
|
|
|
-- Familiar Super-key layout, based on Omarchy's core bindings.
|
|
hl.bind(mainMod .. " + Space", hl.dsp.exec_cmd(menu))
|
|
hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd(terminal))
|
|
hl.bind(mainMod .. " + SHIFT + Return", hl.dsp.exec_cmd(browser))
|
|
hl.bind(mainMod .. " + ALT + Return", hl.dsp.exec_cmd(terminal, { float = true, size = {800, 550} }))
|
|
hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(fileManager))
|
|
hl.bind(mainMod .. " + SHIFT + F", hl.dsp.exec_cmd(fileManager))
|
|
hl.bind(mainMod .. " + SHIFT + E", hl.dsp.exec_cmd(terminal .. " -e ${pkgs.yazi}/bin/yazi"))
|
|
hl.bind(mainMod .. " + V", hl.dsp.exec_cmd(terminal .. " --gtk-single-instance=false --class=org.imnyang.clipse -e ${pkgs.clipse}/bin/clipse"))
|
|
hl.bind(mainMod .. " + CTRL + V", hl.dsp.exec_cmd(terminal .. " --gtk-single-instance=false --class=org.imnyang.clipse -e ${pkgs.clipse}/bin/clipse"))
|
|
hl.bind(mainMod .. " + Grave", hl.dsp.exec_cmd("${scratchpad}"))
|
|
hl.bind(mainMod .. " + W", hl.dsp.window.close())
|
|
hl.bind(mainMod .. " + ALT + Space", hl.dsp.exec_cmd("${inputs.hyprmod.packages.${pkgs.system}.default}/bin/hyprmod"))
|
|
hl.bind(mainMod .. " + K", hl.dsp.exec_cmd("${keybindHelp}"))
|
|
|
|
hl.bind(mainMod .. " + Q", hl.dsp.window.close())
|
|
hl.bind("CTRL + ALT + Delete", hl.dsp.exit())
|
|
hl.bind(mainMod .. " + T", hl.dsp.window.float({ action = "toggle" }))
|
|
hl.bind(mainMod .. " + F", hl.dsp.window.fullscreen())
|
|
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo())
|
|
hl.bind(mainMod .. " + J", hl.dsp.layout("togglesplit"))
|
|
hl.bind(mainMod .. " + L", hl.dsp.exec_cmd("${pkgs.hyprlock}/bin/hyprlock"))
|
|
hl.bind(mainMod .. " + CTRL + L", hl.dsp.exec_cmd("${pkgs.hyprlock}/bin/hyprlock"))
|
|
hl.bind(mainMod .. " + F1", hl.dsp.exec_cmd("${quickshellToggleSearch}"))
|
|
hl.bind(mainMod .. " + H", hl.dsp.exec_cmd("${qsWrapper}/bin/qs -c ii ipc call bar toggle"))
|
|
hl.bind("Alt_R", hl.dsp.exec_cmd("${pkgs.fcitx5}/bin/fcitx5-remote -t"))
|
|
hl.bind(mainMod .. " + SHIFT + S", hl.dsp.exec_cmd("${screenshotArea}"))
|
|
hl.bind("Print", hl.dsp.exec_cmd("${screenshotScreen}"))
|
|
|
|
local MIN_ZOOM = 1.0
|
|
local MAX_ZOOM = 3.0
|
|
local ZOOM_STEP = 0.25
|
|
local function setZoom(delta)
|
|
local current = hl.get_config("cursor.zoom_factor")
|
|
local next = math.max(MIN_ZOOM, math.min(MAX_ZOOM, current + delta))
|
|
hl.config({ cursor = { zoom_factor = next } })
|
|
end
|
|
|
|
local zoomIn = function()
|
|
setZoom(ZOOM_STEP)
|
|
end
|
|
local zoomOut = function()
|
|
setZoom(-ZOOM_STEP)
|
|
end
|
|
hl.bind(mainMod .. " + equal", zoomIn)
|
|
hl.bind(mainMod .. " + SHIFT + equal", zoomIn)
|
|
hl.bind(mainMod .. " + KP_ADD", zoomIn)
|
|
hl.bind(mainMod .. " + minus", zoomOut)
|
|
hl.bind(mainMod .. " + KP_SUBTRACT", zoomOut)
|
|
|
|
for i = 1, 10 do
|
|
local key = tostring(i % 10)
|
|
hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i }))
|
|
hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i }))
|
|
end
|
|
|
|
hl.bind(mainMod .. " + Tab", hl.dsp.focus({ workspace = "e+1" }))
|
|
hl.bind(mainMod .. " + SHIFT + Tab", hl.dsp.focus({ workspace = "e-1" }))
|
|
hl.bind(mainMod .. " + CTRL + Tab", hl.dsp.focus({ workspace = "previous" }))
|
|
hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
|
|
hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
|
|
|
|
for _, direction in ipairs({ "left", "right", "up", "down" }) do
|
|
hl.bind(mainMod .. " + " .. direction, hl.dsp.focus({ direction = direction }))
|
|
hl.bind(mainMod .. " + CTRL + " .. direction, hl.dsp.window.move({ direction = direction }))
|
|
hl.bind(mainMod .. " + SHIFT + " .. direction, hl.dsp.window.swap({ direction = direction }))
|
|
end
|
|
|
|
-- Resize with Super + Alt + arrows; repeating matches the old binde behavior.
|
|
hl.bind(mainMod .. " + ALT + left", hl.dsp.window.resize({ x = -50, y = 0, relative = true }), { repeating = true })
|
|
hl.bind(mainMod .. " + ALT + right", hl.dsp.window.resize({ x = 50, y = 0, relative = true }), { repeating = true })
|
|
hl.bind(mainMod .. " + ALT + up", hl.dsp.window.resize({ x = 0, y = -50, relative = true }), { repeating = true })
|
|
hl.bind(mainMod .. " + ALT + down", hl.dsp.window.resize({ x = 0, y = 50, relative = true }), { repeating = true })
|
|
|
|
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true })
|
|
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
|
|
hl.bind(mainMod .. " + Control_L", hl.dsp.window.drag(), { mouse = true })
|
|
hl.bind(mainMod .. " + Alt_L", hl.dsp.window.resize(), { mouse = true })
|
|
|
|
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("${pkgs.wireplumber}/bin/wpctl set-volume -l 1.5 @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true, repeating = true })
|
|
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("${pkgs.wireplumber}/bin/wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), { locked = true, repeating = true })
|
|
hl.bind("XF86AudioMute", hl.dsp.exec_cmd("${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), { locked = true })
|
|
hl.bind("XF86AudioMicMute", hl.dsp.exec_cmd("${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), { locked = true })
|
|
hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("${pkgs.brightnessctl}/bin/brightnessctl set 10%+"), { locked = true, repeating = true })
|
|
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("${pkgs.brightnessctl}/bin/brightnessctl set 10%-"), { locked = true, repeating = true })
|
|
hl.bind("XF86AudioNext", hl.dsp.exec_cmd("${pkgs.playerctl}/bin/playerctl next"), { locked = true })
|
|
hl.bind("XF86AudioPause", hl.dsp.exec_cmd("${pkgs.playerctl}/bin/playerctl play-pause"), { locked = true })
|
|
hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("${pkgs.playerctl}/bin/playerctl play-pause"), { locked = true })
|
|
hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("${pkgs.playerctl}/bin/playerctl previous"), { locked = true })
|
|
'';
|
|
|
|
in
|
|
{
|
|
# Run the shell under the user manager so it survives the launcher shell and
|
|
# is restarted if a QML/runtime failure takes it down.
|
|
systemd.user.services.ena-quickshell = {
|
|
Unit = {
|
|
Description = "ena Quickshell desktop shell";
|
|
After = [ "graphical-session.target" ];
|
|
PartOf = [ "graphical-session.target" ];
|
|
};
|
|
Service = {
|
|
ExecStart = quickshellStart;
|
|
Restart = "on-failure";
|
|
RestartSec = 2;
|
|
};
|
|
Install = {
|
|
WantedBy = [ "graphical-session.target" ];
|
|
};
|
|
};
|
|
|
|
systemd.user.services.ena-1password = {
|
|
Unit = {
|
|
Description = "1Password background agent";
|
|
After = [ "graphical-session.target" ];
|
|
PartOf = [ "graphical-session.target" ];
|
|
};
|
|
Service = {
|
|
ExecStart = "${pkgs._1password-gui}/bin/1password --silent";
|
|
Restart = "on-failure";
|
|
RestartSec = 5;
|
|
};
|
|
Install = {
|
|
WantedBy = [ "graphical-session.target" ];
|
|
};
|
|
};
|
|
|
|
home.packages = with pkgs; [
|
|
awww
|
|
adwaita-icon-theme
|
|
bc
|
|
blueman
|
|
brightnessctl
|
|
cava
|
|
cliphist
|
|
clipse
|
|
ddcutil
|
|
ffmpeg
|
|
fuzzel
|
|
grim
|
|
hypridle
|
|
hyprpicker
|
|
jq
|
|
hicolor-icon-theme
|
|
hyprpolkitagent
|
|
hyprsunset
|
|
kdePackages.kirigami
|
|
kdePackages.breeze-icons
|
|
kdePackages.syntax-highlighting
|
|
imagemagick
|
|
libqalculate
|
|
libnotify
|
|
matugen
|
|
material-symbols
|
|
nautilus
|
|
networkmanagerapplet
|
|
pavucontrol
|
|
playerctl
|
|
qt6Packages.qtimageformats
|
|
qt6Packages.qtmultimedia
|
|
qt6Packages.qtpositioning
|
|
qt6Packages.qtquicktimeline
|
|
qt6Packages.qtsensors
|
|
qt6Packages.qt5compat
|
|
qt6Packages.qtvirtualkeyboard
|
|
rofi
|
|
slurp
|
|
satty
|
|
songrec
|
|
swappy
|
|
tesseract
|
|
translate-shell
|
|
upower
|
|
wl-clipboard
|
|
wf-recorder
|
|
qsWrapper
|
|
wireplumber
|
|
wlogout
|
|
wget
|
|
wtype
|
|
xdg-user-dirs
|
|
yazi
|
|
ydotool
|
|
];
|
|
|
|
home.file."Pictures/wallpapers" = {
|
|
source = "${assets}/wallpaper";
|
|
recursive = true;
|
|
};
|
|
|
|
xdg.configFile = {
|
|
"hypr/hyprland.lua".text = hyprlandLuaConfig;
|
|
"hypr/colors.conf".text = colorsConfig;
|
|
"hypr/hypridle.conf".source = "${upstream}/hypr/hypridle.conf";
|
|
"hypr/hyprlock.conf".text = hyprlockConfig;
|
|
"matugen".source = "${dots}/.config/matugen";
|
|
"quickshell/ii".source = quickshellConfig;
|
|
"satty/config.toml".text = sattyConfig;
|
|
"wlogout/layout".text = ''
|
|
{
|
|
"label" : "lock",
|
|
"action" : "${pkgs.hyprlock}/bin/hyprlock",
|
|
"text" : "Lock",
|
|
"keybind" : "l"
|
|
}
|
|
{
|
|
"label" : "reboot",
|
|
"action" : "systemctl reboot",
|
|
"text" : "Reboot",
|
|
"keybind" : "r"
|
|
}
|
|
{
|
|
"label" : "shutdown",
|
|
"action" : "systemctl poweroff",
|
|
"text" : "Shutdown",
|
|
"keybind" : "s"
|
|
}
|
|
{
|
|
"label" : "logout",
|
|
"action" : "loginctl kill-session $XDG_SESSION_ID",
|
|
"text" : "Logout",
|
|
"keybind" : "e"
|
|
}
|
|
{
|
|
"label" : "suspend",
|
|
"action" : "systemctl suspend",
|
|
"text" : "Suspend",
|
|
"keybind" : "u"
|
|
}
|
|
'';
|
|
"wlogout/style.css".source = "${upstream}/wlogout/style.css";
|
|
"wlogout/icons" = {
|
|
source = "${upstream}/wlogout/icons";
|
|
recursive = true;
|
|
};
|
|
};
|
|
}
|