From 7ebf90b81c5485b5f94b0b10f9bdb07576cc4092 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:27:51 -0300 Subject: [PATCH 1/2] Create alert component --- demo/lib/components/alert.dart | 37 +++++++++ demo/lib/main.directories.g.dart | 41 ++++++---- lib/components/alert/alert.dart | 67 +++++++++++++++++ lib/components/alert/alert.style.dart | 104 ++++++++++++++++++++++++++ lib/remix_ui.dart | 2 + 5 files changed, 237 insertions(+), 14 deletions(-) create mode 100644 demo/lib/components/alert.dart create mode 100644 lib/components/alert/alert.dart create mode 100644 lib/components/alert/alert.style.dart diff --git a/demo/lib/components/alert.dart b/demo/lib/components/alert.dart new file mode 100644 index 0000000..1f67ccf --- /dev/null +++ b/demo/lib/components/alert.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:mix/mix.dart'; +import 'package:remix_ui/remix_ui.dart'; +import 'package:widgetbook/widgetbook.dart'; +import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; + +@widgetbook.UseCase( + name: 'interactive playground', + type: RemixAlert, +) +Widget buildCheckboxUseCase(BuildContext context) { + return Center( + child: SizedBox( + width: 300, + child: RemixAlert( + title: StyledText( + context.knobs.string( + label: 'Title', + initialValue: 'Error', + ), + ), + subtitle: StyledText( + context.knobs.string( + label: 'Subtitle', + initialValue: 'Your session has expired. Please log in again.', + ), + ), + leading: context.knobs.boolean( + label: 'Leading', + initialValue: false, + ) + ? const StyledIcon(Icons.warning_amber_rounded) + : null, + ), + ), + ); +} diff --git a/demo/lib/main.directories.g.dart b/demo/lib/main.directories.g.dart index 1e1e610..43adeb8 100644 --- a/demo/lib/main.directories.g.dart +++ b/demo/lib/main.directories.g.dart @@ -9,19 +9,32 @@ // ************************************************************************** // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:demo/components/avatar.dart' as _i2; -import 'package:demo/components/badge.dart' as _i3; -import 'package:demo/components/button.dart' as _i4; -import 'package:demo/components/checkbox.dart' as _i5; -import 'package:demo/components/list_tile.dart' as _i6; -import 'package:demo/components/radio.dart' as _i7; -import 'package:demo/components/switch.dart' as _i8; +import 'package:demo/components/alert.dart' as _i2; +import 'package:demo/components/avatar.dart' as _i3; +import 'package:demo/components/badge.dart' as _i4; +import 'package:demo/components/button.dart' as _i5; +import 'package:demo/components/checkbox.dart' as _i6; +import 'package:demo/components/list_tile.dart' as _i7; +import 'package:demo/components/radio.dart' as _i8; +import 'package:demo/components/switch.dart' as _i9; import 'package:widgetbook/widgetbook.dart' as _i1; final directories = <_i1.WidgetbookNode>[ _i1.WidgetbookFolder( name: 'components', children: [ + _i1.WidgetbookFolder( + name: 'alert', + children: [ + _i1.WidgetbookLeafComponent( + name: 'RemixAlert', + useCase: _i1.WidgetbookUseCase( + name: 'interactive playground', + builder: _i2.buildCheckboxUseCase, + ), + ) + ], + ), _i1.WidgetbookFolder( name: 'avatar', children: [ @@ -29,7 +42,7 @@ final directories = <_i1.WidgetbookNode>[ name: 'RemixAvatar', useCase: _i1.WidgetbookUseCase( name: 'interactive playground', - builder: _i2.buildCheckboxUseCase, + builder: _i3.buildCheckboxUseCase, ), ) ], @@ -41,7 +54,7 @@ final directories = <_i1.WidgetbookNode>[ name: 'RemixBadge', useCase: _i1.WidgetbookUseCase( name: 'interactive playground', - builder: _i3.buildCheckboxUseCase, + builder: _i4.buildCheckboxUseCase, ), ) ], @@ -53,7 +66,7 @@ final directories = <_i1.WidgetbookNode>[ name: 'RemixButton', useCase: _i1.WidgetbookUseCase( name: 'interactive playground', - builder: _i4.buildButtonUseCase, + builder: _i5.buildButtonUseCase, ), ) ], @@ -65,7 +78,7 @@ final directories = <_i1.WidgetbookNode>[ name: 'RemixCheckbox', useCase: _i1.WidgetbookUseCase( name: 'interactive playground', - builder: _i5.buildCheckboxUseCase, + builder: _i6.buildCheckboxUseCase, ), ) ], @@ -77,7 +90,7 @@ final directories = <_i1.WidgetbookNode>[ name: 'RemixListTile', useCase: _i1.WidgetbookUseCase( name: 'interactive playground', - builder: _i6.buildCheckboxUseCase, + builder: _i7.buildCheckboxUseCase, ), ) ], @@ -89,7 +102,7 @@ final directories = <_i1.WidgetbookNode>[ name: 'RemixRadio', useCase: _i1.WidgetbookUseCase( name: 'interactive playground', - builder: _i7.buildRadioUseCase, + builder: _i8.buildRadioUseCase, ), ) ], @@ -101,7 +114,7 @@ final directories = <_i1.WidgetbookNode>[ name: 'RemixSwitch', useCase: _i1.WidgetbookUseCase( name: 'interactive playground', - builder: _i8.buildRadioUseCase, + builder: _i9.buildRadioUseCase, ), ) ], diff --git a/lib/components/alert/alert.dart b/lib/components/alert/alert.dart new file mode 100644 index 0000000..d850403 --- /dev/null +++ b/lib/components/alert/alert.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:mix/mix.dart'; +import 'package:remix_ui/components/alert/alert.style.dart'; +import 'package:remix_ui/components/card/card.style.dart'; + +import '../../utils/component_recipe.dart'; + +class RemixAlert extends StatelessWidget + implements RemixComponentRecipe { + const RemixAlert({ + super.key, + this.leading, + this.title, + this.subtitle, + this.style, + this.variants = const [], + }); + + final Widget? leading; + final Widget? title; + final Widget? subtitle; + + @override + final AlertStyles? style; + + @override + final List variants; + + AlertStyles buildStyle(List variants) { + final result = style == null ? AlertStyles.base() : style!; + return result.applyVariants(variants); + } + + @override + Widget build(BuildContext context) { + final style = buildStyle(variants); + + return HBox( + style: style.outerRowContainer, + children: [ + if (leading != null) + MixProvider.build( + context, + style: style.icon, + builder: (_) => leading!, + ), + VBox( + style: style.innerColumnContainer, + children: [ + if (title != null) + MixProvider.build( + context, + style: style.title, + builder: (_) => title!, + ), + if (subtitle != null) + MixProvider.build( + context, + style: style.subtitle, + builder: (_) => subtitle!, + ), + ], + ), + ], + ); + } +} diff --git a/lib/components/alert/alert.style.dart b/lib/components/alert/alert.style.dart new file mode 100644 index 0000000..e9bb26a --- /dev/null +++ b/lib/components/alert/alert.style.dart @@ -0,0 +1,104 @@ +import 'package:mix/mix.dart'; + +class AlertStyles extends StyleRecipe { + const AlertStyles({ + this.outerRowContainer = const Style.empty(), + this.innerColumnContainer = const Style.empty(), + this.title = const Style.empty(), + this.subtitle = const Style.empty(), + this.icon = const Style.empty(), + }); + + final Style outerRowContainer; + final Style innerColumnContainer; + final Style title; + final Style subtitle; + final Style icon; + + factory AlertStyles.base() { + return AlertStyles( + outerRowContainer: _outerRowContainer(), + innerColumnContainer: _innerColumnContainer(), + title: _title(), + subtitle: _subtitle(), + icon: _icon(), + ); + } + + @override + AlertStyles applyVariants(List variants) { + return AlertStyles( + outerRowContainer: outerRowContainer.applyVariants(variants), + innerColumnContainer: innerColumnContainer.applyVariants(variants), + title: title.applyVariants(variants), + subtitle: subtitle.applyVariants(variants), + icon: icon.applyVariants(variants), + ); + } + + @override + AlertStyles merge(AlertStyles? other) { + if (other == null) return this; + return copyWith( + outerRowContainer: outerRowContainer.merge(other.outerRowContainer), + innerColumnContainer: + innerColumnContainer.merge(other.innerColumnContainer), + title: title.merge(other.title), + subtitle: subtitle.merge(other.subtitle), + icon: icon.merge(other.icon), + ); + } + + @override + AlertStyles copyWith({ + Style? outerRowContainer, + Style? innerColumnContainer, + Style? title, + Style? subtitle, + Style? icon, + }) { + return AlertStyles( + outerRowContainer: outerRowContainer ?? this.outerRowContainer, + innerColumnContainer: innerColumnContainer ?? this.innerColumnContainer, + title: title ?? this.title, + subtitle: subtitle ?? this.subtitle, + icon: icon ?? this.icon, + ); + } +} + +Style _outerRowContainer() => Style( + flex.gap(8), + box.padding(16), + box.borderRadius(8), + box.border.width(1), + box.border.color.redAccent(), + flex.mainAxisSize.min(), + flex.mainAxisAlignment.start(), + flex.crossAxisAlignment.start(), + ); + +Style _innerColumnContainer() => Style( + flex.gap(2), + flex.mainAxisSize.min(), + flex.mainAxisAlignment.start(), + flex.crossAxisAlignment.start(), + flexible.expanded(), + ); + +Style _title() => Style( + text.style.fontSize(14), + text.style.fontWeight.w600(), + text.style.color.redAccent(), + ); + +Style _subtitle() => Style( + text.style.fontSize(14), + text.style.fontWeight.normal(), + text.style.color.redAccent(), + ); + +Style _icon() => Style( + icon.size(20), + icon.color.redAccent(), + ); diff --git a/lib/remix_ui.dart b/lib/remix_ui.dart index e134e5e..750555c 100644 --- a/lib/remix_ui.dart +++ b/lib/remix_ui.dart @@ -1,5 +1,7 @@ library remix_ui; +export 'components/alert/alert.dart'; +export 'components/alert/alert.style.dart'; export 'components/button/button.dart'; export 'components/button/button.style.dart'; export 'components/button/button.variants.dart'; From 0e0b3b5edee3dfd68780b5d9812ae6de83d057b6 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Wed, 7 Feb 2024 15:28:09 -0300 Subject: [PATCH 2/2] small changes in RemixCards --- lib/components/card/card.dart | 30 +++++++++++++++++++++-------- lib/components/card/card.style.dart | 9 +-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/lib/components/card/card.dart b/lib/components/card/card.dart index 72f5e12..8c3bd00 100644 --- a/lib/components/card/card.dart +++ b/lib/components/card/card.dart @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; import 'package:mix/mix.dart'; import 'package:remix_ui/components/card/card.style.dart'; +import '../../utils/component_recipe.dart'; + class PresableRemixCard extends RemixCard { const PresableRemixCard({ super.key, @@ -11,16 +13,14 @@ class PresableRemixCard extends RemixCard { }); } -class RemixCard extends StatelessWidget { +class RemixCard extends StatelessWidget + implements RemixComponentRecipe { const RemixCard({ super.key, required this.child, - CardStyles? style, - }) : _customStyle = style; - - final Widget child; - - final CardStyles? _customStyle; + this.style, + this.variants = const [], + }); factory RemixCard.pressable( Widget child, { @@ -34,9 +34,23 @@ class RemixCard extends StatelessWidget { ); } + final Widget child; + + @override + final CardStyles? style; + + @override + final List variants; + + CardStyles buildStyle(List variants) { + final result = style == null ? CardStyles.base() : style!; + + return result.applyVariants(variants); + } + @override Widget build(BuildContext context) { - final style = CardStyles.build(_customStyle); + final style = buildStyle(variants); return Box( style: style.container, diff --git a/lib/components/card/card.style.dart b/lib/components/card/card.style.dart index 8a962fc..ead52ae 100644 --- a/lib/components/card/card.style.dart +++ b/lib/components/card/card.style.dart @@ -7,14 +7,7 @@ class CardStyles extends StyleRecipe { final Style container; - factory CardStyles.build([ - CardStyles? other, - List variants = const [], - ]) { - return CardStyles.defaults().merge(other).applyVariants(variants); - } - - factory CardStyles.defaults() { + factory CardStyles.base() { return CardStyles( container: Style( box.padding(16),