Compare commits
63 Commits
a2261cacd1
...
quickshell
| Author | SHA1 | Date | |
|---|---|---|---|
|
237a62ea8a
|
|||
|
a63be876f7
|
|||
| 2b5a96bc20 | |||
| 02216bfa0c | |||
|
793dbac197
|
|||
|
c584091e60
|
|||
|
68b1765582
|
|||
|
8a169dbfa1
|
|||
|
2c035ac47a
|
|||
|
5648ae6b31
|
|||
|
c504274eca
|
|||
|
bd192f0443
|
|||
|
99e5362345
|
|||
|
35693c9782
|
|||
|
aba70d46a9
|
|||
|
be4de25d84
|
|||
|
2177549100
|
|||
|
abdc2f5c6c
|
|||
|
99121f72c9
|
|||
|
b460cb58ef
|
|||
|
32232d08db
|
|||
|
2d9c505ad7
|
|||
|
667af5a5a6
|
|||
|
e79ed0f643
|
|||
|
d0fcde133d
|
|||
|
b953e5b7ce
|
|||
|
c8f098f1a2
|
|||
|
e454e12d2f
|
|||
|
44a72b39e4
|
|||
|
4af7226777
|
|||
|
28c59be2a7
|
|||
|
51b882f2c5
|
|||
|
13b69ccc95
|
|||
|
be5fd3b9ff
|
|||
|
20ddfb5ddd
|
|||
|
4d2949ab93
|
|||
|
e0faac096b
|
|||
|
1c6708bad5
|
|||
|
a07742a206
|
|||
|
7bacc8ae06
|
|||
|
f400aaf570
|
|||
|
dbd3195430
|
|||
|
d041f61c46
|
|||
|
705f702535
|
|||
|
8fe373eeb5
|
|||
|
64dd1077b6
|
|||
|
8fe95f071a
|
|||
|
bd21506f0d
|
|||
|
c8c6a09684
|
|||
|
0c679290c5
|
|||
|
4685f31aa1
|
|||
|
77b8578379
|
|||
|
5bf4a22e8f
|
|||
|
91257fbcf8
|
|||
|
13cc8234e1
|
|||
|
89aa6186f2
|
|||
|
794593222c
|
|||
|
8c64e8e7b9
|
|||
|
8348cd9a54
|
|||
|
83772d34dd
|
|||
|
5e5f2ed1bb
|
|||
|
d7a3fc7a07
|
|||
|
3c4bc5043e
|
@@ -1,6 +1,7 @@
|
||||
keys:
|
||||
- &imxyy-nix age1jf5pg2x6ta8amj40xdy0stvcvrdlkwc2nrwtmkpymu0qclk0eg5qmm9kns
|
||||
- &imxyy-nix-server age1hpgg6psejh4y6jcdd34wxuml75fnweqpe0kh8376yqsctsfn9qxs037kk6
|
||||
- &imxyy-nix-x16 age1r0fv0tagxupfacv0aaxk5ss7sqvswv6kq8tk3x46ndqrj6f5afvqegahxq
|
||||
- &imxyy-cloudwin age1tp7th3rrv3x0l6jl76n0hjqjp223w2y586pkgr0hcjwdm254jd5shkj6a8
|
||||
creation_rules:
|
||||
- path_regex: secrets/.*\.(yaml|toml|json|env|dae|txt|conf)$
|
||||
@@ -8,4 +9,5 @@ creation_rules:
|
||||
- age:
|
||||
- *imxyy-nix
|
||||
- *imxyy-nix-server
|
||||
- *imxyy-nix-x16
|
||||
- *imxyy-cloudwin
|
||||
|
||||
16
Makefile
16
Makefile
@@ -2,15 +2,19 @@ all: fmt switch
|
||||
|
||||
switch:
|
||||
@echo "Rebuilding NixOS..."
|
||||
@nixos-rebuild switch --flake . --sudo --json |& nom
|
||||
@nh os switch .
|
||||
|
||||
boot:
|
||||
@echo "Rebuilding NixOS..."
|
||||
@nixos-rebuild boot --flake . --sudo --json |& nom
|
||||
@nh os boot .
|
||||
|
||||
test:
|
||||
@echo "Rebuilding NixOS..."
|
||||
@nh os test .
|
||||
|
||||
vm:
|
||||
@echo "Building NixOS VM..."
|
||||
@nixos-rebuild build-vm --flake . --json |& nom
|
||||
@nh os build-vm .
|
||||
|
||||
update:
|
||||
@echo "Updating flakes..."
|
||||
@@ -23,17 +27,17 @@ replpkgs:
|
||||
@nix repl -f flake:nixpkgs
|
||||
|
||||
repl:
|
||||
@nixos-rebuild repl --flake .
|
||||
@nh os repl .
|
||||
|
||||
cleandry:
|
||||
@echo "Listing all generations older than 15 days..."
|
||||
@sudo nix profile wipe-history --profile /nix/var/nix/profiles/system --dry-run --older-than 15d
|
||||
@nix run home-manager#home-manager -- expire-generations -15days --dry-run
|
||||
@nix profile wipe-history --profile ~/.local/state/nix/profiles/home-manager --dry-run --older-than 15d
|
||||
|
||||
clean:
|
||||
@echo "Removing all generations older than 15 days..."
|
||||
@sudo nix profile wipe-history --profile /nix/var/nix/profiles/system --older-than 15d
|
||||
@nix run home-manager#home-manager -- expire-generations -15days
|
||||
@nix profile wipe-history --profile ~/.local/state/nix/profiles/home-manager --older-than 15d
|
||||
|
||||
gc:
|
||||
@nix store gc --debug
|
||||
|
||||
27
README.md
27
README.md
@@ -32,7 +32,7 @@ As for Flakes, refer to
|
||||
| **Application Launcher** | wofi |
|
||||
| **Notification Daemon** | SwayNotificationCenter |
|
||||
| **Input method framework** | Fcitx5 |
|
||||
| **Shell** | zsh & custom oh-my-zsh |
|
||||
| **Shell** | Zsh |
|
||||
| **Netease Cloudmusic Player** | go-musicfox |
|
||||
| **Media Player** | mpv |
|
||||
| **Text Editor** | Neovim |
|
||||
@@ -52,28 +52,3 @@ And more...
|
||||
- `vars.nix` - my variables
|
||||
- `secrets/` - secrets managed by sops-nix. see [./secrets](./secrets) for details
|
||||
- `flake.nix` - flake entry
|
||||
|
||||
<!--
|
||||
## Deployment Guide
|
||||
|
||||
Since this repository is **heavily** based on my **own** daily use,
|
||||
it includes, but not limit to, the tweaks listed below:
|
||||
|
||||
- auto login some specific TTYs (see [./modules/getty-autologin.nix](./modules/getty-autologin.nix) for details)
|
||||
- `config.my` alias for custom modules and `config.my.home` alias for single user home-manger configuartion
|
||||
- `lib.my` utilities to define custom modules conveniently
|
||||
|
||||
Therefore, if you want to deploy this setup locally, make sure that
|
||||
you have **carefully** read **every single line** of code in this repository.
|
||||
|
||||
Then, you can follow the guide to deploy:
|
||||
|
||||
0. make sure that you have a very **reliable** networking environment (you know what I'm talking about)
|
||||
1. boot into LiveCD
|
||||
2. repartition your disk, it should be like this:
|
||||
- `/dev/sda`
|
||||
- `/dev/sda1`: boot partition (remember to set its type to `EFI System` in `cfdisk`, don't ask me why)
|
||||
3. clone the repository (if you don't have `git` installed, `nix-shell -p git` will do the trick)
|
||||
4. rename one of the folders in the `config/hosts` folder
|
||||
5.
|
||||
-->
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -22,10 +22,17 @@
|
||||
nixosDirs = [
|
||||
"/root"
|
||||
"/var"
|
||||
"/etc/ssh"
|
||||
];
|
||||
nixosFiles = [
|
||||
"/etc/machine-id"
|
||||
];
|
||||
homeDirs = [
|
||||
{
|
||||
directory = ".ssh";
|
||||
mode = "0700";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.open-webui = {
|
||||
enable = true;
|
||||
host = "127.0.0.1";
|
||||
port = 8089;
|
||||
package = pkgs.stable.open-webui;
|
||||
};
|
||||
services.caddy.virtualHosts."ai.imxyy.top" = {
|
||||
extraConfig = ''
|
||||
|
||||
47
config/hosts/imxyy-nix-server/build.nix
Normal file
47
config/hosts/imxyy-nix-server/build.nix
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
sopsRoot,
|
||||
...
|
||||
}:
|
||||
{
|
||||
sops.secrets.et-imxyy-nix-server-nixremote = {
|
||||
sopsFile = sopsRoot + /et-imxyy-nix-server-nixremote.toml;
|
||||
format = "binary";
|
||||
};
|
||||
environment.systemPackages = [ pkgs.easytier ];
|
||||
systemd.services."easytier-nixremote" = {
|
||||
enable = true;
|
||||
script = "${pkgs.easytier}/bin/easytier-core -c ${config.sops.secrets.et-imxyy-nix-server-nixremote.path}";
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 500 "always";
|
||||
RestartMaxDelaySec = lib.mkOverride 500 "1m";
|
||||
RestartSec = lib.mkOverride 500 "100ms";
|
||||
RestartSteps = lib.mkOverride 500 9;
|
||||
User = "root";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [
|
||||
"network.target"
|
||||
"sops-nix.service"
|
||||
];
|
||||
};
|
||||
users.groups.nixremote = { };
|
||||
users.users.nixremote = {
|
||||
isSystemUser = true;
|
||||
description = "nix remote build user";
|
||||
group = "nixremote";
|
||||
openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOEFLUkyeaK8ZPPZdVNEmtx8zvoxi7xqS2Z6oxRBuUPO imxyy@imxyy-nix"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBWOy0QmAyxENg/O5m3cus8U3c9jCLioivwcWsh5/a82 imxyy-hisense-pad"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8pivvE8PMtsOxmccfNhH/4KehDKhBfUfJbQZxo/SZT imxyy-ace5"
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKALTBn/QSGcSPgMg0ViSazFcaA0+nEF05EJpjbsI6dE imxyy_soope_@imxyy-cloudwin"
|
||||
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIENauvvhVMLsUwH9cPYsvnOg7VCL3a4yEiKm8I524TE efl@efl-nix"
|
||||
];
|
||||
};
|
||||
nix.settings.trusted-users = [
|
||||
"nixremote"
|
||||
];
|
||||
}
|
||||
@@ -21,5 +21,7 @@
|
||||
./note.nix
|
||||
./matrix.nix
|
||||
./minio.nix
|
||||
./build.nix
|
||||
./immich.nix
|
||||
];
|
||||
}
|
||||
|
||||
@@ -12,20 +12,11 @@
|
||||
"workspace"
|
||||
"Virt"
|
||||
|
||||
{
|
||||
directory = ".ssh";
|
||||
mode = "0700";
|
||||
}
|
||||
".local/state"
|
||||
".local/share"
|
||||
".local/share/nvim"
|
||||
".cache"
|
||||
|
||||
".ollama"
|
||||
];
|
||||
nixosDirs = [
|
||||
"/etc/ssh"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
17
config/hosts/imxyy-nix-server/immich.nix
Normal file
17
config/hosts/imxyy-nix-server/immich.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ ... }:
|
||||
{
|
||||
services.immich = {
|
||||
enable = true;
|
||||
host = "127.0.0.1";
|
||||
port = 8096;
|
||||
mediaLocation = "/mnt/nas/immich";
|
||||
group = "nextcloud";
|
||||
};
|
||||
services.caddy.virtualHosts."immich.imxyy.top" = {
|
||||
extraConfig = ''
|
||||
reverse_proxy :8096 {
|
||||
header_up X-Real-IP {remote_host}
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
@@ -392,6 +392,21 @@
|
||||
customDomains = [ "matrix.imxyy.top" ];
|
||||
}
|
||||
|
||||
{
|
||||
name = "immich-http";
|
||||
type = "http";
|
||||
localIP = "127.0.0.1";
|
||||
localPort = 80;
|
||||
customDomains = [ "immich.imxyy.top" ];
|
||||
}
|
||||
{
|
||||
name = "immich-https";
|
||||
type = "https";
|
||||
localIP = "127.0.0.1";
|
||||
localPort = 443;
|
||||
customDomains = [ "immich.imxyy.top" ];
|
||||
}
|
||||
|
||||
{
|
||||
name = "minecraft";
|
||||
type = "tcp";
|
||||
@@ -455,7 +470,7 @@
|
||||
environment.systemPackages = [ pkgs.easytier ];
|
||||
systemd.services."easytier" = {
|
||||
enable = true;
|
||||
script = "easytier-core -c ${config.sops.secrets.et-imxyy-nix-server.path}";
|
||||
script = "${pkgs.easytier}/bin/easytier-core -c ${config.sops.secrets.et-imxyy-nix-server.path}";
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 500 "always";
|
||||
RestartMaxDelaySec = lib.mkOverride 500 "1m";
|
||||
@@ -468,11 +483,6 @@
|
||||
"network.target"
|
||||
"sops-nix.service"
|
||||
];
|
||||
path = with pkgs; [
|
||||
easytier
|
||||
iproute2
|
||||
bash
|
||||
];
|
||||
};
|
||||
|
||||
virtualisation.oci-containers = {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
ports = [ "8093:8080" ];
|
||||
};
|
||||
siyuan = {
|
||||
image = "apkdv/siyuan-unlock:v3.1.24";
|
||||
image = "apkdv/siyuan-unlock:v3.1.30";
|
||||
volumes = [
|
||||
"/mnt/nas/siyuan/workspace:/workspace"
|
||||
"/mnt/nas/siyuan:/home/siyuan"
|
||||
|
||||
@@ -26,9 +26,8 @@
|
||||
];
|
||||
users = {
|
||||
users.nas = {
|
||||
isNormalUser = true;
|
||||
home = "/var/empty";
|
||||
description = "nas user";
|
||||
isSystemUser = true;
|
||||
description = "NAS user";
|
||||
group = "nextcloud";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23,6 +23,10 @@ in
|
||||
"amd_iommu=on"
|
||||
"vfio-pci.ids=${lib.concatStringsSep "," gpuIDs}"
|
||||
];
|
||||
extraModprobeConfig = ''
|
||||
options kvm ignore_msrs=Y
|
||||
options kvm report_ignored_msrs=N
|
||||
'';
|
||||
};
|
||||
virtualisation.spiceUSBRedirection.enable = true;
|
||||
my.virt.enable = true;
|
||||
|
||||
8
config/hosts/imxyy-nix-x16/default.nix
Normal file
8
config/hosts/imxyy-nix-x16/default.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
imports = [
|
||||
./nixos.nix
|
||||
./hardware.nix
|
||||
./home.nix
|
||||
./net.nix
|
||||
];
|
||||
}
|
||||
106
config/hosts/imxyy-nix-x16/hardware.nix
Normal file
106
config/hosts/imxyy-nix-x16/hardware.nix
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
username,
|
||||
...
|
||||
}:
|
||||
let
|
||||
btrfs = "/dev/disk/by-uuid/69ab72d4-6ced-4f70-8b5e-aa2daa8c0b6b";
|
||||
in
|
||||
{
|
||||
boot = {
|
||||
initrd = {
|
||||
kernelModules = [ "amdgpu" ];
|
||||
availableKernelModules = [
|
||||
"nvme"
|
||||
"xhci_pci"
|
||||
"thunderbolt"
|
||||
"uas"
|
||||
"sd_mod"
|
||||
];
|
||||
verbose = false;
|
||||
};
|
||||
|
||||
kernelPackages = lib.mkForce pkgs.linuxPackages_cachyos;
|
||||
kernelModules = [ "kvm-amd" ];
|
||||
|
||||
tmp.useTmpfs = true;
|
||||
kernel.sysctl = {
|
||||
"fs.file-max" = 9223372036854775807;
|
||||
};
|
||||
};
|
||||
services.scx.enable = true;
|
||||
|
||||
fileSystems."/" = {
|
||||
device = btrfs;
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
"subvol=root"
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/nix" = {
|
||||
device = btrfs;
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
"subvol=nix"
|
||||
];
|
||||
};
|
||||
|
||||
my.persist.location = "/nix/persist";
|
||||
fileSystems."/nix/persist" = {
|
||||
device = btrfs;
|
||||
fsType = "btrfs";
|
||||
options = [
|
||||
"compress=zstd"
|
||||
"subvol=persist"
|
||||
];
|
||||
neededForBoot = true;
|
||||
};
|
||||
|
||||
boot.initrd.postDeviceCommands = lib.mkAfter ''
|
||||
mkdir /btrfs_tmp
|
||||
mount ${btrfs} /btrfs_tmp
|
||||
mkdir -p /btrfs_tmp/old_roots
|
||||
if [[ -e /btrfs_tmp/root ]]; then
|
||||
timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/root)" "+%Y-%m-%-d_%H:%M:%S")
|
||||
mv /btrfs_tmp/root "/btrfs_tmp/old_roots/$timestamp"
|
||||
fi
|
||||
|
||||
delete_subvolume_recursively() {
|
||||
IFS=$'\n'
|
||||
for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
|
||||
delete_subvolume_recursively "/btrfs_tmp/$i"
|
||||
done
|
||||
btrfs subvolume delete "$1"
|
||||
}
|
||||
|
||||
for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +14); do
|
||||
delete_subvolume_recursively "$i"
|
||||
done
|
||||
|
||||
btrfs subvolume create /btrfs_tmp/root
|
||||
umount /btrfs_tmp
|
||||
'';
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/96D3-93B0";
|
||||
fsType = "vfat";
|
||||
options = [
|
||||
"uid=0"
|
||||
"gid=0"
|
||||
"fmask=0077"
|
||||
"dmask=0077"
|
||||
];
|
||||
};
|
||||
|
||||
networking.useDHCP = lib.mkDefault false;
|
||||
|
||||
hardware.enableRedistributableFirmware = lib.mkDefault true;
|
||||
hardware.cpu.amd.updateMicrocode = config.hardware.enableRedistributableFirmware;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkForce "x86_64-linux";
|
||||
}
|
||||
141
config/hosts/imxyy-nix-x16/home.nix
Normal file
141
config/hosts/imxyy-nix-x16/home.nix
Normal file
@@ -0,0 +1,141 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
username,
|
||||
...
|
||||
}:
|
||||
{
|
||||
my.home = {
|
||||
home.packages = with pkgs; [
|
||||
localsend
|
||||
|
||||
rclone
|
||||
|
||||
wpsoffice-cn
|
||||
wps-office-fonts
|
||||
ttf-wps-fonts
|
||||
evince
|
||||
|
||||
anki
|
||||
|
||||
ayugram-desktop
|
||||
telegram-desktop
|
||||
signal-desktop
|
||||
discord
|
||||
qq
|
||||
wechat
|
||||
|
||||
gnome-clocks
|
||||
|
||||
wineWowPackages.waylandFull
|
||||
|
||||
pavucontrol
|
||||
pamixer
|
||||
];
|
||||
programs.zsh = {
|
||||
sessionVariables = {
|
||||
PATH = "/home/${username}/bin:$PATH";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
gpg.enable = true;
|
||||
cli.all.enable = true;
|
||||
coding.all.enable = true;
|
||||
desktop.all.enable = true;
|
||||
|
||||
desktop.browser.librewolf.enable = lib.mkForce false;
|
||||
|
||||
i18n.fcitx5.enable = true;
|
||||
|
||||
xdg = {
|
||||
enable = true;
|
||||
defaultApplications =
|
||||
let
|
||||
browser = [ "zen-beta.desktop" ];
|
||||
editor = [ "codium.desktop" ];
|
||||
imageviewer = [ "org.gnome.Shotwell-Viewer.desktop" ];
|
||||
in
|
||||
{
|
||||
"inode/directory" = [ "nemo.desktop" ];
|
||||
|
||||
"application/pdf" = [ "org.gnome.Evince.desktop" ];
|
||||
|
||||
"text/*" = editor;
|
||||
"application/json" = editor;
|
||||
"text/html" = editor;
|
||||
"text/xml" = editor;
|
||||
"application/xml" = editor;
|
||||
"application/xhtml+xml" = editor;
|
||||
"application/xhtml_xml" = editor;
|
||||
"application/rdf+xml" = editor;
|
||||
"application/rss+xml" = editor;
|
||||
"application/x-extension-htm" = editor;
|
||||
"application/x-extension-html" = editor;
|
||||
"application/x-extension-shtml" = editor;
|
||||
"application/x-extension-xht" = editor;
|
||||
"application/x-extension-xhtml" = editor;
|
||||
|
||||
"x-scheme-handler/about" = browser;
|
||||
"x-scheme-handler/ftp" = browser;
|
||||
"x-scheme-handler/http" = browser;
|
||||
"x-scheme-handler/https" = browser;
|
||||
"x-scheme-handler/unknown" = browser;
|
||||
|
||||
"audio/*" = imageviewer;
|
||||
"video/*" = imageviewer;
|
||||
"image/*" = imageviewer;
|
||||
"image/gif" = imageviewer;
|
||||
"image/jpeg" = imageviewer;
|
||||
"image/png" = imageviewer;
|
||||
"image/webp" = imageviewer;
|
||||
};
|
||||
extraBookmarks =
|
||||
let
|
||||
homedir = config.my.home.home.homeDirectory;
|
||||
in
|
||||
[
|
||||
"file://${homedir}/NAS NAS"
|
||||
"file://${homedir}/NAS/imxyy_soope_ NAS imxyy_soope_"
|
||||
"file://${homedir}/NAS/imxyy_soope_/OS NAS OS"
|
||||
];
|
||||
};
|
||||
persist = {
|
||||
enable = true;
|
||||
homeDirs = [
|
||||
"Documents"
|
||||
"Downloads"
|
||||
"Videos"
|
||||
"Music"
|
||||
"Pictures"
|
||||
|
||||
"bin"
|
||||
"workspace"
|
||||
|
||||
".cache"
|
||||
".local/state"
|
||||
".local/share/Anki2"
|
||||
".local/share/shotwell"
|
||||
".local/share/cheat.sh"
|
||||
".local/share/Kingsoft"
|
||||
|
||||
".local/share/AyuGramDesktop"
|
||||
".local/share/TelegramDesktop"
|
||||
".config/Signal"
|
||||
".config/discord"
|
||||
".config/QQ"
|
||||
".xwechat"
|
||||
|
||||
".config/Kingsoft"
|
||||
".config/dconf"
|
||||
".config/gh"
|
||||
".config/pulse"
|
||||
".config/pip"
|
||||
".config/libreoffice"
|
||||
".config/sunshine"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
59
config/hosts/imxyy-nix-x16/net.nix
Normal file
59
config/hosts/imxyy-nix-x16/net.nix
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
sopsRoot,
|
||||
...
|
||||
}:
|
||||
{
|
||||
boot.kernelParams = [
|
||||
"biosdevname=0"
|
||||
"net.ifnames=0"
|
||||
];
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
sops.secrets.dae-imxyy-nix-x16 = {
|
||||
sopsFile = sopsRoot + /dae-imxyy-nix-x16.dae;
|
||||
format = "binary";
|
||||
};
|
||||
services.dae = {
|
||||
enable = true;
|
||||
configFile = config.sops.secrets.dae-imxyy-nix-x16.path;
|
||||
};
|
||||
systemd.services.dae.after = [ "sops-nix.service" ];
|
||||
sops.secrets.mihomo = {
|
||||
sopsFile = sopsRoot + /mihomo.yaml;
|
||||
format = "yaml";
|
||||
key = "";
|
||||
};
|
||||
systemd.services.mihomo.after = [ "sops-nix.service" ];
|
||||
services.mihomo = {
|
||||
enable = true;
|
||||
configFile = config.sops.secrets.mihomo.path;
|
||||
webui = pkgs.metacubexd;
|
||||
};
|
||||
|
||||
sops.secrets.et-imxyy-nix-x16 = {
|
||||
sopsFile = sopsRoot + /et-imxyy-nix-x16.toml;
|
||||
format = "binary";
|
||||
};
|
||||
environment.systemPackages = with pkgs; [
|
||||
easytier
|
||||
];
|
||||
systemd.services."easytier" = {
|
||||
enable = true;
|
||||
script = "${pkgs.easytier}/bin/easytier-core -c ${config.sops.secrets.et-imxyy-nix-x16.path}";
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 500 "always";
|
||||
RestartMaxDelaySec = lib.mkOverride 500 "1m";
|
||||
RestartSec = lib.mkOverride 500 "100ms";
|
||||
RestartSteps = lib.mkOverride 500 9;
|
||||
User = "root";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [
|
||||
"network.target"
|
||||
"sops-nix.service"
|
||||
];
|
||||
};
|
||||
}
|
||||
175
config/hosts/imxyy-nix-x16/nixos.nix
Normal file
175
config/hosts/imxyy-nix-x16/nixos.nix
Normal file
@@ -0,0 +1,175 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
username,
|
||||
sopsRoot,
|
||||
...
|
||||
}:
|
||||
{
|
||||
security.pam.loginLimits = [
|
||||
{
|
||||
domain = "*";
|
||||
type = "soft";
|
||||
item = "nofile";
|
||||
value = "524288";
|
||||
}
|
||||
];
|
||||
|
||||
boot.kernelParams = [
|
||||
"usbcore.autosuspend=-1" # Avoid usb autosuspend (for usb bluetooth adapter)
|
||||
];
|
||||
|
||||
boot.loader = {
|
||||
efi.canTouchEfiVariables = true;
|
||||
systemd-boot.enable = true;
|
||||
grub.enable = false;
|
||||
timeout = 0;
|
||||
};
|
||||
|
||||
hardware.graphics.enable = true;
|
||||
hardware.graphics.enable32Bit = true;
|
||||
|
||||
systemd.services.nix-daemon = {
|
||||
environment.TMPDIR = "/var/cache/nix";
|
||||
serviceConfig.CacheDirectory = "nix";
|
||||
};
|
||||
environment.variables.NIX_REMOTE = "daemon";
|
||||
|
||||
security.rtkit.enable = true;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = false;
|
||||
alsa.support32Bit = false;
|
||||
pulse.enable = false;
|
||||
audio.enable = false;
|
||||
};
|
||||
services.pulseaudio = {
|
||||
enable = true;
|
||||
support32Bit = true;
|
||||
package = pkgs.pulseaudioFull;
|
||||
extraConfig = ''
|
||||
load-module module-switch-on-connect
|
||||
unload-module module-suspend-on-idle
|
||||
'';
|
||||
};
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
settings = {
|
||||
General = {
|
||||
Enable = "Source,Sink,Media,Socket";
|
||||
Disable = "HeadSet";
|
||||
MultiProfile = "multiple";
|
||||
};
|
||||
};
|
||||
};
|
||||
users.extraUsers.${username}.extraGroups = [ "audio" ];
|
||||
|
||||
fonts = {
|
||||
enableDefaultPackages = false;
|
||||
fontDir.enable = true;
|
||||
|
||||
packages = with pkgs; [
|
||||
noto-fonts
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-emoji
|
||||
|
||||
jetbrains-mono
|
||||
|
||||
nerd-fonts.symbols-only
|
||||
];
|
||||
|
||||
fontconfig.defaultFonts = {
|
||||
serif = [
|
||||
"Noto Serif CJK SC"
|
||||
"Noto Serif"
|
||||
"Symbols Nerd Font"
|
||||
];
|
||||
sansSerif = [
|
||||
"Noto Sans CJK SC"
|
||||
"Noto Sans"
|
||||
"Symbols Nerd Font"
|
||||
];
|
||||
monospace = [
|
||||
"JetBrains Mono"
|
||||
"Noto Sans Mono CJK SC"
|
||||
"Symbols Nerd Font Mono"
|
||||
];
|
||||
emoji = [ "Noto Color Emoji" ];
|
||||
};
|
||||
};
|
||||
|
||||
services.printing.enable = true;
|
||||
|
||||
services.keyd = {
|
||||
enable = true;
|
||||
keyboards.default.settings = {
|
||||
main = {
|
||||
capslock = "overload(control, esc)";
|
||||
home = "end";
|
||||
};
|
||||
shift = {
|
||||
home = "home";
|
||||
};
|
||||
control = {
|
||||
delete = "print";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.gvfs.enable = true;
|
||||
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
# Forbid root login through SSH.
|
||||
PermitRootLogin = null;
|
||||
PasswordAuthentication = true;
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
pkgs.rclone
|
||||
];
|
||||
|
||||
sops.secrets.imxyy-nix-rclone = {
|
||||
sopsFile = sopsRoot + /imxyy-nix-rclone.conf;
|
||||
format = "binary";
|
||||
};
|
||||
fileSystems = {
|
||||
"/home/${username}/Nextcloud" = {
|
||||
device = "Nextcloud:";
|
||||
fsType = "rclone";
|
||||
options = [
|
||||
"nodev"
|
||||
"nofail"
|
||||
"allow_other"
|
||||
"args2env"
|
||||
"config=${config.sops.secrets.imxyy-nix-rclone.path}"
|
||||
"uid=1000"
|
||||
"gid=100"
|
||||
"rw"
|
||||
"no-check-certificate"
|
||||
"vfs-cache-mode=full"
|
||||
];
|
||||
};
|
||||
"/home/${username}/NAS" = {
|
||||
device = "//10.0.0.1/share";
|
||||
fsType = "cifs";
|
||||
options = [
|
||||
"username=nas"
|
||||
"password=nasshare"
|
||||
"x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s"
|
||||
"nodev"
|
||||
"nofail"
|
||||
"uid=1000"
|
||||
"gid=100"
|
||||
"vers=3"
|
||||
"rw"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
my.persist.nixosDirs = [ "/etc/NetworkManager/system-connections" ];
|
||||
}
|
||||
@@ -23,7 +23,7 @@ in
|
||||
verbose = false;
|
||||
};
|
||||
|
||||
kernelPackages = lib.mkForce pkgs.linuxKernel.packages.linux_zen;
|
||||
kernelPackages = lib.mkForce pkgs.linuxPackages_cachyos;
|
||||
kernelModules = [ "kvm-amd" ];
|
||||
|
||||
tmp.useTmpfs = true;
|
||||
@@ -36,6 +36,7 @@ in
|
||||
"resume_offset=6444127"
|
||||
];
|
||||
};
|
||||
services.scx.enable = true;
|
||||
|
||||
fileSystems."/" = {
|
||||
device = btrfs;
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
ayugram-desktop
|
||||
telegram-desktop
|
||||
signal-desktop
|
||||
cinny-desktop
|
||||
discord
|
||||
qq
|
||||
wechat
|
||||
|
||||
gnome-clocks
|
||||
|
||||
@@ -76,27 +76,6 @@
|
||||
scale = 1.25;
|
||||
};
|
||||
};
|
||||
spawn-at-startup = [
|
||||
{
|
||||
command = [
|
||||
"sh"
|
||||
"-c"
|
||||
"sleep 3; echo 'Xft.dpi: 120' | ${lib.getExe pkgs.xorg.xrdb} -merge"
|
||||
];
|
||||
}
|
||||
{
|
||||
command = [
|
||||
(toString (
|
||||
pkgs.writeShellScript "xsettingsd" ''
|
||||
while :
|
||||
do
|
||||
${lib.getExe pkgs.xsettingsd} -c ${pkgs.writeText "xsettingsd.conf" "Xft/DPI 122880\n"}
|
||||
done
|
||||
''
|
||||
))
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -127,7 +106,7 @@
|
||||
{
|
||||
"inode/directory" = [ "nemo.desktop" ];
|
||||
|
||||
"application/pdf" = [ "evince.desktop" ];
|
||||
"application/pdf" = [ "org.gnome.Evince.desktop" ];
|
||||
|
||||
"text/*" = editor;
|
||||
"application/json" = editor;
|
||||
@@ -175,53 +154,32 @@
|
||||
".android"
|
||||
"Android"
|
||||
|
||||
".ssh"
|
||||
|
||||
"bin"
|
||||
"workspace"
|
||||
"WineApps"
|
||||
"Virt"
|
||||
|
||||
".cache"
|
||||
".local/state"
|
||||
".local/share/Anki2"
|
||||
".local/share/dooit"
|
||||
".local/share/nvim"
|
||||
".local/share/shotwell"
|
||||
".local/share/Steam"
|
||||
".local/share/SteamOS"
|
||||
".local/share/Trash"
|
||||
".local/share/cheat.sh"
|
||||
".local/share/Kingsoft"
|
||||
".local/share/oss.krtirtho.spotube"
|
||||
|
||||
".local/share/AyuGramDesktop"
|
||||
".local/share/TelegramDesktop"
|
||||
".local/share/cinny"
|
||||
".config/Signal"
|
||||
".config/discord"
|
||||
".config/QQ"
|
||||
".xwechat"
|
||||
|
||||
".config/Kingsoft"
|
||||
".config/dconf"
|
||||
".config/gh"
|
||||
".config/pulse"
|
||||
".config/go-musicfox/db"
|
||||
".config/tmux/plugins"
|
||||
".config/pip"
|
||||
".config/obs-studio"
|
||||
".config/libreoffice"
|
||||
".config/Moonlight Game Streaming Project"
|
||||
".config/sunshine"
|
||||
];
|
||||
nixosDirs = [
|
||||
"/etc/ssh"
|
||||
];
|
||||
homeFiles = [
|
||||
".config/mpd/mpd.db" # requires bindfs
|
||||
".config/go-musicfox/cookie"
|
||||
".hmcl.json"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
environment.systemPackages = [ pkgs.easytier ];
|
||||
systemd.services."easytier" = {
|
||||
enable = true;
|
||||
script = "easytier-core -c ${config.sops.secrets.et-imxyy-nix.path}";
|
||||
script = "${pkgs.easytier}/bin/easytier-core -c ${config.sops.secrets.et-imxyy-nix.path}";
|
||||
serviceConfig = {
|
||||
Restart = lib.mkOverride 500 "always";
|
||||
RestartMaxDelaySec = lib.mkOverride 500 "1m";
|
||||
@@ -126,10 +126,5 @@
|
||||
"network.target"
|
||||
"sops-nix.service"
|
||||
];
|
||||
path = with pkgs; [
|
||||
easytier
|
||||
iproute2
|
||||
bash
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -160,19 +160,16 @@ in
|
||||
"Noto Serif CJK SC"
|
||||
"Noto Serif"
|
||||
"Symbols Nerd Font"
|
||||
"Noto Color Emoji"
|
||||
];
|
||||
sansSerif = [
|
||||
"Noto Sans CJK SC"
|
||||
"Noto Sans"
|
||||
"Symbols Nerd Font"
|
||||
"Noto Color Emoji"
|
||||
];
|
||||
monospace = [
|
||||
"JetBrains Mono"
|
||||
"Noto Sans Mono CJK SC"
|
||||
"Symbols Nerd Font Mono"
|
||||
"Noto Color Emoji"
|
||||
];
|
||||
emoji = [ "Noto Color Emoji" ];
|
||||
};
|
||||
@@ -198,8 +195,6 @@ in
|
||||
|
||||
services.gvfs.enable = true;
|
||||
|
||||
virtualisation.waydroid.enable = true;
|
||||
|
||||
programs.wireshark.enable = true;
|
||||
programs.wireshark.package = pkgs.wireshark;
|
||||
users.users.${username}.extraGroups = [ "wireshark" ];
|
||||
|
||||
394
flake.lock
generated
394
flake.lock
generated
@@ -100,18 +100,18 @@
|
||||
},
|
||||
"chaotic": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-schemas": "flake-schemas",
|
||||
"home-manager": "home-manager",
|
||||
"jovian": "jovian",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750098200,
|
||||
"narHash": "sha256-BtCFs/Ixxn6mEE2zGA/wIH+tR+psjobxs8SXVUyEiiI=",
|
||||
"lastModified": 1752141190,
|
||||
"narHash": "sha256-RHNq77Z84BtLTwyRtrBffm5V9006Dqw4vh3vrvULlxM=",
|
||||
"owner": "chaotic-cx",
|
||||
"repo": "nyx",
|
||||
"rev": "0d0115e6b3e2dce6d2260c7bb3fe894b1cc6b9a6",
|
||||
"rev": "ef0794b8e94eea166407141f7e92da75f6df925a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -128,11 +128,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749134809,
|
||||
"narHash": "sha256-1WErpDYTlMW/889Efe3OUM3uwt5w+EttjOGoBolBZvE=",
|
||||
"lastModified": 1750940343,
|
||||
"narHash": "sha256-qmc/jreM09MOwQ8dOa/+yyh99rU7TowSqo8L33VHfto=",
|
||||
"owner": "Bali10050",
|
||||
"repo": "Darkly",
|
||||
"rev": "c26d5e6a00c053850befd6c6af550797a5758dac",
|
||||
"rev": "77770c8d3c35f7ad39da2c57122c360096df0aac",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -166,38 +166,16 @@
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"chaotic",
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750056063,
|
||||
"narHash": "sha256-PGQjkjaj8XUa19tGZi0GHbnCzol4YHurA4pyifmhrs0=",
|
||||
"lastModified": 1752129689,
|
||||
"narHash": "sha256-0Xq5tZbvgZvxbbxv6kRHFuZE4Tq2za016NXh32nX0+Q=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "879b4b73522a78529778ce2eb6f3374d1016cf8f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749969540,
|
||||
"narHash": "sha256-jkSMD64ral4yBW0tiHgcZo6zyGsO0x0Aows0SEmWqPo=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "c0491d36bb321bc23021714e73369790e315984d",
|
||||
"rev": "70bb04a7de606a75ba0a2ee9d47b99802780b35d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -254,21 +232,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_3": {
|
||||
"locked": {
|
||||
"lastModified": 1747046372,
|
||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
@@ -338,11 +301,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743550720,
|
||||
"narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
|
||||
"lastModified": 1751413152,
|
||||
"narHash": "sha256-Tyw1RjYEsp5scoigs1384gIg6e0GoBVjms4aXFfRssQ=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "c621e8422220273271f52058f618c94e405bb0f5",
|
||||
"rev": "77826244401ea9de6e3bac47c2db46005e1f30b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -441,32 +404,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"git-hooks_2": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"stylix",
|
||||
"flake-compat"
|
||||
],
|
||||
"gitignore": "gitignore_2",
|
||||
"nixpkgs": [
|
||||
"stylix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1747372754,
|
||||
"narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=",
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "git-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -490,41 +427,19 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"stylix",
|
||||
"git-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gnome-shell": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1744584021,
|
||||
"narHash": "sha256-0RJ4mJzf+klKF4Fuoc8VN8dpQQtZnKksFmR2jhWE1Ew=",
|
||||
"lastModified": 1748186689,
|
||||
"narHash": "sha256-UaD7Y9f8iuLBMGHXeJlRu6U1Ggw5B9JnkFs3enZlap0=",
|
||||
"owner": "GNOME",
|
||||
"repo": "gnome-shell",
|
||||
"rev": "52c517c8f6c199a1d6f5118fae500ef69ea845ae",
|
||||
"rev": "8c88f917db0f1f0d80fa55206c863d3746fa18d0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "GNOME",
|
||||
"ref": "48.1",
|
||||
"ref": "48.2",
|
||||
"repo": "gnome-shell",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -556,6 +471,27 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"haumea": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1685133229,
|
||||
"narHash": "sha256-FePm/Gi9PBSNwiDFq3N+DWdfxFq0UKsVVTJS3cQPn94=",
|
||||
"owner": "nix-community",
|
||||
"repo": "haumea",
|
||||
"rev": "34dd58385092a23018748b50f9b23de6266dffc2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "v0.2.2",
|
||||
"repo": "haumea",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
@@ -564,11 +500,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750033262,
|
||||
"narHash": "sha256-TcFN78w6kPspxpbPsxW/8vQ1GAtY8Y3mjBaC+oB8jo4=",
|
||||
"lastModified": 1751824240,
|
||||
"narHash": "sha256-aDDC0CHTlL7QDKWWhdbEgVPK6KwWt+ca0QkmHYZxMzI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "66523b0efe93ce5b0ba96dcddcda15d36673c1f0",
|
||||
"rev": "fd9e55f5fac45a26f6169310afca64d56b681935",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -584,11 +520,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749944797,
|
||||
"narHash": "sha256-1l6ZW+2+LDQhYgE4fo2KsM2Ms3lY3ZXv0n6uKka2yMk=",
|
||||
"lastModified": 1752202894,
|
||||
"narHash": "sha256-knafgng4gCjZIUMyAEWjxxdols6n/swkYnbWr+oF+1w=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "c5f345153397f62170c18ded1ae1f0875201d49a",
|
||||
"rev": "fab659b346c0d4252208434c3c4b3983a4b38fec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -599,27 +535,6 @@
|
||||
}
|
||||
},
|
||||
"home-manager_3": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"stylix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748737919,
|
||||
"narHash": "sha256-5kvBbLYdp+n7Ftanjcs6Nv+UO6sBhelp6MIGJ9nWmjQ=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "5675a9686851d9626560052a032c4e14e533c1fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager_4": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zen",
|
||||
@@ -680,11 +595,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749627191,
|
||||
"narHash": "sha256-bUv8CDE6Uyxak4UkOvRjx5xj6+msEHSpYGeAjkuTnTs=",
|
||||
"lastModified": 1751529406,
|
||||
"narHash": "sha256-jwKDHyUycp678zDYa5Hyfq3msO73YMXdZPxp96dU7po=",
|
||||
"owner": "Jovian-Experiments",
|
||||
"repo": "Jovian-NixOS",
|
||||
"rev": "f31df4cb6b2eeef6cf0113edb687297be72a69df",
|
||||
"rev": "b2e5ce654e4f5bf8905c2e07a96dcf4966e6277d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -753,11 +668,11 @@
|
||||
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749890123,
|
||||
"narHash": "sha256-pRkyWFytGAMaHlrOJIYYEur8NRDe0kTfMIhRdTeasRQ=",
|
||||
"lastModified": 1752078530,
|
||||
"narHash": "sha256-TrRmlYdhWcadWvBpDjB9Xlry4uT4ZUIO46d+o5tjtCQ=",
|
||||
"owner": "sodiboo",
|
||||
"repo": "niri-flake",
|
||||
"rev": "8f39eb82488525728eda222b34e79b1ecf6d3f96",
|
||||
"rev": "d231d92313192d4d0c78d6ef04167fed9dee87cf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -769,16 +684,16 @@
|
||||
"niri-stable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1740117926,
|
||||
"narHash": "sha256-mTTHA0RAaQcdYe+9A3Jx77cmmyLFHmRoZdd8RpWa+m8=",
|
||||
"lastModified": 1748151941,
|
||||
"narHash": "sha256-z4viQZLgC2bIJ3VrzQnR+q2F3gAOEQpU1H5xHtX/2fs=",
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"rev": "b94a5db8790339cf9134873d8b490be69e02ac71",
|
||||
"rev": "8ba57fcf25d2fc9565131684a839d58703f1dae7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "YaLTeR",
|
||||
"ref": "v25.02",
|
||||
"ref": "v25.05.1",
|
||||
"repo": "niri",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -786,11 +701,11 @@
|
||||
"niri-unstable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1749797708,
|
||||
"narHash": "sha256-P5x0U6AW5Zn20bARv4D83d8XlNaWK1st9QwBfSe+Vfg=",
|
||||
"lastModified": 1750791124,
|
||||
"narHash": "sha256-F5iVU/hjoSHSSe0gllxm0PcAaseEtGNanYK5Ha3k2Tg=",
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"rev": "f3f6e79eeca8924ff9cfea4b30006e5b782bc93e",
|
||||
"rev": "37458d94b288945f6cfbd3c5c233f634d59f246c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -889,11 +804,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749574455,
|
||||
"narHash": "sha256-fm2/8KPOYvvIAnNVtjDlTt/My00lIbZQ+LMrfQIWVzs=",
|
||||
"lastModified": 1752199438,
|
||||
"narHash": "sha256-xSBMmGtq8K4Qv80TMqREmESCAsRLJRHAbFH2T/2Bf1Y=",
|
||||
"owner": "nix-community",
|
||||
"repo": "NixOS-WSL",
|
||||
"rev": "917af390377c573932d84b5e31dd9f2c1b5c0f09",
|
||||
"rev": "d34d9412556d3a896e294534ccd25f53b6822e80",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -904,11 +819,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1749794982,
|
||||
"narHash": "sha256-Kh9K4taXbVuaLC0IL+9HcfvxsSUx8dPB5s5weJcc9pc=",
|
||||
"lastModified": 1751984180,
|
||||
"narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ee930f9755f58096ac6e8ca94a1887e0534e2d81",
|
||||
"rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -932,11 +847,11 @@
|
||||
},
|
||||
"nixpkgs-master": {
|
||||
"locked": {
|
||||
"lastModified": 1749984179,
|
||||
"narHash": "sha256-N0GRVSCbIDnrFd+tGP9WkuXA4xt1+MeGRMnMr4JgkqU=",
|
||||
"lastModified": 1752206449,
|
||||
"narHash": "sha256-NVAbC/s4CupABWGXF8M9mDiVw/n0YCftxwc1KatVjDk=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f706574484e18612c3f08e63836906651e52b55f",
|
||||
"rev": "1bd4d0d4a678d48b63eb18f457d74df2fcee6c69",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -948,11 +863,11 @@
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1749984206,
|
||||
"narHash": "sha256-L4siXsrFIMgVkjd01JVAvzNOxYOq56BEY//IljBfObA=",
|
||||
"lastModified": 1752203688,
|
||||
"narHash": "sha256-uJ054F5PVGPu5SvLPMevhdY/EfK0X5DUyRtXhQYNUyo=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "f19b0fbf99317dd622b71e96ef6cde564972cd67",
|
||||
"rev": "a70a12c75e13aa546c20ce0fe515de634d52c39e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -964,11 +879,11 @@
|
||||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1749896453,
|
||||
"narHash": "sha256-6+AmSZBogyr1zbVc2k4IBcmY/Yt39mC4+cfZi0n/AAA=",
|
||||
"lastModified": 1752124863,
|
||||
"narHash": "sha256-5rWuf6RAlMDp/CAEuyYEz7ryxzgjxOCgUDhWEef864c=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ba48a1f6ce571455cb631dee840c6cd401ea4adb",
|
||||
"rev": "40de82b434526744da778ed53c742c1282d9e75e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1028,11 +943,11 @@
|
||||
},
|
||||
"nixpkgs_5": {
|
||||
"locked": {
|
||||
"lastModified": 1749794982,
|
||||
"narHash": "sha256-Kh9K4taXbVuaLC0IL+9HcfvxsSUx8dPB5s5weJcc9pc=",
|
||||
"lastModified": 1751984180,
|
||||
"narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ee930f9755f58096ac6e8ca94a1887e0534e2d81",
|
||||
"rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1045,15 +960,14 @@
|
||||
"nur": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts_3",
|
||||
"nixpkgs": "nixpkgs_5",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
"nixpkgs": "nixpkgs_5"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749983324,
|
||||
"narHash": "sha256-UCht45QsAY3lARXXoaJ4KaoVMtYUQbXuvaTaD5aN6m8=",
|
||||
"lastModified": 1752207112,
|
||||
"narHash": "sha256-dnVoQSGQqEGJQzS6iHAG95c0oFrezzBinwu1bDLj9J4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "NUR",
|
||||
"rev": "783b27b3f6593f7c82d9dce4869b1b83814f378e",
|
||||
"rev": "f166dc14862dfec043f9545e8291cc4402f8b866",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1071,15 +985,14 @@
|
||||
"nixpkgs": [
|
||||
"stylix",
|
||||
"nixpkgs"
|
||||
],
|
||||
"treefmt-nix": "treefmt-nix_2"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748730660,
|
||||
"narHash": "sha256-5LKmRYKdPuhm8j5GFe3AfrJL8dd8o57BQ34AGjJl1R0=",
|
||||
"lastModified": 1751906969,
|
||||
"narHash": "sha256-BSQAOdPnzdpOuCdAGSJmefSDlqmStFNScEnrWzSqKPw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "NUR",
|
||||
"rev": "2c0bc52fe14681e9ef60e3553888c4f086e46ecb",
|
||||
"rev": "ddb679f4131e819efe3bbc6457ba19d7ad116f25",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1095,11 +1008,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749982371,
|
||||
"narHash": "sha256-+lrgH2+Hwmoo13DvztAj6D+a4kiTl08LFFzpXcnPHAw=",
|
||||
"lastModified": 1752146885,
|
||||
"narHash": "sha256-ZJK989GL+bTCQSxbG8v8/7tHMCEl/FPovkeDBNyClQE=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "d9164578a2fc4f0721aaf61c2af8bc6c5cdb11b4",
|
||||
"revCount": 581,
|
||||
"rev": "d7079b75241c6e2b67f2429996fa7679ffc052e2",
|
||||
"revCount": 616,
|
||||
"type": "git",
|
||||
"url": "https://git.outfoxxed.me/outfoxxed/quickshell"
|
||||
},
|
||||
@@ -1112,8 +1025,9 @@
|
||||
"inputs": {
|
||||
"chaotic": "chaotic",
|
||||
"darkly": "darkly",
|
||||
"fenix": "fenix_2",
|
||||
"fenix": "fenix",
|
||||
"go-musicfox": "go-musicfox",
|
||||
"haumea": "haumea",
|
||||
"home-manager": "home-manager_2",
|
||||
"impermanence": "impermanence",
|
||||
"infuse": "infuse",
|
||||
@@ -1135,11 +1049,11 @@
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1750005282,
|
||||
"narHash": "sha256-VXLDkb1iOw7wWhgOgBMP9hTcpW6Eo399YbBif5hlxS8=",
|
||||
"lastModified": 1752086493,
|
||||
"narHash": "sha256-USpVUdiWXDfPoh+agbvoBQaBhg3ZdKZgHXo/HikMfVo=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "a207299344bf7797e4253c3f6130313e33c2ba6f",
|
||||
"rev": "6e3abe164b9036048dce1a3aa65a7e7e5200c0d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1149,20 +1063,24 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src_2": {
|
||||
"flake": false,
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"chaotic",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749877986,
|
||||
"narHash": "sha256-qEkNilgV6N4J0EhuPE8U4ispuMXgrRHAhi/BirBfC4I=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "fe5a925a74efde7ec6a7d3e388b946f96d36e760",
|
||||
"lastModified": 1751856221,
|
||||
"narHash": "sha256-/QE1eV0ckFvgRMcKjZqgdJDoXFNwSMepwRoBjaw2MCk=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "34cae4b56929c5b340e1c5b10d9a98a425b2a51e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -1173,11 +1091,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749592509,
|
||||
"narHash": "sha256-VunQzfZFA+Y6x3wYi2UE4DEQ8qKoAZZCnZPUlSoqC+A=",
|
||||
"lastModified": 1751606940,
|
||||
"narHash": "sha256-KrDPXobG7DFKTOteqdSVeL1bMVitDcy7otpVZWDE6MA=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "50754dfaa0e24e313c626900d44ef431f3210138",
|
||||
"rev": "3633fc4acf03f43b260244d94c71e9e14a2f6e0d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1193,11 +1111,8 @@
|
||||
"base16-helix": "base16-helix",
|
||||
"base16-vim": "base16-vim",
|
||||
"firefox-gnome-theme": "firefox-gnome-theme",
|
||||
"flake-compat": "flake-compat_3",
|
||||
"flake-parts": "flake-parts_4",
|
||||
"git-hooks": "git-hooks_2",
|
||||
"gnome-shell": "gnome-shell",
|
||||
"home-manager": "home-manager_3",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
@@ -1210,11 +1125,11 @@
|
||||
"tinted-zed": "tinted-zed"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749905587,
|
||||
"narHash": "sha256-sZpQM+InPCYwJQiTxs/PCCupwbYNaSCFi2Hvpl1/pOo=",
|
||||
"lastModified": 1752201883,
|
||||
"narHash": "sha256-SZVbQ4YThvYU50cJ4W4GNMy7/rVOJI8qmXqbEcRNsug=",
|
||||
"owner": "danth",
|
||||
"repo": "stylix",
|
||||
"rev": "77a8b26520f48305f3b1bacffaa8740dde8afa2a",
|
||||
"rev": "d395780b9c5c36f191b990b2021c71af180a1982",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1289,11 +1204,11 @@
|
||||
"tinted-schemes": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1748180480,
|
||||
"narHash": "sha256-7n0XiZiEHl2zRhDwZd/g+p38xwEoWtT0/aESwTMXWG4=",
|
||||
"lastModified": 1750770351,
|
||||
"narHash": "sha256-LI+BnRoFNRa2ffbe3dcuIRYAUcGklBx0+EcFxlHj0SY=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "schemes",
|
||||
"rev": "87d652edd26f5c0c99deda5ae13dfb8ece2ffe31",
|
||||
"rev": "5a775c6ffd6e6125947b393872cde95867d85a2a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1305,11 +1220,11 @@
|
||||
"tinted-tmux": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1748740859,
|
||||
"narHash": "sha256-OEM12bg7F4N5WjZOcV7FHJbqRI6jtCqL6u8FtPrlZz4=",
|
||||
"lastModified": 1751159871,
|
||||
"narHash": "sha256-UOHBN1fgHIEzvPmdNMHaDvdRMgLmEJh2hNmDrp3d3LE=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "tinted-tmux",
|
||||
"rev": "57d5f9683ff9a3b590643beeaf0364da819aedda",
|
||||
"rev": "bded5e24407cec9d01bd47a317d15b9223a1546c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1321,11 +1236,11 @@
|
||||
"tinted-zed": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1725758778,
|
||||
"narHash": "sha256-8P1b6mJWyYcu36WRlSVbuj575QWIFZALZMTg5ID/sM4=",
|
||||
"lastModified": 1751158968,
|
||||
"narHash": "sha256-ksOyv7D3SRRtebpXxgpG4TK8gZSKFc4TIZpR+C98jX8=",
|
||||
"owner": "tinted-theming",
|
||||
"repo": "base16-zed",
|
||||
"rev": "122c9e5c0e6f27211361a04fae92df97940eccf9",
|
||||
"rev": "86a470d94204f7652b906ab0d378e4231a5b3384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1334,62 +1249,19 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nur",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733222881,
|
||||
"narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "49717b5af6f80172275d47a418c9719a31a78b53",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"stylix",
|
||||
"nur",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733222881,
|
||||
"narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "49717b5af6f80172275d47a418c9719a31a78b53",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"xwayland-satellite-stable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1739246919,
|
||||
"narHash": "sha256-/hBM43/Gd0/tW+egrhlWgOIISeJxEs2uAOIYVpfDKeU=",
|
||||
"lastModified": 1748488455,
|
||||
"narHash": "sha256-IiLr1alzKFIy5tGGpDlabQbe6LV1c9ABvkH6T5WmyRI=",
|
||||
"owner": "Supreeeme",
|
||||
"repo": "xwayland-satellite",
|
||||
"rev": "44590a416d4a3e8220e19e29e0b6efe64a80315d",
|
||||
"rev": "3ba30b149f9eb2bbf42cf4758d2158ca8cceef73",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "Supreeeme",
|
||||
"ref": "v0.5.1",
|
||||
"ref": "v0.6",
|
||||
"repo": "xwayland-satellite",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -1397,11 +1269,11 @@
|
||||
"xwayland-satellite-unstable": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1749315541,
|
||||
"narHash": "sha256-bEik1BfVOFnWvtOrcOHluos/edJ8f+G2y1QySbt/0Ak=",
|
||||
"lastModified": 1751228685,
|
||||
"narHash": "sha256-MENtauGBhJ+kDeFaawvWGXaFG3Il6qQzjaP0RmtfM0k=",
|
||||
"owner": "Supreeeme",
|
||||
"repo": "xwayland-satellite",
|
||||
"rev": "da2ecb5be816de35e2efe23a408a1c49fe8b11ba",
|
||||
"rev": "557ebeb616e03d5e4a8049862bbbd1f02c6f020b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1412,17 +1284,17 @@
|
||||
},
|
||||
"zen": {
|
||||
"inputs": {
|
||||
"home-manager": "home-manager_4",
|
||||
"home-manager": "home-manager_3",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1749982886,
|
||||
"narHash": "sha256-v64Bz3dJGpoznDK55+6g58P5jjP9dLLPDMSVv6eCsRc=",
|
||||
"lastModified": 1752164817,
|
||||
"narHash": "sha256-LJFIx27IOUowLsJn5wci9mHZ4CesJsiAivQWDjnZPCc=",
|
||||
"owner": "0xc000022070",
|
||||
"repo": "zen-browser-flake",
|
||||
"rev": "e3ea161123e576ee049f1c8ec05d877ffbb7014c",
|
||||
"rev": "9193992c4c2c4349b4280ec2b49648cae208fe63",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
43
flake.nix
43
flake.nix
@@ -8,6 +8,7 @@
|
||||
nixpkgs-master.url = "github:nixos/nixpkgs/master";
|
||||
# nixpkgs.follows = "nixpkgs-stable";
|
||||
nixpkgs.follows = "nixpkgs-unstable";
|
||||
# nixpkgs.follows = "nixpkgs-master";
|
||||
|
||||
# Nyxpkgs
|
||||
chaotic.url = "github:chaotic-cx/nyx/nyxpkgs-unstable";
|
||||
@@ -56,6 +57,9 @@
|
||||
|
||||
infuse.url = "git+https://codeberg.org/amjoseph/infuse.nix";
|
||||
infuse.flake = false;
|
||||
|
||||
haumea.url = "github:nix-community/haumea/v0.2.2";
|
||||
haumea.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs =
|
||||
@@ -76,17 +80,29 @@
|
||||
}) (builtins.attrNames (builtins.readDir ./config/hosts))
|
||||
);
|
||||
|
||||
lib = nixpkgs.lib.extend (
|
||||
lib = (import ./lib/stdlib-extended.nix nixpkgs.lib).extend (
|
||||
final: prev: {
|
||||
inherit (inputs.home-manager.lib) hm;
|
||||
inherit infuse;
|
||||
my = import ./lib { lib = final; };
|
||||
haumea = inputs.haumea.lib;
|
||||
}
|
||||
);
|
||||
infuse = (import inputs.infuse { inherit (nixpkgs) lib; }).v1.infuse;
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (system: import ./pkgs nixpkgs.legacyPackages.${system});
|
||||
packages = forAllSystems (
|
||||
system:
|
||||
lib.haumea.load {
|
||||
src = ./pkgs;
|
||||
loader = [
|
||||
{
|
||||
matches = str: builtins.match ".*\\.nix" str != null;
|
||||
loader = _: path: nixpkgs.legacyPackages.${system}.callPackage path { };
|
||||
}
|
||||
];
|
||||
transformer = lib.haumea.transformers.liftDefault;
|
||||
}
|
||||
);
|
||||
|
||||
# workaround for "treefmt warning"
|
||||
formatter = forAllSystems (
|
||||
@@ -108,7 +124,9 @@
|
||||
}
|
||||
);
|
||||
|
||||
overlays = import ./overlays { inherit inputs infuse; };
|
||||
overlays = import ./overlays {
|
||||
inherit inputs lib;
|
||||
};
|
||||
|
||||
nixosConfigurations = forAllHosts (
|
||||
hostname:
|
||||
@@ -126,7 +144,7 @@
|
||||
withJemalloc = true;
|
||||
withQtSvg = true;
|
||||
withWayland = true;
|
||||
withPipewire = false;
|
||||
withPipewire = true;
|
||||
withPam = false;
|
||||
withX11 = false;
|
||||
withHyprland = false;
|
||||
@@ -167,11 +185,20 @@
|
||||
outputs
|
||||
hostname
|
||||
;
|
||||
|
||||
sopsRoot = ./secrets;
|
||||
flake = ./.;
|
||||
} // vars;
|
||||
modules = [
|
||||
./modules
|
||||
modules =
|
||||
(lib.umport {
|
||||
paths = [ ./modules ];
|
||||
exclude = [
|
||||
./modules/virt/types
|
||||
./modules/desktop/wm/niri/waybar
|
||||
];
|
||||
recursive = true;
|
||||
})
|
||||
++ [
|
||||
(lib.mkAliasOptionModule [ "my" "home" ] [ "home-manager" "users" vars.username ])
|
||||
./config/base.nix
|
||||
./config/hosts/${hostname}
|
||||
inputs.chaotic.nixosModules.default
|
||||
|
||||
@@ -9,5 +9,6 @@ in
|
||||
stdlib.extend (
|
||||
self: super: {
|
||||
my = mkMyLib { lib = self; };
|
||||
umport = import ./umport.nix { lib = self; };
|
||||
}
|
||||
)
|
||||
|
||||
48
lib/umport.nix
Normal file
48
lib/umport.nix
Normal file
@@ -0,0 +1,48 @@
|
||||
# This function is modified from:
|
||||
# https://github.com/yunfachi/nypkgs/blob/master/lib/umport.nix
|
||||
#
|
||||
# !!! REMOVING THIS NOTICE VIOLATES THE MIT LICENSE OF THE UMPORT PROJECT !!!
|
||||
# This notice must be retained in all copies of this function, including modified versions!
|
||||
# The MIT License can be found here:
|
||||
# https://github.com/yunfachi/nypkgs/blob/master/LICENSE
|
||||
{ lib, ... }:
|
||||
let
|
||||
umport =
|
||||
{
|
||||
path ? null,
|
||||
paths ? [ ],
|
||||
include ? [ ],
|
||||
exclude ? [ ],
|
||||
recursive ? true,
|
||||
}:
|
||||
with lib;
|
||||
with fileset;
|
||||
let
|
||||
excludedFiles = filter (path: pathIsRegularFile path) exclude;
|
||||
excludedDirs = filter (path: pathIsDirectory path) exclude;
|
||||
isExcluded =
|
||||
path:
|
||||
if elem path excludedFiles then
|
||||
true
|
||||
else
|
||||
(filter (excludedDir: lib.path.hasPrefix excludedDir path) excludedDirs) != [ ];
|
||||
in
|
||||
unique (
|
||||
(filter
|
||||
(file: pathIsRegularFile file && hasSuffix ".nix" (builtins.toString file) && !isExcluded file)
|
||||
(
|
||||
concatMap (
|
||||
_path:
|
||||
if recursive then
|
||||
toList _path
|
||||
else
|
||||
mapAttrsToList (
|
||||
name: type: _path + (if type == "directory" then "/${name}/default.nix" else "/${name}")
|
||||
) (builtins.readDir _path)
|
||||
) (unique (if path == null then paths else [ path ] ++ paths))
|
||||
)
|
||||
)
|
||||
++ (if recursive then concatMap (path: toList path) (unique include) else unique include)
|
||||
);
|
||||
in
|
||||
umport
|
||||
@@ -12,6 +12,7 @@ lib.my.makeSwitch {
|
||||
misc.enable = true;
|
||||
monitor.all.enable = true;
|
||||
shell.all.enable = true;
|
||||
vcs.all.enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./media
|
||||
./misc
|
||||
./monitor
|
||||
./shell
|
||||
];
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./ffmpeg.nix
|
||||
./mpd
|
||||
./cava
|
||||
./go-musicfox
|
||||
];
|
||||
}
|
||||
@@ -23,6 +23,13 @@ lib.my.makeSwitch {
|
||||
};
|
||||
|
||||
cli.media.mpd.enable = true;
|
||||
|
||||
persist.homeDirs = [
|
||||
".config/go-musicfox/db"
|
||||
];
|
||||
persist.homeFiles = [
|
||||
".config/go-musicfox/cookie"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,12 +14,15 @@ lib.my.makeSwitch {
|
||||
];
|
||||
config' = {
|
||||
my.home = {
|
||||
home.packages = with pkgs; [
|
||||
home.packages = with pkgs.stable; [
|
||||
mpd
|
||||
mpc-cli
|
||||
];
|
||||
services.mpris-proxy.enable = true;
|
||||
xdg.configFile."mpd/mpd.conf".source = ./mpd.conf;
|
||||
};
|
||||
my.persist.homeFiles = [
|
||||
".config/mpd/mpd.db"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
85
modules/cli/misc.nix
Normal file
85
modules/cli/misc.nix
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
username,
|
||||
userfullname,
|
||||
useremail,
|
||||
...
|
||||
}:
|
||||
lib.my.makeSwitch {
|
||||
inherit config;
|
||||
default = true;
|
||||
optionName = "misc command line tools";
|
||||
optionPath = [
|
||||
"cli"
|
||||
"misc"
|
||||
];
|
||||
config' = {
|
||||
environment.systemPackages = with pkgs; [
|
||||
vim
|
||||
wget
|
||||
git
|
||||
|
||||
file
|
||||
gnused
|
||||
gnutar
|
||||
|
||||
zip
|
||||
unzip
|
||||
xz
|
||||
p7zip
|
||||
unrar-free
|
||||
|
||||
pciutils
|
||||
usbutils
|
||||
|
||||
lsof
|
||||
|
||||
nmap
|
||||
traceroute
|
||||
tcping-go
|
||||
dnsutils
|
||||
|
||||
killall
|
||||
];
|
||||
|
||||
programs.dconf.enable = true;
|
||||
|
||||
my.home = {
|
||||
home.packages = with pkgs; [
|
||||
lsd
|
||||
fd
|
||||
neofetch
|
||||
fzf
|
||||
bat
|
||||
ripgrep
|
||||
|
||||
aria2
|
||||
socat
|
||||
];
|
||||
programs.tmux = {
|
||||
enable = true;
|
||||
extraConfig = "set-option -g mouse on";
|
||||
plugins = [
|
||||
(pkgs.tmuxPlugins.mkTmuxPlugin {
|
||||
pluginName = "tokyo-night-tmux";
|
||||
rtpFilePath = "tokyo-night.tmux";
|
||||
version = "legacy";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "janoamaral";
|
||||
repo = "tokyo-night-tmux";
|
||||
rev = "16469dfad86846138f594ceec780db27039c06cd";
|
||||
hash = "sha256-EKCgYan0WayXnkSb2fDJxookdBLW0XBKi2hf/YISwJE=";
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
programs.tealdeer = {
|
||||
enable = true;
|
||||
enableAutoUpdates = true;
|
||||
settings.updates.auto_update = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
set-option -g mouse on
|
||||
|
||||
set -g @plugin 'tmux-plugins/tpm'
|
||||
set -g @plugin 'tmux-plugins/tmux-sensible'
|
||||
|
||||
set -g @plugin "janoamaral/tokyo-night-tmux#legacy"
|
||||
|
||||
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
|
||||
run '~/.config/tmux/plugins/tpm/tpm'
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./btop
|
||||
];
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./zsh.nix
|
||||
];
|
||||
}
|
||||
190
modules/cli/shell/starship-preset.toml
Normal file
190
modules/cli/shell/starship-preset.toml
Normal file
@@ -0,0 +1,190 @@
|
||||
[aws]
|
||||
symbol = " "
|
||||
|
||||
[buf]
|
||||
symbol = " "
|
||||
|
||||
[bun]
|
||||
symbol = " "
|
||||
|
||||
[c]
|
||||
symbol = " "
|
||||
|
||||
[cpp]
|
||||
symbol = " "
|
||||
|
||||
[cmake]
|
||||
symbol = " "
|
||||
|
||||
[conda]
|
||||
symbol = " "
|
||||
|
||||
[crystal]
|
||||
symbol = " "
|
||||
|
||||
[dart]
|
||||
symbol = " "
|
||||
|
||||
[deno]
|
||||
symbol = " "
|
||||
|
||||
[directory]
|
||||
read_only = " "
|
||||
|
||||
[docker_context]
|
||||
symbol = " "
|
||||
|
||||
[elixir]
|
||||
symbol = " "
|
||||
|
||||
[elm]
|
||||
symbol = " "
|
||||
|
||||
[fennel]
|
||||
symbol = " "
|
||||
|
||||
[fossil_branch]
|
||||
symbol = " "
|
||||
|
||||
[gcloud]
|
||||
symbol = " "
|
||||
|
||||
[git_branch]
|
||||
symbol = " "
|
||||
|
||||
[git_commit]
|
||||
tag_symbol = ' '
|
||||
|
||||
[golang]
|
||||
symbol = " "
|
||||
|
||||
[guix_shell]
|
||||
symbol = " "
|
||||
|
||||
[haskell]
|
||||
symbol = " "
|
||||
|
||||
[haxe]
|
||||
symbol = " "
|
||||
|
||||
[hg_branch]
|
||||
symbol = " "
|
||||
|
||||
[hostname]
|
||||
ssh_symbol = " "
|
||||
|
||||
[java]
|
||||
symbol = " "
|
||||
|
||||
[julia]
|
||||
symbol = " "
|
||||
|
||||
[kotlin]
|
||||
symbol = " "
|
||||
|
||||
[lua]
|
||||
symbol = " "
|
||||
|
||||
[memory_usage]
|
||||
symbol = " "
|
||||
|
||||
[meson]
|
||||
symbol = " "
|
||||
|
||||
[nim]
|
||||
symbol = " "
|
||||
|
||||
[nix_shell]
|
||||
symbol = " "
|
||||
|
||||
[nodejs]
|
||||
symbol = " "
|
||||
|
||||
[ocaml]
|
||||
symbol = " "
|
||||
|
||||
[os.symbols]
|
||||
Alpaquita = " "
|
||||
Alpine = " "
|
||||
AlmaLinux = " "
|
||||
Amazon = " "
|
||||
Android = " "
|
||||
Arch = " "
|
||||
Artix = " "
|
||||
CachyOS = " "
|
||||
CentOS = " "
|
||||
Debian = " "
|
||||
DragonFly = " "
|
||||
Emscripten = " "
|
||||
EndeavourOS = " "
|
||||
Fedora = " "
|
||||
FreeBSD = " "
|
||||
Garuda = " "
|
||||
Gentoo = " "
|
||||
HardenedBSD = " "
|
||||
Illumos = " "
|
||||
Kali = " "
|
||||
Linux = " "
|
||||
Mabox = " "
|
||||
Macos = " "
|
||||
Manjaro = " "
|
||||
Mariner = " "
|
||||
MidnightBSD = " "
|
||||
Mint = " "
|
||||
NetBSD = " "
|
||||
NixOS = " "
|
||||
Nobara = " "
|
||||
OpenBSD = " "
|
||||
openSUSE = " "
|
||||
OracleLinux = " "
|
||||
Pop = " "
|
||||
Raspbian = " "
|
||||
Redhat = " "
|
||||
RedHatEnterprise = " "
|
||||
RockyLinux = " "
|
||||
Redox = " "
|
||||
Solus = " "
|
||||
SUSE = " "
|
||||
Ubuntu = " "
|
||||
Unknown = " "
|
||||
Void = " "
|
||||
Windows = " "
|
||||
|
||||
[package]
|
||||
symbol = " "
|
||||
|
||||
[perl]
|
||||
symbol = " "
|
||||
|
||||
[php]
|
||||
symbol = " "
|
||||
|
||||
[pijul_channel]
|
||||
symbol = " "
|
||||
|
||||
[pixi]
|
||||
symbol = " "
|
||||
|
||||
[python]
|
||||
symbol = " "
|
||||
|
||||
[rlang]
|
||||
symbol = " "
|
||||
|
||||
[ruby]
|
||||
symbol = " "
|
||||
|
||||
[rust]
|
||||
symbol = " "
|
||||
|
||||
[scala]
|
||||
symbol = " "
|
||||
|
||||
[swift]
|
||||
symbol = " "
|
||||
|
||||
[zig]
|
||||
symbol = " "
|
||||
|
||||
[gradle]
|
||||
symbol = " "
|
||||
@@ -36,6 +36,56 @@ lib.my.makeSwitch {
|
||||
fzf
|
||||
zoxide
|
||||
];
|
||||
programs.starship = {
|
||||
enable = true;
|
||||
settings = lib.recursiveUpdate (with builtins; fromTOML (readFile ./starship-preset.toml)) {
|
||||
add_newline = false;
|
||||
custom = {
|
||||
jj = {
|
||||
ignore_timeout = true;
|
||||
description = "The current jj status";
|
||||
when = "jj root";
|
||||
symbol = " ";
|
||||
command = ''
|
||||
jj log --revisions @ --no-graph --ignore-working-copy --color always --limit 1 --template '
|
||||
separate(" ",
|
||||
change_id.shortest(4),
|
||||
bookmarks,
|
||||
"|",
|
||||
concat(
|
||||
if(conflict, "💥"),
|
||||
if(divergent, "🚧"),
|
||||
if(hidden, "👻"),
|
||||
if(immutable, "🔒"),
|
||||
),
|
||||
raw_escape_sequence("\x1b[1;32m") ++ if(empty, "(empty)"),
|
||||
raw_escape_sequence("\x1b[1;32m") ++ coalesce(
|
||||
truncate_end(29, description.first_line(), "…"),
|
||||
"(no description set)",
|
||||
) ++ raw_escape_sequence("\x1b[0m"),
|
||||
)
|
||||
'
|
||||
'';
|
||||
};
|
||||
git_branch = {
|
||||
when = true;
|
||||
command = "jj root >/dev/null 2>&1 || starship module git_branch";
|
||||
description = "Only show git_branch if we're not in a jj repo";
|
||||
};
|
||||
git_status = {
|
||||
when = true;
|
||||
command = "jj root >/dev/null 2>&1 || starship module git_status";
|
||||
description = "Only show git_status if we're not in a jj repo";
|
||||
};
|
||||
};
|
||||
git_state.disabled = true;
|
||||
git_commit.disabled = true;
|
||||
git_metrics.disabled = true;
|
||||
git_branch.disabled = true;
|
||||
git_status.disabled = true;
|
||||
nix_shell.disabled = true;
|
||||
};
|
||||
};
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
dotDir = ".config/zsh";
|
||||
|
||||
16
modules/cli/vcs/all.nix
Normal file
16
modules/cli/vcs/all.nix
Normal file
@@ -0,0 +1,16 @@
|
||||
{ config, lib, ... }:
|
||||
lib.my.makeSwitch {
|
||||
inherit config;
|
||||
optionName = "all command line tools";
|
||||
optionPath = [
|
||||
"cli"
|
||||
"vcs"
|
||||
"all"
|
||||
];
|
||||
config' = {
|
||||
my.cli.vcs = {
|
||||
git.enable = true;
|
||||
jj.enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -7,49 +7,17 @@
|
||||
useremail,
|
||||
...
|
||||
}:
|
||||
lib.my.makeSwitch {
|
||||
lib.my.makeHomeProgramConfig {
|
||||
inherit config;
|
||||
default = true;
|
||||
optionName = "misc command line tools";
|
||||
programName = "git";
|
||||
optionPath = [
|
||||
"cli"
|
||||
"misc"
|
||||
"vcs"
|
||||
"git"
|
||||
];
|
||||
config' = {
|
||||
environment.systemPackages = with pkgs; [
|
||||
vim
|
||||
wget
|
||||
git
|
||||
|
||||
file
|
||||
gnused
|
||||
gnutar
|
||||
|
||||
zip
|
||||
unzip
|
||||
xz
|
||||
p7zip
|
||||
unrar-free
|
||||
|
||||
pciutils
|
||||
usbutils
|
||||
|
||||
lsof
|
||||
|
||||
nmap
|
||||
traceroute
|
||||
tcping-go
|
||||
dnsutils
|
||||
|
||||
killall
|
||||
];
|
||||
|
||||
programs.dconf.enable = true;
|
||||
|
||||
extraConfig = {
|
||||
my.home = {
|
||||
programs.home-manager.enable = true;
|
||||
programs.git = {
|
||||
enable = true;
|
||||
userName = "${userfullname}";
|
||||
userEmail = "${useremail}";
|
||||
signing = {
|
||||
@@ -69,31 +37,6 @@ lib.my.makeSwitch {
|
||||
programs.lazygit = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
lsd
|
||||
fd
|
||||
neofetch
|
||||
fzf
|
||||
bat
|
||||
ripgrep
|
||||
|
||||
aria2
|
||||
socat
|
||||
|
||||
nix-output-monitor
|
||||
|
||||
tmux
|
||||
|
||||
trash-cli
|
||||
|
||||
cht-sh
|
||||
|
||||
dooit
|
||||
|
||||
# translate-shell
|
||||
];
|
||||
xdg.configFile."tmux/tmux.conf".source = ./tmux.conf;
|
||||
};
|
||||
};
|
||||
}
|
||||
45
modules/cli/vcs/jj.nix
Normal file
45
modules/cli/vcs/jj.nix
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
username,
|
||||
userfullname,
|
||||
useremail,
|
||||
...
|
||||
}:
|
||||
lib.my.makeHomeProgramConfig {
|
||||
inherit config;
|
||||
programName = "jujutsu";
|
||||
optionPath = [
|
||||
"cli"
|
||||
"vcs"
|
||||
"jj"
|
||||
];
|
||||
extraConfig = {
|
||||
my.home = {
|
||||
programs.jujutsu = {
|
||||
settings = {
|
||||
user = {
|
||||
name = "${userfullname}";
|
||||
email = "${useremail}";
|
||||
};
|
||||
ui = {
|
||||
graph.style = "square";
|
||||
default-command = "status";
|
||||
};
|
||||
signing = {
|
||||
backend = "ssh";
|
||||
behavior = "own";
|
||||
key = "/home/${username}/.ssh/id_ed25519";
|
||||
backends.backends.ssh.allowed-signers =
|
||||
(pkgs.writeText "allowed_signers" ''
|
||||
imxyy1soope1@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOEFLUkyeaK8ZPPZdVNEmtx8zvoxi7xqS2Z6oxRBuUPO imxyy@imxyy-nix
|
||||
imxyy@imxyy.top ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOEFLUkyeaK8ZPPZdVNEmtx8zvoxi7xqS2Z6oxRBuUPO imxyy@imxyy-nix
|
||||
'').outPath;
|
||||
};
|
||||
};
|
||||
};
|
||||
home.packages = [ pkgs.lazyjj ];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./misc.nix
|
||||
./langs
|
||||
./editor
|
||||
];
|
||||
}
|
||||
@@ -11,6 +11,7 @@ lib.my.makeSwitch {
|
||||
my.coding.editor = {
|
||||
neovim.enable = true;
|
||||
vscode.enable = true;
|
||||
zed.enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./neovim
|
||||
./vscode
|
||||
];
|
||||
}
|
||||
@@ -54,5 +54,8 @@ lib.my.makeHomeProgramConfig {
|
||||
];
|
||||
};
|
||||
};
|
||||
my.persist.homeDirs = [
|
||||
".local/share/nvim"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,6 +62,9 @@ local extra_config = {
|
||||
},
|
||||
},
|
||||
},
|
||||
qmlls = {
|
||||
cmd = {"qmlls", "-E"}
|
||||
}
|
||||
}
|
||||
|
||||
local capabilities = require("cmp_nvim_lsp").default_capabilities()
|
||||
|
||||
@@ -179,6 +179,23 @@ local plugins = {
|
||||
require("telescope").setup(require("plugins.telescope"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
"ggandor/leap.nvim",
|
||||
dependencies = { "tpope/vim-repeat" },
|
||||
config = function()
|
||||
require("leap").set_default_mappings()
|
||||
-- Exclude whitespace and the middle of alphabetic words from preview:
|
||||
-- foobar[baaz] = quux
|
||||
-- ^----^^^--^^-^-^--^
|
||||
require('leap').opts.preview_filter = function(ch0, ch1, ch2)
|
||||
return not (
|
||||
ch1:match('%s') or
|
||||
ch0:match('%a') and ch1:match('%a') and ch2:match('%a')
|
||||
)
|
||||
end
|
||||
require('leap.user').set_repeat_keys('<enter>', '<backspace>')
|
||||
end
|
||||
},
|
||||
{
|
||||
"alexghergh/nvim-tmux-navigation",
|
||||
event = "VeryLazy",
|
||||
@@ -189,6 +206,7 @@ local plugins = {
|
||||
{
|
||||
"MeanderingProgrammer/render-markdown.nvim",
|
||||
dependencies = { "nvim-treesitter/nvim-treesitter", "nvim-tree/nvim-web-devicons" },
|
||||
event = "BufEnter *.md",
|
||||
opts = {},
|
||||
},
|
||||
{
|
||||
|
||||
20
modules/coding/editor/zed/default.nix
Normal file
20
modules/coding/editor/zed/default.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
lib.my.makeHomeProgramConfig {
|
||||
inherit config;
|
||||
programName = "zed-editor";
|
||||
optionPath = [
|
||||
"coding"
|
||||
"editor"
|
||||
"zed"
|
||||
];
|
||||
extraConfig = {
|
||||
my.persist.homeDirs = [
|
||||
".config/zed"
|
||||
".local/share/zed"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
#compdef gh
|
||||
|
||||
# zsh completion for gh -*- shell-script -*-
|
||||
|
||||
__gh_debug()
|
||||
{
|
||||
local file="$BASH_COMP_DEBUG_FILE"
|
||||
if [[ -n ${file} ]]; then
|
||||
echo "$*" >> "${file}"
|
||||
fi
|
||||
}
|
||||
|
||||
_gh()
|
||||
{
|
||||
local shellCompDirectiveError=1
|
||||
local shellCompDirectiveNoSpace=2
|
||||
local shellCompDirectiveNoFileComp=4
|
||||
local shellCompDirectiveFilterFileExt=8
|
||||
local shellCompDirectiveFilterDirs=16
|
||||
|
||||
local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace
|
||||
local -a completions
|
||||
|
||||
__gh_debug "\n========= starting completion logic =========="
|
||||
__gh_debug "CURRENT: ${CURRENT}, words[*]: ${words[*]}"
|
||||
|
||||
# The user could have moved the cursor backwards on the command-line.
|
||||
# We need to trigger completion from the $CURRENT location, so we need
|
||||
# to truncate the command-line ($words) up to the $CURRENT location.
|
||||
# (We cannot use $CURSOR as its value does not work when a command is an alias.)
|
||||
words=("${=words[1,CURRENT]}")
|
||||
__gh_debug "Truncated words[*]: ${words[*]},"
|
||||
|
||||
lastParam=${words[-1]}
|
||||
lastChar=${lastParam[-1]}
|
||||
__gh_debug "lastParam: ${lastParam}, lastChar: ${lastChar}"
|
||||
|
||||
# For zsh, when completing a flag with an = (e.g., gh -n=<TAB>)
|
||||
# completions must be prefixed with the flag
|
||||
setopt local_options BASH_REMATCH
|
||||
if [[ "${lastParam}" =~ '-.*=' ]]; then
|
||||
# We are dealing with a flag with an =
|
||||
flagPrefix="-P ${BASH_REMATCH}"
|
||||
fi
|
||||
|
||||
# Prepare the command to obtain completions
|
||||
requestComp="${words[1]} __complete ${words[2,-1]}"
|
||||
if [ "${lastChar}" = "" ]; then
|
||||
# If the last parameter is complete (there is a space following it)
|
||||
# We add an extra empty parameter so we can indicate this to the go completion code.
|
||||
__gh_debug "Adding extra empty parameter"
|
||||
requestComp="${requestComp} \"\""
|
||||
fi
|
||||
|
||||
__gh_debug "About to call: eval ${requestComp}"
|
||||
|
||||
# Use eval to handle any environment variables and such
|
||||
out=$(eval ${requestComp} 2>/dev/null)
|
||||
__gh_debug "completion output: ${out}"
|
||||
|
||||
# Extract the directive integer following a : from the last line
|
||||
local lastLine
|
||||
while IFS='\n' read -r line; do
|
||||
lastLine=${line}
|
||||
done < <(printf "%s\n" "${out[@]}")
|
||||
__gh_debug "last line: ${lastLine}"
|
||||
|
||||
if [ "${lastLine[1]}" = : ]; then
|
||||
directive=${lastLine[2,-1]}
|
||||
# Remove the directive including the : and the newline
|
||||
local suffix
|
||||
(( suffix=${#lastLine}+2))
|
||||
out=${out[1,-$suffix]}
|
||||
else
|
||||
# There is no directive specified. Leave $out as is.
|
||||
__gh_debug "No directive found. Setting do default"
|
||||
directive=0
|
||||
fi
|
||||
|
||||
__gh_debug "directive: ${directive}"
|
||||
__gh_debug "completions: ${out}"
|
||||
__gh_debug "flagPrefix: ${flagPrefix}"
|
||||
|
||||
if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then
|
||||
__gh_debug "Completion received error. Ignoring completions."
|
||||
return
|
||||
fi
|
||||
|
||||
local activeHelpMarker="_activeHelp_ "
|
||||
local endIndex=${#activeHelpMarker}
|
||||
local startIndex=$((${#activeHelpMarker}+1))
|
||||
local hasActiveHelp=0
|
||||
while IFS='\n' read -r comp; do
|
||||
# Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
|
||||
if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
|
||||
__gh_debug "ActiveHelp found: $comp"
|
||||
comp="${comp[$startIndex,-1]}"
|
||||
if [ -n "$comp" ]; then
|
||||
compadd -x "${comp}"
|
||||
__gh_debug "ActiveHelp will need delimiter"
|
||||
hasActiveHelp=1
|
||||
fi
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ -n "$comp" ]; then
|
||||
# If requested, completions are returned with a description.
|
||||
# The description is preceded by a TAB character.
|
||||
# For zsh's _describe, we need to use a : instead of a TAB.
|
||||
# We first need to escape any : as part of the completion itself.
|
||||
comp=${comp//:/\\:}
|
||||
|
||||
local tab="$(printf '\t')"
|
||||
comp=${comp//$tab/:}
|
||||
|
||||
__gh_debug "Adding completion: ${comp}"
|
||||
completions+=${comp}
|
||||
lastComp=$comp
|
||||
fi
|
||||
done < <(printf "%s\n" "${out[@]}")
|
||||
|
||||
# Add a delimiter after the activeHelp statements, but only if:
|
||||
# - there are completions following the activeHelp statements, or
|
||||
# - file completion will be performed (so there will be choices after the activeHelp)
|
||||
if [ $hasActiveHelp -eq 1 ]; then
|
||||
if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
|
||||
__gh_debug "Adding activeHelp delimiter"
|
||||
compadd -x "--"
|
||||
hasActiveHelp=0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
|
||||
__gh_debug "Activating nospace."
|
||||
noSpace="-S ''"
|
||||
fi
|
||||
|
||||
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
|
||||
# File extension filtering
|
||||
local filteringCmd
|
||||
filteringCmd='_files'
|
||||
for filter in ${completions[@]}; do
|
||||
if [ ${filter[1]} != '*' ]; then
|
||||
# zsh requires a glob pattern to do file filtering
|
||||
filter="\*.$filter"
|
||||
fi
|
||||
filteringCmd+=" -g $filter"
|
||||
done
|
||||
filteringCmd+=" ${flagPrefix}"
|
||||
|
||||
__gh_debug "File filtering command: $filteringCmd"
|
||||
_arguments '*:filename:'"$filteringCmd"
|
||||
elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
|
||||
# File completion for directories only
|
||||
local subdir
|
||||
subdir="${completions[1]}"
|
||||
if [ -n "$subdir" ]; then
|
||||
__gh_debug "Listing directories in $subdir"
|
||||
pushd "${subdir}" >/dev/null 2>&1
|
||||
else
|
||||
__gh_debug "Listing directories in ."
|
||||
fi
|
||||
|
||||
local result
|
||||
_arguments '*:dirname:_files -/'" ${flagPrefix}"
|
||||
result=$?
|
||||
if [ -n "$subdir" ]; then
|
||||
popd >/dev/null 2>&1
|
||||
fi
|
||||
return $result
|
||||
else
|
||||
__gh_debug "Calling _describe"
|
||||
if eval _describe "completions" completions $flagPrefix $noSpace; then
|
||||
__gh_debug "_describe found some completions"
|
||||
|
||||
# Return the success of having called _describe
|
||||
return 0
|
||||
else
|
||||
__gh_debug "_describe did not find completions."
|
||||
__gh_debug "Checking if we should do file completion."
|
||||
if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then
|
||||
__gh_debug "deactivating file completion"
|
||||
|
||||
# We must return an error code here to let zsh know that there were no
|
||||
# completions found by _describe; this is what will trigger other
|
||||
# matching algorithms to attempt to find completions.
|
||||
# For example zsh can match letters in the middle of words.
|
||||
return 1
|
||||
else
|
||||
# Perform file completion
|
||||
__gh_debug "Activating file completion"
|
||||
|
||||
# We must return the result of this command, so it must be the
|
||||
# last command, or else we must store its result to return it.
|
||||
_arguments '*:filename:_files'" ${flagPrefix}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# don't run the completion function when being source-ed or eval-ed
|
||||
if [ "$funcstack[1]" = "_gh" ]; then
|
||||
_gh
|
||||
fi
|
||||
@@ -15,6 +15,7 @@ lib.my.makeSwitch {
|
||||
python.enable = true;
|
||||
rust.enable = true;
|
||||
lua.enable = true;
|
||||
qml.enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./c.nix
|
||||
./go.nix
|
||||
./js.nix
|
||||
./rust.nix
|
||||
./python.nix
|
||||
./lua.nix
|
||||
];
|
||||
}
|
||||
@@ -24,6 +24,9 @@ lib.my.makeSwitch {
|
||||
prefix = ''${HOME}/.npm-global
|
||||
registry = https://registry.npmmirror.com
|
||||
'';
|
||||
programs.zsh.initContent = lib.mkAfter ''
|
||||
export PATH=$PATH:$HOME/.npm-global/bin
|
||||
'';
|
||||
};
|
||||
my.persist.homeDirs = [
|
||||
".npm"
|
||||
|
||||
20
modules/coding/langs/qml.nix
Normal file
20
modules/coding/langs/qml.nix
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
lib.my.makeSwitch {
|
||||
inherit config;
|
||||
optionName = "QML";
|
||||
optionPath = [
|
||||
"coding"
|
||||
"langs"
|
||||
"qml"
|
||||
];
|
||||
config' = {
|
||||
my.home.home.packages = with pkgs; [
|
||||
kdePackages.qtdeclarative
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -17,9 +17,6 @@ lib.my.makeSwitch {
|
||||
gnumake
|
||||
github-cli # gh
|
||||
];
|
||||
programs.zsh.initContent = ''
|
||||
source ${./github-cli-comp}
|
||||
'';
|
||||
programs.direnv.enable = true;
|
||||
};
|
||||
my.persist.homeDirs = [
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
lib,
|
||||
username,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
./cli
|
||||
./coding
|
||||
./virt
|
||||
./desktop
|
||||
./i18n
|
||||
./nix.nix
|
||||
./sops.nix
|
||||
./gpg.nix
|
||||
./time.nix
|
||||
./user.nix
|
||||
./xdg.nix
|
||||
./persist.nix
|
||||
./getty-autologin.nix
|
||||
|
||||
(lib.mkAliasOptionModule [ "my" "home" ] [ "home-manager" "users" username ])
|
||||
];
|
||||
}
|
||||
@@ -17,6 +17,7 @@ lib.my.makeSwitch {
|
||||
wm.all.enable = true;
|
||||
style.enable = true;
|
||||
quickshell.enable = true;
|
||||
wine.enable = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./firefox.nix
|
||||
./librewolf.nix
|
||||
./chromium.nix
|
||||
./zen.nix
|
||||
];
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./browser
|
||||
./gaming
|
||||
./media
|
||||
./notify
|
||||
./screencast
|
||||
./terminal
|
||||
./wm
|
||||
./style
|
||||
./quickshell
|
||||
];
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./minecraft.nix
|
||||
./steam.nix
|
||||
];
|
||||
}
|
||||
@@ -23,5 +23,8 @@ lib.my.makeSwitch {
|
||||
".minecraft"
|
||||
".local/share/hmcl"
|
||||
];
|
||||
my.persist.homeFiles = [
|
||||
".hmcl.json"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -20,5 +20,8 @@ lib.my.makeSwitch {
|
||||
gamescope
|
||||
];
|
||||
};
|
||||
my.persist.homeDirs = [
|
||||
".local/share/Steam"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./mpv.nix
|
||||
./shotwell.nix
|
||||
./thunderbird.nix
|
||||
./vlc.nix
|
||||
./spotify.nix
|
||||
./spotube.nix
|
||||
];
|
||||
}
|
||||
@@ -13,4 +13,9 @@ lib.my.makeHomePackageConfig {
|
||||
"media"
|
||||
"spotube"
|
||||
];
|
||||
extraConfig = {
|
||||
my.persist.homeDirs = [
|
||||
".local/share/oss.krtirtho.spotube"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./all.nix
|
||||
./dunst
|
||||
./swaync
|
||||
];
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import Quickshell
|
||||
import Quickshell.Services.UPower
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami
|
||||
|
||||
Rectangle {
|
||||
id: bat
|
||||
|
||||
Layout.preferredWidth: batIcon.width
|
||||
Layout.fillHeight: true
|
||||
color: 'transparent'
|
||||
|
||||
readonly property var battery: UPower.displayDevice
|
||||
readonly property int percentage: Math.round(battery.percentage * 100)
|
||||
property var size: height * 0.4
|
||||
|
||||
visible: battery.isLaptopBattery
|
||||
|
||||
Icon {
|
||||
id: batIcon
|
||||
anchors.centerIn: parent
|
||||
|
||||
implicitHeight: bat.size
|
||||
implicitWidth: bat.size
|
||||
|
||||
// This recolors the entire svg, instead of only classless components.
|
||||
// Hopefully in the future classes can be selected for recoloring.
|
||||
isMask: true
|
||||
color: 'white'
|
||||
|
||||
source: {
|
||||
const nearestTen = Math.round(bat.percentage / 10) * 10;
|
||||
const number = nearestTen.toString().padStart(2, "0");
|
||||
let charging;
|
||||
|
||||
if (bat.battery.state == UPowerDeviceState.Charging) {
|
||||
charging = "-charging";
|
||||
} else if (bat.battery.state.toString() == UPowerDeviceState.FullyCharged) {
|
||||
charging = "-charged";
|
||||
} else {
|
||||
charging = "";
|
||||
}
|
||||
|
||||
return Quickshell.iconPath(`battery-level-${number}${charging}-symbolic`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import "../../utils"
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
color: "transparent"
|
||||
implicitWidth: clockText.width
|
||||
|
||||
Text {
|
||||
id: clockText
|
||||
text: Time.time
|
||||
color: Colors.fg
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
color: "salmon"
|
||||
implicitWidth: mprisText.width
|
||||
|
||||
Text {
|
||||
id: mprisText
|
||||
text: "Mpris"
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import "../../utils"
|
||||
|
||||
Rectangle {
|
||||
id: resources
|
||||
|
||||
Layout.fillHeight: true
|
||||
color: "transparent"
|
||||
implicitWidth: rowLayout.width
|
||||
|
||||
property int valueSize: 8
|
||||
property int textSize: 6
|
||||
|
||||
property string valueColor: "white"
|
||||
property string textColor: "lightgray"
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
anchors.centerIn: parent
|
||||
|
||||
ColumnLayout {
|
||||
id: cpuColumn
|
||||
Label {
|
||||
color: textColor
|
||||
font.pointSize: textSize
|
||||
text: "CPU"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
Label {
|
||||
color: valueColor
|
||||
font.pointSize: valueSize
|
||||
text: Resources.cpu_percent + "%"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
color: textColor
|
||||
font.pointSize: textSize
|
||||
text: "MEM"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
Label {
|
||||
color: valueColor
|
||||
font.pointSize: valueSize
|
||||
text: Resources.mem_percent + "%"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import QtQuick
|
||||
|
||||
Text {
|
||||
renderType: Text.NativeRendering
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
color: "lightblue"
|
||||
implicitWidth: trayText.width
|
||||
|
||||
Text {
|
||||
id: trayText
|
||||
text: "Tray"
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
||||
Rectangle {
|
||||
id: ws
|
||||
|
||||
property bool hovered: false
|
||||
|
||||
Layout.preferredWidth: parent.height * 0.4
|
||||
Layout.preferredHeight: parent.height * 0.4
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
radius: height / 2
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onEntered: () => {
|
||||
ws.hovered = true;
|
||||
}
|
||||
onExited: () => {
|
||||
ws.hovered = false;
|
||||
}
|
||||
onClicked: () => console.log(`workspace ?`)
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import "../../../utils"
|
||||
import Quickshell.Hyprland
|
||||
|
||||
Rectangle {
|
||||
id: workspaces
|
||||
|
||||
color: 'transparent'
|
||||
|
||||
width: workspacesRow.implicitWidth
|
||||
Layout.fillHeight: true
|
||||
|
||||
RowLayout {
|
||||
id: workspacesRow
|
||||
|
||||
height: parent.height
|
||||
implicitWidth: (parent.height * 0.5 + spacing) * 2 - spacing
|
||||
anchors.centerIn: parent
|
||||
|
||||
spacing: height / 7
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: HyprlandUtils.maxWorkspace
|
||||
|
||||
Workspace {
|
||||
id: ws
|
||||
required property int index
|
||||
property HyprlandWorkspace currWorkspace: Hyprland.workspaces.values.find(e => e.id == index + 1) || null
|
||||
property bool nonexistent: currWorkspace === null
|
||||
property bool focused: index + 1 === Hyprland.focusedMonitor.activeWorkspace.id
|
||||
|
||||
Layout.preferredWidth: {
|
||||
if (focused) {
|
||||
return parent.height * 0.8;
|
||||
} else {
|
||||
return parent.height * 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
color: {
|
||||
if (nonexistent) {
|
||||
return Colors.bgBlur;
|
||||
} else {
|
||||
return Colors.monitorColors[Hyprland.monitors.values.indexOf(Hyprland.workspaces.values.find(e => e.id === index + 1).monitor)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import "./windows"
|
||||
import Quickshell // for ShellRoot and PanelWindow
|
||||
|
||||
ShellRoot {
|
||||
Bar {}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import Quickshell
|
||||
pragma Singleton
|
||||
|
||||
Singleton {
|
||||
property var bgBar: Qt.rgba(0, 0, 0, 0.21)
|
||||
property var bgBlur: Qt.rgba(0, 0, 0, 0.3)
|
||||
property var fg: "white"
|
||||
property list<var> monitorColors: ["#e06c75", "#e5c07b", "#98c379", "#61afef"]
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: hyprland
|
||||
|
||||
property list<HyprlandWorkspace> workspaces: sortWorkspaces(Hyprland.workspaces.values)
|
||||
property HyprlandWorkspace focusedWorkspace: Hyprland.focusedMonitor?.activeWorkspace
|
||||
property int maxWorkspace: findMaxId()
|
||||
|
||||
function sortWorkspaces(ws) {
|
||||
return [...ws].sort((a, b) => a?.id - b?.id);
|
||||
}
|
||||
|
||||
function switchWorkspace(w: int): void {
|
||||
console.log(`workspace: focus ${focusedWorkspace.id} -> ${w}`);
|
||||
Hyprland.dispatch(`workspace ${w}`);
|
||||
}
|
||||
|
||||
function findMaxId(): int {
|
||||
let num = hyprland.workspaces.length;
|
||||
return hyprland.workspaces[num - 1]?.id;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Hyprland
|
||||
function onRawEvent(event) {
|
||||
// console.log("EVENT NAME", event.name);
|
||||
// consow.wg("EVENT DATA", event.data);
|
||||
let eventName = event.name;
|
||||
|
||||
switch (eventName) {
|
||||
// Both of these are required in order to detect workspace changes
|
||||
// even when switching monitors.
|
||||
// case "workspacev2":
|
||||
// {
|
||||
// // hyprland.focusedWorkspace = Hyprland.focusedMonitor?.activeWorkspace;
|
||||
// console.log(`workspace: ${hyprland.focusedWorkspace.id}`);
|
||||
// console.log(`num workspaces ${hyprland.workspaces.length}`)
|
||||
// console.log(`num workspaces (real) ${Hyprland.workspaces.values.length}`)
|
||||
// break;
|
||||
// }
|
||||
// case "focusedmonv2":
|
||||
// {
|
||||
// // hyprland.focusedWorkspace = Hyprland.focusedMonitor?.activeWorkspace;
|
||||
// console.log(`workspace: ${hyprland.focusedWorkspace.id}`);
|
||||
// console.log(`num workspaces ${hyprland.workspaces.length}`)
|
||||
// console.log(`num workspaces (real) ${Hyprland.workspaces.values.length}`)
|
||||
// break;
|
||||
// }
|
||||
case "createworkspacev2":
|
||||
{
|
||||
hyprland.workspaces = hyprland.sortWorkspaces(Hyprland.workspaces.values);
|
||||
hyprland.maxWorkspace = findMaxId();
|
||||
}
|
||||
case "destroyworkspacev2":
|
||||
{
|
||||
hyprland.workspaces = hyprland.sortWorkspaces(Hyprland.workspaces.values);
|
||||
hyprland.maxWorkspace = findMaxId();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
property int cpu_percent
|
||||
property string cpu_freq
|
||||
property int mem_percent
|
||||
property string mem_used
|
||||
|
||||
Process {
|
||||
id: process_cpu_percent
|
||||
running: true
|
||||
command: ["sh", "-c", "top -bn1 | rg '%Cpu' | awk '{print 100-$8}'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => cpu_percent = Math.round(data)
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: process_cpu_freq
|
||||
running: true
|
||||
command: ["sh", "-c", "lscpu --parse=MHZ"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
// delete the first 4 lines (comments)
|
||||
const mhz = data.split("\n").slice(4);
|
||||
// compute mean frequency
|
||||
const freq = mhz.reduce((acc, e) => acc + Number(e), 0) / mhz.length;
|
||||
|
||||
cpu_freq = Math.round(freq) + " MHz";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: process_mem_percent
|
||||
running: true
|
||||
command: ["sh", "-c", "free | awk 'NR==2{print $3/$2*100}'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => mem_percent = Math.round(data)
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: process_mem_used
|
||||
running: true
|
||||
command: ["sh", "-c", "free --si -h | awk 'NR==2{print $3}'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => mem_used = data
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 2000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: () => {
|
||||
process_cpu_percent.running = true
|
||||
process_cpu_freq.running = true
|
||||
process_mem_percent.running = true
|
||||
process_mem_used.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
property var locale: Qt.locale()
|
||||
|
||||
function createDate(): string {
|
||||
let date = new Date();
|
||||
let hh = date.getHours().toString().padStart(2, 0);
|
||||
let mm = date.getMinutes().toString().padStart(2, 0)
|
||||
let weekday = locale.dayName(date.getDay(), Locale.ShortFormat)
|
||||
let month = locale.monthName(date.getMonth(), Locale.ShortFormat)
|
||||
let day = date.getDate()
|
||||
|
||||
return `${weekday} ${month} ${day} ${hh}:${mm}`
|
||||
}
|
||||
|
||||
property var time: createDate()
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: time = createDate()
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
//@ pragma NativeTextRendering
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import "../utils"
|
||||
import "../components/bar"
|
||||
import "../components/bar/workspaces"
|
||||
|
||||
Scope {
|
||||
PanelWindow {
|
||||
id: barWindow
|
||||
screen: Quickshell.screens[0]
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
height: 32
|
||||
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
id: bar
|
||||
anchors.fill: parent
|
||||
|
||||
color: Colors.bgBlur
|
||||
|
||||
// left
|
||||
// RowLayout {
|
||||
// id: barLeft
|
||||
//
|
||||
// anchors.bottom: parent.bottom
|
||||
// anchors.left: parent.left
|
||||
// anchors.top: parent.top
|
||||
//
|
||||
// anchors.leftMargin: height / 4
|
||||
// anchors.rightMargin: height / 4
|
||||
// spacing: height / 4
|
||||
//
|
||||
// Workspaces {}
|
||||
// }
|
||||
|
||||
// middle
|
||||
RowLayout {
|
||||
id: barMiddle
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
|
||||
anchors.leftMargin: height / 4
|
||||
anchors.rightMargin: height / 4
|
||||
spacing: height / 4
|
||||
|
||||
Mpris {}
|
||||
}
|
||||
|
||||
// right
|
||||
RowLayout {
|
||||
id: barRight
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
|
||||
anchors.leftMargin: height / 4
|
||||
anchors.rightMargin: height / 4
|
||||
spacing: height / 4
|
||||
|
||||
Tray {}
|
||||
Resources {}
|
||||
Battery {}
|
||||
Clock {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,12 @@
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
# FIXME: symlink
|
||||
homeDir = config.my.home.home.homeDirectory;
|
||||
quickshellDir = "${homeDir}/workspace/nixos-dotfiles/modules/desktop/quickshell/qml";
|
||||
quickshellTarget = "${homeDir}/.config/quickshell";
|
||||
in
|
||||
lib.my.makeSwitch {
|
||||
inherit config;
|
||||
default = false;
|
||||
@@ -13,17 +19,25 @@ lib.my.makeSwitch {
|
||||
"quickshell"
|
||||
];
|
||||
config' = {
|
||||
my.home = {
|
||||
home.packages = [ pkgs.quickshell ];
|
||||
home.sessionVariables.QML2_IMPORT_PATH = lib.concatStringsSep ":" [
|
||||
my.home.home = {
|
||||
packages = with pkgs; [
|
||||
quickshell
|
||||
qt6Packages.qt5compat
|
||||
libsForQt5.qt5.qtgraphicaleffects
|
||||
kdePackages.qtbase
|
||||
kdePackages.qtdeclarative
|
||||
|
||||
material-symbols
|
||||
material-icons
|
||||
];
|
||||
sessionVariables.QML2_IMPORT_PATH = lib.concatStringsSep ":" [
|
||||
"${pkgs.quickshell}/lib/qt-6/qml"
|
||||
"${pkgs.kdePackages.qtdeclarative}/lib/qt-6/qml"
|
||||
"${pkgs.kdePackages.kirigami.unwrapped}/lib/qt-6/qml"
|
||||
];
|
||||
xdg.configFile."quickshell" = {
|
||||
source = ./config;
|
||||
recursive = true;
|
||||
};
|
||||
activation.symlinkQuickshellAndFaceIcon = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
|
||||
ln -sfn "${quickshellDir}" "${quickshellTarget}"
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
2
modules/desktop/quickshell/qml/.gitignore
vendored
Normal file
2
modules/desktop/quickshell/qml/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/debug.log
|
||||
/quickshell.log
|
||||
BIN
modules/desktop/quickshell/qml/Assets/UserProfile.gif
Normal file
BIN
modules/desktop/quickshell/qml/Assets/UserProfile.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 37 KiB |
84
modules/desktop/quickshell/qml/Core/Corners.qml
Normal file
84
modules/desktop/quickshell/qml/Core/Corners.qml
Normal file
@@ -0,0 +1,84 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import "root:/Data" as Settings
|
||||
|
||||
// Concave corner shape component for rounded panel edges
|
||||
Shape {
|
||||
id: root
|
||||
|
||||
property string position: "topleft" // Corner position: topleft/topright/bottomleft/bottomright
|
||||
property real size: 1.0 // Scale multiplier for entire corner
|
||||
property int concaveWidth: 100 * size
|
||||
property int concaveHeight: 60 * size
|
||||
property int offsetX: -20
|
||||
property int offsetY: -20
|
||||
property color fillColor: Settings.Colors.bgColor
|
||||
property int arcRadius: 20 * size
|
||||
|
||||
// Position flags derived from position string
|
||||
property bool _isTop: position.includes("top")
|
||||
property bool _isLeft: position.includes("left")
|
||||
property bool _isRight: position.includes("right")
|
||||
property bool _isBottom: position.includes("bottom")
|
||||
|
||||
// Base coordinates for left corner shape
|
||||
property real _baseStartX: 30 * size
|
||||
property real _baseStartY: _isTop ? 20 * size : 0
|
||||
property real _baseLineX: 30 * size
|
||||
property real _baseLineY: _isTop ? 0 : 20 * size
|
||||
property real _baseArcX: 50 * size
|
||||
property real _baseArcY: _isTop ? 20 * size : 0
|
||||
|
||||
// Mirror coordinates for right corners
|
||||
property real _startX: _isRight ? (concaveWidth - _baseStartX) : _baseStartX
|
||||
property real _startY: _baseStartY
|
||||
property real _lineX: _isRight ? (concaveWidth - _baseLineX) : _baseLineX
|
||||
property real _lineY: _baseLineY
|
||||
property real _arcX: _isRight ? (concaveWidth - _baseArcX) : _baseArcX
|
||||
property real _arcY: _baseArcY
|
||||
|
||||
// Arc direction varies by corner to maintain proper concave shape
|
||||
property int _arcDirection: {
|
||||
if (_isTop && _isLeft)
|
||||
return PathArc.Counterclockwise;
|
||||
if (_isTop && _isRight)
|
||||
return PathArc.Clockwise;
|
||||
if (_isBottom && _isLeft)
|
||||
return PathArc.Clockwise;
|
||||
if (_isBottom && _isRight)
|
||||
return PathArc.Counterclockwise;
|
||||
return PathArc.Counterclockwise;
|
||||
}
|
||||
|
||||
width: concaveWidth
|
||||
height: concaveHeight
|
||||
// Position relative to parent based on corner type
|
||||
x: _isLeft ? offsetX : (parent ? parent.width - width + offsetX : 0)
|
||||
y: _isTop ? offsetY : (parent ? parent.height - height + offsetY : 0)
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
layer.enabled: true
|
||||
layer.samples: 4
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: 0
|
||||
fillColor: root.fillColor
|
||||
strokeColor: root.fillColor // Use same color as fill to eliminate artifacts
|
||||
|
||||
startX: root._startX
|
||||
startY: root._startY
|
||||
|
||||
PathLine {
|
||||
x: root._lineX
|
||||
y: root._lineY
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: root._arcX
|
||||
y: root._arcY
|
||||
radiusX: root.arcRadius
|
||||
radiusY: root.arcRadius
|
||||
useLargeArc: false
|
||||
direction: root._arcDirection
|
||||
}
|
||||
}
|
||||
}
|
||||
48
modules/desktop/quickshell/qml/Core/LoaderManager.qml
Normal file
48
modules/desktop/quickshell/qml/Core/LoaderManager.qml
Normal file
@@ -0,0 +1,48 @@
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
// Keep track of loaded components
|
||||
property var activeLoaders: ({})
|
||||
|
||||
// Dynamically load a QML component
|
||||
function load(componentUrl, parent, properties) {
|
||||
if (!activeLoaders[componentUrl]) {
|
||||
var loader = Qt.createQmlObject(`
|
||||
import QtQuick
|
||||
Loader {
|
||||
active: false
|
||||
asynchronous: true
|
||||
visible: false
|
||||
}
|
||||
`, parent);
|
||||
|
||||
loader.source = componentUrl;
|
||||
loader.active = true;
|
||||
|
||||
if (properties) {
|
||||
for (var prop in properties) {
|
||||
loader[prop] = properties[prop];
|
||||
}
|
||||
}
|
||||
|
||||
activeLoaders[componentUrl] = loader;
|
||||
}
|
||||
return activeLoaders[componentUrl];
|
||||
}
|
||||
|
||||
// Destroy and remove a loaded component
|
||||
function unload(componentUrl) {
|
||||
if (activeLoaders[componentUrl]) {
|
||||
activeLoaders[componentUrl].active = false;
|
||||
activeLoaders[componentUrl].destroy();
|
||||
delete activeLoaders[componentUrl];
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a component is loaded
|
||||
function isLoaded(componentUrl) {
|
||||
return !!activeLoaders[componentUrl];
|
||||
}
|
||||
}
|
||||
189
modules/desktop/quickshell/qml/Core/ProcessManager.qml
Normal file
189
modules/desktop/quickshell/qml/Core/ProcessManager.qml
Normal file
@@ -0,0 +1,189 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
|
||||
// System process and resource monitoring
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
// System resource metrics
|
||||
property real cpuUsage: 0
|
||||
property real ramUsage: 0
|
||||
property real totalRam: 0
|
||||
property real usedRam: 0
|
||||
|
||||
// System control processes
|
||||
property Process shutdownProcess: Process {
|
||||
command: ["shutdown", "-h", "now"]
|
||||
}
|
||||
|
||||
property Process rebootProcess: Process {
|
||||
command: ["reboot"]
|
||||
}
|
||||
|
||||
property Process lockProcess: Process {
|
||||
command: ["hyprlock"]
|
||||
}
|
||||
|
||||
property Process logoutProcess: Process {
|
||||
command: ["loginctl", "terminate-user", "$USER"]
|
||||
}
|
||||
|
||||
property Process pavucontrolProcess: Process {
|
||||
command: ["pavucontrol"]
|
||||
}
|
||||
|
||||
// Resource monitoring processes
|
||||
property Process cpuProcess: Process {
|
||||
command: ["sh", "-c", "grep '^cpu ' /proc/stat | awk '{usage=($2+$3+$4)*100/($2+$3+$4+$5)} END {print usage}'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
root.cpuUsage = parseFloat(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property Process ramProcess: Process {
|
||||
command: ["sh", "-c", "free -b | awk '/Mem:/ {print $2\" \"$3\" \"$3/$2*100}'"]
|
||||
stdout: SplitParser {
|
||||
onRead: data => {
|
||||
var parts = data.trim().split(/\s+/);
|
||||
if (parts.length >= 3) {
|
||||
root.totalRam = parseFloat(parts[0]) / (1024 * 1024 * 1024);
|
||||
root.usedRam = parseFloat(parts[1]) / (1024 * 1024 * 1024);
|
||||
root.ramUsage = parseFloat(parts[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Monitoring timers (start manually when needed)
|
||||
property Timer cpuTimer: Timer {
|
||||
interval: 30000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
cpuProcess.running = false;
|
||||
cpuProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
property Timer ramTimer: Timer {
|
||||
interval: 30000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
ramProcess.running = false;
|
||||
ramProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
// System control functions
|
||||
function shutdown() {
|
||||
console.log("Executing shutdown command");
|
||||
shutdownProcess.running = true;
|
||||
}
|
||||
|
||||
function reboot() {
|
||||
console.log("Executing reboot command");
|
||||
rebootProcess.running = true;
|
||||
}
|
||||
|
||||
function lock() {
|
||||
console.log("Executing lock command");
|
||||
lockProcess.running = true;
|
||||
}
|
||||
|
||||
function logout() {
|
||||
console.log("Executing logout command");
|
||||
logoutProcess.running = true;
|
||||
}
|
||||
|
||||
function openPavuControl() {
|
||||
console.log("Opening PavuControl");
|
||||
pavucontrolProcess.running = true;
|
||||
}
|
||||
|
||||
// Performance monitoring control
|
||||
function startMonitoring() {
|
||||
console.log("Starting system monitoring");
|
||||
cpuTimer.running = true;
|
||||
ramTimer.running = true;
|
||||
}
|
||||
|
||||
function stopMonitoring() {
|
||||
console.log("Stopping system monitoring");
|
||||
cpuTimer.running = false;
|
||||
ramTimer.running = false;
|
||||
}
|
||||
|
||||
function setMonitoringInterval(intervalMs) {
|
||||
console.log("Setting monitoring interval to", intervalMs, "ms");
|
||||
cpuTimer.interval = intervalMs;
|
||||
ramTimer.interval = intervalMs;
|
||||
}
|
||||
|
||||
function refreshSystemStats() {
|
||||
console.log("Manually refreshing system stats");
|
||||
cpuProcess.running = false;
|
||||
cpuProcess.running = true;
|
||||
ramProcess.running = false;
|
||||
ramProcess.running = true;
|
||||
}
|
||||
|
||||
// Process state queries
|
||||
function isShutdownRunning() {
|
||||
return shutdownProcess.running;
|
||||
}
|
||||
function isRebootRunning() {
|
||||
return rebootProcess.running;
|
||||
}
|
||||
function isLogoutRunning() {
|
||||
return logoutProcess.running;
|
||||
}
|
||||
function isPavuControlRunning() {
|
||||
return pavucontrolProcess.running;
|
||||
}
|
||||
function isMonitoringActive() {
|
||||
return cpuTimer.running && ramTimer.running;
|
||||
}
|
||||
|
||||
function stopPavuControl() {
|
||||
pavucontrolProcess.running = false;
|
||||
}
|
||||
|
||||
// Formatted output helpers
|
||||
function getCpuUsageFormatted() {
|
||||
return Math.round(cpuUsage) + "%";
|
||||
}
|
||||
|
||||
function getRamUsageFormatted() {
|
||||
return Math.round(ramUsage) + "% (" + usedRam.toFixed(1) + "GB/" + totalRam.toFixed(1) + "GB)";
|
||||
}
|
||||
|
||||
function getRamUsageSimple() {
|
||||
return Math.round(ramUsage) + "%";
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
// Stop all timers
|
||||
cpuTimer.running = false;
|
||||
ramTimer.running = false;
|
||||
|
||||
// Stop monitoring processes
|
||||
cpuProcess.running = false;
|
||||
ramProcess.running = false;
|
||||
|
||||
// Stop control processes if running
|
||||
if (shutdownProcess.running)
|
||||
shutdownProcess.running = false;
|
||||
if (rebootProcess.running)
|
||||
rebootProcess.running = false;
|
||||
if (lockProcess.running)
|
||||
lockProcess.running = false;
|
||||
if (logoutProcess.running)
|
||||
logoutProcess.running = false;
|
||||
if (pavucontrolProcess.running)
|
||||
pavucontrolProcess.running = false;
|
||||
}
|
||||
}
|
||||
38
modules/desktop/quickshell/qml/Data/MatugenManager.qml
Normal file
38
modules/desktop/quickshell/qml/Data/MatugenManager.qml
Normal file
@@ -0,0 +1,38 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
property var service: null
|
||||
|
||||
// Expose current colors from the service
|
||||
readonly property color primary: service?.colors?.raw?.primary || "#7ed7b8"
|
||||
readonly property color on_primary: service?.colors?.raw?.on_primary || "#00382a"
|
||||
readonly property color primary_container: service?.colors?.raw?.primary_container || "#454b03"
|
||||
readonly property color on_primary_container: service?.colors?.raw?.on_primary_container || "#e2e993"
|
||||
readonly property color secondary: service?.colors?.raw?.secondary || "#c8c9a6"
|
||||
readonly property color surface_bright: service?.colors?.raw?.surface_bright || "#373b30"
|
||||
readonly property bool hasColors: service?.isLoaded || false
|
||||
|
||||
// Expose all raw Material 3 colors for complete access
|
||||
readonly property var rawColors: service?.colors?.raw || ({})
|
||||
|
||||
function setService(matugenService) {
|
||||
service = matugenService;
|
||||
console.log("MatugenManager: Service registered");
|
||||
}
|
||||
|
||||
function reloadColors() {
|
||||
if (service && service.reloadColors) {
|
||||
console.log("MatugenManager: Triggering color reload");
|
||||
service.reloadColors();
|
||||
return true;
|
||||
} else {
|
||||
console.warn("MatugenManager: No service available for reload");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isAvailable() {
|
||||
return service !== null;
|
||||
}
|
||||
}
|
||||
315
modules/desktop/quickshell/qml/Data/Settings.qml
Normal file
315
modules/desktop/quickshell/qml/Data/Settings.qml
Normal file
@@ -0,0 +1,315 @@
|
||||
pragma Singleton
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: settings
|
||||
|
||||
// Prevent auto-saving during initial load
|
||||
property bool isLoading: true
|
||||
|
||||
// Settings persistence with atomic writes
|
||||
FileView {
|
||||
id: settingsFile
|
||||
path: "settings.json"
|
||||
blockWrites: true
|
||||
atomicWrites: true
|
||||
watchChanges: false
|
||||
|
||||
onLoaded: {
|
||||
settings.isLoading = true; // Disable auto-save during loading
|
||||
try {
|
||||
var content = JSON.parse(text());
|
||||
if (content) {
|
||||
// Load with fallback defaults
|
||||
settings.isDarkTheme = content.isDarkTheme ?? true;
|
||||
settings.currentTheme = content.currentTheme ?? (content.isDarkTheme !== false ? "oxocarbon_dark" : "oxocarbon_light");
|
||||
settings.useCustomAccent = content.useCustomAccent ?? false;
|
||||
settings.avatarSource = content.avatarSource ?? "/home/imxyy/Pictures/icon.jpg";
|
||||
settings.weatherLocation = content.weatherLocation ?? "Dinslaken";
|
||||
settings.useFahrenheit = content.useFahrenheit ?? false;
|
||||
settings.displayTime = content.displayTime ?? 6000;
|
||||
settings.videoPath = content.videoPath ?? "~/Videos/";
|
||||
settings.customDarkAccent = content.customDarkAccent ?? "#be95ff";
|
||||
settings.customLightAccent = content.customLightAccent ?? "#8a3ffc";
|
||||
settings.autoSwitchPlayer = content.autoSwitchPlayer ?? true;
|
||||
settings.alwaysShowPlayerDropdown = content.alwaysShowPlayerDropdown ?? true;
|
||||
settings.historyLimit = content.historyLimit ?? 25;
|
||||
settings.nightLightEnabled = content.nightLightEnabled ?? false;
|
||||
settings.nightLightWarmth = content.nightLightWarmth ?? 0.4;
|
||||
settings.nightLightAuto = content.nightLightAuto ?? false;
|
||||
settings.nightLightStartHour = content.nightLightStartHour ?? 20;
|
||||
settings.nightLightEndHour = content.nightLightEndHour ?? 6;
|
||||
settings.nightLightManualOverride = content.nightLightManualOverride ?? false;
|
||||
settings.nightLightManuallyEnabled = content.nightLightManuallyEnabled ?? false;
|
||||
settings.ignoredApps = content.ignoredApps ?? [];
|
||||
settings.workspaceBurstEnabled = content.workspaceBurstEnabled ?? true;
|
||||
settings.workspaceGlowEnabled = content.workspaceGlowEnabled ?? true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Error parsing user settings:", e);
|
||||
}
|
||||
// Re-enable auto-save after loading is complete
|
||||
settings.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
// User-configurable settings
|
||||
property string avatarSource: "/home/imxyy/Pictures/icon.jpg"
|
||||
property bool isDarkTheme: true // Keep for backwards compatibility
|
||||
property string currentTheme: "oxocarbon_dark" // New theme system
|
||||
property bool useCustomAccent: false // Whether to use custom accent colors
|
||||
property string weatherLocation: "Dinslaken"
|
||||
property bool useFahrenheit: false // Temperature unit setting
|
||||
property int displayTime: 6000 // Notification display time in ms
|
||||
property var ignoredApps: [] // Apps to ignore notifications from (case-insensitive)
|
||||
property int historyLimit: 25 // Notification history limit
|
||||
property string videoPath: "~/Videos/"
|
||||
property string customDarkAccent: "#be95ff"
|
||||
property string customLightAccent: "#8a3ffc"
|
||||
|
||||
// Music Player settings
|
||||
property bool autoSwitchPlayer: true
|
||||
property bool alwaysShowPlayerDropdown: true
|
||||
|
||||
// Night Light settings
|
||||
property bool nightLightEnabled: false
|
||||
property real nightLightWarmth: 0.4
|
||||
property bool nightLightAuto: false
|
||||
property int nightLightStartHour: 20 // 8 PM
|
||||
property int nightLightEndHour: 6 // 6 AM
|
||||
property bool nightLightManualOverride: false // Track manual user actions
|
||||
property bool nightLightManuallyEnabled: false // Track if user manually enabled it
|
||||
|
||||
// Animation settings
|
||||
property bool workspaceBurstEnabled: true
|
||||
property bool workspaceGlowEnabled: true
|
||||
|
||||
// UI constants
|
||||
readonly property real borderWidth: 9
|
||||
readonly property real cornerRadius: 20
|
||||
|
||||
signal settingsChanged
|
||||
|
||||
// Helper functions for managing ignored apps
|
||||
function addIgnoredApp(appName) {
|
||||
if (appName && appName.trim() !== "") {
|
||||
var trimmedName = appName.trim();
|
||||
// Case-insensitive check for existing apps
|
||||
var exists = false;
|
||||
for (var i = 0; i < ignoredApps.length; i++) {
|
||||
if (ignoredApps[i].toLowerCase() === trimmedName.toLowerCase()) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exists) {
|
||||
var newApps = ignoredApps.slice(); // Create a copy
|
||||
newApps.push(trimmedName);
|
||||
ignoredApps = newApps;
|
||||
console.log("Added ignored app:", trimmedName, "Current list:", ignoredApps);
|
||||
// Force save immediately (only if not loading)
|
||||
if (!isLoading) {
|
||||
saveSettings();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function removeIgnoredApp(appName) {
|
||||
var index = ignoredApps.indexOf(appName);
|
||||
if (index > -1) {
|
||||
var newApps = ignoredApps.slice(); // Create a copy
|
||||
newApps.splice(index, 1);
|
||||
ignoredApps = newApps;
|
||||
console.log("Removed ignored app:", appName, "Current list:", ignoredApps);
|
||||
// Force save immediately (only if not loading)
|
||||
if (!isLoading) {
|
||||
saveSettings();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
try {
|
||||
var content = {
|
||||
isDarkTheme: settings.isDarkTheme,
|
||||
currentTheme: settings.currentTheme,
|
||||
useCustomAccent: settings.useCustomAccent,
|
||||
avatarSource: settings.avatarSource,
|
||||
weatherLocation: settings.weatherLocation,
|
||||
useFahrenheit: settings.useFahrenheit,
|
||||
displayTime: settings.displayTime,
|
||||
videoPath: settings.videoPath,
|
||||
customDarkAccent: settings.customDarkAccent,
|
||||
customLightAccent: settings.customLightAccent,
|
||||
autoSwitchPlayer: settings.autoSwitchPlayer,
|
||||
alwaysShowPlayerDropdown: settings.alwaysShowPlayerDropdown,
|
||||
historyLimit: settings.historyLimit,
|
||||
nightLightEnabled: settings.nightLightEnabled,
|
||||
nightLightWarmth: settings.nightLightWarmth,
|
||||
nightLightAuto: settings.nightLightAuto,
|
||||
nightLightStartHour: settings.nightLightStartHour,
|
||||
nightLightEndHour: settings.nightLightEndHour,
|
||||
nightLightManualOverride: settings.nightLightManualOverride,
|
||||
nightLightManuallyEnabled: settings.nightLightManuallyEnabled,
|
||||
ignoredApps: settings.ignoredApps,
|
||||
workspaceBurstEnabled: settings.workspaceBurstEnabled,
|
||||
workspaceGlowEnabled: settings.workspaceGlowEnabled
|
||||
};
|
||||
var jsonContent = JSON.stringify(content, null, 4);
|
||||
settingsFile.setText(jsonContent);
|
||||
} catch (e) {
|
||||
console.log("Error saving user settings:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-save watchers (only save when not loading)
|
||||
onIsDarkThemeChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onCurrentThemeChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onUseCustomAccentChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onAvatarSourceChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onWeatherLocationChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onUseFahrenheitChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onDisplayTimeChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onHistoryLimitChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onVideoPathChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onCustomDarkAccentChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onCustomLightAccentChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onAutoSwitchPlayerChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onAlwaysShowPlayerDropdownChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onNightLightEnabledChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onNightLightWarmthChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onNightLightAutoChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onNightLightStartHourChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onNightLightEndHourChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onNightLightManualOverrideChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onNightLightManuallyEnabledChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onIgnoredAppsChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onWorkspaceBurstEnabledChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
onWorkspaceGlowEnabledChanged: {
|
||||
if (!isLoading) {
|
||||
settingsChanged();
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
settingsFile.reload();
|
||||
}
|
||||
}
|
||||
240
modules/desktop/quickshell/qml/Data/ThemeManager.qml
Normal file
240
modules/desktop/quickshell/qml/Data/ThemeManager.qml
Normal file
@@ -0,0 +1,240 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import "Themes" as Themes
|
||||
|
||||
Singleton {
|
||||
id: themeManager
|
||||
|
||||
// Import all theme definitions
|
||||
property var oxocarbon: Themes.Oxocarbon
|
||||
property var dracula: Themes.Dracula
|
||||
property var gruvbox: Themes.Gruvbox
|
||||
property var catppuccin: Themes.Catppuccin
|
||||
property var matugen: Themes.Matugen
|
||||
|
||||
// Available theme definitions
|
||||
readonly property var themes: ({
|
||||
"oxocarbon_dark": oxocarbon.dark,
|
||||
"oxocarbon_light": oxocarbon.light,
|
||||
"dracula_dark": dracula.dark,
|
||||
"dracula_light": dracula.light,
|
||||
"gruvbox_dark": gruvbox.dark,
|
||||
"gruvbox_light": gruvbox.light,
|
||||
"catppuccin_dark": catppuccin.dark,
|
||||
"catppuccin_light": catppuccin.light,
|
||||
"matugen_dark": matugen.dark,
|
||||
"matugen_light": matugen.light
|
||||
})
|
||||
|
||||
// Current theme selection - defaults to oxocarbon_dark if not set
|
||||
readonly property string currentThemeId: Settings.currentTheme || "oxocarbon_dark"
|
||||
readonly property var currentTheme: themes[currentThemeId] || themes["oxocarbon_dark"]
|
||||
|
||||
// Auto-update accents when Matugen colors change
|
||||
Connections {
|
||||
target: MatugenManager
|
||||
function onPrimaryChanged() {
|
||||
if (currentThemeId.startsWith("matugen_")) {
|
||||
updateMatugenAccents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to MatugenService signals for automatic accent updates
|
||||
Connections {
|
||||
target: MatugenManager.service
|
||||
function onMatugenColorsUpdated() {
|
||||
if (currentThemeId.startsWith("matugen_")) {
|
||||
console.log("ThemeManager: Received matugen colors update signal");
|
||||
updateMatugenAccents();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize currentTheme in settings if not present
|
||||
Component.onCompleted: {
|
||||
if (!Settings.currentTheme) {
|
||||
console.log("Initializing currentTheme in settings");
|
||||
Settings.currentTheme = "oxocarbon_dark";
|
||||
Settings.saveSettings();
|
||||
}
|
||||
|
||||
// Matugen theme is now self-contained with service-based colors
|
||||
console.log("Matugen theme initialized with service-based colors");
|
||||
|
||||
// Update accents if already using matugen theme
|
||||
if (currentThemeId.startsWith("matugen_")) {
|
||||
updateMatugenAccents();
|
||||
}
|
||||
}
|
||||
|
||||
// Custom accent colors (can be changed by user)
|
||||
property string customDarkAccent: Settings.customDarkAccent || "#be95ff"
|
||||
property string customLightAccent: Settings.customLightAccent || "#8a3ffc"
|
||||
|
||||
// Dynamic color properties based on current theme
|
||||
readonly property color base00: currentTheme.base00
|
||||
readonly property color base01: currentTheme.base01
|
||||
readonly property color base02: currentTheme.base02
|
||||
readonly property color base03: currentTheme.base03
|
||||
readonly property color base04: currentTheme.base04
|
||||
readonly property color base05: currentTheme.base05
|
||||
readonly property color base06: currentTheme.base06
|
||||
readonly property color base07: currentTheme.base07
|
||||
readonly property color base08: currentTheme.base08
|
||||
readonly property color base09: currentTheme.base09
|
||||
readonly property color base0A: currentTheme.base0A
|
||||
readonly property color base0B: currentTheme.base0B
|
||||
readonly property color base0C: currentTheme.base0C
|
||||
readonly property color base0D: currentTheme.base0D
|
||||
readonly property color base0E: Settings.useCustomAccent ? (currentTheme.type === "dark" ? customDarkAccent : customLightAccent) : currentTheme.base0E
|
||||
readonly property color base0F: currentTheme.base0F
|
||||
|
||||
// Common UI color mappings
|
||||
readonly property color bgColor: base00
|
||||
readonly property color bgLight: base01
|
||||
readonly property color bgLighter: base02
|
||||
readonly property color fgColor: base04
|
||||
readonly property color fgColorBright: base05
|
||||
readonly property color accentColor: base0E
|
||||
readonly property color accentColorBright: base0D
|
||||
readonly property color highlightBg: Qt.rgba(base0E.r, base0E.g, base0E.b, 0.15)
|
||||
readonly property color errorColor: base08
|
||||
readonly property color greenColor: base0B
|
||||
readonly property color redColor: base08
|
||||
|
||||
// Alternative semantic aliases for convenience
|
||||
readonly property color background: base00
|
||||
readonly property color panelBackground: base01
|
||||
readonly property color selection: base02
|
||||
readonly property color border: base03
|
||||
readonly property color secondaryText: base04
|
||||
readonly property color primaryText: base05
|
||||
readonly property color brightText: base06
|
||||
readonly property color brightestText: base07
|
||||
readonly property color error: base08
|
||||
readonly property color warning: base09
|
||||
readonly property color highlight: base0A
|
||||
readonly property color success: base0B
|
||||
readonly property color info: base0C
|
||||
readonly property color primary: base0D
|
||||
readonly property color accent: base0E
|
||||
readonly property color special: base0F
|
||||
|
||||
// UI styling constants
|
||||
readonly property real borderWidth: 9
|
||||
readonly property real cornerRadius: 20
|
||||
|
||||
// Color utility functions
|
||||
function withOpacity(color, opacity) {
|
||||
return Qt.rgba(color.r, color.g, color.b, opacity);
|
||||
}
|
||||
|
||||
function withHighlight(color) {
|
||||
return Qt.rgba(color.r, color.g, color.b, 0.15);
|
||||
}
|
||||
|
||||
// Theme management functions
|
||||
function setTheme(themeId) {
|
||||
if (themes[themeId]) {
|
||||
const previousThemeId = Settings.currentTheme;
|
||||
Settings.currentTheme = themeId;
|
||||
|
||||
// Check if switching between matugen light/dark modes
|
||||
if (themeId.startsWith("matugen_") && previousThemeId && previousThemeId.startsWith("matugen_")) {
|
||||
const newMode = themeId.includes("_light") ? "light" : "dark";
|
||||
const oldMode = previousThemeId.includes("_light") ? "light" : "dark";
|
||||
|
||||
if (newMode !== oldMode) {
|
||||
console.log(`🎨 Switching matugen from ${oldMode} to ${newMode} mode`);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-update accents for Matugen themes
|
||||
if (themeId.startsWith("matugen_")) {
|
||||
updateMatugenAccents();
|
||||
}
|
||||
|
||||
Settings.saveSettings();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Auto-update accent colors when using Matugen theme
|
||||
function updateMatugenAccents() {
|
||||
if (MatugenManager.isAvailable() && MatugenManager.hasColors) {
|
||||
// Get colors from the raw matugen palette
|
||||
const rawColors = MatugenManager.rawColors;
|
||||
|
||||
// Use primary for both dark and light themes - it's generated appropriately by matugen
|
||||
const accent = rawColors.primary;
|
||||
|
||||
// Debug log the colors we're using
|
||||
console.log("Raw colors available:", Object.keys(rawColors));
|
||||
console.log("Selected accent for both themes:", accent);
|
||||
|
||||
// Update custom accents - use the same accent for both
|
||||
setCustomAccent(accent, accent);
|
||||
|
||||
// Enable custom accents for Matugen theme
|
||||
Settings.useCustomAccent = true;
|
||||
Settings.saveSettings();
|
||||
|
||||
console.log("Auto-updated Matugen accents from service:", accent);
|
||||
} else {
|
||||
console.log("MatugenManager service not available or no colors loaded yet");
|
||||
}
|
||||
}
|
||||
|
||||
function getThemeList() {
|
||||
return Object.keys(themes).map(function (key) {
|
||||
return {
|
||||
id: key,
|
||||
name: themes[key].name,
|
||||
type: themes[key].type
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getDarkThemes() {
|
||||
return getThemeList().filter(function (theme) {
|
||||
return theme.type === "dark";
|
||||
});
|
||||
}
|
||||
|
||||
function getLightThemes() {
|
||||
return getThemeList().filter(function (theme) {
|
||||
return theme.type === "light";
|
||||
});
|
||||
}
|
||||
|
||||
function setCustomAccent(darkColor, lightColor) {
|
||||
customDarkAccent = darkColor;
|
||||
customLightAccent = lightColor;
|
||||
Settings.customDarkAccent = darkColor;
|
||||
Settings.customLightAccent = lightColor;
|
||||
Settings.saveSettings();
|
||||
}
|
||||
|
||||
function toggleCustomAccent() {
|
||||
Settings.useCustomAccent = !Settings.useCustomAccent;
|
||||
Settings.saveSettings();
|
||||
}
|
||||
|
||||
// Legacy function for backwards compatibility
|
||||
function toggleTheme() {
|
||||
// Switch between dark and light variants of current theme family
|
||||
var currentFamily = currentThemeId.replace(/_dark|_light/, "");
|
||||
var newThemeId = currentTheme.type === "dark" ? currentFamily + "_light" : currentFamily + "_dark";
|
||||
|
||||
// If the opposite variant doesn't exist, switch to oxocarbon
|
||||
if (!themes[newThemeId]) {
|
||||
newThemeId = currentTheme.type === "dark" ? "oxocarbon_light" : "oxocarbon_dark";
|
||||
}
|
||||
|
||||
setTheme(newThemeId);
|
||||
}
|
||||
}
|
||||
76
modules/desktop/quickshell/qml/Data/Themes/Catppuccin.qml
Normal file
76
modules/desktop/quickshell/qml/Data/Themes/Catppuccin.qml
Normal file
@@ -0,0 +1,76 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
readonly property var dark: ({
|
||||
name: "Catppuccin Mocha",
|
||||
type: "dark",
|
||||
base00: "#1e1e2e" // Base
|
||||
,
|
||||
base01: "#181825" // Mantle
|
||||
,
|
||||
base02: "#313244" // Surface0
|
||||
,
|
||||
base03: "#45475a" // Surface1
|
||||
,
|
||||
base04: "#585b70" // Surface2
|
||||
,
|
||||
base05: "#cdd6f4" // Text
|
||||
,
|
||||
base06: "#f5e0dc" // Rosewater
|
||||
,
|
||||
base07: "#b4befe" // Lavender
|
||||
,
|
||||
base08: "#f38ba8" // Red
|
||||
,
|
||||
base09: "#fab387" // Peach
|
||||
,
|
||||
base0A: "#f9e2af" // Yellow
|
||||
,
|
||||
base0B: "#a6e3a1" // Green
|
||||
,
|
||||
base0C: "#94e2d5" // Teal
|
||||
,
|
||||
base0D: "#89b4fa" // Blue
|
||||
,
|
||||
base0E: "#cba6f7" // Mauve
|
||||
,
|
||||
base0F: "#f2cdcd" // Flamingo
|
||||
})
|
||||
|
||||
readonly property var light: ({
|
||||
name: "Catppuccin Latte",
|
||||
type: "light",
|
||||
base00: "#eff1f5" // Base
|
||||
,
|
||||
base01: "#e6e9ef" // Mantle
|
||||
,
|
||||
base02: "#ccd0da" // Surface0
|
||||
,
|
||||
base03: "#bcc0cc" // Surface1
|
||||
,
|
||||
base04: "#acb0be" // Surface2
|
||||
,
|
||||
base05: "#4c4f69" // Text
|
||||
,
|
||||
base06: "#dc8a78" // Rosewater
|
||||
,
|
||||
base07: "#7287fd" // Lavender
|
||||
,
|
||||
base08: "#d20f39" // Red
|
||||
,
|
||||
base09: "#fe640b" // Peach
|
||||
,
|
||||
base0A: "#df8e1d" // Yellow
|
||||
,
|
||||
base0B: "#40a02b" // Green
|
||||
,
|
||||
base0C: "#179299" // Teal
|
||||
,
|
||||
base0D: "#1e66f5" // Blue
|
||||
,
|
||||
base0E: "#8839ef" // Mauve
|
||||
,
|
||||
base0F: "#dd7878" // Flamingo
|
||||
})
|
||||
}
|
||||
76
modules/desktop/quickshell/qml/Data/Themes/Dracula.qml
Normal file
76
modules/desktop/quickshell/qml/Data/Themes/Dracula.qml
Normal file
@@ -0,0 +1,76 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
readonly property var dark: ({
|
||||
name: "Dracula",
|
||||
type: "dark",
|
||||
base00: "#282a36" // Background
|
||||
,
|
||||
base01: "#44475a" // Current line
|
||||
,
|
||||
base02: "#565761" // Selection
|
||||
,
|
||||
base03: "#6272a4" // Comment
|
||||
,
|
||||
base04: "#6272a4" // Dark foreground
|
||||
,
|
||||
base05: "#f8f8f2" // Foreground
|
||||
,
|
||||
base06: "#f8f8f2" // Light foreground
|
||||
,
|
||||
base07: "#ffffff" // Light background
|
||||
,
|
||||
base08: "#ff5555" // Red
|
||||
,
|
||||
base09: "#ffb86c" // Orange
|
||||
,
|
||||
base0A: "#f1fa8c" // Yellow
|
||||
,
|
||||
base0B: "#50fa7b" // Green
|
||||
,
|
||||
base0C: "#8be9fd" // Cyan
|
||||
,
|
||||
base0D: "#bd93f9" // Blue
|
||||
,
|
||||
base0E: "#ff79c6" // Magenta
|
||||
,
|
||||
base0F: "#ffb86c" // Orange
|
||||
})
|
||||
|
||||
readonly property var light: ({
|
||||
name: "Dracula Light",
|
||||
type: "light",
|
||||
base00: "#f8f8f2" // Light background
|
||||
,
|
||||
base01: "#ffffff" // Lighter background
|
||||
,
|
||||
base02: "#e5e5e5" // Selection
|
||||
,
|
||||
base03: "#bfbfbf" // Comment
|
||||
,
|
||||
base04: "#6272a4" // Dark foreground
|
||||
,
|
||||
base05: "#282a36" // Dark text
|
||||
,
|
||||
base06: "#21222c" // Darker text
|
||||
,
|
||||
base07: "#191a21" // Darkest
|
||||
,
|
||||
base08: "#e74c3c" // Red (adjusted for light)
|
||||
,
|
||||
base09: "#f39c12" // Orange
|
||||
,
|
||||
base0A: "#f1c40f" // Yellow
|
||||
,
|
||||
base0B: "#27ae60" // Green
|
||||
,
|
||||
base0C: "#17a2b8" // Cyan
|
||||
,
|
||||
base0D: "#6c7ce0" // Blue
|
||||
,
|
||||
base0E: "#e91e63" // Magenta
|
||||
,
|
||||
base0F: "#f39c12" // Orange
|
||||
})
|
||||
}
|
||||
76
modules/desktop/quickshell/qml/Data/Themes/Gruvbox.qml
Normal file
76
modules/desktop/quickshell/qml/Data/Themes/Gruvbox.qml
Normal file
@@ -0,0 +1,76 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
readonly property var dark: ({
|
||||
name: "Gruvbox Dark",
|
||||
type: "dark",
|
||||
base00: "#282828" // Dark background
|
||||
,
|
||||
base01: "#3c3836" // Dark1
|
||||
,
|
||||
base02: "#504945" // Dark2
|
||||
,
|
||||
base03: "#665c54" // Dark3
|
||||
,
|
||||
base04: "#bdae93" // Light4
|
||||
,
|
||||
base05: "#d5c4a1" // Light3
|
||||
,
|
||||
base06: "#ebdbb2" // Light2
|
||||
,
|
||||
base07: "#fbf1c7" // Light1
|
||||
,
|
||||
base08: "#fb4934" // Red
|
||||
,
|
||||
base09: "#fe8019" // Orange
|
||||
,
|
||||
base0A: "#fabd2f" // Yellow
|
||||
,
|
||||
base0B: "#b8bb26" // Green
|
||||
,
|
||||
base0C: "#8ec07c" // Cyan
|
||||
,
|
||||
base0D: "#83a598" // Blue
|
||||
,
|
||||
base0E: "#d3869b" // Purple
|
||||
,
|
||||
base0F: "#d65d0e" // Brown
|
||||
})
|
||||
|
||||
readonly property var light: ({
|
||||
name: "Gruvbox Light",
|
||||
type: "light",
|
||||
base00: "#fbf1c7" // Light background
|
||||
,
|
||||
base01: "#ebdbb2" // Light1
|
||||
,
|
||||
base02: "#d5c4a1" // Light2
|
||||
,
|
||||
base03: "#bdae93" // Light3
|
||||
,
|
||||
base04: "#665c54" // Dark3
|
||||
,
|
||||
base05: "#504945" // Dark2
|
||||
,
|
||||
base06: "#3c3836" // Dark1
|
||||
,
|
||||
base07: "#282828" // Dark background
|
||||
,
|
||||
base08: "#cc241d" // Red
|
||||
,
|
||||
base09: "#d65d0e" // Orange
|
||||
,
|
||||
base0A: "#d79921" // Yellow
|
||||
,
|
||||
base0B: "#98971a" // Green
|
||||
,
|
||||
base0C: "#689d6a" // Cyan
|
||||
,
|
||||
base0D: "#458588" // Blue
|
||||
,
|
||||
base0E: "#b16286" // Purple
|
||||
,
|
||||
base0F: "#d65d0e" // Brown
|
||||
})
|
||||
}
|
||||
141
modules/desktop/quickshell/qml/Data/Themes/Matugen.qml
Normal file
141
modules/desktop/quickshell/qml/Data/Themes/Matugen.qml
Normal file
@@ -0,0 +1,141 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
// Reference to the MatugenService
|
||||
property var matugenService: null
|
||||
|
||||
// Debug helper to check service status
|
||||
function debugServiceStatus() {
|
||||
console.log("🔍 Debug: matugenService =", matugenService);
|
||||
console.log("🔍 Debug: matugenService.isLoaded =", matugenService ? matugenService.isLoaded : "N/A");
|
||||
console.log("🔍 Debug: matugenService.colorVersion =", matugenService ? matugenService.colorVersion : "N/A");
|
||||
console.log("🔍 Debug: condition result =", (matugenService && matugenService.isLoaded && matugenService.colorVersion >= 0));
|
||||
if (matugenService && matugenService.colors) {
|
||||
console.log("🔍 Debug: service.colors.dark =", JSON.stringify(matugenService.colors.dark));
|
||||
}
|
||||
}
|
||||
|
||||
// Map matugen colors to base16 scheme - using the service when available
|
||||
// The colorVersion dependency forces re-evaluation when colors update
|
||||
readonly property var dark: {
|
||||
debugServiceStatus();
|
||||
if (matugenService && matugenService.isLoaded && matugenService.colorVersion >= 0) {
|
||||
// Use service colors if available, or generate fallback if we have light colors
|
||||
return matugenService.colors.dark || {
|
||||
name: "Matugen Dark (Generated from Light)",
|
||||
type: "dark",
|
||||
// If we only have light colors, create dark fallback
|
||||
base00: "#141311",
|
||||
base01: "#1c1c19",
|
||||
base02: "#20201d",
|
||||
base03: "#2a2a27",
|
||||
base04: "#c9c7ba",
|
||||
base05: "#e5e2de",
|
||||
base06: "#31302e",
|
||||
base07: "#e5e2de",
|
||||
base08: "#ffb4ab",
|
||||
base09: "#b5ccb9",
|
||||
base0A: "#e4e5c1",
|
||||
base0B: "#c8c7b7",
|
||||
base0C: "#c8c9a6",
|
||||
base0D: "#c8c9a6",
|
||||
base0E: "#47483b",
|
||||
base0F: "#000000"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
name: "Matugen Dark",
|
||||
type: "dark",
|
||||
// Updated fallback colors to match current quickshell-colors.qml
|
||||
base00: "#141311",
|
||||
base01: "#1c1c19",
|
||||
base02: "#20201d",
|
||||
base03: "#2a2a27",
|
||||
base04: "#c9c7ba",
|
||||
base05: "#e5e2de",
|
||||
base06: "#31302e",
|
||||
base07: "#e5e2de",
|
||||
base08: "#ffb4ab",
|
||||
base09: "#b5ccb9",
|
||||
base0A: "#e4e5c1",
|
||||
base0B: "#c8c7b7",
|
||||
base0C: "#c8c9a6",
|
||||
base0D: "#c8c9a6",
|
||||
base0E: "#47483b",
|
||||
base0F: "#000000"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var light: {
|
||||
if (matugenService && matugenService.isLoaded && matugenService.colorVersion >= 0) {
|
||||
// Use service colors if available, or generate fallback if we have dark colors
|
||||
return matugenService.colors.light || {
|
||||
name: "Matugen Light (Generated from Dark)",
|
||||
type: "light",
|
||||
// If we only have dark colors, create light fallback
|
||||
base00: "#ffffff",
|
||||
base01: "#f5f5f5",
|
||||
base02: "#e8e8e8",
|
||||
base03: "#d0d0d0",
|
||||
base04: "#666666",
|
||||
base05: "#1a1a1a",
|
||||
base06: "#000000",
|
||||
base07: "#ffffff",
|
||||
base08: "#d32f2f",
|
||||
base09: "#7b1fa2",
|
||||
base0A: "#f57c00",
|
||||
base0B: "#388e3c",
|
||||
base0C: "#0097a7",
|
||||
base0D: "#1976d2",
|
||||
base0E: "#5e35b1",
|
||||
base0F: "#000000"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
name: "Matugen Light",
|
||||
type: "light",
|
||||
// Updated fallback colors based on current colors
|
||||
base00: "#ffffff",
|
||||
base01: "#f5f5f5",
|
||||
base02: "#e8e8e8",
|
||||
base03: "#d0d0d0",
|
||||
base04: "#666666",
|
||||
base05: "#1a1a1a",
|
||||
base06: "#000000",
|
||||
base07: "#ffffff",
|
||||
base08: "#d32f2f",
|
||||
base09: "#7b1fa2",
|
||||
base0A: "#f57c00",
|
||||
base0B: "#388e3c",
|
||||
base0C: "#0097a7",
|
||||
base0D: "#1976d2",
|
||||
base0E: "#5e35b1",
|
||||
base0F: "#000000"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Direct access to primary colors for accent updates
|
||||
readonly property color primary: (matugenService && matugenService.getColor && matugenService.colorVersion >= 0) ? matugenService.getColor("primary") || "#c8c9a6" : "#c8c9a6"
|
||||
readonly property color on_primary: (matugenService && matugenService.getColor && matugenService.colorVersion >= 0) ? matugenService.getColor("on_primary") || "#303219" : "#303219"
|
||||
|
||||
// Function to set the service reference
|
||||
function setMatugenService(service) {
|
||||
matugenService = service;
|
||||
console.log("🔌 MatugenService connected to theme:", service);
|
||||
|
||||
// Connect to service signals for automatic updates
|
||||
if (service) {
|
||||
service.matugenColorsUpdated.connect(function () {
|
||||
console.log("🎨 Matugen colors updated in theme (version " + service.colorVersion + ")");
|
||||
debugServiceStatus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Matugen theme loaded, waiting for MatugenService connection");
|
||||
}
|
||||
}
|
||||
76
modules/desktop/quickshell/qml/Data/Themes/Oxocarbon.qml
Normal file
76
modules/desktop/quickshell/qml/Data/Themes/Oxocarbon.qml
Normal file
@@ -0,0 +1,76 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
readonly property var dark: ({
|
||||
name: "Oxocarbon Dark",
|
||||
type: "dark",
|
||||
base00: "#161616" // OLED-friendly background
|
||||
,
|
||||
base01: "#262626" // Surface 1
|
||||
,
|
||||
base02: "#393939" // Surface 2
|
||||
,
|
||||
base03: "#525252" // Surface 3
|
||||
,
|
||||
base04: "#6f6f6f" // Text secondary
|
||||
,
|
||||
base05: "#c6c6c6" // Text primary
|
||||
,
|
||||
base06: "#e0e0e0" // Text on color
|
||||
,
|
||||
base07: "#f4f4f4" // Text inverse
|
||||
,
|
||||
base08: "#ff7eb6" // Red (pink)
|
||||
,
|
||||
base09: "#ee5396" // Magenta
|
||||
,
|
||||
base0A: "#42be65" // Green
|
||||
,
|
||||
base0B: "#be95ff" // Purple
|
||||
,
|
||||
base0C: "#3ddbd9" // Cyan
|
||||
,
|
||||
base0D: "#78a9ff" // Blue
|
||||
,
|
||||
base0E: "#be95ff" // Purple (accent)
|
||||
,
|
||||
base0F: "#08bdba" // Teal
|
||||
})
|
||||
|
||||
readonly property var light: ({
|
||||
name: "Oxocarbon Light",
|
||||
type: "light",
|
||||
base00: "#f4f4f4" // Light background
|
||||
,
|
||||
base01: "#ffffff" // Surface 1
|
||||
,
|
||||
base02: "#e0e0e0" // Surface 2
|
||||
,
|
||||
base03: "#c6c6c6" // Surface 3
|
||||
,
|
||||
base04: "#525252" // Text secondary
|
||||
,
|
||||
base05: "#262626" // Text primary
|
||||
,
|
||||
base06: "#161616" // Text on color
|
||||
,
|
||||
base07: "#000000" // Text inverse
|
||||
,
|
||||
base08: "#da1e28" // Red
|
||||
,
|
||||
base09: "#d12771" // Magenta
|
||||
,
|
||||
base0A: "#198038" // Green
|
||||
,
|
||||
base0B: "#8a3ffc" // Purple
|
||||
,
|
||||
base0C: "#007d79" // Cyan
|
||||
,
|
||||
base0D: "#0f62fe" // Blue
|
||||
,
|
||||
base0E: "#8a3ffc" // Purple (accent)
|
||||
,
|
||||
base0F: "#005d5d" // Teal
|
||||
})
|
||||
}
|
||||
60
modules/desktop/quickshell/qml/Data/quickshell-colors.qml
Normal file
60
modules/desktop/quickshell/qml/Data/quickshell-colors.qml
Normal file
@@ -0,0 +1,60 @@
|
||||
pragma Singleton
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
readonly property color background: "#13140c"
|
||||
readonly property color error: "#ffb4ab"
|
||||
readonly property color error_container: "#93000a"
|
||||
readonly property color inverse_on_surface: "#313128"
|
||||
readonly property color inverse_primary: "#5d631c"
|
||||
readonly property color inverse_surface: "#e5e3d6"
|
||||
readonly property color on_background: "#e5e3d6"
|
||||
readonly property color on_error: "#690005"
|
||||
readonly property color on_error_container: "#ffdad6"
|
||||
readonly property color on_primary: "#2f3300"
|
||||
readonly property color on_primary_container: "#e2e993"
|
||||
readonly property color on_primary_fixed: "#1b1d00"
|
||||
readonly property color on_primary_fixed_variant: "#454b03"
|
||||
readonly property color on_secondary: "#30321a"
|
||||
readonly property color on_secondary_container: "#e4e5c1"
|
||||
readonly property color on_secondary_fixed: "#1b1d07"
|
||||
readonly property color on_secondary_fixed_variant: "#47492e"
|
||||
readonly property color on_surface: "#e5e3d6"
|
||||
readonly property color on_surface_variant: "#c8c7b7"
|
||||
readonly property color on_tertiary: "#07372c"
|
||||
readonly property color on_tertiary_container: "#beecdc"
|
||||
readonly property color on_tertiary_fixed: "#002019"
|
||||
readonly property color on_tertiary_fixed_variant: "#234e42"
|
||||
readonly property color outline: "#929182"
|
||||
readonly property color outline_variant: "#47483b"
|
||||
readonly property color primary: "#c5cc7a"
|
||||
readonly property color primary_container: "#454b03"
|
||||
readonly property color primary_fixed: "#e2e993"
|
||||
readonly property color primary_fixed_dim: "#c5cc7a"
|
||||
readonly property color scrim: "#000000"
|
||||
readonly property color secondary: "#c8c9a6"
|
||||
readonly property color secondary_container: "#47492e"
|
||||
readonly property color secondary_fixed: "#e4e5c1"
|
||||
readonly property color secondary_fixed_dim: "#c8c9a6"
|
||||
readonly property color shadow: "#000000"
|
||||
readonly property color surface: "#13140c"
|
||||
readonly property color surface_bright: "#3a3a31"
|
||||
readonly property color surface_container: "#202018"
|
||||
readonly property color surface_container_high: "#2a2a22"
|
||||
readonly property color surface_container_highest: "#35352c"
|
||||
readonly property color surface_container_low: "#1c1c14"
|
||||
readonly property color surface_container_lowest: "#0e0f08"
|
||||
readonly property color surface_dim: "#13140c"
|
||||
readonly property color surface_tint: "#c5cc7a"
|
||||
|
||||
readonly property color surface_variant: "#47483b"
|
||||
readonly property color tertiary: "#a3d0c0"
|
||||
readonly property color tertiary_container: "#234e42"
|
||||
readonly property color tertiary_fixed: "#beecdc"
|
||||
readonly property color tertiary_fixed_dim: "#a3d0c0"
|
||||
|
||||
function withAlpha(color: color, alpha: real): color {
|
||||
return Qt.rgba(color.r, color.g, color.b, alpha);
|
||||
}
|
||||
}
|
||||
7
modules/desktop/quickshell/qml/Data/settings.json
Normal file
7
modules/desktop/quickshell/qml/Data/settings.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"isDarkTheme": true,
|
||||
"avatarSource": "/home/imxyy/Pictures/icon.jpg",
|
||||
"weatherLocation": "Dinslaken",
|
||||
"displayTime": 6000,
|
||||
"videoPath": "~/Videos/"
|
||||
}
|
||||
35
modules/desktop/quickshell/qml/Layout/Bar.qml
Normal file
35
modules/desktop/quickshell/qml/Layout/Bar.qml
Normal file
@@ -0,0 +1,35 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import "root:/Data" as Data
|
||||
import "root:/Widgets/System" as System
|
||||
import "root:/Widgets/Calendar" as Calendar
|
||||
|
||||
// Vertical sidebar layout
|
||||
Rectangle {
|
||||
id: bar
|
||||
|
||||
// Clean bar background
|
||||
color: Data.ThemeManager.bgColor
|
||||
|
||||
// Workspace indicator at top
|
||||
System.NiriWorkspaces {
|
||||
id: workspaceIndicator
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
horizontalCenterOffset: Data.Settings.borderWidth / 2
|
||||
topMargin: 20
|
||||
}
|
||||
}
|
||||
|
||||
// Clock at bottom
|
||||
Calendar.Clock {
|
||||
id: clockWidget
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
horizontalCenterOffset: Data.Settings.borderWidth / 2
|
||||
bottomMargin: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
575
modules/desktop/quickshell/qml/Layout/Border.qml
Normal file
575
modules/desktop/quickshell/qml/Layout/Border.qml
Normal file
@@ -0,0 +1,575 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import QtQuick.Effects
|
||||
import "root:/Data" as Data
|
||||
|
||||
// Screen border with shadow effects
|
||||
Shape {
|
||||
id: borderShape
|
||||
|
||||
// Border dimensions
|
||||
property real borderWidth: Data.Settings.borderWidth
|
||||
property real radius: Data.Settings.cornerRadius
|
||||
property real innerX: borderWidth
|
||||
property real innerY: borderWidth
|
||||
property real innerWidth: borderShape.width - (borderWidth * 2)
|
||||
property real innerHeight: borderShape.height - (borderWidth * 2)
|
||||
|
||||
// Widget references for shadow positioning
|
||||
property var workspaceIndicator: null
|
||||
property var volumeOSD: null
|
||||
property var clockWidget: null
|
||||
|
||||
// Initialization state to prevent ShaderEffect warnings
|
||||
property bool effectsReady: false
|
||||
|
||||
// Burst effect properties - controlled by workspace indicator
|
||||
property real masterProgress: workspaceIndicator ? workspaceIndicator.masterProgress : 0.0
|
||||
property bool effectsActive: workspaceIndicator ? workspaceIndicator.effectsActive : false
|
||||
property color effectColor: workspaceIndicator ? workspaceIndicator.effectColor : Data.ThemeManager.accent
|
||||
|
||||
// Delay graphics effects until component is fully loaded
|
||||
Timer {
|
||||
id: initTimer
|
||||
interval: 100
|
||||
running: true
|
||||
onTriggered: borderShape.effectsReady = true
|
||||
}
|
||||
|
||||
// Burst effect overlays (DISABLED - using unified overlay)
|
||||
Item {
|
||||
id: burstEffects
|
||||
anchors.fill: parent
|
||||
visible: false // Disabled in favor of unified overlay
|
||||
z: 5
|
||||
}
|
||||
|
||||
// Individual widget shadows (positioned separately)
|
||||
|
||||
// Workspace indicator shadow
|
||||
Shape {
|
||||
id: workspaceDropShadow
|
||||
visible: borderShape.workspaceIndicator !== null
|
||||
x: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.x : 0 // Exact match
|
||||
y: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.y : 0
|
||||
width: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.width : 0 // Exact match
|
||||
height: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.height : 0
|
||||
z: -1
|
||||
|
||||
layer.enabled: borderShape.workspaceIndicator !== null
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: 1
|
||||
verticalOffset: 1
|
||||
radius: 12 + (effectsActive && Data.Settings.workspaceGlowEnabled ? Math.sin(masterProgress * Math.PI) * 4 : 0)
|
||||
samples: 25
|
||||
color: {
|
||||
if (!effectsActive)
|
||||
return Qt.rgba(0, 0, 0, 0.4);
|
||||
if (!Data.Settings.workspaceGlowEnabled)
|
||||
return Qt.rgba(0, 0, 0, 0.4);
|
||||
// Use accent color directly with reduced intensity
|
||||
const intensity = Math.sin(masterProgress * Math.PI) * 0.4;
|
||||
return Qt.rgba(effectColor.r * intensity + 0.08, effectColor.g * intensity + 0.08, effectColor.b * intensity + 0.08, 0.4 + intensity * 0.2);
|
||||
}
|
||||
cached: true
|
||||
spread: 0.2 + (effectsActive && Data.Settings.workspaceGlowEnabled ? Math.sin(masterProgress * Math.PI) * 0.15 : 0)
|
||||
}
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: 0
|
||||
fillColor: "black"
|
||||
|
||||
startX: 12
|
||||
startY: 0
|
||||
|
||||
// Right side - standard rounded corners
|
||||
PathLine {
|
||||
x: workspaceDropShadow.width - 16
|
||||
y: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: workspaceDropShadow.width
|
||||
y: 16
|
||||
radiusX: 16
|
||||
radiusY: 16
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: workspaceDropShadow.width
|
||||
y: workspaceDropShadow.height - 16
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: workspaceDropShadow.width - 16
|
||||
y: workspaceDropShadow.height
|
||||
radiusX: 16
|
||||
radiusY: 16
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: 12
|
||||
y: workspaceDropShadow.height
|
||||
}
|
||||
|
||||
// Left side - concave curves for border integration
|
||||
PathLine {
|
||||
x: 0
|
||||
y: workspaceDropShadow.height - 12
|
||||
}
|
||||
PathArc {
|
||||
x: 12
|
||||
y: workspaceDropShadow.height - 24
|
||||
radiusX: 12
|
||||
radiusY: 12
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: 12
|
||||
y: 24
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: 0
|
||||
y: 12
|
||||
radiusX: 12
|
||||
radiusY: 12
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
PathLine {
|
||||
x: 12
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Volume OSD shadow
|
||||
Rectangle {
|
||||
id: volumeOsdDropShadow
|
||||
visible: borderShape.volumeOSD !== null && borderShape.volumeOSD.visible
|
||||
opacity: borderShape.volumeOSD ? borderShape.volumeOSD.opacity : 0
|
||||
x: parent.width - 45
|
||||
y: (parent.height - 250) / 2
|
||||
width: 45
|
||||
height: 250
|
||||
color: "black"
|
||||
topLeftRadius: 20
|
||||
bottomLeftRadius: 20
|
||||
topRightRadius: 0
|
||||
bottomRightRadius: 0
|
||||
z: -1
|
||||
|
||||
// Sync opacity animations with volume OSD
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
layer.enabled: borderShape.volumeOSD !== null
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: -1
|
||||
verticalOffset: 1
|
||||
radius: 12 // Much more subtle
|
||||
samples: 25
|
||||
color: Qt.rgba(0, 0, 0, 0.4) // Very light shadow
|
||||
cached: false
|
||||
spread: 0.2 // Minimal spread
|
||||
}
|
||||
}
|
||||
|
||||
// Clock shadow
|
||||
Rectangle {
|
||||
id: clockDropShadow
|
||||
visible: borderShape.clockWidget !== null
|
||||
x: borderShape.clockWidget ? borderShape.clockWidget.x : 0
|
||||
y: borderShape.clockWidget ? borderShape.clockWidget.y : 0
|
||||
width: borderShape.clockWidget ? borderShape.clockWidget.width : 0
|
||||
height: borderShape.clockWidget ? borderShape.clockWidget.height : 0
|
||||
color: "black"
|
||||
topLeftRadius: 0
|
||||
topRightRadius: borderShape.clockWidget ? borderShape.clockWidget.height / 2 : 16
|
||||
bottomLeftRadius: 0
|
||||
bottomRightRadius: 0
|
||||
z: -2 // Lower z-index to render behind border corners
|
||||
|
||||
layer.enabled: borderShape.clockWidget !== null
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: 1
|
||||
verticalOffset: -1
|
||||
radius: 12 // Much more subtle
|
||||
samples: 25
|
||||
color: Qt.rgba(0, 0, 0, 0.4) // Very light shadow
|
||||
cached: false
|
||||
spread: 0.2 // Minimal spread
|
||||
}
|
||||
}
|
||||
|
||||
// Shadow rendering source (hidden)
|
||||
Item {
|
||||
id: shadowSource
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
|
||||
Shape {
|
||||
id: borderShadowShape
|
||||
anchors.fill: parent
|
||||
|
||||
layer.enabled: true
|
||||
layer.samples: 4
|
||||
|
||||
ShapePath {
|
||||
fillColor: "black"
|
||||
strokeWidth: 0
|
||||
fillRule: ShapePath.OddEvenFill
|
||||
|
||||
// Outer rectangle (full screen)
|
||||
PathMove {
|
||||
x: 0
|
||||
y: 0
|
||||
}
|
||||
PathLine {
|
||||
x: shadowSource.width
|
||||
y: 0
|
||||
}
|
||||
PathLine {
|
||||
x: shadowSource.width
|
||||
y: shadowSource.height
|
||||
}
|
||||
PathLine {
|
||||
x: 0
|
||||
y: shadowSource.height
|
||||
}
|
||||
PathLine {
|
||||
x: 0
|
||||
y: 0
|
||||
}
|
||||
|
||||
// Inner rounded cutout creates border
|
||||
PathMove {
|
||||
x: borderShape.innerX + borderShape.radius
|
||||
y: borderShape.innerY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX + borderShape.innerWidth - borderShape.radius
|
||||
y: borderShape.innerY
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX + borderShape.innerWidth
|
||||
y: borderShape.innerY + borderShape.radius
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX + borderShape.innerWidth
|
||||
y: borderShape.innerY + borderShape.innerHeight - borderShape.radius
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX + borderShape.innerWidth - borderShape.radius
|
||||
y: borderShape.innerY + borderShape.innerHeight
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX + borderShape.radius
|
||||
y: borderShape.innerY + borderShape.innerHeight
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX
|
||||
y: borderShape.innerY + borderShape.innerHeight - borderShape.radius
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX
|
||||
y: borderShape.innerY + borderShape.radius
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX + borderShape.radius
|
||||
y: borderShape.innerY
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workspace indicator shadow with concave curves
|
||||
Shape {
|
||||
id: workspaceShadowShape
|
||||
visible: borderShape.workspaceIndicator !== null
|
||||
x: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.x : 0 // Exact match
|
||||
y: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.y : 0
|
||||
width: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.width : 0 // Exact match
|
||||
height: borderShape.workspaceIndicator ? borderShape.workspaceIndicator.height : 0
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
|
||||
layer.enabled: borderShape.workspaceIndicator !== null
|
||||
layer.samples: 8
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: 2
|
||||
verticalOffset: 3
|
||||
radius: 25 + (effectsActive && Data.Settings.workspaceGlowEnabled ? Math.sin(masterProgress * Math.PI) * 6 : 0)
|
||||
samples: 40
|
||||
color: {
|
||||
if (!effectsActive)
|
||||
return Qt.rgba(0, 0, 0, 0.8);
|
||||
if (!Data.Settings.workspaceGlowEnabled)
|
||||
return Qt.rgba(0, 0, 0, 0.8);
|
||||
// Accent color glow with reduced intensity
|
||||
const intensity = Math.sin(masterProgress * Math.PI) * 0.3;
|
||||
return Qt.rgba(effectColor.r * intensity + 0.1, effectColor.g * intensity + 0.1, effectColor.b * intensity + 0.1, 0.6 + intensity * 0.15);
|
||||
}
|
||||
cached: false
|
||||
spread: 0.5 + (effectsActive && Data.Settings.workspaceGlowEnabled ? Math.sin(masterProgress * Math.PI) * 0.2 : 0)
|
||||
}
|
||||
|
||||
ShapePath {
|
||||
strokeWidth: 0
|
||||
fillColor: "black"
|
||||
strokeColor: "black"
|
||||
|
||||
startX: 12
|
||||
startY: 0
|
||||
|
||||
// Right side - standard rounded corners
|
||||
PathLine {
|
||||
x: workspaceShadowShape.width - 16
|
||||
y: 0
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: workspaceShadowShape.width
|
||||
y: 16
|
||||
radiusX: 16
|
||||
radiusY: 16
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: workspaceShadowShape.width
|
||||
y: workspaceShadowShape.height - 16
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: workspaceShadowShape.width - 16
|
||||
y: workspaceShadowShape.height
|
||||
radiusX: 16
|
||||
radiusY: 16
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: 12
|
||||
y: workspaceShadowShape.height
|
||||
}
|
||||
|
||||
// Left side - concave curves for border integration
|
||||
PathLine {
|
||||
x: 0
|
||||
y: workspaceShadowShape.height - 12
|
||||
}
|
||||
PathArc {
|
||||
x: 12
|
||||
y: workspaceShadowShape.height - 24
|
||||
radiusX: 12
|
||||
radiusY: 12
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: 12
|
||||
y: 24
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: 0
|
||||
y: 12
|
||||
radiusX: 12
|
||||
radiusY: 12
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
PathLine {
|
||||
x: 12
|
||||
y: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Volume OSD shadow
|
||||
Rectangle {
|
||||
id: volumeOsdShadowShape
|
||||
visible: borderShape.volumeOSD !== null && borderShape.volumeOSD.visible
|
||||
x: shadowSource.width - 45
|
||||
y: (shadowSource.height - 250) / 2
|
||||
width: 45
|
||||
height: 250
|
||||
color: "black"
|
||||
topLeftRadius: 20
|
||||
bottomLeftRadius: 20
|
||||
topRightRadius: 0
|
||||
bottomRightRadius: 0
|
||||
|
||||
layer.enabled: borderShape.volumeOSD !== null && borderShape.volumeOSD.visible
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: -2 // Shadow to the left for right-side widget
|
||||
verticalOffset: 3
|
||||
radius: 25
|
||||
samples: 40
|
||||
color: Qt.rgba(0, 0, 0, 0.8)
|
||||
cached: false
|
||||
spread: 0.5
|
||||
}
|
||||
}
|
||||
|
||||
// Clock shadow
|
||||
Rectangle {
|
||||
id: clockShadowShape
|
||||
visible: borderShape.clockWidget !== null
|
||||
x: borderShape.clockWidget ? borderShape.clockWidget.x : 0
|
||||
y: borderShape.clockWidget ? borderShape.clockWidget.y : 0
|
||||
width: borderShape.clockWidget ? borderShape.clockWidget.width : 0
|
||||
height: borderShape.clockWidget ? borderShape.clockWidget.height : 0
|
||||
color: "black"
|
||||
topLeftRadius: 0
|
||||
topRightRadius: borderShape.clockWidget ? borderShape.clockWidget.height / 2 : 16
|
||||
bottomLeftRadius: 0
|
||||
bottomRightRadius: 0
|
||||
|
||||
layer.enabled: borderShape.clockWidget !== null
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: 2
|
||||
verticalOffset: -2 // Shadow upward for bottom widget
|
||||
radius: 25
|
||||
samples: 40
|
||||
color: Qt.rgba(0, 0, 0, 0.8)
|
||||
cached: false
|
||||
spread: 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply shadow effect to entire border shape
|
||||
layer.enabled: true
|
||||
layer.samples: 8
|
||||
layer.smooth: true
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: 1
|
||||
verticalOffset: 2
|
||||
radius: 30 // Slightly less dramatic
|
||||
samples: 45
|
||||
color: Qt.rgba(0, 0, 0, 0.75) // A bit lighter
|
||||
cached: false
|
||||
spread: 0.5 // Less spread
|
||||
}
|
||||
|
||||
// Main border shape
|
||||
ShapePath {
|
||||
fillColor: Data.ThemeManager.bgColor
|
||||
strokeWidth: 0
|
||||
fillRule: ShapePath.OddEvenFill
|
||||
|
||||
// Outer rectangle
|
||||
PathMove {
|
||||
x: 0
|
||||
y: 0
|
||||
}
|
||||
PathLine {
|
||||
x: borderShape.width
|
||||
y: 0
|
||||
}
|
||||
PathLine {
|
||||
x: borderShape.width
|
||||
y: borderShape.height
|
||||
}
|
||||
PathLine {
|
||||
x: 0
|
||||
y: borderShape.height
|
||||
}
|
||||
PathLine {
|
||||
x: 0
|
||||
y: 0
|
||||
}
|
||||
|
||||
// Inner rounded cutout
|
||||
PathMove {
|
||||
x: borderShape.innerX + borderShape.radius
|
||||
y: borderShape.innerY
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX + borderShape.innerWidth - borderShape.radius
|
||||
y: borderShape.innerY
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX + borderShape.innerWidth
|
||||
y: borderShape.innerY + borderShape.radius
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX + borderShape.innerWidth
|
||||
y: borderShape.innerY + borderShape.innerHeight - borderShape.radius
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX + borderShape.innerWidth - borderShape.radius
|
||||
y: borderShape.innerY + borderShape.innerHeight
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX + borderShape.radius
|
||||
y: borderShape.innerY + borderShape.innerHeight
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX
|
||||
y: borderShape.innerY + borderShape.innerHeight - borderShape.radius
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: borderShape.innerX
|
||||
y: borderShape.innerY + borderShape.radius
|
||||
}
|
||||
|
||||
PathArc {
|
||||
x: borderShape.innerX + borderShape.radius
|
||||
y: borderShape.innerY
|
||||
radiusX: borderShape.radius
|
||||
radiusY: borderShape.radius
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
}
|
||||
}
|
||||
302
modules/desktop/quickshell/qml/Layout/Desktop.qml
Normal file
302
modules/desktop/quickshell/qml/Layout/Desktop.qml
Normal file
@@ -0,0 +1,302 @@
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import "root:/Data" as Data
|
||||
import "root:/Widgets/System" as System
|
||||
import "root:/Core" as Core
|
||||
import "root:/Widgets" as Widgets
|
||||
import "root:/Widgets/Notifications" as Notifications
|
||||
import "root:/Widgets/ControlPanel" as ControlPanel
|
||||
|
||||
// Desktop with borders and UI widgets
|
||||
Scope {
|
||||
id: desktop
|
||||
|
||||
property var shell
|
||||
property var notificationService
|
||||
|
||||
// Desktop UI layer per screen
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
PanelWindow {
|
||||
required property var modelData
|
||||
screen: modelData
|
||||
|
||||
implicitWidth: Screen.width
|
||||
implicitHeight: Screen.height
|
||||
color: "transparent"
|
||||
exclusiveZone: 0
|
||||
|
||||
WlrLayershell.namespace: "quickshell-desktop"
|
||||
|
||||
// Interactive mask for workspace indicator only
|
||||
mask: Region {
|
||||
item: workspaceIndicator
|
||||
}
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
bottom: true
|
||||
right: true
|
||||
}
|
||||
|
||||
// Workspace indicator at left border
|
||||
System.NiriWorkspaces {
|
||||
id: workspaceIndicator
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: Data.Settings.borderWidth
|
||||
}
|
||||
z: 10
|
||||
width: 32
|
||||
}
|
||||
|
||||
// Volume OSD at right border (primary screen only)
|
||||
System.OSD {
|
||||
id: osd
|
||||
shell: desktop.shell
|
||||
visible: modelData === Quickshell.primaryScreen
|
||||
anchors {
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
rightMargin: Data.Settings.borderWidth
|
||||
}
|
||||
z: 10
|
||||
}
|
||||
|
||||
// Widget shadows (positioned behind border for proper layering)
|
||||
|
||||
// Workspace indicator shadow
|
||||
Rectangle {
|
||||
id: workspaceShadow
|
||||
visible: workspaceIndicator !== null
|
||||
x: workspaceIndicator.x
|
||||
y: workspaceIndicator.y
|
||||
width: workspaceIndicator.width
|
||||
height: workspaceIndicator.height
|
||||
color: "black"
|
||||
radius: 16
|
||||
z: -10 // Behind border
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: 2
|
||||
verticalOffset: 2
|
||||
radius: 8 + (workspaceIndicator.effectsActive && Data.Settings.workspaceGlowEnabled ? Math.sin(workspaceIndicator.masterProgress * Math.PI) * 3 : 0)
|
||||
samples: 17
|
||||
color: {
|
||||
if (!workspaceIndicator.effectsActive)
|
||||
return Qt.rgba(0, 0, 0, 0.3);
|
||||
if (!Data.Settings.workspaceGlowEnabled)
|
||||
return Qt.rgba(0, 0, 0, 0.3);
|
||||
// Use accent color glow with reduced intensity
|
||||
const intensity = Math.sin(workspaceIndicator.masterProgress * Math.PI) * 0.3;
|
||||
return Qt.rgba(workspaceIndicator.effectColor.r * intensity + 0.05, workspaceIndicator.effectColor.g * intensity + 0.05, workspaceIndicator.effectColor.b * intensity + 0.05, 0.3 + intensity * 0.15);
|
||||
}
|
||||
cached: true
|
||||
spread: 0.1 + (workspaceIndicator.effectsActive && Data.Settings.workspaceGlowEnabled ? Math.sin(workspaceIndicator.masterProgress * Math.PI) * 0.1 : 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Clock widget shadow
|
||||
Rectangle {
|
||||
id: clockShadow
|
||||
visible: clockWidget !== null
|
||||
x: clockWidget.x
|
||||
y: clockWidget.y
|
||||
width: clockWidget.width
|
||||
height: clockWidget.height
|
||||
color: "black"
|
||||
topLeftRadius: 0
|
||||
topRightRadius: clockWidget.height / 2
|
||||
bottomLeftRadius: 0
|
||||
bottomRightRadius: 0
|
||||
z: -10 // Behind border
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: DropShadow {
|
||||
transparentBorder: true
|
||||
horizontalOffset: 1
|
||||
verticalOffset: -1
|
||||
radius: 8
|
||||
samples: 17
|
||||
color: Qt.rgba(0, 0, 0, 0.3)
|
||||
cached: true
|
||||
spread: 0.1
|
||||
}
|
||||
}
|
||||
|
||||
// Border background with shadow
|
||||
Border {
|
||||
id: screenBorder
|
||||
anchors.fill: parent
|
||||
workspaceIndicator: workspaceIndicator
|
||||
volumeOSD: volumeOsd
|
||||
clockWidget: clockWidget
|
||||
z: -5 // Behind UI elements to prevent shadow from covering control panel
|
||||
}
|
||||
|
||||
// Unified Wave Overlay - simple burst effect
|
||||
Item {
|
||||
id: waveOverlay
|
||||
anchors.fill: parent
|
||||
visible: workspaceIndicator.effectsActive && Data.Settings.workspaceBurstEnabled
|
||||
z: 15
|
||||
|
||||
property real progress: workspaceIndicator.masterProgress
|
||||
property color waveColor: workspaceIndicator.effectColor
|
||||
|
||||
// Workspace indicator burst effects
|
||||
Item {
|
||||
x: workspaceIndicator.x
|
||||
y: workspaceIndicator.y
|
||||
width: workspaceIndicator.width
|
||||
height: workspaceIndicator.height
|
||||
|
||||
// Expanding pill burst - positioned at current workspace index (mimics pill shape)
|
||||
Rectangle {
|
||||
x: parent.width / 2 - width / 2
|
||||
y: {
|
||||
// Find current workspace index directly from currentWorkspace
|
||||
let focusedIndex = 0;
|
||||
for (let i = 0; i < workspaceIndicator.workspaces.count; i++) {
|
||||
const workspace = workspaceIndicator.workspaces.get(i);
|
||||
if (workspace && workspace.id === workspaceIndicator.currentWorkspace) {
|
||||
focusedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate position accounting for Column centering and pill sizes
|
||||
let cumulativeHeight = 0;
|
||||
for (let i = 0; i < focusedIndex; i++) {
|
||||
const ws = workspaceIndicator.workspaces.get(i);
|
||||
cumulativeHeight += (ws && ws.isFocused ? 36 : 22) + 6; // pill height + spacing
|
||||
}
|
||||
|
||||
// Current pill height
|
||||
const currentWs = workspaceIndicator.workspaces.get(focusedIndex);
|
||||
const currentPillHeight = (currentWs && currentWs.isFocused ? 36 : 22);
|
||||
|
||||
// Column is centered, so start from center and calculate offset
|
||||
const columnHeight = parent.height - 24; // Total available height minus padding
|
||||
const columnTop = 12; // Top padding
|
||||
|
||||
return columnTop + cumulativeHeight + currentPillHeight / 2 - height / 2;
|
||||
}
|
||||
width: 20 + waveOverlay.progress * 30
|
||||
height: 36 + waveOverlay.progress * 20 // Pill-like height
|
||||
radius: width / 2 // Pill-like rounded shape
|
||||
color: "transparent"
|
||||
border.width: 2
|
||||
border.color: Qt.rgba(waveOverlay.waveColor.r, waveOverlay.waveColor.g, waveOverlay.waveColor.b, 1.0 - waveOverlay.progress)
|
||||
opacity: Math.max(0, 1.0 - waveOverlay.progress)
|
||||
}
|
||||
|
||||
// Secondary expanding pill burst - positioned at current workspace index
|
||||
Rectangle {
|
||||
x: parent.width / 2 - width / 2
|
||||
y: {
|
||||
// Find current workspace index directly from currentWorkspace
|
||||
let focusedIndex = 0;
|
||||
for (let i = 0; i < workspaceIndicator.workspaces.count; i++) {
|
||||
const workspace = workspaceIndicator.workspaces.get(i);
|
||||
if (workspace && workspace.id === workspaceIndicator.currentWorkspace) {
|
||||
focusedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate position accounting for Column centering and pill sizes
|
||||
let cumulativeHeight = 0;
|
||||
for (let i = 0; i < focusedIndex; i++) {
|
||||
const ws = workspaceIndicator.workspaces.get(i);
|
||||
cumulativeHeight += (ws && ws.isFocused ? 36 : 22) + 6; // pill height + spacing
|
||||
}
|
||||
|
||||
// Current pill height
|
||||
const currentWs = workspaceIndicator.workspaces.get(focusedIndex);
|
||||
const currentPillHeight = (currentWs && currentWs.isFocused ? 36 : 22);
|
||||
|
||||
// Column is centered, so start from center and calculate offset
|
||||
const columnHeight = parent.height - 24; // Total available height minus padding
|
||||
const columnTop = 12; // Top padding
|
||||
|
||||
return columnTop + cumulativeHeight + currentPillHeight / 2 - height / 2;
|
||||
}
|
||||
width: 18 + waveOverlay.progress * 45
|
||||
height: 30 + waveOverlay.progress * 35 // Pill-like height
|
||||
radius: width / 2 // Pill-like rounded shape
|
||||
color: "transparent"
|
||||
border.width: 1.5
|
||||
border.color: Qt.rgba(waveOverlay.waveColor.r, waveOverlay.waveColor.g, waveOverlay.waveColor.b, 0.6)
|
||||
opacity: Math.max(0, 0.8 - waveOverlay.progress * 1.2)
|
||||
visible: waveOverlay.progress > 0.2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clock at bottom-left corner
|
||||
Widgets.Clock {
|
||||
id: clockWidget
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
bottomMargin: Data.Settings.borderWidth
|
||||
leftMargin: Data.Settings.borderWidth
|
||||
}
|
||||
z: 10
|
||||
}
|
||||
|
||||
// Notification popups (primary screen only)
|
||||
Notifications.Notification {
|
||||
id: notificationPopup
|
||||
visible: (modelData === (Quickshell.primaryScreen || Quickshell.screens[0])) && calculatedHeight > 20
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
rightMargin: Data.Settings.borderWidth + 20
|
||||
topMargin: 0
|
||||
}
|
||||
width: 420
|
||||
height: calculatedHeight
|
||||
shell: desktop.shell
|
||||
notificationServer: desktop.notificationService ? desktop.notificationService.notificationServer : null
|
||||
z: 15
|
||||
|
||||
Component.onCompleted: {
|
||||
let targetScreen = Quickshell.primaryScreen || Quickshell.screens[0];
|
||||
if (modelData === targetScreen) {
|
||||
desktop.shell.notificationWindow = notificationPopup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UI overlay layer for modal components
|
||||
Item {
|
||||
id: uiLayer
|
||||
anchors.fill: parent
|
||||
z: 20
|
||||
|
||||
ControlPanel.ControlPanel {
|
||||
id: controlPanelComponent
|
||||
shell: desktop.shell
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle dynamic screen configuration changes
|
||||
Connections {
|
||||
target: Quickshell
|
||||
function onScreensChanged() {
|
||||
// Screen changes handled by Variants automatically
|
||||
}
|
||||
}
|
||||
}
|
||||
394
modules/desktop/quickshell/qml/Services/AppLauncherService.qml
Normal file
394
modules/desktop/quickshell/qml/Services/AppLauncherService.qml
Normal file
@@ -0,0 +1,394 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
// App launcher service - discovers and manages applications
|
||||
Item {
|
||||
id: appService
|
||||
|
||||
property var applications: []
|
||||
property bool isLoading: false
|
||||
|
||||
// Categories for apps
|
||||
property var categories: {
|
||||
"AudioVideo": "🎵",
|
||||
"Audio": "🎵",
|
||||
"Video": "🎬",
|
||||
"Development": "💻",
|
||||
"Education": "📚",
|
||||
"Game": "🎮",
|
||||
"Graphics": "🎨",
|
||||
"Network": "🌐",
|
||||
"Office": "📄",
|
||||
"Science": "🔬",
|
||||
"Settings": "⚙️",
|
||||
"System": "🔧",
|
||||
"Utility": "🛠️",
|
||||
"Other": "📦"
|
||||
}
|
||||
|
||||
property string userName: ""
|
||||
property string homeDirectory: ""
|
||||
property bool userInfoLoaded: false
|
||||
property var currentApp: ({})
|
||||
property var pendingSearchPaths: []
|
||||
|
||||
Component.onCompleted: {
|
||||
// First get user info, then load applications
|
||||
loadUserInfo();
|
||||
}
|
||||
|
||||
function loadUserInfo() {
|
||||
userNameProcess.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: userNameProcess
|
||||
command: ["whoami"]
|
||||
running: false
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: line => {
|
||||
if (line.trim()) {
|
||||
userName = line.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
// Now get home directory
|
||||
homeDirProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: homeDirProcess
|
||||
command: ["sh", "-c", "echo $HOME"]
|
||||
running: false
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: line => {
|
||||
if (line.trim()) {
|
||||
homeDirectory = line.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
// Now we have user info, start loading applications
|
||||
userInfoLoaded = true;
|
||||
loadApplications();
|
||||
}
|
||||
}
|
||||
|
||||
function loadApplications() {
|
||||
if (!userInfoLoaded) {
|
||||
console.log("User info not loaded yet, skipping application scan");
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading = true;
|
||||
applications = [];
|
||||
|
||||
console.log("DEBUG: Starting application scan with user:", userName, "home:", homeDirectory);
|
||||
|
||||
// Comprehensive search paths for maximum Linux compatibility
|
||||
appService.pendingSearchPaths = [
|
||||
// User-specific locations (highest priority)
|
||||
homeDirectory + "/.local/share/applications/",
|
||||
|
||||
// Standard FreeDesktop.org locations
|
||||
"/usr/share/applications/", "/usr/local/share/applications/",
|
||||
|
||||
// Flatpak locations
|
||||
"/var/lib/flatpak/exports/share/applications/", homeDirectory + "/.local/share/flatpak/exports/share/applications/",
|
||||
|
||||
// Snap locations
|
||||
"/var/lib/snapd/desktop/applications/", "/snap/bin/",
|
||||
|
||||
// AppImage locations (common user directories)
|
||||
homeDirectory + "/Applications/", homeDirectory + "/AppImages/",
|
||||
|
||||
// Distribution-specific paths
|
||||
"/opt/*/share/applications/" // For manually installed software
|
||||
, "/usr/share/applications/kde4/" // KDE4 legacy
|
||||
|
||||
,
|
||||
|
||||
// NixOS-specific (will be ignored on non-NixOS systems)
|
||||
"/run/current-system/sw/share/applications/", "/etc/profiles/per-user/" + userName + "/share/applications/"];
|
||||
|
||||
console.log("DEBUG: Starting with essential paths:", JSON.stringify(appService.pendingSearchPaths));
|
||||
|
||||
// Add XDG and home-manager paths
|
||||
getXdgDataDirs.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getXdgDataDirs
|
||||
command: ["sh", "-c", "echo $XDG_DATA_DIRS"]
|
||||
running: false
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: line => {
|
||||
if (line.trim()) {
|
||||
var xdgDirs = line.trim().split(":");
|
||||
for (var i = 0; i < xdgDirs.length; i++) {
|
||||
if (xdgDirs[i].trim()) {
|
||||
var xdgPath = xdgDirs[i].trim() + "/applications/";
|
||||
if (appService.pendingSearchPaths.indexOf(xdgPath) === -1) {
|
||||
appService.pendingSearchPaths.push(xdgPath);
|
||||
console.log("DEBUG: Added XDG path:", xdgPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
// Now add home-manager path
|
||||
getHomeManagerPaths.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getHomeManagerPaths
|
||||
command: ["sh", "-c", "find /nix/store -maxdepth 1 -name '*home-manager-path*' -type d 2>/dev/null | head -1"]
|
||||
running: false
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: line => {
|
||||
if (line.trim()) {
|
||||
var homeManagerPath = line.trim() + "/share/applications/";
|
||||
appService.pendingSearchPaths.push(homeManagerPath);
|
||||
console.log("DEBUG: Added home-manager path:", homeManagerPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
// CRITICAL: Always ensure these essential directories are included
|
||||
var essentialPaths = ["/run/current-system/sw/share/applications/", "/usr/share/applications/", "/usr/local/share/applications/"];
|
||||
|
||||
for (var i = 0; i < essentialPaths.length; i++) {
|
||||
var path = essentialPaths[i];
|
||||
if (appService.pendingSearchPaths.indexOf(path) === -1) {
|
||||
appService.pendingSearchPaths.push(path);
|
||||
console.log("DEBUG: Added missing essential path:", path);
|
||||
}
|
||||
}
|
||||
|
||||
// Start bulk parsing with all paths including XDG and home-manager
|
||||
startBulkParsing(appService.pendingSearchPaths);
|
||||
}
|
||||
}
|
||||
|
||||
function startBulkParsing(searchPaths) {
|
||||
// BULLETPROOF: Ensure critical system directories are always included
|
||||
var criticalPaths = ["/run/current-system/sw/share/applications/", "/usr/share/applications/", "/usr/local/share/applications/"];
|
||||
|
||||
for (var i = 0; i < criticalPaths.length; i++) {
|
||||
var path = criticalPaths[i];
|
||||
if (searchPaths.indexOf(path) === -1) {
|
||||
searchPaths.push(path);
|
||||
console.log("DEBUG: BULLETPROOF: Added missing critical path:", path);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("DEBUG: Final directories to scan:", searchPaths.join(", "));
|
||||
|
||||
// Single command to parse all .desktop files at once
|
||||
// Only parse fields from the main [Desktop Entry] section, ignore [Desktop Action] sections
|
||||
var cmd = 'for dir in ' + searchPaths.map(p => "'" + p + "'").join(" ") + '; do ' + 'if [ -d "$dir" ]; then ' + 'find "$dir" -name "*.desktop" 2>/dev/null | while read file; do ' + 'echo "===FILE:$file"; ' + 'sed -n \'/^\\[Desktop Entry\\]/,/^\\[.*\\]/{/^\\[Desktop Entry\\]/d; /^\\[.*\\]/q; /^Name=/p; /^Exec=/p; /^Icon=/p; /^Comment=/p; /^Categories=/p; /^Hidden=/p; /^NoDisplay=/p}\' "$file" 2>/dev/null || true; ' + 'done; ' + 'fi; ' + 'done';
|
||||
|
||||
bulkParseProcess.command = ["sh", "-c", cmd];
|
||||
bulkParseProcess.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: bulkParseProcess
|
||||
running: false
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: line => {
|
||||
if (line.startsWith("===FILE:")) {
|
||||
// Start of new file
|
||||
if (appService.currentApp.name && appService.currentApp.exec && !appService.currentApp.hidden && !appService.currentApp.noDisplay) {
|
||||
applications.push(appService.currentApp);
|
||||
}
|
||||
appService.currentApp = {
|
||||
name: "",
|
||||
exec: "",
|
||||
icon: "",
|
||||
comment: "",
|
||||
categories: [],
|
||||
hidden: false,
|
||||
noDisplay: false,
|
||||
filePath: line.substring(8) // Remove "===FILE:" prefix
|
||||
};
|
||||
} else if (line.startsWith("Name=")) {
|
||||
appService.currentApp.name = line.substring(5);
|
||||
} else if (line.startsWith("Exec=")) {
|
||||
appService.currentApp.exec = line.substring(5);
|
||||
} else if (line.startsWith("Icon=")) {
|
||||
appService.currentApp.icon = line.substring(5);
|
||||
} else if (line.startsWith("Comment=")) {
|
||||
appService.currentApp.comment = line.substring(8);
|
||||
} else if (line.startsWith("Categories=")) {
|
||||
appService.currentApp.categories = line.substring(11).split(";").filter(cat => cat.length > 0);
|
||||
} else if (line === "Hidden=true") {
|
||||
appService.currentApp.hidden = true;
|
||||
} else if (line === "NoDisplay=true") {
|
||||
appService.currentApp.noDisplay = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onStarted: {
|
||||
appService.currentApp = {};
|
||||
}
|
||||
|
||||
onExited: {
|
||||
// Process the last app
|
||||
if (appService.currentApp.name && appService.currentApp.exec && !appService.currentApp.hidden && !appService.currentApp.noDisplay) {
|
||||
applications.push(appService.currentApp);
|
||||
}
|
||||
|
||||
console.log("DEBUG: Before deduplication: Found", applications.length, "applications");
|
||||
|
||||
// Deduplicate applications - prefer user installations over system ones
|
||||
var uniqueApps = {};
|
||||
var finalApps = [];
|
||||
|
||||
for (var i = 0; i < applications.length; i++) {
|
||||
var app = applications[i];
|
||||
var key = app.name + "|" + app.exec.split(" ")[0]; // Use name + base command as key
|
||||
|
||||
if (!uniqueApps[key]) {
|
||||
// First occurrence of this app
|
||||
uniqueApps[key] = app;
|
||||
finalApps.push(app);
|
||||
} else {
|
||||
// Duplicate found - check if this version should replace the existing one
|
||||
var existing = uniqueApps[key];
|
||||
var shouldReplace = false;
|
||||
|
||||
// Priority order (higher priority replaces lower):
|
||||
// 1. User local applications (highest priority)
|
||||
// 2. Home-manager applications
|
||||
// 3. User profile applications
|
||||
// 4. System applications (lowest priority)
|
||||
|
||||
if (app.filePath.includes("/.local/share/applications/")) {
|
||||
shouldReplace = true; // User local always wins
|
||||
} else if (app.filePath.includes("home-manager-path") && !existing.filePath.includes("/.local/share/applications/")) {
|
||||
shouldReplace = true; // Home-manager beats system
|
||||
} else if (app.filePath.includes("/home/") && !existing.filePath.includes("/.local/share/applications/") && !existing.filePath.includes("home-manager-path")) {
|
||||
shouldReplace = true; // User profile beats system
|
||||
}
|
||||
|
||||
if (shouldReplace) {
|
||||
// Replace the existing app in finalApps array
|
||||
for (var j = 0; j < finalApps.length; j++) {
|
||||
if (finalApps[j] === existing) {
|
||||
finalApps[j] = app;
|
||||
uniqueApps[key] = app;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If not replacing, just ignore the duplicate
|
||||
}
|
||||
}
|
||||
|
||||
applications = finalApps;
|
||||
console.log("DEBUG: After deduplication: Found", applications.length, "unique applications");
|
||||
|
||||
isLoading = false;
|
||||
applicationsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
function launchApplication(app) {
|
||||
if (!app || !app.exec)
|
||||
return;
|
||||
|
||||
// Clean up the exec command (remove field codes like %f, %F, %u, %U)
|
||||
var cleanExec = app.exec.replace(/%[fFuU]/g, "").trim();
|
||||
|
||||
launchProcess.command = ["sh", "-c", cleanExec];
|
||||
launchProcess.running = true;
|
||||
|
||||
console.log("Launching:", app.name, "with command:", cleanExec);
|
||||
}
|
||||
|
||||
Process {
|
||||
id: launchProcess
|
||||
running: false
|
||||
|
||||
onExited: {
|
||||
if (exitCode !== 0) {
|
||||
console.log("Failed to launch application, exit code:", exitCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fuzzy search function
|
||||
function fuzzySearch(query, apps) {
|
||||
if (!query || query.length === 0) {
|
||||
return apps;
|
||||
}
|
||||
|
||||
query = query.toLowerCase();
|
||||
|
||||
return apps.filter(app => {
|
||||
var searchText = (app.name + " " + app.comment).toLowerCase();
|
||||
|
||||
// Simple fuzzy matching - check if all characters of query appear in order
|
||||
var queryIndex = 0;
|
||||
for (var i = 0; i < searchText.length && queryIndex < query.length; i++) {
|
||||
if (searchText[i] === query[queryIndex]) {
|
||||
queryIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
return queryIndex === query.length;
|
||||
}).sort((a, b) => {
|
||||
// Sort by relevance - exact matches first, then by name
|
||||
var aName = a.name.toLowerCase();
|
||||
var bName = b.name.toLowerCase();
|
||||
|
||||
var aExact = aName.includes(query);
|
||||
var bExact = bName.includes(query);
|
||||
|
||||
if (aExact && !bExact)
|
||||
return -1;
|
||||
if (!aExact && bExact)
|
||||
return 1;
|
||||
|
||||
return aName.localeCompare(bName);
|
||||
});
|
||||
}
|
||||
|
||||
function getCategoryIcon(app) {
|
||||
if (!app.categories || app.categories.length === 0) {
|
||||
return categories["Other"];
|
||||
}
|
||||
|
||||
// Find the first matching category
|
||||
for (var i = 0; i < app.categories.length; i++) {
|
||||
var category = app.categories[i];
|
||||
if (categories[category]) {
|
||||
return categories[category];
|
||||
}
|
||||
}
|
||||
|
||||
return categories["Other"];
|
||||
}
|
||||
}
|
||||
155
modules/desktop/quickshell/qml/Services/MatugenService.qml
Normal file
155
modules/desktop/quickshell/qml/Services/MatugenService.qml
Normal file
@@ -0,0 +1,155 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
import "root:/Data" as Data
|
||||
|
||||
// Matugen color integration service
|
||||
Item {
|
||||
id: service
|
||||
|
||||
property var shell
|
||||
property var colors: ({})
|
||||
property bool isLoaded: false
|
||||
property int colorVersion: 0 // Increments every time colors update to force QML re-evaluation
|
||||
|
||||
// Signals to notify when colors change
|
||||
signal matugenColorsUpdated
|
||||
signal matugenColorsLoaded
|
||||
|
||||
// File watcher for the matugen quickshell-colors.qml
|
||||
FileView {
|
||||
id: matugenFile
|
||||
path: "/home/imxyy/.config/quickshell/Data/quickshell-colors.qml"
|
||||
blockWrites: true
|
||||
|
||||
onLoaded: {
|
||||
parseColors(text());
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
parseColors(text());
|
||||
}
|
||||
}
|
||||
|
||||
// Parse QML color definitions and map them to base16 colors
|
||||
function parseColors(qmlText) {
|
||||
if (!qmlText) {
|
||||
console.warn("MatugenService: No QML content to parse");
|
||||
return;
|
||||
}
|
||||
|
||||
const lines = qmlText.split('\n');
|
||||
const parsedColors = {};
|
||||
|
||||
// Extract readonly property color definitions
|
||||
for (const line of lines) {
|
||||
const match = line.match(/readonly\s+property\s+color\s+(\w+):\s*"(#[0-9a-fA-F]{6})"/);
|
||||
if (match) {
|
||||
const colorName = match[1];
|
||||
const colorValue = match[2];
|
||||
parsedColors[colorName] = colorValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect if this is a light or dark theme based on surface luminance
|
||||
const surfaceColor = parsedColors.surface || "#000000";
|
||||
const isLightTheme = getLuminance(surfaceColor) > 0.5;
|
||||
|
||||
console.log(`MatugenService: Detected ${isLightTheme ? 'light' : 'dark'} theme from surface color: ${surfaceColor}`);
|
||||
|
||||
// Use Material Design 3 colors directly with better contrast
|
||||
const baseMapping = {
|
||||
base00: parsedColors.surface || (isLightTheme ? "#ffffff" : "#000000") // Background
|
||||
,
|
||||
base01: parsedColors.surface_container_low || (isLightTheme ? "#f8f9fa" : "#1a1a1a") // Panel bg
|
||||
,
|
||||
base02: parsedColors.surface_container || (isLightTheme ? "#e9ecef" : "#2a2a2a") // Selection
|
||||
,
|
||||
base03: parsedColors.surface_container_high || (isLightTheme ? "#dee2e6" : "#3a3a3a") // Border/separator
|
||||
,
|
||||
base04: parsedColors.on_surface_variant || (isLightTheme ? "#6c757d" : "#adb5bd") // Secondary text (better contrast)
|
||||
,
|
||||
base05: parsedColors.on_surface || (isLightTheme ? "#212529" : "#f8f9fa") // Primary text (high contrast)
|
||||
,
|
||||
base06: parsedColors.on_background || (isLightTheme ? "#000000" : "#ffffff") // Bright text
|
||||
,
|
||||
base07: isLightTheme ? parsedColors.surface_container_lowest || "#ffffff" : parsedColors.surface_bright || "#ffffff" // Brightest
|
||||
,
|
||||
base08: isLightTheme ? parsedColors.on_error || "#dc3545" : parsedColors.error || "#ff6b6b" // Error (theme appropriate)
|
||||
,
|
||||
base09: parsedColors.tertiary || (isLightTheme ? "#6f42c1" : "#a855f7") // Purple
|
||||
,
|
||||
base0A: parsedColors.primary_fixed || (isLightTheme ? "#fd7e14" : "#fbbf24") // Orange/Yellow
|
||||
,
|
||||
base0B: parsedColors.secondary || (isLightTheme ? "#198754" : "#10b981") // Green
|
||||
,
|
||||
base0C: parsedColors.surface_tint || (isLightTheme ? "#0dcaf0" : "#06b6d4") // Cyan
|
||||
,
|
||||
base0D: parsedColors.primary_container || (isLightTheme ? "#0d6efd" : "#3b82f6") // Blue
|
||||
,
|
||||
base0E: parsedColors.primary || (isLightTheme ? "#6610f2" : parsedColors.secondary || "#8b5cf6") // Accent - use primary for light, secondary for dark
|
||||
,
|
||||
base0F: parsedColors.scrim || "#000000" // Special/black
|
||||
};
|
||||
|
||||
// Create the theme object
|
||||
const theme = Object.assign({
|
||||
name: isLightTheme ? "Matugen Light" : "Matugen Dark",
|
||||
type: isLightTheme ? "light" : "dark"
|
||||
}, baseMapping);
|
||||
|
||||
// Store colors in the appropriate theme slot
|
||||
colors = {
|
||||
raw: parsedColors,
|
||||
[isLightTheme ? 'light' : 'dark']: theme,
|
||||
// Keep the other theme as null or use fallback
|
||||
[isLightTheme ? 'dark' : 'light']: null
|
||||
};
|
||||
|
||||
isLoaded = true;
|
||||
colorVersion++; // Increment version to force QML property updates
|
||||
|
||||
console.log("MatugenService: Colors loaded successfully from QML (version " + colorVersion + ")");
|
||||
console.log("Available colors:", Object.keys(parsedColors).join(", "));
|
||||
|
||||
// Emit signals to notify theme system
|
||||
matugenColorsUpdated();
|
||||
matugenColorsLoaded();
|
||||
}
|
||||
|
||||
// Calculate luminance of a hex color
|
||||
function getLuminance(hexColor) {
|
||||
// Remove # if present
|
||||
const hex = hexColor.replace('#', '');
|
||||
|
||||
// Convert to RGB
|
||||
const r = parseInt(hex.substr(0, 2), 16) / 255;
|
||||
const g = parseInt(hex.substr(2, 2), 16) / 255;
|
||||
const b = parseInt(hex.substr(4, 2), 16) / 255;
|
||||
|
||||
// Calculate relative luminance
|
||||
const rs = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
|
||||
const gs = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
|
||||
const bs = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
|
||||
|
||||
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
|
||||
}
|
||||
|
||||
// Reload colors from file
|
||||
function reloadColors() {
|
||||
matugenFile.reload();
|
||||
}
|
||||
|
||||
// Get specific color by name
|
||||
function getColor(colorName) {
|
||||
return colors.raw ? colors.raw[colorName] : null;
|
||||
}
|
||||
|
||||
// Check if matugen colors are available
|
||||
function isAvailable() {
|
||||
return isLoaded && colors.raw && Object.keys(colors.raw).length > 0;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("MatugenService: Initialized, watching quickshell-colors.qml");
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user