Compare commits
94 Commits
59a0e500f2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d101b23351 | |||
| e6b7f53794 | |||
| 806841d435 | |||
| f9f73db10f | |||
| dbc2997de0 | |||
| dc47d1a6ec | |||
| 952776c4f9 | |||
| f4d60d387e | |||
| 1e8b0d4ab0 | |||
| 7b6ba3b0d1 | |||
| aef7f64b59 | |||
| 0064170430 | |||
| 39094ee026 | |||
| d5c1b8a155 | |||
| 8aaf7cae5b | |||
| 89c3a9261e | |||
| e4ea267b6b | |||
| 8485a63ab7 | |||
| 6e14258ad9 | |||
| 9432bc4831 | |||
| 373bfd4a9b | |||
| c2cee85488 | |||
| 971a6eb577 | |||
| 0a38347cb9 | |||
| f4f6ede2a7 | |||
| ee85b87d3a | |||
| fcac91b540 | |||
| 324dda0548 | |||
| 0433f08f08 | |||
| 9bc753e092 | |||
| a360d12bde | |||
| 97e4b81930 | |||
| b8753bf84f | |||
| a55c7ea9d1 | |||
| ab066724f0 | |||
| 2363e76b4a | |||
| 4dd8aae2f0 | |||
| 47ae8d5d51 | |||
| 4c609135e9 | |||
| f6869c9cea | |||
| 48b0de071e | |||
| b6beabe500 | |||
| 8ddbb23851 | |||
| 46ba8365db | |||
| d815e21b1d | |||
| 6d3a7c8d72 | |||
| ac2b210a1f | |||
| e1e80ca414 | |||
| 579a948449 | |||
| 6a258151fa | |||
| 037d311607 | |||
| 2b8e40f37f | |||
| ef8ff7099f | |||
| 7a2b1ece05 | |||
| 62495d8e3d | |||
| 76f5602b47 | |||
| 466ba773dc | |||
| 9f994d03fb | |||
| 80c395fc14 | |||
| 25baf88a2a | |||
| 29550b8a14 | |||
| 27247a4ffb | |||
| fdedc8071f | |||
| 0fba63571c | |||
| 23a14e95d5 | |||
| 52a49bfcc3 | |||
| 047ff53091 | |||
| 24b81df63c | |||
| 1004a0b986 | |||
| ba4a413097 | |||
| cf9eae1edc | |||
| 8faca0ed48 | |||
| 7f06c8e501 | |||
| 93ff264824 | |||
| d4eec1c506 | |||
| 6b21b6d50c | |||
| 997f7d90a0 | |||
| 3673b22009 | |||
| 7f509eff95 | |||
| 8c7e9407c6 | |||
| 7cd34f2ace | |||
| aa1567487f | |||
| 5b37bfe525 | |||
| 1e19f08776 | |||
| 491a3cd3e2 | |||
| 077e852b3b | |||
| ca7f9bb79e | |||
| f2a28f8577 | |||
| 684d54e0c2 | |||
| 3acb71a210 | |||
| 4eca6190f2 | |||
| c011672bc2 | |||
| 9dde069e3e | |||
| f5d199fa5a |
@@ -0,0 +1,61 @@
|
|||||||
|
# ABOUTME: Updates pkgver in moonarch-pkgbuilds after a push to main.
|
||||||
|
# ABOUTME: Ensures paru detects new versions of this package.
|
||||||
|
|
||||||
|
name: Update PKGBUILD version
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
# Only files that the moonarch-git PKGBUILD actually packages.
|
||||||
|
# README.md, DECISIONS.md, scripts/post-install.sh, scripts/lib.sh,
|
||||||
|
# CI workflow edits, etc. don't change the built package and must
|
||||||
|
# not trigger a rebuild.
|
||||||
|
- 'defaults/**'
|
||||||
|
- 'packages/**'
|
||||||
|
- 'scripts/moonarch-update'
|
||||||
|
- 'scripts/moonarch-doctor'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-pkgver:
|
||||||
|
runs-on: moonarch
|
||||||
|
steps:
|
||||||
|
- name: Checkout source repo
|
||||||
|
run: |
|
||||||
|
git clone --bare https://gitea.moonarch.de/nevaforget/moonarch.git source.git
|
||||||
|
cd source.git
|
||||||
|
PKGVER=$(printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)")
|
||||||
|
echo "New pkgver: $PKGVER"
|
||||||
|
echo "$PKGVER" > /tmp/pkgver
|
||||||
|
|
||||||
|
- name: Update PKGBUILD
|
||||||
|
env:
|
||||||
|
PKGBUILD_TOKEN: ${{ secrets.PKGBUILD_TOKEN }}
|
||||||
|
run: |
|
||||||
|
PKGVER=$(cat /tmp/pkgver)
|
||||||
|
git clone https://gitea.moonarch.de/nevaforget/moonarch-pkgbuilds.git pkgbuilds
|
||||||
|
cd pkgbuilds
|
||||||
|
|
||||||
|
OLD_VER=$(grep '^pkgver=' moonarch-git/PKGBUILD | cut -d= -f2)
|
||||||
|
if [ "$OLD_VER" = "$PKGVER" ]; then
|
||||||
|
echo "pkgver already up to date ($PKGVER)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -i "s/^pkgver=.*/pkgver=$PKGVER/" moonarch-git/PKGBUILD
|
||||||
|
echo "Updated pkgver: $OLD_VER → $PKGVER"
|
||||||
|
|
||||||
|
git config user.name "pkgver-bot"
|
||||||
|
git config user.email "gitea@moonarch.de"
|
||||||
|
git add moonarch-git/PKGBUILD
|
||||||
|
git commit -m "chore(moonarch-git): bump pkgver to $PKGVER"
|
||||||
|
|
||||||
|
# Push via credential helper with a chmod 600 temp file, so the token
|
||||||
|
# never appears in /proc/PID/cmdline (as it would with `git -c
|
||||||
|
# http.extraHeader=...`).
|
||||||
|
CRED_FILE=$(mktemp)
|
||||||
|
chmod 600 "$CRED_FILE"
|
||||||
|
trap 'rm -f "$CRED_FILE"' EXIT
|
||||||
|
printf "https://pkgver-bot:%s@gitea.moonarch.de\n" "$PKGBUILD_TOKEN" > "$CRED_FILE"
|
||||||
|
git -c credential.helper="store --file=$CRED_FILE" push
|
||||||
@@ -1,20 +1,94 @@
|
|||||||
# Moonarch
|
# Moonarch
|
||||||
|
|
||||||
Reproduzierbares Arch-Linux-Setup basierend auf archinstall + Post-Install-Automatisierung.
|
Reproducible Arch Linux setup based on archinstall + post-install automation.
|
||||||
|
|
||||||
## Projektstruktur
|
## Project Structure
|
||||||
|
|
||||||
- `config/` — archinstall-Konfiguration (inkl. custom-commands die das Repo nach /opt/moonarch klonen, root-owned)
|
- `config/` — archinstall configuration (incl. custom-commands that clone the repo to /opt/moonarch, root-owned)
|
||||||
- `scripts/` — Post-Install- und Helper-Scripts
|
- `scripts/` — post-install and helper scripts
|
||||||
- `packages/` — Paketlisten (offiziell + AUR), getrennt gepflegt
|
- `packages/` — package lists (official + AUR), maintained separately
|
||||||
- `defaults/` — XDG-Configs, Shell-Config, Helper-Binaries, greetd/moongreet-Config, Wallpaper
|
- `defaults/` — XDG configs, shell config, helper binaries, systemd services, udev rules, greetd/moongreet config, wallpaper
|
||||||
|
|
||||||
## Konventionen
|
## Battery Conservation Mode
|
||||||
|
|
||||||
- Paketlisten sind einfache Textdateien, ein Paket pro Zeile, Kommentare mit `#`
|
Laptops with `charge_control_end_threshold` support (ThinkPad, Framework, etc.) get a Waybar toggle:
|
||||||
- Shell-Scripts müssen POSIX-kompatibel oder explizit bash/zsh sein
|
- Clicking the battery module toggles the charge limit between 80% and 100%
|
||||||
- Alle Pfade im archinstall-Config relativ zum Installationsziel
|
- When conservation is active, a ♥ icon appears next to the battery indicator
|
||||||
|
- State is persisted in `/var/lib/moonarch/batsaver-threshold` and restored on boot via a systemd service (`moonarch-batsaver-restore`)
|
||||||
|
- Toggle flow: `moonarch-batsaver-toggle` (user script) reads sysfs, decides 80↔100, calls `pkexec /usr/bin/moonarch-batsaver-apply $NEW` for the privileged sysfs+state write step. Standard pkexec prompt (password once per session cache)
|
||||||
|
- On desktops without battery support the feature is hidden entirely
|
||||||
|
|
||||||
## Ich bin Apollo
|
## Nightlight (Blue Light Filter)
|
||||||
|
|
||||||
Benannt nach dem Programm, das Menschen zum Mond gebracht hat — passend für ein Projekt namens Moonarch.
|
Waybar toggle for wlsunset (Wayland-native blue light filter), persistent state via systemd:
|
||||||
|
- `wlsunset.service` (systemd user service) with `After=kanshi.service` — starts only once all outputs are configured
|
||||||
|
- **Default OFF** — fresh installs start without the filter. The PKGBUILD deliberately creates NO symlink for `wlsunset` in `/etc/systemd/user/graphical-session.target.wants/`, and post-install.sh does not enable the service.
|
||||||
|
- Clicking the nightlight module in `group/brightness` toggles wlsunset on/off (`enable --now` / `disable --now`)
|
||||||
|
- State survives reboots (user-scope symlink in `~/.config/systemd/user/...wants/`)
|
||||||
|
- Active state shows in Catppuccin Yellow, inactive in the default text color
|
||||||
|
- Signal SIGRTMIN+11 for immediate Waybar refresh
|
||||||
|
- Scripts: `moonarch-nightlight` (toggle), `moonarch-waybar-nightlight` (status JSON)
|
||||||
|
- **Important**: Never create a global-scope symlink at `/etc/systemd/user/...wants/wlsunset.service` — it overrides any user `disable` and makes the filter effectively impossible to turn off.
|
||||||
|
|
||||||
|
## Waybar Config Merger (moonarch-waybar)
|
||||||
|
|
||||||
|
Waybar is started via `moonarch-waybar` (not directly). The wrapper merges an optional user config (`~/.config/waybar/userconfig`) with the system config (`/etc/xdg/waybar/config`):
|
||||||
|
- `prepend`/`append` keys in the userconfig extend the `modules-left`/`modules-center`/`modules-right` arrays
|
||||||
|
- All other top-level keys are inserted as module definitions via object merge
|
||||||
|
- The merge runs only on changes (timestamp comparison)
|
||||||
|
- On error: `notify-send` + `logger`, Waybar starts with the system config
|
||||||
|
- Generates `~/.config/waybar/style.css` with an `@import` of the system styles if not present
|
||||||
|
- Requires `jq` (declared as a dependency in the PKGBUILD)
|
||||||
|
- The system config must be valid JSON (no JSONC)
|
||||||
|
|
||||||
|
## mpv + ModernZ OSC
|
||||||
|
|
||||||
|
The video player is `mpv` with [ModernZ](https://github.com/Samillion/ModernZ) as the OSC, thumbnails via thumbfast:
|
||||||
|
- `mpv-modernz-git` provides `modernz.lua` + font + default config to `/etc/mpv/`
|
||||||
|
- `mpv-thumbfast-git` provides `thumbfast.lua` to `/etc/mpv/scripts/` (auto-detected by ModernZ)
|
||||||
|
- `defaults/etc/mpv/mpv.conf` is installed directly to `/etc/mpv/mpv.conf` by moonarch-git (owned)
|
||||||
|
- Stock OSC + title bar disabled, `autofit-larger=80%x80%` caps oversized windows
|
||||||
|
- ModernZ overrides via `script-opts-append` in mpv.conf: orange accent → Catppuccin Lavender (`#b4befe`), OSC scale 0.75, `window_title_font_size=18`, `ontop_button=no`
|
||||||
|
- **Important**: mpv treats `#` as a mid-line comment; hex colors must be quoted: `script-opts-append="modernz-seekbarfg_color=#b4befe"` (not `\#`, which only escapes and swallows the rest)
|
||||||
|
- Niri opens mpv floating (`window-rule` in `defaults/xdg/niri/config.kdl`)
|
||||||
|
|
||||||
|
## System Health Check (moonarch-doctor / moondoc)
|
||||||
|
|
||||||
|
Diagnostic script that checks the system state against moonarch defaults:
|
||||||
|
- Packages (official.txt + aur.txt installed? Orphans?)
|
||||||
|
- System services (NetworkManager, bluetooth, greetd, ufw, auto-cpufreq, etc.)
|
||||||
|
- User services (kanshi, wlsunset, stasis, walker, nautilus, cliphist-text, cliphist-image)
|
||||||
|
- Config files (SHA256 comparison deployed vs. moonarch default)
|
||||||
|
- Helper scripts + symlinks (moonup, moondoc)
|
||||||
|
- System config (UFW, pacman/paru repos, default shell)
|
||||||
|
- Directories + permissions
|
||||||
|
|
||||||
|
## Fontconfig Defaults
|
||||||
|
|
||||||
|
System-wide generic-family defaults via `defaults/etc/fonts/conf.d/65-moonarch-fonts.conf` (owned by moonarch-git):
|
||||||
|
- `sans-serif` → UbuntuSans Nerd Font, `monospace` → UbuntuSansMono Nerd Font
|
||||||
|
- Number **65**: loads after `60-latin.conf`, so the moonarch prefs beat the stock default (Noto/DejaVu). `local.conf` (at 51 via `51-local.conf`) loads too early and is overridden by 60-latin — therefore **do not** use it (it is also reserved for local user overrides).
|
||||||
|
- Aliases need `binding="strong"` — a weak `<prefer>` (fontconfig default) ranks behind the effective generic fallback and does not take effect.
|
||||||
|
- Only applies to apps that use generic families (e.g. Firefox web fallback). moonarch apps (Waybar, foot, GTK, walker, swaync) set the font explicitly.
|
||||||
|
|
||||||
|
## Browser Idle-Inhibit (xdg-desktop-portal)
|
||||||
|
|
||||||
|
So that windowed browser video (Firefox/Waterfox) keeps the screen awake, via `defaults/etc/xdg-desktop-portal/niri-portals.conf` (owned by moonarch-git, higher priority than niri's `/usr/share/xdg-desktop-portal/niri-portals.conf`):
|
||||||
|
- `xdg-desktop-portal-gtk` reports the `Inhibit` interface as success even though nobody implements it under Niri → Firefox believes the idle-inhibit went through the portal and does not use the native Wayland `idle-inhibit`. Result: no inhibitor, screen sleeps.
|
||||||
|
- Fix: `org.freedesktop.impl.portal.Inhibit=none` → Firefox falls back to `zwp_idle_inhibit`, which Niri honors. The remaining `[preferred]` lines are taken 1:1 from niri's default (portals.conf is not merged — the highest-priority file applies in full).
|
||||||
|
- stasis is uninvolved here: `monitor_media` (pactl) does not capture browser audio by design (non-browser players only); browsers go through the inhibit path.
|
||||||
|
- **Activation:** restart xdg-desktop-portal + the browser — Firefox queries portal support at startup.
|
||||||
|
|
||||||
|
### Windowed / Muted Video: wayland-pipewire-idle-inhibit
|
||||||
|
|
||||||
|
The portal fix only applies to **fullscreen** video — Firefox/Waterfox send the idle-inhibit only in fullscreen. Windowed video remains unprotected: stasis ignores browser audio (pactl, browser-excluded, no MPRIS backend), Niri gets no inhibitor, the screen sleeps mid-video.
|
||||||
|
|
||||||
|
Solution: `wayland-pipewire-idle-inhibit` (AUR, systemd user service; in `packages/aur.txt` + `post-install.sh` USER_SERVICES + moonarch-doctor). Holds a Wayland `zwp_idle_inhibit` inhibitor while PipeWire outputs audio (default threshold 5s). Niri then suppresses idle → stasis stays awake, daemon-independent. Releases automatically when audio stops.
|
||||||
|
- Catches windowed video **with sound**. Misses muted video (no audio signal) — edge case, accepted.
|
||||||
|
- **Never** put `waterfox`/a browser in stasis `inhibit_apps`: that inhibits unconditionally as long as the browser process runs → the system never idles. This exact wrong fix caused the "no idle" bug.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Package lists are plain text files, one package per line, comments with `#`
|
||||||
|
- Shell scripts must be POSIX-compatible or explicitly bash/zsh
|
||||||
|
- All paths in the archinstall config are relative to the install target
|
||||||
|
|||||||
+129
-6
@@ -1,37 +1,160 @@
|
|||||||
# Decisions
|
# Decisions
|
||||||
|
|
||||||
|
## 2026-06-08 – Fontconfig generic-family defaults via owned conf.d (65)
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Waybar rendered in Hack instead of Ubuntu after the Nerd Fonts "Ubuntu"→"UbuntuSans" rename (Canonical rebrand). Waybar's style.css referenced the now-dead family "Ubuntu Nerd Font"; fontconfig token-matched it to "Hack Nerd Font". An unowned hand-written `/etc/fonts/local.conf` additionally pinned sans-serif/monospace to Hack — a stale relic.
|
||||||
|
- **Tradeoffs**: `local.conf` (loaded at 51 via `51-local.conf`) is structurally too early — `60-latin.conf` prepends Noto/DejaVu afterwards and wins, so its sans-serif pin never took effect. local.conf is also reserved for local admin overrides, and packaging it as owned would collide with pre-existing unowned files on pacman update. A conf.d file at 65 loads after 60-latin (convention: 60–69 = generic→family) and wins cleanly without conflict.
|
||||||
|
- **How**: New owned `defaults/etc/fonts/conf.d/65-moonarch-fonts.conf` maps sans-serif→UbuntuSans Nerd Font, monospace→UbuntuSansMono Nerd Font; installed by moonarch-git PKGBUILD. Stale `/etc/fonts/local.conf` removed. Waybar `style.css` font-family corrected "Ubuntu Nerd Font"→"UbuntuSans Nerd Font" (the bar wants the explicit proportional font, not a generic). The aliases need `binding="strong"` — verified that a weak `<prefer>` (fontconfig's default for `<alias>`) ranks behind the system's effective generic fallback and does not take effect; strong is required for it to apply.
|
||||||
|
|
||||||
|
## 2026-05-04 – Nightlight default OFF, no global enablement
|
||||||
|
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Filter survived reboots even after the user toggled it off. Root cause: `moonarch-pkgbuilds/moonarch-git/PKGBUILD` looped over every user service in `defaults/etc/systemd/user/*.service` and dropped a WantedBy symlink into `/etc/systemd/user/graphical-session.target.wants/`. That path is global scope. `moonarch-nightlight` runs `systemctl --user disable wlsunset`, which can only remove user-scope symlinks under `~/.config/`. Systemd's own warning during disable spelled it out: "The following unit files have been enabled in global scope. This means they will still be started automatically after a successful disablement in user scope." Verified empirically — `is-enabled` stayed `enabled`, root symlink untouched. Additionally, `scripts/post-install.sh` enabled `wlsunset` by default in its `USER_SERVICES` array, so even without the global symlink the filter would default ON.
|
||||||
|
- **Tradeoffs**: Three options weighed. (1) Default OFF + user-scope toggle — minimal change, fresh installs start without filter, toggle creates `~/.config/.../wants/` symlink that user-disable can actually remove. (2) Default ON + user-scope toggle — same plumbing, post-install enables in user scope; filter on by default but disable persists. (3) Status-file gate inside the unit — service stays enabled, ExecStartPre checks a file and exits when off. Picked (1): no behavioral default imposed on fresh installs, no extra plumbing, the toggle stays the single source of truth. Could have moved enablement to a per-user `systemctl --user --global enable` from the .install hook, but that fights the "this is a UI toggle" framing.
|
||||||
|
- **How**: `moonarch-pkgbuilds/moonarch-git/PKGBUILD` — symlink loop now skips a `skip_enable` list (currently `wlsunset.service`); skipped services are still installed under `/etc/systemd/user/` but not wanted by `graphical-session.target` at the global level. `moonarch-pkgbuilds/moonarch-git/moonarch.install` — `pre_upgrade()` deletes any pre-existing `/etc/systemd/user/graphical-session.target.wants/wlsunset.service` to clean up systems that received the old packaging. `moonarch/scripts/post-install.sh` — `wlsunset` removed from `USER_SERVICES`; comment explains why. `moonarch/CLAUDE.md` — Nightlight section reflects "Default OFF" and the global-scope-symlink hazard.
|
||||||
|
|
||||||
|
## 2026-05-04 – Battery threshold permissions: udev rule → pkexec helper
|
||||||
|
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: The wheel-write-via-udev approach for `/sys/class/power_supply/BAT0/charge_control_end_threshold` had been broken since 2026-04-08 (commit `ac2b210`, "audit remediation Q-W3"). That commit added `ACTION=="add"` to `90-moonarch-battery.rules` to "avoid firing on every battery event" — but that filter is precisely what the rule needs not to have. On Lenovo, the threshold attribute does not exist yet at the `add` event (the driver creates it slightly later); the rule fires, `chmod` fails silently because `2>/dev/null` swallows the error, and permissions are never set. The unfiltered original rule worked by accident: `add` failed silently as well, but a subsequent `change` event on the same device caught the now-existing attribute and set permissions. After the audit commit, change events stopped re-firing the rule and the toggle was permanently broken — `moonarch-batsaver-toggle` returned `Permission denied`. Verified via journalctl + manual chmod: rule fires for hidpp_battery_0 (visible exit-1 errors), no trace for BAT0; manual `chmod g+w` on BAT0's threshold succeeds (sysfs accepts the change), so the permission model itself works — only the rule path failed.
|
||||||
|
- **Tradeoffs**: Three approaches considered. (A) Restore the original unfiltered rule — fixes the symptom by accident, leaves the failure mode intact (silent fail at add, retry hopefully at change). (B) Switch to `tmpfiles.d` — Arch Wiki explicitly warns this can run before driver modules load, undefined for sysfs. (C) pkexec helper with polkit-rule — standard pattern (Battery-Health-Charging GNOME extension uses exactly this). Picked C with default Standard-pkexec prompt rather than no-password polkit rule: minor UX cost (password once per pkauth session, ≈5min cache), eliminates the entire sysfs-permission problem class, no privilege-escalation surface from a misvalidated helper. The wheel-can-write-sysfs design was a moonarch-specific deviation from common Linux practice — bringing it in line with the standard root-orientiert helper pattern.
|
||||||
|
- **How**: `defaults/bin/moonarch-batsaver-apply` (new): privileged helper invoked via pkexec; strictly validates argument (digits only, range 1-100), writes sysfs (idempotent — skips kernel write when value already matches to avoid Lenovo EINVAL on same-value writes), writes state file. `defaults/bin/moonarch-batsaver-toggle` (rewritten): user-side reads current threshold, picks 80↔100, dispatches `pkexec /usr/bin/moonarch-batsaver-apply $NEW`, then signals waybar. `defaults/etc/udev/rules.d/90-moonarch-battery.rules` deleted (and the now-empty `defaults/etc/udev/` parent removed). PKGBUILD: udev install line removed. `moonarch-doctor`: removed the udev-effectiveness check (no longer relevant). `moonarch-batsaver.service` and `moonarch-batsaver-restore` (also new in this commit, extracted from the old inline ExecStart for readability) keep root-owned boot-time restore — no permission concerns there. `CLAUDE.md` Battery-Conservation-Mode section updated to describe the new flow.
|
||||||
|
|
||||||
|
## 2026-05-04 – Cleanup: remove invented zsh override layer, harden moondoc
|
||||||
|
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Audit revealed two classes of cruft introduced by earlier ClaudeCode sessions without explicit decision or DECISIONS.md entry. (1) An invented user-override mechanism (`~/.zshrc.d/*.zsh` snippet loop, `~/.zshrc.local` fallback) was wired into `defaults/shell/zshrc` and `scripts/post-install.sh`. Not a zsh convention, not documented, redundant to the user's own `~/.zshrc`. `post-install.sh` created the `~/.zshrc.d` directory unconditionally on every fresh install — leaving an empty directory in every user's home. (2) `moonarch-doctor` had only existence checks (`/etc/zsh/zshrc.moonarch` exists?, `/usr/share/moonarch/` exists?) which are redundant with the package check, and hardcoded service/script lists that drift silently when moonarch-git's payload changes. The udev rule for `charge_control_end_threshold` (battery conservation) had no effectiveness check at all — a broken rule would not show up.
|
||||||
|
- **Tradeoffs**: Could have left the invented override layer alone (no active harm) but it muddies `defaults/shell/zshrc` and produces empty directories on every fresh install. Could have kept the existence checks (cosmetic noise, no harm) but they create false positives — doctor reports "pass" while the actual mechanism may be broken. Kept the 7 hardcoded `check_config_match` entries for `/etc/xdg/foot/`, `/etc/greetd/`, `/etc/moongreet/` etc. — the source-to-destination mapping is not 1:1 (foot → `/etc/xdg/foot/`, greetd → `/etc/greetd/`, moongreet → `/etc/moongreet/`), so dynamic discovery would need a manifest. Acceptable hardcoding for now.
|
||||||
|
- **How**: `defaults/shell/zshrc` — `~/.zshrc.d/*.zsh` source loop and `~/.zshrc.local` fallback removed; second ABOUTME line that referenced them removed. `scripts/post-install.sh` — Zsh-block now writes `~/.zshrc` with only `source /etc/zsh/zshrc.moonarch` (no mkdir, no `~/.zshrc.d` reference); stale "rustup default stable" hint and "User overrides in `~/.zshrc.d/`" hint removed from next-steps. `scripts/lib.sh` — dead `confirm()` (orphaned since transform.sh deletion 2026-04-21) removed. `scripts/moonarch-doctor` — user-services and helper-scripts lists now derived from `pacman -Qql moonarch-git` plus an explicit list of post-install-enabled externals (currently `stasis`); useless existence checks for `/etc/zsh/zshrc.moonarch` and `/usr/share/moonarch/` removed; new udev-effectiveness check for `charge_control_end_threshold` (group=wheel + group-writable). `defaults/bin/moonarch-waybar-cpugov`, `moonarch-waybar-gpustat` — German ABOUTME comments translated to English for consistency.
|
||||||
|
|
||||||
|
## 2026-04-24 – Stasis: flip `ignore_remote_media` to false for browser video
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Idle was firing on a second machine even while a video was playing in the browser. Original config carried the comment "browser uses D-Bus inhibit" and set `ignore_remote_media true`, deliberately excluding browser MPRIS on the assumption that Firefox/Chromium would keep the session alive via `org.freedesktop.ScreenSaver.Inhibit`. Verified against browser behavior: both browsers only raise that inhibit during **fullscreen** video playback (Firefox also requires `dom.screenwakelock.enabled`, default off on Linux). Windowed playback — the common case, YouTube in a tab — sends no inhibit, so stasis saw zero inhibitors and zero media players and ran the full idle plan to suspend. Upstream example config lists `r"firefox.*"` in `inhibit_apps` for exactly this reason; Moonarch removed it without a working substitute.
|
||||||
|
- **Tradeoffs**: Three options. (A) Put `firefox`/`chromium` back into `inhibit_apps` — works but inhibits whenever the browser *process* is running, even with zero tabs playing; wrong shape. (B) Tell users to flip `dom.screenwakelock.enabled` per browser — pushes per-user config, fragile across browsers. (C) Let browser MPRIS count as a media player by setting `ignore_remote_media false` — stasis already tracks playback state, so it only inhibits during actual playback. Picked C. Cost: any MPRIS source stasis classifies as "remote" (e.g. a Chromecast bridge) now also inhibits; acceptable — that is usually what a user wants anyway, and the inhibit releases the moment playback stops.
|
||||||
|
- **How**: `defaults/xdg/stasis/stasis.rune` — `ignore_remote_media true` → `false`, comment rewritten to document the fullscreen-only D-Bus behavior. PKGBUILD deploys to `/etc/xdg/stasis/stasis.rune`; existing users still need the 2026-04-22 seed mechanism (or a manual merge) to pick it up in `~/.config/stasis/stasis.rune`.
|
||||||
|
|
||||||
|
## 2026-04-22 – moonarch-doctor housekeeping: drop stale check, add missing services
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Noticed while running `moondoc` on a healthy system that it reported `Paru [moonarch-pkgbuilds] repo missing from /etc/paru.conf` — a false failure. The paru PKGBUILD-repo mechanism was retired on 2026-04-20 in favor of the registry-only flow, and the `moonarch-git` install hook strips the legacy paru.conf section on upgrade; the doctor script was not updated in lockstep. Audit of the rest of the script surfaced two related gaps: the user-services loop skipped `walker.service` and `nautilus.service`, even though the PKGBUILD ships both in `/etc/systemd/user/` and enables them via `graphical-session.target.wants` symlinks. A silently missing walker or nautilus would not show up in diagnostics.
|
||||||
|
- **How**: Removed the `[moonarch-pkgbuilds]` check from `scripts/moonarch-doctor`. Added `walker` and `nautilus` to the user-service loop. Updated `CLAUDE.md` user-services listing to match (also filled in the missing `wlsunset`). The `[moonarch]` pacman-repo check stays — that is the path that matters now.
|
||||||
|
|
||||||
|
## 2026-04-22 – Seed Stasis user config from post-install.sh
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Moonarch shipped `defaults/xdg/stasis/stasis.rune` (deployed to `/etc/xdg/stasis/stasis.rune` by the PKGBUILD) on the assumption that stasis honors the XDG system config hierarchy. It does not. Verified against upstream source (v1.1.0, `src/config/mod.rs:30` + `src/config/bootstrap.rs`): stasis only reads `~/.config/stasis/stasis.rune` (primary) or `/etc/stasis/stasis.rune` (fallback, no `xdg/`). On every start with no user config, `ensure_user_config_exists()` writes its own hardcoded default (laptop/desktop template compiled into the binary) to `~/.config/stasis/stasis.rune`. Net effect: Moonarch's Idle-Manager tuning (AC/battery plans, moonlock integration, inhibit apps, niri DPMS commands) was never active on fresh installs — users got the upstream defaults with `swaylock` as locker.
|
||||||
|
- **Tradeoffs**: Three options were considered. (A) Service drop-in with `--config /etc/stasis/stasis.rune` — cleanest, upgrades propagate via package, no user-home touching; rejected because it takes stasis out of the standard config path users expect when they want to customize, and requires packaging a drop-in unit. (B) Seed once from post-install.sh into `~/.config/stasis/stasis.rune` — chosen: user-owned file, immediately editable, no magic. Cost: package updates to the template never reach users who already ran post-install; they have to merge manually. (C) Recurring systemd user service that keeps seeding — ruled out, too clever, user edits would race with it. Stasis has no config hierarchy / merging, so "system default + user override" cannot be modeled at all.
|
||||||
|
- **How**: Added a block to `scripts/post-install.sh` before the user-services-enable step: if `~/.config/stasis/stasis.rune` does not exist and `/etc/xdg/stasis/stasis.rune` does, `install -Dm644` copies the template into the user home. Order is correct — moonarch-git is installed earlier in the script (deploys `/etc/xdg/…`), and stasis.service is only *enabled* (not started) later, so the seed is in place before stasis ever runs. The `/etc/xdg/stasis/` payload stays as the canonical template source inside the package.
|
||||||
|
|
||||||
|
## 2026-04-21 – post-install.sh pulls aur.txt, rust for paru build, rustup out of official
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Three related gaps uncovered while fixing the paru bootstrap: (1) `moonarch-git` cannot depend on AUR packages, so every AUR package in `aur.txt` (walker-bin, elephant-*-bin, awww's theme, waypaper, stasis, …) was silently never installed by post-install.sh — a fresh install would have a working pacman but no launcher, no idle manager, no theming. (2) `makepkg -si` for `paru` (AUR source build) needs `rust` as makedep; neither archinstall nor post-install.sh installed it, so the restored paru bootstrap would have crashed on rust-less systems. (3) `rustup` sat in `official.txt` "for something we don't remember" — turned out to be a leftover; `rust` suffices for the paru build, and rustup is only needed for dev toolchain management which is a per-user concern, not a Moonarch default.
|
||||||
|
- **Tradeoffs**: Installing `rust` (~350MB) just to bootstrap paru feels heavy. Alternative `paru-bin` avoids the compile step entirely; rejected because Dominik's documented workflow uses `paru` (source) and consistency with that matters more than ~30s of build time. rustup can be re-added to official.txt if the dev workflow grows that demand.
|
||||||
|
- **How**: (1) post-install.sh now runs `read_packages "$AUR_PACKAGES" | paru -S --needed` after `paru -S moonarch-git`. (2) `sudo pacman -S base-devel rust` before the paru git-clone. (3) `rustup` removed from `official.txt` (remains in PKGBUILD `optdepends` for discoverability).
|
||||||
|
|
||||||
|
## 2026-04-21 – Restore AUR bootstrap for paru in post-install.sh
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Commit 0726451 (2026-03-29) replaced the working `git clone https://aur.archlinux.org/paru.git && makepkg -si` bootstrap with `sudo pacman -S paru`, on the (wrong) assumption that paru had landed in `[extra]`. Verified against archlinux.org API: paru and paru-bin are AUR-only, not in any official repo. Fresh installs have been silently broken since — the command fails, the installer aborts before the moonarch registry is configured.
|
||||||
|
- **Tradeoffs**: Bootstrap builds paru from source, which needs `base-devel` (already pulled by archinstall). Alternative `paru-bin` would skip the compile step; chose `paru` to match the upstream recommendation the user follows. Alternative "bundle paru in the Moonarch registry" would be internally consistent but adds a dependency on a running Gitea during install.
|
||||||
|
- **How**: Replaced the `pacman -S paru` line in `post-install.sh` with the original bootstrap — `mktemp -d`, `git clone`, `makepkg -si --noconfirm`, `rm -rf`. Wrapped in an EXIT trap so the tempdir gets cleaned up even on failure.
|
||||||
|
|
||||||
|
## 2026-04-21 – Drop transform.sh and legacy update.sh shim
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: transform.sh was added 2026-03-29 to onboard users from existing Arch+Wayland systems, but was never actually used — Moonarch is installed fresh via archinstall. Maintaining it meant duplicated paru/repo/key setup, a second entry point with its own backup/pre-flight logic, and a second reason for the `/opt/moonarch` clone. scripts/update.sh was a deprecation shim from before moonarch-update moved into the moonarch-git package; obsolete now that the package ships moonup/moondoc.
|
||||||
|
- **Tradeoffs**: Existing Arch+Wayland users now have to install paru, add the `[moonarch]` repo + key manually, then `paru -S moonarch-git`. That's three commands instead of one script — acceptable since nobody actually uses that path. If the need returns, transform can be resurrected from git history.
|
||||||
|
- **How**: Deleted `scripts/transform.sh` and `scripts/update.sh`. `lib.sh` stays (still sourced by post-install.sh). README "Transform" section removed, project-structure listing trimmed. Fresh-install flow via archinstall + post-install.sh is unchanged.
|
||||||
|
|
||||||
|
## 2026-04-20 – Registry-only install: drop paru --pkgbuilds from setup scripts
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Two parallel paths for finding moonarch packages (Arch registry via `[moonarch]` in pacman.conf, and paru's PKGBUILD-repo via `[moonarch-pkgbuilds]` in paru.conf) caused ambiguity during debugging: `paru -S moonarch-git` was resolving against the registry's stale DB (zombie r99 entry) while the PKGBUILD source would have had r105. Also: the PKGBUILD-repo path triggered a local build on every client, while the registry ships prebuilt binaries. With the registry DB now stable (see `moonarch-pkgbuilds/DECISIONS.md`, same date), the second mechanism is redundant.
|
||||||
|
- **Tradeoffs**: If the registry is down or broken, clients have no local-build fallback. Acceptable — a broken registry is a server-side bug to fix, not something to mask with a parallel mechanism that complicates diagnostics.
|
||||||
|
- **How**: `post-install.sh` and `transform.sh` no longer write `Mode = arp` or a `[moonarch-pkgbuilds]` section to `/etc/paru.conf`, and no longer call `paru -Syu --pkgbuilds`. They run `pacman -Sy` + `paru -S moonarch-git` against the registry. The `moonarch-git` install hook now strips the legacy paru.conf entries on upgrade (see moonarch-pkgbuilds repo).
|
||||||
|
|
||||||
|
## 2026-04-19 – moonup i18n: reuse pacman gettext catalog + inline fallback
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: moonup prompts looked foreign next to pacman/paru output (`[y/N]` vs `[J/n]`, English strings on a German system). User wanted consistency with the rest of the pacman UX.
|
||||||
|
- **Tradeoffs**: Full `.po`/`.mo` build-chain for moonarch was overkill for ~15 strings. gettext-only approach misses most moonarch-specific strings (no matching msgids in pacman catalog). Chose hybrid: `TEXTDOMAIN=pacman` for strings that match upstream msgids (prompts like `Proceed with installation?`, `Do you want to remove these packages?`, `[Y/n]`, `Starting full system upgrade...`), inline `_t()` helper for moonarch-specific strings.
|
||||||
|
- **How**: `moonarch-update` sets `TEXTDOMAIN=pacman`/`TEXTDOMAINDIR=/usr/share/locale`. `_t "en" "de"` picks by `${LANG%%.*}` matching `de_*`. `confirm()` now uses `::` prefix, default Y, accepts `y/Y/j/J`. No PKGBUILD change — `gettext` is in `base`. pacman msgids with trailing `\n` (e.g. `Starting full system upgrade...\n`) require ANSI-C quoting `$'...\n'` to match.
|
||||||
|
|
||||||
|
## 2026-04-08 – Battery conservation mode: udev + sysfs + Waybar toggle
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Laptops with `charge_control_end_threshold` support benefit from limiting charge to 80% to extend battery lifespan. Needed a user-friendly toggle without requiring sudo.
|
||||||
|
- **Tradeoffs**: udev RUN approach for permissions (group wheel gets write access) vs polkit/pkexec (password prompt on every toggle). Chose udev for seamless UX. State persisted in `/var/lib/moonarch/` (system-wide, not per-user) — acceptable since charge threshold is a hardware setting, not a user preference. Fixed 80% threshold instead of configurable — KISS, matches industry standard.
|
||||||
|
- **How**: udev rule grants wheel group write on `charge_control_end_threshold`. Toggle script writes sysfs + state file. systemd oneshot service restores on boot. Waybar shows ♥ icon when active, hidden when inactive. Click on battery module toggles.
|
||||||
|
|
||||||
|
## 2026-04-07 – Walker theme: gtk-inherit → moonarch with fixed colors
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: gtk-inherit theme relied on GTK4 color inheritance which works but doesn't update live when switching GTK themes (Walker service needs restart). Explicit color definitions make the theme self-contained and predictable.
|
||||||
|
- **Tradeoffs**: Colors no longer auto-follow GTK theme changes. Acceptable since moonarch uses a fixed Catppuccin Mocha palette anyway.
|
||||||
|
- **How**: Renamed theme to moonarch, added @define-color with Colloid-Grey-Dark-Catppuccin values, reduced border/shadow weight.
|
||||||
|
|
||||||
|
## 2026-04-07 – Migrate archinstall config to v4 format
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: archinstall v4.1 introduced new canonical key names. Old keys (audio_config, bootloader, custom-commands) are soft-deprecated and auto-mapped, but custom-commands (hyphen) vs custom_commands (underscore) was risky.
|
||||||
|
- **Tradeoffs**: Config now requires archinstall v4+. Older ISOs with v2/v3 may not parse the new keys.
|
||||||
|
- **How**: Migrated audio_config into app_config, bootloader into bootloader_config, custom-commands to custom_commands, gfx_driver value updated.
|
||||||
|
|
||||||
|
## 2026-04-07 – kanshi config: no ABOUTME, no overwrite on transform
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: ABOUTME comments in kanshi config broke the profile parser in wdisplays-persistent store.c, preventing config saves. Additionally, transform.sh was overwriting user display profiles on every run.
|
||||||
|
- **Tradeoffs**: kanshi default template is now empty (no comments). Users get no guidance in the seed file, but wdisplays-persistent provides the GUI for config management.
|
||||||
|
- **How**: Removed ABOUTME from defaults/xdg/kanshi/config. Added skip logic in transform.sh to preserve existing kanshi user configs.
|
||||||
|
|
||||||
|
## 2026-04-07 – Move paru repo config into moonarch.install hook
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: paru PKGBUILD repo config was only set up by post-install.sh and transform.sh. If paru updated and overwrote /etc/paru.conf, or the config was missing on existing systems, moonarch-git couldn't update itself — bootstrap loop where the fix requires the package that delivers the fix.
|
||||||
|
- **Tradeoffs**: Config setup is now in two places: moonarch.install (for updates) and post-install.sh (for first install before moonarch-git exists). Acceptable duplication to break the circular dependency.
|
||||||
|
- **How**: Added paru repo config (Mode=arp + [moonarch-pkgbuilds] section) to moonarch.install post_install/post_upgrade hook. Kept post-install.sh setup for bootstrap. Removed redundant setup from transform.sh.
|
||||||
|
|
||||||
|
## 2026-04-02 – Rename paru PKGBUILD repo, move config to /etc/paru.conf
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: paru PKGBUILD repo and pacman package registry both used `[moonarch]` as section name. When pkgver-bot pushed version bumps, paru tried to resolve PKGBUILD targets (moongreet-git, moonlock-git) against the pacman repo — which only contains moonarch-git — causing "nicht alle benötigten Pakete gefunden" errors.
|
||||||
|
- **Tradeoffs**: Renaming the PKGBUILD repo section means existing installations need a one-time manual fix. Using `/etc/paru.conf` instead of `~/.config/paru/paru.conf` is consistent with moonarch's system-wide config philosophy.
|
||||||
|
- **How**: Renamed PKGBUILD repo section from `[moonarch]` to `[moonarch-pkgbuilds]`. Moved paru config (Mode + repo) from user-level `~/.config/paru/paru.conf` to system-wide `/etc/paru.conf`. Updated post-install.sh accordingly.
|
||||||
|
|
||||||
|
## 2026-04-01 – Replace dunst with swaync as notification daemon
|
||||||
|
- **Who**: Dominik, ClaudeCode
|
||||||
|
- **Why**: Dunst lacks wp_fractional_scale_v1 support, causing aliased/jagged font rendering on external monitors in mixed-DPI setups (laptop eDP-1 at 2.5x, externals at 1x). Confirmed by testing: removing fractional scaling fixed the issue. swaync uses GTK4 which handles fractional scaling natively.
|
||||||
|
- **Tradeoffs**: swaync is heavier than dunst (GTK4 + libadwaita dependency). Loses dunstctl CLI (replaced by swaync-client). Gains notification center panel with DnD toggle, grouping, MPRIS widget support. Waybar already had swaync-client integration with exec-if guard.
|
||||||
|
- **How**: Replaced dunst with swaync in packages/official.txt and archinstall config. Niri spawn-at-startup updated. Waybar dunstctl widget removed (swaync-client widget already present). New swaync config.json and style.css based on catppuccin/swaync upstream theme with Lavender accent instead of Blue.
|
||||||
|
|
||||||
|
## 2026-03-31 – Audit: shell script quoting fixes, PKGBUILD permissions
|
||||||
|
|
||||||
|
- **Who**: ClaudeCode, Dom
|
||||||
|
- **Why**: Security audit found command injection risk in moonarch-cpugov (unquoted array expansion with pkexec), word-splitting in moonarch-btnote (upower output from Bluetooth devices), and nmcli argument injection in moonarch-vpn. PKGBUILD for moongreet had world-readable cache dir.
|
||||||
|
- **Tradeoffs**: `eval` in cpugov is safe because COMMANDS values are hardcoded string literals, not user input. Alternative (function dispatch) would be cleaner but over-engineered for 3 fixed entries. moonarch-btnote switched from for-loop to while+read with process substitution to avoid subshell.
|
||||||
|
- **How**: (1) `eval "${COMMANDS[$choice]}"` in cpugov. (2) `while IFS= read -r` + process substitution + quoted `$DEVICE_DATA` in btnote. (3) `--` guard before `$connection` in vpn nmcli calls. (4) `install -dm700` for moongreet cache dirs in PKGBUILD. (5) `else err` logging in post-install.sh when USER_DEFAULTS missing.
|
||||||
|
|
||||||
## 2026-03-29 – /opt/moonarch stays root-owned, no chown to user
|
## 2026-03-29 – /opt/moonarch stays root-owned, no chown to user
|
||||||
- **Who**: Dominik, Ragnar
|
- **Who**: Dominik, ClaudeCode
|
||||||
- **Why**: Multi-user system — chown to UID 1000 locks out other users from moonarch-update
|
- **Why**: Multi-user system — chown to UID 1000 locks out other users from moonarch-update
|
||||||
- **Tradeoffs**: sudo required for git operations in update.sh vs. simpler user-owned repo
|
- **Tradeoffs**: sudo required for git operations in update.sh vs. simpler user-owned repo
|
||||||
- **How**: Repo stays at /opt/moonarch owned by root:root. update.sh uses `sudo git` for fetch/pull. All scripts already use sudo for system-level operations, so this is consistent.
|
- **How**: Repo stays at /opt/moonarch owned by root:root. update.sh uses `sudo git` for fetch/pull. All scripts already use sudo for system-level operations, so this is consistent.
|
||||||
|
|
||||||
## 2026-03-29 – Add transform.sh for existing Arch+Wayland systems
|
## 2026-03-29 – Add transform.sh for existing Arch+Wayland systems
|
||||||
- **Who**: Dominik, Ragnar
|
- **Who**: Dominik, ClaudeCode
|
||||||
- **Why**: Users with existing Arch+Wayland setups should be able to adopt Moonarch without reinstalling
|
- **Why**: Users with existing Arch+Wayland setups should be able to adopt Moonarch without reinstalling
|
||||||
- **Tradeoffs**: Hard overwrite of all configs (user + system) vs. selective/merge approach — chose hard overwrite for simplicity and consistency
|
- **Tradeoffs**: Hard overwrite of all configs (user + system) vs. selective/merge approach — chose hard overwrite for simplicity and consistency
|
||||||
- **How**: New transform.sh with pre-flight summary, backup, DM conflict resolution, and --dry-run flag. Shared helpers extracted to lib.sh.
|
- **How**: New transform.sh with pre-flight summary, backup, DM conflict resolution, and --dry-run flag. Shared helpers extracted to lib.sh.
|
||||||
|
|
||||||
## 2026-03-29 – Package moonarch as moonarch-git PKGBUILD
|
## 2026-03-29 – Package moonarch as moonarch-git PKGBUILD
|
||||||
- **Who**: Dominik, Ragnar
|
- **Who**: Dominik, ClaudeCode
|
||||||
- **Why**: System artifacts (XDG configs, helper scripts, zsh config, wallpaper) should be managed by pacman for clean deployment, versioning, rollback, and deinstallation
|
- **Why**: System artifacts (XDG configs, helper scripts, zsh config, wallpaper) should be managed by pacman for clean deployment, versioning, rollback, and deinstallation
|
||||||
- **Tradeoffs**: /etc/xdg/ configs NOT in backup= (moonarch philosophy: system defaults flow through, users override in ~/.config/). /etc/greetd/ and /etc/moongreet/ NOT owned by package (owned by greetd/moongreet-git, overwritten via .install hook). Helper scripts move from /usr/local/bin/ to /usr/bin/ (FHS for package-managed files)
|
- **Tradeoffs**: /etc/xdg/ configs NOT in backup= (moonarch philosophy: system defaults flow through, users override in ~/.config/). /etc/greetd/ and /etc/moongreet/ NOT owned by package (owned by greetd/moongreet-git, overwritten via .install hook). Helper scripts move from /usr/local/bin/ to /usr/bin/ (FHS for package-managed files)
|
||||||
- **How**: moonarch-git PKGBUILD in moonarch-pkgbuilds repo. sweet-cursors-git as separate package. moonarch-update simplified (no git-sync, pacman handles file deployment). Installer scripts (post-install.sh, transform.sh) remain for orchestration, will be refactored in a follow-up to delegate file deployment to `paru -S moonarch-git`
|
- **How**: moonarch-git PKGBUILD in moonarch-pkgbuilds repo. sweet-cursors-git as separate package. moonarch-update simplified (no git-sync, pacman handles file deployment). Installer scripts (post-install.sh, transform.sh) remain for orchestration, will be refactored in a follow-up to delegate file deployment to `paru -S moonarch-git`
|
||||||
|
|
||||||
## 2026-03-30 – Replace Rofi with Walker as application launcher
|
## 2026-03-30 – Replace Rofi with Walker as application launcher
|
||||||
- **Who**: Dominik, Ragnar
|
- **Who**: Dominik, ClaudeCode
|
||||||
- **Why**: Walker is Wayland-native (GTK4 + gtk4-layer-shell), has built-in providers for clipboard, bluetooth, audio (wireplumber), and Niri integration. Reduces custom shell scripts from 8 to 3. Rofi required a Wayland fork (rofi-lbonn-wayland-git) and every applet was a custom bash script.
|
- **Why**: Walker is Wayland-native (GTK4 + gtk4-layer-shell), has built-in providers for clipboard, bluetooth, audio (wireplumber), and Niri integration. Reduces custom shell scripts from 8 to 3. Rofi required a Wayland fork (rofi-lbonn-wayland-git) and every applet was a custom bash script.
|
||||||
- **Tradeoffs**: Walker is newer/less battle-tested than Rofi. Requires separate Elephant daemon with per-provider packages. Dmenu mode lacks Rofi's `-a`/`-u` (active/urgent) and `-mesg` flags. Settings menu (moonarch-setmen) dropped entirely — apps are findable via Walker's app search.
|
- **Tradeoffs**: Walker is newer/less battle-tested than Rofi. Requires separate Elephant daemon with per-provider packages. Dmenu mode lacks Rofi's `-a`/`-u` (active/urgent) and `-mesg` flags. Settings menu (moonarch-setmen) dropped entirely — apps are findable via Walker's app search.
|
||||||
- **How**: Walker + Elephant as systemd user services. Native providers replace 5 rofi scripts (launcher, clipboard, bluetooth, volume, sink-switcher). 3 scripts ported to walker dmenu (vpn, cpugov, sink-switcher). Walker theme inherits GTK4 system theme colors (gtk-inherit). Old rofi configs preserved in `legacy/rofi/`.
|
- **How**: Walker + Elephant as systemd user services. Native providers replace 5 rofi scripts (launcher, clipboard, bluetooth, volume, sink-switcher). 3 scripts ported to walker dmenu (vpn, cpugov, sink-switcher). Walker theme inherits GTK4 system theme colors (gtk-inherit). Old rofi configs preserved in `legacy/rofi/`.
|
||||||
|
|
||||||
## 2026-03-30 – Use nm-applet as VPN secret agent, add WireGuard support
|
## 2026-03-30 – Use nm-applet as VPN secret agent, add WireGuard support
|
||||||
- **Who**: Dominik, Ragnar
|
- **Who**: Dominik, ClaudeCode
|
||||||
- **Why**: VPN auth previously spawned a foot terminal for `nmcli --ask`, which was fragile and ugly. WireGuard connections were invisible to the VPN script and Waybar indicator because both only checked for OpenVPN (`tun0` / `vpn` type).
|
- **Why**: VPN auth previously spawned a foot terminal for `nmcli --ask`, which was fragile and ugly. WireGuard connections were invisible to the VPN script and Waybar indicator because both only checked for OpenVPN (`tun0` / `vpn` type).
|
||||||
- **Tradeoffs**: nm-applet adds a tray indicator (mitigated with `--indicator` mode which is minimal). Requires nm-applet running at session start. Alternative was gnome-keyring or a custom secret agent — nm-applet is simpler and handles all NM secret types.
|
- **Tradeoffs**: nm-applet adds a tray indicator (mitigated with `--indicator` mode which is minimal). Requires nm-applet running at session start. Alternative was gnome-keyring or a custom secret agent — nm-applet is simpler and handles all NM secret types.
|
||||||
- **How**: nm-applet started via niri spawn-at-startup. moonarch-vpn rewritten to support both vpn and wireguard types, uses nm-applet for auth instead of foot terminal, sends notify-send for connect/disconnect results. Waybar VPN module uses `nmcli` active connection check instead of `/proc/sys/net/ipv4/conf/tun0`, plus RTMIN+9 signal for instant updates after toggle.
|
- **How**: nm-applet started via niri spawn-at-startup. moonarch-vpn rewritten to support both vpn and wireguard types, uses nm-applet for auth instead of foot terminal, sends notify-send for connect/disconnect results. Waybar VPN module uses `nmcli` active connection check instead of `/proc/sys/net/ipv4/conf/tun0`, plus RTMIN+9 signal for instant updates after toggle.
|
||||||
|
|
||||||
## 2026-03-30 – Standardize GTK theme to Colloid-Grey-Dark-Catppuccin
|
## 2026-03-30 – Standardize GTK theme to Colloid-Grey-Dark-Catppuccin
|
||||||
- **Who**: Dominik, Ragnar
|
- **Who**: Dominik, ClaudeCode
|
||||||
- **Why**: gsettings had `Colloid-Dark-Catppuccin` while config files had `Colloid-Catppuccin` — inconsistent. Grey accent matches the icon theme (Colloid-Grey-Catppuccin-Dark). Explicit `-Dark` variant is more reliable than depending on `prefer-dark` color-scheme setting.
|
- **Why**: gsettings had `Colloid-Dark-Catppuccin` while config files had `Colloid-Catppuccin` — inconsistent. Grey accent matches the icon theme (Colloid-Grey-Catppuccin-Dark). Explicit `-Dark` variant is more reliable than depending on `prefer-dark` color-scheme setting.
|
||||||
- **Tradeoffs**: Explicit dark locks out light mode toggle — acceptable since Moonarch is dark-only by design.
|
- **Tradeoffs**: Explicit dark locks out light mode toggle — acceptable since Moonarch is dark-only by design.
|
||||||
- **How**: Updated transform.sh, post-install.sh, gtk-3.0/settings.ini, and gsettings to `Colloid-Grey-Dark-Catppuccin`. GTK4 symlinks updated accordingly.
|
- **How**: Updated transform.sh, post-install.sh, gtk-3.0/settings.ini, and gsettings to `Colloid-Grey-Dark-Catppuccin`. GTK4 symlinks updated accordingly.
|
||||||
|
|||||||
@@ -16,20 +16,21 @@ desktop that can be rebuilt from scratch in minutes.
|
|||||||
| **Greeter** | [greetd](https://sr.ht/~kennylevinsen/greetd/) + [moongreet](https://gitea.moonarch.de/nevaforget/moongreet) | Minimal, Wayland-native login. moongreet provides GTK4 UI with fingerprint support, running inside its own Niri instance. |
|
| **Greeter** | [greetd](https://sr.ht/~kennylevinsen/greetd/) + [moongreet](https://gitea.moonarch.de/nevaforget/moongreet) | Minimal, Wayland-native login. moongreet provides GTK4 UI with fingerprint support, running inside its own Niri instance. |
|
||||||
| **Lock Screen** | [moonlock](https://gitea.moonarch.de/nevaforget/moonlock) | ext-session-lock-v1 protocol — compositor guarantees lock on crash. PAM + fprintd, GPU blur, multi-monitor. |
|
| **Lock Screen** | [moonlock](https://gitea.moonarch.de/nevaforget/moonlock) | ext-session-lock-v1 protocol — compositor guarantees lock on crash. PAM + fprintd, GPU blur, multi-monitor. |
|
||||||
| **Power Menu** | [moonset](https://gitea.moonarch.de/nevaforget/moonset) | GTK4 Layer Shell overlay above Waybar. Lock, logout, hibernate, reboot, shutdown with confirmation. |
|
| **Power Menu** | [moonset](https://gitea.moonarch.de/nevaforget/moonset) | GTK4 Layer Shell overlay above Waybar. Lock, logout, hibernate, reboot, shutdown with confirmation. |
|
||||||
| **Idle Manager** | [stasis](https://aur.archlinux.org/packages/stasis) | Separate AC/battery power plans. Brightness dimming, DPMS, lock (via moonlock), and suspend on configurable timeouts. |
|
| **Idle Manager** | [stasis](https://aur.archlinux.org/packages/stasis) + [wayland-pipewire-idle-inhibit](https://github.com/rafaelrc7/wayland-pipewire-idle-inhibit) | Separate AC/battery power plans. Brightness dimming, DPMS, lock (via moonlock), and suspend on configurable timeouts. The companion inhibitor holds a Wayland idle-inhibitor while audio plays — keeps the screen awake during windowed browser video, which stasis' pactl detection skips by design. |
|
||||||
| **Bar** | [Waybar](https://github.com/Alexays/Waybar) | Wayland-native, highly customizable. Niri workspace/window modules via community plugins. |
|
| **Bar** | [Waybar](https://github.com/Alexays/Waybar) | Wayland-native, highly customizable. Niri workspace/window modules via community plugins. |
|
||||||
| **Launcher** | [Walker](https://github.com/abenz1267/walker) + [Elephant](https://github.com/abenz1267/elephant) | Wayland-native GTK4 launcher with built-in providers for apps, clipboard, bluetooth, audio, files, and calculator. Dmenu mode for custom scripts (VPN, CPU governor). |
|
| **Launcher** | [Walker](https://github.com/abenz1267/walker) + [Elephant](https://github.com/abenz1267/elephant) | Wayland-native GTK4 launcher with built-in providers for apps, clipboard, bluetooth, audio, files, and calculator. Dmenu mode for custom scripts (VPN, CPU governor). |
|
||||||
| **Terminal** | [Foot](https://codeberg.org/dnkl/foot) | Fast, minimal Wayland-native terminal. Server mode for instant window spawning. |
|
| **Terminal** | [Foot](https://codeberg.org/dnkl/foot) | Fast, minimal Wayland-native terminal. Server mode for instant window spawning. |
|
||||||
| **Shell** | Zsh | Programmable completion, FZF integration, syntax highlighting. |
|
| **Shell** | Zsh | Programmable completion, FZF integration, syntax highlighting. |
|
||||||
| **Audio** | PipeWire | Drop-in replacement for PulseAudio/JACK with lower latency. RNNoise input denoising configured out of the box. |
|
| **Audio** | PipeWire | Drop-in replacement for PulseAudio/JACK with lower latency. RNNoise input denoising configured out of the box. |
|
||||||
| **Display Management** | [kanshi](https://sr.ht/~emersion/kanshi/) + [wdisplays](https://github.com/artizirk/wdisplays) | kanshi auto-switches output profiles on hotplug. wdisplays for manual GUI configuration. |
|
| **Display Management** | [kanshi](https://sr.ht/~emersion/kanshi/) + [wdisplays-persistent](https://github.com/sfs-pra/wdisplays) | kanshi auto-switches output profiles on hotplug. wdisplays-persistent saves changes directly to kanshi config. |
|
||||||
| **Notifications** | [dunst](https://dunst-project.org/) | Lightweight, scriptable. DND mode exposed as Waybar module. |
|
| **Notifications** | [swaync](https://github.com/ErikReider/SwayNotificationCenter) | GTK4 notification daemon with DND toggle, grouping, MPRIS support. Fractional scaling via native GTK4. |
|
||||||
| **Clipboard** | Walker clipboard provider | Built-in clipboard history with image support. Managed by Elephant backend. |
|
| **Clipboard** | [cliphist](https://github.com/sentriz/cliphist) + Walker | Clipboard history stored in runtime dir, wiped on session start. Walker provides the picker UI. |
|
||||||
| **GTK Theme** | Colloid-Grey-Dark-Catppuccin | Catppuccin Mocha palette, grey accent, explicit dark variant. |
|
| **GTK Theme** | Colloid-Grey-Dark-Catppuccin | Catppuccin Mocha palette, grey accent, explicit dark variant. |
|
||||||
| **Icons** | Colloid-Grey-Catppuccin-Dark | Catppuccin-colored icon set matching the GTK theme. |
|
| **Icons** | Colloid-Grey-Catppuccin-Dark | Catppuccin-colored icon set matching the GTK theme. |
|
||||||
| **Cursor** | Sweet-cursors | Visible on dark backgrounds without clashing. |
|
| **Cursor** | Sweet-cursors | Visible on dark backgrounds without clashing. |
|
||||||
| **Font** | UbuntuSans Nerd Font | Clean sans-serif with full Nerd Font glyph coverage for bar/terminal icons. |
|
| **Font** | UbuntuSans Nerd Font | Clean sans-serif with full Nerd Font glyph coverage for bar/terminal icons. |
|
||||||
| **Wallpaper** | [waypaper](https://github.com/anufrievroman/waypaper) + [awww](https://codeberg.org/LGFae/awww) | waypaper provides GUI selection, awww handles animated transitions (60 FPS, 2s crossfade). |
|
| **Wallpaper** | [waypaper](https://github.com/anufrievroman/waypaper) + [awww](https://codeberg.org/LGFae/awww) | waypaper provides GUI selection, awww handles animated transitions (60 FPS, 2s crossfade). |
|
||||||
|
| **Night Light** | [wlsunset](https://sr.ht/~kennylevinsen/wlsunset/) | Wayland-native blue light filter via wlr-gamma-control. Toggleable from Waybar brightness group. |
|
||||||
| **Firewall** | UFW | Simple deny-incoming/allow-outgoing default. Sane baseline without iptables complexity. |
|
| **Firewall** | UFW | Simple deny-incoming/allow-outgoing default. Sane baseline without iptables complexity. |
|
||||||
| **AUR Helper** | [paru](https://github.com/Morganamilo/paru) | Rust-based, pacman-compatible. Supports custom PKGBUILD repos for moongreet/moonlock/moonset. |
|
| **AUR Helper** | [paru](https://github.com/Morganamilo/paru) | Rust-based, pacman-compatible. Supports custom PKGBUILD repos for moongreet/moonlock/moonset. |
|
||||||
|
|
||||||
@@ -50,47 +51,28 @@ desktop that can be rebuilt from scratch in minutes.
|
|||||||
4. Reboot again — done.
|
4. Reboot again — done.
|
||||||
|
|
||||||
The archinstall config clones this repo to `/opt/moonarch` via custom-commands.
|
The archinstall config clones this repo to `/opt/moonarch` via custom-commands.
|
||||||
post-install.sh handles the remaining ~100 packages, all configs, themes, services,
|
post-install.sh handles the remaining ~95 packages, all configs, themes, services,
|
||||||
and user setup.
|
and user setup.
|
||||||
|
|
||||||
### Transform (Existing Arch+Wayland System)
|
|
||||||
|
|
||||||
Already running Arch with a Wayland compositor (Sway, Hyprland, GNOME Wayland, etc.)?
|
|
||||||
Transform converts your system to Moonarch without reinstalling.
|
|
||||||
|
|
||||||
**Prerequisites:** Active Wayland session, git installed.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone the repo
|
|
||||||
sudo git clone https://gitea.moonarch.de/nevaforget/moonarch.git /opt/moonarch
|
|
||||||
|
|
||||||
# Preview what will happen (no changes made)
|
|
||||||
/opt/moonarch/scripts/transform.sh --dry-run
|
|
||||||
|
|
||||||
# Run the transform
|
|
||||||
/opt/moonarch/scripts/transform.sh
|
|
||||||
|
|
||||||
# Reboot (do NOT log out — your previous DM is already disabled)
|
|
||||||
sudo reboot
|
|
||||||
```
|
|
||||||
|
|
||||||
The script will:
|
|
||||||
1. Show a pre-flight summary (package diff, config changes, detected conflicts)
|
|
||||||
2. Back up your `~/.config/`, `~/.zshrc`, and `/etc/xdg/` to timestamped tar archives
|
|
||||||
3. Disable conflicting display managers (SDDM, GDM, LightDM, etc.)
|
|
||||||
4. Remove conflicting packages (e.g. PulseAudio → PipeWire)
|
|
||||||
5. Install all Moonarch packages and configs (**hard overwrite** of all user configs)
|
|
||||||
6. Enable greetd, firewall, and system services
|
|
||||||
|
|
||||||
### Update
|
### Update
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
moonarch-update
|
moonup # or: moonarch-update
|
||||||
```
|
```
|
||||||
|
|
||||||
Interactive updater that syncs the repo, upgrades system/AUR packages, reconciles
|
Interactive updater that upgrades system and AUR packages, reconciles package lists
|
||||||
package lists against what's installed, deploys changed XDG defaults, and cleans
|
against what's installed, and cleans orphaned packages. Config deployment happens
|
||||||
orphaned packages.
|
automatically via the moonarch-git package on `paru -Syu`.
|
||||||
|
|
||||||
|
### Health Check
|
||||||
|
|
||||||
|
```bash
|
||||||
|
moondoc # or: moonarch-doctor
|
||||||
|
```
|
||||||
|
|
||||||
|
Diagnostic tool that verifies the system state against moonarch defaults: services,
|
||||||
|
configs, packages, helper scripts, firewall, shell and directory permissions. Reports
|
||||||
|
pass/fail/warn per check with a summary at the end.
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
@@ -99,47 +81,50 @@ config/
|
|||||||
user_configuration.json archinstall config (locale, audio, services, custom-commands)
|
user_configuration.json archinstall config (locale, audio, services, custom-commands)
|
||||||
|
|
||||||
packages/
|
packages/
|
||||||
official.txt Arch repo packages (~100), one per line
|
official.txt Arch repo packages (~80), one per line
|
||||||
aur.txt AUR packages (~15), one per line
|
aur.txt AUR packages (~20), one per line
|
||||||
|
|
||||||
scripts/
|
scripts/
|
||||||
lib.sh Shared helpers sourced by all scripts
|
lib.sh Shared helpers sourced by post-install.sh
|
||||||
post-install.sh Main automation (packages, configs, themes, services)
|
post-install.sh Main automation (packages, configs, themes, services)
|
||||||
transform.sh Convert existing Arch+Wayland system to Moonarch
|
moonarch-update Interactive updater (deployed to /usr/bin/ as moonup)
|
||||||
install-themes.sh Cursor theme installer (Sweet-cursors)
|
moonarch-doctor System health checker (deployed to /usr/bin/ as moondoc)
|
||||||
update.sh System updater (symlinked to moonarch-update)
|
|
||||||
|
|
||||||
defaults/
|
defaults/
|
||||||
xdg/ System-wide XDG configs (deployed to /etc/xdg/)
|
xdg/ System-wide XDG configs (deployed to /etc/xdg/)
|
||||||
niri/config.kdl Compositor: layout, keybinds, startup apps
|
niri/config.kdl Compositor: layout, keybinds, startup apps
|
||||||
waybar/config, style.css Bar: modules, layout, Catppuccin styling
|
waybar/config, style.css Bar: modules, layout, Catppuccin styling
|
||||||
walker/config.toml, themes/ Launcher: Walker config + gtk-inherit theme
|
walker/config.toml, themes/ Launcher: Walker config + moonarch theme (Catppuccin Mocha)
|
||||||
foot/foot.ini Terminal: font, colors, keybinds
|
foot/foot.ini Terminal: font, colors, keybinds
|
||||||
dunst/dunstrc Notifications: geometry, colors, behavior
|
swaync/config.json, style.css Notifications: appearance, behavior, MPRIS
|
||||||
kanshi/config Display profiles (empty, user-configured)
|
kanshi/config Display profiles (empty seed, user-configured via wdisplays)
|
||||||
gtklock/ Lock screen: config, UI layout, CSS
|
|
||||||
stasis/stasis.rune Idle manager: AC/battery power plans
|
stasis/stasis.rune Idle manager: AC/battery power plans
|
||||||
pipewire/ Audio: RNNoise input denoising
|
pipewire/ Audio: RNNoise input denoising
|
||||||
waypaper/config.ini Wallpaper manager: backend, folder, transitions
|
waypaper/config.ini Wallpaper manager: backend, folder, transitions
|
||||||
fastfetch/config.jsonc System info display
|
fastfetch/config.jsonc System info display
|
||||||
gtk-3.0/, gtk-4.0/ GTK theme settings
|
gtk-3.0/, gtk-4.0/ GTK theme settings
|
||||||
|
|
||||||
bin/ Helper scripts (deployed to /usr/local/bin/)
|
bin/ Helper scripts (deployed to /usr/bin/)
|
||||||
moonarch-sink-switcher Audio output switcher (walker dmenu + pactl)
|
moonarch-sink-switcher Audio output switcher (walker dmenu + pactl)
|
||||||
moonarch-vpn VPN connection manager (walker dmenu + nmcli)
|
moonarch-vpn VPN connection manager (walker dmenu + nmcli)
|
||||||
moonarch-cpugov CPU governor switcher (walker dmenu + auto-cpufreq)
|
moonarch-cpugov CPU governor switcher (walker dmenu + auto-cpufreq)
|
||||||
moonarch-dnd Dunst Do Not Disturb toggle (Waybar JSON output)
|
|
||||||
moonarch-btnote Bluetooth device battery monitor (upower + notify-send)
|
moonarch-btnote Bluetooth device battery monitor (upower + notify-send)
|
||||||
moonarch-capsnote Caps Lock toggle notification
|
moonarch-capsnote Caps Lock toggle notification
|
||||||
moonarch-waybar-cpugov Waybar module: CPU governor status
|
moonarch-waybar-cpugov Waybar module: CPU governor status
|
||||||
moonarch-waybar-gpustat Waybar module: GPU utilization
|
moonarch-waybar-gpustat Waybar module: GPU utilization
|
||||||
moonarch-waybar-hidpp Waybar module: Logitech HID++ device battery
|
moonarch-waybar-hidpp Waybar module: Logitech HID++ device battery
|
||||||
|
moonarch-waybar-batsaver Waybar module: battery conservation mode indicator
|
||||||
|
moonarch-waybar-updates Waybar module: package update checker (repo + AUR)
|
||||||
|
moonarch-batsaver-toggle Toggle battery charge limit (80% ↔ 100%)
|
||||||
|
moonarch-nightlight Toggle wlsunset blue light filter on/off
|
||||||
|
moonarch-waybar-nightlight Waybar module: nightlight status
|
||||||
|
|
||||||
shell/zshrc Zsh config: prompt, aliases, FZF, completion
|
shell/zshrc Zsh config: prompt, aliases, FZF, completion
|
||||||
etc/greetd/ greetd daemon + greeter Niri config
|
etc/greetd/ greetd daemon + greeter Niri config
|
||||||
etc/moongreet/ moongreet configuration
|
etc/moongreet/ moongreet configuration
|
||||||
user/systemd/user/ Systemd user services (kanshi, walker, elephant)
|
etc/systemd/user/ Systemd user services (cliphist, kanshi, walker, nautilus)
|
||||||
user/waybar/ Per-user Waybar overrides (only copied if missing)
|
etc/systemd/system/ System service (battery conservation restore on boot)
|
||||||
|
etc/udev/rules.d/ udev rules (battery threshold permissions)
|
||||||
backgrounds/wallpaper.jpg Default wallpaper (shared by desktop, greeter, lock screen)
|
backgrounds/wallpaper.jpg Default wallpaper (shared by desktop, greeter, lock screen)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -153,10 +138,11 @@ greetd ─► niri (greeter instance) ─► moongreet ─► user authenticates
|
|||||||
│
|
│
|
||||||
┌──────────┬────────┬────────┬──────────┐
|
┌──────────┬────────┬────────┬──────────┐
|
||||||
▼ ▼ ▼ ▼ ▼
|
▼ ▼ ▼ ▼ ▼
|
||||||
waybar dunst foot waypaper cliphist
|
waybar swaync foot waypaper nm-applet wlsunset
|
||||||
(bar) (notify) (server) (wallpaper) (clipboard)
|
(bar) (notify) (server) (wallpaper) (VPN) (nightlight)
|
||||||
|
|
||||||
kanshi runs as a systemd user service (graphical-session.target)
|
systemd user services (graphical-session.target):
|
||||||
|
kanshi, cliphist, walker, nautilus
|
||||||
```
|
```
|
||||||
|
|
||||||
## Keybinds (Default)
|
## Keybinds (Default)
|
||||||
@@ -178,7 +164,7 @@ greetd ─► niri (greeter instance) ─► moongreet ─► user authenticates
|
|||||||
| `Super+E` | File manager |
|
| `Super+E` | File manager |
|
||||||
| `Super+A` | Audio control (walker) |
|
| `Super+A` | Audio control (walker) |
|
||||||
| `Super+N` | VPN manager |
|
| `Super+N` | VPN manager |
|
||||||
| `Super+Alt+L` | Session menu (wlogout) |
|
| `Mod+Escape` | Session menu (moonset) |
|
||||||
| `Print` | Screenshot |
|
| `Print` | Screenshot |
|
||||||
| `Ctrl+Print` | Screenshot screen |
|
| `Ctrl+Print` | Screenshot screen |
|
||||||
| `Alt+Print` | Screenshot window |
|
| `Alt+Print` | Screenshot window |
|
||||||
@@ -189,17 +175,17 @@ All system configs live in `/etc/xdg/` and can be overridden per-user in `~/.con
|
|||||||
|
|
||||||
| Component | System Default | User Override |
|
| Component | System Default | User Override |
|
||||||
|-----------|---------------|---------------|
|
|-----------|---------------|---------------|
|
||||||
| Niri | `/etc/xdg/niri/config.kdl` | `~/.config/niri/config.kdl` |
|
| Niri | `/etc/xdg/niri/config.kdl` | `~/.config/niri/config.kdl` (includes system config) |
|
||||||
| Waybar | `/etc/xdg/waybar/` | `~/.config/waybar/` |
|
| Waybar | `/etc/xdg/waybar/` | `~/.config/waybar/` |
|
||||||
| Walker | `/etc/xdg/walker/` | `~/.config/walker/` |
|
| Walker | `/etc/xdg/walker/` | `~/.config/walker/` |
|
||||||
| Foot | `/etc/xdg/foot/foot.ini` | `~/.config/foot/foot.ini` |
|
| Foot | `/etc/xdg/foot/foot.ini` | `~/.config/foot/foot.ini` |
|
||||||
| Dunst | `/etc/xdg/dunst/dunstrc` | `~/.config/dunst/dunstrc` |
|
| swaync | `/etc/xdg/swaync/` | `~/.config/swaync/` |
|
||||||
| kanshi | `/etc/xdg/kanshi/config` | `~/.config/kanshi/config` |
|
| kanshi | `/etc/xdg/kanshi/config` | `~/.config/kanshi/config` |
|
||||||
| PipeWire | `/etc/xdg/pipewire/` | `~/.config/pipewire/` |
|
| PipeWire | `/etc/xdg/pipewire/` | `~/.config/pipewire/` |
|
||||||
| Zsh | `/etc/zsh/zshrc.moonarch` | `~/.zshrc` + `~/.zshrc.d/` |
|
| Zsh | `/etc/zsh/zshrc.moonarch` | `~/.zshrc` + `~/.zshrc.d/` |
|
||||||
|
|
||||||
Helper scripts in `/usr/local/bin/moonarch-*` are not meant to be overridden — they
|
Helper scripts in `/usr/bin/moonarch-*` are not meant to be overridden — they
|
||||||
are part of the system and updated via `moonarch-update`.
|
are part of the system and updated via `paru -Syu`.
|
||||||
|
|
||||||
## System Services
|
## System Services
|
||||||
|
|
||||||
@@ -208,7 +194,6 @@ are part of the system and updated via `moonarch-update`.
|
|||||||
| greetd | Login greeter (runs moongreet inside Niri) |
|
| greetd | Login greeter (runs moongreet inside Niri) |
|
||||||
| NetworkManager | Network management (WiFi, VPN, Ethernet) |
|
| NetworkManager | Network management (WiFi, VPN, Ethernet) |
|
||||||
| bluetooth | Bluetooth stack (bluez) |
|
| bluetooth | Bluetooth stack (bluez) |
|
||||||
| docker | Container runtime |
|
|
||||||
| systemd-timesyncd | NTP time synchronization |
|
| systemd-timesyncd | NTP time synchronization |
|
||||||
| ufw | Firewall (deny incoming, allow outgoing) |
|
| ufw | Firewall (deny incoming, allow outgoing) |
|
||||||
| auto-cpufreq | CPU frequency scaling (AC: performance, battery: powersave) |
|
| auto-cpufreq | CPU frequency scaling (AC: performance, battery: powersave) |
|
||||||
@@ -217,8 +202,11 @@ are part of the system and updated via `moonarch-update`.
|
|||||||
|
|
||||||
| Service | Purpose |
|
| Service | Purpose |
|
||||||
|---------|---------|
|
|---------|---------|
|
||||||
|
| cliphist | Clipboard history (wipes on session start, stores in runtime dir) |
|
||||||
| kanshi | Dynamic display configuration (auto-switch output profiles on hotplug) |
|
| kanshi | Dynamic display configuration (auto-switch output profiles on hotplug) |
|
||||||
| elephant | Walker data provider backend (apps, clipboard, bluetooth, audio) |
|
| nautilus | File manager preload (faster first launch) |
|
||||||
|
| stasis | Idle manager (dimming, DPMS, lock, suspend on AC/battery plans) |
|
||||||
|
| wayland-pipewire-idle-inhibit | Holds a Wayland idle-inhibitor while audio plays (keeps screen awake for windowed browser video that stasis skips) |
|
||||||
| walker | Walker application launcher (GTK4 service mode for instant startup) |
|
| walker | Walker application launcher (GTK4 service mode for instant startup) |
|
||||||
|
|
||||||
## Moonarch Ecosystem
|
## Moonarch Ecosystem
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
FROM archlinux:base-devel
|
||||||
|
RUN pacman -Sy --noconfirm git curl && pacman -Scc --noconfirm
|
||||||
|
RUN useradd -m builder && echo "builder ALL=(ALL) NOPASSWD: /usr/bin/pacman -S --needed *" >> /etc/sudoers
|
||||||
|
ADD https://gitea.com/gitea/act_runner/releases/download/v0.3.1/act_runner-0.3.1-linux-amd64 /usr/local/bin/act_runner
|
||||||
|
RUN echo "a05b2103a7cc5617197da214eaa06a1055362f21f9f475eb7fbacb8344d86cf8 /usr/local/bin/act_runner" | sha256sum -c - \
|
||||||
|
&& chmod +x /usr/local/bin/act_runner
|
||||||
|
COPY --from=gitea/act_runner:0.3.1 /usr/local/bin/run.sh /usr/local/bin/run.sh
|
||||||
|
RUN mkdir -p /data && chown builder:builder /data
|
||||||
|
USER builder
|
||||||
|
ENV HOME=/home/builder
|
||||||
|
ENTRYPOINT ["/usr/local/bin/run.sh"]
|
||||||
@@ -2,11 +2,18 @@
|
|||||||
"__comment": "ABOUTME: archinstall configuration for Moonarch.",
|
"__comment": "ABOUTME: archinstall configuration for Moonarch.",
|
||||||
"__comment2": "ABOUTME: Base setup — kernel, disk and filesystem are chosen interactively.",
|
"__comment2": "ABOUTME: Base setup — kernel, disk and filesystem are chosen interactively.",
|
||||||
|
|
||||||
"audio_config": {
|
"app_config": {
|
||||||
"audio": "pipewire"
|
"audio_config": {
|
||||||
|
"audio": "pipewire"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"bootloader": "Systemd-boot",
|
"bootloader_config": {
|
||||||
|
"bootloader": "Systemd-boot",
|
||||||
|
"uki": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"kernels": ["linux-zen"],
|
||||||
|
|
||||||
"hostname": "moonarch",
|
"hostname": "moonarch",
|
||||||
|
|
||||||
@@ -36,21 +43,19 @@
|
|||||||
"pipewire-jack",
|
"pipewire-jack",
|
||||||
"pipewire-pulse",
|
"pipewire-pulse",
|
||||||
"wireplumber",
|
"wireplumber",
|
||||||
"docker",
|
|
||||||
"docker-compose",
|
|
||||||
"fwupd",
|
"fwupd",
|
||||||
"ufw",
|
"ufw",
|
||||||
"greetd",
|
"greetd",
|
||||||
"niri",
|
"niri",
|
||||||
"waybar",
|
"waybar",
|
||||||
"foot",
|
"foot",
|
||||||
"dunst",
|
"swaync",
|
||||||
"polkit-gnome",
|
"polkit-gnome",
|
||||||
"stow"
|
"stow"
|
||||||
],
|
],
|
||||||
|
|
||||||
"profile_config": {
|
"profile_config": {
|
||||||
"gfx_driver": "All open-source",
|
"gfx_driver": "All open-source (default)",
|
||||||
"greeter": "greetd",
|
"greeter": "greetd",
|
||||||
"profile": {
|
"profile": {
|
||||||
"main": "Desktop",
|
"main": "Desktop",
|
||||||
@@ -61,7 +66,6 @@
|
|||||||
"services": [
|
"services": [
|
||||||
"NetworkManager",
|
"NetworkManager",
|
||||||
"bluetooth",
|
"bluetooth",
|
||||||
"docker",
|
|
||||||
"greetd",
|
"greetd",
|
||||||
"systemd-timesyncd",
|
"systemd-timesyncd",
|
||||||
"ufw"
|
"ufw"
|
||||||
@@ -69,7 +73,7 @@
|
|||||||
|
|
||||||
"timezone": "Europe/Berlin",
|
"timezone": "Europe/Berlin",
|
||||||
|
|
||||||
"custom-commands": [
|
"custom_commands": [
|
||||||
"git clone https://gitea.moonarch.de/nevaforget/moonarch.git /opt/moonarch"
|
"git clone https://gitea.moonarch.de/nevaforget/moonarch.git /opt/moonarch"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
# ABOUTME: Privileged helper invoked via pkexec from moonarch-batsaver-toggle.
|
||||||
|
# ABOUTME: Validates the threshold value and writes it to sysfs and the state file.
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
VAL="${1:-}"
|
||||||
|
|
||||||
|
case "$VAL" in
|
||||||
|
""|*[!0-9]*)
|
||||||
|
echo "Invalid argument: '$VAL' (expected integer 1-100)" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$VAL" -lt 1 ] || [ "$VAL" -gt 100 ]; then
|
||||||
|
echo "Out of range: $VAL (expected 1-100)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
THRESHOLD_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold"
|
||||||
|
STATE_DIR="/var/lib/moonarch"
|
||||||
|
STATE_FILE="$STATE_DIR/batsaver-threshold"
|
||||||
|
|
||||||
|
[ -f "$THRESHOLD_FILE" ] || { echo "No battery threshold support" >&2; exit 1; }
|
||||||
|
|
||||||
|
# Skip the kernel write when the value already matches — some Lenovo drivers
|
||||||
|
# reject same-value writes with EINVAL.
|
||||||
|
CURRENT=$(cat "$THRESHOLD_FILE")
|
||||||
|
if [ "$CURRENT" != "$VAL" ]; then
|
||||||
|
printf %s "$VAL" > "$THRESHOLD_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$STATE_DIR"
|
||||||
|
printf %s "$VAL" > "$STATE_FILE"
|
||||||
Executable
+23
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ABOUTME: Restores the saved battery charge end threshold on boot.
|
||||||
|
# ABOUTME: Skips silently when the kernel already reports the same value (avoids EINVAL on some Lenovo drivers).
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
STATE_FILE="/var/lib/moonarch/batsaver-threshold"
|
||||||
|
SYS_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold"
|
||||||
|
|
||||||
|
[ -f "$STATE_FILE" ] || exit 0
|
||||||
|
[ -f "$SYS_FILE" ] || exit 0
|
||||||
|
|
||||||
|
V=$(cat "$STATE_FILE")
|
||||||
|
case "$V" in
|
||||||
|
""|*[!0-9]*) exit 0 ;;
|
||||||
|
esac
|
||||||
|
[ "$V" -ge 1 ] && [ "$V" -le 100 ] || exit 0
|
||||||
|
|
||||||
|
# Some Lenovo drivers reject writing the same value with EINVAL.
|
||||||
|
C=$(cat "$SYS_FILE")
|
||||||
|
[ "$C" = "$V" ] && exit 0
|
||||||
|
|
||||||
|
printf %s "$V" > "$SYS_FILE"
|
||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
# ABOUTME: Toggles battery conservation mode between 80% and 100% charge limit.
|
||||||
|
# ABOUTME: Reads sysfs as user, dispatches the privileged write via pkexec.
|
||||||
|
|
||||||
|
THRESHOLD_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold"
|
||||||
|
CONSERVATION_LIMIT=80
|
||||||
|
|
||||||
|
[[ -f "$THRESHOLD_FILE" ]] || exit 1
|
||||||
|
|
||||||
|
CURRENT=$(cat "$THRESHOLD_FILE")
|
||||||
|
[[ "$CURRENT" =~ ^[0-9]+$ ]] || exit 1
|
||||||
|
|
||||||
|
if [[ "$CURRENT" -le "$CONSERVATION_LIMIT" ]]; then
|
||||||
|
NEW=100
|
||||||
|
else
|
||||||
|
NEW="$CONSERVATION_LIMIT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
pkexec /usr/bin/moonarch-batsaver-apply "$NEW" || exit 1
|
||||||
|
|
||||||
|
# Signal Waybar to refresh the batsaver module (SIGRTMIN+9)
|
||||||
|
pkill -RTMIN+9 waybar
|
||||||
@@ -5,15 +5,15 @@
|
|||||||
NOTIFY_AT_PERCENTAGE=70
|
NOTIFY_AT_PERCENTAGE=70
|
||||||
ICON="battery-empty"
|
ICON="battery-empty"
|
||||||
|
|
||||||
for d in $(upower -e); do
|
while IFS= read -r d; do
|
||||||
|
[ -z "$d" ] && continue
|
||||||
DEVICE_DATA=$(upower -i "$d")
|
DEVICE_DATA=$(upower -i "$d")
|
||||||
PERCENTAGE=$(echo $DEVICE_DATA | grep -Po '(?<=(percentage: )).*(?= icon)')
|
PER_INT=$(echo "$DEVICE_DATA" | grep -oP 'percentage:\s+\K[0-9]+')
|
||||||
PER_INT=$(echo "${PERCENTAGE//%}")
|
DEVICE_NAME=$(echo "$DEVICE_DATA" | grep -oP 'model:\s+\K.+')
|
||||||
DEVICE_NAME=$(echo $DEVICE_DATA | grep -Po '(?<=(model: )).*(?= serial)')
|
|
||||||
|
|
||||||
if [ -n "$DEVICE_NAME" ] && [ -n "$PER_INT" ] && [ "$PER_INT" -lt "$NOTIFY_AT_PERCENTAGE" ]; then
|
if [ -n "$DEVICE_NAME" ] && [ -n "$PER_INT" ] && [ "$PER_INT" -lt "$NOTIFY_AT_PERCENTAGE" ]; then
|
||||||
notify-send -t 5000 -e "Low battery $DEVICE_NAME $PER_INT%" -i "$ICON" \
|
notify-send -t 5000 -e "Low battery $DEVICE_NAME $PER_INT%" -i "$ICON" \
|
||||||
-h string:x-canonical-private-synchronous:battery \
|
-h string:x-canonical-private-synchronous:battery \
|
||||||
-h int:value:"$PER_INT" -u critical
|
-h int:value:"$PER_INT" -u critical
|
||||||
fi
|
fi
|
||||||
done
|
done < <(upower -e)
|
||||||
|
|||||||
@@ -60,10 +60,12 @@ fi
|
|||||||
# check if choice exists
|
# check if choice exists
|
||||||
if test "${COMMANDS[$choice]+isset}"
|
if test "${COMMANDS[$choice]+isset}"
|
||||||
then
|
then
|
||||||
# Execute the choice
|
|
||||||
${COMMANDS[$choice]}
|
${COMMANDS[$choice]}
|
||||||
|
|
||||||
notify-send -h string:x-canonical-private-synchronous:cpugov -i cpu "CPU Mode" "Set to $choice ${LABELS[$choice]}"
|
notify-send -h string:x-canonical-private-synchronous:cpugov -i cpu "CPU Mode" "Set to $choice ${LABELS[$choice]}"
|
||||||
|
|
||||||
|
# Signal Waybar to refresh the cpugov module (SIGRTMIN+10)
|
||||||
|
pkill -RTMIN+10 waybar
|
||||||
else
|
else
|
||||||
notify-send -u critical "CPU Governor" "Unknown command: ${choice}"
|
notify-send -u critical "CPU Governor" "Unknown command: ${choice}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ABOUTME: Toggles wlsunset night light on/off via systemd user service.
|
||||||
|
# ABOUTME: Persists state across reboots (enable/disable), signals waybar for refresh.
|
||||||
|
|
||||||
|
if systemctl --user is-active --quiet wlsunset; then
|
||||||
|
systemctl --user disable --now wlsunset
|
||||||
|
else
|
||||||
|
systemctl --user enable --now wlsunset
|
||||||
|
fi
|
||||||
|
|
||||||
|
pkill -RTMIN+11 waybar
|
||||||
@@ -5,7 +5,11 @@
|
|||||||
# choose audio sink via rofi
|
# choose audio sink via rofi
|
||||||
# changes default sink and moves all streams to that sink
|
# changes default sink and moves all streams to that sink
|
||||||
|
|
||||||
sink=$(pactl list sinks short | awk '{print $1, $2}' | walker -d -p " Sink Switcher" | awk '{print $1}') &&
|
sink=$(pactl list sinks short | awk '{print $1, $2}' | walker -d -p " Sink Switcher" | awk '{print $1}')
|
||||||
|
|
||||||
|
# Walker cancel returns empty — awk masks its non-zero exit. Guard here so we
|
||||||
|
# don't call `pactl set-default-sink ""` on dismissal.
|
||||||
|
[[ -n "$sink" ]] || exit 0
|
||||||
|
|
||||||
pactl set-default-sink "$sink" &&
|
pactl set-default-sink "$sink" &&
|
||||||
for input in $(pactl list sink-inputs short | awk '{print $1}'); do
|
for input in $(pactl list sink-inputs short | awk '{print $1}'); do
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
ACTIVE_PREFIX=" "
|
ACTIVE_PREFIX=" "
|
||||||
INACTIVE_PREFIX=" "
|
INACTIVE_PREFIX=" "
|
||||||
|
|
||||||
for cmd in nmcli walker notify-send; do
|
for cmd in nmcli walker; do
|
||||||
command -v "$cmd" >/dev/null 2>&1 || {
|
command -v "$cmd" >/dev/null 2>&1 || {
|
||||||
echo "Error: '$cmd' not found" >&2
|
echo "Error: '$cmd' not found" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -35,29 +35,17 @@ function extract_connection_name() {
|
|||||||
echo "$result"
|
echo "$result"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Connect a VPN and notify the result.
|
# Connect a VPN.
|
||||||
# Requires nm-applet (or another NM secret agent) for interactive auth.
|
# Requires nm-applet (or another NM secret agent) for interactive auth.
|
||||||
function connect_vpn() {
|
function connect_vpn() {
|
||||||
local connection="$1"
|
local connection="$1"
|
||||||
local feedback
|
nmcli connection up id "$connection"
|
||||||
|
|
||||||
if feedback=$(nmcli connection up "$connection" 2>&1); then
|
|
||||||
notify-send "VPN" "Connected to '$connection'"
|
|
||||||
else
|
|
||||||
notify-send -u critical "VPN" "Connection failed: $feedback"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Disconnect a VPN and notify the result.
|
# Disconnect a VPN.
|
||||||
function disconnect_vpn() {
|
function disconnect_vpn() {
|
||||||
local connection="$1"
|
local connection="$1"
|
||||||
local feedback
|
nmcli connection down id "$connection"
|
||||||
|
|
||||||
if feedback=$(nmcli connection down "$connection" 2>&1); then
|
|
||||||
notify-send "VPN" "Disconnected from '$connection'"
|
|
||||||
else
|
|
||||||
notify-send -u critical "VPN" "Disconnect failed: $feedback"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Toggle the VPN connection based on its current state.
|
# Toggle the VPN connection based on its current state.
|
||||||
@@ -89,7 +77,6 @@ function main() {
|
|||||||
connections=$(list_vpn_connections)
|
connections=$(list_vpn_connections)
|
||||||
|
|
||||||
if [[ -z "$connections" ]]; then
|
if [[ -z "$connections" ]]; then
|
||||||
notify-send "VPN" "No VPN connections configured"
|
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Executable
+61
@@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ABOUTME: Wrapper that merges system waybar config with per-machine userconfig.
|
||||||
|
# ABOUTME: Handles array prepend/append that waybar's native include cannot do.
|
||||||
|
|
||||||
|
SYSTEM_CONFIG="/etc/xdg/waybar/config"
|
||||||
|
SYSTEM_STYLE="/etc/xdg/waybar/style.css"
|
||||||
|
USER_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/waybar"
|
||||||
|
USERCONFIG="$USER_DIR/userconfig"
|
||||||
|
OUTPUT="$USER_DIR/config"
|
||||||
|
USER_STYLE="$USER_DIR/style.css"
|
||||||
|
|
||||||
|
merge_config() {
|
||||||
|
mkdir -p "$USER_DIR"
|
||||||
|
|
||||||
|
if ! jq -s '
|
||||||
|
.[0] as $sys | .[1] as $user |
|
||||||
|
(($user.prepend // {}) | to_entries) as $prepends |
|
||||||
|
(($user.append // {}) | to_entries) as $appends |
|
||||||
|
$sys |
|
||||||
|
reduce $prepends[] as $p (.;
|
||||||
|
.[$p.key] = ($p.value + (.[$p.key] // []))
|
||||||
|
) |
|
||||||
|
reduce $appends[] as $a (.;
|
||||||
|
.[$a.key] = ((.[$a.key] // []) + $a.value)
|
||||||
|
) |
|
||||||
|
($user | del(.prepend) | del(.append)) as $extras |
|
||||||
|
. * $extras
|
||||||
|
' "$SYSTEM_CONFIG" "$USERCONFIG" > "${OUTPUT}.tmp" 2>&1; then
|
||||||
|
local err
|
||||||
|
err=$(cat "${OUTPUT}.tmp")
|
||||||
|
rm -f "${OUTPUT}.tmp"
|
||||||
|
logger -t moonarch-waybar "Config merge failed: $err"
|
||||||
|
notify-send -u critical "moonarch-waybar" "Config merge failed — using system config.\n$err"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv "${OUTPUT}.tmp" "$OUTPUT"
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrap_style() {
|
||||||
|
if [[ ! -f "$USER_STYLE" ]]; then
|
||||||
|
mkdir -p "$USER_DIR"
|
||||||
|
cat > "$USER_STYLE" << 'CSS'
|
||||||
|
/* Generated by moonarch-waybar — add custom styles below */
|
||||||
|
@import url("/etc/xdg/waybar/style.css");
|
||||||
|
CSS
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ -f "$USERCONFIG" ]]; then
|
||||||
|
if [[ ! -f "$OUTPUT" ]] ||
|
||||||
|
[[ "$USERCONFIG" -nt "$OUTPUT" ]] ||
|
||||||
|
[[ "$SYSTEM_CONFIG" -nt "$OUTPUT" ]]; then
|
||||||
|
# On merge failure the previous $OUTPUT is stale — remove it so waybar
|
||||||
|
# falls back to XDG's system config instead of running with stale merged data.
|
||||||
|
merge_config || rm -f "$OUTPUT"
|
||||||
|
fi
|
||||||
|
bootstrap_style
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec waybar "$@"
|
||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
# ABOUTME: Waybar module showing battery conservation mode status.
|
||||||
|
# ABOUTME: Outputs heart icon when active (threshold ≤80), empty when inactive.
|
||||||
|
|
||||||
|
THRESHOLD_FILE="/sys/class/power_supply/BAT0/charge_control_end_threshold"
|
||||||
|
|
||||||
|
# No battery threshold support → no output → Waybar hides module
|
||||||
|
[[ -f "$THRESHOLD_FILE" ]] || exit 0
|
||||||
|
|
||||||
|
THRESHOLD=$(cat "$THRESHOLD_FILE")
|
||||||
|
|
||||||
|
if [[ "$THRESHOLD" -le 80 ]]; then
|
||||||
|
jq --compact-output -n \
|
||||||
|
--arg text "♥" \
|
||||||
|
--arg tooltip "Battery Conservation: ON (limit ${THRESHOLD}%)" \
|
||||||
|
--arg class "on" \
|
||||||
|
'{text: $text, tooltip: $tooltip, class: $class}'
|
||||||
|
fi
|
||||||
|
# Threshold > 80 → no output → Waybar hides module
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
# ABOUTME: Waybar-Modul das den CPU-Governor als JSON ausgibt.
|
# ABOUTME: Waybar module that outputs the CPU governor as JSON.
|
||||||
# ABOUTME: Wird von der Waybar custom/cpugov Config referenziert.
|
# ABOUTME: Referenced by the Waybar custom/cpugov config.
|
||||||
|
|
||||||
CPU_GOV=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
|
CPU_GOV=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor 2>/dev/null)
|
||||||
|
|
||||||
case $CPU_GOV in
|
case $CPU_GOV in
|
||||||
performance)
|
performance)
|
||||||
|
|||||||
@@ -1,39 +1,33 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
# ABOUTME: Waybar-Modul das die GPU-Auslastung als JSON ausgibt.
|
# ABOUTME: Waybar module that outputs GPU utilization as JSON.
|
||||||
# ABOUTME: Wird von der Waybar custom/gpu-usage Config referenziert.
|
# ABOUTME: Referenced by the Waybar custom/gpu-usage config.
|
||||||
|
|
||||||
while :
|
GPU_STAT=$(cat /sys/class/hwmon/hwmon*/device/gpu_busy_percent 2>/dev/null | head -1 || echo "0")
|
||||||
do
|
GPU_STAT="${GPU_STAT:-0}"
|
||||||
GPU_STAT=$(cat /sys/class/hwmon/hwmon*/device/gpu_busy_percent 2>/dev/null | head -1 || echo "0")
|
ICON="<span color='#69ff94' size='8pt' rise='1.5pt'>▁</span>"
|
||||||
GPU_STAT="${GPU_STAT:-0}"
|
|
||||||
|
if [ "$GPU_STAT" -lt 10 ]; then
|
||||||
ICON="<span color='#69ff94' size='8pt' rise='1.5pt'>▁</span>"
|
ICON="<span color='#69ff94' size='8pt' rise='1.5pt'>▁</span>"
|
||||||
|
elif [ "$GPU_STAT" -lt 20 ]; then
|
||||||
|
ICON="<span color='#2aa9ff' size='8pt' rise='1.5pt'>▂</span>"
|
||||||
|
elif [ "$GPU_STAT" -lt 40 ]; then
|
||||||
|
ICON="<span color='#f8f8f2' size='8pt' rise='1.5pt'>▃</span>"
|
||||||
|
elif [ "$GPU_STAT" -lt 50 ]; then
|
||||||
|
ICON="<span color='#f8f8f2' size='8pt' rise='1.5pt'>▄</span>"
|
||||||
|
elif [ "$GPU_STAT" -lt 60 ]; then
|
||||||
|
ICON="<span color='#ffffa5' size='8pt' rise='1.5pt'>▅</span>"
|
||||||
|
elif [ "$GPU_STAT" -lt 70 ]; then
|
||||||
|
ICON="<span color='#ffffa5' size='8pt' rise='1.5pt'>▆</span>"
|
||||||
|
elif [ "$GPU_STAT" -lt 80 ]; then
|
||||||
|
ICON="<span color='#ff9977' size='8pt' rise='1.5pt'>▇</span>"
|
||||||
|
elif [ "$GPU_STAT" -lt 100 ]; then
|
||||||
|
ICON="<span color='#dd532e' size='8pt' rise='1.5pt'>█</span>"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$GPU_STAT" -lt 10 ]; then
|
jq --unbuffered --compact-output -n \
|
||||||
ICON="<span color='#69ff94' size='8pt' rise='1.5pt'>▁</span>"
|
--arg text "GPU $ICON" \
|
||||||
elif [ "$GPU_STAT" -lt 20 ]; then
|
--arg alt "GPU $ICON $GPU_STAT%" \
|
||||||
ICON="<span color='#2aa9ff' size='8pt' rise='1.5pt'>▂</span>"
|
--arg tooltip "GPU $ICON $GPU_STAT%" \
|
||||||
elif [ "$GPU_STAT" -lt 40 ]; then
|
--arg class "gpustat" \
|
||||||
ICON="<span color='#f8f8f2' size='8pt' rise='1.5pt'>▃</span>"
|
--argjson percentage "$GPU_STAT" \
|
||||||
elif [ "$GPU_STAT" -lt 50 ]; then
|
'{text: $text, alt: $alt, tooltip: $tooltip, class: $class, percentage: $percentage}'
|
||||||
ICON="<span color='#f8f8f2' size='8pt' rise='1.5pt'>▄</span>"
|
|
||||||
elif [ "$GPU_STAT" -lt 60 ]; then
|
|
||||||
ICON="<span color='#ffffa5' size='8pt' rise='1.5pt'>▅</span>"
|
|
||||||
elif [ "$GPU_STAT" -lt 70 ]; then
|
|
||||||
ICON="<span color='#ffffa5' size='8pt' rise='1.5pt'>▆</span>"
|
|
||||||
elif [ "$GPU_STAT" -lt 80 ]; then
|
|
||||||
ICON="<span color='#ff9977' size='8pt' rise='1.5pt'>▇</span>"
|
|
||||||
elif [ "$GPU_STAT" -lt 100 ]; then
|
|
||||||
ICON="<span color='#dd532e' size='8pt' rise='1.5pt'>█</span>"
|
|
||||||
fi
|
|
||||||
|
|
||||||
s="text|alt|tooltip|class|percentage
|
|
||||||
GPU $ICON|GPU $ICON $GPU_STAT%|GPU $ICON $GPU_STAT%|gpustat|$GPU_STAT"
|
|
||||||
|
|
||||||
jq --unbuffered --compact-output -Rn '
|
|
||||||
( input | split("|") ) as $keys |
|
|
||||||
( inputs | split("|") ) as $vals |
|
|
||||||
[[$keys, $vals] | transpose[] | {key:.[0],value:.[1]}] | from_entries
|
|
||||||
' <<<"$s"
|
|
||||||
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
|
|||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ABOUTME: Outputs JSON status for waybar nightlight module.
|
||||||
|
# ABOUTME: Checks wlsunset systemd service, shows warm icon when active.
|
||||||
|
|
||||||
|
if systemctl --user is-active --quiet wlsunset; then
|
||||||
|
jq -nc '{text: "", alt: "on", tooltip: "Nightlight: An (5000K)", class: "on"}'
|
||||||
|
else
|
||||||
|
jq -nc '{text: "", alt: "off", tooltip: "Nightlight: Aus", class: "off"}'
|
||||||
|
fi
|
||||||
Executable
+68
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
# ABOUTME: Waybar module that checks for available package updates with caching.
|
||||||
|
# ABOUTME: Combines pacman repo updates (checkupdates) and AUR updates (paru -Qua).
|
||||||
|
|
||||||
|
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/moonarch"
|
||||||
|
CACHE_FILE="$CACHE_DIR/waybar-updates"
|
||||||
|
PACMAN_DB="/var/lib/pacman/local"
|
||||||
|
MAX_AGE=3600
|
||||||
|
|
||||||
|
mkdir -p "$CACHE_DIR"
|
||||||
|
|
||||||
|
needs_refresh() {
|
||||||
|
# No cache yet
|
||||||
|
[[ ! -f "$CACHE_FILE" ]] && return 0
|
||||||
|
|
||||||
|
# Pacman DB changed since last check (update was installed)
|
||||||
|
[[ "$PACMAN_DB" -nt "$CACHE_FILE" ]] && return 0
|
||||||
|
|
||||||
|
# Cache older than MAX_AGE
|
||||||
|
local age=$(( $(date +%s) - $(stat -c %Y "$CACHE_FILE") ))
|
||||||
|
[[ "$age" -ge "$MAX_AGE" ]] && return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if needs_refresh; then
|
||||||
|
repo_updates=$(checkupdates 2>/dev/null)
|
||||||
|
repo_count=0
|
||||||
|
if [[ -n "$repo_updates" ]]; then
|
||||||
|
repo_count=$(echo "$repo_updates" | wc -l)
|
||||||
|
fi
|
||||||
|
|
||||||
|
aur_updates=""
|
||||||
|
aur_count=0
|
||||||
|
if command -v paru &>/dev/null; then
|
||||||
|
aur_updates=$(paru -Qua 2>/dev/null)
|
||||||
|
if [[ -n "$aur_updates" ]]; then
|
||||||
|
aur_count=$(echo "$aur_updates" | wc -l)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
total=$((repo_count + aur_count))
|
||||||
|
|
||||||
|
if [[ "$total" -eq 0 ]]; then
|
||||||
|
echo "" > "$CACHE_FILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build tooltip with package lists
|
||||||
|
tooltip=""
|
||||||
|
if [[ -n "$repo_updates" ]]; then
|
||||||
|
tooltip+="Repo ($repo_count):"$'\n'"$repo_updates"
|
||||||
|
fi
|
||||||
|
if [[ -n "$aur_updates" ]]; then
|
||||||
|
[[ -n "$tooltip" ]] && tooltip+=$'\n\n'
|
||||||
|
tooltip+="AUR ($aur_count):"$'\n'"$aur_updates"
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq --compact-output -n \
|
||||||
|
--arg text "$total" \
|
||||||
|
--arg alt "has-updates" \
|
||||||
|
--arg tooltip "$tooltip" \
|
||||||
|
--arg class "has-updates" \
|
||||||
|
'{text: $text, alt: $alt, tooltip: $tooltip, class: $class}' > "$CACHE_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Output cached result (empty cache = no updates = module hidden)
|
||||||
|
cat "$CACHE_FILE"
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- ABOUTME: System-wide fontconfig generic-family defaults for Moonarch. -->
|
||||||
|
<!-- ABOUTME: Loads after 60-latin (number 65) so these prefs win over stock defaults. -->
|
||||||
|
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
|
||||||
|
<fontconfig>
|
||||||
|
<description>Moonarch generic-family defaults</description>
|
||||||
|
<!-- binding="strong" required: the default weak <prefer> ranks behind
|
||||||
|
stock generic fallbacks, so it would not take effect. -->
|
||||||
|
<alias binding="strong">
|
||||||
|
<family>sans-serif</family>
|
||||||
|
<prefer>
|
||||||
|
<family>UbuntuSans Nerd Font</family>
|
||||||
|
</prefer>
|
||||||
|
</alias>
|
||||||
|
<alias binding="strong">
|
||||||
|
<family>monospace</family>
|
||||||
|
<prefer>
|
||||||
|
<family>UbuntuSansMono Nerd Font</family>
|
||||||
|
</prefer>
|
||||||
|
</alias>
|
||||||
|
</fontconfig>
|
||||||
@@ -35,6 +35,12 @@ layout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Greeter needs no portal services — prevent GTK from triggering
|
||||||
|
// xdg-desktop-portal activation (which fails without a proper display).
|
||||||
|
environment {
|
||||||
|
"GTK_USE_PORTAL" "0"
|
||||||
|
}
|
||||||
|
|
||||||
// Start moongreet and quit niri once moongreet exits.
|
// Start moongreet and quit niri once moongreet exits.
|
||||||
// Retry loop ensures niri shuts down even on early moongreet crashes.
|
// Retry loop ensures niri shuts down even on early moongreet crashes.
|
||||||
spawn-sh-at-startup "moongreet; while ! niri msg action quit --skip-confirmation 2>/dev/null; do sleep 0.5; done"
|
spawn-sh-at-startup "moongreet; while ! niri msg action quit --skip-confirmation 2>/dev/null; do sleep 0.5; done"
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
[appearance]
|
[appearance]
|
||||||
background = "/usr/share/moonarch/wallpaper.jpg"
|
background = "/usr/share/moonarch/wallpaper.jpg"
|
||||||
|
cursor-theme = "Sweet-cursors"
|
||||||
|
cursor-size = 24
|
||||||
|
|
||||||
[behavior]
|
[behavior]
|
||||||
# show_user_list = true
|
# show_user_list = true
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Disable stock OSC — ModernZ replaces it.
|
||||||
|
osc=no
|
||||||
|
|
||||||
|
# Hide native title bar for a cleaner borderless look (ModernZ draws its own).
|
||||||
|
title-bar=no
|
||||||
|
|
||||||
|
# Cap window size at 80% of screen for oversized videos.
|
||||||
|
autofit-larger=80%x80%
|
||||||
|
|
||||||
|
# --- ModernZ overrides ---
|
||||||
|
# mpv treats # as a mid-line comment; the full value must be quoted so the
|
||||||
|
# hex color survives.
|
||||||
|
script-opts-append="modernz-seekbarfg_color=#b4befe"
|
||||||
|
script-opts-append="modernz-seek_handle_color=#b4befe"
|
||||||
|
script-opts-append="modernz-seek_handle_border_color=#b4befe"
|
||||||
|
script-opts-append="modernz-hover_effect_color=#b4befe"
|
||||||
|
script-opts-append="modernz-nibble_color=#b4befe"
|
||||||
|
script-opts-append="modernz-ontop_button=no"
|
||||||
|
script-opts-append="modernz-window_title_font_size=18"
|
||||||
|
|
||||||
|
# Scale OSC down globally
|
||||||
|
script-opts-append="modernz-scalewindowed=0.75"
|
||||||
|
script-opts-append="modernz-scalefullscreen=0.75"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# ABOUTME: Restores battery charge threshold from saved state on boot.
|
||||||
|
# ABOUTME: Only runs on laptops with threshold support and a saved state file.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Restore battery conservation mode threshold
|
||||||
|
After=sysinit.target
|
||||||
|
ConditionPathExists=/sys/class/power_supply/BAT0/charge_control_end_threshold
|
||||||
|
ConditionPathExists=/var/lib/moonarch/batsaver-threshold
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/bin/moonarch-batsaver-restore
|
||||||
|
NoNewPrivileges=true
|
||||||
|
ProtectHome=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectKernelModules=true
|
||||||
|
ProtectControlGroups=true
|
||||||
|
RestrictNamespaces=true
|
||||||
|
RestrictRealtime=true
|
||||||
|
LockPersonality=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# ABOUTME: systemd user service for image clipboard history via cliphist + wl-paste.
|
||||||
|
# ABOUTME: Stores image clipboard entries in XDG_RUNTIME_DIR.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Clipboard history manager (image)
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
After=cliphist-text.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/bin/wl-paste --type image --watch cliphist -db-path %t/cliphist/db store
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# ABOUTME: systemd user service for text clipboard history via cliphist + wl-paste.
|
||||||
|
# ABOUTME: Wipes history on start, stores text entries in XDG_RUNTIME_DIR.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Clipboard history manager (text)
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStartPre=/bin/sh -c 'mkdir -p $XDG_RUNTIME_DIR/cliphist && /usr/bin/cliphist wipe'
|
||||||
|
ExecStart=/usr/bin/wl-paste --watch cliphist -db-path %t/cliphist/db store
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Nautilus File Manager (GApplication Service)
|
||||||
|
After=graphical-session.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=nautilus --gapplication-service
|
||||||
|
Restart=on-failure
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# ABOUTME: systemd user service for wlsunset night light (blue light filter).
|
||||||
|
# ABOUTME: Starts after kanshi to ensure all outputs are configured.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Wlsunset night light (blue light filter)
|
||||||
|
Documentation=man:wlsunset(1)
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
After=graphical-session.target kanshi.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
# Give kanshi time to configure all outputs before wlsunset captures them
|
||||||
|
ExecStartPre=/bin/sleep 2
|
||||||
|
ExecStart=/usr/bin/wlsunset -T 6500 -t 5000 -S 00:00 -s 00:01
|
||||||
|
ExecStartPost=/usr/bin/pkill -RTMIN+11 waybar
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[preferred]
|
||||||
|
default=gnome;gtk;
|
||||||
|
org.freedesktop.impl.portal.Access=gtk;
|
||||||
|
org.freedesktop.impl.portal.Notification=gtk;
|
||||||
|
org.freedesktop.impl.portal.Secret=gnome-keyring;
|
||||||
|
# xdg-desktop-portal-gtk reports the Inhibit interface as success even though
|
||||||
|
# nothing implements it under Niri, which makes Firefox/Waterfox skip the
|
||||||
|
# native Wayland idle-inhibit. With no backend the browser falls back to
|
||||||
|
# zwp_idle_inhibit, which Niri honors, so windowed video keeps the screen awake.
|
||||||
|
org.freedesktop.impl.portal.Inhibit=none;
|
||||||
+19
-32
@@ -1,5 +1,4 @@
|
|||||||
# ABOUTME: Moonarch default zsh configuration with Catppuccin-themed prompt.
|
# ABOUTME: Moonarch default zsh configuration with Catppuccin-themed prompt.
|
||||||
# ABOUTME: Sources user overrides from ~/.zshrc.d/ and ~/.zshrc.local
|
|
||||||
|
|
||||||
# --- History ---
|
# --- History ---
|
||||||
HISTFILE=~/.histfile
|
HISTFILE=~/.histfile
|
||||||
@@ -30,26 +29,25 @@ add-zsh-hook preexec _preexec_title
|
|||||||
|
|
||||||
# --- Prompt (Catppuccin Mocha) ---
|
# --- Prompt (Catppuccin Mocha) ---
|
||||||
parse_git_branch() {
|
parse_git_branch() {
|
||||||
local branch=""
|
# Gate on cheap check first — spawning git in every non-repo directory on every
|
||||||
branch=$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
|
# prompt render costs 20-80ms per prompt. Pattern-match the status output with
|
||||||
local git_status=$(git status --porcelain 2>/dev/null)
|
# zsh glob matching instead of piping to grep for three subshell-spawning checks.
|
||||||
local color=green
|
git rev-parse --git-dir &>/dev/null || return
|
||||||
if echo "$git_status" | grep -q "^ M"; then
|
local branch="" git_status="" color=green flags=""
|
||||||
color=yellow
|
branch=$(git symbolic-ref --short HEAD 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)
|
||||||
branch="${branch}*"
|
git_status=$(git status --porcelain 2>/dev/null)
|
||||||
|
if [[ "$git_status" == *$'\n M '* || "$git_status" == " M "* || "$git_status" == *$'\nM'* ]]; then
|
||||||
|
color=yellow; flags+="*"
|
||||||
fi
|
fi
|
||||||
if echo "$git_status" | grep -qE "^ A|^\?\?"; then
|
if [[ "$git_status" == *$'\nA '* || "$git_status" == "A "* || "$git_status" == *'??'* ]]; then
|
||||||
color=yellow
|
color=yellow; flags+="+"
|
||||||
branch="${branch}+"
|
|
||||||
fi
|
fi
|
||||||
if echo "$git_status" | grep -q "^ D"; then
|
if [[ "$git_status" == *$'\n D '* || "$git_status" == " D "* ]]; then
|
||||||
color=yellow
|
color=yellow; flags+="-"
|
||||||
branch="${branch}-"
|
|
||||||
fi
|
fi
|
||||||
if [[ -n "$branch" ]]; then
|
if [[ -n "$branch" ]]; then
|
||||||
branch=[%F{${color}}${branch}%F{reset}]
|
echo " [%F{${color}}${branch}${flags}%F{reset}]"
|
||||||
fi
|
fi
|
||||||
echo " $branch"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
precmd() {
|
precmd() {
|
||||||
@@ -117,12 +115,12 @@ if command -v fzf &>/dev/null; then
|
|||||||
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"
|
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Plugins (oh-my-zsh) ---
|
# --- Plugins (system packages) ---
|
||||||
if [[ -d "${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting" ]]; then
|
if [[ -f /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]]; then
|
||||||
source "${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
|
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
|
||||||
fi
|
fi
|
||||||
if [[ -d "${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions" ]]; then
|
if [[ -f /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh ]]; then
|
||||||
source "${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh"
|
source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||||
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
|
ZSH_AUTOSUGGEST_STRATEGY=(history completion)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -141,14 +139,3 @@ export XDG_SESSION_TYPE="wayland"
|
|||||||
export EDITOR="nvim"
|
export EDITOR="nvim"
|
||||||
export SUDO_EDITOR="nvim"
|
export SUDO_EDITOR="nvim"
|
||||||
export MOZ_ENABLE_WAYLAND="1"
|
export MOZ_ENABLE_WAYLAND="1"
|
||||||
|
|
||||||
# --- User override scripts ---
|
|
||||||
# Drop custom config snippets into ~/.zshrc.d/*.zsh
|
|
||||||
if [[ -d "$HOME/.zshrc.d" ]]; then
|
|
||||||
for f in "$HOME/.zshrc.d"/*.zsh(N); do
|
|
||||||
source "$f"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Single-file user override (for simple additions)
|
|
||||||
[[ -f "$HOME/.zshrc.local" ]] && source "$HOME/.zshrc.local"
|
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
// ABOUTME: User override for Waybar — extends the system-wide config from /etc/xdg/waybar/.
|
|
||||||
// ABOUTME: Define custom modules here and add them to modules-left/center/right.
|
|
||||||
|
|
||||||
// Load system-wide Moonarch config as base.
|
|
||||||
// Properties defined here override those from the include.
|
|
||||||
"include": ["/etc/xdg/waybar/config"]
|
|
||||||
|
|
||||||
// Example: extend module bar (must be specified completely as it replaces
|
|
||||||
// the system-wide one):
|
|
||||||
//
|
|
||||||
// "modules-right": [
|
|
||||||
// "mpris",
|
|
||||||
// "custom/cpugov",
|
|
||||||
// "group/net",
|
|
||||||
// "group/sound",
|
|
||||||
// "backlight",
|
|
||||||
// "custom/keyboard",
|
|
||||||
// "battery",
|
|
||||||
// "group/indicators"
|
|
||||||
// ],
|
|
||||||
|
|
||||||
// Example: show HID++ device battery (e.g. Logitech keyboard)
|
|
||||||
// moonarch-waybar-hidpp finds the correct hidpp_battery_* entry dynamically
|
|
||||||
//
|
|
||||||
// "custom/keyboard": {
|
|
||||||
// "exec": "moonarch-waybar-hidpp 'G515 LS TKL'",
|
|
||||||
// "return-type": "json",
|
|
||||||
// "interval": 120,
|
|
||||||
// "format": "{}",
|
|
||||||
// "exec-on-event": false
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/* ABOUTME: User override for Waybar styling — extends the system-wide style.css. */
|
|
||||||
/* ABOUTME: Define custom styles here, the system-wide base is loaded via @import. */
|
|
||||||
|
|
||||||
@import url("/etc/xdg/waybar/style.css");
|
|
||||||
|
|
||||||
/* Add custom styles below. */
|
|
||||||
/* Selectors from the system-wide config can be overridden here. */
|
|
||||||
|
|
||||||
/* Example: color Logitech keyboard battery */
|
|
||||||
/*
|
|
||||||
#battery-keyboard.warning:not(.charging) {
|
|
||||||
color: #e6a200;
|
|
||||||
}
|
|
||||||
|
|
||||||
#battery-keyboard.critical:not(.charging) {
|
|
||||||
color: #cc3436;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,460 +0,0 @@
|
|||||||
# ABOUTME: Moonarch default dunst notification daemon config with Catppuccin Mocha colors.
|
|
||||||
# ABOUTME: User overrides go in ~/.config/dunst/dunstrc
|
|
||||||
|
|
||||||
# See dunst(5) for all configuration options
|
|
||||||
|
|
||||||
[global]
|
|
||||||
### Display ###
|
|
||||||
|
|
||||||
enable_posix_regex = true
|
|
||||||
|
|
||||||
# Which monitor should the notifications be displayed on.
|
|
||||||
monitor = 0
|
|
||||||
|
|
||||||
# Display notification on focused monitor. Possible modes are:
|
|
||||||
# mouse: follow mouse pointer
|
|
||||||
# keyboard: follow window with keyboard focus
|
|
||||||
# none: don't follow anything
|
|
||||||
#
|
|
||||||
# "keyboard" needs a window manager that exports the
|
|
||||||
# _NET_ACTIVE_WINDOW property.
|
|
||||||
# This should be the case for almost all modern window managers.
|
|
||||||
#
|
|
||||||
# If this option is set to mouse or keyboard, the monitor option
|
|
||||||
# will be ignored.
|
|
||||||
follow = mouse
|
|
||||||
|
|
||||||
### Geometry ###
|
|
||||||
|
|
||||||
# dynamic width from 0 to 300
|
|
||||||
# width = (0, 300)
|
|
||||||
# constant width of 300
|
|
||||||
width = 300
|
|
||||||
|
|
||||||
# The maximum height of a single notification, excluding the frame.
|
|
||||||
#height = 300
|
|
||||||
|
|
||||||
# Position the notification in the top right corner
|
|
||||||
origin = top-right
|
|
||||||
|
|
||||||
# Offset from the origin
|
|
||||||
offset = (15, 15)
|
|
||||||
|
|
||||||
# Scale factor. It is auto-detected if value is 0.
|
|
||||||
scale = 0
|
|
||||||
|
|
||||||
# Maximum number of notification (0 means no limit)
|
|
||||||
notification_limit = 10
|
|
||||||
|
|
||||||
### Progress bar ###
|
|
||||||
|
|
||||||
# Turn on the progess bar. It appears when a progress hint is passed with
|
|
||||||
# for example dunstify -h int:value:12
|
|
||||||
progress_bar = true
|
|
||||||
|
|
||||||
# Set the progress bar height. This includes the frame, so make sure
|
|
||||||
# it's at least twice as big as the frame width.
|
|
||||||
progress_bar_height = 8
|
|
||||||
|
|
||||||
# Set the frame width of the progress bar
|
|
||||||
progress_bar_frame_width = 1
|
|
||||||
|
|
||||||
# Set the minimum width for the progress bar
|
|
||||||
progress_bar_min_width = 150
|
|
||||||
|
|
||||||
# Set the maximum width for the progress bar
|
|
||||||
progress_bar_max_width = 300
|
|
||||||
|
|
||||||
highlight = "#b4befe"
|
|
||||||
|
|
||||||
# Show how many messages are currently hidden (because of
|
|
||||||
# notification_limit).
|
|
||||||
indicate_hidden = yes
|
|
||||||
|
|
||||||
# The transparency of the window. Range: [0; 100].
|
|
||||||
# This option will only work if a compositing window manager is
|
|
||||||
# present (e.g. xcompmgr, compiz, etc.). (X11 only)
|
|
||||||
transparency = 0
|
|
||||||
|
|
||||||
# Draw a line of "separator_height" pixel height between two
|
|
||||||
# notifications.
|
|
||||||
# Set to 0 to disable.
|
|
||||||
# If gap_size is greater than 0, this setting will be ignored.
|
|
||||||
separator_height = 2
|
|
||||||
|
|
||||||
# Padding between text and separator.
|
|
||||||
padding = 16
|
|
||||||
|
|
||||||
# Horizontal padding.
|
|
||||||
horizontal_padding = 16
|
|
||||||
|
|
||||||
# Padding between text and icon.
|
|
||||||
text_icon_padding = 0
|
|
||||||
|
|
||||||
# Defines width in pixels of frame around the notification window.
|
|
||||||
# Set to 0 to disable.
|
|
||||||
frame_width = 2
|
|
||||||
|
|
||||||
# Defines color of the frame around the notification window.
|
|
||||||
frame_color = "#b4befe"
|
|
||||||
|
|
||||||
# Size of gap to display between notifications - requires a compositor.
|
|
||||||
# If value is greater than 0, separator_height will be ignored and a border
|
|
||||||
# of size frame_width will be drawn around each notification instead.
|
|
||||||
# Click events on gaps do not currently propagate to applications below.
|
|
||||||
gap_size = 5
|
|
||||||
|
|
||||||
# Define a color for the separator.
|
|
||||||
# possible values are:
|
|
||||||
# * auto: dunst tries to find a color fitting to the background;
|
|
||||||
# * foreground: use the same color as the foreground;
|
|
||||||
# * frame: use the same color as the frame;
|
|
||||||
# * anything else will be interpreted as a X color.
|
|
||||||
separator_color = frame
|
|
||||||
|
|
||||||
# Sort messages by urgency.
|
|
||||||
sort = yes
|
|
||||||
|
|
||||||
# Don't remove messages, if the user is idle (no mouse or keyboard input)
|
|
||||||
# for longer than idle_threshold seconds.
|
|
||||||
# Set to 0 to disable.
|
|
||||||
# A client can set the 'transient' hint to bypass this. See the rules
|
|
||||||
# section for how to disable this if necessary
|
|
||||||
# idle_threshold = 120
|
|
||||||
|
|
||||||
### Text ###
|
|
||||||
|
|
||||||
font = UbuntuSans Nerd Font 10
|
|
||||||
|
|
||||||
# The spacing between lines. If the height is smaller than the
|
|
||||||
# font height, it will get raised to the font height.
|
|
||||||
line_height = 0
|
|
||||||
|
|
||||||
# Possible values are:
|
|
||||||
# full: Allow a small subset of html markup in notifications:
|
|
||||||
# <b>bold</b>
|
|
||||||
# <i>italic</i>
|
|
||||||
# <s>strikethrough</s>
|
|
||||||
# <u>underline</u>
|
|
||||||
#
|
|
||||||
# For a complete reference see
|
|
||||||
# <https://docs.gtk.org/Pango/pango_markup.html>.
|
|
||||||
#
|
|
||||||
# strip: This setting is provided for compatibility with some broken
|
|
||||||
# clients that send markup even though it's not enabled on the
|
|
||||||
# server. Dunst will try to strip the markup but the parsing is
|
|
||||||
# simplistic so using this option outside of matching rules for
|
|
||||||
# specific applications *IS GREATLY DISCOURAGED*.
|
|
||||||
#
|
|
||||||
# no: Disable markup parsing, incoming notifications will be treated as
|
|
||||||
# plain text. Dunst will not advertise that it has the body-markup
|
|
||||||
# capability if this is set as a global setting.
|
|
||||||
#
|
|
||||||
# It's important to note that markup inside the format option will be parsed
|
|
||||||
# regardless of what this is set to.
|
|
||||||
markup = full
|
|
||||||
|
|
||||||
# The format of the message. Possible variables are:
|
|
||||||
# %a appname
|
|
||||||
# %s summary
|
|
||||||
# %b body
|
|
||||||
# %i iconname (including its path)
|
|
||||||
# %I iconname (without its path)
|
|
||||||
# %p progress value if set ([ 0%] to [100%]) or nothing
|
|
||||||
# %n progress value if set without any extra characters
|
|
||||||
# %% Literal %
|
|
||||||
# Markup is allowed
|
|
||||||
format = "<b>%s</b>\n%b"
|
|
||||||
|
|
||||||
# Alignment of message text.
|
|
||||||
# Possible values are "left", "center" and "right".
|
|
||||||
alignment = left
|
|
||||||
|
|
||||||
# Vertical alignment of message text and icon.
|
|
||||||
# Possible values are "top", "center" and "bottom".
|
|
||||||
vertical_alignment = center
|
|
||||||
|
|
||||||
# Show age of message if message is older than show_age_threshold
|
|
||||||
# seconds.
|
|
||||||
# Set to -1 to disable.
|
|
||||||
show_age_threshold = 60
|
|
||||||
|
|
||||||
# Specify where to make an ellipsis in long lines.
|
|
||||||
# Possible values are "start", "middle" and "end".
|
|
||||||
ellipsize = middle
|
|
||||||
|
|
||||||
# Ignore newlines '\n' in notifications.
|
|
||||||
ignore_newline = no
|
|
||||||
|
|
||||||
# Stack together notifications with the same content
|
|
||||||
stack_duplicates = true
|
|
||||||
|
|
||||||
# Hide the count of stacked notifications with the same content
|
|
||||||
hide_duplicate_count = false
|
|
||||||
|
|
||||||
# Display indicators for URLs (U) and actions (A).
|
|
||||||
show_indicators = yes
|
|
||||||
|
|
||||||
### Icons ###
|
|
||||||
|
|
||||||
# Recursive icon lookup. You can set a single theme, instead of having to
|
|
||||||
# define all lookup paths.
|
|
||||||
enable_recursive_icon_lookup = true
|
|
||||||
|
|
||||||
# Set icon theme (only used for recursive icon lookup)
|
|
||||||
icon_theme = "Colloid-Grey-Catppuccin-Dark"
|
|
||||||
# You can also set multiple icon themes, with the leftmost one being used first.
|
|
||||||
# icon_theme = "Adwaita, breeze"
|
|
||||||
|
|
||||||
# Align icons left/right/top/off
|
|
||||||
icon_position = left
|
|
||||||
|
|
||||||
# Scale small icons up to this size, set to 0 to disable. Helpful
|
|
||||||
# for e.g. small files or high-dpi screens. In case of conflict,
|
|
||||||
# max_icon_size takes precedence over this.
|
|
||||||
min_icon_size = 16
|
|
||||||
|
|
||||||
# Scale larger icons down to this size, set to 0 to disable
|
|
||||||
max_icon_size = 64
|
|
||||||
|
|
||||||
# Paths to default icons (only neccesary when not using recursive icon lookup)
|
|
||||||
#icon_path = /usr/share/icons/Tela-purple-dark/16x16/status/:/usr/share/icons/Tela-purple-dark/16x16/devices/
|
|
||||||
|
|
||||||
### History ###
|
|
||||||
|
|
||||||
# Should a notification popped up from history be sticky or timeout
|
|
||||||
# as if it would normally do.
|
|
||||||
sticky_history = yes
|
|
||||||
|
|
||||||
# Maximum amount of notifications kept in history
|
|
||||||
history_length = 20
|
|
||||||
|
|
||||||
### Misc/Advanced ###
|
|
||||||
|
|
||||||
# dmenu path.
|
|
||||||
dmenu = /usr/bin/dmenu -p dunst:
|
|
||||||
|
|
||||||
# Browser for opening urls in context menu.
|
|
||||||
browser = /usr/bin/xdg-open
|
|
||||||
|
|
||||||
# Always run rule-defined scripts, even if the notification is suppressed
|
|
||||||
always_run_script = true
|
|
||||||
|
|
||||||
# Define the title of the windows spawned by dunst
|
|
||||||
title = Dunst
|
|
||||||
|
|
||||||
# Define the class of the windows spawned by dunst
|
|
||||||
class = Dunst
|
|
||||||
|
|
||||||
# Define the corner radius of the notification window
|
|
||||||
# in pixel size. If the radius is 0, you have no rounded
|
|
||||||
# corners.
|
|
||||||
# The radius will be automatically lowered if it exceeds half of the
|
|
||||||
# notification height to avoid clipping text and/or icons.
|
|
||||||
corner_radius = 10
|
|
||||||
|
|
||||||
# Ignore the dbus closeNotification message.
|
|
||||||
# Useful to enforce the timeout set by dunst configuration. Without this
|
|
||||||
# parameter, an application may close the notification sent before the
|
|
||||||
# user defined timeout.
|
|
||||||
ignore_dbusclose = false
|
|
||||||
|
|
||||||
### Wayland ###
|
|
||||||
# These settings are Wayland-specific. They have no effect when using X11
|
|
||||||
|
|
||||||
# Uncomment this if you want to let notications appear under fullscreen
|
|
||||||
# applications (default: overlay)
|
|
||||||
layer = overlay
|
|
||||||
|
|
||||||
# Set this to true to use X11 output on Wayland.
|
|
||||||
force_xwayland = false
|
|
||||||
|
|
||||||
### Legacy
|
|
||||||
|
|
||||||
# Use the Xinerama extension instead of RandR for multi-monitor support.
|
|
||||||
# This setting is provided for compatibility with older nVidia drivers that
|
|
||||||
# do not support RandR and using it on systems that support RandR is highly
|
|
||||||
# discouraged.
|
|
||||||
#
|
|
||||||
# By enabling this setting dunst will not be able to detect when a monitor
|
|
||||||
# is connected or disconnected which might break follow mode if the screen
|
|
||||||
# layout changes.
|
|
||||||
force_xinerama = false
|
|
||||||
|
|
||||||
### mouse
|
|
||||||
|
|
||||||
# Defines list of actions for each mouse event
|
|
||||||
# Possible values are:
|
|
||||||
# * none: Don't do anything.
|
|
||||||
# * do_action: Invoke the action determined by the action_name rule. If there is no
|
|
||||||
# such action, open the context menu.
|
|
||||||
# * open_url: If the notification has exactly one url, open it. If there are multiple
|
|
||||||
# ones, open the context menu.
|
|
||||||
# * close_current: Close current notification.
|
|
||||||
# * close_all: Close all notifications.
|
|
||||||
# * context: Open context menu for the notification.
|
|
||||||
# * context_all: Open context menu for all notifications.
|
|
||||||
# These values can be strung together for each mouse event, and
|
|
||||||
# will be executed in sequence.
|
|
||||||
mouse_left_click = close_current
|
|
||||||
mouse_middle_click = do_action, close_current
|
|
||||||
mouse_right_click = close_all
|
|
||||||
|
|
||||||
# Experimental features that may or may not work correctly. Do not expect them
|
|
||||||
# to have a consistent behaviour across releases.
|
|
||||||
[experimental]
|
|
||||||
# Calculate the dpi to use on a per-monitor basis.
|
|
||||||
# If this setting is enabled the Xft.dpi value will be ignored and instead
|
|
||||||
# dunst will attempt to calculate an appropriate dpi value for each monitor
|
|
||||||
# using the resolution and physical size. This might be useful in setups
|
|
||||||
# where there are multiple screens with very different dpi values.
|
|
||||||
per_monitor_dpi = true
|
|
||||||
|
|
||||||
|
|
||||||
[urgency_low]
|
|
||||||
# IMPORTANT: colors have to be defined in quotation marks.
|
|
||||||
# Otherwise the "#" and following would be interpreted as a comment.
|
|
||||||
background = "#1e1e2e"
|
|
||||||
foreground = "#eff1f5"
|
|
||||||
timeout = 10
|
|
||||||
# Icon for notifications with low urgency, uncomment to enable
|
|
||||||
#default_icon = /path/to/icon
|
|
||||||
|
|
||||||
[urgency_normal]
|
|
||||||
background = "#1e1e2e"
|
|
||||||
foreground = "#eff1f5"
|
|
||||||
timeout = 10
|
|
||||||
# Icon for notifications with normal urgency, uncomment to enable
|
|
||||||
#default_icon = /path/to/icon
|
|
||||||
|
|
||||||
[urgency_critical]
|
|
||||||
background = "#313244"
|
|
||||||
foreground = "#CDD6F4"
|
|
||||||
frame_color = "#eba0ac"
|
|
||||||
timeout = 60
|
|
||||||
# Icon for notifications with critical urgency, uncomment to enable
|
|
||||||
#default_icon = /path/to/icon
|
|
||||||
|
|
||||||
# Every section that isn't one of the above is interpreted as a rules to
|
|
||||||
# override settings for certain messages.
|
|
||||||
#
|
|
||||||
# Messages can be matched by
|
|
||||||
# appname (discouraged, see desktop_entry)
|
|
||||||
# body
|
|
||||||
# category
|
|
||||||
# desktop_entry
|
|
||||||
# icon
|
|
||||||
# match_transient
|
|
||||||
# msg_urgency
|
|
||||||
# stack_tag
|
|
||||||
# summary
|
|
||||||
#
|
|
||||||
# and you can override the
|
|
||||||
# background
|
|
||||||
# foreground
|
|
||||||
# format
|
|
||||||
# frame_color
|
|
||||||
# fullscreen
|
|
||||||
# new_icon
|
|
||||||
# set_stack_tag
|
|
||||||
# set_transient
|
|
||||||
# set_category
|
|
||||||
# timeout
|
|
||||||
# urgency
|
|
||||||
# icon_position
|
|
||||||
# skip_display
|
|
||||||
# history_ignore
|
|
||||||
# action_name
|
|
||||||
# word_wrap
|
|
||||||
# ellipsize
|
|
||||||
# alignment
|
|
||||||
# hide_text
|
|
||||||
#
|
|
||||||
# Shell-like globbing will get expanded.
|
|
||||||
#
|
|
||||||
# Instead of the appname filter, it's recommended to use the desktop_entry filter.
|
|
||||||
# GLib based applications export their desktop-entry name. In comparison to the appname,
|
|
||||||
# the desktop-entry won't get localized.
|
|
||||||
#
|
|
||||||
# SCRIPTING
|
|
||||||
# You can specify a script that gets run when the rule matches by
|
|
||||||
# setting the "script" option.
|
|
||||||
# The script will be called as follows:
|
|
||||||
# script appname summary body icon urgency
|
|
||||||
# where urgency can be "LOW", "NORMAL" or "CRITICAL".
|
|
||||||
#
|
|
||||||
# NOTE: It might be helpful to run dunst -print in a terminal in order
|
|
||||||
# to find fitting options for rules.
|
|
||||||
|
|
||||||
# Disable the transient hint so that idle_threshold cannot be bypassed from the
|
|
||||||
# client
|
|
||||||
#[transient_disable]
|
|
||||||
# match_transient = yes
|
|
||||||
# set_transient = no
|
|
||||||
#
|
|
||||||
# Make the handling of transient notifications more strict by making them not
|
|
||||||
# be placed in history.
|
|
||||||
#[transient_history_ignore]
|
|
||||||
# match_transient = yes
|
|
||||||
# history_ignore = yes
|
|
||||||
|
|
||||||
# fullscreen values
|
|
||||||
# show: show the notifications, regardless if there is a fullscreen window opened
|
|
||||||
# delay: displays the new notification, if there is no fullscreen window active
|
|
||||||
# If the notification is already drawn, it won't get undrawn.
|
|
||||||
# pushback: same as delay, but when switching into fullscreen, the notification will get
|
|
||||||
# withdrawn from screen again and will get delayed like a new notification
|
|
||||||
#[fullscreen_delay_everything]
|
|
||||||
# fullscreen = delay
|
|
||||||
[fullscreen_show_critical]
|
|
||||||
msg_urgency = critical
|
|
||||||
fullscreen = pushback
|
|
||||||
|
|
||||||
#[espeak]
|
|
||||||
# summary = "*"
|
|
||||||
# script = dunst_espeak.sh
|
|
||||||
|
|
||||||
#[script-test]
|
|
||||||
# summary = "*script*"
|
|
||||||
# script = dunst_test.sh
|
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
# # This notification will not be displayed
|
|
||||||
# summary = "foobar"
|
|
||||||
# skip_display = true
|
|
||||||
|
|
||||||
#[history-ignore]
|
|
||||||
# # This notification will not be saved in history
|
|
||||||
# summary = "foobar"
|
|
||||||
# history_ignore = yes
|
|
||||||
|
|
||||||
#[skip-display]
|
|
||||||
# # This notification will not be displayed, but will be included in the history
|
|
||||||
# summary = "foobar"
|
|
||||||
# skip_display = yes
|
|
||||||
|
|
||||||
#[signed_on]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = "*signed on*"
|
|
||||||
# urgency = low
|
|
||||||
#
|
|
||||||
#[signed_off]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = *signed off*
|
|
||||||
# urgency = low
|
|
||||||
#
|
|
||||||
#[says]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = *says*
|
|
||||||
# urgency = critical
|
|
||||||
#
|
|
||||||
#[twitter]
|
|
||||||
# appname = Pidgin
|
|
||||||
# summary = *twitter.com*
|
|
||||||
# urgency = normal
|
|
||||||
#
|
|
||||||
#[stack-volumes]
|
|
||||||
# appname = "some_volume_notifiers"
|
|
||||||
# set_stack_tag = "volume"
|
|
||||||
#
|
|
||||||
# vim: ft=cfg
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
# title=foot
|
# title=foot
|
||||||
# locked-title=no
|
# locked-title=no
|
||||||
|
|
||||||
font=UbuntuSans Nerd Font:size=11
|
font=UbuntuSansMono Nerd Font:size=11
|
||||||
# font-bold=<bold variant of regular font>
|
# font-bold=<bold variant of regular font>
|
||||||
# font-italic=<italic variant of regular font>
|
# font-italic=<italic variant of regular font>
|
||||||
# font-bold-italic=<bold+italic variant of regular font>
|
# font-bold-italic=<bold+italic variant of regular font>
|
||||||
|
|||||||
@@ -2,4 +2,8 @@
|
|||||||
# ABOUTME: User overrides go in ~/.config/gtk-4.0/settings.ini
|
# ABOUTME: User overrides go in ~/.config/gtk-4.0/settings.ini
|
||||||
|
|
||||||
[Settings]
|
[Settings]
|
||||||
|
gtk-theme-name=Colloid-Grey-Dark-Catppuccin
|
||||||
|
gtk-icon-theme-name=Colloid-Grey-Catppuccin-Dark
|
||||||
|
gtk-cursor-theme-name=Sweet-cursors
|
||||||
|
gtk-cursor-theme-size=24
|
||||||
gtk-application-prefer-dark-theme=1
|
gtk-application-prefer-dark-theme=1
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
# ABOUTME: Moonarch default gtklock configuration.
|
|
||||||
# ABOUTME: User overrides go in ~/.config/gtklock/config.ini
|
|
||||||
|
|
||||||
[main]
|
|
||||||
modules=powerbar-module;userinfo-module;playerctl-module;dpms
|
|
||||||
follow-focus=true
|
|
||||||
layout=/etc/xdg/gtklock/gtklock.ui
|
|
||||||
|
|
||||||
[powerbar]
|
|
||||||
show-labels=false
|
|
||||||
linked-buttons=true
|
|
||||||
reboot-command=systemctl reboot
|
|
||||||
poweroff-command=systemctl -i poweroff
|
|
||||||
suspend-command=systemctl suspend
|
|
||||||
userswitch-command=
|
|
||||||
logout-command=
|
|
||||||
|
|
||||||
[playerctl]
|
|
||||||
art-size=64
|
|
||||||
position=under-clock
|
|
||||||
|
|
||||||
[userinfo]
|
|
||||||
round-image=true
|
|
||||||
horizontal-layout=false
|
|
||||||
under-clock=false
|
|
||||||
|
|
||||||
[dpms]
|
|
||||||
idle-hide=true
|
|
||||||
idle-timeout=10
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
<!-- ABOUTME: Moonarch default gtklock UI layout definition. -->
|
|
||||||
<!-- ABOUTME: User overrides go in ~/.config/gtklock/gtklock.ui -->
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<interface>
|
|
||||||
<object class="GtkBox" id="window-box">
|
|
||||||
<property name="name">window-box</property>
|
|
||||||
<property name="margin">20</property>
|
|
||||||
<property name="halign">center</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">50</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="info-box">
|
|
||||||
<property name="name">info-box</property>
|
|
||||||
<property name="halign">center</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">5</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="time-box">
|
|
||||||
<property name="name">time-box</property>
|
|
||||||
<property name="halign">center</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="clock-label">
|
|
||||||
<property name="name">clock-label</property>
|
|
||||||
<property name="halign">center</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="date-label">
|
|
||||||
<property name="name">date-label</property>
|
|
||||||
<property name="halign">center</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRevealer" id="body-revealer">
|
|
||||||
<property name="transition-type">none</property>
|
|
||||||
<property name="reveal-child">0</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkGrid" id="body-grid">
|
|
||||||
<property name="row-spacing">5</property>
|
|
||||||
<property name="column-spacing">5</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="input-label">
|
|
||||||
<property name="name">input-label</property>
|
|
||||||
<property name="label" translatable="yes">Password:</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">0</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkEntry" id="input-field">
|
|
||||||
<property name="name">input-field</property>
|
|
||||||
<property name="width-request">380</property>
|
|
||||||
<property name="visibility">0</property>
|
|
||||||
<property name="caps-lock-warning">0</property>
|
|
||||||
<property name="input-purpose">password</property>
|
|
||||||
<property name="secondary-icon-name">view-reveal-symbolic</property>
|
|
||||||
<signal name="icon-release" handler="window_pw_toggle_vis"/>
|
|
||||||
<signal name="activate" handler="window_pw_check"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
<property name="width">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRevealer" id="message-revealer">
|
|
||||||
<property name="transition-type">none</property>
|
|
||||||
<property name="no-show-all">1</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow" id="message-scrolled-window">
|
|
||||||
<property name="hscrollbar-policy">never</property>
|
|
||||||
<property name="max-content-height">256</property>
|
|
||||||
<property name="propagate-natural-height">1</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkViewport">
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="message-box">
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="homogeneous">1</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">1</property>
|
|
||||||
<property name="width">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="spacing">5</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="warning-label">
|
|
||||||
<property name="name">warning-label</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="error-label">
|
|
||||||
<property name="name">error-label</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="unlock-button">
|
|
||||||
<property name="name">unlock-button</property>
|
|
||||||
<property name="label" translatable="yes">Unlock</property>
|
|
||||||
<style>
|
|
||||||
<class name="suggested-action"/>
|
|
||||||
</style>
|
|
||||||
<signal name="clicked" handler="window_pw_check"/>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">2</property>
|
|
||||||
<property name="width">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</interface>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
/* ABOUTME: Moonarch default gtklock stylesheet. */
|
|
||||||
/* ABOUTME: User overrides go in ~/.config/gtklock/style.css */
|
|
||||||
|
|
||||||
window {
|
|
||||||
background-image: url("/usr/share/moonarch/wallpaper.jpg");
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
#powerbar {
|
|
||||||
padding-bottom: 100px;
|
|
||||||
background: red;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# ABOUTME: kanshi configuration for dynamic display output management.
|
|
||||||
# ABOUTME: Add profiles here to auto-switch outputs on hotplug events.
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ gestures {
|
|||||||
layout {
|
layout {
|
||||||
gaps 8
|
gaps 8
|
||||||
center-focused-column "never"
|
center-focused-column "never"
|
||||||
|
always-center-single-column
|
||||||
|
|
||||||
preset-column-widths {
|
preset-column-widths {
|
||||||
proportion 0.33333
|
proportion 0.33333
|
||||||
@@ -78,15 +79,15 @@ layout {
|
|||||||
|
|
||||||
// xwayland-satellite is managed automatically since niri 25.08
|
// xwayland-satellite is managed automatically since niri 25.08
|
||||||
// kanshi is managed via systemd user service (kanshi.service)
|
// kanshi is managed via systemd user service (kanshi.service)
|
||||||
spawn-at-startup "waybar"
|
spawn-at-startup "moonarch-waybar"
|
||||||
spawn-at-startup "dunst" "-conf" "/etc/xdg/dunst/dunstrc"
|
spawn-at-startup "swaync"
|
||||||
spawn-at-startup "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1"
|
spawn-at-startup "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1"
|
||||||
spawn-at-startup "nm-applet" "--indicator"
|
spawn-at-startup "nm-applet" "--indicator"
|
||||||
spawn-sh-at-startup "waypaper --restore"
|
spawn-sh-at-startup "waypaper --restore"
|
||||||
// spawn-sh-at-startup "nemo . &> /dev/null &"
|
// spawn-sh-at-startup "nemo . &> /dev/null &"
|
||||||
spawn-sh-at-startup "foot --server"
|
spawn-sh-at-startup "foot --server"
|
||||||
spawn-sh-at-startup "mkdir -p $XDG_RUNTIME_DIR/cliphist && wl-paste --watch cliphist -db-path $XDG_RUNTIME_DIR/cliphist/db store"
|
// wlsunset is managed via systemd user service (wlsunset.service)
|
||||||
spawn-sh-at-startup "mkdir -p $XDG_RUNTIME_DIR/cliphist && wl-paste --type image --watch cliphist -db-path $XDG_RUNTIME_DIR/cliphist/db store"
|
// Clipboard history managed by cliphist.service (systemd user service)
|
||||||
|
|
||||||
hotkey-overlay {
|
hotkey-overlay {
|
||||||
hide-not-bound
|
hide-not-bound
|
||||||
@@ -115,6 +116,11 @@ window-rule {
|
|||||||
open-floating true
|
open-floating true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window-rule {
|
||||||
|
match app-id=r#"^mpv$"#
|
||||||
|
open-floating true
|
||||||
|
}
|
||||||
|
|
||||||
window-rule {
|
window-rule {
|
||||||
geometry-corner-radius 4
|
geometry-corner-radius 4
|
||||||
clip-to-geometry true
|
clip-to-geometry true
|
||||||
@@ -125,7 +131,7 @@ binds {
|
|||||||
|
|
||||||
Super+C hotkey-overlay-title=null { spawn "walker" "-s" "clipboard"; }
|
Super+C hotkey-overlay-title=null { spawn "walker" "-s" "clipboard"; }
|
||||||
|
|
||||||
Alt+W { spawn-sh "killall waybar && waybar &"; }
|
Alt+W { spawn-sh "killall waybar && moonarch-waybar &"; }
|
||||||
|
|
||||||
Super+E { spawn-sh "xdg-open ~"; }
|
Super+E { spawn-sh "xdg-open ~"; }
|
||||||
|
|
||||||
@@ -134,7 +140,7 @@ binds {
|
|||||||
|
|
||||||
Mod+Return hotkey-overlay-title="Open a Terminal: foot" { spawn "foot"; }
|
Mod+Return hotkey-overlay-title="Open a Terminal: foot" { spawn "foot"; }
|
||||||
Mod+Space hotkey-overlay-title="Run an Application: walker" { spawn "walker"; }
|
Mod+Space hotkey-overlay-title="Run an Application: walker" { spawn "walker"; }
|
||||||
Super+Alt+L hotkey-overlay-title="Session Menu: moonset" { spawn "moonset"; }
|
Mod+Escape hotkey-overlay-title="Session Menu: moonset" { spawn "moonset"; }
|
||||||
|
|
||||||
Mod+A { spawn "walker" "-s" "audio"; }
|
Mod+A { spawn "walker" "-s" "audio"; }
|
||||||
|
|
||||||
@@ -272,7 +278,7 @@ binds {
|
|||||||
Ctrl+Print { screenshot-screen; }
|
Ctrl+Print { screenshot-screen; }
|
||||||
Alt+Print { screenshot-window; }
|
Alt+Print { screenshot-window; }
|
||||||
|
|
||||||
Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
|
Super+Alt+L allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
|
||||||
|
|
||||||
Mod+Shift+E { quit; }
|
Mod+Shift+E { quit; }
|
||||||
Ctrl+Alt+Delete { quit; }
|
Ctrl+Alt+Delete { quit; }
|
||||||
|
|||||||
@@ -5,9 +5,15 @@
|
|||||||
@description "Idle management for Moonarch (Niri + moonlock)"
|
@description "Idle management for Moonarch (Niri + moonlock)"
|
||||||
|
|
||||||
default:
|
default:
|
||||||
# Media playback inhibits idle (non-browser only, browser uses D-Bus inhibit)
|
# monitor_media: detect active media via PipeWire/PulseAudio sink-inputs
|
||||||
|
# (pactl), not MPRIS. Non-browser players (mpv, vlc, ...) are counted and
|
||||||
|
# inhibit idle. Browser audio is excluded by design; browser idle-inhibit is
|
||||||
|
# expected via D-Bus (enable_dbus_inhibit), which Waterfox/Firefox only send
|
||||||
|
# in fullscreen -- so windowed browser video is NOT caught by stasis.
|
||||||
|
# ignore_remote_media false: also count remote players (Spotify-remote,
|
||||||
|
# KDEConnect, Chromecast); has no effect on windowed browser video.
|
||||||
monitor_media true
|
monitor_media true
|
||||||
ignore_remote_media true
|
ignore_remote_media false
|
||||||
|
|
||||||
# App/process inhibit patterns (apps that don't use D-Bus idle-inhibit)
|
# App/process inhibit patterns (apps that don't use D-Bus idle-inhibit)
|
||||||
inhibit_apps [
|
inhibit_apps [
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"$schema": "/etc/xdg/swaync/configSchema.json",
|
||||||
|
|
||||||
|
"positionX": "right",
|
||||||
|
"positionY": "top",
|
||||||
|
"layer": "overlay",
|
||||||
|
"control-center-layer": "top",
|
||||||
|
"cssPriority": "user",
|
||||||
|
|
||||||
|
"notification-window-width": 300,
|
||||||
|
"notification-window-height": -1,
|
||||||
|
"notification-body-image-height": 100,
|
||||||
|
"notification-body-image-width": 200,
|
||||||
|
|
||||||
|
"timeout": 10,
|
||||||
|
"timeout-low": 5,
|
||||||
|
"timeout-critical": 0,
|
||||||
|
|
||||||
|
"fit-to-screen": true,
|
||||||
|
"control-center-margin-top": 15,
|
||||||
|
"control-center-margin-bottom": 15,
|
||||||
|
"control-center-margin-right": 15,
|
||||||
|
"control-center-width": 400,
|
||||||
|
"control-center-height": 600,
|
||||||
|
|
||||||
|
"notification-2fa-action": true,
|
||||||
|
"notification-inline-replies": false,
|
||||||
|
"notification-visibility": {},
|
||||||
|
|
||||||
|
"widgets": [
|
||||||
|
"title",
|
||||||
|
"dnd",
|
||||||
|
"notifications"
|
||||||
|
],
|
||||||
|
|
||||||
|
"widget-config": {
|
||||||
|
"title": {
|
||||||
|
"text": "Notifications",
|
||||||
|
"clear-all-button": true,
|
||||||
|
"button-text": "Clear All"
|
||||||
|
},
|
||||||
|
"dnd": {
|
||||||
|
"text": "Do Not Disturb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
/* ABOUTME: Moonarch swaync notification styling with Catppuccin Mocha colors. */
|
||||||
|
/* ABOUTME: Based on catppuccin/swaync v1.0.1 release, accent changed from Blue to Lavender. */
|
||||||
|
|
||||||
|
* {
|
||||||
|
all: unset;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: "UbuntuSans Nerd Font";
|
||||||
|
transition: 200ms;
|
||||||
|
--notification-icon-size: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
trough highlight {
|
||||||
|
background: #cdd6f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale {
|
||||||
|
margin: 0 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale trough {
|
||||||
|
margin: 0rem 1rem;
|
||||||
|
min-height: 8px;
|
||||||
|
min-width: 70px;
|
||||||
|
border-radius: 12.6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
trough slider {
|
||||||
|
margin: -10px;
|
||||||
|
border-radius: 12.6px;
|
||||||
|
box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
background-color: #b4befe;
|
||||||
|
}
|
||||||
|
|
||||||
|
trough slider:hover {
|
||||||
|
box-shadow: 0 0 2px rgba(0, 0, 0, 0.8), 0 0 8px #b4befe;
|
||||||
|
}
|
||||||
|
|
||||||
|
trough {
|
||||||
|
background-color: #313244;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* notifications */
|
||||||
|
.notification-background {
|
||||||
|
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.8), inset 0 0 0 1px #45475a;
|
||||||
|
border-radius: 12.6px;
|
||||||
|
margin: 18px;
|
||||||
|
background: #181825;
|
||||||
|
color: #cdd6f4;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-background .notification {
|
||||||
|
padding: 7px;
|
||||||
|
border-radius: 12.6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-background .notification.critical {
|
||||||
|
box-shadow: inset 0 0 7px 0 #f38ba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-content {
|
||||||
|
margin: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-content overlay {
|
||||||
|
/* icons */
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-content .summary {
|
||||||
|
color: #cdd6f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-content .time {
|
||||||
|
color: #a6adc8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-content .body {
|
||||||
|
color: #bac2de;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification > *:last-child > * {
|
||||||
|
min-height: 3.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-background .close-button {
|
||||||
|
margin: 7px;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 6.3px;
|
||||||
|
color: #1e1e2e;
|
||||||
|
background-color: #f38ba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-background .close-button:hover {
|
||||||
|
background-color: #eba0ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-background .close-button:active {
|
||||||
|
background-color: #f5c2e7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-action {
|
||||||
|
border-radius: 7px;
|
||||||
|
color: #cdd6f4;
|
||||||
|
box-shadow: inset 0 0 0 1px #45475a;
|
||||||
|
margin: 4px;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 0.2rem; /* controls the button size not text size*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-action {
|
||||||
|
background-color: #313244;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-action:hover {
|
||||||
|
background-color: #45475a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification .notification-action:active {
|
||||||
|
background-color: #585b70;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification.critical progress {
|
||||||
|
background-color: #f38ba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification.low progress,
|
||||||
|
.notification.normal progress {
|
||||||
|
background-color: #b4befe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification progress,
|
||||||
|
.notification trough,
|
||||||
|
.notification progressbar {
|
||||||
|
border-radius: 12.6px;
|
||||||
|
padding: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* control center */
|
||||||
|
.control-center {
|
||||||
|
box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.8), inset 0 0 0 1px #313244;
|
||||||
|
border-radius: 12.6px;
|
||||||
|
background-color: #1e1e2e;
|
||||||
|
color: #cdd6f4;
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .notification-background {
|
||||||
|
border-radius: 7px;
|
||||||
|
box-shadow: inset 0 0 0 1px #45475a;
|
||||||
|
margin: 4px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .notification-background .notification {
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .notification-background .notification.low {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .widget-title > label {
|
||||||
|
color: #cdd6f4;
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .widget-title button {
|
||||||
|
border-radius: 7px;
|
||||||
|
color: #cdd6f4;
|
||||||
|
background-color: #313244;
|
||||||
|
box-shadow: inset 0 0 0 1px #45475a;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .widget-title button:hover {
|
||||||
|
background-color: #45475a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .widget-title button:active {
|
||||||
|
background-color: #585b70;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .notification-group {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .notification-group:focus .notification-background {
|
||||||
|
background-color: #313244;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbar slider {
|
||||||
|
margin: -3px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollbar trough {
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dnd */
|
||||||
|
.widget-dnd {
|
||||||
|
margin-top: 5px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-dnd > switch {
|
||||||
|
font-size: initial;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #313244;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-dnd > switch:checked {
|
||||||
|
background: #b4befe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-dnd > switch slider {
|
||||||
|
background: #45475a;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mpris */
|
||||||
|
.widget-mpris-player {
|
||||||
|
background: #313244;
|
||||||
|
border-radius: 12.6px;
|
||||||
|
color: #cdd6f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mpris-overlay {
|
||||||
|
background-color: #313244;
|
||||||
|
opacity: 0.9;
|
||||||
|
padding: 15px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris-album-art {
|
||||||
|
-gtk-icon-size: 100px;
|
||||||
|
border-radius: 12.6px;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #cdd6f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris-subtitle {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #bac2de;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris button {
|
||||||
|
border-radius: 12.6px;
|
||||||
|
color: #cdd6f4;
|
||||||
|
margin: 0 5px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris button image {
|
||||||
|
-gtk-icon-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris button:hover {
|
||||||
|
background-color: #313244;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris button:active {
|
||||||
|
background-color: #45475a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-mpris button:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-menubar > box > .menu-button-bar > button > label {
|
||||||
|
font-size: 3rem;
|
||||||
|
padding: 0.5rem 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-menubar > box > .menu-button-bar > :last-child {
|
||||||
|
color: #f38ba8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.power-buttons button:hover,
|
||||||
|
.powermode-buttons button:hover,
|
||||||
|
.screenshot-buttons button:hover {
|
||||||
|
background: #313244;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-center .widget-label > label {
|
||||||
|
color: #cdd6f4;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-buttons-grid {
|
||||||
|
padding-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-buttons-grid > flowbox > flowboxchild > button label {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-volume {
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-volume label {
|
||||||
|
color: #74c7ec;
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-volume trough highlight {
|
||||||
|
background: #74c7ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-backlight trough highlight {
|
||||||
|
background: #f9e2af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-backlight label {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: #f9e2af;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-backlight .KB {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ click_to_close = true
|
|||||||
as_window = false
|
as_window = false
|
||||||
single_click_activation = true
|
single_click_activation = true
|
||||||
selection_wrap = false
|
selection_wrap = false
|
||||||
theme = "gtk-inherit"
|
theme = "moonarch"
|
||||||
disable_mouse = false
|
disable_mouse = false
|
||||||
page_jump_items = 10
|
page_jump_items = 10
|
||||||
hide_quick_activation = false
|
hide_quick_activation = false
|
||||||
@@ -49,7 +49,6 @@ show_actions = ["alt j"]
|
|||||||
default = [
|
default = [
|
||||||
"desktopapplications",
|
"desktopapplications",
|
||||||
"calc",
|
"calc",
|
||||||
"websearch",
|
|
||||||
]
|
]
|
||||||
empty = ["desktopapplications"]
|
empty = ["desktopapplications"]
|
||||||
max_results = 50
|
max_results = 50
|
||||||
@@ -66,6 +65,10 @@ empty = ["bluetooth"]
|
|||||||
default = ["wireplumber"]
|
default = ["wireplumber"]
|
||||||
empty = ["wireplumber"]
|
empty = ["wireplumber"]
|
||||||
|
|
||||||
|
[providers.sets.sessions]
|
||||||
|
default = ["nirisessions"]
|
||||||
|
empty = ["nirisessions"]
|
||||||
|
|
||||||
[[providers.prefixes]]
|
[[providers.prefixes]]
|
||||||
prefix = ";"
|
prefix = ";"
|
||||||
provider = "providerlist"
|
provider = "providerlist"
|
||||||
@@ -78,26 +81,14 @@ provider = "runner"
|
|||||||
prefix = "/"
|
prefix = "/"
|
||||||
provider = "files"
|
provider = "files"
|
||||||
|
|
||||||
[[providers.prefixes]]
|
|
||||||
prefix = "."
|
|
||||||
provider = "symbols"
|
|
||||||
|
|
||||||
[[providers.prefixes]]
|
[[providers.prefixes]]
|
||||||
prefix = "="
|
prefix = "="
|
||||||
provider = "calc"
|
provider = "calc"
|
||||||
|
|
||||||
[[providers.prefixes]]
|
|
||||||
prefix = "@"
|
|
||||||
provider = "websearch"
|
|
||||||
|
|
||||||
[[providers.prefixes]]
|
[[providers.prefixes]]
|
||||||
prefix = ":"
|
prefix = ":"
|
||||||
provider = "clipboard"
|
provider = "clipboard"
|
||||||
|
|
||||||
[[providers.prefixes]]
|
|
||||||
prefix = "$"
|
|
||||||
provider = "windows"
|
|
||||||
|
|
||||||
[providers.clipboard]
|
[providers.clipboard]
|
||||||
time_format = "relative"
|
time_format = "relative"
|
||||||
|
|
||||||
@@ -150,26 +141,12 @@ wireplumber = [
|
|||||||
{ action = "set_default_device", label = "set default", bind = "ctrl d", after = "Nothing" },
|
{ action = "set_default_device", label = "set default", bind = "ctrl d", after = "Nothing" },
|
||||||
]
|
]
|
||||||
|
|
||||||
archlinuxpkgs = [
|
|
||||||
{ action = "install", bind = "Return", default = true },
|
|
||||||
{ action = "remove", bind = "Return" },
|
|
||||||
{ action = "show_all", label = "show all", bind = "ctrl i", after = "AsyncClearReload" },
|
|
||||||
{ action = "refresh", label = "refresh", bind = "ctrl r", after = "AsyncReload" },
|
|
||||||
{ action = "visit_url", label = "open URL", bind = "ctrl o" },
|
|
||||||
{ action = "show_installed", label = "show installed", bind = "ctrl i", after = "AsyncClearReload" },
|
|
||||||
]
|
|
||||||
|
|
||||||
calc = [
|
calc = [
|
||||||
{ action = "copy", default = true, bind = "Return" },
|
{ action = "copy", default = true, bind = "Return" },
|
||||||
{ action = "delete", bind = "ctrl d", after = "AsyncReload" },
|
{ action = "delete", bind = "ctrl d", after = "AsyncReload" },
|
||||||
{ action = "delete_all", bind = "ctrl shift d", after = "AsyncReload" },
|
{ action = "delete_all", bind = "ctrl shift d", after = "AsyncReload" },
|
||||||
]
|
]
|
||||||
|
|
||||||
websearch = [
|
|
||||||
{ action = "search", default = true, bind = "Return" },
|
|
||||||
{ action = "open_url", label = "open url", default = true, bind = "Return" },
|
|
||||||
]
|
|
||||||
|
|
||||||
files = [
|
files = [
|
||||||
{ action = "open", default = true, bind = "Return" },
|
{ action = "open", default = true, bind = "Return" },
|
||||||
{ action = "opendir", label = "open dir", bind = "ctrl Return" },
|
{ action = "opendir", label = "open dir", bind = "ctrl Return" },
|
||||||
@@ -182,6 +159,3 @@ runner = [
|
|||||||
{ action = "runterminal", label = "run in terminal", bind = "shift Return" },
|
{ action = "runterminal", label = "run in terminal", bind = "shift Return" },
|
||||||
]
|
]
|
||||||
|
|
||||||
symbols = [
|
|
||||||
{ action = "run_cmd", label = "select", default = true, bind = "Return" },
|
|
||||||
]
|
|
||||||
|
|||||||
+11
-6
@@ -1,5 +1,10 @@
|
|||||||
/* ABOUTME: Walker theme that inherits colors from the active GTK4 theme.
|
@define-color window_bg_color #292c3c;
|
||||||
ABOUTME: Only overrides layout/spacing — colors come from Colloid-Dark-Catppuccin or whatever is active. */
|
@define-color window_fg_color #eff1f5;
|
||||||
|
@define-color accent_bg_color #ccd0da;
|
||||||
|
@define-color accent_fg_color rgba(17, 17, 27, 0.87);
|
||||||
|
@define-color error_bg_color #ea999c;
|
||||||
|
@define-color error_fg_color rgba(17, 17, 27, 0.87);
|
||||||
|
@define-color theme_fg_color @window_fg_color;
|
||||||
|
|
||||||
* {
|
* {
|
||||||
all: unset;
|
all: unset;
|
||||||
@@ -8,7 +13,7 @@
|
|||||||
|
|
||||||
popover {
|
popover {
|
||||||
background: lighter(@window_bg_color);
|
background: lighter(@window_bg_color);
|
||||||
border: 1px solid darker(@accent_bg_color);
|
border: 1px solid alpha(@accent_bg_color, 0.15);
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
@@ -27,12 +32,12 @@ scrollbar {
|
|||||||
|
|
||||||
.box-wrapper {
|
.box-wrapper {
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 19px 38px rgba(0, 0, 0, 0.3),
|
0 19px 38px rgba(0, 0, 0, 0.15),
|
||||||
0 15px 12px rgba(0, 0, 0, 0.22);
|
0 15px 12px rgba(0, 0, 0, 0.1);
|
||||||
background: @window_bg_color;
|
background: @window_bg_color;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
border: 1px solid darker(@accent_bg_color);
|
border: 1px solid alpha(@accent_bg_color, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-box,
|
.preview-box,
|
||||||
+81
-145
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"__aboutme1": "Moonarch default waybar configuration for Niri.",
|
"__aboutme1": "Moonarch default waybar configuration for Niri.",
|
||||||
"__aboutme2": "User overrides go in ~/.config/waybar/config",
|
"__aboutme2": "Deployed to /etc/xdg/waybar/ by moonarch-git package.",
|
||||||
"layer": "top",
|
"layer": "top",
|
||||||
"margin-top": 0,
|
"margin-top": 0,
|
||||||
"spacing": 5,
|
"spacing": 5,
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
"modules-left": [
|
"modules-left": [
|
||||||
"group/sys",
|
"group/sys",
|
||||||
"niri/workspaces",
|
"niri/workspaces",
|
||||||
"tray",
|
|
||||||
"wlr/taskbar",
|
"wlr/taskbar",
|
||||||
"niri/window"
|
"niri/window"
|
||||||
],
|
],
|
||||||
@@ -16,32 +15,25 @@
|
|||||||
|
|
||||||
],
|
],
|
||||||
"modules-right": [
|
"modules-right": [
|
||||||
|
"tray",
|
||||||
"mpris",
|
"mpris",
|
||||||
"custom/cpugov",
|
"bluetooth",
|
||||||
"group/net",
|
|
||||||
"group/sound",
|
"group/sound",
|
||||||
"backlight",
|
"group/brightness",
|
||||||
"battery",
|
"group/bat",
|
||||||
"group/indicators"
|
"group/indicators"
|
||||||
],
|
],
|
||||||
"group/indicators": {
|
"group/indicators": {
|
||||||
"orientation": "inherit",
|
"orientation": "inherit",
|
||||||
"modules": [
|
"modules": [
|
||||||
|
"custom/cpugov",
|
||||||
"gamemode",
|
"gamemode",
|
||||||
//"custom/updates",
|
"custom/updates",
|
||||||
"idle_inhibitor",
|
"idle_inhibitor",
|
||||||
"custom/dnd",
|
"custom/notification",
|
||||||
"privacy"
|
"privacy"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"group/net": {
|
|
||||||
"orientation": "inherit",
|
|
||||||
"modules": [
|
|
||||||
"custom/vpn",
|
|
||||||
"network",
|
|
||||||
"bluetooth"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"group/stats": {
|
"group/stats": {
|
||||||
"orientation": "inherit",
|
"orientation": "inherit",
|
||||||
"modules": [
|
"modules": [
|
||||||
@@ -63,9 +55,28 @@
|
|||||||
],
|
],
|
||||||
"drawer": {
|
"drawer": {
|
||||||
"transition-duration": 500,
|
"transition-duration": 500,
|
||||||
"transition-left-to-right": true
|
"transition-left-to-right": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"group/brightness": {
|
||||||
|
"orientation": "inherit",
|
||||||
|
"modules": [
|
||||||
|
"custom/nightlight",
|
||||||
|
"backlight",
|
||||||
|
"backlight/slider"
|
||||||
|
],
|
||||||
|
"drawer": {
|
||||||
|
"transition-duration": 500,
|
||||||
|
"transition-left-to-right": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"group/bat": {
|
||||||
|
"orientation": "inherit",
|
||||||
|
"modules": [
|
||||||
|
"battery",
|
||||||
|
"custom/batsaver"
|
||||||
|
]
|
||||||
|
},
|
||||||
"group/sys": {
|
"group/sys": {
|
||||||
"orientation": "inherit",
|
"orientation": "inherit",
|
||||||
"modules": [
|
"modules": [
|
||||||
@@ -73,23 +84,6 @@
|
|||||||
"clock"
|
"clock"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"network": {
|
|
||||||
"format-wifi": "{icon}",
|
|
||||||
"format-ethernet": " {ifname}",
|
|
||||||
"format-disconnected": " Offline",
|
|
||||||
"tooltip-format": " {ifname} via {gwaddr}",
|
|
||||||
"tooltip-format-wifi": " WiFi {essid} ({signalStrength}%)",
|
|
||||||
"tooltip-format-ethernet": " {ifname}",
|
|
||||||
"tooltip-format-disconnected": "Disconnected",
|
|
||||||
"on-click": "nm-connection-editor",
|
|
||||||
"format-icons": [
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"max-length": 5
|
|
||||||
},
|
|
||||||
"tray": {
|
"tray": {
|
||||||
"icon-size": 15,
|
"icon-size": 15,
|
||||||
"spacing": 10
|
"spacing": 10
|
||||||
@@ -121,7 +115,6 @@
|
|||||||
"on-scroll-down": "shift_down",
|
"on-scroll-down": "shift_down",
|
||||||
"on-click-middle": "alarm-clock-applet"
|
"on-click-middle": "alarm-clock-applet"
|
||||||
}
|
}
|
||||||
// "on-click": "evolution"
|
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"format": "{user}",
|
"format": "{user}",
|
||||||
@@ -197,7 +190,6 @@
|
|||||||
"format": "{icon}",
|
"format": "{icon}",
|
||||||
"icon-size": 16,
|
"icon-size": 16,
|
||||||
"tooltip-format": "{title:.100}",
|
"tooltip-format": "{title:.100}",
|
||||||
// "sort-by-app-id": true,
|
|
||||||
"on-click": "activate",
|
"on-click": "activate",
|
||||||
"on-click-middle": "close",
|
"on-click-middle": "close",
|
||||||
"on-right-middle": "minimize-raise",
|
"on-right-middle": "minimize-raise",
|
||||||
@@ -210,7 +202,7 @@
|
|||||||
"firefox": "Firefox",
|
"firefox": "Firefox",
|
||||||
"VSCodium": "Code",
|
"VSCodium": "Code",
|
||||||
"codium": "Code",
|
"codium": "Code",
|
||||||
"Alacritty": "Terminal",
|
"Alacritty": "Terminal"
|
||||||
},
|
},
|
||||||
"squash-list": [
|
"squash-list": [
|
||||||
"firefox"
|
"firefox"
|
||||||
@@ -223,41 +215,33 @@
|
|||||||
"has-updates": "",
|
"has-updates": "",
|
||||||
"updated": ""
|
"updated": ""
|
||||||
},
|
},
|
||||||
"exec-if": "which waybar-module-pacman-updates",
|
"exec": "moonarch-waybar-updates",
|
||||||
"exec": "waybar-module-pacman-updates",
|
"interval": 60,
|
||||||
"on-click": "alacritty paru"
|
"on-click": "foot env MOONUP_WAIT=1 moonarch-update"
|
||||||
},
|
|
||||||
"custom/dnd": {
|
|
||||||
"format": "{}",
|
|
||||||
"exec": "dunstctl is-paused | sed 's/false//;s/true//'",
|
|
||||||
"interval": 2,
|
|
||||||
"on-click": "dunstctl set-paused toggle"
|
|
||||||
},
|
},
|
||||||
"custom/notification": {
|
"custom/notification": {
|
||||||
"tooltip": false,
|
"tooltip": true,
|
||||||
"format": "{icon} {}",
|
"format": "{icon}",
|
||||||
"format-icons": {
|
"format-icons": {
|
||||||
"notification": "",
|
"notification": "",
|
||||||
"none": "",
|
"none": "",
|
||||||
"dnd-notification": "",
|
"dnd-notification": "",
|
||||||
"dnd-none": "",
|
"dnd-none": "",
|
||||||
"inhibited-notification": "",
|
"inhibited-notification": "",
|
||||||
"inhibited-none": "",
|
"inhibited-none": "",
|
||||||
"dnd-inhibited-notification": "",
|
"dnd-inhibited-notification": "",
|
||||||
"dnd-inhibited-none": ""
|
"dnd-inhibited-none": ""
|
||||||
},
|
},
|
||||||
"return-type": "json",
|
"return-type": "json",
|
||||||
"exec-if": "which swaync-client",
|
"exec-if": "which swaync-client",
|
||||||
"exec": "swaync-client -swb",
|
"exec": "swaync-client -swb",
|
||||||
"on-click": "sh -c 'sleep 0.1s; swaync-client -t -sw; sleep 0.1s'",
|
"on-click": "swaync-client -t -sw",
|
||||||
"on-click-right": "swaync-client -d -sw",
|
"on-click-right": "swaync-client -d -sw",
|
||||||
"escape": true
|
"escape": true
|
||||||
},
|
},
|
||||||
"cava": {
|
"cava": {
|
||||||
// "cava_config": "$XDG_CONFIG_HOME/cava/cava.conf",
|
|
||||||
"framerate": 30,
|
"framerate": 30,
|
||||||
"autosens": 1,
|
"autosens": 1,
|
||||||
//"sensitivity": 50,
|
|
||||||
"bars": 2,
|
"bars": 2,
|
||||||
"lower_cutoff_freq": 50,
|
"lower_cutoff_freq": 50,
|
||||||
"higher_cutoff_freq": 10000,
|
"higher_cutoff_freq": 10000,
|
||||||
@@ -317,16 +301,25 @@
|
|||||||
"<span color='#dd532e' size='8pt' rise='1.5pt'>█</span>"
|
"<span color='#dd532e' size='8pt' rise='1.5pt'>█</span>"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"custom/nightlight": {
|
||||||
|
"exec": "moonarch-waybar-nightlight",
|
||||||
|
"return-type": "json",
|
||||||
|
"interval": "once",
|
||||||
|
"signal": 11,
|
||||||
|
"on-click": "moonarch-nightlight",
|
||||||
|
"format": "{}"
|
||||||
|
},
|
||||||
"custom/cpugov": {
|
"custom/cpugov": {
|
||||||
"exec": "moonarch-waybar-cpugov",
|
"exec": "moonarch-waybar-cpugov",
|
||||||
"return-type": "json",
|
"return-type": "json",
|
||||||
"interval": 5,
|
"interval": 60,
|
||||||
|
"signal": 10,
|
||||||
"on-click": "moonarch-cpugov"
|
"on-click": "moonarch-cpugov"
|
||||||
},
|
},
|
||||||
"custom/gpu-usage": {
|
"custom/gpu-usage": {
|
||||||
"exec": "moonarch-waybar-gpustat",
|
"exec": "moonarch-waybar-gpustat",
|
||||||
"return-type": "json",
|
"return-type": "json",
|
||||||
"restart-interval": 10
|
"interval": 60
|
||||||
},
|
},
|
||||||
"battery": {
|
"battery": {
|
||||||
"bat": "BAT0",
|
"bat": "BAT0",
|
||||||
@@ -337,18 +330,30 @@
|
|||||||
},
|
},
|
||||||
"format": "{capacity}% {icon}",
|
"format": "{capacity}% {icon}",
|
||||||
"format-icons": [
|
"format-icons": [
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
""
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
""
|
||||||
],
|
],
|
||||||
"max-length": 25
|
"max-length": 25,
|
||||||
|
"on-click": "moonarch-batsaver-toggle"
|
||||||
|
},
|
||||||
|
"custom/batsaver": {
|
||||||
|
"exec": "moonarch-waybar-batsaver",
|
||||||
|
"return-type": "json",
|
||||||
|
"interval": 30,
|
||||||
|
"signal": 9
|
||||||
},
|
},
|
||||||
"bluetooth": {
|
"bluetooth": {
|
||||||
// "controller": "controller1", // specify the alias of the controller if there are more than 1 on the system
|
"format": "",
|
||||||
"format": " {status}",
|
"format-disabled": "",
|
||||||
"format-disabled": "", // an empty format will hide the module
|
|
||||||
"format-connected": "<small>{num_connections}</small>",
|
"format-connected": "<small>{num_connections}</small>",
|
||||||
"tooltip-format": "{controller_alias}\t{controller_address}",
|
"tooltip-format": "{controller_alias}\t{controller_address}",
|
||||||
"tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{device_enumerate}\t{device_battery_percentage}%",
|
"tooltip-format-connected": "{controller_alias}\t{controller_address}\n\n{device_enumerate}\t{device_battery_percentage}%",
|
||||||
@@ -364,14 +369,6 @@
|
|||||||
"tooltip-format-activated": " No Lockscreen on idle",
|
"tooltip-format-activated": " No Lockscreen on idle",
|
||||||
"tooltip-format-deactivated": " Lockscreen on idle"
|
"tooltip-format-deactivated": " Lockscreen on idle"
|
||||||
},
|
},
|
||||||
"custom/vpn": {
|
|
||||||
"format": "",
|
|
||||||
"exec": "echo '{\"class\": \"connected\", \"tooltip\": \"VPN Connected\"}'",
|
|
||||||
"exec-if": "nmcli -t -f TYPE,STATE connection show --active | grep -qE '^(vpn|wireguard):'",
|
|
||||||
"return-type": "json",
|
|
||||||
"interval": 5,
|
|
||||||
"signal": 9
|
|
||||||
},
|
|
||||||
"power-profiles-daemon": {
|
"power-profiles-daemon": {
|
||||||
"format": "{icon}",
|
"format": "{icon}",
|
||||||
"tooltip-format": "Power profile: {profile}\nDriver: {driver}",
|
"tooltip-format": "Power profile: {profile}\nDriver: {driver}",
|
||||||
@@ -408,13 +405,10 @@
|
|||||||
"niri/workspaces": {
|
"niri/workspaces": {
|
||||||
"format": "{icon}",
|
"format": "{icon}",
|
||||||
"format-icons": {
|
"format-icons": {
|
||||||
// Named workspaces
|
|
||||||
// (you need to configure them in niri)
|
|
||||||
"browser": "",
|
"browser": "",
|
||||||
"discord": "",
|
"discord": "",
|
||||||
"chat": "<b></b>",
|
"chat": "<b></b>",
|
||||||
|
|
||||||
// Icons by state
|
|
||||||
"active": "",
|
"active": "",
|
||||||
"default": ""
|
"default": ""
|
||||||
}
|
}
|
||||||
@@ -438,114 +432,56 @@
|
|||||||
"device": "intel_backlight"
|
"device": "intel_backlight"
|
||||||
},
|
},
|
||||||
"cffi/niri-workspaces-enhanced": {
|
"cffi/niri-workspaces-enhanced": {
|
||||||
// Make sure to set the path to the install location on your system
|
|
||||||
// "module_path": "~/.config/waybar/niri-workspaces-enhanced.so",
|
|
||||||
"module_path": "/usr/lib/waybar/libwaybar_niri_workspaces_enhanced.so",
|
"module_path": "/usr/lib/waybar/libwaybar_niri_workspaces_enhanced.so",
|
||||||
// Format string for workspace labels. Available placeholders:
|
|
||||||
// {index} - Workspace index number
|
|
||||||
// {name} - Workspace name (might be empty)
|
|
||||||
// {index-and-name} - Index followed by name if present (e.g., "1 Work")
|
|
||||||
// {value} - Name if present, otherwise index
|
|
||||||
// {separator} - ": " when icons are present, "" when empty
|
|
||||||
// {window-icons} - Formatted icons for windows in workspace
|
|
||||||
"format": "{window-icons}",
|
"format": "{window-icons}",
|
||||||
// Apply separate styles to icons depending on current state
|
|
||||||
"window-icon-format": {
|
"window-icon-format": {
|
||||||
"default": "{icon}",
|
"default": "{icon}",
|
||||||
"urgent": "<span foreground='red'>{icon}</span>",
|
"urgent": "<span foreground='red'>{icon}</span>",
|
||||||
"focused": "<span foreground='blue'>{icon}</span>",
|
"focused": "<span foreground='blue'>{icon}</span>"
|
||||||
},
|
},
|
||||||
// A mapping from window app_id to icon. Note that this module does
|
|
||||||
// case-insensitive matching of app_ids, so capitalization doesn't matter.
|
|
||||||
"window-icons": {
|
"window-icons": {
|
||||||
"com.mitchellh.ghostty": "",
|
"com.mitchellh.ghostty": "",
|
||||||
"darktable": "",
|
"darktable": "",
|
||||||
"foot": "",
|
"foot": "",
|
||||||
"google-chrome": "",
|
"google-chrome": "",
|
||||||
"spotify": "",
|
"spotify": "",
|
||||||
"steam": "",
|
"steam": ""
|
||||||
},
|
},
|
||||||
// If no icon is found for a window, the default is used instead
|
"window-icon-default": "*"
|
||||||
"window-icon-default": "*",
|
|
||||||
},
|
},
|
||||||
"height": 40,
|
"height": 40,
|
||||||
"cffi/niri-windows": {
|
"cffi/niri-windows": {
|
||||||
// path where you placed the .so file
|
|
||||||
"module_path": "/usr/lib/waybar-niri-windows.so",
|
"module_path": "/usr/lib/waybar-niri-windows.so",
|
||||||
// configure the module's behavior
|
|
||||||
"options": {
|
"options": {
|
||||||
// set the module mode
|
|
||||||
// "graphical" (default): draw a minimap of windows in the current workspace
|
|
||||||
// "text": draws symbols and a focus indicator for each column (mirrors v1 behavior)
|
|
||||||
"mode": "graphical",
|
"mode": "graphical",
|
||||||
|
|
||||||
// ======= graphical mode options =======
|
|
||||||
// when to show floating windows
|
|
||||||
// - "always": always show floating window view, even if there are no floating windows
|
|
||||||
// - "auto" (default): show floating window view if there are floating windows on the current workspace
|
|
||||||
// - "never": never show floating windows
|
|
||||||
"show-floating": "auto",
|
"show-floating": "auto",
|
||||||
// pick where the floating windows be shown relative to tiled windows
|
|
||||||
// - "left": show floating windows on the left
|
|
||||||
// - "right" (default): show floating windows on the right
|
|
||||||
"floating-position": "right",
|
"floating-position": "right",
|
||||||
// set minimum size of windows, in pixels (default: 1, minimum: 1)
|
|
||||||
// if this value is too large to fit all windows (e.g. in a column with many windows),
|
|
||||||
// it will be reduced
|
|
||||||
"minimum-size": 1,
|
"minimum-size": 1,
|
||||||
// set spacing between windows/columns, in pixels (default: 1, minimum: 0)
|
|
||||||
// if this value is too large, it will be reduced
|
|
||||||
"spacing": 1,
|
"spacing": 1,
|
||||||
// set minimum size of windows, in pixels, to draw icons for (default: 0, minimum: 0)
|
|
||||||
// if unset or 0, icons will only be drawn for tiled windows that are the only one in their column
|
|
||||||
// if 1+, icons will be drawn for all windows where w >= icon-minimum-size and h >= icon-minimum-size
|
|
||||||
// icons must be set in the "rules" section below for this to have any effect
|
|
||||||
"icon-minimum-size": 0,
|
"icon-minimum-size": 0,
|
||||||
// account for borders when calculating window sizes; see note below (default: 0, minimum: 0)
|
"column-borders": 0,
|
||||||
"column-borders": 0, // border on .column
|
"floating-borders": 0,
|
||||||
"floating-borders": 0, // border on .floating
|
"on-tile-click": "FocusWindow",
|
||||||
// trigger actions on tile click (see https://yalter.github.io/niri/niri_ipc/enum.Action.html for available actions)
|
"on-tile-middle-click": "CloseWindow",
|
||||||
// only actions that take a single window ID are supported
|
"on-tile-right-click": "",
|
||||||
// set to an empty string to disable
|
|
||||||
"on-tile-click": "FocusWindow", // (default: FocusWindow)
|
|
||||||
"on-tile-middle-click": "CloseWindow", // (default: CloseWindow)
|
|
||||||
"on-tile-right-click": "", // (default: none)
|
|
||||||
// add CSS classes/icons to windows based on their App ID/Title (see `niri msg windows`)
|
|
||||||
// Go regular expression syntax is supported for app-id and title (see https://pkg.go.dev/regexp/syntax)
|
|
||||||
// rules are checked in the order they are defined - first match wins and checking stops
|
|
||||||
// set "continue" to true to also check and apply subsequent rules even if this rule matches
|
|
||||||
// if multiple rules with icons are applied, the first one will be used
|
|
||||||
// *icons are not drawn for floating windows by default*; set "icon-minimum-size" to enable (see above)
|
|
||||||
"rules": [
|
"rules": [
|
||||||
// .alacritty will be added to all windows with the App ID "Alacritty"
|
|
||||||
// will be drawn in windows that match
|
|
||||||
{ "app-id": "Alacritty", "class": "alacritty", "icon": "" },
|
{ "app-id": "Alacritty", "class": "alacritty", "icon": "" },
|
||||||
// .firefox will be added to all windows with the App ID "firefox"
|
|
||||||
// subsequent rules are also checked and applied for firefox windows
|
|
||||||
{ "app-id": "firefox", "class": "firefox", "continue": true },
|
{ "app-id": "firefox", "class": "firefox", "continue": true },
|
||||||
// .youtube-music will be added to all windows that have "YouTube Music" at the end of their title
|
|
||||||
// will be drawn in windows that match
|
|
||||||
{ "title": "YouTube Music$", "class": "youtube-music", "icon": "" }
|
{ "title": "YouTube Music$", "class": "youtube-music", "icon": "" }
|
||||||
],
|
],
|
||||||
|
|
||||||
// ======= text mode options =======
|
|
||||||
// customize the symbols used to draw the columns/windows
|
|
||||||
"symbols": {
|
"symbols": {
|
||||||
"unfocused": "⋅",
|
"unfocused": "⋅",
|
||||||
"focused": "⊙",
|
"focused": "⊙",
|
||||||
"unfocused-floating": "∗",
|
"unfocused-floating": "∗",
|
||||||
"focused-floating": "⊛",
|
"focused-floating": "⊛",
|
||||||
// text to display when there are no windows on the current workspace
|
|
||||||
// if this is an empty string (default), the module will be hidden when there are no windows
|
|
||||||
"empty": ""
|
"empty": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actions": {
|
"actions": {
|
||||||
// use niri IPC action names to trigger them (see https://yalter.github.io/niri/niri_ipc/enum.Action.html for available actions)
|
|
||||||
// any action that has no fields is supported
|
|
||||||
"on-scroll-up": "FocusColumnLeft",
|
"on-scroll-up": "FocusColumnLeft",
|
||||||
"on-scroll-down": "FocusColumnRight"
|
"on-scroll-down": "FocusColumnRight"
|
||||||
// in graphical mode, don't configure click actions here—they're handled by the module above
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+168
-246
@@ -1,22 +1,23 @@
|
|||||||
|
/* ABOUTME: System-wide Waybar styling for Moonarch. */
|
||||||
|
/* ABOUTME: Uses GTK theme colors via @theme_* variables, Catppuccin Mocha palette. */
|
||||||
|
|
||||||
* {
|
* {
|
||||||
border: none;
|
border: none;
|
||||||
font-family: "Ubuntu Nerd Font", sans-serif;
|
font-family: "UbuntuSans Nerd Font", sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: alpha(@theme_text_color, 0.8);
|
color: alpha(@theme_text_color, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
window#waybar {
|
window#waybar {
|
||||||
/*background: transparent;*/
|
|
||||||
background: alpha(@theme_selected_fg_color, 0.2);
|
background: alpha(@theme_selected_fg_color, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----main groups----*/
|
/* --- Module areas --- */
|
||||||
.modules-right {
|
|
||||||
|
.modules-left {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 0;
|
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.modules-center {
|
.modules-center {
|
||||||
@@ -24,108 +25,63 @@ window#waybar {
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modules-left {
|
.modules-right {
|
||||||
margin: 0 0 0 5px;
|
margin: 0;
|
||||||
/* background-color:alpha(@theme_selected_bg_color, 0.15);
|
padding-left: 5px;
|
||||||
background: @theme_bg_color */
|
padding-right: 5px;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
margin-left: 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* --- Module boxes --- */
|
||||||
## ALL MODULES
|
|
||||||
**/
|
.modules-left>widget>*,
|
||||||
#clock,
|
.modules-center>widget>*,
|
||||||
#battery,
|
.modules-right>widget>* {
|
||||||
#backlight,
|
padding: 0px 10px;
|
||||||
#cpu,
|
border-radius: 4px;
|
||||||
#memory,
|
margin: 8px 2px;
|
||||||
#bluetooth,
|
background-color: alpha(@theme_selected_bg_color, 0.05);
|
||||||
#temperature,
|
}
|
||||||
#network,
|
|
||||||
#pulseaudio,
|
|
||||||
#tray,
|
|
||||||
#mode,
|
|
||||||
#idle_inhibitor,
|
|
||||||
#workspaces,
|
#workspaces,
|
||||||
#custom-power,
|
|
||||||
#custom-menu,
|
|
||||||
#custom-media,
|
|
||||||
#custom-notification,
|
|
||||||
#custom-updates,
|
|
||||||
#custom-pacman,
|
|
||||||
#user,
|
|
||||||
#cava,
|
|
||||||
#custom-gpu-usage,
|
|
||||||
#custom-cpugov,
|
|
||||||
#custom-dnd,
|
|
||||||
#custom-vpn.connected,
|
|
||||||
#power-profiles-daemon,
|
|
||||||
#privacy,
|
|
||||||
#gamemode,
|
|
||||||
#taskbar,
|
#taskbar,
|
||||||
#window {
|
#window {
|
||||||
padding: 0px 10px;
|
border-radius: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/* --- Group children --- */
|
||||||
* GROUPS
|
|
||||||
**/
|
widget widget>* {
|
||||||
|
padding: 0 6px;
|
||||||
|
margin: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Groups --- */
|
||||||
|
|
||||||
#sys,
|
#sys,
|
||||||
#stats,
|
#stats,
|
||||||
#net,
|
#sound,
|
||||||
#sound {
|
#brightness,
|
||||||
margin: 0;
|
#indicators {
|
||||||
|
padding: 0 4px;
|
||||||
color: alpha(@theme_text_color, 0.5);
|
color: alpha(@theme_text_color, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SYS
|
|
||||||
**/
|
|
||||||
#sys {
|
|
||||||
padding: 0 0px 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#custom-power {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#user {
|
|
||||||
padding-left: 0;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#custom-weather {
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#stats .drawer-child {
|
#stats .drawer-child {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#tray {
|
#tray {
|
||||||
border-radius: 4px;
|
padding: 0;
|
||||||
padding: 0px 8px 0px 8px;
|
|
||||||
margin: 8px 0px 8px 0px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom-notification {
|
/* --- Sound --- */
|
||||||
padding-right: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SOUND
|
|
||||||
**/
|
|
||||||
|
|
||||||
#cava {
|
|
||||||
background-color: transparent;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pulseaudio-slider {
|
#pulseaudio-slider {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
@@ -140,7 +96,6 @@ window#waybar {
|
|||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
background-color: @insensitive_bg_color;
|
background-color: @insensitive_bg_color;
|
||||||
border: 1px solid alpha(@theme_selected_bg_color, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pulseaudio-slider trough {
|
#pulseaudio-slider trough {
|
||||||
@@ -151,119 +106,64 @@ window#waybar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#pulseaudio-slider highlight {
|
#pulseaudio-slider highlight {
|
||||||
|
|
||||||
min-width: 5px;
|
min-width: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background-color: #6c7086;
|
background-color: alpha(@theme_selected_bg_color, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom-updates {
|
|
||||||
padding-right: 5px;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MISC
|
|
||||||
**/
|
|
||||||
#mpris {
|
|
||||||
border-radius: 0;
|
|
||||||
margin: 8px 10px 8px 0px;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WORKSPACES
|
|
||||||
**/
|
|
||||||
/*#workspaces {
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button {
|
|
||||||
padding: 0px 10px 0px 8px;
|
|
||||||
margin: 8px 2px 8px 0px;
|
|
||||||
outline: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button.empty,
|
|
||||||
#workspaces button.active.empty {
|
|
||||||
color: inherit;
|
|
||||||
padding: 0px 0px 0px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button.active {
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 0px 10px 0px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button.visible {
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button.urgent {
|
|
||||||
color: #cc3436;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button:hover {
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.05);
|
|
||||||
box-shadow: inherit;
|
|
||||||
text-shadow: inherit;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
#workspaces {
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button {
|
|
||||||
margin: 8px 2px 8px 0px;
|
|
||||||
padding: 0;
|
|
||||||
outline: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button.empty,
|
|
||||||
#workspaces button.active.empty {
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button.active {}
|
|
||||||
|
|
||||||
#workspaces button.visible {
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button.urgent {
|
|
||||||
color: #cc3436;
|
|
||||||
}
|
|
||||||
|
|
||||||
#workspaces button:hover {
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.05);
|
|
||||||
box-shadow: inherit;
|
|
||||||
text-shadow: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
## INDICATORS
|
|
||||||
**/
|
|
||||||
#pulseaudio.muted {
|
#pulseaudio.muted {
|
||||||
color: #cc3436;
|
color: #cc3436;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- Brightness --- */
|
||||||
|
|
||||||
|
#backlight-slider {
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#backlight-slider slider {
|
||||||
|
min-height: 0px;
|
||||||
|
min-width: 0px;
|
||||||
|
opacity: 0;
|
||||||
|
background-image: none;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
background-color: @insensitive_bg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#backlight-slider trough {
|
||||||
|
min-height: 4px;
|
||||||
|
min-width: 80px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: alpha(@theme_selected_bg_color, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#backlight-slider highlight {
|
||||||
|
min-width: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: alpha(@theme_selected_bg_color, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Battery group (hidden when empty, requires Waybar PR #4941) --- */
|
||||||
|
|
||||||
|
#bat.empty,
|
||||||
|
#bat.empty * {
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: none;
|
||||||
|
font-size: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Battery --- */
|
||||||
|
|
||||||
|
#battery {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#battery.charging {
|
#battery.charging {
|
||||||
color: #2dcc36;
|
color: #2dcc36;
|
||||||
}
|
}
|
||||||
@@ -276,6 +176,79 @@ window#waybar {
|
|||||||
color: #cc3436;
|
color: #cc3436;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#custom-batsaver {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Workspaces --- */
|
||||||
|
|
||||||
|
#workspaces button {
|
||||||
|
margin: 8px 2px;
|
||||||
|
padding: 0 2px 0 0;
|
||||||
|
outline: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: alpha(@theme_selected_bg_color, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.empty,
|
||||||
|
#workspaces button.active.empty {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.visible {
|
||||||
|
background-color: alpha(@theme_selected_bg_color, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button.urgent {
|
||||||
|
color: #cc3436;
|
||||||
|
}
|
||||||
|
|
||||||
|
#workspaces button:hover {
|
||||||
|
background-color: alpha(@theme_selected_bg_color, 0.05);
|
||||||
|
box-shadow: inherit;
|
||||||
|
text-shadow: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Taskbar --- */
|
||||||
|
|
||||||
|
#taskbar {
|
||||||
|
font-size: 8px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taskbar.empty {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taskbar button {
|
||||||
|
padding: 3px 4px 0 10px;
|
||||||
|
border-bottom: 3px solid transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taskbar button.empty {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taskbar button:hover {
|
||||||
|
background-color: alpha(@theme_selected_bg_color, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#taskbar button.active {
|
||||||
|
background-color: alpha(@theme_selected_bg_color, 0.1);
|
||||||
|
border-bottom: 3px solid @theme_selected_bg_color;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- Misc --- */
|
||||||
|
|
||||||
|
#mpris {
|
||||||
|
border-radius: 0;
|
||||||
|
margin: 8px 10px 8px 0px;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#temperature.critical {
|
#temperature.critical {
|
||||||
color: #cc3436;
|
color: #cc3436;
|
||||||
}
|
}
|
||||||
@@ -284,65 +257,14 @@ window#waybar {
|
|||||||
color: alpha(@theme_selected_bg_color, 0.9);
|
color: alpha(@theme_selected_bg_color, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
#indicators {
|
#custom-nightlight.on {
|
||||||
padding-right: 5px;
|
color: #f9e2af;
|
||||||
padding-left: 5px;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TASKBAR
|
|
||||||
**/
|
|
||||||
#taskbar {
|
|
||||||
font-size: 8px;
|
|
||||||
margin: 0 0 0 5px;
|
|
||||||
opacity: 1;
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#taskbar.empty {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#taskbar button {
|
|
||||||
padding: 3px 10px 3px 10px;
|
|
||||||
transition: 100ms border ease-in-out;
|
|
||||||
border-radius: 0;
|
|
||||||
font-size: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#taskbar button:not(:first-child) {
|
|
||||||
border-radius: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#taskbar button:first-child {}
|
|
||||||
|
|
||||||
#taskbar button:last-child {}
|
|
||||||
|
|
||||||
#taskbar button:last-child:first-child {}
|
|
||||||
|
|
||||||
#taskbar button.empty {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#taskbar button:hover {
|
|
||||||
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#taskbar button.active {
|
|
||||||
background-color: alpha(@theme_selected_bg_color, 0.05);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
menu {
|
menu {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
menuitem {
|
menuitem {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
}
|
}
|
||||||
+8
-6
@@ -5,12 +5,13 @@
|
|||||||
# paru
|
# paru
|
||||||
|
|
||||||
# Theming
|
# Theming
|
||||||
colloid-catppuccin-gtk-theme-git
|
|
||||||
colloid-catppuccin-theme-git
|
colloid-catppuccin-theme-git
|
||||||
|
|
||||||
|
# Fonts
|
||||||
|
otf-openmoji
|
||||||
|
|
||||||
# Niri / Wayland Extras
|
# Niri / Wayland Extras
|
||||||
walker-bin
|
walker-bin
|
||||||
elephant-bin
|
|
||||||
elephant-desktopapplications-bin
|
elephant-desktopapplications-bin
|
||||||
elephant-clipboard-bin
|
elephant-clipboard-bin
|
||||||
elephant-bluetooth-bin
|
elephant-bluetooth-bin
|
||||||
@@ -22,17 +23,18 @@ elephant-niriactions-bin
|
|||||||
elephant-wireplumber-bin
|
elephant-wireplumber-bin
|
||||||
waybar-niri-windows-bin
|
waybar-niri-windows-bin
|
||||||
waybar-niri-workspaces-enhanced-git
|
waybar-niri-workspaces-enhanced-git
|
||||||
waypaper
|
|
||||||
wdisplays-persistent-gettext
|
wdisplays-persistent-gettext
|
||||||
wl-color-picker
|
wl-color-picker
|
||||||
wlogout
|
|
||||||
gtklock-dpms-module
|
|
||||||
|
|
||||||
# Applications
|
# Applications
|
||||||
blueberry
|
blueberry
|
||||||
waterfox-bin
|
waterfox-bin
|
||||||
|
|
||||||
|
# Media
|
||||||
|
mpv-modernz-git
|
||||||
|
mpv-thumbfast-git
|
||||||
|
|
||||||
# System & Tools
|
# System & Tools
|
||||||
auto-cpufreq
|
auto-cpufreq
|
||||||
stasis
|
stasis
|
||||||
timeshift-autosnap
|
wayland-pipewire-idle-inhibit
|
||||||
|
|||||||
+7
-12
@@ -14,6 +14,8 @@ zip
|
|||||||
|
|
||||||
# Shell & Terminal
|
# Shell & Terminal
|
||||||
zsh
|
zsh
|
||||||
|
zsh-autosuggestions
|
||||||
|
zsh-syntax-highlighting
|
||||||
foot
|
foot
|
||||||
foot-terminfo
|
foot-terminfo
|
||||||
bat
|
bat
|
||||||
@@ -58,17 +60,14 @@ xwayland-satellite
|
|||||||
|
|
||||||
# Desktop Utilities
|
# Desktop Utilities
|
||||||
waybar
|
waybar
|
||||||
dunst
|
swaync
|
||||||
cliphist
|
cliphist
|
||||||
wl-clipboard
|
wl-clipboard
|
||||||
|
wlsunset
|
||||||
libnotify
|
libnotify
|
||||||
upower
|
upower
|
||||||
awww
|
awww
|
||||||
brightnessctl
|
brightnessctl
|
||||||
gtklock
|
|
||||||
gtklock-playerctl-module
|
|
||||||
gtklock-powerbar-module
|
|
||||||
gtklock-userinfo-module
|
|
||||||
nwg-look
|
nwg-look
|
||||||
greetd
|
greetd
|
||||||
polkit-gnome
|
polkit-gnome
|
||||||
@@ -92,16 +91,12 @@ viewnior
|
|||||||
|
|
||||||
# Development
|
# Development
|
||||||
git
|
git
|
||||||
glab
|
|
||||||
go
|
|
||||||
neovim
|
neovim
|
||||||
npm
|
|
||||||
rustup
|
|
||||||
|
|
||||||
# System
|
# System
|
||||||
docker
|
|
||||||
docker-compose
|
|
||||||
fwupd
|
fwupd
|
||||||
plocate
|
plocate
|
||||||
timeshift
|
rebuild-detector
|
||||||
|
snapper
|
||||||
|
snap-pac
|
||||||
ufw
|
ufw
|
||||||
|
|||||||
+1
-7
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# ABOUTME: Shared helper functions and constants for Moonarch scripts.
|
# ABOUTME: Shared helper functions and constants for Moonarch scripts.
|
||||||
# ABOUTME: Sourced by post-install.sh, update.sh and transform.sh.
|
# ABOUTME: Sourced by post-install.sh.
|
||||||
|
|
||||||
# Path constants — BASH_SOURCE[1] resolves to the calling script, not lib.sh itself.
|
# Path constants — BASH_SOURCE[1] resolves to the calling script, not lib.sh itself.
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
|
||||||
@@ -8,7 +8,6 @@ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
|||||||
OFFICIAL_PACKAGES="$PROJECT_DIR/packages/official.txt"
|
OFFICIAL_PACKAGES="$PROJECT_DIR/packages/official.txt"
|
||||||
AUR_PACKAGES="$PROJECT_DIR/packages/aur.txt"
|
AUR_PACKAGES="$PROJECT_DIR/packages/aur.txt"
|
||||||
DEFAULTS_DIR="$PROJECT_DIR/defaults"
|
DEFAULTS_DIR="$PROJECT_DIR/defaults"
|
||||||
USER_DEFAULTS="/usr/share/moonarch/user-defaults"
|
|
||||||
|
|
||||||
# --- Helper functions ---
|
# --- Helper functions ---
|
||||||
|
|
||||||
@@ -24,11 +23,6 @@ read_packages() {
|
|||||||
grep -v '^\s*#' "$1" | grep -v '^\s*$'
|
grep -v '^\s*#' "$1" | grep -v '^\s*$'
|
||||||
}
|
}
|
||||||
|
|
||||||
confirm() {
|
|
||||||
read -r -p "$1 [y/N] " response
|
|
||||||
[[ "$response" =~ ^[yY]$ ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
# --- Prerequisite checks ---
|
# --- Prerequisite checks ---
|
||||||
|
|
||||||
check_not_root() {
|
check_not_root() {
|
||||||
|
|||||||
Executable
+301
@@ -0,0 +1,301 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ABOUTME: Moonarch system health checker — verifies services, configs, packages and paths.
|
||||||
|
# ABOUTME: Shipped as /usr/bin/moonarch-doctor (alias: moondoc) by the moonarch-git package.
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
# --- Output helpers ---
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
WARN=0
|
||||||
|
|
||||||
|
pass() {
|
||||||
|
echo -e " \e[1;32m✓\e[0m $*"
|
||||||
|
((PASS++))
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo -e " \e[1;31m✗\e[0m $*"
|
||||||
|
((FAIL++))
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
echo -e " \e[1;33m⚠\e[0m $*"
|
||||||
|
((WARN++))
|
||||||
|
}
|
||||||
|
|
||||||
|
section() {
|
||||||
|
echo
|
||||||
|
echo -e "\e[1;34m[$1]\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Check functions ---
|
||||||
|
|
||||||
|
check_system_service() {
|
||||||
|
local svc="$1"
|
||||||
|
local type
|
||||||
|
type=$(systemctl show "$svc" --property=Type 2>/dev/null | cut -d= -f2)
|
||||||
|
|
||||||
|
if systemctl is-enabled "$svc" &>/dev/null; then
|
||||||
|
if systemctl is-active "$svc" &>/dev/null; then
|
||||||
|
pass "$svc (enabled, active)"
|
||||||
|
elif [[ "$type" == "oneshot" ]]; then
|
||||||
|
# Oneshot services are inactive after completion — check if they succeeded
|
||||||
|
local result
|
||||||
|
result=$(systemctl show "$svc" --property=Result 2>/dev/null | cut -d= -f2)
|
||||||
|
if [[ "$result" == "success" ]]; then
|
||||||
|
pass "$svc (enabled, oneshot completed)"
|
||||||
|
else
|
||||||
|
fail "$svc (enabled, oneshot failed: $result)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "$svc (enabled, NOT active)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "$svc (NOT enabled)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_user_service() {
|
||||||
|
local svc="$1"
|
||||||
|
if systemctl --user is-enabled "$svc" &>/dev/null; then
|
||||||
|
if systemctl --user is-active "$svc" &>/dev/null; then
|
||||||
|
pass "$svc (enabled, active)"
|
||||||
|
else
|
||||||
|
# User services may be inactive if not in a graphical session
|
||||||
|
warn "$svc (enabled, not active — may need graphical session)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "$svc (NOT enabled)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_config_match() {
|
||||||
|
local deployed="$1"
|
||||||
|
local source="$2"
|
||||||
|
local label="${deployed}"
|
||||||
|
|
||||||
|
if [[ ! -f "$deployed" ]]; then
|
||||||
|
fail "$label (missing)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ ! -f "$source" ]]; then
|
||||||
|
warn "$label (exists, but no source to compare at $source)"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local hash_deployed hash_source
|
||||||
|
hash_deployed=$(sha256sum "$deployed" | cut -d' ' -f1)
|
||||||
|
hash_source=$(sha256sum "$source" | cut -d' ' -f1)
|
||||||
|
|
||||||
|
if [[ "$hash_deployed" == "$hash_source" ]]; then
|
||||||
|
pass "$label"
|
||||||
|
else
|
||||||
|
warn "$label (differs from moonarch default)"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Header ---
|
||||||
|
|
||||||
|
echo -e "\e[1;34m"
|
||||||
|
echo " Moonarch Doctor"
|
||||||
|
echo -e "\e[0m"
|
||||||
|
|
||||||
|
# --- 1. Packages ---
|
||||||
|
|
||||||
|
section "Packages"
|
||||||
|
|
||||||
|
OFFICIAL="/usr/share/moonarch/official.txt"
|
||||||
|
AUR="/usr/share/moonarch/aur.txt"
|
||||||
|
|
||||||
|
# Hoist INSTALLED so the AUR block below can use it even if OFFICIAL is absent —
|
||||||
|
# otherwise `set -u` aborts the script when $INSTALLED is referenced unset.
|
||||||
|
INSTALLED=$(pacman -Qq 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ -f "$OFFICIAL" ]]; then
|
||||||
|
MISSING_OFFICIAL=()
|
||||||
|
while IFS= read -r pkg; do
|
||||||
|
[[ "$pkg" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
[[ -z "${pkg// }" ]] && continue
|
||||||
|
if ! echo "$INSTALLED" | grep -qx "$pkg"; then
|
||||||
|
MISSING_OFFICIAL+=("$pkg")
|
||||||
|
fi
|
||||||
|
done < "$OFFICIAL"
|
||||||
|
|
||||||
|
if [[ ${#MISSING_OFFICIAL[@]} -eq 0 ]]; then
|
||||||
|
pass "All official packages installed"
|
||||||
|
else
|
||||||
|
fail "Missing official packages: ${MISSING_OFFICIAL[*]}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "$OFFICIAL not found (moonarch-git not installed?)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f "$AUR" ]]; then
|
||||||
|
MISSING_AUR=()
|
||||||
|
while IFS= read -r pkg; do
|
||||||
|
[[ "$pkg" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
[[ -z "${pkg// }" ]] && continue
|
||||||
|
if ! echo "$INSTALLED" | grep -qx "$pkg"; then
|
||||||
|
MISSING_AUR+=("$pkg")
|
||||||
|
fi
|
||||||
|
done < "$AUR"
|
||||||
|
|
||||||
|
if [[ ${#MISSING_AUR[@]} -eq 0 ]]; then
|
||||||
|
pass "All AUR packages installed"
|
||||||
|
else
|
||||||
|
fail "Missing AUR packages: ${MISSING_AUR[*]}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "$AUR not found (moonarch-git not installed?)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ORPHANS=$(pacman -Qdtq 2>/dev/null || true)
|
||||||
|
if [[ -z "$ORPHANS" ]]; then
|
||||||
|
pass "No orphaned packages"
|
||||||
|
else
|
||||||
|
ORPHAN_COUNT=$(echo "$ORPHANS" | wc -l)
|
||||||
|
warn "$ORPHAN_COUNT orphaned package(s) (run moonup to clean)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 2. System Services ---
|
||||||
|
|
||||||
|
section "System Services"
|
||||||
|
|
||||||
|
for svc in NetworkManager bluetooth greetd systemd-timesyncd ufw auto-cpufreq; do
|
||||||
|
check_system_service "$svc"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Battery conservation service (laptop only)
|
||||||
|
if [[ -f /sys/class/power_supply/BAT0/charge_control_end_threshold ]]; then
|
||||||
|
check_system_service moonarch-batsaver
|
||||||
|
else
|
||||||
|
pass "moonarch-batsaver (skipped — no battery threshold support)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 3. User Services ---
|
||||||
|
|
||||||
|
section "User Services"
|
||||||
|
|
||||||
|
if [[ $EUID -eq 0 ]]; then
|
||||||
|
warn "Running as root — skipping user service checks"
|
||||||
|
elif pacman -Qq moonarch-git &>/dev/null; then
|
||||||
|
EXPECTED_SVCS=()
|
||||||
|
while IFS= read -r svc_file; do
|
||||||
|
EXPECTED_SVCS+=("$(basename "$svc_file" .service)")
|
||||||
|
done < <(pacman -Qql moonarch-git | grep -E '^/etc/systemd/user/[^/]+\.service$')
|
||||||
|
# Services enabled by post-install.sh from other packages
|
||||||
|
EXPECTED_SVCS+=(stasis wayland-pipewire-idle-inhibit)
|
||||||
|
|
||||||
|
for svc in "${EXPECTED_SVCS[@]}"; do
|
||||||
|
check_user_service "$svc"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
warn "moonarch-git not installed — skipping user service checks"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 4. Config Files ---
|
||||||
|
|
||||||
|
section "Config Files"
|
||||||
|
|
||||||
|
SRC="/usr/share/moonarch"
|
||||||
|
|
||||||
|
check_config_match "/etc/xdg/foot/foot.ini" "$SRC/foot/foot.ini"
|
||||||
|
check_config_match "/etc/xdg/waybar/style.css" "$SRC/waybar/style.css"
|
||||||
|
check_config_match "/etc/xdg/swaync/config.json" "$SRC/swaync/config.json"
|
||||||
|
check_config_match "/etc/xdg/swaync/style.css" "$SRC/swaync/style.css"
|
||||||
|
check_config_match "/etc/greetd/config.toml" "$SRC/greetd/config.toml"
|
||||||
|
check_config_match "/etc/greetd/niri-greeter.kdl" "$SRC/greetd/niri-greeter.kdl"
|
||||||
|
check_config_match "/etc/moongreet/moongreet.toml" "$SRC/moongreet/moongreet.toml"
|
||||||
|
|
||||||
|
# --- 5. Helper Scripts ---
|
||||||
|
|
||||||
|
section "Helper Scripts"
|
||||||
|
|
||||||
|
if pacman -Qq moonarch-git &>/dev/null; then
|
||||||
|
EXPECTED_SCRIPTS=()
|
||||||
|
while IFS= read -r script; do
|
||||||
|
EXPECTED_SCRIPTS+=("$(basename "$script")")
|
||||||
|
done < <(pacman -Qql moonarch-git | grep -E '^/usr/bin/moonarch-[^/]+$')
|
||||||
|
|
||||||
|
MISSING_SCRIPTS=()
|
||||||
|
for script in "${EXPECTED_SCRIPTS[@]}"; do
|
||||||
|
if [[ ! -x "/usr/bin/$script" ]]; then
|
||||||
|
MISSING_SCRIPTS+=("$script")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#MISSING_SCRIPTS[@]} -eq 0 ]]; then
|
||||||
|
pass "All ${#EXPECTED_SCRIPTS[@]} helper scripts present"
|
||||||
|
else
|
||||||
|
fail "Missing scripts: ${MISSING_SCRIPTS[*]}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "moonarch-git not installed — skipping helper script checks"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Symlinks
|
||||||
|
for link in moonup moondoc; do
|
||||||
|
if [[ -L "/usr/bin/$link" ]]; then
|
||||||
|
pass "$link symlink"
|
||||||
|
else
|
||||||
|
fail "$link symlink (missing)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- 6. System Config ---
|
||||||
|
|
||||||
|
section "System Config"
|
||||||
|
|
||||||
|
# UFW (check via systemd, no sudo needed)
|
||||||
|
if command -v ufw &>/dev/null; then
|
||||||
|
if systemctl is-active ufw &>/dev/null; then
|
||||||
|
pass "UFW active"
|
||||||
|
else
|
||||||
|
fail "UFW not active"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "UFW not installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pacman moonarch repo
|
||||||
|
if grep -q '^\[moonarch\]' /etc/pacman.conf 2>/dev/null; then
|
||||||
|
pass "Pacman [moonarch] repo configured"
|
||||||
|
else
|
||||||
|
fail "Pacman [moonarch] repo missing from /etc/pacman.conf"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default shell
|
||||||
|
USER_SHELL=$(getent passwd "$USER" | cut -d: -f7)
|
||||||
|
if [[ "$USER_SHELL" == */zsh ]]; then
|
||||||
|
pass "Default shell: zsh"
|
||||||
|
else
|
||||||
|
warn "Default shell: $USER_SHELL (expected zsh)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- 7. Directories ---
|
||||||
|
|
||||||
|
section "Directories"
|
||||||
|
|
||||||
|
if [[ -d /var/lib/moonarch ]]; then
|
||||||
|
DIR_PERMS=$(stat -c '%a' /var/lib/moonarch)
|
||||||
|
DIR_GROUP=$(stat -c '%G' /var/lib/moonarch)
|
||||||
|
if [[ "$DIR_GROUP" == "wheel" ]]; then
|
||||||
|
pass "/var/lib/moonarch/ (group: wheel, mode: $DIR_PERMS)"
|
||||||
|
else
|
||||||
|
warn "/var/lib/moonarch/ (group: $DIR_GROUP, expected wheel)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "/var/lib/moonarch/ missing (created on first battery toggle)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Summary ---
|
||||||
|
|
||||||
|
echo
|
||||||
|
TOTAL=$((PASS + FAIL + WARN))
|
||||||
|
echo -e "\e[1;34m[Summary]\e[0m $TOTAL checks: \e[1;32m$PASS passed\e[0m, \e[1;31m$FAIL failed\e[0m, \e[1;33m$WARN warnings\e[0m"
|
||||||
|
|
||||||
|
if [[ $FAIL -gt 0 ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
+55
-22
@@ -4,6 +4,37 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
_t() {
|
||||||
|
# _t "english" "deutsch" — picks by $LANG
|
||||||
|
case "${LANG%%.*}" in
|
||||||
|
de_*) printf '%s' "$2" ;;
|
||||||
|
*) printf '%s' "$1" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pause on exit when launched from a GUI (Waybar sets MOONUP_WAIT=1).
|
||||||
|
# Runs via trap so it fires even when `set -e` aborts the script mid-way.
|
||||||
|
# Reads from /dev/tty because stdin may have been drained/closed by pacman/paru.
|
||||||
|
_pause_on_exit() {
|
||||||
|
local rc=$?
|
||||||
|
if [[ -n "${MOONUP_WAIT:-}" ]]; then
|
||||||
|
echo
|
||||||
|
if (( rc != 0 )); then
|
||||||
|
echo -e "\e[1;31m[Moonarch ERROR]\e[0m $(_t "Exited with error (code $rc)" "Mit Fehler beendet (Code $rc)")" >&2
|
||||||
|
fi
|
||||||
|
read -n 1 -s -r -p "$(_t "Press any key to close..." "Beliebige Taste drücken zum Schließen …")" < /dev/tty || true
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap _pause_on_exit EXIT
|
||||||
|
|
||||||
|
# --- i18n ---
|
||||||
|
# Reuse pacman's gettext catalog for prompts that match upstream msgids.
|
||||||
|
# For moonarch-specific strings fall back to _t() inline translation.
|
||||||
|
export TEXTDOMAIN=pacman
|
||||||
|
export TEXTDOMAINDIR=/usr/share/locale
|
||||||
|
YN=$(gettext "[Y/n]")
|
||||||
|
|
||||||
# --- Helper functions ---
|
# --- Helper functions ---
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
@@ -19,8 +50,10 @@ read_packages() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
confirm() {
|
confirm() {
|
||||||
read -r -p "$1 [y/N] " response
|
# Read from /dev/tty so stdin state (drained by pacman/paru, closed by
|
||||||
[[ "$response" =~ ^[yY]$ ]]
|
# a Waybar launch) doesn't auto-confirm prompts by returning empty input.
|
||||||
|
read -r -p ":: $1 $YN " response < /dev/tty
|
||||||
|
[[ -z "$response" || "$response" =~ ^[yYjJ]$ ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
OFFICIAL_PACKAGES="/usr/share/moonarch/official.txt"
|
OFFICIAL_PACKAGES="/usr/share/moonarch/official.txt"
|
||||||
@@ -29,79 +62,79 @@ AUR_PACKAGES="/usr/share/moonarch/aur.txt"
|
|||||||
# --- Prerequisites ---
|
# --- Prerequisites ---
|
||||||
|
|
||||||
if [[ $EUID -eq 0 ]]; then
|
if [[ $EUID -eq 0 ]]; then
|
||||||
err "Do NOT run as root. The script uses sudo where needed."
|
err "$(_t "Do NOT run as root. The script uses sudo where needed." "Nicht als root ausführen. Das Script verwendet sudo wo nötig.")"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 1. Update system packages ---
|
# --- 1. Update system packages ---
|
||||||
|
|
||||||
log "=== Update system packages ==="
|
log "=== $(gettext $'Starting full system upgrade...\n' | tr -d '\n.') ==="
|
||||||
|
|
||||||
if confirm "Run pacman -Syu?"; then
|
if confirm "$(_t "Run pacman -Syu?" "pacman -Syu ausführen?")"; then
|
||||||
sudo pacman -Syu
|
sudo pacman -Syu
|
||||||
else
|
else
|
||||||
log "System update skipped."
|
log "$(_t "System update skipped." "Systemaktualisierung übersprungen.")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if command -v paru &>/dev/null; then
|
if command -v paru &>/dev/null; then
|
||||||
if confirm "Update AUR packages (paru -Sua)?"; then
|
if confirm "$(_t "Update AUR packages (paru -Sua)?" "AUR-Pakete aktualisieren (paru -Sua)?")"; then
|
||||||
paru -Sua
|
paru -Sua
|
||||||
else
|
else
|
||||||
log "AUR update skipped."
|
log "$(_t "AUR update skipped." "AUR-Aktualisierung übersprungen.")"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 2. Reconcile package lists ---
|
# --- 2. Reconcile package lists ---
|
||||||
|
|
||||||
log "=== Reconcile package lists ==="
|
log "=== $(_t "Reconcile package lists" "Paketlisten abgleichen") ==="
|
||||||
|
|
||||||
if [[ -f "$OFFICIAL_PACKAGES" ]]; then
|
if [[ -f "$OFFICIAL_PACKAGES" ]]; then
|
||||||
MISSING_OFFICIAL=$(comm -23 <(read_packages "$OFFICIAL_PACKAGES" | sort) <(pacman -Qqe | sort) || true)
|
MISSING_OFFICIAL=$(comm -23 <(read_packages "$OFFICIAL_PACKAGES" | sort) <(pacman -Qq | sort) || true)
|
||||||
if [[ -n "$MISSING_OFFICIAL" ]]; then
|
if [[ -n "$MISSING_OFFICIAL" ]]; then
|
||||||
log "Missing official packages:"
|
log "$(_t "Missing official packages:" "Fehlende offizielle Pakete:")"
|
||||||
echo "$MISSING_OFFICIAL"
|
echo "$MISSING_OFFICIAL"
|
||||||
if confirm "Install?"; then
|
if confirm "$(gettext 'Proceed with installation?')"; then
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
sudo pacman -S --needed --noconfirm $MISSING_OFFICIAL
|
sudo pacman -S --needed --noconfirm $MISSING_OFFICIAL
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log "All official packages installed."
|
log "$(_t "All official packages installed." "Alle offiziellen Pakete installiert.")"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f "$AUR_PACKAGES" ]] && command -v paru &>/dev/null; then
|
if [[ -f "$AUR_PACKAGES" ]] && command -v paru &>/dev/null; then
|
||||||
MISSING_AUR=$(comm -23 <(read_packages "$AUR_PACKAGES" | sort) <(pacman -Qqe | sort) || true)
|
MISSING_AUR=$(comm -23 <(read_packages "$AUR_PACKAGES" | sort) <(pacman -Qq | sort) || true)
|
||||||
if [[ -n "$MISSING_AUR" ]]; then
|
if [[ -n "$MISSING_AUR" ]]; then
|
||||||
log "Missing AUR packages:"
|
log "$(_t "Missing AUR packages:" "Fehlende AUR-Pakete:")"
|
||||||
echo "$MISSING_AUR"
|
echo "$MISSING_AUR"
|
||||||
if confirm "Install?"; then
|
if confirm "$(gettext 'Proceed with installation?')"; then
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
paru -S --needed --noconfirm $MISSING_AUR
|
paru -S --needed --noconfirm $MISSING_AUR
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log "All AUR packages installed."
|
log "$(_t "All AUR packages installed." "Alle AUR-Pakete installiert.")"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- 3. Orphaned packages ---
|
# --- 3. Orphaned packages ---
|
||||||
|
|
||||||
log "=== Orphaned packages ==="
|
log "=== $(_t "Orphaned packages" "Verwaiste Pakete") ==="
|
||||||
|
|
||||||
ORPHANS=$(pacman -Qdtq 2>/dev/null || true)
|
ORPHANS=$(pacman -Qdtq 2>/dev/null || true)
|
||||||
if [[ -n "$ORPHANS" ]]; then
|
if [[ -n "$ORPHANS" ]]; then
|
||||||
log "Orphaned packages found:"
|
log "$(_t "Orphaned packages found:" "Verwaiste Pakete gefunden:")"
|
||||||
echo "$ORPHANS"
|
echo "$ORPHANS"
|
||||||
if confirm "Remove?"; then
|
if confirm "$(gettext 'Do you want to remove these packages?')"; then
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
sudo pacman -Rsn --noconfirm $ORPHANS
|
sudo pacman -Rsn --noconfirm $ORPHANS
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log "No orphaned packages."
|
log "$(_t "No orphaned packages." "Keine verwaisten Pakete.")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Done ---
|
# --- Done ---
|
||||||
|
|
||||||
log ""
|
log ""
|
||||||
log "============================================"
|
log "============================================"
|
||||||
log " Moonarch update complete!"
|
log " $(_t "Moonarch update complete!" "Moonarch-Aktualisierung abgeschlossen!")"
|
||||||
log "============================================"
|
log "============================================"
|
||||||
|
|||||||
+83
-47
@@ -14,34 +14,77 @@ check_pacman
|
|||||||
# --- Install paru (AUR Helper) ---
|
# --- Install paru (AUR Helper) ---
|
||||||
|
|
||||||
if ! command -v paru &>/dev/null; then
|
if ! command -v paru &>/dev/null; then
|
||||||
|
log "Installing paru build dependencies..."
|
||||||
|
sudo pacman -S --needed --noconfirm base-devel rust
|
||||||
|
|
||||||
log "Installing paru..."
|
log "Installing paru..."
|
||||||
sudo pacman -S --needed --noconfirm paru
|
PARU_TMPDIR=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$PARU_TMPDIR"' EXIT
|
||||||
|
git clone https://aur.archlinux.org/paru.git "$PARU_TMPDIR/paru"
|
||||||
|
(cd "$PARU_TMPDIR/paru" && makepkg -si --noconfirm)
|
||||||
|
rm -rf "$PARU_TMPDIR"
|
||||||
|
trap - EXIT
|
||||||
else
|
else
|
||||||
log "paru already installed."
|
log "paru already installed."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Set up Moonarch custom paru repo ---
|
# --- Set up Moonarch package registry ---
|
||||||
|
|
||||||
|
log "Setting up Moonarch package registry..."
|
||||||
|
if ! grep -q '\[moonarch\]' /etc/pacman.conf 2>/dev/null; then
|
||||||
|
sudo tee -a /etc/pacman.conf > /dev/null <<'EOCONF'
|
||||||
|
|
||||||
log "Setting up Moonarch paru repo..."
|
|
||||||
PARU_CONF="$HOME/.config/paru/paru.conf"
|
|
||||||
mkdir -p "$(dirname "$PARU_CONF")"
|
|
||||||
if ! grep -q '\[moonarch\]' "$PARU_CONF" 2>/dev/null; then
|
|
||||||
cat >> "$PARU_CONF" <<'EOCONF'
|
|
||||||
[moonarch]
|
[moonarch]
|
||||||
Url = https://gitea.moonarch.de/nevaforget/moonarch-pkgbuilds.git
|
SigLevel = Required DatabaseOptional
|
||||||
|
Server = https://gitea.moonarch.de/api/packages/nevaforget/arch/$repo/$arch
|
||||||
EOCONF
|
EOCONF
|
||||||
log " + Moonarch repo added to paru.conf."
|
log " + Moonarch repo added to pacman.conf."
|
||||||
else
|
else
|
||||||
log " ~ Moonarch repo already in paru.conf."
|
log " ~ Moonarch repo already in pacman.conf."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
paru -Syu --pkgbuilds --noconfirm
|
log "Importing Moonarch registry signing key..."
|
||||||
|
EXPECTED_FINGERPRINT="9B02C596A4652C40CA768E75B90C8B82EA30A131"
|
||||||
|
KEY_FILE=$(mktemp)
|
||||||
|
trap 'rm -f "$KEY_FILE"' EXIT
|
||||||
|
curl -sf https://gitea.moonarch.de/api/packages/nevaforget/arch/repository.key -o "$KEY_FILE"
|
||||||
|
if [[ ! -s "$KEY_FILE" ]]; then
|
||||||
|
err "Failed to download registry key (empty response)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
KEY_FPR=$(gpg --show-keys --with-colons "$KEY_FILE" 2>/dev/null | awk -F: '/^fpr/{print $10; exit}')
|
||||||
|
if [[ "$KEY_FPR" != "$EXPECTED_FINGERPRINT" ]]; then
|
||||||
|
err "Registry key fingerprint mismatch! Expected $EXPECTED_FINGERPRINT, got ${KEY_FPR:-<empty>}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
KEY_ID=$(gpg --show-keys --with-colons "$KEY_FILE" 2>/dev/null | awk -F: '/^pub/{print $5}')
|
||||||
|
if [[ -n "$KEY_ID" ]] && ! sudo pacman-key --list-keys "$KEY_ID" &>/dev/null; then
|
||||||
|
sudo pacman-key --add "$KEY_FILE"
|
||||||
|
sudo pacman-key --lsign-key "$KEY_ID"
|
||||||
|
log " + Registry key $KEY_ID imported and locally signed."
|
||||||
|
else
|
||||||
|
log " ~ Registry key already imported."
|
||||||
|
fi
|
||||||
|
rm -f "$KEY_FILE"
|
||||||
|
trap - EXIT
|
||||||
|
|
||||||
# --- Install moonarch-git (pulls in all configs, scripts, themes as dependencies) ---
|
# --- Install moonarch-git from the Arch registry ---
|
||||||
|
|
||||||
log "Installing moonarch-git package..."
|
log "Installing moonarch-git package..."
|
||||||
|
sudo pacman -Sy --noconfirm
|
||||||
paru -S --needed --noconfirm moonarch-git
|
paru -S --needed --noconfirm moonarch-git
|
||||||
|
|
||||||
|
# --- Install AUR extras (cannot be hard depends of moonarch-git) ---
|
||||||
|
|
||||||
|
if [[ -f "$AUR_PACKAGES" ]]; then
|
||||||
|
log "Installing AUR packages from $AUR_PACKAGES..."
|
||||||
|
# shellcheck disable=SC2046
|
||||||
|
paru -S --needed --noconfirm $(read_packages "$AUR_PACKAGES")
|
||||||
|
else
|
||||||
|
err "AUR package list not found: $AUR_PACKAGES"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# --- User-level GTK4 symlinks for libadwaita apps ---
|
# --- User-level GTK4 symlinks for libadwaita apps ---
|
||||||
|
|
||||||
THEME_NAME="Colloid-Grey-Dark-Catppuccin"
|
THEME_NAME="Colloid-Grey-Dark-Catppuccin"
|
||||||
@@ -67,37 +110,22 @@ gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
|
|||||||
gsettings set org.gnome.desktop.interface icon-theme 'Colloid-Grey-Catppuccin-Dark'
|
gsettings set org.gnome.desktop.interface icon-theme 'Colloid-Grey-Catppuccin-Dark'
|
||||||
gsettings set org.gnome.desktop.interface font-name 'UbuntuSans Nerd Font 11'
|
gsettings set org.gnome.desktop.interface font-name 'UbuntuSans Nerd Font 11'
|
||||||
|
|
||||||
# --- Install user config defaults ---
|
|
||||||
|
|
||||||
log "Installing user config defaults to ~/.config/..."
|
|
||||||
if [[ -d "$USER_DEFAULTS" ]]; then
|
|
||||||
# Each subdirectory in user-defaults/ corresponds to a ~/.config/ directory.
|
|
||||||
# Files are only copied if they don't exist yet (no overwriting).
|
|
||||||
for src_dir in "$USER_DEFAULTS"/*/; do
|
|
||||||
app_name="$(basename "$src_dir")"
|
|
||||||
dest_dir="$HOME/.config/$app_name"
|
|
||||||
mkdir -p "$dest_dir"
|
|
||||||
find "$src_dir" -type f -print0 | while IFS= read -r -d '' src_file; do
|
|
||||||
rel_path="${src_file#"$src_dir"}"
|
|
||||||
dest_file="$dest_dir/$rel_path"
|
|
||||||
if [[ ! -f "$dest_file" ]]; then
|
|
||||||
mkdir -p "$(dirname "$dest_file")"
|
|
||||||
cp "$src_file" "$dest_file"
|
|
||||||
log " + $app_name/$rel_path"
|
|
||||||
else
|
|
||||||
log " ~ $app_name/$rel_path already exists, skipped."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- Zsh user config ---
|
# --- Zsh user config ---
|
||||||
|
|
||||||
if [[ ! -f "$HOME/.zshrc" ]]; then
|
if [[ ! -f "$HOME/.zshrc" ]]; then
|
||||||
log "No ~/.zshrc found — sourcing Moonarch defaults."
|
log "No ~/.zshrc found — sourcing Moonarch defaults."
|
||||||
mkdir -p "$HOME/.zshrc.d"
|
echo "source /etc/zsh/zshrc.moonarch" > "$HOME/.zshrc"
|
||||||
echo "# Load Moonarch defaults, add custom overrides in ~/.zshrc.d/ or below" > "$HOME/.zshrc"
|
fi
|
||||||
echo "source /etc/zsh/zshrc.moonarch" >> "$HOME/.zshrc"
|
|
||||||
|
# --- Seed Stasis user config ---
|
||||||
|
#
|
||||||
|
# Stasis reads ~/.config/stasis/stasis.rune (or /etc/stasis/stasis.rune as
|
||||||
|
# fallback) but never /etc/xdg/. Without a user config it writes its own
|
||||||
|
# upstream default on first start. Seed Moonarch's template so the bootstrap
|
||||||
|
# sees an existing file and skips. Never overwrite an existing user config.
|
||||||
|
if [[ ! -f "$HOME/.config/stasis/stasis.rune" && -f /etc/xdg/stasis/stasis.rune ]]; then
|
||||||
|
log "Seeding Moonarch stasis config to user home."
|
||||||
|
install -Dm644 /etc/xdg/stasis/stasis.rune "$HOME/.config/stasis/stasis.rune"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Enable systemd user services ---
|
# --- Enable systemd user services ---
|
||||||
@@ -105,7 +133,14 @@ fi
|
|||||||
log "Enabling systemd user services..."
|
log "Enabling systemd user services..."
|
||||||
USER_SERVICES=(
|
USER_SERVICES=(
|
||||||
"kanshi"
|
"kanshi"
|
||||||
|
"stasis"
|
||||||
|
"wayland-pipewire-idle-inhibit"
|
||||||
|
"cliphist-text"
|
||||||
|
"cliphist-image"
|
||||||
)
|
)
|
||||||
|
# wlsunset deliberately excluded: nightlight is a user-toggle (off by default).
|
||||||
|
# Enabling it system-wide would create a global-scope WantedBy symlink that
|
||||||
|
# overrides any user-scope `systemctl --user disable`.
|
||||||
|
|
||||||
for service in "${USER_SERVICES[@]}"; do
|
for service in "${USER_SERVICES[@]}"; do
|
||||||
if systemctl --user cat "${service}.service" &>/dev/null; then
|
if systemctl --user cat "${service}.service" &>/dev/null; then
|
||||||
@@ -122,7 +157,6 @@ log "Enabling services..."
|
|||||||
SERVICES=(
|
SERVICES=(
|
||||||
"NetworkManager"
|
"NetworkManager"
|
||||||
"bluetooth"
|
"bluetooth"
|
||||||
"docker"
|
|
||||||
"greetd"
|
"greetd"
|
||||||
"systemd-timesyncd"
|
"systemd-timesyncd"
|
||||||
"ufw"
|
"ufw"
|
||||||
@@ -152,12 +186,15 @@ sudo ufw default deny incoming
|
|||||||
sudo ufw default allow outgoing
|
sudo ufw default allow outgoing
|
||||||
sudo ufw --force enable
|
sudo ufw --force enable
|
||||||
|
|
||||||
# --- Docker-Gruppe ---
|
# --- Boot parameters: add quiet to systemd-boot entries ---
|
||||||
|
|
||||||
if ! groups | grep -q docker; then
|
log "Configuring boot parameters..."
|
||||||
log "Adding user to docker group..."
|
for entry in /boot/loader/entries/*.conf; do
|
||||||
sudo usermod -aG docker "$USER"
|
if [[ -f "$entry" ]] && [[ "$(basename "$entry")" != *fallback* ]] && ! grep -q 'quiet' "$entry"; then
|
||||||
fi
|
sudo sed -i '/^options/ s/$/ quiet/' "$entry"
|
||||||
|
log " + $(basename "$entry") — quiet added"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
# --- Screenshots directory ---
|
# --- Screenshots directory ---
|
||||||
|
|
||||||
@@ -174,6 +211,5 @@ log ""
|
|||||||
log "Next steps:"
|
log "Next steps:"
|
||||||
log " 1. Reboot"
|
log " 1. Reboot"
|
||||||
log " 2. Place wallpapers in ~/Pictures/Wallpaper/"
|
log " 2. Place wallpapers in ~/Pictures/Wallpaper/"
|
||||||
log " 3. rustup default stable"
|
log " 3. User overrides in ~/.config/"
|
||||||
log " 4. User overrides in ~/.config/ or ~/.zshrc.d/"
|
|
||||||
log ""
|
log ""
|
||||||
|
|||||||
@@ -1,381 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ABOUTME: Transforms an existing Arch+Wayland system into a Moonarch system.
|
|
||||||
# ABOUTME: Backs up configs, installs moonarch-git package, deploys user configs with hard overwrite.
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib.sh"
|
|
||||||
|
|
||||||
# --- Parse arguments ---
|
|
||||||
|
|
||||||
DRY_RUN=false
|
|
||||||
if [[ "${1:-}" == "--dry-run" ]]; then
|
|
||||||
DRY_RUN=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 1: Prerequisites & Detection
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
check_not_root
|
|
||||||
check_pacman
|
|
||||||
|
|
||||||
# Require active Wayland session
|
|
||||||
if [[ "${XDG_SESSION_TYPE:-}" != "wayland" ]] && [[ -z "${WAYLAND_DISPLAY:-}" ]]; then
|
|
||||||
err "No active Wayland session detected. Transform requires Wayland."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Detect conflicting display managers
|
|
||||||
CONFLICTING_DMS=()
|
|
||||||
for dm in sddm gdm lightdm ly lemurs; do
|
|
||||||
if systemctl is-enabled "${dm}.service" &>/dev/null; then
|
|
||||||
CONFLICTING_DMS+=("$dm")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Detect conflicting packages
|
|
||||||
CONFLICTING_PKGS=()
|
|
||||||
if pacman -Qq pulseaudio &>/dev/null && ! pacman -Qq pipewire-pulse &>/dev/null; then
|
|
||||||
CONFLICTING_PKGS+=("pulseaudio")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 2: Pre-flight Summary
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
if $DRY_RUN; then
|
|
||||||
log "============================================"
|
|
||||||
log " Moonarch Transform — Dry Run"
|
|
||||||
log "============================================"
|
|
||||||
else
|
|
||||||
log "============================================"
|
|
||||||
log " Moonarch Transform — Pre-flight Summary"
|
|
||||||
log "============================================"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
log "Wayland session: detected"
|
|
||||||
|
|
||||||
if [[ ${#CONFLICTING_DMS[@]} -gt 0 ]]; then
|
|
||||||
log "Display managers: ${CONFLICTING_DMS[*]} (will be disabled)"
|
|
||||||
else
|
|
||||||
log "Display managers: none conflicting"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#CONFLICTING_PKGS[@]} -gt 0 ]]; then
|
|
||||||
log "Package conflicts: ${CONFLICTING_PKGS[*]} (will be removed)"
|
|
||||||
else
|
|
||||||
log "Package conflicts: none"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
log "Actions:"
|
|
||||||
log " 1. (Optional) Backup ~/.config/, ~/.zshrc, /etc/xdg/"
|
|
||||||
log " 2. Install moonarch-git package (pulls in all dependencies)"
|
|
||||||
log " 3. Disable conflicting DMs, enable greetd"
|
|
||||||
log " 4. Overwrite ALL user configs (~/.config/)"
|
|
||||||
log " 5. Configure GTK themes, firewall, services"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Show package diff
|
|
||||||
MISSING_OFFICIAL=$(comm -23 <(read_packages "$OFFICIAL_PACKAGES" | sort) <(pacman -Qqe | sort) 2>/dev/null || true)
|
|
||||||
MISSING_AUR=""
|
|
||||||
if [[ -f "$AUR_PACKAGES" ]]; then
|
|
||||||
MISSING_AUR=$(comm -23 <(read_packages "$AUR_PACKAGES" | sort) <(pacman -Qqe | sort) 2>/dev/null || true)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$MISSING_OFFICIAL" ]] || [[ -n "$MISSING_AUR" ]]; then
|
|
||||||
log "Packages to install:"
|
|
||||||
if [[ -n "$MISSING_OFFICIAL" ]]; then
|
|
||||||
OFFICIAL_COUNT=$(echo "$MISSING_OFFICIAL" | wc -l)
|
|
||||||
log " Official ($OFFICIAL_COUNT):"
|
|
||||||
echo "$MISSING_OFFICIAL" | sed 's/^/ /'
|
|
||||||
fi
|
|
||||||
if [[ -n "$MISSING_AUR" ]]; then
|
|
||||||
AUR_COUNT=$(echo "$MISSING_AUR" | wc -l)
|
|
||||||
log " AUR ($AUR_COUNT):"
|
|
||||||
echo "$MISSING_AUR" | sed 's/^/ /'
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log "Packages: all already installed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Show config diff summary
|
|
||||||
CHANGED_XDG=0
|
|
||||||
CHANGED_BIN=0
|
|
||||||
for src_dir in "$DEFAULTS_DIR/xdg/"*/; do
|
|
||||||
app_name="$(basename "$src_dir")"
|
|
||||||
dest_dir="$HOME/.config/$app_name"
|
|
||||||
if [[ -d "$dest_dir" ]]; then
|
|
||||||
if ! diff -rq "$src_dir" "$dest_dir" &>/dev/null 2>&1; then
|
|
||||||
((CHANGED_XDG++)) || true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
((CHANGED_XDG++)) || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
for bin in "$DEFAULTS_DIR/bin/moonarch-"*; do
|
|
||||||
name=$(basename "$bin")
|
|
||||||
if ! cmp -s "$bin" "/usr/bin/$name" 2>/dev/null; then
|
|
||||||
((CHANGED_BIN++)) || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
log "Config changes: $CHANGED_XDG XDG app(s), $CHANGED_BIN helper script(s)"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
err "This will REPLACE your current desktop configuration."
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if $DRY_RUN; then
|
|
||||||
log "Dry run complete — no changes were made."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! confirm "Proceed?"; then
|
|
||||||
log "Transform cancelled."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 3: Backup (optional)
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
BACKUP_FILE=""
|
|
||||||
SYSTEM_BACKUP=""
|
|
||||||
|
|
||||||
if confirm "Create backup of current configs before overwriting?"; then
|
|
||||||
BACKUP_FILE="$HOME/moonarch-backup-$(date +%Y%m%d-%H%M%S).tar.gz"
|
|
||||||
log "Creating backup: $BACKUP_FILE"
|
|
||||||
|
|
||||||
# Build list of paths that actually exist
|
|
||||||
BACKUP_PATHS=()
|
|
||||||
[[ -d "$HOME/.config" ]] && BACKUP_PATHS+=(".config")
|
|
||||||
[[ -f "$HOME/.zshrc" ]] && BACKUP_PATHS+=(".zshrc")
|
|
||||||
[[ -d "$HOME/.zshrc.d" ]] && BACKUP_PATHS+=(".zshrc.d")
|
|
||||||
|
|
||||||
if [[ ${#BACKUP_PATHS[@]} -gt 0 ]]; then
|
|
||||||
tar czf "$BACKUP_FILE" -C "$HOME" "${BACKUP_PATHS[@]}"
|
|
||||||
log " + User configs backed up."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Backup system XDG separately (needs sudo)
|
|
||||||
if [[ -d /etc/xdg ]]; then
|
|
||||||
SYSTEM_BACKUP="$HOME/moonarch-backup-system-$(date +%Y%m%d-%H%M%S).tar.gz"
|
|
||||||
sudo tar czf "$SYSTEM_BACKUP" -C / etc/xdg
|
|
||||||
sudo chown "$USER:$USER" "$SYSTEM_BACKUP"
|
|
||||||
log " + System configs backed up: $SYSTEM_BACKUP"
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Backup complete: $(du -h "$BACKUP_FILE" | cut -f1)"
|
|
||||||
else
|
|
||||||
log "Skipping backup."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 4: Disable Conflicting Display Managers
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
if [[ ${#CONFLICTING_DMS[@]} -gt 0 ]]; then
|
|
||||||
log "Disabling conflicting display managers..."
|
|
||||||
for dm in "${CONFLICTING_DMS[@]}"; do
|
|
||||||
sudo systemctl disable "$dm"
|
|
||||||
log " - $dm disabled"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 5: Remove Conflicting Packages
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
if pacman -Qq pulseaudio &>/dev/null; then
|
|
||||||
log "Removing PulseAudio (replaced by PipeWire)..."
|
|
||||||
sudo pacman -Rdd --noconfirm pulseaudio pulseaudio-alsa pulseaudio-bluetooth 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 6: Install moonarch-git Package
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
# Install paru if not present
|
|
||||||
if ! command -v paru &>/dev/null; then
|
|
||||||
log "Installing paru..."
|
|
||||||
sudo pacman -S --needed --noconfirm paru
|
|
||||||
else
|
|
||||||
log "paru already installed."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Moonarch custom paru repo
|
|
||||||
log "Setting up Moonarch paru repo..."
|
|
||||||
PARU_CONF="$HOME/.config/paru/paru.conf"
|
|
||||||
mkdir -p "$(dirname "$PARU_CONF")"
|
|
||||||
if ! grep -q '\[moonarch\]' "$PARU_CONF" 2>/dev/null; then
|
|
||||||
cat >> "$PARU_CONF" <<'EOCONF'
|
|
||||||
[moonarch]
|
|
||||||
Url = https://gitea.moonarch.de/nevaforget/moonarch-pkgbuilds.git
|
|
||||||
EOCONF
|
|
||||||
log " + Moonarch repo added to paru.conf."
|
|
||||||
else
|
|
||||||
log " ~ Moonarch repo already in paru.conf."
|
|
||||||
fi
|
|
||||||
|
|
||||||
paru -Sy --pkgbuilds --noconfirm
|
|
||||||
|
|
||||||
log "Installing moonarch-git package..."
|
|
||||||
paru -S --needed --noconfirm moonarch-git
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 7: User-Level Configuration
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
# User-level GTK4 symlinks for libadwaita apps
|
|
||||||
THEME_NAME="Colloid-Grey-Dark-Catppuccin"
|
|
||||||
THEME_GTK4="/usr/share/themes/$THEME_NAME/gtk-4.0"
|
|
||||||
|
|
||||||
if [[ -d "$THEME_GTK4" ]]; then
|
|
||||||
log "Creating user-level GTK4 symlinks for $THEME_NAME..."
|
|
||||||
USER_GTK4="$HOME/.config/gtk-4.0"
|
|
||||||
mkdir -p "$USER_GTK4"
|
|
||||||
ln -sf "$THEME_GTK4/gtk-dark.css" "$USER_GTK4/gtk.css"
|
|
||||||
ln -sf "$THEME_GTK4/gtk-dark.css" "$USER_GTK4/gtk-dark.css"
|
|
||||||
rm -f "$USER_GTK4/assets"
|
|
||||||
ln -s "$THEME_GTK4/assets" "$USER_GTK4/assets"
|
|
||||||
else
|
|
||||||
err "GTK4 theme not found: $THEME_GTK4 — libadwaita apps will use fallback theme."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# gsettings
|
|
||||||
log "Setting gsettings for GTK theme..."
|
|
||||||
gsettings set org.gnome.desktop.interface gtk-theme "$THEME_NAME"
|
|
||||||
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
|
|
||||||
gsettings set org.gnome.desktop.interface icon-theme 'Colloid-Grey-Catppuccin-Dark'
|
|
||||||
gsettings set org.gnome.desktop.interface font-name 'UbuntuSans Nerd Font 11'
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 8: Deploy User Configs (Hard Overwrite)
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
# Replace user-level XDG configs from /etc/xdg/ (deployed by moonarch-git)
|
|
||||||
log "Deploying XDG configs to ~/.config/ (overwrite)..."
|
|
||||||
for src_dir in /etc/xdg/*/; do
|
|
||||||
app_name="$(basename "$src_dir")"
|
|
||||||
# Only overwrite apps that moonarch manages
|
|
||||||
[[ -d "$DEFAULTS_DIR/xdg/$app_name" ]] || continue
|
|
||||||
# gtk-4.0 is handled separately with Colloid-Catppuccin theme symlinks
|
|
||||||
[[ "$app_name" == "gtk-4.0" ]] && continue
|
|
||||||
dest_dir="$HOME/.config/$app_name"
|
|
||||||
rm -rf "$dest_dir" 2>/dev/null || sudo rm -rf "$dest_dir"
|
|
||||||
cp -r --no-preserve=ownership "$src_dir" "$dest_dir"
|
|
||||||
log " + $app_name/"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Deploy user defaults (overwrite, no existence check)
|
|
||||||
log "Deploying user config defaults to ~/.config/ (overwrite)..."
|
|
||||||
if [[ -d "$USER_DEFAULTS" ]]; then
|
|
||||||
for src_dir in "$USER_DEFAULTS"/*/; do
|
|
||||||
app_name="$(basename "$src_dir")"
|
|
||||||
dest_dir="$HOME/.config/$app_name"
|
|
||||||
mkdir -p "$dest_dir"
|
|
||||||
find "$src_dir" -type f -print0 | while IFS= read -r -d '' src_file; do
|
|
||||||
rel_path="${src_file#"$src_dir"}"
|
|
||||||
dest_file="$dest_dir/$rel_path"
|
|
||||||
mkdir -p "$(dirname "$dest_file")"
|
|
||||||
cp "$src_file" "$dest_file"
|
|
||||||
log " + $app_name/$rel_path"
|
|
||||||
done
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Zsh: always create a fresh .zshrc that sources Moonarch defaults
|
|
||||||
log "Creating ~/.zshrc with Moonarch defaults..."
|
|
||||||
mkdir -p "$HOME/.zshrc.d"
|
|
||||||
echo "# Load Moonarch defaults, add custom overrides in ~/.zshrc.d/ or below" > "$HOME/.zshrc"
|
|
||||||
echo "source /etc/zsh/zshrc.moonarch" >> "$HOME/.zshrc"
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 9: Services & Finalization
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
# Enable systemd user services
|
|
||||||
log "Enabling systemd user services..."
|
|
||||||
USER_SERVICES=(
|
|
||||||
"kanshi"
|
|
||||||
)
|
|
||||||
|
|
||||||
for service in "${USER_SERVICES[@]}"; do
|
|
||||||
if systemctl --user cat "${service}.service" &>/dev/null; then
|
|
||||||
systemctl --user enable "$service"
|
|
||||||
log " + $service (user)"
|
|
||||||
else
|
|
||||||
log " ~ $service (user) not found, skipped."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
log "Enabling services..."
|
|
||||||
SERVICES=(
|
|
||||||
"NetworkManager"
|
|
||||||
"bluetooth"
|
|
||||||
"docker"
|
|
||||||
"greetd"
|
|
||||||
"systemd-timesyncd"
|
|
||||||
"ufw"
|
|
||||||
"auto-cpufreq"
|
|
||||||
)
|
|
||||||
|
|
||||||
for service in "${SERVICES[@]}"; do
|
|
||||||
if systemctl list-unit-files "${service}.service" &>/dev/null; then
|
|
||||||
sudo systemctl enable "$service"
|
|
||||||
log " + $service"
|
|
||||||
else
|
|
||||||
log " ~ $service not found, skipped."
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Set shell to zsh
|
|
||||||
if [[ "$SHELL" != */zsh ]]; then
|
|
||||||
log "Setting default shell to zsh..."
|
|
||||||
chsh -s "$(which zsh)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Firewall
|
|
||||||
log "Configuring UFW..."
|
|
||||||
sudo ufw default deny incoming
|
|
||||||
sudo ufw default allow outgoing
|
|
||||||
sudo ufw --force enable
|
|
||||||
|
|
||||||
# Docker group
|
|
||||||
if ! groups | grep -q docker; then
|
|
||||||
log "Adding user to docker group..."
|
|
||||||
sudo usermod -aG docker "$USER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
mkdir -p "$HOME/Pictures/Screenshots"
|
|
||||||
mkdir -p "$HOME/Pictures/Wallpaper"
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# Phase 10: Done
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
log "============================================"
|
|
||||||
log " Moonarch transform complete!"
|
|
||||||
log "============================================"
|
|
||||||
echo ""
|
|
||||||
if [[ -n "$BACKUP_FILE" ]]; then
|
|
||||||
log "Your previous config is backed up at:"
|
|
||||||
log " $BACKUP_FILE"
|
|
||||||
if [[ -n "$SYSTEM_BACKUP" ]]; then
|
|
||||||
log " $SYSTEM_BACKUP"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
log "Next steps:"
|
|
||||||
log " 1. Reboot (greetd replaces your previous display manager)"
|
|
||||||
log " 2. Place wallpapers in ~/Pictures/Wallpaper/"
|
|
||||||
log " 3. rustup default stable"
|
|
||||||
log " 4. User overrides in ~/.config/ or ~/.zshrc.d/"
|
|
||||||
echo ""
|
|
||||||
err "Do NOT log out — your previous DM is disabled. Reboot instead."
|
|
||||||
echo ""
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ABOUTME: Legacy updater — replaced by moonarch-update from the moonarch-git package.
|
|
||||||
# ABOUTME: Prints deprecation notice and forwards if package version is available.
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "\e[1;33m[Moonarch]\e[0m moonarch-update is now provided by the moonarch-git package."
|
|
||||||
echo -e "\e[1;33m[Moonarch]\e[0m Install with: paru -S moonarch-git"
|
|
||||||
echo -e "\e[1;33m[Moonarch]\e[0m Then run: moonarch-update"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
if command -v moonarch-update &>/dev/null && [[ "$(which moonarch-update)" == "/usr/bin/moonarch-update" ]]; then
|
|
||||||
echo -e "\e[1;34m[Moonarch]\e[0m Package version detected. Forwarding..."
|
|
||||||
exec moonarch-update
|
|
||||||
fi
|
|
||||||
Reference in New Issue
Block a user