treewide: move nixos modules

This commit is contained in:
Charlotte Van Petegem 2024-07-18 15:04:18 +02:00
parent d84be7c616
commit 8eff4c5e4f
73 changed files with 62 additions and 62 deletions

View file

@ -0,0 +1,7 @@
{ pkgs }:
pkgs.writeShellScriptBin "color_picker" ''
color=$(${pkgs.grim}/bin/grim -t png -g "$(${pkgs.slurp}/bin/slurp -p)" - | ${pkgs.imagemagick}/bin/convert png:- -unique-colors txt:- | grep -o '#[A-F0-9]\+')
${pkgs.sway}/bin/swaymsg exec -- "echo -n '$color' | ${pkgs.wl-clipboard}/bin/wl-copy --foreground"
''

View file

@ -0,0 +1,523 @@
{ config, lib, pkgs, ... }:
let
launcher = import ./launcher.nix { inherit pkgs; stdenv = pkgs.stdenv; };
color-picker = import ./color-picker.nix { inherit pkgs; };
screenshot = import ./screenshot.nix { inherit pkgs; };
mail-status = pkgs.writeShellScript "mail-status" ''
mails=$(${pkgs.mblaze}/bin/mlist -N ~/mail/*/INBOX | ${pkgs.coreutils}/bin/wc -l)
if [ "$mails" -gt 0 ]
then
echo "{ \"class\": \"has-mail\", \"text\": \"📬 $mails\" }"
else
echo "{ \"text\": \"📭\" }"
fi
'';
lock = pkgs.writeShellScript "lock" ''
if [ "$(darkman get)" == "light" ]
then
${pkgs.swaylock}/bin/swaylock -fF -c eff1f5
else
${pkgs.swaylock}/bin/swaylock -fF -c 303446
fi
'';
baseWrapper = pkgs.writeShellScriptBin "river" ''
export XDG_SESSION_TYPE=wayland
export XDG_CURRENT_DESKTOP=river
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
export QT_AUTO_SCREEN_SCALE_FACTOR=0
export QT_SCALE_FACTOR=1
export GDK_SCALE=1
export GDK_DPI_SCALE=1
export MOZ_ENABLE_WAYLAND=1
export XCURSOR_SIZE=24
export _JAVA_AWT_WM_NONREPARENTING=1
if [ "$DBUS_SESSION_BUS_ADDRESS" ]; then
export DBUS_SESSION_BUS_ADDRESS
exec ${pkgs.river}/bin/river
else
exec ${pkgs.dbus}/bin/dbus-run-session ${pkgs.river}/bin/river
fi
'';
river = pkgs.symlinkJoin {
name = "river-${pkgs.river.version}";
paths = [ baseWrapper pkgs.river ];
strictDeps = false;
nativeBuildInputs = with pkgs; [ makeWrapper wrapGAppsHook ];
buildInputs = with pkgs; [ gdk-pixbuf glib gtk3 ];
dontWrapGApps = true;
postBuild = ''
gappsWrapperArgsHook
wrapProgram $out/bin/river "''${gappsWrapperArgs[@]}"
'';
};
river-init = pkgs.writeShellScript "river-init" ''
riverctl map normal Super Return spawn foot
riverctl map normal Super D spawn 'foot --app-id launcher -- zsh -ic ${launcher}/bin/launcher'
riverctl map normal None Menu spawn 'foot --app-id launcher -- zsh -ic ${launcher}/bin/launcher'
riverctl map normal Super C spawn ${lock}
riverctl map normal Super+Shift C close
riverctl map normal Super+Shift E exit
riverctl map normal Super J focus-view next
riverctl map normal Super K focus-view previous
riverctl map normal Super+Shift J swap next
riverctl map normal Super+Shift K swap previous
riverctl map normal Super H focus-output next
riverctl map normal Super L focus-output previous
riverctl map normal Super+Shift H send-to-output -current-tags next
riverctl map normal Super+Shift L send-to-output -current-tags previous
riverctl map normal Super F zoom
riverctl map normal Super+Shift F toggle-fullscreen
riverctl map normal Super+Control H send-layout-cmd rivertile "main-ratio -0.05"
riverctl map normal Super+Control L send-layout-cmd rivertile "main-ratio +0.05"
riverctl map normal Super+Control+Shift H send-layout-cmd rivertile "main-count +1"
riverctl map normal Super+Control+Shift L send-layout-cmd rivertile "main-count -1"
riverctl map normal Super+Alt H move left 100
riverctl map normal Super+Alt J move down 100
riverctl map normal Super+Alt K move up 100
riverctl map normal Super+Alt L move right 100
riverctl map normal Super+Alt+Control H snap left
riverctl map normal Super+Alt+Control J snap down
riverctl map normal Super+Alt+Control K snap up
riverctl map normal Super+Alt+Control L snap right
riverctl map normal Super+Alt+Shift H resize horizontal -100
riverctl map normal Super+Alt+Shift J resize vertical 100
riverctl map normal Super+Alt+Shift K resize vertical -100
riverctl map normal Super+Alt+Shift L resize horizontal 100
riverctl map normal Super Space toggle-float
riverctl map-pointer normal Super BTN_LEFT move-view
riverctl map-pointer normal Super BTN_RIGHT resize-view
for i in $(seq 1 9)
do
tags=$((1 << ($i - 1)))
riverctl map normal Super $i set-focused-tags $tags
riverctl map normal Super+Shift $i set-view-tags $tags
riverctl map normal Super+Control $i toggle-focused-tags $tags
riverctl map normal Super+Shift+Control $i toggle-view-tags $tags
done
all_tags=$(((1 << 32) - 1))
riverctl map normal Super 0 set-focused-tags $all_tags
riverctl map normal Super+Shift 0 set-view-tags $all_tags
riverctl map normal Super Up send-layout-cmd rivertile "main-location top"
riverctl map normal Super Right send-layout-cmd rivertile "main-location right"
riverctl map normal Super Down send-layout-cmd rivertile "main-location bottom"
riverctl map normal Super Left send-layout-cmd rivertile "main-location left"
riverctl map normal None XF86AudioRaiseVolume spawn '${pkgs.pamixer}/bin/pamixer -i 5'
riverctl map normal None XF86AudioLowerVolume spawn '${pkgs.pamixer}/bin/pamixer -d 5'
riverctl map normal None XF86AudioMute spawn '${pkgs.pamixer}/bin/pamixer --toggle-mute'
riverctl map normal None XF86MonBrightnessDown spawn '${pkgs.brightnessctl}/bin/brightnessctl s -- -5%'
riverctl map normal None XF86MonBrightnessUp spawn '${pkgs.brightnessctl}/bin/brightnessctl s -- +5%'
riverctl map normal None Print spawn '${screenshot}/bin/screenshot'
riverctl map normal Alt Print spawn '${screenshot}/bin/screenshot -d'
riverctl map normal Shift Print spawn '${screenshot}/bin/screenshot -r'
riverctl map normal Alt+Shift Print spawn '${screenshot}/bin/screenshot -r -d'
riverctl rule-add -app-id launcher float
riverctl rule-add -app-id be.ugent.objprog.ugentopoly.Ugentopoly float
riverctl rule-add -title "Quick Format Citation" float
riverctl rule-add ssd
riverctl default-layout rivertile
rivertile -view-padding 0 -outer-padding 0 &
riverctl default-attach-mode bottom
riverctl background-color 0xacb0be
riverctl border-color-focused 0x04e5e5
riverctl border-color-unfocused 0xdce0e8
riverctl border-color-urgent 0xea76cb
riverctl border-width 1
riverctl focus-follows-cursor normal
riverctl hide-cursor when-typing enabled
riverctl set-cursor-warp on-output-change
riverctl xcursor-theme Catppuccin-Latte-Light-Cursors 24
riverctl keyboard-layout -variant altgr-intl -options compose:caps us
configure_touchpads() {
riverctl list-inputs | grep 'type: pointer' -B 1 | grep -vE 'type: pointer|^--$' | xargs -I '{}' riverctl input '{}' $@
}
configure_touchpads drag enabled
configure_touchpads tap enabled
configure_touchpads scroll-method two-finger
${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY XDG_CURRENT_DESKTOP XDG_SESSION_TYPE XCURSOR_SIZE QT_QPA_PLATFORM_THEME QT_STYLE_OVERRIDE QT_PLUGIN_PATH QTWEBKIT_PLUGIN_PATH GDK_PIXBUF_MODULE_FILE XDG_DATA_DIRS GIO_EXTRA_MODULES PATH
systemctl --user start river-session.target
systemctl --user start tray.target
'';
in
{
options.chvp.graphical.compositor.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.compositor.enable {
services = {
dbus.packages = with pkgs; [ dconf ];
greetd = {
enable = true;
settings =
let
river-run = pkgs.writeShellScript "river-run" ''
exec zsh -c "systemd-cat -t river ${river}/bin/river"
'';
in
{
default_session = {
command = "${pkgs.greetd.greetd}/bin/agreety --cmd ${river-run}";
};
initial_session = {
command = "${river-run}";
user = "charlotte";
};
};
};
};
security.pam.services.swaylock = { };
xdg.portal = {
enable = true;
extraPortals = [ pkgs.xdg-desktop-portal-gtk pkgs.xdg-desktop-portal-wlr ];
config.preferred = {
default = "gtk";
"org.freedesktop.impl.portal.Screencast" = "wlr";
};
};
home-manager.users.charlotte = { ... }: {
home.packages = [
river
color-picker
screenshot
pkgs.wf-recorder
pkgs.wl-clipboard
pkgs.wl-mirror
];
programs = {
waybar = {
enable = true;
settings = {
mainBar = {
spacing = 2;
modules-left = [ "river/tags" ];
modules-center = [ "river/window" ];
modules-right = [ "idle_inhibitor" "network#wlp0s20f3" "network#enp0s13f0u2u2" "battery" "backlight" "mpris" "pulseaudio" "custom/mail-status" "clock" "tray" ];
backlight = {
format = "{percent}% {icon}";
format-icons = [ "🌑" "🌒" "🌓" "🌔" "🌕" ];
on-scroll-up = "${pkgs.brightnessctl}/bin/brightnessctl s -- +5%";
on-scroll-down = "${pkgs.brightnessctl}/bin/brightnessctl s -- -5%";
};
battery = {
states = {
good = 90;
warning = 30;
critical = 15;
};
format = "{capacity}% {icon}";
format-charging = "{capacity}% ";
format-plugged = "";
format-alt = "{time} {icon}";
format-icons = [ "" "" "" "" "" ];
};
clock.format = " {:%a %d/%m %H:%M}";
"custom/mail-status" = {
exec = "${mail-status}";
return-type = "json";
interval = 1;
on-click = "${pkgs.isync}/bin/mbsync -a && ${config.chvp.base.emacs.package}/bin/emacsclient --eval \"(mu4e-update-index)\"";
};
idle_inhibitor = {
format = "{icon}";
format-icons = {
activated = "";
deactivated = "";
};
};
mpris = {
player = "firefox";
format = "{status_icon} {artist} - {title}";
status-icons = {
playing = "";
paused = "";
stopped = "";
};
};
"network#wlp0s20f3" = {
interface = "wlp0s20f3";
format-wifi = "{essid} ";
format-ethernet = "{ipaddr}/{cidr} ";
tooltip-format = "{ifname} via {gwaddr} ";
format-linked = "{ifname} (No IP) ";
format-disconnected = "";
format-alt = "{ifname}: {ipaddr}/{cidr}";
};
"network#enp0s13f0u2u2" = {
interface = "enp0s13f0u2u2";
format-wifi = "{essid} ";
format-ethernet = "{ipaddr}/{cidr} ";
tooltip-format = "{ifname} via {gwaddr} ";
format-linked = "{ifname} (No IP) ";
format-disconnected = "";
format-alt = "{ifname}: {ipaddr}/{cidr}";
};
pulseaudio = {
format = "{volume}% {icon} {format_source}";
format-bluetooth = "{volume}% {icon} {format_source}";
format-bluetooth-muted = " {icon} {format_source}";
format-muted = " {format_source}";
format-source = "{volume}% ";
format-source-muted = "";
format-icons = {
headphone = "";
hands-free = "";
headset = "";
phone = "";
portable = "";
car = "";
default = [ "" "" "" ];
};
on-click = "${pkgs.pamixer}/bin/pamixer -t";
on-click-right = "${pkgs.pamixer}/bin/pamixer --default-source -t";
on-click-middle = "${pkgs.pavucontrol}/bin/pavucontrol";
};
tray.spacing = 2;
};
};
style = ''
@import "colors.css";
* {
font-family: Hack, monospace;
font-size: 11px;
}
#window, #idle_inhibitor, #network, #battery, #backlight, #mpris, #pulseaudio, #custom-mail-status, #clock, #tray {
margin: 0;
padding: 0 5px;
background-color: @surface0;
}
button {
border: none;
border-radius: 0;
}
button:hover {
border: none;
border-radius: 0;
}
window#waybar {
background-color: @base;
color: @text;
}
#backlight {
color: @sky;
}
#battery {
color: @green;
}
#battery.good {
color: @sky;
}
#battery.warning {
color: @yellow;
}
#battery.critical {
color: @pink;
}
#custom-mail-status.has-mail {
color: @sky;
}
#idle_inhibitor.activated {
color: @sky;
}
#pulseaudio {
color: @yellow;
}
#tags button {
padding: 0;
box-shadow: inset 0 -3px transparent
color: @text;
}
#tags button.occupied {
background-color: @surface1;
}
#tags button.focused {
color: @sky;
}
#tags button.urgent {
color: @pink;
}
#tags button:hover {
box-shadow: inset 0 -3px @text;
}
'';
systemd.enable = true;
};
zsh.initExtra = ''
rs() {
riverctl spawn "$*"
}
'';
};
services = {
kanshi = {
enable = true;
systemdTarget = "river-session.target";
settings = [
{
profile = {
name = "home-undocked";
outputs = [
{ criteria = "AU Optronics 0x2036 Unknown"; position = "0,0"; mode = "2560x1440"; scale = 1.0; }
];
};
}
{
profile = {
name = "home-docked";
outputs = [
{ criteria = "AU Optronics 0x2036 Unknown"; position = "0,0"; mode = "2560x1440"; scale = 1.0; }
{ criteria = "Dell Inc. DELL U2718Q FN84K01T095L"; position = "2560,0"; mode = "3840x2160"; scale = 1.0; }
];
};
}
];
};
mako = {
enable = true;
font = "Hack Regular 9";
};
swayidle = {
enable = true;
systemdTarget = "river-session.target";
events = [{ event = "before-sleep"; command = "${lock}"; }];
timeouts = [
{ timeout = 150; command = "${pkgs.wlopm}/bin/wlopm --off '*'"; resumeCommand = "${pkgs.wlopm}/bin/wlopm --on '*'"; }
{ timeout = 300; command = "${lock}"; }
];
};
};
systemd.user.targets = {
river-session.Unit = {
Description = "river compositor session";
BindsTo = [ "graphical-session.target" ];
Wants = [ "graphical-session-pre.target" ];
After = [ "graphical-session-pre.target" ];
};
tray.Unit = {
Description = "tray target";
Wants = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
};
};
xdg.configFile = {
"river/init" = {
source = river-init;
onChange = ''
if [ -d /run/user/$UID ]
then
WAYLAND_DISPLAY="$(${pkgs.findutils}/bin/find /run/user/$UID -mindepth 1 -maxdepth 1 -type s -name wayland-\*)"
if [ -S "WAYLAND_DISPLAY" ]
then
${river-init}
fi
fi
'';
};
"waybar/frappe.css".text = ''
@define-color base #303446;
@define-color mantle #292c3c;
@define-color crust #232634;
@define-color text #c6d0f5;
@define-color subtext0 #a5adce;
@define-color subtext1 #b5bfe2;
@define-color surface0 #414559;
@define-color surface1 #51576d;
@define-color surface2 #626880;
@define-color overlay0 #737994;
@define-color overlay1 #838ba7;
@define-color overlay2 #949cbb;
@define-color blue #8caaee;
@define-color lavender #babbf1;
@define-color sapphire #85c1dc;
@define-color sky #99d1db;
@define-color teal #81c8be;
@define-color green #a6d189;
@define-color yellow #e5c890;
@define-color peach #ef9f76;
@define-color maroon #ea999c;
@define-color red #e78284;
@define-color mauve #ca9ee6;
@define-color pink #f4b8e4;
@define-color flamingo #eebebe;
@define-color rosewater #f2d5cf;
'';
"waybar/latte.css".text = ''
@define-color base #eff1f5;
@define-color mantle #e6e9ef;
@define-color crust #dce0e8;
@define-color text #4c4f69;
@define-color subtext0 #6c6f85;
@define-color subtext1 #5c5f77;
@define-color surface0 #ccd0da;
@define-color surface1 #bcc0cc;
@define-color surface2 #acb0be;
@define-color overlay0 #9ca0b0;
@define-color overlay1 #8c8fa1;
@define-color overlay2 #7c7f93;
@define-color blue #1e66f5;
@define-color lavender #7287fd;
@define-color sapphire #209fb5;
@define-color sky #04a5e5;
@define-color teal #179299;
@define-color green #40a02b;
@define-color yellow #df8e1d;
@define-color peach #fe640b;
@define-color maroon #e64553;
@define-color red #d20f39;
@define-color mauve #8839ef;
@define-color pink #ea76cb;
@define-color flamingo #dd7878;
@define-color rosewater #dc8a78;
'';
};
};
};
}

View file

@ -0,0 +1,24 @@
{ pkgs, stdenv }:
let
script = pkgs.substituteAll {
src = ./launcher.zsh;
inherit (pkgs)
fzy
jq
libqalculate
nix
pass
slurp
uni
zsh
;
wfRecorder = pkgs.wf-recorder;
wlClipboard = pkgs.wl-clipboard;
xdgUserDirs = pkgs.xdg-user-dirs;
};
in
pkgs.runCommand "launcher" { } ''
mkdir -p $out/bin
cp ${script} $out/bin/launcher
chmod +x $out/bin/launcher
''

View file

@ -0,0 +1,61 @@
#!@zsh@/bin/zsh
_sighandler() {
kill -INT "$child" 2>/dev/null
}
calc_options() {
echo "calc "
}
calc() {
if [ -n "$1" ]
then
@libqalculate@/bin/qalc "$1"
sleep 5
else
@libqalculate@/bin/qalc
fi
}
emoji_options() {
@uni@/bin/uni emoji all | sed "s/^/emoji /"
}
emoji() {
char=$(echo -n "$1" | sed "s/^\([^ ]*\) .*/\1/")
riverctl spawn "echo -n $char | @wlClipboard@/bin/wl-copy --foreground"
}
nrun_options() {
echo "nrun "
}
nrun() {
riverctl spawn "@nix@/bin/nix run nixpkgs\#$1"
}
run_options() {
print -rl -- ''${(ko)commands} | grep -v "^\\." | sed "s/^/run /"
}
run() {
riverctl spawn $1
}
systemctl_options() {
echo systemctl hibernate
echo systemctl poweroff
echo systemctl reboot
echo systemctl suspend
}
CHOSEN=$(cat <(systemctl_options) <(nrun_options) <(run_options) <(calc_options) <(emoji_options) | @fzy@/bin/fzy --lines 80 | tail -n1)
if [ -n "$CHOSEN" ]
then
PREFIX=$(echo $CHOSEN | sed "s/^\([^ ]*\) .*/\1/g")
WORD=$(echo $CHOSEN | sed "s/^[^ ]* \(.*\)/\1/g")
$PREFIX $WORD
fi

