/// inou Text Styles & Typography Widgets /// /// RULES: /// - Pages MUST use InouText.* styles or widgets /// - NO raw TextStyle() in page code /// - NO fontSize: or fontWeight: in page code /// /// Usage: /// Text('Hello', style: InouText.pageTitle) /// InouText.pageTitle('Hello') /// InouText.body('Paragraph', color: InouTheme.textMuted) import 'package:flutter/material.dart'; import 'inou_theme.dart'; /// Typography system for inou /// /// Base: 16px (1rem), Sora font, line-height 1.5 class InouText { InouText._(); // =========================================== // FONT FAMILY // =========================================== static const String fontFamily = 'Sora'; // =========================================== // TEXT STYLES // =========================================== /// Page title: 2.5rem (40px), weight 800 (ExtraBold) /// Use for: Main page headings like "Style Guide", "Privacy Policy" static const TextStyle pageTitle = TextStyle( fontFamily: fontFamily, fontSize: 40.0, // 2.5 * 16 fontWeight: FontWeight.w800, letterSpacing: -0.5, height: 1.2, color: InouTheme.text, ); /// Hero title: 2.25rem (36px), weight 300 (Light) /// Use for: Large hero text like "Your data. Your rules." static const TextStyle heroTitle = TextStyle( fontFamily: fontFamily, fontSize: 36.0, // 2.25 * 16 fontWeight: FontWeight.w300, height: 1.2, letterSpacing: -1.08, // -0.03em color: InouTheme.text, ); /// Section title: 1.4rem (22.4px), weight 600 (SemiBold) /// Use for: Section headings like "What we collect" static const TextStyle sectionTitle = TextStyle( fontFamily: fontFamily, fontSize: 22.4, // 1.4 * 16 fontWeight: FontWeight.w600, color: InouTheme.text, ); /// Subsection title: 1.1rem (17.6px), weight 600 (SemiBold) /// Use for: Subsection headings like "Account information" static const TextStyle subsectionTitle = TextStyle( fontFamily: fontFamily, fontSize: 17.6, // 1.1 * 16 fontWeight: FontWeight.w600, color: InouTheme.text, ); /// H3: 1.125rem (18px), weight 500 (Medium) /// Use for: Tertiary headings static const TextStyle h3 = TextStyle( fontFamily: fontFamily, fontSize: 18.0, // 1.125 * 16 fontWeight: FontWeight.w500, color: InouTheme.text, ); /// Intro text: 1.15rem (18.4px), weight 300 (Light) /// Use for: Introduction paragraphs, larger body text static const TextStyle intro = TextStyle( fontFamily: fontFamily, fontSize: 18.4, fontWeight: FontWeight.w300, height: 1.8, color: InouTheme.textMuted, ); /// Body light: 1rem (16px), weight 300 (Light) /// Use for: Long-form content, articles, descriptions static const TextStyle bodyLight = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w300, height: 1.5, color: InouTheme.text, ); /// Body regular: 1rem (16px), weight 400 (Regular) /// Use for: UI labels, default text, buttons static const TextStyle body = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w400, height: 1.5, color: InouTheme.text, ); /// Body small: 0.85rem (13.6px), weight 400 (Regular) /// Use for: Secondary text, captions, helper text static const TextStyle bodySmall = TextStyle( fontFamily: fontFamily, fontSize: 13.6, // 0.85 * 16 fontWeight: FontWeight.w400, color: InouTheme.text, ); /// Label: 1rem (16px), weight 500 (Medium) /// Use for: Form labels, button text static const TextStyle label = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w500, color: InouTheme.text, ); /// Label caps: 0.75rem (12px), weight 600, uppercase /// Use for: Category labels like "TEXT BLOCKS", "TYPOGRAPHY SCALE" static const TextStyle labelCaps = TextStyle( fontFamily: fontFamily, fontSize: 12.0, // 0.75 * 16 fontWeight: FontWeight.w600, letterSpacing: 1.2, // 0.1em color: InouTheme.textSubtle, ); /// Logo: 1.75rem (28px), weight 700 (Bold) /// Use for: "inou" in header static const TextStyle logo = TextStyle( fontFamily: fontFamily, fontSize: 28.0, // 1.75 * 16 fontWeight: FontWeight.w700, letterSpacing: -0.56, // -0.02em ); /// Logo light: 1.75rem (28px), weight 300 (Light) /// Use for: "health" in header static const TextStyle logoLight = TextStyle( fontFamily: fontFamily, fontSize: 28.0, // 1.75 * 16 fontWeight: FontWeight.w300, letterSpacing: -0.56, // -0.02em ); /// Logo tagline: 0.95rem (15.2px), weight 300 (Light) /// Use for: "ai answers for you" tagline static const TextStyle logoTagline = TextStyle( fontFamily: fontFamily, fontSize: 15.2, // 0.95 * 16 fontWeight: FontWeight.w300, letterSpacing: 0.608, // 0.04em color: InouTheme.textMuted, ); /// Nav item: 1rem (16px), weight 400 (Regular) /// Use for: Navigation menu items static const TextStyle nav = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w400, color: InouTheme.text, ); /// Nav item active: 1rem (16px), weight 600 (SemiBold) /// Use for: Active navigation menu items static const TextStyle navActive = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w600, color: InouTheme.accent, ); /// Mono: SF Mono, 0.85rem (13.6px) /// Use for: Code, technical data, IDs static const TextStyle mono = TextStyle( fontFamily: 'SF Mono', fontFamilyFallback: ['Monaco', 'Consolas', 'monospace'], fontSize: 13.6, // 0.85 * 16 fontWeight: FontWeight.w400, color: InouTheme.text, ); /// Profile name: 1.25rem (20px), weight 600 (SemiBold) /// Use for: User names in profile cards static const TextStyle profileName = TextStyle( fontFamily: fontFamily, fontSize: 20.0, // 1.25 * 16 fontWeight: FontWeight.w600, color: InouTheme.text, ); /// Badge: 1rem (16px), weight 500 (Medium) /// Use for: Badge/pill text static const TextStyle badge = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w500, ); /// Button: 1rem (16px), weight 500 (Medium) /// Use for: Button text static const TextStyle button = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w500, ); /// Input: 1rem (16px), weight 400 (Regular) /// Use for: Text input fields static const TextStyle input = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w400, color: InouTheme.text, ); /// Input placeholder: 1rem (16px), weight 400 (Regular) /// Use for: Placeholder text in inputs static const TextStyle inputPlaceholder = TextStyle( fontFamily: fontFamily, fontSize: 16.0, fontWeight: FontWeight.w400, color: InouTheme.textSubtle, ); /// Error text: 0.85rem (13.6px), weight 400 (Regular) /// Use for: Form validation errors static const TextStyle error = TextStyle( fontFamily: fontFamily, fontSize: 13.6, fontWeight: FontWeight.w400, color: InouTheme.danger, ); /// Link: inherits size, weight 400, accent color /// Use for: Inline links static TextStyle link({double? fontSize}) => TextStyle( fontFamily: fontFamily, fontSize: fontSize ?? 16.0, fontWeight: FontWeight.w400, color: InouTheme.accent, decoration: TextDecoration.underline, decorationColor: InouTheme.accent, ); // =========================================== // CONVENIENCE WIDGETS // =========================================== /// Page title widget static Widget pageTitleText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: pageTitle.copyWith(color: color), textAlign: textAlign, ); } /// Hero title widget static Widget heroTitleText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: heroTitle.copyWith(color: color), textAlign: textAlign, ); } /// Section title widget static Widget sectionTitleText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: sectionTitle.copyWith(color: color), textAlign: textAlign, ); } /// Subsection title widget static Widget subsectionTitleText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: subsectionTitle.copyWith(color: color), textAlign: textAlign, ); } /// Body text widget static Widget bodyText( String text, { Color? color, TextAlign? textAlign, int? maxLines, TextOverflow? overflow, }) { return Text( text, style: body.copyWith(color: color), textAlign: textAlign, maxLines: maxLines, overflow: overflow, ); } /// Body light text widget (for long-form) static Widget bodyLightText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: bodyLight.copyWith(color: color), textAlign: textAlign, ); } /// Intro text widget static Widget introText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: intro.copyWith(color: color), textAlign: textAlign, ); } /// Label caps widget (auto-uppercases) static Widget labelCapsText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text.toUpperCase(), style: labelCaps.copyWith(color: color), textAlign: textAlign, ); } /// Mono text widget static Widget monoText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: mono.copyWith(color: color), textAlign: textAlign, ); } /// Small text widget static Widget smallText( String text, { Color? color, TextAlign? textAlign, }) { return Text( text, style: bodySmall.copyWith(color: color), textAlign: textAlign, ); } /// Error text widget static Widget errorText( String text, { TextAlign? textAlign, }) { return Text( text, style: error, textAlign: textAlign, ); } // =========================================== // RICH TEXT HELPERS // =========================================== /// Build rich text with multiple styled spans static Widget rich( List children, { TextAlign? textAlign, }) { return Text.rich( TextSpan(children: children), textAlign: textAlign, ); } } /// Styled text spans for use with InouText.rich() class InouSpan { InouSpan._(); /// Accent colored text static TextSpan accent(String text, {TextStyle? baseStyle}) { return TextSpan( text: text, style: (baseStyle ?? InouText.body).copyWith(color: InouTheme.accent), ); } /// Muted colored text static TextSpan muted(String text, {TextStyle? baseStyle}) { return TextSpan( text: text, style: (baseStyle ?? InouText.body).copyWith(color: InouTheme.textMuted), ); } /// Subtle colored text static TextSpan subtle(String text, {TextStyle? baseStyle}) { return TextSpan( text: text, style: (baseStyle ?? InouText.body).copyWith(color: InouTheme.textSubtle), ); } /// Bold text static TextSpan bold(String text, {TextStyle? baseStyle}) { return TextSpan( text: text, style: (baseStyle ?? InouText.body).copyWith(fontWeight: FontWeight.w700), ); } /// SemiBold text static TextSpan semiBold(String text, {TextStyle? baseStyle}) { return TextSpan( text: text, style: (baseStyle ?? InouText.body).copyWith(fontWeight: FontWeight.w600), ); } /// Light text static TextSpan light(String text, {TextStyle? baseStyle}) { return TextSpan( text: text, style: (baseStyle ?? InouText.body).copyWith(fontWeight: FontWeight.w300), ); } /// Plain text (default style) static TextSpan plain(String text, {TextStyle? style}) { return TextSpan(text: text, style: style); } /// Link text static TextSpan link( String text, { VoidCallback? onTap, TextStyle? baseStyle, }) { return TextSpan( text: text, style: (baseStyle ?? InouText.body).copyWith( color: InouTheme.accent, decoration: TextDecoration.underline, decorationColor: InouTheme.accent, ), // Note: For tap handling, wrap in GestureDetector or use url_launcher ); } }