// Flutter Styleguide — matches inou.com/styleguide import 'package:flutter/material.dart'; import 'package:inou_app/design/inou_theme.dart'; import 'package:inou_app/design/inou_text.dart'; import 'package:inou_app/design/widgets/widgets.dart'; class StyleguideScreen extends StatefulWidget { const StyleguideScreen({super.key}); @override State createState() => _StyleguideScreenState(); } class _StyleguideScreenState extends State { String? _selectedOption = 'Option 1'; String _selectedSex = 'male'; bool _checkboxValue = true; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: InouTheme.bg, body: Column( children: [ // Header component const InouHeader(), // Content Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: InouTheme.maxWidth), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Page title Text('Style Guide', style: InouText.pageTitle), const SizedBox(height: 8), Text( 'Design system components for inou', style: InouText.bodyLight.copyWith( color: InouTheme.textMuted, ), ), const SizedBox(height: 32), // Header Component Preview _buildHeaderSection(), // Text Blocks _buildTextBlocksSection(), // Typography _buildTypographySection(), // Colors _buildColorsSection(), // Buttons _buildButtonsSection(), // Badges _buildBadgesSection(), // Messages _buildMessagesSection(), // Form Elements _buildFormsSection(), // Profile Cards _buildProfileCardsSection(), // Data Cards (Imaging, Labs) _buildDataCardsSection(), // Settings _buildSettingsSection(), // Genetics _buildGeneticsSection(), // Notes _buildNotesSection(), // Supplements _buildSupplementsSection(), // Peptides _buildPeptidesSection(), // Upload Area _buildUploadSection(), // Empty State _buildEmptyStateSection(), const SizedBox(height: 48), ], ), ), ), ), ), ], ), ); } String _selectedLLM = 'claude'; String _selectedUnits = 'metric'; Widget _buildSettingsSection() { return InouCard( title: 'Settings', indicatorColor: InouTheme.indicatorPrivacy, child: Column( children: [ // LLM Selector Padding( padding: const EdgeInsets.all(16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Primary AI Assistant', style: InouText.label), const SizedBox(height: 2), Text( 'Used for "Ask AI" prompts and analysis', style: InouText.bodySmall.copyWith(color: InouTheme.textMuted), ), ], ), ), const SizedBox(width: 24), Expanded( flex: 3, child: Column( children: [ _LLMOption( icon: '🤖', name: 'Claude (Anthropic)', selected: _selectedLLM == 'claude', onTap: () => setState(() => _selectedLLM = 'claude'), ), _LLMOption( icon: '💬', name: 'ChatGPT (OpenAI)', selected: _selectedLLM == 'chatgpt', onTap: () => setState(() => _selectedLLM = 'chatgpt'), ), _LLMOption( icon: '✖', name: 'Grok (xAI)', selected: _selectedLLM == 'grok', onTap: () => setState(() => _selectedLLM = 'grok'), ), ], ), ), ], ), ), const Divider(height: 1, color: InouTheme.border), // Units Padding( padding: const EdgeInsets.all(16), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Units', style: InouText.label), const SizedBox(height: 2), Text( 'Measurement system for vitals', style: InouText.bodySmall.copyWith(color: InouTheme.textMuted), ), ], ), ), const SizedBox(width: 24), Expanded( flex: 3, child: InouSelect( value: _selectedUnits, options: const [ InouSelectOption(value: 'metric', label: 'Metric (kg, cm, °C)'), InouSelectOption(value: 'imperial', label: 'Imperial (lb, in, °F)'), ], onChanged: (v) => setState(() => _selectedUnits = v ?? 'metric'), ), ), ], ), ), ], ), ); } Widget _buildGeneticsSection() { return InouCard( title: 'Genetics', subtitle: 'Medication Response · 47 variants', indicatorColor: InouTheme.indicatorGenetics, child: Column( children: [ InouDataRow( label: 'Medication Response', meta: '47 variants', isExpandable: true, initiallyExpanded: true, children: [ Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text('CYP2C19', style: InouText.label), const SizedBox(width: 8), Text('rs4244285', style: InouText.mono.copyWith(color: InouTheme.textMuted)), const Spacer(), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: InouTheme.bg, borderRadius: BorderRadius.circular(4), ), child: Text('G;A', style: InouText.mono.copyWith(fontWeight: FontWeight.w600)), ), const SizedBox(width: 8), Text('intermediate', style: InouText.bodySmall.copyWith(color: InouTheme.accent)), ], ), const SizedBox(height: 8), Text( 'Intermediate metabolizer for clopidogrel (Plavix). May need dose adjustment or alternative medication.', style: InouText.bodySmall.copyWith(color: InouTheme.textMuted, height: 1.4), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: InouTheme.accentLight, border: Border.all(color: InouTheme.accent), borderRadius: BorderRadius.circular(4), ), child: Text( 'Ask AI', style: InouText.bodySmall.copyWith(color: InouTheme.accent, fontWeight: FontWeight.w500), ), ), ], ), ), ], ), InkWell( onTap: () {}, child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: const BoxDecoration( border: Border(top: BorderSide(color: InouTheme.border)), ), child: Center( child: Text( 'Show all 47 variants in Medication Response →', style: InouText.bodySmall.copyWith(color: InouTheme.accent), ), ), ), ), const InouDataRow(label: 'Metabolism', meta: '23 variants', isExpandable: true), const InouDataRow(label: 'Cardiovascular', meta: '18 variants', isExpandable: true), ], ), ); } Widget _buildNotesSection() { return InouCard( title: 'Notes', subtitle: 'Health journal entries', indicatorColor: InouTheme.indicatorJournal, trailing: InouButton( text: '+ Add', variant: ButtonVariant.secondary, size: ButtonSize.small, onPressed: () {}, ), child: Column( children: [ InouDataRow( label: 'Knee injury', meta: '3 photos', date: 'Dec 20', leading: const InouNoteIcon(emoji: '📷', color: Color(0xFF6366F1)), isExpandable: true, initiallyExpanded: true, children: [ Container( padding: const EdgeInsets.all(16), color: InouTheme.bg, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Photos Row( children: [ _PhotoPlaceholder(label: 'Dec 20'), const SizedBox(width: 12), _PhotoPlaceholder(label: 'Dec 22'), const SizedBox(width: 12), _PhotoPlaceholder(label: 'Dec 26'), const SizedBox(width: 12), _AddPhotoPlaceholder(), ], ), const SizedBox(height: 16), // Timeline _NoteTimelineEntry(date: 'Dec 20, 3:45 PM', text: 'Jim fell on his knee at soccer practice. Swelling visible, applied ice.'), _NoteTimelineEntry(date: 'Dec 22, 10:20 AM', text: 'Swelling reduced. Still some bruising. Can walk without pain.'), _NoteTimelineEntry(date: 'Dec 26, 9:15 AM', text: 'Almost fully healed. Light bruise remaining.'), ], ), ), ], ), InouDataRow( label: 'Mild headache after workout', date: 'Dec 25', leading: const InouNoteIcon(emoji: '📝', color: InouTheme.accent), isExpandable: true, ), ], ), ); } Widget _buildSupplementsSection() { return InouCard( title: 'Supplements', subtitle: 'Daily routine', indicatorColor: InouTheme.indicatorMedications, trailing: InouButton( text: '+ Add', variant: ButtonVariant.secondary, size: ButtonSize.small, onPressed: () {}, ), child: Column( children: const [ _SupplementRow(name: 'Vitamin D3', dose: '1 capsule', amount: '5000 IU', timing: 'morning, with food'), _SupplementRow(name: 'Omega-3 Fish Oil', dose: '2 capsules', amount: '2000 mg EPA/DHA', timing: 'morning, with food'), _SupplementRow(name: 'Magnesium Glycinate', dose: '2 capsules', amount: '400 mg', timing: 'evening'), _SupplementRow(name: 'Liquid B12', dose: '5 ml', amount: '1000 mcg', timing: 'morning'), ], ), ); } Widget _buildPeptidesSection() { return InouCard( title: 'Peptides', subtitle: 'Therapeutic protocols', indicatorColor: InouTheme.indicatorMedications, child: Column( children: const [ _PeptideRow(name: 'BPC-157', dose: '250 mcg subQ · 2x daily', endDate: 'until Jan 23, 2025', status: 'active'), _PeptideRow(name: 'TB-500', dose: '2.5 mg subQ · 2x weekly', endDate: 'until Feb 5, 2025', status: 'active'), _PeptideRow(name: 'BPC-157', dose: '250 mcg subQ · 2x daily', endDate: 'Aug 15 – Sep 7, 2025', status: 'completed'), ], ), ); } Widget _buildEmptyStateSection() { return InouCard( title: 'Empty State', indicatorColor: InouTheme.indicatorRecords, child: Container( padding: const EdgeInsets.all(32), child: Center( child: Text( 'No lab data', style: InouText.body.copyWith(color: InouTheme.textMuted), ), ), ), ); } Widget _buildHeaderSection() { return InouCard( title: 'Header Component', indicatorColor: InouTheme.accent, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'The InouHeader widget is shown at the top of this page.', style: InouText.body.copyWith(color: InouTheme.textMuted), ), const SizedBox(height: 16), Container( decoration: BoxDecoration( border: Border.all(color: InouTheme.border), borderRadius: InouTheme.borderRadiusLg, ), child: ClipRRect( borderRadius: InouTheme.borderRadiusLg, child: const InouHeader(), ), ), const SizedBox(height: 16), Text( 'Logo: "inou" (accent, 700) + "health" (muted, 300) • Font: Sora 1.75rem', style: InouText.mono.copyWith( color: InouTheme.textMuted, ), ), ], ), ), ); } Widget _buildTextBlocksSection() { return InouCard( title: 'Text Blocks', indicatorColor: InouTheme.indicatorImaging, child: Padding( padding: const EdgeInsets.all(32), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Your data. Your rules.', style: InouText.heroTitle, ), const SizedBox(height: 16), InouText.rich([ InouSpan.plain('We built ', style: InouText.intro), InouSpan.accent('inou', baseStyle: InouText.intro.copyWith(fontWeight: FontWeight.w700)), InouSpan.plain( ' because health data is personal. Not personal like "preferences" — personal like your body, your history, your family. So we made privacy the foundation, not an afterthought.', style: InouText.intro, ), ]), const SizedBox(height: 32), Text( 'What we collect', style: InouText.sectionTitle, ), const SizedBox(height: 16), Text( 'Account information.', style: InouText.subsectionTitle, ), const SizedBox(height: 8), Text( 'Name, email address, date of birth, and sex. Date of birth and sex help provide accurate medical context — an MRI interpretation differs significantly between a 6-year-old and a 16-year-old.', style: InouText.intro, ), ], ), ), ); } Widget _buildTypographySection() { return InouCard( title: 'Typography Scale', indicatorColor: InouTheme.indicatorLabs, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _TypographyRow('Page Title', InouText.pageTitle, '2.5rem / 800'), _TypographyRow('Section Title', InouText.sectionTitle, '1.4rem / 600'), _TypographyRow('Subsection Title', InouText.subsectionTitle, '1.1rem / 600'), _TypographyRow( 'LABEL / CATEGORY', InouText.labelCaps, '0.75rem / 600 / caps', ), _TypographyRow( 'Intro text — larger, lighter', InouText.intro, '1.15rem / 300', ), _TypographyRow( 'Body light — long-form', InouText.bodyLight, '1rem / 300', ), _TypographyRow( 'Body regular — UI labels', InouText.body, '1rem / 400', ), _TypographyRow( 'Mono: 1,234,567.89', InouText.mono, 'SF Mono', ), ], ), ), ); } Widget _buildColorsSection() { return InouCard( title: 'Colors', indicatorColor: InouTheme.indicatorUploads, child: Padding( padding: const EdgeInsets.all(16), child: Column( children: [ _ColorRow('Accent', InouTheme.accent, '#B45309'), _ColorRow('Text', InouTheme.text, '#1C1917'), _ColorRow('Text Muted', InouTheme.textMuted, '#78716C'), _ColorRow('Background', InouTheme.bg, '#F8F7F6', hasBorder: true), _ColorRow('Success', InouTheme.success, '#059669'), _ColorRow('Danger', InouTheme.danger, '#DC2626'), ], ), ), ); } Widget _buildButtonsSection() { return InouCard( title: 'Buttons', indicatorColor: InouTheme.indicatorVitals, child: Padding( padding: const EdgeInsets.all(24), child: Wrap( spacing: 12, runSpacing: 12, children: [ InouButton(text: 'Primary', onPressed: () {}), InouButton( text: 'Secondary', variant: ButtonVariant.secondary, onPressed: () {}, ), InouButton( text: 'Danger', variant: ButtonVariant.danger, onPressed: () {}, ), InouButton( text: 'Small', size: ButtonSize.small, onPressed: () {}, ), ], ), ), ); } Widget _buildBadgesSection() { return InouCard( title: 'Badges', indicatorColor: InouTheme.indicatorMedications, child: Padding( padding: const EdgeInsets.all(24), child: Wrap( spacing: 12, runSpacing: 12, children: const [ InouBadge(text: 'default'), InouBadge(text: 'care', variant: BadgeVariant.care), InouBadge(text: 'Coming Soon', variant: BadgeVariant.comingSoon), InouBadge(text: 'processing', variant: BadgeVariant.processing), ], ), ), ); } Widget _buildMessagesSection() { return InouCard( title: 'Messages', indicatorColor: InouTheme.indicatorRecords, child: Padding( padding: const EdgeInsets.all(24), child: Column( children: const [ InouMessage( message: 'Error message — something went wrong.', type: MessageType.error, ), SizedBox(height: 12), InouMessage( message: 'Info message — useful information.', type: MessageType.info, ), SizedBox(height: 12), InouMessage( message: 'Success message — operation completed.', type: MessageType.success, ), ], ), ), ); } Widget _buildFormsSection() { return InouCard( title: 'Form Elements', indicatorColor: InouTheme.indicatorJournal, child: Padding( padding: const EdgeInsets.all(24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const InouTextField( label: 'Text Input', placeholder: 'Enter text...', ), const SizedBox(height: 16), InouSelect( label: 'Select', value: _selectedOption, options: const [ InouSelectOption(value: 'Option 1', label: 'Option 1'), InouSelectOption(value: 'Option 2', label: 'Option 2'), InouSelectOption(value: 'Option 3', label: 'Option 3'), ], onChanged: (v) => setState(() => _selectedOption = v), ), const SizedBox(height: 16), const InouTextField( label: 'Code Input', placeholder: '123456', isCode: true, maxLength: 6, keyboardType: TextInputType.number, ), const SizedBox(height: 16), InouRadioGroup( value: _selectedSex, options: const [ InouRadioOption(value: 'male', label: 'Male'), InouRadioOption(value: 'female', label: 'Female'), ], onChanged: (v) => setState(() => _selectedSex = v ?? 'male'), ), const SizedBox(height: 16), InouCheckbox( value: _checkboxValue, label: 'Can add data (supplements, notes, etc.)', onChanged: (v) => setState(() => _checkboxValue = v ?? false), ), ], ), ), ); } Widget _buildProfileCardsSection() { return InouCard( title: 'Profile Cards', indicatorColor: InouTheme.indicatorImaging, child: Padding( padding: const EdgeInsets.all(24), child: LayoutBuilder( builder: (context, constraints) { final cardWidth = constraints.maxWidth > 700 ? (constraints.maxWidth - 24) / 3 : constraints.maxWidth; return Wrap( spacing: 12, runSpacing: 12, children: [ SizedBox( width: cardWidth, height: 180, child: InouProfileCard( name: 'Johan Jongsma', role: 'you', dob: '1985-03-15', sex: 'Male', stats: const [ ProfileStat('📷', '3 studies'), ProfileStat('🧪', '12 labs'), ProfileStat('🧬', 'genome'), ], onTap: () {}, ), ), SizedBox( width: cardWidth, height: 180, child: InouProfileCard( name: 'Sophia', role: 'Parent', dob: '2017-01-01', sex: 'Female', isCare: true, stats: const [ ProfileStat('📷', '16 studies'), ProfileStat('🧪', '0 labs'), ], onTap: () {}, ), ), SizedBox( width: cardWidth, height: 180, child: InouAddCard( label: 'Add dossier', onTap: () {}, ), ), ], ); }, ), ), ); } Widget _buildDataCardsSection() { return Column( children: [ // Imaging InouCard( title: 'Imaging', subtitle: '16 studies · 4113 slices', indicatorColor: InouTheme.indicatorImaging, trailing: InouButton( text: 'Open viewer', variant: ButtonVariant.secondary, size: ButtonSize.small, onPressed: () {}, ), child: Column( children: [ InouDataRow( label: 'MRI BRAIN W/WO CONTRAST', meta: '13 series', date: '5/5/2022', isExpandable: true, children: [ InouChildRow(label: 'AX T1', meta: '24 slices'), InouChildRow(label: 'AX T2 FLAIR', meta: '24 slices'), InouChildRow(label: 'SAG T1', meta: '20 slices'), ], ), const InouDataRow( label: 'XR CHEST AP ONLY', date: '5/6/2022', ), ], ), ), // Labs InouCard( title: 'Labs', subtitle: '4 panels · 23 results', indicatorColor: InouTheme.indicatorLabs, child: Column( children: [ InouDataRow( label: 'Complete Blood Count (CBC)', meta: '8 tests', date: '12/15/2024', isExpandable: true, initiallyExpanded: true, children: const [ InouChildRow( label: 'Hemoglobin', value: '14.2 g/dL', meta: '12.0–16.0', ), InouChildRow( label: 'White Blood Cells', value: '7.8 K/µL', meta: '4.5–11.0', ), InouChildRow( label: 'Platelets', value: '142 K/µL', meta: '150–400', valueColor: InouTheme.danger, ), ], ), ], ), ), // Vitals InouCard( title: 'Vitals', subtitle: 'Self-reported measurements', indicatorColor: InouTheme.indicatorVitals, trailing: InouButton( text: '+ Add', variant: ButtonVariant.secondary, size: ButtonSize.small, onPressed: () {}, ), child: Column( children: [ InouDataRow( label: 'Temperature', value: '37.2 °C', meta: 'today', leading: const InouNoteIcon( emoji: '🌡', color: InouTheme.danger, ), isExpandable: true, ), InouDataRow( label: 'Weight', value: '72.4 kg', meta: 'today', leading: InouNoteIcon( emoji: '⚖', color: Colors.blue.shade600, ), isExpandable: true, ), InouDataRow( label: 'Blood Pressure', value: '118/76', meta: 'yesterday', leading: InouNoteIcon( emoji: '❤', color: Colors.pink.shade600, ), isExpandable: true, ), ], ), ), ], ); } Widget _buildUploadSection() { return InouCard( title: 'Upload Area', indicatorColor: InouTheme.indicatorUploads, child: Padding( padding: const EdgeInsets.all(24), child: Container( padding: const EdgeInsets.all(40), decoration: BoxDecoration( border: Border.all( color: InouTheme.border, width: 2, ), borderRadius: InouTheme.borderRadiusLg, ), child: Column( children: [ Icon( Icons.cloud_upload_outlined, size: 32, color: InouTheme.accent, ), const SizedBox(height: 12), Text( 'Click or drag files here', style: InouText.label, ), const SizedBox(height: 4), Text( 'DICOM, PDF, CSV, VCF, and more', style: InouText.bodySmall.copyWith(color: InouTheme.textMuted), ), ], ), ), ), ); } } // Helper widgets class _TypographyRow extends StatelessWidget { final String text; final TextStyle style; final String spec; const _TypographyRow(this.text, this.style, this.spec); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Expanded(child: Text(text, style: style)), Text( spec, style: InouText.mono.copyWith( fontSize: 12, color: InouTheme.textMuted, ), ), ], ), ); } } class _ColorRow extends StatelessWidget { final String name; final Color color; final String hex; final bool hasBorder; const _ColorRow(this.name, this.color, this.hex, {this.hasBorder = false}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( children: [ Container( width: 32, height: 32, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(6), border: hasBorder ? Border.all(color: InouTheme.border) : null, ), ), const SizedBox(width: 16), Expanded( child: Text(name, style: InouText.label), ), Text( hex, style: InouText.mono.copyWith( fontSize: 12, color: InouTheme.textMuted, ), ), ], ), ); } } class _LLMOption extends StatelessWidget { final String icon; final String name; final bool selected; final VoidCallback onTap; const _LLMOption({ required this.icon, required this.name, required this.selected, required this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: selected ? InouTheme.accentLight : InouTheme.bgCard, border: Border.all(color: selected ? InouTheme.accent : InouTheme.border), borderRadius: BorderRadius.circular(6), ), child: Row( children: [ Container( width: 24, height: 24, decoration: BoxDecoration( color: InouTheme.bg, borderRadius: BorderRadius.circular(4), ), alignment: Alignment.center, child: Text(icon, style: const TextStyle(fontSize: 12)), ), const SizedBox(width: 8), Text( name, style: InouText.body.copyWith(color: selected ? InouTheme.accent : InouTheme.text), ), ], ), ), ); } } class _PhotoPlaceholder extends StatelessWidget { final String label; const _PhotoPlaceholder({required this.label}); @override Widget build(BuildContext context) { return Column( children: [ Container( width: 64, height: 64, decoration: BoxDecoration( color: InouTheme.border, borderRadius: BorderRadius.circular(8), ), alignment: Alignment.center, child: const Text('🦵', style: TextStyle(fontSize: 24)), ), const SizedBox(height: 4), Text(label, style: InouText.bodySmall.copyWith(fontSize: 11)), ], ); } } class _AddPhotoPlaceholder extends StatelessWidget { @override Widget build(BuildContext context) { return Column( children: [ Container( width: 64, height: 64, decoration: BoxDecoration( color: InouTheme.bgCard, borderRadius: BorderRadius.circular(8), border: Border.all(color: InouTheme.border), ), alignment: Alignment.center, child: Text('+', style: TextStyle(fontSize: 24, color: InouTheme.accent)), ), const SizedBox(height: 4), Text('Add photo', style: InouText.bodySmall.copyWith(fontSize: 11, color: InouTheme.accent)), ], ); } } class _NoteTimelineEntry extends StatelessWidget { final String date; final String text; const _NoteTimelineEntry({required this.date, required this.text}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(date, style: InouText.bodySmall.copyWith(color: InouTheme.textMuted)), const SizedBox(height: 4), Text(text, style: InouText.bodySmall), ], ), ); } } class _SupplementRow extends StatelessWidget { final String name; final String dose; final String amount; final String timing; const _SupplementRow({ required this.name, required this.dose, required this.amount, required this.timing, }); @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), decoration: const BoxDecoration( border: Border(bottom: BorderSide(color: InouTheme.border)), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(name, style: InouText.label), const SizedBox(height: 2), Text('$dose · $amount', style: InouText.bodySmall.copyWith(color: InouTheme.textMuted)), ], ), ), Text(timing, style: InouText.bodySmall.copyWith(color: InouTheme.textSubtle)), ], ), ); } } class _PeptideRow extends StatelessWidget { final String name; final String dose; final String endDate; final String status; const _PeptideRow({ required this.name, required this.dose, required this.endDate, required this.status, }); @override Widget build(BuildContext context) { final isActive = status == 'active'; return Container( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), decoration: const BoxDecoration( border: Border(bottom: BorderSide(color: InouTheme.border)), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text(name, style: InouText.label), const SizedBox(width: 8), Text(dose, style: InouText.bodySmall.copyWith(color: InouTheme.textMuted)), ], ), const SizedBox(height: 2), Text(endDate, style: InouText.bodySmall.copyWith(color: InouTheme.textSubtle)), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: isActive ? InouTheme.successLight : InouTheme.bg, borderRadius: BorderRadius.circular(4), ), child: Text( status, style: InouText.bodySmall.copyWith( color: isActive ? InouTheme.success : InouTheme.textMuted, fontWeight: FontWeight.w500, ), ), ), ], ), ); } }