View file

@ -0,0 +1,36 @@
{ pkgs }:
pkgs.writeShellScriptBin "screenshot" ''
while getopts ":rd" opt
do
case "''${opt}" in
r)
remote=true
;;
d)
delay=true
;;
esac
done
dims="$(${pkgs.slurp}/bin/slurp)"
if [[ -n "$delay" ]]
then
sleep 5
fi
if [[ -n "$remote" ]]
then
name=$(${pkgs.util-linux}/bin/uuidgen).png
${pkgs.grim}/bin/grim -t png -g "$dims" - | ${pkgs.openssh}/bin/ssh data "cat > data/public/$name"
path="https://data.vanpetegem.me/public/$name"
else
name=$(date +'screenshot_%Y-%m-%d-%H%M%S.png')
path="$(${pkgs.xdg-user-dirs}/bin/xdg-user-dir PICTURES)/$name"
${pkgs.grim}/bin/grim -g "$dims" "$path"
fi
${pkgs.sway}/bin/swaymsg exec -- "echo -n '$path' | ${pkgs.wl-clipboard}/bin/wl-copy --foreground"
${pkgs.libnotify}/bin/notify-send "Screenshot taken" "$path"
''

View file

@ -0,0 +1,56 @@
{ config, lib, pkgs, ... }:
{
imports = [
./compositor
./firefox
./gnupg
./mail
./nextcloud-client
./pass
./sound
./terminal
./theme
./xdg
];
options.chvp.graphical.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.enable {
users.users.charlotte.extraGroups = [ "input" "video" ];
chvp = {
base = {
nix.unfreePackages = [ "google-chrome" ];
};
graphical = {
compositor.enable = lib.mkDefault true;
firefox.enable = lib.mkDefault true;
gnupg = {
enable = lib.mkDefault true;
pinentryFlavor = "qt";
};
mail.enable = lib.mkDefault true;
nextcloud-client.enable = lib.mkDefault true;
pass.enable = lib.mkDefault true;
sound.enable = lib.mkDefault true;
terminal.enable = lib.mkDefault true;
theme.enable = lib.mkDefault true;
xdg.enable = lib.mkDefault true;
};
};
home-manager.users.charlotte = { ... }: {
home.packages = with pkgs; [
google-chrome
mpv
okular
ranger
uni
wtype
];
};
};
}

