Small European communities to support better digital choices

Better Tech Club website

The Better Tech Club website is a welcoming entry point to a community-oriented advocacy for digital independence. It serves as a hub for a network of local, off-line first groups promoting free and open source software (FOSS) in Europe. A place where community organizers find each other to share experience and collaborate, but most of all for regular people looking to connect with like-minded neighbors.

The website prioritizes accessibility; positive, user-friendly design; and semantic correctness. It evolves through a transparent, commit-driven process (see the Devlog below). It is deployed as a static site hosted on Codeberg Pages – itself a community operated service that perfectly aligns with our values.

Originally launched as "FOSS for Normies," the project was rebranded to Better Tech Club – a more accessible name, reflecting our conviction that the ethical, sustainable, and inclusive tech choices we promote are simply better than Big Tech alternatives.

https://bettertechclub.eu

Development Environment

The project utilizes Nix Flakes combined with Devenv to create a fully isolated and reproducible development environment. This setup guarantees that every contributor works with identical versions of tools, eliminating "it works on my machine" issues. The development environment includes:

Front-End Practices

To invite wider collaboration we avoid heavy frameworks in favor of semantic HTML5 and modern CSS3, focusing on performance and accessibility:

Branding and Assets

Branding assets, like the logotype and icons, are created as SVG files to ensure infinite scalability and crisp rendering on any device. The color palette is anchored by a deep blue and a vibrant yellow, chosen for their high contrast and friendly aesthetic. The site supports progressive web app (PWA) standards with a comprehensive site.webmanifest and a full suite of touch icons for seamless installation on mobile devices.

Latest developments

from see older.

Upgrade TBB

On by Tad Lispy

