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      config,
 17      pkgs,
 18      ...
 19    }: let
 20      natsumiSrc = pkgs.fetchFromGitHub {
 21        owner = "greeeen-dev";
 22        repo = "natsumi-browser";
 23        rev = "v6.12.4";
 24        hash = "sha256-Ur0+WjTEEY9MpGNSfLD+QzT9rcAxhv0db+oQtyOABCM=";
 25      };
 26
 27      mkChrome = {config ? "", ...}:
 28        pkgs.runCommand "floorp-natsumi-chrome" {} ''
 29          mkdir -p $out
 30          cp -r ${natsumiSrc}/natsumi $out/natsumi
 31          cp ${natsumiSrc}/userChrome.css ${natsumiSrc}/userContent.css $out/
 32          echo ${lib.escapeShellArg config} > $out/natsumi-config.css
 33        '';
 34
 35      profileDir = ".floorp/${config.programs.floorp.profiles.default.path}";
 36    in {
 37      imports = [./_hjem-module.nix];
 38
 39      files."${profileDir}/chrome" = {
 40        clobber = true;
 41        generator = mkChrome;
 42        value = {};
 43      };
 44
 45      programs.floorp = {
 46        enable = true;
 47
 48        policies = {
 49          DisableAppUpdate = true;
 50          DisablePocket = true;
 51          DisableSetDesktopBackground = true;
 52          DisableTelemetry = true;
 53          DontCheckDefaultBrowser = true;
 54          ExtensionUpdate = false;
 55          NoDefaultBookmarks = true;
 56          OfferToSaveLogins = false;
 57          PasswordManagerEnabled = false;
 58        };
 59
 60        profiles.default = {
 61          id = 0;
 62          isDefault = true;
 63
 64          search = {
 65            force = true;
 66            default = "kagi";
 67            privateDefault = "kagi";
 68            order = [
 69              "kagi"
 70              "bing"
 71              "google"
 72              "ddg"
 73            ];
 74            engines = {
 75              kagi = {
 76                name = "Kagi";
 77                description = "A privacy-focused, user-centric search engine.";
 78                urls = [
 79                  {template = "https://kagi.com/search?q={searchTerms}";}
 80                  {
 81                    type = "application/x-suggestions+json";
 82                    template = "https://kagisuggest.com/api/autosuggest?q={searchTerms}";
 83                  }
 84                ];
 85                iconMapObj = {
 86                  "16" = "https://kagi.com/favicon-16x16.png";
 87                  "32" = "https://kagi.com/favicon-32x32.png";
 88                };
 89                definedAliases = ["@kagi"];
 90              };
 91
 92              baidu.metaData.hidden = true;
 93              startpage.metaData.hidden = true;
 94              "you.com".metaData.hidden = true;
 95            };
 96          };
 97
 98          extensions.force = true;
 99          extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
100            ublock-origin
101            bitwarden
102            tampermonkey
103            kiss-translator
104          ];
105
106          settings = {
107            # == General ==
108            "browser.startup.page" = 3; # Open prev session pages
109            "browser.tabs.unloadOnLowMemory" = true;
110            "widget.use-xdg-desktop-portal.file-picker" = 1;
111            # No first run
112            "app.normandy.first_run" = false;
113            "doh-rollout.doneFirstRun" = true;
114            "toolkit.telemetry.reportingpolicy.firstRun" = false;
115            "trailhead.firstrun.didSeeAboutWelcome" = true;
116            "browser.toolbarbuttons.introduced.sidebar-button" = true;
117            "sidebar.old-sidebar.has-used" = true;
118            "sidebar.new-sidebar.has-used" = true;
119            "floorp.browser.welcome.page.shown" = true;
120            # Language
121            "general.useragent.locale" = "zh-CN";
122            "intl.locale.requested" = "zh-CN,en-US";
123            "browser.translations.mostRecentTargetLanguages" = "zh-Hans";
124            # No ads
125            "browser.urlbar.suggest.topsites" = false;
126            "browser.urlbar.suggest.trending" = false;
127            "browser.newtabpage.pinned" = [];
128            "browser.newtabpage.activity-stream.showSponsored" = false;
129            "browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
130            "browser.ai.control.sidebarChatbot" = "blocked";
131            # == Telemetry ==
132            "toolkit.telemetry.unified" = false;
133            "toolkit.telemetry.enabled" = false;
134            "toolkit.telemetry.server" = "data:,";
135            "toolkit.telemetry.archive.enabled" = false;
136            "toolkit.telemetry.newProfilePing.enabled" = false;
137            "toolkit.telemetry.shutdownPingSender.enabled" = false;
138            "toolkit.telemetry.updatePing.enabled" = false;
139            "toolkit.telemetry.bhrPing.enabled" = false;
140            "toolkit.telemetry.firstShutdownPing.enabled" = false;
141            "toolkit.telemetry.shutdownPingSender.enabledFirstsession" = false;
142            "browser.ping-centre.telemetry" = false;
143            "browser.newtabpage.activity-stream.feeds.telemetry" = false;
144            "browser.newtabpage.activity-stream.telemetry" = false;
145            # == Appearance ==
146            "browser.newtabpage.activity-stream.feeds.topsites" = false;
147            "browser.newtabpage.activity-stream.default.sites" = "";
148            "browser.toolbars.bookmarks.visibility" = "always";
149            "sidebar.verticalTabs" = true;
150            "sidebar.main.tools" = "syncedtabs";
151            "sidebar.visibility" = "always-show";
152            # Floorp's new tab page
153            "floorp.newtab.configs" = {
154              "backround"."type" = "none";
155              "components" = {
156                "topSites" = false;
157                "clock" = false;
158                "searchBar" = true;
159                "firefoxLayout" = true;
160              };
161              "searchBar" = {"searchEngine" = "default";};
162              "topSites" = {
163                "pinned" = [];
164                "blocked" = [];
165              };
166            };
167            # panelSideBar
168            "floorp.panelSidebar.enabled" = true;
169            "floorp.panelSidebar.config" = {
170              "autoUnload" = false;
171              "position_start" = true;
172              "globalWidth" = 400;
173              "displayed" = true;
174              "webExtensionRunningEnabled" = false;
175            };
176            "floorp.panelSidebar.data"."data" =
177              (lib.map (x: {
178                "id" = "default-panel-${x}";
179                "url" = "floorp//${x}";
180                "width" = 0;
181                "type" = "static";
182              }) ["bookmarks" "history" "downloads"])
183              ++ (lib.map (url: let
184                  id = lib.pipe url [
185                    (x: lib.removePrefix "http://" x)
186                    (x: lib.removePrefix "https://" x)
187                    (x: lib.splitString "?" x)
188                    (x: lib.elemAt x 0)
189                    (x: lib.replaceStrings ["/" "."] ["-" "-"] x)
190                    (x: lib.removeSuffix "-" x)
191                    (x: "panel-${x}")
192                  ];
193                in {
194                  inherit id url;
195                  "width" = 0;
196                  "userContextId" = 0;
197                  "zoomLevel" = null;
198                  "type" = "web";
199                }) [
200                  "https://translate.kagi.com"
201                  "https://squoosh.app"
202                ]);
203            # Workspace
204            "floorp.workspaces.enabled" = true;
205            "floorp.workspaces.v4.config" = {
206              "manageOnBms" = true;
207              "showWorkspaceNameOnToolbar" = true;
208            };
209            # Top toolbar
210            "browser.uiCustomization.state" = {
211              "placements" = {
212                "widget-overflow-fixed-list" = [];
213                "unified-extensions-area" = [
214                  "firefox_tampermonkey_net-browser-action" # Tampermonkey
215                  "ublock0_raymondhill_net-browser-action" # uBlock Origin
216                  "_fb25c100-22ce-4d5a-be7e-75f3d6f0fc13_-browser-action" # Kiss Translator
217                ];
218                "nav-bar" = [
219                  "sidebar-button"
220                  "back-button"
221                  "forward-button"
222                  "stop-reload-button"
223                  "urlbar-container"
224                  "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action"
225                  "unified-extensions-button"
226                  "reset-pbm-toolbar-button"
227                  "fxa-toolbar-menu-button"
228                ];
229                "toolbar-menubar" = ["menubar-items"];
230                "TabsToolbar" = [];
231                "vertical-tabs" = ["tabbrowser-tabs"];
232                "PersonalToolbar" = ["personal-bookmarks"];
233                "nora-statusbar" = [
234                  "screenshot-button"
235                  "fullscreen-button"
236                  "status-text"
237                ];
238              };
239              # I don't know what "seen" means, but toolbar will reset without them
240              "seen" = [
241                "developer-button"
242                "reset-pbm-toolbar-button"
243                "firefox_tampermonkey_net-browser-action"
244                "ublock0_raymondhill_net-browser-action"
245                "_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action"
246                "_fb25c100-22ce-4d5a-be7e-75f3d6f0fc13_-browser-action"
247                "ipprotection-button"
248                "profile-manager-button"
249                "undo-closed-tab"
250                "zen-mode-button"
251                "workspaces-toolbar-button"
252                "screenshot-button"
253              ];
254              "dirtyAreaCache" = [
255                "unified-extensions-area"
256                "nav-bar"
257                "toolbar-menubar"
258                "TabsToolbar"
259                "vertical-tabs"
260                "PersonalToolbar"
261                "nora-statusbar"
262              ];
263              "currentVersion" = 28;
264              "newElementCount" = 3;
265            };
266            # == Natsumi ==
267            "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
268            "layout.css.backdrop-filter.enabled" = true;
269            "layout.css.backdrop-filter.force-enabled" = true;
270
271            "natsumi.browser.type" = "floorp";
272            "natsumi.updater.disabled" = true;
273            "natsumi.welcome.viewed" = true;
274            "natsumi.startup.sound" = false;
275            "natsumi.browser.ignore-security-notice" = true;
276            "natsumi.theme.floorp-hide-preferences-warnings" = true;
277
278            "natsumi.pdfjs.disabled" = false;
279
280            "natsumi.theme.compact-extensions" = true;
281            "natsumi.urlbar.always-expanded" = true;
282
283            "natsumi.tabs.use-custom-type" = false;
284          };
285        };
286      };
287    };
288  };
289
290  den.aspects.desktop.app.browser.floorp.themes = {
291    catppuccin = {
292      hjem = {config, ...}: {
293        # files.".floorp/${config.programs.floorp.profiles.default.path}/natsumi-theme/master.json".source = ./catppuccin-natsumi.json;
294        files.".floorp/${config.programs.floorp.profiles.default.path}/chrome".value.config = ''
295          * {
296            --natsumi-accent-color: #cba6f7;
297            --natsumi-theme-layer-0-opacity: 0.85;
298            --natsumi-theme-layer-0-background: hsl(240deg, 21%, 15%);
299          }
300        '';
301
302        programs.floorp.profiles.default.settings = {
303          "natsumi.theme.type" = "custom";
304        };
305      };
306    };
307  };
308}