mirror of
https://github.com/nix-community/home-manager.git
synced 2026-08-26 01:33:59 +00:00
noctalia: init module
Noctalia is a native Wayland desktop shell for people who want a polished, configurable Linux desktop without stitching together a separate bar, launcher, notification daemon, lock screen, wallpaper tool, and settings UI.
This commit is contained in:
committed by
GitHub
parent
9f56e690e4
commit
03f4cd46bc
10
modules/misc/news/2026/08/2026-08-01_09-29-44.nix
Normal file
10
modules/misc/news/2026/08/2026-08-01_09-29-44.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
time = "2026-08-01T09:29:44+00:00";
|
||||
condition = pkgs.stdenv.hostPlatform.isLinux;
|
||||
message = ''
|
||||
A new module is available `programs.noctalia`.
|
||||
|
||||
Noctalia is a sleek, customizable shell crafted for Wayland.
|
||||
'';
|
||||
}
|
||||
153
modules/programs/noctalia.nix
Normal file
153
modules/programs/noctalia.nix
Normal file
@@ -0,0 +1,153 @@
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.programs.noctalia;
|
||||
jsonFormat = pkgs.formats.json { };
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
|
||||
generateConfig =
|
||||
format: name: value:
|
||||
if lib.isString value then
|
||||
pkgs.writeText name value
|
||||
else if builtins.isPath value || lib.isStorePath value then
|
||||
value
|
||||
else
|
||||
format.generate name value;
|
||||
|
||||
generateToml = generateConfig tomlFormat;
|
||||
generateJson = generateConfig jsonFormat;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
rachitvrma
|
||||
];
|
||||
|
||||
options.programs.noctalia = {
|
||||
enable = lib.mkEnableOption "noctalia, a lightweight Wayland shell and bar";
|
||||
|
||||
systemd.enable = lib.mkEnableOption "a systemd user service for noctalia";
|
||||
|
||||
package = lib.mkPackageOption pkgs "noctalia" { nullable = true; };
|
||||
|
||||
checkConfig = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Validate the configuration file at build time.";
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type =
|
||||
with lib.types;
|
||||
oneOf [
|
||||
tomlFormat.type
|
||||
str
|
||||
path
|
||||
];
|
||||
default = { };
|
||||
description = ''
|
||||
Default settings for noctalia, can be written as:
|
||||
- A Nix attrset (converted to TOML via nixpkgs' tomlFormat)
|
||||
- A raw TOML string
|
||||
- A path to a `.toml` file
|
||||
|
||||
See <https://docs.noctalia.dev/v5> for more information and examples.
|
||||
|
||||
Note: these settings can still be overwritten at runtime via the settings menu.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
shell = {
|
||||
font = "JetBrainsMono Nerd Font";
|
||||
settings_show_advanced = true;
|
||||
};
|
||||
|
||||
theme = {
|
||||
mode = "dark";
|
||||
source = "builtin";
|
||||
builtin = "Catppuccin";
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
customPalettes = lib.mkOption {
|
||||
type =
|
||||
with lib.types;
|
||||
attrsOf (oneOf [
|
||||
jsonFormat.type
|
||||
str
|
||||
path
|
||||
]);
|
||||
default = { };
|
||||
description = ''
|
||||
Custom color palettes, keyed by name. Each value can be:
|
||||
- A Nix attrset (converted to JSON)
|
||||
- A raw JSON string
|
||||
- A path to a {file}`.json` file
|
||||
|
||||
See <https://docs.noctalia.dev/v5/theming/#custom_palette>.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "programs.noctalia" pkgs lib.platforms.linux)
|
||||
|
||||
{
|
||||
assertion = !cfg.systemd.enable || cfg.package != null;
|
||||
message = "programs.noctalia.package cannot be null when programs.noctalia.systemd.enable is true";
|
||||
}
|
||||
];
|
||||
systemd.user.services.noctalia = lib.mkIf cfg.systemd.enable {
|
||||
Unit = {
|
||||
Description = "Noctalia - A lightweight Wayland shell and bar";
|
||||
Documentation = "https://docs.noctalia.dev/v5/";
|
||||
PartOf = [ config.wayland.systemd.target ];
|
||||
After = [ config.wayland.systemd.target ];
|
||||
X-Restart-Triggers =
|
||||
lib.optional (cfg.settings != { }) "${config.xdg.configFile."noctalia/config.toml".source}"
|
||||
++ lib.mapAttrsToList (
|
||||
name: _: "${config.xdg.configFile."noctalia/palettes/${name}.json".source}"
|
||||
) cfg.customPalettes;
|
||||
};
|
||||
|
||||
Service = {
|
||||
ExecStart = lib.getExe cfg.package;
|
||||
Restart = "on-failure";
|
||||
};
|
||||
|
||||
Install.WantedBy = [ config.wayland.systemd.target ];
|
||||
};
|
||||
|
||||
home.packages = lib.optional (cfg.package != null) cfg.package;
|
||||
|
||||
xdg = {
|
||||
configFile = lib.mkMerge [
|
||||
(lib.mkIf (cfg.settings != { }) {
|
||||
"noctalia/config.toml".source =
|
||||
let
|
||||
rawConfig = generateToml "config.toml" cfg.settings;
|
||||
in
|
||||
if cfg.checkConfig && cfg.package != null then
|
||||
pkgs.runCommand "noctalia-config.toml" { } ''
|
||||
${lib.getExe cfg.package} config validate ${rawConfig}
|
||||
cp ${rawConfig} $out
|
||||
''
|
||||
else
|
||||
rawConfig;
|
||||
})
|
||||
(lib.mapAttrs' (
|
||||
name: palette:
|
||||
lib.nameValuePair "noctalia/palettes/${name}.json" {
|
||||
source = generateJson "${name}-palette.json" palette;
|
||||
}
|
||||
) cfg.customPalettes)
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
106
tests/modules/programs/noctalia/custom-palette.nix
Normal file
106
tests/modules/programs/noctalia/custom-palette.nix
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
programs.noctalia = {
|
||||
enable = true;
|
||||
checkConfig = false;
|
||||
customPalettes.example_gruvbox = {
|
||||
dark = {
|
||||
mError = "#ea6962";
|
||||
mHover = "#89b482";
|
||||
mOnError = "#141617";
|
||||
mOnHover = "#141617";
|
||||
mOnPrimary = "#141617";
|
||||
mOnSecondary = "#141617";
|
||||
mOnSurface = "#ddc7a1";
|
||||
mOnSurfaceVariant = "#bdae93";
|
||||
mOnTertiary = "#141617";
|
||||
mOutline = "#5a524c";
|
||||
mPrimary = "#d3869b";
|
||||
mSecondary = "#7daea3";
|
||||
mShadow = "#141617";
|
||||
mSurface = "#141617";
|
||||
mSurfaceVariant = "#1d2021";
|
||||
mTertiary = "#89b482";
|
||||
terminal = {
|
||||
background = "#141617";
|
||||
bright = {
|
||||
black = "#5a524c";
|
||||
blue = "#7daea3";
|
||||
cyan = "#89b482";
|
||||
green = "#a9b665";
|
||||
magenta = "#d3869b";
|
||||
red = "#ea6962";
|
||||
white = "#ebdbb2";
|
||||
yellow = "#d8a657";
|
||||
};
|
||||
cursor = "#ddc7a1";
|
||||
cursorText = "#141617";
|
||||
foreground = "#ddc7a1";
|
||||
normal = {
|
||||
black = "#1d2021";
|
||||
blue = "#7daea3";
|
||||
cyan = "#89b482";
|
||||
green = "#a9b665";
|
||||
magenta = "#d3869b";
|
||||
red = "#ea6962";
|
||||
white = "#ddc7a1";
|
||||
yellow = "#d8a657";
|
||||
};
|
||||
selectionBg = "#5a524c";
|
||||
selectionFg = "#ddc7a1";
|
||||
};
|
||||
};
|
||||
light = {
|
||||
mError = "#cc241d";
|
||||
mHover = "#427b58";
|
||||
mOnError = "#fbf1c7";
|
||||
mOnHover = "#fbf1c7";
|
||||
mOnPrimary = "#fbf1c7";
|
||||
mOnSecondary = "#fbf1c7";
|
||||
mOnSurface = "#3c3836";
|
||||
mOnSurfaceVariant = "#7c6f64";
|
||||
mOnTertiary = "#fbf1c7";
|
||||
mOutline = "#bdae93";
|
||||
mPrimary = "#b16286";
|
||||
mSecondary = "#458588";
|
||||
mShadow = "#d5c4a1";
|
||||
mSurface = "#fbf1c7";
|
||||
mSurfaceVariant = "#f2e5bc";
|
||||
mTertiary = "#427b58";
|
||||
terminal = {
|
||||
background = "#fbf1c7";
|
||||
bright = {
|
||||
black = "#928374";
|
||||
blue = "#076678";
|
||||
cyan = "#427b58";
|
||||
green = "#79740e";
|
||||
magenta = "#8f3f71";
|
||||
red = "#9d0006";
|
||||
white = "#3c3836";
|
||||
yellow = "#b57614";
|
||||
};
|
||||
cursor = "#3c3836";
|
||||
cursorText = "#fbf1c7";
|
||||
foreground = "#3c3836";
|
||||
normal = {
|
||||
black = "#fbf1c7";
|
||||
blue = "#458588";
|
||||
cyan = "#689d6a";
|
||||
green = "#98971a";
|
||||
magenta = "#b16286";
|
||||
red = "#cc241d";
|
||||
white = "#7c6f64";
|
||||
yellow = "#d79921";
|
||||
};
|
||||
selectionBg = "#3c3836";
|
||||
selectionFg = "#fbf1c7";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
local customPalette="home-files/.config/noctalia/palettes/example_gruvbox.json"
|
||||
assertFileExists $customPalette
|
||||
assertFileContent $customPalette "${./expected-custom-palette.json}"
|
||||
'';
|
||||
}
|
||||
7
tests/modules/programs/noctalia/default.nix
Normal file
7
tests/modules/programs/noctalia/default.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ lib, pkgs, ... }:
|
||||
lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
|
||||
noctalia-empty-config = ./empty-config.nix;
|
||||
noctalia-example-config = ./example-config.nix;
|
||||
noctalia-custom-palette = ./custom-palette.nix;
|
||||
noctalia-systemd-enabled = ./systemd-enabled.nix;
|
||||
}
|
||||
7
tests/modules/programs/noctalia/empty-config.nix
Normal file
7
tests/modules/programs/noctalia/empty-config.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
programs.noctalia.enable = true;
|
||||
|
||||
nmt.script = ''
|
||||
assertPathNotExists "home-files/.config/noctalia";
|
||||
'';
|
||||
}
|
||||
36
tests/modules/programs/noctalia/example-config.nix
Normal file
36
tests/modules/programs/noctalia/example-config.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
programs.noctalia = {
|
||||
enable = true;
|
||||
checkConfig = false;
|
||||
settings = {
|
||||
audio = {
|
||||
enable_sounds = true;
|
||||
};
|
||||
bar = {
|
||||
default = {
|
||||
background_opacity = 0.8;
|
||||
capsule = true;
|
||||
capsule_border = "outline";
|
||||
font_family = "JetBrainsMono Nerd Font Mono";
|
||||
position = "top";
|
||||
};
|
||||
};
|
||||
desktop_widgets = {
|
||||
grid = {
|
||||
cell_size = 16;
|
||||
major_interval = 4;
|
||||
visible = true;
|
||||
};
|
||||
schema_version = 2;
|
||||
widget = { };
|
||||
widget_order = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
local configFile="home-files/.config/noctalia/config.toml"
|
||||
assertFileExists $configFile
|
||||
assertFileContent $configFile ${./expected-example-config.toml}
|
||||
'';
|
||||
}
|
||||
94
tests/modules/programs/noctalia/expected-custom-palette.json
Normal file
94
tests/modules/programs/noctalia/expected-custom-palette.json
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"dark": {
|
||||
"mError": "#ea6962",
|
||||
"mHover": "#89b482",
|
||||
"mOnError": "#141617",
|
||||
"mOnHover": "#141617",
|
||||
"mOnPrimary": "#141617",
|
||||
"mOnSecondary": "#141617",
|
||||
"mOnSurface": "#ddc7a1",
|
||||
"mOnSurfaceVariant": "#bdae93",
|
||||
"mOnTertiary": "#141617",
|
||||
"mOutline": "#5a524c",
|
||||
"mPrimary": "#d3869b",
|
||||
"mSecondary": "#7daea3",
|
||||
"mShadow": "#141617",
|
||||
"mSurface": "#141617",
|
||||
"mSurfaceVariant": "#1d2021",
|
||||
"mTertiary": "#89b482",
|
||||
"terminal": {
|
||||
"background": "#141617",
|
||||
"bright": {
|
||||
"black": "#5a524c",
|
||||
"blue": "#7daea3",
|
||||
"cyan": "#89b482",
|
||||
"green": "#a9b665",
|
||||
"magenta": "#d3869b",
|
||||
"red": "#ea6962",
|
||||
"white": "#ebdbb2",
|
||||
"yellow": "#d8a657"
|
||||
},
|
||||
"cursor": "#ddc7a1",
|
||||
"cursorText": "#141617",
|
||||
"foreground": "#ddc7a1",
|
||||
"normal": {
|
||||
"black": "#1d2021",
|
||||
"blue": "#7daea3",
|
||||
"cyan": "#89b482",
|
||||
"green": "#a9b665",
|
||||
"magenta": "#d3869b",
|
||||
"red": "#ea6962",
|
||||
"white": "#ddc7a1",
|
||||
"yellow": "#d8a657"
|
||||
},
|
||||
"selectionBg": "#5a524c",
|
||||
"selectionFg": "#ddc7a1"
|
||||
}
|
||||
},
|
||||
"light": {
|
||||
"mError": "#cc241d",
|
||||
"mHover": "#427b58",
|
||||
"mOnError": "#fbf1c7",
|
||||
"mOnHover": "#fbf1c7",
|
||||
"mOnPrimary": "#fbf1c7",
|
||||
"mOnSecondary": "#fbf1c7",
|
||||
"mOnSurface": "#3c3836",
|
||||
"mOnSurfaceVariant": "#7c6f64",
|
||||
"mOnTertiary": "#fbf1c7",
|
||||
"mOutline": "#bdae93",
|
||||
"mPrimary": "#b16286",
|
||||
"mSecondary": "#458588",
|
||||
"mShadow": "#d5c4a1",
|
||||
"mSurface": "#fbf1c7",
|
||||
"mSurfaceVariant": "#f2e5bc",
|
||||
"mTertiary": "#427b58",
|
||||
"terminal": {
|
||||
"background": "#fbf1c7",
|
||||
"bright": {
|
||||
"black": "#928374",
|
||||
"blue": "#076678",
|
||||
"cyan": "#427b58",
|
||||
"green": "#79740e",
|
||||
"magenta": "#8f3f71",
|
||||
"red": "#9d0006",
|
||||
"white": "#3c3836",
|
||||
"yellow": "#b57614"
|
||||
},
|
||||
"cursor": "#3c3836",
|
||||
"cursorText": "#fbf1c7",
|
||||
"foreground": "#3c3836",
|
||||
"normal": {
|
||||
"black": "#fbf1c7",
|
||||
"blue": "#458588",
|
||||
"cyan": "#689d6a",
|
||||
"green": "#98971a",
|
||||
"magenta": "#b16286",
|
||||
"red": "#cc241d",
|
||||
"white": "#7c6f64",
|
||||
"yellow": "#d79921"
|
||||
},
|
||||
"selectionBg": "#3c3836",
|
||||
"selectionFg": "#fbf1c7"
|
||||
}
|
||||
}
|
||||
}
|
||||
20
tests/modules/programs/noctalia/expected-example-config.toml
Normal file
20
tests/modules/programs/noctalia/expected-example-config.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[audio]
|
||||
enable_sounds = true
|
||||
|
||||
[bar.default]
|
||||
background_opacity = 0.8
|
||||
capsule = true
|
||||
capsule_border = "outline"
|
||||
font_family = "JetBrainsMono Nerd Font Mono"
|
||||
position = "top"
|
||||
|
||||
[desktop_widgets]
|
||||
schema_version = 2
|
||||
widget_order = []
|
||||
|
||||
[desktop_widgets.grid]
|
||||
cell_size = 16
|
||||
major_interval = 4
|
||||
visible = true
|
||||
|
||||
[desktop_widgets.widget]
|
||||
26
tests/modules/programs/noctalia/systemd-enabled.nix
Normal file
26
tests/modules/programs/noctalia/systemd-enabled.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{ config, ... }: {
|
||||
programs.noctalia = {
|
||||
enable = true;
|
||||
package = config.lib.test.mkStubPackage { outPath = "@noctalia@"; };
|
||||
systemd.enable = true;
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileContent \
|
||||
home-files/.config/systemd/user/noctalia.service \
|
||||
${builtins.toFile "noctalia.service" ''
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
|
||||
[Service]
|
||||
ExecStart=@noctalia@/bin/dummy
|
||||
Restart=on-failure
|
||||
|
||||
[Unit]
|
||||
After=graphical-session.target
|
||||
Description=Noctalia - A lightweight Wayland shell and bar
|
||||
Documentation=https://docs.noctalia.dev/v5/
|
||||
PartOf=graphical-session.target
|
||||
''}
|
||||
'';
|
||||
}
|
||||
Reference in New Issue
Block a user