Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions ansible/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# hypr — Ansible deployment

Installs the runtime packages this Hyprland config shells out to and links the
config into place. Mirrors the sibling [`quickshell`](https://github.com/quantumfate/quickshell)
role — deploy both for the full desktop.

## Deploy locally

```sh
ansible-galaxy collection install -r ansible/requirements.yml
ansible-playbook ansible/playbook.yml --ask-become-pass
```

## What it does

- Installs `hypr_packages` (compositor + `hypr*` ecosystem, terminals, menu,
and the tools binds/scripts call — see `roles/hypr/defaults/main.yml`).
- Symlinks the checkout to `~/.config/hypr` (skipped when you edit in place).
- Seeds the shared Dofus state dir (`$XDG_STATE_HOME/dofus`).

## Not installed here

AUR / proprietary / per-host bits the config touches but can't come from the
official repos — install yourself:

- `ankama-launcher` (Dofus), the NVIDIA driver, `hyprqt6engine` (Qt theming).
- User scripts on `PATH` (`,hyprshot.sh`, `,brightness.sh`, `dofus_swap.py`).

Set `hypr_install_extra_packages: true` (with an AUR helper configured) to let
the role attempt `hypr_extra_packages`.
15 changes: 15 additions & 0 deletions ansible/playbook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
# Standalone entrypoint — deploy this Hyprland config to the local machine:
#
# ansible-playbook ansible/playbook.yml --ask-become-pass
#
# From a separate controller, import instead of running directly (see README):
# - import_playbook: path/to/hypr/ansible/playbook.yml
# or include just the role:
# roles: [{ role: hypr }] # with ansible/roles on your roles_path
- name: Deploy quantumfate Hyprland config
hosts: localhost
connection: local
gather_facts: true
roles:
- role: hypr
18 changes: 18 additions & 0 deletions ansible/requirements.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# Collections this role needs (install with: ansible-galaxy collection install -r requirements.yml).
collections:
- name: community.general # pacman module

# --- Consuming this from a controller ------------------------------------------
# This repo's role lives at ansible/roles/hypr. To import it into another
# controller/playbook, either add it as a git submodule and put ansible/roles on
# your `roles_path`, or vendor it. Then in your playbook:
#
# - hosts: workstation
# roles:
# - role: hypr
# vars:
# hypr_repo_path: /path/to/checkout
#
# Pairs with the sibling `quickshell` role (the bar); deploy both for the full
# desktop. This mirrors how a Nix flake exposes a module for another to import.
48 changes: 48 additions & 0 deletions ansible/roles/hypr/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
# Path to this repo checkout on the target. Defaults to the repo this role ships
# in; override when importing from a controller that clones it elsewhere.
hypr_repo_path: "{{ playbook_dir }}/.."

# Where the live config lives. The role symlinks it to hypr_repo_path unless they
# already resolve to the same path (i.e. you edit the config in place).
hypr_config_dir: "{{ ansible_user_dir }}/.config/hypr"

# Runtime packages (Arch). Set false to manage them yourself.
hypr_install_packages: true
hypr_packages:
# --- compositor + hypr* ecosystem (each has its own .conf in this repo) ---
- hyprland # the compositor
- hypridle # hypridle.conf (idle → lock/dpms)
- hyprlock # hyprlock.conf / hyprlock-laptop.conf
- hyprpaper # hyprpaper.conf (wallpaper)
- hyprsunset # hyprsunset.conf (night light)
- hyprpicker # color-pick bind
- hyprshot # screenshot binds
- xdg-desktop-portal-hyprland # portal backend
- xdg-desktop-portal-gtk # portal (file pickers / settings)
# --- shell / launcher / session ---
- uwsm # session-scoped app launches (autostart qs)
- rofi-wayland # menus
- kitty # terminal
- foot # terminal (alttab preview)
# --- tools invoked from binds / lua / scripts ---
- xdotool # window poke / click-repeat helpers
- brightnessctl # brightness binds
- gamemode # gamemoderun (Dofus launch)
- satty # screenshot annotate
- grim # screenshot capture
- jq # JSON parsing in lua/scripts
- libnotify # notify-send (fallback path)
- procps-ng # pgrep / pkill
- xorg-setxkbmap # setxkbmap dvorak-custom
- inetutils # hostname (per-host config selection)
# The bar itself (`qs -c quantumfate`) is deployed by the sibling quickshell
# repo's role; its package is pulled in there. Listed as a reminder, not here.

# AUR / proprietary bits the config touches but can't be installed from the
# official repos — install these yourself (paru/yay). Enable to have the role
# attempt them via community.general.pacman with an AUR helper you configure.
hypr_install_extra_packages: false
hypr_extra_packages:
- hyprqt6engine # hyprqt6engine.conf (Qt theming) — AUR
# ankama-launcher (Dofus) is proprietary; install manually.
18 changes: 18 additions & 0 deletions ansible/roles/hypr/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
galaxy_info:
role_name: hypr
namespace: quantumfate
author: quantumfate
description: Deploy the quantumfate Hyprland (Lua) config + its runtime deps.
license: MIT
min_ansible_version: "2.14"
platforms:
- name: Archlinux
versions:
- all
galaxy_tags:
- hyprland
- wayland
- desktop
- dotfiles
dependencies: []
40 changes: 40 additions & 0 deletions ansible/roles/hypr/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
- name: Install Hyprland runtime packages
become: true
community.general.pacman:
name: "{{ hypr_packages }}"
state: present
when: hypr_install_packages | bool

- name: Install extra (AUR) packages
become: true
community.general.pacman:
name: "{{ hypr_extra_packages }}"
state: present
when: hypr_install_extra_packages | bool

- name: Ensure the ~/.config directory exists
ansible.builtin.file:
path: "{{ ansible_user_dir }}/.config"
state: directory
mode: "0755"

# Deploy the config by symlinking it to the checkout — unless the checkout IS
# the config dir already (editing in place), in which case there's nothing to do.
- name: Symlink the config into place
ansible.builtin.file:
src: "{{ hypr_repo_path | realpath }}"
dest: "{{ hypr_config_dir }}"
state: link
force: true
when: (hypr_repo_path | realpath) != (hypr_config_dir | realpath)

# Shared Dofus state (team.json) lives in XDG_STATE_HOME and is written by both
# this config (hypr/lib/store.lua) and the quickshell UI. Seed the directory.
- name: Ensure the XDG state directory exists
ansible.builtin.file:
path: >-
{{ (ansible_env.XDG_STATE_HOME | default(ansible_user_dir + '/.local/state'))
+ '/dofus' }}
state: directory
mode: "0755"
78 changes: 61 additions & 17 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,68 @@

outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = import nixpkgs { inherit system; };
in {
let
pkgs = import nixpkgs { inherit system; };

# Repo tooling (formatters, hooks, linters) for editing the Lua config.
devTools = with pkgs; [
git
just
pre-commit
stylua
luajit
lua-language-server
luarocks
luaPackages.luacheck
shfmt
shellcheck
yamllint
prettier
nixpkgs-fmt
];

# Runtime dependencies the config binds/scripts shell out to, so a
# `nix develop` shell can drive it. Mirrors the ansible role
# (ansible/roles/hypr). Package names track the binaries scanned from
# hypr/**.lua, *.conf and scripts/*.sh.
runtimeDeps = with pkgs; [
# --- compositor + hypr* ecosystem (own .conf files in this repo) ---
hyprland # the compositor
hypridle # hypridle.conf
hyprlock # hyprlock.conf / hyprlock-laptop.conf
hyprpaper # hyprpaper.conf
hyprsunset # hyprsunset.conf
hyprpicker # color pick binds
hyprshot # screenshot binds (,hyprshot.sh)
xdg-desktop-portal-hyprland # portal backend
xdg-desktop-portal-gtk # portal (file pickers)
# --- shell / launcher / session ---
quickshell # the bar (autostarted: `uwsm app -- qs -c quantumfate`)
uwsm # session-scoped app launches
rofi-wayland # menus
kitty # terminal
foot # terminal (alttab preview)
# --- tools invoked from binds / lua / scripts ---
xdotool # window poke / click-repeat helpers
brightnessctl # brightness binds
gamemode # gamemoderun (Dofus launch)
satty # screenshot annotate
grim # screenshot capture
jq # JSON parsing in lua/scripts
libnotify # notify-send (fallback path)
procps # pgrep / pkill
xorg.setxkbmap # keyboard layout (setxkbmap dvorak-custom)
inetutils # hostname (per-host config selection)
# Not declared (host/proprietary, install per-host):
# ankama-launcher (AUR) — `gamemoderun ankama-launcher`
# nvidia driver, hyprqt6engine (hyprqt6engine.conf) — host Qt theming
# dofus_swap.py — provided by the quickshell repo's scripts/bin on PATH
# ~/.config/waybar/scripts/*, ,brightness.sh, ,hyprshot.sh — user scripts
];
in
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
git
just
pre-commit
stylua
luajit
lua-language-server
luarocks
luaPackages.luacheck
shfmt
shellcheck
yamllint
prettier
nixpkgs-fmt
];
packages = devTools ++ runtimeDeps;
# Wire the repo into git on shell entry.
shellHook = ''
command -v pre-commit >/dev/null && \
Expand Down
22 changes: 22 additions & 0 deletions hypr/binds.lua
Original file line number Diff line number Diff line change
Expand Up @@ -277,5 +277,27 @@ submap.tree({
qs.notify("Quickshell IPC", "help", "all")
end,
},
{
key = "m",
desc = "Toggle system monitor",
action = function()
qs.call("sysmon", "toggle")
end,
},
{
key = "b",
desc = "Toggle notifications",
action = function()
qs.call("notifications", "toggle")
end,
},
{
key = "d",
desc = "Toggle do-not-disturb",
stay = true,
action = function()
qs.call("notify", "dnd")
end,
},
},
})
27 changes: 14 additions & 13 deletions hypr/lib/notify.lua
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
-- NotifyWrapper — routes WM feedback (swap on/off, launch enable, layout hints)
-- through the Quickshell notification daemon instead of Hyprland's internal
-- overlay. These are all transient: shown once, never kept in history.
-- Public API is unchanged (text, duration, level) so call sites need no edits.
---@class NotifyWrapper
local M = {}

local colors = require("hypr.themes.macchiato")

---@enum NotifyLevel
M.level = {
INFO = "INFO",
WARNING = "WARNING",
ERROR = "ERROR",
}

M.colors = {
[M.level.INFO] = colors.mauve,
[M.level.WARNING] = colors.peach,
[M.level.ERROR] = colors.red,
-- WM levels → the shell's toast levels (it has no distinct "warning").
local qs_level = {
INFO = "info",
WARNING = "info",
ERROR = "error",
}

---@param text string
---@param duration integer
---@param _duration integer unused — the daemon owns toast lifetime (kept for API compat)
---@param level NotifyLevel
function M:notify(text, duration, level)
hl.notification.create({
text = text,
duration = duration,
color = self.colors[level],
})
function M:notify(text, _duration, level)
local lvl = qs_level[level] or "info"
-- Transient `notify toast`: feedback-only, excluded from history.
hl.exec_cmd(("qs -c quantumfate ipc call notify toast %q %q"):format(text, lvl))
end

M.__index = M
Expand Down
Loading