adaptive_kit 1.0.1 copy "adaptive_kit: ^1.0.1" to clipboard
adaptive_kit: ^1.0.1 copied to clipboard

The Tailwind CSS of Flutter. Zero-config adaptive UI toolkit with responsive breakpoints, adaptive widgets, design tokens, and utility extensions.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:adaptive_kit/adaptive_kit.dart';

void main() {
  runApp(const SmartUiExampleApp());
}

class SmartUiExampleApp extends StatelessWidget {
  const SmartUiExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return SmartUi(
      child: MaterialApp(
        title: 'smartui Example',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
          useMaterial3: true,
        ),
        darkTheme: ThemeData(
          colorScheme: ColorScheme.fromSeed(
            seedColor: Colors.blue,
            brightness: Brightness.dark,
          ),
          useMaterial3: true,
        ),
        home: const HomePage(),
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedIndex = 0;

  final _pages = const [
    GridDemoPage(),
    LayoutDemoPage(),
    AdaptiveDemoPage(),
    TokensDemoPage(),
  ];

  @override
  Widget build(BuildContext context) {
    return SmartScaffold(
      selectedIndex: _selectedIndex,
      onDestinationSelected: (index) {
        setState(() => _selectedIndex = index);
      },
      destinations: const [
        SmartDestination(
          icon: Icon(Icons.grid_view_outlined),
          selectedIcon: Icon(Icons.grid_view),
          label: 'Grid',
        ),
        SmartDestination(
          icon: Icon(Icons.view_quilt_outlined),
          selectedIcon: Icon(Icons.view_quilt),
          label: 'Layout',
        ),
        SmartDestination(
          icon: Icon(Icons.widgets_outlined),
          selectedIcon: Icon(Icons.widgets),
          label: 'Adaptive',
        ),
        SmartDestination(
          icon: Icon(Icons.palette_outlined),
          selectedIcon: Icon(Icons.palette),
          label: 'Tokens',
        ),
      ],
      appBar: AppBar(
        title: const Text('smartui Demo'),
        actions: [
          IconButton(
            icon: const Icon(Icons.info_outline),
            onPressed: () => _showInfoDialog(context),
          ),
        ],
      ),
      body: _pages[_selectedIndex],
    );
  }

  void _showInfoDialog(BuildContext context) {
    showSmartDialog<void>(
      context: context,
      title: 'smartui',
      content: 'The Tailwind CSS of Flutter. A zero-config, declarative '
          'adaptive UI toolkit for responsive, platform-aware Flutter apps.',
      actions: [
        SmartDialogAction(
          label: 'OK',
          isDefault: true,
          onPressed: () => Navigator.of(context).pop(),
        ),
      ],
    );
  }
}

// Grid Demo Page
class GridDemoPage extends StatelessWidget {
  const GridDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(SmartSpacing.md),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const SmartText(
            'Responsive Grid',
            style: TypographyStyle.headlineMedium,
          ),
          const VGap.md(),
          ResponsiveBuilder(
            builder: (context, info) {
              return SmartText(
                'Current breakpoint: ${info.breakpoint.name} '
                '(${info.screenWidth.toInt()}px)',
                style: TypographyStyle.bodyMedium,
              );
            },
          ),
          const VGap.lg(),
          SmartGrid(
            columns: 12,
            spacing: SmartSpacing.md,
            runSpacing: SmartSpacing.md,
            children: List.generate(6, (index) {
              return SmartCol(
                mobile: 12,
                tablet: 6,
                desktop: 4,
                child: _ProductCard(index: index),
              );
            }),
          ),
        ],
      ),
    );
  }
}

class _ProductCard extends StatelessWidget {
  const _ProductCard({required this.index});

  final int index;

  @override
  Widget build(BuildContext context) {
    final colors = [
      Colors.blue,
      Colors.green,
      Colors.orange,
      Colors.purple,
      Colors.red,
      Colors.teal,
    ];

    return Card(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            height: 120,
            decoration: BoxDecoration(
              color: colors[index % colors.length].withOpacity(0.2),
              borderRadius: SmartRadius.top(12),
            ),
            child: Center(
              child: Icon(
                Icons.image,
                size: 48,
                color: colors[index % colors.length],
              ),
            ),
          ),
          SmartPadding.all(
            SpacingSize.md,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                SmartText(
                  'Product ${index + 1}',
                  style: TypographyStyle.titleMedium,
                ),
                const VGap.xs(),
                SmartText(
                  'This is a description of the product.',
                  style: TypographyStyle.bodySmall,
                  textColor: Theme.of(context).colorScheme.onSurfaceVariant,
                ),
                const VGap.sm(),
                SmartText(
                  '\$${(index + 1) * 19.99}',
                  style: TypographyStyle.titleLarge,
                  textColor: Theme.of(context).colorScheme.primary,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// Layout Demo Page
class LayoutDemoPage extends StatelessWidget {
  const LayoutDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return SmartLayout(
      mobile: _MobileLayout(),
      tablet: _TabletLayout(),
      desktop: _DesktopLayout(),
    );
  }
}

class _MobileLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(SmartSpacing.md),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const SmartText(
            'Mobile Layout',
            style: TypographyStyle.headlineMedium,
          ),
          const VGap.md(),
          const SmartText(
            'This layout is optimized for mobile devices. '
            'Content is displayed in a single column.',
            style: TypographyStyle.bodyMedium,
          ),
          const VGap.lg(),
          ...List.generate(3, (index) {
            return Padding(
              padding: const EdgeInsets.only(bottom: SmartSpacing.md),
              child: _ContentCard(
                title: 'Item ${index + 1}',
                color: Colors.primaries[index % Colors.primaries.length],
              ),
            );
          }),
        ],
      ),
    );
  }
}

class _TabletLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(SmartSpacing.lg),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const SmartText(
            'Tablet Layout',
            style: TypographyStyle.headlineMedium,
          ),
          const VGap.md(),
          const SmartText(
            'This layout is optimized for tablets. '
            'Content is displayed in two columns.',
            style: TypographyStyle.bodyMedium,
          ),
          const VGap.lg(),
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                child: Column(
                  children: List.generate(2, (index) {
                    return Padding(
                      padding: const EdgeInsets.only(bottom: SmartSpacing.md),
                      child: _ContentCard(
                        title: 'Left ${index + 1}',
                        color: Colors
                            .primaries[(index * 2) % Colors.primaries.length],
                      ),
                    );
                  }),
                ),
              ),
              const HGap.md(),
              Expanded(
                child: Column(
                  children: List.generate(2, (index) {
                    return Padding(
                      padding: const EdgeInsets.only(bottom: SmartSpacing.md),
                      child: _ContentCard(
                        title: 'Right ${index + 1}',
                        color: Colors.primaries[
                            (index * 2 + 1) % Colors.primaries.length],
                      ),
                    );
                  }),
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class _DesktopLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(SmartSpacing.xl),
      child: SmartContainer(
        maxWidth: 1200,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const SmartText(
              'Desktop Layout',
              style: TypographyStyle.headlineMedium,
            ),
            const VGap.md(),
            const SmartText(
              'This layout is optimized for desktop. '
              'Content uses a max-width container with three columns.',
              style: TypographyStyle.bodyMedium,
            ),
            const VGap.lg(),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: List.generate(3, (colIndex) {
                return Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(
                      left: colIndex == 0 ? 0 : SmartSpacing.md / 2,
                      right: colIndex == 2 ? 0 : SmartSpacing.md / 2,
                    ),
                    child: Column(
                      children: List.generate(2, (rowIndex) {
                        return Padding(
                          padding:
                              const EdgeInsets.only(bottom: SmartSpacing.md),
                          child: _ContentCard(
                            title: 'Col ${colIndex + 1}, Row ${rowIndex + 1}',
                            color: Colors.primaries[(colIndex * 2 + rowIndex) %
                                Colors.primaries.length],
                          ),
                        );
                      }),
                    ),
                  ),
                );
              }),
            ),
          ],
        ),
      ),
    );
  }
}

class _ContentCard extends StatelessWidget {
  const _ContentCard({required this.title, required this.color});

  final String title;
  final Color color;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Container(
        padding: const EdgeInsets.all(SmartSpacing.md),
        decoration: BoxDecoration(
          border: Border(
            left: BorderSide(color: color, width: 4),
          ),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            SmartText(title, style: TypographyStyle.titleMedium),
            const VGap.sm(),
            SmartText(
              'This is sample content for the card.',
              style: TypographyStyle.bodySmall,
              textColor: Theme.of(context).colorScheme.onSurfaceVariant,
            ),
          ],
        ),
      ),
    );
  }
}

// Adaptive Demo Page
class AdaptiveDemoPage extends StatefulWidget {
  const AdaptiveDemoPage({super.key});

  @override
  State<AdaptiveDemoPage> createState() => _AdaptiveDemoPageState();
}

