diff --git a/home/programs/qutebrowser/bookmarks.nix b/home/programs/qutebrowser/bookmarks/default.nix similarity index 51% rename from home/programs/qutebrowser/bookmarks.nix rename to home/programs/qutebrowser/bookmarks/default.nix index 3bdb6e6..4c2877e 100644 --- a/home/programs/qutebrowser/bookmarks.nix +++ b/home/programs/qutebrowser/bookmarks/default.nix @@ -4,178 +4,32 @@ pkgs, ... }: let - bookmarkList = [ - { - name = "Proton Mail"; - url = "https://mail.proton.me"; - } - { - name = "Proton Drive"; - url = "https://drive.proton.me"; - } - { - name = "Proton Lumo"; - url = "https://lumo.proton.me"; - } - { - name = "Proton Calendar"; - url = "https://calendar.proton.me"; - } - { - name = "Tools"; - bookmarks = [ - { - name = "tldr"; - url = "https://tldr.inbrowser.app/"; - } - { - name = "Excalidraw"; - url = "https://excalidraw.com"; - } - { - name = "Cobalt (downloader)"; - url = "https://cobalt.meowing.de"; - } - { - name = "Mazanoke (image)"; - url = "https://mazanoke.hadi.icu"; - } - { - name = "Stirling PDF"; - url = "https://pdf.hadi.icu"; - } - { - name = "Vert"; - url = "https://vert.sh"; - } - { - name = "Markdown to PDF"; - url = "https://md2file.com"; - } - { - name = "Image to Vector"; - url = "https://www.vectorcascade.com/"; - } - { - name = "PrivateBin"; - url = "https://privatebin.net"; - } - ]; - } - { - name = "Social"; - bookmarks = [ - { - name = "Bluesky"; - url = "https://bsky.app"; - } - { - name = "Reddit"; - url = "https://reddit.com"; - } - { - name = "Youtube"; - url = "https://youtube.com"; - } - { - name = "Instagram"; - url = "https://instagram.com"; - } - { - name = "Github"; - url = "https://github.com"; - } - { - name = "Discord"; - url = "https://discord.com/channels/@me/"; - } - ]; - } - { - name = "Other"; - bookmarks = [ - { - name = "Startpage Config"; - url = "https://www.startpage.com/do/mypage.pl?prfe=45d331deb05471d659dba933e7400df51d952bb103da6f6125c0e769a6be1d65610456a479f495ceeee7e97311cf227d7c1bb198de0ceeb193d8cddf9c455c19a409cc35c3e3f542ee27bd7cecd3"; - } - { - name = "Hyprland Wiki"; - url = "https://wiki.hypr.land"; - } - { - name = "MyNixOS"; - url = "https://mynixos.com"; - } - { - name = "Nixpkgs"; - url = "https://github.com/NixOS/nixpkgs"; - } - { - name = "Claude"; - url = "https://claude.ai"; - } - { - name = "Gemini"; - url = "https://gemini.google.com"; - } - { - name = "Medium"; - url = "https://medium.com"; - } - { - name = "Maps"; - url = "https://maps.apple.com"; - } - { - name = "Amazon"; - url = "https://amazon.fr"; - } - ]; - } - { - name = "Infosec"; - bookmarks = [ - { - name = "Nix 4 Cyber"; - url = "https://n4c.hadi.icu"; - } - { - name = "Cyberchef"; - url = "https://cyberchef.hadi.icu"; - } - { - name = "TryHackMe"; - url = "https://tryhackme.com"; - } - { - name = "Root-Me"; - url = "https://root-me.org"; - } - { - name = "Exploit-DB"; - url = "https://exploit-db.com"; - } - { - name = "Crack Station"; - url = "https://crackstation.net"; - } - { - name = "Osint Tracker"; - url = "https://app.osintracker.com"; - } - ]; - } - ]; + bookmarkList = + (import ./general.nix) + ++ (import ./tools.nix) + ++ (import ./social.nix) + ++ (import ./infosec.nix) + ++ (import ./other.nix) + ++ (import ./jack.nix); c = config.lib.stylix.colors; stripProtocol = url: lib.removePrefix "https://" (lib.removePrefix "http://" url); - mkCard = item: '' + stripDomain = url: + builtins.head ( + lib.splitString "/" (stripProtocol url) + ); + + mkCard = item: let + domain = stripDomain item.url; + initial = builtins.substring 0 1 item.name; + in ''
- ${builtins.substring 0 1 item.name} + +
${item.name} @@ -183,6 +37,54 @@
''; + # Render a list of items (cards and/or sub-folders) inside a folder + mkFolderContent = items: let + step = acc: item: + if item ? url + then acc // {pending = acc.pending ++ [item];} + else { + chunks = + acc.chunks + ++ lib.optional (acc.pending != []) { + isCards = true; + items = acc.pending; + } + ++ [{isCards = false; folder = item;}]; + pending = []; + }; + result = lib.foldl' step {chunks = []; pending = [];} items; + chunks = + result.chunks + ++ lib.optional (result.pending != []) { + isCards = true; + items = result.pending; + }; + in + lib.concatMapStrings (chunk: + if chunk.isCards + then '' +
+ ${lib.concatMapStrings mkCard chunk.items} +
'' + else mkFolder chunk.folder) + chunks; + + mkFolder = folder: let + iconHtml = + if folder ? icon + then '''' + else ""; + in '' +
+ + ${iconHtml}${folder.name} + + +
+ ${mkFolderContent folder.bookmarks} +
+
''; + # Group consecutive root items so they share the same .cards grid grouped = let step = acc: item: @@ -195,12 +97,7 @@ isRoot = true; items = acc.pending; } - ++ [ - { - isRoot = false; - inherit item; - } - ]; + ++ [{isRoot = false; inherit item;}]; pending = []; }; result = @@ -219,30 +116,24 @@ mkSection = group: if group.isRoot then '' -
+
${lib.concatMapStrings mkCard group.items}
-
- '' - else '' -
-

${group.item.name}

-
- ${lib.concatMapStrings mkCard group.item.bookmarks} -
-
- ''; +
'' + else mkFolder group.item; + + # Recursively collect all leaf bookmarks with their full folder path + collectBookmarks = prefix: items: + lib.concatMapStrings (item: + if item ? url + then "${item.url} ${prefix}${item.name}\n" + else collectBookmarks "${prefix}${item.name}/" item.bookmarks + ) items; publicBookmarks = pkgs.writeText "qutebrowser-public-bookmarks" - (lib.concatMapStrings ( - item: - if item ? url - then "${item.url} ${item.name}\n" - else lib.concatMapStrings (b: "${b.url} ${item.name}/${b.name}\n") item.bookmarks - ) - bookmarkList); + (collectBookmarks "" bookmarkList); inherit (config.qutebrowser) privateBookmarksPath; in { @@ -253,7 +144,6 @@ in { }; config = { - # Fully static HTML — order is preserved, no dependency on qutebrowser's Jinja rendering xdg.dataFile."qutebrowser/bookmarks.html".text = '' @@ -261,6 +151,7 @@ in { Bookmarks +