nash_ui 1.0.0
nash_ui: ^1.0.0 copied to clipboard
A modern, scalable Flutter Design System built with Material 3, providing design tokens, themes, responsive framework, animations, widgets, and templates.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:nash_ui/nash_ui.dart';
import 'pages/animations_page.dart';
import 'pages/charts_page.dart';
import 'pages/colors_page.dart';
import 'pages/dashboard_page.dart';
import 'pages/feedback_page.dart';
import 'pages/forms_page.dart';
import 'pages/home_page.dart';
import 'pages/loading_page.dart';
import 'pages/templates_page.dart';
void main() {
runApp(const NashExampleApp());
}
/// Root application with theme switching.
class NashExampleApp extends StatefulWidget {
const NashExampleApp({super.key});
@override
State<NashExampleApp> createState() => _NashExampleAppState();
}
class _NashExampleAppState extends State<NashExampleApp> {
ThemeMode _mode = ThemeMode.system;
void _setMode(ThemeMode mode) {
setState(() => _mode = mode);
}
@override
Widget build(BuildContext context) => MaterialApp(
title: 'Nash UI',
debugShowCheckedModeBanner: false,
theme: NashTheme.light(),
darkTheme: NashTheme.dark(),
themeMode: _mode,
home: HomeShell(
mode: _mode,
onModeChanged: _setMode,
),
);
}
/// Navigation shell for the demo.
class HomeShell extends StatelessWidget {
const HomeShell({
super.key,
required this.mode,
required this.onModeChanged,
});
final ThemeMode mode;
final ValueChanged<ThemeMode> onModeChanged;
@override
Widget build(BuildContext context) => AppResponsive(
child: Builder(
builder: (BuildContext context) {
final AppScreenType screen = context.screenType;
if (screen.isDesktop) {
return _DesktopShell(mode: mode, onModeChanged: onModeChanged);
}
return _MobileShell(mode: mode, onModeChanged: onModeChanged);
},
),
);
}
class _Destinations {
static const List<Destination> items = <Destination>[
Destination('Home', Icons.home_outlined, Icons.home_rounded),
Destination('Dashboard', Icons.dashboard_outlined, Icons.dashboard_rounded),
Destination('Colors', Icons.palette_outlined, Icons.palette_rounded),
Destination('Forms', Icons.edit_outlined, Icons.edit_rounded),
Destination(
'Feedback', Icons.notifications_outlined, Icons.notifications_rounded),
Destination(
'Loading', Icons.hourglass_top_rounded, Icons.hourglass_bottom_rounded),
Destination('Charts', Icons.bar_chart_rounded, Icons.bar_chart_rounded),
Destination(
'Animations', Icons.animation_outlined, Icons.animation_rounded),
Destination('Templates', Icons.apps_rounded, Icons.apps_rounded),
];
}
class Destination {
const Destination(this.label, this.icon, this.activeIcon);
final String label;
final IconData icon;
final IconData activeIcon;
}
class _MobileShell extends StatefulWidget {
const _MobileShell({required this.mode, required this.onModeChanged});
final ThemeMode mode;
final ValueChanged<ThemeMode> onModeChanged;
@override
State<_MobileShell> createState() => _MobileShellState();
}
class _MobileShellState extends State<_MobileShell> {
int _index = 0;
@override
Widget build(BuildContext context) => Scaffold(
appBar: NashAppBar(
title: _Destinations.items[_index].label,
actions: <Widget>[
_ThemeModeMenu(
mode: widget.mode, onModeChanged: widget.onModeChanged),
],
),
body: _buildPage(_index, widget.mode, widget.onModeChanged),
bottomNavigationBar: BottomNavBar(
currentIndex: _index,
onTap: (int i) => setState(() => _index = i),
items: <BottomNavItem>[
for (final Destination d in _Destinations.items.take(4))
BottomNavItem(
icon: d.icon,
selectedIcon: d.activeIcon,
label: d.label,
),
],
),
);
}
class _DesktopShell extends StatefulWidget {
const _DesktopShell({required this.mode, required this.onModeChanged});
final ThemeMode mode;
final ValueChanged<ThemeMode> onModeChanged;
@override
State<_DesktopShell> createState() => _DesktopShellState();
}
class _DesktopShellState extends State<_DesktopShell> {
int _index = 0;
@override
Widget build(BuildContext context) => Scaffold(
body: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
NavigationRail(
selectedIndex: _index,
onDestinationSelected: (int i) => setState(() => _index = i),
extended: MediaQuery.sizeOf(context).width > 1100,
leading: const Padding(
padding: EdgeInsets.only(bottom: 16),
child: CircleAvatar(
backgroundColor: Colors.transparent,
child: Text('N', style: TextStyle(fontSize: 24)),
),
),
trailing: _ThemeModeMenu(
mode: widget.mode,
onModeChanged: widget.onModeChanged,
),
destinations: <NavigationRailDestination>[
for (final Destination d in _Destinations.items)
NavigationRailDestination(
icon: Icon(d.icon),
selectedIcon: Icon(d.activeIcon),
label: Text(d.label),
),
],
),
const VerticalDivider(width: 1),
Expanded(
child: Scaffold(
appBar: NashAppBar(title: _Destinations.items[_index].label),
body: _buildPage(_index, widget.mode, widget.onModeChanged),
),
),
],
),
);
}
Widget _buildPage(
int index,
ThemeMode mode,
ValueChanged<ThemeMode> onModeChanged,
) {
switch (index) {
case 0:
return const HomePage();
case 1:
return const DashboardPage();
case 2:
return const ColorsPage();
case 3:
return const FormsPage();
case 4:
return const FeedbackPage();
case 5:
return const LoadingPage();
case 6:
return const ChartsPage();
case 7:
return const AnimationsPage();
case 8:
return const TemplatesPage();
default:
return const HomePage();
}
}
/// Theme mode switch menu.
class _ThemeModeMenu extends StatelessWidget {
const _ThemeModeMenu({required this.mode, required this.onModeChanged});
final ThemeMode mode;
final ValueChanged<ThemeMode> onModeChanged;
@override
Widget build(BuildContext context) => IconButton(
icon: const Icon(Icons.brightness_6_rounded),
tooltip: 'Switch theme',
onPressed: () {
final ThemeMode next = switch (mode) {
ThemeMode.light => ThemeMode.dark,
ThemeMode.dark => ThemeMode.system,
ThemeMode.system => ThemeMode.light,
};
onModeChanged(next);
},
);
}