diff options
Diffstat (limited to 'linux')
329 files changed, 25015 insertions, 0 deletions
diff --git a/linux/etc/X11/xorg.conf.d/70-synaptics.conf b/linux/etc/X11/xorg.conf.d/70-synaptics.conf new file mode 100644 index 0000000..e073d94 --- /dev/null +++ b/linux/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/etc/issue b/linux/etc/issue new file mode 100644 index 0000000..c165efa --- /dev/null +++ b/linux/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/etc/lightdm/lightdm-gtk-greeter.conf b/linux/etc/lightdm/lightdm-gtk-greeter.conf new file mode 100644 index 0000000..9e50dd3 --- /dev/null +++ b/linux/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/etc/lightdm/lightdm-webkit2-greeter.conf b/linux/etc/lightdm/lightdm-webkit2-greeter.conf new file mode 100644 index 0000000..57785a8 --- /dev/null +++ b/linux/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/etc/lightdm/lightdm.conf b/linux/etc/lightdm/lightdm.conf new file mode 100644 index 0000000..f751866 --- /dev/null +++ b/linux/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/etc/udev/rules.d/99-reload-monitor.rules b/linux/etc/udev/rules.d/99-reload-monitor.rules new file mode 100644 index 0000000..948aba5 --- /dev/null +++ b/linux/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/.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 Binary files differnew file mode 100644 index 0000000..204aeda --- /dev/null +++ b/linux/home/.config/dunst/assets/notification/fallback.png diff --git a/linux/home/.config/dunst/assets/notification/music.png b/linux/home/.config/dunst/assets/notification/music.png Binary files differnew file mode 100644 index 0000000..ae91be3 --- /dev/null +++ b/linux/home/.config/dunst/assets/notification/music.png diff --git a/linux/home/.config/dunst/assets/notification/scrot.png b/linux/home/.config/dunst/assets/notification/scrot.png Binary files differnew file mode 100644 index 0000000..1e12f38 --- /dev/null +++ b/linux/home/.config/dunst/assets/notification/scrot.png 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/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/tmux/file_manager.sh b/linux/home/.config/tmux/file_manager.sh new file mode 100755 index 0000000..b3a70a5 --- /dev/null +++ b/linux/home/.config/tmux/file_manager.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# tmux file opener with fallback file manager (no preview) + +# Mark this pane as the file manager immediately +tmux select-pane -T "FILE_MANAGER" +# Also set the option as backup +tmux set-option -pq @file_manager 1 + +orig_pane="$1" +chooser_file="$HOME/.cache/tmux-fm-selected" +rm -f "$chooser_file" + +# Function: pick available file manager +pick_fm() { + if command -v lf >/dev/null 2>&1; then + echo "lf" + elif command -v nnn >/dev/null 2>&1; then + echo "nnn" + elif command -v ranger >/dev/null 2>&1; then + echo "ranger" + else + echo "" + fi +} + +fm=$(pick_fm) +if [[ -z "$fm" ]]; then + echo "No file manager found (lf, nnn, ranger)." >&2 + cleanup + exit 1 +fi + +# Cleanup function to reset both title and option +cleanup() { + tmux select-pane -T "" + tmux set-option -puq @file_manager + rm -f "$chooser_file" +} + +# Set trap to cleanup on exit (including when user presses 'q') +trap cleanup EXIT INT TERM + +# Launch the chosen file manager with no preview where possible +case "$fm" in + nnn) + # Disable preview completely and use picker mode + # -A: disable dir auto-select, -e: open text files in editor + # -o: open files with opener, -x: show only selection + NNN_OPENER="tee \"$chooser_file\"" nnn -Axo + ;; + lf) + # Disable preview and set selection path + lf -command 'set preview false' -selection-path="$chooser_file" + ;; + ranger) + # Disable all previews + ranger --choosefile="$chooser_file" \ + --cmd='set preview_files false' \ + --cmd='set preview_directories false' \ + --cmd='set preview_images false' + ;; +esac + +# Exit if no file chosen (user pressed 'q' or cancelled) +if [[ ! -s "$chooser_file" ]]; then + exit 0 +fi + +file="$(head -n 1 "$chooser_file")" +rm -f "$chooser_file" + +# Restrict to current window panes and exclude the file manager pane +current_window=$(tmux display-message -p '#I') +mapfile -t panes < <( + tmux list-panes -t "$current_window" -F '#S:#I.#P' | + grep -v "^$(tmux display-message -p '#S:#I').$(tmux display-message -p '#P')$" +) + +# Choose target pane +if [[ ${#panes[@]} -eq 0 ]]; then + exit 1 +elif [[ ${#panes[@]} -eq 1 ]]; then + target="${panes[0]}" +else + echo "Select target pane:" + for i in "${!panes[@]}"; do + letter=$(printf "\\$(printf '%03o' $((97 + i)))") # a, b, c... + echo "$letter) ${panes[$i]}" + done + read -n 1 -p "Choice: " choice + echo + idx=$(( $(printf "%d" "'$choice") - 97 )) + if [[ $idx -ge 0 && $idx -lt ${#panes[@]} ]]; then + target="${panes[$idx]}" + else + exit 1 + fi +fi + +# Decide if file is text or binary +if file --mime-type "$file" 2>/dev/null | grep -q 'text/'; then + opener="${EDITOR:-$(command -v nvim || command -v vim || echo 'vi')}" +else + opener="$(command -v xdg-open || command -v open || echo 'cat')" +fi + +# Send open command to target pane +tmux send-keys -t "$target" "$opener \"$file\"" C-m diff --git a/linux/home/.config/tmux/fzf-menu.sh b/linux/home/.config/tmux/fzf-menu.sh new file mode 100755 index 0000000..d7863d9 --- /dev/null +++ b/linux/home/.config/tmux/fzf-menu.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +# fzf session name +FZF_SESSION_NAME="fzf" + +# Print error messages +error() { + echo "Error: $1" >&2 +} + +# Check if tmux is installed +if ! command -v tmux >/dev/null 2>&1; then + error "tmux is not installed." + exit 1 +fi + +# Function to handle file or directory opening +open_selected_item() { + # Use fzf to select a file from the specified directory + SELECTED_FILE=$(find ~ -type f | fzf --preview "bat --style=numbers --color=always --line-range=:500 {}" \ + --preview-window=up:60% --height=90% --layout=reverse --border=sharp --ansi) + + if [ "$SELECTED_FILE" != "" ]; then + # Ask whether to open the file or its directory + read -p "Open file (f) or directory (d)? " choice + case "$choice" in + f | F) + # Open the selected file in nvim + nvim "$SELECTED_FILE" + ;; + d | D) + # Change to the directory containing the selected file + cd "$(dirname "$SELECTED_FILE")" + ;; + *) + echo "Invalid choice. Please enter 'f' for file or 'd' for directory." + ;; + esac + else + echo "No file selected." + fi +} + +# Check if the fzf session exists +if tmux has-session -t "$FZF_SESSION_NAME" 2>/dev/null; then + # Get the current tmux session name + CURRENT_SESSION=$(tmux display-message -p '#S') + + # If currently in the fzf session, detach; otherwise, attach to it + if [ "$CURRENT_SESSION" = "$FZF_SESSION_NAME" ]; then + tmux detach-client + else + tmux set -gF '@last_session_name' '#S' # Store the current session name + tmux display-popup -E -x200% -y0 -w50% -h99% "tmux attach-session -t $FZF_SESSION_NAME" + fi +else + # If the fzf session doesn't exist, create it and run file selection logic in a popup + tmux set -gF '@last_session_name' '#S' # Store the current session name + tmux display-popup -E -w100% -h100% -y0 -x0 "tmux new-session -A -s fzf '$0 open_selected_item'" +fi diff --git a/linux/home/.config/tmux/left-status.sh b/linux/home/.config/tmux/left-status.sh new file mode 100755 index 0000000..e4a8c49 --- /dev/null +++ b/linux/home/.config/tmux/left-status.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +function ip-address() { + # Loop through the interfaces and check for the interface that is up. + for file in /sys/class/net/*; do + iface=$(basename $file); + read status < $file/operstate; + [ "$status" == "up" ] && ip addr show $iface | awk '/inet /{printf $2""}' + done +} + +function vpn-connection() { + # Check for tun0 interface. + [ -d /sys/class/net/tun0 ] && printf "%s " 'VPN*' +} + +function main() { + # Comment out any function you do not need. + ip-address + vpn-connection +} + +# Calling the main function which will call the other functions. +main + diff --git a/linux/home/.config/tmux/notes.sh b/linux/home/.config/tmux/notes.sh new file mode 100755 index 0000000..71a8dc7 --- /dev/null +++ b/linux/home/.config/tmux/notes.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +# Notes/TODO management & quick search engine via tmux + +NOTES_DIR="$HOME/documents/main" +TODO_FILE="$NOTES_DIR/inbox/tasks/TODO.md" +EDITOR="nvim" +NOTE_SESSION_NAME="note" +BROWSER_PREFERENCES=("firefox" "chromium" "google-chrome" "brave-browser" "chrome") +SEARCH_URL="https://www.google.com/search?q=" + +# simple error printing +error() { + echo "Error: $1" >&2 +} + +# add a TODO entry with timestamp +add_todo() { + local todo_text="$1" + [ -z "$todo_text" ] && return 1 + + [ ! -f "$TODO_FILE" ] && echo -e "# TODO List\n" > "$TODO_FILE" + + echo "- [ ] $todo_text ($(date '+%Y-%m-%d %H:%M'))" >> "$TODO_FILE" + tmux display-message "Added TODO: $todo_text" +} + +# open a web search +search_web() { + local query="$1" + [ -z "$query" ] && return 1 + + local encoded_query=$(printf '%s' "$query" | sed 's/ /+/g' | sed 's/[^a-zA-Z0-9+._-]//g') + local search_url="${SEARCH_URL}${encoded_query}" + + if command -v xdg-open >/dev/null 2>&1; then + xdg-open "$search_url" >/dev/null 2>&1 & + else + for browser in "${BROWSER_PREFERENCES[@]}"; do + command -v "$browser" >/dev/null 2>&1 && $browser "$search_url" >/dev/null 2>&1 & break + done + fi + + tmux display-message "Opening search for: $query" +} + +# display the notes menu (in-editor or popup) +open_menu() { + tmux set -gF '@last_session_name' '#S' + + if tmux has-session -t "$NOTE_SESSION_NAME" 2>/dev/null && tmux list-panes -t "$NOTE_SESSION_NAME" -F "#{pane_current_command}" | grep -q "^nvim$"; then + # menu for active nvim session + tmux display-menu -T "#[align=center] Notes (nvim-mode)" \ + "New note" n "command-prompt -p 'Enter note title:' 'send-keys -t $NOTE_SESSION_NAME \":e $NOTES_DIR/%%.md\" Enter'" \ + "Open note" o "send-keys -t $NOTE_SESSION_NAME \":cd $NOTES_DIR | FzfLua files\" Enter" \ + "TODO List" t "send-keys -t $NOTE_SESSION_NAME \":e $TODO_FILE\" Enter" \ + "Add Quick TODO" T "command-prompt -p 'Enter TODO:' 'run-shell \"$0 --add-todo %%\"'" \ + "Grep/find patterns" g "send-keys -t $NOTE_SESSION_NAME \":cd $NOTES_DIR | FzfLua live_grep\" Enter" \ + "Web Search" s "command-prompt -p 'Search query:' 'run-shell \"$0 --search %%\"'" \ + "Quit (q)" q "" + else + # popup menu outside of nvim + tmux display-menu -T "#[align=center] Notes (popup-mode)" \ + "New note" n "command-prompt -p 'Enter note title:' \"display-popup -w 100% -h 100% -E 'tmux new-session -A -s $NOTE_SESSION_NAME \\\"$EDITOR $NOTES_DIR/%%.md\\\"'\"" \ + "Open note" o "display-popup -w 100% -h 100% -E \"tmux new-session -A -s $NOTE_SESSION_NAME 'fzf --preview \\\"bat --style=numbers --color=always --line-range=:500 {}\\\" --preview-window=up:60% --height=90% --layout=reverse --border=sharp --ansi < <(find $NOTES_DIR -type f -name \\\"*.md\\\") | xargs -r $EDITOR'\"" \ + "TODO List" t "display-popup -w 100% -h 100% -E \"tmux new-session -A -s $NOTE_SESSION_NAME \\\"$EDITOR $TODO_FILE\\\"\"" \ + "Add Quick TODO" T "command-prompt -p 'Enter TODO:' 'run-shell \"$0 --add-todo %%\"'" \ + "Grep/find patterns" g "display-popup -w 100% -h 100% -E \"tmux new-session -A -s $NOTE_SESSION_NAME 'rg --color=always --line-number --no-heading --smart-case . $NOTES_DIR | fzf --delimiter=: --preview \\\"bat --style=numbers --color=always --line-range=:500 {1}\\\" --preview-window=up:60% --height=90% --layout=reverse --border=sharp --ansi | cut -d ':' -f 1 | xargs -r $EDITOR'\"" \ + "Web Search" s "command-prompt -p 'Search query:' 'run-shell \"$0 --search %%\"'" \ + "Quit (q)" q "" + fi +} + +# make sure tmux is installed +command -v tmux >/dev/null 2>&1 || { error "tmux is not installed."; exit 1; } + +# handle CLI arguments +if [ "$1" = "--add-todo" ]; then + shift + add_todo "$*" + exit 0 +fi + +if [ "$1" = "--search" ]; then + shift + search_web "$*" + exit 0 +fi + +if [ "$1" = "--new" ]; then + if tmux has-session -t "$NOTE_SESSION_NAME" 2>/dev/null; then + # reuse existing session + tmux display-popup -w 100% -h 100% -E " + FILE=\$(find $NOTES_DIR -type f -name '*.md' \ + | fzf --preview 'bat --style=numbers --color=always --line-range=:500 {}' \ + --preview-window=up:60% --height=90% --layout=reverse --border=sharp --ansi) + [ -n \"\$FILE\" ] && tmux send-keys -t $NOTE_SESSION_NAME \":e \$FILE\" Enter + " + else + open_menu + fi + exit 0 +fi + +# default behavior: toggle or open menu +if [ -z "$1" ]; then + if tmux has-session -t "$NOTE_SESSION_NAME" 2>/dev/null; then + CURRENT_SESSION=$(tmux display-message -p '#S') + [ "$CURRENT_SESSION" = "$NOTE_SESSION_NAME" ] && tmux detach-client || tmux display-popup -E -x200% -y0 -w50% -h99% "tmux attach-session -t $NOTE_SESSION_NAME" + else + open_menu + fi +fi diff --git a/linux/home/.config/tmux/right-status.sh b/linux/home/.config/tmux/right-status.sh new file mode 100755 index 0000000..a14bbe3 --- /dev/null +++ b/linux/home/.config/tmux/right-status.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Get CPU average +getCPU=$[100-$(vmstat 1 2|tail -1|awk '{print $15}')] + +# Grab the second line of the ouput produced by the command: free -g (displays output in Gb) +getMem=$(free -h | sed -n '2p') +getMemPct=$(free -g | sed -n '2p') + +# Split the string in secondLine into an array +read -ra ADDR <<< "$getMem" +read -ra ADDRPct <<< "$getMemPct" + +# Get the total RAM from arrays +totalRam="${ADDR[1]//[^0-9.0-9]/}" +totalRamPct="${ADDRPct[1]}" + +# Get the used RAM from arrays +usedRam="${ADDR[2]//[^0-9.0-9]/}" +usedRamPct="${ADDRPct[2]}" + +# Calculate and display the percentages +pct="$(($usedRamPct*100/$totalRamPct))" +usage="$usedRam/$totalRam" +#echo "cpu:$getCPU% | mem:$pct% ($usage""G)" +echo "Cpu:$getCPU% | Mem:$pct% |" + diff --git a/linux/home/.config/tmux/tmux-popup-pane-manager.sh b/linux/home/.config/tmux/tmux-popup-pane-manager.sh new file mode 100755 index 0000000..bb0cfef --- /dev/null +++ b/linux/home/.config/tmux/tmux-popup-pane-manager.sh @@ -0,0 +1,152 @@ +#!/usr/bin/bash +# tmux-popup-pane-manager.sh - menu driven tmux pane activities +# github repo: https://github.com/pl643/tmux-scripts +# resize, selection, syncronize, layout, splits, kill, break + +# sample tmux.conf binding: +# bind-key -n M-p tmux-popup-pane-manager.sh + +[ "$TMUX" = "" ] && echo "NOTE: needs to be run inside a tmux sessions" && exit 1 + +run_after_popup="/tmp/.run_after_popup" +realpath="$(realpath "$0")" +if [ "$1" != "--no-popup" ]; then + tmux popup -E -T "────────────── Pane Manager ─────" -w 46 -h 35 "$realpath --no-popup" + + [ -f "$run_after_popup" ] && bash "$run_after_popup" && rm "$run_after_popup" + exit 0 +fi + +pane_border_status="off" +display_menu() { + clear + tmux list-windows | grep active | awk '{print $2}' | tail -c2 | grep -q Z && zoom_status="on" || zoom_status="off" + tmux show-options -w | grep -q 'synchronize-panes.*on' && synchronize_panes="on" || synchronize_panes="off" + tmux show-options -w | grep -q 'pane-border-status.*top' && pane_border_status="top" + tmux show-options -w | grep -q 'pane-border-status.*bottom' && pane_border_status="bottom" + printf " + Resize + + hjkl x 5 HJKL x 1 + 1 - 9 | x 10%% ! - ) ─ x 10%% + = equally | + equally ─ + + Split + + s - spilt - v | spilt | + + Navigation + + n p next/prev pane + N P next/prev layout + u d swap pane up/down + + Toggles + + b border [ %s ] + S syncronize [ %s ] + z zoom [ %s ] + + Misc + + B break (make pane into window) + o join this pane to window + D send C-d + e display panes / exit + t rename pane + X kill (no confirm!) + q quit" "$pane_border_status" "$synchronize_panes" "$zoom_status" +} +display_menu + +# https://www.reddit.com/r/tmux/comments/g9nr01/how_to_show_message_or_effect_when/ +# Uncomment this setting if want status of pane sync on the status bar +tmux set -ag status-right '#{?pane_synchronized, #[fg=red]IN_SYNC#[default],}' + +# https://www.reddit.com/r/tmux/comments/dfj5ye/rename_pane_not_window_is_there_a_builtin/ +tmux set -g pane-border-format " [ ###P #T ] " + +# If C-c is press in the while [ true ] loop, a run runaway process occurs, limiting +# it to 20 will cause the loop to exit after 20 loops. Modify MAXNUMLOOP if you +# need more keys presses. +MAXNUMLOOP=100 +COUNTER=0 +while [ "$COUNTER" -lt "$MAXNUMLOOP" ]; do + + read -sn1 c || exit + + # Resize x 1 + [ "$c" = "H" ] && tmux resize-pane -L 1 + [ "$c" = "L" ] && tmux resize-pane -R 1 + [ "$c" = "J" ] && tmux resize-pane -D 1 + [ "$c" = "K" ] && tmux resize-pane -U 1 + + # Resize x 5 + [ "$c" = "h" ] && tmux resize-pane -L 5 + [ "$c" = "l" ] && tmux resize-pane -R 5 + [ "$c" = "j" ] && tmux resize-pane -D 5 + [ "$c" = "k" ] && tmux resize-pane -U 5 + + # Resize X percent + [ "$c" = "1" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 10 / 100)) + [ "$c" = "2" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 20 / 100)) + [ "$c" = "3" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 30 / 100)) + [ "$c" = "4" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 40 / 100)) + [ "$c" = "5" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 50 / 100)) + [ "$c" = "6" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 60 / 100)) + [ "$c" = "7" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 70 / 100)) + [ "$c" = "8" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 80 / 100)) + [ "$c" = "9" ] && tmux resize-pane -x $(($(tmux display-message -p "#{window_width}") * 90 / 100)) + + # Resize Y percent + [ "$c" = "!" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 10 / 100)) + [ "$c" = "@" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 20 / 100)) + [ "$c" = "#" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 30 / 100)) + [ "$c" = "$" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 40 / 100)) + [ "$c" = "%" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 50 / 100)) + [ "$c" = "^" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 60 / 100)) + [ "$c" = "&" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 70 / 100)) + [ "$c" = "*" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 80 / 100)) + [ "$c" = "(" ] && tmux resize-pane -y $(($(tmux display-message -p "#{window_height}") * 90 / 100)) + + # Pane layout cycle + [ "$c" = "N" ] || [ "$c" = " " ] && tmux next-layout + [ "$c" = "P" ] && tmux previous-layout + + # Pane selection cycle + [ "$c" = "n" ] && tmux select-pane -t :.+ + [ "$c" = "p" ] && tmux select-pane -t :.- + + # Pane layout selection even horizontal/vertical + [ "$c" = "=" ] && tmux select-layout even-horizontal + [ "$c" = "+" ] && tmux select-layout even-vertical + + # Rotate pane + [ "$c" = "u" ] && tmux swap-pane -U + [ "$c" = "d" ] && tmux swap-pane -D + + # Syncronize pane + [ "$c" = "S" ] && tmux setw synchronize-pane && display_menu + + # border status ( 3 toggle off, top, bottom ) + [ "$c" = "b" ] && [ "$pane_border_status" = "off" ] && tmux set pane-border-status && display_menu && continue + [ "$c" = "b" ] && [ "$pane_border_status" = "top" ] && tmux set pane-border-status bottom && display_menu && continue + [ "$c" = "b" ] && [ "$pane_border_status" = "bottom" ] && tmux set pane-border-status off && + pane_border_status="off" && display_menu && continue + + # Split panes + [ "$c" = "s" ] || [ "$c" = "-" ] && tmux split -v + [ "$c" = "v" ] || [ "$c" = "|" ] && tmux split -h + + # Misc + [ "$c" = "B" ] && tmux break-pane + [ "$c" = "o" ] && printf "\n\n join window: " && read window && tmux join-pane -t "$window" + [ "$c" = "X" ] && tmux kill-pane + [ "$c" = "D" ] && tmux send-key C-d + display_menu + [ "$c" = "q" ] && exit + [ "$c" = "e" ] && echo tmux display-panes >"$run_after_popup" && exit + [ "$c" = "z" ] && tmux resize-pane -Z && display_menu + [ "$c" = "t" ] && printf "\n\n pane name: " && read pane_name && tmux select-pane -T "$pane_name" && display_menu + let COUNTER=COUNTER+1 +done diff --git a/linux/home/.config/tmux/tmux-toggle-option.sh b/linux/home/.config/tmux/tmux-toggle-option.sh new file mode 100755 index 0000000..52d5fdb --- /dev/null +++ b/linux/home/.config/tmux/tmux-toggle-option.sh @@ -0,0 +1,27 @@ +#!/usr/bin/bash + +#USAGE="USAGE: $0 OPTION_NAME ON_STATE OFF_STATE" + +#OPTION_NAME=$1 +#ON_STATE=$2 +#OFF_STATE=$3 +# +#if [[ "$#" != 3 ]]; then +# echo $USAGE +# exit 1 +#fi +# +#if [[ `tmux show-option -w | grep "$OPTION_NAME $ON_STATE"` ]]; then +# OPTION_VALUE=$OFF_STATE +#else +# OPTION_VALUE=$ON_STATE +#fi +# +#tmux display-message "monitor activity: $OPTION_NAME $OPTION_VALUE" +#tmux set-option -w $OPTION_NAME $OPTION_VALUE > /dev/null + +if [ $(tmux show-option -A status-left) != 'status-left* "#[fg=#50fa7b,bg=default] #[bg=#50fa7b,fg=black]❐ #S #[fg=#50fa7b,bg=default]"' ]; then + tmux set -g status-left "#[fg=#50fa7b,bg=default] #[bg=#50fa7b,fg=black]❐ #S #[fg=#50fa7b,bg=default] "; +else + tmux set -g status-left "#[fg=#50fa7b,bg=default]#[bg=#50fa7b,fg=black] ❐ #S #( ~/.config/tmux/left-status.sh ) #[fg=#50fa7b,bg=default]" && tmux set -g status-right "#[fg=#50fa7b,bg=default] #{?client_prefix,#[reverse] Prefix #[noreverse] ,}#[bg=default,fg=#50fa7b]#[bg=#50fa7b,fg=black] #( ~/.config/tmux/right-status.sh ) %d-%b-%y | %H:%M #[bg=default,fg=#50fa7b]"; +fi diff --git a/linux/home/.config/tmux/tmux.conf b/linux/home/.config/tmux/tmux.conf new file mode 100644 index 0000000..a62e3e3 --- /dev/null +++ b/linux/home/.config/tmux/tmux.conf @@ -0,0 +1,835 @@ +# ████████╗███╗ ███╗██╗ ██╗██╗ ██╗ +# ╚══██╔══╝████╗ ████║██║ ██║╚██╗██╔╝ +# ██║ ██╔████╔██║██║ ██║ ╚███╔╝ +# ██║ ██║╚██╔╝██║██║ ██║ ██╔██╗ +# ██║ ██║ ╚═╝ ██║╚██████╔╝██╔╝ ██╗ +# ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ +#―――――――――――――――――――――――――――――――――――――――――― + +### Options ### + +# Setting the Prefix from Ctrl+b to Ctrl+s +unbind C-b +set -g prefix C-s +#set -g prefix M-Space + +# Ensure that we can send Ctrl+s to other apps +bind C-s send-prefix + +# Check if in (n)vim +is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'" + +# Send the prefix to client inside window (nested tmux) +#bind-key -n C-a send-prefix +bind -n C-a if-shell "$is_vim" "send-keys C-a" "send-prefix" + +# Disable local tmux keys (nested tmux) +bind -T root F12 \ + set prefix None \;\ + set key-table off \;\ + if -F '#{pane_in_mode}' 'send-keys -X cancel' \;\ + refresh-client -S \;\ + +bind -T off F12 \ + set -u prefix \;\ + set -u key-table \;\ + refresh-client -S + +# Toggle Sync Panes +bind C-y set-window-option synchronize-panes\; display-message "Synchronize-Panes is now #{?pane_synchronized,on,off}" + +# Setting the delay between Prefix and Command +set -sg escape-time 10 +#set-option -sg escape-time 10 + +# Reload tmux with <Prefix>r +bind r source-file ~/.config/tmux/tmux.conf \; display "Reloaded!" + +# Use <Prefix>L to clear terminal +bind -r L send-keys "clear" Enter + +# Rename current window (Ctrl + A, A) +bind R rename-window '' \; \ + command-prompt -I "#W" "rename-window -- '%%'" + +# Auto rename pane +set -wg automatic-rename on +set -g automatic-rename-format "#{pane_current_command}" + +# Renumber all windows when one is killed +set -g renumber-windows on + +# Mouse +set -g mouse on + +# Right Click Menu +bind -n MouseDown3Pane \ + if-shell -F "#{||:#{match:#{pane_current_command},nvim},#{match:#{pane_current_command},vim}}" \ + "send-keys -M" \ + "display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' \ + 'Vim' v 'send-keys \"vi\" Enter' \ + 'File-manager' f 'send-keys \"yazi\" Enter' \ + '' \ + 'Horizontal Split' '\\\\' 'split-window -h -c \"#{pane_current_path}\"' \ + 'Vertical Split' '-' 'split-window -v -c \"#{pane_current_path}\"' \ + '' \ + 'Copy Mode' 'C' 'copy-mode -e' \ + 'Paste' 'p' {send-keys C-v} \ + 'Open with xdg-open' 'o' 'send-keys \"xdg-open #{pane_current_path}\"' \ + 'Enter' 'e' 'send-keys Enter' \ + '' \ + 'Go To Top' '↑' 'copy-mode -e; send-keys gg' \ + 'Go To Bottom' '↓' 'copy-mode -e; send-keys G' \ + '' \ + 'Break Pane' 't' 'break-pane' \ + 'Join Pane' 'j' 'choose-window \"join-pane -h -s %%\"' \ + '#{?pane_marked,Unmark,Mark}' 'm' 'select-pane -m' \ + '#{?#{>:#{window_panes},1},,-}Swap Up' 'u' 'swap-pane -U' \ + '#{?#{>:#{window_panes},1},,-}Swap Down' 'd' 'swap-pane -D' \ + '' \ + 'New Window' 'n' 'new-window' \ + 'Previous Window' '🡠' 'previous-window' \ + 'Next Window' '🡢' 'next-window' \ + 'Swap Window Left' '<' 'swap-window -t -1' \ + 'Swap Window Right' '>' 'swap-window -t +1' \ + '' \ + 'Kill' 'X' 'kill-pane' \ + 'Respawn' 'R' 'respawn-pane -k' \ + 'Interrupt (Ctrl+C)' 'c' 'send-keys C-c' \ + '#{?#{>:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}' 'z' 'resize-pane -Z'" + + +# Disable copy on primary selection (prevents auto-copy on mouse drag release) +unbind -T root MouseDrag1Pane +unbind -T copy-mode MouseDragEnd1Pane +unbind -T copy-mode-vi MouseDragEnd1Pane + +# Left-click to select a pane (no copy mode) +bind -T root MouseDown1Pane { + select-pane -t= # Select pane under mouse + send-keys -M # Enable mouse interaction in pane +} + +# Don't go into copy-mode on first click/drag +bind -T root MouseDrag1Pane if-shell '[ "#{mouse_flags}" = "drag" ]' { + if-shell '[ "#{pane_id}" = "#{mouse_pane}" ]' { + copy-mode + send-keys -X begin-selection + } { + select-pane -t= + send-keys -M + } +} { + select-pane -t= + send-keys -M +} + +# Left-click to start selection in copy-mode +bind -T root DoubleClick1Pane { + copy-mode + send-keys -X begin-selection +} + +# Left-click to start selection in copy-mode +bind -T copy-mode-vi MouseDown1Pane { + send-keys -X cancel-selection + send-keys -X begin-selection +} + +# Left-click drag to start selection in copy-mode +bind -T copy-mode-vi MouseDown1Pane { + send-keys -X begin-selection +} + +# Right click to copy the selected text and exit copy mode +bind -T copy-mode-vi MouseDown3Pane { + send-keys -X copy-pipe-no-clear + send-keys -X end-selection + send-keys Escape +} + +# Middle click exit copy mode without copying (cancel the selection) +bind -T copy-mode-vi MouseDown2Pane { + send-keys -X end-selection + send-keys Escape +} + +# Middle click paste if not in copy-mode +# Conditional behavior for MouseDown2Pane +if-shell '[ "$CTRL_V_PASTE" = "true" ]' \ + "bind -T root MouseDown2Pane send-keys C-v" \ + "bind -T root MouseDown2Pane send-keys C-S-v" + +## Right-click drag to exit copy mode without selecting text +#bind -T copy-mode-vi MouseDragEnd3Pane { +# send-keys -X end-selection # End selection +# send-keys Escape # Exit copy mode +#} + +# Make mouse-drag work only with Ctrl +#unbind -T root MouseDrag1Pane +#unbind -T copy-mode-vi MouseDrag1Pane +#bind -n C-MouseDrag1Pane if -Ft= \ +#'#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" send-keys -X \"send-keys -M\"' 'copy-mode -M' +#bind -T copy-mode-vi C-MouseDrag1Pane send-keys -X begin-selection + +# Exiting copy mode without copying (Left-click to exit) +#bind -T copy-mode-vi MouseDown1Pane { +# select-pane -t= # Deselect pane +# send-keys Escape # Exit copy mode +#} + + +# Scrollback +set -g history-limit 10000 + +# Sane scrolling +set -g terminal-overrides 'xterm*:smcup@:rmcup@' + +# Sane scrolling +bind -n WheelUpPane { + if -F '#{==:#{window_name},nvim}' { + #send-keys -M + send-keys Up + } { + copy-mode -e + } +} +bind -n WheelDownPane { + if -F '#{==:#{window_name},nvim}' { + #send-keys -M + send-keys Down + } { + copy-mode -e + } +} + +# Focus events, allow supported requests from applications to passthrough/run in tmux +set-option -g focus-events on + +# Update the TERM variable of terminal emulator when creating a new session or attaching a existing session +set -g update-environment 'DISPLAY SSH_ASKPASS SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY TERM' + +# New session +#bind -n M-N new-session + + +# Lock +#set-option -g lock-command "vlock -c" +#set -g lock-after-time 910 # Seconds; 0 = never +#bind -n M-Escape lock-session + + +#―――――――――――――――――――――――――――――――――――――――――― + +### Window Movement/Control ### + +# Aggressive resizing, useful when using "grouped sessions" and multi-monitor setup +setw -g aggressive-resize on + +# Menu +bind-key -n M-m display-menu -x W -y S \ + "New Session" S "command-prompt -p \"New Session:\" \"new-session -A -s '%%'\"" \ + "Kill Session" x "kill-session" \ + "Kill Other Session(s)" X "kill-session -a" \ + "" \ + "New Window" ␍ new-window \ + "Kill Window" k "killw" \ + "Choose Window" w choose-window \ + "Previous Window" 🡠 previous-window \ + "Next Window" 🡢 next-window \ + "Swap Window Right" ↑ "swap-window -t -1" \ + "Swap Window Left" ↓ "swap-window -t +1" \ + "Horizontal Split" v "split-window -h" \ + "Vertical Split" s "split-window -v" \ + "" \ + "Layout Horizontal" h "select-layout even-horizontal" \ + "Layout Vertical" k "select-layout even-horizontal" \ + "" \ + "Swap Pane Up" < "swap-pane -U" \ + "Swap Pane Down" > "swap-pane -D" \ + "Break Pane" t break-pane \ + "Join Pane" j "choose-window 'join-pane -h -s \"%%\"'" \ + "#{?window_zoomed_flag,Unzoom,Zoom}" z "resize-pane -Z" + + +# Popup Pane Manager +bind-key -n M-/ run-shell ~/.config/tmux/tmux-popup-pane-manager.sh + +# List sessions + +#bind M-q display-popup -E -w 75% -h 75% "\ +# tmux list-sessions -F '#{?session_attached,,#{session_name}}' |\ +# sed '/^$/d' |\ +# fzf --reverse --header jump-to-session --preview 'tmux capture-pane -pt {}' |\ +# xargs tmux switch-client -t" + +# Kill sessions +bind M-q display-popup -E "\ + tmux list-sessions -F '#{?session_attached,,#{session_name}}' |\ + fzf --reverse -m --header=kill-session |\ + xargs -I {} tmux kill-session -t {}" + +# List sessions +bind -n M-Space display-popup -E "\ + tmux list-sessions -F '#{?session_attached,,#{session_name}}' |\ + sed '/^$/d' |\ + fzf --reverse --header jump-to-session --preview 'tmux capture-pane -pt {}' |\ + xargs tmux switch-client -t" + +# Session chooser +#bind -n M-q choose-tree -Zs -O time + +# Quick window select +bind -n M-? list-keys +bind -n M-0 select-window -t :=0 +bind -n M-1 select-window -t :=1 +bind -n M-2 select-window -t :=2 +bind -n M-3 select-window -t :=3 +bind -n M-4 select-window -t :=4 +bind -n M-5 select-window -t :=5 +bind -n M-6 select-window -t :=6 +bind -n M-7 select-window -t :=7 +bind -n M-8 select-window -t :=8 +bind -n M-9 select-window -t :=9 + +# move pane to existing window or create it +bind-key -n M-! run -C '#{?#{m:*|1|*,|#{W:#I|}},joinp -ht :1,breakp -t :1}' +bind-key -n M-@ run -C '#{?#{m:*|2|*,|#{W:#I|}},joinp -ht :2,breakp -t :2}' +bind-key -n M-# run -C '#{?#{m:*|3|*,|#{W:#I|}},joinp -ht :3,breakp -t :3}' +bind-key -n M-$ run -C '#{?#{m:*|4|*,|#{W:#I|}},joinp -ht :4,breakp -t :4}' +bind-key -n M-% run -C '#{?#{m:*|5|*,|#{W:#I|}},joinp -ht :5,breakp -t :5}' +bind-key -n M-^ run -C '#{?#{m:*|6|*,|#{W:#I|}},joinp -ht :6,breakp -t :6}' +bind-key -n M-& run -C '#{?#{m:*|7|*,|#{W:#I|}},joinp -ht :7,breakp -t :7}' +bind-key -n M-* run -C '#{?#{m:*|8|*,|#{W:#I|}},joinp -ht :8,breakp -t :8}' +bind-key -n M-( run -C '#{?#{m:*|9|*,|#{W:#I|}},joinp -ht :9,breakp -t :9}' +bind-key -n M-) run -C '#{?#{m:*|0|*,|#{W:#I|}},joinp -ht :0,breakp -t :0}' + +#―――――――――――――――――――――――――――――――――――――――――― + +### Pane Movement/Control ### + +# Smart pane switching with awareness of Vim splits. +# See: https://github.com/christoomey/vim-tmux-navigator +# Navigate across tmux-vim + +# {{{ keybinds: select-pane +#bind -Tnav h select-pane -L +#bind h select-pane -L +#bind -Tnav C-h select-pane -L +#bind C-h select-pane -L +#bind -Tnav j select-pane -D +#bind j select-pane -D +#bind -Tnav C-j select-pane -D +#bind C-j select-pane -D +#bind -Tnav k select-pane -U +#bind k select-pane -U +#bind -Tnav C-k select-pane -U +#bind C-k select-pane -U +#bind -Tnav l select-pane -R +#bind l select-pane -R +#bind -Tnav C-l select-pane -R +#bind C-l select-pane -R + +# {{{ keybinds: select-pane +# Smart pane switching with Vim awareness +is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(n?vim|vimx?)'" + +bind -n C-h if-shell "$is_vim" "send-keys C-\\ C-n C-h" "select-pane -L" +bind -n C-j if-shell "$is_vim" "send-keys C-\\ C-n C-j" "select-pane -D" +bind -n C-k if-shell "$is_vim" "send-keys C-\\ C-n C-k" "select-pane -U" +bind -n C-l if-shell "$is_vim" "send-keys C-\\ C-n C-l" "select-pane -R" +# keybinds: select-pane }}} + +# {{{ keybinds: split-window +bind -Tnav "\\" split-window -h -c "#{pane_current_path}" # vertical +bind "\\" split-window -h -c "#{pane_current_path}" # vertical +bind -Tnav "|" split-window -fh -c "#{pane_current_path}" # full vertical +bind "|" split-window -fh -c "#{pane_current_path}" # full vertical +bind -Tnav "-" split-window -v -c "#{pane_current_path}" # horizontal +bind "-" split-window -v -c "#{pane_current_path}" # horizontal +bind -Tnav "_" split-window -fv -c "#{pane_current_path}" # full horizontal +bind "_" split-window -fv -c "#{pane_current_path}" # full horizontal +# keybinds: split-window }}} + +# {{{ keybinds: resize-pane +bind -r -Tnav M-h resize-pane -L 10 +bind -r M-h resize-pane -L 10 +bind -r -Tnav M-j resize-pane -D 5 +bind -r M-j resize-pane -D 5 +bind -r -Tnav M-k resize-pane -U 5 +bind -r M-k resize-pane -U 5 +bind -r -Tnav M-l resize-pane -R 10 +bind -r M-l resize-pane -R 10 +# keybinds: resize-pane }}} + +# Hide a pane and bring it back with <Prefix>! and <Prefix>@ respectively +bind-key ! break-pane -d -n _hidden_pane +bind-key @ join-pane -s $.0 + +# Send Pane to another session/window with <Prefix>= +bind-key = command-prompt -p "send pane to:" "join-pane -t '%%'" + +#―――――――――――――――――――――――――――――――――――――――――― + +### Popup ### + +# Toggle popup "term" session +set -g @term_session_name "term" +bind -n M-t if-shell -F '#{==:#{session_name},term}' { + detach-client + } { + if-shell "tmux has-session -t term" { + set -gF '@last_session_name' '#S' # Store the current session name + display-popup -E -xC -yC -w60% -h60% "tmux attach-session -t term" + } { + set -gF '@last_session_name' '#S' # Store the current session name + display-popup -E -xC -yC -w60% -h60% "tmux new-session -d -c '#{pane_current_path}' -s term && tmux set-option -t term status off && tmux attach-session -t term" + } +} + + +## Toggle popup "note" session +bind-key -n M-n if-shell -F "#{client_in_popup}" \ + "detach-client -P" \ + "run-shell ~/.config/tmux/notes.sh" + +bind-key -n M-N run-shell "~/.config/tmux/notes.sh --new" + +# Toggle popup "pack" session +bind-key -n M-p if-shell -F '#{==:#{session_name},pack}' { + detach-client +} { + set -gF '@last_session_name' '#S' # Store the current session name + #display-popup -w 80% -h 80% -E "tmux new-session -A -s pack" + display-popup -E -x200% -y0 -w50% -h99% "tmux new-session -A -s pack" +} + +# M-T → Open TODO.md in popup +bind-key -n M-o if-shell -F '#{==:#{session_name},todo}' { + + detach-client +} { + set -gF '@last_session_name' '#S' + display-popup -E -x200% -y0 -w50% -h99% "tmux new-session -A -s todo 'nvim ~/documents/main/inbox/tasks/TODO.md'" +} + +# M-y → Toggle VM popup (starts/attaches session "virt" inside popup) +bind-key -n M-y if-shell -F '#{==:#{session_name},virt}' { + detach-client -P +} { + set -gF '@last_session_name' '#S' + display-popup -E -x200% -y0 -w40% -h60% "tmux new-session -A -s virt bash -lc 'echo \"### VM Manager ###\"; echo; echo \"Available VM scripts:\"; ls -1 ~/.scripts/env/virt/ 2>/dev/null || echo \"No scripts found in ~/.scripts/env/virt/\"; echo; echo \"Run your VM by typing its script name (e.g., ubuntu, fedora, win11).\"; exec \$SHELL'" +} + +# M-H → Open history in popup +bind-key -n M-H if-shell -F '#{==:#{session_name},hist}' { + detach-client +} { + set -gF '@last_session_name' '#S' + display-popup -E -x200% -y0 -w50% -h99% "tmux new-session -A -s hist \"bash -c \' + shell=\\\$(basename \\\$SHELL) + if [[ \\\$shell == zsh ]]; then + if [[ -f \\\$HOME/.config/zsh/.zhistory ]]; then + nvim \\\$HOME/.config/zsh/.zhistory + elif [[ -f \\\$HOME/.zhistory ]]; then + nvim \\\$HOME/.zhistory + else + echo \\\"No Zsh history found\\\"; sleep 5 + fi + elif [[ \\\$shell == bash ]]; then + if [[ -f \\\$HOME/.bash_history ]]; then + nvim \\\$HOME/.bash_history + else + echo \\\"No Bash history found\\\"; sleep 5 + fi + else + echo \\\"Unknown shell: \\\$shell\\\"; sleep 5 + fi + \'\"" +} + +# Move popup session (note, term, or pack) to scratchpad (tmux)/last session or back to respective popup +bind -n M-x run-shell ' + current_session=$(tmux display-message -p "#S"); + + # Check if the current session is one of the popups (note, term, pack) + if [ "$current_session" = "note" ] || [ "$current_session" = "term" ] || [ "$current_session" = "pack" ]; then + # Detach, break the pane out of the popup, and join it to the last session + tmux detach-client; + tmux break-pane; + last_session=$(tmux show -gvq @last_session_name || echo tmux); + tmux set -g @last_popup_session "$current_session"; # Save which popup it was + tmux join-pane -s "$current_session" -t "$last_session" -h; + else + # If not in one of the popups, move the last popup session back to its popup + last_popup=$(tmux show -gqv @last_popup_session); + + if [ "$last_popup" = "note" ]; then + if ! tmux has-session -t note; then + # Spawn note session in detached mode without blocking + tmux new-session -d -s note; + fi + tmux join-pane -s $(tmux display-message -p "#P") -t note; + tmux kill-pane -a -t note:0; + elif [ "$last_popup" = "term" ]; then + if ! tmux has-session -t term; then + tmux new-session -d -s term; + fi + tmux join-pane -s $(tmux display-message -p "#P") -t term; + tmux kill-pane -a -t term:0; + elif [ "$last_popup" = "pack" ]; then + if ! tmux has-session -t pack; then + tmux new-session -d -s pack; + fi + tmux join-pane -s $(tmux display-message -p "#P") -t pack; + tmux kill-pane -a -t pack:0; + fi + fi' +# TODO: add keybinding that will allow going across the dipslay popup and main tmux session +# TODO: add keybinding for toggling the display popup size to/from fullscreen and it's original size + +# Toggle popup "fzf" session +#bind-key -n M-o run-shell ~/.config/tmux/fzf-menu.sh + +# Toggle popup "htop" session +bind -n M-i if-shell -F '#{==:#{session_name},htop}' { + detach-client + } { + if-shell "tmux has-session -t HUD" { + display-popup -E -x200% -y0 -w40% -h40% "tmux new-session -A -s HUD" + } { + display-popup -E -x200% -y0 -w40% -h40% "tmux new-session -A -s htop 'htop'" + } +} + +# Toggle popup "lazygit" session +bind-key -n M-g if-shell -F '#{==:#{session_name},lazygit}' { + detach-client +} { + display-popup -w 90% -h 90% -E "tmux new-session -A -s lazygit 'lazygit'" +} + +## Toggle popup "yazi" session +#bind-key -n M-f if-shell -F '#{==:#{session_name},yazi}' { +# detach-client +#} { +# display-popup -w 90% -h 90% -E "tmux new-session -A -s yazi 'yazi'" +#} +#tmux split-window -h -p 30 \ +# "NNN_OPENER=~/.config/tmux/file_manager.sh nnn" + +#bind-key -n M-f run-shell 'tmux split-window -hb -p 30 "~/.config/tmux/file_manager.sh $(tmux display-message -p "#I.#P")"' + +# Robust file manager toggle - checks both title and option +bind-key -n M-f run-shell "\ +fm_pane_title=\$(tmux list-panes -F '#{pane_id} #{pane_title}' | awk '\$2==\"FILE_MANAGER\" {print \$1}'); \ +fm_pane_option=\$(tmux list-panes -F '#{pane_id} #{@file_manager}' | awk '\$2==\"1\" {print \$1}'); \ +fm_pane=\${fm_pane_title:-\$fm_pane_option}; \ +if [ -n \"\$fm_pane\" ]; then \ + tmux kill-pane -t \"\$fm_pane\"; \ +else \ + current_pane=\$(tmux display-message -p '#{session_name}:#{window_index}.#{pane_index}'); \ + tmux split-window -hb -p 30 \"~/.config/tmux/file_manager.sh \$current_pane\"; \ +fi" + +## Toggle popup "speedtest" session +#bind-key -n M-s if-shell -F '#{==:#{session_name},speedtest}' { +# detach-client +#} { +# display-popup -E "tmux new-session -A -s speedtest 'speedtest'" +#} + + +# Toggle popup "nvim" session +bind-key -n M-v if-shell -F '#{==:#{session_name},edit}' { + detach-client +} { + display-popup -w 100% -h 100% -E "tmux new-session -A -s edit 'cd && nvim'" +} + + +# Toggle popup "ssh" session +bind-key -n M-s if-shell -F '#{==:#{session_name},ssh}' { + detach-client +} { + display-popup -w 40% -h 50% -E "tmux new-session -A -s ssh" +} + +# Toggle popup session to fullscreen +bind-key -n M-F run-shell ' + popup_session=$(tmux display-message -p "#{session_name}"); + if [[ "$popup_session" == "term" || "$popup_session" == "note" || "$popup_session" == "lazygit" || "$popup_session" == "yazi" || "$popup_session" == "speedtest" || "$popup_session" == "nvim" || "$popup_session" == "ssh" || "$popup_session" == "pack" || "$popup_session" == "htop" ]]; then + tmux detach-client + sleep 0.1 + tmux display-popup -E -w 100% -h 100% "tmux new-session -A -s $popup_session" + fi +' + +bind -n M-L lock-session + +#bind-key -n M-o display-popup -E nvim -c ":ObsidianNew" +#bind-key -n M-/ display-popup -w "90%" -h "85%" -E nvim -c ":ObsidianSearch" + + +#proc +#netw +#ssh + + +#―――――――――――――――――――――――――――――――――――――――――― + +### Copy Mode (Copy/Paste) ### + +# Set Vi copy mode, use <prefix>[ to enter copy mode +setw -g mode-keys vi # `<prefix>:list-keys -T copy-mode-vi` to confirm + +# super fast way to reach copy-mode and search upwards +bind-key / copy-mode \; send-key ? + +# Alt + Space copy-mode without prefix +bind-key -n M-c copy-mode + +# Shift up/down copy-mode without prefix +bind-key -n S-Up copy-mode \; send-key Up +bind-key -n S-Down copy-mode \; send-key Down +bind-key -n Pageup copy-mode \; send-key Pageup +bind-key -n Pagedown copy-mode \; send-key Pagedown +#bind -n Pageup if-shell "$is_vim" "send-keys Pageup" "copy-mode -u" +#bind -n S-Pageup if-shell "$is_vim" "send-keys Pageup" "copy-mode -u" +bind -n Pageup if-shell "$is_vim" "send-keys Pageup" +bind -n S-Pageup if-shell "$is_vim" "send-keys Pageup" +bind -n S-Pagedown send-keys Pagedown + +# Change selection <space> and enter to vi keybinding +bind-key -T copy-mode-vi 'v' send -X begin-selection +bind-key -T copy-mode-vi 'y' send -X copy-selection-and-cancel +bind -T copy-mode-vi Escape send -X cancel +bind -T copy-mode-vi C-c send -X clear-selection +bind -T copy-mode-vi C-v send -X begin-selection \; send-keys -X rectangle-toggle + +# Unbind any previous 'y' in copy-mode-vi to prevent conflicts +unbind -T copy-mode-vi 'y' + +# Clipboard copy for X11/XWayland +if-shell -b '[ "$DISPLAY" ] && command -v xclip >/dev/null' "\ + bind-key -T copy-mode-vi 'y' send-keys -X copy-pipe-and-cancel 'xclip -in -selection clipboard > /dev/null 2>&1'" + +# Clipboard copy for Wayland +if-shell -b '[ \"$WAYLAND_DISPLAY\" ] && command -v wl-copy >/dev/null' "\ + bind-key -T copy-mode-vi 'y' send-keys -X copy-pipe-and-cancel 'wl-copy --foreground --type text/plain > /dev/null 2>&1'" + +# macOS clipboard copy +if-shell -b '[ \"$(uname -s)\" = \"Darwin\" ] && command -v pbcopy >/dev/null' "\ + bind-key -T copy-mode-vi 'y' send-keys -X copy-pipe-and-cancel 'pbcopy'" + +# Windows (WSL) clipboard copy +if-shell -b 'uname -r | grep -qi microsoft && command -v clip.exe >/dev/null' "\ + bind-key -T copy-mode-vi 'y' send-keys -X copy-pipe-and-cancel 'clip.exe > /dev/null 2>&1'" + +# For OSC-Yank in vim to work over ssh +# https://github.com/ojroques/vim-oscyank +#set -s set-clipboard on +#set -g set-clipboard on +#set -g terminal-overrides 'xterm*:paste:Ctrl+Shift+V' + +set -g allow-passthrough on +set extended-keys on + +# notify when a window has activity +set-window-option -g monitor-activity on + +# Copy mode search with a simple shortcut (@see https://superuser.com/a/1253137) +bind-key / copy-mode \; send-key ? + +#―――――――――――――――――――――――――――――――――――――――――― + +### Colors ### + +## Assume external terminal supports the 256 colors palette (when TERM=xterm-256color) +#set -sa terminal-features ",xterm-256color:256" +## Assume external terminal supports RGB colors (when TERM=xterm-256color) +#set -sa terminal-features ",xterm-256color:RGB" +# +## Set TERM for proper colors +#set -g default-terminal "tmux-256color" +#set -g default-terminal "xterm-256color" + +# Set 256 color terminal +#set-option -sa terminal-overrides ",tmux-256color:Tc" +#set-option -sa terminal-overrides ",xterm*:Tc,alacritty*:Tc" + +# Colors for pane borders(default) +setw -g pane-border-style fg=white +setw -g pane-active-border-style fg=green + +# Active pane normal, other shaded out +setw -g window-style fg=colour240 +setw -g window-active-style fg=white + +# Popup border +set -g popup-border-lines rounded + +# + +#―――――――――――――――――――――――――――――――――――――――――― + +### Status ### + +set -g status-position bottom # [top, bottom] +set -g status on +#set -g status-interval 1 +set -g status-interval 500 +#set -g status-style fg=#50fa7b,bg=default + +# Toggle status +bind T set status + +# Inactive windows +set -g status-style bg=default +set -g window-status-activity-style noreverse +set -g window-status-format "#[fg=#ffffff,bg=default]#I: #W" + +## Left +set -g status-left "" +set -g status-left-length 60 + +## Center +set -g status-justify absolute-centre + +## Right +set -g status-right-length 60 +set-option -g status-right "" + + +### Status Style +set -g status-style "bg=default,fg=#CDD6F4" +#set -g status-left-length 100 +#set -g status-right-length 150 + +### Left +set -g status-left '#( \ + if fc-list | grep -qi nerd; then \ + cat ~/.vi-mode | awk '\''/-- NORMAL --/ {print "#[fg=#39BAE6]#[bg=default]#[bg=#39BAE6,fg=#000000] ❐ #S #[fg=#39BAE6,bg=default]"} \ + /-- INSERT --/ {print "#[fg=#50fa7b]#[bg=default]#[bg=#50fa7b,fg=#000000] ❐ #S #[fg=#50fa7b,bg=default]"}'\''; \ + else \ + cat ~/.vi-mode | awk '\''/-- NORMAL --/ {print "#[bg=default,fg=#39BAE6] #S "} \ + /-- INSERT --/ {print "#[bg=default,fg=#50fa7b] #S "}'\''; \ + fi \ +)' + +### Center +set -g window-status-current-format '#( \ + if fc-list | grep -qi nerd; then \ + cat ~/.vi-mode | awk '\''/-- NORMAL --/ {print "#[fg=#39BAE6]#[bg=default]#[fg=#000000,bg=#39BAE6] #I:#W #[bg=default,fg=#39BAE6]"} \ + /-- INSERT --/ {print "#[fg=#50fa7b]#[bg=default]#[fg=#000000,bg=#50fa7b] #I:#W #[bg=default,fg=#50fa7b]"}'\''; \ + else \ + cat ~/.vi-mode | awk '\''/-- NORMAL --/ {print "#[fg=#39BAE6,bg=default] #I:#W "} \ + /-- INSERT --/ {print "#[fg=#50fa7b,bg=default] #I:#W "}'\''; \ + fi \ +)' + +### Right +set -g status-right '#( \ + key_off="#[fg=#50fa7b,bg=default]#([ $(tmux show-option -qv key-table) = off ] && echo KEYS\ OFF)#[default]"; \ + vi_segment=$(cat ~/.vi-mode | awk '\''/-- NORMAL --/ {print "#[fg=#50fa7b,bg=default] #[fg=#39BAE6]#[bg=#39BAE6,fg=#000000] %H:%M #[bg=default,fg=#39BAE6]"} \ + /-- INSERT --/ {print "#[fg=#39BAE6,bg=default] #[fg=#50fa7b]#[bg=#50fa7b,fg=#000000] %H:%M #[bg=default,fg=#50fa7b]"}'\'') + + if fc-list | grep -qi nerd; then \ + echo "$key_off $vi_segment"; \ + else \ + cat ~/.vi-mode | awk '\''/-- NORMAL --/ {print "#[fg=#50fa7b,bg=default] #[fg=#39BAE6] %H:%M "} \ + /-- INSERT --/ {print "#[fg=#39BAE6,bg=default] #[fg=#50fa7b] %H:%M "}'\''; \ + fi \ +)' + +# Force refresh after session creation +#set-hook -g after-new-session 'source-file ~/.tmux.conf' +#set-hook -g client-attached 'source-file ~/.tmux.conf' + + +# Set environment variable from script output +#run-shell 'tmux set-environment -g NERD_FONT_DETECTED "$(~/.config/tmux/detect_nerd_font)"' + +## Reload Status with IP addr, Cpu, Mem and Date +bind a run-shell ~/.config/tmux/tmux-toggle-option.sh + +## Numbers +bind < command-prompt -p index "run-shell '~/.config/tmux/tmux_number.sh %%'" + +## Reload Config/Status silently +bind b source-file ~/.config/tmux/tmux.conf + +set-option -g default-shell "/usr/bin/zsh" + + +#―――――――――――――――――――――――――――――――――――――――――― + +### Plugin Install ### + +set -g @plugin "tmux-plugins/tpm" +set -g @plugin "tmux-plugins/tmux-sensible" +set -g @plugin "tmux-plugins/tmux-resurrect" +set -g @plugin "tmux-plugins/tmux-continuum" +#set -g @plugin "loichyan/tmux-toggle-popup" +set -g @plugin "christoomey/vim-tmux-navigator" +#set -g @plugin "tmux-plugins/tmux-yank" +#set -g @plugin 'srdusr/tmux-vi-mode' +#set -g @plugin 'vi-mode ~/.config/tmux/plugins/vi-mode.sh' + + +set -g @plugin 'catppuccin/tmux' +set -g @plugin 'tmux-plugins/tmux-online-status' +set -g @plugin 'tmux-plugins/tmux-battery' + +#―――――――――――――――――――――――――――――――――――――――――― + +### Plugins Settings ### + +# Plugin to save and restore tmux sessions after restart +# * Save with: <Prefix> + Ctrl-s +# * Restore with: <Prefix> + Ctlr-r +# Change default save and restore keybindings + set -g @resurrect-save "W" # <Prefix> + W + set -g @resurrect-restore "E" # <Prefix> + E + +# Restore vim and nvim sessions as well +# For vim: + set -g @resurrect-strategy-vim "session" +# For neovim: + set -g @resurrect-strategy-nvim "session" + +# Automatic restore + #set -g @continuum-restore "on" + #set -g @continuum-boot "on" + +# Restore Panes +# set -g @resurrect-capture-pane-contents "on" + +# This is a hook for tmux-resurrect which tells it to kill session 0 before restoring the panels + set -g @resurrect-hook-pre-restore-pane-processes "tmux switch-client -n && tmux kill-session -t=0" + +# Tmux navigation + #set -g @plugin 'christoomey/vim-tmux-navigator' +# Plugin uninstall + # Delete or comment out the plugin in .tmux.conf. + # Press <prefix> + alt + u to remove the plugin. + +# >>>>> CATPPUCCIN CONFIGS <<<<< + +# Configure Catppuccin +set -g @catppuccin_flavor "mocha" +set -g @catppuccin_status_background "none" +set -g @catppuccin_window_status_style "none" +set -g @catppuccin_pane_status_enabled "off" +set -g @catppuccin_pane_border_status "off" + +# Configure Online status +set -g @online_icon "ok" +set -g @offline_icon "nok" + +# TMUX plugin manager (keep at the bottom of tmux.conf) + #run "~/.config/tmux/plugins/tpm/tpm" + if "test ! -d ~/.config/tmux/plugins/tpm" \ + "run 'git clone https://github.com/tmux-plugins/tpm ~/.config/tmux/plugins/tpm && ~/.config/tmux/plugins/tpm/bin/install_plugins'" +run -b "~/.config/tmux/plugins/tpm/tpm" diff --git a/linux/home/.config/tmux/tmux_number.sh b/linux/home/.config/tmux/tmux_number.sh new file mode 100755 index 0000000..5d239d0 --- /dev/null +++ b/linux/home/.config/tmux/tmux_number.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -x +dest="$1" +[ "x""$dest" != "x" ] +tmux list-windows -F "#{window_index}" | grep "^${dest}$" 2>&1 >/dev/null +ret="$?" +if [ "x""$ret" = "x0" ]; then + tmux swap-window -t ":${dest}" +else + tmux move-window -t ":${dest}" +fi 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": "‭ﭥ " // This stop symbol is RTL. So ‭ 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/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/.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 Binary files differnew file mode 100755 index 0000000..585d6d2 --- /dev/null +++ b/linux/home/.local/bin/eww 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/.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/autoload/statusline.vim b/linux/home/.vim/autoload/autoload/statusline.vim new file mode 100644 index 0000000..bf5f972 --- /dev/null +++ b/linux/home/.vim/autoload/autoload/statusline.vim @@ -0,0 +1,267 @@ +" statusline.vim + +if exists('g:loaded_statusline') | finish | endif +let g:loaded_statusline = 1 + +" --- Detect Nerd Fonts --- +function! s:HasNerdFonts() + if exists('g:statusline_nerd_fonts') + return g:statusline_nerd_fonts + endif + + if executable('fc-list') + let l:output = system('fc-list | grep -i nerd') + if len(split(l:output, '\n')) > 0 + return 1 + endif + endif + + return 0 +endfunction + +let g:statusline_has_nerd_fonts = s:HasNerdFonts() + +" --- Color Palette --- +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 = 'NONE' +let g:StslineColorDark3 = '#303030' + +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 + +" --- Highlight Groups --- +" Initial setup of highlight groups (will be updated by UpdateStslineColors) +execute 'highlight StslinePriColorBG guifg=' . g:StslineOnPriColor . ' guibg=' . g:StslinePriColor +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 +execute 'highlight StslinePriColorBG_SecColorBG guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor +execute 'highlight StslineModeSep guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor +execute 'highlight StslineGitSep guifg=' . g:StslineSecColor . ' guibg=' . g:StslineColorDark2 + +" --- Statusline Settings --- +if has('nvim') + set laststatus=3 +else + set laststatus=2 +endif + +"set noshowmode +"set termguicolors + +let space = '' + +" 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 ' + else + let g:StslinePriColor = g:StslineColorGreen + endif + + call autoload#statusline#UpdateStslineColors() + + return b:CurrentMode +endfunction + +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 StslineModeSep guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor + execute 'highlight StslineGitSep guifg=' . g:StslineSecColor . ' guibg=' . g:StslineColorDark2 + 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 + execute 'highlight StslinePriColorBG_SecColorBG guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor + execute 'highlight StslineSecColorFG guifg=' . g:StslineSecColor . ' guibg=' . g:StslineBackColor +endfunction + +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 icon = g:statusline_has_nerd_fonts ? ' ' : ' [git] ' + let b:GitBranch = icon . substitute(l:gitrevparse, '\n', '', 'g') . ' ' + endif + catch + endtry +endfunction + +function! autoload#statusline#GetFileType() abort + if !g:statusline_has_nerd_fonts + let b:FiletypeIcon = '' + return + endif + 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 ==# '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 ==# 'haskell' | let b:FiletypeIcon = ' ' + else | let b:FiletypeIcon = ' ' + endif +endfunction + +function! autoload#statusline#ActivateStatusline() abort + call autoload#statusline#GetFileType() + call autoload#statusline#GetGitBranch() " Ensure git branch is updated + + let current_mode_str = autoload#statusline#StslineMode() + call autoload#statusline#UpdateStslineColors() + + let readonly_icon = g:statusline_has_nerd_fonts ? ' ' : '[RO] ' + let modified_icon = g:statusline_has_nerd_fonts ? ' ' : '[+] ' + let git_sep = g:statusline_has_nerd_fonts ? '' : ' ' + let file_sep1 = g:statusline_has_nerd_fonts ? ' ' : ' ' + let file_sep2 = g:statusline_has_nerd_fonts ? '' : '' + + " Get dynamic parts as simple strings + let git_status_str = get(b:, "coc_git_status", get(b:, "GitBranch", "")) + let git_blame_str = get(b:, "coc_git_blame", "") + let filetype_icon_str = get(b:, "FiletypeIcon", "") + let file_encoding_str = '' + if &fenc != "utf-8" + let file_encoding_str = &fenc . ' ' + endif + + " Build the statusline as a static string + let l:statusline = '' + + let l:statusline .= '%#StslinePriColorBG# ' . current_mode_str . '' + let l:statusline .= '%#StslineModeSep#' . git_sep + let l:statusline .= '%#StslineSecColorBG#' . git_status_str . git_blame_str + let l:statusline .= '%#StslineGitSep#' . git_sep + + " File info (Readonly, Modified, Filename) + let l:statusline .= '%#StslinePriColorFG#' + if &readonly + let l:statusline .= readonly_icon + endif + let l:statusline .= ' %F ' + if &modified + let l:statusline .= modified_icon + endif + + " Right align everything after this + let l:statusline .= '%=' + + " Right side (Filetype, Encoding, Position) + let l:statusline .= '%#StslinePriColorFG# ' . filetype_icon_str . '%y' + let l:statusline .= '%#StslineSecColorFG#' . file_sep1 + "let l:statusline .= '%#StslineSecColorBG# ' . file_encoding_str + let l:statusline .= '%#StslinePriColorFGSecColorBG#' . file_sep2 + let l:statusline .= '%#StslinePriColorBG# %p%% %#StslinePriColorBGBold#%l%#StslinePriColorBG#/%L :%c ' + let l:statusline .= '%#StslineBackColorBG#' + + " Set the statusline for the current buffer + let &l:statusline = l:statusline +endfunction + +function! autoload#statusline#DeactivateStatusline() abort + let git_sep = g:statusline_has_nerd_fonts ? '' : '' + let readonly_icon = g:statusline_has_nerd_fonts ? ' ' : '[RO] ' + let modified_icon = g:statusline_has_nerd_fonts ? ' ' : '[+] ' + + " NOTE: This DeactivateStatusline function still uses %{} for dynamic parts. + " If you encounter general E518 or other issues related to %{} expressions, + " you will need to refactor this function to build a static string + " similar to how ActivateStatusline now does it. + if !exists("b:GitBranch") || b:GitBranch == '' + let statusline = + \ '%#StslineSecColorBG# INACTIVE ' . + \ '%{get(b:,"coc_git_statusline",b:GitBranch)}%{get(b:,"coc_git_blame","")}' . + \ '%#StslineBackColorFGSecColorBG#' . git_sep . + \ '%#StslineBackColorBG# %{&readonly?"' . readonly_icon . '":""}%F ' . + \ '%#StslineModColorFG#%{&modified?"' . modified_icon . '":""}' . + \ '%=%#StslineBackColorBG# %{b:FiletypeIcon}%{&filetype}' . + \ '%#StslineSecColorFGBackColorBG# | %p%% %l/%L :%c' + else + let statusline = + \ '%#StslineSecColorBG# %{get(b:,"coc_git_statusline",b:GitBranch)}%{get(b:,"coc_git_blame","")}' . + \ '%#StslineBackColorFGSecColorBG#' . git_sep . + \ '%#StslineBackColorBG# %{&readonly?"' . readonly_icon . '":""}%F ' . + \ '%#StslineModColorFG#%{&modified?"' . modified_icon . '":""}' . + \ '%=%#StslineBackColorBG# %{b:FiletypeIcon}%{&filetype}' . + \ '%#StslineSecColorFGBackColorBG# | %p%% %l/%L :%c' + endif + + execute 'setlocal statusline=' . substitute(statusline, '"', '\\"', 'g') +endfunction + +augroup StatuslineGit + autocmd! + autocmd BufEnter * call autoload#statusline#GetGitBranch() +augroup END + +augroup SetStsline + autocmd! + autocmd BufEnter,WinEnter * call autoload#statusline#ActivateStatusline() + autocmd ModeChanged * call autoload#statusline#ActivateStatusline() +augroup END + +augroup StatuslineAutoReload + autocmd! + autocmd BufWritePost statusline.vim source <afile> | call autoload#statusline#ActivateStatusline() +augroup END + +"call autoload#statusline#ActivateStatusline() diff --git a/linux/home/.vim/autoload/statusline.vim b/linux/home/.vim/autoload/statusline.vim new file mode 100644 index 0000000..bf5f972 --- /dev/null +++ b/linux/home/.vim/autoload/statusline.vim @@ -0,0 +1,267 @@ +" statusline.vim + +if exists('g:loaded_statusline') | finish | endif +let g:loaded_statusline = 1 + +" --- Detect Nerd Fonts --- +function! s:HasNerdFonts() + if exists('g:statusline_nerd_fonts') + return g:statusline_nerd_fonts + endif + + if executable('fc-list') + let l:output = system('fc-list | grep -i nerd') + if len(split(l:output, '\n')) > 0 + return 1 + endif + endif + + return 0 +endfunction + +let g:statusline_has_nerd_fonts = s:HasNerdFonts() + +" --- Color Palette --- +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 = 'NONE' +let g:StslineColorDark3 = '#303030' + +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 + +" --- Highlight Groups --- +" Initial setup of highlight groups (will be updated by UpdateStslineColors) +execute 'highlight StslinePriColorBG guifg=' . g:StslineOnPriColor . ' guibg=' . g:StslinePriColor +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 +execute 'highlight StslinePriColorBG_SecColorBG guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor +execute 'highlight StslineModeSep guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor +execute 'highlight StslineGitSep guifg=' . g:StslineSecColor . ' guibg=' . g:StslineColorDark2 + +" --- Statusline Settings --- +if has('nvim') + set laststatus=3 +else + set laststatus=2 +endif + +"set noshowmode +"set termguicolors + +let space = '' + +" 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 ' + else + let g:StslinePriColor = g:StslineColorGreen + endif + + call autoload#statusline#UpdateStslineColors() + + return b:CurrentMode +endfunction + +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 StslineModeSep guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor + execute 'highlight StslineGitSep guifg=' . g:StslineSecColor . ' guibg=' . g:StslineColorDark2 + 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 + execute 'highlight StslinePriColorBG_SecColorBG guifg=' . g:StslinePriColor . ' guibg=' . g:StslineSecColor + execute 'highlight StslineSecColorFG guifg=' . g:StslineSecColor . ' guibg=' . g:StslineBackColor +endfunction + +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 icon = g:statusline_has_nerd_fonts ? ' ' : ' [git] ' + let b:GitBranch = icon . substitute(l:gitrevparse, '\n', '', 'g') . ' ' + endif + catch + endtry +endfunction + +function! autoload#statusline#GetFileType() abort + if !g:statusline_has_nerd_fonts + let b:FiletypeIcon = '' + return + endif + 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 ==# '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 ==# 'haskell' | let b:FiletypeIcon = ' ' + else | let b:FiletypeIcon = ' ' + endif +endfunction + +function! autoload#statusline#ActivateStatusline() abort + call autoload#statusline#GetFileType() + call autoload#statusline#GetGitBranch() " Ensure git branch is updated + + let current_mode_str = autoload#statusline#StslineMode() + call autoload#statusline#UpdateStslineColors() + + let readonly_icon = g:statusline_has_nerd_fonts ? ' ' : '[RO] ' + let modified_icon = g:statusline_has_nerd_fonts ? ' ' : '[+] ' + let git_sep = g:statusline_has_nerd_fonts ? '' : ' ' + let file_sep1 = g:statusline_has_nerd_fonts ? ' ' : ' ' + let file_sep2 = g:statusline_has_nerd_fonts ? '' : '' + + " Get dynamic parts as simple strings + let git_status_str = get(b:, "coc_git_status", get(b:, "GitBranch", "")) + let git_blame_str = get(b:, "coc_git_blame", "") + let filetype_icon_str = get(b:, "FiletypeIcon", "") + let file_encoding_str = '' + if &fenc != "utf-8" + let file_encoding_str = &fenc . ' ' + endif + + " Build the statusline as a static string + let l:statusline = '' + + let l:statusline .= '%#StslinePriColorBG# ' . current_mode_str . '' + let l:statusline .= '%#StslineModeSep#' . git_sep + let l:statusline .= '%#StslineSecColorBG#' . git_status_str . git_blame_str + let l:statusline .= '%#StslineGitSep#' . git_sep + + " File info (Readonly, Modified, Filename) + let l:statusline .= '%#StslinePriColorFG#' + if &readonly + let l:statusline .= readonly_icon + endif + let l:statusline .= ' %F ' + if &modified + let l:statusline .= modified_icon + endif + + " Right align everything after this + let l:statusline .= '%=' + + " Right side (Filetype, Encoding, Position) + let l:statusline .= '%#StslinePriColorFG# ' . filetype_icon_str . '%y' + let l:statusline .= '%#StslineSecColorFG#' . file_sep1 + "let l:statusline .= '%#StslineSecColorBG# ' . file_encoding_str + let l:statusline .= '%#StslinePriColorFGSecColorBG#' . file_sep2 + let l:statusline .= '%#StslinePriColorBG# %p%% %#StslinePriColorBGBold#%l%#StslinePriColorBG#/%L :%c ' + let l:statusline .= '%#StslineBackColorBG#' + + " Set the statusline for the current buffer + let &l:statusline = l:statusline +endfunction + +function! autoload#statusline#DeactivateStatusline() abort + let git_sep = g:statusline_has_nerd_fonts ? '' : '' + let readonly_icon = g:statusline_has_nerd_fonts ? ' ' : '[RO] ' + let modified_icon = g:statusline_has_nerd_fonts ? ' ' : '[+] ' + + " NOTE: This DeactivateStatusline function still uses %{} for dynamic parts. + " If you encounter general E518 or other issues related to %{} expressions, + " you will need to refactor this function to build a static string + " similar to how ActivateStatusline now does it. + if !exists("b:GitBranch") || b:GitBranch == '' + let statusline = + \ '%#StslineSecColorBG# INACTIVE ' . + \ '%{get(b:,"coc_git_statusline",b:GitBranch)}%{get(b:,"coc_git_blame","")}' . + \ '%#StslineBackColorFGSecColorBG#' . git_sep . + \ '%#StslineBackColorBG# %{&readonly?"' . readonly_icon . '":""}%F ' . + \ '%#StslineModColorFG#%{&modified?"' . modified_icon . '":""}' . + \ '%=%#StslineBackColorBG# %{b:FiletypeIcon}%{&filetype}' . + \ '%#StslineSecColorFGBackColorBG# | %p%% %l/%L :%c' + else + let statusline = + \ '%#StslineSecColorBG# %{get(b:,"coc_git_statusline",b:GitBranch)}%{get(b:,"coc_git_blame","")}' . + \ '%#StslineBackColorFGSecColorBG#' . git_sep . + \ '%#StslineBackColorBG# %{&readonly?"' . readonly_icon . '":""}%F ' . + \ '%#StslineModColorFG#%{&modified?"' . modified_icon . '":""}' . + \ '%=%#StslineBackColorBG# %{b:FiletypeIcon}%{&filetype}' . + \ '%#StslineSecColorFGBackColorBG# | %p%% %l/%L :%c' + endif + + execute 'setlocal statusline=' . substitute(statusline, '"', '\\"', 'g') +endfunction + +augroup StatuslineGit + autocmd! + autocmd BufEnter * call autoload#statusline#GetGitBranch() +augroup END + +augroup SetStsline + autocmd! + autocmd BufEnter,WinEnter * call autoload#statusline#ActivateStatusline() + autocmd ModeChanged * call autoload#statusline#ActivateStatusline() +augroup END + +augroup StatuslineAutoReload + autocmd! + autocmd BufWritePost statusline.vim source <afile> | call autoload#statusline#ActivateStatusline() +augroup END + +"call autoload#statusline#ActivateStatusline() diff --git a/linux/home/.vim/colors/colors/colorscheme.vim b/linux/home/.vim/colors/colors/colorscheme.vim new file mode 100644 index 0000000..ce0526e --- /dev/null +++ b/linux/home/.vim/colors/colors/colorscheme.vim @@ -0,0 +1,247 @@ +" Vim Colorscheme +" Name: cherryblossom.vim +" Author: Luo Boming +" Version: 0.3 +" License: The MIT Licence + +"{{{ Pre-setting +let g:colors_name = expand('<sfile>:t:r') + +"hi clear +"if exists("syntax_on") +" syntax reset +"endif + +if ! exists("g:terminal_italics") + let g:terminal_italics = 0 +endif + +"if ! exists("g:switch_statusline_bg_in_insert") +" let g:switch_statusline_bg_in_insert = 0 +"endif + +if ! exists("g:spell_undercurl") + let g:spell_undercurl = 0 +endif + +"}}} +"{{{ Color Palette +" Color Entity +let s:black = { "gui": "#171717", "cterm": "16" } +let s:white = { "gui": "#EAE8E7", "cterm": "231" } + +let s:gray = { "gui": "#3a3f52", "cterm": "247" } + +let s:green = { "gui": "#30B536", "cterm": "34" } +let s:pink = { "gui": "#D36DD3", "cterm": "170" } +let s:orange = { "gui": "#FC923F", "cterm": "208" } +let s:purple = { "gui": "#B586E7", "cterm": "141" } +let s:light_cyan = { "gui": "#D7FFFF", "cterm": "195" } +let s:dark_cyan = { "gui": "#00AF87", "cterm": "36" } +let s:ultramarine = { "gui": "#229EC0", "cterm": "38" } +let s:skyblue = { "gui": "#9BE7F8", "cterm": "195" } + +let s:white_pink = { "gui": "#FEF7FE", "cterm": "231" } +let s:white_pink_deep = { "gui": "#FEF0FE", "cterm": "255" } +let s:black_green = { "gui": "#053703", "cterm": "235" } +let s:black_green_bright = { "gui": "#074005", "cterm": "239" } +let s:middle_gray = { "gui": "#8a8a8a", "cterm": "245" } + +let s:light_gray = { "gui": "#E1DCDA", "cterm": "253" } +let s:light_green = { "gui": "#B7EFA5", "cterm": "157" } +let s:light_pink = { "gui": "#FEDCFE", "cterm": "225" } +let s:light_yellow = { "gui": "#EDE682", "cterm": "228" } +let s:light_red = { "gui": "#EB5A7C", "cterm": "204" } + +let s:dark_gray = { "gui": "#4D4A48", "cterm": "241" } +let s:dark_green = { "gui": "#09570A", "cterm": "22" } +let s:dark_yellow = { "gui": "#BC922B", "cterm": "3" } +let s:dark_pink = { "gui": "#B365A2", "cterm": "133" } +let s:dark_red = { "gui": "#D9372D", "cterm": "160" } +let s:NONE = { "gui": "NONE", "cterm": "NONE" } + +" Color Alias +if &background == "light" + let s:norm = s:black + let s:bg = s:NONE + let s:bg_subtle = s:white_pink_deep + let s:gray_fg = s:middle_gray + let s:green_fg = s:green + let s:yellow_fg = s:dark_yellow + let s:pink_fg = s:dark_pink + let s:cyan_fg = s:dark_cyan + let s:blue_fg = s:ultramarine + let s:red_fg = s:dark_red + let s:gray_bg = s:light_gray + let s:green_bg = s:light_green + let s:yellow_bg = s:light_yellow + let s:pink_bg = s:light_pink + let s:cyan_bg = s:light_cyan + let s:blue_bg = s:skyblue + let s:red_bg = s:light_red +endif + +if &background == "dark" + let s:norm = s:white + let s:bg = s:NONE + let s:bg_subtle = s:gray + let s:gray_fg = s:middle_gray + let s:green_fg = s:light_green + let s:yellow_fg = s:light_yellow + let s:pink_fg = s:light_pink + let s:cyan_fg = s:light_cyan + let s:blue_fg = s:skyblue + let s:red_fg = s:light_red + let s:gray_bg = s:dark_gray + let s:green_bg = s:green + let s:yellow_bg = s:dark_yellow + let s:pink_bg = s:pink + let s:cyan_bg = s:dark_cyan + let s:blue_bg = s:ultramarine + let s:red_bg = s:dark_red +endif +"}}} +"{{{ Highlight Function +" shamelessly stolen from pencil: https://github.com/reedes/vim-colors-pencil +function! s:hi(group, style) + if g:terminal_italics == 0 + if has_key(a:style, "cterm") && a:style["cterm"] == "italic" + unlet a:style.cterm + endif + if has_key(a:style, "term") && a:style["term"] == "italic" + unlet a:style.term + endif + endif + execute "highlight" a:group + \ "guifg=" (has_key(a:style, "fg") ? a:style.fg.gui : "NONE") + \ "guibg=" (has_key(a:style, "bg") ? a:style.bg.gui : "NONE") + \ "guisp=" (has_key(a:style, "sp") ? a:style.sp.gui : "NONE") + \ "gui=" (has_key(a:style, "gui") ? a:style.gui : "NONE") + \ "ctermfg=" (has_key(a:style, "fg") ? a:style.fg.cterm : "NONE") + \ "ctermbg=" (has_key(a:style, "bg") ? a:style.bg.cterm : "NONE") + \ "cterm=" (has_key(a:style, "cterm") ? a:style.cterm : "NONE") + \ "term=" (has_key(a:style, "term") ? a:style.term : "NONE") +endfunction + +if g:spell_undercurl == 1 + let s:attr_un = 'undercurl' +else + let s:attr_un = 'underline' +endif + +"}}} +"{{{ Common Highlighting +call s:hi("Normal", {"fg": s:norm, "bg": s:bg}) +call s:hi("Cursor", {}) +call s:hi("Comment", {"fg": s:gray_fg, "gui": "italic", "cterm": "italic", "term": "italic"}) + +call s:hi("Constant", {"fg": s:pink_fg}) +hi! link String Constant +hi! link Character Constant +hi! link Number Constant +hi! link Boolean Constant +hi! link Float Constant + +call s:hi("Identifier", {"fg": s:red_fg}) +hi! link Function Identifier + +call s:hi("Statement", {"fg": s:green_fg}) +hi! link Conditonal Statement +hi! link Repeat Statement +hi! link Label Statement +hi! link Operator Statement +hi! link Keyword Statement +hi! link Exception Statement + +call s:hi("PreProc", {"fg": s:blue_fg}) +hi! link Include PreProc +hi! link Define PreProc +hi! link Macro PreProc +hi! link PreCondit PreProc + +call s:hi("Type", {"fg": s:yellow_fg}) +hi! link StorageClass Type +hi! link Structure Type +hi! link Typedef Type + +call s:hi("Special", {"fg": s:orange}) +hi! link SpecialChar Special +hi! link Tag Special +hi! link Delimiter Special +hi! link SpecialComment Special +hi! link Debug Special + +call s:hi("Underlined", {"gui": "underline", "cterm": "underline"}) +call s:hi("Ignore", {"fg": s:bg_subtle}) +call s:hi("Error", {"fg": s:white, "bg": s:red_fg , "gui": "bold", "cterm": "bold"}) +call s:hi("Todo", {"bg": s:yellow_bg, "gui": "bold", "cterm": "bold"}) + +"}}} +"{{{ Semi-Common Highlighting +call s:hi("SpecialKey", {"fg": s:purple, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("NonText", {"fg": s:cyan_bg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("Directory", {"fg": s:blue_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("ErrorMsg", {"fg": s:red_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("IncSearch", {"gui": "reverse", "cterm": "reverse", "term": "reverse"}) +call s:hi("Search", {"fg": s:norm, "bg": s:pink_bg}) +call s:hi("MoreMsg", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("ModeMsg", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("LineNr", {"fg": s:gray}) +call s:hi("CursorLineNr", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("Question", {"fg": s:purple, "gui": "bold", "cterm": "bold", "term": "bold"}) +"call s:hi("StatusLine", {"fg": s:norm, "bg": s:green_bg, "gui": "bold", "cterm": "bold", "term": "bold"}) +"call s:hi("StatusLineNC", {"fg": s:norm, "bg": s:gray_bg}) +call s:hi("Conceal", {"fg": s:yellow_fg}) +call s:hi("VertSplit", {"gui": "reverse", "cterm": "reverse", "term": "reverse"}) +call s:hi("Title", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("Visual", {"gui": "reverse", "cterm": "reverse", "term": "reverse"}) +call s:hi("VisualNOS", {"gui": "bold,underline", "cterm": "bold,underline", "term": "bold,underline"}) +call s:hi("WarningMsg", {"fg": s:orange, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("WildMenu", {"fg": s:norm, "bg": s:blue_bg}) +call s:hi("Folded", {"fg": s:green_fg, "bg": s:gray_bg}) +call s:hi("FoldColumn", {"fg": s:green_fg, "bg": s:gray_bg}) +call s:hi("DiffAdd", {"bg": s:green_bg}) +call s:hi("DiffChange", {"bg": s:yellow_bg}) +call s:hi("DiffDelete", {"bg": s:red_bg}) +call s:hi("DiffText", {"bg": s:blue_bg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("SignColumn", {"fg": s:green_fg, "bg": s:gray}) +if has("gui_running") + call s:hi("SpellBad", {"gui": s:attr_un, "sp": s:red_bg}) + call s:hi("SpellCap", {"gui": s:attr_un, "sp": s:yellow_bg}) + call s:hi("SpellRare", {"gui": s:attr_un, "sp": s:blue_bg}) + call s:hi("SpellLocal", {"gui": s:attr_un, "sp": s:green_bg}) +else + call s:hi("SpellBad", {"cterm": s:attr_un, "fg": s:red_fg}) + call s:hi("SpellCap", {"cterm": s:attr_un, "fg": s:yellow_fg}) + call s:hi("SpellRare", {"cterm": s:attr_un, "fg": s:blue_fg}) + call s:hi("SpellLocal", {"cterm": s:attr_un, "fg": s:green_fg}) +endif +call s:hi("Pmenu", {"bg": s:gray_bg}) +call s:hi("PmenuSel", {"bg": s:pink_bg}) +call s:hi("PmenuSbar", {"bg": s:gray_bg}) +call s:hi("PmenuThumb", {"bg": s:gray_bg}) +call s:hi("TabLine", {"bg": s:bg_subtle}) +call s:hi("TabLineSel", {"bg": s:pink_bg}) +call s:hi("TabLineFill", {"bg": s:bg_subtle}) +call s:hi("CursorColumn", {"bg": s:yellow_fg}) +call s:hi("CursorLine", {"bg": s:bg_subtle}) +call s:hi("ColorColumn", {"bg": s:bg_subtle}) +call s:hi("MatchParen", {"fg": s:pink_fg, "gui": "underline", "cterm": "underline"}) +call s:hi("qfLineNr", {"fg": s:gray}) + +"}}} +""{{{ Switching StatusLine bg +"function! s:changebg(group, color) +" execute "highlight" a:group "guibg=" a:color.gui "ctermbg=" a:color.cterm +"endfunction +" +"if g:switch_statusline_bg_in_insert == 1 +" "" Change Color when entering Insert Mode +" autocmd InsertEnter * call s:changebg("StatusLine", s:pink_bg) +" "" Revert Color to default when leaving Insert Mode +" autocmd InsertLeave * call s:changebg("StatusLine", s:green_bg) +"endif + +"}}} +" vim: set foldmethod=marker: + diff --git a/linux/home/.vim/colors/colors/default.vim b/linux/home/.vim/colors/colors/default.vim new file mode 100644 index 0000000..ebc66e8 --- /dev/null +++ b/linux/home/.vim/colors/colors/default.vim @@ -0,0 +1,175 @@ +"{{{ Pre-setting +let g:colors_name = expand('<sfile>:t:r') + +if ! exists("g:terminal_italics") + let g:terminal_italics = 0 +endif + +if ! exists("g:spell_undercurl") + let g:spell_undercurl = 0 +endif +"}}} + +"{{{ Color Palette (updated to match official Vim default colors) +" Note: Hex colors chosen to reflect official Vim default colorscheme + +let s:black = { "gui": "#171717", "cterm": "16" } +let s:white = { "gui": "#EAE8E7", "cterm": "231" } +let s:gray = { "gui": "#808080", "cterm": "244" } + +" Reds +let s:red_fg = { "gui": "#FFFFFF", "cterm": "231" } " White fg on red bg for errors +let s:red_bg = { "gui": "#A40000", "cterm": "52" } " DarkRed bg (ErrorMsg bg) + +" Blues and Cyan +let s:blue_fg = { "gui": "#6A5ACD", "cterm": "60" } " SlateBlue +let s:dark_cyan = { "gui": "#008B8B", "cterm": "36" } " DarkCyan +let s:cyan_bg = { "gui": "#00CED1", "cterm": "38" } " DarkTurquoise + +" Greens +let s:green_fg = { "gui": "#008000", "cterm": "22" } " DarkGreen +let s:green_bg = { "gui": "#90EE90", "cterm": "120" } " LightGreen + +" Yellows and Oranges +let s:yellow_fg = { "gui": "#A52A2A", "cterm": "94" } " Brown (used in Vim default) +let s:yellow_bg = { "gui": "#FFFF00", "cterm": "226" } " Yellow bg + +let s:orange = { "gui": "#FFA500", "cterm": "214" } " Orange + +" Purples +let s:purple = { "gui": "#6A0DAD", "cterm": "90" } " DarkMagenta + +" Grays +let s:light_gray = { "gui": "#D3D3D3", "cterm": "252" } +let s:dark_gray = { "gui": "#4D4D4D", "cterm": "240" } + +" No color +let s:NONE = { "gui": "NONE", "cterm": "NONE" } + +" Alias for Normal fg and background depending on background setting +if &background == "light" + let s:norm = s:black + let s:bg = s:NONE + let s:bg_subtle = s:light_gray + let s:gray_fg = s:gray + let s:green_fg = s:green_fg + let s:yellow_fg = s:yellow_fg + let s:pink_fg = s:purple + let s:cyan_fg = s:dark_cyan + let s:blue_fg = s:blue_fg + let s:red_fg = s:red_bg + let s:gray_bg = s:light_gray + let s:green_bg = s:green_bg + let s:yellow_bg = s:yellow_bg + let s:pink_bg = s:orange + let s:cyan_bg = s:cyan_bg + let s:blue_bg = s:blue_fg + let s:red_bg = s:red_bg +else + let s:norm = s:white + let s:bg = s:NONE + let s:bg_subtle = s:dark_gray + let s:gray_fg = s:gray + let s:green_fg = s:green_bg + let s:yellow_fg = s:yellow_bg + let s:pink_fg = s:orange + let s:cyan_fg = s:cyan_bg + let s:blue_fg = s:blue_bg + let s:red_fg = s:red_bg + let s:gray_bg = s:dark_gray + let s:green_bg = s:green_fg + let s:yellow_bg = s:yellow_fg + let s:pink_bg = s:purple + let s:cyan_bg = s:dark_cyan + let s:blue_bg = s:blue_fg + let s:red_bg = s:red_bg +endif +"}}} + +"{{{ Highlight Function (keep your existing function) +function! s:hi(group, style) + if g:terminal_italics == 0 + if has_key(a:style, "cterm") && a:style["cterm"] == "italic" + unlet a:style.cterm + endif + if has_key(a:style, "term") && a:style["term"] == "italic" + unlet a:style.term + endif + endif + execute "highlight" a:group + \ "guifg=" (has_key(a:style, "fg") ? a:style.fg.gui : "NONE") + \ "guibg=" (has_key(a:style, "bg") ? a:style.bg.gui : "NONE") + \ "guisp=" (has_key(a:style, "sp") ? a:style.sp.gui : "NONE") + \ "gui=" (has_key(a:style, "gui") ? a:style.gui : "NONE") + \ "ctermfg=" (has_key(a:style, "fg") ? a:style.fg.cterm : "NONE") + \ "ctermbg=" (has_key(a:style, "bg") ? a:style.bg.cterm : "NONE") + \ "cterm=" (has_key(a:style, "cterm") ? a:style.cterm : "NONE") + \ "term=" (has_key(a:style, "term") ? a:style.term : "NONE") +endfunction + +if g:spell_undercurl == 1 + let s:attr_un = 'undercurl' +else + let s:attr_un = 'underline' +endif +"}}} + +"{{{ Common Highlighting updated to match official Vim default colorscheme + +call s:hi("Normal", {"fg": s:norm, "bg": s:bg}) +call s:hi("Cursor", {}) +call s:hi("Conceal", {"fg": s:yellow_fg}) +call s:hi("ErrorMsg", {"fg": s:red_fg, "bg": s:red_bg, "gui": "bold", "cterm": "bold"}) +call s:hi("IncSearch", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("ModeMsg", {"gui": "bold", "cterm": "bold"}) +call s:hi("NonText", {"fg": s:blue_fg, "gui": "bold", "cterm": "bold"}) +call s:hi("PmenuSbar", {"bg": s:gray_bg}) +call s:hi("StatusLine", {"gui": "reverse,bold", "cterm": "reverse,bold"}) +call s:hi("StatusLineNC", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("TabLineFill", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("TabLineSel", {"gui": "bold", "cterm": "bold"}) +call s:hi("TermCursor", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("WinBar", {"gui": "bold", "cterm": "bold"}) +call s:hi("WildMenu", {"fg": s:black, "bg": s:yellow_bg}) + +call s:hi("VertSplit", {"link": "Normal"}) +call s:hi("WinSeparator", {"link": "VertSplit"}) +call s:hi("WinBarNC", {"link": "WinBar"}) +call s:hi("DiffTextAdd", {"link": "DiffText"}) +call s:hi("EndOfBuffer", {"link": "NonText"}) +call s:hi("LineNrAbove", {"link": "LineNr"}) +call s:hi("LineNrBelow", {"link": "LineNr"}) +call s:hi("QuickFixLine", {"link": "Search"}) +call s:hi("CursorLineSign", {"link": "SignColumn"}) +call s:hi("CursorLineFold", {"link": "FoldColumn"}) +call s:hi("CurSearch", {"link": "Search"}) +call s:hi("PmenuKind", {"link": "Pmenu"}) +call s:hi("PmenuKindSel", {"link": "PmenuSel"}) +call s:hi("PmenuMatch", {"link": "Pmenu"}) +call s:hi("PmenuMatchSel", {"link": "PmenuSel"}) +call s:hi("PmenuExtra", {"link": "Pmenu"}) +call s:hi("PmenuExtraSel", {"link": "PmenuSel"}) +call s:hi("ComplMatchIns", {}) +call s:hi("Substitute", {"link": "Search"}) +call s:hi("Whitespace", {"link": "NonText"}) +call s:hi("MsgSeparator", {"link": "StatusLine"}) +call s:hi("NormalFloat", {"link": "Pmenu"}) +call s:hi("FloatBorder", {"link": "WinSeparator"}) +call s:hi("FloatTitle", {"link": "Title"}) +call s:hi("FloatFooter", {"link": "Title"}) + +call s:hi("Error", {"fg": s:red_fg, "bg": s:red_bg, "gui": "bold", "cterm": "bold"}) +call s:hi("Todo", {"fg": s:black, "bg": s:yellow_bg, "gui": "bold", "cterm": "bold"}) + +call s:hi("String", {"link": "Constant"}) +call s:hi("Character", {"link": "Constant"}) +call s:hi("Number", {"link": "Constant"}) +call s:hi("Boolean", {"link": "Constant"}) +call s:hi("Float", {"link": "Number"}) +call s:hi("Function", {"link": "Identifier"}) +call s:hi("Conditional", {"link": "Statement"}) +call s:hi("Repeat", {"link": "Statement"}) +call s:hi("Label", {"link": "Statement"}) +call s:hi("Operator", {"link": "Statement"}) +call s:hi("Keyword", {"link": "Statement"}) +call s:hi("Exception", diff --git a/linux/home/.vim/colors/colorscheme.vim b/linux/home/.vim/colors/colorscheme.vim new file mode 100644 index 0000000..ce0526e --- /dev/null +++ b/linux/home/.vim/colors/colorscheme.vim @@ -0,0 +1,247 @@ +" Vim Colorscheme +" Name: cherryblossom.vim +" Author: Luo Boming +" Version: 0.3 +" License: The MIT Licence + +"{{{ Pre-setting +let g:colors_name = expand('<sfile>:t:r') + +"hi clear +"if exists("syntax_on") +" syntax reset +"endif + +if ! exists("g:terminal_italics") + let g:terminal_italics = 0 +endif + +"if ! exists("g:switch_statusline_bg_in_insert") +" let g:switch_statusline_bg_in_insert = 0 +"endif + +if ! exists("g:spell_undercurl") + let g:spell_undercurl = 0 +endif + +"}}} +"{{{ Color Palette +" Color Entity +let s:black = { "gui": "#171717", "cterm": "16" } +let s:white = { "gui": "#EAE8E7", "cterm": "231" } + +let s:gray = { "gui": "#3a3f52", "cterm": "247" } + +let s:green = { "gui": "#30B536", "cterm": "34" } +let s:pink = { "gui": "#D36DD3", "cterm": "170" } +let s:orange = { "gui": "#FC923F", "cterm": "208" } +let s:purple = { "gui": "#B586E7", "cterm": "141" } +let s:light_cyan = { "gui": "#D7FFFF", "cterm": "195" } +let s:dark_cyan = { "gui": "#00AF87", "cterm": "36" } +let s:ultramarine = { "gui": "#229EC0", "cterm": "38" } +let s:skyblue = { "gui": "#9BE7F8", "cterm": "195" } + +let s:white_pink = { "gui": "#FEF7FE", "cterm": "231" } +let s:white_pink_deep = { "gui": "#FEF0FE", "cterm": "255" } +let s:black_green = { "gui": "#053703", "cterm": "235" } +let s:black_green_bright = { "gui": "#074005", "cterm": "239" } +let s:middle_gray = { "gui": "#8a8a8a", "cterm": "245" } + +let s:light_gray = { "gui": "#E1DCDA", "cterm": "253" } +let s:light_green = { "gui": "#B7EFA5", "cterm": "157" } +let s:light_pink = { "gui": "#FEDCFE", "cterm": "225" } +let s:light_yellow = { "gui": "#EDE682", "cterm": "228" } +let s:light_red = { "gui": "#EB5A7C", "cterm": "204" } + +let s:dark_gray = { "gui": "#4D4A48", "cterm": "241" } +let s:dark_green = { "gui": "#09570A", "cterm": "22" } +let s:dark_yellow = { "gui": "#BC922B", "cterm": "3" } +let s:dark_pink = { "gui": "#B365A2", "cterm": "133" } +let s:dark_red = { "gui": "#D9372D", "cterm": "160" } +let s:NONE = { "gui": "NONE", "cterm": "NONE" } + +" Color Alias +if &background == "light" + let s:norm = s:black + let s:bg = s:NONE + let s:bg_subtle = s:white_pink_deep + let s:gray_fg = s:middle_gray + let s:green_fg = s:green + let s:yellow_fg = s:dark_yellow + let s:pink_fg = s:dark_pink + let s:cyan_fg = s:dark_cyan + let s:blue_fg = s:ultramarine + let s:red_fg = s:dark_red + let s:gray_bg = s:light_gray + let s:green_bg = s:light_green + let s:yellow_bg = s:light_yellow + let s:pink_bg = s:light_pink + let s:cyan_bg = s:light_cyan + let s:blue_bg = s:skyblue + let s:red_bg = s:light_red +endif + +if &background == "dark" + let s:norm = s:white + let s:bg = s:NONE + let s:bg_subtle = s:gray + let s:gray_fg = s:middle_gray + let s:green_fg = s:light_green + let s:yellow_fg = s:light_yellow + let s:pink_fg = s:light_pink + let s:cyan_fg = s:light_cyan + let s:blue_fg = s:skyblue + let s:red_fg = s:light_red + let s:gray_bg = s:dark_gray + let s:green_bg = s:green + let s:yellow_bg = s:dark_yellow + let s:pink_bg = s:pink + let s:cyan_bg = s:dark_cyan + let s:blue_bg = s:ultramarine + let s:red_bg = s:dark_red +endif +"}}} +"{{{ Highlight Function +" shamelessly stolen from pencil: https://github.com/reedes/vim-colors-pencil +function! s:hi(group, style) + if g:terminal_italics == 0 + if has_key(a:style, "cterm") && a:style["cterm"] == "italic" + unlet a:style.cterm + endif + if has_key(a:style, "term") && a:style["term"] == "italic" + unlet a:style.term + endif + endif + execute "highlight" a:group + \ "guifg=" (has_key(a:style, "fg") ? a:style.fg.gui : "NONE") + \ "guibg=" (has_key(a:style, "bg") ? a:style.bg.gui : "NONE") + \ "guisp=" (has_key(a:style, "sp") ? a:style.sp.gui : "NONE") + \ "gui=" (has_key(a:style, "gui") ? a:style.gui : "NONE") + \ "ctermfg=" (has_key(a:style, "fg") ? a:style.fg.cterm : "NONE") + \ "ctermbg=" (has_key(a:style, "bg") ? a:style.bg.cterm : "NONE") + \ "cterm=" (has_key(a:style, "cterm") ? a:style.cterm : "NONE") + \ "term=" (has_key(a:style, "term") ? a:style.term : "NONE") +endfunction + +if g:spell_undercurl == 1 + let s:attr_un = 'undercurl' +else + let s:attr_un = 'underline' +endif + +"}}} +"{{{ Common Highlighting +call s:hi("Normal", {"fg": s:norm, "bg": s:bg}) +call s:hi("Cursor", {}) +call s:hi("Comment", {"fg": s:gray_fg, "gui": "italic", "cterm": "italic", "term": "italic"}) + +call s:hi("Constant", {"fg": s:pink_fg}) +hi! link String Constant +hi! link Character Constant +hi! link Number Constant +hi! link Boolean Constant +hi! link Float Constant + +call s:hi("Identifier", {"fg": s:red_fg}) +hi! link Function Identifier + +call s:hi("Statement", {"fg": s:green_fg}) +hi! link Conditonal Statement +hi! link Repeat Statement +hi! link Label Statement +hi! link Operator Statement +hi! link Keyword Statement +hi! link Exception Statement + +call s:hi("PreProc", {"fg": s:blue_fg}) +hi! link Include PreProc +hi! link Define PreProc +hi! link Macro PreProc +hi! link PreCondit PreProc + +call s:hi("Type", {"fg": s:yellow_fg}) +hi! link StorageClass Type +hi! link Structure Type +hi! link Typedef Type + +call s:hi("Special", {"fg": s:orange}) +hi! link SpecialChar Special +hi! link Tag Special +hi! link Delimiter Special +hi! link SpecialComment Special +hi! link Debug Special + +call s:hi("Underlined", {"gui": "underline", "cterm": "underline"}) +call s:hi("Ignore", {"fg": s:bg_subtle}) +call s:hi("Error", {"fg": s:white, "bg": s:red_fg , "gui": "bold", "cterm": "bold"}) +call s:hi("Todo", {"bg": s:yellow_bg, "gui": "bold", "cterm": "bold"}) + +"}}} +"{{{ Semi-Common Highlighting +call s:hi("SpecialKey", {"fg": s:purple, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("NonText", {"fg": s:cyan_bg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("Directory", {"fg": s:blue_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("ErrorMsg", {"fg": s:red_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("IncSearch", {"gui": "reverse", "cterm": "reverse", "term": "reverse"}) +call s:hi("Search", {"fg": s:norm, "bg": s:pink_bg}) +call s:hi("MoreMsg", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("ModeMsg", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("LineNr", {"fg": s:gray}) +call s:hi("CursorLineNr", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("Question", {"fg": s:purple, "gui": "bold", "cterm": "bold", "term": "bold"}) +"call s:hi("StatusLine", {"fg": s:norm, "bg": s:green_bg, "gui": "bold", "cterm": "bold", "term": "bold"}) +"call s:hi("StatusLineNC", {"fg": s:norm, "bg": s:gray_bg}) +call s:hi("Conceal", {"fg": s:yellow_fg}) +call s:hi("VertSplit", {"gui": "reverse", "cterm": "reverse", "term": "reverse"}) +call s:hi("Title", {"fg": s:pink_fg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("Visual", {"gui": "reverse", "cterm": "reverse", "term": "reverse"}) +call s:hi("VisualNOS", {"gui": "bold,underline", "cterm": "bold,underline", "term": "bold,underline"}) +call s:hi("WarningMsg", {"fg": s:orange, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("WildMenu", {"fg": s:norm, "bg": s:blue_bg}) +call s:hi("Folded", {"fg": s:green_fg, "bg": s:gray_bg}) +call s:hi("FoldColumn", {"fg": s:green_fg, "bg": s:gray_bg}) +call s:hi("DiffAdd", {"bg": s:green_bg}) +call s:hi("DiffChange", {"bg": s:yellow_bg}) +call s:hi("DiffDelete", {"bg": s:red_bg}) +call s:hi("DiffText", {"bg": s:blue_bg, "gui": "bold", "cterm": "bold", "term": "bold"}) +call s:hi("SignColumn", {"fg": s:green_fg, "bg": s:gray}) +if has("gui_running") + call s:hi("SpellBad", {"gui": s:attr_un, "sp": s:red_bg}) + call s:hi("SpellCap", {"gui": s:attr_un, "sp": s:yellow_bg}) + call s:hi("SpellRare", {"gui": s:attr_un, "sp": s:blue_bg}) + call s:hi("SpellLocal", {"gui": s:attr_un, "sp": s:green_bg}) +else + call s:hi("SpellBad", {"cterm": s:attr_un, "fg": s:red_fg}) + call s:hi("SpellCap", {"cterm": s:attr_un, "fg": s:yellow_fg}) + call s:hi("SpellRare", {"cterm": s:attr_un, "fg": s:blue_fg}) + call s:hi("SpellLocal", {"cterm": s:attr_un, "fg": s:green_fg}) +endif +call s:hi("Pmenu", {"bg": s:gray_bg}) +call s:hi("PmenuSel", {"bg": s:pink_bg}) +call s:hi("PmenuSbar", {"bg": s:gray_bg}) +call s:hi("PmenuThumb", {"bg": s:gray_bg}) +call s:hi("TabLine", {"bg": s:bg_subtle}) +call s:hi("TabLineSel", {"bg": s:pink_bg}) +call s:hi("TabLineFill", {"bg": s:bg_subtle}) +call s:hi("CursorColumn", {"bg": s:yellow_fg}) +call s:hi("CursorLine", {"bg": s:bg_subtle}) +call s:hi("ColorColumn", {"bg": s:bg_subtle}) +call s:hi("MatchParen", {"fg": s:pink_fg, "gui": "underline", "cterm": "underline"}) +call s:hi("qfLineNr", {"fg": s:gray}) + +"}}} +""{{{ Switching StatusLine bg +"function! s:changebg(group, color) +" execute "highlight" a:group "guibg=" a:color.gui "ctermbg=" a:color.cterm +"endfunction +" +"if g:switch_statusline_bg_in_insert == 1 +" "" Change Color when entering Insert Mode +" autocmd InsertEnter * call s:changebg("StatusLine", s:pink_bg) +" "" Revert Color to default when leaving Insert Mode +" autocmd InsertLeave * call s:changebg("StatusLine", s:green_bg) +"endif + +"}}} +" vim: set foldmethod=marker: + diff --git a/linux/home/.vim/colors/default.vim b/linux/home/.vim/colors/default.vim new file mode 100644 index 0000000..ebc66e8 --- /dev/null +++ b/linux/home/.vim/colors/default.vim @@ -0,0 +1,175 @@ +"{{{ Pre-setting +let g:colors_name = expand('<sfile>:t:r') + +if ! exists("g:terminal_italics") + let g:terminal_italics = 0 +endif + +if ! exists("g:spell_undercurl") + let g:spell_undercurl = 0 +endif +"}}} + +"{{{ Color Palette (updated to match official Vim default colors) +" Note: Hex colors chosen to reflect official Vim default colorscheme + +let s:black = { "gui": "#171717", "cterm": "16" } +let s:white = { "gui": "#EAE8E7", "cterm": "231" } +let s:gray = { "gui": "#808080", "cterm": "244" } + +" Reds +let s:red_fg = { "gui": "#FFFFFF", "cterm": "231" } " White fg on red bg for errors +let s:red_bg = { "gui": "#A40000", "cterm": "52" } " DarkRed bg (ErrorMsg bg) + +" Blues and Cyan +let s:blue_fg = { "gui": "#6A5ACD", "cterm": "60" } " SlateBlue +let s:dark_cyan = { "gui": "#008B8B", "cterm": "36" } " DarkCyan +let s:cyan_bg = { "gui": "#00CED1", "cterm": "38" } " DarkTurquoise + +" Greens +let s:green_fg = { "gui": "#008000", "cterm": "22" } " DarkGreen +let s:green_bg = { "gui": "#90EE90", "cterm": "120" } " LightGreen + +" Yellows and Oranges +let s:yellow_fg = { "gui": "#A52A2A", "cterm": "94" } " Brown (used in Vim default) +let s:yellow_bg = { "gui": "#FFFF00", "cterm": "226" } " Yellow bg + +let s:orange = { "gui": "#FFA500", "cterm": "214" } " Orange + +" Purples +let s:purple = { "gui": "#6A0DAD", "cterm": "90" } " DarkMagenta + +" Grays +let s:light_gray = { "gui": "#D3D3D3", "cterm": "252" } +let s:dark_gray = { "gui": "#4D4D4D", "cterm": "240" } + +" No color +let s:NONE = { "gui": "NONE", "cterm": "NONE" } + +" Alias for Normal fg and background depending on background setting +if &background == "light" + let s:norm = s:black + let s:bg = s:NONE + let s:bg_subtle = s:light_gray + let s:gray_fg = s:gray + let s:green_fg = s:green_fg + let s:yellow_fg = s:yellow_fg + let s:pink_fg = s:purple + let s:cyan_fg = s:dark_cyan + let s:blue_fg = s:blue_fg + let s:red_fg = s:red_bg + let s:gray_bg = s:light_gray + let s:green_bg = s:green_bg + let s:yellow_bg = s:yellow_bg + let s:pink_bg = s:orange + let s:cyan_bg = s:cyan_bg + let s:blue_bg = s:blue_fg + let s:red_bg = s:red_bg +else + let s:norm = s:white + let s:bg = s:NONE + let s:bg_subtle = s:dark_gray + let s:gray_fg = s:gray + let s:green_fg = s:green_bg + let s:yellow_fg = s:yellow_bg + let s:pink_fg = s:orange + let s:cyan_fg = s:cyan_bg + let s:blue_fg = s:blue_bg + let s:red_fg = s:red_bg + let s:gray_bg = s:dark_gray + let s:green_bg = s:green_fg + let s:yellow_bg = s:yellow_fg + let s:pink_bg = s:purple + let s:cyan_bg = s:dark_cyan + let s:blue_bg = s:blue_fg + let s:red_bg = s:red_bg +endif +"}}} + +"{{{ Highlight Function (keep your existing function) +function! s:hi(group, style) + if g:terminal_italics == 0 + if has_key(a:style, "cterm") && a:style["cterm"] == "italic" + unlet a:style.cterm + endif + if has_key(a:style, "term") && a:style["term"] == "italic" + unlet a:style.term + endif + endif + execute "highlight" a:group + \ "guifg=" (has_key(a:style, "fg") ? a:style.fg.gui : "NONE") + \ "guibg=" (has_key(a:style, "bg") ? a:style.bg.gui : "NONE") + \ "guisp=" (has_key(a:style, "sp") ? a:style.sp.gui : "NONE") + \ "gui=" (has_key(a:style, "gui") ? a:style.gui : "NONE") + \ "ctermfg=" (has_key(a:style, "fg") ? a:style.fg.cterm : "NONE") + \ "ctermbg=" (has_key(a:style, "bg") ? a:style.bg.cterm : "NONE") + \ "cterm=" (has_key(a:style, "cterm") ? a:style.cterm : "NONE") + \ "term=" (has_key(a:style, "term") ? a:style.term : "NONE") +endfunction + +if g:spell_undercurl == 1 + let s:attr_un = 'undercurl' +else + let s:attr_un = 'underline' +endif +"}}} + +"{{{ Common Highlighting updated to match official Vim default colorscheme + +call s:hi("Normal", {"fg": s:norm, "bg": s:bg}) +call s:hi("Cursor", {}) +call s:hi("Conceal", {"fg": s:yellow_fg}) +call s:hi("ErrorMsg", {"fg": s:red_fg, "bg": s:red_bg, "gui": "bold", "cterm": "bold"}) +call s:hi("IncSearch", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("ModeMsg", {"gui": "bold", "cterm": "bold"}) +call s:hi("NonText", {"fg": s:blue_fg, "gui": "bold", "cterm": "bold"}) +call s:hi("PmenuSbar", {"bg": s:gray_bg}) +call s:hi("StatusLine", {"gui": "reverse,bold", "cterm": "reverse,bold"}) +call s:hi("StatusLineNC", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("TabLineFill", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("TabLineSel", {"gui": "bold", "cterm": "bold"}) +call s:hi("TermCursor", {"gui": "reverse", "cterm": "reverse"}) +call s:hi("WinBar", {"gui": "bold", "cterm": "bold"}) +call s:hi("WildMenu", {"fg": s:black, "bg": s:yellow_bg}) + +call s:hi("VertSplit", {"link": "Normal"}) +call s:hi("WinSeparator", {"link": "VertSplit"}) +call s:hi("WinBarNC", {"link": "WinBar"}) +call s:hi("DiffTextAdd", {"link": "DiffText"}) +call s:hi("EndOfBuffer", {"link": "NonText"}) +call s:hi("LineNrAbove", {"link": "LineNr"}) +call s:hi("LineNrBelow", {"link": "LineNr"}) +call s:hi("QuickFixLine", {"link": "Search"}) +call s:hi("CursorLineSign", {"link": "SignColumn"}) +call s:hi("CursorLineFold", {"link": "FoldColumn"}) +call s:hi("CurSearch", {"link": "Search"}) +call s:hi("PmenuKind", {"link": "Pmenu"}) +call s:hi("PmenuKindSel", {"link": "PmenuSel"}) +call s:hi("PmenuMatch", {"link": "Pmenu"}) +call s:hi("PmenuMatchSel", {"link": "PmenuSel"}) +call s:hi("PmenuExtra", {"link": "Pmenu"}) +call s:hi("PmenuExtraSel", {"link": "PmenuSel"}) +call s:hi("ComplMatchIns", {}) +call s:hi("Substitute", {"link": "Search"}) +call s:hi("Whitespace", {"link": "NonText"}) +call s:hi("MsgSeparator", {"link": "StatusLine"}) +call s:hi("NormalFloat", {"link": "Pmenu"}) +call s:hi("FloatBorder", {"link": "WinSeparator"}) +call s:hi("FloatTitle", {"link": "Title"}) +call s:hi("FloatFooter", {"link": "Title"}) + +call s:hi("Error", {"fg": s:red_fg, "bg": s:red_bg, "gui": "bold", "cterm": "bold"}) +call s:hi("Todo", {"fg": s:black, "bg": s:yellow_bg, "gui": "bold", "cterm": "bold"}) + +call s:hi("String", {"link": "Constant"}) +call s:hi("Character", {"link": "Constant"}) +call s:hi("Number", {"link": "Constant"}) +call s:hi("Boolean", {"link": "Constant"}) +call s:hi("Float", {"link": "Number"}) +call s:hi("Function", {"link": "Identifier"}) +call s:hi("Conditional", {"link": "Statement"}) +call s:hi("Repeat", {"link": "Statement"}) +call s:hi("Label", {"link": "Statement"}) +call s:hi("Operator", {"link": "Statement"}) +call s:hi("Keyword", {"link": "Statement"}) +call s:hi("Exception", diff --git a/linux/home/.vim/ftplugin/after/vim.vim b/linux/home/.vim/ftplugin/after/vim.vim new file mode 100644 index 0000000..3548816 --- /dev/null +++ b/linux/home/.vim/ftplugin/after/vim.vim @@ -0,0 +1,12 @@ +" Enable Vim-specific options +setlocal tabstop=4 +setlocal shiftwidth=4 +setlocal softtabstop=4 +setlocal expandtab +setlocal foldmethod=marker +setlocal keywordprg=:help +setlocal iskeyword+=: + +" Spell-check off by default +setlocal nospell + diff --git a/linux/home/.vim/ftplugin/ftplugin/after/vim.vim b/linux/home/.vim/ftplugin/ftplugin/after/vim.vim new file mode 100644 index 0000000..3548816 --- /dev/null +++ b/linux/home/.vim/ftplugin/ftplugin/after/vim.vim @@ -0,0 +1,12 @@ +" Enable Vim-specific options +setlocal tabstop=4 +setlocal shiftwidth=4 +setlocal softtabstop=4 +setlocal expandtab +setlocal foldmethod=marker +setlocal keywordprg=:help +setlocal iskeyword+=: + +" Spell-check off by default +setlocal nospell + 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..5b0f444 --- /dev/null +++ b/linux/home/.vim/vimrc @@ -0,0 +1,700 @@ +" ============================================================================ +" Vim Configuration +" Maintainer: srdusr +" ============================================================================ + +" ============================================================================ +" Core Settings +" ============================================================================ +set nocompatible +set encoding=utf-8 +set fileencoding=utf-8 +scriptencoding utf-8 +set termguicolors +set mouse=a +set clipboard=unnamedplus +set hidden +set updatetime=300 +set timeoutlen=500 +set ttimeoutlen=10 + +" Performance +set ttyfast +set lazyredraw +set ttyscroll=3 + +" ============================================================================ +" Display and UI Settings +" ============================================================================ +set number +set relativenumber +set cursorline +set signcolumn=no +set showcmd +set showmode +set showmatch +set matchtime=2 +set laststatus=2 +set cmdheight=1 +set scrolloff=8 +set sidescrolloff=8 +set sidescroll=1 +set display=lastline +set nowrap +set linebreak +set showbreak=↪\ + +" Window behavior +set splitright +set splitbelow +set winminwidth=1 +set winwidth=5 + +" ============================================================================ +" Formatting and Indentation Settings +" ============================================================================ +set autoindent +set smartindent +set expandtab +set tabstop=2 +set shiftwidth=2 +set softtabstop=2 +set shiftround +set textwidth=80 +set formatoptions+=j +" set colorcolumn=+1 + +" File-specific formatting +setlocal tabstop=4 +setlocal shiftwidth=4 +setlocal softtabstop=4 +setlocal foldmethod=marker + +" ============================================================================ +" Search and Matching Settings +" ============================================================================ +set hlsearch +set incsearch +set ignorecase +set smartcase +set showmatch +" set inccommand=split + +" ============================================================================ +" File Handling and Backup Settings +" ============================================================================ +set autoread +set autowrite +set autochdir +set confirm +set fileformats=unix,dos,mac + +" Backup and undo configuration +set backup +set writebackup +set backupcopy=yes +set undofile +set noswapfile +set backupdir=~/.cache/vim/backup// +set directory=~/.cache/vim/swap// +set undodir=~/.cache/vim/undo// +set undolevels=10000 +set undoreload=10000 + +" Create necessary directories +let s:config_dir = expand('~/.vim') +let s:cache_dir = expand('~/.cache/vim') +let s:dirs = [ + \ s:cache_dir . '/backup', + \ s:cache_dir . '/swap', + \ s:cache_dir . '/undo', + \ s:cache_dir . '/shada', + \ s:config_dir . '/sessions', + \ ] + +for s:dir in s:dirs + if !isdirectory(s:dir) + call mkdir(s:dir, 'p', 0700) + endif +endfor + +" ============================================================================ +" Completion and Command Line Settings +" ============================================================================ +set omnifunc=syntaxcomplete#Complete +set complete=.,w,b,u,t,i,kspell +set completeopt=menu,menuone,noselect + +" Wildmenu configuration +set wildmenu +set wildmode=longest:full,full +set wildignorecase +set wildignore+=*.o,*.obj,.git,*.rbc,*.pyc,__pycache__ +set wildignore+=.git,.hg,.svn +set wildignore+=*.swp,*.swo +set wildignore+=*.DS_Store +set wildignore+=*.class + +" ============================================================================ +" Leader Keys +" ============================================================================ +let mapleader = ";" +let maplocalleader = "\\" + +" ============================================================================ +" Navigation and Movement Mappings +" ============================================================================ + +" Tmux/Vim Navigation Function +function! SmartMove(direction, tmux_flag) + let curwin = win_getid() + execute 'wincmd ' . a:direction + if win_getid() == curwin + call system('tmux select-pane ' . a:tmux_flag) + endif +endfunction + +" Window navigation +nnoremap <silent> <C-h> :call SmartMove('h', '-L')<CR> +nnoremap <silent> <C-j> :call SmartMove('j', '-D')<CR> +nnoremap <silent> <C-k> :call SmartMove('k', '-U')<CR> +nnoremap <silent> <C-l> :call SmartMove('l', '-R')<CR> + +" Split window horizontally +nnoremap <leader>- :split<CR> + +" Split window vertically +nnoremap <leader>\ :vsplit<CR> + +" Close the current window +nnoremap <leader>c <C-w>c + +" Buffer navigation +nnoremap <silent> <leader>bn :bnext<CR> +nnoremap <silent> <leader>bp :bprevious<CR> +nnoremap <silent> <leader>bd :bdelete<CR> +nnoremap <silent> <leader>ba :%bdelete<CR> +nnoremap <silent> <leader>bl :ls<CR>:b<Space> + +" Quickfix and location list +nnoremap ]q :cnext<CR>zz +nnoremap [q :cprev<CR>zz +nnoremap ]l :lnext<CR>zz +nnoremap [l :lprev<CR>zz + +" ============================================================================ +" File and Buffer Management Mappings +" ============================================================================ +nnoremap <silent> <leader>w :w<CR> +nnoremap <silent> <leader>q :q<CR> +nnoremap <silent> <leader>wq :wq<CR> +nnoremap <silent> <leader>Q :qa!<CR> + +" File operations +nnoremap <leader>f :Lex<CR> +noremap <leader>o :Explore<CR> +nnoremap <leader>rf :browse old<cr> + +" Utility mappings +nnoremap <silent> <leader>r :registers<CR> +nnoremap <silent> <leader>m :redir @+<CR>:silent messages<CR>:redir END<CR> +nnoremap <silent> <leader>hx :call HexState()<CR> +nnoremap <buffer> <leader>h :help <C-R><C-W><CR> + +" Format disable +cnoremap F! :noautocmd w<CR> + +" ============================================================================ +" Window and Terminal Mappings +" ============================================================================ + +" Window resizing +nnoremap <M-Up> :resize -2<CR> +noremap <M-Down> :resize +2<CR> +noremap <M-Left> :vertical resize -2<CR> +noremap <M-Right> :vertical resize +2<CR> + +" Terminal mode +nnoremap <silent> <C-t> :terminal<CR> +tnoremap <C-t> <C-\><C-n>:q!<CR> +tnoremap <Esc> <C-\><C-n> +tnoremap <C-h> <C-\><C-n><C-w>h +tnoremap <C-j> <C-\><C-n><C-w>j +tnoremap <C-k> <C-\><C-n><C-w>k +tnoremap <C-l> <C-\><C-n><C-w>l + +" ============================================================================ +" Text Editing and Visual Mode Mappings +" ============================================================================ + +" Insert mode shortcuts +inoremap jk <ESC> + +" Visual mode operations +vnoremap J :m '>+1<CR>gv=gv +vnoremap K :m '>-2<CR>gv=gv +vnoremap < <gv +vnoremap > >gv + +" Text formatting +nnoremap Q gqap + +" Auto-closing pairs +inoremap [ []<left> +inoremap ( ()<left> +inoremap { {}<left> +inoremap /* /**/<left><left> + +" ============================================================================ +" Tab and Completion Functions +" ============================================================================ + +" Smart Tab Function +function! SmartIndentTab() + let line = getline('.') + let col = col('.') - 1 + + if col == 0 || line[col - 1] =~ '^\s*$' + return "\<C-T>" + else + return "\<tab>" + endif +endfunction + +" Tab mappings +silent! iunmap <tab> +inoremap <silent><expr> <tab> SmartIndentTab() +inoremap <expr> <CR> pumvisible() ? "\<C-Y>" : "\<CR>" + +" Auto-completion function +function! AutoComplete() + let skip_filetypes = ['netrw', 'help', 'startify', 'qf', 'man', 'gitcommit'] + + if index(skip_filetypes, &filetype) >= 0 + return + endif + + let col = col('.') + if col < 4 + return + endif + + let line = getline('.') + let prev3 = line[col - 4] + let prev2 = line[col - 3] + let prev1 = line[col - 2] + let curr = v:char + + if curr =~ '\k' && prev3 !~ '\k' && prev2 =~ '\k' && prev1 =~ '\k' + call feedkeys("\<C-n>", 'n') + endif +endfunction + +" ============================================================================ +" Spell Checking +" ============================================================================ +noremap <silent> <C-z> :setlocal spell!<CR> +setlocal nospell + +function! SpellCheckStatus() + return &spell ? ' [SPELL]' : '' +endfunction + +" ============================================================================ +" File Explorer Configuration +" ============================================================================ +let g:netrw_banner=0 +let g:netrw_browse_split=4 +let g:netrw_altv=1 +let g:netrw_liststyle=3 +let g:netrw_fastbrowse = 0 +let g:netrw_winsize=20 + +" ============================================================================ +" Search Tools Configuration +" ============================================================================ +if executable("rg") + set grepprg=rg\ --vimgrep\ --no-heading + set grepformat=%f:%l:%c:%m,%f:%l:%m +endif + +" ============================================================================ +" Clipboard Configuration +" ============================================================================ + +" OS Detection +let s:uname = substitute(system('uname'), '\n', '', '') +let g:is_mac = has('mac') +let g:is_linux = s:uname ==# 'Linux' +let g:is_windows = has('win32') || has('win64') || s:uname =~? 'Windows' +let g:is_wsl = has('wsl') || (g:is_linux && !empty($WSL_DISTRO_NAME)) +let g:is_termux = has('termux') || (!empty($PREFIX) && $PREFIX =~# 'com.termux') +let g:is_wayland = !empty($WAYLAND_DISPLAY) +let g:is_x11 = !empty($DISPLAY) && empty($WAYLAND_DISPLAY) + +" Clipboard configuration +if has('unnamedplus') + set clipboard=unnamed,unnamedplus +else + set clipboard=unnamed +endif + +if has('clipboard') + " Linux: Wayland/X11 providers + if g:is_wayland && executable('wl-copy') && executable('wl-paste') + let g:clipboard = { + \ 'name': 'wl-clipboard', + \ 'copy': { + \ '+': ['wl-copy', '--trim-newline'], + \ '*': ['wl-copy', '--trim-newline', '--primary'], + \ }, + \ 'paste': { + \ '+': ['wl-paste', '--no-newline'], + \ '*': ['wl-paste', '--no-newline', '--primary'], + \ }, + \ 'cache_enabled': 1, + \ } + elseif g:is_x11 && executable('xclip') + let g:clipboard = { + \ 'name': 'xclip', + \ 'copy': { + \ '+': ['xclip', '-selection', 'clipboard'], + \ '*': ['xclip', '-selection', 'primary'], + \ }, + \ 'paste': { + \ '+': ['xclip', '-selection', 'clipboard', '-o'], + \ '*': ['xclip', '-selection', 'primary', '-o'], + \ }, + \ 'cache_enabled': 1, + \ } + elseif g:is_x11 && executable('xsel') + let g:clipboard = { + \ 'name': 'xsel', + \ 'copy': { + \ '+': ['xsel', '--clipboard', '--input'], + \ '*': ['xsel', '--primary', '--input'], + \ }, + \ 'paste': { + \ '+': ['xsel', '--clipboard', '--output'], + \ '*': ['xsel', '--primary', '--output'], + \ }, + \ 'cache_enabled': 1, + \ } + " macOS: pbcopy/pbpaste + elseif g:is_mac && executable('pbcopy') && executable('pbpaste') + let g:clipboard = { + \ 'name': 'macOS-clipboard', + \ 'copy': { '+': ['pbcopy'], '*': ['pbcopy'] }, + \ 'paste': { '+': ['pbpaste'], '*': ['pbpaste'] }, + \ 'cache_enabled': 1, + \ } + " WSL: prefer win32yank, fallback to clip.exe + PowerShell + elseif g:is_wsl && executable('win32yank.exe') + let g:clipboard = { + \ 'name': 'win32yank-wsl', + \ 'copy': { '+': ['win32yank.exe', '-i', '--crlf'], + \ '*': ['win32yank.exe', '-i', '--crlf'] }, + \ 'paste': { '+': ['win32yank.exe', '-o', '--lf'], + \ '*': ['win32yank.exe', '-o', '--lf'] }, + \ 'cache_enabled': 1, + \ } + elseif g:is_wsl && executable('clip.exe') && executable('powershell.exe') + let g:clipboard = { + \ 'name': 'wsl-clip', + \ 'copy': { + \ '+': ['clip.exe'], + \ '*': ['clip.exe'], + \ }, + \ 'paste': { + \ '+': ['powershell.exe', '-NoProfile', '-Command', + \ '[Console]::Out.Write((Get-Clipboard -Raw) -replace "`r","")'], + \ '*': ['powershell.exe', '-NoProfile', '-Command', + \ '[Console]::Out.Write((Get-Clipboard -Raw) -replace "`r","")'], + \ }, + \ 'cache_enabled': 0, + \ } + " Native Windows + elseif g:is_windows && !g:is_wsl && executable('win32yank.exe') + let g:clipboard = { + \ 'name': 'win32yank', + \ 'copy': { '+': ['win32yank.exe', '-i', '--crlf'], + \ '*': ['win32yank.exe', '-i', '--crlf'] }, + \ 'paste': { '+': ['win32yank.exe', '-o', '--lf'], + \ '*': ['win32yank.exe', '-o', '--lf'] }, + \ 'cache_enabled': 1, + \ } + elseif g:is_windows && !g:is_wsl && executable('powershell.exe') + let g:clipboard = { + \ 'name': 'powershell-clipboard', + \ 'copy': { + \ '+': ['powershell.exe', '-NoProfile', '-Command', + \ 'Set-Clipboard ([Console]::In.ReadToEnd())'], + \ '*': ['powershell.exe', '-NoProfile', '-Command', + \ 'Set-Clipboard ([Console]::In.ReadToEnd())'], + \ }, + \ 'paste': { + \ '+': ['powershell.exe', '-NoProfile', '-Command', + \ '[Console]::Out.Write((Get-Clipboard -Raw) -replace "`r","")'], + \ '*': ['powershell.exe', '-NoProfile', '-Command', + \ '[Console]::Out.Write((Get-Clipboard -Raw) -replace "`r","")'], + \ }, + \ 'cache_enabled': 0, + \ } + endif +endif + +" ============================================================================ +" Colorscheme and Appearance +" ============================================================================ +syntax enable +set termguicolors +set guicursor= +let &t_SI = "\e[6 q" +let &t_EI = "\e[2 q" +set background=dark + +" Window title +let progname = substitute($VIM, '.*[/\\]', '', '') +set title titlestring=%{progname}\ %f\ +%l\ #%{tabpagenr()}.%{winnr()} +if &term =~ '^screen' && !has('vim') + exe "set t_ts=\e]2; t_fs=\7" +endif + +colorscheme colorscheme + +" ============================================================================ +" Custom Functions +" ============================================================================ + +" Clear Terminal Buffer +function! ClearTerminal() + if &buftype == 'terminal' + let s:scroll_value = &scrollback + set scrollback=1 + call feedkeys("\<C-\\>\<C-n>i") + call feedkeys("clear\<CR>") + call timer_start(100, {-> execute('let &scrollback=' . s:scroll_value)}) + endif +endfunction + +" Rename Current File +function! RenameFile() + let old_name = expand('%') + let new_name = input('New file name: ', old_name, 'file') + if new_name != '' && new_name != old_name + try + execute 'saveas ' . fnameescape(new_name) + if filereadable(old_name) && !filereadable(new_name) + call delete(old_name) + endif + redraw! + catch /^Vim\%(\w\+\).*/ + echohl ErrorMsg | echo 'Error renaming file: ' . v:exception | echohl None + endtry + endif +endfunction + +" Format with cursor preservation +function! PreserveCursorFormat() + let l:pos = getpos(".") + silent! normal! gg=G + call setpos('.', l:pos) +endfunction + +" File/URL opener +function! OpenFileOrUrl(path) abort + if !exists('g:os_name') + echohl WarningMsg | echom 'OS detection not available' | echohl None + return + endif + + let cmd = '' + if g:os_name ==# 'mac' + let cmd = 'open ' . shellescape(a:path) + elseif g:os_name ==# 'linux' + let cmd = 'xdg-open ' . shellescape(a:path) . ' >/dev/null 2>&1 &' + elseif g:os_name ==# 'wsl' + let cmd = 'wslview ' . shellescape(a:path) . ' >/dev/null 2>&1 &' + elseif g:os_name ==# 'windows' + let cmd = 'start "" ' . shellescape(a:path) + elseif g:os_name ==# 'termux' + let cmd = 'am start -a android.intent.action.VIEW -d ' . shellescape(a:path) + else + echohl WarningMsg | echom 'No file opener for OS: ' . g:os_name | echohl None + return + endif + + call system(cmd) + if v:shell_error + echohl ErrorMsg | echom 'Failed to open: ' . a:path | echohl None + endif +endfunction + +" ============================================================================ +" Hex Editing Functions +" ============================================================================ + +" Convert to hex +function! DoHex() abort + let current_file = expand('%:p') + if empty(current_file) + echohl ErrorMsg | echo 'No file name' | echohl None + return + endif + + let new_file = current_file . '.hex' + try + execute 'w !xxd > ' . fnameescape(new_file) + echohl Directory | echo 'Hex file created: ' . new_file | echohl None + catch /^Vim\%(\w\+\):/ + echohl ErrorMsg | echo 'Error creating hex file: ' . v:exception | echohl None + endtry +endfunction + +" Convert from hex +function! UndoHex() abort + let current_file = expand('%:p') + if empty(current_file) + echohl ErrorMsg | echo 'No file name' | echohl None + return + endif + + let new_file = substitute(current_file, '\.hex$', '', '') + if new_file ==# current_file + echohl WarningMsg | echo 'Not a .hex file' | echohl None + return + endif + + try + execute '%!xxd -r' + execute 'w ' . fnameescape(new_file) + echohl Directory | echo 'Binary file restored: ' . new_file | echohl None + catch /^Vim\%(\w\+\):/ + echohl ErrorMsg | echo 'Error converting hex file: ' . v:exception | echohl None + endtry +endfunction + +" Hex state switcher +function! HexState() abort + let choices = [ + \ '1. Convert to hex', + \ '2. Convert from hex', + \ '3. Cancel' + \ ] + + let choice = inputlist(choices) + if choice == 1 + call DoHex() + elseif choice == 2 + call UndoHex() + else + echo 'Operation cancelled.' + endif +endfunction + +" ============================================================================ +" Commands +" ============================================================================ +command! -nargs=0 OpenFile call OpenFileOrUrl(expand('%:p')) + +" ============================================================================ +" Auto Commands +" ============================================================================ + +" Return to last position +augroup line_return + au! + au BufReadPost * + \ if line("'\"") > 0 && line("'\"") <= line("$") | + \ execute 'normal! g`"zvzz' | + \ endif +augroup END + +" Auto-completion +augroup AutoCompleteWordStart + autocmd! + autocmd InsertCharPre * call AutoComplete() +augroup END + +" Relative numbers in insert mode +autocmd InsertEnter * set norelativenumber +autocmd InsertLeave * set relativenumber + +" Netrw cleanup +autocmd FileType netrw setl bufhidden=wipe + +" Reload config +augroup ReloadVimrc + autocmd! + autocmd BufWritePost $MYVIMRC nested source $MYVIMRC | + \ doautocmd ColorScheme | + \ call autoload#statusline#ActivateStatusline() | + \ echon "Reloaded .vimrc" | + \ redraw! +augroup END + +" Auto format +augroup FormatOnSave + autocmd! + autocmd BufWritePre * call PreserveCursorFormat() +augroup END + +" ============================================================================ +" Statusline Configuration +" ============================================================================ +let s:statusline_file = expand('~/.vim/autoload/statusline.vim') +if filereadable(s:statusline_file) + execute 'source ' . fnameescape(s:statusline_file) + + augroup StatuslineConfig + autocmd! + autocmd VimEnter * call autoload#statusline#ActivateStatusline() + autocmd ColorScheme * call autoload#statusline#UpdateStslineColors() + autocmd VimEnter * redrawstatus! + augroup END + + set laststatus=2 + set statusline=%!StatusLine() + + augroup StatuslineOverride + autocmd! + autocmd FileType help,gitcommit,netrw setlocal statusline=%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P + augroup END +endif + +" ============================================================================ +" GUI Configuration +" ============================================================================ +if has('gui_running') + color slate + + if has('mac') + set guifont=Menlo\ Regular:h14 + elseif has('win32') + set guifont=Consolas:h12 + else + set guifont=Monospace\ 11 + endif + + set guioptions-=T + set guioptions-=r + set guioptions-=L + set guioptions-=m + + autocmd VimEnter * :Lexplore | wincmd p +endif + +" ============================================================================ +" Final Setup +" ============================================================================ +syntax on +filetype plugin indent on +setlocal keywordprg=:help +setlocal iskeyword+=: + +" Load matchit for better % matching +if !exists('g:loaded_matchit') && findfile('plugin/matchit.vim', &rtp) ==# '' + runtime! macros/matchit.vim +endif + +" ============================================================================ 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 & + |
