Skip to content

Commit 922ae3d

Browse files
committed
feat: add OpenWidgetbookCommand and widgetbook entry point, update .gitignore for Flutter generated files
1 parent 5529714 commit 922ae3d

7 files changed

Lines changed: 120 additions & 34 deletions

File tree

.gitignore

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,14 @@ mason-lock.json
1111
*.iml
1212
.DS_Store
1313
.DS_Store?
14-
**/.DS_Store
14+
**/.DS_Store
15+
16+
# Files generated by Flutter
17+
*.iml
18+
.dart_tool/
19+
.flutter-plugins
20+
.flutter-plugins-dependencies
21+
.packages
22+
pubspec.lock
23+
.mason/
24+
build/

lib/src/commands/command_runner.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'config_command.dart';
1212
import 'create_app_command.dart';
1313
import 'doctor_command.dart';
1414
import 'generate_command.dart';
15+
import 'open_widget_book.dart';
1516
import 'update_app_command.dart';
1617

1718
class FlutterBunnyRunner extends CompletionCommandRunner<int> {
@@ -30,6 +31,7 @@ class FlutterBunnyRunner extends CompletionCommandRunner<int> {
3031
) {
3132
_setupArgParser();
3233
addCommand(CreateAppCommand(logger: _base.logger));
34+
addCommand(OpenWidgetbookCommand(logger: _base.logger));
3335
addCommand(UpdateCommand(_base.logger));
3436
addCommand(BuildCommand(logger: _base.logger));
3537
addCommand(GenerateCommand(logger: _base.logger));
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import 'dart:io';
2+
3+
import 'package:args/command_runner.dart';
4+
import 'package:mason_logger/mason_logger.dart';
5+
import 'package:meta/meta.dart';
6+
7+
import '../common/base_command.dart';
8+
9+
class OpenWidgetbookCommand extends Command<int> {
10+
OpenWidgetbookCommand({
11+
required Logger logger,
12+
@visibleForTesting MasonGeneratorFromBundle? generatorFromBundle,
13+
@visibleForTesting MasonGeneratorFromBrick? generatorFromBrick,
14+
});
15+
16+
@override
17+
String get description => 'Open Widgetbook for your Flutter application';
18+
19+
@override
20+
String get name => 'widgetbook';
21+
22+
@override
23+
Future<int> run() async {
24+
print('📦 Launching Widgetbook...');
25+
try {
26+
final result = await Process.run(
27+
'flutter',
28+
['run', '-d', 'chrome', '-t', 'lib/widgetbook.dart'],
29+
);
30+
31+
stdout.write(result.stdout);
32+
stderr.write(result.stderr);
33+
34+
return ExitCode.success.code;
35+
} catch (e) {
36+
print('❌ Failed to launch Widgetbook: $e');
37+
return ExitCode.osError.code;
38+
}
39+
}
40+
}

lib/src/common/cli_exception.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
class CliException implements Exception {
2+
CliException(this.message, [this.cause]);
23
final String message;
34
final dynamic cause;
45
StackTrace? _stackTrace;
56

6-
CliException(this.message, [this.cause]);
7-
87
/// Get the stack trace
98
StackTrace? get stackTrace => _stackTrace;
109

@@ -28,7 +27,10 @@ class CliException implements Exception {
2827

2928
extension CliExceptionUtils on CliException {
3029
static CliException withTrace(
31-
String message, dynamic cause, StackTrace stackTrace) {
30+
String message,
31+
dynamic cause,
32+
StackTrace stackTrace,
33+
) {
3234
final exception = CliException(message, cause);
3335
exception.setStackTrace(stackTrace);
3436
return exception;
@@ -39,7 +41,10 @@ class CommandException extends CliException {
3941
CommandException(super.message, [super.cause]);
4042

4143
static CommandException withTrace(
42-
String message, dynamic cause, StackTrace stackTrace) {
44+
String message,
45+
dynamic cause,
46+
StackTrace stackTrace,
47+
) {
4348
final exception = CommandException(message, cause);
4449
exception.setStackTrace(stackTrace);
4550
return exception;

lib/src/common/config_flags.dart

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:args/args.dart';
2-
import 'package:flutter_bunny/src/common/config_manager.dart';
2+
3+
import 'config_manager.dart';
34

45
/// Default description for new Flutter projects.
56
const _defaultDescription =
@@ -26,28 +27,40 @@ mixin ArgParserConfiguration {
2627
}) {
2728
// If we have a config manager, use it to get default values
2829
final config = configManager;
29-
30+
3031
// Get defaults from config or use provided defaults
3132
final defaultArchitecture = config?.getValue<String>(
32-
'defaults.architecture',
33-
defaultValue: architecture ?? 'clean_architecture',
34-
) ?? architecture ?? 'clean_architecture';
35-
33+
'defaults.architecture',
34+
defaultValue: architecture ?? 'clean_architecture',
35+
) ??
36+
architecture ??
37+
'clean_architecture';
38+
3639
final defaultStateManagement = config?.getValue<String>(
37-
'defaults.state_management',
38-
defaultValue: stateManagement ?? 'provider',
39-
) ?? stateManagement ?? 'provider';
40-
41-
final defaultFeatures = config?.getValue<List<dynamic>>(
42-
'defaults.features',
43-
defaultValue: features?.cast<dynamic>() ?? ['authentication'],
44-
)?.cast<String>() ?? features ?? ['authentication'];
45-
46-
final defaultModules = config?.getValue<List<dynamic>>(
47-
'defaults.modules',
48-
defaultValue: modules?.cast<dynamic>() ?? ['network_layer'],
49-
)?.cast<String>() ?? modules ?? ['network_layer'];
50-
40+
'defaults.state_management',
41+
defaultValue: stateManagement ?? 'provider',
42+
) ??
43+
stateManagement ??
44+
'provider';
45+
46+
final defaultFeatures = config
47+
?.getValue<List<dynamic>>(
48+
'defaults.features',
49+
defaultValue: features?.cast<dynamic>() ?? ['authentication'],
50+
)
51+
?.cast<String>() ??
52+
features ??
53+
['authentication'];
54+
55+
final defaultModules = config
56+
?.getValue<List<dynamic>>(
57+
'defaults.modules',
58+
defaultValue: modules?.cast<dynamic>() ?? ['network_layer'],
59+
)
60+
?.cast<String>() ??
61+
modules ??
62+
['network_layer'];
63+
5164
// Configure the argument parser with the resolved default values
5265
argParser
5366
// Project configuration options
@@ -67,7 +80,7 @@ mixin ArgParserConfiguration {
6780
help: 'The name of the Flutter project (in snake_case).',
6881
defaultsTo: projectName ?? 'my_flutter_app',
6982
)
70-
83+
7184
// Architecture and structure options
7285
..addOption(
7386
'architecture',
@@ -93,7 +106,7 @@ mixin ArgParserConfiguration {
93106
],
94107
defaultsTo: defaultStateManagement,
95108
)
96-
109+
97110
// Feature and module options
98111
..addMultiOption(
99112
'features',
@@ -102,7 +115,7 @@ mixin ArgParserConfiguration {
102115
'authentication',
103116
'user_profile',
104117
'settings',
105-
'dashboard'
118+
'dashboard',
106119
],
107120
defaultsTo: defaultFeatures,
108121
)
@@ -117,22 +130,22 @@ mixin ArgParserConfiguration {
117130
],
118131
defaultsTo: defaultModules,
119132
)
120-
133+
121134
// Mode options
122135
..addFlag(
123136
'interactive',
124137
abbr: 'i',
125138
help: 'Run in interactive mode to configure the project.',
126-
negatable: true,
127139
defaultsTo: config?.getValue<bool>(
128-
'generation.interactive',
129-
defaultValue: true,
130-
) ?? true,
140+
'generation.interactive',
141+
defaultValue: true,
142+
) ??
143+
true,
131144
)
132145
..addFlag(
133146
'verbose',
134147
help: 'Show verbose output for debugging.',
135148
negatable: false,
136149
);
137150
}
138-
}
151+
}

lib/widgetbook.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// lib/widgetbook.dart
2+
import 'package:flutter/material.dart';
3+
4+
void main() {
5+
runApp(
6+
const MaterialApp(
7+
home: Scaffold(
8+
body: Center(
9+
child: Text('Hello, Widgetbook!'),
10+
),
11+
),
12+
),
13+
);
14+
}

pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ dependencies:
2727
sprintf: ^7.0.0
2828
universal_io: ^2.2.2
2929
win32: ^5.6.0
30+
flutter:
31+
sdk: flutter
3032

3133
dev_dependencies:
3234
build_runner: ^2.4.9

0 commit comments

Comments
 (0)