mervey_ui_kit 0.1.0 copy "mervey_ui_kit: ^0.1.0" to clipboard
mervey_ui_kit: ^0.1.0 copied to clipboard

Adaptive Material/Cupertino design system: theming tokens, semantic color palette and reusable widgets that pick the right backend per platform.

example/lib/main.dart

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

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

/// Top-level app that exposes a light/dark switch and renders the
/// component showcase.
class ExampleApp extends StatefulWidget {
  /// Creates the example app.
  const ExampleApp({super.key});

  @override
  State<ExampleApp> createState() => _ExampleAppState();
}

class _ExampleAppState extends State<ExampleApp> {
  ThemeMode _mode = ThemeMode.light;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'mervey_ui_kit example',
      debugShowCheckedModeBanner: false,
      theme: AppTheme.light(),
      darkTheme: AppTheme.dark(),
      themeMode: _mode,
      builder: AppTheme.wrapWithCupertino,
      home: _Showcase(
        mode: _mode,
        onModeChanged: (m) => setState(() => _mode = m),
      ),
    );
  }
}

class _Showcase extends StatefulWidget {
  const _Showcase({required this.mode, required this.onModeChanged});

  final ThemeMode mode;
  final ValueChanged<ThemeMode> onModeChanged;

  @override
  State<_Showcase> createState() => _ShowcaseState();
}

class _ShowcaseState extends State<_Showcase> {
  final _textController = TextEditingController();
  final _searchController = TextEditingController();
  int _tabIndex = 0;
  int _navIndex = 0;
  bool _switchValue = false;

