super_navigation_sidebar 3.2.0
super_navigation_sidebar: ^3.2.0 copied to clipboard
A themeable, responsive navigation sidebar for Flutter with expanded, rail, and drawer modes, typed NavNode<T> trees, search, favorites, recents, state persistence, localization, RTL support, and a re [...]
// super_navigation_sidebar · Example app launcher
//
// A polished launcher: hero header + responsive card grid, each card carrying
// a live token-driven mini-preview of the sidebar mode it opens. Every example
// is pushed with a floating "back to demos" button.
import 'package:flutter/material.dart';
import 'package:super_core/super_core.dart';
import 'package:super_navigation_sidebar/super_navigation_sidebar.dart';
import 'example_01_responsive_shell.dart';
import 'example_02_admin_dashboard.dart';
import 'example_03_theme_rtl.dart';
import 'example_04_erp_banking.dart';
import 'example_05_navigation_search_view.dart';
import 'example_07_kitchen_sink.dart';
import 'navigation_sidebar_demo.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatefulWidget {
const ExampleApp({super.key});
@override
State<ExampleApp> createState() => _ExampleAppState();
}
class _ExampleAppState extends State<ExampleApp> {
bool _dark = true;
@override
Widget build(BuildContext context) {
final typography = SuperTextTheme();
final dark = SuperMaterialThemeData.dark(
textTheme: typography,
primaryTextTheme: typography,
);
final light = SuperMaterialThemeData.light(
textTheme: typography,
primaryTextTheme: typography,
);
return MaterialApp(
title: 'super_navigation_sidebar 3.2.0 examples',
debugShowCheckedModeBanner: false,
localizationsDelegates:
SuperNavigationLocalization.localizationsDelegates,
supportedLocales: SuperNavigationLocalization.supportedLocales,
theme: light.copyWith(
extensions: [SuperNavigationSidebarThemeData.fromMaterialTheme(light)],
),
darkTheme: dark.copyWith(
extensions: [SuperNavigationSidebarThemeData.fromMaterialTheme(dark)],
),
themeMode: _dark ? ThemeMode.dark : ThemeMode.light,
home: LauncherScreen(
dark: _dark,
onToggleTheme: (v) => setState(() => _dark = v),
),
);
}
}
// ════════════════════════════════════════════════════════════
// LAUNCHER
// ════════════════════════════════════════════════════════════
class LauncherScreen extends StatelessWidget {
final bool dark;
final ValueChanged<bool> onToggleTheme;
const LauncherScreen({
super.key,
required this.dark,
required this.onToggleTheme,
});
@override
Widget build(BuildContext context) {
final s = SuperNavigationSidebarThemeData.of(context);
final demos = <_Demo>[
_Demo(
title: 'Kitchen sink — every feature (3.2)',
subtitle:
'One workbench with the full 3.2 surface: adaptive pane layouts, '
'screen codes + keyword search, dialog/sheet SuperNavigationSearchView, '
'recent navigation, snapshot save/restore, badge roll-up, favorites, '
'locked/status nodes and RTL — all behind live toggles.',
badge: 'ALL · search view · codes · recents · snapshot',
preview: const _SidebarThumb(
mode: _Mode.expanded,
activeIndex: 2,
badges: true,
erp: true,
),
screen: const KitchenSinkExample(),
),
_Demo(
title: 'Responsive app shell',
subtitle:
'A device-width simulator (Fill · Desktop · Tablet · Mobile) drives '
'SuperNavSidebarBreakpoints — watch the same controller flip between '
'expanded, rail and drawer modes.',
badge: 'expanded · rail · drawer',
preview: const _SidebarThumb(mode: _Mode.expanded, activeIndex: 1),
screen: const ResponsiveShellExample(),
),
_Demo(
title: 'Admin dashboard',
subtitle:
'15+ nodes across 4 sections with badge tones, favorites and search. '
'Deep-link from page content via of(context), and live badge updates '
'through replaceSections.',
badge: 'badges · favorites · search · of(context)',
preview: const _SidebarThumb(
mode: _Mode.expanded,
activeIndex: 2,
badges: true,
),
screen: const AdminDashboardExample(),
),
_Demo(
title: 'Custom theme + RTL',
subtitle:
'Three themes (Dark / Light / Warm) built with copyWith, an LTR/RTL '
'toggle, plus showGuides and railFlyouts switches.',
badge: 'theming · RTL',
preview: const _SidebarThumb(
mode: _Mode.expanded,
activeIndex: 0,
warm: true,
),
screen: const ThemeRtlExample(),
),
_Demo(
title: 'Banking / accounting ERP',
subtitle:
'The ERP capability set — built-in search & filter, Quick Access '
'favorites, permission-locked screens, and fiscal-period status '
'dots on a deep banking tree.',
badge: 'search · favorites · locked · status',
preview: const _SidebarThumb(
mode: _Mode.expanded,
activeIndex: 2,
badges: true,
erp: true,
),
screen: const ErpBankingExample(),
),
_Demo(
title: 'SuperNavigationSearchView',
subtitle:
'The reusable 3.2 search experience shown inline, in a dialog, or '
'as a modal bottom sheet. It shares the same controller and typed '
'navigation tree used by SuperNavigationSidebar.',
badge: 'embedded · dialog · sheet',
preview: const _SidebarThumb(
mode: _Mode.expanded,
activeIndex: 1,
badges: true,
),
screen: const NavigationSearchViewExample(),
),
_Demo(
title: 'Full component workbench',
subtitle:
'The original showcase — device simulator, all three modes, live '
'Light/Dark, LTR/RTL, sidebar search, and workspace + user menus.',
badge: 'Original',
preview: const _SidebarThumb(mode: _Mode.rail, activeIndex: 1),
screen: const NavigationSidebarDemo(),
),
];
return Scaffold(
backgroundColor: s.bg,
body: SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 1040),
child: ListView(
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 44),
children: [
// ── hero ──────────────────────────────────────
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
_Mark(),
const SizedBox(width: 12),
Text(
'SUPER_NAVIGATION_SIDEBAR',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.monoFont,
fontSize: 12,
fontWeight: FontWeight.w700,
letterSpacing: 1.6,
color: SuperNavigationSidebarThemeData.accent,
),
),
const SizedBox(width: 10),
_VersionPill(),
],
),
const SizedBox(height: 16),
Text(
'Responsive app navigation',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.displayFont,
fontSize: 34,
fontWeight: FontWeight.w800,
letterSpacing: -0.8,
height: 1.05,
color: s.fg1,
),
),
const SizedBox(height: 12),
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 640),
child: Text(
'One typed SuperNavNode<T> tree renders as an expanded '
'tree, an icon rail with flyouts, or an off-canvas '
'drawer. Search, badges, favorites, header/footer slots and RTL '
'are included. Open any example to try it live.',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.bodyFont,
fontSize: 14.5,
height: 1.6,
color: s.fg3,
),
),
),
],
),
),
_ThemeToggle(dark: dark, onToggle: onToggleTheme),
],
),
const SizedBox(height: 36),
// ── grid ──────────────────────────────────────
LayoutBuilder(
builder: (context, c) {
final cols = c.maxWidth > 720 ? 2 : 1;
return GridView.count(
crossAxisCount: cols,
crossAxisSpacing: 18,
mainAxisSpacing: 18,
childAspectRatio: 1.42,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: [
for (var i = 0; i < demos.length; i++)
_DemoCard(
index: i + 1,
demo: demos[i],
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) =>
_BackScaffold(child: demos[i].screen),
),
),
),
],
);
},
),
const SizedBox(height: 24),
Center(
child: Text(
'MIT © GeniusLink · pure Flutter, zero dependencies',
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.monoFont,
fontSize: 11,
color: s.fg4,
),
),
),
],
),
),
),
),
);
}
}
class _Demo {
final String title, subtitle, badge;
final Widget preview;
final Widget screen;
const _Demo({
required this.title,
required this.subtitle,
required this.badge,
required this.preview,
required this.screen,
});
}
// ── Demo card ─────────────────────────────────────────────────────
class _DemoCard extends StatefulWidget {
final int index;
final _Demo demo;
final VoidCallback onTap;
const _DemoCard({
required this.index,
required this.demo,
required this.onTap,
});
@override
State<_DemoCard> createState() => _DemoCardState();
}
class _DemoCardState extends State<_DemoCard> {
bool _h = false;
@override
Widget build(BuildContext context) {
final s = SuperNavigationSidebarThemeData.of(context);
return MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (_) => setState(() => _h = true),
onExit: (_) => setState(() => _h = false),
child: GestureDetector(
onTap: widget.onTap,
child: AnimatedContainer(
duration: SuperNavigationSidebarThemeData.durFast,
curve: SuperNavigationSidebarThemeData.curveStandard,
transform: _h
? Matrix4.translationValues(0.0, -4.0, 0.0)
: Matrix4.identity(),
decoration: BoxDecoration(
color: s.surface,
border: Border.all(
color: _h
? SuperNavigationSidebarThemeData.accent
.withValues(alpha: 0.55)
: s.border,
),
borderRadius: BorderRadius.circular(s.radiusXl),
boxShadow: _h ? SuperNavigationSidebarThemeData.popShadow : null,
),
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Stack(
children: [
Positioned.fill(child: widget.demo.preview),
Positioned(
top: 10,
right: 10,
child: Container(
width: 24,
height: 24,
alignment: Alignment.center,
decoration: BoxDecoration(
color: s.bg.withValues(alpha: 0.82),
borderRadius: BorderRadius.circular(7),
border: Border.all(color: s.border),
),
child: Text(
'0${widget.index}',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.monoFont,
fontSize: 10,
fontWeight: FontWeight.w700,
color: s.fg2,
),
),
),
),
],
),
),
Container(
decoration: BoxDecoration(
color: s.surface,
border: Border(top: BorderSide(color: s.border)),
),
padding: const EdgeInsets.fromLTRB(16, 14, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
widget.demo.title,
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.displayFont,
fontSize: 16.5,
fontWeight: FontWeight.w700,
color: s.fg1,
),
),
),
Icon(
Icons.arrow_outward,
size: 16,
color: _h
? SuperNavigationSidebarThemeData.accent
: s.fg3,
),
],
),
const SizedBox(height: 6),
Text(
widget.demo.subtitle,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.bodyFont,
fontSize: 12.5,
height: 1.5,
color: s.fg3,
),
),
const SizedBox(height: 10),
_TagPill(widget.demo.badge),
],
),
),
],
),
),
),
);
}
}
// ════════════════════════════════════════════════════════════
// MINI SIDEBAR PREVIEW (token-driven; reflects dark/light)
// ════════════════════════════════════════════════════════════
enum _Mode { expanded, rail }
class _SidebarThumb extends StatelessWidget {
final _Mode mode;
final int activeIndex;
final bool badges;
final bool warm;
final bool erp;
const _SidebarThumb({
required this.mode,
required this.activeIndex,
this.badges = false,
this.warm = false,
this.erp = false,
});
@override
Widget build(BuildContext context) {
final base = SuperNavigationSidebarThemeData.of(context);
final s = warm
? base.copyWith(
bg: const Color(0xFFF3EEE7),
surface: const Color(0xFFFFFFFF),
inputBg: const Color(0xFFEAE3D9),
hover: const Color(0xFFEAE3D9),
border: const Color(0xFFDED7CB),
guide: const Color(0xFFCEC6B9),
fg1: const Color(0xFF231F1A),
fg3: const Color(0xFF8A8175),
fg4: const Color(0xFFB4A99A),
)
: base;
const accent = SuperNavigationSidebarThemeData.accent;
final rows = erp
? <(IconData, String, SuperNavBadgeTone?)>[
(Icons.fact_check_outlined, 'Approvals', SuperNavBadgeTone.danger),
(Icons.event_available_outlined, 'FY25 · Q3', null),
(Icons.edit_note_outlined, 'Journal Entry', null),
(Icons.bolt_outlined, 'Wire / SWIFT', null),
(Icons.balance, 'Trial Balance', null),
]
: <(IconData, String, SuperNavBadgeTone?)>[
(Icons.dashboard_outlined, 'Dashboard', null),
(
Icons.menu_book_outlined,
'Accounts',
badges ? SuperNavBadgeTone.success : null,
),
(
Icons.receipt_long_outlined,
'Journals',
badges ? SuperNavBadgeTone.danger : null,
),
(Icons.storefront_outlined, 'Inventory', null),
(Icons.settings_outlined, 'Settings', null),
];
Color toneColor(SuperNavBadgeTone t) {
switch (t) {
case SuperNavBadgeTone.success:
return SuperNavigationSidebarThemeData.success;
case SuperNavBadgeTone.danger:
return SuperNavigationSidebarThemeData.danger;
case SuperNavBadgeTone.warning:
return SuperNavigationSidebarThemeData.warning;
case SuperNavBadgeTone.muted:
return s.fg3;
case SuperNavBadgeTone.accent:
return accent;
}
}
final isRail = mode == _Mode.rail;
final panelW = isRail ? 52.0 : 132.0;
Widget railIcon(int i) {
final (icon, _, tone) = rows[i];
final active = i == activeIndex;
return Container(
width: 34,
height: 34,
margin: const EdgeInsets.symmetric(vertical: 3),
alignment: Alignment.center,
decoration: BoxDecoration(
color: active ? accent.withValues(alpha: 0.16) : Colors.transparent,
borderRadius: BorderRadius.circular(8),
border:
active ? Border.all(color: accent.withValues(alpha: 0.5)) : null,
),
child: Stack(
clipBehavior: Clip.none,
children: [
Icon(icon, size: 15, color: active ? accent : s.fg3),
if (tone != null)
Positioned(
right: -3,
top: -3,
child: Container(
width: 6,
height: 6,
decoration: BoxDecoration(
color: toneColor(tone),
shape: BoxShape.circle,
),
),
),
],
),
);
}
Widget expandedRow(int i) {
final (icon, label, tone) = rows[i];
final active = i == activeIndex;
final locked = erp && i == 3;
final statusOpen = erp && i == 1;
final star = erp && (i == 2 || i == 4);
return Opacity(
opacity: locked ? 0.5 : 1,
child: Container(
height: 26,
margin: const EdgeInsets.only(bottom: 4),
padding: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: active ? accent : Colors.transparent,
borderRadius: BorderRadius.circular(7),
),
child: Row(
children: [
Icon(icon, size: 12, color: active ? Colors.white : s.fg3),
const SizedBox(width: 7),
if (statusOpen) ...[
Container(
width: 6,
height: 6,
decoration: const BoxDecoration(
color: SuperNavigationSidebarThemeData.success,
shape: BoxShape.circle,
),
),
const SizedBox(width: 5),
],
Expanded(
child: Text(
label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.bodyFont,
fontSize: 10,
fontWeight: active ? FontWeight.w700 : FontWeight.w500,
color: active ? Colors.white : s.fg2,
),
),
),
if (tone != null)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 4,
vertical: 1,
),
decoration: BoxDecoration(
color: active
? Colors.white.withValues(alpha: 0.25)
: toneColor(tone).withValues(alpha: 0.18),
borderRadius: BorderRadius.circular(999),
),
child: Text(
tone == SuperNavBadgeTone.success ? 'Live' : '9+',
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.monoFont,
fontSize: 7,
fontWeight: FontWeight.w700,
color: active ? Colors.white : toneColor(tone),
),
),
),
if (star)
Icon(
Icons.star_rounded,
size: 11,
color: active
? Colors.white
: SuperNavigationSidebarThemeData.accent,
),
if (locked) Icon(Icons.lock_outline, size: 10, color: s.fg3),
],
),
),
);
}
return Container(
color: s.bg,
child: Row(
children: [
// panel
Container(
width: panelW,
decoration: BoxDecoration(
color: s.surface,
border: Border(right: BorderSide(color: s.border)),
),
padding: EdgeInsets.symmetric(
horizontal: isRail ? 9 : 10,
vertical: 10,
),
child: Column(
crossAxisAlignment:
isRail ? CrossAxisAlignment.center : CrossAxisAlignment.start,
children: [
// header
if (isRail)
Container(
width: 26,
height: 26,
alignment: Alignment.center,
decoration: BoxDecoration(
color: accent,
borderRadius: BorderRadius.circular(7),
),
child: const Text(
'GL',
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.displayFont,
fontSize: 9,
fontWeight: FontWeight.w800,
color: Colors.white,
),
),
)
else
Row(
children: [
Container(
width: 22,
height: 22,
alignment: Alignment.center,
decoration: BoxDecoration(
color: accent,
borderRadius: BorderRadius.circular(6),
),
child: const Text(
'GL',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.displayFont,
fontSize: 8,
fontWeight: FontWeight.w800,
color: Colors.white,
),
),
),
const SizedBox(width: 7),
Text(
'GeniusLink',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.displayFont,
fontSize: 11,
fontWeight: FontWeight.w800,
color: s.fg1,
),
),
],
),
const SizedBox(height: 12),
if (erp && !isRail) ...[
Container(
height: 22,
padding: const EdgeInsetsDirectional.only(start: 7, end: 4),
decoration: BoxDecoration(
color: s.inputBg,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: s.border),
),
child: Row(
children: [
Icon(Icons.search, size: 10, color: s.fg3),
const SizedBox(width: 5),
Text(
'Search…',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.bodyFont,
fontSize: 8.5,
color: s.fg4,
),
),
],
),
),
const SizedBox(height: 8),
],
if (!isRail)
Padding(
padding: const EdgeInsets.only(left: 2, bottom: 6),
child: Text(
erp ? 'GENERAL LEDGER' : 'OVERVIEW',
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.monoFont,
fontSize: 7,
letterSpacing: 1.2,
fontWeight: FontWeight.w700,
color: s.fg4,
),
),
),
Expanded(
child: Column(
children: [
for (var i = 0; i < rows.length; i++)
isRail ? railIcon(i) : expandedRow(i),
],
),
),
// footer help
if (!isRail)
Container(
height: 26,
padding: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
color: s.inputBg,
borderRadius: BorderRadius.circular(7),
border: Border.all(color: s.border),
),
child: Row(
children: [
Icon(Icons.info_outline, size: 11, color: accent),
const SizedBox(width: 6),
Text(
'Need help?',
style: TextStyle(
fontFamily:
SuperNavigationSidebarThemeData.bodyFont,
fontSize: 9,
fontWeight: FontWeight.w600,
color: s.fg2,
),
),
],
),
)
else
Container(
width: 32,
height: 26,
alignment: Alignment.center,
decoration: BoxDecoration(
color: s.inputBg,
borderRadius: BorderRadius.circular(7),
border: Border.all(color: s.border),
),
child: Icon(Icons.info_outline, size: 12, color: accent),
),
],
),
),
// faux page
Expanded(
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 80,
height: 8,
decoration: BoxDecoration(
color: s.fg1.withValues(alpha: 0.65),
borderRadius: BorderRadius.circular(3),
),
),
const SizedBox(height: 10),
Row(
children: [
for (var i = 0; i < 3; i++) ...[
if (i > 0) const SizedBox(width: 6),
Expanded(
child: Container(
height: 30,
decoration: BoxDecoration(
color: s.surface,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: s.border),
),
),
),
],
],
),
const SizedBox(height: 8),
Expanded(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: s.surface,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: s.border),
),
),
),
],
),
),
),
],
),
);
}
}
// ── small shared bits ─────────────────────────────────────────────
class _Mark extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 30,
height: 30,
alignment: Alignment.center,
decoration: BoxDecoration(
color: SuperNavigationSidebarThemeData.accent,
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
Icons.view_sidebar_rounded,
size: 16,
color: Colors.white,
),
);
}
}
class _VersionPill extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: SuperNavigationSidebarThemeData.accent.withValues(alpha: 0.13),
borderRadius: BorderRadius.circular(999),
border: Border.all(
color: SuperNavigationSidebarThemeData.accent.withValues(alpha: 0.35),
),
),
child: const Text(
'v3.2.0',
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.monoFont,
fontSize: 10.5,
fontWeight: FontWeight.w700,
color: SuperNavigationSidebarThemeData.accent,
),
),
);
}
}
class _TagPill extends StatelessWidget {
final String text;
const _TagPill(this.text);
@override
Widget build(BuildContext context) {
final s = SuperNavigationSidebarThemeData.of(context);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: s.inputBg,
borderRadius: BorderRadius.circular(6),
border: Border.all(color: s.border),
),
child: Text(
text,
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.monoFont,
fontSize: 10,
fontWeight: FontWeight.w600,
letterSpacing: 0.3,
color: s.fg3,
),
),
);
}
}
class _ThemeToggle extends StatelessWidget {
final bool dark;
final ValueChanged<bool> onToggle;
const _ThemeToggle({required this.dark, required this.onToggle});
@override
Widget build(BuildContext context) {
final s = SuperNavigationSidebarThemeData.of(context);
return GestureDetector(
onTap: () => onToggle(!dark),
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: Container(
height: 38,
padding: const EdgeInsets.symmetric(horizontal: 14),
decoration: BoxDecoration(
color: s.surface,
border: Border.all(color: s.borderStrong),
borderRadius: BorderRadius.circular(s.radiusMd),
),
child: Row(
children: [
Icon(
dark ? Icons.dark_mode_outlined : Icons.light_mode_outlined,
size: 15,
color: s.fg2,
),
const SizedBox(width: 8),
Text(
dark ? 'Dark' : 'Light',
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.bodyFont,
fontSize: 13,
fontWeight: FontWeight.w600,
color: s.fg1,
),
),
],
),
),
),
);
}
}
// ── floating "back to demos" wrapper for a pushed screen ──────────
class _BackScaffold extends StatelessWidget {
final Widget child;
const _BackScaffold({required this.child});
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned.fill(child: child),
Positioned(
left: 16,
bottom: 16,
child: SafeArea(
child: Material(
color: Colors.black.withValues(alpha: 0.62),
borderRadius: BorderRadius.circular(999),
child: InkWell(
borderRadius: BorderRadius.circular(999),
onTap: () => Navigator.of(context).maybePop(),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 14, vertical: 10),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.arrow_back, size: 16, color: Colors.white),
SizedBox(width: 7),
Text(
'Demos',
style: TextStyle(
fontFamily: SuperNavigationSidebarThemeData.bodyFont,
fontSize: 13,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
],
),
),
),
),
),
),
],
);
}
}