index f1c3398..f611911 100644
--- a/flake.lock
+++ b/flake.lock
@@ -114,11 +114,73 @@
=        ]
=      },
=      "locked": {
-        "lastModified": 1760971495,
-        "narHash": "sha256-IwnNtbNVrlZIHh7h4Wz6VP0Furxg9Hh0ycighvL5cZc=",
+        "lastModified": 1774017633,
+        "narHash": "sha256-CWhnwL2M83/ItapPVeJqCevRoQttesYxJ1h0Mo6ZCXs=",
=        "owner": "cachix",
=        "repo": "cachix",
-        "rev": "c5bfd933d1033672f51a863c47303fc0e093c2d2",
+        "rev": "e8be573b417f3daa3dd4cb9052178f848e0c9d1d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "ref": "latest",
+        "repo": "cachix",
+        "type": "github"
+      }
+    },
+    "cachix_5": {
+      "inputs": {
+        "devenv": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix"
+        ],
+        "flake-compat": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix"
+        ],
+        "git-hooks": "git-hooks_4",
+        "nixpkgs": "nixpkgs_5"
+      },
+      "locked": {
+        "lastModified": 1767714506,
+        "narHash": "sha256-WaTs0t1CxhgxbIuvQ97OFhDTVUGd1HA+KzLZUZBhe0s=",
+        "owner": "cachix",
+        "repo": "cachix",
+        "rev": "894c649f0daaa38bbcfb21de64be47dfa7cd0ec9",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "ref": "latest",
+        "repo": "cachix",
+        "type": "github"
+      }
+    },
+    "cachix_6": {
+      "inputs": {
+        "devenv": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable"
+        ],
+        "flake-compat": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable"
+        ],
+        "git-hooks": "git-hooks_5",
+        "nixpkgs": "nixpkgs_6"
+      },
+      "locked": {
+        "lastModified": 1767714506,
+        "narHash": "sha256-WaTs0t1CxhgxbIuvQ97OFhDTVUGd1HA+KzLZUZBhe0s=",
+        "owner": "cachix",
+        "repo": "cachix",
+        "rev": "894c649f0daaa38bbcfb21de64be47dfa7cd0ec9",
=        "type": "github"
=      },
=      "original": {
@@ -157,6 +219,36 @@
=        "type": "github"
=      }
=    },
+    "crate2nix_2": {
+      "inputs": {
+        "cachix": "cachix_5",
+        "crate2nix_stable": "crate2nix_stable_2",
+        "devshell": "devshell_4",
+        "flake-compat": "flake-compat_5",
+        "flake-parts": "flake-parts_5",
+        "nix-test-runner": "nix-test-runner_4",
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "nixpkgs"
+        ],
+        "pre-commit-hooks": "pre-commit-hooks_4"
+      },
+      "locked": {
+        "lastModified": 1772186516,
+        "narHash": "sha256-8s28pzmQ6TOIUzznwFibtW1CMieMUl1rYJIxoQYor58=",
+        "owner": "rossng",
+        "repo": "crate2nix",
+        "rev": "ba5dd398e31ee422fbe021767eb83b0650303a6e",
+        "type": "github"
+      },
+      "original": {
+        "owner": "rossng",
+        "repo": "crate2nix",
+        "rev": "ba5dd398e31ee422fbe021767eb83b0650303a6e",
+        "type": "github"
+      }
+    },
=    "crate2nix_stable": {
=      "inputs": {
=        "cachix": "cachix_3",
@@ -187,6 +279,37 @@
=        "type": "github"
=      }
=    },
+    "crate2nix_stable_2": {
+      "inputs": {
+        "cachix": "cachix_6",
+        "crate2nix_stable": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable"
+        ],
+        "devshell": "devshell_3",
+        "flake-compat": "flake-compat_4",
+        "flake-parts": "flake-parts_4",
+        "nix-test-runner": "nix-test-runner_3",
+        "nixpkgs": "nixpkgs_7",
+        "pre-commit-hooks": "pre-commit-hooks_3"
+      },
+      "locked": {
+        "lastModified": 1769627083,
+        "narHash": "sha256-SUuruvw1/moNzCZosHaa60QMTL+L9huWdsCBN6XZIic=",
+        "owner": "nix-community",
+        "repo": "crate2nix",
+        "rev": "7c33e664668faecf7655fa53861d7a80c9e464a2",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "ref": "0.15.0",
+        "repo": "crate2nix",
+        "type": "github"
+      }
+    },
=    "devenv": {
=      "inputs": {
=        "cachix": "cachix",
@@ -218,21 +341,24 @@
=    "devenv_2": {
=      "inputs": {
=        "cachix": "cachix_4",
-        "flake-compat": "flake-compat_4",
-        "flake-parts": "flake-parts_4",
-        "git-hooks": "git-hooks_4",
+        "crate2nix": "crate2nix_2",
+        "flake-compat": "flake-compat_6",
+        "flake-parts": "flake-parts_6",
+        "git-hooks": "git-hooks_6",
=        "nix": "nix_2",
+        "nixd": "nixd_2",
=        "nixpkgs": [
=          "tad-better-behavior",
=          "nixpkgs"
-        ]
+        ],
+        "rust-overlay": "rust-overlay_2"
=      },
=      "locked": {
-        "lastModified": 1762889687,
-        "narHash": "sha256-oKvHfeYDZ0LfuHSaFLA0w/dfZ9R6C5W8pCGUjUWawGI=",
+        "lastModified": 1777040077,
+        "narHash": "sha256-21hK/8gia6FbcE2+R49WNCD24yd6Qf0VPpiYi1qEI3I=",
=        "owner": "cachix",
=        "repo": "devenv",
-        "rev": "3b4fb549962342c928aae1bbea3a13f0eeed2703",
+        "rev": "0b0246b7fed27e788d639cb82364c452b405970c",
=        "type": "github"
=      },
=      "original": {
@@ -286,6 +412,53 @@
=        "type": "github"
=      }
=    },
+    "devshell_3": {
+      "inputs": {
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1768818222,
+        "narHash": "sha256-460jc0+CZfyaO8+w8JNtlClB2n4ui1RbHfPTLkpwhU8=",
+        "owner": "numtide",
+        "repo": "devshell",
+        "rev": "255a2b1725a20d060f566e4755dbf571bbbb5f76",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "devshell",
+        "type": "github"
+      }
+    },
+    "devshell_4": {
+      "inputs": {
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1768818222,
+        "narHash": "sha256-460jc0+CZfyaO8+w8JNtlClB2n4ui1RbHfPTLkpwhU8=",
+        "owner": "numtide",
+        "repo": "devshell",
+        "rev": "255a2b1725a20d060f566e4755dbf571bbbb5f76",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "devshell",
+        "type": "github"
+      }
+    },
=    "flake-compat": {
=      "locked": {
=        "lastModified": 1733328505,
@@ -331,13 +504,41 @@
=      }
=    },
=    "flake-compat_4": {
+      "locked": {
+        "lastModified": 1733328505,
+        "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+        "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+        "revCount": 69,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
+    "flake-compat_5": {
+      "locked": {
+        "lastModified": 1733328505,
+        "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+        "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+        "revCount": 69,
+        "type": "tarball",
+        "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
+      }
+    },
+    "flake-compat_6": {
=      "flake": false,
=      "locked": {
-        "lastModified": 1761588595,
-        "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
+        "lastModified": 1767039857,
+        "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
=        "owner": "edolstra",
=        "repo": "flake-compat",
-        "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
+        "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
=        "type": "github"
=      },
=      "original": {
@@ -417,15 +618,62 @@
=        "nixpkgs-lib": [
=          "tad-better-behavior",
=          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
=          "nixpkgs"
=        ]
=      },
=      "locked": {
-        "lastModified": 1760948891,
-        "narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
+        "lastModified": 1768135262,
+        "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
=        "owner": "hercules-ci",
=        "repo": "flake-parts",
-        "rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
+        "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "flake-parts_5": {
+      "inputs": {
+        "nixpkgs-lib": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1768135262,
+        "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "type": "github"
+      }
+    },
+    "flake-parts_6": {
+      "inputs": {
+        "nixpkgs-lib": [
+          "tad-better-behavior",
+          "devenv",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1775087534,
+        "narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
=        "type": "github"
=      },
=      "original": {
@@ -517,46 +765,207 @@
=        "type": "github"
=      },
=      "original": {
-        "owner": "cachix",
-        "repo": "git-hooks.nix",
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "type": "github"
+      }
+    },
+    "git-hooks_4": {
+      "inputs": {
+        "flake-compat": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "cachix",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore_6",
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "cachix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1765404074,
+        "narHash": "sha256-+ZDU2d+vzWkEJiqprvV5PR26DVFN2vgddwG5SnPZcUM=",
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "rev": "2d6f58930fbcd82f6f9fd59fb6d13e37684ca529",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "type": "github"
+      }
+    },
+    "git-hooks_5": {
+      "inputs": {
+        "flake-compat": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
+          "cachix",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore_7",
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
+          "cachix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1765404074,
+        "narHash": "sha256-+ZDU2d+vzWkEJiqprvV5PR26DVFN2vgddwG5SnPZcUM=",
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "rev": "2d6f58930fbcd82f6f9fd59fb6d13e37684ca529",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "type": "github"
+      }
+    },
+    "git-hooks_6": {
+      "inputs": {
+        "flake-compat": [
+          "tad-better-behavior",
+          "devenv",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore_10",
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1775585728,
+        "narHash": "sha256-8Psjt+TWvE4thRKktJsXfR6PA/fWWsZ04DVaY6PUhr4=",
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "rev": "580633fa3fe5fc0379905986543fd7495481913d",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "git-hooks.nix",
+        "type": "github"
+      }
+    },
+    "gitignore": {
+      "inputs": {
+        "nixpkgs": [
+          "devenv",
+          "crate2nix",
+          "cachix",
+          "git-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "gitignore_10": {
+      "inputs": {
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "git-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "type": "github"
+      }
+    },
+    "gitignore_2": {
+      "inputs": {
+        "nixpkgs": [
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
+          "cachix",
+          "git-hooks",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "type": "github"
+      },
+      "original": {
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
=        "type": "github"
=      }
=    },
-    "git-hooks_4": {
+    "gitignore_3": {
=      "inputs": {
-        "flake-compat": [
-          "tad-better-behavior",
-          "devenv",
-          "flake-compat"
-        ],
-        "gitignore": "gitignore_6",
=        "nixpkgs": [
-          "tad-better-behavior",
=          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
+          "pre-commit-hooks",
=          "nixpkgs"
=        ]
=      },
=      "locked": {
-        "lastModified": 1760663237,
-        "narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=",
-        "owner": "cachix",
-        "repo": "git-hooks.nix",
-        "rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37",
+        "lastModified": 1709087332,
+        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
+        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
=        "type": "github"
=      },
=      "original": {
-        "owner": "cachix",
-        "repo": "git-hooks.nix",
+        "owner": "hercules-ci",
+        "repo": "gitignore.nix",
=        "type": "github"
=      }
=    },
-    "gitignore": {
+    "gitignore_4": {
=      "inputs": {
=        "nixpkgs": [
=          "devenv",
=          "crate2nix",
-          "cachix",
-          "git-hooks",
+          "pre-commit-hooks",
=          "nixpkgs"
=        ]
=      },
@@ -574,13 +983,10 @@
=        "type": "github"
=      }
=    },
-    "gitignore_2": {
+    "gitignore_5": {
=      "inputs": {
=        "nixpkgs": [
=          "devenv",
-          "crate2nix",
-          "crate2nix_stable",
-          "cachix",
=          "git-hooks",
=          "nixpkgs"
=        ]
@@ -599,13 +1005,14 @@
=        "type": "github"
=      }
=    },
-    "gitignore_3": {
+    "gitignore_6": {
=      "inputs": {
=        "nixpkgs": [
+          "tad-better-behavior",
=          "devenv",
=          "crate2nix",
-          "crate2nix_stable",
-          "pre-commit-hooks",
+          "cachix",
+          "git-hooks",
=          "nixpkgs"
=        ]
=      },
@@ -623,12 +1030,15 @@
=        "type": "github"
=      }
=    },
-    "gitignore_4": {
+    "gitignore_7": {
=      "inputs": {
=        "nixpkgs": [
+          "tad-better-behavior",
=          "devenv",
=          "crate2nix",
-          "pre-commit-hooks",
+          "crate2nix_stable",
+          "cachix",
+          "git-hooks",
=          "nixpkgs"
=        ]
=      },
@@ -646,11 +1056,14 @@
=        "type": "github"
=      }
=    },
-    "gitignore_5": {
+    "gitignore_8": {
=      "inputs": {
=        "nixpkgs": [
+          "tad-better-behavior",
=          "devenv",
-          "git-hooks",
+          "crate2nix",
+          "crate2nix_stable",
+          "pre-commit-hooks",
=          "nixpkgs"
=        ]
=      },
@@ -668,12 +1081,13 @@
=        "type": "github"
=      }
=    },
-    "gitignore_6": {
+    "gitignore_9": {
=      "inputs": {
=        "nixpkgs": [
=          "tad-better-behavior",
=          "devenv",
-          "git-hooks",
+          "crate2nix",
+          "pre-commit-hooks",
=          "nixpkgs"
=        ]
=      },
@@ -763,6 +1177,38 @@
=        "type": "github"
=      }
=    },
+    "nix-test-runner_3": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1588761593,
+        "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=",
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2",
+        "type": "github"
+      },
+      "original": {
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "type": "github"
+      }
+    },
+    "nix-test-runner_4": {
+      "flake": false,
+      "locked": {
+        "lastModified": 1588761593,
+        "narHash": "sha256-FKJykltAN/g3eIceJl4SfDnnyuH2jHImhMrXS2KvGIs=",
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "rev": "c45d45b11ecef3eb9d834c3b6304c05c49b06ca2",
+        "type": "github"
+      },
+      "original": {
+        "owner": "stoeffel",
+        "repo": "nix-test-runner",
+        "type": "github"
+      }
+    },
=    "nix_2": {
=      "inputs": {
=        "flake-compat": [
@@ -795,16 +1241,16 @@
=        ]
=      },
=      "locked": {
-        "lastModified": 1761648602,
-        "narHash": "sha256-H97KSB/luq/aGobKRuHahOvT1r7C03BgB6D5HBZsbN8=",
+        "lastModified": 1776511668,
+        "narHash": "sha256-g2KEBuHpc3a56c+jPcg0+w6LSuIj6f+zzdztLCOyIhc=",
=        "owner": "cachix",
=        "repo": "nix",
-        "rev": "3e5644da6830ef65f0a2f7ec22830c46285bfff6",
+        "rev": "42d4b7de21c15f28c568410f4383fa06a8458a40",
=        "type": "github"
=      },
=      "original": {
=        "owner": "cachix",
-        "ref": "devenv-2.30.6",
+        "ref": "devenv-2.34",
=        "repo": "nix",
=        "type": "github"
=      }
@@ -835,6 +1281,30 @@
=        "type": "github"
=      }
=    },
+    "nixd_2": {
+      "inputs": {
+        "flake-parts": [
+          "tad-better-behavior",
+          "devenv",
+          "flake-parts"
+        ],
+        "nixpkgs": "nixpkgs_8",
+        "treefmt-nix": "treefmt-nix_2"
+      },
+      "locked": {
+        "lastModified": 1776341634,
+        "narHash": "sha256-L//ltP2o5+BnuK+KEulbi2gGeDpyyex6SkXLZcGQ/Ac=",
+        "owner": "nix-community",
+        "repo": "nixd",
+        "rev": "951e98e2025c47614f5249556ecf509b0ea35b51",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nixd",
+        "type": "github"
+      }
+    },
=    "nixpkgs": {
=      "locked": {
=        "lastModified": 1765186076,
@@ -919,6 +1389,67 @@
=        "type": "github"
=      }
=    },
+    "nixpkgs_5": {
+      "locked": {
+        "lastModified": 1765186076,
+        "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_6": {
+      "locked": {
+        "lastModified": 1765186076,
+        "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_7": {
+      "locked": {
+        "lastModified": 1769433173,
+        "narHash": "sha256-Gf1dFYgD344WZ3q0LPlRoWaNdNQq8kSBDLEWulRQSEs=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "13b0f9e6ac78abbbb736c635d87845c4f4bee51b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs_8": {
+      "locked": {
+        "lastModified": 1772963539,
+        "narHash": "sha256-G4+9cEu8XSqEWYUB6iRgDfrg53av6yyRwAKhSeKbUVw=",
+        "rev": "9dcb002ca1690658be4a04645215baea8b95f31d",
+        "type": "tarball",
+        "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre960399.9dcb002ca169/nixexprs.tar.xz"
+      },
+      "original": {
+        "type": "tarball",
+        "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
+      }
+    },
=    "pre-commit-hooks": {
=      "inputs": {
=        "flake-compat": [
@@ -977,6 +1508,68 @@
=        "type": "github"
=      }
=    },
+    "pre-commit-hooks_3": {
+      "inputs": {
+        "flake-compat": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore_8",
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "crate2nix_stable",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1769069492,
+        "narHash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "a1ef738813b15cf8ec759bdff5761b027e3e1d23",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
+    "pre-commit-hooks_4": {
+      "inputs": {
+        "flake-compat": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "flake-compat"
+        ],
+        "gitignore": "gitignore_9",
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "crate2nix",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1769069492,
+        "narHash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U=",
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "rev": "a1ef738813b15cf8ec759bdff5761b027e3e1d23",
+        "type": "github"
+      },
+      "original": {
+        "owner": "cachix",
+        "repo": "pre-commit-hooks.nix",
+        "type": "github"
+      }
+    },
=    "root": {
=      "inputs": {
=        "devenv": "devenv",
@@ -1006,6 +1599,28 @@
=        "type": "github"
=      }
=    },
+    "rust-overlay_2": {
+      "inputs": {
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1776741231,
+        "narHash": "sha256-k9G98qzn+7npROUaks8VqCFm7cFtEG8ulQLBBo5lItg=",
+        "owner": "oxalica",
+        "repo": "rust-overlay",
+        "rev": "02061303f7c4c964f7b4584dabd9e985b4cd442b",
+        "type": "github"
+      },
+      "original": {
+        "owner": "oxalica",
+        "repo": "rust-overlay",
+        "type": "github"
+      }
+    },
=    "systems": {
=      "locked": {
=        "lastModified": 1681028828,
@@ -1045,11 +1660,11 @@
=        "systems": "systems_2"
=      },
=      "locked": {
-        "lastModified": 1775133254,
-        "narHash": "sha256-orxwlnOwsWqRtZaYvt6Tu6l0Pdp9okpVZBaW/+gND2g=",
+        "lastModified": 1777445619,
+        "narHash": "sha256-HjHKZsgkNXvhPC22js+lEvhVBjP5delbuZ4jfsFw1sU=",
=        "ref": "refs/heads/main",
-        "rev": "fbf91ce2b8ebab992a7cbac5bf8ca91115985aea",
-        "revCount": 161,
+        "rev": "a5dc03a114f6284aa4e8e79a27d3846461d251ce",
+        "revCount": 186,
=        "type": "git",
=        "url": "http://codeberg.org/tad-lispy/tad-better-behavior"
=      },
@@ -1079,6 +1694,29 @@
=        "repo": "treefmt-nix",
=        "type": "github"
=      }
+    },
+    "treefmt-nix_2": {
+      "inputs": {
+        "nixpkgs": [
+          "tad-better-behavior",
+          "devenv",
+          "nixd",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1775636079,
+        "narHash": "sha256-pc20NRoMdiar8oPQceQT47UUZMBTiMdUuWrYu2obUP0=",
+        "owner": "numtide",
+        "repo": "treefmt-nix",
+        "rev": "790751ff7fd3801feeaf96d7dc416a8d581265ba",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "treefmt-nix",
+        "type": "github"
+      }
=    }
=  },
=  "root": "root",

Spec: test horizontal overflow on Bussum page

On by Tad Lispy

We know that on small screens the page overflows (has a horizontal scroll). Before we fix it, let's have a TBB scenario to test it.

For now only at 320px width. It is hardcoded. I intend to make it composable and parameterized. But let's take small steps.

index 3d85e45..22835e5 100644
--- a/spec/interpreters/web_automation.clj
+++ b/spec/interpreters/web_automation.clj
@@ -27,6 +27,12 @@
=       (slurp)
=       (tbb/send-text))))
=
+(tbb/implement-step
+ "Set the browser window size to {0} x {1}"
+ (fn [width height data]
+   (e/set-window-size @web-driver {:width (Integer/parseInt width)
+                                   :height (Integer/parseInt height)})))
+
=(tbb/implement-step
= "Navigate to {0}"
= (fn [url data]
@@ -65,4 +71,3 @@
=
=(when (= *file* (System/getProperty "babashka.file"))
=  (apply -main *command-line-args*))
-
index 4ddf9fa..b91450a 100644
--- a/spec/layout.md
+++ b/spec/layout.md
@@ -12,3 +12,13 @@ This scenario asserts that page content fits inside the viewport, i.e. there is
=  * Navigate to `http://localhost:1234/`
=  * The title should be `Better Tech Club`
=  * The content is not wider than the viewport
+
+## The Width of the Body Doesn't Exceed the Viewport on Bussum page
+
+This scenario asserts that page content fits inside the viewport, i.e. there is no need for horizontal scrolling
+
+  * Serve the `.` directory on port `1234`
+  * Set the browser window size to `320` x `480`
+  * Navigate to `http://localhost:1234/bussum.html`
+  * The title should be `Better Tech Club Bussum`
+  * The content is not wider than the viewport

Use TBB delegation to compose spec scenarios

On by Tad Lispy

There are now two main scenarios and two fixtures. The main scenarios are:

  1. All pages fit in a viewport
  2. All pages have correct titles

Each of them lists pages and delegates checking of each page to a specialized fixture scenario.

With this change, the main scenarios don't need to open browser windows. If they do, it looks weird with big empty windows hanging in the background, while action is happening in smaller windows from the fixtures. To facilitate an option to open a browser, there is now a step called "Open the ... browser" that starts a web driver with a chosen browser. Currently only Firefox is available, but in principle we can add other browsers via flake.nix.

I've also implemented the tbb/delegate function to facilitate delegation. There are two delegating steps, corresponding to the delegated scenarios:

  1. Test if page at {0} has title {1}
  2. Test if page at {0} fits in a viewport
index 1429264..beeeb30 100644
--- a/spec/interpreters/tbb.clj
+++ b/spec/interpreters/tbb.clj
@@ -68,6 +68,12 @@
=
=  (timbre/debug "Done reading from tbb."))
=
+(defn delegate [suite scenario parameters]
+  (println (json/generate-string {:type       "Delegate"
+                                  :suite      suite
+                                  :scenario   scenario
+                                  :parameters parameters})))
+
=(defn send-text [text]
=  (println (json/generate-string {:type   "Text"
=                                  :content text}))
index 22835e5..db80f45 100644
--- a/spec/interpreters/web_automation.clj
+++ b/spec/interpreters/web_automation.clj
@@ -27,6 +27,29 @@
=       (slurp)
=       (tbb/send-text))))
=
+(tbb/implement-step
+ "Test if page at {0} fits in a viewport"
+ (fn [url data]
+   (tbb/delegate "spec/layout.md"
+                 "The Width of the Body Doesn't Exceed the Viewport"
+                 {:url url})))
+
+(tbb/implement-step
+ "Test if page at {0} has title {1}"
+ (fn [url title _data]
+   (tbb/delegate "spec/layout.md"
+                 "The page title is correct"
+                 {:url url
+                  :title title})))
+
+(tbb/implement-step
+ "Open the {0} browser"
+ (fn [browser data]
+   (->> browser
+        keyword
+        e/boot-driver
+        (reset! web-driver))))
+
=(tbb/implement-step
= "Set the browser window size to {0} x {1}"
= (fn [width height data]
@@ -62,9 +85,9 @@
=
=(defn -main [& args]
=  (timbre/info "Interpreter start")
-  (reset! web-driver (e/firefox))
=  (tbb/ready)
-  (e/quit @web-driver)
+  (when-not (nil? @web-driver)
+    (e/quit @web-driver))
=  (when @miniserve-process
=    (destroy-tree @miniserve-process))
=  (timbre/info "Interpreter done"))
index b91450a..97a1a2f 100644
--- a/spec/layout.md
+++ b/spec/layout.md
@@ -4,21 +4,45 @@ interpreter: bb spec/interpreters/web_automation.clj
=
=# Basic Layout of the Page
=
+## All pages fit in a viewport
+
+  * Serve the `.` directory on port `1234`
+  * Test if page at `http://localhost:1234/` fits in a viewport
+  * Test if page at `http://localhost:1234/bussum.html` fits in a viewport
+
+
=## The Width of the Body Doesn't Exceed the Viewport
=
=This scenario asserts that page content fits inside the viewport, i.e. there is no need for horizontal scrolling
=
-  * Serve the `.` directory on port `1234`
+``` yaml tbb
+tags: [ fixture ]
+parameters:
+    url: http://localhost:1234/
+```
+
+  * Open the `firefox` browser
+  * Set the browser window size to `320` x `480`
=  * Navigate to `http://localhost:1234/`
-  * The title should be `Better Tech Club`
=  * The content is not wider than the viewport
=
-## The Width of the Body Doesn't Exceed the Viewport on Bussum page
=
-This scenario asserts that page content fits inside the viewport, i.e. there is no need for horizontal scrolling
+## All pages have correct titles
=
=  * Serve the `.` directory on port `1234`
-  * Set the browser window size to `320` x `480`
-  * Navigate to `http://localhost:1234/bussum.html`
-  * The title should be `Better Tech Club Bussum`
-  * The content is not wider than the viewport
+  * Test if page at `http://localhost:1234/` has title `Better Tech Club`
+  * Test if page at `http://localhost:1234/bussum.html` has title `Better Tech Club Bussum`
+
+
+## The page title is correct
+
+``` yaml tbb
+tags: [ fixture ]
+parameters:
+    url: http://localhost:1234/
+    title: Better Tech Club
+```
+
+  * Open the `firefox` browser
+  * Navigate to `http://localhost:1234/`
+  * The title should be `Better Tech Club`

Fix horizontal scroll on narrow viewports

On by Tad Lispy

In the header and main containers, include the padding in box size calculations.

index 15e11bb..7ea856e 100644
--- a/bussum.html
+++ b/bussum.html
@@ -154,6 +154,7 @@
=             width: 100%;
=             max-width: var(--content-width);
=             padding: 2rem;
+             box-sizing: border-box;
=         }
=
=         main {

Larger text in the single-column layout of the Bussum page

On by Tad Lispy

On very small viewports the main section collapses to a single column. In general, the font sizes are also smaller on smaller screens. Together it made the content crammed on the left side, with a lot of empty space on the right.

Now, when the grid collapses, the font is increased. For the headings to retain proportionality with the content, h2 is now scaled with em, not rem units.

I've also included a gap between the columns, so their content never gets too close together.

index 7ea856e..c98a9c4 100644
--- a/bussum.html
+++ b/bussum.html
@@ -83,10 +83,14 @@
=             main {
=                 display: grid;
=                 grid-template-columns: 1fr;
+                 gap: 2rem;
=                 align-items: start;
=
+                 font-size: 2rem;
+
=                 @media(width > 560px) {
=                     grid-template-columns: 1fr 1fr;
+                     font-size: 1rem;
=                 }
=             }
=
@@ -117,7 +121,7 @@
=         }
=
=         h2 {
-             font-size: 1.4rem;
+             font-size: 1.4em;
=             align-self: start;
=             color: var(--accent-color);
=             font-family: "Caveat";

Write "The Netherlands" in full in the heading

On by Tad Lispy

Instead of the abbreviated "NL", which looked weird.

index c98a9c4..58bd57b 100644
--- a/bussum.html
+++ b/bussum.html
@@ -149,6 +149,10 @@
=                     color: var(--accent-color);
=                     font-size: 1.5rem;
=                 }
+                 p {
+                     margin: -0.8rem 0px;
+                     font-weight: bold;
+                 }
=             }
=         }
=
@@ -257,7 +261,8 @@
=        <header>
=            <hgroup>
=                <small>Better Tech Club</small>
-                <h1> Bussum, NL</h1>
+                <h1> Bussum</h1>
+                <p>The Netherlands</p>
=            </hgroup>
=            <img
=                id="big-logo"

Rotate the Better Tech Club above Bussum a bit

On by Tad Lispy

For a more hand-written feeling.

index 58bd57b..e282566 100644
--- a/bussum.html
+++ b/bussum.html
@@ -144,10 +144,12 @@
=                     margin: 0
=                 }
=                 small {
+                     display: block;
=                     font-family: "Caveat";
=                     font-weight: bold;
=                     color: var(--accent-color);
=                     font-size: 1.5rem;
+                     rotate: -4deg;
=                 }
=                 p {
=                     margin: -0.8rem 0px;

Older Devlog Entries