Skip to content
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