many changed, added nixos-hardware

This commit is contained in:
Charlie Root 2024-07-07 13:23:38 +02:00
commit 2accd81424
149 changed files with 19124 additions and 238 deletions

223
flake.lock generated
View file

@ -221,7 +221,7 @@
}, },
"devshell": { "devshell": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_5", "flake-utils": "flake-utils_6",
"nixpkgs": [ "nixpkgs": [
"nixvim", "nixvim",
"nixpkgs" "nixpkgs"
@ -260,11 +260,11 @@
"doomemacs": { "doomemacs": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1720224658, "lastModified": 1720315114,
"narHash": "sha256-ugNtDBO92zFbRx7URXdvtzmGJGLPG6tzDC72UOpf9IA=", "narHash": "sha256-YeXi76K7U2U8u+s3B76zDtJYEglOD+JtIq0o/sGYFJI=",
"owner": "doomemacs", "owner": "doomemacs",
"repo": "doomemacs", "repo": "doomemacs",
"rev": "7bb5df4cd4ae3a0916616dd7e50566b3caa9c931", "rev": "21a427c33b57ab66eb7caa2830c0dfe930509318",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -280,11 +280,11 @@
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1720256942, "lastModified": 1720343386,
"narHash": "sha256-ohfS5d4yR+zdLTICE78rNJmqL/en0BNPGm5zCK6N0QA=", "narHash": "sha256-6OVidxIFSmlK7dWcU8UvTu5erv9yLXeCdRftaDR9wQk=",
"owner": "nix-community", "owner": "nix-community",
"repo": "emacs-overlay", "repo": "emacs-overlay",
"rev": "6d9837126e1be779c8f34ed9fdd609e676a1b891", "rev": "907ffaedc98068a23118e7d9d90ac7200095b3cd",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -301,11 +301,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1720247208, "lastModified": 1720333712,
"narHash": "sha256-isVgeEPkkRz2Tw3vx0J+HyIvKmwpyY4SNcw7MbKZa/I=", "narHash": "sha256-qZmpIPUe4mwdBGmKPBJ5KzvXH6GOCXheiusTAgNjAAA=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "27cbad7cc093c5298231b87daa04db9610053651", "rev": "b78c98c53a46e2a2d6479a920f98aa0aeae56281",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -660,23 +660,8 @@
} }
}, },
"flake-utils_3": { "flake-utils_3": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_4": {
"inputs": { "inputs": {
"systems": "systems_7" "systems": "systems_6"
}, },
"locked": { "locked": {
"lastModified": 1710146030, "lastModified": 1710146030,
@ -692,10 +677,43 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils_4": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_5": { "flake-utils_5": {
"inputs": { "inputs": {
"systems": "systems_8" "systems": "systems_8"
}, },
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_6": {
"inputs": {
"systems": "systems_9"
},
"locked": { "locked": {
"lastModified": 1701680307, "lastModified": 1701680307,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
@ -710,9 +728,9 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils_6": { "flake-utils_7": {
"inputs": { "inputs": {
"systems": "systems_10" "systems": "systems_11"
}, },
"locked": { "locked": {
"lastModified": 1685518550, "lastModified": 1685518550,
@ -728,6 +746,21 @@
"type": "github" "type": "github"
} }
}, },
"flakey-profile": {
"locked": {
"lastModified": 1712898590,
"narHash": "sha256-FhGIEU93VHAChKEXx905TSiPZKga69bWl1VB37FK//I=",
"owner": "lf-",
"repo": "flakey-profile",
"rev": "243c903fd8eadc0f63d205665a92d4df91d42d9d",
"type": "github"
},
"original": {
"owner": "lf-",
"repo": "flakey-profile",
"type": "github"
}
},
"fromYaml": { "fromYaml": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -934,11 +967,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1720188602, "lastModified": 1720327769,
"narHash": "sha256-lC3byBmhVZFzWl/dCic8+cKUEEAXAswWOYjq4paFmbo=", "narHash": "sha256-kAsg3Lg4YKKpGw+f1W2s5hzjP8B0y/juowvjK8utIag=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "e3582e5151498bc4d757e8361431ace8529e7bb7", "rev": "6b7ce96f34b324e4e104abc30d06955d216bac71",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -1203,7 +1236,7 @@
}, },
"lib-aggregate": { "lib-aggregate": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_4", "flake-utils": "flake-utils_5",
"nixpkgs-lib": "nixpkgs-lib_2" "nixpkgs-lib": "nixpkgs-lib_2"
}, },
"locked": { "locked": {
@ -1220,6 +1253,41 @@
"type": "github" "type": "github"
} }
}, },
"lix": {
"flake": false,
"locked": {
"lastModified": 1718419213,
"narHash": "sha256-WY7BGnu5PnbK4O8cKKv9kvxwzZIGbIQUQLGPHFXitI0=",
"rev": "253546d5fbf8a5aa60ac8164c1b4f5794dc4e9d1",
"type": "tarball",
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/253546d5fbf8a5aa60ac8164c1b4f5794dc4e9d1.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.lix.systems/lix-project/lix/archive/2.90.0-rc1.tar.gz"
}
},
"lix-module": {
"inputs": {
"flake-utils": "flake-utils_2",
"flakey-profile": "flakey-profile",
"lix": "lix",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1718778548,
"narHash": "sha256-64lB/NO6AQ6z6EDCemPSYZWX/Qc6Rt04cPia5T5v01g=",
"rev": "29ed1bb67751e5b107d08df35d18dda6d45324e9",
"type": "tarball",
"url": "https://git.lix.systems/api/v1/repos/lix-project/nixos-module/archive/29ed1bb67751e5b107d08df35d18dda6d45324e9.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.lix.systems/lix-project/nixos-module/archive/2.90.0-rc1.tar.gz"
}
},
"naersk": { "naersk": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -1245,7 +1313,7 @@
"neovim-flake": { "neovim-flake": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_2", "flake-parts": "flake-parts_2",
"flake-utils": "flake-utils_2", "flake-utils": "flake-utils_3",
"nil": "nil", "nil": "nil",
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
@ -1350,15 +1418,15 @@
"plugin-vim-vsnip": "plugin-vim-vsnip", "plugin-vim-vsnip": "plugin-vim-vsnip",
"plugin-which-key": "plugin-which-key", "plugin-which-key": "plugin-which-key",
"rnix-lsp": "rnix-lsp", "rnix-lsp": "rnix-lsp",
"systems": "systems_6", "systems": "systems_7",
"zig": "zig" "zig": "zig"
}, },
"locked": { "locked": {
"lastModified": 1720032146, "lastModified": 1720293276,
"narHash": "sha256-m+442OenNQB3SAhVWh2WmKVIauv+OFvl8a7U1weW19s=", "narHash": "sha256-MUhm7MFTQymDgKziGaEC34jFFpFROv3ZXlD6K+IF4Ek=",
"owner": "notashelf", "owner": "notashelf",
"repo": "nvf", "repo": "nvf",
"rev": "3f5ed9e979f3048dc7ad07b0e9f0a6546588ce6c", "rev": "f1849c0ce57452988bf600e354f33d864881b9ac",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -1511,6 +1579,22 @@
"type": "github" "type": "github"
} }
}, },
"nixos-hardware": {
"locked": {
"lastModified": 1719895800,
"narHash": "sha256-xNbjISJTFailxass4LmdWeV4jNhAlmJPwj46a/GxE6M=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "6e253f12b1009053eff5344be5e835f604bb64cd",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixos-hardware",
"type": "github"
}
},
"nixpak": { "nixpak": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_5", "flake-parts": "flake-parts_5",
@ -1596,16 +1680,16 @@
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
"locked": { "locked": {
"lastModified": 1719957072, "lastModified": 1720110830,
"narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=", "narHash": "sha256-E5dN9GDV4LwMEduhBLSkyEz51zM17XkWZ3/9luvNOPs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "7144d6241f02d171d25fba3edeaf15e0f2592105", "rev": "c0d0be00d4ecc4b51d2d6948e37466194c1e6c51",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-23.11", "ref": "nixos-24.05",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -1618,11 +1702,11 @@
"nixpkgs": "nixpkgs_10" "nixpkgs": "nixpkgs_10"
}, },
"locked": { "locked": {
"lastModified": 1720254101, "lastModified": 1720297047,
"narHash": "sha256-uLdBJWNxJcq/avc9lSOZ9IbURy+fnRTkApPOkQJhGDY=", "narHash": "sha256-RXwn9ABn7cdMcachf8m6iu5nHDfY621movgpIM6M9vw=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixpkgs-wayland", "repo": "nixpkgs-wayland",
"rev": "3077de42e37d6835fc29196efda76991493c96c9", "rev": "6cebaff2235ddd938eac062c48dfc14477e56b82",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -1821,11 +1905,11 @@
"treefmt-nix": "treefmt-nix_2" "treefmt-nix": "treefmt-nix_2"
}, },
"locked": { "locked": {
"lastModified": 1720262861, "lastModified": 1720298683,
"narHash": "sha256-KMCrvbTAF9mdEv8ZcG6jqMCKmsZH7K5VTRw5Iv57Zl4=", "narHash": "sha256-CNtfHBwlKuTTanwmUI85Z/HkHShnqZs+WYyxQR8zRFY=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixvim", "repo": "nixvim",
"rev": "04a255ed7e24b0d54a158de5252e8471ac4c6d8f", "rev": "6674dea8403747827431d4d8497c34023f93d047",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -1852,11 +1936,11 @@
}, },
"nur": { "nur": {
"locked": { "locked": {
"lastModified": 1720262786, "lastModified": 1720340553,
"narHash": "sha256-lOw+DePpT6JEzudxzq/yhDqWW9fOga9vrojV2E1DgAs=", "narHash": "sha256-yltkWY9tbcTO1E9lsegEUcqcHdF+F3Yb8O79CjSAHrg=",
"owner": "nix-community", "owner": "nix-community",
"repo": "NUR", "repo": "NUR",
"rev": "7907d743f2a29c574db99f3297da264fe5fe7a6e", "rev": "64eb60afcb54464e61d34fda417e7a5c7a935c21",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -3466,8 +3550,10 @@
"home-manager": "home-manager_2", "home-manager": "home-manager_2",
"hyprland": "hyprland", "hyprland": "hyprland",
"hyprland-plugins": "hyprland-plugins", "hyprland-plugins": "hyprland-plugins",
"lix-module": "lix-module",
"neovim-flake": "neovim-flake", "neovim-flake": "neovim-flake",
"neovim-nightly-overlay": "neovim-nightly-overlay", "neovim-nightly-overlay": "neovim-nightly-overlay",
"nixos-hardware": "nixos-hardware",
"nixpak": "nixpak", "nixpak": "nixpak",
"nixpkgs": "nixpkgs_8", "nixpkgs": "nixpkgs_8",
"nixpkgs-wayland": "nixpkgs-wayland", "nixpkgs-wayland": "nixpkgs-wayland",
@ -3482,11 +3568,11 @@
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1720175310, "lastModified": 1720292183,
"narHash": "sha256-PQG46r17hX06Q1akkuVSeMD1hfiNBENWVlgGn1SF/SE=", "narHash": "sha256-CPcdVpsgmNXYVsw4nKPrM23J5mYXtiotYMz2BjPDIKU=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "f2afcb874e7410121c366ae601660abe327e320b", "rev": "058c88da66797eb588b47a4aac3e42847d1333d7",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -3535,7 +3621,7 @@
"nixpkgs" "nixpkgs"
], ],
"searx-randomizer": "searx-randomizer", "searx-randomizer": "searx-randomizer",
"systems": "systems_9" "systems": "systems_10"
}, },
"locked": { "locked": {
"lastModified": 1719058240, "lastModified": 1719058240,
@ -3576,7 +3662,7 @@
}, },
"spicetify-nix": { "spicetify-nix": {
"inputs": { "inputs": {
"flake-utils": "flake-utils_6", "flake-utils": "flake-utils_7",
"nixpkgs": "nixpkgs_11" "nixpkgs": "nixpkgs_11"
}, },
"locked": { "locked": {
@ -3658,6 +3744,21 @@
} }
}, },
"systems_10": { "systems_10": {
"locked": {
"lastModified": 1689347949,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
"owner": "nix-systems",
"repo": "default-linux",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default-linux",
"type": "github"
}
},
"systems_11": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
@ -3779,16 +3880,16 @@
}, },
"systems_9": { "systems_9": {
"locked": { "locked": {
"lastModified": 1689347949, "lastModified": 1681028828,
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems", "owner": "nix-systems",
"repo": "default-linux", "repo": "default",
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nix-systems", "owner": "nix-systems",
"repo": "default-linux", "repo": "default",
"type": "github" "type": "github"
} }
}, },
@ -3883,7 +3984,7 @@
"zig": { "zig": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"flake-utils": "flake-utils_3", "flake-utils": "flake-utils_4",
"nixpkgs": "nixpkgs_6" "nixpkgs": "nixpkgs_6"
}, },
"locked": { "locked": {

View file

@ -14,11 +14,17 @@
url = "github:hyprwm/hyprland-plugins"; url = "github:hyprwm/hyprland-plugins";
inputs.hyprland.follows = "hyprland"; inputs.hyprland.follows = "hyprland";
}; };
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
# Plugin to get split monitor workspaces # Plugin to get split monitor workspaces
split-monitor-workspaces = { split-monitor-workspaces = {
url = "github:Duckonaut/split-monitor-workspaces"; url = "github:Duckonaut/split-monitor-workspaces";
inputs.hyprland.follows = "hyprland"; inputs.hyprland.follows = "hyprland";
}; };
# Lix because fast rebuild times are cool
lix-module = {
url = "https://git.lix.systems/lix-project/nixos-module/archive/2.90.0-rc1.tar.gz";
inputs.nixpkgs.follows = "nixpkgs";
};
# Sandboxing # Sandboxing
nixpak = { nixpak = {
url = "github:nixpak/nixpak"; url = "github:nixpak/nixpak";

View file

@ -21,7 +21,9 @@ in {
../modules ../modules
inputs.home-manager.nixosModules.home-manager inputs.home-manager.nixosModules.home-manager
inputs.agenix.nixosModules.default inputs.agenix.nixosModules.default
inputs.lix-module.nixosModules.default
inputs.stylix.nixosModules.stylix inputs.stylix.nixosModules.stylix
inputs.nixos-hardware.nixosModules.dell-xps-15-7590-nvidia
]; ];
}; };
} }

View file

@ -62,7 +62,6 @@
mpv.enable = true; mpv.enable = true;
kitty.enable = true; kitty.enable = true;
newsboat.enable = true; newsboat.enable = true;
foot.enable = true;
fish.enable = true; fish.enable = true;
nh.enable = true; nh.enable = true;
waybar.enable = true; waybar.enable = true;
@ -70,6 +69,10 @@
schizofox.enable = true; schizofox.enable = true;
anyrun.enable = true; anyrun.enable = true;
ags.enable = true; ags.enable = true;
foot = {
enable = true;
server = false;
};
}; };
editors = { editors = {
emacs = { emacs = {
@ -89,10 +92,11 @@
stylix = { stylix = {
enable = true; enable = true;
scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-pale.yaml"; scheme = "${pkgs.base16-schemes}/share/themes/gruvbox-dark-pale.yaml";
cursor = {size = 16;}; cursor = {size = 28;};
fontsizes = { fontsizes = {
terminal = 12; terminal = 14;
popups = 12; popups = 14;
applications = 14;
}; };
image = ../../../assets/wallpapers/tiredgod.png; image = ../../../assets/wallpapers/tiredgod.png;
}; };

View file

@ -4,7 +4,7 @@ _: {
../../../options/common/bluetooth.nix ../../../options/common/bluetooth.nix
../../../options/desktop/fonts.nix ../../../options/desktop/fonts.nix
../../../options/common/networking.nix ../../../options/common/networking.nix
# ../../../options/common/gpu/nvidia.nix ../../../options/common/gpu/nvidia.nix
../../../options/desktop/monitors.nix ../../../options/desktop/monitors.nix
../../../overlay.nix ../../../overlay.nix
]; ];

View file

@ -1 +1 @@
_: {imports = [./fish.nix ./nh.nix];} _: {imports = [./fish.nix ./nh.nix ./starship.nix];}

View file

@ -45,10 +45,10 @@ in {
name = "done"; name = "done";
inherit (pkgs.fishPlugins.done) src; inherit (pkgs.fishPlugins.done) src;
} }
{ # {
name = "tide"; # name = "tide";
inherit (pkgs.fishPlugins.tide) src; # inherit (pkgs.fishPlugins.tide) src;
} # }
]; ];
shellAbbrs = shellAbbrs =
{ {

View file

@ -4,15 +4,12 @@
... ...
}: let }: let
inherit (builtins) map; inherit (builtins) map;
inherit (config.modules.other.system) username;
hmCfg = config.home-manager.users.${username};
inherit (lib.strings) concatStrings; inherit (lib.strings) concatStrings;
in { in {
home = { home-manager.users.${username} = let
sessionVariables = {
STARSHIP_CACHE = "${config.xdg.cacheHome}/starship";
};
};
programs.starship = let
elemsConcatted = concatStrings ( elemsConcatted = concatStrings (
map (s: "\$${s}") [ map (s: "\$${s}") [
"hostname" "hostname"
@ -29,75 +26,95 @@ in {
] ]
); );
in { in {
enable = true; home.sessionVariables = {
STARSHIP_CACHE = "${hmCfg.home.homeDirectory}/.cache/starship";
};
programs.starship = {
enable = true;
enableFishIntegration = true;
enableTransience = true;
settings = {
scan_timeout = 2;
command_timeout = 2000; # nixpkgs makes starship implode with lower values
add_newline = false;
line_break.disabled = false;
settings = { format = "${elemsConcatted}\n$character";
scan_timeout = 2; # format = concatStrings [
command_timeout = 2000; # nixpkgs makes starship implode with lower values # "$hostname"
add_newline = false; # #"$username"
line_break.disabled = false; # "$directory"
# "$shell"
# "$nix_shell"
# "$git_branch"
# "$git_commit"
# "$git_state"
# "$git_status"
# "$jobs"
# "$cmd_duration"
# "\n$character"
# ];
format = "${elemsConcatted}\n$character"; hostname = {
ssh_only = true;
hostname = { disabled = false;
ssh_only = true; format = "@[$hostname](bold blue) "; # the whitespace at the end is actually important
disabled = false;
format = "@[$hostname](bold blue) "; # the whitespace at the end is actually important
};
# configure specific elements
character = {
error_symbol = "[](bold red)";
success_symbol = "[](bold green)";
vicmd_symbol = "[](bold yellow)";
format = "$symbol [|](bold bright-black) ";
};
username = {
format = "[$user]($style) in ";
};
directory = {
truncation_length = 2;
# removes the read_only symbol from the format, it doesn't play nicely with my folder icon
format = "[ ](bold green) [$path]($style) ";
# the following removes tildes from the path, and substitutes some folders with shorter names
substitutions = {
"~/Dev" = "Dev";
"~/Documents" = "Docs";
}; };
# configure specific elements
character = {
error_symbol = "[](bold red)";
success_symbol = "[](bold green)";
vicmd_symbol = "[](bold yellow)";
format = "$symbol [|](bold bright-black) ";
};
username = {
format = "[$user]($style) in ";
};
directory = {
truncation_length = 2;
# removes the read_only symbol from the format, it doesn't play nicely with my folder icon
format = "[ ](bold green) [$path]($style) ";
# the following removes tildes from the path, and substitutes some folders with shorter names
substitutions = {
"~/Dev" = "Dev";
"~/Documents" = "Docs";
};
};
# git
git_commit.commit_hash_length = 7;
git_branch.style = "bold purple";
git_status = {
style = "red";
ahead = " ";
behind = " ";
conflicted = " ";
renamed = "»";
deleted = " ";
diverged = " ";
modified = "!";
stashed = "";
staged = "+";
untracked = "?";
};
# language configurations
# the whitespaces at the end *are* necessary for proper formatting
lua.symbol = "[ ](blue) ";
python.symbol = "[ ](blue) ";
rust.symbol = "[ ](red) ";
nix_shell.symbol = "[󱄅 ](blue) ";
golang.symbol = "[󰟓 ](blue)";
c.symbol = "[ ](black)";
nodejs.symbol = "[󰎙 ](yellow)";
package.symbol = "📦 ";
}; };
# git
git_commit.commit_hash_length = 7;
git_branch.style = "bold purple";
git_status = {
style = "red";
ahead = " ";
behind = " ";
conflicted = " ";
renamed = "»";
deleted = " ";
diverged = " ";
modified = "!";
stashed = "";
staged = "+";
untracked = "?";
};
# language configurations
# the whitespaces at the end *are* necessary for proper formatting
lua.symbol = "[ ](blue) ";
python.symbol = "[ ](blue) ";
rust.symbol = "[ ](red) ";
nix_shell.symbol = "[󱄅 ](blue) ";
golang.symbol = "[󰟓 ](blue)";
c.symbol = "[ ](black)";
nodejs.symbol = "[󰎙 ](yellow)";
package.symbol = "📦 ";
}; };
}; };
} }

View file

@ -6,7 +6,7 @@
... ...
}: }:
with lib; let with lib; let
username = config.modules.other.system.username; inherit (config.modules.other.system) username;
cfg = config.modules.programs.anyrun; cfg = config.modules.programs.anyrun;
in { in {
options.modules.programs.anyrun.enable = mkEnableOption "anyrun"; options.modules.programs.anyrun.enable = mkEnableOption "anyrun";
@ -20,11 +20,12 @@ in {
plugins = with inputs.anyrun.packages.${pkgs.system}; [ plugins = with inputs.anyrun.packages.${pkgs.system}; [
applications applications
dictionary dictionary
kidex # kidex
rink rink
shell shell
symbols # symbols
translate translate
websearch
]; ];
hideIcons = false; hideIcons = false;
ignoreExclusiveZones = false; ignoreExclusiveZones = false;
@ -42,7 +43,13 @@ in {
Config( Config(
desktop_actions: false, desktop_actions: false,
max_entries: 5, max_entries: 5,
terminal: Some("kitty"), terminal: Some("foot"),
)
'';
extraConfigFiles."websearch.ron".text = ''
Config(
prefix: "?",
engines: [DuckDuckGo]
) )
''; '';
}; };

View file

@ -1,5 +1,5 @@
{config, ...}: let {config, ...}: let
username = config.modules.other.system.username; inherit (config.modules.other.system) username;
hmCfg = config.home-manager.users.${username}; hmCfg = config.home-manager.users.${username};
primary_browser = "Schizofox.desktop"; primary_browser = "Schizofox.desktop";
@ -7,7 +7,7 @@
file_manager = "nautilus.desktop"; file_manager = "nautilus.desktop";
media_player = "mpv.desktop"; media_player = "mpv.desktop";
image_viewer = "imv.desktop"; image_viewer = "imv.desktop";
text_editor = "helix.desktop"; text_editor = "nvim.desktop";
terminal = "foot.desktop"; terminal = "foot.desktop";
in { in {
environment.sessionVariables = {TERMINAL = "${terminal}";}; environment.sessionVariables = {TERMINAL = "${terminal}";};

View file

@ -13,18 +13,29 @@ in {
options.modules.programs.ags.enable = mkEnableOption "ags"; options.modules.programs.ags.enable = mkEnableOption "ags";
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [
ags
bun
ddcutil
brightnessctl
gtksourceview
webkitgtk
gtksourceview4
ollama
python311Packages.material-color-utilities
python311Packages.pywayland
pywal
sassc
webp-pixbuf-loader
ydotool
accountsservice
];
home-manager.users.${username} = { home-manager.users.${username} = {
imports = [inputs.ags.homeManagerModules.default]; imports = [inputs.ags.homeManagerModules.default];
programs.ags = { programs.ags = {
enable = true; enable = true;
configDir = ./config; configDir = ./config;
extraPackages = with pkgs; [
ags
bun
gtksourceview
webkitgtk
accountsservice
];
}; };
}; };
}; };

View file

@ -0,0 +1,21 @@
const main = "/tmp/ags/main.js";
try {
await Utils.execAsync([
"bun",
"build",
`${App.configDir}/main.ts`,
"--outfile",
main,
"--external",
"resource://*",
"--external",
"gi://*",
"--external",
"file://*",
]);
await import(`file://${main}`);
} catch (error) {
console.error(error);
App.quit();
}

View file

@ -0,0 +1,40 @@
window.bar {
background-color: @theme_bg_color;
color: @theme_fg_color;
}
button {
min-width: 0;
padding-top: 0;
padding-bottom: 0;
background-color: transparent;
}
button:active {
background-color: @theme_selected_bg_color;
}
button:hover {
border-bottom: 3px solid @theme_fg_color;
}
label {
font-weight: bold;
}
.workspaces button.focused {
border-bottom: 3px solid @theme_selected_bg_color;
}
.client-title {
color: @theme_selected_bg_color;
}
.notification {
color: yellow;
}
levelbar block,
highlight {
min-height: 10px;
}

View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.0"
width="20"
height="19.999941"
id="svg2424"
sodipodi:docname="archlinux-logo-black-scalable.f931920e6cdb.svg"
viewBox="0 0 166.18749 166.187"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="16.650008"
inkscape:cx="13.093087"
inkscape:cy="16.366359"
inkscape:window-width="1340"
inkscape:window-height="768"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g2424" />
<defs
id="defs2426">
<linearGradient
x1="112.49854"
y1="6.1372099"
x2="112.49853"
y2="129.3468"
id="path1082_2_"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(287,-83)">
<stop
id="stop193"
style="stop-color:#ffffff;stop-opacity:0"
offset="0" />
<stop
id="stop195"
style="stop-color:#ffffff;stop-opacity:0.27450982"
offset="1" />
<midPointStop
offset="0"
style="stop-color:#FFFFFF"
id="midPointStop197" />
<midPointStop
offset="0.5"
style="stop-color:#FFFFFF"
id="midPointStop199" />
<midPointStop
offset="1"
style="stop-color:#000000"
id="midPointStop201" />
</linearGradient>
<linearGradient
x1="541.33502"
y1="104.50665"
x2="606.91248"
y2="303.14029"
id="linearGradient2544"
xlink:href="#path1082_2_"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.3937741,0,0,0.393752,357.51969,122.00151)" />
<linearGradient
id="linearGradient3388">
<stop
id="stop3390"
style="stop-color:#000000;stop-opacity:0"
offset="0" />
<stop
id="stop3392"
style="stop-color:#000000;stop-opacity:0.37113401"
offset="1" />
</linearGradient>
<linearGradient
x1="490.72305"
y1="237.72447"
x2="490.72305"
y2="183.9644"
id="linearGradient4416"
xlink:href="#linearGradient3388"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.749107,0,0,0.749107,-35.459862,91.44108)" />
</defs>
<g
transform="translate(-57.527313,-146.42741)"
id="layer1">
<g
transform="matrix(0.8746356,0,0,0.8746356,14.730518,23.408954)"
id="g2424"
style="fill:#000000">
<g
transform="matrix(0.6378586,0,0,0.6378586,36.486487,2.17139)"
id="g2809"
style="fill:#000000;fill-opacity:1" />
<path
d="m 143.91698,140.65081 c -8.45709,20.73453 -13.55799,34.29734 -22.97385,54.41552 5.7731,6.11948 12.85931,13.24593 24.36729,21.29458 -12.37221,-5.09109 -20.81157,-10.20242 -27.11844,-15.50646 -12.0505,25.14523 -30.930177,60.96349 -69.243121,129.80406 30.112687,-17.38458 53.455511,-28.10236 75.209891,-32.19198 -0.93414,-4.01773 -1.46524,-8.36369 -1.42916,-12.89823 l 0.0357,-0.96469 c 0.47781,-19.2924 10.51371,-34.12825 22.40218,-33.12093 11.88848,1.00732 21.12927,17.4729 20.65146,36.76531 -0.0899,3.63022 -0.49934,7.12245 -1.21479,10.36146 21.51819,4.20934 44.61141,14.89968 74.31666,32.04906 -5.85729,-10.78369 -11.08544,-20.5044 -16.07812,-29.7624 -7.86429,-6.09535 -16.06714,-14.02847 -32.79938,-22.61656 11.50078,2.98839 19.73519,6.43619 26.15375,10.29 -50.76203,-94.51003 -54.87267,-107.06846 -72.2801,-147.91874 z"
id="path2518"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.14333" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
width="20"
height="20"
viewBox="-30.5 0 317.00242 317.00243"
version="1.1"
preserveAspectRatio="xMidYMid"
id="svg12"
sodipodi:docname="debian-symbolic.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
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="defs12" />
<sodipodi:namedview
id="namedview12"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="17.5"
inkscape:cx="13.742857"
inkscape:cy="12.628571"
inkscape:window-width="1295"
inkscape:window-height="867"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg12" />
<g
fill="#A80030"
id="g12"
style="fill:#1a1a1a"
transform="translate(0.05835351,0.0538775)">
<path
d="m 152.79662,167.42537 c -5.25095,0.0731 0.9935,2.70583 7.84865,3.76069 1.8935,-1.47856 3.61167,-2.97466 5.14283,-4.42984 -4.26913,1.04609 -8.61424,1.06947 -12.99148,0.66915"
id="path1"
style="fill:#1a1a1a" />
<path
d="m 180.9799,160.40073 c 3.12661,-4.31588 5.40581,-9.04086 6.20938,-13.92654 -0.70129,3.4831 -2.59187,6.4899 -4.3714,9.66326 -9.81521,6.18016 -0.92337,-3.67011 -0.006,-7.41328 -10.55448,13.2837 -1.44934,7.96554 -1.83213,11.67656"
id="path2"
style="fill:#1a1a1a" />
<path
d="m 191.38244,133.33075 c 0.63409,-9.45579 -1.86135,-6.46652 -2.69999,-2.85777 0.9789,0.50844 1.75324,6.66522 2.69999,2.85777"
id="path3"
style="fill:#1a1a1a" />
<path
d="m 132.88569,4.0879643 c 2.80225,0.5025946 6.05451,0.8883068 5.59867,1.5574589 3.06524,-0.6720742 3.76069,-1.2915513 -5.59867,-1.5574589"
id="path4"
style="fill:#1a1a1a" />
<path
d="m 138.48436,5.6454232 -1.98116,0.4090887 1.84382,-0.1636355 0.13734,-0.2454532"
id="path5"
style="fill:#1a1a1a" />
<path
d="m 225.86569,136.91612 c 0.31266,8.49151 -2.48375,12.61162 -5.00549,19.90509 l -4.53796,2.26752 c -3.71394,7.21165 0.35941,4.57887 -2.29967,10.31487 -5.79737,5.15452 -17.59373,16.12979 -21.36903,17.13205 -2.75551,-0.0614 1.86719,-3.25225 2.47206,-4.50289 -7.76099,5.32984 -6.22691,8.0006 -18.09633,11.23824 l -0.34772,-0.77142 c -29.27322,13.77168 -69.93663,-13.52038 -69.40189,-50.75913 -0.31266,2.36394 -0.88831,1.77369 -1.537,2.7292 -1.51071,-19.15996 8.848,-38.40465 26.31901,-46.262078 17.08821,-8.459369 37.12187,-4.987959 49.36238,6.419768 -6.72366,-8.807092 -20.1067,-18.14308 -35.96765,-17.269383 -15.53661,0.245453 -30.07094,10.1191 -34.92156,20.837223 -7.9597,5.01133 -8.88307,19.31775 -12.351558,21.93592 -4.666532,34.29623 8.777878,49.11401 31.520278,66.54411 3.57953,2.41362 1.00811,2.77888 1.49318,4.61685 -7.55646,-3.53861 -14.4759,-8.88014 -20.16515,-15.41972 3.01849,4.41816 6.27659,8.71359 10.48728,12.08857 -7.12399,-2.41362 -16.64115,-17.26354 -19.42003,-17.8684 12.28143,21.98851 49.827,38.56245 69.48663,30.33976 -9.09638,0.33604 -20.65313,0.18702 -30.8745,-3.59121 -4.29251,-2.20908 -10.13079,-6.78503 -9.08761,-7.64119 26.83037,10.02267 54.54612,7.59151 77.7619,-11.0191 5.90549,-4.59932 12.3574,-12.4246 14.22168,-12.53272 -2.8081,4.22238 0.47921,2.03083 -1.67727,5.75938 5.88504,-9.49085 -2.5568,-3.86296 6.08374,-16.38984 l 3.19089,4.39478 c -1.18636,-7.87788 9.78306,-17.44471 8.66975,-29.90438 2.5159,-3.81037 2.80811,4.09965 0.13734,12.86584 3.70517,-9.72462 0.97597,-11.28793 1.92856,-19.31191 1.02857,2.69707 2.37856,5.56361 3.07109,8.4097 -2.41362,-9.39735 2.47791,-15.82589 3.68764,-21.28722 -1.1922,-0.52889 -3.72563,4.15517 -4.3042,-6.94574 0.0847,-4.8214 1.34123,-2.52759 1.82629,-3.71394 -0.94675,-0.54351 -3.4305,-4.23991 -4.9412,-11.328836 1.09577,-1.665575 2.9279,4.318806 4.41815,4.564256 -0.95843,-5.636653 -2.6094,-9.935006 -2.67661,-14.259657 -4.35387,-9.0993 -1.53992,1.212656 -5.07269,-3.906796 -4.63439,-14.45544 3.84543,-3.354527 4.41815,-9.923322 7.02464,10.177541 11.03079,25.950835 12.86876,32.484565 -1.40259,-7.965545 -3.67011,-15.68271 -6.4373,-23.148578 2.13311,0.897073 -3.43634,-16.389844 2.77304,-4.941206 -6.63308,-24.40506 -28.38783,-47.208829 -48.40103,-57.909419 2.44869,2.241221 5.54023,5.055166 4.42984,5.496398 -9.95254,-5.925941 -8.20223,-6.387627 -9.62819,-8.891834 -8.10872,-3.299008 -8.64054,0.265908 -14.01129,0.0058 -15.28238,-8.105755 -18.22782,-7.243747 -32.2917,-12.32229 l 0.63993,2.9892691 c -10.12494,-3.3720592 -11.79636,1.279863 -22.73948,0.011688 -0.66623,-0.520127 3.50647,-1.8818077 6.93989,-2.3814803 -9.7889,1.2915513 -9.33014,-1.9285607 -18.90866,0.3564916 2.36103,-1.656809 4.85647,-2.7525822 7.37529,-4.1610159 -7.98308,0.4850622 -19.05769,4.6460781 -15.63888,0.8620082 C 96.316085,8.9298206 73.190888,17.085295 60.214012,29.25276 L 59.804924,26.526476 C 53.858528,33.665073 33.874548,47.845838 32.282025,57.091242 l -1.589602,0.371102 C 27.59796,62.7016 25.596347,68.63923 23.141816,74.030433 19.09476,80.926499 17.21003,76.683665 17.785676,77.764828 9.8259803,93.903375 5.8724309,107.46466 2.4565407,118.58603 4.8906182,122.224 2.514982,140.48688 3.4354314,155.10304 -0.56194899,227.28965 54.098137,297.37822 113.84553,313.5606 c 8.75742,3.13245 21.78105,3.01264 32.85859,3.33407 -13.07039,-3.73732 -14.75934,-1.98116 -27.49076,-6.41977 -9.18404,-4.32465 -11.19734,-9.26293 -17.70185,-14.90836 l 2.57434,4.54965 c -12.757724,-4.51458 -7.419118,-5.58698 -17.798281,-8.8743 l 2.74966,-3.59121 c -4.134717,-0.31266 -10.951887,-6.96912 -12.816162,-10.65384 l -4.523352,0.17825 C 66.26268,270.46895 63.366917,265.63586 63.577306,261.8927 l -1.461031,2.60356 c -1.656809,-2.84317 -19.995669,-25.15019 -10.481436,-19.95768 -1.767847,-1.6159 -4.117185,-2.62986 -6.665222,-7.2584 l 1.937326,-2.21493 c -4.57887,-5.89087 -8.427226,-13.44148 -8.135019,-15.95737 2.442843,3.299 4.137639,3.91556 5.814902,4.47952 -11.562598,-28.68881 -12.211295,-1.58084 -20.968714,-29.20309 l 1.852587,-0.14902 c -1.420122,-2.13895 -2.28213,-4.46199 -3.424657,-6.7412 l 0.80649,-8.03567 c -8.324954,-9.62527 -2.328884,-40.9264 -1.127916,-58.09351 0.832787,-6.9808 6.948662,-14.41161 11.600585,-26.064789 l -2.8344,-0.487985 c 5.417502,-9.449947 30.932945,-37.951737 42.749763,-36.484862 5.724319,-7.191194 -1.136683,-0.0263 -2.255832,-1.837977 12.573631,-13.011941 16.527181,-9.192806 25.012848,-11.533378 9.1519,-5.432112 -7.854502,2.118495 -3.51524,-2.071741 15.82004,-4.041212 11.21195,-9.186962 31.85047,-11.23825 2.17694,1.238955 -5.05224,1.913951 -6.86684,3.521085 13.18142,-6.448991 41.71243,-4.982116 60.24414,3.579525 21.50346,10.04897 45.66306,39.75465 46.61565,67.704172 l 1.08409,0.2922 c -0.54935,11.10968 1.70064,23.95799 -2.19739,35.76019 l 2.65323,-5.58698"
id="path6"
style="fill:#1a1a1a" />
<path
d="m 95.483297,174.6341 -0.736359,3.68179 c 3.450955,4.68699 6.188932,9.76553 10.595392,13.4298 -3.17043,-6.18893 -5.525615,-8.74573 -9.859033,-17.11159"
id="path7"
style="fill:#1a1a1a" />
<path
d="m 103.64169,174.31267 c -1.82629,-2.01915 -2.90745,-4.4503 -4.117181,-6.87269 1.157141,4.25744 3.526931,7.91586 5.733081,11.63565 l -1.6159,-4.76296"
id="path8"
style="fill:#1a1a1a" />
<path
d="m 248.00323,142.93557 -0.77142,1.9344 c -1.41428,10.04605 -4.46784,19.98691 -9.14898,29.20309 5.17205,-9.72462 8.51781,-20.36093 9.9204,-31.13749"
id="path9"
style="fill:#1a1a1a" />
<path
d="M 133.92302,1.5691471 C 137.47332,0.26882968 142.65122,0.85616408 146.41775,0 141.50869,0.4120107 136.623,0.65746388 131.79868,1.279863 l 2.12434,0.2892841"
id="path10"
style="fill:#1a1a1a" />
<path
d="m 9.2824769,67.847351 c 0.8181771,7.573984 -5.6980203,10.513578 1.4434981,5.519774 3.827901,-8.623004 -1.4960952,-2.38148 -1.4434981,-5.519774"
id="path11"
style="fill:#1a1a1a" />
<path
d="M 0.89031567,102.9004 C 2.5354364,97.85108 2.8334867,94.81798 3.46173,91.895919 -1.084998,97.707899 1.3695338,98.946854 0.89031567,102.9004"
id="path12"
style="fill:#1a1a1a" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 448.00288 448.00288"
version="1.1"
id="svg1"
sodipodi:docname="Fa-Team-Fontawesome-Brands-FontAwesome-Brands-Fedora.svg"
width="19.999744"
height="19.999744"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
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="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="13.671875"
inkscape:cx="19.2"
inkscape:cy="17.664"
inkscape:window-width="1313"
inkscape:window-height="908"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. -->
<path
d="M 0.0413,223.8 C 0.1219,100.2 100.3,0 224,0 347.7,0 448,100.3 448,224 448,347.7 347.8,447.9 224.1,448 H 50.93 C 22.84,448 0.0832,425.3 0.0416,397.2 H 0 V 223.8 Z M 342.6,160.7 c 0,-39.7 -35.6,-68.5 -73.2,-68.5 -34.9,0 -65.8,26.3 -70.1,59.9 -0.2,3.8 -0.4,5 -0.4,8.5 -0.1,21.1 0,42.8 -0.8,64.4 0.9,26.1 1,52.1 0,76.6 0,27.1 -19.4,45.5 -44.7,45.5 -25.3,0 -45.8,-20.2 -45.8,-45.5 0.5,-27.7 22.6,-45.3 48.5,-46.1 h 0.2 l 26.3,-0.2 V 218 l -26.3,0.2 c -47.1,-0.4 -84.58,36.5 -85.94,83.4 0,45.6 37.54,82.9 83.04,82.9 43,0 78.7,-33.6 82.6,-75.6 l 0.2,-53.5 32.6,-0.3 c 25.3,0.2 25,-37.8 -0.2,-37.3 l -32.4,0.3 c 0,-6.4 0.1,-12.8 0.1,-19.2 0.1,-12.7 0.1,-25.4 -0.1,-38.2 0.1,-16.5 15.8,-31.2 33.2,-31.2 17.5,0 35.9,8.7 35.9,31.2 0,3.2 -0.1,5.1 -0.3,6.3 -1.9,10.5 5.2,20.4 15.7,21.9 10.6,1.5 20.2,-6.1 21.2,-16.6 0.6,-4.2 0.7,-7.9 0.7,-11.6 z"
id="path1" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
role="img"
viewBox="0 0 24.000009 24.000009"
version="1.1"
id="svg1"
sodipodi:docname="flatpak_logo_icon_248537.svg"
width="20"
height="20"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
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"
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/">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="18.229167"
inkscape:cx="11.190857"
inkscape:cy="11.766857"
inkscape:window-width="1164"
inkscape:window-height="648"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<title
id="title1">Flatpak</title>
<path
d="m 12.000004,7.3336774e-5 c -0.556,0 -1.110999,0.143999993226 -1.609999,0.431999993226 L 2.7870046,4.8220733 a 3.217,3.217 0 0 0 -1.61,2.788 v 8.7799997 c 0,1.151 0.612,2.212 1.61,2.788 l 7.6030004,4.39 a 3.217,3.217 0 0 0 3.219999,0 l 7.603,-4.39 a 3.217,3.217 0 0 0 1.61,-2.788 V 7.6100733 a 3.217,3.217 0 0 0 -1.61,-2.788 l -7.603,-4.38999997 a 3.218,3.218 0 0 0 -1.61,-0.431999993226 z m 0,2.357999963226 c 0.15,0 0.299,0.039 0.431,0.115 l 7.604,4.39 c 0.132,0.077 0.24,0.187 0.315,0.316 l -8.35,4.8209997 v 9.642 a 0.863,0.863 0 0 1 -0.431,-0.116 l -7.6039994,-4.39 a 0.866,0.866 0 0 1 -0.431,-0.746 V 7.6100733 c 0,-0.153 0.041,-0.302 0.116,-0.43 l 8.3499994,4.8199997 z"
id="path1" />
<metadata
id="metadata1">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title>Flatpak</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
fill="#000000"
width="20"
height="20"
viewBox="0 0 380.95238 380.95238"
version="1.1"
id="svg1"
sodipodi:docname="google-gemini-symbolic.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
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"
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/">
<defs
id="defs1" />
<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="6.1871843"
inkscape:cx="39.840417"
inkscape:cy="52.931994"
inkscape:window-width="1183"
inkscape:window-height="1028"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<title
id="title1">ionicons-v5_logos</title>
<path
d="m 275.79491,211.5275 -1.32807,-5.6355 H 151.97845 v 51.84191 h 73.1851 c -7.59823,36.0813 -42.85683,55.07394 -71.65724,55.07394 -20.95536,0 -43.04487,-8.81465 -57.665446,-22.98274 A 82.317089,82.317089 0 0 1 71.277365,231.71893 c 0,-21.83683 9.813652,-43.67954 24.093389,-58.04741 14.279736,-14.36788 35.846246,-22.40685 57.289356,-22.40685 24.55762,0 42.15754,13.03981 48.73915,18.98676 l 36.83935,-36.64544 c -10.80674,-9.49631 -40.49449,-33.42515 -86.76554,-33.42515 v 0 c -35.69934,0 -69.929575,13.67445 -94.951433,38.61404 -24.692774,24.55761 -37.474018,60.06891 -37.474018,93.01808 0,32.94916 12.0937,66.68577 36.022537,91.4373 25.568365,26.39695 61.778964,40.19482 99.064944,40.19482 33.92466,0 66.0805,-13.2925 88.99858,-37.40938 22.53025,-23.74079 34.18323,-56.59006 34.18323,-91.02597 0,-14.49716 -1.45736,-23.10613 -1.522,-23.48223 z"
id="path1"
style="stroke-width:0.587643" />
<path
d="m 289.72137,169.73053 v 0 0 C 283.37821,127.87205 250.52413,95.017925 208.66564,88.674797 v 0 0 c 41.85849,-6.343163 74.71257,-39.197259 81.05573,-81.0557495 v 0 0 c 6.34314,41.8584905 39.19721,74.7125865 81.05574,81.0557495 v 0 0 c -41.85853,6.343128 -74.7126,39.197253 -81.05574,81.055733 z"
fill="#076eff"
id="path19"
style="fill:#000000;stroke-width:2.22805" />
<metadata
id="metadata1">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title>ionicons-v5_logos</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
height="20"
width="19.999744"
version="1.1"
id="svg8"
sodipodi:docname="nixos-symbolic.svg"
viewBox="0 0 512.00001 512.00656"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
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="defs8" />
<sodipodi:namedview
id="namedview8"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="27.34375"
inkscape:cx="8.832"
inkscape:cy="15.817143"
inkscape:window-width="1075"
inkscape:window-height="1028"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<g
fill-rule="evenodd"
transform="matrix(1.2756532,0,0,-1.2756532,9.0810546e-6,478.03773)"
id="g8"
style="fill:#000000">
<path
d="m 122.453,169.761 97.758,-169.34 -44.926,-0.422 -26.101,45.496 -26.286,-45.25 -22.32,0.008 -11.433,19.75 37.449,64.394 -26.582,46.258 z"
fill="#5277c3"
id="path1"
style="fill:#000000" />
<path
d="M 157.738,239.515 59.961,70.183 37.133,108.882 63.484,154.229 11.152,154.366 0,173.702 l 11.391,19.777 74.488,-0.234 26.769,46.152 z"
fill="#7ebae4"
id="path2"
style="fill:#000000" />
<path
d="M 165.238,104.155 360.77,104.143 338.672,65.026 286.223,65.171 312.27,19.784 301.102,0.456 278.277,0.429 241.238,65.058 187.883,65.167 Z"
fill="#7ebae4"
id="path3"
style="fill:#000000" />
<path
d="m 279.043,178.35 -97.758,169.34 44.926,0.422 26.101,-45.496 26.286,45.254 22.32,-0.008 11.434,-19.754 -37.45,-64.39 26.582,-46.262 z"
fill="#7ebae4"
id="path4"
style="fill:#000000" />
<g
fill="#5277c3"
id="g7"
style="fill:#000000">
<path
d="m 122.453,169.761 97.758,-169.34 -44.926,-0.422 -26.101,45.496 -26.286,-45.25 -22.32,0.008 -11.433,19.75 37.449,64.394 -26.582,46.258 z"
id="path5"
style="fill:#000000" />
<path
d="m 236,244.386 -195.535,0.011 22.101,39.118 52.45,-0.149 -26.047,45.391 11.168,19.328 22.82,0.023 37.043,-64.625 53.352,-0.109 z"
id="path6"
style="fill:#000000" />
<path
d="m 243.625,108.636 97.777,169.328 22.825,-38.696 -26.348,-45.351 52.332,-0.137 11.152,-19.336 -11.39,-19.777 -74.489,0.238 -26.769,-46.152 z"
id="path7"
style="fill:#000000" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 322.58065 322.58064"
version="1.1"
id="svg1"
sodipodi:docname="openai-symbolic.svg"
width="20"
height="20"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
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="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="30.935922"
inkscape:cx="9.0348044"
inkscape:cy="14.917933"
inkscape:window-width="1183"
inkscape:window-height="1028"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<path
d="m 298.66868,131.77215 c 7.30439,-21.92321 4.7891,-45.939129 -6.89187,-65.880296 C 274.21007,35.30601 238.89549,19.570397 204.40593,26.975391 189.0627,9.6903649 167.01876,-0.13936259 143.90833,0.0014933 108.65412,-0.07899576 77.374064,22.618921 66.528162,56.162739 43.880552,60.800921 24.33177,74.977058 12.892261,95.069141 -4.8052718,125.57449 -0.77075743,164.02814 22.872905,190.18709 c -7.304382,21.92321 -4.789099,45.93913 6.891877,65.8803 17.566738,30.58585 52.881316,46.32146 87.370878,38.91646 15.33316,17.28503 37.38717,27.11476 60.49759,26.96384 35.27433,0.0905 66.56446,-22.62749 77.41036,-56.20149 22.64761,-4.63818 42.19639,-18.81432 53.6359,-38.9064 17.67741,-30.50536 13.63284,-68.92883 -10.00077,-95.08777 z M 177.65337,300.90986 c -14.11577,0.0201 -27.78885,-4.91989 -38.62469,-13.96485 0.493,-0.26159 1.34819,-0.73446 1.90156,-1.07654 l 64.10954,-37.02497 c 3.27993,-1.86131 5.29215,-5.35253 5.27203,-9.12545 v -90.37916 l 27.09463,15.64506 c 0.29178,0.14086 0.48294,0.42257 0.52318,0.74453 v 74.84477 c -0.0402,33.28222 -26.99402,60.26618 -60.27625,60.33661 z M 48.025738,245.54345 c -7.072976,-12.21422 -9.618443,-26.53121 -7.19371,-40.42564 0.472874,0.28171 1.307948,0.79483 1.901554,1.13691 l 64.109538,37.02497 c 3.24974,1.90155 7.2742,1.90155 10.534,0 l 78.26556,-45.19461 v 31.29012 c 0.0201,0.32196 -0.1308,0.63386 -0.38232,0.83508 l -64.80376,37.41735 c -28.86539,16.62099 -65.72938,6.74096 -82.4208,-22.08418 z M 31.153218,105.60314 c 7.042793,-12.234331 18.160346,-21.591185 31.400797,-26.450712 0,0.553362 -0.03018,1.529292 -0.03018,2.213449 v 74.059993 c -0.02012,3.76287 1.992105,7.25408 5.261973,9.11539 l 78.265542,45.18455 -27.09463,15.64506 c -0.27165,0.1811 -0.61373,0.21129 -0.91556,0.0805 L 53.227344,188.00382 C 24.42232,171.32247 14.542287,134.46853 31.143157,105.6132 Z m 222.612632,51.80478 -78.26556,-45.19461 27.09463,-15.634999 c 0.27165,-0.181101 0.61373,-0.211284 0.91557,-0.08049 l 64.81382,37.417349 c 28.85533,16.6713 38.74542,53.5856 22.07412,82.44093 -7.05285,12.21421 -18.16034,21.57107 -31.39073,26.44066 V 166.5233 c 0.0302,-3.76286 -1.97199,-7.24401 -5.23179,-9.11538 z m 26.96383,-40.58661 c -0.47287,-0.29178 -1.30794,-0.79483 -1.90155,-1.13691 L 214.71859,78.659433 c -3.24975,-1.901555 -7.2742,-1.901555 -10.53401,0 L 125.91903,123.85404 V 92.563919 c -0.0201,-0.321957 0.13079,-0.633852 0.38232,-0.835074 l 64.80376,-37.387171 c 28.86539,-16.651176 65.76963,-6.74096 82.41074,22.134493 7.03273,12.194093 9.5782,26.470833 7.19371,40.345143 z M 111.18953,172.59017 84.08484,156.94511 c -0.291773,-0.14086 -0.482934,-0.42257 -0.523179,-0.74453 V 81.355816 c 0.02012,-33.322473 27.054379,-60.326555 60.376859,-60.306432 14.09564,0 27.73854,4.950077 38.57438,13.964853 -0.493,0.261589 -1.33813,0.734462 -1.90155,1.076541 l -64.10954,37.02497 c -3.27993,1.86131 -5.29216,5.342462 -5.27204,9.115387 l -0.0402,90.338915 z m 14.71943,-31.73282 34.86183,-20.13232 34.86183,20.12226 v 40.2546 l -34.86183,20.12226 -34.86183,-20.12226 z"
id="path1"
style="stroke-width:1.00611" />
</svg>

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
fill="#000000"
height="20.000002"
width="20"
version="1.1"
id="Capa_1"
viewBox="0 0 493.42511 493.42516"
xml:space="preserve"
sodipodi:docname="ubuntu-logo-svgrepo-com.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
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="defs9" /><sodipodi:namedview
id="namedview9"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="12.374369"
inkscape:cx="24.76894"
inkscape:cy="15.515943"
inkscape:window-width="1415"
inkscape:window-height="753"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="ubuntu"
transform="translate(5.5573583e-4,0.00107926)">
<g
id="g2">
<g
id="g1">
<path
d="m 168.839,241.198 c 0,-38.117 17.894,-72.05 45.685,-93.896 L 171.988,79.22 c -35.648,25.603 -62.472,62.66 -75.127,105.796 19.811,12.751 32.949,35.031 32.949,60.353 0,24.424 -12.143,45.957 -30.783,58.918 13.606,40.86 40.12,75.838 74.706,100.113 l 39.559,-70.358 c -27.105,-21.838 -44.453,-55.318 -44.453,-92.844 z"
id="path1" />
</g>
</g>
<g
id="g3">
<path
d="m 109.704,245.368 c 0,28.484 -23.132,51.592 -51.609,51.592 -28.491,0 -51.606,-23.107 -51.606,-51.592 0,-28.47 23.115,-51.577 51.606,-51.577 28.477,0 51.609,23.107 51.609,51.577 z"
id="path2" />
</g>
<g
id="g5">
<g
id="g4">
<path
d="m 399.494,370.126 c 12.002,0 23.301,2.936 33.23,8.149 30.924,-32.591 50.906,-75.595 54.211,-123.228 l -80.148,-1.551 c -6.171,60.111 -56.954,106.941 -118.677,106.941 -17.084,0 -33.388,-3.594 -48.101,-10.093 l -39.841,69.704 c 26.56,13.069 56.376,20.411 87.941,20.411 13.622,0 26.981,-1.379 39.854,-4.006 2.746,-37.072 33.717,-66.327 71.531,-66.327 z"
id="path3" />
</g>
</g>
<g
id="g6">
<path
d="m 451.071,441.847 c 0,28.478 -23.084,51.576 -51.577,51.576 -28.493,0 -51.594,-23.098 -51.594,-51.576 0,-28.5 23.101,-51.592 51.594,-51.592 28.493,0 51.577,23.092 51.577,51.592 z"
id="path5" />
</g>
<g
id="g8">
<g
id="g7">
<path
d="m 438.211,110.152 c -11.677,8.269 -25.968,13.163 -41.399,13.163 -39.637,0 -71.73,-32.102 -71.73,-71.715 0,-2.104 0.094,-4.139 0.25,-6.181 -12.05,-2.307 -24.503,-3.491 -37.222,-3.491 -31.859,0 -61.988,7.498 -88.689,20.777 l 39.607,69.75 c 14.979,-6.748 31.593,-10.544 49.082,-10.544 61.177,0 111.601,46.074 118.491,105.414 l 80.147,-2.447 C 483.209,181.12 465.487,141.372 438.211,110.152 Z"
id="path6" />
</g>
</g>
<g
id="g9">
<path
d="m 448.374,51.601 c 0,28.492 -23.038,51.592 -51.561,51.592 -28.491,0 -51.592,-23.1 -51.592,-51.592 C 345.22,23.107 368.321,0 396.812,0 c 28.523,0 51.562,23.107 51.562,51.601 z"
id="path8" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -1,21 +1,70 @@
const main = "/tmp/ags/main.js"; "use strict";
// Import
import Gdk from 'gi://Gdk';
import App from 'resource:///com/github/Aylur/ags/app.js'
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
// Widgets
import { Bar, BarCornerTopleft, BarCornerTopright } from './widgets/bar/main.js';
import Cheatsheet from './widgets/cheatsheet/main.js';
// import DesktopBackground from './widgets/desktopbackground/main.js';
// import Dock from './widgets/dock/main.js';
import Corner from './widgets/screencorners/main.js';
import Indicator from './widgets/indicators/main.js';
import Osk from './widgets/onscreenkeyboard/main.js';
import Overview from './widgets/overview/main.js';
import Session from './widgets/session/main.js';
import SideLeft from './widgets/sideleft/main.js';
import SideRight from './widgets/sideright/main.js';
try { const range = (length, start = 1) => Array.from({ length }, (_, i) => i + start);
await Utils.execAsync([ function forMonitors(widget) {
"bun", const n = Gdk.Display.get_default()?.get_n_monitors() || 1;
"build", return range(n, 0).map(widget).flat(1);
`${App.configDir}/main.ts`,
"--outfile",
main,
"--external",
"resource://*",
"--external",
"gi://*",
"--external",
"file://*",
]);
await import(`file://${main}`);
} catch (error) {
console.error(error);
App.quit();
} }
// SCSS compilation
Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicwal.scss'`); // reset music styles
Utils.exec(`bash -c 'echo "" > ${App.configDir}/scss/_musicmaterial.scss'`); // reset music styles
function applyStyle() {
Utils.exec(`sassc ${App.configDir}/scss/main.scss ${App.configDir}/style.css`);
App.resetCss();
App.applyCss(`${App.configDir}/style.css`);
console.log('[LOG] Styles loaded')
}
applyStyle();
const Windows = () => [
// forMonitors(DesktopBackground),
// Dock(),
Overview(),
forMonitors(Indicator),
Cheatsheet(),
SideLeft(),
SideRight(),
Osk(),
Session(),
// forMonitors(Bar),
// forMonitors(BarCornerTopleft),
// forMonitors(BarCornerTopright),
forMonitors((id) => Corner(id, 'top left')),
forMonitors((id) => Corner(id, 'top right')),
forMonitors((id) => Corner(id, 'bottom left')),
forMonitors((id) => Corner(id, 'bottom right')),
];
const CLOSE_ANIM_TIME = 210; // Longer than actual anim time to make sure widgets animate fully
export default {
css: `${App.configDir}/style.css`,
stackTraceOnError: true,
closeWindowDelay: { // For animations
'sideright': CLOSE_ANIM_TIME,
'sideleft': CLOSE_ANIM_TIME,
'osk': CLOSE_ANIM_TIME,
},
windows: Windows().flat(1),
};
// Stuff that don't need to be toggled. And they're async so ugh...
// Bar().catch(print); // Use this to debug the bar. Single monitor only.
forMonitors(Bar);
forMonitors(BarCornerTopleft);
forMonitors(BarCornerTopright);

View file

@ -0,0 +1,135 @@
export const keybindList = [[
{
"icon": "pin_drop",
"name": "Workspaces: navigation",
"binds": [
{ "keys": ["", "+", "#"], "action": "Go to workspace #" },
{ "keys": ["", "+", "S"], "action": "Toggle special workspace" },
{ "keys": ["", "+", "(Scroll ↑↓)"], "action": "Go to workspace -1/+1" },
{ "keys": ["Ctrl", "", "+", "←"], "action": "Go to workspace on the left" },
{ "keys": ["Ctrl", "", "+", "→"], "action": "Go to workspace on the right" },
{ "keys": ["", "+", "PageUp"], "action": "Go to workspace on the left" },
{ "keys": ["", "+", "PageDown"], "action": "Go to workspace on the right" }
],
"appeartick": 1
},
{
"icon": "overview_key",
"name": "Workspaces: management",
"binds": [
{ "keys": ["", "Alt", "+", "#"], "action": "Move window to workspace #" },
{ "keys": ["", "Alt", "+", "S"], "action": "Move window to special workspace" },
{ "keys": ["", "Alt", "+", "PageUp"], "action": "Move window to workspace on the left" },
{ "keys": ["", "Alt", "+", "PageDown"], "action": "Move window to workspace on the right" }
],
"appeartick": 1
},
{
"icon": "move_group",
"name": "Windows",
"binds": [
{ "keys": ["", "+", "←↑→↓"], "action": "Focus window in direction" },
{ "keys": ["", "Shift", "+", "←↑→↓"], "action": "Swap window in direction" },
{ "keys": ["", "+", ";"], "action": "Split ratio -" },
{ "keys": ["", "+", "'"], "action": "Split ratio +" },
{ "keys": ["", "+", "Lmb"], "action": "Move window" },
{ "keys": ["", "+", "Mmb"], "action": "Move window" },
{ "keys": ["", "+", "Rmb"], "action": "Resize window" },
{ "keys": ["", "+", "F"], "action": "Fullscreen" },
{ "keys": ["", "Alt", "+", "F"], "action": "Fake fullscreen" }
],
"appeartick": 1
}
],
[
{
"icon": "widgets",
"name": "Widgets (AGS)",
"binds": [
{ "keys": ["", "OR", "", "+", "Tab"], "action": "Toggle overview/launcher" },
{ "keys": ["Ctrl", "", "+", "R"], "action": "Restart AGS" },
{ "keys": ["", "+", "/"], "action": "Toggle this cheatsheet" },
{ "keys": ["", "+", "N"], "action": "Toggle system sidebar" },
{ "keys": ["", "+", "B", "OR", "", "+", "O"], "action": "Toggle utilities sidebar" },
{ "keys": ["", "+", "K"], "action": "Toggle virtual keyboard" },
{ "keys": ["Ctrl", "Alt", "+", "Del"], "action": "Power/Session menu" },
{ "keys": ["Esc"], "action": "Exit a window" },
{ "keys": ["rightCtrl"], "action": "Dismiss/close sidebar" },
{ "keys": ["Ctrl", "", "+", "T"], "action": "Change wallpaper+colorscheme" },
// { "keys": ["", "+", "B"], "action": "Toggle left sidebar" },
// { "keys": ["", "+", "N"], "action": "Toggle right sidebar" },
// { "keys": ["", "+", "G"], "action": "Toggle volume mixer" },
// { "keys": ["", "+", "M"], "action": "Toggle useless audio visualizer" },
// { "keys": ["(right)Ctrl"], "action": "Dismiss notification & close menus" }
],
"appeartick": 2
},
{
"icon": "construction",
"name": "Utilities",
"binds": [
{ "keys": ["PrtSc"], "action": "Screenshot >> clipboard" },
{ "keys": ["", "Shift", "+", "S"], "action": "Screen snip >> clipboard" },
{ "keys": ["", "Shift", "+", "T"], "action": "Image to text >> clipboard" },
{ "keys": ["", "Shift", "+", "C"], "action": "Color picker" },
{ "keys": ["", "Alt", "+", "R"], "action": "Record region" },
{ "keys": ["Ctrl", "Alt", "+", "R"], "action": "Record region with sound" },
{ "keys": ["", "Shift", "Alt", "+", "R"], "action": "Record screen with sound" }
],
"appeartick": 2
},
// {
// "icon": "edit",
// "name": "Edit mode",
// "binds": [
// { "keys": ["Esc"], "action": "Exit Edit mode" },
// { "keys": ["#"], "action": "Go to to workspace #" },
// { "keys": ["Alt", "+", "#"], "action": "Dump windows to workspace #" },
// { "keys": ["Shift", "+", "#"], "action": "Swap windows with workspace #" },
// { "keys": ["Lmb"], "action": "Move window" },
// { "keys": ["Mmb"], "action": "Move window" },
// { "keys": ["Rmb"], "action": "Resize window" }
// ],
// "appeartick": 2
// }
],
[
{
"icon": "apps",
"name": "Apps",
"binds": [
{ "keys": ["", "+", "T"], "action": "Launch terminal: foot" },
{ "keys": ["", "+", "W"], "action": "Launch browser: Firefox" },
{ "keys": ["", "+", "C"], "action": "Launch editor: vscode" },
{ "keys": ["", "+", "X"], "action": "Launch editor: GNOME Text Editor" },
{ "keys": ["", "+", "I"], "action": "Launch settings: GNOME Control center" }
],
"appeartick": 3
},
{
"icon": "keyboard",
"name": "Typing",
"binds": [
{ "keys": ["", "+", "V"], "action": "Clipboard history >> clipboard" },
{ "keys": ["", "+", "."], "action": "Emoji picker >> clipboard" },
],
"appeartick": 3
},
{
"icon": "terminal",
"name": "Launcher actions",
"binds": [
{ "keys": [">raw"], "action": "Toggle mouse acceleration" },
{ "keys": [">img"], "action": "Select wallpaper and generate colorscheme" },
{ "keys": [">light"], "action": "Switch to light theme" },
{ "keys": [">dark"], "action": "Switch to dark theme" },
{ "keys": [">badapple"], "action": "Apply black n' white colorscheme" },
{ "keys": [">color"], "action": "Pick acccent color" },
{ "keys": [">todo"], "action": "Type something after that to add a To-do item" },
],
"appeartick": 3
}
]];

View file

@ -0,0 +1,218 @@
// We're going to use ydotool
// See /usr/include/linux/input-event-codes.h for keycodes
export const defaultOskLayout = "qwerty_full"
export const oskLayouts = {
qwerty_full: {
name: "QWERTY - Full",
name_short: "US",
comment: "Like physical keyboard",
// A key looks like this: { k: "a", ks: "A", t: "normal" } (key, key-shift, type)
// key types are: normal, tab, caps, shift, control, fn (normal w/ half height), space, expand
// keys: [
// [{ k: "Esc", t: "fn" }, { k: "F1", t: "fn" }, { k: "F2", t: "fn" }, { k: "F3", t: "fn" }, { k: "F4", t: "fn" }, { k: "F5", t: "fn" }, { k: "F6", t: "fn" }, { k: "F7", t: "fn" }, { k: "F8", t: "fn" }, { k: "F9", t: "fn" }, { k: "F10", t: "fn" }, { k: "F11", t: "fn" }, { k: "F12", t: "fn" }, { k: "PrtSc", t: "fn" }, { k: "Del", t: "fn" }],
// [{ k: "`", ks: "~", t: "normal" }, { k: "1", ks: "!", t: "normal" }, { k: "2", ks: "@", t: "normal" }, { k: "3", ks: "#", t: "normal" }, { k: "4", ks: "$", t: "normal" }, { k: "5", ks: "%", t: "normal" }, { k: "6", ks: "^", t: "normal" }, { k: "7", ks: "&", t: "normal" }, { k: "8", ks: "*", t: "normal" }, { k: "9", ks: "(", t: "normal" }, { k: "0", ks: ")", t: "normal" }, { k: "-", ks: "_", t: "normal" }, { k: "=", ks: "+", t: "normal" }, { k: "Backspace", t: "shift" }],
// [{ k: "Tab", t: "tab" }, { k: "q", ks: "Q", t: "normal" }, { k: "w", ks: "W", t: "normal" }, { k: "e", ks: "E", t: "normal" }, { k: "r", ks: "R", t: "normal" }, { k: "t", ks: "T", t: "normal" }, { k: "y", ks: "Y", t: "normal" }, { k: "u", ks: "U", t: "normal" }, { k: "i", ks: "I", t: "normal" }, { k: "o", ks: "O", t: "normal" }, { k: "p", ks: "P", t: "normal" }, { k: "[", ks: "{", t: "normal" }, { k: "]", ks: "}", t: "normal" }, { k: "\\", ks: "|", t: "expand" }],
// [{ k: "Caps", t: "caps" }, { k: "a", ks: "A", t: "normal" }, { k: "s", ks: "S", t: "normal" }, { k: "d", ks: "D", t: "normal" }, { k: "f", ks: "F", t: "normal" }, { k: "g", ks: "G", t: "normal" }, { k: "h", ks: "H", t: "normal" }, { k: "j", ks: "J", t: "normal" }, { k: "k", ks: "K", t: "normal" }, { k: "l", ks: "L", t: "normal" }, { k: ";", ks: ":", t: "normal" }, { k: "'", ks: '"', t: "normal" }, { k: "Enter", t: "expand" }],
// [{ k: "Shift", t: "shift" }, { k: "z", ks: "Z", t: "normal" }, { k: "x", ks: "X", t: "normal" }, { k: "c", ks: "C", t: "normal" }, { k: "v", ks: "V", t: "normal" }, { k: "b", ks: "B", t: "normal" }, { k: "n", ks: "N", t: "normal" }, { k: "m", ks: "M", t: "normal" }, { k: ",", ks: "<", t: "normal" }, { k: ".", ks: ">", t: "normal" }, { k: "/", ks: "?", t: "normal" }, { k: "Shift", t: "expand" }],
// [{ k: "Ctrl", t: "control" }, { k: "Fn", t: "normal" }, { k: "Win", t: "normal" }, { k: "Alt", t: "normal" }, { k: "Space", t: "space" }, { k: "Alt", t: "normal" }, { k: "Menu", t: "normal" }, { k: "Ctrl", t: "control" }]
// ]
// A normal key looks like this: {label: "a", labelShift: "A", shape: "normal", keycode: 30, type: "normal"}
// A modkey looks like this: {label: "Ctrl", shape: "control", keycode: 29, type: "modkey"}
// key types are: normal, tab, caps, shift, control, fn (normal w/ half height), space, expand
keys: [
[
{ keytype: "normal", label: "Esc", shape: "fn", keycode: 1 },
{ keytype: "normal", label: "F1", shape: "fn", keycode: 59 },
{ keytype: "normal", label: "F2", shape: "fn", keycode: 60 },
{ keytype: "normal", label: "F3", shape: "fn", keycode: 61 },
{ keytype: "normal", label: "F4", shape: "fn", keycode: 62 },
{ keytype: "normal", label: "F5", shape: "fn", keycode: 63 },
{ keytype: "normal", label: "F6", shape: "fn", keycode: 64 },
{ keytype: "normal", label: "F7", shape: "fn", keycode: 65 },
{ keytype: "normal", label: "F8", shape: "fn", keycode: 66 },
{ keytype: "normal", label: "F9", shape: "fn", keycode: 67 },
{ keytype: "normal", label: "F10", shape: "fn", keycode: 68 },
{ keytype: "normal", label: "F11", shape: "fn", keycode: 87 },
{ keytype: "normal", label: "F12", shape: "fn", keycode: 88 },
{ keytype: "normal", label: "PrtSc", shape: "fn", keycode: 99 },
{ keytype: "normal", label: "Del", shape: "fn", keycode: 111 }
],
[
{ keytype: "normal", label: "`", labelShift: "~", shape: "normal", keycode: 41 },
{ keytype: "normal", label: "1", labelShift: "!", shape: "normal", keycode: 2 },
{ keytype: "normal", label: "2", labelShift: "@", shape: "normal", keycode: 3 },
{ keytype: "normal", label: "3", labelShift: "#", shape: "normal", keycode: 4 },
{ keytype: "normal", label: "4", labelShift: "$", shape: "normal", keycode: 5 },
{ keytype: "normal", label: "5", labelShift: "%", shape: "normal", keycode: 6 },
{ keytype: "normal", label: "6", labelShift: "^", shape: "normal", keycode: 7 },
{ keytype: "normal", label: "7", labelShift: "&", shape: "normal", keycode: 8 },
{ keytype: "normal", label: "8", labelShift: "*", shape: "normal", keycode: 9 },
{ keytype: "normal", label: "9", labelShift: "(", shape: "normal", keycode: 10 },
{ keytype: "normal", label: "0", labelShift: ")", shape: "normal", keycode: 11 },
{ keytype: "normal", label: "-", labelShift: "_", shape: "normal", keycode: 12 },
{ keytype: "normal", label: "=", labelShift: "+", shape: "normal", keycode: 13 },
{ keytype: "normal", label: "Backspace", shape: "expand", keycode: 14 }
],
[
{ keytype: "normal", label: "Tab", shape: "tab", keycode: 15 },
{ keytype: "normal", label: "q", labelShift: "Q", shape: "normal", keycode: 16 },
{ keytype: "normal", label: "w", labelShift: "W", shape: "normal", keycode: 17 },
{ keytype: "normal", label: "e", labelShift: "E", shape: "normal", keycode: 18 },
{ keytype: "normal", label: "r", labelShift: "R", shape: "normal", keycode: 19 },
{ keytype: "normal", label: "t", labelShift: "T", shape: "normal", keycode: 20 },
{ keytype: "normal", label: "y", labelShift: "Y", shape: "normal", keycode: 21 },
{ keytype: "normal", label: "u", labelShift: "U", shape: "normal", keycode: 22 },
{ keytype: "normal", label: "i", labelShift: "I", shape: "normal", keycode: 23 },
{ keytype: "normal", label: "o", labelShift: "O", shape: "normal", keycode: 24 },
{ keytype: "normal", label: "p", labelShift: "P", shape: "normal", keycode: 25 },
{ keytype: "normal", label: "[", labelShift: "{", shape: "normal", keycode: 26 },
{ keytype: "normal", label: "]", labelShift: "}", shape: "normal", keycode: 27 },
{ keytype: "normal", label: "\\", labelShift: "|", shape: "expand", keycode: 43 }
],
[
//{ keytype: "normal", label: "Caps", shape: "caps", keycode: 58 }, // not needed as double-pressing shift does that
{ keytype: "spacer", label: "", shape: "empty" },
{ keytype: "spacer", label: "", shape: "empty" },
{ keytype: "normal", label: "a", labelShift: "A", shape: "normal", keycode: 30 },
{ keytype: "normal", label: "s", labelShift: "S", shape: "normal", keycode: 31 },
{ keytype: "normal", label: "d", labelShift: "D", shape: "normal", keycode: 32 },
{ keytype: "normal", label: "f", labelShift: "F", shape: "normal", keycode: 33 },
{ keytype: "normal", label: "g", labelShift: "G", shape: "normal", keycode: 34 },
{ keytype: "normal", label: "h", labelShift: "H", shape: "normal", keycode: 35 },
{ keytype: "normal", label: "j", labelShift: "J", shape: "normal", keycode: 36 },
{ keytype: "normal", label: "k", labelShift: "K", shape: "normal", keycode: 37 },
{ keytype: "normal", label: "l", labelShift: "L", shape: "normal", keycode: 38 },
{ keytype: "normal", label: ";", labelShift: ":", shape: "normal", keycode: 39 },
{ keytype: "normal", label: "'", labelShift: '"', shape: "normal", keycode: 40 },
{ keytype: "normal", label: "Enter", shape: "expand", keycode: 28 }
],
[
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "shift", keycode: 42 },
{ keytype: "normal", label: "z", labelShift: "Z", shape: "normal", keycode: 44 },
{ keytype: "normal", label: "x", labelShift: "X", shape: "normal", keycode: 45 },
{ keytype: "normal", label: "c", labelShift: "C", shape: "normal", keycode: 46 },
{ keytype: "normal", label: "v", labelShift: "V", shape: "normal", keycode: 47 },
{ keytype: "normal", label: "b", labelShift: "B", shape: "normal", keycode: 48 },
{ keytype: "normal", label: "n", labelShift: "N", shape: "normal", keycode: 49 },
{ keytype: "normal", label: "m", labelShift: "M", shape: "normal", keycode: 50 },
{ keytype: "normal", label: ",", labelShift: "<", shape: "normal", keycode: 51 },
{ keytype: "normal", label: ".", labelShift: ">", shape: "normal", keycode: 52 },
{ keytype: "normal", label: "/", labelShift: "?", shape: "normal", keycode: 53 },
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "expand", keycode: 54 } // optional
],
[
{ keytype: "modkey", label: "Ctrl", shape: "control", keycode: 29 },
// { label: "Super", shape: "normal", keycode: 125 }, // dangerous
{ keytype: "modkey", label: "Alt", shape: "normal", keycode: 56 },
{ keytype: "normal", label: "Space", shape: "space", keycode: 57 },
{ keytype: "modkey", label: "Alt", shape: "normal", keycode: 100 },
// { label: "Super", shape: "normal", keycode: 126 }, // dangerous
{ keytype: "normal", label: "Menu", shape: "normal", keycode: 139 },
{ keytype: "modkey", label: "Ctrl", shape: "control", keycode: 97 }
]
]
},
qwertz_full: {
name: "QWERTZ - Full",
name_short: "DE",
comment: "Keyboard layout commonly used in German-speaking countries",
keys: [
[
{ keytype: "normal", label: "Esc", shape: "fn", keycode: 1 },
{ keytype: "normal", label: "F1", shape: "fn", keycode: 59 },
{ keytype: "normal", label: "F2", shape: "fn", keycode: 60 },
{ keytype: "normal", label: "F3", shape: "fn", keycode: 61 },
{ keytype: "normal", label: "F4", shape: "fn", keycode: 62 },
{ keytype: "normal", label: "F5", shape: "fn", keycode: 63 },
{ keytype: "normal", label: "F6", shape: "fn", keycode: 64 },
{ keytype: "normal", label: "F7", shape: "fn", keycode: 65 },
{ keytype: "normal", label: "F8", shape: "fn", keycode: 66 },
{ keytype: "normal", label: "F9", shape: "fn", keycode: 67 },
{ keytype: "normal", label: "F10", shape: "fn", keycode: 68 },
{ keytype: "normal", label: "F11", shape: "fn", keycode: 87 },
{ keytype: "normal", label: "F12", shape: "fn", keycode: 88 },
{ keytype: "normal", label: "Druck", shape: "fn", keycode: 99 },
{ keytype: "normal", label: "Entf", shape: "fn", keycode: 111 }
],
[
{ keytype: "normal", label: "^", labelShift: "°", labelAlt: "", shape: "normal", keycode: 41 },
{ keytype: "normal", label: "1", labelShift: "!", labelAlt: "¹", shape: "normal", keycode: 2 },
{ keytype: "normal", label: "2", labelShift: "\"", labelAlt: "²", shape: "normal", keycode: 3 },
{ keytype: "normal", label: "3", labelShift: "§", labelAlt: "³", shape: "normal", keycode: 4 },
{ keytype: "normal", label: "4", labelShift: "$", labelAlt: "¼", shape: "normal", keycode: 5 },
{ keytype: "normal", label: "5", labelShift: "%", labelAlt: "½", shape: "normal", keycode: 6 },
{ keytype: "normal", label: "6", labelShift: "&", labelAlt: "¬", shape: "normal", keycode: 7 },
{ keytype: "normal", label: "7", labelShift: "/", labelAlt: "{", shape: "normal", keycode: 8 },
{ keytype: "normal", label: "8", labelShift: "(", labelAlt: "[", shape: "normal", keycode: 9 },
{ keytype: "normal", label: "9", labelShift: ")", labelAlt: "]", shape: "normal", keycode: 10 },
{ keytype: "normal", label: "0", labelShift: "=", labelAlt: "}", shape: "normal", keycode: 11 },
{ keytype: "normal", label: "ß", labelShift: "?", labelAlt: "\\", shape: "normal", keycode: 12 },
{ keytype: "normal", label: "´", labelShift: "`", labelAlt: "¸", shape: "normal", keycode: 13 },
{ keytype: "normal", label: "⟵", shape: "expand", keycode: 14 }
],
[
{ keytype: "normal", label: "Tab ⇆", shape: "tab", keycode: 15 },
{ keytype: "normal", label: "q", labelShift: "Q", labelAlt: "@", shape: "normal", keycode: 16 },
{ keytype: "normal", label: "w", labelShift: "W", labelAlt: "ſ", shape: "normal", keycode: 17 },
{ keytype: "normal", label: "e", labelShift: "E", labelAlt: "€", shape: "normal", keycode: 18 },
{ keytype: "normal", label: "r", labelShift: "R", labelAlt: "¶", shape: "normal", keycode: 19 },
{ keytype: "normal", label: "t", labelShift: "T", labelAlt: "ŧ", shape: "normal", keycode: 20 },
{ keytype: "normal", label: "z", labelShift: "Z", labelAlt: "←", shape: "normal", keycode: 21 },
{ keytype: "normal", label: "u", labelShift: "U", labelAlt: "↓", shape: "normal", keycode: 22 },
{ keytype: "normal", label: "i", labelShift: "I", labelAlt: "→", shape: "normal", keycode: 23 },
{ keytype: "normal", label: "o", labelShift: "O", labelAlt: "ø", shape: "normal", keycode: 24 },
{ keytype: "normal", label: "p", labelShift: "P", labelAlt: "þ", shape: "normal", keycode: 25 },
{ keytype: "normal", label: "ü", labelShift: "Ü", labelAlt: "¨", shape: "normal", keycode: 26 },
{ keytype: "normal", label: "+", labelShift: "*", labelAlt: "~", shape: "normal", keycode: 27 },
{ keytype: "normal", label: "↵", shape: "expand", keycode: 28 }
],
[
//{ keytype: "normal", label: "Umschalt ⇩", shape: "caps", keycode: 58 },
{ keytype: "spacer", label: "", shape: "empty" },
{ keytype: "spacer", label: "", shape: "empty" },
{ keytype: "normal", label: "a", labelShift: "A", labelAlt: "æ", shape: "normal", keycode: 30 },
{ keytype: "normal", label: "s", labelShift: "S", labelAlt: "ſ", shape: "normal", keycode: 31 },
{ keytype: "normal", label: "d", labelShift: "D", labelAlt: "ð", shape: "normal", keycode: 32 },
{ keytype: "normal", label: "f", labelShift: "F", labelAlt: "đ", shape: "normal", keycode: 33 },
{ keytype: "normal", label: "g", labelShift: "G", labelAlt: "ŋ", shape: "normal", keycode: 34 },
{ keytype: "normal", label: "h", labelShift: "H", labelAlt: "ħ", shape: "normal", keycode: 35 },
{ keytype: "normal", label: "j", labelShift: "J", labelAlt: "", shape: "normal", keycode: 36 },
{ keytype: "normal", label: "k", labelShift: "K", labelAlt: "ĸ", shape: "normal", keycode: 37 },
{ keytype: "normal", label: "l", labelShift: "L", labelAlt: "ł", shape: "normal", keycode: 38 },
{ keytype: "normal", label: "ö", labelShift: "Ö", labelAlt: "˝", shape: "normal", keycode: 39 },
{ keytype: "normal", label: "ä", labelShift: 'Ä', labelAlt: "^", shape: "normal", keycode: 40 },
{ keytype: "normal", label: "#", labelShift: '\'', labelAlt: "", shape: "normal", keycode: 43 },
{ keytype: "spacer", label: "", shape: "empty" },
//{ keytype: "normal", label: "↵", shape: "expand", keycode: 28 }
],
[
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "shift", keycode: 42 },
{ keytype: "normal", label: "<", labelShift: ">", labelAlt: "|", shape: "normal", keycode: 86 },
{ keytype: "normal", label: "y", labelShift: "Y", labelAlt: "»", shape: "normal", keycode: 44 },
{ keytype: "normal", label: "x", labelShift: "X", labelAlt: "«", shape: "normal", keycode: 45 },
{ keytype: "normal", label: "c", labelShift: "C", labelAlt: "¢", shape: "normal", keycode: 46 },
{ keytype: "normal", label: "v", labelShift: "V", labelAlt: "„", shape: "normal", keycode: 47 },
{ keytype: "normal", label: "b", labelShift: "B", labelAlt: "“", shape: "normal", keycode: 48 },
{ keytype: "normal", label: "n", labelShift: "N", labelAlt: "”", shape: "normal", keycode: 49 },
{ keytype: "normal", label: "m", labelShift: "M", labelAlt: "µ", shape: "normal", keycode: 50 },
{ keytype: "normal", label: ",", labelShift: ";", labelAlt: "·", shape: "normal", keycode: 51 },
{ keytype: "normal", label: ".", labelShift: ":", labelAlt: "…", shape: "normal", keycode: 52 },
{ keytype: "normal", label: "-", labelShift: "_", labelAlt: "", shape: "normal", keycode: 53 },
{ keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "expand", keycode: 54 }, // optional
],
[
{ keytype: "modkey", label: "Strg", shape: "control", keycode: 29 },
//{ keytype: "normal", label: "", shape: "normal", keycode: 125 }, // dangerous
{ keytype: "modkey", label: "Alt", shape: "normal", keycode: 56 },
{ keytype: "normal", label: "Leertaste", shape: "space", keycode: 57 },
{ keytype: "modkey", label: "AltGr", shape: "normal", keycode: 100 },
// { label: "Super", shape: "normal", keycode: 126 }, // dangerous
//{ keytype: "normal", label: "Menu", shape: "normal", keycode: 139 }, // doesn't work?
{ keytype: "modkey", label: "Strg", shape: "control", keycode: 97 },
{ keytype: "normal", label: "⇦", shape: "normal", keycode: 105 },
{ keytype: "normal", label: "⇨", shape: "normal", keycode: 106 },
]
]
}
}

View file

@ -0,0 +1,62 @@
// For keyboard layout in lib/statusicons.js
// This list is not exhaustive. It just includes known/possible languages of users of my dotfiles
// Add your language here if you use multi-lang xkb input. Else, ignore
// Note that something like "French (Canada)" should go before "French"
// and "English (US)" should go before "English"
export const languages = [
{
layout: 'us',
name: 'English (US)',
flag: '🇺🇸'
},
{
layout: 'ru',
name: 'Russian',
flag: '🇷🇺',
},
{
layout: 'pl',
name: 'Polish',
flag: '🇷🇵🇵🇱',
},
{
layout: 'ro',
name: 'Romanian',
flag: '🇷🇴',
},
{
layout: 'ca',
name: 'French (Canada)',
flag: '🇫🇷',
},
{
layout: 'fr',
name: 'French',
flag: '🇫🇷',
},
{
layout: 'tr',
name: 'Turkish',
flag: '🇹🇷',
},
{
layout: 'jp',
name: 'Japanese',
flag: '🇯🇵',
},
{
layout: 'cn',
name: 'Chinese',
flag: '🇨🇳',
},
{
layout: 'vn',
name: 'Vietnamese',
flag: '🇻🇳',
},
{
layout: 'undef',
name: 'Undefined',
flag: '🧐',
},
]

View file

@ -0,0 +1,14 @@
export const quickLaunchItems = [
{
"name": "GitHub + Files×2",
"command": "github-desktop & nautilus --new-window & nautilus --new-window &"
},
{
"name": "Terminal×2",
"command": "foot & foot &"
},
{
"name": "Discord + Youtube + Github",
"command": "xdg-open 'https://discord.com/app' && xdg-open 'https://youtube.com/' && xdg-open 'https://github.com/' &"
},
]

View file

@ -0,0 +1,14 @@
export const quotes = [
{
quote: 'Nvidia, fuck you',
author: 'Linus Torvalds',
},
{
quote: 'reproducible system? cock and vagina?',
author: 'vaxry',
},
{
quote: "haha pointers hee hee i love pointe-\\\nProcess Vaxry exited with signal SIGSEGV",
author: 'vaxry',
}
];

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<style-scheme id="custom" _name="Custom" version="1.0">
<author>end_4</author>
<_description>Monokai port but very random</_description>
<!-- The scheme tries to look like the default GVim scheme,
since it is also what the hardwired GtkSourceView 1 color
scheme did -->
<!-- Palette -->
<color name="white" value="#F8F8F2"/>
<color name="blue" value="#179FFF"/>
<color name="magenta" value="#DA70D6"/>
<color name="violet" value="#AA7FF9"/>
<color name="cyan" value="#66D9EF"/>
<color name="grey" value="#817D69"/>
<color name="green" value="#A0D82E"/>
<color name="bordeaux" value="#B22757"/>
<color name="red" value="#F92672"/>
<color name="yellow" value="#E4D973"/>
<color name="purple" value="#A47AEE"/>
<color name="onSuccess" value="#D1E8D5"/>
<color name="success" value="#213528"/>
<color name="onError" value="#ffb4a9"/>
<color name="error" value="#680003"/>
<!-- Global Settings -->
<style name="current-line" background="#3E3D32"/>
<style name="current-line-number" background="#eeeeec"/>
<style name="draw-spaces" foreground="#babdb6"/>
<style name="background-pattern" background="#000000"/>
<!-- Bracket Matching -->
<!-- <style name="bracket-match" foreground="white" background="grey"/> -->
<!-- <style name="bracket-mismatch" foreground="white" background="red"/> -->
<!-- Right Margin -->
<style name="right-margin" foreground="#000000" background="#000000"/>
<!-- Search Matching -->
<style name="search-match" background="yellow"/>
<!-- Comments -->
<style name="def:comment" foreground="grey" italic="true"/>
<style name="def:shebang" foreground="grey" bold="true"/>
<style name="def:doc-comment-element" italic="true"/>
<!-- Constants -->
<style name="def:constant" foreground="white"/>
<style name="def:special-char" foreground="yellow"/>
<!-- Identifiers -->
<style name="def:identifier" foreground="green"/>
<!-- Statements -->
<style name="def:statement" foreground="cyan" bold="true"/>
<!-- Types -->
<style name="def:type" foreground="cyan" bold="true"/>
<!-- Others -->
<style name="def:preprocessor" foreground="purple"/>
<style name="def:error" background="red" bold="true"/>
<style name="def:warning" background="yellow"/>
<style name="def:note" foreground="bordeaux" bold="true"/>
<style name="def:underlined" italic="true" underline="single"/>
<!-- Heading styles, uncomment to enable -->
<!--
<style name="def:heading0" scale="5.0"/>
<style name="def:heading1" scale="2.5"/>
<style name="def:heading2" scale="2.0"/>
<style name="def:heading3" scale="1.7"/>
<style name="def:heading4" scale="1.5"/>
<style name="def:heading5" scale="1.3"/>
<style name="def:heading6" scale="1.2"/>
-->
<!-- Language specific styles -->
<style name="diff:added-line" background="success" foreground="onSuccess"/>
<style name="diff:removed-line" background="error" foreground="onError"/>
<style name="diff:changed-line" use-style="def:preprocessor"/>
<style name="diff:special-case" use-style="def:constant"/>
<style name="diff:location" use-style="def:statement"/>
<style name="diff:diff-file" use-style="def:type"/>
<style name="xml:tags" foreground="red"/>
<style name="xml:attribute-name" foreground="green"/>
<style name="xml:namespace" foreground="cyan" bold="true"/>
<style name="js:object" foreground="cyan" bold="true"/>
<style name="js:constructors" foreground="cyan"/>
<style name="latex:display-math" foreground="purple"/>
<style name="latex:command" foreground="green" bold="true"/>
<style name="latex:include" use-style="def:preprocessor"/>
<style name="sh:variable" foreground="purple"/>
<!-- legacy styles for old lang files -->
<style name="Others" foreground="cyan" bold="true"/>
<style name="Others 2" foreground="cyan"/>
<style name="Others 3" foreground="purple"/>
</style-scheme>

View file

@ -0,0 +1,94 @@
export const WWO_CODE = {
"113": "Sunny",
"116": "PartlyCloudy",
"119": "Cloudy",
"122": "VeryCloudy",
"143": "Fog",
"176": "LightShowers",
"179": "LightSleetShowers",
"182": "LightSleet",
"185": "LightSleet",
"200": "ThunderyShowers",
"227": "LightSnow",
"230": "HeavySnow",
"248": "Fog",
"260": "Fog",
"263": "LightShowers",
"266": "LightRain",
"281": "LightSleet",
"284": "LightSleet",
"293": "LightRain",
"296": "LightRain",
"299": "HeavyShowers",
"302": "HeavyRain",
"305": "HeavyShowers",
"308": "HeavyRain",
"311": "LightSleet",
"314": "LightSleet",
"317": "LightSleet",
"320": "LightSnow",
"323": "LightSnowShowers",
"326": "LightSnowShowers",
"329": "HeavySnow",
"332": "HeavySnow",
"335": "HeavySnowShowers",
"338": "HeavySnow",
"350": "LightSleet",
"353": "LightShowers",
"356": "HeavyShowers",
"359": "HeavyRain",
"362": "LightSleetShowers",
"365": "LightSleetShowers",
"368": "LightSnowShowers",
"371": "HeavySnowShowers",
"374": "LightSleetShowers",
"377": "LightSleet",
"386": "ThunderyShowers",
"389": "ThunderyHeavyRain",
"392": "ThunderySnowShowers",
"395": "HeavySnowShowers",
}
export const WEATHER_SYMBOL = {
"Unknown": "air",
"Cloudy": "cloud",
"Fog": "foggy",
"HeavyRain": "rainy",
"HeavyShowers": "rainy",
"HeavySnow": "snowing",
"HeavySnowShowers": "snowing",
"LightRain": "rainy",
"LightShowers": "rainy",
"LightSleet": "rainy",
"LightSleetShowers": "rainy",
"LightSnow": "cloudy_snowing",
"LightSnowShowers": "cloudy_snowing",
"PartlyCloudy": "partly_cloudy_day",
"Sunny": "clear_day",
"ThunderyHeavyRain": "thunderstorm",
"ThunderyShowers": "thunderstorm",
"ThunderySnowShowers": "thunderstorm",
"VeryCloudy": "cloud",
}
export const NIGHT_WEATHER_SYMBOL = {
"Unknown": "air",
"Cloudy": "cloud",
"Fog": "foggy",
"HeavyRain": "rainy",
"HeavyShowers": "rainy",
"HeavySnow": "snowing",
"HeavySnowShowers": "snowing",
"LightRain": "rainy",
"LightShowers": "rainy",
"LightSleet": "rainy",
"LightSleetShowers": "rainy",
"LightSnow": "cloudy_snowing",
"LightSnowShowers": "cloudy_snowing",
"PartlyCloudy": "partly_cloudy_night",
"Sunny": "clear_night",
"ThunderyHeavyRain": "thunderstorm",
"ThunderyShowers": "thunderstorm",
"ThunderySnowShowers": "thunderstorm",
"VeryCloudy": "cloud",
}

View file

@ -0,0 +1,38 @@
const resource = file => `resource:///com/github/Aylur/ags/${file}.js`;
const require = async file => (await import(resource(file))).default;
const service = async file => (await require(`service/${file}`));
export const App = await require('app');
// export const Widget = await require('widget');
// export const Service = await require('service');
// export const Variable = await require('variable');
export const Utils = await import(resource('utils'));
// export const Applications = await service('applications');
// export const Audio = await service('audio');
// export const Battery = await service('battery');
// export const Bluetooth = await service('bluetooth');
// export const Hyprland = await service('hyprland');
export const Mpris = await service('mpris');
export const Network = await service('network');
export const Notifications = await service('notifications');
// export const SystemTray = await service('systemtray');
globalThis['App'] = App; //////////////////////////////
// globalThis['Widget'] = Widget;
// globalThis['Service'] = Service;
// globalThis['Variable'] = Variable;
globalThis['Utils'] = Utils; ///////////////////////////
// globalThis['Applications'] = Applications;
// globalThis['Audio'] = Audio;
// globalThis['Battery'] = Battery;
// globalThis['Bluetooth'] = Bluetooth;
// globalThis['Hyprland'] = Hyprland;
globalThis['Mpris'] = Mpris;
globalThis['Network'] = Network;
globalThis['Notifications'] = Notifications;
// globalThis['SystemTray'] = SystemTray;
const { exec } = Utils;
export const SCREEN_WIDTH = Number(exec(`bash -c "xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f1 | head -1" | awk '{print $1}'`));
export const SCREEN_HEIGHT = Number(exec(`bash -c "xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2 | head -1" | awk '{print $1}'`));

View file

@ -0,0 +1,78 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
const { Revealer, Scrollable } = Widget;
export const MarginRevealer = ({
transition = 'slide_down',
child,
revealChild,
showClass = 'element-show', // These are for animation curve, they don't really hide
hideClass = 'element-hide', // Don't put margins in these classes!
extraSetup = () => { },
...rest
}) => {
const widget = Scrollable({
...rest,
attribute: {
'revealChild': true, // It'll be set to false after init if it's supposed to hide
'transition': transition,
'show': () => {
if (widget.attribute.revealChild) return;
widget.hscroll = 'never';
widget.vscroll = 'never';
child.toggleClassName(hideClass, false);
child.toggleClassName(showClass, true);
widget.attribute.revealChild = true;
child.css = 'margin: 0px;';
},
'hide': () => {
if (!widget.attribute.revealChild) return;
child.toggleClassName(hideClass, true);
child.toggleClassName(showClass, false);
widget.attribute.revealChild = false;
if (widget.attribute.transition == 'slide_left')
child.css = `margin-right: -${child.get_allocated_width()}px;`;
else if (widget.attribute.transition == 'slide_right')
child.css = `margin-left: -${child.get_allocated_width()}px;`;
else if (widget.attribute.transition == 'slide_up')
child.css = `margin-bottom: -${child.get_allocated_height()}px;`;
else if (widget.attribute.transition == 'slide_down')
child.css = `margin-top: -${child.get_allocated_height()}px;`;
},
'toggle': () => {
if (widget.attribute.revealChild) widget.attribute.hide();
else widget.attribute.show();
},
},
child: child,
hscroll: `${revealChild ? 'never' : 'always'}`,
vscroll: `${revealChild ? 'never' : 'always'}`,
setup: (self) => {
extraSetup(self);
}
});
child.toggleClassName(`${revealChild ? showClass : hideClass}`, true);
return widget;
}
// TODO: Allow reveal update. Currently this just helps at declaration
export const DoubleRevealer = ({
transition1 = 'slide_right',
transition2 = 'slide_left',
duration1 = 150,
duration2 = 150,
child,
revealChild,
}) => {
return Revealer({
transition: transition1,
transitionDuration: duration1,
revealChild: revealChild,
child: Revealer({
transition: transition2,
transitionDuration: duration2,
revealChild: revealChild,
child: child,
})
})
}

View file

@ -0,0 +1,106 @@
const { Gtk } = imports.gi;
const Lang = imports.lang;
import Widget from 'resource:///com/github/Aylur/ags/widget.js'
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
// -- Styling --
// min-height for diameter
// min-width for trough stroke
// padding for space between trough and progress
// margin for space between widget and parent
// background-color for trough color
// color for progress color
// -- Usage --
// font size for progress value (0-100px) (hacky i know, but i want animations)
export const AnimatedCircProg = ({
initFrom = 0,
initTo = 0,
initAnimTime = 2900,
initAnimPoints = 1,
extraSetup = () => { },
...rest
}) => Widget.DrawingArea({
...rest,
css: `${initFrom != initTo ? 'font-size: ' + initFrom + 'px; transition: ' + initAnimTime + 'ms linear;' : ''}`,
setup: (area) => {
const styleContext = area.get_style_context();
const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left;
const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right;
const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top;
const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom;
area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom);
area.connect('draw', Lang.bind(area, (area, cr) => {
const styleContext = area.get_style_context();
const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left;
const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right;
const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top;
const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom;
area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom);
const progressValue = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 100.0;
const bg_stroke = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
const fg_stroke = bg_stroke - padding;
const radius = Math.min(width, height) / 2.0 - Math.max(bg_stroke, fg_stroke) / 2.0;
const center_x = width / 2.0 + marginLeft;
const center_y = height / 2.0 + marginTop;
const start_angle = -Math.PI / 2.0;
const end_angle = start_angle + (2 * Math.PI * progressValue);
const start_x = center_x + Math.cos(start_angle) * radius;
const start_y = center_y + Math.sin(start_angle) * radius;
const end_x = center_x + Math.cos(end_angle) * radius;
const end_y = center_y + Math.sin(end_angle) * radius;
// Draw background
const background_color = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
cr.setSourceRGBA(background_color.red, background_color.green, background_color.blue, background_color.alpha);
cr.arc(center_x, center_y, radius, 0, 2 * Math.PI);
cr.setLineWidth(bg_stroke);
cr.stroke();
if (progressValue == 0) return;
// Draw progress
const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL);
cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha);
cr.arc(center_x, center_y, radius, start_angle, end_angle);
cr.setLineWidth(fg_stroke);
cr.stroke();
// Draw rounded ends for progress arcs
cr.setLineWidth(0);
cr.arc(start_x, start_y, fg_stroke / 2, 0, 0 - 0.01);
cr.fill();
cr.arc(end_x, end_y, fg_stroke / 2, 0, 0 - 0.01);
cr.fill();
}));
// Init animation
if (initFrom != initTo) {
area.css = `font-size: ${initFrom}px; transition: ${initAnimTime}ms linear;`;
Utils.timeout(20, () => {
area.css = `font-size: ${initTo}px;`;
}, area)
const transitionDistance = initTo - initFrom;
const oneStep = initAnimTime / initAnimPoints;
area.css = `
font-size: ${initFrom}px;
transition: ${oneStep}ms linear;
`;
for (let i = 0; i < initAnimPoints; i++) {
Utils.timeout(Math.max(10, i * oneStep), () => {
if(!area) return;
area.css = `${initFrom != initTo ? 'font-size: ' + (initFrom + (transitionDistance / initAnimPoints * (i + 1))) + 'px;' : ''}`;
});
}
}
else area.css = 'font-size: 0px;';
extraSetup(area);
},
})

View file

@ -0,0 +1,85 @@
function checkLeapYear(year) {
return (
year % 400 == 0 ||
(year % 4 == 0 && year % 100 != 0));
}
function getMonthDays(month, year) {
const leapYear = checkLeapYear(year);
if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 31;
if (month == 2 && leapYear) return 29;
if (month == 2 && !leapYear) return 28;
return 30;
}
function getNextMonthDays(month, year) {
const leapYear = checkLeapYear(year);
if (month == 1 && leapYear) return 29;
if (month == 1 && !leapYear) return 28;
if (month == 12) return 31;
if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30;
return 31;
}
function getPrevMonthDays(month, year) {
const leapYear = checkLeapYear(year);
if (month == 3 && leapYear) return 29;
if (month == 3 && !leapYear) return 28;
if (month == 1) return 31;
if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30;
return 31;
}
export function getCalendarLayout(dateObject, highlight) {
if (!dateObject) dateObject = new Date();
const weekday = (dateObject.getDay() + 6) % 7; // MONDAY IS THE FIRST DAY OF THE WEEK
const day = dateObject.getDate();
const month = dateObject.getMonth() + 1;
const year = dateObject.getFullYear();
const weekdayOfMonthFirst = (weekday + 35 - (day - 1)) % 7;
const daysInMonth = getMonthDays(month, year);
const daysInNextMonth = getNextMonthDays(month, year);
const daysInPrevMonth = getPrevMonthDays(month, year);
// Fill
var monthDiff = (weekdayOfMonthFirst == 0 ? 0 : -1);
var toFill, dim;
if(weekdayOfMonthFirst == 0) {
toFill = 1;
dim = daysInMonth;
}
else {
toFill = (daysInPrevMonth - (weekdayOfMonthFirst - 1));
dim = daysInPrevMonth;
}
var calendar = [...Array(6)].map(() => Array(7));
var i = 0, j = 0;
while (i < 6 && j < 7) {
calendar[i][j] = {
"day": toFill,
"today": ((toFill == day && monthDiff == 0 && highlight) ? 1 : (
monthDiff == 0 ? 0 :
-1
))
};
// Increment
toFill++;
if (toFill > dim) { // Next month?
monthDiff++;
if (monthDiff == 0)
dim = daysInMonth;
else if (monthDiff == 1)
dim = daysInNextMonth;
toFill = 1;
}
// Next tile
j++;
if (j == 7) {
j = 0;
i++;
}
}
return calendar;
}

View file

@ -0,0 +1,126 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
import { MaterialIcon } from './materialicon.js';
import { setupCursorHover } from './cursorhover.js';
const { Box, Button, Label, Revealer } = Widget;
export const ConfigToggle = ({ icon, name, desc = '', initValue, onChange, ...rest }) => {
let value = initValue;
const toggleIcon = Label({
className: `icon-material txt-bold ${value ? '' : 'txt-poof'}`,
label: `${value ? 'check' : ''}`,
})
const toggleButtonIndicator = Box({
className: `switch-fg ${value ? 'switch-fg-true' : ''}`,
vpack: 'center',
hpack: 'start',
homogeneous: true,
children: [toggleIcon,],
});
const toggleButton = Box({
hpack: 'end',
className: `switch-bg ${value ? 'switch-bg-true' : ''}`,
homogeneous: true,
children: [toggleButtonIndicator,],
});
const widgetContent = Box({
tooltipText: desc,
className: 'txt spacing-h-5 configtoggle-box',
children: [
MaterialIcon(icon, 'norm'),
Label({
className: 'txt txt-small',
label: name,
}),
Box({ hexpand: true }),
toggleButton,
]
});
const interactionWrapper = Button({
attribute: {
toggle: (newValue) => {
value = !value;
toggleIcon.toggleClassName('switch-fg-toggling-false', false);
if (!value) {
toggleIcon.label = '';
toggleIcon.toggleClassName('txt-poof', true);
}
toggleButtonIndicator.toggleClassName('switch-fg-true', value);
toggleButton.toggleClassName('switch-bg-true', value);
if (value) Utils.timeout(1, () => {
toggleIcon.label = 'check';
toggleIcon.toggleClassName('txt-poof', false);
})
onChange(interactionWrapper, value);
}
},
child: widgetContent,
onClicked: (self) => self.attribute.toggle(self),
setup: (button) => {
setupCursorHover(button),
button.connect('pressed', () => { // mouse down
toggleIcon.toggleClassName('txt-poof', true);
toggleIcon.toggleClassName('switch-fg-true', false);
if (!value) toggleIcon.toggleClassName('switch-fg-toggling-false', true);
});
},
...rest,
});
return interactionWrapper;
}
export const ConfigSegmentedSelection = ({
icon, name, desc = '',
options = [{ name: 'Option 1', value: 0 }, { name: 'Option 2', value: 1 }],
initIndex = 0,
onChange,
...rest
}) => {
let lastSelected = initIndex;
let value = options[initIndex].value;
const widget = Box({
tooltipText: desc,
className: 'segment-container',
// homogeneous: true,
children: options.map((option, id) => {
const selectedIcon = Revealer({
revealChild: id == initIndex,
transition: 'slide_right',
transitionDuration: 150,
child: MaterialIcon('check', 'norm')
});
return Button({
setup: setupCursorHover,
className: `segment-btn ${id == initIndex ? 'segment-btn-enabled' : ''}`,
child: Box({
hpack: 'center',
className: 'spacing-h-5',
children: [
selectedIcon,
Label({
label: option.name,
})
]
}),
onClicked: (self) => {
value = option.value;
const kids = widget.get_children();
kids[lastSelected].toggleClassName('segment-btn-enabled', false);
kids[lastSelected].get_children()[0].get_children()[0].revealChild = false;
lastSelected = id;
self.toggleClassName('segment-btn-enabled', true);
selectedIcon.revealChild = true;
onChange(option.value, option.name);
}
})
}),
...rest,
});
return widget;
}
export const ConfigGap = ({ vertical = true, size = 5, ...rest }) => Box({
className: `gap-${vertical ? 'v' : 'h'}-${size}`,
...rest,
})

View file

@ -0,0 +1,57 @@
const { Gdk } = imports.gi;
export function setupCursorHover(button) { // Hand pointing cursor on hover
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) { // Crosshair cursor on hover
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) { // Hand ready to grab on hover
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);
});
}
export function setupCursorHoverInfo(button) { // "?" mark cursor on hover
const display = Gdk.Display.get_default();
button.connect('enter-notify-event', () => {
const cursor = Gdk.Cursor.new_from_name(display, 'help');
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);
});
}

View file

@ -0,0 +1,7 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
export const MaterialIcon = (icon, size, props = {}) => Widget.Label({
className: `icon-material txt-${size}`,
label: icon,
...props,
})

View file

@ -0,0 +1,86 @@
// Converts from Markdown to Pango. This does not support code blocks.
// For illogical-impulse, code blocks are treated separately, in their own GtkSourceView widgets.
// Partly inherited from https://github.com/ubunatic/md2pango
const monospaceFonts = 'JetBrains Mono NF, JetBrains Mono Nerd Font, JetBrains Mono NL, SpaceMono NF, SpaceMono Nerd Font, monospace';
const replacements = {
'indents': [
{ name: 'BULLET', re: /^(\s*)([\*\-]\s)(.*)(\s*)$/, sub: ' $1- $3' },
{ name: 'NUMBERING', re: /^(\s*[0-9]+\.\s)(.*)(\s*)$/, sub: ' $1 $2' },
],
'escapes': [
{ name: 'COMMENT', re: /<!--.*-->/, sub: '' },
{ name: 'AMPERSTAND', re: /&/g, sub: '&amp;' },
{ name: 'LESSTHAN', re: /</g, sub: '&lt;' },
{ name: 'GREATERTHAN', re: />/g, sub: '&gt;' },
],
'sections': [
{ name: 'H1', re: /^(#\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="170%">$2</span>' },
{ name: 'H2', re: /^(##\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="150%">$2</span>' },
{ name: 'H3', re: /^(###\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="125%">$2</span>' },
{ name: 'H4', re: /^(####\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="100%">$2</span>' },
{ name: 'H5', re: /^(#####\s+)(.*)(\s*)$/, sub: '<span font_weight="bold" size="90%">$2</span>' },
],
'styles': [
{ name: 'BOLD', re: /(\*\*)(\S[\s\S]*?\S)(\*\*)/g, sub: "<b>$2</b>" },
{ name: 'UND', re: /(__)(\S[\s\S]*?\S)(__)/g, sub: "<u>$2</u>" },
{ name: 'EMPH', re: /\*(\S.*?\S)\*/g, sub: "<i>$1</i>" },
// { name: 'EMPH', re: /_(\S.*?\S)_/g, sub: "<i>$1</i>" },
{ name: 'HEXCOLOR', re: /#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, sub: '<span bgcolor="#$1" fgcolor="#000000" font_family="' + monospaceFonts + '">#$1</span>' },
{ name: 'INLCODE', re: /(`)([^`]*)(`)/g, sub: '<span font_weight="bold" font_family="' + monospaceFonts + '">$2</span>' },
// { name: 'UND', re: /(__|\*\*)(\S[\s\S]*?\S)(__|\*\*)/g, sub: "<u>$2</u>" },
],
}
const replaceCategory = (text, replaces) => {
for (const type of replaces) {
text = text.replace(type.re, type.sub);
}
return text;
}
// Main function
export default (text) => {
let lines = text.split('\n')
let output = [];
// Replace
for (const line of lines) {
let result = line;
result = replaceCategory(result, replacements.indents);
result = replaceCategory(result, replacements.escapes);
result = replaceCategory(result, replacements.sections);
result = replaceCategory(result, replacements.styles);
output.push(result)
}
// Remove trailing whitespaces
output = output.map(line => line.replace(/ +$/, ''))
return output.join('\n');
}
export const markdownTest = `# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
1. yes
2. no
127. well
- Bulletpoint starting with minus
* Bulletpoint starting with asterisk
---
- __Underline__ __ No underline __
- **Bold** ** No bold **
- _Italics1_ *Italics2* _ No Italics _
- A color: #D6BAFF
- nvidia green: #7ABB08
- sub-item
\`\`\`javascript
// A code block!
myArray = [23, 123, 43, 54, '6969'];
console.log('uwu');
\`\`\`
- Random instruction thing
- To update arch lincox, run \`sudo pacman -Syu\`
`;

View file

@ -0,0 +1,71 @@
const { Gtk } = imports.gi;
const Lang = imports.lang;
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
// min-height/min-width for height/width
// background-color/color for background/indicator color
// padding for pad of indicator
// font-size for selected index (0-based)
export const NavigationIndicator = (count, vertical, props) => Widget.DrawingArea({
...props,
setup: (area) => {
const styleContext = area.get_style_context();
const width = Math.max(styleContext.get_property('min-width', Gtk.StateFlags.NORMAL), area.get_allocated_width());
const height = Math.max(styleContext.get_property('min-height', Gtk.StateFlags.NORMAL), area.get_allocated_height());
area.set_size_request(width, height);
area.connect('draw', Lang.bind(area, (area, cr) => {
const styleContext = area.get_style_context();
const width = Math.max(styleContext.get_property('min-width', Gtk.StateFlags.NORMAL), area.get_allocated_width());
const height = Math.max(styleContext.get_property('min-height', Gtk.StateFlags.NORMAL), area.get_allocated_height());
// console.log('allocated width/height:', area.get_allocated_width(), '/', area.get_allocated_height())
area.set_size_request(width, height);
const paddingLeft = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
const paddingRight = styleContext.get_padding(Gtk.StateFlags.NORMAL).right;
const paddingTop = styleContext.get_padding(Gtk.StateFlags.NORMAL).top;
const paddingBottom = styleContext.get_padding(Gtk.StateFlags.NORMAL).bottom;
const selectedCell = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
let cellWidth = width;
let cellHeight = height;
if (vertical) cellHeight /= count;
else cellWidth /= count;
const indicatorWidth = cellWidth - paddingLeft - paddingRight;
const indicatorHeight = cellHeight - paddingTop - paddingBottom;
const background_color = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL);
cr.setLineWidth(2);
// Background
cr.setSourceRGBA(background_color.red, background_color.green, background_color.blue, background_color.alpha);
cr.rectangle(0, 0, width, height);
cr.fill();
// The indicator line
cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha);
if (vertical) {
cr.rectangle(paddingLeft, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth, indicatorHeight - indicatorWidth);
cr.stroke();
cr.rectangle(paddingLeft, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth, indicatorHeight - indicatorWidth);
cr.fill();
cr.arc(paddingLeft + indicatorWidth / 2, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth / 2, Math.PI, 2 * Math.PI);
cr.fill();
cr.arc(paddingLeft + indicatorWidth / 2, paddingTop + cellHeight * selectedCell + indicatorHeight - indicatorWidth / 2, indicatorWidth / 2, 0, Math.PI);
cr.fill();
}
else {
cr.rectangle(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop, indicatorWidth - indicatorHeight, indicatorHeight);
cr.stroke();
cr.rectangle(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop, indicatorWidth - indicatorHeight, indicatorHeight);
cr.fill();
cr.arc(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop + indicatorHeight / 2, indicatorHeight / 2, 0.5 * Math.PI, 1.5 * Math.PI);
cr.fill();
cr.arc(paddingLeft + cellWidth * selectedCell + indicatorWidth - indicatorHeight / 2, paddingTop + indicatorHeight / 2, indicatorHeight / 2, -0.5 * Math.PI, 0.5 * Math.PI);
cr.fill();
}
}))
},
})

View file

@ -0,0 +1,445 @@
// This file is for the actual widget for each single notification
const { GLib, Gdk, Gtk } = imports.gi;
import Widget from 'resource:///com/github/Aylur/ags/widget.js'
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
const { Box, EventBox, Icon, Overlay, Label, Button, Revealer } = Widget;
import { MaterialIcon } from "./materialicon.js";
import { setupCursorHover } from "./cursorhover.js";
import { AnimatedCircProg } from "./animatedcircularprogress.js";
function guessMessageType(summary) {
if (summary.includes('recording')) return 'screen_record';
if (summary.includes('battery') || summary.includes('power')) return 'power';
if (summary.includes('screenshot')) return 'screenshot_monitor';
if (summary.includes('welcome')) return 'waving_hand';
if (summary.includes('time')) return 'scheduleb';
if (summary.includes('installed')) return 'download';
if (summary.includes('update')) return 'update';
if (summary.startsWith('file')) return 'folder_copy';
return 'chat';
}
function exists(widget) {
return widget !== null;
}
const NotificationIcon = (notifObject) => {
// { appEntry, appIcon, image }, urgency = 'normal'
if (notifObject.image) {
return Box({
valign: Gtk.Align.CENTER,
hexpand: false,
className: 'notif-icon',
css: `
background-image: url("${notifObject.image}");
background-size: auto 100%;
background-repeat: no-repeat;
background-position: center;
`,
});
}
let icon = 'NO_ICON';
if (Utils.lookUpIcon(notifObject.appIcon))
icon = notifObject.appIcon;
if (Utils.lookUpIcon(notifObject.appEntry))
icon = notifObject.appEntry;
return Box({
vpack: 'center',
hexpand: false,
className: `notif-icon notif-icon-material-${notifObject.urgency}`,
homogeneous: true,
children: [
(icon != 'NO_ICON' ?
Icon({
vpack: 'center',
icon: icon,
})
:
MaterialIcon(`${notifObject.urgency == 'critical' ? 'release_alert' : guessMessageType(notifObject.summary.toLowerCase())}`, 'hugerass', {
hexpand: true,
})
)
],
});
};
export default ({
notifObject,
isPopup = false,
props = {},
} = {}) => {
const popupTimeout = notifObject.timeout || (notifObject.urgency == 'critical' ? 8000 : 3000);
const command = (isPopup ?
() => notifObject.dismiss() :
() => notifObject.close()
)
const destroyWithAnims = () => {
widget.sensitive = false;
notificationBox.setCss(middleClickClose);
Utils.timeout(200, () => {
if (wholeThing) wholeThing.revealChild = false;
}, wholeThing);
Utils.timeout(400, () => {
command();
if (wholeThing) {
wholeThing.destroy();
wholeThing = null;
}
}, wholeThing);
}
const widget = EventBox({
onHover: (self) => {
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
if (!wholeThing.attribute.hovered)
wholeThing.attribute.hovered = true;
},
onHoverLost: (self) => {
self.window.set_cursor(null);
if (wholeThing.attribute.hovered)
wholeThing.attribute.hovered = false;
if (isPopup) {
command();
}
},
onMiddleClick: (self) => {
destroyWithAnims();
},
setup: (self) => {
self.on("button-press-event", () => {
wholeThing.attribute.held = true;
notificationContent.toggleClassName(`${isPopup ? 'popup-' : ''}notif-clicked-${notifObject.urgency}`, true);
Utils.timeout(800, () => {
if (wholeThing?.attribute.held) {
Utils.execAsync(['wl-copy', `${notifObject.body}`])
notifTextSummary.label = notifObject.summary + " (copied)";
Utils.timeout(3000, () => notifTextSummary.label = notifObject.summary)
}
})
}).on("button-release-event", () => {
wholeThing.attribute.held = false;
notificationContent.toggleClassName(`${isPopup ? 'popup-' : ''}notif-clicked-${notifObject.urgency}`, false);
})
}
});
let wholeThing = Revealer({
attribute: {
'close': undefined,
'destroyWithAnims': destroyWithAnims,
'dragging': false,
'held': false,
'hovered': false,
'id': notifObject.id,
},
revealChild: false,
transition: 'slide_down',
transitionDuration: 200,
child: Box({ // Box to make sure css-based spacing works
homogeneous: true,
}),
});
const display = Gdk.Display.get_default();
const notifTextPreview = Revealer({
transition: 'slide_down',
transitionDuration: 120,
revealChild: true,
child: Label({
xalign: 0,
className: `txt-smallie notif-body-${notifObject.urgency}`,
useMarkup: true,
xalign: 0,
justify: Gtk.Justification.LEFT,
maxWidthChars: 24,
truncate: 'end',
label: notifObject.body.split("\n")[0],
}),
});
const notifTextExpanded = Revealer({
transition: 'slide_up',
transitionDuration: 120,
revealChild: false,
child: Box({
vertical: true,
className: 'spacing-v-10',
children: [
Label({
xalign: 0,
className: `txt-smallie notif-body-${notifObject.urgency}`,
useMarkup: true,
xalign: 0,
justify: Gtk.Justification.LEFT,
maxWidthChars: 24,
wrap: true,
label: notifObject.body,
}),
Box({
className: 'notif-actions spacing-h-5',
children: [
Button({
hexpand: true,
className: `notif-action notif-action-${notifObject.urgency}`,
onClicked: () => destroyWithAnims(),
child: Label({
label: 'Close',
})
}),
...notifObject.actions.map(action => Widget.Button({
hexpand: true,
className: `notif-action notif-action-${notifObject.urgency}`,
onClicked: () => notifObject.invoke(action.id),
child: Label({
label: action.label,
})
}))
],
})
]
}),
});
const notifIcon = Box({
vpack: 'start',
homogeneous: true,
children: [
Overlay({
child: NotificationIcon(notifObject),
overlays: isPopup ? [AnimatedCircProg({
className: `notif-circprog-${notifObject.urgency}`,
vpack: 'center', hpack: 'center',
initFrom: (isPopup ? 100 : 0),
initTo: 0,
initAnimTime: popupTimeout,
})] : [],
}),
]
});
let notifTime = '';
const messageTime = GLib.DateTime.new_from_unix_local(notifObject.time);
if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year())
notifTime = messageTime.format('%H:%M');
else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1)
notifTime = 'Yesterday';
else
notifTime = messageTime.format('%d/%m');
const notifTextSummary = Label({
xalign: 0,
className: 'txt-small txt-semibold titlefont',
justify: Gtk.Justification.LEFT,
hexpand: true,
maxWidthChars: 24,
truncate: 'end',
ellipsize: 3,
useMarkup: notifObject.summary.startsWith('<'),
label: notifObject.summary,
});
const notifTextBody = Label({
vpack: 'center',
justification: 'right',
className: 'txt-smaller txt-semibold',
label: notifTime,
});
const notifText = Box({
valign: Gtk.Align.CENTER,
vertical: true,
hexpand: true,
children: [
Box({
children: [
notifTextSummary,
notifTextBody,
]
}),
notifTextPreview,
notifTextExpanded,
]
});
const notifExpandButton = Button({
vpack: 'start',
className: 'notif-expand-btn',
onClicked: (self) => {
if (notifTextPreview.revealChild) { // Expanding...
notifTextPreview.revealChild = false;
notifTextExpanded.revealChild = true;
self.child.label = 'expand_less';
expanded = true;
}
else {
notifTextPreview.revealChild = true;
notifTextExpanded.revealChild = false;
self.child.label = 'expand_more';
expanded = false;
}
},
child: MaterialIcon('expand_more', 'norm', {
vpack: 'center',
}),
setup: setupCursorHover,
});
const notificationContent = Box({
...props,
className: `${isPopup ? 'popup-' : ''}notif-${notifObject.urgency} spacing-h-10`,
children: [
notifIcon,
Box({
className: 'spacing-h-5',
children: [
notifText,
notifExpandButton,
]
})
]
})
// Gesture stuff
const gesture = Gtk.GestureDrag.new(widget);
var initDirX = 0;
var initDirVertical = -1; // -1: unset, 0: horizontal, 1: vertical
var expanded = false;
// in px
const startMargin = 0;
const MOVE_THRESHOLD = 10;
const DRAG_CONFIRM_THRESHOLD = 100;
// in rem
const maxOffset = 10.227;
const endMargin = 20.455;
const disappearHeight = 6.818;
const leftAnim1 = `transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
margin-left: -${Number(maxOffset + endMargin)}rem;
margin-right: ${Number(maxOffset + endMargin)}rem;
opacity: 0;`;
const rightAnim1 = `transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
margin-left: ${Number(maxOffset + endMargin)}rem;
margin-right: -${Number(maxOffset + endMargin)}rem;
opacity: 0;`;
const middleClickClose = `transition: 200ms cubic-bezier(0.85, 0, 0.15, 1);
margin-left: ${Number(maxOffset + endMargin)}rem;
margin-right: -${Number(maxOffset + endMargin)}rem;
opacity: 0;`;
const notificationBox = Box({
attribute: {
'leftAnim1': leftAnim1,
'rightAnim1': rightAnim1,
'middleClickClose': middleClickClose,
'ready': false,
},
homogeneous: true,
children: [notificationContent],
setup: (self) => self
.hook(gesture, self => {
var offset_x = gesture.get_offset()[1];
var offset_y = gesture.get_offset()[2];
// Which dir?
if (initDirVertical == -1) {
if (Math.abs(offset_y) > MOVE_THRESHOLD)
initDirVertical = 1;
if (initDirX == 0 && Math.abs(offset_x) > MOVE_THRESHOLD) {
initDirVertical = 0;
initDirX = (offset_x > 0 ? 1 : -1);
}
}
// Horizontal drag
if (initDirVertical == 0 && offset_x > MOVE_THRESHOLD) {
if (initDirX < 0)
self.setCss(`margin-left: 0px; margin-right: 0px;`);
else
self.setCss(`
margin-left: ${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
margin-right: -${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
`);
}
else if (initDirVertical == 0 && offset_x < -MOVE_THRESHOLD) {
if (initDirX > 0)
self.setCss(`margin-left: 0px; margin-right: 0px;`);
else {
offset_x = Math.abs(offset_x);
self.setCss(`
margin-right: ${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
margin-left: -${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
`);
}
}
// Update dragging
wholeThing.attribute.dragging = Math.abs(offset_x) > MOVE_THRESHOLD;
if (Math.abs(offset_x) > MOVE_THRESHOLD ||
Math.abs(offset_y) > MOVE_THRESHOLD) wholeThing.attribute.held = false;
widget.window?.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
// Vertical drag
if (initDirVertical == 1 && offset_y > MOVE_THRESHOLD && !expanded) {
notifTextPreview.revealChild = false;
notifTextExpanded.revealChild = true;
expanded = true;
notifExpandButton.child.label = 'expand_less';
}
else if (initDirVertical == 1 && offset_y < -MOVE_THRESHOLD && expanded) {
notifTextPreview.revealChild = true;
notifTextExpanded.revealChild = false;
expanded = false;
notifExpandButton.child.label = 'expand_more';
}
}, 'drag-update')
.hook(gesture, self => {
if (!self.attribute.ready) {
wholeThing.revealChild = true;
self.attribute.ready = true;
return;
}
const offset_h = gesture.get_offset()[1];
if (Math.abs(offset_h) > DRAG_CONFIRM_THRESHOLD && offset_h * initDirX > 0) {
if (offset_h > 0) {
self.setCss(rightAnim1);
widget.sensitive = false;
}
else {
self.setCss(leftAnim1);
widget.sensitive = false;
}
Utils.timeout(200, () => {
if (wholeThing) wholeThing.revealChild = false;
}, wholeThing);
Utils.timeout(400, () => {
command();
if (wholeThing) {
wholeThing.destroy();
wholeThing = null;
}
}, wholeThing);
}
else {
self.setCss(`transition: margin 200ms cubic-bezier(0.05, 0.7, 0.1, 1), opacity 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
margin-left: ${startMargin}px;
margin-right: ${startMargin}px;
margin-bottom: unset; margin-top: unset;
opacity: 1;`);
if (widget.window)
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
wholeThing.attribute.dragging = false;
}
initDirX = 0;
initDirVertical = -1;
}, 'drag-end')
,
})
widget.add(notificationBox);
wholeThing.child.children = [widget];
if (isPopup) Utils.timeout(popupTimeout, () => {
if (wholeThing) {
wholeThing.revealChild = false;
Utils.timeout(200, () => {
if (wholeThing) {
wholeThing.destroy();
wholeThing = null;
}
command();
}, wholeThing);
}
})
return wholeThing;
}

View file

@ -0,0 +1,30 @@
import App from 'resource:///com/github/Aylur/ags/app.js';
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
const { Box, Window } = Widget;
export default ({
name,
child,
showClassName,
hideClassName,
...props
}) => Window({
name,
popup: true,
visible: false,
layer: 'overlay',
...props,
child: Box({
className: `${showClassName} ${hideClassName}`,
setup: (self) => self
.hook(App, (self, currentName, visible) => {
if (currentName === name) {
self.toggleClassName(hideClassName, !visible);
}
})
,
child: child,
}),
});

View file

@ -0,0 +1,54 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
const { Gtk } = imports.gi;
const Lang = imports.lang;
import Cairo from 'gi://cairo?version=1.0';
export const dummyRegion = new Cairo.Region();
export const enableClickthrough = (self) => self.input_shape_combine_region(dummyRegion);
export const RoundedCorner = (place, props) => Widget.DrawingArea({
...props,
hpack: place.includes('left') ? 'start' : 'end',
vpack: place.includes('top') ? 'start' : 'end',
setup: (widget) => Utils.timeout(1, () => {
const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL);
const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
widget.set_size_request(r, r);
widget.connect('draw', Lang.bind(widget, (widget, cr) => {
const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL);
const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
// const borderColor = widget.get_style_context().get_property('color', Gtk.StateFlags.NORMAL);
// const borderWidth = widget.get_style_context().get_border(Gtk.StateFlags.NORMAL).left; // ur going to write border-width: something anyway
widget.set_size_request(r, r);
switch (place) {
case 'topleft':
cr.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
cr.lineTo(0, 0);
break;
case 'topright':
cr.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI);
cr.lineTo(r, 0);
break;
case 'bottomleft':
cr.arc(r, 0, r, Math.PI / 2, Math.PI);
cr.lineTo(0, r);
break;
case 'bottomright':
cr.arc(0, 0, r, 0, Math.PI / 2);
cr.lineTo(r, r);
break;
}
cr.closePath();
cr.setSourceRGBA(c.red, c.green, c.blue, c.alpha);
cr.fill();
// cr.setLineWidth(borderWidth);
// cr.setSourceRGBA(borderColor.red, borderColor.green, borderColor.blue, borderColor.alpha);
// cr.stroke();
}));
}),
});

View file

@ -0,0 +1,5 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
export const separatorLine = Widget.Box({
className: 'separator-line',
})

View file

@ -0,0 +1,253 @@
import App from 'resource:///com/github/Aylur/ags/app.js';
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
import { MaterialIcon } from './materialicon.js';
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
import Network from 'resource:///com/github/Aylur/ags/service/network.js';
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
import { languages } from '../data/languages.js';
// A guessing func to try to support langs not listed in data/languages.js
function isLanguageMatch(abbreviation, word) {
const lowerAbbreviation = abbreviation.toLowerCase();
const lowerWord = word.toLowerCase();
let j = 0;
for (let i = 0; i < lowerWord.length; i++) {
if (lowerWord[i] === lowerAbbreviation[j]) {
j++;
}
if (j === lowerAbbreviation.length) {
return true;
}
}
return false;
}
export const NotificationIndicator = (notifCenterName = 'sideright') => {
const widget = Widget.Revealer({
transition: 150,
transition: 'slide_left',
revealChild: false,
setup: (self) => self
.hook(Notifications, (self, id) => {
if (!id || Notifications.dnd) return;
if (!Notifications.getNotification(id)) return;
self.revealChild = true;
}, 'notified')
.hook(App, (self, currentName, visible) => {
if (visible && currentName === notifCenterName) {
self.revealChild = false;
}
})
,
child: Widget.Box({
children: [
MaterialIcon('notifications', 'norm'),
Widget.Label({
className: 'txt-small titlefont',
attribute: {
unreadCount: 0,
update: (self) => self.label = `${self.attribute.unreadCount}`,
},
setup: (self) => self
.hook(Notifications, (self, id) => {
if (!id || Notifications.dnd) return;
if (!Notifications.getNotification(id)) return;
self.attribute.unreadCount++;
self.attribute.update(self);
}, 'notified')
.hook(App, (self, currentName, visible) => {
if (visible && currentName === notifCenterName) {
self.attribute.unreadCount = 0;
self.attribute.update(self);
}
})
,
})
]
})
});
return widget;
}
export const BluetoothIndicator = () => Widget.Stack({
transition: 'slide_up_down',
children: {
'false': Widget.Label({ className: 'txt-norm icon-material', label: 'bluetooth_disabled' }),
'true': Widget.Label({ className: 'txt-norm icon-material', label: 'bluetooth' }),
},
setup: (self) => self
.hook(Bluetooth, stack => {
stack.shown = String(Bluetooth.enabled);
})
,
});
const NetworkWiredIndicator = () => Widget.Stack({
transition: 'slide_up_down',
children: {
'fallback': SimpleNetworkIndicator(),
'unknown': Widget.Label({ className: 'txt-norm icon-material', label: 'wifi_off' }),
'disconnected': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_off' }),
'connected': Widget.Label({ className: 'txt-norm icon-material', label: 'lan' }),
'connecting': Widget.Label({ className: 'txt-norm icon-material', label: 'settings_ethernet' }),
},
setup: (self) => self.hook(Network, stack => {
if (!Network.wired)
return;
const { internet } = Network.wired;
if (['connecting', 'connected'].includes(internet))
stack.shown = internet;
else if (Network.connectivity !== 'full')
stack.shown = 'disconnected';
else
stack.shown = 'fallback';
}),
});
const SimpleNetworkIndicator = () => Widget.Icon({
setup: (self) => self.hook(Network, self => {
const icon = Network[Network.primary || 'wifi']?.iconName;
self.icon = icon || '';
self.visible = icon;
}),
});
const NetworkWifiIndicator = () => Widget.Stack({
transition: 'slide_up_down',
children: {
'disabled': Widget.Label({ className: 'txt-norm icon-material', label: 'wifi_off' }),
'disconnected': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_off' }),
'connecting': Widget.Label({ className: 'txt-norm icon-material', label: 'settings_ethernet' }),
'0': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_0_bar' }),
'1': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_1_bar' }),
'2': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_2_bar' }),
'3': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_3_bar' }),
'4': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_4_bar' }),
},
setup: (self) => self.hook(Network, (stack) => {
if (!Network.wifi) {
return;
}
if (Network.wifi.internet == 'connected') {
stack.shown = String(Math.ceil(Network.wifi.strength / 25));
}
else if (["disconnected", "connecting"].includes(Network.wifi.internet)) {
stack.shown = Network.wifi.internet;
}
}),
});
export const NetworkIndicator = () => Widget.Stack({
transition: 'slide_up_down',
children: {
'fallback': SimpleNetworkIndicator(),
'wifi': NetworkWifiIndicator(),
'wired': NetworkWiredIndicator(),
},
setup: (self) => self.hook(Network, stack => {
if (!Network.primary) {
stack.shown = 'wifi';
return;
}
const primary = Network.primary || 'fallback';
if (['wifi', 'wired'].includes(primary))
stack.shown = primary;
else
stack.shown = 'fallback';
}),
});
const HyprlandXkbKeyboardLayout = async ({ useFlag } = {}) => {
try {
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
var initLangs = [];
var languageStackArray = [];
var currentKeyboard;
const updateCurrentKeyboards = () => {
currentKeyboard = JSON.parse(Utils.exec('hyprctl -j devices')).keyboards
.find(device => device.name === 'at-translated-set-2-keyboard');
if (currentKeyboard) {
initLangs = currentKeyboard.layout.split(',').map(lang => lang.trim());
}
languageStackArray = Array.from({ length: initLangs.length }, (_, i) => {
const lang = languages.find(lang => lang.layout == initLangs[i]);
// if (!lang) return [
// initLangs[i],
// Widget.Label({ label: initLangs[i] })
// ];
// return [
// lang.layout,
// Widget.Label({ label: (useFlag ? lang.flag : lang.layout) })
// ];
// Object
if (!lang) return {
[initLangs[i]]: Widget.Label({ label: initLangs[i] })
};
return {
[lang.layout]: Widget.Label({ label: (useFlag ? lang.flag : lang.layout) })
};
});
};
updateCurrentKeyboards();
const widgetRevealer = Widget.Revealer({
transition: 150,
transition: 'slide_left',
revealChild: languageStackArray.length > 1,
});
const widgetKids = {
...languageStackArray.reduce((obj, lang) => {
return { ...obj, ...lang };
}, {}),
'undef': Widget.Label({ label: '?' }),
}
const widgetContent = Widget.Stack({
transition: 'slide_up_down',
children: widgetKids,
setup: (self) => self.hook(Hyprland, (stack, kbName, layoutName) => {
if (!kbName) {
return;
}
var lang = languages.find(lang => layoutName.includes(lang.name));
if (lang) {
widgetContent.shown = lang.layout;
}
else { // Attempt to support langs not listed
lang = languageStackArray.find(lang => isLanguageMatch(lang[0], layoutName));
if (!lang) stack.shown = 'undef';
else stack.shown = lang[0];
}
}, 'keyboard-layout'),
});
widgetRevealer.child = widgetContent;
return widgetRevealer;
} catch {
return null;
}
}
const OptionalKeyboardLayout = async () => {
try {
return await HyprlandXkbKeyboardLayout({ useFlag: false });
} catch {
return null;
}
};
const optionalKeyboardLayoutInstance = await OptionalKeyboardLayout();
export const StatusIcons = (props = {}) => Widget.Box({
...props,
child: Widget.Box({
className: 'spacing-h-15',
children: [
optionalKeyboardLayoutInstance,
NotificationIndicator(),
NetworkIndicator(),
BluetoothIndicator(),
]
})
});

View file

@ -0,0 +1,3 @@
# scripts folder
- For ARM devices, you have to compile C++ files yourself. If there are none, yippee
- It is advised to use services instead of listening/polling scripts, so everything here are just scripts for actions

View file

@ -0,0 +1,178 @@
#!/usr/bin/env bash
# sleep 0 # idk i wanted some delay or colors dont get applied properly
if [ ! -d "$HOME"/.cache/ags/user/generated ]; then
mkdir -p "$HOME"/.cache/ags/user/generated
fi
cd "$HOME/.config/ags" || exit
colornames=''
colorstrings=''
colorlist=()
colorvalues=()
if [[ "$1" = "--bad-apple" ]]; then
cp scripts/color_generation/specials/_material_badapple.scss scss/_material.scss
colornames=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f1)
colorstrings=$(cat scripts/color_generation/specials/_material_badapple.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1)
IFS=$'\n'
# filearr=( $filelist ) # Get colors
colorlist=( $colornames ) # Array of color names
colorvalues=( $colorstrings ) # Array of color values
else
colornames=$(cat scss/_material.scss | cut -d: -f1)
colorstrings=$(cat scss/_material.scss | cut -d: -f2 | cut -d ' ' -f2 | cut -d ";" -f1)
IFS=$'\n'
# filearr=( $filelist ) # Get colors
colorlist=( $colornames ) # Array of color names
colorvalues=( $colorstrings ) # Array of color values
fi
transparentize() {
local hex="$1"
local alpha="$2"
local red green blue
red=$((16#${hex:1:2}))
green=$((16#${hex:3:2}))
blue=$((16#${hex:5:2}))
printf 'rgba(%d, %d, %d, %.2f)\n' "$red" "$green" "$blue" "$alpha"
}
get_light_dark() {
lightdark=""
if [ ! -f "$HOME"/.cache/ags/user/colormode.txt ]; then
echo "" > "$HOME"/.cache/ags/user/colormode.txt
else
lightdark=$(cat "$HOME"/.cache/ags/user/colormode.txt) # either "" or "-l"
fi
echo "$lightdark"
}
apply_gtklock() {
# Check if scripts/templates/gtklock/main.scss exists
if [ ! -f "scripts/templates/gtklock/main.scss" ]; then
echo "SCSS not found for Gtklock. Skipping that."
return
fi
# Copy template
mkdir -p "$HOME"/.cache/ags/user/generated/gtklock
sassc "scripts/templates/gtklock/main.scss" "$HOME"/.cache/ags/user/generated/gtklock/style.css
cp "$HOME"/.cache/ags/user/generated/gtklock/style.css "$HOME"/.config/gtklock/style.css
}
apply_fuzzel() {
# Check if scripts/templates/fuzzel/fuzzel.ini exists
if [ ! -f "scripts/templates/fuzzel/fuzzel.ini" ]; then
echo "Template file not found for Fuzzel. Skipping that."
return
fi
# Copy template
mkdir -p "$HOME"/.cache/ags/user/generated/fuzzel
cp "scripts/templates/fuzzel/fuzzel.ini" "$HOME"/.cache/ags/user/generated/fuzzel/fuzzel.ini
# Apply colors
for i in "${!colorlist[@]}"; do
sed -i "s/{{ ${colorlist[$i]} }}/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/fuzzel/fuzzel.ini
done
cp "$HOME"/.cache/ags/user/generated/fuzzel/fuzzel.ini "$HOME"/.config/fuzzel/fuzzel.ini
}
apply_foot() {
if [ ! -f "scripts/templates/foot/foot.ini" ]; then
echo "Template file not found for Foot. Skipping that."
return
fi
# Copy template
mkdir -p "$HOME"/.cache/ags/user/generated/foot
cp "scripts/templates/foot/foot.ini" "$HOME"/.cache/ags/user/generated/foot/foot.ini
# Apply colors
for i in "${!colorlist[@]}"; do
# sed -i "s/${colorlist[$i]} #/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/foot/foot.ini
sed -i "s/{{ ${colorlist[$i]} }}/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/foot/foot.ini
done
cp "$HOME"/.cache/ags/user/generated/foot/foot.ini "$HOME/.config/foot/foot.ini"
}
apply_term() {
# Check if scripts/templates/foot/foot.ini exists
if [ ! -f "scripts/templates/terminal/sequences.txt" ]; then
echo "Template file not found for Terminal. Skipping that."
return
fi
# Copy template
mkdir -p "$HOME"/.cache/ags/user/generated/terminal
cp "scripts/templates/terminal/sequences.txt" "$HOME"/.cache/ags/user/generated/terminal/sequences.txt
# Apply colors
for i in "${!colorlist[@]}"; do
sed -i "s/${colorlist[$i]} #/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/terminal/sequences.txt
done
cp "$HOME"/.cache/ags/user/generated/terminal/sequences.txt "$HOME"/.config/fish/sequences.txt
for file in /dev/pts/*; do
if [[ $file =~ ^/dev/pts/[0-9]+$ ]]; then
cat "$HOME"/.config/fish/sequences.txt > "$file"
fi
done
}
apply_hyprland() {
# Check if scripts/templates/hypr/colors.conf exists
if [ ! -f "scripts/templates/hypr/colors.conf" ]; then
echo "Template file not found for Hyprland colors. Skipping that."
return
fi
# Copy template
mkdir -p "$HOME"/.cache/ags/user/generated/hypr
cp "scripts/templates/hypr/colors.conf" "$HOME"/.cache/ags/user/generated/hypr/colors.conf
# Apply colors
for i in "${!colorlist[@]}"; do
sed -i "s/{{ ${colorlist[$i]} }}/${colorvalues[$i]#\#}/g" "$HOME"/.cache/ags/user/generated/hypr/colors.conf
done
cp "$HOME"/.cache/ags/user/generated/hypr/colors.conf "$HOME"/.config/hypr/colors.conf
}
apply_gtk() { # Using gradience-cli
lightdark=$(get_light_dark)
# Copy template
mkdir -p "$HOME"/.cache/ags/user/generated/gradience
cp "scripts/templates/gradience/preset.json" "$HOME"/.cache/ags/user/generated/gradience/preset.json
# Apply colors
for i in "${!colorlist[@]}"; do
sed -i "s/{{ ${colorlist[$i]} }}/${colorvalues[$i]}/g" "$HOME"/.cache/ags/user/generated/gradience/preset.json
done
mkdir -p "$HOME/.config/presets" # create gradience presets folder
gradience-cli apply -p "$HOME"/.cache/ags/user/generated/gradience/preset.json --gtk both
# Set light/dark preference
# And set GTK theme manually as Gradience defaults to light adw-gtk3
# (which is unreadable when broken when you use dark mode)
if [ "$lightdark" = "-l" ]; then
gsettings set org.gnome.desktop.interface gtk-theme 'adw-gtk3'
gsettings set org.gnome.desktop.interface color-scheme 'prefer-light'
else
gsettings set org.gnome.desktop.interface gtk-theme adw-gtk3-dark
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
fi
}
apply_ags() {
sassc "$HOME"/.config/ags/scss/main.scss "$HOME"/.config/ags/style.css
ags run-js 'openColorScheme.value = true; Utils.timeout(2000, () => openColorScheme.value = false);'
ags run-js "App.resetCss(); App.applyCss('${HOME}/.config/ags/style.css');"
}
apply_ags &
apply_hyprland &
apply_gtk &
apply_foot &
apply_gtklock &
apply_fuzzel &
apply_term &

View file

@ -0,0 +1,59 @@
#!/usr/bin/env bash
# check if no arguments
if [ $# -eq 0 ]; then
echo "Usage: colorgen.sh /path/to/image (--apply)"
exit 1
fi
# check if the file ~/.cache/ags/user/colormode.txt exists. if not, create it. else, read it to $lightdark
lightdark=""
if [ ! -f "$HOME/.cache/ags/user/colormode.txt" ]; then
echo "" > "$HOME/.cache/ags/user/colormode.txt"
else
lightdark=$(cat "$HOME/.cache/ags/user/colormode.txt") # either "" or "-l"
fi
backend="material" # color generator backend
if [ ! -f "$HOME/.cache/ags/user/colorbackend.txt" ]; then
echo "material" > "$HOME/.cache/ags/user/colorbackend.txt"
else
backend=$(cat "$HOME/.cache/ags/user/colorbackend.txt") # either "" or "-l"
fi
cd "$HOME/.config/ags/scripts/" || exit
if [[ "$1" = "#"* ]]; then # this is a color
color_generation/generate_colors_material.py --color "$1" "$lightdark" > "$HOME"/.cache/ags/user/generated/material_colors.scss
if [ "$2" = "--apply" ]; then
cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss"
color_generation/applycolor.sh
fi
elif [ "$backend" = "material" ]; then
color_generation/generate_colors_material.py --path "$1" "$lightdark" > "$HOME"/.cache/ags/user/generated/material_colors.scss
if [ "$2" = "--apply" ]; then
cp "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME/.config/ags/scss/_material.scss"
color_generation/applycolor.sh
fi
elif [ "$backend" = "pywal" ]; then
# clear and generate
wal -c
wal -i "$1" -n $lightdark -q
# copy scss
cp "$HOME/.cache/wal/colors.scss" "$HOME"/.cache/ags/user/generated/material_colors.scss
cat color_generation/pywal_to_material.scss >> "$HOME"/.cache/ags/user/generated/material_colors.scss
if [ "$2" = "--apply" ]; then
sassc "$HOME"/.cache/ags/user/generated/material_colors.scss "$HOME"/.cache/ags/user/generated/colors_classes.scss --style compact
sed -i "s/ { color//g" "$HOME"/.cache/ags/user/generated/colors_classes.scss
sed -i "s/\./$/g" "$HOME"/.cache/ags/user/generated/colors_classes.scss
sed -i "s/}//g" "$HOME"/.cache/ags/user/generated/colors_classes.scss
if [ "$lightdark" = "-l" ]; then
printf "\n""\$darkmode: false;""\n" >> "$HOME"/.cache/ags/user/generated/colors_classes.scss
else
printf "\n""\$darkmode: true;""\n" >> "$HOME"/.cache/ags/user/generated/colors_classes.scss
fi
cp "$HOME"/.cache/ags/user/generated/colors_classes.scss "$HOME/.config/ags/scss/_material.scss"
color_generation/applycolor.sh
fi
fi

View file

@ -0,0 +1,122 @@
#!/usr/bin/env python3
from material_color_utilities_python import *
from pathlib import Path
import sys
import subprocess
def darken(hex_color, factor=0.7):
if not (hex_color.startswith('#') and len(hex_color) in (4, 7)):
raise ValueError("Invalid hex color format")
hex_color = hex_color.lstrip('#')
rgb = tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4))
darkened_rgb = tuple(int(max(0, val * factor)) for val in rgb)
darkened_hex = "#{:02X}{:02X}{:02X}".format(*darkened_rgb)
return darkened_hex
img = 0
newtheme=0
if len(sys.argv) > 1 and sys.argv[1] == '--path':
# try:
img = Image.open(sys.argv[2])
basewidth = 64
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize),Image.Resampling.LANCZOS)
newtheme = themeFromImage(img)
# except FileNotFoundError:
# print('[generate_colors_material.py] File not found', file=sys.stderr);
# exit()
# except:
# print('[generate_colors_material.py] Something went wrong', file=sys.stderr);
# exit()
elif len(sys.argv) > 1 and sys.argv[1] == '--color':
colorstr = sys.argv[2]
newtheme = themeFromSourceColor(argbFromHex(colorstr))
else:
# try:
# imagePath = subprocess.check_output("ags run-js 'wallpaper.get(0)'", shell=True)
imagePath = subprocess.check_output("swww query | awk -F 'image: ' '{print $2}'", shell=True)
imagePath = imagePath[:-1].decode("utf-8")
img = Image.open(imagePath)
basewidth = 64
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize),Image.Resampling.LANCZOS)
newtheme = themeFromImage(img)
# except FileNotFoundError:
# print('[generate_colors_material.py] File not found', file=sys.stderr)
# exit()
# except:
# print('[generate_colors_material.py] Something went wrong', file=sys.stderr);
# exit()
colorscheme=0
darkmode = True
if("-l" in sys.argv):
darkmode = False
colorscheme = newtheme.get('schemes').get('light')
print('$darkmode: false;')
else:
colorscheme = newtheme.get('schemes').get('dark')
print('$darkmode: true;')
primary = hexFromArgb(colorscheme.get_primary())
onPrimary = hexFromArgb(colorscheme.get_onPrimary())
primaryContainer = hexFromArgb(colorscheme.get_primaryContainer())
onPrimaryContainer = hexFromArgb(colorscheme.get_onPrimaryContainer())
secondary = hexFromArgb(colorscheme.get_secondary())
onSecondary = hexFromArgb(colorscheme.get_onSecondary())
secondaryContainer = hexFromArgb(colorscheme.get_secondaryContainer())
onSecondaryContainer = hexFromArgb(colorscheme.get_onSecondaryContainer())
tertiary = hexFromArgb(colorscheme.get_tertiary())
onTertiary = hexFromArgb(colorscheme.get_onTertiary())
tertiaryContainer = hexFromArgb(colorscheme.get_tertiaryContainer())
onTertiaryContainer = hexFromArgb(colorscheme.get_onTertiaryContainer())
error = hexFromArgb(colorscheme.get_error())
onError = hexFromArgb(colorscheme.get_onError())
errorContainer = hexFromArgb(colorscheme.get_errorContainer())
onErrorContainer = hexFromArgb(colorscheme.get_onErrorContainer())
background = hexFromArgb(colorscheme.get_background())
onBackground = hexFromArgb(colorscheme.get_onBackground())
surface = hexFromArgb(colorscheme.get_surface())
onSurface = hexFromArgb(colorscheme.get_onSurface())
surfaceVariant = hexFromArgb(colorscheme.get_surfaceVariant())
onSurfaceVariant = hexFromArgb(colorscheme.get_onSurfaceVariant())
outline = hexFromArgb(colorscheme.get_outline())
shadow = hexFromArgb(colorscheme.get_shadow())
inverseSurface = hexFromArgb(colorscheme.get_inverseSurface())
inverseOnSurface = hexFromArgb(colorscheme.get_inverseOnSurface())
inversePrimary = hexFromArgb(colorscheme.get_inversePrimary())
# make material less boring
if darkmode:
background = darken(background, 0.6)
print('$primary: ' + primary + ';')
print('$onPrimary: ' + onPrimary + ';')
print('$primaryContainer: ' + primaryContainer + ';')
print('$onPrimaryContainer: ' + onPrimaryContainer + ';')
print('$secondary: ' + secondary + ';')
print('$onSecondary: ' + onSecondary + ';')
print('$secondaryContainer: ' + secondaryContainer + ';')
print('$onSecondaryContainer: ' + onSecondaryContainer + ';')
print('$tertiary: ' + tertiary + ';')
print('$onTertiary: ' + onTertiary + ';')
print('$tertiaryContainer: ' + tertiaryContainer + ';')
print('$onTertiaryContainer: ' + onTertiaryContainer + ';')
print('$error: ' + error + ';')
print('$onError: ' + onError + ';')
print('$errorContainer: ' + errorContainer + ';')
print('$onErrorContainer: ' + onErrorContainer + ';')
print('$colorbarbg: ' + background + ';')
print('$background: ' + background + ';')
print('$onBackground: ' + onBackground + ';')
print('$surface: ' + surface + ';')
print('$onSurface: ' + onSurface + ';')
print('$surfaceVariant: ' + surfaceVariant + ';')
print('$onSurfaceVariant: ' + onSurfaceVariant + ';')
print('$outline: ' + outline + ';')
print('$shadow: ' + shadow + ';')
print('$inverseSurface: ' + inverseSurface + ';')
print('$inverseOnSurface: ' + inverseOnSurface + ';')
print('$inversePrimary: ' + inversePrimary + ';')

View file

@ -0,0 +1,57 @@
$primary: lighten($color4, 20%);
$onPrimary: darken($color2, 20%);
$primaryContainer: darken($color2, 10%);
$onPrimaryContainer: lighten($color4, 10%);
$secondary: desaturate(lighten($color5, 20%), 20%);
$onSecondary: desaturate(darken($color3, 20%), 20%);
$secondaryContainer: desaturate(darken($color3, 20%), 20%);
$onSecondaryContainer: desaturate(lighten($color5, 20%), 20%);
$tertiary: adjust-hue(lighten($color4, 20%), 30deg);
$onTertiary: adjust-hue(darken($color2, 20%), 30deg);
$tertiaryContainer: adjust-hue(darken($color2, 10%), 30deg);
$tertiaryContainer: adjust-hue(lighten($color4, 10%), 30deg);
$error: #ffb4a9;
$onError: #680003;
$errorContainer: #930006;
$onErrorContainer: #ffb4a9;
$colorbarbg: $color0;
$background: $color0;
$onBackground: $color7;
$surface: $color0;
$onSurface: $color7;
$surfaceVariant: $color1;
$onSurfaceVariant: $color7;
$outline: $color7;
$shadow: #000000;
$inverseSurface: invert($surface);
$inverseOnSurface: invert($onSurface);
$inversePrimary: invert($primary);
.primary { color: $primary; }
.onPrimary { color: $onPrimary; }
.primaryContainer { color: $primaryContainer; }
.onPrimaryContainer { color: $onPrimaryContainer; }
.secondary { color: $secondary; }
.onSecondary { color: $onSecondary; }
.secondaryContainer { color: $secondaryContainer; }
.onSecondaryContainer { color: $onSecondaryContainer; }
.tertiary { color: $tertiary; }
.onTertiary { color: $onTertiary; }
.tertiaryContainer { color: $tertiaryContainer; }
.onTertiaryContainer { color: $tertiaryContainer; }
.error { color: $error; }
.onError { color: $onError; }
.errorContainer { color: $errorContainer; }
.onErrorContainer { color: $onErrorContainer; }
.colorbarbg { color: $colorbarbg; }
.background { color: $background; }
.onBackground { color: $onBackground; }
.surface { color: $surface; }
.onSurface { color: $onSurface; }
.surfaceVariant { color: $surfaceVariant; }
.onSurfaceVariant { color: $onSurfaceVariant; }
.outline { color: $outline; }
.shadow { color: $shadow; }
.inverseSurface { color: $inverseSurface; }
.inverseOnSurface { color: $inverseOnSurface; }
.inversePrimary { color: $inversePrimary; }

View file

@ -0,0 +1,30 @@
$darkmode: true;
$primary: #e2e2e2;
$onPrimary: #000000;
$primaryContainer: #6b6b6b;
$onPrimaryContainer: #e2e2e2;
$secondary: #e2e2e2;
$onSecondary: #000000;
$secondaryContainer: #313131;
$onSecondaryContainer: #e2e2e2;
$tertiary: #e2e2e2;
$onTertiary: #000000;
$tertiaryContainer: #000000;
$onTertiaryContainer: #e2e2e2;
$error: #e2e2e2;
$onError: #000000;
$errorContainer: #000000;
$onErrorContainer: #e2e2e2;
$colorbarbg: #000000;
$background: #000000;
$onBackground: #e2e2e2;
$surface: #161616;
$onSurface: #e2e2e2;
$surfaceVariant: #242424;
$onSurfaceVariant: #e2e2e2;
$outline: #a1a1a1;
$shadow: #000000;
$inverseSurface: #e2e2e2;
$inverseOnSurface: #000000;
$inversePrimary: #e2e2e2;

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
color=$(hyprpicker --no-fancy)
# Generate colors for ags n stuff
"$HOME"/.config/ags/scripts/color_generation/colorgen.sh "${color}" --apply

View file

@ -0,0 +1,29 @@
#!/usr/bin/env bash
if [ "$1" == "--noswitch" ]; then
imgpath=$(swww query | awk -F 'image: ' '{print $2}')
# imgpath=$(ags run-js 'wallpaper.get(0)')
else
# Select and set image (hyprland)
cd "$HOME/Pictures"
imgpath=$(yad --width 1200 --height 800 --file --title='Choose wallpaper')
screensizey=$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2 | head -1)
cursorposx=$(hyprctl cursorpos -j | gojq '.x' 2>/dev/null) || cursorposx=960
cursorposy=$(hyprctl cursorpos -j | gojq '.y' 2>/dev/null) || cursorposy=540
cursorposy_inverted=$(( screensizey - cursorposy ))
if [ "$imgpath" == '' ]; then
echo 'Aborted'
exit 0
fi
# ags run-js "wallpaper.set('')"
# sleep 0.1 && ags run-js "wallpaper.set('${imgpath}')" &
swww img "$imgpath" --transition-step 100 --transition-fps 60 \
--transition-type grow --transition-angle 30 --transition-duration 1 \
--transition-pos "$cursorposx, $cursorposy_inverted"
fi
# Generate colors for ags n stuff
"$HOME"/.config/ags/scripts/color_generation/colorgen.sh "${imgpath}" --apply

View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash
hyprctl dispatch "$1" $(((($(hyprctl activeworkspace -j | gojq -r .id) - 1) / 10) * 10 + $2))

View file

@ -0,0 +1,243 @@
#!/usr/bin/env bash
set -euo pipefail
## Defaults
keepGensDef=30; keepDaysDef=30
keepGens=$keepGensDef; keepDays=$keepDaysDef
## Usage
usage () {
printf "Usage:\n\t ./trim-generations.sh <keep-gernerations> <keep-days> <profile> \n\n
(defaults are: Keep-Gens=$keepGensDef Keep-Days=$keepDaysDef Profile=user)\n\n"
printf "If you enter any parameters, you must enter all three, or none to use defaults.\n"
printf "Example:\n\t trim-generations.sh 15 10 home-manager\n"
printf " this will work on the home-manager profile and keep all generations from the\n"
printf "last 10 days, and keep at least 15 generations no matter how old.\n"
printf "\nProfiles available are:\tuser, home-manager, channels, system (root)\n"
printf "\n-h or --help prints this help text."
}
if [ $# -eq 1 ]; then # if help requested
if [ $1 = "-h" ]; then
usage
exit 1;
fi
if [ $1 = "--help" ]; then
usage
exit 2;
fi
printf "Dont recognise your option exiting..\n\n"
usage
exit 3;
elif [ $# -eq 0 ]; then # print the defaults
printf "The current defaults are:\n Keep-Gens=$keepGensDef Keep-Days=$keepDaysDef \n\n"
read -p "Keep these defaults? (y/n):" answer
case "$answer" in
[yY1] )
printf "Using defaults..\n"
;;
[nN0] ) printf "ok, doing nothing, exiting..\n"
exit 6;
;;
* ) printf "%b" "Doing nothing, exiting.."
exit 7;
;;
esac
fi
## Handle parameters (and change if root)
if [[ $EUID -ne 0 ]]; then # if not root
profile=$(readlink /home/$USER/.nix-profile)
else
if [ -d /nix/var/nix/profiles/system ]; then # maybe this or the other
profile="/nix/var/nix/profiles/system"
elif [ -d /nix/var/nix/profiles/default ]; then
profile="/nix/var/nix/profiles/default"
else
echo "Cant find profile for root. Exiting"
exit 8
fi
fi
if (( $# < 1 )); then
printf "Keeping default: $keepGensDef generations OR $keepDaysDef days, whichever is more\n"
elif [[ $# -le 2 ]]; then
printf "\nError: Not enough arguments.\n\n" >&2
usage
exit 1
elif (( $# > 4)); then
printf "\nError: Too many arguments.\n\n" >&2
usage
exit 2
else
if [ $1 -lt 1 ]; then
printf "using Gen numbers less than 1 not recommended. Setting to min=1\n"
read -p "is that ok? (y/n): " asnwer
#printf "$asnwer"
case "$asnwer" in
[yY1] )
printf "ok, continuing..\n"
;;
[nN0] )
printf "ok, doing nothing, exiting..\n"
exit 6;
;;
* )
printf "%b" "Doing nothing, exiting.."
exit 7;
;;
esac
fi
if [ $2 -lt 0 ]; then
printf "using negative days number not recommended. Setting to min=0\n"
read -p "is that ok? (y/n): " asnwer
case "$asnwer" in
[yY1] )
printf "ok, continuing..\n"
;;
[nN0] )
printf "ok, doing nothing, exiting..\n"
exit 6;
;;
* )
printf "%b" "Doing nothing, exiting.."
exit 7;
;;
esac
fi
keepGens=$1; keepDays=$2;
(( keepGens < 1 )) && keepGens=1
(( keepDays < 0 )) && keepDays=0
if [[ $EUID -ne 0 ]]; then
if [[ $3 == "user" ]] || [[ $3 == "default" ]]; then
profile=$(readlink /home/$USER/.nix-profile)
elif [[ $3 == "home-manager" ]]; then
# home-manager defaults to $XDG_STATE_HOME; otherwise, use
# `home-manager generations` and `nix-store --query --roots
# /nix/store/...` to figure out what reference is keeping the old
# generations alive.
profile="${XDG_STATE_HOME:-$HOME/.local/state}/nix/profiles/home-manager"
elif [[ $3 == "channels" ]]; then
profile="/nix/var/nix/profiles/per-user/$USER/channels"
else
printf "\nError: Do not understand your third argument. Should be one of: (user / home-manager/ channels)\n\n"
usage
exit 3
fi
else
if [[ $3 == "system" ]]; then
profile="/nix/var/nix/profiles/system"
elif [[ $3 == "user" ]] || [[ $3 == "default" ]]; then
profile="/nix/var/nix/profiles/default"
else
printf "\nError: Do not understand your third argument. Should be one of: (user / system)\n\n"
usage
exit 3
fi
fi
printf "OK! \t Keep Gens = $keepGens \t Keep Days = $keepDays\n\n"
fi
printf "Operating on profile: \t $profile\n\n"
## Runs at the end, to decide whether to delete profiles that match chosen parameters.
choose () {
local default="$1"
local prompt="$2"
local answer
read -p "$prompt" answer
[ -z "$answer" ] && answer="$default"
case "$answer" in
[yY1] ) #printf "answered yes!\n"
nix-env --delete-generations -p $profile ${!gens[@]}
exit 0
;;
[nN0] ) printf "Ok doing nothing exiting..\n"
exit 6;
;;
* ) printf "%b" "Unexpected answer '$answer'!" >&2
exit 7;
;;
esac
} # end of function choose
# printf "profile = $profile\n\n"
## Query nix-env for generations list
IFS=$'\n' nixGens=( $(nix-env --list-generations -p $profile | sed 's:^\s*::; s:\s*$::' | tr '\t' ' ' | tr -s ' ') )
timeNow=$(date +%s)
## Get info on oldest generation
IFS=' ' read -r -a oldestGenArr <<< "${nixGens[0]}"
oldestGen=${oldestGenArr[0]}
oldestDate=${oldestGenArr[1]}
printf "%-30s %s\n" "oldest generation:" $oldestGen
#oldestDate=${nixGens[0]:3:19}
printf "%-30s %s\n" "oldest generation created:" $oldestDate
oldestTime=$(date -d "$oldestDate" +%s)
oldestElapsedSecs=$((timeNow-oldestTime))
oldestElapsedMins=$((oldestElapsedSecs/60))
oldestElapsedHours=$((oldestElapsedMins/60))
oldestElapsedDays=$((oldestElapsedHours/24))
printf "%-30s %s\n" "minutes before now:" $oldestElapsedMins
printf "%-30s %s\n" "hours before now:" $oldestElapsedHours
printf "%-30s %s\n\n" "days before now:" $oldestElapsedDays
## Get info on current generation
for i in "${nixGens[@]}"; do
IFS=' ' read -r -a iGenArr <<< "$i"
genNumber=${iGenArr[0]}
genDate=${iGenArr[1]}
if [[ "$i" =~ current ]]; then
currentGen=$genNumber
printf "%-30s %s\n" "current generation:" $currentGen
currentDate=$genDate
printf "%-30s %s\n" "current generation created:" $currentDate
currentTime=$(date -d "$currentDate" +%s)
currentElapsedSecs=$((timeNow-currentTime))
currentElapsedMins=$((currentElapsedSecs/60))
currentElapsedHours=$((currentElapsedMins/60))
currentElapsedDays=$((currentElapsedHours/24))
printf "%-30s %s\n" "minutes before now:" $currentElapsedMins
printf "%-30s %s\n" "hours before now:" $currentElapsedHours
printf "%-30s %s\n\n" "days before now:" $currentElapsedDays
fi
done
## Compare oldest and current generations
timeBetweenOldestAndCurrent=$((currentTime-oldestTime))
elapsedDays=$((timeBetweenOldestAndCurrent/60/60/24))
generationsDiff=$((currentGen-oldestGen))
## Figure out what we should do, based on generations and options
if [[ elapsedDays -le keepDays ]]; then
printf "All generations are no more than $keepDays days older than current generation. \nOldest gen days difference from current gen: $elapsedDays \n\n\tNothing to do!\n"
exit 4;
elif [[ generationsDiff -lt keepGens ]]; then
printf "Oldest generation ($oldestGen) is only $generationsDiff generations behind current ($currentGen). \n\n\t Nothing to do!\n"
exit 5;
else
printf "\tSomething to do...\n"
declare -a gens
for i in "${nixGens[@]}"; do
IFS=' ' read -r -a iGenArr <<< "$i"
genNumber=${iGenArr[0]}
genDiff=$((currentGen-genNumber))
genDate=${iGenArr[1]}
genTime=$(date -d "$genDate" +%s)
elapsedSecs=$((timeNow-genTime))
genDaysOld=$((elapsedSecs/60/60/24))
if [[ genDaysOld -gt keepDays ]] && [[ genDiff -ge keepGens ]]; then
gens["$genNumber"]="$genDate, $genDaysOld day(s) old"
fi
done
printf "\nFound the following generation(s) to delete:\n"
for K in "${!gens[@]}"; do
printf "generation $K \t ${gens[$K]}\n"
done
printf "\n"
choose "y" "Do you want to delete these? [Y/n]: "
fi

View file

@ -0,0 +1,22 @@
#!/usr/bin/env bash
getdate() {
date '+%Y%m%d_%H-%M-%S'
}
cd ~/Videos || exit
if pgrep wf-recorder > /dev/null; then
notify-send "Recording Stopped" "Stopped" -a 'record-script.sh' &
pkill wf-recorder &
else
notify-send "Starting recording" 'recording_'"$(getdate)"'.mp4' -a 'record-script.sh'
if [[ "$1" == "--sound" ]]; then
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$(slurp)" --audio=alsa_output.pci-0000_08_00.6.analog-stereo.monitor & disown
elif [[ "$1" == "--fullscreen-sound" ]]; then
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --audio=alsa_output.pci-0000_08_00.6.analog-stereo.monitor & disown
elif [[ "$1" == "--fullscreen" ]]; then
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t & disown
else
wf-recorder --pixel-format yuv420p -f './recording_'"$(getdate)"'.mp4' -t --geometry "$(slurp)" & disown
fi
fi

View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Check if sway is running
if ! pgrep -x sway > /dev/null; then
echo "Sway is not running"
exit 1
fi
# Get the current workspace number
current=$(swaymsg -t get_workspaces | gojq '.[] | select(.focused==true) | .num')
# Check if a number was passed as an argument
if [[ "$1" =~ ^[+-]?[0-9]+$ ]]; then
new_workspace=$((current + $1))
else
new_workspace=$((current + 1))
fi
# Check if the new workspace number is out of bounds
if [[ $new_workspace -lt 1 ]]; then
exit 0
fi
# Switch to the new workspace
if [[ $2 == 'move' ]]; then
swaymsg move container to workspace $new_workspace
else
swaymsg workspace $new_workspace
fi

View file

@ -0,0 +1,133 @@
shell=fish
term=xterm-256color
title=foot
font=SpaceMono Nerd Font:size=11
letter-spacing=0
# horizontal-letter-offset=0
# vertical-letter-offset=0
# underline-offset=<font metrics>
# box-drawings-uses-font-glyphs=no
dpi-aware=no
# initial-window-size-pixels=700x500 # Or,
# initial-window-size-chars=<COLSxROWS>
# initial-window-mode=windowed
pad=25x25 # optionally append 'center'
# resize-delay-ms=100
# notify=notify-send -a ${app-id} -i ${app-id} ${title} ${body}
bold-text-in-bright=no
# word-delimiters=,│`|:"'()[]{}<>
# selection-target=primary
# workers=<number of logical CPUs>
[scrollback]
lines=10000
[url]
# launch=xdg-open ${url}
# label-letters=sadfjklewcmpgh
# osc8-underline=url-mode
# protocols=http, https, ftp, ftps, file, gemini, gopher
# uri-characters=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.,~:;/?#@!$&%*+="'
[cursor]
style=beam
color={{ $background }} {{ $onBackground }}
# blink=no
beam-thickness=1.5
# underline-thickness=<font underline thickness>
[colors]
alpha=1
background={{ $background }}
foreground={{ $onBackground }}
regular0={{ $background }}
regular1={{ $error }}
regular2={{ $inversePrimary }}
regular3={{ $onPrimaryContainer }}
regular4={{ $onPrimaryContainer }}
regular5={{ $onSecondaryContainer }}
regular6={{ $primary }}
regular7={{ $onSurfaceVariant }}
bright0={{ $background }}
bright1={{ $error }}
bright2={{ $inversePrimary }}
bright3={{ $onPrimaryContainer }}
bright4={{ $onPrimaryContainer }}
bright5={{ $onSecondaryContainer }}
bright6={{ $primary }}
bright7={{ $onSurfaceVariant }}
[csd]
# preferred=server
# size=26
# font=<primary font>
# color=<foreground color>
# button-width=26
# button-color=<background color>
# button-minimize-color=<regular4>
# button-maximize-color=<regular2>
# button-close-color=<regular1>
[key-bindings]
scrollback-up-page=Page_Up
# scrollback-up-half-page=none
# scrollback-up-line=none
scrollback-down-page=Page_Down
# scrollback-down-half-page=none
# scrollback-down-line=none
clipboard-copy=Control+c
clipboard-paste=Control+v
# primary-paste=Shift+Insert
search-start=Control+f
# font-increase=Control+plus Control+equal Control+KP_Add
# font-decrease=Control+minus Control+KP_Subtract
# font-reset=Control+0 Control+KP_0
# spawn-terminal=Control+Shift+n
# minimize=none
# maximize=none
# fullscreen=none
# pipe-visible=[sh -c "xurls | fuzzel | xargs -r firefox"] none
# pipe-scrollback=[sh -c "xurls | fuzzel | xargs -r firefox"] none
# pipe-selected=[xargs -r firefox] none
# show-urls-launch=Control+Shift+u
# show-urls-copy=none
[search-bindings]
cancel=Escape
find-prev=Shift+F3
find-next=F3 Control+G
# commit=Return
# cursor-left=Left Control+b
# cursor-left-word=Control+Left Mod1+b
# cursor-right=Right Control+f
# cursor-right-word=Control+Right Mod1+f
# cursor-home=Home Control+a
# cursor-end=End Control+e
# delete-prev=BackSpace
# delete-prev-word=Control+BackSpace
# delete-next=Delete
# delete-next-word=Mod1+d Control+Delete
# extend-to-word-boundary=Control+w
# extend-to-next-whitespace=Control+Shift+w
# clipboard-paste=Control+v Control+y
# primary-paste=Shift+Insert
[url-bindings]
# cancel=Control+g Control+c Control+d Escape
# toggle-url-visible=t
[mouse-bindings]
# primary-paste=BTN_MIDDLE
# select-begin=BTN_LEFT
# select-begin-block=Control+BTN_LEFT
# select-extend=BTN_RIGHT
# select-extend-character-wise=Control+BTN_RIGHT
# select-word=BTN_LEFT-2
# select-word-whitespace=Control+BTN_LEFT-2
# select-row=BTN_LEFT-3

View file

@ -0,0 +1,21 @@
font=Gabarito
terminal=foot -e
prompt=">> "
layer=overlay
[colors]
background={{ $background }}ff
text={{ $onBackground }}ff
selection={{ $surfaceVariant }}ff
selection-text={{ $onSurfaceVariant }}ff
border={{ $surfaceVariant }}ff
match={{ $primary }}ff
selection-match={{ $primary }}ff
[border]
radius=17
width=2
[dmenu]
exit-immediately-if-empty=yes

View file

@ -0,0 +1,144 @@
{
"name": "Material3_Generated",
"variables": {
"theme_fg_color": "#AEE5FA",
"theme_text_color": "#AEE5FA",
"theme_bg_color": "#1a1b26",
"theme_base_color": "#1a1b26",
"theme_selected_bg_color": "#AEE5FA",
"theme_selected_fg_color": "rgba(0, 0, 0, 0.87)",
"insensitive_bg_color": "#1a1b26",
"insensitive_fg_color": "rgba(192, 202, 245, 0.5)",
"insensitive_base_color": "#24283b",
"theme_unfocused_fg_color": "#AEE5FA",
"theme_unfocused_text_color": "#c0caf5",
"theme_unfocused_bg_color": "#1a1b26",
"theme_unfocused_base_color": "#1a1b26",
"theme_unfocused_selected_bg_color": "#a9b1d6",
"theme_unfocused_selected_fg_color": "rgba(0, 0, 0, 0.87)",
"unfocused_insensitive_color": "rgba(192, 202, 245, 0.5)",
"borders": "rgba(192, 202, 245, 0.12)",
"unfocused_borders": "rgba(192, 202, 245, 0.12)",
"warning_color": "#FDD633",
"error_color": "#BA1B1B",
"success_color": "#81C995",
"wm_title": "#AEE5FA",
"wm_unfocused_title": "rgba(192, 202, 245, 0.7)",
"wm_highlight": "rgba(192, 202, 245, 0.1)",
"wm_bg": "#1a1b26",
"wm_unfocused_bg": "#1a1b26",
"wm_button_close_icon": "#1a1b26",
"wm_button_close_hover_bg": "#a9b1d6",
"wm_button_close_active_bg": "#c7c7c7",
"content_view_bg": "#1a1b26",
"placeholder_text_color": "silver",
"text_view_bg": "#1d1d1d",
"budgie_tasklist_indicator_color": "#90D1F6",
"budgie_tasklist_indicator_color_active": "#90D1F6",
"budgie_tasklist_indicator_color_active_window": "#999999",
"budgie_tasklist_indicator_color_attention": "#FDD633",
"STRAWBERRY_100": "#FF9262",
"STRAWBERRY_300": "#FF793E",
"STRAWBERRY_500": "#F15D22",
"STRAWBERRY_700": "#CF3B00",
"STRAWBERRY_900": "#AC1800",
"ORANGE_100": "#FFDB91",
"ORANGE_300": "#FFCA40",
"ORANGE_500": "#FAA41A",
"ORANGE_700": "#DE8800",
"ORANGE_900": "#C26C00",
"BANANA_100": "#FFFFA8",
"BANANA_300": "#FFFA7D",
"BANANA_500": "#FFCE51",
"BANANA_700": "#D1A023",
"BANANA_900": "#A27100",
"LIME_100": "#A2F3BE",
"LIME_300": "#8ADBA6",
"LIME_500": "#73C48F",
"LIME_700": "#479863",
"LIME_900": "#1C6D38",
"BLUEBERRY_100": "#94A6FF",
"BLUEBERRY_300": "#6A7CE0",
"BLUEBERRY_500": "#3F51B5",
"BLUEBERRY_700": "#213397",
"BLUEBERRY_900": "#031579",
"GRAPE_100": "#D25DE6",
"GRAPE_300": "#B84ACB",
"GRAPE_500": "#9C27B0",
"GRAPE_700": "#830E97",
"GRAPE_900": "#6A007E",
"COCOA_100": "#9F9792",
"COCOA_300": "#7B736E",
"COCOA_500": "#574F4A",
"COCOA_700": "#463E39",
"COCOA_900": "#342C27",
"SILVER_100": "#EEE",
"SILVER_300": "#CCC",
"SILVER_500": "#AAA",
"SILVER_700": "#888",
"SILVER_900": "#666",
"SLATE_100": "#888",
"SLATE_300": "#666",
"SLATE_500": "#444",
"SLATE_700": "#222",
"SLATE_900": "#111",
"BLACK_100": "#474341",
"BLACK_300": "#403C3A",
"BLACK_500": "#393634",
"BLACK_700": "#33302F",
"BLACK_900": "#2B2928",
"accent_bg_color": "{{ $primary }}",
"accent_fg_color": "{{ $onPrimary }}",
"accent_color": "{{ $primary }}",
"destructive_bg_color": "{{ $error }}",
"destructive_fg_color": "{{ $onError }}",
"destructive_color": "{{ $error }}",
"success_bg_color": "#81C995",
"success_fg_color": "rgba(0, 0, 0, 0.87)",
"warning_bg_color": "#FDD633",
"warning_fg_color": "rgba(0, 0, 0, 0.87)",
"error_bg_color": "{{ $error }}",
"error_fg_color": "{{ $onError }}",
"window_bg_color": "{{ $background }}",
"window_fg_color": "{{ $onBackground }}",
"view_bg_color": "{{ $surface }}",
"view_fg_color": "{{ $onSurface }}",
"headerbar_bg_color": "mix(@dialog_bg_color, @window_bg_color, 0.5)",
"headerbar_fg_color": "{{ $onSecondaryContainer }}",
"headerbar_border_color": "{{ $secondaryContainer }}",
"headerbar_backdrop_color": "@headerbar_bg_color",
"headerbar_shade_color": "rgba(0, 0, 0, 0.09)",
"card_bg_color": "{{ $background }}",
"card_fg_color": "{{ $onSecondaryContainer }}",
"card_shade_color": "rgba(0, 0, 0, 0.09)",
"dialog_bg_color": "{{ $secondaryContainer }}",
"dialog_fg_color": "{{ $onSecondaryContainer }}",
"popover_bg_color": "{{ $secondaryContainer }}",
"popover_fg_color": "{{ $onSecondaryContainer }}",
"thumbnail_bg_color": "#1a1b26",
"thumbnail_fg_color": "#AEE5FA",
"shade_color": "rgba(0, 0, 0, 0.36)",
"scrollbar_outline_color": "rgba(0, 0, 0, 0.5)",
"sidebar_bg_color": "@window_bg_color",
"sidebar_fg_color":"@window_fg_color",
"sidebar_border_color": "@sidebar_bg_color",
"sidebar_backdrop_color": "@sidebar_bg_color"
},
"palette": {
"blue_": {},
"green_": {},
"yellow_": {},
"orange_": {},
"red_": {},
"purple_": {},
"brown_": {},
"light_": {},
"dark_": {}
},
"custom_css": {
"gtk4": "",
"gtk3": ""
},
"plugins": {}
}

View file

@ -0,0 +1,89 @@
// Could just sed but scss is better
@import '../../../scss/_material.scss'; // Which is ~/.config/ags/scss/_material.scss
* {
all: unset;
border: 0rem;
}
window {
background-color: transparentize($background, 0.6);
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
#window-box {
border-radius: 1.5rem;
padding: 1.5rem;
}
#input-label {
font-size: 1.5rem;
color: transparent;
background-color: transparent;
margin: -20rem; // bye bye
}
#input-field {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
caret-color: $onSecondaryContainer;
border-radius: 999px;
font-size: 1.3rem;
padding: 0.341rem 1.364rem;
margin: 0.477rem;
box-shadow: 2px 2px 4px rgba(22, 22, 22, 0.5);
min-height: 2.727rem;
}
#unlock-button {
margin: -20rem; // bye bye
color: transparent;
background-color: transparent;
}
#error-label {
color: $error;
}
#clock-label {
font-family: 'Lexend';
font-size: 6rem;
border-radius: 1.2rem;
padding: 0.5rem;
margin: 0.6rem;
margin-top: -35rem; // higher clock position
color: $onSecondaryContainer;
text-shadow: 1px 1px 2px rgba(22, 22, 30, 0.5);
}
// #user-image {}
// #powerbar-box {}
#poweroff-button,
#reboot-button,
#suspend-button {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
min-width: 3rem;
min-height: 3rem;
margin: 0.341rem;
border-radius: 9999px;
}
#poweroff-button:hover,
#reboot-button:hover,
#suspend-button:hover,
#poweroff-button:focus,
#reboot-button:focus,
#suspend-button:focus {
background-color: mix($secondaryContainer, white, 80%);
}
#poweroff-button:active,
#reboot-button:active,
#suspend-button:active {
background-color: mix($secondaryContainer, white, 70%);
}

View file

@ -0,0 +1,32 @@
$SLURP_COMMAND="$(slurp -d -c {{ $onSecondaryContainer }}BB -b {{ $secondaryContainer }}44 -s 00000000)"
general {
col.active_border = rgba({{ $onPrimary }}FF)
col.inactive_border = rgba({{ $secondaryContainer }}CC)
}
misc {
background_color = rgba({{ $surface }}FF)
}
plugin {
hyprbars {
# Honestly idk if it works like css, but well, why not
bar_text_font = Rubik, Geist, AR One Sans, Reddit Sans, Inter, Roboto, Ubuntu, Noto Sans, sans-serif
bar_height = 30
bar_padding = 10
bar_button_padding = 5
bar_precedence_over_border = true
bar_part_of_window = true
bar_color = rgb({{ $background }})
col.text = rgb({{ $onBackground }})
# example buttons (R -> L)
# hyprbars-button = color, size, on-click
hyprbars-button = rgb({{ $onBackground }}), 13, 󰖭, hyprctl dispatch killactive
hyprbars-button = rgb({{ $onBackground }}), 13, 󰖯, hyprctl dispatch fullscreen 1
hyprbars-button = rgb({{ $onBackground }}), 13, 󰖰, hyprctl dispatch movetoworkspacesilent special
}
}

View file

@ -0,0 +1 @@
]4;0;#$background #\]4;1;#$error #\]4;2;#$inversePrimary #\]4;3;#$onPrimaryContainer #\]4;4;#$onPrimaryContainer #\]4;5;#$onSecondaryContainer #\]4;6;#$primary #\]4;7;#$onSurfaceVariant #\]4;8;#$background #\]4;9;#$error #\]4;10;#$inversePrimary #\]4;11;#$onPrimaryContainer #\]4;12;#$onPrimaryContainer #\]4;13;#$onSecondaryContainer #\]4;14;#$primary #\]4;15;#$onSurfaceVariant #\]10;#$onSurfaceVariant #\]11;#$background #\]12;#$onSurfaceVariant #\]13;#$onSurfaceVariant #\]17;#$onSurfaceVariant #\]19;#$background #\]4;232;#$background #\]4;256;#$onSurfaceVariant #\]708;#$background #\

View file

@ -0,0 +1,81 @@
#!/usr/bin/env python
import sys
from dataclasses import dataclass
from signal import SIGINT, SIGTERM, signal
from threading import Event
from pywayland.client.display import Display
from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import (
ZwpIdleInhibitManagerV1,
)
from pywayland.protocol.wayland.wl_compositor import WlCompositor
from pywayland.protocol.wayland.wl_registry import WlRegistryProxy
from pywayland.protocol.wayland.wl_surface import WlSurface
@dataclass
class GlobalRegistry:
surface: WlSurface | None = None
inhibit_manager: ZwpIdleInhibitManagerV1 | None = None
def handle_registry_global(
wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int
) -> None:
global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry()
if iface_name == "wl_compositor":
compositor = wl_registry.bind(id_num, WlCompositor, version)
global_registry.surface = compositor.create_surface() # type: ignore
elif iface_name == "zwp_idle_inhibit_manager_v1":
global_registry.inhibit_manager = wl_registry.bind(
id_num, ZwpIdleInhibitManagerV1, version
)
def main() -> None:
done = Event()
signal(SIGINT, lambda _, __: done.set())
signal(SIGTERM, lambda _, __: done.set())
global_registry = GlobalRegistry()
display = Display()
display.connect()
registry = display.get_registry() # type: ignore
registry.user_data = global_registry
registry.dispatcher["global"] = handle_registry_global
def shutdown() -> None:
display.dispatch()
display.roundtrip()
display.disconnect()
display.dispatch()
display.roundtrip()
if global_registry.surface is None or global_registry.inhibit_manager is None:
print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.")
shutdown()
sys.exit(1)
inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore
global_registry.surface
)
display.dispatch()
display.roundtrip()
print("Inhibiting idle...")
done.wait()
print("Shutting down...")
inhibitor.destroy()
shutdown()
if __name__ == "__main__":
main()

View file

@ -0,0 +1,321 @@
// Made to be pixel-perfect with 11pt font size
// 1rem = 11pt = 14.6666666667px
$black: black;
$white: white;
$bar_ws_width: 1.774rem;
$bar_subgroup_bg: $surfaceVariant;
@mixin bar-group-rounding {
@include small-rounding;
}
.bar-height {
min-height: 2.727rem;
}
.bar-bg {
background-color: $t_background;
min-height: 2.727rem;
}
.bar-sidespace {
min-width: 1.5rem;
}
.bar-group-margin {
padding: 0.273rem 0rem;
}
.bar-group {
background-color: $l_l_t_surfaceVariant;
}
.bar-group-pad {
padding: 0.205rem;
}
.bar-group-pad-less {
padding: 0rem 0.681rem;
}
.bar-group-pad-system {
padding: 0rem 0.341rem;
}
.bar-group-pad-music {
padding-right: 1.023rem;
padding-left: 0.341rem;
}
.bar-group-standalone {
@include bar-group-rounding;
-gtk-outline-radius: 1.364rem;
}
.bar-group-round {
border-radius: 10rem;
-gtk-outline-radius: 10rem;
}
.bar-group-middle {
border-radius: 0.477rem;
-gtk-outline-radius: 0.477rem;
}
.bar-group-left {
border-radius: 0.477rem;
-gtk-outline-radius: 0.477rem;
border-top-left-radius: 1.364rem;
border-bottom-left-radius: 1.364rem;
}
.bar-group-right {
border-radius: 0.477rem;
-gtk-outline-radius: 0.477rem;
border-top-right-radius: 1.364rem;
border-bottom-right-radius: 1.364rem;
}
.bar-ws-width {
min-width: 18.341rem;
}
.bar-ws {
min-width: $bar_ws_width;
color: mix($onBackground, $background, 40%);
@if $darkmode ==true {
color: mix($onBackground, $background, 45%);
}
}
.bar-ws-active {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.bar-ws-occupied {
background-color: $bar_subgroup_bg;
color: $onSurfaceVariant;
}
.bar-separator {
@include full-rounding;
min-width: 0.341rem;
min-height: 0.341rem;
background-color: mix($t_surface, $t_onSurface, 90%);
margin: 0rem 0.341rem;
}
.bar-clock-box {
margin: 0rem 0.682rem;
}
.bar-clock {
@include titlefont;
font-size: 1.2727rem;
}
.bar-date {
@include titlefont;
font-size: 1rem;
color: $onBackground;
}
.bar-batt {
@include full-rounding;
@include element_decel;
min-height: 1.77rem;
min-width: 1.77rem;
border-radius: 10rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.bar-sidemodule {
min-width: 26rem;
}
.bar-batt-low {
background-color: $error;
color: $errorContainer;
}
.bar-batt-full {
background-color: $successContainer;
color: $onSuccessContainer;
}
.bar-batt-circprog {
@include fluent_decel_long;
min-width: 0.068rem; // line width
min-height: 1.636rem;
padding: 0rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.bar-batt-circprog-low {
background-color: $error;
color: $errorContainer;
}
.bar-batt-circprog-full {
background-color: $successContainer;
color: $onSuccessContainer;
}
.bar-music-playstate {
@include element_decel;
min-height: 1.77rem;
min-width: 1.77rem;
border-radius: 10rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.bar-music-circprog {
@include fluent_decel_long;
min-width: 0.068rem; // line width
min-height: 1.636rem;
padding: 0rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.bar-music-playstate-playing {
min-height: 1.77rem;
min-width: 1.77rem;
border-radius: 10rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.bar-music-playstate-txt {
transition: 100ms cubic-bezier(0.05, 0.7, 0.1, 1);
@include icon-material;
}
.bar-music-cover {
background-position: center;
background-repeat: no-repeat;
background-size: 100% auto;
min-width: 11.932rem;
}
.bar-music-extended-bg {
border-radius: 1.364rem;
min-width: 34.091rem;
}
.bar-music-extended-ctl-bg {
border-radius: 1.364rem;
background-color: rgba(30, 30, 30, 0.6);
}
.bar-music-hide-false {
@include menu_decel;
transition-duration: 100ms;
opacity: 1;
}
.bar-music-hide-true {
@include menu_accel;
transition-duration: 100ms;
opacity: 0;
}
.bar-corner-spacing {
min-width: $rounding_large;
min-height: $rounding_large;
}
.corner {
background-color: $t_background;
@include large-rounding;
}
.corner-black {
background-color: $black; // Hard code: fake screen corner
@include large-rounding;
}
.bar-topdesc {
margin-top: -0.136rem;
margin-bottom: -0.341rem;
color: $subtext;
}
.bar-space-button {
padding: 0.341rem;
}
.bar-space-button > box:first-child {
@include full-rounding;
padding: 0rem 0.682rem;
}
.bar-space-button:hover > box:first-child,
.bar-space-button:focus > box:first-child {
background-color: $hovercolor;
}
.bar-space-button:active > box:first-child {
background-color: $activecolor;
}
.bar-space-button-leftmost {
box {
margin: 0rem 0.682rem;
}
}
.bar-space-area-rightmost > box {
padding-right: 2.386rem;
}
.bar-systray {
@include full-rounding;
margin: 0.137rem 0rem;
padding: 0rem 0.682rem;
}
.bar-systray-item {
@include full-rounding;
@include element_decel;
min-height: 1.032rem;
min-width: 1.032rem;
font-size: 1.032rem;
}
.bar-statusicons {
@include full-rounding;
@include element_decel;
margin: 0.273rem;
padding: 0rem 0.614rem;
}
.bar-statusicons-hover {
background-color: mix($t_background, $t_onBackground, 90%);
}
.bar-statusicons-active {
background-color: mix($t_background, $t_onBackground, 80%);
}
.bar-util-btn {
@include full-rounding;
@include element_decel;
min-height: 1.77rem;
min-width: 1.77rem;
background-color: $bar_subgroup_bg;
}
.bar-util-btn:hover,
.bar-util-btn:focus {
background-color: mix($bar_subgroup_bg, $onSurfaceVariant, 90%);
}
.bar-util-btn:active {
background-color: mix($bar_subgroup_bg, $onSurfaceVariant, 80%);
}

View file

@ -0,0 +1,52 @@
.cheatsheet-bg {
@include large-rounding;
@include elevation-border;
@include elevation2;
margin-bottom: 0.682rem;
background-color: $t_background;
padding: 1.364rem;
}
.cheatsheet-key {
@include techfont;
min-height: 1.364rem;
min-width: 1.364rem;
margin: 0.17rem;
padding: 0.136rem 0.205rem;
border-radius: 0.409rem;
-gtk-outline-radius: 0.409rem;
color: $primary;
border: 0.068rem solid $primary;
box-shadow: 0rem 0.136rem 0rem $primary;
font-weight: 500;
}
.cheatsheet-key-notkey {
min-height: 1.364rem;
padding: 0.136rem 0.205rem;
margin: 0.17rem;
color: $onPrimaryContainer;
}
// .cheatsheet-action {}
.cheatsheet-closebtn {
@include element_decel;
@include full-rounding;
min-width: 2.386rem;
min-height: 2.386rem;
}
.cheatsheet-closebtn:hover,
.cheatsheet-closebtn:focus {
background-color: $hovercolor;
}
.cheatsheet-closebtn:active {
background-color: $activecolor;
}
.cheatsheet-category-title {
@include titlefont;
font-size: 1.705rem;
}

View file

@ -0,0 +1,132 @@
///////////// COLOR MODIFICATIONS /////////////
// Material colors provide excellent readability, but can be uninteresting.
// This is an attempt to improve that.
$transparency_enabled: false;
@if $transparency_enabled ==false {
@if $darkmode ==true {
$primary: mix($primary, white, 70%);
$primaryContainer: mix($primaryContainer, white, 90%);
$background: mix(mix($background, $primary, 94%), #000000, 50%);
$surface: mix($surface, $primaryContainer, 98%);
$surfaceVariant: mix($surfaceVariant, #000000, 75%);
// $secondaryContainer: mix($secondaryContainer, $primaryContainer, 90%);
}
@if $darkmode ==false {
$background: mix($background, $primary, 87%);
$surface: mix($surface, $primary, 93%);
$surfaceVariant: mix($surfaceVariant, #ffffff, 25%);
}
}
@if $transparency_enabled ==true {
@if $darkmode ==true {
$background: mix(mix($background, $primary, 94%), #000000, 50%);
$surface: mix($surface, $primaryContainer, 98%);
$surfaceVariant: mix($surfaceVariant, #000000, 55%);
}
@if $darkmode ==false {
$background: mix($background, $primary, 94%);
$surface: mix($surface, $primary, 93%);
$surfaceVariant: mix($surfaceVariant, #ffffff, 55%);
}
}
// Amounts
$transparentize_amount: 0.3;
$transparentize_surface_amount_less: 0.6;
$transparentize_surface_amount_less_less: 0.55;
$transparentize_surface_amount: 0.7;
$transparentize_surface_amount_more: 0.8;
$transparentize_surface_amount_subtract_surface: $transparentize_surface_amount - $transparentize_amount;
@if $darkmode ==true {
// Less transparency
$transparentize_amount: 0.15;
$transparentize_surface_amount_less: 0.5;
$transparentize_surface_amount_less_less: 0.55;
$transparentize_surface_amount: 0.69;
$transparentize_surface_amount_more: 0.9;
$transparentize_surface_amount_subtract_surface: $transparentize_surface_amount - $transparentize_amount;
}
@if $transparency_enabled ==false {
$transparentize_amount: 0;
}
// Extended material
$success: #4f6354;
$onSuccess: #ffffff;
$successContainer: #d1e8d5;
$onSuccessContainer: #0c1f13;
@if $darkmode ==true {
// Dark variant
$success: #b5ccba;
$onSuccess: #213528;
$successContainer: #374b3e;
$onSuccessContainer: #d1e9d6;
}
// Transparent versions
$t_primary: transparentize($primary, $transparentize_amount);
$t_onPrimary: transparentize($onPrimary, $transparentize_amount);
$t_primaryContainer: transparentize($primaryContainer, $transparentize_amount);
$t_onPrimaryContainer: transparentize($onPrimaryContainer, $transparentize_amount);
$t_secondary: transparentize($secondary, $transparentize_amount);
$t_onSecondary: transparentize($onSecondary, $transparentize_amount);
$t_secondaryContainer: transparentize($secondaryContainer, $transparentize_amount);
$l_t_secondaryContainer: transparentize($secondaryContainer, $transparentize_surface_amount_less);
$t_onSecondaryContainer: transparentize($onSecondaryContainer, $transparentize_amount);
$t_t_t_onSecondaryContainer: transparentize($onSecondaryContainer, 0.93);
$t_tertiary: transparentize($tertiary, $transparentize_amount);
$t_onTertiary: transparentize($onTertiary, $transparentize_amount);
$t_tertiaryContainer: transparentize($tertiaryContainer, $transparentize_amount);
$t_onTertiaryContainer: transparentize($onTertiaryContainer, $transparentize_amount);
$t_error: transparentize($error, $transparentize_amount);
$t_onError: transparentize($onError, $transparentize_amount);
$t_errorContainer: transparentize($errorContainer, $transparentize_amount);
$t_onErrorContainer: transparentize($onErrorContainer, $transparentize_amount);
$t_colorbarbg: transparentize($colorbarbg, $transparentize_amount);
$t_background: transparentize($background, $transparentize_amount);
$t_t_background: transparentize($background, $transparentize_surface_amount_more);
$t_onBackground: transparentize($onBackground, $transparentize_amount);
$t_surface: transparentize($surface, $transparentize_surface_amount);
$t_t_surface: transparentize($surface, $transparentize_surface_amount_more);
$t_onSurface: transparentize($onSurface, $transparentize_surface_amount);
$t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount);
$t_onSurfaceVariant: transparentize($onSurfaceVariant, $transparentize_surface_amount);
$t_t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount_more);
$l_t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount_less);
$l_l_t_surfaceVariant: transparentize($surfaceVariant, $transparentize_surface_amount_less_less);
$t_outline: transparentize($outline, $transparentize_amount);
$t_shadow: transparentize($shadow, $transparentize_amount);
$t_inverseSurface: transparentize($inverseSurface, $transparentize_amount);
$t_inverseOnSurface: transparentize($inverseOnSurface, $transparentize_amount);
$t_inversePrimary: transparentize($inversePrimary, $transparentize_amount);
// Transparent material (extended)
$t_success: transparentize($error, $transparentize_amount);
$t_onSuccess: transparentize($onError, $transparentize_amount);
$t_successContainer: transparentize($errorContainer, $transparentize_amount);
$t_onSuccessContainer: transparentize($onErrorContainer,
$transparentize_amount);
// Others
$hovercolor: mix($t_surface, $t_onSurface, 50%);
$activecolor: mix($t_surface, $t_onSurface, 30%);
$subtext: mix($onBackground, $background, 70%);
$actiontext: mix($onBackground, $background, 85%);
// Terminal colors
$termbg: mix($t_surfaceVariant, $t_onSurfaceVariant, 80%);
$termfg: $onSurfaceVariant;
$term0: $t_background;
$term1: $error;
$term2: $inversePrimary;
$term3: $onPrimaryContainer;
$term4: $onPrimaryContainer;
$term5: $onSecondaryContainer;
$term6: $primary;
$term7: $onSurfaceVariant;

View file

@ -0,0 +1,234 @@
// * {
// border: 1px solid $onSurfaceVariant; // Debugging
// }
// *:focus {
// outline: 1px solid mix($onSurface, $surface, 40%);
// -gtk-outline-radius: $rounding_small;
// }
* {
selection {
background-color: $secondary;
color: $onSecondary;
}
caret-color: $primary;
}
@keyframes appear {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
menu {
@include elevation-border-softer;
padding: 0.681rem;
background: $surfaceVariant;
color: $onSurfaceVariant;
border-radius: 1.159rem;
-gtk-outline-radius: 1.159rem;
animation-name: appear;
animation-duration: 40ms;
animation-timing-function: ease-out;
animation-iteration-count: 1;
}
menubar>menuitem {
border-radius: 0.545rem;
-gtk-outline-radius: 0.545rem;
min-width: 13.636rem;
min-height: 2.727rem;
}
menu>menuitem {
padding: 0.4em 1.5rem;
background: transparent;
transition: 0.2s ease background;
border-radius: 0.545rem;
-gtk-outline-radius: 0.545rem;
}
menu>menuitem:hover,
menu>menuitem:focus {
background-color: mix($surfaceVariant, $onSurfaceVariant, 90%);
}
menu>menuitem:active {
background-color: mix($surfaceVariant, $onSurfaceVariant, 80%);
}
radio {
@include full-rounding;
margin: 0.273rem;
min-width: 15px;
min-height: 15px;
border: 0.068rem solid $outline;
}
// radio:first-child {
// background-color: red;
// }
radio:checked {
min-width: 8px;
min-height: 8px;
background-color: $onPrimary;
border: 0.477rem solid $primary;
}
tooltip {
animation-name: appear;
animation-duration: 100ms;
animation-timing-function: ease-out;
animation-iteration-count: 1;
@include normal-rounding;
background-color: $surfaceVariant;
color: $onSurfaceVariant;
border: 1px solid $onSurfaceVariant;
}
/////////////////////////////////////////
// Emoji Chooser structure
// popover
// box.emoji-searchbar
// entry.search
// box.emoji-toolbar
// button.image-button.emoji-section
// ...
// button.image-button.emoji-section
popover {
@include elevation-border-softer;
padding: 0.681rem;
background: $surfaceVariant;
color: $onSurfaceVariant;
border-radius: 1.159rem;
-gtk-outline-radius: 1.159rem;
animation-name: appear;
animation-duration: 40ms;
animation-timing-function: ease-out;
animation-iteration-count: 1;
}
/////////////////////////////////////////
.configtoggle-box {
padding: 0.205rem 0.341rem;
border: 0.136rem solid transparent;
}
.configtoggle-box:focus {
border: 0.136rem solid mix($onSurface, $surface, 40%);
}
.switch-bg {
@include element_decel;
@include full-rounding;
background-color: mix($surface, $background, 50%);
border: 0.136rem solid $onSurface;
min-width: 2.864rem;
min-height: 1.637rem;
}
.switch-bg-true {
background-color: $primary;
border: 0.136rem solid $primary;
}
.switch-fg {
@include full-rounding;
@include menu_decel;
background-color: $onSurface;
color: $surface;
min-width: 0.819rem;
min-height: 0.819rem;
margin-left: 0.477rem;
}
.switch-fg-true {
background-color: $onPrimary;
color: $primary;
min-width: 1.431rem;
min-height: 1.431rem;
margin-left: 1.431rem;
}
.switch-fg-toggling-false {
@include menu_decel;
min-width: 1.636rem;
min-height: 0.819rem;
}
.segment-container {
@include full-rounding;
border: 0.068rem solid $outline;
}
.segment-container>*:first-child {
border-top-left-radius: 9999px;
border-bottom-left-radius: 9999px;
}
.segment-container>* {
border-right: 0.068rem solid $outline;
padding: 0.341rem 0.682rem;
}
.segment-container>*:last-child {
border-right: 0rem solid transparent;
border-top-right-radius: 9999px;
border-bottom-right-radius: 9999px;
}
.segment-btn {
color: $onSurface;
}
.segment-btn:focus,
.segment-btn:hover {
background-color: $hovercolor;
}
.segment-btn-enabled {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.segment-btn-enabled:hover,
.segment-btn-enabled:focus {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.gap-v-5 {
min-height: 0.341rem;
}
.gap-h-5 {
min-width: 0.341rem;
}
.gap-v-10 {
min-height: 0.682rem;
}
.gap-h-10 {
min-width: 0.682rem;
}
.gap-v-15 {
min-height: 1.023rem;
}
.gap-h-15 {
min-width: 1.023rem;
}

View file

@ -0,0 +1,94 @@
.bg-wallpaper-transition {
transition: 1000ms cubic-bezier(0.05, 0.7, 0.1, 1);
font-size: 1px;
}
@mixin bg-textshadow {
// text-shadow: mix($shadow, $secondaryContainer, 50%) 1px 0px 3px;
}
.bg-time-box {
@include large-rounding;
margin: 2.045rem;
padding: 0.682rem;
}
.bg-time-clock {
@include bg-textshadow;
font-family: 'Gabarito';
font-size: 5.795rem;
color: $onBackground;
}
.bg-time-date {
@include bg-textshadow;
font-family: 'Gabarito';
font-size: 2.591rem;
color: $onBackground;
}
.bg-distro-box {
@include large-rounding;
margin: 2.045rem;
padding: 0.682rem;
}
.bg-distro-txt {
@include bg-textshadow;
font-family: 'Gabarito';
font-size: 1.432rem;
color: $onBackground;
}
.bg-distro-name {
@include bg-textshadow;
font-family: 'Gabarito';
font-size: 1.432rem;
color: $onSecondaryContainer;
}
.bg-graph {
color: rgba(255, 255, 255, 0.5);
border-radius: 0.614rem;
border: 0.682rem solid;
}
.bg-quicklaunch-title {
@include mainfont;
color: $onSurfaceVariant;
}
.bg-quicklaunch-btn {
@include mainfont;
@include full-rounding;
background-color: $surfaceVariant;
color: $onSurfaceVariant;
border: 0.068rem solid $subtext;
min-width: 4.432rem;
min-height: 2.045rem;
padding: 0.273rem 0.682rem;
}
.bg-quicklaunch-btn:hover,
.bg-quicklaunch-btn:focus {
background-color: mix($surfaceVariant, $onSurfaceVariant, 95%);
}
.bg-quicklaunch-btn:active {
background-color: mix($surfaceVariant, $onSurfaceVariant, 90%);
}
.bg-system-bg {
@include normal-rounding;
// background-color: $background;
}
.bg-system-circprog {
@include fluent_decel_long;
// margin-left: 0.273rem;
min-width: 0.205rem; // Trough stroke width
min-height: 4.091rem; // Diameter
font-size: 0px;
padding: 0rem;
background-color: $surfaceVariant;
}

View file

@ -0,0 +1,31 @@
.dock-bg {
@include large-rounding;
@include elevation2;
background-color: $t_background;
padding: 0.682rem;
}
.dock-app-btn {
@include normal-rounding;
padding: 0.273rem;
}
.dock-app-btn:hover,
.dock-app-btn:focus {
background-color: mix($t_surface, $t_onSurface, 95%);
}
.dock-app-btn:active {
background-color: mix($t_surface, $t_onSurface, 85%);
}
.dock-app-icon {
min-width: 3.409rem;
min-height: 3.409rem;
font-size: 3.409rem;
}
.dock-separator {
min-width: 0.068rem;
background-color: $surfaceVariant;
}

View file

@ -0,0 +1,524 @@
.test {
background-image: linear-gradient(
45deg, #f4d609 0%, #f4d609 10%, #212121 10%, #212121 20%, #f4d609 20%, #f4d609 30%, #212121 30%,
#212121 40%, #f4d609 40%, #f4d609 50%, #212121 50%, #212121 60%, #f4d609 60%,
#f4d609 70%, #212121 70%, #212121 80%, #f4d609 80%, #f4d609 90%, #212121 90%, #212121 100%
);
background-repeat: repeat;
}
.test-size {
min-height: 3rem;
min-width: 3rem;
}
.txt-title {
@include titlefont;
font-size: 2.045rem;
}
.txt-title-small {
@include titlefont;
font-size: 1.364rem;
}
.techfont {
@include techfont;
}
.txt-reading {
@include readingfont;
}
.no-anim {
@include noanim;
}
.txt {
color: $onBackground;
}
.txt-primary {
color: $primary;
}
.txt-onSecondaryContainer {
color: $onSecondaryContainer;
}
.txt-onSurfaceVariant {
color: $onSurfaceVariant;
}
.txt-shadow {
text-shadow: 1px 2px 8px rgba(0, 0, 0, 0.69);
margin: 10px;
}
.txt-gigantic {
@include mainfont;
font-size: 3rem;
}
.txt-massive {
@include mainfont;
font-size: 2.7273rem;
}
.txt-hugerass {
@include mainfont;
font-size: 2.045rem;
}
.txt-hugeass {
@include mainfont;
font-size: 1.8182rem;
}
.txt-larger {
@include mainfont;
font-size: 1.6363rem;
}
.txt-large {
//16pt
@include mainfont;
font-size: 1.4545rem;
}
.txt-norm {
//14pt
@include mainfont;
font-size: 1.2727rem;
}
.txt-small {
//12pt
@include mainfont;
font-size: 1.0909rem;
}
.txt-smallie {
//11pt
@include mainfont;
font-size: 1rem;
}
.txt-smaller {
//10pt
@include mainfont;
font-size: 0.9091rem;
}
.txt-tiny {
@include mainfont;
font-size: 0.7273rem;
}
.txt-poof {
font-size: 0px;
}
.txt-subtext {
@include subtext;
}
.txt-action {
@include actiontext;
}
.txt-thin {
font-weight: 300;
}
.txt-semibold {
font-weight: 500;
}
.txt-bold {
font-weight: bold;
}
.txt-italic {
font-style: italic;
}
.btn-primary {
@include full-rounding;
background-color: $primary;
color: $onPrimary;
padding: 0.682rem 1.023rem;
}
.titlefont {
@include titlefont;
}
.mainfont {
@include mainfont;
}
.icon-material {
@include icon-material;
}
.icon-nerd {
@include icon-nerd;
}
.separator-line {
background-color: $outline;
min-width: 0.068rem;
min-height: 0.068rem;
}
.separator-circle {
@include full-rounding;
background-color: $outline;
margin: 0rem 0.682rem;
min-width: 0.273rem;
min-height: 0.273rem;
}
.spacing-h-3 > * {
margin-right: 0.205rem;
}
.spacing-h-3 > *:last-child {
margin-right: 0rem;
}
.spacing-v-3 > * {
margin-bottom: 0.205rem;
}
.spacing-v-3 > *:last-child {
margin-bottom: 0rem;
}
.spacing-v-15 > * {
margin-bottom: 1.023rem;
}
.spacing-v-15 > *:last-child {
margin-bottom: 0rem;
}
.spacing-h-15 > * {
margin-right: 1.023rem;
}
.spacing-h-15 > *:last-child {
margin-right: 0rem;
}
.spacing-h-15 > revealer > * {
margin-right: 1.023rem;
}
.spacing-h-15 > revealer:last-child > * {
margin-right: 0rem;
}
.spacing-h-15 > scrolledwindow > * {
margin-right: 1.023rem;
}
.spacing-h-15 > scrolledwindow:last-child > * {
margin-right: 0rem;
}
.spacing-v-5 > box {
margin-bottom: 0.341rem;
}
.spacing-v-5 > box:last-child {
margin-bottom: 0rem;
}
.spacing-v-5 > * {
margin-bottom: 0.341rem;
}
.spacing-v-5 > *:last-child {
margin-bottom: 0rem;
}
.spacing-v-5-revealer > revealer > * {
margin-bottom: 0.341rem;
}
.spacing-v-5-revealer > revealer:last-child > * {
margin-bottom: 0rem;
}
.spacing-v-5-revealer > scrolledwindow > * {
margin-bottom: 0.341rem;
}
.spacing-v-5-revealer > scrolledwindow:last-child > * {
margin-bottom: 0rem;
}
.spacing-h-4 > * {
margin-right: 0.273rem;
}
.spacing-h-4 > *:last-child {
margin-right: 0rem;
}
.spacing-h-4 > overlay > *:first-child {
margin-right: 0.273rem;
}
.spacing-h-4 > overlay:last-child > * {
margin-right: 0rem;
}
.spacing-h-5 > * {
margin-right: 0.341rem;
}
.spacing-h-5 > *:last-child {
margin-right: 0rem;
}
.spacing-h-5 > widget > * {
margin-right: 0.341rem;
}
.spacing-h-5 > widget:last-child > * {
margin-right: 0rem;
}
.spacing-h-5 > revealer > * {
margin-right: 0.341rem;
}
.spacing-h-5 > revealer:last-child > * {
margin-right: 0rem;
}
.spacing-h-5 > scrolledwindow > * {
margin-right: 0.341rem;
}
.spacing-h-5 > scrolledwindow:last-child > * {
margin-right: 0rem;
}
.spacing-v-minus5 > * {
margin-bottom: -0.341rem;
}
.spacing-v-minus5 > *:last-child {
margin-bottom: 0rem;
}
.spacing-h-10 > * {
margin-right: 0.682rem;
}
.spacing-h-10 > *:last-child {
margin-right: 0rem;
}
.spacing-h-10 > revealer > * {
margin-right: 0.682rem;
}
.spacing-h-10 > revealer:last-child > * {
margin-right: 0rem;
}
.spacing-h-10 > scrolledwindow > * {
margin-right: 0.682rem;
}
.spacing-h-10 > scrolledwindow:last-child > * {
margin-right: 0rem;
}
.spacing-h-10 > flowboxchild > * {
margin-right: 0.682rem;
}
.spacing-h-10 > flowboxchild:last-child > * {
margin-right: 0rem;
}
.spacing-v-10 > * {
margin-bottom: 0.682rem;
}
.spacing-v-10 > *:last-child {
margin-bottom: 0rem;
}
.spacing-h-20 > * {
margin-right: 1.364rem;
}
.spacing-h-20 > *:last-child {
margin-right: 0rem;
}
.spacing-v-20 > * {
margin-bottom: 1.364rem;
}
.spacing-v-20 > *:last-child {
margin-bottom: 0rem;
}
.anim-enter {
@include anim-enter;
}
.anim-exit {
@include anim-exit;
}
.button-minsize {
@include button-minsize;
}
.margin-right-5 {
margin-right: 0.341rem;
}
.margin-left-5 {
margin-left: 0.341rem;
}
.margin-top-5 {
margin-top: 0.341rem;
}
.margin-bottom-5 {
margin-bottom: 0.341rem;
}
.margin-right-10 {
margin-right: 0.682rem;
}
.margin-left-10 {
margin-left: 0.682rem;
}
.margin-top-10 {
margin-top: 0.682rem;
}
.margin-bottom-10 {
margin-bottom: 0.682rem;
}
.margin-right-15 {
margin-right: 1.023rem;
}
.margin-left-15 {
margin-left: 1.023rem;
}
.margin-top-15 {
margin-top: 1.023rem;
}
.margin-bottom-15 {
margin-bottom: 1.023rem;
}
.width-10 {
min-width: 0.682rem;
}
.height-10 {
min-width: 0.682rem;
}
.invisible {
opacity: 0;
background-color: transparent;
color: transparent;
}
.spacing-h--5 > box {
margin-right: -0.341rem;
}
.spacing-h--5 > box:last-child {
margin-right: 0rem;
}
.spacing-v--5 > * {
margin-bottom: -0.341rem;
}
.spacing-v--5 > *:last-child {
margin-bottom: 0rem;
}
.spacing-h--10 > * {
margin-left: -1.364rem;
}
.spacing-h--10 > *:first-child {
margin-left: 0rem;
}
.spacing-v--10 > * {
margin-bottom: -0.682rem;
}
.spacing-v--10 > *:last-child {
margin-bottom: 0rem;
}
.spacing-v--10 > * {
margin-bottom: -0.682rem;
}
.spacing-v--10 > *:last-child {
margin-bottom: 0rem;
}
.spacing-h--20 > * {
margin-left: -1.364rem;
}
.spacing-h--20 > *:first-child {
margin-left: 0rem;
}
.instant {
transition: 0ms;
}
.menu-decel {
@include menu_decel;
}
.element-show {
@include element_easeInOut;
}
.element-hide {
@include element_easeInOut;
}
.element-move {
@include element_easeInOut;
}
.element-decel {
@include element_decel;
}
.element-bounceout {
@include element_bounceOut;
}
.element-accel {
@include element_accel;
}
.page-move {
@include page_move;
}

View file

@ -0,0 +1,223 @@
// Common colors
$hovercolor: rgba(128, 128, 128, 0.3);
$activecolor: rgba(128, 128, 128, 0.7);
$rounding_small: 0.818rem;
$rounding_mediumsmall: 0.955rem;
$rounding_medium: 1.159rem;
$rounding_mediumlarge: 1.364rem;
$rounding_large: 1.705rem;
// Common rules
@mixin small-rounding {
border-radius: $rounding_small;
-gtk-outline-radius: $rounding_small;
}
@mixin normal-rounding {
border-radius: $rounding_medium;
-gtk-outline-radius: $rounding_medium;
}
@mixin large-rounding {
border-radius: $rounding_large;
-gtk-outline-radius: $rounding_large;
}
@mixin full-rounding {
border-radius: 9999px;
-gtk-outline-radius: 9999px;
}
@mixin titlefont {
// Geometric sans-serif
font-family: "Gabarito", "Poppins", "Lexend", sans-serif;
}
@mixin mainfont {
// Other clean sans-serif
font-family: "Rubik", "Geist", "AR One Sans", "Reddit Sans", "Inter",
"Roboto", "Ubuntu", "Noto Sans", sans-serif;
// font-weight: 500;
}
@mixin icon-material {
// Material Design Icons
font-family: "Material Symbols Rounded", "MaterialSymbolsRounded", "Material Symbols Outlined",
"Material Symbols Sharp";
}
@mixin icon-nerd {
// Nerd Fonts
font-family: "SpaceMono NF", "SpaceMono Nerd Font", "JetBrains Mono NF",
"JetBrains Mono Nerd Font", monospace;
}
@mixin techfont {
// Monospace for sys info n stuff. Doesn't have to be a nerd font, but it's cool.
font-family: "JetBrains Mono NF", "JetBrains Mono Nerd Font",
"JetBrains Mono NL", "SpaceMono NF", "SpaceMono Nerd Font", monospace;
}
@mixin readingfont {
// The most readable fonts, for a comfortable reading experience
// in stuff like ChatGPT widget
font-family: "Lexend", "Noto Sans", sans-serif;
// font-weight: 500;
}
@mixin subtext {
color: $subtext;
}
@mixin actiontext {
color: $actiontext;
}
$elevation_margin: 0.476rem;
@mixin elevation-safe {
background: $surface;
color: $onSurface;
box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.69);
margin: $elevation_margin;
}
@mixin elevation2 {
box-shadow: 0px 2px 3px transparentize($shadow, 0.55);
margin: $elevation_margin;
}
@mixin elevation2-margin {
margin: $elevation_margin;
}
@mixin elevation2-padding {
padding: $elevation_margin;
}
@mixin elevation3 {
box-shadow: 0px 2px 5px $shadow;
margin: $elevation_margin;
}
@keyframes flyin-top {
from {
margin-top: -2.795rem;
}
to {
margin-top: 0rem;
}
}
@keyframes flyin-bottom {
from {
margin-top: 4.841rem;
margin-bottom: -4.841rem;
}
to {
margin-bottom: 0rem;
margin-top: 0rem;
}
}
@mixin menu_decel {
transition: 300ms cubic-bezier(0.1, 1, 0, 1);
}
@mixin menu_decel_fast {
transition: 170ms cubic-bezier(0.1, 1, 0, 1);
}
@mixin menu_accel {
transition: 160ms cubic-bezier(0.38, 0.04, 1, 0.07);
}
@mixin menu_accel_fast {
transition: 100ms cubic-bezier(0.38, 0.04, 1, 0.07);
}
@mixin fluent_decel {
transition: 200ms cubic-bezier(0.1, 1, 0, 1);
}
@mixin fluent_decel_long {
transition: 1000ms cubic-bezier(0.1, 1, 0, 1);
}
@mixin fluent_accel {
transition: 150ms cubic-bezier(0.42, 0, 1, 1);
}
@mixin noanim {
transition: 0ms;
}
@mixin anim-enter {
transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
}
@mixin anim-exit {
transition: 150ms cubic-bezier(0.3, 0, 0.8, 0.15);
}
@mixin element_decel {
transition: 300ms cubic-bezier(0, 0.55, 0.45, 1);
}
@mixin element_bounceOut {
transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
@mixin element_accel {
transition: 300ms cubic-bezier(0.55, 0, 1, 0.45);
}
@mixin element_easeInOut {
transition: 300ms cubic-bezier(0.85, 0, 0.15, 1);
}
@mixin page_move {
transition: 500ms cubic-bezier(0.85, 0, 0.15, 1);
}
@function tint($color, $percentage) {
@return mix(rgb(245, 250, 255), $color, $percentage);
}
@function shade($color, $percentage) {
@return mix(rgb(0, 0, 0), $color, $percentage);
}
$overlay1: mix($onSurface, rgba(0, 0, 0, 0), 25%);
$overlay2: mix($onSurface, rgba(0, 0, 0, 0), 40%);
@mixin elevation-border-softer {
border-top: 1px solid mix($t_t_surface, $t_onSurface, 90%);
border-left: 1px solid mix($t_t_surface, $t_onSurface, 90%);
border-right: 1px solid mix($t_t_surface, $t_onSurface, 95%);
border-bottom: 1px solid mix($t_t_surface, $t_onSurface, 95%);
}
@mixin elevation-border {
border-top: 1px solid mix($t_t_surface, $onSurface, 90%);
border-left: 1px solid mix($t_t_surface, $onSurface, 90%);
border-right: 1px solid mix($t_t_surface, $onSurface, 95%);
border-bottom: 1px solid mix($t_t_surface, $onSurface, 95%);
}
@mixin elevation-border-heavier {
border-top: 1px solid mix($t_t_surface, $onSurface, 80%);
border-left: 1px solid mix($t_t_surface, $onSurface, 80%);
border-right: 1px solid mix($t_t_surface, $onSurface, 85%);
border-bottom: 1px solid mix($t_t_surface, $onSurface, 85%);
}
@mixin elevation-border-transparent {
border-top: 1px solid transparent;
}
@mixin button-minsize {
min-width: 2.727rem;
min-height: 2.727rem;
}
$white: white;
$black: black;

View file

@ -0,0 +1,29 @@
$darkmode: true;
$primary: #ffb1c3;
$onPrimary: #66002a;
$primaryContainer: #861c40;
$onPrimaryContainer: #ffd9e0;
$secondary: #e4bcc3;
$onSecondary: #42292e;
$secondaryContainer: #5c3f45;
$onSecondaryContainer: #ffd9df;
$tertiary: #ecbe91;
$onTertiary: #462a08;
$tertiaryContainer: #60401d;
$onTertiaryContainer: #ffdcb9;
$error: #ffb4a9;
$onError: #680003;
$errorContainer: #930006;
$onErrorContainer: #ffb4a9;
$colorbarbg: #130F10;
$background: #130F10;
$onBackground: #ecdfe0;
$surface: #201a1b;
$onSurface: #ecdfe0;
$surfaceVariant: #514345;
$onSurfaceVariant: #d6c1c4;
$outline: #9f8c8f;
$shadow: #000000;
$inverseSurface: #ecdfe0;
$inverseOnSurface: #362f30;
$inversePrimary: #a53557;

View file

@ -0,0 +1,155 @@
@import './material';
@import './musicmaterial';
@import './wal';
@import './musicwal';
@import './colors';
@import './lib_mixins';
$music_gradient1: mix($color1, $background, 50%);
// @if $darkmode ==true {
// $music_gradient1: mix($color1, $background, 30%);
// }
$music_gradient2: $color3;
$music_gradient3: $color5;
$music_colorstart_transparentize: 0.3;
$music_extra_transparentize: 0.15;
$secondaryContainer: transparentize(mix(mix($background, $color2, 50%), $color6, 80%), 0.5);
$onSecondaryContainer: mix($color7, $color2, 90%);
@if $darkmode ==false {
$onSecondaryContainer: mix($onSecondaryContainer, black, 50%);
}
.osd-music {
@include menu_decel;
@include elevation2;
margin-top: 0.313rem;
@include normal-rounding;
// min-height: 7.159rem;
min-width: 29.659rem;
background-color: $t_background;
padding: 0rem 1.023rem;
background: // Inspired by Amberol
linear-gradient(127deg, transparentize($music_gradient1, $music_colorstart_transparentize), transparentize($music_gradient1, $music_colorstart_transparentize - $transparentize_amount + $music_extra_transparentize) 70.71%),
linear-gradient(217deg, transparentize($music_gradient2, $music_colorstart_transparentize), transparentize($music_gradient2, $music_colorstart_transparentize - $transparentize_amount + $music_extra_transparentize) 70.71%),
radial-gradient(circle at 0% 100%, $color4 13%, rgba(0, 0, 0, 0) 100%),
linear-gradient(336deg, transparentize($music_gradient3, $music_colorstart_transparentize), transparentize($music_gradient3, $music_colorstart_transparentize - $transparentize_amount + $music_extra_transparentize) 70.71%),
linear-gradient($background, $background), // We don't want wallpaper tint, so here's a fully opaque surface
;
}
.osd-music-cover-fallback {
@include element_decel;
@include small-rounding;
// margin: 1.023rem;
min-width: 7.5rem;
min-height: 7.5rem;
background-color: $t_surface;
color: $onSecondaryContainer;
}
.osd-music-cover {
@include small-rounding;
@include menu_decel;
// Must be -top and -bottom or it'll mess up horizontal spacing
margin-top: 1.023rem;
margin-bottom: 1.023rem;
min-width: 7.5rem;
min-height: 7.5rem;
}
.osd-music-cover-art {
@include small-rounding;
min-width: 7.5rem;
min-height: 7.5rem;
background-size: cover;
background-position: center;
}
.osd-music-info {
margin: 1.023rem 0rem;
}
.osd-music-title {
@include element_decel;
@include titlefont;
font-size: 1.364rem;
color: $onSecondaryContainer;
}
.osd-music-artists {
@include element_decel;
@include mainfont;
font-size: 0.955rem;
color: mix($onSecondaryContainer, $secondaryContainer, 80%);
}
.osd-music-pill {
@include element_decel;
@include full-rounding;
@include titlefont;
min-width: 1.833rem;
padding: 0.273rem 0.682rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.osd-music-controls {
@include element_decel;
@include full-rounding;
@include titlefont;
min-width: 1.833rem;
padding: 0.205rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.osd-music-controlbtn {
@include menu_decel;
min-width: 2.045rem;
min-height: 2.045rem;
@include full-rounding;
}
.osd-music-controlbtn:hover,
.osd-music-controlbtn:focus {
background-color: mix($secondaryContainer, $onSecondaryContainer, 90%);
}
.osd-music-controlbtn:active {
background-color: mix($secondaryContainer, $onSecondaryContainer, 85%);
}
.osd-music-controlbtn-txt {
@include element_decel;
transition: 100ms cubic-bezier(0.05, 0.7, 0.1, 1);
@include icon-material;
font-size: 1.364rem;
margin: -0.1rem 0rem;
}
.osd-music-circprog {
@include fluent_decel_long;
min-width: 0.409rem; // width of progress
min-height: 3.068rem;
padding: 0.273rem;
color: $onSecondaryContainer;
}
.osd-music-playstate {
@include menu_decel;
min-height: 3.068rem;
min-width: 3.068rem;
border-radius: 10rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.osd-music-playstate-btn>label {
transition: 50ms cubic-bezier(0.05, 0.7, 0.1, 1);
@include icon-material;
font-size: 1.364rem;
margin: -0.1rem 0rem;
}

View file

@ -0,0 +1,26 @@
// SCSS Variables
// Generated by 'wal'
$wallpaper: "/home/end/.cache/ags/media/8100fe8cfe618b3be1ae9c6c5379e90af63bc3fc";
// Special
$background: #121520;
$foreground: #e8e1e5;
$cursor: #e8e1e5;
// Colors
$color0: #121520;
$color1: #8F7A9E;
$color2: #688BB7;
$color3: #9B93B0;
$color4: #D0AAB0;
$color5: #A9A2CB;
$color6: #C9BAD3;
$color7: #e8e1e5;
$color8: #a29da0;
$color9: #8F7A9E;
$color10: #688BB7;
$color11: #9B93B0;
$color12: #D0AAB0;
$color13: #A9A2CB;
$color14: #C9BAD3;
$color15: #e8e1e5;

View file

@ -0,0 +1,243 @@
$notif_surface: $t_background;
@mixin notif-rounding {
@include normal-rounding;
}
.notif-low {
@include notif-rounding;
background-color: $l_l_t_surfaceVariant;
color: $onSurfaceVariant;
padding: $rounding_small;
padding-right: $rounding_small + 0.545rem;
}
.notif-normal {
@include notif-rounding;
background-color: $l_l_t_surfaceVariant;
color: $onSurfaceVariant;
padding: $rounding_small;
padding-right: $rounding_small + 0.545rem;
}
.notif-critical {
@include notif-rounding;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
padding: $rounding_small;
padding-right: $rounding_small + 0.545rem;
}
.notif-clicked-low {
background-color: mix($l_l_t_surfaceVariant, $t_onSurfaceVariant, 85%);
}
.notif-clicked-normal {
background-color: mix($l_l_t_surfaceVariant, $t_onSurfaceVariant, 85%);
}
.notif-clicked-critical {
background-color: mix($secondaryContainer, $onSecondaryContainer, 95%);
}
.popup-notif-low {
@include notif-rounding;
min-width: 30.682rem;
background-color: $notif_surface;
color: $onSurfaceVariant;
padding: $rounding_small;
padding-right: $rounding_small + 0.545rem;
}
.popup-notif-normal {
@include notif-rounding;
min-width: 30.682rem;
background-color: $notif_surface;
color: $onSurfaceVariant;
padding: $rounding_small;
padding-right: $rounding_small + 0.545rem;
}
.popup-notif-critical {
@include notif-rounding;
min-width: 30.682rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
padding: $rounding_small;
padding-right: $rounding_small + 0.545rem;
}
.popup-notif-clicked-low {
background-color: mix($notif_surface, $onBackground, 94%);
}
.popup-notif-clicked-normal {
background-color: mix($notif_surface, $onBackground, 94%);
}
.popup-notif-clicked-critical {
background-color: mix($secondaryContainer, $onSecondaryContainer, 96%);
}
.notif-body-low {
color: mix($onSurfaceVariant, $surfaceVariant, 67%);
}
.notif-body-normal {
color: mix($onSurfaceVariant, $surfaceVariant, 67%);
}
.notif-body-critical {
color: mix($onSecondaryContainer, $secondaryContainer, 67%);
}
.notif-icon {
@include full-rounding;
min-width: 3.409rem;
min-height: 3.409rem;
font-size: 3.409rem;
}
.notif-icon-material {
background-color: $t_secondaryContainer;
color: $onSecondaryContainer;
}
.notif-icon-material-low {
background-color: $t_secondaryContainer;
color: $onSecondaryContainer;
}
.notif-icon-material-normal {
background-color: $t_secondaryContainer;
color: $onSecondaryContainer;
}
.notif-icon-material-critical {
background-color: $t_onSecondaryContainer;
color: $secondaryContainer;
}
.notif-expand-btn {
@include notif-rounding;
min-width: 1.841rem;
min-height: 1.841rem;
}
.notif-expand-btn:hover,
.notif-expand-btn:focus {
background: $hovercolor;
}
.notif-expand-btn:active {
background: $activecolor;
}
.notif-listaction-btn {
@include notif-rounding;
padding: 0.341rem 0.682rem;
}
.notif-listaction-btn:hover,
.notif-listaction-btn:focus {
background-color: $hovercolor;
}
.notif-listaction-btn:active {
background-color: $activecolor;
}
.notif-listaction-btn-enabled {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.notif-listaction-btn-enabled:hover,
.notif-listaction-btn-enabled:focus {
background-color: mix($secondaryContainer, $onSecondaryContainer, 90%);
}
.notif-listaction-btn-enabled:active {
background-color: mix($secondaryContainer, $onSecondaryContainer, 75%);
}
.osd-notif {
@include notif-rounding;
background-color: transparentize($background,
$transparentize_surface_amount_subtract_surface );
min-width: 30.682rem;
}
.notif-circprog-low {
transition: 0ms linear;
min-width: 0.136rem; // line width
min-height: 3.136rem;
padding: 0rem;
color: $onSecondaryContainer;
}
.notif-circprog-normal {
transition: 0ms linear;
min-width: 0.136rem; // line width
min-height: 3.136rem;
padding: 0rem;
color: $onSecondaryContainer;
}
.notif-circprog-critical {
transition: 0ms linear;
min-width: 0.136rem; // line width
min-height: 3.136rem;
padding: 0rem;
color: $secondaryContainer;
}
.notif-actions {
min-height: 2.045rem;
}
.notif-action {
@include small-rounding;
}
.notif-action-low {
background-color: mix($t_onSurfaceVariant, $t_surface, 10%);
color: $onSurfaceVariant;
}
.notif-action-low:focus,
.notif-action-low:hover {
background-color: $hovercolor;
}
.notif-action-low:active {
background-color: $activecolor;
}
.notif-action-normal {
background-color: mix($t_onSurfaceVariant, $t_surface, 10%);
color: $onSurfaceVariant;
}
.notif-action-normal:focus,
.notif-action-normal:hover {
background-color: $hovercolor;
}
.notif-action-normal:active {
background-color: $activecolor;
}
.notif-action-critical {
background-color: mix($t_onSecondaryContainer, $t_secondaryContainer, 10%);
color: $onSurfaceVariant;
}
.notif-action-critical:focus,
.notif-action-critical:hover {
background-color: mix($t_onSecondaryContainer, $t_secondaryContainer, 18%);
}
.notif-action-critical:active {
background-color: mix($t_onSecondaryContainer, $t_secondaryContainer, 23%);
}

View file

@ -0,0 +1,128 @@
// .osd-window {
// margin-top: 2.727rem;
// }
.osd-bg {
min-width: 8.864rem;
min-height: 3.409rem;
}
.osd-value {
@include elevation-border;
@include elevation2;
background-color: $t_background;
border-radius: 1.023rem;
padding: 0.625rem 1.023rem;
padding-top: 0.313rem;
}
.osd-progress {
min-height: 0.955rem;
min-width: 0.068rem;
padding: 0rem;
border-radius: 10rem;
@include fluent_decel;
trough {
min-height: 0.954rem;
min-width: 0.068rem;
border-radius: 10rem;
background-color: $secondaryContainer;
// border: 0.068rem solid $onSecondaryContainer;
}
progress {
@include fluent_decel;
min-height: 0.680rem;
min-width: 0.680rem;
margin: 0rem 0.137rem;
border-radius: 10rem;
background-color: $onSecondaryContainer;
}
}
.osd-icon {
color: $onPrimaryContainer;
}
.osd-label {
font-size: 1.023rem;
font-weight: 500;
color: $onBackground;
margin-top: 0.341rem;
}
.osd-value-txt {
@include titlefont;
font-size: 1.688rem;
font-weight: 500;
color: $onBackground;
}
.osd-notifs {
padding-top: 0.313rem;
}
.osd-colorscheme {
border-radius: 1.023rem;
background-color: $t_background;
padding: 1.023rem;
@include elevation2;
}
.osd-color {
@include full-rounding;
min-width: 2.727rem;
min-height: 1.705rem;
padding: 0rem 0.341rem;
font-weight: bold;
box {
@include full-rounding;
margin: 0.409rem;
}
}
.osd-color-primary {
background-color: $primary;
color: $onPrimary;
box { background-color: $onPrimary; }
}
.osd-color-primaryContainer {
background-color: $primaryContainer;
color: $onPrimaryContainer;
box { background-color: $onPrimaryContainer; }
}
.osd-color-secondary {
background-color: $secondary;
color: $onSecondary;
box { background-color: $onSecondary; }
}
.osd-color-secondaryContainer {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
box { background-color: $onSecondaryContainer; }
}
.osd-color-surfaceVariant {
background-color: $surfaceVariant;
color: $onSurfaceVariant;
box { background-color: $onSurfaceVariant; }
}
.osd-color-surface {
background-color: $surface;
color: $onSurface;
box { background-color: $onSurface; }
}
.osd-color-background {
background-color: $background;
color: $onBackground;
box { background-color: $onBackground; }
}
.osd-show {
transition: 200ms cubic-bezier(0.1, 1, 0, 1);
}
.osd-hide {
transition: 190ms cubic-bezier(0.85, 0, 0.15, 1);
}

View file

@ -0,0 +1,118 @@
$osk_key_height: 2.5rem;
$osk_key_width: 2.5rem;
$osk_key_padding: 0.188rem;
$osk_key_rounding: 0.682rem;
$osk_key_fontsize: 1.091rem;
.osk-window {
// @include menu_decel_fast;
@include large-rounding;
@include elevation-border;
@include elevation2;
// min-height: 29.591rem;
// min-width: 50rem;
background-color: $t_background;
}
.osk-body {
padding: 1.023rem;
padding-top: 0px;
}
.osk-show {
@include menu_decel_fast;
}
.osk-hide {
margin-top: 30.682rem;
margin-bottom: -30.682rem;
// opacity: 0;
@include menu_accel_fast;
}
.osk-dragline {
@include full-rounding;
background-color: $surfaceVariant;
min-height: 0.273rem;
min-width: 10.227rem;
margin-top: 0.545rem;
margin-bottom: 0.205rem;
}
.osk-key {
border-radius: $osk_key_rounding;
background-color: $t_surfaceVariant;
color: $onSurfaceVariant;
padding: $osk_key_padding;
font-weight: 500;
font-size: $osk_key_fontsize;
}
.osk-key:hover,
.osk-key:focus {
background-color: $hovercolor;
}
.osk-key:active {
background-color: $activecolor;
font-size: $osk_key_fontsize;
}
.osk-key-active {
background-color: $activecolor;
}
.osk-key-normal {
min-width: $osk_key_width;
min-height: $osk_key_height;
}
.osk-key-fn {
min-width: $osk_key_width * 1.005;
min-height: $osk_key_height / 2;
}
.osk-key-tab {
min-width: $osk_key_width * 1.6;
min-height: $osk_key_height;
}
.osk-key-caps {
min-width: $osk_key_width * 1.9;
min-height: $osk_key_height;
}
.osk-key-shift {
min-width: $osk_key_width * 2.5;
min-height: $osk_key_height;
}
.osk-key-control {
min-width: $osk_key_width * 1.3;
min-height: $osk_key_height;
}
.osk-control-button {
border-radius: $osk_key_rounding;
background-color: $t_surfaceVariant;
color: $onSurfaceVariant;
font-weight: 500;
font-size: $osk_key_fontsize;
padding: 0.682rem;
}
.osk-control-button:hover,
.osk-control-button:focus {
background-color: mix($t_surfaceVariant, $t_onSurfaceVariant, 90%);
}
.osk-control-button:active {
background-color: mix($t_surfaceVariant, $t_onSurfaceVariant, 70%);
font-size: $osk_key_fontsize;
}
.osk-key-empty, .osk-key-empty:hover, .osk-key-empty:focus {
min-width: $osk_key_width;
min-height: $osk_key_height;
background-color: transparent;
}

View file

@ -0,0 +1,139 @@
.overview-window {
margin-top: 2.727rem;
}
.overview-search-box {
@include element_decel;
@include large-rounding;
@include elevation-border;
@include elevation2;
min-width: 13.636rem;
min-height: 3.409rem;
padding: 0rem 1.364rem;
padding-right: 2.864rem;
background-color: $t_background;
color: $onBackground;
selection {
background-color: $secondary;
color: $onSecondary;
}
caret-color: transparent;
}
.overview-search-box-extended {
min-width: 25.909rem;
caret-color: $onSecondaryContainer;
}
.overview-search-prompt {
color: $subtext;
}
.overview-search-icon {
margin: 0rem 1.023rem;
}
.overview-search-prompt-box {
margin-left: -18.545rem;
margin-right: $elevation_margin + 0.068rem;
}
.overview-search-icon-box {
margin-left: -18.545rem;
margin-right: $elevation_margin + 0.068rem;
}
.overview-search-results {
// min-height: 2.813rem;
// min-height: 37.5rem;
@include large-rounding;
@include elevation-border;
@include elevation2;
min-width: 28.773rem;
padding: 0.682rem;
background-color: $t_background;
color: $onBackground;
}
.overview-search-results-icon {
margin: 0rem 0.682rem;
font-size: 2.386rem;
min-width: 2.386rem;
min-height: 2.386rem;
}
.overview-search-results-txt {
margin-right: 0.682rem;
}
.overview-search-results-txt-cmd {
margin-right: 0.682rem;
@include techfont;
font-size: 1.227rem;
}
.overview-search-result-btn {
@include normal-rounding;
padding: 0.341rem;
min-width: 2.386rem;
min-height: 2.386rem;
caret-color: transparent;
}
.overview-search-result-btn:hover,
.overview-search-result-btn:focus {
background-color: $hovercolor;
}
.overview-search-result-btn:active {
background-color: $activecolor;
}
.overview-tasks {
@include large-rounding;
@include elevation-border;
@include elevation2;
padding: 0.341rem;
background-color: $t_background;
color: $onBackground;
}
.overview-tasks-workspace {
@include normal-rounding;
// @include elevation-border;
margin: 0.341rem;
background-color: mix($t_t_surface, $t_onSurface, 93%);
}
.overview-tasks-workspace-number {
@include mainfont;
color: mix($t_onSurface, $t_surface, 93%);
}
.overview-tasks-window {
@include normal-rounding;
@include menu_decel;
background-color: $t_surfaceVariant;
color: $onSecondaryContainer;
border: 0.068rem solid $t_t_t_onSecondaryContainer;
}
.overview-tasks-window:hover,
.overview-tasks-window:focus {
background-color: mix($l_t_secondaryContainer, $primary, 95%);
}
.overview-tasks-window:active {
background-color: mix($l_t_secondaryContainer, $primary, 90%);
}
.overview-tasks-window-selected {
background-color: mix($l_t_secondaryContainer, $primary, 90%);
}
.overview-tasks-window-dragging {
opacity: 0.2;
}

View file

@ -0,0 +1,36 @@
.session-bg {
margin-top: -2.727rem;
background-color: mix($t_t_background, $background, 40%);
}
.session-button {
@include large-rounding;
min-width: 8.182rem;
min-height: 8.182rem;
background-color: $surfaceVariant;
color: $onSurfaceVariant;
font-size: 3rem;
}
.session-button-focused {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.session-button-desc {
background-color: mix($surface, $surfaceVariant, 50%);
color: mix($onSurface, $onSurfaceVariant, 50%);
border-bottom-left-radius: $rounding_large;
border-bottom-right-radius: $rounding_large;
padding: 0.205rem 0.341rem;
font-weight: 700;
}
.session-button-cancel {
@include large-rounding;
min-width: 8.182rem;
min-height: 5.455rem;
background-color: $surfaceVariant;
color: $onSurfaceVariant;
font-size: 3rem;
}

View file

@ -0,0 +1,859 @@
$sidebar_chat_textboxareaColor: mix($onSurfaceVariant, $surfaceVariant, 40%);
$textboxColor: mix($surface, $surfaceVariant, 80%);
$system: $secondary;
$onSystem: $onSecondary;
$chatgpt: $primary;
$onChatgpt: $onPrimary;
@mixin group-padding {
padding: 0.341rem;
}
.sidebar-right {
@include menu_decel;
@include elevation-border;
@include elevation2;
border-radius: $rounding_large - $elevation_margin + 0.068rem;
min-width: 27.818rem; // COMMENT THIS LATER IF TEXT WRAP IS USED
// min-height: 29.591rem;
background-color: $t_background;
padding: 1.023rem;
}
.sideright-show {
@include menu_decel;
}
.sideright-hide {
@include menu_accel;
margin-right: -30.682rem;
// opacity: 0;
}
.sidebar-left {
@include menu_decel;
@include elevation-border;
@include elevation2;
border-radius: $rounding_large - $elevation_margin + 0.068rem;
min-width: 27.818rem; // COMMENT THIS LATER IF TEXT WRAP IS USED
// min-height: 29.591rem;
background-color: $t_background;
padding: 1.023rem;
}
.sideleft-show {
@include menu_decel;
}
.sideleft-hide {
margin-left: -30.682rem;
// opacity: 0;
@include menu_accel;
}
.sidebar-group {
@include normal-rounding;
@include group-padding;
background-color: $t_surface;
}
.sidebar-group-nopad {
@include normal-rounding;
background-color: $t_surface;
}
.sidebar-group-invisible {
@include group-padding;
}
.sidebar-group-invisible-morehorizpad {
padding: 0.341rem 0.682rem;
}
.sidebar-togglesbox {
@include full-rounding;
@include group-padding;
background-color: $t_surface;
}
.sidebar-iconbutton {
@include full-rounding;
@include element_decel;
color: $onSurface;
min-width: 2.727rem;
min-height: 2.727rem;
}
.sidebar-iconbutton:hover,
.sidebar-iconbutton:focus {
background-color: $hovercolor;
}
.sidebar-iconbutton:active {
background-color: $activecolor;
}
.sidebar-button {
@include element_decel;
padding: 0rem $rounding_small;
background-color: $t_secondaryContainer;
color: $onSecondaryContainer;
}
.sidebar-button:hover,
.sidebar-button:focus {
background-color: $hovercolor;
}
.sidebar-button:active {
background-color: $activecolor;
}
.sidebar-button-active {
background-color: $primary;
color: $onPrimary;
}
.sidebar-button-active:hover,
.sidebar-button-active:focus {
background-color: mix($primary, $hovercolor, 70%);
}
.sidebar-button-active:active {
background-color: mix($primary, $hovercolor, 40%);
}
.sidebar-buttons-separator {
min-width: 0.068rem;
min-height: 0.068rem;
background-color: $onSurfaceVariant;
}
.sidebar-navrail {
// background-color: $t_surface;
padding: 0rem $rounding_medium;
}
.sidebar-navrail-btn>box>label {
@include full-rounding;
@include menu_decel;
}
.sidebar-navrail-btn:hover>box>label:first-child,
.sidebar-navrail-btn:focus>box>label:first-child {
background-color: $hovercolor;
}
.sidebar-navrail-btn:active>box>label:first-child {
background-color: $activecolor;
}
.sidebar-navrail-btn-active>box>label:first-child {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.sidebar-navrail-btn-active:hover>box>label:first-child,
.sidebar-navrail-btn-active:focus>box>label:first-child {
background-color: mix($secondaryContainer, $hovercolor, 90%);
color: mix($onSecondaryContainer, $hovercolor, 90%);
}
.sidebar-sysinfo-grouppad {
padding: 1.159rem;
}
.sidebar-memory-ram-circprog {
@include fluent_decel_long;
min-width: $rounding_small;
min-height: 4.091rem;
padding: 0.409rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
font-size: 0px;
}
.sidebar-memory-swap-circprog {
@include fluent_decel_long;
min-width: $rounding_small;
min-height: 2.255rem;
padding: 0.409rem;
margin: 0.918rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
font-size: 0px;
}
.sidebar-cpu-circprog {
min-width: $rounding_small;
min-height: 3.409rem;
padding: 0.409rem;
background-color: $secondaryContainer;
color: $onSecondaryContainer;
@include fluent_decel_long;
font-size: 0px;
}
.sidebar-scrollbar {
trough {
@include full-rounding;
min-width: 0.545rem;
background-color: transparent;
}
slider {
@include full-rounding;
@include element_decel;
min-width: 0.273rem;
min-height: 2.045rem;
background-color: $t_onSurfaceVariant;
}
slider:hover,
slider:focus {
background-color: mix($t_onSurfaceVariant, $onSurfaceVariant, 80%);
}
slider:active {
background-color: mix($onSurfaceVariant, $surfaceVariant, 50%);
}
}
.sidebar-calendar-btn {
@include full-rounding;
@include element_decel;
min-height: 2.523rem;
min-width: 2.523rem;
color: $onSurface;
}
.sidebar-calendar-btn:hover,
.sidebar-calendar-btn:focus {
background-color: $hovercolor;
}
.sidebar-calendar-btn:active {
background-color: $activecolor;
}
.sidebar-calendar-btn-txt {
margin-left: -10.341rem;
margin-right: -10.341rem;
}
.sidebar-calendar-btn-today {
background-color: $primary;
color: $onPrimary;
}
.sidebar-calendar-btn-today:hover,
.sidebar-calendar-btn-today:focus {
background-color: mix($primary, $hovercolor, 70%);
}
.sidebar-calendar-btn-today:active {
background-color: mix($primary, $hovercolor, 40%);
}
.sidebar-calendar-btn-othermonth {
color: mix($onSurface, $surface, 50%);
}
.sidebar-calendar-header {
margin: 0.341rem;
}
.sidebar-calendar-monthyear-btn {
@include full-rounding;
@include element_decel;
padding: 0rem 0.682rem;
background-color: $t_surfaceVariant;
color: $onSurfaceVariant;
}
.sidebar-calendar-monthyear-btn:hover,
.sidebar-calendar-monthyear-btn:focus {
background-color: $hovercolor;
color: mix($onSurfaceVariant, $surfaceVariant, 95%);
}
.sidebar-calendar-monthyear-btn:active {
background-color: $activecolor;
color: mix($onSurfaceVariant, $surfaceVariant, 85%);
}
.sidebar-calendar-monthshift-btn {
@include full-rounding;
@include element_decel;
min-width: 2.045rem;
min-height: 2.045rem;
background-color: $t_surfaceVariant;
color: $onSurfaceVariant;
}
.sidebar-calendar-monthshift-btn:hover {
background-color: $hovercolor;
color: mix($onSurfaceVariant, $surfaceVariant, 95%);
}
.sidebar-calendar-monthshift-btn:active {
background-color: $activecolor;
color: mix($onSurfaceVariant, $surfaceVariant, 85%);
}
.sidebar-selector-tab {
@include small-rounding;
@include element_decel;
min-height: 2.5rem;
color: $onSurface;
}
.sidebar-selector-tab:hover,
.sidebar-selector-tab:focus {
background-color: $hovercolor;
}
.sidebar-selector-tab:active {
background-color: $activecolor;
}
.sidebar-selector-tab-active>box>label {
color: $primary;
}
.sidebar-selector-highlight-offset {
margin-top: -0.205rem;
margin-bottom: 0.205rem;
}
.sidebar-selector-highlight {
transition: 180ms ease-in-out; // Doesn't look that good, but it syncs with the GtkStack
color: $primary;
// padding: 0rem 2.045rem;
min-height: 0.205rem;
}
.sidebar-todo-item {
padding-right: 0.545rem;
}
.sidebar-todo-item-even {
background-color: $t_t_surfaceVariant;
}
.sidebar-todo-item-action {
@include element_decel;
border-radius: 9999px;
min-width: 1.705rem;
min-height: 1.705rem;
}
.sidebar-todo-item-action:hover,
.sidebar-todo-item-action:focus {
background-color: $hovercolor;
}
.sidebar-todo-item-action:active {
background-color: $activecolor;
}
.sidebar-todo-crosser {
transition: margin 200ms cubic-bezier(0.1, 1, 0, 1), background-color 0ms;
min-width: 0rem;
}
.sidebar-todo-crosser-crossed {
background-color: $onBackground;
}
.sidebar-todo-crosser-removed {
background-color: $error;
}
.sidebar-todo-new {
@include full-rounding;
@include element_decel;
color: $onSecondaryContainer;
margin: 0.341rem;
padding: 0.205rem 0.545rem;
border: 0.068rem solid $onSurface;
}
.sidebar-todo-new,
.sidebar-todo-new:focus {
background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 97%);
}
.sidebar-todo-new:active {
background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 80%);
}
.sidebar-todo-add {
@include element_decel;
@include small-rounding;
min-width: 1.705rem;
min-height: 1.705rem;
color: $onSecondaryContainer;
border: 0.068rem solid $onSurface;
}
.sidebar-todo-add:hover,
.sidebar-todo-add:focus {
background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 97%);
}
.sidebar-todo-add:active {
background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 80%);
}
.sidebar-todo-add-available {
@include element_decel;
@include small-rounding;
min-width: 1.705rem;
min-height: 1.705rem;
background-color: $primary;
color: $onPrimary;
border: 0.068rem solid $primary;
}
.sidebar-todo-add-available:hover,
.sidebar-todo-add-available:focus {
background-color: mix($primary, $onPrimary, 97%);
}
.sidebar-todo-add-available:active {
background-color: mix($primary, $onPrimary, 80%);
}
.sidebar-todo-entry {
@include element_decel;
@include small-rounding;
background-color: $surfaceVariant;
color: $onSurfaceVariant;
caret-color: $onSurfaceVariant;
margin: 0rem 0.341rem;
min-height: 1.773rem;
min-width: 0rem;
padding: 0.205rem 0.682rem;
border: 0.068rem solid mix($onSurfaceVariant, $surfaceVariant, 50%);
}
.sidebar-todo-entry:focus {
border: 0.068rem solid mix($onSurfaceVariant, $surfaceVariant, 90%);
}
.sidebar-module {
@include normal-rounding;
@include group-padding;
background-color: $l_l_t_surfaceVariant;
padding: 0.682rem;
}
.sidebar-module-btn-arrow {
@include full-rounding;
@include icon-material;
background-color: $l_l_t_surfaceVariant;
min-width: 1.705rem;
min-height: 1.705rem;
&:hover {
background-color: $hovercolor;
}
}
.sidebar-module-scripts-button {
@include full-rounding;
@include icon-material;
background-color: $l_l_t_surfaceVariant;
min-width: 1.705rem;
min-height: 1.705rem;
&:hover {
background-color: $hovercolor;
}
&:active {
background-color: $activecolor;
}
}
$colorpicker_rounding: 0.341rem;
.sidebar-module-colorpicker-wrapper {
padding: 0.341rem;
}
.sidebar-module-colorpicker-cursorwrapper {
padding: 0.341rem 0.136rem;
}
.sidebar-module-colorpicker-hue {
min-height: 13.636rem;
min-width: 1.091rem;
border-radius: $colorpicker_rounding;
}
.sidebar-module-colorpicker-hue-cursor {
background-color: $onBackground;
border: 0.136rem solid $onBackground;
min-height: 0.136rem;
margin-top: -0.136rem;
border-radius: $colorpicker_rounding;
}
.sidebar-module-colorpicker-saturationandlightness-wrapper {
padding: 0.341rem;
}
.sidebar-module-colorpicker-saturationandlightness {
min-height: 13.636rem;
min-width: 13.636rem;
border-radius: $colorpicker_rounding;
}
.sidebar-module-colorpicker-saturationandlightness-cursorwrapper {
padding: 0.341rem;
margin-top: -0.409rem;
margin-left: -0.409rem;
}
.sidebar-module-colorpicker-saturationandlightness-cursor {
@include full-rounding;
border: 0.136rem solid white;
min-width: 0.682rem;
min-height: 0.682rem;
margin-top: -0.409rem;
margin-left: -0.409rem;
}
.sidebar-module-colorpicker-result-area {
padding: 0.341rem;
}
.sidebar-module-colorpicker-result-box {
border-radius: $colorpicker_rounding;
min-width: 2.045rem;
min-height: 0.682rem;
padding: 0.341rem;
}
.sidebar-chat-apiswitcher {
@include full-rounding;
@include group-padding;
background-color: $t_surface;
}
.sidebar-chat-apiswitcher-icon {
@include element_decel;
@include full-rounding;
min-width: 2.182rem;
min-height: 2.182rem;
font-size: 1.406rem;
color: $onSurface;
}
.sidebar-chat-apiswitcher-icon-enabled {
background-color: $secondaryContainer;
color: $onSecondaryContainer;
}
.sidebar-chat-viewport {
@include element_decel;
// margin: 0.682rem 0rem;
padding: 0.682rem 0rem;
}
.sidebar-chat-textarea {
@include normal-rounding;
background-color: $textboxColor;
color: $onSurfaceVariant;
padding: 0.682rem;
}
.sidebar-chat-entry {
color: $onSurfaceVariant;
caret-color: $onSurfaceVariant;
min-height: 1.773rem;
min-width: 0rem;
}
.sidebar-chat-wrapper {
transition: 400ms cubic-bezier(0.1, 1, 0, 1);
}
.sidebar-chat-wrapper-extended {
min-height: 7.500rem;
}
.sidebar-chat-send {
@include element_decel;
min-width: 1.705rem;
min-height: 1.705rem;
border-radius: $rounding_medium - 0.681rem;
}
.sidebar-chat-send:hover,
.sidebar-chat-send:focus {
background-color: $surfaceVariant;
}
.sidebar-chat-send:active {
background-color: mix($surfaceVariant, $onBackground, 80%);
}
.sidebar-chat-send-available {
background-color: $primary;
color: $onPrimary;
}
.sidebar-chat-send-available:hover,
.sidebar-chat-send-available:focus {
background-color: mix($primary, $onPrimary, 97%);
}
.sidebar-chat-send-available:active {
background-color: mix($primary, $onPrimary, 80%);
}
.sidebar-chat-message {
margin: 0.682rem;
}
.sidebar-chat-indicator {
@include element_decel;
@include full-rounding;
min-width: 0.136rem;
background-color: $onBackground;
}
.sidebar-chat-indicator-user {
background-color: $onBackground;
}
.sidebar-chat-indicator-bot {
background-color: $chatgpt;
}
.sidebar-chat-indicator-System {
background-color: $system;
}
.sidebar-chat-name {
@include titlefont;
padding: 0.341rem;
margin-left: -0.136rem;
padding-left: 0.818rem;
}
.sidebar-chat-txtblock {
margin-left: -0.136rem;
padding: 0.341rem;
padding-left: 0.818rem;
}
.sidebar-chat-txt {
@include readingfont;
}
.sidebar-chat-codeblock {
@include normal-rounding;
// @include elevation2;
background-color: $termbg;
color: $termfg;
margin: 0rem 0.682rem;
border: 0.068rem solid $t_t_t_onSecondaryContainer;
}
.sidebar-chat-codeblock-topbar {
@include mainfont;
margin: 0.273rem;
margin-bottom: 0rem;
background-color: mix($t_secondaryContainer, $t_onSurfaceVariant, 30%);
color: $onSecondaryContainer;
border-radius: $rounding_medium - 0.273rem;
border: 0.068rem solid mix($secondaryContainer, $onSecondaryContainer, 90%);
border-top-left-radius: $rounding_small + 0.068rem;
border-top-right-radius: $rounding_small + 0.068rem;
padding: 0.341rem 0.477rem;
}
.sidebar-chat-codeblock-topbar-txt {
@include full-rounding;
padding: 0.273rem;
}
.sidebar-chat-codeblock-topbar-btn {
@include full-rounding;
@include element_decel;
padding: 0.273rem 0.477rem;
}
.sidebar-chat-codeblock-topbar-btn:hover,
.sidebar-chat-codeblock-topbar-btn:focus {
background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 80%);
}
.sidebar-chat-codeblock-topbar-btn:active {
background-color: mix($t_secondaryContainer, $t_onSecondaryContainer, 60%);
}
.sidebar-chat-codeblock-code {
@include techfont;
padding: 0.682rem;
}
.sidebar-chat-divider {
min-height: 1px;
background-color: $sidebar_chat_textboxareaColor;
margin: 0rem 0.545rem;
}
.sidebar-chat-welcome-txt {
margin: 0rem 3.409rem;
}
.sidebar-chat-settings-toggles {
margin: 0rem 5.455rem;
}
.sidebar-chat-welcome-icon {
@include full-rounding;
font-size: 4rem;
}
.sidebar-chat-welcome-logo {
@include full-rounding;
@include element_decel;
@include icon-material;
min-height: 4.773rem;
min-width: 4.773rem;
font-size: 3.076rem;
background-color: $onBackground;
color: $background;
}
.sidebar-chat-chip {
@include element_decel;
@include small-rounding;
padding: 0.341rem 0.477rem;
}
.sidebar-chat-chip-action {
@include element_decel;
background-color: $textboxColor;
color: $onSurfaceVariant;
}
.sidebar-chat-chip-action:hover,
.sidebar-chat-chip-action:focus {
background-color: $hovercolor;
}
.sidebar-chat-chip-action:active {
background-color: $activecolor;
}
.sidebar-chat-chip-action-active {
color: $sidebar_chat_textboxareaColor;
border: 0.068rem solid $sidebar_chat_textboxareaColor;
}
.sidebar-chat-chip-toggle {
@include element_decel;
@include small-rounding;
padding: 0.341rem 0.477rem;
background-color: $textboxColor;
color: $onSurfaceVariant;
}
.sidebar-chat-chip-toggle:focus,
.sidebar-chat-chip-toggle:hover {
background-color: $hovercolor;
}
.sidebar-chat-chip-toggle:active {
background-color: $activecolor;
}
.sidebar-pin {
@include small-rounding;
@include element_decel;
min-height: 2.386rem;
min-width: 2.386rem;
color: $onSurface;
}
.sidebar-pin:hover,
.sidebar-pin:focus {
background-color: $hovercolor;
}
.sidebar-pin:active {
background-color: $activecolor;
}
.sidebar-pin-enabled {
background-color: $primary;
label {
color: $onPrimary;
}
}
.sidebar-pin-enabled:hover,
.sidebar-pin-enabled:focus {
background-color: mix($primary, $onPrimary, 90%);
}
.sidebar-pin-enabled:active {
background-color: mix($primary, $onPrimary, 80%);
}
.sidebar-waifu-heading {
@include titlefont;
padding: 0.341rem;
margin-left: -0.136rem;
padding-left: 0.818rem;
}
.sidebar-waifu-content {
margin-left: 0.682rem;
}
.sidebar-waifu-txt {
@include readingfont;
margin-left: 0.682rem;
}
.sidebar-waifu-image {
margin-left: 0.682rem;
@include normal-rounding;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.sidebar-waifu-image-actions {
@include element_decel;
padding: 0.313rem;
}
$waifu_image_overlay_transparency: 0.7;
.sidebar-waifu-image-action {
@include full-rounding;
min-width: 1.875rem;
min-height: 1.875rem;
background-color: rgba(0, 0, 0,
$waifu_image_overlay_transparency ); // Fixed cuz on image
color: rgba(255, 255, 255, $waifu_image_overlay_transparency);
}
.sidebar-waifu-image-action:hover,
.sidebar-waifu-image-action:focus {
background-color: rgba(30, 30, 30, $waifu_image_overlay_transparency);
}
.sidebar-waifu-image-action:active {
background-color: rgba(60, 60, 60, $waifu_image_overlay_transparency);
}

View file

@ -0,0 +1,8 @@
// To prevent errors
$color1: $surfaceVariant;
$color2: $surfaceVariant;
$color3: $surfaceVariant;
$color4: $secondaryContainer;
$color5: $secondaryContainer;
$color6: $secondaryContainer;
$color7: $onBackground;

View file

@ -0,0 +1,41 @@
// Reset
// * {
// all: unset;
// }
*:not(popover) { all: unset; }
// Colors
@import './material'; // Material colors
@import './colors'; // Global color definitions. Uses material colors as base.
@import './lib_mixins';
@import './lib_classes';
@import './common'; // Context menu n stuff
// Components
@import './bar';
@import './cheatsheet';
@import './desktopbackground';
@import './dock';
@import './osd';
@import './overview';
@import './osk';
@import './sidebars';
@import './session';
@import './notifications';
// Music is put last as it might mess stuff up with pywal
@import './music'; // Everything related to music is here
// Classes for interaction
.growingRadial {
transition: 300ms cubic-bezier(0.2, 0.0, 0, 1.0);
}
.fadingRadial {
transition: 50ms cubic-bezier(0.2, 0.0, 0, 1.0);
}
.sidebar-pinned {
margin: 0rem;
border-radius: 0rem;
border-bottom-right-radius: $rounding_large;
border: 0rem solid;
}

View file

@ -0,0 +1,59 @@
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
const { exec, execAsync } = Utils;
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
class BrightnessService extends Service {
static {
Service.register(
this,
{ 'screen-changed': ['float'], },
{ 'screen-value': ['float', 'rw'], },
);
}
_screenValue = 0;
// the getter has to be in snake_case
get screen_value() { return this._screenValue; }
// the setter has to be in snake_case too
set screen_value(percent) {
percent = clamp(percent, 0, 1);
this._screenValue = percent;
Utils.execAsync(`brightnessctl s ${percent * 100}% -q`)
.then(() => {
// signals has to be explicity emitted
this.emit('screen-changed', percent);
this.notify('screen-value');
// or use Service.changed(propName: string) which does the above two
// this.changed('screen');
})
.catch(print);
}
constructor() {
super();
const current = Number(exec('brightnessctl g'));
const max = Number(exec('brightnessctl m'));
this._screenValue = current / max;
}
// overwriting connectWidget method, lets you
// change the default event that widgets connect to
connectWidget(widget, callback, event = 'screen-changed') {
super.connectWidget(widget, callback, event);
}
}
// the singleton instance
const service = new BrightnessService();
// make it global for easy use with cli
globalThis.brightness = service;
// export to use in other modules
export default service;

View file

@ -0,0 +1,266 @@
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import Soup from 'gi://Soup?version=3.0';
import { fileExists } from './messages.js';
// Custom prompt
const initMessages =
[
{ role: "user", content: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are encouraged to use bullet points and headings. Use casual language and be short and concise. \nThanks!", },
{ role: "assistant", content: "- Got it!", },
{ role: "user", content: "\"He rushed to where the event was supposed to be hold, he didn't know it got calceled\"", },
{ role: "assistant", content: "## Grammar correction\nErrors:\n\"He rushed to where the event was supposed to be __hold____,__ he didn't know it got calceled\"\nCorrection + minor improvements:\n\"He rushed to the place where the event was supposed to be __held____, but__ he didn't know that it got calceled\"", },
{ role: "user", content: "raise volume by 5%", },
{ role: "assistant", content: "## Volume +5```bash\nwpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+\n```\nThis command uses the `wpctl` utility to adjust the volume of the default sink.", },
{ role: "user", content: "main advantages of the nixos operating system", },
{ role: "assistant", content: "## NixOS advantages\n- **Reproducible**: A config working on one device will also work on another\n- **Declarative**: One config language to rule them all. Effortlessly share them with others.\n- **Reliable**: Per-program software versioning. Mitigates the impact of software breakage", },
{ role: "user", content: "whats skeumorphism", },
{ role: "assistant", content: "## Skeuomorphism\n- A design philosophy- From early days of interface designing- Tries to imitate real-life objects- It's in fact still used by Apple in their icons until today.", },
];
function expandTilde(path) {
if (path.startsWith('~')) {
return GLib.get_home_dir() + path.slice(1);
} else {
return path;
}
}
// We're using many models to not be restricted to 3 messages per minute.
// The whole chat will be sent every request anyway.
Utils.exec(`mkdir -p ${GLib.get_user_cache_dir()}/ags/user/ai`);
const KEY_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/openai_key.txt`;
const APIDOM_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/openai_api_dom.txt`;
function replaceapidom(URL) {
//Utils.writeFile(URL, "/tmp/openai-url-old.log"); // For debugging
if (fileExists(expandTilde(APIDOM_FILE_LOCATION))) {
var contents = Utils.readFile(expandTilde(APIDOM_FILE_LOCATION)).trim();
var URL = URL.toString().replace("api.openai.com", contents);
}
//Utils.writeFile(URL, "/tmp/openai-url.log"); // For debugging
return URL;
}
const CHAT_MODELS = ["gpt-3.5-turbo-1106", "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-3.5-turbo-0613"]
const ONE_CYCLE_COUNT = 3;
class ChatGPTMessage extends Service {
static {
Service.register(this,
{
'delta': ['string'],
},
{
'content': ['string'],
'thinking': ['boolean'],
'done': ['boolean'],
});
}
_role = '';
_content = '';
_thinking = false;
_done = false;
constructor(role, content, thinking = false, done = false) {
super();
this._role = role;
this._content = content;
this._thinking = thinking;
this._done = done;
}
get done() { return this._done }
set done(isDone) { this._done = isDone; this.notify('done') }
get role() { return this._role }
set role(role) { this._role = role; this.emit('changed') }
get content() { return this._content }
set content(content) {
this._content = content;
this.notify('content')
this.emit('changed')
}
get label() { return this._parserState.parsed + this._parserState.stack.join('') }
get thinking() { return this._thinking }
set thinking(thinking) {
this._thinking = thinking;
this.notify('thinking')
this.emit('changed')
}
addDelta(delta) {
if (this.thinking) {
this.thinking = false;
this.content = delta;
}
else {
this.content += delta;
}
this.emit('delta', delta);
}
}
class ChatGPTService extends Service {
static {
Service.register(this, {
'initialized': [],
'clear': [],
'newMsg': ['int'],
'hasKey': ['boolean'],
});
}
_assistantPrompt = true;
_messages = [];
_cycleModels = true;
_requestCount = 0;
_temperature = 0.9;
_modelIndex = 0;
_key = '';
_decoder = new TextDecoder();
url = GLib.Uri.parse(replaceapidom('https://api.openai.com/v1/chat/completions'), GLib.UriFlags.NONE);
constructor() {
super();
if (fileExists(expandTilde(KEY_FILE_LOCATION))) this._key = Utils.readFile(expandTilde(KEY_FILE_LOCATION)).trim();
else this.emit('hasKey', false);
if (this._assistantPrompt) this._messages = [...initMessages];
else this._messages = [];
this.emit('initialized');
}
get modelName() { return CHAT_MODELS[this._modelIndex] }
get keyPath() { return KEY_FILE_LOCATION }
get key() { return this._key }
set key(keyValue) {
this._key = keyValue;
Utils.writeFile(this._key, expandTilde(KEY_FILE_LOCATION))
.then(this.emit('hasKey', true))
.catch(err => print(err));
}
get cycleModels() { return this._cycleModels }
set cycleModels(value) {
this._cycleModels = value;
if (!value) this._modelIndex = 0;
else {
this._modelIndex = (this._requestCount - (this._requestCount % ONE_CYCLE_COUNT)) % CHAT_MODELS.length;
}
}
get temperature() { return this._temperature }
set temperature(value) { this._temperature = value; }
get messages() { return this._messages }
get lastMessage() { return this._messages[this._messages.length - 1] }
clear() {
if (this._assistantPrompt)
this._messages = [...initMessages];
else
this._messages = [];
this.emit('clear');
}
get assistantPrompt() { return this._assistantPrompt; }
set assistantPrompt(value) {
this._assistantPrompt = value;
if (value) this._messages = [...initMessages];
else this._messages = [];
}
readResponse(stream, aiResponse) {
stream.read_line_async(
0, null,
(stream, res) => {
if (!stream) return;
const [bytes] = stream.read_line_finish(res);
const line = this._decoder.decode(bytes);
if (line && line != '') {
let data = line.substr(6);
if (data == '[DONE]') return;
try {
const result = JSON.parse(data);
if (result.choices[0].finish_reason === 'stop') {
aiResponse.done = true;
return;
}
aiResponse.addDelta(result.choices[0].delta.content);
}
catch {
aiResponse.addDelta(line + '\n');
}
}
this.readResponse(stream, aiResponse);
});
}
addMessage(role, message) {
this._messages.push(new ChatGPTMessage(role, message));
this.emit('newMsg', this._messages.length - 1);
}
send(msg) {
this._messages.push(new ChatGPTMessage('user', msg));
this.emit('newMsg', this._messages.length - 1);
const aiResponse = new ChatGPTMessage('assistant', 'thinking...', true, false)
this._messages.push(aiResponse);
this.emit('newMsg', this._messages.length - 1);
const body = {
model: CHAT_MODELS[this._modelIndex],
messages: this._messages.map(msg => { let m = { role: msg.role, content: msg.content }; return m; }),
temperature: this._temperature,
// temperature: 2, // <- Nuts
stream: true,
};
const session = new Soup.Session();
const message = new Soup.Message({
method: 'POST',
uri: this.url,
});
message.request_headers.append('Authorization', `Bearer ${this._key}`);
message.set_request_body_from_bytes('application/json', new GLib.Bytes(JSON.stringify(body)));
session.send_async(message, GLib.DEFAULT_PRIORITY, null, (_, result) => {
const stream = session.send_finish(result);
this.readResponse(new Gio.DataInputStream({
close_base_stream: true,
base_stream: stream
}), aiResponse);
});
if (this._cycleModels) {
this._requestCount++;
if (this._cycleModels)
this._modelIndex = (this._requestCount - (this._requestCount % ONE_CYCLE_COUNT)) % CHAT_MODELS.length;
}
}
}
export default new ChatGPTService();

View file

@ -0,0 +1,277 @@
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import Soup from 'gi://Soup?version=3.0';
import { fileExists } from './messages.js';
const initMessages =
[
{ role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with very brief explanation for each command\n3. Otherwise, when asked to summarize information or explaining concepts, you are encouraged to use bullet points and headings. Use casual language and be short and concise. \nThanks!" }], },
{ role: "model", parts: [{ text: "- Got it!" }], },
{ role: "user", parts: [{ text: "\"He rushed to where the event was supposed to be hold, he didn't know it got calceled\"" }], },
{ role: "model", parts: [{ text: "## Grammar correction\nErrors:\n\"He rushed to where the event was supposed to be __hold____,__ he didn't know it got calceled\"\nCorrection + minor improvements:\n\"He rushed to the place where the event was supposed to be __held____, but__ he didn't know that it got calceled\"" }], },
{ role: "user", parts: [{ text: "raise volume by 5%" }], },
{ role: "model", parts: [{ text: "## Volume +5```bash\nwpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+\n```\nThis command uses the `wpctl` utility to adjust the volume of the default sink." }], }, { role: "user", parts: [{ text: "main advantages of the nixos operating system" }], },
{ role: "model", parts: [{ text: "## NixOS advantages\n- **Reproducible**: A config working on one device will also work on another\n- **Declarative**: One config language to rule them all. Effortlessly share them with others.\n- **Reliable**: Per-program software versioning. Mitigates the impact of software breakage" }], },
{ role: "user", parts: [{ text: "whats skeumorphism" }], },
{ role: "model", parts: [{ text: "## Skeuomorphism\n- A design philosophy- From early days of interface designing- Tries to imitate real-life objects- It's in fact still used by Apple in their icons until today." }], },
{ role: "user", parts: [{ text: "\"ignorance is bliss\"" }], },
{ role: "model", parts: [{ text: "## \"Ignorance is bliss\"\n- A Latin proverb that means being unaware of something negative can be a source of happiness\n- Often used to justify avoiding difficult truths or responsibilities\n- Can also be interpreted as a warning against seeking knowledge that may bring pain or sorrow" }], },
];
function expandTilde(path) {
if (path.startsWith('~')) {
return GLib.get_home_dir() + path.slice(1);
} else {
return path;
}
}
Utils.exec(`mkdir -p ${GLib.get_user_cache_dir()}/ags/user/ai`);
const KEY_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/google_key.txt`;
const APIDOM_FILE_LOCATION = `${GLib.get_user_cache_dir()}/ags/user/ai/google_api_dom.txt`;
function replaceapidom(URL) {
if (fileExists(expandTilde(APIDOM_FILE_LOCATION))) {
var contents = Utils.readFile(expandTilde(APIDOM_FILE_LOCATION)).trim();
var URL = URL.toString().replace("generativelanguage.googleapis.com", contents);
}
return URL;
}
const CHAT_MODELS = ["gemini-pro"]
const ONE_CYCLE_COUNT = 3;
class GeminiMessage extends Service {
static {
Service.register(this,
{
'delta': ['string'],
},
{
'content': ['string'],
'thinking': ['boolean'],
'done': ['boolean'],
});
}
_role = '';
_parts = [{ text: '' }];
_thinking = false;
_done = false;
_rawData = '';
constructor(role, content, thinking = false, done = false) {
super();
this._role = role;
this._parts = [{ text: content }];
this._thinking = thinking;
this._done = done;
}
get rawData() { return this._rawData }
set rawData(value) { this._rawData = value }
get done() { return this._done }
set done(isDone) { this._done = isDone; this.notify('done') }
get role() { return this._role }
set role(role) { this._role = role; this.emit('changed') }
get content() {
return this._parts.map(part => part.text).join();
}
set content(content) {
this._parts = [{ text: content }];
this.notify('content')
this.emit('changed')
}
get parts() { return this._parts }
get label() { return this._parserState.parsed + this._parserState.stack.join('') }
get thinking() { return this._thinking }
set thinking(thinking) {
this._thinking = thinking;
this.notify('thinking')
this.emit('changed')
}
addDelta(delta) {
if (this.thinking) {
this.thinking = false;
this.content = delta;
}
else {
this.content += delta;
}
this.emit('delta', delta);
}
parseSection() {
if(this._thinking) {
this._thinking = false;
this._parts[0].text= '';
}
const parsedData = JSON.parse(this._rawData);
const delta = parsedData.candidates[0].content.parts[0].text;
this._parts[0].text += delta;
// this.emit('delta', delta);
this.notify('content');
this._rawData = '';
}
}
class GeminiService extends Service {
static {
Service.register(this, {
'initialized': [],
'clear': [],
'newMsg': ['int'],
'hasKey': ['boolean'],
});
}
_assistantPrompt = true;
_messages = [];
_cycleModels = true;
_requestCount = 0;
_temperature = 0.9;
_modelIndex = 0;
_key = '';
_decoder = new TextDecoder();
constructor() {
super();
if (fileExists(expandTilde(KEY_FILE_LOCATION))) this._key = Utils.readFile(expandTilde(KEY_FILE_LOCATION)).trim();
else this.emit('hasKey', false);
if (this._assistantPrompt) this._messages = [...initMessages];
else this._messages = [];
this.emit('initialized');
}
get modelName() { return CHAT_MODELS[this._modelIndex] }
get keyPath() { return KEY_FILE_LOCATION }
get key() { return this._key }
set key(keyValue) {
this._key = keyValue;
Utils.writeFile(this._key, expandTilde(KEY_FILE_LOCATION))
.then(this.emit('hasKey', true))
.catch(err => print(err));
}
get cycleModels() { return this._cycleModels }
set cycleModels(value) {
this._cycleModels = value;
if (!value) this._modelIndex = 0;
else {
this._modelIndex = (this._requestCount - (this._requestCount % ONE_CYCLE_COUNT)) % CHAT_MODELS.length;
}
}
get temperature() { return this._temperature }
set temperature(value) { this._temperature = value; }
get messages() { return this._messages }
get lastMessage() { return this._messages[this._messages.length - 1] }
clear() {
if (this._assistantPrompt)
this._messages = [...initMessages];
else
this._messages = [];
this.emit('clear');
}
get assistantPrompt() { return this._assistantPrompt; }
set assistantPrompt(value) {
this._assistantPrompt = value;
if (value) this._messages = [...initMessages];
else this._messages = [];
}
readResponse(stream, aiResponse) {
stream.read_line_async(
0, null,
(stream, res) => {
try {
const [bytes] = stream.read_line_finish(res);
const line = this._decoder.decode(bytes);
if (line == '[{') { // beginning of response
aiResponse._rawData += '{';
this.thinking = false;
}
else if (line == ',\u000d' || line == ']') { // end of stream pulse
aiResponse.parseSection();
}
else // Normal content
aiResponse._rawData += line;
this.readResponse(stream, aiResponse);
} catch {
aiResponse.done = true;
return;
}
});
}
addMessage(role, message) {
this._messages.push(new GeminiMessage(role, message));
this.emit('newMsg', this._messages.length - 1);
}
send(msg) {
this._messages.push(new GeminiMessage('user', msg));
this.emit('newMsg', this._messages.length - 1);
const aiResponse = new GeminiMessage('model', 'thinking...', true, false)
const body =
{
"contents": this._messages.map(msg => { let m = { role: msg.role, parts: msg.parts }; return m; }),
// "safetySettings": [
// { category: "HARM_CATEGORY_DEROGATORY", threshold: "BLOCK_NONE", },
// { category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE", },
// { category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_NONE", },
// { category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_NONE", },
// { category: "HARM_CATEGORY_UNSPECIFIED", threshold: "BLOCK_NONE", },
// ],
"generationConfig": {
"temperature": this._temperature,
},
// "key": this._key,
// "apiKey": this._key,
};
const session = new Soup.Session();
const message = new Soup.Message({
method: 'POST',
uri: GLib.Uri.parse(replaceapidom(`https://generativelanguage.googleapis.com/v1/models/${this.modelName}:streamGenerateContent?key=${this._key}`), GLib.UriFlags.NONE),
});
message.request_headers.append('Content-Type', `application/json`);
message.set_request_body_from_bytes('application/json', new GLib.Bytes(JSON.stringify(body)));
session.send_async(message, GLib.DEFAULT_PRIORITY, null, (_, result) => {
const stream = session.send_finish(result);
this.readResponse(new Gio.DataInputStream({
close_base_stream: true,
base_stream: stream
}), aiResponse);
});
this._messages.push(aiResponse);
this.emit('newMsg', this._messages.length - 1);
if (this._cycleModels) {
this._requestCount++;
if (this._cycleModels)
this._modelIndex = (this._requestCount - (this._requestCount % ONE_CYCLE_COUNT)) % CHAT_MODELS.length;
}
}
}
export default new GeminiService();

View file

@ -0,0 +1,41 @@
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
const { exec, execAsync } = Utils;
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
class IndicatorService extends Service {
static {
Service.register(
this,
{ 'popup': ['double'], },
);
}
_delay = 1500;
_count = 0;
popup(value) {
this.emit('popup', value);
this._count++;
Utils.timeout(this._delay, () => {
this._count--;
if (this._count === 0)
this.emit('popup', -1);
});
}
connectWidget(widget, callback) {
connect(this, widget, callback, 'popup');
}
}
// the singleton instance
const service = new IndicatorService();
// make it global for easy use with cli
globalThis['indicator'] = service;
// export to use in other modules
export default service;

View file

@ -0,0 +1,58 @@
const { Notify, GLib, Gio } = imports.gi;
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
export function fileExists(filePath) {
let file = Gio.File.new_for_path(filePath);
return file.query_exists(null);
}
const FIRST_RUN_FILE = "firstrun.txt";
const FIRST_RUN_PATH = GLib.build_filenamev([GLib.get_user_cache_dir(), "ags", "user", FIRST_RUN_FILE]);
const FIRST_RUN_FILE_CONTENT = "Just a file to confirm that you have been greeted ;)";
const APP_NAME = "illogical-impulse";
const FIRST_RUN_NOTIF_TITLE = "Welcome!";
const FIRST_RUN_NOTIF_BODY = `Looks like this is your first run. For a list of keybinds, hit <span foreground="#c06af1" font_weight="bold">Super + /</span>.`;
export async function firstRunWelcome() {
if (!fileExists(FIRST_RUN_PATH)) {
Utils.writeFile(FIRST_RUN_FILE_CONTENT, FIRST_RUN_PATH)
.then(() => {
// Note that we add a little delay to make sure the cool circular progress works
Utils.execAsync(['hyprctl', 'keyword', 'bind', "Super,Slash,exec,ags -t cheatsheet"]);
Utils.execAsync(['bash', '-c',
`sleep 0.5; notify-send "Millis since epoch" "$(date +%s%N | cut -b1-13)"; sleep 0.5; notify-send '${FIRST_RUN_NOTIF_TITLE}' '${FIRST_RUN_NOTIF_BODY}' -a '${APP_NAME}' &`
]).catch(print)
})
.catch(print);
}
}
const BATTERY_WARN_LEVELS = [20, 15, 5];
const BATTERY_WARN_TITLES = ["Low battery", "Very low battery", 'Critical Battery']
const BATTERY_WARN_BODIES = ["Plug in the charger", "You there?", 'PLUG THE CHARGER ALREADY']
var batteryWarned = false;
async function batteryMessage() {
const perc = Battery.percent;
const charging = Battery.charging;
if(charging) {
batteryWarned = false;
return;
}
for (let i = BATTERY_WARN_LEVELS.length - 1; i >= 0; i--) {
if (perc <= BATTERY_WARN_LEVELS[i] && !charging && !batteryWarned) {
batteryWarned = true;
Utils.execAsync(['bash', '-c',
`notify-send "${BATTERY_WARN_TITLES[i]}" "${BATTERY_WARN_BODIES[i]}" -u critical -a 'ags' &`
]).catch(print);
break;
}
}
}
// Run them
firstRunWelcome();
Utils.timeout(1, () => {
Battery.connect('changed', () => batteryMessage());
})

View file

@ -0,0 +1,400 @@
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
import Service from "resource:///com/github/Aylur/ags/service.js";
const SIS = GLib.getenv('SWAYSOCK');
export const PAYLOAD_TYPE = {
MESSAGE_RUN_COMMAND: 0,
MESSAGE_GET_WORKSPACES: 1,
MESSAGE_SUBSCRIBE: 2,
MESSAGE_GET_OUTPUTS: 3,
MESSAGE_GET_TREE: 4,
MESSAGE_GET_MARKS: 5,
MESSAGE_GET_BAR_CONFIG: 6,
MESSAGE_GET_VERSION: 7,
MESSAGE_GET_BINDING_NODES: 8,
MESSAGE_GET_CONFIG: 9,
MESSAGE_SEND_TICK: 10,
MESSAGE_SYNC: 11,
MESSAGE_GET_BINDING_STATE: 12,
MESSAGE_GET_INPUTS: 100,
MESSAGE_GET_SEATS: 101,
EVENT_WORKSPACE: 0x80000000,
EVENT_MODE: 0x80000002,
EVENT_WINDOW: 0x80000003,
EVENT_BARCONFIG_UPDATE: 0x80000004,
EVENT_BINDING: 0x80000005,
EVENT_SHUTDOWN: 0x80000006,
EVENT_TICK: 0x80000007,
EVENT_BAR_STATE_UPDATE: 0x80000014,
EVENT_INPUT: 0x80000015,
}
const Client_Event = {
change: undefined,
container: undefined,
}
const Workspace_Event = {
change: undefined,
current: undefined,
old: undefined,
}
const Geometry = {
x: undefined,
y: undefined,
width: undefined,
height: undefined,
}
//NOTE: not all properties are listed here
export const Node = {
id: undefined,
name: undefined,
type: undefined,
border: undefined,
current_border_width: undefined,
layout: undefined,
orientation: undefined,
percent: undefined,
rect: undefined,
window_rect: undefined,
deco_rect: undefined,
geometry: undefined,
urgent: undefined,
sticky: undefined,
marks: undefined,
focused: undefined,
active: undefined,
focus: undefined,
nodes: undefined,
floating_nodes: undefined,
representation: undefined,
fullscreen_mode: undefined,
app_id: undefined,
pid: undefined,
visible: undefined,
shell: undefined,
output: undefined,
inhibit_idle: undefined,
idle_inhibitors: {
application: undefined,
user: undefined,
},
window: undefined,
window_properties: {
title: undefined,
class: undefined,
instance: undefined,
window_role: undefined,
window_type: undefined,
transient_for: undefined,
}
}
export class SwayActiveClient extends Service {
static {
Service.register(this, {}, {
'id': ['int'],
'name': ['string'],
'class': ['string'],
});
}
_id = 0;
_name = '';
_class = '';
get id() { return this._id; }
get name() { return this._name; }
get class() { return this._class; }
updateProperty(prop, value) {
if (!['id', 'name', 'class'].includes(prop)) return;
super.updateProperty(prop, value);
this.emit('changed');
}
}
export class SwayActiveID extends Service {
static {
Service.register(this, {}, {
'id': ['int'],
'name': ['string'],
});
}
_id = 0;
_name = '';
get id() { return this._id; }
get name() { return this._name; }
update(id, name) {
super.updateProperty('id', id);
super.updateProperty('name', name);
this.emit('changed');
}
}
export class SwayActives extends Service {
static {
Service.register(this, {}, {
'client': ['jsobject'],
'monitor': ['jsobject'],
'workspace': ['jsobject'],
});
}
_client = new SwayActiveClient;
_monitor = new SwayActiveID;
_workspace = new SwayActiveID;
constructor() {
super();
(['client', 'workspace', 'monitor']).forEach(obj => {
this[`_${obj}`].connect('changed', () => {
this.notify(obj);
this.emit('changed');
});
});
}
get client() { return this._client; }
get monitor() { return this._monitor; }
get workspace() { return this._workspace; }
}
export class Sway extends Service {
static {
Service.register(this, {}, {
'active': ['jsobject'],
'monitors': ['jsobject'],
'workspaces': ['jsobject'],
'clients': ['jsobject'],
});
}
_decoder = new TextDecoder();
_encoder = new TextEncoder();
_socket;
_active;
_monitors;
_workspaces;
_clients;
get active() { return this._active; }
get monitors() { return Array.from(this._monitors.values()); }
get workspaces() { return Array.from(this._workspaces.values()); }
get clients() { return Array.from(this._clients.values()); }
getMonitor(id) { return this._monitors.get(id); }
getWorkspace(name) { return this._workspaces.get(name); }
getClient(id) { return this._clients.get(id); }
msg(payload) { this._send(PAYLOAD_TYPE.MESSAGE_RUN_COMMAND, payload); }
constructor() {
if (!SIS)
console.error('Sway is not running');
super();
this._active = new SwayActives();
this._monitors = new Map();
this._workspaces = new Map();
this._clients = new Map();
this._socket = new Gio.SocketClient().connect(new Gio.UnixSocketAddress({
path: `${SIS}`,
}), null);
this._watchSocket(this._socket.get_input_stream());
this._send(PAYLOAD_TYPE.MESSAGE_GET_TREE, '');
this._send(PAYLOAD_TYPE.MESSAGE_SUBSCRIBE, JSON.stringify(['window', 'workspace']));
this._active.connect('changed', () => this.emit('changed'));
['monitor', 'workspace', 'client'].forEach(active =>
this._active.connect(`notify::${active}`, () => this.notify('active')));
}
_send(payloadType, payload) {
const pb = this._encoder.encode(payload);
const type = new Uint32Array([payloadType]);
const pl = new Uint32Array([pb.length]);
const magic_string = this._encoder.encode('i3-ipc');
const data = new Uint8Array([
...magic_string,
...(new Uint8Array(pl.buffer)),
...(new Uint8Array(type.buffer)),
...pb]);
this._socket.get_output_stream().write(data, null);
}
_watchSocket(stream) {
stream.read_bytes_async(14, GLib.PRIORITY_DEFAULT, null, (_, resultHeader) => {
const data = stream.read_bytes_finish(resultHeader).get_data();
if (!data)
return;
const payloadLength = new Uint32Array(data.slice(6, 10).buffer)[0];
const payloadType = new Uint32Array(data.slice(10, 14).buffer)[0];
stream.read_bytes_async(
payloadLength,
GLib.PRIORITY_DEFAULT,
null,
(_, resultPayload) => {
const data = stream.read_bytes_finish(resultPayload).get_data();
if (!data)
return;
this._onEvent(payloadType, JSON.parse(this._decoder.decode(data)));
this._watchSocket(stream);
});
});
}
async _onEvent(event_type, event) {
if (!event)
return;
try {
switch (event_type) {
case PAYLOAD_TYPE.EVENT_WORKSPACE:
this._handleWorkspaceEvent(event);
break;
case PAYLOAD_TYPE.EVENT_WINDOW:
this._handleWindowEvent(event);
break;
case PAYLOAD_TYPE.MESSAGE_GET_TREE:
this._handleTreeMessage(event);
break;
default:
break;
}
} catch (error) {
logError(error);
}
this.emit('changed');
}
_handleWorkspaceEvent(workspaceEvent) {
const workspace = workspaceEvent.current;
switch (workspaceEvent.change) {
case 'init':
this._workspaces.set(workspace.name, workspace);
break;
case 'empty':
this._workspaces.delete(workspace.name);
break;
case 'focus':
this._active.workspace.update(workspace.id, workspace.name);
this._active.monitor.update(1, workspace.output);
this._workspaces.set(workspace.name, workspace);
this._workspaces.set(workspaceEvent.old.name, workspaceEvent.old);
break;
case 'rename':
if (this._active.workspace.id === workspace.id)
this._active.workspace.updateProperty('name', workspace.name);
this._workspaces.set(workspace.name, workspace);
break;
case 'reload':
break;
case 'move':
case 'urgent':
default:
this._workspaces.set(workspace.name, workspace);
}
this.notify('workspaces');
}
_handleWindowEvent(clientEvent) {
const client = clientEvent.container;
const id = client.id;
switch (clientEvent.change) {
case 'new':
case 'close':
case 'floating':
case 'move':
// Refresh tree since client events don't contain the relevant information
// to be able to modify `workspace.nodes` or `workspace.floating_nodes`.
// There has to be a better way than this though :/
this._send(PAYLOAD_TYPE.MESSAGE_GET_TREE, '');
break;
case 'focus':
if (this._active.client.id === id)
return;
// eslint-disable-next-line no-case-declarations
const current_active = this._clients.get(this._active.client.id);
if (current_active)
current_active.focused = false;
this._active.client.updateProperty('id', id);
this._active.client.updateProperty('name', client.name);
this._active.client.updateProperty('class', client.shell === 'xwayland'
? client.window_properties?.class || ''
: client.app_id,
);
break;
case 'title':
if (client.focused)
this._active.client.updateProperty('name', client.name);
this._clients.set(id, client);
this.notify('clients');
break;
case 'fullscreen_mode':
case 'urgent':
case 'mark':
default:
this._clients.set(id, client);
this.notify('clients');
}
}
_handleTreeMessage(node) {
switch (node.type) {
case 'root':
this._workspaces.clear();
this._clients.clear();
this._monitors.clear();
node.nodes.map(n => this._handleTreeMessage(n));
break;
case 'output':
this._monitors.set(node.id, node);
if (node.active)
this._active.monitor.update(node.id, node.name);
node.nodes.map(n => this._handleTreeMessage(n));
this.notify('monitors');
break;
case 'workspace':
this._workspaces.set(node.name, node);
// I think I'm missing something. There has to be a better way.
// eslint-disable-next-line no-case-declarations
const hasFocusedChild =
(n) => n.nodes.some(c => c.focused || hasFocusedChild(c));
if (node.focused || hasFocusedChild(node))
this._active.workspace.update(node.id, node.name);
node.nodes.map(n => this._handleTreeMessage(n));
this.notify('workspaces');
break;
case 'con':
case 'floating_con':
this._clients.set(node.id, node);
if (node.focused) {
this._active.client.updateProperty('id', node.id);
this._active.client.updateProperty('name', node.name);
this._active.client.updateProperty('class', node.shell === 'xwayland'
? node.window_properties?.class || ''
: node.app_id,
);
}
node.nodes.map(n => this._handleTreeMessage(n));
this.notify('clients');
break;
}
}
}
export const sway = new Sway;
export default sway;

View file

@ -0,0 +1,89 @@
const { Gio, GLib } = imports.gi;
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
const { exec, execAsync } = Utils;
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
function fileExists(filePath) {
let file = Gio.File.new_for_path(filePath);
return file.query_exists(null);
}
class TodoService extends Service {
static {
Service.register(
this,
{ 'updated': [], },
);
}
_todoPath = '';
_todoJson = [];
refresh(value) {
this.emit('updated', value);
}
connectWidget(widget, callback) {
this.connect(widget, callback, 'updated');
}
get todo_json() {
return this._todoJson;
}
_save() {
Utils.writeFile(JSON.stringify(this._todoJson), this._todoPath)
.catch(print);
}
add(content) {
this._todoJson.push({ content, done: false });
this._save();
this.emit('updated');
}
check(index) {
this._todoJson[index].done = true;
this._save();
this.emit('updated');
}
uncheck(index) {
this._todoJson[index].done = false;
this._save();
this.emit('updated');
}
remove(index) {
this._todoJson.splice(index, 1);
Utils.writeFile(JSON.stringify(this._todoJson), this._todoPath)
.catch(print);
this.emit('updated');
}
constructor() {
super();
this._todoPath = `${GLib.get_user_cache_dir()}/ags/user/todo.json`;
try {
const fileContents = Utils.readFile(this._todoPath);
this._todoJson = JSON.parse(fileContents);
}
catch {
Utils.exec(`bash -c 'mkdir -p ${GLib.get_user_cache_dir()}/ags/user'`);
Utils.exec(`touch ${this._todoPath}`);
Utils.writeFile("[]", this._todoPath).then(() => {
this._todoJson = JSON.parse(Utils.readFile(this._todoPath))
}).catch(print);
}
}
}
// the singleton instance
const service = new TodoService();
// make it global for easy use with cli
globalThis.todo = service;
// export to use in other modules
export default service;

View file

@ -0,0 +1,161 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
// Usage from my python waifu fetcher, for reference
// Usage: waifu-get.py [OPTION]... [TAG]...
// Options:
// --im\tUse waifu.im API. You can use many tags
// --pics\tUse waifu.pics API. Use 1 tag only.
// --nekos\tUse nekos.life (old) API. No tags.
// --segs\tForce NSFW images
// Tags:
// waifu.im (type):
// maid waifu marin-kitagawa mori-calliope raiden-shogun oppai selfies uniform
// waifu.im (nsfw tags):
// ecchi hentai ero ass paizuri oral milf
function paramStringFromObj(params) {
return Object.entries(params)
.map(([key, value]) => {
if (Array.isArray(value)) { // If it's an array, repeat
if (value.length == 0) return '';
let thisKey = `${encodeURIComponent(key)}=${encodeURIComponent(value[0])}`
for (let i = 1; i < value.length; i++) {
thisKey += `&${encodeURIComponent(key)}=${encodeURIComponent(value[i])}`;
}
return thisKey;
}
return `${key}=${value}`;
})
.join('&');
}
class WaifuService extends Service {
_endpoints = {
'im': 'https://api.waifu.im/search',
'nekos': 'https://nekos.life/api/neko',
'pics': 'https://api.waifu.pics/sfw/',
}
_headers = {
'im': { 'Accept-Version': 'v5' },
'nekos': {},
'pics': {},
}
_baseUrl = 'https://api.waifu.im/search';
_mode = 'im'; // Allowed: im
_responses = [];
_queries = [];
_nsfw = false;
_minHeight = 600;
_status = 0;
static {
Service.register(this, {
'initialized': [],
'clear': [],
'newResponse': ['int'],
'updateResponse': ['int'],
});
}
constructor() {
super();
this.emit('initialized');
}
clear() {
this._responses = [];
this._queries = [];
this.emit('clear');
}
get mode() { return this._mode }
set mode(value) {
this._mode = value;
this._baseUrl = this._endpoints[this._mode];
}
get nsfw() { return this._nsfw }
set nsfw(value) { this._nsfw = value }
get queries() { return this._queries }
get responses() { return this._responses }
async fetch(msg) {
// Init
const userArgs = msg.split(/\s+/);
let taglist = [];
this._nsfw = false;
// Construct body/headers
for (let i = 0; i < userArgs.length; i++) {
const thisArg = userArgs[i].trim();
if(thisArg.length == 0) continue;
if (thisArg == '--im') this._mode = 'im';
else if (thisArg == '--nekos') this._mode = 'nekos';
else if (thisArg.includes('pics')) this._mode = 'pics';
else if (thisArg.includes('segs') || thisArg.includes('sex') || thisArg.includes('lewd')) this._nsfw = true;
else {
taglist.push(thisArg);
if(['ecchi', 'hentai', 'ero', 'ass', 'paizuri', 'oral', 'milf'].includes(thisArg)) this._nsfw = true;
}
}
const newMessageId = this._queries.length;
this._queries.push(taglist);
this.emit('newResponse', newMessageId);
const params = {
'included_tags': taglist,
'height': `>=${this._minHeight}`,
'nsfw': this._nsfw,
};
const paramString = paramStringFromObj(params);
// Fetch
// Note: body isn't included since passing directly to url is more reliable
const options = {
method: 'GET',
headers: this._headers[this._mode],
};
var status = 0;
Utils.fetch(`${this._endpoints[this._mode]}?${paramString}`, options)
.then(result => {
status = result.status;
return result.text();
})
.then((dataString) => { // Store interesting stuff and emit
const parsedData = JSON.parse(dataString);
if (!parsedData.images) this._responses.push({
status: status,
signature: -1,
url: '',
extension: '',
source: '',
dominant_color: '#383A40',
is_nsfw: false,
width: 0,
height: 0,
tags: [],
});
else {
const imageData = parsedData.images[0];
this._responses.push({
status: status,
signature: imageData?.signature || -1,
url: imageData?.url || undefined,
extension: imageData.extension,
source: imageData?.source,
dominant_color: imageData?.dominant_color || '#9392A6',
is_nsfw: imageData?.is_nsfw || false,
width: imageData?.width || 0,
height: imageData?.height || 0,
tags: imageData?.tags.map(obj => obj["name"]) || [],
});
}
this.emit('updateResponse', newMessageId);
})
.catch(console.error)
}
}
export default new WaifuService();

View file

@ -0,0 +1,75 @@
const { Gdk, Gio, GLib } = imports.gi;
import Service from 'resource:///com/github/Aylur/ags/service.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
const { exec, execAsync } = Utils;
const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
function fileExists(filePath) {
let file = Gio.File.new_for_path(filePath);
return file.query_exists(null);
}
class WallpaperService extends Service {
static {
Service.register(
this,
{ 'updated': [], },
);
}
_wallPath = '';
_wallJson = [];
_monitorCount = 1;
_save() {
Utils.writeFile(JSON.stringify(this._wallJson), this._wallPath)
.catch(print);
}
add(path) {
this._wallJson.push(path);
this._save();
this.emit('updated');
}
set(path, monitor = -1) {
this._monitorCount = Gdk.Display.get_default()?.get_n_monitors() || 1;
if (this._wallJson.length < this._monitorCount) this._wallJson[this._monitorCount - 1] = "";
if (monitor == -1)
this._wallJson.fill(path);
else
this._wallJson[monitor] = path;
this._save();
this.emit('updated');
}
get(monitor = 0) {
return this._wallJson[monitor];
}
constructor() {
super();
// How many screens?
this._monitorCount = Gdk.Display.get_default()?.get_n_monitors() || 1;
// Read config
this._wallPath = `${GLib.get_user_cache_dir()}/ags/user/wallpaper.json`;
try {
const fileContents = Utils.readFile(this._wallPath);
this._wallJson = JSON.parse(fileContents);
}
catch {
Utils.exec(`bash -c 'mkdir -p ${GLib.get_user_cache_dir()}/ags/user'`);
Utils.exec(`touch ${this._wallPath}`);
Utils.writeFile('[]', this._wallPath).then(() => {
this._wallJson = JSON.parse(Utils.readFile(this._wallPath))
}).catch(print);
}
}
}
// instance
const service = new WallpaperService();
// make it global for easy use with cli
globalThis['wallpaper'] = service;
export default service;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,7 @@
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
// AGS Variables
export const showMusicControls = Variable(false, {})
export const showColorScheme = Variable(false, {})
globalThis['openMusicControls'] = showMusicControls;
globalThis['openColorScheme'] = showColorScheme;

View file

@ -0,0 +1,75 @@
const { Gtk } = imports.gi;
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import WindowTitle from "./spaceleft.js";
import Indicators from "./spaceright.js";
import Music from "./music.js";
import System from "./system.js";
import { RoundedCorner, enableClickthrough } from "../../lib/roundedcorner.js";
const OptionalWorkspaces = async () => {
try {
return (await import('./workspaces_hyprland.js')).default();
} catch {
try {
return (await import('./workspaces_sway.js')).default();
} catch {
return null;
}
}
};
export const Bar = async (monitor = 0) => {
const SideModule = (children) => Widget.Box({
className: 'bar-sidemodule',
children: children,
});
const barContent = Widget.CenterBox({
className: 'bar-bg',
setup: (self) => {
const styleContext = self.get_style_context();
const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
// execAsync(['bash', '-c', `hyprctl keyword monitor ,addreserved,${minHeight},0,0,0`]).catch(print);
},
startWidget: WindowTitle(),
centerWidget: Widget.Box({
className: 'spacing-h-4',
children: [
SideModule([Music()]),
Widget.Box({
homogeneous: true,
children: [await OptionalWorkspaces()],
}),
SideModule([System()]),
]
}),
endWidget: Indicators(),
});
return Widget.Window({
monitor,
name: `bar${monitor}`,
anchor: ['top', 'left', 'right'],
exclusivity: 'exclusive',
visible: true,
child: barContent,
});
}
export const BarCornerTopleft = (id = '') => Widget.Window({
name: `barcornertl${id}`,
layer: 'top',
anchor: ['top', 'left'],
exclusivity: 'normal',
visible: true,
child: RoundedCorner('topleft', { className: 'corner', }),
setup: enableClickthrough,
});
export const BarCornerTopright = (id = '') => Widget.Window({
name: `barcornertr${id}`,
layer: 'top',
anchor: ['top', 'right'],
exclusivity: 'normal',
visible: true,
child: RoundedCorner('topright', { className: 'corner', }),
setup: enableClickthrough,
});

View file

@ -0,0 +1,182 @@
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
const { Box, Label, Overlay, Revealer } = Widget;
const { execAsync, exec } = Utils;
import { AnimatedCircProg } from "../../lib/animatedcircularprogress.js";
import { MaterialIcon } from '../../lib/materialicon.js';
import { showMusicControls } from '../../variables.js';
function trimTrackTitle(title) {
if (!title) return '';
const cleanRegexes = [
/【[^】]*】/, // Touhou n weeb stuff
/\[FREE DOWNLOAD\]/, // F-777
];
cleanRegexes.forEach((expr) => title.replace(expr, ''));
return title;
}
const BarGroup = ({ child }) => Widget.Box({
className: 'bar-group-margin bar-sides',
children: [
Widget.Box({
className: 'bar-group bar-group-standalone bar-group-pad-system',
children: [child],
}),
]
});
const BarResource = (name, icon, command) => {
const resourceCircProg = AnimatedCircProg({
className: 'bar-batt-circprog',
vpack: 'center',
hpack: 'center',
});
const resourceProgress = Overlay({
child: Widget.Box({
vpack: 'center',
className: 'bar-batt',
homogeneous: true,
children: [
MaterialIcon(icon, 'small'),
],
}),
overlays: [resourceCircProg]
});
const resourceLabel = Label({
className: 'txt-smallie txt-onSurfaceVariant',
});
const widget = Box({
className: 'spacing-h-4 txt-onSurfaceVariant',
children: [
resourceLabel,
resourceProgress,
],
setup: (self) => self
.poll(5000, () => execAsync(['bash', '-c', command])
.then((output) => {
resourceCircProg.css = `font-size: ${Number(output)}px;`;
resourceLabel.label = `${Math.round(Number(output))}%`;
widget.tooltipText = `${name}: ${Math.round(Number(output))}%`;
}).catch(print))
,
});
return widget;
}
const TrackProgress = () => {
const _updateProgress = (circprog) => {
const mpris = Mpris.getPlayer('');
if (!mpris) return;
// Set circular progress value
circprog.css = `font-size: ${Math.max(mpris.position / mpris.length * 100, 0)}px;`
}
return AnimatedCircProg({
className: 'bar-music-circprog',
vpack: 'center', hpack: 'center',
extraSetup: (self) => self
.hook(Mpris, _updateProgress)
.poll(3000, _updateProgress)
,
})
}
const switchToRelativeWorkspace = async (self, num) => {
try {
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
Hyprland.sendMessage(`dispatch workspace ${num > 0 ? '+' : ''}${num}`);
} catch {
execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print);
}
}
export default () => {
// TODO: use cairo to make button bounce smaller on click, if that's possible
const playingState = Widget.Box({ // Wrap a box cuz overlay can't have margins itself
homogeneous: true,
children: [Widget.Overlay({
child: Widget.Box({
vpack: 'center',
className: 'bar-music-playstate',
homogeneous: true,
children: [Widget.Label({
vpack: 'center',
className: 'bar-music-playstate-txt',
justification: 'center',
setup: (self) => self.hook(Mpris, label => {
const mpris = Mpris.getPlayer('');
label.label = `${mpris !== null && mpris.playBackStatus == 'Playing' ? 'pause' : 'play_arrow'}`;
}),
})],
setup: (self) => self.hook(Mpris, label => {
const mpris = Mpris.getPlayer('');
if (!mpris) return;
label.toggleClassName('bar-music-playstate-playing', mpris !== null && mpris.playBackStatus == 'Playing');
label.toggleClassName('bar-music-playstate', mpris !== null || mpris.playBackStatus == 'Paused');
}),
}),
overlays: [
TrackProgress(),
]
})]
});
const trackTitle = Widget.Scrollable({
hexpand: true,
child: Widget.Label({
className: 'txt-smallie txt-onSurfaceVariant',
setup: (self) => self.hook(Mpris, label => {
const mpris = Mpris.getPlayer('');
if (mpris)
label.label = `${trimTrackTitle(mpris.trackTitle)}${mpris.trackArtists.join(', ')}`;
else
label.label = 'No media';
}),
})
})
const musicStuff = Box({
className: 'spacing-h-10',
hexpand: true,
children: [
playingState,
trackTitle,
]
})
const systemResources = BarGroup({
child: Box({
children: [
BarResource('RAM Usage', 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`),
Revealer({
revealChild: true,
transition: 'slide_left',
transitionDuration: 200,
child: Box({
className: 'spacing-h-10 margin-left-10',
children: [
BarResource('Swap Usage', 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`),
BarResource('CPU Usage', 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`),
]
}),
setup: (self) => self.hook(Mpris, label => {
const mpris = Mpris.getPlayer('');
self.revealChild = (!mpris);
}),
})
],
})
});
return Widget.EventBox({
onScrollUp: (self) => switchToRelativeWorkspace(self, -1),
onScrollDown: (self) => switchToRelativeWorkspace(self, +1),
onPrimaryClickRelease: () => showMusicControls.setValue(!showMusicControls.value),
onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']),
onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print),
child: Box({
className: 'spacing-h-5',
children: [
BarGroup({ child: musicStuff }),
systemResources,
]
})
});
}

View file

@ -0,0 +1,72 @@
import App from 'resource:///com/github/Aylur/ags/app.js';
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import Brightness from '../../services/brightness.js';
import Indicator from '../../services/indicator.js';
const WindowTitle = async () => {
try {
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
return Widget.Scrollable({
hexpand: true, vexpand: true,
hscroll: 'automatic', vscroll: 'never',
child: Widget.Box({
vertical: true,
children: [
Widget.Label({
xalign: 0,
className: 'txt-smaller bar-topdesc txt',
setup: (self) => self.hook(Hyprland.active.client, label => { // Hyprland.active.client
label.label = Hyprland.active.client.class.length === 0 ? 'Desktop' : Hyprland.active.client.class;
}),
}),
Widget.Label({
xalign: 0,
className: 'txt txt-smallie',
setup: (self) => self.hook(Hyprland.active.client, label => { // Hyprland.active.client
label.label = Hyprland.active.client.title.length === 0 ? `Workspace ${Hyprland.active.workspace.id}` : Hyprland.active.client.title;
}),
})
]
})
});
} catch {
return null;
}
}
const OptionalWindowTitleInstance = await WindowTitle();
export default () => Widget.EventBox({
onScrollUp: () => {
Indicator.popup(1); // Since the brightness and speaker are both on the same window
Brightness.screen_value += 0.05;
},
onScrollDown: () => {
Indicator.popup(1); // Since the brightness and speaker are both on the same window
Brightness.screen_value -= 0.05;
},
onPrimaryClick: () => {
App.toggleWindow('sideleft');
},
child: Widget.Box({
homogeneous: false,
children: [
Widget.Box({ className: 'bar-corner-spacing' }),
Widget.Overlay({
overlays: [
Widget.Box({ hexpand: true }),
Widget.Box({
className: 'bar-sidemodule', hexpand: true,
children: [Widget.Box({
vertical: true,
className: 'bar-space-button',
children: [
OptionalWindowTitleInstance,
]
})]
}),
]
})
]
})
});

View file

@ -0,0 +1,82 @@
import App from 'resource:///com/github/Aylur/ags/app.js';
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js';
const { execAsync } = Utils;
import Indicator from '../../services/indicator.js';
import { StatusIcons } from "../../lib/statusicons.js";
import { Tray } from "./tray.js";
export default () => {
const barTray = Tray();
const separatorDot = Widget.Revealer({
transition: 'slide_left',
revealChild: false,
attribute: {
'count': SystemTray.items.length,
'update': (self, diff) => {
self.attribute.count += diff;
self.revealChild = (self.attribute.count > 0);
}
},
child: Widget.Box({
vpack: 'center',
className: 'separator-circle',
}),
setup: (self) => self
.hook(SystemTray, (self) => self.attribute.update(self, 1), 'added')
.hook(SystemTray, (self) => self.attribute.update(self, -1), 'removed')
,
});
const barStatusIcons = StatusIcons({
className: 'bar-statusicons',
setup: (self) => self.hook(App, (self, currentName, visible) => {
if (currentName === 'sideright') {
self.toggleClassName('bar-statusicons-active', visible);
}
}),
});
const actualContent = Widget.Box({
hexpand: true,
className: 'spacing-h-5 txt',
children: [
Widget.Box({
hexpand: true,
className: 'spacing-h-5 txt',
children: [
Widget.Box({ hexpand: true, }),
barTray,
separatorDot,
barStatusIcons,
],
}),
]
});
return Widget.EventBox({
onScrollUp: () => {
if (!Audio.speaker) return;
Audio.speaker.volume += 0.03;
Indicator.popup(1);
},
onScrollDown: () => {
if (!Audio.speaker) return;
Audio.speaker.volume -= 0.03;
Indicator.popup(1);
},
onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) },
onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) },
onPrimaryClick: () => App.toggleWindow('sideright'),
onSecondaryClickRelease: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print),
onMiddleClickRelease: () => execAsync('playerctl play-pause').catch(print),
child: Widget.Box({
homogeneous: false,
children: [
actualContent,
Widget.Box({ className: 'bar-corner-spacing' }),
]
})
});
}

View file

@ -0,0 +1,235 @@
// This is for the right pills of the bar.
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
const { Box, Label, Button, Overlay, Revealer, Scrollable, Stack, EventBox } = Widget;
const { exec, execAsync } = Utils;
const { GLib } = imports.gi;
import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
import { MaterialIcon } from '../../lib/materialicon.js';
import { AnimatedCircProg } from "../../lib/animatedcircularprogress.js";
import { WWO_CODE, WEATHER_SYMBOL, NIGHT_WEATHER_SYMBOL } from '../../data/weather.js';
const BATTERY_LOW = 20;
const WEATHER_CACHE_FOLDER = `${GLib.get_user_cache_dir()}/ags/weather`;
Utils.exec(`mkdir -p ${WEATHER_CACHE_FOLDER}`);
let WEATHER_CITY = '';
try {
WEATHER_CITY = GLib.getenv('AGS_WEATHER_CITY');
} catch (e) {
print(e);
}
const BatBatteryProgress = () => {
const _updateProgress = (circprog) => { // Set circular progress value
circprog.css = `font-size: ${Math.abs(Battery.percent)}px;`
circprog.toggleClassName('bar-batt-circprog-low', Battery.percent <= BATTERY_LOW);
circprog.toggleClassName('bar-batt-circprog-full', Battery.charged);
}
return AnimatedCircProg({
className: 'bar-batt-circprog',
vpack: 'center', hpack: 'center',
extraSetup: (self) => self
.hook(Battery, _updateProgress)
,
})
}
const BarClock = () => Widget.Box({
vpack: 'center',
className: 'spacing-h-5 txt-onSurfaceVariant bar-clock-box',
children: [
Widget.Label({
className: 'bar-clock',
label: GLib.DateTime.new_now_local().format("%H:%M"),
setup: (self) => self.poll(5000, label => {
label.label = GLib.DateTime.new_now_local().format("%H:%M");
}),
}),
Widget.Label({
className: 'txt-norm',
label: '•',
}),
Widget.Label({
className: 'txt-smallie',
label: GLib.DateTime.new_now_local().format("%A, %d/%m"),
setup: (self) => self.poll(5000, label => {
label.label = GLib.DateTime.new_now_local().format("%A, %d/%m");
}),
}),
],
});
const UtilButton = ({ name, icon, onClicked }) => Button({
vpack: 'center',
tooltipText: name,
onClicked: onClicked,
className: 'bar-util-btn icon-material txt-norm',
label: `${icon}`,
})
const Utilities = () => Box({
hpack: 'center',
className: 'spacing-h-5 txt-onSurfaceVariant',
children: [
UtilButton({
name: 'Screen snip', icon: 'screenshot_region', onClicked: () => {
Utils.execAsync(['bash', '-c', `grim -g "$(slurp -d -c e2e2e2BB -b 31313122 -s 00000000)" - | wl-copy &`])
.catch(print)
}
}),
UtilButton({
name: 'Color picker', icon: 'colorize', onClicked: () => {
Utils.execAsync(['hyprpicker', '-a']).catch(print)
}
}),
UtilButton({
name: 'Toggle on-screen keyboard', icon: 'keyboard', onClicked: () => {
App.toggleWindow('osk');
}
}),
]
})
const BarBattery = () => Box({
className: 'spacing-h-4 txt-onSurfaceVariant',
children: [
Revealer({
transitionDuration: 150,
revealChild: false,
transition: 'slide_right',
child: MaterialIcon('bolt', 'norm', { tooltipText: "Charging" }),
setup: (self) => self.hook(Battery, revealer => {
self.revealChild = Battery.charging;
}),
}),
Label({
className: 'txt-smallie txt-onSurfaceVariant',
setup: (self) => self.hook(Battery, label => {
label.label = `${Battery.percent}%`;
}),
}),
Overlay({
child: Widget.Box({
vpack: 'center',
className: 'bar-batt',
homogeneous: true,
children: [
MaterialIcon('settings_heart', 'small'),
],
setup: (self) => self.hook(Battery, box => {
box.toggleClassName('bar-batt-low', Battery.percent <= BATTERY_LOW);
box.toggleClassName('bar-batt-full', Battery.charged);
}),
}),
overlays: [
BatBatteryProgress(),
]
}),
]
});
const BarGroup = ({ child }) => Widget.Box({
className: 'bar-group-margin bar-sides',
children: [
Widget.Box({
className: 'bar-group bar-group-standalone bar-group-pad-system',
children: [child],
}),
]
});
const BatteryModule = () => Stack({
transition: 'slide_up_down',
transitionDuration: 150,
children: {
'laptop': Box({
className: 'spacing-h-5', children: [
BarGroup({ child: Utilities() }),
BarGroup({ child: BarBattery() }),
]
}),
'desktop': BarGroup({
child: Box({
hexpand: true,
hpack: 'center',
className: 'spacing-h-5',
children: [
MaterialIcon('device_thermostat', 'small'),
Label({
label: 'Weather',
})
],
setup: (self) => self.poll(900000, async (self) => {
const WEATHER_CACHE_PATH = WEATHER_CACHE_FOLDER + '/wttr.in.txt';
const updateWeatherForCity = (city) => execAsync(`curl https://wttr.in/${city}?format=j1`)
.then(output => {
const weather = JSON.parse(output);
Utils.writeFile(JSON.stringify(weather), WEATHER_CACHE_PATH)
.catch(print);
const weatherCode = weather.current_condition[0].weatherCode;
const weatherDesc = weather.current_condition[0].weatherDesc[0].value;
const temperature = weather.current_condition[0].temp_C;
const feelsLike = weather.current_condition[0].FeelsLikeC;
const weatherSymbol = WEATHER_SYMBOL[WWO_CODE[weatherCode]];
self.children[0].label = weatherSymbol;
self.children[1].label = `${temperature}℃ • Feels like ${feelsLike}`;
self.tooltipText = weatherDesc;
}).catch((err) => {
try { // Read from cache
const weather = JSON.parse(
Utils.readFile(WEATHER_CACHE_PATH)
);
const weatherCode = weather.current_condition[0].weatherCode;
const weatherDesc = weather.current_condition[0].weatherDesc[0].value;
const temperature = weather.current_condition[0].temp_C;
const feelsLike = weather.current_condition[0].FeelsLikeC;
const weatherSymbol = WEATHER_SYMBOL[WWO_CODE[weatherCode]];
self.children[0].label = weatherSymbol;
self.children[1].label = `${temperature}℃ • Feels like ${feelsLike}`;
self.tooltipText = weatherDesc;
} catch (err) {
print(err);
}
});
if (WEATHER_CITY != '' && WEATHER_CITY != null) {
updateWeatherForCity(WEATHER_CITY);
}
else {
Utils.execAsync('curl ipinfo.io')
.then(output => {
return JSON.parse(output)['city'].toLowerCase();
})
.then(updateWeatherForCity);
}
}),
})
}),
},
setup: (stack) => Utils.timeout(10, () => {
if (!Battery.available) stack.shown = 'desktop';
else stack.shown = 'laptop';
})
})
const switchToRelativeWorkspace = async (self, num) => {
try {
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
Hyprland.sendMessage(`dispatch workspace ${num > 0 ? '+' : ''}${num}`);
} catch {
execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print);
}
}
export default () => Widget.EventBox({
onScrollUp: (self) => switchToRelativeWorkspace(self, -1),
onScrollDown: (self) => switchToRelativeWorkspace(self, +1),
onPrimaryClick: () => App.toggleWindow('sideright'),
child: Widget.Box({
className: 'spacing-h-5',
children: [
BarGroup({ child: BarClock() }),
BatteryModule(),
]
})
});

View file

@ -0,0 +1,89 @@
const { Gtk } = imports.gi;
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js';
const { Box, Icon, Button, Revealer } = Widget;
const { Gravity } = imports.gi.Gdk;
const revealerDuration = 200;
const SysTrayItem = (item) => Button({
className: 'bar-systray-item',
child: Icon({
hpack: 'center',
icon: item.icon,
setup: (self) => self.hook(item, (self) => self.icon = item.icon),
}),
setup: (self) => self
.hook(item, (self) => self.tooltipMarkup = item['tooltip-markup'])
,
onClicked: btn => item.menu.popup_at_widget(btn, Gravity.SOUTH, Gravity.NORTH, null),
onSecondaryClick: btn => item.menu.popup_at_widget(btn, Gravity.SOUTH, Gravity.NORTH, null),
});
export const Tray = (props = {}) => {
const trayContent = Box({
className: 'margin-right-5 spacing-h-15',
// attribute: {
// items: new Map(),
// addItem: (box, item) => {
// if (!item) return;
// console.log('init item:', item)
// item.menu.className = 'menu';
// if (box.attribute.items.has(item.id) || !item)
// return;
// const widget = SysTrayItem(item);
// box.attribute.items.set(item.id, widget);
// box.add(widget);
// box.show_all();
// },
// onAdded: (box, id) => {
// console.log('supposed to add', id)
// const item = SystemTray.getItem(id);
// if (!item) return;
// console.log('which is', box.attribute.items.get(id))
// item.menu.className = 'menu';
// if (box.attribute.items.has(id) || !item)
// return;
// const widget = SysTrayItem(item);
// box.attribute.items.set(id, widget);
// box.add(widget);
// box.show_all();
// },
// onRemoved: (box, id) => {
// console.log('supposed to remove', id)
// if (!box.attribute.items.has(id)) return;
// console.log('which is', box.attribute.items.get(id))
// box.attribute.items.get(id).destroy();
// box.attribute.items.delete(id);
// },
// },
// setup: (self) => {
// // self.hook(SystemTray, (box, id) => box.attribute.onAdded(box, id), 'added')
// // .hook(SystemTray, (box, id) => box.attribute.onRemoved(box, id), 'removed');
// // SystemTray.items.forEach(item => self.attribute.addItem(self, item));
// // self.chidren = SystemTray.items.map(item => SysTrayItem(item));
// console.log(SystemTray.items.map(item => SysTrayItem(item)))
// self.chidren = SystemTray.items.map(item => SysTrayItem(item));
// self.show_all();
// },
setup: (self) => self
.hook(SystemTray, (self) => {
self.children = SystemTray.items.map(SysTrayItem);
self.show_all();
})
,
});
const trayRevealer = Widget.Revealer({
revealChild: true,
transition: 'slide_left',
transitionDuration: revealerDuration,
child: trayContent,
});
return Box({
...props,
children: [trayRevealer],
});
}

Some files were not shown because too many files have changed in this diff Show more