feat(brand): rename product to Recl∆Im (Reclaim) across app, bundle, docs
Recl∆Im — the F∆I product line for Pflicht-basierte
Wirkungsanalyse und Reform-Vorschlags-Pipelines. Replaces the
working title 'Law-Heatmap', which described the demo view
rather than the platform. Heatmap, Norms list, Hub view,
Methodik are now four panes of the same Recl∆Im app.
Renames in this commit:
Flutter package lawheatmap_app -> reclaim_app
macOS bundle id ai.flemming.lawheatmapApp -> ai.flemming.reclaim
macOS PRODUCT_NAME lawheatmap_app -> reclaim_app
Theme tokens LawHeatmapColors/Space/Radius/Typography/Theme
-> Reclaim*
Surface card LawHeatmapCard -> ReclaimCard
Top-level widget LawHeatmapApp -> ReclaimApp
Theme files lawheatmap_theme.dart/lawheatmap_tokens.dart
-> reclaim_theme.dart/reclaim_tokens.dart
Widget file lawheatmap_card.dart -> reclaim_card.dart
Build script build-macos.sh paths and headline string
Docs MACHBARKEITSSTUDIE.md, METHODIK.md, RUN.md,
app/README.md, flow YAML
UI strings 'F∆I Law-Heatmap' / 'Law-Heatmap'
-> 'Recl∆Im' / 'Recl∆Im (F∆I)' for vendor-
prefixed contexts
flutter analyze: clean. flutter test: 2/2 passing.
The local working directory stays fai_lawheatmap/ for now —
the dir is referenced by the .claude project metadata; renaming
it would break session continuity for no real gain. The Forgejo
repo was renamed via API in the same change-set (fai/lawheatmap
-> fai/reclaim), with the legacy slug serving a redirect
courtesy of Forgejo's built-in rename handling.
Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
parent
90b7500aaf
commit
e08cedcd3f
29 changed files with 291 additions and 226 deletions
|
|
@ -5,13 +5,13 @@ import 'data/hub_endpoint.dart';
|
|||
import 'data/hub_repository.dart';
|
||||
import 'data/repository.dart';
|
||||
import 'pages/landing_page.dart';
|
||||
import 'theme/lawheatmap_theme.dart';
|
||||
import 'theme/reclaim_theme.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
final settings = await HubSettings.load();
|
||||
final repository = await _pickRepository(settings);
|
||||
runApp(LawHeatmapApp(repository: repository, settings: settings));
|
||||
runApp(ReclaimApp(repository: repository, settings: settings));
|
||||
}
|
||||
|
||||
/// Decide which repository to start with.
|
||||
|
|
@ -28,8 +28,8 @@ Future<EvaluationRepository> _pickRepository(HubSettings settings) async {
|
|||
return const MockRepository();
|
||||
}
|
||||
|
||||
class LawHeatmapApp extends StatelessWidget {
|
||||
const LawHeatmapApp({
|
||||
class ReclaimApp extends StatelessWidget {
|
||||
const ReclaimApp({
|
||||
super.key,
|
||||
this.repository = const MockRepository(),
|
||||
this.settings,
|
||||
|
|
@ -41,10 +41,10 @@ class LawHeatmapApp extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'F∆I Law-Heatmap',
|
||||
title: 'Recl∆Im',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: LawHeatmapTheme.light(),
|
||||
darkTheme: LawHeatmapTheme.dark(),
|
||||
theme: ReclaimTheme.light(),
|
||||
darkTheme: ReclaimTheme.dark(),
|
||||
themeMode: ThemeMode.dark,
|
||||
localizationsDelegates: const [
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../widgets/lawheatmap_card.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import '../widgets/reclaim_card.dart';
|
||||
|
||||
class AboutPage extends StatelessWidget {
|
||||
const AboutPage({super.key});
|
||||
|
|
@ -10,25 +10,25 @@ class AboutPage extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(LawHeatmapSpace.xl),
|
||||
padding: const EdgeInsets.all(ReclaimSpace.xl),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Methodik & Quellen', style: t.displaySmall),
|
||||
const SizedBox(height: LawHeatmapSpace.xs),
|
||||
const SizedBox(height: ReclaimSpace.xs),
|
||||
Text(
|
||||
'Wie das System bewertet, woran es sich messen lässt.',
|
||||
style: t.bodyLarge?.copyWith(color: LawHeatmapColors.mute),
|
||||
style: t.bodyLarge?.copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
LawHeatmapCard(
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
ReclaimCard(
|
||||
accent: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Drei nicht verhandelbare Sätze',
|
||||
style: t.headlineSmall),
|
||||
const SizedBox(height: LawHeatmapSpace.md),
|
||||
const SizedBox(height: ReclaimSpace.md),
|
||||
Text(
|
||||
'1. Wir bewerten Pflichten, nicht Gesetze.\n'
|
||||
'2. Jede Zahl trägt die Tier-Stufe ihres schwächsten '
|
||||
|
|
@ -40,13 +40,13 @@ class AboutPage extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
LawHeatmapCard(
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
ReclaimCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Methodische Vorbilder', style: t.headlineSmall),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
_bullet(t,
|
||||
'Standardkostenmodell (SKM) — Nationaler Normenkontrollrat. P × F × T × h.'),
|
||||
_bullet(t,
|
||||
|
|
@ -62,13 +62,13 @@ class AboutPage extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
LawHeatmapCard(
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
ReclaimCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('4-Tier-Evidenz-Modell', style: t.headlineSmall),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
_bullet(t,
|
||||
'T1 — amtlich/peer-reviewed: NKR, DESTATIS, ifo, ZEW, BMWK, SVR, IfM Bonn.'),
|
||||
_bullet(t,
|
||||
|
|
@ -80,13 +80,13 @@ class AboutPage extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
LawHeatmapCard(
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
ReclaimCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Plattform', style: t.headlineSmall),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
Text(
|
||||
'Ch∆In v0.16.0 — Vendor: F∆I = Flemming.AI. '
|
||||
'Hub. Module. Flow. Deterministisch, WASM-sandboxed, '
|
||||
|
|
@ -104,7 +104,7 @@ class AboutPage extends StatelessWidget {
|
|||
|
||||
Widget _bullet(TextTheme t, String text) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: LawHeatmapSpace.sm),
|
||||
padding: const EdgeInsets.only(bottom: ReclaimSpace.sm),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -114,7 +114,7 @@ class AboutPage extends StatelessWidget {
|
|||
width: 5,
|
||||
height: 5,
|
||||
decoration: const BoxDecoration(
|
||||
color: LawHeatmapColors.signal,
|
||||
color: ReclaimColors.signal,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import '../data/models.dart';
|
||||
import '../data/repository.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import '../widgets/demo_banner.dart';
|
||||
import '../widgets/heatmap_grid.dart';
|
||||
import '../widgets/lawheatmap_card.dart';
|
||||
import '../widgets/reclaim_card.dart';
|
||||
import '../widgets/tier_badge.dart';
|
||||
import 'norm_detail_page.dart';
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ class _HeatmapPageState extends State<HeatmapPage> {
|
|||
const DemoBanner(),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(LawHeatmapSpace.xl),
|
||||
padding: const EdgeInsets.all(ReclaimSpace.xl),
|
||||
child: FutureBuilder<List<Evaluation>>(
|
||||
future: _future,
|
||||
builder: (context, snap) {
|
||||
|
|
@ -48,18 +48,18 @@ class _HeatmapPageState extends State<HeatmapPage> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Heatmap', style: t.displaySmall),
|
||||
const SizedBox(height: LawHeatmapSpace.xs),
|
||||
const SizedBox(height: ReclaimSpace.xs),
|
||||
Text(
|
||||
'X: jährliche Bürokratiekosten (€, log10). '
|
||||
'Y: Nutzen-Score 0–5. Punktgröße: Betroffenheit. '
|
||||
'Klick auf einen Punkt → Detail mit Pflichten + Quellen.',
|
||||
style: t.bodyLarge?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
Expanded(
|
||||
child: LawHeatmapCard(
|
||||
child: ReclaimCard(
|
||||
accent: true,
|
||||
expand: true,
|
||||
child: HeatmapGrid(
|
||||
|
|
@ -77,10 +77,10 @@ class _HeatmapPageState extends State<HeatmapPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
Wrap(
|
||||
spacing: LawHeatmapSpace.md,
|
||||
runSpacing: LawHeatmapSpace.sm,
|
||||
spacing: ReclaimSpace.md,
|
||||
runSpacing: ReclaimSpace.sm,
|
||||
children: [
|
||||
for (final e in items)
|
||||
InkWell(
|
||||
|
|
@ -94,10 +94,10 @@ class _HeatmapPageState extends State<HeatmapPage> {
|
|||
),
|
||||
);
|
||||
},
|
||||
child: LawHeatmapCard(
|
||||
child: ReclaimCard(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LawHeatmapSpace.md,
|
||||
vertical: LawHeatmapSpace.sm,
|
||||
horizontal: ReclaimSpace.md,
|
||||
vertical: ReclaimSpace.sm,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
@ -105,7 +105,7 @@ class _HeatmapPageState extends State<HeatmapPage> {
|
|||
TierBadge(
|
||||
tier: e.tierLowest, compact: true),
|
||||
const SizedBox(
|
||||
width: LawHeatmapSpace.sm),
|
||||
width: ReclaimSpace.sm),
|
||||
Text(
|
||||
'${e.norm.jurabk} ${e.norm.paragraph}',
|
||||
style: t.labelLarge,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
|||
import '../data/hub_endpoint.dart';
|
||||
import '../data/hub_repository.dart';
|
||||
import '../data/repository.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import '../widgets/hub_capabilities_card.dart';
|
||||
import '../widgets/lawheatmap_card.dart';
|
||||
import '../widgets/reclaim_card.dart';
|
||||
|
||||
/// Hub connection + settings. Read-only summary at the top, then
|
||||
/// an editable form for endpoint host/port/secure/token, then a
|
||||
|
|
@ -109,18 +109,18 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
final repo = widget.repository;
|
||||
final s = _settings;
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(LawHeatmapSpace.xl),
|
||||
padding: const EdgeInsets.all(ReclaimSpace.xl),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Ch∆In Hub', style: t.displaySmall),
|
||||
const SizedBox(height: LawHeatmapSpace.xs),
|
||||
const SizedBox(height: ReclaimSpace.xs),
|
||||
Text(
|
||||
'Status der Verbindung und Konfiguration des lokalen Hubs.',
|
||||
style: t.bodyLarge?.copyWith(color: LawHeatmapColors.mute),
|
||||
style: t.bodyLarge?.copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
LawHeatmapCard(
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
ReclaimCard(
|
||||
accent: true,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -142,23 +142,23 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
LawHeatmapCard(
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
ReclaimCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Verbindung konfigurieren',
|
||||
style: t.headlineSmall),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
Text(
|
||||
'`chain serve` läuft standardmäßig auf '
|
||||
'127.0.0.1:50051 ohne Auth. '
|
||||
'Bei aktiver Auth den Bearer-Token aus '
|
||||
'~/.chain/hub-auth-token hier eintragen.',
|
||||
style: t.labelSmall
|
||||
?.copyWith(color: LawHeatmapColors.mute),
|
||||
?.copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
Row(children: [
|
||||
Expanded(
|
||||
flex: 3,
|
||||
|
|
@ -170,7 +170,7 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: LawHeatmapSpace.md),
|
||||
const SizedBox(width: ReclaimSpace.md),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _portCtl,
|
||||
|
|
@ -182,7 +182,7 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
),
|
||||
),
|
||||
]),
|
||||
const SizedBox(height: LawHeatmapSpace.md),
|
||||
const SizedBox(height: ReclaimSpace.md),
|
||||
TextField(
|
||||
controller: _tokenCtl,
|
||||
decoration: const InputDecoration(
|
||||
|
|
@ -190,23 +190,23 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
),
|
||||
obscureText: true,
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.md),
|
||||
const SizedBox(height: ReclaimSpace.md),
|
||||
Row(children: [
|
||||
Switch(
|
||||
value: _secure,
|
||||
onChanged: (v) => setState(() => _secure = v),
|
||||
),
|
||||
const SizedBox(width: LawHeatmapSpace.sm),
|
||||
const SizedBox(width: ReclaimSpace.sm),
|
||||
const Text('TLS (https)'),
|
||||
const SizedBox(width: LawHeatmapSpace.xl),
|
||||
const SizedBox(width: ReclaimSpace.xl),
|
||||
Switch(
|
||||
value: _useHub,
|
||||
onChanged: (v) => setState(() => _useHub = v),
|
||||
),
|
||||
const SizedBox(width: LawHeatmapSpace.sm),
|
||||
const SizedBox(width: ReclaimSpace.sm),
|
||||
const Text('Hub beim Start nutzen'),
|
||||
]),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
Row(children: [
|
||||
FilledButton.icon(
|
||||
onPressed: _probing ? null : _probe,
|
||||
|
|
@ -221,7 +221,7 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
: const Icon(Icons.bolt_outlined),
|
||||
label: const Text('Verbindung testen'),
|
||||
),
|
||||
const SizedBox(width: LawHeatmapSpace.md),
|
||||
const SizedBox(width: ReclaimSpace.md),
|
||||
OutlinedButton.icon(
|
||||
onPressed: _save,
|
||||
icon: const Icon(Icons.save_outlined),
|
||||
|
|
@ -229,24 +229,24 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
),
|
||||
]),
|
||||
if (_probeMessage != null) ...[
|
||||
const SizedBox(height: LawHeatmapSpace.md),
|
||||
const SizedBox(height: ReclaimSpace.md),
|
||||
Text(_probeMessage!,
|
||||
style: t.labelLarge?.copyWith(
|
||||
color: LawHeatmapColors.signal,
|
||||
color: ReclaimColors.signal,
|
||||
)),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
HubCapabilitiesCard(repository: repo),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
LawHeatmapCard(
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
ReclaimCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Geplanter Live-Flow', style: t.headlineSmall),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
Text(
|
||||
'1. `chain serve` auf localhost:50051 starten.\n'
|
||||
'2. Module installieren (`chain install`).\n'
|
||||
|
|
@ -261,7 +261,7 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
'Evaluation-Objekte übersetzt.',
|
||||
style: t.bodyLarge?.copyWith(
|
||||
height: 1.6,
|
||||
fontFamily: LawHeatmapTypography.mono,
|
||||
fontFamily: ReclaimTypography.mono,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
|
|
@ -282,12 +282,12 @@ class _HubStatusPageState extends State<HubStatusPage> {
|
|||
width: 200,
|
||||
child: Text(label,
|
||||
style: t.labelLarge
|
||||
?.copyWith(color: LawHeatmapColors.mute)),
|
||||
?.copyWith(color: ReclaimColors.mute)),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(value,
|
||||
style: t.bodyLarge
|
||||
?.copyWith(fontFamily: LawHeatmapTypography.mono)),
|
||||
?.copyWith(fontFamily: ReclaimTypography.mono)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/repository.dart';
|
||||
import '../theme/lawheatmap_theme.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_theme.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import '../widgets/delta_mark.dart';
|
||||
import 'shell_page.dart';
|
||||
|
||||
|
|
@ -23,28 +23,28 @@ class LandingPage extends StatelessWidget {
|
|||
constraints: const BoxConstraints(maxWidth: 720),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LawHeatmapSpace.xxl,
|
||||
vertical: LawHeatmapSpace.xxxl,
|
||||
horizontal: ReclaimSpace.xxl,
|
||||
vertical: ReclaimSpace.xxxl,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const DeltaMark(size: 96),
|
||||
const SizedBox(height: LawHeatmapSpace.xxl),
|
||||
Text('F∆I Law-Heatmap', style: t.displaySmall),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.xxl),
|
||||
Text('Recl∆Im', style: t.displaySmall),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
Text(
|
||||
'Pflicht-basierte Wirkungsanalyse von Rechtsnormen — '
|
||||
'auf Ch∆In, mit Quellen-Audit by construction.',
|
||||
style: t.bodyLarge
|
||||
?.copyWith(color: LawHeatmapColors.mute),
|
||||
?.copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.xxl),
|
||||
const SizedBox(height: ReclaimSpace.xxl),
|
||||
Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: LawHeatmapSpace.md,
|
||||
runSpacing: LawHeatmapSpace.sm,
|
||||
spacing: ReclaimSpace.md,
|
||||
runSpacing: ReclaimSpace.sm,
|
||||
children: [
|
||||
FilledButton.icon(
|
||||
onPressed: () {
|
||||
|
|
@ -61,18 +61,18 @@ class LandingPage extends StatelessWidget {
|
|||
Text(
|
||||
'Demo: 5 Pilot-Normen, ohne Hub-Verbindung',
|
||||
style: t.labelSmall?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.xl),
|
||||
const SizedBox(height: ReclaimSpace.xl),
|
||||
Text(
|
||||
'v0.1.0 · Phase 0 · Mock-Modus · '
|
||||
'Live-Hub-Anbindung folgt in Woche 1',
|
||||
style: LawHeatmapTheme.mono(
|
||||
style: ReclaimTheme.mono(
|
||||
t.labelSmall ?? const TextStyle(),
|
||||
).copyWith(color: LawHeatmapColors.mute),
|
||||
).copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import '../data/models.dart';
|
||||
import '../data/repository.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import '../widgets/demo_banner.dart';
|
||||
import '../widgets/lawheatmap_card.dart';
|
||||
import '../widgets/reclaim_card.dart';
|
||||
import '../widgets/tier_badge.dart';
|
||||
import 'norm_detail_page.dart';
|
||||
|
||||
|
|
@ -21,20 +21,20 @@ class NormsListPage extends StatelessWidget {
|
|||
const DemoBanner(),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(LawHeatmapSpace.xl),
|
||||
padding: const EdgeInsets.all(ReclaimSpace.xl),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Normen-Pilotkorpus', style: t.displaySmall),
|
||||
const SizedBox(height: LawHeatmapSpace.xs),
|
||||
const SizedBox(height: ReclaimSpace.xs),
|
||||
Text(
|
||||
'5 Normen für den vertikalen Durchstich. '
|
||||
'Korpus erweiterbar in Phase 1.',
|
||||
style: t.bodyLarge?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
FutureBuilder<List<Evaluation>>(
|
||||
future: repository.list(),
|
||||
builder: (context, snap) {
|
||||
|
|
@ -47,7 +47,7 @@ class NormsListPage extends StatelessWidget {
|
|||
for (final e in snap.data!)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
bottom: LawHeatmapSpace.md),
|
||||
bottom: ReclaimSpace.md),
|
||||
child: _NormRow(
|
||||
evaluation: e,
|
||||
repository: repository,
|
||||
|
|
@ -86,7 +86,7 @@ class _NormRow extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
},
|
||||
child: LawHeatmapCard(
|
||||
child: ReclaimCard(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -103,14 +103,14 @@ class _NormRow extends StatelessWidget {
|
|||
Text(
|
||||
evaluation.norm.eli,
|
||||
style: t.labelSmall?.copyWith(
|
||||
fontFamily: LawHeatmapTypography.mono,
|
||||
color: LawHeatmapColors.mute,
|
||||
fontFamily: ReclaimTypography.mono,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: LawHeatmapSpace.lg),
|
||||
const SizedBox(width: ReclaimSpace.lg),
|
||||
Expanded(
|
||||
child: _MetricColumn(
|
||||
label: 'Schaden / Jahr',
|
||||
|
|
@ -130,7 +130,7 @@ class _NormRow extends StatelessWidget {
|
|||
value: _kmu(evaluation.affectedCount),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: LawHeatmapSpace.md),
|
||||
const SizedBox(width: ReclaimSpace.md),
|
||||
TierBadge(tier: evaluation.tierLowest),
|
||||
],
|
||||
),
|
||||
|
|
@ -166,7 +166,7 @@ class _MetricColumn extends StatelessWidget {
|
|||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: t.labelSmall?.copyWith(color: LawHeatmapColors.mute),
|
||||
style: t.labelSmall?.copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(value, style: t.titleMedium),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/repository.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import '../widgets/delta_mark.dart';
|
||||
import 'about_page.dart';
|
||||
import 'heatmap_page.dart';
|
||||
|
|
@ -42,18 +42,18 @@ class _ShellPageState extends State<ShellPage> {
|
|||
onDestinationSelected: (i) => setState(() => _index = i),
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: LawHeatmapSpace.lg,
|
||||
horizontal: LawHeatmapSpace.md,
|
||||
vertical: ReclaimSpace.lg,
|
||||
horizontal: ReclaimSpace.md,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
const DeltaMark(size: 36),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
Text(
|
||||
'F∆I',
|
||||
style: t.labelLarge?.copyWith(
|
||||
letterSpacing: 2,
|
||||
color: LawHeatmapColors.signal,
|
||||
color: ReclaimColors.signal,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'lawheatmap_tokens.dart';
|
||||
import 'reclaim_tokens.dart';
|
||||
|
||||
/// ThemeData assembly for the F∆I Law-Heatmap client.
|
||||
/// ThemeData assembly for the F∆I Recl∆Im client.
|
||||
///
|
||||
/// Dark mode is the default (consistent with fai_web's
|
||||
/// `color-scheme: dark`). Light mode falls back to the paper
|
||||
/// palette for printing/screenshot work.
|
||||
class LawHeatmapTheme {
|
||||
LawHeatmapTheme._();
|
||||
class ReclaimTheme {
|
||||
ReclaimTheme._();
|
||||
|
||||
static ThemeData dark() => _build(Brightness.dark);
|
||||
static ThemeData light() => _build(Brightness.light);
|
||||
|
||||
static ThemeData _build(Brightness brightness) {
|
||||
final isDark = brightness == Brightness.dark;
|
||||
final canvas = isDark ? LawHeatmapColors.ink : LawHeatmapColors.paper;
|
||||
final canvas = isDark ? ReclaimColors.ink : ReclaimColors.paper;
|
||||
final surface =
|
||||
isDark ? LawHeatmapColors.inkRaised : LawHeatmapColors.paperRaised;
|
||||
isDark ? ReclaimColors.inkRaised : ReclaimColors.paperRaised;
|
||||
final onSurface = isDark
|
||||
? const Color(0xFFE9E7E2)
|
||||
: const Color(0xFF1A1B1E);
|
||||
|
||||
final colorScheme = ColorScheme(
|
||||
brightness: brightness,
|
||||
primary: LawHeatmapColors.signal,
|
||||
onPrimary: LawHeatmapColors.ink,
|
||||
secondary: LawHeatmapColors.mute,
|
||||
primary: ReclaimColors.signal,
|
||||
onPrimary: ReclaimColors.ink,
|
||||
secondary: ReclaimColors.mute,
|
||||
onSecondary: onSurface,
|
||||
error: const Color(0xFFD8723A),
|
||||
onError: LawHeatmapColors.ink,
|
||||
onError: ReclaimColors.ink,
|
||||
surface: surface,
|
||||
onSurface: onSurface,
|
||||
);
|
||||
|
|
@ -42,33 +42,33 @@ class LawHeatmapTheme {
|
|||
colorScheme: colorScheme,
|
||||
scaffoldBackgroundColor: canvas,
|
||||
canvasColor: canvas,
|
||||
fontFamily: LawHeatmapTypography.body,
|
||||
fontFamily: ReclaimTypography.body,
|
||||
textTheme: textTheme,
|
||||
cardTheme: CardThemeData(
|
||||
color: surface,
|
||||
elevation: 0,
|
||||
margin: EdgeInsets.zero,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(LawHeatmapRadius.md),
|
||||
borderRadius: BorderRadius.all(ReclaimRadius.md),
|
||||
side: BorderSide(color: Color(0x24FFFFFF)),
|
||||
),
|
||||
),
|
||||
dividerTheme: DividerThemeData(
|
||||
color: onSurface.withValues(alpha: LawHeatmapColors.hairlineDarkOpacity),
|
||||
color: onSurface.withValues(alpha: ReclaimColors.hairlineDarkOpacity),
|
||||
thickness: 1,
|
||||
space: 1,
|
||||
),
|
||||
filledButtonTheme: FilledButtonThemeData(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: LawHeatmapColors.signal,
|
||||
foregroundColor: LawHeatmapColors.ink,
|
||||
backgroundColor: ReclaimColors.signal,
|
||||
foregroundColor: ReclaimColors.ink,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(LawHeatmapRadius.sm),
|
||||
borderRadius: BorderRadius.all(ReclaimRadius.sm),
|
||||
),
|
||||
textStyle: textTheme.labelLarge,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LawHeatmapSpace.lg,
|
||||
vertical: LawHeatmapSpace.md,
|
||||
horizontal: ReclaimSpace.lg,
|
||||
vertical: ReclaimSpace.md,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -76,8 +76,8 @@ class LawHeatmapTheme {
|
|||
}
|
||||
|
||||
static TextTheme _textTheme(Color onSurface) {
|
||||
const display = LawHeatmapTypography.display;
|
||||
const body = LawHeatmapTypography.body;
|
||||
const display = ReclaimTypography.display;
|
||||
const body = ReclaimTypography.body;
|
||||
return TextTheme(
|
||||
displaySmall: TextStyle(
|
||||
fontFamily: display,
|
||||
|
|
@ -123,5 +123,5 @@ class LawHeatmapTheme {
|
|||
/// Convenience: JetBrains-Mono variant of an existing style for
|
||||
/// technical content (ELI/CELEX, SHA-256, audit-event IDs).
|
||||
static TextStyle mono(TextStyle base) =>
|
||||
base.copyWith(fontFamily: LawHeatmapTypography.mono);
|
||||
base.copyWith(fontFamily: ReclaimTypography.mono);
|
||||
}
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Visual tokens for the F∆I Law-Heatmap client, sourced from the
|
||||
/// Visual tokens for the F∆I Recl∆Im client, sourced from the
|
||||
/// fai_web brand palette (see fai_web/src/styles/global.css:14-20).
|
||||
///
|
||||
/// Unlike `fai_chain_studio`'s `ChainColors` (Tailwind sky-400 —
|
||||
/// dev-tool look), this palette matches the public-facing brand:
|
||||
/// ink/paper with a petrol "signal" accent that doubles as the eye
|
||||
/// of the `∆` mark.
|
||||
class LawHeatmapColors {
|
||||
LawHeatmapColors._();
|
||||
class ReclaimColors {
|
||||
ReclaimColors._();
|
||||
|
||||
// Core palette (fai_web/src/styles/global.css)
|
||||
static const ink = Color(0xFF08090A);
|
||||
|
|
@ -40,8 +40,8 @@ class LawHeatmapColors {
|
|||
|
||||
/// Spacing scale — 4/8/12/16/24/32/48 multiples, matching
|
||||
/// `ChainSpace` from `fai_chain_studio/lib/theme/tokens.dart`.
|
||||
class LawHeatmapSpace {
|
||||
LawHeatmapSpace._();
|
||||
class ReclaimSpace {
|
||||
ReclaimSpace._();
|
||||
|
||||
static const xs = 4.0;
|
||||
static const sm = 8.0;
|
||||
|
|
@ -52,15 +52,15 @@ class LawHeatmapSpace {
|
|||
static const xxxl = 48.0;
|
||||
}
|
||||
|
||||
class LawHeatmapRadius {
|
||||
LawHeatmapRadius._();
|
||||
class ReclaimRadius {
|
||||
ReclaimRadius._();
|
||||
|
||||
static const sm = Radius.circular(6);
|
||||
static const md = Radius.circular(10);
|
||||
}
|
||||
|
||||
class LawHeatmapTypography {
|
||||
LawHeatmapTypography._();
|
||||
class ReclaimTypography {
|
||||
ReclaimTypography._();
|
||||
|
||||
static const display = 'SpaceGroteskVariable';
|
||||
static const body = 'InterVariable';
|
||||
|
|
@ -2,7 +2,7 @@ import 'dart:math' as math;
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
|
||||
/// The F∆I / Ch∆In brand mark: an upward triangle (the `∆`) with
|
||||
/// a petrol "eye" at the centre. Geometry mirrors fai_web's
|
||||
|
|
@ -89,7 +89,7 @@ class _DeltaPainter extends CustomPainter {
|
|||
// Eye — petrol fill, centred on the triangle's centroid.
|
||||
final eyeCentre = Offset(w / 2, inset + (h - 2 * inset) * 2 / 3);
|
||||
final eyeR = w * 0.06 * pulse;
|
||||
final eye = Paint()..color = LawHeatmapColors.signal;
|
||||
final eye = Paint()..color = ReclaimColors.signal;
|
||||
canvas.drawCircle(eyeCentre, eyeR, eye);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
|
||||
/// Permanent banner shown above all data screens in mock mode.
|
||||
/// Carries the political-defensibility caveat: this is demo data,
|
||||
|
|
@ -14,29 +14,29 @@ class DemoBanner extends StatelessWidget {
|
|||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: LawHeatmapSpace.lg,
|
||||
vertical: LawHeatmapSpace.sm,
|
||||
horizontal: ReclaimSpace.lg,
|
||||
vertical: ReclaimSpace.sm,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: LawHeatmapColors.tierT4.withValues(alpha: 0.12),
|
||||
color: ReclaimColors.tierT4.withValues(alpha: 0.12),
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: LawHeatmapColors.tierT4.withValues(alpha: 0.55),
|
||||
color: ReclaimColors.tierT4.withValues(alpha: 0.55),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.science_outlined,
|
||||
size: 18, color: LawHeatmapColors.tierT4),
|
||||
const SizedBox(width: LawHeatmapSpace.sm),
|
||||
size: 18, color: ReclaimColors.tierT4),
|
||||
const SizedBox(width: ReclaimSpace.sm),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Demo-Daten — Phase 0, ohne Verbands-Erhebung. '
|
||||
'Keine Juristen-Approval, keine Beirats-Validierung. '
|
||||
'Alle Werte tragen Tier T4, bis T1/T2-Pipeline läuft.',
|
||||
style: t.labelSmall?.copyWith(
|
||||
color: LawHeatmapColors.tierT4,
|
||||
color: ReclaimColors.tierT4,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/models.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import 'lawheatmap_card.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import 'reclaim_card.dart';
|
||||
import 'source_chip.dart';
|
||||
|
||||
/// Sidebar listing the citable sources behind an evaluation.
|
||||
|
|
@ -16,39 +16,39 @@ class EvidenceSidebar extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return LawHeatmapCard(
|
||||
return ReclaimCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Quellen', style: t.headlineSmall),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
Text(
|
||||
'Jede Zahl trägt die Tier-Stufe ihres schwächsten '
|
||||
'Bestandteils (Regel der niedrigsten Stufe, §6.7).',
|
||||
style: t.labelSmall?.copyWith(color: LawHeatmapColors.mute),
|
||||
style: t.labelSmall?.copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.lg),
|
||||
const SizedBox(height: ReclaimSpace.lg),
|
||||
for (final s in evaluation.sources) SourceChip(source: s),
|
||||
const Divider(height: LawHeatmapSpace.xl),
|
||||
const Divider(height: ReclaimSpace.xl),
|
||||
Text('Audit-Event', style: t.labelLarge),
|
||||
const SizedBox(height: 4),
|
||||
SelectableText(
|
||||
evaluation.auditEventId,
|
||||
style: t.labelSmall?.copyWith(
|
||||
fontFamily: LawHeatmapTypography.mono,
|
||||
color: LawHeatmapColors.mute,
|
||||
fontFamily: ReclaimTypography.mono,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
Text(
|
||||
'Quell-SHA-256:',
|
||||
style: t.labelSmall?.copyWith(color: LawHeatmapColors.mute),
|
||||
style: t.labelSmall?.copyWith(color: ReclaimColors.mute),
|
||||
),
|
||||
SelectableText(
|
||||
evaluation.norm.sourceSha256,
|
||||
style: t.labelSmall?.copyWith(
|
||||
fontFamily: LawHeatmapTypography.mono,
|
||||
color: LawHeatmapColors.mute,
|
||||
fontFamily: ReclaimTypography.mono,
|
||||
color: ReclaimColors.mute,
|
||||
fontSize: 10,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import 'dart:math' as math;
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/models.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
|
||||
/// 2D scatter heatmap — x: Schaden (€/Jahr, log-scaled),
|
||||
/// y: Nutzen (0–5), point area: Betroffenheit (sqrt-scaled).
|
||||
|
|
@ -121,7 +121,7 @@ class _HeatmapPainter extends CustomPainter {
|
|||
void paint(Canvas canvas, Size size) {
|
||||
final layout = _Layout(size);
|
||||
final onSurface = theme.colorScheme.onSurface;
|
||||
const mute = LawHeatmapColors.mute;
|
||||
const mute = ReclaimColors.mute;
|
||||
|
||||
// Plot frame.
|
||||
final frame = Paint()
|
||||
|
|
@ -163,7 +163,7 @@ class _HeatmapPainter extends CustomPainter {
|
|||
const axisStyle = TextStyle(
|
||||
color: mute,
|
||||
fontSize: 10,
|
||||
fontFamily: LawHeatmapTypography.body,
|
||||
fontFamily: ReclaimTypography.body,
|
||||
);
|
||||
_drawText(
|
||||
canvas,
|
||||
|
|
@ -205,8 +205,8 @@ class _HeatmapPainter extends CustomPainter {
|
|||
final r = layout.radius(e);
|
||||
final hot = e.skmEurPerYear > 50000000;
|
||||
final color = Color.lerp(
|
||||
LawHeatmapColors.benefitSaturated,
|
||||
LawHeatmapColors.harmWarm,
|
||||
ReclaimColors.benefitSaturated,
|
||||
ReclaimColors.harmWarm,
|
||||
hot ? 0.5 : 0.0,
|
||||
)!;
|
||||
final body = Paint()..color = color.withValues(alpha: 0.7);
|
||||
|
|
@ -224,7 +224,7 @@ class _HeatmapPainter extends CustomPainter {
|
|||
TextStyle(
|
||||
color: onSurface,
|
||||
fontSize: 11,
|
||||
fontFamily: LawHeatmapTypography.body,
|
||||
fontFamily: ReclaimTypography.body,
|
||||
fontWeight: i == hoverIndex ? FontWeight.w600 : FontWeight.w400,
|
||||
),
|
||||
);
|
||||
|
|
@ -240,8 +240,8 @@ class _HeatmapPainter extends CustomPainter {
|
|||
..color = theme.colorScheme.surface.withValues(alpha: 0.92);
|
||||
final boxBorder = Paint()
|
||||
..style = PaintingStyle.stroke
|
||||
..color = LawHeatmapColors.signal.withValues(alpha: 0.6);
|
||||
final rrect = RRect.fromRectAndRadius(box, LawHeatmapRadius.sm);
|
||||
..color = ReclaimColors.signal.withValues(alpha: 0.6);
|
||||
final rrect = RRect.fromRectAndRadius(box, ReclaimRadius.sm);
|
||||
canvas.drawRRect(rrect, boxPaint);
|
||||
canvas.drawRRect(rrect, boxBorder);
|
||||
_drawText(
|
||||
|
|
@ -252,7 +252,7 @@ class _HeatmapPainter extends CustomPainter {
|
|||
color: onSurface,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: LawHeatmapTypography.body,
|
||||
fontFamily: ReclaimTypography.body,
|
||||
),
|
||||
);
|
||||
_drawText(
|
||||
|
|
@ -262,7 +262,7 @@ class _HeatmapPainter extends CustomPainter {
|
|||
const TextStyle(
|
||||
color: mute,
|
||||
fontSize: 11,
|
||||
fontFamily: LawHeatmapTypography.body,
|
||||
fontFamily: ReclaimTypography.body,
|
||||
),
|
||||
);
|
||||
_drawText(
|
||||
|
|
@ -272,7 +272,7 @@ class _HeatmapPainter extends CustomPainter {
|
|||
const TextStyle(
|
||||
color: mute,
|
||||
fontSize: 11,
|
||||
fontFamily: LawHeatmapTypography.body,
|
||||
fontFamily: ReclaimTypography.body,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import '../data/hub_repository.dart';
|
||||
import '../data/repository.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import 'lawheatmap_card.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import 'reclaim_card.dart';
|
||||
|
||||
/// Lists the capabilities the connected hub has installed.
|
||||
/// Empty / explanatory state when the active repository is not
|
||||
|
|
@ -39,7 +39,7 @@ class _HubCapabilitiesCardState extends State<HubCapabilitiesCard> {
|
|||
final repo = widget.repository;
|
||||
final liveHub = repo is HubRepository && repo.isHealthy;
|
||||
|
||||
return LawHeatmapCard(
|
||||
return ReclaimCard(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -53,13 +53,13 @@ class _HubCapabilitiesCardState extends State<HubCapabilitiesCard> {
|
|||
icon: const Icon(Icons.refresh),
|
||||
),
|
||||
]),
|
||||
const SizedBox(height: LawHeatmapSpace.sm),
|
||||
const SizedBox(height: ReclaimSpace.sm),
|
||||
if (!liveHub)
|
||||
Text(
|
||||
'Sichtbar sobald die App im Hub-Modus startet und '
|
||||
'der Hub erreichbar ist (siehe Verbindung oben).',
|
||||
style: t.labelSmall?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
)
|
||||
else
|
||||
|
|
@ -68,14 +68,14 @@ class _HubCapabilitiesCardState extends State<HubCapabilitiesCard> {
|
|||
builder: (context, snap) {
|
||||
if (snap.connectionState == ConnectionState.waiting) {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.all(LawHeatmapSpace.md),
|
||||
padding: EdgeInsets.all(ReclaimSpace.md),
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
if (snap.hasError) {
|
||||
return Text('Fehler: ${snap.error}',
|
||||
style: t.labelLarge
|
||||
?.copyWith(color: LawHeatmapColors.harmWarm));
|
||||
?.copyWith(color: ReclaimColors.harmWarm));
|
||||
}
|
||||
final items = snap.data ?? const [];
|
||||
if (items.isEmpty) {
|
||||
|
|
@ -83,7 +83,7 @@ class _HubCapabilitiesCardState extends State<HubCapabilitiesCard> {
|
|||
'Hub hat noch keine Capabilities installiert. '
|
||||
'Mit `chain install <name>` hinzufügen.',
|
||||
style: t.bodyLarge?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ class _HubCapabilitiesCardState extends State<HubCapabilitiesCard> {
|
|||
child: Text(
|
||||
'${c.capability}@${c.version}',
|
||||
style: t.bodyLarge?.copyWith(
|
||||
fontFamily: LawHeatmapTypography.mono,
|
||||
fontFamily: ReclaimTypography.mono,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -110,7 +110,7 @@ class _HubCapabilitiesCardState extends State<HubCapabilitiesCard> {
|
|||
'${c.moduleName} ${c.moduleVersion}'
|
||||
'${c.kind.isEmpty ? "" : " · ${c.kind}"}',
|
||||
style: t.labelSmall?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
|
||||
/// Surface container — visual equivalent of fai_chain_studio's
|
||||
/// `ChainCard`, retuned to the fai_web palette.
|
||||
class LawHeatmapCard extends StatelessWidget {
|
||||
const LawHeatmapCard({
|
||||
class ReclaimCard extends StatelessWidget {
|
||||
const ReclaimCard({
|
||||
super.key,
|
||||
required this.child,
|
||||
this.padding =
|
||||
const EdgeInsets.all(LawHeatmapSpace.lg),
|
||||
const EdgeInsets.all(ReclaimSpace.lg),
|
||||
this.accent = false,
|
||||
this.expand = false,
|
||||
});
|
||||
|
|
@ -39,9 +39,9 @@ class LawHeatmapCard extends StatelessWidget {
|
|||
Container(
|
||||
height: 2,
|
||||
decoration: const BoxDecoration(
|
||||
color: LawHeatmapColors.signal,
|
||||
color: ReclaimColors.signal,
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: LawHeatmapRadius.md,
|
||||
top: ReclaimRadius.md,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/models.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
import 'tier_badge.dart';
|
||||
|
||||
/// A citable source line: tier badge + label + (planned) link.
|
||||
|
|
@ -16,7 +16,7 @@ class SourceChip extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: LawHeatmapSpace.sm),
|
||||
padding: const EdgeInsets.only(bottom: ReclaimSpace.sm),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
|
@ -24,7 +24,7 @@ class SourceChip extends StatelessWidget {
|
|||
padding: const EdgeInsets.only(top: 2),
|
||||
child: TierBadge(tier: source.tier, compact: true),
|
||||
),
|
||||
const SizedBox(width: LawHeatmapSpace.sm),
|
||||
const SizedBox(width: ReclaimSpace.sm),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
|
@ -33,14 +33,14 @@ class SourceChip extends StatelessWidget {
|
|||
Text(
|
||||
source.url,
|
||||
style: t.labelSmall?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
),
|
||||
),
|
||||
if (source.note != null)
|
||||
Text(
|
||||
source.note!,
|
||||
style: t.labelSmall?.copyWith(
|
||||
color: LawHeatmapColors.mute,
|
||||
color: ReclaimColors.mute,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/models.dart';
|
||||
import '../theme/lawheatmap_tokens.dart';
|
||||
import '../theme/reclaim_tokens.dart';
|
||||
|
||||
/// Tier badge — surfaces the lowest evidence tier in a composed
|
||||
/// value. Every figure in the app carries one of these next to it.
|
||||
|
|
@ -15,22 +15,22 @@ class TierBadge extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final t = Theme.of(context).textTheme;
|
||||
final color = switch (tier) {
|
||||
EvidenceTier.t1 => LawHeatmapColors.tierT1,
|
||||
EvidenceTier.t2 => LawHeatmapColors.tierT2,
|
||||
EvidenceTier.t3 => LawHeatmapColors.tierT3,
|
||||
EvidenceTier.t4 => LawHeatmapColors.tierT4,
|
||||
EvidenceTier.t1 => ReclaimColors.tierT1,
|
||||
EvidenceTier.t2 => ReclaimColors.tierT2,
|
||||
EvidenceTier.t3 => ReclaimColors.tierT3,
|
||||
EvidenceTier.t4 => ReclaimColors.tierT4,
|
||||
};
|
||||
return Tooltip(
|
||||
message: '${tier.short} — ${tier.description}',
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: compact ? 6 : LawHeatmapSpace.sm,
|
||||
horizontal: compact ? 6 : ReclaimSpace.sm,
|
||||
vertical: compact ? 2 : 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.18),
|
||||
border: Border.all(color: color.withValues(alpha: 0.55)),
|
||||
borderRadius: const BorderRadius.all(LawHeatmapRadius.sm),
|
||||
borderRadius: const BorderRadius.all(ReclaimRadius.sm),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue