summaryrefslogtreecommitdiff
path: root/home-manager
diff options
context:
space:
mode:
authortriethyl <triethylammonium@pm.me>2025-09-02 10:48:21 -0400
committertriethyl <triethylammonium@pm.me>2025-09-02 10:48:21 -0400
commit31c316d19cd974bb81a5d6de62142ff24db1c78e (patch)
treecb941422c76cb8953830a8d58c8e14dca1a10319 /home-manager
parent1c21018347aa277caba74e554cb8d1b1e7fc6bed (diff)
reorganized directory structure
Diffstat (limited to 'home-manager')
-rw-r--r--home-manager/features/cli/apps/btop.nix15
-rw-r--r--home-manager/features/cli/apps/helix.nix71
-rw-r--r--home-manager/features/cli/apps/lazygit.nix12
-rw-r--r--home-manager/features/cli/apps/zellij.nix22
-rw-r--r--home-manager/features/cli/bundles/go-env.nix14
-rw-r--r--home-manager/features/cli/scripts/spiral/default.nix10
-rw-r--r--home-manager/features/cli/scripts/spiral/plan.md47
-rwxr-xr-xhome-manager/features/cli/scripts/spiral/spiral.nu329
-rw-r--r--home-manager/features/cli/shells/nushell/completion.nu17
-rw-r--r--home-manager/features/cli/shells/nushell/default.nix109
-rw-r--r--home-manager/features/cli/shells/nushell/direnv-project-template/.envrc1
-rw-r--r--home-manager/features/cli/shells/nushell/direnv-project-template/.gitignore1
-rw-r--r--home-manager/features/cli/shells/nushell/direnv-project-template/flake.nix29
-rw-r--r--home-manager/features/cli/shells/nushell/prompt.nu97
-rw-r--r--home-manager/features/cli/utils/git.nix16
-rw-r--r--home-manager/features/cli/utils/pandoc.nix13
-rw-r--r--home-manager/features/cli/utils/ssh.nix20
-rw-r--r--home-manager/features/global/home-manager.nix3
-rw-r--r--home-manager/features/global/nixpkgs.nix3
-rw-r--r--home-manager/features/gui/apps/foot.nix18
-rw-r--r--home-manager/features/gui/apps/librewolf.nix19
-rw-r--r--home-manager/features/gui/apps/mpv.nix28
-rw-r--r--home-manager/features/gui/apps/obs.nix10
-rw-r--r--home-manager/features/gui/apps/qutebrowser/default.nix81
-rw-r--r--home-manager/features/gui/apps/qutebrowser/scripts/yt-ad-skip.js29
-rw-r--r--home-manager/features/gui/apps/qutebrowser/scripts/yt-dislike-viewer.js704
-rw-r--r--home-manager/features/gui/apps/qutebrowser/scripts/yt-shorts-blocker.js23
-rw-r--r--home-manager/features/gui/apps/qutebrowser/scripts/yt-sponsor-skip.js51
-rw-r--r--home-manager/features/gui/apps/vesktop.nix8
-rw-r--r--home-manager/features/gui/bundles/video.nix11
-rwxr-xr-xhome-manager/features/gui/desktops/niri/default.nix125
-rw-r--r--home-manager/features/gui/desktops/niri/keybinds.nix168
-rwxr-xr-xhome-manager/features/gui/desktops/niri/parts/fuzzel.nix30
-rwxr-xr-xhome-manager/features/gui/desktops/niri/parts/hyprlock.nix46
-rwxr-xr-xhome-manager/features/gui/desktops/niri/parts/mako.nix26
-rw-r--r--home-manager/features/gui/desktops/niri/parts/quickshell/.envrc1
-rw-r--r--home-manager/features/gui/desktops/niri/parts/quickshell/flake.lock64
-rw-r--r--home-manager/features/gui/desktops/niri/parts/quickshell/flake.nix29
-rw-r--r--home-manager/features/gui/desktops/niri/parts/selectors.nix123
-rwxr-xr-xhome-manager/features/gui/desktops/niri/parts/swww.nix8
-rwxr-xr-xhome-manager/features/gui/desktops/niri/parts/waybar.nix136
-rw-r--r--home-manager/features/gui/desktops/niri/parts/wl-kbptr.nix14
-rw-r--r--home-manager/features/gui/desktops/niri/parts/wluma.nix11
-rw-r--r--home-manager/features/gui/desktops/niri/readme.md9
-rw-r--r--home-manager/features/services/flatpak.nix27
-rw-r--r--home-manager/features/services/udiskie.nix17
-rw-r--r--home-manager/features/services/wluma.nix11
-rw-r--r--home-manager/modules/aesthetics/default.nix101
-rw-r--r--home-manager/modules/aesthetics/readme.md15
-rw-r--r--home-manager/modules/aesthetics/targets/default.nix11
-rw-r--r--home-manager/modules/aesthetics/targets/foot.nix55
-rw-r--r--home-manager/modules/aesthetics/targets/gtk.nix119
-rw-r--r--home-manager/modules/aesthetics/targets/helix.nix28
-rw-r--r--home-manager/modules/aesthetics/targets/mako.nix23
-rw-r--r--home-manager/modules/aesthetics/targets/qutebrowser.nix213
-rw-r--r--home-manager/modules/aesthetics/targets/vesktop.nix65
-rw-r--r--home-manager/modules/aesthetics/targets/zellij.nix28
-rw-r--r--home-manager/modules/aesthetics/themes/default.nix5
-rw-r--r--home-manager/modules/aesthetics/themes/oxocarbon/default.nix68
-rw-r--r--home-manager/modules/aesthetics/themes/oxocarbon/helix-theme.toml52
-rw-r--r--home-manager/modules/default-apps.nix49
-rw-r--r--home-manager/modules/default.nix6
-rw-r--r--home-manager/users/ideapad-laptop/lucas.nix61
-rw-r--r--home-manager/users/nzxt-desktop/culsans.nix71
-rw-r--r--home-manager/users/prodesk-server/server.nix0
-rw-r--r--home-manager/users/steam-deck/culsans.nix59
-rw-r--r--home-manager/users/thinkpad-laptop/lucas.nix61
67 files changed, 3746 insertions, 0 deletions
diff --git a/home-manager/features/cli/apps/btop.nix b/home-manager/features/cli/apps/btop.nix
new file mode 100644
index 0000000..5bb2499
--- /dev/null
+++ b/home-manager/features/cli/apps/btop.nix
@@ -0,0 +1,15 @@
+{ config, lib, ... }: let
+ cfg = config.features.cli.apps.btop;
+in {
+ options.features.cli.apps.btop.enable = lib.mkEnableOption "btop";
+ config = lib.mkIf cfg.enable {
+ programs.btop = {
+ enable = true;
+ settings = {
+ color_theme = "TTY";
+ theme_background = false;
+ update_ms = 500;
+ };
+ };
+ };
+}
diff --git a/home-manager/features/cli/apps/helix.nix b/home-manager/features/cli/apps/helix.nix
new file mode 100644
index 0000000..a267b23
--- /dev/null
+++ b/home-manager/features/cli/apps/helix.nix
@@ -0,0 +1,71 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ cfg = config.features.cli.apps.helix;
+in {
+ options.features.cli.apps.helix.enable = lib.mkEnableOption "helix";
+ config = lib.mkIf cfg.enable {
+ home.packages = with pkgs; [
+ wl-clipboard
+ ];
+ programs.helix = {
+ enable = true;
+ extraPackages = with pkgs; [
+ markdown-oxide
+ python312Packages.black
+ vscode-langservers-extracted
+ nil
+ ];
+ settings = {
+ editor = {
+ color-modes = true;
+ true-color = true;
+ line-number = "relative";
+ mouse = false;
+ lsp.display-messages = true;
+ statusline = {
+ left = ["file-name" "file-modification-indicator"];
+ center = [];
+ right = [];
+ mode = {
+ normal = "NORMAL";
+ insert = "INSERT";
+ select = "SELECT";
+ };
+ };
+ cursor-shape = {
+ normal = "block";
+ insert = "bar";
+ select = "underline";
+ };
+ soft-wrap = {
+ enable = true;
+ wrap-indicator = "";
+ };
+ };
+ keys = {
+ normal = {
+ esc = ["collapse_selection" "keep_primary_selection"];
+ space = {
+ v = "file_picker_in_current_buffer_directory";
+ h = ":lsp-workspace-command";
+ };
+ };
+ };
+ };
+ languages = {
+ language = [
+ {
+ name = "nix";
+ auto-format = true;
+ formatter.command = "${pkgs.alejandra}/bin/alejandra";
+ language-servers = ["nil"];
+ }
+ ];
+ };
+ };
+ };
+}
diff --git a/home-manager/features/cli/apps/lazygit.nix b/home-manager/features/cli/apps/lazygit.nix
new file mode 100644
index 0000000..9d19a36
--- /dev/null
+++ b/home-manager/features/cli/apps/lazygit.nix
@@ -0,0 +1,12 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.features.cli.apps.lazygit;
+in {
+ options.features.cli.apps.lazygit.enable = lib.mkEnableOption "lazygit";
+ config = lib.mkIf cfg.enable {
+ programs.lazygit.enable = true;
+ };
+}
diff --git a/home-manager/features/cli/apps/zellij.nix b/home-manager/features/cli/apps/zellij.nix
new file mode 100644
index 0000000..8942771
--- /dev/null
+++ b/home-manager/features/cli/apps/zellij.nix
@@ -0,0 +1,22 @@
+{ config, lib, ... }: let
+ cfg = config.features.cli.apps.zellij;
+in {
+ options.features.cli.apps.zellij.enable = lib.mkEnableOption "zellij";
+ config = lib.mkIf cfg.enable {
+ programs.zellij = {
+ enable = true;
+ settings = {
+ pane_frames = true;
+ ui.pane_frames.rounded_corners = true;
+ simplified_ui = true;
+ default_layout = "compact";
+ hide_session_name = true;
+
+ mouse_mode = false;
+
+ on_force_close = "detach";
+ session_serialization = true;
+ };
+ };
+ };
+}
diff --git a/home-manager/features/cli/bundles/go-env.nix b/home-manager/features/cli/bundles/go-env.nix
new file mode 100644
index 0000000..6e103a3
--- /dev/null
+++ b/home-manager/features/cli/bundles/go-env.nix
@@ -0,0 +1,14 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.cli.bundles.go-env;
+in {
+ options.features.cli.bundles.go-env.enable = lib.mkEnableOption "go-env";
+ config = lib.mkIf cfg.enable {
+ home.sessionVariables = {
+ GOPATH = "~/.go";
+ };
+ home.packages = with pkgs; [
+ go
+ gopls
+ ];
+ };
+}
diff --git a/home-manager/features/cli/scripts/spiral/default.nix b/home-manager/features/cli/scripts/spiral/default.nix
new file mode 100644
index 0000000..780c207
--- /dev/null
+++ b/home-manager/features/cli/scripts/spiral/default.nix
@@ -0,0 +1,10 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.cli.scripts.spiral;
+in {
+ options.features.cli.scripts.spiral.enable = lib.mkEnableOption "spiral";
+ config = lib.mkIf cfg.enable {
+ home.packages = [
+ (pkgs.writers.writeNuBin "sp" (builtins.readFile ./spiral.nu))
+ ];
+ };
+}
diff --git a/home-manager/features/cli/scripts/spiral/plan.md b/home-manager/features/cli/scripts/spiral/plan.md
new file mode 100644
index 0000000..adbcba0
--- /dev/null
+++ b/home-manager/features/cli/scripts/spiral/plan.md
@@ -0,0 +1,47 @@
+# Spiral Plan
+
+## Main Functions
+
+Are ran by the user.
+
+- `main new (--no-frontmatter (-n)) (title: <string>)`
+- `main open (--by-title (-t)) (--by-contents (-c)) (title: <string>)`
+- `main tags (tag: <string>)`
+- `main remove (--by-title (-t)) (--by-contents (-c)) (title: <string>)`
+- `main list`
+- `main restore (--by-title (-t)) (--by-contents (-c)) (title: <string>)`
+- `main journal (date: <string>)`
+
+## Action Functions
+
+Accept parameters and perform an action.
+
+- `create_note (--no-frontmatter) --title <string>`
+- `create_journal_entry --title <string>`
+- `open_file_in_editor --dir <dir>`
+
+## Interface Functions
+
+Accept a prompt and other data and return a value from the user.
+
+- `get_confirmation --prompt <string> -> bool`
+- `get_string_input --prompt <string> -> string`
+- `get_choice_from_list --list <list> -> string`
+- `get_choice_from_dir --dir <dir> -> path`
+- `get_choice_from_dir_file_contents --dir <dir> -> path: line number`
+- `get_choice_from_note_titles --dir <dir> -> path`
+
+## String Manipulation Functions
+
+Accept, modify, and return strings.
+
+- `title_to_path title: <string> -> path`
+- `strip_line_number string: <string> -> string`
+- `generate_note_text (--no-frontmatter) --title <string> -> string`
+
+## File Manipulation Functions
+
+Read, write, or otherwise manipulate files.
+
+- `parse_note_frontmatter path: <path> -> record`
+- `list_notes -> table`
diff --git a/home-manager/features/cli/scripts/spiral/spiral.nu b/home-manager/features/cli/scripts/spiral/spiral.nu
new file mode 100755
index 0000000..399dace
--- /dev/null
+++ b/home-manager/features/cli/scripts/spiral/spiral.nu
@@ -0,0 +1,329 @@
+#!/usr/bin/env nu
+
+# +---------------+
+# | Configuration |
+# +---------------+
+
+# Default config options.
+mut config = {
+ notebook_dir: "~/Sync/notebook"
+ journal_dir: "~/Sync/notebook/journal"
+ trash_dir: "~/Sync/notebook/.trash"
+}
+
+# Read config options from environment variables.
+if ((try {$env.spiral_notebook_dir}) != null) {
+ $config.notebook_dir = $env.spiral_notebook_dir
+}
+if ((try {$env.spiral_journal_dir}) != null) {
+ $config.journal_dir = $env.spiral_journal_dir
+}
+if ((try {$env.spiral_trash_dir}) != null) {
+ $config.trash_dir = $env.spiral_trash_dir
+}
+
+# Make config immutable.
+let config = $config
+
+# +-------------+
+# | Subcommands |
+# +-------------+
+
+# A commandline utility written in nushell to manage your markdown notebook!
+def "main" [] {}
+
+# Create a new note.
+def "main new" [
+ title?: string # The title of the new note.
+ --no-frontmatter (-n) # Don't add a frontmatter to the note.
+] {
+ mut title = $title
+ if ($title == null) {
+ $title = get_string_input "Enter a title: "
+ }
+ if $no_frontmatter {
+ create_note --no-frontmatter $title
+ } else {
+ create_note $title
+ }
+}
+
+# Open a pre-existing note.
+def "main open" [
+ --by-title (-t) # Filter notes by their title (disables preview)
+ --by-contents (-c) # Search through the contents of the notebook.
+ title?: string # The title of the note to open.
+] {
+ if ($by_title and $by_contents) {
+ error make {msg: "Only one flag can be used at a time."}
+ }
+ if ($title != null) {
+ if ((title_to_path $title) | path exists) {
+ return (title_to_path $title)
+ } else {
+ if (confirm $"The note ($title) does not exist. Would you like to create it? ") {
+ create_note $title
+ }
+ }
+ } else if $by_title {
+ edit $"(get_choice_from_note_titles --dir $config.notebook_dir)"
+ } else if $by_contents {
+ edit (get_choice_from_dir_file_contents --dir $config.notebook_dir)
+ } else {
+ edit $"(get_choice_from_dir --dir $config.notebook_dir)"
+ }
+}
+
+# Open a note based on the tag.
+def "main tags" [
+ tag?: string # The tag to select a note from.
+] {
+ # This section of code creates nested records with tags and notes and stores them in $tag_record.
+ let note_table = list_notes --dir $config.notebook_dir
+
+ let tag_list = $note_table
+ | get tags
+ | flatten
+ | where (($it != null) and ($it != ""))
+
+ mut tag_record = {}
+
+ print $tag_list
+ for tag in $tag_list {
+ mut notes = {}
+ for note_path in ($note_table | get path) {
+ let note_tags = ($note_table | where path == $note_path | get tags | flatten)
+ let note_title = ($note_table | where path == $note_path | get title | to text | str trim)
+ if ($note_tags != []) {
+ for note_tag in $note_tags {
+ if ($note_tag == $tag) {
+ $notes = $notes | insert $note_title { $note_path }
+ }
+ }
+ }
+ }
+ let notes = $notes
+ # $tag_record = $tag_record | insert $tag { $notes }
+ }
+
+ # Actual logic of the subcommand
+ if ($tag == null) {
+ let user_tag_choice = get_choice_from_list --list $tag_list
+ if ($user_tag_choice != "") {
+ let note_record = $tag_record | get $user_tag_choice
+ let user_note_title_choice = get_choice_from_list --list ($note_record | columns)
+ if ($user_note_title_choice != "") {
+ edit ($note_record | get $user_note_title_choice)
+ }
+ }
+ } else {
+ if ($tag_list | any {|item| $item == $tag}) {
+ let note_record = $tag_record | get $tag
+ let user_note_title_choice = get_choice_from_list --list ($note_record | columns)
+ if ($user_note_title_choice != "") {
+ edit ($note_record | get $user_note_title_choice)
+ }
+ } else {
+ print $"The tag '($tag)' does not exist."
+ }
+ }
+}
+
+# Get a table of notes and their properties.
+def "main list" [] {
+ return (list_notes --dir $config.notebook_dir)
+}
+
+# Send a note to the trash.
+def "main remove" [
+ --by-title (-t) # Filter notes by their title (disables preview)
+ --by-contents (-c) # Search through the contents of the notebook.
+ title?: string # The title of the note to send to the trash.
+] {
+ if ($by_title and $by_contents) {
+ error make {msg: "Only one flag can be used at a time."}
+ }
+ if ($title != null) {
+ if ((title_to_path $title) | path exists) {
+ return (title_to_path $title)
+ } else {
+ if (confirm $"The note ($title) does not exist. Would you like to create it? ") {
+ create_note $title
+ }
+ }
+ } else if $by_title {
+ mv (select_note --by-title --dir $config.notebook_dir)
+ } else if $by_contents {
+ ^$env.editor (select_note --by-contents --dir $config.notebook_dir)
+ } else {
+ ^$env.editor (select_note --dir $config.notebook_dir)
+ }
+}
+
+# Explains how to configural Spiral.
+def "main config" [] {
+ print "The default options:"
+ print $config
+ print "These can be modified by editing the environment variables corresponding to each option. For example, to change the notebook directory, set $env.spiral_notebook_dir='~/custom-dir/notebook'."
+}
+
+# +------------------+
+# | Action Functions |
+# +------------------+
+
+def create_note [--no-frontmatter, title: string] {
+ let note_path = title_to_path $title
+ if ($note_path | path exists) {
+ if (confirm "This note already exists. Would you like to open it?") {
+ edit $note_path
+ } else {exit}
+ } else {
+ if $no_frontmatter {
+ generate_note_text --no-frontmatter --title $title | save $note_path
+ } else {
+ generate_note_text --title $title | save $note_path
+ }
+ edit $"($note_path):100:100"
+ }
+}
+
+def create_journal_entry [
+
+] {
+
+}
+
+def edit [
+ file_path: string
+] {
+ if (($file_path | path type) == file) {
+ ^$env.editor ($file_path | path expand)
+ }
+}
+
+# +---------------------+
+# | Interface Functions |
+# +---------------------+
+
+def get_string_input [prompt: string] {
+ print $prompt
+ return (input)
+}
+
+def get_confirmation [prompt: string] {
+ print $"($prompt) \(Y/n)"
+ let confirmation = (input | str downcase)
+ if ($confirmation == "n" ) {
+ return false
+ } else {return true}
+}
+
+def get_choice_from_list [ --list: list ] {
+ return (($list | to text) | tv)
+} # -> string
+
+def get_choice_from_dir [ --dir: string ] {
+ return $"($config.notebook_dir | path expand)/(tv files ($dir | path expand))"
+} # -> full path
+
+def get_choice_from_dir_file_contents [ --dir: string ] {
+ return $"($config.notebook_dir | path expand)/(tv text ($dir | path expand))"
+} # -> full path: line number
+
+def get_choice_from_note_titles [ --dir: string ] {
+ let note_table = list_notes --dir $config.notebook_dir
+ let user_choice = get_choice_from_list --list ($note_table | get title)
+ let user_choice_path = (
+ $note_table
+ | where title == $user_choice
+ | get path
+ | to text
+ | str trim
+ )
+ if (($user_choice_path | path type) == file) {
+ return $user_choice_path
+ }
+} # -> full path
+
+# +-------------------------------+
+# | String Manipulation Functions |
+# +-------------------------------+
+
+def title_to_path [title: string] {
+ return (
+ $"($config.notebook_dir)/($title | str kebab-case).md"
+ | path expand
+ )
+} # -> full path
+
+def strip_line_number [string: string] {
+ return (
+ $string
+ | split row ":"
+ | select 0
+ | to text
+ | str trim
+ )
+} # -> string
+
+def generate_note_text [
+ --no-frontmatter
+ --title: string
+] {
+ if $no_frontmatter {
+ return $"# ($title)\n"
+ } else {
+ let frontmatter_info = {
+ title: $title
+ date: (date now)
+ lang: "en-US"
+ tags: ['note']
+ }
+ return $"---\n($frontmatter_info | to yaml)---\n\n# ($title)"
+ }
+} # -> string
+
+# +-----------------------------+
+# | File Manipulation Functions |
+# +-----------------------------+
+
+def list_notes [--dir: string] {
+ return ((
+ ls ($dir | path expand)
+ | where type == file
+ | get name
+ ) | par-each {
+ |note_path|
+ let frontmatter = parse_frontmatter $note_path
+ if ($frontmatter != null) {
+ return {
+ title: (try {$frontmatter.title})
+ path: $note_path
+ tags: (try {$frontmatter.tags})
+ date: (try {$frontmatter.date})
+ lang: (try {$frontmatter.lang})
+ }
+ }
+ })
+} # -> table
+
+def parse_frontmatter [path: string] {
+ let frontmatter = try {
+ open ($path | path expand)
+ | split row "---"
+ | get 1
+ | from yaml
+ }
+ if ($frontmatter == null) {
+ let title = try {
+ open ($path | path expand)
+ | split row "#"
+ | get 1
+ | split row "\n"
+ | get 0
+ | str trim
+ }
+ return {title: $title}
+ }
+ return $frontmatter
+} # -> record
diff --git a/home-manager/features/cli/shells/nushell/completion.nu b/home-manager/features/cli/shells/nushell/completion.nu
new file mode 100644
index 0000000..b25d387
--- /dev/null
+++ b/home-manager/features/cli/shells/nushell/completion.nu
@@ -0,0 +1,17 @@
+# Carapace Autocomplete
+let carapace_completer = {|spans|
+ carapace $spans.0 nushell ...$spans | from json
+}
+$env.config = {
+ completions: {
+ case_sensitive: false
+ quick: true
+ partial: true
+ algorithm: fuzzy
+ external: {
+ enable: true
+ max_results: 100
+ completer: $carapace_completer
+ }
+ }
+}
diff --git a/home-manager/features/cli/shells/nushell/default.nix b/home-manager/features/cli/shells/nushell/default.nix
new file mode 100644
index 0000000..7561fb1
--- /dev/null
+++ b/home-manager/features/cli/shells/nushell/default.nix
@@ -0,0 +1,109 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ cfg = config.features.cli.shells.nushell;
+in {
+ options.features.cli.shells.nushell.enable = lib.mkEnableOption "nushell";
+ config = lib.mkIf cfg.enable {
+ home.packages = with pkgs; [
+ television
+ gitprompt-rs
+ ];
+ programs.nushell = {
+ enable = true;
+ plugins = with pkgs.nushellPlugins; [
+ gstat
+ ];
+ shellAliases = {
+ "nix-shell" = "nix-shell --command 'SHELL=nu nu'";
+ "cd" = "z";
+ "ze" = "zellij";
+ "lg" = "lazygit";
+ "bk" = "cd $env.OLDPWD";
+ "fg" = "job unfreeze";
+ };
+ configFile.text =
+ /*
+ nu
+ */
+ ''
+ # Source modularized configs.
+ source ${./prompt.nu}
+ source ${./completion.nu}
+
+ # General Config
+ $env.config = {
+ show_banner: false
+ edit_mode: 'emacs'
+
+ history: {
+ isolation: true # Isolate the history of each nushell session
+ file_format: sqlite # Required for isolation
+ }
+ }
+ $env.editor = "hx"
+
+ # go should use a hidden directory
+ $env.gopath = "${config.home.homeDirectory}/.go"
+
+ # Use direnv if present.
+ { ||
+ if (which direnv | is-empty) {
+ return
+ }
+ direnv export json | from json | default {} | load-env
+
+ }
+
+ # define a function to initialize a direnv project
+ def projinit [path?: string] { # this code sucks but I'm tired of working on it
+ mut path = $path
+ if ($path == null) {
+ $path = "./"
+ }
+ let path = $path | path expand
+ let template_path = "${./direnv-project-template}" | path expand
+ let template_files = ls -a $template_path | get name
+ $template_files | each {|item| cp $item $path}
+ ls -a $path | get name | where {|name| $template_files | str contains ($name | path basename) | any {}} | each {|name| chmod +w $name}
+ if (try {git rev-parse --is-inside-work-tree e> /dev/null}) != null {
+ direnv allow
+ } else {
+ # git init
+ direnv allow
+ }
+ # git add $"($path)/."
+ # git commit -m "initialized"
+ }
+
+ # Quickly create a nix shell.
+ def qs [...packages] {
+ if $packages == [] {
+ print "Please use a package name."
+ return
+ }
+ let packages_string = $packages
+ | each {|package| return $"nixpkgs#($package) "}
+ | str join
+ | str trim
+ nu -c $"nix shell ($packages_string)"
+ }
+
+ # Quickly run a nix package.
+ def qr --wrapped [package: string ...arguments] {
+ nix run $"nixpkgs#($package)" -- ($arguments | str join " ")
+ }
+ '';
+ };
+ programs.zoxide.enable = true;
+ programs.carapace.enable = true;
+ programs.direnv = {
+ enable = true;
+ nix-direnv.enable = true;
+ silent = true;
+ };
+ };
+}
diff --git a/home-manager/features/cli/shells/nushell/direnv-project-template/.envrc b/home-manager/features/cli/shells/nushell/direnv-project-template/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/home-manager/features/cli/shells/nushell/direnv-project-template/.envrc
@@ -0,0 +1 @@
+use flake
diff --git a/home-manager/features/cli/shells/nushell/direnv-project-template/.gitignore b/home-manager/features/cli/shells/nushell/direnv-project-template/.gitignore
new file mode 100644
index 0000000..92b2793
--- /dev/null
+++ b/home-manager/features/cli/shells/nushell/direnv-project-template/.gitignore
@@ -0,0 +1 @@
+.direnv
diff --git a/home-manager/features/cli/shells/nushell/direnv-project-template/flake.nix b/home-manager/features/cli/shells/nushell/direnv-project-template/flake.nix
new file mode 100644
index 0000000..4bab14a
--- /dev/null
+++ b/home-manager/features/cli/shells/nushell/direnv-project-template/flake.nix
@@ -0,0 +1,29 @@
+{
+ description = "Project flake";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+ systems.url = "github:nix-systems/default";
+ flake-utils = {
+ url = "github:numtide/flake-utils";
+ inputs.systems.follows = "systems";
+ };
+ };
+
+ outputs = {
+ nixpkgs,
+ flake-utils,
+ ...
+ }:
+ flake-utils.lib.eachDefaultSystem (
+ system: let
+ pkgs = nixpkgs.legacyPackages.${system};
+ in {
+ devShells.default = pkgs.mkShell {
+ packages = with pkgs; [
+ hello
+ ];
+ };
+ }
+ );
+}
diff --git a/home-manager/features/cli/shells/nushell/prompt.nu b/home-manager/features/cli/shells/nushell/prompt.nu
new file mode 100644
index 0000000..cfdd478
--- /dev/null
+++ b/home-manager/features/cli/shells/nushell/prompt.nu
@@ -0,0 +1,97 @@
+# +---------------+
+# | Prompt Config |
+# +---------------+
+
+# define segmants
+def path_segment [] {
+ let current_dir = pwd
+ let truncated_current_dir = $current_dir
+ return (pwd | str replace $env.home '~')
+}
+def git_segment [] {
+ return (gitprompt-rs)
+}
+let do_newline = false # whether to do the newline thing
+$env.PROMPT_COMMAND = {||
+ # add a newline at the beginning if it isn't the first prompt
+ mut newline = ""
+ if ($env.CMD_DURATION_MS != '0823') and $do_newline {
+ $newline = "\n"
+ }
+ # define the prompt
+ return $"($newline)(ansi white) ╭ (ansi green_bold)(path_segment)(ansi reset) (git_segment)\n "
+}
+
+# remove right prompt section
+$env.PROMPT_COMMAND_RIGHT = { "" }
+
+# set default prompt indicator
+$env.PROMPT_INDICATOR = $'(ansi white)╰ (ansi red_bold)> '
+# $env.TRANSIENT_PROMPT_INDICATOR = $' (ansi red_bold)> '
+$env.PROMPT_MULTILINE_INDICATOR = " : "
+
+# change prompt to a lambda if in a nix shell
+let in_nix_shell = $env.path | str contains "/nix/store" | any {|el| $el}
+if $in_nix_shell {
+ $env.PROMPT_INDICATOR = $'(ansi white)╰ (ansi red_bold)λ '
+}
+
+# replace vi insert and normal mode prompt indicators with cursor changes
+$env.PROMPT_INDICATOR_VI_NORMAL = $env.PROMPT_INDICATOR
+$env.PROMPT_INDICATOR_VI_INSERT = $env.PROMPT_INDICATOR
+$env.config.cursor_shape.vi_insert = "line"
+$env.config.cursor_shape.vi_normal = "block"
+
+$env.config.cursor_shape.emacs = "line"
+
+# customize menus to match
+$env.config.menus = [
+ {
+ name: help_menu
+ only_buffer_difference: true # Search is done on the text written after activating the menu
+ marker: $env.PROMPT_INDICATOR # Indicator that appears with the menu is active
+ type: {
+ layout: description # Type of menu
+ columns: 4 # Number of columns where the options are displayed
+ col_width: 20 # Optional value. If missing all the screen width is used to calculate column width
+ col_padding: 2 # Padding between columns
+ selection_rows: 4 # Number of rows allowed to display found options
+ description_rows: 10 # Number of rows allowed to display command description
+ }
+ style: {
+ text: green # Text style
+ selected_text: green_reverse # Text style for selected option
+ description_text: yellow # Text style for description
+ }
+ }
+ {
+ name: completion_menu
+ only_buffer_difference: false # Search is done on the text written after activating the menu
+ marker: $env.PROMPT_INDICATOR # Indicator that appears with the menu is active
+ type: {
+ layout: columnar # Type of menu
+ columns: 4 # Number of columns where the options are displayed
+ col_width: 20 # Optional value. If missing all the screen width is used to calculate column width
+ col_padding: 2 # Padding between columns
+ }
+ style: {
+ text: green # Text style
+ selected_text: green_reverse # Text style for selected option
+ description_text: yellow # Text style for description
+ }
+ }
+ {
+ name: history_menu
+ only_buffer_difference: true # Search is done on the text written after activating the menu
+ marker: $env.PROMPT_INDICATOR # Indicator that appears with the menu is active
+ type: {
+ layout: list # Type of menu
+ page_size: 10 # Number of entries that will presented when activating the menu
+ }
+ style: {
+ text: green # Text style
+ selected_text: green_reverse # Text style for selected option
+ description_text: yellow # Text style for description
+ }
+ }
+]
diff --git a/home-manager/features/cli/utils/git.nix b/home-manager/features/cli/utils/git.nix
new file mode 100644
index 0000000..b827d7b
--- /dev/null
+++ b/home-manager/features/cli/utils/git.nix
@@ -0,0 +1,16 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.features.cli.utils.git;
+in {
+ options.features.cli.utils.git.enable = lib.mkEnableOption "git";
+ config = lib.mkIf cfg.enable {
+ programs.git = {
+ enable = true;
+ userEmail = "triethylammonium@pm.me";
+ userName = "triethyl";
+ };
+ };
+}
diff --git a/home-manager/features/cli/utils/pandoc.nix b/home-manager/features/cli/utils/pandoc.nix
new file mode 100644
index 0000000..899bd4b
--- /dev/null
+++ b/home-manager/features/cli/utils/pandoc.nix
@@ -0,0 +1,13 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.cli.utils.pandoc;
+in {
+ options.features.cli.utils.pandoc.enable = lib.mkEnableOption "pandoc";
+ config = lib.mkIf cfg.enable {
+ programs.pandoc = {
+ enable = true;
+ };
+ home.packages = with pkgs; [
+ texliveSmall
+ ];
+ };
+}
diff --git a/home-manager/features/cli/utils/ssh.nix b/home-manager/features/cli/utils/ssh.nix
new file mode 100644
index 0000000..f10d0b2
--- /dev/null
+++ b/home-manager/features/cli/utils/ssh.nix
@@ -0,0 +1,20 @@
+{ config, lib, ... }: let
+ cfg = config.features.cli.utils.ssh;
+in {
+ options.features.cli.utils.ssh.enable = lib.mkEnableOption "ssh";
+ config = lib.mkIf cfg.enable {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ "culsans.site" = {
+ hostname = "culsans.site";
+ user = "server";
+ port = 2200;
+ };
+ "git.culsans.site" = {
+ hostname = "culsans.site";
+ };
+ };
+ };
+ };
+}
diff --git a/home-manager/features/global/home-manager.nix b/home-manager/features/global/home-manager.nix
new file mode 100644
index 0000000..4be0d07
--- /dev/null
+++ b/home-manager/features/global/home-manager.nix
@@ -0,0 +1,3 @@
+{ ... }: {
+ programs.home-manager.enable = true;
+}
diff --git a/home-manager/features/global/nixpkgs.nix b/home-manager/features/global/nixpkgs.nix
new file mode 100644
index 0000000..b19d5e0
--- /dev/null
+++ b/home-manager/features/global/nixpkgs.nix
@@ -0,0 +1,3 @@
+{...}: {
+ nixpkgs.config.allowUnfree = true;
+}
diff --git a/home-manager/features/gui/apps/foot.nix b/home-manager/features/gui/apps/foot.nix
new file mode 100644
index 0000000..321e7e8
--- /dev/null
+++ b/home-manager/features/gui/apps/foot.nix
@@ -0,0 +1,18 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ cfg = config.features.gui.apps.foot;
+in {
+ options.features.gui.apps.foot.enable = lib.mkEnableOption "foot";
+ config = lib.mkIf cfg.enable {
+ programs.foot = {
+ enable = true;
+ settings = {
+ main.pad = "0x4";
+ };
+ };
+ };
+}
diff --git a/home-manager/features/gui/apps/librewolf.nix b/home-manager/features/gui/apps/librewolf.nix
new file mode 100644
index 0000000..fc6c2c4
--- /dev/null
+++ b/home-manager/features/gui/apps/librewolf.nix
@@ -0,0 +1,19 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ cfg = config.features.gui.apps.librewolf;
+in {
+ options.features.gui.apps.librewolf.enable = lib.mkEnableOption "librewolf";
+ config = lib.mkIf cfg.enable {
+ # programs.librewolf = {
+ # enable = true;
+ # settings = {
+ # "browser.tabs.inTitlebar" = 0;
+ # };
+ # };
+ home.packages = [ pkgs.librewolf-bin ];
+ };
+}
diff --git a/home-manager/features/gui/apps/mpv.nix b/home-manager/features/gui/apps/mpv.nix
new file mode 100644
index 0000000..562d151
--- /dev/null
+++ b/home-manager/features/gui/apps/mpv.nix
@@ -0,0 +1,28 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.gui.apps.mpv;
+in {
+ options.features.gui.apps.mpv.enable = lib.mkEnableOption "mpv";
+ config = lib.mkIf cfg.enable {
+ programs.mpv = {
+ enable = true;
+ config = {
+ # Change youtube downloader to yt-dlp for faster downloads.
+ script-opts = "ytdl_hook-ytdl_path=${lib.getExe pkgs.yt-dlp}";
+ # Download videos at 720p or lower.
+ ytdl-format = "bestvideo[height<=720]+bestaudio/best[height<=720]";
+
+ save-position-on-quit = false; # makes mpv audio only when true?
+
+ osd-bar = false;
+ };
+ bindings = {
+ "tab" = "script-binding uosc/toggle-ui";
+ };
+ scripts = with pkgs.mpvScripts; [
+ uosc
+ thumbfast
+ sponsorblock
+ ];
+ };
+ };
+}
diff --git a/home-manager/features/gui/apps/obs.nix b/home-manager/features/gui/apps/obs.nix
new file mode 100644
index 0000000..916f11e
--- /dev/null
+++ b/home-manager/features/gui/apps/obs.nix
@@ -0,0 +1,10 @@
+{ config, lib, ... }: let
+ cfg = config.features.gui.apps.obs;
+in {
+ options.features.gui.apps.obs.enable = lib.mkEnableOption "obs";
+ config = lib.mkIf cfg.enable {
+ programs.obs-studio = {
+ enable = true;
+ };
+ };
+}
diff --git a/home-manager/features/gui/apps/qutebrowser/default.nix b/home-manager/features/gui/apps/qutebrowser/default.nix
new file mode 100644
index 0000000..e12c9f3
--- /dev/null
+++ b/home-manager/features/gui/apps/qutebrowser/default.nix
@@ -0,0 +1,81 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.gui.apps.qutebrowser;
+in {
+ options.features.gui.apps.qutebrowser.enable = lib.mkEnableOption "qutebrowser";
+ config = lib.mkIf cfg.enable {
+ programs.qutebrowser = {
+ enable = true;
+ settings = {
+ content = {
+ autoplay = false;
+ tls.certificate_errors = "ask-block-thirdparty";
+ };
+ scrolling.bar = "never";
+ window.transparent = true;
+ keyhint.delay = 0;
+ tabs = {
+ position = "left";
+ width = "10%";
+ };
+ url = {
+ default_page = "https://web.tabliss.io";
+ start_pages = "https://web.tabliss.io";
+ };
+ input.insert_mode.auto_load = true;
+ };
+ keyBindings = {
+ normal = {
+ # Tab Movement Keys
+ "<Ctrl-j>" = "tab-move +";
+ "<Ctrl-k>" = "tab-move -";
+
+ # Universal Scrolling Keys
+ "<Alt-j>" = "scroll-px 0 50";
+ "<Alt-k>" = "scroll-px 0 -50";
+
+ # Open Tab Relatively
+ "<Ctrl-o>" = "cmd-set-text -s :open -tr";
+
+ # Move Tab to Another Window
+ "gc" = "cmd-set-text -s :tab-give";
+
+ # Hide UI
+ "z" = lib.mkMerge [
+ "config-cycle tabs.show never always"
+ "config-cycle statusbar.show in-mode always"
+ "config-cycle scrolling.bar never always"
+ ];
+ };
+ };
+ searchEngines = {
+ # Default Search Engine
+ DEFAULT = "https://search.brave.com/search?q={}";
+
+ # General Search Engines
+ g = "https://www.google.com/search?q={}";
+ b = "https://www.bing.com/search?q={}";
+
+ # Other Search Engines
+ w = "https://en.wikipedia.org/wiki/Special:Search?search={}&amp;go=Go&amp;ns0=1";
+ y = "https://youtube.com/results?search_query={}";
+ t = "https://www.wordreference.com/es/translation.asp?tranword={}";
+ p = "https://thangs.com/search/{}?scope=all";
+
+ # Nix Search Engines
+ n = "https://mynixos.com/search?q={}";
+ nw = "https://wiki.nixos.org/index.php?search={}";
+ np = "https://search.nixos.org/packages?channel=unstable&from=0&size=50&sort=relevance&type=packages&query={}";
+ no = "https://search.nixos.org/options?channel=unstable&size=50&sort=relevance&type=packages&query={}";
+ nh = "https://home-manager-options.extranix.com/?query={}&release=master";
+ };
+ greasemonkey = let
+ mkGmScript = name: ( pkgs.writeText "${name}.js" (builtins.readFile ./scripts/${name}.js) );
+ in [
+ (mkGmScript "yt-ad-skip")
+ (mkGmScript "yt-sponsor-skip")
+ (mkGmScript "yt-shorts-blocker")
+ (mkGmScript "yt-dislike-viewer")
+ ];
+ };
+ };
+}
diff --git a/home-manager/features/gui/apps/qutebrowser/scripts/yt-ad-skip.js b/home-manager/features/gui/apps/qutebrowser/scripts/yt-ad-skip.js
new file mode 100644
index 0000000..56336df
--- /dev/null
+++ b/home-manager/features/gui/apps/qutebrowser/scripts/yt-ad-skip.js
@@ -0,0 +1,29 @@
+// ==UserScript==
+// @name Youtube Ad Skip
+// @version 0.0.7
+// @description Make Youtube more tolerable by automatically skipping ads
+// @author Adcott
+// @match *://*.youtube.com/*
+// ==/UserScript==
+
+GM_addStyle(`
+#player-ads,
+.adDisplay,
+.ad-container,
+.ytd-display-ad-renderer,
+.video-ads,
+ytd-rich-item-renderer:has(ytd-ad-slot-renderer),
+ytd-ad-slot-renderer,
+#masthead-ad,
+*[class^="ytd-ad-"],
+#panels.ytd-watch-flexy {
+ display: none !important;
+}`);
+
+document.addEventListener('load', () => {
+ let ad = document.querySelector('.ad-showing:has(.ytp-ad-persistent-progress-bar-container) video');
+ let skipButton = document.querySelector('.ytp-ad-skip-button');
+
+ if (ad) ad.currentTime = 99999;
+ if (skipButton) skipButton.click();
+}, true);
diff --git a/home-manager/features/gui/apps/qutebrowser/scripts/yt-dislike-viewer.js b/home-manager/features/gui/apps/qutebrowser/scripts/yt-dislike-viewer.js
new file mode 100644
index 0000000..50f3eff
--- /dev/null
+++ b/home-manager/features/gui/apps/qutebrowser/scripts/yt-dislike-viewer.js
@@ -0,0 +1,704 @@
+// ==UserScript==
+// @name Return YouTube Dislike
+// @namespace https://www.returnyoutubedislike.com/
+// @homepage https://www.returnyoutubedislike.com/
+// @version 3.1.5
+// @encoding utf-8
+// @description Return of the YouTube Dislike, Based off https://www.returnyoutubedislike.com/
+// @icon https://github.com/Anarios/return-youtube-dislike/raw/main/Icons/Return%20Youtube%20Dislike%20-%20Transparent.png
+// @author Anarios & JRWR
+// @match *://*.youtube.com/*
+// @exclude *://music.youtube.com/*
+// @exclude *://*.music.youtube.com/*
+// @compatible chrome
+// @compatible firefox
+// @compatible opera
+// @compatible safari
+// @compatible edge
+// @grant GM.xmlHttpRequest
+// @connect youtube.com
+// @grant GM_addStyle
+// @run-at document-end
+// @downloadURL https://update.greasyfork.org/scripts/436115/Return%20YouTube%20Dislike.user.js
+// @updateURL https://update.greasyfork.org/scripts/436115/Return%20YouTube%20Dislike.meta.js
+// ==/UserScript==
+
+const extConfig = {
+ // BEGIN USER OPTIONS
+ // You may change the following variables to allowed values listed in the corresponding brackets (* means default). Keep the style and keywords intact.
+ showUpdatePopup: false, // [true, false*] Show a popup tab after extension update (See what's new)
+ disableVoteSubmission: false, // [true, false*] Disable like/dislike submission (Stops counting your likes and dislikes)
+ disableLogging: true, // [true*, false] Disable Logging API Response in JavaScript Console.
+ coloredThumbs: false, // [true, false*] Colorize thumbs (Use custom colors for thumb icons)
+ coloredBar: false, // [true, false*] Colorize ratio bar (Use custom colors for ratio bar)
+ colorTheme: "classic", // [classic*, accessible, neon] Color theme (red/green, blue/yellow, pink/cyan)
+ numberDisplayFormat: "compactShort", // [compactShort*, compactLong, standard] Number format (For non-English locale users, you may be able to improve appearance with a different option. Please file a feature request if your locale is not covered)
+ numberDisplayRoundDown: true, // [true*, false] Round down numbers (Show rounded down numbers)
+ tooltipPercentageMode: "none", // [none*, dash_like, dash_dislike, both, only_like, only_dislike] Mode of showing percentage in like/dislike bar tooltip.
+ numberDisplayReformatLikes: false, // [true, false*] Re-format like numbers (Make likes and dislikes format consistent)
+ rateBarEnabled: false, // [true, false*] Enables ratio bar under like/dislike buttons
+ // END USER OPTIONS
+};
+
+const LIKED_STATE = "LIKED_STATE";
+const DISLIKED_STATE = "DISLIKED_STATE";
+const NEUTRAL_STATE = "NEUTRAL_STATE";
+let previousState = 3; //1=LIKED, 2=DISLIKED, 3=NEUTRAL
+let likesvalue = 0;
+let dislikesvalue = 0;
+let preNavigateLikeButton = null;
+
+let isMobile = location.hostname == "m.youtube.com";
+let isShorts = () => location.pathname.startsWith("/shorts");
+let mobileDislikes = 0;
+function cLog(text, subtext = "") {
+ if (!extConfig.disableLogging) {
+ subtext = subtext.trim() === "" ? "" : `(${subtext})`;
+ console.log(`[Return YouTube Dislikes] ${text} ${subtext}`);
+ }
+}
+
+function isInViewport(element) {
+ const rect = element.getBoundingClientRect();
+ const height = innerHeight || document.documentElement.clientHeight;
+ const width = innerWidth || document.documentElement.clientWidth;
+ return (
+ // When short (channel) is ignored, the element (like/dislike AND short itself) is
+ // hidden with a 0 DOMRect. In this case, consider it outside of Viewport
+ !(rect.top == 0 && rect.left == 0 && rect.bottom == 0 && rect.right == 0) &&
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= height &&
+ rect.right <= width
+ );
+}
+
+function getButtons() {
+ if (isShorts()) {
+ let elements = document.querySelectorAll(
+ isMobile ? "ytm-like-button-renderer" : "#like-button > ytd-like-button-renderer",
+ );
+ for (let element of elements) {
+ if (isInViewport(element)) {
+ return element;
+ }
+ }
+ }
+ if (isMobile) {
+ return (
+ document.querySelector(".slim-video-action-bar-actions .segmented-buttons") ??
+ document.querySelector(".slim-video-action-bar-actions")
+ );
+ }
+ if (document.getElementById("menu-container")?.offsetParent === null) {
+ return (
+ document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div") ??
+ document.querySelector("ytd-menu-renderer.ytd-video-primary-info-renderer > div")
+ );
+ } else {
+ return document.getElementById("menu-container")?.querySelector("#top-level-buttons-computed");
+ }
+}
+
+function getDislikeButton() {
+ if (getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER") {
+ if (getButtons().children[0].children[1] === undefined) {
+ return document.querySelector("#segmented-dislike-button");
+ } else {
+ return getButtons().children[0].children[1];
+ }
+ } else {
+ if (getButtons().querySelector("segmented-like-dislike-button-view-model")) {
+ const dislikeViewModel = getButtons().querySelector("dislike-button-view-model");
+ if (!dislikeViewModel) cLog("Dislike button wasn't added to DOM yet...");
+ return dislikeViewModel;
+ } else {
+ return getButtons().children[1];
+ }
+ }
+}
+
+function getLikeButton() {
+ return getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER"
+ ? document.querySelector("#segmented-like-button") !== null
+ ? document.querySelector("#segmented-like-button")
+ : getButtons().children[0].children[0]
+ : getButtons().querySelector("like-button-view-model") ?? getButtons().children[0];
+}
+
+function getLikeTextContainer() {
+ return (
+ getLikeButton().querySelector("#text") ??
+ getLikeButton().getElementsByTagName("yt-formatted-string")[0] ??
+ getLikeButton().querySelector("span[role='text']")
+ );
+}
+
+function getDislikeTextContainer() {
+ const dislikeButton = getDislikeButton();
+ let result =
+ dislikeButton?.querySelector("#text") ??
+ dislikeButton?.getElementsByTagName("yt-formatted-string")[0] ??
+ dislikeButton?.querySelector("span[role='text']");
+ if (result === null) {
+ let textSpan = document.createElement("span");
+ textSpan.id = "text";
+ textSpan.style.marginLeft = "6px";
+ dislikeButton?.querySelector("button").appendChild(textSpan);
+ if (dislikeButton) dislikeButton.querySelector("button").style.width = "auto";
+ result = textSpan;
+ }
+ return result;
+}
+
+function createObserver(options, callback) {
+ const observerWrapper = new Object();
+ observerWrapper.options = options;
+ observerWrapper.observer = new MutationObserver(callback);
+ observerWrapper.observe = function (element) {
+ this.observer.observe(element, this.options);
+ };
+ observerWrapper.disconnect = function () {
+ this.observer.disconnect();
+ };
+ return observerWrapper;
+}
+
+let shortsObserver = null;
+
+if (isShorts() && !shortsObserver) {
+ cLog("Initializing shorts mutation observer");
+ shortsObserver = createObserver(
+ {
+ attributes: true,
+ },
+ (mutationList) => {
+ mutationList.forEach((mutation) => {
+ if (
+ mutation.type === "attributes" &&
+ mutation.target.nodeName === "TP-YT-PAPER-BUTTON" &&
+ mutation.target.id === "button"
+ ) {
+ cLog("Short thumb button status changed");
+ if (mutation.target.getAttribute("aria-pressed") === "true") {
+ mutation.target.style.color =
+ mutation.target.parentElement.parentElement.id === "like-button"
+ ? getColorFromTheme(true)
+ : getColorFromTheme(false);
+ } else {
+ mutation.target.style.color = "unset";
+ }
+ return;
+ }
+ cLog("Unexpected mutation observer event: " + mutation.target + mutation.type);
+ });
+ },
+ );
+}
+
+function isVideoLiked() {
+ if (isMobile) {
+ return getLikeButton().querySelector("button").getAttribute("aria-label") == "true";
+ }
+ return getLikeButton().classList.contains("style-default-active");
+}
+
+function isVideoDisliked() {
+ if (isMobile) {
+ return getDislikeButton()?.querySelector("button").getAttribute("aria-label") == "true";
+ }
+ return getDislikeButton()?.classList.contains("style-default-active");
+}
+
+function isVideoNotLiked() {
+ if (isMobile) {
+ return !isVideoLiked();
+ }
+ return getLikeButton().classList.contains("style-text");
+}
+
+function isVideoNotDisliked() {
+ if (isMobile) {
+ return !isVideoDisliked();
+ }
+ return getDislikeButton()?.classList.contains("style-text");
+}
+
+function checkForUserAvatarButton() {
+ if (isMobile) {
+ return;
+ }
+ if (document.querySelector("#avatar-btn")) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+function getState() {
+ if (isVideoLiked()) {
+ return LIKED_STATE;
+ }
+ if (isVideoDisliked()) {
+ return DISLIKED_STATE;
+ }
+ return NEUTRAL_STATE;
+}
+
+function setLikes(likesCount) {
+ if (isMobile) {
+ getButtons().children[0].querySelector(".button-renderer-text").innerText = likesCount;
+ return;
+ }
+ getLikeTextContainer().innerText = likesCount;
+}
+
+function setDislikes(dislikesCount) {
+ if (isMobile) {
+ mobileDislikes = dislikesCount;
+ return;
+ }
+
+ const _container = getDislikeTextContainer();
+ _container?.removeAttribute("is-empty");
+ if (_container?.innerText !== dislikesCount) {
+ _container.innerText = dislikesCount;
+ }
+}
+
+function getLikeCountFromButton() {
+ try {
+ if (isShorts()) {
+ //Youtube Shorts don't work with this query. It's not necessary; we can skip it and still see the results.
+ //It should be possible to fix this function, but it's not critical to showing the dislike count.
+ return false;
+ }
+ let likeButton =
+ getLikeButton().querySelector("yt-formatted-string#text") ?? getLikeButton().querySelector("button");
+
+ let likesStr = likeButton.getAttribute("aria-label").replace(/\D/g, "");
+ return likesStr.length > 0 ? parseInt(likesStr) : false;
+ } catch {
+ return false;
+ }
+}
+
+(typeof GM_addStyle != "undefined"
+ ? GM_addStyle
+ : (styles) => {
+ let styleNode = document.createElement("style");
+ styleNode.type = "text/css";
+ styleNode.innerText = styles;
+ document.head.appendChild(styleNode);
+ })(`
+ #return-youtube-dislike-bar-container {
+ background: var(--yt-spec-icon-disabled);
+ border-radius: 2px;
+ }
+
+ #return-youtube-dislike-bar {
+ background: var(--yt-spec-text-primary);
+ border-radius: 2px;
+ transition: all 0.15s ease-in-out;
+ }
+
+ .ryd-tooltip {
+ position: absolute;
+ display: block;
+ height: 2px;
+ bottom: -10px;
+ }
+
+ .ryd-tooltip-bar-container {
+ width: 100%;
+ height: 2px;
+ position: absolute;
+ padding-top: 6px;
+ padding-bottom: 12px;
+ top: -6px;
+ }
+
+ ytd-menu-renderer.ytd-watch-metadata {
+ overflow-y: visible !important;
+ }
+
+ #top-level-buttons-computed {
+ position: relative !important;
+ }
+ `);
+
+function createRateBar(likes, dislikes) {
+ if (isMobile || !extConfig.rateBarEnabled) {
+ return;
+ }
+ let rateBar = document.getElementById("return-youtube-dislike-bar-container");
+
+ const widthPx = getLikeButton().clientWidth + (getDislikeButton()?.clientWidth ?? 52);
+
+ const widthPercent = likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
+
+ var likePercentage = parseFloat(widthPercent.toFixed(1));
+ const dislikePercentage = (100 - likePercentage).toLocaleString();
+ likePercentage = likePercentage.toLocaleString();
+
+ var tooltipInnerHTML;
+ switch (extConfig.tooltipPercentageMode) {
+ case "dash_like":
+ tooltipInnerHTML = `${likes.toLocaleString()}&nbsp;/&nbsp;${dislikes.toLocaleString()}&nbsp;&nbsp;-&nbsp;&nbsp;${likePercentage}%`;
+ break;
+ case "dash_dislike":
+ tooltipInnerHTML = `${likes.toLocaleString()}&nbsp;/&nbsp;${dislikes.toLocaleString()}&nbsp;&nbsp;-&nbsp;&nbsp;${dislikePercentage}%`;
+ break;
+ case "both":
+ tooltipInnerHTML = `${likePercentage}%&nbsp;/&nbsp;${dislikePercentage}%`;
+ break;
+ case "only_like":
+ tooltipInnerHTML = `${likePercentage}%`;
+ break;
+ case "only_dislike":
+ tooltipInnerHTML = `${dislikePercentage}%`;
+ break;
+ default:
+ tooltipInnerHTML = `${likes.toLocaleString()}&nbsp;/&nbsp;${dislikes.toLocaleString()}`;
+ }
+
+ if (!rateBar && !isMobile) {
+ let colorLikeStyle = "";
+ let colorDislikeStyle = "";
+ if (extConfig.coloredBar) {
+ colorLikeStyle = "; background-color: " + getColorFromTheme(true);
+ colorDislikeStyle = "; background-color: " + getColorFromTheme(false);
+ }
+
+ getButtons().insertAdjacentHTML(
+ "beforeend",
+ `
+ <div class="ryd-tooltip" style="width: ${widthPx}px">
+ <div class="ryd-tooltip-bar-container">
+ <div
+ id="return-youtube-dislike-bar-container"
+ style="width: 100%; height: 2px;${colorDislikeStyle}"
+ >
+ <div
+ id="return-youtube-dislike-bar"
+ style="width: ${widthPercent}%; height: 100%${colorDislikeStyle}"
+ ></div>
+ </div>
+ </div>
+ <tp-yt-paper-tooltip position="top" id="ryd-dislike-tooltip" class="style-scope ytd-sentiment-bar-renderer" role="tooltip" tabindex="-1">
+ <!--css-build:shady-->${tooltipInnerHTML}
+ </tp-yt-paper-tooltip>
+ </div>
+`,
+ );
+ let descriptionAndActionsElement = document.getElementById("top-row");
+ descriptionAndActionsElement.style.borderBottom = "1px solid var(--yt-spec-10-percent-layer)";
+ descriptionAndActionsElement.style.paddingBottom = "10px";
+ } else {
+ document.querySelector(".ryd-tooltip").style.width = widthPx + "px";
+ document.getElementById("return-youtube-dislike-bar").style.width = widthPercent + "%";
+
+ if (extConfig.coloredBar) {
+ document.getElementById("return-youtube-dislike-bar-container").style.backgroundColor = getColorFromTheme(false);
+ document.getElementById("return-youtube-dislike-bar").style.backgroundColor = getColorFromTheme(true);
+ }
+ }
+}
+
+function setState() {
+ cLog("Fetching votes...");
+ let statsSet = false;
+
+ fetch(`https://returnyoutubedislikeapi.com/votes?videoId=${getVideoId()}`).then((response) => {
+ response.json().then((json) => {
+ if (json && !("traceId" in response) && !statsSet) {
+ const { dislikes, likes } = json;
+ cLog(`Received count: ${dislikes}`);
+ likesvalue = likes;
+ dislikesvalue = dislikes;
+ setDislikes(numberFormat(dislikes));
+ if (extConfig.numberDisplayReformatLikes === true) {
+ const nativeLikes = getLikeCountFromButton();
+ if (nativeLikes !== false) {
+ setLikes(numberFormat(nativeLikes));
+ }
+ }
+ createRateBar(likes, dislikes);
+ if (extConfig.coloredThumbs === true) {
+ const dislikeButton = getDislikeButton();
+ if (isShorts()) {
+ // for shorts, leave deactived buttons in default color
+ const shortLikeButton = getLikeButton().querySelector("tp-yt-paper-button#button");
+ const shortDislikeButton = dislikeButton?.querySelector("tp-yt-paper-button#button");
+ if (shortLikeButton.getAttribute("aria-pressed") === "true") {
+ shortLikeButton.style.color = getColorFromTheme(true);
+ }
+ if (shortDislikeButton && shortDislikeButton.getAttribute("aria-pressed") === "true") {
+ shortDislikeButton.style.color = getColorFromTheme(false);
+ }
+ shortsObserver.observe(shortLikeButton);
+ shortsObserver.observe(shortDislikeButton);
+ } else {
+ getLikeButton().style.color = getColorFromTheme(true);
+ if (dislikeButton) dislikeButton.style.color = getColorFromTheme(false);
+ }
+ }
+ }
+ });
+ });
+}
+
+function updateDOMDislikes() {
+ setDislikes(numberFormat(dislikesvalue));
+ createRateBar(likesvalue, dislikesvalue);
+}
+
+function likeClicked() {
+ if (checkForUserAvatarButton() == true) {
+ if (previousState == 1) {
+ likesvalue--;
+ updateDOMDislikes();
+ previousState = 3;
+ } else if (previousState == 2) {
+ likesvalue++;
+ dislikesvalue--;
+ updateDOMDislikes();
+ previousState = 1;
+ } else if (previousState == 3) {
+ likesvalue++;
+ updateDOMDislikes();
+ previousState = 1;
+ }
+ if (extConfig.numberDisplayReformatLikes === true) {
+ const nativeLikes = getLikeCountFromButton();
+ if (nativeLikes !== false) {
+ setLikes(numberFormat(nativeLikes));
+ }
+ }
+ }
+}
+
+function dislikeClicked() {
+ if (checkForUserAvatarButton() == true) {
+ if (previousState == 3) {
+ dislikesvalue++;
+ updateDOMDislikes();
+ previousState = 2;
+ } else if (previousState == 2) {
+ dislikesvalue--;
+ updateDOMDislikes();
+ previousState = 3;
+ } else if (previousState == 1) {
+ likesvalue--;
+ dislikesvalue++;
+ updateDOMDislikes();
+ previousState = 2;
+ if (extConfig.numberDisplayReformatLikes === true) {
+ const nativeLikes = getLikeCountFromButton();
+ if (nativeLikes !== false) {
+ setLikes(numberFormat(nativeLikes));
+ }
+ }
+ }
+ }
+}
+
+function setInitialState() {
+ setState();
+}
+
+function getVideoId() {
+ const urlObject = new URL(window.location.href);
+ const pathname = urlObject.pathname;
+ if (pathname.startsWith("/clip")) {
+ return (document.querySelector("meta[itemprop='videoId']") || document.querySelector("meta[itemprop='identifier']")).content;
+ } else {
+ if (pathname.startsWith("/shorts")) {
+ return pathname.slice(8);
+ }
+ return urlObject.searchParams.get("v");
+ }
+}
+
+function isVideoLoaded() {
+ if (isMobile) {
+ return document.getElementById("player").getAttribute("loading") == "false";
+ }
+ const videoId = getVideoId();
+
+ return (
+ // desktop: spring 2024 UI
+ document.querySelector(`ytd-watch-grid[video-id='${videoId}']`) !== null ||
+ // desktop: older UI
+ document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null ||
+ // mobile: no video-id attribute
+ document.querySelector('#player[loading="false"]:not([hidden])') !== null
+ );
+}
+
+function roundDown(num) {
+ if (num < 1000) return num;
+ const int = Math.floor(Math.log10(num) - 2);
+ const decimal = int + (int % 3 ? 1 : 0);
+ const value = Math.floor(num / 10 ** decimal);
+ return value * 10 ** decimal;
+}
+
+function numberFormat(numberState) {
+ let numberDisplay;
+ if (extConfig.numberDisplayRoundDown === false) {
+ numberDisplay = numberState;
+ } else {
+ numberDisplay = roundDown(numberState);
+ }
+ return getNumberFormatter(extConfig.numberDisplayFormat).format(numberDisplay);
+}
+
+function getNumberFormatter(optionSelect) {
+ let userLocales;
+ if (document.documentElement.lang) {
+ userLocales = document.documentElement.lang;
+ } else if (navigator.language) {
+ userLocales = navigator.language;
+ } else {
+ try {
+ userLocales = new URL(
+ Array.from(document.querySelectorAll("head > link[rel='search']"))
+ ?.find((n) => n?.getAttribute("href")?.includes("?locale="))
+ ?.getAttribute("href"),
+ )?.searchParams?.get("locale");
+ } catch {
+ cLog("Cannot find browser locale. Use en as default for number formatting.");
+ userLocales = "en";
+ }
+ }
+
+ let formatterNotation;
+ let formatterCompactDisplay;
+ switch (optionSelect) {
+ case "compactLong":
+ formatterNotation = "compact";
+ formatterCompactDisplay = "long";
+ break;
+ case "standard":
+ formatterNotation = "standard";
+ formatterCompactDisplay = "short";
+ break;
+ case "compactShort":
+ default:
+ formatterNotation = "compact";
+ formatterCompactDisplay = "short";
+ }
+
+ const formatter = Intl.NumberFormat(userLocales, {
+ notation: formatterNotation,
+ compactDisplay: formatterCompactDisplay,
+ });
+ return formatter;
+}
+
+function getColorFromTheme(voteIsLike) {
+ let colorString;
+ switch (extConfig.colorTheme) {
+ case "accessible":
+ if (voteIsLike === true) {
+ colorString = "dodgerblue";
+ } else {
+ colorString = "gold";
+ }
+ break;
+ case "neon":
+ if (voteIsLike === true) {
+ colorString = "aqua";
+ } else {
+ colorString = "magenta";
+ }
+ break;
+ case "classic":
+ default:
+ if (voteIsLike === true) {
+ colorString = "lime";
+ } else {
+ colorString = "red";
+ }
+ }
+ return colorString;
+}
+
+let smartimationObserver = null;
+
+function setEventListeners(evt) {
+ let jsInitChecktimer;
+
+ function checkForJS_Finish() {
+ //console.log();
+ if (isShorts() || (getButtons()?.offsetParent && isVideoLoaded())) {
+ const buttons = getButtons();
+ const dislikeButton = getDislikeButton();
+
+ if (preNavigateLikeButton !== getLikeButton() && dislikeButton) {
+ cLog("Registering button listeners...");
+ try {
+ getLikeButton().addEventListener("click", likeClicked);
+ dislikeButton?.addEventListener("click", dislikeClicked);
+ getLikeButton().addEventListener("touchstart", likeClicked);
+ dislikeButton?.addEventListener("touchstart", dislikeClicked);
+ dislikeButton?.addEventListener("focusin", updateDOMDislikes);
+ dislikeButton?.addEventListener("focusout", updateDOMDislikes);
+ preNavigateLikeButton = getLikeButton();
+
+ if (!smartimationObserver) {
+ smartimationObserver = createObserver(
+ {
+ attributes: true,
+ subtree: true,
+ childList: true,
+ },
+ updateDOMDislikes,
+ );
+ smartimationObserver.container = null;
+ }
+
+ const smartimationContainer = buttons.querySelector("yt-smartimation");
+ if (smartimationContainer && smartimationObserver.container != smartimationContainer) {
+ cLog("Initializing smartimation mutation observer");
+ smartimationObserver.disconnect();
+ smartimationObserver.observe(smartimationContainer);
+ smartimationObserver.container = smartimationContainer;
+ }
+ } catch {
+ return;
+ } //Don't spam errors into the console
+ }
+ if (dislikeButton) {
+ setInitialState();
+ clearInterval(jsInitChecktimer);
+ }
+ }
+ }
+
+ cLog("Setting up...");
+ jsInitChecktimer = setInterval(checkForJS_Finish, 111);
+}
+
+(function () {
+ "use strict";
+ window.addEventListener("yt-navigate-finish", setEventListeners, true);
+ setEventListeners();
+})();
+if (isMobile) {
+ let originalPush = history.pushState;
+ history.pushState = function (...args) {
+ window.returnDislikeButtonlistenersSet = false;
+ setEventListeners(args[2]);
+ return originalPush.apply(history, args);
+ };
+ setInterval(() => {
+ const dislikeButton = getDislikeButton();
+ if (dislikeButton?.querySelector(".button-renderer-text") === null) {
+ getDislikeTextContainer().innerText = mobileDislikes;
+ } else {
+ if (dislikeButton) dislikeButton.querySelector(".button-renderer-text").innerText = mobileDislikes;
+ }
+ }, 1000);
+}
diff --git a/home-manager/features/gui/apps/qutebrowser/scripts/yt-shorts-blocker.js b/home-manager/features/gui/apps/qutebrowser/scripts/yt-shorts-blocker.js
new file mode 100644
index 0000000..383fec3
--- /dev/null
+++ b/home-manager/features/gui/apps/qutebrowser/scripts/yt-shorts-blocker.js
@@ -0,0 +1,23 @@
+// ==UserScript==
+// @name YouTube Shorts Blocker
+// @namespace http://tampermonkey.net/
+// @version 0.1.2
+// @description Blocks the YouTube shorts from appearing.
+// @author Aiden Charles
+// @license MIT
+// @match https://www.youtube.com/*
+// @require https://code.jquery.com/jquery-3.4.1.slim.min.js
+// @grant none
+// ==/UserScript==
+
+(function() {
+ console.log("YouTube Shorts blocker script is running!");
+
+ setInterval(function() {
+ $("ytd-reel-shelf-renderer").hide();
+ $("a[title='Shorts']").hide();
+ $('a[href^="/shorts/"]').closest('ytd-video-renderer').hide();
+ $('span:contains("Shorts")').closest('#content.ytd-rich-section-renderer').hide();
+ }, 1000);
+})();
+
diff --git a/home-manager/features/gui/apps/qutebrowser/scripts/yt-sponsor-skip.js b/home-manager/features/gui/apps/qutebrowser/scripts/yt-sponsor-skip.js
new file mode 100644
index 0000000..3779cbf
--- /dev/null
+++ b/home-manager/features/gui/apps/qutebrowser/scripts/yt-sponsor-skip.js
@@ -0,0 +1,51 @@
+// ==UserScript==
+// @name Sponsorblock
+// @version 1.1.0
+// @description Skip sponsor segments automatically
+// @author afreakk
+// @author vongaisberg
+// @match *://*.youtube.com/*
+// @exclude *://*.youtube.com/subscribe_embed?*
+// ==/UserScript==
+const delay = 1000;
+
+const tryFetchSkipSegments = (videoID) =>
+
+ fetch(`https://sponsor.ajay.app/api/skipSegments?videoID=${videoID}`)
+ .then((r) => r.json())
+ .then((rJson) =>
+ rJson.filter((a) => a.actionType === 'skip').map((a) => a.segment)
+ )
+ .catch(
+ (e) =>
+ console.log(
+ `Sponsorblock: failed fetching skipSegments for ${videoID}, reason: ${e}`
+ ) || []
+ );
+
+const skipSegments = async () => {
+ const videoID = new URL(document.location).searchParams.get('v');
+ if (!videoID) {
+ return;
+ }
+ const key = `segmentsToSkip-${videoID}`;
+ window[key] = window[key] || (await tryFetchSkipSegments(videoID));
+ for (const v of document.querySelectorAll('video')) {
+ if (Number.isNaN(v.duration)) continue;
+ for (const [start, end] of window[key]) {
+ if (v.currentTime < end && v.currentTime >= start) {
+ console.log(`Sponsorblock: skipped video @${v.currentTime} from ${start} to ${end}`);
+ v.currentTime = end;
+ return
+ }
+ const timeToSponsor = (start - v.currentTime) / v.playbackRate;
+ if (v.currentTime < start && timeToSponsor < (delay / 1000)) {
+ console.log(`Sponsorblock: Almost at sponsor segment, sleep for ${timeToSponsor * 1000}ms`);
+ setTimeout(skipSegments, timeToSponsor * 1000);
+ }
+ }
+ }
+};
+if (!window.skipSegmentsIntervalID) {
+ window.skipSegmentsIntervalID = setInterval(skipSegments, delay);
+}
diff --git a/home-manager/features/gui/apps/vesktop.nix b/home-manager/features/gui/apps/vesktop.nix
new file mode 100644
index 0000000..f28d719
--- /dev/null
+++ b/home-manager/features/gui/apps/vesktop.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.gui.apps.vesktop;
+in {
+ options.features.gui.apps.vesktop.enable = lib.mkEnableOption "vesktop";
+ config = lib.mkIf cfg.enable {
+ home.packages = with pkgs; [(vesktop.override { withSystemVencord = false; })];
+ };
+}
diff --git a/home-manager/features/gui/bundles/video.nix b/home-manager/features/gui/bundles/video.nix
new file mode 100644
index 0000000..491bf21
--- /dev/null
+++ b/home-manager/features/gui/bundles/video.nix
@@ -0,0 +1,11 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.gui.bundles.video;
+in {
+ options.features.gui.bundles.video.enable = lib.mkEnableOption "video";
+ config = lib.mkIf cfg.enable {
+ home.packages = with pkgs; [
+ kdePackages.kdenlive
+ ];
+ features.gui.apps.obs.enable = true;
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/default.nix b/home-manager/features/gui/desktops/niri/default.nix
new file mode 100755
index 0000000..6304c66
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/default.nix
@@ -0,0 +1,125 @@
+{
+ config,
+ pkgs,
+ lib,
+ inputs,
+ ...
+}: let
+ cfg = config.features.gui.desktops.niri;
+ aes = config.aesthetics;
+in {
+ imports = [
+ inputs.niri.homeModules.niri
+ ./keybinds.nix
+ ];
+ options.features.gui.desktops.niri.enable = lib.mkEnableOption "niri";
+ config = lib.mkIf cfg.enable {
+ features.gui.desktops.niri.parts = {
+ waybar.enable = true;
+ fuzzel.enable = true;
+ selectors.enable = true;
+ swww.enable = true;
+ mako.enable = true;
+ hyprlock.enable = true;
+ };
+ programs.niri = {
+ enable = true;
+ package = inputs.niri.packages.${pkgs.system}.niri-unstable;
+ settings = {
+ outputs = {
+ "Samsung Electric Company SAMSUNG 0x00000001" = {
+ enable = true;
+ scale = 1.5;
+ };
+ };
+ spawn-at-startup = [
+ # Status Bar
+ {command = ["waybar"];}
+
+ # Wallpaper Daemon
+ {command = ["swww-daemon"];}
+
+ # Allows x apps to be used in wayland.
+ {command = ["${lib.getExe pkgs.xwayland-satellite}"];}
+
+ # Logs the clipboard for use in utilities.
+ {command = ["${pkgs.wl-clipboard}/bin/wl-paste" "--watch" "${pkgs.cliphist}/bin/cliphist" "store"];}
+ ];
+ environment = {
+ DISPLAY = ":0"; # Important for Xwayland.
+ };
+ window-rules = [
+ {
+ geometry-corner-radius = let
+ radius = 4.0;
+ in {
+ top-left = radius;
+ top-right = radius;
+ bottom-left = radius;
+ bottom-right = radius;
+ };
+ clip-to-geometry = true;
+ default-column-width.proportion = 1. / 3.;
+ }
+ {
+ # Prevent Tor from being screen captured.
+ matches = [{app-id = "Tor Browser";}];
+ block-out-from = "screen-capture";
+ }
+ ];
+ switch-events = {
+ lid-close.action.spawn = ["hyprlock"];
+ };
+ prefer-no-csd = true;
+ overview = {
+ backdrop-color = "#${aes.scheme.base01}";
+ };
+ layout = {
+ gaps = 14;
+ insert-hint.enable = false;
+ shadow = {
+ enable = true;
+ softness = 10;
+ spread = 5;
+ offset = {
+ x = 0;
+ y = 0;
+ };
+ };
+ focus-ring = {
+ enable = true;
+ width = 3;
+ active.color = "#${aes.scheme.base09}";
+ };
+ border = {
+ enable = false;
+ width = 3;
+ inactive.color = "#${aes.scheme.base03}";
+ active.color = "#${aes.scheme.base08}";
+ };
+ struts = {
+ # left = -1;
+ # right = -1;
+
+ left = 20;
+ right = 20;
+ top = 20;
+ bottom = 20;
+ };
+ always-center-single-column = false;
+ empty-workspace-above-first = true;
+ };
+ input.keyboard.xkb.options = ''
+ caps:escape,
+ compose:ins
+ '';
+ hotkey-overlay.skip-at-startup = true;
+ input = {
+ touchpad = {
+ click-method = "clickfinger";
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/keybinds.nix b/home-manager/features/gui/desktops/niri/keybinds.nix
new file mode 100644
index 0000000..56324bc
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/keybinds.nix
@@ -0,0 +1,168 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: {
+ config = lib.mkIf config.features.gui.desktops.niri.enable {
+ programs.niri.settings.binds = let
+ left = "h";
+ down = "j";
+ up = "k";
+ right = "l";
+ in {
+ # App Launching Keys
+ "Mod+Q".action.spawn = ["foot"];
+ "Mod+W".action.spawn = ["qutebrowser"];
+ "Mod+Shift+W".action.spawn = ["librewolf"];
+ "Mod+E".action.spawn = ["neovide"];
+
+ # Reboot to gaming OS
+ "Mod+G".action.spawn = ["${lib.getExe (pkgs.writers.writeNuBin "gameos" "pkexec ${pkgs.efibootmgr}/bin/efibootmgr --bootnext 0000; reboot")}"];
+
+ # Clear Notifications
+ "Mod+B".action.spawn = ["makoctl" "dismiss" "-a"];
+
+ # Selectors
+ "Mod+R".action.spawn = ["fuzzel"];
+ "Mod+T".action.spawn = ["tool-selector"];
+ "Mod+Y".action.spawn = ["clipboard-selector"];
+ "Mod+U".action.spawn = ["wallpaper-selector" "--all-outputs"];
+ "Mod+Shift+U".action.spawn = ["wallpaper-selector"];
+ "Mod+Control+U".action.spawn = ["wallpaper-selector" "--randomize" "--all-outputs"];
+ "Mod+Control+Shift+U".action.spawn = ["wallpaper-selector" "--randomize"];
+
+ # Screenshot Keys
+ "Mod+P".action.screenshot = [];
+ "Shift+Mod+P".action.screenshot-screen = [];
+ "Control+Mod+P".action.screenshot-window = [];
+
+ # Power Keys
+ "Mod+comma".action.spawn = ["${lib.getExe (pkgs.writers.writeNuBin "nirilock" "systemctl suspend ; hyprlock")}"];
+
+ # Horizontal Tiling Keys
+ "Mod+A".action.maximize-column = [];
+ "Mod+S".action.switch-preset-column-width = [];
+
+ # Vertical Tiling Keys
+ "Mod+Shift+A".action.reset-window-height = [];
+ "Mod+Shift+S".action.switch-preset-window-height = [];
+ "Mod+D".action.consume-or-expel-window-right = [];
+
+ # Floating Window Management Keys
+ "Mod+Z".action.switch-focus-between-floating-and-tiling = [];
+ "Mod+X".action.toggle-window-floating = [];
+
+ # Other Window Management Keys
+ "Mod+C".action.close-window = [];
+ "Mod+V".action.fullscreen-window = [];
+
+ # Overlay Keys
+ "Mod+F".action.toggle-overview = [];
+
+ # +---------------------+
+ # | Arrow Movement Keys |
+ # +---------------------+
+
+ # Window Focus Keys
+ "Mod+Left".action.focus-column-left = [];
+ "Mod+Right".action.focus-column-right = [];
+ "Mod+Up".action.focus-window-up = [];
+ "Mod+Down".action.focus-window-down = [];
+
+ # Monitor Focus Keys
+ "Mod+Shift+Left".action.focus-monitor-left = [];
+ "Mod+Shift+Right".action.focus-monitor-right = [];
+
+ # Workspace Focus Keys
+ "Mod+Shift+Up".action.focus-workspace-up = [];
+ "Mod+Shift+Down".action.focus-workspace-down = [];
+
+ # Window Motion Keys
+ "Mod+Control+Left".action.move-column-left = [];
+ "Mod+Control+Right".action.move-column-right = [];
+ "Mod+Control+Up".action.move-window-up = [];
+ "Mod+Control+Down".action.move-window-down = [];
+
+ # Window - Monitor Motion Keys
+ "Mod+Control+Shift+Left".action.move-column-to-monitor-left = [];
+ "Mod+Control+Shift+Right".action.move-column-to-monitor-right = [];
+
+ # Window - Workspace Motion Keys
+ "Mod+Control+Shift+Up".action.move-window-to-workspace-up = [];
+ "Mod+Control+Shift+Down".action.move-window-to-workspace-down = [];
+
+ # Workspace Motion Keys
+ "Mod+Alt+Shift+Up".action.move-workspace-up = [];
+ "Mod+Alt+Shift+Down".action.move-workspace-down = [];
+
+ # Workspace - Monitor Motion Keys
+ "Mod+Alt+Shift+Left".action.move-workspace-to-monitor-left = [];
+ "Mod+Alt+Shift+Right".action.move-workspace-to-monitor-right = [];
+
+ # +-------------------+
+ # | Vim Movement Keys |
+ # +-------------------+
+
+ # Window Focus Keys
+ "Mod+${left}".action.focus-column-left = [];
+ "Mod+${right}".action.focus-column-right = [];
+ "Mod+${up}".action.focus-window-up = [];
+ "Mod+${down}".action.focus-window-down = [];
+
+ # Monitor Focus Keys
+ "Mod+Shift+${left}".action.focus-monitor-left = [];
+ "Mod+Shift+${right}".action.focus-monitor-right = [];
+
+ # Workspace Focus Keys
+ "Mod+Shift+${up}".action.focus-workspace-up = [];
+ "Mod+Shift+${down}".action.focus-workspace-down = [];
+
+ # Monitor Motion Keys
+ "Mod+Control+Shift+${left}".action.move-column-to-monitor-left = [];
+ "Mod+Control+Shift+${right}".action.move-column-to-monitor-right = [];
+
+ # Workspace Motion Keys
+ "Mod+Control+Shift+${up}".action.move-window-to-workspace-up = [];
+ "Mod+Control+Shift+${down}".action.move-window-to-workspace-down = [];
+
+ # Window Motion Keys
+ "Mod+Control+${left}".action.move-column-left = [];
+ "Mod+Control+${right}".action.move-column-right = [];
+ "Mod+Control+${up}".action.move-window-up = [];
+ "Mod+Control+${down}".action.move-window-down = [];
+
+ # Workspace Motion Keys
+ "Mod+Alt+Shift+${up}".action.move-workspace-up = [];
+ "Mod+Alt+Shift+${down}".action.move-workspace-down = [];
+
+ # Workspace - Monitor Motion Keys
+ "Mod+Alt+Shift+${left}".action.move-workspace-to-monitor-left = [];
+ "Mod+Alt+Shift+${right}".action.move-workspace-to-monitor-right = [];
+
+ # +-------------------+
+
+ # Numbered Workspace Movement Keys
+ "Mod+1".action.focus-workspace = 1;
+ "Mod+2".action.focus-workspace = 2;
+ "Mod+3".action.focus-workspace = 3;
+ "Mod+4".action.focus-workspace = 4;
+ "Mod+5".action.focus-workspace = 5;
+ "Mod+6".action.focus-workspace = 6;
+ "Mod+7".action.focus-workspace = 7;
+ "Mod+8".action.focus-workspace = 8;
+ "Mod+9".action.focus-workspace = 9;
+ "Mod+0".action.focus-workspace = 0;
+
+ # XF86 Keys
+ "XF86AudioRaiseVolume".action.spawn = ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%+"];
+ "XF86AudioLowerVolume".action.spawn = ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-"];
+ "XF86AudioMute".action.spawn = ["wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"];
+
+ "XF86MonBrightnessUp".action.spawn = ["${lib.getExe pkgs.brightnessctl}" "s" "+5%"];
+ "XF86MonBrightnessDown".action.spawn = ["${lib.getExe pkgs.brightnessctl}" "s" "5%-"];
+
+ "XF86LaunchB".action.spawn = ["fuzzel"];
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/fuzzel.nix b/home-manager/features/gui/desktops/niri/parts/fuzzel.nix
new file mode 100755
index 0000000..e939f88
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/fuzzel.nix
@@ -0,0 +1,30 @@
+{ config, lib, ... }: let
+ cfg = config.features.gui.desktops.niri.parts.fuzzel;
+ aes = config.aesthetics;
+in {
+ options.features.gui.desktops.niri.parts.fuzzel.enable = lib.mkEnableOption "fuzzel";
+ config = lib.mkIf cfg.enable {
+ programs.fuzzel = {
+ enable = true;
+ settings = {
+ main = {
+ width = 20;
+ #terminal = config.custom.libraries.default-applications.terminal-emulator.command;
+ };
+ border = {
+ width = 3;
+ radius = 4;
+ };
+ colors = with aes.scheme; {
+ background = "${base00}ff";
+ selection = "${base00}ff";
+ selection-text = "${base0C}ff";
+ selection-match = "${base0E}ff";
+ match = "${base0E}ff";
+ border = "${base0C}ff";
+ text = "${base05}ff";
+ };
+ };
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/hyprlock.nix b/home-manager/features/gui/desktops/niri/parts/hyprlock.nix
new file mode 100755
index 0000000..f8a50e3
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/hyprlock.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }: let
+ cfg = config.features.gui.desktops.niri.parts.hyprlock;
+in {
+ options.features.gui.desktops.niri.parts.hyprlock.enable = lib.mkEnableOption "hyprlock";
+ config = lib.mkIf cfg.enable {
+ home.packages = [(
+ pkgs.writers.writeNuBin "nirilock" /*nu*/ ''
+ niri msg action do-screen-transition --delay-ms 500
+ systemctl suspend
+ hyprlock
+ ''
+ )];
+ programs.niri.settings.window-rules = [
+ {
+ matches = [{ title = "hyprlock"; }];
+ draw-border-with-background = false;
+ }
+ ];
+ programs.hyprlock = {
+ enable = true;
+ settings = {
+ background = {
+ monitor = "";
+ path = "${config.aesthetics.wallpaper}";
+ blur_passes = 0;
+ blur_size = 5;
+ };
+ label = {
+ text = "$TIME";
+ font_size = 65;
+ font_family = "Cantarell Bold";
+
+ position = "0, 0";
+ halign = "center";
+ valign = "center";
+ };
+ input-field = {
+ size = "250, 50";
+ position = "0, -80";
+ outline_thickness = 0;
+ placeholder_text = "";
+ };
+ };
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/mako.nix b/home-manager/features/gui/desktops/niri/parts/mako.nix
new file mode 100755
index 0000000..e5bc3b8
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/mako.nix
@@ -0,0 +1,26 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.features.gui.desktops.niri.parts.mako;
+in {
+ options.features.gui.desktops.niri.parts.mako.enable = lib.mkEnableOption "mako";
+ config = lib.mkIf cfg.enable {
+ services.mako = {
+ enable = true;
+ settings = {
+ border-radius = 4;
+ border-size = 3;
+ # margin = "11";
+ margin = "31";
+ padding = "5";
+
+ anchor = "top-center";
+
+ ignore-timeout = true;
+ default-timeout = 10000;
+ };
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/quickshell/.envrc b/home-manager/features/gui/desktops/niri/parts/quickshell/.envrc
new file mode 100644
index 0000000..3550a30
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/quickshell/.envrc
@@ -0,0 +1 @@
+use flake
diff --git a/home-manager/features/gui/desktops/niri/parts/quickshell/flake.lock b/home-manager/features/gui/desktops/niri/parts/quickshell/flake.lock
new file mode 100644
index 0000000..29f5851
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/quickshell/flake.lock
@@ -0,0 +1,64 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": [
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1751498133,
+ "narHash": "sha256-QWJ+NQbMU+NcU2xiyo7SNox1fAuwksGlQhpzBl76g1I=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "d55716bb59b91ae9d1ced4b1ccdea7a442ecbfdb",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs",
+ "systems": "systems"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/quickshell/flake.nix b/home-manager/features/gui/desktops/niri/parts/quickshell/flake.nix
new file mode 100644
index 0000000..2122f1f
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/quickshell/flake.nix
@@ -0,0 +1,29 @@
+{
+ description = "Project flake";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+ systems.url = "github:nix-systems/default";
+ flake-utils = {
+ url = "github:numtide/flake-utils";
+ inputs.systems.follows = "systems";
+ };
+ };
+
+ outputs = {
+ nixpkgs,
+ flake-utils,
+ ...
+ }:
+ flake-utils.lib.eachDefaultSystem (
+ system: let
+ pkgs = nixpkgs.legacyPackages.${system};
+ in {
+ devShells.default = pkgs.mkShell {
+ packages = with pkgs; [
+ quickshell
+ ];
+ };
+ }
+ );
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/selectors.nix b/home-manager/features/gui/desktops/niri/parts/selectors.nix
new file mode 100644
index 0000000..1adc917
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/selectors.nix
@@ -0,0 +1,123 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ cfg = config.features.gui.desktops.niri.parts.selectors;
+ aes = config.aesthetics;
+in {
+ options.features.gui.desktops.niri.parts.selectors.enable = lib.mkEnableOption "selectors";
+ config = lib.mkIf cfg.enable {
+ home.packages = with pkgs; [
+ # Tool Selector
+ (
+ pkgs.writers.writeNuBin "tool-selector"
+ /*
+ nu
+ */
+ ''
+
+ # Tools
+ let tools = {
+ "rebuild nixos": {
+ # footclient -H sudo nixos-rebuild switch --flake ($"~/Sync/setup#(hostname)" | path expand)
+ foot -H nh os switch
+ }
+ "rebuild home": {
+ # foot -H home-manager switch --flake ($"~/Sync/setup#(whoami)@(hostname)" | path expand)
+ foot -H nh home switch
+ }
+ "update flake": {
+ foot -H nix flake update --flake ($"~/Sync/setup/" | path expand)
+ }
+ "manage wifi": {
+ foot ${pkgs.impala}/bin/impala
+ }
+ "manage bluetooth": {
+ foot ${lib.getExe pkgs.bluetui}
+ }
+ "create qr-code": {
+ let temp_file = mktemp
+ let qr_code_bin = ${lib.getExe pkgs.qrtool} encode (${pkgs.wl-clipboard}/bin/wl-paste)
+ $qr_code_bin | ${pkgs.wl-clipboard}/bin/wl-copy
+ $qr_code_bin | save -f $temp_file
+ ${lib.getExe pkgs.imv} $temp_file
+ }
+ "steam big-picture": {
+ rm -r ~/.steam
+ gamescope -f --backend sdl -- steam -bigpicture
+ }
+ }
+
+ # Logic
+ let user_tool_choice = $tools
+ | columns
+ | to text
+ | fuzzel -d --placeholder "Tools"
+ if ($user_tool_choice != "") {
+ do ($tools | get $user_tool_choice)
+ }
+
+ ''
+ )
+
+ # Wallpaper Selector
+ (
+ writers.writeNuBin "wallpaper-selector"
+ /*
+ nu
+ */
+ ''
+ def main [
+ --all-outputs # Change wallpaper for all outputs
+ --randomize
+ ] {
+ mut wallpapers = {}
+ for path in (ls ${aes.wallpapersDir}/**/* | where {|item| $item.type != dir} | get name) {
+ $wallpapers = $wallpapers | insert ($path | path basename | split row "." | get 0) $path
+ }
+ mut prompt = "Wallpaper (current)"
+ if $all_outputs {
+ $prompt = "Wallpaper (all)"
+ }
+ mut wallpaper_path = ""
+ if $randomize {
+ $wallpaper_path = $wallpapers | get (
+ $wallpapers
+ | columns
+ | shuffle
+ | get 0
+ )
+ } else {
+ $wallpaper_path = $wallpapers | get (
+ $wallpapers
+ | columns
+ | to text
+ | ${lib.getExe pkgs.fuzzel} -d --placeholder $prompt
+ )
+ }
+ if $all_outputs {
+ ${lib.getExe pkgs.swww} img $wallpaper_path -t wipe --transition-fps 60 --transition-angle 45
+ } else {
+ let focused_display = niri msg -j focused-output
+ | from json
+ | get name
+ ${lib.getExe pkgs.swww} img $wallpaper_path -t wipe --transition-fps 60 --transition-angle 45 --outputs $focused_display
+ }
+ }
+ ''
+ )
+
+ # Clipboard Selector
+ (
+ writers.writeNuBin "clipboard-selector" ''
+ ${lib.getExe pkgs.cliphist} list
+ | cut -f 2-
+ | ${lib.getExe pkgs.fuzzel} --dmenu
+ | ${pkgs.wl-clipboard}/bin/wl-copy
+ ''
+ )
+ ];
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/swww.nix b/home-manager/features/gui/desktops/niri/parts/swww.nix
new file mode 100755
index 0000000..dca163b
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/swww.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.gui.desktops.niri.parts.swww;
+in {
+ options.features.gui.desktops.niri.parts.swww.enable = lib.mkEnableOption "swww";
+ config = lib.mkIf cfg.enable {
+ home.packages = [pkgs.swww];
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/waybar.nix b/home-manager/features/gui/desktops/niri/parts/waybar.nix
new file mode 100755
index 0000000..7535b0c
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/waybar.nix
@@ -0,0 +1,136 @@
+{ config, pkgs, lib, ... }:
+let
+ cfg = config.features.gui.desktops.niri.parts.waybar;
+ aes = config.aesthetics;
+in {
+ options.features.gui.desktops.niri.parts.waybar.enable = lib.mkEnableOption "waybar";
+ config = lib.mkIf cfg.enable {
+ programs.waybar = {
+ enable = true;
+ settings = {
+ bar = {
+ layer = "top";
+ position = "bottom";
+ height = 32;
+ modules-left = [ "battery" "network" "backlight" "pulseaudio" ];
+ modules-center = [ "niri/workspaces" ];
+ modules-right = [ "clock#date" "clock#time" ];
+ "clock#date" = {
+ format = " {:%A, %B %d}";
+ };
+ "clock#time" = {
+ format = " {:%I:%M}";
+ };
+ pulseaudio = {
+ format = " {volume}%";
+ format-muted = " {volume}%";
+ };
+ network = {
+ format = "{essid}";
+ format-wifi = "{icon} {essid}";
+ format-ethernet = "󰈀 Ethernet";
+ format-disconnected = "󰤭 Disconnected";
+ format-icons = [ "󰤯" "󰤟" "󰤢" "󰤥" "󰤨" ];
+ };
+ battery = {
+ format = "{icon} {capacity}%";
+ format-charging = "󰂄 {capacity}%";
+ format-icons = [ "󰂎" "󰁺" "󰁻" "󰁼" "󰁽" "󰁾" "󰁿" "󰂀" "󰂁" "󰂂" "󰁹" ];
+ };
+ backlight = {
+ format = " {percent}%";
+ };
+ "niri/workspaces" = {
+ format = "{icon}";
+ format-icons = {
+ default = "";
+ active = "";
+ /*
+ "1" = "1";
+ "2" = "2";
+ "3" = "3";
+ "4" = "4";
+ "5" = "5";
+ "6" = "6";
+ "7" = "7";
+ "8" = "8";
+ "9" = "9";
+ "10" = "10";
+ "11" = "11";
+ "12" = "12";
+ */
+ };
+ };
+ };
+ };
+ style = let
+ border-radius = "4";
+ padding = "12";
+ in /*css*/ ''
+ @define-color background-color #${aes.scheme.base00};
+ @define-color border-color #${aes.scheme.base0C};
+ @define-color text-color #${aes.scheme.base05};
+ * {
+ font-family: ${aes.font.name};
+ font-weight: 600;
+ font-size: ${aes.font.size.medium}px;
+ }
+ window#waybar {
+ background-color: transparent;
+ }
+ #clock.time, #clock.date, #backlight, #pulseaudio, #battery, #network {
+ background-color: @background-color;
+ color: @text-color;
+ border-radius: ${border-radius}px;
+ border-width: 0px;
+ border-color: @border-color;
+ padding: 0px ${padding}px;
+ }
+ #backlight, #pulseaudio, #battery, #network {
+ margin: 0px 0px ${padding} ${padding};
+ }
+ #workspaces {
+ background-color: @background-color;
+ color: @background-color;
+ border-radius: ${border-radius}px;
+ border-width: 0px;
+ border-color: @border-color;
+ padding: 0px 0px;
+ margin-bottom: ${padding}px;
+ }
+ #workspaces button {
+ font-weight: bold;
+ padding: 0px 4px;
+ margin: 4px 4px;
+ border-radius: ${border-radius}px;
+ color: @background-color;
+ background: @text-color;
+ opacity: 0.5;
+ transition: all 0.3s cubic-bezier(.25,.1,.25,1);
+ }
+ #workspaces button.active {
+ font-weight: bold;
+ padding: 0px 4px;
+ margin: 4px 4px;
+ border-radius: ${border-radius}px;
+ color: @background-color;
+ background: @text-color;
+ transition: all 0.3s cubic-bezier(.25,.1,.25,1);
+ opacity: 1.0;
+ min-width: 40px;
+ }
+ #workspaces button:hover {
+ font-weight: bold;
+ border-radius: ${border-radius}px;
+ color: @background-color;
+ background: @text-color;
+ opacity: 0.8;
+ transition: all 0.3s cubic-bezier(.25,.1,.25,1);
+ }
+ #clock.date, #clock.time {
+ margin: 0px ${padding} ${padding} 0px
+ }
+ '';
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/wl-kbptr.nix b/home-manager/features/gui/desktops/niri/parts/wl-kbptr.nix
new file mode 100644
index 0000000..6f6ed56
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/wl-kbptr.nix
@@ -0,0 +1,14 @@
+{ config, lib, pkgs, inputs, ... }: let
+ cfg = config.features.gui.desktops.niri.parts.wl-kbptr;
+in {
+ options.features.gui.desktops.niri.parts.wl-kbptr.enable = lib.mkEnableOption "wl-kbptr";
+ config = lib.mkIf cfg.enable {
+ home.packages = [ pkgs.wl-kbptr ];
+ home.file."wl-kbptr-config" = {
+ target = ".config/wl-kbptr/config";
+ text = ''
+
+ '';
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/parts/wluma.nix b/home-manager/features/gui/desktops/niri/parts/wluma.nix
new file mode 100644
index 0000000..21b9edc
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/parts/wluma.nix
@@ -0,0 +1,11 @@
+{ config, lib, ... }: let
+ cfg = config.features.gui.desktops.niri.parts.wluma;
+in {
+ options.features.gui.desktops.niri.parts.wluma.enable = lib.mkEnableOption "wluma";
+ config = lib.mkIf cfg.enable {
+ services.wluma = {
+ enable = true;
+ systemd.enable = true;
+ };
+ };
+}
diff --git a/home-manager/features/gui/desktops/niri/readme.md b/home-manager/features/gui/desktops/niri/readme.md
new file mode 100644
index 0000000..a70f77d
--- /dev/null
+++ b/home-manager/features/gui/desktops/niri/readme.md
@@ -0,0 +1,9 @@
+# Keybinds Scheme
+
+OS: The OS + Arrows combination is for moving between windows within a workspace.
+
+OS + Shift: The OS + Shift + Arrows combination is for moving between workspaces.
+
+OS + Alt: The OS + Alt + Arrows combination is for moving between monitors.
+
+The control key can be used with any of these combos to bring the current window along with you.
diff --git a/home-manager/features/services/flatpak.nix b/home-manager/features/services/flatpak.nix
new file mode 100644
index 0000000..37225aa
--- /dev/null
+++ b/home-manager/features/services/flatpak.nix
@@ -0,0 +1,27 @@
+{
+ config,
+ pkgs,
+ lib,
+ inputs,
+ ...
+}: let
+ cfg = config.features.services.flatpak;
+in {
+ imports = [inputs.nix-flatpak.homeManagerModules.nix-flatpak];
+ options.features.services.flatpak = {
+ enable = lib.mkEnableOption "flatpak";
+ packages = lib.mkOption {
+ type = lib.types.listOf lib.types.str;
+ default = [];
+ description = "A list of flatpaks to install.";
+ };
+ };
+ config = lib.mkIf cfg.enable {
+ home.packages = [pkgs.flatpak];
+ services.flatpak = {
+ enable = true;
+ packages = cfg.packages;
+ overrides.global.Context.sockets = ["wayland" "!x11" "!fallback-x11"];
+ };
+ };
+}
diff --git a/home-manager/features/services/udiskie.nix b/home-manager/features/services/udiskie.nix
new file mode 100644
index 0000000..9b79d11
--- /dev/null
+++ b/home-manager/features/services/udiskie.nix
@@ -0,0 +1,17 @@
+{ config, lib, ... }: let
+ cfg = config.features.services.udiskie;
+in {
+ options.features.services.udiskie.enable = lib.mkEnableOption "udiskie";
+ config = lib.mkIf cfg.enable {
+ services.udiskie = {
+ enable = true;
+ automount = true;
+ };
+ systemd.user.targets.tray = {
+ Unit = {
+ Description = "Home Manager System Tray";
+ Requires = [ "graphical-session-pre.target" ];
+ };
+ };
+ };
+}
diff --git a/home-manager/features/services/wluma.nix b/home-manager/features/services/wluma.nix
new file mode 100644
index 0000000..7c9369e
--- /dev/null
+++ b/home-manager/features/services/wluma.nix
@@ -0,0 +1,11 @@
+{ config, pkgs, lib, ... }: let
+ cfg = config.features.services.wluma;
+in {
+ options.features.services.wluma.enable = lib.mkEnableOption "wluma";
+ config = lib.mkIf cfg.enable {
+ services.wluma = {
+ enable = true;
+ systemd.enable = true;
+ };
+ };
+}
diff --git a/home-manager/modules/aesthetics/default.nix b/home-manager/modules/aesthetics/default.nix
new file mode 100644
index 0000000..c49a198
--- /dev/null
+++ b/home-manager/modules/aesthetics/default.nix
@@ -0,0 +1,101 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ cfg = config.aesthetics;
+in {
+ imports = [
+ ./targets
+ ./themes
+ ];
+ options.aesthetics = {
+ enable = lib.mkEnableOption "aesthetics";
+ theme = lib.mkOption {
+ type = lib.types.str;
+ description = "The name of the theme to use.";
+ default = "oxocarbon";
+ };
+ hasGui = lib.mkOption {
+ type = lib.types.bool;
+ description = "Whether to theme gui apps. (can break if no gui)";
+ default = false;
+ };
+ enableAllTargets = lib.mkEnableOption "all targets";
+ wallpapersDir = lib.mkOption {
+ type = lib.types.path;
+ description = "Where to find wallpapers.";
+ };
+ wallpaper = lib.mkOption {
+ type = lib.types.path;
+ description = "Where to find the default wallpaper.";
+ };
+ font = {
+ name = lib.mkOption {
+ type = lib.types.str;
+ default = "CodeNewRoman Nerd Font";
+ description = "The font to use.";
+ };
+ package = lib.mkOption {
+ type = lib.types.package;
+ default = pkgs.nerd-fonts.code-new-roman;
+ description = "The font package to use.";
+ };
+ size = {
+ small = lib.mkOption {
+ type = lib.types.str;
+ default = "10";
+ description = "The size of the font to use for small text. (e.g. terminals)";
+ };
+ medium = lib.mkOption {
+ type = lib.types.str;
+ default = "14";
+ description = "The size of the font to use for medium text. (e.g. waybar)";
+ };
+ large = lib.mkOption {
+ type = lib.types.str;
+ default = "18";
+ description = "The size of the font to use for large text.";
+ };
+ };
+ };
+ scheme = let
+ mkHexOption = {}:
+ lib.mkOption {
+ type = lib.types.str;
+ default = "";
+ example = "ffffff";
+ description = "A hex color";
+ };
+ in {
+ base00 = mkHexOption {};
+ base01 = mkHexOption {};
+ base02 = mkHexOption {};
+ base03 = mkHexOption {};
+ base04 = mkHexOption {};
+ base05 = mkHexOption {};
+ base06 = mkHexOption {};
+ base07 = mkHexOption {};
+ base08 = mkHexOption {};
+ base09 = mkHexOption {};
+ base0A = mkHexOption {};
+ base0B = mkHexOption {};
+ base0C = mkHexOption {};
+ base0D = mkHexOption {};
+ base0E = mkHexOption {};
+ base0F = mkHexOption {};
+ };
+ opacity = lib.mkOption {
+ type = lib.types.float;
+ description = "Opacity";
+ default = 1.0;
+ };
+ };
+ config = lib.mkIf cfg.enable {
+ aesthetics.themes.${cfg.theme}.enable = true;
+
+ home.packages = [cfg.font.package];
+ fonts.fontconfig.enable = true;
+ };
+}
diff --git a/home-manager/modules/aesthetics/readme.md b/home-manager/modules/aesthetics/readme.md
new file mode 100644
index 0000000..75588a2
--- /dev/null
+++ b/home-manager/modules/aesthetics/readme.md
@@ -0,0 +1,15 @@
+# Aesthetics
+
+My crappy custom nix module for managing:
+
+- Base16 colors
+- Window opacity
+- System font
+- Wallpapers
+
+## Structure
+
+- default.nix: Creates all main options to be set by modules in the themes dir. also configures the font and enables one theme.
+- themes/: Contains modules with sets of base16 colors and which set options in default.nix. These modules can contain direct configs for certain apps if the apps have poor base16 support, but they must obey the options set in the app's target module.
+- targets/: Contains modules configuring apps using base16 colors or just setting options to enable or disable the theming of an app.
+
diff --git a/home-manager/modules/aesthetics/targets/default.nix b/home-manager/modules/aesthetics/targets/default.nix
new file mode 100644
index 0000000..7dba76d
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/default.nix
@@ -0,0 +1,11 @@
+{...}: {
+ imports = [
+ ./mako.nix
+ ./zellij.nix
+ ./qutebrowser.nix
+ ./helix.nix
+ ./gtk.nix
+ ./foot.nix
+ ./vesktop.nix
+ ];
+}
diff --git a/home-manager/modules/aesthetics/targets/foot.nix b/home-manager/modules/aesthetics/targets/foot.nix
new file mode 100644
index 0000000..c6c2283
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/foot.nix
@@ -0,0 +1,55 @@
+{ config, lib, ... }: let
+ cfg = config.aesthetics.targets.foot;
+ aes = config.aesthetics;
+in {
+ options.aesthetics.targets.foot.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = (aes.enableAllTargets && aes.hasGui);
+ description = "Whether to enable the aesthetics foot target.";
+ };
+ config = lib.mkIf (cfg.enable && config.programs.foot.enable) {
+ programs.foot.settings = {
+ main.font = "${aes.font.name}:size=${aes.font.size.small}";
+ tweak.font-monospace-warn = false;
+ colors = with aes.scheme; {
+ background = base00;
+ foreground = base05;
+
+ # normal
+ regular0 = base00;
+ regular1 = base08;
+ regular2 = base0B;
+ regular3 = base0A;
+ regular4 = base0D;
+ regular5 = base0E;
+ regular6 = base0C;
+ regular7 = base05;
+
+ # bright
+ bright0 = base03;
+ bright1 = base09;
+ bright2 = base01;
+ bright3 = base02;
+ bright4 = base04;
+ bright5 = base06;
+ bright6 = base0F;
+ bright7 = base07;
+
+ # extended
+ "16" = base09;
+ "17" = base0F;
+ "18" = base01;
+ "19" = base02;
+ "20" = base04;
+ "21" = base06;
+
+ # misc
+ selection-background = base05;
+ selection-foreground = base00;
+ urls = base04;
+ jump-labels = "${base00} ${base0A}";
+ scrollback-indicator = "${base00} ${base04}";
+ };
+ };
+ };
+}
diff --git a/home-manager/modules/aesthetics/targets/gtk.nix b/home-manager/modules/aesthetics/targets/gtk.nix
new file mode 100644
index 0000000..795365d
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/gtk.nix
@@ -0,0 +1,119 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ cfg = config.aesthetics.targets.gtk;
+ aes = config.aesthetics;
+
+ gtkCSS = with aes.scheme; ''
+ @define-color accent_color #${base0D};
+ @define-color accent_bg_color #${base0D};
+ @define-color accent_fg_color #${base00};
+ @define-color destructive_color #${base08};
+ @define-color destructive_bg_color #${base08};
+ @define-color destructive_fg_color #${base00};
+ @define-color success_color #${base0B};
+ @define-color success_bg_color #${base0B};
+ @define-color success_fg_color #${base00};
+ @define-color warning_color #${base0E};
+ @define-color warning_bg_color #${base0E};
+ @define-color warning_fg_color #${base00};
+ @define-color error_color #${base08};
+ @define-color error_bg_color #${base08};
+ @define-color error_fg_color #${base00};
+ @define-color window_bg_color #${base00};
+ @define-color window_fg_color #${base05};
+ @define-color view_bg_color #${base00};
+ @define-color view_fg_color #${base05};
+ @define-color headerbar_bg_color #${base01};
+ @define-color headerbar_fg_color #${base05};
+ @define-color headerbar_border_color #${base01};
+ @define-color headerbar_backdrop_color @window_bg_color;
+ @define-color headerbar_shade_color rgba(0, 0, 0, 0.07);
+ @define-color headerbar_darker_shade_color rgba(0, 0, 0, 0.07);
+ @define-color sidebar_bg_color #${base01};
+ @define-color sidebar_fg_color #${base05};
+ @define-color sidebar_backdrop_color @window_bg_color;
+ @define-color sidebar_shade_color rgba(0, 0, 0, 0.07);
+ @define-color secondary_sidebar_bg_color @sidebar_bg_color;
+ @define-color secondary_sidebar_fg_color @sidebar_fg_color;
+ @define-color secondary_sidebar_backdrop_color @sidebar_backdrop_color;
+ @define-color secondary_sidebar_shade_color @sidebar_shade_color;
+ @define-color card_bg_color #${base01};
+ @define-color card_fg_color #${base05};
+ @define-color card_shade_color rgba(0, 0, 0, 0.07);
+ @define-color dialog_bg_color #${base01};
+ @define-color dialog_fg_color #${base05};
+ @define-color popover_bg_color #${base01};
+ @define-color popover_fg_color #${base05};
+ @define-color popover_shade_color rgba(0, 0, 0, 0.07);
+ @define-color shade_color rgba(0, 0, 0, 0.07);
+ @define-color scrollbar_outline_color #${base02};
+ @define-color blue_1 #${base0D};
+ @define-color blue_2 #${base0D};
+ @define-color blue_3 #${base0D};
+ @define-color blue_4 #${base0D};
+ @define-color blue_5 #${base0D};
+ @define-color green_1 #${base0B};
+ @define-color green_2 #${base0B};
+ @define-color green_3 #${base0B};
+ @define-color green_4 #${base0B};
+ @define-color green_5 #${base0B};
+ @define-color yellow_1 #${base0A};
+ @define-color yellow_2 #${base0A};
+ @define-color yellow_3 #${base0A};
+ @define-color yellow_4 #${base0A};
+ @define-color yellow_5 #${base0A};
+ @define-color orange_1 #${base09};
+ @define-color orange_2 #${base09};
+ @define-color orange_3 #${base09};
+ @define-color orange_4 #${base09};
+ @define-color orange_5 #${base09};
+ @define-color red_1 #${base08};
+ @define-color red_2 #${base08};
+ @define-color red_3 #${base08};
+ @define-color red_4 #${base08};
+ @define-color red_5 #${base08};
+ @define-color purple_1 #${base0E};
+ @define-color purple_2 #${base0E};
+ @define-color purple_3 #${base0E};
+ @define-color purple_4 #${base0E};
+ @define-color purple_5 #${base0E};
+ @define-color brown_1 #${base0F};
+ @define-color brown_2 #${base0F};
+ @define-color brown_3 #${base0F};
+ @define-color brown_4 #${base0F};
+ @define-color brown_5 #${base0F};
+ @define-color light_1 #${base01};
+ @define-color light_2 #${base01};
+ @define-color light_3 #${base01};
+ @define-color light_4 #${base01};
+ @define-color light_5 #${base01};
+ @define-color dark_1 #${base01};
+ @define-color dark_2 #${base01};
+ @define-color dark_3 #${base01};
+ @define-color dark_4 #${base01};
+ @define-color dark_5 #${base01};
+ '';
+in {
+ options.aesthetics.targets.gtk.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = aes.enableAllTargets && aes.hasGui;
+ description = "Whether to enable the aesthetics GTK target.";
+ };
+ config = lib.mkIf cfg.enable {
+ gtk = {
+ enable = true;
+ theme = {
+ package = pkgs.adw-gtk3;
+ name = "adw-gtk3";
+ };
+ };
+ xdg.configFile = {
+ "gtk-3.0/gtk.css".text = gtkCSS;
+ "gtk-4.0/gtk.css".text = gtkCSS;
+ };
+ };
+}
diff --git a/home-manager/modules/aesthetics/targets/helix.nix b/home-manager/modules/aesthetics/targets/helix.nix
new file mode 100644
index 0000000..dde557e
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/helix.nix
@@ -0,0 +1,28 @@
+{ config, lib, ... }: let
+ cfg = config.aesthetics.targets.helix;
+ aes = config.aesthetics;
+in {
+ options.aesthetics.targets.helix = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = aes.enableAllTargets;
+ description = "Whether to enable the aesthetics helix target.";
+ };
+ theme = lib.mkOption {
+ type = lib.types.str;
+ default = "default";
+ description = "The name of the theme to use for helix.";
+ };
+ };
+ config = lib.mkIf (cfg.enable && config.programs.helix.enable) {
+ programs.helix.settings.theme = "custom-default";
+ home.file."helix-theme" = {
+ target = ".config/helix/themes/custom-default.toml";
+ text = /*toml*/ ''
+ inherits = "${cfg.theme}"
+ "ui.background" = { }
+ "ui.statusline" = { bg = "" }
+ '';
+ };
+ };
+}
diff --git a/home-manager/modules/aesthetics/targets/mako.nix b/home-manager/modules/aesthetics/targets/mako.nix
new file mode 100644
index 0000000..2ade32e
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/mako.nix
@@ -0,0 +1,23 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.aesthetics.targets.mako;
+ aes = config.aesthetics;
+in {
+ options.aesthetics.targets.mako.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = aes.enableAllTargets && aes.hasGui;
+ description = "Whether to enable the aesthetics mako target.";
+ };
+ config = lib.mkIf (cfg.enable && config.services.mako.enable) {
+ services.mako.settings = with aes.scheme; {
+ background-color = "#${base00}";
+ border-color = "#${base0C}";
+ text-color = "#${base05}";
+ progress-color = "over #${base02}";
+ font = "${aes.font.name} ${aes.font.size.small}";
+ };
+ };
+}
diff --git a/home-manager/modules/aesthetics/targets/qutebrowser.nix b/home-manager/modules/aesthetics/targets/qutebrowser.nix
new file mode 100644
index 0000000..ef7f17d
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/qutebrowser.nix
@@ -0,0 +1,213 @@
+{
+ config,
+ lib,
+ ...
+}: let
+ cfg = config.aesthetics.targets.qutebrowser;
+ aes = config.aesthetics;
+in {
+ options.aesthetics.targets.qutebrowser.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = aes.enableAllTargets && aes.hasGui;
+ description = "Whether to enable the aesthetics qutebrowser target.";
+ };
+ config = lib.mkIf (cfg.enable && config.programs.qutebrowser.enable) {
+ programs.qutebrowser.settings = {
+ fonts = {
+ default_family = aes.font.name;
+ default_size = "${aes.font.size.small}pt";
+ };
+ colors = with aes.scheme; let
+ background = "#${base00}";
+ secondary-background = "#${base01}";
+ selection-background = "#${base03}";
+ foreground = "#${base05}";
+ inverted-foreground = "#${base00}";
+ error = "#${base08}";
+ info = "#${base0B}";
+ secondary-info = "#${base0C}";
+ warning = "#${base0E}";
+ in {
+ completion = {
+ category = {
+ bg = background;
+ fg = info;
+ border = {
+ bottom = background;
+ top = background;
+ };
+ };
+ even.bg = background;
+ fg = foreground;
+ item.selected = {
+ bg = selection-background;
+ border = {
+ bottom = selection-background;
+ top = selection-background;
+ };
+ fg = foreground;
+ };
+ match.fg = info;
+ odd.bg = secondary-background;
+ scrollbar = {
+ bg = background;
+ fg = foreground;
+ };
+ };
+ contextmenu = {
+ disabled = {
+ bg = secondary-background;
+ fg = inverted-foreground;
+ };
+ menu = {
+ bg = background;
+ fg = foreground;
+ };
+ selected = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+ downloads = {
+ bar.bg = background;
+ error = {
+ bg = error;
+ fg = inverted-foreground;
+ };
+ start = {
+ bg = info;
+ fg = inverted-foreground;
+ };
+ stop = {
+ bg = secondary-info;
+ fg = inverted-foreground;
+ };
+ };
+ hints = {
+ bg = secondary-background;
+ fg = foreground;
+ match.fg = info;
+ };
+ keyhint = {
+ bg = background;
+ fg = foreground;
+ suffix.fg = foreground;
+ };
+ messages = {
+ error = {
+ bg = error;
+ fg = inverted-foreground;
+ border = error;
+ };
+ info = {
+ bg = info;
+ fg = inverted-foreground;
+ border = info;
+ };
+ warning = {
+ bg = warning;
+ fg = inverted-foreground;
+ border = warning;
+ };
+ };
+ prompts = {
+ bg = background;
+ border = background;
+ fg = foreground;
+ selected.bg = secondary-background;
+ };
+ statusbar = {
+ caret = {
+ bg = selection-background;
+ fg = foreground;
+ selection = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+ command = {
+ bg = background;
+ fg = foreground;
+ private = {
+ bg = secondary-background;
+ fg = foreground;
+ };
+ };
+ insert = {
+ bg = info;
+ fg = inverted-foreground;
+ };
+ normal = {
+ bg = background;
+ fg = foreground;
+ };
+ passthrough = {
+ bg = info;
+ fg = inverted-foreground;
+ };
+ private = {
+ bg = secondary-background;
+ fg = foreground;
+ };
+ progress.bg = info;
+ url = {
+ error.fg = error;
+ fg = foreground;
+ hover.fg = foreground;
+ success = {
+ http.fg = secondary-info;
+ https.fg = info;
+ };
+ warn.fg = warning;
+ };
+ };
+ tabs = {
+ bar.bg = background;
+ even = {
+ bg = secondary-background;
+ fg = foreground;
+ };
+ indicator = {
+ inherit error;
+ start = secondary-info;
+ stop = info;
+ };
+ odd = {
+ bg = background;
+ fg = foreground;
+ };
+ pinned = {
+ even = {
+ bg = info;
+ fg = inverted-foreground;
+ };
+ odd = {
+ bg = secondary-info;
+ fg = inverted-foreground;
+ };
+ selected = {
+ even = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ odd = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+ };
+ selected = {
+ even = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ odd = {
+ bg = selection-background;
+ fg = foreground;
+ };
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/home-manager/modules/aesthetics/targets/vesktop.nix b/home-manager/modules/aesthetics/targets/vesktop.nix
new file mode 100644
index 0000000..968df1a
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/vesktop.nix
@@ -0,0 +1,65 @@
+{ config, lib, ... }: let
+ cfg = config.aesthetics.targets.vesktop;
+ aes = config.aesthetics;
+in {
+ options.aesthetics.targets.vesktop.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = (aes.enableAllTargets && aes.hasGui);
+ description = "Whether to enable the aesthetics vesktop target.";
+ };
+ config = lib.mkIf cfg.enable {
+ xdg.configFile."vesktop/themes/stylix.theme.css".text = with aes.scheme; ''
+ :root {
+ --base00: #${base00}; /* Black */
+ --base01: #${base01}; /* Bright Black */
+ --base02: #${base02}; /* Grey */
+ --base03: #${base03}; /* Brighter Grey */
+ --base04: #${base04}; /* Bright Grey */
+ --base05: #${base05}; /* White */
+ --base06: #${base06}; /* Brighter White */
+ --base07: #${base07}; /* Bright White */
+ --base08: #${base08}; /* Red */
+ --base09: #${base09}; /* Orange */
+ --base0A: #${base0A}; /* Yellow */
+ --base0B: #${base0B}; /* Green */
+ --base0C: #${base0C}; /* Cyan */
+ --base0D: #${base0D}; /* Blue */
+ --base0E: #${base0E}; /* Purple */
+ --base0F: #${base0F}; /* Magenta */
+
+ --primary-630: var(--base00); /* Autocomplete background */
+ --primary-660: var(--base00); /* Search input background */
+ }
+
+ .theme-light, .theme-dark {
+ --search-popout-option-fade: none; /* Disable fade for search popout */
+ --bg-overlay-2: var(--base00); /* These 2 are needed for proper threads coloring */
+ --home-background: var(--base00);
+ --bg-overlay-chat : var(--base00); /* Recolor forum channels */
+ --background-primary: var(--base00);
+ --background-secondary: var(--base01);
+ --background-secondary-alt: var(--base01);
+ --channeltextarea-background: var(--base01);
+ --background-tertiary: var(--base00);
+ --background-accent: var(--base0E);
+ --background-floating: var(--base01);
+ --background-modifier-hover: #{{base00-hex}}4c; /* 30% of base00 */
+ --background-modifier-selected: var(--base00);
+ --text-normal: var(--base05);
+ --text-secondary: var(--base03);
+ --text-muted: var(--base04);
+ --text-link: var(--base0C);
+ --interactive-normal: var(--base05);
+ --interactive-hover: var(--base05);
+ --interactive-active: var(--base07);
+ --interactive-muted: var(--base03);
+ --channels-default: var(--base04);
+ --channel-icon: var(--base04);
+ --header-primary: var(--base06);
+ --header-secondary: var(--base04);
+ --scrollbar-thin-track: transparent;
+ --scrollbar-auto-track: transparent;
+ }
+ '';
+ };
+}
diff --git a/home-manager/modules/aesthetics/targets/zellij.nix b/home-manager/modules/aesthetics/targets/zellij.nix
new file mode 100644
index 0000000..cefd8ab
--- /dev/null
+++ b/home-manager/modules/aesthetics/targets/zellij.nix
@@ -0,0 +1,28 @@
+{ config, lib, ... }: let
+ cfg = config.aesthetics.targets.zellij;
+ aes = config.aesthetics;
+in {
+ options.aesthetics.targets.zellij.enable = lib.mkOption {
+ type = lib.types.bool;
+ default = aes.enableAllTargets;
+ description = "Whether to enable the aesthetics zellij target.";
+ };
+ config = lib.mkIf (cfg.enable && config.programs.zellij.enable) {
+ programs.zellij.settings = {
+ theme = "base16";
+ themes.base16 = with aes.scheme; {
+ bg = "#${base03}";
+ fg = "#${base05}";
+ red = "#${base08}";
+ green = "#${base0B}";
+ blue = "#${base0D}";
+ yellow = "#${base0A}";
+ magenta = "#${base0E}";
+ orange = "#${base09}";
+ cyan = "#${base0C}";
+ black = "#${base00}";
+ white = "#${base07}";
+ };
+ };
+ };
+}
diff --git a/home-manager/modules/aesthetics/themes/default.nix b/home-manager/modules/aesthetics/themes/default.nix
new file mode 100644
index 0000000..cc5ebdb
--- /dev/null
+++ b/home-manager/modules/aesthetics/themes/default.nix
@@ -0,0 +1,5 @@
+{...}: {
+ imports = [
+ ./oxocarbon
+ ];
+}
diff --git a/home-manager/modules/aesthetics/themes/oxocarbon/default.nix b/home-manager/modules/aesthetics/themes/oxocarbon/default.nix
new file mode 100644
index 0000000..2c6ee6e
--- /dev/null
+++ b/home-manager/modules/aesthetics/themes/oxocarbon/default.nix
@@ -0,0 +1,68 @@
+{
+ config,
+ pkgs,
+ lib,
+ inputs,
+ ...
+}: let
+ cfg = config.aesthetics.themes.oxocarbon;
+ wallpapers = inputs.wallpapers.packages.${pkgs.system}.default;
+in {
+ options.aesthetics.themes.oxocarbon.enable = lib.mkEnableOption "oxocarbon theme";
+ config = lib.mkMerge [
+ (
+ lib.mkIf cfg.enable {
+ aesthetics = {
+ wallpaper = "${wallpapers}/neutral/landscape/salt-flats.jpg";
+ wallpapersDir = "${wallpapers}/neutral";
+ scheme = {
+ base00 = "161616";
+ base01 = "262626";
+ base02 = "393939";
+ base03 = "525252";
+ base04 = "dde1e6";
+ base05 = "f2f4f8";
+ base06 = "ffffff";
+ base07 = "08bdba";
+ base08 = "3ddbd9";
+ base09 = "78a9ff";
+ base0A = "ee5396";
+ base0B = "33b1ff";
+ base0C = "ff7eb6";
+ base0D = "42be65";
+ base0E = "be95ff";
+ base0F = "82cfff";
+ };
+ font = {
+ name = "CodeNewRoman Nerd Font";
+ package = pkgs.nerd-fonts.code-new-roman;
+ };
+ # font = {
+ # name = "Kirsch Nerd Font";
+ # size = "22";
+ # package = inputs.kirsch.packages.x86_64-linux.kirsch-nerd;
+ # };
+ };
+ # home.pointerCursor = {
+ # package = pkgs.oreo-cursors-plus;
+ # name = "oreo_spark_black_bordered_cursors";
+ # size = 22;
+ # };
+ home.pointerCursor = {
+ package = pkgs.qogir-icon-theme;
+ name = "Qogir-Dark";
+ size = 22;
+ };
+ }
+ )
+ (
+ lib.mkIf config.aesthetics.targets.helix.enable {
+ aesthetics.targets.helix.theme = "oxocarbon";
+ home.file."helix-oxocarbon-theme" = {
+ target = ".config/helix/themes/oxocarbon.toml";
+ source = ./helix-theme.toml;
+ };
+ }
+ )
+ ];
+}
diff --git a/home-manager/modules/aesthetics/themes/oxocarbon/helix-theme.toml b/home-manager/modules/aesthetics/themes/oxocarbon/helix-theme.toml
new file mode 100644
index 0000000..8cf3c49
--- /dev/null
+++ b/home-manager/modules/aesthetics/themes/oxocarbon/helix-theme.toml
@@ -0,0 +1,52 @@
+
+# inherits = "fleet_dark"
+
+"attribute" = { fg = "#82cfff" }
+"type" = { fg = "#78a9ff" }
+"type.builtin" = { fg = "#dde1e6" }
+"constructor" = { fg = "#78a9ff" }
+"constant" = { fg = "#be95ff" }
+"constant.builtin" = { fg = "#08bdba" }
+"constant.builtin.character" = { fg = "#be95ff" }
+"constant.builtin.numeric" = { fg = "#82cfff" }
+"string" = { fg = "#be95ff" }
+"string.regexp" = { fg = "#08bdba" }
+"comment" = { fg = "#525252" }
+"variable" = { fg = "#dde1e6" }
+"label" = { fg = "#82cfff" }
+"punctuation" = { fg = "#3ddbd9" }
+"keyword" = { fg = "#78a9ff" }
+"keyword.control.exception" = { fg = "#82cfff" }
+"keyword.operator" = { fg = "#3ddbd9" }
+"keyword.function" = { fg = "#3ddbd9" }
+"operator" = { fg = "#78a9ff" }
+"function" = { fg = "#ff7eb6" }
+"function.builtin" = { fg = "#ff7eb6" }
+"function.method" = { fg = "#08bdba" }
+"function.macro" = { fg = "#08bdba" }
+"tag" = { fg = "#dde1e6" }
+"namespace" = { fg = "#dde1e6" }
+"diff.plus" = { fg = "#42be65", bg = "#393939" }
+"diff.minus" = { fg = "#78a9ff", bg = "#393939" }
+"diff.delta" = { fg = "#dde1e6", bg = "#262626" }
+
+"ui.background" = { fg= "#ffffff", bg = "#161616"}
+"ui.separator" = "#161616"
+"ui.selection" = { bg = "#393939"}
+"ui.text" = { fg = "#ffffff" }
+"ui.cursor" = { fg = "#161616", bg = "#dde1e6" }
+"ui.cursor.normal" = { fg = "#dde1e6", bg = "#161616" }
+"ui.linenr" = { fg = "#525252", bg = "#161616" }
+"ui.linenr.selected" = { fg = "#dde1e6" }
+"ui.statusline" = { fg = "#ffffff", bg = "#161616" }
+"ui.statusline.inactive" = { fg = "#525252"}
+"ui.statusline.normal" = { fg = "#ffffff", bg = "#161616" }
+"ui.statusline.insert" = { fg = "#ffffff", bg = "#ff7eb6" }
+"ui.popup" = { fg = "#ffffff", bg = "#262626" }
+"ui.window" = { fg = "#ffffff", bg = "#262626" }
+"ui.menu" = { fg = "#ffffff", bg = "#262626" }
+"ui.menu.selected" = { fg = "#ffffff", bg = "#525252" }
+"diagnostic.error" = { fg = "#b3b3b3", bg = "#262626", underline = { color = "#ff0000", style = "curl"} }
+"diagnostic.warning" = { fg = "#b3b3b3", bg = "#262626", underline = { color = "#ff6f00", style = "curl"} }
+"error" = { fg = "#ffffff", bg = "#262626" }
+"warning" = { fg = "#ffffff", bg = "#262626" }
diff --git a/home-manager/modules/default-apps.nix b/home-manager/modules/default-apps.nix
new file mode 100644
index 0000000..7ec2b16
--- /dev/null
+++ b/home-manager/modules/default-apps.nix
@@ -0,0 +1,49 @@
+{ config, lib, ... }:
+let
+ cfg = config.default-applications;
+ mkCommand = name: lib.mkOption {
+ type = lib.types.str;
+ default = "";
+ description = "The default ${name}.";
+ };
+ mkDesktopFile = name: lib.mkOption {
+ type = lib.types.str;
+ default = "";
+ description = "The default ${name}'s .desktop file";
+ };
+in {
+ options.default-applications = {
+ web-browser = {
+ command = mkCommand "web browser";
+ desktop-file = mkDesktopFile "web browser";
+ };
+ text-editor = {
+ command = mkCommand "text editor";
+ desktop-file = mkDesktopFile "text editor";
+ };
+ image-viewer = {
+ command = mkCommand "image viewer";
+ desktop-file = mkDesktopFile "image viewer";
+ };
+ video-viewer = {
+ command = mkCommand "video viewer";
+ desktop-file = mkDesktopFile "video viewer";
+ };
+ terminal-emulator = {
+ command = mkCommand "terminal emulator";
+ runTuiCommand = mkCommand "terminal emulator run tui command";
+ runCliCommand = mkCommand "terminal emulator run cli command";
+ desktop-file = mkDesktopFile "terminal emulator";
+ };
+ };
+ config = {
+ xdg.mimeApps = {
+ enable = true;
+ defaultApplications = {
+ "text/plain" = [ cfg.text-editor.desktop-file ];
+ "text/html" = [ cfg.text-editor.desktop-file ];
+ "text/nix" = [ cfg.text-editor.desktop-file ];
+ };
+ };
+ };
+}
diff --git a/home-manager/modules/default.nix b/home-manager/modules/default.nix
new file mode 100644
index 0000000..104148e
--- /dev/null
+++ b/home-manager/modules/default.nix
@@ -0,0 +1,6 @@
+{...}: {
+ imports = [
+ ./aesthetics
+ ./default-apps.nix
+ ];
+}
diff --git a/home-manager/users/ideapad-laptop/lucas.nix b/home-manager/users/ideapad-laptop/lucas.nix
new file mode 100644
index 0000000..e5caa58
--- /dev/null
+++ b/home-manager/users/ideapad-laptop/lucas.nix
@@ -0,0 +1,61 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ home = {
+ username = "lucas";
+ homeDirectory = "/home/lucas";
+ stateVersion = "23.11";
+
+ packages = with pkgs; [
+ tor-browser
+ onlyoffice-desktopeditors
+ calibre
+
+ # My custom neovim package.
+ custom-neovim
+ neovide
+ ];
+ };
+ aesthetics = {
+ enable = true;
+ enableAllTargets = true;
+ hasGui = true;
+ theme = "oxocarbon";
+ };
+ programs.helix.package = lib.mkForce pkgs.helix; # Building helix takes too much power
+ features = {
+ gui = {
+ apps = {
+ foot.enable = true;
+ librewolf.enable = true;
+ qutebrowser.enable = true;
+ };
+ desktops.niri.enable = true;
+ };
+ cli = {
+ shells.nushell.enable = true;
+ apps = {
+ btop.enable = true;
+ helix.enable = true;
+ zellij.enable = true;
+ lazygit.enable = true;
+ };
+ utils = {
+ git.enable = true;
+ pandoc.enable = true;
+ ssh.enable = true;
+ };
+ bundles = {
+ go-env.enable = true;
+ };
+ scripts = {
+ spiral.enable = true;
+ };
+ };
+ services = {
+ udiskie.enable = true;
+ };
+ };
+}
diff --git a/home-manager/users/nzxt-desktop/culsans.nix b/home-manager/users/nzxt-desktop/culsans.nix
new file mode 100644
index 0000000..b13ba17
--- /dev/null
+++ b/home-manager/users/nzxt-desktop/culsans.nix
@@ -0,0 +1,71 @@
+{pkgs, ...}: {
+ home = {
+ username = "culsans";
+ homeDirectory = "/home/culsans";
+ stateVersion = "23.11";
+
+ packages = with pkgs; [
+ tor-browser
+ prismlauncher
+ onlyoffice-desktopeditors
+ calibre
+
+ custom-neovim
+ neovide
+
+ vintagestory
+ ];
+ };
+ # Fix Vintage Story dotnet 7 insecurity
+ nixpkgs.config.permittedInsecurePackages = ["dotnet-runtime-wrapped-7.0.20" "dotnet-runtime-7.0.20"];
+ aesthetics = {
+ enable = true;
+ enableAllTargets = true;
+ hasGui = true;
+ theme = "oxocarbon";
+ };
+ features = {
+ gui = {
+ apps = {
+ foot.enable = true;
+ librewolf.enable = true;
+ qutebrowser.enable = true;
+ vesktop.enable = true;
+ mpv.enable = true;
+ };
+ bundles = {
+ video.enable = true;
+ };
+ desktops.niri.enable = true;
+ };
+ cli = {
+ shells.nushell.enable = true;
+ apps = {
+ btop.enable = true;
+ helix.enable = true;
+ zellij.enable = true;
+ lazygit.enable = true;
+ };
+ utils = {
+ git.enable = true;
+ pandoc.enable = true;
+ ssh.enable = true;
+ };
+ bundles = {
+ go-env.enable = true;
+ };
+ scripts = {
+ spiral.enable = true;
+ };
+ };
+ services = {
+ udiskie.enable = true;
+ flatpak = {
+ enable = true;
+ packages = [
+ "at.vintagestory.VintageStory"
+ ];
+ };
+ };
+ };
+}
diff --git a/home-manager/users/prodesk-server/server.nix b/home-manager/users/prodesk-server/server.nix
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/home-manager/users/prodesk-server/server.nix
diff --git a/home-manager/users/steam-deck/culsans.nix b/home-manager/users/steam-deck/culsans.nix
new file mode 100644
index 0000000..984c272
--- /dev/null
+++ b/home-manager/users/steam-deck/culsans.nix
@@ -0,0 +1,59 @@
+{pkgs, ...}: {
+ home = {
+ username = "culsans";
+ homeDirectory = "/home/culsans";
+ stateVersion = "23.11";
+
+ packages = with pkgs; [
+ tor-browser
+ prismlauncher
+ onlyoffice-desktopeditors
+ calibre
+ vintagestory
+ ];
+ };
+ nixpkgs.config.permittedInsecurePackages = ["dotnet-runtime-wrapped-7.0.20" "dotnet-runtime-7.0.20"];
+ aesthetics = {
+ enable = true;
+ enableAllTargets = true;
+ hasGui = true;
+ theme = "oxocarbon";
+ };
+ features = {
+ gui = {
+ apps = {
+ foot.enable = true;
+ librewolf.enable = true;
+ qutebrowser.enable = true;
+ vesktop.enable = true;
+ mpv.enable = true;
+ };
+ bundles = {
+ video.enable = true;
+ };
+ desktops.niri.enable = true;
+ };
+ cli = {
+ shells.nushell.enable = true;
+ apps = {
+ btop.enable = true;
+ helix.enable = true;
+ zellij.enable = true;
+ };
+ utils = {
+ git.enable = true;
+ pandoc.enable = true;
+ ssh.enable = true;
+ };
+ bundles = {
+ go-env.enable = true;
+ };
+ scripts = {
+ spiral.enable = true;
+ };
+ };
+ services = {
+ udiskie.enable = true;
+ };
+ };
+}
diff --git a/home-manager/users/thinkpad-laptop/lucas.nix b/home-manager/users/thinkpad-laptop/lucas.nix
new file mode 100644
index 0000000..bd6ba38
--- /dev/null
+++ b/home-manager/users/thinkpad-laptop/lucas.nix
@@ -0,0 +1,61 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ home = {
+ username = "lucas";
+ homeDirectory = "/home/lucas";
+ stateVersion = "24.11";
+
+ packages = with pkgs; [
+ tor-browser
+ onlyoffice-desktopeditors
+ calibre
+
+ # My custom neovim package.
+ custom-neovim
+ neovide
+ ];
+ };
+ aesthetics = {
+ enable = true;
+ enableAllTargets = true;
+ hasGui = true;
+ theme = "oxocarbon";
+ };
+ programs.helix.package = lib.mkForce pkgs.helix; # Building helix takes too much power
+ features = {
+ gui = {
+ apps = {
+ foot.enable = true;
+ librewolf.enable = true;
+ qutebrowser.enable = true;
+ };
+ desktops.niri.enable = true;
+ };
+ cli = {
+ shells.nushell.enable = true;
+ apps = {
+ btop.enable = true;
+ helix.enable = true;
+ zellij.enable = true;
+ lazygit.enable = true;
+ };
+ utils = {
+ git.enable = true;
+ pandoc.enable = true;
+ ssh.enable = true;
+ };
+ bundles = {
+ go-env.enable = true;
+ };
+ scripts = {
+ spiral.enable = true;
+ };
+ };
+ services = {
+ udiskie.enable = true;
+ };
+ };
+}