class _AdaptiveDemoPageState extends State<AdaptiveDemoPage> {
  bool _switchValue = false;
  bool _checkboxValue = false;
  String _radioValue = 'option1';

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(SmartSpacing.md),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const SmartText(
            'Adaptive Widgets',
            style: TypographyStyle.headlineMedium,
          ),
          const VGap.md(),
          const SmartText(
            'These widgets automatically adapt to the current platform. '
            'On iOS, they show Cupertino styling. On Android, Material.',
            style: TypographyStyle.bodyMedium,
          ),
          const VGap.lg(),

          // Buttons section
          const SmartText('Buttons', style: TypographyStyle.titleLarge),
          const VGap.md(),
          Wrap(
            spacing: SmartSpacing.md,
            runSpacing: SmartSpacing.sm,
            children: [
              SmartButton(
                onPressed: () =>
                    _showSnackBar(context, 'Default button pressed'),
                child: const Text('Default'),
              ),
              SmartButton.filled(
                onPressed: () =>
                    _showSnackBar(context, 'Filled button pressed'),
                child: const Text('Filled'),
              ),
              SmartButton.text(
                onPressed: () => _showSnackBar(context, 'Text button pressed'),
                child: const Text('Text'),
              ),
              SmartButton.outlined(
                onPressed: () =>
                    _showSnackBar(context, 'Outlined button pressed'),
                child: const Text('Outlined'),
              ),
            ],
          ),
          const VGap.xl(),

          // Switch section
          const SmartText('Switch', style: TypographyStyle.titleLarge),
          const VGap.md(),
          Row(
            children: [
              SmartSwitch(
                value: _switchValue,
                onChanged: (value) => setState(() => _switchValue = value),
              ),
              const HGap.md(),
              Text(_switchValue ? 'On' : 'Off'),
            ],
          ),
          const VGap.xl(),

          // Checkbox section
          const SmartText('Checkbox', style: TypographyStyle.titleLarge),
          const VGap.md(),
          Row(
            children: [
              SmartCheckbox(
                value: _checkboxValue,
                onChanged: (value) =>
                    setState(() => _checkboxValue = value ?? false),
              ),
              const HGap.md(),
              Text(_checkboxValue ? 'Checked' : 'Unchecked'),
            ],
          ),
          const VGap.xl(),

          // Radio section
          const SmartText('Radio', style: TypographyStyle.titleLarge),
          const VGap.md(),
          Row(
            children: [
              SmartRadio<String>(
                value: 'option1',
                groupValue: _radioValue,
                onChanged: (value) =>
                    setState(() => _radioValue = value ?? 'option1'),
              ),
              const HGap.sm(),
              const Text('Option 1'),
              const HGap.lg(),
              SmartRadio<String>(
                value: 'option2',
                groupValue: _radioValue,
                onChanged: (value) =>
                    setState(() => _radioValue = value ?? 'option1'),
              ),
              const HGap.sm(),
              const Text('Option 2'),
            ],
          ),
          const VGap.xl(),

          // Progress indicators
          const SmartText('Progress Indicators',
              style: TypographyStyle.titleLarge),
          const VGap.md(),
          const Row(
            children: [
              SmartIndicator(),
              HGap.lg(),
              SmartIndicator(value: 0.7),
            ],
          ),
          const VGap.md(),
          const SmartLinearIndicator(value: 0.5),
          const VGap.xl(),

          // Dialogs
          const SmartText('Dialogs', style: TypographyStyle.titleLarge),
          const VGap.md(),
          SmartButton(
            onPressed: () => _showAlertDialog(context),
            child: const Text('Show Alert Dialog'),
          ),
          const VGap.md(),
          SmartButton(
            onPressed: () => _showConfirmDialog(context),
            child: const Text('Show Confirm Dialog'),
          ),
        ],
      ),
    );
  }

  void _showSnackBar(BuildContext context, String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }

  void _showAlertDialog(BuildContext context) {
    showSmartDialog<void>(
      context: context,
      title: 'Alert',
      content: 'This is an adaptive alert dialog.',
      actions: [
        SmartDialogAction(
          label: 'OK',
          onPressed: () => Navigator.of(context).pop(),
        ),
      ],
    );
  }

  void _showConfirmDialog(BuildContext context) async {
    final confirmed = await showSmartConfirmDialog(
      context: context,
      title: 'Confirm Action',
      content: 'Are you sure you want to proceed?',
      confirmLabel: 'Yes',
      cancelLabel: 'No',
    );

    if (context.mounted) {
      _showSnackBar(context, confirmed ? 'Confirmed!' : 'Cancelled');
    }
  }
}

