nix/graphical/webapps.nix

179 lines
3.9 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkOption
mkAliasOptionModule
types
mapAttrsToList
attrNames
filterAttrs
replaceStrings
getExe
toLower
;
inherit (types)
str
strMatching
package
path
nullOr
listOf
attrsOf
submodule
either
;
browser = getExe config.apps.browser;
webAppLauncher = pkgs.writeShellScript "web-app-launcher" ''
browser="${browser}"
browser_exec=""
for path in ~/.local ~/.nix-profile /usr /nix/var/nix/profiles/system/etc/profiles/per-user/$USER; do
if [ -f "$path/share/applications/$browser.desktop" ]; then
browser_exec=$(sed -n 's/^Exec=\([^ ]*\).*/\1/p' "$path/share/applications/$browser.desktop" 2>/dev/null | head -1)
break
fi
done
if [ -z "$browser_exec" ]; then
browser_exec="${browser}"
fi
url="$1"
app_name="''${2:-$(basename "$0")}"
shift 2
exec setsid "$browser_exec" \
--app="$url" \
--user-data-dir="$HOME/.local/share/web-apps/$app_name" \
--no-first-run \
--no-default-browser-check \
--disable-background-timer-throttling \
--disable-backgrounding-occluded-windows \
--disable-renderer-backgrounding \
--enable-quic \
--quic-version=h3-29 \
--enable-features=UseOzonePlatform,WaylandWindowDecorations,WaylandPerWindowScaling,WaylandTextInputV3,WebRTCPipeWireCapturer \
--disable-features=WebRtcAllowInputVolumeAdjustment \
--ozone-platform=wayland \
--gtk-version=4 \
--enable-experimental-web-platform-features \
"$@"
'';
# Create web app package
mkWebApp =
{
name,
url,
icon,
description,
categories,
}:
let
cleanName = replaceStrings [ " " "\n" "\t" ] [ "-" "-" "-" ] name |> toLower;
pname = "${cleanName}-webapp";
in
pkgs.stdenv.mkDerivation {
inherit pname;
version = "1.0";
dontUnpack = true;
nativeBuildInputs = [
pkgs.copyDesktopItems
pkgs.makeWrapper
];
installPhase = ''
runHook preInstall
makeWrapper ${webAppLauncher} $out/bin/${pname} \
--add-flags "${url}" \
--add-flags "${pname}"
runHook postInstall
'';
desktopItems = [
(pkgs.makeDesktopItem (
{
name = pname;
exec = "${pname} %U";
desktopName = name;
startupNotify = true;
startupWMClass = pname;
}
// filterAttrs (_: v: v != null) {
inherit icon categories;
comment = description;
}
))
];
meta.mainProgram = pname;
};
innerOpts = {
options = {
name = mkOption {
type = str;
};
url = mkOption {
type = strMatching "[hH][tT][tT][pP][sS]?://[^\n\r[:space:]]+";
};
icon = mkOption {
type = nullOr (either str path);
default = null;
};
description = mkOption {
type = nullOr str;
default = null;
};
categories = mkOption {
type = nullOr (listOf str);
default = null;
};
};
};
pwaModule = submodule (
{ config, ... }:
{
imports =
let
names = innerOpts.options |> attrNames;
in
map (optName: mkAliasOptionModule [ optName ] [ "settings" optName ]) names;
options = {
settings = mkOption {
type = submodule innerOpts;
default = { };
};
package = mkOption {
type = package;
readOnly = true;
default = mkWebApp config.settings;
};
};
}
);
in
{
options = {
programs.pwas = mkOption {
description = "PWA Applications";
type = attrsOf pwaModule;
default = { };
};
};
config = {
environment.systemPackages = mapAttrsToList (_: v: v.package) config.programs.pwas;
};
}