aboutsummaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorsrdusr <trevorgray@srdusr.com>2025-08-30 19:22:59 +0200
committersrdusr <trevorgray@srdusr.com>2025-08-30 19:22:59 +0200
commit19120d4f9761c67d99ed1ce3da6084b83f5a49c9 (patch)
treef234cad1bdad88114a63c9702144da487024967a /linux
parent5928998af5404ae2be84c6cecc10ebf84bd3f3ed (diff)
downloaddotfiles-19120d4f9761c67d99ed1ce3da6084b83f5a49c9.tar.gz
dotfiles-19120d4f9761c67d99ed1ce3da6084b83f5a49c9.zip
Linux-specific dotfiles
Diffstat (limited to 'linux')
-rw-r--r--linux/home/.config/Code/User/keybindings.json274
-rw-r--r--linux/home/.config/Code/User/settings.json734
-rw-r--r--linux/home/.config/Code/User/snippets/snippet.code-snippets126
-rw-r--r--linux/home/.config/Code/User/spellright.dict14
-rw-r--r--linux/home/.config/Code/User/vsc.css408
-rw-r--r--linux/home/.config/Code/User/vsc.js100
-rw-r--r--linux/home/.config/X11/.Xresources307
-rw-r--r--linux/home/.config/X11/.xbindkeysrc31
-rwxr-xr-xlinux/home/.config/X11/.xinitrc34
-rw-r--r--linux/home/.config/X11/.xprofile24
-rw-r--r--linux/home/.config/ags/.eslintrc.yml130
-rw-r--r--linux/home/.config/ags/.gitignore6
-rw-r--r--linux/home/.config/ags/assets/arrows-down.svg10
-rw-r--r--linux/home/.config/ags/assets/arrows-left.svg10
-rw-r--r--linux/home/.config/ags/assets/arrows-right.svg10
-rw-r--r--linux/home/.config/ags/assets/arrows-up.svg10
-rw-r--r--linux/home/.config/ags/assets/battery-flash-symbolic.svg4
-rw-r--r--linux/home/.config/ags/assets/bomb-kill.svg36
-rw-r--r--linux/home/.config/ags/assets/chat-bubbles-symbolic.svg5
-rw-r--r--linux/home/.config/ags/assets/controller-symbolic.svg4
-rw-r--r--linux/home/.config/ags/assets/controls-symbolic.svg5
-rw-r--r--linux/home/.config/ags/assets/dark-mode-symbolic.svg4
-rw-r--r--linux/home/.config/ags/assets/float.svg44
-rw-r--r--linux/home/.config/ags/assets/fullscreen.svg43
-rw-r--r--linux/home/.config/ags/assets/hourglass-symbolic.svg4
-rw-r--r--linux/home/.config/ags/assets/light-mode-symbolic.svg4
-rw-r--r--linux/home/.config/ags/assets/mixer-symbolic.svg6
-rw-r--r--linux/home/.config/ags/assets/nix-snowflake-symbolic.svg155
-rw-r--r--linux/home/.config/ags/assets/nixos-symbolic.svg155
-rw-r--r--linux/home/.config/ags/assets/nixos.svg277
-rw-r--r--linux/home/.config/ags/assets/osk.svg132
-rw-r--r--linux/home/.config/ags/assets/pinned.svg36
-rw-r--r--linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg321
-rw-r--r--linux/home/.config/ags/assets/processor-symbolic.svg17
-rw-r--r--linux/home/.config/ags/assets/rotation.svg8
-rw-r--r--linux/home/.config/ags/assets/swapnext.svg8
-rw-r--r--linux/home/.config/ags/assets/tbox-close.svg49
-rw-r--r--linux/home/.config/ags/assets/terminal-symbolic.svg5
-rw-r--r--linux/home/.config/ags/assets/togglesplit.svg10
-rw-r--r--linux/home/.config/ags/assets/toolbars-symbolic.svg4
-rw-r--r--linux/home/.config/ags/assets/wp-next.svg10
-rw-r--r--linux/home/.config/ags/assets/wp-prev.svg10
-rw-r--r--linux/home/.config/ags/config.js46
-rw-r--r--linux/home/.config/ags/default.nix104
-rw-r--r--linux/home/.config/ags/greeter.js18
-rw-r--r--linux/home/.config/ags/greeter/auth.ts109
-rw-r--r--linux/home/.config/ags/greeter/greeter.scss64
-rw-r--r--linux/home/.config/ags/greeter/greeter.ts37
-rw-r--r--linux/home/.config/ags/greeter/session.ts20
-rw-r--r--linux/home/.config/ags/greeter/statusbar.ts46
-rw-r--r--linux/home/.config/ags/lib/battery.ts16
-rw-r--r--linux/home/.config/ags/lib/client.js134
-rw-r--r--linux/home/.config/ags/lib/cursorhover.js86
-rw-r--r--linux/home/.config/ags/lib/gtk.ts16
-rw-r--r--linux/home/.config/ags/lib/hyprland.ts80
-rw-r--r--linux/home/.config/ags/lib/iconUtils.js46
-rw-r--r--linux/home/.config/ags/lib/icons.ts186
-rw-r--r--linux/home/.config/ags/lib/init.ts19
-rw-r--r--linux/home/.config/ags/lib/matugen.ts113
-rw-r--r--linux/home/.config/ags/lib/notifications.ts16
-rw-r--r--linux/home/.config/ags/lib/option.ts115
-rw-r--r--linux/home/.config/ags/lib/session.ts16
-rw-r--r--linux/home/.config/ags/lib/tmux.ts14
-rw-r--r--linux/home/.config/ags/lib/utils.ts113
-rw-r--r--linux/home/.config/ags/lib/variables.ts47
-rw-r--r--linux/home/.config/ags/main.ts47
-rw-r--r--linux/home/.config/ags/options.ts261
-rw-r--r--linux/home/.config/ags/package.json18
-rw-r--r--linux/home/.config/ags/service/asusctl.ts52
-rw-r--r--linux/home/.config/ags/service/brightness.ts69
-rw-r--r--linux/home/.config/ags/service/colorpicker.ts56
-rw-r--r--linux/home/.config/ags/service/nix.ts109
-rw-r--r--linux/home/.config/ags/service/powermenu.ts43
-rw-r--r--linux/home/.config/ags/service/screenrecord.ts102
-rw-r--r--linux/home/.config/ags/service/wallpaper.ts127
-rw-r--r--linux/home/.config/ags/service/weather.ts59
-rw-r--r--linux/home/.config/ags/style/extra.scss67
-rw-r--r--linux/home/.config/ags/style/mixins/a11y-button.scss48
-rw-r--r--linux/home/.config/ags/style/mixins/button.scss70
-rw-r--r--linux/home/.config/ags/style/mixins/floating-widget.scss12
-rw-r--r--linux/home/.config/ags/style/mixins/hidden.scss15
-rw-r--r--linux/home/.config/ags/style/mixins/media.scss42
-rw-r--r--linux/home/.config/ags/style/mixins/scrollable.scss42
-rw-r--r--linux/home/.config/ags/style/mixins/slider.scss74
-rw-r--r--linux/home/.config/ags/style/mixins/spacing.scss53
-rw-r--r--linux/home/.config/ags/style/mixins/switch.scss16
-rw-r--r--linux/home/.config/ags/style/mixins/unset.scss9
-rw-r--r--linux/home/.config/ags/style/mixins/widget.scss7
-rw-r--r--linux/home/.config/ags/style/style.ts103
-rw-r--r--linux/home/.config/ags/tsconfig.json19
-rw-r--r--linux/home/.config/ags/widget/PopupWindow.ts156
-rw-r--r--linux/home/.config/ags/widget/RegularWindow.ts3
-rw-r--r--linux/home/.config/ags/widget/bar/Bar.ts57
-rw-r--r--linux/home/.config/ags/widget/bar/PanelButton.ts46
-rw-r--r--linux/home/.config/ags/widget/bar/ScreenCorners.ts25
-rw-r--r--linux/home/.config/ags/widget/bar/bar.scss242
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts94
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts37
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/Date.ts15
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/Launcher.ts49
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/Media.ts92
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/Messages.ts16
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts15
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts21
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/SysTray.ts39
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts107
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/Taskbar.ts90
-rw-r--r--linux/home/.config/ags/widget/bar/buttons/Workspaces.ts66
-rw-r--r--linux/home/.config/ags/widget/bar/screencorner.scss51
-rw-r--r--linux/home/.config/ags/widget/datemenu/DateColumn.ts58
-rw-r--r--linux/home/.config/ags/widget/datemenu/DateMenu.ts36
-rw-r--r--linux/home/.config/ags/widget/datemenu/NotificationColumn.ts113
-rw-r--r--linux/home/.config/ags/widget/datemenu/datemenu.scss110
-rw-r--r--linux/home/.config/ags/widget/desktop/Desktop.ts40
-rw-r--r--linux/home/.config/ags/widget/dock/Dock.ts150
-rw-r--r--linux/home/.config/ags/widget/dock/FloatingDock.ts70
-rw-r--r--linux/home/.config/ags/widget/dock/ToolBox.ts122
-rw-r--r--linux/home/.config/ags/widget/dock/ToolBoxDock.ts57
-rw-r--r--linux/home/.config/ags/widget/dock/dock.scss73
-rw-r--r--linux/home/.config/ags/widget/launcher/AppLauncher.ts125
-rw-r--r--linux/home/.config/ags/widget/launcher/Launcher.ts134
-rw-r--r--linux/home/.config/ags/widget/launcher/NixRun.ts118
-rw-r--r--linux/home/.config/ags/widget/launcher/ShRun.ts89
-rw-r--r--linux/home/.config/ags/widget/launcher/launcher.scss143
-rw-r--r--linux/home/.config/ags/widget/notifications/Notification.ts138
-rw-r--r--linux/home/.config/ags/widget/notifications/NotificationPopups.ts90
-rw-r--r--linux/home/.config/ags/widget/notifications/notifications.scss79
-rw-r--r--linux/home/.config/ags/widget/osd/OSD.ts111
-rw-r--r--linux/home/.config/ags/widget/osd/Progress.ts74
-rw-r--r--linux/home/.config/ags/widget/osd/osd.scss26
-rw-r--r--linux/home/.config/ags/widget/overview/Overview.ts41
-rw-r--r--linux/home/.config/ags/widget/overview/Window.ts48
-rw-r--r--linux/home/.config/ags/widget/overview/Workspace.ts76
-rw-r--r--linux/home/.config/ags/widget/overview/overview.scss34
-rw-r--r--linux/home/.config/ags/widget/powermenu/PowerMenu.ts56
-rw-r--r--linux/home/.config/ags/widget/powermenu/Verification.ts47
-rw-r--r--linux/home/.config/ags/widget/powermenu/powermenu.scss110
-rw-r--r--linux/home/.config/ags/widget/quicksettings/QuickSettings.ts84
-rw-r--r--linux/home/.config/ags/widget/quicksettings/ToggleButton.ts154
-rw-r--r--linux/home/.config/ags/widget/quicksettings/quicksettings.scss177
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts61
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts23
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/DND.ts12
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts12
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/Header.ts69
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/Media.ts153
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts18
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/Network.ts61
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts99
-rw-r--r--linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts161
-rw-r--r--linux/home/.config/ags/widget/settings/Group.ts34
-rw-r--r--linux/home/.config/ags/widget/settings/Page.ts19
-rw-r--r--linux/home/.config/ags/widget/settings/Row.ts55
-rw-r--r--linux/home/.config/ags/widget/settings/Setter.ts93
-rw-r--r--linux/home/.config/ags/widget/settings/SettingsDialog.ts63
-rw-r--r--linux/home/.config/ags/widget/settings/Wallpaper.ts31
-rw-r--r--linux/home/.config/ags/widget/settings/layout.ts147
-rw-r--r--linux/home/.config/ags/widget/settings/settingsdialog.scss144
-rw-r--r--linux/home/.config/betterlockscreen/betterlockscreenrc37
-rwxr-xr-xlinux/home/.config/bspwm/bspwmrc275
-rwxr-xr-xlinux/home/.config/bspwm/scripts/bspdragtofloat46
-rwxr-xr-xlinux/home/.config/bspwm/scripts/bspswallow12
-rwxr-xr-xlinux/home/.config/bspwm/scripts/bspwindows14
-rwxr-xr-xlinux/home/.config/bspwm/scripts/bspwm-monitor-setup59
-rwxr-xr-xlinux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh23
-rwxr-xr-xlinux/home/.config/bspwm/scripts/close-window11
-rwxr-xr-xlinux/home/.config/bspwm/scripts/drag-float42
-rwxr-xr-xlinux/home/.config/bspwm/scripts/external_rules.sh71
-rwxr-xr-xlinux/home/.config/bspwm/scripts/hide-window38
-rw-r--r--linux/home/.config/dunst/assets/notification/fallback.pngbin0 -> 54750 bytes
-rw-r--r--linux/home/.config/dunst/assets/notification/music.pngbin0 -> 814 bytes
-rw-r--r--linux/home/.config/dunst/assets/notification/scrot.pngbin0 -> 35737 bytes
-rw-r--r--linux/home/.config/dunst/assets/ui/volume-high.svg1
-rw-r--r--linux/home/.config/dunst/assets/ui/volume-low.svg1
-rw-r--r--linux/home/.config/dunst/assets/ui/volume-medium.svg1
-rw-r--r--linux/home/.config/dunst/assets/ui/volume-muted.svg1
-rw-r--r--linux/home/.config/dunst/dunstrc456
-rwxr-xr-xlinux/home/.config/dunst/scripts/openEwwPopup.sh36
-rwxr-xr-xlinux/home/.config/dunst/scripts/songArtLogger.sh17
-rw-r--r--linux/home/.config/eww/eww.scss11
-rw-r--r--linux/home/.config/eww/eww.yuck23
-rwxr-xr-xlinux/home/.config/hypr/autostart34
-rw-r--r--linux/home/.config/hypr/hyprland.conf175
-rwxr-xr-xlinux/home/.config/hypr/scripts/move-scratchpad.sh9
-rw-r--r--linux/home/.config/hypr/user/binds.conf167
-rw-r--r--linux/home/.config/hypr/user/env.conf23
-rw-r--r--linux/home/.config/hypr/user/exec.conf4
-rw-r--r--linux/home/.config/hypr/user/monitors.conf4
-rw-r--r--linux/home/.config/hypr/user/window_rules.conf70
-rw-r--r--linux/home/.config/inputrc86
-rw-r--r--linux/home/.config/jgmenu/jgmenurc32
-rw-r--r--linux/home/.config/jgmenu/menu.csv32
-rw-r--r--linux/home/.config/kitty/kitty.conf827
-rw-r--r--linux/home/.config/mimeapps.list14
-rw-r--r--linux/home/.config/picom/picom.conf494
-rw-r--r--linux/home/.config/plank/dock/launchers/Alacritty.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/discord.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/firefox.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/gimp.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/google-chrome.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/obsidian.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/spotify.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/steam.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/trash.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/virtualbox.dockitem2
-rw-r--r--linux/home/.config/plank/dock/launchers/vlc.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/code-oss.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/discord.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/firefox.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/obsidian.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/phototonic.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/steam.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/trash.dockitem2
-rw-r--r--linux/home/.config/plank/dock1/launchers/vlc.dockitem2
-rw-r--r--linux/home/.config/polybar/config.ini671
-rwxr-xr-xlinux/home/.config/polybar/launch.sh31
-rwxr-xr-xlinux/home/.config/polybar/scripts/bluetooth.sh12
-rwxr-xr-xlinux/home/.config/polybar/scripts/check-network.sh21
-rwxr-xr-xlinux/home/.config/polybar/scripts/check_updates.sh118
-rwxr-xr-xlinux/home/.config/polybar/scripts/cmus.sh39
-rwxr-xr-xlinux/home/.config/polybar/scripts/get_spotify_status.sh52
-rwxr-xr-xlinux/home/.config/polybar/scripts/menu.sh6
-rwxr-xr-xlinux/home/.config/polybar/scripts/menu.shsave63
-rwxr-xr-xlinux/home/.config/polybar/scripts/menu_full.sh65
-rwxr-xr-xlinux/home/.config/polybar/scripts/now-playing.sh217
-rwxr-xr-xlinux/home/.config/polybar/scripts/polybar_wrapper92
-rwxr-xr-xlinux/home/.config/polybar/scripts/popup-calendar.sh41
-rwxr-xr-xlinux/home/.config/polybar/scripts/rofi-power.sh45
-rwxr-xr-xlinux/home/.config/polybar/scripts/scroll_spotify_status.sh12
-rwxr-xr-xlinux/home/.config/polybar/scripts/sysmenu.sh42
-rwxr-xr-xlinux/home/.config/polybar/scripts/sysmenu.shsave40
-rwxr-xr-xlinux/home/.config/polybar/scripts/system-usb-mount.sh53
-rwxr-xr-xlinux/home/.config/polybar/scripts/temperature.sh18
-rwxr-xr-xlinux/home/.config/polybar/scripts/toggle_bluetooth.sh8
-rwxr-xr-xlinux/home/.config/polybar/scripts/vpn.sh28
-rw-r--r--linux/home/.config/powershell/Microsoft.PowerShell_profile.ps114
-rw-r--r--linux/home/.config/powershell/bloatware.ps1335
-rw-r--r--linux/home/.config/powershell/bootstrap.ps1396
-rw-r--r--linux/home/.config/powershell/initialize.ps1227
-rw-r--r--linux/home/.config/pypoetry/config.toml3
-rw-r--r--linux/home/.config/rofi/Notif.rasi153
-rw-r--r--linux/home/.config/rofi/colors/gruvbox.rasi10
-rw-r--r--linux/home/.config/rofi/colors/nord.rasi10
-rw-r--r--linux/home/.config/rofi/colors/simple.rasi10
-rw-r--r--linux/home/.config/rofi/config.rasi178
-rw-r--r--linux/home/.config/rofi/options_menu.rasi71
-rw-r--r--linux/home/.config/rofi/rofi-network-manager.conf41
-rw-r--r--linux/home/.config/rofi/rofi-network-manager.rasi127
-rw-r--r--linux/home/.config/rofi/styles/appmenu.rasi186
-rw-r--r--linux/home/.config/rofi/styles/powermenu.rasi187
-rw-r--r--linux/home/.config/rofi/themes/colors.rasi18
-rw-r--r--linux/home/.config/rofi/themes/dmenu.rasi38
-rw-r--r--linux/home/.config/rofi/themes/power.rasi34
-rwxr-xr-xlinux/home/.config/sxhkd/show_help.sh3
-rwxr-xr-xlinux/home/.config/sxhkd/sxhkdrc490
-rw-r--r--linux/home/.config/tridactyl/tridactylrc170
-rw-r--r--linux/home/.config/user-dirs.dirs15
-rw-r--r--linux/home/.config/user-dirs.locale1
-rw-r--r--linux/home/.config/waybar/config.jsonc292
-rw-r--r--linux/home/.config/waybar/style.css434
-rw-r--r--linux/home/.config/wezterm/wezterm.lua206
-rw-r--r--linux/home/.config/windows-terminal/settings.json590
-rw-r--r--linux/home/.config/wofi/config17
-rw-r--r--linux/home/.config/wofi/style.css99
-rw-r--r--linux/home/.config/xkb/symbols/custom-us27
-rwxr-xr-xlinux/home/.config/xob/launch.sh10
-rwxr-xr-xlinux/home/.config/xob/manage-brightness16
-rwxr-xr-xlinux/home/.config/xob/manage-microphone56
-rwxr-xr-xlinux/home/.config/xob/manage-volume46
-rw-r--r--linux/home/.config/xob/styles.cfg100
-rw-r--r--linux/home/.config/zathura/zathurarc27
-rw-r--r--linux/home/.config/zsh/.zshenv348
-rw-r--r--linux/home/.config/zsh/.zshrc63
-rw-r--r--linux/home/.config/zsh/user/aliases.zsh129
-rw-r--r--linux/home/.config/zsh/user/bindings.zsh39
-rw-r--r--linux/home/.config/zsh/user/completion.zsh156
-rw-r--r--linux/home/.config/zsh/user/functions.zsh813
-rw-r--r--linux/home/.config/zsh/user/options.zsh50
-rw-r--r--linux/home/.config/zsh/user/prompt.zsh202
-rw-r--r--linux/home/.editorconfig76
-rw-r--r--linux/home/.facebin0 -> 11569 bytes
-rw-r--r--linux/home/.gitconfig28
-rw-r--r--linux/home/.github/workflows/release.yml59
-rw-r--r--linux/home/.gitignore48
-rw-r--r--linux/home/.gitmodules12
-rw-r--r--linux/home/.gitsubtrees8
-rwxr-xr-xlinux/home/.local/bin/control-center31
-rwxr-xr-xlinux/home/.local/bin/ewwbin0 -> 22225024 bytes
-rwxr-xr-xlinux/home/.local/bin/ffmpeg24
-rwxr-xr-xlinux/home/.local/bin/nitrogen63
-rwxr-xr-xlinux/home/.local/bin/notification-center26
-rwxr-xr-xlinux/home/.local/bin/xcolor-pick31
-rw-r--r--linux/home/.local/share/applications/com.obsproject.Studio.desktop99
-rw-r--r--linux/home/.local/share/applications/phototonic.desktop17
-rw-r--r--linux/home/.local/share/fonts/fantasque_sans_mono.ttfbin0 -> 140224 bytes
-rw-r--r--linux/home/.local/share/fonts/fira_code_nerd_fonts.ttfbin0 -> 1149928 bytes
-rw-r--r--linux/home/.local/share/fonts/hack_nerd_fonts_mono.ttfbin0 -> 1169264 bytes
-rw-r--r--linux/home/.local/share/fonts/iosevka_nerd_font.ttfbin0 -> 1301148 bytes
-rw-r--r--linux/home/.local/share/fonts/material_design_iconic_font.ttfbin0 -> 99212 bytes
-rw-r--r--linux/home/.local/share/fonts/symbola.ttfbin0 -> 3424752 bytes
-rw-r--r--linux/home/.prettierrc.yml5
-rw-r--r--linux/home/.profile16
-rwxr-xr-xlinux/home/.scripts/Heads-Up-Display28
-rw-r--r--linux/home/.scripts/README.md1
-rwxr-xr-xlinux/home/.scripts/bspwm-toggle-visibility.sh23
-rwxr-xr-xlinux/home/.scripts/bspwm_resize.sh67
-rw-r--r--linux/home/.scripts/check-updates.sh0
-rwxr-xr-xlinux/home/.scripts/colors.sh78
-rwxr-xr-xlinux/home/.scripts/cryptocheck31
-rwxr-xr-xlinux/home/.scripts/cryptonotify19
-rwxr-xr-xlinux/home/.scripts/dotfiles.sh37
-rwxr-xr-xlinux/home/.scripts/ffmpeg24
-rwxr-xr-xlinux/home/.scripts/get_zle_keymap_select.sh13
-rwxr-xr-xlinux/home/.scripts/gsettings.sh27
-rwxr-xr-xlinux/home/.scripts/killandnotify4
-rwxr-xr-xlinux/home/.scripts/layer.sh24
-rwxr-xr-xlinux/home/.scripts/neovim.sh421
-rwxr-xr-xlinux/home/.scripts/opacity-change.sh34
-rwxr-xr-xlinux/home/.scripts/powermenu38
-rwxr-xr-xlinux/home/.scripts/qemu-helper.sh172
-rwxr-xr-xlinux/home/.scripts/random_data.py153
-rwxr-xr-xlinux/home/.scripts/scratchpad64
-rwxr-xr-xlinux/home/.scripts/spec73
-rwxr-xr-xlinux/home/.scripts/track-books.sh19
-rw-r--r--linux/home/.scripts/win-nvim.bat37
-rw-r--r--linux/home/.scripts/win-nvim.ps139
-rw-r--r--linux/home/.vim/autoload/statusline.vim227
m---------linux/home/.vim/pack/plugins/start/vim-tmux-navigator0
-rw-r--r--linux/home/.vim/vimrc296
-rw-r--r--linux/home/.vnc/config4
-rwxr-xr-xlinux/home/.vnc/xstartup16
-rw-r--r--linux/home/README.md698
-rw-r--r--linux/home/assets/desktop.jpgbin0 -> 523045 bytes
-rw-r--r--linux/home/assets/old_desktop.jpgbin0 -> 108709 bytes
-rw-r--r--linux/home/extras/etc/X11/xorg.conf.d/70-synaptics.conf15
-rw-r--r--linux/home/extras/etc/issue14
-rw-r--r--linux/home/extras/etc/lightdm/lightdm-gtk-greeter.conf17
-rw-r--r--linux/home/extras/etc/lightdm/lightdm-webkit2-greeter.conf49
-rw-r--r--linux/home/extras/etc/lightdm/lightdm.conf161
-rw-r--r--linux/home/extras/etc/udev/rules.d/99-reload-monitor.rules1
-rw-r--r--linux/home/install.bat6
-rwxr-xr-xlinux/home/install.sh927
-rw-r--r--linux/home/packages.yml436
348 files changed, 27965 insertions, 0 deletions
diff --git a/linux/home/.config/Code/User/keybindings.json b/linux/home/.config/Code/User/keybindings.json
new file mode 100644
index 0000000..9d04af3
--- /dev/null
+++ b/linux/home/.config/Code/User/keybindings.json
@@ -0,0 +1,274 @@
+[
+ {
+ "key": "ctrl+shift+r",
+ "command": "workbench.action.reloadWindow",
+ "when": "editorTextFocus"
+ },
+ {
+ "key": "ctrl+i",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .py",
+ "args": {
+ "text": "python \"${file}\" < ./i\n"
+ }
+ },
+ {
+ "key": "f5",
+ "command": "python.execInTerminal",
+ "when": "resourceExtname == .py",
+ },
+ {
+ "key": "f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .dart",
+ "args": {
+ "text": "dart \"${file}\"\n"
+ }
+ },
+ {
+ "key": "f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .js",
+ "args": {
+ "text": "node \"${file}\"\n"
+ }
+ },
+ {
+ "key": "f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .java",
+ "args": {
+ "text": "java \"${file}\"\n"
+ }
+ },
+ {
+ "key": "f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .sh",
+ "args": {
+ "text": "\"${file}\"\n"
+ }
+ },
+ {
+ "key": "f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .cpp",
+ "args": {
+ "text": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n"
+ }
+ },
+ {
+ "key": "f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .c",
+ "args": {
+ "text": "gcc -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n"
+ }
+ },
+ {
+ "key": "f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .asm",
+ "args": {
+ "text": "nasm -f elf64 \"${file}\" && ld -o \"${fileDirname}/${fileBasenameNoExtension}\" \"${fileDirname}/${fileBasenameNoExtension}.o\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n"
+ }
+ },
+ {
+ "key": "ctrl+i",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .cpp",
+ "args": {
+ "text": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\" < ./i\n"
+ }
+ },
+ {
+ "key": "ctrl+g",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .cpp",
+ "args": {
+ "text": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" -lgraph -lGL -lGLU -lglut && \"${fileDirname}/${fileBasenameNoExtension}\" 2>/dev/null\n"
+ }
+ },
+ // {
+ // "key": "f5",
+ // "command": "workbench.action.tasks.runTask",
+ // "when": "resourceExtname == .cpp",
+ // "args": "Build and Run C++"
+ // },
+ {
+ "key": "shift+f5",
+ "command": "workbench.action.terminal.sendSequence",
+ "when": "resourceExtname == .cpp",
+ "args": {
+ "text": "g++ -g \"${fileDirname}/*.cpp\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n"
+ }
+ },
+ // {
+ // "key": "shift+f5",
+ // "command": "workbench.action.tasks.runTask",
+ // "when": "resourceExtname == .cpp",
+ // "args": "Build and Run C++ (Multiple cpp files)"
+ // },
+ {
+ "key": "f4",
+ "command": "workbench.action.debug.continue",
+ "when": "inDebugMode"
+ },
+ {
+ "key": "f4",
+ "command": "workbench.action.debug.start",
+ "when": "!inDebugMode"
+ },
+ {
+ "key": "f4",
+ "command": "workbench.action.debug.start",
+ "when": "debuggersAvailable && !inDebugMode"
+ },
+ {
+ "key": "f5",
+ "command": "-workbench.action.debug.continue",
+ "when": "inDebugMode"
+ },
+ {
+ "key": "f5",
+ "command": "-workbench.action.debug.start",
+ "when": "!inDebugMode"
+ },
+ {
+ "key": "f5",
+ "command": "-workbench.action.debug.start",
+ "when": "debuggersAvailable && !inDebugMode"
+ },
+ {
+ "key": "shift+f4",
+ "command": "workbench.action.debug.stop",
+ "when": "inDebugMode"
+ },
+ {
+ "key": "shift+f5",
+ "command": "-workbench.action.debug.stop",
+ "when": "inDebugMode"
+ },
+ {
+ "key": "ctrl+v",
+ "command": "workbench.action.terminal.paste",
+ "when": "terminalFocus && terminalProcessSupported"
+ },
+ {
+ "key": "ctrl+shift+v",
+ "command": "-workbench.action.terminal.paste",
+ "when": "terminalFocus && terminalProcessSupported"
+ },
+ {
+ "key": "ctrl+alt+up",
+ "command": "editor.action.copyLinesUpAction",
+ "when": "editorTextFocus && !editorReadonly"
+ },
+ {
+ "key": "ctrl+alt+down",
+ "command": "editor.action.copyLinesDownAction",
+ "when": "editorTextFocus && !editorReadonly"
+ },
+ {
+ "key": "ctrl+shift+alt+up",
+ "command": "-editor.action.copyLinesUpAction",
+ "when": "editorTextFocus && !editorReadonly"
+ },
+ {
+ "key": "ctrl+shift+alt+down",
+ "command": "-editor.action.copyLinesDownAction",
+ "when": "editorTextFocus && !editorReadonly"
+ },
+ {
+ "key": "ctrl+,",
+ "command": "-workbench.action.openSettings"
+ },
+ {
+ "key": "ctrl+,",
+ "command": "workbench.action.openSettingsJson"
+ },
+ {
+ "key": "ctrl+i",
+ "command": "-editor.action.triggerSuggest",
+ "when": "editorHasCompletionItemProvider && textInputFocus && !editorReadonly"
+ },
+ {
+ "key": "ctrl+c",
+ "command": "workbench.action.terminal.copySelection",
+ "when": "terminalFocus && terminalProcessSupported && terminalTextSelected && terminalTextSelected"
+ },
+ {
+ "key": "ctrl+shift+c",
+ "command": "-workbench.action.terminal.copySelection",
+ "when": "terminalFocus && terminalProcessSupported && terminalTextSelected && terminalTextSelected"
+ },
+ {
+ "key": "ctrl+k",
+ "command": "workbench.action.terminal.kill",
+ "when": "terminalIsOpen && terminalFocus"
+ },
+ {
+ "key": "delete",
+ "command": "-workbench.action.terminal.killInstance",
+ "when": "terminalIsOpen && terminalTabsFocus || terminalProcessSupported && terminalTabsFocus"
+ },
+ {
+ "key": "ctrl+shift+i",
+ "command": "-editor.action.formatDocument.none",
+ "when": "editorTextFocus && !editorHasDocumentFormattingProvider && !editorReadonly"
+ },
+ {
+ "key": "ctrl+shift+i",
+ "command": "-notebook.formatCell",
+ "when": "editorHasDocumentFormattingProvider && editorTextFocus && inCompositeEditor && notebookEditable && !editorReadonly && activeEditor == 'workbench.editor.notebook'"
+ },
+ {
+ "key": "ctrl+shift+i",
+ "command": "editor.action.formatDocument",
+ "when": "editorTextFocus"
+ },
+ {
+ "key": "ctrl+shift+i",
+ "command": "-editor.action.formatDocument",
+ "when": "editorHasDocumentFormattingProvider && editorTextFocus && !editorReadonly && !inCompositeEditor"
+ },
+ {
+ "key": "ctrl+shift+i",
+ "command": "workbench.action.toggleDevTools",
+ "when": "!editorTextFocus"
+ },
+ {
+ "key": "ctrl+shift+i",
+ "command": "-workbench.action.toggleDevTools",
+ "when": "isDevelopment"
+ },
+ {
+ "key": "ctrl+t",
+ "command": "-workbench.action.showAllSymbols"
+ },
+ {
+ "key": "ctrl+t",
+ "command": "workbench.action.files.newUntitledFile"
+ },
+ {
+ "key": "ctrl+n",
+ "command": "-workbench.action.files.newUntitledFile"
+ },
+ {
+ "key": "ctrl+shift+m",
+ "command": "github.cweijan.mysql.focus"
+ },
+ {
+ "key": "ctrl+shift+m",
+ "command": "-workbench.actions.view.problems",
+ "when": "workbench.panel.markers.view.active"
+ },
+ {
+ "key": "ctrl+shift+0",
+ "command": "workbench.action.zoomReset"
+ },
+ {
+ "key": "ctrl+numpad0",
+ "command": "-workbench.action.zoomReset"
+ }
+]
diff --git a/linux/home/.config/Code/User/settings.json b/linux/home/.config/Code/User/settings.json
new file mode 100644
index 0000000..8686b1b
--- /dev/null
+++ b/linux/home/.config/Code/User/settings.json
@@ -0,0 +1,734 @@
+{
+ "workbench.colorCustomizations": {
+ "[Chromodynamics]": {
+ "terminal.background": "#060606",
+ "terminal.foreground": "#e0e0e0",
+ "terminal.selectionBackground": "#555555",
+ "titleBar.activeBackground": "#020202",
+ "titleBar.activeForeground": "#e0e0e0",
+ "titleBar.inactiveBackground": "#020202",
+ "titleBar.inactiveForeground": "#e0e0e0",
+ "tab.inactiveBackground": "#0b0b0b",
+ "editor.background": "#060606",
+ "editor.findMatchBorder": "#0c0c0d",
+ "editor.findMatchHighlightBorder": "#0c0c0d",
+ "editor.lineHighlightBackground": "#060606",
+ "editor.selectionBackground": "#222222",
+ "editor.selectionHighlightBackground": "#e4dddd",
+ "editor.selectionHighlightBorder": "#0c0c0d",
+ "editorGroupHeader.tabsBackground": "#0b0b0b",
+ "editorGutter.background": "#000000",
+ "sideBar.background": "#060606",
+ "sideBarSectionHeader.background": "#0b0b0b",
+ "statusBar.background": "#060606"
+ },
+ "[Sweet Dracula]": {
+ "editorGroupHeader.tabsBackground": "#161925",
+ }
+ },
+ "editor.tokenColorCustomizations": {
+ "[Chromodynamics]": {
+ "textMateRules": [
+ {
+ "scope": [
+ "constant.language.python",
+ "variable.parameter.function.language.special.self.python"
+ ],
+ "settings": {
+ "foreground": "#66D9EF"
+ }
+ },
+ {
+ "scope": [
+ "entity.name.function.operator",
+ "keyword.operator"
+ ],
+ "settings": {
+ "foreground": "#E8364F",
+ "fontStyle": ""
+ }
+ },
+ {
+ "scope": [
+ "punctuation.definition.template-expression.begin.js",
+ "punctuation.definition.template-expression.end.js"
+ ],
+ "settings": {
+ "foreground": "#da70d6",
+ "fontStyle": "italic"
+ }
+ },
+ {
+ "scope": [
+ "variable.other.readwrite.js"
+ ],
+ "settings": {
+ "foreground": "#c6c6c6",
+ "fontStyle": ""
+ }
+ }
+ ]
+ },
+ "textMateRules": [
+ {
+ "scope": [
+ "entity.name.type.class",
+ "storage.type.class",
+ "storage.modifier",
+ "storage.type",
+ "constant",
+ "comment",
+ "keyword",
+ "invalid"
+ ],
+ "settings": {
+ "fontStyle": "italic"
+ }
+ }
+ ]
+ },
+ // Window Settings
+ "window.commandCenter": false,
+ "window.menuBarVisibility": "toggle",
+ "window.newWindowDimensions": "maximized",
+ "window.restoreWindows": "all",
+ "window.title": "${activeEditorShort}${separator}${rootName}",
+ "window.titleBarStyle": "native",
+ "window.titleSeparator": " ・ ・",
+ "workbench.editor.enablePreviewFromQuickOpen": false,
+ "workbench.editor.highlightModifiedTabs": true,
+ "workbench.editor.restoreViewState": false,
+ "workbench.editor.sharedViewState": false,
+ "workbench.editor.showTabs": "multiple",
+ "workbench.editor.tabCloseButton": "right",
+ "workbench.editor.tabSizing": "shrink",
+ "workbench.iconTheme": "sweet-vscode-icons",
+ "workbench.layoutControl.type": "menu",
+ "workbench.list.smoothScrolling": true,
+ "workbench.panel.defaultLocation": "right",
+ "workbench.startupEditor": "none",
+ "workbench.statusBar.visible": true,
+ "workbench.editorAssociations": {
+ "*.ipynb": "jupyter-notebook"
+ },
+ "workbench.reduceMotion": "off",
+ // Editor Settings
+ "editor.acceptSuggestionOnEnter": "smart",
+ "editor.autoClosingBrackets": "always",
+ "editor.bracketPairColorization.enabled": true,
+ "editor.codeActionsOnSave": {
+ "source.organizeImports": "explicit"
+ },
+ "editor.colorDecorators": false,
+ "editor.cursorBlinking": "phase",
+ "editor.cursorSmoothCaretAnimation": "on",
+ "editor.cursorStyle": "line-thin",
+ "editor.detectIndentation": false,
+ "editor.emptySelectionClipboard": false,
+ "editor.fontFamily": "'Operator Mono SSm Lig Book', 'FiraCode Nerd Font', 'Hack Nerd Font Mono', 'codicon'",
+ "editor.fontVariations": true,
+ "editor.fontLigatures": "'ss01', 'ss02', 'ss03', 'ss04', 'ss05', 'ss06', 'zero', 'onum'",
+ "editor.fontSize": 12,
+ "editor.fontWeight": "normal",
+ "editor.formatOnSave": true,
+ "editor.formatOnType": true,
+ "editor.glyphMargin": true,
+ "editor.guides.bracketPairs": "active",
+ "editor.guides.bracketPairsHorizontal": "active",
+ "editor.guides.highlightActiveBracketPair": true,
+ "editor.hover.above": false,
+ "editor.inlayHints.enabled": "on",
+ "editor.inlineSuggest.enabled": true,
+ "editor.insertSpaces": true,
+ "editor.linkedEditing": true,
+ "editor.matchBrackets": "never",
+ "editor.maxTokenizationLineLength": 99999999,
+ "editor.minimap.enabled": false,
+ "editor.mouseWheelScrollSensitivity": 1.5,
+ "editor.occurrencesHighlight": "off",
+ "editor.renderControlCharacters": true,
+ "editor.renderFinalNewline": "on",
+ "editor.renderLineHighlight": "gutter",
+ "editor.renderWhitespace": "none",
+ "editor.scrollbar.horizontal": "auto",
+ "editor.scrollbar.vertical": "auto",
+ "editor.selectionHighlight": true,
+ "editor.smoothScrolling": true,
+ "editor.stickyScroll.enabled": true,
+ "editor.stickyScroll.maxLineCount": 5,
+ "editor.stickyTabStops": false,
+ "editor.suggestSelection": "first",
+ "editor.suggest.insertMode": "replace",
+ "editor.suggest.preview": true,
+ "editor.suggest.snippetsPreventQuickSuggestions": false,
+ "editor.tabCompletion": "on",
+ "editor.tabSize": 4,
+ "editor.wordBasedSuggestions": "matchingDocuments",
+ "editor.wordBasedSuggestionsMode": "matchingDocuments",
+ "editor.wordWrap": "on",
+ "editor.quickSuggestions": {
+ "other": "on",
+ "comments": "on",
+ "strings": "on",
+ },
+ // Emmet Settings
+ "emmet.excludeLanguages": [],
+ "emmet.includeLanguages": {
+ "javascript": "javascriptreact",
+ "markdown": "html",
+ "vue-html": "html"
+ },
+ // Explorer Settings
+ "explorer.compactFolders": false,
+ "explorer.confirmDelete": false,
+ "explorer.confirmDragAndDrop": false,
+ // Customize UI
+ // "customizeUI.activityBar": "bottom",
+ // "customizeUI.activityBarHideSettings": true,
+ // "customizeUI.listRowHeight": 20,
+ // "customizeUI.font.monospace": "CaskaydiaCove Nerd Font",
+ // "customizeUI.font.regular": "CaskaydiaCove Nerd Font",
+ // "customizeUI.fontSizeMap": {
+ // "13px": "12px",
+ // "monospace": "12px",
+ // "tab-title": "12px",
+ // "window-title": "12.5px"
+ // },
+ // "customizeUI.titleBar": "inline",
+ // "customizeUI.stylesheet": {
+ // ":root,::after,::before": "--tab-height: 25px;--tab-radius: 8px;--ui-radius: 6px;--base-color: #bd93f9;--gradient-one: #c50ed2;--gradient-two: #8500f7;--side-pane-color: var(--vscode-editor-background);--focus-border: #3f4f81;--sash-size: 2px !important;--sash-hover-size: 2px !important;",
+ // ".editor-container": "-webkit-font-smoothing: antialiased;",
+ // ".monaco-workbench .part.editor > .content > .watermark": "display: none !important;",
+ // ".monaco-workbench .part.titlebar .window-controls-container .layout-dropdown-container": "margin-left: auto !important;",
+ // ".monaco-workbench .part.titlebar > .window-controls-container": "width: unset !important;",
+ // ".monaco-workbench .part.titlebar > .window-controls-container > .window-icon": "width: 30px !important;",
+ // ".monaco-workbench .part.titlebar > .titlebar-container .window-appicon > .home-bar-icon-badge, .monaco-workbench .part.titlebar > .titlebar-container > .window-appicon:not(.codicon)": "background-image: url(./vsc/vsc.svg) !important;",
+ // ".monaco-workbench .part.editor > .content .editor-group-container.empty .editor-group-letterpress": "background-image: url(./vsc/vsc-back.svg) !important;",
+ // ".monaco-workbench .part.editor.has-watermark > .content.empty .editor-group-container > .editor-group-letterpress": "background-position-y: 50% !important;",
+ // ".monaco-sash.hover:before, .monaco-sash.active:before": "background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important;",
+ // ".monaco-editor .squiggly-error": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorError-foreground) !important;",
+ // ".monaco-editor .squiggly-warning": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorWarning-foreground) !important;",
+ // ".monaco-editor .squiggly-info": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorInfo-foreground) !important;",
+ // ".monaco-editor .squiggly-hint": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorHint-foreground) !important;",
+ // "body.activity-bar-at-bottom .monaco-workbench .activitybar .active-item-indicator": "display: block !important;",
+ // ".monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before": "border: 0 !important;width: 100% !important;height: 3px !important;position: absolute !important;bottom: 0 !important;left: 0 !important;top: unset !important;background-image: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important;border-radius: 100vmax !important;",
+ // ".monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-bottom-container, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-top-container": "background-image: linear-gradient(to left, var(--gradient-one), var(--gradient-two)) !important;height: 3px !important;",
+ // ".monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .badge-content": "background-image: linear-gradient(90deg, var(--gradient-one), var(--gradient-two)) !important;",
+ // ".monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before": "content: '' !important;",
+ // ".codicon-git-branch:before": "background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important;-webkit-background-clip: text !important;background-clip: text !important;color: rgba(255, 255, 255, 0.4) !important;",
+ // ".monaco-editor, .split-view-view .monaco-editor-background": "background: url(./vsc/pek.png) bottom right / 10% auto no-repeat scroll;",
+ // ".monaco-scrollable-element > .scrollbar > .slider": "border-radius: 7px !important;",
+ // ".monaco-scrollable-element > .scrollbar > .slider.active": "background: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important;",
+ // "canvas.decorationsOverviewRuler, .monaco-scrollable-element > .scrollbar.vertical, .monaco-scrollable-element > .scrollbar.vertical > .slider": "width: 7px !important;",
+ // ".monaco-scrollable-element > .scrollbar.horizontal, .monaco-scrollable-element > .scrollbar.horizontal > .slider": "height: 7px !important;",
+ // ".monaco-scrollable-element > .scrollbar.horizontal > .slider": "width: 135px !important;",
+ // ".monaco-editor .monaco-hover, .monaco-editor .suggest-widget, .monaco-editor .suggest-details": "border-radius: var(--ui-radius) !important;overflow: hidden !important;box-shadow: rgb(0 0 0 / 36%) 0px 2px calc(var(--ui-radius) + 2px) !important;",
+ // ".pane .pane-body, .pane .pane-body .monaco-list, .pane .pane-body .monaco-list .monaco-scrollable-element, .pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows, .pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows .monaco-list-row": "overflow: visible !important;",
+ // ".open-editors .monaco-list .monaco-list-row": "padding-left: 0px !important;",
+ // ".monaco-list-row:hover, .monaco-list-row.selected, .monaco-list-row.focused": "border-radius: 0 var(--ui-radius) var(--ui-radius) 0 !important;",
+ // ".monaco-workbench .monaco-list:not(.element-focused):focus:before, .monaco-select-box, .monaco-select-box-dropdown-container, .monaco-select-box-dropdown-container .monaco-list-row:hover, .monaco-select-box-dropdown-container .monaco-list-row.selected, .monaco-select-box-dropdown-container .monaco-list-row.focused": "border-radius: var(--ui-radius) !important;",
+ // ".monaco-list-row.selected::before, .monaco-list-row.selected::after": "--ui-radius: 6px;content: '' !important;display: block !important;position: absolute !important;width: var(--ui-radius) !important;height: var(--ui-radius) !important;left: 0 !important;pointer-events: none !important;",
+ // ".monaco-list-row.selected::before": "top: calc(0px - var(--ui-radius)) !important;background: radial-gradient(circle at 100% 0%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat;background-position: 100% 0%;",
+ // ".monaco-list-row.selected::after": "bottom: calc(0px - var(--ui-radius)) !important;background: radial-gradient(circle at 100% 100%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat;background-position: 100% 100%;",
+ // ".monaco-button.monaco-text-button": "border-radius: var(--ui-radius) !important;",
+ // ".monaco-editor .cursors-layer.cursor-smooth-caret-animation > .cursor": "transition: all 100ms ease-out;",
+ // ".tab:first-child": "margin-left: var(--tab-radius) !important;",
+ // ".tab:last-child": "margin-right: var(--tab-radius) !important;",
+ // ".tab.active": "border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important;",
+ // ".tab.dirty-border-top > .tab-border-top-container": "border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important;",
+ // ".tab.active::before, .tab.active::after": "content: '' !important;display: block !important;box-sizing: border-box !important;position: absolute !important;z-index: 1;width: var(--tab-radius) !important;height: var(--tab-radius) !important;bottom: 0px !important;pointer-events: none !important;",
+ // ".tab.active::before": "left: calc(0px - var(--tab-radius)) !important;border-bottom-right-radius: var(--tab-radius) !important;box-shadow: 3px 3px 0 3px var(--vscode-editor-background) !important;",
+ // ".tab.active::after": "right: 0 !important;transform: translateX(var(--tab-radius)) !important;border-bottom-left-radius: var(--tab-radius) !important;box-shadow: -3px 3px 0 3px var(--vscode-editor-background) !important;",
+ // ".monaco-workbench .part.sidebar>.title>.title-label h2": "font-weight: bold !important;",
+ // "body.activity-bar-at-bottom div.monaco-grid-view > div > div > div.monaco-scrollable-element > div.split-view-container > div.split-view-view.visible > div > div > div.monaco-scrollable-element > div.split-view-container > div:nth-child(1) > div > div > div.monaco-scrollable-element > div.split-view-container > div:nth-child(2)": "height: auto !important;",
+ // "body.activity-bar-at-bottom .monaco-workbench .part.activitybar": "border: none !important; padding: 0px 6px 6px 6px !important;margin-top: -8px !important; background-color: var(--vscode-editor-background) !important; position: relative !important; z-index: 10 !important;",
+ // "body.activity-bar-at-bottom .monaco-workbench .activitybar.bordered:before": "display: none !important;",
+ // "body.activity-bar-at-bottom .monaco-workbench .activitybar > .content": "justify-content: center !important; border-radius: 6px; width: unset !important; border: 1px solid #3f4f818c !important;",
+ // "body.activity-bar-at-bottom .monaco-workbench .activitybar>.content>.composite-bar": "margin-bottom: unset !important;",
+ // "body.activity-bar-at-bottom .monaco-action-bar .action-item.icon > .action-label": "color: var(--vscode-editor-foreground) !important;opacity: 0.4;",
+ // "body.activity-bar-at-bottom .monaco-action-bar .action-item.icon.checked > .action-label": "opacity: 1 !important;",
+ // ".monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container": "display: flex;flex-grow: 0;flex-shrink: 0;text-align: center; -webkit-app-region: no-drag; height: 100%;",
+ // ".monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon": "width: 30px !important;height: 30px !important; display: flex; align-items: center; justify-content: center;",
+ // ".monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon.window-close:hover": "background-color: #FF5555",
+ // },
+ // Terminal Settings
+ "terminal.integrated.altClickMovesCursor": true,
+ "terminal.integrated.cursorBlinking": true,
+ "terminal.integrated.customGlyphs": true,
+ "terminal.integrated.cursorStyle": "line",
+ "terminal.integrated.enableMultiLinePasteWarning": false,
+ "terminal.integrated.fontFamily": "'CaskaydiaCove Nerd Font', 'FiraCode Nerd Font', 'Hack Nerd Font Mono'",
+ "terminal.integrated.fontSize": 13,
+ "terminal.integrated.gpuAcceleration": "auto",
+ "terminal.integrated.scrollback": 200000,
+ "terminal.integrated.smoothScrolling": true,
+ "terminal.integrated.tabs.enabled": false,
+ "terminal.integrated.tabs.enableAnimation": true,
+ "terminal.integrated.profiles.linux": {
+ "zsh": {
+ "path": "/usr/bin/zsh"
+ }
+ },
+ "terminal.integrated.shellIntegration.enabled": false,
+ "terminal.integrated.shellIntegration.decorationsEnabled": "never",
+ // Language Settings
+ "[python]": {
+ "editor.semanticHighlighting.enabled": false
+ },
+ "python.analysis.completeFunctionParens": true,
+ "python.formatting.provider": "black",
+ "python.formatting.blackArgs": [
+ "--line-length",
+ "120"
+ ],
+ "python.languageServer": "Pylance",
+ "python.linting.ignorePatterns": [
+ ".vscode/*.py",
+ "**/site-packages/**/*.py",
+ ".git"
+ ],
+ "python.linting.enabled": true,
+ "python.linting.pylintEnabled": true,
+ "python.linting.pylintArgs": [
+ "--rcfile",
+ "${env:HOME}/.pylintrc"
+ // "--load-plugins=pylint_django"
+ ],
+ "[cpp]": {
+ "editor.semanticHighlighting.enabled": false,
+ },
+ "C_Cpp.default.includePath": [
+ "${workspaceFolder}/**",
+ "/usr/include",
+ "/usr/local/include",
+ "/usr/include/c++/11.1.0"
+ ],
+ "C_Cpp.default.defines": [
+ "${default}"
+ ],
+ "C_Cpp.default.compilerPath": "/usr/bin/g++",
+ "C_Cpp.default.cppStandard": "c++20",
+ "C_Cpp.default.cStandard": "c17",
+ "C_Cpp.default.intelliSenseMode": "gcc-x64",
+ "C_Cpp.default.compilerArgs": [
+ "-g"
+ ],
+ "launch": {
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "(gdb) Launch",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${fileDirname}/${fileBasenameNoExtension}",
+ "args": [],
+ "stopAtEntry": false,
+ "cwd": "${workspaceFolder}",
+ "environment": [],
+ "externalConsole": false,
+ "MIMode": "gdb",
+ "miDebuggerPath": "/usr/bin/gdb",
+ "preLaunchTask": "Build",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ }
+ ]
+ }
+ ]
+ },
+ "tasks": {
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "Build",
+ "type": "shell",
+ "command": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\"",
+ "problemMatcher": [
+ "$gcc"
+ ],
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ }
+ },
+ {
+ "label": "Build (Multiple cpp files)",
+ "type": "shell",
+ "command": "g++ -g \"${fileDirname}/*.cpp\" -o \"${fileDirname}/${fileBasenameNoExtension}\"",
+ "problemMatcher": [
+ "$gcc"
+ ],
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ }
+ }
+ ]
+ },
+ "C_Cpp.autocompleteAddParentheses": true,
+ "C_Cpp.codeFolding": "enabled",
+ "C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 2, ColumnLimit: 0}",
+ "C_Cpp.inlayHints.autoDeclarationTypes.enabled": true,
+ "C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft": true,
+ "C_Cpp.inlayHints.parameterNames.enabled": true,
+ "C_Cpp.inlayHints.parameterNames.hideLeadingUnderscores": true,
+ "C_Cpp.inlayHints.parameterNames.suppressWhenArgumentContainsName": true,
+ "C_Cpp.inlayHints.referenceOperator.enabled": true,
+ "C_Cpp.inlayHints.referenceOperator.showSpace": false,
+ "css.format.enable": true,
+ "css.format.newlineBetweenRules": true,
+ "css.format.newlineBetweenSelectors": true,
+ "css.format.spaceAroundSelectorSeparator": true,
+ "[css]": {
+ "editor.tabSize": 2
+ },
+ "java.jdt.ls.java.home": "/usr/lib/jvm/java-11-openjdk-amd64",
+ "java.configuration.runtimes": [
+ {
+ "name": "JavaSE-11",
+ "path": "/usr/lib/jvm/java-11-openjdk-amd64"
+ }
+ ],
+ "java.server.launchMode": "LightWeight",
+ "[html]": {
+ "editor.tabSize": 2
+ },
+ "html.autoClosingTags": true,
+ "html.completion.attributeDefaultValue": "singlequotes",
+ "[dart]": {
+ "editor.suggestSelection": "first",
+ "editor.tabCompletion": "onlySnippets",
+ "editor.wordBasedSuggestions": "off"
+ },
+ "[javascript]": {
+ "editor.tabSize": 2
+ },
+ "javascript.autoClosingTags": true,
+ "javascript.suggest.autoImports": true,
+ "javascript.suggest.completeFunctionCalls": true,
+ "javascript.suggest.enabled": true,
+ "javascript.updateImportsOnFileMove.enabled": "always",
+ "javascript.validate.enable": false,
+ "[json]": {
+ "editor.tabSize": 2
+ },
+ "json.maxItemsComputed": 100000,
+ "[markdown]": {
+ "editor.quickSuggestions": {
+ "other": "on",
+ "comments": "on",
+ "strings": "on",
+ }
+ },
+ "[scss]": {
+ "editor.tabSize": 2
+ },
+ "[typescript]": {
+ "editor.tabSize": 2
+ },
+ "typescript.autoClosingTags": true,
+ "typescript.suggest.autoImports": true,
+ "typescript.updateImportsOnFileMove.enabled": "always",
+ "typescript.validate.enable": false,
+ "[typescriptreact]": {
+ "editor.tabSize": 2,
+ "editor.formatOnSave": false,
+ },
+ "js/ts.implicitProjectConfig.checkJs": true,
+ //Latex
+ "[latex]": {
+ "editor.formatOnSave": false
+ },
+ // Empty-Indent Extension
+ "emptyIndent.highlightColor": "rgba(246,36,89,0.6)",
+ "emptyIndent.highlightIndent": false,
+ "emptyIndent.removeIndent": true,
+ // Github Co-pilot
+ "github.copilot.inlineSuggest.enable": true,
+ "github.copilot.enable": {
+ "*": true,
+ "yaml": false,
+ "plaintext": true,
+ "markdown": false
+ },
+ // Gitlens
+ "gitlens.currentLine.enabled": true,
+ "gitlens.hovers.currentLine.over": "line",
+ "gitlens.codeLens.enabled": false,
+ "gitlens.statusBar.enabled": true,
+ // General Setting\
+ "color-highlight.markRuler": false,
+ "color-highlight.markerType": "background",
+ "debug.onTaskErrors": "showErrors",
+ "debug.openDebug": "openOnDebugBreak",
+ "eslint.enable": true,
+ "extensions.ignoreRecommendations": true,
+ "files.autoSave": "onWindowChange",
+ "files.insertFinalNewline": true,
+ "files.restoreUndoStack": true,
+ "files.trimFinalNewlines": true,
+ "files.trimTrailingWhitespace": true,
+ "git.autofetch": true,
+ "grammarly.files.include": [
+ "**/*.md",
+ "**/*.txt",
+ "**/*.tex",
+ ],
+ "latex-workshop.latex.autoBuild.cleanAndRetry.enabled": true,
+ "latex-workshop.latex.autoBuild.run": "never",
+ "latex-workshop.latex.clean.fileTypes": [
+ "*/*.aux",
+ "*/*.synctex.gz"
+ ],
+ "latex-workshop.latex.outDir": "/tmp/Review-Paper/",
+ "latex-workshop.latex.recipe.default": "latexmk (lualatex)",
+ "latex-workshop.latex.recipes": [
+ {
+ "name": "latexmk 🔃",
+ "tools": [
+ "latexmk"
+ ]
+ },
+ {
+ "name": "latexmk (latexmkrc)",
+ "tools": [
+ "latexmk_rconly"
+ ]
+ },
+ {
+ "name": "latexmk (lualatex)",
+ "tools": [
+ "lualatexmk"
+ ]
+ },
+ {
+ "name": "latexmk (xelatex)",
+ "tools": [
+ "xelatexmk"
+ ]
+ },
+ {
+ "name": "pdflatex ➞ bibtex ➞ pdflatex × 2",
+ "tools": [
+ "pdflatex",
+ "bibtex",
+ "pdflatex",
+ "pdflatex"
+ ]
+ },
+ {
+ "name": "Compile Rnw files",
+ "tools": [
+ "rnw2tex",
+ "latexmk"
+ ]
+ },
+ {
+ "name": "Compile Jnw files",
+ "tools": [
+ "jnw2tex",
+ "latexmk"
+ ]
+ },
+ {
+ "name": "tectonic",
+ "tools": [
+ "tectonic"
+ ]
+ }
+ ],
+ "latex-workshop.latex.tools": [
+ {
+ "name": "latexmk",
+ "command": "latexmk",
+ "args": [
+ "-synctex=1",
+ "-interaction=nonstopmode",
+ "-file-line-error",
+ "-pdf",
+ "-outdir=%OUTDIR%",
+ "%DOC%"
+ ],
+ "env": {}
+ },
+ {
+ "name": "lualatexmk",
+ "command": "latexmk",
+ "args": [
+ "-synctex=1",
+ "-interaction=nonstopmode",
+ "-file-line-error",
+ "-lualatex",
+ "-outdir=%OUTDIR%",
+ "%DOC%"
+ ],
+ "env": {}
+ },
+ {
+ "name": "xelatexmk",
+ "command": "latexmk",
+ "args": [
+ "-synctex=1",
+ "-interaction=nonstopmode",
+ "-file-line-error",
+ "-xelatex",
+ "-outdir=%OUTDIR%",
+ "%DOC%"
+ ],
+ "env": {}
+ },
+ {
+ "name": "latexmk_rconly",
+ "command": "latexmk",
+ "args": [
+ "%DOC%"
+ ],
+ "env": {}
+ },
+ {
+ "name": "pdflatex",
+ "command": "pdflatex",
+ "args": [
+ "-synctex=1",
+ "-interaction=nonstopmode",
+ "-file-line-error",
+ "-output-directory=%OUTDIR%",
+ "%DOC%"
+ ],
+ "env": {}
+ },
+ {
+ "name": "bibtex",
+ "command": "bibtex",
+ "args": [
+ "%DOCFILE%"
+ ],
+ "env": {}
+ },
+ {
+ "name": "rnw2tex",
+ "command": "Rscript",
+ "args": [
+ "-e",
+ "knitr::opts_knit$set(concordance = TRUE); knitr::knit('%DOCFILE_EXT%')"
+ ],
+ "env": {}
+ },
+ {
+ "name": "jnw2tex",
+ "command": "julia",
+ "args": [
+ "-e",
+ "using Weave; weave(\"%DOC_EXT%\", doctype=\"tex\")"
+ ],
+ "env": {}
+ },
+ {
+ "name": "jnw2texmintex",
+ "command": "julia",
+ "args": [
+ "-e",
+ "using Weave; weave(\"%DOC_EXT%\", doctype=\"texminted\")"
+ ],
+ "env": {}
+ },
+ {
+ "name": "tectonic",
+ "command": "tectonic",
+ "args": [
+ "--synctex",
+ "--keep-logs",
+ "%DOC%.tex"
+ ],
+ "env": {}
+ }
+ ],
+ "liveServer.settings.donotShowInfoMsg": true,
+ "liveServer.settings.donotVerifyTags": true,
+ "liveServer.settings.file": "404.html",
+ // "liveServer.settings.https": {
+ // "enable": true,
+ // "cert": "/home/proxzima/.ssh/cert/cert.pem",
+ // "key": "/home/proxzima/.ssh/cert/key.pem",
+ // "passphrase": "1234"
+ // },
+ "liveServer.settings.useLocalIp": true,
+ "markdown.preview.markEditorSelection": true,
+ "markdown.preview.scrollEditorWithPreview": false,
+ "markdown.preview.scrollPreviewWithEditor": false,
+ "svgPreview.autoOpen": true,
+ "svgPreview.scaleToFit": true,
+ "svgPreview.style": {
+ "html": {
+ "background-position": "0 0, 13px 13px",
+ "background-size": "26px 26px",
+ "background": "rgba(255, 255, 255, 1)",
+ // "background-image": "linear-gradient(45deg, #141414 25%, transparent 25%, transparent 75%, #141414 75%, #141414), linear-gradient(45deg, #141414 25%, transparent 25%, transparent 75%, #141414 75%, #141414)"
+ }
+ },
+ "print.folder.exclude": [
+ "{bin,obj,out}",
+ "node_module",
+ "**/*.{bin,exe,dll,hex,pdb,pdf,pfx,png,jpg,gif,bmp,suo,pptx,ppt,jar,woff2,woff,ttf,eot,odt,otf,class}"
+ ],
+ "print.lineNumbers": "on",
+ "print.printAndClose": false,
+ "print.colourScheme": "XCode",
+ "print.alternateBrowser": true,
+ "print.browserPath": "/usr/bin/google-chrome",
+ "spellright.documentTypes": [
+ "markdown",
+ "latex",
+ "plaintext"
+ ],
+ "spellright.language": [
+ "en_GB"
+ ],
+ "spellright.notificationClass": "information",
+ "spellright.suggestionsInHints": false,
+ "spellright.useDocumentSymbolsInCode": true,
+ "telemetry.telemetryLevel": "off",
+ "search.exclude": {
+ "**/bower_components": true,
+ "**/*.code-search": true,
+ "**/node_modules": true,
+ "**/env": true,
+ "**/venv": true
+ },
+ "files.associations": {
+ "*.xml": "html",
+ "*.svg": "html",
+ "*.json": "jsonc"
+ },
+ "files.exclude": {
+ "**/.DS_Store": true,
+ "**/.git": true,
+ "**/.svn": true,
+ "**/.hg": true,
+ "**/CVS": true,
+ "**/.classpath": true,
+ "**/.project": true,
+ "**/.settings": true,
+ "**/.factorypath": true
+ },
+ "files.watcherExclude": {
+ "**/.DS_Store/**": true,
+ "**/.git/objects/**": true,
+ "**/.git/subtree-cache/**": true,
+ "**/.svn/**": true,
+ "**/.hg/**": true,
+ "**/CVS/**": true,
+ "**/node_modules/**": true,
+ "**/env/**": true,
+ "**/venv/**": true,
+ "env-*": true
+ },
+ "workbench.colorTheme": "Sweet Dracula",
+ "security.workspace.trust.untrustedFiles": "open",
+ "workbench.activityBar.location": "hidden",
+ "workbench.editor.tabActionLocation": "right",
+ "workbench.editor.empty.hint": "hidden"
+}
diff --git a/linux/home/.config/Code/User/snippets/snippet.code-snippets b/linux/home/.config/Code/User/snippets/snippet.code-snippets
new file mode 100644
index 0000000..16bdfed
--- /dev/null
+++ b/linux/home/.config/Code/User/snippets/snippet.code-snippets
@@ -0,0 +1,126 @@
+{
+ // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
+ // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
+ // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
+ // used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
+ // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
+ // Placeholders with the same ids are connected.
+ // Example:
+ "if name is main": {
+ "scope": "python",
+ "prefix": "ifn",
+ "body": [
+ "if __name__ == '__main__':",
+ "\t$0"
+ ],
+ "description": ""
+ },
+ "for in": {
+ "scope": "python",
+ "prefix": "fori",
+ "body": [
+ "for ${1:item} in ${2:items}:",
+ "\t$0"
+ ],
+ "description": ""
+ },
+ "for in range": {
+ "scope": "python",
+ "prefix": "forr",
+ "body": [
+ "for ${1:i} in range($2):",
+ "\t$0"
+ ],
+ "description": ""
+ },
+ "lambda": {
+ "scope": "python",
+ "prefix": "lamb",
+ "body": [
+ "lambda ${1:arg} : $0",
+ ],
+ "description": ""
+ },
+ "map input": {
+ "scope": "python",
+ "prefix": "mapi",
+ "body": [
+ "map(${1:func}, input($2).split())"
+ ],
+ "description": ""
+ },
+ "html boiler plate": {
+ "scope": "html",
+ "prefix": "html",
+ "body": [
+ "<!DOCTYPE html>",
+ "<html lang=\"en\">",
+ "",
+ "<head>",
+ " <meta charset=\"utf-8\">",
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">",
+ "",
+ " <title>${1:Basic HTML5}</title>",
+ " <meta name=\"author\" content=\"${2:Trevor Gray}\">",
+ " <meta name=\"description\" content=\"${3:HTML5 Template}\">",
+ "",
+ " <meta property=\"og:title\" content=\"${4:HTML5 Template}\">",
+ " <meta property=\"og:type\" content=\"website\">",
+ " <meta property=\"og:url\" content=\"https://$5\">",
+ " <meta property=\"og:description\" content=\"${6:HTML5 Template}\">",
+ " <meta property=\"og:image\" content=\"${7:./assets/preview.png}\">",
+ "",
+ " <link rel=\"icon\" href=\"${8:./assets/favicon.ico}\">",
+ " <link rel=\"icon\" href=\"${9:./assets/favicon.svg}\" type=\"image/svg+xml\">",
+ " <link rel=\"apple-touch-icon\" href=\"${10:./assets/apple-touch-icon.png}\">",
+ "",
+ " <link rel=\"stylesheet\" href=\"${11:./css/style.css}\">",
+ "",
+ "</head>",
+ "",
+ "<body>",
+ " ${0:<!-- your content here... -->}",
+ " <script src=\"${12:./js/main.js}\" defer></script>",
+ "</body>",
+ "",
+ "</html>",
+ ],
+ "description": ""
+ },
+ "css boiler plate": {
+ "scope": "css",
+ "prefix": "css",
+ "body": [
+ "html {",
+ " font-family: sans-serif;",
+ " font-size: 100%;",
+ " box-sizing: border-box;",
+ "}",
+ "",
+ "*, ::before, ::after {",
+ " box-sizing: inherit;",
+ "}",
+ "",
+ "html, body {",
+ " margin: 0;",
+ " padding: 0;",
+ " width: 100vw;",
+ " min-height: 100%;",
+ " text-rendering: optimizeLegibility;",
+ "}",
+ ""
+ ]
+ },
+ "consoleLog": {
+ "scope": "javascript",
+ "prefix": "clg",
+ "body": "console.log(${1:object});",
+ "description": "Displays a message in the console"
+ },
+ "consoleLogObject": {
+ "scope": "javascript",
+ "prefix": "clo",
+ "body": "console.log('${1:object} :>> ', ${1:object});",
+ "description": "Displays an object in the console with its name"
+ }
+}
diff --git a/linux/home/.config/Code/User/spellright.dict b/linux/home/.config/Code/User/spellright.dict
new file mode 100644
index 0000000..94f1e64
--- /dev/null
+++ b/linux/home/.config/Code/User/spellright.dict
@@ -0,0 +1,14 @@
+srdusr
+gui
+url
+yara
+backend
+txt
+Regex
+github
+args
+grep
+res
+yar
+shipit
+json
diff --git a/linux/home/.config/Code/User/vsc.css b/linux/home/.config/Code/User/vsc.css
new file mode 100644
index 0000000..8316df0
--- /dev/null
+++ b/linux/home/.config/Code/User/vsc.css
@@ -0,0 +1,408 @@
+/* *:not(.monaco-editor .margin):not(.monaco-editor .lines-content.monaco-editor-background):not(.monaco-editor .cursors-layer.cursor-smooth-caret-animation > .cursor):not(.monaco-scrollable-element > .scrollbar.vertical > .slider):not(.monaco-scrollable-element > .scrollbar.horizontal > .slider):not(.pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows) {
+ transition-duration: 100ms !important;
+} */
+
+:root,
+::after,
+::before {
+ --tab-height: 25px;
+ --tab-radius: 8px;
+ --ui-radius: 6px;
+ --base-color: #bd93f9;
+ --gradient-one: #cba6f7;
+ --gradient-two: #89b4fa;
+ --side-pane-color: var(--vscode-editor-background);
+ --focus-border: #3f4f81;
+ --sash-size: 2px !important;
+ --sash-hover-size: 2px !important;
+}
+
+body > .monaco-workbench > .monaco-grid-view > .monaco-grid-branch-node > .monaco-split-view2 > .monaco-scrollable-element > .split-view-container {
+ background: var(--vscode-editor-background) !important;
+}
+
+.editor-container {
+ -webkit-font-smoothing: antialiased;
+}
+
+.monaco-workbench .part.titlebar .window-controls-container .window-icon,
+.monaco-workbench .part.editor > .content > .watermark {
+ display: none !important;
+}
+
+.monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container {
+ display: flex;
+ flex-grow: 0;
+ flex-shrink: 0;
+ text-align: center;
+ -webkit-app-region: no-drag;
+ height: 100%;
+}
+
+.monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon {
+ width: 30px !important;
+ height: 30px !important;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon.window-close:hover {
+ background: #FF5555 !important;
+}
+
+.monaco-workbench .part.titlebar .window-controls-container .layout-dropdown-container {
+ margin-left: auto !important;
+}
+
+.monaco-workbench .part.titlebar > .window-controls-container {
+ width: unset !important;
+}
+
+.monaco-workbench .part.titlebar > .window-controls-container > .window-icon {
+ width: 30px !important;
+}
+
+.monaco-workbench.linux .part.titlebar > .window-title {
+ font-size: 12.5px !important;
+}
+
+.monaco-workbench .part.titlebar > .titlebar-container .window-appicon > .home-bar-icon-badge,
+.monaco-workbench .part.titlebar > .titlebar-container > .window-appicon:not(.codicon) {
+ background-image: url(./vsc/vsc.svg) !important;
+}
+
+.monaco-workbench .part.editor > .content .editor-group-container.empty .editor-group-letterpress {
+ background-image: url(./vsc/vsc-back.svg) !important;
+}
+
+.monaco-workbench .part.editor.has-watermark > .content.empty .editor-group-container > .editor-group-letterpress {
+ background-position-y: 50% !important;
+}
+
+.mac,
+.windows,
+.linux {
+ /* font-family: 'CaskaydiaCove Nerd Font' !important;
+ --monaco-monospace-font: 'CaskaydiaCove Nerd Font' !important; */
+ /* font-family: 'Delugia' !important;
+ --monaco-monospace-font: 'Delugia Mono' !important; */
+}
+
+
+.monaco-workbench .part.sidebar > .title > .title-label h2 {
+ font-weight: bold !important;
+}
+
+.monaco-sash.hover:before,
+.monaco-sash.active:before {
+ background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important;
+}
+
+/* Squiggly lines to straight lines */
+
+.monaco-editor .squiggly-error {
+ background: none !important;
+ border-bottom: 0.5px solid var(--vscode-editorError-foreground) !important;
+}
+
+.monaco-editor .squiggly-warning {
+ background: none !important;
+ border-bottom: 0.5px solid var(--vscode-editorWarning-foreground) !important;
+}
+
+.monaco-editor .squiggly-info {
+ background: none !important;
+ border-bottom: 0.5px solid var(--vscode-editorInfo-foreground) !important;
+}
+
+.monaco-editor .squiggly-hint {
+ background: none !important;
+ border-bottom: 0.5px solid var(--vscode-editorHint-foreground) !important;
+}
+
+/* */
+
+/* Gradient Tab border */
+body.activity-bar-at-bottom .monaco-workbench .activitybar .active-item-indicator {
+ display: block !important;
+}
+
+.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before {
+ border: 0 !important;
+ width: 3px !important;
+ height: 100% !important;
+ position: absolute !important;
+ top: 0 !important;
+ left: 0 !important;
+ background-image: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important;
+ border-radius: 100vmax !important;
+}
+
+.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-bottom-container,
+.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-top-container {
+ background-image: linear-gradient(to left, var(--gradient-one), var(--gradient-two)) !important;
+ height: 3px !important;
+ display: none !important;
+}
+
+.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .badge-content {
+ background-image: linear-gradient(90deg, var(--gradient-one), var(--gradient-two)) !important;
+}
+
+/* */
+
+/* Hides dirty tab white dot indicator */
+
+.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before,
+.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before {
+ content: '' !important;
+}
+
+/* */
+
+/* Git icon background */
+
+.codicon-git-branch:before {
+ background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important;
+ -webkit-background-clip: text !important;
+ background-clip: text !important;
+ color: rgba(255, 255, 255, 0.4) !important;
+}
+
+/* */
+
+/* Editor Background */
+
+.monaco-editor,
+.split-view-view .lines-content.monaco-editor-background {
+ background: url(./vsc/pek.png) bottom right / 10% auto no-repeat scroll;
+ /*background: linear-gradient(rgba(0,0,0,.65), rgba(0,0,0,.65)), url(./vsc/bg.jpg) center center / auto 100vh no-repeat scroll;*/
+}
+
+/* */
+
+/* Scrollbar */
+.monaco-scrollable-element > .scrollbar > .slider {
+ border-radius: 7px !important;
+}
+
+.monaco-scrollable-element > .scrollbar > .slider.active {
+ background: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important;
+}
+
+canvas.decorationsOverviewRuler,
+.monaco-scrollable-element > .scrollbar.vertical,
+.monaco-scrollable-element > .scrollbar.vertical > .slider {
+ width: 7px !important;
+}
+
+.monaco-scrollable-element > .scrollbar.vertical > .slider {
+ transition: all 100ms ease-out;
+}
+
+.monaco-scrollable-element > .scrollbar.horizontal,
+.monaco-scrollable-element > .scrollbar.horizontal > .slider {
+ height: 7px !important;
+}
+
+.monaco-scrollable-element > .scrollbar.horizontal > .slider {
+ transition: all 100ms ease-out;
+}
+
+.monaco-scrollable-element > .scrollbar.horizontal > .slider {
+ width: 135px !important;
+}
+
+/* */
+
+/* Rounded UI */
+
+/* Suggestions */
+.monaco-editor .monaco-hover,
+.monaco-editor .suggest-widget,
+.monaco-editor .suggest-details {
+ border-radius: var(--ui-radius) !important;
+ overflow: hidden !important;
+ box-shadow: rgb(0 0 0 / 36%) 0px 2px calc(var(--ui-radius) + 2px) !important;
+}
+
+/* Left pane selected file */
+.pane .pane-body,
+.pane .pane-body .monaco-list,
+.pane .pane-body .monaco-list .monaco-scrollable-element,
+.pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows,
+.pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows .monaco-list-row {
+ overflow: visible !important;
+}
+
+.open-editors .monaco-list .monaco-list-row {
+ padding-left: 0px !important;
+}
+
+.monaco-list-row:hover,
+.monaco-list-row.selected,
+.monaco-list-row.focused {
+ border-radius: 0 var(--ui-radius) var(--ui-radius) 0 !important;
+}
+
+.monaco-workbench .monaco-list:not(.element-focused):focus:before,
+.monaco-select-box,
+.monaco-select-box-dropdown-container,
+.monaco-select-box-dropdown-container .monaco-list-row:hover,
+.monaco-select-box-dropdown-container .monaco-list-row.selected,
+.monaco-select-box-dropdown-container .monaco-list-row.focused {
+ border-radius: var(--ui-radius) !important;
+}
+
+.monaco-list-row.selected::before,
+.monaco-list-row.selected::after {
+ content: '' !important;
+ display: block !important;
+ position: absolute !important;
+ width: var(--ui-radius) !important;
+ height: var(--ui-radius) !important;
+ left: 0 !important;
+ pointer-events: none !important;
+}
+
+.monaco-list-row.selected::before {
+ top: calc(0px - var(--ui-radius)) !important;
+ background: radial-gradient(circle at 100% 0%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat;
+ background-position: 100% 0%;
+}
+
+.monaco-list-row.selected::after {
+ bottom: calc(0px - var(--ui-radius)) !important;
+ background: radial-gradient(circle at 100% 100%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat;
+ background-position: 100% 100%;
+}
+
+.monaco-button.monaco-text-button {
+ border-radius: var(--ui-radius) !important;
+}
+
+/* */
+
+/* Smooth cursor */
+
+.monaco-editor .cursors-layer.cursor-smooth-caret-animation > .cursor {
+ transition: all 100ms ease-out;
+}
+
+/* */
+
+/* Active tab (Without border) */
+
+..tab:first-child {
+ margin-left: var(--tab-radius) !important;
+ /* margin-left: calc(var(--tab-radius) - 2px) !important; */
+}
+
+..tab:last-child {
+ margin-right: var(--tab-radius) !important;
+ /* margin-right: calc(var(--tab-radius) - 2px) !important; */
+}
+
+..tab.active {
+ /* border: 2px solid var(--base-color) !important; */
+ /* background-color: transparent !important; */
+ /* rgb(20, 24, 34) */
+ border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important;
+ /* border-bottom: 2px solid #0c0e14 !important; */
+ /* z-index: 1 !important; */
+}
+
+.tab.dirty-border-top > .tab-border-top-container {
+ border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important;
+}
+
+/* Border bottom radius*/
+..tab.active::before,
+..tab.active::after {
+ content: '' !important;
+ display: block !important;
+ box-sizing: border-box !important;
+ position: absolute !important;
+ z-index: 1;
+ width: var(--tab-radius) !important;
+ height: var(--tab-radius) !important;
+ bottom: 0px !important;
+ /* bottom: -2px !important; */
+ pointer-events: none !important;
+ /* border-bottom: 2px solid var(--base-color) !important; */
+}
+
+...tab.active::before {
+ left: calc(0px - var(--tab-radius)) !important;
+ /* transform: translateX(calc(0px - var(--tab-radius))) !important; */
+ /* border-right: 2px solid var(--base-color) !important; */
+ border-bottom-right-radius: var(--tab-radius) !important;
+ /* box-shadow: 3px 3px 0 3px var(--tab-color) !important; */
+ box-shadow: 3px 3px 0 3px var(--vscode-editor-background) !important;
+ /* background: radial-gradient(circle at 0% 0%, transparent 70.71%, var(--tab-color) 29.289%) no-repeat;
+ background-position: 0% 0%; */
+}
+
+..tab.active::after {
+ right: 0 !important;
+ transform: translateX(var(--tab-radius)) !important;
+ /* border-left: 2px solid var(--base-color) !important; */
+ border-bottom-left-radius: var(--tab-radius) !important;
+ /* box-shadow: -3px 3px 0 3px var(--tab-color) !important; */
+ box-shadow: -3px 3px 0 3px var(--vscode-editor-background) !important;
+ /* background: radial-gradient(circle at 100% 0%, transparent 70.71%, var(--tab-color) 29.289%) no-repeat;
+ background-position: 100% 0%; */
+}
+
+/* .tabs-container:before {
+ content: '' !important;
+ top: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+ background: linear-gradient(90deg, rgb(12, 14, 20), rgb(189, 172, 255), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 172, 249), rgb(12, 14, 20)) !important;
+ clip: rect(33px, 2600px, 33px, 0px) !important;
+ position: absolute !important;
+}
+
+.tabs-container:after {
+ content: '' !important;
+ top: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+ background: linear-gradient(90deg, rgb(12, 14, 20), rgb(189, 172, 255), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 172, 249), rgb(12, 14, 20)) !important;
+ clip: rect(33px, 2600px, 35px, 0px) !important;
+ position: absolute !important;
+}
+
+.tab-label > .monaco-icon-label-container::after {
+ background: transparent !important;
+} */
+
+/* */
+
+.tab{
+ border-radius: 12px !important;
+ margin: 5px !important;
+ height: 40px !important;
+ border:2px solid #313244 !important;
+ background-color: #161925 !important;
+}
+.tab.active {
+ border: 2px solid var(--gradient-one) !important;
+ color: var(--gradient-one) !important;
+ font-weight: bold !important;
+}
+.tab.dirty {
+ border: 2px solid var(--gradient-two) !important;
+
+}
+.tabs-container{
+ height: auto !important;
+ padding: 5px !important;
+}
+.editor-actions {
+ height: inherit !important;
+}
diff --git a/linux/home/.config/Code/User/vsc.js b/linux/home/.config/Code/User/vsc.js
new file mode 100644
index 0000000..a14bf5a
--- /dev/null
+++ b/linux/home/.config/Code/User/vsc.js
@@ -0,0 +1,100 @@
+function getOffset(el) {
+ const rect = el.getBoundingClientRect();
+ return {
+ left: rect.left + window.scrollX,
+ top: rect.top + window.scrollY,
+ };
+}
+
+const prevOffset = {};
+
+const displayEffect = (event) => {
+ if (prevOffset.top === undefined) {
+ let initialOffset = getOffset(document.getElementsByClassName("cursor")[0]);
+ prevOffset.top = initialOffset.top;
+ prevOffset.left = initialOffset.left;
+ }
+
+ const existingRect = document.getElementById("myRect");
+ if (existingRect !== null) {
+ existingRect.remove();
+ }
+
+ setTimeout(function () {
+ const currOffset = getOffset(document.getElementsByClassName("cursor")[0]);
+ const top = prevOffset.top;
+ const left = prevOffset.left;
+ const rect = document.createElement("div");
+
+ // console.log("prev: ", top, left);
+ // console.log("curr: ", currOffset.top, currOffset.left);
+
+ rect.id = "myRect";
+ rect.style.cssText = `
+ position:absolute;
+ top:${top}px;
+ left:${left}px;
+ width:9px;
+ height:20px;
+ z-index:10;
+ background-color:red;
+ opacity: 0.5;
+ `;
+ rect.animate(
+ [
+ // keyframes
+ { transform: "scale(1) skew(10deg)" },
+ { transform: "scale(0) skew(10deg)" },
+ ],
+ {
+ // timing options
+ duration: 500,
+ easing: "ease-in-out",
+ direction: "alternate",
+ iterations: Infinity,
+ }
+ );
+
+ document.body.appendChild(rect);
+ prevOffset.top = currOffset.top;
+ prevOffset.left = currOffset.left;
+ }, 24);
+};
+
+// NOTE: First enable editor.cursorSmoothCaretAnimation.
+// NOTE: Uncomment this to get a cursor trail effect.
+// document.addEventListener("keydown", displayEffect);
+
+const windowControls = document.createElement('div');
+windowControls.className = 'window-controls-container';
+const minimize = document.createElement('div');
+minimize.classList.add('window-icon', 'window-minimize', 'codicon', 'codicon-chrome-minimize');
+const restore = document.createElement('div');
+restore.classList.add('window-icon', 'window-max-restore', 'codicon', 'codicon-chrome-restore');
+const close = document.createElement('div');
+close.classList.add('window-icon', 'window-close', 'codicon', 'codicon-chrome-close');
+windowControls.appendChild(minimize);
+windowControls.appendChild(restore);
+windowControls.appendChild(close);
+// const html = '<div class="window-controls-container"><div class="window-icon window-minimize codicon codicon-chrome-minimize"></div><div class="window-icon window-max-restore codicon codicon-chrome-restore"></div><div class="window-icon window-close codicon codicon-chrome-close"></div></div>';
+// template.innerHTML = html;
+// const windowControls = template.content.firstChild;
+
+var observer = new MutationObserver(function (mutations, me) {
+ console.warn('Observing if window controls present');
+ // const windowControls = document.querySelector(".window-controls-container");
+ const tabContainer = document.querySelector(".tabs-and-actions-container");
+
+ if (windowControls && tabContainer) {
+ tabContainer.appendChild(windowControls);
+ console.warn('Observing completed');
+ me.disconnect();
+ return;
+ }
+});
+
+
+// observer.observe(document, {
+// childList: true,
+// subtree: true
+// });
diff --git a/linux/home/.config/X11/.Xresources b/linux/home/.config/X11/.Xresources
new file mode 100644
index 0000000..be509d1
--- /dev/null
+++ b/linux/home/.config/X11/.Xresources
@@ -0,0 +1,307 @@
+st.alpha: 255
+!! Transparency (0-1):
+*.alpha: 0.2
+
+urxvt*shading: 10
+urxvt*tintColor: #000000
+urxvt*blurRadius: 5
+urxvt*transparent: true
+urxvt*depth: 32
+urxvt*background: rgba:0000/0000/1111/dddd
+!urxvt*background: rgba:0000/0000/0200/c800
+!URxvt*scrollstyle: plain
+URxvt.scrollBar: False
+!URxvt.font: xft:DejaVu Sans Mono:pixelsize=11:antialias=true
+URxvt.font: xft:monospace:Bold:pixelsize=12:antialias=true
+!URxvt*transparent: true
+!URxvt*shading: 5
+! change to whateva background
+URxvt.keysym.C-7: command:\033]11;#ff0000\007
+!URxvt*reverseVideo: True
+
+URxvt*saveLines : 10000
+
+!URxvt.keysym.Control-Up: \033[1;5A
+!URxvt.keysym.Control-Down: \033[1;5B
+!URxvt.keysym.Control-Left: \033[1;5D
+!URxvt.keysym.Control-Right: \033[1;5C
+
+URxvt.keysym.Control-1: command:\007\033]711;xft:monospace:Bold:pixelsize=12:antialias=true\007
+URxvt.keysym.Control-2: command:\007\033]711;xft:monospace:Bold:pixelsize=18:antialias=true\007
+URxvt.keysym.Control-3: command:\007\033]711;xft:monospace:Bold:pixelsize=28:antialias=true\007
+!URxvt.keysym.Control-1: command:\033]710;xft:Terminus:pixelsize=10:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=10:antialias=false\007
+!URxvt.keysym.Control-2: command:\033]710;xft:Terminus:pixelsize=14:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=14:antialias=false\007
+!URxvt.keysym.Control-3: command:\033]710;xft:Terminus:pixelsize=18:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=18:antialias=false\007
+!URxvt.keysym.Control-4: command:\033]710;xft:Terminus:Bold:pixelsize=20:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=20:antialias=false\007
+!URxvt.keysym.Control-5: command:\033]710;xft:Terminus:Bold:pixelsize=28:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=28:antialias=false\007
+
+
+
+
+
+
+
+!URxvt.perl-ext-common: selection-to-clipboard
+!URxvt.keysym.Shift-Control-V: eval:paste_clipboard
+!URxvt.keysym.Shift-Control-C: eval:selection_to_clipboard
+
+
+URxvt.iso14755: false
+URxvt.iso14755_52: false
+
+
+!URxvt.scrollBar: true
+!URxvt.scrollBar_right: true
+!URxvt.scrollBar_floating: true
+!URxvt.searchable-scrollback: false
+URxvt.url-select.underline: true
+URxvt.url-select.autocopy: true
+URxvt.cutchars: `""()''*<>[]{|}
+URxvt.cursorBlink: True
+URxvt.cursorColor: green
+URxvt.colorBD: yellow
+URxvt.colorUL: green
+!URxvt.blurRadius: 5
+
+
+!! Copy Paste & Other Extensions
+!URxvt.perl-ext-common: default,clipboard,url-select,keyboard-select
+!URxvt.copyCommand: xclip -i -selection clipboard
+!URxvt.pasteCommand: xclip -o -selection clipboard
+!URxvt.keysym.M-c: perl:clipboard:copy
+!URxvt.keysym.M-v: perl:clipboard:paste
+!URxvt.keysym.M-C-v: perl:clipboard:paste_escaped
+!URxvt.keysym.M-Escape: perl:keyboard-select:activate
+!URxvt.keysym.M-s: perl:keyboard-select:search
+!URxvt.keysym.M-u: perl:url-select:select_next
+!URxvt.urlLauncher: firefox
+!URxvt.underlineURLs: true
+!URxvt.urlButton: 1
+
+
+
+
+URxvt.keysym.Control-v: eval:paste_clipboard
+URxvt.keysym.Control-c: eval:selection_to_clipboard
+URxvt.keysym.Control-Meta-c: builtin-string:
+URxvt.keysym.Control-Meta-v: builtin-string:
+
+
+URxvt.keysym.Control-k: command:\033]720;1\007
+URxvt.keysym.Control-j: command:\033]721;1\007
+
+
+URxvt.keysym.Meta-Page_Up: perl:pageup
+URxvt.keysym.Meta-Page_Down: perl:pagedown
+URxvt.perl-lib: /usr/local/lib/urxvt/perl
+URxvt.perl-ext: custom.pl
+
+
+!URxvt*loginShell: true
+!URxvt*termName: screen-256color
+
+!URxvt*perl-ext-common:
+!URxvt*perl-ext:
+
+
+!URxvt.keysym.Control-B: eval:scroll_up_pages 1
+!URxvt.keysym.Control-F: eval:scroll_down_pages 1
+
+
+URxvt.perl-ext-common: default,matcher,clipboard,tabbed
+URxvt.clipboard.autocopy: true
+URxvt.keysym.M-c: perl:clipboard:copy
+URxvt.keysym.M-v: perl:clipboard:paste
+
+!URxvt.url-launcher: /usr/bin/xdg-open
+!URxvt.matcher.button: 1
+!URxvt.keysym.C-Delete: perl:matcher:last
+!URxvt.keysym.M-Delete: perl:matcher:list
+!URxvt.matcher.rend.0: Uline Bold fg5
+
+!URxvt.perl-ext-common: ...,tabbed,...
+
+
+!Key Description
+!Shift+Down New tab
+!Shift+Left Go to left tab
+!Shift+Right Go to right tab
+!Ctrl+Left Move tab to the left
+!Ctrl+Right Move tab to the right
+!Ctrl+d Close tab
+
+
+!URxvt.keysym.Control-k: \033[1;5A
+!URxvt.keysym.Control-j: \033[1;5B
+!URxvt.keysym.Control-l: \033[1;5C
+!URxvt.keysym.Control-h: \033[1;5D
+
+!^[[5~
+
+
+rofi.kb-row-up: Up,Control+k,Shift+Tab,Shift+ISO_Left_Tab
+rofi.kb-row-down: Down,Control+j
+rofi.kb-accept-entry: Control+m,Return,KP_Enter
+rofi.terminal: st
+rofi.kb-remove-to-eol: Control+Shift+e
+rofi.kb-mode-next: Shift+Right,Control+Tab,Control+l
+rofi.kb-mode-previous: Shift+Left,Control+Shift+Tab,Control+h
+rofi.kb-remove-char-back: BackSpace
+
+
+
+
+!! Set a default font and font size as below:
+!*.font: monospace:size=10
+rofi.font: Noto Sans 11
+
+/* name dark light */
+/* black 0 8 */
+/* red 1 9 */
+/* green 2 10 */
+/* yellow 3 11 */
+/* blue 4 12 */
+/* purple 5 13 */
+/* cyan 6 14 */
+/* white 7 15 */
+
+/* !! gruvbox: */
+/* *.color0: #1d2021 */
+/* *.color1: #cc241d */
+/* *.color2: #98971a */
+/* *.color3: #d79921 */
+/* *.color4: #458588 */
+/* *.color5: #b16286 */
+/* *.color6: #689d6a */
+/* *.color7: #a89984 */
+/* *.color8: #928374 */
+/* *.color9: #fb4934 */
+/* *.color10: #b8bb26 */
+/* *.color11: #fabd2f */
+/* *.color12: #83a598 */
+/* *.color13: #d3869b */
+/* *.color14: #8ec07c */
+/* *.color15: #ebdbb2 */
+/* *.color256: #1d2021 */
+/* *.color257: #ebdbb2 */
+
+* !! gruvbox light: */
+* *.color0: #fbf1c7 */
+* *.color1: #cc241d */
+* *.color2: #98971a */
+* *.color3: #d79921 */
+* *.color4: #458588 */
+* *.color5: #b16286 */
+* *.color6: #689d6a */
+* *.color7: #7c6f64 */
+* *.color8: #928374 */
+* *.color9: #9d0006 */
+* *.color10: #79740e */
+* *.color11: #b57614 */
+* *.color12: #076678 */
+* *.color13: #8f3f71 */
+* *.color14: #427b58 */
+* *.color15: #3c3836 */
+* *.background: #fbf1c7 */
+* *.foreground: #282828 */
+* st.alpha: 0.2 */
+
+/* !! brogrammer: */
+/* *.foreground: #d6dbe5 */
+/* *.background: #131313 */
+/* *.color0: #1f1f1f */
+/* *.color8: #d6dbe5 */
+/* *.color1: #f81118 */
+/* *.color9: #de352e */
+/* *.color2: #2dc55e */
+/* *.color10: #1dd361 */
+/* *.color3: #ecba0f */
+/* *.color11: #f3bd09 */
+/* *.color4: #2a84d2 */
+/* *.color12: #1081d6 */
+/* *.color5: #4e5ab7 */
+/* *.color13: #5350b9 */
+/* *.color6: #1081d6 */
+/* *.color14: #0f7ddb */
+/* *.color7: #d6dbe5 */
+/* *.color15: #ffffff */
+/* *.colorBD: #d6dbe5 */
+
+/* ! base16 */
+/* *.color0: #181818 */
+/* *.color1: #ab4642 */
+/* *.color2: #a1b56c */
+/* *.color3: #f7ca88 */
+/* *.color4: #7cafc2 */
+/* *.color5: #ba8baf */
+/* *.color6: #86c1b9 */
+/* *.color7: #d8d8d8 */
+/* *.color8: #585858 */
+/* *.color9: #ab4642 */
+/* *.color10: #a1b56c */
+/* *.color11: #f7ca88 */
+/* *.color12: #7cafc2 */
+/* *.color13: #ba8baf */
+/* *.color14: #86c1b9 */
+/* *.color15: #f8f8f8 */
+
+/* !! solarized */
+/* *.color0: #073642 */
+/* *.color1: #dc322f */
+/* *.color2: #859900 */
+/* *.color3: #b58900 */
+/* *.color4: #268bd2 */
+/* *.color5: #d33682 */
+/* *.color6: #2aa198 */
+/* *.color7: #eee8d5 */
+/* *.color9: #cb4b16 */
+/* *.color8: #fdf6e3 */
+/* *.color10: #586e75 */
+/* *.color11: #657b83 */
+/* *.color12: #839496 */
+/* *.color13: #6c71c4 */
+/* *.color14: #93a1a1 */
+/* *.color15: #fdf6e3 */
+
+/* !! xterm */
+/* *.color0: #000000 */
+/* *.color1: #cd0000 */
+/* *.color2: #00cd00 */
+/* *.color3: #cdcd00 */
+/* *.color4: #0000cd */
+/* *.color5: #cd00cd */
+/* *.color6: #00cdcd */
+/* *.color7: #e5e5e5 */
+/* *.color8: #4d4d4d */
+/* *.color9: #ff0000 */
+/* *.color10: #00ff00 */
+/* *.color11: #ffff00 */
+/* *.color12: #0000ff */
+/* *.color13: #ff00ff */
+/* *.color14: #00ffff */
+/* *.color15: #aabac8 */
+/* *.background: #000000 */
+
+/* ! Dracula Xresources palette */
+/* *.foreground: #F8F8F2 */
+/* *.background: #282A36 */
+/* *.color0: #000000 */
+/* *.color8: #4D4D4D */
+/* *.color1: #FF5555 */
+/* *.color9: #FF6E67 */
+/* *.color2: #50FA7B */
+/* *.color10: #5AF78E */
+/* *.color3: #F1FA8C */
+/* *.color11: #F4F99D */
+/* *.color4: #BD93F9 */
+/* *.color12: #CAA9FA */
+/* *.color5: #FF79C6 */
+/* *.color13: #FF92D0 */
+/* *.color6: #8BE9FD */
+/* *.color14: #9AEDFE */
+/* *.color7: #BFBFBF */
+/* *.color15: #E6E6E6 */
+
+/* *.background: .color0 */
+/* *.color256: 0#1d2021 */
+/* *.color257: 15#ebdbb2 */
diff --git a/linux/home/.config/X11/.xbindkeysrc b/linux/home/.config/X11/.xbindkeysrc
new file mode 100644
index 0000000..481943d
--- /dev/null
+++ b/linux/home/.config/X11/.xbindkeysrc
@@ -0,0 +1,31 @@
+# # Up
+# "xdotool mousemove_relative --sync -- 0 -24"
+# alt + w
+#
+# # Left
+# "xdotool mousemove_relative --sync -- -24 0"
+# alt + a
+#
+# # Down
+# "xdotool mousemove_relative --sync -- 0 24"
+# alt + s
+#
+# # Right
+# "xdotool mousemove_relative --sync -- 24 0"
+# alt + d
+#
+# # left + up
+# "xdotool mousemove_relative --sync -- -24 -24"
+# Shift+alt + q
+#
+# # right + up
+# "xdotool mousemove_relative --sync -- 24 -24"
+# Shift+alt + e
+#
+# # right + down
+# "xdotool mousemove_relative --sync -- 24 24"
+# Shift+alt + d
+#
+# # left + down
+# "xdotool mousemove_relative --sync -- -24 24"
+# Shift+alt + a
diff --git a/linux/home/.config/X11/.xinitrc b/linux/home/.config/X11/.xinitrc
new file mode 100755
index 0000000..d500044
--- /dev/null
+++ b/linux/home/.config/X11/.xinitrc
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+#░█▀▀░▀█▀░█▀█░█▀▄░▀█▀░█░█
+#░▀▀█░░█░░█▀█░█▀▄░░█░░▄▀▄
+#░▀▀▀░░▀░░▀░▀░▀░▀░░▀░░▀░▀
+#
+
+# xinitrc.d
+if [ -d /etc/X11/xinit/xinitrc.d ]; then
+ for f in /etc/X11/xinit/xinitrc.d/*; do
+ [ -x "$f" ] && . "$f"
+ done
+ unset f
+fi
+
+# Keyboard layout
+setxkbmap -model pc105 -layout us -variant qwerty
+
+# xinitrc runs automatically when you run startx.
+
+# There are some small but important commands that need to be run when we start
+# the graphical environment. There is a link to this file in ~/.xprofile
+# because that file is run automatically if someone uses a display manager
+# (login screen) and so they are needed there. To prevent doubling up commands,
+# I source them here with the line below.
+
+# Profile
+[[ -f /etc/profile ]] && source /etc/profile
+
+if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/X11/.xprofile" ]; then
+ . "${XDG_CONFIG_HOME:-$HOME/.config}/X11/.xprofile"
+else
+ . "$HOME/.xprofile"
+fi
diff --git a/linux/home/.config/X11/.xprofile b/linux/home/.config/X11/.xprofile
new file mode 100644
index 0000000..bc2e5f8
--- /dev/null
+++ b/linux/home/.config/X11/.xprofile
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# Xresources
+[[ -f ~/.config/X11/.Xresources ]] && xrdb -merge ~/.config/X11/.Xresources
+
+#Xset
+xset r rate 150 50
+#xset r rate 290 70
+
+# Xbindkeys
+xbindkeys -f "$XDG_CONFIG_HOME"/X11/xbindkeysrc
+
+# XKB
+setxkbmap -print | xkbcomp -I"$HOME"/.config/xkb - "$DISPLAY"
+
+#export XAUTHORITY="$XDG_RUNTIME_DIR/.Xauthority" # This line will break some DMs.
+export USERXSESSION="$XDG_CACHE_HOME/X11/xsession"
+export USERXSESSIONRC="$XDG_CACHE_HOME/X11/xsessionrc"
+export ALTUSERXSESSION="$XDG_CACHE_HOME/X11/Xsession"
+export ERRFILE="$XDG_CACHE_HOME/X11/xsession-errors"
+
+if [[ "$(tty)" = "/dev/tty1" ]]; then
+ pgrep bspwm || startx "$XDG_CONFIG_HOME/X11/.xinitrc"
+fi
diff --git a/linux/home/.config/ags/.eslintrc.yml b/linux/home/.config/ags/.eslintrc.yml
new file mode 100644
index 0000000..ff96a83
--- /dev/null
+++ b/linux/home/.config/ags/.eslintrc.yml
@@ -0,0 +1,130 @@
+env:
+ es2022: true
+extends:
+ - "eslint:recommended"
+ - "plugin:@typescript-eslint/recommended"
+parser: "@typescript-eslint/parser"
+parserOptions:
+ ecmaVersion: 2022
+ sourceType: "module"
+ project: "./tsconfig.json"
+ warnOnUnsupportedTypeScriptVersion: false
+root: true
+ignorePatterns:
+ - types/
+plugins:
+ - "@typescript-eslint"
+rules:
+ "@typescript-eslint/ban-ts-comment":
+ - "off"
+ "@typescript-eslint/no-non-null-assertion":
+ - "off"
+ # "@typescript-eslint/no-explicit-any":
+ # - "off"
+ "@typescript-eslint/no-unused-vars":
+ - error
+ - varsIgnorePattern: (^unused|_$)
+ argsIgnorePattern: ^(unused|_)
+ "@typescript-eslint/no-empty-interface":
+ - "off"
+
+ arrow-parens:
+ - error
+ - as-needed
+ comma-dangle:
+ - error
+ - always-multiline
+ comma-spacing:
+ - error
+ - before: false
+ after: true
+ comma-style:
+ - error
+ - last
+ curly:
+ - error
+ - multi-or-nest
+ - consistent
+ dot-location:
+ - error
+ - property
+ eol-last:
+ - error
+ eqeqeq:
+ - error
+ - always
+ indent:
+ - error
+ - 4
+ - SwitchCase: 1
+ keyword-spacing:
+ - error
+ - before: true
+ lines-between-class-members:
+ - error
+ - always
+ - exceptAfterSingleLine: true
+ padded-blocks:
+ - error
+ - never
+ - allowSingleLineBlocks: false
+ prefer-const:
+ - error
+ quotes:
+ - error
+ - double
+ - avoidEscape: true
+ semi:
+ - error
+ - never
+ nonblock-statement-body-position:
+ - error
+ - below
+ no-trailing-spaces:
+ - error
+ no-useless-escape:
+ - off
+ max-len:
+ - error
+ - code: 100
+ func-call-spacing:
+ - error
+ array-bracket-spacing:
+ - error
+ space-before-function-paren:
+ - error
+ - anonymous: never
+ named: never
+ asyncArrow: ignore
+ space-before-blocks:
+ - error
+ key-spacing:
+ - error
+ object-curly-spacing:
+ - error
+ - always
+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/linux/home/.config/ags/.gitignore b/linux/home/.config/ags/.gitignore
new file mode 100644
index 0000000..f56dbd1
--- /dev/null
+++ b/linux/home/.config/ags/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+types
+package-lock.json
+bun.lockb
+flake.lock
+.weather
diff --git a/linux/home/.config/ags/assets/arrows-down.svg b/linux/home/.config/ags/assets/arrows-down.svg
new file mode 100644
index 0000000..5851aed
--- /dev/null
+++ b/linux/home/.config/ags/assets/arrows-down.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" version="1.1">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g transform="matrix(1,0,0,1,4,4)">
+ <path class="ColorScheme-Text" d="M 7,2 V 10 L 3.5,6.5 2,8 8,14 14,8 12.5,6.5 9,10 V 2 Z" style="fill:currentColor"/>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/arrows-left.svg b/linux/home/.config/ags/assets/arrows-left.svg
new file mode 100644
index 0000000..f3c1b2e
--- /dev/null
+++ b/linux/home/.config/ags/assets/arrows-left.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" version="1.1">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g transform="matrix(1,0,0,1,4,4)">
+ <path class="ColorScheme-Text" d="M 14,7 H 6 L 9.5,3.5 8,2 2,8 8,14 9.5,12.5 6,9 H 14 Z" style="fill:currentColor"/>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/arrows-right.svg b/linux/home/.config/ags/assets/arrows-right.svg
new file mode 100644
index 0000000..30baa8f
--- /dev/null
+++ b/linux/home/.config/ags/assets/arrows-right.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" version="1.1">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g transform="matrix(1,0,0,1,4,4)">
+ <path class="ColorScheme-Text" d="M 2,9 H 10 L 6.5,12.5 8,14 14,8 8,2 6.5,3.5 10,7 H 2 Z" style="fill:currentColor"/>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/arrows-up.svg b/linux/home/.config/ags/assets/arrows-up.svg
new file mode 100644
index 0000000..68b9944
--- /dev/null
+++ b/linux/home/.config/ags/assets/arrows-up.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" version="1.1">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g transform="matrix(1,0,0,1,4,4)">
+ <path class="ColorScheme-Text" d="M 7,14 V 6 L 3.5,9.5 2,8 8,2 14,8 12.5,9.5 9,6 V 14 Z" style="fill:currentColor"/>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/battery-flash-symbolic.svg b/linux/home/.config/ags/assets/battery-flash-symbolic.svg
new file mode 100644
index 0000000..21b5e33
--- /dev/null
+++ b/linux/home/.config/ags/assets/battery-flash-symbolic.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 8.96875 0 c -0.332031 0.0117188 -0.640625 0.1875 -0.816406 0.46875 l -5 8 c -0.105469 0.171875 -0.152344 0.355469 -0.152344 0.53125 v 1 h 3 v 5 c 0 1.003906 1.316406 1.378906 1.847656 0.53125 l 5 -8 c 0.105469 -0.171875 0.152344 -0.355469 0.152344 -0.53125 v -1 h -3 v -5 c 0 -0.5625 -0.464844 -1.015625 -1.03125 -1 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/bomb-kill.svg b/linux/home/.config/ags/assets/bomb-kill.svg
new file mode 100644
index 0000000..a6e9f09
--- /dev/null
+++ b/linux/home/.config/ags/assets/bomb-kill.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ viewBox="0 0 22 22"
+ version="1.1"
+ id="svg1"
+ sodipodi:docname="bomb-kill.svg"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview1"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="28.545455"
+ inkscape:cx="11"
+ inkscape:cy="11"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3051">
+ <style
+ type="text/css"
+ id="current-color-scheme">.ColorScheme-Text { color: #fcfcfc; } </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none;stroke-width:0.855269"
+ d="m 17.858728,4.1743879 c -1.13103,0.2314779 -2.107737,0.9080479 -2.727751,1.858046 -0.214576,-0.095764 -0.450425,-0.1516429 -0.701613,-0.1516429 -0.178764,0 -0.347261,0.034927 -0.509046,0.084986 -0.975172,-0.5918778 -2.11854,-0.9381881 -3.348989,-0.9381881 -3.5622531,0 -6.4300571,2.8539574 -6.4300571,6.3990111 0,3.545055 2.867804,6.399011 6.4300571,6.399011 3.562254,0 6.430058,-2.853956 6.430058,-6.39901 0,-1.224507 -0.347991,-2.3623553 -0.94274,-3.3328191 0.0503,-0.1610043 0.0854,-0.3286874 0.0854,-0.5065884 0,-0.3822616 -0.128156,-0.7309813 -0.339922,-1.0148431 0.459139,-0.7437673 1.188057,-1.2957452 2.054604,-1.5197652 V 4.1743879 M 6.9862372,7.1755908 C 6.173802,8.138787 5.6851553,9.38169 5.6851553,10.743373 c 0,3.07238 2.4854307,5.54581 5.5727167,5.54581 1.36784,0 2.61568,-0.486764 3.583418,-1.2948 -1.020672,1.209625 -2.551332,1.978028 -4.269961,1.978028 -3.0872862,0 -5.5727161,-2.47343 -5.5727161,-5.54581 0,-1.7106949 0.7716789,-3.2352661 1.9876243,-4.2510102"
+ class="ColorScheme-Text"
+ id="path1" />
+</svg>
diff --git a/linux/home/.config/ags/assets/chat-bubbles-symbolic.svg b/linux/home/.config/ags/assets/chat-bubbles-symbolic.svg
new file mode 100644
index 0000000..fdee0b3
--- /dev/null
+++ b/linux/home/.config/ags/assets/chat-bubbles-symbolic.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 14 3.175781 v 3.824219 c 0 2.179688 -1.820312 4 -4 4 h -3.585938 l -2 2 h 5.585938 l 3 3 v -3 c 1.644531 0 3 -1.355469 3 -3 v -4 c 0 -1.292969 -0.839844 -2.40625 -2 -2.824219 z m 0 0" fill-opacity="0.34902"/>
+ <path d="m 3 0 c -1.644531 0 -3 1.355469 -3 3 v 4 c 0 1.644531 1.355469 3 3 3 v 3 l 3 -3 h 4 c 1.644531 0 3 -1.355469 3 -3 v -4 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/controller-symbolic.svg b/linux/home/.config/ags/assets/controller-symbolic.svg
new file mode 100644
index 0000000..98bf5d6
--- /dev/null
+++ b/linux/home/.config/ags/assets/controller-symbolic.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 3.785156 2.03125 c -0.242187 0 -0.523437 0.066406 -0.804687 0.21875 c -1.039063 0.546875 -1.992188 2.335938 -2.511719 4.65625 c -0.4414062 1.972656 -0.605469 4.664062 -0.339844 5.75 c 0.226563 0.933594 0.625 1.34375 1.332032 1.34375 c 1.042968 -0.019531 2.359374 -1.183594 3.191406 -2.75 c 0.601562 -0.867188 2 -1.261719 3.347656 -1.21875 c 1.347656 -0.046875 2.746094 0.351562 3.347656 1.21875 c 0.832032 1.566406 2.148438 2.730469 3.191406 2.75 c 0.707032 0 1.105469 -0.410156 1.332032 -1.34375 c 0.265625 -1.085938 0.101562 -3.777344 -0.339844 -5.75 c -0.519531 -2.320312 -1.472656 -4.109375 -2.511719 -4.65625 c -0.566406 -0.304688 -1.039062 -0.296875 -1.453125 0 c -0.527344 0.375 -1.628906 0.78125 -3.566406 0.78125 c -1.9375 0.003906 -3.039062 -0.40625 -3.566406 -0.78125 c -0.207032 -0.148438 -0.40625 -0.21875 -0.648438 -0.21875 z m 0.246094 3 h 0.992188 v 1 h 0.992187 v 1 h -0.992187 v 1 h -0.992188 v -1 h -0.992188 v -1 h 0.992188 z m 7.441406 0 c 0.273438 0 0.496094 0.222656 0.496094 0.5 s -0.222656 0.5 -0.496094 0.5 c -0.273437 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222657 -0.5 0.496094 -0.5 z m -0.992187 1 c 0.273437 0 0.496093 0.222656 0.496093 0.5 s -0.222656 0.5 -0.496093 0.5 c -0.273438 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222656 -0.5 0.496094 -0.5 z m 1.984375 0 c 0.273437 0 0.496094 0.222656 0.496094 0.5 s -0.222657 0.5 -0.496094 0.5 c -0.273438 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222656 -0.5 0.496094 -0.5 z m -0.992188 1 c 0.273438 0 0.496094 0.222656 0.496094 0.5 s -0.222656 0.5 -0.496094 0.5 c -0.273437 0 -0.496094 -0.222656 -0.496094 -0.5 s 0.222657 -0.5 0.496094 -0.5 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/controls-symbolic.svg b/linux/home/.config/ags/assets/controls-symbolic.svg
new file mode 100644
index 0000000..7df5663
--- /dev/null
+++ b/linux/home/.config/ags/assets/controls-symbolic.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 4.550781 1 c -1.9375 0 -3.5 1.5625 -3.5 3.5 s 1.5625 3.5 3.5 3.5 h 7 c 1.941407 0 3.5 -1.5625 3.5 -3.5 s -1.558593 -3.5 -3.5 -3.5 z m 7 1 c 1.386719 0 2.5 1.113281 2.5 2.5 c 0 1.382812 -1.113281 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.117188 -2.5 -2.5 c 0 -1.386719 1.117188 -2.5 2.5 -2.5 z m 0 0"/>
+ <path d="m 4.550781 9 c -1.9375 0 -3.5 1.5625 -3.5 3.5 s 1.5625 3.5 3.5 3.5 h 7 c 1.941407 0 3.5 -1.5625 3.5 -3.5 s -1.558593 -3.5 -3.5 -3.5 z m 0 1 c 1.386719 0 2.5 1.113281 2.5 2.5 c 0 1.382812 -1.113281 2.5 -2.5 2.5 c -1.382812 0 -2.5 -1.117188 -2.5 -2.5 c 0 -1.386719 1.117188 -2.5 2.5 -2.5 z m 0 0" fill-opacity="0.34902"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/dark-mode-symbolic.svg b/linux/home/.config/ags/assets/dark-mode-symbolic.svg
new file mode 100644
index 0000000..9f2e6b4
--- /dev/null
+++ b/linux/home/.config/ags/assets/dark-mode-symbolic.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 0.917969 8.003906 c 0 3.914063 3.164062 7.078125 7.078125 7.078125 c 3.605468 -0.007812 6.617187 -2.703125 7.023437 -6.285156 c 0.042969 -0.378906 -0.136719 -0.75 -0.457031 -0.957031 c -0.324219 -0.203125 -0.738281 -0.207032 -1.0625 -0.003906 c -0.609375 0.375 -1.316406 0.578124 -2.03125 0.578124 c -2.140625 0 -3.882812 -1.742187 -3.882812 -3.882812 c 0 -0.714844 0.203124 -1.421875 0.578124 -2.03125 c 0.203126 -0.324219 0.199219 -0.738281 -0.003906 -1.0625 c -0.207031 -0.320312 -0.578125 -0.5 -0.957031 -0.457031 c -3.582031 0.40625 -6.277344 3.417969 -6.285156 7.023437 z m 4.667969 -3.472656 c 0 3.253906 2.628906 5.882812 5.886718 5.882812 c 1.085938 0 2.152344 -0.304687 3.078125 -0.878906 l -1.519531 -0.960937 c -0.289062 2.554687 -2.464844 4.503906 -5.035156 4.507812 c -2.796875 0 -5.078125 -2.28125 -5.078125 -5.078125 c 0.003906 -2.570312 1.953125 -4.746094 4.507812 -5.035156 l -0.960937 -1.519531 c -0.574219 0.925781 -0.875 1.992187 -0.878906 3.082031 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/float.svg b/linux/home/.config/ags/assets/float.svg
new file mode 100644
index 0000000..dc8078a
--- /dev/null
+++ b/linux/home/.config/ags/assets/float.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ viewBox="0 0 16 16"
+ version="1.1"
+ id="svg2"
+ sodipodi:docname="float.svg"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview2"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="39.25"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:current-layer="svg2" />
+ <defs
+ id="defs1">
+ <style
+ type="text/css"
+ id="current-color-scheme">.ColorScheme-Text { color: #fcfcfc; } </style>
+ </defs>
+ <path
+ class="ColorScheme-Text"
+ d="M 7.8252389,2.2944865 A 5.6426155,5.4275975 0 0 0 2.1826234,7.722084 5.6426155,5.4275975 0 0 0 7.8252389,13.149682 5.6426155,5.4275975 0 0 0 13.467855,7.722084 5.6426155,5.4275975 0 0 0 7.8252389,2.2944865 m 0,0.9045996 A 4.7021795,4.5229979 0 0 1 12.527419,7.722084 4.7021795,4.5229979 0 0 1 7.8252389,12.245082 4.7021795,4.5229979 0 0 1 3.1230593,7.722084 4.7021795,4.5229979 0 0 1 7.8252389,3.1990861"
+ fill="currentColor"
+ id="path1"
+ style="stroke-width:0.922343" />
+ <path
+ class="ColorScheme-Text"
+ d="M 12.52741,7.7220642 A 4.7021795,4.5229979 0 0 1 7.8252308,12.245062 4.7021795,4.5229979 0 0 1 3.1230512,7.7220642 4.7021795,4.5229979 0 0 1 7.8252308,3.1990663 4.7021795,4.5229979 0 0 1 12.52741,7.7220642 Z"
+ fill="currentColor"
+ fill-opacity="0.5"
+ id="path2"
+ style="stroke-width:0.922343" />
+</svg>
diff --git a/linux/home/.config/ags/assets/fullscreen.svg b/linux/home/.config/ags/assets/fullscreen.svg
new file mode 100644
index 0000000..e9ab0b8
--- /dev/null
+++ b/linux/home/.config/ags/assets/fullscreen.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="24"
+ height="24"
+ version="1.1"
+ id="svg1"
+ sodipodi:docname="fullscreen.svg"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview1"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="19.666667"
+ inkscape:cx="12"
+ inkscape:cy="12"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs1">
+ <style
+ id="current-color-scheme"
+ type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g
+ transform="matrix(0.94763804,0,0,0.95290155,4.4188957,4.3767876)"
+ id="g1">
+ <path
+ style="fill:currentColor"
+ class="ColorScheme-Text"
+ d="M 4,10 1,8 4,6 Z m 8,0 3,-2 -3,-2 z m -4,5 2,-3 H 6 Z M 8,1 10,4 H 6 Z m 7,6 h 1 V 9 H 15 Z M 0,7 H 1 V 9 H 0 Z m 7,8 h 2 v 1 H 7 Z M 7,0 H 9 V 1 H 7 Z M 0,16 v -5 h 1 v 4 h 4 v 1 z m 16,0 v -4 h -1 v 3 h -4 v 1 z M 16,0 V 5 H 15 V 1 H 11 V 0 Z M 0,0 V 5 H 1 V 1 H 5 V 0 Z"
+ id="path1" />
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/hourglass-symbolic.svg b/linux/home/.config/ags/assets/hourglass-symbolic.svg
new file mode 100644
index 0000000..aa4f97c
--- /dev/null
+++ b/linux/home/.config/ags/assets/hourglass-symbolic.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 5 0 c -0.96875 0 -2 1.050781 -2 2 v 2.988281 c 0 0.429688 0.222656 0.675781 0.554688 1.007813 l 2.023437 2.003906 l -2.007813 1.992188 c -0.367187 0.363281 -0.570312 0.6875 -0.570312 1 v 3.007812 c 0 1.011719 0.988281 2 2 2 h 6 c 1.007812 0 2 -1.011719 2 -2.003906 v -3.003906 c 0 -0.3125 -0.222656 -0.628907 -0.570312 -0.976563 l -2.015626 -2.015625 l 1.988282 -1.988281 c 0.261718 -0.261719 0.585937 -0.6875 0.597656 -1.015625 v -2.996094 c 0 -1.003906 -1.007812 -2 -2 -2 z m 6 4 h -6 v -2 h 6 m -3.589844 7 h 1.175782 l 2.414062 2.414062 v 1.585938 h -6 v -1.613281 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/light-mode-symbolic.svg b/linux/home/.config/ags/assets/light-mode-symbolic.svg
new file mode 100644
index 0000000..d5fb271
--- /dev/null
+++ b/linux/home/.config/ags/assets/light-mode-symbolic.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 8 0 c -0.554688 0 -1 0.445312 -1 1 v 1 c 0 0.554688 0.445312 1 1 1 s 1 -0.445312 1 -1 v -1 c 0 -0.554688 -0.445312 -1 -1 -1 z m -4.996094 2.003906 c -0.253906 0 -0.507812 0.097656 -0.707031 0.296875 c -0.390625 0.390625 -0.390625 1.019531 0 1.414063 l 0.707031 0.707031 c 0.394532 0.390625 1.023438 0.390625 1.414063 0 c 0.394531 -0.394531 0.394531 -1.023437 0 -1.414063 l -0.707031 -0.707031 c -0.195313 -0.199219 -0.449219 -0.296875 -0.707032 -0.296875 z m 9.988282 0 c -0.253907 0 -0.507813 0.097656 -0.707032 0.296875 l -0.707031 0.707031 c -0.390625 0.390626 -0.390625 1.019532 0 1.414063 c 0.394531 0.390625 1.023437 0.390625 1.414063 0 l 0.707031 -0.707031 c 0.394531 -0.394532 0.394531 -1.023438 0 -1.414063 c -0.195313 -0.199219 -0.449219 -0.296875 -0.707031 -0.296875 z m -4.992188 1.996094 c -2.210938 0 -4 1.789062 -4 4 s 1.789062 4 4 4 s 4 -1.789062 4 -4 s -1.789062 -4 -4 -4 z m 0 2 c 1.105469 0 2 0.894531 2 2 s -0.894531 2 -2 2 s -2 -0.894531 -2 -2 s 0.894531 -2 2 -2 z m -7 1 c -0.554688 0 -1 0.445312 -1 1 s 0.445312 1 1 1 h 1 c 0.554688 0 1 -0.445312 1 -1 s -0.445312 -1 -1 -1 z m 13 0 c -0.554688 0 -1 0.445312 -1 1 s 0.445312 1 1 1 h 1 c 0.554688 0 1 -0.445312 1 -1 s -0.445312 -1 -1 -1 z m -10.335938 4.289062 c -0.238281 0.007813 -0.472656 0.105469 -0.660156 0.292969 l -0.707031 0.707031 c -0.390625 0.390626 -0.390625 1.019532 0 1.414063 c 0.394531 0.390625 1.023437 0.390625 1.414063 0 l 0.707031 -0.707031 c 0.394531 -0.394532 0.394531 -1.023438 0 -1.414063 c -0.207031 -0.210937 -0.484375 -0.308593 -0.753907 -0.292969 z m 8.574219 0 c -0.238281 0.007813 -0.472656 0.105469 -0.660156 0.292969 c -0.390625 0.390625 -0.390625 1.019531 0 1.414063 l 0.707031 0.707031 c 0.394532 0.390625 1.023438 0.390625 1.414063 0 c 0.394531 -0.394531 0.394531 -1.023437 0 -1.414063 l -0.707031 -0.707031 c -0.207032 -0.210937 -0.484376 -0.308593 -0.753907 -0.292969 z m -4.292969 1.710938 c -0.527343 0.027344 -0.945312 0.464844 -0.945312 1 v 1 c 0 0.554688 0.445312 1 1 1 s 1 -0.445312 1 -1 v -1 c 0 -0.554688 -0.445312 -1 -1 -1 c -0.015625 0 -0.035156 0 -0.050781 0 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/mixer-symbolic.svg b/linux/home/.config/ags/assets/mixer-symbolic.svg
new file mode 100644
index 0000000..ad6cfa8
--- /dev/null
+++ b/linux/home/.config/ags/assets/mixer-symbolic.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 11.5 1 c -1.921875 0 -3.5 1.578125 -3.5 3.5 s 1.578125 3.5 3.5 3.5 s 3.5 -1.578125 3.5 -3.5 s -1.578125 -3.5 -3.5 -3.5 z m 0 2 c 0.839844 0 1.5 0.660156 1.5 1.5 s -0.660156 1.5 -1.5 1.5 s -1.5 -0.660156 -1.5 -1.5 s 0.660156 -1.5 1.5 -1.5 z m 0 0"/>
+ <path d="m 4.5 8 c -1.921875 0 -3.5 1.578125 -3.5 3.5 s 1.578125 3.5 3.5 3.5 c 1.386719 0 2.59375 -0.820312 3.15625 -2 h 5.84375 c 0.832031 0 1.5 -0.667969 1.5 -1.5 s -0.667969 -1.5 -1.5 -1.5 h -5.84375 c -0.5625 -1.179688 -1.769531 -2 -3.15625 -2 z m 0 2 c 0.839844 0 1.5 0.660156 1.5 1.5 s -0.660156 1.5 -1.5 1.5 s -1.5 -0.660156 -1.5 -1.5 s 0.660156 -1.5 1.5 -1.5 z m 0 0"/>
+ <path d="m 2.5 3 c -0.832031 0 -1.5 0.667969 -1.5 1.5 s 0.667969 1.5 1.5 1.5 h 4.769531 c -0.175781 -0.480469 -0.265625 -0.988281 -0.269531 -1.5 c 0 -0.511719 0.09375 -1.019531 0.269531 -1.5 z m 0 0" fill-opacity="0.34902"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/nix-snowflake-symbolic.svg b/linux/home/.config/ags/assets/nix-snowflake-symbolic.svg
new file mode 100644
index 0000000..7bb42ed
--- /dev/null
+++ b/linux/home/.config/ags/assets/nix-snowflake-symbolic.svg
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="496"
+ height="496"
+ version="1"
+ id="svg6"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <g
+ id="g946"
+ transform="matrix(0.97173996,0,0,0.97173996,4.043873,36.112138)">
+ <g
+ id="layer7"
+ style="display:none"
+ transform="translate(-23.75651,-24.84972)">
+ <rect
+ transform="translate(-132.5822,958.04022)"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5389"
+ width="1543.4283"
+ height="483.7439"
+ x="132.5822"
+ y="-957.77832" />
+ </g>
+ <g
+ id="layer6"
+ style="display:none"
+ transform="translate(-156.33871,933.1905)">
+ <rect
+ y="-958.02759"
+ x="132.65129"
+ height="484.30399"
+ width="550.41602"
+ id="rect5379"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5c201e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c24a46;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5372"
+ width="501.94415"
+ height="434.30405"
+ x="156.12303"
+ y="-933.02759" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d98d8a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5381"
+ width="24.939611"
+ height="24.939611"
+ x="658.02826"
+ y="-958.04022" />
+ </g>
+ <g
+ id="layer3"
+ style="display:inline;opacity:1"
+ transform="translate(37.235605,912.8581)">
+ <g
+ id="g2072"
+ transform="matrix(0.99894325,0,0,0.99894325,-36.551621,-913.90743)"
+ style="fill:#cccccc;fill-opacity:1">
+ <g
+ style="display:none;fill:#cccccc;fill-opacity:1"
+ transform="matrix(0.09048806,0,0,0.09048806,-14.15991,84.454917)"
+ id="layer1-3">
+ <rect
+ y="-2102.4253"
+ x="-1045.6049"
+ height="7145.4614"
+ width="7947.0356"
+ id="rect995"
+ style="opacity:1;fill:#cccccc;fill-opacity:1;stroke-width:10.3605" />
+ </g>
+ <g
+ transform="translate(-156.48372,537.56136)"
+ style="display:inline;opacity:1;fill:#cccccc;fill-opacity:1"
+ id="layer3-6">
+ <g
+ style="fill:#cccccc;stroke-width:11.0512;fill-opacity:1"
+ transform="matrix(0.09048806,0,0,0.09048806,142.32381,-453.10644)"
+ id="g955">
+ <g
+ transform="matrix(11.047619,0,0,11.047619,-1572.2888,9377.7107)"
+ id="g869"
+ style="fill:#cccccc;fill-opacity:1">
+ <g
+ transform="rotate(-60,226.35754,-449.37199)"
+ id="g932"
+ style="fill:#cccccc;stroke-width:11.0512;fill-opacity:1">
+ <path
+ id="path3336-6-7"
+ d="m 449.71876,-420.51322 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83003 31.20698,-53.66007 46.81047,-80.4901 -11.07649,-19.27523 -22.15297,-38.55047 -33.22946,-57.8257 9.35083,-16.29387 18.70167,-32.58775 28.0525,-48.88162 z"
+ style="opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <path
+ id="path4260-0-5"
+ d="m 309.54892,-710.38827 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83003 31.20698,-53.66007 46.81047,-80.4901 -11.07649,-19.2752 -22.15297,-38.5504 -33.22946,-57.8256 9.35083,-16.29391 18.70167,-32.58781 28.0525,-48.88172 z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#path3336-6-7"
+ id="use3439-6-3"
+ transform="rotate(60,728.23563,-692.24036)"
+ width="100%"
+ height="100%"
+ style="fill:#cccccc;fill-opacity:1;stroke-width:11.0512" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#path3336-6-7"
+ id="use3449-5-5"
+ transform="rotate(180,477.5036,-570.81898)"
+ width="100%"
+ height="100%"
+ style="fill:#cccccc;fill-opacity:1;stroke-width:11.0512" />
+ <use
+ style="display:inline;fill:#cccccc;fill-opacity:1;stroke-width:11.0512"
+ x="0"
+ y="0"
+ xlink:href="#path4260-0-5"
+ id="use4354-5-6"
+ transform="rotate(120,407.33916,-716.08356)"
+ width="100%"
+ height="100%" />
+ <use
+ style="display:inline;fill:#cccccc;fill-opacity:1;stroke-width:11.0512"
+ x="0"
+ y="0"
+ xlink:href="#path4260-0-5"
+ id="use4362-2-2"
+ transform="rotate(-120,407.28823,-715.86995)"
+ width="100%"
+ height="100%" />
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/nixos-symbolic.svg b/linux/home/.config/ags/assets/nixos-symbolic.svg
new file mode 100644
index 0000000..7bb42ed
--- /dev/null
+++ b/linux/home/.config/ags/assets/nixos-symbolic.svg
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="496"
+ height="496"
+ version="1"
+ id="svg6"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <g
+ id="g946"
+ transform="matrix(0.97173996,0,0,0.97173996,4.043873,36.112138)">
+ <g
+ id="layer7"
+ style="display:none"
+ transform="translate(-23.75651,-24.84972)">
+ <rect
+ transform="translate(-132.5822,958.04022)"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5389"
+ width="1543.4283"
+ height="483.7439"
+ x="132.5822"
+ y="-957.77832" />
+ </g>
+ <g
+ id="layer6"
+ style="display:none"
+ transform="translate(-156.33871,933.1905)">
+ <rect
+ y="-958.02759"
+ x="132.65129"
+ height="484.30399"
+ width="550.41602"
+ id="rect5379"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5c201e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c24a46;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5372"
+ width="501.94415"
+ height="434.30405"
+ x="156.12303"
+ y="-933.02759" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d98d8a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5381"
+ width="24.939611"
+ height="24.939611"
+ x="658.02826"
+ y="-958.04022" />
+ </g>
+ <g
+ id="layer3"
+ style="display:inline;opacity:1"
+ transform="translate(37.235605,912.8581)">
+ <g
+ id="g2072"
+ transform="matrix(0.99894325,0,0,0.99894325,-36.551621,-913.90743)"
+ style="fill:#cccccc;fill-opacity:1">
+ <g
+ style="display:none;fill:#cccccc;fill-opacity:1"
+ transform="matrix(0.09048806,0,0,0.09048806,-14.15991,84.454917)"
+ id="layer1-3">
+ <rect
+ y="-2102.4253"
+ x="-1045.6049"
+ height="7145.4614"
+ width="7947.0356"
+ id="rect995"
+ style="opacity:1;fill:#cccccc;fill-opacity:1;stroke-width:10.3605" />
+ </g>
+ <g
+ transform="translate(-156.48372,537.56136)"
+ style="display:inline;opacity:1;fill:#cccccc;fill-opacity:1"
+ id="layer3-6">
+ <g
+ style="fill:#cccccc;stroke-width:11.0512;fill-opacity:1"
+ transform="matrix(0.09048806,0,0,0.09048806,142.32381,-453.10644)"
+ id="g955">
+ <g
+ transform="matrix(11.047619,0,0,11.047619,-1572.2888,9377.7107)"
+ id="g869"
+ style="fill:#cccccc;fill-opacity:1">
+ <g
+ transform="rotate(-60,226.35754,-449.37199)"
+ id="g932"
+ style="fill:#cccccc;stroke-width:11.0512;fill-opacity:1">
+ <path
+ id="path3336-6-7"
+ d="m 449.71876,-420.51322 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83003 31.20698,-53.66007 46.81047,-80.4901 -11.07649,-19.27523 -22.15297,-38.55047 -33.22946,-57.8257 9.35083,-16.29387 18.70167,-32.58775 28.0525,-48.88162 z"
+ style="opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ <path
+ id="path4260-0-5"
+ d="m 309.54892,-710.38827 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83003 31.20698,-53.66007 46.81047,-80.4901 -11.07649,-19.2752 -22.15297,-38.5504 -33.22946,-57.8256 9.35083,-16.29391 18.70167,-32.58781 28.0525,-48.88172 z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:33.1535;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#path3336-6-7"
+ id="use3439-6-3"
+ transform="rotate(60,728.23563,-692.24036)"
+ width="100%"
+ height="100%"
+ style="fill:#cccccc;fill-opacity:1;stroke-width:11.0512" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#path3336-6-7"
+ id="use3449-5-5"
+ transform="rotate(180,477.5036,-570.81898)"
+ width="100%"
+ height="100%"
+ style="fill:#cccccc;fill-opacity:1;stroke-width:11.0512" />
+ <use
+ style="display:inline;fill:#cccccc;fill-opacity:1;stroke-width:11.0512"
+ x="0"
+ y="0"
+ xlink:href="#path4260-0-5"
+ id="use4354-5-6"
+ transform="rotate(120,407.33916,-716.08356)"
+ width="100%"
+ height="100%" />
+ <use
+ style="display:inline;fill:#cccccc;fill-opacity:1;stroke-width:11.0512"
+ x="0"
+ y="0"
+ xlink:href="#path4260-0-5"
+ id="use4362-2-2"
+ transform="rotate(-120,407.28823,-715.86995)"
+ width="100%"
+ height="100%" />
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/nixos.svg b/linux/home/.config/ags/assets/nixos.svg
new file mode 100644
index 0000000..1a756ed
--- /dev/null
+++ b/linux/home/.config/ags/assets/nixos.svg
@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="496"
+ height="496"
+ version="1"
+ id="svg6"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10">
+ <linearGradient
+ id="linearGradient5562">
+ <stop
+ style="stop-color:#699ad7;stop-opacity:1"
+ offset="0"
+ id="stop5564" />
+ <stop
+ id="stop5566"
+ offset="0.24345198"
+ style="stop-color:#7eb1dd;stop-opacity:1" />
+ <stop
+ style="stop-color:#7ebae4;stop-opacity:1"
+ offset="1"
+ id="stop5568" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5053">
+ <stop
+ style="stop-color:#415e9a;stop-opacity:1"
+ offset="0"
+ id="stop5055" />
+ <stop
+ id="stop5057"
+ offset="0.23168644"
+ style="stop-color:#4a6baf;stop-opacity:1" />
+ <stop
+ style="stop-color:#5277c3;stop-opacity:1"
+ offset="1"
+ id="stop5059" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5960">
+ <stop
+ id="stop5962"
+ offset="0"
+ style="stop-color:#637ddf;stop-opacity:1" />
+ <stop
+ style="stop-color:#649afa;stop-opacity:1"
+ offset="0.23168644"
+ id="stop5964" />
+ <stop
+ id="stop5966"
+ offset="1"
+ style="stop-color:#719efa;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ y2="515.97058"
+ x2="282.26105"
+ y1="338.62445"
+ x1="213.95642"
+ gradientTransform="translate(983.36076,293.12113)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5855"
+ xlink:href="#linearGradient5960" />
+ <linearGradient
+ xlink:href="#linearGradient5562"
+ id="linearGradient4328"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(70.650339,-1055.1511)"
+ x1="200.59668"
+ y1="351.41116"
+ x2="290.08701"
+ y2="506.18814" />
+ <linearGradient
+ xlink:href="#linearGradient5053"
+ id="linearGradient4330"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(864.69589,-1491.3405)"
+ x1="-584.19934"
+ y1="782.33563"
+ x2="-496.29703"
+ y2="937.71399" />
+ </defs>
+ <g
+ id="g946"
+ transform="matrix(0.97173996,0,0,0.97173996,4.043873,36.112138)">
+ <g
+ id="layer7"
+ style="display:none"
+ transform="translate(-23.75651,-24.84972)">
+ <rect
+ transform="translate(-132.5822,958.04022)"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5389"
+ width="1543.4283"
+ height="483.7439"
+ x="132.5822"
+ y="-957.77832" />
+ </g>
+ <g
+ id="layer6"
+ style="display:none"
+ transform="translate(-156.33871,933.1905)">
+ <rect
+ y="-958.02759"
+ x="132.65129"
+ height="484.30399"
+ width="550.41602"
+ id="rect5379"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5c201e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c24a46;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5372"
+ width="501.94415"
+ height="434.30405"
+ x="156.12303"
+ y="-933.02759" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#d98d8a;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5381"
+ width="24.939611"
+ height="24.939611"
+ x="658.02826"
+ y="-958.04022" />
+ </g>
+ <g
+ id="layer1"
+ style="display:inline"
+ transform="translate(-156.33871,933.1905)">
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 309.40365,-710.2521 c 40.73228,70.55837 81.46455,141.11673 122.19683,211.6751 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83007 31.20698,-53.66013 46.81047,-80.4902 -11.07649,-19.2752 -22.15297,-38.5504 -33.22946,-57.8256 9.35083,-16.29387 18.70167,-32.58773 28.0525,-48.8816 z"
+ id="path4861" />
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#7ebae4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 353.50926,-797.4433 c -40.73919,70.55437 -81.47837,141.10873 -122.21756,211.6631 -9.51159,-16.12333 -19.02318,-32.24667 -28.53477,-48.37 10.97946,-18.89583 21.95893,-37.79167 32.93839,-56.6875 -21.80507,-0.0573 -43.61014,-0.1146 -65.41521,-0.1719 -4.64713,-8.0566 -9.29427,-16.1132 -13.9414,-24.1698 4.74546,-8.24033 9.49091,-16.48067 14.23637,-24.721 31.03726,0.098 62.07451,0.19593 93.11177,0.2939 11.15457,-19.2301 22.30914,-38.4602 33.46371,-57.6903 18.78623,-0.0488 37.57247,-0.0977 56.3587,-0.1465 z"
+ id="use4863" />
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#7ebae4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 362.88537,-628.243 c 81.47146,0.004 162.94293,0.008 244.41439,0.012 -9.20743,16.29893 -18.41486,32.59787 -27.62229,48.8968 -21.854,-0.0606 -43.70799,-0.12113 -65.56199,-0.1817 10.85292,18.91237 21.70584,37.82473 32.55876,56.7371 -4.65366,8.05283 -9.30732,16.10567 -13.96098,24.1585 -9.50907,0.0107 -19.01815,0.0213 -28.52722,0.032 -15.43377,-26.92803 -30.86753,-53.85607 -46.3013,-80.7841 -22.23106,-0.0451 -44.46211,-0.0902 -66.69317,-0.1353 -9.4354,-16.2451 -18.8708,-32.4902 -28.3062,-48.7353 z"
+ id="use4865" />
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#7ebae4;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 505.14318,-720.9886 c -40.73228,-70.55837 -81.46455,-141.11673 -122.19683,-211.6751 18.71902,-0.1756 37.43804,-0.3512 56.15706,-0.5268 10.87453,18.9564 21.74907,37.9128 32.6236,56.8692 10.95215,-18.8551 21.9043,-37.7102 32.85645,-56.5653 9.30079,0.004 18.60158,0.007 27.90237,0.011 4.76362,8.22987 9.52724,16.45973 14.29086,24.6896 -15.60349,26.83007 -31.20698,53.66013 -46.81047,80.4902 11.07649,19.2752 22.15297,38.5504 33.22946,57.8256 -9.35083,16.29387 -18.70167,32.58773 -28.0525,48.8816 z"
+ id="use4867" />
+ <path
+ id="path4873"
+ d="m 309.40365,-710.2521 c 40.73228,70.55837 81.46455,141.11673 122.19683,211.6751 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83007 31.20698,-53.66013 46.81047,-80.4902 -11.07649,-19.2752 -22.15297,-38.5504 -33.22946,-57.8256 9.35083,-16.29387 18.70167,-32.58773 28.0525,-48.8816 z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="use4875"
+ d="m 451.3364,-803.53264 c -81.47147,-0.004 -162.94293,-0.008 -244.4144,-0.012 9.20743,-16.29895 18.41486,-32.5979 27.62229,-48.89685 21.854,0.0606 43.70799,0.12117 65.56199,0.18175 -10.85292,-18.91239 -21.70583,-37.82478 -32.55875,-56.73717 4.65366,-8.05284 9.30731,-16.10567 13.96097,-24.15851 9.50907,-0.0105 19.01815,-0.021 28.52722,-0.0315 15.43377,26.92805 30.86753,53.85609 46.3013,80.78414 22.23106,0.0451 44.46211,0.0902 66.69317,0.13524 9.4354,16.24497 18.87081,32.48993 28.30621,48.7349 z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="use4877"
+ d="m 460.87178,-633.8425 c 40.73919,-70.55435 81.47838,-141.10869 122.21757,-211.66304 9.51159,16.12334 19.02318,32.24669 28.53477,48.37003 -10.97946,18.89584 -21.95893,37.79167 -32.93839,56.68751 21.80507,0.0573 43.61013,0.11453 65.4152,0.1718 4.64713,8.0566 9.29427,16.1132 13.9414,24.1698 -4.74545,8.24037 -9.49091,16.48073 -14.23636,24.7211 -31.03726,-0.098 -62.07451,-0.196 -93.11177,-0.294 -11.15457,19.23013 -22.30914,38.46027 -33.46371,57.6904 -18.78624,0.0488 -37.57247,0.0976 -56.35871,0.1464 z"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#5277c3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ id="layer2"
+ style="display:none"
+ transform="translate(72.039038,-1799.4476)">
+ <path
+ d="M 460.60629,594.72881 209.74183,594.7288 84.309616,377.4738 209.74185,160.21882 l 250.86446,1e-5 125.43222,217.255 z"
+ id="path6032"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.236;fill:#4e4d52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate" />
+ <path
+ transform="translate(0,-308.26772)"
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#4e4d52;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="path5875"
+ d="m 385.59154,773.06721 -100.83495,0 -50.41747,-87.32564 50.41748,-87.32563 100.83495,10e-6 50.41748,87.32563 z" />
+ <path
+ id="path5851"
+ d="m 1216.5591,630.26623 c 41.0182,76.04675 82.0363,152.09355 123.0545,228.14035 -14.2269,-0.4205 -28.4538,-0.8411 -42.6807,-1.2616 -14.4941,-26.5908 -28.9882,-53.1817 -43.4823,-79.7725 -13.2169,26.7756 -26.4337,53.5511 -39.6506,80.3267 -10.8958,-6.5995 -21.7917,-13.1989 -32.6875,-19.7984 17.8246,-33.4283 35.6491,-66.8565 53.4737,-100.2848 -12.3719,-24.6298 -24.7438,-49.2597 -37.1157,-73.88955 6.3629,-11.1534 12.7257,-22.3068 19.0886,-33.4602 z"
+ style="fill:url(#linearGradient5855);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.415;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c53a3a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect5884"
+ width="48.834862"
+ height="226.22897"
+ x="-34.74221"
+ y="446.17056"
+ transform="rotate(-30)" />
+ <path
+ transform="translate(0,-308.26772)"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.509;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="path3428"
+ d="m 251.98568,878.63831 -14.02447,24.29109 h -28.04894 l -14.02447,-24.29109 14.02447,-24.2911 h 28.04894 z" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#rect5884"
+ id="use4252"
+ transform="rotate(60,268.29786,489.4515)"
+ width="100%"
+ height="100%" />
+ <rect
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.650794;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ id="rect4254"
+ width="5.3947482"
+ height="115.12564"
+ x="545.71014"
+ y="467.07007"
+ transform="rotate(30,575.23539,-154.13386)" />
+ </g>
+ </g>
+ <g
+ id="layer3"
+ style="display:inline;opacity:1"
+ transform="translate(-156.33871,933.1905)">
+ <path
+ id="path3336-6"
+ d="m 309.54892,-710.38827 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -9.30079,-0.004 -18.60158,-0.007 -27.90237,-0.011 -4.76362,-8.22987 -9.52724,-16.45973 -14.29086,-24.6896 15.60349,-26.83003 31.20698,-53.66007 46.81047,-80.4901 -11.07649,-19.27523 -22.15297,-38.55047 -33.22946,-57.8257 9.35083,-16.29387 18.70167,-32.58775 28.0525,-48.88162 z"
+ style="opacity:1;fill:url(#linearGradient4328);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <use
+ height="100%"
+ width="100%"
+ transform="rotate(60,407.11155,-715.78724)"
+ id="use3439-6"
+ xlink:href="#path3336-6"
+ y="0"
+ x="0" />
+ <use
+ height="100%"
+ width="100%"
+ transform="rotate(-60,407.31177,-715.70016)"
+ id="use3445-0"
+ xlink:href="#path3336-6"
+ y="0"
+ x="0" />
+ <use
+ height="100%"
+ width="100%"
+ transform="rotate(180,407.41868,-715.7565)"
+ id="use3449-5"
+ xlink:href="#path3336-6"
+ y="0"
+ x="0" />
+ <path
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient4330);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m 309.54892,-710.38827 c 40.73228,70.55837 81.46455,141.11675 122.19683,211.67512 -18.71902,0.1756 -37.43804,0.3512 -56.15706,0.5268 -10.87453,-18.9564 -21.74907,-37.9128 -32.6236,-56.8692 -10.95215,18.8551 -21.9043,37.7102 -32.85645,56.5653 -10.54113,-2.26829 -26.58606,6.01638 -31.9377,-7.5219 -4.39393,-6.91787 -12.57856,-15.53043 -6.85074,-23.97221 8.26178,-12.05394 14.90093,-25.28023 22.52611,-37.79439 6.95986,-11.9674 13.91971,-23.9348 20.87957,-35.9022 -11.07649,-19.2752 -22.15297,-38.5504 -33.22946,-57.8256 9.35083,-16.29391 18.70167,-32.58781 28.0525,-48.88172 z"
+ id="path4260-0" />
+ <use
+ height="100%"
+ width="100%"
+ transform="rotate(120,407.33916,-716.08356)"
+ id="use4354-5"
+ xlink:href="#path4260-0"
+ y="0"
+ x="0"
+ style="display:inline" />
+ <use
+ height="100%"
+ width="100%"
+ transform="rotate(-120,407.28823,-715.86995)"
+ id="use4362-2"
+ xlink:href="#path4260-0"
+ y="0"
+ x="0"
+ style="display:inline" />
+ </g>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/osk.svg b/linux/home/.config/ags/assets/osk.svg
new file mode 100644
index 0000000..511420a
--- /dev/null
+++ b/linux/home/.config/ags/assets/osk.svg
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="24"
+ height="24"
+ version="1"
+ id="svg20"
+ sodipodi:docname="osk.svg"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs20" />
+ <sodipodi:namedview
+ id="namedview20"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="26.166667"
+ inkscape:cx="12"
+ inkscape:cy="12"
+ inkscape:current-layer="svg20" />
+ <rect
+ style="fill:#4f4f4f;stroke-width:0.871697"
+ width="11.938859"
+ height="17.820761"
+ x="-18.006235"
+ y="-20.910379"
+ rx="0.85277563"
+ ry="0.891038"
+ transform="matrix(0,-1,-1,0,0,0)"
+ id="rect1" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="m 9.3268859,13.31597 a 0.89103802,0.85277564 0 0 1 -0.891038,0.852775 0.89103802,0.85277564 0 0 1 -0.891038,-0.852775 0.89103802,0.85277564 0 0 1 0.891038,-0.852776 0.89103802,0.85277564 0 0 1 0.891038,0.852776 z"
+ id="path1" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="M 12,13.31597 A 0.89103802,0.85277564 0 0 1 11.108962,14.168745 0.89103802,0.85277564 0 0 1 10.217924,13.31597 0.89103802,0.85277564 0 0 1 11.108962,12.463194 0.89103802,0.85277564 0 0 1 12,13.31597 Z"
+ id="path2" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="m 14.673114,13.31597 a 0.89103802,0.85277564 0 0 1 -0.891038,0.852775 0.89103802,0.85277564 0 0 1 -0.891038,-0.852775 0.89103802,0.85277564 0 0 1 0.891038,-0.852776 0.89103802,0.85277564 0 0 1 0.891038,0.852776 z"
+ id="path3" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="M 17.346228,13.31597 A 0.89103802,0.85277564 0 0 1 16.45519,14.168745 0.89103802,0.85277564 0 0 1 15.564152,13.31597 0.89103802,0.85277564 0 0 1 16.45519,12.463194 0.89103802,0.85277564 0 0 1 17.346228,13.31597 Z"
+ id="path4" />
+ <rect
+ style="opacity:0.2;stroke-width:0.871697"
+ width="12.474532"
+ height="1.7055513"
+ x="5.7627339"
+ y="15.874296"
+ rx="0.41611475"
+ ry="0.42638782"
+ id="rect4" />
+ <rect
+ style="fill:#e4e4e4;stroke-width:0.871697"
+ width="12.474532"
+ height="1.7055513"
+ x="5.7627339"
+ y="15.447908"
+ rx="0.41611475"
+ ry="0.42638782"
+ id="rect5" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="M 15.564152,9.904867 A 0.89103802,0.85277564 0 0 1 14.673114,10.757643 0.89103802,0.85277564 0 0 1 13.782076,9.904867 0.89103802,0.85277564 0 0 1 14.673114,9.0520913 0.89103802,0.85277564 0 0 1 15.564152,9.904867 Z"
+ id="path5" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="M 7.5448099,9.904867 A 0.89103802,0.85277564 0 0 1 6.6537719,10.757643 0.89103802,0.85277564 0 0 1 5.7627339,9.904867 0.89103802,0.85277564 0 0 1 6.6537719,9.0520913 0.89103802,0.85277564 0 0 1 7.5448099,9.904867 Z"
+ id="path6" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="M 10.217924,9.904867 A 0.89103802,0.85277564 0 0 1 9.3268859,10.757643 0.89103802,0.85277564 0 0 1 8.4358479,9.904867 0.89103802,0.85277564 0 0 1 9.3268859,9.0520913 0.89103802,0.85277564 0 0 1 10.217924,9.904867 Z"
+ id="path7" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="M 12.891038,9.904867 A 0.89103802,0.85277564 0 0 1 12,10.757643 0.89103802,0.85277564 0 0 1 11.108962,9.904867 0.89103802,0.85277564 0 0 1 12,9.0520913 0.89103802,0.85277564 0 0 1 12.891038,9.904867 Z"
+ id="path8" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="M 18.237266,9.904867 A 0.89103802,0.85277564 0 0 1 17.346228,10.757643 0.89103802,0.85277564 0 0 1 16.45519,9.904867 0.89103802,0.85277564 0 0 1 17.346228,9.0520913 0.89103802,0.85277564 0 0 1 18.237266,9.904867 Z"
+ id="path9" />
+ <g
+ style="fill:#e4e4e4"
+ id="g18"
+ transform="matrix(0.89103802,0,0,0.85277564,1.3075438,1.8034984)">
+ <path
+ d="M 9,13 A 1,1 0 0 1 8,14 1,1 0 0 1 7,13 1,1 0 0 1 8,12 1,1 0 0 1 9,13 Z"
+ id="path10" />
+ <path
+ d="m 12,13 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
+ id="path11" />
+ <path
+ d="m 15,13 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
+ id="path12" />
+ <path
+ d="m 18,13 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
+ id="path13" />
+ <path
+ d="m 16,9 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
+ id="path14" />
+ <path
+ d="M 7,9 A 1,1 0 0 1 6,10 1,1 0 0 1 5,9 1,1 0 0 1 6,8 1,1 0 0 1 7,9 Z"
+ id="path15" />
+ <path
+ d="M 10,9 A 1,1 0 0 1 9,10 1,1 0 0 1 8,9 1,1 0 0 1 9,8 1,1 0 0 1 10,9 Z"
+ id="path16" />
+ <path
+ d="m 13,9 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
+ id="path17" />
+ <path
+ d="m 19,9 a 1,1 0 0 1 -1,1 1,1 0 0 1 -1,-1 1,1 0 0 1 1,-1 1,1 0 0 1 1,1 z"
+ id="path18" />
+ </g>
+ <path
+ style="opacity:0.1;fill:#ffffff;stroke-width:0.871697"
+ d="m 3.9806578,6.0673766 c -0.493635,0 -0.891038,0.3803379 -0.891038,0.8527756 v 0.4263879 c 0,-0.4724377 0.397403,-0.8527757 0.891038,-0.8527757 H 20.019342 c 0.493635,0 0.891038,0.380338 0.891038,0.8527757 V 6.9201522 c 0,-0.4724377 -0.397403,-0.8527756 -0.891038,-0.8527756 z"
+ id="path19" />
+ <path
+ style="opacity:0.2;stroke-width:0.871697"
+ d="m 3.0896198,17.15346 v 0.426388 c 0,0.472437 0.397403,0.852775 0.891038,0.852775 H 20.019342 c 0.493635,0 0.891038,-0.380338 0.891038,-0.852775 V 17.15346 c 0,0.472438 -0.397403,0.852776 -0.891038,0.852776 H 3.9806578 c -0.493635,0 -0.891038,-0.380338 -0.891038,-0.852776 z"
+ id="path20" />
+</svg>
diff --git a/linux/home/.config/ags/assets/pinned.svg b/linux/home/.config/ags/assets/pinned.svg
new file mode 100644
index 0000000..ce8efb3
--- /dev/null
+++ b/linux/home/.config/ags/assets/pinned.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ viewBox="0 0 22 22"
+ version="1.1"
+ id="svg1"
+ sodipodi:docname="pinned.svg"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview1"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="21.454545"
+ inkscape:cx="11"
+ inkscape:cy="11"
+ inkscape:current-layer="svg1" />
+ <defs
+ id="defs3051">
+ <style
+ type="text/css"
+ id="current-color-scheme">.ColorScheme-Text { color: #fcfcfc; } </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none;stroke-width:0.906415"
+ d="m 11,3.7453986 c -4.015418,0 -7.2480469,3.2355522 -7.2480469,7.2546014 0,4.019049 3.2326289,7.254601 7.2480469,7.254601 4.015418,0 7.248047,-3.235552 7.248047,-7.254601 0,-4.0190492 -3.232629,-7.2546014 -7.248047,-7.2546014 z m 0,0.9068251 c 3.513491,0 6.342041,2.8311083 6.342041,6.3477763 0,3.516668 -2.82855,6.347776 -6.342041,6.347776 C 7.4865093,17.347776 4.657959,14.516668 4.657959,11 4.657959,7.483332 7.4865093,4.6522237 11,4.6522237 Z m 0,4.5341259 c -1.0038533,0 -1.8120117,0.8088893 -1.8120117,1.8136504 0,1.004761 0.8081584,1.81365 1.8120117,1.81365 1.003854,0 1.812012,-0.808889 1.812012,-1.81365 0,-1.0047611 -0.808158,-1.8136504 -1.812012,-1.8136504 z m 0,0.9068254 c 0.501926,0 0.906006,0.404445 0.906006,0.906825 0,0.50238 -0.40408,0.906825 -0.906006,0.906825 -0.501926,0 -0.906006,-0.404445 -0.906006,-0.906825 0,-0.50238 0.40408,-0.906825 0.906006,-0.906825 z"
+ class="ColorScheme-Text"
+ id="path1" />
+</svg>
diff --git a/linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg b/linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg
new file mode 100644
index 0000000..4461454
--- /dev/null
+++ b/linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg
@@ -0,0 +1,321 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ height="16px"
+ viewBox="0 0 16 16"
+ width="16px"
+ version="1.1"
+ id="svg3533"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <defs
+ id="defs3537" />
+ <filter
+ id="a"
+ height="1"
+ width="1"
+ x="0"
+ y="0">
+ <feColorMatrix
+ in="SourceGraphic"
+ type="matrix"
+ values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"
+ id="feColorMatrix3414" />
+ </filter>
+ <mask
+ id="b">
+ <g
+ filter="url(#a)"
+ id="g3419">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwcB8GZcBWQFEIoq/qy3b9Y8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQdi/bMl/PXorsAAADAA+ffDwAAAAD7CQAAAAAQIAAAAABAgAAAAAAAAQIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8dQMXagEYjYWofQAAAABJRU5ErkJggg=="
+ id="image3417" />
+ </g>
+ </mask>
+ <clipPath
+ id="c">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3422" />
+ </clipPath>
+ <mask
+ id="d">
+ <g
+ filter="url(#a)"
+ id="g3427">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
+ id="image3425" />
+ </g>
+ </mask>
+ <clipPath
+ id="e">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3430" />
+ </clipPath>
+ <mask
+ id="f">
+ <g
+ filter="url(#a)"
+ id="g3435">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
+ id="image3433" />
+ </g>
+ </mask>
+ <clipPath
+ id="g">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3438" />
+ </clipPath>
+ <mask
+ id="h">
+ <g
+ filter="url(#a)"
+ id="g3443">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
+ id="image3441" />
+ </g>
+ </mask>
+ <clipPath
+ id="i">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3446" />
+ </clipPath>
+ <mask
+ id="j">
+ <g
+ filter="url(#a)"
+ id="g3451">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
+ id="image3449" />
+ </g>
+ </mask>
+ <clipPath
+ id="k">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3454" />
+ </clipPath>
+ <mask
+ id="l">
+ <g
+ filter="url(#a)"
+ id="g3459">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
+ id="image3457" />
+ </g>
+ </mask>
+ <clipPath
+ id="m">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3462" />
+ </clipPath>
+ <mask
+ id="n">
+ <g
+ filter="url(#a)"
+ id="g3467">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwUCd/SdlAFYAkYji72rLdv1jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBx6I98+X8teguAAAA8MD59wMAAADAfgIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAECAAAAAAAABAgAAAAAECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX90LagEYFVKkEwAAAABJRU5ErkJggg=="
+ id="image3465" />
+ </g>
+ </mask>
+ <clipPath
+ id="o">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3470" />
+ </clipPath>
+ <mask
+ id="p">
+ <g
+ filter="url(#a)"
+ id="g3475">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMr0lEQVR4nO3YsQ2AMAwAwcB8GZcBWQFEIoq/qy3b9Y8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQdi/bMl/PXorsAAADAA+ffDwAAAAD7CQAAAAAQIAAAAABAgAAAAAAAAQIAAAAABAgAAAAAECAAAAAAQIAAAAAAAAECAAAAAAQIAAAAABAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8dQMXagEYjYWofQAAAABJRU5ErkJggg=="
+ id="image3473" />
+ </g>
+ </mask>
+ <clipPath
+ id="q">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3478" />
+ </clipPath>
+ <mask
+ id="r">
+ <g
+ filter="url(#a)"
+ id="g3483">
+ <image
+ height="800"
+ width="1024"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAMgCAYAAAC9FhA7AAAABmJLR0QA/wD/AP+gvaeTAAAMqUlEQVR4nO3YsQ3AMAwEMSeTe/QM4QgujqwF4etbCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIen76s4fvAQAAgAPv7QEAAADAPAEAAAAAAgQAAAAACBAAAAAAIEAAAAAAgAABAAAAAAIEAAAAAAgQAAAAACBAAAAAAIAAAQAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAUx8hKgEYqUBSPgAAAABJRU5ErkJggg=="
+ id="image3481" />
+ </g>
+ </mask>
+ <clipPath
+ id="s">
+ <path
+ d="m 0 0 h 1024 v 800 h -1024 z"
+ id="path3486" />
+ </clipPath>
+ <path
+ d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 10 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -0.570312 -0.167969 -1.101562 -0.449219 -1.558594 l -1.550781 1.554688 v 6.003906 c 0 0.570312 -0.429688 1 -1 1 h -10 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.570312 0.429688 -1 1 -1 h 5.96875 l 2.007812 -2 z m 0 0"
+ fill="#2e3436"
+ id="path3489"
+ style="fill:#000000" />
+ <g
+ clip-path="url(#c)"
+ mask="url(#b)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3493"
+ style="fill:#000000">
+ <path
+ d="m 439.105469 225.78125 h 7.839843 c -0.890624 0.371094 -0.972656 1.847656 0 2.25 h -7.839843 z m 0 0"
+ fill="#2e3436"
+ id="path3491"
+ style="fill:#000000" />
+ </g>
+ <g
+ clip-path="url(#e)"
+ mask="url(#d)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3497"
+ style="fill:#000000">
+ <path
+ d="m 29.25 627.75 h 0.75 v 0.75 h -0.75 z m 0 0"
+ fill="#2e3436"
+ fill-rule="evenodd"
+ id="path3495"
+ style="fill:#000000" />
+ </g>
+ <g
+ clip-path="url(#g)"
+ mask="url(#f)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3501"
+ style="fill:#000000">
+ <path
+ d="m 30 627 h 0.75 v 0.75 h -0.75 z m 0 0"
+ fill="#2e3436"
+ fill-rule="evenodd"
+ id="path3499"
+ style="fill:#000000" />
+ </g>
+ <g
+ clip-path="url(#i)"
+ mask="url(#h)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3505"
+ style="fill:#000000">
+ <path
+ d="m 30.75 629.25 h 0.75 v 0.75 h -0.75 z m 0 0"
+ fill="#2e3436"
+ fill-rule="evenodd"
+ id="path3503"
+ style="fill:#000000" />
+ </g>
+ <g
+ clip-path="url(#k)"
+ mask="url(#j)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3509"
+ style="fill:#000000">
+ <path
+ d="m 29.25 629.25 h 0.75 v 0.75 h -0.75 z m 0 0"
+ fill="#2e3436"
+ fill-rule="evenodd"
+ id="path3507"
+ style="fill:#000000" />
+ </g>
+ <g
+ clip-path="url(#m)"
+ mask="url(#l)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3513"
+ style="fill:#000000">
+ <path
+ d="m 30 630 h 0.75 v 0.75 h -0.75 z m 0 0"
+ fill="#2e3436"
+ fill-rule="evenodd"
+ id="path3511"
+ style="fill:#000000" />
+ </g>
+ <g
+ clip-path="url(#o)"
+ mask="url(#n)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3517"
+ style="fill:#000000">
+ <path
+ d="m 31.5 630 h 0.75 v 0.75 h -0.75 z m 0 0"
+ fill="#2e3436"
+ fill-rule="evenodd"
+ id="path3515"
+ style="fill:#000000" />
+ </g>
+ <g
+ clip-path="url(#q)"
+ mask="url(#p)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3521"
+ style="fill:#000000">
+ <path
+ d="m 119.253906 648.75 v 5.25 h 5.25 v -5.25 z m 0 0"
+ fill="#2e3436"
+ id="path3519"
+ style="fill:#000000" />
+ </g>
+ <path
+ d="m 11 7 c 0 1.65625 -1.339844 3.007812 -3 3 h -3 v -3 c 0 -1.660156 1.34375 -3 3 -3 c 1.660156 0 3 1.339844 3 3 z m 0 0"
+ fill="#2e3436"
+ id="path3523"
+ style="fill:#000000" />
+ <path
+ d="m 13.398438 0 l -3.46875 3.457031 c 0.683593 0.355469 1.234374 0.910157 1.589843 1.589844 l 0.171875 -0.171875 l 0.007813 0.007812 l 4.300781 -4.300781 v -0.582031 z m 0 0"
+ fill="#2e3436"
+ id="path3525"
+ style="fill:#000000" />
+ <g
+ clip-path="url(#s)"
+ mask="url(#r)"
+ transform="matrix(1 0 0 1 -40 -620)"
+ id="g3529"
+ style="fill:#000000">
+ <path
+ d="m 181.503906 635.25 h 2.25 v 9 h -2.25 z m 0 0"
+ fill="#2e3436"
+ id="path3527"
+ style="fill:#000000" />
+ </g>
+ <path
+ d="m 5 14 c -1.105469 0 -2 0.894531 -2 2 h 10 c 0 -1.105469 -0.894531 -2 -2 -2 z m 0 0"
+ fill="#2e3436"
+ id="path3531"
+ style="fill:#000000" />
+</svg>
diff --git a/linux/home/.config/ags/assets/processor-symbolic.svg b/linux/home/.config/ags/assets/processor-symbolic.svg
new file mode 100644
index 0000000..832dbaf
--- /dev/null
+++ b/linux/home/.config/ags/assets/processor-symbolic.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 5 5 h 6 v 6 h -6 z m 0 0"/>
+ <path d="m 13 5 h 3 v 1 h -3 z m 0 0"/>
+ <path d="m 13 7 h 3 v 1 h -3 z m 0 0"/>
+ <path d="m 13 9 h 3 v 1 h -3 z m 0 0"/>
+ <path d="m 0 6 h 3 v 1 h -3 z m 0 0"/>
+ <path d="m 0 8 h 3 v 1 h -3 z m 0 0"/>
+ <path d="m 0 10 h 3 v 1 h -3 z m 0 0"/>
+ <path d="m 5 0 h 1 v 3 h -1 z m 0 0"/>
+ <path d="m 7 0 h 1 v 3 h -1 z m 0 0"/>
+ <path d="m 9 0 h 1 v 3 h -1 z m 0 0"/>
+ <path d="m 10 13 h 1 v 3 h -1 z m 0 0"/>
+ <path d="m 8 13 h 1 v 3 h -1 z m 0 0"/>
+ <path d="m 6 13 h 1 v 3 h -1 z m 0 0"/>
+ <path d="m 5 2 c -1.644531 0 -3 1.355469 -3 3 v 6 c 0 1.644531 1.355469 3 3 3 h 6 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -1.644531 -1.355469 -3 -3 -3 z m 0 2 h 6 c 0.570312 0 1 0.429688 1 1 v 6 c 0 0.570312 -0.429688 1 -1 1 h -6 c -0.570312 0 -1 -0.429688 -1 -1 v -6 c 0 -0.570312 0.429688 -1 1 -1 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/rotation.svg b/linux/home/.config/ags/assets/rotation.svg
new file mode 100644
index 0000000..7ed7e34
--- /dev/null
+++ b/linux/home/.config/ags/assets/rotation.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <path style="fill:currentColor" class="ColorScheme-Text" d="M 1 1 L 1 10 L 7 10 L 7 5 L 9 5 C 10.108 5 11 5.89199 11 7 L 11 9 L 8 9 L 8 11 L 6 11 L 6 15 L 15 15 L 15 9 L 12 9 L 12 7 C 12 5.338 10.662 4 9 4 L 7 4 L 7 1 L 1 1 z" transform="translate(4 4)"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/swapnext.svg b/linux/home/.config/ags/assets/swapnext.svg
new file mode 100644
index 0000000..0690cb9
--- /dev/null
+++ b/linux/home/.config/ags/assets/swapnext.svg
@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <path style="fill:currentColor" class="ColorScheme-Text" d="M 3 1 C 1.892 1 1 1.892 1 3 L 1 13 C 1 14.108 1.892 15 3 15 L 13 15 C 14.108 15 15 14.108 15 13 L 15 3 C 15 1.892 14.108 1 13 1 L 3 1 z M 3 3 L 13 3 L 13 13 L 3 13 L 3 3 z M 5 4 A 1 1 0 0 0 4 5 A 1 1 0 0 0 5 6 A 1 1 0 0 0 6 5 A 1 1 0 0 0 5 4 z M 11 4 A 1 1 0 0 0 10 5 A 1 1 0 0 0 11 6 A 1 1 0 0 0 12 5 A 1 1 0 0 0 11 4 z M 8 7 A 1 1 0 0 0 7 8 A 1 1 0 0 0 8 9 A 1 1 0 0 0 9 8 A 1 1 0 0 0 8 7 z M 5 10 A 1 1 0 0 0 4 11 A 1 1 0 0 0 5 12 A 1 1 0 0 0 6 11 A 1 1 0 0 0 5 10 z M 11 10 A 1 1 0 0 0 10 11 A 1 1 0 0 0 11 12 A 1 1 0 0 0 12 11 A 1 1 0 0 0 11 10 z" transform="translate(4 4)"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/tbox-close.svg b/linux/home/.config/ags/assets/tbox-close.svg
new file mode 100644
index 0000000..f325d3c
--- /dev/null
+++ b/linux/home/.config/ags/assets/tbox-close.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="24"
+ height="24"
+ version="1.1"
+ id="svg1"
+ sodipodi:docname="tbox-close.svg"
+ xml:space="preserve"
+ inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
+ id="namedview1"
+ pagecolor="#ffffff"
+ bordercolor="#000000"
+ borderopacity="0.25"
+ inkscape:showpageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1"
+ inkscape:zoom="26.708333"
+ inkscape:cx="11.981279"
+ inkscape:cy="11.981279"
+ inkscape:current-layer="svg1" /><defs
+ id="defs1"><style
+ id="current-color-scheme"
+ type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style></defs><g
+ id="g2"
+ transform="matrix(0.43167414,0,0,0.42254065,1.6211,1.3192164)"><path
+ style="opacity:0.2"
+ d="m 34.158694,7.001891 c -2.339941,-0.051114 -4.593769,0.9363666 -6.144072,2.6910582 -0.0012,0.0014 -0.0027,0.0025 -0.0039,0.0039 l -4.015616,4.4240828 -4.01174,-4.4162958 c -1.424465,-1.6183716 -3.450682,-2.592914 -5.603207,-2.6949526 -0.260519,-0.012616 -0.51772,-0.013001 -0.778224,0 a 5.977352,5.9824591 0 0 0 -0.01945,0 C 7.2433432,7.3455998 3.8467314,15.780704 8.1816032,20.422133 L 13.224489,25.975605 8.2594255,31.4434 c -1.5192901,1.580887 -2.4400962,4.078962 -2.2296097,6.266155 0.2104868,2.187194 1.2500876,3.924619 2.6187213,5.167923 1.3686339,1.243304 3.1976469,2.112373 5.3930859,2.110788 2.19544,-0.0016 4.590268,-1.161185 6.015666,-2.827365 l 3.937809,-4.330618 4.054544,4.463029 -0.147863,-0.167461 c 1.418645,1.683037 3.819828,2.866353 6.02734,2.874097 2.20751,0.0078 4.047562,-0.863731 5.420324,-2.110787 1.372761,-1.247055 2.417086,-2.995369 2.622612,-5.195185 0.205525,-2.199813 -0.739595,-4.705945 -2.276302,-6.281731 l -4.933937,-5.43664 5.050669,-5.561261 c 2.191468,-2.3538 2.626913,-5.893796 1.513644,-8.536614 C 40.212861,9.2349127 37.376326,7.0748944 34.162585,7.001891 a 5.977352,5.9824591 0 0 0 -0.0039,0 z"
+ id="path1-3" /><path
+ style="fill:#4f4f4f"
+ d="m 34.158694,6.0018906 c -2.339941,-0.051114 -4.593769,0.9363666 -6.144072,2.6910586 -0.0012,0.00139 -0.0027,0.0025 -0.0039,0.0039 L 23.995106,13.120932 19.983366,8.7046361 C 18.558901,7.0862642 16.532684,6.1117218 14.380159,6.0096832 c -0.260519,-0.012616 -0.51772,-0.013001 -0.778224,0 a 5.977352,5.9824591 0 0 0 -0.01945,0 C 7.2433432,6.3455994 3.8467314,14.780704 8.1816032,19.422133 L 13.224489,24.975605 8.2594255,30.4434 c -1.5192901,1.580887 -2.4400962,4.078962 -2.2296097,6.266155 0.2104868,2.187194 1.2500876,3.924619 2.6187213,5.167923 1.3686339,1.243304 3.1976469,2.112373 5.3930859,2.110788 2.19544,-0.0016 4.590268,-1.161185 6.015666,-2.827365 l 3.937809,-4.330618 4.054544,4.463029 -0.147863,-0.167461 c 1.418645,1.683037 3.819828,2.866353 6.02734,2.874097 2.20751,0.0078 4.047562,-0.863731 5.420324,-2.110787 1.372761,-1.247055 2.417086,-2.995369 2.622612,-5.195185 0.205525,-2.199813 -0.739595,-4.705945 -2.276302,-6.281731 l -4.933937,-5.43664 5.050669,-5.561261 c 2.191468,-2.3538 2.626913,-5.893796 1.513644,-8.536614 C 40.212861,8.2349123 37.376326,6.074894 34.162585,6.0018906 a 5.977352,5.9824591 0 0 0 -0.0039,0 z"
+ id="path2" /><path
+ style="opacity:0.2"
+ d="m 13.875,12.980111 a 2.0002,2.0002 0 0 0 -1.355469,3.363282 l 8.789063,9.667968 -8.769532,9.644532 A 2.0002,2.0002 0 1 0 15.5,38.343393 l 8.507812,-9.359374 8.51172,9.359374 a 2.0006762,2.0006762 0 1 0 2.960936,-2.6875 L 26.710938,26.011361 35.5,16.343393 a 2.0002,2.0002 0 0 0 -1.417968,-3.363282 2.0002,2.0002 0 0 0 -1.54297,0.675782 l -8.53125,9.382812 -8.527343,-9.382812 a 2.0002,2.0002 0 0 0 -1.40625,-0.675782 2.0002,2.0002 0 0 0 -0.199219,0 z"
+ id="path3" /><path
+ style="fill:#ffffff"
+ transform="scale(2)"
+ d="M 6.9375,5.9902344 A 1.0001,1.0001 0 0 0 6.2597656,7.671875 l 4.3945314,4.833984 -4.3847658,4.822266 A 1.0001,1.0001 0 1 0 7.75,18.671875 l 4.253906,-4.679687 4.25586,4.679687 a 1.0003381,1.0003381 0 1 0 1.480468,-1.34375 L 13.355469,12.505859 17.75,7.671875 A 1.0001,1.0001 0 0 0 17.041016,5.9902344 1.0001,1.0001 0 0 0 16.269531,6.328125 L 12.003906,11.019531 7.7402344,6.328125 a 1.0001,1.0001 0 0 0 -0.703125,-0.3378906 1.0001,1.0001 0 0 0 -0.099609,0 z"
+ id="path4" /><path
+ style="opacity:0.2;fill:#ffffff"
+ transform="scale(2)"
+ d="m 17.080078,3 c -1.16997,-0.025557 -2.297114,0.4683571 -3.072266,1.3457031 0,0 -0.002,0.00195 -0.002,0.00195 L 11.998047,6.5605469 9.9921875,4.3515625 C 9.279955,3.5423765 8.2657156,3.0549255 7.1894531,3.0039062 c -0.1302595,-0.00631 -0.2584199,-0.0065 -0.3886719,0 a 2.988676,2.9912295 0 0 0 -0.00977,0 C 4.516087,3.1244563 3.008504,5.3315905 3.1347612,7.4257812 3.2542394,5.4946775 4.6972247,3.6148577 6.7910112,3.5039062 a 2.988676,2.9912295 0 0 1 0.00977,0 c 0.130252,-0.0065 0.2584124,-0.00631 0.3886719,0 1.0762625,0.051019 2.0905019,0.5384705 2.8027344,1.3476563 l 2.0058595,2.2089844 2.007812,-2.2128907 c 0,0 0.002,-0.00195 0.002,-0.00195 C 14.782964,3.9683573 15.910108,3.474443 17.080078,3.5 a 2.988676,2.9912295 0 0 0 0.002,0 c 1.606871,0.036502 3.023444,1.1180442 3.580078,2.4394531 0.16598,0.3940229 0.255721,0.8292143 0.28125,1.2753907 0.03853,-0.6193247 -0.05357,-1.2348847 -0.28125,-1.7753907 C 20.105475,4.1180443 18.688902,3.0365017 17.082031,3 a 2.988676,2.9912295 0 0 0 -0.002,0 z M 6.3847656,12.738281 4.1289062,15.222656 c -0.7462708,0.776527 -1.199139,1.994686 -1.1152343,3.074219 0.063557,-0.939898 0.4824865,-1.915817 1.1152343,-2.574219 l 2.4824219,-2.734375 z m 11.2226564,0 -0.226563,0.25 2.466797,2.71875 c 0.646214,0.662647 1.079159,1.652595 1.140625,2.605469 0.08979,-1.091494 -0.380318,-2.325827 -1.140625,-3.105469 z"
+ id="path5" /></g></svg>
diff --git a/linux/home/.config/ags/assets/terminal-symbolic.svg b/linux/home/.config/ags/assets/terminal-symbolic.svg
new file mode 100644
index 0000000..9f82bcf
--- /dev/null
+++ b/linux/home/.config/ags/assets/terminal-symbolic.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 2.199219 0 c -1.207031 0 -2.199219 1.007812 -2.199219 2.207031 v 10.585938 c 0 1.199219 0.992188 2.207031 2.199219 2.207031 h 11.601562 c 1.207031 0 2.199219 -1.007812 2.199219 -2.207031 v -10.585938 c 0 -1.199219 -0.992188 -2.207031 -2.199219 -2.207031 z m 0 2 h 11.601562 c 0.121094 0 0.199219 0.070312 0.199219 0.207031 v 10.585938 c 0 0.136719 -0.078125 0.207031 -0.199219 0.207031 h -11.601562 c -0.121094 0 -0.199219 -0.070312 -0.199219 -0.207031 v -10.585938 c 0 -0.136719 0.078125 -0.207031 0.199219 -0.207031 z m 0 0"/>
+ <path d="m 4.515625 5.898438 c -0.164063 -0.003907 -0.324219 0.0625 -0.441406 0.175781 c -0.230469 0.234375 -0.230469 0.617187 0 0.851562 l 1.578125 1.574219 l -1.578125 1.574219 c -0.230469 0.234375 -0.230469 0.617187 0 0.851562 c 0.234375 0.230469 0.617187 0.230469 0.851562 0 l 2 -2 c 0.230469 -0.234375 0.230469 -0.617187 0 -0.851562 l -2 -2 c -0.109375 -0.105469 -0.257812 -0.167969 -0.410156 -0.175781 z m 3.484375 4.101562 v 1 h 3 v -1 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/togglesplit.svg b/linux/home/.config/ags/assets/togglesplit.svg
new file mode 100644
index 0000000..15d5011
--- /dev/null
+++ b/linux/home/.config/ags/assets/togglesplit.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" version="1.1">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g transform="translate(4,4)">
+ <path style="fill:currentColor" class="ColorScheme-Text" d="M 1,1 V 10 H 5 V 5 H 10 V 1 Z M 6,6 H 15 V 15 H 6 Z"/>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/toolbars-symbolic.svg b/linux/home/.config/ags/assets/toolbars-symbolic.svg
new file mode 100644
index 0000000..9f4c564
--- /dev/null
+++ b/linux/home/.config/ags/assets/toolbars-symbolic.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
+ <path d="m 2 0 c -1.214844 0 -2 0.828125 -2 2 v 12 c 0 1 1 2 2 2 h 11.984375 c 1 0 2 -1 2 -2 v -12 c 0 -1.238281 -0.828125 -2 -2 -2 z m 0 2 h 2 v 2 h -2 z m 3 0 h 2 v 2 h -2 z m 3 0 h 2 v 2 h -2 z m -6 4 h 11.984375 v 8 h -11.984375 z m 0 0"/>
+</svg>
diff --git a/linux/home/.config/ags/assets/wp-next.svg b/linux/home/.config/ags/assets/wp-next.svg
new file mode 100644
index 0000000..ac0245d
--- /dev/null
+++ b/linux/home/.config/ags/assets/wp-next.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" version="1.1">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g transform="translate(4,4)">
+ <path style="fill:currentColor" class="ColorScheme-Text" d="M 3,2 V 14 L 14,8 Z"/>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/assets/wp-prev.svg b/linux/home/.config/ags/assets/wp-prev.svg
new file mode 100644
index 0000000..12ed8dd
--- /dev/null
+++ b/linux/home/.config/ags/assets/wp-prev.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" version="1.1">
+ <defs>
+ <style id="current-color-scheme" type="text/css">
+ .ColorScheme-Text { color:#dfdfdf; } .ColorScheme-Highlight { color:#4285f4; } .ColorScheme-NeutralText { color:#ff9800; } .ColorScheme-PositiveText { color:#4caf50; } .ColorScheme-NegativeText { color:#f44336; }
+ </style>
+ </defs>
+ <g transform="translate(4,4)">
+ <path style="fill:currentColor" class="ColorScheme-Text" d="M 13,2 2,8 13,14 Z"/>
+ </g>
+</svg>
diff --git a/linux/home/.config/ags/config.js b/linux/home/.config/ags/config.js
new file mode 100644
index 0000000..2864dec
--- /dev/null
+++ b/linux/home/.config/ags/config.js
@@ -0,0 +1,46 @@
+import GLib from "gi://GLib"
+
+const main = "/tmp/ags/main.js"
+const entry = `${App.configDir}/main.ts`
+const bundler = GLib.getenv("AGS_BUNDLER") || "bun"
+
+const v = {
+ ags: pkg.version?.split(".").map(Number) || [],
+ expect: [1, 8, 0],
+}
+
+try {
+ switch (bundler) {
+ case "bun": await Utils.execAsync([
+ "bun", "build", entry,
+ "--outfile", main,
+ "--external", "resource://*",
+ "--external", "gi://*",
+ "--external", "file://*",
+ ]); break
+
+ case "esbuild": await Utils.execAsync([
+ "esbuild", "--bundle", entry,
+ "--format=esm",
+ `--outfile=${main}`,
+ "--external:resource://*",
+ "--external:gi://*",
+ "--external:file://*",
+ ]); break
+
+ default:
+ throw `"${bundler}" is not a valid bundler`
+ }
+
+ if (v.ags[1] < v.expect[1] || v.ags[2] < v.expect[2]) {
+ print(`my config needs at least v${v.expect.join(".")}, yours is v${v.ags.join(".")}`)
+ App.quit()
+ }
+
+ await import(`file://${main}`)
+} catch (error) {
+ console.error(error)
+ App.quit()
+}
+
+export { }
diff --git a/linux/home/.config/ags/default.nix b/linux/home/.config/ags/default.nix
new file mode 100644
index 0000000..f0e0c41
--- /dev/null
+++ b/linux/home/.config/ags/default.nix
@@ -0,0 +1,104 @@
+{
+ inputs,
+ writeShellScript,
+ system,
+ stdenv,
+ cage,
+ swww,
+ esbuild,
+ dart-sass,
+ fd,
+ fzf,
+ brightnessctl,
+ accountsservice,
+ slurp,
+ wf-recorder,
+ wl-clipboard,
+ wayshot,
+ swappy,
+ hyprpicker,
+ pavucontrol,
+ networkmanager,
+ gtk3,
+ which,
+}: let
+ name = "asztal";
+
+ ags = inputs.ags.packages.${system}.default.override {
+ extraPackages = [accountsservice];
+ };
+
+ dependencies = [
+ which
+ dart-sass
+ fd
+ fzf
+ brightnessctl
+ swww
+ inputs.matugen.packages.${system}.default
+ inputs.hyprland.packages.${system}.default
+ slurp
+ wf-recorder
+ wl-clipboard
+ wayshot
+ swappy
+ hyprpicker
+ pavucontrol
+ networkmanager
+ gtk3
+ ];
+
+ addBins = list: builtins.concatStringsSep ":" (builtins.map (p: "${p}/bin") list);
+
+ greeter = writeShellScript "greeter" ''
+ export PATH=$PATH:${addBins dependencies}
+ ${cage}/bin/cage -ds -m last ${ags}/bin/ags -- -c ${config}/greeter.js
+ '';
+
+ desktop = writeShellScript name ''
+ export PATH=$PATH:${addBins dependencies}
+ ${ags}/bin/ags -b ${name} -c ${config}/config.js $@
+ '';
+
+ config = stdenv.mkDerivation {
+ inherit name;
+ src = ./.;
+
+ buildPhase = ''
+ ${esbuild}/bin/esbuild \
+ --bundle ./main.ts \
+ --outfile=main.js \
+ --format=esm \
+ --external:resource://\* \
+ --external:gi://\* \
+
+ ${esbuild}/bin/esbuild \
+ --bundle ./greeter/greeter.ts \
+ --outfile=greeter.js \
+ --format=esm \
+ --external:resource://\* \
+ --external:gi://\* \
+ '';
+
+ installPhase = ''
+ mkdir -p $out
+ cp -r assets $out
+ cp -r style $out
+ cp -r greeter $out
+ cp -r widget $out
+ cp -f main.js $out/config.js
+ cp -f greeter.js $out/greeter.js
+ '';
+ };
+in
+ stdenv.mkDerivation {
+ inherit name;
+ src = config;
+
+ installPhase = ''
+ mkdir -p $out/bin
+ cp -r . $out
+ cp ${desktop} $out/bin/${name}
+ cp ${greeter} $out/bin/greeter
+ '';
+ }
diff --git a/linux/home/.config/ags/greeter.js b/linux/home/.config/ags/greeter.js
new file mode 100644
index 0000000..5c8e369
--- /dev/null
+++ b/linux/home/.config/ags/greeter.js
@@ -0,0 +1,18 @@
+const main = "/tmp/ags/greeter.js"
+const entry = `${App.configDir}/greeter/greeter.ts`
+
+try {
+ await Utils.execAsync([
+ "bun", "build", entry,
+ "--outfile", main,
+ "--external", "resource://*",
+ "--external", "gi://*",
+ "--external", "file://*",
+ ])
+ await import(`file://${main}`)
+} catch (error) {
+ console.error(error)
+ App.quit()
+}
+
+export { }
diff --git a/linux/home/.config/ags/greeter/auth.ts b/linux/home/.config/ags/greeter/auth.ts
new file mode 100644
index 0000000..23477eb
--- /dev/null
+++ b/linux/home/.config/ags/greeter/auth.ts
@@ -0,0 +1,109 @@
+import AccountsService from "gi://AccountsService?version=1.0"
+import GLib from "gi://GLib?version=2.0"
+import icons from "lib/icons"
+
+const { iconFile, realName, userName } = AccountsService.UserManager
+ .get_default().list_users()[0]
+
+const loggingin = Variable(false)
+
+const CMD = GLib.getenv("ASZTAL_DM_CMD")
+ || "Hyprland"
+
+const ENV = GLib.getenv("ASZTAL_DM_ENV")
+ || "WLR_NO_HARDWARE_CURSORS=1 _JAVA_AWT_WM_NONREPARENTING=1"
+
+async function login(pw: string) {
+ loggingin.value = true
+ const greetd = await Service.import("greetd")
+ return greetd.login(userName, pw, CMD, ENV.split(/\s+/))
+ .catch(res => {
+ loggingin.value = false
+ response.label = res?.description || JSON.stringify(res)
+ password.text = ""
+ revealer.reveal_child = true
+ })
+}
+
+const avatar = Widget.Box({
+ class_name: "avatar",
+ hpack: "center",
+ css: `background-image: url('${iconFile}')`,
+})
+
+const password = Widget.Entry({
+ placeholder_text: "Password",
+ hexpand: true,
+ visibility: false,
+ on_accept: ({ text }) => { login(text || "") },
+})
+
+const response = Widget.Label({
+ class_name: "response",
+ wrap: true,
+ max_width_chars: 35,
+ hpack: "center",
+ hexpand: true,
+ xalign: .5,
+})
+
+const revealer = Widget.Revealer({
+ transition: "slide_down",
+ child: response,
+})
+
+export default Widget.Box({
+ class_name: "auth",
+ attribute: { password },
+ vertical: true,
+ children: [
+ Widget.Overlay({
+ child: Widget.Box(
+ {
+ css: "min-width: 200px; min-height: 200px;",
+ vertical: true,
+ },
+ Widget.Box({
+ class_name: "wallpaper",
+ css: `background-image: url('${WALLPAPER}')`,
+ }),
+ Widget.Box({
+ class_name: "wallpaper-contrast",
+ vexpand: true,
+ }),
+ ),
+ overlay: Widget.Box(
+ {
+ vpack: "end",
+ vertical: true,
+ },
+ avatar,
+ Widget.Box({
+ hpack: "center",
+ children: [
+ Widget.Icon(icons.ui.avatar),
+ Widget.Label(realName || userName),
+ ],
+ }),
+ Widget.Box(
+ {
+ class_name: "password",
+ },
+ Widget.Spinner({
+ visible: loggingin.bind(),
+ active: true,
+ }),
+ Widget.Icon({
+ visible: loggingin.bind().as(b => !b),
+ icon: icons.ui.lock,
+ }),
+ password,
+ ),
+ ),
+ }),
+ Widget.Box(
+ { class_name: "response-box" },
+ revealer,
+ ),
+ ],
+})
diff --git a/linux/home/.config/ags/greeter/greeter.scss b/linux/home/.config/ags/greeter/greeter.scss
new file mode 100644
index 0000000..e3a5cd8
--- /dev/null
+++ b/linux/home/.config/ags/greeter/greeter.scss
@@ -0,0 +1,64 @@
+@import "../style/mixins/floating-widget.scss";
+@import "../style/mixins/widget.scss";
+@import "../style/mixins/spacing.scss";
+@import "../style/mixins/unset.scss";
+@import "../style/mixins/a11y-button.scss";
+@import "../widget/bar/bar.scss";
+
+window#greeter {
+ background-color: lighten($bg, 6%);
+ color: $fg;
+
+ .bar {
+ background-color: transparent;
+
+ .date {
+ @include unset($rec: true);
+ @include panel-button($flat: true, $reactive: false);
+ }
+ }
+
+ .auth {
+ @include floating_widget;
+ border-radius: $radius;
+ min-width: 400px;
+ padding: 0;
+
+ .wallpaper {
+ min-height: 220px;
+ background-size: cover;
+ border-top-left-radius: $radius;
+ border-top-right-radius: $radius;
+ }
+
+ .wallpaper-contrast {
+ min-height: 100px;
+ }
+
+ .avatar {
+ border-radius: 99px;
+ min-width: 140px;
+ min-height: 140px;
+ background-size: cover;
+ box-shadow: 3px 3px 6px 0 $shadow-color;
+ margin-bottom: $spacing;
+ }
+
+
+ .password {
+ entry {
+ @include button;
+ padding: $padding*.7 $padding;
+ margin-left: $spacing*.5;
+ }
+
+ margin: 0 $padding*4;
+ margin-top: $spacing;
+ }
+
+ .response-box {
+ color: $error-bg;
+ margin: $spacing 0;
+ }
+ }
+}
diff --git a/linux/home/.config/ags/greeter/greeter.ts b/linux/home/.config/ags/greeter/greeter.ts
new file mode 100644
index 0000000..eb1493f
--- /dev/null
+++ b/linux/home/.config/ags/greeter/greeter.ts
@@ -0,0 +1,37 @@
+import "./session"
+import "style/style"
+import GLib from "gi://GLib?version=2.0"
+import RegularWindow from "widget/RegularWindow"
+import statusbar from "./statusbar"
+import auth from "./auth"
+
+const win = RegularWindow({
+ name: "greeter",
+ setup: self => {
+ self.set_default_size(500, 500)
+ self.show_all()
+ auth.attribute.password.grab_focus()
+ },
+ child: Widget.Overlay({
+ child: Widget.Box({ expand: true }),
+ overlays: [
+ Widget.Box({
+ vpack: "start",
+ hpack: "fill",
+ hexpand: true,
+ child: statusbar,
+ }),
+ Widget.Box({
+ vpack: "center",
+ hpack: "center",
+ child: auth,
+ }),
+ ],
+ }),
+})
+
+App.config({
+ icons: "./assets",
+ windows: [win],
+ cursorTheme: GLib.getenv("XCURSOR_THEME")!,
+})
diff --git a/linux/home/.config/ags/greeter/session.ts b/linux/home/.config/ags/greeter/session.ts
new file mode 100644
index 0000000..092a5c2
--- /dev/null
+++ b/linux/home/.config/ags/greeter/session.ts
@@ -0,0 +1,20 @@
+import GLib from "gi://GLib?version=2.0"
+import AccountsService from "gi://AccountsService?version=1.0"
+
+const { userName } = AccountsService.UserManager.get_default().list_users()[0]
+
+declare global {
+ const WALLPAPER: string
+}
+
+Object.assign(globalThis, {
+ TMP: `${GLib.get_tmp_dir()}/greeter`,
+ OPTIONS: "/var/cache/greeter/options.json",
+ WALLPAPER: "/var/cache/greeter/background",
+ // TMP: "/tmp/ags",
+ // OPTIONS: Utils.CACHE_DIR + "/options.json",
+ // WALLPAPER: Utils.HOME + "/.config/background",
+ USER: userName,
+})
+
+Utils.ensureDirectory(TMP)
diff --git a/linux/home/.config/ags/greeter/statusbar.ts b/linux/home/.config/ags/greeter/statusbar.ts
new file mode 100644
index 0000000..8076011
--- /dev/null
+++ b/linux/home/.config/ags/greeter/statusbar.ts
@@ -0,0 +1,46 @@
+import { clock } from "lib/variables"
+import options from "options"
+import icons from "lib/icons"
+import BatteryBar from "widget/bar/buttons/BatteryBar"
+import PanelButton from "widget/bar/PanelButton"
+
+const { scheme } = options.theme
+const { monochrome } = options.bar.powermenu
+const { format } = options.bar.date
+
+const poweroff = PanelButton({
+ class_name: "powermenu",
+ child: Widget.Icon(icons.powermenu.shutdown),
+ on_clicked: () => Utils.exec("shutdown now"),
+ setup: self => self.hook(monochrome, () => {
+ self.toggleClassName("colored", !monochrome.value)
+ self.toggleClassName("box")
+ }),
+})
+
+const date = PanelButton({
+ class_name: "date",
+ child: Widget.Label({
+ label: clock.bind().as(c => c.format(`${format}`)!),
+ }),
+})
+
+const darkmode = PanelButton({
+ class_name: "darkmode",
+ child: Widget.Icon({ icon: scheme.bind().as(s => icons.color[s]) }),
+ on_clicked: () => scheme.value = scheme.value === "dark" ? "light" : "dark",
+})
+
+export default Widget.CenterBox({
+ class_name: "bar",
+ hexpand: true,
+ center_widget: date,
+ end_widget: Widget.Box({
+ hpack: "end",
+ children: [
+ darkmode,
+ BatteryBar(),
+ poweroff,
+ ],
+ }),
+})
diff --git a/linux/home/.config/ags/lib/battery.ts b/linux/home/.config/ags/lib/battery.ts
new file mode 100644
index 0000000..3817260
--- /dev/null
+++ b/linux/home/.config/ags/lib/battery.ts
@@ -0,0 +1,16 @@
+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/linux/home/.config/ags/lib/client.js b/linux/home/.config/ags/lib/client.js
new file mode 100644
index 0000000..9fb9164
--- /dev/null
+++ b/linux/home/.config/ags/lib/client.js
@@ -0,0 +1,134 @@
+import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
+import { find_icon } from "./iconUtils.js";
+import { lookUpIcon, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
+
+
+export let clientMapWorkSpace = {};
+
+export function substitute(str) {
+ const subs = [
+ { from: "code-url-handler", to: "visual-studio-code" },
+ { from: "Code", to: "visual-studio-code" },
+ { from: "GitHub Desktop", to: "github-desktop" },
+ { from: "wpsoffice", to: "wps-office2019-kprometheus" },
+ { from: "gnome-tweaks", to: "org.gnome.tweaks" },
+ { from: "Minecraft* 1.20.1", to: "minecraft" },
+ { from: "", to: "image-missing" },
+ ];
+
+ for (const { from, to } of subs) {
+ if (from === str) {
+ return to;
+ }
+ }
+
+ return str;
+}
+
+function titleToClient(title, className) {
+ const subs = [
+ { from: "musicfox", to: "musicfox" },
+ ];
+
+ for (const { from, to } of subs) {
+ if (title.indexOf(from) !== -1) {
+ return to;
+ }
+ }
+
+ return className
+}
+
+export const getClientByAdrees = function(address) {
+
+ const clients = Hyprland.clients
+
+ const client = clients.find(item => {
+ return item.address === address
+ })
+
+ return client
+}
+
+//Fullscreen client
+export const getFullScreenClientAddress = function(workspace_id) {
+
+ const clients = Hyprland.clients
+ const client = clients.find(item => {
+ return item.fullscreen && item.workspace.id === workspace_id
+ })
+ return client
+}
+
+export const ignoreAppsClass = [
+ 'image-missing',
+ 'fcitx',
+ 'rofi'
+]
+
+export const getClientIcon = (clientClass, title = "") => {
+
+ clientClass.toLowerCase()
+ clientClass = clientClass.replace(" ", "_");
+
+
+ if (title.length > 0) {
+ clientClass = titleToClient(title, clientClass)
+ }
+
+ const awesome_icon = find_icon(clientClass)
+ if (awesome_icon) {
+ return awesome_icon
+ }
+
+ if (lookUpIcon(clientClass)) {
+ return clientClass
+ }
+
+ if (find_icon('system')) {
+ return find_icon('system')
+ }
+
+ return ""
+}
+
+
+export const focus = (client) => {
+ //client
+ const { address } = client;
+ const liveClient = getClientByAdrees(address);
+
+ //special window
+ if (liveClient.workspace.id < 0) {
+ const oldWorkSpace = clientMapWorkSpace[address];
+ if (oldWorkSpace) {
+ Utils.exec(
+ `hyprctl dispatch movetoworkspace ${oldWorkSpace},address:${address}`,
+ );
+ Utils.exec(`hyprctl dispatch workspace ${oldWorkSpace}`);
+ }
+ }
+
+ //fullscreen
+ if (liveClient.fullscreen) {
+ Utils.exec("hyprctl dispatch focuswindow address:" + address);
+ return;
+ }
+
+ //workspace fullscreen client
+ const currentFullScreenAddress = getFullScreenClientAddress(
+ liveClient.workspace.id,
+ );
+ if (currentFullScreenAddress) {
+ const fullScreenAdress = currentFullScreenAddress.address;
+ Utils.exec("hyprctl dispatch focuswindow address:" + fullScreenAdress);
+ Utils.exec("hyprctl dispatch fullscreen 1");
+ }
+
+ Utils.exec("hyprctl dispatch focuswindow address:" + address);
+ // Utils.exec('hyprctl dispatch cyclenext')
+ Utils.exec("hyprctl dispatch alterzorder top,address:" + address);
+ if (currentFullScreenAddress) {
+ Utils.exec("hyprctl dispatch fullscreen 1");
+ }
+};
diff --git a/linux/home/.config/ags/lib/cursorhover.js b/linux/home/.config/ags/lib/cursorhover.js
new file mode 100644
index 0000000..d93d021
--- /dev/null
+++ b/linux/home/.config/ags/lib/cursorhover.js
@@ -0,0 +1,86 @@
+const { Gdk, Gtk } = imports.gi;
+
+const CLICK_BRIGHTEN_AMOUNT = 0.13;
+
+export function setupCursorHover(button) {
+ const display = Gdk.Display.get_default();
+ button.connect('enter-notify-event', () => {
+ const cursor = Gdk.Cursor.new_from_name(display, 'pointer');
+ button.get_window().set_cursor(cursor);
+ });
+
+ button.connect('leave-notify-event', () => {
+ const cursor = Gdk.Cursor.new_from_name(display, 'default');
+ button.get_window().set_cursor(cursor);
+ });
+
+}
+
+export function setupCursorHoverAim(button) {
+ button.connect('enter-notify-event', () => {
+ const display = Gdk.Display.get_default();
+ const cursor = Gdk.Cursor.new_from_name(display, 'crosshair');
+ button.get_window().set_cursor(cursor);
+ });
+
+ button.connect('leave-notify-event', () => {
+ const display = Gdk.Display.get_default();
+ const cursor = Gdk.Cursor.new_from_name(display, 'default');
+ button.get_window().set_cursor(cursor);
+ });
+}
+
+export function setupCursorHoverGrab(button) {
+ button.connect('enter-notify-event', () => {
+ const display = Gdk.Display.get_default();
+ const cursor = Gdk.Cursor.new_from_name(display, 'grab');
+ button.get_window().set_cursor(cursor);
+ });
+
+ button.connect('leave-notify-event', () => {
+ const display = Gdk.Display.get_default();
+ const cursor = Gdk.Cursor.new_from_name(display, 'default');
+ button.get_window().set_cursor(cursor);
+ });
+}
+
+// failed radial ripple experiment
+//
+// var clicked = false;
+// var dummy = false;
+// var cursorX = 0;
+// var cursorY = 0;
+// const styleContext = button.get_style_context();
+// var clickColor = styleContext.get_property('background-color', Gtk.StateFlags.HOVER);
+// clickColor.green += CLICK_BRIGHTEN_AMOUNT;
+// clickColor.blue += CLICK_BRIGHTEN_AMOUNT;
+// clickColor.red += CLICK_BRIGHTEN_AMOUNT;
+// clickColor = clickColor.to_string();
+// button.add_events(Gdk.EventMask.POINTER_MOTION_MASK);
+// button.connect('motion-notify-event', (widget, event) => {
+// [dummy, cursorX, cursorY] = event.get_coords(); // Get the mouse coordinates relative to the widget
+// if(!clicked) widget.css = `
+// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%);
+// `;
+// });
+
+// button.connect('button-press-event', (widget, event) => {
+// clicked = true;
+// [dummy, cursorX, cursorY] = event.get_coords(); // Get the mouse coordinates relative to the widget
+// cursorX = Math.round(cursorX); cursorY = Math.round(cursorY);
+// widget.css = `
+// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%);
+// `;
+// widget.toggleClassName('growingRadial', true);
+// widget.css = `
+// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 70%, ${clickColor} 70%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%);
+// `
+// });
+// button.connect('button-release-event', (widget, event) => {
+// widget.toggleClassName('growingRadial', false);
+// widget.toggleClassName('fadingRadial', false);
+// widget.css = `
+// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%);
+// `
+// clicked = false;
+// });
diff --git a/linux/home/.config/ags/lib/gtk.ts b/linux/home/.config/ags/lib/gtk.ts
new file mode 100644
index 0000000..8cd60a3
--- /dev/null
+++ b/linux/home/.config/ags/lib/gtk.ts
@@ -0,0 +1,16 @@
+import Gio from "gi://Gio"
+import options from "options"
+
+const settings = new Gio.Settings({
+ schema: "org.gnome.desktop.interface",
+})
+
+function gtk() {
+ const scheme = options.theme.scheme.value
+ settings.set_string("color-scheme", `prefer-${scheme}`)
+}
+
+export default function init() {
+ options.theme.scheme.connect("changed", gtk)
+ gtk()
+}
diff --git a/linux/home/.config/ags/lib/hyprland.ts b/linux/home/.config/ags/lib/hyprland.ts
new file mode 100644
index 0000000..7f6a68c
--- /dev/null
+++ b/linux/home/.config/ags/lib/hyprland.ts
@@ -0,0 +1,80 @@
+import options from "options"
+const { messageAsync } = await Service.import("hyprland")
+
+const {
+ hyprland,
+ theme: {
+ spacing,
+ radius,
+ border: { width },
+ blur,
+ shadows,
+ dark: {
+ primary: { bg: darkActive },
+ },
+ light: {
+ primary: { bg: lightActive },
+ },
+ scheme,
+ },
+} = options
+
+const deps = [
+ "hyprland",
+ spacing.id,
+ radius.id,
+ blur.id,
+ width.id,
+ shadows.id,
+ darkActive.id,
+ lightActive.id,
+ scheme.id,
+]
+
+function activeBorder() {
+ const color = scheme.value === "dark"
+ ? darkActive.value
+ : lightActive.value
+
+ return color.replace("#", "")
+}
+
+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}`,
+ // `general:gaps_out ${wm_gaps}`,
+ // `general:gaps_in ${Math.floor(wm_gaps / 2)}`,
+ // `general:col.active_border rgba(${activeBorder()}ff)`,
+ // `general:col.inactive_border rgba(${hyprland.inactiveBorder.value})`,
+ // `decoration:rounding ${radius}`,
+ // `decoration:drop_shadow ${shadows.value ? "yes" : "no"}`,
+ // `dwindle:no_gaps_when_only ${hyprland.gapsWhenOnly.value ? 0 : 1}`,
+ // `master:no_gaps_when_only ${hyprland.gapsWhenOnly.value ? 0 : 1}`,
+ //])
+
+ //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 */.29}, ${name}`,
+ ]))
+ }
+}
+
+export default function init() {
+ options.handler(deps, setupHyprland)
+ setupHyprland()
+}
diff --git a/linux/home/.config/ags/lib/iconUtils.js b/linux/home/.config/ags/lib/iconUtils.js
new file mode 100644
index 0000000..baba660
--- /dev/null
+++ b/linux/home/.config/ags/lib/iconUtils.js
@@ -0,0 +1,46 @@
+const { Gio, Gdk, Gtk } = imports.gi;
+
+function fileExists(filePath) {
+ let file = Gio.File.new_for_path(filePath);
+ return file.query_exists(null);
+}
+
+function cartesianProduct(arrays) {
+ if (arrays.length === 0) {
+ return [[]];
+ }
+
+ const [head, ...tail] = arrays;
+ const tailCartesian = cartesianProduct(tail);
+ const result = [];
+
+ for (const item of head) {
+ for (const tailItem of tailCartesian) {
+ result.push([item, ...tailItem]);
+ }
+ }
+ return result;
+}
+import { HOME } from '../utils.ts';
+export const find_icon = app_class => {
+ const themPath = [
+ [`${HOME}/.local/share/icons/WhiteSur/`, `${HOME}/.local/share//icons/WhiteSur-dark/`],
+ ['512x512/', '128x128/', '64x64/', '96x96/', '72x72/', '48x48/', '36x36/'],
+ ['apps/', ''],
+ [app_class + '.png', app_class + '.svg', app_class + '.xpm'],
+ ];
+
+ let real_path = '';
+ const all_icon_dir = cartesianProduct(themPath);
+
+ for (let index = 0; index < all_icon_dir.length; index++) {
+ const pathItem = all_icon_dir[index];
+ const icon_path = pathItem.join('');
+ if (fileExists(icon_path)) {
+ real_path = icon_path;
+ break;
+ }
+ }
+
+ return real_path;
+};
diff --git a/linux/home/.config/ags/lib/icons.ts b/linux/home/.config/ags/lib/icons.ts
new file mode 100644
index 0000000..dfc9e18
--- /dev/null
+++ b/linux/home/.config/ags/lib/icons.ts
@@ -0,0 +1,186 @@
+export const substitutes = {
+ "transmission-gtk": "transmission",
+ "blueberry.py": "blueberry",
+ "Caprine": "facebook-messenger",
+ "phototonic": "terminal-symbolic",
+ "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-volume-medium-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",
+ nix: {
+ nix: "nix-snowflake-symbolic",
+ },
+ app: {
+ terminal: "terminal-symbolic",
+ },
+ fallback: {
+ executable: "application-x-executable",
+ notification: "dialog-information-symbolic",
+ video: "video-x-generic-symbolic",
+ // audio: "audio-x-generic-symbolic",
+ audio: "audio-volume-medium-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-medium-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",
+ },
+ ui: {
+ arch: "archlinux-logo",
+ close: "window-close",
+ colorpicker: "color-select",
+ info: "info",
+ link: "external-link",
+ lock: "system-lock-screen",
+ menu: "open-menu",
+ refresh: "view-refresh",
+ search: "system-search",
+ settings: "emblem-system",
+ themes: "preferences-desktop-theme",
+ tick: "object-select",
+ time: "hourglass",
+ toolbars: "toolbars-symbolic",
+ warning: "dialog-warning",
+ avatar: "avatar-default",
+ tbox_osk: "osk",
+ tbox_appkill: "bomb-kill",
+ tbox_close: "tbox-close",
+ tbox_rotate: "rotation",
+ tbox_moveup: "arrows-up",
+ tbox_movedown: "arrows-down",
+ tbox_moveleft: "arrows-left",
+ tbox_moveright: "arrows-right",
+ tbox_workspacenext: "wp-next",
+ tbox_workspaceprev: "wp-prev",
+ tbox_fullscreen: "fullscreen",
+ tbox_swapnext: "swapnext",
+ tbox_float: "float",
+ tbox_pinned: "pinned",
+ tbox_split: "togglesplit",
+ arrow: {
+ right: "pan-end",
+ left: "pan-start",
+ down: "pan-down",
+ up: "pan-up",
+ },
+ },
+}
diff --git a/linux/home/.config/ags/lib/init.ts b/linux/home/.config/ags/lib/init.ts
new file mode 100644
index 0000000..e9e396c
--- /dev/null
+++ b/linux/home/.config/ags/lib/init.ts
@@ -0,0 +1,19 @@
+import matugen from './matugen';
+import hyprland from './hyprland';
+import tmux from './tmux';
+import gtk from './gtk';
+import lowBattery from './battery';
+import notifications from './notifications';
+
+export default function init() {
+ try {
+ gtk();
+ tmux();
+ matugen();
+ lowBattery();
+ notifications();
+ hyprland();
+ } catch (error) {
+ logError(error);
+ }
+}
diff --git a/linux/home/.config/ags/lib/matugen.ts b/linux/home/.config/ags/lib/matugen.ts
new file mode 100644
index 0000000..dfccccf
--- /dev/null
+++ b/linux/home/.config/ags/lib/matugen.ts
@@ -0,0 +1,113 @@
+import wallpaper from "service/wallpaper"
+import options from "options"
+import { sh, dependencies } from "./utils"
+
+export default function init() {
+ wallpaper.connect("changed", () => matugen())
+ options.autotheme.connect("changed", () => matugen())
+}
+
+function animate(...setters: Array<() => void>) {
+ const delay = options.transition.value / 2
+ setters.forEach((fn, i) => Utils.timeout(delay * i, fn))
+}
+
+export async function matugen(
+ type: "image" | "color" = "image",
+ arg = wallpaper.wallpaper,
+) {
+ if (!options.autotheme.value || !dependencies("matugen"))
+ return
+
+ const colors = await sh(`matugen --dry-run -j hex ${type} ${arg}`)
+ const c = JSON.parse(colors).colors as { light: Colors, dark: Colors }
+ const { dark, light } = options.theme
+
+ animate(
+ () => {
+ dark.widget.value = c.dark.on_surface
+ light.widget.value = c.light.on_surface
+ },
+ () => {
+ dark.border.value = c.dark.outline
+ light.border.value = c.light.outline
+ },
+ () => {
+ dark.bg.value = c.dark.surface
+ light.bg.value = c.light.surface
+ },
+ () => {
+ dark.fg.value = c.dark.on_surface
+ light.fg.value = c.light.on_surface
+ },
+ () => {
+ dark.primary.bg.value = c.dark.primary
+ light.primary.bg.value = c.light.primary
+ options.bar.battery.charging.value = options.theme.scheme.value === "dark"
+ ? c.dark.primary : c.light.primary
+ },
+ () => {
+ dark.primary.fg.value = c.dark.on_primary
+ light.primary.fg.value = c.light.on_primary
+ },
+ () => {
+ dark.error.bg.value = c.dark.error
+ light.error.bg.value = c.light.error
+ },
+ () => {
+ dark.error.fg.value = c.dark.on_error
+ light.error.fg.value = c.light.on_error
+ },
+ )
+}
+
+type Colors = {
+ background: string
+ error: string
+ error_container: string
+ inverse_on_surface: string
+ inverse_primary: string
+ inverse_surface: string
+ on_background: string
+ on_error: string
+ on_error_container: string
+ on_primary: string
+ on_primary_container: string
+ on_primary_fixed: string
+ on_primary_fixed_variant: string
+ on_secondary: string
+ on_secondary_container: string
+ on_secondary_fixed: string
+ on_secondary_fixed_variant: string
+ on_surface: string
+ on_surface_variant: string
+ on_tertiary: string
+ on_tertiary_container: string
+ on_tertiary_fixed: string
+ on_tertiary_fixed_variant: string
+ outline: string
+ outline_variant: string
+ primary: string
+ primary_container: string
+ primary_fixed: string
+ primary_fixed_dim: string
+ scrim: string
+ secondary: string
+ secondary_container: string
+ secondary_fixed: string
+ secondary_fixed_dim: string
+ shadow: string
+ surface: string
+ surface_bright: string
+ surface_container: string
+ surface_container_high: string
+ surface_container_highest: string
+ surface_container_low: string
+ surface_container_lowest: string
+ surface_dim: string
+ surface_variant: string
+ tertiary: string
+ tertiary_container: string
+ tertiary_fixed: string
+ tertiary_fixed_dim: string
+}
diff --git a/linux/home/.config/ags/lib/notifications.ts b/linux/home/.config/ags/lib/notifications.ts
new file mode 100644
index 0000000..0000831
--- /dev/null
+++ b/linux/home/.config/ags/lib/notifications.ts
@@ -0,0 +1,16 @@
+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/linux/home/.config/ags/lib/option.ts b/linux/home/.config/ags/lib/option.ts
new file mode 100644
index 0000000..2d73978
--- /dev/null
+++ b/linux/home/.config/ags/lib/option.ts
@@ -0,0 +1,115 @@
+import { Variable } from "resource:///com/github/Aylur/ags/variable.js"
+
+type OptProps = {
+ persistent?: boolean
+}
+
+export class Opt<T = unknown> extends Variable<T> {
+ 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 = <T>(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<T extends object>(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<Array<string>> {
+ 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/linux/home/.config/ags/lib/session.ts b/linux/home/.config/ags/lib/session.ts
new file mode 100644
index 0000000..0e3e0cf
--- /dev/null
+++ b/linux/home/.config/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()}/asztal`,
+ USER: GLib.get_user_name(),
+})
+
+Utils.ensureDirectory(TMP)
+App.addIcons(`${App.configDir}/assets`)
diff --git a/linux/home/.config/ags/lib/tmux.ts b/linux/home/.config/ags/lib/tmux.ts
new file mode 100644
index 0000000..1372eb2
--- /dev/null
+++ b/linux/home/.config/ags/lib/tmux.ts
@@ -0,0 +1,14 @@
+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.bg.value : light.primary.bg.value
+ if (await sh("which tmux"))
+ sh(`tmux set @main_accent "${hex}"`)
+}
+
+export default function init() {
+ options.theme.dark.primary.bg.connect("changed", tmux)
+ options.theme.light.primary.bg.connect("changed", tmux)
+}
diff --git a/linux/home/.config/ags/lib/utils.ts b/linux/home/.config/ags/lib/utils.ts
new file mode 100644
index 0000000..f3ff2e3
--- /dev/null
+++ b/linux/home/.config/ags/lib/utils.ts
@@ -0,0 +1,113 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { type Application } from "types/service/applications"
+import icons, { substitutes } from "./icons"
+import Gtk from "gi://Gtk?version=3.0"
+import Gdk from "gi://Gdk"
+import GLib from "gi://GLib?version=2.0"
+
+export const HOME = GLib.get_home_dir();
+
+export type Binding<T> = import("types/service").Binding<any, any, T>
+
+/**
+ * @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).map(widget).flat(1)
+}
+
+/**
+ * @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 => {
+ return !Utils.exec(`which ${bin}`)
+ })
+
+ if (missing.length > 0) {
+ console.warn("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
+}
diff --git a/linux/home/.config/ags/lib/variables.ts b/linux/home/.config/ags/lib/variables.ts
new file mode 100644
index 0000000..78d8793
--- /dev/null
+++ b/linux/home/.config/ags/lib/variables.ts
@@ -0,0 +1,47 @@
+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 user = {
+ name: GLib.get_user_name()
+}
+
+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/linux/home/.config/ags/main.ts b/linux/home/.config/ags/main.ts
new file mode 100644
index 0000000..fa18846
--- /dev/null
+++ b/linux/home/.config/ags/main.ts
@@ -0,0 +1,47 @@
+import "lib/session"
+import "style/style"
+import init from "lib/init"
+import options from "options"
+import Bar from "widget/bar/Bar"
+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 ScreenCorners from "widget/bar/ScreenCorners"
+import SettingsDialog from "widget/settings/SettingsDialog"
+import Verification from "widget/powermenu/Verification"
+import { forMonitors } from "lib/utils"
+import { setupQuickSettings } from "widget/quicksettings/QuickSettings"
+import { setupDateMenu } from "widget/datemenu/DateMenu"
+//import Dock from "widget/dock/Dock";
+import FloatingDock from "widget/dock/FloatingDock"
+import ToolBoxDock from "widget/dock/ToolBoxDock"
+
+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(Dock),
+ ...forMonitors(FloatingDock),
+ //...forMonitors(ToolBoxDock),
+ ...forMonitors(NotificationPopups),
+ ...forMonitors(ScreenCorners),
+ ...forMonitors(OSD),
+ Launcher(),
+ Overview(),
+ PowerMenu(),
+ SettingsDialog(),
+ Verification(),
+ ],
+})
diff --git a/linux/home/.config/ags/options.ts b/linux/home/.config/ags/options.ts
new file mode 100644
index 0000000..4cf5a53
--- /dev/null
+++ b/linux/home/.config/ags/options.ts
@@ -0,0 +1,261 @@
+import { opt, mkOptions } from 'lib/option';
+import { distro } from 'lib/variables';
+import { icon } from 'lib/utils';
+import { icons } from 'assets';
+import icons from 'lib/icons';
+//import Dock from "./widgets/dock/index.js";
+
+const options = mkOptions(OPTIONS, {
+ autotheme: opt(false),
+
+ wallpaper: {
+ enable: opt(false),
+ resolution: opt<import('service/wallpaper').Resolution>(1920),
+ market: opt<import('service/wallpaper').Market>('random'),
+ },
+
+ theme: {
+ dark: {
+ primary: {
+ bg: opt('#51a4e7'),
+ fg: opt('#141414'),
+ },
+ error: {
+ bg: opt('#e55f86'),
+ fg: opt('#141414'),
+ },
+ bg: opt('#171717'),
+ fg: opt('#eeeeee'),
+ widget: opt('#eeeeee'),
+ border: opt('#eeeeee'),
+ },
+ light: {
+ primary: {
+ bg: opt('#426ede'),
+ fg: opt('#eeeeee'),
+ },
+ error: {
+ bg: opt('#b13558'),
+ fg: opt('#eeeeee'),
+ },
+ bg: opt('#fffffa'),
+ fg: opt('#080808'),
+ widget: opt('#080808'),
+ border: opt('#080808'),
+ },
+
+ blur: opt(0),
+ scheme: opt<'dark' | 'light'>('dark'),
+ widget: { opacity: opt(94) },
+ border: {
+ width: opt(1),
+ opacity: opt(100),
+ },
+
+ shadows: opt(true),
+ padding: opt(7),
+ spacing: opt(12),
+ radius: opt(11),
+ },
+
+ transition: opt(200),
+
+ font: {
+ size: opt(13),
+ name: opt('Ubuntu Nerd Font'),
+ },
+ bar: {
+ flatButtons: opt(true),
+ position: opt<'top' | 'bottom'>('top'),
+ corners: opt(false),
+ layout: {
+ start: opt<Array<import('widget/bar/Bar').BarWidget>>([
+ 'launcher',
+ 'workspaces',
+ //"taskbar",
+ 'expander',
+ 'messages',
+ ]),
+ center: opt<Array<import('widget/bar/Bar').BarWidget>>(['date']),
+ end: opt<Array<import('widget/bar/Bar').BarWidget>>([
+ 'media',
+ 'expander',
+ //"colorpicker",
+ 'screenrecord',
+ 'battery',
+ 'systray',
+ 'system',
+ 'powermenu',
+ ]),
+ },
+ launcher: {
+ icon: {
+ colored: opt(true),
+ icon: opt(icon(distro.logo, icons.ui.search)),
+ },
+ label: {
+ colored: opt(false),
+ label: opt(''),
+ //label: opt(" Applications"),
+ },
+ action: opt(() => App.toggleWindow('launcher')),
+ },
+ date: {
+ format: opt('%a %d %b %Y %H:%M:%S'),
+ action: opt(() => App.toggleWindow('datemenu')),
+ },
+ battery: {
+ bar: opt<'hidden' | 'regular' | 'whole'>('regular'),
+ charging: opt('#00D787'),
+ percentage: opt(true),
+ blocks: opt(7),
+ width: opt(50),
+ low: opt(30),
+ },
+ workspaces: {
+ workspaces: opt(6),
+ },
+ 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')),
+ },
+ },
+
+ dock: {
+ iconSize: opt(44),
+ pinnedApps: opt([
+ 'nemo',
+ 'firefox',
+ 'mullvad',
+ 'qbittorrent',
+ 'com.obsproject.Studio',
+ 'vlc',
+ 'spotify',
+ //"viewnior",
+ //"phototonic",
+ 'gthumb',
+ 'nomachine',
+ 'lutris',
+ 'steam',
+ 'discord',
+ 'vscode',
+ 'wezterm',
+ 'obsidian',
+ ]),
+ toolbox: {
+ icons: [opt(icon(icons.ui.tbox_close)), opt(icon(icons.ui.tbox_appkill)), opt(icon(icons.ui.tbox_rotate)), opt(icon(icons.ui.tbox_workspaceprev)), opt(icon(icons.ui.tbox_workspacenext)), opt(icon(icons.ui.tbox_moveleft)), opt(icon(icons.ui.tbox_moveright)), opt(icon(icons.ui.tbox_moveup)), opt(icon(icons.ui.tbox_movedown)), opt(icon(icons.ui.tbox_swapnext)), opt(icon(icons.ui.tbox_split)), opt(icon(icons.ui.tbox_float)), opt(icon(icons.ui.tbox_pinned)), opt(icon(icons.ui.tbox_fullscreen)), opt(icon(icons.ui.tbox_osk))],
+ },
+ },
+ launcher: {
+ width: opt(0),
+ margin: opt(80),
+ nix: {
+ pkgs: opt('nixpkgs/nixos-unstable'),
+ max: opt(8),
+ },
+ sh: {
+ max: opt(16),
+ },
+ apps: {
+ iconSize: opt(62),
+ max: opt(6),
+ favorites: opt([['firefox', 'nemo', 'obsidian', 'discord', 'spotify']]),
+ },
+ },
+
+ overview: {
+ scale: opt(9),
+ workspaces: opt(6),
+ monochromeIcon: opt(false),
+ },
+
+ powermenu: {
+ //sleep: opt('systemctl suspend'),
+ sleep: opt('loginctl suspend'),
+ //reboot: opt('reboot'),
+ reboot: opt('loginctl reboot'),
+ logout: opt('pkill Hyprland'),
+ //shutdown: opt('shutdown now'),
+ shutdown: opt('loginctl poweroff'),
+ layout: opt<'line' | 'box'>('line'),
+ labels: opt(true),
+ },
+
+ quicksettings: {
+ avatar: {
+ image: opt(`/var/lib/AccountsService/icons/${Utils.USER}`),
+ size: opt(40),
+ },
+ width: opt(380),
+ position: opt<'left' | 'center' | 'right'>('right'),
+ networkSettings: opt('gtk-launch nm-connection-editor'),
+ //networkSettings: opt('gtk-launch gnome-control-center'),
+ media: {
+ monochromeIcon: opt(true),
+ coverSize: opt(100),
+ },
+ },
+
+ datemenu: {
+ position: opt<'left' | 'center' | 'right'>('center'),
+ weather: {
+ interval: opt(60_000),
+ unit: opt<'metric' | 'imperial' | 'standard'>('metric'),
+ key: opt<string>(JSON.parse(Utils.readFile(`${App.configDir}/.weather`) || '{}')?.key || ''),
+ cities: opt<Array<number>>(JSON.parse(Utils.readFile(`${App.configDir}/.weather`) || '{}')?.cities || []),
+ },
+ },
+
+ 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<Array<'top' | 'bottom' | 'left' | 'right'>>(['top', 'right']),
+ blacklist: opt(['']),
+ //blacklist: opt(["Spotify"]),
+ width: opt(440),
+ },
+
+ hyprland: {
+ gaps: opt(2.4),
+ inactiveBorder: opt('333333ff'),
+ gapsWhenOnly: opt(false),
+ },
+});
+
+globalThis['options'] = options;
+export default options;
diff --git a/linux/home/.config/ags/package.json b/linux/home/.config/ags/package.json
new file mode 100644
index 0000000..e0586f7
--- /dev/null
+++ b/linux/home/.config/ags/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "ags",
+ "author": "srdusr",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/srdusr/dotfiles.git"
+ },
+ "devDependencies": {
+ "@girs/accountsservice-1.0": "^1.0.0-3.2.7",
+ "@typescript-eslint/eslint-plugin": "^6.20.0",
+ "eslint": "^8.56.0",
+ "eslint-config-standard-with-typescript": "^43.0.1",
+ "eslint-plugin-import": "^2.29.1",
+ "eslint-plugin-n": "^16.6.2",
+ "eslint-plugin-promise": "^6.1.1",
+ "typescript": "^5.3.3"
+ }
+}
diff --git a/linux/home/.config/ags/service/asusctl.ts b/linux/home/.config/ags/service/asusctl.ts
new file mode 100644
index 0000000..16acbd7
--- /dev/null
+++ b/linux/home/.config/ags/service/asusctl.ts
@@ -0,0 +1,52 @@
+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"],
+ })
+ }
+
+ available = !!Utils.exec("which asusctl")
+ #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/linux/home/.config/ags/service/brightness.ts b/linux/home/.config/ags/service/brightness.ts
new file mode 100644
index 0000000..a0b8eb5
--- /dev/null
+++ b/linux/home/.config/ags/service/brightness.ts
@@ -0,0 +1,69 @@
+import { bash, dependencies, sh } from "lib/utils"
+
+if (!dependencies("brightnessctl"))
+ 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`
+
+class Brightness extends Service {
+ static {
+ Service.register(this, {}, {
+ "screen": ["float", "rw"],
+ "kbd": ["int", "rw"],
+ })
+ }
+
+ #kbdMax = get(`--device ${kbd} max`)
+ #kbd = get(`--device ${kbd} get`)
+ #screenMax = get("max")
+ #screen = get("get") / get("max")
+
+ get kbd() { return this.#kbd }
+ get screen() { return this.#screen }
+
+ set kbd(value) {
+ if (value < 0 || value > this.#kbdMax)
+ return
+
+ sh(`brightnessctl -d ${kbd} s ${value} -q`).then(() => {
+ this.#kbd = value
+ this.changed("kbd")
+ })
+ }
+
+ set screen(percent) {
+ if (percent < 0)
+ percent = 0
+
+ if (percent > 1)
+ percent = 1
+
+ sh(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => {
+ this.#screen = percent
+ this.changed("screen")
+ })
+ }
+
+ constructor() {
+ super()
+
+ 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")
+ })
+ }
+}
+
+export default new Brightness
diff --git a/linux/home/.config/ags/service/colorpicker.ts b/linux/home/.config/ags/service/colorpicker.ts
new file mode 100644
index 0000000..5918f31
--- /dev/null
+++ b/linux/home/.config/ags/service/colorpicker.ts
@@ -0,0 +1,56 @@
+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/linux/home/.config/ags/service/nix.ts b/linux/home/.config/ags/service/nix.ts
new file mode 100644
index 0000000..3bde9fc
--- /dev/null
+++ b/linux/home/.config/ags/service/nix.ts
@@ -0,0 +1,109 @@
+import icons from "lib/icons"
+import { bash, dependencies } from "lib/utils"
+import options from "options"
+
+const CACHE = `${Utils.CACHE_DIR}/nixpkgs`
+const PREFIX = "legacyPackages.x86_64-linux."
+const MAX = options.launcher.nix.max
+const nixpkgs = options.launcher.nix.pkgs
+
+export type Nixpkg = {
+ name: string
+ description: string
+ pname: string
+ version: string
+}
+
+class Nix extends Service {
+ static {
+ Service.register(this, {}, {
+ "available": ["boolean", "r"],
+ "ready": ["boolean", "rw"],
+ })
+ }
+
+ #db: { [name: string]: Nixpkg } = {}
+ #ready = true
+
+ private set ready(r: boolean) {
+ this.#ready = r
+ this.changed("ready")
+ }
+
+ get db() { return this.#db }
+ get ready() { return this.#ready }
+ get available() { return Utils.exec("which nix") }
+
+ constructor() {
+ super()
+ if (!this.available)
+ return this
+
+ this.#updateList()
+ nixpkgs.connect("changed", this.#updateList)
+ }
+
+ query = async (filter: string) => {
+ if (!dependencies("fzf", "nix") || !this.#ready)
+ return [] as string[]
+
+ return bash(`cat ${CACHE} | fzf -f ${filter} -e | head -n ${MAX} `)
+ .then(str => str.split("\n").filter(i => i))
+ }
+
+ nix(cmd: string, bin: string, args: string) {
+ return Utils.execAsync(`nix ${cmd} ${nixpkgs}#${bin} --impure ${args}`)
+ }
+
+ run = async (input: string) => {
+ if (!dependencies("nix"))
+ return
+
+ try {
+ const [bin, ...args] = input.trim().split(/\s+/)
+
+ this.ready = false
+ await this.nix("shell", bin, "--command sh -c 'exit'")
+ this.ready = true
+
+ this.nix("run", bin, ["--", ...args].join(" "))
+ } catch (err) {
+ if (typeof err === "string")
+ Utils.notify("NixRun Error", err, icons.nix.nix)
+ else
+ logError(err)
+ } finally {
+ this.ready = true
+ }
+ }
+
+ #updateList = async () => {
+ if (!dependencies("nix"))
+ return
+
+ this.ready = false
+ this.#db = {}
+
+ // const search = await bash(`nix search ${nixpkgs} --json`)
+ const search = ""
+ if (!search) {
+ this.ready = true
+ return
+ }
+
+ const json = Object.entries(JSON.parse(search) as {
+ [name: string]: Nixpkg
+ })
+
+ for (const [pkg, info] of json) {
+ const name = pkg.replace(PREFIX, "")
+ this.#db[name] = { ...info, name }
+ }
+
+ const list = Object.keys(this.#db).join("\n")
+ await Utils.writeFile(list, CACHE)
+ this.ready = true
+ }
+}
+
+export default new Nix
diff --git a/linux/home/.config/ags/service/powermenu.ts b/linux/home/.config/ags/service/powermenu.ts
new file mode 100644
index 0000000..fd16bc1
--- /dev/null
+++ b/linux/home/.config/ags/service/powermenu.ts
@@ -0,0 +1,43 @@
+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 }
+ get cmd() { return this.#cmd }
+
+ 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")
+ }
+}
+
+const powermenu = new PowerMenu
+Object.assign(globalThis, { powermenu })
+export default powermenu
diff --git a/linux/home/.config/ags/service/screenrecord.ts b/linux/home/.config/ags/service/screenrecord.ts
new file mode 100644
index 0000000..58721d2
--- /dev/null
+++ b/linux/home/.config/ags/service/screenrecord.ts
@@ -0,0 +1,102 @@
+import GLib from "gi://GLib"
+import icons from "lib/icons"
+import { dependencies, sh, bash } from "lib/utils"
+
+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
+
+ async start() {
+ if (!dependencies("slurp", "wf-recorder"))
+ return
+
+ if (this.recording)
+ return
+
+ 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)
+
+ 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)
+
+ if (full) {
+ await sh(`wayshot -f ${file}`)
+ }
+ else {
+ const size = await sh("slurp")
+ if (!size)
+ return
+
+ await sh(`wayshot -f ${file} -s "${size}"`)
+ }
+
+ 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/linux/home/.config/ags/service/wallpaper.ts b/linux/home/.config/ags/service/wallpaper.ts
new file mode 100644
index 0000000..865c6d9
--- /dev/null
+++ b/linux/home/.config/ags/service/wallpaper.ts
@@ -0,0 +1,127 @@
+import options from 'options';
+import { dependencies, sh } from 'lib/utils';
+
+export type Resolution = 1920 | 1366 | 3840;
+export type Market = 'random' | 'en-US' | 'ja-JP' | 'en-AU' | 'en-GB' | 'de-DE' | 'en-NZ' | 'en-CA';
+
+const WP = `${Utils.HOME}/pictures/wallpapers`;
+const Cache = `${Utils.HOME}/Pictures/Wallpapers/Bing`;
+
+class Wallpaper extends Service {
+ static {
+ Service.register(
+ this,
+ {},
+ {
+ wallpaper: ['string'],
+ },
+ );
+ }
+
+ #blockMonitor = false;
+
+ #wallpaper() {
+ if (!dependencies('swww')) return;
+
+ sh('hyprctl cursorpos').then(pos => {
+ sh(['swww', 'img', '--transition-type', 'grow', '--transition-pos', pos.replace(' ', ''), WP]).then(() => {
+ this.changed('wallpaper');
+ });
+ });
+ }
+
+ async #setWallpaper(path: string) {
+ this.#blockMonitor = true;
+
+ await sh(`cp "${path}" "${WP}"`);
+ this.#wallpaper();
+
+ this.#blockMonitor = false;
+ }
+
+ async #fetchBing() {
+ // Check if wallpaper functionality is enabled
+ if (!options.wallpaper.enable.value) {
+ console.log('Wallpaper functionality is disabled.');
+ return;
+ }
+
+ try {
+ const res = await Utils.fetch('https://bing.biturl.top/', {
+ params: {
+ resolution: options.wallpaper.resolution.value,
+ format: 'json',
+ image_format: 'jpg',
+ index: 'random',
+ mkt: options.wallpaper.market.value,
+ },
+ });
+
+ if (!res.ok) {
+ console.warn('Failed to fetch from Bing:', res.statusText);
+ return;
+ }
+
+ const data = await res.json();
+ const { url } = data;
+
+ if (!url) {
+ console.warn('No URL found in Bing response:', data);
+ return;
+ }
+
+ const file = `${Cache}/${url.replace('https://www.bing.com/th?id=', '')}`;
+
+ Utils.ensureDirectory(Cache);
+
+ if (!(await Utils.fileExists(file))) {
+ await sh(`curl "${url}" --output "${file}"`);
+ await this.#setWallpaper(file);
+ } else {
+ console.log(`Wallpaper already exists: ${file}`);
+ }
+ } catch (error) {
+ console.error('Error fetching wallpaper:', error);
+ }
+ }
+
+ readonly random = () => {
+ // Check if wallpaper functionality is enabled
+ if (!options.wallpaper.enable.value) {
+ console.log('Wallpaper functionality is disabled.');
+ return;
+ }
+ this.#fetchBing();
+ };
+
+ readonly set = (path: string) => {
+ this.#setWallpaper(path);
+ };
+
+ get wallpaper() {
+ return WP;
+ }
+ constructor() {
+ super();
+
+ // Respect wallpaper.enable option
+ if (!options.wallpaper.enable.value) {
+ console.log('Wallpaper functionality is disabled, not starting swww-daemon.');
+ return;
+ }
+
+ if (!dependencies('swww')) return;
+
+ // Monitor and set wallpaper if enabled
+ Utils.monitorFile(WP, () => {
+ if (!this.#blockMonitor) this.#wallpaper();
+ });
+
+ // Start swww-daemon only when wallpaper is enabled
+ Utils.execAsync('swww-daemon')
+ .then(this.#wallpaper)
+ .catch(() => null);
+ }
+}
+
+export default new Wallpaper();
diff --git a/linux/home/.config/ags/service/weather.ts b/linux/home/.config/ags/service/weather.ts
new file mode 100644
index 0000000..14f2df2
--- /dev/null
+++ b/linux/home/.config/ags/service/weather.ts
@@ -0,0 +1,59 @@
+import options from "options"
+
+const { interval, key, cities, unit } = options.datemenu.weather
+
+class Weather extends Service {
+ static {
+ Service.register(this, {}, {
+ "forecasts": ["jsobject"],
+ })
+ }
+
+ #forecasts: Forecast[] = []
+ get forecasts() { return this.#forecasts }
+
+ async #fetch(placeid: number) {
+ const url = "https://api.openweathermap.org/data/2.5/forecast"
+ const res = await Utils.fetch(url, {
+ params: {
+ id: placeid,
+ appid: key.value,
+ untis: unit.value,
+ },
+ })
+ return await res.json()
+ }
+
+ constructor() {
+ super()
+ if (!key.value)
+ return this
+
+ Utils.interval(interval.value, () => {
+ Promise.all(cities.value.map(this.#fetch)).then(forecasts => {
+ this.#forecasts = forecasts as Forecast[]
+ this.changed("forecasts")
+ })
+ })
+ }
+}
+
+export default new Weather
+
+type Forecast = {
+ city: {
+ name: string,
+ }
+ list: Array<{
+ dt: number
+ main: {
+ temp: number
+ feels_like: number
+ },
+ weather: Array<{
+ main: string,
+ description: string,
+ icon: string,
+ }>
+ }>
+}
diff --git a/linux/home/.config/ags/style/extra.scss b/linux/home/.config/ags/style/extra.scss
new file mode 100644
index 0000000..e7f9d44
--- /dev/null
+++ b/linux/home/.config/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 * .5;
+ margin: ($spacing * .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/linux/home/.config/ags/style/mixins/a11y-button.scss b/linux/home/.config/ags/style/mixins/a11y-button.scss
new file mode 100644
index 0000000..00b24c6
--- /dev/null
+++ b/linux/home/.config/ags/style/mixins/a11y-button.scss
@@ -0,0 +1,48 @@
+@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/linux/home/.config/ags/style/mixins/button.scss b/linux/home/.config/ags/style/mixins/button.scss
new file mode 100644
index 0000000..79ec275
--- /dev/null
+++ b/linux/home/.config/ags/style/mixins/button.scss
@@ -0,0 +1,70 @@
+@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/linux/home/.config/ags/style/mixins/floating-widget.scss b/linux/home/.config/ags/style/mixins/floating-widget.scss
new file mode 100644
index 0000000..613668d
--- /dev/null
+++ b/linux/home/.config/ags/style/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/linux/home/.config/ags/style/mixins/hidden.scss b/linux/home/.config/ags/style/mixins/hidden.scss
new file mode 100644
index 0000000..ea6a42c
--- /dev/null
+++ b/linux/home/.config/ags/style/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/linux/home/.config/ags/style/mixins/media.scss b/linux/home/.config/ags/style/mixins/media.scss
new file mode 100644
index 0000000..3178029
--- /dev/null
+++ b/linux/home/.config/ags/style/mixins/media.scss
@@ -0,0 +1,42 @@
+@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 * .5;
+
+ &.play-pause {
+ margin: 0 ($spacing * .5);
+ }
+
+ image {
+ font-size: 1.2em;
+ }
+ }
+
+ .artist {
+ color: transparentize($fg, .2);
+ font-size: .9em;
+ }
+
+ scale {
+ @include slider($width: .5em, $slider: false, $gradient: linear-gradient($fg, $fg));
+ margin-bottom: $padding * .5;
+
+ trough {
+ border: none;
+ }
+ }
+}
diff --git a/linux/home/.config/ags/style/mixins/scrollable.scss b/linux/home/.config/ags/style/mixins/scrollable.scss
new file mode 100644
index 0000000..b66f246
--- /dev/null
+++ b/linux/home/.config/ags/style/mixins/scrollable.scss
@@ -0,0 +1,42 @@
+@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: .6em;
+ }
+ }
+ }
+
+
+ scrollbar.vertical slider {
+ background-color: transparentize($fg, 0.5);
+ border-radius: $radius;
+ min-width: .4em;
+ min-height: 2em;
+ transition: $transition;
+ }
+}
diff --git a/linux/home/.config/ags/style/mixins/slider.scss b/linux/home/.config/ags/style/mixins/slider.scss
new file mode 100644
index 0000000..b90e566
--- /dev/null
+++ b/linux/home/.config/ags/style/mixins/slider.scss
@@ -0,0 +1,74 @@
+@import './unset';
+
+@mixin slider($width: 0.7em, $slider-width: .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/linux/home/.config/ags/style/mixins/spacing.scss b/linux/home/.config/ags/style/mixins/spacing.scss
new file mode 100644
index 0000000..4096fba
--- /dev/null
+++ b/linux/home/.config/ags/style/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/linux/home/.config/ags/style/mixins/switch.scss b/linux/home/.config/ags/style/mixins/switch.scss
new file mode 100644
index 0000000..2abf360
--- /dev/null
+++ b/linux/home/.config/ags/style/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/linux/home/.config/ags/style/mixins/unset.scss b/linux/home/.config/ags/style/mixins/unset.scss
new file mode 100644
index 0000000..eb80af5
--- /dev/null
+++ b/linux/home/.config/ags/style/mixins/unset.scss
@@ -0,0 +1,9 @@
+@mixin unset($rec: false) {
+ all: unset;
+
+ @if $rec {
+ * {
+ all: unset
+ }
+ }
+}
diff --git a/linux/home/.config/ags/style/mixins/widget.scss b/linux/home/.config/ags/style/mixins/widget.scss
new file mode 100644
index 0000000..053f1aa
--- /dev/null
+++ b/linux/home/.config/ags/style/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/linux/home/.config/ags/style/style.ts b/linux/home/.config/ags/style/style.ts
new file mode 100644
index 0000000..a9b94fe
--- /dev/null
+++ b/linux/home/.config/ags/style/style.ts
@@ -0,0 +1,103 @@
+/* eslint-disable max-len */
+import { type Opt } from "lib/option"
+import options from "options"
+import { bash, dependencies, sh } from "lib/utils"
+
+const deps = [
+ "font",
+ "theme",
+ "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: Opt<any> | string, light: Opt<any> | string) => scheme.value === "dark"
+ ? `${dark}` : `${light}`
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const $ = (name: string, value: string | Opt<any>) => `$${name}: ${value};`
+
+const variables = () => [
+ $("bg", blur.value ? `transparentize(${t(dark.bg, light.bg)}, ${blur.value / 100})` : t(dark.bg, light.bg)),
+ $("fg", t(dark.fg, light.fg)),
+
+ $("primary-bg", t(dark.primary.bg, light.primary.bg)),
+ $("primary-fg", t(dark.primary.fg, light.primary.fg)),
+
+ $("error-bg", t(dark.error.bg, light.error.bg)),
+ $("error-fg", t(dark.error.fg, light.error.fg)),
+
+ $("scheme", scheme),
+ $("padding", `${padding}pt`),
+ $("spacing", `${spacing}pt`),
+ $("radius", `${radius}px`),
+ $("transition", `${options.transition}ms`),
+
+ $("shadows", `${shadows}`),
+
+ $("widget-bg", `transparentize(${t(dark.widget, light.widget)}, ${widget.opacity.value / 100})`),
+
+ $("hover-bg", `transparentize(${t(dark.widget, light.widget)}, ${(widget.opacity.value * .9) / 100})`),
+ $("hover-fg", `lighten(${t(dark.fg, light.fg)}, 8%)`),
+
+ $("border-width", `${border.width}px`),
+ $("border-color", `transparentize(${t(dark.border, light.border)}, ${border.opacity.value / 100})`),
+ $("border", "$border-width solid $border-color"),
+
+ $("active-gradient", `linear-gradient(to right, ${t(dark.primary.bg, light.primary.bg)}, darken(${t(dark.primary.bg, light.primary.bg)}, 4%))`),
+ $("shadow-color", t("rgba(0,0,0,.6)", "rgba(0,0,0,.4)")),
+ $("text-shadow", t("2pt 2pt 2pt $shadow-color", "none")),
+
+ $("popover-border-color", `transparentize(${t(dark.border, light.border)}, ${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}pt`),
+ $("font-name", options.font.name),
+
+ // etc
+ $("charging-bg", options.bar.battery.charging),
+ $("bar-battery-blocks", options.bar.battery.blocks),
+ $("bar-position", options.bar.position),
+ $("hyprland-gaps-multiplier", options.hyprland.gaps),
+]
+
+async function resetCss() {
+ if (!dependencies("sass", "fd"))
+ return
+
+ try {
+ const vars = `${TMP}/variables.scss`
+ await Utils.writeFile(variables().join("\n"), vars)
+
+ const fd = await sh(`fd ".scss" ${App.configDir}`)
+ const files = fd.split(/\s+/).map(f => `@import '${f}';`)
+ const scss = [`@import '${vars}';`, ...files].join("\n")
+ const css = await bash`echo "${scss}" | sass --stdin`
+
+ App.applyCss(css, true)
+ } catch (error) {
+ logError(error)
+ }
+}
+
+Utils.monitorFile(App.configDir, resetCss)
+options.handler(deps, resetCss)
+await resetCss()
diff --git a/linux/home/.config/ags/tsconfig.json b/linux/home/.config/ags/tsconfig.json
new file mode 100644
index 0000000..1708aa3
--- /dev/null
+++ b/linux/home/.config/ags/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ES2022",
+ "lib": [
+ "ES2022"
+ ],
+ "allowJs": true,
+ "checkJs": true,
+ "strict": true,
+ "noImplicitAny": false,
+ "baseUrl": ".",
+ "typeRoots": [
+ "./types",
+ "./node_modules/@girs"
+ ],
+ "skipLibCheck": true
+ }
+}
diff --git a/linux/home/.config/ags/widget/PopupWindow.ts b/linux/home/.config/ags/widget/PopupWindow.ts
new file mode 100644
index 0000000..b53b6fd
--- /dev/null
+++ b/linux/home/.config/ags/widget/PopupWindow.ts
@@ -0,0 +1,156 @@
+import { type WindowProps } from "types/widgets/window"
+import { type RevealerProps } from "types/widgets/revealer"
+import { type EventBoxProps } from "types/widgets/eventbox"
+import type Gtk from "gi://Gtk?version=3.0"
+import options from "options"
+
+type Transition = RevealerProps["transition"]
+type Child = WindowProps["child"]
+
+type PopupWindowProps = Omit<WindowProps, "name"> & {
+ name: string
+ layout?: keyof ReturnType<typeof Layout>
+ 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<Gtk.Widget>({
+ 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/linux/home/.config/ags/widget/RegularWindow.ts b/linux/home/.config/ags/widget/RegularWindow.ts
new file mode 100644
index 0000000..1e4225d
--- /dev/null
+++ b/linux/home/.config/ags/widget/RegularWindow.ts
@@ -0,0 +1,3 @@
+import Gtk from "gi://Gtk?version=3.0"
+
+export default Widget.subclass<typeof Gtk.Window, Gtk.Window.ConstructorProperties>(Gtk.Window)
diff --git a/linux/home/.config/ags/widget/bar/Bar.ts b/linux/home/.config/ags/widget/bar/Bar.ts
new file mode 100644
index 0000000..9343a36
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/Bar.ts
@@ -0,0 +1,57 @@
+import BatteryBar from "./buttons/BatteryBar"
+import ColorPicker from "./buttons/ColorPicker"
+import Date from "./buttons/Date"
+import Launcher from "./buttons/Launcher"
+import Media from "./buttons/Media"
+import PowerMenu from "./buttons/PowerMenu"
+import SysTray from "./buttons/SysTray"
+import SystemIndicators from "./buttons/SystemIndicators"
+import Taskbar from "./buttons/Taskbar"
+import Workspaces from "./buttons/Workspaces"
+import ScreenRecord from "./buttons/ScreenRecord"
+import Messages from "./buttons/Messages"
+import options from "options"
+
+const { start, center, end } = options.bar.layout
+const pos = options.bar.position.bind()
+
+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,
+ messages: Messages,
+ expander: () => Widget.Box({ expand: true }),
+}
+
+export default (monitor: number) => Widget.Window({
+ monitor,
+ class_name: "bar",
+ name: `bar${monitor}`,
+ exclusivity: "exclusive",
+ anchor: pos.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]())),
+ }),
+ }),
+})
diff --git a/linux/home/.config/ags/widget/bar/PanelButton.ts b/linux/home/.config/ags/widget/bar/PanelButton.ts
new file mode 100644
index 0000000..332b46d
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/PanelButton.ts
@@ -0,0 +1,46 @@
+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/linux/home/.config/ags/widget/bar/ScreenCorners.ts b/linux/home/.config/ags/widget/bar/ScreenCorners.ts
new file mode 100644
index 0000000..1b35e50
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/ScreenCorners.ts
@@ -0,0 +1,25 @@
+import options from "options"
+
+const { corners } = 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)
+ }),
+})
diff --git a/linux/home/.config/ags/widget/bar/bar.scss b/linux/home/.config/ags/widget/bar/bar.scss
new file mode 100644
index 0000000..5c6c2cd
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/bar.scss
@@ -0,0 +1,242 @@
+@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;
+ background-color: $bg;
+ }
+
+ label,
+ image {
+ font-weight: bold;
+ }
+
+ >* {
+ padding: $padding * 0.8 $padding * 1.2;
+ }
+}
+
+.bar {
+ .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;
+ }
+
+ &.inctive {
+ // background-color: $primary-bg;
+ background-image: $active-gradient;
+ min-width: 20pt;
+ min-height: 12pt;
+ }
+ }
+
+ &.inactive,
+ &:active {
+ label {
+ background-color: transparentize($primary-fg, 0.3);
+
+ &.occupied {
+ background-color: transparentize($primary-fg, 0.15);
+ }
+
+ &.active {
+ background-color: $primary-fg;
+ }
+
+ &.inactive {
+ background-color: $primary-fg;
+ }
+ }
+ }
+ }
+
+ .media 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;
+ }
+ }
+}
diff --git a/linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts b/linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts
new file mode 100644
index 0000000..18de329
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts
@@ -0,0 +1,94 @@
+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/linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts b/linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts
new file mode 100644
index 0000000..5b1f3f6
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts
@@ -0,0 +1,37 @@
+import PanelButton from "../PanelButton"
+import colorpicker from "service/colorpicker"
+import Gdk from "gi://Gdk"
+
+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/linux/home/.config/ags/widget/bar/buttons/Date.ts b/linux/home/.config/ags/widget/bar/buttons/Date.ts
new file mode 100644
index 0000000..44c2540
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/Date.ts
@@ -0,0 +1,15 @@
+import { clock } from "lib/variables"
+import PanelButton from "../PanelButton"
+import options from "options"
+
+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/linux/home/.config/ags/widget/bar/buttons/Launcher.ts b/linux/home/.config/ags/widget/bar/buttons/Launcher.ts
new file mode 100644
index 0000000..f3fee6b
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/Launcher.ts
@@ -0,0 +1,49 @@
+import PanelButton from "../PanelButton"
+import options from "options"
+import nix from "service/nix"
+
+const { icon, label, action } = options.bar.launcher
+
+function Spinner() {
+ const child = Widget.Icon({
+ icon: icon.icon.bind(),
+ class_name: Utils.merge([
+ icon.colored.bind(),
+ nix.bind("ready"),
+ ], (c, r) => `${c ? "colored" : ""} ${r ? "" : "spinning"}`),
+ css: `
+ @keyframes spin {
+ to { -gtk-icon-transform: rotate(1turn); }
+ }
+
+ image.spinning {
+ animation-name: spin;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ }
+ `,
+ })
+
+ return Widget.Revealer({
+ transition: "slide_left",
+ child,
+ reveal_child: Utils.merge([
+ icon.icon.bind(),
+ nix.bind("ready"),
+ ], (i, r) => Boolean(i || r)),
+ })
+}
+
+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/linux/home/.config/ags/widget/bar/buttons/Media.ts b/linux/home/.config/ags/widget/bar/buttons/Media.ts
new file mode 100644
index 0000000..b3aab61
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/Media.ts
@@ -0,0 +1,92 @@
+import { type MprisPlayer } from "types/service/mpris"
+import PanelButton from "../PanelButton"
+import options from "options"
+import icons from "lib/icons"
+import { icon } from "lib/utils"
+
+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/linux/home/.config/ags/widget/bar/buttons/Messages.ts b/linux/home/.config/ags/widget/bar/buttons/Messages.ts
new file mode 100644
index 0000000..a8971e9
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/Messages.ts
@@ -0,0 +1,16 @@
+import icons from "lib/icons"
+import PanelButton from "../PanelButton"
+import options from "options"
+
+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/linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts b/linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts
new file mode 100644
index 0000000..4432ade
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts
@@ -0,0 +1,15 @@
+import icons from "lib/icons"
+import PanelButton from "../PanelButton"
+import options from "options"
+
+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/linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts b/linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts
new file mode 100644
index 0000000..1d6eb36
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts
@@ -0,0 +1,21 @@
+import PanelButton from "../PanelButton"
+import screenrecord from "service/screenrecord"
+import icons from "lib/icons"
+
+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/linux/home/.config/ags/widget/bar/buttons/SysTray.ts b/linux/home/.config/ags/widget/bar/buttons/SysTray.ts
new file mode 100644
index 0000000..9f569d1
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/SysTray.ts
@@ -0,0 +1,39 @@
+import { type TrayItem } from "types/service/systemtray"
+import PanelButton from "../PanelButton"
+import Gdk from "gi://Gdk"
+import options from "options"
+
+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/linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts b/linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts
new file mode 100644
index 0000000..cc98548
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts
@@ -0,0 +1,107 @@
+import PanelButton from '../PanelButton';
+import icons from 'lib/icons';
+import asusctl from 'service/asusctl';
+
+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,
+ child: Widget.Icon({
+ icon: icons.bluetooth.enabled,
+ visible: bluetooth.bind('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(),
+ MicrophoneIndicator(),
+ AudioIndicator(),
+ NetworkIndicator(),
+ ]),
+ });
diff --git a/linux/home/.config/ags/widget/bar/buttons/Taskbar.ts b/linux/home/.config/ags/widget/bar/buttons/Taskbar.ts
new file mode 100644
index 0000000..b9c65fa
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/Taskbar.ts
@@ -0,0 +1,90 @@
+import { launchApp, icon } from "lib/utils"
+import icons from "lib/icons"
+import options from "options"
+import PanelButton from "../PanelButton"
+
+const hyprland = await Service.import("hyprland")
+const apps = await Service.import("applications")
+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 = apps.list.find(app => app.match(client.class))
+
+ const btn = PanelButton({
+ class_name: "panel-button",
+ tooltip_text: Utils.watch(client.title, hyprland, () =>
+ hyprland.getClient(address)?.title || "",
+ ),
+ on_primary_click: () => focus(address),
+ on_middle_click: () => app && launchApp(app),
+ child: Widget.Icon({
+ size: iconSize.bind(),
+ icon: monochrome.bind().as(m => icon(
+ (app?.icon_name || client.class) + (m ? "-symbolic" : ""),
+ icons.fallback.executable + (m ? "-symbolic" : ""),
+ )),
+ }),
+ })
+
+ 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<T extends { attribute: { address: string } }>(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/linux/home/.config/ags/widget/bar/buttons/Workspaces.ts b/linux/home/.config/ags/widget/bar/buttons/Workspaces.ts
new file mode 100644
index 0000000..a59f61b
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/buttons/Workspaces.ts
@@ -0,0 +1,66 @@
+import PanelButton from '../PanelButton';
+import options from 'options';
+import { sh, range } from 'lib/utils';
+
+const hyprland = await Service.import('hyprland');
+const { workspaces } = options.bar.workspaces;
+
+const dispatch = arg => {
+ sh(`hyprctl dispatch workspace ${arg}`);
+};
+
+const Workspaces = ws =>
+ Widget.Box({
+ children: range(ws || 20).map(i =>
+ Widget.Label({
+ attribute: i,
+ vpack: 'center',
+ label: `${i}`,
+ setup: self => {
+ const updateState = () => {
+ const monitorData = JSON.parse(hyprland.message('j/monitors'));
+ const activeWorkspaceId = monitorData[0]?.activeWorkspace?.id;
+ const workspaceData = hyprland.getWorkspace(i);
+
+ if (activeWorkspaceId !== undefined) {
+ self.toggleClassName('active', activeWorkspaceId === i);
+ }
+ self.toggleClassName('occupied', (workspaceData?.windows || 0) > 0);
+ };
+
+ // Hook to Hyprland for updates
+ self.hook(hyprland, updateState);
+
+ // Initial update
+ updateState();
+ },
+ }),
+ ),
+ setup: box => {
+ box.hook(hyprland, () => {
+ const monitorData = JSON.parse(hyprland.message('j/monitors'));
+ const activeWorkspaceId = monitorData[0]?.activeWorkspace?.id;
+
+ if (activeWorkspaceId !== undefined) {
+ for (const btn of box.children) {
+ const workspaceId = btn.attribute;
+ btn.toggleClassName('active', workspaceId === activeWorkspaceId);
+
+ if (ws === 0) {
+ btn.visible = hyprland.workspaces.some(workspace => workspace.id === workspaceId);
+ }
+ }
+ }
+ });
+ },
+ });
+
+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/linux/home/.config/ags/widget/bar/screencorner.scss b/linux/home/.config/ags/widget/bar/screencorner.scss
new file mode 100644
index 0000000..93cd459
--- /dev/null
+++ b/linux/home/.config/ags/widget/bar/screencorner.scss
@@ -0,0 +1,51 @@
+$_shadow-size: $padding;
+$_radius: $radius * $hyprland-gaps-multiplier;
+$_margin: 99px;
+
+window.screen-corner {
+ box.shadow {
+ margin-right: $_margin * -1;
+ margin-left: $_margin * -1;
+
+ @if $shadows {
+ box-shadow: inset 0 0 $_shadow-size 0 transparent;
+ }
+
+ @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 none $bg;
+ //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 * $hyprland-gaps-multiplier, 0);
+ box-shadow: 0 0 0 $_radius $bg;
+ }
+
+ box.corner {
+ border-radius: if($radius>0, $radius * $hyprland-gaps-multiplier, 0);
+ }
+ }
+}
diff --git a/linux/home/.config/ags/widget/datemenu/DateColumn.ts b/linux/home/.config/ags/widget/datemenu/DateColumn.ts
new file mode 100644
index 0000000..a462302
--- /dev/null
+++ b/linux/home/.config/ags/widget/datemenu/DateColumn.ts
@@ -0,0 +1,58 @@
+import { clock, uptime } from 'lib/variables';
+import GLib from 'gi://GLib';
+import Gtk from 'gi://Gtk';
+
+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: [
+ (() => {
+ const calendar = Widget.Calendar({
+ hexpand: true,
+ hpack: 'center',
+ });
+
+ // Get today's date and mark it
+ const today = new Date();
+ calendar.select_day(today.getDate());
+ calendar.select_month(today.getMonth(), today.getFullYear());
+ calendar.mark_day(today.getDate()); // This should trigger styling
+
+ // Prevent scrolling from triggering GNOME Calendar
+ const eventBox = Widget.EventBox({
+ child: calendar,
+ onPrimaryClick: () => {
+ GLib.spawn_command_line_async('gnome-calendar');
+ },
+ });
+
+ return eventBox;
+ })(),
+ ],
+ }),
+ ],
+ });
diff --git a/linux/home/.config/ags/widget/datemenu/DateMenu.ts b/linux/home/.config/ags/widget/datemenu/DateMenu.ts
new file mode 100644
index 0000000..f7fdf6d
--- /dev/null
+++ b/linux/home/.config/ags/widget/datemenu/DateMenu.ts
@@ -0,0 +1,36 @@
+import PopupWindow from "widget/PopupWindow"
+import NotificationColumn from "./NotificationColumn"
+import DateColumn from "./DateColumn"
+import options from "options"
+
+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/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts b/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts
new file mode 100644
index 0000000..07d6829
--- /dev/null
+++ b/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts
@@ -0,0 +1,113 @@
+import { type Notification as Notif } from "types/service/notifications"
+import Notification from "widget/notifications/Notification"
+import options from "options"
+import icons from "lib/icons"
+
+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<number, ReturnType<typeof Animated>> = 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/linux/home/.config/ags/widget/datemenu/datemenu.scss b/linux/home/.config/ags/widget/datemenu/datemenu.scss
new file mode 100644
index 0000000..6fd9257
--- /dev/null
+++ b/linux/home/.config/ags/widget/datemenu/datemenu.scss
@@ -0,0 +1,110 @@
+@import "../notifications/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: .2em;
+ }
+}
+
+window#datemenu .datemenu {
+ @include floating-widget;
+
+ .notifications {
+ .header {
+ margin-bottom: $spacing;
+ margin-right: $spacing;
+
+ >label {
+ margin-left: $radius * .5;
+ }
+
+ button {
+ @include button;
+ padding: $padding*.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/linux/home/.config/ags/widget/desktop/Desktop.ts b/linux/home/.config/ags/widget/desktop/Desktop.ts
new file mode 100644
index 0000000..f711967
--- /dev/null
+++ b/linux/home/.config/ags/widget/desktop/Desktop.ts
@@ -0,0 +1,40 @@
+import options from "options"
+import { matugen } from "lib/matugen"
+const mpris = await Service.import("mpris")
+
+const pref = () => options.bar.media.preferred.value
+
+export default (monitor: number) => Widget.Window({
+ monitor,
+ layer: "bottom",
+ name: `desktop${monitor}`,
+ class_name: "desktop",
+ anchor: ["top", "bottom", "left", "right"],
+ child: Widget.Box({
+ expand: true,
+ css: options.theme.dark.primary.bg.bind().as(c => `
+ transition: 500ms;
+ background-color: ${c}`),
+ child: Widget.Box({
+ class_name: "wallpaper",
+ expand: true,
+ vpack: "center",
+ hpack: "center",
+ setup: self => self
+ .hook(mpris, () => {
+ const img = mpris.getPlayer(pref())!.cover_path
+ matugen("image", img)
+ Utils.timeout(500, () => self.css = `
+ background-image: url('${img}');
+ background-size: contain;
+ background-repeat: no-repeat;
+ transition: 200ms;
+ min-width: 700px;
+ min-height: 700px;
+ border-radius: 30px;
+ box-shadow: 25px 25px 30px 0 rgba(0,0,0,0.5);`,
+ )
+ }),
+ }),
+ }),
+})
diff --git a/linux/home/.config/ags/widget/dock/Dock.ts b/linux/home/.config/ags/widget/dock/Dock.ts
new file mode 100644
index 0000000..c55f89f
--- /dev/null
+++ b/linux/home/.config/ags/widget/dock/Dock.ts
@@ -0,0 +1,150 @@
+import { launchApp } from "lib/utils";
+import options from "options";
+import * as Gtk from "gi://Gtk?version=3.0";
+import { type ButtonProps } from "types/widgets/button";
+import { type BoxProps } from "types/widgets/box";
+
+const hyprland = await Service.import("hyprland");
+const applications = await Service.import("applications");
+
+const focus = (address: string) => hyprland.messageAsync(`dispatch focuswindow address:${address}`);
+
+const AppButton = ({ icon, pinned = false, term, ...rest }: ButtonProps & { term?: string }): Gtk.Button & ButtonProps => {
+ const { iconSize } = options.dock;
+
+ const buttonBox = Widget.Box({
+ class_name: 'box',
+ child: Widget.Icon({
+ icon,
+ size: iconSize,
+ }),
+ });
+
+ const button = Widget.Button({
+ ...rest,
+ class_name: '',
+ child: pinned ? buttonBox : Widget.Overlay({
+ child: buttonBox,
+ pass_through: false,
+ overlays: [],
+ }),
+ });
+
+ return Object.assign(button, {});
+};
+
+const createAppButton = ({ app, term, ...params }) => {
+ return AppButton({
+ icon: app.icon_name || '',
+ term,
+ ...params,
+ });
+};
+
+const filterValidClients = (clients: any[]) => {
+ return clients.filter(client => (
+ client.mapped &&
+ [client.class, client.title, client.initialClass].every(prop => typeof prop === 'string' && prop !== '')
+ ));
+};
+
+const Taskbar = (): Gtk.Box & BoxProps => {
+ const addedApps = new Set<string>();
+
+ const updateTaskbar = (clients: any[]) => {
+ const validClients = filterValidClients(clients);
+
+ const focusedAddress = hyprland?.active.client?.address;
+ const running = validClients.filter(client => client.mapped);
+ const focused = running.find(client => client.address === focusedAddress);
+
+ return validClients.map(client => {
+ if (![client.class, client.title, client.initialClass].every(prop => typeof prop === 'string' && prop !== '')) {
+ return null;
+ }
+
+ if (addedApps.has(client.title)) {
+ return null;
+ }
+
+ for (const appName of options.dock.pinnedApps.value) {
+ if (!appName || typeof appName !== 'string') {
+ continue;
+ }
+
+ if (client.class.includes(appName) || client.title.includes(appName)
+ || client.initialClass.includes(appName)) {
+ return null;
+ }
+ }
+
+ const matchingApp = applications?.list.find(app => (
+ app.match(client.title) || app.match(client.class) || app.match(client.initialClass)
+ ));
+
+ if (matchingApp) {
+ addedApps.add(client.title);
+ return createAppButton({
+ app: matchingApp,
+ term: matchingApp.title,
+ on_primary_click: () => {
+ const clickAddress = client.address || focusedAddress;
+ clickAddress && focus(clickAddress);
+ },
+ on_secondary_click: () => launchApp(matchingApp),
+ });
+ a
+ }
+ return null;
+ });
+ };
+
+ return Widget.Box({
+ vertical: false,
+ })
+ .bind('children', hyprland, 'clients', updateTaskbar);
+};
+
+const PinnedApps = (): Gtk.Box & BoxProps => {
+ const updatePinnedApps = (pinnedApps: string[]) => {
+ return pinnedApps
+ .map(term => ({ app: applications?.query(term)?.[0], term }))
+ .filter(({ app }) => app)
+ .map(({ app, term = true }) => createAppButton({
+ app,
+ term,
+ pinned: true,
+ on_primary_click: () => {
+ const matchingClients = hyprland?.clients.filter(client => (
+ typeof client.class === 'string' &&
+ typeof client.title === 'string' &&
+ typeof client.initialClass === 'string' &&
+ (client.class.includes(term) || client.title.includes(term) || client.initialClass.includes(term))
+ ));
+
+ if (matchingClients.length > 0) {
+ const { address } = matchingClients[0];
+ address && focus(address);
+ } else {
+ launchApp(app);
+ }
+ },
+ on_secondary_click: () => launchApp(app),
+ }));
+ };
+
+ return Widget.Box({
+ class_name: 'pins',
+ vertical: false,
+ homogeneous: true,
+ })
+ .bind('children', options.dock.pinnedApps, 'value', updatePinnedApps);
+};
+
+const Dock = (): Gtk.Box & BoxProps => Widget.Box({
+ class_name: 'dock',
+ vertical: false,
+ children: [PinnedApps(), Taskbar()],
+});
+
+export default Dock;
diff --git a/linux/home/.config/ags/widget/dock/FloatingDock.ts b/linux/home/.config/ags/widget/dock/FloatingDock.ts
new file mode 100644
index 0000000..369f56f
--- /dev/null
+++ b/linux/home/.config/ags/widget/dock/FloatingDock.ts
@@ -0,0 +1,70 @@
+import options from 'options';
+import Dock from './Dock.ts';
+const hyprland = await Service.import('hyprland');
+const apps = await Service.import('applications');
+
+const { Gdk, Gtk } = imports.gi;
+import type Gtk from 'gi://Gtk?version=3.0';
+import { type WindowProps } from 'types/widgets/window';
+import { type RevealerProps } from 'types/widgets/revealer';
+import { type EventBoxProps } from 'types/widgets/eventbox';
+
+/** @param {number} monitor */
+const FloatingDock = (monitor: number): Gtk.Window & WindowProps => {
+ const update = () => {
+ const ws = Hyprland.getWorkspace(Hyprland.active.workspace.id);
+ if (Hyprland.getMonitor(monitor)?.name === ws?.monitor) self.reveal_child = ws?.windows === 0;
+ };
+ const revealer: Gtk.Revealer & RevealerProps = Widget.Revealer({
+ transition: 'slide_up',
+ transitionDuration: 90,
+ child: Dock(),
+ setup: self => self.hook(hyprland, update, 'client-added').hook(hyprland, update, 'client-removed').hook(hyprland.active.workspace, update),
+ });
+
+ const window = Widget.Window({
+ monitor,
+ //halign: 'fill',
+ halign: 'end',
+ //layer: "overlay",
+ layer: 'dock',
+ name: `dock${monitor}`,
+ click_through: false,
+ class_name: 'floating-dock',
+ // class_name: 'floating-dock-no-gap',
+ // class_name: "f-dock-wrap",
+
+ typeHint: Gdk.WindowTypeHint.DOCK,
+ exclusivity: 'false',
+
+ anchor: ['bottom'],
+ child: Widget.Box({
+ vertical: false,
+ halign: 'bottom',
+ hpack: 'start',
+ children: [
+ revealer,
+ Widget.Box({
+ class_name: 'padding',
+ css: 'padding: 9px; margin: 0;',
+ vertical: false,
+ halign: 'bottom',
+ hpack: 'start',
+ }),
+ ],
+ }),
+ });
+
+ window
+ .on('enter-notify-event', () => {
+ revealer.reveal_child = true;
+ })
+ .on('leave-notify-event', () => {
+ revealer.reveal_child = false;
+ })
+ .bind('visible', options.bar.position, 'value', v => v !== 'left');
+
+ return window;
+};
+
+export default FloatingDock;
diff --git a/linux/home/.config/ags/widget/dock/ToolBox.ts b/linux/home/.config/ags/widget/dock/ToolBox.ts
new file mode 100644
index 0000000..51fda72
--- /dev/null
+++ b/linux/home/.config/ags/widget/dock/ToolBox.ts
@@ -0,0 +1,122 @@
+import options from "options";
+import { sh } from "lib/utils";
+import * as Gtk from "gi://Gtk?version=3.0";
+import { type ButtonProps } from "types/widgets/button";
+import { type BoxProps } from "types/widgets/box";
+
+const hyprland = await Service.import("hyprland");
+const { icons } = options.dock.toolbox;
+const buttonToggles = {};
+
+const dispatch = (action: string, arg: string) => {
+ //console.log(`Performing action: ${action} with argument: ${arg}`);
+ sh(`hyprctl dispatch ${action} ${arg}`);
+};
+
+const keyword = (action: string, arg: string) => {
+ //console.log(`Performing action: ${action} with argument: ${arg}`);
+ sh(`hyprctl keyword ${action} ${arg}`);
+};
+
+const ToggleSwitch = (buttonIndex, actionOn, argOn, actionOff, argOff, actionExec) => {
+ buttonToggles[buttonIndex] = !buttonToggles[buttonIndex];
+ const { action, arg } = buttonToggles[buttonIndex] ? { action: actionOn, arg: argOn } : { action: actionOff, arg: argOff };
+ actionExec(action, arg);
+};
+
+const ToggleOnMulti = (buttonIndex, actionOn, argOn, actionOff, argOff, actionExec) => {
+ buttonToggles[buttonIndex] = !buttonToggles[buttonIndex];
+ if (buttonToggles[buttonIndex]) {
+ actionOn.forEach(({ action, arg }) => {
+ actionExec(action, arg);
+ });
+ } else {
+ actionExec(actionOff, argOff);
+ }
+};
+
+const execAction = (trigger, actionIndex, actionOn, argOn, actionOff, argOff, action, arg, actionExec) => {
+ switch (trigger) {
+ case 'toggleOn-multi':
+ ToggleOnMulti(actionIndex, actionOn, argOn, actionOff, argOff, actionExec);
+ break;
+ case 'toggle-switch':
+ ToggleSwitch(actionIndex, actionOn, argOn, actionOff, argOff, actionExec);
+ break;
+ case 'oneshot':
+ actionExec(action, arg);
+ break;
+ default:
+ break;
+ }
+};
+
+const buttonConfigs = [
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 0, action: 'killactive', arg: '' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 1, action: 'exec hyprctl', arg: 'kill' },
+ {
+ actionExec: keyword,
+ trigger: 'toggle-switch',
+ actionIndex: 2,
+ actionOn: 'monitor', argOn: 'eDP-1,2736x1824,0x0,0,transform,1',
+ actionOff: 'monitor', argOff: 'eDP-1,2736x1824,0x0,0,transform,0'
+ },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 3, action: 'workspace', arg: 'r-1' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 4, action: 'workspace', arg: 'r+1' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 5, action: 'movewindow', arg: 'l' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 6, action: 'movewindow', arg: 'r' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 7, action: 'movewindow', arg: 'u' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 8, action: 'movewindow', arg: 'd' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 9, action: 'swapnext', arg: 'next' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 10, action: 'togglesplit', arg: '' },
+ {
+ actionExec: dispatch,
+ trigger: 'toggleOn-multi',
+ actionIndex: 11,
+ actionOn: [
+ { action: 'setfloating', arg: 'active' },
+ { action: 'resizeactive', arg: 'exact 90% 90%' },
+ { action: 'centerwindow', arg: '' },
+ ],
+ actionOff: 'settiled', argOff: 'active'
+ },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 12, action: 'pin', arg: '' },
+ { actionExec: dispatch, trigger: 'oneshot', actionIndex: 13, action: 'fullscreen', arg: '0' },
+ {
+ actionExec: dispatch,
+ trigger: 'toggle-switch',
+ actionIndex: 14,
+ actionOn: 'exec', argOn: 'wvctl 1',
+ actionOff: 'exec', argOff: 'wvctl 0'
+ },
+];
+
+const ToolBox = () => {
+ const ToolBoxButtons = () => {
+ const buttons = buttonConfigs.map(({ actionIndex, actionOn, argOn, actionOff, argOff, actionExec, trigger, action, arg }) => {
+ const execActionWrapper = () => execAction(trigger, actionIndex, actionOn, argOn, actionOff, argOff, action, arg, actionExec);
+
+ return Widget.Button({
+ child: Widget.Icon({
+ icon: icons[actionIndex].bind(),
+ }),
+ on_clicked: execActionWrapper,
+ });
+ });
+
+ return Widget.Box({
+ vertical: true,
+ homogeneous: true,
+ children: buttons,
+ });
+ };
+
+ return Widget.Box({
+ class_name: "toolbox",
+ vertical: true,
+ homogeneous: true,
+ children: [ToolBoxButtons()],
+ });
+};
+
+export default ToolBox;
diff --git a/linux/home/.config/ags/widget/dock/ToolBoxDock.ts b/linux/home/.config/ags/widget/dock/ToolBoxDock.ts
new file mode 100644
index 0000000..21beaeb
--- /dev/null
+++ b/linux/home/.config/ags/widget/dock/ToolBoxDock.ts
@@ -0,0 +1,57 @@
+import options from "options";
+import ToolBox from "./ToolBox.ts";
+const hyprland = await Service.import("hyprland");
+const apps = await Service.import("applications");
+
+import type Gtk from "gi://Gtk?version=3.0";
+import { type WindowProps } from "types/widgets/window";
+import { type RevealerProps } from "types/widgets/revealer";
+import { type EventBoxProps } from "types/widgets/eventbox";
+
+/** @param {number} monitor */
+const ToolBoxDock = (monitor: number): Gtk.Window & WindowProps => {
+
+ const revealer: Gtk.Revealer & RevealerProps = Widget.Revealer({
+ transition: 'slide_left',
+ transitionDuration: 50,
+ child: ToolBox(),
+ });
+
+ const window = Widget.Window({
+ monitor,
+ halign: 'fill',
+ layer: "overlay",
+ name: `toolbox${monitor}`,
+ click_through: false,
+ class_name: 'floating-toolbox',
+ anchor: ['right'],
+ child: Widget.Box({
+ vertical: true,
+ halign: 'top',
+ hpack: 'fill',
+ children: [
+ revealer,
+ Widget.Box({
+ class_name: 'padding',
+ css: 'padding: 14px;',
+ vertical: true,
+ halign: 'top',
+ hpack: 'fill',
+ }),
+ ],
+ }),
+ });
+
+ window
+ .on('enter-notify-event', () => {
+ revealer.reveal_child = true;
+ })
+ .on('leave-notify-event', () => {
+ revealer.reveal_child = false;
+ })
+ .bind('visible', options.bar.position, 'value', v => v !== 'left');
+
+ return window;
+};
+
+export default ToolBoxDock;
diff --git a/linux/home/.config/ags/widget/dock/dock.scss b/linux/home/.config/ags/widget/dock/dock.scss
new file mode 100644
index 0000000..9dc6256
--- /dev/null
+++ b/linux/home/.config/ags/widget/dock/dock.scss
@@ -0,0 +1,73 @@
+@use 'sass:color';
+
+.floating-dock {
+ padding-left: 0.2rem;
+ padding-right: 0.2rem;
+ padding-top: 0.3rem;
+ padding-bottom: 0.3rem;
+ border-radius: 1rem;
+}
+
+.dock {
+ // @include floating-widget;
+ border-radius: $radius;
+ background-color: transparentize($bg, 0.07);
+ min-width: 0;
+ padding: 6;
+
+ // Common styles for both PinnedApps and Taskbar buttons
+ button {
+ @include button($flat: true);
+ border-radius: 4;
+ padding: 2;
+
+ .box {
+ margin: 0em;
+ min-width: 1em;
+ min-height: 0em;
+ padding: 0;
+ }
+
+ image {
+ margin: 0px;
+ }
+
+ .indicator {
+ background-color: transparentize($primary-bg, 0.3);
+ border-radius: $radius;
+ min-height: 1pt;
+ min-width: 16pt;
+ margin: 1pt;
+ }
+ }
+}
+
+.toolbox {
+ // @include floating-widget;
+ border-radius: $radius;
+ background-color: transparentize($bg, 0.07);
+ min-width: 0;
+ padding: 6;
+
+ // Common styles for both PinnedApps and Taskbar buttons
+ button {
+ @include button($flat: true);
+ border-radius: 0;
+ padding: 0;
+
+ image {
+ margin: 0px;
+ font-size: 32px;
+ }
+
+ &:hover,
+ &:active,
+ &:focus {
+ // Override hover, active, and focus styles for buttons in .toolbox
+ background-color: transparent;
+ border: none;
+ box-shadow: none;
+ outline: none;
+ }
+ }
+}
diff --git a/linux/home/.config/ags/widget/launcher/AppLauncher.ts b/linux/home/.config/ags/widget/launcher/AppLauncher.ts
new file mode 100644
index 0000000..08258de
--- /dev/null
+++ b/linux/home/.config/ags/widget/launcher/AppLauncher.ts
@@ -0,0 +1,125 @@
+import { type Application } from 'types/service/applications';
+import { launchApp, icon } from 'lib/utils';
+import options from 'options';
+import icons from 'lib/icons';
+
+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, {
+ 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/linux/home/.config/ags/widget/launcher/Launcher.ts b/linux/home/.config/ags/widget/launcher/Launcher.ts
new file mode 100644
index 0000000..90b4d58
--- /dev/null
+++ b/linux/home/.config/ags/widget/launcher/Launcher.ts
@@ -0,0 +1,134 @@
+import { type Binding } from 'lib/utils';
+import PopupWindow, { Padding } from 'widget/PopupWindow';
+import icons from 'lib/icons';
+import options from 'options';
+import nix from 'service/nix';
+import * as AppLauncher from './AppLauncher';
+import * as NixRun from './NixRun';
+import * as ShRun from './ShRun';
+
+const { width, margin } = options.launcher;
+const isnix = nix.available;
+
+function Launcher() {
+ const favs = AppLauncher.Favorites();
+ const applauncher = AppLauncher.Launcher();
+ const sh = ShRun.ShRun();
+ const shicon = ShRun.Icon();
+ const nix = NixRun.NixRun();
+ const nixload = NixRun.Spinner();
+
+ function HelpButton(cmd: string, desc: string | Binding<string>) {
+ 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'),
+ isnix
+ ? HelpButton(
+ 'nx',
+ options.launcher.nix.pkgs.bind().as(pkg => `run a nix package from ${pkg}`),
+ )
+ : Widget.Box(),
+ ),
+ });
+
+ const entry = Widget.Entry({
+ hexpand: true,
+ primary_icon_name: icons.ui.search,
+ on_accept: ({ text }) => {
+ if (text?.startsWith(':nx')) nix.run(text.substring(3));
+ else if (text?.startsWith(':sh')) sh.run(text.substring(3));
+ else applauncher.launchFirst();
+
+ App.toggleWindow('launcher');
+ entry.text = '';
+ },
+ on_change: ({ text }) => {
+ text ||= '';
+ favs.reveal_child = text === '';
+ help.reveal_child = text.split(' ').length === 1 && text?.startsWith(':');
+
+ if (text?.startsWith(':nx')) nix.filter(text.substring(3));
+ else nix.filter('');
+
+ if (text?.startsWith(':sh')) sh.filter(text.substring(3));
+ else sh.filter('');
+
+ if (!text?.startsWith(':')) applauncher.filter(text);
+ },
+ });
+
+ function focus() {
+ entry.text = '';
+ entry.set_position(-1);
+ entry.select_region(0, -1);
+ entry.grab_focus();
+ favs.reveal_child = true;
+ }
+
+ 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, nixload, shicon]),
+ favs,
+ help,
+ applauncher,
+ //nix,
+ sh,
+ ],
+ });
+
+ return Widget.Box(
+ { vertical: true, css: 'padding: 1px' },
+ Padding('applauncher', {
+ css: margin.bind().as(v => `min-height: ${v}pt;`),
+ vexpand: false,
+ }),
+ layout,
+ );
+}
+
+export default () =>
+ PopupWindow({
+ name: 'launcher',
+ layout: 'top',
+ child: Launcher(),
+ });
diff --git a/linux/home/.config/ags/widget/launcher/NixRun.ts b/linux/home/.config/ags/widget/launcher/NixRun.ts
new file mode 100644
index 0000000..cec9e09
--- /dev/null
+++ b/linux/home/.config/ags/widget/launcher/NixRun.ts
@@ -0,0 +1,118 @@
+import icons from "lib/icons"
+import nix, { type Nixpkg } from "service/nix"
+
+const iconVisible = Variable(false)
+
+function Item(pkg: Nixpkg) {
+ const name = Widget.Label({
+ class_name: "name",
+ label: pkg.name.split(".").at(-1),
+ })
+
+ const subpkg = pkg.name.includes(".") ? Widget.Label({
+ class_name: "description",
+ hpack: "end",
+ hexpand: true,
+ label: ` ${pkg.name.split(".").slice(0, -1).join(".")}`,
+ }) : null
+
+ const version = Widget.Label({
+ class_name: "version",
+ label: pkg.version,
+ hexpand: true,
+ hpack: "end",
+ })
+
+ const description = pkg.description ? Widget.Label({
+ class_name: "description",
+ label: pkg.description,
+ justification: "left",
+ wrap: true,
+ hpack: "start",
+ max_width_chars: 40,
+ }) : null
+
+ return Widget.Box(
+ {
+ attribute: { name: pkg.name },
+ vertical: true,
+ },
+ Widget.Separator(),
+ Widget.Button(
+ {
+ class_name: "nix-item",
+ on_clicked: () => {
+ nix.run(pkg.name)
+ App.closeWindow("launcher")
+ },
+ },
+ Widget.Box(
+ { vertical: true },
+ Widget.Box([name, version]),
+ Widget.Box([
+ description as ReturnType<typeof Widget.Label>,
+ subpkg as ReturnType<typeof Widget.Label>,
+ ]),
+ ),
+ ),
+ )
+}
+
+export function Spinner() {
+ const icon = Widget.Icon({
+ icon: icons.nix.nix,
+ class_name: "spinner",
+ css: `
+ @keyframes spin {
+ to { -gtk-icon-transform: rotate(1turn); }
+ }
+
+ image.spinning {
+ animation-name: spin;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ }
+ `,
+ setup: self => self.hook(nix, () => {
+ self.toggleClassName("spinning", !nix.ready)
+ }),
+ })
+
+ return Widget.Revealer({
+ transition: "slide_left",
+ child: icon,
+ reveal_child: Utils.merge([
+ nix.bind("ready"),
+ iconVisible.bind(),
+ ], (ready, show) => !ready || show),
+ })
+}
+
+export function NixRun() {
+ const list = Widget.Box<ReturnType<typeof Item>>({
+ 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 nix.query(term)
+ list.children = found.map(k => Item(nix.db[k]))
+ revealer.reveal_child = true
+ }
+ }
+
+ return Object.assign(revealer, {
+ filter,
+ run: nix.run,
+ })
+}
diff --git a/linux/home/.config/ags/widget/launcher/ShRun.ts b/linux/home/.config/ags/widget/launcher/ShRun.ts
new file mode 100644
index 0000000..c4215ef
--- /dev/null
+++ b/linux/home/.config/ags/widget/launcher/ShRun.ts
@@ -0,0 +1,89 @@
+import icons from "lib/icons"
+import options from "options"
+import { bash, dependencies } from "lib/utils"
+
+const iconVisible = Variable(false)
+
+const MAX = options.launcher.sh.max
+const BINS = `${Utils.CACHE_DIR}/binaries`
+bash("{ IFS=:; ls -H $PATH; } | sort ")
+ .then(bins => Utils.writeFile(bins, 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)
+ })
+}
+
+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<ReturnType<typeof Item>>({
+ 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 query(term)
+ list.children = found.map(Item)
+ revealer.reveal_child = true
+ }
+ }
+
+ return Object.assign(revealer, { filter, run })
+}
diff --git a/linux/home/.config/ags/widget/launcher/launcher.scss b/linux/home/.config/ags/widget/launcher/launcher.scss
new file mode 100644
index 0000000..926abc3
--- /dev/null
+++ b/linux/home/.config/ags/widget/launcher/launcher.scss
@@ -0,0 +1,143 @@
+@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, .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,
+ button.nix-item {
+ @include button($flat: true, $reactive: false);
+ padding: 0 ($padding * .5);
+
+ label {
+ transition: $transition;
+ color: $fg;
+ }
+
+ .name {
+ font-size: 1.2em;
+ font-weight: bold;
+ }
+
+ .description {
+ color: transparentize($fg, .3)
+ }
+
+ &:hover,
+ &:focus {
+ label {
+ text-shadow: $text-shadow;
+ }
+
+ .name,
+ .version {
+ color: $primary-bg;
+ }
+
+ .description {
+ color: transparentize($primary-bg, .3)
+ }
+ }
+ }
+
+ button.sh-item {
+ @include button($flat: true, $reactive: false);
+ padding: 0 ($padding * .5);
+
+ transition: $transition;
+ color: $fg;
+
+ &:hover,
+ &:focus {
+ color: $primary-bg;
+ text-shadow: $text-shadow;
+ }
+ }
+}
diff --git a/linux/home/.config/ags/widget/notifications/Notification.ts b/linux/home/.config/ags/widget/notifications/Notification.ts
new file mode 100644
index 0000000..c1c8dd8
--- /dev/null
+++ b/linux/home/.config/ags/widget/notifications/Notification.ts
@@ -0,0 +1,138 @@
+import { type Notification } from "types/service/notifications"
+import GLib from "gi://GLib"
+import icons from "lib/icons"
+
+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/linux/home/.config/ags/widget/notifications/NotificationPopups.ts b/linux/home/.config/ags/widget/notifications/NotificationPopups.ts
new file mode 100644
index 0000000..a4a2b54
--- /dev/null
+++ b/linux/home/.config/ags/widget/notifications/NotificationPopups.ts
@@ -0,0 +1,90 @@
+import Notification from "./Notification"
+import options from "options"
+
+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<number, ReturnType<typeof Animated>> = 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/linux/home/.config/ags/widget/notifications/notifications.scss b/linux/home/.config/ags/widget/notifications/notifications.scss
new file mode 100644
index 0000000..369932f
--- /dev/null
+++ b/linux/home/.config/ags/widget/notifications/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: 200px;
+ }
+ }
+}
diff --git a/linux/home/.config/ags/widget/osd/OSD.ts b/linux/home/.config/ags/widget/osd/OSD.ts
new file mode 100644
index 0000000..8239a08
--- /dev/null
+++ b/linux/home/.config/ags/widget/osd/OSD.ts
@@ -0,0 +1,111 @@
+import { icon } from "lib/utils"
+import icons from "lib/icons"
+import Progress from "./Progress"
+import brightness from "service/brightness"
+import options from "options"
+
+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/linux/home/.config/ags/widget/osd/Progress.ts b/linux/home/.config/ags/widget/osd/Progress.ts
new file mode 100644
index 0000000..bcf27da
--- /dev/null
+++ b/linux/home/.config/ags/widget/osd/Progress.ts
@@ -0,0 +1,74 @@
+import type Gtk from "gi://Gtk?version=3.0"
+import GLib from "gi://GLib?version=2.0"
+import { range } from "lib/utils"
+import options from "options"
+
+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/linux/home/.config/ags/widget/osd/osd.scss b/linux/home/.config/ags/widget/osd/osd.scss
new file mode 100644
index 0000000..33df6d2
--- /dev/null
+++ b/linux/home/.config/ags/widget/osd/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/linux/home/.config/ags/widget/overview/Overview.ts b/linux/home/.config/ags/widget/overview/Overview.ts
new file mode 100644
index 0000000..8911920
--- /dev/null
+++ b/linux/home/.config/ags/widget/overview/Overview.ts
@@ -0,0 +1,41 @@
+import PopupWindow from "widget/PopupWindow"
+import Workspace from "./Workspace"
+import options from "options"
+import { range } from "lib/utils"
+
+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/linux/home/.config/ags/widget/overview/Window.ts b/linux/home/.config/ags/widget/overview/Window.ts
new file mode 100644
index 0000000..02f71eb
--- /dev/null
+++ b/linux/home/.config/ags/widget/overview/Window.ts
@@ -0,0 +1,48 @@
+import { type Client } from "types/service/hyprland"
+import { createSurfaceFromWidget, icon } from "lib/utils"
+import Gdk from "gi://Gdk"
+import Gtk from "gi://Gtk?version=3.0"
+import options from "options"
+import icons from "lib/icons"
+
+const monochrome = options.overview.monochromeIcon
+const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)]
+const hyprland = await Service.import("hyprland")
+const apps = await Service.import("applications")
+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 = apps.list.find(app => app.match(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/linux/home/.config/ags/widget/overview/Workspace.ts b/linux/home/.config/ags/widget/overview/Workspace.ts
new file mode 100644
index 0000000..1b8d60b
--- /dev/null
+++ b/linux/home/.config/ags/widget/overview/Workspace.ts
@@ -0,0 +1,76 @@
+import Window from "./Window"
+import Gdk from "gi://Gdk"
+import Gtk from "gi://Gtk?version=3.0"
+import options from "options"
+
+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/linux/home/.config/ags/widget/overview/overview.scss b/linux/home/.config/ags/widget/overview/overview.scss
new file mode 100644
index 0000000..4665b52
--- /dev/null
+++ b/linux/home/.config/ags/widget/overview/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/linux/home/.config/ags/widget/powermenu/PowerMenu.ts b/linux/home/.config/ags/widget/powermenu/PowerMenu.ts
new file mode 100644
index 0000000..fe0a0e9
--- /dev/null
+++ b/linux/home/.config/ags/widget/powermenu/PowerMenu.ts
@@ -0,0 +1,56 @@
+import PopupWindow from "widget/PopupWindow"
+import powermenu, { type Action } from "service/powermenu"
+import icons from "lib/icons"
+import options from "options"
+import type Gtk from "gi://Gtk?version=3.0"
+
+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<Gtk.Widget>({
+ 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/linux/home/.config/ags/widget/powermenu/Verification.ts b/linux/home/.config/ags/widget/powermenu/Verification.ts
new file mode 100644
index 0000000..e85c81a
--- /dev/null
+++ b/linux/home/.config/ags/widget/powermenu/Verification.ts
@@ -0,0 +1,47 @@
+import PopupWindow from "widget/PopupWindow"
+import powermenu from "service/powermenu"
+
+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: () => Utils.exec(powermenu.cmd),
+ }),
+ ],
+ }),
+ ],
+ }),
+})
diff --git a/linux/home/.config/ags/widget/powermenu/powermenu.scss b/linux/home/.config/ags/widget/powermenu/powermenu.scss
new file mode 100644
index 0000000..d5ce0de
--- /dev/null
+++ b/linux/home/.config/ags/widget/powermenu/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, .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 * -.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 * .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/linux/home/.config/ags/widget/quicksettings/QuickSettings.ts b/linux/home/.config/ags/widget/quicksettings/QuickSettings.ts
new file mode 100644
index 0000000..2c0d6ac
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/QuickSettings.ts
@@ -0,0 +1,84 @@
+import type Gtk from "gi://Gtk?version=3.0"
+import { ProfileSelector, ProfileToggle } from "./widgets/PowerProfile"
+import { Header } from "./widgets/Header"
+import { Volume, Microhone, SinkSelector, AppMixer } from "./widgets/Volume"
+import { Brightness } from "./widgets/Brightness"
+import { NetworkToggle, WifiSelection } from "./widgets/Network"
+import { BluetoothToggle, BluetoothDevices } from "./widgets/Bluetooth"
+import { DND } from "./widgets/DND"
+import { DarkModeToggle } from "./widgets/DarkMode"
+import { MicMute } from "./widgets/MicMute"
+import { Media } from "./widgets/Media"
+import PopupWindow from "widget/PopupWindow"
+import options from "options"
+
+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],
+ ),
+ Microhone(),
+ Brightness(),
+ ],
+ }),
+ Row(
+ [NetworkToggle, 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/linux/home/.config/ags/widget/quicksettings/ToggleButton.ts b/linux/home/.config/ags/widget/quicksettings/ToggleButton.ts
new file mode 100644
index 0000000..62a2e67
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/ToggleButton.ts
@@ -0,0 +1,154 @@
+import { type Props as IconProps } from "types/widgets/icon"
+import { type Props as LabelProps } from "types/widgets/label"
+import type GObject from "gi://GObject?version=2.0"
+import type Gtk from "gi://Gtk?version=3.0"
+import icons from "lib/icons"
+
+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/linux/home/.config/ags/widget/quicksettings/quicksettings.scss b/linux/home/.config/ags/widget/quicksettings/quicksettings.scss
new file mode 100644
index 0000000..bd18ff1
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/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(.5);
+ color: transparentize($fg, .15);
+
+ button {
+ @include button;
+ padding: $padding;
+
+ image {
+ font-size: 1.4em;
+ }
+ }
+ }
+
+ .sliders-box {
+ @include widget;
+ padding: $padding;
+
+ button {
+ @include button($flat: true);
+ padding: $padding * .5;
+ }
+
+ .volume button.arrow:last-child {
+ margin-left: $spacing * .4;
+ }
+
+ .volume,
+ .brightness {
+ padding: $padding * .5;
+ }
+
+ scale {
+ @include slider;
+ margin: 0 ($spacing * .5);
+
+ &.muted highlight {
+ background-image: none;
+ background-color: transparentize($fg, $amount: .2);
+ }
+ }
+ }
+
+ .row {
+ @include spacing;
+ }
+
+ .menu {
+ @include unset;
+ @include widget;
+ padding: $padding;
+ margin-top: $spacing;
+
+ .icon {
+ margin: 0 ($spacing * .5);
+ margin-left: $spacing * .2;
+ }
+
+ .title {
+ font-weight: bold;
+ }
+
+ separator {
+ margin: ($radius * .5);
+ background-color: $border-color;
+ }
+
+ button {
+ @include button($flat: true);
+ padding: ($padding * .5);
+
+ image:first-child {
+ margin-right: $spacing * .5;
+ }
+ }
+
+ .bluetooth-devices {
+ @include spacing(.5);
+ }
+
+ switch {
+ @include switch;
+ }
+ }
+
+ .sliders-box .menu {
+ margin: ($spacing * .5) 0;
+
+ &.app-mixer {
+ .mixer-item {
+ padding: $padding * .5;
+ padding-left: 0;
+ padding-right: $padding * 2;
+
+ scale {
+ @include slider($width: .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 * .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 * .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 * .3;
+ }
+
+ image {
+ font-size: 1.3em;
+ }
+ }
+
+ .media {
+ @include spacing;
+
+ .player {
+ @include media;
+ }
+ }
+}
diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts
new file mode 100644
index 0000000..649e654
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts
@@ -0,0 +1,61 @@
+import { type BluetoothDevice } from "types/service/bluetooth"
+import { Menu, ArrowToggleButton } from "../ToggleButton"
+import icons from "lib/icons"
+
+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 === 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/linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts
new file mode 100644
index 0000000..a3ce565
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts
@@ -0,0 +1,23 @@
+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/linux/home/.config/ags/widget/quicksettings/widgets/DND.ts b/linux/home/.config/ags/widget/quicksettings/widgets/DND.ts
new file mode 100644
index 0000000..7fc1fd0
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/DND.ts
@@ -0,0 +1,12 @@
+import { SimpleToggleButton } from "../ToggleButton"
+import icons from "lib/icons"
+
+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/linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts b/linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts
new file mode 100644
index 0000000..9ec94df
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts
@@ -0,0 +1,12 @@
+import { SimpleToggleButton } from "../ToggleButton"
+import icons from "lib/icons"
+import options from "options"
+
+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/linux/home/.config/ags/widget/quicksettings/widgets/Header.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Header.ts
new file mode 100644
index 0000000..44c26f2
--- /dev/null
+++ b/linux/home/.config/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.Label({ label: `${user.name}\n` }),
+ // //Widget.Label({ label: uptime.bind().value }),
+ // Widget.Label({ label: `${user.name}\n ${uptime.bind().value}` }),
+ // //Widget.Icon({ icon: icons.ui.time }),
+ ]),
+
+ ],
+ }),
+ 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/linux/home/.config/ags/widget/quicksettings/widgets/Media.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Media.ts
new file mode 100644
index 0000000..52254ea
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/Media.ts
@@ -0,0 +1,153 @@
+import { type MprisPlayer } from "types/service/mpris"
+import icons from "lib/icons"
+import options from "options"
+import { icon } from "lib/utils"
+
+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/linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts b/linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts
new file mode 100644
index 0000000..b6e9454
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts
@@ -0,0 +1,18 @@
+import { SimpleToggleButton } from "../ToggleButton"
+import icons from "lib/icons"
+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/linux/home/.config/ags/widget/quicksettings/widgets/Network.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Network.ts
new file mode 100644
index 0000000..eb14ab4
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/Network.ts
@@ -0,0 +1,61 @@
+import { Menu, ArrowToggleButton } from "../ToggleButton"
+import icons from "lib/icons.js"
+import { dependencies, sh } from "lib/utils"
+import options from "options"
+const { wifi } = await Service.import("network")
+
+export const NetworkToggle = () => ArrowToggleButton({
+ name: "network",
+ icon: wifi.bind("icon_name"),
+ label: wifi.bind("ssid").as(ssid => ssid || "Not Connected"),
+ connection: [wifi, () => wifi.enabled],
+ deactivate: () => wifi.enabled = false,
+ activate: () => {
+ wifi.enabled = true
+ wifi.scan()
+ },
+})
+
+export const WifiSelection = () => Menu({
+ name: "network",
+ icon: wifi.bind("icon_name"),
+ title: "Wifi Selection",
+ content: [
+ Widget.Box({
+ vertical: true,
+ setup: self => self.hook(wifi, () => self.children =
+ wifi.access_points.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/linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts b/linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts
new file mode 100644
index 0000000..f566aaf
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts
@@ -0,0 +1,99 @@
+import { ArrowToggleButton, Menu } from "../ToggleButton"
+import icons from "lib/icons"
+
+import asusctl from "service/asusctl"
+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/linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts
new file mode 100644
index 0000000..077439a
--- /dev/null
+++ b/linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts
@@ -0,0 +1,161 @@
+import { type Stream } from "types/service/audio"
+import { Arrow, Menu } from "../ToggleButton"
+import { dependencies, icon, sh } from "lib/utils"
+import icons from "lib/icons.js"
+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.volume.medium)),
+ tooltipText: audio[type].bind("volume")
+ .as(vol => `Volume: ${Math.floor(vol * 100)}%`),
+ }),
+})
+
+const micIndicator = (type: Type = "microphone") => 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.medium)),
+ 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 Microhone = () => Widget.Box({
+ class_name: "slider horizontal",
+ visible: audio.bind("recorders").as(a => a.length > 0),
+ children: [
+ micIndicator("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/linux/home/.config/ags/widget/settings/Group.ts b/linux/home/.config/ags/widget/settings/Group.ts
new file mode 100644
index 0000000..e9356e0
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/Group.ts
@@ -0,0 +1,34 @@
+import icons from "lib/icons"
+import Row from "./Row"
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export default (title: string, ...rows: ReturnType<typeof Row<any>>[]) => 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/linux/home/.config/ags/widget/settings/Page.ts b/linux/home/.config/ags/widget/settings/Page.ts
new file mode 100644
index 0000000..220e560
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/Page.ts
@@ -0,0 +1,19 @@
+import Group from "./Group"
+
+export default <T>(
+ name: string,
+ icon: string,
+ ...groups: ReturnType<typeof Group<T>>[]
+) => 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/linux/home/.config/ags/widget/settings/Row.ts b/linux/home/.config/ags/widget/settings/Row.ts
new file mode 100644
index 0000000..1e17096
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/Row.ts
@@ -0,0 +1,55 @@
+import { Opt } from "lib/option"
+import Setter from "./Setter"
+import icons from "lib/icons"
+
+export type RowProps<T> = {
+ opt: Opt<T>
+ title: string
+ note?: string
+ type?:
+ | "number"
+ | "color"
+ | "float"
+ | "object"
+ | "string"
+ | "enum"
+ | "boolean"
+ | "img"
+ | "font"
+ enums?: string[]
+ max?: number
+ min?: number
+}
+
+export default <T>(props: RowProps<T>) => 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/linux/home/.config/ags/widget/settings/Setter.ts b/linux/home/.config/ags/widget/settings/Setter.ts
new file mode 100644
index 0000000..7e455c9
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/Setter.ts
@@ -0,0 +1,93 @@
+import { type RowProps } from "./Row"
+import { Opt } from "lib/option"
+import icons from "lib/icons"
+import Gdk from "gi://Gdk"
+
+function EnumSetter(opt: Opt<string>, 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<T>({
+ opt,
+ type = typeof opt.value as RowProps<T>["type"],
+ enums,
+ max = 1000,
+ min = 0,
+}: RowProps<T>) {
+ 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<string>, 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/linux/home/.config/ags/widget/settings/SettingsDialog.ts b/linux/home/.config/ags/widget/settings/SettingsDialog.ts
new file mode 100644
index 0000000..be0c35e
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/SettingsDialog.ts
@@ -0,0 +1,63 @@
+import RegularWindow from "widget/RegularWindow"
+import layout from "./layout"
+import icons from "lib/icons"
+import options from "options"
+
+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/linux/home/.config/ags/widget/settings/Wallpaper.ts b/linux/home/.config/ags/widget/settings/Wallpaper.ts
new file mode 100644
index 0000000..998f3b7
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/Wallpaper.ts
@@ -0,0 +1,31 @@
+import wallpaper from "service/wallpaper"
+
+export default () => Widget.Box(
+ { class_name: "row wallpaper" },
+ Widget.Box(
+ { vertical: true },
+ Widget.Label({
+ xalign: 0,
+ class_name: "row-title",
+ label: "Wallpaper",
+ vpack: "start",
+ }),
+ Widget.Button({
+ on_clicked: wallpaper.random,
+ label: "Random",
+ }),
+ Widget.FileChooserButton({
+ on_file_set: ({ uri }) => wallpaper.set(uri!.replace("file://", "")),
+ }),
+ ),
+ Widget.Box({ hexpand: true }),
+ Widget.Box({
+ class_name: "preview",
+ css: wallpaper.bind("wallpaper").as(wp => `
+ min-height: 120px;
+ min-width: 200px;
+ background-image: url('${wp}');
+ background-size: cover;
+ `),
+ }),
+)
diff --git a/linux/home/.config/ags/widget/settings/layout.ts b/linux/home/.config/ags/widget/settings/layout.ts
new file mode 100644
index 0000000..2b45810
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/layout.ts
@@ -0,0 +1,147 @@
+/* eslint-disable max-len */
+import Row from "./Row"
+import Group from "./Group"
+import Page from "./Page"
+import Wallpaper from "./Wallpaper"
+import options from "options"
+import icons from "lib/icons"
+
+const {
+ autotheme: at,
+ font,
+ theme,
+ bar: b,
+ launcher: l,
+ overview: ov,
+ powermenu: pm,
+ quicksettings: qs,
+ osd,
+ hyprland: h,
+} = options
+
+const {
+ dark,
+ light,
+ blur,
+ scheme,
+ padding,
+ spacing,
+ radius,
+ shadows,
+ widget,
+ border,
+} = theme
+
+export default [
+ Page("Theme", icons.ui.themes,
+ Group("",
+ Wallpaper() as ReturnType<typeof Row>,
+ Row({ opt: at, title: "Auto Generate Color Scheme" }),
+ 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.fg, title: "Foreground", type: "color" }),
+ Row({ opt: dark.primary.bg, title: "Primary", type: "color" }),
+ Row({ opt: dark.primary.fg, title: "On Primary", type: "color" }),
+ Row({ opt: dark.error.bg, title: "Error", type: "color" }),
+ Row({ opt: dark.error.fg, title: "On Error", 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.fg, title: "Foreground", type: "color" }),
+ Row({ opt: light.primary.bg, title: "Primary", type: "color" }),
+ Row({ opt: light.primary.fg, title: "On Primary", type: "color" }),
+ Row({ opt: light.error.bg, title: "Error", type: "color" }),
+ Row({ opt: light.error.fg, title: "On Error", 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.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("Hyprland",
+ Row({ opt: h.gapsWhenOnly, title: "Gaps When Only" }),
+ ),
+ 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/linux/home/.config/ags/widget/settings/settingsdialog.scss b/linux/home/.config/ags/widget/settings/settingsdialog.scss
new file mode 100644
index 0000000..b8c9820
--- /dev/null
+++ b/linux/home/.config/ags/widget/settings/settingsdialog.scss
@@ -0,0 +1,144 @@
+window.settings-dialog {
+ background-color: $bg;
+ color: $fg;
+
+ .header {
+ .pager {
+ @include spacing(.5);
+ }
+
+ padding: $padding;
+
+ button {
+ @include button;
+ font-weight: bold;
+ padding: $padding*.5 $padding;
+
+ box {
+ @include spacing($spacing: .3em);
+ }
+ }
+
+ button.close {
+ padding: $padding * .5;
+ }
+
+ button.reset {
+ @include button($flat: true);
+ padding: $padding*.5;
+ }
+ }
+
+ .page {
+ @include scrollable($top: true);
+
+ .page-content {
+ padding: $padding*2;
+ padding-top: 0;
+ }
+ }
+
+ .group {
+ .group-title {
+ color: $primary-bg;
+ margin-bottom: $spacing*.5;
+ }
+
+ .group-reset {
+ @include button($flat: true);
+ margin: $spacing * .5;
+ padding: $padding * .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, .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;
+ }
+ }
+
+ &.wallpaper {
+ button {
+ margin-top: $spacing * .5;
+ }
+
+ .preview {
+ border-radius: $radius;
+ }
+ }
+ }
+}
diff --git a/linux/home/.config/betterlockscreen/betterlockscreenrc b/linux/home/.config/betterlockscreen/betterlockscreenrc
new file mode 100644
index 0000000..4cdfbe8
--- /dev/null
+++ b/linux/home/.config/betterlockscreen/betterlockscreenrc
@@ -0,0 +1,37 @@
+# ~/.config/betterlockscreenrc
+
+# default options
+display_on=0
+span_image=false
+lock_timeout=300
+fx_list=(dim blur dimblur pixel dimpixel color)
+dim_level=40
+blur_level=1
+pixel_scale=10,1000
+solid_color=333333
+wallpaper_cmd="feh --bg-fill"
+quiet=false
+# i3lockcolor_bin="i3lock-color" # Manually set command for i3lock-color
+
+# default theme
+loginbox=00000066
+loginshadow=00000000
+locktext="Type password to unlock..."
+font="sans-serif"
+ringcolor=ffffffff
+insidecolor=00000000
+separatorcolor=00000000
+ringvercolor=ffffffff
+insidevercolor=00000000
+ringwrongcolor=ffffffff
+insidewrongcolor=d23c3dff
+timecolor=ffffffff
+time_format="%H:%M:%S"
+greetercolor=ffffffff
+layoutcolor=ffffffff
+keyhlcolor=d23c3dff
+bshlcolor=d23c3dff
+verifcolor=ffffffff
+wrongcolor=d23c3dff
+modifcolor=d23c3dff
+bgcolor=000000ff
diff --git a/linux/home/.config/bspwm/bspwmrc b/linux/home/.config/bspwm/bspwmrc
new file mode 100755
index 0000000..d30d6db
--- /dev/null
+++ b/linux/home/.config/bspwm/bspwmrc
@@ -0,0 +1,275 @@
+#! /bin/sh
+
+################################################################################
+# ██████╗ ███████╗██████╗ ██╗ ██╗███╗ ███╗ #
+# ██╔══██╗██╔════╝██╔══██╗██║ ██║████╗ ████║ #
+# ██████╔╝███████╗██████╔╝██║ █╗ ██║██╔████╔██║ #
+# ██╔══██╗╚════██║██╔═══╝ ██║███╗██║██║╚██╔╝██║ #
+# ██████╔╝███████║██║ ╚███╔███╔╝██║ ╚═╝ ██║ #
+# ╚═════╝ ╚══════╝╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝ #
+################################## By: srdusr ##################################
+
+# ##############################################################################
+# # ENV VARS #
+# ##############################################################################
+
+## Environments
+export PATH="${PATH}:${HOME}/.config/bspwm/bin"
+
+# Get the name of the primary monitor
+mainmonitor=$(xrandr --query | awk '/ primary/{print $1}')
+
+## Monitors
+# If no primary monitor is identified, use the first connected monitor
+if [ "$mainmonitor" = "" ]; then
+ mainmonitor=$(xrandr --query | awk '/ connected/ {print $1; exit}')
+fi
+
+# Set up workspaces on the primary monitor
+bspc monitor "$mainmonitor" -d 󰲡 󰲣 󰲥 󰲧 󰲩 #1 2 3 4 5
+
+# Check the number of connected monitors
+connected_monitors=$(xrandr --query | grep -c " connected")
+
+if [ "$connected_monitors" -gt 1 ]; then
+ # Get the name of the secondary monitor (exclude the primary monitor)
+ secondmonitor=$(xrandr --query | awk '/ connected/ && $1 != "'"$mainmonitor"'" {print $1; exit}')
+
+ # Set up workspaces on the secondary monitor
+ bspc monitor "$secondmonitor" -d 󰲫 󰲭 󰲯 󰲱 󰿭 #6 7 8 9 10
+ # Check if the secondary monitor is connected and configure the layout
+ if [ "$secondmonitor" != "" ]; then
+ xrandr --output "$mainmonitor" --primary --auto --output "$secondmonitor" --auto --right-of "$mainmonitor"
+ fi
+fi
+
+#INTERNAL_MONITOR="LVDS-1"
+#EXTERNAL_MONITOR="HDMI-1"
+## on first load setup default workspaces
+#if [[ "$1" = 0 ]]; then
+# if [[ $(xrandr -q | grep "${EXTERNAL_MONITOR} connected") ]]; then
+# bspc monitor "$EXTERNAL_MONITOR" -d 1 2 3 4 5
+# bspc monitor "$INTERNAL_MONITOR" -d 6 7 8 9 10
+# bspc wm -O "$EXTERNAL_MONITOR" "$INTERNAL_MONITOR"
+# else
+# bspc monitor "$INTERNAL_MONITOR" -d 1 2 3 4 5 6 7 8 9 10
+# fi
+#fi
+
+# ##############################################################################
+# # FUNCTIONS #
+# ##############################################################################
+
+config() { bspc config "$@" & }
+rule() { bspc rule -a "$@" & }
+run_once() {
+ if [ ! "$(pgrep -f "$1")" ]; then
+ "$@" &
+ fi
+}
+
+# ##############################################################################
+# # WINDOW RULES #
+# ##############################################################################
+
+## Rules
+bspc rule -r *:* # remove all rules first
+rule '*' --one-shot state=below private=border_width:10
+#rule '*:Tiled' --one-shot state=tiled rectangle=50x50+0+50
+#rule '*' --one-shot state=floating rectangle=1028x374+0+50
+#rule \* rectangle=680x700+340+40
+rule '*:*:Picture-in-Picture' state=floating sticky=on layer=above
+rule '*:*:Picture in picture' state=floating sticky=on layer=above
+rule firefox:Toolkit focus=on state=floating sticky=on layer=above rectangle=400x280+955+475 #320x190+1030+480 #522x316-10+280
+rule "https://www.youtube.com - Enhancer for YouTube™ — Mozilla Firefox" state=floating sticky=on layer=above
+rule Wezterm state=floating
+rule Zathura state=tiled
+rule Pavucontrol state=floating rectangle=490x260+862+37
+rule Blueman-manager state=floating rectangle=536x420+818+37 #490x260-9+37
+rule scratchpad sticky=on state=floating # SCRATCHPAD
+rule heads-up-display sticky=on state=floating rectangle=360x160+990+35 # Heads Up Display (scratchpad)
+rule Onboard sticky=on state=floating rectangle=700x205+480-89 # Virtual keyboard
+rule Plank layer=above border=off
+rule Protonvpn state=floating
+rule qBittorrent desktop='^2'
+rule discord desktop='^4'
+rule firefox -o desktop=^1
+rule stalonetray state=floating manage=off
+#bspc rule -a Spotify:spotify desktop='^󰲥' state=tiled
+#bspc rule -a '*:spotify' desktop='^3' state=tiled
+
+# ##############################################################################
+# # AUTOSTART APPS #
+# ##############################################################################
+
+# Clear cache
+#rm "$HOME"/.cache/dunst.log
+#rm "$HOME"/.cache/fake_battery_capacity
+#rm "$HOME"/.cache/eww-calendar.lock
+#rm "$HOME"/.cache/eww-escreen.lock
+#rm "$HOME"/.cache/eww-control-center.lock
+#rm -r "$HOME"/.cache/dunst/
+
+# Autostart applications
+#"$HOME"/.config/bspwm/scripts/bspwm_setup_monitors &
+pgrep -x sxhkd > /dev/null || sxhkd &
+pgrep -x plank > /dev/null || plank &
+pgrep -x jgmenu > /dev/null || bspc rule -a jgmenu desktop='^H' state=floating hidden=on && jgmenu --hide-on-startup &
+picom --config "$HOME"/.config/picom/picom.conf &
+rm "$HOME"/.jgmenu-lockfile
+"$HOME"/.config/polybar/launch.sh &
+run_once unclutter & # Remove mouse when idle
+run_once "$HOME"/.scripts/lockscreen-wallpaper &
+run_once xss-lock -- betterlockscreen -l &
+nitrogen --force-setter=xinerama --restore &
+run_once redshift &
+run_once low-bat-notifier &
+pkill persistentQuickUtilities.sh; "$HOME"/.config/bspwm/scripts/persistentQuickUtilities.sh &
+#xfce4-panel --disable-wm-check &
+
+# Start polkit agent
+#[ "$(pidof xfce-polkit)" != "" ] || /usr/lib/xfce-polkit/xfce-polkit &
+run_once /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 &
+
+# Volume and brightness indicator (xob)
+source "$HOME"/.virtualenvs/bin/activate # Activate virtual environment
+run_once "$HOME"/.config/xob/launch.sh &
+deactivate # Deactivate virtual environment
+
+# Eww
+pkill eww
+eww daemon
+
+xset m 0 0 # Disable mouse drift
+
+pgrep -x plank.sh > /dev/null || plank.sh &
+
+#wmname LG3D # Fixes Java applications
+# Solve java apps issues (e.g. JetBrains IDEs like PyCharm, CLion, etc). #
+#export _JAVA_AWT_WM_NONREPARENTING=1
+
+#export QT_QPA_PLATFORMTHEME="qt5ct" # Use qt5ct to set Qt theme
+
+# Start MPD and mpDris2
+#exec mpd &
+#exec mpDris2 &
+
+# Systray
+#run_once signal-desktop --start-in-tray & #--use-tray-icon
+#run_once onboard --not-show-in=DESKTOPS &
+if ! pgrep -x "stalonetray" > /dev/null; then
+ stalonetray &
+fi
+
+declare -a restart=(clipit blueman-applet caffeine)
+for i in "${restart[@]}"; do
+ pgrep -x "$i" | xargs kill
+ sleep 0.5
+ eval "$i" &
+done
+
+while ! pgrep -x "clipit" > /dev/null || ! pgrep -x "blueman-applet" > /dev/null || ! pgrep -x "caffeine" > /dev/null; do
+ #sleep 0.5
+ systray &
+done
+xdo hide -N stalonetray
+touch "/tmp/syshide.lock"
+
+# ##############################################################################
+# # CONFIGURATION #
+# ##############################################################################
+
+## Config
+PANEL_HEIGHT=24
+config top_padding "$PANEL_HEIGHT"
+config honor_size_hints true
+config automatic_scheme alternate
+config initial_polarity second_child
+config pointer_modifier mod4
+config click_to_focus none
+config pointer_action1 move
+config pointer_action2 resize_side
+config pointer_action3 resize_corner
+config focus_follows_pointer true
+config remove_disabled_monitors true
+config remove_unplugged_monitors true
+config merge_overlapping_monitors true
+config border_width 4
+config border_radius 10
+config window_gap 10
+config split_ratio 0.52
+config borderless_monocle true
+config gapless_monocle true
+config swallow_first_click false
+config normal_border_color "#000000"
+config focused_border_color "#000000"
+config active_border_color "#000000"
+config presel_feedback_color "#BF616A"
+
+# ##############################################################################
+# # MISCELLANEOUS #
+# ##############################################################################
+
+## Fullscreen
+bspc subscribe node_state | while read -r _ _ _ _ state flag; do
+ if [[ "$state" != fullscreen ]]; then continue; fi
+ if [[ "$flag" == on ]]; then
+ xdo lower -N Plank
+ #"$(which eww)" -c "$HOME"/.config/eww close-all
+ else
+ xdo raise -N Plank
+ #"$(which eww)" -c "$HOME"/.config/eww open bar
+ fi
+done &
+
+## Title-bar
+rm -rf /tmp/title-bar_debug.log
+rm -rf /tmp/title-bar.lock
+
+processes=("title-bar" "update-title" "lemonbar")
+
+for process in "${processes[@]}"; do
+ if pidof -q "$process"; then
+ pkill -x "$process" > /dev/null; sleep 0.1
+ fi
+done
+
+# Check if title-bar is already running
+if ! pgrep -x "title-bar" >/dev/null; then
+ # Create a lock file
+ lockfile="/tmp/title-bar.lock"
+
+ # Check if the lock file exists
+ if [ ! -e "$lockfile" ]; then
+ # Create the lock file
+ touch "$lockfile"
+
+ # Function to handle BSPWM events
+ handle_bspwm_events() {
+ while read; do
+ if ! pgrep -x "title-bar" >/dev/null; then
+ bash "$HOME/.scripts/title-bar" &
+ fi
+ done
+ }
+
+ # Start bspc subscribe in the background and pass events to the handler function
+ bspc subscribe | handle_bspwm_events &
+
+ # Remove the lock file when the script exits
+ trap 'rm -f "$lockfile"' EXIT
+ else
+ echo "title-bar is already running."
+ fi
+fi
+
+start_dunst() {
+ # stop dunst if it has been started by any application that called notify-send
+ killall -q dunst
+ # Wait until the processes have been shut down
+ while pgrep -u "$UID" -x dunst >/dev/null; do sleep .05; done
+ while ! pgrep -u "$UID" -x dunst >/dev/null; do sleep .05; done
+}
+start_dunst &
+
+config external_rules_command ~/.config/bspwm/scripts/external_rules.sh &
diff --git a/linux/home/.config/bspwm/scripts/bspdragtofloat b/linux/home/.config/bspwm/scripts/bspdragtofloat
new file mode 100755
index 0000000..e2f88a2
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/bspdragtofloat
@@ -0,0 +1,46 @@
+#!/bin/env bash
+
+: "${BSPWM_DIR:="${XDG_CONFIG_HOME:-$HOME/.config}/bspwm"}"
+
+status_file="$BSPWM_DIR/tmp/drag_to_float"
+
+[[ "$1" = stop ]] && {
+ [[ -e "$status_file" ]] \
+ && rm -r -- "$status_file"
+ exit
+}
+
+[[ -e "$status_file" ]] \
+ && exit
+
+< <(bspc query -T -n pointed.window | jq -r '"\(.id) \(.client.state)"') read -r node node_state
+
+[[ -z "$node" ]] \
+ && exit
+
+case "$node_state" in
+ floating)
+ ;;
+ tiled|pseudo_tiled)
+ node_tiled_rect=($(bspc query -T -n "$node" | jq -r '.client.tiledRectangle[]'))
+ bspc node "$node" -t floating
+ xdo move -x "${node_tiled_rect[0]}" -y "${node_tiled_rect[1]}" "$node"
+ xdo resize -w "${node_tiled_rect[2]}" -h "${node_tiled_rect[3]}" "$node" ;;
+ *) # fullscreen
+ exit ;;
+esac
+
+eval "$(xdotool getmouselocation --shell)"
+x="$X" y="$Y"
+touch -- "$status_file"
+while [[ -e "$status_file" ]]; do
+ eval "$(xdotool getmouselocation --shell)"
+ (( X != x || Y != y )) && {
+ bspc node "$node" -v "$((X - x))" "$((Y - y))"
+ x="$X" y="$Y"
+ }
+ sleep .01
+done
+
+[[ -e "$status_file" ]] \
+ && rm -r -- "$status_file"
diff --git a/linux/home/.config/bspwm/scripts/bspswallow b/linux/home/.config/bspwm/scripts/bspswallow
new file mode 100755
index 0000000..dea343f
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/bspswallow
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+NODE_CURRENT=$(bspc query -N -n focused)
+$@ &
+PID_COMMAND=$!
+WATCH=$(bspc subscribe -c 1 node_add)
+NODE_NEW=${WATCH%% *}
+bspc node -s $NODE_CURRENT
+bspc node $NODE_CURRENT --flag hidden=on
+wait $PID_COMMAND
+bspc node $NODE_CURRENT --flag hidden=off
+bspc node $NODE_CURRENT --focus
diff --git a/linux/home/.config/bspwm/scripts/bspwindows b/linux/home/.config/bspwm/scripts/bspwindows
new file mode 100755
index 0000000..26deeab
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/bspwindows
@@ -0,0 +1,14 @@
+#!/bin/sh
+# bspwindows
+# get targets for drawing borders/whatever on in bspwm
+
+target="${1:-active}"
+
+case "$target" in
+ active)
+ bspc query -N -n .local.descendant_of.window.leaf.!fullscreen
+ ;;
+ inactive)
+ bspc query -N -n .local.!descendant_of.window.leaf.!fullscreen
+ ;;
+esac
diff --git a/linux/home/.config/bspwm/scripts/bspwm-monitor-setup b/linux/home/.config/bspwm/scripts/bspwm-monitor-setup
new file mode 100755
index 0000000..6e38bb7
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/bspwm-monitor-setup
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+INTERNAL_MONITOR="eDP"
+EXTERNAL_MONITOR="HDMI-A-0"
+
+monitor_add() {
+ # Move first 5 desktops to external monitor
+ for desktop in $(bspc query -D --names -m "$INTERNAL_MONITOR" | sed 5q); do
+ bspc desktop "$desktop" --to-monitor "$EXTERNAL_MONITOR"
+ done
+ # Remove default desktop created by bspwm
+ bspc desktop Desktop --remove
+ # reorder monitors
+ bspc wm -O "$EXTERNAL_MONITOR" "$INTERNAL_MONITOR"
+}
+
+monitor_remove() {
+ # Add default temp desktop because a minimum of one desktop is required per monitor
+ bspc monitor "$EXTERNAL_MONITOR" -a Desktop
+
+ # Move all desktops except the last default desktop to internal monitor
+ for desktop in $(bspc query -D -m "$EXTERNAL_MONITOR"); do
+ bspc desktop "$desktop" --to-monitor "$INTERNAL_MONITOR"
+ done
+
+ # delete default desktops
+ bspc desktop Desktop --remove
+ # reorder desktops
+ bspc monitor "$INTERNAL_MONITOR" -o 1 2 3 4 5 6 7 8 9 10
+}
+
+if [[ $(xrandr -q | grep "${EXTERNAL_MONITOR} connected") ]]; then
+ # set xrandr rules for docked setup
+ xrandr --output "$INTERNAL_MONITOR" --mode 1920x1080 --pos 0x0 --rotate normal --output "$EXTERNAL_MONITOR" --primary --mode 1920x1080 --pos 1920x780 --rotate normal
+ if [[ $(bspc query -D -m "${EXTERNAL_MONITOR}" | wc -l) -ne 5 ]]; then
+ monitor_add
+ fi
+ bspc wm -O "$EXTERNAL_MONITOR" "$INTERNAL_MONITOR"
+else
+ # set xrandr rules for mobile setup
+ xrandr --output "$INTERNAL_MONITOR" --primary --mode 1920x1080 --pos 0x0 --rotate normal --output "$EXTERNAL_MONITOR" --off
+ if [[ $(bspc query -D -m "${INTERNAL_MONITOR}" | wc -l) -ne 10 ]]; then
+ monitor_remove
+ fi
+fi
+
+# Set wallpaper
+~/.local/bin/setbg.sh &
+
+# Kill and relaunch polybar
+kill -9 $(pgrep -f 'polybar') >/dev/null 2>&1
+polybar-msg cmd quit >/dev/null 2>&1
+while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done
+if [[ $(xrandr -q | grep "${EXTERNAL_MONITOR} connected") ]]; then
+ polybar --reload primary -c ~/.config/polybar/config.ini </dev/null >/var/tmp/polybar-primary.log 2>&1 200>&- &
+ polybar --reload secondary -c ~/.config/polybar/config.ini </dev/null >/var/tmp/polybar-secondary.log 2>&1 200>&- &
+else
+ polybar --reload primary -c ~/.config/polybar/config.ini </dev/null >/var/tmp/polybar-primary.log 2>&1 200>&- &
+fi
diff --git a/linux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh b/linux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh
new file mode 100755
index 0000000..45a4c53
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# Created By: srdusr
+# Created On: Mon 18 Sep 2023 18:37:21 CAT
+# Project: Bspwm script to toggle visibility of initial window and bring focus back to it
+
+# Get the ID of the currently focused desktop
+current_desktop_id=$(bspc query -D -d focused --names)
+
+# Get the ID of the first hidden window in the current desktop
+hidden_window_id=$(bspc query -N -d "$current_desktop_id" -n .hidden | head -n 1)
+
+# Check if there's a hidden window in the current desktop
+if [[ -n "$hidden_window_id" ]]; then
+ # There's a hidden window, so unhide it
+ bspc node "$hidden_window_id" -g hidden=off
+ # Bring focus back to the previously hidden window
+ bspc node -f "$hidden_window_id"
+else
+ # There's no hidden window in the current desktop, hide the first available window
+ first_window_id=$(bspc query -N -n focused.window)
+ bspc node "$first_window_id" -g hidden=on
+fi
diff --git a/linux/home/.config/bspwm/scripts/close-window b/linux/home/.config/bspwm/scripts/close-window
new file mode 100755
index 0000000..8f7f36b
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/close-window
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# close or kill a bspwm window
+
+# show wallpaper if last tile
+bspc query -N -n .focused.tiled.window &> /dev/null \
+ && ! bspc query -N -n .!focused.local.tiled.window &> /dev/null \
+ && show-wallpaper -d
+
+# close focused window
+[ "$1" = "kill" ] && bspc node -k || bspc node -c
diff --git a/linux/home/.config/bspwm/scripts/drag-float b/linux/home/.config/bspwm/scripts/drag-float
new file mode 100755
index 0000000..788e978
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/drag-float
@@ -0,0 +1,42 @@
+#!/bin/env bash
+
+: "${BUTTON:=1}"
+
+node="$(bspc query -N -n pointed)"
+
+die() {
+ jobs -p | xargs -r -n1 -I{} kill {}
+ exit
+}
+
+trap 'die' USR1
+
+{ bspc subscribe node_focus | while read -r _ _ _ wid; do
+ (( wid != node )) && break; done; kill -USR1 "$$" ;} &
+{ while xinput list \
+ | sed -nE 's,.*id=([0-9]+).*slave\s+pointer.*,\1,p' \
+ | xargs -r -n1 -I{} xinput query-state {} 2> /dev/null \
+ | grep -qF "button[${BUTTON}]=down"; do sleep .3; done; kill -USR1 "$$" ;} &
+
+if bspc node "$node.tiled" -f; then
+ node_tiled_rect=($(bspc query -T -n "$node" | jq -r '.client.tiledRectangle[]'))
+ bspc node "$node" -t floating
+ xdo move -x "${node_tiled_rect[0]}" -y "${node_tiled_rect[1]}" "$node"
+ xdo resize -w "${node_tiled_rect[2]}" -h "${node_tiled_rect[3]}" "$node"
+elif bspc node "$node.floating" -f; then
+ :
+else
+ die
+fi
+
+eval "$(xdotool getmouselocation --shell)"
+x="$X" y="$Y"
+while :; do
+ eval "$(xdotool getmouselocation --shell)"
+ (( X != x || Y != y )) && {
+ bspc node "$node" -v "$((X - x))" "$((Y - y))"
+ x="$X" y="$Y"
+ }
+done
+
+wait
diff --git a/linux/home/.config/bspwm/scripts/external_rules.sh b/linux/home/.config/bspwm/scripts/external_rules.sh
new file mode 100755
index 0000000..7b07ae8
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/external_rules.sh
@@ -0,0 +1,71 @@
+#!/bin/env bash
+#
+# external_rules_command
+#
+# Absolute path to the command used to retrieve rule consequences.
+# The command will receive the following arguments: window ID, class
+# name, instance name, and intermediate consequences. The output of
+# that command must have the following format: key1=value1
+# key2=value2 ... (the valid key/value pairs are given in the
+# description of the rule command).
+#
+#
+# Rule
+# General Syntax
+# rule COMMANDS
+#
+# Commands
+# -a, --add (<class_name>|*)[:(<instance_name>|*)] [-o|--one-shot]
+# [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL]
+# [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO]
+# [(hidden|sticky|private|locked|marked|center|follow|manage|focus|border)=(on|off)]
+# [rectangle=WxH+X+Y]
+# Create a new rule.
+#
+# -r, --remove
+# ^<n>|head|tail|(<class_name>|*)[:(<instance_name>|*)]...
+# Remove the given rules.
+#
+# -l, --list
+# List the rules.
+
+# Programs to specific desktops
+wid=$1
+class=$2
+instance=$3
+consequences=$4
+
+main() {
+ case "$class" in
+ firefox)
+ if [ "$instance" = "Toolkit" ]; then
+ echo "state=floating sticky=on"
+ fi
+ ;;
+ Spotify)
+ echo desktop=^5 follow=on focus=on
+ ;;
+ "")
+ sleep 0.5
+
+ wm_class=("$(xprop -id "$wid" | grep "WM_CLASS" | grep -Po '"\K[^,"]+')")
+
+ class=${wm_class[-1]}
+
+ [[ ${#wm_class[@]} == "2" ]] && instance=${wm_class[0]}
+
+ [[ -n "$class" ]] && main
+ ;;
+ esac
+}
+
+main
+
+# Allow floating windows over fullscreen
+wid="$1"
+class="$2"
+instance="$3"
+eval "$4"
+
+[[ "$state" = floating ]] &&
+ echo 'layer=above'
diff --git a/linux/home/.config/bspwm/scripts/hide-window b/linux/home/.config/bspwm/scripts/hide-window
new file mode 100755
index 0000000..c350a0e
--- /dev/null
+++ b/linux/home/.config/bspwm/scripts/hide-window
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+CMD=${1:-help}
+shift
+
+help() {
+ echo "Available commands:"
+ echo " * unhide - select and unhide window"
+}
+
+unhide() {
+ action=${1:-list}
+ case $action in
+ "list")
+ selection=$(for id in "$(bspc query -N -n .hidden)"; do
+ title=$(xtitle "$id")
+ [[ -z "$title" ]] && title="<unnamed>"
+ echo "$id" "$title"
+ done | rofi -dmenu -i -p "Hidden windows" | cut -f1 -d' ')
+
+ [[ -z "$selection" ]] && exit 1
+
+ bspc node "$selection" -g hidden=off
+ ;;
+ esac
+ }
+
+ case $CMD in
+ "help")
+ help
+ ;;
+ "unhide")
+ unhide "$1"
+ ;;
+ *)
+ help
+ ;;
+ esac
diff --git a/linux/home/.config/dunst/assets/notification/fallback.png b/linux/home/.config/dunst/assets/notification/fallback.png
new file mode 100644
index 0000000..204aeda
--- /dev/null
+++ b/linux/home/.config/dunst/assets/notification/fallback.png
Binary files differ
diff --git a/linux/home/.config/dunst/assets/notification/music.png b/linux/home/.config/dunst/assets/notification/music.png
new file mode 100644
index 0000000..ae91be3
--- /dev/null
+++ b/linux/home/.config/dunst/assets/notification/music.png
Binary files differ
diff --git a/linux/home/.config/dunst/assets/notification/scrot.png b/linux/home/.config/dunst/assets/notification/scrot.png
new file mode 100644
index 0000000..1e12f38
--- /dev/null
+++ b/linux/home/.config/dunst/assets/notification/scrot.png
Binary files differ
diff --git a/linux/home/.config/dunst/assets/ui/volume-high.svg b/linux/home/.config/dunst/assets/ui/volume-high.svg
new file mode 100644
index 0000000..43152c9
--- /dev/null
+++ b/linux/home/.config/dunst/assets/ui/volume-high.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#eceff4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-volume-2"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg> \ No newline at end of file
diff --git a/linux/home/.config/dunst/assets/ui/volume-low.svg b/linux/home/.config/dunst/assets/ui/volume-low.svg
new file mode 100644
index 0000000..09b3650
--- /dev/null
+++ b/linux/home/.config/dunst/assets/ui/volume-low.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#eceff4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-volume"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon></svg> \ No newline at end of file
diff --git a/linux/home/.config/dunst/assets/ui/volume-medium.svg b/linux/home/.config/dunst/assets/ui/volume-medium.svg
new file mode 100644
index 0000000..6b3c1fa
--- /dev/null
+++ b/linux/home/.config/dunst/assets/ui/volume-medium.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#eceff4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-volume-1"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg> \ No newline at end of file
diff --git a/linux/home/.config/dunst/assets/ui/volume-muted.svg b/linux/home/.config/dunst/assets/ui/volume-muted.svg
new file mode 100644
index 0000000..50434d4
--- /dev/null
+++ b/linux/home/.config/dunst/assets/ui/volume-muted.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#BF616A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-volume-x"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><line x1="23" y1="9" x2="17" y2="15"></line><line x1="17" y1="9" x2="23" y2="15"></line></svg> \ No newline at end of file
diff --git a/linux/home/.config/dunst/dunstrc b/linux/home/.config/dunst/dunstrc
new file mode 100644
index 0000000..8989a2d
--- /dev/null
+++ b/linux/home/.config/dunst/dunstrc
@@ -0,0 +1,456 @@
+# See dunst(5) for all configuration options
+
+[global]
+ ### Display ###
+
+ # Which monitor should the notifications be displayed on.
+ monitor = 0
+
+ # Display notification on focused monitor. Possible modes are:
+ # mouse: follow mouse pointer
+ # keyboard: follow window with keyboard focus
+ # none: don't follow anything
+ #
+ # "keyboard" needs a window manager that exports the
+ # _NET_ACTIVE_WINDOW property.
+ # This should be the case for almost all modern window managers.
+ #
+ # If this option is set to mouse or keyboard, the monitor option
+ # will be ignored.
+ follow = none
+
+ ### Geometry ###
+
+ # dynamic width from 0 to 300
+ width = (200, 300)
+ # constant width of 300
+ # width = 300
+
+ # The maximum height of a single notification, excluding the frame.
+ height = 300
+
+ # Position the notification in the top right corner
+ origin = bottom-right
+
+ # Offset from the origin
+ offset = 6x30
+ # offset = 10x35 # i3 gaps = 20x20
+ # (H_Right_Gap/2) x (25+V_Bottom_Gap/2)
+
+ # Scale factor. It is auto-detected if value is 0.
+ scale = 0
+
+ # Maximum number of notification (0 means no limit)
+ notification_limit = 0
+
+ ### Progress bar ###
+
+ # Turn on the progess bar. It appears when a progress hint is passed with
+ # for example dunstify -h int:value:12
+ progress_bar = true
+
+ # Set the progress bar height. This includes the frame, so make sure
+ # it's at least twice as big as the frame width.
+ progress_bar_height = 10
+
+ # Set the frame width of the progress bar
+ progress_bar_frame_width = 1
+
+ # Set the minimum width for the progress bar
+ progress_bar_min_width = 150
+
+ # Set the maximum width for the progress bar
+ progress_bar_max_width = 300
+
+ # Show how many messages are currently hidden (because of
+ # notification_limit).
+ indicate_hidden = yes
+
+ # The transparency of the window. Range: [0; 100].
+ # This option will only work if a compositing window manager is
+ # present (e.g. xcompmgr, compiz, etc.). (X11 only)
+ transparency = 0
+
+ # Draw a line of "separator_height" pixel height between two
+ # notifications.
+ # Set to 0 to disable.
+ separator_height = 2
+
+ # Padding between text and separator.
+ padding = 11
+
+ # Horizontal padding.
+ horizontal_padding = 11
+
+ # Padding between text and icon.
+ text_icon_padding = 0
+
+ # Defines width in pixels of frame around the notification window.
+ # Set to 0 to disable.
+ frame_width = 2
+
+ # Define a color for the separator.
+ # possible values are:
+ # * auto: dunst tries to find a color fitting to the background;
+ # * foreground: use the same color as the foreground;
+ # * frame: use the same color as the frame;
+ # * anything else will be interpreted as a X color.
+ separator_color = "#1a1b26"
+
+ # Sort messages by urgency.
+ sort = yes
+
+ # Don't remove messages, if the user is idle (no mouse or keyboard input)
+ # for longer than idle_threshold seconds.
+ # Set to 0 to disable.
+ # A client can set the 'transient' hint to bypass this. See the rules
+ # section for how to disable this if necessary
+ idle_threshold = 120
+
+ ### Text ###
+
+ font = JetBrainsMono Nerd Font Medium 9
+
+ # The spacing between lines. If the height is smaller than the
+ # font height, it will get raised to the font height.
+ line_height = 5
+
+ # Possible values are:
+ # full: Allow a small subset of html markup in notifications:
+ # <b>bold</b>
+ # <i>italic</i>
+ # <s>strikethrough</s>
+ # <u>underline</u>
+ #
+ # For a complete reference see
+ # <https://docs.gtk.org/Pango/pango_markup.html>.
+ #
+ # strip: This setting is provided for compatibility with some broken
+ # clients that send markup even though it's not enabled on the
+ # server. Dunst will try to strip the markup but the parsing is
+ # simplistic so using this option outside of matching rules for
+ # specific applications *IS GREATLY DISCOURAGED*.
+ #
+ # no: Disable markup parsing, incoming notifications will be treated as
+ # plain text. Dunst will not advertise that it has the body-markup
+ # capability if this is set as a global setting.
+ #
+ # It's important to note that markup inside the format option will be parsed
+ # regardless of what this is set to.
+ markup = full
+
+ # The format of the message. Possible variables are:
+ # %a appname
+ # %s summary
+ # %b body
+ # %i iconname (including its path)
+ # %I iconname (without its path)
+ # %p progress value if set ([ 0%] to [100%]) or nothing
+ # %n progress value if set without any extra characters
+ # %% Literal %
+ # Markup is allowed
+ format = "<b>%s</b>\n%b"
+
+ # Alignment of message text.
+ # Possible values are "left", "center" and "right".
+ alignment = center
+
+ # Vertical alignment of message text and icon.
+ # Possible values are "top", "center" and "bottom".
+ vertical_alignment = center
+
+ # Show age of message if message is older than show_age_threshold
+ # seconds.
+ # Set to -1 to disable.
+ show_age_threshold = 60
+
+ # Specify where to make an ellipsis in long lines.
+ # Possible values are "start", "middle" and "end".
+ ellipsize = middle
+
+ # Ignore newlines '\n' in notifications.
+ ignore_newline = no
+
+ # Stack together notifications with the same content
+ stack_duplicates = true
+
+ # Hide the count of stacked notifications with the same content
+ hide_duplicate_count = true
+
+ # Display indicators for URLs (U) and actions (A).
+ show_indicators = yes
+
+ ### Icons ###
+
+ # Align icons left/right/off
+ icon_position = left
+
+ # Scale small icons up to this size, set to 0 to disable. Helpful
+ # for e.g. small files or high-dpi screens. In case of conflict,
+ # max_icon_size takes precedence over this.
+ min_icon_size = 0
+
+ # Scale larger icons down to this size, set to 0 to disable
+ max_icon_size = 32
+
+ # Paths to default icons.
+ #icon_path = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/
+ #icon_path = /usr/share/icons/Qogir/16/status:/usr/share/icons/Qogir/16/devices/:/usr/share/icons/Qogir/16/apps/:/usr/share/pixmaps/
+ icon_path = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/
+
+ ### History ###
+
+ # Should a notification popped up from history be sticky or timeout
+ # as if it would normally do.
+ sticky_history = yes
+
+ #history_file = ~/.cache/dunst/history
+
+ # Maximum amount of notifications kept in history
+ rhistory_length = 100
+
+ ### Misc/Advanced ###
+
+ # dmenu path.
+ dmenu = /usr/bin/dmenu -p dunst:
+
+ # Browser for opening urls in context menu.
+ browser = /usr/bin/brave
+
+ # Always run rule-defined scripts, even if the notification is suppressed
+ always_run_script = true
+
+ # Define the title of the windows spawned by dunst
+ title = Dunst
+
+ # Define the class of the windows spawned by dunst
+ class = Dunst
+
+ # Define the corner radius of the notification window
+ # in pixel size. If the radius is 0, you have no rounded
+ # corners.
+ # The radius will be automatically lowered if it exceeds half of the
+ # notification height to avoid clipping text and/or icons.
+ corner_radius = 10
+
+ # Ignore the dbus closeNotification message.
+ # Useful to enforce the timeout set by dunst configuration. Without this
+ # parameter, an application may close the notification sent before the
+ # user defined timeout.
+ ignore_dbusclose = false
+
+ ### Wayland ###
+ # These settings are Wayland-specific. They have no effect when using X11
+
+ # Uncomment this if you want to let notications appear under fullscreen
+ # applications (default: overlay)
+ # layer = top
+
+ # Set this to true to use X11 output on Wayland.
+ force_xwayland = false
+
+ ### Legacy
+
+ # Use the Xinerama extension instead of RandR for multi-monitor support.
+ # This setting is provided for compatibility with older nVidia drivers that
+ # do not support RandR and using it on systems that support RandR is highly
+ # discouraged.
+ #
+ # By enabling this setting dunst will not be able to detect when a monitor
+ # is connected or disconnected which might break follow mode if the screen
+ # layout changes.
+ force_xinerama = false
+
+ ### mouse
+
+ # Defines list of actions for each mouse event
+ # Possible values are:
+ # * none: Don't do anything.
+ # * do_action: Invoke the action determined by the action_name rule. If there is no
+ # such action, open the context menu.
+ # * open_url: If the notification has exactly one url, open it. If there are multiple
+ # ones, open the context menu.
+ # * close_current: Close current notification.
+ # * close_all: Close all notifications.
+ # * context: Open context menu for the notification.
+ # * context_all: Open context menu for all notifications.
+ # These values can be strung together for each mouse event, and
+ # will be executed in sequence.
+ mouse_left_click = close_current
+ mouse_middle_click = do_action, close_current
+ mouse_right_click = close_all
+
+# Experimental features that may or may not work correctly. Do not expect them
+# to have a consistent behaviour across releases.
+[experimental]
+ # Calculate the dpi to use on a per-monitor basis.
+ # If this setting is enabled the Xft.dpi value will be ignored and instead
+ # dunst will attempt to calculate an appropriate dpi value for each monitor
+ # using the resolution and physical size. This might be useful in setups
+ # where there are multiple screens with very different dpi values.
+ per_monitor_dpi = false
+
+# Every section that isn't one of the above is interpreted as a rules to
+# override settings for certain messages.
+#
+# Messages can be matched by
+# appname (discouraged, see desktop_entry)
+# body
+# category
+# desktop_entry
+# icon
+# match_transient
+# msg_urgency
+# stack_tag
+# summary
+#
+# and you can override the
+# background
+# foreground
+# format
+# frame_color
+# fullscreen
+# new_icon
+# set_stack_tag
+# set_transient
+# set_category
+# timeout
+# urgency
+# skip_display
+# history_ignore
+# action_name
+# word_wrap
+# ellipsize
+# alignment
+#
+# Shell-like globbing will get expanded.
+#
+# Instead of the appname filter, it's recommended to use the desktop_entry filter.
+# GLib based applications export their desktop-entry name. In comparison to the appname,
+# the desktop-entry won't get localized.
+#
+# SCRIPTING
+# You can specify a script that gets run when the rule matches by
+# setting the "script" option.
+# The script will be called as follows:
+# script appname summary body icon urgency
+# where urgency can be "LOW", "NORMAL" or "CRITICAL".
+#
+# NOTE: It might be helpful to run dunst -print in a terminal in order
+# to find fitting options for rules.
+
+# Disable the transient hint so that idle_threshold cannot be bypassed from the
+# client
+#[transient_disable]
+# match_transient = yes
+# set_transient = no
+#
+# Make the handling of transient notifications more strict by making them not
+# be placed in history.
+#[transient_history_ignore]
+# match_transient = yes
+# history_ignore = yes
+
+# fullscreen values
+# show: show the notifications, regardless if there is a fullscreen window opened
+# delay: displays the new notification, if there is no fullscreen window active
+# If the notification is already drawn, it won't get undrawn.
+# pushback: same as delay, but when switching into fullscreen, the notification will get
+# withdrawn from screen again and will get delayed like a new notification
+#[fullscreen_delay_everything]
+# fullscreen = delay
+[fullscreen_show_critical]
+ msg_urgency = critical
+ fullscreen = show
+[fullscreen_show_normal]
+ msg_urgency = normal
+ fullscreen = show
+
+
+#[espeak]
+# summary = "*"
+# script = dunst_espeak.sh
+
+#[script-test]
+# summary = "*script*"
+# script = dunst_test.sh
+
+#[ignore]
+# # This notification will not be displayed
+# summary = "foobar"
+# skip_display = true
+
+#[history-ignore]
+# # This notification will not be saved in history
+# summary = "foobar"
+# history_ignore = yes
+
+#[skip-display]
+# # This notification will not be displayed, but will be included in the history
+# summary = "foobar"
+# skip_display = yes
+
+#[signed_on]
+# appname = Pidgin
+# summary = "*signed on*"
+# urgency = low
+#
+#[signed_off]
+# appname = Pidgin
+# summary = *signed off*
+# urgency = low
+#
+#[says]
+# appname = Pidgin
+# summary = *says*
+# urgency = critical
+#
+#[twitter]
+# appname = Pidgin
+# summary = *twitter.com*
+# urgency = normal
+#
+
+[openEwwPopup]
+ script = ~/.config/dunst/scripts/openEwwPopup.sh
+
+[songArtLogger]
+ script = ~/.config/dunst/scripts/songArtLogger.sh
+
+[stack-volumes]
+ appname = "some_volume_notifiers"
+ set_stack_tag = "volume"
+
+[flameshot-urgency]
+ appname = flameshot
+ urgency = low
+
+[whatsapp-alignment]
+ appname = whatsapp-nativefier-d40211
+ alignment = left
+
+[discord-alignment]
+ appname = discord
+ alignment = left
+
+[signal-alignment]
+ appname = Signal
+ alignment = left
+
+[urgency_low]
+ background = "#16161e"
+ foreground = "#c0caf5"
+ frame_color = "#1f2335"
+ timeout = 3
+
+[urgency_normal]
+ background = "#16161e"
+ foreground = "#c0caf5"
+ frame_color = "#3d59a1"
+ timeout = 15
+
+[urgency_critical]
+ background = "#191D24"
+ foreground = "#c0caf5"
+ frame_color = "#db4b4b"
+ timeout = 60
diff --git a/linux/home/.config/dunst/scripts/openEwwPopup.sh b/linux/home/.config/dunst/scripts/openEwwPopup.sh
new file mode 100755
index 0000000..d22e981
--- /dev/null
+++ b/linux/home/.config/dunst/scripts/openEwwPopup.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+DND_LOCK_FILE="$HOME/.cache/dnd-lock.lock"
+EWW_BIN="$HOME/.local/bin/eww"
+
+finish() {
+ ${EWW_BIN} update noti=false; sleep 0.075
+ ${EWW_BIN} close notification-popup
+}
+
+# Run eww daemon if not running
+if [[ ! `pidof eww` ]]; then
+ ${EWW_BIN} daemon
+ sleep 1
+else
+ if [[ ! -f "$DND_LOCK_FILE" ]]; then
+ KILLED=false
+ for pid in $(pidof -x openEwwPopup.sh); do
+ if [ $pid != $$ ]; then
+ kill -9 $pid
+ KILLED=true
+ fi
+ done >/dev/nullx
+
+ if ! $KILLED; then
+ sleep 0.5
+ ${EWW_BIN} update noti=true
+ ${EWW_BIN} open notification-popup
+ canberra-gtk-play -i message
+ fi
+
+ sleep 5
+ finish
+ unset KILLED
+ fi
+fi
diff --git a/linux/home/.config/dunst/scripts/songArtLogger.sh b/linux/home/.config/dunst/scripts/songArtLogger.sh
new file mode 100755
index 0000000..f73beb4
--- /dev/null
+++ b/linux/home/.config/dunst/scripts/songArtLogger.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+TMP_DIR="$HOME/.cache/dunst"
+TMP_COVER_PATH="$TMP_DIR/$DUNST_SUMMARY.png"
+TMP_TEMP_PATH="$TMP_DIR/temp.png"
+
+if [ ! -d "$TMP_DIR" ]; then
+ mkdir -p "$TMP_DIR"
+fi
+
+ART_FROM_SPOTIFY="$(playerctl -p %any,spotify metadata mpris:artUrl | sed -e 's/open.spotify.com/i.scdn.co/g')"
+
+if [[ $(playerctl -p spotify,%any,firefox,chromium,brave,mpd metadata mpris:artUrl) ]]; then
+ curl -s "$ART_FROM_SPOTIFY" --output "$TMP_COVER_PATH"
+fi
+
+cp "$TMP_TEMP_PATH" "$TMP_COVER_PATH" \ No newline at end of file
diff --git a/linux/home/.config/eww/eww.scss b/linux/home/.config/eww/eww.scss
new file mode 100644
index 0000000..9405a6a
--- /dev/null
+++ b/linux/home/.config/eww/eww.scss
@@ -0,0 +1,11 @@
+@import "./src/scss/variables";
+@import "./src/scss/overrides";
+@import "./src/scss/modules";
+
+@import "./src/scss/bar/index.scss";
+@import "./src/scss/control-center/index.scss";
+@import "./src/scss/exitscreen/index.scss";
+@import "./src/scss/info-center/index.scss";
+@import "./src/scss/lockscreen/index.scss";
+@import "./src/scss/notification-center/index.scss";
+@import "./src/scss/notification-popup/index.scss";
diff --git a/linux/home/.config/eww/eww.yuck b/linux/home/.config/eww/eww.yuck
new file mode 100644
index 0000000..191b30c
--- /dev/null
+++ b/linux/home/.config/eww/eww.yuck
@@ -0,0 +1,23 @@
+(include "./src/yuck/_variables.yuck")
+(include "./src/yuck/_modules.yuck")
+
+(include "./src/yuck/bar/_widgets.yuck")
+(include "./src/yuck/bar/_windows.yuck")
+
+(include "./src/yuck/control-center/_widgets.yuck")
+(include "./src/yuck/control-center/_windows.yuck")
+
+(include "./src/yuck/exitscreen/_widgets.yuck")
+(include "./src/yuck/exitscreen/_windows.yuck")
+
+(include "./src/yuck/info-center/_widgets.yuck")
+(include "./src/yuck/info-center/_windows.yuck")
+
+(include "./src/yuck/lockscreen/_widgets.yuck")
+(include "./src/yuck/lockscreen/_windows.yuck")
+
+(include "./src/yuck/notification-center/_widgets.yuck")
+(include "./src/yuck/notification-center/_windows.yuck")
+
+(include "./src/yuck/notification-popup/_widgets.yuck")
+(include "./src/yuck/notification-popup/_windows.yuck")
diff --git a/linux/home/.config/hypr/autostart b/linux/home/.config/hypr/autostart
new file mode 100755
index 0000000..2805e42
--- /dev/null
+++ b/linux/home/.config/hypr/autostart
@@ -0,0 +1,34 @@
+#!/usr/bin/bash
+
+# Policy Authentication Agent
+/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 &
+
+eval "$(/usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh)"
+export "$(gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh)"
+
+# Setup Environment
+systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP &
+dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY XDG_CURRENT_DESKTOP --all &
+#dbus-update-activation-environment DISPLAY XAUTHORITY WAYLAND_DISPLAY &
+
+# variables
+scripts=~/.scripts
+
+# gsettings
+#gsettings set org.gnome.desktop.interface gtk-theme 'Tokyonight-Dark-BL-LB'
+#gsettings set org.gnome.desktop.interface font-name 'CaskaydiaCove Nerd Font 9'
+#gsettings set org.gnome.desktop.interface icon-theme 'Tokyonight-Moon'
+#gsettings set org.gnome.desktop.interface cursor-theme 'Sweet-cursors'
+
+# For nemo
+gsettings set org.cinnamon.desktop.default-applications.terminal exec wezterm
+
+# music daemon
+mpd &
+
+# other
+hyprctl setcursor Sweet-cursors 24
+wl-paste --watch cliphist store &
+notify-send -a aurora "hello $(whoami)" &
+sleep 2
+mpd-mpris &
diff --git a/linux/home/.config/hypr/hyprland.conf b/linux/home/.config/hypr/hyprland.conf
new file mode 100644
index 0000000..620dc55
--- /dev/null
+++ b/linux/home/.config/hypr/hyprland.conf
@@ -0,0 +1,175 @@
+# Sourcing external config files
+source=~/.config/hypr/user/monitors.conf
+source=~/.config/hypr/user/exec.conf
+source=~/.config/hypr/user/env.conf
+source=~/.config/hypr/user/binds.conf
+source=~/.config/hypr/user/window_rules.conf
+
+
+# Defaults
+$term = wezterm
+$browser = firefox
+#$gmail = firefox --new-instance -P app "https://mail.google.com/" --class appProfile
+$editor = nvim
+#$explorer = nemo
+#$music = g4music
+$notepad = code --profile notepad --unity-launch ~/Templates
+$launcher = wofi --show drun -n
+$launcher_alt = wofi --show run -n
+#$discord = discord
+#env = GTK_THEME,Breeze-Dark
+
+
+general {
+ gaps_in = 5
+ gaps_out = 5
+ border_size = 2
+ col.active_border = rgba(cba6f7ff) rgba(89b4faff) rgba(94e2d5ff) 10deg
+ col.inactive_border = 0xff313244
+ # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse)
+ apply_sens_to_raw = 0
+ layout = "master";
+ resize_on_border = yes
+ extend_border_grab_area = 20
+}
+
+
+input {
+ kb_layout = custom-us
+ #sensitivity = 0.75 # for mouse cursor
+ sensitivity = 0
+ follow_mouse = 0
+ scroll_method = 2fg
+
+ touchpad {
+ natural_scroll = false
+ disable_while_typing = true
+ tap-to-click = true
+ }
+}
+
+
+decoration {
+ rounding = 10
+ active_opacity = 0.95
+ inactive_opacity = 0.9
+ fullscreen_opacity = 0.95
+
+ dim_inactive = false
+ dim_strength = 0.05
+
+ blur {
+ enabled = true
+ #enabled = false
+ size = 3
+ passes = 1
+
+ vibrancy = 0.1696
+ }
+
+ drop_shadow = true
+ shadow_range = 4
+ shadow_render_power = 3
+ col.shadow = rgba(1a1a1aee)
+ #blur = true
+ #blur_size = 5
+ #blur_passes = 4
+ #blur_new_optimizations = true
+ #blur_xray = true
+ #blur_ignore_opacity = true
+
+ #drop_shadow = true
+ #shadow_ignore_window = true
+ #shadow_range = 20
+ #shadow_render_power = 3
+ #col.shadow = 0x55161925
+ col.shadow_inactive = 0x22161925
+ # Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts.
+ # if you want heavy blur, you need to up the blur_passes.
+ # the more passes, the more you can up the blur_size without noticing artifacts.
+
+ # Blurring layerSurfaces
+ # blurls = gtk-layer-shell
+ # blurls = waybar
+ # blurls = lockscreen
+ blurls = rofi
+ blurls = wofi
+ blurls = firefox
+}
+
+
+animations {
+ enabled = true
+ # bezier = overshot, 0.05, 0.9, 0.1, 1.1
+ bezier = overshot, 0.13, 0.99, 0.29, 1.1
+ animation = windows, 1, 4, overshot, slide
+ animation = border, 1, 10, default
+ animation = fade, 1, 10, default
+ animation = workspaces, 1, 6, overshot, slidevert
+}
+
+
+dwindle {
+ pseudotile = true # enable pseudotiling on dwindle
+ force_split = 0
+ #col.group_border = 0xff89dceb
+ #col.group_border_active = 0xfff9e2af
+ preserve_split = true
+}
+
+
+master {
+ new_on_top = true
+ no_gaps_when_only = false
+}
+
+
+gestures {
+ workspace_swipe = true
+ workspace_swipe_invert = false
+ workspace_swipe_fingers = 3
+}
+
+
+misc {
+ disable_hyprland_logo = true
+
+ focus_on_activate = true
+
+ enable_swallow = true
+ #swallow_regex = ^(scratchpad)$
+}
+
+
+binds {
+ allow_workspace_cycles = true
+}
+
+
+custom {
+
+}
+
+
+layerrule = blur, bar0
+layerrule = noanim, bar0
+layerrule = ignorealpha 0.2, bar0
+layerrule = blur, dock0
+layerrule = noanim, dock0
+layerrule = ignorealpha 0.2, dock0
+layerrule = blur, indicator0
+layerrule = ignorealpha 0.2, indicator0
+layerrule = blur, toolbox0
+layerrule = noanim, toolbox0
+layerrule = ignorealpha 0.2, toolbox0
+layerrule = blur, applauncher
+layerrule = ignorealpha 0.2, applauncher
+layerrule = blur, datemenu
+layerrule = ignorealpha 0.2, datemenu
+layerrule = blur, quicksettings
+layerrule = ignorealpha 0.2, quicksettings
+layerrule = blur, wlroots
+layerrule = ignorealpha 0.2, wlroots
+layerrule = blur, notifications0
+layerrule = ignorealpha 0.2, notifications0
+
diff --git a/linux/home/.config/hypr/scripts/move-scratchpad.sh b/linux/home/.config/hypr/scripts/move-scratchpad.sh
new file mode 100755
index 0000000..a8d0731
--- /dev/null
+++ b/linux/home/.config/hypr/scripts/move-scratchpad.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# Number of pixels to move down
+pixels_to_move=10
+
+# Get the PID of each scratchpad window and move it down
+for pid in "$(hyprctl -j clients | jq -r '.[] | select(.class == "scratchpad") | .pid')"; do
+ hyprctl dispatch movewindowpixel 0 "$pixels_to_move",pid:"$pid"
+done
diff --git a/linux/home/.config/hypr/user/binds.conf b/linux/home/.config/hypr/user/binds.conf
new file mode 100644
index 0000000..a337a0e
--- /dev/null
+++ b/linux/home/.config/hypr/user/binds.conf
@@ -0,0 +1,167 @@
+# Window Manager keybindings
+
+# Scratchpad
+bind = SUPER, semicolon, exec, ~/.scripts/scratchpad && bash ~/.config/hypr/scripts/move-scratchpad.sh
+bind = SUPER, X, exec, ~/.scripts/scratchpad && bash ~/.config/hypr/scripts/move-scratchpad.sh
+#bind = SUPER, semicolon, exec, ~/.scripts/scratchpad
+#bind = SUPER, X, exec, ~/.scripts/scratchpad
+
+# HUD
+bind = SUPER, E, exec, ~/.scripts/heads-up-display
+
+# Package manager Terminal
+bind = SUPER, Q, exec, ~/.scripts/pac
+
+# Mouse binds
+bindm = SUPER, mouse:272, movewindow
+bindm = SUPER, mouse:273, resizewindow
+bind = SUPER, mouse_down, workspace, e-1
+bind = SUPER, mouse_up, workspace, e+1
+
+# Screenshot binds
+bind = , Print, exec,~/.scripts/screenshot_full
+bind = ALT, Print, exec,~/.scripts/screenshot
+
+# Application binds
+$term=wezterm
+bind = SUPER, T, exec, $term -e tmux new-session -A -s term
+bind = SUPER, Enter, exec, $term -e tmux new-session -A -s term
+bind = SUPER, W, exec, $browser
+#bind = SUPER, G, exec, $notepad
+
+# ags
+bind = SUPER_SHIFT, R, exec, ags -q; ags; notify-send "ags reloaded"
+bind=SUPER, Space, exec, ags -t launcher
+bind=,XF86PowerOff, exec, ags -t powermenu
+bind=SUPER, escape, exec, ags -t powermenu
+bind=SUPER, Tab, exec, ags -t overview
+#bind = SUPER, Space, exec, ags -r "toggleLauncher()"
+
+# Clipboard
+bind = SUPER, V, exec, pkill wofi || cliphist list | wofi --dmenu -p clippick -l top_right -x -15 -y 10 -n | cliphist decode | wl-copy
+
+
+# Hyprland keys
+bind=SUPER_SHIFT,Escape,exec,hyprctl reload; notify-send "Config Reloaded"
+bind = SUPER, D, killactive,
+#bind = SUPER_SHIFT, S, movetoworkspace,special
+#bind = SUPER, S, togglespecialworkspace,
+
+
+# Other dispatchers
+bind = ALT, Tab, cyclenext
+bind = SUPER, C, cyclenext
+bind = SUPER, F, fullscreen
+#bind = SUPER, T, exec, hyprctl dispatch centerwindow none
+bind = SUPER, M, fullscreen, 1
+bind = SUPER_SHIFT, M, fakefullscreen
+
+
+bind = SUPER, P, pseudo,
+bind = SUPER, S, togglefloating,
+bind = SUPER_SHIFT, G, togglegroup,
+bind = SUPER, tab, changegroupactive,
+bind = SUPER_SHIFT, I, togglesplit, # dwindle
+
+
+# Move window with SUPER + Shift + arrow keys
+# [↑]
+# [←] [↓] [→]
+bind = SUPER_SHIFT, left, movewindow, l
+bind = SUPER_SHIFT, right, movewindow, r
+bind = SUPER_SHIFT, up, movewindow, u
+bind = SUPER_SHIFT, down, movewindow, d
+bind = SUPER_SHIFT, H, movewindow, l
+bind = SUPER_SHIFT, L, movewindow, r
+bind = SUPER_SHIFT, K, movewindow, u
+bind = SUPER_SHIFT, J, movewindow, d
+
+# Move window focus with SUPER + arrow keys
+# [↑]
+# [←] [↓] [→]
+bind = SUPER, left, movefocus, l
+bind = SUPER, right, movefocus, r
+bind = SUPER, up, movefocus, u
+bind = SUPER, down, movefocus, d
+bind = SUPER, H, movefocus, l
+bind = SUPER, L, movefocus, r
+bind = SUPER, K, movefocus, u
+bind = SUPER, J, movefocus, d
+
+# Move To a workspaces
+bind = SUPER, 1, workspace, 1
+bind = SUPER, 2, workspace, 2
+bind = SUPER, 3, workspace, 3
+bind = SUPER, 4, workspace, 4
+bind = SUPER, 5, workspace, 5
+bind = SUPER, 6, workspace, 6
+bind = SUPER, 7, workspace, 7
+bind = SUPER, 8, workspace, 8
+bind = SUPER, 9, workspace, 9
+
+# Move windows between workspaces
+bind = SUPER_SHIFT, 1, movetoworkspace, 1
+bind = SUPER_SHIFT, 2, movetoworkspace, 2
+bind = SUPER_SHIFT, 3, movetoworkspace, 3
+bind = SUPER_SHIFT, 4, movetoworkspace, 4
+bind = SUPER_SHIFT, 5, movetoworkspace, 5
+bind = SUPER_SHIFT, 6, movetoworkspace, 6
+bind = SUPER_SHIFT, 7, movetoworkspace, 7
+bind = SUPER_SHIFT, 8, movetoworkspace, 8
+bind = SUPER_SHIFT, 9, movetoworkspace, 9
+
+
+# Use this to get thw XF86 bind (FN + Fx combination) for your keyboard
+# xev | grep -A2 --line-buffered '^KeyRelease' | sed -n '/keycode /s/^.*keycode \([0-9]*\).* (.*, \(.*\)).*$/\1 \2/p'
+
+# Volume Control
+#binde = , XF86AudioRaiseVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ +1%
+#binde = , XF86AudioLowerVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ -1%
+bind = , XF86AudioMute, exec, pactl set-sink-mute @DEFAULT_SINK@ toggle
+bind = , XF86AudioMicMute, exec, pactl set-source-mute @DEFAULT_SOURCE@ toggle
+bind = ALT, down, exec, pactl set-sink-volume @DEFAULT_SINK@ -5%
+bind = ALT, up, exec, pactl set-sink-volume @DEFAULT_SINK@ +5%
+
+# Media Control
+bind = , XF86AudioMedia, exec, playerctl play-pause
+bind = , XF86AudioPlay, exec, playerctl play-pause
+bind = , XF86AudioStop, exec, playerctl stop
+bind = , XF86AudioPrev, exec, playerctl previous
+bind = , XF86AudioNext, exec, playerctl next
+
+# Use arrow keys as multimedia keys
+bind = ALT_SHIFT, left, exec, playerctl previous
+bind = ALT_SHIFT, up, exec, playerctl play-pause
+bind = ALT_SHIFT, right, exec, playerctl next
+
+# Brightness Control
+binde = , XF86MonBrightnessUp, exec, light -A 1
+binde = , XF86MonBrightnessDown, exec, light -U 1
+
+bind = ALT, left, exec, brightnessctl set 10%- # Screen brightness down FN+F7
+bind = ALT, right, exec, brightnessctl set 10%+ # Screen brightness up FN+F8
+
+# Screensaver key
+bind = , XF86ScreenSaver, exec,~/.scripts/lock
+
+bind = SUPER_SHIFT, Y, exec, spotify
+bind = SUPER_SHIFT, D, exec, discord
+bind = SUPER , W, exec, firefox
+bind = SUPER_SHIFT, B, exec, rofi-rbw
+
+# Others
+#bind = , XF86Mail, exec,$gmail
+#bind = , XF86HomePage, exec, $explorer ~/
+#bind = , XF86Calculator, exec, qalculate-gtk
+#bind = , XF86Search, exec, wofi
+
+$mainMod = SUPER
+bind = $mainMod, tilde, exec, ~/.scripts/translate.sh
+bind = $mainMod CONTROL, k, exec, ~/.scripts/killmenu
+
+
+
+# trigger when the switch is turning on
+# bindl = , switch:on:Lid Switch, exec, hyprctl keyword monitor ", 1920x1080@60, auto, 1"
+# trigger when the switch is turning off
+bindl = , switch:off:Lid Switch, exec, playerctl --all-players stop; ~/.scripts/lock; systemctl suspend
diff --git a/linux/home/.config/hypr/user/env.conf b/linux/home/.config/hypr/user/env.conf
new file mode 100644
index 0000000..93f7694
--- /dev/null
+++ b/linux/home/.config/hypr/user/env.conf
@@ -0,0 +1,23 @@
+#Environment Variables for the Hyprland session
+
+# XDG
+env = XDG_CURRENT_DESKTOP,Hyprland
+env = XDG_SESSION_TYPE,wayland
+env = XDG_SESSION_DESKTOP,Hyprland
+
+# QT
+env = QT_AUTO_SCREEN_SCALE_FACTOR,1
+env = QT_QPA_PLATFORM=wayland;xcb # Not yet working for onlyoffice-editor
+env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
+env = QT_QPA_PLATFORMTHEME,qt6ct
+
+# GTK
+#env = GDK_BACKEND=wayland
+
+# Toolkit
+#env = SDL_VIDEODRIVER,wayland
+env = _JAVA_AWT_WM_NONEREPARENTING,1
+env = CLUTTER_BACKEND,wayland
+env = GDK_BACKEND,wayland,x11
+env = MOZ_ENABLE_WAYLAND,1
+
diff --git a/linux/home/.config/hypr/user/exec.conf b/linux/home/.config/hypr/user/exec.conf
new file mode 100644
index 0000000..22846d9
--- /dev/null
+++ b/linux/home/.config/hypr/user/exec.conf
@@ -0,0 +1,4 @@
+exec-once=$HOME/.config/hypr/autostart
+exec-once = swww kill; swww init --format xrgb
+exec = ags
+exec =$HOME/.scripts/move-qemu.sh
diff --git a/linux/home/.config/hypr/user/monitors.conf b/linux/home/.config/hypr/user/monitors.conf
new file mode 100644
index 0000000..7464786
--- /dev/null
+++ b/linux/home/.config/hypr/user/monitors.conf
@@ -0,0 +1,4 @@
+monitor=auto,preferred,auto, 1, bitdepth,10
+#monitor=, 1920x1080@60, auto, 1
+#monitor=, 1366x768@60, auto, 1
+#monitor=LVDS-1, 1366x768@60, auto, 1, bitdepth,10
diff --git a/linux/home/.config/hypr/user/window_rules.conf b/linux/home/.config/hypr/user/window_rules.conf
new file mode 100644
index 0000000..3964de2
--- /dev/null
+++ b/linux/home/.config/hypr/user/window_rules.conf
@@ -0,0 +1,70 @@
+# {{@@ header() @@}}
+# vim:fileencoding=utf-8:ft=conf:foldmethod=marker
+
+# Workspaces
+windowrulev2 = workspace 1 silent, class:firefox
+windowrulev2 = workspace 4 silent, class:discord
+windowrulev2 = workspace 5 silent, class:Spotify
+
+# Scratchpad
+$scratchpad = class:^(scratchpad)$
+windowrulev2 = opacity 1 0.9,class:^(scratchpad)$
+windowrulev2 = float,$scratchpad
+#windowrule = float,^(scratchpad)$
+#windowrule = move 15 40, ^(scratchpad)$
+#windowrule = move center,^(scratchpad)$
+#$scratchpadsize = size 98% 93%
+#windowrulev2 = tile,$scratchpad
+#windowrulev2 = pin,$scratchpad
+#windowrulev2=windowdance,$scratchpad
+#windowrulev2 = move 100%-20,$scratchpad
+#windowrulev2 = $scratchpadsize,$scratchpad
+
+# HUD
+windowrule = float, ^(heads-up-display)$
+windowrule = pin, ^(heads-up-display)$
+windowrule = size 325 160, ^(heads-up-display)$
+windowrule = move 1020 50, ^(heads-up-display)$
+
+# Package manager Terminal
+windowrule = float, ^(pac)$
+windowrule = pin, ^(pac)$
+windowrule = size 325 160, ^(pac)$
+windowrule = move 50 50, ^(pac)$
+
+# Picture-in-Picture
+windowrulev2 = idleinhibit fullscreen, title:^Picture-in-Picture$
+windowrulev2 = float, title:^Picture-in-Picture$
+windowrulev2 = pin, title:^Picture-in-Picture$
+windowrulev2 = move 920 480, title:^Picture-in-Picture$
+windowrulev2 = size 425 260, title:^Picture-in-Picture$
+
+# Firefox
+windowrulev2 = float, class:^(firefox)$, title:^(Firefox — Sharing Indicator)$
+windowrulev2 = opacity 1 1,class:^(firefox)$
+
+# Applications
+windowrule = float,^(rlr)$
+windowrule = float,^(pavucontrol)$
+windowrule = float,^(blueman-manager)$
+windowrule = float,^(nm-connection-editor)$
+windowrule = float,^(mediainfo-gui)$
+windowrulev2 = float, class:^(nemo)$, title:^(.*Properties)$
+windowrulev2 = float, class:^(Nemo-preview-start)$
+windowrulev2 = move 100%-433 53, class:^(wofi)$, title:^(clippick)$
+windowrulev2 = animation popin, class:^(wlogout)$, title:^(wlogout)$
+windowrulev2 = float, class:^(wlogout)$, title:^(wlogout)$
+windowrulev2 = animation slide, class:^(wofi)$
+#windowrulev2 = float, class:^(steam)$
+windowrule = float,^(com.github.neithern.g4music)$
+windowrule = size 670 635,^(com.github.neithern.g4music)$
+windowrule = move center,^(com.github.neithern.g4music)$
+windowrulev2 = opacity 0.0 override,class:^(xwaylandvideobridge)$
+windowrulev2 = noanim,class:^(xwaylandvideobridge)$
+windowrulev2 = noinitialfocus,class:^(xwaylandvideobridge)$
+windowrulev2 = maxsize 1 1,class:^(xwaylandvideobridge)$
+windowrulev2 = noblur,class:^(xwaylandvideobridge)$
+
+# Blur
+windowrule = noblur,^(firefox)$ # disables blur for firefox
+windowrule = noblur,^(scratchpad)$ # disables blur for firefox
diff --git a/linux/home/.config/inputrc b/linux/home/.config/inputrc
new file mode 100644
index 0000000..adfeec4
--- /dev/null
+++ b/linux/home/.config/inputrc
@@ -0,0 +1,86 @@
+$include /etc/inputrc
+
+"\f": clear-screen
+
+set bell-style none
+set meta-flag on
+set input-meta on
+set convert-meta off
+set output-meta on
+set show-all-if-ambiguous on # set show-all-if-unmodified on
+
+# Color files by types
+# Note that this may cause completion text blink in some terminals (e.g. xterm).
+set colored-stats On
+# Append char to indicate type
+set visible-stats On
+# Mark symlinked directories
+set mark-symlinked-directories On
+# Color the common prefix
+set colored-completion-prefix On
+# Color the common prefix in menu-complete
+set menu-complete-display-prefix On
+
+# set editing-mode vi
+set show-mode-in-prompt on
+set keyseq-timeout 0 # Reduce the delay between pressing escape and the cursor change
+set vi-cmd-mode-string "\1\e[2 q\2"
+set vi-ins-mode-string "\1\e[6 q\2"
+
+$if mode=vi
+ set keymap vi-command
+ # these are for vi-command mode
+ "\e[A": history-search-backward
+ "\e[B": history-search-forward
+ j: history-search-forward
+ k: history-search-backward
+ set keymap vi-insert
+ # these are for vi-insert mode
+ "\e[A": history-search-backward
+ "\e[B": history-search-forward
+ "jk" # escape
+$endif
+
+$if mode=emacs
+
+ "\C-P": history-search-backward
+ "\C-N": history-search-forward
+
+ # for linux console and RH/Debian xterm
+ "\e[1~": beginning-of-line
+ "\e[4~": end-of-line
+ "\e[5~": beginning-of-history
+ "\e[6~": end-of-history
+ "\e[7~": beginning-of-line
+ "\e[3~": delete-char
+ "\e[2~": quoted-insert
+ "\e[5C": forward-word
+ "\e[5D": backward-word
+ "\e\e[C": forward-word
+ "\e\e[D": backward-word
+ "\e[1;5C": forward-word
+ "\e[1;5D": backward-word
+
+ # for rxvt
+ "\e[8~": end-of-line
+
+ # for non RH/Debian xterm, can't hurt for RH/DEbian xterm
+ "\eOH": beginning-of-line
+ "\eOF": end-of-line
+
+ # for freebsd console
+ "\e[H": beginning-of-line
+ "\e[F": end-of-line
+
+$endif
+
+#set editing-mode emacs
+set editing-mode vi
+
+# # switch between vi or emacs
+# set keymap emacs
+# "\e[": vi-editing-mode
+# set keymap vi-insert
+# "\e[": emacs-editing-mode
+# set keymap vi-command
+# "\e[": emacs-editing-mode
diff --git a/linux/home/.config/jgmenu/jgmenurc b/linux/home/.config/jgmenu/jgmenurc
new file mode 100644
index 0000000..d35eee6
--- /dev/null
+++ b/linux/home/.config/jgmenu/jgmenurc
@@ -0,0 +1,32 @@
+stay_alive = 1
+tint2_look = 0
+position_mode = pointer
+terminal_exec = wezterm
+terminal_args = -x
+sub_spacing = 5
+menu_width = 200
+menu_padding_top = 5
+menu_padding_right = 2
+menu_padding_bottom = 5
+menu_padding_left = 2
+menu_radius = 7
+menu_border = 0
+menu_halign = left
+sub_hover_action = 1
+item_margin_y = 5
+item_height = 30
+item_padding_x = 8
+item_radius = 6
+item_border = 0
+sep_height = 5
+font = Roboto Medium 15px
+icon_theme = Papirus
+icon_size = 24
+color_menu_bg = #171B20 80
+color_menu_border = #c0caf5
+color_norm_bg = #171B20 0
+color_norm_fg = #b6beca 100
+color_sel_bg = #74bee9 50
+color_sel_fg = #b6beca 100
+color_sep_fg = b6beca 80
+csv_cmd = cat ~/.config/jgmenu/menu.csv
diff --git a/linux/home/.config/jgmenu/menu.csv b/linux/home/.config/jgmenu/menu.csv
new file mode 100644
index 0000000..dbece5a
--- /dev/null
+++ b/linux/home/.config/jgmenu/menu.csv
@@ -0,0 +1,32 @@
+Terminal,scratchpad,utilities-terminal
+Web-browser,firefox,web-browser
+Neovim,kitty -e nvim,nvim
+Ranger,wezterm -e ranger,stock_folder
+^sep()
+
+Extras,^checkout(extras),add
+^sep()
+
+Critical,^checkout(critical),gtk-dialog-warning
+^sep()
+
+Lock,betterlockscreen --lock,system-lock-screen
+Logout,pkill -KILL -u "$USER" &,system-log-out
+
+Exit,^checkout(exit),exit
+
+^tag(exit)
+Suspend,systemctl suspend,system-suspend
+Reboot,reboot,system-reboot
+Poweroff,poweroff,system-shutdown
+
+^tag(extras)
+Change wallpaper,nitrogen,nitrogen
+Randomize Wallpaper,random-wall
+Control-center,~/.config/eww/scripts/openControlCenter.sh
+Reload eww,pkill -f eww && eww daemon
+
+^tag(critical)
+Restart BSPWM,control_box -bspres
+Restart SXHKD,control_box -kbres,input-keyboard
+Restart Pipewire,control_box -soundres,audio-speakers
diff --git a/linux/home/.config/kitty/kitty.conf b/linux/home/.config/kitty/kitty.conf
new file mode 100644
index 0000000..cbf9f70
--- /dev/null
+++ b/linux/home/.config/kitty/kitty.conf
@@ -0,0 +1,827 @@
+
+# vim:fileencoding=utf-8:ft=conf:foldmethod=marker
+
+#: Fonts {{{
+
+#: kitty has very powerful font management. You can configure
+#: individual font faces and even specify special fonts for particular
+#: characters.
+
+font_family JetBrains Mono Medium
+bold_font auto
+italic_font auto
+bold_italic_font auto
+
+#: You can specify different fonts for the bold/italic/bold-italic
+#: variants. By default they are derived automatically, by the OSes
+#: font system. Setting them manually is useful for font families that
+#: have many weight variants like Book, Medium, Thick, etc. For
+#: example:
+
+#: font_family Operator Mono Book
+#: bold_font Operator Mono Medium
+#: italic_font Operator Mono Book Italic
+#: bold_italic_font Operator Mono Medium Italic
+
+font_size 9.0
+
+#: Font size (in pts)
+
+# adjust_line_height 0
+# adjust_column_width 0
+
+#: Change the size of each character cell kitty renders. You can use
+#: either numbers, which are interpreted as pixels or percentages
+#: (number followed by %), which are interpreted as percentages of the
+#: unmodified values. You can use negative pixels or percentages less
+#: than 100% to reduce sizes (but this might cause rendering
+#: artifacts).
+
+# symbol_map U+E0A0-U+E0A2,U+E0B0-U+E0B3 PowerlineSymbols
+
+#: Map the specified unicode codepoints to a particular font. Useful
+#: if you need special rendering for some symbols, such as for
+#: Powerline. Avoids the need for patched fonts. Each unicode code
+#: point is specified in the form U+<code point in hexadecimal>. You
+#: can specify multiple code points, separated by commas and ranges
+#: separated by hyphens. symbol_map itself can be specified multiple
+#: times. Syntax is::
+
+#: symbol_map codepoints Font Family Name
+
+# box_drawing_scale 0.001, 1, 1.5, 2
+
+#: Change the sizes of the lines used for the box drawing unicode
+#: characters These values are in pts. They will be scaled by the
+#: monitor DPI to arrive at a pixel value. There must be four values
+#: corresponding to thin, normal, thick, and very thick lines.
+
+#: }}}
+
+#: Cursor customization {{{
+
+# cursor magenta
+cursor white
+
+#: Default cursor color
+
+# cursor_shape block
+
+#: The cursor shape can be one of (block, beam, underline)
+
+cursor_blink_interval 0.5
+cursor_stop_blinking_after 15.0
+
+#: The interval (in seconds) at which to blink the cursor. Set to zero
+#: to disable blinking. Note that numbers smaller than repaint_delay
+#: will be limited to repaint_delay. Stop blinking cursor after the
+#: specified number of seconds of keyboard inactivity. Set to zero to
+#: never stop blinking.
+
+#: }}}
+
+#: Scrollback {{{
+
+scrollback_lines 20000
+
+#: Number of lines of history to keep in memory for scrolling back.
+#: Memory is allocated on demand.
+
+# scrollback_pager less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER
+
+#: Program with which to view scrollback in a new window. The
+#: scrollback buffer is passed as STDIN to this program. If you change
+#: it, make sure the program you use can handle ANSI escape sequences
+#: for colors and text formatting. INPUT_LINE_NUMBER in the command
+#: line above will be replaced by an integer representing which line
+#: should be at the top of the screen.
+
+wheel_scroll_multiplier 5
+
+#: Modify the amount scrolled by the mouse wheel or touchpad. Use
+#: negative numbers to change scroll direction.
+
+#: }}}
+
+#: Mouse {{{
+
+url_color #0087BD
+url_style curly
+
+#: The color and style for highlighting URLs on mouse-over. url_style
+#: can be one of: none, single, double, curly
+
+open_url_modifiers kitty_mod
+
+#: The modifier keys to press when clicking with the mouse on URLs to
+#: open the URL
+
+open_url_with default
+
+#: The program with which to open URLs that are clicked on. The
+#: special value default means to use the operating system's default
+#: URL handler.
+
+copy_on_select yes
+
+#: Copy to clipboard on select. With this enabled, simply selecting
+#: text with the mouse will cause the text to be copied to clipboard.
+#: Useful on platforms such as macOS/Wayland that do not have the
+#: concept of primary selectons. Note that this is a security risk,
+#: as all programs, including websites open in your browser can read
+#: the contents of the clipboard.
+
+# rectangle_select_modifiers ctrl+alt
+
+#: The modifiers to use rectangular selection (i.e. to select text in
+#: a rectangular block with the mouse)
+
+# select_by_word_characters :@-./_~?&=%+#
+
+#: Characters considered part of a word when double clicking. In
+#: addition to these characters any character that is marked as an
+#: alpha-numeric character in the unicode database will be matched.
+
+click_interval 0.5
+
+#: The interval between successive clicks to detect double/triple
+#: clicks (in seconds)
+
+# mouse_hide_wait 3.0
+
+#: Hide mouse cursor after the specified number of seconds of the
+#: mouse not being used. Set to zero to disable mouse cursor hiding.
+
+# focus_follows_mouse no
+
+#: Set the active window to the window under the mouse when moving the
+#: mouse around
+
+#: }}}
+
+#: Performance tuning {{{
+
+repaint_delay 10
+
+#: Delay (in milliseconds) between screen updates. Decreasing it,
+#: increases frames-per-second (FPS) at the cost of more CPU usage.
+#: The default value yields ~100 FPS which is more than sufficient for
+#: most uses. Note that to actually achieve 100 FPS you have to either
+#: set sync_to_monitor to no or use a monitor with a high refresh
+#: rate.
+
+# input_delay 3
+
+#: Delay (in milliseconds) before input from the program running in
+#: the terminal is processed. Note that decreasing it will increase
+#: responsiveness, but also increase CPU usage and might cause flicker
+#: in full screen programs that redraw the entire screen on each loop,
+#: because kitty is so fast that partial screen updates will be drawn.
+
+# sync_to_monitor yes
+
+#: Sync screen updates to the refresh rate of the monitor. This
+#: prevents tearing (https://en.wikipedia.org/wiki/Screen_tearing)
+#: when scrolling. However, it limits the rendering speed to the
+#: refresh rate of your monitor. With a very high speed mouse/high
+#: keyboard repeat rate, you may notice some slight input latency. If
+#: so, set this to no.
+
+#: }}}
+
+#: Terminal bell {{{
+
+enable_audio_bell no
+
+#: Enable/disable the audio bell. Useful in environments that require
+#: silence.
+
+# visual_bell_duration 0.5
+
+#: Visual bell duration. Flash the screen when a bell occurs for the
+#: specified number of seconds. Set to zero to disable.
+
+window_alert_on_bell yes
+
+#: Request window attention on bell. Makes the dock icon bounce on
+#: macOS or the taskbar flash on linux.
+
+bell_on_tab yes
+
+#: Show a bell symbol on the tab if a bell occurs in one of the
+#: windows in the tab and the window is not the currently focused
+#: window
+
+#: }}}
+
+#: Window layout {{{
+
+# remember_window_size yes
+# initial_window_width 640
+# initial_window_height 400
+
+#: If enabled, the window size will be remembered so that new
+#: instances of kitty will have the same size as the previous
+#: instance. If disabled, the window will initially have size
+#: configured by initial_window_width/height, in pixels. You can use a
+#: suffix of "c" on the width/height values to have them interpreted
+#: as number of cells instead of pixels.
+
+enabled_layouts *
+
+#: The enabled window layouts. A comma separated list of layout names.
+#: The special value * means all layouts. The first listed layout will
+#: be used as the startup layout. For a list of available layouts, see
+#: the layouts.
+
+# window_resize_step_cells 2
+# window_resize_step_lines 2
+
+#: The step size (in units of cell width/cell height) to use when
+#: resizing windows. The cells value is used for horizontal resizing
+#: and the lines value for vertical resizing.
+
+window_border_width 1
+
+#: The width (in pts) of window borders. Will be rounded to the
+#: nearest number of pixels based on screen resolution. Note that
+#: borders are displayed only when more than one window is visible.
+#: They are meant to separate multiple windows.
+
+window_margin_width 0
+
+#: The window margin (in pts) (blank area outside the border)
+
+# single_window_margin_width -1000.0
+
+#: The window margin (in pts) to use when only a single window is
+#: visible. Negative values will cause the value of
+#: window_margin_width to be used instead.
+
+window_padding_width 2
+
+#: The window padding (in pts) (blank area between the text and the
+#: window border)
+
+active_border_color #282c34
+
+#: The color for the border of the active window
+
+inactive_border_color #22262d
+
+#: The color for the border of inactive windows
+
+# bell_border_color #ff5a00
+
+#: The color for the border of inactive windows in which a bell has
+#: occurred
+
+inactive_text_alpha .6
+
+#: Fade the text in inactive windows by the specified amount (a number
+#: between zero and one, with zero being fully faded).
+
+#: }}}
+
+#: Tab bar {{{
+
+# tab_bar_edge bottom
+
+#: Which edge to show the tab bar on, top or bottom
+
+tab_bar_margin_width 4
+
+#: The margin to the left and right of the tab bar (in pts)
+
+tab_bar_style fade
+
+#: The tab bar style, can be one of: fade or separator. In the fade
+#: style, each tab's edges fade into the background color, in the
+#: separator style, tabs are separated by a configurable separator.
+
+# tab_fade 0.25 0.5 0.75 1
+tab_fade 1 1 1
+
+#: Control how each tab fades into the background when using fade for
+#: the tab_bar_style. Each number is an alpha (between zero and one)
+#: that controls how much the corresponding cell fades into the
+#: background, with zero being no fade and one being full fade. You
+#: can change the number of cells used by adding/removing entries to
+#: this list.
+
+# tab_separator " "
+
+#: The separator between tabs in the tab bar when using separator as
+#: the tab_bar_style.
+
+active_tab_foreground #282c34
+active_tab_background #abb2bf
+active_tab_font_style bold
+inactive_tab_foreground #5c6370
+inactive_tab_background #22262d
+inactive_tab_font_style normal
+
+#: Tab bar colors and styles
+
+#: }}}
+
+#: Color scheme {{{
+
+foreground #d8dee9
+#background #1d1f21
+background #000000
+
+#: The foreground and background colors
+
+background_opacity 0.7
+dynamic_background_opacity yes
+# Increase background opacity ctrl+shift+a>m
+
+# Decrease background opacity ctrl+shift+a>l
+
+# Full background opacity ctrl+shift+a>1
+
+# Reset background opacity ctrl+shift+a>d
+
+#: The opacity of the background. A number between 0 and 1, where 1 is
+#: opaque and 0 is fully transparent. This will only work if
+#: supported by the OS (for instance, when using a compositor under
+#: X11). Note that it only sets the default background color's
+#: opacity. This is so that things like the status bar in vim,
+#: powerline prompts, etc. still look good. But it means that if you
+#: use a color theme with a background color in your editor, it will
+#: not be rendered as transparent. Instead you should change the
+#: default background color in your kitty config and not use a
+#: background color in the editor color scheme. Or use the escape
+#: codes to set the terminals default colors in a shell script to
+#: launch your editor. Be aware that using a value less than 1.0 is a
+#: (possibly significant) performance hit. If you want to dynamically
+#: change transparency of windows set dynamic_background_opacity to
+#: yes (this is off by default as it has a performance cost)
+
+dim_opacity 1.0
+
+#: How much to dim text that has the DIM/FAINT attribute set. One
+#: means no dimming and zero means fully dimmed (i.e. invisible).
+
+selection_foreground #000000
+selection_background #FFFACD
+
+#: The foreground and background for text selected with the mouse
+
+
+#: The 16 terminal colors. There are 8 basic colors, each color has a
+#: dull and bright version. You can also set the remaining colors from
+#: the 256 color table as color16 to color255.
+
+#: black
+color0 #313539
+color8 #676f78
+
+#: red
+color1 #b02626
+color9 #b55454
+
+#: green
+color2 #40a62f
+color10 #78a670
+
+#: yellow
+color3 #f2e635
+color11 #faf380
+
+#: blue
+color4 #314ad0
+color12 #707fd0
+
+#: magenta
+color5 #b30ad0
+color13 #c583d0
+
+#: cyan
+color6 #32d0fc
+color14 #8adaf1
+
+#: white
+color7 #acadb1
+color15 #e0e3e7
+
+
+#: }}}
+
+#: Advanced {{{
+
+# shell zsh
+
+#: The shell program to execute. The default value of . means to use
+#: whatever shell is set as the default shell for the current user.
+#: Note that on macOS if you change this, you might need to add
+#: --login to ensure that the shell starts in interactive mode and
+#: reads its startup rc files.
+
+editor .
+
+#: The console editor to use when editing the kitty config file or
+#: similar tasks. A value of . means to use the environment variable
+#: EDITOR. Note that this environment variable has to be set not just
+#: in your shell startup scripts but system-wide, otherwise kitty will
+#: not see it.
+
+# Confirm when closing where 0 disables it; -1 enables it
+confirm_os_window_close 0
+
+# close_on_child_death nvim
+
+#: Close the window when the child process (shell) exits. If no (the
+#: default), the terminal will remain open when the child exits as
+#: long as there are still processes outputting to the terminal (for
+#: example disowned or backgrounded processes). If yes, the window
+#: will close as soon as the child process exits. Note that setting it
+#: to yes means that any background processes still using the terminal
+#: can fail silently because their stdout/stderr/stdin no longer work.
+
+# allow_remote_control no
+
+#: Allow other programs to control kitty. If you turn this on other
+#: programs can control all aspects of kitty, including sending text
+#: to kitty windows, opening new windows, closing windows, reading the
+#: content of windows, etc. Note that this even works over ssh
+#: connections.
+
+# startup_session none
+
+#: Path to a session file to use for all kitty instances. Can be
+#: overridden by using the kitty --session command line option for
+#: individual instances. See sessions in the kitty documentation for
+#: details. Note that relative paths are interpreted with respect to
+#: the kitty config directory. Environment variables in the path are
+#: expanded.
+
+# clipboard_control write-clipboard write-primary
+clipboard_control write-primary write-clipboard no-append
+
+#: Allow programs running in kitty to read and write from the
+#: clipboard. You can control exactly which actions are allowed. The
+#: set of possible actions is: write-clipboard read-clipboard write-
+#: primary read-primary The default is to allow writing to the
+#: clipboard and primary selection. Note that enabling the read
+#: functionality is a security risk as it means that any program, even
+#: one running on a remote server via SSH can read your clipboard.
+
+#term xterm-kitty
+
+#: The value of the TERM environment variable to set. Changing this
+#: can break many terminal programs, only change it if you know what
+#: you are doing, not because you read some advice on Stack Overflow
+#: to change it.
+
+#: }}}
+
+#: OS specific tweaks {{{
+
+# macos_titlebar_color #22262d
+
+#: Change the color of the kitty window's titlebar on macOS. A value
+#: of system means to use the default system color, a value of
+#: background means to use the background color of the currently
+#: active window and finally you can use an arbitrary color, such as
+#: #12af59 or red. WARNING: This option works by using a hack, as
+#: there is no proper Cocoa API for it. It sets the background color
+#: of the entire window and makes the titlebar transparent. As such it
+#: is incompatible with background_opacity. If you want to use both,
+#: you are probably better off just hiding the titlebar with
+#: macos_hide_titlebar.
+
+# macos_hide_titlebar no
+
+#: Hide the kitty window's title bar on macOS.
+
+hide_window_decorations yes
+
+#: Hide the window decorations (title bar and window borders) on X11
+#: and Wayland. Whether this works and exactly what effect it has
+#: depends on the window manager, as it is the job of the window
+#: manager/compositor to draw window decorations.
+
+# macos_option_as_alt yes
+
+#: Use the option key as an alt key. With this set to no, kitty will
+#: use the macOS native Option+Key = unicode character behavior. This
+#: will break any Alt+key keyboard shortcuts in your terminal
+#: programs, but you can use the macOS unicode input technique.
+
+# macos_hide_from_tasks no
+
+#: Hide the kitty window from running tasks (Option+Tab) on macOS.
+
+# macos_quit_when_last_window_closed no
+
+#: Have kitty quit when all the top-level windows are closed. By
+#: default, kitty will stay running, even with no open windows, as is
+#: the expected behavior on macOS.
+
+linux_display_server x11
+
+#: Choose between Wayland and X11 backends. By default, an appropriate
+#: backend based on the system state is chosen automatically. Set it
+#: to x11 or wayland to force the choice.
+
+#: }}}
+
+#: Keyboard shortcuts {{{
+
+#: For a list of key names, see: GLFW keys
+#: <http://www.glfw.org/docs/latest/group__keys.html>. The name to use
+#: is the part after the GLFW_KEY_ prefix. For a list of modifier
+#: names, see: GLFW mods
+#: <http://www.glfw.org/docs/latest/group__mods.html>
+
+#: On Linux you can also use XKB key names to bind keys that are not
+#: supported by GLFW. See XKB keys
+#: <https://github.com/xkbcommon/libxkbcommon/blob/master/xkbcommon/xkbcommon-
+#: keysyms.h> for a list of key names. The name to use is the part
+#: after the XKB_KEY_ prefix. Note that you should only use an XKB key
+#: name for keys that are not present in the list of GLFW keys.
+
+#: You can use the special action no_op to unmap a keyboard shortcut
+#: that is assigned in the default configuration.
+
+#: You can combine multiple actions to be triggered by a single
+#: shortcut, using the syntax below::
+
+#: map key combine <separator> action1 <separator> action2 <separator> action3 ...
+
+#: For example::
+
+#: map kitty_mod+e combine : new_window : next_layout
+
+#: this will create a new window and switch to the next available
+#: layout
+
+#: You can use multi-key shortcuts using the syntax shown below::
+
+#: map key1>key2>key3 action
+
+#: For example::
+
+#: map ctrl+f>2 set_font_size 20
+
+# kitty_mod ctrl+shift
+
+#: The value of kitty_mod is used as the modifier for all default
+#: shortcuts, you can change it in your kitty.conf to change the
+#: modifiers for all the default shortcuts.
+
+# clear_all_shortcuts no
+
+#: You can have kitty remove all shortcut definition seen up to this
+#: point. Useful, for instance, to remove the default shortcuts.
+
+#: Clipboard {{{
+
+# map cmd+c copy_to_clipboard
+#map kitty_mod+c copy_to_clipboard
+# map cmd+v paste_from_clipboard
+#map kitty_mod+v paste_from_clipboard
+#map kitty_mod+s paste_from_selection
+map shift+insert paste_from_selection
+# map kitty_mod+o pass_selection_to_program
+map ctrl+c copy_to_clipboard
+map ctrl+v paste_from_clipboard
+
+#: You can also pass the contents of the current selection to any
+#: program using pass_selection_to_program. By default, the system's
+#: open program is used, but you can specify your own, for example::
+
+#: map kitty_mod+o pass_selection_to_program firefox
+
+#: You can pass the current selection to a terminal program running in
+#: a new kitty window, by using the @selection placeholder::
+
+#: map kitty_mod+y new_window less @selection
+
+#: }}}
+
+#: Scrolling {{{
+
+#map kitty_mod+up scroll_line_up
+#map ctrl+k scroll_line_up
+#map kitty_mod+k scroll_line_up
+#map kitty_mod+down scroll_line_down
+#map ctrl+j scroll_line_down
+#map kitty_mod+j scroll_line_down
+map kitty_mod+page_up scroll_page_up
+map kitty_mod+page_down scroll_page_down
+map kitty_mod+b scroll_page_up
+map kitty_mod+f scroll_page_down
+# map kitty_mod+home scroll_home
+# map kitty_mod+end scroll_end
+# map kitty_mod+h show_scrollback
+
+#: You can send the contents of the current screen + history buffer as
+#: stdin to an arbitrary program using the placeholders @text (which
+#: is the plain text) and @ansi (which includes text styling escape
+#: codes). For only the current screen, use @screen or @ansi_screen.
+#: For example, the following command opens the scrollback buffer in
+#: less in a new window::
+
+#: map kitty_mod+y new_window @ansi less +G -R
+
+#: }}}
+
+#: Window management {{{
+
+# map kitty_mod+enter new_window
+map kitty_mod+enter no_op
+map kitty_mod+enter new_window_with_cwd
+
+#: You can open a new window running an arbitrary program, for
+#: example::
+
+#: map kitty_mod+y new_window mutt
+
+#: You can open a new window with the current working directory set to
+#: the working directory of the current window using::
+
+#: map ctrl+alt+enter new_window_with_cwd
+
+# map cmd+n new_os_window
+# map kitty_mod+n new_os_window
+# map kitty_mod+w close_window
+# map kitty_mod+] next_window
+# map kitty_mod+[ previous_window
+map kitty_mod+j previous_window
+map kitty_mod+k next_window
+map kitty_mod+up move_window_forward
+map kitty_mod+down move_window_backward
+# map kitty_mod+f move_window_forward
+# map kitty_mod+b move_window_backward
+# map kitty_mod+` move_window_to_top
+# map kitty_mod+r start_resizing_window
+# map kitty_mod+1 first_window
+# map kitty_mod+2 second_window
+# map kitty_mod+3 third_window
+# map kitty_mod+4 fourth_window
+# map kitty_mod+5 fifth_window
+# map kitty_mod+6 sixth_window
+# map kitty_mod+7 seventh_window
+# map kitty_mod+8 eighth_window
+# map kitty_mod+9 ninth_window
+# map kitty_mod+0 tenth_window
+#: }}}
+
+#: Tab management {{{
+
+# map kitty_mod+right next_tab
+# map kitty_mod+left previous_tab
+map kitty_mod+] no_op
+map kitty_mod+] next_tab
+map kitty_mod+[ no_op
+map kitty_mod+[ previous_tab
+# map kitty_mod+t new_tab
+# map kitty_mod+q close_tab
+# map kitty_mod+. move_tab_forward
+# map kitty_mod+, move_tab_backward
+map kitty_mod+right no_op
+map kitty_mod+right move_tab_forward
+map kitty_mod+left no_op
+map kitty_mod+left move_tab_backward
+# map kitty_mod+alt+t set_tab_title
+map kitty_mod+t no_op
+map kitty_mod+t new_tab_with_cwd
+
+#: You can also create shortcuts to go to specific tabs, with 1 being
+#: the first tab::
+
+#: map ctrl+alt+1 goto_tab 1
+#: map ctrl+alt+2 goto_tab 2
+
+#: Just as with new_window above, you can also pass the name of
+#: arbitrary commands to run when using new_tab and use
+#: new_tab_with_cwd.
+#: }}}
+
+#: Layout management {{{
+
+# map kitty_mod+l next_layout
+
+#: You can also create shortcuts to switch to specific layouts::
+
+map kitty_mod+0 no_op
+map kitty_mod+0 goto_layout stack
+map kitty_mod+9 no_op
+map kitty_mod+9 goto_layout tall
+map kitty_mod+8 no_op
+map kitty_mod+8 goto_layout fat
+#: map ctrl+alt+t goto_layout tall
+#: map ctrl+alt+s goto_layout stack
+#: }}}
+
+#: Font sizes {{{
+
+#: You can change the font size for all top-level kitty windows at a
+#: time or only the current one.
+
+map kitty_mod+equal change_font_size all +2.0
+map kitty_mod+minus change_font_size all -2.0
+map kitty_mod+backspace change_font_size all 0
+
+#: To setup shortcuts for specific font sizes::
+
+#: map kitty_mod+f6 change_font_size all 10.0
+
+#: To setup shortcuts to change only the current window's font size::
+
+#: map kitty_mod+f6 change_font_size current 10.0
+#: }}}
+
+#: Select and act on visible text {{{
+
+#: Use the hints kitten to select text and either pass it to an
+#: external program or insert it into the terminal or copy it to the
+#: clipboard.
+
+# map kitty_mod+e kitten hints
+
+#: Open a currently visible URL using the keyboard. The program used
+#: to open the URL is specified in open_url_with.
+
+# map kitty_mod+p>f kitten hints --type path --program -
+
+#: Select a path/filename and insert it into the terminal. Useful, for
+#: instance to run git commands on a filename output from a previous
+#: git command.
+
+# map kitty_mod+p>shift+f kitten hints --type path
+
+#: Select a path/filename and open it with the default open program.
+
+# map kitty_mod+p>l kitten hints --type line --program -
+
+#: Select a line of text and insert it into the terminal. Use for the
+#: output of things like: ls -1
+
+# map kitty_mod+p>w kitten hints --type word --program -
+
+#: Select words and insert into terminal.
+
+# map kitty_mod+p>h kitten hints --type hash --program -
+
+#: Select something that looks like a hash and insert it into the
+#: terminal. Useful with git, which uses sha1 hashes to identify
+#: commits
+
+
+#: The hints kitten has many more modes of operation that you can map
+#: to different shortcuts. For a full description see kittens/hints.
+#: }}}
+
+#: Miscellaneous {{{
+
+
+# map kitty_mod+f11 toggle_fullscreen
+# map kitty_mod+u input_unicode_character
+# map kitty_mod+f2 edit_config_file
+# map kitty_mod+escape kitty_shell window
+
+#: Open the kitty shell in a new window/tab/overlay/os_window to
+#: control kitty using commands.
+
+# map kitty_mod+a>m set_background_opacity +0.1
+# map kitty_mod+a>l set_background_opacity -0.1
+# map kitty_mod+a>1 set_background_opacity 1
+# map kitty_mod+a>d set_background_opacity default
+#
+# map kitty_mod+a>m set_background_opacity +0.1
+# map kitty_mod+a>l set_background_opacity -0.1
+map kitty_mod+, set_background_opacity 1
+map kitty_mod+. set_background_opacity default
+
+#: You can tell kitty to send arbitrary (UTF-8) encoded text to the
+#: client program when pressing specified shortcut keys. For example::
+
+#: map ctrl+alt+a send_text all Special text
+
+#: This will send "Special text" when you press the ctrl+alt+a key
+#: combination. The text to be sent is a python string literal so you
+#: can use escapes like \x1b to send control codes or \u21fb to send
+#: unicode characters (or you can just input the unicode characters
+#: directly as UTF-8 text). The first argument to send_text is the
+#: keyboard modes in which to activate the shortcut. The possible
+#: values are normal or application or kitty or a comma separated
+#: combination of them. The special keyword all means all modes. The
+#: modes normal and application refer to the DECCKM cursor key mode
+#: for terminals, and kitty refers to the special kitty extended
+#: keyboard protocol.
+
+#: Another example, that outputs a word and then moves the cursor to
+#: the start of the line (same as pressing the Home key)::
+
+#: map ctrl+alt+a send_text normal Word\x1b[H
+#: map ctrl+alt+a send_text application Word\x1bOH
+
+#: }}}
+
+map ctrl+space send_text all \x10
+
+# }}}
diff --git a/linux/home/.config/mimeapps.list b/linux/home/.config/mimeapps.list
new file mode 100644
index 0000000..85d088c
--- /dev/null
+++ b/linux/home/.config/mimeapps.list
@@ -0,0 +1,14 @@
+[Default Applications]
+application/pdf=zathura.desktop;
+application/tex=zathura.desktop;
+image/png=phototonic.desktop
+image/jpeg=phototonic.desktop;
+video/mp4=mpv.desktop;
+video/mkv=mpv.desktop;
+inode/directory=pcmanfm.desktop
+
+[Added Associations]
+image/png=phototonic.desktop;
+
+[Removed Associations]
+
diff --git a/linux/home/.config/picom/picom.conf b/linux/home/.config/picom/picom.conf
new file mode 100644
index 0000000..d189670
--- /dev/null
+++ b/linux/home/.config/picom/picom.conf
@@ -0,0 +1,494 @@
+#################################
+# Animations #
+#################################
+# requires https://github.com/jonaburg/picom
+# (These are also the default values)
+transition-length = 300
+transition-pow-x = 0.1
+transition-pow-y = 0.1
+transition-pow-w = 0.1
+transition-pow-h = 0.1
+size-transition = true
+
+
+#################################
+# Corners #
+#################################
+# requires: https://github.com/sdhand/compton or https://github.com/jonaburg/picom
+corner-radius = 10.0;
+rounded-corners-exclude = [
+#"window_type = 'normal'",
+# "class_g = 'Bspwm' && class_i = 'presel_feedback'",
+# "class_g = 'URxvt'",
+# "class_g = 'alacritty'",
+# "class_g = 'Org.gnome.Nautilus'",
+# "class_g = 'Nemo'",
+# "class_g = 'firefox'",
+# "class_g = 'Rofi'",
+# "class_g = 'Spotify'",
+# "class_g = 'discord'",
+# "class_g = 'Code'",
+# "class_g = 'TelegramDesktop'",
+# "class_g = 'YouTube Music'",
+ "class_g = 'Polybar'"
+# "class_g = 'qutebrowser'",
+# "class_g = 'Zathura'",
+# "class_g = 'Pavucontrol'"
+
+];
+round-borders = 1;
+#round-borders-exclude = [
+# "class_g = 'TelegramDesktop'",
+#];
+
+
+
+#################################
+# Shadows #
+#################################
+
+
+# Enabled client-side shadows on windows. Note desktop windows
+# (windows with '_NET_WM_WINDOW_TYPE_DESKTOP') never get shadow,
+# unless explicitly requested using the wintypes option.
+#
+shadow = false;
+#shadow = true;
+
+# The blur radius for shadows, in pixels. (defaults to 12)
+# shadow-radius = 12
+shadow-radius = 20;
+
+# The opacity of shadows. (0.0 - 1.0, defaults to 0.75)
+# shadow-opacity = .75
+
+# The left offset for shadows, in pixels. (defaults to -15)
+# shadow-offset-x = -15
+shadow-offset-x = -5;
+
+# The top offset for shadows, in pixels. (defaults to -15)
+# shadow-offset-y = -15
+shadow-offset-y = -5;
+
+# Avoid drawing shadows on dock/panel windows. This option is deprecated,
+# you should use the *wintypes* option in your config file instead.
+#
+# no-dock-shadow = false
+
+# Don't draw shadows on drag-and-drop windows. This option is deprecated,
+# you should use the *wintypes* option in your config file instead.
+#
+# no-dnd-shadow = false
+
+# Red color value of shadow (0.0 - 1.0, defaults to 0).
+# shadow-red = 0
+
+# Green color value of shadow (0.0 - 1.0, defaults to 0).
+# shadow-green = 0
+
+# Blue color value of shadow (0.0 - 1.0, defaults to 0).
+# shadow-blue = 0
+
+# Do not paint shadows on shaped windows. Note shaped windows
+# here means windows setting its shape through X Shape extension.
+# Those using ARGB background is beyond our control.
+# Deprecated, use
+# shadow-exclude = 'bounding_shaped'
+# or
+# shadow-exclude = 'bounding_shaped && !rounded_corners'
+# instead.
+#
+# shadow-ignore-shaped = ''
+
+# Specify a list of conditions of windows that should have no shadow.
+#
+# examples:
+# shadow-exclude = "n:e:Notification";
+#
+# shadow-exclude = []
+shadow-exclude = [
+ "name = 'Notification'",
+ "class_g = 'Conky'",
+ #"class_g ?= 'Notify-osd'",
+ "class_g = 'Cairo-clock'",
+ "class_g = 'Polybar'",
+ "class_g = 'Nwg-menu'",
+ # "class_g = 'Rofi'"
+ "_GTK_FRAME_EXTENTS@:c"
+ ];
+
+# Specify a X geometry that describes the region in which shadow should not
+# be painted in, such as a dock window region. Use
+# shadow-exclude-reg = "x10+0+0"
+# for example, if the 10 pixels on the bottom of the screen should not have shadows painted on.
+#
+# shadow-exclude-reg = ""
+
+# Crop shadow of a window fully on a particular Xinerama screen to the screen.
+# xinerama-shadow-crop = false
+
+
+#################################
+# Fading #
+#################################
+
+
+# Fade windows in/out when opening/closing and when opacity changes,
+# unless no-fading-openclose is used.
+# fading = false
+fading = true
+
+# Opacity change between steps while fading in. (0.01 - 1.0, defaults to 0.028)
+# fade-in-step = 0.028
+fade-in-step = 0.08;
+
+# Opacity change between steps while fading out. (0.01 - 1.0, defaults to 0.03)
+# fade-out-step = 0.03
+fade-out-step = 0.08;
+
+# The time between steps in fade step, in milliseconds. (> 0, defaults to 10)
+# fade-delta = 10
+
+# Specify a list of conditions of windows that should not be faded.
+# fade-exclude = []
+
+# Do not fade on window open/close.
+# no-fading-openclose = false
+
+# Do not fade destroyed ARGB windows with WM frame. Workaround of bugs in Openbox, Fluxbox, etc.
+# no-fading-destroyed-argb = false
+
+
+#################################
+# Transparency / Opacity #
+#################################
+
+# Opacity of inactive windows. (0.1 - 1.0, defaults to 1.0)
+# inactive-opacity = 1
+inactive-opacity = 1;
+
+# Opacity of window titlebars and borders. (0.1 - 1.0, disabled by default)
+# frame-opacity = 1.0
+frame-opacity = 1;
+
+# Default opacity for dropdown menus and popup menus. (0.0 - 1.0, defaults to 1.0)
+# menu-opacity = 1.0
+
+# Let inactive opacity set by -i override the '_NET_WM_OPACITY' values of windows.
+# inactive-opacity-override = true
+inactive-opacity-override = false;
+
+# Default opacity for active windows. (0.0 - 1.0, defaults to 1.0)
+active-opacity = 1.0;
+
+# Dim inactive windows. (0.0 - 1.0, defaults to 0.0)
+inactive-dim = 0.2
+
+# Specify a list of conditions of windows that should always be considered focused.
+# focus-exclude = []
+focus-exclude = ["class_g = 'Plank'", "class_g = 'Nwg-menu'", "class_g = 'st'", "class_g = 'kitty'", "class_g = 'wezterm'", "class_g = 'Alacritty'", "class_g = 'firefox'"];
+
+# Use fixed inactive dim value, instead of adjusting according to window opacity.
+# inactive-dim-fixed = 1.0
+
+# Specify a list of opacity rules, in the format `PERCENT:PATTERN`,
+# like `50:name *= "Firefox"`. picom-trans is recommended over this.
+# Note we don't make any guarantee about possible conflicts with other
+# programs that set '_NET_WM_WINDOW_OPACITY' on frame or client windows.
+# example:
+# opacity-rule = [ "80:class_g = 'URxvt'" ];
+opacity-rule = ["80:class_g = 'betterlockscreen'", "80:class_g = 'URxvt'", "100:class_g = 'firefox'", "100:class_g = 'Zathura'", "80:class_g = 'Spotify'", "80:class_g *?= 'Rofi'", "100:class_g = 'kitty' && focused", "100:class_g = 'kitty' && !focused", "100:class_g = 'Alacritty' && focused", "100:class_g = 'Alacritty' && !focused", "100:class_g = 'wezterm' && focused", "100:class_g = 'wezterm' && !focused"];
+#
+#opacity-rule = ["85:class_g ?= 'Alacritty' && focused"];
+
+#blur-background-exclude = ["class_g = 'scratchpad'"];
+
+#################################
+# Background-Blurring #
+#################################
+
+
+# Parameters for background blurring, see the *BLUR* section for more information.
+blur-method = "dual_kawase";
+#blur-method = "gaussian";
+blur-strength = 6;
+# blur-size = 12
+#
+# blur-deviation = false
+
+# Blur background of semi-transparent / ARGB windows.
+# Bad in performance, with driver-dependent behavior.
+# The name of the switch may change without prior notifications.
+#
+blur-background = false;
+
+# Blur background of windows when the window frame is not opaque.
+# Implies:
+# blur-background
+# Bad in performance, with driver-dependent behavior. The name may change.
+#
+# blur-background-frame = false
+
+
+# Use fixed blur strength rather than adjusting according to window opacity.
+#blur-background-fixed = false
+
+
+# Specify the blur convolution kernel, with the following format:
+# example:
+# blur-kern = "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1";
+#
+# blur-kern = ''
+#blur-kern = "3x3box";
+blur-kern = "7x7box";
+
+# Exclude conditions for background blur.
+# blur-background-exclude = []
+blur-background-exclude = [
+ "window_type = 'dock'",
+ "window_type = 'desktop'",
+ "_GTK_FRAME_EXTENTS@:c",
+ "class_g = 'kitty'",
+ "class_g = 'Alacritty'",
+ "class_g = 'wezterm'",
+# "class_g = 'Polybar'",
+ "class_g = 'URxvt'",
+ "class_g = 'scratchpad'",
+ "class_g = 'heads-up-display'",
+ "class_g = 'Firefox'",
+ "class_g = 'firefox'",
+ "class_g = 'discord'",
+ "class_g = 'Rofi'",
+ "class_g = 'Zathura'",
+ "class_g = 'Notification'",
+];
+
+#################################
+# General Settings #
+#################################
+
+# Daemonize process. Fork to background after initialization. Causes issues with certain (badly-written) drivers.
+# daemon = false
+
+# Specify the backend to use: `xrender`, `glx`, or `xr_glx_hybrid`.
+# `xrender` is the default one.
+#
+#experimental-backends = true;
+#backend = 'glx'
+backend = "glx";
+#backend = "xrender";
+
+# Enable/disable VSync.
+# vsync = false
+vsync = true
+
+# Enable remote control via D-Bus. See the *D-BUS API* section below for more details.
+# dbus = false
+
+# Try to detect WM windows (a non-override-redirect window with no
+# child that has 'WM_STATE') and mark them as active.
+#
+# mark-wmwin-focused = false
+mark-wmwin-focused = true;
+
+# Mark override-redirect windows that doesn't have a child window with 'WM_STATE' focused.
+mark-ovredir-focused = false;
+#mark-ovredir-focused = true;
+
+# Try to detect windows with rounded corners and don't consider them
+# shaped windows. The accuracy is not very high, unfortunately.
+#
+# detect-rounded-corners = false
+detect-rounded-corners = true;
+
+# Detect '_NET_WM_OPACITY' on client windows, useful for window managers
+# not passing '_NET_WM_OPACITY' of client windows to frame windows.
+#
+# detect-client-opacity = false
+detect-client-opacity = true;
+
+# Specify refresh rate of the screen. If not specified or 0, picom will
+# try detecting this with X RandR extension.
+#
+# refresh-rate = 60
+refresh-rate = 0
+
+# Limit picom to repaint at most once every 1 / 'refresh_rate' second to
+# boost performance. This should not be used with
+# vsync drm/opengl/opengl-oml
+# as they essentially does sw-opti's job already,
+# unless you wish to specify a lower refresh rate than the actual value.
+#
+# sw-opti =
+
+# Use EWMH '_NET_ACTIVE_WINDOW' to determine currently focused window,
+# rather than listening to 'FocusIn'/'FocusOut' event. Might have more accuracy,
+# provided that the WM supports it.
+#
+# use-ewmh-active-win = false
+
+# Unredirect all windows if a full-screen opaque window is detected,
+# to maximize performance for full-screen windows. Known to cause flickering
+# when redirecting/unredirecting windows.
+#
+# unredir-if-possible = false
+
+# Delay before unredirecting the window, in milliseconds. Defaults to 0.
+# unredir-if-possible-delay = 0
+
+# Conditions of windows that shouldn't be considered full-screen for unredirecting screen.
+# unredir-if-possible-exclude = []
+
+# Use 'WM_TRANSIENT_FOR' to group windows, and consider windows
+# in the same group focused at the same time.
+#
+# detect-transient = false
+detect-transient = true
+
+# Use 'WM_CLIENT_LEADER' to group windows, and consider windows in the same
+# group focused at the same time. 'WM_TRANSIENT_FOR' has higher priority if
+# detect-transient is enabled, too.
+#
+# detect-client-leader = false
+detect-client-leader = true
+
+# Resize damaged region by a specific number of pixels.
+# A positive value enlarges it while a negative one shrinks it.
+# If the value is positive, those additional pixels will not be actually painted
+# to screen, only used in blur calculation, and such. (Due to technical limitations,
+# with use-damage, those pixels will still be incorrectly painted to screen.)
+# Primarily used to fix the line corruption issues of blur,
+# in which case you should use the blur radius value here
+# (e.g. with a 3x3 kernel, you should use `--resize-damage 1`,
+# with a 5x5 one you use `--resize-damage 2`, and so on).
+# May or may not work with *--glx-no-stencil*. Shrinking doesn't function correctly.
+#
+# resize-damage = 1
+
+# Specify a list of conditions of windows that should be painted with inverted color.
+# Resource-hogging, and is not well tested.
+#
+# invert-color-include = []
+
+# GLX backend: Avoid using stencil buffer, useful if you don't have a stencil buffer.
+# Might cause incorrect opacity when rendering transparent content (but never
+# practically happened) and may not work with blur-background.
+# My tests show a 15% performance boost. Recommended.
+#
+# glx-no-stencil = false
+
+# GLX backend: Avoid rebinding pixmap on window damage.
+# Probably could improve performance on rapid window content changes,
+# but is known to break things on some drivers (LLVMpipe, xf86-video-intel, etc.).
+# Recommended if it works.
+#
+# glx-no-rebind-pixmap = false
+
+# Disable the use of damage information.
+# This cause the whole screen to be redrawn everytime, instead of the part of the screen
+# has actually changed. Potentially degrades the performance, but might fix some artifacts.
+# The opposing option is use-damage
+#
+# no-use-damage = false
+use-damage = true
+
+# Use X Sync fence to sync clients' draw calls, to make sure all draw
+# calls are finished before picom starts drawing. Needed on nvidia-drivers
+# with GLX backend for some users.
+#
+# xrender-sync-fence = false
+
+# GLX backend: Use specified GLSL fragment shader for rendering window contents.
+# See `compton-default-fshader-win.glsl` and `compton-fake-transparency-fshader-win.glsl`
+# in the source tree for examples.
+#
+# glx-fshader-win = ''
+
+# Force all windows to be painted with blending. Useful if you
+# have a glx-fshader-win that could turn opaque pixels transparent.
+#
+# force-win-blend = false
+
+# Do not use EWMH to detect fullscreen windows.
+# Reverts to checking if a window is fullscreen based only on its size and coordinates.
+#
+# no-ewmh-fullscreen = false
+
+# Dimming bright windows so their brightness doesn't exceed this set value.
+# Brightness of a window is estimated by averaging all pixels in the window,
+# so this could comes with a performance hit.
+# Setting this to 1.0 disables this behaviour. Requires --use-damage to be disabled. (default: 1.0)
+#
+# max-brightness = 1.0
+
+# Make transparent windows clip other windows like non-transparent windows do,
+# instead of blending on top of them.
+#
+# transparent-clipping = false
+
+# Set the log level. Possible values are:
+# "trace", "debug", "info", "warn", "error"
+# in increasing level of importance. Case doesn't matter.
+# If using the "TRACE" log level, it's better to log into a file
+# using *--log-file*, since it can generate a huge stream of logs.
+#
+# log-level = "debug"
+log-level = "warn";
+
+# Set the log file.
+# If *--log-file* is never specified, logs will be written to stderr.
+# Otherwise, logs will to written to the given file, though some of the early
+# logs might still be written to the stderr.
+# When setting this option from the config file, it is recommended to use an absolute path.
+#
+# log-file = '/path/to/your/log/file'
+
+# Show all X errors (for debugging)
+# show-all-xerrors = false
+
+# Write process ID to a file.
+# write-pid-path = '/path/to/your/log/file'
+
+# Window type settings
+#
+# 'WINDOW_TYPE' is one of the 15 window types defined in EWMH standard:
+# "unknown", "desktop", "dock", "toolbar", "menu", "utility",
+# "splash", "dialog", "normal", "dropdown_menu", "popup_menu",
+# "tooltip", "notification", "combo", and "dnd".
+#
+# Following per window-type options are available: ::
+#
+# fade, shadow:::
+# Controls window-type-specific shadow and fade settings.
+#
+# opacity:::
+# Controls default opacity of the window type.
+#
+# focus:::
+# Controls whether the window of this type is to be always considered focused.
+# (By default, all window types except "normal" and "dialog" has this on.)
+#
+# full-shadow:::
+# Controls whether shadow is drawn under the parts of the window that you
+# normally won't be able to see. Useful when the window has parts of it
+# transparent, and you want shadows in those areas.
+#
+# redir-ignore:::
+# Controls whether this type of windows should cause screen to become
+# redirected again after been unredirected. If you have unredir-if-possible
+# set, and doesn't want certain window to cause unnecessary screen redirection,
+# you can set this to `true`.
+#
+wintypes:
+{
+ #normal = { full-shadow = true; };
+ #menu = { full-shadow = true; };
+ tooltip = { fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; };
+ dock = { shadow = false; };
+ dnd = { shadow = false; };
+ popup_menu = { full-shadow = false opacity = 0.8; };
+ #utility = { full-shadow = true; };
+ #toolbar = { full-shadow = true; };
+ notification = { opacity = 0.75; }
+};
+
diff --git a/linux/home/.config/plank/dock/launchers/Alacritty.dockitem b/linux/home/.config/plank/dock/launchers/Alacritty.dockitem
new file mode 100644
index 0000000..b3091c5
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/Alacritty.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/Alacritty.desktop
diff --git a/linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem b/linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem
new file mode 100644
index 0000000..7626308
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/com.obsproject.Studio.desktop
diff --git a/linux/home/.config/plank/dock/launchers/discord.dockitem b/linux/home/.config/plank/dock/launchers/discord.dockitem
new file mode 100644
index 0000000..c6736ba
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/discord.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/discord.desktop
diff --git a/linux/home/.config/plank/dock/launchers/firefox.dockitem b/linux/home/.config/plank/dock/launchers/firefox.dockitem
new file mode 100644
index 0000000..0dbfff7
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/firefox.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/firefox.desktop
diff --git a/linux/home/.config/plank/dock/launchers/gimp.dockitem b/linux/home/.config/plank/dock/launchers/gimp.dockitem
new file mode 100644
index 0000000..c9f9438
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/gimp.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/gimp.desktop
diff --git a/linux/home/.config/plank/dock/launchers/google-chrome.dockitem b/linux/home/.config/plank/dock/launchers/google-chrome.dockitem
new file mode 100644
index 0000000..cd04294
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/google-chrome.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/google-chrome.desktop
diff --git a/linux/home/.config/plank/dock/launchers/obsidian.dockitem b/linux/home/.config/plank/dock/launchers/obsidian.dockitem
new file mode 100644
index 0000000..0170dbd
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/obsidian.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/obsidian.desktop
diff --git a/linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem b/linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem
new file mode 100644
index 0000000..ae5f8d9
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/org.gnome.Nautilus.desktop
diff --git a/linux/home/.config/plank/dock/launchers/spotify.dockitem b/linux/home/.config/plank/dock/launchers/spotify.dockitem
new file mode 100644
index 0000000..8ae95b4
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/spotify.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/spotify.desktop
diff --git a/linux/home/.config/plank/dock/launchers/steam.dockitem b/linux/home/.config/plank/dock/launchers/steam.dockitem
new file mode 100644
index 0000000..143d3b4
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/steam.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/steam.desktop
diff --git a/linux/home/.config/plank/dock/launchers/trash.dockitem b/linux/home/.config/plank/dock/launchers/trash.dockitem
new file mode 100644
index 0000000..567a63e
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/trash.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=docklet://trash
diff --git a/linux/home/.config/plank/dock/launchers/virtualbox.dockitem b/linux/home/.config/plank/dock/launchers/virtualbox.dockitem
new file mode 100644
index 0000000..fa95934
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/virtualbox.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/virtualbox.desktop
diff --git a/linux/home/.config/plank/dock/launchers/vlc.dockitem b/linux/home/.config/plank/dock/launchers/vlc.dockitem
new file mode 100644
index 0000000..c20771a
--- /dev/null
+++ b/linux/home/.config/plank/dock/launchers/vlc.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/vlc.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/code-oss.dockitem b/linux/home/.config/plank/dock1/launchers/code-oss.dockitem
new file mode 100644
index 0000000..3d8af2b
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/code-oss.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/code-oss.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem b/linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem
new file mode 100644
index 0000000..39554a1
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///home/srdusr/.local/share/applications/com.obsproject.Studio.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/discord.dockitem b/linux/home/.config/plank/dock1/launchers/discord.dockitem
new file mode 100644
index 0000000..c6736ba
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/discord.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/discord.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/firefox.dockitem b/linux/home/.config/plank/dock1/launchers/firefox.dockitem
new file mode 100644
index 0000000..0dbfff7
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/firefox.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/firefox.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/obsidian.dockitem b/linux/home/.config/plank/dock1/launchers/obsidian.dockitem
new file mode 100644
index 0000000..0170dbd
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/obsidian.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/obsidian.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem b/linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem
new file mode 100644
index 0000000..7475952
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/org.qbittorrent.qBittorrent.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem b/linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem
new file mode 100644
index 0000000..bc3af9d
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/pcmanfm.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/phototonic.dockitem b/linux/home/.config/plank/dock1/launchers/phototonic.dockitem
new file mode 100644
index 0000000..e391893
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/phototonic.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///home/srdusr/.local/share/applications/phototonic.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/steam.dockitem b/linux/home/.config/plank/dock1/launchers/steam.dockitem
new file mode 100644
index 0000000..143d3b4
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/steam.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/steam.desktop
diff --git a/linux/home/.config/plank/dock1/launchers/trash.dockitem b/linux/home/.config/plank/dock1/launchers/trash.dockitem
new file mode 100644
index 0000000..567a63e
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/trash.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=docklet://trash
diff --git a/linux/home/.config/plank/dock1/launchers/vlc.dockitem b/linux/home/.config/plank/dock1/launchers/vlc.dockitem
new file mode 100644
index 0000000..c20771a
--- /dev/null
+++ b/linux/home/.config/plank/dock1/launchers/vlc.dockitem
@@ -0,0 +1,2 @@
+[PlankDockItemPreferences]
+Launcher=file:///usr/share/applications/vlc.desktop
diff --git a/linux/home/.config/polybar/config.ini b/linux/home/.config/polybar/config.ini
new file mode 100644
index 0000000..afb14a8
--- /dev/null
+++ b/linux/home/.config/polybar/config.ini
@@ -0,0 +1,671 @@
+;==========================================================
+;
+;
+; ██████╗ ██████╗ ██╗ ██╗ ██╗██████╗ █████╗ ██████╗
+; ██╔══██╗██╔═══██╗██║ ╚██╗ ██╔╝██╔══██╗██╔══██╗██╔══██╗
+; ██████╔╝██║ ██║██║ ╚████╔╝ ██████╔╝███████║██████╔╝
+; ██╔═══╝ ██║ ██║██║ ╚██╔╝ ██╔══██╗██╔══██║██╔══██╗
+; ██║ ╚██████╔╝███████╗██║ ██████╔╝██║ ██║██║ ██║
+; ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
+;
+;
+; To learn more about how to configure Polybar
+; go to https://github.com/polybar/polybar
+;
+; The README contains a lot of information
+;
+;==========================================================
+
+[settings]
+screenchange-reload = true
+pseudo-transparency = true
+;throttle-output = 5
+;throttle-output-for = 10
+;compositing-background = source
+;compositing-foreground = over
+;compositing-overline = over
+;compositing-underline = over
+;compositing-border = over
+
+[colors]
+foreground = #fafafa
+foreground-alt = #aaCECCC9
+;background = #aa000000
+background = #dd000000
+background-alt = #aaCECCC9
+disabled = #707880
+alert = #ff8989
+blue = #61afef
+dark_blue = #42A5F5
+light_blue = #ADD8E6
+nord = #81a1c1
+purple = #c882e7
+orange = #E57C46
+gray = #676E95
+red = #EC7875
+pink = #EC407A
+yellow = #FDD835
+amber = #FBC02D
+indigo = #6C77BB
+green = #61C766
+lime = #B9C244
+
+[fonts]
+font0 = "SF Pro Mono:style=Display Bold:size=10;2"
+font1 = "Material Design Icons:style=Bold:size=11.5;2"
+font2 = "Material Design Icons:style=Bold:size=13.5;2"
+font3 = "SF Pro:style=Medium:size=10.5;2"
+font4 = "SF Pro:style=Regular:size=13;2"
+font5 = "UbuntuMono Nerd font:size=11;2"
+font6 = "Feather:style=Regular:size=15;4"
+font7 = "Font Awesome 6 Pro Solid:style=Solid:size=14;4"
+font8 = "JetBrainsMono Nerd Font:size=9;2"
+font9 = "Fira Nerd font:size=11;2"
+font10 = "RobotoMono Nerd Font:weight=bold:size=9;2"
+font11 = "RobotoMono Nerd Font:size=10;3"
+font12 = "RobotoMono Nerd Font:size=11;3"
+
+[common]
+line-size = 1pt
+enable-ipc = true
+wm-restack = bspwm
+dpi = 96
+font-0 = ${fonts.font0}
+font-1 = ${fonts.font1}
+font-2 = ${fonts.font2}
+font-3 = ${fonts.font3}
+font-4 = ${fonts.font4}
+font-5 = ${fonts.font5}
+font-6 = ${fonts.font6}
+font-7 = ${fonts.font7}
+font-8 = ${fonts.font8}
+font-9 = ${fonts.font9}
+font-10 = ${fonts.font10}
+font-11 = ${fonts.font11}
+font-12 = ${fonts.font12}
+background = ${colors.background}
+foreground = ${colors.foreground}
+
+[bar/main-0]
+monitor = ${env:MONITOR:}
+width = 99%
+offset-x = 0.5%
+offset-y = 0.5%
+height = 20pt
+radius = 10.0
+fixed-center = true
+inherit = common
+;modules-left = space space menu space space space bspwm space space
+modules-left = space space menu space space space bspwm space space big_space space space cpu space sep space memory space sep space temperature space sep space battery
+modules-center = space space date space space
+;modules-center = space space cpu space sep space memory space sep space temperature space sep space battery big_space date big_space wireless-network space sep space netspeed space sep space vpn space space
+;modules-right = space space mic space sep space volume space sep space backlight space sep space inbox space sep space systray space space sep control space space
+modules-right = space space wireless-network space sep space netspeed space sep space vpn space space big_space space space mic space sep space volume space sep space backlight space sep space inbox space sep space systray space space sep control space space
+
+[bar/main-1]
+monitor = ${env:MONITOR:}
+;width = 260px
+width = 180px
+offset-x = 0%:+10px
+offset-y = 0.5%
+height = 20pt
+radius = 10.0
+fixed-center = true
+inherit = common
+modules-left = space space menu space space space bspwm space space
+
+[bar/main-2]
+monitor = ${env:MONITOR:}
+;width = 230px
+;offset-x = 33.3333%:-130px
+width = 295px
+offset-x = 33.3333%:-195px
+offset-y = 0.5%
+height = 20pt
+radius = 10.0
+fixed-center = true
+inherit = common
+modules-center = space space cpu space sep space memory space sep space temperature space sep space battery space space
+
+[bar/main-3]
+monitor = ${env:MONITOR:}
+;width = 220px
+;width = 150px
+width = 170px
+;offset-x = 50%:-110px
+;offset-x = 50%:-110px
+offset-x = 50%:-85px
+offset-y = 0.5%
+height = 20pt
+radius = 10.0
+fixed-center = true
+inherit = common
+font-0 = "RobotoMono Nerd Font:weight=bold:size=9;2"
+font-1 = "RobotoMono Nerd Font:size=10;3"
+font-2 = "RobotoMono Nerd Font:size=11;3"
+;modules-center = space space day space sep space date space sep space time space space
+modules-center = space space date space space
+
+[bar/main-4]
+monitor = ${env:MONITOR:}
+;width = 230px
+;offset-x = 66.6667%:-100px
+width = 295px
+offset-x = 66.6667%:-100px
+offset-y = 0.5%
+height = 20pt
+radius = 10.0
+fixed-center = true
+;padding-right = 4
+inherit = common
+;modules-center = space space space sep space vpn space space
+modules-center = space space wireless-network space sep space netspeed space sep space vpn space space
+;modules-center = space space wireless-network netspeed space sep space space space
+
+[bar/main-5]
+monitor = ${env:MONITOR:}
+;width = 260px
+width = 180px
+offset-x = 100%:-190px
+offset-y = 0.5%
+height = 20pt
+radius = 10.0
+fixed-center = true
+padding-left = 2
+;padding-right = 2
+inherit = common
+modules-right = space space mic space sep space volume space sep space backlight space sep space inbox space sep space systray space space sep control space space
+
+
+;; Modules
+
+[module/bspwm]
+type = internal/bspwm
+format = <label-state>
+format-padding = 2
+format-foreground = ${colors.foreground}
+index-sort = true
+enable-click = true
+reverse-scroll = false
+label-focused = ●
+label-focused-padding = 1
+label-occupied = "%name%"
+label-occupied-foreground = ${colors.foreground}
+label-occupied-padding = 1
+;label-empty = ○
+label-empty="%name%"
+label-empty-foreground = ${colors.disabled}
+label-empty-padding = 1
+format-font = 5
+
+[module/xwindow]
+type = internal/xwindow
+format = <label>
+format-background = ${colors.background}
+format-foreground = ${colors.foreground}
+format-padding = 2
+label = %title%
+label-maxlen = 40
+label-empty = ~/
+label-empty-foreground = ${colors.disabled}
+
+[module/volume]
+type = internal/pulseaudio
+;format-volume = <label-volume> <bar-volume>
+;label-volume = 
+;label-volume-foreground = ${colors.foreground}
+;label-muted =  muted
+;bar-volume-width = 10
+;bar-volume-foreground-0 = #55aa55
+;bar-volume-foreground-1 = #55aa55
+;bar-volume-foreground-2 = #55aa55
+;bar-volume-foreground-3 = #55aa55
+;bar-volume-foreground-4 = #55aa55
+;bar-volume-foreground-5 = #f5a70a
+;bar-volume-foreground-6 = #ff5555
+;bar-volume-gradient = false
+;bar-volume-indicator = │
+;bar-volume-indicator-font = 2
+;bar-volume-indicator-foreground = #ff
+;bar-volume-fill = ─
+;bar-volume-fill-font = 2
+;bar-volume-empty = ─
+;bar-volume-empty-font = 2
+;bar-volume-empty-foreground =
+
+;format-volume = <ramp-volume> <label-volume
+format-volume = <ramp-volume>
+format-volume-font = 9
+format-volume-padding = 0
+label-volume = %percentage:2%%
+label-volume-padding = 1
+;label-muted-foreground = ${colors.foreground}
+;format-volume-foreground = ${colors.purple}
+format-muted-foreground = ${colors.red}
+format-muted-underline = ${colors.red}
+ramp-volume-foreground = ${colors.foreground}
+;label-muted = "muted"
+label-muted = "  "
+label-muted-foreground = ${colors.disabled}
+ramp-volume-0 = "  "
+ramp-volume-1 = "  "
+ramp-volume-2 = "  "
+ramp-volume-3 = "  "
+ramp-volume-4 = " "
+ramp-volume-5 = " "
+ramp-volume-6 = " "
+click-right = "pavucontrol"
+scroll-interval = 10
+
+[module/inbox]
+type = custom/text
+content-foreground = ${colors.foreground}
+;content-padding = 1
+;content-font = 3
+content = "󰮒"
+;content = " "
+;󰧬󰮒󰻨
+click-left = ~/.config/eww/scripts/openNotificationCenter.sh
+;click-left = notification-center
+
+[module/day]
+type = internal/date
+interval = 1
+date = %a
+label = %date%
+label-foreground = ${colors.foreground}
+
+;[module/day]
+;type = internal/date
+;interval = 1
+;date = %A
+;label = %date:8%
+;label-foreground = ${colors.foreground}
+;
+;[module/date]
+;type = internal/date
+;interval = 1
+;;date = %d-%m-%Y
+;date = %d %b %Y
+;label = %date%
+;label-foreground = ${colors.foreground}
+;format = %{A1:$HOME/.config/eww/scripts/popup calendar &:}<label>%{A}
+
+[module/date]
+type = internal/date
+interval = 1
+label = %date% %time%
+;label-padding = 2.5
+label-background =
+date = %a %d %b %Y
+time = %H:%M:%S
+format-font = 11
+
+
+[module/calendar]
+type = custom/text
+content = 󰸗
+;content-font = 1
+content-padding = 1
+content-foreground = ${colors.primary}
+enable-click = true
+click-left = ~/.config/eww/scripts/popup calendar &
+
+[module/time]
+type = internal/date
+interval = 1
+date = %H:%M:%S
+label = %date%
+label-foreground = ${colors.foreground}
+
+[module/memory]
+type=internal/memory
+interval=5
+format=<label>
+format-font=8
+format-prefix="󰨅"
+;󰘚󰥜󰥠󰨅
+format-foreground=${colors.foreground}
+format-prefix-foreground=${colors.foreground}
+label-font=2
+label-foreground=${colors.foreground}
+label="%{A1:alacritty -e htop &:} %gb_used%%{A}"
+
+[module/cpu]
+type=internal/cpu
+interval=5
+format-prefix-font=4
+format-prefix="󰍛 "
+format-padding=0
+;format-prefix-foreground=${colors.green}
+format-prefix-foreground=${colors.foreground}
+format-foreground=${colors.foreground}
+label="%percentage%%"
+label-foreground=${colors.foreground}
+label-font=2
+
+;[module/temperature]
+;type=internal/temperature
+;; Seconds to sleep between updates
+;; Default: 1
+;interval=10
+;; Thermal zone to use
+;; To list all the zone types, run
+;; $ for i in /sys/class/thermal/thermal_zone*; do echo "$i: $(<$i/type)"; done
+;; Default: 0
+;thermal-zone=0
+;; Full path of temperature sysfs path
+;; Use `sensors` to find preferred temperature source, then run
+;; $ for i in /sys/class/hwmon/hwmon*/temp*_input; do echo "$(<$(dirname $i)/name): $(cat ${i%_*}_label 2>/dev/null || echo $(basename ${i%_*})) $(readlink -f $i)"; done
+;; to find path to desired file
+;; Default reverts to thermal zone setting
+;;hwmon-path=/sys/devices/platform/dell_smm_hwmon/hwmon/hwmon2/temp1_input
+;hwmon-path=/sys/devices/platform/dell_smm_hwmon/hwmon/hwmon1/temp1_input
+;; Base temperature for where to start the ramp (in degrees celsius)
+;; Default: 0
+;base-temperature=20
+;warn-temperature=60
+;; Threshold temperature to display warning label (in degrees celsius)
+;; Default: 80
+;format-prefix="  "
+;format-warn-prefix="  "
+;format-warn-foreground=${colors.red}
+;format-foreground=${colors.foreground}
+;format-font=4
+;format-warn-font=4
+;label-warn-font=2
+;label-foreground=${colors.foreground}
+;format = "<label>"
+;label-font=2
+
+[module/temperature]
+type = custom/script
+interval = 5
+format = <label>
+format-prefix = "  "
+format-prefix-foreground = ${colors.foreground}
+exec = ~/.config/polybar/scripts/temperature.sh
+
+
+[module/battery]
+type = custom/script
+exec = $HOME/.scripts/battery.sh
+format-font = 1
+format-prefix = ""
+interval = 10
+;click-right = xfce4-power-manager-settings
+
+[module/backlight]
+type = internal/backlight
+; Use the following command to list available cards:
+; $ ls -1 /sys/class/backlight/
+; Default: first usable card in /sys/class/backlight (new in version 3.7.0)
+card = intel_backlight
+; Use the `/sys/class/backlight/.../actual-brightness` file
+; rather than the regular `brightness` file.
+; New in version 3.6.0
+; Changed in version: 3.7.0: Defaults to true also on amdgpu backlights
+; Default: true
+;use-actual-brightness = true
+; Interval in seconds after which after which the current brightness is read
+; (even if no update is detected).
+; Use this as a fallback if brightness updates are not registering in polybar
+; (which happens if the use-actual-brightness is false).
+; There is no guarantee on the precisio of this timing.
+; Set to 0 to turn off
+; New in version 3.7.0
+; Default: 0 (5 if use-actual-brightness is false)
+;poll-interval = 0
+; Enable changing the backlight with the scroll wheel
+; NOTE: This may require additional configuration on some systems. Polybar will
+; write to `/sys/class/backlight/${self.card}/brightness` which requires polybar
+; to have write access to that file.
+; DO NOT RUN POLYBAR AS ROOT.
+; The recommended way is to add the user to the
+; `video` group and give that group write-privileges for the `brightness` file.
+; See the ArchWiki for more information:
+; https://wiki.archlinux.org/index.php/Backlight#ACPI
+; Default: false
+enable-scroll = true
+; Interval for changing the brightness (in percentage points).
+; New in version 3.7.0
+; Default: 5
+scroll-interval = 10
+; Available tags:
+; <label> (default)
+; <ramp>
+; <bar>
+format = <ramp>
+format-foreground = {colors.foreground}
+; Available tokens:
+; %percentage% (default)
+label = %percentage:2%%
+label-font=7
+;; Only applies if <ramp> is used
+ramp-0 = 󰃞
+ramp-1 = 󰃝
+ramp-2 = 󰃟
+ramp-3 = 󰃠
+;; Only applies if <bar> is used
+;bar-width = 10
+;bar-indicator = |
+;bar-fill = ─
+;bar-empty = ─
+
+[module/bluetooth]
+type = custom/text
+content = ""
+format = <label>
+content-foreground = ${colors.foreground}
+; click-middle = bspc rule -a '*' -o state=floating rectangle=400x120+775+48 && kitty -e sudo polybarblue.sh
+ click-left = blueman-manager
+
+[module/control]
+type = custom/script
+exec = echo 􀜊
+format = <label>
+format-padding = 1
+label-padding =
+content-background =
+format-foreground = ${colors.foreground}
+click-left = ~/.config/eww/scripts/openControlCenter.sh
+;click-left = control-center
+;click-left = $HOME/.scripts/toggle-control &
+
+[module/wireless-network]
+type = internal/network
+interface = wlan0
+interval = 3.0
+unknown-as-up = true
+format-connected-background = ${colors.background}
+format-connected-foreground = ${colors.foreground}
+format-connected-padding = 1
+format-connected = %{A1:$HOME/.scripts/rofi-network-manager.sh:}<ramp-signal> <label-connected>%{A}
+label-connected = "%essid:03:5%/%local_ip%"
+#label-connected = "ESSID/127.0.0.1"
+format-disconnected-background = ${colors.background}
+format-disconnected-foreground = ${colors.foreground}
+format-disconnected-padding = 1
+format-disconnected = %{A1:$HOME/.scripts//rofi-network-manager.sh:}<label-disconnected>%{A}
+;label-disconnected ="Network Disconnected 󱍢 ......"
+;label-disconnected =" 󰤮 Network Disconnected ......... 󱍢 .......... "
+label-disconnected ="󰤮 Net Disconnected"
+ramp-signal-0 = "󰤯"
+ramp-signal-1 = "󰤟"
+ramp-signal-2 = "󰤢"
+ramp-signal-3 = "󰤥"
+ramp-signal-4 = "󰤨"
+ramp-signal-foreground = ${colors.white}
+enable-click = true
+click-left = $HOME/.scripts/rofi-network-manager.sh &
+
+[module/wifi]
+type = custom/script
+tail = true
+interval = 1
+format = <label>
+format-prefix = " "
+wifi = wifi
+wifi-alt = iwgetid -r
+exec = iwgetid -r
+click-left = kitty nmtui
+click-right = nm-connection-editor
+label-disconnected = %{A1:nm-connection-editor:}%essid%%{A}
+
+[module/wlan-signal]
+type = custom/script
+label = %output%
+exec = awk 'NR==3 {print $4 "00 dBm"}' /proc/net/wireless
+format-prefix = "ﴽ "
+format-prefix-foreground = ${colors.yellow}
+format-background = ${colors.background}
+format-foreground = ${colors.foreground}
+interval = 1
+
+[module/netspeed]
+type = internal/network
+;interface = ${system.sys_network_interface}
+interface-type = wireless
+interval = 3.0
+accumulate-stats = true
+;unknown-as-up = true
+format-connected = <label-connected>
+format-disconnected = <label-disconnected>
+;label-disconnected = ""
+label-disconnected = " 0 KB/s "
+format-disconnected-prefix = "󰯎"
+format-connected-prefix = "󰯎"
+speed-unit = ""
+label-connected = "%netspeed:5%B/s "
+
+[module/upspeed]
+type = internal/network
+interface-type = wireless
+interval = 1
+format-connected = <label-connected>
+format-disconnected = <label-disconnected>
+label-disconnected = ""
+format-disconnected-prefix = ""
+format-connected-prefix = " "
+label-connected = " %upspeed:8%"
+
+[module/downspeed]
+type = internal/network
+interface-type = wireless
+interval = 1
+format-connected = <label-connected>
+format-disconnected = <label-disconnected>
+label-disconnected = ""
+format-disconnected-prefix = ""
+format-connected-prefix = ""
+label-connected = " %downspeed:8%"
+
+[module/vpn]
+type = custom/script
+#exec = protonvpn status
+exec = ~/.config/polybar/scripts/vpn.sh
+;tail = true
+interval = 1
+label-font = 6
+format-prefix = " "
+format = <label>
+click-left = sudo protonvpn c -f
+click-right = sudo protonvpn disconnect
+;
+
+[module/gpu-nvidia]
+type = custom/script
+exec = $HOME/.config/polybar/scripts/gpu-nvidia.sh
+interval = 2
+format-font = 2
+format-foreground = #69F0AE
+
+[module/gpu-intel]
+type = custom/script
+#exec = $HOME/.config/polybar/scripts/gpu-intel.sh
+interval = 2
+
+[module/spotify]
+type = custom/script
+tail = true
+interval = 1
+format-prefix = " "
+format = <label>
+exec = ~/.config/polybar/scripts/get_spotify_status.sh
+
+[module/menu]
+type = custom/text
+content = 󱎂
+;󰣇󰈷󰨝󰵆􀇸􀘸􀟒􀣺􀦲
+content-font = 3
+content-padding = 1
+content-foreground = ${colors.foreground}
+enable-click = true
+click-left = ~/.config/jgmenu/scripts/startmenu.sh
+click-right = $HOME/.scripts/menu_full.sh
+
+[module/power]
+type = custom/text
+content = 󰐥
+;content = 襤
+content-foreground = ${colors.red}
+content-padding = 1
+label-margin = 3
+click-left = ~/.scripts/sysmenu.sh
+
+[module/systray]
+type=custom/ipc
+hook-0=echo " "
+hook-1=echo " "
+click-left=systray
+initial=2
+format-font=2
+format-foreground=${colors.blue}
+;format-foreground=${colors.foreground}
+
+[module/weather]
+type = custom/script
+exec = "sh ~/.config/polybar/weather.sh"
+interval = 700
+
+[module/tray]
+type = internal/tray
+format-margin = 8px
+tray-spacing = 8px
+
+[module/updates]
+type = custom/script
+tail = true
+interval = 1
+format-prefix = " "
+format = <label>
+exec = checkupdates | wc -l
+click-left = kitty yay -Syu --noconfirm
+
+[module/mic]
+type = custom/script
+interval = 0.5
+exec = $HOME/.config/polybar/scripts/microphone.sh
+format = <label>
+format-font = 9
+click-left = pamixer --source 1 -t
+scroll-up = pamixer --source 1 -i 5
+scroll-down = pamixer --source 1 -d 5
+
+
+;; decor
+
+[module/sep]
+type = custom/text
+content = "|"
+content-foreground = ${colors.disabled}
+
+[module/space]
+type = custom/text
+content = " "
+
+[module/big_space]
+type = custom/text
+content = " "
+
+; vim:ft=dosini
diff --git a/linux/home/.config/polybar/launch.sh b/linux/home/.config/polybar/launch.sh
new file mode 100755
index 0000000..5468c8e
--- /dev/null
+++ b/linux/home/.config/polybar/launch.sh
@@ -0,0 +1,31 @@
+#!/usr/bin/env sh
+
+# Terminate already running bar instances
+killall -q polybar
+
+# Wait until the processes have been shut down
+while pgrep -u "$UID" -x polybar >/dev/null; do sleep 1; done
+
+
+# Launch bar
+#polybar main-0 &
+polybar main-1 &
+polybar main-2 &
+polybar main-3 &
+polybar main-4 &
+polybar main-5 &
+
+# Define bars per monitors
+#declare -A ARRANGEMENTS=(["$mainmonitor"]="main-0" ["$secondmonitor"]="main-0")
+declare -A ARRANGEMENTS=(["$mainmonitor"]="main-1,main-2,main-3,main-4,main-5" ["$secondmonitor"]="main-1,main-2,main-3,main-4,main-5")
+
+# Each key
+for MONITOR in "${!ARRANGEMENTS[@]}"; do
+ # split at `,` into array
+ while IFS=',' read -ra BARLIST; do
+ # for each bar (seperated by `,`) at current key
+ for BAR in "${BARLIST[@]}"; do
+ MONITOR="$MONITOR" polybar --reload "$BAR" &
+ done
+ done <<< "${ARRANGEMENTS[$MONITOR]}"
+done
diff --git a/linux/home/.config/polybar/scripts/bluetooth.sh b/linux/home/.config/polybar/scripts/bluetooth.sh
new file mode 100755
index 0000000..061604b
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/bluetooth.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+if [ $(bluetoothctl show | grep "Powered: yes" | wc -c) -eq 0 ]
+then
+ echo ""
+else
+ if [ $(echo info | bluetoothctl | grep 'Device' | wc -c) -eq 0 ]
+ then
+ echo ""
+ fi
+ echo ""
+fi
+
diff --git a/linux/home/.config/polybar/scripts/check-network.sh b/linux/home/.config/polybar/scripts/check-network.sh
new file mode 100755
index 0000000..dabe74c
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/check-network.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+count=0
+disconnected="睊"
+wireless_connected="直"
+ethernet_connected="泌"
+
+ID="$(ip link | awk '/state UP/ {print $2}')"
+
+while true; do
+ if (ping -c 1 archlinux.org || ping -c 1 google.com || ping -c 1 bitbucket.org || ping -c 1 github.com || ping -c 1 sourceforge.net) &>/dev/null; then
+ if [[ $ID == e* ]]; then
+ echo "$ethernet_connected" ; sleep 25
+ else
+ echo "$wireless_connected" ; sleep 25
+ fi
+ else
+ echo "$disconnected" ; sleep 0.5
+ fi
+done
+
diff --git a/linux/home/.config/polybar/scripts/check_updates.sh b/linux/home/.config/polybar/scripts/check_updates.sh
new file mode 100755
index 0000000..52e51a9
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/check_updates.sh
@@ -0,0 +1,118 @@
+
+#!/usr/bin/bash
+#
+# checkupdates: Safely print a list of pending updates.
+#
+# Copyright (c) 2013 Kyle Keen <keenerd@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+declare -r myname='checkupdates'
+declare -r myver='1.0.0'
+
+plain() {
+ (( QUIET )) && return
+ local mesg=$1; shift
+ printf "${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&1
+}
+
+msg() {
+ (( QUIET )) && return
+ local mesg=$1; shift
+ printf "${GREEN}==>${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&1
+}
+
+msg2() {
+ (( QUIET )) && return
+ local mesg=$1; shift
+ printf "${BLUE} ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&1
+}
+
+ask() {
+ local mesg=$1; shift
+ printf "${BLUE}::${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}" "$@" >&1
+}
+
+warning() {
+ local mesg=$1; shift
+ printf "${YELLOW}==> $(gettext "WARNING:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+}
+
+error() {
+ local mesg=$1; shift
+ printf "${RED}==> $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2
+}
+
+# check if messages are to be printed using color
+unset ALL_OFF BOLD BLUE GREEN RED YELLOW
+if [[ -t 2 && ! $USE_COLOR = "n" ]]; then
+ # prefer terminal safe colored and bold text when tput is supported
+ if tput setaf 0 &>/dev/null; then
+ ALL_OFF="$(tput sgr0)"
+ BOLD="$(tput bold)"
+ BLUE="${BOLD}$(tput setaf 4)"
+ GREEN="${BOLD}$(tput setaf 2)"
+ RED="${BOLD}$(tput setaf 1)"
+ YELLOW="${BOLD}$(tput setaf 3)"
+ else
+ ALL_OFF="\e[1;0m"
+ BOLD="\e[1;1m"
+ BLUE="${BOLD}\e[1;34m"
+ GREEN="${BOLD}\e[1;32m"
+ RED="${BOLD}\e[1;31m"
+ YELLOW="${BOLD}\e[1;33m"
+ fi
+fi
+readonly ALL_OFF BOLD BLUE GREEN RED YELLOW
+
+
+if (( $# > 0 )); then
+ echo "${myname} v${myver}"
+ echo
+ echo "Safely print a list of pending updates"
+ echo
+ echo "Usage: ${myname}"
+ echo
+ echo 'Note: Export the "CHECKUPDATES_DB" variable to change the path of the temporary database.'
+ exit 0
+fi
+
+if ! type -P fakeroot >/dev/null; then
+ error 'Cannot find the fakeroot binary.'
+ exit 1
+fi
+
+if [[ -z $CHECKUPDATES_DB ]]; then
+ CHECKUPDATES_DB="${TMPDIR:-/tmp}/checkup-db-${USER}/"
+fi
+
+trap 'rm -f $CHECKUPDATES_DB/db.lck' INT TERM EXIT
+
+DBPath="$(pacman-conf DBPath)"
+if [[ -z "$DBPath" ]] || [[ ! -d "$DBPath" ]]; then
+ DBPath="/var/lib/pacman/"
+fi
+
+mkdir -p "$CHECKUPDATES_DB"
+ln -s "${DBPath}/local" "$CHECKUPDATES_DB" &> /dev/null
+if ! fakeroot -- pacman -Sy --dbpath "$CHECKUPDATES_DB" --logfile /dev/null &> /dev/null; then
+ error 'Cannot fetch updates'
+ exit 1
+fi
+pacman -Qu --dbpath "$CHECKUPDATES_DB" 2> /dev/null | grep -v '\[.*\]'
+
+exit 0
+
+# vim: set noet:
diff --git a/linux/home/.config/polybar/scripts/cmus.sh b/linux/home/.config/polybar/scripts/cmus.sh
new file mode 100755
index 0000000..2f42c63
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/cmus.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+prepend_zero () {
+ seq -f "%02g" $1 $1
+}
+
+artist=$(echo -n $(cmus-remote -C status | grep "tag artist" | cut -c 12-))
+
+if [[ $artist = *[!\ ]* ]]; then
+ song=$(echo -n $(cmus-remote -C status | grep title | cut -c 11-))
+ position=$(cmus-remote -C status | grep position | cut -c 10-)
+ minutes1=$(prepend_zero $(($position / 60)))
+ seconds1=$(prepend_zero $(($position % 60)))
+ duration=$(cmus-remote -C status | grep duration | cut -c 10-)
+ minutes2=$(prepend_zero $(($duration / 60)))
+ seconds2=$(prepend_zero $(($duration % 60)))
+ echo -n "$artist - $song "
+else
+ echo
+fi
+
+#prepend_zero () {
+# seq -f "%02g" $1 $1
+#}
+#
+#artist=$(echo -n $(cmus-remote -C status | grep "tag artist" | cut -c 12-))
+#
+#if [[ $artist = *[!\ ]* ]]; then
+# song=$(echo -n $(cmus-remote -C status | grep title | cut -c 11-))
+# position=$(cmus-remote -C status | grep position | cut -c 10-)
+# minutes1=$(prepend_zero $(($position / 60)))
+# seconds1=$(prepend_zero $(($position % 60)))
+# duration=$(cmus-remote -C status | grep duration | cut -c 10-)
+# minutes2=$(prepend_zero $(($duration / 60)))
+# seconds2=$(prepend_zero $(($duration % 60)))
+# echo -n "$artist - $song [$minutes1:$seconds1/$minutes2:$seconds2]"
+#else
+# echo
+#fi
diff --git a/linux/home/.config/polybar/scripts/get_spotify_status.sh b/linux/home/.config/polybar/scripts/get_spotify_status.sh
new file mode 100755
index 0000000..f04400d
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/get_spotify_status.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# The name of polybar bar which houses the main spotify module and the control modules.
+PARENT_BAR="now-playing"
+PARENT_BAR_PID=$(pgrep -a "polybar" | grep "$PARENT_BAR" | cut -d" " -f1)
+
+# Set the source audio player here.
+# Players supporting the MPRIS spec are supported.
+# Examples: spotify, vlc, chrome, mpv and others.
+# Use `playerctld` to always detect the latest player.
+# See more here: https://github.com/altdesktop/playerctl/#selecting-players-to-control
+#PLAYER="spotify"
+PLAYER="playerctld"
+
+# Format of the information displayed
+# Eg. {{ artist }} - {{ album }} - {{ title }}
+# See more attributes here: https://github.com/altdesktop/playerctl/#printing-properties-and-metadata
+FORMAT="{{ title }} - {{ artist }}"
+
+# Sends $2 as message to all polybar PIDs that are part of $1
+update_hooks() {
+ while IFS= read -r id
+ do
+ polybar-msg -p "$id" hook spotify-play-pause $2 1>/dev/null 2>&1
+ done < <(echo "$1")
+}
+
+PLAYERCTL_STATUS=$(playerctl --player=$PLAYER status 2>/dev/null)
+EXIT_CODE=$?
+
+if [ $EXIT_CODE -eq 0 ]; then
+ STATUS=$PLAYERCTL_STATUS
+else
+ STATUS="No player is running"
+fi
+
+if [ "$1" == "--status" ]; then
+ echo "$STATUS"
+else
+ if [ "$STATUS" = "Stopped" ]; then
+ echo "No music is playing"
+ elif [ "$STATUS" = "Paused" ]; then
+ update_hooks "$PARENT_BAR_PID" 2
+ playerctl --player=$PLAYER metadata --format "$FORMAT"
+ elif [ "$STATUS" = "No player is running" ]; then
+ echo ""
+ else
+ update_hooks "$PARENT_BAR_PID" 1
+ playerctl --player=$PLAYER metadata --format "$FORMAT"
+ fi
+fi
+
diff --git a/linux/home/.config/polybar/scripts/menu.sh b/linux/home/.config/polybar/scripts/menu.sh
new file mode 100755
index 0000000..cd95ee0
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/menu.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# Specify the path to the Rofi configuration file
+config_file="$HOME/.config/rofi/styles/appmenu.rasi"
+
+rofi -no-lazy-grab -show drun -display-drun "Applications " -drun-display-format "{name}" -sep -config "$config_file"
diff --git a/linux/home/.config/polybar/scripts/menu.shsave b/linux/home/.config/polybar/scripts/menu.shsave
new file mode 100755
index 0000000..ea5bf8e
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/menu.shsave
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+# Custom Rofi Script
+
+BORDER="#1F1F1F"
+SEPARATOR="#1F1F1F"
+FOREGROUND="#A9ABB0"
+BACKGROUND="#1F1F1F"
+BACKGROUND_ALT="#252525"
+HIGHLIGHT_BACKGROUND="#FF6F00"
+HIGHLIGHT_FOREGROUND="#FFFFFF"
+
+BLACK="#000000"
+WHITE="#ffffff"
+RED="#e53935"
+GREEN="#43a047"
+YELLOW="#fdd835"
+BLUE="#1e88e5"
+MAGENTA="#00897b"
+CYAN="#00acc1"
+PINK="#d81b60"
+PURPLE="#8e24aa"
+INDIGO="#3949ab"
+TEAL="#00897b"
+LIME="#c0ca33"
+AMBER="#ffb300"
+ORANGE="#fb8c00"
+BROWN="#6d4c41"
+GREY="#757575"
+BLUE_GREY="#546e7a"
+DEEP_PURPLE="#5e35b1"
+DEEP_ORANGE="#f4511e"
+LIGHT_BLUE="#039be5"
+LIGHT_GREEN="#7cb342"
+
+# Launch Rofi
+rofi -no-lazy-grab -show drun -display-drun "Applications " -drun-display-format "{name}" -hide-scrollbar false \
+-hide-sidebar-mode true \
+-bw 0 \
+-lines 15 \
+-line-padding 10 \
+-padding 0 \
+-width 20 \
+-xoffset 7 -yoffset 28 \
+-location 1 \
+-columns 1 \
+-show-icons -icon-theme "Papirus" \
+-color-enabled true \
+-color-window "$BACKGROUND,$BORDER,$SEPARATOR" \
+-color-normal "$BACKGROUND_ALT,$FOREGROUND,$BACKGROUND_ALT,$HIGHLIGHT_BACKGROUND,$HIGHLIGHT_FOREGROUND" \
+-color-active "$BACKGROUND,$MAGENTA,$BACKGROUND_ALT,$HIGHLIGHT_BACKGROUND,$HIGHLIGHT_FOREGROUND" \
+-color-urgent "$BACKGROUND,$YELLOW,$BACKGROUND_ALT,$HIGHLIGHT_BACKGROUND,$HIGHLIGHT_FOREGROUND"
+#rofi -no-lazy-grab -show drun -display-drun "Applications " -drun-display-format "{name}" -hide-scrollbar true -sidebar-mode false -bw 0 -lines 6 -line-padding 10 -padding 20 -width 30 -xoffset 7 -yoffset 25 -location 1 -columns 2 -show-icons -icon-theme "Papirus"
+
+# More Options
+# -fullscreen \
+
+# Theming help
+# color window = background, border, separator
+# color normal = background, foreground, background-alt, highlight-background, highlight-foreground
+# color active = background, foreground, background-alt, highlight-background, highlight-foreground
+# color urgent = background, foreground, background-alt, highlight-background, highlight-foreground
+
diff --git a/linux/home/.config/polybar/scripts/menu_full.sh b/linux/home/.config/polybar/scripts/menu_full.sh
new file mode 100755
index 0000000..9f898a4
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/menu_full.sh
@@ -0,0 +1,65 @@
+
+#!/bin/bash
+
+# Custom Rofi Script
+
+BORDER="#1F1F1F"
+SEPARATOR="#1F1F1F"
+FOREGROUND="#A9ABB0"
+BACKGROUND="#1F1F1F"
+BACKGROUND_ALT="#252525"
+HIGHLIGHT_BACKGROUND="#FF6F00"
+HIGHLIGHT_FOREGROUND="#FFFFFF"
+
+BLACK="#000000"
+WHITE="#ffffff"
+RED="#e53935"
+GREEN="#43a047"
+YELLOW="#fdd835"
+BLUE="#1e88e5"
+MAGENTA="#00897b"
+CYAN="#00acc1"
+PINK="#d81b60"
+PURPLE="#8e24aa"
+INDIGO="#3949ab"
+TEAL="#00897b"
+LIME="#c0ca33"
+AMBER="#ffb300"
+ORANGE="#fb8c00"
+BROWN="#6d4c41"
+GREY="#757575"
+BLUE_GREY="#546e7a"
+DEEP_PURPLE="#5e35b1"
+DEEP_ORANGE="#f4511e"
+LIGHT_BLUE="#039be5"
+LIGHT_GREEN="#7cb342"
+
+# Launch Rofi
+rofi -no-lazy-grab -show drun \
+-display-drun "Applications " -drun-display-format "{name}" \
+-hide-scrollbar true \
+-bw 0 \
+-lines 10 \
+-line-padding 15 \
+-padding 60 \
+-width 30 \
+-xoffset 10 -yoffset 40 \
+-location 1 \
+-fullscreen \
+-columns 4 \
+-show-icons -icon-theme "Papirus" \
+-font "Fantasque Sans Mono 10" \
+-color-enabled true \
+-color-window "$BACKGROUND,$BORDER,$SEPARATOR" \
+-color-normal "$BACKGROUND_ALT,$FOREGROUND,$BACKGROUND_ALT,$HIGHLIGHT_BACKGROUND,$HIGHLIGHT_FOREGROUND" \
+-color-active "$BACKGROUND,$MAGENTA,$BACKGROUND_ALT,$HIGHLIGHT_BACKGROUND,$HIGHLIGHT_FOREGROUND" \
+-color-urgent "$BACKGROUND,$YELLOW,$BACKGROUND_ALT,$HIGHLIGHT_BACKGROUND,$HIGHLIGHT_FOREGROUND"
+
+# More Options
+# -fullscreen \
+
+# Theming help
+# color window = background, border, separator
+# color normal = background, foreground, background-alt, highlight-background, highlight-foreground
+# color active = background, foreground, background-alt, highlight-background, highlight-foreground
+# color urgent = background, foreground, background-alt, highlight-background, highlight-foreground
diff --git a/linux/home/.config/polybar/scripts/now-playing.sh b/linux/home/.config/polybar/scripts/now-playing.sh
new file mode 100755
index 0000000..8fa6000
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/now-playing.sh
@@ -0,0 +1,217 @@
+#!/usr/bin/env python3
+import dbus
+import signal
+import time
+from unicodedata import east_asian_width
+
+# Config options
+
+# (int) : Length of media info string. If length of string exceedes this value, the text will scroll. Default value is 20
+message_display_len = 20
+
+# (int) : Font index of polybar. this value should be 1 more than the font value specified in polybar config.
+font_index = 1
+
+# (float) : Update speed of the text in seconds.
+update_delay = 0.3
+
+# (list) : list of chars containing previous, play, pause, next glyphs for media controls in respective order
+control_chars = ['','','','']
+
+# (dict) : dict of char icons to display as prefix.
+# If player name is available as key, then use the corressponding icon,
+# else default key value.
+# example:
+display_player_prefix = {
+ "spotify": ' ',
+ "firefox": ' ',
+ "default": ' '
+}
+
+# (list) : list of metadata fields based on mpris sepecification.
+# For more details/ field names, refer [mpris sepecification](https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/)
+metadata_fields = ["xesam:title", "xesam:artist"]
+
+# (char) : separator for metadata fields
+metadata_separator = "-"
+
+# (bool) : Hide text when no player is available? True disables the output for no players.
+hide_output = False
+
+# Defult initialization
+current_player = None
+player_names = None
+players = None
+message = None
+display_text = ""
+display_prefix = " "
+display_suffix = ""
+last_player_name = None
+
+session_bus = dbus.SessionBus()
+
+def get_name(player_name ):
+ if player_name not in player_names:
+ return
+ name = ".".join(player_name.split(".")[3:])
+ return name
+
+def get_name_by_index(index):
+ if index >= len(player_names):
+ return
+ return get_name(player_names[index])
+
+def get_status(player):
+ status = ""
+ try:
+ status = player.Get('org.mpris.MediaPlayer2.Player', 'PlaybackStatus', dbus_interface='org.freedesktop.DBus.Properties')
+ except Exception as e:
+ pass
+ return status
+
+def get_metadata(player):
+ metadata = {}
+ try:
+ metadata = player.Get('org.mpris.MediaPlayer2.Player', 'Metadata', dbus_interface='org.freedesktop.DBus.Properties')
+ except Exception as e:
+ pass
+ return metadata
+
+def update_prefix_suffix(player_name="", status=""):
+ global display_prefix, display_suffix, status_paused
+
+ player_option = ""
+ if player_name != "":
+ player_option = "-p " + player_name
+
+ prev_button = "%%{A:playerctl %s previous :}%c%%{A}" %(player_option,control_chars[0])
+ play_button = "%%{A:playerctl %s play :}%c%%{A}" %(player_option,control_chars[1])
+ pause_button = "%%{A:playerctl %s pause :}%c%%{A}" %(player_option,control_chars[2])
+ next_button = "%%{A:playerctl %s next :}%c%%{A}" %(player_option,control_chars[3])
+
+ suffix = "| " + prev_button
+ if status == "Playing":
+ suffix += " "+pause_button
+ status_paused = False
+ else:
+ suffix += " "+play_button
+ status_paused = True
+ suffix += " "+next_button
+ # print(suffix)
+ display_suffix = suffix
+
+ for key in display_player_prefix.keys():
+ if key in player_name:
+ display_prefix = display_player_prefix[key]
+ break
+ else:
+ display_prefix = display_player_prefix["default"]
+
+def update_players():
+ global player_names, players, session_bus, current_player, last_player_name
+ player_names = [service for service in session_bus.list_names() if service.startswith('org.mpris.MediaPlayer2.')]
+ players = [session_bus.get_object(service, '/org/mpris/MediaPlayer2') for service in player_names]
+ if last_player_name != get_name(current_player):
+ for index, player in enumerate(player_names):
+ if get_name(player) == last_player_name:
+ current_player = index
+
+def handle_event(*args):
+ global current_player, players, last_player_name
+ update_players()
+ if len(players) == 0:
+ return
+ current_player += 1
+ current_player %= len(players)
+ last_player_name = getname_by_index(current_player)
+# print("SIGUSR1: updated values - current_player = %d players len = %d"%(current_player,len(players)))
+
+def update_message():
+ global players, current_player,player_names, message, display_text, message_display_len, display_suffix, last_player_name
+ if len(players) == 0:
+ tmp_message = "No player available"
+ update_prefix_suffix()
+ else:
+ name = get_name_by_index(current_player)
+ status = get_status(players[current_player])
+ metadata_obj = get_metadata(players[current_player])
+ metadata_string_list = []
+ for field in metadata_fields:
+ result = metadata_obj.get(field)
+ if type(result) == dbus.Array:
+ result = result[0]
+ if not result:
+ result = "No "+field.split(":")[1]
+ metadata_string_list.append(str(result))
+ metadata_string = (" "+metadata_separator+" ").join(metadata_string_list)
+ if visual_len(metadata_string) > message_display_len:
+ metadata_string = " " + metadata_string + " |"
+ update_prefix_suffix(name,status)
+ tmp_message = ""
+ if metadata_string:
+ tmp_message += str(metadata_string)
+ last_player_name = name
+ if message != tmp_message:
+ message = tmp_message
+ display_text = message
+
+def scroll():
+ global display_text, message_display_len, status_paused
+ if not status_paused:
+ if len(display_text) > message_display_len:
+ display_text = display_text[1:] + display_text[0]
+ elif len(display_text) < message_display_len:
+ display_text += " "*(message_display_len - len(display_text))
+
+def visual_len(text):
+ visual_length = 0
+ for ch in text:
+ width = east_asian_width(ch)
+ if width == 'W' or width == 'F':
+ visual_length += 1
+ visual_length += 1
+ return visual_length
+
+def make_visual_len(text, visual_desired_length):
+ visual_length = 0
+ altered_text = ''
+ for char in text:
+ if visual_length < visual_desired_length:
+ width = east_asian_width(char)
+ if width == 'W' or width == 'F':
+ visual_length += 2
+ else:
+ visual_length += 1
+ altered_text += char
+ else:
+ break
+ if visual_length == visual_desired_length + 1:
+ altered_text = altered_text[:-1] + ' '
+ elif visual_length < visual_desired_length:
+ altered_text += ' ' * (visual_desired_length - visual_length)
+ return altered_text
+
+def print_text():
+ global display_text, message_display_len, players, player_names, display_prefix, display_suffix
+ if hide_output and len(players)==0:
+ print("", flush = True)
+ return
+ scroll()
+ print(display_prefix + " " +
+ "%%{T%d}" % (font_index) +
+ make_visual_len(display_text, message_display_len) +
+ "%{T-}" + display_suffix, flush=True)
+
+def main():
+ global current_player, players
+ update_players()
+ current_player = 0
+ while True:
+ time.sleep(update_delay)
+ update_players()
+ update_message()
+ print_text()
+
+if __name__ == '__main__':
+ signal.signal(signal.SIGUSR1, handle_event)
+ main()
diff --git a/linux/home/.config/polybar/scripts/polybar_wrapper b/linux/home/.config/polybar/scripts/polybar_wrapper
new file mode 100755
index 0000000..901bb28
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/polybar_wrapper
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+DIR=$(dirname $(realpath $0))
+
+WINDOW_ID_CONKY=/tmp/conky_window_id
+WINDOW_ID_TOP=/tmp/polybar_top_window_id
+WINDOW_ID_EXPANDED=/tmp/polybar_expanded_window_id
+
+conky_launch() {
+ # Hacky X11 magic to make Conky appear above polybar
+ killall conky
+ # xdotool search can't find Conky's window but fortunately Conky outputs it
+ conky -c ~/.config/conky/config 2> /tmp/conky_out
+ # Extract the hex window id from Conky's output
+ HEX=$(awk '/drawing to created window/ {print $NF}' /tmp/conky_out | tr -d '()' | awk -Fx '{print $2}')
+ WIN_ID=$(( 16#$HEX )) # convert to decimal
+ xdotool windowunmap $WIN_ID
+ echo $WIN_ID > $WINDOW_ID_CONKY
+}
+
+polybar_launch() {
+ killall polybar
+
+ polybar top &
+ xdotool search --sync --pid $! > $WINDOW_ID_TOP
+
+ polybar expanded &
+ xdotool search --sync --pid $! > $WINDOW_ID_EXPANDED
+
+ bar_collapse
+}
+
+launch() {
+ # Temporarily disable conky until I update the config
+ # conky_launch
+ # sleep 0.2
+ polybar_launch
+}
+
+bar_expand() {
+ xdotool windowmap $(cat $WINDOW_ID_EXPANDED)
+ xdotool windowunmap $(cat $WINDOW_ID_TOP)
+}
+
+bar_collapse() {
+ xdotool windowunmap $(cat $WINDOW_ID_EXPANDED)
+ xdotool windowmap $(cat $WINDOW_ID_TOP)
+}
+
+rofi_open() {
+ options_close
+ bar_expand &
+ rofi -modi run -show run
+ bar_collapse
+}
+
+drun_open() {
+ bar_expand &
+ rofi -theme drun -modi drun -show drun -drun-categories Custom
+ bar_collapse
+}
+
+search_open() {
+ options_close
+ bar_expand &
+ rofi -theme window -modi window -show window
+ bar_collapse
+}
+
+options_open() {
+ bar_expand
+ $DIR/rofi_option_menu
+ bar_collapse
+ # echo "open" > /tmp/polybar_side_panel_state
+ # ID_CONKY=$(cat $WINDOW_ID_CONKY)
+ # xdotool windowmap $ID_CONKY
+ # xdotool windowraise $ID_CONKY
+ # ~/.config/i3/scripts/music_player show_applet
+}
+
+case "$1" in
+ rofi)
+ rofi_open;;
+ search)
+ search_open;;
+ drun)
+ drun_open;;
+ options)
+ options_open;;
+ launch)
+ launch;;
+esac
diff --git a/linux/home/.config/polybar/scripts/popup-calendar.sh b/linux/home/.config/polybar/scripts/popup-calendar.sh
new file mode 100755
index 0000000..4e5303c
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/popup-calendar.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+BAR_HEIGHT=22 # polybar height
+BORDER_SIZE=1 # border size from your wm settings
+YAD_WIDTH=222 # 222 is minimum possible value
+YAD_HEIGHT=193 # 193 is minimum possible value
+DATE="$(date +"%a %d %b, %H:%M")"
+
+case "$1" in
+--popup)
+ if [ "$(xdotool getwindowfocus getwindowname)" = "yad-calendar" ]; then
+ exit 0
+ fi
+
+ eval "$(xdotool getmouselocation --shell)"
+ eval "$(xdotool getdisplaygeometry --shell)"
+
+ # X
+ if [ "$((X + YAD_WIDTH / 2 + BORDER_SIZE))" -gt "$WIDTH" ]; then #Right side
+ : $((pos_x = WIDTH - YAD_WIDTH - BORDER_SIZE))
+ elif [ "$((X - YAD_WIDTH / 2 - BORDER_SIZE))" -lt 0 ]; then #Left side
+ : $((pos_x = BORDER_SIZE))
+ else #Center
+ : $((pos_x = X - YAD_WIDTH / 2))
+ fi
+
+ # Y
+ if [ "$Y" -gt "$((HEIGHT / 2))" ]; then #Bottom
+ : $((pos_y = HEIGHT - YAD_HEIGHT - BAR_HEIGHT - BORDER_SIZE))
+ else #Top
+ : $((pos_y = BAR_HEIGHT + BORDER_SIZE))
+ fi
+
+ yad --calendar --undecorated --fixed --close-on-unfocus --no-buttons \
+ --width="$YAD_WIDTH" --height="$YAD_HEIGHT" --posx="$pos_x" --posy="$pos_y" \
+ --title="yad-calendar" --borders=0 >/dev/null &
+ ;;
+*)
+ echo "$DATE"
+ ;;
+esac
diff --git a/linux/home/.config/polybar/scripts/rofi-power.sh b/linux/home/.config/polybar/scripts/rofi-power.sh
new file mode 100755
index 0000000..87ac92c
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/rofi-power.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env sh
+#
+# A rofi powered menu to execute power related action.
+# Uses: amixer mpc poweroff reboot rofi rofi-prompt
+
+power_off=''
+reboot=''
+lock=''
+suspend='鈴'
+log_out=''
+
+chosen=$(printf '%s;%s;%s;%s;%s\n' "$power_off" "$reboot" "$lock" "$suspend" \
+ "$log_out" \
+ | rofi -theme '~/.config/rofi/themes/power.rasi' \
+ -dmenu \
+ -sep ';' \
+ -selected-row 2)
+
+case "$chosen" in
+ "$power_off")
+ rofi-prompt --query 'Shutdown?' && poweroff
+ ;;
+
+ "$reboot")
+ rofi-prompt --query 'Reboot?' && reboot
+ ;;
+
+ "$lock")
+ # TODO Add your lockscreen command.
+ ;;
+
+ "$suspend")
+ # Pause music and mute volume before suspending.
+ mpc --quiet pause
+ amixer set Master mute
+ # TODO Add your suspend command.
+ ;;
+
+ "$log_out")
+ # TODO Add your log out command.
+ ;;
+
+ *) exit 1 ;;
+esac
+
diff --git a/linux/home/.config/polybar/scripts/scroll_spotify_status.sh b/linux/home/.config/polybar/scripts/scroll_spotify_status.sh
new file mode 100755
index 0000000..74e0bfd
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/scroll_spotify_status.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# see man zscroll for documentation of the following parameters
+zscroll -l 20 \
+ --delay 0.1 \
+ --scroll-padding " " \
+ --match-command "$HOME/.config/polybar/scripts/get_spotify_status.sh --status" \
+ --match-text "Playing" "--scroll 1" \
+ --match-text "Paused" "--scroll 0" \
+ --update-check true "$HOME/.config/polybar/scripts/get_spotify_status.sh" &
+
+wait
diff --git a/linux/home/.config/polybar/scripts/sysmenu.sh b/linux/home/.config/polybar/scripts/sysmenu.sh
new file mode 100755
index 0000000..a3a7a2a
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/sysmenu.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# Display a power menu to: shutdown, reboot,
+# lock, logout, and suspend. This script can be
+# executed by clicking on the polybar powermenu module
+# or with a keyboard shortcut
+
+# Options to be displayed
+shutdown=" Shutdown"
+reboot=" Reboot"
+lock=" Lock"
+logout=" Logout"
+suspend=" Suspend"
+
+uptime=$(uptime -p | sed -e 's/up //g')
+
+# Options passed into variable
+options="$shutdown\n$reboot\n$lock\n$logout\n$suspend"
+
+# Specify the path to the Rofi configuration file
+config_file="$HOME/.config/rofi/styles/powermenu.rasi"
+
+# Show Rofi with the specified configuration file
+chosen="$(echo -e "$options" | rofi -no-lazy-grab -sep -config "$config_file" -dmenu -p 'System ' "$uptime")"
+
+case $chosen in
+ $shutdown)
+ shutdown now
+ ;;
+ $reboot)
+ systemctl reboot
+ ;;
+ $lock)
+ betterlockscreen --lock dimblur
+ ;;
+ $logout)
+ bspc quit
+ ;;
+ $suspend)
+ systemctl suspend
+ ;;
+esac
diff --git a/linux/home/.config/polybar/scripts/sysmenu.shsave b/linux/home/.config/polybar/scripts/sysmenu.shsave
new file mode 100755
index 0000000..00ce125
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/sysmenu.shsave
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# display a power menu to: shutdown, reboot,
+# lock, logout, and suspend. This script can be
+# executed by clicking on the polybar powermenu module
+# or with a keyboard shortcut
+
+
+# options to be displayed
+shutdown=" Shutdown"
+reboot=" Reboot"
+lock=" Lock"
+logout=" Logout"
+suspend=" Suspend"
+
+uptime=$(uptime -p | sed -e 's/up //g')
+
+# options passed into variable
+options="$shutdown\n$reboot\n$lock\n$logout\n$suspend"
+
+chosen="$(echo -e "$options" | rofi -no-lazy-grab -sep -lines 5 -hide-scrollbar true -border 0 -padding 0 -height 2px -width 15 -xoffset -10 -yoffset 28 -location 3 -columns 1 -dmenu -p 'System ' "$uptime")"
+
+case $chosen in
+$shutdown)
+ systemctl poweroff
+ ;;
+$reboot)
+ systemctl reboot
+ ;;
+$lock)
+ betterlockscreen --lock dimblur
+ ;;
+$logout)
+ bspc quit
+ ;;
+$suspend)
+ systemctl suspend
+ ;;
+esac
+
diff --git a/linux/home/.config/polybar/scripts/system-usb-mount.sh b/linux/home/.config/polybar/scripts/system-usb-mount.sh
new file mode 100755
index 0000000..63e9187
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/system-usb-mount.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+devices=$(lsblk -Jplno NAME,TYPE,RM,SIZE,MOUNTPOINT,VENDOR)
+
+case "$1" in
+ --mount)
+ for mount in $(echo "$devices" | jq -r '.blockdevices[] | select(.type == "part") | select(.rm == true) | select(.mountpoint == null) | .name'); do
+ udisksctl mount --no-user-interaction -b "$mount"
+
+ mountpoint=$(udisksctl mount --no-user-interaction -b $mount)
+ mountpoint=$(echo $mountpoint | cut -d " " -f 4- | tr -d ".")
+ kitty -e "bash -lc 'pcmanfm $mountpoint'" &
+ done
+ ;;
+ --unmount)
+ for unmount in $(echo "$devices" | jq -r '.blockdevices[] | select(.type == "part") | select(.rm == true) | select(.mountpoint != null) | .name'); do
+ udisksctl unmount --no-user-interaction -b "$unmount"
+ udisksctl power-off --no-user-interaction -b "$unmount"
+ done
+ ;;
+ *)
+ output=""
+ counter=0
+
+ for unmounted in $(echo "$devices" | jq -r '.blockdevices[] | select(.type == "part") | select(.rm == true) | select(.mountpoint == null) | .name'); do
+ unmounted=$(echo "$unmounted" | tr -d "[:digit:]")
+ unmounted=$(echo "$devices" | jq -r '.blockdevices[] | select(.name == "'"$unmounted"'") | .vendor')
+ unmounted=$(echo "$unmounted" | tr -d ' ')
+
+ if [ $counter -eq 0 ]; then
+ space=""
+ else
+ space=" "
+ fi
+ counter=$((counter + 1))
+
+ output="$output$space#1 $unmounted"
+ done
+
+ for mounted in $(echo "$devices" | jq -r '.blockdevices[] | select(.type == "part") | select(.rm == true) | select(.mountpoint != null) | .size'); do
+ if [ $counter -eq 0 ]; then
+ space=""
+ else
+ space=" "
+ fi
+ counter=$((counter + 1))
+
+ output="$output$space#2 $mounted"
+ done
+
+ echo "$output"
+ ;;
+esac
diff --git a/linux/home/.config/polybar/scripts/temperature.sh b/linux/home/.config/polybar/scripts/temperature.sh
new file mode 100755
index 0000000..7ef6abb
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/temperature.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Pulls CPU temps, averages them, and outputs them
+
+count=0
+sum=0.0
+
+# Iterate over each temperature reading
+for temp in "$(sensors | grep "^Core" | grep -e '+.*C' | cut -f 2 -d '+' | cut -f 1 -d ' ' | sed 's/°C//')"; do
+ sum=$(echo "$sum + $temp" | bc)
+ ((count++))
+done
+
+# Calculate the average
+avg=$(echo "scale=0; $sum / $count" | bc)
+
+# Output the average temperature without decimal points
+echo " ${avg%.*}°C"
diff --git a/linux/home/.config/polybar/scripts/toggle_bluetooth.sh b/linux/home/.config/polybar/scripts/toggle_bluetooth.sh
new file mode 100755
index 0000000..899d5ec
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/toggle_bluetooth.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+if [ $(bluetoothctl show | grep "Powered: yes" | wc -c) -eq 0 ]
+then
+ bluetoothctl power on
+else
+ bluetoothctl power off
+fi
+
diff --git a/linux/home/.config/polybar/scripts/vpn.sh b/linux/home/.config/polybar/scripts/vpn.sh
new file mode 100755
index 0000000..ab1eb9d
--- /dev/null
+++ b/linux/home/.config/polybar/scripts/vpn.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Set a default message
+default_message=" vpn"
+
+# Check if Protonvpn service is running
+if pgrep -x "openvpn" >/dev/null; then
+ # If Protonvpn service is running, get the country
+ country=$(protonvpn s | grep Country)
+ # Extract the connection ID
+ connection=$(pgrep -a openvpn$ | head -n 1 | awk '{print $NF }' | cut -d '.' -f 1)
+ # Output vpn status with the country if connected
+ echo " vpn" #"$country"
+else
+ # If Protonvpn service is not running, output default message
+ echo "$default_message"
+fi
+
+#
+#proton_status=$(protonvpn s)
+#current_status=$(protonvpn s | wc -l)
+#current_server=$(protonvpn s | awk '/Server:/ {print "VPN "$2}')
+#
+#if [ "$current_status" -gt 2 ]; then
+# echo "$current_server"
+#else
+# echo "%{F#bf616a}NO VPN"
+#fi
diff --git a/linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1 b/linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1
new file mode 100644
index 0000000..349f7ab
--- /dev/null
+++ b/linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1
@@ -0,0 +1,14 @@
+# Dotfiles special git command
+function global:config {
+ git --git-dir="$env:USERPROFILE\.cfg" --work-tree="$env:USERPROFILE" $args
+}
+
+# Shows navigable menu of all options when hitting Tab
+Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
+
+# Autocompletion for arrow keys
+Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
+Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward
+
+New-Alias vi nvim.exe
+
diff --git a/linux/home/.config/powershell/bloatware.ps1 b/linux/home/.config/powershell/bloatware.ps1
new file mode 100644
index 0000000..2c8dacb
--- /dev/null
+++ b/linux/home/.config/powershell/bloatware.ps1
@@ -0,0 +1,335 @@
+# bloatware.ps1
+
+# Check if the powershell-yaml module is installed, if not, install it
+if (-not (Get-Module powershell-yaml -ListAvailable)) {
+ $policy = Get-PSRepository -Name 'PSGallery' | Select-Object -ExpandProperty InstallationPolicy
+ Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
+ Install-Module powershell-yaml
+ Set-PSRepository -Name 'PSGallery' -InstallationPolicy $policy
+}
+
+Import-Module powershell-yaml
+
+# Define the path to the YAML file
+$yamlFilePath = "$HOME\packages.yml"
+
+# Parse the YAML file
+$packages = ConvertFrom-Yaml -Path $yamlFilePath
+$bloatware = $packages.bloatware
+$defaultApps = $packages.defaultApps
+
+# Check if Registry key exists
+function Check-RegistryKeyExists {
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$KeyPath
+ )
+
+ if (Test-Path $KeyPath) {
+ Write-Host "Registry key exists: $KeyPath"
+ return $true
+ } else {
+ Write-Host "Registry key does not exist: $KeyPath"
+ return $false
+ }
+}
+
+# Helper functions ------------------------
+function force-mkdir($path) {
+ if (!(Test-Path $path)) {
+ Write-Host "-- Creating full path to: " $path -ForegroundColor White -BackgroundColor DarkGreen
+ New-Item -ItemType Directory -Force -Path $path
+ }
+}
+
+function Takeown-Registry($key) {
+ # TODO does not work for all root keys yet
+ switch ($key.split('\')[0]) {
+ "HKEY_CLASSES_ROOT" {
+ $reg = [Microsoft.Win32.Registry]::ClassesRoot
+ $key = $key.substring(18)
+ }
+ "HKEY_CURRENT_USER" {
+ $reg = [Microsoft.Win32.Registry]::CurrentUser
+ $key = $key.substring(18)
+ }
+ "HKEY_LOCAL_MACHINE" {
+ $reg = [Microsoft.Win32.Registry]::LocalMachine
+ $key = $key.substring(19)
+ }
+ }
+
+ # get administrator group
+ $admins = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
+ $admins = $admins.Translate([System.Security.Principal.NTAccount])
+
+ # set owner
+ $key = $reg.OpenSubKey($key, "ReadWriteSubTree", "TakeOwnership")
+ $acl = $key.GetAccessControl()
+ $acl.SetOwner($admins)
+ $key.SetAccessControl($acl)
+
+ # set FullControl
+ $acl = $key.GetAccessControl()
+ $rule = New-Object System.Security.AccessControl.RegistryAccessRule($admins, "FullControl", "Allow")
+ $acl.SetAccessRule($rule)
+ $key.SetAccessControl($acl)
+}
+
+# Function to take ownership of registry keys
+function Takeown-Registry($keyPath) {
+ $regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($keyPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
+ $acl = $regKey.GetAccessControl()
+ $acl.SetOwner([System.Security.Principal.NTAccount]"Administrators")
+ $regKey.SetAccessControl($acl)
+ $regKey.Close()
+}
+
+# Remove Features
+function Takeown-File($path) {
+ takeown.exe /A /F $path
+ $acl = Get-Acl $path
+
+ # get administrator group
+ $admins = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
+ $admins = $admins.Translate([System.Security.Principal.NTAccount])
+
+ # add NT Authority\SYSTEM
+ $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($admins, "FullControl", "None", "None", "Allow")
+ $acl.AddAccessRule($rule)
+
+ Set-Acl -Path $path -AclObject $acl
+}
+
+function Takeown-Folder($path) {
+ Takeown-File $path
+ foreach ($item in Get-ChildItem $path) {
+ if (Test-Path $item -PathType Container) {
+ Takeown-Folder $item.FullName
+ }
+ else {
+ Takeown-File $item.FullName
+ }
+ }
+}
+
+function Elevate-Privileges {
+ param($Privilege)
+ $Definition = @"
+ using System;
+ using System.Runtime.InteropServices;
+
+ public class AdjPriv {
+ [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
+ internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr rele);
+
+ [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
+ internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ internal struct TokPriv1Luid {
+ public int Count;
+ public long Luid;
+ public int Attr;
+ }
+
+ internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
+ internal const int TOKEN_QUERY = 0x00000008;
+ internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
+
+ public static bool EnablePrivilege(long processHandle, string privilege) {
+ bool retVal;
+ TokPriv1Luid tp;
+ IntPtr hproc = new IntPtr(processHandle);
+ IntPtr htok = IntPtr.Zero;
+ retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
+ tp.Count = 1;
+ tp.Luid = 0;
+ tp.Attr = SE_PRIVILEGE_ENABLED;
+ retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
+ retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
+ return retVal;
+ }
+ }
+"@
+ $ProcessHandle = (Get-Process -id $pid).Handle
+ $type = Add-Type $definition -PassThru
+ $type[0]::EnablePrivilege($processHandle, $Privilege)
+}
+
+# Remove Features ------------------------
+foreach ($bloat in $bloatware) {
+ Write-Output "Removing packages containing $bloat"
+ $pkgs = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages" | Where-Object Name -Like "*$bloat*"
+
+ foreach ($pkg in $pkgs) {
+ $pkgname = $pkg.Name.Split('\')[-1]
+ Takeown-Registry $pkg.Name
+ Takeown-Registry ($pkg.Name + "\Owners")
+ Set-ItemProperty -Path ("HKLM:" + $pkg.Name.Substring(18)) -Name Visibility -Value 1
+ New-ItemProperty -Path ("HKLM:" + $pkg.Name.Substring(18)) -Name DefVis -PropertyType DWord -Value 2
+ Remove-Item -Path ("HKLM:" + $pkg.Name.Substring(18) + "\Owners")
+ dism.exe /Online /Remove-Package /PackageName:$pkgname /NoRestart
+ }
+}
+
+# Remove default apps and bloat
+Write-Output "Uninstalling default apps"
+foreach ($app in $defaultApps) {
+ Write-Output "Trying to remove $app"
+ Get-AppxPackage -Name $app -AllUsers | Remove-AppxPackage -AllUsers
+ Get-AppXProvisionedPackage -Online | Where-Object DisplayName -EQ $app | Remove-AppxProvisionedPackage -Online
+}
+
+# Disable Microsoft Edge sidebar
+$RegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge'
+$Name = 'HubsSidebarEnabled'
+$Value = '00000000'
+# Create the key if it does not exist
+If (-NOT (Test-Path $RegistryPath)) {
+ New-Item -Path $RegistryPath -Force | Out-Null
+}
+New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force
+
+# Disable Microsoft Edge first-run Welcome screen
+$RegistryPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Edge'
+$Name = 'HideFirstRunExperience'
+$Value = '00000001'
+# Create the key if it does not exist
+If (-NOT (Test-Path $RegistryPath)) {
+ New-Item -Path $RegistryPath -Force | Out-Null
+}
+New-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -PropertyType DWORD -Force
+
+# Remove Microsoft Edge ------------------------
+$ErrorActionPreference = "Stop"
+$regView = [Microsoft.Win32.RegistryView]::Registry32
+$microsoft = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $regView).
+OpenSubKey('SOFTWARE\Microsoft', $true)
+$edgeUWP = "$env:SystemRoot\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe"
+$uninstallRegKey = $microsoft.OpenSubKey('Windows\CurrentVersion\Uninstall\Microsoft Edge')
+$uninstallString = $uninstallRegKey.GetValue('UninstallString') + ' --force-uninstall'
+Write-Host "Removed Microsoft Edge"
+
+$edgeClient = $microsoft.OpenSubKey('EdgeUpdate\ClientState\{56EB18F8-B008-4CBD-B6D2-8C97FE7E9062}', $true)
+if ($null -ne $edgeClient.GetValue('experiment_control_labels')) {
+ $edgeClient.DeleteValue('experiment_control_labels')
+}
+$microsoft.CreateSubKey('EdgeUpdateDev').SetValue('AllowUninstall', '')
+[void](New-Item $edgeUWP -ItemType Directory -ErrorVariable fail -ErrorAction SilentlyContinue)
+[void](New-Item "$edgeUWP\MicrosoftEdge.exe" -ErrorAction Continue)
+Start-Process cmd.exe "/c $uninstallString" -WindowStyle Hidden -Wait
+[void](Remove-Item "$edgeUWP\MicrosoftEdge.exe" -ErrorAction Continue)
+
+if (-not $fail) {
+ [void](Remove-Item "$edgeUWP")
+}
+
+Write-Output "Edge should now be uninstalled!"
+
+# Kill OneDrive with fire ------------------------
+Write-Output "Kill OneDrive process"
+taskkill.exe /F /IM "OneDrive.exe"
+taskkill.exe /F /IM "explorer.exe"
+Write-Output "Remove OneDrive"
+if (Test-Path "$env:systemroot\System32\OneDriveSetup.exe") {
+ & "$env:systemroot\System32\OneDriveSetup.exe" /uninstall
+}
+if (Test-Path "$env:systemroot\SysWOW64\OneDriveSetup.exe") {
+ & "$env:systemroot\SysWOW64\OneDriveSetup.exe" /uninstall
+}
+
+Write-Output "Removing OneDrive leftovers"
+Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:localappdata\Microsoft\OneDrive"
+Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:programdata\Microsoft OneDrive"
+Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:systemdrive\OneDriveTemp"
+# check if directory is empty before removing:
+If ((Get-ChildItem "$env:userprofile\OneDrive" -Recurse | Measure-Object).Count -eq 0) {
+ Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:userprofile\OneDrive"
+}
+
+Write-Output "Disable OneDrive via Group Policies"
+force-mkdir "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\OneDrive"
+Set-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft\Windows\OneDrive" "DisableFileSyncNGSC" 1
+
+Write-Output "Remove Onedrive from explorer sidebar"
+New-PSDrive -PSProvider "Registry" -Root "HKEY_CLASSES_ROOT" -Name "HKCR"
+force-mkdir "HKCR:\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}"
+Set-ItemProperty "HKCR:\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" "System.IsPinnedToNameSpaceTree" 0
+force-mkdir "HKCR:\Wow6432Node\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}"
+Set-ItemProperty "HKCR:\Wow6432Node\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}" "System.IsPinnedToNameSpaceTree" 0
+Remove-PSDrive "HKCR"
+
+# Thank you Matthew Israelsson
+Write-Output "Removing run hook for new users"
+reg load "hku\Default" "C:\Users\Default\NTUSER.DAT"
+reg delete "HKEY_USERS\Default\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "OneDriveSetup" /f
+reg unload "hku\Default"
+
+Write-Output "Removing startmenu entry"
+Remove-Item -Force -ErrorAction SilentlyContinue "$env:userprofile\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\OneDrive.lnk"
+
+Write-Output "Removing scheduled task"
+$scheduledTasks = Get-ScheduledTask -TaskPath '\' -TaskName 'OneDrive*' -ErrorAction SilentlyContinue
+if ($scheduledTasks) {
+ try {
+ $scheduledTasks | Unregister-ScheduledTask -Confirm:$false
+ Write-Output "OneDrive scheduled tasks removed."
+ } catch {
+ Write-Warning "Failed to unregister scheduled tasks: $_"
+ }
+} else {
+ Write-Output "No OneDrive scheduled tasks found."
+}
+
+Write-Output "Restarting explorer"
+Start-Process "explorer.exe"
+
+Write-Output "Waiting for explorer to complete loading"
+Start-Sleep 10
+
+Write-Output "Removing additional OneDrive leftovers"
+foreach ($item in (Get-ChildItem "$env:WinDir\WinSxS\*onedrive*")) {
+ Takeown-Folder $item.FullName
+ try {
+ Remove-Item -Recurse -Force -ErrorAction Continue -ErrorVariable RemoveError $item.FullName
+ if ($RemoveError) {
+ Write-Warning "Failed to remove $($item.FullName): $($RemoveError.Exception.Message)"
+ } else {
+ Write-Output "Successfully removed: $($item.FullName)"
+ }
+ } catch {
+ Write-Warning "Failed to remove $($item.FullName): $_"
+ }
+}
+
+# As a last step, disable UAC ------------------------
+New-ItemProperty -Path HKLM:Software\Microsoft\Windows\CurrentVersion\policies\system -Name EnableLUA -PropertyType DWord -Value 0 -Force
+
+# Remove OneDrive directory if it exists
+Write-Host "Removing OneDrive directory"
+
+# Change directory to user's home directory
+Set-Location $HOME
+
+# Check if OneDrive directory exists
+$OneDrivePath = Join-Path $HOME "OneDrive"
+if (Test-Path -Path $OneDrivePath -PathType Container) {
+ # Remove OneDrive directory recursively and forcefully
+ Remove-Item -Path $OneDrivePath -Recurse -Force -ErrorAction Continue
+ if ($?) {
+ Write-Output "OneDrive directory removed successfully."
+ } else {
+ Write-Warning "Failed to remove OneDrive directory."
+ }
+} else {
+ Write-Output "OneDrive directory not found."
+}
+
+# Prevents "Suggested Applications" returning
+if (Check-RegistryKeyExists -KeyPath "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content") {
+ Set-ItemProperty "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content" "DisableWindowsConsumerFeatures" 1
+}
diff --git a/linux/home/.config/powershell/bootstrap.ps1 b/linux/home/.config/powershell/bootstrap.ps1
new file mode 100644
index 0000000..73d53b5
--- /dev/null
+++ b/linux/home/.config/powershell/bootstrap.ps1
@@ -0,0 +1,396 @@
+# Requires -RunAsAdministrator
+
+# Set execution policy to remote signed
+Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
+
+# Set network category to private
+Set-NetConnectionProfile -NetworkCategory Private
+
+# Variables
+$dotfiles_url = 'https://github.com/srdusr/dotfiles.git'
+$dotfiles_dir = "$HOME\.cfg"
+
+# Function to handle errors
+function handle_error {
+ param ($message)
+ Write-Host $message -ForegroundColor Red
+ exit 1
+}
+
+# Logs
+New-Item -Path $Env:USERPROFILE\Logs -ItemType directory -Force
+Start-Transcript -Path $Env:USERPROFILE\Logs\Bootstrap.log
+$ErrorActionPreference = 'SilentlyContinue'
+Write-Host "Bootstrap.log generated in Logs\"
+
+# Function to check if the current session is elevated
+function Test-IsAdmin {
+ $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
+ $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
+ return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
+}
+
+# Ensure the script is run as administrator
+if (-not (Test-IsAdmin)) {
+ handle_error "This script must be run as an administrator."
+}
+
+# Imports
+. $HOME\.config\powershell\initialize.ps1
+. $HOME\.config\powershell\bloatware.ps1
+
+# Configure PowerShell
+Write-Host "Configuring PowerShell"
+Write-Host "----------------------------------------"
+
+# Get the "MyDocuments" path for the current user, excluding OneDrive
+$UserMyDocumentsPath = [System.Environment]::GetFolderPath('MyDocuments').Replace("OneDrive", "")
+
+$PowerShellProfileDirectory = "$UserMyDocumentsPath\PowerShell"
+$PowerShellLegacySymlink = "$UserMyDocumentsPath\WindowsPowerShell"
+
+$PowerShellProfileTemplate = "$PSScriptRoot\$USERNAME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1"
+$env:PSModulePath = $env:PSModulePath -replace "\\OneDrive\\Documents\\WindowsPowerShell\\","\.powershell\"
+
+# Set documents path to user's local Documents folder
+$documentsPath = "$UserMyDocumentsPath"
+$powerShellProfileDir = "$documentsPath\PowerShell"
+
+# Output the chosen PowerShell profile directory
+$PROFILE = "$powerShellProfileDir\Microsoft.PowerShell_profile.ps1"
+Write-Host "PowerShell profile directory set to: $powerShellProfileDir"
+
+if (-not (Test-Path -Path $powerShellProfileDir)) {
+ New-Item -ItemType Directory -Path $powerShellProfileDir -Force
+}
+
+New-Item -ItemType HardLink -Force `
+ -Path "$powerShellProfileDir\Microsoft.PowerShell_profile.ps1" `
+ -Target "$home\.config\powershell\Microsoft.PowerShell_profile.ps1"
+
+# Set environment variable
+[System.Environment]::SetEnvironmentVariable('PowerShellProfileDir', $powerShellProfileDir, [System.EnvironmentVariableTarget]::User)
+
+Write-Host "PowerShell profile directory set to: $powerShellProfileDir"
+Write-Host "Environment variable 'PowerShellProfileDir' set to: $powerShellProfileDir"
+
+# Verify profile sourcing
+if (!(Test-Path -Path "$home\.config\powershell\Microsoft.PowerShell_profile.ps1")) {
+ handle_error "PowerShell profile does not exist. Please create it at $home\.config\powershell\Microsoft.PowerShell_profile.ps1"
+}
+
+# Install Chocolatey if not installed
+Write-Host "Installing Chocolatey"
+Write-Host "----------------------------------------"
+
+if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
+ [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
+ Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
+
+ # Check if Chocolatey installed successfully
+ if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
+ handle_error "Chocolatey installation failed."
+ }
+} else {
+ Write-Host "Chocolatey is already installed."
+}
+
+# Install Applications
+Write-Host "Installing Applications"
+Write-Host "----------------------------------------"
+
+# Check if the powershell-yaml module is installed, if not, install it
+if (-not (Get-Module powershell-yaml -ListAvailable)) {
+ $policy = Get-PSRepository -Name 'PSGallery' | Select-Object -ExpandProperty InstallationPolicy
+ Set-PSRepository -Name 'PSGallery' -InstallationPolicy Trusted
+ Install-Module powershell-yaml
+ Set-PSRepository -Name 'PSGallery' -InstallationPolicy $policy
+}
+
+Import-Module powershell-yaml
+
+# Load packages.yml
+$packagesFile = "$HOME\packages.yml"
+$packages = Get-Content $packagesFile | ConvertFrom-Yaml
+
+# Ensure 'windows' section exists and has applications listed
+if ($packages.windows) {
+ foreach ($app in $packages.windows) {
+ # Check if the application is already installed
+ if (-not (choco list --local-only | Select-String -Pattern "^$app\s")) {
+ Write-Host "Installing $app"
+ choco install $app -y
+
+ if ($LASTEXITCODE -ne 0) {
+ handle_error "Installation of $app failed."
+ } else {
+ Write-Host "$app installed successfully."
+ }
+ } else {
+ Write-Host "$app is already installed."
+ }
+ }
+} else {
+ Write-Host "No applications specified under the 'windows' section in $packagesFile."
+}
+
+# Set Chrome as default browser ------------------------
+#Add-Type -AssemblyName 'System.Windows.Forms'
+#Start-Process $env:windir\system32\control.exe -ArgumentList '/name Microsoft.DefaultPrograms /page pageDefaultProgram\pageAdvancedSettings?pszAppName=google%20chrome'
+#Sleep 2
+#[System.Windows.Forms.SendKeys]::SendWait("{TAB} {TAB}{TAB} ")
+SetDefaultBrowser firefox
+
+# Refresh the environment variables
+Write-Host "Refreshing environment variables"
+
+# Update the current session environment variables
+Write-Host "Setting environment variables" -ForegroundColor Cyan
+$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
+[System.Environment]::SetEnvironmentVariable("Path", $env:Path, [System.EnvironmentVariableTarget]::Process)
+[Environment]::SetEnvironmentVariable("HOME", "$env:USERPROFILE", "User")
+[Environment]::SetEnvironmentVariable("LC_ALL", "C.UTF-8", "User")
+refreshenv
+
+# Add Git to PATH if it's installed via Chocolatey
+Write-Host "Checking for Git installation"
+$gitBinPath = "C:\Program Files\Git\bin"
+$gitCmdPath = "C:\Program Files\Git\cmd"
+$gitPaths = @($gitBinPath, $gitCmdPath)
+
+foreach ($path in $gitPaths) {
+ if (Test-Path $path) {
+ Write-Host "Adding $path to PATH"
+ [System.Environment]::SetEnvironmentVariable("Path", "$env:Path;$path", [System.EnvironmentVariableTarget]::Machine)
+ [System.Environment]::SetEnvironmentVariable("Path", "$env:Path;$path", [System.EnvironmentVariableTarget]::User)
+ [System.Environment]::SetEnvironmentVariable("Path", "$env:Path;$path", [System.EnvironmentVariableTarget]::Process)
+ } else {
+ Write-Host "$path does not exist."
+ }
+}
+
+# Check if Git is installed
+Write-Host "Checking for Git installation"
+if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
+ handle_error "Git is not installed or not found in PATH after installation."
+} else {
+ Write-Host "Git is installed and available in PATH."
+}
+
+# Define the `config` alias in the current session
+function global:config {
+ git --git-dir="$env:USERPROFILE\.cfg" --work-tree="$env:USERPROFILE" $args
+}
+
+# Add .gitignore entries
+Add-Content -Path "$HOME\.gitignore" -Value ".cfg"
+Add-Content -Path "$HOME\.gitignore" -Value "install.bat"
+Add-Content -Path "$HOME\.gitignore" -Value ".config/powershell/bootstrap.ps1"
+
+# Create symbolic links
+Write-Host "Create symbolic links"
+Write-Host "----------------------------------------"
+
+# Visual Studio Code settings.json
+New-Item -Force -ItemType SymbolicLink $HOME\AppData\Roaming\Code\User\ -Name settings.json -Value $HOME\.config\Code\User\settings.json
+
+# Visual Studio Code keybindings
+New-Item -Force -ItemType SymbolicLink $HOME\AppData\Roaming\Code\User\ -Name keybindings.json -Value $HOME\.config\Code\User\keybindings.json
+
+# Function to install dotfiles
+function install_dotfiles {
+ if (Test-Path -Path $dotfiles_dir) {
+ config pull | Out-Null
+ $update = $true
+ } else {
+ git clone --bare $dotfiles_url $dotfiles_dir | Out-Null
+ $update = $false
+ }
+
+ $std_err_output = config checkout 2>&1
+
+ if ($std_err_output -match "following untracked working tree files would be overwritten") {
+ if (-not $update) {
+ config checkout | Out-Null
+ }
+ }
+ config config status.showUntrackedFiles no
+
+ git config --global include.path "$HOME\.gitconfig.aliases"
+
+ if ($update -or (Read-Host "Do you want to overwrite existing files and continue with the dotfiles setup? [Y/n]" -eq "Y")) {
+ config fetch origin main:main | Out-Null
+ config reset --hard main | Out-Null
+ config checkout -f
+ if ($?) {
+ Write-Host "Successfully imported $dotfiles_dir."
+ } else {
+ handle_error "Mission failed."
+ }
+ } else {
+ handle_error "Aborted by user. Exiting..."
+ }
+}
+
+install_dotfiles
+
+# Install python
+Write-Host "Updating python packages" -ForegroundColor Cyan
+python -m pip install --upgrade pip
+
+# Enable WSL feature
+dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
+Write-Host "Enable WSL feature"
+wsl --install -d ubuntu
+wsl --set-default-version 2
+
+# Enable Virtual Machine feature
+#dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
+#Write-Host "Enable Virtual Machine feature"
+
+Write-Header "Installing Hyper-V"
+
+# Install Hyper-V
+Write-Host "Installing Hyper-V and restart"
+Enable-WindowsOptionalFeature -Online -FeatureName Containers -All -NoRestart
+Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart
+Install-WindowsFeature -Name Hyper-V -IncludeAllSubFeature -IncludeManagementTools -NoRestart
+
+# Configure Neovim
+Write-Host "Configuring Neovim"
+Write-Host "----------------------------------------"
+
+$neovimLocalPath = "$home\AppData\Local\nvim"
+$neovimConfigPath = "$home\.config\nvim"
+
+# Check if nvim directory already exists in AppData\Local
+if (-not (Test-Path -Path $neovimLocalPath)) {
+ New-Item -ItemType Junction -Force -Path $neovimLocalPath -Target $neovimConfigPath
+} else {
+ Write-Host "Neovim directory ($neovimLocalPath) already exists."
+}
+
+# Install Windows Terminal, and configure
+Write-Host "Install Windows Terminal, and configure"
+Write-Host "----------------------------------------"
+
+$windowsTerminalSettingsPath = "$home\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json"
+$windowsTerminalConfigPath = "$home\.config\windows-terminal\settings.json"
+
+# Check if Windows Terminal settings.json already exists
+if (Test-Path -Path $windowsTerminalSettingsPath) {
+ # Backup existing settings.json
+ Move-Item -Force $windowsTerminalSettingsPath "$windowsTerminalSettingsPath.old"
+} else {
+ Write-Host "Windows Terminal settings.json not found, no need to backup."
+}
+
+# Create a hard link to the settings.json file in .config\windows-terminal
+New-Item -ItemType HardLink -Force -Path $windowsTerminalSettingsPath -Target $windowsTerminalConfigPath
+
+# Function to check if a registry key exists
+function Test-RegistryKeyExists {
+ param ($path)
+ return (Test-Path $path -PathType Container)
+}
+
+# Function to check if a registry property exists
+function Test-RegistryPropertyExists {
+ param ($keyPath, $propertyName)
+ if (Test-Path $keyPath) {
+ $properties = Get-ItemProperty -Path $keyPath
+ return $properties.PSObject.Properties.Name -contains $propertyName
+ }
+ return $false
+}
+
+# Registry Tweaks
+Write-Host "Registry Tweaks"
+Write-Host "----------------------------------------"
+
+# Show hidden files
+$advancedKeyPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
+if (-not (Test-RegistryPropertyExists $advancedKeyPath "Hidden")) {
+ Set-ItemProperty -Path $advancedKeyPath -Name Hidden -Value 1
+}
+
+# Show file extensions in Windows Explorer
+$hideFileExtPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
+if (-not (Test-RegistryPropertyExists $hideFileExtPath "HideFileExt")) {
+ Set-ItemProperty -Path $hideFileExtPath -Name HideFileExt -Value 0
+}
+
+# Never Combine taskbar buttons when the taskbar is full
+$taskbarGlomLevelPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
+if (-not (Test-RegistryPropertyExists $taskbarGlomLevelPath "TaskbarGlomLevel")) {
+ Set-ItemProperty -Path $taskbarGlomLevelPath -Name TaskbarGlomLevel -Value 2
+}
+
+# Taskbar small icons
+$taskbarSmallIconsPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"
+if (-not (Test-RegistryPropertyExists $taskbarSmallIconsPath "TaskbarSmallIcons")) {
+ Set-ItemProperty -Path $taskbarSmallIconsPath -Name TaskbarSmallIcons -Value 1
+}
+
+# Set Windows to use UTC time instead of local time for system clock
+$timeZoneInfoPath = "HKLM:\SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
+if (-not (Test-RegistryPropertyExists $timeZoneInfoPath "RealTimeIsUniversal")) {
+ Set-ItemProperty -Path $timeZoneInfoPath -Name RealTimeIsUniversal -Value 1
+}
+
+# Disable the search in taskbar
+$searchBoxTaskbarPath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Search"
+if (-not (Test-RegistryPropertyExists $searchBoxTaskbarPath "SearchBoxTaskbarMode")) {
+ New-ItemProperty -Path $searchBoxTaskbarPath -Name SearchBoxTaskbarMode -Value 0 -Type DWord -Force
+}
+
+# Dark mode:
+$personalizePath = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize"
+if (-not (Test-RegistryPropertyExists $personalizePath "AppsUseLightTheme")) {
+ Set-ItemProperty -Path $personalizePath -Name AppsUseLightTheme -Value 0 -Type Dword -Force
+}
+if (-not (Test-RegistryPropertyExists $personalizePath "SystemUsesLightTheme")) {
+ Set-ItemProperty -Path $personalizePath -Name SystemUsesLightTheme -Value 0 -Type Dword -Force
+}
+
+# Restart explorer so the rest of the settings take effect:
+Stop-Process -f -ProcessName explorer
+Start-Process explorer.exe
+
+# Function to disable the Windows key
+function Disable-WindowsKey {
+ $regPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Keyboard Layout"
+ $regName = "Scancode Map"
+
+ # Binary data to remap the Windows key to F24 (an unused key)
+ $binaryValue = [byte[]](
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x3A, 0x00, 0x5B, 0xE0,
+ 0x00, 0x00, 0x00, 0x00
+ )
+
+ # Create the registry key if it doesn't exist
+ if (-not (Test-RegistryKeyExists $regPath)) {
+ New-Item -Path $regPath -Force | Out-Null
+ }
+
+ # Set the Scancode Map value if it doesn't exist
+ if (-not (Test-RegistryPropertyExists $regPath $regName)) {
+ Set-ItemProperty -Path $regPath -Name $regName -Value $binaryValue
+ }
+
+ Write-Output "Windows key has been disabled from opening the start menu. Please restart your computer for the changes to take effect."
+}
+
+#Disable-WindowsKey
+
+Write-Host "Bootstrap script completed."
+Write-Host "Please Restart."
+
+# Clean up Bootstrap.log
+Write-Host "Clean up Bootstrap.log"
+Stop-Transcript
+$logSuppress = Get-Content $Env:USERPROFILE\Logs\Bootstrap.log | Where-Object { $_ -notmatch "Host Application: powershell.exe" }
+$logSuppress | Set-Content $Env:USERPROFILE\Logs\Bootstrap.log -Force
diff --git a/linux/home/.config/powershell/initialize.ps1 b/linux/home/.config/powershell/initialize.ps1
new file mode 100644
index 0000000..a616998
--- /dev/null
+++ b/linux/home/.config/powershell/initialize.ps1
@@ -0,0 +1,227 @@
+<#
+ .SYNOPSIS
+ Bootstrap Windows command prompts (cmd, PS, PSCore) with my dotfiles and apps.
+
+ .DESCRIPTION
+ To bootstrap directly from GitHub, run these 2 cmdlets in a PowerShell prompt:
+ > Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
+ > irm 'https://raw.githubusercontent.com/srdusr/dotfiles/main/bootstrap.ps1' | iex
+#>
+[CmdletBinding()]
+param (
+ [ValidateSet('clone', 'setup', 'apps', 'env', IgnoreCase = $true)]
+ [Parameter(Position = 0)] [string]
+ $verb = 'clone',
+ [Parameter()] [string]
+ $userName = $null,
+ [Parameter()] [string]
+ $email = $null,
+ [Parameter()] [switch]
+ $runAsAdmin = $false
+)
+
+$ErrorActionPreference = 'Stop'
+
+$originGitHub = 'https://github.com/srdusr/dotfiles.git'
+$dotPath = (Join-Path $env:USERPROFILE '.cfg')
+
+# Ensure Tls12
+[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
+
+function ensureLocalGit {
+ if (Get-Command 'git' -ErrorAction SilentlyContinue) {
+ return
+ }
+
+ $localGitFolder = (Join-Path $env:USERPROFILE (Join-Path "Downloads" "localGit"))
+ Write-Host "Installing ad-hoc git into $localGitFolder..."
+
+ $gitUrl = Invoke-RestMethod 'https://api.github.com/repos/git-for-windows/git/releases/latest' |
+ Select-Object -ExpandProperty 'assets' |
+ Where-Object { $_.name -Match 'MinGit' -and $_.name -Match '64-bit' -and $_.name -notmatch 'busybox' } |
+ Select-Object -ExpandProperty 'browser_download_url'
+ $localGitZip = (Join-Path $localGitFolder "MinGit.zip")
+ New-Item -ItemType Directory -Path $localGitFolder -Force | Out-Null
+ (New-Object Net.WebClient).DownloadFile($gitUrl, $localGitZip)
+ Expand-Archive -Path $localGitZip -DestinationPath $localGitFolder -Force
+
+ $gitPath = (Join-Path $localGitFolder 'cmd')
+ $env:Path += ";$gitPath"
+}
+
+function cloneDotfiles {
+ Write-Host "Cloning $originGitHub -> $dotPath"
+ Write-Host -NoNewline "OK to proceed with setup? [Y/n] "
+ $answer = (Read-Host).ToUpper()
+ if ($answer -ne 'Y' -and $answer -ne '') {
+ Write-Warning "Aborting."
+ return 4
+ }
+
+ ensureLocalGit
+
+ if (-not $userName -or $userName -eq '') {
+ $userName = (& git config --global --get user.name)
+ }
+ if (-not $userName -or $userName -eq '') {
+ $userName = "$env:USERNAME@$env:COMPUTERNAME"
+ }
+
+ if (-not $email -or $email -eq '') {
+ $email = (& git config --global --get user.email)
+ }
+ if (-not $email -or $email -eq '') {
+ $email = Read-Host "Enter your email address for git commits"
+ if ($email -eq '') {
+ Write-Warning "Need email address, aborting."
+ return 3
+ }
+ }
+
+ & git.exe config --global user.name $userName
+ & git.exe config --global user.email $email
+
+
+ function global:config {
+ git --git-dir="$dotPath" --work-tree="$env:USERPROFILE" $args
+ }
+
+ Add-Content -Path "$env:USERPROFILE\.gitignore" -Value ".cfg"
+
+ if (Test-Path -Path $dotfiles_dir) {
+ config pull | Out-Null
+ $update = $true
+ } else {
+ git clone --bare $originGitHub $dotPath | Out-Null
+ $update = $false
+ }
+
+ $std_err_output = config checkout 1>&1
+
+ if ($std_err_output -match "following untracked working tree files would be overwritten") {
+ if (-not $update) {
+ config checkout | Out-Null
+ }
+ }
+ config config --local status.showUntrackedFiles no
+
+ if ($update -or (Read-Host "Do you want to overwrite existing files and continue with the dotfiles setup? [Y/n]" -eq "Y")) {
+ config fetch origin main:main | Out-Null
+ config reset --hard main | Out-Null
+ config checkout -f
+ if ($?) {
+ Write-Host "Successfully imported $dotPath."
+ } else {
+ handle_error "Mission failed."
+ }
+ } else {
+ handle_error "Aborted by user. Exiting..."
+ }
+
+ return 0
+}
+
+function setup {
+ ensureLocalGit
+}
+
+function installApps {
+ ensureLocalGit
+}
+
+function writeGitConfig {
+ param (
+ [Parameter(Mandatory = $true)] [string] $configIniFile
+ )
+
+ if ((Test-Path (Join-Path $env:USERPROFILE '.gitconfig')) -and -not (Test-Path (Join-Path $env:USERPROFILE '.gitconfig.bak'))) {
+ $userName = (& git config --global --get user.name)
+ $email = (& git config --global --get user.email)
+
+ Move-Item -Path (Join-Path $env:USERPROFILE '.gitconfig') -Destination (Join-Path $env:USERPROFILE '.gitconfig.bak')
+
+ if ($userName -and $userName -ne '') {
+ & git.exe config --global user.name $userName
+ }
+ if ($email -and $email -ne '') {
+ & git.exe config --global user.email $email
+ }
+ }
+
+ Get-Content $configIniFile | ForEach-Object {
+ if ($_.TrimStart().StartsWith('#')) { return }
+ $key, $value = $_.Split('=', 2)
+ Write-Verbose "git config --global $key $value"
+ & git.exe config --global $key "$value"
+ }
+}
+
+function setupShellEnvs {
+ Write-Host "Setting cmd console properties:"
+ $consolePath = 'HKCU\Console'
+ & reg add $consolePath /v QuickEdit /d 0x1 /t REG_DWORD /f | Out-Null
+ & reg add $consolePath /v WindowSize /d 0x00320078 /t REG_DWORD /f | Out-Null
+ & reg add $consolePath /v ScreenBufferSize /d 0x23280078 /t REG_DWORD /f | Out-Null
+ & reg add $consolePath /v FontFamily /d 0x36 /t REG_DWORD /f | Out-Null
+ & reg add $consolePath /v HistoryBufferSize /d 0x64 /t REG_DWORD /f | Out-Null
+ & reg add $consolePath /v FaceName /d "Hack Nerd Font Mono" /t REG_SZ /f | Out-Null
+ & reg add $consolePath /v FontSize /d 0x00100000 /t REG_DWORD /f | Out-Null
+
+ $win32rc = (Join-Path $PSScriptRoot (Join-Path 'win' 'win32-rc.cmd'))
+ Write-Host "Setting up cmd autorun: $win32rc"
+ & reg add "HKCU\Software\Microsoft\Command Processor" /v AutoRun /t REG_SZ /d $win32rc /f | Out-Null
+
+ Write-Host "Configuring user home dir..."
+ $configDir = (Join-Path $env:USERPROFILE '.config')
+ New-Item -ItemType Directory -Path $configDir -ErrorAction SilentlyContinue | Out-Null
+
+ $sshDir = (Join-Path $env:USERPROFILE '.ssh')
+ Remove-Item (Join-Path $sshDir 'config') -ErrorAction SilentlyContinue -Force | Out-Null
+ $openSsh = ((Join-Path $env:windir 'System32\OpenSSH\ssh.exe').Replace("\", "/"))
+ & git config --global core.sshCommand $openSsh
+}
+
+function main {
+ param (
+ [Parameter(Mandatory = $true)] [string] $verbAction
+ )
+
+ Write-Verbose "PS: $($PSVersionTable.PSVersion)-$($PSVersionTable.PSEdition)"
+ switch ($verbAction) {
+ 'clone' {
+ Write-Host
+ if (Test-Path (Join-Path $dotPath '.git')) {
+ Write-Host "Local git repo already exists, skipping."
+ main setup
+ return
+ }
+
+ $rc = cloneDotfiles
+ if ($rc -ne 0) {
+ Write-Error "Cloning dotfiles failed, aborting."
+ return
+ }
+
+ $script = (Join-Path $dotPath '.config\powershell\bootstrap.ps1')
+ Write-Host "Continue $script in child process"
+ Start-Process -PassThru -NoNewWindow -FilePath "powershell.exe" -ArgumentList "-NoProfile -File $script setup" | Wait-Process
+ }
+
+ 'setup' {
+ Write-Host "Setting up..."
+ setup
+ installApps
+ setupShellEnvs
+ Write-Host "Done (setup)."
+ exit
+ }
+
+ 'apps' { installApps }
+
+ 'env' { setupShellEnvs }
+ }
+
+ Write-Host "Done."
+}
+
+main $verb
diff --git a/linux/home/.config/pypoetry/config.toml b/linux/home/.config/pypoetry/config.toml
new file mode 100644
index 0000000..53b35d3
--- /dev/null
+++ b/linux/home/.config/pypoetry/config.toml
@@ -0,0 +1,3 @@
+[virtualenvs]
+create = true
+in-project = true
diff --git a/linux/home/.config/rofi/Notif.rasi b/linux/home/.config/rofi/Notif.rasi
new file mode 100644
index 0000000..47bc1af
--- /dev/null
+++ b/linux/home/.config/rofi/Notif.rasi
@@ -0,0 +1,153 @@
+configuration {
+ display-drun: " Apps";
+ display-window: "缾 Windows";
+ show-icons:true;
+ font: "Fira Code 10";
+}
+
+* {
+ background-color: #fffff7;
+ bg: #fffff7;
+ text-color: #927f70;
+ selbg: #927f70;
+ actbg: #eee8da;
+ urgbg: #eee8da;
+ winbg: #eee8da;
+
+ selected-normal-foreground: @text-color;
+ normal-foreground: @text-color;
+ selected-normal-background: @actbg;
+ normal-background: @background-color;
+
+ selected-urgent-foreground: @urgbg;
+ urgent-foreground: @text-color;
+ selected-urgent-background: @actbg;
+ urgent-background: @background-color;
+ urgent-foreground: @urgbg;
+
+ selected-active-foreground: @selbg;
+ active-foreground: @selbg;
+ selected-active-background: @actbg;
+ active-background: @background-color;
+
+ line-margin: 2;
+ line-padding: 2;
+ separator-style: "none";
+ hide-scrollbar: "true";
+ margin: 0;
+ padding: 5;
+}
+
+window {
+ location: northeast;
+ anchor: northeast;
+ //height: 40%;
+ y-offset: 60px;
+ x-offset: -20px;
+ width: 16%;
+ orientation: horizontal;
+ children: [mainbox];
+ border: 2px solid;
+ border-radius: 10px;
+ border-color: #eee8da;
+}
+
+mainbox {
+ spacing: 0.8em;
+ orientation: vertical;
+ children: [ inputbar, listview ];
+}
+
+button { padding: 2px 2px; }
+
+button selected {
+ background-color: @active-background;
+ text-color: @background-color;
+}
+
+inputbar {
+ padding: 2px;
+ spacing: 5px;
+}
+
+listview {
+ spacing: 0.5em;
+ dynamic: true;
+ cycle: false;
+}
+
+element {
+ padding: 10px;
+}
+
+prompt {
+ padding: 10px 0px 0px 20px;
+ font: "Fira Code 10";
+}
+
+entry {
+ expand: true;
+ text-color: @normal-foreground;
+ vertical-align: 0;
+ padding: 5px 0px 0px 20px;
+ enabled: false;
+}
+
+element normal.normal {
+ background-color: @bg;
+ border-radius: 8px;
+ text-color: @normal-foreground;
+}
+
+element normal.urgent {
+ background-color: @bg;
+ border-radius: 8px;
+ text-color: @urgent-foreground;
+}
+
+element normal.active {
+ background-color: @bg;
+ border-radius: 8px;
+ text-color: @active-foreground;
+}
+
+element selected.normal {
+ background-color: @selected-normal-background;
+ text-color: @selected-normal-foreground;
+}
+
+element selected.urgent {
+ background-color: @selected-urgent-background;
+ text-color: @selected-urgent-foreground;
+}
+
+element selected.active {
+ background-color: @selected-active-background;
+ text-color: @selected-active-foreground;
+}
+
+element alternate.normal {
+ background-color: @bg;
+ border-radius: 8px;
+ text-color: @normal-foreground;
+}
+
+element alternate.urgent {
+ background-color: @bg;
+ border-radius: 8px;
+ text-color: @urgent-foreground;
+}
+
+element alternate.active {
+ background-color: @bg;
+ border-radius: 8px;
+ text-color: @active-foreground;
+}
+element-icon {
+ size: 7ch;
+}
+element.selected {
+ border-radius: 8px;
+ border: 0 0 0 5px solid;
+ border-color: @winbg;
+}
diff --git a/linux/home/.config/rofi/colors/gruvbox.rasi b/linux/home/.config/rofi/colors/gruvbox.rasi
new file mode 100644
index 0000000..f5c9169
--- /dev/null
+++ b/linux/home/.config/rofi/colors/gruvbox.rasi
@@ -0,0 +1,10 @@
+/* colors */
+
+* {
+ al: #00000000;
+ bg: #32302f;
+ pg: #7c6f64;
+ se: #101010ff;
+ fg: #FFFFFFff;
+ ac: #fe8019;
+}
diff --git a/linux/home/.config/rofi/colors/nord.rasi b/linux/home/.config/rofi/colors/nord.rasi
new file mode 100644
index 0000000..2e72da1
--- /dev/null
+++ b/linux/home/.config/rofi/colors/nord.rasi
@@ -0,0 +1,10 @@
+/* colors */
+
+* {
+ al: #00000000;
+ bg: #2e3440;
+ pg: #4c566a;
+ se: #101010ff;
+ fg: #FFFFFFff;
+ ac: #88c0d0;
+}
diff --git a/linux/home/.config/rofi/colors/simple.rasi b/linux/home/.config/rofi/colors/simple.rasi
new file mode 100644
index 0000000..31f260e
--- /dev/null
+++ b/linux/home/.config/rofi/colors/simple.rasi
@@ -0,0 +1,10 @@
+/* colors */
+
+* {
+ al: #00000000;
+ bg: #2c2f31;
+ pg: #666666;
+ se: #6cb6eb;
+ fg: #FFFFFFff;
+ ac: #3b4041;
+}
diff --git a/linux/home/.config/rofi/config.rasi b/linux/home/.config/rofi/config.rasi
new file mode 100644
index 0000000..dfe7afd
--- /dev/null
+++ b/linux/home/.config/rofi/config.rasi
@@ -0,0 +1,178 @@
+configuration {
+ bw: 0;
+ columns: 1;
+ location: 0;
+ lines: 5;
+ padding: 0;
+ fixed-num-lines: true;
+ show-icons: true;
+ sidebar-mode: false;
+ separator-style: "beam";
+ hide-scrollbar: false;
+ scroll-method: 0;
+ click-to-exit: true;
+ show-match: true;
+ combi-hide-mode-prefix: false;
+ display-combi: "Combi";
+ display-drun: "Start";
+ display-window: "Window";
+ display-windowcd: "Windowcd";
+ display-run: "Commands";
+ display-ssh: "Ssh";
+ modi: "drun,window,run,ssh,";
+ opacity: "0";
+ fake-transparency: false;
+ kb-row-up: "Up,Control+k,Shift+Tab,Shift+ISO_Left_Tab";
+ kb-row-down: "Down,Control+j";
+ kb-accept-entry: "Control+m,Return,KP_Enter";
+ me-select-entry: "";
+ me-accept-entry: "MousePrimary";
+ terminal: "kitty";
+ kb-remove-to-eol: "Control+Shift+e";
+ kb-mode-next: "Shift+Right,Control+Tab,Control+l";
+ kb-mode-previous: "Shift+Left,Control+Shift+Tab,Control+h";
+ kb-remove-char-back: "BackSpace";
+ kb-mode-complete: "Control+c";
+}
+
+* {
+ background-color: @background;
+ font: "Source Code Pro Semibold 9";
+ spacing: 2;
+}
+
+#window {
+ background-color: @background;
+ border: 3;
+ border-color: @cyber;
+ padding: 0.5ch;
+}
+
+#mainbox {
+ border: 0;
+ border-color: @ac;
+ padding: 0;
+}
+
+#message {
+ border: 0px 0px 0px;
+ border-color: @ac;
+ padding: 1px;
+}
+
+#textbox {
+ text-color: @foreground;
+}
+
+#inputbar {
+ children: [ prompt,textbox-prompt-colon,entry,case-indicator ];
+}
+
+#textbox-prompt-colon {
+ expand: false;
+ str: ":";
+ margin: 0px 0.3em 0em 0em;
+ text-color: inherit;
+}
+
+#listview {
+ fixed-height: 0;
+ border: 0px 0px 0px;
+ border-color: @ac;
+ spacing: 2px;
+ scrollbar: true;
+ padding: 2px 0px 0px;
+}
+
+#element {
+ border: 0;
+ padding: 1px;
+}
+
+#element.normal.normal {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.normal.urgent {
+ background-color: @background;
+ text-color: @red;
+}
+
+#element.normal.active {
+ background-color: @foreground;
+ text-color: @background;
+}
+
+#element.selected.normal {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.selected.urgent {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.selected.active {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.alternate.normal {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.alternate.urgent {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.alternate.active {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#scrollbar {
+ width: 0px;
+ border: 0;
+ handle-width: 0px;
+ padding: 0;
+}
+
+#sidebar {
+ border: 2px 0px 0px;
+ border-color: @ac;
+}
+
+#button {
+ text-color: @background;
+}
+
+#button.selected {
+ background-color: @ac;
+ text-color: @foreground;
+}
+
+#inputbar {
+ spacing: 0;
+ text-color: @foreground;
+ padding: 1px;
+}
+
+#case-indicator {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+#entry {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+#prompt {
+ spacing: 0;
+ text-color: @foreground;
+}
+@import "~/.config/rofi/themes/colors.rasi"
diff --git a/linux/home/.config/rofi/options_menu.rasi b/linux/home/.config/rofi/options_menu.rasi
new file mode 100644
index 0000000..173da88
--- /dev/null
+++ b/linux/home/.config/rofi/options_menu.rasi
@@ -0,0 +1,71 @@
+configuration {
+ show-icons: false;
+ font: "Font Awesome 17";
+}
+
+window {
+ height: 300;
+ width: 300;
+ location: northeast;
+ anchor: northeast;
+ x-offset: -10;
+ y-offset: 10;
+ transparency: "real";
+ background-color: #00000000;
+ border: 4px 4px solid 4px 4px;
+ border-radius: 8;
+ border-color: @primary;
+}
+
+mainbox {
+ children: [message, listview];
+ padding: 0px 0px;
+}
+
+
+textbox {
+ horizontal-align: 0.5;
+ border: 0px 0px 2px;
+ border-color: @primary;
+ margin: 12px;
+ padding: 12px;
+}
+
+listview {
+ padding: 8px 32px;
+}
+
+element {
+ padding: 8px;
+ orientation: horizontal;
+}
+
+element normal.urgent, element alternate.urgent {
+ background-color: @urgent;
+}
+
+element normal.active, element alternate.active {
+ background-color: @background-alt;
+ border: 4px 4px solid 4px 4px;
+ border-radius: 8;
+ border-color: transparent;
+}
+
+element selected {
+ border: 4px 4px solid 4px 4px;
+ border-radius: 8;
+ border-color: @primary;
+}
+
+element selected.urgent {
+ background-color: @urgent;
+}
+
+element selected.active {
+ background-color: @background-alt;
+}
+
+element-text {
+ horizontal-align: 0;
+ padding: 0px 8px;
+}
diff --git a/linux/home/.config/rofi/rofi-network-manager.conf b/linux/home/.config/rofi/rofi-network-manager.conf
new file mode 100644
index 0000000..e182dc1
--- /dev/null
+++ b/linux/home/.config/rofi/rofi-network-manager.conf
@@ -0,0 +1,41 @@
+# Location
+# +---------- +
+# | 1 | 2 | 3 |
+# | 8 | 0 | 4 |
+# | 7 | 6 | 5 |
+# +-----------+
+#The grid represents the screen with the numbers indicating the location of the window.
+#If you want the window to be in the upper right corner, set location to 3.
+LOCATION=3
+#This sets the anchor point for the window displaying the QR code.
+QRCODE_LOCATION=$LOCATION
+#X, Y Offset
+#This sets the distance of the window from the edge of the screen on the X and Y axis.
+Y_AXIS=35
+X_AXIS=-10
+#X_AXIS=-315
+#Use notifications or not
+#Values can be "true" or "false"
+NOTIFICATIONS="false"
+#Location of qrcode wifi image
+QRCODE_DIR="/tmp/"
+#WIDTH_FIX_MAIN/WIDTH_FIX_STATUS
+#These values can be adjusted if the text doesn't fit or
+#if there is too much space at the end when you launch the script.
+#It will depend on the font type and size.
+WIDTH_FIX_MAIN=1
+WIDTH_FIX_STATUS=10
+#Values can be "true" or "false"
+#Set it to true, if the script outputs the signal strength with asterisks
+#and you want bars.
+ASCII_OUT=false
+#Values can be "true" or "false"
+#Set it to true if you want to use custom icons
+#for the signal strength instead of the default ones.
+CHANGE_BARS=false
+#Custom signal strength indicators
+SIGNAL_STRENGTH_0="0"
+SIGNAL_STRENGTH_1="1"
+SIGNAL_STRENGTH_2="12"
+SIGNAL_STRENGTH_3="123"
+SIGNAL_STRENGTH_4="1234"
diff --git a/linux/home/.config/rofi/rofi-network-manager.rasi b/linux/home/.config/rofi/rofi-network-manager.rasi
new file mode 100644
index 0000000..7e2da9b
--- /dev/null
+++ b/linux/home/.config/rofi/rofi-network-manager.rasi
@@ -0,0 +1,127 @@
+configuration {
+ show-icons: false;
+ sidebar-mode: false;
+ hover-select: true;
+ me-select-entry: "";
+ me-accept-entry: [MousePrimary];
+}
+*{
+ font: "DejaVu Sans Mono 9"; //Font
+ //Colors
+ foreground:#f8f8f2; //Text
+ background:#0A1229; //Background
+ accent:#00BCD4; //Highlight
+ foreground-selection:@foreground; //Selection_fg
+ background-selection:#e34039; //Selection_bg
+
+ transparent: #ffffff00;
+ background-color: @transparent;
+ text-color: @foreground;
+ selected-normal-foreground: @foreground-selection;
+ normal-foreground: @foreground;
+ alternate-normal-background: @transparent;
+ selected-urgent-foreground: @foreground;
+ urgent-foreground: @foreground;
+ alternate-urgent-background: @background;
+ active-foreground: @accent;
+ selected-active-foreground: @background-selection;
+ alternate-normal-foreground: @foreground;
+ alternate-active-background: @background;
+ bordercolor: @background;
+ normal-background: @transparent;
+ selected-normal-background: @background-selection;
+ separatorcolor: @accent;
+ urgent-background: @accent;
+ alternate-urgent-foreground: @foreground;
+ selected-urgent-background: @accent;
+ alternate-active-foreground: @foreground;
+ selected-active-background: @transparent;
+ active-background: @transparent;
+}
+window {
+ text-color: @foreground;
+ background-color: @background;
+ border-radius: 6px;
+ padding: 10;
+}
+mainbox {
+ border: 0;
+ padding: 0;
+}
+textbox {
+ text-color: @foreground;
+}
+listview {
+ spacing: 4px;
+ dynamic: true;
+ fixed-height: false;
+ border: 0;
+ scrollbar: false;
+ text-color: @separatorcolor;
+}
+element {
+ border: 0;
+ padding: 0;
+ border-radius: 4px;
+}
+element-text {
+ background-color: inherit;
+ text-color: inherit;
+}
+element.normal.normal {
+ text-color: @normal-foreground;
+ background-color: @normal-background;
+}
+element.normal.urgent {
+ text-color: @urgent-foreground;
+ background-color: @urgent-background;
+}
+element.normal.active {
+ text-color: @active-foreground;
+ background-color: @active-background;
+}
+element.selected.normal {
+ text-color: @selected-normal-foreground;
+ background-color: @selected-normal-background;
+}
+element.selected.urgent {
+ text-color: @selected-urgent-foreground;
+ background-color: @selected-urgent-background;
+}
+element.selected.active {
+ text-color: @selected-active-foreground;
+ background-color: @selected-active-background;
+}
+element.alternate.normal {
+ text-color: @alternate-normal-foreground;
+ background-color: @alternate-normal-background;
+}
+element.alternate.urgent {
+ text-color: @alternate-urgent-foreground;
+ background-color: @alternate-urgent-background;
+}
+element.alternate.active {
+ text-color: @alternate-active-foreground;
+ background-color: @alternate-active-background;
+}
+mode-switcher {
+ border: 0;
+}
+button selected {
+ text-color: @selected-normal-foreground;
+ background-color: @selected-normal-background;
+}
+button normal {
+ text-color: @foreground;
+}
+inputbar {
+ children: [textbox-prompt-colon,entry];
+}
+textbox-prompt-colon{
+ expand: false;
+ margin: 0;
+ str: ":";
+}
+entry {
+ placeholder: "";
+}
diff --git a/linux/home/.config/rofi/styles/appmenu.rasi b/linux/home/.config/rofi/styles/appmenu.rasi
new file mode 100644
index 0000000..83445be
--- /dev/null
+++ b/linux/home/.config/rofi/styles/appmenu.rasi
@@ -0,0 +1,186 @@
+configuration {
+ bw: 0;
+ columns: 1;
+ location: 0;
+ lines: 15;
+ padding: 0;
+ fixed-num-lines: true;
+ show-icons: true;
+ sidebar-mode: false;
+ separator-style: "beam";
+ hide-scrollbar: false;
+ scroll-method: 0;
+ click-to-exit: true;
+ show-match: true;
+ combi-hide-mode-prefix: false;
+ display-combi: "Combi";
+ display-drun: "Start";
+ display-window: "Window";
+ display-windowcd: "Windowcd";
+ display-run: "Commands";
+ display-ssh: "Ssh";
+ modi: "drun,window,run,ssh,";
+ opacity: "0";
+ fake-transparency: false;
+ kb-row-up: "Up,Control+k,Shift+Tab,Shift+ISO_Left_Tab";
+ kb-row-down: "Down,Control+j";
+ kb-accept-entry: "Control+m,Return,KP_Enter";
+ me-select-entry: "";
+ me-accept-entry: "MousePrimary";
+ terminal: "kitty";
+ kb-remove-to-eol: "Control+Shift+e";
+ kb-mode-next: "Shift+Right,Control+Tab,Control+l";
+ kb-mode-previous: "Shift+Left,Control+Shift+Tab,Control+h";
+ kb-remove-char-back: "BackSpace";
+ kb-mode-complete: "Control+c";
+}
+
+* {
+ padding: 0;
+ hide-scrollbar: true;
+ border: 0;
+ width: 15%;
+ columns: 1;
+ background-color: @background;
+ font: "Source Code Pro Semibold 9";
+ spacing: 2;
+}
+
+#window {
+ background-color: @background;
+ border: 3;
+ border-color: @cyber;
+ padding: 0.5ch;
+ location: northwest;
+ margin: 28px 0 0 8px;
+}
+
+#mainbox {
+ border: 0;
+ border-color: @ac;
+ padding: 0;
+}
+
+#message {
+ border: 0px 0px 0px;
+ border-color: @ac;
+ padding: 1px;
+}
+
+#textbox {
+ text-color: @foreground;
+}
+
+#inputbar {
+ children: [ prompt, textbox-prompt-colon, entry, case-indicator ];
+}
+
+#textbox-prompt-colon {
+ expand: false;
+ str: ":";
+ margin: 0px 0.3em 0em 0em;
+ text-color: inherit;
+}
+
+#listview {
+ fixed-height: 0;
+ border: 0px 0px 0px;
+ border-color: @ac;
+ spacing: 2px;
+ scrollbar: true;
+ padding: 2px 0px 0px;
+}
+
+#element {
+ border: 0;
+ padding: 1px;
+}
+
+#element.normal.normal {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.normal.urgent {
+ background-color: @background;
+ text-color: @red;
+}
+
+#element.normal.active {
+ background-color: @foreground;
+ text-color: @background;
+}
+
+#element.selected.normal {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.selected.urgent {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.selected.active {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.alternate.normal {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.alternate.urgent {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.alternate.active {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#scrollbar {
+ width: 0px;
+ border: 0;
+ handle-width: 0px;
+ padding: 0;
+}
+
+#sidebar {
+ border: 2px 0px 0px;
+ border-color: @ac;
+}
+
+#button {
+ text-color: @background;
+}
+
+#button.selected {
+ background-color: @ac;
+ text-color: @foreground;
+}
+
+#inputbar {
+ spacing: 0;
+ text-color: @foreground;
+ padding: 1px;
+}
+
+#case-indicator {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+#entry {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+#prompt {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+@import "~/.config/rofi/themes/colors.rasi"
diff --git a/linux/home/.config/rofi/styles/powermenu.rasi b/linux/home/.config/rofi/styles/powermenu.rasi
new file mode 100644
index 0000000..1b7219d
--- /dev/null
+++ b/linux/home/.config/rofi/styles/powermenu.rasi
@@ -0,0 +1,187 @@
+configuration {
+ bw: 0;
+ columns: 1;
+ location: 0;
+ lines: 5;
+ padding: 0;
+ fixed-num-lines: true;
+ show-icons: true;
+ sidebar-mode: false;
+ separator-style: "beam";
+ hide-scrollbar: false;
+ scroll-method: 0;
+ click-to-exit: true;
+ show-match: true;
+ combi-hide-mode-prefix: false;
+ display-combi: "Combi";
+ display-drun: "Start";
+ display-window: "Window";
+ display-windowcd: "Windowcd";
+ display-run: "Commands";
+ display-ssh: "Ssh";
+ modi: "drun,window,run,ssh,";
+ opacity: "0";
+ fake-transparency: false;
+ kb-row-up: "Up,Control+k,Shift+Tab,Shift+ISO_Left_Tab";
+ kb-row-down: "Down,Control+j";
+ kb-accept-entry: "Control+m,Return,KP_Enter";
+ me-select-entry: "";
+ me-accept-entry: "MousePrimary";
+ terminal: "kitty";
+ kb-remove-to-eol: "Control+Shift+e";
+ kb-mode-next: "Shift+Right,Control+Tab,Control+l";
+ kb-mode-previous: "Shift+Left,Control+Shift+Tab,Control+h";
+ kb-remove-char-back: "BackSpace";
+ kb-mode-complete: "Control+c";
+}
+
+* {
+ lines: 5;
+ padding: 0;
+ hide-scrollbar: true;
+ border: 0;
+ width: 15%;
+ columns: 1;
+ background-color: @background;
+ font: "Source Code Pro Semibold 9";
+ spacing: 2;
+}
+
+#window {
+ background-color: @background;
+ border: 3;
+ border-color: @cyber;
+ padding: 0.5ch;
+ location: northeast;
+ margin: 28px 8px 0 0; /* Adjust these values for spacing and positioning */
+}
+
+#mainbox {
+ border: 0;
+ border-color: @ac;
+ padding: 0;
+}
+
+#message {
+ border: 0px 0px 0px;
+ border-color: @ac;
+ padding: 1px;
+}
+
+#textbox {
+ text-color: @foreground;
+}
+
+#inputbar {
+ children: [ prompt, textbox-prompt-colon, entry, case-indicator ];
+}
+
+#textbox-prompt-colon {
+ expand: false;
+ str: ":";
+ margin: 0px 0.3em 0em 0em;
+ text-color: inherit;
+}
+
+#listview {
+ fixed-height: 0;
+ border: 0px 0px 0px;
+ border-color: @ac;
+ spacing: 2px;
+ scrollbar: true;
+ padding: 2px 0px 0px;
+}
+
+#element {
+ border: 0;
+ padding: 1px;
+}
+
+#element.normal.normal {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.normal.urgent {
+ background-color: @background;
+ text-color: @red;
+}
+
+#element.normal.active {
+ background-color: @foreground;
+ text-color: @background;
+}
+
+#element.selected.normal {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.selected.urgent {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.selected.active {
+ background-color: @foreground;
+ text-color: @black;
+}
+
+#element.alternate.normal {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.alternate.urgent {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#element.alternate.active {
+ background-color: @background;
+ text-color: @foreground;
+}
+
+#scrollbar {
+ width: 0px;
+ border: 0;
+ handle-width: 0px;
+ padding: 0;
+}
+
+#sidebar {
+ border: 2px 0px 0px;
+ border-color: @ac;
+}
+
+#button {
+ text-color: @background;
+}
+
+#button.selected {
+ background-color: @ac;
+ text-color: @foreground;
+}
+
+#inputbar {
+ spacing: 0;
+ text-color: @foreground;
+ padding: 1px;
+}
+
+#case-indicator {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+#entry {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+#prompt {
+ spacing: 0;
+ text-color: @foreground;
+}
+
+@import "~/.config/rofi/themes/colors.rasi"
diff --git a/linux/home/.config/rofi/themes/colors.rasi b/linux/home/.config/rofi/themes/colors.rasi
new file mode 100644
index 0000000..d1419e4
--- /dev/null
+++ b/linux/home/.config/rofi/themes/colors.rasi
@@ -0,0 +1,18 @@
+/* colors */
+
+* {
+ alternative: #00101212;
+ background: #101010ff;
+ seperator: #00101212;
+ foreground: #FAFAFA;
+ ac: #00000000;
+ red: #CECCC9;
+ green: #CECCC9;
+ yellow: #CECCC9;
+ blue: #CECCC9;
+ purple: #CECCC9;
+ cyan: #CECCC9;
+ black: #101212;
+ cyber: #53E2AE;
+ orange: #fe8019;
+}
diff --git a/linux/home/.config/rofi/themes/dmenu.rasi b/linux/home/.config/rofi/themes/dmenu.rasi
new file mode 100644
index 0000000..1e8f319
--- /dev/null
+++ b/linux/home/.config/rofi/themes/dmenu.rasi
@@ -0,0 +1,38 @@
+
+* {
+ background-color: #1a2026;
+ border-color: #29343d;
+ text-color: #ffffff;
+ font: "Fira Code Nerd Font Mono 11";
+}
+
+window {
+ anchor: north;
+ location: north;
+ width: 100%;
+ padding: 4px;
+ children: [ horibox ];
+}
+
+horibox {
+ orientation: horizontal;
+ children: [ prompt, entry, listview ];
+}
+
+listview {
+ layout: horizontal;
+ spacing: 10px;
+ lines: 100;
+}
+
+entry {
+ expand: false;
+ width: 14em;
+}
+
+element {
+ padding: 2px 5px;
+}
+element selected {
+ color: #a9bcef;
+}
diff --git a/linux/home/.config/rofi/themes/power.rasi b/linux/home/.config/rofi/themes/power.rasi
new file mode 100644
index 0000000..209a9ac
--- /dev/null
+++ b/linux/home/.config/rofi/themes/power.rasi
@@ -0,0 +1,34 @@
+/**
+ * This theme is intended for a 5 items wide menu
+ * on a 1366x768 pixels resolution.
+ */
+@import "colors.rasi"
+#window {
+ width: 1366px;
+ height: 768px;
+ /* vertical horizontal */
+ padding: 270px 88px;
+ children: [ horibox ];
+}
+#horibox {
+ children: [ listview ];
+}
+#listview {
+ layout: horizontal;
+ spacing: 56px;
+ lines: 5;
+}
+#element {
+ /**
+ * Values bellow are 'no-padding' ones, to which we add 70
+ * top right bottom left
+ * -14px 0px -14px -93px */
+ padding: 56px 70px 56px -23px;
+ background-color: @background-light;
+}
+#element.selected {
+ background-color: @accent;
+ text-color: @background;
+}
+
+
diff --git a/linux/home/.config/sxhkd/show_help.sh b/linux/home/.config/sxhkd/show_help.sh
new file mode 100755
index 0000000..bd0cd6c
--- /dev/null
+++ b/linux/home/.config/sxhkd/show_help.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+cat ~/.config/sxhkd/sxhkdrc | awk '/^[a-z]/ && last {print $0,"\t",last} {last=""} /^#/{last=$0}' | column -t -s $'\t' | rofi -dmenu -i -no-show-icons -width 1000
+
diff --git a/linux/home/.config/sxhkd/sxhkdrc b/linux/home/.config/sxhkd/sxhkdrc
new file mode 100755
index 0000000..1b276c7
--- /dev/null
+++ b/linux/home/.config/sxhkd/sxhkdrc
@@ -0,0 +1,490 @@
+#################################################
+# ███████╗██╗ ██╗██╗ ██╗██╗ ██╗██████╗ #
+# ██╔════╝╚██╗██╔╝██║ ██║██║ ██╔╝██╔══██╗ #
+# ███████╗ ╚███╔╝ ███████║█████╔╝ ██║ ██║ #
+# ╚════██║ ██╔██╗ ██╔══██║██╔═██╗ ██║ ██║ #
+# ███████║██╔╝ ██╗██║ ██║██║ ██╗██████╔╝ #
+# ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ #
+#################################################
+
+#---------------------------------------------------------------
+#
+# WM independent hotkeys
+#
+
+# Help
+super + slash
+ ~/.config/sxhkd/show_help.sh -m -3
+
+# Application menu
+super + a
+ ~/.config/polybar/scripts/menu.sh
+
+# Shutdown menu
+#super + alt + Delete
+# ~/.config/polybar/scripts/sysmenu.sh
+
+# lockscreen
+super + Escape
+ betterlockscreen -l
+
+# Program launcher
+super + @space
+ rofi -show drun
+
+# Run launcher (commands)
+super + r
+ rofi -show run
+
+# Task switcher
+alt + Tab
+ rofi -show window
+
+# Turn off compositor
+super + shift + p
+ toggleprogram "picom" "--experimental-backends"
+
+#picom-trans -c -10
+#picom-trans -c +10
+
+# Close all active notifications.
+# ~button1
+# bspc query -D -d .focused.!occupied && $HOME/.local/bin/eww update noti=false; sleep 0.270; $HOME/.local/bin/eww close notification-popup; pkill openEwwPopup.sh
+
+# Toggle control center using middle click.
+~button2
+ xqp 0 $(xdo id -N Bspwm -n root) && sh $HOME/.config/jgmenu/scripts/windows.sh
+#bspc query -D -d .focused.!occupied && sh $HOME/.config/eww/scripts/openControlCenter.sh
+
+# Right click menu
+~button3
+ xqp 0 $(xdo id -N Bspwm -n root) && sh $HOME/.config/jgmenu/scripts/jgmenu.sh
+
+# Toggle control center.
+super + shift + c
+ sh $HOME/.config/eww/scripts/openControlCenter.sh
+
+# Toggle notification center.
+super + shift + n
+ sh $HOME/.config/eww/scripts/openNotificationCenter.sh
+
+## Toggle info center.
+#super + shift + i
+# sh $HOME/.config/eww/scripts/openInfoCenter.sh
+#
+## Toggle color picker.
+#super + shift + x
+# sh $HOME/.local/bin/xcolor-pick
+#
+## Toggle bar.
+#super + shift + b
+# sh $HOME/.local/bin/tglbar
+#
+## Toggle exit screen.
+#super + Escape
+# sh $HOME/.config/eww/scripts/openExitScreen.sh
+#
+## Close exit screen when it's enabled.
+#~Escape
+# [[ -f "$HOME/.cache/eww-escreen.lock" ]] && sh $HOME/.config/eww/scripts/openExitScreen.sh
+
+## Open web browser, and file manager.
+#super + shift + {w,f}
+# {firefox-developer-edition,thunar}
+
+# Terminal emulator
+#super + Return
+# $TERMINAL
+
+# Browser
+super + w
+ $BROWSER
+
+# Keyboard
+super + o
+ onboard
+
+# Show clipmenu
+#alt + x
+# parcellite
+ #~/.scripts/clip.sh
+
+# Screenshots tool (selection)
+ctrl + Print
+ screenshot crop
+
+# Screenshots tool (screen)
+shift + Print
+ screenshot full
+
+# make sxhkd reload its configuration files:
+super + ctrl + x
+ pkill -USR1 -x sxhkd; dunstify "Sxhkd configuration reloaded"
+
+# Kill window
+ctrl + alt + Escape
+ xkill
+
+# Un/mount drives
+ctrl + alt + {m,u}
+ {_,u}mnt
+
+
+#---------------------------------------------------------------
+#
+# bspwm hotkeys
+#
+
+# Quit/restart bspwm
+super + alt + shift + {q,r}
+ bspc {quit,wm -r}
+
+# Close and kill
+super + d
+ bspc node -c
+
+# Alternate between the tiled and monocle layout
+super + m
+ bspc desktop -l next
+super + z
+ bspc desktop -l next
+
+# Send the newest marked node to the newest preselected node
+super + y
+ bspc node newest.marked.local -n newest.!automatic.local
+
+# Swap the current node and the biggest window
+super + g
+ bspc node -s biggest.window
+
+
+#---------------------------------------------------------------
+#
+# state/flags
+#
+
+# Set the window state
+#super + {t,shift + t,s,f}
+# bspc node -t {tiled,pseudo_tiled,floating,fullscreen}
+
+# Floating into monocle layout
+super + shift + m
+ bspc node -t pseudo_tiled; bspc node -t floating && wtp 10 36 $(($(bspc query -T -m | jq '.rectangle.width') * 98 / 100)) $(($(($(bspc query -T -m | jq '.rectangle.height') - $(bspc config top_padding))) * 96 / 100)) "$(pfw)"
+
+# Floating window pane left
+super + shift + h
+ bspc node -t pseudo_tiled; bspc node -t floating && wtp 10 36 $(($(($(bspc query -T -m | jq '.rectangle.width') / 2)) - 5)) $(($(($(bspc query -T -m | jq '.rectangle.height') - $(bspc config top_padding))) * 96 / 100)) "$(pfw)"
+
+# Floating window pane right
+super + shift + l
+ bspc node -t pseudo_tiled && bspc node -t floating && wtp $(($(bspc query -T -m | jq '.rectangle.width') - $(($(bspc query -T -m | jq '.rectangle.width') / 2)))) 36 $(($(($(bspc query -T -m | jq '.rectangle.width') / 2)) - 15)) $(($(($(bspc query -T -m | jq '.rectangle.height') - $(bspc config top_padding))) * 96 / 100)) "$(pfw)"
+
+# Set the window state
+super + {t,shift + t,s}
+ bspc node -t {tiled,pseudo_tiled,floating}; \
+ xdo raise -N Plank; \
+ xdo raise -N '*:*:Picture in picture'; \
+ xdo raise -N "Picture-in-Picture"
+
+# Toggle fullscreen
+super + {f}
+ bspc node -t \~fullscreen
+
+# Toggle sticky
+#super + q
+# bspc node -g sticky=on
+
+# Set the node flags
+super + ctrl + {m,x,y,z}
+ bspc node -g {marked,locked,sticky,private}
+
+# Move layers of windows above/below each other (script)
+super + {equal,minus}
+ layer.sh {+,-}
+
+
+#---------------------------------------------------------------
+#
+# Focus/Swap
+#
+
+# Focus the node in the given direction
+super + {_,shift + }{h,j,k,l}
+ bspc node -{f,s} {west,south,north,east}
+
+# Focus the node for the given path jump
+#super + {p,b,comma,period}
+# bspc node -f @{parent,brother,first,second}
+
+# Focus the next/previous window in the current desktop
+super + {_,shift + }c
+ bspc node -f {next,prev}.local.!hidden.window
+
+# Focus the next/previous desktop in the current monitor
+super + bracket{left,right}
+ bspc desktop -f {prev,next}.local
+
+# Focus the last node/desktop
+super + {grave,Tab}
+ bspc {node,desktop} -f last
+
+# Focus the older or newer node in the focus history
+#super + {o,i}
+# bspc wm -h off; \
+# bspc node {older,newer} -f; \
+# bspc wm -h on
+
+# Focus or send to the given desktop
+super + {_,shift + }{1-9,0}
+ bspc {desktop -f,node -d} '^{1-9,10}'
+
+# Hide window
+super + comma
+ bspc node -g hidden
+
+# Unhide window (script)
+super + period
+ ${HOME}/.config/bspwm/scripts/hide-window unhide
+
+# Toggle the hidden state of the focused node
+super + q
+ ~/.scripts/bspwm-toggle-visibility.sh
+
+#---------------------------------------------------------------
+#
+# Preselect
+#
+
+# Preselect the direction
+super + ctrl + {h,j,k,l}
+ bspc node -p {west,south,north,east}
+
+# Preselect the ratio
+super + ctrl + {1-9}
+ bspc node -o 0.{1-9}
+
+# Cancel the preselection for the focused node
+super + ctrl + space
+ bspc node -p cancel
+
+# Cancel the preselection for the focused desktop
+super + ctrl + shift + space
+ bspc query -N -d | xargs -I id -n 1 bspc node id -p cancel
+
+# Close all receptacle
+super + shift + i
+ for win in `bspc query -N -n .leaf.\!window`; do bspc node $win -k ; done;
+
+# Insert receptacle
+super + i; {h,j,k,l}
+ bspc node --presel-dir {west,south,north,east} -i
+
+# Move to rectacle
+super + ctrl + i
+ bspreceptacle
+
+# Balance nodes
+super + alt + i
+ bspc node @/ -B
+
+
+
+#---------------------------------------------------------------
+#
+# Move/resize
+#
+
+## Drag tiling window to floating
+alt + button1
+ bspdragtofloat
+alt + @button1
+ bspdragtofloat stop
+@button1
+ bspdragtofloat stop
+~button1
+ :
+
+# Move a floating window or swap with any other adjacent tiled/pseudo_tiled window
+ctrl + alt + {h,j,k,l}
+ { dir=west dx=-20 dy=0 \
+ , dir=south dx=0 dy=20 \
+ , dir=north dx=0 dy=-20 \
+ , dir=east dx=20 dy=0 \
+ }; \
+ bspc node --move "$dx" "$dy" || bspc node --swap $dir
+
+# Rotate windows to different nodes
+super + ctrl + r
+ bspc node @parent -R 90
+
+# Resize tiled/floating windows (script)
+shift + alt + {h,j,k,l}
+ bspwm_resize.sh {west,south,north,east}
+#shift + alt + {h,j,k,l}
+# {bspc node @parent/second -z left -20 0; \
+# bspc node @parent/first -z right -20 0, \
+# bspc node @parent/second -z top 0 +20; \
+# bspc node @parent/first -z bottom 0 +20, \
+# bspc node @parent/first -z bottom 0 -20; \
+# bspc node @parent/second -z top 0 -20, \
+# bspc node @parent/first -z right +20 0; \
+# bspc node @parent/second -z left +20 0}
+
+# Resize window into predefined pseudo_tiled window
+super + shift + s
+ bspc node -t pseudo_tiled; bspc node -t floating && wtp 396 185 570 394 "$(pfw)"
+
+# Spawn next window/program into predefined floating window
+super + ctrl + s
+ bspc rule -a '*' -o state=floating rectangle=720x480+320+200
+
+# Spawn next window/program into another desktop
+super + alt + {1-9,0}
+ bspc rule -a '*' -o desktop=^{1-9,10}
+
+# Focused desktop window gaps scroll
+shift + alt + {1,2}
+ bspc config -d focused window_gap $((`bspc config -d focused window_gap` {-,+} 5 ))
+
+# Global window gaps scroll
+ctrl + alt + {1,2}
+ bspc config window_gap $(( $(bspc config window_gap) {-,+} 5 ))
+
+#---------------------------------------------------------------
+#
+# Multimedia
+#
+# Multimedia control
+{XF86AudioStop,XF86AudioPlay,XF86AudioPrev,XF86AudioNext}
+ playerctl {stop,play-pause,previous,next}
+
+# Use arrow keys as multimedia keys
+alt + shift + {Left,Up,Right}
+ playerctl {previous,play-pause,next}
+
+# Brightness control
+XF86MonBrightness{Up,Down}
+ brightnessctl s 5%{+,-}
+
+# Use arrow keys as brightness keys
+alt + {Right,Left}
+ brightnessctl s 5%{+,-}
+
+# Volume control
+XF86Audio{Raise,Lower}Volume
+ pulsemixer --change-volume {+,-}5
+
+# Use arrow keys as volume keys
+alt + {Up,Down}
+ pulsemixer --change-volume {+,-}5
+
+
+#---------------------------------------------------------------
+#
+# Xdotool keys
+#
+
+# Move mouse cursor north, west, south, east
+alt + {w,a,s,d}
+ xdotool mousemove_relative --sync {-- 0 -24, -- -24 0, 0 24, 24 0}
+
+# Move mouse cursor diagonally north-west, north-east, south-west, south-east
+shift + alt + {q,e,a,d}
+ xdotool mousemove_relative --sync {-- -24 -24, -- 24 -24, -- -24 24,-- 24 24}
+
+# Emulate left mouse click
+alt + i
+ xdotool click --clearmodifiers 1
+
+# Emulate left mouse click select
+alt + shift + i
+ xdotool mousedown 1 sleep 0.5 mousemove_relative --sync {-- -8 0, 0 8, -- 0 -8, 8 0} sleep 0.5 mouseup 1
+
+# Emulate mouse right click
+alt + o
+ xdotool click --clearmodifiers 3
+
+# Emulate mouse scroll up
+alt + n
+ xdotool click --clearmodifiers 4
+
+# Emulate mouse scroll down
+alt + m
+ xdotool click --clearmodifiers 5
+
+# Emulate mouse scroll button
+alt + p
+ xdotool click --clearmodifiers 2
+
+# Emulate home key
+alt + ctrl + Left
+ xdotool keyup Left key --clearmodifiers Home
+
+# Emulate end key
+alt + ctrl + Right
+ xdotool keyup Right key --clearmodifiers End
+
+# Emulate delete key
+~alt + BackSpace
+ xte 'keyup Alt_L' 'key Delete' 'keydown Alt_L'
+
+
+#---------------------------------------------------------------
+#
+# Programs
+#
+
+# Scratchpd
+super + semicolon
+ ~/.scripts/scratchpad
+
+super + x
+ ~/.scripts/scratchpad
+
+# Heads-Up-Display scratchpad terminal
+super + e
+ ~/.scripts/heads-up-display
+
+## File manager nnn
+#super + shift + n
+# $TERMINAL -e nnn
+
+# File manager pcmanfm (GUI)
+super + shift + f
+ pcmanfm
+
+# Bitwarden-rofi
+super + shift + b
+ rofi-rbw
+
+# Thunderbird mail
+#super + shift + m
+# thunderbird
+
+# VirtualBox gui
+super + v
+ /usr/bin/VirtualBox -- :0 vt1
+
+# Discord
+super + shift + d
+ discord
+
+# Spotify
+super + shift + y
+ spotify
+
+# Book reader (zathura)
+super + shift + z
+ zathura
+
+# Dictionary
+super + ctrl + w
+ goldendict
+
+# Thesaurus
+super + shift + w
+ artha
+
+# Suspend
+alt + F4
+ systemctl suspend && betterlockscreen --lock dimblur
diff --git a/linux/home/.config/tridactyl/tridactylrc b/linux/home/.config/tridactyl/tridactylrc
new file mode 100644
index 0000000..a9547cc
--- /dev/null
+++ b/linux/home/.config/tridactyl/tridactylrc
@@ -0,0 +1,170 @@
+" -*- vimrc-generic -*-
+"
+" Base on
+" https://raw.githubusercontent.com/tridactyl/tridactyl/master/.tridactylrc
+" See that for more advanced examples.
+
+" Installing Tridactyl:
+"
+" * Put this config in ~/.tridactylrc (or $XDG_CONFIG_DIR/tridactyl/tridactylrc).
+"
+" * Install the native messenger by running :installnative in Tridactyl
+" and then running the shell command it copies to clipboard.
+"
+" * Run :source in the browser or just restart.
+
+" NB: If you want "vim-like" behaviour where removing a line from
+" here makes the setting disappear, uncomment the line below.
+"
+"sanitise tridactyllocal tridactylsync
+
+" Use this to see current config in the browser
+" :viewconfig --user
+
+" WARNING: THERE IS A BUG WHEREBY SOMETIMES SOME LINES IN THE CONFIG GET IGNORED :/
+" https://github.com/tridactyl/tridactyl/issues/1409
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+"
+" Search Urls
+"
+" These work in the 'o' -> ':open ' dialog, but not in the regular
+" address bar.
+"
+" In addition to using %s for a single query param, you can use %1,
+" %2, etc, for multiple query params.
+
+"set searchurls.hackage http://hackage.haskell.org/package/%s
+"set searchurls.hayoo http://hayoo.fh-wedel.de/?query=%s
+"set searchurls.h4 https://www.haskell.org/hoogle/?hoogle=%s
+"set searchurls.h5 https://hoogle.haskell.org/?hoogle=%s&scope=set%3Astackage
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+"
+" Quickmarks
+"
+" Use go<key>/gn<key>/gw<key> to open quickmark for <key> in
+" current/new tab/new window
+
+quickmark g https://mail.google.com/mail/u/0/#inbox
+quickmark G https://mail.google.com/mail/u/1/#inbox
+
+""""""""""""""""
+"
+" Disable on some sites
+"
+
+"blacklistadd youtube.com
+blacklistadd calendar.google.com
+blacklistadd docs.google.com
+blacklistadd drive.google.com
+blacklistadd keep.google.com
+blacklistadd mail.google.com
+blacklistadd monkeytype.com
+blacklistadd typeracer.com
+blacklistadd codepen.io
+blacklistadd codesandbox.io
+"blacklistadd github.dev
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+"
+" Binds
+"
+" Some defaults:
+" - :help
+" - :tutor
+" - b : buffers/tabs navigation
+" - yy : yank url
+" - gg : top of page
+" - G : bottom of page
+" - insert, shift+insert, ctrl+alt+`, shift+escape : toggle pass thru
+" - d/D : close current tab and move focus right/left
+" - p/P : open url in clipboard or search for clipboard content in current/new tab
+" - zi/zo/zz : zoom in/out/reset
+" - \[\[ / \]\] : guess previous/next page (seems smart, e.g. works when
+" url does not end in a number, but "next" occurs in link text)
+" - ;; : focus an element. Useful if you want to scroll something non-default with up/down or j/k
+" - ;p : copy element (e.g. link, paragraph) to clipboard
+" - ;k : kill element (e.g. a big "please disable your ad blocker" banner)
+" - :viewconfig nmaps : see all key bindings (but how to delete?)
+" - f/;t/F: follow hint in current tab/new foreground tab (switch focus)/new background tab (don't switch focus)
+" - C-o : run a single command (in normal mode) when in ignore mode, then switch back to ignore mode
+
+" Make 'd' switch to previous active tab after close
+bind d composite tabclose | buffer #
+
+" Don't bind paste to ignore mode. Can use 'S-Esc' or 'C-A-Esc' instead.
+unbind <S-Insert>
+
+" Don't bind 'f' in youtube
+unbindurl youtube\.com/watch\?v=.* f
+
+" Bind <Insert> to toggle normal/ignore mode. I use <Insert> to toggle
+" Ctrl-lock in Emacs, so hopefully this will be memorable. We leave
+" insert mode, but don't enter it. The insert mode bind doesn't work,
+" but <C-,> still allows escape.
+bind --mode=normal <Insert> mode ignore
+bind --mode=ignore <Insert> mode normal
+"bind --mode=insert <Insert> mode normal
+
+" Bind <C-o> to toggle normal/ignore mode for one command. Already
+" bound to C-o in normal mode, make it work everywhere. I'm rebinding
+" the existing normal mode bind for completeness/clairity. We leave
+" insert mode, but don't enter. The insert mode bind doesn't work, but
+" <C-,> still allows escape.
+bind --mode=normal <C-o> nmode normal 1 mode ignore
+bind --mode=ignore <C-o> nmode ignore 1 mode normal
+"bind --mode=insert <C-o> nmode insert 1 mode normal
+
+bind / fillcmdline find
+bind n findnext 1
+bind N findnext -1
+"bind <Space>/ nohlsearch
+set findcase smart
+
+" Workaround bug on web.whatsapp.com that prevents focus from leaving
+" message entry
+"" box. https://github.com/tridactyl/tridactyl/issues/3070
+"bindurl web.whatsapp.com --mode=normal <Escape> composite hint -f m2 ; fillcmdline ; ex.hide_and_clear
+"bindurl web.whatsapp.com --mode=insert <Escape> composite hint -f m2 ; fillcmdline ; ex.hide_and_clear
+"bindurl web.whatsapp.com --mode=input <Escape> composite hint -f m2 ; fillcmdline ; ex.hide_and_clear
+
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+"
+" Misc settings
+"
+
+" but make sure i can always get into the console"
+bind : fillcmdline_notrail
+
+" newtab
+set newtab about:blank
+
+" I’m a smooth operator
+set smoothscroll true
+
+" Vimperator-style hinting, using numbers to select and letters to
+" narrow, instead of just letters to select.
+set hintfiltermode vimperator-reflow
+set hintnames numeric
+" " I use Programmer Dvorak
+" set hintchars dhtnaoeuifgcrl',.pybm;qjkx
+
+" Defaults to 300ms
+set hintdelay 100
+
+" Don't autofocus!
+autocmd TabEnter .* unfocus
+autocmd DocLoad .* unfocus
+
+
+" Include numbers in tab names, to make 'b' and '<A-<number>>'
+" switching easier.
+guiset tabs numbers
+
+" Make Tridactyl work on more sites at the expense of some security
+" set csp clobber
+" fixamo_quiet
+
+" This will have to do until someone writes us a nice syntax file :)
+" vim: set filetype=vim:
diff --git a/linux/home/.config/user-dirs.dirs b/linux/home/.config/user-dirs.dirs
new file mode 100644
index 0000000..0db0cae
--- /dev/null
+++ b/linux/home/.config/user-dirs.dirs
@@ -0,0 +1,15 @@
+# This file is written by xdg-user-dirs-update
+# If you want to change or add directories, just edit the line you're
+# interested in. All local changes will be retained on the next run.
+# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
+# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
+# absolute path. No other format is supported.
+#
+XDG_DESKTOP_DIR="$HOME/"
+XDG_DOWNLOAD_DIR="$HOME/downloads"
+XDG_TEMPLATES_DIR="$HOME/"
+XDG_PUBLICSHARE_DIR="$HOME/"
+XDG_DOCUMENTS_DIR="$HOME/documents"
+XDG_MUSIC_DIR="$HOME/music"
+XDG_PICTURES_DIR="$HOME/pictures"
+XDG_VIDEOS_DIR="$HOME/videos"
diff --git a/linux/home/.config/user-dirs.locale b/linux/home/.config/user-dirs.locale
new file mode 100644
index 0000000..3e0b419
--- /dev/null
+++ b/linux/home/.config/user-dirs.locale
@@ -0,0 +1 @@
+en_US \ No newline at end of file
diff --git a/linux/home/.config/waybar/config.jsonc b/linux/home/.config/waybar/config.jsonc
new file mode 100644
index 0000000..dbf6556
--- /dev/null
+++ b/linux/home/.config/waybar/config.jsonc
@@ -0,0 +1,292 @@
+{
+ "layer": "top", // Waybar at top layer
+ "position": "top", // Waybar position (top|bottom|left|right)
+ //"gtk-layer-shell": "false",
+ "height": 45, // Waybar height (to be removed for auto height)
+ // "width": 2560, // Waybar width
+ "spacing": 0, // Gaps between modules (0px) Adjusted in the css
+ "margin-top": 0,
+ //"margin-bottom":-10,
+ "margin-left": 10,
+ "margin-right": 10,
+ // Choose the order of the modules
+ "modules-left": [
+ "custom/launcher",
+ "wlr/workspaces",
+ "cpu",
+ "memory",
+ "temperature",
+ "disk",
+ "custom/updates"
+ ],
+ "modules-center": [
+ "custom/music"
+ ],
+ "modules-right": [
+ "network",
+ "pulseaudio",
+ "backlight",
+ "battery",
+ "custom/notifications",
+ "tray",
+ "clock",
+ "custom/weather",
+ "custom/cycle_wall",
+ "custom/clipboard",
+ "custom/power",
+ "custom/custom"
+ ],
+ "custom/launcher": {
+ "format": "{}",
+ "tooltip": true,
+ "exec": "echo '{\"text\":\"💧\",\"tooltip\":\"Drun | Run\"}'",
+ "return-type": "json",
+ "on-click": "pkill wofi || wofi --show drun -n",
+ "on-click-right": "pkill wofi || wofi --show run -n",
+ },
+ "wlr/workspaces": {
+ // "format": "{icon} {name}",
+ "format": "",
+ "format-icons": {
+ "active": "",
+ "default": ""
+ },
+ "on-scroll-up": "hyprctl dispatch workspace e-1",
+ "on-scroll-down": "hyprctl dispatch workspace e+1",
+ "on-click": "activate"
+ },
+ "cpu": {
+ "format": " {usage}%",
+ "tooltip": true,
+ "on-click": "kitty --start-as=fullscreen --title all_is_kitty sh -c 'btop'",
+ "interval": 2
+ },
+ "memory": {
+ "format": " {}%",
+ "tooltip": true,
+ "on-click": "kitty --start-as=fullscreen --title all_is_kitty sh -c 'btop'",
+ "interval": 2
+ },
+ "temperature": {
+ // "thermal-zone": 2,
+ // "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
+ "critical-threshold": 40,
+ "format-critical": "{icon} {temperatureC}°C",
+ "format": "{icon} {temperatureC}°C",
+ "format-icons": [
+ "",
+ "",
+ ""
+ ],
+ "tooltip": true,
+ "on-click": "kitty --start-as=fullscreen --title all_is_kitty sh -c 'btop'",
+ "interval": 2
+ },
+ "disk": {
+ "format": " {percentage_used}% ({free})",
+ "tooltip": true,
+ "on-click": "kitty --start-as=fullscreen --title all_is_kitty sh -c 'btop'",
+ "interval": 2
+ },
+ "custom/updates": {
+ "format": "{}",
+ "exec": "~/.scripts/updates",
+ "on-click": "~/.scripts/updates update",
+ "interval": 300,
+ "tooltip": true,
+ // "tooltip-format": "{}",
+ // "exec-tooltip": "~/.scripts/updates tooltip"
+ },
+ "custom/music": {
+ "format": "{icon}{}",
+ "format-icons": {
+ // "Playing": " ", // Uncomment if not using the dynamic script
+ "Paused": " ",
+ "Stopped": "&#x202d;ﭥ " // This stop symbol is RTL. So &#x202d; is left-to-right override.
+ },
+ "escape": true,
+ "tooltip": true,
+ "exec": "~/.scripts/caway -b 10",
+ "return-type": "json",
+ "on-click": "playerctl play-pause",
+ "on-scroll-up": "playerctl previous",
+ "on-scroll-down": "playerctl next",
+ "on-click-right": "g4music",
+ "max-length": 35
+ },
+ "hyprland/window": {
+ "format": "{}",
+ "separate-outputs": true,
+ "max-length": 35
+ },
+ "network": {
+ // "interface": "wlp2*", // (Optional) To force the use of this interface
+ "format": "↕{bandwidthTotalBytes}",
+ "format-disconnected": "{icon} No Internet",
+ "format-linked": " {ifname} (No IP)",
+ "format-alt": "↕{bandwidthUpBytes} | ↕{bandwidthDownBytes}",
+ "tooltip-format": "{ifname}: {ipaddr}/{cidr}  {gwaddr}",
+ "tooltip-format-wifi": "{icon} {essid} ({signalStrength}%)",
+ "tooltip-format-ethernet": "{icon} {ipaddr}/{cidr}",
+ "tooltip-format-disconnected": "{icon} Disconnected",
+ "on-click-right": "nm-connection-editor",
+ "format-icons": {
+ "ethernet": "",
+ "disconnected": "⚠",
+ "wifi": [
+ "睊",
+ "直"
+ ]
+ },
+ "interval": 2
+ },
+ "pulseaudio": {
+ // "scroll-step": 1, // %, can be a float
+ "format": "{icon} {volume}%", // {format_source}
+ "format-bluetooth": "{icon} {volume}%", // {format_source}
+ "format-bluetooth-muted": "", // {format_source}
+ "format-muted": "", // {format_source}
+ "format-source": "{volume}% ",
+ "format-source-muted": "",
+ "format-icons": {
+ "headphone": "",
+ "headset": "",
+ "phone": "",
+ "portable": "",
+ "car": " ",
+ "default": [
+ "",
+ "",
+ ""
+ ]
+ },
+ "on-click": "pavucontrol"
+ },
+ "backlight": {
+ // "device": "acpi_video1",
+ "format": "{icon} {percent}%",
+ "format-icons": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "on-scroll-up": "light -A 1",
+ "on-scroll-down": "light -U 1",
+ "interval": 2
+ },
+ "battery": {
+ "states": {
+ "good": 100,
+ "warning": 30,
+ "critical": 10
+ },
+ "format": "{icon} {capacity}%",
+ "format-charging": " {capacity}%",
+ "format-plugged": " {capacity}%",
+ "format-alt": "{icon} {time}",
+ // "format-good": "", // An empty format will hide the module
+ "format-full": " {capacity}%",
+ "format-icons": [
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ ""
+ ],
+ "interval": 2
+ },
+ "custom/notifications": {
+ "tooltip": false,
+ "format": "{icon}",
+ "format-icons": {
+ "notification": "<span foreground='red'><sup></sup></span>",
+ "none": "",
+ "dnd-notification": "<span foreground='red'><sup></sup></span>",
+ "dnd-none": ""
+ },
+ "return-type": "json",
+ "exec-if": "which swaync-client",
+ "exec": "swaync-client -swb",
+ "on-click": "swaync-client -t -sw",
+ "on-click-right": "swaync-client -d -sw",
+ "escape": true
+ },
+ "tray": {
+ "icon-size": 15,
+ "spacing": 15
+ },
+ "clock": {
+ "timezone": "Asia/Calcutta",
+ "format": " {:%d <small>%a</small> %H:%M}",
+ //"format": " {:%a %b %d %Y | %H:%M}",
+ "format-alt": " {:%A %B %d %Y (%V) | %r}",
+ "tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>",
+ "calendar-weeks-pos": "right",
+ "today-format": "<span color='#f38ba8'><b><u>{}</u></b></span>",
+ "format-calendar": "<span color='#f2cdcd'><b>{}</b></span>",
+ "format-calendar-weeks": "<span color='#94e2d5'><b>W{:%U}</b></span>",
+ "format-calendar-weekdays": "<span color='#f9e2af'><b>{}</b></span>",
+ "interval": 60
+ },
+ "idle_inhibitor": {
+ "format": "{icon}",
+ "format-icons": {
+ "activated": "",
+ "deactivated": ""
+ }
+ },
+ "custom/weather": {
+ "tooltip": true,
+ "format": "{}",
+ "exec": "~/.scripts/tools/expand weather",
+ "return-type": "json"
+ },
+ "custom/ss": {
+ "format": "{}",
+ "exec": "~/./scripts/tools/expand ss-icon",
+ "return-type": "json",
+ "on-click": "~/.scripts/screenshot_full"
+ },
+ "custom/cycle_wall": {
+ "format": "{}",
+ "exec": "~/.scripts/tools/expand wall",
+ "return-type": "json",
+ // "interval": 1,
+ "on-click": "~/.scripts/tools/expand cycle",
+ "on-click-right": "~/.scripts/tools/expand cycler"
+ },
+ "custom/clipboard": {
+ "format": "{}",
+ "exec": "~/.scripts/tools/expand clipboard",
+ "return-type": "json",
+ // Here "-l top_right -x -15 -y 10" doesn't matter as '-n' mode is used
+ // Window position is managed in Hyperland config's windowrulev2
+ "on-click": "pkill wofi || cliphist list | wofi --dmenu -p clippick -l top_right -x -15 -y 10 -n | cliphist decode | wl-copy",
+ "on-click-middle": "rm -f ~/.cache/cliphist/db",
+ "on-click-right": "pkill wofi || cliphist list | wofi --dmenu -p clippick -l top_right -x -15 -y 10 -n | cliphist delete",
+ "escape": true
+ },
+ "custom/power": {
+ "format": "{}",
+ "exec": "~/.scripts/tools/expand power",
+ "return-type": "json",
+ "on-click": "~/.config/wlogout/launch.sh"
+ },
+ "custom/custom": {
+ "format": "{}",
+ "exec": "~/.scripts/tools/expand arrow-icon",
+ "on-click": "~/.scripts/tools/expand_toolbar",
+ "return-type": "json"
+ }
+}
diff --git a/linux/home/.config/waybar/style.css b/linux/home/.config/waybar/style.css
new file mode 100644
index 0000000..348bb04
--- /dev/null
+++ b/linux/home/.config/waybar/style.css
@@ -0,0 +1,434 @@
+/*
+@import "catppuccin/mocha.css";
+*/
+
+/*
+* Catppuccin Mocha palette
+*/
+
+@define-color base #1e1e2e;
+@define-color mantle #181825;
+@define-color crust #11111b;
+
+@define-color text #cdd6f4;
+@define-color subtext0 #a6adc8;
+@define-color subtext1 #bac2de;
+
+@define-color surface0 rgba(22, 25, 37, 0.9);
+@define-color surface1 #45475a;
+@define-color surface2 #585b70;
+@define-color surface3 #394161;
+
+@define-color overlay0 #6c7086;
+@define-color overlay1 #7f849c;
+@define-color overlay2 #9ba3c3;
+
+@define-color blue #89b4fa;
+@define-color lavender #b4befe;
+@define-color sapphire #74c7ec;
+@define-color sky #89dceb;
+@define-color teal #94e2d5;
+@define-color green #a6e3a1;
+@define-color yellow #f9e2af;
+@define-color peach #fab387;
+@define-color maroon #eba0ac;
+@define-color red #f38ba8;
+@define-color mauve #cba6f7;
+@define-color pink #f5c2e7;
+@define-color flamingo #f2cdcd;
+@define-color rosewater #f5e0dc;
+
+/* =============================== */
+/* Universal Styling */
+* {
+ border: none;
+ border-radius: 0;
+ font-family: 'CaskaydiaCove Nerd Font', monospace;
+ font-size: 13px;
+ min-height: 0;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* Bar Styling */
+#waybar {
+ background: transparent;
+ color: @text;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* Main Modules */
+#custom-launcher,
+#workspaces,
+#window,
+#tray,
+#backlight,
+#clock,
+#battery,
+#pulseaudio,
+#network,
+#mpd,
+#cpu,
+#memory,
+#disk,
+#temperature,
+#custom-music,
+#custom-updates,
+#custom-nordvpn,
+#custom-notifications,
+#custom-power,
+#custom-custom,
+#custom-cycle_wall,
+#custom-clipboard,
+#custom-ss,
+#custom-weather {
+ background-color: @surface0;
+ color: @text;
+ border-radius: 16px;
+ padding: 0.5rem 1rem;
+ box-shadow: rgba(0, 0, 0, 0.116) 2px 2px 5px 2px;
+ margin-top: 10px;
+ /*
+ margin-bottom: 10px;
+*/
+ margin-right: 10px;
+}
+
+/* =============================== */
+/* Launcher Module */
+#custom-launcher {
+ color: @green;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ padding-right: 10px;
+}
+
+/* =============================== */
+/* Workspaces */
+#workspaces {
+ padding-left: 8px;
+ padding-right: 8px;
+}
+
+#workspaces * {
+ font-size: 0px;
+}
+
+#workspaces button {
+ background-color: @surface3;
+ color: @mauve;
+ border-radius: 100%;
+ min-height: 14px;
+ min-width: 14px;
+ margin: 5px 8px;
+ padding: 0px;
+ /*transition: all 0.5s cubic-bezier(0.33, 1.0, 0.68, 1.0); easeInOutCubic */
+ transition: all 0.5s cubic-bezier(.55, -0.68, .48, 1.68);
+ box-shadow: rgba(0, 0, 0, 0.288) 2px 2px 5px 2px;
+}
+
+#workspaces button.active {
+ /*color: @surface0;
+ border-radius: 1rem;
+ padding: 0rem 10px;*/
+ background: radial-gradient(circle, rgba(203, 166, 247, 1) 0%, rgba(193, 168, 247, 1) 12%, rgba(249, 226, 175, 1) 19%, rgba(189, 169, 247, 1) 20%, rgba(182, 171, 247, 1) 24%, rgba(198, 255, 194, 1) 36%, rgba(177, 172, 247, 1) 37%, rgba(170, 173, 248, 1) 48%, rgba(255, 255, 255, 1) 52%, rgba(166, 174, 248, 1) 52%, rgba(160, 175, 248, 1) 59%, rgba(148, 226, 213, 1) 66%, rgba(155, 176, 248, 1) 67%, rgba(152, 177, 248, 1) 68%, rgba(205, 214, 244, 1) 77%, rgba(148, 178, 249, 1) 78%, rgba(144, 179, 250, 1) 82%, rgba(180, 190, 254, 1) 83%, rgba(141, 179, 250, 1) 90%, rgba(137, 180, 250, 1) 100%);
+ background-size: 400% 400%;
+ animation: gradient_f 20s ease-in-out infinite;
+ transition: all 0.3s cubic-bezier(.55, -0.68, .48, 1.682);
+}
+
+#workspaces button:hover {
+ background-color: @mauve;
+}
+
+@keyframes gradient {
+ 0% {
+ background-position: 0% 50%;
+ }
+
+ 50% {
+ background-position: 100% 30%;
+ }
+
+ 100% {
+ background-position: 0% 50%;
+ }
+}
+
+@keyframes gradient_f {
+ 0% {
+ background-position: 0% 200%;
+ }
+
+ 50% {
+ background-position: 200% 0%;
+ }
+
+ 100% {
+ background-position: 400% 200%;
+ }
+}
+
+@keyframes gradient_f_nh {
+ 0% {
+ background-position: 0% 200%;
+ }
+
+ 100% {
+ background-position: 200% 200%;
+ }
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* System Monitoring Modules */
+#cpu,
+#memory,
+#temperature {
+ color: @blue;
+}
+
+#cpu {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ margin-right: 0px;
+ padding-right: 5px;
+}
+
+#memory {
+ border-radius: 0px;
+ margin-right: 0px;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+#temperature {
+ border-radius: 0px;
+ margin-right: 0px;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+#disk {
+ color: @peach;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ padding-left: 5px;
+ padding-right: 1rem;
+}
+
+/* Updates Module */
+#custom-updates {
+ color: @sky;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* Clock Module */
+#clock {
+ color: @flamingo;
+}
+
+/* =============================== */
+
+
+#custom-music.low {
+ background: rgb(148, 226, 213);
+ background: linear-gradient(52deg, rgba(148, 226, 213, 1) 0%, rgba(137, 220, 235, 1) 19%, rgba(116, 199, 236, 1) 43%, rgba(137, 180, 250, 1) 56%, rgba(180, 190, 254, 1) 80%, rgba(186, 187, 241, 1) 100%);
+ background-size: 300% 300%;
+ text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.377);
+ animation: gradient 15s ease infinite;
+ font-weight: bold;
+ color: #fff;
+}
+
+#custom-music.random {
+ background: rgb(148, 226, 213);
+ background: radial-gradient(circle, rgba(148, 226, 213, 1) 0%, rgba(156, 227, 191, 1) 21%, rgba(249, 226, 175, 1) 34%, rgba(158, 227, 186, 1) 35%, rgba(163, 227, 169, 1) 59%, rgba(148, 226, 213, 1) 74%, rgba(164, 227, 167, 1) 74%, rgba(166, 227, 161, 1) 100%);
+ background-size: 400% 400%;
+ animation: gradient_f 4s ease infinite;
+ text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.377);
+ font-weight: bold;
+ color: #fff;
+}
+
+#custom-music.critical {
+ background: rgb(235, 160, 172);
+ background: linear-gradient(52deg, rgba(235, 160, 172, 1) 0%, rgba(243, 139, 168, 1) 30%, rgba(231, 130, 132, 1) 48%, rgba(250, 179, 135, 1) 77%, rgba(249, 226, 175, 1) 100%);
+ background-size: 300% 300%;
+ animation: gradient 15s cubic-bezier(.55, -0.68, .48, 1.68) infinite;
+ text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.377);
+ font-weight: bold;
+ color: #fff;
+}
+
+#custom-music.Playing {
+ background: rgb(137, 180, 250);
+ background: radial-gradient(circle, rgba(137, 180, 250, 120) 0%, rgba(142, 179, 250, 120) 6%, rgba(148, 226, 213, 1) 14%, rgba(147, 178, 250, 1) 14%, rgba(155, 176, 249, 1) 18%, rgba(245, 194, 231, 1) 28%, rgba(158, 175, 249, 1) 28%, rgba(181, 170, 248, 1) 58%, rgba(205, 214, 244, 1) 69%, rgba(186, 169, 248, 1) 69%, rgba(195, 167, 247, 1) 72%, rgba(137, 220, 235, 1) 73%, rgba(198, 167, 247, 1) 78%, rgba(203, 166, 247, 1) 100%);
+ background-size: 400% 400%;
+ animation: gradient_f 9s cubic-bezier(.72, .39, .21, 1) infinite;
+ text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.377);
+ font-weight: bold;
+ color: #fff;
+}
+
+#custom-music.Paused,
+#custom-music.Stopped {
+ background: @surface0;
+}
+
+
+/* =============================== */
+/* Music/PlayerCTL Module */
+#custom-music {
+ color: @mauve;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* Network Module */
+#network {
+ color: @blue;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ margin-right: 0px;
+ padding-right: 5px;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* PulseAudio Module */
+#pulseaudio {
+ color: @mauve;
+ border-radius: 0;
+ margin-right: 0px;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* Backlight Module */
+#backlight {
+ color: @teal;
+ border-radius: 0;
+ margin-right: 0px;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* Battery Module */
+#battery {
+ color: @green;
+ border-radius: 0;
+ margin-right: 0px;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+#battery.charging {
+ color: @green;
+}
+
+#battery.warning:not(.charging) {
+ color: @maroon;
+}
+
+#battery.critical:not(.charging) {
+ color: @red;
+ animation-name: blink;
+ animation-duration: 1s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+}
+
+@keyframes blink {
+ to {
+ background: @red;
+ color: @surface1;
+ }
+}
+
+/* =============================== */
+
+/* Notifications Module */
+#custom-notifications {
+ color: @mauve;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ padding-left: 5px;
+ padding-right: 1.25rem;
+}
+
+
+/* =============================== */
+/* Tray Module */
+#tray {
+ color: @mauve;
+ padding-right: 1.25rem;
+}
+
+/* =============================== */
+
+
+/* =============================== */
+/* | Custom Modules | */
+/* =============================== */
+#custom-custom {
+ color: @peach;
+ padding-right: 1.25rem;
+ margin-right: 0px;
+}
+
+/* Screenshot */
+#custom-ss {
+ color: @mauve;
+ padding-right: 1.5rem;
+}
+
+/* Wallpaper */
+#custom-cycle_wall {
+ background: linear-gradient(45deg, rgba(245, 194, 231, 1) 0%, rgba(203, 166, 247, 1) 0%, rgba(243, 139, 168, 1) 13%, rgba(235, 160, 172, 1) 26%, rgba(250, 179, 135, 1) 34%, rgba(249, 226, 175, 1) 49%, rgba(166, 227, 161, 1) 65%, rgba(148, 226, 213, 1) 77%, rgba(137, 220, 235, 1) 82%, rgba(116, 199, 236, 1) 88%, rgba(137, 180, 250, 1) 95%);
+ background-size: 500% 500%;
+ animation: gradient 7s linear infinite;
+}
+
+/* Notifications Module */
+#custom-clipboard {
+ color: @mauve;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ margin-right: 0px;
+ padding-right: 8px;
+}
+
+/* Powermenu Module */
+#custom-power {
+ color: @mauve;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ padding-left: 8px;
+ padding-right: 1.20rem;
+}
+
+/* =============================== */
diff --git a/linux/home/.config/wezterm/wezterm.lua b/linux/home/.config/wezterm/wezterm.lua
new file mode 100644
index 0000000..4f4bd07
--- /dev/null
+++ b/linux/home/.config/wezterm/wezterm.lua
@@ -0,0 +1,206 @@
+local wezterm = require("wezterm")
+
+---- Function to unset Ctrl+C keybinding
+--local function unsetCtrlCKeybinding(window)
+-- local keys = window:get_config().keys
+-- for i, key in ipairs(keys) do
+-- if key.key == 'c' and key.mods == 'CTRL' then
+-- table.remove(keys, i)
+-- break
+-- end
+-- end
+-- window:set_config({ keys = keys })
+--end
+--
+---- Event handler to unset Ctrl+C keybinding when using nvim
+--wezterm.on("spawn_command", function(window, pane)
+-- local cmd = pane:get_command()
+-- if cmd and cmd[1] == "nvim" then
+-- unsetCtrlCKeybinding(window)
+-- end
+--end)
+
+--local function isNvimRunning(window)
+-- local pane = window.active_pane
+-- local cmd = pane:get_command()
+-- return cmd and cmd[1] == "nvim"
+--end
+--
+---- Function to modify keybindings based on the current program
+--local function updateKeybindings(window)
+-- local isNvim = isNvimRunning(window)
+--
+-- local keys = {}
+-- if not isNvim then
+-- -- Add the default Ctrl+C keybinding
+-- keys = {
+-- {
+-- key = "c",
+-- mods = "CTRL",
+-- action = wezterm.action{CopyTo = "ClipboardAndPrimarySelection"}
+-- }
+-- }
+-- end
+--
+-- window:set_config({
+-- keys = keys
+-- })
+--end
+--
+---- Event handler to update keybindings when the active program changes
+--wezterm.on("update-right-status", function(window)
+-- updateKeybindings(window)
+--end)
+
+wezterm.on("toggle-opacity", function(window)
+ local overrides = window:get_config_overrides() or {}
+ if not overrides.window_background_opacity then
+ overrides.window_background_opacity = 1.0
+ elseif overrides.window_background_opacity == 1.0 then
+ overrides.window_background_opacity = 0.6
+ else
+ overrides.window_background_opacity = nil
+ end
+ window:set_config_overrides(overrides)
+end)
+
+return {
+ front_end = "OpenGL",
+ --font = wezterm.font 'JetBrains Mono',
+ font = wezterm.font_with_fallback({
+ {
+ family = "JetBrains Mono",
+ --intensity = 'Normal',
+ weight = "Medium",
+ italic = false,
+ harfbuzz_features = { "calt=0", "clig=0", "liga=0" },
+ },
+ { family = "Hack Nerd Font", weight = "Medium" },
+ {
+ family = "Fira Code",
+ harfbuzz_features = { "zero" },
+ },
+ { family = "Terminus", weight = "Bold" },
+ "Noto Color Emoji",
+ }),
+ font_size = 9,
+ warn_about_missing_glyphs = false,
+ adjust_window_size_when_changing_font_size = false,
+ line_height = 1.0,
+ --dpi = 96.0,
+ -- Keybinds
+ disable_default_key_bindings = true,
+ use_dead_keys = false,
+ mouse_bindings = {
+ -- Ctrl-click will open the link under the mouse cursor
+ {
+ event = { Up = { streak = 1, button = "Left" } },
+ mods = "CTRL",
+ action = wezterm.action.OpenLinkAtMouseCursor,
+ },
+ },
+ keys = {
+ --leader = { key = 'a', mods = 'CTRL', timeout_milliseconds = 1000 },
+ {
+ key = "O",
+ mods = "CTRL|SHIFT",
+ action = wezterm.action({ EmitEvent = "toggle-opacity" }),
+ },
+ { key = "R", mods = "CTRL", action = "ReloadConfiguration" },
+ { key = "Y", mods = "CTRL", action = "ShowDebugOverlay" },
+ {
+ key = "-",
+ mods = "CTRL",
+ action = wezterm.action.DecreaseFontSize,
+ },
+ {
+ key = "=",
+ mods = "CTRL",
+ action = wezterm.action.IncreaseFontSize,
+ },
+ {
+ key = "0",
+ mods = "CTRL",
+ action = wezterm.action.ResetFontSize,
+ },
+ {
+ key = "v",
+ mods = "CTRL",
+ action = wezterm.action({ PasteFrom = "Clipboard" }),
+ },
+ --{
+ -- key = "c",
+ -- mods = "CTRL",
+ -- action = wezterm.action({ CopyTo = "ClipboardAndPrimarySelection" }),
+ --},
+ {
+ key = "c",
+ mods = "CTRL",
+ action = wezterm.action_callback(function(window, pane)
+ local has_selection = window:get_selection_text_for_pane(pane) ~= ""
+ if has_selection then
+ window:perform_action(wezterm.action({ CopyTo = "ClipboardAndPrimarySelection" }), pane)
+ window:perform_action("ClearSelection", pane)
+ else
+ window:perform_action(wezterm.action({ SendKey = { key = "c", mods = "CTRL" } }), pane)
+ end
+ end),
+ },
+ },
+ -- Aesthetic Night Colorscheme
+ bold_brightens_ansi_colors = true,
+ -- Padding
+ window_padding = {
+ left = 5,
+ right = 5,
+ top = 6,
+ bottom = 4,
+ },
+ -- Cursor style
+ --default_cursor_style = "BlinkingUnderline",
+ default_cursor_style = "BlinkingBar",
+ cursor_blink_rate = 700,
+ -- needed to prevent 'easing' from using 40%+ cpu util ...
+ --animation_fps = 1,
+ force_reverse_video_cursor = true,
+ colors = {
+ cursor_bg = "white",
+ compose_cursor = "orange",
+ --cursor_border = 'white',
+ },
+
+ -- Tab Bar
+ enable_tab_bar = false,
+ --hide_tab_bar_if_only_one_tab = true,
+ --show_tab_index_in_tab_bar = false,
+ tab_bar_at_bottom = false,
+
+ -- General
+ -- X11
+ enable_wayland = false,
+ audible_bell = "Disabled",
+
+ visual_bell = {
+ fade_in_duration_ms = 5,
+ fade_out_duration_ms = 5,
+ target = "CursorColor",
+ },
+ automatically_reload_config = true,
+ scrollback_lines = 3500,
+ --inactive_pane_hsb = { saturation = 1.0, brightness = 1.0 },
+ --text_background_opacity = 0.3,
+ window_background_opacity = 0.8,
+ --window_background_image = '/path/to/wallpaper.jpg',
+ --window_background_image_hsb = {
+ -- -- Darken the background image by reducing it to 1/3rd
+ -- brightness = 0.3,
+ -- -- You can adjust the hue by scaling its value.
+ -- -- a multiplier of 1.0 leaves the value unchanged.
+ -- hue = 1.0,
+ -- -- You can adjust the saturation also.
+ -- saturation = 1.0,
+ --},
+ window_close_confirmation = "NeverPrompt",
+ --color_scheme = 'transparent',
+ use_resize_increments = true,
+}
diff --git a/linux/home/.config/windows-terminal/settings.json b/linux/home/.config/windows-terminal/settings.json
new file mode 100644
index 0000000..71bf5bd
--- /dev/null
+++ b/linux/home/.config/windows-terminal/settings.json
@@ -0,0 +1,590 @@
+{
+ "$help": "https://aka.ms/terminal-documentation",
+ "$schema": "https://aka.ms/terminal-profiles-schema",
+ "actions":
+ [
+ { "command": "scrollDownPage", "keys": "ctrl+shift+pgdn" },
+ { "command": "unbound", "keys": "ctrl+v" },
+ { "command": "unbound", "keys": "ctrl+c" },
+ { "command": { "action": "copy", "singleLine": false } },
+ { "command": { "action": "scrollUp" }, "keys": "ctrl+shift+up" },
+ { "command": "find", "keys": "ctrl+shift+f" },
+ { "command": "paste" },
+
+ { "command": { "action": "splitPane", "split": "vertical", "splitMode": "duplicate" }, "keys": "alt+shift+plus" },
+ { "command": { "action": "splitPane", "split": "horizontal", "splitMode": "duplicate" }, "keys": "alt+shift+-" },
+
+ { "command": { "action": "nextTab", "tabSwitcherMode": "mru" }, "keys": "ctrl+tab" },
+ { "command": "openTabRenamer", "keys": "ctrl+shift+r" },
+
+ { "command": { "action": "splitPane", "split": "auto", "splitMode": "duplicate" }, "keys": "alt+shift+d" },
+ { "command": { "action": "scrollDown" }, "keys": "ctrl+shift+down" },
+
+ { "command": "scrollUpPage", "keys": "ctrl+shift+pgup" },
+
+ { "command": { "action": "moveFocus", "direction": "left" }, "keys": "alt+h" },
+ { "command": { "action": "moveFocus", "direction": "down" }, "keys": "alt+j" },
+ { "command": { "action": "moveFocus", "direction": "up" }, "keys": "alt+k" },
+ { "command": { "action": "moveFocus", "direction": "right" }, "keys": "alt+l" },
+
+ { "command": { "action": "resizePane", "direction": "left" }, "keys": "alt+shift+y" },
+ { "command": { "action": "resizePane", "direction": "down" }, "keys": "alt+shift+u" },
+ { "command": { "action": "resizePane", "direction": "up" }, "keys": "alt+shift+i" },
+ { "command": { "action": "resizePane", "direction": "right" }, "keys": "alt+shift+o" },
+
+ { "command": { "action": "swapPane", "direction": "left" }, "keys": "alt+shift+h" },
+ { "command": { "action": "swapPane", "direction": "down" }, "keys": "alt+shift+j" },
+ { "command": { "action": "swapPane", "direction": "up" }, "keys": "alt+shift+k" },
+ { "command": { "action": "swapPane", "direction": "right" }, "keys": "alt+shift+l" },
+
+ { "command": "togglePaneZoom", "keys": "alt+f" }
+ ],
+ "copyFormatting": "none",
+ "copyOnSelect": false,
+ "defaultProfile": "{f19ccc1d-fe9a-4e79-ad18-49276786d144}",
+ "launchMode": "default",
+ "profiles":
+ {
+ "defaults":
+ {
+ "backgroundImage": null,
+ "colorScheme": "Gruvbox Dark",
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "historySize": 9001,
+ "opacity": 100,
+ "padding": "0",
+ "snapOnInput": false,
+ "useAcrylic": false,
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ "list":
+ [
+ {
+ "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\download3.jpg",
+ "backgroundImageOpacity": 0.089999999999999997,
+ "colorScheme": "Tokyo Night",
+ "commandline": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
+ "experimental.retroTerminalEffect": false,
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{f19ccc1d-fe9a-4e79-ad18-49276786d144}",
+ "historySize": 99999,
+ "icon": "ms-appx:///ProfileIcons/pwsh.png",
+ "name": "PowerShell 7 - BG",
+ "opacity": 100,
+ "padding": "0",
+ "scrollbarState": "visible",
+ "startingDirectory": "%USERPROFILE%",
+ "suppressApplicationTitle": false,
+ "useAcrylic": false,
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\photo-1533484306792-cf313c2b8ab0 (2).jpg",
+ "backgroundImageOpacity": 0.19,
+ "bellStyle": "taskbar",
+ "colorScheme": "Tokyo Night",
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}",
+ "hidden": false,
+ "historySize": 99999,
+ "name": "Ubuntu-20.04",
+ "source": "Windows.Terminal.Wsl",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "guid": "{f9ceaf27-504c-58d7-927c-d1d6a7ac7d3c}",
+ "hidden": false,
+ "backgroundImage": "C:\\Users\\srdusr\\wallpapers\\photo-1533484306792-cf313c2b8ab0 (2).jpg",
+ "backgroundImageOpacity": 0.19,
+ "name": "Ubuntu 22.04.1 LTS",
+ "source": "CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc",
+ "colorScheme": "Tokyo Night",
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
+ "hidden": false,
+ "historySize": 99999,
+ "name": "PowerShell 7 - NO BG",
+ "padding": "0",
+ "source": "Windows.Terminal.PowershellCore",
+ "suppressApplicationTitle": false,
+ "useAcrylic": false,
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
+ "hidden": false,
+ "historySize": 99999,
+ "name": "Command Prompt",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
+ "hidden": false,
+ "historySize": 99999,
+ "name": "PowerShell 5",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{46ca431a-3a87-5fb3-83cd-11ececc031d2}",
+ "hidden": false,
+ "name": "Kali Linux",
+ "source": "Windows.Terminal.Wsl",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
+ "hidden": false,
+ "historySize": 99999,
+ "name": "Azure Cloud Shell",
+ "source": "Windows.Terminal.Azure",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "backgroundImage": null,
+ "backgroundImageOpacity": 0.29999999999999999,
+ "commandline": "C:\\GBox\\Applications\\Tools\\Applications\\Neovim\\nvim-win64\\0.6.0\\bin\\nvim.exe",
+ "font":
+ {
+ "face": "CaskaydiaCove NF"
+ },
+ "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6102}",
+ "hidden": false,
+ "historySize": 99999,
+ "name": "Neovim",
+ "padding": "0",
+ "useAcrylic": false,
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "guid": "{d701ea23-d39a-51a9-9966-855f1c8051f1}",
+ "hidden": false,
+ "name": "Developer Command Prompt for VS 2022 [Preview]",
+ "source": "Windows.Terminal.VisualStudio",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "guid": "{960e8c7a-d53d-5f77-ad6f-daf9dfeb597d}",
+ "hidden": false,
+ "name": "Developer PowerShell for VS 2022 [Preview]",
+ "source": "Windows.Terminal.VisualStudio",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "guid": "{fddd4872-371a-5869-85aa-657716af07fa}",
+ "hidden": true,
+ "name": "Developer Command Prompt for VS 2022",
+ "source": "Windows.Terminal.VisualStudio",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ },
+ {
+ "guid": "{e1c4148c-0ee2-5cd8-802c-8a170e188519}",
+ "hidden": true,
+ "name": "Developer PowerShell for VS 2022",
+ "source": "Windows.Terminal.VisualStudio",
+ "closeOnExit":"graceful",
+ "intenseTextStyle": "all"
+ }
+ ]
+ },
+ "schemes":
+ [
+ {
+ "background": "#0C0C0C",
+ "black": "#0C0C0C",
+ "blue": "#0037DA",
+ "brightBlack": "#767676",
+ "brightBlue": "#3B78FF",
+ "brightCyan": "#61D6D6",
+ "brightGreen": "#16C60C",
+ "brightPurple": "#B4009E",
+ "brightRed": "#E74856",
+ "brightWhite": "#F2F2F2",
+ "brightYellow": "#F9F1A5",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#3A96DD",
+ "foreground": "#CCCCCC",
+ "green": "#13A10E",
+ "name": "Campbell",
+ "purple": "#881798",
+ "red": "#C50F1F",
+ "selectionBackground": "#FFFFFF",
+ "white": "#CCCCCC",
+ "yellow": "#C19C00"
+ },
+ {
+ "background": "#012456",
+ "black": "#0C0C0C",
+ "blue": "#0037DA",
+ "brightBlack": "#767676",
+ "brightBlue": "#3B78FF",
+ "brightCyan": "#61D6D6",
+ "brightGreen": "#16C60C",
+ "brightPurple": "#B4009E",
+ "brightRed": "#E74856",
+ "brightWhite": "#F2F2F2",
+ "brightYellow": "#F9F1A5",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#3A96DD",
+ "foreground": "#CCCCCC",
+ "green": "#13A10E",
+ "name": "Campbell Powershell",
+ "purple": "#881798",
+ "red": "#C50F1F",
+ "selectionBackground": "#FFFFFF",
+ "white": "#CCCCCC",
+ "yellow": "#C19C00"
+ },
+ {
+ "background": "#282828",
+ "black": "#282828",
+ "blue": "#458588",
+ "brightBlack": "#928374",
+ "brightBlue": "#83A598",
+ "brightCyan": "#8EC07C",
+ "brightGreen": "#B8BB26",
+ "brightPurple": "#D3869B",
+ "brightRed": "#FB4934",
+ "brightWhite": "#EBDBB2",
+ "brightYellow": "#FABD2F",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#689D6A",
+ "foreground": "#EBDBB2",
+ "green": "#98971A",
+ "name": "Gruvbox Dark",
+ "purple": "#B16286",
+ "red": "#CC241D",
+ "selectionBackground": "#FFFFFF",
+ "white": "#A89984",
+ "yellow": "#D79921"
+ },
+ {
+ "background": "#282C34",
+ "black": "#282C34",
+ "blue": "#61AFEF",
+ "brightBlack": "#5A6374",
+ "brightBlue": "#61AFEF",
+ "brightCyan": "#56B6C2",
+ "brightGreen": "#98C379",
+ "brightPurple": "#C678DD",
+ "brightRed": "#E06C75",
+ "brightWhite": "#DCDFE4",
+ "brightYellow": "#E5C07B",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#56B6C2",
+ "foreground": "#DCDFE4",
+ "green": "#98C379",
+ "name": "One Half Dark",
+ "purple": "#C678DD",
+ "red": "#E06C75",
+ "selectionBackground": "#FFFFFF",
+ "white": "#DCDFE4",
+ "yellow": "#E5C07B"
+ },
+ {
+ "background": "#282C34",
+ "black": "#282C34",
+ "blue": "#61AFEF",
+ "brightBlack": "#282C34",
+ "brightBlue": "#61AFEF",
+ "brightCyan": "#56B6C2",
+ "brightGreen": "#98C379",
+ "brightPurple": "#C678DD",
+ "brightRed": "#E06C75",
+ "brightWhite": "#DCDFE4",
+ "brightYellow": "#E5C07B",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#56B6C2",
+ "foreground": "#DCDFE4",
+ "green": "#98C379",
+ "name": "One Half Dark2",
+ "purple": "#C678DD",
+ "red": "#E06C75",
+ "selectionBackground": "#FFFFFF",
+ "white": "#DCDFE4",
+ "yellow": "#E5C07B"
+ },
+ {
+ "background": "#FAFAFA",
+ "black": "#383A42",
+ "blue": "#0184BC",
+ "brightBlack": "#4F525D",
+ "brightBlue": "#61AFEF",
+ "brightCyan": "#56B5C1",
+ "brightGreen": "#98C379",
+ "brightPurple": "#C577DD",
+ "brightRed": "#DF6C75",
+ "brightWhite": "#FFFFFF",
+ "brightYellow": "#E4C07A",
+ "cursorColor": "#4F525D",
+ "cyan": "#0997B3",
+ "foreground": "#383A42",
+ "green": "#50A14F",
+ "name": "One Half Light",
+ "purple": "#A626A4",
+ "red": "#E45649",
+ "selectionBackground": "#FFFFFF",
+ "white": "#FAFAFA",
+ "yellow": "#C18301"
+ },
+ {
+ "background": "#FAFAFA",
+ "black": "#383A42",
+ "blue": "#0184BC",
+ "brightBlack": "#383A42",
+ "brightBlue": "#0184BC",
+ "brightCyan": "#0997B3",
+ "brightGreen": "#50A14F",
+ "brightPurple": "#A626A4",
+ "brightRed": "#E45649",
+ "brightWhite": "#FAFAFA",
+ "brightYellow": "#C18401",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#0997B3",
+ "foreground": "#383A42",
+ "green": "#50A14F",
+ "name": "One Half Light2",
+ "purple": "#A626A4",
+ "red": "#E45649",
+ "selectionBackground": "#FFFFFF",
+ "white": "#FAFAFA",
+ "yellow": "#C18401"
+ },
+ {
+ "background": "#002B36",
+ "black": "#002B36",
+ "blue": "#268BD2",
+ "brightBlack": "#073642",
+ "brightBlue": "#839496",
+ "brightCyan": "#93A1A1",
+ "brightGreen": "#586E75",
+ "brightPurple": "#6C71C4",
+ "brightRed": "#CB4B16",
+ "brightWhite": "#FDF6E3",
+ "brightYellow": "#657B83",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#2AA198",
+ "foreground": "#839496",
+ "green": "#859900",
+ "name": "Solarized Dark",
+ "purple": "#D33682",
+ "red": "#DC322F",
+ "selectionBackground": "#FFFFFF",
+ "white": "#EEE8D5",
+ "yellow": "#B58900"
+ },
+ {
+ "background": "#001E27",
+ "black": "#002831",
+ "blue": "#2176C7",
+ "brightBlack": "#475B62",
+ "brightBlue": "#708284",
+ "brightCyan": "#819090",
+ "brightGreen": "#475B62",
+ "brightPurple": "#5956BA",
+ "brightRed": "#BD3613",
+ "brightWhite": "#FCF4DC",
+ "brightYellow": "#536870",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#259286",
+ "foreground": "#708284",
+ "green": "#738A05",
+ "name": "Solarized Dark - Patched",
+ "purple": "#C61C6F",
+ "red": "#D11C24",
+ "selectionBackground": "#FFFFFF",
+ "white": "#EAE3CB",
+ "yellow": "#A57706"
+ },
+ {
+ "background": "#FDF6E3",
+ "black": "#002B36",
+ "blue": "#268BD2",
+ "brightBlack": "#073642",
+ "brightBlue": "#839496",
+ "brightCyan": "#93A1A1",
+ "brightGreen": "#586E75",
+ "brightPurple": "#6C71C4",
+ "brightRed": "#CB4B16",
+ "brightWhite": "#FDF6E3",
+ "brightYellow": "#657B83",
+ "cursorColor": "#002B36",
+ "cyan": "#2AA198",
+ "foreground": "#657B83",
+ "green": "#859900",
+ "name": "Solarized Light",
+ "purple": "#D33682",
+ "red": "#DC322F",
+ "selectionBackground": "#FFFFFF",
+ "white": "#EEE8D5",
+ "yellow": "#B58900"
+ },
+ {
+ "background": "#000000",
+ "black": "#000000",
+ "blue": "#3465A4",
+ "brightBlack": "#555753",
+ "brightBlue": "#729FCF",
+ "brightCyan": "#34E2E2",
+ "brightGreen": "#8AE234",
+ "brightPurple": "#AD7FA8",
+ "brightRed": "#EF2929",
+ "brightWhite": "#EEEEEC",
+ "brightYellow": "#FCE94F",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#06989A",
+ "foreground": "#D3D7CF",
+ "green": "#4E9A06",
+ "name": "Tango Dark",
+ "purple": "#75507B",
+ "red": "#CC0000",
+ "selectionBackground": "#FFFFFF",
+ "white": "#D3D7CF",
+ "yellow": "#C4A000"
+ },
+ {
+ "background": "#FFFFFF",
+ "black": "#000000",
+ "blue": "#3465A4",
+ "brightBlack": "#555753",
+ "brightBlue": "#729FCF",
+ "brightCyan": "#34E2E2",
+ "brightGreen": "#8AE234",
+ "brightPurple": "#AD7FA8",
+ "brightRed": "#EF2929",
+ "brightWhite": "#EEEEEC",
+ "brightYellow": "#FCE94F",
+ "cursorColor": "#000000",
+ "cyan": "#06989A",
+ "foreground": "#555753",
+ "green": "#4E9A06",
+ "name": "Tango Light",
+ "purple": "#75507B",
+ "red": "#CC0000",
+ "selectionBackground": "#FFFFFF",
+ "white": "#D3D7CF",
+ "yellow": "#C4A000"
+ },
+ {
+ "background": "#1A1B2C",
+ "black": "#414868",
+ "blue": "#7AA2F7",
+ "brightBlack": "#414868",
+ "brightBlue": "#7AA2F7",
+ "brightCyan": "#7DCFFF",
+ "brightGreen": "#73DACA",
+ "brightPurple": "#BB9AF7",
+ "brightRed": "#F7768E",
+ "brightWhite": "#C0CAF5",
+ "brightYellow": "#E0AF68",
+ "cursorColor": "#C0CAF5",
+ "cyan": "#7DCFFF",
+ "foreground": "#A9B1DC",
+ "green": "#73DACA",
+ "name": "Tokyo Night",
+ "purple": "#BB9AF7",
+ "red": "#F7768E",
+ "selectionBackground": "#28344A",
+ "white": "#C0CAF5",
+ "yellow": "#E0AF68"
+ },
+ {
+ "background": "#24283B",
+ "black": "#414868",
+ "blue": "#7AA2F7",
+ "brightBlack": "#414868",
+ "brightBlue": "#7AA2F7",
+ "brightCyan": "#7DCFFF",
+ "brightGreen": "#73DACA",
+ "brightPurple": "#BB9AF7",
+ "brightRed": "#F7768E",
+ "brightWhite": "#C0CAF5",
+ "brightYellow": "#E0AF68",
+ "cursorColor": "#C0CAF5",
+ "cyan": "#7DCFFF",
+ "foreground": "#A9B1DC",
+ "green": "#73DACA",
+ "name": "Tokyo Night Storm",
+ "purple": "#BB9AF7",
+ "red": "#F7768E",
+ "selectionBackground": "#28344A",
+ "white": "#C0CAF5",
+ "yellow": "#E0AF68"
+ },
+ {
+ "background": "#000000",
+ "black": "#000000",
+ "blue": "#000080",
+ "brightBlack": "#808080",
+ "brightBlue": "#0000FF",
+ "brightCyan": "#00FFFF",
+ "brightGreen": "#00FF00",
+ "brightPurple": "#FF00FF",
+ "brightRed": "#FF0000",
+ "brightWhite": "#FFFFFF",
+ "brightYellow": "#FFFF00",
+ "cursorColor": "#FFFFFF",
+ "cyan": "#008080",
+ "foreground": "#C0C0C0",
+ "green": "#008000",
+ "name": "Vintage",
+ "purple": "#800080",
+ "red": "#800000",
+ "selectionBackground": "#FFFFFF",
+ "white": "#C0C0C0",
+ "yellow": "#808000"
+ }
+ ],
+ "showTabsInTitlebar": true,
+ "showTerminalTitleInTitlebar": true,
+ "tabWidthMode": "titleLength",
+ "trimBlockSelection": true,
+ "useAcrylicInTabRow": false
+}
diff --git a/linux/home/.config/wofi/config b/linux/home/.config/wofi/config
new file mode 100644
index 0000000..d1ea4c8
--- /dev/null
+++ b/linux/home/.config/wofi/config
@@ -0,0 +1,17 @@
+width=420
+height=550
+location=center
+show=drun
+matching=fuzzy
+prompt=Search...
+filter_rate=100
+allow_markup=true
+no_actions=true
+halign=fill
+orientation=vertical
+content_halign=fill
+insensitive=true
+allow_images=true
+image_size=28
+gtk_dark=false
+term=kitty
diff --git a/linux/home/.config/wofi/style.css b/linux/home/.config/wofi/style.css
new file mode 100644
index 0000000..6fb5107
--- /dev/null
+++ b/linux/home/.config/wofi/style.css
@@ -0,0 +1,99 @@
+* {
+ transition: 0.2s;
+}
+
+window {
+ font-family: "FiraCode Nerd Font Mono";
+ font-size: 13px;
+}
+
+window {
+ margin: 0px;
+ border: 2px solid #cba6f7;
+/*
+ background-color: #161925;
+*/
+ background-color: transparent;
+ border-radius: 16px;
+}
+
+#input {
+ padding: 4px;
+ margin: 20px;
+ padding-left: 20px;
+ border: none;
+ color: #fff;
+ font-weight: bold;
+ background: linear-gradient(90deg, #cba6f7 0%, #94e2d5 100%);
+ outline: none;
+ border-radius: 16px;
+}
+
+#input image {
+ color: #fff;
+}
+
+#input:focus {
+ border: none;
+ outline: none;
+}
+
+#inner-box {
+ margin: 20px;
+ margin-top: 0px;
+ border: none;
+ color: #cba6f7;
+ border-radius: 16px;
+}
+
+#inner-box * {
+ transition: none;
+}
+
+#outer-box {
+ margin: 0px;
+ border: none;
+ padding: 0px;
+ border-radius: 16px;
+}
+
+#scroll {
+ margin-top: 5px;
+ border: none;
+ border-radius: 16px;
+ margin-bottom: 5px;
+}
+
+#text:selected {
+ color: #fff;
+ font-weight: bold;
+}
+
+#img {
+ margin-right: 20px;
+ background: transparent;
+}
+
+#text {
+ margin: 0px;
+ border: none;
+ padding: 0px;
+ background: transparent;
+}
+
+#entry {
+ margin: 0px;
+ border: none;
+ border-radius: 16px;
+ background-color: transparent;
+ min-height:32px;
+ font-weight: bold;
+}
+
+#entry:selected {
+ outline: none;
+ margin: 0px;
+ border: none;
+ border-radius: 16px;
+ background: linear-gradient(90deg, #cba6f7 0%, #94e2d5 100%);
+}
diff --git a/linux/home/.config/xkb/symbols/custom-us b/linux/home/.config/xkb/symbols/custom-us
new file mode 100644
index 0000000..9faa2e9
--- /dev/null
+++ b/linux/home/.config/xkb/symbols/custom-us
@@ -0,0 +1,27 @@
+// Clear existing modifiers
+//default partial modifier_keys
+partial alphanumeric_keys
+xkb_symbols "basic" {
+ include "us(basic)"
+
+ // Define a custom modifier (Mode_switch)
+ modifier_map Mod5 { <MDSW> };
+
+ // Remap Caps Lock to AltGr (ISO_Level3_Shift) and clear other modifiers
+ key <CAPS> {
+ type[Group1] = "ONE_LEVEL",
+ symbols[Group1] = [ ISO_Level3_Shift ],
+ actions[Group1] = [ SetMods(modifiers=Mod5) ]
+ };
+
+ // Remap h, j, k, l to arrow keys when Mode_switch is active and clear other modifiers
+ key <AC06> { [ h, H, Left ] };
+ key <AC07> { [ j, J, Down ] };
+ key <AC08> { [ k, K, Up ] };
+ key <AC09> { [ l, L, Right ] };
+
+ key <AD02> { [ w, W, Up ] };
+ key <AC01> { [ a, A, Left ] };
+ key <AC02> { [ s, S, Down ] };
+ key <AC03> { [ d, D, Right ] };
+};
diff --git a/linux/home/.config/xob/launch.sh b/linux/home/.config/xob/launch.sh
new file mode 100755
index 0000000..46d4861
--- /dev/null
+++ b/linux/home/.config/xob/launch.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+killall -q xob
+pkill -f manage-volume
+pkill -f manage-brightness
+pkill -f manage-microphone
+
+"$HOME"/.config/xob/manage-volume | xob -s default &
+"$HOME"/.config/xob/manage-brightness | xob -s default &
+"$HOME"/.config/xob/manage-microphone | xob -s default &
diff --git a/linux/home/.config/xob/manage-brightness b/linux/home/.config/xob/manage-brightness
new file mode 100755
index 0000000..496900f
--- /dev/null
+++ b/linux/home/.config/xob/manage-brightness
@@ -0,0 +1,16 @@
+#!/bin/node
+
+const fs = require('fs')
+const { exec } = require("child_process");
+
+let device = "intel_backlight";
+
+brightnessFile = `/sys/class/backlight/${device}/brightness`;
+maxBrightnessFile = `/sys/class/backlight/${device}/max_brightness`;
+
+maxValue = parseInt(fs.readFileSync(maxBrightnessFile, 'utf8'));
+
+fs.watch(brightnessFile, () => {
+ value = parseInt(fs.readFileSync(brightnessFile, 'utf8'));
+ console.log(Math.round(value / maxValue * 100));
+})
diff --git a/linux/home/.config/xob/manage-microphone b/linux/home/.config/xob/manage-microphone
new file mode 100755
index 0000000..3bf5972
--- /dev/null
+++ b/linux/home/.config/xob/manage-microphone
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+
+import sys
+
+from pulsectl import Pulse, PulseLoopStop
+
+
+def callback(ev):
+ if ev.index == source_index:
+ raise PulseLoopStop
+
+
+def current_status(source):
+ return round(source.volume.value_flat * 100), source.mute == 1
+
+
+def get_default_source_idx():
+ default_source_name = pulse.server_info().default_source_name
+ try:
+ source_index = next(index for index, source in sources.items()
+ if source.name == default_source_name)
+ return source_index
+ except StopIteration:
+ raise StopIteration("No default source was found.")
+
+
+try:
+ with Pulse() as pulse:
+ sources = {s.index: s for s in pulse.source_list()}
+
+ if len(sys.argv) > 1:
+ # Source index from command line argument if provided
+ source_index = int(sys.argv[1])
+ if source_index not in sources:
+ raise KeyError(
+ f"Source index {source_index} not found in list of sources."
+ )
+ else:
+ # Automatic determination of default source otherwise
+ source_index = get_default_source_idx()
+
+ pulse.event_mask_set('source')
+ pulse.event_callback_set(callback)
+ last_value, last_mute = current_status(sources[source_index])
+
+ while True:
+ pulse.event_listen()
+ sources = {s.index: s for s in pulse.source_list()}
+ value, mute = current_status(sources[source_index])
+ if value != last_value or mute != last_mute:
+ print(str(value) + ('!' if mute else ''))
+ last_value, last_mute = value, mute
+ sys.stdout.flush()
+
+except Exception as e:
+ print(f"ERROR: {e}", file=sys.stderr)
diff --git a/linux/home/.config/xob/manage-volume b/linux/home/.config/xob/manage-volume
new file mode 100755
index 0000000..d05a92f
--- /dev/null
+++ b/linux/home/.config/xob/manage-volume
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+
+from pulsectl import Pulse, PulseLoopStop
+import sys
+
+with Pulse() as pulse:
+ while True:
+ def callback(ev):
+ if ev.index == sink_index: raise PulseLoopStop
+
+ def current_status(sink):
+ return round(sink.volume.value_flat * 100), sink.mute == 1
+
+ def get_default_sink_idx():
+ default_sink_name = pulse.server_info().default_sink_name
+ try:
+ sink_index = next(index for index,sink in sinks.items() if sink.name == default_sink_name)
+ return sink_index
+ except StopIteration: raise StopIteration("No default sink was found.")
+
+ try:
+ sinks = {s.index:s for s in pulse.sink_list()}
+ if len(sys.argv) > 1:
+ # Sink index from command line argument if provided
+ sink_index = int(sys.argv[1])
+ if not sink_index in sinks:
+ raise KeyError(f"Sink index {sink_index} not found in list of sinks.")
+ else:
+ # Automatic determination of default sink otherwise
+ sink_index = get_default_sink_idx()
+
+ pulse.event_mask_set('sink')
+ pulse.event_callback_set(callback)
+ last_value, last_mute = current_status(sinks[sink_index])
+
+ while True:
+ pulse.event_listen()
+ sinks = {s.index:s for s in pulse.sink_list()}
+ value, mute = current_status(sinks[sink_index])
+ if value != last_value or mute != last_mute:
+ print(str(value) + ('!' if mute else ''))
+ last_value, last_mute = value, mute
+ sys.stdout.flush()
+
+ except Exception as e:
+ print(f"ERROR: {e}", file=sys.stderr)
diff --git a/linux/home/.config/xob/styles.cfg b/linux/home/.config/xob/styles.cfg
new file mode 100644
index 0000000..d236ff8
--- /dev/null
+++ b/linux/home/.config/xob/styles.cfg
@@ -0,0 +1,100 @@
+#vol = {
+# x = {relative = 1 ;offset = 88}
+# y = {relative = 0 ;offset = 32}
+# length = {relative = 0; offset = 0;};
+# padding = 0;
+# border = 0;
+# outline = 0;
+# thickness = 20;
+# orientation = "vertical"
+# color = {
+# normal = {
+# fg = "#ffffff";
+# bg = "#000000";
+# border = "#ffffff";
+# };
+# alt = {
+# fg = "#dc322f";
+# bg = "#000000";
+# border = "#dc322f";
+# };
+# overflow = {
+# fg = "#555555";
+# bg = "#000000";
+# border = "#555555";
+# };
+# altoverflow = {
+# fg = "#550000";
+# bg = "#000000";
+# border = "#550000";
+# };
+# };
+#};
+#
+#brightness = {
+# x = {relative = 1 ;offset = 88}
+# y = {relative = 0 ;offset = 88}
+# length = {relative = 0; offset = 0;};
+# padding = 0;
+# border = 0;
+# outline = 0;
+# thickness = 20;
+# orientation = "vertical"
+# color = {
+# normal = {
+# fg = "#ffffff";
+# bg = "#000000";
+# border = "#ffffff";
+# };
+# alt = {
+# fg = "#dc322f";
+# bg = "#000000";
+# border = "#dc322f";
+# };
+# overflow = {
+# fg = "#555555";
+# bg = "#000000";
+# border = "#555555";
+# };
+# altoverflow = {
+# fg = "#550000";
+# bg = "#000000";
+# border = "#550000";
+# };
+# };
+#};
+default = {
+ x = {relative = 1; offset = -48;};
+ y = {relative = 0.5; offset = 0;};
+ length = {relative = 0.3; offset = 0;};
+ thickness = 24;
+ outline = 3;
+ border = 4;
+ padding = 3;
+ orientation = "vertical";
+
+ overflow = "proportional";
+
+ color = {
+ normal = {
+ fg = "#ffffff";
+ bg = "#00000090";
+ border = "#ffffff";
+ };
+ alt = {
+ fg = "#555555";
+ bg = "#00000090";
+ border = "#555555";
+ };
+ overflow = {
+ fg = "#ff0000";
+ bg = "#00000090";
+ border = "#ff0000";
+ };
+ altoverflow = {
+ fg = "#550000";
+ bg = "#00000090";
+ border = "#550000";
+ };
+ };
+};
diff --git a/linux/home/.config/zathura/zathurarc b/linux/home/.config/zathura/zathurarc
new file mode 100644
index 0000000..78d66a1
--- /dev/null
+++ b/linux/home/.config/zathura/zathurarc
@@ -0,0 +1,27 @@
+set window-title-basename "true"
+
+
+
+
+# Basic Settings
+
+set highlight-transparency .1
+set zoom-center "true"
+set selection-clipboard "clipboard"
+set render-loading "false"
+set pages-per-row 1
+set scroll-page-aware "true"
+set scroll-full-overlap 0.01
+set scroll-step 50
+set zoom-min 10
+set guioptions ""
+set render-loading "false"
+
+
+# Startup options
+set adjust-open "best-fit"
+set recolor true
+
+# Side by side view (view 2 pages like an open book)
+map D set "first-page-column 1:1"
+map <C-d> set "first-page-column 1:2"
diff --git a/linux/home/.config/zsh/.zshenv b/linux/home/.config/zsh/.zshenv
new file mode 100644
index 0000000..1d6eee9
--- /dev/null
+++ b/linux/home/.config/zsh/.zshenv
@@ -0,0 +1,348 @@
+# Load local/system wide binaries and scripts
+export PATH=$HOME/.bin:$HOME/.local/bin:$HOME/.scripts:$HOME/.scripts/test:/usr/local/bin:/sbin:/usr/sbin:$PATH
+export PATH="/data/data/com.termux/files/usr/local/bin:$PATH"
+
+if [ -d "$HOME/.scripts" ]; then
+ for d in "$HOME/.scripts"/*; do
+ [ -d "$d" ] && PATH="$PATH:$d"
+ done
+fi
+
+#export PATH
+
+export TERM=xterm-256color
+# Skip the not really helpful global compinit
+skip_global_compinit=1
+
+#export WINEARCH=win64 #<or win32>
+#export WINEPREFIX=~/.wine
+#export PATH=$PATH:/usr/bin/wine
+#winetricks vcrun2019
+### Conditionally set WM(window manager)
+#available_wms=("bspwm" "mutter" "i3")
+#for wm in "${available_wms[@]}"; do
+# if command -v "$wm" &> /dev/null; then
+# export WM="$wm"
+# break
+# fi
+#done
+
+## Set a flag to indicate if the display server type is found
+#display_server_found=0
+#
+## Conditionally set Display server
+#available_displays=("wayland" "x11")
+#for display in "${available_displays[@]}"; do
+# if [ "$WAYLAND_DISPLAY" = "$display" ]; then
+# export XDG_SESSION_TYPE="$display"
+# display_server_found=1
+# break
+# fi
+#done
+#
+## Check if XDG_SESSION_TYPE is "x11" and set X11-specific variables
+#if [ "$display_server_found" -eq 1 ] && [ "$XDG_SESSION_TYPE" == "x11" ]; then
+# # X11-specific variables
+# export XINITRC="$HOME/.config/X11/.xinitrc"
+# export XSERVERRC="$XDG_CONFIG_HOME/X11/xserverrc"
+# export USERXSESSION="$XDG_CONFIG_HOME/X11/xsession"
+# export USERXSESSIONRC="$XDG_CONFIG_HOME/X11/xsessionrc"
+# export ALTUSERXSESSION="$XDG_CONFIG_HOME/X11/Xsession"
+# export ERRFILE="$XDG_CONFIG_HOME/X11/xsession-errors"
+# export ICEAUTHORITY="$XDG_CACHE_HOME/.ICEauthority"
+#fi
+
+# Conditionally set default term
+available_terms=("wezterm" "alacritty" "xterm")
+for term in "${available_terms[@]}"; do
+ if command -v "$term" &> /dev/null; then
+ export TERMINAL="$term"
+ break
+ fi
+done
+
+# Default Programs:
+export EDITOR=$(command -v nvim || echo "vim")
+#if command -v nvim &> /dev/null; then
+# export EDITOR=nvim
+#else
+# export EDITOR=vim
+#fi
+export VISUAL=$EDITOR
+export GIT_EDITOR="$EDITOR"
+export COLORTERM="truecolor"
+export TERM="xterm-256color"
+export READER="zathura"
+export BROWSER="firefox"
+export OPENER="xdg-open"
+#export MANPAGER="$EDITOR +Man!"
+#if [ "$EDITOR" = "nvim" ]; then
+if command -v nvim &> /dev/null; then
+ #export MANPAGER="sh -c 'col -b | nvim -c \"set ft=man ts=8 nomod nolist nonu noma\" -c \"autocmd VimEnter * call feedkeys(\\\"q\\\")\" -'"
+ export MANPAGER="sh -c 'col -b | nvim -c \"set ft=man ts=8 nomod nolist nonu noma\" -c \"autocmd VimEnter * call feedkeys(\\\"\\<CR>q\\\")\" -'"
+ #export MANPAGER="$nvim --clean -n -i NONE -u NORC -c 'colorscheme desert' -c 'highlight Normal ctermbg=NONE guibg=NONE' +Man\!"
+else
+ export MANPAGER="bat"
+ #export MANPAGER="less -R --use-color -Dd+r -Du+b"
+ #export MANPAGER="sh -c 'col -bx | bat -l man -p --pager \"less -R\"'"
+fi
+export MANROFFOPT="-c"
+export PAGER="less"
+export SUDO_ASKPASS=/usr/lib/ssh/x11-ssh-askpass
+export FAQ_STYLE='github'
+export VIDEO="mpv"
+export IMAGE="phototonic"
+
+# XDG Paths:
+export XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
+export XDG_DATA_HOME=${XDG_DATA_HOME:-$HOME/.local/share}
+export XDG_CACHE_HOME=${XDG_CACHE_HOME:-$HOME/.cache}
+export INPUTRC="${XDG_CONFIG_HOME:-$HOME/.config}/inputrc"
+export ZDOTDIR="$XDG_CONFIG_HOME/zsh"
+export HISTFILE="$ZDOTDIR/.zhistory" # History filepath
+export HISTSIZE=1000000 # Maximum events for internal history
+export SAVEHIST=1000000 # Maximum events in history file
+export BANG_HIST # Treat the '!' character specially during expansion.
+export EXTENDED_HISTORY # Write the history file in the ":start:elapsed;command" format.
+export INC_APPEND_HISTORY # Write to the history file immediately, not when the shell exits.
+export SHARE_HISTORY # Share history between all sessions.
+export HIST_EXPIRE_DUPS_FIRST # Expire duplicate entries first when trimming history.
+export HIST_IGNORE_DUPS # Don't record an entry that was just recorded again.
+export HIST_IGNORE_ALL_DUPS # Delete old recorded entry if new entry is a duplicate.
+export HIST_FIND_NO_DUPS # Do not display a line previously found.
+export HIST_IGNORE_SPACE # Don't record an entry starting with a space.
+export HIST_SAVE_NO_DUPS # Don't write duplicate entries in the history file.
+export HIST_REDUCE_BLANKS # Remove superfluous blanks before recording entry.
+export HIST_VERIFY # Don't execute immediately upon history expansion.
+export HIST_BEEP # Beep when accessing nonexistent history.
+export INC_APPEND_HISTORY
+
+# Customize `ls` colours
+export LSCOLORS=ExGxBxDxCxEgEdxbxgxcxd
+
+# Other XDG paths:
+export RIPGREP_CONFIG_PATH="$XDG_CONFIG_HOME/ripgrep/ripgreprc"
+export DOCKER_CONFIG="$XDG_CONFIG_HOME/docker"
+export VSCODE_PORTABLE="$XDG_DATA_HOME/vscode"
+export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc"
+export PATH="/usr/bin/cmake:$PATH"
+export PATH=$PATH:/opt/google/chrome
+export DISCORD_USER_DATA_DIR="$XDG_DATA_HOME"
+export LYNX_CFG="$XDG_CONFIG_HOME/.lynxrc"
+
+# Manage Arch linux build sources
+export ASPROOT="${XDG_CACHE_HOME:-$HOME/.cache}/asp"
+
+# Homebrew
+#export PATH=/opt/homebrew/bin:$PATH
+export PATH="/opt/homebrew/sbin:$PATH"
+
+# Nix-profile
+export PATH=$HOME/.nix-profile/bin:$PATH
+
+# GnuPG
+export GPG_TTY=$(tty)
+#export GNUPGHOME="$XDG_CONFIG_HOME/gnupg"
+
+# Nvim
+export NVIM_TUI_ENABLE_TRUE_COLOR=1
+
+# Fzf
+export FZF_DEFAULT_COMMAND="rg --files --hidden --glob '!{node_modules/*,.git/*}'"
+export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
+export FZF_DEFAULT_OPTS='-m --height 50% --border'
+
+
+# enable git scripts
+export DEVELOPMENT_DIRECTORY="$HOME/code"
+
+# Android Home
+export ANDROID_HOME=/opt/android-sdk
+export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$PATH
+#export PATH=$ANDROID_HOME/cmdline-tools/bin:$PATH
+export PATH=$ANDROID_HOME/tools:$PATH
+export PATH=$ANDROID_HOME/tools/bin:$PATH
+export PATH=$ANDROID_HOME/platform-tools:$PATH
+# Android emulator PATH
+export PATH=$ANDROID_HOME/emulator:$PATH
+# Android SDK ROOT PATH
+export ANDROID_SDK_ROOT=/opt/android-sdk
+export PATH=$ANDROID_SDK_ROOT:$PATH
+#export ANDROID_SDK_HOME="${XDG_CONFIG_HOME:-$HOME/.config}/android"
+
+# Programming Environment Variables:
+
+# Rust
+export RUSTUP_HOME=${XDG_DATA_HOME:-$HOME/.local/share}/rustup
+export CARGO_HOME=${XDG_DATA_HOME:-$HOME/.local/share}/cargo
+export PATH="${CARGO_HOME}/bin:${RUSTUP_HOME}/bin:$PATH"
+#export PATH="$PATH:$CARGO_HOME/bin"
+#[[ -d $CARGO_HOME/bin ]] && path=($CARGO_HOME/bin $path)
+if which rustc > /dev/null; then export RUST_BACKTRACE=1; fi
+#export PATH="$HOME/.cargo/bin:$PATH"
+#export CARGO_HOME=${XDG_DATA_HOME}/cargo
+#export RUSTUP_HOME=${XDG_DATA_HOME}/rustup
+
+
+# Dotnet
+# # Currently dotnet does not support XDG ( https://github.com/dotnet/sdk/issues/10390 )
+#export DOTNET_TOOLS_DIR="$HOME/.dotnet/tools"
+export DOTNET_HOME=${XDG_DATA_HOME:-$HOME/.local/share}/dotnet
+export DOTNET_CLI_HOME="$XDG_CONFIG_HOME/dotnet"
+#mkdir -p "$DOTNET_CLI_HOME";
+export PATH="$PATH":"$DOTNET_HOME"/tools
+export DOTNET_ROOT=/opt/dotnet
+# Disable telemetry for dotnet apps
+export DOTNET_CLI_TELEMETRY_OPTOUT=1
+
+
+# Java
+#export JAVA_HOME=/usr/lib/jvm/default-java
+#export JAVA_HOME='/usr/lib/jvm/java-8-openjdk'
+#export JAVA_HOME='/usr/lib/jvm/java-10-openjdk'
+#export JAVA_HOME='/usr/lib/jvm/java-11-openjdk'
+#export JAVA_HOME='/usr/lib/jvm/java-17-openjdk'
+export JAVA_HOME='/usr/lib/jvm/java-20-openjdk'
+#export PATH=$JAVA_HOME/bin:$PATH
+export _JAVA_OPTIONS=-Djava.util.prefs.userRoot="$XDG_CONFIG_HOME"/java
+#export DEFAULT_JVM_OPTS='"-Dcom.android.sdklib.toolsdir=$APP_HOME" -XX:+IgnoreUnrecognizedVMOptions'
+#export _JAVA_AWT_WM_NONREPARENTING=1
+#export JAVA_OPTS='-XX:+IgnoreUnrecognizedVMOptions --add-modules java.se.ee'
+#export JAVA_OPTS='-XX:+IgnoreUnrecognizedVMOptions --add-modules java.xml.bind'
+#Windows:
+#set JAVA_OPTS=-XX:+IgnoreUnrecognizedVMOptions --add-modules java.se.ee
+
+
+# Dart/Flutter
+export PATH="/opt/flutter/bin:/usr/lib/dart/bin:$PATH"
+
+
+# Go
+export GO_PATH=${XDG_DATA_HOME}/go
+export GOPATH="${XDG_DATA_HOME:-$HOME/.local/share}/go"
+
+
+# Javascript
+# NVM
+export NVM_DIR="$HOME/.config/nvm"
+[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
+#[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
+
+# global node installs (gross)
+[[ -d "$XDG_DATA_HOME/node/bin" ]] && path=($XDG_DATA_HOME/node/bin $path)
+export NODE_REPL_HISTORY="$XDG_DATA_HOME"/node_repl_history
+export NPM_CONFIG_USERCONFIG=$XDG_CONFIG_HOME/npm/npmrc
+#export NPM_CONFIG_INIT_AUTHOR_NAME='srdusr'
+#export NPM_CONFIG_INIT_AUTHOR_EMAIL='trevorgray@srdusr.com'
+#export NPM_CONFIG_INIT_AUTHOR_URL='https://srdusr.com'
+#export NPM_CONFIG_INIT_LICENSE='GPL-3.0'
+#export NPM_CONFIG_INIT_VERSION='0.0.0'
+#export NPM_CONFIG_SIGN_GIT_TAG='true'
+
+# Yarn
+#if command -v yarn >/dev/null 2>&1; then
+# export PATH="$PATH:`yarn global bin`"
+#fi
+#export PATH="$(yarn global bin):$PATH"
+#YARN_PATH="$HOME/.yarn/bin"
+#YARN_BIN_EXPORT="$HOME/.config/yarn/global/node_modules/.bin"
+
+# Ruby
+export GEM_PATH="$XDG_DATA_HOME/ruby/gems"
+export GEM_SPEC_CACHE="$XDG_DATA_HOME/ruby/specs"
+export GEM_HOME="$XDG_DATA_HOME/ruby/gems"
+#if [[ -d ~/.gem/ruby ]]; then
+# ver=$(find ~/.gem/ruby/* -maxdepth 0 | sort -rV | head -n 1)
+# export PATH="$PATH:${ver}/bin"
+#fi
+
+
+# Python
+# lazy load pyenv
+#export PYENV_ROOT=${PYENV_ROOT:-$HOME/.pyenv}
+#[[ -a $PYENV_ROOT/bin/pyenv ]] && path=($PYENV_ROOT/bin $path)
+#if type pyenv &> /dev/null || [[ -a $PYENV_ROOT/bin/pyenv ]]; then
+# function pyenv() {
+# unset pyenv
+# path=($PYENV_ROOT/shims $path)
+# eval "$(command pyenv init -)"
+# if which pyenv-virtualenv-init > /dev/null; then
+# eval "$(pyenv virtualenv-init -)"
+# export PYENV_VIRTUALENV_DISABLE_PROMPT=1
+# fi
+# pyenv $@
+# }
+#fi
+#export WORKON_HOME="$XDG_DATA_HOME/virtualenvs"
+export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=`which python3`
+export VIRTUALENVWRAPPER_VIRTUALENV=`which virtualenv`
+#source /usr/local/bin/virtualenvwrapper.sh
+source $(which virtualenvwrapper.sh)
+export VIRTUAL_ENV_DISABLE_PROMPT=false
+export JUPYTER_CONFIG_DIR="$XDG_CONFIG_HOME/jupyter"
+export IPYTHONDIR="$XDG_CONFIG_HOME/jupyter"
+
+# Python
+[[ "$(uname)" == "Darwin" ]] && export PYTHON_CONFIGURE_OPTS="--enable-framework"
+[[ "$(uname)" == "Linux" ]] && export PYTHON_CONFIGURE_OPTS="--enable-shared"
+
+export PYENV_ROOT="$HOME/.pyenv"
+export PATH="$PYENV_ROOT/bin:$PATH"
+
+# PHP
+PATH="$HOME/.config/composer/vendor/bin:$PATH"
+
+
+# Lua
+export PATH=$PATH:/usr/local/luarocks/bin
+#export PATH="$XDG_DATA_HOME/luarocks/bin:$PATH"
+
+#ver=$(find lua* -maxdepth 0 | sort -rV | head -n 1)
+#export LUA_PATH="$LUA_PATH:${ver}/share/lua/5.1/?.lua;${ver}/share/lua/5.1/?/init.lua;;"
+#export LUA_CPATH="$LUA_CPATH:${ver}/lib/lua/5.1/?.so;;"
+
+#LUAROCKS_PREFIX=/usr/local
+#export LUA_PATH="$LUAROCKS_PREFIX/share/lua/5.1/?.lua;$LUAROCKS_PREFIX/share/lua/5.1/?/init.lua;;"
+#export LUA_CPATH="$LUAROCKS_PREFIX/lib/lua/5.1/?.so;;"
+
+#export LUA_PATH="<path-to-add>;;"
+#export LUA_CPATH="./?.so;/usr/local/lib/lua/5.3/?.so;
+# /usr/local/share/lua/5.3/?.so;<path-to-add>"
+
+
+# Program settings
+#export MOZ_USE_XINPUT2="1" # Mozilla smooth scrolling/touchpads.
+# Pixel-perfect Firefox touchpad scrolling
+export MOZ_USE_XINPUT2=1
+
+
+# Scaling
+#export QT_AUTO_SCREEN_SCALE_FACTOR=0
+#export QT_SCALE_FACTOR=1
+#export QT_SCREEN_SCALE_FACTORS="1;1;1"
+#export GDK_SCALE=1
+#export GDK_DPI_SCALE=1
+
+
+#typeset -U PATH path
+export GTK_IM_MODULE='fcitx'
+export QT_IM_MODULE='fcitx'
+export SDL_IM_MODULE='fcitx'
+export XMODIFIERS='@im=fcitx'
+
+
+# Start blinking
+export LESS_TERMCAP_mb=$(tput bold; tput setaf 2) # green
+# Start bold
+export LESS_TERMCAP_md=$(tput bold; tput setaf 2) # green
+# Start stand out
+export LESS_TERMCAP_so=$(tput bold; tput setaf 3) # yellow
+# End standout
+export LESS_TERMCAP_se=$(tput rmso; tput sgr0)
+# Start underline
+export LESS_TERMCAP_us=$(tput smul; tput bold; tput setaf 1) # red
+# End Underline
+export LESS_TERMCAP_ue=$(tput sgr0)
+# End bold, blinking, standout, underline
+export LESS_TERMCAP_me=$(tput sgr0).
diff --git a/linux/home/.config/zsh/.zshrc b/linux/home/.config/zsh/.zshrc
new file mode 100644
index 0000000..ececf24
--- /dev/null
+++ b/linux/home/.config/zsh/.zshrc
@@ -0,0 +1,63 @@
+
+# ███████╗███████╗██╗ ██╗██████╗ ██████╗
+# ╚══███╔╝██╔════╝██║ ██║██╔══██╗██╔════╝
+# ███╔╝ ███████╗███████║██████╔╝██║
+# ███╔╝ ╚════██║██╔══██║██╔══██╗██║
+# ███████╗███████║██║ ██║██║ ██║╚██████╗
+# ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝
+
+for zsh_source in "$HOME"/.config/zsh/user/*.zsh; do
+ source $zsh_source
+done
+
+# If not running interactively, don't do anything
+[[ $- != *i* ]] && return
+
+if [[ -n "$SSH_CLIENT" ]]; then
+ export KEYTIMEOUT=10
+else
+ export KEYTIMEOUT=15
+fi
+
+# Tmux default session
+if command -v tmux &> /dev/null && [ -n "$PS1" ] && [ -z "$DISPLAY" ] && [ -z "$TMUX" ]; then
+ if ! tmux list-sessions | grep -q '^tmux:'; then
+ tmux new -s tmux
+ fi
+fi
+
+# Enable various options
+setopt interactive_comments beep extendedglob nomatch notify completeinword prompt_subst
+
+# Some other useful functionalities
+setopt autocd # Automatically cd into typed directory.
+setopt AUTO_PUSHD # More history for cd and use "cd -TAB"
+stty intr '^q' # free Ctrl+C for copy use Ctrl+q instead
+stty lnext '^-' # free Ctrl+V for paste use ^- instead
+stty stop undef # Disable ctrl-s to freeze terminal.
+stty start undef
+#COMPLETION_WAITING_DOTS="false"
+#unsetopt BEEP
+
+########## Source Plugins, should be last ##########
+#source /usr/share/nvm/init-nvm.sh
+
+# Load fzf keybindings and completion if fzf is installed
+if command -v fzf > /dev/null 2>&1; then
+ #FZF_BASE="/usr/share/fzf"
+ FZF_BASE="/usr/local/bin/fzf/shell"
+ source "${FZF_BASE}/key-bindings.zsh"
+ source "${FZF_BASE}/completion.zsh"
+else
+ echo "fzf not found, please install it to use fzf keybindings and completion."
+fi
+
+# Suggest aliases for commands
+source ~/.config/zsh/plugins/zsh-you-should-use/you-should-use.plugin.zsh
+
+# Load zsh-syntax-highlighting
+source ~/.config/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+
+# Load fish like auto suggestions
+source ~/.config/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh
+source ~/.config/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
diff --git a/linux/home/.config/zsh/user/aliases.zsh b/linux/home/.config/zsh/user/aliases.zsh
new file mode 100644
index 0000000..df0c4af
--- /dev/null
+++ b/linux/home/.config/zsh/user/aliases.zsh
@@ -0,0 +1,129 @@
+########## Aliases ##########
+
+### Dotfiles
+alias config='git --git-dir=$HOME/.cfg --work-tree=$HOME'
+cfg_files=$(config ls-tree --name-only -r HEAD)
+
+export CFG_FILES="$cfg_files"
+
+# Define alias for nvim/vim (fallback to vim)
+if command -v nvim > /dev/null; then
+ alias vi='nvim'
+else
+ alias vi='vim'
+fi
+
+# Confirmation #
+alias mv='mv -i'
+alias cp='cp -i'
+alias ln='ln -i'
+
+# Disable 'rm'
+alias rm='function _rm() { echo -e "\033[0;31mrm\033[0m is disabled, use \033[0;32mtrash\033[0m or \033[0;32mdel \033[0m\033[0;33m$1\033[0m"; }; _rm'
+alias del='/bin/rm'
+
+alias ls='lsd --color=auto --group-directories-first'
+#alias ls="ls --color=auto --group-directories-first"
+
+# ls variants
+alias l='ls -FAh --group-directories-first'
+alias la='ls -lAFh --group-directories-first'
+alias lt='ls -lFAht --group-directories-first'
+alias lr='ls -RFAh --group-directories-first'
+
+# more ls variants
+alias ldot='ls -ld .* --group-directories-first'
+alias lS='ls -1FASsh --group-directories-first'
+alias lart='ls -1Fcart --group-directories-first'
+alias lrt='ls -1Fcrt --group-directories-first'
+
+# ls with different alphabethical sorting
+#unalias ll
+#ll() { LC_COLLATE=C ls "$@" }
+
+# suffix aliases
+alias -g CP='| xclip -selection clipboard -rmlastnl'
+alias -g LL="| less"
+alias -g CA="| cat -A"
+alias -g KE="2>&1"
+alias -g NE="2>/dev/null"
+alias -g NUL=">/dev/null 2>&1"
+
+alias grep='grep --color=auto --exclude-dir={.git,.svn,.hg}'
+alias egrep='egrep --color=auto --exclude-dir={.git,.svn,.hg}'
+alias egrep='fgrep --color=auto --exclude-dir={.git,.svn,.hg}'
+
+alias gdb='gdb -q'
+alias rust-gdb='rust-gdb -q'
+
+# List upto last 10 visited directories using "d" and quickly cd into any specific one
+alias d="dirs -v | head -10"
+
+# Using just a number from "0" to "9"
+alias 0="cd +0"
+alias 1="cd +1"
+alias 2="cd +2"
+alias 3="cd +3"
+alias 4="cd +4"
+alias 5="cd +5"
+alias 6="cd +6"
+alias 7="cd +7"
+alias 8="cd +8"
+alias 9="cd +9"
+
+alias sudo='sudo ' # zsh: elligible for alias expansion/fix syntax highlight
+alias sedit='sudoedit'
+#alias se='sudoedit'
+alias se='sudo -e'
+alias :q='exit'
+alias sc="systemctl"
+alias jc="journalctl"
+alias jck="journalctl -k" # Kernel
+alias jce='sudo journalctl -b --priority 0..3' # error
+alias journalctl-error='sudo journalctl -b --priority 0..3'
+alias jcssh="sudo journalctl -u sshd"
+alias tunnel='ssh -fNTL'
+# tty aliases
+if [[ "$TERM" == 'linux' ]]; then
+ alias tmux='/usr/bin/tmux -L linux'
+fi
+alias logout="loginctl kill-user $(whoami)"
+
+#alias suspend='systemctl suspend && betterlockscreen -l' # Suspend(sleep) and lock screen if using systemctl
+alias suspend='systemctl suspend' # Suspend(sleep) and lock screen if using systemctl
+alias hibernate='systemctl hibernate' # Hibernate
+alias lock='DISPLAY=:0 xautolock -locknow' # Lock my workstation screen from my phone
+alias oports="sudo lsof -i -P -n | grep -i 'listen'" # List open ports
+alias keyname="xev | sed -n 's/[ ]*state.* \([^ ]*\)).*/\1/p'"
+alias wget=wget --hsts-file="$XDG_CACHE_HOME/wget-hsts" # wget does not support environment variables
+alias pp='getlast 2>&1 |&tee -a output.txt'
+alias lg='la | grep'
+alias pg='ps aux | grep'
+alias py='python'
+alias py3='python3'
+alias sha256='shasum -a 256'
+alias rgf='rg -F'
+alias weather='curl wttr.in/durban'
+alias wifi='nmcli dev wifi show-password'
+alias ddg='w3m lite.duckduckgo.com'
+alias rss='newsboat'
+alias vpn='protonvpn'
+alias yt-dl="yt-dlp -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' --restrict-filename"
+
+# Time aliases
+alias utc='TZ=Africa/Johannesburg date'
+alias ber='TZ=Europe/Berlin date'
+alias nyc='TZ=America/New_York date'
+alias sfo='TZ=America/Los_Angeles date'
+alias utc='TZ=Etc/UTC date'
+
+alias src='source ~/.zshrc'
+alias p=proxy
+
+alias cheat='~/.scripts/cheat.sh ~/documents/notes/cheatsheets'
+alias crypto='curl -s rate.sx | head -n -2 | tail -n +10'
+alias todo='glow "$HOME"/media/notes/_TODO.md'
+
+alias android-studio='/opt/android-studio/bin/studio.sh' # android-studio
+alias nomachine='/usr/NX/bin/nxplayer' # nomachine
+alias spotify='LD_PRELOAD=/usr/lib/spotify-adblock.so /bin/spotify %U'
diff --git a/linux/home/.config/zsh/user/bindings.zsh b/linux/home/.config/zsh/user/bindings.zsh
new file mode 100644
index 0000000..ce8451b
--- /dev/null
+++ b/linux/home/.config/zsh/user/bindings.zsh
@@ -0,0 +1,39 @@
+########## Vi mode ##########
+bindkey -v
+#bindkey -M viins '^?' backward-delete-char
+#local WORDCHARS='*?_-.[]~=&;!#$%^(){}<>'
+backward-kill-dir () {
+ local WORDCHARS=${WORDCHARS/\/}
+ zle backward-kill-word
+ zle -f kill
+}
+zle -N backward-kill-dir
+bindkey '^[^?' backward-kill-dir
+bindkey "^W" backward-kill-dir
+bindkey -M viins '^[[3~' delete-char
+bindkey -M vicmd '^[[3~' delete-char
+bindkey -v '^?' backward-delete-char
+bindkey -r '\e/'
+bindkey -s jk '\e'
+#bindkey "^W" backward-kill-word
+bindkey "^H" backward-delete-char # Control-h also deletes the previous char
+bindkey "^U" backward-kill-line
+bindkey "^[j" history-search-forward # or you can bind it to the down key "^[[B"
+bindkey "^[k" history-search-backward # or you can bind it to Up key "^[[A"
+
+# Define the 'autosuggest-execute' and 'autosuggest-accept' ZLE widgets
+autoload -Uz autosuggest-execute autosuggest-accept
+zle -N autosuggest-execute
+zle -N autosuggest-accept
+bindkey '^X' autosuggest-execute
+bindkey '^Y' autosuggest-accept
+
+# Edit line in vim with alt-e
+autoload edit-command-line; zle -N edit-command-line
+bindkey '^e' edit-command-line
+bindkey '^[e' edit-command-line # alt + e
+
+# Allow CTRL+D to exit zsh with partial command line (non empty line)
+exit_zsh() { exit }
+zle -N exit_zsh
+bindkey '^D' exit_zsh
diff --git a/linux/home/.config/zsh/user/completion.zsh b/linux/home/.config/zsh/user/completion.zsh
new file mode 100644
index 0000000..7d9198a
--- /dev/null
+++ b/linux/home/.config/zsh/user/completion.zsh
@@ -0,0 +1,156 @@
+#!/bin/zsh
+
+########## Completion(s) ##########
+
+autoload -Uz compinit
+_comp_path="${XDG_CACHE_HOME:-$HOME/.cache}/zcompdump"
+
+# Expands globs in conditional expressions
+if [[ $_comp_path(#qNmh-20) ]]; then
+ # -C (skip function check) implies -i (skip security check).
+ compinit -C -d "$_comp_path"
+else
+ mkdir -p "$_comp_path:h"
+ compinit -i -d "$_comp_path"
+ # Keep $_comp_path younger than cache time even if it isn't regenerated.
+ touch "$_comp_path"
+fi
+unset _comp_path
+
+# Accept completion with <tab> or Ctrl+i and go to next/previous suggestions with Vi like keys: Ctrl+n/p
+zmodload -i zsh/complist
+accept-and-complete-next-history() {
+ zle expand-or-complete-prefix
+}
+zle -N accept-and-complete-next-history
+bindkey -M menuselect '^i' accept-and-complete-next-history
+bindkey '^n' expand-or-complete
+bindkey '^p' reverse-menu-complete
+bindkey -M menuselect '^[' undo
+
+#zstyle ':completion:*' menu select=1
+#zstyle ':completion:*:directory-stack' list-colors '=(#b) #([0-9]#)*( *)==95=38;5;12'
+
+# Options
+setopt COMPLETE_IN_WORD # Complete from both ends of a word.
+setopt ALWAYS_TO_END # Move cursor to the end of a completed word.
+setopt PATH_DIRS # Perform path search even on command names with slashes.
+setopt AUTO_MENU # Show completion menu on a successive tab press.
+setopt AUTO_LIST # Automatically list choices on ambiguous completion.
+setopt AUTO_PARAM_SLASH # If completed parameter is a directory, add a trailing slash.
+setopt EXTENDED_GLOB # Needed for file modification glob modifiers with compinit.
+unsetopt MENU_COMPLETE # Do not autoselect the first completion entry.
+
+# Variables
+LS_COLORS=${LS_COLORS:-'di=34:ln=35:so=32:pi=33:ex=31:bd=36;01:cd=33;01:su=31;40;07:sg=36;40;07:tw=32;40;07:ow=33;40;07:'}
+
+# Styles
+# Defaults.
+zstyle ':completion:*:default' list-colors ${(s.:.)LS_COLORS}
+zstyle ':completion:*:default' list-prompt '%S%M matches%s'
+
+# Use caching to make completion for commands such as dpkg and apt usable.
+zstyle ':completion::complete:*' use-cache on
+zstyle ':completion::complete:*' cache-path "${XDG_CACHE_HOME:-$HOME/.cache}/zcompcache"
+
+
+# Group matches and describe.
+zstyle ':completion:*:*:*:*:*' menu select
+zstyle ':completion:*:matches' group 'yes'
+zstyle ':completion:*:options' description 'yes'
+zstyle ':completion:*:options' auto-description '%d'
+zstyle ':completion:*:corrections' format ' %F{green}-- %d (errors: %e) --%f'
+zstyle ':completion:*:descriptions' format ' %F{yellow}-- %d --%f'
+zstyle ':completion:*:messages' format ' %F{purple} -- %d --%f'
+zstyle ':completion:*:warnings' format ' %F{red}-- no matches found --%f'
+zstyle ':completion:*' format ' %F{yellow}-- %d --%f'
+zstyle ':completion:*' group-name ''
+zstyle ':completion:*' verbose yes
+
+# Fuzzy match mistyped completions.
+zstyle ':completion:*' completer _complete _match _approximate
+zstyle ':completion:*:match:*' original only
+zstyle ':completion:*:approximate:*' max-errors 1 numeric
+
+# Increase the number of errors based on the length of the typed word. But make
+# sure to cap (at 7) the max-errors to avoid hanging.
+zstyle -e ':completion:*:approximate:*' max-errors 'reply=($((($#PREFIX+$#SUFFIX)/3>7?7:($#PREFIX+$#SUFFIX)/3))numeric)'
+
+# Don't complete unavailable commands.
+zstyle ':completion:*:functions' ignored-patterns '(_*|pre(cmd|exec))'
+
+# Array completion element sorting.
+zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
+
+# Directories
+zstyle ':completion:*:*:cd:*' tag-order local-directories directory-stack path-directories
+zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
+zstyle ':completion:*:-tilde-:*' group-order 'named-directories' 'path-directories' 'users' 'expand'
+zstyle ':completion:*' squeeze-slashes true
+
+# History
+zstyle ':completion:*:history-words' stop yes
+zstyle ':completion:*:history-words' remove-all-dups yes
+zstyle ':completion:*:history-words' list false
+zstyle ':completion:*:history-words' menu yes
+
+# Environment Variables
+zstyle ':completion::*:(-command-|export):*' fake-parameters ${${${_comps[(I)-value-*]#*,}%%,*}:#-*-}
+
+# Populate hostname completion. But allow ignoring custom entries from static
+# */etc/hosts* which might be uninteresting.
+zstyle -a ':completion:*:hosts' etc-host-ignores '_etc_host_ignores'
+
+zstyle -e ':completion:*:hosts' hosts 'reply=(
+ ${=${=${=${${(f)"$(cat {/etc/ssh/ssh_,~/.ssh/}known_hosts(|2)(N) 2> /dev/null)"}%%[#| ]*}//\]:[0-9]*/ }//,/ }//\[/ }
+ ${=${(f)"$(cat /etc/hosts(|)(N) <<(ypcat hosts 2> /dev/null))"}%%(\#${_etc_host_ignores:+|${(j:|:)~_etc_host_ignores}})*}
+ ${=${${${${(@M)${(f)"$(cat ~/.ssh/config 2> /dev/null)"}:#Host *}#Host }:#*\**}:#*\?*}}
+)'
+
+# Don't complete uninteresting users...
+zstyle ':completion:*:*:*:users' ignored-patterns \
+ adm amanda apache avahi beaglidx bin cacti canna clamav daemon \
+ dbus distcache dovecot fax ftp games gdm gkrellmd gopher \
+ hacluster haldaemon halt hsqldb ident junkbust ldap lp mail \
+ mailman mailnull mldonkey mysql nagios \
+ named netdump news nfsnobody nobody nscd ntp nut nx openvpn \
+ operator pcap postfix postgres privoxy pulse pvm quagga radvd \
+ rpc rpcuser rpm shutdown squid sshd sync uucp vcsa xfs '_*'
+
+# ... unless we really want to.
+zstyle '*' single-ignored show
+
+# Ignore multiple entries.
+zstyle ':completion:*:(rm|kill|diff):*' ignore-line other
+zstyle ':completion:*:rm:*' file-patterns '*:all-files'
+
+# Kill
+zstyle ':completion:*:*:*:*:processes' command 'ps -u $LOGNAME -o pid,user,command -w'
+zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#) ([0-9a-z-]#)*=01;36=0=01'
+zstyle ':completion:*:*:kill:*' menu yes select
+zstyle ':completion:*:*:kill:*' force-list always
+zstyle ':completion:*:*:kill:*' insert-ids single
+
+# Man
+zstyle ':completion:*:manuals' separate-sections true
+zstyle ':completion:*:manuals.(^1*)' insert-sections true
+
+# Media Players
+zstyle ':completion:*:*:mpg123:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories'
+zstyle ':completion:*:*:mpg321:*' file-patterns '*.(mp3|MP3):mp3\ files *(-/):directories'
+zstyle ':completion:*:*:ogg123:*' file-patterns '*.(ogg|OGG|flac):ogg\ files *(-/):directories'
+zstyle ':completion:*:*:mocp:*' file-patterns '*.(wav|WAV|mp3|MP3|ogg|OGG|flac):ogg\ files *(-/):directories'
+
+# Mutt
+if [[ -s "$HOME/.mutt/aliases" ]]; then
+ zstyle ':completion:*:*:mutt:*' menu yes select
+ zstyle ':completion:*:mutt:*' users ${${${(f)"$(<"$HOME/.mutt/aliases")"}#alias[[:space:]]}%%[[:space:]]*}
+fi
+
+# SSH/SCP/RSYNC
+zstyle ':completion:*:(ssh|scp|rsync):*' tag-order 'hosts:-host:host hosts:-domain:domain hosts:-ipaddr:ip\ address *'
+zstyle ':completion:*:(scp|rsync):*' group-order users files all-files hosts-domain hosts-host hosts-ipaddr
+zstyle ':completion:*:ssh:*' group-order users hosts-domain hosts-host users hosts-ipaddr
+zstyle ':completion:*:(ssh|scp|rsync):*:hosts-host' ignored-patterns '*(.|:)*' loopback ip6-loopback localhost ip6-localhost broadcasthost
+zstyle ':completion:*:(ssh|scp|rsync):*:hosts-domain' ignored-patterns '<->.<->.<->.<->' '^[-[:alnum:]]##(.[-[:alnum:]]##)##' '*@*'
+zstyle ':completion:*:(ssh|scp|rsync):*:hosts-ipaddr' ignored-patterns '^(<->.<->.<->.<->|(|::)([[:xdigit:].]##:(#c,2))##(|%*))' '127.0.0.<->' '255.255.255.255' '::1' 'fe80::*'
diff --git a/linux/home/.config/zsh/user/functions.zsh b/linux/home/.config/zsh/user/functions.zsh
new file mode 100644
index 0000000..75032ba
--- /dev/null
+++ b/linux/home/.config/zsh/user/functions.zsh
@@ -0,0 +1,813 @@
+## Function to temporarily unset GIT_WORK_TREE
+function git_without_work_tree() {
+ # Only proceed if a git command is being run
+ if [ "$1" = "git" ]; then
+ shift
+ # Check if the current directory is inside a Git work tree
+ if git rev-parse --is-inside-work-tree &>/dev/null; then
+ # If inside a work tree, temporarily unset GIT_WORK_TREE
+ GIT_WORK_TREE_OLD="$GIT_WORK_TREE"
+ unset GIT_WORK_TREE
+ git "$@"
+ export GIT_WORK_TREE="$GIT_WORK_TREE_OLD"
+ else
+ # If not inside a work tree, call git command directly
+ git "$@"
+ fi
+ else
+ # If it's not a git command, just execute it normally
+ command "$@"
+ fi
+}
+
+# Set alias conditionally
+alias git='git_without_work_tree git'
+
+# Set bare dotfiles repository git environment variables dynamically
+function set_git_env_vars() {
+ # Check if the current command is a package manager command
+ if [[ "${(%)${(z)history[1]}}" =~ ^(pacman|yay|apt|dnf|brew|npm|pip|gem|go|cargo) ]]; then
+ return
+ fi
+ local git_dir="$(git rev-parse --git-dir -C . 2>/dev/null)"
+ if [[ -n "$git_dir" ]]; then
+ local is_bare="$(git -C "$git_dir" rev-parse --is-bare-repository 2>/dev/null)"
+ if [[ "$is_bare" == "true" ]]; then
+ export GIT_DIR="$HOME/.cfg"
+ export GIT_WORK_TREE=$(realpath $(eval echo ~))
+ else
+ unset GIT_DIR
+ unset GIT_WORK_TREE
+ fi
+ else
+ local root_dir="$(git rev-parse --show-toplevel 2>/dev/null)"
+ if [[ -n "$root_dir" ]]; then
+ unset GIT_DIR
+ export GIT_WORK_TREE="$root_dir"
+ else
+ export GIT_DIR="$HOME/.cfg"
+ export GIT_WORK_TREE=$(realpath $(eval echo ~))
+ fi
+ fi
+}
+
+# Define an auto_cd hook to automatically update Git environment variables
+#function chpwd() {
+# set_git_env_vars
+#}
+# Call the function to set Git environment variables when the shell starts up
+set_git_env_vars
+
+
+function gsp() {
+ # Config file for subtrees
+ #
+ # Format:
+ # <prefix>;<remote address>;<remote branch>
+ # # Lines starting with '#' will be ignored
+ GIT_SUBTREE_FILE="$PWD/.gitsubtrees"
+
+ if [ ! -f "$GIT_SUBTREE_FILE" ]; then
+ echo "Nothing to do - file <$GIT_SUBTREE_FILE> does not exist."
+ return
+ fi
+
+ if ! command -v config &> /dev/null; then
+ echo "Error: 'config' command not found. Make sure it's available in your PATH."
+ return
+ fi
+
+ OLD_IFS=$IFS
+ IFS=$'\n'
+ for LINE in $(cat "$GIT_SUBTREE_FILE"); do
+
+ # Skip lines starting with '#'.
+ if [[ $LINE = \#* ]]; then
+ continue
+ fi
+
+ # Parse the current line.
+ PREFIX=$(echo "$LINE" | cut -d';' -f 1)
+ REMOTE=$(echo "$LINE" | cut -d';' -f 2)
+ BRANCH=$(echo "$LINE" | cut -d';' -f 3)
+
+ # Pull from the remote.
+ echo "Executing: git subtree pull --prefix=$PREFIX $REMOTE $BRANCH"
+ if git subtree pull --prefix="$PREFIX" "$REMOTE" "$BRANCH"; then
+ echo "Subtree pull successful for $PREFIX."
+ else
+ echo "Error: Subtree pull failed for $PREFIX."
+ fi
+ done
+
+ IFS=$OLD_IFS
+}
+
+# Print previous command into a file
+getlast () {
+ fc -nl $((HISTCMD - 1))
+}
+
+# Enter directory and list contents
+#cd() { builtin cd $@ && lsd }
+cd() {
+ if [ -n "$1" ]; then
+ builtin cd "$@" && ls
+ else
+ builtin cd ~ && ls
+ fi
+}
+
+# cd using "up n" as a command up as many directories, example "up 3"
+up() {
+ # default parameter to 1 if non provided
+ declare -i d=${@:-1}
+ # ensure given parameter is non-negative. Print error and return if it is
+ (( $d < 0 )) && (>&2 echo "up: Error: negative value provided") && return 1;
+ # remove last d directories from pwd, append "/" in case result is empty
+ cd "$(pwd | sed -E 's;(/[^/]*){0,'$d'}$;;')/";
+}
+
+# cd into $XDG_CONFIG_HOME/$1 directory
+c() {
+ local root=${XDG_CONFIG_HOME:-~/.config}
+ local dname="$root/$1"
+ if [[ ! -d "$dname" ]]; then
+ return
+ fi
+ cd "$dname"
+}
+
+# Make and cd into directory and any parent directories
+mkcd () {
+ if [[ -z "$1" ]]; then
+ echo "Usage: mkcd <dir>" 1>&2
+ return 1
+ fi
+ mkdir -p "$1"
+ cd "$1"
+}
+
+bak() {
+ if [[ -e "$1" ]]; then
+ echo "Found: $1"
+ mv "${1%.*}"{,.bak}
+ elif [[ -e "$1.bak" ]]; then
+ echo "Found: $1.bak"
+ mv "$1"{.bak,}
+ fi
+}
+
+back() {
+ for file in "$@"; do
+ cp -r "$file" "$file".bak
+ done
+}
+
+# tre is a shorthand for tree
+tre() {
+ tree -aC -I \
+ '.git|.hg|.svn|.tmux|.backup|.vim-backup|.swap|.vim-swap|.undo|.vim-undo|*.bak|tags' \
+ --dirsfirst "$@" \
+ | less
+}
+
+# switch from/to project/package dir
+pkg() {
+ if [ "$#" -eq 2 ]; then
+ ln -s "$(readlink -f $1)" "$(readlink -f $2)"/._pkg
+ ln -s "$(readlink -f $2)" "$(readlink -f $1)"/._pkg
+ else
+ cd "$(readlink -f ./._pkg)"
+ fi
+}
+
+# Prepare C/C++ project for Language Server Protoco
+lsp-prep() {
+ (cd build && cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON) \
+ && ln -sf build/compile_commands.json
+}
+
+reposize() {
+ url=`echo $1 \
+ | perl -pe 's#(?:https?://github.com/)([\w\d.-]+\/[\w\d.-]+).*#\1#g' \
+ | perl -pe 's#git\@github.com:([\w\d.-]+\/[\w\d.-]+)\.git#\1#g'
+ `
+ printf "https://github.com/$url => "
+ curl -s https://api.github.com/repos/$url \
+ | jq '.size' \
+ | numfmt --to=iec --from-unit=1024
+}
+
+# Launch a program in a terminal without getting any output,
+# and detache the process from terminal
+# (can then close the terminal without terminating process)
+-echo() {
+ "$@" &> /dev/null & disown
+}
+
+# Reload shell
+function reload() {
+ local compdump_files="$ZDOTDIR/.zcompdump*"
+
+ if ls $compdump_files &> /dev/null; then
+ rm -f $compdump_files
+ fi
+
+ exec $SHELL -l
+}
+
+#pom() {
+# local -r HOURS=${1:?}
+# local -r MINUTES=${2:-0}
+# local -r POMODORO_DURATION=${3:-25}
+#
+# bc <<< "(($HOURS * 60) + $MINUTES) / $POMODORO_DURATION"
+#}
+
+#mnt() {
+# local FILE="/mnt/external"
+# if [ ! -z $2 ]; then
+# FILE=$2
+# fi
+#
+# if [ ! -z $1 ]; then
+# sudo mount "$1" "$FILE" -o rw
+# echo "Device in read/write mounted in $FILE"
+# fi
+#
+# if [ $# = 0 ]; then
+# echo "You need to provide the device (/dev/sd*) - use lsblk"
+# fi
+#}
+#
+#umnt() {
+# local DIRECTORY="/mnt"
+# if [ ! -z $1 ]; then
+# DIRECTORY=$1
+# fi
+# MOUNTED=$(grep $DIRECTORY /proc/mounts | cut -f2 -d" " | sort -r)
+# cd "/mnt"
+# sudo umount $MOUNTED
+# echo "$MOUNTED unmounted"
+#}
+
+mntmtp() {
+ local DIRECTORY="$HOME/mnt"
+ if [ ! -z $2 ]; then
+ local DIRECTORY=$2
+ fi
+ if [ ! -d $DIRECTORY ]; then
+ mkdir $DIRECTORY
+ fi
+
+ if [ ! -z $1 ]; then
+ simple-mtpfs --device "$1" "$DIRECTORY"
+ echo "MTPFS device in read/write mounted in $DIRECTORY"
+ fi
+
+ if [ $# = 0 ]; then
+ echo "You need to provide the device number - use simple-mtpfs -l"
+ fi
+}
+
+umntmtp() {
+ local DIRECTORY="$HOME/mnt"
+ if ; then
+ DIRECTORY=$1
+ fi
+ cd $HOME
+ umount $DIRECTORY
+ echo "$DIRECTORY with mtp filesystem unmounted"
+}
+duckduckgo() {
+ lynx -vikeys -accept_all_cookies "https://lite.duckduckgo.com/lite/?q=$@"
+}
+
+wikipedia() {
+ lynx -vikeys -accept_all_cookies "https://en.wikipedia.org/wiki?search=$@"
+}
+#function filesize() {
+# # Check if 'du' supports the -b option, which provides sizes in bytes.
+# if du -b /dev/null > /dev/null 2>&1; then
+# local arg=-sbh; # If supported, use -sbh options for 'du'.
+# else
+# local arg=-sh; # If not supported, use -sh options for 'du'.
+# fi
+#
+# # Check if no arguments are provided.
+# if [ "$#" -eq 0 ]; then
+# # Calculate and display sizes for all files and directories in cwd.
+# du $arg ./*
+# else
+# # Calculate and display sizes for the specified files and directories.
+# du $arg -- "$@"
+# fi
+#}
+#
+
+fgl() {
+ git log --graph --color=always \
+ --format="%C(auto)%h%d %s %C(black)%C(bold)%cr" "$@" |
+ fzf --ansi --no-sort --reverse --tiebreak=index --bind=ctrl-s:toggle-sort \
+ --bind "ctrl-m:execute:
+ (grep -o '[a-f0-9]\{7\}' | head -1 |
+ xargs -I % sh -c 'git show --color=always % | less -R') << 'FZF-EOF'
+ {}
+FZF-EOF"
+}
+
+fgb() {
+ local branches branch
+ branches=$(git --no-pager branch -vv) &&
+ branch=$(echo "$branches" | fzf +m) &&
+ git checkout $(echo "$branch" | awk '{print $1}' | sed "s/.* //")
+}
+
+# +--------+
+# | Pacman |
+# +--------+
+
+# TODO can improve that with a bind to switch to what was installed
+fpac() {
+ pacman -Slq | fzf --multi --reverse --preview 'pacman -Si {1}' | xargs -ro sudo pacman -S
+}
+
+fyay() {
+ yay -Slq | fzf --multi --reverse --preview 'yay -Si {1}' | xargs -ro yay -S
+}
+
+# +------+
+# | tmux |
+# +------+
+
+fmux() {
+ prj=$(find $XDG_CONFIG_HOME/tmuxp/ -execdir bash -c 'basename "${0%.*}"' {} ';' | sort | uniq | nl | fzf | cut -f 2)
+ echo $prj
+ [ -n "$prj" ] && tmuxp load $prj
+}
+
+# ftmuxp - propose every possible tmuxp session
+ftmuxp() {
+ if [[ -n $TMUX ]]; then
+ return
+ fi
+
+ # get the IDs
+ ID="$(ls $XDG_CONFIG_HOME/tmuxp | sed -e 's/\.yml$//')"
+ if [[ -z "$ID" ]]; then
+ tmux new-session
+ fi
+
+ create_new_session="Create New Session"
+
+ ID="${create_new_session}\n$ID"
+ ID="$(echo $ID | fzf | cut -d: -f1)"
+
+ if [[ "$ID" = "${create_new_session}" ]]; then
+ tmux new-session
+ elif [[ -n "$ID" ]]; then
+ # Change name of urxvt tab to session name
+ printf '\033]777;tabbedx;set_tab_name;%s\007' "$ID"
+ tmuxp load "$ID"
+ fi
+}
+
+# ftmux - help you choose tmux sessions
+ftmux() {
+ if [[ ! -n $TMUX ]]; then
+ # get the IDs
+ ID="`tmux list-sessions`"
+ if [[ -z "$ID" ]]; then
+ tmux new-session
+ fi
+ create_new_session="Create New Session"
+ ID="$ID\n${create_new_session}:"
+ ID="`echo $ID | fzf | cut -d: -f1`"
+ if [[ "$ID" = "${create_new_session}" ]]; then
+ tmux new-session
+ elif [[ -n "$ID" ]]; then
+ printf '\033]777;tabbedx;set_tab_name;%s\007' "$ID"
+ tmux attach-session -t "$ID"
+ else
+ : # Start terminal normally
+ fi
+ fi
+}
+
+# +-------+
+# | Other |
+# +-------+
+
+# List install files for dotfiles
+fdot() {
+ file=$(find "$DOTFILES/install" -exec basename {} ';' | sort | uniq | nl | fzf | cut -f 2)
+ [ -n "$file" ] && "$EDITOR" "$DOTFILES/install/$file"
+}
+
+# List projects
+fwork() {
+ result=$(find ~/workspace/* -type d -prune -exec basename {} ';' | sort | uniq | nl | fzf | cut -f 2)
+ [ -n "$result" ] && cd ~/workspace/$result
+}
+
+# Open pdf with Zathura
+fpdf() {
+ result=$(find -type f -name '*.pdf' | fzf --bind "ctrl-r:reload(find -type f -name '*.pdf')" --preview "pdftotext {} - | less")
+ [ -n "$result" ] && nohup zathura "$result" &> /dev/null & disown
+}
+
+# Open epubs with Zathura
+fepub() {
+ result=$(find -type f -name '*.epub' | fzf --bind "ctrl-r:reload(find -type f -name '*.epub')")
+ [ -n "$result" ] && nohup zathura "$result" &> /dev/null & disown
+}
+
+# Search and find directories in the dir stack
+fpop() {
+ # Only work with alias d defined as:
+
+ # alias d='dirs -v'
+ # for index ({1..9}) alias "$index"="cd +${index}"; unset index
+
+ d | fzf --height="20%" | cut -f 1 | source /dev/stdin
+}
+
+#ip() {
+# emulate -LR zsh
+#
+# if [[ $1 == 'get' ]]; then
+# res=$(curl -s ipinfo.io/ip)
+# echo -n $res | xsel --clipboard
+# echo "copied $res to clipboard"
+# # only run ip if it exists
+# elif (( $+commands[ip] )); then
+# command ip $*
+# fi
+#}
+
+ssh-create() {
+ if [ ! -z "$1" ]; then
+ ssh-keygen -f $HOME/.ssh/$1 -t rsa -N '' -C "$1"
+ chmod 700 $HOME/.ssh/$1*
+ fi
+}
+
+historystat() {
+ history 0 | awk '{print $2}' | sort | uniq -c | sort -n -r | head
+}
+
+promptspeed() {
+ for i in $(seq 1 10); do /usr/bin/time zsh -i -c exit; done
+}
+
+#matrix () {
+# local lines=$(tput lines)
+# cols=$(tput cols)
+#
+# awkscript='
+# {
+# letters="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()"
+# lines=$1
+# random_col=$3
+# c=$4
+# letter=substr(letters,c,1)
+# cols[random_col]=0;
+# for (col in cols) {
+# line=cols[col];
+# cols[col]=cols[col]+1;
+# printf "\033[%s;%sH\033[2;32m%s", line, col, letter;
+# printf "\033[%s;%sH\033[1;37m%s\033[0;0H", cols[col], col, letter;
+# if (cols[col] >= lines) {
+# cols[col]=0;
+# }
+# }
+# }
+# '
+#
+# echo -e "\e[1;40m"
+# clear
+#
+# while :; do
+# echo $lines $cols $(( $RANDOM % $cols)) $(( $RANDOM % 72 ))
+# sleep 0.05
+# done | awk "$awkscript"
+#}
+
+matrix() {
+ local lines=$(tput lines)
+ cols=$(tput cols)
+
+ # Check if tmux is available
+ if command -v tmux > /dev/null; then
+ # Save the current status setting
+ local status_setting=$(tmux show -g -w -v status)
+
+ # Turn off tmux status
+ tmux set -g status off
+ else
+ echo "tmux is not available. Exiting."
+ return 1
+ fi
+
+ # Function to restore terminal state
+ restore_terminal() {
+ # Clear the screen
+ clear
+
+ # Bring back tmux status to its original setting
+ if command -v tmux > /dev/null; then
+ tmux set -g status "$status_setting"
+ fi
+ }
+
+ trap 'restore_terminal' INT
+
+ awkscript='
+ {
+ letters="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()"
+ lines=$1
+ random_col=$3
+ c=$4
+ letter=substr(letters,c,1)
+ cols[random_col]=0;
+ for (col in cols) {
+ line=cols[col];
+ cols[col]=cols[col]+1;
+ printf "\033[%s;%sH\033[2;32m%s", line, col, letter;
+ printf "\033[%s;%sH\033[1;37m%s\033[0;0H", cols[col], col, letter;
+ if (cols[col] >= lines) {
+ cols[col]=0;
+ }
+ }
+ }
+ '
+
+ echo -e "\e[1;40m"
+ clear
+
+ while :; do
+ echo $lines $cols $(( $RANDOM % $cols)) $(( $RANDOM % 72 ))
+ sleep 0.05
+ done | awk "$awkscript"
+
+ # Restore terminal state
+ restore_terminal
+}
+
+## Reload shell
+function reload() {
+ local compdump_files="$ZDOTDIR/.zcompdump*"
+
+ if ls $compdump_files &> /dev/null; then
+ rm -f $compdump_files
+ fi
+
+ exec $SHELL -l
+}
+## Generate a secure password
+function passgen() {
+ LC_ALL=C tr -dc ${1:-"[:graph:]"} < /dev/urandom | head -c ${2:-20}
+}
+## Encode/Decode string using base64
+function b64e() {
+ echo "$@" | base64
+}
+
+function b64d() {
+ echo "$@" | base64 -D
+}
+# Search through all man pages
+function fman() {
+ man -k . | fzf -q "$1" --prompt='man> ' --preview $'echo {} | tr -d \'()\' | awk \'{printf "%s ", $2} {print $1}\' | xargs -r man' | tr -d '()' | awk '{printf "%s ", $2} {print $1}' | xargs -r man
+}
+# Back up a file. Usage "backupthis <filename>"
+backupthis() {
+ cp -riv $1 ${1}-$(date +%Y%m%d%H%M).backup;
+}
+
+# Spawn a clone of current terminal
+putstate () {
+ declare +x >~/environment.tmp
+ declare -x >>~/environment.tmp
+ echo cd "$PWD" >>~/environment.tmp
+}
+
+getstate () {
+ . ~/environment.tmp
+}
+
+# use ctrl-z to toggle in and out of bg
+function toggle_fg_bg() {
+ if [[ $#BUFFER -eq 0 ]]; then
+ BUFFER="fg"
+ zle accept-line
+ else
+ BUFFER=""
+ zle clear-screen
+ fi
+}
+zle -N toggle_fg_bg
+bindkey '^Z' toggle_fg_bg
+
+# Tmux layout
+openSession () {
+ tmux split-window -h -t
+ tmux split-window -v -t
+ tmux resize-pane -U 5
+}
+
+# archive compress
+compress() {
+ if [[ -n "$1" ]]; then
+ local file=$1
+ shift
+ case "$file" in
+ *.tar ) tar cf "$file" "$*" ;;
+ *.tar.bz2 ) tar cjf "$file" "$*" ;;
+ *.tar.gz ) tar czf "$file" "$*" ;;
+ *.tgz ) tar czf "$file" "$*" ;;
+ *.zip ) zip "$file" "$*" ;;
+ *.rar ) rar "$file" "$*" ;;
+ * ) tar zcvf "$file.tar.gz" "$*" ;;
+ esac
+ else
+ echo 'usage: compress <foo.tar.gz> ./foo ./bar'
+ fi
+}
+
+# archive extract
+extract() {
+ if [[ -f "$1" ]] ; then
+ local filename=$(basename "$1")
+ local foldername=${filename%%.*}
+ local fullpath=$(perl -e 'use Cwd "abs_path";print abs_path(shift)' "$1")
+ local didfolderexist=false
+ if [[ -d "$foldername" ]]; then
+ didfolderexist=true
+ read -p "$foldername already exists, do you want to overwrite it? (y/n) " -n 1
+ echo
+ if [[ "$REPLY" =~ ^[Nn]$ ]]; then
+ return
+ fi
+ fi
+ mkdir -p "$foldername" && cd "$foldername"
+ case "$1" in
+ *.tar.bz2) tar xjf "$fullpath" ;;
+ *.tar.gz) tar xzf "$fullpath" ;;
+ *.tar.xz) tar Jxvf "$fullpath" ;;
+ *.tar.Z) tar xzf "$fullpath" ;;
+ *.tar) tar xf "$fullpath" ;;
+ *.taz) tar xzf "$fullpath" ;;
+ *.tb2) tar xjf "$fullpath" ;;
+ *.tbz) tar xjf "$fullpath" ;;
+ *.tbz2) tar xjf "$fullpath" ;;
+ *.tgz) tar xzf "$fullpath" ;;
+ *.txz) tar Jxvf "$fullpath" ;;
+ *.zip) unzip "$fullpath" ;;
+ *) echo "'$1' cannot be extracted via extract()" \
+ && cd .. \
+ && ! "$didfolderexist" \
+ && rm -r "$foldername" ;;
+ esac
+ else
+ echo "'$1' is not a valid file"
+ fi
+}
+## Extract with one command
+#extract () {
+# if [ -f $1 ] ; then
+# case $1 in
+# *.tar.bz2) tar xjf $1 ;;
+# *.tar.gz) tar xzf $1 ;;
+# *.bz2) bunzip2 $1 ;;
+# *.rar) rar x $1 ;;
+# *.gz) gunzip $1 ;;
+# *.tar) tar xf $1 ;;
+# *.tbz2) tar xjf $1 ;;
+# *.tgz) tar xzf $1 ;;
+# *.zip) unzip $1 ;;
+# *.Z) uncompress $1 ;;
+# *.7z) 7z x $1 ;;
+# *) echo "'$1' cannot be extracted via extract()" ;;
+# esac
+# else
+# echo "'$1' is not a valid file"
+# fi
+#}
+
+ports() {
+ local result
+ result=$(sudo netstat -tulpn | grep LISTEN)
+ echo "$result" | fzf
+}
+
+trash() {
+ case "$1" in
+ --list)
+ ls -A1 ~/.local/share/Trash/files/
+ ;;
+ --empty)
+ ls -A1 ~/.local/share/Trash/files/ && \rm -rfv ~/.local/share/Trash/files/*
+ ;;
+ --restore)
+ gio trash --restore "$(gio trash --list | fzf | cut -f 1)"
+ ;;
+ --delete)
+ trash_files=$(ls -A ~/.local/share/Trash/files/ | fzf --multi); echo $trash_files | xargs -I {} rm -rf ~/.local/share/Trash/files/{}
+ ;;
+ *)
+ gio trash "$@"
+ ;;
+ esac
+}
+
+# Git
+## Use gh instead of git (fast GitHub command line client).
+#if type gh >/dev/null; then
+# alias git=gh
+# if type compdef >/dev/null 2>/dev/null; then
+# compdef gh=git
+# fi
+#fi
+#check_gh_installed() {
+# if command -v gh &> /dev/null; then
+# return 0 # gh is installed
+# else
+# return 1 # gh is not installed
+# fi
+#}
+#
+## Set alias for git to gh if gh is installed
+#if check_gh_installed; then
+# alias git=gh
+#fi
+
+# No arguments: `git status`
+# With arguments: acts like `git`
+g() {
+ if [ $# -gt 0 ]; then
+ git "$@" # If arguments are provided, pass them to git
+ else
+ git status # Otherwise, show git status
+ fi
+}
+
+# Complete g like git
+compdef g=git
+
+# Define functions for common Git commands
+ga() { g add "$@"; } # ga: Add files to the staging area
+gaw() { g add -A && g diff --cached -w | g apply --cached -R; } # gaw: Add all changes to the staging area and unstage whitespace changes
+grm() { g rm "$@"; }
+gb() { g branch "$@"; } # gb: List branches
+gbl() { g branch -l "$@"; } # gbl: List local branches
+gbD() { g branch -D "$@"; } # gbD: Delete a branch
+gbu() { g branch -u "$@"; } # gbu: Set upstream branch
+ge() { g clone "$@"; }
+gc() { g commit "$@"; } # gc: Commit changes
+gcm() { g commit -m "$@"; } # gcm: Commit with a message
+gca() { g commit -a "$@"; } # gca: Commit all changes
+gcaa() { g commit -a --amend "$@"; } # gcaa: Amend the last commit
+gcam() { g commit -a -m "$@"; } # gcam: Commit all changes with a message
+gce() { g commit -e "$@"; } # gce: Commit with message and allow editing
+gcfu() { g commit --fixup "$@"; } # gcfu: Commit fixes in the context of the previous commit
+gco() { g checkout "$@"; } # gco: Checkout a branch or file
+gcob() { g checkout -b "$@"; } # gcob: Checkout a new branch
+gcoB() { g checkout -B "$@"; } # gcoB: Checkout a new branch, even if it exists
+gcp() { g cherry-pick "$@"; } # gcp: Cherry-pick a commit
+gcpc() { g cherry-pick --continue "$@"; } # gcpc: Continue cherry-picking after resolving conflicts
+gd() { g diff "$@"; } # gd: Show changes
+#gd^() { g diff HEAD^ HEAD "$@"; } # gd^: Show changes between HEAD^ and HEAD
+gds() { g diff --staged "$@"; } # gds: Show staged changes
+gl() { g lg "$@"; } # gl: Show a customized log
+glg() { g log --graph --decorate --all "$@"; } # glg: Show a customized log with graph
+gls() { # Query `glog` with regex query.
+ query="$1"
+ shift
+ glog --pickaxe-regex "-S$query" "$@"
+}
+gdc() { g diff --cached "$@"; } # gdc: Show changes between the working directory and the index
+gu() { g pull "$@"} # gu: Pull
+gp() { g push "$@"} # gp: Push
+gpom() { g push origin main "$@"; } # gpom: Push changes to origin main
+gr() { g remote "$@"; } # gr: Show remote
+gra() { g rebase --abort "$@"; } # gra: Abort a rebase
+grb() { g rebase --committer-date-is-author-date "$@"; } # grb: Rebase with the author date preserved
+grbom() { grb --onto master "$@"; } # grbom: Rebase onto master
+grbasi() { g rebase --autosquash --interactive "$@"; } # grbasi: Interactive rebase with autosquash
+grc() { g rebase --continue "$@"; } # grc: Continue a rebase
+grs() { g restore --staged "$@"; } # grs: Restore changes staged for the next commit
+grv() { g remote -v "$@"; } # grv: Show remote URLs after each name
+grh() { g reset --hard "$@"; } # grh: Reset the repository and the working directory
+grH() { g reset HEAD "$@"; } # grH: Reset the index but not the working directory
+#grH^() { g reset HEAD^ "$@"; } # grH^: Reset the index and working directory to the state of the HEAD's first parent
+gs() { g status -sb "$@"; } # gs: Show the status of the working directory and the index
+gsd() { g stash drop "$@"; } # gsd: Drop a stash
+gsl() { g stash list --date=relative "$@"; } # gsl: List all stashes
+gsp() { g stash pop "$@"; } # gsp: Apply and remove a single stash
+gss() { g stash show "$@"; } # gss: Show changes recorded in the stash as a diff
+gst() { g status "$@"; } # gst: Show the status of the working directory and the index
+gsu() { g standup "$@"; } # gsu: Customized standup command
+gforgotrecursive() { g submodule update --init --recursive --remote "$@"; } # gforgotrecursive: Update submodules recursively
+gfp() { g commit --amend --no-edit && g push --force-with-lease "$@"; } # gfp: Amending the last commit and force-pushing
diff --git a/linux/home/.config/zsh/user/options.zsh b/linux/home/.config/zsh/user/options.zsh
new file mode 100644
index 0000000..0e97fed
--- /dev/null
+++ b/linux/home/.config/zsh/user/options.zsh
@@ -0,0 +1,50 @@
+
+# Let FZF use ripgrep by default
+if type rg &> /dev/null; then
+ export FZF_DEFAULT_COMMAND='rg --files'
+ export FZF_DEFAULT_OPTS='-m --height 50% --border'
+fi
+
+
+# Allow nnn filemanager to cd on quit
+nnn() {
+ declare -x +g NNN_TMPFILE=$(mktemp --tmpdir $0.XXXX)
+ trap "rm -f $NNN_TMPFILE" EXIT
+ =nnn $@
+ [ -s $NNN_TMPFILE ] && source $NNN_TMPFILE
+}
+
+
+# NVM
+#nvm() {
+# local green_color
+# green_color=$(tput setaf 2)
+# local reset_color
+# reset_color=$(tput sgr0)
+# echo -e "${green_color}nvm${reset_color} $@"
+#}
+if [ -s "$NVM_DIR/nvm.sh" ]; then
+ nvm_cmds=(nvm node npm yarn)
+ for cmd in "${nvm_cmds[@]}"; do
+ alias "$cmd"="unalias ${nvm_cmds[*]} && unset nvm_cmds && . $NVM_DIR/nvm.sh && $cmd"
+ done
+fi
+
+# Kubernetes
+# kubernetes aliases
+if command -v kubectl > /dev/null; then
+ replaceNS() { kubectl config view --minify --flatten --context=$(kubectl config current-context) | yq ".contexts[0].context.namespace=\"$1\"" ; }
+ alias kks='KUBECONFIG=<(replaceNS "kube-system") kubectl'
+ alias kam='KUBECONFIG=<(replaceNS "authzed-monitoring") kubectl'
+ alias kas='KUBECONFIG=<(replaceNS "authzed-system") kubectl'
+ alias kar='KUBECONFIG=<(replaceNS "authzed-region") kubectl'
+ alias kt='KUBECONFIG=<(replaceNS "tenant") kubectl'
+
+ if command -v kubectl-krew > /dev/null; then
+ path=($XDG_CONFIG_HOME/krew/bin $path)
+ fi
+
+ rmfinalizers() {
+ kubectl get deployment "$1" -o json | jq '.metadata.finalizers = null' | kubectl apply -f -
+ }
+fi
diff --git a/linux/home/.config/zsh/user/prompt.zsh b/linux/home/.config/zsh/user/prompt.zsh
new file mode 100644
index 0000000..d9fc148
--- /dev/null
+++ b/linux/home/.config/zsh/user/prompt.zsh
@@ -0,0 +1,202 @@
+#!/bin/zsh
+
+########## Prompt(s) ##########
+
+terminfo_down_sc=$terminfo[cud1]$terminfo[cuu1]$terminfo[sc]$terminfo[cud1]
+
+autoload -Uz vcs_info
+autoload -Uz add-zsh-hook
+autoload -U colors && colors
+
+precmd_vcs_info() { vcs_info }
+
+precmd_functions+=( precmd_vcs_info )
+
+setopt prompt_subst
+
+git_branch_test_color() {
+ local ref=$(git symbolic-ref --short HEAD 2> /dev/null)
+ if [ -n "${ref}" ]; then
+ if [ -n "$(git status --porcelain)" ]; then
+ local gitstatuscolor='%F{green}'
+ else
+ local gitstatuscolor='%F{82}'
+ fi
+ echo "${gitstatuscolor}${ref}"
+ else
+ echo ""
+ fi
+}
+
+zstyle ':vcs_info:*' check-for-changes true
+zstyle ':vcs_info:*' stagedstr ' +%F{15}staged%f'
+zstyle ':vcs_info:*' unstagedstr ' -%F{15}unstaged%f'
+zstyle ':vcs_info:*' actionformats '%F{5}%F{2}%b%F{3}|%F{1}%a%F{5}%f '
+zstyle ':vcs_info:*' formats '%F{208} '$'\uE0A0'' %f$(git_branch_test_color)%f%F{76}%c%F{3}%u%f '
+zstyle ':vcs_info:git*+set-message:*' hooks git-untracked
+zstyle ':vcs_info:*' enable git
+
++vi-git-untracked() {
+ if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \
+ git status --porcelain | grep '??' &> /dev/null ; then
+ hook_com[unstaged]+='%F{196} !%f%F{15}untracked%f'
+ fi
+}
+
+ssh_name() {
+ if [[ -n $SSH_CONNECTION ]]; then
+ local ssh_info
+ ssh_info="ssh:%F{green}%n$nc%f"
+ if [[ -n $SSH_CONNECTION ]]; then
+ local ip_address
+ ip_address=$(echo $SSH_CONNECTION | awk '{print $3}')
+ ssh_info="$ssh_info@%F{green}$ip_address%f"
+ fi
+ echo " ${ssh_info}"
+ fi
+}
+
+function job_name() {
+ job_name=""
+ job_length=0
+ if [ "${COLUMNS}" -gt 69 ]; then
+ job_length=$((${COLUMNS}-70))
+ [ "${job_length}" -lt "0" ] && job_length=0
+ fi
+
+ if [ "${job_length}" -gt 0 ]; then
+ local job_count=$(jobs | wc -l)
+ if [ "${job_count}" -gt 0 ]; then
+ local title_jobs="jobs:"
+ job_name="${title_jobs}"
+ job_name+="%F{green}$(jobs | grep + | tr -s " " | cut -d " " -f 4- | cut -b 1-${job_length} | sed "s/\(.*\)/\1/")%f"
+ fi
+ fi
+
+ echo "${job_name}"
+}
+
+function job_count() {
+ local job_count
+ job_count=$(jobs -s | grep -c "suspended")
+ if [ "${job_count}" -gt 0 ]; then
+ echo "(${job_count})"
+ fi
+}
+
+current_jobs=' $(job_name)$(job_count)'
+user="%n"
+at="%F{15}at%{$reset_color%}"
+machine="%F{4}%m%{$reset_color%}"
+relative_home="%F{4}%~%{$reset_color%}"
+carriage_return=""$'\n'""
+empty_line_bottom="%r"
+chevron_right=""
+color_reset="%{$(tput sgr0)%}"
+color_yellow="%{$(tput setaf 226)%}"
+color_blink="%{$(tput blink)%}"
+prompt_symbol="$"
+dollar_sign="${color_yellow}${color_blink}${prompt_symbol}${color_reset}"
+dollar="%(?:%F{2}${dollar_sign}:%F{1}${dollar_sign})"
+space=" "
+cmd_prompt="%(?:%F{2}${chevron_right} :%F{1}${chevron_right} )"
+git_info="\$vcs_info_msg_0_"
+v1="%{┌─[%}"
+v2="%{]%}"
+v3="└─["
+v4="]"
+
+function insert-mode () { echo "-- INSERT --" }
+function normal-mode () { echo "-- NORMAL --" }
+
+vi-mode-indicator () {
+ if [[ ${KEYMAP} == vicmd || ${KEYMAP} == vi-cmd-mode ]]; then
+ echo -ne '\e[1 q'
+ vi_mode=$(normal-mode)
+ elif [[ ${KEYMAP} == main || ${KEYMAP} == viins || ${KEYMAP} == '' ]]; then
+ echo -ne '\e[5 q'
+ vi_mode=$(insert-mode)
+ fi
+}
+
+function set-prompt () {
+ vi-mode-indicator
+ mode="%F{145}%{$terminfo_down_sc$vi_mode$terminfo[rc]%f%}"
+ #PS1="${relative_home}${vcs_info_msg_0_}${current_jobs} ${carriage_return}${mode}${dollar}${space}"
+ PS1="${v1}${user}${v2}${space}${relative_home}${vcs_info_msg_0_}${current_jobs}$(ssh_name) ${carriage_return}${mode}${v3}${dollar}${v4}${empty_line_bottom}"
+ #RPROMPT="$(ssh_name)"
+}
+
+precmd () {
+ print -rP
+ vcs_info
+ set-prompt
+}
+
+function update-mode-file() {
+ set-prompt
+ local current_mode=$(cat ~/.vi-mode)
+ local new_mode="$vi_mode"
+ if [[ "$new_mode" != "$current_mode" ]]; then
+ echo "$new_mode" >| ~/.vi-mode
+ fi
+ if command -v tmux &>/dev/null && [[ -n "$TMUX" ]]; then
+ tmux refresh-client -S
+ fi
+}
+
+function check-nvim-running() {
+ if pgrep -x "nvim" > /dev/null; then
+ vi_mode=""
+ update-mode-file
+ if command -v tmux &>/dev/null && [[ -n "$TMUX" ]]; then
+ tmux refresh-client -S
+ fi
+ else
+ if [[ ${KEYMAP} == vicmd || ${KEYMAP} == vi-cmd-mode ]]; then
+ vi_mode=$(normal-mode)
+ elif [[ ${KEYMAP} == main || ${KEYMAP} == viins || ${KEYMAP} == '' ]]; then
+ vi_mode=$(insert-mode)
+ fi
+ update-mode-file
+ if command -v tmux &>/dev/null && [[ -n "$TMUX" ]]; then
+ tmux refresh-client -S
+ fi
+ fi
+}
+
+function zle-line-init() {
+ zle reset-prompt
+ case "${KEYMAP}" in
+ vicmd)
+ echo -ne '\e[1 q'
+ ;;
+ main|viins|*)
+ echo -ne '\e[5 q'
+ ;;
+ esac
+}
+
+function zle-keymap-select() {
+ update-mode-file
+ zle reset-prompt
+ case "${KEYMAP}" in
+ vicmd)
+ echo -ne '\e[1 q'
+ ;;
+ main|viins|*)
+ echo -ne '\e[5 q'
+ ;;
+ esac
+}
+
+preexec () { print -rn -- $terminfo[el]; echo -ne '\e[5 q' ; }
+
+zle -N zle-line-init
+zle -N zle-keymap-select
+
+TRAPWINCH() {
+ update-mode-file
+}
+
+set-prompt
diff --git a/linux/home/.editorconfig b/linux/home/.editorconfig
new file mode 100644
index 0000000..b76ecee
--- /dev/null
+++ b/linux/home/.editorconfig
@@ -0,0 +1,76 @@
+
+root = true
+
+
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 4
+max_line_length = 10000
+
+# Makefile-specific settings
+[Makefile]
+indent_style = tab
+indent_size = 4
+
+# C/C++ source files
+[*.c]
+indent_style = tab
+indent_size = 4
+
+# TypeScript/JavaScript config
+[**.{ts,js}]
+indent_size = 2
+
+# Json config
+[**.json]
+indent_size = 2
+
+# Lua config
+[*.lua]
+indent_size = 2
+tab_width = 2
+# [none/single/double]
+quote_style = double
+# [line break]
+break_all_list_when_line_exceed = false
+auto_collapse_lines = false
+break_before_braces = false
+# [preference]
+ignore_space_after_colon = false
+remove_call_expression_list_finish_comma = false
+end_statement_with_semicolon = keep
+
+# Python config
+[*.py]
+indent_size = 4
+
+# Bash config
+[*.bash]
+indent_size = 4
+
+# Yaml config
+[*.yml]
+indent_size = 2
+
+# Latex config
+[**.tex]
+trim_trailing_whitespace = false
+
+# Markdown config
+[**.md]
+indent_size = 2
+trim_trailing_whitespace = false
+
+# Textfile config
+[**.txt]
+trim_trailing_whitespace = false
+insert_final_newline = false
+
+# Snippets config
+[**.snippets]
+indent_style = tab
+
diff --git a/linux/home/.face b/linux/home/.face
new file mode 100644
index 0000000..3aafd06
--- /dev/null
+++ b/linux/home/.face
Binary files differ
diff --git a/linux/home/.gitconfig b/linux/home/.gitconfig
new file mode 100644
index 0000000..8b2ef30
--- /dev/null
+++ b/linux/home/.gitconfig
@@ -0,0 +1,28 @@
+[user]
+ name = srdusr
+ email = trevorgray@srdusr.com
+[init]
+ defaultBranch = main
+[color]
+ ui = true
+[alias]
+ graph = log --oneline --graph --decorate
+ ls = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate
+ ll = log --pretty=format:"%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --numstat
+ lds = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --date=short
+ conflicts = diff --name-only --diff-filter=U
+ local-branches = !git branch -vv | cut -c 3- | awk '$3 !~/\\[/ { print $1 }'
+ recent-branches = !git branch --sort=-committerdate | head
+ authors = !git log --format='%aN <%aE>' | grep -v 'users.noreply.github.com' | sort -u --ignore-case
+ sba ="!f() { git subtree add --prefix $2 $1 main; }; f"
+ sbu ="!f() { git subtree pull --prefix $2 $1 main; }; f"
+ stashrebase = "!f() { if [ \"$(git symbolic-ref --short HEAD)\" = \"main\" ]; then git stash save && git fetch && git rebase origin main && git stash apply; else git stash save && git fetch && git rebase origin master && git stash apply; fi; }; f"
+ dotfiles = "!f() { git --git-dir=$HOME/.cfg --work-tree=$HOME stashrebase; }; f"
+
+
+[credential "https://github.com"]
+ helper =
+ helper = !/usr/bin/gh auth git-credential
+[credential "https://gist.github.com"]
+ helper =
+ helper = !/usr/bin/gh auth git-credential
diff --git a/linux/home/.github/workflows/release.yml b/linux/home/.github/workflows/release.yml
new file mode 100644
index 0000000..0dcf439
--- /dev/null
+++ b/linux/home/.github/workflows/release.yml
@@ -0,0 +1,59 @@
+name: Create Release
+
+on:
+ push:
+ tags:
+ - 'v*' # This triggers the workflow on version tags
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Download dotfiles zip
+ run: |
+ mkdir -p $HOME/temp-dotfiles
+ cd $HOME/temp-dotfiles
+ echo "Downloading dotfiles-main.zip..."
+ curl -LOk https://github.com/srdusr/dotfiles/archive/main.zip
+ ls -lh main.zip # Log file size
+ unzip main.zip -d dotfiles-main
+ mv dotfiles-main/dotfiles-main dotfiles
+ ls -lh dotfiles # Log extracted files
+
+ - name: Create zip file
+ run: |
+ cd $HOME/temp-dotfiles
+ zip -r dotfiles.zip dotfiles
+
+ - name: Move zip file to home directory
+ run: |
+ mv /home/runner/temp-dotfiles/dotfiles.zip /home/runner/dotfiles.zip
+ ls -lh $HOME/dotfiles.zip # Verify existence after move (optional)
+
+ - name: Clean up
+ run: |
+ rm -rf $HOME/temp-dotfiles
+ echo $HOME
+
+ - name: Create GitHub Release
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ github.ref }}
+ release_name: Release ${{ github.ref }}
+ body: Automatically generated release
+ draft: false
+ prerelease: false
+
+ - name: Upload zip to release
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }}
+ asset_path: /home/runner/dotfiles.zip
+ asset_name: dotfiles.zip
+ asset_content_type: application/zip
diff --git a/linux/home/.gitignore b/linux/home/.gitignore
new file mode 100644
index 0000000..dc6a064
--- /dev/null
+++ b/linux/home/.gitignore
@@ -0,0 +1,48 @@
+.cfg
+install.sh
+# Ignore Packer's compiled files
+packer_compiled.lua
+
+# Ignore Zsh plugins directory
+~/.config/zsh/plugins
+
+# Ignore zcompdump files
+zcompdump
+
+# Ignore .DS_Store files (macOS)
+*.DS_Store
+
+# Ignore .git directory
+.git/
+
+# Ignore .spl files
+*.spl
+
+# Ignore node_modules directory
+node_modules/
+
+## Ignore .png files
+#*.png
+
+# Ignore .zip files
+*.zip
+
+# Ignore .pxd files
+*.pxd
+
+# Ignore .local directory
+#^.local/
+
+# Ignore .cache directory
+^.cache/
+
+# Ignore downloads directory
+^downloads/
+
+# Ignore music directory
+^music/
+
+^images/
+^pictures/
+^machines/
+
diff --git a/linux/home/.gitmodules b/linux/home/.gitmodules
new file mode 100644
index 0000000..37da2b9
--- /dev/null
+++ b/linux/home/.gitmodules
@@ -0,0 +1,12 @@
+[submodule ".vim/pack/plugins/start/vim-tmux-navigator"]
+ path = .vim/pack/plugins/start/vim-tmux-navigator
+ url = https://github.com/christoomey/vim-tmux-navigator.git
+[submodule "zsh/plugins/zsh-you-should-use"]
+ path = .config/zsh/plugins/zsh-you-should-use
+ url = git@github.com:MichaelAquilina/zsh-you-should-use.git
+[submodule "zsh/plugins/zsh-syntax-highlighting"]
+ path = .config/zsh/plugins/zsh-syntax-highlighting
+ url = git@github.com:zsh-users/zsh-syntax-highlighting.git
+[submodule "zsh/plugins/zsh-syntax-highlighting"]
+ path = .config/zsh/plugins/zsh-autosuggestions
+ url = git@github.com:zsh-users/zsh-autosuggestions.git
diff --git a/linux/home/.gitsubtrees b/linux/home/.gitsubtrees
new file mode 100644
index 0000000..dd055cf
--- /dev/null
+++ b/linux/home/.gitsubtrees
@@ -0,0 +1,8 @@
+[subtree ".config/nvim"]
+ path = .config/nvim
+ url = git@github.com:srdusr/nvim.git
+
+[subtree ".scripts"]
+ path = .scripts
+ url = git@github.com:srdusr/scripts.git
+
diff --git a/linux/home/.local/bin/control-center b/linux/home/.local/bin/control-center
new file mode 100755
index 0000000..d0b3320
--- /dev/null
+++ b/linux/home/.local/bin/control-center
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+LOCK_FILE="$HOME/.cache/eww-control-center.lock"
+EWW_BIN="$HOME/.local/bin/eww"
+ACTIVE_PLAYERS=$(playerctl -l | head -n 1)
+
+run() {
+ ${EWW_BIN} open control-center
+ sleep 0.2
+ xdo raise -N eww-bar
+ ${EWW_BIN} update ccenter=true
+
+ sleep 1 && [[ ! -z "$ACTIVE_PLAYERS" ]] && ${EWW_BIN} update mp=true
+}
+
+# Run eww daemon if not running
+if [[ ! `pidof eww` ]]; then
+ ${EWW_BIN} daemon
+ sleep 1
+else
+ if [[ ! -f "$LOCK_FILE" ]]; then
+ touch "$LOCK_FILE"
+ run
+ else
+ [[ ! -z "$ACTIVE_PLAYERS" ]] && ${EWW_BIN} update mp=false && sleep 0.4
+ ${EWW_BIN} update ccenter=false
+ sleep 0.6
+ ${EWW_BIN} close control-center
+ rm "$LOCK_FILE"
+ fi
+fi
diff --git a/linux/home/.local/bin/eww b/linux/home/.local/bin/eww
new file mode 100755
index 0000000..585d6d2
--- /dev/null
+++ b/linux/home/.local/bin/eww
Binary files differ
diff --git a/linux/home/.local/bin/ffmpeg b/linux/home/.local/bin/ffmpeg
new file mode 100755
index 0000000..2258fbd
--- /dev/null
+++ b/linux/home/.local/bin/ffmpeg
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# audio
+A="$(pactl list sources | grep 'analog.*monitor' | awk '{print $2}')"
+# screen size
+S="$(xdpyinfo | grep dimensions | awk '{print $2}')"
+# file name
+N="$(date +"%m-%d-%Y_%I:%M%p").mp4"
+
+# Desktop audio + screen recording
+ffmpeg \
+-s "$S" -r 25 -f x11grab -i :0.0+0,0 \
+-ac 2 ~/"$N"
+
+# ffmpeg can output high quality GIF. Before you start it is always recommended to use a recent version: download or compile.
+
+# ffmpeg -ss 30 -t 3 -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif
+
+# This example will skip the first 30 seconds (-ss 30) of the input and create a 3 second output (-t 3).
+# fps filter sets the frame rate. A rate of 10 frames per second is used in the example.
+# scale filter will resize the output to 320 pixels wide and automatically determine the height while preserving the aspect ratio. The lanczos scaling algorithm is used in this example.
+# palettegen and paletteuse filters will generate and use a custom palette generated from your input. These filters have many options, so refer to the links for a list of all available options and values. Also see the Advanced options section below.
+# split filter will allow everything to be done in one command and avoids having to create a temporary PNG file of the palette.
+# Control looping with -loop output option but the values are confusing. A value of 0 is infinite looping, -1 is no looping, and 1 will loop once meaning it will play twice. So a value of 10 will cause the GIF to play 11 times.
diff --git a/linux/home/.local/bin/nitrogen b/linux/home/.local/bin/nitrogen
new file mode 100755
index 0000000..b8afe27
--- /dev/null
+++ b/linux/home/.local/bin/nitrogen
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+# Wrapper for nitrogen setting the freedesktop.org AccountsService/BackgroundFile so LightDM wallpaper is synced.
+# Inspired by <https://rafaelc.org/posts/sync-wm-wallpaper-with-lightdm-on-linux-mint/>
+
+key_value_retriever() {
+ KEY="${1}"
+ if [[ -z "$KEY" ]]; then
+ printf "ERROR: KEY should not be empty\n"
+ return
+ fi
+ FILE="${2}"
+ if [[ ! -f "$FILE" ]]; then
+ printf "ERROR: Cannot find FILE: %s\n" "$FILE"
+ return
+ fi
+ VALUE_VARNAME="${3}"
+ if [[ -z "$VALUE_VARNAME" ]]; then
+ printf "ERROR: VALUE_VARNAME should not be empty\n"
+ return
+ fi
+ MATCH=$(grep -m1 "^[[:space:]]*${KEY}=" "$FILE")
+ INDEX_OF_FIRST_EQUAL=$(expr index "$MATCH" =)
+ VALUE="${MATCH:${INDEX_OF_FIRST_EQUAL}}"
+ export "$VALUE_VARNAME"="$VALUE"
+}
+
+/usr/bin/nitrogen "$@"
+if [[ "${1:-}" == "--restore" ]]; then
+ exit $?
+fi
+
+NITROGEN_BG_SAVED_CFG_FILE="${HOME}/.config/nitrogen/bg-saved.cfg"
+if [[ ! -f "$NITROGEN_BG_SAVED_CFG_FILE" ]]; then
+ printf "!ERROR! Cannot find NITROGEN_BG_SAVED_CFG_FILE[%s]\n" "$NITROGEN_BG_SAVED_CFG_FILE" 1>&2
+ exit 1
+fi
+
+key_value_retriever "file" "$NITROGEN_BG_SAVED_CFG_FILE" "NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE"
+
+if [[ -z "$NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE" ]]; then
+ printf "!ERROR! Cannot retrieve NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE from NITROGEN_BG_SAVED_CFG_FILE[%s]\n" "NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE" 1>&2
+ exit 1
+fi
+
+if [[ ! -f "$NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE" ]]; then
+ printf "!ERROR! Cannot find NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE[%s]\n" "$NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE" 1>&2
+ exit 1
+fi
+
+printf "Setting nitrogen background into freedesktop.org AccountsService...\n"
+printf "NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE[%s]\n" "$NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE"
+
+"$HOME"/.scripts/lockscreen-wallpaper &
+dbus-send \
+ --print-reply \
+ --system \
+ --dest=org.freedesktop.Accounts \
+ /org/freedesktop/Accounts/User"$(id -u)" \
+ org.freedesktop.DBus.Properties.Set \
+ string:org.freedesktop.DisplayManager.AccountsService \
+ string:BackgroundFile \
+ variant:string:"$NITROGEN_BG_SAVED_CFG_FIRST_BACKGROUND_FILE"
diff --git a/linux/home/.local/bin/notification-center b/linux/home/.local/bin/notification-center
new file mode 100755
index 0000000..d785628
--- /dev/null
+++ b/linux/home/.local/bin/notification-center
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+LOCK_FILE="$HOME/.cache/eww-notification-center.lock"
+EWW_BIN="$HOME/.local/bin/eww"
+
+run() {
+ "$EWW_BIN" open notification-center
+ sleep 0.2
+ "$EWW_BIN" update noticenter=true
+}
+
+# Run eww daemon if not running
+if [[ ! $(pidof eww) ]]; then
+ "$EWW_BIN" daemon
+ sleep 1
+else
+ if [[ ! -f "$LOCK_FILE" ]]; then
+ touch "$LOCK_FILE"
+ run
+ else
+ "$EWW_BIN" update noticenter=false
+ sleep 0.8
+ "$EWW_BIN" close notification-center
+ rm "$LOCK_FILE"
+ fi
+fi
diff --git a/linux/home/.local/bin/xcolor-pick b/linux/home/.local/bin/xcolor-pick
new file mode 100755
index 0000000..459246f
--- /dev/null
+++ b/linux/home/.local/bin/xcolor-pick
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+# ██╗ ██╗ ██████╗ ██████╗ ██╗ ██████╗ ██████╗
+# ╚██╗██╔╝██╔════╝██╔═══██╗██║ ██╔═══██╗██╔══██╗
+# ╚███╔╝ ██║ ██║ ██║██║ ██║ ██║██████╔╝
+# ██╔██╗ ██║ ██║ ██║██║ ██║ ██║██╔══██╗
+# ██╔╝ ██╗╚██████╗╚██████╔╝███████╗╚██████╔╝██║ ██║
+# ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝
+# color picker for X.
+# Simple Script To Pick Color Quickly Using Gpick.
+# Created By: rxyhn.
+
+TEMP_DIR=/tmp/xcolor
+MSG=${XDG_CACHE_HOME:-$HOME/.cache}/xcolor.msg
+
+EXPIRE_TIME=5000
+
+main() {
+
+ HEX_COLOR=$(gpick -pso --no-newline)
+ mkdir -p $TEMP_DIR
+ HEX="${HEX_COLOR#\#}"
+ FNAME="$TEMP_DIR/$HEX.png"
+ convert -size 100x100 xc:"$HEX_COLOR" "$FNAME"
+ COLOR_CODE="$HEX_COLOR"
+
+ printf %s "$COLOR_CODE" | xclip -sel c
+ notify-send -a XColor "$COLOR_CODE" --icon="$FNAME" --expire-time="$EXPIRE_TIME"
+}
+
+main
diff --git a/linux/home/.local/share/applications/com.obsproject.Studio.desktop b/linux/home/.local/share/applications/com.obsproject.Studio.desktop
new file mode 100644
index 0000000..a0a09fd
--- /dev/null
+++ b/linux/home/.local/share/applications/com.obsproject.Studio.desktop
@@ -0,0 +1,99 @@
+[Desktop Entry]
+Version=1.0
+Name=OBS Studio
+GenericName=Streaming/Recording Software
+Comment=Free and Open Source Streaming/Recording Software
+Exec=obs
+#Icon=$HOME/.icons/WhiteSur-dark/apps/scalable/obs.svg
+#Icon=$HOME/.local/share/icons/WhiteSur-dark/apps/scalable/obs.svg
+Icon=/home/srdusr/.local/share/icons/WhiteSur-dark/apps/scalable/obs.svg
+Terminal=false
+Type=Application
+Categories=AudioVideo;Recorder;
+StartupNotify=true
+StartupWMClass=obs
+
+GenericName[an_ES]=Programa de retransmisión/gravación
+Comment[an_ES]=Program de retransmisión/gravación libre y de codigo ubierto
+GenericName[ar_SA]=برامج البث / التسجيل
+Comment[ar_SA]=برنامج بث / تسجيل مجاني ومفتوح المصدر
+GenericName[bn_BD]=স্ট্রিমিং/রেকর্ডিং সফটওয়্যার
+Comment[bn_BD]=ফ্রি এবং মুক্ত সোর্স স্ট্রিমিং/রেকর্ডিং সফ্টওয়্যার
+GenericName[ca_ES]=Programa de retransmissió/enregistrament
+Comment[ca_ES]=Programa de retransmissió/enregistrament de codi lliure i gratuït
+GenericName[cs_CZ]=Software pro vysílání a nahrávání
+Comment[cs_CZ]=Svobodný software pro vysílání a nahrávání
+GenericName[da_DK]=Streaming-/optagelsessoftware
+Comment[da_DK]=Gratis og open-source streaming-/optagelsessoftware
+GenericName[de_DE]=Streaming-/Aufnahme-Software
+Comment[de_DE]=Freie und Open-Source-Streaming-/Aufnahme-Software
+GenericName[el_GR]=Λογισμικό Ροής/Καταγραφής
+Comment[el_GR]=Δωρεαν Λογισμικό Streaming/Kαταγραφή ανοιχτου κωδικα
+GenericName[en_GB]=Streaming/Recording Software
+Comment[en_GB]=Free and Open Source Streaming/Recording Software
+GenericName[es_ES]=Disfusion digital/ Software de grabacion
+Comment[es_ES]=Difusion Digital/Software de grabacion Gratis y con Fuentes Abiertas
+GenericName[et_EE]=Video voogesituse ja salvestuse tarkvara
+Comment[et_EE]=Tasuta ja avatud lähtekoodiga video voogesituse ja salvestuse tarkvara
+GenericName[fa_IR]=نرم افزار جریان/ضبط
+Comment[fa_IR]=نرم افزار منبع باز و رایگان جریان/ضبط
+GenericName[fi_FI]=Striimaus-/tallennusohjelmisto
+Comment[fi_FI]=Ilmainen ja avoimen lähdekoodin striimaus-/tallennusohjelmisto
+GenericName[fil_PH]=Software para sa Streaming/Recording
+Comment[fil_PH]=Libre at Open Source na Streaming/Recording Software
+GenericName[fr_FR]=Logiciel de diffusion/enregistrement
+Comment[fr_FR]=Logiciel de diffusion/enregistrement gratuit et Open Source
+GenericName[gd_GB]=Bathar-bog sruthaidh/clàraidh
+Comment[gd_GB]=Bathar-bog sruthaidh/clàraidh saor le bun-tùs fosgailte
+GenericName[he_IL]=תוכנה לשידורים חיים והקלטה
+Comment[he_IL]=תכנה חינמית בקוד פתוח לשידורים חיים ולהקלטה
+GenericName[hi_IN]=स्ट्रीमिंग/रिकॉर्डिंग सॉफ्टवेयर
+Comment[hi_IN]=स्वतंत्र एवं खुले स्रोत वाला स्ट्रीमिंग/रिकॉर्डिंग सॉफ्टवेयर
+GenericName[hr_HR]=Softver za emitiranje/snimanje
+Comment[hr_HR]=Slobodan softver otvorenog koda za emitiranje/snimanje
+GenericName[hu_HU]=Közvetítő/rögzítő szoftver
+Comment[hu_HU]=Szabad és nyílt forráskódú közvetítő/rögzítő szoftver
+GenericName[id_ID]=Perangkat Lunak Streaming/Perekaman
+Comment[id_ID]=Perangkat Lunak Streaming/Perekaman Gratis dan Sumber Terbuka
+GenericName[it_IT]=Software per dirette e registrazione schermo
+Comment[it_IT]=Software Libero e Open Source Streaming/Registrazione
+GenericName[ja_JP]=配信/録画ソフトウェア
+Comment[ja_JP]=無料のオープンソース配信/録画ソフトウェア
+GenericName[ka_GE]=ვიდეოს ეთერში გამშვები/ჩამწერი პროგრამა
+Comment[ka_GE]=თავისუფალი და ღია წყაროს მქონე, ვიდეოს ეთერში გამშვები/ჩამწერი პროგრამა
+GenericName[kmr_TR]=Nermalava weşandin/tomarkirin-ê
+Comment[kmr_TR]=Nermalava weşandin/tomarkirin-ê belaş û çavkaniya azad
+GenericName[ko_KR]=방송 및 녹화 프로그램
+Comment[ko_KR]=무료 오픈소스 방송 및 녹화 프로그램
+GenericName[ms_MY]=Perisian Penstriman/Rakaman
+Comment[ms_MY]=Perisian Penstriman/Rakaman Bersumber Terbuka dan Bebas
+GenericName[nb_NO]=Strømming- og Opptaksprogramvare
+Comment[nb_NO]=Gratis Strømming- og Opptaksprogramvare med Åpen Kildekode
+GenericName[nl_NL]=Streaming/Opname Software
+Comment[nl_NL]=Vrij en Open Source Streaming/Opname Sofware
+GenericName[pl_PL]=Oprogramowanie do transmisji strumieniowej/nagrywania
+Comment[pl_PL]=Darmowe i otwarte oprogramowanie do transmisji strumieniowej/nagrywania
+GenericName[pt_BR]=Software de Streaming/Gravação
+Comment[pt_BR]=Software de Streaming/Gravação de Código Aberto e Livre
+GenericName[pt_PT]=Programa de transmissão/gravação
+Comment[pt_PT]=Programa de transmissão/gravação livre e de código aberto
+GenericName[ro_RO]=Program de Streaming/Înregistrare
+Comment[ro_RO]=Program de streaming / înregistrare gratuit și open source
+GenericName[ru_RU]=Программа для видеостриминга и видеозаписи
+Comment[ru_RU]=Свободное и открытое ПО для видеостриминга и видеозаписи
+GenericName[sk_SK]=Streamovací/Nahrávací Software
+Comment[sk_SK]=Bezplatný a otvorený streamovací/nahrávací software
+GenericName[sl_SI]=Pretočna/snemalna programska oprema
+Comment[sl_SI]=Brezplačni in odprtokodna programska oprema za pretakanje/snemanje
+GenericName[sv_SE]=Programvara för strömning/inspelning
+Comment[sv_SE]=Fri programvara för strömning/inspelning med öppen källkod
+GenericName[tr_TR]=Yayın/Kayıt Yazılımı
+Comment[tr_TR]=Ücretsiz ve Açık Kaynaklı Yayın/Kayıt Yazılımı
+GenericName[uk_UA]=Програма для трансляцій/запису
+Comment[uk_UA]=Вільне та відкрите програмне забезпечення для трансляцій/запису
+GenericName[vi_VN]=Phần mềm ghi hình/phát luồng
+Comment[vi_VN]=Phần mềm ghi hình / phát luồng mở và miễn phí
+GenericName[zh_CN]=直播/录像软件
+Comment[zh_CN]=自由且开源的用于直播串流以及视频录制的软件
+GenericName[zh_TW]=串流與錄影軟體
+Comment[zh_TW]=免費,開源的串流與錄影軟體
diff --git a/linux/home/.local/share/applications/phototonic.desktop b/linux/home/.local/share/applications/phototonic.desktop
new file mode 100644
index 0000000..b99875e
--- /dev/null
+++ b/linux/home/.local/share/applications/phototonic.desktop
@@ -0,0 +1,17 @@
+[Desktop Entry]
+Name=Phototonic
+Name[de]=Phototonic
+Name[fr]=Phototonic
+Comment=View photos on your computer
+Comment[de]=Photos betrachten und verwalten
+Comment[fr]=Visionner et gérer des photos sur votre ordinateur
+GenericName=Image Viewer
+GenericName[de]=Bildbetrachter
+GenericName[fr]=Visionneuse d'images
+Exec=phototonic %F
+Icon=/home/srdusr/.local/share/icons/WhiteSur-dark/apps/scalable/gwenview.svg
+Terminal=false
+Type=Application
+Categories=Graphics;Viewer;
+StartupNotify=true
+MimeType=image/png;image/gif;image/jpeg;image/bmp;image/svg+xml;
diff --git a/linux/home/.local/share/fonts/fantasque_sans_mono.ttf b/linux/home/.local/share/fonts/fantasque_sans_mono.ttf
new file mode 100644
index 0000000..2fa4311
--- /dev/null
+++ b/linux/home/.local/share/fonts/fantasque_sans_mono.ttf
Binary files differ
diff --git a/linux/home/.local/share/fonts/fira_code_nerd_fonts.ttf b/linux/home/.local/share/fonts/fira_code_nerd_fonts.ttf
new file mode 100644
index 0000000..b19b2f8
--- /dev/null
+++ b/linux/home/.local/share/fonts/fira_code_nerd_fonts.ttf
Binary files differ
diff --git a/linux/home/.local/share/fonts/hack_nerd_fonts_mono.ttf b/linux/home/.local/share/fonts/hack_nerd_fonts_mono.ttf
new file mode 100644
index 0000000..cd3d793
--- /dev/null
+++ b/linux/home/.local/share/fonts/hack_nerd_fonts_mono.ttf
Binary files differ
diff --git a/linux/home/.local/share/fonts/iosevka_nerd_font.ttf b/linux/home/.local/share/fonts/iosevka_nerd_font.ttf
new file mode 100644
index 0000000..bbb351c
--- /dev/null
+++ b/linux/home/.local/share/fonts/iosevka_nerd_font.ttf
Binary files differ
diff --git a/linux/home/.local/share/fonts/material_design_iconic_font.ttf b/linux/home/.local/share/fonts/material_design_iconic_font.ttf
new file mode 100644
index 0000000..5d489fd
--- /dev/null
+++ b/linux/home/.local/share/fonts/material_design_iconic_font.ttf
Binary files differ
diff --git a/linux/home/.local/share/fonts/symbola.ttf b/linux/home/.local/share/fonts/symbola.ttf
new file mode 100644
index 0000000..1248c29
--- /dev/null
+++ b/linux/home/.local/share/fonts/symbola.ttf
Binary files differ
diff --git a/linux/home/.prettierrc.yml b/linux/home/.prettierrc.yml
new file mode 100644
index 0000000..c5d13e2
--- /dev/null
+++ b/linux/home/.prettierrc.yml
@@ -0,0 +1,5 @@
+semi: true
+singleQuote: true
+jsxSingleQuote: true
+trailingComma: all
+arrowParens: avoid
diff --git a/linux/home/.profile b/linux/home/.profile
new file mode 100644
index 0000000..623fbb0
--- /dev/null
+++ b/linux/home/.profile
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+#if [ "$(tty)" = "/dev/tty1" -a -z "$(printenv HYPRLAND_INSTANCE_SIGNATURE)" ]; then
+if [ "$DISPLAY" = "" ] && [ "$XDG_VTNR" -eq 1 ]; then
+ exec ~/.scripts/session_manager.sh
+fi
+
+load_zsh_env() {
+ if [ "$ZSH_VERSION" != "" ]; then
+ if [ -f ~/.config/zsh/.zshenv ]; then
+ . ~/.config/zsh/.zshenv
+ fi
+ fi
+}
+
+load_zsh_env
diff --git a/linux/home/.scripts/Heads-Up-Display b/linux/home/.scripts/Heads-Up-Display
new file mode 100755
index 0000000..8680123
--- /dev/null
+++ b/linux/home/.scripts/Heads-Up-Display
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Created By: srdusr
+# Created On: Wed 05 Feb 2023 01:24:37 AM CAT
+# Project: bspwm scratchpad (Heads-Up-Display) with tmux session
+
+if id="$(xdo id -N Heads-Up-Display)"
+ then bspc node "$id" -g hidden -f
+ else kitty --class "Heads-Up-Display" -e tmux new-session -A -s HUD -e bash > /dev/null 2>&1 &
+fi
+
+#- - - - - - - - - -
+
+
+### Alternative method
+
+#id=$(xdotool search --class Heads-Up-Display);
+#if [ -z "$id" ]; then
+# #kitty --class "Heads-Up-Display" -e tmux new-session -A -s HUD -e bash > /dev/null 2>&1 &
+# alacritty --class "Heads-Up-Display" -e tmux new-session -A -s HUD -e bash > /dev/null 2>&1 &
+#else
+# if [ ! -f /tmp/hide_hud ]; then
+# touch /tmp/hide_hud && xdo hide "$id"
+# elif [ -f /tmp/hide_hud ]; then
+# rm /tmp/hide_hud && xdo show "$id"
+# fi
+#fi
+
diff --git a/linux/home/.scripts/README.md b/linux/home/.scripts/README.md
new file mode 100644
index 0000000..458b3cc
--- /dev/null
+++ b/linux/home/.scripts/README.md
@@ -0,0 +1 @@
+# scripts
diff --git a/linux/home/.scripts/bspwm-toggle-visibility.sh b/linux/home/.scripts/bspwm-toggle-visibility.sh
new file mode 100755
index 0000000..45a4c53
--- /dev/null
+++ b/linux/home/.scripts/bspwm-toggle-visibility.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# Created By: srdusr
+# Created On: Mon 18 Sep 2023 18:37:21 CAT
+# Project: Bspwm script to toggle visibility of initial window and bring focus back to it
+
+# Get the ID of the currently focused desktop
+current_desktop_id=$(bspc query -D -d focused --names)
+
+# Get the ID of the first hidden window in the current desktop
+hidden_window_id=$(bspc query -N -d "$current_desktop_id" -n .hidden | head -n 1)
+
+# Check if there's a hidden window in the current desktop
+if [[ -n "$hidden_window_id" ]]; then
+ # There's a hidden window, so unhide it
+ bspc node "$hidden_window_id" -g hidden=off
+ # Bring focus back to the previously hidden window
+ bspc node -f "$hidden_window_id"
+else
+ # There's no hidden window in the current desktop, hide the first available window
+ first_window_id=$(bspc query -N -n focused.window)
+ bspc node "$first_window_id" -g hidden=on
+fi
diff --git a/linux/home/.scripts/bspwm_resize.sh b/linux/home/.scripts/bspwm_resize.sh
new file mode 100755
index 0000000..29ab5cf
--- /dev/null
+++ b/linux/home/.scripts/bspwm_resize.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+size=${2:-'10'}
+dir=$1
+
+# Find current window mode
+is_tiled() {
+bspc query -T -n | grep -q '"state":"tiled"'
+}
+# If the window is floating, move it
+if ! is_tiled; then
+#only parse input if window is floating,tiled windows accept input as is
+ case "$dir" in
+ west) switch="-w"
+ sign="-"
+ ;;
+ east) switch="-w"
+ sign="+"
+ ;;
+ north) switch="-h"
+ sign="-"
+ ;;
+ south) switch="-h"
+ sign="+"
+ ;;
+ esac
+ xdo resize ${switch} ${sign}${size}
+
+# Otherwise, window is tiled: switch with window in given direction
+else
+ case "$dir" in
+ west) bspc node @west -r -$size || bspc node @east -r -${size}
+ ;;
+ east) bspc node @west -r +$size || bspc node @east -r +${size}
+ ;;
+ north) bspc node @south -r -$size || bspc node @north -r -${size}
+ ;;
+ south) bspc node @south -r +$size || bspc node @north -r +${size}
+ ;;
+ esac
+fi
+
+##!/bin/bash
+#
+#[ "$#" -eq 3 ] || { echo "Needs exactly three arguments."; exit 1; }
+#
+#motion="$1"
+#direction="$2"
+#size="$3"
+#
+#if [ "$motion" = 'expand' ]; then
+# # These expand the window's given side
+# case "$direction" in
+# north) bspc node -z top 0 -"$size" ;;
+# east) bspc node -z right "$size" 0 ;;
+# south) bspc node -z bottom 0 "$size" ;;
+# west) bspc node -z left -"$size" 0 ;;
+# esac
+#else
+# # These contract the window's given side
+# case "$direction" in
+# north) bspc node -z top 0 "$size" ;;
+# east) bspc node -z right -"$size" 0 ;;
+# south) bspc node -z bottom 0 -"$size" ;;
+# west) bspc node -z left "$size" 0 ;;
+# esac
+#fi
diff --git a/linux/home/.scripts/check-updates.sh b/linux/home/.scripts/check-updates.sh
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/linux/home/.scripts/check-updates.sh
diff --git a/linux/home/.scripts/colors.sh b/linux/home/.scripts/colors.sh
new file mode 100755
index 0000000..fc1c10c
--- /dev/null
+++ b/linux/home/.scripts/colors.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+colors=$@
+for (( n=0; n < $colors; n++ )) do
+ printf " [%d] $(tput setaf $n)%s$(tput sgr0)" $n "Hello World!
+"
+done
+PADDING='Padding'
+
+main() {
+ local xterm_start=0 \
+ xterm_width=8 \
+ xterm_height=2
+
+ local cube_start=$((xterm_start + xterm_width * xterm_height)) \
+ cube_width=6 \
+ cube_height=$((6 * 6))
+
+ local greys_start=$((cube_start + cube_width * cube_height)) \
+ greys_width=8 \
+ greys_height=3
+
+ color_block $xterm_start $xterm_width $xterm_height
+ color_block $cube_start $cube_width $cube_height use_padding
+ color_block $greys_start $greys_width $greys_height
+ echo
+}
+
+color_block() {
+ local start=$1 width=$2 height=$3 use_padding=$4
+ local max s color_nums colors
+
+ max=$((start + width * height - 1))
+
+ echo
+ for s in $(seq $start $width $max); do
+ color_nums=$(seq $s $((s + width - 1)))
+ colors="${use_padding:+$PADDING }${color_nums}${use_padding:+ $PADDING}"
+
+ printf '%s%s %s%s\n' \
+ "$(fg_bars $colors)" $ansi_reset \
+ "$(bg_bars $colors)" $ansi_reset
+ done
+}
+
+fg_bars() {
+ for color in $@; do
+ color_bar ansi_fg $color ''
+ done
+}
+
+bg_bars() {
+ for color in $@; do
+ color_bar ansi_bg $color ' '
+ done
+}
+
+color_bar() {
+ local ansi=$1 color=$2 trail=$3
+
+ if [ "$color" == $PADDING ]; then
+ printf '%s %s' $ansi_reset "$trail"
+ else
+ local color_seq=$($ansi $color)
+ printf '%s %03d%s' $color_seq $color "$trail"
+ fi
+}
+
+ansi_reset=$'\033[0m'
+
+ansi_fg() {
+ printf '\033[38;5;%dm' $1
+}
+
+ansi_bg() {
+ printf '\033[48;5;%dm' $1
+}
+
+main
diff --git a/linux/home/.scripts/cryptocheck b/linux/home/.scripts/cryptocheck
new file mode 100755
index 0000000..02ba42d
--- /dev/null
+++ b/linux/home/.scripts/cryptocheck
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+if [ ! -d ~/.cache/crypto ]; then
+ mkdir ~/.cache/crypto
+fi
+ticker=(BTC ETH ADA DOT SOL XMR)
+
+for currency in "${ticker[@]}"; do
+ echo "$currency"
+done | while read coin
+ do
+ price=$(curl rate.sx/1$coin)
+ if [ $coin = "BTC" ]; then
+ icon=󰠓
+ elif [ $coin = "ETH" ]; then
+ icon=󰡪
+ elif [ $coin = "ADA" ]; then
+ icon=󰝨
+ elif [ $coin = "DOT" ]; then
+ icon=󰐇
+ elif [ $coin = "SOL" ]; then
+ icon=󰘙
+ elif [ $coin = "XMR" ]; then
+ icon=󰝴
+ fi
+
+ echo "$icon $coin: $price" > ~/.cache/crypto/$coin
+
+ done
+
+date > ~/.cache/crypto/time
+
diff --git a/linux/home/.scripts/cryptonotify b/linux/home/.scripts/cryptonotify
new file mode 100755
index 0000000..47883c3
--- /dev/null
+++ b/linux/home/.scripts/cryptonotify
@@ -0,0 +1,19 @@
+#!/bin/sh
+source cryptocheck
+Output=
+for file in ~/.cache/crypto/*
+do
+ if [ ! -z "$Output" ]; then
+ if [ ! $(basename $file) = "time" ]; then
+ Output="$Output\n$(cat $file)"
+ fi
+ else
+ if [ ! $(basename $file) = "time" ]; then
+ Output="$Output$(cat $file)"
+ fi
+ fi
+
+done
+
+Output="$Output\n$(cat ~/.cache/crypto/time)"
+notify-send "Crypto Prices" "$Output"
diff --git a/linux/home/.scripts/dotfiles.sh b/linux/home/.scripts/dotfiles.sh
new file mode 100755
index 0000000..b231367
--- /dev/null
+++ b/linux/home/.scripts/dotfiles.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# Set the bare dotfiles repo directory
+dotfiles_dir="$HOME/.cfg"
+
+# Set the home directory
+home_dir="$HOME"
+
+# Exclude the .cfg directory and any other files/directories you want to ignore
+exclude_list=(".cfg")
+
+# Change to the home directory
+cd "$home_dir"
+
+# Get a list of all dotfiles in the repository
+files=$(find "$dotfiles_dir" -maxdepth 1 -type f -not -name ".*" -not -name "${exclude_list[*]}" -printf "%f\n")
+
+# Link each file to its corresponding location in $HOME
+for file in $files; do
+ ln -sf "$dotfiles_dir/$file" "$home_dir/.$file"
+done
+
+# Get a list of all dot directories in the repository
+dirs=$(find "$dotfiles_dir" -maxdepth 1 -type d -not -path "$dotfiles_dir" -not -name ".*" -not -name "${exclude_list[*]}" -printf "%f\n")
+
+# Link each directory to its corresponding location in $HOME
+for dir in $dirs; do
+ ln -sf "$dotfiles_dir/$dir" "$home_dir/.$dir"
+done
+
+# Remove any symlinks that are no longer present in the repo
+while IFS= read -r -d '' link; do
+ if [[ ! -e "$link" ]]; then
+ rm "$link"
+ fi
+done < <(find "$home_dir" -maxdepth 1 -type l -name ".*" -not -name ".cfg" -print0)
+
diff --git a/linux/home/.scripts/ffmpeg b/linux/home/.scripts/ffmpeg
new file mode 100755
index 0000000..2258fbd
--- /dev/null
+++ b/linux/home/.scripts/ffmpeg
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# audio
+A="$(pactl list sources | grep 'analog.*monitor' | awk '{print $2}')"
+# screen size
+S="$(xdpyinfo | grep dimensions | awk '{print $2}')"
+# file name
+N="$(date +"%m-%d-%Y_%I:%M%p").mp4"
+
+# Desktop audio + screen recording
+ffmpeg \
+-s "$S" -r 25 -f x11grab -i :0.0+0,0 \
+-ac 2 ~/"$N"
+
+# ffmpeg can output high quality GIF. Before you start it is always recommended to use a recent version: download or compile.
+
+# ffmpeg -ss 30 -t 3 -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif
+
+# This example will skip the first 30 seconds (-ss 30) of the input and create a 3 second output (-t 3).
+# fps filter sets the frame rate. A rate of 10 frames per second is used in the example.
+# scale filter will resize the output to 320 pixels wide and automatically determine the height while preserving the aspect ratio. The lanczos scaling algorithm is used in this example.
+# palettegen and paletteuse filters will generate and use a custom palette generated from your input. These filters have many options, so refer to the links for a list of all available options and values. Also see the Advanced options section below.
+# split filter will allow everything to be done in one command and avoids having to create a temporary PNG file of the palette.
+# Control looping with -loop output option but the values are confusing. A value of 0 is infinite looping, -1 is no looping, and 1 will loop once meaning it will play twice. So a value of 10 will cause the GIF to play 11 times.
diff --git a/linux/home/.scripts/get_zle_keymap_select.sh b/linux/home/.scripts/get_zle_keymap_select.sh
new file mode 100755
index 0000000..1e2eaf4
--- /dev/null
+++ b/linux/home/.scripts/get_zle_keymap_select.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Get the value of the zle-keymap-select variable
+value=$(print -v zle-keymap-select)
+
+# Specify the file path to save the value
+file_path="~/file.txt"
+
+# Write the value to the file
+echo "$value" > "$file_path"
+
+# Optionally, you can also print the value to the console
+echo "The value of zle-keymap-select is: $value"
diff --git a/linux/home/.scripts/gsettings.sh b/linux/home/.scripts/gsettings.sh
new file mode 100755
index 0000000..0cd28c2
--- /dev/null
+++ b/linux/home/.scripts/gsettings.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Disable screen lock
+gsettings set org.gnome.desktop.screensaver lock-enabled false
+gsettings set org.gnome.desktop.session idle-delay 0
+
+# Mutter Overlay Key
+gsettings set org.gnome.mutter overlay-key ''
+
+# Disable update notification
+#gsettings set org.gnome.software download-updates false
+#gsettings set com.ubuntu.update-notifier no-show-notifications true
+#sudo rm /etc/xdg/autostart/upg-notifier-autostart.desktop
+
+#sudo mv /etc/xdg/autostart/update-notifier.desktop /etc/xdg/autostart/update-notifier.desktop.old
+#sudo mv /etc/xdg/autostart/gnome-software-service.desktop /etc/xdg/autostart/gnome-software-service.desktop.old
+
+# Custom Keybinding Names
+gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "['/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/']"
+
+# Custom Keybinding 0
+gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ binding "<Alt>T"
+gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ command "scratchpad"
+gsettings set org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/ name "scratchpad"
+
+# Disable keyboard plugin
+gsettings set org.gnome.settings-daemon.plugins.keyboard active false
diff --git a/linux/home/.scripts/killandnotify b/linux/home/.scripts/killandnotify
new file mode 100755
index 0000000..2e7222e
--- /dev/null
+++ b/linux/home/.scripts/killandnotify
@@ -0,0 +1,4 @@
+#!/bin/sh
+# Kills an application and sends a notification that it's been killed
+
+killall "$1" && notify-send "$1" "$2"
diff --git a/linux/home/.scripts/layer.sh b/linux/home/.scripts/layer.sh
new file mode 100755
index 0000000..4b17ed1
--- /dev/null
+++ b/linux/home/.scripts/layer.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+current_layer="$(bspc query -T -n | jq -r '.client.layer')"
+case $1 in
+ +|-)
+ declare -A _layers=( [below]=0 [normal]=1 [above]=2 )
+ layers=( below normal above )
+ maxl=$(( ${#layers[@]} - 1 ))
+ current_layer="$(bspc query -T -n | jq -r '.client.layer')"
+ i=$(( ${_layers[$current_layer]} $1 1 ))
+ if [[ $i -lt 0 ]]; then
+ i=0
+ elif [[ $i -gt $maxl ]]; then
+ i=$maxl
+ fi
+ #cycle? nah
+ #i=$(( (${_layers[$current_layer]} + ${#layers[@]} ${1} 1) % ${#layers[@]} ))
+ new_layer="${layers[$i]}"
+ ;;
+ *)
+ new_layer="$(bspc query -T -n | jq -r '.client.lastLayer')"
+ ;;
+esac
+[[ "$current_layer" != "$new_layer" ]] && bspc node -l "$new_layer"
diff --git a/linux/home/.scripts/neovim.sh b/linux/home/.scripts/neovim.sh
new file mode 100755
index 0000000..39554cb
--- /dev/null
+++ b/linux/home/.scripts/neovim.sh
@@ -0,0 +1,421 @@
+#!/bin/bash
+
+# Created By: srdusr
+# Created On: Sat 12 Aug 2023 13:11:39 CAT
+# Project: Install/update/uninstall/change version Neovim script, primarily for Linux but may work in other platforms
+
+# Dependencies: wget/curl, fuse
+
+# Color definitions
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+NC='\033[0m' # No Color
+
+# Function to handle errors
+handle_error() {
+ local message="$1"
+ printf "${RED}Error: $message${NC}\n"
+}
+
+# Check if necessary dependencies are installed
+check_dependencies() {
+ if [ -x "$(command -v wget)" ]; then
+ DOWNLOAD_COMMAND="wget"
+ elif [ -x "$(command -v curl)" ]; then
+ DOWNLOAD_COMMAND="curl"
+ else
+ printf "${RED}Error: Neither wget nor curl found. Please install one of them to continue!${NC}\n"
+ exit 1
+ fi
+}
+
+# Check for privilege escalation tools
+check_privilege_tools() {
+ if [ -x "$(command -v sudo)" ]; then
+ PRIVILEGE_TOOL="sudo"
+ elif [ -x "$(command -v doas)" ]; then
+ PRIVILEGE_TOOL="doas"
+ elif [ -x "$(command -v pkexec)" ]; then
+ PRIVILEGE_TOOL="pkexec"
+ elif [ -x "$(command -v dzdo)" ]; then
+ PRIVILEGE_TOOL="dzdo"
+ elif [ "$(id -u)" -eq 0 ]; then
+ PRIVILEGE_TOOL="" # root
+ else
+ PRIVILEGE_TOOL="" # No privilege escalation mechanism found
+ printf "\n${RED}Error: No privilege escalation tool (sudo, doas, pkexec, dzdo, or root privileges) found. You may not have sufficient permissions to run this script.${NC}\n"
+ printf "\nAttempt to continue Installation (might fail without a privilege escalation tool)? [yes/no] "
+ read continue_choice
+ case $continue_choice in
+ [Yy] | [Yy][Ee][Ss]) ;;
+ [Nn] | [Nn][Oo]) exit ;;
+ *) handle_error "Invalid choice. Exiting..." && exit ;;
+ esac
+ fi
+}
+
+# Check if Neovim is already installed
+check_neovim_installed() {
+ if [ -x "$(command -v nvim)" ]; then
+ return 0 # Neovim is installed
+ else
+ return 1 # Neovim is not installed
+ fi
+}
+
+# Nightly version
+nightly_version() {
+ local url="https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage"
+ install_neovim "$url"
+ local version_output=$(nvim --version)
+ version_id="Nightly $(echo "$version_output" | grep -oP 'NVIM \d+\.\d+')"
+}
+
+# Stable version
+stable_version() {
+ local url="https://github.com/neovim/neovim/releases/download/stable/nvim.appimage"
+ install_neovim "$url"
+ local version_output=$(nvim --version)
+ version_id="Stable $(echo "$version_output" | grep -oP 'NVIM \d+\.\d+')"
+}
+
+# Specific version
+specific_version() {
+ local version="$1"
+
+ # Add 'v' prefix if not present
+ if [[ $version != v* ]]; then
+ version="v$version"
+ fi
+
+ local url="https://github.com/neovim/neovim/releases/download/$version/nvim.appimage"
+ install_neovim "$url"
+ local version_output=$(nvim --version)
+ version_id="Version $version $(echo "$version_output" | grep -oP 'NVIM \d+\.\d+')"
+}
+
+# Function to download a file using wget or curl
+download_file() {
+ local url="$1"
+ local output="$2"
+
+ if [ "$DOWNLOAD_COMMAND" = "wget" ]; then
+ if ! "$DOWNLOAD_COMMAND" -q --show-progress -O "$output" "$url"; then
+ handle_error "Download failed. Exiting..."
+ exit 1
+ fi
+ elif [ "$DOWNLOAD_COMMAND" = "curl" ]; then
+ if ! "$DOWNLOAD_COMMAND" --progress-bar -# -o "$output" "$url"; then
+ handle_error "Download failed. Exiting..."
+ exit 1
+ fi
+ else
+ echo "Unsupported download command: $DOWNLOAD_COMMAND"
+ exit 1
+ fi
+}
+
+# Check if a specific version of Neovim exists
+version_exists() {
+ local version="$1"
+
+ # Add 'v' prefix if not present
+ if [[ $version != v* ]]; then
+ version="v$version"
+ fi
+
+ # Fetch all the release tags from GitHub
+ ALL_TAGS=$(curl -s "https://api.github.com/repos/neovim/neovim/tags" | grep '"name":' | cut -d '"' -f 4)
+
+ # Check if the desired version is in the list of release tags
+ if echo "$ALL_TAGS" | grep -q "$version"; then
+ return 0 # Version exists
+ else
+ return 1 # Version does not exist
+ fi
+}
+
+# Update Neovim to the latest version (nightly/stable)
+update_version() {
+ valid_choice=false
+ while [ "$valid_choice" = false ]; do
+ # Determine which version to update to (nightly/stable)
+ printf "Select version to install/update to:\n"
+ printf " 1. Nightly\n"
+ printf " 2. Stable\n"
+ printf " 3. Choose specific version by tag\n"
+ printf "Enter the number corresponding to your choice (1/2/3): "
+ read update_choice
+
+ case $update_choice in
+ 1)
+ version="Nightly"
+ nightly_version
+ valid_choice=true
+ ;;
+ 2)
+ version="Stable"
+ stable_version
+ valid_choice=true
+ ;;
+ 3)
+ # Ask user for specific version
+ read -p "Enter the specific version (e.g., v0.1.0): " version
+ # Normalize version
+ if [[ $version != v* ]]; then
+ version="v$version"
+ fi
+ # Check if the specific version exists on GitHub releases
+ if version_exists "$version"; then
+ # Install specific version
+ specific_version "$version" # Pass the normalized version to the function
+ valid_choice=true
+ else
+ printf "${RED}The specified version $version does not exist.${NC}\n"
+ fi
+ ;;
+
+ *)
+ handle_error "Invalid choice. Please enter a valid option (1, 2 or 3)."
+ ;;
+ esac
+ done
+
+}
+
+# Install Neovim
+install_neovim() {
+ local url="$1"
+ local install_action="$3"
+
+ if [ "$install_action" = "installed" ]; then
+ printf "Downloading and installing Neovim $version...\n"
+ else
+ printf "${GREEN}Updating Neovim to the latest version ($version)...${NC}\n"
+ fi
+
+ # Determine the platform-specific installation steps
+ case "$(uname -s)" in
+ Linux)
+ printf "Detected Linux OS.\n"
+ if [ -x "$(command -v fusermount)" ]; then
+ printf "FUSE is available. Downloading and running the AppImage...\n"
+ download_file "$url" "nvim.appimage"
+ chmod u+x nvim.appimage
+ "$PRIVILEGE_TOOL" cp nvim.appimage /usr/local/bin/nvim
+ "$PRIVILEGE_TOOL" mv nvim.appimage /usr/bin/nvim
+ else
+ printf "FUSE is not available. Downloading and extracting the AppImage...\n"
+ download_file "$url" "nvim.appimage"
+ chmod u+x nvim.appimage
+ ./nvim.appimage --appimage-extract
+ "$PRIVILEGE_TOOL" cp squashfs-root/usr/bin/nvim /usr/local/bin
+ "$PRIVILEGE_TOOL" mv squashfs-root/usr/bin/nvim /usr/bin
+ fi
+ ;;
+
+ Darwin)
+ printf "Detected macOS.\n"
+ download_file "$url" "nvim-macos.tar.gz"
+ xattr -c ./nvim-macos.tar.gz
+ tar xzvf nvim-macos.tar.gz
+ "$PRIVILEGE_TOOL" cp nvim-macos/bin/nvim /usr/local/bin
+ "$PRIVILEGE_TOOL" mv nvim-macos/bin/nvim /usr/bin/nvim
+ ;;
+
+ MINGW*)
+ printf "Detected Windows.\n"
+ download_file "$url" "nvim.appimage"
+ chmod +x nvim.appimage
+ if [ "$PRIVILEGE_TOOL" = "sudo" ]; then
+ "$PRIVILEGE_TOOL" cp nvim.appimage /usr/local/bin/nvim
+ "$PRIVILEGE_TOOL" mv /usr/local/bin/nvim /usr/bin
+ elif [ "$PRIVILEGE_TOOL" = "" ]; then
+ cp nvim.appimage /usr/local/bin/nvim
+ mv /usr/local/bin/nvim /usr/bin
+ else
+ printf "No privilege escalation tool found. Cannot install Neovim on Windows.\n"
+ fi
+ ;;
+
+ *)
+ printf "Unsupported operating system.\n"
+ exit 1
+ ;;
+ esac
+ # Check if the installation was successful
+ if [ $? -eq 0 ]; then
+ if [ "$install_action" = "installed" ]; then
+ printf "${GREEN}Neovim $version has been installed successfully!${NC}\n"
+ else
+ printf "${GREEN}Neovim has been updated successfully to $version!${NC}\n"
+ fi
+ else
+ printf "${RED}Error: Neovim installation/update failed.${NC}\n"
+ exit 1
+ fi
+}
+
+# Uninstall Neovim
+uninstall_neovim() {
+ printf "${RED}Uninstalling Neovim...${NC}\n"
+
+ # Detect the operating system to determine the appropriate uninstallation method
+ case "$(uname -s)" in
+ Linux)
+ printf "Detected Linux OS.\n"
+ "$PRIVILEGE_TOOL" rm /usr/local/bin/nvim
+ "$PRIVILEGE_TOOL" rm /usr/bin/nvim
+ ;;
+
+ Darwin)
+ printf "Detected macOS.\n"
+ "$PRIVILEGE_TOOL" rm /usr/local/bin/nvim
+ "$PRIVILEGE_TOOL" rm /usr/bin/nvim
+ ;;
+
+ MINGW*)
+ printf "Detected Windows.\n"
+ if [ "$PRIVILEGE_TOOL" = "sudo" ]; then
+ "$PRIVILEGE_TOOL" rm /usr/local/bin/nvim
+ "$PRIVILEGE_TOOL" rm /usr/bin/nvim
+ else
+ [ "$PRIVILEGE_TOOL" = "" ]
+ rm /usr/local/bin/nvim
+ rm /usr/bin/nvim
+ fi
+ ;;
+ *)
+ printf "Unsupported operating system.\n"
+ ;;
+ esac
+
+ printf "${GREEN}Neovim has been uninstalled successfully!${NC}\n"
+}
+
+# Check if Neovim is running
+check_neovim_running() {
+ if pgrep nvim >/dev/null; then
+ printf "${RED}Error: Neovim is currently running. Please close Neovim before proceeding.${NC}\n"
+ read -p "Do you want to forcefully terminate Neovim and continue? [yes/no] " terminate_choice
+
+ case $terminate_choice in
+ [Yy] | [Yy][Ee][Ss])
+ pkill nvim # Forcefully terminate Neovim
+ ;;
+ [Nn] | [Nn][Oo])
+ echo "Exiting..."
+ exit 1
+ ;;
+ *)
+ handle_error "Invalid choice."
+ ;;
+ esac
+ fi
+}
+
+check_neovim_running
+
+# Define the variable to control the prompt
+SHOW_PROMPT=1
+
+# Check if necessary dependencies are installed
+check_dependencies
+
+# Check for privilege escalation tools
+check_privilege_tools
+
+# Check if Neovim is already installed and ask the user if want to install it
+if check_neovim_installed; then
+ printf "${GREEN}Neovim is already installed!${NC}\n"
+else
+ printf "${RED}Neovim is not installed.${NC}\n"
+ read -p "Install Neovim? (y/n): " install_choice
+
+ case $install_choice in
+ [Yy])
+ update_version
+ ;;
+ [Nn])
+ echo "Exiting..."
+ exit
+ ;;
+ *)
+ handle_error "Invalid choice. Please enter 'y' for yes or 'n' for no."
+ ;;
+ esac
+fi
+
+# Function to check for updates and display breaking changes
+check_version_updates() {
+ local latest_version_url="https://api.github.com/repos/neovim/neovim/releases/latest"
+ local latest_version=""
+
+ if [ -x "$(command -v curl)" ]; then
+ latest_version=$(curl -sSL "$latest_version_url" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
+ elif [ -x "$(command -v wget)" ]; then
+ latest_version=$(wget -qO - "$latest_version_url" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
+ else
+ printf "${RED}Error: Neither curl nor wget found. Please install one of them to continue!${NC}\n"
+ exit 1
+ fi
+
+ if version_exists "$latest_version"; then
+ printf "${GREEN}An update is available!${NC}\n"
+ display_breaking_changes "$latest_version"
+ else
+ printf "You have the latest version of Neovim.\n"
+ fi
+}
+
+# Function to display breaking changes for a specific version
+display_breaking_changes() {
+ local version="$1"
+ local changelog_url="https://github.com/neovim/neovim/releases/tag/$version"
+ local changelog=""
+
+ if [ -x "$(command -v curl)" ]; then
+ changelog=$(curl -sSL "$changelog_url" | grep -oE '<h1>Breaking Changes.*?</ul>' | sed 's/<[^>]*>//g')
+ elif [ -x "$(command -v wget)" ]; then
+ changelog=$(wget -qO - "$changelog_url" | grep -oE '<h1>Breaking Changes.*?</ul>' | sed 's/<[^>]*>//g')
+ else
+ printf "${RED}Error: Neither curl nor wget found. Please install one of them to continue!${NC}\n"
+ exit 1
+ fi
+
+ printf "\nBreaking Changes in Neovim $version:\n"
+ printf "$changelog\n"
+}
+
+# Main loop
+while [ "$SHOW_PROMPT" -gt 0 ]; do
+ printf "Select an option:\n"
+ printf " 1. Install/update Neovim\n"
+ printf " 2. Check for updates\n"
+ printf " 3. Uninstall Neovim\n"
+ printf " 4. Run Neovim\n"
+ printf " 5. Quit\n"
+ read -p "Enter a number or press 'q' to quit: " choice
+
+ case $choice in
+ 1)
+ update_version
+ ;;
+ 2)
+ check_version_updates
+ ;;
+ 3)
+ uninstall_neovim
+ ;;
+ 4)
+ nvim
+ ;;
+ 5 | [Qq])
+ echo "Exiting..."
+ exit
+ ;;
+ *)
+ handle_error "Invalid choice. Please choose a valid option by entering the corresponding number or press 'q' to 'quit'."
+ ;;
+ esac
+done
diff --git a/linux/home/.scripts/opacity-change.sh b/linux/home/.scripts/opacity-change.sh
new file mode 100755
index 0000000..b509936
--- /dev/null
+++ b/linux/home/.scripts/opacity-change.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+set -eu
+[[ -n ${DEBUG:-} ]] && set -x
+
+#### Example alacritty.yml usage
+#key_bindings:
+# - { key: N, mods: Control|Shift, action: SpawnNewInstance }
+# - { key: O, mods: Control|Shift, command: { program: "opacity-change.sh", args: ["-"] } }
+# - { key: P, mods: Control|Shift, command: { program: "opacity-change.sh", args: ["+"] } }
+
+
+operation="${1:-}${2:-}" # Arg #1 & #2 (in case the user misinterpreted a space in the usage), Default ''
+step="${operation:1}" # Substring from char index 1
+step="${step:-1}" # Default '1'
+operation="${operation:0:1}" # Substring from char index 0 length of 1
+config_file="$HOME/.config/alacritty/alacritty.yml"
+config_field="opacity"
+tmp_file="/tmp/$(basename $config_file).$(date +%s)"
+current_value=$(sed 's/#.*//g; /\b'"$config_field"':/!d; s/.*: \?//' < "$config_file")
+
+case $operation in
+"-")
+ verb="Decreasing" ;;
+"+")
+ verb="Increasing" ;;
+*)
+ echo "Usage: ${BASH_SOURCE[0]} (-|+)[int]"; exit 255 ;;
+esac
+
+new_value="$(awk '{n=$1+$2/10; print (n<0 ? 0 : n>1 ? 1 : n)}' <<<"$current_value $operation$step")"
+echo "$verb $config_field from $current_value to $new_value" >&2
+cp "$config_file" "$tmp_file"
+sed "s/\b$config_field:.*/$config_field: $new_value/" "$tmp_file" > "$config_file"
+
diff --git a/linux/home/.scripts/powermenu b/linux/home/.scripts/powermenu
new file mode 100755
index 0000000..7bd913e
--- /dev/null
+++ b/linux/home/.scripts/powermenu
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# display a power menu to: shutdown, reboot,
+# lock, logout, and suspend. This script can be
+# executed by clicking on the polybar powermenu module
+# or with a keyboard shortcut
+
+# options to be displayed
+shutdown=" Shutdown"
+reboot=" Reboot"
+lock=" Lock"
+logout=" Logout"
+suspend=" Suspend"
+
+uptime=$(uptime -p | sed -e 's/up //g')
+
+# options passed into variable
+options="$shutdown\n$reboot\n$lock\n$logout\n$suspend"
+
+chosen="$(echo -e "$options" | rofi -theme ~/.config/rofi/styles/powermenu.rasi -lines 5 -dmenu -p "$uptime")"
+
+case $chosen in
+$shutdown)
+ systemctl poweroff
+ ;;
+$reboot)
+ systemctl reboot
+ ;;
+$lock)
+ betterlockscreen --lock dimblur
+ ;;
+$logout)
+ bspc quit
+ ;;
+$suspend)
+ systemctl suspend
+ ;;
+esac
diff --git a/linux/home/.scripts/qemu-helper.sh b/linux/home/.scripts/qemu-helper.sh
new file mode 100755
index 0000000..0d38aba
--- /dev/null
+++ b/linux/home/.scripts/qemu-helper.sh
@@ -0,0 +1,172 @@
+#!/bin/bash
+
+# Created By: srdusr
+# Created On: Wed 02 Aug 2023 16:16:21 PM CAT
+# Project: QEMU setup/opener helper wrapper script
+
+# Set global variables for VM parameters
+ram_size="4G"
+
+# Function to prompt user for VM parameters
+function get_vm_parameters() {
+ read -p "Enter VM name (default: vm): " vm_name
+ vm_name=${vm_name:-vm}
+
+ # Set the default ISO file path to ~/machines/images
+ default_iso_path="$HOME/machines/images"
+
+ # Generate completions for ISO and IMG files in the images directory
+ COMPREPLY=()
+ local files=$(compgen -G "$default_iso_path/*.{iso,img}" -o plusdirs)
+ for file in $files; do
+ COMPREPLY+=("$file")
+ done
+
+ # Use read with -i and -e options for tab-completion
+ read -ep "Enter ISO file path (default: $default_iso_path): " -i "$default_iso_path" iso_path
+
+ # Manually expand the ~ to the user's home directory
+ iso_path=$(eval echo "$iso_path")
+
+ # Validate the user input
+ while [ ! -f "$iso_path" ]; do
+ read -ep "Invalid file path. Enter a valid ISO file path: " iso_path
+ done
+
+ # Check if the selected file is an IMG file
+ if [[ "$iso_path" == *.img ]]; then
+ guest_os="windows"
+ else
+ guest_os="linux"
+ fi
+
+ # Show available disk space before asking for disk image size
+ echo "Available disk space:"
+ df -h "$vm_images_path"
+
+ read -p "Enter disk image size in GB (default: 10G): " disk_size
+ disk_size=${disk_size:-10G}
+
+ read -p "Enter RAM size in GB (default: 4G): " ram_size
+ ram_size=${ram_size:-4G}
+
+ # Check if the RAM size is in the correct format (e.g., "4G")
+ while ! [[ $ram_size =~ ^[0-9]+[kKmMgGtTpPeE]$ ]]; do
+ read -p "Invalid RAM size format. Enter RAM size in GB (e.g., 4G): " ram_size
+ done
+
+ read -p "Enter number of CPU cores (default: 2): " cpu_cores
+ cpu_cores=${cpu_cores:-2}
+}
+
+
+# Function to list available VMs
+function list_vms() {
+ echo "Available VMs:"
+ for vm_file in "$vm_images_path"/*.qcow2; do
+ vm=$(basename "$vm_file" .qcow2)
+ echo " - $vm"
+ done
+}
+
+# Function to list available ISO and IMG files in the images directory
+function list_iso_img_files() {
+ echo "Available ISO and IMG files in $iso_images_path:"
+ iso_img_files=()
+ while IFS= read -r -d $'\0' file; do
+ iso_img_files+=("$file")
+ done < <(find "$iso_images_path" -type f \( -iname \*.iso -o -iname \*.img \) -print0)
+
+ for ((i = 0; i < ${#iso_img_files[@]}; i++)); do
+ echo " $((i + 1)). ${iso_img_files[i]##*/}"
+ done
+}
+
+# Function to check if VM is already running
+function is_vm_running() {
+ vm_name=$1
+ if ps aux | grep -v grep | grep -q "[q]emu-system-x86_64.*$vm_name"; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+# Function to start VM
+function start_vm() {
+ vm_name=$1
+ is_vm_running "$vm_name"
+ if [ $? -eq 0 ]; then
+ echo "VM '$vm_name' is already running."
+ return
+ fi
+
+ # VM parameters
+ qemu_cmd="qemu-system-x86_64 -enable-kvm -machine type=q35 -m $ram_size -cpu host -smp 2 -vga virtio"
+ qemu_cmd+=" -device qemu-xhci -device usb-tablet -device usb-kbd -device virtio-net,netdev=user0 -netdev user,id=user0,hostfwd=tcp::5555-:22"
+ qemu_cmd+=" -cdrom \"$iso_path\" -drive file=\"$vm_images_path/$vm_name.qcow2\",index=0,media=disk,if=virtio"
+
+ if [[ $guest_os == "windows" ]]; then
+ qemu_cmd+=" -drive file=\"$iso_images_path/virtio-win.iso\",index=3,media=cdrom"
+ fi
+
+ qemu_cmd+=" -boot menu=on"
+ qemu_cmd+=" -net nic -net user,hostname=$vm_name -name \"$vm_name\""
+
+ echo "Starting VM: $vm_name"
+ eval "$qemu_cmd"
+}
+
+# Main script starts here
+vm_images_path="$HOME/machines/vm"
+iso_images_path="$HOME/machines/images"
+
+# Check if directories exist
+mkdir -p "$vm_images_path"
+mkdir -p "$iso_images_path"
+
+# List available VMs
+list_vms
+
+# List available ISO and IMG files in the images directory
+list_iso_img_files
+
+# Ask the user if they want to use an existing VM or create a new one
+read -p "Do you want to use an existing VM? (y/n): " use_existing_vm
+if [[ $use_existing_vm =~ ^[Yy]$ ]]; then
+ read -p "Enter the name of the existing VM: " existing_vm_name
+ while [ ! -f "$vm_images_path/$existing_vm_name.qcow2" ]; do
+ echo "VM '$existing_vm_name' does not exist."
+ read -p "Enter a valid existing VM name: " existing_vm_name
+ done
+ vm_name=$existing_vm_name
+else
+ # Prompt user for VM parameters
+ get_vm_parameters
+
+ # Check if VM already exists
+ if [ -f "$vm_images_path/$vm_name.qcow2" ]; then
+ read -p "VM '$vm_name' already exists. Do you want to start it? (y/n): " start_vm_choice
+ if [[ $start_vm_choice =~ ^[Yy]$ ]]; then
+ start_vm "$vm_name"
+ exit 0
+ fi
+ else
+ # Create new VM
+ echo "Creating new VM: $vm_name"
+ qemu-img create -f qcow2 "$vm_images_path/$vm_name.qcow2" "$disk_size"
+ start_vm "$vm_name"
+ exit 0
+ fi
+fi
+
+# If an existing VM is selected, ask if the user wants to modify its parameters
+read -p "Do you want to modify the VM parameters? (y/n): " modify_vm_params
+if [[ $modify_vm_params =~ ^[Yy]$ ]]; then
+ get_vm_parameters
+fi
+
+# Start the VM
+start_vm "$vm_name"
+
+echo "Script execution completed."
diff --git a/linux/home/.scripts/random_data.py b/linux/home/.scripts/random_data.py
new file mode 100755
index 0000000..071ab7c
--- /dev/null
+++ b/linux/home/.scripts/random_data.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python3
+
+import os
+import random
+import string
+import json
+import datetime
+import csv
+
+
+def generate_random_string(length, charset=string.ascii_letters):
+ """Generate a random string of given length and character set."""
+ return ''.join(random.choice(charset) for _ in range(length))
+
+
+def generate_random_number(min_value, max_value):
+ """Generate a random number within the specified range."""
+ return random.randint(min_value, max_value)
+
+
+def generate_random_date(start_date, end_date):
+ """Generate a random date within the specified range."""
+ time_between_dates = end_date - start_date
+ days_between_dates = time_between_dates.days
+ random_number_of_days = random.randrange(days_between_dates)
+ random_date = start_date + datetime.timedelta(days=random_number_of_days)
+ return random_date.strftime("%Y-%m-%d")
+
+
+def generate_sql_insert(table_name, columns, num_records):
+ """Generate SQL INSERT statements for populating a table."""
+ sql_statements = []
+ for _ in range(num_records):
+ values = [f"'{generate_random_string(int(input(f'Enter length for {column}: ')))}'" for column in columns]
+ sql = f"INSERT INTO {table_name} ({', '.join(columns)}) VALUES ({', '.join(values)});"
+ sql_statements.append(sql)
+ return sql_statements
+
+
+def generate_placeholder_data(num_records, data_format):
+ """Generate placeholder data based on user-defined format."""
+ placeholder_data = []
+ for _ in range(num_records):
+ record = {}
+ for field, field_data in data_format.items():
+ data_type = field_data['type']
+ if data_type == 'string':
+ length = field_data['length']
+ charset = field_data['charset']
+ record[field] = generate_random_string(length, charset)
+ elif data_type == 'number':
+ min_value = field_data['min']
+ max_value = field_data['max']
+ record[field] = generate_random_number(min_value, max_value)
+ elif data_type == 'date':
+ start_date = datetime.datetime.strptime(field_data['start_date'], "%Y-%m-%d")
+ end_date = datetime.datetime.strptime(field_data['end_date'], "%Y-%m-%d")
+ record[field] = generate_random_date(start_date, end_date)
+ elif data_type == 'boolean':
+ record[field] = random.choice([True, False])
+ placeholder_data.append(record)
+ return placeholder_data
+
+
+def get_data_format_from_user():
+ """Prompt the user for data format preferences."""
+ data_format = {}
+ while True:
+ field = input("Enter field name (or 'done' to finish): ").strip()
+ if field.lower() == 'done':
+ break
+
+ data_type = input(f"Enter data type for '{field}' (string/number/date/boolean): ").strip()
+ if data_type not in ['string', 'number', 'date', 'boolean']:
+ print("Invalid data type. Please enter 'string', 'number', 'date', or 'boolean'.")
+ continue
+
+ if data_type == 'string':
+ length = int(input(f"Enter length for '{field}' (integer): "))
+ charset = input(f"Enter character set for '{field}' (optional, press Enter for default): ").strip()
+ if not charset:
+ charset = string.ascii_letters
+ data_format[field] = {'type': 'string', 'length': length, 'charset': charset}
+ elif data_type == 'number':
+ min_value = int(input(f"Enter minimum value for '{field}' (integer): "))
+ max_value = int(input(f"Enter maximum value for '{field}' (integer): "))
+ data_format[field] = {'type': 'number', 'min': min_value, 'max': max_value}
+ elif data_type == 'date':
+ start_date = input(f"Enter start date for '{field}' (YYYY-MM-DD): ")
+ end_date = input(f"Enter end date for '{field}' (YYYY-MM-DD): ")
+ data_format[field] = {'type': 'date', 'start_date': start_date, 'end_date': end_date}
+ elif data_type == 'boolean':
+ data_format[field] = {'type': 'boolean'}
+
+ return data_format
+
+
+def get_file_type_from_user():
+ """Prompt the user for the desired file type (e.g., JSON, CSV, SQL, TXT, MD, HTML)."""
+ while True:
+ file_type = input("Enter the desired file type for saving the data (json/csv/sql/txt/md/html): ").strip().lower()
+ if file_type in ['json', 'csv', 'sql', 'txt', 'md', 'html']:
+ return file_type
+ else:
+ print("Invalid file type. Please enter 'json', 'csv', 'sql', 'txt', 'md', or 'html'.")
+
+
+def save_data_to_file(data, file_type):
+ """Save the generated data to a file of the specified type."""
+ if file_type == 'json':
+ with open('placeholder_data.json', 'w') as json_file:
+ json.dump(data, json_file, indent=4)
+ elif file_type == 'csv':
+ with open('placeholder_data.csv', 'w', newline='') as csv_file:
+ fieldnames = data[0].keys()
+ writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
+ writer.writeheader()
+ for record in data:
+ writer.writerow(record)
+ elif file_type == 'sql':
+ table_name = input("Enter the SQL table name: ")
+ columns = input("Enter column names separated by commas: ").split(',')
+ sql_statements = generate_sql_insert(table_name, columns, len(data))
+ with open('generated_data.sql', 'w') as sql_file:
+ sql_file.write('\n'.join(sql_statements))
+ elif file_type == 'txt':
+ with open('placeholder_data.txt', 'w') as txt_file:
+ for record in data:
+ txt_file.write(str(record) + '\n')
+ elif file_type == 'md':
+ with open('placeholder_data.md', 'w') as md_file:
+ for record in data:
+ md_file.write('- ' + ', '.join([f"{key}: {value}" for key, value in record.items()]) + '\n')
+ elif file_type == 'html':
+ with open('placeholder_data.html', 'w') as html_file:
+ html_file.write('<html>\n<head>\n<title>Placeholder Data</title>\n</head>\n<body>\n')
+ for record in data:
+ html_file.write('<ul>\n')
+ for key, value in record.items():
+ html_file.write(f'<li>{key}: {value}</li>\n')
+ html_file.write('</ul>\n')
+
+
+if __name__ == "__main__":
+ num_records = int(input("Enter the number of records to generate: "))
+ data_format = get_data_format_from_user()
+ file_type = get_file_type_from_user()
+
+ placeholder_data = generate_placeholder_data(num_records, data_format)
+
+ save_data_to_file(placeholder_data, file_type)
+
+ print(f"Data will be saved to: {os.path.abspath('generated_data.sql')}")
diff --git a/linux/home/.scripts/scratchpad b/linux/home/.scripts/scratchpad
new file mode 100755
index 0000000..8a1aea0
--- /dev/null
+++ b/linux/home/.scripts/scratchpad
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# Created By: srdusr
+# Created On: Tue 07 Mar 2023 15:06:47 PM CAT
+# Project: Agnostic scratchpad/dropdown terminal that works on most window managers
+
+# Dependencies: wmctrl, xprop, xdo, xdotool
+# NOTE: Ensure script is included in system's path and can therefore be invoked with the command 'scratchpad'.
+# Furthermore make sure the terminal is using x11 as a backend in wayland to allow this to work.
+# Example: wezterm.lua: enable_wayland = false,
+# kitty.conf: linux_display_server x11
+
+# Set the environment variables to x11 to allow working in Wayland
+export GDK_BACKEND=x11
+export QT_QPA_PLATFORM=xcb
+export WAYLAND_DISPLAY=""
+export WINIT_UNIX_BACKEND=x11
+
+# Supported terminals and dropdown class
+supported_terminals=("wezterm" "kitty" "alacritty")
+
+# Check if any supported terminal with scratchpad class is running
+for term in "${supported_terminals[@]}"; do
+ if pgrep -f "$term.*--class scratchpad" >/dev/null; then
+ my_term="$term"
+ break
+ fi
+done
+
+# If no supported terminal is running, start the first available one
+if [ "$my_term" = "" ]; then
+ for term in "${supported_terminals[@]}"; do
+ if command -v "$term" >/dev/null 2>&1; then
+ my_term="$term"
+ break
+ fi
+ done
+ if [ "$my_term" = "" ]; then
+ echo "No supported terminal found." && exit 1
+ fi
+
+ # Start terminal with scratchpad class
+ case "$my_term" in
+ "wezterm") wezterm start --class scratchpad -e tmux new-session -A -s tmux -e bash & ;;
+ "kitty") kitty --class scratchpad tmux new-session -A -s tmux -e bash & ;;
+ "alacritty") alacritty --class scratchpad -e tmux new-session -A -s tmux -e bash & ;;
+ esac
+fi
+
+# Get the window ID of the scratchpad terminal
+id="$(xdo id -N scratchpad)"
+
+# Toggle scratchpad terminal visibility
+if [ "$id" != "" ]; then
+ if xwininfo -id "$id" | grep "Map State: IsViewable" >/dev/null; then
+ # Scratchpad is visible, hide it
+ dimensions="$(xwininfo -id "$id" | awk '/Width:|Height:/ { printf("%s=%s;", tolower($1), $2) }')"
+ xdo hide "$id" 2>/dev/null
+ else
+ # Scratchpad is hidden, show it and restore dimensions
+ xdo show "$id"
+ xdotool windowsize "$id" "$(echo "$dimensions" | tr ';' ' ')" 2>/dev/null
+ fi
+fi
diff --git a/linux/home/.scripts/spec b/linux/home/.scripts/spec
new file mode 100755
index 0000000..19810fc
--- /dev/null
+++ b/linux/home/.scripts/spec
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+
+# Created By: srdusr
+# Created On: Wed 18 Oct 2023 20:19:03 CAT
+# Project: Create Spectrograms of audio files
+
+# Dependencies: sox
+
+# Define the timestamp function
+timestamp() {
+ date +%Y%m%d%H%M%S
+}
+
+spec() {
+
+ if [[ $# -eq 0 ]]; then
+ echo "No audio files provided."
+ return
+ fi
+
+ local outdir
+
+ if [[ -d "$HOME/pictures" ]]; then
+ outdir="$HOME/pictures/spectrograms"
+ elif [[ -d "$HOME/Pictures" ]]; then
+ outdir="$HOME/Pictures/Spectrograms"
+ elif [[ -d "$HOME/Images" ]]; then
+ outdir="$HOME/Images/Spectrograms"
+ else
+ outdir="./spectrograms" # Save to the current directory if none of the expected directories exist
+ fi
+
+ for file in "$@"; do
+ if [[ -f "$file" ]]; then
+ local filename
+ filename=$(basename "$file")
+ local filename_no_extension="${filename%.*}"
+ local target_dir="$outdir"
+ local outname="$target_dir/sox-spec-$(timestamp)-${filename_no_extension}.png"
+
+ if [[ ! -d "$target_dir" ]]; then
+ mkdir -p "$target_dir" # Create the directory if it doesn't exist
+ fi
+
+ sox "$file" -S -n spectrogram -o "$outname"
+
+ # Add the generated spectrogram file name to the array
+ spectrogram_files+=("$outname")
+ else
+ echo "File not found: $file"
+ fi
+ done
+
+ if [[ ${#} -gt 0 ]]; then
+ read -p "Do you want to open the spectrogram(s)? (y/n): " open_choice
+ case "$open_choice" in
+ [Yy])
+ for file in "${spectrogram_files[@]}"; do
+ xdg-open "$file" # Open the spectrogram images generated from the provided audio files
+ done
+ ;;
+ [Nn])
+ echo "Not opening the spectrogram(s)."
+ ;;
+ *)
+ echo "Invalid choice. Not opening the spectrogram(s)."
+ ;;
+ esac
+ fi
+}
+
+# Call the spec function with provided arguments
+spec "$@"
diff --git a/linux/home/.scripts/track-books.sh b/linux/home/.scripts/track-books.sh
new file mode 100755
index 0000000..f13add8
--- /dev/null
+++ b/linux/home/.scripts/track-books.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Created By: srdusr
+# Created On: Wed 25 Oct 2023 13:45:52 CAT
+# Project: Simple script to track most recent books opened, mainly for neovim usage.
+
+# Dependencies: inotify-tools
+
+books_directory="$HOME/documents/books"
+recent_books_file="$HOME/.config/nvim/tmp/recent_books.txt"
+
+inotifywait -m -e CREATE -e OPEN -r "$books_directory" |
+ while read -r path action file; do
+ if [[ $file == *.pdf || $file == *.epub ]]; then
+ echo "$path/$file" >>"$recent_books_file"
+ # Remove duplicates and overwrite the recent_books_file
+ sort -u -o "$recent_books_file" "$recent_books_file"
+ fi
+ done
diff --git a/linux/home/.scripts/win-nvim.bat b/linux/home/.scripts/win-nvim.bat
new file mode 100644
index 0000000..c99374d
--- /dev/null
+++ b/linux/home/.scripts/win-nvim.bat
@@ -0,0 +1,37 @@
+@echo off
+
+REM Install NeoVim with winget, if not already present on the system
+where nvim >nul 2>nul
+if %errorlevel% neq 0 (
+ winget install Neovim.Neovim -q
+)
+
+REM Clone my dotfiles repo
+set dotFilesRoot=%USERPROFILE%\dotfiles
+if not exist "%dotFilesRoot%\." (
+ git clone git@github.com:srdusr/dotfiles.git "%dotFilesRoot%"
+)
+
+REM Link NeoVim configuration
+set localConfiguration=%LOCALAPPDATA%\nvim
+set dotfilesConfiguration=%dotFilesRoot%\.config\nvim
+
+if not exist "%localConfiguration%\." (
+ mklink /D "%localConfiguration%" "%dotfilesConfiguration%"
+)
+
+REM Clone Packer.nvim, if not already present on the system
+set localPacker=%LOCALAPPDATA%\nvim-data\site\pack\packer\start\packer.nvim
+
+if not exist "%localPacker%\." (
+ git clone https://github.com/wbthomason/packer.nvim "%localPacker%"
+)
+
+REM Run the script by using this command in the same existing directory: win-nvim.bat
+
+@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://aka.ms/install-winget'))"
+iex ((new-object net.webclient).DownloadString('https://aka.ms/install-winget'))
+curl -o winget-cli.appxbundle https://aka.ms/winget-cli-appxbundle
+
+powershell Add-AppxPackage -Path "winget-cli.appxbundle"
+
diff --git a/linux/home/.scripts/win-nvim.ps1 b/linux/home/.scripts/win-nvim.ps1
new file mode 100644
index 0000000..ca67755
--- /dev/null
+++ b/linux/home/.scripts/win-nvim.ps1
@@ -0,0 +1,39 @@
+# Install NeoVim with winget, if not already present on the system
+if (!(Get-Command nvim -ErrorAction SilentlyContinue)) {
+ winget install Neovim.Neovim
+}
+
+# Clone my dotfiles repo
+$dotFilesRoot = Join-Path $HOME "dotfiles"
+
+if (!(Test-Path $dotFilesRoot -PathType Container)) {
+ git clone https://github.com/srdusr/dotfiles.git $dotFilesRoot
+}
+
+# Link NeoVim configuration
+$localConfiguration = Join-Path $env:LOCALAPPDATA "nvim"
+$dotfilesConfiguration = Join-Path $dotFilesRoot ".config" "nvim"
+
+if (!(Test-Path $localConfiguration -PathType Container)) {
+ Start-Process -FilePath "cmd.exe" -ArgumentList "/c mklink /D $localConfiguration $dotfilesConfiguration" -Verb runas
+}
+
+# Clone Packer.nvim, if not already present on the system
+$localPacker = Join-Path $env:LOCALAPPDATA "nvim-data" "site" "pack" "packer" "start" "packer.nvim"
+
+if (!(Test-Path $localPacker -PathType Container)) {
+ git clone https://github.com/wbthomason/packer.nvim $localPacker
+}
+
+# To allow script execution, run the following command in PowerShell as an administrator:
+# Set-ExecutionPolicy RemoteSigned
+# Then run the script by using this command in the same existing directory:
+# ./win-nvim.ps1
+#curl -o winget-cli.appxbundle https://aka.ms/winget-cli-appxbundle
+#powershell Add-AppxPackage -Path "winget-cli.appxbundle"
+#Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
+#use `-y` or consider: choco feature enable -n allowGlobalConfirmation
+#choco install git
+#- Refresh the environment
+#Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1
+#refreshenv
diff --git a/linux/home/.vim/autoload/statusline.vim b/linux/home/.vim/autoload/statusline.vim
new file mode 100644
index 0000000..5e5a671
--- /dev/null
+++ b/linux/home/.vim/autoload/statusline.vim
@@ -0,0 +1,227 @@
+"" This was made by Reddit user u/SamLovesNotion. Also with the help of - https://tdaly.co.uk/projects/vim-statusline-generator/ for learning the syntax. Sorry for English & grammar, this post was made in hurry.
+
+" Images - https://www.reddit.com/r/vim/comments/ld8h2j/i_made_a_status_line_from_scratch_no_plugins_used/
+" I have used Nerd icon fonts. Icons won't work without them. https://github.com/ryanoasis/nerd-fonts/
+
+" This statusline looks exactly like Vim Airline (even more customizable & powerful) & loads faster than Vim airline. Only take few ms to load.
+
+" STARTUP TIME - With Vim Airline - ~250ms. With this statusline - ~100ms. Without any statusline - ~98ms.
+
+" Add all of this at the end of your vimrc OR Create separate file like 'statusline.vim' & 'colorsgroup.vim' & source those files in your main vimrc.
+" e.g. source "~/.config/vim/statusline.vim"
+
+
+
+
+" statusline.vim
+
+" NOTE: This has been edited to fit my needs and is intended to be autoloaded in the autoload directory: "~/.vim/autoload/statusline.vim"
+
+if exists('g:loaded_statusline') | finish | endif
+let g:loaded_statusline = 1
+
+" Color highlighting groups
+" Add this AFTER `colorscheme` option in your vimrc. Otherwise your colorscheme will clear these highlightings.
+" OR use ColorScheme autocommand. VERY IMPORTANT.
+
+" Color pallet
+" Green - #2BBB4F (BG) - #080808 (FG)
+" Blue - #4799EB
+" Violet - #986FEC
+" Yellow - #D7A542
+" Orange - #EB754D
+" Grey1 - #202020
+" Grey - #303030
+
+" Define color variables
+let g:StslineColorGreen = '#2BBB4F'
+let g:StslineColorBlue = '#4799EB'
+let g:StslineColorViolet = '#986FEC'
+let g:StslineColorYellow = '#D7A542'
+let g:StslineColorOrange = '#EB754D'
+
+let g:StslineColorLight = '#C0C0C0'
+let g:StslineColorDark = '#080808'
+let g:StslineColorDark1 = '#181818'
+let g:StslineColorDark2 = '#202020'
+let g:StslineColorDark3 = '#303030'
+
+" Define colors
+let g:StslineBackColor = g:StslineColorDark2
+let g:StslineOnBackColor = g:StslineColorLight
+"let g:StslinePriColor = g:StslineColorGreen
+let g:StslineOnPriColor = g:StslineColorDark
+let g:StslineSecColor = g:StslineColorDark3
+let g:StslineOnSecColor = g:StslineColorLight
+
+" Create highlight groups
+execute 'highlight StslineSecColorFG guifg=' . g:StslineSecColor ' guibg=' . g:StslineBackColor
+execute 'highlight StslineSecColorBG guifg=' . g:StslineColorLight ' guibg=' . g:StslineSecColor
+execute 'highlight StslineBackColorBG guifg=' . g:StslineColorLight ' guibg=' . g:StslineBackColor
+execute 'highlight StslineBackColorFGSecColorBG guifg=' . g:StslineBackColor ' guibg=' . g:StslineSecColor
+execute 'highlight StslineSecColorFGBackColorBG guifg=' . g:StslineSecColor ' guibg=' . g:StslineBackColor
+execute 'highlight StslineModColorFG guifg=' . g:StslineColorYellow ' guibg=' . g:StslineBackColor
+
+" Statusline
+" Enable statusline
+set laststatus=2
+" Disable showmode - i.e. Don't show mode like --INSERT-- in current statusline.
+set noshowmode
+
+" Enable GUI colors for terminals (Some terminals may not support this, so you'll have to *manually* set color pallet for tui colors.)
+set termguicolors
+
+
+
+" Understand statusline elements
+
+" %{StslineMode()} = Output of a function
+" %#StslinePriColorBG# = Highlight group
+" %F, %c, etc. are variables which contain value like - current file path, current colums, etc.
+" %{&readonly?\"\ \":\"\"} = If file is readonly ? Then "Lock icon" Else : "Nothing"
+" %{get(b:,'coc_git_status',b:GitBranch)} = If b:coc_git_status efists, then it's value, else value of b:GitBranch
+" &filetype, things starting with & are also like variables with info.
+" \ - Is for escaping a space. \" is for escaping a double quote.
+" %{&fenc!='utf-8'?\"\ \":''} = If file encoding is NOT!= 'utf-8' ? THEN output a "Space" else : no character
+
+let space = ' '
+
+" Define active statusline
+function! autoload#statusline#ActivateStatusline() abort
+ call autoload#statusline#GetFileType()
+ setlocal statusline=%#StslinePriColorBG#\ \ %{autoload#statusline#StslineMode()}\ %#StslineSecColorBG#%{get(b:,'coc_git_status',b:GitBranch)}%{get(b:,'coc_git_blame','')}%#StslineBackColorFGPriColorBG#%#StslinePriColorFG#\ %{&readonly?\"\ \":\"\"}%F\ %#StslineModColorFG#%{&modified?\"\ \":\"\"}%=%#StslinePriColorFG#\ %{b:FiletypeIcon}%{&filetype}\ %#StslineSecColorFG#%#StslineSecColorBG#%{&fenc!='utf-8'?\"\ \":''}%{&fenc!='utf-8'?&fenc:''}%{&fenc!='utf-8'?\"\ \":''}%#StslinePriColorFGSecColorBG#%#StslinePriColorBG#\ %p\%%\ %#StslinePriColorBGBold#%l%#StslinePriColorBG#/%L\ :%c\ \ %#{space}
+endfunction
+
+" Define Inactive statusline
+function! autoload#statusline#DeactivateStatusline() abort
+ if !exists("b:GitBranch") || b:GitBranch == ''
+ setlocal statusline=%#StslineSecColorBG#\ INACTIVE\ %#StslineSecColorBG#%{get(b:,'coc_git_statusline',b:GitBranch)}%{get(b:,'coc_git_blame','')}%#StslineBackColorFGSecColorBG#%#StslineBackColorBG#\ %{&readonly?\"\ \":\"\"}%F\ %#StslineModColorFG#%{&modified?\"\ \":\"\"}%=%#StslineBackColorBG#\ %{b:FiletypeIcon}%{&filetype}\ %#StslineSecColorFGBackColorBG#%#StslineSecColorBG#\ %p\%%\ %l/%L\ :%c\
+ else
+ setlocal statusline=%#StslineSecColorBG#%{get(b:,'coc_git_statusline',b:GitBranch)}%{get(b:,'coc_git_blame','')}%#StslineBackColorFGSecColorBG#%#StslineBackColorBG#\ %{&readonly?\"\ \":\"\"}%F\ %#StslineModColorFG#%{&modified?\"\ \":\"\"}%=%#StslineBackColorBG#\ %{b:FiletypeIcon}%{&filetype}\ %#StslineSecColorFGBackColorBG#%#StslineSecColorBG#\ %p\%%\ %l/%L\ :%c\
+ endif
+endfunction
+
+" Get Statusline mode & also set primary color for that mode
+function! autoload#statusline#StslineMode() abort
+ let l:CurrentMode = mode()
+
+ if l:CurrentMode ==# 'n'
+ let g:StslinePriColor = g:StslineColorGreen
+ let b:CurrentMode = 'NORMAL '
+ elseif l:CurrentMode ==# 'i'
+ let g:StslinePriColor = g:StslineColorViolet
+ let b:CurrentMode = 'INSERT '
+ elseif l:CurrentMode ==# 'c'
+ let g:StslinePriColor = g:StslineColorYellow
+ let b:CurrentMode = 'COMMAND '
+ elseif l:CurrentMode ==# 'v'
+ let g:StslinePriColor = g:StslineColorBlue
+ let b:CurrentMode = 'VISUAL '
+ elseif l:CurrentMode ==# '\<C-v>'
+ let g:StslinePriColor = g:StslineColorBlue
+ let b:CurrentMode = 'V-BLOCK '
+ elseif l:CurrentMode ==# 'V'
+ let g:StslinePriColor = g:StslineColorBlue
+ let b:CurrentMode = 'V-LINE '
+ elseif l:CurrentMode ==# 'R'
+ let g:StslinePriColor = g:StslineColorViolet
+ let b:CurrentMode = 'REPLACE '
+ elseif l:CurrentMode ==# 's'
+ let g:StslinePriColor = g:StslineColorBlue
+ let b:CurrentMode = 'SELECT '
+ elseif l:CurrentMode ==# 't'
+ let g:StslinePriColor = g:StslineColorYellow
+ let b:CurrentMode = 'TERM '
+ elseif l:CurrentMode ==# '!'
+ let g:StslinePriColor = g:StslineColorYellow
+ let b:CurrentMode = 'SHELL '
+ endif
+
+ call autoload#statusline#UpdateStslineColors()
+
+ return b:CurrentMode
+endfunction
+
+" Update colors. Recreate highlight groups with new Primary color value.
+function! autoload#statusline#UpdateStslineColors() abort
+ execute 'highlight StslinePriColorBG guifg=' . g:StslineOnPriColor . ' guibg=' . g:StslinePriColor
+ execute 'highlight StslinePriColorBGBold guifg=' . g:StslineOnPriColor . ' guibg=' . g:StslinePriColor . ' gui=bold'
+ execute 'highlight StslinePriColorFG guifg=' . g:StslinePriColor . ' guibg=' . g:StslineBackColor
+ execute 'highlight StslinePriColorFGSecColorBG guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor
+ execute 'highlight StslineSecColorFGPriColorBG guifg=' . g:StslineSecColor . ' guibg=' . g:StslinePriColor
+
+ if !exists("b:GitBranch") || b:GitBranch == ''
+ execute 'highlight StslineBackColorFGPriColorBG guifg=' . g:StslineBackColor . ' guibg=' . g:StslinePriColor
+ endif
+endfunction
+
+" Get git branch name
+function! autoload#statusline#GetGitBranch() abort
+ let b:GitBranch = ""
+ try
+ let l:dir = expand('%:p:h')
+ let l:gitrevparse = system("git -C ".l:dir." rev-parse --abbrev-ref HEAD")
+ if !v:shell_error
+ let b:GitBranch = "  " . substitute(l:gitrevparse, '\n', '', 'g') . " "
+ execute 'highlight StslineBackColorFGPriColorBG guifg=' . g:StslineBackColor . ' guibg=' . g:StslineSecColor
+ endif
+ catch
+ endtry
+endfunction
+
+" Get filetype & custom icon. Put your most used file types first for optimized performance.
+function! autoload#statusline#GetFileType() abort
+ if &filetype ==# 'typescript'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'html'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'scss'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'css'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'javascript'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'javascriptreact'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'markdown'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'sh' || &filetype ==# 'zsh'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'vim'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# ''
+ let b:FiletypeIcon = ''
+ elseif &filetype ==# 'rust'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'ruby'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'cpp'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'c'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'go'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'lua'
+ let b:FiletypeIcon = ' '
+ elseif &filetype ==# 'haskel'
+ let b:FiletypeIcon = ' '
+ else
+ let b:FiletypeIcon = ' '
+ endif
+endfunction
+
+" Automatically update git branch name when entering a buffer
+augroup GetGitBranch
+ autocmd!
+ autocmd BufEnter * call autoload#statusline#GetGitBranch()
+augroup END
+
+" Set active / inactive statusline when entering or leaving a buffer
+augroup SetStsline
+ autocmd!
+ autocmd BufEnter,WinEnter * call autoload#statusline#ActivateStatusline()
+ autocmd BufLeave,WinLeave * call autoload#statusline#DeactivateStatusline()
+augroup END
+
+call autoload#statusline#ActivateStatusline()
+
diff --git a/linux/home/.vim/pack/plugins/start/vim-tmux-navigator b/linux/home/.vim/pack/plugins/start/vim-tmux-navigator
new file mode 160000
+Subproject 38b1d0402c4600543281dc85b3f51884205674b
diff --git a/linux/home/.vim/vimrc b/linux/home/.vim/vimrc
new file mode 100644
index 0000000..ce034e9
--- /dev/null
+++ b/linux/home/.vim/vimrc
@@ -0,0 +1,296 @@
+"===============================================================================
+" Mappings/Keybindings/Commands
+"===============================================================================
+
+let mapleader = ";" " map leader to Semi colon
+
+inoremap jk <Esc> " Use <jk> to escape
+
+" Easier split navigations, just ctrl-j instead of ctrl-w then j
+nnoremap <C-J> <C-W><C-J>
+nnoremap <C-K> <C-W><C-K>
+nnoremap <C-L> <C-W><C-L>
+nnoremap <C-H> <C-W><C-H>
+
+" Recent files (MRU)
+nnoremap <leader>m :browse old<cr>
+" Search files by name
+"nnoremap <leader>p :find **/**<left>
+" browse files from same dir as current file
+nnoremap <leader>e :e %:p:h<CR>
+
+" Combine buffers list with buffer name
+"nnoremap <Leader>b :buffers<CR>:buffer<Space>
+
+" Jump to a buffer
+nnoremap <leader>b :ls t<cr>:b
+
+" Map buffer next, prev and delete to <leader+(n/p/d)>
+map <leader>n :bn<cr>
+map <leader>p :bp<cr>
+map <leader>d :bd<cr>
+
+" tab navigation
+noremap <C-t>h :tabprevious<CR>
+noremap <C-t>l :tabnext<CR>
+noremap <C-t>k :tabfirst<CR>
+noremap <C-t>j :tablast<CR>
+noremap <C-t>n :tabnew<CR>
+noremap <C-t>e :tabedit<Space>
+noremap <C-t>c :tabclose<CR>
+noremap <C-t>m :tabm<Space>
+
+" Swap two pieces of text, use x to cut in visual mode, then use Ctrl-x in
+" visual mode to select text to swap with
+:vnoremap <C-X> <Esc>`.``gvP``P
+
+" To resize in different steps, you can create maps that will adjust the window
+" size differently. For example to increase the window size by a factor of 1.5
+" and decrease the window size by 0.67, you can map this:
+"nnoremap <silent> <Leader>+ :exe "resize " . (winheight(0) * 3/2)<CR>
+"nnoremap <silent> <Leader>- :exe "resize " . (winheight(0) * 2/3)<CR>
+nnoremap <Leader>+ :resize +5<CR>
+nnoremap <Leader>- :resize -5<CR>
+nnoremap <Leader>> :vertical resize +5<CR>
+nnoremap <Leader>< :vertical resize -5<CR>
+
+" Toggle set number
+"nnoremap <leader>$ :NumbersToggle<CR>
+"nnoremap <leader>% :NumbersOnOff<CR>
+
+" Copy and Paste with <C-c> and <C-v>
+"vmap <C-c> y:call system("xclip -i -selection clipboard", getreg("\""))<CR>:call system("xclip -i", getreg("\""))<CR>
+"nmap <C-v> :call setreg("\"",system("xclip -o -selection clipboard"))<CR>p
+nnoremap <expr> p (v:register == '"' && &clipboard =~ 'unnamed' ? '"*p' : '"' . v:register . 'p')
+
+" Use command :Vb for Visual Block or <C-q> since <C-v> is used for Copy
+command! Vb normal! <C-v>
+
+" Map <w!!> to save/edit a root permission/read-only file, only works in
+" traditional vim and not neovim
+cmap w!! %!sudo tee > /dev/null
+
+nnoremap <leader>x :silent !chmod +x %<CR>
+
+"nnoremap <[-p> m`o<ESC>p``
+" Paste on next line
+"nnoremap <]-p> m`O<ESC>p``
+
+"inoremap <C-CR> <C-R>"
+"set keywordprg=:help
+"runtime ftplugin/man.vim
+
+
+"===============================================================================
+" Settings
+"===============================================================================
+
+" Neovim requires xclip, check if normal vim has +clipboard by
+" <:echo has('clipboard')> from within Vim (if the output is 1, good to
+" go otherwise 0 then need a build that has it
+" Next two commands make vim use X11 clipboard
+set clipboard+=unnamedplus
+let g:clipbrdDefaultReg = '+'
+
+"let g:loaded_clipboard_provider = 1
+" <:e %:h/filename> will create a new file named filename in the same
+" directory as the currently open file, and write it.
+set autochdir " or use this to use <:e> to create a file in current directory
+set splitright " make vsplit put the new buffer on the right of the current buffer
+set splitbelow " make split put the new buffer below the current buffer
+" :Bclose script (delete a buffer without closing the window) sourced as a
+" plugin in ~/.config/nvim/plugin/bclose.vim | keymap: <leader>bd
+"let bclose_multiple = 1
+"set syntax
+" Compute syntax highlighting from beginning of file. (By default, vim only
+" looks 200 lines back, which can make it highlight code incorrectly in some
+" long files.)
+autocmd BufEnter * :syntax sync fromstart
+" Don't syntax highlight markdown because it's often wrong
+autocmd! FileType mkd setlocal syn=off
+set ttyfast
+set lazyredraw
+" Set lazyredraw to false
+"let &lazyredraw = 0
+set timeout timeoutlen=1000 ttimeoutlen=100 " fix slow O inserts
+set scrolloff=8 sidescrolloff=8
+set tabstop=4 softtabstop=4 shiftwidth=4 expandtab
+set autoindent
+set smartindent
+" Also load indent files, to automatically do language-dependent indenting.
+filetype plugin indent on
+set exrc
+set relativenumber
+set hidden
+set noerrorbells
+set nowrap
+set ignorecase
+set smartcase
+set noswapfile
+set nobackup
+set incsearch
+"set cursorline
+set showmatch
+set showcmd
+set incsearch
+set hlsearch
+set laststatus=2
+let g:python3_host_prog = '/usr/bin/python3'
+"let g:loaded_python3_provider = 1
+let g:sh_noisk=1
+set modeline
+set modelines=3 " modelines (comments that set vim options on a per-file basis)
+set foldmethod=manual
+set nofoldenable " turn folding off
+" Insert only one space when joining lines that contain sentence-terminating
+" punctuation like `.`.
+set nojoinspaces
+set autoread " if a file is changed outside of vim, automatically reload it without asking
+set diffopt=vertical " diffs are shown side-by-side not above/below
+set signcolumn=no " always show the sign column
+set textwidth=80
+set mouse=a
+
+" FILE BROWSING:
+let g:netrw_banner=0 " disable annoying banner
+let g:netrw_browse_split=4 " open in prior window
+let g:netrw_altv=1 " open splits to the right
+let g:netrw_liststyle=3 " tree view
+let g:netrw_fastbrowse = 0
+autocmd FileType netrw setl bufhidden=wipe
+
+" Faster vimgrep/grep via ripgrep
+if executable("rg")
+ set grepprg=rg\ --vimgrep\ --no-heading
+ set grepformat=%f:%l:%c:%m,%f:%l:%m
+endif
+
+
+"===============================================================================
+" Colorscheme
+"===============================================================================
+
+" enable syntax, plugins (for netrw) and indentation
+syntax enable
+
+"set shell=zsh
+set termguicolors
+set guicursor=
+let &t_SI = "\e[6 q"
+let &t_EI = "\e[2 q"
+
+"colorscheme desert
+"colorscheme city-lights
+set background=dark
+highlight Normal guibg=NONE ctermbg=NONE
+highlight EndOfBuffer ctermfg=NONE ctermbg=NONE
+
+
+"-------------------------------------------------------------------------------
+
+
+"===============================================================================
+" Functions/Scripts
+"===============================================================================
+
+" Enable mouse scrollback
+"---------------------------------------
+set mouse=a
+tnoremap <Esc> <C-\><C-n>
+tnoremap <c-b> <c-\><c-n>
+function! ClearTerminal()
+ set scrollback=1
+ let &g:scrollback=1
+ echo &scrollback
+ call feedkeys("\i")
+ call feedkeys("clear\<CR>")
+ call feedkeys("\<C-\>\<C-n>")
+ call feedkeys("\i")
+ sleep 100m
+ let &scrollback=s:scroll_value
+endfunction
+
+"-------------------------------------------------------------------------------
+
+" :Rename {newname}
+"---------------------------------------
+function! RenameFile()
+ let old_name = expand('%')
+ let new_name = input('New file name: ', expand('%'), 'file')
+ if new_name != '' && new_name != old_name
+ exec ':saveas ' . new_name
+ exec ':silent !rm ' . old_name
+ redraw!
+ endif
+endfunction
+map <leader>r :call RenameFile()<cr>
+
+"-------------------------------------------------------------------------------
+
+" Return to the same line when we reopen a file
+"---------------------------------------
+ augroup line_return
+ au!
+ au BufReadPost *
+ \ if line("'\"") > 0 && line("'\"") <= line("$") |
+ \ execute 'normal! g`"zvzz' |
+ \ endif
+ augroup END
+
+"-------------------------------------------------------------------------------
+"
+" Function to update tmux status and .vi-mode file
+"---------------------------------------
+function! UpdateTmuxStatus() abort
+ " Check if the current buffer has a man filetype
+ if &filetype ==# 'man'
+ return
+ endif
+
+ " Determine the mode name based on the mode value
+ let mode = mode()
+ let mode_name = ''
+ if mode ==# 'n'
+ let mode_name = '-- NORMAL --'
+ elseif mode ==# 'i' || mode ==# 'ic'
+ let mode_name = '-- INSERT --'
+ else
+ let mode_name = '-- NORMAL --'
+ endif
+
+ " Write the mode name to the file
+ call writefile([mode_name], expand('$HOME') . '/.vi-mode')
+
+endfunction
+
+" Function to refresh tmux status
+function! s:UpdateTmux() abort
+ call system('tmux refresh-client -S')
+endfunction
+
+" Set up autocommands for tmux status update
+if !empty($TMUX) && system('command -v tmux >/dev/null 2>&1') == 0
+augroup TmuxStatus
+ autocmd!
+ autocmd ModeChanged * call UpdateTmuxStatus() | call s:UpdateTmux()
+augroup END
+endif
+
+"-------------------------------------------------------------------------------
+
+
+"===============================================================================
+" Statusline Configuration
+"===============================================================================
+
+" Autoload statusline
+"---------------------------------------
+" Load statusline script
+if filereadable(expand("~/.vim/autoload/statusline.vim"))
+ source ~/.vim/autoload/statusline.vim
+endif
+
+" Call the statusline activation function
+call autoload#statusline#ActivateStatusline()
+
+"-------------------------------------------------------------------------------
diff --git a/linux/home/.vnc/config b/linux/home/.vnc/config
new file mode 100644
index 0000000..5c1462c
--- /dev/null
+++ b/linux/home/.vnc/config
@@ -0,0 +1,4 @@
+session=bspwm
+geometry=1920x1080
+localhost
+alwaysshared
diff --git a/linux/home/.vnc/xstartup b/linux/home/.vnc/xstartup
new file mode 100755
index 0000000..bbbc0db
--- /dev/null
+++ b/linux/home/.vnc/xstartup
@@ -0,0 +1,16 @@
+#!/data/data/com.termux/files/usr/bin/sh
+
+## file is executed during VNC server
+## startup.
+
+# Launch terminal emulator Aterm.
+# Requires package 'aterm'.
+
+unset SESSION_MANAGER
+unset DBUS_SESSION_BUS_ADDRESS
+
+export PULSE_SERVER=127.0.0.1 && pulseaudio --start --disable-shm=1 --exit-idle-time=-1
+
+# Launch Window Manager/Desktop Environment
+bspwm &
+
diff --git a/linux/home/README.md b/linux/home/README.md
new file mode 100644
index 0000000..750dc02
--- /dev/null
+++ b/linux/home/README.md
@@ -0,0 +1,698 @@
+# Dotfiles
+
+<pre>
+<p align="center">
+██████╗ ██████╗ ████████╗███████╗██╗██╗ ███████╗███████╗
+██╔══██╗██╔═══██╗╚══██╔══╝██╔════╝██║██║ ██╔════╝██╔════╝
+██║ ██║██║ ██║ ██║ █████╗ ██║██║ █████╗ ███████╗
+██║ ██║██║ ██║ ██║ ██╔══╝ ██║██║ ██╔══╝ ╚════██║
+██████╔╝╚██████╔╝ ██║ ██║ ██║███████╗███████╗███████║
+╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝
+</p>
+</pre>
+
+<h3 align="center">
+Welcome, and make yourself at <b><i>$HOME</i></b>
+</h3>
+
+![1](assets/desktop.jpg)
+
+> NOTE: Primarily for Linux but currently under work to make this as agnostic/cross-platform as possible
+
+---
+
+## Details
+
+- **OS:** [Gentoo Hardened](https://www.gentoo.org)
+- **WM/Compositor:** [hyprland](https://hyprland.org)
+- **Widgets:** [ags](https://aylur.github.io/ags)
+- **Shell:** [zsh](https://zsh.org)
+- **Terminal:** [wezterm](https://https://wezfurlong.org/wezterm)
+- **Multiplexer:** [tmux](https://github.com/tmux/tmux/wiki)
+- **Editor:** [neovim](https://neovim.io)
+ - **Config:** [nvim](https://github.com/srdusr/nvim)
+- **Fonts:**
+ - **Icons:** Whitesur
+ - **UI:** San Francisco
+ - **Terminal:** JetBrains Mono
+
+---
+
+### Installing onto a new system (bare git repository)
+
+1. Avoid weird behaviour/recursion issues when .cfg tries to track itself
+
+```bash
+$ echo ".cfg" >> .gitignore
+```
+
+2. Clone this repo
+
+```bash
+# bash
+$ git clone --bare https://github.com/srdusr/dotfiles.git $HOME/.cfg
+```
+
+```ps1
+# ps1 (Windows)
+# Clone the dotfiles repository into ~/.cfg (C:\Users\yourusername\.cfg)
+git clone --bare https://github.com/srdusr/dotfiles.git $env:USERPROFILE/.cfg
+git --git-dir=$HOME/.cfg --work-tree=$HOME checkout
+```
+
+3. Set up the alias 'config'
+
+```bash
+# bash
+$ alias config='git --git-dir=$HOME/.cfg --work-tree=$HOME'
+```
+
+```ps1
+# ps1 (Windows)
+echo '. "$HOME\Documents\PowerShell\Microsoft.PowerShell_profile.ps1"' > $PROFILE
+```
+
+4. Set local configuration into .cfg to ignore untracked files
+
+```bash
+$ config config --local status.showUntrackedFiles no
+```
+
+5. Checkout
+
+```bash
+$ config checkout
+```
+
+---
+
+### Installing onto a new Unix/Linux system
+
+```bash
+wget -q "https://github.com/srdusr/dotfiles/archive/main.tar.gz" -O "$HOME/Downloads/dotfiles.tar.gz"
+mkdir -p "$HOME/dotfiles-main"
+tar -xf "$HOME/Downloads/dotfiles.tar.gz" -C "$HOME/dotfiles-main" --strip-components=1
+mv -f "$HOME/dotfiles-main/"* "$HOME"
+rm -rf "$HOME/dotfiles-main"
+chmod +x "$HOME/install.sh"
+rm "$HOME/Downloads/dotfiles.tar.gz"
+$HOME/install.sh
+```
+
+---
+
+### Installing onto a new Windows system
+
+```ps1
+Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force; `
+$ProgressPreference = 'SilentlyContinue'; `
+Invoke-WebRequest "https://github.com/srdusr/dotfiles/archive/main.zip" `
+-OutFile "$HOME\Downloads\dotfiles.zip"; `
+Expand-Archive -Path "$HOME\Downloads\dotfiles.zip" -DestinationPath "$HOME" -Force; `
+Move-Item -Path "$HOME\dotfiles-main\*" -Destination "$HOME" -Force; `
+Remove-Item -Path "$HOME\dotfiles-main" -Recurse -Force; `
+. "$HOME\install.bat"
+
+
+Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
+irm 'https://raw.githubusercontent.com/srdusr/dotfiles/main/.config/powershell/bootstrap.ps1' | iex
+```
+
+---
+
+<details>
+ <summary><b>Notes</b> (If you have some time to read)</summary>
+
+### Fzf
+
+- Install Fzf
+
+```
+$ sudo git clone --depth 1 https://github.com/junegunn/fzf.git /usr/local/bin/fzf
+```
+
+- Put this into `.bashrc`/`.zshrc` or any similar shell configuration file to make it persistent across sessions
+
+```bash
+export PATH="$PATH:/usr/local/bin/fzf/bin"
+export FZF_BASE="/usr/local/bin/fzf"
+```
+
+- Also put this in to load fzf keybindings and completions
+
+```bash
+# bash
+source /usr/local/bin/fzf/shell/key-bindings.bash
+source /usr/local/bin/fzf/shell/completion.bash
+```
+
+```bash
+# zsh
+source /usr/local/bin/fzf/shell/key-bindings.zsh
+source /usr/local/bin/fzf/shell/completion.zsh
+```
+
+---
+
+### Zsh plugins
+
+- Install the plugins
+
+```bash
+# Clone zsh-you-should-use
+$ git clone https://github.com/MichaelAquilina/zsh-you-should-use.git ~/.config/zsh/plugins/zsh-you-should-use
+
+# Clone zsh-syntax-highlighting
+$ git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ~/.config/zsh/plugins/zsh-syntax-highlighting
+
+# Clone zsh-autosuggestions
+$ git clone https://github.com/zsh-users/zsh-autosuggestions.git ~/.config/zsh/plugins/zsh-autosuggestions
+```
+
+- Put this into `.zshrc` (preferably at the very end of the file) to allow it to source the plugins across sessions
+
+```bash
+# Suggest aliases for commands
+source ~/.config/zsh/plugins/zsh-you-should-use/you-should-use.plugin.zsh
+
+# Load zsh-syntax-highlighting
+source ~/.config/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+
+# Load fish like auto suggestions
+source ~/.config/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.plugin.zsh
+source ~/.config/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
+```
+
+---
+
+### Wezterm
+
+- Make sure Rust is installed first
+
+```bash
+$ curl https://sh.rustup.rs -sSf | sh -s
+```
+
+- Install and build Wezterm
+
+```bash
+$ git clone --depth=1 --branch=main --recursive https://github.com/wez/wezterm.git
+$ cd wezterm
+$ git submodule update --init --recursive
+$ ./get-deps
+$ cargo build --release
+$ cargo run --release --bin wezterm -- start
+$ sudo install wezterm wezterm-gui wezterm-mux-server strip-ansi-escapes /usr/local/bin
+
+```
+
+---
+
+### Neovim
+
+> Dependencies
+
+| Platform | ninja-build | ninja | base-devel | build-base | coreutils | gmake | cmake | make | gcc | g++ | gcc-c++ | unzip | wget | curl | gettext | gettext-tools | gettext-tiny-dev | automake | autoconf | libtool | libtool-bin | pkg-config | pkgconfig | pkgconf | tree-sitter | patch | doxygen | sha | git | Pack Manager |
+| ------------------ | ----------- | ----- | ---------- | ---------- | --------- | ----- | ----- | ---- | --- | --- | ------- | ----- | ---- | ---- | ------- | ------------- | ---------------- | -------- | -------- | ------- | ----------- | ---------- | --------- | ------- | ----------- | ----- | ------- | --- | --- | ------------ |
+| Ubuntu/Debian | ✓ | | | | | | ✓ | | | ✓ | | ✓ | | ✓ | ✓ | | | ✓ | ✓ | ✓ | ✓ | ✓ | | | | | ✓ | | | apt-get |
+| CentOS/RHEL/Fedora | ✓ | | | | | | ✓ | ✓ | ✓ | | ✓ | ✓ | | ✓ | ✓ | | | ✓ | ✓ | ✓ | | | ✓ | | | ✓ | | | | dnf |
+| openSUSE | | ✓ | | | | | ✓ | | | | ✓ | | | ✓ | | ✓ | | ✓ | ✓ | ✓ | | | | | | | | | | zypper |
+| Arch Linux | | ✓ | ✓ | | | | ✓ | | | | | ✓ | | ✓ | | | | | | | | | | | ✓ | | | | | pacman |
+| Alpine Linux | | | | | ✓ | | ✓ | | | | | ✓ | | ✓ | | | ✓ | ✓ | ✓ | ✓ | | | | ✓ | | | | | | apk |
+| Void Linux | | | ✓ | ✓ | | | ✓ | | | | | | | ✓ | | | | | | | | | | | | | | | ✓ | xbps |
+| FreeBSD | | | | | | ✓ | ✓ | | | | | ✓ | ✓ | ✓ | ✓ | | | | | ✓ | | | | ✓ | | | | ✓ | | pkg |
+| OpenBSD | | | | | | ✓ | ✓ | | | | | ✓ | | ✓ | | ✓ | | ✓ | ✓ | ✓ | | | | | | | | | | pkg_add |
+| macOS/Homebrew | | ✓ | | | | | ✓ | | | | | | | ✓ | ✓ | | | ✓ | | ✓ | | ✓ | | | | | | | | brew |
+| macOS/MacPorts | | ✓ | | | | | ✓ | | | | | | | | ✓ | | | | | | | | | | | | | | | port |
+
+- Install (default is nightly)
+ ```bash
+ $ git clone https://github.com/neovim/neovim.git
+ $ cd neovim
+ ```
+ - Optional install stable version
+ ```bash
+ $ git checkout stable
+ ```
+ - or specific version by tag
+ ```bash
+ $ git checkout release-0.7
+ ```
+- Build nvim
+ ```bash
+ $ make CMAKE_BUILD_TYPE=Release
+ $ sudo make install
+ ```
+- Install Packer (package manager)
+ ```bash
+ $ git clone --depth 1 https://github.com/wbthomason/packer.nvim\
+ ~/.local/share/nvim/site/pack/packer/start/packer.nvim
+ ```
+- Post-installation:
+ - Install plugins
+ ```vi
+ :PackerSync
+ ```
+ - or save/write on .config/nvim/lua/user/pack.lua to automatically install plugins
+ ```vi
+ :w
+ ```
+ - Install language servers
+ ```vi
+ :Mason
+ ```
+ - Exit out of Mason with `q`, configured language servers should then install automatically
+ > NOTE: If any errors occur, npm needs to be installed and executable, complete **_Development Environment/Languages/Javascript_** section to install nvm/npm
+ - Reload nvim/config with `<leader><space>` where `<leader>` is `;`
+- Uninstall:
+ ```bash
+ $ sudo rm /usr/local/bin/nvim
+ $ sudo rm -r /usr/local/share/nvim/
+ ```
+
+---
+
+### Gnome Custom Settings
+
+- Run gnome custom settings script, located at `~/.scripts`:
+
+```bash
+$ gsettings.sh
+```
+
+---
+
+## Development Environment
+
+### Languages
+
+#### Python
+
+```bash
+
+```
+
+---
+
+#### Java
+
+Recommended to choose Openjdk 8 or 10 otherwise get an error when using Android tools
+
+```bash
+
+```
+
+---
+
+#### Rust
+
+- Download and run rustup script
+
+```bash
+$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+```
+
+---
+
+#### Go
+
+```bash
+
+```
+
+---
+
+#### Lua
+
+- Download LuaRocks
+
+```bash
+$ git clone git://github.com/luarocks/luarocks.git
+```
+
+- Install and specify the installation directory to build and configure LuaRocks
+
+```bash
+$ ./configure --prefix=/usr/local/luarocks
+$ make build
+$ sudo make install
+```
+
+- Add LuaRocks to system's environment variables by running the following command or add it `.bashrc`/`.zshrc` or any similar shell configuration file to make it persistent across sessions
+
+```bash
+export PATH=$PATH:/usr/local/luarocks/bin
+```
+
+- Install Lua
+
+```bash
+$ luarocks install lua
+```
+
+---
+
+#### PHP
+
+- Install PHP
+- Install Web server (Apache or Nginx)
+- Install PHP extensions
+
+```
+php-apache php-cgi php-fpm php-gd php-embed php-intl php-redis php-snmp
+mysql-server php8.1-mysql
+phpmyadmin
+```
+
+- Install composer (Dependency Manager for PHP)
+
+```bash
+$ curl -sS https://getcomposer.org/installer | php
+```
+
+- Install laravel
+
+```bash
+$ composer global require laravel/installer
+```
+
+- Edit PHP config
+
+```bash
+$ sudoedit /etc/php/php.ini
+```
+
+- Enable PHP extensions, make sure these lines are uncommented (remove the `;` from each line)
+
+```
+extention=bcmath
+extention=zip
+extension=pdo_mysql
+extension=mysqli
+extension=iconv
+
+extension=gd
+extension=imagick
+extension=pdo_pgsql
+extension=pgsql
+```
+
+- Recommended to set correct timezone
+
+```
+date.timezone = <Continent/City>
+```
+
+- Display errors to debug PHP code
+
+```
+display_errors = On
+```
+
+- Allow paths to be accessed by PHP
+
+```
+open_basedir = /srv/http/:/var/www/:/home/:/tmp/:/var/tmp/:/var/cache/:/usr/share/pear/:/usr/share/webapps/:/etc/webapps/
+```
+
+---
+
+#### Dart
+
+- Install dart or skip and install flutter (recommended) that includes dart
+
+```bash
+$ curl -O "https://storage.googleapis.com/dart-archive/channels/be/raw/latest/sdk/dartsdk-linux-x64-release.zip"
+$ unzip dartsdk-linux-x64-release.zip
+$ sudo mv dart-sdk /usr/lib/dart
+```
+
+NOTE: If Dart SDK is downloaded separately, make sure that the Flutter version of dart is first in path, as the two versions might not be compatible. Use this command `which flutter dart` to see if flutter and dart originate from the same bin directory and are therefore compatible.
+
+- Install flutter
+
+```bash
+$ git clone https://github.com/flutter/flutter.git -b stable
+```
+
+- Move flutter to the `/opt` directory
+
+```bash
+$ sudo mv flutter /opt/
+```
+
+- Export Flutter over Dart by putting this into `.bashrc`/`.zshrc` or any similar shell configuration file to make it persistent across sessions
+
+```bash
+# Flutter/dart path
+export PATH="/opt/flutter:/usr/lib/dart/bin:$PATH"
+# Flutter Web Support
+export PATH=$PATH:/opt/google/chrome
+```
+
+- Set permissions since only Root has access
+
+```bash
+$ sudo groupadd flutterusers
+$ sudo gpasswd -a $USER flutterusers
+$ sudo chown -R :flutterusers /opt/flutter
+$ sudo chmod -R g+w /opt/flutter/
+```
+
+- If still getting any permission denied errors then do this
+
+```bash
+$ sudo chown -R $USER /opt/flutter
+```
+
+- Continue to step **_Development Tools/Android Studio_** section to complete setup
+
+---
+
+#### Javascript
+
+- nvm install/update script
+
+```bash
+$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
+```
+
+- Put these lines into `.bashrc`/`.zshrc` or any similar shell configuration file to make it persistent across sessions
+
+```bash
+export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
+[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
+```
+
+- Install node
+
+```bash
+$ nvm install node
+```
+
+- Install the latest version in order to make npm executable
+
+```bash
+$ nvm install --lts
+```
+
+---
+
+### Development Tools
+
+#### MySQL
+
+- Install MySQL
+- Ensure the MySQL service starts when reboot or startup machine.
+
+```bash
+$ sudo systemctl start mysqld
+```
+
+- Setup MySQL for use
+
+```bash
+$ sudo mysql_secure_installation
+```
+
+- To check its installed and working just open up mysql command prompt with
+
+```
+$ sudo mysql
+```
+
+---
+
+#### Android Studio/SDK
+
+> NOTE: Android Studio is an Integrated Development Environment (IDE) that provides a comprehensive set of tools for Android app development. It includes the Android SDK (Software Development Kit), which consists of various libraries, tools, and system images necessary for developing Android applications.
+
+> The Android SDK can be installed separately without Android Studio, allowing you to use alternative text editors or IDEs for development. However, Android Studio provides a more streamlined and feature-rich development experience.
+
+> Make sure to properly set the Java environment (either 8 or 10, eg., java-8-openjdk) otherwise android-studio will not start.
+
+> If Android Studio shows up as a blank window try exporting `_JAVA_AWT_WM_NONREPARENTING=1`.
+
+- Install android studio
+ - Directly from the official website
+ ```bash
+ $ curl -L -o android-studio.tar.gz "$(curl -s "https://developer.android.com/studio#downloads" | grep -oP 'https://redirector\.gvt1\.com/[^"]+' | head -n 1)"
+ $ tar -xvzf android-studio.tar.gz
+ $ sudo mv android-studio /opt/
+ $ cd /opt/android-studio/bin script # Configure Android Studio by running this script
+ $ ./studio.sh
+ ```
+ - Or optionally install jetbrains-toolbox that includes android-studio amongst many other applications/tools from jetbrains
+ ```bash
+ $ latest_url=$(curl -sL "https://data.services.jetbrains.com/products/releases?code=TBA" | grep -oP 'https://download.jetbrains.com/toolbox/jetbrains-toolbox-\d+\.\d+\.\d+\.\d+\.tar\.gz' | head -n 1) && curl -L -o jetbrains-toolbox.tar.gz "$latest_url"
+ $ tar -xvzf jetbrains-toolbox.tar.gz
+ $ sudo mv jetbrains-toolbox /opt/jetbrains
+ ```
+- Complete the Android Studio Setup Wizard
+ - Click `Next` on the Welcome Window
+ - Click `Custom` and `Next`
+ - Make sure `/opt/android-sdk` directory exists otherwise create it by typing in the following command in a terminal
+ ```bash
+ $ sudo mkdir /opt/android-sdk
+ ```
+ - Click on the folder icon next to the SDK path field.
+ - In the file picker dialog, navigate to the /opt directory and select the android-sdk directory.
+ - Proceed with the setup wizard, following the remaining instructions to complete the installation.
+- If already installed and prefer not to have a `$HOME/Android` directory but rather use `/opt/android-sdk`
+
+ - Launch Android Studio.
+ - Go to "File" > "Settings" (on Windows/Linux) or "Android Studio" > "Preferences" (on macOS) to open the settings.
+ - In the settings, navigate to "Appearance & Behavior" > "System Settings" > "Android SDK".
+ - In the "Android SDK Location" field, update the path to `/opt/android-sdk`.
+ - Click "Apply" or "OK" to save the settings.
+
+- Put these lines into `.bashrc`/`.zshrc` or any similar shell configuration file to make it persistent across sessions
+
+```
+# Android Home
+export ANDROID_HOME=/opt/android-sdk
+export PATH=$ANDROID_HOME/tools:$PATH
+export PATH=$ANDROID_HOME/tools/bin:$PATH
+export PATH=$ANDROID_HOME/platform-tools:$PATH
+export PATH=$ANDROID_HOME/cmdline-tools/latest/bin:$PATH
+# Android emulator PATH
+export PATH=$ANDROID_HOME/emulator:$PATH
+# Android SDK ROOT PATH
+export ANDROID_SDK_ROOT=/opt/android-sdk
+export PATH=$ANDROID_SDK_ROOT:$PATH
+# Alias for android-studio
+alias android-studio='/opt/android-studio/bin/studio.sh'
+```
+
+- Android SDK and tools installation
+ > NOTE: Can be installed either through Android Studio or separately.
+ - Android Studio Installed: Launch Android Studio and go to the "SDK Manager" (usually found under "Configure" or "Preferences" menu). From the SDK Manager, select the desired SDK components (platforms, build tools, system images, etc.) and click "Apply" to install them.
+ - To install Android SDK separately (without Android Studio):
+ ```bash
+ $ curl -L -o commandlinetools.zip "$(curl -s "https://developer.android.com/studio#downloads" | grep -oP 'https://dl.google.com/android/repository/commandlinetools-linux-\d+_latest\.zip' | head -n 1)"
+ $ unzip commandlinetools.zip -d android-sdk
+ $ mkdir android-sdk/cmdline-tools/latest
+ $ sudo mv android-sdk /opt/
+ or
+ $ sudo mv android-sdk/cmdline-tools /opt/android-sdk/
+ ```
+- If Android SDK was installed separately then configure the user's permissions since android-sdk is installed in /opt/android-sdk directory
+
+```bash
+$ sudo groupadd android-sdk
+$ sudo gpasswd -a $USER android-sdk
+$ sudo setfacl -R -m g:android-sdk:rwx /opt/android-sdk
+$ sudo setfacl -d -m g:android-sdk:rwX /opt/android-sdk
+```
+
+- If Android SDK has been installed separately then install platform-tools and build-tools like this:
+ - First list `sdkmanager`'s available/installed packages
+ ```bash
+ $ sdkmanager --list
+ ```
+ - Install platform-tools and build-tools
+ > NOTE: Replace <version> with the specific version number for platforms and build tools to install (e.g., "platforms;android-`33`" "build-tools;`34.0.0`").
+ ```bash
+ $ sdkmanager "platform-tools" "platforms;android-<version>" "build-tools;<version>"
+ ```
+- Android emulator
+ - List of available android system images.
+ ```bash
+ $ sdkmanager --list
+ ```
+ - Install an android image of your choice. For example.
+ ```bash
+ $ sdkmanager --install "system-images;android-29;default;x86"
+ ```
+ - Then create an android emulator using Android Virtual Devices Manager
+ ```bash
+ $ avdmanager create avd -n <name> -k "system-images;android-29;default;x86"
+ ```
+- Continuing from **_Dart(flutter)_** section
+ - Update Flutter Config SDK PATH for custom SDK PATH
+ ```bash
+ $ flutter config --android-sdk /opt/android-sdk
+ ```
+ - Accept all andfoid licenses with this command
+ ```
+ $ flutter doctor --android-licenses
+ ```
+ - If licenses are still not accepted even after running `flutter doctor --android-licenses` try these commands and then run `flutter doctor --android-licenses again`
+ ```
+ $ sudo chown -R $(whoami) $ANDROID_SDK_ROOT
+ ```
+ - Run this
+ ```
+ $ flutter doctor
+ ```
+- Update emulator binaries
+
+```bash
+$ sdkmanager --sdk_root=${ANDROID_HOME} tools
+```
+
+- Accept emulator licenses
+ > NOTE: Required to accept the necessary license for each package installed.
+
+```bash
+$ sdkmanager --licenses
+```
+
+---
+
+## Commands
+
+---
+
+#### Windows
+
+- Install nvim natively to Windows
+ - First allow script execution, run the following command in PowerShell as an administrator:
+ ```dos
+ Set-ExecutionPolicy RemoteSigned
+ # or
+ Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
+ ```
+ - Then run the script by using this command in the same existing directory:
+ ```dos
+ ./win-nvim.ps1
+ ```
+ ```dos
+ curl -o winget-cli.appxbundle https://aka.ms/winget-cli-appxbundle
+ powershell Add-AppxPackage -Path "winget-cli.appxbundle"
+ Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
+ ```
+ - Use `-y` or consider: choco feature enable -n allowGlobalConfirmation
+ ```dos
+ choco install git
+ ```
+ - Refresh the environment
+ ```dos
+ Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1
+ refreshenv
+ ```
+ ```dos
+ git config --global user.name "Firstname Lastname"
+ git config --global user.email "your_email@example.com"
+ ```
+ </details>
diff --git a/linux/home/assets/desktop.jpg b/linux/home/assets/desktop.jpg
new file mode 100644
index 0000000..e85b2ff
--- /dev/null
+++ b/linux/home/assets/desktop.jpg
Binary files differ
diff --git a/linux/home/assets/old_desktop.jpg b/linux/home/assets/old_desktop.jpg
new file mode 100644
index 0000000..3ecb22e
--- /dev/null
+++ b/linux/home/assets/old_desktop.jpg
Binary files differ
diff --git a/linux/home/extras/etc/X11/xorg.conf.d/70-synaptics.conf b/linux/home/extras/etc/X11/xorg.conf.d/70-synaptics.conf
new file mode 100644
index 0000000..e073d94
--- /dev/null
+++ b/linux/home/extras/etc/X11/xorg.conf.d/70-synaptics.conf
@@ -0,0 +1,15 @@
+Section "InputClass"
+ Identifier "touchpad"
+ Driver "synaptics"
+ MatchIsTouchpad "on"
+ Option "FingerHigh" "5"
+ Option "FingerLow" "5"
+ Option "TapButton1" "1"
+ Option "TapButton2" "3"
+ Option "TapButton3" "2"
+ Option "HorizTwoFingerScroll" "on"
+ Option "VertTwoFingerScroll" "on"
+ Option "PalmDetect" "1"
+ Option "PalmMinWidth" "8"
+ Option "PalmMinZ" "100"
+EndSection
diff --git a/linux/home/extras/etc/issue b/linux/home/extras/etc/issue
new file mode 100644
index 0000000..c165efa
--- /dev/null
+++ b/linux/home/extras/etc/issue
@@ -0,0 +1,14 @@
+,---,---,---,---,---,---,---,---,---,---,---,---,---,-------,
+| ~ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | <- |
+|---'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-----|
+| ->| | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \\ | TTY: \l
+|-----',--',--',--',--',--',--',--',--',--',--',--',--'-----| Host: \n
+| Caps | A | S | D | F | G | H | J | K | L | ; | ' | Enter | Arch: \m
+|------'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'-,-'--------| Kernel: \r
+| shift | Z | X | C | V | B | N | M | , | . | / | shift | Build: \v
+|---------'---'---'---'---'---'---'---'---'---'---'---------|
+| ctrl | + | alt | | alt | Fn | ctrl |
+'------'---'-----'------------------------'-----'----'------'
+
+
+
diff --git a/linux/home/extras/etc/lightdm/lightdm-gtk-greeter.conf b/linux/home/extras/etc/lightdm/lightdm-gtk-greeter.conf
new file mode 100644
index 0000000..9e50dd3
--- /dev/null
+++ b/linux/home/extras/etc/lightdm/lightdm-gtk-greeter.conf
@@ -0,0 +1,17 @@
+[greeter]
+theme-name = WhiteSur-Dark
+icon-theme-name = WhiteSur-Dark
+font-name = SF Pro Regular 9
+cursor-theme-name=WhiteSur
+cursor-theme-size=<%= @cursor_size %>
+xft-dpi=<%= @dpi %>
+xft-antialias=true
+xft-hintstyle=hintslight
+xft-rgba=rgb
+indicators=~clock;~spacer;~layout;~language;~session;~ally;~power
+show-clock=true
+#clock-format=
+#default-user-image = /home/srdusr/.face
+hide-user-image = false
+user-background = true
+
diff --git a/linux/home/extras/etc/lightdm/lightdm-webkit2-greeter.conf b/linux/home/extras/etc/lightdm/lightdm-webkit2-greeter.conf
new file mode 100644
index 0000000..57785a8
--- /dev/null
+++ b/linux/home/extras/etc/lightdm/lightdm-webkit2-greeter.conf
@@ -0,0 +1,49 @@
+#
+# [greeter]
+# debug_mode = Greeter theme debug mode.
+# detect_theme_errors = Provide an option to load a fallback theme when theme errors are detected.
+# screensaver_timeout = Blank the screen after this many seconds of inactivity.
+# secure_mode = Don't allow themes to make remote http requests.
+# time_format = A moment.js format string so the greeter can generate localized time for display.
+# time_language = Language to use when displaying the time or "auto" to use the system's language.
+# webkit_theme = Webkit theme to use.
+#
+# NOTE: See moment.js documentation for format string options: http://momentjs.com/docs/#/displaying/format/
+#
+
+[greeter]
+debug_mode = true
+detect_theme_errors = true
+screensaver_timeout = 300
+secure_mode = true
+time_format = LT
+time_language = auto
+webkit_theme = glorious
+#theme-name = WhiteSur-Dark
+#icon-theme-name = WhiteSur-Dark
+#font-name = SF Pro Regular 9
+#cursor-theme-name=WhiteSur
+#cursor-theme-size=<%= @cursor_size %>
+#xft-dpi=<%= @dpi %>
+#xft-antialias=true
+#xft-hintstyle=hintslight
+#xft-rgba=rgb
+#indicators=~clock;~spacer;~layout;~language;~session;~ally;~power
+#show-clock=true
+#clock-format=
+#default-user-image = /home/srdusr/.face
+hide-user-image = false
+user-background = true
+#
+# [branding]
+# background_images = Path to directory that contains background images for use by themes.
+# logo = Path to logo image for use by greeter themes.
+# user_image = Default user image/avatar. This is used by themes for users that have no .face image.
+#
+# NOTE: Paths must be accessible to the lightdm system user account (so they cannot be anywhere in /home)
+#
+
+#[branding]
+#background_images = /usr/share/backgrounds
+#logo = /usr/share/pixmaps/archlinux-logo.svg
+#user_image = /usr/share/pixmaps/archlinux-user.svg
diff --git a/linux/home/extras/etc/lightdm/lightdm.conf b/linux/home/extras/etc/lightdm/lightdm.conf
new file mode 100644
index 0000000..f751866
--- /dev/null
+++ b/linux/home/extras/etc/lightdm/lightdm.conf
@@ -0,0 +1,161 @@
+#
+# General configuration
+#
+# start-default-seat = True to always start one seat if none are defined in the configuration
+# greeter-user = User to run greeter as
+# minimum-display-number = Minimum display number to use for X servers
+# minimum-vt = First VT to run displays on
+# lock-memory = True to prevent memory from being paged to disk
+# user-authority-in-system-dir = True if session authority should be in the system location
+# guest-account-script = Script to be run to setup guest account
+# logind-check-graphical = True to on start seats that are marked as graphical by logind
+# log-directory = Directory to log information to
+# run-directory = Directory to put running state in
+# cache-directory = Directory to cache to
+# sessions-directory = Directory to find sessions
+# remote-sessions-directory = Directory to find remote sessions
+# greeters-directory = Directory to find greeters
+# backup-logs = True to move add a .old suffix to old log files when opening new ones
+# dbus-service = True if LightDM provides a D-Bus service to control it
+#
+[LightDM]
+#start-default-seat=true
+#greeter-user=lightdm
+#minimum-display-number=0
+#minimum-vt=7 # Setting this to a value < 7 implies security issues, see FS#46799
+#lock-memory=true
+#user-authority-in-system-dir=false
+#guest-account-script=guest-account
+#logind-check-graphical=false
+#log-directory=/var/log/lightdm
+run-directory=/run/lightdm
+#cache-directory=/var/cache/lightdm
+#sessions-directory=/usr/share/lightdm/sessions:/usr/share/xsessions:/usr/share/wayland-sessions
+#remote-sessions-directory=/usr/share/lightdm/remote-sessions
+#greeters-directory=$XDG_DATA_DIRS/lightdm/greeters:$XDG_DATA_DIRS/xgreeters
+#backup-logs=true
+#dbus-service=true
+
+#
+# Seat configuration
+#
+# Seat configuration is matched against the seat name glob in the section, for example:
+# [Seat:*] matches all seats and is applied first.
+# [Seat:seat0] matches the seat named "seat0".
+# [Seat:seat-thin-client*] matches all seats that have names that start with "seat-thin-client".
+#
+# type = Seat type (local, xremote)
+# pam-service = PAM service to use for login
+# pam-autologin-service = PAM service to use for autologin
+# pam-greeter-service = PAM service to use for greeters
+# xserver-command = X server command to run (can also contain arguments e.g. X -special-option)
+# xmir-command = Xmir server command to run (can also contain arguments e.g. Xmir -special-option)
+# xserver-config = Config file to pass to X server
+# xserver-layout = Layout to pass to X server
+# xserver-allow-tcp = True if TCP/IP connections are allowed to this X server
+# xserver-share = True if the X server is shared for both greeter and session
+# xserver-hostname = Hostname of X server (only for type=xremote)
+# xserver-display-number = Display number of X server (only for type=xremote)
+# xdmcp-manager = XDMCP manager to connect to (implies xserver-allow-tcp=true)
+# xdmcp-port = XDMCP UDP/IP port to communicate on
+# xdmcp-key = Authentication key to use for XDM-AUTHENTICATION-1 (stored in keys.conf)
+# greeter-session = Session to load for greeter
+# greeter-hide-users = True to hide the user list
+# greeter-allow-guest = True if the greeter should show a guest login option
+# greeter-show-manual-login = True if the greeter should offer a manual login option
+# greeter-show-remote-login = True if the greeter should offer a remote login option
+# user-session = Session to load for users
+# allow-user-switching = True if allowed to switch users
+# allow-guest = True if guest login is allowed
+# guest-session = Session to load for guests (overrides user-session)
+# session-wrapper = Wrapper script to run session with
+# greeter-wrapper = Wrapper script to run greeter with
+# guest-wrapper = Wrapper script to run guest sessions with
+# display-stopped-script = Script to run after stopping the display server (runs as root)
+# session-setup-script = Script to run when starting a user session (runs as root)
+# session-cleanup-script = Script to run when quitting a user session (runs as root)
+# autologin-guest = True to log in as guest by default
+# autologin-user = User to log in with by default (overrides autologin-guest)
+# autologin-user-timeout = Number of seconds to wait before loading default user
+# autologin-session = Session to load for automatic login (overrides user-session)
+# autologin-in-background = True if autologin session should not be immediately activated
+# exit-on-failure = True if the daemon should exit if this seat fails
+#
+[Seat:*]
+#type=local
+#pam-service=lightdm
+#pam-autologin-service=lightdm-autologin
+#pam-greeter-service=lightdm-greeter
+#xserver-command=X
+#xmir-command=Xmir
+#xserver-config=
+#xserver-layout=
+#xserver-allow-tcp=false
+#xserver-share=true
+#xserver-hostname=
+#xserver-display-number=
+#xdmcp-manager=
+#xdmcp-port=177
+#xdmcp-key=
+greeter-session=lightdm-webkit2-greeter
+greeter-hide-users=false
+#greeter-allow-guest=true
+#greeter-show-manual-login=false
+#greeter-show-remote-login=true
+#user-session=bspwm.desktop
+#allow-user-switching=true
+#allow-guest=true
+#guest-session=
+session-wrapper=/etc/lightdm/Xsession
+#greeter-wrapper=
+#guest-wrapper=
+#display-stopped-script=
+#session-setup-script=
+#session-cleanup-script=
+#autologin-guest=false
+#autologin-user=
+#autologin-user-timeout=0
+#autologin-in-background=false
+#autologin-session=
+#exit-on-failure=false
+
+#
+# XDMCP Server configuration
+#
+# enabled = True if XDMCP connections should be allowed
+# port = UDP/IP port to listen for connections on
+# listen-address = Host/address to listen for XDMCP connections (use all addresses if not present)
+# key = Authentication key to use for XDM-AUTHENTICATION-1 or blank to not use authentication (stored in keys.conf)
+# hostname = Hostname to report to XDMCP clients (defaults to system hostname if unset)
+#
+# The authentication key is a 56 bit DES key specified in hex as 0xnnnnnnnnnnnnnn. Alternatively
+# it can be a word and the first 7 characters are used as the key.
+#
+[XDMCPServer]
+#enabled=false
+#port=177
+#listen-address=
+#key=
+#hostname=
+
+#
+# VNC Server configuration
+#
+# enabled = True if VNC connections should be allowed
+# command = Command to run Xvnc server with
+# port = TCP/IP port to listen for connections on
+# listen-address = Host/address to listen for VNC connections (use all addresses if not present)
+# width = Width of display to use
+# height = Height of display to use
+# depth = Color depth of display to use
+#
+[VNCServer]
+#enabled=false
+#command=Xvnc
+#port=5900
+#listen-address=
+#width=1024
+#height=768
+#depth=8
+[Seat:seat*]
+greeter-setup-script=xhost +LOCAL:
diff --git a/linux/home/extras/etc/udev/rules.d/99-reload-monitor.rules b/linux/home/extras/etc/udev/rules.d/99-reload-monitor.rules
new file mode 100644
index 0000000..948aba5
--- /dev/null
+++ b/linux/home/extras/etc/udev/rules.d/99-reload-monitor.rules
@@ -0,0 +1 @@
+ACTION=="change", SUBSYSTEM=="drm", RUN+="/bin/su srdusr --command='systemctl --user start bspwm-reload.service'"
diff --git a/linux/home/install.bat b/linux/home/install.bat
new file mode 100644
index 0000000..d5298f1
--- /dev/null
+++ b/linux/home/install.bat
@@ -0,0 +1,6 @@
+REM Installing Dotfiles
+
+powershell . $HOME\.config\powershell\Microsoft.PowerShell_profile.ps1
+powershell Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
+powershell . $HOME\.config\powershell\bootstrap.ps1
+
diff --git a/linux/home/install.sh b/linux/home/install.sh
new file mode 100755
index 0000000..1b52e27
--- /dev/null
+++ b/linux/home/install.sh
@@ -0,0 +1,927 @@
+#!/usr/bin/env bash
+
+#======================================
+# Variables
+#======================================
+
+# Color definitions
+NOCOLOR='\033[0m'
+RED='\033[00;31m'
+GREEN='\033[00;32m'
+
+# Dotfiles
+dotfiles_url='https://github.com/srdusr/dotfiles.git'
+dotfiles_dir="$HOME/.cfg"
+
+# Log file
+LOG_FILE="dotfiles.log"
+TRASH_DIR="$HOME/.local/share/Trash"
+
+# Ensure Trash directory exists
+if [ ! -d "$TRASH_DIR" ]; then
+ mkdir -p "$TRASH_DIR"
+ if [ $? -ne 0 ]; then
+ echo "Failed to create Trash directory. Exiting..."
+ exit 1
+ fi
+fi
+
+# Move log file to Trash directory
+mv -f "$LOG_FILE" "$TRASH_DIR/"
+
+# Redirect stderr to both stderr and log file
+exec 2> >(tee -a "$LOG_FILE")
+
+# Function to log errors
+log_error() {
+ local message="$1"
+ echo "[ERROR] $(date +'%Y-%m-%d %H:%M:%S') - $message" | tee -a "$LOG_FILE" >&2
+}
+
+# Function to handle errors
+handle_error() {
+ local message="$1"
+ log_error "$message"
+ exit 1
+}
+
+# Function to log completion messages
+log_complete() {
+ local message="$1"
+ echo "[COMPLETE] $(date +'%Y-%m-%d %H:%M:%S') - $message" | tee -a "$LOG_FILE"
+}
+
+# Function to handle completion
+handle_complete() {
+ local message="$1"
+ log_complete "$message"
+}
+
+# Function to prompt the user
+prompt_user() {
+ local prompt="$1 [Y/n] "
+ local default_response="${2:-Y}"
+ local response
+
+ read -p "$prompt" -n 1 -r -e -i "$default_response" response
+ case "${response^^}" in
+ Y) return 0 ;;
+ N) return 1 ;;
+ *) handle_error "Invalid choice. Exiting.." && exit ;;
+ esac
+}
+
+# Function to temporarily unset GIT_WORK_TREE
+function git_without_work_tree() {
+ # Check if the current directory is a Git repository
+ if [ -d "$PWD/.git" ]; then
+ # Check if the current directory is inside the work tree
+ if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then
+ # If it's a Git repository and inside the work tree, proceed with unsetting GIT_WORK_TREE
+ GIT_WORK_TREE_OLD="$GIT_WORK_TREE"
+ unset GIT_WORK_TREE
+ "$@"
+ export GIT_WORK_TREE="$GIT_WORK_TREE_OLD"
+ else
+ # If it's a Git repository but not inside the work tree, call git command directly
+ git "$@"
+ fi
+ else
+ # If it's not a Git repository, call git command directly
+ git "$@"
+ fi
+}
+
+# Set alias conditionally
+alias git='git_without_work_tree'
+
+# Check for privilege escalation tools
+#--------------------------------------
+check_privilege_tools() {
+ if [ -x "$(command -v sudo)" ]; then
+ PRIVILEGE_TOOL="sudo"
+ elif [ -x "$(command -v doas)" ]; then
+ PRIVILEGE_TOOL="doas"
+ elif [ -x "$(command -v pkexec)" ]; then
+ PRIVILEGE_TOOL="pkexec"
+ elif [ -x "$(command -v dzdo)" ]; then
+ PRIVILEGE_TOOL="dzdo"
+ elif [ "$(id -u)" -eq 0 ]; then
+ PRIVILEGE_TOOL="" # root
+ else
+ PRIVILEGE_TOOL="" # No privilege escalation mechanism found
+ printf "\n${RED}Error: No privilege escalation tool (sudo, doas, pkexec, dzdo, or root privileges) found. You may not have sufficient permissions to run this script.${NOCOLOR}\n"
+ printf "\nAttempt to continue Installation (might fail without a privilege escalation tool)? [yes/no] "
+ read continue_choice
+ case $continue_choice in
+ [Yy] | [Yy][Ee][Ss]) ;;
+ [Nn] | [Nn][Oo]) exit ;;
+ *) handle_error "Invalid choice. Exiting..." && exit ;;
+ esac
+ fi
+}
+
+# Function to set locale to en_US.UTF-8
+set_locale() {
+ echo "Setting locale to en_US.UTF-8..."
+ if ! "$PRIVILEGE_TOOL" localectl set-locale LANG=en_US.UTF-8; then
+ handle_error "Failed to set locale to en_US.UTF-8"
+ fi
+}
+
+# Change shell to zsh
+change_shell() {
+ if prompt_user "Change shell to zsh?"; then
+ if command -v zsh &>/dev/null; then
+ chsh -s "$(which zsh)" && echo "Shell changed to zsh. Please log out and log back in to apply the changes."
+ #sudo chsh -s "$(which zsh)" "$(whoami)"
+ else
+ echo "Error: zsh is not installed."
+ fi
+ else
+ echo "Shell not changed."
+ fi
+}
+
+# Initialize git submodules
+submodules() {
+ echo "Initializing submodule(s)"
+ git submodule update --init --recursive
+}
+
+# Install Zsh plugins
+install_zsh_plugins() {
+ local zsh_plugins_dir="$HOME/.config/zsh/plugins"
+
+ mkdir -p "$HOME/.config/zsh"
+ mkdir -p "$zsh_plugins_dir"
+
+ if [ ! -d "$zsh_plugins_dir/zsh-you-should-use" ]; then
+ echo "Installing zsh-you-should-use..."
+ git clone https://github.com/MichaelAquilina/zsh-you-should-use.git "$zsh_plugins_dir/zsh-you-should-use"
+ else
+ echo "zsh-you-should-use is already installed."
+ fi
+
+ if [ ! -d "$zsh_plugins_dir/zsh-syntax-highlighting" ]; then
+ echo "Installing zsh-syntax-highlighting..."
+ git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$zsh_plugins_dir/zsh-syntax-highlighting"
+ else
+ echo "zsh-syntax-highlighting is already installed."
+ fi
+
+ if [ ! -d "$zsh_plugins_dir/zsh-autosuggestions" ]; then
+ echo "Installing zsh-autosuggestions..."
+ git clone https://github.com/zsh-users/zsh-autosuggestions.git "$zsh_plugins_dir/zsh-autosuggestions"
+ else
+ echo "zsh-autosuggestions is already installed."
+ fi
+}
+
+#==============================================================================
+
+#======================================
+# Common Sources/Dependencies
+#======================================
+echo "$dotfiles_dir" >>.gitignore
+echo "install.sh" >>.gitignore
+
+# Dotfiles
+function config {
+ git --git-dir="$dotfiles_dir"/ --work-tree="$HOME" "$@"
+}
+
+# Function to install dotfiles
+install_dotfiles() {
+ # Check if the $dotfiles_dir directory exists
+ if [ -d "$dotfiles_dir" ]; then
+ config pull >/dev/null 2>&1
+ update=true
+ else
+ git clone --bare "$dotfiles_url" "$dotfiles_dir" >/dev/null 2>&1
+ update=false
+ fi
+ std_err_output=$(config checkout 2>&1 >/dev/null) || true
+
+ if [[ $std_err_output == *"following untracked working tree files would be overwritten"* ]]; then
+ if [ "$update" = false ]; then
+ config checkout -- /dev/null 2>&1
+ fi
+ fi
+ config config status.showUntrackedFiles no
+
+ git config --global include.path "$HOME.gitconfig.aliases"
+
+ # Prompt the user if they want to overwrite existing files
+ if prompt_user "Do you want to overwrite existing files and continue with the dotfiles setup?"; then
+ config fetch origin main:main
+
+ config reset --hard main
+
+ config checkout -f
+ if [ $? -eq 0 ]; then
+ echo "Successfully backed up conflicting dotfiles in $dotfiles_dir-backup/ and imported $dotfiles_dir."
+ else
+ handle_error "Mission failed."
+ fi
+ else
+ # User chose not to overwrite existing files
+ handle_error "Aborted by user. Exiting..."
+ fi
+}
+
+# Check if necessary dependencies are installed
+#--------------------------------------
+# Download dependencies (wget/curl)
+check_download_dependencies() {
+ if [ -x "$(command -v wget)" ]; then
+ DOWNLOAD_COMMAND="wget"
+ elif [ -x "$(command -v curl)" ]; then
+ DOWNLOAD_COMMAND="curl"
+ else
+ handle_error "Neither wget nor curl found. Please install one of them to continue!"
+ fi
+}
+
+# Download a file using wget or curl
+download_file() {
+ local url="$1"
+ local output="$2"
+
+ if [ "$DOWNLOAD_COMMAND" = "wget" ]; then
+ if ! wget -q --show-progress -O "$output" "$url"; then
+ handle_error "Download failed. Exiting..."
+ exit 1
+ fi
+ elif [ "$DOWNLOAD_COMMAND" = "curl" ]; then
+ if ! curl --progress-bar -# -o "$output" "$url"; then
+ handle_error "Download failed. Exiting..."
+ exit 1
+ fi
+ else
+ echo "Unsupported download command: $DOWNLOAD_COMMAND"
+ exit 1
+ fi
+}
+
+# Install yq
+install_yq() {
+ if ! command -v yq &>/dev/null; then
+ echo "yq not found, installing..."
+ local bin_dir="$HOME/.local/bin"
+ local yq_url="https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64"
+ local yq_path="$bin_dir/yq"
+
+ echo "Installing yq..."
+
+ # Create bin directory if it doesn't exist
+ mkdir -p "$bin_dir" || {
+ echo "Error: Failed to create directory $bin_dir"
+ return 1
+ }
+
+ # Download yq
+ download_file "$yq_url" "$yq_path" || return 1
+
+ # Make yq executable
+ chmod +x "$yq_path" || {
+ echo "Error: Failed to set executable permissions for $yq_path"
+ return 1
+ }
+
+ echo "yq installed successfully to $bin_dir."
+
+ # Add bin directory to PATH if not already added
+ if [[ ":$PATH:" != *":$bin_dir:"* ]]; then
+ echo "Adding $bin_dir to PATH"
+ echo "export PATH=\"$bin_dir:\$PATH\"" >>"$HOME/.bashrc"
+ export PATH="$bin_dir:$PATH"
+ fi
+ else
+ echo "yq is already installed."
+ fi
+}
+
+#------------------------------------------------------------------------------
+
+#==============================================================================
+
+#======================================
+# Check Operating System
+#======================================
+check_os() {
+ if [[ "$OSTYPE" == "linux-gnu"* ]]; then
+ echo "Linux OS detected."
+ # Implement Linux-specific checks
+ elif [[ "$OSTYPE" == "darwin"* ]]; then
+ echo "MacOS detected."
+ # Implement MacOS-specific checks
+ elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then
+ echo "Windows-like environment detected."
+ # Implement Windows-specific checks
+ else
+ handle_error "Unsupported operating system."
+ fi
+}
+
+#==============================================================================
+
+#======================================
+# Linux
+#======================================
+
+# Check Distro
+#--------------------------------------
+
+# Detect package type from /etc/issue
+_found_arch() {
+ local _ostype="$1"
+ shift
+ grep -qis "$*" /etc/issue && _distro="$_ostype"
+}
+
+# Detect package type
+_distro_detect() {
+ # Check if /etc/os-release exists and extract information
+ if [ -f /etc/os-release ]; then
+ source /etc/os-release
+ case "$ID" in
+ "arch")
+ _distro="PACMAN"
+ return
+ ;;
+ "debian")
+ _distro="DPKG"
+ return
+ ;;
+ "ubuntu")
+ _distro="DPKG"
+ return
+ ;;
+ "centos")
+ _distro="YUM"
+ return
+ ;;
+ "fedora")
+ _distro="YUM"
+ return
+ ;;
+ "opensuse" | "suse")
+ _distro="ZYPPER"
+ return
+ ;;
+ "gentoo")
+ _distro="PORTAGE"
+ return
+ ;;
+ esac
+ fi
+
+ # Fallback method if /etc/os-release doesn't provide the information
+ if [ -f /etc/issue ]; then
+ _found_arch PACMAN "Arch Linux" && return
+ _found_arch DPKG "Debian GNU/Linux" && return
+ _found_arch DPKG "Ubuntu" && return
+ _found_arch YUM "CentOS" && return
+ _found_arch YUM "Red Hat" && return
+ _found_arch YUM "Fedora" && return
+ _found_arch ZYPPER "SUSE" && return
+ _found_arch PORTAGE "Gentoo" && return
+ fi
+
+ # Check for package managers and prompt the user if none found
+ local available_package_managers=("apt" "pacman" "portage" "yum" "zypper")
+ for manager in "${available_package_managers[@]}"; do
+ if command -v "$manager" &>/dev/null; then
+ _distro="$manager"
+ return
+ fi
+ done
+
+ # If none of the above methods work, prompt the user to specify the package manager
+ printf "Unable to detect the package manager. Please specify the package manager (e.g., apt, pacman, portage, yum, zypper): "
+ read -r user_package_manager
+ if [ -x "$(command -v "$user_package_manager")" ]; then
+ _distro="$user_package_manager"
+ return
+ else
+ _error "Specified package manager '$user_package_manager' not found. Exiting..."
+ exit 1
+ fi
+}
+
+#------------------------------------------------------------------------------
+
+# Define directories to create
+user_dirs() {
+ directories=('.cache' '.config' '.scripts')
+
+ # Prompt the user if they want to use user-dirs.dirs
+ if prompt_user "Do you want to use the directories specified in user-dirs.dirs?"; then
+ # Check if ~/.config/user-dirs.dirs exists
+ config_dirs_file="$HOME/.config/user-dirs.dirs"
+ if [ -f "$config_dirs_file" ]; then
+ echo "Config file $config_dirs_file exists. Proceeding..."
+ else
+ echo "Error: Config file $config_dirs_file not found. Please check your configuration."
+ exit 1
+ fi
+
+ # Prompt the user if they want to change directory names
+ if prompt_user "Do you want to change the directory names to lowercase?"; then
+ # Function to change directory names from uppercase to lowercase
+ change_dir_names() {
+ local config_file="$HOME/.config/user-dirs.dirs"
+
+ # Check if the system is not macOS
+ if [[ ! "$OSTYPE" == "darwin"* ]]; then
+ # Check if the config file exists
+ if [ -f "$config_file" ]; then
+ echo "Changing directory names from uppercase to lowercase..."
+
+ # Read the lines from the config file and process them
+ while read -r line; do
+ # Extract variable name and path from each line
+ if [[ $line =~ ^[[:space:]]*([A-Z_]+)=\"(.+)\" ]]; then
+ var_name="${BASH_REMATCH[1]}"
+ var_path="${BASH_REMATCH[2]}"
+
+ # Convert the variable name to lowercase
+ var_name_lowercase="$(echo "$var_name" | tr '[:upper:]' '[:lower:]')"
+
+ # Check if the directory exists
+ if [ -d "$var_path" ]; then
+ # Rename the directory to lowercase
+ new_var_path="$HOME/${var_name_lowercase}"
+ mv "$var_path" "$new_var_path"
+ echo "Renamed $var_path to $new_var_path"
+ fi
+ fi
+ done <"$config_file"
+
+ echo "Directory names changed successfully."
+ else
+ echo "The config file $config_file does not exist. Skipping directory name changes."
+ fi
+ else
+ echo "macOS detected. Skipping directory name changes."
+ fi
+ }
+
+ # Run the function to change directory names
+ change_dir_names
+ elif prompt_user "Do you want to change the directory names to uppercase?"; then
+ # Function to change directory names from lowercase to uppercase
+ change_dir_names() {
+ local config_file="$HOME/.config/user-dirs.dirs"
+
+ # Check if the system is not macOS
+ if [[ ! "$OSTYPE" == "darwin"* ]]; then
+ # Check if the config file exists
+ if [ -f "$config_file" ]; then
+ echo "Changing directory names from lowercase to uppercase..."
+
+ # Read the lines from the config file and process them
+ while read -r line; do
+ # Extract variable name and path from each line
+ if [[ $line =~ ^[[:space:]]*([A-Z_]+)=\"(.+)\" ]]; then
+ var_name="${BASH_REMATCH[1]}"
+ var_path="${BASH_REMATCH[2]}"
+
+ # Convert the variable name to uppercase
+ var_name_uppercase="$(echo "$var_name" | tr '[:lower:]' '[:upper:]')"
+
+ # Check if the directory exists
+ if [ -d "$var_path" ]; then
+ # Rename the directory to uppercase
+ new_var_path="$HOME/${var_name_uppercase}"
+ mv "$var_path" "$new_var_path"
+ echo "Renamed $var_path to $new_var_path"
+ fi
+ fi
+ done <"$config_file"
+
+ echo "Directory names changed successfully."
+ else
+ echo "The config file $config_file does not exist. Skipping directory name changes."
+ fi
+ else
+ echo "macOS detected. Skipping directory name changes."
+ fi
+ }
+
+ # Run the function to change directory names
+ change_dir_names
+ #xdg-user-dirs-update
+ fi
+ fi
+
+ # Create needed dirs and set proper permissions
+ for d in "${directories[@]}"; do
+ full_path="$HOME/$d"
+ if [ ! -d "$full_path" ]; then
+ mkdir -p "$full_path"
+ # Assuming $USER is defined or replace it with the desired user
+ chown -R "$USER" "$full_path"
+ echo "Created $full_path"
+ fi
+ done
+}
+
+#------------------------------------------------------------------------------
+
+# Update system
+linux_update_system() {
+ # Prompt the user if they want to update the system
+ prompt_user "Do you want to update the system?" Y || {
+ echo "System update skipped."
+ return
+ }
+
+ # Continue with system update based on detected package manager
+ case "$_distro" in
+ "PACMAN")
+ "$PRIVILEGE_TOOL" pacman -Syyy && "$PRIVILEGE_TOOL" pacman -Syu --noconfirm
+ ;;
+ "DPKG")
+ "$PRIVILEGE_TOOL" apt-get update && "$PRIVILEGE_TOOL" apt-get upgrade -y
+ ;;
+ "YUM")
+ "$PRIVILEGE_TOOL" yum update -y
+ ;;
+ "ZYPPER")
+ "$PRIVILEGE_TOOL" zypper --non-interactive update
+ ;;
+ "PORTAGE")
+ "$PRIVILEGE_TOOL" emerge --sync && "$PRIVILEGE_TOOL" emerge --ask --update --deep --newuse @world
+ ;;
+ *)
+ echo "Package manager not supported."
+ return 1
+ ;;
+ esac
+}
+
+#------------------------------------------------------------------------------
+
+linux_install_packages() {
+ local failed_packages=()
+ local any_failures=false
+ local packages_file="packages.yml"
+
+ # Check if yq is available
+ if ! command -v yq &>/dev/null; then
+ echo "Error: yq (YAML parser) is not installed or not found."
+ return 1
+ fi
+
+ # Read package names from packages.yml under PackageManager for most distributions
+ local packages=()
+ if [[ -f "$packages_file" ]]; then
+ while IFS= read -r package; do
+ packages+=("$package")
+ done < <(yq e '.PackageManager[]' "$packages_file" 2>/dev/null)
+ else
+ echo "Error: packages.yml not found."
+ return 1
+ fi
+
+ # Read the package manager type detected by _distro_detect()
+ case "$_distro" in
+ "PACMAN")
+ # Read additional package names from arch section if present
+ if [[ -f "$packages_file" ]]; then
+ while IFS= read -r package; do
+ packages+=("$package")
+ done < <(yq e '.arch[]' "$packages_file" 2>/dev/null)
+ fi
+
+ # Installation using Pacman
+ for package in "${packages[@]}"; do
+ if ! pacman -Q "$package" &>/dev/null; then
+ if ! "$PRIVILEGE_TOOL" pacman -S --noconfirm "$package"; then
+ failed_packages+=("$package")
+ any_failures=true
+ fi
+ fi
+ done
+ ;;
+ "DPKG")
+ # Try installing packages with dpkg
+ for package in "${packages[@]}"; do
+ if ! dpkg-query -W "$package" &>/dev/null; then
+ if ! "$PRIVILEGE_TOOL" apt-get install -y "$package"; then
+ failed_packages+=("$package")
+ any_failures=true
+ fi
+ fi
+ done
+ ;;
+ "YUM")
+ # Try installing packages with yum
+ for package in "${packages[@]}"; do
+ if ! rpm -q "$package" &>/dev/null; then
+ if ! "$PRIVILEGE_TOOL" yum install -y "$package"; then
+ failed_packages+=("$package")
+ any_failures=true
+ fi
+ fi
+ done
+ ;;
+ "ZYPPER")
+ # Try installing packages with zypper
+ for package in "${packages[@]}"; do
+ if ! rpm -q "$package" &>/dev/null; then
+ if ! "$PRIVILEGE_TOOL" zypper --non-interactive install "$package"; then
+ failed_packages+=("$package")
+ any_failures=true
+ fi
+ fi
+ done
+ ;;
+ "PORTAGE")
+ # Try installing packages with emerge for Gentoo
+ if [[ -f "$packages_file" ]]; then
+ # Read package names from packages.yml under gentoo
+ gentoo_packages=()
+ while IFS= read -r package; do
+ gentoo_packages+=("$package")
+ done < <(yq e '.gentoo[]' "$packages_file" 2>/dev/null)
+ else
+ echo "Error: packages.yml not found."
+ return 1
+ fi
+
+ for package in "${gentoo_packages[@]}"; do
+ if [ "$package" != "" ]; then
+ if ! equery list "$package" &>/dev/null; then
+ if ! "$PRIVILEGE_TOOL" emerge "$package"; then
+ failed_packages+=("$package")
+ any_failures=true
+ fi
+ fi
+ fi
+ done
+ ;;
+ *)
+ echo "Package manager not supported."
+ return 1
+ ;;
+ esac
+
+ # Check if any packages failed to install
+ if "$any_failures"; then
+ echo "Failed to install the following packages:"
+ printf '%s\n' "${failed_packages[@]}"
+ return 1
+ else
+ echo "All packages installed successfully."
+ return 0
+ fi
+}
+
+# Install Rust using rustup and install Rust packages from packages.yml
+install_rust() {
+ if command -v "rustup" &>/dev/null; then
+ echo "Installing Rust using rustup..."
+ CARGO_HOME=${XDG_DATA_HOME:-$HOME/.local/share}/cargo RUSTUP_HOME=${XDG_DATA_HOME:-$HOME/.local/share}/rustup bash -c 'curl https://sh.rustup.rs -sSf | sh -s -- -y'
+ else
+ echo "Rust is already installed."
+ fi
+
+ # Read Rust-specific packages from packages.yml under the 'rust' section
+ local rust_packages=()
+ if [[ -f "$packages_file" ]]; then
+ rust_packages=("$(yq '.rust[]' "$packages_file" 2>/dev/null)")
+ #rust_packages=("$(grep 'rust:' -A 1 "$packages_file" | grep -v 'rust:' | grep -vE '^\s*$' | sed 's/^\s*-\s*//')")
+ else
+ echo "Error: packages.yml not found."
+ return 1
+ fi
+
+ # Install Rust packages using cargo if rust is installed
+ if command -v "cargo" &>/dev/null; then
+ for package in "${rust_packages[@]}"; do
+ if ! cargo install "$package"; then
+ echo "Failed to install Rust package: $package"
+ return 1
+ fi
+ done
+ else
+ echo "Cargo not found. Rust packages installation skipped."
+ fi
+}
+
+# Function to install Node Version Manager (NVM)
+install_nvm() {
+ # Set NVM_DIR environment variable
+ export NVM_DIR="$HOME/.config/nvm"
+ if [ ! -d "$NVM_DIR" ]; then
+ mkdir -p "$NVM_DIR"
+ fi
+ # Download and install or update NVM script
+ if command -v nvm &>/dev/null; then
+ echo "Updating Node Version Manager (NVM)..."
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
+ else
+ echo "Installing Node Version Manager (NVM)..."
+ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
+ fi
+ # Source NVM script to enable it in the current shell
+ if [ -s "$NVM_DIR/nvm.sh" ]; then
+ echo "Sourcing NVM script..."
+ . "$NVM_DIR/nvm.sh"
+ else
+ echo "NVM script not found. Make sure installation was successful."
+ return 1
+ fi
+
+ # Verify installation
+ if command -v nvm &>/dev/null; then
+ echo "NVM installation completed successfully."
+ export NVM_DIR="$HOME/.config/nvm"
+ [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
+ [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
+ else
+ echo "NVM installation failed."
+ return 1
+ fi
+}
+
+install_node() {
+ # Check if Node.js is already installed
+ if ! command -v node &>/dev/null; then
+ echo "Node.js is already installed."
+ return
+ fi
+
+ echo "Installing Node.js..."
+ # Set up environment variables for Node.js installation
+ export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node/
+ export NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node/
+
+ # Install the latest stable version of Node.js using NVM
+ nvm
+ nvm install node
+ nvm use node
+ nvm install --lts
+ nvm alias default lts/* # Set LTS version as default
+
+ echo "Node.js installation completed successfully."
+}
+
+install_yarn() {
+ # Check if Yarn is already installed
+ if command -v yarn &>/dev/null; then
+ echo "Yarn is already installed."
+ return
+ fi
+
+ # Check if the .yarn directory exists
+ if [ -d "$HOME/.yarn" ]; then
+ echo "Removing existing .yarn directory..."
+ rm -rf "$HOME/.yarn"
+ fi
+
+ echo "Installing Yarn..."
+ # Install Yarn using npm
+ curl -o- -L https://yarnpkg.com/install.sh | bash
+ echo "Yarn installation completed successfully."
+}
+
+setup_tmux_plugins() {
+ local tpm_dir="$HOME/.config/tmux/plugins/tpm"
+ local plugins_dir="$HOME/.config/tmux/plugins"
+
+ # Ensure the plugins directory exists
+ if [ ! -d "$plugins_dir" ]; then
+ mkdir -p "$plugins_dir"
+ fi
+
+ # Ensure the TPM directory exists
+ if [ ! -d "$tpm_dir" ]; then
+ mkdir -p "$tpm_dir"
+ fi
+
+ if [ "$(ls -A "$tpm_dir")" ]; then
+ # TPM is already installed and directory is not empty, so we skip installation.
+ echo "TPM has been installed...skipping"
+ else
+ # If TPM directory doesn't exist or is empty, we proceed with installation.
+ if [ -d "$tpm_dir" ]; then
+ rm -rf "$tpm_dir" # Remove existing directory if it exists
+ fi
+ echo "Installing TPM..."
+ git clone https://github.com/tmux-plugins/tpm "$tpm_dir"
+ fi
+}
+
+install_tailscale() {
+ if ! command -v tailscale &>/dev/null; then
+ curl -fsSL https://tailscale.com/install.sh | bash
+ fi
+}
+
+setup_ssh() {
+ SSH_DIR="$HOME/.ssh"
+ if ! [[ -f "$SSH_DIR/authorized_keys" ]]; then
+ echo "Generating SSH keys"
+ mkdir -p "$SSH_DIR"
+ chmod 700 "$SSH_DIR"
+ ssh-keygen -b 4096 -t rsa -f "$SSH_DIR"/id_rsa -N '' -C "$USER@$HOSTNAME"
+ cat "$SSH_DIR"/id_rsa.pub >>"$SSH_DIR"/authorized_keys
+ fi
+}
+
+linux_specific_steps() {
+ install_dotfiles
+ user_dirs
+ _distro_detect
+ check_privilege_tools
+ #set_locale
+ submodules
+ change_dir_names
+ #linux_update_system
+ install_yq
+ #install_rust
+ #install_nvm
+ #install_node
+ #install_yarn
+ install_tailscale
+ linux_install_packages
+ install_zsh_plugins
+ setup_tmux_plugins
+ setup_ssh
+ change_shell
+}
+
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+
+#==============================================================================
+
+#======================================
+# MacOS
+#======================================
+
+macos_specific_steps() {
+ set_locale
+ macos_install_packages
+ git_install_macos
+
+}
+
+#==============================================================================
+
+#======================================
+# Windows
+#======================================
+
+windows_specific_steps() {
+ check_git_installed_windows
+ install_dependencies_windows
+ windows_install_packages
+ git_install_windows
+ symlink_configuration_files_windows
+}
+#------------------------------------------------------------------------------
+
+#==============================================================================
+
+#======================================
+# Main Installation
+#======================================
+
+# Main Installation
+main_installation() {
+ echo "Starting main installation..."
+
+ case "$OSTYPE" in
+ linux-gnu*)
+ linux_specific_steps
+ ;;
+ darwin*)
+ macos_specific_steps
+ ;;
+ msys* | cygwin*)
+ windows_specific_steps
+ ;;
+ *)
+ handle_error "Unsupported operating system."
+ ;;
+ esac
+
+ sleep 1
+}
+
+# Script entry point
+main() {
+ echo "Log File for Dotfiles Installation" >"$LOG_FILE"
+ check_download_dependencies
+ check_os
+ main_installation
+ handle_complete "Installation completed successfully."
+}
+
+main "$@"
diff --git a/linux/home/packages.yml b/linux/home/packages.yml
new file mode 100644
index 0000000..d6f1361
--- /dev/null
+++ b/linux/home/packages.yml
@@ -0,0 +1,436 @@
+common: []
+
+PackageManager:
+ - git
+ - curl
+ - wget
+ - yq
+ - zsh
+ - zsh-completions
+ - bash
+ - bash-completion
+ - clang
+ - gcc
+ - meson
+ # - llvm
+ - gdb
+ - make
+ - cmake
+ - go
+ - ninja
+ - ripgrep
+ - fd
+ - tree-sitter
+ - python3
+ - python-pip
+ - python-virtualenvwrapper
+ - time
+ - ufw
+ - jq
+ - fzf
+ - man-pages
+ - sudo
+ - doas
+ - bc
+ - man-db
+ - emacs
+ - vim
+ - neovim
+ - tmux
+ - wezterm
+ - openssh
+ - wmctrl
+ - xdo
+ - xdotool
+ - xbindkeys
+ - ncdu
+ - fcitx
+ - rsync
+ - net-tools
+ - xorg
+ - xorg-server
+ - wayland
+ - xorg-xwayland
+ - xclip
+ - xterm
+ - xdg-user-dirs
+ - gtk
+ - dunst
+ - clamav
+ - reflector
+ - firefox
+ - udiskie
+ - powertop
+ - iftop
+ - iotop
+ - atop
+ - btop
+ - bashtop
+ - htop-vim
+ # - pulseaudio
+ # - pulseaudio-alsa
+ # - pavucontrol
+ - picom
+ - rofi
+ - wofi
+ - pkgfile
+ - jgmenu
+ - hyprland
+ - eww
+ - bspwm
+ - sxhkd
+ - polybar
+ - mpv
+ - discord
+ - libinput
+ - xf86-input-libinput
+ - xf86-input-synaptics
+ - nnn
+ - ranger
+ - qbittorrent
+ - obs-studio
+ - tlp
+ - unrar
+ - unzip
+ - p7zip
+ - xqp
+ - bashtop
+ - xsel
+ - aylurs-gtk-shell-git
+ - brightnessctl
+ - bun-bin
+ - dart-sass
+ - gnome-bluetooth-3.0
+ - hyprpicker
+ - libdbusmenu-gtk3
+ - slurp
+ - swappy
+ - swww
+ - wayshot
+ - wf-recorder
+ - wl-clipboard
+ - networkmanager
+ - ntpsec
+ - wpa_applicant
+ - nemo
+ - mpd
+ - wireplumber
+ - pipewire
+ - ncmpcpp
+ - ffmpeg
+ - xdg-desktop-portal-wlr
+ - hwinfo
+ - readline
+ - imagemagick
+ - gjs
+ - sysstat
+ - blueman
+ - bluez
+ - bluez-lib
+ - bluez-tools
+ - bluez-utils
+ - cabextract
+ - wine
+ - winetricks
+ - steam
+ - steam-fonts
+ - libvirt
+ - qemu-full
+ - smartmontools
+ - hdparm
+ - acpi
+ - dosfstools
+ - ntfs-3g
+ - nfs-utils
+ - parted
+ - gparted
+ - cups
+ # - asusctl #*cli controls for asus laptops
+ # - supergfxctl #*gpu switching for asus laptops
+ # - nvidia
+ # - opencl-nvidia
+ # - nvidia-dkms
+ # - nvidia-settings
+
+rust:
+ - matugen
+
+arch:
+ - dkms
+ - linux
+ - linux-headers
+ - linux-tools
+ - base-devel
+ - bind-tools
+ - nvme-cli
+ - vulkan-devel
+ - lm_sensors
+debian/ubuntu:
+fedora:
+gentoo:
+ - dev-vcs/git
+ - net-misc/curl
+ - net-misc/wget
+ - app-misc/yq
+ - app-shells/zsh
+ - app-shells/zsh-completions
+ - app-shells/bash
+ - app-shells/bash-completion
+ - sys-devel/clang
+ - sys-devel/gcc
+ - dev-util/meson
+ # - sys-devel/llvm
+ - sys-devel/gdb
+ - sys-devel/make
+ - dev-util/cmake
+ - dev-lang/go
+ - dev-util/ninja
+ - sys-apps/ripgrep
+ - sys-apps/fd
+ - dev-libs/tree-sitter
+ # - dev-lang/python
+ - dev-python/pip
+ - dev-python/virtualenvwrapper
+ - sys-apps/time
+ - net-firewall/ufw
+ - app-misc/jq
+ - app-misc/fzf
+ - sys-apps/man-pages
+ - app-admin/sudo
+ - app-admin/doas
+ - sys-apps/bc
+ - sys-apps/man-db
+ - app-editors/emacs
+ - app-editors/vim
+ - app-editors/neovim
+ - app-misc/tmux
+ - x11-terms/wezterm
+ - net-misc/openssh
+ - x11-misc/wmctrl
+ - x11-misc/xdo
+ - x11-misc/xdotool
+ - x11-misc/xbindkeys
+ - sys-fs/ncdu
+ - app-i18n/fcitx
+ - net-misc/rsync
+ - net-misc/net-tools
+ - x11-base/xorg-server
+ - x11-base/xorg-drivers
+ - gui-libs/wayland
+ - x11-apps/xwayland
+ - x11-misc/xclip
+ - x11-terms/xterm
+ - x11-misc/xdg-user-dirs
+ - x11-libs/gtk+
+ - x11-misc/dunst
+ - app-antivirus/clamav
+ - sys-apps/reflector
+ - www-client/firefox-bin
+ - sys-fs/udiskie
+ - sys-power/powertop
+ - sys-process/iftop
+ - sys-process/iotop
+ - sys-process/atop
+ - sys-process/btop
+ - sys-process/bashtop
+ - sys-process/htop
+ # - media-sound/pulseaudio
+ # - media-sound/pulseaudio-alsa
+ # - media-sound/pavucontrol
+ - x11-misc/picom
+ - x11-misc/rofi
+ - gui-apps/wofi
+ - sys-apps/pkgfile
+ - gui-apps/jgmenu
+ - gui-wm/hyprland
+ - gui-apps/eww
+ - x11-wm/bspwm
+ - x11-misc/sxhkd
+ - x11-misc/polybar
+ - media-video/mpv
+ - net-im/discord
+ - x11-libs/libinput
+ - x11-drivers/xf86-input-libinput
+ - x11-drivers/xf86-input-synaptics
+ - app-misc/nnn
+ - app-misc/ranger
+ - net-p2p/qbittorrent
+ - media-video/obs-studio
+ - app-laptop/tlp
+ - app-arch/unrar
+ - app-arch/unzip
+ - app-arch/p7zip
+ - xqp
+ - x11-misc/xsel
+ - dev-util/aylurs-gtk-shell-git
+ - sys-apps/brightnessctl
+ - dev-util/bun-bin
+ - dev-util/dart-sass
+ - gnome-extra/gnome-bluetooth-3.0
+ - gui-apps/hyprpicker
+ - x11-libs/libdbusmenu-gtk3
+ - gui-apps/slurp
+ - gui-apps/swappy
+ - gui-apps/swww
+ - gui-apps/wayshot
+ - media-video/wf-recorder
+ - sys-apps/wl-clipboard
+ - net-misc/networkmanager
+ - net-misc/ntpsec
+ - net-wireless/wpa_supplicant
+ - gnome-extra/nemo
+ - media-sound/mpd
+ - media-video/wireplumber
+ - media-video/pipewire
+ - media-sound/ncmpcpp
+ - media-video/ffmpeg
+ - gui-libs/xdg-desktop-portal-wlr
+ - sys-apps/hwinfo
+ - sys-libs/readline
+ - media-gfx/imagemagick
+ - dev-libs/gjs
+ - sys-apps/sysstat
+ - net-wireless/blueman
+ - net-wireless/bluez
+ - net-wireless/bluez-lib
+ - net-wireless/bluez-tools
+ - net-wireless/bluez-utils
+ - app-arch/cabextract
+ - app-emulation/wine
+ - app-emulation/winetricks
+ - games-util/steam
+ - games-util/steam-fonts
+ - app-emulation/libvirt
+ - app-emulation/qemu
+ - sys-apps/smartmontools
+ - sys-apps/hdparm
+ - sys-power/acpi
+ - sys-fs/dosfstools
+ - sys-fs/ntfs3g
+ - net-fs/nfs-utils
+ - sys-block/parted
+ - sys-block/gparted
+ - net-print/cups
+ # - sys-apps/asusctl #*cli controls for asus laptops
+ # - sys-apps/supergfxctl #*gpu switching for asus laptops
+ # - x11-drivers/nvidia-drivers
+ # - dev-util/opencl-nvidia
+ # - x11-drivers/nvidia-dkms
+ # - x11-drivers/nvidia-settings
+
+fonts:
+ - ttf-hack
+ - ttf-nerd-fonts-symbols-mono
+ - ttf-font-awesome
+ - ttf-dejavu
+
+windows:
+ - git
+ - ripgrep
+ - fd
+ - sudo
+ - win32yank
+ - microsoft-windows-terminal
+ - wsl
+ - firefox
+ - setdefaultbrowser
+ - nodejs
+ - bat
+ - 7zip
+ - python
+ - javaruntime
+ - autohotkey
+ - bitwarden
+ - notepadplusplus
+ - neovim
+
+bloatware:
+ # - Anytime
+ - BioEnrollment
+ # - Browser
+ - ContactSupport
+ - Cortana
+ # - Defender
+ - Feedback
+ - Flash
+ # - Gaming # Breaks Xbox Live Account Login
+ # - Holo
+ # - InternetExplorer
+ - Maps
+ # - MiracastView
+ - OneDrive
+ # - SecHealthUI
+ - Wallet
+ # - Xbox # Causes a bootloop since upgrade 1511?
+
+default:
+ # default Windows 10 apps
+ # - Microsoft.3DBuilder
+ - Microsoft.Appconnector
+ - Microsoft.BingFinance
+ - Microsoft.BingNews
+ - Microsoft.BingSports
+ - Microsoft.BingTranslator
+ - Microsoft.BingWeather
+ # - Microsoft.FreshPaint
+ # - Microsoft.Microsoft3DViewer
+ - Microsoft.MicrosoftOfficeHub
+ - Microsoft.MicrosoftSolitaireCollection
+ - Microsoft.MicrosoftPowerBIForWindows
+ - Microsoft.MinecraftUWP
+ # - Microsoft.MicrosoftStickyNotes
+ # - Microsoft.NetworkSpeedTest
+ - Microsoft.Office.OneNote
+ # - Microsoft.OneConnect
+ - Microsoft.People
+ # - Microsoft.Print3D
+ - Microsoft.SkypeApp
+ - Microsoft.Wallet
+ # - Microsoft.Windows.Photos
+ # - Microsoft.WindowsAlarms
+ # - Microsoft.WindowsCalculator
+ - Microsoft.WindowsCamera
+ - microsoft.windowscommunicationsapps
+ - Microsoft.WindowsMaps
+ - Microsoft.WindowsPhone
+ - Microsoft.WindowsSoundRecorder
+ - Microsoft.WindowsStore
+ # - Microsoft.XboxApp
+ # - Microsoft.XboxGameOverlay
+ # - Microsoft.XboxIdentityProvider
+ # - Microsoft.XboxSpeechToTextOverlay
+ - Microsoft.ZuneMusic
+ - Microsoft.ZuneVideo
+
+ # Threshold 2 apps
+ - Microsoft.CommsPhone
+ - Microsoft.ConnectivityStore
+ - Microsoft.GetHelp
+ - Microsoft.Getstarted
+ - Microsoft.Messaging
+ - Microsoft.Office.Sway
+ - Microsoft.OneConnect
+ - Microsoft.WindowsFeedbackHub
+
+ # Redstone apps
+ - Microsoft.BingFoodAndDrink
+ - Microsoft.BingTravel
+ - Microsoft.BingHealthAndFitness
+ - Microsoft.WindowsReadingList
+
+ # non-Microsoft
+ - king.com.CandyCrushSaga
+ - king.com.CandyCrushSodaSaga
+ - king.com.*
+ - Facebook.Facebook
+
+ # apps which cannot be removed using Remove-AppxPackage
+ # - Microsoft.BioEnrollment
+ # - Microsoft.MicrosoftEdge
+ # - Microsoft.Windows.Cortana
+ # - Microsoft.WindowsFeedback
+ # - Microsoft.XboxGameCallableUI
+ # - Microsoft.XboxIdentityProvider
+ # - Windows.ContactSupport
+
+macos: []