  @override
  void dispose() {
    _textController.dispose();
    _searchController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final colors = context.colors;
    final tokens = context.typography;
    final isDark = widget.mode == ThemeMode.dark;

    return AppScaffold(
      title: 'mervey_ui_kit',
      actions: [
        IconButton(
          tooltip: isDark ? 'Switch to light' : 'Switch to dark',
          icon: Icon(isDark ? Icons.light_mode : Icons.dark_mode),
          onPressed: () =>
              widget.onModeChanged(isDark ? ThemeMode.light : ThemeMode.dark),
        ),
      ],
      bottomNavigationBar: AppNavbar(
        currentIndex: _navIndex,
        onTap: (i) => setState(() => _navIndex = i),
        items: const [
          AppNavBarItem(icon: Icon(Icons.home), label: 'Home'),
          AppNavBarItem(icon: Icon(Icons.search), label: 'Browse'),
          AppNavBarItem(icon: Icon(Icons.settings), label: 'Settings'),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(AppSpacing.md),
        children: [
          _Section(
            title: 'Typography',
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text('Headline', style: AppTextStyles.headline(tokens)),
                const SizedBox(height: AppSpacing.xs),
                Text('Title', style: AppTextStyles.title(tokens)),
                const SizedBox(height: AppSpacing.xs),
                Text('Body', style: AppTextStyles.body(tokens)),
                const SizedBox(height: AppSpacing.xs),
                Text('Caption', style: AppTextStyles.caption(tokens)),
                const SizedBox(height: AppSpacing.xs),
                Text('Label', style: AppTextStyles.label(tokens)),
              ],
            ),
          ),
          _Section(
            title: 'Pills',
            child: AppPill(label: 'Active', color: colors.success),
          ),
          _Section(
            title: 'Buttons',
            child: Wrap(
              spacing: AppSpacing.sm,
              runSpacing: AppSpacing.sm,
              children: [
                AppButton(label: 'Primary', onPressed: () {}),
                AppButton(
                  label: 'Secondary',
                  variant: AppButtonVariant.secondary,
                  onPressed: () {},
                ),
                const AppButton(label: 'Disabled'),
                AppButton(label: 'Loading', isLoading: true, onPressed: () {}),
                AppGlassButton(onTap: () {}, child: const Icon(Icons.star)),
              ],
            ),
          ),
          _Section(
            title: 'Inputs',
            child: Column(
              children: [
                AppTextField(
                  label: 'Username',
                  controller: _textController,
                  helperText: 'Lowercase, no spaces',
                ),
                const SizedBox(height: AppSpacing.sm),
                AppSearchField(
                  controller: _searchController,
                  hintText: 'Search items',
                ),
              ],
            ),
          ),
          _Section(
            title: 'Cards',
            child: Column(
              children: [
                const AppCard(child: Text('Plain AppCard content')),
                const SizedBox(height: AppSpacing.sm),
                AppTappableCard(
                  padding: const EdgeInsets.all(AppSpacing.md),
                  onTap: () {},
                  child: const Text('Tappable card'),
                ),
              ],
            ),
          ),
          _Section(
            title: 'Pill tabs',
            child: AppPillTabs(
              tabs: const ['All', 'Tokens', 'Components', 'States'],
              selectedIndex: _tabIndex,
              onTabSelected: (i) => setState(() => _tabIndex = i),
            ),
          ),
          _Section(
            title: 'Avatar & badged icon',
            child: Row(
              children: [
                const AvatarInitials(name: 'Mervey UI Kit'),
                const SizedBox(width: AppSpacing.md),
                BadgedIcon(
                  icon: Icon(Icons.notifications, color: colors.textPrimary),
                  count: 7,
                ),
              ],
            ),
          ),
          _Section(
            title: 'Switch',
            child: Row(
              children: [
                AppSwitch(
                  value: _switchValue,
                  onChanged: (v) => setState(() => _switchValue = v),
                ),
                const SizedBox(width: AppSpacing.sm),
                const Text('Toggle me'),
              ],
            ),
          ),
          _Section(
            title: 'Overlays',
            child: Wrap(
              spacing: AppSpacing.sm,
              runSpacing: AppSpacing.sm,
              children: [
                AppButton(
                  label: 'Show dialog',
                  variant: AppButtonVariant.secondary,
                  onPressed: () => showAppDialog<void>(
                    context: context,
                    title: 'Hello',
                    content: const Text('A platform-native dialog.'),
                    actions: const [
                      AppDialogAction(label: 'Cancel'),
                      AppDialogAction(label: 'OK', isDefault: true),
                    ],
                  ),
                ),
                AppButton(
                  label: 'Show sheet',
                  variant: AppButtonVariant.secondary,
                  onPressed: () => showAppBottomSheet<void>(
                    context,
                    builder: (_) => const AppBottomSheet(
                      header: AppBottomSheetHeader(title: 'Sheet'),
                      child: Padding(
                        padding: EdgeInsets.symmetric(vertical: AppSpacing.md),
                        child: Text('Bottom sheet content'),
                      ),
                    ),
                  ),
                ),
                AppButton(
                  label: 'Show snack',
                  variant: AppButtonVariant.secondary,
                  onPressed: () => context.showSnack(
                    'Saved',
                    variant: AppSnackVariant.success,
                  ),
                ),
              ],
            ),
          ),
          _Section(
            title: 'States',
            child: Column(
              children: [
                const SizedBox(
                  height: 80,
                  child: LoadingState(label: 'Loading'),
                ),
                SizedBox(
                  height: 80,
                  child: ErrorState(
                    label: 'Something went wrong',
                    onRetry: () {},
                  ),
                ),
                const SizedBox(
                  height: 60,
                  child: EmptyState(label: 'Nothing here'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _Section extends StatelessWidget {
  const _Section({required this.title, required this.child});

  final String title;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    final tokens = context.typography;
    return Padding(
      padding: const EdgeInsets.only(bottom: AppSpacing.lg),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
            style: AppTextStyles.title(
              tokens,
            ).copyWith(color: context.colors.textSecondary),
          ),
          const SizedBox(height: AppSpacing.sm),
          child,
        ],
      ),
    );
  }
}
0
likes
150
points
124
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Adaptive Material/Cupertino design system: theming tokens, semantic color palette and reusable widgets that pick the right backend per platform.

Topics

#design-system #theming #material #cupertino #widget

License

MIT (license)

Dependencies

flutter

More

Packages that depend on mervey_ui_kit