From 98c39d1dec96394339c82defc821189a6ad82593 Mon Sep 17 00:00:00 2001 From: Nhan Pham <74626967+Nitestack@users.noreply.github.com> Date: Sat, 28 Sep 2024 14:48:56 +0200 Subject: [PATCH] Revert "Migrate Dotfiles from Arch to NixOS with Minor Updates and Refactoring" --- .github/workflows/update-bindings.yml | 31 + README.md | 181 ++- config/.chezmoi.yml.tmpl | 3 +- config/.chezmoidata/apps.yml | 33 +- config/.chezmoidata/arch.yml | 103 ++ config/.chezmoidata/macos.yml | 7 +- config/.chezmoidata/packages.yml | 96 +- config/.chezmoidata/settings.yml | 66 + config/.chezmoidata/windows.yml | 2 + config/.chezmoiexternal.yml.tmpl | 17 +- config/.chezmoiignore | 35 +- .../_unix/run_before_01_greet.sh.tmpl | 6 +- .../run_after_01-configure-system.sh.tmpl | 41 + .../arch/run_after_02-configure-gnome.sh.tmpl | 47 + .../arch/run_after_03-add-ags-types.sh.tmpl | 28 + .../run_after_04-configure-brightness.sh.tmpl | 50 + .../run_before_01-configure-locales.sh.tmpl | 54 + .../run_before_02-configure-pacman.sh.tmpl | 63 + .../run_before_03-configure-reflector.sh.tmpl | 23 + .../arch/run_before_04-install-paru.sh.tmpl | 25 + .../arch/run_before_05-chsh.sh.tmpl | 21 + ...n_onchange_after_01-configure-grub.sh.tmpl | 49 + ...n_onchange_after_02-configure-sddm.sh.tmpl | 37 + ...hange_after_03-configure-hyprshade.sh.tmpl | 15 + ...run_onchange_after_04-configure-vm.sh.tmpl | 46 + .../unix/run_after_01-update-neovim.sh.tmpl | 6 +- .../run_before_01-configure-spicetify.sh.tmpl | 25 + .../run_onchange_01-install-packages.sh.tmpl | 56 +- .../unix/run_onchange_02-install-apps.sh.tmpl | 43 + ...e_03-display-manual-installations.sh.tmpl} | 5 + .../run_after_02-update-neovim.ps1.tmpl | 6 +- config/.chezmoitemplates/bash-library.sh | 87 + .../.chezmoitemplates/bat/config | 9 +- config/.chezmoitemplates/entry.desktop | 9 + config/.chezmoitemplates/lazygit/config.yml | 1 - config/.chezmoitemplates/qt/qt.conf | 32 + .../spicetify/config-xpui.ini | 36 + .../Microsoft.PowerShell_profile.ps1.tmpl | 4 +- .../dot_oh-my-zsh/exact_completions/_bob.tmpl | 4 + .../dot_oh-my-zsh/exact_completions/_bw.tmpl | 4 + .../exact_completions/_dotfiles.tmpl | 4 + nix/pkgs/default.nix => config/dot_zprofile | 10 +- config/dot_zshrc.tmpl | 13 +- config/empty_dot_hushlogin | 0 .../private_AppData/Roaming/bat/config.tmpl | 1 + .../Roaming/exact_komorebi/applications.yaml | 1443 +++++++++++++++++ .../Roaming/exact_komorebi/komorebi.ahk | 75 + .../Roaming/exact_komorebi/komorebi.json.tmpl | 62 + .../Roaming/spicetify/config-xpui.ini.tmpl | 1 + .../Application Support/bat/config.tmpl | 1 + config/private_dot_config/bat/config.tmpl | 1 + .../exact_ags/.eslintrc.json | 71 + .../private_dot_config/exact_ags/.gitignore | 2 + config/private_dot_config/exact_ags/bun.lockb | Bin 0 -> 70003 bytes .../exact_ags/config.js.tmpl | 24 + .../exact_assets/battery-flash-symbolic.svg | 4 + .../exact_assets/chat-bubbles-symbolic.svg | 5 + .../exact_assets/controller-symbolic.svg | 4 + .../exact_assets/controls-symbolic.svg | 5 + .../exact_assets/dark-mode-symbolic.svg | 4 + .../exact_assets/hourglass-symbolic.svg | 4 + .../exact_assets/light-mode-symbolic.svg | 4 + .../exact_ags/exact_assets/mixer-symbolic.svg | 6 + .../preferences-desktop-theme-symbolic.svg | 321 ++++ .../exact_assets/processor-symbolic.svg | 17 + .../exact_assets/terminal-symbolic.svg | 5 + .../exact_assets/toolbars-symbolic.svg | 4 + .../exact_templates/gradience/preset.json | 165 ++ .../exact_ags/lib/battery.ts | 15 + .../exact_ags/lib/colorgen.ts | 151 ++ .../private_dot_config/exact_ags/lib/gtk.ts | 20 + .../exact_ags/lib/hyprland.ts | 54 + .../private_dot_config/exact_ags/lib/icons.ts | 142 ++ .../private_dot_config/exact_ags/lib/init.ts | 19 + .../exact_ags/lib/notifications.ts | 19 + .../exact_ags/lib/option.ts | 118 ++ .../exact_ags/lib/session.ts | 16 + .../private_dot_config/exact_ags/lib/tmux.ts | 18 + .../private_dot_config/exact_ags/lib/utils.ts | 156 ++ .../exact_ags/lib/variables.ts | 57 + config/private_dot_config/exact_ags/main.ts | 42 + .../private_dot_config/exact_ags/options.ts | 245 +++ .../private_dot_config/exact_ags/package.json | 16 + .../exact_ags/prettier.config.mjs | 28 + .../exact_ags/service/asusctl.ts | 73 + .../exact_ags/service/brightness.ts | 111 ++ .../exact_ags/service/cliphist.ts | 76 + .../exact_ags/service/colorpicker.ts | 58 + .../exact_ags/service/hyprshade.ts | 39 + .../exact_ags/service/powermenu.ts | 53 + .../exact_ags/service/screenrecord.ts | 119 ++ .../exact_ags/service/sh.ts | 55 + .../style/exact_mixins/a11y-button.scss | 45 + .../exact_ags/style/exact_mixins/button.scss | 74 + .../style/exact_mixins/floating-widget.scss | 12 + .../exact_ags/style/exact_mixins/hidden.scss | 15 + .../exact_ags/style/exact_mixins/media.scss | 46 + .../style/exact_mixins/scrollable.scss | 56 + .../exact_ags/style/exact_mixins/slider.scss | 79 + .../exact_ags/style/exact_mixins/spacing.scss | 53 + .../exact_ags/style/exact_mixins/switch.scss | 16 + .../exact_ags/style/exact_mixins/unset.scss | 9 + .../exact_ags/style/exact_mixins/widget.scss | 7 + .../exact_ags/style/exact_widgets/bar.scss | 282 ++++ .../style/exact_widgets/datemenu.scss | 110 ++ .../style/exact_widgets/launcher.scss | 158 ++ .../style/exact_widgets/notifications.scss | 79 + .../exact_ags/style/exact_widgets/osd.scss | 26 + .../style/exact_widgets/overview.scss | 34 + .../style/exact_widgets/powermenu.scss | 110 ++ .../style/exact_widgets/quicksettings.scss | 177 ++ .../style/exact_widgets/screencorner.scss | 52 + .../style/exact_widgets/settingsdialog.scss | 134 ++ .../exact_ags/style/extra.scss | 67 + .../exact_ags/style/style.ts | 133 ++ .../exact_ags/template.ts.tmpl | 3 + .../exact_ags/tsconfig.json | 22 + .../exact_ags/widget/PopupWindow.ts | 175 ++ .../exact_ags/widget/RegularWindow.ts | 6 + .../exact_ags/widget/bar/Bar.ts | 67 + .../exact_ags/widget/bar/PanelButton.ts | 45 + .../exact_ags/widget/bar/ScreenCorners.ts | 31 + .../widget/bar/buttons/BatteryBar.ts | 103 ++ .../widget/bar/buttons/ColorPicker.ts | 41 + .../exact_ags/widget/bar/buttons/Date.ts | 17 + .../exact_ags/widget/bar/buttons/Hyprshade.ts | 17 + .../exact_ags/widget/bar/buttons/Launcher.ts | 40 + .../exact_ags/widget/bar/buttons/Media.ts | 107 ++ .../exact_ags/widget/bar/buttons/Messages.ts | 16 + .../exact_ags/widget/bar/buttons/PowerMenu.ts | 18 + .../widget/bar/buttons/ScreenRecord.ts | 23 + .../exact_ags/widget/bar/buttons/SysTray.ts | 50 + .../widget/bar/buttons/SystemIndicators.ts | 117 ++ .../widget/bar/buttons/SystemInfo.ts | 17 + .../exact_ags/widget/bar/buttons/Taskbar.ts | 128 ++ .../widget/bar/buttons/Workspaces.ts | 51 + .../exact_ags/widget/datemenu/DateColumn.ts | 38 + .../exact_ags/widget/datemenu/DateMenu.ts | 40 + .../widget/datemenu/NotificationColumn.ts | 116 ++ .../exact_ags/widget/launcher/AppLauncher.ts | 132 ++ .../exact_ags/widget/launcher/Cliphist.ts | 85 + .../exact_ags/widget/launcher/Launcher.ts | 144 ++ .../exact_ags/widget/launcher/ShRun.ts | 65 + .../widget/notifications/Notification.ts | 140 ++ .../notifications/NotificationPopups.ts | 94 ++ .../exact_ags/widget/osd/OSD.ts | 120 ++ .../exact_ags/widget/osd/Progress.ts | 75 + .../exact_ags/widget/overview/Overview.ts | 52 + .../exact_ags/widget/overview/Window.ts | 55 + .../exact_ags/widget/overview/Workspace.ts | 81 + .../exact_ags/widget/powermenu/PowerMenu.ts | 63 + .../widget/powermenu/Verification.ts | 48 + .../widget/quicksettings/QuickSettings.ts | 86 + .../widget/quicksettings/ToggleButton.ts | 161 ++ .../widget/quicksettings/widgets/Bluetooth.ts | 69 + .../quicksettings/widgets/Brightness.ts | 26 + .../widget/quicksettings/widgets/DND.ts | 14 + .../widget/quicksettings/widgets/DarkMode.ts | 14 + .../widget/quicksettings/widgets/Header.ts | 69 + .../widget/quicksettings/widgets/Media.ts | 155 ++ .../widget/quicksettings/widgets/MicMute.ts | 21 + .../widget/quicksettings/widgets/Network.ts | 102 ++ .../quicksettings/widgets/PowerProfile.ts | 112 ++ .../widget/quicksettings/widgets/Volume.ts | 156 ++ .../exact_ags/widget/settings/Group.ts | 40 + .../exact_ags/widget/settings/Page.ts | 20 + .../exact_ags/widget/settings/Row.ts | 54 + .../exact_ags/widget/settings/Setter.ts | 116 ++ .../widget/settings/SettingsDialog.ts | 66 + .../exact_ags/widget/settings/layout.ts | 245 +++ .../exact_fastfetch/config.jsonc | 2 +- .../exact_hypr/exact_hyprland/bindings.conf | 110 ++ .../exact_hyprland/config.conf.tmpl | 122 ++ .../exact_hypr/exact_hyprland/env.conf.tmpl | 52 + .../exact_hypr/exact_hyprland/execs.conf | 22 + .../exact_hypr/exact_hyprland/rules.conf.tmpl | 22 + .../exact_hypr/executable_battery-status.sh | 24 + .../exact_hypr/executable_layout-status.sh | 19 +- .../exact_hypr/executable_network-status.sh | 31 + .../exact_hypr/executable_song-status.sh | 22 + .../executable_xdg-desktop-portal-hyprland.sh | 22 +- .../exact_hypr/hypridle.conf | 38 + .../exact_hypr/hyprland.conf | 18 +- .../exact_hypr/hyprlock.conf.tmpl | 153 ++ .../exact_hypr/hyprpaper.conf | 6 + .../exact_hypr/hyprshade.toml | 15 + .../exact_nvim/create_lazy-lock.json | 97 +- .../exact_nvim/create_lazyvim.json | 7 +- .../exact_nvim/lua/exact_core/cmds.lua | 14 + .../exact_nvim/lua/exact_core/mappings.lua | 47 + .../lua/exact_languages/ansible.lua | 9 + .../exact_nvim/lua/exact_languages/hypr.lua | 11 + .../exact_nvim/lua/exact_languages/java.lua | 9 + .../exact_nvim/lua/exact_languages/kotlin.lua | 9 + .../exact_nvim/lua/exact_languages/nix.lua | 35 - .../exact_nvim/lua/exact_languages/typst.lua | 15 - .../lua/exact_plugins/_disabled.lua | 1 + .../exact_nvim/lua/exact_plugins/_extras.lua | 1 + .../lua/exact_plugins/chezmoi.lua.tmpl | 1 + .../lua/exact_plugins/toggleterm.lua | 52 + .../lua/exact_utils/breadcrumbs.lua | 1 + .../exact_oh-my-posh/config.yml | 2 +- .../private_dot_config/exact_paru/paru.conf | 14 + .../{wezterm => exact_wezterm}/colors.lua | 0 .../config/appearance.lua.tmpl | 0 .../config/general.lua | 0 .../config/keys.lua | 0 .../config/platforms/init.lua | 0 .../config/platforms/linux.lua | 3 + .../config/platforms/macos.lua | 0 .../config/platforms/unix.lua | 0 .../config/platforms/windows.lua.tmpl | 0 .../{wezterm => exact_wezterm}/utils.lua | 0 .../{wezterm => exact_wezterm}/wezterm.lua | 0 .../private_spicetify/config-xpui.ini.tmpl | 1 + .../private_dot_config/qt5ct/qt5ct.conf.tmpl | 1 + .../private_dot_config/qt6ct/qt6ct.conf.tmpl | 1 + config/private_dot_config/tmux/tmux.conf | 61 +- .../share/icons/Snapdrop.png | Bin 0 -> 42050 bytes .../snapdrop.desktop.tmpl | 1 + config/private_dot_ssh/config | 12 - nix/config.nix | 45 - nix/flake.lock | 464 ------ nix/flake.nix | 90 - nix/home-manager/bat.nix | 18 - nix/home-manager/browser.nix | 38 - nix/home-manager/dunst.nix | 34 - nix/home-manager/git.nix | 28 - nix/home-manager/home.nix | 101 -- nix/home-manager/hyprland/default.nix | 417 ----- nix/home-manager/hyprland/hypridle.nix | 49 - nix/home-manager/hyprland/hyprlock.nix | 244 --- nix/home-manager/hyprland/hyprpaper.nix | 16 - nix/home-manager/hyprland/hyprshade.nix | 49 - nix/home-manager/kitty.nix | 21 - nix/home-manager/modules/default.nix | 1 - nix/home-manager/rofi.nix | 363 ----- nix/home-manager/scripts/nix-utils.nix | 39 - nix/home-manager/theme.nix | 84 - nix/home-manager/wezterm.nix | 28 - nix/nixos/audio.nix | 55 - nix/nixos/configuration.nix | 82 - nix/nixos/gnome.nix | 35 - nix/nixos/hyprland.nix | 39 - nix/nixos/locale.nix | 36 - nix/nixos/modules/default.nix | 1 - nix/nixos/sddm.nix | 22 - nix/nixos/system.nix | 140 -- nix/pkgs/hyprshade/default.nix | 43 - scripts/install.sh | 11 +- scripts/update_bindings.py | 331 ++++ 251 files changed, 12255 insertions(+), 2856 deletions(-) create mode 100644 .github/workflows/update-bindings.yml create mode 100644 config/.chezmoidata/arch.yml create mode 100644 config/.chezmoiscripts/arch/run_after_01-configure-system.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_after_02-configure-gnome.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_after_03-add-ags-types.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_after_04-configure-brightness.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_before_01-configure-locales.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_before_02-configure-pacman.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_before_03-configure-reflector.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_before_04-install-paru.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_before_05-chsh.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_onchange_after_01-configure-grub.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_onchange_after_02-configure-sddm.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_onchange_after_03-configure-hyprshade.sh.tmpl create mode 100644 config/.chezmoiscripts/arch/run_onchange_after_04-configure-vm.sh.tmpl create mode 100644 config/.chezmoiscripts/unix/run_before_01-configure-spicetify.sh.tmpl create mode 100644 config/.chezmoiscripts/unix/run_onchange_02-install-apps.sh.tmpl rename config/.chezmoiscripts/unix/{run_onchange_02-display-manual-installations.sh.tmpl => run_onchange_03-display-manual-installations.sh.tmpl} (65%) rename nix/home-manager/scripts/default.nix => config/.chezmoitemplates/bat/config (77%) create mode 100644 config/.chezmoitemplates/entry.desktop create mode 100644 config/.chezmoitemplates/qt/qt.conf create mode 100644 config/.chezmoitemplates/spicetify/config-xpui.ini create mode 100644 config/dot_oh-my-zsh/exact_completions/_bob.tmpl create mode 100644 config/dot_oh-my-zsh/exact_completions/_bw.tmpl create mode 100644 config/dot_oh-my-zsh/exact_completions/_dotfiles.tmpl rename nix/pkgs/default.nix => config/dot_zprofile (68%) create mode 100644 config/empty_dot_hushlogin create mode 100644 config/private_AppData/Roaming/bat/config.tmpl create mode 100644 config/private_AppData/Roaming/exact_komorebi/applications.yaml create mode 100644 config/private_AppData/Roaming/exact_komorebi/komorebi.ahk create mode 100644 config/private_AppData/Roaming/exact_komorebi/komorebi.json.tmpl create mode 100644 config/private_AppData/Roaming/spicetify/config-xpui.ini.tmpl create mode 100644 config/private_Library/Application Support/bat/config.tmpl create mode 100644 config/private_dot_config/bat/config.tmpl create mode 100644 config/private_dot_config/exact_ags/.eslintrc.json create mode 100644 config/private_dot_config/exact_ags/.gitignore create mode 100755 config/private_dot_config/exact_ags/bun.lockb create mode 100644 config/private_dot_config/exact_ags/config.js.tmpl create mode 100644 config/private_dot_config/exact_ags/exact_assets/battery-flash-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/chat-bubbles-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/controller-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/controls-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/dark-mode-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/hourglass-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/light-mode-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/mixer-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/preferences-desktop-theme-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/processor-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/terminal-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_assets/toolbars-symbolic.svg create mode 100644 config/private_dot_config/exact_ags/exact_templates/gradience/preset.json create mode 100644 config/private_dot_config/exact_ags/lib/battery.ts create mode 100644 config/private_dot_config/exact_ags/lib/colorgen.ts create mode 100644 config/private_dot_config/exact_ags/lib/gtk.ts create mode 100644 config/private_dot_config/exact_ags/lib/hyprland.ts create mode 100644 config/private_dot_config/exact_ags/lib/icons.ts create mode 100644 config/private_dot_config/exact_ags/lib/init.ts create mode 100644 config/private_dot_config/exact_ags/lib/notifications.ts create mode 100644 config/private_dot_config/exact_ags/lib/option.ts create mode 100644 config/private_dot_config/exact_ags/lib/session.ts create mode 100644 config/private_dot_config/exact_ags/lib/tmux.ts create mode 100644 config/private_dot_config/exact_ags/lib/utils.ts create mode 100644 config/private_dot_config/exact_ags/lib/variables.ts create mode 100644 config/private_dot_config/exact_ags/main.ts create mode 100644 config/private_dot_config/exact_ags/options.ts create mode 100644 config/private_dot_config/exact_ags/package.json create mode 100644 config/private_dot_config/exact_ags/prettier.config.mjs create mode 100644 config/private_dot_config/exact_ags/service/asusctl.ts create mode 100644 config/private_dot_config/exact_ags/service/brightness.ts create mode 100644 config/private_dot_config/exact_ags/service/cliphist.ts create mode 100644 config/private_dot_config/exact_ags/service/colorpicker.ts create mode 100644 config/private_dot_config/exact_ags/service/hyprshade.ts create mode 100644 config/private_dot_config/exact_ags/service/powermenu.ts create mode 100644 config/private_dot_config/exact_ags/service/screenrecord.ts create mode 100644 config/private_dot_config/exact_ags/service/sh.ts create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/a11y-button.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/button.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/floating-widget.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/hidden.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/media.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/scrollable.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/slider.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/spacing.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/switch.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/unset.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_mixins/widget.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/bar.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/datemenu.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/launcher.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/notifications.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/osd.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/overview.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/powermenu.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/quicksettings.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/screencorner.scss create mode 100644 config/private_dot_config/exact_ags/style/exact_widgets/settingsdialog.scss create mode 100644 config/private_dot_config/exact_ags/style/extra.scss create mode 100644 config/private_dot_config/exact_ags/style/style.ts create mode 100644 config/private_dot_config/exact_ags/template.ts.tmpl create mode 100644 config/private_dot_config/exact_ags/tsconfig.json create mode 100644 config/private_dot_config/exact_ags/widget/PopupWindow.ts create mode 100644 config/private_dot_config/exact_ags/widget/RegularWindow.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/Bar.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/PanelButton.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/ScreenCorners.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/BatteryBar.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/ColorPicker.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/Date.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/Hyprshade.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/Launcher.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/Media.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/Messages.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/PowerMenu.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/ScreenRecord.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/SysTray.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/SystemIndicators.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/SystemInfo.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/Taskbar.ts create mode 100644 config/private_dot_config/exact_ags/widget/bar/buttons/Workspaces.ts create mode 100644 config/private_dot_config/exact_ags/widget/datemenu/DateColumn.ts create mode 100644 config/private_dot_config/exact_ags/widget/datemenu/DateMenu.ts create mode 100644 config/private_dot_config/exact_ags/widget/datemenu/NotificationColumn.ts create mode 100644 config/private_dot_config/exact_ags/widget/launcher/AppLauncher.ts create mode 100644 config/private_dot_config/exact_ags/widget/launcher/Cliphist.ts create mode 100644 config/private_dot_config/exact_ags/widget/launcher/Launcher.ts create mode 100644 config/private_dot_config/exact_ags/widget/launcher/ShRun.ts create mode 100644 config/private_dot_config/exact_ags/widget/notifications/Notification.ts create mode 100644 config/private_dot_config/exact_ags/widget/notifications/NotificationPopups.ts create mode 100644 config/private_dot_config/exact_ags/widget/osd/OSD.ts create mode 100644 config/private_dot_config/exact_ags/widget/osd/Progress.ts create mode 100644 config/private_dot_config/exact_ags/widget/overview/Overview.ts create mode 100644 config/private_dot_config/exact_ags/widget/overview/Window.ts create mode 100644 config/private_dot_config/exact_ags/widget/overview/Workspace.ts create mode 100644 config/private_dot_config/exact_ags/widget/powermenu/PowerMenu.ts create mode 100644 config/private_dot_config/exact_ags/widget/powermenu/Verification.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/QuickSettings.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/ToggleButton.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/Bluetooth.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/Brightness.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/DND.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/DarkMode.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/Header.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/Media.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/MicMute.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/Network.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/PowerProfile.ts create mode 100644 config/private_dot_config/exact_ags/widget/quicksettings/widgets/Volume.ts create mode 100644 config/private_dot_config/exact_ags/widget/settings/Group.ts create mode 100644 config/private_dot_config/exact_ags/widget/settings/Page.ts create mode 100644 config/private_dot_config/exact_ags/widget/settings/Row.ts create mode 100644 config/private_dot_config/exact_ags/widget/settings/Setter.ts create mode 100644 config/private_dot_config/exact_ags/widget/settings/SettingsDialog.ts create mode 100644 config/private_dot_config/exact_ags/widget/settings/layout.ts create mode 100644 config/private_dot_config/exact_hypr/exact_hyprland/bindings.conf create mode 100644 config/private_dot_config/exact_hypr/exact_hyprland/config.conf.tmpl create mode 100644 config/private_dot_config/exact_hypr/exact_hyprland/env.conf.tmpl create mode 100644 config/private_dot_config/exact_hypr/exact_hyprland/execs.conf create mode 100644 config/private_dot_config/exact_hypr/exact_hyprland/rules.conf.tmpl create mode 100644 config/private_dot_config/exact_hypr/executable_battery-status.sh rename nix/home-manager/eza.nix => config/private_dot_config/exact_hypr/executable_layout-status.sh (57%) create mode 100644 config/private_dot_config/exact_hypr/executable_network-status.sh create mode 100644 config/private_dot_config/exact_hypr/executable_song-status.sh rename nix/overlays/default.nix => config/private_dot_config/exact_hypr/executable_xdg-desktop-portal-hyprland.sh (51%) create mode 100644 config/private_dot_config/exact_hypr/hypridle.conf rename nix/home-manager/fzf.nix => config/private_dot_config/exact_hypr/hyprland.conf (54%) create mode 100644 config/private_dot_config/exact_hypr/hyprlock.conf.tmpl create mode 100644 config/private_dot_config/exact_hypr/hyprpaper.conf create mode 100644 config/private_dot_config/exact_hypr/hyprshade.toml create mode 100644 config/private_dot_config/exact_nvim/lua/exact_languages/ansible.lua create mode 100644 config/private_dot_config/exact_nvim/lua/exact_languages/hypr.lua create mode 100644 config/private_dot_config/exact_nvim/lua/exact_languages/java.lua create mode 100644 config/private_dot_config/exact_nvim/lua/exact_languages/kotlin.lua delete mode 100644 config/private_dot_config/exact_nvim/lua/exact_languages/nix.lua delete mode 100644 config/private_dot_config/exact_nvim/lua/exact_languages/typst.lua create mode 100644 config/private_dot_config/exact_nvim/lua/exact_plugins/toggleterm.lua create mode 100644 config/private_dot_config/exact_paru/paru.conf rename config/private_dot_config/{wezterm => exact_wezterm}/colors.lua (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/appearance.lua.tmpl (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/general.lua (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/keys.lua (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/platforms/init.lua (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/platforms/linux.lua (89%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/platforms/macos.lua (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/platforms/unix.lua (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/config/platforms/windows.lua.tmpl (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/utils.lua (100%) rename config/private_dot_config/{wezterm => exact_wezterm}/wezterm.lua (100%) create mode 100644 config/private_dot_config/private_spicetify/config-xpui.ini.tmpl create mode 100644 config/private_dot_config/qt5ct/qt5ct.conf.tmpl create mode 100644 config/private_dot_config/qt6ct/qt6ct.conf.tmpl create mode 100644 config/private_dot_local/share/icons/Snapdrop.png create mode 100644 config/private_dot_local/share/private_applications/snapdrop.desktop.tmpl delete mode 100644 nix/config.nix delete mode 100644 nix/flake.lock delete mode 100644 nix/flake.nix delete mode 100644 nix/home-manager/bat.nix delete mode 100644 nix/home-manager/browser.nix delete mode 100644 nix/home-manager/dunst.nix delete mode 100644 nix/home-manager/git.nix delete mode 100644 nix/home-manager/home.nix delete mode 100644 nix/home-manager/hyprland/default.nix delete mode 100644 nix/home-manager/hyprland/hypridle.nix delete mode 100644 nix/home-manager/hyprland/hyprlock.nix delete mode 100644 nix/home-manager/hyprland/hyprpaper.nix delete mode 100644 nix/home-manager/hyprland/hyprshade.nix delete mode 100644 nix/home-manager/kitty.nix delete mode 100644 nix/home-manager/modules/default.nix delete mode 100644 nix/home-manager/rofi.nix delete mode 100644 nix/home-manager/scripts/nix-utils.nix delete mode 100644 nix/home-manager/theme.nix delete mode 100644 nix/home-manager/wezterm.nix delete mode 100644 nix/nixos/audio.nix delete mode 100644 nix/nixos/configuration.nix delete mode 100644 nix/nixos/gnome.nix delete mode 100644 nix/nixos/hyprland.nix delete mode 100644 nix/nixos/locale.nix delete mode 100644 nix/nixos/modules/default.nix delete mode 100644 nix/nixos/sddm.nix delete mode 100644 nix/nixos/system.nix delete mode 100644 nix/pkgs/hyprshade/default.nix create mode 100644 scripts/update_bindings.py diff --git a/.github/workflows/update-bindings.yml b/.github/workflows/update-bindings.yml new file mode 100644 index 00000000..0c02663b --- /dev/null +++ b/.github/workflows/update-bindings.yml @@ -0,0 +1,31 @@ +name: Update Bindings + +on: + push: + paths: + - "home/private_dot_config/exact_hypr/exact_hyprland/bindings.conf" + - "scripts/update_bindings.py" + +jobs: + update-readme: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Parse bindings and update README.md + run: python scripts/update_bindings.py + + - name: Push changes + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore(build): Update bindings" + commit_user_name: "github-actions[bot]" + commit_user_email: "github-actions[bot]@users.noreply.github.com" + commit_author: "github-actions[bot] " diff --git a/README.md b/README.md index 9cadb490..569e3cda 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ ![image](https://github.com/Nitestack/dotfiles/assets/74626967/154b824c-42f2-4ec0-818b-f244f8c91f4b) -_Elevate your computing experience across platforms with this curated collection of configuration files and setup scripts. From [NixOS](https://nixos.org) to [macOS](https://apple.com/macos) and [Windows](https://microsoft.com/windows), personalize your environment effortlessly, managed securely across multiple diverse machines using [chezmoi](https://chezmoi.io). Leverage advanced features like templates, password manager support, file encryption, and script execution for seamless deployment and synchronization._ +_Elevate your computing experience across platforms with this curated collection of configuration files and setup scripts. From [Arch Linux](https://archlinux.org) to [macOS](https://apple.com/macos) and [Windows](https://microsoft.com/windows), personalize your environment effortlessly, managed securely across multiple diverse machines using [chezmoi](https://chezmoi.io). Leverage advanced features like templates, password manager support, file encryption, and script execution for seamless deployment and synchronization._

Be sure to โญ๏ธ or fork this repo if you find it useful! @@ -26,16 +26,7 @@ _Elevate your computing experience across platforms with this curated collection ## ๐Ÿš€ Features -### NixOS (Full System) - -> [!WARNING] -> The NixOS full system configuration is still incomplete! The key feature yet to be implemented is the integration of [Astal](https://aylur.github.io/astal) and [AGS](https://aylur.github.io/ags-docs). This requires a rewrite from the previous Arch-based version of the dotfiles, meaning there is currently no top or bottom bar, and the power menu is also missing. - -This setup operates on the [Wayland](https://wayland.freedesktop.org) protocol, utilizing [Hyprland](https://hyprland.org) as the compositor to deliver a smooth and visually pleasing window management experience. For login management, [SDDM](https://github.com/sddm/sddm) is employed with a custom theme, providing a refined and polished interface. The system uses [GRUB](https://www.gnu.org/software/grub) as the bootloader, enhanced with a theme and os-prober for seamless dual-booting with Windows or other operating systems. To further elevate the visual aesthetic, both [Astal](https://aylur.github.io/astal) and [AGS](https://aylur.github.io/ags-docs) are used, creating a cohesive design for app launchers, power and notification menus, top and bottom bars, and more. - -Everything is built using a [Nix Flake](https://nix.dev/concepts/flakes.html), ensuring the system is reproducible. It also includes all the features listed in the [Cross-Platform](#cross-platform-nixos-macos-windows) and the [UNIX](#unix-nixos-macos) section, making it a complete and fully functional environment. - -### Cross-Platform (NixOS, macOS, Windows) +### Cross-Platform (Arch Linux, macOS, Windows) - **Neovim Configuration**: Powered by [LazyVim](http://www.lazyvim.org), ensuring a robust and efficient text editing experience @@ -47,15 +38,25 @@ Everything is built using a [Nix Flake](https://nix.dev/concepts/flakes.html), e - **Fastfetch Configuration**: Customized settings for a fast and efficient system information display +- **bat Configuration**: Themed with the [Catppuccin Mocha](https://github.com/catppuccin/bat) theme + - **Lazygit Configuration**: Themed with the [Catppuccin Mocha](https://github.com/catppuccin/lazygit) theme for a cohesive look and feel +- **Spicetify Configuration**: Add extensibility and customization to Spotify + - **Git Configuration**: Customized settings for version control - **ShellCheck Configuration**: Setup for shell script analysis - **SSH Configuration**: Consistent and secure SSH setup across systems -### UNIX (NixOS, macOS) +- **Package & App Management**: Consistent management of common apps and packages across all systems, including system-specific packages and apps + +- **Font Management**: Ensuring a uniform look and feel across different platforms, with support for Nerd icons ([Symbols Nerd Font](https://www.nerdfonts.com/font-downloads)) and emojis ([Noto Color Emoji](https://fonts.google.com/noto)) + +- **Performance Always in Mind**: Optimized configurations to ensure efficient and smooth performance + +### UNIX - **tmux Configuration**: Themed with the [Catppuccin Mocha](https://github.com/catppuccin/tmux) theme, featuring session management and an integrated Neovim workflow @@ -63,6 +64,30 @@ Everything is built using a [Nix Flake](https://nix.dev/concepts/flakes.html), e - **Zsh Configuration**: Powered by [Oh My Zsh](https://ohmyz.sh), this configuration includes styled prompts, shell completions, optimized history settings, and useful aliases for a seamless command-line experience +### Arch Linux + +This repository provides a comprehensive setup for Arch Linux, including: + +- **Hyprland Configuration**: Customized settings and tweaks for the Wayland compositor + +- **AGS Configuration**: Beautiful and functional Wayland widgets configuration using [ags](https://aylur.github.io/ags-docs) + +- **GRUB Setup**: Configured GRUB options and themed with [Hyperfluent Arch](https://github.com/Coopydood/HyperFluent-GRUB-Theme/tree/main) + +- **SDDM Theme**: Aesthetic display manager theme using [Astronaut Theme](https://github.com/Keyitdev/sddm-astronaut-theme) + +- **System Services**: Automatic setup for essential services like [Bluetooth](https://wiki.archlinux.org/title/bluetooth) + +- **Synced Theming**: Consistent theming across different applications and system components + +- **Pacman Configuration**: Enhanced pacman settings for faster downloads and updated servers using [reflector](https://wiki.archlinux.org/title/reflector), along with efficient package cache management ([paccache](https://wiki.archlinux.org/title/Pacman#Cleaning_the_package_cache)) + +- **AUR Helper**: Inclusion of [paru](https://github.com/Morganamilo/paru) for seamless access to AUR packages + +- **Zsh**: Zsh shell configuration for an improved command-line experience + +After installing Arch Linux on a new machine, this repository can set up the rest of the system to work properly, ensuring a smooth and efficient workflow. + ### macOS - **Dependency Management**: Managed with [Homebrew](https://brew.sh), including [formulae](https://formulae.brew.sh), [casks](https://formulae.brew.sh/cask), fonts, and Mac App Store applications (via [mas](https://github.com/mas-cli/mas)), all bundled using [`brew bundle`](https://github.com/Homebrew/homebrew-bundle) @@ -75,18 +100,18 @@ Everything is built using a [Nix Flake](https://nix.dev/concepts/flakes.html), e - **PowerShell Profile**: Customized PowerShell profile with a styled prompt, optimized history settings, aliases, and various Linux utilities ported over to PowerShell for enhanced productivity +- **Komorebi Configuration**: Customizations and tweaks for the tiling window manager (extension to the [Desktop Window Manager](https://docs.microsoft.com/windows/win32/dwm/dwm-overview)) + --- And more to discover. ## โš™๏ธ Requirements -Ensure you have the latest stable release of [NixOS](https://nixos.org), [macOS](https://apple.com/macos) or [Windows](https://microsoft.com/windows) installed. +Ensure you have the latest stable release of [Arch Linux](https://archlinux.org), [macOS](https://apple.com/macos) or [Windows](https://microsoft.com/windows) installed. ### Dependencies -> **NixOS** users can skip this section. - [**Homebrew**](https://brew.sh) (**macOS only**) ```sh @@ -95,6 +120,12 @@ curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | [**Git**](https://www.git-scm.com) +Arch Linux: + +```sh +sudo pacman -S --needed --noconfirm git +``` + macOS: ```sh @@ -109,6 +140,12 @@ winget install -e --accept-package-agreements --accept-source-agreements --id Gi [**chezmoi**](https://chezmoi.io) +Arch Linux: + +```sh +sudo pacman -S --needed --noconfirm chezmoi +``` + macOS: ```sh @@ -121,6 +158,20 @@ Windows: winget install -e --accept-package-agreements --accept-source-agreements --id twpayne.chezmoi ``` +[**Wget**](https://www.gnu.org/software/wget) or [**curl**](https://curl.se) (**UNIX only**) + +Arch Linux: + +```sh +sudo pacman -S --needed --noconfirm wget curl +``` + +macOS (`curl` is pre-installed, but if you want to use `wget`): + +```sh +brew install wget +``` + [**PowerShell**](https://microsoft.com/PowerShell) (**Windows only**) > All versions of Windows come with PowerShell 5.1 pre-installed. However, please note that this repository requires PowerShell 7.x or higher. PowerShell 7.x+ does not replace or upgrade PowerShell 5.1; instead, it is installed alongside PowerShell 5.1. @@ -182,6 +233,101 @@ iwr https://raw.githubusercontent.com/Nitestack/dotfiles/HEAD/scripts/install.ps ## ๐Ÿ“– Documentation +### Bindings + +| Modifiers | Key | Description | OS | Flags | +| --- | --- | --- | --- | --- | +| Ctrl + Shift | R | Reload `ags` | `L`, `W` | - | +| Win | Tab | Toggle Workspaces Overview | `L` | - | +| Alt | Space | Toggle App Launcher | `L`, `W` | - | +| Win | V | Open Clipboard History | `L`, `W` | - | +| - | PowerOff Button | Toggle Power Menu | `L`, `W` | - | +| - | Print | Take Screenshot (Select Area) | `L`, `W` | - | +| Win | Print | Take Fullscreen Screenshot | `L`, `W` | - | +| Win + Alt | Print | Start Screen Recording | `L`, `W` | - | +| Win | Backslash | Open Terminal | `L`, `W` | - | +| Win | E | Open File Manager | `L`, `W` | - | +| Win | W | Open Browser | `L`, `W` | - | +| Ctrl + Shift | Escape | Open System Monitor | `L`, `W` | - | +| - | AudioLowerVolume Button | Decrease Volume | `L`, `W` | `l`, `e` | +| - | AudioRaiseVolume Button | Increase Volume | `L`, `W` | `l`, `e` | +| - | AudioMute Button | Mute/Unmute Volume | `L`, `W` | `l` | +| - | AudioMicMute Button | Mute/Unmute Microphone | `L`, `W` | `l` | +| - | AudioPlay Button | Play/Pause | `L`, `W` | `l` | +| - | AudioPause Button | Play/Pause | `L`, `W` | `l` | +| - | AudioNext Button | Skip to Next Track | `L`, `W` | `l` | +| - | AudioPrev Button | Return to Previous Track | `L`, `W` | `l` | +| - | MonBrightnessDown Button | Decrease Screen Brightness | `L`, `W` | `l`, `e` | +| - | MonBrightnessUp Button | Increase Screen Brightness | `L`, `W` | `l`, `e` | +| Win | H | Move Focus to Left Window | `L`, `W` | - | +| Win | L | Move Focus to Right Window | `L`, `W` | - | +| Win | K | Move Focus to Upper Window | `L`, `W` | - | +| Win | J | Move Focus to Lower Window | `L`, `W` | - | +| Win | Right Mouse Button | Resize Window | `L` | - | +| Win | F | Toggle Fullscreen | `L` | - | +| Win | M | Maximize/Restore Window | `L`, `W` | - | +| Win | โ† | Resize Window to the Left | `L`, `W` | `e` | +| Win | โ†’ | Resize Window to the Right | `L`, `W` | `e` | +| Win | โ†‘ | Resize Window Upwards | `L`, `W` | `e` | +| Win | โ†“ | Resize Window Downwards | `L`, `W` | `e` | +| Win | Left Mouse Button | Move Window | `L` | - | +| Win + Alt | H | Move Window Left | `L`, `W` | - | +| Win + Alt | L | Move Window Right | `L`, `W` | - | +| Win + Alt | K | Move Window Upwards | `L`, `W` | - | +| Win + Alt | J | Move Window Downwards | `L`, `W` | - | +| Win | Q | Close Active Window | `L`, `W` | - | +| Win | C | Center Window | `L` | - | +| Win | P | Toggle Focused Window's Pseudo Mode | `L` | - | +| Win | R | Toggle Split Orientation | `L`, `W` | - | +| Win | T | Toggle Active Window Floating | `L`, `W` | - | +| Win + Shift | T | Toggle All Windows Floating | `L`, `W` | - | +| Win | 1 | Switch to Workspace 1 | `L`, `W` | - | +| Win | 2 | Switch to Workspace 2 | `L`, `W` | - | +| Win | 3 | Switch to Workspace 3 | `L`, `W` | - | +| Win | 4 | Switch to Workspace 4 | `L`, `W` | - | +| Win | 5 | Switch to Workspace 5 | `L`, `W` | - | +| Win | 6 | Switch to Workspace 6 | `L`, `W` | - | +| Win | 7 | Switch to Workspace 7 | `L`, `W` | - | +| Win | 8 | Switch to Workspace 8 | `L`, `W` | - | +| Win | 9 | Switch to Workspace 9 | `L`, `W` | - | +| Win | 0 | Switch to Workspace 10 | `L`, `W` | - | +| Win + Ctrl | H | Switch to Previous Workspace | `L`, `W` | - | +| Win + Ctrl | L | Switch to Next Workspace | `L`, `W` | - | +| Win | Mouse Wheel Down | Switch to Previous Workspace | `L`, `W` | - | +| Win | Mouse Wheel Up | Switch to Next Workspace | `L`, `W` | - | +| Win + Shift | 1 | Move Active Window to Workspace 1 | `L`, `W` | - | +| Win + Shift | 2 | Move Active Window to Workspace 2 | `L`, `W` | - | +| Win + Shift | 3 | Move Active Window to Workspace 3 | `L`, `W` | - | +| Win + Shift | 4 | Move Active Window to Workspace 4 | `L`, `W` | - | +| Win + Shift | 5 | Move Active Window to Workspace 5 | `L`, `W` | - | +| Win + Shift | 6 | Move Active Window to Workspace 6 | `L`, `W` | - | +| Win + Shift | 7 | Move Active Window to Workspace 7 | `L`, `W` | - | +| Win + Shift | 8 | Move Active Window to Workspace 8 | `L`, `W` | - | +| Win + Shift | 9 | Move Active Window to Workspace 9 | `L`, `W` | - | +| Win + Shift | 0 | Move Active Window to Workspace 10 | `L`, `W` | - | +| Win + Shift | H | Move Active Window to Previous Workspace | `L`, `W` | - | +| Win + Shift | L | Move Active Window to Next Workspace | `L`, `W` | - | +| Win | S | Toggle Scratchpad | `L` | - | +| Win + Shift | S | Move Active Window to Scratchpad | `L` | - | + +#### OS Compatibility + +- `L` - Linux +- `W` - Windows +- `M` - macOS + +#### Binding Flags + +From the [Hyprland binding flags reference](https://wiki.hyprland.org/Configuring/Binds/#bind-flags): + +- `l` - locked, will also work when an input inhibitor (e.g. a lockscreen) is active. +- `r` - release, will trigger on release of a key. +- `e` - repeat, will repeat when held. +- `n` - non-consuming, key/mouse events will be passed to the active window in addition to triggering the dispatcher. +- `t` - transparent, cannot be shadowed by other binds. +- `i` - ignore mods, will ignore modifiers. +- `s` - separate, will arbitrarily combine keys between each mod/key, see [Keysym combos](https://wiki.hyprland.org/Configuring/Binds/#keysym-combos). + ## ๐Ÿ™Œ Credits - [Tom Payne](https://github.com/twpayne) @@ -195,13 +341,12 @@ iwr https://raw.githubusercontent.com/Nitestack/dotfiles/HEAD/scripts/install.ps - [Renรฉ-Marc Simard](https://github.com/renemarc) - the header section of his dotfiles README is used - [Aylur](https://github.com/Aylur) - - parts of his Nix configuration was used + - creator of [ags](https://aylur.github.io/ags-docs) + - his ags configuration was used as a base - [end-4](https://github.com/end-4) - parts of his dotfiles are used - [Pratik Gayen](https://github.com/FireDrop6000/hyprland-mydots) - Hyprlock config is used -- [Elliott Minns](https://github.com/elliottminns) ([Dreams of Code](https://www.youtube.com/@dreamsofcode)) - - parts of his Nix configuration was used ## ๐Ÿ“ License diff --git a/config/.chezmoi.yml.tmpl b/config/.chezmoi.yml.tmpl index 896bd256..61aa233d 100644 --- a/config/.chezmoi.yml.tmpl +++ b/config/.chezmoi.yml.tmpl @@ -1,5 +1,5 @@ {{- $name := promptStringOnce . "name" "Name" "Nitestack" -}} -{{- $email := promptStringOnce . "email" "Email Address" "74626967+Nitestack@users.noreply.github.com" -}} +{{- $email := promptStringOnce . "email" "Email Address" -}} {{- $hosttype := promptChoiceOnce . "host-type" "Host Type" (list "personal" "work") "personal" -}} {{- $osID := .chezmoi.os -}} {{- if (and (eq .chezmoi.os "linux") (hasKey .chezmoi.osRelease "id")) -}} @@ -28,6 +28,7 @@ data: hosttype: {{ $hosttype | quote }} device_type: {{ $chassisType | quote }} osid: {{ $osID | quote }} + project_base_path: "Programming/projects" # do not override the following values {{- if eq .chezmoi.os "linux" -}} {{- if (.chezmoi.kernel.osrelease | lower | contains "microsoft") }} diff --git a/config/.chezmoidata/apps.yml b/config/.chezmoidata/apps.yml index ea0323a4..452aafb2 100644 --- a/config/.chezmoidata/apps.yml +++ b/config/.chezmoidata/apps.yml @@ -5,28 +5,48 @@ --- apps: common: + - name: "Android Studio" + arch: + paru: "android-studio" + mac: "android-studio" + win: "Google.AndroidStudio" - name: "Bitwarden" + arch: "bitwarden" mac: "bitwarden" win: "Bitwarden.Bitwarden" - name: "Docker" + arch: + paru: "docker-desktop" mac: "docker" win: "Docker.DockerDesktop" + - name: "Ferdium" + arch: + paru: "ferdium" + mac: "ferdium" + win: "Ferdium.Ferdium" - name: "Figma" mac: "figma" win: "Figma.Figma" - - name: "Firefox" - mac: "firefox" - win: "Mozilla.Firefox" + - name: "Firefox Developer Edition" + arch: "firefox-developer-edition" + mac: "firefox@developer-edition" + win: "Mozilla.Firefox.DeveloperEdition" - name: "Google Chrome" + arch: + paru: "google-chrome" mac: "google-chrome" win: "Google.Chrome" - name: "IntelliJ IDEA Ultimate Edition" + arch: + paru: "intellij-idea-ultimate-edition" mac: "intellij-idea" win: "JetBrains.IntelliJIDEA.Ultimate" - name: "Logi Options+" mac: "logi-options-plus" win: "Logitech.OptionsPlus" - name: "Notion" + arch: + paru: "notion-app-electron" mac: "notion" win: "Notion.Notion" - name: "Notion Calendar" @@ -42,16 +62,23 @@ apps: mac: "readdle-spark" win: "Readdle.Spark" - name: "Spotify" + arch: "spotify-launcher" mac: "spotify" win: "Spotify.Spotify" - name: "Visual Studio Code" + arch: + paru: "visual-studio-code-bin" mac: "visual-studio-code" win: "Microsoft.VisualStudioCode" - name: "WebStorm" + arch: + paru: "webstorm" mac: "webstorm" win: "JetBrains.WebStorm" - name: "WezTerm" + arch: "wezterm" mac: "wezterm" win: "wez.wezterm" - name: "Zed" + arch: "zed" mac: "zed" diff --git a/config/.chezmoidata/arch.yml b/config/.chezmoidata/arch.yml new file mode 100644 index 00000000..0c238fe8 --- /dev/null +++ b/config/.chezmoidata/arch.yml @@ -0,0 +1,103 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ Arch Linux โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +--- +packages: + arch: + pacman: + - "bluez" # Bluetooth + - "bluez-utils" # Bluetooth + - "brightnessctl" # Brightness control for internal monitors + - "dart-sass" # Required dependency for ags + - "desktop-file-utils" # Utilities for working with desktop entries + - "ddcutil" # Required for `ddcci-driver-linux` + - "docker" # Containerization + - "docker-compose" # Required for `docker` + - "dnsmasq" # Required for `libvirt` + - "easyeffects" # Audio effects for PipeWire applications + - "efibootmgr" # Required for `grub` + - "grub" # Boot loader + - "gst-plugin-pipewire" # Required for `pipewire` + - "gnome-bluetooth-3.0" # Required for `ags` + - "gvfs" # Required for `ags` + - "htop" # Process monitor + - "hypridle" # Idle daemon for Hyprland + - "hyprland" # Wayland compositor + - "hyprlock" # Lock screen for Hyprland + - "hyprpaper" # Wallpaper utility for Hyprland + - "i2c-tools" # Required for `ddcutil` + - "iptables-nft" # Required for `libvirt` + - "iwd" # Wireless daemon + - "java-environment-common" # containing common files for JDK + - "jdk-openjdk" # Latest JDK + - "kvantum" # Qt6 theme engine + - "kvantum-qt5" # Qt6 theme engine + - "libpulse" # Required for `pipewire-pulse` + - "libvirt" # collection of software that provides a convenient way to manage VM's + - "man-db" # man for Arch + - "networkmanager" # Network manager + - "noto-fonts-emoji" # Font: Noto Emoji Color + - "openbsd-netcat" # Required for `libvirt` + - "openssh" # SSH protocol implementation + - "otf-monaspace-nerd" # Font: MonaspiceNe Nerd Font + - "pacman-contrib" # Required for `paccache` + - "pavucontrol" # Volume control tool ("mixer") for PulseAudio + - "pipewire" # Multimedia framework + - "pipewire-audio" # Audio + - "pipewire-alsa" # ALSA support + - "pipewire-jack" # JACK support + - "pipewire-pulse" # PulseAudio support + - "playerctl" # Media control + - "polkit-gnome" # Authentication agent + - "power-profiles-daemon" # Power profiles + - "qt5-wayland" # Widget toolkit + - "qt6-wayland" # Widget toolkit + - "sddm" # Display manager + - "slurp" # Region selection for Wayland compositors + - "smartmontools" # analyzing and monitoring storage devices + - "swappy" # Wayland native snapshot editing tool + - "ttf-nerd-fonts-symbols" # Font: Symbols Nerd Font + - "waybar" # Wayland bar + - "wf-recorder" # Recording program for wlroots-based compositors + - "wireless_tools" # Manipulate the Wireless Extensions + - "wireplumber" # Volume control with PipeWire + - "wpa_supplicant" # Supplicant + - "xdg-desktop-portal" # Desktop integration portal for sandboxed apps + - "xdg-desktop-portal-hyprland" # Required for `Hyprland` + - "xdg-desktop-portal-wlr" # Required for `Hyprland` + - "xdg-user-dirs" # Manage "well known" user directories + - "xdg-utils" # Utilities for managing XDG MIME Applications + paru: + - "adw-gtk3-git" # System theme (customizable with `gradience`) + - "aylurs-gtk-shell" # ags - GTK widget toolkit + - "ddcci-driver-linux-dkms-git" # Expose external monitors in `sysfs` + - "easyeffects-presets" # Control EasyEffects from the polybar status bar + - "gradience" # Customizing Libadwaita applications and the adw-gtk3 theme + - "hyprpicker-git" # Color picker feature in Hyprland + - "hyprshade-git" # Switching screen shaders in Hyprland + - "mpris-proxy-service" # mpris-proxy automation + - "safeeyes" # Reduce and prevent repetitive strain injury + - "swww" # Required dependency for ags + - "ttf-rubik-vf" # Font: Rubik + - "wayshot" # Screenshot tool for wlroots compositors + - "wl-clip-persist" # Persistent clipboard +apps: + arch: + pacman: + - "dconf-editor" # dconf editor + - "geary" # Email client + - "gnome-calculator" # Calculator + - "gnome-clocks" # Timers + - "gnome-control-center" # System settings + - "gnome-disk-utility" # Disk utility + - "gnome-screenshot" # Screenshot + - "gnome-system-monitor" # Task manager + - "gnome-terminal" # Required dependency for `docker` + - "loupe" # Image viewer + - "nautilus" # File Manager + - "qemu-full" # VM support + - "qt5ct" # Qt5 Configuration Tool + - "qt6ct" # Qt6 Configuration Tool + - "virt-manager" # Desktop user interface for managing VM's + - "vlc" # Media player diff --git a/config/.chezmoidata/macos.yml b/config/.chezmoidata/macos.yml index 055c8bb2..2646492d 100644 --- a/config/.chezmoidata/macos.yml +++ b/config/.chezmoidata/macos.yml @@ -5,12 +5,7 @@ --- packages: mac: - formulae: - - "bc" # for TokyoNight TMUX - - "nowplaying-cli" - - "tmux" - - "jstkdng/programs/ueberzugpp" - + formulae: [] apps: mac: casks: diff --git a/config/.chezmoidata/packages.yml b/config/.chezmoidata/packages.yml index ad8ea0df..d214a606 100644 --- a/config/.chezmoidata/packages.yml +++ b/config/.chezmoidata/packages.yml @@ -6,25 +6,45 @@ packages: # โ”€โ”€ Essentials (get installed before the other packages) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ essentials: + - name: "base-devel" + arch: "base-devel" - name: "chezmoi" + arch: "chezmoi" mac: "chezmoi" win: "twpayne.chezmoi" + - name: "curl" + arch: "curl" + mac: "curl" - name: "git" + arch: "git" mac: "git" win: "Git.Git" - - name: "gum" - mac: "gum" - win: "charmbracelet.gum" - name: "pwsh" win: "Microsoft.PowerShell" - name: "python" + arch: "python" win: "Python.Python.3.12" + - name: "pip" + arch: "python-pip" + - name: "ruby" + arch: "ruby" + mac: "ruby" + - name: "unzip" + arch: "unzip" - name: "volta" mac: "volta" + arch: + custom: "curl https://get.volta.sh | bash -s -- --skip-setup" win: "Volta.Volta" - name: "wget" + arch: "wget" mac: "wget" - name: "rustup" + arch: + custom: | + sudo pacman -S --needed --noconfirm rustup + rustup update + rustup default stable mac: custom: | brew install rustup-init @@ -41,51 +61,105 @@ packages: - "yarn" # โ”€โ”€ Packages โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ common: + - name: "bashly" + arch: + custom: "gem install bashly" + mac: + custom: "gem install bashly" - name: "bat" + arch: "bat" mac: "bat" win: "sharkdp.bat" + - name: "bun" + arch: + custom: "curl -fsSL https://bun.sh/install | bash" + mac: "oven-sh/bun/bun" + win: "Oven-sh.Bun" + - name: "cmake" + arch: "cmake" + mac: "cmake" + win: "Kitware.CMake" - name: "delta" + arch: "git-delta" mac: "git-delta" win: "dandavison.delta" - name: "eza" + arch: "eza" mac: "eza" win: "eza-community.eza" - name: "fd" + arch: "fd" mac: "fd" win: "sharkdp.fd" - name: "fastfetch" + arch: "fastfetch" mac: "fastfetch" win: "Fastfetch-cli.Fastfetch" - name: "fzf" + arch: "fzf" mac: "fzf" win: "junegunn.fzf" + - name: "go" + arch: "go" + mac: "go" + win: "GoLang.Go" + - name: "gum" + arch: "gum" + mac: "gum" + win: "charmbracelet.gum" - name: "java" - mac: "openjdk" - win: "ojdkbuild.ojdkbuild" - - name: "lazydocker" - mac: "jesseduffield/lazydocker/lazydocker" - win: "JesseDuffield.lazydocker" + arch: "java-runtime-common" + mac: "oracle-jdk" + win: "Oracle.JDK.22" - name: "lazygit" - mac: "jesseduffield/lazygit/lazygit" + arch: "lazygit" win: "JesseDuffield.lazygit" + mac: "jesseduffield/lazygit/lazygit" - name: "less" + arch: "less" mac: "less" win: "jftuga.less" - name: "nvim" - mac: "neovim" - win: "Neovim.Neovim" + custom: | + bob install stable + bob install nightly + bob use stable - name: "oh-my-posh" + arch: + custom: "curl -s https://ohmyposh.dev/install.sh | bash -s -- -d ~/.local/bin" mac: "jandedobbeleer/oh-my-posh/oh-my-posh" win: "JanDeDobbeleer.OhMyPosh" - name: "rg" + arch: "ripgrep" mac: "ripgrep" win: "BurntSushi.ripgrep.MSVC" + - name: "Spicetify" + arch: + paru: "spicetify-cli" + mac: "spicetify-cli" + win: "Spicetify.Spicetify" + - name: "tmux" + arch: "tmux" + mac: "tmux" + - name: "ueberzug" + arch: + paru: "ueberzugpp" + mac: "jstkdng/programs/ueberzugpp" + - name: "vim" + arch: "vim" + mac: "vim" + win: "vim.vim" - name: "zoxide" + arch: "zoxide" mac: "zoxide" win: "ajeetdsouza.zoxide" npm: + - "@bitwarden/cli" - "npkill" - "tree-sitter-cli" + - "tsx" - "turbo" + - "vercel" cargo: + - "bob-nvim" - "nvim-switcher" diff --git a/config/.chezmoidata/settings.yml b/config/.chezmoidata/settings.yml index 28f6409c..29348bfa 100644 --- a/config/.chezmoidata/settings.yml +++ b/config/.chezmoidata/settings.yml @@ -3,6 +3,16 @@ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ --- +gtk: + icon: + theme: + name: "WhiteSur" + install: + paru: "whitesur-icon-theme" + cursor: + theme: + name: "macOS" + size: 24 font: size: 14 sans: @@ -11,3 +21,59 @@ font: nerd: family: "MonaspiceNe Nerd Font" weight: "Regular" +theme: + colorscheme: "dark" + blur: 15 + spacing: 12 + padding: 7 + window_margin: 1.7 + border: + width: 1 + opacity: 96 + radius: 11 + widget: + opacity: 94 + dark: + primary: + bg: "#1e66f5" + accent: "#89b4fa" + error: + bg: "#d20f39" + accent: "#f38ba8" + success: + bg: "#40a02b" + accent: "#a6e3a1" + warning: + bg: "#df8e1d" + accent: "#f9e2af" + fg: "#cdd6f4" + bg: "#1e1e2e" + view: "#181825" + card: "#11111b" + surface: "#313244" + + widget: "#cdd6f4" + border: "#cdd6f4" + inactiveBorder: "#282828" + light: + primary: + bg: "#1e66f5" + accent: "#8caaee" + error: + bg: "#d20f39" + accent: "#e78284" + success: + bg: "#40a02b" + accent: "#a6d189" + warning: + bg: "#df8e1d" + accent: "#e5c890" + fg: "#4c4f69" + bg: "#eff1f5" + view: "#e6e9ef" + card: "#dce0e8" + surface: "#ccd0da" + + widget: "#4c4f69" + border: "#4c4f69" + inactiveBorder: "#282828" diff --git a/config/.chezmoidata/windows.yml b/config/.chezmoidata/windows.yml index 0abd326b..5b80d0c9 100644 --- a/config/.chezmoidata/windows.yml +++ b/config/.chezmoidata/windows.yml @@ -6,7 +6,9 @@ packages: win: winget: + - "AutoHotkey.AutoHotkey" - "Microsoft.DotNet.SDK.8" + - "LGUG2Z.komorebi" - "LLVM.LLVM" - "mbuilov.sed" - "gerardog.gsudo" diff --git a/config/.chezmoiexternal.yml.tmpl b/config/.chezmoiexternal.yml.tmpl index 530e9bcb..5041dda2 100644 --- a/config/.chezmoiexternal.yml.tmpl +++ b/config/.chezmoiexternal.yml.tmpl @@ -3,11 +3,12 @@ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ # bat -{{ if or (eq .chezmoi.os "windows") (eq .chezmoi.os "darwin") }} -{{- if eq .chezmoi.os "windows" -}} +{{ if eq .chezmoi.os "windows" -}} "AppData/Roaming/bat": {{- else if eq .chezmoi.os "darwin" }} "Library/Application Support": +{{- else }} +".config/bat": {{- end }} type: archive url: "https://github.com/catppuccin/bat/archive/master.tar.gz" @@ -15,7 +16,6 @@ refreshPeriod: "168h" include: - "*/themes/**" -{{ end }} # Oh My Zsh {{ if ne .chezmoi.os "windows" -}} @@ -59,3 +59,14 @@ exact: true refreshPeriod: "168h" {{ end }} + +# Apple Cursor Theme +{{ if eq .osid "linux-arch" }} +".icons": + type: archive + url: "https://github.com/ful1e5/apple_cursor/releases/download/{{- (gitHubLatestRelease "ful1e5/apple_cursor").TagName -}}/macOS.tar.xz" + stripComponents: 1 + refreshPeriod: "168h" + exclude: + - "*/LICENSE" +{{ end }} diff --git a/config/.chezmoiignore b/config/.chezmoiignore index 35de212c..e162d781 100644 --- a/config/.chezmoiignore +++ b/config/.chezmoiignore @@ -13,13 +13,25 @@ Documents .wslconfig {{ end }} +# Arch Linux +{{ if ne .osid "linux-arch" }} +.chezmoiscripts/arch/** -# NixOS -{{ if ne .osid "linux-nixos" }} +Pictures + +.config/ags +.config/bat .config/Code +.config/hypr .config/lazygit +.config/paru +.config/qt5ct +.config/qt6ct -Pictures +.local + +.hushlogin +.zprofile {{ end }} # macOS @@ -34,6 +46,7 @@ Library .chezmoiscripts/_unix/** .chezmoiscripts/unix/** +.config/spicetify .config/tmux .config/zed @@ -44,16 +57,14 @@ Library .config/nvim/templates -# Ignore on NixOS -{{ if eq .osid "linux-nixos" }} -.config/wezterm/wezterm.lua - -.ssh - -.gitconfig -{{ end }} +# ags +.config/ags/bun.lockb +.config/ags/node_modules +.config/ags/package.json +.config/ags/prettier.config.mjs +.config/ags/types -# Ignore SSH keys in work environment or on NixOS +# Ignore SSH keys in work environment # {{ if eq .hosttype "work" }} .ssh # {{ end }} diff --git a/config/.chezmoiscripts/_unix/run_before_01_greet.sh.tmpl b/config/.chezmoiscripts/_unix/run_before_01_greet.sh.tmpl index e1db2ef2..7da0f269 100644 --- a/config/.chezmoiscripts/_unix/run_before_01_greet.sh.tmpl +++ b/config/.chezmoiscripts/_unix/run_before_01_greet.sh.tmpl @@ -16,7 +16,11 @@ EOF echo # Install gum -# {{ if eq .chezmoi.os "darwin" }} +# {{ if eq .osid "linux-arch" }} +if ! pacman -Q "gum" &>/dev/null; then + sudo pacman -S --needed --noconfirm gum &>/dev/null +fi +# {{ else if eq .chezmoi.os "darwin" }} if ! brew list "gum" &>/dev/null; then brew install gum &>/dev/null fi diff --git a/config/.chezmoiscripts/arch/run_after_01-configure-system.sh.tmpl b/config/.chezmoiscripts/arch/run_after_01-configure-system.sh.tmpl new file mode 100644 index 00000000..2ef02c3c --- /dev/null +++ b/config/.chezmoiscripts/arch/run_after_01-configure-system.sh.tmpl @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "systemd Units" + +# paccache +_enable_system_service "paccache.timer" + +# playerctl +echo +_enable_user_service "gvfs-daemon.service" +_enable_user_service "mpris-proxy.service" + +# Bluetooth +echo +_enable_system_service "bluetooth.service" + +_set_option_with_sudo "Experimental" "true" "/etc/bluetooth/main.conf" false true + +# Network +echo +_enable_system_service "NetworkManager.service" + +# Audio +echo +_enable_user_service "pipewire-pulse.service" + +# Power Profile +echo +_enable_system_service "power-profiles-daemon.service" + +# Docker +echo +_enable_system_service "docker.socket" + +echo +_log -l info --prefix "systemd" "Enabled units for system and user" diff --git a/config/.chezmoiscripts/arch/run_after_02-configure-gnome.sh.tmpl b/config/.chezmoiscripts/arch/run_after_02-configure-gnome.sh.tmpl new file mode 100644 index 00000000..874bdaab --- /dev/null +++ b/config/.chezmoiscripts/arch/run_after_02-configure-gnome.sh.tmpl @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +function gsettings_ensure() { + local schema=$1 + local key=$2 + local value=$3 + + local first_args=() + + local current_value + current_value="$(gsettings "${first_args[@]}" get "${schema}" "${key}")" + + if [[ "${current_value}" != "${value}" && "${current_value}" != "'${value}'" ]]; then + gsettings "${first_args[@]}" set "${schema}" "${key}" "${value}" + fi +} + +_log_header "GNOME Configuration" + +# Setup VS Code as default text editor on GNOME +xdg-mime default code.desktop text/plain + +# Calculator +gsettings_ensure org.gnome.calculator show-thousands true + +# Nautilus +gsettings_ensure org.gnome.nautilus.preferences default-folder-viewer "icon-view" +gsettings_ensure org.gnome.nautilus.preferences show-delete-permanently true + +# Misc +gsettings_ensure org.gnome.desktop.interface font-name "{{- .font.sans.family -}}" +gsettings_ensure org.gnome.desktop.interface document-font-name "{{- .font.sans.family -}}" +gsettings_ensure org.gnome.desktop.interface monospace-font-name "{{- .font.nerd.family -}}" + +gsettings_ensure org.gtk.Settings.FileChooser show-hidden true +gsettings_ensure org.gtk.gtk4.Settings.FileChooser show-hidden true +gsettings_ensure org.gtk.Settings.FileChooser sort-directories-first true +gsettings_ensure org.gtk.gtk4.Settings.FileChooser sort-directories-first true +gsettings_ensure org.gtk.Settings.FileChooser startup-mode "cwd" +gsettings_ensure org.gtk.gtk4.Settings.FileChooser startup-mode "cwd" + +_log -l info --prefix "GNOME" "Set options" diff --git a/config/.chezmoiscripts/arch/run_after_03-add-ags-types.sh.tmpl b/config/.chezmoiscripts/arch/run_after_03-add-ags-types.sh.tmpl new file mode 100644 index 00000000..3b266f02 --- /dev/null +++ b/config/.chezmoiscripts/arch/run_after_03-add-ags-types.sh.tmpl @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "AGS Types" + +ags_config_path=$(find "${HOME}/.dotfiles/home" -type d -name '*ags' | head -n 1) + +if [[ -z "${ags_config_path}" ]]; then + _log -l warn --prefix "ags" "No config found" + exit +fi + +# Check if the types already exist +if [[ -d "${ags_config_path}/types" ]]; then + _log -l warn --prefix "ags" "types are already added" + exit +fi + +# Init config in ags-dotfiles +_spin "Generating types for ags" -- ags --init --config "${ags_config_path}/config.js" + +rm -f "${ags_config_path}/README.md" + +_log -l info --prefix "ags" "Added types" diff --git a/config/.chezmoiscripts/arch/run_after_04-configure-brightness.sh.tmpl b/config/.chezmoiscripts/arch/run_after_04-configure-brightness.sh.tmpl new file mode 100644 index 00000000..182c5611 --- /dev/null +++ b/config/.chezmoiscripts/arch/run_after_04-configure-brightness.sh.tmpl @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "External Display" + +# Check if i2c_dev is loaded +if ls /dev/i2c-* >&/dev/null; then + _log -l warn "i2c_dev module is already loaded" +else + sudo -v + + _spin "Adding i2c_dev to /etc/modules-load.d/" -- echo "i2c_dev" | sudo tee "/etc/modules-load.d/i2c.conf" + _log -l info "Loaded i2c_dev module" + _log -l fatal "A reboot is required" + exit 1 +fi + +# _log -l info "Checking if ddcci module is loaded" + +# # Check if the ddcci kernel module is loaded +# if lsmod | grep -q '^ddcci'; then +# _log -l warn "ddcci module is already loaded" +# else +# sudo -v +# +# # Load the ddcci kernel module +# _spin "Loading ddcci module" -- sudo modprobe ddcci +# _log -l info "Loaded ddcci module" +# fi + +# # Extract the device number using ddcutil +# device_number=$(ddcutil detect | grep -oE 'i2c-[0-9]+') + +# # Check if device number is found +# if [[ -n "${device_number}" ]]; then +# sudo -v +# +# # Attempt to create the new device entry +# if ! echo "ddcci 0x37" | sudo tee "/sys/bus/i2c/devices/${device_number}/new_device" >/dev/null 2>&1; then +# _log -l warn "Device entry for external display already exists" +# exit +# fi +# else +# _log -l error "Failed to find ddcci device number for external display" +# exit 1 +# fi \ No newline at end of file diff --git a/config/.chezmoiscripts/arch/run_before_01-configure-locales.sh.tmpl b/config/.chezmoiscripts/arch/run_before_01-configure-locales.sh.tmpl new file mode 100644 index 00000000..aadc43f7 --- /dev/null +++ b/config/.chezmoiscripts/arch/run_before_01-configure-locales.sh.tmpl @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "Locales" + +SYSTEM_LOCALE="en_US" +REGIONAL_LOCALE="de_DE" + +locale_is_set() { + local locale=$1 + localectl list-locales | grep -q "^${locale}.UTF-8$" +} + +# Check if both locales are already set +if locale_is_set "${SYSTEM_LOCALE}" && locale_is_set "${REGIONAL_LOCALE}"; then + _log -l warn "Locales are already generated and set" + exit +fi + +sudo -v + +# Uncomment the locales in /etc/locale.gen +if ! locale_is_set "${SYSTEM_LOCALE}"; then + sudo sed -i "s/^#${SYSTEM_LOCALE}.UTF-8 UTF-8/${SYSTEM_LOCALE}.UTF-8 UTF-8/" /etc/locale.gen +fi +if ! locale_is_set "${REGIONAL_LOCALE}"; then + sudo sed -i "s/^#${REGIONAL_LOCALE}.UTF-8 UTF-8/${REGIONAL_LOCALE}.UTF-8 UTF-8/" /etc/locale.gen +fi + +# Generate the locales +_spin "Generating locales" -- sudo locale-gen + +# Set the system locale +if ! locale_is_set "${SYSTEM_LOCALE}"; then + sudo localectl set-locale LANG="${SYSTEM_LOCALE}.UTF-8" +fi +# Set regional settings +if ! locale_is_set "${REGIONAL_LOCALE}"; then + sudo localectl set-locale LC_ADDRESS="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_IDENTIFICATION="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_MEASUREMENT="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_MONETARY="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_NAME="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_NUMERIC="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_PAPER="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_TELEPHONE="${REGIONAL_LOCALE}.UTF-8" + sudo localectl set-locale LC_TIME="${REGIONAL_LOCALE}.UTF-8" +fi + +_log "Generated and set locales" diff --git a/config/.chezmoiscripts/arch/run_before_02-configure-pacman.sh.tmpl b/config/.chezmoiscripts/arch/run_before_02-configure-pacman.sh.tmpl new file mode 100644 index 00000000..5c1acadf --- /dev/null +++ b/config/.chezmoiscripts/arch/run_before_02-configure-pacman.sh.tmpl @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +# Path to the pacman configuration file +PACMAN_CONF="/etc/pacman.conf" + +_log_header "pacman Configuration" + +# Uncomment an option or flag if commented +uncomment_option() { + local option=$1 + + # Uncomment if commented + if grep -q "^#\s*${option}" "${PACMAN_CONF}"; then + sudo sed -i "s/^#\s*\(${option}\)/\1/" "${PACMAN_CONF}" + fi +} + +# Uncomment the next line if it is commented +uncomment_next_line_if_commented() { + local option=$1 + local line_number + + line_number=$(grep -n "^${option}" "${PACMAN_CONF}" | cut -d: -f1) + if [[ -n "${line_number}" ]]; then + local next_line_number=$((line_number + 1)) + if sed "${next_line_number}q;d" "${PACMAN_CONF}" | grep -q "^#"; then + sudo sed -i "${next_line_number}s/^#//" "${PACMAN_CONF}" + fi + fi +} + +# Add a line under a specified line +add_line_after() { + local line_to_add="$1" + local line_to_search="$2" + + if ! grep -q "${line_to_add}" "${PACMAN_CONF}"; then + sudo sed -i "/${line_to_search}/a ${line_to_add}" "${PACMAN_CONF}" + fi +} + +# Enable UseSyslog +_enable_flag_with_sudo "UseSyslog" "${PACMAN_CONF}" + +# Enable ParallelDownloads +_set_option_with_sudo "ParallelDownloads" "5" "${PACMAN_CONF}" false true + +# Enable Color +_enable_flag_with_sudo "Color" "${PACMAN_CONF}" + +# Add ILoveCandy under ParallelDownloads if not already there +add_line_after "ILoveCandy" "ParallelDownloads" + +# Uncomment multilib repository (for 32-bit support) +_enable_flag_with_sudo "\[multilib\]" "${PACMAN_CONF}" +uncomment_next_line_if_commented "\[multilib\]" + +_log -l info --prefix "pacman" "Set up ${PACMAN_CONF}" diff --git a/config/.chezmoiscripts/arch/run_before_03-configure-reflector.sh.tmpl b/config/.chezmoiscripts/arch/run_before_03-configure-reflector.sh.tmpl new file mode 100644 index 00000000..d4da5e2e --- /dev/null +++ b/config/.chezmoiscripts/arch/run_before_03-configure-reflector.sh.tmpl @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "Latest Mirrors" + +pre_exec() { + # Ensure reflector is installed + _install_packages_pacman "reflector" + + # Create or overwrite the reflector configuration file + _write_file_with_sudo "/etc/xdg/reflector/reflector.conf" "--save /etc/pacman.d/mirrorlist +--country Germany +--protocol https +--latest 5 +EOF' + " +} + +_enable_system_service "reflector.timer" "pre_exec" diff --git a/config/.chezmoiscripts/arch/run_before_04-install-paru.sh.tmpl b/config/.chezmoiscripts/arch/run_before_04-install-paru.sh.tmpl new file mode 100644 index 00000000..1136a701 --- /dev/null +++ b/config/.chezmoiscripts/arch/run_before_04-install-paru.sh.tmpl @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "AUR Helper" + +# Check if paru is already installed +if pacman -Q paru &>/dev/null; then + _log -l warn "paru is already installed" + exit +fi + +# Install paru +mkdir -p /tmp/paru-git +( + git clone https://aur.archlinux.org/paru.git /tmp/paru-git + cd /tmp/paru-git || exit 1 + makepkg -si --noconfirm +) +rm -rf /tmp/paru-git + +_log -l info "Installed paru" diff --git a/config/.chezmoiscripts/arch/run_before_05-chsh.sh.tmpl b/config/.chezmoiscripts/arch/run_before_05-chsh.sh.tmpl new file mode 100644 index 00000000..292cd85a --- /dev/null +++ b/config/.chezmoiscripts/arch/run_before_05-chsh.sh.tmpl @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "Shell Configuration" + +# Check if the current shell is zsh already +if [[ "${SHELL}" == "/usr/bin/zsh" ]]; then + _log -l warn "Default shell is already zsh" + exit +fi + +# Ensure zsh is installed +_install_packages_pacman "zsh" + +chsh -s "/usr/bin/zsh" + +_log -l info "Set the default shell to zsh" diff --git a/config/.chezmoiscripts/arch/run_onchange_after_01-configure-grub.sh.tmpl b/config/.chezmoiscripts/arch/run_onchange_after_01-configure-grub.sh.tmpl new file mode 100644 index 00000000..8a863c4f --- /dev/null +++ b/config/.chezmoiscripts/arch/run_onchange_after_01-configure-grub.sh.tmpl @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +# Reruns script when a new release was made. Current release: {{ (gitHubLatestRelease "Coopydood/HyperFluent-GRUB-Theme").TagName }} + +THEMES_DIR="/boot/grub/themes" +TMP_DIR="/tmp/HyperFluent-GRUB-Theme" +GRUB_CONFIG="/etc/default/grub" + +_log_header "Boot Loader Configuration" + +mkdir -p "${TMP_DIR}" + +# Download the theme tar.gz +_spin "Downloading hyperfluent themes" -- git clone --depth 1 "https://github.com/Coopydood/HyperFluent-GRUB-Theme.git" "${TMP_DIR}" +_log -l info "Downloaded hyperfluent themes" + +sudo -v + +sudo rm -rf "${THEMES_DIR}/hyperfluent-arch" +sudo mkdir -p "${THEMES_DIR}/hyperfluent-arch" +_spin "Moving hyperfluent-arch to the GRUB themes directory" -- sudo mv "${TMP_DIR}"/arch/* "${THEMES_DIR}/hyperfluent-arch" + +rm -rf "${TMP_DIR}" + +# Update the GRUB configuration file +_set_option_with_sudo "GRUB_THEME" "${THEMES_DIR}/hyperfluent-arch/theme.txt" "${GRUB_CONFIG}" + +_set_option_with_sudo "GRUB_GFXMODE" "1920x1080,auto" "${GRUB_CONFIG}" + +if gum confirm "Do you have a dual-boot system and want os-prober to auto-detect other operating systems?" --default=false; then + _install_packages_pacman "os-prober" + + _set_option_with_sudo "GRUB_DISABLE_OS_PROBER" "false" "${GRUB_CONFIG}" + + sudo os-prober +fi +_log -l info "Set grub options" + +# Update GRUB +_spin "Updating GRUB configuration" -- sudo grub-mkconfig -o /boot/grub/grub.cfg +_log -l info "Updated GRUB configuration" + +echo +_log -l info "Set up grub" diff --git a/config/.chezmoiscripts/arch/run_onchange_after_02-configure-sddm.sh.tmpl b/config/.chezmoiscripts/arch/run_onchange_after_02-configure-sddm.sh.tmpl new file mode 100644 index 00000000..1970d9d6 --- /dev/null +++ b/config/.chezmoiscripts/arch/run_onchange_after_02-configure-sddm.sh.tmpl @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +TARGET_DIR="/usr/share/sddm/themes/sddm-astronaut-theme" + +_log_header "Display Manager Theme" + +_log -l info "Ensure required dependencies are installed" +_install_packages_pacman "qt6-5compat" "qt6-declarative" "qt6-svg" + +sudo -v + +sudo rm -rf "${TARGET_DIR}" +_spin "Downloading sddm-astronaut-theme" -- sudo git clone --depth 1 "https://github.com/keyitdev/sddm-astronaut-theme.git" "${TARGET_DIR}" +_log -l info "Downloaded sddm-astronaut-theme" +sudo cp "${TARGET_DIR}"/Fonts/* "/usr/share/fonts/" + +# Customize sddm-astronaut-theme +_write_file_with_sudo "${TARGET_DIR}/theme.conf.user" 'PartialBlur="false" +Font="{{- .font.sans.family -}}" +HourFormat="hh:mm" +DateFormat="dddd, MMMM d"' +_log -l info "Customized sddm-astronaut-theme" + +# Create sddm config +_write_file_with_sudo "/etc/sddm.conf" "[Theme] +Current=sddm-astronaut-theme" +_log -l info "Created sddm config and set theme" + +_enable_system_service "sddm.service" + +echo +_log -l info "Set up sddm" diff --git a/config/.chezmoiscripts/arch/run_onchange_after_03-configure-hyprshade.sh.tmpl b/config/.chezmoiscripts/arch/run_onchange_after_03-configure-hyprshade.sh.tmpl new file mode 100644 index 00000000..44848b25 --- /dev/null +++ b/config/.chezmoiscripts/arch/run_onchange_after_03-configure-hyprshade.sh.tmpl @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +# Rerun if the following file changes: {{ include "private_dot_config/exact_hypr/hyprshade.toml" | sha256sum }} + +_log_header "Hyprland: Screen Shader" + +_spin "Installing systemd units for hyprshade" -- hyprshade install +_log -l info --prefix "hyprshade" "Installed systemd units" + +_enable_user_service "hyprshade.timer" diff --git a/config/.chezmoiscripts/arch/run_onchange_after_04-configure-vm.sh.tmpl b/config/.chezmoiscripts/arch/run_onchange_after_04-configure-vm.sh.tmpl new file mode 100644 index 00000000..b8698772 --- /dev/null +++ b/config/.chezmoiscripts/arch/run_onchange_after_04-configure-vm.sh.tmpl @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "Virtualization Configuration" + +_enable_system_service "libvirtd.service" +_enable_system_service "libvirtd.socket" + +_set_option_with_sudo "unix_sock_group" "libvirt" "/etc/libvirt/libvirtd.conf" true true +_set_option_with_sudo "unix_sock_rw_perms" "0770" "/etc/libvirt/libvirtd.conf" true true + +_set_option_with_sudo "firewall_backend" "iptables" "/etc/libvirt/network.conf" true + +_set_option_with_sudo "user" "${USER}" "/etc/libvirt/qemu.conf" true true +_set_option_with_sudo "group" "${USER}" "/etc/libvirt/qemu.conf" true true + +# Check if the user is in the kvm and libvirt groups +if groups "${USER}" | grep -qE "\b(kvm|libvirt)\b"; then + _log -l warn --prefix "usermod" "${USER} is already in kvm and libvirt groups" +else + sudo -v + _spin "Adding ${USER} to kvm and libvirt groups" -- sudo usermod -aG kvm,libvirt "${USER}" + _log -l info --prefix "usermod" "Added ${USER} to kvm and libvirt groups" +fi + +# Check the status of the libvirtd service +if ! systemctl is-active --quiet libvirtd.service; then + sudo systemctl restart libvirtd.service +fi +if ! systemctl is-active --quiet libvirtd.socket; then + sudo systemctl restart libvirtd.socket +fi + +# Set default network to autostart if not already set +if [[ $(sudo virsh net-info default | grep -i "Autostart" | awk '{print $2}') == "yes" ]]; then + _log -l warn --prefix "virsh" "Default network is already set to autostart" +else + sudo virsh net-autostart default + _log -l info --prefix "virsh" "Set default network to autostart" +fi + +_log -l info "Configured VM support" diff --git a/config/.chezmoiscripts/unix/run_after_01-update-neovim.sh.tmpl b/config/.chezmoiscripts/unix/run_after_01-update-neovim.sh.tmpl index bb3133d1..6b76246a 100644 --- a/config/.chezmoiscripts/unix/run_after_01-update-neovim.sh.tmpl +++ b/config/.chezmoiscripts/unix/run_after_01-update-neovim.sh.tmpl @@ -42,7 +42,7 @@ if gum confirm "Proceed with the updates?" --default=false; then _log -l warn "No changes in lazy-lock.json file" else git add "${lazy_lock_path}" - git commit "${lazy_lock_path}" -m "chore(nvim): update Neovim plugins" + git commit "${lazy_lock_path}" -m "chore(nvim): update lazy-lock.json" cd "${current_path}" || exit 1 _log -l info "Committed updated lazy-lock.json file" fi @@ -66,12 +66,12 @@ if gum confirm "Proceed with the updates?" --default=false; then _log -l warn "No changes in lazyvim.json file" else git add "${lazyvim_path}" - git commit "${lazyvim_path}" -m "chore(nvim): update LazyVim config" + git commit "${lazyvim_path}" -m "chore(nvim): update lazyvim.json" cd "${current_path}" || exit 1 _log -l info "Committed updated lazyvim.json file" fi _log -l info "Completed updates" else - _log -l warn "Skipping update process" + _log -l warn "Cancelled update process" fi diff --git a/config/.chezmoiscripts/unix/run_before_01-configure-spicetify.sh.tmpl b/config/.chezmoiscripts/unix/run_before_01-configure-spicetify.sh.tmpl new file mode 100644 index 00000000..332d8b9d --- /dev/null +++ b/config/.chezmoiscripts/unix/run_before_01-configure-spicetify.sh.tmpl @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +_log_header "Spicetify" + +if [[ -e "$(spicetify -c)" ]]; then + _log -l warn "Spicetify is already configured" + exit +fi + +if [[ ! -d "${HOME}/.config/spotify" ]] || [[ ! -d "${HOME}/.local/share/spotify-launcher" ]]; then + _log -l error "Please open Spotify and log in. Then run this script again." +fi + +_spin "Generating config file" -- spicetify + +_spin "Enabling devtools" -- spicetify backup apply enable-devtools + +curl -fsSL https://raw.githubusercontent.com/spicetify/spicetify-marketplace/main/resources/install.sh | sh + +_log -l info "Spicetify configured" diff --git a/config/.chezmoiscripts/unix/run_onchange_01-install-packages.sh.tmpl b/config/.chezmoiscripts/unix/run_onchange_01-install-packages.sh.tmpl index 3766750d..5170da19 100644 --- a/config/.chezmoiscripts/unix/run_onchange_01-install-packages.sh.tmpl +++ b/config/.chezmoiscripts/unix/run_onchange_01-install-packages.sh.tmpl @@ -17,15 +17,29 @@ _log_header "Essential Packages" # {{ $osid := .osid }} # {{ $os := .chezmoi.os }} +# {{ $essentialPackages := list }} # {{ $essentialCustomPackages := list }} # {{ range .packages.essentials }} -# {{ if and (eq $os "darwin") (and (hasKey . "mac") (hasKey .mac "custom")) }} +# {{ if and (eq $osid "linux-arch") (hasKey . "arch") }} +# {{ if eq "string" (printf "%T" .arch) }} +# {{ $essentialPackages = mustAppend $essentialPackages .arch }} +# {{ else if hasKey .arch "custom" }} +# {{ $essentialCustomPackages = mustAppend $essentialCustomPackages (dict .name .arch.custom) }} +# {{ end }} +# {{ else if and (eq $os "darwin") (and (hasKey . "mac") (hasKey .mac "custom")) }} # {{ $essentialCustomPackages = mustAppend $essentialCustomPackages (dict .name .mac.custom) }} # {{ else if hasKey . "custom" }} # {{ $essentialCustomPackages = mustAppend $essentialCustomPackages (dict .name .custom) }} # {{ end }} # {{ end }} +# {{ if eq $osid "linux-arch"}} +# โ”€โ”€ pacman โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +gum format -- "## pacman:" +paru -Syu +_install_packages_pacman "{{- $essentialPackages | join "\" \"" -}}" +# {{ end }} + # โ”€โ”€ custom โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ gum format -- "## custom:" # {{ range $essentialCustomPackages }} @@ -59,15 +73,53 @@ _log -l info "Installed essential packages" # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ _log_header "Packages" +# {{ $packages := list }} +# {{ $paruPackages := list }} # {{ $customPackages := list }} # {{ range .packages.common }} -# {{ if and (eq $os "darwin") (and (hasKey . "mac") (hasKey .mac "custom")) }} +# {{ if and (eq $osid "linux-arch") (hasKey . "arch") }} +# {{ if eq "string" (printf "%T" .arch) }} +# {{ $packages = mustAppend $packages .arch }} +# {{ else if hasKey .arch "paru" }} +# {{ $paruPackages = mustAppend $paruPackages .arch.paru }} +# {{ else if hasKey .arch "custom" }} +# {{ $customPackages = mustAppend $customPackages (dict .name .arch.custom) }} +# {{ end }} +# {{ else if and (eq $os "darwin") (and (hasKey . "mac") (hasKey .mac "custom")) }} # {{ $customPackages = mustAppend $customPackages (dict .name .mac.custom) }} # {{ else if hasKey . "custom" }} # {{ $customPackages = mustAppend $customPackages (dict .name .custom) }} # {{ end }} # {{ end }} +# {{ if eq $osid "linux-arch" }} +# If icon theme installation is specified, install it +# {{ if hasKey .gtk.icon.theme "install" }} +# {{ if hasKey .gtk.icon.theme.install "pacman" }} +# {{ $packages = mustAppend $packages .gtk.icon.theme.install.pacman }} +# {{ else if hasKey .gtk.icon.theme.install "paru" }} +# {{ $paruPackages = mustAppend $paruPackages .gtk.icon.theme.install.paru }} +# {{ end }} +# {{ end }} + +# If cursor theme installation is specified, install it +# {{ if hasKey .gtk.cursor.theme "install" }} +# {{ if hasKey .gtk.cursor.theme.install "pacman" }} +# {{ $packages = mustAppend $packages .gtk.cursor.theme.install.pacman }} +# {{ else if hasKey .gtk.cursor.theme.install "paru" }} +# {{ $paruPackages = mustAppend $paruPackages .gtk.cursor.theme.install.paru }} +# {{ end }} +# {{ end }} + +# โ”€โ”€ pacman โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +gum format -- "## pacman:" +_install_packages_pacman "{{- concat $packages .packages.arch.pacman | uniq | sortAlpha | join "\" \"" -}}" + +# โ”€โ”€ paru โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +gum format -- "## paru:" +_install_packages_paru "{{- concat $paruPackages .packages.arch.paru | uniq | sortAlpha | join "\" \"" -}}" +# {{ end }} + # โ”€โ”€ custom โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ gum format -- "## custom:" # {{ range $customPackages }} diff --git a/config/.chezmoiscripts/unix/run_onchange_02-install-apps.sh.tmpl b/config/.chezmoiscripts/unix/run_onchange_02-install-apps.sh.tmpl new file mode 100644 index 00000000..660dec29 --- /dev/null +++ b/config/.chezmoiscripts/unix/run_onchange_02-install-apps.sh.tmpl @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# {{ template "bash-library.sh" . }} + +# The following line is for ShellCheck to correctly identify the above included library +true || source "../../.chezmoitemplates/bash-library.sh" + +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ Note: Any brew related packages for macOS are handled โ”‚ +# โ”‚ already, check the custom mac scripts โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +# {{ if eq .osid "linux-arch"}} +# {{ $pacmanApps := list }} +# {{ $paruApps := list }} +# {{ range .apps.common }} +# {{ if hasKey . "arch" }} +# {{ if eq "string" (printf "%T" .arch) }} +# {{ $pacmanApps = mustAppend $pacmanApps .arch }} +# {{ else if hasKey .arch "paru" }} +# {{ $paruApps = mustAppend $paruApps .arch.paru }} +# {{ end }} +# {{ end }} +# {{ end }} +# {{ if hasKey .apps.arch "pacman" }} +# {{ $pacmanApps = concat $pacmanApps .apps.arch.pacman }} +# {{ else if hasKey .apps.arch "paru" }} +# {{ $paruApps = concat $paruApps .apps.arch.paru }} +# {{ end }} + +_log_header "Apps" + +# โ”€โ”€ pacman โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +gum format -- "## pacman:" +_install_packages_pacman "{{- $pacmanApps | uniq | sortAlpha | join "\" \"" -}}" + +# โ”€โ”€ paru โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +gum format -- "## paru:" +_install_packages_paru "{{- $paruApps | uniq | sortAlpha | join "\" \"" -}}" + +echo +_log -l info "Installed apps" +# {{ end }} diff --git a/config/.chezmoiscripts/unix/run_onchange_02-display-manual-installations.sh.tmpl b/config/.chezmoiscripts/unix/run_onchange_03-display-manual-installations.sh.tmpl similarity index 65% rename from config/.chezmoiscripts/unix/run_onchange_02-display-manual-installations.sh.tmpl rename to config/.chezmoiscripts/unix/run_onchange_03-display-manual-installations.sh.tmpl index f103e0e5..2e62ca80 100644 --- a/config/.chezmoiscripts/unix/run_onchange_02-display-manual-installations.sh.tmpl +++ b/config/.chezmoiscripts/unix/run_onchange_03-display-manual-installations.sh.tmpl @@ -10,4 +10,9 @@ _log -l info "You have to manually install the following apps:" # {{ range (concat .apps.mac.manual | uniq | sortAlpha) }} echo "- {{ . -}}" # {{ end }} +# {{ else if and (eq .osid "linux-arch") (hasKey .apps.arch "manual") }} +_log -l info "You have to manually install the following apps:" +# {{ range (concat .apps.arch.manual | uniq | sortAlpha) }} +echo "- {{ . -}}" +# {{ end }} # {{ end }} diff --git a/config/.chezmoiscripts/windows/run_after_02-update-neovim.ps1.tmpl b/config/.chezmoiscripts/windows/run_after_02-update-neovim.ps1.tmpl index 613c2aaa..5f305e91 100644 --- a/config/.chezmoiscripts/windows/run_after_02-update-neovim.ps1.tmpl +++ b/config/.chezmoiscripts/windows/run_after_02-update-neovim.ps1.tmpl @@ -40,7 +40,7 @@ if ($?) { } else { git add "$LazyLockPath" - git commit "$LazyLockPath" -m "chore(nvim): update Neovim plugins" + git commit "$LazyLockPath" -m "chore(nvim): update lazy-lock.json" Set-Location "$CurrentPath" _Log -l info "Committed updated lazy-lock.json file" } @@ -66,7 +66,7 @@ if ($?) { } else { git add "$LazyvimPath" - git commit "$LazyvimPath" -m "chore(nvim): update LazyVim config" + git commit "$LazyvimPath" -m "chore(nvim): update lazyvim.json" Set-Location "$CurrentPath" _Log -l info "Committed updated lazyvim.json file" } @@ -74,5 +74,5 @@ if ($?) { _Log -l info "Completed updates" } else { - _Log -l warn "Skipping update process" + _Log -l warn "Cancelled update process" } diff --git a/config/.chezmoitemplates/bash-library.sh b/config/.chezmoitemplates/bash-library.sh index 7be584ff..9085f48c 100644 --- a/config/.chezmoitemplates/bash-library.sh +++ b/config/.chezmoitemplates/bash-library.sh @@ -101,3 +101,90 @@ _write_file_with_sudo() { _spin "Writing to ${file_path}" -- echo "${content}" | sudo tee "${file_path}" >/dev/null } + +# โ”€โ”€ Arch Linux โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# {{ if eq .osid "linux-arch" }} + +# Function to install packages using pacman +# Usage: _install_packages_pacman [ ...] +_install_packages_pacman() { + toInstall=() + + for pkg; do + if pacman -Q "${pkg}" &>/dev/null; then + _log -l warn --prefix "pacman" "${pkg} is already installed" + continue + fi + toInstall+=("${pkg}") + done + + if [[ "${toInstall[*]}" == "" ]]; then + return + fi + + sudo pacman --needed --noconfirm -S "${toInstall[@]}" +} + +# Function to install packages using paru +# Usage: _install_packages_paru [ ...] +_install_packages_paru() { + toInstall=() + + for pkg; do + if paru -Q "${pkg}" &>/dev/null; then + _log -l warn --prefix "paru" "${pkg} is already installed" + continue + fi + toInstall+=("${pkg}") + done + + if [[ "${toInstall[*]}" == "" ]]; then + return + fi + + paru --needed -S "${toInstall[@]}" +} + +# Function to ensure a system service is enabled with sudo +# Usage: _enable_system_service [] +_enable_system_service() { + local service_name="$1" + local pre_exec_function="${2:-}" + + _log -l info --prefix "systemd" "Enabling ${service_name} unit" + + if systemctl is-enabled --quiet "${service_name}"; then + _log -l warn --prefix "systemd" "${service_name} unit is already enabled" + else + [[ -n ${pre_exec_function} ]] && ${pre_exec_function} + + sudo -v + + # Enable service + _spin "Enabling and starting ${service_name} unit" -- sudo systemctl enable --now "${service_name}" + + _log -l info --prefix "systemd" "Enabled ${service_name} unit" + fi +} + +# Function to ensure a system service is enabled for the current user +# Usage: _enable_user_service [] +_enable_user_service() { + local service_name="$1" + local pre_exec_function="${2:-}" + + _log -l info --prefix "systemd" "Enabling ${service_name} unit for the current user" + + if systemctl --user is-enabled --quiet "${service_name}"; then + _log -l warn --prefix "systemd" "${service_name} unit is already enabled for the current user" + else + [[ -n ${pre_exec_function} ]] && ${pre_exec_function} + + # Enable and start service for the current user + _spin "Enabling and starting ${service_name} unit for the current user" -- systemctl --user enable --now "${service_name}" + + _log -l info --prefix "systemd" "Enabled ${service_name} unit for the current user" + fi +} + +# {{ end }} diff --git a/nix/home-manager/scripts/default.nix b/config/.chezmoitemplates/bat/config similarity index 77% rename from nix/home-manager/scripts/default.nix rename to config/.chezmoitemplates/bat/config index 9f04db33..08140820 100644 --- a/nix/home-manager/scripts/default.nix +++ b/config/.chezmoitemplates/bat/config @@ -1,8 +1,5 @@ # โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Scripts โ”‚ +# โ”‚ BAT CONFIG โ”‚ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - imports = [ - ./nix-utils.nix - ]; -} + +--theme="Catppuccin Mocha" diff --git a/config/.chezmoitemplates/entry.desktop b/config/.chezmoitemplates/entry.desktop new file mode 100644 index 00000000..ae087fe8 --- /dev/null +++ b/config/.chezmoitemplates/entry.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Version=1.0 +Name={{- .name }} +Comment={{- .comment }} +Exec=google-chrome-stable --app="{{- .url -}}" --name={{- .name }} +Terminal=false +Type=Application +Icon={{- env "HOME" -}}/.local/share/icons/{{- .name -}}.png +Categories={{- .categories | join ";" }}; diff --git a/config/.chezmoitemplates/lazygit/config.yml b/config/.chezmoitemplates/lazygit/config.yml index d27c2a63..18141fa2 100644 --- a/config/.chezmoitemplates/lazygit/config.yml +++ b/config/.chezmoitemplates/lazygit/config.yml @@ -3,7 +3,6 @@ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ --- -# yaml-language-server: $schema=https://raw.githubusercontent.com/jesseduffield/lazygit/master/schema/config.json gui: # Catpuccin Mocha Blue theme: diff --git a/config/.chezmoitemplates/qt/qt.conf b/config/.chezmoitemplates/qt/qt.conf new file mode 100644 index 00000000..ba1ae342 --- /dev/null +++ b/config/.chezmoitemplates/qt/qt.conf @@ -0,0 +1,32 @@ +[Appearance] +color_scheme_path=/usr/share/qt{{- .qt -}}ct/colors/darker.conf +custom_palette=true +icon_theme={{- .icon_theme }} +standard_dialogs=default +style=kvantum-dark + +[Fonts] +fixed="{{- .font.nerd.family -}},12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,Regular" +general="{{- .font.sans.family -}},12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,Regular" + +[Interface] +activate_item_on_single_click=1 +buttonbox_layout=3 +cursor_flash_time=1000 +dialog_buttons_have_icons=2 +double_click_interval=400 +gui_effects=General, FadeMenu, AnimateCombo, FadeTooltip, AnimateToolBox +keyboard_scheme=4 +menus_have_icons=true +show_shortcuts_in_context_menus=true +stylesheets=@Invalid() +toolbutton_style=4 +underline_shortcut=2 +wheel_scroll_lines=3 + +[SettingsWindow] +geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x3\x93\0\0\x3\xd9\0\0\0\0\0\0\0\0\0\0\x3\xbf\0\0\x4\x13\0\0\0\0\x2\0\0\0\a\x80\0\0\0\0\0\0\0\0\0\0\x3\x93\0\0\x3\xd9) + +[Troubleshooting] +force_raster_widgets=1 +ignored_applications=@Invalid() diff --git a/config/.chezmoitemplates/spicetify/config-xpui.ini b/config/.chezmoitemplates/spicetify/config-xpui.ini new file mode 100644 index 00000000..e8b2e9f7 --- /dev/null +++ b/config/.chezmoitemplates/spicetify/config-xpui.ini @@ -0,0 +1,36 @@ +; โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +; โ”‚ SPICETIFY CONFIG โ”‚ +; โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +[Setting] +spotify_path = {{ .spotify_path }} +prefs_path = {{ .prefs_path }} +current_theme = marketplace +color_scheme = +spotify_launch_flags = +overwrite_assets = 0 +always_enable_devtools = 0 +inject_theme_js = 1 +inject_css = 1 +replace_colors = 1 +check_spicetify_update = 1 + +[Preprocesses] +disable_sentry = 1 +disable_ui_logging = 1 +remove_rtl_rule = 1 +expose_apis = 1 + +[AdditionalOptions] +custom_apps = marketplace +sidebar_config = 1 +home_config = 1 +experimental_features = 1 +extensions = + +[Patch] + +; DO NOT CHANGE! +[Backup] +version = +with = diff --git a/config/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl b/config/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl index c9984552..6bd9828b 100644 --- a/config/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl +++ b/config/Documents/PowerShell/Microsoft.PowerShell_profile.ps1.tmpl @@ -16,7 +16,6 @@ Set-Alias v nvim Set-Alias c Clear-Host Set-Alias lvim "$env:USERPROFILE\.local\bin\lvim.ps1" Set-Alias lg lazygit -Set-Alias lzd lazydocker Remove-Alias ls Remove-Alias cat Set-Alias cat bat @@ -89,7 +88,8 @@ function pgrep($Name) { # โ”€โ”€ Environment Variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ export "EDITOR" "{{- .editor -}}" -export BAT_THEME="Catppuccin Mocha" +export "KOMOREBI_CONFIG_HOME" "$env:APPDATA\komorebi" +export "KOMOREBI_AHK_EXE" "$env:LOCALAPPDATA\Programs\AutoHotkey\v2\AutoHotkey64.exe" # โ”€โ”€ User config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/config/dot_oh-my-zsh/exact_completions/_bob.tmpl b/config/dot_oh-my-zsh/exact_completions/_bob.tmpl new file mode 100644 index 00000000..8909b001 --- /dev/null +++ b/config/dot_oh-my-zsh/exact_completions/_bob.tmpl @@ -0,0 +1,4 @@ +{{- $bin := lookPath "bob" -}} +{{- if $bin -}} +{{- output $bin "complete" "zsh" -}} +{{- end -}} diff --git a/config/dot_oh-my-zsh/exact_completions/_bw.tmpl b/config/dot_oh-my-zsh/exact_completions/_bw.tmpl new file mode 100644 index 00000000..3c687e36 --- /dev/null +++ b/config/dot_oh-my-zsh/exact_completions/_bw.tmpl @@ -0,0 +1,4 @@ +{{- $bin := lookPath "bw" -}} +{{- if $bin -}} +{{- output $bin "completion" "--shell" "zsh" -}} +{{- end -}} diff --git a/config/dot_oh-my-zsh/exact_completions/_dotfiles.tmpl b/config/dot_oh-my-zsh/exact_completions/_dotfiles.tmpl new file mode 100644 index 00000000..ce5c1f3d --- /dev/null +++ b/config/dot_oh-my-zsh/exact_completions/_dotfiles.tmpl @@ -0,0 +1,4 @@ +{{- $bin := lookPath "dotfiles" -}} +{{- if $bin -}} +{{- output $bin "completion" -}} +{{- end -}} diff --git a/nix/pkgs/default.nix b/config/dot_zprofile similarity index 68% rename from nix/pkgs/default.nix rename to config/dot_zprofile index 563b01cc..d6c63151 100644 --- a/nix/pkgs/default.nix +++ b/config/dot_zprofile @@ -1,6 +1,8 @@ # โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ CUSTOM PACKAGES โ”‚ +# โ”‚ ZSH PROFILE CONFIG โ”‚ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -pkgs: { - hyprshade = pkgs.callPackage ./hyprshade { }; -} + +if [[ "$(tty)" = "/dev/tty1" ]]; then + mkdir -p ~/.cache + exec Hyprland > ~/.cache/hyprland.log 2>&1 +fi diff --git a/config/dot_zshrc.tmpl b/config/dot_zshrc.tmpl index 44b487fa..409f932e 100644 --- a/config/dot_zshrc.tmpl +++ b/config/dot_zshrc.tmpl @@ -6,19 +6,16 @@ export BUN_INSTALL="$HOME/.bun" export PATH="$BUN_INSTALL/bin:$PATH" +export PATH="$PATH:$(gem env path | sed 's#[^:]\+#&/bin#g')" + export PNPM_HOME="$HOME/.local/share/pnpm" export PATH="$PNPM_HOME:$PATH" -{{- if eq .osid "linux-nixos" }} - -export NIX_LD=$(nix eval --impure --raw --expr 'let pkgs = import {}; NIX_LD = pkgs.lib.fileContents "${pkgs.stdenv.cc}/nix-support/dynamic-linker"; in NIX_LD') -{{- end }} - export VOLTA_HOME="$HOME/.volta" export PATH="$VOLTA_HOME/bin:$PATH" {{ $paths := list }} {{- $homeDir := .chezmoi.homeDir }} -{{- range $_, $relPath := list "bin" ".local/bin" ".cargo/bin" ".console-ninja/.bin" -}} +{{- range $_, $relPath := list "bin" ".local/bin" ".local/share/bob/nvim-bin" ".cargo/bin" ".console-ninja/.bin" "go/bin" -}} {{- $path := joinPath $homeDir $relPath -}} {{- if stat $path -}} {{- $paths = mustAppend $paths $path -}} @@ -130,7 +127,6 @@ alias v="nvim" alias c="clear" alias cat="bat" alias lg="lazygit" -alias lzd="lazydocker" alias ls="eza --group-directories-first --icons --git --octal-permissions" alias lt="ls -T" @@ -142,9 +138,6 @@ eval "$(zoxide init --cmd cd zsh)" # Load fzf (must stay on the end) source <(fzf --zsh) -# bat theme -export BAT_THEME="Catppuccin Mocha" - # fastfetch if [[ $(tty) == *"pts"* ]]; then fastfetch diff --git a/config/empty_dot_hushlogin b/config/empty_dot_hushlogin new file mode 100644 index 00000000..e69de29b diff --git a/config/private_AppData/Roaming/bat/config.tmpl b/config/private_AppData/Roaming/bat/config.tmpl new file mode 100644 index 00000000..9394f72c --- /dev/null +++ b/config/private_AppData/Roaming/bat/config.tmpl @@ -0,0 +1 @@ +{{- template "bat/config" . -}} diff --git a/config/private_AppData/Roaming/exact_komorebi/applications.yaml b/config/private_AppData/Roaming/exact_komorebi/applications.yaml new file mode 100644 index 00000000..0128221e --- /dev/null +++ b/config/private_AppData/Roaming/exact_komorebi/applications.yaml @@ -0,0 +1,1443 @@ +- name: 1Password + identifier: + kind: Exe + id: 1Password.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: 1Password.exe + matching_strategy: Equals +- name: Ableton Live + identifier: + kind: Class + id: Ableton Live Window Class + matching_strategy: Legacy + float_identifiers: + - kind: Class + id: AbletonVstPlugClass + matching_strategy: Legacy + - kind: Class + id: Vst3PlugWindow + matching_strategy: Legacy +- name: Adobe Creative Cloud + identifier: + kind: Class + id: CreativeCloudDesktopWindowClass + matching_strategy: Legacy + options: + - tray_and_multi_window +- name: Adobe Photoshop + identifier: + kind: Class + id: Photoshop + matching_strategy: Legacy +- name: Adobe Premiere Pro + identifier: + kind: Class + id: Premiere Pro + matching_strategy: Legacy + float_identifiers: + - kind: Class + id: DroverLord - Window Class + matching_strategy: Equals +- name: Affinity Photo 2 + identifier: + kind: Title + id: Affinity Photo 2 + matching_strategy: Legacy + options: + - force + float_identifiers: + - kind: Exe + id: Photo.exe + matching_strategy: Equals +- name: Akiflow + identifier: + kind: Exe + id: Akiflow.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Android Studio + identifier: + kind: Exe + id: studio64.exe + matching_strategy: Equals + options: + - object_name_change +- name: Anki + identifier: + kind: Exe + id: anki.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: ArmCord + identifier: + kind: Exe + id: ArmCord.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: AutoHotkey + identifier: + kind: Exe + id: AutoHotkeyU64.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Title + id: Window Spy + matching_strategy: StartsWith + - kind: Exe + id: AutoHotkeyUX.exe + matching_strategy: Equals +- name: Beeper + identifier: + kind: Exe + id: Beeper.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Bitwarden + identifier: + kind: Exe + id: Bitwarden.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Blitz + identifier: + kind: Exe + id: Blitz.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Bloxstrap + identifier: + kind: Exe + id: Bloxstrap.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Bloxstrap.exe + matching_strategy: Equals +- name: Brave Browser + identifier: + kind: Exe + id: brave.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: CLion + identifier: + kind: Exe + id: clion64.exe + matching_strategy: Equals + options: + - object_name_change + - tray_and_multi_window + float_identifiers: + - kind: Class + id: SunAwtDialog + matching_strategy: Equals +- name: Calculator + identifier: + kind: Title + id: Calculator + matching_strategy: Equals + float_identifiers: + - kind: Title + id: Calculator + matching_strategy: Equals +- name: Citrix Receiver + identifier: + kind: Exe + id: SelfService.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: SelfService.exe + matching_strategy: Equals +- name: Clash Verge + identifier: + kind: Exe + id: Clash Verge.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Clementine + identifier: + kind: Exe + id: clementine.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: CopyQ + identifier: + kind: Exe + id: copyq.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Credential Manager UI Host + identifier: + kind: Exe + id: CredentialUIBroker.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: CredentialUIBroker.exe + matching_strategy: Equals +- name: Cron + identifier: + kind: Exe + id: Cron.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: DS4Windows + identifier: + kind: Exe + id: DS4Windows.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Delphi applications + identifier: + kind: Class + id: TApplication + matching_strategy: Legacy + float_identifiers: + - kind: Class + id: TApplication + matching_strategy: Legacy + - kind: Class + id: TWizardForm + matching_strategy: Legacy +- name: Discord + identifier: + kind: Exe + id: Discord.exe + matching_strategy: Equals + options: + - tray_and_multi_window + - layered +- name: Discord Bot Client + identifier: + kind: Exe + id: DiscordBotClient.exe + matching_strategy: Equals +- name: DiscordCanary + identifier: + kind: Exe + id: DiscordCanary.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: DiscordDevelopment + identifier: + kind: Exe + id: DiscordDevelopment.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: DiscordPTB + identifier: + kind: Exe + id: DiscordPTB.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Docker Desktop + identifier: + kind: Exe + id: Docker Desktop.exe + matching_strategy: Equals +- name: Dropbox + identifier: + kind: Exe + id: Dropbox.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Dropbox.exe + matching_strategy: Equals +- name: EA Desktop Client + identifier: + kind: Exe + id: EADesktop.exe + matching_strategy: Equals +- name: Eagle + identifier: + kind: Exe + id: Eagle.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: ElectronMail + identifier: + kind: Exe + id: ElectronMail.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Element + identifier: + kind: Exe + id: Element.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Elephicon + identifier: + kind: Exe + id: Elephicon.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Elephicon.exe + matching_strategy: Equals +- name: ElevenClock + identifier: + kind: Exe + id: ElevenClock.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Elgato Camera Hub + identifier: + kind: Exe + id: Camera Hub.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Camera Hub.exe + matching_strategy: Equals +- name: Elgato Control Center + identifier: + kind: Exe + id: ControlCenter.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: ControlCenter.exe + matching_strategy: Equals +- name: Elgato Wave Link + identifier: + kind: Exe + id: WaveLink.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: WaveLink.exe + matching_strategy: Equals +- name: Epic Games Launcher + identifier: + kind: Exe + id: EpicGamesLauncher.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Everything + identifier: + kind: Class + id: EVERYTHING + matching_strategy: Legacy + options: + - tray_and_multi_window +- name: Everything1.5a + identifier: + kind: Class + id: EVERYTHING_(1.5a) + matching_strategy: Legacy + options: + - force + - tray_and_multi_window +- name: FFMetrics + identifier: + kind: Exe + id: FFMetrics.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Figma + identifier: + kind: Exe + id: Figma.exe + matching_strategy: Equals +- name: Files + identifier: + kind: Exe + id: Files.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Flow Launcher + identifier: + kind: Exe + id: Flow.Launcher.exe + matching_strategy: Equals +- name: GOG Galaxy + identifier: + kind: Exe + id: GalaxyClient.exe + matching_strategy: Equals + options: + - force + - tray_and_multi_window + float_identifiers: + - kind: Class + id: Chrome_RenderWidgetHostHWND + matching_strategy: Legacy +- name: GitHub Credential Manager + identifier: + kind: Exe + id: git-credential-manager.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: git-credential-manager.exe + matching_strategy: Equals +- name: GitHub Desktop + identifier: + kind: Exe + id: GitHubDesktop.exe + matching_strategy: Equals +- name: GoPro Webcam + identifier: + kind: Class + id: GoPro Webcam + matching_strategy: Legacy + options: + - tray_and_multi_window +- name: Godot Manager + identifier: + kind: Exe + id: GodotManager.exe + matching_strategy: Equals + options: + - force + - object_name_change +- name: Golden Dict + identifier: + kind: Exe + id: GoldenDict.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Google Chrome + identifier: + kind: Exe + id: chrome.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Google Drive + identifier: + kind: Exe + id: GoogleDriveFS.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: GoogleDriveFS.exe + matching_strategy: Equals +- name: Guitar Rig 7 + identifier: + kind: Exe + id: Guitar Rig 7.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Guitar Rig 7.exe + matching_strategy: Equals +- name: Honeyview + identifier: + kind: Class + id: HoneyviewClassX + matching_strategy: Legacy +- name: Houdoku + identifier: + kind: Exe + id: Houdoku.exe + matching_strategy: Equals +- name: IntelliJ IDEA + identifier: + kind: Exe + id: idea64.exe + matching_strategy: Equals + options: + - object_name_change + - tray_and_multi_window + float_identifiers: + - kind: Class + id: SunAwtDialog + matching_strategy: Equals +- name: Itch.io + identifier: + kind: Exe + id: itch.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: KOOK + identifier: + kind: Exe + id: KOOK.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Keyviz + identifier: + kind: Exe + id: keyviz.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: keyviz.exe + matching_strategy: Equals +- name: Kleopatra + identifier: + kind: Exe + id: kleopatra.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Kotatogram + identifier: + kind: Exe + id: Kotatogram.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: LocalSend + identifier: + kind: Exe + id: localsend_app.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Logi Bolt + identifier: + kind: Exe + id: LogiBolt.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: LogiBolt.exe + matching_strategy: Equals +- name: LogiTune + identifier: + kind: Exe + id: LogiTune.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: LogiTune.exe + matching_strategy: Equals +- name: Logitech G HUB + identifier: + kind: Exe + id: lghub.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Logitech Options + identifier: + kind: Exe + id: LogiOptionsUI.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: LogiOptionsUI.exe + matching_strategy: Equals +- name: Mailspring + identifier: + kind: Exe + id: mailspring.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: ManicTime + identifier: + kind: Exe + id: ManicTimeClient.exe + matching_strategy: Equals + options: + - force + - object_name_change + - tray_and_multi_window +- name: ManyCam + identifier: + kind: Exe + id: ManyCam.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Mattermost + identifier: + kind: Exe + id: Mattermost.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Mica For Everyone + identifier: + kind: Exe + id: MicaForEveryone.exe + matching_strategy: Equals +- name: Microsoft Active Accessibility + identifier: + kind: Class + id: '' + matching_strategy: Legacy + float_identifiers: + - kind: Class + id: '#32770' + matching_strategy: Legacy +- name: Microsoft Excel + identifier: + kind: Exe + id: EXCEL.EXE + matching_strategy: Equals + options: + - layered + float_identifiers: + - kind: Class + id: _WwB + matching_strategy: Legacy +- name: Microsoft Outlook + identifier: + kind: Exe + id: OUTLOOK.EXE + matching_strategy: Equals + options: + - layered + - tray_and_multi_window + float_identifiers: + - kind: Class + id: _WwB + matching_strategy: Legacy + - kind: Class + id: MsoSplash + matching_strategy: Equals +- name: Microsoft PC Manager + identifier: + kind: Exe + id: MSPCManager.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: MSPCManager.exe + matching_strategy: Equals +- name: Microsoft PowerPoint + identifier: + kind: Exe + id: POWERPNT.EXE + matching_strategy: Equals + options: + - layered + float_identifiers: + - kind: Class + id: _WwB + matching_strategy: Legacy +- name: Microsoft SQL Server Management Studio + identifier: + kind: Exe + id: Ssms.exe + matching_strategy: Equals +- name: Microsoft Teams + identifier: + kind: Class + id: TeamsWebView + matching_strategy: Legacy + options: + - tray_and_multi_window +- name: Microsoft Teams classic + identifier: + kind: Exe + id: Teams.exe + matching_strategy: Equals + float_identifiers: + - kind: Title + id: Microsoft Teams Notification + matching_strategy: Legacy + - kind: Title + id: Microsoft Teams Call + matching_strategy: Legacy +- name: Microsoft Word + identifier: + kind: Exe + id: WINWORD.EXE + matching_strategy: Equals + options: + - layered + float_identifiers: + - kind: Class + id: _WwB + matching_strategy: Legacy +- name: Modern Flyouts + identifier: + kind: Exe + id: ModernFlyoutsHost.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Morgen + identifier: + kind: Exe + id: Morgen.exe + matching_strategy: Equals +- name: Mozilla Firefox + identifier: + kind: Exe + id: firefox.exe + matching_strategy: Equals + options: + - object_name_change + - tray_and_multi_window + float_identifiers: + - kind: Class + id: MozillaTaskbarPreviewClass + matching_strategy: Legacy +- name: MuseScore + identifier: + kind: Exe + id: MuseScore.exe + matching_strategy: Equals +- name: NVIDIA GeForce Experience + identifier: + kind: Exe + id: NVIDIA GeForce Experience.exe + matching_strategy: Equals +- name: NZXT CAM + identifier: + kind: Exe + id: NZXT CAM.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: NetEase Cloud Music + identifier: + kind: Exe + id: cloudmusic.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: NiceHash Miner + identifier: + kind: Exe + id: nhm_app.exe + matching_strategy: Equals + options: + - force +- name: NohBoard + identifier: + kind: Exe + id: NohBoard.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: NohBoard.exe + matching_strategy: Equals +- name: Notion Enhanced + identifier: + kind: Exe + id: Notion Enhanced.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: OBS Studio (32-bit) + identifier: + kind: Exe + id: obs32.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: OBS Studio (64-bit) + identifier: + kind: Exe + id: obs64.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: ONLYOFFICE Editors + identifier: + kind: Class + id: DocEditorsWindowClass + matching_strategy: Legacy + options: + - tray_and_multi_window +- name: Obsidian + identifier: + kind: Exe + id: Obsidian.exe + matching_strategy: Equals +- name: OneDrive + identifier: + kind: Exe + id: OneDrive.exe + matching_strategy: Equals + float_identifiers: + - kind: Class + id: OneDriveReactNativeWin32WindowClass + matching_strategy: Legacy +- name: OneQuick + identifier: + kind: Exe + id: OneQuick.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: OpenRGB + identifier: + kind: Exe + id: OpenRGB.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Paradox Launcher + identifier: + kind: Exe + id: Paradox Launcher.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Paradox Launcher.exe + matching_strategy: Equals +- name: Passware Kit Forensic + identifier: + kind: Exe + id: PasswareKitForensic.exe + matching_strategy: Equals +- name: Playnite + identifier: + kind: Exe + id: Playnite.DesktopApp.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: Playnite.FullscreenApp.exe + matching_strategy: Equals +- name: Plexamp + identifier: + kind: Exe + id: Plexamp.exe + matching_strategy: Equals +- name: Postman + identifier: + kind: Exe + id: Postman.exe + matching_strategy: Equals +- name: PowerToys + identifier: + kind: Exe + id: PowerToys.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: PowerToys.ColorPickerUI.exe + matching_strategy: Equals + - kind: Exe + id: PowerToys.CropAndLock.exe + matching_strategy: Equals + - kind: Exe + id: PowerToys.ImageResizer.exe + matching_strategy: Equals + - kind: Exe + id: PowerToys.Peek.UI.exe + matching_strategy: Equals + - kind: Exe + id: PowerToys.PowerLauncher.exe + matching_strategy: Equals + - kind: Exe + id: PowerToys.PowerAccent.exe + matching_strategy: Equals +- name: Process Hacker + identifier: + kind: Exe + id: ProcessHacker.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: ProcessHacker.exe + matching_strategy: Equals +- name: ProtonDrive + identifier: + kind: Exe + id: ProtonDrive.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: ProtonVPN + identifier: + kind: Exe + id: ProtonVPN.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: PyCharm + identifier: + kind: Exe + id: pycharm64.exe + matching_strategy: Equals + options: + - object_name_change + - tray_and_multi_window + float_identifiers: + - kind: Class + id: SunAwtDialog + matching_strategy: Equals +- name: QQ + identifier: + kind: Exe + id: QQ.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Title + id: ๅ›พ็‰‡ๆŸฅ็œ‹ๅ™จ + matching_strategy: Legacy + - kind: Title + id: ็พค่Š็š„่Šๅคฉ่ฎฐๅฝ• + matching_strategy: Legacy + - kind: Title + id: ่ฏญ้Ÿณ้€š่ฏ + matching_strategy: Legacy +- name: QtScrcpy + identifier: + kind: Exe + id: QtScrcpy.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: QuickLook + identifier: + kind: Exe + id: QuickLook.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: QuickLook.exe + matching_strategy: Equals +- name: RepoZ + identifier: + kind: Exe + id: RepoZ.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: RepoZ.exe + matching_strategy: Equals +- name: Rider + identifier: + kind: Exe + id: rider64.exe + matching_strategy: Equals + options: + - object_name_change + - tray_and_multi_window + float_identifiers: + - kind: Class + id: SunAwtDialog + matching_strategy: Equals + - kind: Title + id: PopupMessageWindow + matching_strategy: Legacy +- name: Roblox FPS Unlocker + identifier: + kind: Exe + id: rbxfpsunlocker.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: RoundedTB + identifier: + kind: Exe + id: RoundedTB.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: RoundedTB.exe + matching_strategy: Equals +- name: RoundedTB + identifier: + kind: Exe + id: RoundedTB.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: RustRover + identifier: + kind: Exe + id: rustrover64.exe + matching_strategy: Equals + options: + - object_name_change + - tray_and_multi_window + float_identifiers: + - kind: Class + id: SunAwtDialog + matching_strategy: Equals +- name: Sandboxie Plus + identifier: + kind: Exe + id: SandMan.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: ShareX + identifier: + kind: Exe + id: ShareX.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Sideloadly + identifier: + kind: Exe + id: sideloadly.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: sideloadly.exe + matching_strategy: Equals +- name: Signal + identifier: + kind: Exe + id: Signal.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: SiriKali + identifier: + kind: Exe + id: sirikali.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Slack + identifier: + kind: Exe + id: Slack.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Class + id: Chrome_RenderWidgetHostHWND + matching_strategy: Legacy +- name: Slack + identifier: + kind: Exe + id: slack.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Class + id: Chrome_RenderWidgetHostHWND + matching_strategy: Legacy +- name: Smart Install Maker + identifier: + kind: Exe + id: SIM.exe + matching_strategy: Equals + float_identifiers: + - kind: Class + id: obj_App + matching_strategy: Legacy + - kind: Class + id: obj_Form + matching_strategy: Legacy +- name: SnippingTool + identifier: + kind: Exe + id: SnippingTool.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: SnippingTool.exe + matching_strategy: Equals +- name: SoulseekQt + identifier: + kind: Exe + id: SoulseekQt.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Spotify + identifier: + kind: Exe + id: Spotify.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Steam + identifier: + kind: Class + id: vguiPopupWindow + matching_strategy: Legacy + float_identifiers: + - - kind: Exe + id: steamwebhelper.exe + matching_strategy: Equals + - kind: Title + id: Steam + matching_strategy: DoesNotEqual +- name: Steam Beta + identifier: + kind: Class + id: SDL_app + matching_strategy: Legacy + options: + - tray_and_multi_window + float_identifiers: + - kind: Title + id: notificationtoasts_ + matching_strategy: Legacy +- name: Stremio + identifier: + kind: Exe + id: stremio.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: System Informer + identifier: + kind: Exe + id: SystemInformer.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: SystemInformer.exe + matching_strategy: Equals +- name: SystemSettings + identifier: + kind: Exe + id: SystemSettings.exe + matching_strategy: Equals + float_identifiers: + - kind: Class + id: Shell_Dialog + matching_strategy: Legacy +- name: Task Manager + identifier: + kind: Exe + id: Taskmgr.exe + matching_strategy: Equals + float_identifiers: + - kind: Class + id: TaskManagerWindow + matching_strategy: Legacy +- name: Telegram + identifier: + kind: Exe + id: Telegram.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: TickTick + identifier: + kind: Exe + id: TickTick.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Total Commander + identifier: + kind: Exe + id: TotalCMD64.exe + matching_strategy: Equals + float_identifiers: + - kind: Class + id: TDLG2FILEACTIONMIN + matching_strategy: Equals +- name: TouchCursor + identifier: + kind: Exe + id: tcconfig.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: tcconfig.exe + matching_strategy: Equals +- name: TranslucentTB + identifier: + kind: Exe + id: TranslucentTB.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: TranslucentTB.exe + matching_strategy: Equals +- name: TranslucentTB + identifier: + kind: Exe + id: TranslucentTB.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Unity Hub + identifier: + kind: Exe + id: Unity Hub.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Unreal Editor + identifier: + kind: Exe + id: UnrealEditor.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: VMware Horizon Client + identifier: + kind: Exe + id: vmware-view.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: VRCX + identifier: + kind: Exe + id: VRCX.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Visual Studio + identifier: + kind: Exe + id: devenv.exe + matching_strategy: Equals + options: + - object_name_change +- name: Visual Studio Code + identifier: + kind: Exe + id: Code.exe + matching_strategy: Equals +- name: Visual Studio Code - Insiders + identifier: + kind: Exe + id: Code - Insiders.exe + matching_strategy: Equals +- name: Voice.ai + identifier: + kind: Exe + id: VoiceAI.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: WebStorm + identifier: + kind: Exe + id: webstorm64.exe + matching_strategy: Equals + options: + - object_name_change + - tray_and_multi_window + float_identifiers: + - kind: Class + id: SunAwtDialog + matching_strategy: Equals +- name: WebTorrent Desktop + identifier: + kind: Exe + id: WebTorrent.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: WinZip (32-bit) + identifier: + kind: Exe + id: winzip32.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: winzip32.exe + matching_strategy: Equals +- name: WinZip (64-bit) + identifier: + kind: Exe + id: winzip64.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: winzip64.exe + matching_strategy: Equals +- name: Windows Console (conhost.exe) + identifier: + kind: Class + id: ConsoleWindowClass + matching_strategy: Equals + options: + - force +- name: Windows Explorer + identifier: + kind: Exe + id: explorer.exe + matching_strategy: Equals + float_identifiers: + - kind: Class + id: OperationStatusWindow + matching_strategy: Legacy + - kind: Title + id: Control Panel + matching_strategy: Legacy +- name: Windows Installer + identifier: + kind: Exe + id: msiexec.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: msiexec.exe + matching_strategy: Equals +- name: Windows Subsystem for Android + identifier: + kind: Exe + id: WsaClient.exe + matching_strategy: Equals + float_identifiers: + - kind: Class + id: android(splash) + matching_strategy: Legacy +- name: Windows Update Standalone Installer + identifier: + kind: Exe + id: wusa.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: wusa.exe + matching_strategy: Equals +- name: WingetUI + identifier: + kind: Exe + id: WingetUI.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: WingetUI + identifier: + kind: Exe + id: wingetui.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Wox + identifier: + kind: Exe + id: Wox.exe + matching_strategy: Equals + float_identifiers: + - kind: Title + id: Hotkey sink + matching_strategy: Legacy +- name: XAMPP Control Panel + identifier: + kind: Exe + id: xampp-control.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: Zebar + identifier: + kind: Exe + id: Zebar.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Zebar.exe + matching_strategy: Equals +- name: Zoom + identifier: + kind: Exe + id: Zoom.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: Zoom.exe + matching_strategy: Equals +- name: komorebi-gui + identifier: + kind: Exe + id: komorebi-gui.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: komorebi-gui.exe + matching_strategy: Equals +- name: mpv + identifier: + kind: Class + id: mpv + matching_strategy: Legacy + options: + - object_name_change +- name: mpv.net + identifier: + kind: Exe + id: mpvnet.exe + matching_strategy: Equals + options: + - object_name_change +- name: paint.net + identifier: + kind: Exe + id: paintdotnet.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: paintdotnet.exe + matching_strategy: Equals +- name: pinentry + identifier: + kind: Exe + id: pinentry.exe + matching_strategy: Equals + float_identifiers: + - kind: Exe + id: pinentry.exe + matching_strategy: Equals +- name: qBittorrent + identifier: + kind: Exe + id: qbittorrent.exe + matching_strategy: Equals + options: + - tray_and_multi_window +- name: todoist + identifier: + kind: Exe + id: Todoist.exe + matching_strategy: Equals +- name: ueli + identifier: + kind: Exe + id: ueli.exe + matching_strategy: Equals + options: + - tray_and_multi_window + float_identifiers: + - kind: Exe + id: ueli.exe + matching_strategy: Equals diff --git a/config/private_AppData/Roaming/exact_komorebi/komorebi.ahk b/config/private_AppData/Roaming/exact_komorebi/komorebi.ahk new file mode 100644 index 00000000..2c0fbb86 --- /dev/null +++ b/config/private_AppData/Roaming/exact_komorebi/komorebi.ahk @@ -0,0 +1,75 @@ +; โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +; โ”‚ KOMOREBI AUTOHOTKEY CONFIG โ”‚ +; โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +#Requires AutoHotkey v2.0.2 +#SingleInstance Force + +Komorebic(cmd) { + RunWait(format("komorebic.exe {}", cmd), , "Hide") +} + +; โ”€โ”€ General โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +^+r:: Komorebic("reload-configuration") + +; โ”€โ”€ Apps โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +#\:: Run "wezterm-gui.exe" +#w:: Run "Arc.exe" + +; โ”€โ”€ Windows โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +; Move focus +#h:: Komorebic("focus left") +#j:: Komorebic("focus down") +#k:: Komorebic("focus up") +#l:: Komorebic("focus right") + +; Resize windows +#m:: Komorebic("toggle-maximize") +#Left:: Komorebic("resize-edge left increase") +#Right:: Komorebic("resize-edge right increase") +#Up:: Komorebic("resize-edge up increase") +#Down:: Komorebic("resize-edge down increase") + +; Move windows +#!h:: Komorebic("move left") +#!j:: Komorebic("move down") +#!k:: Komorebic("move up") +#!l:: Komorebic("move right") + +#q:: Komorebic("close") + +; Toggling +#r:: Komorebic("cycle-layout next") +#t:: Komorebic("toggle-float") ++#t:: Komorebic("toggle-pause") + +; Workspaces +#1:: Komorebic("focus-workspace 0") +#2:: Komorebic("focus-workspace 1") +#3:: Komorebic("focus-workspace 2") +#4:: Komorebic("focus-workspace 3") +#5:: Komorebic("focus-workspace 4") +#6:: Komorebic("focus-workspace 5") +#7:: Komorebic("focus-workspace 6") +#8:: Komorebic("focus-workspace 7") +#9:: Komorebic("focus-workspace 8") +#0:: Komorebic("focus-workspace 9") +^#l:: Komorebic("cycle-workspace next") +^#h:: Komorebic("cycle-workspace previous") +#WheelUp:: Komorebic("cycle-workspace next") +#WheelDown:: Komorebic("cycle-workspace previous") + +; Move windows across workspaces +#+1:: Komorebic("move-to-workspace 0") +#+2:: Komorebic("move-to-workspace 1") +#+3:: Komorebic("move-to-workspace 2") +#+4:: Komorebic("move-to-workspace 3") +#+5:: Komorebic("move-to-workspace 4") +#+6:: Komorebic("move-to-workspace 5") +#+7:: Komorebic("move-to-workspace 6") +#+8:: Komorebic("move-to-workspace 7") +#+9:: Komorebic("move-to-workspace 8") +#+0:: Komorebic("move-to-workspace 9") +#+l:: Komorebic("cycle-move-to-workspace next") +#+h:: Komorebic("cycle-move-to-workspace previous") \ No newline at end of file diff --git a/config/private_AppData/Roaming/exact_komorebi/komorebi.json.tmpl b/config/private_AppData/Roaming/exact_komorebi/komorebi.json.tmpl new file mode 100644 index 00000000..8c645cd9 --- /dev/null +++ b/config/private_AppData/Roaming/exact_komorebi/komorebi.json.tmpl @@ -0,0 +1,62 @@ +{ + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.27/schema.json", + "app_specific_configuration_path": "{{- env "KOMOREBI_CONFIG_HOME" | replace "\\" "/" -}}/applications.yaml", + "window_hiding_behaviour": "Cloak", + "cross_monitor_move_behaviour": "Insert", + "default_workspace_padding": {{ floor (divf (mulf .theme.window_margin .theme.spacing) 2) -}}, + "default_container_padding": {{ floor (divf (mulf .theme.window_margin .theme.spacing) 2) -}}, + "border": true, + "border_width": {{ .theme.border.width -}}, + "border_z_order": "TopMost", + "border_offset": -1, + "border_colours": { + "single": "#42a5f5", + "stack": "#00a542", + "monocle": "#ff3399", + "unfocused": "#808080" + }, + "stackbar": { + "height": 40, + "mode": "OnStack", + "tabs": { + "width": 300, + "focused_text": "#00a542", + "unfocused_text": "#b3b3b3", + "background": "#141414" + } + }, + "monitors": [ + { + "workspaces": [ + { + "name": "I", + "layout": "BSP" + }, + { + "name": "II", + "layout": "VerticalStack" + }, + { + "name": "III", + "layout": "HorizontalStack" + }, + { + "name": "IV", + "layout": "UltrawideVerticalStack" + }, + { + "name": "V", + "layout": "Rows" + }, + { + "name": "VI", + "layout": "Grid" + }, + { + "name": "VII", + "layout": "RightMainVerticalStack" + } + ] + } + ] +} diff --git a/config/private_AppData/Roaming/spicetify/config-xpui.ini.tmpl b/config/private_AppData/Roaming/spicetify/config-xpui.ini.tmpl new file mode 100644 index 00000000..bad74953 --- /dev/null +++ b/config/private_AppData/Roaming/spicetify/config-xpui.ini.tmpl @@ -0,0 +1 @@ +{{- template "spicetify/config-xpui.ini" dict "spotify_path" (printf "%s%s" (env "APPDATA") "\\Spotify") "prefs_path" (printf "%s%s" (env "APPDATA") "\\Spotify\\prefs") -}} diff --git a/config/private_Library/Application Support/bat/config.tmpl b/config/private_Library/Application Support/bat/config.tmpl new file mode 100644 index 00000000..9394f72c --- /dev/null +++ b/config/private_Library/Application Support/bat/config.tmpl @@ -0,0 +1 @@ +{{- template "bat/config" . -}} diff --git a/config/private_dot_config/bat/config.tmpl b/config/private_dot_config/bat/config.tmpl new file mode 100644 index 00000000..9394f72c --- /dev/null +++ b/config/private_dot_config/bat/config.tmpl @@ -0,0 +1 @@ +{{- template "bat/config" . -}} diff --git a/config/private_dot_config/exact_ags/.eslintrc.json b/config/private_dot_config/exact_ags/.eslintrc.json new file mode 100644 index 00000000..92738994 --- /dev/null +++ b/config/private_dot_config/exact_ags/.eslintrc.json @@ -0,0 +1,71 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2022, + "project": true + }, + "ignorePatterns": ["types/"], + "root": true, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended-type-checked", + "plugin:@typescript-eslint/stylistic-type-checked" + ], + "rules": { + "@typescript-eslint/prefer-nullish-coalescing": [ + "error", + { + "ignoreConditionalTests": true + } + ], + "@typescript-eslint/array-type": [ + "warn", + { + "default": "array" + } + ], + "@typescript-eslint/consistent-type-imports": [ + "warn", + { + "prefer": "type-imports", + "fixStyle": "separate-type-imports" + } + ], + "@typescript-eslint/no-unused-vars": [ + "warn", + { "argsIgnorePattern": "^_" } + ], + "prefer-const": "error", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/no-misused-promises": "warn", + "@typescript-eslint/no-floating-promises": "off" + }, + "globals": { + "Widget": "readonly", + "Utils": "readonly", + "App": "readonly", + "Variable": "readonly", + "Service": "readonly", + "pkg": "readonly", + "ARGV": "readonly", + "Debugger": "readonly", + "GIRepositoryGType": "readonly", + "globalThis": "readonly", + "imports": "readonly", + "Intl": "readonly", + "log": "readonly", + "logError": "readonly", + "print": "readonly", + "printerr": "readonly", + "window": "readonly", + "TextEncoder": "readonly", + "TextDecoder": "readonly", + "console": "readonly", + "setTimeout": "readonly", + "setInterval": "readonly", + "clearTimeout": "readonly", + "clearInterval": "readonly" + } +} diff --git a/config/private_dot_config/exact_ags/.gitignore b/config/private_dot_config/exact_ags/.gitignore new file mode 100644 index 00000000..971fcb7d --- /dev/null +++ b/config/private_dot_config/exact_ags/.gitignore @@ -0,0 +1,2 @@ +node_modules +types diff --git a/config/private_dot_config/exact_ags/bun.lockb b/config/private_dot_config/exact_ags/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..996c439117d923fa7fae49c87bf9814701d97d11 GIT binary patch literal 70003 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 + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/chat-bubbles-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/chat-bubbles-symbolic.svg new file mode 100644 index 00000000..fdee0b38 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/chat-bubbles-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/controller-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/controller-symbolic.svg new file mode 100644 index 00000000..98bf5d62 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/controller-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/controls-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/controls-symbolic.svg new file mode 100644 index 00000000..7df5663f --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/controls-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/dark-mode-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/dark-mode-symbolic.svg new file mode 100644 index 00000000..9f2e6b4e --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/dark-mode-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/hourglass-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/hourglass-symbolic.svg new file mode 100644 index 00000000..aa4f97cf --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/hourglass-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/light-mode-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/light-mode-symbolic.svg new file mode 100644 index 00000000..d5fb2713 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/light-mode-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/mixer-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/mixer-symbolic.svg new file mode 100644 index 00000000..ad6cfa85 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/mixer-symbolic.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/preferences-desktop-theme-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/preferences-desktop-theme-symbolic.svg new file mode 100644 index 00000000..44614542 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/preferences-desktop-theme-symbolic.svg @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/processor-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/processor-symbolic.svg new file mode 100644 index 00000000..832dbaf3 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/processor-symbolic.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/terminal-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/terminal-symbolic.svg new file mode 100644 index 00000000..9f82bcf5 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/terminal-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/config/private_dot_config/exact_ags/exact_assets/toolbars-symbolic.svg b/config/private_dot_config/exact_ags/exact_assets/toolbars-symbolic.svg new file mode 100644 index 00000000..9f4c564a --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_assets/toolbars-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/config/private_dot_config/exact_ags/exact_templates/gradience/preset.json b/config/private_dot_config/exact_ags/exact_templates/gradience/preset.json new file mode 100644 index 00000000..2a75a635 --- /dev/null +++ b/config/private_dot_config/exact_ags/exact_templates/gradience/preset.json @@ -0,0 +1,165 @@ +{ + "name": "Material3_Generated", + "variables": { + "theme_fg_color": "#AEE5FA", + "theme_text_color": "#AEE5FA", + "theme_bg_color": "#1a1b26", + "theme_base_color": "#1a1b26", + "theme_selected_bg_color": "#AEE5FA", + "theme_selected_fg_color": "rgba(0, 0, 0, 0.87)", + "insensitive_bg_color": "#1a1b26", + "insensitive_fg_color": "rgba(192, 202, 245, 0.5)", + "insensitive_base_color": "#24283b", + "theme_unfocused_fg_color": "#AEE5FA", + "theme_unfocused_text_color": "#c0caf5", + "theme_unfocused_bg_color": "#1a1b26", + "theme_unfocused_base_color": "#1a1b26", + "theme_unfocused_selected_bg_color": "#a9b1d6", + "theme_unfocused_selected_fg_color": "rgba(0, 0, 0, 0.87)", + "unfocused_insensitive_color": "rgba(192, 202, 245, 0.5)", + "borders": "rgba(192, 202, 245, 0.12)", + "unfocused_borders": "rgba(192, 202, 245, 0.12)", + "wm_title": "#AEE5FA", + "wm_unfocused_title": "rgba(192, 202, 245, 0.7)", + "wm_highlight": "rgba(192, 202, 245, 0.1)", + "wm_bg": "#1a1b26", + "wm_unfocused_bg": "#1a1b26", + "wm_button_close_icon": "#1a1b26", + "wm_button_close_hover_bg": "#a9b1d6", + "wm_button_close_active_bg": "#c7c7c7", + "content_view_bg": "#1a1b26", + "placeholder_text_color": "silver", + "text_view_bg": "#1d1d1d", + "budgie_tasklist_indicator_color": "#90D1F6", + "budgie_tasklist_indicator_color_active": "#90D1F6", + "budgie_tasklist_indicator_color_active_window": "#999999", + "budgie_tasklist_indicator_color_attention": "#FDD633", + + "STRAWBERRY_100": "#FF9262", + "STRAWBERRY_300": "#FF793E", + "STRAWBERRY_500": "#F15D22", + "STRAWBERRY_700": "#CF3B00", + "STRAWBERRY_900": "#AC1800", + + "ORANGE_100": "#FFDB91", + "ORANGE_300": "#FFCA40", + "ORANGE_500": "#FAA41A", + "ORANGE_700": "#DE8800", + "ORANGE_900": "#C26C00", + + "BANANA_100": "#FFFFA8", + "BANANA_300": "#FFFA7D", + "BANANA_500": "#FFCE51", + "BANANA_700": "#D1A023", + "BANANA_900": "#A27100", + + "LIME_100": "#A2F3BE", + "LIME_300": "#8ADBA6", + "LIME_500": "#73C48F", + "LIME_700": "#479863", + "LIME_900": "#1C6D38", + + "BLUEBERRY_100": "#94A6FF", + "BLUEBERRY_300": "#6A7CE0", + "BLUEBERRY_500": "#3F51B5", + "BLUEBERRY_700": "#213397", + "BLUEBERRY_900": "#031579", + + "GRAPE_100": "#D25DE6", + "GRAPE_300": "#B84ACB", + "GRAPE_500": "#9C27B0", + "GRAPE_700": "#830E97", + "GRAPE_900": "#6A007E", + + "COCOA_100": "#9F9792", + "COCOA_300": "#7B736E", + "COCOA_500": "#574F4A", + "COCOA_700": "#463E39", + "COCOA_900": "#342C27", + + "SILVER_100": "#EEE", + "SILVER_300": "#CCC", + "SILVER_500": "#AAA", + "SILVER_700": "#888", + "SILVER_900": "#666", + + "SLATE_100": "#888", + "SLATE_300": "#666", + "SLATE_500": "#444", + "SLATE_700": "#222", + "SLATE_900": "#111", + + "BLACK_100": "#474341", + "BLACK_300": "#403C3A", + "BLACK_500": "#393634", + "BLACK_700": "#33302F", + "BLACK_900": "#2B2928", + + "accent_color": "{{ $primaryAccent }}", + "accent_bg_color": "{{ $primary }}", + "accent_fg_color": "{{ $onPrimary }}", + + "destructive_color": "{{ $errorAccent }}", + "destructive_bg_color": "{{ $error }}", + "destructive_fg_color": "{{ $onError }}", + + "success_color": "{{ $successAccent }}", + "success_bg_color": "{{ $success }}", + "success_fg_color": "{{ $onSuccess }}", + + "warning_color": "{{ $warningAccent }}", + "warning_bg_color": "{{ $warning }}", + "warning_fg_color": "{{ $onWarning }}", + + "error_color": "{{ $errorAccent }}", + "error_bg_color": "{{ $error }}", + "error_fg_color": "{{ $onError }}", + + "window_bg_color": "{{ $background }}", + "window_fg_color": "{{ $onBackground }}", + + "view_bg_color": "{{ $view }}", + "view_fg_color": "{{ $onView }}", + + "headerbar_bg_color": "mix(@dialog_bg_color, @window_bg_color, 0.5)", + "headerbar_fg_color": "{{ $onSurface }}", + "headerbar_border_color": "{{ $surface }}", + "headerbar_backdrop_color": "@headerbar_bg_color", + "headerbar_shade_color": "rgba(0, 0, 0, 0.09)", + + "card_bg_color": "{{ $card }}", + "card_fg_color": "{{ $onCard }}", + "card_shade_color": "rgba(0, 0, 0, 0.09)", + + "dialog_bg_color": "{{ $surface }}", + "dialog_fg_color": "{{ $onSurface }}", + + "popover_bg_color": "{{ $surface }}", + "popover_fg_color": "{{ $onSurface }}", + + "thumbnail_bg_color": "#1a1b26", + "thumbnail_fg_color": "#AEE5FA", + "shade_color": "rgba(0, 0, 0, 0.36)", + "scrollbar_outline_color": "rgba(0, 0, 0, 0.5)", + "sidebar_bg_color": "@window_bg_color", + "sidebar_fg_color": "@window_fg_color", + "sidebar_border_color": "@sidebar_bg_color", + "sidebar_backdrop_color": "@sidebar_bg_color" + }, + "palette": { + "blue_": {}, + "green_": {}, + "yellow_": {}, + "orange_": {}, + "red_": {}, + "purple_": {}, + "brown_": {}, + "light_": {}, + "dark_": {} + }, + "custom_css": { + "gtk4": "", + "gtk3": "" + }, + "plugins": {} +} diff --git a/config/private_dot_config/exact_ags/lib/battery.ts b/config/private_dot_config/exact_ags/lib/battery.ts new file mode 100644 index 00000000..4077f462 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/battery.ts @@ -0,0 +1,15 @@ +import icons from "./icons"; + +export default async function init() { + const bat = await Service.import("battery"); + bat.connect("notify::percent", ({ percent, charging }) => { + const low = 30; + if (percent !== low ?? percent !== low / 2 ?? !charging) return; + + Utils.notify({ + summary: `${percent}% Battery Percentage`, + iconName: icons.battery.warning, + urgency: "critical", + }); + }); +} diff --git a/config/private_dot_config/exact_ags/lib/colorgen.ts b/config/private_dot_config/exact_ags/lib/colorgen.ts new file mode 100644 index 00000000..9c47a8be --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/colorgen.ts @@ -0,0 +1,151 @@ +// โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +// โ”‚ COLOR GENERATION โ”‚ +// โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +import { bash, dependencies } from "lib/utils"; +import options from "options"; +import { hyprland as _hyprland } from "resource:///com/github/Aylur/ags/service/hyprland.js"; + +export default function init() { + const gtkOnlyArgs = ["changed", () => colorgen("gtk")] as const; + + // Primary + options.theme.light.primary.bg.connect(...gtkOnlyArgs); + options.theme.light.primary.accent.connect(...gtkOnlyArgs); + options.theme.dark.primary.bg.connect(...gtkOnlyArgs); + options.theme.dark.primary.accent.connect(...gtkOnlyArgs); + // Error + options.theme.light.error.bg.connect(...gtkOnlyArgs); + options.theme.light.error.accent.connect(...gtkOnlyArgs); + options.theme.dark.error.bg.connect(...gtkOnlyArgs); + options.theme.dark.error.accent.connect(...gtkOnlyArgs); + // Success + options.theme.light.success.bg.connect(...gtkOnlyArgs); + options.theme.light.success.accent.connect(...gtkOnlyArgs); + options.theme.dark.success.bg.connect(...gtkOnlyArgs); + options.theme.dark.success.accent.connect(...gtkOnlyArgs); + // Warning + options.theme.light.warning.bg.connect(...gtkOnlyArgs); + options.theme.light.warning.accent.connect(...gtkOnlyArgs); + options.theme.dark.warning.bg.connect(...gtkOnlyArgs); + options.theme.dark.warning.accent.connect(...gtkOnlyArgs); + + options.theme.light.fg.connect("changed", () => colorgen("gtk", "hypr")); + options.theme.dark.fg.connect("changed", () => colorgen("gtk", "hypr")); + options.theme.light.bg.connect(...gtkOnlyArgs); + options.theme.dark.bg.connect(...gtkOnlyArgs); + options.theme.light.view.connect(...gtkOnlyArgs); + options.theme.dark.view.connect(...gtkOnlyArgs); + options.theme.light.card.connect(...gtkOnlyArgs); + options.theme.dark.card.connect(...gtkOnlyArgs); + options.theme.light.surface.connect(...gtkOnlyArgs); + options.theme.dark.surface.connect(...gtkOnlyArgs); + + // Inactive Border + options.theme.light.inactiveBorder.connect("changed", () => colorgen("hypr")); + options.theme.dark.inactiveBorder.connect("changed", () => colorgen("hypr")); + + colorgen("all"); +} + +// โ”€โ”€ GTK Theme โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +const presetPath = "/tmp/gradience-preset.json"; + +function overridePresetTemplate(palette: Record) { + return bash( + Object.keys(palette) + .map( + (prop) => `sed -i "s/{{ \\$${prop} }}/${palette[prop]}/g" ${presetPath}` + ) + .join("\n") + ); +} + +function generateGTKTheme() { + if (!dependencies("gradience-cli")) return; + + const colorPalette = + options.theme.scheme.value === "dark" + ? options.theme.dark + : options.theme.light; + + bash( + `cp ${App.configDir}/templates/gradience/preset.json ${presetPath}` + ).then(() => { + overridePresetTemplate({ + primaryAccent: colorPalette.primary.accent.value, + primary: colorPalette.primary.bg.value, + onPrimary: colorPalette.fg.value, + + errorAccent: colorPalette.error.accent.value, + error: colorPalette.error.bg.value, + onError: colorPalette.fg.value, + + successAccent: colorPalette.success.accent.value, + success: colorPalette.success.bg.value, + onSuccess: colorPalette.fg.value, + + warningAccent: colorPalette.warning.accent.value, + warning: colorPalette.warning.bg.value, + onWarning: colorPalette.fg.value, + + background: colorPalette.bg.value, + onBackground: colorPalette.fg.value, + + view: colorPalette.view.value, + onView: colorPalette.fg.value, + + card: colorPalette.card.value, + onCard: colorPalette.fg.value, + + surface: colorPalette.surface.value, + onSurface: colorPalette.fg.value, + }).then(() => { + bash("mkdir -p ~/.config/presets").then(() => { + bash(`gradience-cli apply -p ${presetPath} --gtk both`).then(() => { + options.theme.scheme.emit("changed"); + bash(`rm -rf ${presetPath}`); + }); + }); + }); + }); +} + +// โ”€โ”€ Hyprland โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +function sendBatch(batch: string[]) { + const cmd = batch + .filter((x) => !!x) + .map((x) => `keyword ${x}`) + .join("; "); + + return _hyprland.messageAsync(`[[BATCH]]/${cmd}`); +} + +function generateHyprlandTheme() { + const colorPalette = + options.theme.scheme.value === "dark" + ? options.theme.dark + : options.theme.light; + sendBatch([ + `general:col.active_border rgba(${colorPalette.fg.value.replace("#", "")}39)`, + `general:col.inactive_border rgba(${colorPalette.inactiveBorder.value.replace("#", "")}30)`, + `misc:background_color rgba(${colorPalette.view.value.replace("#", "")}FF)`, + ]); +} + +// โ”€โ”€ Color Generation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +type GenerationType = "gtk" | "hypr"; +export async function colorgen(...generate: (GenerationType | "all")[]) { + const genMap: Record void> = { + gtk: generateGTKTheme, + hypr: generateHyprlandTheme, + }; + for (const genKey of Object.keys(genMap)) { + if ( + generate.includes("all") ?? + generate.includes(genKey as GenerationType) + ) { + genMap[genKey as GenerationType](); + } + } +} diff --git a/config/private_dot_config/exact_ags/lib/gtk.ts b/config/private_dot_config/exact_ags/lib/gtk.ts new file mode 100644 index 00000000..f478f0c1 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/gtk.ts @@ -0,0 +1,20 @@ +import Gio from "gi://Gio"; +import options from "options"; +import { ICON_THEME } from "template"; + +const settings = new Gio.Settings({ + schema: "org.gnome.desktop.interface", +}); + +function gtk() { + const scheme = options.theme.scheme.value; + const suffixLower = options.theme.scheme.value === "dark" ? "-dark" : ""; + const suffixUpper = options.theme.scheme.value === "dark" ? "-Dark" : ""; + settings.set_string("color-scheme", `prefer${suffixLower}`); + settings.set_string("gtk-theme", `adw-gtk3${suffixLower}`); +} + +export default function init() { + options.theme.scheme.connect("changed", gtk); + gtk(); +} diff --git a/config/private_dot_config/exact_ags/lib/hyprland.ts b/config/private_dot_config/exact_ags/lib/hyprland.ts new file mode 100644 index 00000000..41908890 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/hyprland.ts @@ -0,0 +1,54 @@ +import options from "options"; + +const { messageAsync } = await Service.import("hyprland"); + +const { + hyprland, + theme: { + spacing, + radius, + border: { width }, + blur, + shadows, + }, +} = options; + +const deps = ["hyprland", spacing.id, radius.id, blur.id, width.id, shadows.id]; + +function sendBatch(batch: string[]) { + const cmd = batch + .filter((x) => !!x) + .map((x) => `keyword ${x}`) + .join("; "); + + return messageAsync(`[[BATCH]]/${cmd}`); +} + +async function setupHyprland() { + const wm_gaps = Math.floor(hyprland.gaps.value * spacing.value); + + sendBatch([ + `general:border_size ${width.value}`, + `general:gaps_out ${wm_gaps}`, + `general:gaps_in ${Math.floor(wm_gaps / 2)}`, + `decoration:rounding ${radius.value}`, + `decoration:drop_shadow ${shadows.value ? "yes" : "no"}`, + ]); + + await sendBatch(App.windows.map(({ name }) => `layerrule unset, ${name}`)); + + if (blur.value > 0) { + sendBatch( + App.windows.flatMap(({ name }) => [ + `layerrule unset, ${name}`, + `layerrule blur, ${name}`, + `layerrule ignorealpha ${/* based on shadow color */ 0.29}, ${name}`, + ]) + ); + } +} + +export default function init() { + options.handler(deps, setupHyprland); + setupHyprland(); +} diff --git a/config/private_dot_config/exact_ags/lib/icons.ts b/config/private_dot_config/exact_ags/lib/icons.ts new file mode 100644 index 00000000..90cf3658 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/icons.ts @@ -0,0 +1,142 @@ +export const substitutes = { + "transmission-gtk": "transmission", + "blueberry.py": "blueberry", + Caprine: "facebook-messenger", + "com.raggesilver.BlackBox-symbolic": "terminal-symbolic", + "org.wezfurlong.wezterm-symbolic": "terminal-symbolic", + "audio-headset-bluetooth": "audio-headphones-symbolic", + "audio-card-analog-usb": "audio-speakers-symbolic", + "audio-card-analog-pci": "audio-card-symbolic", + "preferences-system": "emblem-system-symbolic", + "com.github.Aylur.ags-symbolic": "controls-symbolic", + "com.github.Aylur.ags": "controls-symbolic", +}; + +export default { + missing: "image-missing-symbolic", + app: { + terminal: "terminal-symbolic", + }, + fallback: { + executable: "application-x-executable", + notification: "dialog-information-symbolic", + video: "video-x-generic-symbolic", + audio: "audio-x-generic-symbolic", + }, + ui: { + close: "window-close-symbolic", + colorpicker: "color-select-symbolic", + info: "info-symbolic", + link: "external-link-symbolic", + lock: "system-lock-screen-symbolic", + menu: "open-menu-symbolic", + refresh: "view-refresh-symbolic", + search: "system-search-symbolic", + settings: "emblem-system-symbolic", + themes: "preferences-desktop-theme-symbolic", + tick: "object-select-symbolic", + time: "hourglass-symbolic", + toolbars: "toolbars-symbolic", + warning: "dialog-warning-symbolic", + avatar: "avatar-default-symbolic", + arrow: { + right: "pan-end-symbolic", + left: "pan-start-symbolic", + down: "pan-down-symbolic", + up: "pan-up-symbolic", + }, + }, + audio: { + mic: { + muted: "microphone-disabled-symbolic", + low: "microphone-sensitivity-low-symbolic", + medium: "microphone-sensitivity-medium-symbolic", + high: "microphone-sensitivity-high-symbolic", + }, + volume: { + muted: "audio-volume-muted-symbolic", + low: "audio-volume-low-symbolic", + medium: "audio-volume-medium-symbolic", + high: "audio-volume-high-symbolic", + overamplified: "audio-volume-overamplified-symbolic", + }, + type: { + headset: "audio-headphones-symbolic", + speaker: "audio-speakers-symbolic", + card: "audio-card-symbolic", + }, + mixer: "mixer-symbolic", + }, + powerprofile: { + balanced: "power-profile-balanced-symbolic", + "power-saver": "power-profile-power-saver-symbolic", + performance: "power-profile-performance-symbolic", + }, + asusctl: { + profile: { + Balanced: "power-profile-balanced-symbolic", + Quiet: "power-profile-power-saver-symbolic", + Performance: "power-profile-performance-symbolic", + }, + mode: { + Integrated: "processor-symbolic", + Hybrid: "controller-symbolic", + }, + }, + battery: { + charging: "battery-flash-symbolic", + warning: "battery-empty-symbolic", + }, + bluetooth: { + enabled: "bluetooth-active-symbolic", + disabled: "bluetooth-disabled-symbolic", + }, + brightness: { + indicator: "display-brightness-symbolic", + keyboard: "keyboard-brightness-symbolic", + screen: "display-brightness-symbolic", + }, + powermenu: { + sleep: "weather-clear-night-symbolic", + reboot: "system-reboot-symbolic", + logout: "system-log-out-symbolic", + shutdown: "system-shutdown-symbolic", + }, + recorder: { + recording: "media-record-symbolic", + }, + notifications: { + noisy: "org.gnome.Settings-notifications-symbolic", + silent: "notifications-disabled-symbolic", + message: "chat-bubbles-symbolic", + }, + trash: { + full: "user-trash-full-symbolic", + empty: "user-trash-symbolic", + }, + mpris: { + shuffle: { + enabled: "media-playlist-shuffle-symbolic", + disabled: "media-playlist-consecutive-symbolic", + }, + loop: { + none: "media-playlist-repeat-symbolic", + track: "media-playlist-repeat-song-symbolic", + playlist: "media-playlist-repeat-symbolic", + }, + playing: "media-playback-pause-symbolic", + paused: "media-playback-start-symbolic", + stopped: "media-playback-start-symbolic", + prev: "media-skip-backward-symbolic", + next: "media-skip-forward-symbolic", + }, + system: { + cpu: "org.gnome.SystemMonitor-symbolic", + ram: "drive-harddisk-solidstate-symbolic", + temp: "temperature-symbolic", + }, + color: { + dark: "dark-mode-symbolic", + light: "light-mode-symbolic", + }, +}; diff --git a/config/private_dot_config/exact_ags/lib/init.ts b/config/private_dot_config/exact_ags/lib/init.ts new file mode 100644 index 00000000..91ee6f92 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/init.ts @@ -0,0 +1,19 @@ +import lowBattery from "./battery"; +import colorgen from "./colorgen"; +import gtk from "./gtk"; +import hyprland from "./hyprland"; +import notifications from "./notifications"; +import tmux from "./tmux"; + +export default function init() { + try { + gtk(); + tmux(); + colorgen(); + hyprland(); + lowBattery(); + notifications(); + } catch (error) { + logError(error); + } +} diff --git a/config/private_dot_config/exact_ags/lib/notifications.ts b/config/private_dot_config/exact_ags/lib/notifications.ts new file mode 100644 index 00000000..7caf7b5b --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/notifications.ts @@ -0,0 +1,19 @@ +import options from "options"; + +const notifs = await Service.import("notifications"); + +// TODO: consider adding this to upstream + +const { blacklist } = options.notifications; + +export default function init() { + const notify = notifs.constructor.prototype.Notify.bind(notifs); + notifs.constructor.prototype.Notify = function ( + appName: string, + ...rest: unknown[] + ) { + if (blacklist.value.includes(appName)) return Number.MAX_SAFE_INTEGER; + + return notify(appName, ...rest); + }; +} diff --git a/config/private_dot_config/exact_ags/lib/option.ts b/config/private_dot_config/exact_ags/lib/option.ts new file mode 100644 index 00000000..f789a674 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/option.ts @@ -0,0 +1,118 @@ +import { Variable } from "resource:///com/github/Aylur/ags/variable.js"; + +type OptProps = { + persistent?: boolean; +}; + +export class Opt extends Variable { + static { + Service.register(this); + } + + constructor(initial: T, { persistent = false }: OptProps = {}) { + super(initial); + this.initial = initial; + this.persistent = persistent; + } + + initial: T; + id = ""; + persistent: boolean; + toString() { + return `${this.value}`; + } + toJSON() { + return `opt:${this.value}`; + } + + getValue = (): T => { + return super.getValue(); + }; + + init(cacheFile: string) { + const cacheV = JSON.parse(Utils.readFile(cacheFile) ?? "{}")[this.id]; + if (cacheV !== undefined) this.value = cacheV; + + this.connect("changed", () => { + const cache = JSON.parse(Utils.readFile(cacheFile) ?? "{}"); + cache[this.id] = this.value; + Utils.writeFileSync(JSON.stringify(cache, null, 2), cacheFile); + }); + } + + reset() { + if (this.persistent) return; + + if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) { + this.value = this.initial; + return this.id; + } + } +} + +export const opt = (initial: T, opts?: OptProps) => new Opt(initial, opts); + +function getOptions(object: object, path = ""): Opt[] { + return Object.keys(object).flatMap((key) => { + const obj: Opt = object[key]; + const id = path ? path + "." + key : key; + + if (obj instanceof Variable) { + obj.id = id; + return obj; + } + + if (typeof obj === "object") return getOptions(obj, id); + + return []; + }); +} + +export function mkOptions(cacheFile: string, object: T) { + for (const opt of getOptions(object)) opt.init(cacheFile); + + Utils.ensureDirectory(cacheFile.split("/").slice(0, -1).join("/")); + + const configFile = `${TMP}/config.json`; + const values = getOptions(object).reduce( + (obj, { id, value }) => ({ [id]: value, ...obj }), + {} + ); + Utils.writeFileSync(JSON.stringify(values, null, 2), configFile); + Utils.monitorFile(configFile, () => { + const cache = JSON.parse(Utils.readFile(configFile) ?? "{}"); + for (const opt of getOptions(object)) { + if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value)) + opt.value = cache[opt.id]; + } + }); + + function sleep(ms = 0) { + return new Promise((r) => setTimeout(r, ms)); + } + + async function reset( + [opt, ...list] = getOptions(object), + id = opt?.reset() + ): Promise> { + if (!opt) return sleep().then(() => []); + + return id + ? [id, ...(await sleep(50).then(() => reset(list)))] + : await sleep().then(() => reset(list)); + } + + return Object.assign(object, { + configFile, + array: () => getOptions(object), + async reset() { + return (await reset()).join("\n"); + }, + handler(deps: string[], callback: () => void) { + for (const opt of getOptions(object)) { + if (deps.some((i) => opt.id.startsWith(i))) + opt.connect("changed", callback); + } + }, + }); +} diff --git a/config/private_dot_config/exact_ags/lib/session.ts b/config/private_dot_config/exact_ags/lib/session.ts new file mode 100644 index 00000000..c2b7de5d --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/session.ts @@ -0,0 +1,16 @@ +import GLib from "gi://GLib?version=2.0"; + +declare global { + const OPTIONS: string; + const TMP: string; + const USER: string; +} + +Object.assign(globalThis, { + OPTIONS: `${GLib.get_user_cache_dir()}/ags/options.json`, + TMP: `${GLib.get_tmp_dir()}/ags`, + USER: GLib.get_user_name(), +}); + +Utils.ensureDirectory(TMP); +App.addIcons(`${App.configDir}/assets`); diff --git a/config/private_dot_config/exact_ags/lib/tmux.ts b/config/private_dot_config/exact_ags/lib/tmux.ts new file mode 100644 index 00000000..0067e625 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/tmux.ts @@ -0,0 +1,18 @@ +import options from "options"; + +import { sh } from "./utils"; + +export async function tmux() { + const { scheme, dark, light } = options.theme; + const hex = + scheme.value === "dark" + ? dark.primary.accent.value + : light.primary.accent.value; + if (await sh("which tmux").catch(() => false)) + sh(`tmux set @main_accent "${hex}"`); +} + +export default function init() { + options.theme.dark.primary.accent.connect("changed", tmux); + options.theme.light.primary.accent.connect("changed", tmux); +} diff --git a/config/private_dot_config/exact_ags/lib/utils.ts b/config/private_dot_config/exact_ags/lib/utils.ts new file mode 100644 index 00000000..3513241e --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/utils.ts @@ -0,0 +1,156 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import Gdk from "gi://Gdk"; +import GLib from "gi://GLib?version=2.0"; +import { type Application } from "types/service/applications"; + +import icons, { substitutes } from "./icons"; + +import type Gtk from "gi://Gtk?version=3.0"; + +const apps = await Service.import("applications"); + +export type Binding = import("types/service").Binding; + +/** + * @returns substitute icon || name || fallback icon + */ +export function icon(name: string | null, fallback = icons.missing) { + if (!name) return fallback ?? ""; + + if (GLib.file_test(name, GLib.FileTest.EXISTS)) return name; + + const icon = substitutes[name] ?? name; + if (Utils.lookUpIcon(icon)) return icon; + + print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`); + return fallback; +} + +/** + * @returns execAsync(["bash", "-c", cmd]) + */ +export async function bash( + strings: TemplateStringsArray | string, + ...values: unknown[] +) { + const cmd = + typeof strings === "string" + ? strings + : strings.flatMap((str, i) => str + `${values[i] ?? ""}`).join(""); + + return Utils.execAsync(["bash", "-c", cmd]).catch((err) => { + console.error(cmd, err); + return ""; + }); +} + +/** + * @returns execAsync(cmd) + */ +export async function sh(cmd: string | string[]) { + return Utils.execAsync(cmd).catch((err) => { + console.error(typeof cmd === "string" ? cmd : cmd.join(" "), err); + return ""; + }); +} + +export function forMonitors(widget: (monitor: number) => Gtk.Window) { + const n = Gdk.Display.get_default()?.get_n_monitors() ?? 1; + return range(n, 0).flatMap(widget); +} + +/** + * @returns [start...length] + */ +export function range(length: number, start = 1) { + return Array.from({ length }, (_, i) => i + start); +} + +/** + * @returns true if all of the `bins` are found + */ +export function dependencies(...bins: string[]) { + const missing = bins.filter((bin) => + Utils.exec({ + cmd: `which ${bin}`, + out: () => false, + err: () => true, + }) + ); + + if (missing.length > 0) { + console.warn(Error(`missing dependencies: ${missing.join(", ")}`)); + Utils.notify(`missing dependencies: ${missing.join(", ")}`); + } + + return missing.length === 0; +} + +/** + * run app detached + */ +export function launchApp(app: Application) { + const exe = app.executable + .split(/\s+/) + .filter((str) => !str.startsWith("%") && !str.startsWith("@")) + .join(" "); + + bash(`${exe} &`); + app.frequency += 1; +} + +/** + * to use with drag and drop + */ +export function createSurfaceFromWidget(widget: Gtk.Widget) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const cairo = imports.gi.cairo as any; + const alloc = widget.get_allocation(); + const surface = new cairo.ImageSurface( + cairo.Format.ARGB32, + alloc.width, + alloc.height + ); + const cr = new cairo.Context(surface); + cr.setSourceRGBA(255, 255, 255, 0); + cr.rectangle(0, 0, alloc.width, alloc.height); + cr.fill(); + widget.draw(cr); + return surface; +} + +export function findApp(className: string) { + function filter(props: string[]) { + return apps.list.filter((app) => + props.some((prop) => { + const value = typeof app[prop] === "function" ? app[prop]() : app[prop]; + return value?.toLowerCase().includes(className.toLowerCase()); + }) + ); + } + + let ret = filter(["icon_name", "desktop"]); + + if (ret.length === 0) ret = filter(["name", "executable", "description"]); + + if (ret.length > 1) { + print(`multiple apps found for ${className}`); + ret.forEach((app) => { + const props = [ + "name", + "icon_name", + "desktop", + "wm_class", + "description", + "frequency", + "executable", + ]; + print(` - name: ${app.name}`); + for (const prop of props) print(` * ${prop}: ${app[prop]}`); + }); + } + + if (ret.length === 0) print(`no app found for ${className}`); + return ret[0]; +} diff --git a/config/private_dot_config/exact_ags/lib/variables.ts b/config/private_dot_config/exact_ags/lib/variables.ts new file mode 100644 index 00000000..90780909 --- /dev/null +++ b/config/private_dot_config/exact_ags/lib/variables.ts @@ -0,0 +1,57 @@ +import GLib from "gi://GLib"; + +// import options from "options" +// +// const intval = options.system.fetchInterval.value +// const tempPath = options.system.temperature.value + +export const clock = Variable(GLib.DateTime.new_now_local(), { + poll: [1000, () => GLib.DateTime.new_now_local()], +}); + +export const uptime = Variable(0, { + poll: [ + 60_000, + "cat /proc/uptime", + (line) => Number.parseInt(line.split(".")[0]) / 60, + ], +}); + +export const df = Variable(0, { + poll: [ + 1000, + "/bin/df / --output=size,used", + (out) => { + out = out.trim().split("\n")[1]!; + const [total, used] = out.match(/\d+/g).map(Number); + return (used! * 100.0) / total!; + }, + ], +}); + +export const distro = { + id: GLib.get_os_info("ID"), + logo: GLib.get_os_info("LOGO"), +}; + +// const divide = ([total, free]: string[]) => Number.parseInt(free) / Number.parseInt(total) +// +// export const cpu = Variable(0, { +// poll: [intval, "top -b -n 1", out => divide(["100", out.split("\n") +// .find(line => line.includes("Cpu(s)")) +// ?.split(/\s+/)[1] +// .replace(",", ".") ?? "0"])], +// }) +// +// export const ram = Variable(0, { +// poll: [intval, "free", out => divide(out.split("\n") +// .find(line => line.includes("Mem:")) +// ?.split(/\s+/) +// .splice(1, 2) ?? ["1", "1"])], +// }) +// +// export const temperature = Variable(0, { +// poll: [intval, `cat ${tempPath}`, n => { +// return Number.parseInt(n) / 100_000 +// }], +// }) diff --git a/config/private_dot_config/exact_ags/main.ts b/config/private_dot_config/exact_ags/main.ts new file mode 100644 index 00000000..8ca928f0 --- /dev/null +++ b/config/private_dot_config/exact_ags/main.ts @@ -0,0 +1,42 @@ +import "lib/session"; +import "style/style"; + +import init from "lib/init"; +import { forMonitors } from "lib/utils"; +import options from "options"; +import Bar from "widget/bar/Bar"; +import ScreenCorners from "widget/bar/ScreenCorners"; +import { setupDateMenu } from "widget/datemenu/DateMenu"; +import Launcher from "widget/launcher/Launcher"; +import NotificationPopups from "widget/notifications/NotificationPopups"; +import OSD from "widget/osd/OSD"; +import Overview from "widget/overview/Overview"; +import PowerMenu from "widget/powermenu/PowerMenu"; +import Verification from "widget/powermenu/Verification"; +import { setupQuickSettings } from "widget/quicksettings/QuickSettings"; +import SettingsDialog from "widget/settings/SettingsDialog"; + +App.config({ + onConfigParsed: () => { + setupQuickSettings(); + setupDateMenu(); + init(); + }, + closeWindowDelay: { + launcher: options.transition.value, + overview: options.transition.value, + quicksettings: options.transition.value, + datemenu: options.transition.value, + }, + windows: () => [ + ...forMonitors(Bar), + ...forMonitors(NotificationPopups), + ...forMonitors(ScreenCorners), + ...forMonitors(OSD), + Launcher(), + Overview(), + PowerMenu(), + SettingsDialog(), + Verification(), + ], +}); diff --git a/config/private_dot_config/exact_ags/options.ts b/config/private_dot_config/exact_ags/options.ts new file mode 100644 index 00000000..ecc811d9 --- /dev/null +++ b/config/private_dot_config/exact_ags/options.ts @@ -0,0 +1,245 @@ +import icons from "lib/icons"; +import { mkOptions, opt } from "lib/option"; +import { icon } from "lib/utils"; +import { distro } from "lib/variables"; +import { FONT_SANS_FAMILY, IS_NOT_VM, THEME } from "template"; + +const options = mkOptions(OPTIONS, { + theme: { + dark: { + primary: { + bg: opt(THEME.dark.primary.bg), + accent: opt(THEME.dark.primary.accent), + }, + error: { + bg: opt(THEME.dark.error.bg), + accent: opt(THEME.dark.error.accent), + }, + success: { + bg: opt(THEME.dark.success.bg), + accent: opt(THEME.dark.success.accent), + }, + warning: { + bg: opt(THEME.dark.warning.bg), + accent: opt(THEME.dark.warning.accent), + }, + fg: opt(THEME.dark.fg), + bg: opt(THEME.dark.bg), + view: opt(THEME.dark.view), + card: opt(THEME.dark.card), + surface: opt(THEME.dark.surface), + + widget: opt(THEME.dark.widget), + border: opt(THEME.dark.border), + inactiveBorder: opt(THEME.dark.inactiveBorder), + }, + light: { + primary: { + bg: opt(THEME.light.primary.bg), + accent: opt(THEME.light.primary.accent), + }, + error: { + bg: opt(THEME.light.error.bg), + accent: opt(THEME.light.error.accent), + }, + success: { + bg: opt(THEME.light.success.bg), + accent: opt(THEME.light.success.accent), + }, + warning: { + bg: opt(THEME.light.warning.bg), + accent: opt(THEME.light.warning.accent), + }, + fg: opt(THEME.light.fg), + bg: opt(THEME.light.bg), + view: opt(THEME.light.view), + card: opt(THEME.light.card), + surface: opt(THEME.light.surface), + + widget: opt(THEME.light.widget), + border: opt(THEME.light.border), + inactiveBorder: opt(THEME.light.inactiveBorder), + }, + + blur: opt(15), + scheme: opt<"dark" | "light">(THEME.colorscheme), + widget: { opacity: opt(THEME.widget.opacity) }, + border: { + width: opt(THEME.border.width), + opacity: opt(THEME.border.opacity), + }, + + shadows: opt(IS_NOT_VM), + padding: opt(THEME.padding), + spacing: opt(THEME.spacing), + radius: opt(THEME.radius), + }, + + transition: opt(200), + + font: { + size: opt(13), + name: opt(FONT_SANS_FAMILY), + }, + + bar: { + flatButtons: opt(false), + position: opt<"top" | "bottom">("top"), + corners: opt(50), + transparent: opt(true), + layout: { + start: opt([ + "launcher", + "workspaces", + "taskbar", + "expander", + "messages", + ]), + center: opt(["date"]), + end: opt([ + "media", + "expander", + "systray", + "colorpicker", + "screenrecord", + "hyprshade", + "system-info", + "system", + "battery", + "powermenu", + ]), + }, + launcher: { + icon: { + colored: opt(true), + icon: opt(icon(distro.logo, icons.ui.search)), + }, + label: { + colored: opt(false), + label: opt(" Arch Linux"), + }, + action: opt(() => App.toggleWindow("launcher")), + }, + date: { + format: opt("%H:%M - %A, %B %e, %Y"), + action: opt(() => App.toggleWindow("datemenu")), + }, + battery: { + bar: opt<"hidden" | "regular" | "whole">("hidden"), + charging: opt("#00D787"), + percentage: opt(true), + blocks: opt(7), + width: opt(50), + low: opt(30), + }, + workspaces: { + workspaces: opt(10), + }, + taskbar: { + iconSize: opt(0), + monochrome: opt(false), + exclusive: opt(false), + }, + messages: { + action: opt(() => App.toggleWindow("datemenu")), + }, + systray: { + ignore: opt(["KDE Connect Indicator", "spotify-client"]), + }, + media: { + monochrome: opt(false), + preferred: opt("spotify"), + direction: opt<"left" | "right">("right"), + format: opt("{artists} - {title}"), + length: opt(40), + }, + powermenu: { + monochrome: opt(false), + action: opt(() => App.toggleWindow("powermenu")), + }, + }, + + launcher: { + width: opt(0), + margin: opt(80), + sh: { + max: opt(16), + }, + cliphist: { + max: opt(16), + }, + apps: { + iconSize: opt(62), + max: opt(6), + favorites: opt([ + ["firefox", "wezterm", "org.gnome.Nautilus", "ferdium", "spotify"], + ]), + }, + }, + + overview: { + scale: opt(9), + workspaces: opt(10), + monochromeIcon: opt(false), + }, + + powermenu: { + sleep: opt("systemctl suspend"), + reboot: opt("systemctl reboot"), + logout: opt("pkill Hyprland"), + shutdown: opt("shutdown now"), + layout: opt<"line" | "box">("line"), + labels: opt(true), + }, + + quicksettings: { + avatar: { + image: opt(`${Utils.HOME}/Pictures/user-avatar.png`), + size: opt(70), + }, + width: opt(380), + position: opt<"left" | "center" | "right">("right"), + networkSettings: opt("gnome-control-center wifi"), + media: { + monochromeIcon: opt(false), + coverSize: opt(100), + }, + }, + + datemenu: { + position: opt<"left" | "center" | "right">("center"), + }, + + hyprshade: { + interval: opt(10000), + }, + + osd: { + progress: { + vertical: opt(true), + pack: { + h: opt<"start" | "center" | "end">("end"), + v: opt<"start" | "center" | "end">("center"), + }, + }, + microphone: { + pack: { + h: opt<"start" | "center" | "end">("center"), + v: opt<"start" | "center" | "end">("end"), + }, + }, + }, + + notifications: { + position: opt<("top" | "bottom" | "left" | "right")[]>(["top", "right"]), + blacklist: opt(["Spotify"]), + width: opt(440), + }, + + hyprland: { + gaps: opt(THEME.window_margin), + }, +}); + +Object.assign(globalThis, { options }); +export default options; diff --git a/config/private_dot_config/exact_ags/package.json b/config/private_dot_config/exact_ags/package.json new file mode 100644 index 00000000..9d24914f --- /dev/null +++ b/config/private_dot_config/exact_ags/package.json @@ -0,0 +1,16 @@ +{ + "name": "ags-dotfiles", + "scripts": { + "lint": "eslint .", + "format": "prettier '**/*.{js,ts,mjs,json,scss}' --ignore-path .gitignore --ignore-unknown --no-error-on-unmatched-pattern --write", + "format:check": "prettier '**/*.{js,ts,mjs,json,scss}' --ignore-path .gitignore --ignore-unknown --no-error-on-unmatched-pattern --check" + }, + "devDependencies": { + "@ianvs/prettier-plugin-sort-imports": "^4.3.0", + "@typescript-eslint/eslint-plugin": "^7.14.1", + "@typescript-eslint/parser": "^7.14.1", + "eslint": "^8.57.0", + "prettier": "^3.3.2", + "typescript": "^5.5.2" + } +} diff --git a/config/private_dot_config/exact_ags/prettier.config.mjs b/config/private_dot_config/exact_ags/prettier.config.mjs new file mode 100644 index 00000000..8f0784a0 --- /dev/null +++ b/config/private_dot_config/exact_ags/prettier.config.mjs @@ -0,0 +1,28 @@ +const THIRD_PARTY_MODULES = ""; // Imports not matched by other special words or groups +const BUILTIN_MODULES = ""; // Node.js built-in modules +const RELATIVE_IMPORTS = "^[.]"; // Relative imports +const TYPES = { + NODE: "^(node:)", // Types from Node.js built-in modules + THIRD_PARTY: "", // Types from third party modules + RELATIVE: "^[.]", // Types from relative imports +}; + +/** @type {import("prettier").Config & import("@ianvs/prettier-plugin-sort-imports").PluginConfig} */ +export default { + trailingComma: "es5", + plugins: ["@ianvs/prettier-plugin-sort-imports"], + // INFO: To group imports into "chunks" with blank lines between, add empty strings + importOrder: [ + "", + BUILTIN_MODULES, + "", + THIRD_PARTY_MODULES, + "", + RELATIVE_IMPORTS, + "", + TYPES.NODE, + TYPES.THIRD_PARTY, + TYPES.RELATIVE, + ], + importOrderTypeScriptVersion: "5.4.3", +}; diff --git a/config/private_dot_config/exact_ags/service/asusctl.ts b/config/private_dot_config/exact_ags/service/asusctl.ts new file mode 100644 index 00000000..cb1de42c --- /dev/null +++ b/config/private_dot_config/exact_ags/service/asusctl.ts @@ -0,0 +1,73 @@ +import { sh } from "lib/utils"; + +type Profile = "Performance" | "Balanced" | "Quiet"; +type Mode = "Hybrid" | "Integrated"; + +class Asusctl extends Service { + static { + Service.register( + this, + {}, + { + profile: ["string", "r"], + mode: ["string", "r"], + } + ); + } + + get available() { + return Utils.exec( + "which asusctl", + () => true, + () => false + ); + } + + #profile: Profile = "Balanced"; + #mode: Mode = "Hybrid"; + + async nextProfile() { + await sh("asusctl profile -n"); + const profile = await sh("asusctl profile -p"); + const p = profile.split(" ")[3] as Profile; + this.#profile = p; + this.changed("profile"); + } + + async setProfile(prof: Profile) { + await sh(`asusctl profile --profile-set ${prof}`); + this.#profile = prof; + this.changed("profile"); + } + + async nextMode() { + await sh( + `supergfxctl -m ${this.#mode === "Hybrid" ? "Integrated" : "Hybrid"}` + ); + this.#mode = (await sh("supergfxctl -g")) as Mode; + this.changed("profile"); + } + + constructor() { + super(); + + if (this.available) { + sh("asusctl profile -p").then( + (p) => (this.#profile = p.split(" ")[3] as Profile) + ); + sh("supergfxctl -g").then((m) => (this.#mode = m as Mode)); + } + } + + get profiles(): Profile[] { + return ["Performance", "Balanced", "Quiet"]; + } + get profile() { + return this.#profile; + } + get mode() { + return this.#mode; + } +} + +export default new Asusctl(); diff --git a/config/private_dot_config/exact_ags/service/brightness.ts b/config/private_dot_config/exact_ags/service/brightness.ts new file mode 100644 index 00000000..ca90bcf4 --- /dev/null +++ b/config/private_dot_config/exact_ags/service/brightness.ts @@ -0,0 +1,111 @@ +import { dependencies, sh } from "lib/utils"; + +// if (!dependencies("brightnessctl")) App.quit(); +if (!dependencies("ddcutil")) App.quit(); + +// const get = (args: string) => Number(Utils.exec(`brightnessctl ${args}`)); +// const screen = await bash`ls -w1 /sys/class/backlight | head -1`; +// const kbd = await bash`ls -w1 /sys/class/leds | head -1`; +const ddcGet = async () => + (await Utils.execAsync(`ddcutil getvcp 10 --brief`)).split(" "); + +class Brightness extends Service { + static { + Service.register( + this, + {}, + { + screen: ["float", "rw"], + kbd: ["int", "rw"], + } + ); + } + + // #kbdMax = get(`--device ${kbd} max`); + // #kbd = get(`--device ${kbd} get`); + + #screen: number; + #screenMax: number; + + // get kbd() { + // return this.#kbd; + // } + get screen() { + return this.#screen; + } + + // set kbd(value: number) { + // if (value < 0 ?? value > this.#kbdMax) return; + + // sh(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { + // this.#kbd = value; + // this.changed("kbd"); + // }); + // } + + set screen(percent: number) { + if (percent < 0) percent = 0; + if (percent > 1) percent = 1; + + sh(`ddcutil setvcp 10 ${Math.round(percent * this.#screenMax)}`).then( + () => { + this.#screen = percent; + this.changed("screen"); + } + ); + + // sh(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { + // this.#screen = percent; + // this.changed("screen"); + // }); + } + + changeRelative(percent: number, direction: "+" | "-") { + if (percent < 0) percent = 0; + if (percent > 100) percent = 100; + + const currentPercentage = this.#screen; + if (direction === "+") this.#screen += percent / 100; + else this.#screen -= percent / 100; + this.changed("screen"); + + sh( + `ddcutil setvcp 10 ${direction} ${Math.round((percent / 100) * this.#screenMax)}` + ).catch(() => { + this.#screen = currentPercentage; + this.changed("screen"); + }); + } + + constructor() { + super(); + + // this.#screenMax = get("max"); + // this.#screen = get("get") / get("max") ?? 1; + + ddcGet().then((values) => { + this.#screenMax = Number(values[4]); + this.#screen = Number(values[3]) / Number(values[4]) ?? 1; + }); + + // const screenPath = `/sys/class/backlight/${screen}/brightness`; + // const kbdPath = `/sys/class/leds/${kbd}/brightness`; + + // Utils.monitorFile(screenPath, async (f) => { + // const v = await Utils.readFileAsync(f); + // this.#screen = Number(v) / this.#screenMax; + // this.changed("screen"); + // }); + + // Utils.monitorFile(kbdPath, async (f) => { + // const v = await Utils.readFileAsync(f); + // this.#kbd = Number(v) / this.#kbdMax; + // this.changed("kbd"); + // }); + } +} + +const brightness = new Brightness(); + +Object.assign(globalThis, { brightness }); +export default brightness; diff --git a/config/private_dot_config/exact_ags/service/cliphist.ts b/config/private_dot_config/exact_ags/service/cliphist.ts new file mode 100644 index 00000000..f41b4de7 --- /dev/null +++ b/config/private_dot_config/exact_ags/service/cliphist.ts @@ -0,0 +1,76 @@ +import GLib from "gi://GLib"; +import icons from "lib/icons"; +import { bash, dependencies } from "lib/utils"; +import options from "options"; + +const MAX = options.launcher.cliphist.max; + +export interface CliphistItem { + id: number; + content: string; + contentType: string; +} + +async function query(filter: string) { + if (!dependencies("fzf")) return [] as CliphistItem[]; + const fzfArgs = filter === "" ? '-f ""' : `-f ${filter}`; + + return bash(`cliphist list | fzf ${fzfArgs} | head -n ${MAX}`) + .then((str) => + Array.from( + new Set( + str + .split("\n") + .filter((i) => i) + .map((x) => { + // [[ binary data 63 Kib png 420x420 ]] + const [id, content] = x.match(/(\d+)\s+(.*)/)!.slice(1); + let contentType = "text"; + if (content.startsWith("[[")) { + contentType = + content.match( + /\[\[\s+binary data.*(jpg|png|webp|jpeg|bmp)/ + )![1] ?? "binary"; + } + return { id: Number(id), content, contentType }; + }) + ).values() + ) + ) + .catch((err) => { + print(err); + return []; + }); +} + +function run(args: CliphistItem) { + bash(`cliphist decode ${args.id} | wl-copy`) + .then((out) => { + print(`:cliphist ${args.id}:`); + print(out); + }) + .catch((err) => { + Utils.notify("Cliphist Error", err, icons.app.terminal); + }); +} + +async function getFile(item: CliphistItem) { + const f = `/tmp/cliphist-${item.id}.${item.contentType}`; + if (!GLib.file_test(f, GLib.FileTest.EXISTS)) + await bash(`cliphist decode ${item.id} > ${f}`); + return f; +} + +class Cliphist extends Service { + static { + Service.register(this); + } + constructor() { + super(); + } + getFile = getFile; + query = query; + run = run; +} + +export default new Cliphist(); diff --git a/config/private_dot_config/exact_ags/service/colorpicker.ts b/config/private_dot_config/exact_ags/service/colorpicker.ts new file mode 100644 index 00000000..d3cf71ab --- /dev/null +++ b/config/private_dot_config/exact_ags/service/colorpicker.ts @@ -0,0 +1,58 @@ +import icons from "lib/icons"; +import { bash, dependencies } from "lib/utils"; + +const COLORS_CACHE = Utils.CACHE_DIR + "/colorpicker.json"; +const MAX_NUM_COLORS = 10; + +class ColorPicker extends Service { + static { + Service.register( + this, + {}, + { + colors: ["jsobject"], + } + ); + } + + #notifID = 0; + #colors = JSON.parse(Utils.readFile(COLORS_CACHE) ?? "[]") as string[]; + + get colors() { + return [...this.#colors]; + } + set colors(colors) { + this.#colors = colors; + this.changed("colors"); + } + + // TODO: doesn't work? + async wlCopy(color: string) { + if (dependencies("wl-copy")) bash(`wl-copy ${color}`); + } + + readonly pick = async () => { + if (!dependencies("hyprpicker")) return; + + const color = await bash("hyprpicker -a -r"); + if (!color) return; + + this.wlCopy(color); + const list = this.colors; + if (!list.includes(color)) { + list.push(color); + if (list.length > MAX_NUM_COLORS) list.shift(); + + this.colors = list; + Utils.writeFile(JSON.stringify(list, null, 2), COLORS_CACHE); + } + + this.#notifID = await Utils.notify({ + id: this.#notifID, + iconName: icons.ui.colorpicker, + summary: color, + }); + }; +} + +export default new ColorPicker(); diff --git a/config/private_dot_config/exact_ags/service/hyprshade.ts b/config/private_dot_config/exact_ags/service/hyprshade.ts new file mode 100644 index 00000000..006dea09 --- /dev/null +++ b/config/private_dot_config/exact_ags/service/hyprshade.ts @@ -0,0 +1,39 @@ +import options from "options"; + +const { interval } = options.hyprshade; +class Hyprshade extends Service { + static { + Service.register( + this, + {}, + { + shader: ["string"], + } + ); + } + #shader = ""; + get shader() { + return this.#shader; + } + async #update() { + this.#shader = Utils.exec("hyprshade current"); + this.changed("shader"); + } + async toggle() { + Utils.exec("hyprshade toggle blue-light-filter"); + this.#update(); + } + + get isNight() { + return this.#shader === "blue-light-filter"; + } + + constructor() { + super(); + + Utils.interval(interval.value, () => { + this.#update(); + }); + } +} +export default new Hyprshade(); diff --git a/config/private_dot_config/exact_ags/service/powermenu.ts b/config/private_dot_config/exact_ags/service/powermenu.ts new file mode 100644 index 00000000..97cabbf3 --- /dev/null +++ b/config/private_dot_config/exact_ags/service/powermenu.ts @@ -0,0 +1,53 @@ +import options from "options"; + +const { sleep, reboot, logout, shutdown } = options.powermenu; + +export type Action = "sleep" | "reboot" | "logout" | "shutdown"; + +class PowerMenu extends Service { + static { + Service.register( + this, + {}, + { + title: ["string"], + cmd: ["string"], + } + ); + } + + #title = ""; + #cmd = ""; + + get title() { + return this.#title; + } + + action(action: Action) { + [this.#cmd, this.#title] = { + sleep: [sleep.value, "Sleep"], + reboot: [reboot.value, "Reboot"], + logout: [logout.value, "Log Out"], + shutdown: [shutdown.value, "Shutdown"], + }[action]; + + this.notify("cmd"); + this.notify("title"); + this.emit("changed"); + App.closeWindow("powermenu"); + App.openWindow("verification"); + } + + readonly shutdown = () => { + this.action("shutdown"); + }; + + readonly exec = () => { + App.closeWindow("verification"); + Utils.exec(this.#cmd); + }; +} + +const powermenu = new PowerMenu(); +Object.assign(globalThis, { powermenu }); +export default powermenu; diff --git a/config/private_dot_config/exact_ags/service/screenrecord.ts b/config/private_dot_config/exact_ags/service/screenrecord.ts new file mode 100644 index 00000000..cf6b3367 --- /dev/null +++ b/config/private_dot_config/exact_ags/service/screenrecord.ts @@ -0,0 +1,119 @@ +import GLib from "gi://GLib"; +import icons from "lib/icons"; +import { bash, dependencies, sh } from "lib/utils"; +import hyprshade from "service/hyprshade"; + +const now = () => GLib.DateTime.new_now_local().format("%Y-%m-%d_%H-%M-%S"); + +class Recorder extends Service { + static { + Service.register( + this, + {}, + { + timer: ["int"], + recording: ["boolean"], + } + ); + } + + #recordings = Utils.HOME + "/Videos/Screencasting"; + #screenshots = Utils.HOME + "/Pictures/Screenshots"; + #file = ""; + #interval = 0; + + recording = false; + timer = 0; + is_night = false; + + stopHyprshade() { + this.is_night = hyprshade.isNight; + if (this.is_night) hyprshade.toggle(); + } + + resetHyprshade() { + if (this.is_night) hyprshade.toggle(); + } + + async start() { + if (!dependencies("slurp", "wf-recorder")) return; + + if (this.recording) return; + + this.stopHyprshade(); + + Utils.ensureDirectory(this.#recordings); + this.#file = `${this.#recordings}/${now()}.mp4`; + sh( + `wf-recorder -g "${await sh("slurp")}" -f ${this.#file} --pixel-format yuv420p` + ); + + this.recording = true; + this.changed("recording"); + + this.timer = 0; + this.#interval = Utils.interval(1000, () => { + this.changed("timer"); + this.timer++; + }); + } + + async stop() { + if (!this.recording) return; + + await bash("killall -INT wf-recorder"); + this.recording = false; + this.changed("recording"); + GLib.source_remove(this.#interval); + + this.resetHyprshade(); + + Utils.notify({ + iconName: icons.fallback.video, + summary: "Screenrecord", + body: this.#file, + actions: { + "Show in Files": () => sh(`xdg-open ${this.#recordings}`), + View: () => sh(`xdg-open ${this.#file}`), + }, + }); + } + + async screenshot(full = false) { + if (!dependencies("slurp", "wayshot")) return; + + const file = `${this.#screenshots}/${now()}.png`; + Utils.ensureDirectory(this.#screenshots); + + this.stopHyprshade(); + + if (full) { + await sh(`wayshot -f ${file}`); + } else { + const size = await sh("slurp"); + if (!size) return; + + await sh(`wayshot -f ${file} -s "${size}"`); + } + this.resetHyprshade(); + + bash(`wl-copy < ${file}`); + + Utils.notify({ + image: file, + summary: "Screenshot", + body: file, + actions: { + "Show in Files": () => sh(`xdg-open ${this.#screenshots}`), + View: () => sh(`xdg-open ${file}`), + Edit: () => { + if (dependencies("swappy")) sh(`swappy -f ${file}`); + }, + }, + }); + } +} + +const recorder = new Recorder(); +Object.assign(globalThis, { recorder }); +export default recorder; diff --git a/config/private_dot_config/exact_ags/service/sh.ts b/config/private_dot_config/exact_ags/service/sh.ts new file mode 100644 index 00000000..c8526b46 --- /dev/null +++ b/config/private_dot_config/exact_ags/service/sh.ts @@ -0,0 +1,55 @@ +import GLib from "gi://GLib?version=2.0"; +import icons from "lib/icons"; +import { bash, dependencies } from "lib/utils"; +import options from "options"; + +const MAX = options.launcher.sh.max; +const BINS = `${Utils.CACHE_DIR}/binaries`; + +async function ls(path: string) { + return Utils.execAsync(`ls ${path}`).catch(() => ""); +} + +async function reload() { + const bins = await Promise.all(GLib.getenv("PATH")!.split(":").map(ls)); + + Utils.writeFile(bins.join("\n"), BINS); +} + +async function query(filter: string) { + if (!dependencies("fzf")) return [] as string[]; + + return bash(`cat ${BINS} | fzf -f ${filter} | head -n ${MAX}`) + .then((str) => + Array.from(new Set(str.split("\n").filter((i) => i)).values()) + ) + .catch((err) => { + print(err); + return []; + }); +} + +function run(args: string) { + Utils.execAsync(args) + .then((out) => { + print(`:sh ${args.trim()}:`); + print(out); + }) + .catch((err) => { + Utils.notify("ShRun Error", err, icons.app.terminal); + }); +} + +class Sh extends Service { + static { + Service.register(this); + } + constructor() { + super(); + reload(); + } + query = query; + run = run; +} + +export default new Sh(); diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/a11y-button.scss b/config/private_dot_config/exact_ags/style/exact_mixins/a11y-button.scss new file mode 100644 index 00000000..5f89693b --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/a11y-button.scss @@ -0,0 +1,45 @@ +@import "./button"; + +@mixin accs-button($flat: false, $reactive: true) { + @include unset; + color: $fg; + + > * { + border-radius: $radius; + transition: $transition; + + @if $flat { + background-color: transparent; + box-shadow: none; + } @else { + background-color: $widget-bg; + box-shadow: inset 0 0 0 $border-width $border-color; + } + } + + @if $reactive { + &:focus > *, + &.focused > * { + @include button-focus; + } + + &:hover > * { + @include button-hover; + } + + &:active, + &.active, + &.on, + &:checked { + > * { + @include button-active; + } + + &:hover > * { + box-shadow: + inset 0 0 0 $border-width $border-color, + inset 0 0 0 99px $hover-bg; + } + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/button.scss b/config/private_dot_config/exact_ags/style/exact_mixins/button.scss new file mode 100644 index 00000000..f742925f --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/button.scss @@ -0,0 +1,74 @@ +@mixin button-focus() { + box-shadow: inset 0 0 0 $border-width $primary-bg; + background-color: $hover-bg; + color: $hover-fg; +} + +@mixin button-hover() { + box-shadow: inset 0 0 0 $border-width $border-color; + background-color: $hover-bg; + color: $hover-fg; +} + +@mixin button-active() { + box-shadow: inset 0 0 0 $border-width $border-color; + background-image: $active-gradient; + background-color: $primary-bg; + color: $primary-fg; +} + +@mixin button-disabled() { + box-shadow: none; + background-color: transparent; + color: transparentize($fg, 0.7); +} + +@mixin button( + $flat: false, + $reactive: true, + $radius: $radius, + $focusable: true +) { + all: unset; + transition: $transition; + border-radius: $radius; + color: $fg; + + @if $flat { + background-color: transparent; + background-image: none; + box-shadow: none; + } @else { + background-color: $widget-bg; + box-shadow: inset 0 0 0 $border-width $border-color; + } + + @if $reactive { + @if $focusable { + &:focus { + @include button-focus; + } + } + + &:hover { + @include button-hover; + } + + &:active, + &.on, + &.active, + &:checked { + @include button-active; + + &:hover { + box-shadow: + inset 0 0 0 $border-width $border-color, + inset 0 0 0 99px $hover-bg; + } + } + } + + &:disabled { + @include button-disabled; + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/floating-widget.scss b/config/private_dot_config/exact_ags/style/exact_mixins/floating-widget.scss new file mode 100644 index 00000000..3ff70273 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/floating-widget.scss @@ -0,0 +1,12 @@ +@mixin floating-widget { + @if $shadows { + box-shadow: 0 0 5px 0 $shadow-color; + } + + margin: max($spacing, 8px); + border: $border-width solid $popover-border-color; + background-color: $bg; + color: $fg; + border-radius: $popover-radius; + padding: $popover-padding; +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/hidden.scss b/config/private_dot_config/exact_ags/style/exact_mixins/hidden.scss new file mode 100644 index 00000000..fc0f404d --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/hidden.scss @@ -0,0 +1,15 @@ +@mixin hidden { + background-color: transparent; + background-image: none; + border-color: transparent; + box-shadow: none; + -gtk-icon-transform: scale(0); + + * { + background-color: transparent; + background-image: none; + border-color: transparent; + box-shadow: none; + -gtk-icon-transform: scale(0); + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/media.scss b/config/private_dot_config/exact_ags/style/exact_mixins/media.scss new file mode 100644 index 00000000..0de03470 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/media.scss @@ -0,0 +1,46 @@ +@mixin media() { + @include widget; + padding: $padding; + + .cover { + @if $shadows { + box-shadow: 2px 2px 2px 0 $shadow-color; + } + + background-size: cover; + background-position: center; + border-radius: $radius * 0.8; + margin-right: $spacing; + } + + button { + @include button($flat: true); + padding: $padding * 0.5; + + &.play-pause { + margin: 0 ($spacing * 0.5); + } + + image { + font-size: 1.2em; + } + } + + .artist { + color: transparentize($fg, 0.2); + font-size: 0.9em; + } + + scale { + @include slider( + $width: 0.5em, + $slider: false, + $gradient: linear-gradient($fg, $fg) + ); + margin-bottom: $padding * 0.5; + + trough { + border: none; + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/scrollable.scss b/config/private_dot_config/exact_ags/style/exact_mixins/scrollable.scss new file mode 100644 index 00000000..eca23fca --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/scrollable.scss @@ -0,0 +1,56 @@ +@mixin scrollable($top: false, $bottom: false) { + @if $top and $shadows { + undershoot.top { + background: linear-gradient( + to bottom, + $shadow-color, + transparent, + transparent, + transparent, + transparent, + transparent + ); + } + } + + @if $bottom and $shadows { + undershoot.bottom { + background: linear-gradient( + to top, + $shadow-color, + transparent, + transparent, + transparent, + transparent, + transparent + ); + } + } + + scrollbar, + scrollbar * { + all: unset; + } + + scrollbar.vertical { + transition: $transition; + background-color: transparentize($bg, 0.7); + + &:hover { + background-color: transparentize($bg, 0.3); + + slider { + background-color: transparentize($fg, 0.3); + min-width: 0.6em; + } + } + } + + scrollbar.vertical slider { + background-color: transparentize($fg, 0.5); + border-radius: $radius; + min-width: 0.4em; + min-height: 2em; + transition: $transition; + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/slider.scss b/config/private_dot_config/exact_ags/style/exact_mixins/slider.scss new file mode 100644 index 00000000..56287686 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/slider.scss @@ -0,0 +1,79 @@ +@import "./unset"; + +@mixin slider( + $width: 0.7em, + $slider-width: 0.5em, + $gradient: $active-gradient, + $slider: true, + $focusable: true, + $radius: $radius +) { + @include unset($rec: true); + + trough { + transition: $transition; + border-radius: $radius; + border: $border; + background-color: $widget-bg; + min-height: $width; + min-width: $width; + + highlight, + progress { + border-radius: max($radius - $border-width, 0); + background-image: $gradient; + min-height: $width; + min-width: $width; + } + } + + slider { + box-shadow: none; + background-color: transparent; + border: $border-width solid transparent; + transition: $transition; + border-radius: $radius; + min-height: $width; + min-width: $width; + margin: -$slider-width; + } + + &:hover { + trough { + background-color: $hover-bg; + } + + slider { + @if $slider { + background-color: $fg; + border-color: $border-color; + + @if $shadows { + box-shadow: 0 0 3px 0 $shadow-color; + } + } + } + } + + &:disabled { + highlight, + progress { + background-color: transparentize($fg, 0.4); + background-image: none; + } + } + + @if $focusable { + trough:focus { + background-color: $hover-bg; + box-shadow: inset 0 0 0 $border-width $primary-bg; + + slider { + @if $slider { + background-color: $fg; + box-shadow: inset 0 0 0 $border-width $primary-bg; + } + } + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/spacing.scss b/config/private_dot_config/exact_ags/style/exact_mixins/spacing.scss new file mode 100644 index 00000000..34572665 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/spacing.scss @@ -0,0 +1,53 @@ +@mixin spacing($multiplier: 1, $spacing: $spacing, $rec: false) { + &.horizontal > * { + margin: 0 calc($spacing * $multiplier / 2); + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + } + + &.vertical > * { + margin: calc($spacing * $multiplier / 2) 0; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + + @if $rec { + box { + &.horizontal > * { + margin: 0 $spacing * $multiplier / 2; + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + } + + &.vertical > * { + margin: $spacing * $multiplier / 2 0; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/switch.scss b/config/private_dot_config/exact_ags/style/exact_mixins/switch.scss new file mode 100644 index 00000000..9650d126 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/switch.scss @@ -0,0 +1,16 @@ +@import "./button"; + +@mixin switch { + @include button; + + slider { + background-color: $primary-fg; + border-radius: $radius; + min-width: 24px; + min-height: 24px; + } + + image { + color: transparent; + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/unset.scss b/config/private_dot_config/exact_ags/style/exact_mixins/unset.scss new file mode 100644 index 00000000..1dce6207 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/unset.scss @@ -0,0 +1,9 @@ +@mixin unset($rec: false) { + all: unset; + + @if $rec { + * { + all: unset; + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_mixins/widget.scss b/config/private_dot_config/exact_ags/style/exact_mixins/widget.scss new file mode 100644 index 00000000..28208ac8 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_mixins/widget.scss @@ -0,0 +1,7 @@ +@mixin widget { + transition: $transition; + border-radius: $radius; + color: $fg; + background-color: $widget-bg; + border: $border; +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/bar.scss b/config/private_dot_config/exact_ags/style/exact_widgets/bar.scss new file mode 100644 index 00000000..7fae3b68 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/bar.scss @@ -0,0 +1,282 @@ +@use "sass:color"; + +$bar-spacing: $spacing * 0.3; +$button-radius: $radius; + +@mixin panel-button($flat: true, $reactive: true) { + @include accs-button($flat, $reactive); + + > * { + border-radius: $button-radius; + margin: $bar-spacing; + } + + label, + image { + font-weight: bold; + } + + > * { + padding: $padding * 0.4 $padding * 0.8; + } +} + +@keyframes error { + to { + background-color: $error-bg; + color: $error-fg; + } +} + +.bar { + transition: $transition; + background-color: $bg; + + .panel-button { + @include panel-button; + + &:not(.flat) { + @include accs-button($flat: false); + } + } + + .launcher { + .colored { + color: transparentize($primary-bg, 0.2); + } + + &:hover .colored { + color: $primary-bg; + } + + &:active .colored, + &.active .colored { + color: $primary-fg; + } + } + + .workspaces { + label { + font-size: 0; + min-width: 5pt; + min-height: 5pt; + border-radius: $radius * 0.6; + box-shadow: inset 0 0 0 $border-width $border-color; + margin: 0 $padding * 0.5; + transition: $transition * 0.5; + background-color: transparentize($fg, 0.8); + + &.occupied { + background-color: transparentize($fg, 0.2); + min-width: 7pt; + min-height: 7pt; + } + + &.active { + // background-color: $primary-bg; + background-image: $active-gradient; + min-width: 20pt; + min-height: 12pt; + } + } + + &.active, + &:active { + label { + background-color: transparentize($primary-fg, 0.3); + + &.occupied { + background-color: transparentize($primary-fg, 0.15); + } + + &.active { + background-color: $primary-fg; + } + } + } + } + + .media label { + margin: 0 ($spacing * 0.5); + } + + .system-info > * { + animation-name: error; + animation-duration: 0.8s; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-direction: alternate; + label { + margin: 0 ($spacing * 0.5); + } + } + + .taskbar .indicator.active { + background-color: $primary-bg; + border-radius: $radius; + min-height: 4pt; + min-width: 6pt; + margin: 2pt; + } + + .powermenu.colored, + .recorder { + image { + color: transparentize($error-bg, 0.3); + } + + &:hover image { + color: transparentize($error-bg, 0.15); + } + + &:active image { + color: $primary-fg; + } + } + + .quicksettings > box > box { + @include spacing($spacing: if($bar-spacing==0, $padding / 2, $bar-spacing)); + } + + .quicksettings:not(.active):not(:active) { + .bluetooth { + color: $primary-bg; + + label { + font-size: $font-size * 0.7; + color: $fg; + text-shadow: $text-shadow; + } + } + } + + .battery-bar { + > * { + padding: 0; + } + + &.bar-hidden > box { + padding: 0 $spacing * 0.5; + + image { + margin: 0; + } + } + + levelbar * { + all: unset; + transition: $transition; + } + + .whole { + @if $shadows { + image { + -gtk-icon-shadow: $text-shadow; + } + + label { + text-shadow: $text-shadow; + } + } + } + + .regular image { + margin-left: $spacing * 0.5; + } + + trough { + @include widget; + min-height: 12pt; + min-width: 12pt; + } + + .regular trough { + margin-right: $spacing * 0.5; + } + + block { + margin: 0; + + &:last-child { + border-radius: 0 $button-radius $button-radius 0; + } + + &:first-child { + border-radius: $button-radius 0 0 $button-radius; + } + } + + .vertical { + block { + &:last-child { + border-radius: 0 0 $button-radius $button-radius; + } + + &:first-child { + border-radius: $button-radius $button-radius 0 0; + } + } + } + + @for $i from 1 through $bar-battery-blocks { + block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $primary-bg, $i * 3); + } + + &.low block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $error-bg, $i * 3); + } + + &.charging block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $charging-bg, $i * 3); + } + + &:active .regular block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $primary-fg, $i * 3); + } + } + + &.low image { + color: $error-bg; + } + + &.charging image { + color: $charging-bg; + } + + &:active image { + color: $primary-fg; + } + } +} + +.bar.transparent { + background-color: transparent; + + .panel-button { + &:hover > * { + box-shadow: + 1px 1px 3px 0 $shadow-color, + inset 0 0 0 $border-width $border-color; + background-color: $bg; + } + + &:not(:hover):not(.active) { + label, + image { + text-shadow: $text-shadow; + -gtk-icon-shadow: $text-shadow; + } + } + } + + .workspaces label { + box-shadow: + inset 0 0 0 $border-width $border-color, + 1px 1px 3px 0 $shadow-color; + } + + .battery-bar trough { + box-shadow: 1px 1px 3px 0 $shadow-color; + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/datemenu.scss b/config/private_dot_config/exact_ags/style/exact_widgets/datemenu.scss new file mode 100644 index 00000000..df0b300b --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/datemenu.scss @@ -0,0 +1,110 @@ +@import "./notifications.scss"; + +@mixin calendar { + @include widget; + padding: $padding * 2 $padding * 2 0; + + calendar { + all: unset; + + &.button { + @include button($flat: true); + } + + &:selected { + box-shadow: + inset 0 -8px 0 0 transparentize($primary-bg, 0.5), + inset 0 0 0 1px $primary-bg; + border-radius: $radius * 0.6; + } + + &.header { + background-color: transparent; + border: none; + color: transparentize($fg, 0.5); + } + + &.highlight { + background-color: transparent; + color: transparentize($primary-bg, 0.5); + } + + &:indeterminate { + color: transparentize($fg, 0.9); + } + + font-size: 1.1em; + padding: 0.2em; + } +} + +window#datemenu .datemenu { + @include floating-widget; + + .notifications { + .header { + margin-bottom: $spacing; + margin-right: $spacing; + + > label { + margin-left: $radius * 0.5; + } + + button { + @include button; + padding: $padding * 0.7 $padding; + } + } + + .notification-scrollable { + @include scrollable($top: true, $bottom: true); + } + + .notification-list { + margin-right: $spacing; + } + + .notification { + @include notification; + @include widget; + padding: $padding; + margin-bottom: $spacing; + } + + .placeholder { + image { + font-size: 7em; + } + + label { + font-size: 1.2em; + } + } + } + + separator { + background-color: $popover-border-color; + border-radius: $radius; + margin-right: $spacing; + } + + .datemenu { + @include spacing; + } + + .clock-box { + padding: $padding; + + .clock { + font-size: 5em; + } + + .uptime { + color: transparentize($fg, 0.2); + } + } + + .calendar { + @include calendar; + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/launcher.scss b/config/private_dot_config/exact_ags/style/exact_widgets/launcher.scss new file mode 100644 index 00000000..9470dab2 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/launcher.scss @@ -0,0 +1,158 @@ +@use "sass:math"; +@use "sass:color"; + +window#launcher .launcher { + @include floating_widget; + + .quicklaunch { + @include spacing; + + button { + @include button($flat: true); + padding: $padding; + } + } + + entry { + @include button; + padding: $padding; + margin: $spacing; + + selection { + color: color.mix($fg, $bg, 50%); + background-color: transparent; + } + + label, + image { + color: $fg; + } + } + + image.spinner { + color: $primary-bg; + margin-right: $spacing; + } + + separator { + margin: 4pt 0; + background-color: $popover-border-color; + } + + button.app-item { + @include button($flat: true, $reactive: false); + + > box { + @include spacing(0.5); + } + + transition: $transition; + padding: $padding; + + label { + transition: $transition; + + &.title { + color: $fg; + } + + &.description { + color: transparentize($fg, 0.3); + } + } + + image { + transition: $transition; + } + + &:hover, + &:focus { + .title { + color: $primary-bg; + } + + .description { + color: transparentize($primary-bg, 0.4); + } + + image { + -gtk-icon-shadow: 2px 2px $primary-bg; + } + } + + &:active { + background-color: transparentize($primary-bg, 0.5); + border-radius: $radius; + box-shadow: inset 0 0 0 $border-width $border-color; + + .title { + color: $fg; + } + } + } + + button.help { + @include button($flat: true, $reactive: false); + padding: 0 ($padding * 0.5); + + label { + transition: $transition; + color: $fg; + } + + .name { + font-size: 1.2em; + font-weight: bold; + } + + .description { + color: transparentize($fg, 0.3); + } + + &:hover, + &:focus { + label { + text-shadow: $text-shadow; + } + + .name, + .version { + color: $primary-bg; + } + + .description { + color: transparentize($primary-bg, 0.3); + } + } + } + + button.sh-item { + @include button($flat: true, $reactive: false); + padding: 0 ($padding * 0.5); + + transition: $transition; + color: $fg; + + &:hover, + &:focus { + color: $primary-bg; + text-shadow: $text-shadow; + } + } + + button.cliphist-item { + @include button($flat: true, $reactive: false); + padding: 0 ($padding * 0.5); + + transition: $transition; + color: $fg; + + &:hover, + &:focus { + color: $primary-bg; + background-color: transparentize($primary-bg, 0.9); + border-radius: 0; + text-shadow: $text-shadow; + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/notifications.scss b/config/private_dot_config/exact_ags/style/exact_widgets/notifications.scss new file mode 100644 index 00000000..55f2b652 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/notifications.scss @@ -0,0 +1,79 @@ +@mixin notification() { + &.critical { + box-shadow: inset 0 0 0.5em 0 $error-bg; + } + + &:hover button.close-button { + @include button-hover; + background-color: transparentize($error-bg, 0.5); + } + + .content { + .title { + margin-right: $spacing; + color: $fg; + font-size: 1.1em; + } + + .time { + color: transparentize($fg, 0.2); + } + + .description { + font-size: 0.9em; + color: transparentize($fg, 0.2); + } + + .icon { + border-radius: $radius * 0.8; + margin-right: $spacing; + + &.img { + border: $border; + } + } + } + + box.actions { + @include spacing(0.5); + margin-top: $spacing; + + button { + @include button; + border-radius: $radius * 0.8; + font-size: 1.2em; + padding: $padding * 0.7; + } + } + + button.close-button { + @include button($flat: true); + margin-left: $spacing / 2; + border-radius: $radius * 0.8; + min-width: 1.2em; + min-height: 1.2em; + + &:hover { + background-color: transparentize($error-bg, 0.2); + } + + &:active { + background-image: none; + background-color: $error-bg; + } + } +} + +window.notifications { + @include unset; + + .notification { + @include notification; + @include floating-widget; + border-radius: $radius; + + .description { + min-width: 350px; + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/osd.scss b/config/private_dot_config/exact_ags/style/exact_widgets/osd.scss new file mode 100644 index 00000000..01f1a45d --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/osd.scss @@ -0,0 +1,26 @@ +window.indicator { + .progress { + @include floating-widget; + padding: $padding * 0.5; + border-radius: if($radius >0, calc($radius + $padding * 0.5), 0); + @debug $radius; + + .fill { + border-radius: $radius; + background-color: $primary-bg; + color: $primary-fg; + + image { + -gtk-icon-transform: scale(0.7); + } + } + } + + .microphone { + @include floating-widget; + margin: $spacing * 2; + padding: $popover-padding * 2; + font-size: 58px; + color: transparentize($fg, 0.1); + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/overview.scss b/config/private_dot_config/exact_ags/style/exact_widgets/overview.scss new file mode 100644 index 00000000..55321e14 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/overview.scss @@ -0,0 +1,34 @@ +window#overview .overview { + @include floating-widget; + @include spacing; + + .workspace { + &.active > widget { + border-color: $primary-bg; + } + + > widget { + @include widget; + border-radius: if($radius ==0, 0, $radius + $padding); + + &:hover { + background-color: $hover-bg; + } + + &:drop(active) { + border-color: $primary-bg; + } + } + } + + .client { + @include button; + border-radius: $radius; + margin: $padding; + + &.hidden { + @include hidden; + transition: 0; + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/powermenu.scss b/config/private_dot_config/exact_ags/style/exact_widgets/powermenu.scss new file mode 100644 index 00000000..d564fdba --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/powermenu.scss @@ -0,0 +1,110 @@ +window#powermenu, +window#verification { + // the fraction has to be more than hyprland ignorealpha + background-color: rgba(0, 0, 0, 0.4); +} + +window#verification .verification { + @include floating-widget; + padding: $popover-padding * 1.5; + min-width: 300px; + min-height: 100px; + + .text-box { + margin-bottom: $spacing; + + .title { + font-size: 1.6em; + } + + .desc { + color: transparentize($fg, 0.1); + font-size: 1.1em; + } + } + + .buttons { + @include spacing; + margin-top: $padding; + + button { + @include button; + font-size: 1.5em; + padding: $padding; + } + } +} + +window#powermenu .powermenu { + @include floating-widget; + + &.line { + padding: $popover-padding * 1.5; + + button { + padding: $popover-padding; + } + + label { + margin-bottom: $spacing * -0.5; + } + } + + &.box { + padding: $popover-padding * 2; + + button { + padding: $popover-padding * 1.5; + } + + label { + margin-bottom: $spacing * -1; + } + } + + button { + @include unset; + + image { + @include button; + border-radius: $radius + ($popover-padding * 1.4); + min-width: 1.7em; + min-height: 1.7em; + font-size: 4em; + } + + label, + image { + color: transparentize($fg, 0.1); + } + + label { + margin-top: $spacing * 0.3; + } + + &:hover { + image { + @include button-hover; + } + + label { + color: $fg; + } + } + + &:focus image { + @include button-focus; + } + + &:active image { + @include button-active; + } + + &:focus, + &:active { + label { + color: $primary-bg; + } + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/quicksettings.scss b/config/private_dot_config/exact_ags/style/exact_widgets/quicksettings.scss new file mode 100644 index 00000000..22544af4 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/quicksettings.scss @@ -0,0 +1,177 @@ +window#quicksettings .quicksettings { + @include floating-widget; + @include spacing; + + padding: $popover-padding * 1.4; + + .avatar { + @include widget; + border-radius: $radius * 3; + } + + .header { + @include spacing(0.5); + color: transparentize($fg, 0.15); + + button { + @include button; + padding: $padding; + + image { + font-size: 1.4em; + } + } + } + + .sliders-box { + @include widget; + padding: $padding; + + button { + @include button($flat: true); + padding: $padding * 0.5; + } + + .volume button.arrow:last-child { + margin-left: $spacing * 0.4; + } + + .volume, + .brightness { + padding: $padding * 0.5; + } + + scale { + @include slider; + margin: 0 ($spacing * 0.5); + + &.muted highlight { + background-image: none; + background-color: transparentize($fg, $amount: 0.2); + } + } + } + + .row { + @include spacing; + } + + .menu { + @include unset; + @include widget; + padding: $padding; + margin-top: $spacing; + + .icon { + margin: 0 ($spacing * 0.5); + margin-left: $spacing * 0.2; + } + + .title { + font-weight: bold; + } + + separator { + margin: ($radius * 0.5); + background-color: $border-color; + } + + button { + @include button($flat: true); + padding: ($padding * 0.5); + + image:first-child { + margin-right: $spacing * 0.5; + } + } + + .bluetooth-devices { + @include spacing(0.5); + } + + switch { + @include switch; + } + } + + .sliders-box .menu { + margin: ($spacing * 0.5) 0; + + &.app-mixer { + .mixer-item { + padding: $padding * 0.5; + padding-left: 0; + padding-right: $padding * 2; + + scale { + @include slider($width: 0.5em); + } + + image { + font-size: 1.2em; + margin: 0 $padding; + } + } + } + } + + .toggle-button { + @include button; + font-weight: bold; + + image { + font-size: 1.3em; + } + + label { + margin-left: $spacing * 0.3; + } + + button { + @include button($flat: true); + + &:first-child { + padding: $padding * 1.2; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + &:last-child { + padding: $padding * 0.5; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + &.active { + background-color: $primary-bg; + + label, + image { + color: $primary-fg; + } + } + } + + .simple-toggle { + @include button; + font-weight: bold; + padding: $padding * 1.2; + + label { + margin-left: $spacing * 0.3; + } + + image { + font-size: 1.3em; + } + } + + .media { + @include spacing; + + .player { + @include media; + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/screencorner.scss b/config/private_dot_config/exact_ags/style/exact_widgets/screencorner.scss new file mode 100644 index 00000000..e163af34 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/screencorner.scss @@ -0,0 +1,52 @@ +$_shadow-size: $padding; +$_radius: $radius * $hyprland-gaps-multiplier * $screen-corner-multiplier; +$_margin: 99px; + +window.screen-corner:not(.hidden) { + transition: $transition; + + box.shadow { + margin-right: $_margin * -1; + margin-left: $_margin * -1; + + @if $shadows { + box-shadow: inset 0 0 $_shadow-size 0 $shadow-color; + } + + @if $bar-position == "top" { + margin-bottom: $_margin * -1; + } + + @if $bar-position == "bottom" { + margin-top: $_margin * -1; + } + } + + box.border { + @if $bar-position == "top" { + border-top: $border-width solid $bg; + } + + @if $bar-position == "bottom" { + border-bottom: $border-width solid $bg; + } + + margin-right: $_margin; + margin-left: $_margin; + } + + box.corner { + box-shadow: 0 0 0 $border-width $border-color; + } + + &.corners { + box.border { + border-radius: if($radius>0, $_radius, 0); + box-shadow: 0 0 0 $_radius $bg; + } + + box.corner { + border-radius: if($radius>0, $_radius, 0); + } + } +} diff --git a/config/private_dot_config/exact_ags/style/exact_widgets/settingsdialog.scss b/config/private_dot_config/exact_ags/style/exact_widgets/settingsdialog.scss new file mode 100644 index 00000000..7dc00dc7 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/exact_widgets/settingsdialog.scss @@ -0,0 +1,134 @@ +window.settings-dialog { + background-color: $bg; + color: $fg; + + .header { + .pager { + @include spacing(0.5); + } + + padding: $padding; + + button { + @include button; + font-weight: bold; + padding: $padding * 0.5 $padding; + + box { + @include spacing($spacing: 0.3em); + } + } + + button.close { + padding: $padding * 0.5; + } + + button.reset { + @include button($flat: true); + padding: $padding * 0.5; + } + } + + .page { + @include scrollable($top: true); + + .page-content { + padding: $padding * 2; + padding-top: 0; + } + } + + .group { + .group-title { + color: $primary-bg; + margin-bottom: $spacing * 0.5; + } + + .group-reset { + @include button($flat: true); + margin: $spacing * 0.5; + padding: $padding * 0.5; + + &:disabled { + color: transparent; + } + } + + &:not(:first-child) { + margin-top: $spacing; + } + } + + .row { + background-color: $widget-bg; + padding: $padding; + border: $border; + border-top: none; + + &:first-child { + border-radius: $radius $radius 0 0; + border: $border; + } + + &:last-child { + border-radius: 0 0 $radius $radius; + } + + &:first-child:last-child { + border-radius: $radius; + border: $border; + } + + button.reset { + margin-left: $spacing; + } + + label.id, + label.note { + color: transparentize($fg, 0.4); + } + + entry, + button { + @include button; + padding: $padding; + } + + switch { + @include switch; + } + + spinbutton { + @include unset; + + entry { + border-radius: $radius 0 0 $radius; + } + + button { + border-radius: 0; + } + + button:last-child { + border-radius: 0 $radius $radius 0; + } + } + + .enum-setter { + label { + background-color: $widget-bg; + border: $border; + padding: 0 $padding; + border-radius: $radius 0 0 $radius; + } + + button { + border-radius: 0; + } + + button:last-child { + border-radius: 0 $radius $radius 0; + } + } + } +} diff --git a/config/private_dot_config/exact_ags/style/extra.scss b/config/private_dot_config/exact_ags/style/extra.scss new file mode 100644 index 00000000..ca51fa85 --- /dev/null +++ b/config/private_dot_config/exact_ags/style/extra.scss @@ -0,0 +1,67 @@ +@import "./mixins/button.scss"; + +* { + font-size: $font-size; + font-family: $font-name; +} + +separator { + &.horizontal { + min-height: $border-width; + } + + &.vertical { + min-width: $border-width; + } +} + +window.popup { + > * { + border: none; + box-shadow: none; + } + + menu { + border-radius: $popover-radius; + background-color: $bg; + padding: $popover-padding; + border: $border-width solid $popover-border-color; + + separator { + background-color: $border-color; + } + + menuitem { + @include button; + padding: $spacing * 0.5; + margin: ($spacing * 0.5) 0; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + } +} + +tooltip { + * { + all: unset; + } + + background-color: transparent; + border: none; + + > * > * { + background-color: $bg; + border-radius: $radius; + border: $border-width solid $popover-border-color; + color: $fg; + padding: 8px; + margin: 4px; + box-shadow: 0 0 3px 0 $shadow-color; + } +} diff --git a/config/private_dot_config/exact_ags/style/style.ts b/config/private_dot_config/exact_ags/style/style.ts new file mode 100644 index 00000000..38bbee1e --- /dev/null +++ b/config/private_dot_config/exact_ags/style/style.ts @@ -0,0 +1,133 @@ +import { bash, dependencies } from "lib/utils"; +import options from "options"; + +const deps = [ + "font", + "theme", + "bar.corners", + "bar.flatButtons", + "bar.position", + "bar.battery.charging", + "bar.battery.blocks", +]; + +const { + dark, + light, + blur, + scheme, + padding, + spacing, + radius, + shadows, + widget, + border, +} = options.theme; + +const popoverPaddingMultiplier = 1.6; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const t = (dark: string, light: string) => + scheme.value === "dark" ? `${dark}` : `${light}`; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const $ = (name: string, value: string | number) => `$${name}: ${value};`; + +const variables = () => [ + $( + "bg", + blur.value + ? `transparentize(${t(dark.bg.value, light.bg.value)}, ${blur.value / 100})` + : t(dark.bg.value, light.bg.value) + ), + $("fg", t(dark.fg.value, light.fg.value)), + + $("primary-bg", t(dark.primary.accent.value, light.primary.accent.value)), + $("primary-fg", t(dark.fg.value, light.fg.value)), + + $("error-bg", t(dark.error.accent.value, light.error.bg.value)), + $("error-fg", t(dark.fg.value, light.fg.value)), + + $("scheme", scheme.value), + $("padding", `${padding.value}pt`), + $("spacing", `${spacing.value}pt`), + $("radius", `${radius.value}px`), + $("transition", `${options.transition.value}ms`), + + $("shadows", `${shadows.value}`), + + $( + "widget-bg", + `transparentize(${t(dark.widget.value, light.widget.value)}, ${widget.opacity.value / 100})` + ), + + $( + "hover-bg", + `transparentize(${t(dark.widget.value, light.widget.value)}, ${(widget.opacity.value * 0.9) / 100})` + ), + $("hover-fg", `lighten(${t(dark.fg.value, light.fg.value)}, 8%)`), + + $("border-width", `${border.width.value}px`), + $( + "border-color", + `transparentize(${t(dark.border.value, light.border.value)}, ${border.opacity.value / 100})` + ), + $("border", "$border-width solid $border-color"), + + $( + "active-gradient", + `linear-gradient(to right, ${t(dark.primary.accent.value, light.primary.accent.value)}, darken(${t(dark.primary.accent.value, light.primary.accent.value)}, 4%))` + ), + $("shadow-color", t("rgba(0,0,0,.6)", "rgba(0,0,0,.4)")), + $("text-shadow", t("2pt 2pt 2pt $shadow-color", "none")), + $( + "box-shadow", + t( + "2pt 2pt 2pt 0 $shadow-color, inset 0 0 0 $border-width $border-color", + "none" + ) + ), + + $( + "popover-border-color", + `transparentize(${t(dark.border.value, light.border.value)}, ${Math.max((border.opacity.value - 1) / 100, 0)})` + ), + $("popover-padding", `$padding * ${popoverPaddingMultiplier}`), + $("popover-radius", radius.value === 0 ? "0" : "$radius + $popover-padding"), + + $("font-size", `${options.font.size.value}pt`), + $("font-name", options.font.name.value), + + // etc + $("charging-bg", options.bar.battery.charging.value), + $("bar-battery-blocks", options.bar.battery.blocks.value), + $("bar-position", options.bar.position.value), + $("hyprland-gaps-multiplier", options.hyprland.gaps.value), + $("screen-corner-multiplier", `${options.bar.corners.value * 0.01}`), +]; + +async function resetCss() { + if (!dependencies("sass", "fd")) return; + + try { + const vars = `${TMP}/variables.scss`; + const scss = `${TMP}/main.scss`; + const css = `${TMP}/main.css`; + + const fd = await bash(`fd ".scss" ${App.configDir}`); + const files = fd.split(/\s+/); + const imports = [vars, ...files].map((f) => `@import '${f}';`); + + await Utils.writeFile(variables().join("\n"), vars); + await Utils.writeFile(imports.join("\n"), scss); + await bash`sass ${scss} ${css}`; + + App.applyCss(css, true); + } catch (error) { + error instanceof Error ? logError(error) : console.error(error); + } +} + +Utils.monitorFile(`${App.configDir}/style`, resetCss); +options.handler(deps, resetCss); +await resetCss(); diff --git a/config/private_dot_config/exact_ags/template.ts.tmpl b/config/private_dot_config/exact_ags/template.ts.tmpl new file mode 100644 index 00000000..7c6b1197 --- /dev/null +++ b/config/private_dot_config/exact_ags/template.ts.tmpl @@ -0,0 +1,3 @@ +export const FONT_SANS_FAMILY = "{{- .font.sans.family -}}"; +export const IS_NOT_VM = {{ ne .device_type "vm" }}; +export const THEME = {{ .theme | toPrettyJson -}}; diff --git a/config/private_dot_config/exact_ags/tsconfig.json b/config/private_dot_config/exact_ags/tsconfig.json new file mode 100644 index 00000000..8b434691 --- /dev/null +++ b/config/private_dot_config/exact_ags/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + /* Base Options: */ + "esModuleInterop": true, + "skipLibCheck": true, + "target": "ES2022", + "allowJs": true, + "moduleDetection": "force", + + /* Strictness */ + "strict": true, + "noUncheckedIndexedAccess": true, + "checkJs": true, + + /* Bundled projects */ + "lib": ["ES2022"], + "module": "ES2022", + + "baseUrl": ".", + "typeRoots": ["./types", "./node_modules/@girs"] + } +} diff --git a/config/private_dot_config/exact_ags/widget/PopupWindow.ts b/config/private_dot_config/exact_ags/widget/PopupWindow.ts new file mode 100644 index 00000000..edf5e178 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/PopupWindow.ts @@ -0,0 +1,175 @@ +import options from "options"; +import { type EventBoxProps } from "types/widgets/eventbox"; +import { type RevealerProps } from "types/widgets/revealer"; +import { type WindowProps } from "types/widgets/window"; + +import type Gtk from "gi://Gtk?version=3.0"; + +type Transition = RevealerProps["transition"]; +type Child = WindowProps["child"]; + +type PopupWindowProps = Omit & { + name: string; + layout?: keyof ReturnType; + transition?: Transition; +}; + +export const Padding = ( + name: string, + { css = "", hexpand = true, vexpand = true }: EventBoxProps = {} +) => + Widget.EventBox({ + hexpand, + vexpand, + can_focus: false, + child: Widget.Box({ css }), + setup: (w) => w.on("button-press-event", () => App.toggleWindow(name)), + }); + +const PopupRevealer = ( + name: string, + child: Child, + transition: Transition = "slide_down" +) => + Widget.Box( + { css: "padding: 1px;" }, + Widget.Revealer({ + transition, + child: Widget.Box({ + class_name: "window-content", + child, + }), + transitionDuration: options.transition.bind(), + setup: (self) => + self.hook(App, (_, wname, visible) => { + if (wname === name) self.reveal_child = visible; + }), + }) + ); + +const Layout = (name: string, child: Child, transition?: Transition) => ({ + center: () => + Widget.CenterBox( + {}, + Padding(name), + Widget.CenterBox( + { vertical: true }, + Padding(name), + PopupRevealer(name, child, transition), + Padding(name) + ), + Padding(name) + ), + top: () => + Widget.CenterBox( + {}, + Padding(name), + Widget.Box( + { vertical: true }, + PopupRevealer(name, child, transition), + Padding(name) + ), + Padding(name) + ), + "top-right": () => + Widget.Box( + {}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + PopupRevealer(name, child, transition), + Padding(name) + ) + ), + "top-center": () => + Widget.Box( + {}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + PopupRevealer(name, child, transition), + Padding(name) + ), + Padding(name) + ), + "top-left": () => + Widget.Box( + {}, + Widget.Box( + { + hexpand: false, + vertical: true, + }, + PopupRevealer(name, child, transition), + Padding(name) + ), + Padding(name) + ), + "bottom-left": () => + Widget.Box( + {}, + Widget.Box( + { + hexpand: false, + vertical: true, + }, + Padding(name), + PopupRevealer(name, child, transition) + ), + Padding(name) + ), + "bottom-center": () => + Widget.Box( + {}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + Padding(name), + PopupRevealer(name, child, transition) + ), + Padding(name) + ), + "bottom-right": () => + Widget.Box( + {}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + Padding(name), + PopupRevealer(name, child, transition) + ) + ), +}); + +export default ({ + name, + child, + layout = "center", + transition, + exclusivity = "ignore", + ...props +}: PopupWindowProps) => + Widget.Window({ + name, + class_names: [name, "popup-window"], + setup: (w) => w.keybind("Escape", () => App.closeWindow(name)), + visible: false, + keymode: "on-demand", + exclusivity, + layer: "top", + anchor: ["top", "bottom", "right", "left"], + child: Layout(name, child, transition)[layout](), + ...props, + }); diff --git a/config/private_dot_config/exact_ags/widget/RegularWindow.ts b/config/private_dot_config/exact_ags/widget/RegularWindow.ts new file mode 100644 index 00000000..6550ab9c --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/RegularWindow.ts @@ -0,0 +1,6 @@ +import Gtk from "gi://Gtk?version=3.0"; + +export default Widget.subclass< + typeof Gtk.Window, + Gtk.Window.ConstructorProperties +>(Gtk.Window); diff --git a/config/private_dot_config/exact_ags/widget/bar/Bar.ts b/config/private_dot_config/exact_ags/widget/bar/Bar.ts new file mode 100644 index 00000000..e9eaeeed --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/Bar.ts @@ -0,0 +1,67 @@ +import options from "options"; + +import BatteryBar from "./buttons/BatteryBar"; +import ColorPicker from "./buttons/ColorPicker"; +import Date from "./buttons/Date"; +import Hyprshade from "./buttons/Hyprshade"; +import Launcher from "./buttons/Launcher"; +import Media from "./buttons/Media"; +import Messages from "./buttons/Messages"; +import PowerMenu from "./buttons/PowerMenu"; +import ScreenRecord from "./buttons/ScreenRecord"; +import SystemIndicators from "./buttons/SystemIndicators"; +import SystemInfo from "./buttons/SystemInfo"; +import SysTray from "./buttons/SysTray"; +import Taskbar from "./buttons/Taskbar"; +import Workspaces from "./buttons/Workspaces"; + +const { start, center, end } = options.bar.layout; +const { transparent, position } = options.bar; + +export type BarWidget = keyof typeof widget; + +const widget = { + battery: BatteryBar, + colorpicker: ColorPicker, + date: Date, + launcher: Launcher, + media: Media, + powermenu: PowerMenu, + systray: SysTray, + system: SystemIndicators, + taskbar: Taskbar, + workspaces: Workspaces, + screenrecord: ScreenRecord, + hyprshade: Hyprshade, + messages: Messages, + ["system-info"]: SystemInfo, + expander: () => Widget.Box({ expand: true }), +}; + +export default (monitor: number) => + Widget.Window({ + monitor, + class_name: "bar", + name: `bar${monitor}`, + exclusivity: "exclusive", + anchor: position.bind().as((pos) => [pos, "right", "left"]), + child: Widget.CenterBox({ + css: "min-width: 2px; min-height: 2px;", + startWidget: Widget.Box({ + hexpand: true, + children: start.bind().as((s) => s.map((w) => widget[w]())), + }), + centerWidget: Widget.Box({ + hpack: "center", + children: center.bind().as((c) => c.map((w) => widget[w]())), + }), + endWidget: Widget.Box({ + hexpand: true, + children: end.bind().as((e) => e.map((w) => widget[w]())), + }), + }), + setup: (self) => + self.hook(transparent, () => { + self.toggleClassName("transparent", transparent.value); + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/PanelButton.ts b/config/private_dot_config/exact_ags/widget/bar/PanelButton.ts new file mode 100644 index 00000000..88881e98 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/PanelButton.ts @@ -0,0 +1,45 @@ +import options from "options"; +import { ButtonProps } from "types/widgets/button"; + +type PanelButtonProps = ButtonProps & { + window?: string; + flat?: boolean; +}; + +export default ({ + window = "", + flat, + child, + setup, + ...rest +}: PanelButtonProps) => + Widget.Button({ + child: Widget.Box({ child }), + setup: (self) => { + let open = false; + + self.toggleClassName("panel-button"); + self.toggleClassName(window); + + self.hook(options.bar.flatButtons, () => { + self.toggleClassName("flat", flat ?? options.bar.flatButtons.value); + }); + + self.hook(App, (_, win, visible) => { + if (win !== window) return; + + if (open && !visible) { + open = false; + self.toggleClassName("active", false); + } + + if (visible) { + open = true; + self.toggleClassName("active"); + } + }); + + if (setup) setup(self); + }, + ...rest, + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/ScreenCorners.ts b/config/private_dot_config/exact_ags/widget/bar/ScreenCorners.ts new file mode 100644 index 00000000..61e5e303 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/ScreenCorners.ts @@ -0,0 +1,31 @@ +import options from "options"; + +const { corners, transparent } = options.bar; + +export default (monitor: number) => + Widget.Window({ + monitor, + name: `corner${monitor}`, + class_name: "screen-corner", + anchor: ["top", "bottom", "right", "left"], + click_through: true, + child: Widget.Box({ + class_name: "shadow", + child: Widget.Box({ + class_name: "border", + expand: true, + child: Widget.Box({ + class_name: "corner", + expand: true, + }), + }), + }), + setup: (self) => + self + .hook(corners, () => { + self.toggleClassName("corners", corners.value > 0); + }) + .hook(transparent, () => { + self.toggleClassName("hidden", transparent.value); + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/BatteryBar.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/BatteryBar.ts new file mode 100644 index 00000000..5dff3bc6 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/BatteryBar.ts @@ -0,0 +1,103 @@ +import icons from "lib/icons"; +import options from "options"; + +import PanelButton from "../PanelButton"; + +const battery = await Service.import("battery"); +const { bar, percentage, blocks, width, low } = options.bar.battery; + +const Indicator = () => + Widget.Icon({ + setup: (self) => + self.hook(battery, () => { + self.icon = + battery.charging ?? battery.charged + ? icons.battery.charging + : battery.icon_name; + }), + }); + +const PercentLabel = () => + Widget.Revealer({ + transition: "slide_right", + click_through: true, + reveal_child: percentage.bind(), + child: Widget.Label({ + label: battery.bind("percent").as((p) => `${p}%`), + }), + }); + +const LevelBar = () => { + const level = Widget.LevelBar({ + bar_mode: "discrete", + max_value: blocks.bind(), + visible: bar.bind().as((b) => b !== "hidden"), + value: battery.bind("percent").as((p) => (p / 100) * blocks.value), + }); + const update = () => { + level.value = (battery.percent / 100) * blocks.value; + level.css = `block { min-width: ${width.value / blocks.value}pt; }`; + }; + return level + .hook(width, update) + .hook(blocks, update) + .hook(bar, () => { + level.vpack = bar.value === "whole" ? "fill" : "center"; + level.hpack = bar.value === "whole" ? "fill" : "center"; + }); +}; + +const WholeButton = () => + Widget.Overlay({ + vexpand: true, + child: LevelBar(), + class_name: "whole", + pass_through: true, + overlay: Widget.Box({ + hpack: "center", + children: [ + Widget.Icon({ + icon: icons.battery.charging, + visible: Utils.merge( + [battery.bind("charging"), battery.bind("charged")], + (ing, ed) => ing ?? ed + ), + }), + Widget.Box({ + hpack: "center", + vpack: "center", + child: PercentLabel(), + }), + ], + }), + }); + +const Regular = () => + Widget.Box({ + class_name: "regular", + children: [Indicator(), PercentLabel(), LevelBar()], + }); + +export default () => + PanelButton({ + class_name: "battery-bar", + hexpand: false, + on_clicked: () => { + percentage.value = !percentage.value; + }, + visible: battery.bind("available"), + child: Widget.Box({ + expand: true, + visible: battery.bind("available"), + child: bar.bind().as((b) => (b === "whole" ? WholeButton() : Regular())), + }), + setup: (self) => + self + .hook(bar, (w) => + w.toggleClassName("bar-hidden", bar.value === "hidden") + ) + .hook(battery, (w) => { + w.toggleClassName("charging", battery.charging ?? battery.charged); + w.toggleClassName("low", battery.percent < low.value); + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/ColorPicker.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/ColorPicker.ts new file mode 100644 index 00000000..f0634048 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/ColorPicker.ts @@ -0,0 +1,41 @@ +import Gdk from "gi://Gdk"; +import colorpicker from "service/colorpicker"; + +import PanelButton from "../PanelButton"; + +const css = (color: string) => ` +* { + background-color: ${color}; + color: transparent; +} +*:hover { + color: white; + text-shadow: 2px 2px 3px rgba(0,0,0,.8); +}`; + +export default () => { + const menu = Widget.Menu({ + class_name: "colorpicker", + children: colorpicker.bind("colors").as((c) => + c.map((color) => + Widget.MenuItem({ + child: Widget.Label(color), + css: css(color), + on_activate: () => colorpicker.wlCopy(color), + }) + ) + ), + }); + + return PanelButton({ + class_name: "color-picker", + child: Widget.Icon("color-select-symbolic"), + tooltip_text: colorpicker.bind("colors").as((v) => `${v.length} colors`), + on_clicked: colorpicker.pick, + on_secondary_click: (self) => { + if (colorpicker.colors.length === 0) return; + + menu.popup_at_widget(self, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null); + }, + }); +}; diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/Date.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/Date.ts new file mode 100644 index 00000000..89d97eb4 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/Date.ts @@ -0,0 +1,17 @@ +import { clock } from "lib/variables"; +import options from "options"; + +import PanelButton from "../PanelButton"; + +const { format, action } = options.bar.date; +const time = Utils.derive([clock, format], (c, f) => c.format(f) ?? ""); + +export default () => + PanelButton({ + window: "datemenu", + on_clicked: action.bind(), + child: Widget.Label({ + justification: "center", + label: time.bind(), + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/Hyprshade.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/Hyprshade.ts new file mode 100644 index 00000000..39c0ccc3 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/Hyprshade.ts @@ -0,0 +1,17 @@ +import hyprshade from "service/hyprshade"; + +import PanelButton from "../PanelButton"; + +export default () => { + return PanelButton({ + class_name: "hyprshade", + child: Widget.Icon({ + icon_name: hyprshade.bind("shader").as(() => { + return hyprshade.isNight + ? "night-light-symbolic" + : "night-light-disabled-symbolic"; + }), + }), + on_clicked: () => hyprshade.toggle(), + }); +}; diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/Launcher.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/Launcher.ts new file mode 100644 index 00000000..a6ceea31 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/Launcher.ts @@ -0,0 +1,40 @@ +import options from "options"; + +import PanelButton from "../PanelButton"; + +const { icon, label, action } = options.bar.launcher; + +function Spinner() { + const child = Widget.Icon({ + icon: icon.icon.bind(), + class_name: Utils.merge( + [icon.colored.bind()], + (c) => `${c ? "colored" : ""}` + ), + css: ` + @keyframes spin { + to { -gtk-icon-transform: rotate(1turn); } + } + `, + }); + + return Widget.Revealer({ + transition: "slide_left", + child, + reveal_child: Utils.merge([icon.icon.bind()], (i) => Boolean(i)), + }); +} + +export default () => + PanelButton({ + window: "launcher", + on_clicked: action.bind(), + child: Widget.Box([ + Spinner(), + Widget.Label({ + class_name: label.colored.bind().as((c) => (c ? "colored" : "")), + visible: label.label.bind().as((v) => !!v), + label: label.label.bind(), + }), + ]), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/Media.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/Media.ts new file mode 100644 index 00000000..f12b7b67 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/Media.ts @@ -0,0 +1,107 @@ +import icons from "lib/icons"; +import { icon } from "lib/utils"; +import options from "options"; +import { type MprisPlayer } from "types/service/mpris"; + +import PanelButton from "../PanelButton"; + +const mpris = await Service.import("mpris"); +const { length, direction, preferred, monochrome, format } = options.bar.media; + +const getPlayer = (name = preferred.value) => + mpris.getPlayer(name) ?? mpris.players[0] ?? null; + +const Content = (player: MprisPlayer) => { + const revealer = Widget.Revealer({ + click_through: true, + visible: length.bind().as((l) => l > 0), + transition: direction.bind().as((d) => `slide_${d}` as const), + setup: (self) => { + let current = ""; + self.hook(player, () => { + if (current === player.track_title) return; + + current = player.track_title; + self.reveal_child = true; + Utils.timeout(3000, () => { + !self.is_destroyed && (self.reveal_child = false); + }); + }); + }, + child: Widget.Label({ + truncate: "end", + max_width_chars: length.bind().as((n) => (n > 0 ? n : -1)), + label: Utils.merge( + [ + player.bind("track_title"), + player.bind("track_artists"), + format.bind(), + ], + () => + `${format}` + .replace("{title}", player.track_title) + .replace("{artists}", player.track_artists.join(", ")) + .replace("{artist}", player.track_artists[0] ?? "") + .replace("{album}", player.track_album) + .replace("{name}", player.name) + .replace("{identity}", player.identity) + ), + }), + }); + + const playericon = Widget.Icon({ + icon: Utils.merge([player.bind("entry"), monochrome.bind()], (entry) => { + const name = `${entry}${monochrome.value ? "-symbolic" : ""}`; + return icon(name, icons.fallback.audio); + }), + }); + + return Widget.Box({ + attribute: { revealer }, + children: direction + .bind() + .as((d) => + d === "right" ? [playericon, revealer] : [revealer, playericon] + ), + }); +}; + +export default () => { + let player = getPlayer(); + + const btn = PanelButton({ + class_name: "media", + child: Widget.Icon(icons.fallback.audio), + }); + + const update = () => { + player = getPlayer(); + btn.visible = !!player; + + if (!player) return; + + const content = Content(player); + const { revealer } = content.attribute; + btn.child = content; + btn.on_primary_click = () => { + player.playPause(); + }; + btn.on_secondary_click = () => { + player.playPause(); + }; + btn.on_scroll_up = () => { + player.next(); + }; + btn.on_scroll_down = () => { + player.previous(); + }; + btn.on_hover = () => { + revealer.reveal_child = true; + }; + btn.on_hover_lost = () => { + revealer.reveal_child = false; + }; + }; + + return btn.hook(preferred, update).hook(mpris, update, "notify::players"); +}; diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/Messages.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/Messages.ts new file mode 100644 index 00000000..0864fc49 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/Messages.ts @@ -0,0 +1,16 @@ +import icons from "lib/icons"; +import options from "options"; + +import PanelButton from "../PanelButton"; + +const n = await Service.import("notifications"); +const notifs = n.bind("notifications"); +const action = options.bar.messages.action.bind(); + +export default () => + PanelButton({ + class_name: "messages", + on_clicked: action, + visible: notifs.as((n) => n.length > 0), + child: Widget.Box([Widget.Icon(icons.notifications.message)]), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/PowerMenu.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/PowerMenu.ts new file mode 100644 index 00000000..232376d3 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/PowerMenu.ts @@ -0,0 +1,18 @@ +import icons from "lib/icons"; +import options from "options"; + +import PanelButton from "../PanelButton"; + +const { monochrome, action } = options.bar.powermenu; + +export default () => + PanelButton({ + window: "powermenu", + on_clicked: action.bind(), + child: Widget.Icon(icons.powermenu.shutdown), + setup: (self) => + self.hook(monochrome, () => { + self.toggleClassName("colored", !monochrome.value); + self.toggleClassName("box"); + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/ScreenRecord.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/ScreenRecord.ts new file mode 100644 index 00000000..2035bbf7 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/ScreenRecord.ts @@ -0,0 +1,23 @@ +import icons from "lib/icons"; +import screenrecord from "service/screenrecord"; + +import PanelButton from "../PanelButton"; + +export default () => + PanelButton({ + class_name: "recorder", + on_clicked: () => screenrecord.stop(), + visible: screenrecord.bind("recording"), + child: Widget.Box({ + children: [ + Widget.Icon(icons.recorder.recording), + Widget.Label({ + label: screenrecord.bind("timer").as((time) => { + const sec = time % 60; + const min = Math.floor(time / 60); + return `${min}:${sec < 10 ? "0" + sec : sec}`; + }), + }), + ], + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/SysTray.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/SysTray.ts new file mode 100644 index 00000000..30bc4a7b --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/SysTray.ts @@ -0,0 +1,50 @@ +import Gdk from "gi://Gdk"; +import options from "options"; +import { type TrayItem } from "types/service/systemtray"; + +import PanelButton from "../PanelButton"; + +const systemtray = await Service.import("systemtray"); +const { ignore } = options.bar.systray; + +const SysTrayItem = (item: TrayItem) => + PanelButton({ + class_name: "tray-item", + child: Widget.Icon({ icon: item.bind("icon") }), + tooltip_markup: item.bind("tooltip_markup"), + setup: (self) => { + const { menu } = item; + if (!menu) return; + + const id = menu.connect("popped-up", () => { + self.toggleClassName("active"); + menu.connect("notify::visible", () => { + self.toggleClassName("active", menu.visible); + }); + menu.disconnect(id!); + }); + + self.connect("destroy", () => menu.disconnect(id)); + }, + + on_primary_click: (btn) => + item.menu?.popup_at_widget( + btn, + Gdk.Gravity.SOUTH, + Gdk.Gravity.NORTH, + null + ), + + on_secondary_click: (btn) => + item.menu?.popup_at_widget( + btn, + Gdk.Gravity.SOUTH, + Gdk.Gravity.NORTH, + null + ), + }); + +export default () => + Widget.Box().bind("children", systemtray, "items", (i) => + i.filter(({ id }) => !ignore.value.includes(id)).map(SysTrayItem) + ); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/SystemIndicators.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/SystemIndicators.ts new file mode 100644 index 00000000..8c879b5f --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/SystemIndicators.ts @@ -0,0 +1,117 @@ +import icons from "lib/icons"; +import asusctl from "service/asusctl"; + +import PanelButton from "../PanelButton"; + +const notifications = await Service.import("notifications"); +const bluetooth = await Service.import("bluetooth"); +const audio = await Service.import("audio"); +const network = await Service.import("network"); +const powerprof = await Service.import("powerprofiles"); + +const ProfileIndicator = () => { + const visible = asusctl.available + ? asusctl.bind("profile").as((p) => p !== "Balanced") + : powerprof.bind("active_profile").as((p) => p !== "balanced"); + + const icon = asusctl.available + ? asusctl.bind("profile").as((p) => icons.asusctl.profile[p]) + : powerprof.bind("active_profile").as((p) => icons.powerprofile[p]); + + return Widget.Icon({ visible, icon }); +}; + +const ModeIndicator = () => { + if (!asusctl.available) { + return Widget.Icon({ + setup(self) { + Utils.idle(() => (self.visible = false)); + }, + }); + } + + return Widget.Icon({ + visible: asusctl.bind("mode").as((m) => m !== "Hybrid"), + icon: asusctl.bind("mode").as((m) => icons.asusctl.mode[m]), + }); +}; + +const MicrophoneIndicator = () => + Widget.Icon() + .hook( + audio, + (self) => + (self.visible = + audio.recorders.length > 0 ?? audio.microphone.is_muted ?? false) + ) + .hook(audio.microphone, (self) => { + const vol = audio.microphone.is_muted ? 0 : audio.microphone.volume; + const { muted, low, medium, high } = icons.audio.mic; + const cons = [ + [67, high], + [34, medium], + [1, low], + [0, muted], + ] as const; + self.icon = cons.find(([n]) => n <= vol * 100)?.[1] ?? ""; + }); + +const DNDIndicator = () => + Widget.Icon({ + visible: notifications.bind("dnd"), + icon: icons.notifications.silent, + }); + +const BluetoothIndicator = () => + Widget.Overlay({ + class_name: "bluetooth", + passThrough: true, + visible: bluetooth.bind("enabled"), + child: Widget.Icon({ + icon: icons.bluetooth.enabled, + }), + overlay: Widget.Label({ + hpack: "end", + vpack: "start", + label: bluetooth.bind("connected_devices").as((c) => `${c.length}`), + visible: bluetooth.bind("connected_devices").as((c) => c.length > 0), + }), + }); + +const NetworkIndicator = () => + Widget.Icon().hook(network, (self) => { + const icon = network[network.primary ?? "wifi"]?.icon_name; + self.icon = icon ?? ""; + self.visible = !!icon; + }); + +const AudioIndicator = () => + Widget.Icon().hook(audio.speaker, (self) => { + const vol = audio.speaker.is_muted ? 0 : audio.speaker.volume; + const { muted, low, medium, high, overamplified } = icons.audio.volume; + const cons = [ + [101, overamplified], + [67, high], + [34, medium], + [1, low], + [0, muted], + ] as const; + self.icon = cons.find(([n]) => n <= vol * 100)?.[1] ?? ""; + }); + +export default () => + PanelButton({ + window: "quicksettings", + on_clicked: () => App.toggleWindow("quicksettings"), + on_scroll_up: () => (audio.speaker.volume += 0.02), + on_scroll_down: () => (audio.speaker.volume -= 0.02), + child: Widget.Box([ + ProfileIndicator(), + ModeIndicator(), + DNDIndicator(), + BluetoothIndicator(), + NetworkIndicator(), + AudioIndicator(), + MicrophoneIndicator(), + ]), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/SystemInfo.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/SystemInfo.ts new file mode 100644 index 00000000..2909dec0 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/SystemInfo.ts @@ -0,0 +1,17 @@ +import { icon } from "lib/utils"; +import { df } from "lib/variables"; + +import PanelButton from "../PanelButton"; + +export default () => { + return PanelButton({ + class_name: "system-info", + visible: df.bind().as((c) => c > 80), + child: Widget.Box([ + Widget.Icon({ icon: icon("drive-harddisk") }), + Widget.Label({ + label: df.bind().as((c) => Math.round(c) + "%"), + }), + ]), + }); +}; diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/Taskbar.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/Taskbar.ts new file mode 100644 index 00000000..03243e32 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/Taskbar.ts @@ -0,0 +1,128 @@ +import icons from "lib/icons"; +import { findApp, icon, launchApp } from "lib/utils"; +import options from "options"; + +import PanelButton from "../PanelButton"; + +const hyprland = await Service.import("hyprland"); +const { monochrome, exclusive, iconSize } = options.bar.taskbar; +const { position } = options.bar; + +const focus = (address: string) => + hyprland.messageAsync(`dispatch focuswindow address:${address}`); + +const DummyItem = (address: string) => + Widget.Box({ + attribute: { address }, + visible: false, + }); + +const AppItem = (address: string) => { + const client = hyprland.getClient(address); + if (!client ?? client.class === "") return DummyItem(address); + + const app = findApp(client.class); + + const title = Utils.watch( + client.title, + hyprland, + () => hyprland.getClient(address)?.title ?? "" + ); + + const ico = Utils.merge([title, monochrome.bind()], (title, monochrome) => { + let icon_name = app?.icon_name ?? client.class; + let icon_fallback = icons.fallback.executable; + + if (app?.name === "WezTerm") { + const cmd = title.split(" ")[1]; + if (cmd) { + icon_fallback = icon_name; + icon_name = cmd; + } + } + + return icon( + icon_name + (monochrome ? "-symbolic" : ""), + icon_fallback + (monochrome ? "-symbolic" : "") + ); + }); + + const btn = PanelButton({ + class_name: "panel-button", + tooltip_text: title, + on_primary_click: () => focus(address), + on_middle_click: () => app && launchApp(app), + child: Widget.Icon({ + size: iconSize.bind(), + icon: ico, + }), + }); + + return Widget.Box( + { + attribute: { address }, + visible: Utils.watch(true, [exclusive, hyprland], () => { + return exclusive.value + ? hyprland.active.workspace.id === client.workspace.id + : true; + }), + }, + Widget.Overlay({ + child: btn, + pass_through: true, + overlay: Widget.Box({ + className: "indicator", + hpack: "center", + vpack: position.bind().as((p) => (p === "top" ? "start" : "end")), + setup: (w) => + w.hook(hyprland, () => { + w.toggleClassName( + "active", + hyprland.active.client.address === address + ); + }), + }), + }) + ); +}; + +function sortItems(arr: T[]) { + return arr.sort(({ attribute: a }, { attribute: b }) => { + const aclient = hyprland.getClient(a.address)!; + const bclient = hyprland.getClient(b.address)!; + return aclient.workspace.id - bclient.workspace.id; + }); +} + +export default () => + Widget.Box({ + class_name: "taskbar", + children: sortItems(hyprland.clients.map((c) => AppItem(c.address))), + setup: (w) => + w + .hook( + hyprland, + (w, address?: string) => { + if (typeof address === "string") + w.children = w.children.filter( + (ch) => ch.attribute.address !== address + ); + }, + "client-removed" + ) + .hook( + hyprland, + (w, address?: string) => { + if (typeof address === "string") + w.children = sortItems([...w.children, AppItem(address)]); + }, + "client-added" + ) + .hook( + hyprland, + (w, event?: string) => { + if (event === "movewindow") w.children = sortItems(w.children); + }, + "event" + ), + }); diff --git a/config/private_dot_config/exact_ags/widget/bar/buttons/Workspaces.ts b/config/private_dot_config/exact_ags/widget/bar/buttons/Workspaces.ts new file mode 100644 index 00000000..18107b81 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/bar/buttons/Workspaces.ts @@ -0,0 +1,51 @@ +import { range, sh } from "lib/utils"; +import options from "options"; + +import PanelButton from "../PanelButton"; + +const hyprland = await Service.import("hyprland"); +const { workspaces } = options.bar.workspaces; + +const dispatch = (arg: string | number) => { + sh(`hyprctl dispatch workspace ${arg}`); +}; + +const Workspaces = (ws: number) => + Widget.Box({ + children: range(ws ?? 20).map((i) => + Widget.Label({ + attribute: i, + vpack: "center", + label: `${i}`, + setup: (self) => + self.hook(hyprland, () => { + self.toggleClassName("active", hyprland.active.workspace.id === i); + self.toggleClassName( + "occupied", + (hyprland.getWorkspace(i)?.windows ?? 0) > 0 + ); + }), + }) + ), + setup: (box) => { + if (ws === 0) { + box.hook(hyprland.active.workspace, () => + box.children.map((btn) => { + btn.visible = hyprland.workspaces.some( + (ws) => ws.id === btn.attribute + ); + }) + ); + } + }, + }); + +export default () => + PanelButton({ + window: "overview", + class_name: "workspaces", + on_scroll_up: () => dispatch("m+1"), + on_scroll_down: () => dispatch("m-1"), + on_clicked: () => App.toggleWindow("overview"), + child: workspaces.bind().as(Workspaces), + }); diff --git a/config/private_dot_config/exact_ags/widget/datemenu/DateColumn.ts b/config/private_dot_config/exact_ags/widget/datemenu/DateColumn.ts new file mode 100644 index 00000000..29b3ab18 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/datemenu/DateColumn.ts @@ -0,0 +1,38 @@ +import { clock, uptime } from "lib/variables"; + +function up(up: number) { + const h = Math.floor(up / 60); + const m = Math.floor(up % 60); + return `uptime: ${h}:${m < 10 ? "0" + m : m}`; +} + +export default () => + Widget.Box({ + vertical: true, + class_name: "date-column vertical", + children: [ + Widget.Box({ + class_name: "clock-box", + vertical: true, + children: [ + Widget.Label({ + class_name: "clock", + label: clock.bind().as((t) => t.format("%H:%M")!), + }), + Widget.Label({ + class_name: "uptime", + label: uptime.bind().as(up), + }), + ], + }), + Widget.Box({ + class_name: "calendar", + children: [ + Widget.Calendar({ + hexpand: true, + hpack: "center", + }), + ], + }), + ], + }); diff --git a/config/private_dot_config/exact_ags/widget/datemenu/DateMenu.ts b/config/private_dot_config/exact_ags/widget/datemenu/DateMenu.ts new file mode 100644 index 00000000..86b1dc49 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/datemenu/DateMenu.ts @@ -0,0 +1,40 @@ +import options from "options"; +import PopupWindow from "widget/PopupWindow"; + +import DateColumn from "./DateColumn"; +import NotificationColumn from "./NotificationColumn"; + +const { bar, datemenu } = options; +const pos = bar.position.bind(); +const layout = Utils.derive( + [bar.position, datemenu.position], + (bar, qs) => `${bar}-${qs}` as const +); + +const Settings = () => + Widget.Box({ + class_name: "datemenu horizontal", + vexpand: false, + children: [ + NotificationColumn(), + Widget.Separator({ orientation: 1 }), + DateColumn(), + ], + }); + +const DateMenu = () => + PopupWindow({ + name: "datemenu", + exclusivity: "exclusive", + transition: pos.as((pos) => (pos === "top" ? "slide_down" : "slide_up")), + layout: layout.value, + child: Settings(), + }); + +export function setupDateMenu() { + App.addWindow(DateMenu()); + layout.connect("changed", () => { + App.removeWindow("datemenu"); + App.addWindow(DateMenu()); + }); +} diff --git a/config/private_dot_config/exact_ags/widget/datemenu/NotificationColumn.ts b/config/private_dot_config/exact_ags/widget/datemenu/NotificationColumn.ts new file mode 100644 index 00000000..8feb9626 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/datemenu/NotificationColumn.ts @@ -0,0 +1,116 @@ +import icons from "lib/icons"; +import options from "options"; +import { type Notification as Notif } from "types/service/notifications"; +import Notification from "widget/notifications/Notification"; + +const notifications = await Service.import("notifications"); +const notifs = notifications.bind("notifications"); + +const Animated = (n: Notif) => + Widget.Revealer({ + transition_duration: options.transition.value, + transition: "slide_down", + child: Notification(n), + setup: (self) => + Utils.timeout(options.transition.value, () => { + if (!self.is_destroyed) self.reveal_child = true; + }), + }); + +const ClearButton = () => + Widget.Button({ + on_clicked: notifications.clear, + sensitive: notifs.as((n) => n.length > 0), + child: Widget.Box({ + children: [ + Widget.Label("Clear "), + Widget.Icon({ + icon: notifs.as((n) => icons.trash[n.length > 0 ? "full" : "empty"]), + }), + ], + }), + }); + +const Header = () => + Widget.Box({ + class_name: "header", + children: [ + Widget.Label({ label: "Notifications", hexpand: true, xalign: 0 }), + ClearButton(), + ], + }); + +const NotificationList = () => { + const map: Map> = new Map(); + const box = Widget.Box({ + vertical: true, + children: notifications.notifications.map((n) => { + const w = Animated(n); + map.set(n.id, w); + return w; + }), + visible: notifs.as((n) => n.length > 0), + }); + + function remove(_: unknown, id: number) { + const n = map.get(id); + if (n) { + n.reveal_child = false; + Utils.timeout(options.transition.value, () => { + n.destroy(); + map.delete(id); + }); + } + } + + return box.hook(notifications, remove, "closed").hook( + notifications, + (_, id: number) => { + if (id !== undefined) { + if (map.has(id)) remove(null, id); + + const n = notifications.getNotification(id)!; + + const w = Animated(n); + map.set(id, w); + box.children = [w, ...box.children]; + } + }, + "notified" + ); +}; + +const Placeholder = () => + Widget.Box({ + class_name: "placeholder", + vertical: true, + vpack: "center", + hpack: "center", + vexpand: true, + hexpand: true, + visible: notifs.as((n) => n.length === 0), + children: [ + Widget.Icon(icons.notifications.silent), + Widget.Label("Your inbox is empty"), + ], + }); + +export default () => + Widget.Box({ + class_name: "notifications", + css: options.notifications.width.bind().as((w) => `min-width: ${w}px`), + vertical: true, + children: [ + Header(), + Widget.Scrollable({ + vexpand: true, + hscroll: "never", + class_name: "notification-scrollable", + child: Widget.Box({ + class_name: "notification-list vertical", + vertical: true, + children: [NotificationList(), Placeholder()], + }), + }), + ], + }); diff --git a/config/private_dot_config/exact_ags/widget/launcher/AppLauncher.ts b/config/private_dot_config/exact_ags/widget/launcher/AppLauncher.ts new file mode 100644 index 00000000..1f28c139 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/launcher/AppLauncher.ts @@ -0,0 +1,132 @@ +import icons from "lib/icons"; +import { icon, launchApp } from "lib/utils"; +import options from "options"; +import { type Application } from "types/service/applications"; + +const apps = await Service.import("applications"); +const { query } = apps; +const { iconSize } = options.launcher.apps; + +const QuickAppButton = (app: Application) => + Widget.Button({ + hexpand: true, + tooltip_text: app.name, + on_clicked: () => { + App.closeWindow("launcher"); + launchApp(app); + }, + child: Widget.Icon({ + size: iconSize.bind(), + icon: icon(app.icon_name, icons.fallback.executable), + }), + }); + +const AppItem = (app: Application) => { + const title = Widget.Label({ + class_name: "title", + label: app.name, + hexpand: true, + xalign: 0, + vpack: "center", + truncate: "end", + }); + + const description = Widget.Label({ + class_name: "description", + label: app.description ?? "", + hexpand: true, + wrap: true, + max_width_chars: 30, + xalign: 0, + justification: "left", + vpack: "center", + }); + + const appicon = Widget.Icon({ + icon: icon(app.icon_name, icons.fallback.executable), + size: iconSize.bind(), + }); + + const textBox = Widget.Box({ + vertical: true, + vpack: "center", + children: app.description ? [title, description] : [title], + }); + + return Widget.Button({ + class_name: "app-item", + attribute: { app }, + child: Widget.Box({ + children: [appicon, textBox], + }), + on_clicked: () => { + App.closeWindow("launcher"); + launchApp(app); + }, + }); +}; +export function Favorites() { + const favs = options.launcher.apps.favorites.bind(); + return Widget.Revealer({ + visible: favs.as((f) => f.length > 0), + child: Widget.Box({ + vertical: true, + children: favs.as((favs) => + favs.flatMap((fs) => [ + Widget.Separator(), + Widget.Box({ + class_name: "quicklaunch horizontal", + children: fs + .map((f) => query(f)?.[0]) + .filter((f) => f) + .map(QuickAppButton), + }), + ]) + ), + }), + }); +} + +export function Launcher() { + const applist = Variable(query("")); + const max = options.launcher.apps.max; + let first = applist.value[0]; + + function SeparatedAppItem(app: Application) { + return Widget.Revealer( + { attribute: { app } }, + Widget.Box({ vertical: true }, Widget.Separator(), AppItem(app)) + ); + } + + const list = Widget.Box({ + vertical: true, + children: applist.bind().as((list) => list.map(SeparatedAppItem)), + setup: (self) => + self.hook(apps, () => (applist.value = query("")), "notify::frequents"), + }); + + return Object.assign(list, { + clear() { + list.children.forEach((item) => (item.reveal_child = false)); + }, + filter(text: string | null) { + first = query(text ?? "")[0]; + list.children.reduce((i, item) => { + if (!text ?? i >= max.value) { + item.reveal_child = false; + return i; + } + if (item.attribute.app.match(text)) { + item.reveal_child = true; + return ++i; + } + item.reveal_child = false; + return i; + }, 0); + }, + launchFirst() { + launchApp(first); + }, + }); +} diff --git a/config/private_dot_config/exact_ags/widget/launcher/Cliphist.ts b/config/private_dot_config/exact_ags/widget/launcher/Cliphist.ts new file mode 100644 index 00000000..d898df37 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/launcher/Cliphist.ts @@ -0,0 +1,85 @@ +import cliphist from "service/cliphist"; + +import type Gtk from "gi://Gtk?version=3.0"; +import type { CliphistItem } from "service/cliphist"; + +const iconVisible = Variable(false); + +async function Item(item: CliphistItem) { + const child: Gtk.Widget = item.contentType.match(/(png|jpg|jpeg|bmp|webp)/) + ? Widget.Icon({ + class_name: "cliphist-image", + icon: await cliphist.getFile(item), + size: 80, + hpack: "start", + // css: `background-image: url('file://${cliphist.getFile(item)}');`, + }) + : Widget.Label({ + label: item.content, + hpack: "start", + truncate: "end", + maxWidthChars: 53, + }); + return Widget.Box( + { + attribute: { item: item }, + vertical: true, + }, + Widget.Separator(), + Widget.Button({ + child, + class_name: "cliphist-item", + on_clicked: () => { + cliphist.run(item); + App.closeWindow("launcher"); + }, + }) + ); +} + +export function Icon() { + const icon = Widget.Icon({ + icon: "edit-copy-symbolic", + class_name: "spinner", + }); + + return Widget.Revealer({ + transition: "slide_left", + child: icon, + reveal_child: iconVisible.bind(), + }); +} + +export function Cliphist() { + const list = Widget.Box>>({ + vertical: true, + }); + + const revealer = Widget.Revealer({ + child: list, + }); + + async function filter(term: string) { + term = term.trim(); + iconVisible.value = true; + const found = await cliphist.query(term); + print(`found: ${found.length} for "${term}"`); + list.children = await Promise.all(found.map(Item)); + revealer.reveal_child = true; + } + function clear() { + iconVisible.value = false; + list.children = []; + revealer.reveal_child = false; + } + + return Object.assign(revealer, { + filter, + clear, + run: cliphist.run, + runFirst: () => { + const first = list.children[0]; + if (first) cliphist.run(first.attribute.item); + }, + }); +} diff --git a/config/private_dot_config/exact_ags/widget/launcher/Launcher.ts b/config/private_dot_config/exact_ags/widget/launcher/Launcher.ts new file mode 100644 index 00000000..9ca79b96 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/launcher/Launcher.ts @@ -0,0 +1,144 @@ +import icons from "lib/icons"; +import { type Binding } from "lib/utils"; +import options from "options"; +import PopupWindow, { Padding } from "widget/PopupWindow"; + +import * as AppLauncher from "./AppLauncher"; +import * as Cliphist from "./Cliphist"; +import * as ShRun from "./ShRun"; + +const { width, margin } = options.launcher; + +function Launcher() { + const favs = AppLauncher.Favorites(); + const applauncher = AppLauncher.Launcher(); + const sh = ShRun.ShRun(); + const shicon = ShRun.Icon(); + const ch = Cliphist.Cliphist(); + const chicon = Cliphist.Icon(); + + function HelpButton(cmd: string, desc: string | Binding) { + return Widget.Box( + { vertical: true }, + Widget.Separator(), + Widget.Button( + { + class_name: "help", + on_clicked: () => { + entry.grab_focus(); + entry.text = `:${cmd} `; + entry.set_position(-1); + }, + }, + Widget.Box([ + Widget.Label({ + class_name: "name", + label: `:${cmd}`, + }), + Widget.Label({ + hexpand: true, + hpack: "end", + class_name: "description", + label: desc, + }), + ]) + ) + ); + } + + const help = Widget.Revealer({ + child: Widget.Box( + { vertical: true }, + HelpButton("sh", "run a binary"), + HelpButton("ch", "copy a clipboard history entry") + ), + }); + + const entry = Widget.Entry({ + hexpand: true, + primary_icon_name: icons.ui.search, + on_accept: ({ text }) => { + if (text?.startsWith(":sh")) sh.run(text.substring(3)); + else if (text?.startsWith(":ch")) { + ch.runFirst(); + } else applauncher.launchFirst(); + + App.toggleWindow("launcher"); + entry.text = ""; + }, + on_change: ({ text }) => { + text ??= ""; + favs.reveal_child = text === ""; + help.reveal_child = text.length < 3 && text?.startsWith(":"); + + if (text?.startsWith(":sh")) sh.filter(text.substring(3)); + else sh.filter(""); + + if (text?.startsWith(":ch")) ch.filter(text.substring(3)); + else ch.clear(); + + if (!text?.startsWith(":")) applauncher.filter(text); + else applauncher.clear(); + }, + }); + + function focus() { + entry.text = "Search"; + entry.set_position(-1); + entry.select_region(0, -1); + entry.grab_focus(); + favs.reveal_child = true; + } + + Object.assign(globalThis, { + launcher: { + open: (text?: string) => { + App.openWindow("launcher"); + if (text) { + entry.grab_focus(); + entry.text = text; + entry.set_position(-1); + favs.reveal_child = false; + } + }, + }, + }); + + const layout = Widget.Box({ + css: width.bind().as((v) => `min-width: ${v}pt;`), + class_name: "launcher", + vertical: true, + vpack: "start", + setup: (self) => + self.hook(App, (_, win, visible) => { + if (win !== "launcher") return; + + entry.text = ""; + if (visible) focus(); + }), + children: [ + Widget.Box([entry, shicon, chicon]), + favs, + help, + applauncher, + sh, + ch, + ], + }); + + return Widget.Box( + { vertical: true, css: "padding: 1px" }, + Padding("launcher", { + css: margin.bind().as((v) => `min-height: ${v}pt;`), + vexpand: false, + }), + layout + ); +} + +export default () => + PopupWindow({ + name: "launcher", + layout: "top", + child: Launcher(), + }); diff --git a/config/private_dot_config/exact_ags/widget/launcher/ShRun.ts b/config/private_dot_config/exact_ags/widget/launcher/ShRun.ts new file mode 100644 index 00000000..87b3a999 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/launcher/ShRun.ts @@ -0,0 +1,65 @@ +import icons from "lib/icons"; +import sh from "service/sh"; + +const iconVisible = Variable(false); + +function Item(bin: string) { + return Widget.Box( + { + attribute: { bin }, + vertical: true, + }, + Widget.Separator(), + Widget.Button({ + child: Widget.Label({ + label: bin, + hpack: "start", + }), + class_name: "sh-item", + on_clicked: () => { + Utils.execAsync(bin); + App.closeWindow("launcher"); + }, + }) + ); +} + +export function Icon() { + const icon = Widget.Icon({ + icon: icons.app.terminal, + class_name: "spinner", + }); + + return Widget.Revealer({ + transition: "slide_left", + child: icon, + reveal_child: iconVisible.bind(), + }); +} + +export function ShRun() { + const list = Widget.Box>({ + vertical: true, + }); + + const revealer = Widget.Revealer({ + child: list, + }); + + async function filter(term: string) { + iconVisible.value = Boolean(term); + + if (!term) revealer.reveal_child = false; + + if (term.trim()) { + const found = await sh.query(term); + list.children = found.map(Item); + revealer.reveal_child = true; + } + } + + return Object.assign(revealer, { + filter, + run: sh.run, + }); +} diff --git a/config/private_dot_config/exact_ags/widget/notifications/Notification.ts b/config/private_dot_config/exact_ags/widget/notifications/Notification.ts new file mode 100644 index 00000000..1e6dbdae --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/notifications/Notification.ts @@ -0,0 +1,140 @@ +import GLib from "gi://GLib"; +import icons from "lib/icons"; +import { type Notification } from "types/service/notifications"; + +const time = (time: number, format = "%H:%M") => + GLib.DateTime.new_from_unix_local(time).format(format); + +const NotificationIcon = ({ app_entry, app_icon, image }: Notification) => { + if (image) { + return Widget.Box({ + vpack: "start", + hexpand: false, + class_name: "icon img", + css: ` + background-image: url("${image}"); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + min-width: 78px; + min-height: 78px; + `, + }); + } + + let icon = icons.fallback.notification; + if (Utils.lookUpIcon(app_icon)) icon = app_icon; + + if (Utils.lookUpIcon(app_entry ?? "")) icon = app_entry ?? ""; + + return Widget.Box({ + vpack: "start", + hexpand: false, + class_name: "icon", + css: ` + min-width: 78px; + min-height: 78px; + `, + child: Widget.Icon({ + icon, + size: 58, + hpack: "center", + hexpand: true, + vpack: "center", + vexpand: true, + }), + }); +}; + +export default (notification: Notification) => { + const content = Widget.Box({ + class_name: "content", + children: [ + NotificationIcon(notification), + Widget.Box({ + hexpand: true, + vertical: true, + children: [ + Widget.Box({ + children: [ + Widget.Label({ + class_name: "title", + xalign: 0, + justification: "left", + hexpand: true, + max_width_chars: 24, + truncate: "end", + wrap: true, + label: notification.summary.trim(), + use_markup: true, + }), + Widget.Label({ + class_name: "time", + vpack: "start", + label: time(notification.time), + }), + Widget.Button({ + class_name: "close-button", + vpack: "start", + child: Widget.Icon("window-close-symbolic"), + on_clicked: notification.close, + }), + ], + }), + Widget.Label({ + class_name: "description", + hexpand: true, + use_markup: true, + xalign: 0, + justification: "left", + label: notification.body.trim(), + max_width_chars: 24, + wrap: true, + }), + ], + }), + ], + }); + + const actionsbox = + notification.actions.length > 0 + ? Widget.Revealer({ + transition: "slide_down", + child: Widget.EventBox({ + child: Widget.Box({ + class_name: "actions horizontal", + children: notification.actions.map((action) => + Widget.Button({ + class_name: "action-button", + on_clicked: () => notification.invoke(action.id), + hexpand: true, + child: Widget.Label(action.label), + }) + ), + }), + }), + }) + : null; + + const eventbox = Widget.EventBox({ + vexpand: false, + on_primary_click: notification.dismiss, + on_hover() { + if (actionsbox) actionsbox.reveal_child = true; + }, + on_hover_lost() { + if (actionsbox) actionsbox.reveal_child = true; + + notification.dismiss(); + }, + child: Widget.Box({ + vertical: true, + children: actionsbox ? [content, actionsbox] : [content], + }), + }); + + return Widget.Box({ + class_name: `notification ${notification.urgency}`, + child: eventbox, + }); +}; diff --git a/config/private_dot_config/exact_ags/widget/notifications/NotificationPopups.ts b/config/private_dot_config/exact_ags/widget/notifications/NotificationPopups.ts new file mode 100644 index 00000000..e10577cc --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/notifications/NotificationPopups.ts @@ -0,0 +1,94 @@ +import options from "options"; + +import Notification from "./Notification"; + +const notifications = await Service.import("notifications"); +const { transition } = options; +const { position } = options.notifications; +const { timeout, idle } = Utils; + +function Animated(id: number) { + const n = notifications.getNotification(id)!; + const widget = Notification(n); + + const inner = Widget.Revealer({ + transition: "slide_left", + transition_duration: transition.value, + child: widget, + }); + + const outer = Widget.Revealer({ + transition: "slide_down", + transition_duration: transition.value, + child: inner, + }); + + const box = Widget.Box({ + hpack: "end", + child: outer, + }); + + idle(() => { + outer.reveal_child = true; + timeout(transition.value, () => { + inner.reveal_child = true; + }); + }); + + return Object.assign(box, { + dismiss() { + inner.reveal_child = false; + timeout(transition.value, () => { + outer.reveal_child = false; + timeout(transition.value, () => { + box.destroy(); + }); + }); + }, + }); +} + +function PopupList() { + const map: Map> = new Map(); + const box = Widget.Box({ + hpack: "end", + vertical: true, + css: options.notifications.width.bind().as((w) => `min-width: ${w}px;`), + }); + + function remove(_: unknown, id: number) { + map.get(id)?.dismiss(); + map.delete(id); + } + + return box + .hook( + notifications, + (_, id: number) => { + if (id !== undefined) { + if (map.has(id)) remove(null, id); + + if (notifications.dnd) return; + + const w = Animated(id); + map.set(id, w); + box.children = [w, ...box.children]; + } + }, + "notified" + ) + .hook(notifications, remove, "dismissed") + .hook(notifications, remove, "closed"); +} + +export default (monitor: number) => + Widget.Window({ + monitor, + name: `notifications${monitor}`, + anchor: position.bind(), + class_name: "notifications", + child: Widget.Box({ + css: "padding: 2px;", + child: PopupList(), + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/osd/OSD.ts b/config/private_dot_config/exact_ags/widget/osd/OSD.ts new file mode 100644 index 00000000..e744a438 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/osd/OSD.ts @@ -0,0 +1,120 @@ +import icons from "lib/icons"; +import { icon } from "lib/utils"; +import options from "options"; +import brightness from "service/brightness"; + +import Progress from "./Progress"; + +const audio = await Service.import("audio"); +const { progress, microphone } = options.osd; + +const DELAY = 2500; + +function OnScreenProgress(vertical: boolean) { + const indicator = Widget.Icon({ + size: 42, + vpack: "start", + }); + const progress = Progress({ + vertical, + width: vertical ? 42 : 300, + height: vertical ? 300 : 42, + child: indicator, + }); + + const revealer = Widget.Revealer({ + transition: "slide_left", + child: progress, + }); + + let count = 0; + function show(value: number, icon: string) { + revealer.reveal_child = true; + indicator.icon = icon; + progress.setValue(value); + count++; + Utils.timeout(DELAY, () => { + count--; + + if (count === 0) revealer.reveal_child = false; + }); + } + + return revealer + .hook( + brightness, + () => show(brightness.screen, icons.brightness.screen), + "notify::screen" + ) + .hook( + brightness, + () => show(brightness.kbd, icons.brightness.keyboard), + "notify::kbd" + ) + .hook( + audio.speaker, + () => + show( + audio.speaker.volume, + icon(audio.speaker.icon_name ?? "", icons.audio.type.speaker) + ), + "notify::volume" + ); +} + +function MicrophoneMute() { + const icon = Widget.Icon({ + class_name: "microphone", + }); + + const revealer = Widget.Revealer({ + transition: "slide_up", + child: icon, + }); + + let count = 0; + let mute = audio.microphone.stream?.is_muted ?? false; + + return revealer.hook(audio.microphone, () => + Utils.idle(() => { + if (mute !== audio.microphone.stream?.is_muted) { + mute = audio.microphone.stream!.is_muted; + icon.icon = icons.audio.mic[mute ? "muted" : "high"]; + revealer.reveal_child = true; + count++; + + Utils.timeout(DELAY, () => { + count--; + if (count === 0) revealer.reveal_child = false; + }); + } + }) + ); +} + +export default (monitor: number) => + Widget.Window({ + monitor, + name: `indicator${monitor}`, + class_name: "indicator", + layer: "overlay", + click_through: true, + anchor: ["right", "left", "top", "bottom"], + child: Widget.Box({ + css: "padding: 2px;", + expand: true, + child: Widget.Overlay( + { child: Widget.Box({ expand: true }) }, + Widget.Box({ + hpack: progress.pack.h.bind(), + vpack: progress.pack.v.bind(), + child: progress.vertical.bind().as(OnScreenProgress), + }), + Widget.Box({ + hpack: microphone.pack.h.bind(), + vpack: microphone.pack.v.bind(), + child: MicrophoneMute(), + }) + ), + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/osd/Progress.ts b/config/private_dot_config/exact_ags/widget/osd/Progress.ts new file mode 100644 index 00000000..d5fab839 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/osd/Progress.ts @@ -0,0 +1,75 @@ +import GLib from "gi://GLib?version=2.0"; +import { range } from "lib/utils"; +import options from "options"; + +import type Gtk from "gi://Gtk?version=3.0"; + +type ProgressProps = { + height?: number; + width?: number; + vertical?: boolean; + child: Gtk.Widget; +}; + +export default ({ + height = 18, + width = 180, + vertical = false, + child, +}: ProgressProps) => { + const fill = Widget.Box({ + class_name: "fill", + hexpand: vertical, + vexpand: !vertical, + hpack: vertical ? "fill" : "start", + vpack: vertical ? "end" : "fill", + child, + }); + + const container = Widget.Box({ + class_name: "progress", + child: fill, + css: ` + min-width: ${width}px; + min-height: ${height}px; + `, + }); + + let fill_size = 0; + let animations: number[] = []; + + return Object.assign(container, { + setValue(value: number) { + if (value < 0) return; + + if (animations.length > 0) { + for (const id of animations) GLib.source_remove(id); + + animations = []; + } + + const axis = vertical ? "height" : "width"; + const axisv = vertical ? height : width; + const min = vertical ? width : height; + const preferred = (axisv - min) * value + min; + + if (!fill_size) { + fill_size = preferred; + fill.css = `min-${axis}: ${preferred}px;`; + return; + } + + const frames = options.transition.value / 10; + const goal = preferred - fill_size; + const step = goal / frames; + + animations = range(frames, 0).map((i) => + Utils.timeout(5 * i, () => { + fill_size += step; + fill.css = `min-${axis}: ${fill_size}px`; + animations.shift(); + }) + ); + }, + }); +}; diff --git a/config/private_dot_config/exact_ags/widget/overview/Overview.ts b/config/private_dot_config/exact_ags/widget/overview/Overview.ts new file mode 100644 index 00000000..aad1d925 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/overview/Overview.ts @@ -0,0 +1,52 @@ +import { range } from "lib/utils"; +import options from "options"; +import PopupWindow from "widget/PopupWindow"; + +import Workspace from "./Workspace"; + +const hyprland = await Service.import("hyprland"); + +const Overview = (ws: number) => + Widget.Box({ + class_name: "overview horizontal", + children: + ws > 0 + ? range(ws).map(Workspace) + : hyprland.workspaces + .map(({ id }) => Workspace(id)) + .sort((a, b) => a.attribute.id - b.attribute.id), + + setup: (w) => { + if (ws > 0) return; + + w.hook( + hyprland, + (w, id?: string) => { + if (id === undefined) return; + + w.children = w.children.filter( + (ch) => ch.attribute.id !== Number(id) + ); + }, + "workspace-removed" + ); + w.hook( + hyprland, + (w, id?: string) => { + if (id === undefined) return; + + w.children = [...w.children, Workspace(Number(id))].sort( + (a, b) => a.attribute.id - b.attribute.id + ); + }, + "workspace-added" + ); + }, + }); + +export default () => + PopupWindow({ + name: "overview", + layout: "center", + child: options.overview.workspaces.bind().as(Overview), + }); diff --git a/config/private_dot_config/exact_ags/widget/overview/Window.ts b/config/private_dot_config/exact_ags/widget/overview/Window.ts new file mode 100644 index 00000000..f4ebaa7f --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/overview/Window.ts @@ -0,0 +1,55 @@ +import Gdk from "gi://Gdk"; +import Gtk from "gi://Gtk?version=3.0"; +import icons from "lib/icons"; +import { createSurfaceFromWidget, findApp, icon } from "lib/utils"; +import options from "options"; +import { type Client } from "types/service/hyprland"; + +const monochrome = options.overview.monochromeIcon; +const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)]; +const hyprland = await Service.import("hyprland"); +const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`); + +export default ({ address, size: [w, h], class: c, title }: Client) => + Widget.Button({ + class_name: "client", + attribute: { address }, + tooltip_text: `${title}`, + child: Widget.Icon({ + css: options.overview.scale.bind().as( + (v) => ` + min-width: ${(v / 100) * w}px; + min-height: ${(v / 100) * h}px; + ` + ), + icon: monochrome.bind().as((m) => { + const app = findApp(c); + if (!app) return icons.fallback.executable + (m ? "-symbolic" : ""); + + return icon( + app.icon_name + (m ? "-symbolic" : ""), + icons.fallback.executable + (m ? "-symbolic" : "") + ); + }), + }), + on_secondary_click: () => dispatch(`closewindow address:${address}`), + on_clicked: () => { + dispatch(`focuswindow address:${address}`); + App.closeWindow("overview"); + }, + setup: (btn) => + btn + .on("drag-data-get", (_w, _c, data) => + data.set_text(address, address.length) + ) + .on("drag-begin", (_, context) => { + Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(btn)); + btn.toggleClassName("hidden", true); + }) + .on("drag-end", () => btn.toggleClassName("hidden", false)) + .drag_source_set( + Gdk.ModifierType.BUTTON1_MASK, + TARGET, + Gdk.DragAction.COPY + ), + }); diff --git a/config/private_dot_config/exact_ags/widget/overview/Workspace.ts b/config/private_dot_config/exact_ags/widget/overview/Workspace.ts new file mode 100644 index 00000000..59907776 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/overview/Workspace.ts @@ -0,0 +1,81 @@ +import Gdk from "gi://Gdk"; +import Gtk from "gi://Gtk?version=3.0"; +import options from "options"; + +import Window from "./Window"; + +const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)]; +const scale = (size: number) => (options.overview.scale.value / 100) * size; +const hyprland = await Service.import("hyprland"); + +const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`); + +const size = (id: number) => { + const def = { h: 1080, w: 1920 }; + const ws = hyprland.getWorkspace(id); + if (!ws) return def; + + const mon = hyprland.getMonitor(ws.monitorID); + return mon ? { h: mon.height, w: mon.width } : def; +}; + +export default (id: number) => { + const fixed = Widget.Fixed(); + + // TODO: early return if position is unchaged + async function update() { + const json = await hyprland.messageAsync("j/clients").catch(() => null); + if (!json) return; + + fixed.get_children().forEach((ch) => ch.destroy()); + const clients = JSON.parse(json) as typeof hyprland.clients; + clients + .filter(({ workspace }) => workspace.id === id) + .forEach((c) => { + const x = c.at[0] - (hyprland.getMonitor(c.monitor)?.x ?? 0); + const y = c.at[1] - (hyprland.getMonitor(c.monitor)?.y ?? 0); + c.mapped && fixed.put(Window(c), scale(x), scale(y)); + }); + fixed.show_all(); + } + + return Widget.Box({ + attribute: { id }, + tooltipText: `${id}`, + class_name: "workspace", + vpack: "center", + css: options.overview.scale.bind().as( + (v) => ` + min-width: ${(v / 100) * size(id).w}px; + min-height: ${(v / 100) * size(id).h}px; + ` + ), + setup(box) { + box.hook(options.overview.scale, update); + box.hook(hyprland, update, "notify::clients"); + box.hook(hyprland.active.client, update); + box.hook(hyprland.active.workspace, () => { + box.toggleClassName("active", hyprland.active.workspace.id === id); + }); + }, + child: Widget.EventBox({ + expand: true, + on_primary_click: () => { + App.closeWindow("overview"); + dispatch(`workspace ${id}`); + }, + setup: (eventbox) => { + eventbox.drag_dest_set( + Gtk.DestDefaults.ALL, + TARGET, + Gdk.DragAction.COPY + ); + eventbox.connect("drag-data-received", (_w, _c, _x, _y, data) => { + const address = new TextDecoder().decode(data.get_data()); + dispatch(`movetoworkspacesilent ${id},address:${address}`); + }); + }, + child: fixed, + }), + }); +}; diff --git a/config/private_dot_config/exact_ags/widget/powermenu/PowerMenu.ts b/config/private_dot_config/exact_ags/widget/powermenu/PowerMenu.ts new file mode 100644 index 00000000..9cae6ed2 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/powermenu/PowerMenu.ts @@ -0,0 +1,63 @@ +import icons from "lib/icons"; +import options from "options"; +import powermenu from "service/powermenu"; +import PopupWindow from "widget/PopupWindow"; + +import type Gtk from "gi://Gtk?version=3.0"; +import type { Action } from "service/powermenu"; + +const { layout, labels } = options.powermenu; + +const SysButton = (action: Action, label: string) => + Widget.Button({ + on_clicked: () => powermenu.action(action), + child: Widget.Box({ + vertical: true, + class_name: "system-button", + children: [ + Widget.Icon(icons.powermenu[action]), + Widget.Label({ + label, + visible: labels.bind(), + }), + ], + }), + }); + +export default () => + PopupWindow({ + name: "powermenu", + transition: "crossfade", + child: Widget.Box({ + class_name: "powermenu horizontal", + setup: (self) => + self.hook(layout, () => { + self.toggleClassName("box", layout.value === "box"); + self.toggleClassName("line", layout.value === "line"); + }), + children: layout.bind().as((layout) => { + switch (layout) { + case "line": + return [ + SysButton("shutdown", "Shutdown"), + SysButton("logout", "Log Out"), + SysButton("reboot", "Reboot"), + SysButton("sleep", "Sleep"), + ]; + case "box": + return [ + Widget.Box( + { vertical: true }, + SysButton("shutdown", "Shutdown"), + SysButton("logout", "Log Out") + ), + Widget.Box( + { vertical: true }, + SysButton("reboot", "Reboot"), + SysButton("sleep", "Sleep") + ), + ]; + } + }), + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/powermenu/Verification.ts b/config/private_dot_config/exact_ags/widget/powermenu/Verification.ts new file mode 100644 index 00000000..0ae538c9 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/powermenu/Verification.ts @@ -0,0 +1,48 @@ +import powermenu from "service/powermenu"; +import PopupWindow from "widget/PopupWindow"; + +export default () => + PopupWindow({ + name: "verification", + transition: "crossfade", + child: Widget.Box({ + class_name: "verification", + vertical: true, + children: [ + Widget.Box({ + class_name: "text-box", + vertical: true, + children: [ + Widget.Label({ + class_name: "title", + label: powermenu.bind("title"), + }), + Widget.Label({ + class_name: "desc", + label: "Are you sure?", + }), + ], + }), + Widget.Box({ + class_name: "buttons horizontal", + vexpand: true, + vpack: "end", + homogeneous: true, + children: [ + Widget.Button({ + child: Widget.Label("No"), + on_clicked: () => App.toggleWindow("verification"), + setup: (self) => + self.hook(App, (_, name: string, visible: boolean) => { + if (name === "verification" && visible) self.grab_focus(); + }), + }), + Widget.Button({ + child: Widget.Label("Yes"), + on_clicked: powermenu.exec, + }), + ], + }), + ], + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/QuickSettings.ts b/config/private_dot_config/exact_ags/widget/quicksettings/QuickSettings.ts new file mode 100644 index 00000000..ce52c82b --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/QuickSettings.ts @@ -0,0 +1,86 @@ +import options from "options"; +import PopupWindow from "widget/PopupWindow"; + +import { BluetoothDevices, BluetoothToggle } from "./widgets/Bluetooth"; +import { Brightness } from "./widgets/Brightness"; +import { DarkModeToggle } from "./widgets/DarkMode"; +import { DND } from "./widgets/DND"; +import { Header } from "./widgets/Header"; +import { Media } from "./widgets/Media"; +import { MicMute } from "./widgets/MicMute"; +import { NetworkIndicator, WifiSelection } from "./widgets/Network"; +import { ProfileSelector, ProfileToggle } from "./widgets/PowerProfile"; +import { AppMixer, Microphone, SinkSelector, Volume } from "./widgets/Volume"; + +import type Gtk from "gi://Gtk?version=3.0"; + +const { bar, quicksettings } = options; +const media = (await Service.import("mpris")).bind("players"); +const layout = Utils.derive( + [bar.position, quicksettings.position], + (bar, qs) => `${bar}-${qs}` as const +); + +const Row = ( + toggles: Array<() => Gtk.Widget> = [], + menus: Array<() => Gtk.Widget> = [] +) => + Widget.Box({ + vertical: true, + children: [ + Widget.Box({ + homogeneous: true, + class_name: "row horizontal", + children: toggles.map((w) => w()), + }), + ...menus.map((w) => w()), + ], + }); + +const Settings = () => + Widget.Box({ + vertical: true, + class_name: "quicksettings vertical", + css: quicksettings.width.bind().as((w) => `min-width: ${w}px;`), + children: [ + Header(), + Widget.Box({ + class_name: "sliders-box vertical", + vertical: true, + children: [ + Row([Volume], [SinkSelector, AppMixer]), + Microphone(), + Brightness(), + ], + }), + Row( + [NetworkIndicator, BluetoothToggle], + [WifiSelection, BluetoothDevices] + ), + Row([ProfileToggle, DarkModeToggle], [ProfileSelector]), + Row([MicMute, DND]), + Widget.Box({ + visible: media.as((l) => l.length > 0), + child: Media(), + }), + ], + }); + +const QuickSettings = () => + PopupWindow({ + name: "quicksettings", + exclusivity: "exclusive", + transition: bar.position + .bind() + .as((pos) => (pos === "top" ? "slide_down" : "slide_up")), + layout: layout.value, + child: Settings(), + }); + +export function setupQuickSettings() { + App.addWindow(QuickSettings()); + layout.connect("changed", () => { + App.removeWindow("quicksettings"); + App.addWindow(QuickSettings()); + }); +} diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/ToggleButton.ts b/config/private_dot_config/exact_ags/widget/quicksettings/ToggleButton.ts new file mode 100644 index 00000000..7dbfdcf0 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/ToggleButton.ts @@ -0,0 +1,161 @@ +import icons from "lib/icons"; +import { type IconProps } from "types/widgets/icon"; +import { type LabelProps } from "types/widgets/label"; + +import type GObject from "gi://GObject?version=2.0"; +import type Gtk from "gi://Gtk?version=3.0"; + +export const opened = Variable(""); +App.connect("window-toggled", (_, name: string, visible: boolean) => { + if (name === "quicksettings" && !visible) + Utils.timeout(500, () => (opened.value = "")); +}); + +export const Arrow = (name: string, activate?: false | (() => void)) => { + let deg = 0; + let iconOpened = false; + const icon = Widget.Icon(icons.ui.arrow.right).hook(opened, () => { + if ( + (opened.value === name && !iconOpened) ?? + (opened.value !== name && iconOpened) + ) { + const step = opened.value === name ? 10 : -10; + iconOpened = !iconOpened; + for (let i = 0; i < 9; ++i) { + Utils.timeout(15 * i, () => { + deg += step; + icon.setCss(`-gtk-icon-transform: rotate(${deg}deg);`); + }); + } + } + }); + return Widget.Button({ + child: icon, + class_name: "arrow", + on_clicked: () => { + opened.value = opened.value === name ? "" : name; + if (typeof activate === "function") activate(); + }, + }); +}; + +type ArrowToggleButtonProps = { + name: string; + icon: IconProps["icon"]; + label: LabelProps["label"]; + activate: () => void; + deactivate: () => void; + activateOnArrow?: boolean; + connection: [GObject.Object, () => boolean]; +}; +export const ArrowToggleButton = ({ + name, + icon, + label, + activate, + deactivate, + activateOnArrow = true, + connection: [service, condition], +}: ArrowToggleButtonProps) => + Widget.Box({ + class_name: "toggle-button", + setup: (self) => + self.hook(service, () => { + self.toggleClassName("active", condition()); + }), + children: [ + Widget.Button({ + child: Widget.Box({ + hexpand: true, + children: [ + Widget.Icon({ + class_name: "icon", + icon, + }), + Widget.Label({ + class_name: "label", + max_width_chars: 10, + truncate: "end", + label, + }), + ], + }), + on_clicked: () => { + if (condition()) { + deactivate(); + if (opened.value === name) opened.value = ""; + } else { + activate(); + } + }, + }), + Arrow(name, activateOnArrow && activate), + ], + }); + +type MenuProps = { + name: string; + icon: IconProps["icon"]; + title: LabelProps["label"]; + content: Gtk.Widget[]; +}; +export const Menu = ({ name, icon, title, content }: MenuProps) => + Widget.Revealer({ + transition: "slide_down", + reveal_child: opened.bind().as((v) => v === name), + child: Widget.Box({ + class_names: ["menu", name], + vertical: true, + children: [ + Widget.Box({ + class_name: "title-box", + children: [ + Widget.Icon({ + class_name: "icon", + icon, + }), + Widget.Label({ + class_name: "title", + truncate: "end", + label: title, + }), + ], + }), + Widget.Separator(), + Widget.Box({ + vertical: true, + class_name: "content vertical", + children: content, + }), + ], + }), + }); + +type SimpleToggleButtonProps = { + icon: IconProps["icon"]; + label: LabelProps["label"]; + toggle: () => void; + connection: [GObject.Object, () => boolean]; +}; +export const SimpleToggleButton = ({ + icon, + label, + toggle, + connection: [service, condition], +}: SimpleToggleButtonProps) => + Widget.Button({ + on_clicked: toggle, + class_name: "simple-toggle", + setup: (self) => + self.hook(service, () => { + self.toggleClassName("active", condition()); + }), + child: Widget.Box([ + Widget.Icon({ icon }), + Widget.Label({ + max_width_chars: 10, + truncate: "end", + label, + }), + ]), + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Bluetooth.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Bluetooth.ts new file mode 100644 index 00000000..ba69196f --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Bluetooth.ts @@ -0,0 +1,69 @@ +import icons from "lib/icons"; +import { type BluetoothDevice } from "types/service/bluetooth"; + +import { ArrowToggleButton, Menu } from "../ToggleButton"; + +const bluetooth = await Service.import("bluetooth"); + +export const BluetoothToggle = () => + ArrowToggleButton({ + name: "bluetooth", + icon: bluetooth + .bind("enabled") + .as((p) => icons.bluetooth[p ? "enabled" : "disabled"]), + label: Utils.watch("Disabled", bluetooth, () => { + if (!bluetooth.enabled) return "Disabled"; + + if (bluetooth.connected_devices.length === 0) return "Not Connected"; + + if (bluetooth.connected_devices.length === 1) + return bluetooth.connected_devices[0]!.alias; + + return `${bluetooth.connected_devices.length} Connected`; + }), + connection: [bluetooth, () => bluetooth.enabled], + deactivate: () => (bluetooth.enabled = false), + activate: () => (bluetooth.enabled = true), + }); + +const DeviceItem = (device: BluetoothDevice) => + Widget.Box({ + children: [ + Widget.Icon(device.icon_name + "-symbolic"), + Widget.Label(device.name), + Widget.Label({ + label: `${device.battery_percentage}%`, + visible: device.bind("battery_percentage").as((p) => p > 0), + }), + Widget.Box({ hexpand: true }), + Widget.Spinner({ + active: device.bind("connecting"), + visible: device.bind("connecting"), + }), + Widget.Switch({ + active: device.connected, + visible: device.bind("connecting").as((p) => !p), + setup: (self) => + self.on("notify::active", () => { + device.setConnection(self.active); + }), + }), + ], + }); + +export const BluetoothDevices = () => + Menu({ + name: "bluetooth", + icon: icons.bluetooth.disabled, + title: "Bluetooth", + content: [ + Widget.Box({ + class_name: "bluetooth-devices", + hexpand: true, + vertical: true, + children: bluetooth + .bind("devices") + .as((ds) => ds.filter((d) => d.name).map(DeviceItem)), + }), + ], + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Brightness.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Brightness.ts new file mode 100644 index 00000000..4f715d7a --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Brightness.ts @@ -0,0 +1,26 @@ +import icons from "lib/icons"; +import brightness from "service/brightness"; + +const BrightnessSlider = () => + Widget.Slider({ + draw_value: false, + hexpand: true, + value: brightness.bind("screen"), + on_change: ({ value }) => (brightness.screen = value), + }); + +export const Brightness = () => + Widget.Box({ + class_name: "brightness", + children: [ + Widget.Button({ + vpack: "center", + child: Widget.Icon(icons.brightness.indicator), + on_clicked: () => (brightness.screen = 0), + tooltip_text: brightness + .bind("screen") + .as((v) => `Screen Brightness: ${Math.floor(v * 100)}%`), + }), + BrightnessSlider(), + ], + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/DND.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/DND.ts new file mode 100644 index 00000000..0b97fd6a --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/DND.ts @@ -0,0 +1,14 @@ +import icons from "lib/icons"; + +import { SimpleToggleButton } from "../ToggleButton"; + +const n = await Service.import("notifications"); +const dnd = n.bind("dnd"); + +export const DND = () => + SimpleToggleButton({ + icon: dnd.as((dnd) => icons.notifications[dnd ? "silent" : "noisy"]), + label: dnd.as((dnd) => (dnd ? "Silent" : "Noisy")), + toggle: () => (n.dnd = !n.dnd), + connection: [n, () => n.dnd], + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/DarkMode.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/DarkMode.ts new file mode 100644 index 00000000..9b45b054 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/DarkMode.ts @@ -0,0 +1,14 @@ +import icons from "lib/icons"; +import options from "options"; + +import { SimpleToggleButton } from "../ToggleButton"; + +const { scheme } = options.theme; + +export const DarkModeToggle = () => + SimpleToggleButton({ + icon: scheme.bind().as((s) => icons.color[s]), + label: scheme.bind().as((s) => (s === "dark" ? "Dark" : "Light")), + toggle: () => (scheme.value = scheme.value === "dark" ? "light" : "dark"), + connection: [scheme, () => scheme.value === "dark"], + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Header.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Header.ts new file mode 100644 index 00000000..d23ae98f --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Header.ts @@ -0,0 +1,69 @@ +import icons from "lib/icons"; +import { uptime } from "lib/variables"; +import options from "options"; +import powermenu, { Action } from "service/powermenu"; + +const battery = await Service.import("battery"); +const { image, size } = options.quicksettings.avatar; + +function up(up: number) { + const h = Math.floor(up / 60); + const m = Math.floor(up % 60); + return `${h}h ${m < 10 ? "0" + m : m}m`; +} + +const Avatar = () => + Widget.Box({ + class_name: "avatar", + css: Utils.merge( + [image.bind(), size.bind()], + (img, size) => ` + min-width: ${size}px; + min-height: ${size}px; + background-image: url('${img}'); + background-size: cover; + ` + ), + }); + +const SysButton = (action: Action) => + Widget.Button({ + vpack: "center", + child: Widget.Icon(icons.powermenu[action]), + on_clicked: () => powermenu.action(action), + }); + +export const Header = () => + Widget.Box( + { class_name: "header horizontal" }, + Avatar(), + Widget.Box({ + vertical: true, + vpack: "center", + children: [ + Widget.Box({ + visible: battery.bind("available"), + children: [ + Widget.Icon({ icon: battery.bind("icon_name") }), + Widget.Label({ label: battery.bind("percent").as((p) => `${p}%`) }), + ], + }), + Widget.Box([ + Widget.Icon({ icon: icons.ui.time }), + Widget.Label({ label: uptime.bind().as(up) }), + ]), + ], + }), + Widget.Box({ hexpand: true }), + Widget.Button({ + vpack: "center", + child: Widget.Icon(icons.ui.settings), + on_clicked: () => { + App.closeWindow("quicksettings"); + App.closeWindow("settings-dialog"); + App.openWindow("settings-dialog"); + }, + }), + SysButton("logout"), + SysButton("shutdown") + ); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Media.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Media.ts new file mode 100644 index 00000000..2ad0bca4 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Media.ts @@ -0,0 +1,155 @@ +import icons from "lib/icons"; +import { icon } from "lib/utils"; +import options from "options"; +import { type MprisPlayer } from "types/service/mpris"; + +const mpris = await Service.import("mpris"); +const players = mpris.bind("players"); +const { media } = options.quicksettings; + +function lengthStr(length: number) { + const min = Math.floor(length / 60); + const sec = Math.floor(length % 60); + const sec0 = sec < 10 ? "0" : ""; + return `${min}:${sec0}${sec}`; +} + +const Player = (player: MprisPlayer) => { + const cover = Widget.Box({ + class_name: "cover", + vpack: "start", + css: Utils.merge( + [ + player.bind("cover_path"), + player.bind("track_cover_url"), + media.coverSize.bind(), + ], + (path, url, size) => ` + min-width: ${size}px; + min-height: ${size}px; + background-image: url('${path ?? url}'); + ` + ), + }); + + const title = Widget.Label({ + class_name: "title", + max_width_chars: 20, + truncate: "end", + hpack: "start", + label: player.bind("track_title"), + }); + + const artist = Widget.Label({ + class_name: "artist", + max_width_chars: 20, + truncate: "end", + hpack: "start", + label: player.bind("track_artists").as((a) => a.join(", ")), + }); + + const positionSlider = Widget.Slider({ + class_name: "position", + draw_value: false, + on_change: ({ value }) => (player.position = value * player.length), + setup: (self) => { + const update = () => { + const { length, position } = player; + self.visible = length > 0; + self.value = length > 0 ? position / length : 0; + }; + self.hook(player, update); + self.hook(player, update, "position"); + self.poll(1000, update); + }, + }); + + const positionLabel = Widget.Label({ + class_name: "position", + hpack: "start", + setup: (self) => { + const update = (_: unknown, time?: number) => { + self.label = lengthStr(time ?? player.position); + self.visible = player.length > 0; + }; + self.hook(player, update, "position"); + self.poll(1000, update); + }, + }); + + const lengthLabel = Widget.Label({ + class_name: "length", + hpack: "end", + visible: player.bind("length").as((l) => l > 0), + label: player.bind("length").as(lengthStr), + }); + + const playericon = Widget.Icon({ + class_name: "icon", + hexpand: true, + hpack: "end", + vpack: "start", + tooltip_text: player.identity ?? "", + icon: Utils.merge( + [player.bind("entry"), media.monochromeIcon.bind()], + (e, s) => { + const name = `${e}${s ? "-symbolic" : ""}`; + return icon(name, icons.fallback.audio); + } + ), + }); + + const playPause = Widget.Button({ + class_name: "play-pause", + on_clicked: () => player.playPause(), + visible: player.bind("can_play"), + child: Widget.Icon({ + icon: player.bind("play_back_status").as((s) => { + switch (s) { + case "Playing": + return icons.mpris.playing; + case "Paused": + case "Stopped": + return icons.mpris.stopped; + } + }), + }), + }); + + const prev = Widget.Button({ + on_clicked: () => player.previous(), + visible: player.bind("can_go_prev"), + child: Widget.Icon(icons.mpris.prev), + }); + + const next = Widget.Button({ + on_clicked: () => player.next(), + visible: player.bind("can_go_next"), + child: Widget.Icon(icons.mpris.next), + }); + + return Widget.Box( + { class_name: "player", vexpand: false }, + cover, + Widget.Box( + { vertical: true }, + Widget.Box([title, playericon]), + artist, + Widget.Box({ vexpand: true }), + positionSlider, + Widget.CenterBox({ + class_name: "footer horizontal", + start_widget: positionLabel, + center_widget: Widget.Box([prev, playPause, next]), + end_widget: lengthLabel, + }) + ) + ); +}; + +export const Media = () => + Widget.Box({ + vertical: true, + class_name: "media vertical", + children: players.as((p) => p.map(Player)), + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/MicMute.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/MicMute.ts new file mode 100644 index 00000000..6e1aef51 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/MicMute.ts @@ -0,0 +1,21 @@ +import icons from "lib/icons"; + +import { SimpleToggleButton } from "../ToggleButton"; + +const { microphone } = await Service.import("audio"); + +const icon = () => + microphone.is_muted ?? microphone.stream?.is_muted + ? icons.audio.mic.muted + : icons.audio.mic.high; + +const label = () => + microphone.is_muted ?? microphone.stream?.is_muted ? "Muted" : "Unmuted"; + +export const MicMute = () => + SimpleToggleButton({ + icon: Utils.watch(icon(), microphone, icon), + label: Utils.watch(label(), microphone, label), + toggle: () => (microphone.is_muted = !microphone.is_muted), + connection: [microphone, () => microphone?.is_muted ?? false], + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Network.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Network.ts new file mode 100644 index 00000000..4f7b3ac5 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Network.ts @@ -0,0 +1,102 @@ +import icons from "lib/icons.js"; +import { dependencies, sh } from "lib/utils"; +import options from "options"; + +import { ArrowToggleButton, Menu } from "../ToggleButton"; + +const network = await Service.import("network"); + +export const NetworkIndicator = () => + Widget.Stack({ + children: { + wifi: WifiToggle(), + wired: EthernetIndicator(), + }, + shown: network.bind("primary").as((p) => p ?? "wifi"), + }); + +export const WifiToggle = () => + ArrowToggleButton({ + name: "network", + icon: network.wifi.bind("icon_name"), + label: network.wifi.bind("ssid").as((ssid) => ssid ?? "Not Connected"), + connection: [network.wifi, () => network.wifi.enabled], + deactivate: () => (network.wifi.enabled = false), + activate: () => { + network.wifi.enabled = true; + network.wifi.scan(); + }, + }); + +export const EthernetIndicator = () => + Widget.Button({ + class_name: "simple-toggle", + setup: (self) => + self.hook(network.wired, () => { + self.toggleClassName("active", network.wired.internet === "connected"); + }), + child: Widget.Box([ + Widget.Icon({ icon: network.wired.bind("icon_name") }), + Widget.Label({ + max_width_chars: 10, + truncate: "end", + label: network.wired + .bind("internet") + .as( + (internet) => `${internet[0]!.toUpperCase()}${internet.slice(1)}` + ), + }), + ]), + }); + +export const WifiSelection = () => + Menu({ + name: "network", + icon: network.wifi.bind("icon_name"), + title: "Wifi Selection", + content: [ + Widget.Box({ + vertical: true, + setup: (self) => + self.hook( + network.wifi, + () => + (self.children = network.wifi.access_points + .sort((a, b) => b.strength - a.strength) + .slice(0, 10) + .map((ap) => + Widget.Button({ + on_clicked: () => { + if (dependencies("nmcli")) + Utils.execAsync( + `nmcli device wifi connect ${ap.bssid}` + ); + }, + child: Widget.Box({ + children: [ + Widget.Icon(ap.iconName), + Widget.Label(ap.ssid ?? ""), + Widget.Icon({ + icon: icons.ui.tick, + hexpand: true, + hpack: "end", + setup: (self) => + Utils.idle(() => { + if (!self.is_destroyed) self.visible = ap.active; + }), + }), + ], + }), + }) + )) + ), + }), + Widget.Separator(), + Widget.Button({ + on_clicked: () => sh(options.quicksettings.networkSettings.value), + child: Widget.Box({ + children: [Widget.Icon(icons.ui.settings), Widget.Label("Network")], + }), + }), + ], + }); diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/PowerProfile.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/PowerProfile.ts new file mode 100644 index 00000000..e97d1e5f --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/PowerProfile.ts @@ -0,0 +1,112 @@ +import icons from "lib/icons"; +import asusctl from "service/asusctl"; + +import { ArrowToggleButton, Menu } from "../ToggleButton"; + +const asusprof = asusctl.bind("profile"); + +const AsusProfileToggle = () => + ArrowToggleButton({ + name: "asusctl-profile", + icon: asusprof.as((p) => icons.asusctl.profile[p]), + label: asusprof, + connection: [asusctl, () => asusctl.profile !== "Balanced"], + activate: () => asusctl.setProfile("Quiet"), + deactivate: () => asusctl.setProfile("Balanced"), + activateOnArrow: false, + }); + +const AsusProfileSelector = () => + Menu({ + name: "asusctl-profile", + icon: asusprof.as((p) => icons.asusctl.profile[p]), + title: "Profile Selector", + content: [ + Widget.Box({ + vertical: true, + hexpand: true, + children: [ + Widget.Box({ + vertical: true, + children: asusctl.profiles.map((prof) => + Widget.Button({ + on_clicked: () => asusctl.setProfile(prof), + child: Widget.Box({ + children: [ + Widget.Icon(icons.asusctl.profile[prof]), + Widget.Label(prof), + ], + }), + }) + ), + }), + ], + }), + Widget.Separator(), + Widget.Button({ + on_clicked: () => Utils.execAsync("rog-control-center"), + child: Widget.Box({ + children: [ + Widget.Icon(icons.ui.settings), + Widget.Label("Rog Control Center"), + ], + }), + }), + ], + }); + +const pp = await Service.import("powerprofiles"); +const profile = pp.bind("active_profile"); +const profiles = pp.profiles.map((p) => p.Profile); + +const pretty = (str: string) => + str + .split("-") + .map((str) => `${str.at(0)?.toUpperCase()}${str.slice(1)}`) + .join(" "); + +const PowerProfileToggle = () => + ArrowToggleButton({ + name: "asusctl-profile", + icon: profile.as((p) => icons.powerprofile[p]), + label: profile.as(pretty), + connection: [pp, () => pp.active_profile !== profiles[1]], + activate: () => (pp.active_profile = profiles[0]), + deactivate: () => (pp.active_profile = profiles[1]), + activateOnArrow: false, + }); + +const PowerProfileSelector = () => + Menu({ + name: "asusctl-profile", + icon: profile.as((p) => icons.powerprofile[p]), + title: "Profile Selector", + content: [ + Widget.Box({ + vertical: true, + hexpand: true, + child: Widget.Box({ + vertical: true, + children: profiles.map((prof) => + Widget.Button({ + on_clicked: () => (pp.active_profile = prof), + child: Widget.Box({ + children: [ + Widget.Icon(icons.powerprofile[prof]), + Widget.Label(pretty(prof)), + ], + }), + }) + ), + }), + }), + ], + }); + +export const ProfileToggle = asusctl.available + ? AsusProfileToggle + : PowerProfileToggle; + +export const ProfileSelector = asusctl.available + ? AsusProfileSelector + : PowerProfileSelector; diff --git a/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Volume.ts b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Volume.ts new file mode 100644 index 00000000..43bf0173 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/quicksettings/widgets/Volume.ts @@ -0,0 +1,156 @@ +import icons from "lib/icons.js"; +import { dependencies, icon, sh } from "lib/utils"; +import { type Stream } from "types/service/audio"; + +import { Arrow, Menu } from "../ToggleButton"; + +const audio = await Service.import("audio"); + +type Type = "microphone" | "speaker"; + +const VolumeIndicator = (type: Type = "speaker") => + Widget.Button({ + vpack: "center", + on_clicked: () => (audio[type].is_muted = !audio[type].is_muted), + child: Widget.Icon({ + icon: audio[type] + .bind("icon_name") + .as((i) => icon(i ?? "", icons.audio.mic.high)), + tooltipText: audio[type] + .bind("volume") + .as((vol) => `Volume: ${Math.floor(vol * 100)}%`), + }), + }); + +const VolumeSlider = (type: Type = "speaker") => + Widget.Slider({ + hexpand: true, + draw_value: false, + on_change: ({ value, dragging }) => { + if (dragging) { + audio[type].volume = value; + audio[type].is_muted = false; + } + }, + value: audio[type].bind("volume"), + class_name: audio[type].bind("is_muted").as((m) => (m ? "muted" : "")), + }); + +export const Volume = () => + Widget.Box({ + class_name: "volume", + children: [ + VolumeIndicator("speaker"), + VolumeSlider("speaker"), + Widget.Box({ + vpack: "center", + child: Arrow("sink-selector"), + }), + Widget.Box({ + vpack: "center", + child: Arrow("app-mixer"), + visible: audio.bind("apps").as((a) => a.length > 0), + }), + ], + }); + +export const Microphone = () => + Widget.Box({ + class_name: "slider horizontal", + visible: audio.bind("recorders").as((a) => a.length > 0), + children: [VolumeIndicator("microphone"), VolumeSlider("microphone")], + }); + +const MixerItem = (stream: Stream) => + Widget.Box( + { + hexpand: true, + class_name: "mixer-item horizontal", + }, + Widget.Icon({ + tooltip_text: stream.bind("name").as((n) => n ?? ""), + icon: stream.bind("name").as((n) => { + return Utils.lookUpIcon(n ?? "") ? n ?? "" : icons.fallback.audio; + }), + }), + Widget.Box( + { vertical: true }, + Widget.Label({ + xalign: 0, + truncate: "end", + max_width_chars: 28, + label: stream.bind("description").as((d) => d ?? ""), + }), + Widget.Slider({ + hexpand: true, + draw_value: false, + value: stream.bind("volume"), + on_change: ({ value }) => (stream.volume = value), + }) + ) + ); + +const SinkItem = (stream: Stream) => + Widget.Button({ + hexpand: true, + on_clicked: () => (audio.speaker = stream), + child: Widget.Box({ + children: [ + Widget.Icon({ + icon: icon(stream.icon_name ?? "", icons.fallback.audio), + tooltip_text: stream.icon_name ?? "", + }), + Widget.Label( + (stream.description ?? "").split(" ").slice(0, 4).join(" ") + ), + Widget.Icon({ + icon: icons.ui.tick, + hexpand: true, + hpack: "end", + visible: audio.speaker.bind("stream").as((s) => s === stream.stream), + }), + ], + }), + }); + +const SettingsButton = () => + Widget.Button({ + on_clicked: () => { + if (dependencies("pavucontrol")) sh("pavucontrol"); + }, + hexpand: true, + child: Widget.Box({ + children: [Widget.Icon(icons.ui.settings), Widget.Label("Settings")], + }), + }); + +export const AppMixer = () => + Menu({ + name: "app-mixer", + icon: icons.audio.mixer, + title: "App Mixer", + content: [ + Widget.Box({ + vertical: true, + class_name: "vertical mixer-item-box", + children: audio.bind("apps").as((a) => a.map(MixerItem)), + }), + Widget.Separator(), + SettingsButton(), + ], + }); + +export const SinkSelector = () => + Menu({ + name: "sink-selector", + icon: icons.audio.type.headset, + title: "Sink Selector", + content: [ + Widget.Box({ + vertical: true, + children: audio.bind("speakers").as((a) => a.map(SinkItem)), + }), + Widget.Separator(), + SettingsButton(), + ], + }); diff --git a/config/private_dot_config/exact_ags/widget/settings/Group.ts b/config/private_dot_config/exact_ags/widget/settings/Group.ts new file mode 100644 index 00000000..45abbce3 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/settings/Group.ts @@ -0,0 +1,40 @@ +import icons from "lib/icons"; + +import Row from "./Row"; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default (title: string, ...rows: ReturnType>[]) => + Widget.Box( + { + class_name: "group", + vertical: true, + }, + Widget.Box([ + Widget.Label({ + hpack: "start", + vpack: "end", + class_name: "group-title", + label: title, + setup: (w) => Utils.idle(() => (w.visible = !!title)), + }), + title + ? Widget.Button({ + hexpand: true, + hpack: "end", + child: Widget.Icon(icons.ui.refresh), + class_name: "group-reset", + sensitive: Utils.merge( + rows.map(({ attribute: { opt } }) => + opt.bind().as((v) => v !== opt.initial) + ), + (...values) => values.some((b) => b) + ), + on_clicked: () => rows.forEach((row) => row.attribute.opt.reset()), + }) + : Widget.Box(), + ]), + Widget.Box({ + vertical: true, + children: rows, + }) + ); diff --git a/config/private_dot_config/exact_ags/widget/settings/Page.ts b/config/private_dot_config/exact_ags/widget/settings/Page.ts new file mode 100644 index 00000000..27f530f4 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/settings/Page.ts @@ -0,0 +1,20 @@ +import Group from "./Group"; + +export default ( + name: string, + icon: string, + ...groups: ReturnType>[] +) => + Widget.Box({ + class_name: "page", + attribute: { name, icon }, + child: Widget.Scrollable({ + css: "min-height: 300px;", + child: Widget.Box({ + class_name: "page-content", + vexpand: true, + vertical: true, + children: groups, + }), + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/settings/Row.ts b/config/private_dot_config/exact_ags/widget/settings/Row.ts new file mode 100644 index 00000000..81fa95ac --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/settings/Row.ts @@ -0,0 +1,54 @@ +import icons from "lib/icons"; +import { Opt } from "lib/option"; + +import Setter from "./Setter"; + +export type RowProps = { + opt: Opt; + title: string; + note?: string; + type?: + | "number" + | "color" + | "float" + | "object" + | "string" + | "enum" + | "boolean" + | "img" + | "font"; + enums?: string[]; + max?: number; + min?: number; +}; + +export default (props: RowProps) => + Widget.Box( + { + attribute: { opt: props.opt }, + class_name: "row", + tooltip_text: props.note ? `note: ${props.note}` : "", + }, + Widget.Box( + { vertical: true, vpack: "center" }, + Widget.Label({ + xalign: 0, + class_name: "row-title", + label: props.title, + }), + Widget.Label({ + xalign: 0, + class_name: "id", + label: props.opt.id, + }) + ), + Widget.Box({ hexpand: true }), + Widget.Box({ vpack: "center" }, Setter(props)), + Widget.Button({ + vpack: "center", + class_name: "reset", + child: Widget.Icon(icons.ui.refresh), + on_clicked: () => props.opt.reset(), + sensitive: props.opt.bind().as((v) => v !== props.opt.initial), + }) + ); diff --git a/config/private_dot_config/exact_ags/widget/settings/Setter.ts b/config/private_dot_config/exact_ags/widget/settings/Setter.ts new file mode 100644 index 00000000..356dea3e --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/settings/Setter.ts @@ -0,0 +1,116 @@ +import Gdk from "gi://Gdk"; +import icons from "lib/icons"; +import { Opt } from "lib/option"; + +import { type RowProps } from "./Row"; + +function EnumSetter(opt: Opt, values: string[]) { + const lbl = Widget.Label({ label: opt.bind().as((v) => `${v}`) }); + const step = (dir: 1 | -1) => { + const i = values.findIndex((i) => i === lbl.label); + opt.setValue( + dir > 0 + ? i + dir > values.length - 1 + ? values[0] + : values[i + dir] + : i + dir < 0 + ? values[values.length - 1] + : values[i + dir] + ); + }; + const next = Widget.Button({ + child: Widget.Icon(icons.ui.arrow.right), + on_clicked: () => step(+1), + }); + const prev = Widget.Button({ + child: Widget.Icon(icons.ui.arrow.left), + on_clicked: () => step(-1), + }); + return Widget.Box({ + class_name: "enum-setter", + children: [lbl, prev, next], + }); +} + +export default function Setter({ + opt, + type = typeof opt.value as RowProps["type"], + enums, + max = 1000, + min = 0, +}: RowProps) { + switch (type) { + case "number": + return Widget.SpinButton({ + setup(self) { + self.set_range(min, max); + self.set_increments(1, 5); + self.on("value-changed", () => (opt.value = self.value as T)); + self.hook(opt, () => (self.value = opt.value as number)); + }, + }); + + case "float": + case "object": + return Widget.Entry({ + on_accept: (self) => (opt.value = JSON.parse(self.text ?? "")), + setup: (self) => + self.hook(opt, () => (self.text = JSON.stringify(opt.value))), + }); + + case "string": + return Widget.Entry({ + on_accept: (self) => (opt.value = self.text as T), + setup: (self) => + self.hook(opt, () => (self.text = opt.value as string)), + }); + + case "enum": + return EnumSetter(opt as unknown as Opt, enums!); + case "boolean": + return Widget.Switch() + .on("notify::active", (self) => (opt.value = self.active as T)) + .hook(opt, (self) => (self.active = opt.value as boolean)); + + case "img": + return Widget.FileChooserButton({ + on_file_set: ({ uri }) => { + opt.value = uri!.replace("file://", "") as T; + }, + }); + + case "font": + return Widget.FontButton({ + show_size: false, + use_size: false, + setup: (self) => + self + .hook(opt, () => (self.font = opt.value as string)) + .on( + "font-set", + ({ font }) => + (opt.value = font!.split(" ").slice(0, -1).join(" ") as T) + ), + }); + + case "color": + return Widget.ColorButton() + .hook(opt, (self) => { + const rgba = new Gdk.RGBA(); + rgba.parse(opt.value as string); + self.rgba = rgba; + }) + .on("color-set", ({ rgba: { red, green, blue } }) => { + const hex = (n: number) => { + const c = Math.floor(255 * n).toString(16); + return c.length === 1 ? `0${c}` : c; + }; + opt.value = `#${hex(red)}${hex(green)}${hex(blue)}` as T; + }); + + default: + return Widget.Label({ + label: `no setter with type ${type}`, + }); + } +} diff --git a/config/private_dot_config/exact_ags/widget/settings/SettingsDialog.ts b/config/private_dot_config/exact_ags/widget/settings/SettingsDialog.ts new file mode 100644 index 00000000..832743b6 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/settings/SettingsDialog.ts @@ -0,0 +1,66 @@ +import icons from "lib/icons"; +import options from "options"; +import RegularWindow from "widget/RegularWindow"; + +import layout from "./layout"; + +const current = Variable(layout[0].attribute.name); + +const Header = () => + Widget.CenterBox({ + class_name: "header", + start_widget: Widget.Button({ + class_name: "reset", + on_clicked: options.reset, + hpack: "start", + vpack: "start", + child: Widget.Icon(icons.ui.refresh), + tooltip_text: "Reset", + }), + center_widget: Widget.Box({ + class_name: "pager horizontal", + children: layout.map(({ attribute: { name, icon } }) => + Widget.Button({ + xalign: 0, + class_name: current.bind().as((v) => `${v === name ? "active" : ""}`), + on_clicked: () => (current.value = name), + child: Widget.Box([Widget.Icon(icon), Widget.Label(name)]), + }) + ), + }), + end_widget: Widget.Button({ + class_name: "close", + hpack: "end", + vpack: "start", + child: Widget.Icon(icons.ui.close), + on_clicked: () => App.closeWindow("settings-dialog"), + }), + }); + +const PagesStack = () => + Widget.Stack({ + transition: "slide_left_right", + children: layout.reduce( + (obj, page) => ({ ...obj, [page.attribute.name]: page }), + {} + ), + shown: current.bind() as never, + }); + +export default () => + RegularWindow({ + name: "settings-dialog", + class_name: "settings-dialog", + title: "Settings", + setup(win) { + win.on("delete-event", () => { + win.hide(); + return true; + }); + win.set_default_size(500, 600); + }, + child: Widget.Box({ + vertical: true, + children: [Header(), PagesStack()], + }), + }); diff --git a/config/private_dot_config/exact_ags/widget/settings/layout.ts b/config/private_dot_config/exact_ags/widget/settings/layout.ts new file mode 100644 index 00000000..b05f1f16 --- /dev/null +++ b/config/private_dot_config/exact_ags/widget/settings/layout.ts @@ -0,0 +1,245 @@ +/* eslint-disable max-len */ + +import icons from "lib/icons"; +import options from "options"; + +import Group from "./Group"; +import Page from "./Page"; +import Row from "./Row"; + +const { + font, + theme, + bar: b, + launcher: l, + overview: ov, + powermenu: pm, + quicksettings: qs, + osd, +} = options; + +const { + dark, + light, + blur, + scheme, + padding, + spacing, + radius, + shadows, + widget, + border, +} = theme; + +export default [ + Page( + "Theme", + icons.ui.themes, + Group( + "", + Row({ + opt: scheme, + title: "Color Scheme", + type: "enum", + enums: ["dark", "light"], + }) + ), + Group( + "Dark Colors", + Row({ opt: dark.bg, title: "Background", type: "color" }), + Row({ opt: dark.view, title: "View Background", type: "color" }), + Row({ opt: dark.card, title: "Card Background", type: "color" }), + Row({ opt: dark.surface, title: "Surface Background", type: "color" }), + Row({ opt: dark.fg, title: "Text", type: "color" }), + Row({ opt: dark.primary.bg, title: "Primary Background", type: "color" }), + Row({ opt: dark.primary.accent, title: "Primary Accent", type: "color" }), + Row({ opt: dark.error.bg, title: "Error Background", type: "color" }), + Row({ opt: dark.error.accent, title: "Error Accent", type: "color" }), + Row({ opt: dark.success.bg, title: "Success Background", type: "color" }), + Row({ opt: dark.success.accent, title: "Success Accent", type: "color" }), + Row({ opt: dark.warning.bg, title: "Warning Background", type: "color" }), + Row({ opt: dark.warning.accent, title: "Warning Accent", type: "color" }), + Row({ opt: dark.widget, title: "Widget", type: "color" }), + Row({ opt: dark.border, title: "Border", type: "color" }) + ), + Group( + "Light Colors", + Row({ opt: light.bg, title: "Background", type: "color" }), + Row({ opt: light.view, title: "View Background", type: "color" }), + Row({ opt: light.card, title: "Card Background", type: "color" }), + Row({ opt: light.surface, title: "Surface Background", type: "color" }), + Row({ opt: light.fg, title: "Text", type: "color" }), + Row({ opt: light.primary.bg, title: "Primary", type: "color" }), + Row({ + opt: light.primary.accent, + title: "Primary Accent", + type: "color", + }), + Row({ opt: light.error.bg, title: "Error", type: "color" }), + Row({ opt: light.error.accent, title: "Error Accent", type: "color" }), + Row({ + opt: light.success.bg, + title: "Success Background", + type: "color", + }), + Row({ + opt: light.success.accent, + title: "Success Accent", + type: "color", + }), + Row({ + opt: light.warning.bg, + title: "Warning Background", + type: "color", + }), + Row({ + opt: light.warning.accent, + title: "Warning Accent", + type: "color", + }), + Row({ opt: light.widget, title: "Widget", type: "color" }), + Row({ opt: light.border, title: "Border", type: "color" }) + ), + Group( + "Theme", + Row({ opt: shadows, title: "Shadows" }), + Row({ opt: widget.opacity, title: "Widget Opacity", max: 100 }), + Row({ opt: border.opacity, title: "Border Opacity", max: 100 }), + Row({ opt: border.width, title: "Border Width" }), + Row({ opt: blur, title: "Blur", note: "0 to disable", max: 70 }) + ), + Group( + "UI", + Row({ opt: padding, title: "Padding" }), + Row({ opt: spacing, title: "Spacing" }), + Row({ opt: radius, title: "Roundness" }), + Row({ opt: font.size, title: "Font Size" }), + Row({ opt: font.name, title: "Font Name", type: "font" }) + ) + ), + Page( + "Bar", + icons.ui.toolbars, + Group( + "General", + Row({ + opt: b.transparent, + title: "Transparent Bar", + note: "Works best on empty-ish wallpapers", + }), + Row({ opt: b.flatButtons, title: "Flat Buttons" }), + Row({ + opt: b.position, + title: "Position", + type: "enum", + enums: ["top", "bottom"], + }), + Row({ opt: b.corners, title: "Corners" }) + ), + Group( + "Launcher", + Row({ opt: b.launcher.icon.icon, title: "Icon" }), + Row({ opt: b.launcher.icon.colored, title: "Colored Icon" }), + Row({ opt: b.launcher.label.label, title: "Label" }), + Row({ opt: b.launcher.label.colored, title: "Colored Label" }) + ), + Group( + "Workspaces", + Row({ + opt: b.workspaces.workspaces, + title: "Number of Workspaces", + note: "0 to make it dynamic", + }) + ), + Group( + "Taskbar", + Row({ opt: b.taskbar.iconSize, title: "Icon Size" }), + Row({ opt: b.taskbar.monochrome, title: "Monochrome" }), + Row({ opt: b.taskbar.exclusive, title: "Exclusive to workspaces" }) + ), + Group("Date", Row({ opt: b.date.format, title: "Date Format" })), + Group( + "Media", + Row({ opt: b.media.monochrome, title: "Monochrome" }), + Row({ opt: b.media.preferred, title: "Preferred Player" }), + Row({ + opt: b.media.direction, + title: "Slide Direction", + type: "enum", + enums: ["left", "right"], + }), + Row({ opt: b.media.format, title: "Format of the Label" }), + Row({ opt: b.media.length, title: "Max Length of Label" }) + ), + Group( + "Battery", + Row({ + opt: b.battery.bar, + title: "Style", + type: "enum", + enums: ["hidden", "regular", "whole"], + }), + Row({ opt: b.battery.blocks, title: "Number of Blocks" }), + Row({ opt: b.battery.width, title: "Width of Bar" }), + Row({ opt: b.battery.charging, title: "Charging Color", type: "color" }) + ), + Group( + "Powermenu", + Row({ opt: b.powermenu.monochrome, title: "Monochrome" }) + ) + ), + Page( + "General", + icons.ui.settings, + Group( + "Launcher", + Row({ opt: l.width, title: "Width" }), + Row({ opt: l.apps.iconSize, title: "Icon Size" }), + Row({ opt: l.apps.max, title: "Max Items" }) + ), + Group( + "Overview", + Row({ opt: ov.scale, title: "Scale", max: 100 }), + Row({ + opt: ov.workspaces, + title: "Workspaces", + max: 11, + note: "set this to 0 to make it dynamic", + }), + Row({ opt: ov.monochromeIcon, title: "Monochrome Icons" }) + ), + Group( + "Powermenu", + Row({ + opt: pm.layout, + title: "Layout", + type: "enum", + enums: ["box", "line"], + }), + Row({ opt: pm.labels, title: "Show Labels" }) + ), + Group( + "Quicksettings", + Row({ opt: qs.avatar.image, title: "Avatar", type: "img" }), + Row({ opt: qs.avatar.size, title: "Avatar Size" }), + Row({ opt: qs.media.monochromeIcon, title: "Media Monochrome Icons" }), + Row({ opt: qs.media.coverSize, title: "Media Cover Art Size" }) + ), + Group( + "On Screen Indicator", + Row({ opt: osd.progress.vertical, title: "Vertical" }), + Row({ + opt: osd.progress.pack.h, + title: "Horizontal Alignment", + type: "enum", + enums: ["start", "center", "end"], + }), + Row({ + opt: osd.progress.pack.v, + title: "Vertical Alignment", + type: "enum", + enums: ["start", "center", "end"], + }) + ) + ), +] as const; diff --git a/config/private_dot_config/exact_fastfetch/config.jsonc b/config/private_dot_config/exact_fastfetch/config.jsonc index 8950dbd5..92969679 100644 --- a/config/private_dot_config/exact_fastfetch/config.jsonc +++ b/config/private_dot_config/exact_fastfetch/config.jsonc @@ -24,7 +24,7 @@ }, { "type": "packages", - "format": "{}", + "format": "{} (pacman)", "key": " โ”œ ๓ฐ– ", "keyColor": "31" }, diff --git a/config/private_dot_config/exact_hypr/exact_hyprland/bindings.conf b/config/private_dot_config/exact_hypr/exact_hyprland/bindings.conf new file mode 100644 index 00000000..c52c63db --- /dev/null +++ b/config/private_dot_config/exact_hypr/exact_hyprland/bindings.conf @@ -0,0 +1,110 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ BINDINGS โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# https://wiki.hyprland.org/Configuring/Binds +# SUPER = "Windows" key + +$lmb = mouse:272 # Left mouse button +$rmb = mouse:273 # Right mouse button +$mmb = mouse:274 # Middle mouse button + +# โ”€โ”€ General โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +bindd = CTRL SHIFT, R, Reload `ags`, exec, ags -b hypr quit; ags -b hypr +bindd = SUPER, tab, Toggle Workspaces Overview, exec, ags -b hypr -t overview +bindd = ALT, space, Toggle App Launcher, exec, ags -b hypr -t launcher +bindd = SUPER, V, Open Clipboard History, exec, ags -b hypr -r 'launcher.open(":ch ")' +bindd = , XF86PowerOff, Toggle Power Menu, exec, ags -b hypr -t powermenu + +# โ”€โ”€ Screenshot โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +bindd = , Print, Take Screenshot (Select Area), exec, ags -b hypr -r 'recorder.screenshot()' +bindd = SUPER, Print, Take Fullscreen Screenshot, exec, ags -b hypr -r 'recorder.screenshot(true)' +bindd = SUPER ALT, Print, Start Screen Recording, exec, ags -b hypr -r 'recorder.start()' + +# โ”€โ”€ Apps โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +bindd = SUPER, Backslash, Open Terminal, exec, wezterm start -- tmux +bindd = SUPER, E, Open File Manager, exec, nautilus --new-window +bindd = SUPER, W, Open Browser, exec, firefox-developer-edition +bindd = CTRL SHIFT, Escape, Open System Monitor, exec, gnome-system-monitor + +# โ”€โ”€ Audio โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +binddle = , XF86AudioLowerVolume, Decrease Volume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ -l 1 2%- +binddle = , XF86AudioRaiseVolume, Increase Volume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ -l 1 2%+ +binddl = , XF86AudioMute, Mute/Unmute Volume, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +binddl = , XF86AudioMicMute, Mute/Unmute Microphone, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +binddl = , XF86AudioPlay, Play/Pause, exec, playerctl play-pause +binddl = , XF86AudioPause, Play/Pause, exec, playerctl play-pause +binddl = , XF86AudioNext, Skip to Next Track, exec, playerctl next +binddl = , XF86AudioPrev, Return to Previous Track, exec, playerctl previous + +# โ”€โ”€ Backlight โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +binddle = , XF86MonBrightnessDown, Decrease Screen Brightness, exec, ags -b hypr -r 'brightness.changeRelative(5, "-")' +binddle = , XF86MonBrightnessUp, Increase Screen Brightness, exec, ags -b hypr -r 'brightness.changeRelative(5, "+")' + +# โ”€โ”€ Windows โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +# Move focus +bindd = SUPER, H, Move Focus to Left Window, movefocus, l +bindd = SUPER, L, Move Focus to Right Window, movefocus, r +bindd = SUPER, K, Move Focus to Upper Window, movefocus, u +bindd = SUPER, J, Move Focus to Lower Window, movefocus, d + +# Resize windows +binddm = SUPER, $rmb, Resize Window, resizewindow +bindd = SUPER, F, Toggle Fullscreen, fullscreen, 0 +bindd = SUPER, M, Maximize/Restore Window, fullscreen, 1 +bindde = SUPER, left, Resize Window to the Left, resizeactive, -20 0 +bindde = SUPER, right, Resize Window to the Right, resizeactive, 20 0 +bindde = SUPER, up, Resize Window Upwards, resizeactive, 0 -20 +bindde = SUPER, down, Resize Window Downwards, resizeactive, 0 20 + +# Move windows +binddm = SUPER, $lmb, Move Window, movewindow +bindd = SUPER ALT, H, Move Window Left, movewindow, l +bindd = SUPER ALT, L, Move Window Right, movewindow, r +bindd = SUPER ALT, K, Move Window Upwards, movewindow, u +bindd = SUPER ALT, J, Move Window Downwards, movewindow, d + +bindd = SUPER, Q, Close Active Window, killactive, +bindd = SUPER, C, Center Window, centerwindow, 1 # `1` respects the monitor reserved area + +# Toggling +bindd = SUPER, P, Toggle Focused Window's Pseudo Mode, pseudo, +bindd = SUPER, R, Toggle Split Orientation, togglesplit, +bindd = SUPER, T, Toggle Active Window Floating, togglefloating, +bindd = SUPER SHIFT, T, Toggle All Windows Floating, exec, hyprctl dispatch workspaceopt allfloat + +# โ”€โ”€ Workspaces โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + +# Switch workspaces +bindd = SUPER, 1, Switch to Workspace 1, workspace, 1 +bindd = SUPER, 2, Switch to Workspace 2, workspace, 2 +bindd = SUPER, 3, Switch to Workspace 3, workspace, 3 +bindd = SUPER, 4, Switch to Workspace 4, workspace, 4 +bindd = SUPER, 5, Switch to Workspace 5, workspace, 5 +bindd = SUPER, 6, Switch to Workspace 6, workspace, 6 +bindd = SUPER, 7, Switch to Workspace 7, workspace, 7 +bindd = SUPER, 8, Switch to Workspace 8, workspace, 8 +bindd = SUPER, 9, Switch to Workspace 9, workspace, 9 +bindd = SUPER, 0, Switch to Workspace 10, workspace, 10 +bindd = SUPER CTRL, H, Switch to Previous Workspace, workspace, e-1 +bindd = SUPER CTRL, L, Switch to Next Workspace, workspace, e+1 +bindd = SUPER, mouse_down, Switch to Previous Workspace, workspace, e+1 +bindd = SUPER, mouse_up, Switch to Next Workspace, workspace, e-1 + +# Move active window to a workspace +bindd = SUPER SHIFT, 1, Move Active Window to Workspace 1, movetoworkspace, 1 +bindd = SUPER SHIFT, 2, Move Active Window to Workspace 2, movetoworkspace, 2 +bindd = SUPER SHIFT, 3, Move Active Window to Workspace 3, movetoworkspace, 3 +bindd = SUPER SHIFT, 4, Move Active Window to Workspace 4, movetoworkspace, 4 +bindd = SUPER SHIFT, 5, Move Active Window to Workspace 5, movetoworkspace, 5 +bindd = SUPER SHIFT, 6, Move Active Window to Workspace 6, movetoworkspace, 6 +bindd = SUPER SHIFT, 7, Move Active Window to Workspace 7, movetoworkspace, 7 +bindd = SUPER SHIFT, 8, Move Active Window to Workspace 8, movetoworkspace, 8 +bindd = SUPER SHIFT, 9, Move Active Window to Workspace 9, movetoworkspace, 9 +bindd = SUPER SHIFT, 0, Move Active Window to Workspace 10, movetoworkspace, 10 +bindd = SUPER SHIFT, H, Move Active Window to Previous Workspace, movetoworkspace, e-1 +bindd = SUPER SHIFT, L, Move Active Window to Next Workspace, movetoworkspace, e+1 + +# Special workspace (scratchpad) +bindd = SUPER, S, Toggle Scratchpad, togglespecialworkspace, magic +bindd = SUPER SHIFT, S, Move Active Window to Scratchpad, movetoworkspace, special:magic diff --git a/config/private_dot_config/exact_hypr/exact_hyprland/config.conf.tmpl b/config/private_dot_config/exact_hypr/exact_hyprland/config.conf.tmpl new file mode 100644 index 00000000..5ce1a891 --- /dev/null +++ b/config/private_dot_config/exact_hypr/exact_hyprland/config.conf.tmpl @@ -0,0 +1,122 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ CONFIG โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# https://wiki.hyprland.org/Configuring/Variables + +# โ”€โ”€ Monitors โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Monitors +{{ if eq .device_type "vm" -}} +monitor=Virtual-1, 1600x900@60, 0x0, 1 +{{- else -}} +monitor=DP-1, 1920x1080@144, 0x0, 1 +# monitor=DP-2, 1920x1080@144, 1920x0, 1 +{{- end }} + +# โ”€โ”€ General โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Variables/#general +general { + gaps_in = 10 # gaps between windows, also supports css style gaps (top, right, bottom, left -> 5,10,15,20) + gaps_out = 10 # gaps between windows and monitor edges, also supports css style gaps (top, right, bottom, left -> 5,10,15,20) + + border_size = 3 # size of the border around windows + + col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg # border color for the active window + col.inactive_border = rgba(595959aa) # border color for inactive windows + + resize_on_border = true # enables resizing windows by clicking and dragging on borders and gaps + + allow_tearing = true # master switch for allowing tearing to occur +} + +# โ”€โ”€ Decoration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Variables/#decoration +decoration { + rounding = 10 # rounded corners' radius (in layout px) + + drop_shadow = {{ ne .device_type "vm" }} # enable drop shadows on windows + shadow_ignore_window = true # if true, the shadow will not be rendered behind the window itself, only around it + shadow_offset = 2 2 # shadowโ€™s rendering offset + shadow_range = 8 # Shadow range (โ€œsizeโ€) in layout px + shadow_render_power = 2 # in what power to render the falloff (more power, the faster the falloff) [1 - 4] + col.shadow = 0x66000000 # shadowโ€™s color. Alpha dictates shadowโ€™s opacity + + # โ”€โ”€ Blur โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + # https://wiki.hyprland.org/Configuring/Variables/#blur + blur { + enabled = {{ ne .device_type "vm" }} # enable kawase window background blur + size = 3 # blur size (distance) + passes = 2 # the amount of passes to perform + } +} + +# โ”€โ”€ Animations โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Variables/#animations +animations { + enabled = {{ ne .device_type "vm" }} # enable animations + + # https://wiki.hyprland.org/Configuring/Animations + bezier = overshot, 0.05, 0.9, 0.1, 1.05 + bezier = smoothOut, 0.36, 0, 0.66, -0.56 + bezier = smoothIn, 0.25, 1, 0.5, 1 + + animation = windows, 1, 5, overshot, slide + animation = windowsOut, 1, 4, smoothOut, slide + animation = windowsMove, 1, 4, default + animation = border, 1, 10, default + animation = fade, 1, 10, smoothIn + animation = fadeDim, 1, 10, smoothIn + animation = workspaces, 1, 6, default + animation = specialWorkspace, 1, 4, default, slidevert +} + +# โ”€โ”€ Input โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Variables/#input +input { + # Toggle between US QWERTY and US Intl QWERTY layout on `Win + Space` + # https://wiki.hyprland.org/Configuring/Variables/#xkb-settings + kb_layout = us, us + kb_variant = basic, intl + kb_model = + kb_options = grp:win_space_toggle + kb_rules = + + # Specify if and how cursor movement should affect window focus. + # https://wiki.hyprland.org/Configuring/Variables/#follow-mouse-cursor + follow_mouse = 2 + + # โ”€โ”€ Touchpad โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + # https://wiki.hyprland.org/Configuring/Variables/#touchpad + touchpad { + natural_scroll = true # Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar + } +} + +# โ”€โ”€ Gestures โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Variables/#gestures +gestures { + workspace_swipe = true # enable workspace swipe gesture on touchpad +} + +# โ”€โ”€ Miscellaneous โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Variables/#misc +misc { + disable_hyprland_logo = true # disables the random Hyprland logo / anime girl background + disable_splash_rendering = true # disables the Hyprland splash rendering. (requires a monitor reload to take effect) + force_default_wallpaper = 0 # Enforce any of the 3 default wallpapers. Setting this to 0 or 1 disables the anime background. -1 means โ€œrandomโ€ + vrr = 2 # controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only + animate_manual_resizes = {{ ne .device_type "vm" }} # If true, will animate manual window resizes/moves + enable_swallow = true # Enable window swallowing +} + +# โ”€โ”€ XWayland โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Variables/#xwayland +xwayland { + force_zero_scaling = true # forces a scale of 1 on xwayland windows on scaled displays +} + +# โ”€โ”€ Dwindle โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +# https://wiki.hyprland.org/Configuring/Dwindle-Layout +dwindle { + pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below + preserve_split = true +} diff --git a/config/private_dot_config/exact_hypr/exact_hyprland/env.conf.tmpl b/config/private_dot_config/exact_hypr/exact_hyprland/env.conf.tmpl new file mode 100644 index 00000000..34a4f497 --- /dev/null +++ b/config/private_dot_config/exact_hypr/exact_hyprland/env.conf.tmpl @@ -0,0 +1,52 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ ENVIRONMENT VARIABLES โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# https://wiki.hyprland.org/Configuring/Environment-variables + +$system_theme = adw-gtk3 +$cursor_theme = {{ .gtk.cursor.theme.name }} +$cursor_size = {{ .gtk.cursor.size }} +$dpi_scale = 1 +$text_scale = 1 + +# โ”€โ”€ Toolkit Backend Variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +env = CLUTTER_BACKEND,wayland # Clutter package already has wayland enabled, this variable will force Clutter applications to try and use the Wayland backend +env = GDK_BACKEND,wayland,x11,* # GTK: Use wayland if available. If not: try x11, then any other GDK backend. +env = SDL_VIDEODRIVER,wayland,x11 # Run SDL2 applications on Wayland. Remove or set to x11 if games that provide older versions of SDL cause compatibility issues + +# โ”€โ”€ XDG Specifications โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +env = XDG_CURRENT_DESKTOP,Hyprland +env = XDG_SESSION_DESKTOP,Hyprland +env = XDG_SESSION_TYPE,wayland + +# โ”€โ”€ Qt Variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +env = QT_AUTO_SCREEN_SCALE_FACTOR,$dpi_scale # Enables automatic scaling, based on the monitorโ€™s pixel density +env = QT_QPA_PLATFORM,wayland;xcb # Tell Qt applications to use the Wayland backend, and fall back to x11 if Wayland is unavailable +env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1 # Disables window decorations on Qt applications +env = QT_QPA_PLATFORMTHEME,qt6ct # Tells Qt based applications to pick your theme from qt6ct, use with Kvantum. +env = QT_STYLE_OVERRIDE,kvantum + +# โ”€โ”€ Theming Related Variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +env = GTK_THEME,$system_theme # Set system theme. +env = XCURSOR_SIZE,$cursor_size # Set cursor size. +env = HYPRCURSOR_SIZE,$cursor_size +env = XCURSOR_THEME,$cursor_theme # Set cursor theme. +env = HYPRCURSOR_THEME,$cursor_theme + +# โ”€โ”€ GTK theme โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +$gnome-schema = org.gnome.desktop.interface +exec = gsettings set $gnome-schema clock-format 24h +exec = gsettings set $gnome-schema gtk-theme $system_theme # For GTK3 apps +exec = gsettings set $gnome-schema icon-theme {{ .gtk.icon.theme.name }} +exec = gsettings set $gnome-schema color-scheme prefer-dark # For GTK4 apps +exec = gsettings set $gnome-schema cursor-theme $cursor_theme +exec = gsettings set $gnome-schema text-scaling-factor $text_scale +exec = gsettings set $gnome-schema cursor-size $cursor_size + +{{ if eq .device_type "vm" -}} +# โ”€โ”€ VM variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +env = WLR_NO_HARDWARE_CURSORS,1 # Show mouse cursor +# env = WLR_RENDERER_ALLOW_SOFTWARE,1 +# env = LIBGL_ALWAYS_SOFTWARE,true +# env = GALLIUM_DRIVER,llvmpipe +{{- end }} diff --git a/config/private_dot_config/exact_hypr/exact_hyprland/execs.conf b/config/private_dot_config/exact_hypr/exact_hyprland/execs.conf new file mode 100644 index 00000000..13213bb0 --- /dev/null +++ b/config/private_dot_config/exact_hypr/exact_hyprland/execs.conf @@ -0,0 +1,22 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ AUTOSTART โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +exec-once = ~/.config/hypr/xdg-desktop-portal-hyprland.sh +exec-once = dbus-update-activation-environment --systemd --all +exec-once = systemctl --user import-environment QT_QPA_PLATFORMTHEME +exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 +exec-once = ags -b hypr +exec-once = easyeffects --gapplication-service +exec-once = hypridle +exec-once = hyprpaper +exec-once = safeeyes -e +exec-once = wl-clip-persist --clipboard regular +exec-once = wl-paste --type text --watch cliphist store +exec-once = wl-paste --type image --watch cliphist store +exec = hyprshade auto + +exec-once=[workspace 1 silent] firefox-developer-edition +exec-once=[workspace 2 silent] wezterm start -- tmux +exec-once=[workspace 3 silent] ferdium +exec-once=[workspace 3 silent] spotify-launcher diff --git a/config/private_dot_config/exact_hypr/exact_hyprland/rules.conf.tmpl b/config/private_dot_config/exact_hypr/exact_hyprland/rules.conf.tmpl new file mode 100644 index 00000000..46a4f497 --- /dev/null +++ b/config/private_dot_config/exact_hypr/exact_hyprland/rules.conf.tmpl @@ -0,0 +1,22 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ WINDOWS AND WORKSPACES โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +# https://wiki.hyprland.org/Configuring/Window-Rules +# https://wiki.hyprland.org/Configuring/Workspace-Rules + +windowrulev2 = suppressevent maximize, class:.* + +# โ”€โ”€ Floating windows โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +{{ range (list "confirm" "file_progress" "dialog" "dconf-editor" "org.gnome.Calculator" "org.gnome.Nautilus" "org.gnome.SystemMonitor" "nm-connection-editor" "org.gnome.Settings" "org.gnome.design.Palette" "Color Picker" "com.github.Aylur.ags" "com.github.GradienceTeam.Gradience") -}} +windowrule=float,^({{- . -}})$ +{{ end }} +{{ range (list "Open File" "Select a File" "Choose wallpaper" "Open Folder" "Save As" "Library" "File Upload") -}} +windowrule=float,title:^({{- . -}})(.*)$ +{{ end }} +windowrulev2 = float,title:^([Pp]icture[-\s]?[Ii]n[-\s]?[Pp]icture)(.*)$ + +# โ”€โ”€ Tearing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +windowrule=immediate,.*\.exe +windowrulev2=immediate,class:(steam_app) + +# โ”€โ”€ Specific window rules โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/config/private_dot_config/exact_hypr/executable_battery-status.sh b/config/private_dot_config/exact_hypr/executable_battery-status.sh new file mode 100644 index 00000000..fc53ca62 --- /dev/null +++ b/config/private_dot_config/exact_hypr/executable_battery-status.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ BATTERY STATUS โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +status="$(cat /sys/class/power_supply/BAT1/status)" +level="$(cat /sys/class/power_supply/BAT1/capacity)" + +if [[ ("${status}" == "Discharging") || ("${status}" == "Full") ]]; then + if [[ "${level}" -eq "0" ]]; then + printf "๏‰„ " + elif [[ ("${level}" -ge "0") && ("${level}" -le "25") ]]; then + printf "๏‰ƒ " + elif [[ ("${level}" -ge "25") && ("${level}" -le "50") ]]; then + printf "๏‰‚ " + elif [[ ("${level}" -ge "50") && ("${level}" -le "75") ]]; then + printf "๏‰ " + elif [[ ("${level}" -ge "75") && ("${level}" -le "100") ]]; then + printf "๏‰€ " + fi +elif [[ "${status}" == "Charging" ]]; then + printf "๏ƒง " +fi diff --git a/nix/home-manager/eza.nix b/config/private_dot_config/exact_hypr/executable_layout-status.sh similarity index 57% rename from nix/home-manager/eza.nix rename to config/private_dot_config/exact_hypr/executable_layout-status.sh index 0957e8f6..66ab1e0b 100644 --- a/nix/home-manager/eza.nix +++ b/config/private_dot_config/exact_hypr/executable_layout-status.sh @@ -1,15 +1,8 @@ +#!/usr/bin/env bash + # โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ eza โ”‚ +# โ”‚ LAYOUT STATUS โ”‚ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - programs.eza = { - enable = true; - enableZshIntegration = true; - extraOptions = [ - "--group-directories-first" - "--octal-permissions" - ]; - git = true; - icons = true; - }; -} + +layout="$(bat /etc/vconsole.conf | grep XKBLAYOUT | awk -F'=' '{print toupper($2)}')" +printf "%s ๏„œ " "${layout}" diff --git a/config/private_dot_config/exact_hypr/executable_network-status.sh b/config/private_dot_config/exact_hypr/executable_network-status.sh new file mode 100644 index 00000000..26942700 --- /dev/null +++ b/config/private_dot_config/exact_hypr/executable_network-status.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ NETWORK STATUS โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +status="$(nmcli general status | grep -oh "\w*connect\w*")" + +if [[ "${status}" == "disconnected" ]]; then + printf "๓ฐคฎ " +elif [[ "${status}" == "connecting" ]]; then + printf "๓ฑธ " +elif [[ "${status}" == "connected" ]]; then + # strength="$(nmcli -f IN-USE,SIGNAL device wifi | grep '*' | awk '{print $2}')" + strength="$(python "${HOME}"/.config/Scripts/wifi-conn-strength)" + if [[ "$?" == "0" ]]; then + if [[ "${strength}" -eq "0" ]]; then + printf "๓ฐคฏ " + elif [[ ("${strength}" -ge "0") && ("${strength}" -le "25") ]]; then + printf "๓ฐคŸ " + elif [[ ("${strength}" -ge "25") && ("${strength}" -le "50") ]]; then + printf "๓ฐคข " + elif [[ ("${strength}" -ge "50") && ("${strength}" -le "75") ]]; then + printf "๓ฐคฅ " + elif [[ ("${strength}" -ge "75") && ("${strength}" -le "100") ]]; then + printf "๓ฐคจ " + fi + else + printf "๓ฐˆ€ " + fi +fi diff --git a/config/private_dot_config/exact_hypr/executable_song-status.sh b/config/private_dot_config/exact_hypr/executable_song-status.sh new file mode 100644 index 00000000..c89dcf9e --- /dev/null +++ b/config/private_dot_config/exact_hypr/executable_song-status.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ SONG STATUS โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +player_name=$(playerctl metadata --format '{{playerName}}') +player_status=$(playerctl status) + +if [[ "${player_status}" == "Playing" ]]; then + if [[ "${player_name}" == "spotify" ]]; then + song_info=$(playerctl metadata --format '{{title}} ๓ฐ“‡ {{artist}}') + elif [[ "${player_name}" == "firefox" ]]; then + song_info=$(playerctl metadata --format '{{title}} ๓ฐˆน {{artist}}') + elif [[ "${player_name}" == "mpd" ]]; then + song_info=$(playerctl metadata --format '{{title}} ๓ฐŽ† {{artist}}') + elif [[ "${player_name}" == "chromium" ]]; then + song_info=$(playerctl metadata --format '{{title}} ๓ฐŠฏ {{artist}}') + fi +fi + +echo "${song_info}" diff --git a/nix/overlays/default.nix b/config/private_dot_config/exact_hypr/executable_xdg-desktop-portal-hyprland.sh similarity index 51% rename from nix/overlays/default.nix rename to config/private_dot_config/exact_hypr/executable_xdg-desktop-portal-hyprland.sh index 61a1d0e6..302acfc4 100644 --- a/nix/overlays/default.nix +++ b/config/private_dot_config/exact_hypr/executable_xdg-desktop-portal-hyprland.sh @@ -1,14 +1,14 @@ +#!/usr/bin/env bash + # โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ OVERLAYS โ”‚ +# โ”‚ XDG DESKTOP PORTAL HYPRLAND โ”‚ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - # Brings custom packages from the 'pkgs' directory - additions = final: _prev: import ../pkgs final.pkgs; +# https://wiki.hyprland.org/Useful-Utilities/xdg-desktop-portal-hyprland/#usage - # Change versions, add patches, set compilation flags, ... - # https://nixos.wiki/wiki/Overlays - modifications = - final: prev: - { - }; -} +sleep 1 +killall -e xdg-desktop-portal-hyprland +killall -e xdg-desktop-portal-wlr +killall xdg-desktop-portal +/usr/lib/xdg-desktop-portal-hyprland & +sleep 2 +/usr/lib/xdg-desktop-portal & diff --git a/config/private_dot_config/exact_hypr/hypridle.conf b/config/private_dot_config/exact_hypr/hypridle.conf new file mode 100644 index 00000000..cf62e63f --- /dev/null +++ b/config/private_dot_config/exact_hypr/hypridle.conf @@ -0,0 +1,38 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ HYPRIDLE CONFIG โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +general { + lock_cmd = pidof hyprlock || hyprlock # avoid starting multiple hyprlock instances + before_sleep_cmd = loginctl lock-session # lock before suspend + after_sleep_cmd = hyprctl dispatch dpms on # to avoid having to press a key twice to turn on the display +} + +listener { + timeout = 150 # 2.5min + on-timeout = ags -b hypr -r 'brightness.screen = 0.1' # set monitor backlight to minimum, avoid 0 on OLED monitor + on-resume = ags -b hypr -r 'brightness.screen = 0.4' # monitor backlight restore +} + +# turn off keyboard backlight, comment out this section if you dont have a keyboard backlight +# listener { +# timeout = 150 # 2.5min +# on-timeout = brightnessctl -sd dell::kbd_backlight set 0 # turn off keyboard backlight +# on-resume = brightnessctl -rd dell::kbd_backlight # turn on keyboard backlight +# } + +listener { + timeout = 300 # 5min + on-timeout = loginctl lock-session # lock screen when timeout has passed +} + +listener { + timeout = 330 # 5.5min + on-timeout = hyprctl dispatch dpms off # screen off when timeout has passed + on-resume = hyprctl dispatch dpms on # screen on when activity is detected after timeout has fired +} + +listener { + timeout = 1800 # 30min + on-timeout = systemctl suspend # suspend pc +} diff --git a/nix/home-manager/fzf.nix b/config/private_dot_config/exact_hypr/hyprland.conf similarity index 54% rename from nix/home-manager/fzf.nix rename to config/private_dot_config/exact_hypr/hyprland.conf index 995aa4d8..7ed3880f 100644 --- a/nix/home-manager/fzf.nix +++ b/config/private_dot_config/exact_hypr/hyprland.conf @@ -1,13 +1,9 @@ # โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ fzf โ”‚ +# โ”‚ HYPRLAND CONFIG โ”‚ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - programs.fzf = { - enable = true; - enableZshIntegration = true; - changeDirWidgetCommand = "fd --type d"; - defaultCommand = "fd --type f"; - fileWidgetCommand = "fd --type f"; - tmux.enableShellIntegration = true; - }; -} + +source = ~/.config/hypr/hyprland/env.conf +source = ~/.config/hypr/hyprland/execs.conf +source = ~/.config/hypr/hyprland/config.conf +source = ~/.config/hypr/hyprland/rules.conf +source = ~/.config/hypr/hyprland/bindings.conf diff --git a/config/private_dot_config/exact_hypr/hyprlock.conf.tmpl b/config/private_dot_config/exact_hypr/hyprlock.conf.tmpl new file mode 100644 index 00000000..65d1e933 --- /dev/null +++ b/config/private_dot_config/exact_hypr/hyprlock.conf.tmpl @@ -0,0 +1,153 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ HYPRLOCK CONFIG โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +# โ”€โ”€ Background โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +background { + monitor = + path = ~/Pictures/wallpapers/Fantasy-Landscape-Night.png # only png supported for now + color = rgba(25, 20, 20, 1.0) + + # all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations + blur_passes = 0 # 0 disables blurring + blur_size = 2 + noise = 0 + contrast = 0 + brightness = 0 + vibrancy = 0 + vibrancy_darkness = 0.0 +} + +# โ”€โ”€ Input Field โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +input-field { + monitor = + size = 200, 30 + outline_thickness = 0 + dots_size = 0.25 # Scale of input-field height, 0.2 - 0.8 + dots_spacing = 0.55 # Scale of dots' absolute size, 0.0 - 1.0 + dots_center = true + dots_rounding = -1 + outer_color = rgba(242, 243, 244, 0.25) + inner_color = rgba(242, 243, 244, 0.25) + font_color = rgba(242, 243, 244, 0.75) + fade_on_empty = false + placeholder_text = # Text rendered in the input box when it's empty. + hide_input = false + check_color = rgba(204, 136, 34, 0) + fail_color = rgba(204, 34, 34, 0) # if authentication failed, changes outer_color and fail message color + fail_text = $FAIL ($ATTEMPTS) # can be set to empty + fail_transition = 300 # transition time in ms between normal outer_color and fail_color + capslock_color = -1 + numlock_color = -1 + bothlock_color = -1 # when both locks are active. -1 means don't change outer color (same for above) + invert_numlock = false # change color if numlock is off + swap_font_color = false # see below + position = 0, -470 + halign = center + valign = center +} + +# โ”€โ”€ Labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +label { + monitor = + text = cmd[update:1000] echo "$(~/.config/hypr/song-status.sh)" + color = rgba(242, 243, 244, 0.75) + font_size = 14 + font_family = {{ .font.sans.family }} + position = 20, 508 + halign = left + valign = center +} + +label { + monitor = + text = cmd[update:1000] echo "$(~/.config/hypr/network-status.sh)" + color = rgba(242, 243, 244, 0.75) + font_size = 15 + font_family = {{ .font.nerd.family }} + position = 920, 507 + halign = center + valign = center +} + +label { + monitor = + text = cmd[update:1000] echo "$(~/.config/hypr/battery-status.sh)" + color = rgba(242, 243, 244, 0.75) + font_size = 18 + font_family = {{ .font.sans.family }} + position = 863, 505 + halign = center + valign = center +} + +label { + monitor = + text = cmd[update:1000] echo "$(~/.config/hypr/layout-status.sh)" + color = rgba(242, 243, 244, 0.75) + font_size = 14 + font_family = {{ .font.sans.family }} + position = 796, 508 + halign = center + valign = center +} + +label { + monitor = + text = cmd[update:1000] echo "$(date +"%A, %B %d")" + color = rgba(242, 243, 244, 0.75) + font_size = 20 + font_family = {{ .font.sans.family }} Bold + position = 0, 400 + halign = center + valign = center +} + +label { + monitor = + text = cmd[update:1000] echo "$(date +"%k:%M")" + color = rgba(242, 243, 244, 0.75) + font_size = 93 + font_family = {{ .font.sans.family }} Bold + position = 0, 253 + halign = center + valign = center +} + +label { + monitor = + text = cmd[update:0] echo "${USER^}" + color = rgba(242, 243, 244, 0.75) + font_size = 12 + font_family = {{ .font.sans.family }} Bold + position = 0, -407 + halign = center + valign = center +} + +label { + monitor = + text = Enter Password + color = rgba(242, 243, 244, 0.75) + font_size = 10 + font_family = {{ .font.sans.family }} + position = 0, -440 + halign = center + valign = center +} + +# โ”€โ”€ Image โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +image { + monitor = + path = ~/Pictures/user-avatar.png + border_color = 0xffdddddd + border_size = 0 + size = 73 + rounding = -1 + rotate = 0 + reload_time = -1 + reload_cmd = + position = 0, -350 + halign = center + valign = center +} diff --git a/config/private_dot_config/exact_hypr/hyprpaper.conf b/config/private_dot_config/exact_hypr/hyprpaper.conf new file mode 100644 index 00000000..277d6f87 --- /dev/null +++ b/config/private_dot_config/exact_hypr/hyprpaper.conf @@ -0,0 +1,6 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ HYPRPAPER CONFIG โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +preload = ~/Pictures/wallpapers/Fantasy-Landscape3.png +wallpaper = ,~/Pictures/wallpapers/Fantasy-Landscape3.png diff --git a/config/private_dot_config/exact_hypr/hyprshade.toml b/config/private_dot_config/exact_hypr/hyprshade.toml new file mode 100644 index 00000000..011e9d6e --- /dev/null +++ b/config/private_dot_config/exact_hypr/hyprshade.toml @@ -0,0 +1,15 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ HYPRSHADE CONFIG โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +# [[shades]] +# name = "vibrance" +# default = true # shader to use during times when there is no other shader scheduled + +[[shaders]] +name = "blue-light-filter" +start_time = 19:00:00 +end_time = 06:00:00 +[shaders.config] +temperature = 3600 +strength = 1 diff --git a/config/private_dot_config/exact_nvim/create_lazy-lock.json b/config/private_dot_config/exact_nvim/create_lazy-lock.json index 40957ce5..9b5f9020 100644 --- a/config/private_dot_config/exact_nvim/create_lazy-lock.json +++ b/config/private_dot_config/exact_nvim/create_lazy-lock.json @@ -1,10 +1,9 @@ { - "CopilotChat.nvim": { "branch": "canary", "commit": "2352cd3e7e980cd73594be05f96b2dc4c0dd4a74" }, - "LazyVim": { "branch": "main", "commit": "a1c3ec4cd43fe61e3b614237a46ac92771191c81" }, - "SchemaStore.nvim": { "branch": "main", "commit": "efa0466f9f7971256ad5da010832180fc7d8996b" }, - "bufferline.nvim": { "branch": "main", "commit": "0b2fd861eee7595015b6561dade52fb060be10c4" }, - "catppuccin": { "branch": "main", "commit": "63685e1562ef53873c9764b483d7ac5c7a608922" }, - "chezmoi.nvim": { "branch": "main", "commit": "f5614261b77cb17df72ba2c4fdbc31f7ee42bc6c" }, + "CopilotChat.nvim": { "branch": "canary", "commit": "43d033b68c8bede4cc87092c7db6bb3bbb2fe145" }, + "LazyVim": { "branch": "main", "commit": "12818a6cb499456f4903c5d8e68af43753ebc869" }, + "SchemaStore.nvim": { "branch": "main", "commit": "54a2cf0105166d5a48172e81f12a2bf10cfc8b2c" }, + "catppuccin": { "branch": "main", "commit": "4fd72a9ab64b393c2c22b168508fd244877fec96" }, + "chezmoi.nvim": { "branch": "main", "commit": "e5d2b2f534d2a1701ea2f9a8849732b28ea4c8c3" }, "chezmoi.vim": { "branch": "main", "commit": "abf37336437867cbd99ce2f8849b717415391cc3" }, "cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" }, "cmp-cmdline": { "branch": "main", "commit": "d250c63aa13ead745e3a40f61fdd3470efde3923" }, @@ -12,78 +11,80 @@ "cmp-nvim-lsp": { "branch": "main", "commit": "39e2eda76828d88b773cc27a3f61d2ad782c922d" }, "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, "comment-box.nvim": { "branch": "main", "commit": "284afa6234d7a6daa809a8928df41a44b750e40f" }, - "conform.nvim": { "branch": "master", "commit": "1a99fdc1d3aa9ccdf3021e67982a679a8c5c740c" }, + "conform.nvim": { "branch": "master", "commit": "62eba813b7501b39612146cbf29cd07f1d4ac29c" }, "copilot-cmp": { "branch": "master", "commit": "b6e5286b3d74b04256d0a7e3bd2908eabec34b44" }, - "copilot.lua": { "branch": "master", "commit": "1a237cf50372830a61d92b0adf00d3b23882e0e1" }, - "crates.nvim": { "branch": "main", "commit": "5a24e3ba60e28e0cfde540696630b3c5a4db6dfd" }, + "copilot.lua": { "branch": "master", "commit": "86537b286f18783f8b67bccd78a4ef4345679625" }, + "crates.nvim": { "branch": "main", "commit": "891063a2dc8471501b9742406a514be62a20c138" }, "dashboard-nvim": { "branch": "master", "commit": "fabf5feec96185817c732d47d363f34034212685" }, - "flash.nvim": { "branch": "main", "commit": "34c7be146a91fec3555c33fe89c7d643f6ef5cf1" }, - "friendly-snippets": { "branch": "main", "commit": "00ba9dd3df89509f95437b8d595553707c46d5ea" }, - "fzf-lua": { "branch": "main", "commit": "cf4f7e095f679856fa8fe74e1539fb60fa552bdd" }, - "garbage-day.nvim": { "branch": "main", "commit": "750ef08ae6031ee3683014c5349144340c08ead6" }, - "gitsigns.nvim": { "branch": "main", "commit": "1ef74b546732f185d0f806860fa5404df7614f28" }, + "friendly-snippets": { "branch": "main", "commit": "00ebcaa159e817150bd83bfe2d51fa3b3377d5c4" }, + "fzf-lua": { "branch": "main", "commit": "9226c5a2291ef623ef157e0e1ffea034ffc8b8de" }, + "garbage-day.nvim": { "branch": "main", "commit": "4a1160bfffb2f499fb55a54333f29d160ab3c8a1" }, + "gitsigns.nvim": { "branch": "main", "commit": "80214a857ce512cc64964abddc1d8eb5a3e28396" }, "grapple.nvim": { "branch": "main", "commit": "7aedc261b05a6c030397c4bc26416efbe746ebf1" }, - "grug-far.nvim": { "branch": "main", "commit": "27a502037da8657a8b2ab7e31a6439d7b7063af5" }, + "grug-far.nvim": { "branch": "main", "commit": "ebab68b2150079732ae8074eefb261a124824139" }, "guess-indent.nvim": { "branch": "main", "commit": "6cd61f7a600bb756e558627cd2e740302c58e32d" }, - "indent-blankline.nvim": { "branch": "master", "commit": "18603eb949eba08300799f64027af11ef922283f" }, + "indent-blankline.nvim": { "branch": "master", "commit": "db926997af951da38e5004ec7b9fbdc480b48f5d" }, "lazy.nvim": { "branch": "main", "commit": "077102c5bfc578693f12377846d427f49bc50076" }, "lazydev.nvim": { "branch": "main", "commit": "491452cf1ca6f029e90ad0d0368848fac717c6d2" }, "lspkind.nvim": { "branch": "master", "commit": "cff4ae321a91ee3473a92ea1a8c637e3a9510aec" }, "lualine.nvim": { "branch": "master", "commit": "b431d228b7bbcdaea818bdc3e25b8cdbe861f056" }, "luvit-meta": { "branch": "main", "commit": "ce76f6f6cdc9201523a5875a4471dcfe0186eb60" }, "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "25c11854aa25558ee6c03432edfa0df0217324be" }, + "markdown.nvim": { "branch": "main", "commit": "7718ee87596b601ddbc93170de3a354f598185e4" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "482350b050bd413931c2cdd4857443c3da7d57cb" }, "mason-nvim-dap.nvim": { "branch": "main", "commit": "8b9363d83b5d779813cdd2819b8308651cec2a09" }, "mason-tool-installer.nvim": { "branch": "main", "commit": "c5e07b8ff54187716334d585db34282e46fa2932" }, "mason.nvim": { "branch": "main", "commit": "e2f7f9044ec30067bc11800a9e266664b88cda22" }, - "mini.ai": { "branch": "main", "commit": "40e380a589d07ec2c856940c6422aafe5d949a0d" }, - "mini.files": { "branch": "main", "commit": "a3a9cce82115a69dba161ac45bda16f4e606f73b" }, - "mini.hipatterns": { "branch": "main", "commit": "fdad87bf545aec5210ca9a2c49fddf6284d72d1e" }, - "mini.icons": { "branch": "main", "commit": "2d89252993fec829b24720097a687412d10f6c85" }, - "mini.indentscope": { "branch": "main", "commit": "da9af64649e114aa79480c238fd23f6524bc0903" }, + "mini.ai": { "branch": "main", "commit": "a9b992b13d22a8db8df6beac25afa59a10b5584d" }, + "mini.files": { "branch": "main", "commit": "916f701c6579001ead97e30aa295354f73b028d7" }, + "mini.hipatterns": { "branch": "main", "commit": "1811b0661721285fc83494d2e687d538fb3ddac8" }, + "mini.icons": { "branch": "main", "commit": "12e7b5d47bfc1b4c5ba4278fb49ec9100138df14" }, + "mini.indentscope": { "branch": "main", "commit": "d2e7b5f0260789c325f92ab3421ff9884ea01842" }, "mini.move": { "branch": "main", "commit": "4caa1c212f5ca3d1633d21cfb184808090ed74b1" }, - "mini.pairs": { "branch": "main", "commit": "e543c760edc5e746e5b6cbd02c066c17ead3ef16" }, - "mini.surround": { "branch": "main", "commit": "0e67c4bc147f2a15cee94e7c94dcc0e115b9f55e" }, - "neo-tree.nvim": { "branch": "main", "commit": "a77af2e764c5ed4038d27d1c463fa49cd4794e07" }, + "mini.pairs": { "branch": "main", "commit": "927d19cbdd0e752ab1c7eed87072e71d2cd6ff51" }, + "mini.surround": { "branch": "main", "commit": "d8913ed23be0a1a4585ae34414821cc343a46174" }, + "neo-tree.nvim": { "branch": "main", "commit": "206241e451c12f78969ff5ae53af45616ffc9b72" }, "neogen": { "branch": "main", "commit": "e932ba918b56723436b77aa3efb844a11b2851ab" }, - "neotest": { "branch": "master", "commit": "48f8b5fce704594eb0ff94338e080defca14f0dc" }, + "neotest": { "branch": "master", "commit": "6d6ad113f56edc7c3f2a77a0836ea8c1b955ebea" }, "neotest-python": { "branch": "master", "commit": "72603dfdbaad5695160268cb10531a14cc37236e" }, - "noice.nvim": { "branch": "main", "commit": "c1ba80ccf6b3bd8c7fc88fe2e61085131d44ad65" }, - "nui.nvim": { "branch": "main", "commit": "b58e2bfda5cea347c9d58b7f11cf3012c7b3953f" }, + "noice.nvim": { "branch": "main", "commit": "448bb9c524a7601035449210838e374a30153172" }, + "nui.nvim": { "branch": "main", "commit": "61574ce6e60c815b0a0c4b5655b8486ba58089a1" }, "nvim-cmp": { "branch": "main", "commit": "ae644feb7b67bf1ce4260c231d1d4300b19c6f30" }, - "nvim-dap": { "branch": "master", "commit": "90616ae6ae40053103dc66872886fc26b94c70c8" }, - "nvim-dap-python": { "branch": "master", "commit": "db72bf6ab9f75fe841e8e11e772ee7fef6f484f1" }, + "nvim-dap": { "branch": "master", "commit": "281a2e4cd1e7a17cea7ecb1745d84a8ab1249925" }, + "nvim-dap-python": { "branch": "master", "commit": "7c427e2bbc72d46ea3c9602bede6465ef61b8c19" }, "nvim-dap-repl-highlights": { "branch": "master", "commit": "a7512fc0a0de0c0be8d58983939856dda6f72451" }, "nvim-dap-ui": { "branch": "master", "commit": "1c351e4e417d4691da12948b6ecf966936a56d28" }, - "nvim-dap-virtual-text": { "branch": "master", "commit": "3497eb39bf413a57ab5b7e7e2e192683e462148c" }, - "nvim-lint": { "branch": "master", "commit": "968a35d54b3a4c1ce66609cf80b14d4ae44fe77f" }, - "nvim-lspconfig": { "branch": "master", "commit": "dd329912c8d446240584a2dbcd3802af3a19105a" }, + "nvim-dap-virtual-text": { "branch": "master", "commit": "484995d573c0f0563f6a66ebdd6c67b649489615" }, + "nvim-jdtls": { "branch": "master", "commit": "99e4b2081de1d9162666cc7b563cbeb01c26b66b" }, + "nvim-lint": { "branch": "master", "commit": "debabca63c0905b59ce596a55a8e33eafdf66342" }, + "nvim-lspconfig": { "branch": "master", "commit": "8a3610d29df83d8632f8ee7c3afc779c12725531" }, "nvim-nio": { "branch": "master", "commit": "a428f309119086dc78dd4b19306d2d67be884eee" }, - "nvim-notify": { "branch": "master", "commit": "fbef5d32be8466dd76544a257d3f3dce20082a07" }, + "nvim-notify": { "branch": "master", "commit": "d333b6f167900f6d9d42a59005d82919830626bf" }, "nvim-snippets": { "branch": "main", "commit": "56b4052f71220144689caaa2e5b66222ba5661eb" }, - "nvim-treesitter": { "branch": "master", "commit": "621f5901f0b3e762cc4c5ed0f9246cf1495193ad" }, - "nvim-treesitter-context": { "branch": "master", "commit": "3d5390c49e3f8fe457b376df2a49aa39d75b7911" }, + "nvim-treesitter": { "branch": "master", "commit": "7499f7379459db3b31c75cf5cec45f785be6e2c7" }, + "nvim-treesitter-context": { "branch": "master", "commit": "0f3332788e0bd37716fbd25f39120dcfd557c90f" }, "nvim-treesitter-endwise": { "branch": "master", "commit": "8b34305ffc28bd75a22f5a0a9928ee726a85c9a6" }, - "nvim-treesitter-textobjects": { "branch": "master", "commit": "bf8d2ad35d1d1a687eae6c065c3d524f7ab61b23" }, - "nvim-ts-autotag": { "branch": "main", "commit": "e239a560f338be31337e7abc3ee42515daf23f5e" }, + "nvim-treesitter-textobjects": { "branch": "master", "commit": "41e3abf6bfd9a9a681eb1f788bdeba91c9004b2b" }, + "nvim-ts-autotag": { "branch": "main", "commit": "0cb76eea80e9c73b88880f0ca78fbd04c5bdcac7" }, "package-info.nvim": { "branch": "master", "commit": "268f4669fc29546726009ad665d26901dbf62c3b" }, "persistence.nvim": { "branch": "main", "commit": "f6aad7dde7fcf54148ccfc5f622c6d5badd0cc3d" }, - "plenary.nvim": { "branch": "master", "commit": "2d9b06177a975543726ce5c73fca176cedbffe9d" }, + "plenary.nvim": { "branch": "master", "commit": "ec289423a1693aeae6cd0d503bac2856af74edaa" }, "refactoring.nvim": { "branch": "master", "commit": "c406fc5fb4d7ba5fce7b668637075fad6e75e9f8" }, - "render-markdown.nvim": { "branch": "main", "commit": "75a0a9596a91130fae43d3b7c0d6c651645ef1df" }, "rustaceanvim": { "branch": "master", "commit": "047f9c9d8cd2861745eb9de6c1570ee0875aa795" }, - "smart-splits.nvim": { "branch": "master", "commit": "3737faa521d12a0c77d0d28bb15ad903a9e8cfe0" }, - "tailwind-tools": { "branch": "master", "commit": "825ac68f3c3b364e30081089c6d78e8e51608a81" }, + "smart-splits.nvim": { "branch": "master", "commit": "e5209df1aa04ee2d4910a25a289efe5a978dba2f" }, + "tailwind-tools": { "branch": "master", "commit": "bf7c89151b55673c1d47f6699fc3d1a4c5b68f11" }, + "template-string.nvim": { "branch": "main", "commit": "419bfb2e4d5f0e6ddd0d4435f85b69da0d88d524" }, "template.nvim": { "branch": "main", "commit": "59955db23613985e031d340756d5c01aebd583a3" }, - "todo-comments.nvim": { "branch": "main", "commit": "ae0a2afb47cf7395dc400e5dc4e05274bf4fb9e0" }, - "tokyonight.nvim": { "branch": "main", "commit": "4b386e66a9599057587c30538d5e6192e3d1c181" }, + "todo-comments.nvim": { "branch": "main", "commit": "8f45f353dc3649cb9b44cecda96827ea88128584" }, + "toggleterm.nvim": { "branch": "main", "commit": "48be57eaba817f038d61bbf64d2c597f578c0827" }, "trouble.nvim": { "branch": "main", "commit": "6efc446226679fda0547c0fd6a7892fd5f5b15d8" }, "ts-comments.nvim": { "branch": "main", "commit": "98d7d4dec0af1312d38e288f800bbf6ff562b6ab" }, "ts-node-action": { "branch": "master", "commit": "6d3b60754fd87963d70eadaa2f77873b447eac26" }, - "typst.vim": { "branch": "main", "commit": "4d18ced62599ffe5b3c0e5e49566d5456121bc02" }, + "venv-selector.nvim": { "branch": "regexp", "commit": "c43dc6bf8c7e7cf124a991775ed3defe87112d3a" }, "vim-illuminate": { "branch": "master", "commit": "5eeb7951fc630682c322e88a9bbdae5c224ff0aa" }, - "vim-matchup": { "branch": "master", "commit": "1975afe63198ab6a0dff7200919828e5cd4330b9" }, + "vim-matchup": { "branch": "master", "commit": "1535a769d5dca851fe7d41b0be95f7c7203a4bef" }, "wezterm-types": { "branch": "main", "commit": "1518752906ba3fac0060d9efab6e4d3ec15d4b5a" }, - "which-key.nvim": { "branch": "main", "commit": "fb070344402cfc662299d9914f5546d840a22126" }, - "workspace-diagnostics.nvim": { "branch": "main", "commit": "573ff93c47898967efdfbc6587a1a39e3c2d365e" } + "which-key.nvim": { "branch": "main", "commit": "6c1584eb76b55629702716995cca4ae2798a9cca" }, + "workspace-diagnostics.nvim": { "branch": "main", "commit": "573ff93c47898967efdfbc6587a1a39e3c2d365e" }, + "yanky.nvim": { "branch": "main", "commit": "73215b77d22ebb179cef98e7e1235825431d10e4" } } diff --git a/config/private_dot_config/exact_nvim/create_lazyvim.json b/config/private_dot_config/exact_nvim/create_lazyvim.json index a7d9c44c..8e6b0ec7 100644 --- a/config/private_dot_config/exact_nvim/create_lazyvim.json +++ b/config/private_dot_config/exact_nvim/create_lazyvim.json @@ -1,8 +1,9 @@ { - "extras": [], + "extras": [ + + ], "news": { "NEWS.md": "6520" }, "version": 6 -} - +} \ No newline at end of file diff --git a/config/private_dot_config/exact_nvim/lua/exact_core/cmds.lua b/config/private_dot_config/exact_nvim/lua/exact_core/cmds.lua index a67cfc82..18bf47c2 100644 --- a/config/private_dot_config/exact_nvim/lua/exact_core/cmds.lua +++ b/config/private_dot_config/exact_nvim/lua/exact_core/cmds.lua @@ -16,6 +16,20 @@ local M = {} -- Autocommands -------------------------------------------------------------------------------- M.auto_cmds = { + -- Close some filetypes with + { + "FileType", + { + group = "close_with_q", + pattern = { + "toggleterm", + }, + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.keymap.set("n", "q", vim.cmd.close, { desc = "Close", buffer = event.buf, silent = true }) + end, + }, + }, { "FileType", { diff --git a/config/private_dot_config/exact_nvim/lua/exact_core/mappings.lua b/config/private_dot_config/exact_nvim/lua/exact_core/mappings.lua index 4c8fad99..a6e33feb 100644 --- a/config/private_dot_config/exact_nvim/lua/exact_core/mappings.lua +++ b/config/private_dot_config/exact_nvim/lua/exact_core/mappings.lua @@ -32,13 +32,20 @@ local M = { -- Terminal "ft", "fT", + "", "", }, t = { -- Terminal "", + "", "", }, + v = { + -- Indenting + "<", + ">", + }, [{ "i", "x", "n", "s" }] = { -- Save "", @@ -54,6 +61,11 @@ M.mappings[{ "n", "v" }] = { }, } +---@param cmd string +local function execute_command(cmd) + require("toggleterm").exec(cmd, nil, nil, nil, "float") +end + M.mappings.n = { -- Windows ["wh"] = { @@ -82,6 +94,41 @@ M.mappings.n = { "\"_x", desc = "Delete character without copying into register", }, + -- Run buffer executable + ["br"] = { + function() + local filetype = vim.api.nvim_get_option_value("filetype", { scope = "local" }) + + if filetype == "sh" and vim.fn.executable("sh") == 0 then + vim.notify("'.sh' files can only be executed on UNIX-based operating systems", vim.log.levels.ERROR) + return + end + + if filetype == "ps1" and vim.fn.executable("pwsh") == 0 then + vim.notify("'.ps1' files can only be executed on Windows", vim.log.levels.ERROR) + return + end + + execute_command(vim.fn.expand("%:p")) + end, + desc = "Run script", + ft = { "sh", "ps1" }, + }, + ["bl"] = { + function() + local filetype = vim.api.nvim_get_option_value("filetype", { scope = "local" }) + + local current_line = vim.api.nvim_get_current_line():gsub("^%s+", ""):gsub("%s+$", "") + + if filetype == "lua" then + vim.cmd(".lua") + elseif (filetype == "sh" and vim.fn.executable("sh")) or (filetype == "ps1" and vim.fn.executable("pwsh")) then + execute_command(current_line) + end + end, + desc = "Run line", + ft = { "lua", "sh", "ps1" }, + }, } if utils.is_unix() then diff --git a/config/private_dot_config/exact_nvim/lua/exact_languages/ansible.lua b/config/private_dot_config/exact_nvim/lua/exact_languages/ansible.lua new file mode 100644 index 00000000..5116bfd1 --- /dev/null +++ b/config/private_dot_config/exact_nvim/lua/exact_languages/ansible.lua @@ -0,0 +1,9 @@ +-- โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +-- โ”‚ Ansible โ”‚ +-- โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +return utils.plugin.get_language_spec({ + plugins = { + { import = "lazyvim.plugins.extras.lang.ansible" }, + }, +}) diff --git a/config/private_dot_config/exact_nvim/lua/exact_languages/hypr.lua b/config/private_dot_config/exact_nvim/lua/exact_languages/hypr.lua new file mode 100644 index 00000000..720f8d78 --- /dev/null +++ b/config/private_dot_config/exact_nvim/lua/exact_languages/hypr.lua @@ -0,0 +1,11 @@ +-- โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +-- โ”‚ Hyprlang โ”‚ +-- โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +return utils.plugin.get_language_spec({ + mason = "hyprls", + treesitter = "hyprlang", + lsp = { + hyprls = {}, + }, +}) diff --git a/config/private_dot_config/exact_nvim/lua/exact_languages/java.lua b/config/private_dot_config/exact_nvim/lua/exact_languages/java.lua new file mode 100644 index 00000000..2a023905 --- /dev/null +++ b/config/private_dot_config/exact_nvim/lua/exact_languages/java.lua @@ -0,0 +1,9 @@ +-- โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +-- โ”‚ Java โ”‚ +-- โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +return utils.plugin.get_language_spec({ + plugins = { + { import = "lazyvim.plugins.extras.lang.java" }, + }, +}) diff --git a/config/private_dot_config/exact_nvim/lua/exact_languages/kotlin.lua b/config/private_dot_config/exact_nvim/lua/exact_languages/kotlin.lua new file mode 100644 index 00000000..23600c59 --- /dev/null +++ b/config/private_dot_config/exact_nvim/lua/exact_languages/kotlin.lua @@ -0,0 +1,9 @@ +-- โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +-- โ”‚ Kotlin โ”‚ +-- โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +return utils.plugin.get_language_spec({ + plugins = { + { import = "lazyvim.plugins.extras.lang.kotlin" }, + }, +}) diff --git a/config/private_dot_config/exact_nvim/lua/exact_languages/nix.lua b/config/private_dot_config/exact_nvim/lua/exact_languages/nix.lua deleted file mode 100644 index e471d03b..00000000 --- a/config/private_dot_config/exact_nvim/lua/exact_languages/nix.lua +++ /dev/null @@ -1,35 +0,0 @@ --- โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ --- โ”‚ Nix โ”‚ --- โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ - -return utils.is_linux() - and utils.plugin.get_language_spec({ - lsp = { - servers = { - nil_ls = { - settings = { - ["nil"] = { - formatting = { - command = { "nixfmt" }, - }, - }, - }, - mason = false, - autostart = false, - }, - nixd = { - settings = { - nixd = { - formatting = { - command = { "nixfmt" }, - }, - }, - }, - }, - }, - }, - plugins = { - { import = "lazyvim.plugins.extras.lang.nix" }, - }, - }) - or {} diff --git a/config/private_dot_config/exact_nvim/lua/exact_languages/typst.lua b/config/private_dot_config/exact_nvim/lua/exact_languages/typst.lua deleted file mode 100644 index ee8b1295..00000000 --- a/config/private_dot_config/exact_nvim/lua/exact_languages/typst.lua +++ /dev/null @@ -1,15 +0,0 @@ -return utils.plugin.get_language_spec({ - treesitter = "typst", - mason = "typst-lsp", - lsp = { - servers = { - typst_lsp = {}, - }, - }, - plugins = { - { - "kaarmu/typst.vim", - ft = "typst", - }, - }, -}) diff --git a/config/private_dot_config/exact_nvim/lua/exact_plugins/_disabled.lua b/config/private_dot_config/exact_nvim/lua/exact_plugins/_disabled.lua index a1cc3cf9..b0bbd929 100644 --- a/config/private_dot_config/exact_nvim/lua/exact_plugins/_disabled.lua +++ b/config/private_dot_config/exact_nvim/lua/exact_plugins/_disabled.lua @@ -13,4 +13,5 @@ end, { "folke/flash.nvim", "folke/tokyonight.nvim", "roobert/tailwindcss-colorizer-cmp.nvim", + "markdown-preview.nvim", }) diff --git a/config/private_dot_config/exact_nvim/lua/exact_plugins/_extras.lua b/config/private_dot_config/exact_nvim/lua/exact_plugins/_extras.lua index 69b518ee..4403d37a 100644 --- a/config/private_dot_config/exact_nvim/lua/exact_plugins/_extras.lua +++ b/config/private_dot_config/exact_nvim/lua/exact_plugins/_extras.lua @@ -5,6 +5,7 @@ return utils.plugin.with_extensions({ { import = "lazyvim.plugins.extras.coding.neogen" }, + { import = "lazyvim.plugins.extras.coding.yanky" }, { import = "lazyvim.plugins.extras.editor.illuminate" }, { import = "lazyvim.plugins.extras.util.dot" }, { import = "lazyvim.plugins.extras.vscode" }, diff --git a/config/private_dot_config/exact_nvim/lua/exact_plugins/chezmoi.lua.tmpl b/config/private_dot_config/exact_nvim/lua/exact_plugins/chezmoi.lua.tmpl index 434a17e9..3cb7b81b 100644 --- a/config/private_dot_config/exact_nvim/lua/exact_plugins/chezmoi.lua.tmpl +++ b/config/private_dot_config/exact_nvim/lua/exact_plugins/chezmoi.lua.tmpl @@ -32,6 +32,7 @@ return { ---@type (string|{[1]:string, ft:string|string[]})[] local modify_servers = { "bashls", + { "hyprls", ft = sourceDir .. "/private_dot_config/exact_hypr/exact_hyprland/*.conf" }, "jsonls", "lua_ls", "powershell_es", diff --git a/config/private_dot_config/exact_nvim/lua/exact_plugins/toggleterm.lua b/config/private_dot_config/exact_nvim/lua/exact_plugins/toggleterm.lua new file mode 100644 index 00000000..18ec3d0d --- /dev/null +++ b/config/private_dot_config/exact_nvim/lua/exact_plugins/toggleterm.lua @@ -0,0 +1,52 @@ +local mapping = "" + +return utils.plugin.with_extensions({ + { + "akinsho/toggleterm.nvim", + version = "*", + cmd = { + "TermSelect", + "TermExec", + "ToggleTerm", + "ToggleTermToggleAll", + "ToggleTermSendVisualLines", + "ToggleTermSendVisualSelection", + "ToggleTermSendCurrentLine", + "ToggleTermSetName", + }, + keys = core.lazy_map({ + [{ "n", "i", "t" }] = { + [mapping] = { + desc = "Toggle Terminal", + }, + }, + }), + ---@module "toggleterm" + ---@param opts ToggleTermConfig + opts = function(_, opts) + ---@diagnostic disable-next-line: assign-type-mismatch + opts.size = function(term) + if term.direction == "horizontal" then + return 15 + elseif term.direction == "vertical" then + return vim.o.columns * 0.4 + end + end + + opts.open_mapping = mapping + opts.direction = "float" + + opts.highlights = opts.highlights or {} + opts.highlights.NormalFloat = { + link = "NormalFloat", + } + + opts.float_opts = opts.float_opts or {} + opts.float_opts.border = core.config.ui.transparent.floats and "curved" or "none" + opts.width = math.floor(core.config.ui.width * vim.fn.winwidth(0)) + opts.height = math.floor(core.config.ui.height * vim.fn.winheight(0)) + end, + }, +}, { + lualine = "toggleterm", +}) diff --git a/config/private_dot_config/exact_nvim/lua/exact_utils/breadcrumbs.lua b/config/private_dot_config/exact_nvim/lua/exact_utils/breadcrumbs.lua index a1e316f1..b69b034e 100644 --- a/config/private_dot_config/exact_nvim/lua/exact_utils/breadcrumbs.lua +++ b/config/private_dot_config/exact_nvim/lua/exact_utils/breadcrumbs.lua @@ -35,6 +35,7 @@ M.winbar_filetype_exclude = { "Outline", "git", "spectre_panel", + "toggleterm", "DressingSelect", "Jaq", "harpoon", diff --git a/config/private_dot_config/exact_oh-my-posh/config.yml b/config/private_dot_config/exact_oh-my-posh/config.yml index 6718592d..7a648021 100644 --- a/config/private_dot_config/exact_oh-my-posh/config.yml +++ b/config/private_dot_config/exact_oh-my-posh/config.yml @@ -17,7 +17,7 @@ blocks: style: plain foreground_templates: - '{{ if eq .OS "windows" }}#00ACEE{{ end }}' - - '{{ if eq .OS "nixos" }}#5277C3{{ end }}' + - '{{ if eq .OS "arch" }}#1894D4{{ end }}' background: transparent template: "{{ .Icon }} " - type: path diff --git a/config/private_dot_config/exact_paru/paru.conf b/config/private_dot_config/exact_paru/paru.conf new file mode 100644 index 00000000..3785c5a2 --- /dev/null +++ b/config/private_dot_config/exact_paru/paru.conf @@ -0,0 +1,14 @@ +# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ +# โ”‚ PARU CONFIG โ”‚ +# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + +[options] +BottomUp +CombinedUpgrade +Devel +DevelSuffixes = -git -cvs -svn -bzr -darcs -always -hg -fossil +FailFast +NewsOnUpgrade +Provides +PgpFetch +UpgradeMenu diff --git a/config/private_dot_config/wezterm/colors.lua b/config/private_dot_config/exact_wezterm/colors.lua similarity index 100% rename from config/private_dot_config/wezterm/colors.lua rename to config/private_dot_config/exact_wezterm/colors.lua diff --git a/config/private_dot_config/wezterm/config/appearance.lua.tmpl b/config/private_dot_config/exact_wezterm/config/appearance.lua.tmpl similarity index 100% rename from config/private_dot_config/wezterm/config/appearance.lua.tmpl rename to config/private_dot_config/exact_wezterm/config/appearance.lua.tmpl diff --git a/config/private_dot_config/wezterm/config/general.lua b/config/private_dot_config/exact_wezterm/config/general.lua similarity index 100% rename from config/private_dot_config/wezterm/config/general.lua rename to config/private_dot_config/exact_wezterm/config/general.lua diff --git a/config/private_dot_config/wezterm/config/keys.lua b/config/private_dot_config/exact_wezterm/config/keys.lua similarity index 100% rename from config/private_dot_config/wezterm/config/keys.lua rename to config/private_dot_config/exact_wezterm/config/keys.lua diff --git a/config/private_dot_config/wezterm/config/platforms/init.lua b/config/private_dot_config/exact_wezterm/config/platforms/init.lua similarity index 100% rename from config/private_dot_config/wezterm/config/platforms/init.lua rename to config/private_dot_config/exact_wezterm/config/platforms/init.lua diff --git a/config/private_dot_config/wezterm/config/platforms/linux.lua b/config/private_dot_config/exact_wezterm/config/platforms/linux.lua similarity index 89% rename from config/private_dot_config/wezterm/config/platforms/linux.lua rename to config/private_dot_config/exact_wezterm/config/platforms/linux.lua index 4f2c7b80..1edf8ca0 100644 --- a/config/private_dot_config/wezterm/config/platforms/linux.lua +++ b/config/private_dot_config/exact_wezterm/config/platforms/linux.lua @@ -11,7 +11,10 @@ function M.setup(config) config.integrated_title_button_style = "Gnome" config.bypass_mouse_reporting_modifiers = "CTRL" + -- On Hyprland config.enable_tab_bar = false + -- NOTE: Temporary solution to make WezTerm work + config.enable_wayland = false end return M diff --git a/config/private_dot_config/wezterm/config/platforms/macos.lua b/config/private_dot_config/exact_wezterm/config/platforms/macos.lua similarity index 100% rename from config/private_dot_config/wezterm/config/platforms/macos.lua rename to config/private_dot_config/exact_wezterm/config/platforms/macos.lua diff --git a/config/private_dot_config/wezterm/config/platforms/unix.lua b/config/private_dot_config/exact_wezterm/config/platforms/unix.lua similarity index 100% rename from config/private_dot_config/wezterm/config/platforms/unix.lua rename to config/private_dot_config/exact_wezterm/config/platforms/unix.lua diff --git a/config/private_dot_config/wezterm/config/platforms/windows.lua.tmpl b/config/private_dot_config/exact_wezterm/config/platforms/windows.lua.tmpl similarity index 100% rename from config/private_dot_config/wezterm/config/platforms/windows.lua.tmpl rename to config/private_dot_config/exact_wezterm/config/platforms/windows.lua.tmpl diff --git a/config/private_dot_config/wezterm/utils.lua b/config/private_dot_config/exact_wezterm/utils.lua similarity index 100% rename from config/private_dot_config/wezterm/utils.lua rename to config/private_dot_config/exact_wezterm/utils.lua diff --git a/config/private_dot_config/wezterm/wezterm.lua b/config/private_dot_config/exact_wezterm/wezterm.lua similarity index 100% rename from config/private_dot_config/wezterm/wezterm.lua rename to config/private_dot_config/exact_wezterm/wezterm.lua diff --git a/config/private_dot_config/private_spicetify/config-xpui.ini.tmpl b/config/private_dot_config/private_spicetify/config-xpui.ini.tmpl new file mode 100644 index 00000000..5cda929a --- /dev/null +++ b/config/private_dot_config/private_spicetify/config-xpui.ini.tmpl @@ -0,0 +1 @@ +{{- template "spicetify/config-xpui.ini" dict "spotify_path" (eq .chezmoi.os "darwin" | ternary "/Applications/Spotify.app/Contents/Resources" "$HOME/.local/share/spotify-launcher/install/usr/share/spotify") "prefs_path" (printf "%s%s" .chezmoi.homeDir "/.config/spotify/prefs") -}} diff --git a/config/private_dot_config/qt5ct/qt5ct.conf.tmpl b/config/private_dot_config/qt5ct/qt5ct.conf.tmpl new file mode 100644 index 00000000..276d235a --- /dev/null +++ b/config/private_dot_config/qt5ct/qt5ct.conf.tmpl @@ -0,0 +1 @@ +{{- template "qt/qt.conf" (dict "qt" "5" "font" (dict "nerd" (dict "family" .font.nerd.family) "sans" (dict "family" .font.sans.family)) "icon_theme" .gtk.icon.theme.name) -}} diff --git a/config/private_dot_config/qt6ct/qt6ct.conf.tmpl b/config/private_dot_config/qt6ct/qt6ct.conf.tmpl new file mode 100644 index 00000000..724f317a --- /dev/null +++ b/config/private_dot_config/qt6ct/qt6ct.conf.tmpl @@ -0,0 +1 @@ +{{- template "qt/qt.conf" (dict "qt" "6" "font" (dict "nerd" (dict "family" .font.nerd.family) "sans" (dict "family" .font.sans.family)) "icon_theme" .gtk.icon.theme.name) -}} diff --git a/config/private_dot_config/tmux/tmux.conf b/config/private_dot_config/tmux/tmux.conf index d3f09ead..69eb2e69 100644 --- a/config/private_dot_config/tmux/tmux.conf +++ b/config/private_dot_config/tmux/tmux.conf @@ -6,6 +6,11 @@ set-option -g default-terminal "$TERM" set-option -g terminal-overrides ",$TERM:RGB" +# Allow undercurls for terminals that support them. +set -as terminal-overrides ",*:Smulx=\E[4::%p1%dm" +# Allow coloured undercurls for terminals that support them. +set -as terminal-overrides ",*:Setulc=\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m" + # Change prefix from C-b to C-a unbind C-b set-option -g prefix C-a @@ -28,12 +33,7 @@ set -g set-clipboard on # โ”€โ”€ Keybindings โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# Copy mode -unbind [ -bind-key v copy-mode -unbind ] -bind-key p paste-buffer - +# Set vi-mode set-window-option -g mode-keys vi bind-key -T copy-mode-vi v send-keys -X begin-selection bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle @@ -41,7 +41,7 @@ bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel # Switch windows unbind C-p -bind -n C-M-h previous-window +bind -n C-M-h previous-window unbind C-n bind -n C-M-l next-window # Rename window @@ -74,8 +74,8 @@ bind -r C-Down resize-pane -D 4 # Maximize current pane unbind z bind -r Space resize-pane -Z -# FIX: C-/ for Vim -bind -n C-_ send-keys C-/ +# Open command prompt +bind : command-prompt # โ”€โ”€ Plugins โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ set -g @plugin "tmux-plugins/tpm" @@ -84,7 +84,7 @@ set -g @plugin "tmux-plugins/tmux-resurrect" set -g @plugin "tmux-plugins/tmux-continuum" set -g @plugin "tmux-plugins/tmux-yank" set -g @plugin "christoomey/vim-tmux-navigator" -set -g @plugin "janoamaral/tokyo-night-tmux" +set -g @plugin "catppuccin/tmux" set -g @plugin "omerxx/tmux-sessionx" # โ”€โ”€ Session โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @@ -100,22 +100,27 @@ set -g @resurrect-strategy-nvim "session" # โ”€โ”€ Theme โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ set -g status-position "top" - -# ID styles -set -g @tokyo-night-tmux_window_id_style digital -set -g @tokyo-night-tmux_pane_id_style hide -set -g @tokyo-night-tmux_zoom_id_style dsquare - -# Widgets -set -g @tokyo-night-tmux_show_path 1 -set -g @tokyo-night-tmux_path_format relative - -set -g @tokyo-night-tmux_show_git 1 - -# Disabled widgets -set -g @tokyo-night-tmux_show_battery_widget 0 -set -g @tokyo-night-tmux_show_datetime 0 -set -g @tokyo-night-tmux_show_music 0 +set -g pane-active-border-style "fg=magenta,bg=default" +set -g pane-border-style "fg=brightblack,bg=default" + +set -g @catppuccin_flavour "mocha" +set -g @catppuccin_window_left_separator " โ–ˆ" +set -g @catppuccin_window_right_separator "โ–ˆ" +set -g @catppuccin_window_middle_separator " ๓ฐœต " +set -g @catppuccin_window_number_position "left" +set -g @catppuccin_window_default_fill "none" +set -g @catppuccin_window_default_text "#W" +set -g @catppuccin_window_current_fill "all" +set -g @catppuccin_window_current_text "#W#{?window_zoomed_flag,(๎ฎ),}" +set -g @catppuccin_status_modules_right "directory date_time", +set -g @catppuccin_status_modules_left "session" +set -g @catppuccin_status_left_separator "โ–ˆ" +set -g @catppuccin_status_right_separator "โ–ˆ" +set -g @catppuccin_status_right_separator_inverse "no" +set -g @catppuccin_status_fill "icon" +set -g @catppuccin_status_connect_separator "no" +set -g @catppuccin_directory_text "#{b:pane_current_path}" +set -g @catppuccin_date_time_text "%d.%m.%Y %H:%M" # Other examples: # set -g @plugin 'github_username/plugin_name' @@ -123,9 +128,5 @@ set -g @tokyo-night-tmux_show_music 0 # set -g @plugin 'git@github.com:user/plugin' # set -g @plugin 'git@bitbucket.com:user/plugin' -# Automatically install plugins -if "test ! -d ~/.config/tmux/plugins/tpm" \ - "run 'git clone https://github.com/tmux-plugins/tpm ~/.config/tmux/plugins/tpm && ~/.config/tmux/plugins/tpm/bin/install_plugins'" - # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) run "~/.config/tmux/plugins/tpm/tpm" diff --git a/config/private_dot_local/share/icons/Snapdrop.png b/config/private_dot_local/share/icons/Snapdrop.png new file mode 100644 index 0000000000000000000000000000000000000000..dea9233553d9a57b66ddf5a4adc1d4586e484372 GIT binary patch literal 42050 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 literal 0 HcmV?d00001 diff --git a/config/private_dot_local/share/private_applications/snapdrop.desktop.tmpl b/config/private_dot_local/share/private_applications/snapdrop.desktop.tmpl new file mode 100644 index 00000000..44990dc4 --- /dev/null +++ b/config/private_dot_local/share/private_applications/snapdrop.desktop.tmpl @@ -0,0 +1 @@ +{{- template "entry.desktop" dict "name" "Snapdrop" "comment" "The easiest way to transfer files across devices" "url" "https://snapdrop.net" "categories" (list "Network" "FileTransfer") -}} diff --git a/config/private_dot_ssh/config b/config/private_dot_ssh/config index 58a2c604..7ec98fea 100644 --- a/config/private_dot_ssh/config +++ b/config/private_dot_ssh/config @@ -2,17 +2,5 @@ # โ”‚ SSH CONFIG โ”‚ # โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -Host * - ForwardAgent no - AddKeysToAgent yes - Compression no - ServerAliveInterval 0 - ServerAliveCountMax 3 - HashKnownHosts no - UserKnownHostsFile ~/.ssh/known_hosts - ControlMaster no - ControlPath ~/.ssh/master-%r@%n:%p - ControlPersist no - Host github.com User git diff --git a/nix/config.nix b/nix/config.nix deleted file mode 100644 index 35fd92cd..00000000 --- a/nix/config.nix +++ /dev/null @@ -1,45 +0,0 @@ -{ pkgs, ... }: -{ - # User Info - hostname = "nixstation"; - username = "nhan"; - description = "Nhan Pham"; - # Theme - theme = { - name = "adw-gtk3-dark"; - package = pkgs.adw-gtk3; - }; - cursorTheme = { - name = "macOS"; - package = pkgs.apple-cursor; - size = 24; - }; - iconTheme = { - name = "WhiteSur"; - package = pkgs.whitesur-icon-theme.override { - alternativeIcons = true; - boldPanelIcons = true; - }; - }; - # Fonts - font = { - sans = { - name = "Rubik"; - package = pkgs.rubik; - }; - mono = { - name = "MonaspiceNe Nerd Font Mono"; - package = pkgs.nerdfonts.override { - fonts = [ - "Iosevka" # For Unicode characters - "Monaspace" - "NerdFontsSymbolsOnly" - ]; - }; - }; - emoji = { - name = "Noto Color Emoji"; - package = pkgs.noto-fonts-color-emoji; - }; - }; -} diff --git a/nix/flake.lock b/nix/flake.lock deleted file mode 100644 index b01b7242..00000000 --- a/nix/flake.lock +++ /dev/null @@ -1,464 +0,0 @@ -{ - "nodes": { - "Hyprspace": { - "inputs": { - "hyprland": [ - "hyprland" - ] - }, - "locked": { - "lastModified": 1726437584, - "narHash": "sha256-lMIFDORuyMYHtUPrRWU5WjGcS+ZMrR4/wBSO+sgUVSY=", - "owner": "KZDKM", - "repo": "Hyprspace", - "rev": "8f14fa2e10d24742d713f04c278bc7651037b74b", - "type": "github" - }, - "original": { - "owner": "KZDKM", - "repo": "Hyprspace", - "type": "github" - } - }, - "aquamarine": { - "inputs": { - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "hyprwayland-scanner": [ - "hyprland", - "hyprwayland-scanner" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1727261104, - "narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=", - "owner": "hyprwm", - "repo": "aquamarine", - "rev": "b82fdaff917582a9d568969e15e61b398c71e990", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "aquamarine", - "type": "github" - } - }, - "firefox-gnome-theme": { - "flake": false, - "locked": { - "lastModified": 1723137499, - "narHash": "sha256-MOE9NeU2i6Ws1GhGmppMnjOHkNLl2MQMJmGhaMzdoJM=", - "owner": "rafaelmardojai", - "repo": "firefox-gnome-theme", - "rev": "fb5b578a4f49ae8705e5fea0419242ed1b8dba70", - "type": "github" - }, - "original": { - "owner": "rafaelmardojai", - "repo": "firefox-gnome-theme", - "type": "github" - } - }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1726153070, - "narHash": "sha256-HO4zgY0ekfwO5bX0QH/3kJ/h4KvUDFZg8YpkNwIbg1U=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "bcef6817a8b2aa20a5a6dbb19b43e63c5bf8619a", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, - "home-manager": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1727383923, - "narHash": "sha256-4/vacp3CwdGoPf8U4e/N8OsGYtO09WTcQK5FqYfJbKs=", - "owner": "nix-community", - "repo": "home-manager", - "rev": "ffe2d07e771580a005e675108212597e5b367d2d", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "home-manager", - "type": "github" - } - }, - "hyprcursor": { - "inputs": { - "hyprlang": [ - "hyprland", - "hyprlang" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1722623071, - "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", - "owner": "hyprwm", - "repo": "hyprcursor", - "rev": "912d56025f03d41b1ad29510c423757b4379eb1c", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprcursor", - "type": "github" - } - }, - "hyprland": { - "inputs": { - "aquamarine": "aquamarine", - "hyprcursor": "hyprcursor", - "hyprland-protocols": "hyprland-protocols", - "hyprlang": "hyprlang", - "hyprutils": "hyprutils", - "hyprwayland-scanner": "hyprwayland-scanner", - "nixpkgs": "nixpkgs", - "systems": "systems", - "xdph": "xdph" - }, - "locked": { - "lastModified": 1727451329, - "narHash": "sha256-ysRNFO8X0qE3/+xWcYMY+v94WurNvvdDKlGVLT/aKmA=", - "ref": "refs/heads/main", - "rev": "58669fef77ac17ea205ce3570f48e17de736111f", - "revCount": 5272, - "submodules": true, - "type": "git", - "url": "https://github.com/hyprwm/Hyprland" - }, - "original": { - "submodules": true, - "type": "git", - "url": "https://github.com/hyprwm/Hyprland" - } - }, - "hyprland-contrib": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1725551787, - "narHash": "sha256-6LgsZHz8w3g4c9bRUwRAR+WIMwFGGf3P1VZQcKNRf2o=", - "owner": "hyprwm", - "repo": "contrib", - "rev": "1e531dc49ad36c88b45bf836081a7a2c8927e072", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "contrib", - "type": "github" - } - }, - "hyprland-protocols": { - "inputs": { - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1727451107, - "narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=", - "owner": "hyprwm", - "repo": "hyprland-protocols", - "rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprland-protocols", - "type": "github" - } - }, - "hyprland-protocols_2": { - "inputs": { - "nixpkgs": [ - "hyprland", - "xdph", - "nixpkgs" - ], - "systems": [ - "hyprland", - "xdph", - "systems" - ] - }, - "locked": { - "lastModified": 1721326555, - "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", - "owner": "hyprwm", - "repo": "hyprland-protocols", - "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprland-protocols", - "type": "github" - } - }, - "hyprlang": { - "inputs": { - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1725997860, - "narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=", - "owner": "hyprwm", - "repo": "hyprlang", - "rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprlang", - "type": "github" - } - }, - "hyprswitch": { - "inputs": { - "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1725107917, - "narHash": "sha256-6on3nwb3gB4t+P/2IExgGhVLVgAkF6ZiE5x+qcQHEXU=", - "owner": "h3rmt", - "repo": "hyprswitch", - "rev": "f478c394ad6db5ba268f80052f1eb2366366b21e", - "type": "github" - }, - "original": { - "owner": "h3rmt", - "ref": "release", - "repo": "hyprswitch", - "type": "github" - } - }, - "hyprutils": { - "inputs": { - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1727300645, - "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=", - "owner": "hyprwm", - "repo": "hyprutils", - "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprutils", - "type": "github" - } - }, - "hyprwayland-scanner": { - "inputs": { - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1726874836, - "narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=", - "owner": "hyprwm", - "repo": "hyprwayland-scanner", - "rev": "500c81a9e1a76760371049a8d99e008ea77aa59e", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprwayland-scanner", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1727122398, - "narHash": "sha256-o8VBeCWHBxGd4kVMceIayf5GApqTavJbTa44Xcg5Rrk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "30439d93eb8b19861ccbe3e581abf97bdc91b093", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1725233747, - "narHash": "sha256-Ss8QWLXdr2JCBPcYChJhz4xJm+h/xjl4G0c0XlP6a74=", - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/356624c12086a18f2ea2825fed34523d60ccc4e3.tar.gz" - }, - "original": { - "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/356624c12086a18f2ea2825fed34523d60ccc4e3.tar.gz" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1711588226, - "narHash": "sha256-nd7goEu+nH/WZ/uCxvbWzSYqzZZn25kWTeKfANOhCjU=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "7232f19f7fb710e3554cafaa9d8e93cff8273b59", - "type": "github" - }, - "original": { - "owner": "nixos", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1727348695, - "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "Hyprspace": "Hyprspace", - "firefox-gnome-theme": "firefox-gnome-theme", - "home-manager": "home-manager", - "hyprland": "hyprland", - "hyprland-contrib": "hyprland-contrib", - "hyprswitch": "hyprswitch", - "nixpkgs": "nixpkgs_3" - } - }, - "systems": { - "locked": { - "lastModified": 1689347949, - "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", - "owner": "nix-systems", - "repo": "default-linux", - "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default-linux", - "type": "github" - } - }, - "xdph": { - "inputs": { - "hyprland-protocols": "hyprland-protocols_2", - "hyprlang": [ - "hyprland", - "hyprlang" - ], - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "hyprwayland-scanner": [ - "hyprland", - "hyprwayland-scanner" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1727109343, - "narHash": "sha256-1PFckA8Im7wMSl26okwOKqBZeCFLD3LvZZFaxswDhbY=", - "owner": "hyprwm", - "repo": "xdg-desktop-portal-hyprland", - "rev": "4adb6c4c41ee5014bfe608123bfeddb26e5f5cea", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "xdg-desktop-portal-hyprland", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/nix/flake.nix b/nix/flake.nix deleted file mode 100644 index bea02e75..00000000 --- a/nix/flake.nix +++ /dev/null @@ -1,90 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ NIX FLAKE โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - description = "NixOS Configuration of Nitestack"; - - # โ”€โ”€ Inputs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - inputs = { - # Nixpkgs - nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - - # Home Manager - home-manager = { - url = "github:nix-community/home-manager"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # Hyprland - hyprland.url = "git+https://github.com/hyprwm/Hyprland?submodules=1"; - - # Hyprswitch - hyprswitch.url = "github:h3rmt/hyprswitch/release"; - - # Hyprspace - Hyprspace = { - url = "github:KZDKM/Hyprspace"; - inputs.hyprland.follows = "hyprland"; - }; - - # Hyprland Contrib - hyprland-contrib = { - url = "github:hyprwm/contrib"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - - # Firefox GNOME Theme - firefox-gnome-theme = { - url = "github:rafaelmardojai/firefox-gnome-theme"; - flake = false; - }; - }; - - # โ”€โ”€ Outputs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - outputs = - { - self, - nixpkgs, - home-manager, - ... - }@inputs: - let - inherit (self) outputs; - - # Supported Systems - systems = [ - "aarch64-linux" - "x86_64-linux" - "aarch64-darwin" - ]; - - forAllSystems = nixpkgs.lib.genAttrs systems; - in - { - packages = forAllSystems (system: import ./pkgs nixpkgs.legacyPackages.${system}); - formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt-rfc-style); - overlays = import ./overlays; - nixosModules = import ./nixos/modules; - homeManagerModules = import ./home-manager/modules; - nixosConfigurations = - let - meta = import ./config.nix { - pkgs = import { - config.allowUnfree = true; - }; - }; - in - { - ${meta.hostname} = nixpkgs.lib.nixosSystem { - specialArgs = { - inherit inputs outputs meta; - }; - system = "x86_64-linux"; - modules = [ - home-manager.nixosModules.home-manager - ./nixos/configuration.nix - ]; - }; - }; - }; -} diff --git a/nix/home-manager/bat.nix b/nix/home-manager/bat.nix deleted file mode 100644 index b58a7972..00000000 --- a/nix/home-manager/bat.nix +++ /dev/null @@ -1,18 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ bat โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ pkgs, ... }: -{ - programs.bat = { - enable = true; - themes."Catppuccin Mocha" = { - src = pkgs.fetchFromGitHub { - owner = "catppuccin"; - repo = "bat"; - rev = "d3feec47b16a8e99eabb34cdfbaa115541d374fc"; - sha256 = "1g73x0p8pbzb8d1g1x1fwhwf05sj3nzhbhb65811752p5178fh5k"; - }; - file = "themes/Catppuccin Mocha.tmTheme"; - }; - }; -} diff --git a/nix/home-manager/browser.nix b/nix/home-manager/browser.nix deleted file mode 100644 index 55537a1c..00000000 --- a/nix/home-manager/browser.nix +++ /dev/null @@ -1,38 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Browser โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ inputs, ... }: -{ - home = { - sessionVariables.BROWSER = "firefox"; - - file."firefox-gnome-theme" = { - target = ".mozilla/firefox/default/chrome/firefox-gnome-theme"; - source = inputs.firefox-gnome-theme; - }; - }; - - programs.firefox = { - enable = true; - profiles.default = { - name = "Default"; - settings = { - "browser.tabs.loadInBackground" = true; - "widget.gtk.rounded-bottom-corners.enabled" = true; - "toolkit.legacyUserProfileCustomizations.stylesheets" = true; - "svg.context-properties.content.enabled" = true; - "gnomeTheme.hideSingleTab" = true; - "gnomeTheme.systemIcons" = true; - "gnomeTheme.bookmarksToolbarUnderTabs" = true; - "gnomeTheme.normalWidthTabs" = false; - "gnomeTheme.tabsAsHeaderbar" = false; - }; - userChrome = '' - @import "firefox-gnome-theme/userChrome.css"; - ''; - userContent = '' - @import "firefox-gnome-theme/userContent.css"; - ''; - }; - }; -} diff --git a/nix/home-manager/dunst.nix b/nix/home-manager/dunst.nix deleted file mode 100644 index f089d86b..00000000 --- a/nix/home-manager/dunst.nix +++ /dev/null @@ -1,34 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Dunst โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ meta, ... }: -let - inherit (meta) font iconTheme; -in -{ - services.dunst = { - inherit iconTheme; - enable = true; - settings = { - global = { - font = font.sans.name; - - frame_color = "#89b4fa"; - separator_color = "frame"; - }; - urgency_low = { - background = "#1e1e2e"; - foreground = "#cdd6f4"; - }; - urgency_normal = { - background = "#1e1e2e"; - foreground = "#cdd6f4"; - }; - urgency_critical = { - background = "#1e1e2e"; - foreground = "#cdd6f4"; - frame_color = "#fab387"; - }; - }; - }; -} diff --git a/nix/home-manager/git.nix b/nix/home-manager/git.nix deleted file mode 100644 index da7c1ac6..00000000 --- a/nix/home-manager/git.nix +++ /dev/null @@ -1,28 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Git โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -let - githubUsername = "Nitestack"; -in -{ - programs.git = { - enable = true; - userName = githubUsername; - userEmail = "74626967+${githubUsername}@users.noreply.github.com"; - extraConfig = { - core.editor = "nvim"; - push.autoSetupRemote = true; - pull.rebase = true; - merge.autoStash = true; - rebase.autoStash = true; - init.defaultBranch = "main"; - color.ui = true; - }; - delta.enable = true; - }; - programs.ssh = { - enable = true; - addKeysToAgent = "yes"; - }; - services.ssh-agent.enable = true; -} diff --git a/nix/home-manager/home.nix b/nix/home-manager/home.nix deleted file mode 100644 index 26d16b54..00000000 --- a/nix/home-manager/home.nix +++ /dev/null @@ -1,101 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ HOME MANAGER CONFIGURATION โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - pkgs, - meta, - config, - ... -}: -{ - # โ”€โ”€ Imports โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - imports = [ - ./bat.nix - ./browser.nix - ./dunst.nix - ./eza.nix - ./fzf.nix - ./git.nix - ./hyprland - ./kitty.nix - ./rofi.nix - ./theme.nix - # ./wezterm.nix - - ./scripts - ]; - - # โ”€โ”€ Configuration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - home = { - username = meta.username; - homeDirectory = "/home/${meta.username}"; - - # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion - stateVersion = "24.05"; - }; - - xdg = { - enable = true; - desktopEntries = - let - googleChrome = "${pkgs.google-chrome}/bin/google-chrome-stable"; - in - { - snapdrop = { - name = "Snapdrop"; - comment = "The easiest way to transfer files across devices"; - categories = [ - "Network" - "FileTransfer" - ]; - exec = "${googleChrome} --app=https://snapdrop.net --name=Snapdrop"; - icon = "${pkgs.fetchurl { - url = "https://raw.githubusercontent.com/snapdrop/snapdrop/master/client/images/logo_transparent_512x512.png"; - sha256 = "sha256-QMgXdeaNxg+e71dKAojR1h1zcpwBCNX10JQfD0fqhes="; - }}"; - }; - }; - userDirs = { - enable = true; - createDirectories = true; - extraConfig = { - XDG_SCREENSHOTS_DIR = "${config.xdg.userDirs.pictures}/Screenshots"; - }; - }; - }; - - news.display = "show"; - - # โ”€โ”€ Programs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - programs = { - btop.enable = true; - fastfetch.enable = true; - fd.enable = true; - home-manager.enable = true; - jq.enable = true; - less.enable = true; - neovim = { - enable = true; - defaultEditor = true; - viAlias = true; - vimAlias = true; - vimdiffAlias = true; - }; - oh-my-posh = { - enable = true; - enableZshIntegration = true; - }; - ripgrep.enable = true; - vscode.enable = true; - zoxide = { - enable = true; - enableZshIntegration = true; - }; - }; - - # โ”€โ”€ Services โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - services = { - cliphist.enable = true; - easyeffects.enable = true; - }; -} diff --git a/nix/home-manager/hyprland/default.nix b/nix/home-manager/hyprland/default.nix deleted file mode 100644 index 445e3e38..00000000 --- a/nix/home-manager/hyprland/default.nix +++ /dev/null @@ -1,417 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Hyprland โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - inputs, - pkgs, - config, - meta, - ... -}: -let - inherit (meta) cursorTheme; - - grimblast_pkg = inputs.hyprland-contrib.packages.${pkgs.stdenv.hostPlatform.system}.grimblast; - hyprswitch_pkg = inputs.hyprswitch.packages.${pkgs.stdenv.hostPlatform.system}.default; -in -{ - imports = [ - ./hypridle.nix - ./hyprlock.nix - ./hyprpaper.nix - ./hyprshade.nix - ]; - - home.packages = [ - pkgs.brightnessctl - grimblast_pkg - pkgs.hyprcursor - pkgs.hyprpicker - hyprswitch_pkg - pkgs.wl-clip-persist - pkgs.wl-clipboard - ]; - - xdg.configFile."hypr/hyprswitch.css".text = '' - .client-index { - display: none; - } - ''; - - wayland.windowManager.hyprland = { - enable = true; - package = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.hyprland; - xwayland.enable = true; - systemd = { - enable = true; - variables = [ "--all" ]; - }; - plugins = [ - inputs.Hyprspace.packages.${pkgs.system}.Hyprspace - ]; - - settings = - let - # Bins - brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl"; - cliphist = "${pkgs.cliphist}/bin/cliphist"; - firefox = "${pkgs.firefox}/bin/firefox"; - gnome-system-monitor = "${pkgs.gnome-system-monitor}/bin/gnome-system-monitor"; - grimblast = "${grimblast_pkg}/bin/grimblast"; - hyprctl = "${pkgs.hyprland}/bin/hyprctl"; - hyprshade = "${pkgs.hyprshade}/bin/hyprshade"; - hyprswitch = "${hyprswitch_pkg}/bin/hyprswitch"; - nautilus = "${pkgs.nautilus}/bin/nautilus"; - playerctl = "${pkgs.playerctl}/bin/playerctl"; - rofi = "${pkgs.rofi-wayland}/bin/rofi"; - safeeyes = "${pkgs.safeeyes}/bin/safeeyes"; - snixembed = "${pkgs.snixembed}/bin/snixembed"; - spotify = "${pkgs.spotify}/bin/spotify"; - webcord = "${pkgs.webcord}/bin/webcord"; - wl-clip-persist = "${pkgs.wl-clip-persist}/bin/wl-clip-persist"; - wl-copy = "${pkgs.wl-clipboard}/bin/wl-copy"; - wl-paste = "${pkgs.wl-clipboard}/bin/wl-paste"; - wpctl = "${pkgs.wireplumber}/bin/wpctl"; - - kitty_startup_script = "${pkgs.kitty}/bin/kitty tmux"; - - cliphist-rofi-img = pkgs.writeShellScriptBin "cliphist-rofi-img" '' - #!/usr/bin/env bash - - tmp_dir="/tmp/cliphist" - rm -rf "$tmp_dir" - - if [[ -n "$1" ]]; then - ${cliphist} decode <<<"$1" | ${wl-copy} - exit - fi - - mkdir -p "$tmp_dir" - - read -r -d \'\' prog <$tmp_dir/"grp[1]"."grp[3]) - print \$0"\0icon\x1f$tmp_dir/"grp[1]"."grp[3] - next - } - 1 - EOF - ${cliphist} list | ${pkgs.gawk}/bin/gawk "$prog" - ''; - screenshots_dir = "${config.xdg.userDirs.pictures}/Screenshots"; - in - { - # โ”€โ”€ Autostart โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - exec-once = [ - "${snixembed} --fork" - "${safeeyes} -e" - "${wl-clip-persist} --clipboard regular" - "${wl-paste} --type text --watch ${cliphist} store" - "${wl-paste} --type image --watch ${cliphist} store" - "${hyprswitch} init --show-title --custom-css ${config.xdg.configHome}/hypr/hyprswitch.css &" - "${hyprctl} setcursor ${cursorTheme.name} ${toString cursorTheme.size}" - - "[workspace 1 silent] ${firefox}" - "[workspace 2 silent] ${kitty_startup_script}" - "[workspace 3 silent] ${webcord}" - "[workspace 4 silent] ${spotify}" - ]; - exec = [ - "${hyprshade} auto" - ]; - - # โ”€โ”€ Environment Variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - # https://wiki.hyprland.org/Configuring/Environment-variables - env = [ - # Toolkit Backend Variables - "CLUTTER_BACKEND,wayland" # Clutter package already has wayland enabled, this variable will force Clutter applications to try and use the Wayland backend - "GDK_BACKEND,wayland,x11,*" # GTK: Use wayland if available. If not: try x11, then any other GDK backend. - "SDL_VIDEODRIVER,wayland,x11" # Run SDL2 applications on Wayland. Remove or set to x11 if games that provide older versions of SDL cause compatibility issues - - # XDG Specifications - "XDG_CURRENT_DESKTOP,Hyprland" - "XDG_SESSION_TYPE,wayland" - "XDG_SESSION_DESKTOP,Hyprland" - - # Qt Variables - "QT_AUTO_SCREEN_SCALE_FACTOR,1" # Enables automatic scaling, based on the monitorโ€™s pixel density - "QT_QPA_PLATFORM,wayland;xcb" # Tell Qt applications to use the Wayland backend, and fall back to x11 if Wayland is unavailable - "QT_WAYLAND_DISABLE_WINDOWDECORATION,1" # Disables window decorations on Qt applications - "QT_QPA_PLATFORMTHEME,qt6ct" # Tells Qt based applications to pick your theme from qt6ct, use with Kvantum. - "QT_STYLE_OVERRIDE,kvantum" - ]; - - # โ”€โ”€ Config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - # https://wiki.hyprland.org/Configuring/Variables - - # Monitors - # https://wiki.hyprland.org/Configuring/Monitors - monitor = [ - "DP-1, 1920x1080@144, 0x0, 1" - # "DP-2, 1920x1080@144, 1920x0, 1" # In case of a second monitor - ]; - - # General - # https://wiki.hyprland.org/Configuring/Variables/#general - general = { - gaps_in = 10; # gaps between windows, also supports css style gaps (top, right, bottom, left -> 5,10,15,20) - gaps_out = 10; # gaps between windows and monitor edges, also supports css style gaps (top, right, bottom, left -> 5,10,15,20) - - border_size = 3; # size of the border around windows - - "col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg"; # border color for the active window - "col.inactive_border" = "rgba(595959aa)"; # border color for inactive windows - - resize_on_border = true; # enables resizing windows by clicking and dragging on borders and gaps - - allow_tearing = true; # master switch for allowing tearing to occur - }; - - # Decoration - # https://wiki.hyprland.org/Configuring/Variables/#decoration - decoration = { - rounding = 10; # rounded corners' radius (in layout px) - - drop_shadow = true; # enable drop shadows on windows - shadow_ignore_window = true; # if true, the shadow will not be rendered behind the window itself, only around it - shadow_offset = "2 2"; # shadowโ€™s rendering offset - shadow_range = 8; # Shadow range (โ€œsizeโ€) in layout px - shadow_render_power = 2; # in what power to render the falloff (more power, the faster the falloff) [1 - 4] - "col.shadow" = "0x66000000"; # shadowโ€™s color. Alpha dictates shadowโ€™s opacity - - # Blur - # https://wiki.hyprland.org/Configuring/Variables/#blur - blur = { - enabled = true; # enable kawase window background blur - size = 3; # blur size (distance) - passes = 2; # the amount of passes to perform - }; - }; - - # Animations - # https://wiki.hyprland.org/Configuring/Variables/#animations - animations = { - enabled = true; # enable animations - - # https://wiki.hyprland.org/Configuring/Animations - bezier = [ - "overshot, 0.05, 0.9, 0.1, 1.05" - "smoothOut, 0.36, 0, 0.66, -0.56" - "smoothIn, 0.25, 1, 0.5, 1" - ]; - animation = [ - "windows, 1, 5, overshot, slide" - "windowsOut, 1, 4, smoothOut, slide" - "windowsMove, 1, 4, default" - "border, 1, 10, default" - "fade, 1, 10, smoothIn" - "fadeDim, 1, 10, smoothIn" - "workspaces, 1, 6, default" - "specialWorkspace, 1, 4, default, slidevert" - ]; - }; - - # Input - # https://wiki.hyprland.org/Configuring/Variables/#input - input = { - # Toggle between US QWERTY and US Intl QWERTY layout on `Win + Space` - # https://wiki.hyprland.org/Configuring/Variables/#xkb-settings - kb_layout = "us, us"; - kb_variant = "basic, intl"; - kb_model = ""; - kb_options = "grp:win_space_toggle"; - kb_rules = ""; - - # Specify if and how cursor movement should affect window focus. - # https://wiki.hyprland.org/Configuring/Variables/#follow-mouse-cursor - follow_mouse = 2; - - # Touchpad - # https://wiki.hyprland.org/Configuring/Variables/#touchpad - touchpad = { - natural_scroll = true; # Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar - }; - }; - - # Gestures - # https://wiki.hyprland.org/Configuring/Variables/#gestures - gestures = { - workspace_swipe = true; # enable workspace swipe gesture on touchpad - }; - - # Miscellaneous - # https://wiki.hyprland.org/Configuring/Variables/#misc - misc = { - disable_hyprland_logo = true; # disables the random Hyprland logo / anime girl background - disable_splash_rendering = true; # disables the Hyprland splash rendering. (requires a monitor reload to take effect) - force_default_wallpaper = 0; # Enforce any of the 3 default wallpapers. Setting this to 0 or 1 disables the anime background. -1 means โ€œrandomโ€ - vrr = 2; # controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only - animate_manual_resizes = true; # If true, will animate manual window resizes/moves - enable_swallow = true; # Enable window swallowing - }; - - # XWayland - # https://wiki.hyprland.org/Configuring/Variables/#xwayland - xwayland = { - force_zero_scaling = true; # forces a scale of 1 on xwayland windows on scaled displays - }; - - # Dwindle - # https://wiki.hyprland.org/Configuring/Dwindle-Layout - dwindle = { - pseudotile = true; # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below - preserve_split = true; - }; - - # โ”€โ”€ Windows and Workspace โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - # https://wiki.hyprland.org/Configuring/Window-Rules - # https://wiki.hyprland.org/Configuring/Workspace-Rules - - windowrule = - let - f = regex: "float, ^(${regex})$"; - in - [ - "opacity 0.89 override 0.89 override, .*" # Transparency - - # Floating windows - (f "confirm") - (f "file_progress") - (f "dialog") - - (f "org.gnome.Calculator") - (f "org.gnome.Nautilus") - (f "org.gnome.SystemMonitor") - (f "nm-connection-editor") - (f "org.gnome.Settings") - (f "org.gnome.design.Palette") - - (f "Color Picker") - (f "dconf-editor") - - (f "com.github.GradienceTeam.Gradience") - - (f "pavucontrol") - (f "nm-connection-editor") - (f "xdg-desktop-portal") - (f "xdg-desktop-portal-gnome") - - "immediate,.*\.exe" # Tearing - ]; - - windowrulev2 = [ - "suppressevent maximize, class:.*" - "immediate,class:(steam_app)" # Tearing - ]; - - # โ”€โ”€ Bindings โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - # https://wiki.hyprland.org/Configuring/Binds - # SUPER = "Windows" key - - "$lmb" = "mouse:272"; # Left mouse button - "$rmb" = "mouse:273"; # Right mouse button - "$mmb" = "mouse:274"; # Middle mouse button - bindd = - [ - "SUPER, Slash, Open Terminal, exec, ${kitty_startup_script}" - "SUPER, E, Open File Manager, exec, ${nautilus} --new-window" - "SUPER, W, Open Browser, exec, ${firefox}" - "CTRL SHIFT, Escape, Open System Monitor, exec, ${gnome-system-monitor}" - - "ALT, tab, Switch Windows, exec, ${hyprswitch} gui --do-initial-execute" - "SUPER, V, Open Clipboard History, exec, ${rofi} -modi clipboard:${cliphist-rofi-img}/bin/cliphist-rofi-img -show clipboard -show-icons" - ", Print, Take Screenshot (Select Area), exec, ${grimblast} --notify --freeze copysave area ${screenshots_dir}/Screenshot_$(date +'%Y-%m-%d_%H-%M-%S').png" - "SUPER, Print, Take Fullscreen Screenshot, exec, ${grimblast} --notify --freeze copysave screen ${screenshots_dir}/Screenshot_$(date +'%Y-%m-%d_%H-%M-%S').png" - - "SUPER, H, Move Focus to Left Window, movefocus, l" - "SUPER, L, Move Focus to Right Window, movefocus, r" - "SUPER, K, Move Focus to Upper Window, movefocus, u" - "SUPER, J, Move Focus to Lower Window, movefocus, d" - - "SUPER, F, Toggle Fullscreen, fullscreen, 0" - "SUPER, M, Maximize/Restore Window, fullscreen, 1" - - "SUPER ALT, H, Move Window Left, movewindow, l" - "SUPER ALT, L, Move Window Right, movewindow, r" - "SUPER ALT, K, Move Window Upwards, movewindow, u" - "SUPER ALT, J, Move Window Downwards, movewindow, d" - - "SUPER, Q, Close Active Window, killactive" - "SUPER, C, Center Window, centerwindow, 1" # `1` respects the monitor reserved area - - "SUPER, P, Toggle Focused Window's Pseudo Mode, pseudo" - "SUPER, R, Toggle Split Orientation, togglesplit" - "SUPER, T, Toggle Active Window Floating, togglefloating" - "SUPER SHIFT, T, Toggle All Windows Floating, exec, ${hyprctl} dispatch workspaceopt allfloat" - ] - ++ (builtins.concatLists ( - builtins.genList ( - i: - let - wsNo = i + 1; - wsIndex = if wsNo == 10 then 0 else wsNo; - in - [ - "SUPER, ${toString wsIndex}, Switch to Workspace ${toString wsNo}, workspace, ${toString wsNo}" - "SUPER SHIFT, ${toString wsIndex}, Move Active Window to Workspace ${toString wsNo}, movetoworkspace, ${toString wsNo}" - ] - ) 10 - )) - ++ [ - "SUPER CTRL, H, Switch to Previous Workspace, workspace, e-1" - "SUPER CTRL, L, Switch to Next Workspace, workspace, e+1" - "SUPER, mouse_down, Switch to Previous Workspace, workspace, e+1" - "SUPER, mouse_up, Switch to Next Workspace, workspace, e-1" - "SUPER SHIFT, H, Move Active Window to Previous Workspace, movetoworkspace, e-1" - "SUPER SHIFT, L, Move Active Window to Next Workspace, movetoworkspace, e+1" - - "SUPER, S, Toggle Scratchpad, togglespecialworkspace, magic" - "SUPER SHIFT, S, Move Active Window to Scratchpad, movetoworkspace, special:magic" - ]; - binddr = [ - "ALT, space, Toggle App Launcher, exec, pkill rofi || ${rofi} -show drun" - "SUPER, SUPER_L, Toggle Workspace Overview, overview:toggle" - ]; - binddrt = [ - "ALT, ALT_L, Close Window Switcher, exec, ${hyprswitch} close" - ]; - bindde = [ - "SUPER ALT, H, Move Window Left, movewindow, l" - "SUPER ALT, L, Move Window Right, movewindow, r" - "SUPER ALT, K, Move Window Upwards, movewindow, u" - "SUPER ALT, J, Move Window Downwards, movewindow, d" - ]; - binddl = [ - ", XF86AudioPlay, Play/Pause, exec, ${playerctl} play-pause" - ", XF86AudioPause, Play/Pause, exec, ${playerctl} play-pause" - ", XF86AudioNext, Skip to Next Track, exec, ${playerctl} next" - ", XF86AudioPrev, Return to Previous Track, exec, ${playerctl} previous" - ]; - binddel = [ - ", XF86AudioRaiseVolume, Increase Volume, exec, ${wpctl} set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+" - ", XF86AudioLowerVolume, Decrease Volume, exec, ${wpctl} set-volume @DEFAULT_AUDIO_SINK@ 5%-" - ", XF86AudioMute, Mute/Unmute Volume, exec, ${wpctl} set-mute @DEFAULT_AUDIO_SINK@ toggle" - ", XF86AudioMicMute, Mute/Unmute Microphone, exec, ${wpctl} set-mute @DEFAULT_AUDIO_SOURCE@ toggle" - - ", XF86MonBrightnessUp, Increase Screen Brightness, exec, ${brightnessctl} s 10%+" - ", XF86MonBrightnessDown, Decrease Screen Brightness, exec, ${brightnessctl} s 10%-" - ]; - binddm = [ - "SUPER, $rmb, Resize Window, resizewindow" - "SUPER, $lmb, Move Window, movewindow" - ]; - }; - }; - - xdg.desktopEntries."org.gnome.Settings" = { - name = "Settings"; - comment = "Gnome Control Center"; - icon = "org.gnome.Settings"; - exec = "env XDG_CURRENT_DESKTOP=gnome ${pkgs.gnome-control-center}/bin/gnome-control-center"; - categories = [ "X-Preferences" ]; - terminal = false; - }; - - services.safeeyes.enable = true; -} diff --git a/nix/home-manager/hyprland/hypridle.nix b/nix/home-manager/hyprland/hypridle.nix deleted file mode 100644 index 33f6d52f..00000000 --- a/nix/home-manager/hyprland/hypridle.nix +++ /dev/null @@ -1,49 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Hypridle โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ pkgs, ... }: -let - brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl"; - hyprctl = "${pkgs.hyprland}/bin/hyprctl"; - hyprlock = "${pkgs.hyprlock}/bin/hyprlock"; - loginctl = "${pkgs.systemd}/bin/loginctl"; - systemctl = "${pkgs.systemd}/bin/systemctl"; -in -{ - services.hypridle = { - enable = true; - settings = { - general = { - lock_cmd = "pidof hyprlock || ${hyprlock}"; # avoid starting multiple hyprlock instances - before_sleep_cmd = "${loginctl} lock-session"; # lock before suspend - after_sleep_cmd = "${hyprctl} dispatch dpms on"; # to avoid having to press a key twice to turn on the display - }; - - listener = [ - { - timeout = 150; # 2.5min - on-timeout = "${brightnessctl} -s set 10"; # set monitor backlight to minimum, avoid 0 on OLED monitor - on-resume = "${brightnessctl} -r"; # monitor backlight restore - } - { - timeout = 150; # 2.5min - on-timeout = "${brightnessctl} -sd dell::kbd_backlight set 0"; # turn off keyboard backlight - on-resume = "${brightnessctl} -rd dell::kbd_backlight"; # turn on keyboard backlight - } - { - timeout = 300; # 5min - on-timeout = "${loginctl} lock-session"; # lock screen when timeout has passed - } - { - timeout = 330; # 5.5min - on-timeout = "${hyprctl} dispatch dpms off"; # screen off when timeout has passed - on-resume = "${hyprctl} dispatch dpms on"; # screen on when activity is detected after timeout has fired - } - { - timeout = 1800; # 30min - on-timeout = "${systemctl} suspend"; # suspend pc - } - ]; - }; - }; -} diff --git a/nix/home-manager/hyprland/hyprlock.nix b/nix/home-manager/hyprland/hyprlock.nix deleted file mode 100644 index 50853142..00000000 --- a/nix/home-manager/hyprland/hyprlock.nix +++ /dev/null @@ -1,244 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Hyprlock โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - pkgs, - meta, - config, - ... -}: -let - inherit (meta) font; - picturesDir = config.xdg.userDirs.pictures; - - scripts = { - battery-status = pkgs.writeShellScriptBin "battery-status" '' - #!/usr/bin/env bash - - status="$(cat /sys/class/power_supply/BAT1/status)" - level="$(cat /sys/class/power_supply/BAT1/capacity)" - - if [[ ("$status" == "Discharging") || ("$status" == "Full") ]]; then - if [[ "$level" -eq "0" ]]; then - printf "๏‰„ " - elif [[ ("$level" -ge "0") && ("$level" -le "25") ]]; then - printf "๏‰ƒ " - elif [[ ("$level" -ge "25") && ("$level" -le "50") ]]; then - printf "๏‰‚ " - elif [[ ("$level" -ge "50") && ("$level" -le "75") ]]; then - printf "๏‰ " - elif [[ ("$level" -ge "75") && ("$level" -le "100") ]]; then - printf "๏‰€ " - fi - elif [[ "$status" == "Charging" ]]; then - printf "๏ƒง " - fi - ''; - layout-status = pkgs.writeShellScriptBin "layout-status" '' - #!/usr/bin/env bash - - layout="$(bat /etc/vconsole.conf | grep XKBLAYOUT | awk -F'=' '{print toupper($2)}')" - printf "%s ๏„œ " "$layout" - ''; - network-status = pkgs.writeShellScriptBin "network-status" '' - #!/usr/bin/env bash - - status="$(nmcli general status | grep -oh "\w*connect\w*")" - - if [[ "$status" == "disconnected" ]]; then - printf "๓ฐคฎ " - elif [[ "$status" == "connecting" ]]; then - printf "๓ฑธ " - elif [[ "$status" == "connected" ]]; then - # strength="$(nmcli -f IN-USE,SIGNAL device wifi | grep '*' | awk '{print $2}')" - strength="$(python ~/.config/Scripts/wifi-conn-strength)" - if [[ "$?" == "0" ]]; then - if [[ "$strength" -eq "0" ]]; then - printf "๓ฐคฏ " - elif [[ ("$strength" -ge "0") && ("$strength" -le "25") ]]; then - printf "๓ฐคŸ " - elif [[ ("$strength" -ge "25") && ("$strength" -le "50") ]]; then - printf "๓ฐคข " - elif [[ ("$strength" -ge "50") && ("$strength" -le "75") ]]; then - printf "๓ฐคฅ " - elif [[ ("$strength" -ge "75") && ("$strength" -le "100") ]]; then - printf "๓ฐคจ " - fi - else - printf "๓ฐˆ€ " - fi - fi - ''; - song-status = pkgs.writeShellScriptBin "song-status" '' - #!/usr/bin/env bash - - player_name=$(playerctl metadata --format '{{playerName}}') - player_status=$(playerctl status) - - if [[ "$player_status" == "Playing" ]]; then - if [[ "$player_name" == "spotify" ]]; then - song_info=$(playerctl metadata --format '{{title}} ๓ฐ“‡ {{artist}}') - elif [[ "$player_name" == "firefox" ]]; then - song_info=$(playerctl metadata --format '{{title}} ๓ฐˆน {{artist}}') - elif [[ "$player_name" == "mpd" ]]; then - song_info=$(playerctl metadata --format '{{title}} ๓ฐŽ† {{artist}}') - elif [[ "$player_name" == "chromium" ]]; then - song_info=$(playerctl metadata --format '{{title}} ๓ฐŠฏ {{artist}}') - fi - fi - - echo "$song_info" - ''; - }; -in -{ - programs.hyprlock = { - enable = true; - settings = { - # โ”€โ”€ Background โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - background = { - monitor = ""; - path = "${picturesDir}/wallpapers/Fantasy-Landscape-Night.png"; # only png supported for now - color = "rgba(25, 20, 20, 1.0)"; - - # all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations - blur_passes = 0; # 0 disables blurring - blur_size = 2; - noise = 0; - contrast = 0; - brightness = 0; - vibrancy = 0; - vibrancy_darkness = "0.0"; - }; - - # โ”€โ”€ Input Field โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - input-field = { - monitor = ""; - size = "200, 30"; - outline_thickness = 0; - dots_size = 0.25; # Scale of input-field height, 0.2 - 0.8 - dots_spacing = 0.55; # Scale of dots' absolute size, 0.0 - 1.0 - dots_center = true; - dots_rounding = -1; - outer_color = "rgba(242, 243, 244, 0.25)"; - inner_color = "rgba(242, 243, 244, 0.25)"; - font_color = "rgba(242, 243, 244, 0.75)"; - fade_on_empty = false; - placeholder_text = ""; # Text rendered in the input box when it's empty. - hide_input = false; - check_color = "rgba(204, 136, 34, 0)"; - fail_color = "rgba(204, 34, 34, 0)"; # if authentication failed, changes outer_color and fail message color - fail_text = "$FAIL ($ATTEMPTS)"; # can be set to empty - fail_transition = 300; # transition time in ms between normal outer_color and fail_color - capslock_color = -1; - numlock_color = -1; - bothlock_color = -1; # when both locks are active. -1 means don't change outer color (same for above) - invert_numlock = false; # change color if numlock is off - swap_font_color = false; # see below - position = "0, -470"; - halign = "center"; - valign = "center"; - }; - - # โ”€โ”€ Labels โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - label = [ - { - monitor = ""; - text = "cmd[update:1000] echo \"$(${scripts.song-status}/bin/song-status)\""; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 14; - font_family = font.mono.name; - position = "20, 508"; - halign = "left"; - valign = "center"; - } - { - monitor = ""; - text = "cmd[update:1000] echo \"$(${scripts.network-status}/bin/network-status)\""; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 15; - font_family = font.mono.name; - position = "920, 507"; - halign = "center"; - valign = "center"; - } - { - monitor = ""; - text = "cmd[update:1000] echo \"$(${scripts.battery-status}/bin/battery-status)\""; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 18; - font_family = font.mono.name; - position = "863, 505"; - halign = "center"; - valign = "center"; - } - { - monitor = ""; - text = "cmd[update:1000] echo \"$(${scripts.layout-status}/bin/layout-status)\""; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 14; - font_family = font.mono.name; - position = "796, 508"; - halign = "center"; - valign = "center"; - } - { - monitor = ""; - text = "cmd[update:1000] echo \"$(date +\"%A, %d. %B\")\""; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 20; - font_family = "${font.sans.name} Bold"; - position = "0, 400"; - halign = "center"; - valign = "center"; - } - { - monitor = ""; - text = "cmd[update:1000] echo \"\$(date +\"%-H:%M\")\""; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 93; - font_family = "${font.sans.name} Bold"; - position = "0, 253"; - halign = "center"; - valign = "center"; - } - { - monitor = ""; - text = "cmd[update:0] echo \"${meta.description}\""; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 12; - font_family = "${font.sans.name} Bold"; - position = "0, -407"; - halign = "center"; - valign = "center"; - } - { - monitor = ""; - text = "Enter Password"; - color = "rgba(242, 243, 244, 0.75)"; - font_size = 10; - font_family = font.sans.name; - position = "0, -440"; - halign = "center"; - valign = "center"; - } - ]; - - # โ”€โ”€ Image โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - image = { - monitor = ""; - path = "${picturesDir}/user-avatar.png"; - border_color = "0xffdddddd"; - border_size = 0; - size = 73; - rounding = -1; - rotate = 0; - reload_time = -1; - reload_cmd = ""; - position = "0, -350"; - halign = "center"; - valign = "center"; - }; - }; - }; -} diff --git a/nix/home-manager/hyprland/hyprpaper.nix b/nix/home-manager/hyprland/hyprpaper.nix deleted file mode 100644 index 975f8a0c..00000000 --- a/nix/home-manager/hyprland/hyprpaper.nix +++ /dev/null @@ -1,16 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Hyprpaper โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ config, ... }: -let - picturesDir = config.xdg.userDirs.pictures; -in -{ - services.hyprpaper = { - enable = true; - settings = { - preload = "${picturesDir}/wallpapers/Fantasy-Landscape3.png"; - wallpaper = ",${picturesDir}/wallpapers/Fantasy-Landscape3.png"; - }; - }; -} diff --git a/nix/home-manager/hyprland/hyprshade.nix b/nix/home-manager/hyprland/hyprshade.nix deleted file mode 100644 index 7b534616..00000000 --- a/nix/home-manager/hyprland/hyprshade.nix +++ /dev/null @@ -1,49 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Hyprshade โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ config, pkgs, ... }: -let - startTime = "19:00:00"; - endTime = "06:00:00"; -in -{ - home.packages = [ pkgs.hyprshade ]; - - systemd.user = { - services.hyprshade = { - Unit = { - description = "Apply screen filter"; - }; - - Service = { - Type = "oneshot"; - ExecStart = "${pkgs.hyprshade}/bin/hyprshade auto"; - }; - }; - timers.hyprshade = { - Unit = { - description = "Apply screen filter on schedule"; - }; - - Timer = { - OnCalendar = [ - "*-*-* ${endTime}" - "*-*-* ${startTime}" - ]; - }; - - Install = { - WantedBy = [ "timers.target" ]; - }; - }; - }; - xdg.configFile."hypr/hyprshade.toml".text = '' - [[shaders]] - name = "blue-light-filter" - start_time = ${startTime} - end_time = ${endTime} - [shaders.config] - temperature = 3600 - strength = 1 - ''; -} diff --git a/nix/home-manager/kitty.nix b/nix/home-manager/kitty.nix deleted file mode 100644 index 102dc021..00000000 --- a/nix/home-manager/kitty.nix +++ /dev/null @@ -1,21 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ kitty โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ meta, ... }: -let - inherit (meta) font; -in -{ - programs.kitty = { - enable = true; - font = { - name = font.mono.name; - size = 14; - }; - shellIntegration.enableZshIntegration = true; - themeFile = "Catppuccin-Mocha"; - settings = { - symbol_map = "U+1FBF0,U+1FBF1,U+1FBF2,U+1FBF3,U+1FBF4,U+1FBF5,U+1FBF6,U+1FBF7,U+1FBF8,U+1FBF9 Iosevka Nerd Font Mono"; - }; - }; -} diff --git a/nix/home-manager/modules/default.nix b/nix/home-manager/modules/default.nix deleted file mode 100644 index ffcd4415..00000000 --- a/nix/home-manager/modules/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/nix/home-manager/rofi.nix b/nix/home-manager/rofi.nix deleted file mode 100644 index 88d00bea..00000000 --- a/nix/home-manager/rofi.nix +++ /dev/null @@ -1,363 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Rofi โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - pkgs, - config, - meta, - ... -}: -let - inherit (meta) font; -in -{ - programs.rofi = { - enable = true; - package = pkgs.rofi-wayland; - extraConfig = { - modi = "drun,run,filebrowser"; - show-icons = true; - display-drun = "๏€‰"; - display-run = "๏„ "; - display-filebrowser = "๏ป"; - drun-display-format = "{name}"; - }; - font = "${font.mono.name} 10"; - pass = { - enable = true; - }; - theme = - let - inherit (config.lib.formats.rasi) mkLiteral; - in - { - /* - * - ***----- Global Properties -----**** - */ - "*" = { - # Catppuccin - background = mkLiteral "#1E1D2FFF"; - background-alt = mkLiteral "#282839FF"; - foreground = mkLiteral "#D9E0EEFF"; - selected = mkLiteral "#7AA2F7FF"; - active = mkLiteral "#ABE9B3FF"; - urgent = mkLiteral "#F28FADFF"; - - font = "${font.mono.name} 10"; - - border-colour = mkLiteral "var(selected)"; - handle-colour = mkLiteral "var(selected)"; - background-colour = mkLiteral "var(background)"; - foreground-colour = mkLiteral "var(foreground)"; - alternate-background = mkLiteral "var(background-alt)"; - normal-background = mkLiteral "var(background)"; - normal-foreground = mkLiteral "var(foreground)"; - urgent-background = mkLiteral "var(urgent)"; - urgent-foreground = mkLiteral "var(background)"; - active-background = mkLiteral "var(active)"; - active-foreground = mkLiteral "var(background)"; - selected-normal-background = mkLiteral "var(selected)"; - selected-normal-foreground = mkLiteral "var(background)"; - selected-urgent-background = mkLiteral "var(active)"; - selected-urgent-foreground = mkLiteral "var(background)"; - selected-active-background = mkLiteral "var(urgent)"; - selected-active-foreground = mkLiteral "var(background)"; - alternate-normal-background = mkLiteral "var(background)"; - alternate-normal-foreground = mkLiteral "var(foreground)"; - alternate-urgent-background = mkLiteral "var(urgent)"; - alternate-urgent-foreground = mkLiteral "var(background)"; - alternate-active-background = mkLiteral "var(active)"; - alternate-active-foreground = mkLiteral "var(background)"; - }; - - /* - * - ***----- Main Window -----**** - */ - window = { - # properties for window widget - transparency = "real"; - location = mkLiteral "center"; - anchor = mkLiteral "center"; - fullscreen = false; - width = mkLiteral "600px"; - x-offset = mkLiteral "0px"; - y-offset = mkLiteral "0px"; - - # properties for all widgets - enabled = true; - margin = mkLiteral "0px"; - padding = mkLiteral "0px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "10px"; - border-color = mkLiteral "@border-colour"; - cursor = "default"; - # Backgroud Colors - background-color = mkLiteral "@background-colour"; - # Backgroud Image - # background-image = mkLiteral "url('/path/to/image.png', none)"; - # Simple Linear Gradient - # background-image = mkLiteral "linear-gradient(red, orange, pink, purple)"; - # Directional Linear Gradient - # background-image = mkLiteral "linear-gradient(to bottom, pink, yellow, magenta)"; - # Angle Linear Gradient - # background-image = mkLiteral "linear-gradient(45, cyan, purple, indigo)"; - }; - - /* - * - ***----- Main Box -----**** - */ - mainbox = { - enabled = true; - spacing = mkLiteral "10px"; - margin = mkLiteral "0px"; - padding = mkLiteral "30px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "0px 0px 0px 0px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "transparent"; - children = [ - "inputbar" - "message" - "listview" - ]; - }; - - /* - * - ***----- Inputbar -----**** - */ - inputbar = { - enabled = true; - spacing = mkLiteral "10px"; - margin = mkLiteral "0px"; - padding = mkLiteral "0px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "0px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "transparent"; - text-color = mkLiteral "@foreground-colour"; - children = [ - "textbox-prompt-colon" - "entry" - "mode-switcher" - ]; - }; - - prompt = { - enabled = mkLiteral "true"; - background-color = mkLiteral "inherit"; - text-color = mkLiteral "inherit"; - }; - textbox-prompt-colon = { - enabled = true; - padding = mkLiteral "5px 0px"; - expand = false; - str = "๏€‚"; - background-color = mkLiteral "inherit"; - text-color = mkLiteral "inherit"; - }; - entry = { - enabled = true; - padding = mkLiteral "5px 0px"; - background-color = mkLiteral "inherit"; - text-color = mkLiteral "inherit"; - cursor = mkLiteral "text"; - placeholder = "Search..."; - placeholder-color = mkLiteral "inherit"; - }; - num-filtered-rows = { - enabled = true; - expand = false; - background-color = mkLiteral "inherit"; - text-color = mkLiteral "inherit"; - }; - textbox-num-sep = { - enabled = true; - expand = false; - str = "/"; - background-color = mkLiteral "inherit"; - text-color = mkLiteral "inherit"; - }; - num-rows = { - enabled = true; - expand = false; - background-color = mkLiteral "inherit"; - text-color = mkLiteral "inherit"; - }; - case-indicator = { - enabled = true; - background-color = mkLiteral "inherit"; - text-color = mkLiteral "inherit"; - }; - - /* - * - ***----- Listview -----**** - */ - listview = { - enabled = true; - columns = mkLiteral "1"; - lines = mkLiteral "8"; - cycle = true; - dynamic = true; - scrollbar = true; - layout = mkLiteral "vertical"; - reverse = false; - fixed-height = true; - fixed-columns = true; - - spacing = mkLiteral "5px"; - margin = mkLiteral "0px"; - padding = mkLiteral "0px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "0px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "transparent"; - text-color = mkLiteral "@foreground-colour"; - cursor = "default"; - }; - scrollbar = { - handle-width = mkLiteral "5px "; - handle-color = mkLiteral "@handle-colour"; - border-radius = mkLiteral "10px"; - background-color = mkLiteral "@alternate-background"; - }; - - /* - * - ***----- Elements -----**** - */ - element = { - enabled = true; - spacing = mkLiteral "10px"; - margin = mkLiteral "0px"; - padding = mkLiteral "5px 10px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "10px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "transparent"; - text-color = mkLiteral "@foreground-colour"; - cursor = mkLiteral "pointer"; - }; - "element normal.normal" = { - background-color = mkLiteral "var(normal-background)"; - text-color = mkLiteral "var(normal-foreground)"; - }; - "element normal.urgent" = { - background-color = mkLiteral "var(urgent-background)"; - text-color = mkLiteral "var(urgent-foreground)"; - }; - "element normal.active" = { - background-color = mkLiteral "var(active-background)"; - text-color = mkLiteral "var(active-foreground)"; - }; - "element selected.normal" = { - background-color = mkLiteral "var(selected-normal-background)"; - text-color = mkLiteral "var(selected-normal-foreground)"; - }; - "element selected.urgent" = { - background-color = mkLiteral "var(selected-urgent-background)"; - text-color = mkLiteral "var(selected-urgent-foreground)"; - }; - "element selected.active" = { - background-color = mkLiteral "var(selected-active-background)"; - text-color = mkLiteral "var(selected-active-foreground)"; - }; - "element alternate.normal" = { - background-color = mkLiteral "var(alternate-normal-background)"; - text-color = mkLiteral "var(alternate-normal-foreground)"; - }; - "element alternate.urgent" = { - background-color = mkLiteral "var(alternate-urgent-background)"; - text-color = mkLiteral "var(alternate-urgent-foreground)"; - }; - "element alternate.active" = { - background-color = mkLiteral "var(alternate-active-background)"; - text-color = mkLiteral "var(alternate-active-foreground)"; - }; - element-icon = { - background-color = mkLiteral "transparent"; - text-color = mkLiteral "inherit"; - size = mkLiteral "24px"; - cursor = mkLiteral "inherit"; - }; - element-text = { - background-color = mkLiteral "transparent"; - text-color = mkLiteral "inherit"; - highlight = mkLiteral "inherit"; - cursor = mkLiteral "inherit"; - vertical-align = mkLiteral "0.5"; - horizontal-align = mkLiteral "0.0"; - }; - - /* - * - ***----- Mode Switcher -----**** - */ - mode-switcher = { - enabled = true; - spacing = mkLiteral "10px"; - margin = mkLiteral "0px"; - padding = mkLiteral "0px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "0px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "transparent"; - text-color = mkLiteral "@foreground-colour"; - }; - button = { - padding = mkLiteral "5px 10px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "10px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "@alternate-background"; - text-color = mkLiteral "inherit"; - cursor = mkLiteral "pointer"; - }; - "button selected" = { - background-color = mkLiteral "var(selected-normal-background)"; - text-color = mkLiteral "var(selected-normal-foreground)"; - }; - - /* - * - ***----- Message -----**** - */ - message = { - enabled = true; - margin = mkLiteral "0px"; - padding = mkLiteral "0px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "0px 0px 0px 0px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "transparent"; - text-color = mkLiteral "@foreground-colour"; - }; - textbox = { - padding = mkLiteral "8px 10px"; - border = mkLiteral "0px solid"; - border-radius = mkLiteral "10px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "@alternate-background"; - text-color = mkLiteral "@foreground-colour"; - vertical-align = mkLiteral "0.5"; - horizontal-align = mkLiteral "0.0"; - highlight = mkLiteral "none"; - placeholder-color = mkLiteral "@foreground-colour"; - blink = true; - markup = true; - }; - error-message = { - padding = mkLiteral "10px"; - border = mkLiteral "2px solid"; - border-radius = mkLiteral "10px"; - border-color = mkLiteral "@border-colour"; - background-color = mkLiteral "@background-colour"; - text-color = mkLiteral "@foreground-colour"; - }; - }; - }; -} diff --git a/nix/home-manager/scripts/nix-utils.nix b/nix/home-manager/scripts/nix-utils.nix deleted file mode 100644 index 1af2f4bb..00000000 --- a/nix/home-manager/scripts/nix-utils.nix +++ /dev/null @@ -1,39 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ NixOS Rebuild โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - pkgs, - meta, - config, - ... -}: -let - nixos-rebuild = "${pkgs.nixos-rebuild}/bin/nixos-rebuild"; - homeDir = config.home.homeDirectory; - - nix-switch = pkgs.writeShellScriptBin "nix-switch" '' - #!/usr/bin/env bash - sudo ${nixos-rebuild} switch --flake ${homeDir}/.dotfiles/nix#${meta.hostname} --impure $@ - ''; - nix-boot = pkgs.writeShellScriptBin "nix-boot" '' - #!/usr/bin/env bash - sudo ${nixos-rebuild} boot --flake ${homeDir}/.dotfiles/nix#${meta.hostname} --impure $@ - ''; - nix-test = pkgs.writeShellScriptBin "nix-test" '' - #!/usr/bin/env bash - sudo ${nixos-rebuild} test --flake ${homeDir}/.dotfiles/nix#${meta.hostname} --impure $@ - ''; - - nix-flake-update = pkgs.writeShellScriptBin "nix-flake-update" '' - #!/usr/bin/env bash - nix flake update --commit-lock-file ${homeDir}/.dotfiles/nix $@ - ''; -in -{ - home.packages = [ - nix-switch - nix-boot - nix-test - nix-flake-update - ]; -} diff --git a/nix/home-manager/theme.nix b/nix/home-manager/theme.nix deleted file mode 100644 index 970d2441..00000000 --- a/nix/home-manager/theme.nix +++ /dev/null @@ -1,84 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Theme โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ meta, ... }: -let - inherit (meta) - font - theme - cursorTheme - iconTheme - ; -in -{ - home = { - packages = [ - font.sans.package - font.mono.package - font.emoji.package - ]; - pointerCursor = cursorTheme // { - gtk.enable = true; - }; - sessionVariables = { - GTK_THEME = theme.name; - - XCURSOR_THEME = cursorTheme.name; - XCURSOR_SIZE = "${toString cursorTheme.size}"; - HYPRCURSOR_THEME = cursorTheme.name; - HYPRCURSOR_SIZE = "${toString cursorTheme.size}"; - }; - }; - - gtk = { - inherit theme cursorTheme iconTheme; - enable = true; - font = font.sans; - }; - qt = { - enable = true; - platformTheme.name = "kde"; - }; - - fonts.fontconfig = { - enable = true; - defaultFonts = { - serif = [ font.sans.name ]; - sansSerif = [ font.sans.name ]; - monospace = [ font.mono.name ]; - emoji = [ font.emoji.name ]; - }; - }; - - dconf = { - enable = true; - settings = - let - # GTK settings - gtk_settings = { - show-hidden = true; - sort-directories-first = true; - startup-mode = "cwd"; - }; - in - { - "org/gnome/desktop/interface" = { - color-scheme = "prefer-dark"; - clock-format = "24h"; - font-antialiasing = "rgba"; - font-hinting = "full"; - monospace-font-name = font.mono.name; - show-battery-percentage = true; - }; - "org/gnome/nautilus/preferences" = { - default-folder-viewer = "icon-view"; - show-delete-permanently = true; - }; - "org/gnome/calculator" = { - show-thousands = true; - }; - "org/gtk/settings/file-chooser" = gtk_settings; - "org/gtk/gtk4/settings/file-chooser" = gtk_settings; - }; - }; -} diff --git a/nix/home-manager/wezterm.nix b/nix/home-manager/wezterm.nix deleted file mode 100644 index b07b8361..00000000 --- a/nix/home-manager/wezterm.nix +++ /dev/null @@ -1,28 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ WezTerm โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - programs.wezterm = { - enable = true; - enableZshIntegration = true; - extraConfig = '' - local config = wezterm.config_builder() - local smart_splits = wezterm.plugin.require("https://github.com/mrjones2014/smart-splits.nvim") - - require("config.appearance").setup(config) - require("config.general").setup(config) - require("config.keys").setup(config, smart_splits) - require("config.platforms").setup(config) - - local smart_splits_config = { - direction_keys = { "h", "j", "k", "l" }, - modifiers = { - move = "CTRL", - resize = "LEADER", - }, - } - - return smart_splits.apply_to_config(config, smart_splits_config) - ''; - }; -} diff --git a/nix/nixos/audio.nix b/nix/nixos/audio.nix deleted file mode 100644 index adb368b4..00000000 --- a/nix/nixos/audio.nix +++ /dev/null @@ -1,55 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Audio โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - hardware.pulseaudio.enable = false; - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - jack.enable = true; - wireplumber.enable = true; - extraConfig.pipewire."92-low-latency" = { - "context.properties" = { - "default.clock.rate" = 44100; - "default.clock.quantum" = 512; - "default.clock.min-quantum" = 512; - "default.clock.max-quantum" = 512; - }; - }; - }; - - services.udev.extraRules = '' - KERNEL=="rtc0", GROUP="audio" - KERNEL=="hpet", GROUP="audio" - ''; - - security.pam.loginLimits = [ - { - domain = "@audio"; - item = "memlock"; - type = "-"; - value = "unlimited"; - } - { - domain = "@audio"; - item = "rtprio"; - type = "-"; - value = "99"; - } - { - domain = "@audio"; - item = "nofile"; - type = "soft"; - value = "99999"; - } - { - domain = "@audio"; - item = "nofile"; - type = "hard"; - value = "524288"; - } - ]; -} diff --git a/nix/nixos/configuration.nix b/nix/nixos/configuration.nix deleted file mode 100644 index d0293a7d..00000000 --- a/nix/nixos/configuration.nix +++ /dev/null @@ -1,82 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ NIX CONFIGURATION โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - inputs, - outputs, - pkgs, - meta, - ... -}: -{ - imports = [ - /etc/nixos/hardware-configuration.nix - - ./audio.nix - ./gnome.nix - ./hyprland.nix - ./locale.nix - ./sddm.nix - ./system.nix - ]; - - # โ”€โ”€ Overlays โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - nixpkgs = { - overlays = [ - # Add overlays your own flake exports (from overlays and pkgs dir): - outputs.overlays.additions - outputs.overlays.modifications - - # You can also add overlays exported from other flakes: - # neovim-nightly-overlay.overlays.default - - # Or define it inline, for example: - # (final: prev: { - # hi = final.hello.overrideAttrs (oldAttrs: { - # patches = [ ./change-hello-to-hi.patch ]; - # }); - # }) - ]; - }; - - # โ”€โ”€ Home Manager โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - home-manager = { - backupFileExtension = "backup"; - useUserPackages = true; - useGlobalPkgs = true; - extraSpecialArgs = { - inherit inputs outputs meta; - }; - users.${meta.username} = import ../home-manager/home.nix; - }; - - # โ”€โ”€ Users โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - users = { - users = { - ${meta.username} = { - isNormalUser = true; - description = meta.description; - openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAE51+iQSvnNjWATieu+alWv351eNsQmF7jRXUvty/ZH nhan@nixos" - ]; - extraGroups = [ - "audio" - "docker" - "libvirtd" - "networkmanager" - "video" - "wheel" - ]; - }; - }; - defaultUserShell = pkgs.zsh; - }; - - programs.zsh.enable = true; - programs.neovim = { - enable = true; - defaultEditor = true; - }; - programs.tmux.enable = true; - programs.nix-ld.enable = true; -} diff --git a/nix/nixos/gnome.nix b/nix/nixos/gnome.nix deleted file mode 100644 index a11f96a4..00000000 --- a/nix/nixos/gnome.nix +++ /dev/null @@ -1,35 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ GNOME โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ pkgs, ... }: -{ - services = { - gnome = { - sushi.enable = true; - core-developer-tools.enable = true; - }; - gvfs.enable = true; - xserver.desktopManager.gnome.enable = true; - }; - - environment.gnome.excludePackages = ( - with pkgs; - [ - baobab - epiphany - gnome-text-editor - gnome-console - gnome-contacts - gnome-logs - gnome-maps - gnome-system-monitor - gnome-weather - gnome-connections - snapshot - yelp - - devhelp - gnome-builder - ] - ); -} diff --git a/nix/nixos/hyprland.nix b/nix/nixos/hyprland.nix deleted file mode 100644 index 18805d64..00000000 --- a/nix/nixos/hyprland.nix +++ /dev/null @@ -1,39 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Hyprland โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ pkgs, ... }: -{ - programs = { - hyprland.enable = true; - hyprlock.enable = true; - }; - - xdg.portal.enable = true; - - security = { - pam.services.hyprlock = { }; - polkit.enable = true; - }; - - systemd.user.services.polkit-gnome-authentication-agent-1 = { - description = "polkit-gnome-authentication-agent-1"; - wantedBy = [ "graphical-session.target" ]; - wants = [ "graphical-session.target" ]; - after = [ "graphical-session.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1"; - Restart = "on-failure"; - RestartSec = 1; - TimeoutStopSec = 10; - }; - }; - - environment.systemPackages = with pkgs; [ - polkit_gnome - snixembed - ]; - - # Use Wayland (Electron) - environment.sessionVariables.NIXOS_OZONE_WL = "1"; -} diff --git a/nix/nixos/locale.nix b/nix/nixos/locale.nix deleted file mode 100644 index 9d9f1415..00000000 --- a/nix/nixos/locale.nix +++ /dev/null @@ -1,36 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Locale โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ pkgs, ... }: -{ - time.timeZone = "Europe/Berlin"; - i18n = - let - english = "en_US.UTF-8"; - german = "de_DE.UTF-8"; - in - { - defaultLocale = english; - extraLocaleSettings = { - LC_ADDRESS = german; - LC_IDENTIFICATION = german; - LC_MEASUREMENT = german; - LC_MONETARY = german; - LC_NAME = german; - LC_NUMERIC = german; - LC_PAPER = german; - LC_TELEPHONE = german; - LC_TIME = german; - }; - }; - console = { - font = "ter-128n"; - keyMap = "us"; - packages = [ pkgs.terminus_font ]; - }; - services.xserver.xkb = { - layout = "us, us"; - variant = "basic, intl"; - options = "grp:win_space_toggle"; - }; -} diff --git a/nix/nixos/modules/default.nix b/nix/nixos/modules/default.nix deleted file mode 100644 index ffcd4415..00000000 --- a/nix/nixos/modules/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/nix/nixos/sddm.nix b/nix/nixos/sddm.nix deleted file mode 100644 index caf38d10..00000000 --- a/nix/nixos/sddm.nix +++ /dev/null @@ -1,22 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Display Manager โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ pkgs, meta, ... }: -let - inherit (meta) font; -in -{ - services.displayManager.sddm = { - enable = true; - package = pkgs.kdePackages.sddm; - theme = "catppuccin-mocha"; - wayland.enable = true; - }; - environment.systemPackages = [ - (pkgs.catppuccin-sddm.override { - flavor = "mocha"; - font = font.sans.name; - }) - font.sans.package - ]; -} diff --git a/nix/nixos/system.nix b/nix/nixos/system.nix deleted file mode 100644 index 41523de2..00000000 --- a/nix/nixos/system.nix +++ /dev/null @@ -1,140 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ System โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - inputs, - config, - lib, - pkgs, - meta, - ... -}: -{ - # nix - documentation.nixos.enable = false; - nixpkgs.config.allowUnfree = true; - nix = - let - flakeInputs = lib.filterAttrs (_: lib.isType "flake") inputs; - in - { - settings = { - experimental-features = "nix-command flakes"; - # Opinionated: disable global registry - flake-registry = ""; - # Workaround for https://github.com/NixOS/nix/issues/9574 - nix-path = config.nix.nixPath; - auto-optimise-store = true; - }; - # Opinionated: disable channels - channel.enable = false; - - # Opinionated: make flake registry and nix path match flake inputs - registry = lib.mapAttrs (_: flake: { inherit flake; }) flakeInputs; - nixPath = lib.mapAttrsToList (n: _: "${n}=flake:${n}") flakeInputs; - }; - - # virtualization - programs.virt-manager.enable = true; - virtualisation = { - libvirtd.enable = true; - docker.enable = true; - }; - - # packages - environment.systemPackages = with pkgs; [ - gcc - - # Essential - chezmoi - curl - git - gum - python3 - volta - wget - rustup - - # Packages - bc # for TokyoNight TMUX - delta - lazydocker - lazygit - openssl - ueberzugpp - unzip - - # Apps - bitwarden-desktop - google-chrome - jetbrains.idea-ultimate - jetbrains.webstorm - spotify - webcord - zed-editor - - # NixOS - gnome-system-monitor - nautilus - nixd - nixfmt-rfc-style - vlc - ]; - - # services - services = { - openssh = { - enable = true; - settings = { - # Opinionated: forbid root login through SSH. - PermitRootLogin = "no"; - # Opinionated: use keys only. - # Remove if you want to SSH using passwords - PasswordAuthentication = false; - }; - }; - xserver = { - enable = true; - excludePackages = with pkgs; [ xterm ]; - }; - playerctld.enable = true; - }; - - # Bootloader - boot = { - tmp.cleanOnBoot = true; - loader = { - timeout = 60; - efi.canTouchEfiVariables = true; - grub = { - enable = true; - theme = ( - pkgs.sleek-grub-theme.override { - withStyle = "dark"; - withBanner = "Boot Manager"; - } - ); - efiSupport = true; - useOSProber = true; - device = "nodev"; - gfxmodeEfi = "1920x1080,auto"; - }; - }; - }; - - # network - networking = { - networkmanager.enable = true; - hostName = meta.hostname; - }; - - # Bluetooth - hardware.bluetooth = { - enable = true; - powerOnBoot = true; - settings.General.Experimental = true; - }; - - # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion - system.stateVersion = "24.05"; -} diff --git a/nix/pkgs/hyprshade/default.nix b/nix/pkgs/hyprshade/default.nix deleted file mode 100644 index b17f82a0..00000000 --- a/nix/pkgs/hyprshade/default.nix +++ /dev/null @@ -1,43 +0,0 @@ -# โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ -# โ”‚ Hyprshade โ”‚ -# โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ -{ - lib, - pkgs, - ... -}: -pkgs.python3Packages.buildPythonPackage rec { - name = "hyprshade"; - format = "pyproject"; - - src = pkgs.fetchFromGitHub { - owner = "loqusion"; - repo = "hyprshade"; - rev = "152cd2ea06d9412d62bc628d62ee5af7771190b1"; - sha256 = "0wf1iqikfg7539k7hf5bbrhzwxfhgwwmkng0sb2bw712cbnhy6jm"; - }; - - nativeBuildInputs = [ - pkgs.python3Packages.hatchling - pkgs.makeWrapper - ]; - - propagatedBuildInputs = [ - pkgs.python3Packages.more-itertools - pkgs.python3Packages.click - (pkgs.python3Packages.buildPythonPackage rec { - pname = "chevron"; - version = "0.14.0"; # >= 0.14.0 is required for hyprshade - src = pkgs.python3Packages.fetchPypi { - inherit pname version; - sha256 = "87613aafdf6d77b6a90ff073165a61ae5086e21ad49057aa0e53681601800ebf"; - }; - }) - ]; - - postFixup = '' - wrapProgram $out/bin/hyprshade \ - --set HYPRSHADE_SHADERS_DIR $out/share/hyprshade/shaders \ - --prefix PATH : ${lib.makeBinPath [ pkgs.hyprland ]} - ''; -} diff --git a/scripts/install.sh b/scripts/install.sh index 120198fb..982685f4 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -31,17 +31,12 @@ else git clone -b "${BRANCH}" "${remote}" "${TARGET}" fi -# NixOS only: initialize system -if command -v "nixos-version" &>/dev/null; then - sudo nixos-rebuild switch --flake "${TARGET}/nix#nixstation" --impure -fi - set -- --source="${TARGET}" --verbose=false if [[ -n "${ONE_SHOT-}" ]]; then - set -- "$@" --one-shot + set -- "$@" --one-shot else - set -- "$@" --apply + set -- "$@" --apply fi -chezmoi init "$@" +chezmoi init "$@" \ No newline at end of file diff --git a/scripts/update_bindings.py b/scripts/update_bindings.py new file mode 100644 index 00000000..890376e6 --- /dev/null +++ b/scripts/update_bindings.py @@ -0,0 +1,331 @@ +import re + +# File paths and markers +HYPRLAND_BINDINGS_FILE = ( + "home/private_dot_config/exact_hypr/exact_hyprland/bindings.conf" +) +KOMOREBI_AHK_CONFIG_FILE = "home/private_AppData/Roaming/exact_komorebi/komorebi.ahk" +README_FILE = "README.md" +START_MARKER = "### Bindings" +END_MARKER = "#### OS Compatibility" + + +def preprocess_hyprland_variables(file_path): + """ + Preprocess variables from a Hyprland configuration file. + + Args: + - file_path (str): Path to the Hyprland configuration file. + + Returns: + - variables (dict): Dictionary of parsed variables. + """ + variables = {} + with open(file_path, "r") as file: + for line in file: + # Remove comments at end of line if present + line = re.sub(r"\s*#.*$", "", line) + line = line.strip() + if line.startswith("$"): + var_match = re.match(r"^\$([^\s=]+)\s*=\s*(.*?)$", line) + if var_match: + var_name = var_match.group(1) + var_value = var_match.group(2).strip() + variables[var_name] = var_value + return variables + + +def parse_bindings(hyprland_config_path, variables, ahk_config_path): + """ + Parse bindings from a configuration file using predefined patterns. + + Args: + - hyprland_config_path (str): Path to the bindings configuration file. + - variables (dict): Dictionary of variables for variable substitution. + - ahk_config_path (str): Path to the AutoHotKey configuration file (Windows). + + Returns: + - bindings (list): List of parsed bindings as dictionaries. + """ + bindings = [] + + win_bindings = [ + {"mods": ["ALT"], "key": "space"}, + {"mods": ["SUPER"], "key": "V"}, + {"mods": [], "key": "XF86PowerOff"}, + {"mods": [], "key": "Print"}, + {"mods": ["SUPER"], "key": "Print"}, + {"mods": ["SUPER", "ALT"], "key": "Print"}, + {"mods": ["SUPER"], "key": "E"}, + {"mods": ["CTRL", "SHIFT"], "key": "Escape"}, + {"mods": [], "key": "XF86AudioLowerVolume"}, + {"mods": [], "key": "XF86AudioRaiseVolume"}, + {"mods": [], "key": "XF86AudioMute"}, + {"mods": [], "key": "XF86AudioMicMute"}, + {"mods": [], "key": "XF86AudioPlay"}, + {"mods": [], "key": "XF86AudioPause"}, + {"mods": [], "key": "XF86AudioNext"}, + {"mods": [], "key": "XF86AudioPrev"}, + {"mods": [], "key": "XF86MonBrightnessDown"}, + {"mods": [], "key": "XF86MonBrightnessUp"}, + ] + + ahk_mods = {"#": "SUPER", "^": "CTRL", "+": "SHIFT", "!": "ALT"} + ahk_characters = { + "\\": "Backslash", + "WheelUp": "mouse_up", + "WheelDown": "mouse_down", + } + + with open(hyprland_config_path, "r") as file: + for line in file: + # Strip leading/trailing whitespace and comments + line = line.strip() + + # Skip lines that do not start with 'bind' + if not line.startswith("bind"): + continue + + # Replace variables + for var_name, var_value in variables.items(): + line = line.replace(f"${var_name}", var_value) + + # Remove comment at end of line if present + line = re.sub(r"\s*#.*$", "", line) + + # Patterns for different binding types + bind_match = re.match( + r"^bind([a-z]*)\s*=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)(?:\s*,\s*(.*?))?\s*$", + line, + ) + bind_with_description = re.match( + r"^bind([a-z]*d[a-z]*)\s*=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)(?:\s*,\s*(.*?))?\s*$", + line, + ) + + # Initialize variables for parsing + flags = [] + mods = [] + unresolved_key = "" + dispatcher = "" + params = "" + description = "" + + # Parse based on matched pattern + if bind_with_description: + flags = list(bind_with_description.group(1).strip()) + mods = ( + bind_with_description.group(2).strip().split(" ") + if bind_with_description.group(2).strip() + else [] + ) + unresolved_key = bind_with_description.group(3).strip() + description = bind_with_description.group(4).strip() + dispatcher = bind_with_description.group(5).strip() + params = ( + bind_with_description.group(6).strip() + if bind_with_description.group(6) + else "" + ) + flags.remove("d") + elif bind_match: + flags = list(bind_match.group(1).strip()) + mods = ( + bind_match.group(2).strip().split(" ") + if bind_match.group(2).strip() + else [] + ) + unresolved_key = bind_match.group(3).strip() + dispatcher = bind_match.group(4).strip() + params = bind_match.group(5).strip() if bind_match.group(5) else "" + + # If a valid binding was found, add to bindings list + if bind_match or bind_with_description: + if "m" in flags: + flags.remove("m") + bindings.append( + { + "flags": flags, + "mods": mods, + "key": unresolved_key, + "description": description, + "dispatcher": dispatcher, + "params": params, + } + ) + + with open(ahk_config_path, "r") as file: + beginning = False + for line in file: + # Strip leading/trailing whitespace and comments + line = line.strip() + + # Don't start until we find the `Komorebic` function + if line.startswith("Komorebic"): + beginning = True + continue + if not beginning or line == "": + continue + + if line[0] not in ahk_mods.keys(): + continue + + mods = [] + key = "" + + keys = re.findall(r"\w+|\W", line.split("::")[0]) + + for unresolved_key in keys: + if unresolved_key in ahk_mods.keys(): + mods.append(ahk_mods[unresolved_key]) + elif unresolved_key in ahk_characters.keys(): + key = ahk_characters[unresolved_key] + else: + key = unresolved_key.upper() or "" + + if key and mods: + win_bindings.append( + { + "mods": mods, + "key": key, + } + ) + + for win_binding in win_bindings: + for binding in bindings: + if ( + set(map(lambda mod: mod.lower(), binding["mods"])) + == set(map(lambda mod: mod.lower(), win_binding["mods"])) + and binding["key"].lower() == win_binding["key"].lower() + ): + binding["has_win"] = True + + return bindings + + +def generate_table(bindings): + """ + Generate a markdown table from parsed bindings. + + Args: + - bindings (list): List of bindings as dictionaries. + + Returns: + - table_content (str): Markdown formatted table content. + """ + key_labels = { + "mouse:272": "Left Mouse Button", + "mouse:273": "Right Mouse Button", + "mouse_up": "Mouse Wheel Up", + "mouse_down": "Mouse Wheel Down", + "left": "โ†", + "right": "โ†’", + "up": "โ†‘", + "down": "โ†“", + } + + table_content = "| Modifiers | Key | Description | OS | Flags |\n" + table_content += "| --- | --- | --- | --- | --- |\n" + + def change_mod_label(mod): + if mod.lower() in key_labels.keys(): + mod = key_labels[mod.lower()] + mod = ( + mod.capitalize() if mod.isalpha() and mod.lower() not in key_labels else mod + ) + + if mod == "Super": + mod = "Win" + + return mod + + for binding in bindings: + # Mods + modifiers = ( + "" + + (" + ".join(map(change_mod_label, binding["mods"]))) + + "" + if len(binding["mods"]) > 0 + else "-" + ) + # Key + key = re.sub(r"XF86([a-zA-Z0-9]+)", r"\1 Button", binding["key"]) + if binding["key"].lower() in key_labels.keys(): + key = key_labels[binding["key"].lower()] + key = ( + key.capitalize() + if key.isalpha() and binding["key"].lower() not in key_labels + else key + ) + + # Optional description + description = binding["description"] if binding["description"] else "-" + + # Flags + flags = "`" + "`, `".join(binding["flags"]) + "`" if binding["flags"] else "-" + + table_content += f"| {modifiers} | {key} | {description} | `L`{", `W`" if ("has_win" in binding and binding["has_win"] or False) else ""} | {flags} |\n" + + return table_content.strip() + + +def update_readme(readme_file, start_marker, end_marker, table_content): + """ + Update the README file with the generated table content. + + Args: + - readme_file (str): Path to the README file. + - start_marker (str): Start marker in README to begin updating from. + - end_marker (str): End marker in README to stop updating at. + - table_content (str): Markdown formatted table content. + """ + updated_readme = "" + in_bindings_section = False + + with open(readme_file, "r") as file: + readme_lines = file.readlines() + + for line in readme_lines: + if line.strip() == start_marker: + in_bindings_section = True + updated_readme += line + updated_readme += "\n" + updated_readme += table_content + "\n\n" + elif line.strip() == end_marker: + in_bindings_section = False + updated_readme += line + elif not in_bindings_section: + updated_readme += line + + with open(readme_file, "w") as file: + file.write(updated_readme) + + +if __name__ == "__main__": + # Debug: Print the starting point + print("Running script...") + + # Preprocess variables from the bindings file + print("Preprocessing variables...") + variables = preprocess_hyprland_variables(HYPRLAND_BINDINGS_FILE) + print(f"Variables: {variables}") + + # Parse bindings using preprocessed variables + print("Parsing bindings...") + bindings = parse_bindings( + HYPRLAND_BINDINGS_FILE, variables, KOMOREBI_AHK_CONFIG_FILE + ) + print(f"Bindings: {bindings}") + + # Generate markdown table from parsed bindings + print("Generating table...") + table_content = generate_table(bindings) + print(f"Table content:\n{table_content}") + + # Update the README file with the generated table content + print("Updating README.md...") + update_readme(README_FILE, START_MARKER, END_MARKER, table_content) + print("README.md updated") + + # Debug: Print the completion + print("Script completed")