main
  1{
  2  den,
  3  lib,
  4  ...
  5}: {
  6  den.aspects.desktop.app.browser.floorp = {
  7    includes = [den.aspects.desktop.app.browser];
  8
  9    persistHome = {config, ...}: {
 10      directories = [
 11        "${config.directory}/.floorp"
 12      ];
 13    };
 14
 15    hjem = {
 16      host,
 17      pkgs,
 18      ...
 19    }: let
 20      fontsCfg = host.settings.desktop.aesthetic.fonts;
 21    in {
 22      imports = [./_hjem-module.nix];
 23
 24      programs.floorp = {
 25        enable = true;
 26
 27        policies = {
 28          DisableAppUpdate = true;
 29          DisablePocket = true;
 30          DisableSetDesktopBackground = true;
 31          DisableTelemetry = true;
 32          DontCheckDefaultBrowser = true;
 33          ExtensionUpdate = false;
 34          NoDefaultBookmarks = true;
 35          OfferToSaveLogins = false;
 36          PasswordManagerEnabled = false;
 37        };
 38
 39        profiles.default = {
 40          id = 0;
 41          isDefault = true;
 42
 43          search = {
 44            force = true;
 45            default = "kagi";
 46            privateDefault = "kagi";
 47            order = [
 48              "kagi"
 49              "bing"
 50              "google"
 51              "ddg"
 52            ];
 53            engines = {
 54              kagi = {
 55                name = "Kagi";
 56                description = "A privacy-focused, user-centric search engine.";
 57                urls = [
 58                  {template = "https://kagi.com/search?q={searchTerms}";}
 59                  {
 60                    type = "application/x-suggestions+json";
 61                    template = "https://kagisuggest.com/api/autosuggest?q={searchTerms}";
 62                  }
 63                ];
 64                iconMapObj = {
 65                  "16" = "https://kagi.com/favicon-16x16.png";
 66                  "32" = "https://kagi.com/favicon-32x32.png";
 67                };
 68                definedAliases = ["@kagi"];
 69              };
 70
 71              baidu.metaData.hidden = true;
 72              startpage.metaData.hidden = true;
 73              "you.com".metaData.hidden = true;
 74            };
 75          };
 76
 77          extensions.force = true;
 78          extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
 79            ublock-origin
 80            bitwarden
 81            tampermonkey
 82            kiss-translator
 83          ];
 84
 85          settings = {
 86            # == General ==
 87            "browser.startup.page" = 3; # Open prev session pages
 88            "browser.tabs.unloadOnLowMemory" = true;
 89            "widget.use-xdg-desktop-portal.file-picker" = 1;
 90            # No first run
 91            "app.normandy.first_run" = false;
 92            "doh-rollout.doneFirstRun" = true;
 93            "toolkit.telemetry.reportingpolicy.firstRun" = false;
 94            "trailhead.firstrun.didSeeAboutWelcome" = true;
 95            "browser.toolbarbuttons.introduced.sidebar-button" = true;
 96            "sidebar.old-sidebar.has-used" = true;
 97            "sidebar.new-sidebar.has-used" = true;
 98            "floorp.browser.welcome.page.shown" = true;
 99            # Language
100            "general.useragent.locale" = "zh-CN";
101            "intl.locale.requested" = "zh-CN,en-US";
102            "browser.translations.mostRecentTargetLanguages" = "zh-Hans";
103            # No ads
104            "browser.urlbar.suggest.topsites" = false;
105            "browser.urlbar.suggest.trending" = false;
106            "browser.newtabpage.pinned" = [];
107            "browser.newtabpage.activity-stream.showSponsored" = false;
108            "browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
109            "browser.ai.control.sidebarChatbot" = "blocked";
110            # == Telemetry ==
111            "toolkit.telemetry.unified" = false;
112            "toolkit.telemetry.enabled" = false;
113            "toolkit.telemetry.server" = "data:,";
114            "toolkit.telemetry.archive.enabled" = false;
115            "toolkit.telemetry.newProfilePing.enabled" = false;
116            "toolkit.telemetry.shutdownPingSender.enabled" = false;
117            "toolkit.telemetry.updatePing.enabled" = false;
118            "toolkit.telemetry.bhrPing.enabled" = false;
119            "toolkit.telemetry.firstShutdownPing.enabled" = false;
120            "toolkit.telemetry.shutdownPingSender.enabledFirstsession" = false;
121            "browser.ping-centre.telemetry" = false;
122            "browser.newtabpage.activity-stream.feeds.telemetry" = false;
123            "browser.newtabpage.activity-stream.telemetry" = false;
124            # == Appearance ==
125            "font.name.monospace.x-western" = (builtins.elemAt fontsCfg.monospace 0).name;
126            "font.name.sans-serif.x-western" = (builtins.elemAt fontsCfg.sansSerif 0).name;
127            "browser.newtabpage.activity-stream.feeds.topsites" = false;
128            "browser.newtabpage.activity-stream.default.sites" = "";
129            "browser.toolbars.bookmarks.visibility" = "always";
130            "sidebar.verticalTabs" = true;
131            "sidebar.main.tools" = "syncedtabs";
132            "sidebar.visibility" = "expand-on-hover";
133            # Floorp's new tab page
134            "floorp.newtab.configs" = {
135              "backround"."type" = "none";
136              "components" = {
137                "topSites" = false;
138                "clock" = false;
139                "searchBar" = true;
140                "firefoxLayout" = true;
141              };
142              "searchBar" = {"searchEngine" = "default";};
143              "topSites" = {
144                "pinned" = [];
145                "blocked" = [];
146              };
147            };
148            # panelSideBar
149            "floorp.panelSidebar.enabled" = true;
150            "floorp.panelSidebar.config" = {
151              "autoUnload" = false;
152              "position_start" = true;
153              "globalWidth" = 400;
154              "displayed" = true;
155              "webExtensionRunningEnabled" = false;
156            };
157            "floorp.panelSidebar.data"."data" =
158              (lib.map (x: {
159                "id" = "default-panel-${x}";
160                "url" = "floorp//${x}";
161                "width" = 0;
162                "type" = "static";
163              }) ["bookmarks" "history" "downloads"])
164              ++ (lib.map (url: let
165                  id = lib.pipe url [
166                    (x: lib.removePrefix "http://" x)
167                    (x: lib.removePrefix "https://" x)
168                    (x: lib.splitString "?" x)
169                    (x: lib.elemAt x 0)
170                    (x: lib.replaceStrings ["/" "."] ["-" "-"] x)
171                    (x: lib.removeSuffix "-" x)
172                    (x: "panel-${x}")
173                  ];
174                in {
175                  inherit id url;
176                  "width" = 0;
177                  "userContextId" = 0;
178                  "zoomLevel" = null;
179                  "type" = "web";
180                }) [
181                  "https://translate.kagi.com"
182                  "https://squoosh.app"
183                ]);
184            # Workspace
185            "floorp.workspaces.enabled" = true;
186            "floorp.workspaces.v4.config" = {
187              "manageOnBms" = true;
188              "showWorkspaceNameOnToolbar" = true;
189            };
190            # Top toolbar
191            "browser.uiCustomization.state" = {
192              "placements" = {
193                "widget-overflow-fixed-list" = [];
194                "unified-extensions-area" = [
195                  "firefox_tampermonkey_net-browser-action" # Tampermonkey
196                  "ublock0_raymondhill_net-browser-action" # uBlock Origin
197                ];
198                "nav-bar" = [
199                  "sidebar-button"
200                  "back-button"
201                  "forward-button"
202                  "stop-reload-button"
203                  "vertical-spacer"
204                  "urlbar-container"
205                  "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action" # Bitwarden
206                  "unified-extensions-button"
207                  "fxa-toolbar-menu-button"
208                ];
209                "toolbar-menubar" = ["menubar-items"];
210                "TabsToolbar" = [];
211                "vertical-tabs" = ["tabbrowser-tabs"];
212                "PersonalToolbar" = ["personal-bookmarks"];
213                "nora-statusbar" = [
214                  "screenshot-button"
215                  "fullscreen-button"
216                  "status-text"
217                ];
218              };
219              "seen" = ["developer-button"];
220              "dirtyAreaCache" = [];
221            };
222          };
223        };
224      };
225    };
226  };
227
228  den.aspects.desktop.app.browser.floorp.themes = {
229    catppuccin = {
230      hjem = {
231        pkgs,
232        lib,
233        ...
234      }: let
235        # From catppuccin/nix
236        # Use static version to avoid IFD
237        themes = lib.importJSON ./catppuccin-firefox-themes.json;
238      in {
239        programs.floorp = {
240          profiles.default = {
241            extensions = {
242              packages = with pkgs.nur.repos.rycee.firefox-addons; [
243                firefox-color
244              ];
245              settings."FirefoxColor@mozilla.com" = {
246                force = true;
247                settings = {
248                  firstRunDone = true;
249                  theme = themes.mocha.mauve;
250                };
251              };
252            };
253          };
254        };
255      };
256    };
257  };
258}