// Tokens Demo Page
class TokensDemoPage extends StatelessWidget {
  const TokensDemoPage({super.key});

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(SmartSpacing.md),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const SmartText(
            'Design Tokens',
            style: TypographyStyle.headlineMedium,
          ),
          const VGap.lg(),

          // Typography section
          const SmartText('Typography', style: TypographyStyle.titleLarge),
          const VGap.md(),
          const _TypographyShowcase(),
          const VGap.xl(),

          // Spacing section
          const SmartText('Spacing', style: TypographyStyle.titleLarge),
          const VGap.md(),
          const _SpacingShowcase(),
          const VGap.xl(),

          // Radius section
          const SmartText('Border Radius', style: TypographyStyle.titleLarge),
          const VGap.md(),
          const _RadiusShowcase(),
        ],
      ),
    );
  }
}

class _TypographyShowcase extends StatelessWidget {
  const _TypographyShowcase();

  @override
  Widget build(BuildContext context) {
    final styles = [
      ('displayLarge', TypographyStyle.displayLarge),
      ('displayMedium', TypographyStyle.displayMedium),
      ('displaySmall', TypographyStyle.displaySmall),
      ('headlineLarge', TypographyStyle.headlineLarge),
      ('headlineMedium', TypographyStyle.headlineMedium),
      ('headlineSmall', TypographyStyle.headlineSmall),
      ('titleLarge', TypographyStyle.titleLarge),
      ('titleMedium', TypographyStyle.titleMedium),
      ('titleSmall', TypographyStyle.titleSmall),
      ('bodyLarge', TypographyStyle.bodyLarge),
      ('bodyMedium', TypographyStyle.bodyMedium),
      ('bodySmall', TypographyStyle.bodySmall),
      ('labelLarge', TypographyStyle.labelLarge),
      ('labelMedium', TypographyStyle.labelMedium),
      ('labelSmall', TypographyStyle.labelSmall),
    ];

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: styles.map((item) {
        return Padding(
          padding: const EdgeInsets.only(bottom: SmartSpacing.sm),
          child: SmartText(item.$1, style: item.$2),
        );
      }).toList(),
    );
  }
}

class _SpacingShowcase extends StatelessWidget {
  const _SpacingShowcase();

  @override
  Widget build(BuildContext context) {
    final spacings = [
      ('xs (4px)', SmartSpacing.xs),
      ('sm (8px)', SmartSpacing.sm),
      ('md (16px)', SmartSpacing.md),
      ('lg (24px)', SmartSpacing.lg),
      ('xl (32px)', SmartSpacing.xl),
      ('xxl (48px)', SmartSpacing.xxl),
    ];

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: spacings.map((item) {
        return Padding(
          padding: const EdgeInsets.only(bottom: SmartSpacing.sm),
          child: Row(
            children: [
              SizedBox(
                width: 100,
                child: SmartText(item.$1, style: TypographyStyle.bodyMedium),
              ),
              Container(
                width: item.$2,
                height: 24,
                color: Theme.of(context).colorScheme.primary,
              ),
            ],
          ),
        );
      }).toList(),
    );
  }
}

class _RadiusShowcase extends StatelessWidget {
  const _RadiusShowcase();

  @override
  Widget build(BuildContext context) {
    final radii = [
      ('none', SmartRadius.none),
      ('xs (2px)', SmartRadius.xs),
      ('sm (4px)', SmartRadius.sm),
      ('md (8px)', SmartRadius.md),
      ('lg (12px)', SmartRadius.lg),
      ('xl (16px)', SmartRadius.xl),
      ('xxl (24px)', SmartRadius.xxl),
      ('full', SmartRadius.full),
    ];

    return Wrap(
      spacing: SmartSpacing.md,
      runSpacing: SmartSpacing.md,
      children: radii.map((item) {
        return Column(
          children: [
            Container(
              width: 60,
              height: 60,
              decoration: BoxDecoration(
                color: Theme.of(context).colorScheme.primaryContainer,
                borderRadius: item.$2,
              ),
            ),
            const VGap.xs(),
            SmartText(item.$1, style: TypographyStyle.labelSmall),
          ],
        );
      }).toList(),
    );
  }
}
2
likes
0
points
323
downloads

Publisher

unverified uploader

Weekly Downloads

The Tailwind CSS of Flutter. Zero-config adaptive UI toolkit with responsive breakpoints, adaptive widgets, design tokens, and utility extensions.

Repository (GitHub)
View/report issues

Topics

#responsive #adaptive #ui #layout #widget

License

unknown (license)

Dependencies

flutter

More

Packages that depend on adaptive_kit