Stage 1: project setup, Exercise Library, both Mode designs and the Mode switch
- Flutter Android app on CookIT's stack (provider, shared_preferences, gen-l10n) - tools/exercise-import turns free-exercise-db into 876 bundled Exercises with 1,746 WebP images (20 MB); stretching -> Stretching, rest -> Workout - ZenStyle tokens per Mode: calm rounded sage/teal with breath ripples vs. dark ember-to-red with floor-tape slashes; the theme morphs at each Mode's own pace - Remembered global Mode switch, Plans / Library / History tabs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5dfa995d55
commit
1289fadb98
1822 files changed
+2819
No files matched your search
@@ -0,0 +1,69 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'zen_style.dart';
|
||||
|
||||
/// A tab's big title and an optional line under it.
|
||||
class PageHeader extends StatelessWidget {
|
||||
const PageHeader({super.key, required this.title, this.subtitle});
|
||||
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = ZenStyle.of(context);
|
||||
final text = Theme.of(context).textTheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 28, 20, 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: text.headlineLarge),
|
||||
if (subtitle != null) ...[
|
||||
const SizedBox(height: 6),
|
||||
Text(subtitle!, style: text.bodyLarge?.copyWith(color: s.inkMuted)),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// What an empty tab shows: what will appear here and how to get it there.
|
||||
class EmptyState extends StatelessWidget {
|
||||
const EmptyState({super.key, required this.icon, required this.title, required this.body});
|
||||
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String body;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = ZenStyle.of(context);
|
||||
final text = Theme.of(context).textTheme;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
color: s.surfaceSoft,
|
||||
borderRadius: BorderRadius.circular(s.controlRadius.clamp(0, 28)),
|
||||
),
|
||||
child: Icon(icon, color: s.accent),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(title, style: text.titleLarge),
|
||||
const SizedBox(height: 6),
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 340),
|
||||
child: Text(body, style: text.bodyMedium?.copyWith(color: s.inkMuted)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user