NavigationFrame is Learn's AppShell without its router and its tabs: a navigation rail from medium windows on with the app's icon on top, leading to the first tab, a bar floating above the foot below, the background of the screen in view around it, and a tick on every choice. TabsStack is Learn's container of the tabs' navigators, every tab kept alive and told whether it shows. Learn's shell is built on both, its tests unchanged; Train's is next. The rail's icon is drawn from 120 px at most in memory, as Learn's was. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
94 lines
4.1 KiB
Markdown
94 lines
4.1 KiB
Markdown
# halkyon_ui
|
|
|
|
Halkyon's look, shared by its apps (Learn, Todo, Train): one theme around the
|
|
kingfisher's cobalt and copper, the bundled Noto Sans, Material 3's window
|
|
sizes, and the widgets every app's screens are built of, with their texts in
|
|
British English, American English and German.
|
|
|
|
Written as the apps are: Dart 3.13's primary constructors, Material from
|
|
`package:material_ui` (never `package:flutter/material.dart`), Lucide icons,
|
|
LeanCode's lints.
|
|
|
|
## What it holds
|
|
|
|
- **Theme** (`lib/src/theme/`): `appTheme(brightness, extensions: …)`, Material
|
|
3 with hand-written light and dark schemes (primary cobalt, tertiary copper,
|
|
cobalt-tinted neutrals), Material 3 Expressive's 64 dp navigation bar, flat
|
|
app bars, floating snack bars; `Brand`; `ThemeExtras`, the status colours
|
|
Material has no role for (`Theme.of(context).extras`); `PaletteColor`, the
|
|
20 colours a person can give content, each with a text colour held to WCAG
|
|
AA by a test; `FittedSnackBars`.
|
|
- **Fonts**: Noto Sans for Latin, Greek and Cyrillic, every weight in one
|
|
variable file, as `appFontFamily` (`packages/halkyon_ui/Noto Sans`). Chinese,
|
|
Japanese and Korean fall back to `Noto Sans JP`, `SC`, `TC` and `KR`, which
|
|
an app bundles itself if it needs them (`appFontFallbackFor` puts a
|
|
language's own first).
|
|
- **Layout** (`lib/src/layout/`): `WindowSize` (`context.windowSize`) and
|
|
`readableContentMaxWidth`.
|
|
- **Widgets** (`lib/src/widget/`): `showAdaptiveSheet` with `SheetScaffold`;
|
|
`TopGradient`, `ScreenTint`, `ScreenColor`, `TintFrame`, `FramedScreen`
|
|
and `TabVisibility`; `FloatingNavigationBar`, and `NavigationFrame`, every
|
|
app's frame around its tabs (the rail with the app's icon, the floating
|
|
bar, a tick on every choice), whichever router drives it;
|
|
`AppLoadingIndicator`, `ButtonLoadingIndicator`, `AppRefreshIndicator`;
|
|
`SectionCard`, `SliverCentered`, `EmptyListMessage`, `CountBadge`,
|
|
`TitleWithKicker`, `CollapsingRow`, `ScrollHidingFab`, `liftWhileDragged`,
|
|
`ReorderToggle`, `ReorderGrip`; `ChevronField`, `requiredDecoration`,
|
|
`FieldInfoButton`, `CountStepper`, `PaletteColorPicker`, `TextLimits` with
|
|
`nearLimitCounter`; `confirmDestructiveAction`, `showUndoSnackBar`,
|
|
`showMoreInfoSheet`; `FoundById`; `KeyboardBackOnResume`; `BrandWordmark`
|
|
and `LaunchScreen`, which take the app's word and icon.
|
|
|
|
What belongs to one app stays in it: its own colours (an extension passed to
|
|
`appTheme`), routes, repositories, editors and texts.
|
|
|
|
## Using it in an app
|
|
|
|
Depend on it by path, within the repository's workspace (an app's packages sit in
|
|
`apps/<app>/`), so a change to the package and to the apps using it is one commit:
|
|
|
|
```yaml
|
|
dependencies:
|
|
halkyon_ui:
|
|
path: ../../../packages/halkyon_ui
|
|
```
|
|
|
|
Then set the app up as `example/lib/main.dart` does:
|
|
|
|
```dart
|
|
MaterialApp(
|
|
theme: appTheme(Brightness.light, extensions: [MyColors.light]),
|
|
darkTheme: appTheme(Brightness.dark, extensions: [MyColors.dark]),
|
|
localizationsDelegates: const [
|
|
AppLocalizations.delegate,
|
|
HalkyonUiLocalizations.delegate,
|
|
// material_ui's: flutter_localizations' serve only the SDK's Material.
|
|
...GlobalMaterialLocalizations.delegates,
|
|
],
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
builder: (context, child) => FittedSnackBars(child: child!),
|
|
…
|
|
);
|
|
```
|
|
|
|
and call `registerFontLicenses()` at start. An app bundling the CJK fonts
|
|
declares them in its own `pubspec.yaml` under exactly the names
|
|
`appFontFallback` lists (no `packages/` prefix) and registers their licence
|
|
itself.
|
|
|
|
## Texts
|
|
|
|
`lib/l10n/halkyon_ui_en.arb` is the template (British English, also the
|
|
fallback); `halkyon_ui_de.arb` German, informal "du"; `halkyon_ui_en_US.arb`
|
|
only what American English spells differently; `halkyon_ui_en_GB.arb` empty. A
|
|
new text goes into the template and German together (`test/l10n/` fails
|
|
otherwise). `flutter pub get` writes `lib/l10n/halkyon_ui_localizations*.dart`,
|
|
which are committed and never edited or
|
|
formatted by hand.
|
|
|
|
## Checks
|
|
|
|
From the workspace root: `dart analyze --fatal-infos`; then `flutter test` in
|
|
`packages/halkyon_ui` and in `packages/halkyon_ui/example`, whose tests check
|
|
what only an app sees (the font under the name an app finds it by, its
|
|
licence).
|