From c2199dfc0e6a09170ecc2eaca3a12cb1408607b7 Mon Sep 17 00:00:00 2001 From: akaboshinit Date: Thu, 9 Jan 2025 13:05:02 +0900 Subject: [PATCH 1/2] feat: adding scenario navigation path --- examples/generator_app/lib/main.dart | 5 +- examples/generator_app/lib/main_catalog.dart | 27 ++- examples/simple_app/lib/main.dart | 5 +- examples/simple_app/lib/main_catalog.dart | 37 ++-- .../playbook_ui/lib/src/playbook_gallery.dart | 203 +++++++++++------- .../lib/src/scenario_container.dart | 20 +- 6 files changed, 164 insertions(+), 133 deletions(-) diff --git a/examples/generator_app/lib/main.dart b/examples/generator_app/lib/main.dart index c055189..8256529 100644 --- a/examples/generator_app/lib/main.dart +++ b/examples/generator_app/lib/main.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; - -import 'bar/bar.dart'; +import 'package:generator_app/bar/bar.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { diff --git a/examples/generator_app/lib/main_catalog.dart b/examples/generator_app/lib/main_catalog.dart index 7b0ea9a..0f3fac1 100644 --- a/examples/generator_app/lib/main_catalog.dart +++ b/examples/generator_app/lib/main_catalog.dart @@ -1,12 +1,14 @@ -import 'package:generator_app/generated_playbook.dart'; import 'package:flutter/material.dart'; +import 'package:generator_app/generated_playbook.dart'; import 'package:playbook_ui/playbook_ui.dart'; void main() { - runApp(MyApp()); + runApp(const MyApp()); } class MyApp extends StatefulWidget { + const MyApp({super.key}); + @override State createState() => _MyAppState(); } @@ -17,18 +19,15 @@ class _MyAppState extends State { @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Playbook Demo', - theme: _isDark ? ThemeData.dark() : ThemeData.light(), - home: PlaybookGallery( - title: 'Generator app', - searchTextController: controller, - checkeredColor: null, - onCustomActionPressed: () => setState(() { - _isDark = !_isDark; - }), - playbook: playbook, - ), + return PlaybookGallery( + title: 'Generator app', + searchTextController: controller, + checkeredColor: null, + onCustomActionPressed: () => setState(() { + _isDark = !_isDark; + }), + lightTheme: _isDark ? ThemeData.dark() : ThemeData.light(), + playbook: playbook, ); } } diff --git a/examples/simple_app/lib/main.dart b/examples/simple_app/lib/main.dart index c055189..8625d3e 100644 --- a/examples/simple_app/lib/main.dart +++ b/examples/simple_app/lib/main.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; - -import 'bar/bar.dart'; +import 'package:simple_app/bar/bar.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { diff --git a/examples/simple_app/lib/main_catalog.dart b/examples/simple_app/lib/main_catalog.dart index dfdb09a..68bd538 100644 --- a/examples/simple_app/lib/main_catalog.dart +++ b/examples/simple_app/lib/main_catalog.dart @@ -8,10 +8,12 @@ import 'package:simple_app/page/page.story.dart'; import 'package:simple_app/scrollable/scrollable.story.dart'; void main() { - runApp(MyApp()); + runApp(const MyApp()); } class MyApp extends StatefulWidget { + const MyApp({super.key}); + @override State createState() => _MyAppState(); } @@ -22,24 +24,21 @@ class _MyAppState extends State { @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Playbook Demo', - theme: _isDark ? ThemeData.dark() : ThemeData.light(), - home: PlaybookGallery( - title: 'Sample app', - searchTextController: controller, - onCustomActionPressed: () => setState(() { - _isDark = !_isDark; - }), - playbook: Playbook( - stories: [ - barStory(), - fooWidgetStory(), - assetImageStory(), - homePageStory(), - scrollableStory(), - ], - ), + return PlaybookGallery( + title: 'Sample app', + searchTextController: controller, + onCustomActionPressed: () => setState(() { + _isDark = !_isDark; + }), + lightTheme: _isDark ? ThemeData.dark() : ThemeData.light(), + playbook: Playbook( + stories: [ + barStory(), + fooWidgetStory(), + assetImageStory(), + homePageStory(), + scrollableStory(), + ], ), ); } diff --git a/packages/playbook_ui/lib/src/playbook_gallery.dart b/packages/playbook_ui/lib/src/playbook_gallery.dart index 952dad3..6c594a6 100644 --- a/packages/playbook_ui/lib/src/playbook_gallery.dart +++ b/packages/playbook_ui/lib/src/playbook_gallery.dart @@ -5,7 +5,11 @@ import 'package:playbook_ui/src/scenario_container.dart'; class PlaybookGallery extends StatefulWidget { const PlaybookGallery({ - super.key, + required this.playbook, + this.initialRoute = '/', + this.lightTheme, + this.darkTheme, + this.themeMode = ThemeMode.system, this.title = 'Playbook', this.canvasColor = Colors.white, this.checkeredColor = Colors.black12, @@ -13,10 +17,14 @@ class PlaybookGallery extends StatefulWidget { this.searchTextController, this.onCustomActionPressed, this.otherCustomActions = const [], - required this.playbook, this.scenarioWidgetBuilder, + super.key, }); + final String initialRoute; + final ThemeData? lightTheme; + final ThemeData? darkTheme; + final ThemeMode? themeMode; final String title; final Color? canvasColor; final Color? checkeredColor; @@ -57,89 +65,128 @@ class PlaybookGalleryState extends State { @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: SearchBox( - controller: _effectiveSearchTextController, - ), - actions: [ - if (widget.onCustomActionPressed != null) - IconButton( - onPressed: widget.onCustomActionPressed, - icon: const Icon(Icons.settings), + final storyMap = Map.fromEntries( + widget.playbook.stories.expand( + (story) => story.scenarios.map( + (scenario) => MapEntry( + "/${Uri.encodeFull('${story.title}-${scenario.title}')}", + (_) => DialogScaffold( + title: Text(scenario.title), + body: ScenarioWidget( + useMaterial: false, + scenario: scenario, + ), ), - ...widget.otherCustomActions, - ], - ), - drawer: StoryDrawer( - stories: _stories, - textController: _effectiveSearchTextController, + ), + ), ), - onDrawerChanged: (opened) { - if (opened) _unfocus(); - }, - body: ListView.builder( - controller: _scrollController, - itemCount: _stories.length, - itemBuilder: (context, index) { - final story = _stories.elementAt(index); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 16), - Row( - children: [ - const SizedBox(width: 16), - Icon( - Icons.folder_outlined, - size: 32, - color: Theme.of(context).colorScheme.primary, - ), - const SizedBox(width: 8), - Flexible( - child: Text( - story.title, - style: Theme.of(context) - .textTheme - .titleLarge - ?.copyWith(fontWeight: FontWeight.bold), + ); + + return MaterialApp( + initialRoute: '/', + themeMode: widget.themeMode, + title: widget.title, + theme: widget.lightTheme, + darkTheme: widget.darkTheme, + routes: { + '/': (_) => Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: SearchBox( + controller: _effectiveSearchTextController, + ), + actions: [ + if (widget.onCustomActionPressed != null) + IconButton( + onPressed: widget.onCustomActionPressed, + icon: const Icon(Icons.settings), ), - ), - const SizedBox(width: 16), + ...widget.otherCustomActions, ], ), - const SizedBox(height: 16), - SingleChildScrollView( - key: PageStorageKey(index), - padding: const EdgeInsets.symmetric(horizontal: 16), - scrollDirection: Axis.horizontal, - physics: const AlwaysScrollableScrollPhysics(), - clipBehavior: Clip.none, - child: Wrap( - spacing: 16, - children: story.scenarios - .map( - (e) => ScenarioContainer( - key: ValueKey(e), - scenario: e, - thumbnailScale: widget.scenarioThumbnailScale, - canvasColor: widget.canvasColor, - checkeredColor: widget.checkeredColor, - widgetBuilder: widget.scenarioWidgetBuilder, + drawer: StoryDrawer( + stories: _stories, + textController: _effectiveSearchTextController, + ), + onDrawerChanged: (opened) { + if (opened) _unfocus(); + }, + body: ListView.builder( + controller: _scrollController, + itemCount: _stories.length, + itemBuilder: (context, index) { + final story = _stories.elementAt(index); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 16), + Row( + children: [ + const SizedBox(width: 16), + Icon( + Icons.folder_outlined, + size: 32, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 8), + Flexible( + child: Text( + story.title, + style: Theme.of(context) + .textTheme + .titleLarge + ?.copyWith(fontWeight: FontWeight.bold), + ), + ), + const SizedBox(width: 16), + ], + ), + const SizedBox(height: 16), + SingleChildScrollView( + key: PageStorageKey(index), + padding: const EdgeInsets.symmetric(horizontal: 16), + scrollDirection: Axis.horizontal, + physics: const AlwaysScrollableScrollPhysics(), + clipBehavior: Clip.none, + child: Wrap( + spacing: 16, + children: story.scenarios + .map( + (scenario) => ScenarioContainer( + key: ValueKey(scenario), + navigationPath: + "/${Uri.encodeFull('${story.title}-${scenario.title}')}", + scenario: scenario, + thumbnailScale: widget.scenarioThumbnailScale, + canvasColor: widget.canvasColor, + checkeredColor: widget.checkeredColor, + widgetBuilder: widget.scenarioWidgetBuilder, + ), + ) + .toList() + ..sort( + (s1, s2) => s1.scenario.title + .compareTo(s2.scenario.title), + ), ), - ) - .toList() - ..sort( - (s1, s2) => - s1.scenario.title.compareTo(s2.scenario.title), - ), - ), + ), + const SizedBox(height: 8), + ], + ); + }, ), - const SizedBox(height: 8), - ], - ); - }, + ), + ...storyMap, + }, + onUnknownRoute: (settings) => MaterialPageRoute( + builder: (_) => Scaffold( + appBar: AppBar( + title: const Text('Not Found'), + ), + body: Center( + child: Text('No route defined for ${settings.name}'), + ), + ), ), ); } diff --git a/packages/playbook_ui/lib/src/scenario_container.dart b/packages/playbook_ui/lib/src/scenario_container.dart index 483a53f..ebea303 100644 --- a/packages/playbook_ui/lib/src/scenario_container.dart +++ b/packages/playbook_ui/lib/src/scenario_container.dart @@ -6,6 +6,7 @@ class ScenarioContainer extends StatelessWidget { const ScenarioContainer({ super.key, required this.scenario, + required this.navigationPath, required this.thumbnailScale, this.canvasColor, this.checkeredColor, @@ -13,6 +14,7 @@ class ScenarioContainer extends StatelessWidget { }); final Scenario scenario; + final String navigationPath; final double thumbnailScale; final Color? canvasColor; final Color? checkeredColor; @@ -80,22 +82,8 @@ class ScenarioContainer extends StatelessWidget { ), onTap: () { FocusScope.of(context).unfocus(); - Navigator.of(context).push( - MaterialPageRoute( - fullscreenDialog: true, - builder: (context) { - return DialogScaffold( - title: Text(scenario.title), - body: ScenarioWidget( - canvasColor: canvasColor, - checkeredColor: checkeredColor, - useMaterial: false, - scenario: scenario, - builder: widgetBuilder, - ), - ); - }, - ), + Navigator.of(context).pushNamed( + navigationPath, ); }, ); From 70cf91e35069c610cf82cc8195331aa36db68e84 Mon Sep 17 00:00:00 2001 From: akaboshinit Date: Thu, 9 Jan 2025 13:45:58 +0900 Subject: [PATCH 2/2] fix: PlaybookGallery props to ScenarioContainer --- packages/playbook_ui/lib/src/playbook_gallery.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/playbook_ui/lib/src/playbook_gallery.dart b/packages/playbook_ui/lib/src/playbook_gallery.dart index 6c594a6..83ee627 100644 --- a/packages/playbook_ui/lib/src/playbook_gallery.dart +++ b/packages/playbook_ui/lib/src/playbook_gallery.dart @@ -75,6 +75,9 @@ class PlaybookGalleryState extends State { body: ScenarioWidget( useMaterial: false, scenario: scenario, + canvasColor: widget.canvasColor, + checkeredColor: widget.checkeredColor, + builder: widget.scenarioWidgetBuilder, ), ), ),