View file

@ -0,0 +1,108 @@
{ config, lib, pkgs, ... }:
let
ff2mpv-host = pkgs.stdenv.mkDerivation rec {
pname = "ff2mpv";
version = "4.0.0";
src = pkgs.fetchFromGitHub {
owner = "woodruffw";
repo = "ff2mpv";
rev = "v${version}";
sha256 = "sxUp/JlmnYW2sPDpIO2/q40cVJBVDveJvbQMT70yjP4=";
};
buildInputs = [ pkgs.python3 ];
buildPhase = ''
sed -i "s#/home/william/scripts/ff2mpv#$out/bin/ff2mpv.py#" ff2mpv.json
sed -i 's#"mpv"#"${pkgs.mpv}/bin/umpv"#' ff2mpv.py
'';
installPhase = ''
mkdir -p $out/bin
cp ff2mpv.py $out/bin
mkdir -p $out/lib/mozilla/native-messaging-hosts
cp ff2mpv.json $out/lib/mozilla/native-messaging-hosts
'';
};
ffPackage = pkgs.firefox.override { pkcs11Modules = [ pkgs.eid-mw ]; };
zotero-connector = pkgs.nur.repos.rycee.firefox-addons.buildFirefoxXpiAddon rec {
pname = "zotero-connector";
version = "5.0.119";
addonId = "zotero@chnm.gmu.edu";
url = "https://download.zotero.org/connector/firefox/release/Zotero_Connector-${version}.xpi";
sha256 = "sha256-uRbhq0OSQ0Exgi5FEVFtdAGuLVla0aoGLmL0bMud0J8=";
meta = with lib; {
homepage = "https://www.zotero.org";
description = "Save references to Zotero from your web browser";
license = licenses.agpl3Plus;
platforms = platforms.all;
};
};
in
{
options.chvp.graphical.firefox = {
enable = lib.mkEnableOption "firefox";
package = lib.mkOption {
description = "Final used firefox package";
default = ffPackage;
readOnly = true;
};
};
config = lib.mkIf config.chvp.graphical.firefox.enable {
chvp.base.zfs.homeLinks = [
{ path = ".mozilla"; type = "data"; }
{ path = ".cache/mozilla"; type = "cache"; }
];
home-manager.users.charlotte = { ... }: {
programs.firefox = {
enable = true;
package = ffPackage;
nativeMessagingHosts = [
pkgs.keepassxc
ff2mpv-host
];
policies = {
DisableFirefoxStudies = true;
DisablePocket = true;
DisableTelemetry = true;
DisableFirefoxAccounts = true;
FirefoxHome = { Pocket = false; Snippets = false; };
OfferToSaveLogins = false;
UserMessaging = { SkipOnboarding = true; ExtensionRecommendations = false; };
};
profiles.default = {
extensions = with pkgs.nur.repos.rycee.firefox-addons; [
belgium-eid
consent-o-matic
cookie-autodelete
darkreader
decentraleyes
ff2mpv
keepassxc-browser
multi-account-containers
stylus
ublock-origin
vue-js-devtools
zotero-connector
];
settings = {
"browser.aboutConfig.showWarning" = false;
"browser.contentblocking.category" = "custom";
"browser.download.dir" = "/home/charlotte/downloads";
"browser.newtabpage.enabled" = false;
"browser.safebrowsing.malware.enabled" = false;
"browser.safebrowsing.phishing.enabled" = false;
"browser.shell.checkDefaultBrowser" = false;
"browser.startup.homepage" = "about:blank";
"browser.startup.page" = 3;
"dom.security.https_only_mode" = true;
"network.cookie.cookieBehavior" = 1;
"privacy.annotate_channels.strict_list.enabled" = true;
"privacy.trackingprotection.enabled" = true;
"privacy.trackingprotection.socialtracking.enabled" = true;
"security.identityblock.show_extended_validation" = true;
};
};
};
};
};
}

