Skip to content

Commit d3b4e4d

Browse files
committed
feat(catalogue): widgetbook v3 component catalogue + pages CI
1 parent c7f537d commit d3b4e4d

18 files changed

Lines changed: 1802 additions & 1 deletion

makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: all setup clean deps deps-update bootstrap analyze build-runner translations hooks ios-pod-update drift-migrations devcontainer container-tools container-app android release debug beta verify test unit-test integration-test fvm-check
1+
.PHONY: all setup clean deps deps-update bootstrap analyze build-runner translations hooks ios-pod-update drift-migrations devcontainer container-tools container-app android release debug beta verify test unit-test integration-test catalogue fvm-check
22

33
fvm-check:
44
@echo "🔍 Checking FVM"
@@ -203,3 +203,12 @@ integration-test:
203203
@echo "🧪 integration tests"
204204
@fvm dart run tool/gen_all_test.dart
205205
@fvm flutter test integration_test/all_test.dart --reporter=expanded
206+
207+
# Build & render the bull_ui design-system catalogue (Widgetbook) locally in the
208+
# browser. Dev-only tooling — never shipped in the app. Regenerates the
209+
# @UseCase directories, then runs the catalogue app on Chrome (hot-reload).
210+
catalogue:
211+
@echo "📚 Building & rendering the bull_ui catalogue in the browser"
212+
@cd packages/bull_ui_catalogue && \
213+
fvm dart run build_runner build --delete-conflicting-outputs && \
214+
fvm flutter run -d chrome
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.build/
9+
.buildlog/
10+
.history
11+
.svn/
12+
.swiftpm/
13+
migrate_working_dir/
14+
15+
# IntelliJ related
16+
*.iml
17+
*.ipr
18+
*.iws
19+
.idea/
20+
21+
# The .vscode folder contains launch configuration and tasks you configure in
22+
# VS Code which you may wish to be included in version control, so this line
23+
# is commented out by default.
24+
#.vscode/
25+
26+
# Flutter/Dart/Pub related
27+
**/doc/api/
28+
**/ios/Flutter/.last_build_id
29+
.dart_tool/
30+
.flutter-plugins-dependencies
31+
.pub-cache/
32+
.pub/
33+
/build/
34+
/coverage/
35+
36+
# The root .gitignore ignores all *.g.dart, but the Widgetbook directories
37+
# file is generated codegen we deliberately commit-to-tree so the catalogue
38+
# runs locally without a build_runner pass. Negate the parent rule for it.
39+
!lib/main.directories.g.dart
40+
41+
# Symbolication related
42+
app.*.symbols
43+
44+
# Obfuscation related
45+
app.*.map.json
46+
47+
# Android Studio will place build artifacts here
48+
/android/app/debug
49+
/android/app/profile
50+
/android/app/release
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This file tracks properties of this Flutter project.
2+
# Used by Flutter tool to assess capabilities and perform upgrades etc.
3+
#
4+
# This file should be version controlled and should not be manually edited.
5+
6+
version:
7+
revision: "924134a44c189315be2148659913dda1671cbe99"
8+
channel: "stable"
9+
10+
project_type: app
11+
12+
# Tracks metadata for the flutter migrate command
13+
migration:
14+
platforms:
15+
- platform: root
16+
create_revision: 924134a44c189315be2148659913dda1671cbe99
17+
base_revision: 924134a44c189315be2148659913dda1671cbe99
18+
- platform: web
19+
create_revision: 924134a44c189315be2148659913dda1671cbe99
20+
base_revision: 924134a44c189315be2148659913dda1671cbe99
21+
22+
# User provided section
23+
24+
# List of Local paths (relative to this file) that should be
25+
# ignored by the migrate tool.
26+
#
27+
# Files that are not part of the templates will be ignored by default.
28+
unmanaged_files:
29+
- 'lib/main.dart'
30+
- 'ios/Runner.xcodeproj/project.pbxproj'
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# bull_ui_catalogue
2+
3+
Dev-only [Widgetbook](https://pub.dev/packages/widgetbook)-powered catalogue for
4+
the `bull_ui` design system.
5+
6+
This package is **not** part of the production app. The app must never depend on
7+
it, so it is never compiled into the APK and has zero reproducible-build impact
8+
(it lives alongside the app like melos tooling). It exists purely to browse and
9+
review every `Bull*` component in isolation, in light and dark themes at
10+
different text scales.
11+
12+
## Why use-cases live here
13+
14+
`bull_ui` stays codegen-free and Widgetbook-free. All `@widgetbook.UseCase`
15+
functions live in this package (`lib/use_cases/use_cases.dart`), so the design
16+
system carries no Widgetbook annotations or generated files.
17+
18+
The `BullTheme` colours are normally injected by the app from its `AppColors`.
19+
This package must not import the app, so `lib/catalogue_theme.dart` holds small
20+
**catalogue-local** sample light/dark palettes mirroring the app — literals are
21+
acceptable here in dev-only code, keeping `bull_ui` itself literal-free.
22+
23+
## Run locally
24+
25+
```bash
26+
fvm flutter pub get # from repo root (workspace resolve)
27+
cd packages/bull_ui_catalogue
28+
fvm dart run build_runner build # regenerate main.directories.g.dart
29+
fvm flutter run -d chrome # browse the catalogue
30+
```
31+
32+
`lib/main.directories.g.dart` is committed to the tree (the root `.gitignore`
33+
ignores `*.g.dart`; this package's `.gitignore` negates that for the directories
34+
file) so the catalogue runs without a build_runner pass.
35+
36+
## Publishing (deferred — local-only for now)
37+
38+
There is **no CI/Pages publishing in this PR** — browse the catalogue locally
39+
with `make catalogue` (or the commands above).
40+
41+
Intended hosting for a follow-up: this repo's GitHub Pages serves `main:/docs`
42+
(custom domain `wallet.bullbitcoin.com`), and a repo has only one Pages site, so
43+
the catalogue would be published as a **subfolder** — built for web with
44+
`--base-href /catalogue/` and dropped into `main:/docs/catalogue/` (preserving
45+
the rest of `/docs`), served at `https://wallet.bullbitcoin.com/catalogue/`. That
46+
requires CI to commit to `main`, so it's left for a dedicated change once the
47+
catalogue renders cleanly (currently on widgetbook v3, pending a v4 migration).
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
include: package:flutter_lints/flutter.yaml
2+
3+
# This is a dev-only catalogue app, not the design-system package. We relax the
4+
# documentation / const-perfection lints that bull_ui itself is held to — the
5+
# use-cases are illustrative sample code, not production API surface.
6+
analyzer:
7+
errors:
8+
# Generated *.directories.g.dart is checked into the tree; never lint it.
9+
todo: ignore
10+
exclude:
11+
- "**/*.g.dart"
12+
13+
linter:
14+
rules:
15+
public_member_api_docs: false
16+
prefer_const_constructors: false
17+
prefer_const_literals_to_create_immutables: false
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import 'package:bull_ui/bull_ui.dart';
2+
import 'package:flutter/material.dart';
3+
4+
/// Catalogue-local sample palettes for the theme addon.
5+
///
6+
/// `bull_ui` is intentionally brightness-agnostic and literal-free: in the real
7+
/// app the [BullTheme] values are injected from `AppColors` (which lives in the
8+
/// app and which this package must NOT import). To render the components with
9+
/// the right fidelity in the catalogue we keep a small *representative* copy of
10+
/// the app palette here. Literals are acceptable in this dev-only catalogue —
11+
/// they keep `bull_ui` itself free of any colour values.
12+
///
13+
/// These mirror `lib/core/themes/colors.dart` closely enough for visual review;
14+
/// they are not the single source of truth and may drift slightly.
15+
class CatalogueColors {
16+
const CatalogueColors._();
17+
18+
static const BullTheme light = BullTheme(
19+
red: Color(0xFFC50909),
20+
onRed: Color(0xFFFFFFFF),
21+
surface: Color(0xFFFFFFFF),
22+
card: Color(0xFFFFFFFF),
23+
text: Color(0xFF15171C),
24+
muted: Color(0xFF70747D),
25+
info: Color(0xFF0063F7),
26+
success: Color(0xFF34C759),
27+
warning: Color(0xFFFB9300),
28+
btc: Color(0xFFFF9500),
29+
outlineVariant: Color(0xFFE8E8E8),
30+
shimmerBase: Color(0xFFE0E0E0),
31+
shimmerHighlight: Color(0xFFF5F5F5),
32+
secondary: Color(0xFF15171C),
33+
onSecondary: Color(0xFFFFFFFF),
34+
secondaryFixedDim: Color(0xFFC9CACD),
35+
border: Color(0xFFC9CACD),
36+
onSurface: Color(0xFF15171C),
37+
onSurfaceVariant: Color(0xFF70747D),
38+
scrim: Color(0x26000000),
39+
);
40+
41+
static const BullTheme dark = BullTheme(
42+
red: Color(0xFFC50909),
43+
onRed: Color(0xFFFFFFFF),
44+
surface: Color(0xFF1C1C1E),
45+
card: Color(0xFF2C2C2E),
46+
text: Color(0xFFFFFFFF),
47+
muted: Color(0xFF8E8E93),
48+
info: Color(0xFF0A84FF),
49+
success: Color(0xFF32D74B),
50+
warning: Color(0xFFFF9F0A),
51+
btc: Color(0xFFFF9F0A),
52+
outlineVariant: Color(0xFF3C3C3E),
53+
shimmerBase: Color(0xFF3C3C3E),
54+
shimmerHighlight: Color(0xFF48484A),
55+
secondary: Color(0xFFFFFFFF),
56+
onSecondary: Color(0xFF15171C),
57+
secondaryFixedDim: Color(0xFF58585A),
58+
border: Color(0xFF58585A),
59+
onSurface: Color(0xFFFFFFFF),
60+
onSurfaceVariant: Color(0xFF8E8E93),
61+
scrim: Color(0x26000000),
62+
);
63+
}
64+
65+
/// Builds a Material [ThemeData] carrying the [BullTheme] extension, matching
66+
/// how the app wires `bull_ui` (extension on `ThemeData.extensions`). Components
67+
/// read their colours via `context.bull`, so the extension is what matters.
68+
ThemeData catalogueThemeData(Brightness brightness) {
69+
final bull = brightness == Brightness.dark
70+
? CatalogueColors.dark
71+
: CatalogueColors.light;
72+
return ThemeData(
73+
useMaterial3: true,
74+
brightness: brightness,
75+
fontFamily: 'Golos Text',
76+
extensions: [bull],
77+
colorScheme: ColorScheme.fromSeed(
78+
seedColor: bull.red,
79+
brightness: brightness,
80+
primary: bull.red,
81+
),
82+
scaffoldBackgroundColor: bull.surface,
83+
canvasColor: bull.card,
84+
);
85+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'package:bull_ui_catalogue/catalogue_theme.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:widgetbook/widgetbook.dart';
4+
import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;
5+
6+
// Generated by build_runner from every `@widgetbook.UseCase` in lib/.
7+
// Checked into the tree (CI does not regenerate on the deploy path's behalf
8+
// only — it does run build_runner — but the file is committed for local runs).
9+
import 'main.directories.g.dart';
10+
11+
void main() {
12+
runApp(const BullUiCatalogue());
13+
}
14+
15+
@widgetbook.App()
16+
class BullUiCatalogue extends StatelessWidget {
17+
const BullUiCatalogue({super.key});
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return Widgetbook.material(
22+
directories: directories,
23+
// WORKAROUND (widgetbook 3.24.0 on Flutter 3.44.1): the default
24+
// `materialAppBuilder` wraps each use-case in a nested `MaterialApp`,
25+
// whose Navigator trips `_history.isNotEmpty` during layout on 3.44.1.
26+
// The catalogue's outer app already provides MediaQuery/Directionality/
27+
// Overlay, and the theme is injected by `MaterialThemeAddon` (a `Theme`
28+
// widget), so the per-use-case shell only needs a `Material` ancestor —
29+
// no second `MaterialApp`/Navigator. Drop this once on widgetbook v4.
30+
appBuilder: (context, child) =>
31+
Material(type: MaterialType.transparency, child: child),
32+
addons: [
33+
// Light + dark, each carrying the BullTheme extension that components
34+
// read via `context.bull`. This is exactly how the app wires bull_ui.
35+
MaterialThemeAddon(
36+
themes: [
37+
WidgetbookTheme(name: 'Light', data: catalogueThemeData(Brightness.light)),
38+
WidgetbookTheme(name: 'Dark', data: catalogueThemeData(Brightness.dark)),
39+
],
40+
initialTheme: WidgetbookTheme(
41+
name: 'Light',
42+
data: catalogueThemeData(Brightness.light),
43+
),
44+
),
45+
// NOTE: ViewportAddon (device frames) is intentionally omitted —
46+
// widgetbook 3.24.0's viewport addon trips a Navigator
47+
// `_history.isNotEmpty` assertion on Flutter 3.44.1 (its nested
48+
// Navigator asserts during layout). Re-add once widgetbook/Flutter
49+
// compatibility is resolved (e.g. widgetbook v4).
50+
TextScaleAddon(initialScale: 1.0, min: 1.0, max: 2.0, divisions: 4),
51+
],
52+
);
53+
}
54+
}

0 commit comments

Comments
 (0)