diff --git a/dotfiles/icons/Amy-Dark-Icons.tar.xz b/dotfiles/icons/Amy-Dark-Icons.tar.xz new file mode 100644 index 0000000..7ec1c31 Binary files /dev/null and b/dotfiles/icons/Amy-Dark-Icons.tar.xz differ diff --git a/dotfiles/icons/Azure-Glassy-Dark-Icons.tar.xz b/dotfiles/icons/Azure-Glassy-Dark-Icons.tar.xz new file mode 100644 index 0000000..8daa7c0 Binary files /dev/null and b/dotfiles/icons/Azure-Glassy-Dark-Icons.tar.xz differ diff --git a/dotfiles/icons/Slot-Beauty-Dark-Icons-V-2.tar.xz b/dotfiles/icons/Slot-Beauty-Dark-Icons-V-2.tar.xz new file mode 100644 index 0000000..126d46c Binary files /dev/null and b/dotfiles/icons/Slot-Beauty-Dark-Icons-V-2.tar.xz differ diff --git a/dotfiles/quickshell/widgets/launcher/LauncherConsole.qml b/dotfiles/quickshell/widgets/launcher/LauncherConsole.qml index ccd113c..a2563d8 100644 --- a/dotfiles/quickshell/widgets/launcher/LauncherConsole.qml +++ b/dotfiles/quickshell/widgets/launcher/LauncherConsole.qml @@ -37,6 +37,12 @@ Scope { WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.keyboardFocus: root.active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None + // Overlay, not a real dock: don't reserve compositor space (default + // ExclusionMode.Auto would claim a strip the full height of the deck + // along the top edge, shrinking every other window's usable area + // even while closed). + exclusionMode: ExclusionMode.Ignore + color: "transparent" anchors { diff --git a/dotfiles/quickshell/widgets/launcher/LauncherCorner.qml b/dotfiles/quickshell/widgets/launcher/LauncherCorner.qml index b53ca8d..ba565dd 100644 --- a/dotfiles/quickshell/widgets/launcher/LauncherCorner.qml +++ b/dotfiles/quickshell/widgets/launcher/LauncherCorner.qml @@ -649,7 +649,7 @@ Scope { spacing: 12 IconImage { - implicitSize: 28 + implicitSize: 34 source: Quickshell.iconPath(appRow.modelData.icon, "application-x-executable") } diff --git a/dotfiles/quickshell/widgets/launcher/LauncherDock.qml b/dotfiles/quickshell/widgets/launcher/LauncherDock.qml index 394d62b..a2e65a8 100644 --- a/dotfiles/quickshell/widgets/launcher/LauncherDock.qml +++ b/dotfiles/quickshell/widgets/launcher/LauncherDock.qml @@ -35,6 +35,12 @@ Scope { WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.keyboardFocus: root.active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None + // Overlay, not a real dock: don't reserve compositor space (default + // ExclusionMode.Auto would claim a strip the full height of the deck + // along the bottom edge, shrinking every other window's usable area + // even while closed). + exclusionMode: ExclusionMode.Ignore + color: "transparent" anchors { diff --git a/dotfiles/scripts/start-communications.sh b/dotfiles/scripts/start-communications.sh index 9385365..4b97e2b 100755 --- a/dotfiles/scripts/start-communications.sh +++ b/dotfiles/scripts/start-communications.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Start both comms apps; Hyprland window rules move them to special:communications. -telegram-desktop & -discord & +flatpak run org.telegram.desktop & +flatpak run com.discordapp.Discord & diff --git a/hosts/terra/configuration.nix b/hosts/terra/configuration.nix index 624ff62..f667cf6 100644 --- a/hosts/terra/configuration.nix +++ b/hosts/terra/configuration.nix @@ -1,10 +1,6 @@ +# ---- TERRA ---- { config, pkgs, lib, inputs, ... }: -# terra — Ryzen 9 5900X / Radeon RX 6800 XT desktop (MSI MS-7A32). Replaces -# CachyOS on the OS SSD (Kingston SA400, sdb). Dev-data disks (sdc ext4 -# /mnt/hdd_01, LVM vg_ssd /mnt/ssd_01) are kept out of disko and mounted here -# as plain filesystems so they're never wiped. The leftover ntfs disks -# (sda, sdf, nvme0n1) are ignored entirely — not referenced anywhere. let unstable = import inputs.nixpkgs-unstable { inherit (pkgs.stdenv.hostPlatform) system; @@ -14,9 +10,9 @@ in { imports = [ ./hardware-configuration.nix - ./disk-config.nix # disko: OS-disk (sdb) partitions + filesystems - ./secrets.nix # sops-nix: darman password, tailscale key - ../../common.nix # shared base: user / ssh / nix / firewall + ./disk-config.nix + ./secrets.nix + ../../common.nix ../../services/vpn/tailscale.nix ../../services/desktop/desktop-hyprland.nix ../../services/desktop/desktop-apps.nix @@ -28,21 +24,27 @@ in enable = true; remotes = [{ name = "flathub"; location = "https://dl.flathub.org/repo/flathub.flatpakrepo"; }]; packages = [ + { appId = "com.github.tchx84.Flatseal"; origin = "flathub"; } { appId = "com.blitzfc.qbz"; origin = "flathub"; } { appId = "com.discordapp.Discord"; origin = "flathub"; } { appId = "org.telegram.desktop"; origin = "flathub"; } + { appId = "com.bambulab.BambuStudio"; origin = "flathub"; } ]; }; - # Proton Pass CLI — in nixpkgs-unstable (2.2.3+); scripts/deploy uses it to - # autofill sudo/ssh passwords from the "HomeLab" vault. environment.systemPackages = [ unstable.proton-pass-cli ]; + # ---- nix-ld: lets generic dynamically-linked Linux binaries run as-is — + # needed for editor extensions (Zed/VSCode LSPs, debuggers, etc.) that + # download prebuilt binaries not built for NixOS. See + # https://nix.dev/permalink/stub-ld ---- + programs.nix-ld.enable = true; + # ---- home-manager (user-level config for darman) ---- home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; home-manager.backupFileExtension = "hm-bak"; - home-manager.extraSpecialArgs = { inherit unstable; }; + home-manager.extraSpecialArgs = { inherit unstable inputs; }; home-manager.users.darman = import ./home.nix; # ---- Boot (UEFI) ---- @@ -50,20 +52,17 @@ in boot.loader.efi.canTouchEfiVariables = true; hardware.cpu.amd.updateMicrocode = true; + # mercury (aarch64) is built/flashed from here. Without this, `nix build` + # for it dies with "platform mismatch" — no qemu binfmt handler registered + # and aarch64-linux missing from nix.settings.extra-platforms. This module + # sets up both (see CLAUDE.md's aarch64 gotcha). + boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; + # ---- GPU (Radeon RX 6800 XT / Navi 21) ---- - # amdgpu needs the redistributable navi21 firmware blobs to bind the card. - # Without them the module loads but never initialises the GPU: there's no - # DRM card for it, the display falls back to the 1024x768 EFI - # simple-framebuffer as "Unknown-1", and the real DP-2/HDMI-A-1 outputs - # never appear — so hyprland's monitor rules match nothing. hardware.enableRedistributableFirmware = true; - # Early KMS: bind amdgpu in the initrd so it drives the console + greeter - # from boot instead of handing over from simple-framebuffer later. boot.initrd.kernelModules = [ "amdgpu" ]; # ---- Dev-data disks — NOT in disko, mounted read-write, never wiped ---- - # UUIDs captured from the running CachyOS box; verify after install - # (`lsblk -o NAME,UUID,MOUNTPOINT`) in case disko/kernel enumerates differently. fileSystems."/mnt/hdd_01" = { device = "/dev/disk/by-uuid/b8445126-ec6d-4f88-818a-d9e13031d9a4"; fsType = "ext4"; @@ -75,5 +74,22 @@ in options = [ "nofail" ]; }; + # jupiter's samba share (services/network/samba.nix) — mounted on demand so + # terra doesn't stall boot/login when jupiter is off or unreachable. + fileSystems."/mnt/jupiter" = { + device = "//jupiter/data"; + fsType = "cifs"; + options = [ + "credentials=${config.sops.templates."jupiter-smb.credentials".path}" + "uid=1000" + "gid=100" + "nofail" + "x-systemd.automount" + "x-systemd.idle-timeout=60" + "x-systemd.mount-timeout=10s" + "_netdev" + ]; + }; + system.stateVersion = "26.05"; } diff --git a/hosts/terra/home.nix b/hosts/terra/home.nix index cf31665..f51f184 100644 --- a/hosts/terra/home.nix +++ b/hosts/terra/home.nix @@ -1,83 +1,56 @@ { pkgs, unstable, ... }: -# home-manager profile for darman on terra. The Hyprland config lives in its -# own module (./hyprland.nix); this handles the rest of the user session -# (theming, terminal, packages). { - imports = [ ./home/hyprland.nix ]; + imports = [ ./home/hyprland.nix ./home/theme.nix ]; home.stateVersion = "26.05"; home.keyboard.layout = "de"; - programs.git.enable = true; - programs.home-manager.enable = true; - - # Give darman a managed ~/.zshrc. Without any zsh dotfile, zsh runs its - # first-run `zsh-newuser-install` prompt on every new terminal. oh-my-zsh + - # powerlevel10k still come from the system /etc/zshrc (common.nix), which - # always loads for interactive shells before this ~/.zshrc. - programs.zsh.enable = true; - - # ---- Dracula theming (GTK + Qt) ---- - gtk = { + programs.git = { enable = true; - theme = { - name = "Dracula"; - package = pkgs.dracula-theme; + settings = { + user.name = "Erik Simon"; + user.email = "mail@erik-s.dev"; }; }; + programs.home-manager.enable = true; - # GTK4 / libadwaita apps ignore gtk-theme-name; they only read the dconf - # color-scheme key via the portal. Writing it here persists it across reboots - # (the gsettings call in the Hyprland autostart only lasts the session). - dconf.settings."org/gnome/desktop/interface" = { - color-scheme = "prefer-dark"; - gtk-theme = "Dracula"; - }; + programs.zsh.enable = true; - # dracula-qt5-theme ships only a qt5ct color scheme (no style plugin), so - # Qt has to go through qt(5|6)ct rather than a direct style/platformTheme - # name. "qtct" pulls in both qt5ct and qt6ct; qt6ct reads its own config - # but understands the same scheme file format, so both point at it. - qt = { + xdg.userDirs = { enable = true; - platformTheme.name = "qtct"; }; - xdg.configFile."qt5ct/qt5ct.conf".text = '' - [Appearance] - color_scheme_path=${pkgs.dracula-qt5-theme}/share/qt5ct/colors/Dracula.conf - custom_palette=true - style=Fusion - ''; - xdg.configFile."qt6ct/qt6ct.conf".text = '' - [Appearance] - color_scheme_path=${pkgs.dracula-qt5-theme}/share/qt5ct/colors/Dracula.conf - custom_palette=true - style=Fusion - ''; - # Custom mime-info defs (sln/slnx). xdg.mime's update-mime-database only - # indexes share/mime/packages inside the hm profile itself, so this has to - # be a package in home.packages, not a plain xdg.dataFile. xdg.mime.enable = true; xdg.configFile."quickshell".source = ../../dotfiles/quickshell; xdg.configFile."scripts".source = ../../dotfiles/scripts; + home.packages = [ (pkgs.writeTextDir "share/mime/packages/application-x-ms-sln.xml" (builtins.readFile ../../dotfiles/mime/application-x-ms-sln.xml)) unstable.claude-code - pkgs.quickshell pkgs.opencode + pkgs.quickshell + pkgs.github-cli + pkgs.tea pkgs.hyprcursor pkgs.bibata-cursors + pkgs.papirus-icon-theme ]; + xdg.desktopEntries.btop = { + name = "btop++"; + genericName = "System Monitor"; + exec = "btop"; + icon = "btop"; + terminal = true; + categories = [ "System" "Monitor" ]; + noDisplay = true; + }; + programs.alacritty = { enable = true; settings = { - # NixOS has no /bin/zsh (only /bin/sh); point at the real store path or - # alacritty exits instantly trying to exec a missing shell — which looked - # like "the SUPER+Return keybind doesn't work". env.SHELL = "${pkgs.zsh}/bin/zsh"; terminal.shell = { program = "${pkgs.zsh}/bin/zsh"; @@ -92,7 +65,7 @@ style = "Regular"; }; colors.primary = { - background = "#222831"; + background = "#0F1012"; foreground = "#ffd369"; }; # hints.enabled = [ diff --git a/hosts/terra/home/hyprland.nix b/hosts/terra/home/hyprland.nix index b64aa2b..220062d 100644 --- a/hosts/terra/home/hyprland.nix +++ b/hosts/terra/home/hyprland.nix @@ -1,4 +1,4 @@ -{ lib, ... }: +{ lib, pkgs, config, inputs, ... }: # Hyprland config migrated from github.com/darman96/hyprland-dotfiles (the # hyprlang `hypr/*.conf` files) into the home-manager lua-style `settings` @@ -12,10 +12,12 @@ # own hyprland.lua. # # Deliberately NOT migrated: -# - hyprbars.conf / hyprredsquare.conf: config for the third-party plugins -# `hyprbevelbars` + `hyprredsquare`, which aren't packaged in nixpkgs. Load -# the plugins via `wayland.windowManager.hyprland.plugins` and re-add their -# config once they're available. +# - hyprbars.conf: config for the third-party `hyprbevelbars` plugin, which +# isn't packaged in nixpkgs. Load it via +# `wayland.windowManager.hyprland.plugins` and re-add its config once +# available. (hyprredsquare.conf's plugin was renamed hypr-chrome and +# rewritten since - it's wired in below via the `hypr-chrome` flake +# input instead, with its own `plugin.hyprchrome` config.) # - hyprqt6engine.conf + `QT_QPA_PLATFORMTHEME=hyprqt6engine`: terra themes Qt # through qtct/Dracula in home.nix, so that env var is left off to avoid a conflict. # - hyprlock.conf: a separate program (use `programs.hyprlock` if wanted). @@ -29,28 +31,35 @@ let lua = lib.generators.mkLuaInline; + # Wallpaper images aren't checked into this repo (binary blobs) — pulled + # from the existing Wallhaven library on /mnt/hdd_01 instead. Picked once + # here rather than at runtime, since hyprpaper has no built-in "random" + # mode; re-pick and rebuild (or swap in real per-monitor selection) when + # this stops being a placeholder. + wallpaper = "/mnt/hdd_01/data/Pictures/Wallhaven/wallhaven-g7jg63.png"; + # Dispatchers → the new hl.dsp.* API (signatures verified against hyprland # 0.55's src/config/lua/bindings/LuaBindingsDispatchers.cpp). dsp = { - exec = cmd: lua ''hl.dsp.exec_cmd("${cmd}")''; - global = name: lua ''hl.dsp.global("${name}")''; - exit = lua "hl.dsp.exit()"; - killactive = lua "hl.dsp.window.close()"; - togglefloating = lua ''hl.dsp.window.float({ action = "toggle" })''; - fullscreen = lua "hl.dsp.window.fullscreen()"; # mode 0 - maximize = lua ''hl.dsp.window.fullscreen({ mode = "maximized" })''; # mode 1 + exec = cmd: lua ''hl.dsp.exec_cmd("${cmd}")''; + global = name: lua ''hl.dsp.global("${name}")''; + exit = lua "hl.dsp.exit()"; + killactive = lua "hl.dsp.window.close()"; + togglefloating = lua ''hl.dsp.window.float({ action = "toggle" })''; + fullscreen = lua "hl.dsp.window.fullscreen()"; # mode 0 + maximize = lua ''hl.dsp.window.fullscreen({ mode = "maximized" })''; # mode 1 togglegroup = lua "hl.dsp.group.toggle()"; changegroupactive = lua "hl.dsp.group.next()"; - drag = lua "hl.dsp.window.drag()"; - resizemouse = lua "hl.dsp.window.resize()"; - movefocus = dir: lua ''hl.dsp.focus({ direction = "${dir}" })''; - movewindow = dir: lua ''hl.dsp.window.move({ direction = "${dir}" })''; - resizeactive = x: y: + drag = lua "hl.dsp.window.drag()"; + resizemouse = lua "hl.dsp.window.resize()"; + movefocus = dir: lua ''hl.dsp.focus({ direction = "${dir}" })''; + movewindow = dir: lua ''hl.dsp.window.move({ direction = "${dir}" })''; + resizeactive = x: y: lua ''hl.dsp.window.resize({ x = ${toString x}, y = ${toString y}, relative = true })''; - workspace = n: lua ''hl.dsp.focus({ workspace = ${toString n} })''; - workspaceRef = s: lua ''hl.dsp.focus({ workspace = "${s}" })''; - movetoworkspace = n: lua ''hl.dsp.window.move({ workspace = ${toString n} })''; - togglespecial = name: lua ''hl.dsp.workspace.toggle_special("${name}")''; + workspace = n: lua ''hl.dsp.focus({ workspace = ${toString n} })''; + workspaceRef = s: lua ''hl.dsp.focus({ workspace = "${s}" })''; + movetoworkspace = n: lua ''hl.dsp.window.move({ workspace = ${toString n} })''; + togglespecial = name: lua ''hl.dsp.workspace.toggle_special("${name}")''; }; bind = keys: dispatcher: { _args = [ keys dispatcher ]; }; @@ -65,14 +74,28 @@ let ]; in { + services.hyprpaper = { + enable = true; + settings = { + ipc = "on"; + splash = false; + preload = [ wallpaper ]; + wallpaper = [ + { monitor = "DP-2"; path = wallpaper; } + { monitor = "HDMI-A-1"; path = wallpaper; } + ]; + }; + }; + wayland.windowManager.hyprland = { enable = true; + plugins = [ inputs.hypr-chrome.packages.${pkgs.stdenv.hostPlatform.system}.default ]; settings = { # ---- colours (from colors.conf) ---- fg_color = { _var = "rgba(eeeeeeff)"; }; fg_accent = { _var = "rgba(FFD063ff)"; }; bg_color = { _var = "rgba(0F1012ff)"; }; - bg_accent = { _var = "rgba(292C30ff)"; }; + bg_accent = { _var = "rgba(40382fff)"; }; # ---- monitors ---- monitor = [ @@ -95,7 +118,15 @@ in border_size = 1; col = { inactive_border = lua "bg_accent"; - active_border = lua "fg_accent"; + # Gradient: hyprland's lua gradient type (CLuaConfigGradient::parse) + # takes either a plain colour string or a table with a `colors` + # array (1+ entries) and an optional `angle` in DEGREES. The list + # entries may be literal "rgba(...)" strings or, as here, the + # `_var` locals declared above rendered raw via mkLuaInline. + active_border = { + colors = [ (lua "fg_accent") (lua "bg_accent") ]; + angle = 45; + }; }; layout = "dwindle"; gaps_in = 4; @@ -130,6 +161,8 @@ in workspace_back_and_forth = true; allow_workspace_cycles = true; }; + + plugin.hyprchrome.enabled = true; }; # ---- animations ---- @@ -150,6 +183,7 @@ in { _args = [ "XDG_CURRENT_DESKTOP" "Hyprland" ]; } { _args = [ "XDG_SESSION_DESKTOP" "Hyprland" ]; } { _args = [ "XDG_SESSION_TYPE" "wayland" ]; } + { _args = [ "QT_QPA_PLATFORMTHEME" "qt6ct" ]; } ]; # ---- keybinds (keybinds.conf) ---- @@ -167,10 +201,11 @@ in (bind "SUPER + CTRL + S" (dsp.global "quickshell:sidebar")) (bind "SUPER + B" (dsp.exec "vivaldi")) - (bind "SUPER + E" (dsp.exec "dolphin")) + (bind "SUPER + E" (dsp.exec "cosmic-files")) (bind "SUPER + SHIFT + G" (dsp.workspaceRef "game")) (bind "SUPER + S" (dsp.exec "grim -o DP-2 ~/screenshot.png")) (bind "SUPER + SHIFT + S" (dsp.exec "grimblast copy area --freeze")) + (bind "Print" (dsp.exec "rishot")) (bind "SUPER + L" (dsp.exec "hyprlock")) (bind "SUPER + W" (dsp.exec "waypaper --random")) @@ -245,7 +280,7 @@ in workspace_rule = [ { workspace = "name:game"; monitor = "DP-2"; decorate = false; } { workspace = "special:terminal"; on_created_empty = "alacritty"; gaps_out = 256; } - { workspace = "special:communications"; on_created_empty = "$HOME/.config/scripts/start-communications.sh"; gaps_out = 128; } + { workspace = "special:communications"; on_created_empty = "${config.home.homeDirectory}/.config/scripts/start-communications.sh"; gaps_out = 128; } { workspace = "special:music"; on_created_empty = "com.blitzfc.qbz"; gaps_out = 128; } { workspace = "special:version_control"; on_created_empty = "com.axosoft.GitKraken"; gaps_out = 128; } ]; @@ -257,7 +292,7 @@ in (lua '' function() hl.exec_cmd("systemctl --user start hyprpolkitagent") - hl.exec_cmd("vicinae server") + hl.exec_cmd("cosmic-settings-daemon") hl.exec_cmd("quickshell") hl.exec_cmd("alacritty", { workspace = "special:terminal silent" }) hl.exec_cmd("kbuildsycoca6 --noincremental") @@ -266,4 +301,6 @@ in }; }; }; + + xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-cosmic ]; } diff --git a/hosts/terra/home/theme.nix b/hosts/terra/home/theme.nix new file mode 100644 index 0000000..396200a --- /dev/null +++ b/hosts/terra/home/theme.nix @@ -0,0 +1,70 @@ +{ pkgs, ... }: + +# Global Dracula theming (GTK + Qt) +let + azureGlassyDarkIcons = pkgs.callPackage ../../../pkgs/azure-glassy-dark-icons.nix { }; + amyDarkIcons = pkgs.callPackage ../../../pkgs/amy-dark-icons.nix { }; + slotBeautyDarkIcons = pkgs.callPackage ../../../pkgs/slot-beauty-dark-icons.nix { }; + + iconTheme = "Amy-Dark-Icons"; + iconThemePackage = amyDarkIcons; + iconThemeFolder = "${iconThemePackage}/share/icons/${iconTheme}"; +in +{ + gtk = { + enable = true; + theme = { + name = "Dracula"; + package = pkgs.dracula-theme; + }; + iconTheme = { + name = iconTheme; + package = iconThemePackage; + }; + }; + + # Flatpak apps are sandboxed and can't see XDG_DATA_DIRS/nix-store theme + # paths, so the portal-reported GTK theme / icon theme names resolve to + # nothing inside the sandbox and they fall back to Adwaita. Flatpak + # auto-exposes ~/.themes and ~/.icons read-only to every sandboxed app + # specifically for this case. + home.file.".themes/Dracula".source = + "${pkgs.dracula-theme}/share/themes/Dracula"; + home.file.".icons/${iconTheme}".source = iconThemeFolder; + + dconf.settings."org/gnome/desktop/interface" = { + color-scheme = "prefer-dark"; + gtk-theme = "Dracula"; + icon-theme = iconTheme; + }; + + # "qtct" (qt5ct/qt6ct) instead of "kde" avoids pulling in + # kdePackages.systemsettings just for the platform-theme plugin — kvantum + # itself carries the Dracula colors, qt5ct/qt6ct just need to be told to + # use it as the style. + qt = { + enable = true; + platformTheme.name = "qtct"; + style.name = "kvantum"; + }; + xdg.configFile."Kvantum/kvantum.kvconfig".text = '' + [General] + theme=Dracula + ''; + xdg.configFile."Kvantum/Dracula".source = + "${pkgs.dracula-theme}/share/Kvantum/Dracula"; + + # Quickshell's IconImage/Quickshell.iconPath() resolves icons through the + # Qt platform theme, not GTK — so the app-launcher grid needs the icon + # theme set HERE (qt5ct/qt6ct), separately from the GTK dconf key above. + xdg.configFile."qt5ct/qt5ct.conf".text = '' + [Appearance] + style=kvantum + icon_theme=${iconTheme} + ''; + xdg.configFile."qt6ct/qt6ct.conf".text = '' + [Appearance] + style=kvantum + icon_theme=${iconTheme} + ''; +} diff --git a/hosts/terra/secrets.nix b/hosts/terra/secrets.nix index 3e34d09..3edce2a 100644 --- a/hosts/terra/secrets.nix +++ b/hosts/terra/secrets.nix @@ -12,4 +12,13 @@ sops.secrets.darman_password.neededForUsers = true; users.users.darman.hashedPasswordFile = config.sops.secrets.darman_password.path; + + # Credentials file for the //jupiter/data cifs mount (see configuration.nix). + # samba_password mirrors jupiter's own samba_password secret (services/network/samba.nix) — + # same value, just also encrypted to terra so it can authenticate as the same smb user. + sops.secrets.samba_password = { }; + sops.templates."jupiter-smb.credentials".content = '' + username=darman + password=${config.sops.placeholder.samba_password} + ''; } diff --git a/pkgs/amy-dark-icons.nix b/pkgs/amy-dark-icons.nix new file mode 100644 index 0000000..17b2176 --- /dev/null +++ b/pkgs/amy-dark-icons.nix @@ -0,0 +1,43 @@ +{ lib, stdenvNoCC, gtk3 }: + +# Amy-Dark-Icons (gnome-look.org/p/2011598), not packaged in nixpkgs. +# gnome-look/pling download links are signed JWTs that expire in ~2 days, so +# fetchurl against one would work today and fail on the next rebuild after +# that window — the tarball is vendored into the repo instead, as verified +# (md5 51bae6972100a36151edd660ba7bf3fa against the gnome-look API's +# reported checksum) at dotfiles/icons/Amy-Dark-Icons.tar.xz. +stdenvNoCC.mkDerivation { + pname = "amy-dark-icons"; + version = "unstable-2026-07-12"; + + src = ../dotfiles/icons/Amy-Dark-Icons.tar.xz; + + nativeBuildInputs = [ gtk3 ]; + + dontBuild = true; + + # Upstream ships dozens of dangling symlinks (icons aliased across sizes + # that don't all exist) — same class of minor packaging bug as + # azure-glassy-dark-icons. Harmless: GTK/Qt icon lookup falls through to + # the theme's own Inherits= chain (breeze, hicolor, Adwaita) for those. + dontCheckForBrokenSymlinks = true; + + # gtk3's setup hook strips icon-theme.cache from $out by default + # (postFixup); opt back out, matching nixpkgs' papirus-icon-theme. + dontDropIconThemeCache = true; + + installPhase = '' + runHook preInstall + mkdir -p "$out/share/icons" + cp -r . "$out/share/icons/Amy-Dark-Icons" + gtk-update-icon-cache --force "$out/share/icons/Amy-Dark-Icons" + runHook postInstall + ''; + + meta = { + description = "Amy dark icon theme, vendored from gnome-look.org (not packaged in nixpkgs)"; + homepage = "https://www.gnome-look.org/p/2011598"; + license = lib.licenses.gpl3Only; + platforms = lib.platforms.all; + }; +} diff --git a/pkgs/azure-glassy-dark-icons.nix b/pkgs/azure-glassy-dark-icons.nix new file mode 100644 index 0000000..ca6cee4 --- /dev/null +++ b/pkgs/azure-glassy-dark-icons.nix @@ -0,0 +1,48 @@ +{ lib, stdenvNoCC, gtk3 }: + +# Azure-Glassy-Dark-Icons (gnome-look.org/p/2154036), not packaged in +# nixpkgs. gnome-look/pling download links are signed JWTs that expire in +# ~2 days (`exp` claim on the URL was ~48h out from issuance) — fetchurl +# against one would work today and fail on the next rebuild after that +# window with no warning. The tarball is vendored into the repo instead, as +# verified (md5 d218b358086ee7f68cb5e98c53e9efaf against the gnome-look API's +# reported checksum) at dotfiles/icons/Azure-Glassy-Dark-Icons.tar.xz. +stdenvNoCC.mkDerivation { + pname = "azure-glassy-dark-icons"; + version = "unstable-2026-07-12"; + + src = ../dotfiles/icons/Azure-Glassy-Dark-Icons.tar.xz; + + nativeBuildInputs = [ gtk3 ]; + + dontBuild = true; + + # Upstream ships a handful of dangling symlinks under mimetypes/16 (e.g. + # libreoffice-spreadsheet.svg -> libreoffice-oasis-spreadsheet.svg, which + # doesn't exist in that size dir) — a minor packaging bug in the theme + # itself. Harmless: GTK's icon lookup just falls through to the theme's + # own Inherits= chain (breeze-dark, breeze, Adwaita, hicolor) for those few + # mimetypes. Nixpkgs' default noBrokenSymlinks fixup check would otherwise + # fail the whole build over it. + dontCheckForBrokenSymlinks = true; + + # gtk3's setup hook strips icon-theme.cache from $out by default + # (postFixup); papirus-icon-theme opts back out the same way rather than + # let the freshly regenerated cache get thrown away. + dontDropIconThemeCache = true; + + installPhase = '' + runHook preInstall + mkdir -p "$out/share/icons" + cp -r . "$out/share/icons/Azure-Glassy-Dark-Icons" + gtk-update-icon-cache --force "$out/share/icons/Azure-Glassy-Dark-Icons" + runHook postInstall + ''; + + meta = { + description = "Azure-Glassy dark icon theme, vendored from gnome-look.org (not packaged in nixpkgs)"; + homepage = "https://www.gnome-look.org/p/2154036"; + license = lib.licenses.gpl3Only; + platforms = lib.platforms.all; + }; +} diff --git a/pkgs/rishot.nix b/pkgs/rishot.nix index c45c2ec..6694d62 100644 --- a/pkgs/rishot.nix +++ b/pkgs/rishot.nix @@ -9,6 +9,7 @@ , curl , kdePackages , libnotify +, qt6 }: # Wayland screenshot + annotation overlay, driven entirely by quickshell (qs -p @@ -16,6 +17,11 @@ # plus src/*.qml, no nixpkgs package exists. bin/rishot resolves its QML dir at # $self/../src by default, which breaks once wrapProgram rewrites argv0; setting # RISHOT_CONFIG_DIR sidesteps that self-lookup entirely (see bin/rishot upstream). +# +# Overlay.qml imports Qt5Compat.GraphicalEffects, which quickshell's own Qt +# runtime doesn't ship — without qt5compat on the QML import path, `qs` +# fails at config-load with "module Qt5Compat.GraphicalEffects is not +# installed" and rishot exits 255 before ever drawing anything. stdenvNoCC.mkDerivation (finalAttrs: { pname = "rishot"; version = "0-unstable-2026-07-10"; @@ -52,7 +58,9 @@ stdenvNoCC.mkDerivation (finalAttrs: { curl kdePackages.kdialog libnotify - ]} + ]} \ + --prefix QML_IMPORT_PATH : "${qt6.qt5compat}/lib/qt-6/qml" \ + --prefix QML2_IMPORT_PATH : "${qt6.qt5compat}/lib/qt-6/qml" runHook postInstall ''; diff --git a/pkgs/slot-beauty-dark-icons.nix b/pkgs/slot-beauty-dark-icons.nix new file mode 100644 index 0000000..8c65478 --- /dev/null +++ b/pkgs/slot-beauty-dark-icons.nix @@ -0,0 +1,46 @@ +{ lib, stdenvNoCC }: + +# Slot Beauty Dark Icons (gnome-look.org/p/2346341), not packaged in +# nixpkgs. gnome-look/pling download links are signed JWTs that expire in +# ~2 days, so fetchurl against one would work today and fail on the next +# rebuild after that window — the tarball is vendored into the repo instead, +# as verified (md5 8b3e3e1e03c667b7f988b78ad2bc18a6 against the gnome-look +# API's reported checksum) at +# dotfiles/icons/Slot-Beauty-Dark-Icons-V-2.tar.xz. +stdenvNoCC.mkDerivation { + pname = "slot-beauty-dark-icons"; + version = "unstable-2026-07-24"; + + src = ../dotfiles/icons/Slot-Beauty-Dark-Icons-V-2.tar.xz; + + dontBuild = true; + + # Upstream ships dozens of dangling symlinks (icons aliased across sizes + # that don't all exist) — same class of minor packaging bug as + # azure-glassy-dark-icons. Harmless: GTK/Qt icon lookup falls through to + # the theme's own Inherits= chain (breeze-dark, Adwaita, hicolor) for those. + dontCheckForBrokenSymlinks = true; + + # index.theme's Directories= lists panel/16@2, panel/22@2, panel/24@2 (with + # Scale=2), but the actual on-disk dirs are named 16@2x/22@2x/24@2x (the + # correct freedesktop-spec suffix) — an upstream index.theme typo. That + # mismatch makes `gtk-update-icon-cache` refuse to emit ANY cache at all + # (exits 1, "The generated cache was invalid"), so unlike the other vendored + # themes here, this one ships with no icon-theme.cache and relies on GTK's + # live directory-scan lookup instead — functionally fine, just not + # cache-accelerated. gtk3's default postFixup hook (dropIconThemeCache) + # would strip a cache anyway, so there's nothing to opt out of. + installPhase = '' + runHook preInstall + mkdir -p "$out/share/icons" + cp -r . "$out/share/icons/Slot-Beauty-Dark-Icons-V-2" + runHook postInstall + ''; + + meta = { + description = "Slot Beauty dark icon theme, vendored from gnome-look.org (not packaged in nixpkgs)"; + homepage = "https://www.gnome-look.org/p/2346341"; + license = lib.licenses.gpl3Only; + platforms = lib.platforms.all; + }; +} diff --git a/secrets/terra.yaml b/secrets/terra.yaml index 388d5c7..5b3fc27 100644 --- a/secrets/terra.yaml +++ b/secrets/terra.yaml @@ -1,5 +1,6 @@ tailscale_authkey: ENC[AES256_GCM,data:DgxbMrKTxC//cWd+ZckCbwZ9j/FgjYwNwadU5cWnnPz+nPEFhXLla2TuUE0pJKpcx9pKZCQmxcGtzQvIB+mbgxjgB0X2CRTp4Yy3WR+PBYMghKx36F8KBg==,iv:hJr6O41OTdMa4wkBXEsRUXgV4zWt21h1kx/CWArLU7o=,tag:IEpMIwKBHakvVYEFdEUe7A==,type:str] darman_password: ENC[AES256_GCM,data:G3ZM+NMxvKq5twblcBvyC+MiUX+X7nz+s1GqBHBkJQy1YgW4KN6rpbdj10F9jWxHph5dJ9j9fG6L7UlEg5W5zUYeLFdEx2xJGE1fxksch+6BB9FT6LKkhJ7MmbJmhNHYwJOZO3LM1f/oRw==,iv:abQTRe9kRyYj+TL0rtoxM6JFBaIBmxu7y77qt1h4eME=,tag:OgKrB3SUgSNJjmtJyrmh/Q==,type:str] +samba_password: ENC[AES256_GCM,data:UkJLUa2hW1iZ++sfJAcg6G1RJMM=,iv:/HbZ9F+GxCydUP50PNBtJknPlmDWh1DAE26N9FJUyb0=,tag:z1cbwUaVdyfwEIU8LINEcw==,type:str] sops: age: - enc: | @@ -20,7 +21,7 @@ sops: sHjKfw8VrrmAR4pQf1dsY+wcyh4FsZxhP3Q+QIVq3eCIXS9PeJkGAg== -----END AGE ENCRYPTED FILE----- recipient: age1rfcmu6zh40v4260l9hnf8ajs9vly0s06rx3ey76eu78dp9t7getqyhmkut - lastmodified: "2026-07-24T23:30:39Z" - mac: ENC[AES256_GCM,data:JaBDewUFFEiGnigXsUjAaIEiz1FI6N17pMQT/7qBpA6rtrUoatzjEkl2rpENXuSh0cGI2p328u8tvqDkgel7pGFLY+fYuYgOv6tOSbCgeZM939FrT1P3T4evTcyCUDyAS0NFYEvge83zjW6mula0HY2AsKN1PHaj4XeKLETNvH8=,iv:pBct6RALFuYRUe2EqCSpUPxJ9/7dMt4O2VMZUUjrJks=,tag:UsGTnEbQzp1v8pVb0j2itw==,type:str] + lastmodified: "2026-07-28T20:18:44Z" + mac: ENC[AES256_GCM,data:TRh/Idd8MEq/5QRb7r+g6msdaObtVzsX5hK5gacJI6seZ5BLW5tcBO/E2m8ya4t50lTofxkwObWskMbCOucLDYt+lnYwHSqDvAeQRvswxaCZgiFOn0upqCi8H4OomvIK475SIH6bniyN9bCQ2gaSS0D9aecyCSmdUARkmcZEYLc=,iv:PBoEUZG0QNyj4B0c6zuWr6Y39EdL1CoAsVExU86P6Tw=,tag:NPxsWkxdojXNsoxVVMb5TQ==,type:str] unencrypted_suffix: _unencrypted version: 3.13.2 diff --git a/services/desktop/desktop-apps.nix b/services/desktop/desktop-apps.nix index 20d6ad6..630a7b3 100644 --- a/services/desktop/desktop-apps.nix +++ b/services/desktop/desktop-apps.nix @@ -24,16 +24,20 @@ in enable = true; remotePlay.openFirewall = true; dedicatedServer.openFirewall = false; + gamescopeSession.enable = true; + extraCompatPackages = [ pkgs.proton-ge-bin ]; }; hardware.graphics.enable32Bit = true; environment.systemPackages = with pkgs; [ alacritty zed-editor - protonplus gitkraken jetbrains-toolbox - kdePackages.dolphin + cosmic-settings-daemon + cosmic-settings + cosmic-icons + cosmic-files vivaldi rishot jq diff --git a/services/desktop/desktop-hyprland.nix b/services/desktop/desktop-hyprland.nix index f95cd7c..7ba7725 100644 --- a/services/desktop/desktop-hyprland.nix +++ b/services/desktop/desktop-hyprland.nix @@ -1,7 +1,6 @@ { pkgs, ... }: # Hyprland (wayland) desktop: compositor, login manager, audio, portals. -# Reusable for any host that wants a local GUI session (currently: terra). { programs.hyprland.enable = true; @@ -23,10 +22,10 @@ pulse.enable = true; }; - # Screen-share / file-picker portals for wayland apps. xdg.portal = { enable = true; - extraPortals = [ pkgs.xdg-desktop-portal-hyprland ]; + extraPortals = [ pkgs.xdg-desktop-portal-hyprland pkgs.xdg-desktop-portal-cosmic ]; + config.common.default = [ "hyprland" "cosmic" ]; }; hardware.graphics.enable = true; # OpenGL/Vulkan for the compositor + apps