View file

@ -0,0 +1,41 @@
{ config, lib, pkgs, ... }:
{
options.chvp.graphical.gnupg = {
enable = lib.mkOption {
default = false;
example = true;
};
pinentryFlavor = lib.mkOption {
type = lib.types.str;
default = "curses";
example = "qt";
description = ''
Pinentry flavor for gnupg.
'';
};
};
config = lib.mkIf config.chvp.graphical.gnupg.enable {
chvp.base.zfs.homeLinks = [
{ path = ".gnupg"; type = "data"; }
];
programs.gnupg.agent = {
enable = true;
pinentryPackage = pkgs."pinentry-${config.chvp.graphical.gnupg.pinentryFlavor}";
};
home-manager.users.charlotte = { lib, ... }: {
home.activation.fixPermissionsCommands = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
mkdir -p /home/charlotte/.gnupg
chmod u=rwX,go= /home/charlotte/.gnupg
'';
programs.gpg.enable = true;
services.gpg-agent = {
enable = true;
defaultCacheTtl = 7200;
maxCacheTtl = 99999;
pinentryPackage = pkgs."pinentry-${config.chvp.graphical.gnupg.pinentryFlavor}";
};
};
};
}

View file

@ -0,0 +1,315 @@
{ config, lib, pkgs, ... }:
let
passwordScript = pkgs.writeShellScript "get_mail_password" ''${pkgs.libsecret}/bin/secret-tool lookup secret-tool-id $1 | ${pkgs.coreutils}/bin/tr -d "\n"'';
notifyScript = name: pkgs.writeShellScript "notify_${name}_mail" ''
unseen_count=$(${pkgs.mblaze}/bin/mlist -N ~/mail/*/INBOX | ${pkgs.coreutils}/bin/wc -l)
if [ "$unseen_count" = "1" ]
then
${pkgs.libnotify}/bin/notify-send -t 5000 'New ${name} mail arrived' "1 unseen mail"
elif [ "$unseen_count" != "0" ]
then
${pkgs.libnotify}/bin/notify-send -t 5000 'New ${name} mail arrived' "$unseen_count unseen mails"
fi
'';
makeAccount = { name, address, host ? "", imapHost ? host, smtpHost ? host, useStartTls ? false, secretToolId, extraConfig ? { }, oauth ? false }: (lib.recursiveUpdate
{
inherit address;
gpg = {
key = "charlotte@vanpetegem.me";
signByDefault = true;
};
imap = {
host = imapHost;
port = 993;
tls.enable = true;
};
imapnotify = {
enable = true;
boxes = [ "INBOX" ];
onNotify = "${pkgs.isync}/bin/mbsync ${name}:INBOX";
onNotifyPost = "${config.chvp.base.emacs.package}/bin/emacsclient --eval \"(mu4e-update-index)\" && ${notifyScript name}";
extraConfig = lib.mkIf oauth { xoauth2 = true; };
};
mbsync = {
enable = true;
create = "both";
expunge = "both";
flatten = ".";
remove = "both";
extraConfig.account.AuthMechs = if (oauth) then "XOAUTH2" else "LOGIN";
};
msmtp = {
enable = true;
extraConfig = lib.mkIf oauth { auth = "xoauth2"; };
};
mu.enable = true;
passwordCommand = if oauth then "${pkgs.mfauth}/bin/mfauth access ${name}" else "${passwordScript} ${secretToolId}";
realName = "Charlotte Van Petegem";
signature = {
showSignature = "none";
};
smtp = {
host = smtpHost;
port = if useStartTls then 587 else 465;
tls = {
enable = true;
inherit useStartTls;
};
};
userName = address;
}
extraConfig);
toRecursiveINI = with lib.strings; with lib.attrsets; with lib.generators; with lib.lists; let
repeat = count: char: concatStrings (genList (_: char) count);
mkHeader = depth: name: concatStrings [ (repeat depth "[") (escape [ "[" ] name) (repeat depth "]") ];
simpleAttrs = filterAttrs (n: v: !(isAttrs v));
complexAttrs = filterAttrs (n: v: isAttrs v);
removeEmpty = filter (v: v != "");
toRecursiveINIBase = depth: data: (concatStringsSep "\n" (
mapAttrsToList
(name: values: concatStringsSep "\n" (removeEmpty [
(mkHeader depth name)
(toKeyValue { } (simpleAttrs values))
(toRecursiveINIBase (depth + 1) (complexAttrs values))
]))
data
));
in
toRecursiveINIBase 1;
in
{
options.chvp.graphical.mail.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.mail.enable {
nixpkgs.overlays = [
(self: super: rec {
isync = super.isync.override { withCyrusSaslXoauth2 = true; };
})
];
chvp = {
base = {
emacs.extraConfig =
let
mkAccountConfig = account: ''
(make-mu4e-context
:name "${account.name}"
:match-func (lambda (msg) (when msg (string-prefix-p "/${account.maildir.path}/" (mu4e-message-field msg :maildir))))
:vars '(
(user-mail-address . "${account.address}")
(user-full-name . "${account.realName}")
(mu4e-drafts-folder . "/${account.maildir.path}/${account.folders.drafts}")
(mu4e-sent-folder . "/${account.maildir.path}/${account.folders.sent}")
(mu4e-refile-folder . "/${account.maildir.path}/${account.folders.trash}")
(mu4e-trash-folder . "/${account.maildir.path}/${account.folders.trash}")
(message-sendmail-extra-arguments . ("--read-envelope-from" "--account" "${account.name}"))
)
)
'';
hmConfig = config.home-manager.users.charlotte;
in
[
''
(use-package mu4e
;; Use mu4e included in the mu package, see emacs/default.nix
:ensure nil
:demand t
:after (vertico)
:hook
(mu4e-view-mode . display-line-numbers-mode)
(mu4e-view-mode . visual-line-mode)
(mu4e-compose-mode . chvp--mu4e-auto-dodona-cc-reply-to)
(mu4e-compose-mode . visual-line-mode)
(mu4e-compose-mode . (lambda () (setq use-hard-newlines nil)))
:custom
(mu4e-read-option-use-builtin nil "Don't use builtin autocomplete in mu4e")
(mu4e-completing-read-function 'completing-read "Use default completing read function")
(mu4e-maildir-initial-input "" "Don't have initial input when completing a maildir")
(mu4e-change-filenames-when-moving t "Avoid sync issues with mbsync")
(mu4e-maildir "${hmConfig.accounts.email.maildirBasePath}" "Root of the maildir hierarchy")
(mu4e-context-policy 'pick-first "Use the first mail context in the list")
(mu4e-attachment-dir "/home/charlotte/downloads/" "Save attachments to downloads folder")
(mu4e-compose-dont-reply-to-self t "Don't reply to myself on reply to all")
(mu4e-compose-format-flowed t "Send format=flowed mails when use-hard-newlines gets enabled")
(fill-flowed-display-column 1000000000000 "Dont fill when decoding flowed messages, let visual-line-mode handle it")
(gnus-treat-fill-long-lines nil "Let visual-line-mode handle filling")
(mu4e-confirm-quit nil "Don't confirm when quitting")
(mu4e-headers-include-related nil "Don't show related messages by default")
(mu4e-headers-skip-duplicates nil "Show duplicate emails")
(message-kill-buffer-on-exit t "Close buffer when finished with email")
(mm-verify-option 'known "Always verify PGP signatures (known protocols)")
(mm-discouraged-alternatives '("text/html" "text/richtext") "Discourage showing HTML views")
(gnus-buttonized-mime-types '("multipart/signed") "Make sure signature verification is always shown")
(mml-secure-openpgp-sign-with-sender t "Sign mails with the sender")
(sendmail-program "msmtp" "Use msmtp to send email")
(message-sendmail-f-is-evil t "Remove username from the emacs message")
(message-send-mail-function 'message-send-mail-with-sendmail "Use sendmail to send mail instead internal smtp")
(message-cite-reply-position 'below "Bottom posting is the correct way to reply to email")
:config
;; mu4e should just open in the currently focused window instead of taking up the whole frame
(add-to-list 'display-buffer-alist
`(,(regexp-quote mu4e-main-buffer-name)
display-buffer-same-window))
(setq mu4e-contexts (list ${lib.concatStringsSep "\n" (map mkAccountConfig (lib.attrValues hmConfig.accounts.email.accounts))}))
(add-to-list
'mu4e-bookmarks
'(:name "Combined inbox" :query "maildir:/personal/INBOX or maildir:/posteo/INBOX or maildir:/rodekruis-eerstehulp/INBOX" :key ?i :favorite t)
)
(defun chvp--mu4e-dodona-cc-reply-to ()
"Add dodona@ugent.be in cc and reply-to headers."
(interactive)
(save-excursion (message-add-header "Cc: dodona@ugent.be\nReply-To: dodona@ugent.be\n"))
)
(defun chvp--mu4e-auto-dodona-cc-reply-to ()
"Set dodona@ugent.be in CC and Reply-To headers when message was directed to dodona@ugent.be"
(let ((msg mu4e-compose-parent-message))
(when (and msg (mu4e-message-contact-field-matches msg :to "dodona@ugent.be")) (chvp--mu4e-dodona-cc-reply-to))
)
)
;; Never actually quit mu4e, just close the current buffer (making sure the modeline is still visible)
(defalias 'mu4e-quit 'chvp--kill-current-buffer)
(define-advice mu4e--context-ask-user
(:around (orig-fun &rest args) mu4e--context-ask-user-completing-read)
"Replace `mu4e-read-option` by general-purpose completing-read"
(cl-letf (((symbol-function 'mu4e-read-option)
(lambda (prompt options)
(let* ((prompt (mu4e-format "%s" prompt))
(choice (completing-read prompt (cl-mapcar #'car options) nil t))
(chosen-el (cl-find-if (lambda (option) (equal choice (car option))) options)))
(if chosen-el
(cdr chosen-el)
(mu4e-warn "Unknown option: '%s'" choice))))))
(apply orig-fun args)))
(mu4e 'background)
:general
(lmap "m" '(mu4e :which-key "mail"))
;; Unmap SPC in the mail view so we can still use the leader.
(lmap mu4e-view-mode-map "" nil)
(lmap mu4e-compose-mode-map
"SPC s" '(mml-secure-message-sign-pgpmime :which-key "Sign")
"SPC c" '(mml-secure-message-encrypt-pgpmime :which-key "Encrypt")
"SPC d" '(chvp--mu4e-dodona-cc-reply-to :which-key "Dodona support headers")
"SPC f" '(mu4e-toggle-use-hard-newlines :which-key "Toggle format=flowed/hard newlines")
)
)
(use-package visual-fill-column
:custom (visual-fill-column-enable-sensible-window-split t "Sensibly split windows in visual-fill-column-mode")
:hook (visual-line-mode . visual-fill-column-mode)
)
(use-package adaptive-wrap
:hook (visual-fill-column-mode . adaptive-wrap-prefix-mode)
)
''
];
zfs.homeLinks = [
{ path = "mail"; type = "data"; }
{ path = ".cache/mu"; type = "cache"; }
{ path = ".cache/mfauth"; type = "cache"; }
];
};
};
home-manager.users.charlotte = { ... }: {
accounts.email = {
maildirBasePath = "/home/charlotte/mail";
accounts = {
personal = makeAccount {
name = "personal";
address = "charlotte@vanpetegem.be";
host = "mail.vanpetegem.me";
secretToolId = "personal-mail";
extraConfig = {
folders = { drafts = "Drafts"; inbox = "INBOX"; sent = "INBOX"; trash = "Trash"; };
primary = true;
};
};
posteo = makeAccount {
name = "posteo";
address = "chvp@posteo.net";
host = "posteo.de";
secretToolId = "posteo";
extraConfig = {
folders = { drafts = "Drafts"; inbox = "INBOX"; sent = "INBOX"; trash = "Trash"; };
};
};
postbot = makeAccount {
name = "postbot";
address = "postbot@vanpetegem.be";
host = "mail.vanpetegem.me";
secretToolId = "postbot";
extraConfig = {
folders = { drafts = "Drafts"; inbox = "INBOX"; sent = "INBOX"; trash = "Trash"; };
};
};
rodekruis-eerstehulp = makeAccount {
name = "rodekruis-eerstehulp";
address = "eerstehulp@gent.rodekruis.be";
imapHost = "imap.gmail.com";
smtpHost = "smtp.gmail.com";
useStartTls = true;
secretToolId = "eerstehulp-mail";
extraConfig = {
folders = { drafts = "[Gmail].Concepten"; inbox = "INBOX"; sent = "INBOX"; trash = "[Gmail].Prullenbak"; };
flavor = "gmail.com";
};
};
webmaster = makeAccount {
name = "webmaster";
address = "webmaster@vanpetegem.be";
host = "mail.vanpetegem.me";
secretToolId = "webmaster";
extraConfig = {
folders = { drafts = "Drafts"; inbox = "INBOX"; sent = "INBOX"; trash = "Trash"; };
};
};
};
};
programs = {
mbsync.enable = true;
msmtp.enable = true;
mu.enable = true;
};
services = {
imapnotify.enable = true;
};
systemd.user = {
services = {
mbsync = {
Unit = {
Description = "MBSync email fetcher";
After = "network-online.target";
Wants = "network-online.target";
};
Service = {
Type = "oneshot";
ExecStart = [ "${pkgs.isync}/bin/mbsync -a" "${config.chvp.base.emacs.package}/bin/emacsclient --eval \"(mu4e-update-index)\"" ];
};
};
};
timers = {
mbsync = {
Unit = { Description = "MBSync email fetcher"; };
Timer = {
OnCalendar = "*:0/5";
Unit = "mbsync.service";
};
Install = { WantedBy = [ "timers.target" ]; };
};
vdirsyncer = {
Unit = { Description = "VDirSyncer WebDAV syncer"; };
Timer = {
OnCalendar = "*:0/5";
Unit = "vdirsyncer.service";
};
Install = { WantedBy = [ "timers.target" ]; };
};
};
};
};
};
}

View file

@ -0,0 +1,22 @@
{ config, lib, pkgs, ... }:
{
options.chvp.graphical.nextcloud-client.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.nextcloud-client.enable {
chvp.base.zfs.homeLinks = [
{ path = ".config/Nextcloud"; type = "cache"; }
{ path = ".local/share/Nextcloud"; type = "cache"; }
{ path = "sync"; type = "cache"; }
];
home-manager.users.charlotte = { ... }: {
services.nextcloud-client = {
enable = true;
startInBackground = true;
};
};
};
}

View file

@ -0,0 +1,42 @@
{ config, lib, pkgs, ... }:
{
options.chvp.graphical.pass.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.pass.enable {
chvp.base.zfs.homeLinks = [
{ path = ".config/keepassxc"; type = "data"; }
{ path = ".cache/keepassxc"; type = "cache"; }
];
chvp.base.emacs.extraConfig = [
''
(use-package secrets
:ensure nil
:custom
(auth-sources '(default))
)
''
];
home-manager.users.charlotte = { ... }: {
home.packages = [ pkgs.keepassxc ];
systemd.user.services.keepassxc = {
Unit = {
Description = "KeepassXC startup";
PartOf = [ "river-session.target" ];
Wants = [ "waybar.service" ];
After = [ "river-session.target" "waybar.service" ];
};
Service = {
ExecStart = "${pkgs.keepassxc}/bin/keepassxc";
Restart = "always";
};
Install.WantedBy = [ "river-session.target" ];
};
};
};
}

View file

@ -0,0 +1,30 @@
{ config, lib, pkgs, ... }:
{
options.chvp.graphical.sound.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.sound.enable {
chvp.base.zfs.homeLinks = [
{ path = ".local/state/wireplumber"; type = "cache"; }
];
home-manager.users.charlotte = { ... }: {
home.packages = with pkgs; [
pavucontrol
qjackctl
];
};
services = {
pipewire = {
enable = true;
alsa.enable = true;
jack.enable = true;
pulse.enable = true;
};
};
};
}

View file

@ -0,0 +1,50 @@
{ config, lib, pkgs, ... }:
{
options.chvp.graphical.terminal.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.terminal.enable {
home-manager.users.charlotte = { pkgs, ... }: {
home.packages = [ pkgs.foot ];
programs.foot = {
enable = true;
settings = {
main = {
font = "Hack:size=9";
dpi-aware = "no";
};
bell = {
urgent = true;
notify = true;
};
scrollback.lines = 10000;
cursor.blink = true;
mouse.hide-when-typing = true;
colors = {
foreground = "4c4f69";
background = "eff1f5";
regular0 = "5c5f77";
regular1 = "d20f39";
regular2 = "40a02b";
regular3 = "df8e1d";
regular4 = "1e66f5";
regular5 = "ea76cb";
regular6 = "179299";
regular7 = "acb0be";
bright0 = "6c6f85";
bright1 = "d20f39";
bright2 = "40a02b";
bright3 = "df8e1d";
bright4 = "1e66f5";
bright5 = "ea76cb";
bright6 = "179299";
bright7 = "bcc0cc";
};
};
};
};
};
}

View file

@ -0,0 +1,198 @@
{ config, lib, pkgs, ... }:
{
options.chvp.graphical.theme.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.theme.enable {
chvp.base.zfs.homeLinks = [
{ path = ".config/qt5ct"; type = "cache"; }
{ path = ".config/qt6ct"; type = "cache"; }
];
fonts = {
fontDir.enable = true;
fontconfig = {
enable = true;
defaultFonts = {
emoji = [ "Noto Color Emoji" ];
# The Tinos and Amiro fonts overlap with Font Awesome's codepoints, so make sure we give Font Awesome a higher priority.
monospace = [ "Hack" "Font Awesome 6 Free" ];
sansSerif = [ "Noto Sans" "Font Awesome 6 Free" ];
serif = [ "Noto Serif" "Font Awesome 6 Free" ];
};
};
packages = with pkgs; [
hack-font
font-awesome
noto-fonts
noto-fonts-cjk
noto-fonts-emoji
noto-fonts-extra
roboto
];
};
programs.dconf.enable = true;
home-manager.users.charlotte = { pkgs, lib, ... }: {
home.packages = [
pkgs.catppuccin-cursors.latteLight
# Also install dark mode to profile for darkman
(pkgs.catppuccin-gtk.override { size = "compact"; variant = "frappe"; })
];
home.file = {
".icons/default/index.theme".text = ''
[Icon Theme]
Name=Default
Comment=Default Cursor Theme
Inherits=catppuccin-latte-light-cursors
'';
};
dconf.settings."org/gnome/desktop/wm/preferences".button-layout = "";
gtk = {
enable = true;
font = {
package = pkgs.noto-fonts;
name = "Noto Sans";
size = 10;
};
gtk2.extraConfig = ''
gtk-cursor-theme-name = "catppuccin-latte-light-cursors"
gtk-cursor-theme-size = 24
'';
gtk3 = {
extraConfig = {
gtk-cursor-theme-name = "catppuccin-latte-light-cursors";
gtk-cursor-theme-size = 24;
};
extraCss = ''
/* No (default) titlebar on wayland */
headerbar.titlebar.default-decoration {
background: transparent;
padding: 0;
margin: 0 0 -17px 0;
border: 0;
min-height: 0;
font-size: 0;
box-shadow: none;
}
/* rm -rf window shadows */
window.csd, /* gtk4? */
window.csd decoration { /* gtk3 */
box-shadow: none;
}
'';
};
gtk4 = {
extraConfig = {
gtk-cursor-theme-name = "catppuccin-latte-light-cursors";
gtk-cursor-theme-size = 24;
};
extraCss = ''
/* No (default) titlebar on wayland */
headerbar.titlebar.default-decoration {
background: transparent;
padding: 0;
margin: 0 0 -17px 0;
border: 0;
min-height: 0;
font-size: 0;
box-shadow: none;
}
/* rm -rf window shadows */
window.csd, /* gtk4? */
window.csd decoration { /* gtk3 */
box-shadow: none;
}
'';
};
iconTheme = {
package = pkgs.libsForQt5.breeze-icons;
name = "breeze";
};
theme = {
package = pkgs.catppuccin-gtk.override { size = "compact"; variant = "latte"; };
name = "Catppuccin-Latte-Compact-Blue-Light";
};
};
qt = {
enable = true;
platformTheme.name = "qtct";
style = {
name = "lightly";
package = pkgs.lightly-qt;
};
};
services.darkman = {
enable = true;
settings = {
lat = 51.0;
lng = 3.7;
usegeoclue = false;
dbusserver = true;
portal = true;
};
darkModeScripts = {
emacs = ''
emacsclient --eval "(setq catppuccin-flavor 'frappe)"
emacsclient --eval "(load-theme 'catppuccin :no-confirm)"
'';
gtk = ''
${pkgs.glib}/bin/gsettings set org.gnome.desktop.interface gtk-theme Catppuccin-Frappe-Compact-Blue-Dark
'';
river = ''
riverctl background-color 0x626880
riverctl border-color-focused 0x99d1db
riverctl border-color-unfocused 0x232634
riverctl border-color-urgent 0xf4b8e4
'';
qt = ''
sed -i "s/Latte/Frappe/" ~/.config/qt5ct/qt5ct.conf
sed -i "s/Latte/Frappe/" ~/.config/qt6ct/qt6ct.conf
'';
terminal = ''
pkill -SIGUSR2 zsh
'';
waybar = ''
ln -sf ~/.config/waybar/frappe.css ~/.config/waybar/colors.css
systemctl --user restart waybar.service
'';
};
lightModeScripts = {
emacs = ''
emacsclient --eval "(setq catppuccin-flavor 'latte)"
emacsclient --eval "(load-theme 'catppuccin :no-confirm)"
'';
gtk = ''
${pkgs.glib}/bin/gsettings set org.gnome.desktop.interface gtk-theme Catppuccin-Latte-Compact-Blue-Light
'';
river = ''
riverctl background-color 0xacb0be
riverctl border-color-focused 0x04e5e5
riverctl border-color-unfocused 0xdce0e8
riverctl border-color-urgent 0xea76cb
'';
qt = ''
sed -i "s/Frappe/Latte/" ~/.config/qt5ct/qt5ct.conf
sed -i "s/Frappe/Latte/" ~/.config/qt6ct/qt6ct.conf
'';
terminal = ''
pkill -SIGUSR1 zsh
'';
waybar = ''
ln -sf ~/.config/waybar/latte.css ~/.config/waybar/colors.css
systemctl --user restart waybar.service
'';
};
};
home.activation = {
linkWaybarCssColors = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
$DRY_RUN_CMD ln -sf $VERBOSE_ARG ~/.config/waybar/latte.css ~/.config/waybar/colors.css
'';
};
};
};
}

