Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding scenario navigation path #116

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions examples/generator_app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down
27 changes: 13 additions & 14 deletions examples/generator_app/lib/main_catalog.dart
Original file line number Diff line number Diff line change
@@ -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<MyApp> createState() => _MyAppState();
}
Expand All @@ -17,18 +19,15 @@ class _MyAppState extends State<MyApp> {

@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,
);
}
}
5 changes: 2 additions & 3 deletions examples/simple_app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down
37 changes: 18 additions & 19 deletions examples/simple_app/lib/main_catalog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<MyApp> createState() => _MyAppState();
}
Expand All @@ -22,24 +24,21 @@ class _MyAppState extends State<MyApp> {

@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(),
],
),
);
}
Expand Down
206 changes: 128 additions & 78 deletions packages/playbook_ui/lib/src/playbook_gallery.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@ 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,
this.scenarioThumbnailScale = 0.3,
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;
Expand Down Expand Up @@ -57,89 +65,131 @@ class PlaybookGalleryState extends State<PlaybookGallery> {

@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<String, WidgetBuilder>.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,
canvasColor: widget.canvasColor,
checkeredColor: widget.checkeredColor,
builder: widget.scenarioWidgetBuilder,
),
),
...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}'),
),
),
),
);
}
Expand Down
Loading
Loading