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: [MDS-924] Add breadcrumb widget #334

Merged
merged 11 commits into from
Jan 19, 2024
Merged
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
100 changes: 100 additions & 0 deletions example/assets/code_snippets/breadcrumb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:moon_design/moon_design.dart';

class BreadcrumbStory extends StatefulWidget {
const BreadcrumbStory({super.key});

@override
State<BreadcrumbStory> createState() => _BreadcrumbStoryState();
}

class _BreadcrumbStoryState extends State<BreadcrumbStory> {
bool _showDropdown = false;
Color? _dropdownIconColor;

@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// The default MoonBreadcrumb.
// Expands horizontally to the full path when the indicated show more item is tapped.
Column(
children: [
MoonBreadcrumb(
items: List.generate(
6,
(int index) {
return MoonBreadcrumbItem(
onTap: () {},
label: Text('Page $index'),
);
},
),
),
// Provides an explicit method to restore the expanded breadcrumb path
// to its collapsed state, enabling external control.
// By default, the state is automatically restored during rebuild.
MoonButton(
onTap: () => setState(() => {}),
label: const Text('Reset'),
),
],
),

// MoonBreadcrumb with the MoonDropdown and a custom showMoreWidget.
MoonBreadcrumb(
divider: Icon(
Directionality.of(context) == TextDirection.ltr
? MoonIcons.controls_chevron_right_small_16_light
: MoonIcons.controls_chevron_left_small_16_light,
),
showMoreWidget: MoonDropdown(
show: _showDropdown,
onTapOutside: () => setState(() {
_showDropdown = false;
_dropdownIconColor = context.moonColors!.iconSecondary;
}),
content: Column(
children: List.generate(
3,
(int index) => MoonMenuItem(
onTap: () {},
label: Text('Page ${index + 1}'),
),
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: MouseRegion(
onHover: (PointerHoverEvent _) {
setState(() => _dropdownIconColor = context.moonColors!.iconPrimary);
},
onExit: (PointerExitEvent _) {
if (!_showDropdown) setState(() => _dropdownIconColor = context.moonColors!.iconSecondary);
},
child: MoonButton.icon(
buttonSize: MoonButtonSize.xs,
hoverEffectColor: Colors.transparent,
iconColor: _dropdownIconColor ?? context.moonColors!.iconSecondary,
onTap: () => setState(() => _showDropdown = !_showDropdown),
icon: const Icon(MoonIcons.generic_burger_regular_16_light),
),
),
),
),
items: List.generate(
6,
(int index) {
return MoonBreadcrumbItem(
onTap: () {},
label: Text('Page $index'),
);
},
),
),
],
);
}
}
7 changes: 7 additions & 0 deletions example/lib/src/storybook/routing/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:example/src/storybook/stories/alert.dart';
import 'package:example/src/storybook/stories/auth_code.dart';
import 'package:example/src/storybook/stories/avatar.dart';
import 'package:example/src/storybook/stories/bottom_sheet.dart';
import 'package:example/src/storybook/stories/breadcrumb.dart';
import 'package:example/src/storybook/stories/button.dart';
import 'package:example/src/storybook/stories/carousel.dart';
import 'package:example/src/storybook/stories/checkbox.dart';
Expand Down Expand Up @@ -100,6 +101,12 @@ GoRouter router = GoRouter(
child: BottomSheetStory(),
),
),
GoRoute(
path: BreadcrumbStory.path,
pageBuilder: (BuildContext context, GoRouterState state) => const NoTransitionPage(
child: BreadcrumbStory(),
),
),
GoRoute(
path: ButtonStory.path,
pageBuilder: (BuildContext context, GoRouterState state) => const NoTransitionPage(
Expand Down
7 changes: 7 additions & 0 deletions example/lib/src/storybook/routing/route_aware_stories.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:example/src/storybook/stories/alert.dart';
import 'package:example/src/storybook/stories/auth_code.dart';
import 'package:example/src/storybook/stories/avatar.dart';
import 'package:example/src/storybook/stories/bottom_sheet.dart';
import 'package:example/src/storybook/stories/breadcrumb.dart';
import 'package:example/src/storybook/stories/button.dart';
import 'package:example/src/storybook/stories/carousel.dart';
import 'package:example/src/storybook/stories/checkbox.dart';
Expand Down Expand Up @@ -66,6 +67,12 @@ final List<Story> routeAwareStories = [
router: router,
codeString: fetchAsset('bottom_sheet.md'),
),
Story.asRoute(
name: 'Breadcrumb',
routePath: BreadcrumbStory.path,
router: router,
codeString: fetchAsset('breadcrumb.md'),
),
Story.asRoute(
name: 'Button',
routePath: ButtonStory.path,
Expand Down
242 changes: 242 additions & 0 deletions example/lib/src/storybook/stories/breadcrumb.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
import 'package:example/src/storybook/common/color_options.dart';
import 'package:example/src/storybook/common/widgets/text_divider.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:moon_design/moon_design.dart';
import 'package:storybook_flutter/storybook_flutter.dart';

class BreadcrumbStory extends StatefulWidget {
static const path = '/breadcrumb';

const BreadcrumbStory({super.key});

@override
State<BreadcrumbStory> createState() => _BreadcrumbStoryState();
}

class _BreadcrumbStoryState extends State<BreadcrumbStory> {
bool _showDropdown = false;
Color? _dropdownIconColor;

@override
Widget build(BuildContext context) {
final itemColorKnob = context.knobs.nullable.options(
label: "Item color",
description: "MoonColors variants for the MoonBreadcrumb's item.",
enabled: false,
initial: 0,
// piccolo
options: colorOptions,
);

final itemColor = colorTable(context)[itemColorKnob ?? 40];

final currentItemColorKnob = context.knobs.nullable.options(
label: "Current item color",
description: "MoonColors variants for the current MoonBreadcrumb's item.",
enabled: false,
initial: 0,
// piccolo
options: colorOptions,
);

final currentItemColor = colorTable(context)[currentItemColorKnob ?? 40];

final hoverEffectColorKnob = context.knobs.nullable.options(
label: "hoverEffectColor",
description: "MoonColors variants for the MoonBreadcrumb's item on hover.",
enabled: false,
initial: 0,
// piccolo
options: colorOptions,
);

final hoverEffectColor = colorTable(context)[hoverEffectColorKnob ?? 40];

final dividerColorKnob = context.knobs.nullable.options(
label: "dividerColor",
description: "MoonColors variants for the MoonBreadcrumb's divider.",
enabled: false,
initial: 0,
// piccolo
options: colorOptions,
);

final dividerColor = colorTable(context)[dividerColorKnob ?? 40];

final itemCountKnob = context.knobs.nullable.sliderInt(
label: "Item count",
description: "Total count of items for the MoonBreadcrumb.",
enabled: false,
initial: 7,
max: 12,
);

final visibleItemCountKnob = context.knobs.nullable.sliderInt(
label: "visibleItemCount",
description: "Count of items to display for the MoonBreadcrumb.",
enabled: false,
initial: 3,
max: 12,
);

final gapKnob = context.knobs.nullable.sliderInt(
label: "gap",
description: "Gap between the MoonBreadcrumb's items.",
enabled: false,
initial: 8,
max: 16,
);

final showLeadingKnob = context.knobs.boolean(
label: "leading",
description: "Show widget in the MoonBreadcrumb item's leading slot.",
);

final showTrailingKnob = context.knobs.boolean(
label: "trailing",
description: "Show widget in the MoonBreadcrumb item's trailing slot.",
);

return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const TextDivider(
text: "MoonBreadcrumb",
paddingTop: 0,
),
Column(
children: [
MoonBreadcrumb(
visibleItemCount: visibleItemCountKnob ?? 3,
gap: gapKnob?.toDouble(),
padding: const EdgeInsets.symmetric(horizontal: 16),
hoverEffectColor: hoverEffectColor,
dividerColor: dividerColor,
itemTextStyle: TextStyle(color: itemColor),
currentItemTextStyle: TextStyle(color: currentItemColor),
items: List.generate(
itemCountKnob ?? 7,
(int index) {
final bool isHomePage = index == 0;

return MoonBreadcrumbItem(
onTap: () => MoonToast.show(
context,
displayDuration: const Duration(seconds: 1),
label: Text(isHomePage ? 'Home Page' : 'Page $index'),
),
leading:
showLeadingKnob && isHomePage ? const Icon(MoonIcons.generic_home_16_light, size: 16) : null,
label: Text(isHomePage ? 'Home' : 'Page $index'),
trailing:
showTrailingKnob && isHomePage ? const Icon(MoonIcons.generic_home_16_light, size: 16) : null,
);
},
),
),
const SizedBox(height: 16),
MoonButton(
backgroundColor: context.moonColors!.piccolo,
onTap: () => setState(() => {}),
label: Text(
'Reset',
style: TextStyle(color: context.moonColors!.goten),
),
),
],
),
const TextDivider(text: "Custom MoonBreadcrumb with MoonDropdown"),
StatefulBuilder(
builder: (context, setState) {
return MoonBreadcrumb(
visibleItemCount: visibleItemCountKnob ?? 3,
gap: gapKnob?.toDouble(),
padding: const EdgeInsets.symmetric(horizontal: 16),
hoverEffectColor: hoverEffectColor,
dividerColor: dividerColor,
itemTextStyle: TextStyle(color: itemColor),
currentItemTextStyle: TextStyle(color: currentItemColor),
itemDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
),
divider: Icon(
Directionality.of(context) == TextDirection.ltr
? MoonIcons.controls_chevron_right_small_16_light
: MoonIcons.controls_chevron_left_small_16_light,
),
showMoreWidget: MoonDropdown(
show: _showDropdown,
onTapOutside: () => setState(() {
_showDropdown = false;
_dropdownIconColor = context.moonColors!.iconSecondary;
}),
content: Column(
children: List.generate(
4,
(int index) => MoonMenuItem(
width: 120,
onTap: () => MoonToast.show(
context,
displayDuration: const Duration(seconds: 1),
label: Text('Page ${index + 1}'),
),
label: Text('Page ${index + 1}'),
),
),
),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: gapKnob?.toDouble() ?? 8),
child: MouseRegion(
onHover: (PointerHoverEvent event) {
setState(() => _dropdownIconColor = hoverEffectColor ?? context.moonColors!.iconPrimary);
},
onExit: (PointerExitEvent event) {
if (!_showDropdown) {
setState(() => _dropdownIconColor = itemColor ?? context.moonColors!.iconSecondary);
}
},
child: MoonButton.icon(
buttonSize: MoonButtonSize.xs,
hoverEffectColor: Colors.transparent,
iconColor: _dropdownIconColor ?? context.moonColors!.iconSecondary,
icon: const Icon(MoonIcons.generic_burger_regular_16_light),
onTap: () => setState(() => _showDropdown = !_showDropdown),
),
),
),
),
items: List.generate(
itemCountKnob ?? 7,
(int index) {
final bool isHomePage = index == 0;

return MoonBreadcrumbItem(
onTap: () => MoonToast.show(
context,
displayDuration: const Duration(seconds: 1),
label: Text(isHomePage ? 'Home Page' : 'Page $index'),
),
leading: showLeadingKnob && isHomePage
? const Icon(
MoonIcons.generic_home_16_light,
size: 16,
)
: null,
label: Text(isHomePage ? 'Home' : 'Page $index'),
trailing: showTrailingKnob && isHomePage
? const Icon(
MoonIcons.generic_home_16_light,
size: 16,
)
: null,
);
},
),
);
},
),
],
);
}
}
Loading