Replaces the Material-default look with a deliberate visual
language. Single accent (sky-cyan), Inter + JetBrains Mono via
google_fonts, dense rows over puffy cards, micro-interactions
under 250ms. Dark-first, light reaches parity.
New foundation under lib/theme/:
- tokens.dart FaiColors / FaiSpace / FaiRadius / FaiMotion
- theme.dart ColorScheme + typography + component themes for
light and dark, plus FaiTheme.mono helper for
technical strings (IDs, paths, capability refs).
Six primitives under lib/widgets/:
- FaiCard flat card, optional accent stripe (top or
left). No shadows.
- FaiPill small inline label with five tones
(neutral / accent / success / warning /
danger), optional mono and leading icon.
- FaiStatusDot breathing dot, used as a "live" indicator.
- FaiDataRow Linear-style dense row for the audit
stream — hover-elevation, mono leading,
coloured leading stripe.
- FaiEmptyState gracious icon + title + hint + action,
replaces "(no data)" everywhere.
- FaiDeltaMark the ∆ signature element. Three modes —
idle (still), live (gentle pulse), busy
(slow rotation). Drawn from primitives,
not a font glyph. Lives in the sidebar
header so the brand is always visible.
Page-level changes:
- main.dart custom 220px sidebar replaces the Material
NavigationRail. ∆ on top, hub-connection
pill below it, hover-animated destinations,
page transitions are 200ms slide+fade.
- modules.dart FaiCard rows with capability pills.
- audit.dart FaiDataRow stream, segmented filter chips,
live status bar with hash-chain badge.
- approvals.dart FaiCard with accent-top stripe, structured
action footer, toast on approve/reject,
themed reject-reason dialog.
google_fonts added as dep. flutter analyze clean. flutter test
2/2. flutter build macos --debug succeeds.
Bumps fai_studio 0.2.0 -> 0.3.0.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
71 lines
2.5 KiB
Dart
71 lines
2.5 KiB
Dart
// Design tokens for F∆I Studio.
|
|
//
|
|
// One file, semantic names, no magic numbers in the rest of the
|
|
// codebase. Both light and dark modes derive from these tokens.
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
/// Colour palette. Single strong accent (F∆I Cyan) plus neutral
|
|
/// greys. Status colours stay restrained — no candy palette.
|
|
class FaiColors {
|
|
FaiColors._();
|
|
|
|
// Brand accent. Slightly cooler / more saturated than the
|
|
// initial #1E3A8A — this reads more as "deep tech, alive"
|
|
// than the previous corporate navy.
|
|
static const accent = Color(0xFF38BDF8); // sky-400 / cyan
|
|
static const accentDeep = Color(0xFF0EA5E9); // sky-500
|
|
static const accentMuted = Color(0xFF0369A1); // sky-700
|
|
|
|
// Semantic status. Used sparingly: tones, not flat fills.
|
|
static const success = Color(0xFF22C55E); // green-500
|
|
static const warning = Color(0xFFF59E0B); // amber-500
|
|
static const danger = Color(0xFFEF4444); // red-500
|
|
|
|
// Neutral scale. Dark-mode first.
|
|
static const black = Color(0xFF09090B); // canvas
|
|
static const surface = Color(0xFF18181B); // cards
|
|
static const surfaceHigh = Color(0xFF27272A); // elevated
|
|
static const border = Color(0xFF3F3F46); // 1px outlines
|
|
static const muted = Color(0xFF71717A); // de-emphasised text
|
|
static const text = Color(0xFFE4E4E7); // body
|
|
static const textStrong = Color(0xFFFAFAFA); // headings
|
|
|
|
// Light-mode neutrals. Calmer than pure white.
|
|
static const lightCanvas = Color(0xFFFAFAFA);
|
|
static const lightSurface = Color(0xFFFFFFFF);
|
|
static const lightSurfaceHigh = Color(0xFFF4F4F5);
|
|
static const lightBorder = Color(0xFFE4E4E7);
|
|
static const lightMuted = Color(0xFF71717A);
|
|
static const lightText = Color(0xFF18181B);
|
|
static const lightTextStrong = Color(0xFF09090B);
|
|
}
|
|
|
|
/// Spacing scale. Stick to multiples of 4. Keep the vocabulary
|
|
/// small — six steps cover everything.
|
|
class FaiSpace {
|
|
FaiSpace._();
|
|
static const xs = 4.0;
|
|
static const sm = 8.0;
|
|
static const md = 12.0;
|
|
static const lg = 16.0;
|
|
static const xl = 24.0;
|
|
static const xxl = 32.0;
|
|
static const xxxl = 48.0;
|
|
}
|
|
|
|
/// Border radii. Two sizes only.
|
|
class FaiRadius {
|
|
FaiRadius._();
|
|
static const sm = 6.0;
|
|
static const md = 10.0;
|
|
}
|
|
|
|
/// Animation durations. Keep them under 300ms for power-user feel.
|
|
class FaiMotion {
|
|
FaiMotion._();
|
|
static const fast = Duration(milliseconds: 120);
|
|
static const base = Duration(milliseconds: 200);
|
|
static const slow = Duration(milliseconds: 320);
|
|
static const easing = Curves.easeOutCubic;
|
|
}
|