No description
  • Dart 65.3%
  • JavaScript 23.5%
  • Python 7.4%
  • Shell 1.9%
  • Typst 1.1%
  • Other 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jan-Henrik Bruhn 7c747d6fdd fix(ui): PrimaryButton carries its own width, action rows stop stretching
PrimaryButton is documented as a full-width button but set no width: it
relied on the consuming app setting `filledButtonTheme` to an infinite
minimum. Both apps duly did, which made every OTHER filled button in them
full-width too — including the confirm in an AlertDialog's action row,
where it takes the whole bar, overflows the OverflowBar and drops Cancel
onto a line of its own. Measured in federfall: Cancel 108.6x48 above a
384x48 confirm, a small text link stranded over a full-width slab.

So the width moves onto the widget that promises it. An app can now leave
its filled buttons at a sane default and still get a form button that
fills the form.

DestructiveActionButton and DestructiveDialog's alternative both sit in
an action row and never want that width, so they state kDialogActionSize
rather than inheriting whatever the app set. The demoted (outlined)
variant deliberately does NOT: an outlined button is not subject to
filledButtonTheme, and a guard for it proved nothing when the canary was
planted, so neither the line nor the test is there.

Three new guards in actions_and_inputs_test, each verified to fail
without its fix — the first two under the default theme, the third under
a hostile one that forces full width. They bound the width loosely
(Align + ConstrainedBox); a SizedBox is a tight constraint and every
button fills it, which is how the first draft of these passed while
proving nothing.

ZugvogelTheme still sets the infinite minimum width. It is left alone on
purpose: eiermann has a sheet button (nest_check_sheet) that appears to
rely on it, and flipping the shared default would re-lay-out an app this
change cannot verify. Federfall flips its own copy alongside its pin bump.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ku6YYeQoKJzDC2ofA48rAP
2026-09-10 17:33:51 +02:00
.github/workflows build!: zurück auf Flutter 3.44.3 — 3.47 verliert Bilder außerhalb von Chrome 2026-08-21 18:38:08 +02:00
backend/pocketbase feat(audit): the correlation columns come from the registry 2026-08-24 10:37:22 +02:00
packages fix(ui): PrimaryButton carries its own width, action rows stop stretching 2026-09-10 17:33:51 +02:00
.gitignore feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
.release-please-manifest.json feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
AGENTS.md docs: the injection-boundary write-up CLAUDE.md was pointing at 2026-08-21 01:58:55 +02:00
analysis_options.yaml build: keep the analyzer excludes flutter pub get writes itself 2026-08-21 15:59:55 +02:00
CLAUDE.md build!: zurück auf Flutter 3.44.3 — 3.47 verliert Bilder außerhalb von Chrome 2026-08-21 18:38:08 +02:00
Dockerfile feat(docker): publish zugvogel-pb-base to GHCR 2026-08-21 08:03:09 +02:00
LICENSE feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
pubspec.yaml feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00
README.md build!: zurück auf Flutter 3.44.3 — 3.47 verliert Bilder außerhalb von Chrome 2026-08-21 18:38:08 +02:00
release-please-config.json feat: initialise zugvogel — pub workspace, four packages, CI, release-please 2026-08-20 22:03:37 +02:00

Zugvogel

The shared library behind federfall and eiermann: the part of both apps that carries no product vocabulary. Four Dart packages plus the PocketBase and Typst assets that go with them.

Zugvogel is not an app and is not published to pub.dev. Both apps consume it through a pinned git ref, so neither one moves until it is moved deliberately.

Layout

packages/
  zugvogel_core/       pure Dart — GeoPoint, converters, wire-value enums,
                       Result, ErrorMessage, logger
  zugvogel_data/       pure Dart — generic PocketBase repository, PbFilter,
                       keyset paging, multipart, idempotency
  zugvogel_pb_client/  Flutter — client, auth token, server URL, reachability
                       probe, /info, version compatibility, realtime
  zugvogel_ui/         Flutter — widgets, charts, map layers, bundled fonts
backend/pocketbase/
  pb_hooks/            shared hooks in the reserved zv_* namespace
  typst/               report_common.typ and the vendored Typst packages
  tests/               the rule/hook harness templates

Dependency direction is one-way: ui/pb_client → data → core. Nothing depends upwards, and nothing in this repo depends on either app.

Consuming it

Pin a commit hash, never a branch and never a tag:

dependencies:
  zugvogel_ui:
    git:
      url: https://github.com/jhbruhn/zugvogel.git
      ref: 0000000000000000000000000000000000000000  # a full 40-char SHA
      path: packages/zugvogel_ui

A commit hash is the only ref that cannot move. A branch obviously moves; a tag can be re-pointed, and pub caches by ref, so a moved tag means two machines resolve the same declaration to different code and only one of them can reproduce the bug. Nothing here is released — there are no tags at all — so the hash is also the only ref there is.

Use the full 40 characters. pub accepts a short one, but a short hash is ambiguous in principle and unhelpful in practice: it cannot be pasted into a compare URL, and git log <short>..<short> is exactly what you want when a version bump breaks something.

The https URL, not git@github.com: — a CI runner has no SSH key, and a dependency that only resolves on a developer's laptop is a dependency that breaks the build. The repo is public, so https needs no credentials at all. Push over SSH (git@github.com:jhbruhn/zugvogel.git); that is the remote configured here.

The members declare resolution: workspace for local development, which does not stand in the way of git consumption — verified: a consuming app that pins zugvogel_data and zugvogel_ui resolves their relative path dependencies inside the same checkout and ends up with exactly one copy of zugvogel_core.

pubspec.lock is deliberately not committed here. This repo ships libraries; the consuming app's lockfile is the one that pins versions.

Versioning

Nothing is released yet, on purpose. Both apps pin a commit hash (see above), so a version number would be decoration — and a tag that exists is a tag somebody can pin by accident.

The machinery is in place for when that changes: release-please watches conventional-commit history and maintains a standing release PR with the next bump and a CHANGELOG. Merging that PR is what would cut a release; leaving it open costs nothing and creates nothing. Pre-1.0 the config bumps a minor for a breaking change and a patch for a feature.

There is no bootstrap-sha in release-please-config.json: the repo starts here, so reading the full history is correct.

The rules

Three injection boundaries keep a wide shared package from welding two product designs together — no strings, no colours, no configuration inside the package. And PocketBase migrations cannot be shared, only copied as templates. Both are spelled out in CLAUDE.md.

Toolchain

Flutter 3.44.3 / Dart 3.12. This library is compiled by the consuming apps' toolchain, so the version in .github/workflows/ci.yml must stay in lockstep with theirs. 3.47.x is skipped deliberately — see CLAUDE.md.

Licence

AGPL-3.0, same as the apps that consume it. See LICENSE.