Skip to content

Commit

Permalink
feat: [MDS-924] Add breadcrumb widget (#334)
Browse files Browse the repository at this point in the history
Co-authored-by: Kolya Paradiuk <kolya@Kolyas-MacBook-Pro.local>
Co-authored-by: BirgittMajas <79840500+BirgittMajas@users.noreply.github.com>
  • Loading branch information
3 people committed Jan 19, 2024
1 parent a13987c commit 6767d86
Show file tree
Hide file tree
Showing 13 changed files with 1,115 additions and 4 deletions.
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

0 comments on commit 6767d86

Please sign in to comment.