View file

@ -0,0 +1,58 @@
{ config, lib, pkgs, ... }:
{
options.chvp.graphical.xdg.enable = lib.mkOption {
default = false;
example = true;
};
config = lib.mkIf config.chvp.graphical.xdg.enable {
chvp.base.zfs.homeLinks = [
{ path = "desktop"; type = "data"; }
{ path = "documents"; type = "data"; }
{ path = "downloads"; type = "cache"; }
{ path = "music"; type = "data"; }
{ path = "pictures"; type = "cache"; }
{ path = "repos"; type = "cache"; }
{ path = "templates"; type = "data"; }
{ path = "videos"; type = "data"; }
];
home-manager.users.charlotte = { pkgs, ... }: {
home.packages = with pkgs; [ xdg-user-dirs xdg-utils ];
xdg = {
enable = true;
# Some applications overwrite mimeapps.list with an identical file
configFile."mimeapps.list".force = true;
mimeApps = {
enable = true;
defaultApplications = {
"image/png" = [ "org.kde.okular.desktop" ];
"image/jpg" = [ "org.kde.okular.desktop" ];
"image/jpeg" = [ "org.kde.okular.desktop" ];
"application/pdf" = [ "org.kde.okular.desktop" ];
"text/html" = [ "firefox.desktop" ];
"x-scheme-handler/about" = [ "firefox.desktop" ];
"x-scheme-handler/http" = [ "firefox.desktop" ];
"x-scheme-handler/https" = [ "firefox.desktop" ];
"x-scheme-handler/unknown" = [ "firefox.desktop" ];
"x-scheme-handler/msteams" = [ "teams.desktop" ];
};
};
userDirs = {
enable = true;
desktop = "\$HOME/desktop";
documents = "\$HOME/documents";
download = "\$HOME/downloads";
music = "\$HOME/music";
pictures = "\$HOME/pictures";
publicShare = "\$HOME/desktop";
templates = "\$HOME/templates";
videos = "\$HOME/videos";
};
};
};
};
}