feat(ui): make components more coherent + docs

This commit is contained in:
Hugo Pointcheval 2023-04-27 16:54:16 +02:00
parent 0d5109fc77
commit 01269027f2
Signed by: hugo
GPG Key ID: 3AAC487E131E00BC
31 changed files with 743 additions and 127 deletions

View File

@ -17,7 +17,11 @@
import 'package:flutter/foundation.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
/// {@template button_component}
/// A button component is a component that can be pressed.
/// {@endtemplate}
abstract class ButtonComponent extends Component {
/// {@macro button_component}
const ButtonComponent({
this.disabledStyle,
this.normalStyle,

View File

@ -18,7 +18,11 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/theme_style.dart';
/// {@template button_style}
/// Base class for button styles.
/// {@endtemplate}
abstract class ButtonStyle<T> extends ThemeStyle<T> {
/// {@macro button_style}
const ButtonStyle({
this.radius,
this.padding,

View File

@ -24,10 +24,10 @@ part 'file_selection_button_component.g.dart';
abstract class FileSelectionButtonComponent extends ButtonComponent
with CopyWithMixin<$FileSelectionButtonComponentCWProxy> {
const FileSelectionButtonComponent({
this.mainAxisSize = MainAxisSize.min,
this.mainAxisSize,
this.leading,
this.title,
this.subTitle,
this.subtitle,
super.disabledStyle,
super.normalStyle,
super.hoveredStyle,
@ -64,8 +64,15 @@ abstract class FileSelectionButtonComponent extends ButtonComponent
@override
FileSelectionButtonStyle? get invalidStyle;
/// The main axis size of the button
final MainAxisSize? mainAxisSize;
/// The leading widget of the button
final Widget? leading;
/// The title of the button
final TextWrapper? title;
final TextWrapper? subTitle;
/// The subtitle of the button
final TextWrapper? subtitle;
}

View File

@ -10,7 +10,7 @@ abstract class $FileSelectionButtonComponentCWProxy {
FileSelectionButtonComponent mainAxisSize(MainAxisSize? mainAxisSize);
FileSelectionButtonComponent leading(Widget? leading);
FileSelectionButtonComponent title(TextWrapper? title);
FileSelectionButtonComponent subTitle(TextWrapper? subTitle);
FileSelectionButtonComponent subtitle(TextWrapper? subtitle);
FileSelectionButtonComponent disabledStyle(
ButtonStyle<dynamic>? disabledStyle);
FileSelectionButtonComponent normalStyle(ButtonStyle<dynamic>? normalStyle);
@ -30,7 +30,7 @@ abstract class $FileSelectionButtonComponentCWProxy {
MainAxisSize? mainAxisSize,
Widget? leading,
TextWrapper? title,
TextWrapper? subTitle,
TextWrapper? subtitle,
ButtonStyle<dynamic>? disabledStyle,
ButtonStyle<dynamic>? normalStyle,
ButtonStyle<dynamic>? hoveredStyle,

View File

@ -20,10 +20,16 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template file_selection_button_style}
/// File selection button style.
///
/// This style is used for the FileSelectionButton widget.
/// {@endtemplate}
class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
/// {@macro file_selection_button_style}
const FileSelectionButtonStyle({
this.title,
this.subTitle,
this.titleStyle,
this.subtitleStyle,
super.radius,
super.padding,
super.foregroundColors,
@ -46,8 +52,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
}
return a.copyWith(
title: b.title,
subTitle: b.subTitle,
titleStyle: b.titleStyle,
subtitleStyle: b.subtitleStyle,
radius: b.radius,
padding: b.padding,
foregroundColors: b.foregroundColors,
@ -69,8 +75,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
}
// b.copyWith to return b attributes even if they are not lerped
return b.copyWith(
title: TextStyle.lerp(a.title, b.title, t),
subTitle: TextStyle.lerp(a.title, b.title, t),
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
foregroundColors: MultiColor.lerp(
a.foregroundColors,
b.foregroundColors,
@ -96,12 +102,12 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
/// Title text style
///
/// Default to `TextTheme.labelLarge`
final TextStyle? title;
final TextStyle? titleStyle;
/// Sub title text style
///
/// Default to `TextTheme.labelSmall`
final TextStyle? subTitle;
final TextStyle? subtitleStyle;
@override
FileSelectionButtonStyle? mergeWith(FileSelectionButtonStyle? other) =>
@ -109,8 +115,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
@override
FileSelectionButtonStyle? copyWith({
TextStyle? title,
TextStyle? subTitle,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? foregroundColors,
@ -120,8 +126,8 @@ class FileSelectionButtonStyle extends ButtonStyle<FileSelectionButtonStyle> {
BoxShadow? shadow,
}) =>
FileSelectionButtonStyle(
title: title ?? this.title,
subTitle: subTitle ?? this.subTitle,
titleStyle: titleStyle ?? this.titleStyle,
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
radius: radius ?? this.radius,
padding: padding ?? this.padding,
foregroundColors: foregroundColors ?? this.foregroundColors,

View File

@ -54,8 +54,15 @@ abstract class FlatButtonComponent extends ButtonComponent
@override
FlatButtonStyle? get tappedStyle;
/// The main axis size of the button.
final MainAxisSize? mainAxisSize;
/// The prefix widget of the button.
final Widget? prefix;
/// The suffix widget of the button.
final Widget? suffix;
/// The label widget of the button.
final TextWrapper? label;
}

View File

@ -20,9 +20,15 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template flat_button_style}
/// Flat button style.
///
/// This style is used for the FlatButton widget.
/// {@endtemplate}
class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
/// {@macro flat_button_style}
const FlatButtonStyle({
this.label,
this.labelStyle,
super.radius,
super.padding,
super.foregroundColors,
@ -45,7 +51,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
}
return a.copyWith(
label: b.label,
labelStyle: b.labelStyle,
radius: b.radius,
padding: b.padding,
foregroundColors: b.foregroundColors,
@ -67,7 +73,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
}
// b.copyWith to return b attributes even if they are not lerped
return b.copyWith(
label: TextStyle.lerp(a.label, b.label, t),
labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
foregroundColors: MultiColor.lerp(
a.foregroundColors,
b.foregroundColors,
@ -90,10 +96,10 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
);
}
/// Label text style
/// labelStyle text style
///
/// Default to `TextTheme.labelLarge`
final TextStyle? label;
final TextStyle? labelStyle;
@override
FlatButtonStyle? mergeWith(FlatButtonStyle? other) =>
@ -101,7 +107,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
@override
FlatButtonStyle? copyWith({
TextStyle? label,
TextStyle? labelStyle,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? foregroundColors,
@ -111,7 +117,7 @@ class FlatButtonStyle extends ButtonStyle<FlatButtonStyle> {
BoxShadow? shadow,
}) =>
FlatButtonStyle(
label: label ?? this.label,
labelStyle: labelStyle ?? this.labelStyle,
radius: radius ?? this.radius,
padding: padding ?? this.padding,
foregroundColors: foregroundColors ?? this.foregroundColors,

View File

@ -51,5 +51,6 @@ abstract class SimpleIconButtonComponent extends ButtonComponent
@override
SimpleIconButtonStyle? get tappedStyle;
final Icon? icon;
/// The icon to display inside the button.
final Widget? icon;
}

View File

@ -7,7 +7,7 @@ part of 'simple_icon_button_component.dart';
// **************************************************************************
abstract class $SimpleIconButtonComponentCWProxy {
SimpleIconButtonComponent icon(Icon? icon);
SimpleIconButtonComponent icon(Widget? icon);
SimpleIconButtonComponent disabledStyle(ButtonStyle<dynamic>? disabledStyle);
SimpleIconButtonComponent normalStyle(ButtonStyle<dynamic>? normalStyle);
SimpleIconButtonComponent hoveredStyle(ButtonStyle<dynamic>? hoveredStyle);
@ -19,7 +19,7 @@ abstract class $SimpleIconButtonComponentCWProxy {
ThemeResolver<dynamic, dynamic, dynamic>? themeResolver);
SimpleIconButtonComponent key(Key? key);
SimpleIconButtonComponent call({
Icon? icon,
Widget? icon,
ButtonStyle<dynamic>? disabledStyle,
ButtonStyle<dynamic>? normalStyle,
ButtonStyle<dynamic>? hoveredStyle,

View File

@ -20,7 +20,13 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template simple_icon_button_style}
/// Simple icon button style.
///
/// This style is used for the SimpleIconButton widget.
/// {@endtemplate}
class SimpleIconButtonStyle extends ButtonStyle<SimpleIconButtonStyle> {
/// {@macro simple_icon_button_style}
const SimpleIconButtonStyle({
this.dimension,
super.radius,

View File

@ -24,7 +24,7 @@ part 'symbol_button_component.g.dart';
abstract class SymbolButtonComponent extends ButtonComponent
with CopyWithMixin<$SymbolButtonComponentCWProxy> {
const SymbolButtonComponent({
this.mainAxisSize = MainAxisSize.min,
this.mainAxisSize,
this.label,
this.icon,
super.disabledStyle,
@ -57,7 +57,12 @@ abstract class SymbolButtonComponent extends ButtonComponent
@override
SymbolButtonStyle? get selectedStyle;
/// The main axis size of the button.
final MainAxisSize? mainAxisSize;
/// The icon widget of the button.
final Widget? icon;
/// The label widget of the button.
final TextWrapper? label;
}

View File

@ -20,9 +20,15 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/buttons/button_style.dart';
/// {@template symbol_button_style}
/// Symbol button style.
///
/// This style is used for the SymbolButton widget.
/// {@endtemplate}
class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
/// {@macro symbol_button_style}
const SymbolButtonStyle({
this.label,
this.labelStyle,
this.dimension,
super.radius,
super.padding,
@ -46,7 +52,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
}
return a.copyWith(
label: b.label,
labelStyle: b.labelStyle,
dimension: b.dimension,
radius: b.radius,
padding: b.padding,
@ -69,7 +75,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
}
// b.copyWith to return b attributes even if they are not lerped
return b.copyWith(
label: TextStyle.lerp(a.label, b.label, t),
labelStyle: TextStyle.lerp(a.labelStyle, b.labelStyle, t),
dimension: lerpDouble(a.dimension, b.dimension, t),
foregroundColors: MultiColor.lerp(
a.foregroundColors,
@ -93,10 +99,10 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
);
}
/// Label text style
/// labelStyle text style
///
/// Default to `TextTheme.labelLarge`
final TextStyle? label;
final TextStyle? labelStyle;
/// Dimension of this button (as a square)
///
@ -109,7 +115,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
@override
SymbolButtonStyle? copyWith({
TextStyle? label,
TextStyle? labelStyle,
double? dimension,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
@ -120,7 +126,7 @@ class SymbolButtonStyle extends ButtonStyle<SymbolButtonStyle> {
BoxShadow? shadow,
}) =>
SymbolButtonStyle(
label: label ?? this.label,
labelStyle: labelStyle ?? this.labelStyle,
dimension: dimension ?? this.dimension,
radius: radius ?? this.radius,
padding: padding ?? this.padding,

View File

@ -18,44 +18,82 @@ import 'package:flutter/widgets.dart';
import 'package:wyatt_ui_components/src/core/utils/multi_color.dart';
import 'package:wyatt_ui_components/src/domain/entities/component.dart';
/// {@template card_component}
/// Card component.
/// Used to display a card with a background and a shadow.
/// {@endtemplate}
abstract class CardComponent extends Component {
const CardComponent({
this.radius = 12,
this.padding = 25,
this.borderColors,
this.radius,
this.padding,
this.backgroundColors,
this.minSize = const Size(330, 230),
this.maxSize = const Size(330, 530),
this.shadow = const BoxShadow(
blurRadius: 30,
offset: Offset(0, 5),
color: Color.fromRGBO(0, 0, 0, 0.05),
),
this.borderColors,
this.stroke,
this.minSize,
this.maxSize,
this.shadow,
this.titleStyle,
this.subtitleStyle,
this.bodyStyle,
this.background,
super.key,
});
/// Card radius
final double? radius;
///
/// Default to `BorderRadius.all(Radius.circular(12.0))`
final BorderRadiusGeometry? radius;
/// Padding and gaps of this card
final double? padding;
///
/// Default to `Theme.cardTheme.margin`
final EdgeInsetsGeometry? padding;
/// Border gradient color (from left to right)
final MultiColor? borderColors;
/// Card background color
/// Card background gradient colors (from left to right)
///
/// Default to `Theme.cardTheme.color`
final MultiColor? backgroundColors;
/// Minimum size for this card
final Size? minSize;
/// Border colors (from left to right).
///
/// Default to `null`
final MultiColor? borderColors;
/// Maximum size for this card
final Size? maxSize;
/// Stroke of the border
///
/// Default to `null`
final double? stroke;
/// Drop shadow
///
/// Default to `null`
final BoxShadow? shadow;
/// Minimum size of the card
///
/// Default to `const Size(330, double.infinity)`
final Size? minSize;
/// Maximum size of the card
///
/// Default to `const Size(double.infinity, double.infinity)`
final Size? maxSize;
/// Title text style
///
/// Default to `Theme.textTheme.titleLarge`
final TextStyle? titleStyle;
/// Subtitle text style
///
/// Default to `Theme.textTheme.titleMedium`
final TextStyle? subtitleStyle;
/// Body text style
///
/// Default to `Theme.textTheme.bodyMedium`
final TextStyle? bodyStyle;
/// Background of the card
final Widget? background;
}

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
export './card_component.dart';
export './information_card_component.dart';
export './portfolio_card_component.dart';
export './quote_card_component.dart';

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'information_card_component.g.dart';
@ -29,21 +28,40 @@ abstract class InformationCardComponent extends CardComponent
this.title,
this.subtitle,
this.body,
this.axis = Axis.vertical,
this.axis,
super.radius,
super.padding,
super.borderColors,
super.backgroundColors,
super.stroke,
super.minSize,
super.maxSize,
super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background,
super.key,
});
/// Axis of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed.
/// Used in header of the card.
final Axis? axis;
/// Icons of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed
/// on the left side of the card and the rest will be ignored.
final List<Widget>? icons;
/// Title of the card
final TextWrapper? title;
/// Subtitle of the card
final TextWrapper? subtitle;
/// Body of the card
final TextWrapper? body;
}

View File

@ -12,13 +12,17 @@ abstract class $InformationCardComponentCWProxy {
InformationCardComponent subtitle(TextWrapper? subtitle);
InformationCardComponent body(TextWrapper? body);
InformationCardComponent axis(Axis? axis);
InformationCardComponent radius(double? radius);
InformationCardComponent padding(double? padding);
InformationCardComponent radius(BorderRadiusGeometry? radius);
InformationCardComponent padding(EdgeInsetsGeometry? padding);
InformationCardComponent borderColors(MultiColor? borderColors);
InformationCardComponent backgroundColors(MultiColor? backgroundColors);
InformationCardComponent stroke(double? stroke);
InformationCardComponent minSize(Size? minSize);
InformationCardComponent maxSize(Size? maxSize);
InformationCardComponent shadow(BoxShadow? shadow);
InformationCardComponent titleStyle(TextStyle? titleStyle);
InformationCardComponent subtitleStyle(TextStyle? subtitleStyle);
InformationCardComponent bodyStyle(TextStyle? bodyStyle);
InformationCardComponent background(Widget? background);
InformationCardComponent key(Key? key);
InformationCardComponent call({
@ -27,13 +31,17 @@ abstract class $InformationCardComponentCWProxy {
TextWrapper? subtitle,
TextWrapper? body,
Axis? axis,
double? radius,
double? padding,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? borderColors,
MultiColor? backgroundColors,
double? stroke,
Size? minSize,
Size? maxSize,
BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background,
Key? key,
});

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'portfolio_card_component.g.dart';
@ -25,9 +24,9 @@ part 'portfolio_card_component.g.dart';
abstract class PortfolioCardComponent extends CardComponent
with CopyWithMixin<$PortfolioCardComponentCWProxy> {
const PortfolioCardComponent({
this.secondaryBackgroundColors,
this.showImagesOnTop,
this.keyword,
this.showAssetsOnTop,
this.keywords,
this.keywordsBackgroundColors,
this.description,
this.logo,
this.projectName,
@ -38,20 +37,42 @@ abstract class PortfolioCardComponent extends CardComponent
super.padding,
super.borderColors,
super.backgroundColors,
super.stroke,
super.minSize,
super.maxSize,
super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background,
super.key,
});
final bool? showImagesOnTop;
final List<TextWrapper>? keyword;
/// Keywords of the portfolio
final List<TextWrapper>? keywords;
/// Background colors for the keywords badges
final MultiColor? keywordsBackgroundColors;
/// Assets to display
final List<Widget>? assets;
final TextWrapper? description;
/// Whether to show the assets on top or on bottom
/// of the card
final bool? showAssetsOnTop;
/// Logo of the portfolio
final Widget? logo;
/// Description of the portfolio
final TextWrapper? description;
/// Name of the portfolio
final TextWrapper? projectName;
/// Subtitle of the portfolio
final TextWrapper? subtitle;
/// Call to actions of the portfolio
final List<Widget>? ctas;
final Color? secondaryBackgroundColors;
}

View File

@ -7,42 +7,50 @@ part of 'portfolio_card_component.dart';
// **************************************************************************
abstract class $PortfolioCardComponentCWProxy {
PortfolioCardComponent secondaryBackgroundColors(
Color? secondaryBackgroundColors);
PortfolioCardComponent showImagesOnTop(bool? showImagesOnTop);
PortfolioCardComponent keyword(List<TextWrapper>? keyword);
PortfolioCardComponent showAssetsOnTop(bool? showAssetsOnTop);
PortfolioCardComponent keywords(List<TextWrapper>? keywords);
PortfolioCardComponent keywordsBackgroundColors(
MultiColor? keywordsBackgroundColors);
PortfolioCardComponent description(TextWrapper? description);
PortfolioCardComponent logo(Widget? logo);
PortfolioCardComponent projectName(TextWrapper? projectName);
PortfolioCardComponent subtitle(TextWrapper? subtitle);
PortfolioCardComponent ctas(List<Widget>? ctas);
PortfolioCardComponent assets(List<Widget>? assets);
PortfolioCardComponent radius(double? radius);
PortfolioCardComponent padding(double? padding);
PortfolioCardComponent radius(BorderRadiusGeometry? radius);
PortfolioCardComponent padding(EdgeInsetsGeometry? padding);
PortfolioCardComponent borderColors(MultiColor? borderColors);
PortfolioCardComponent backgroundColors(MultiColor? backgroundColors);
PortfolioCardComponent stroke(double? stroke);
PortfolioCardComponent minSize(Size? minSize);
PortfolioCardComponent maxSize(Size? maxSize);
PortfolioCardComponent shadow(BoxShadow? shadow);
PortfolioCardComponent titleStyle(TextStyle? titleStyle);
PortfolioCardComponent subtitleStyle(TextStyle? subtitleStyle);
PortfolioCardComponent bodyStyle(TextStyle? bodyStyle);
PortfolioCardComponent background(Widget? background);
PortfolioCardComponent key(Key? key);
PortfolioCardComponent call({
Color? secondaryBackgroundColors,
bool? showImagesOnTop,
List<TextWrapper>? keyword,
bool? showAssetsOnTop,
List<TextWrapper>? keywords,
MultiColor? keywordsBackgroundColors,
TextWrapper? description,
Widget? logo,
TextWrapper? projectName,
TextWrapper? subtitle,
List<Widget>? ctas,
List<Widget>? assets,
double? radius,
double? padding,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? borderColors,
MultiColor? backgroundColors,
double? stroke,
Size? minSize,
Size? maxSize,
BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background,
Key? key,
});

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'quote_card_component.g.dart';
@ -28,7 +27,6 @@ abstract class QuoteCardComponent extends CardComponent
this.avatar,
this.name,
this.subtitle,
this.gradient,
this.quote,
this.leftQuote,
this.rightQuote,
@ -36,19 +34,32 @@ abstract class QuoteCardComponent extends CardComponent
super.padding,
super.borderColors,
super.backgroundColors,
super.stroke,
super.minSize,
super.maxSize,
super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background,
super.key,
});
/// Avatar of the contact who wrote the quote
final Widget? avatar;
/// Name of the contact who wrote the quote
final TextWrapper? name;
/// Subtitle, usually the date of the quote or the company of the contact
final TextWrapper? subtitle;
/// Quote
final TextWrapper? quote;
final Gradient? gradient;
/// Left quote, usually a double quote
final Widget? leftQuote;
/// Right quote, usually a double quote
final Widget? rightQuote;
}

View File

@ -10,34 +10,40 @@ abstract class $QuoteCardComponentCWProxy {
QuoteCardComponent avatar(Widget? avatar);
QuoteCardComponent name(TextWrapper? name);
QuoteCardComponent subtitle(TextWrapper? subtitle);
QuoteCardComponent gradient(Gradient? gradient);
QuoteCardComponent quote(TextWrapper? quote);
QuoteCardComponent leftQuote(Widget? leftQuote);
QuoteCardComponent rightQuote(Widget? rightQuote);
QuoteCardComponent radius(double? radius);
QuoteCardComponent padding(double? padding);
QuoteCardComponent radius(BorderRadiusGeometry? radius);
QuoteCardComponent padding(EdgeInsetsGeometry? padding);
QuoteCardComponent borderColors(MultiColor? borderColors);
QuoteCardComponent backgroundColors(MultiColor? backgroundColors);
QuoteCardComponent stroke(double? stroke);
QuoteCardComponent minSize(Size? minSize);
QuoteCardComponent maxSize(Size? maxSize);
QuoteCardComponent shadow(BoxShadow? shadow);
QuoteCardComponent titleStyle(TextStyle? titleStyle);
QuoteCardComponent subtitleStyle(TextStyle? subtitleStyle);
QuoteCardComponent bodyStyle(TextStyle? bodyStyle);
QuoteCardComponent background(Widget? background);
QuoteCardComponent key(Key? key);
QuoteCardComponent call({
Widget? avatar,
TextWrapper? name,
TextWrapper? subtitle,
Gradient? gradient,
TextWrapper? quote,
Widget? leftQuote,
Widget? rightQuote,
double? radius,
double? padding,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? borderColors,
MultiColor? backgroundColors,
double? stroke,
Size? minSize,
Size? maxSize,
BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background,
Key? key,
});

View File

@ -16,7 +16,6 @@
import 'package:flutter/widgets.dart';
import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
import 'package:wyatt_ui_components/src/domain/entities/cards/card_component.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
part 'skill_card_component.g.dart';
@ -25,29 +24,56 @@ part 'skill_card_component.g.dart';
abstract class SkillCardComponent extends CardComponent
with CopyWithMixin<$SkillCardComponentCWProxy> {
const SkillCardComponent({
this.icon,
this.gradient,
this.axis,
this.icons,
this.title,
this.subtitle,
this.description,
this.skills,
this.leadingIcon,
this.secondaryBackgroundColors,
this.bulletColors,
this.bulletIcon,
super.radius,
super.padding,
super.borderColors,
super.backgroundColors,
super.stroke,
super.minSize,
super.maxSize,
super.shadow,
super.titleStyle,
super.subtitleStyle,
super.bodyStyle,
super.background,
super.key,
});
final Widget? icon;
final List<Color>? gradient;
/// Axis of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed.
/// Used in header of the card.
final Axis? axis;
/// Icons of the card
///
/// If [axis] is [Axis.horizontal] then only the first icon will be displayed
/// on the left side of the card and the rest will be ignored.
final List<Widget>? icons;
/// Title of the card
final TextWrapper? title;
/// Subtitle of the card
final TextWrapper? subtitle;
/// Description of the card
final TextWrapper? description;
/// Skills to be displayed
final List<TextWrapper>? skills;
final IconData? leadingIcon;
final Color? secondaryBackgroundColors;
/// Gradient of skill icons.
final MultiColor? bulletColors;
/// Icon to be displayed before each skill.
final Widget? bulletIcon;
}

View File

@ -7,38 +7,47 @@ part of 'skill_card_component.dart';
// **************************************************************************
abstract class $SkillCardComponentCWProxy {
SkillCardComponent icon(Widget? icon);
SkillCardComponent gradient(List<Color>? gradient);
SkillCardComponent axis(Axis? axis);
SkillCardComponent icons(List<Widget>? icons);
SkillCardComponent title(TextWrapper? title);
SkillCardComponent subtitle(TextWrapper? subtitle);
SkillCardComponent description(TextWrapper? description);
SkillCardComponent skills(List<TextWrapper>? skills);
SkillCardComponent leadingIcon(IconData? leadingIcon);
SkillCardComponent secondaryBackgroundColors(
Color? secondaryBackgroundColors);
SkillCardComponent radius(double? radius);
SkillCardComponent padding(double? padding);
SkillCardComponent bulletColors(MultiColor? bulletColors);
SkillCardComponent bulletIcon(Widget? bulletIcon);
SkillCardComponent radius(BorderRadiusGeometry? radius);
SkillCardComponent padding(EdgeInsetsGeometry? padding);
SkillCardComponent borderColors(MultiColor? borderColors);
SkillCardComponent backgroundColors(MultiColor? backgroundColors);
SkillCardComponent stroke(double? stroke);
SkillCardComponent minSize(Size? minSize);
SkillCardComponent maxSize(Size? maxSize);
SkillCardComponent shadow(BoxShadow? shadow);
SkillCardComponent titleStyle(TextStyle? titleStyle);
SkillCardComponent subtitleStyle(TextStyle? subtitleStyle);
SkillCardComponent bodyStyle(TextStyle? bodyStyle);
SkillCardComponent background(Widget? background);
SkillCardComponent key(Key? key);
SkillCardComponent call({
Widget? icon,
List<Color>? gradient,
Axis? axis,
List<Widget>? icons,
TextWrapper? title,
TextWrapper? subtitle,
TextWrapper? description,
List<TextWrapper>? skills,
IconData? leadingIcon,
Color? secondaryBackgroundColors,
double? radius,
double? padding,
MultiColor? bulletColors,
Widget? bulletIcon,
BorderRadiusGeometry? radius,
EdgeInsetsGeometry? padding,
MultiColor? borderColors,
MultiColor? backgroundColors,
double? stroke,
Size? minSize,
Size? maxSize,
BoxShadow? shadow,
TextStyle? titleStyle,
TextStyle? subtitleStyle,
TextStyle? bodyStyle,
Widget? background,
Key? key,
});

View File

@ -16,17 +16,43 @@
import 'package:flutter/widgets.dart';
/// {@template rich_text_style_parameter}
/// Rich text style parameter used to parse the text.
/// {@endtemplate}
class RichTextStyleParameter {
/// {@macro rich_text_style_parameter}
const RichTextStyleParameter(
this.defaultStyle,
this.definedStyle,
this.styleName,
);
/// Default style to use if no style is defined.
final TextStyle? defaultStyle;
/// Map of defined styles. The key is the style name.
///
/// Example:
/// ```dart
/// definedStyle: {
/// 'bold': TextStyle(fontWeight: FontWeight.bold),
/// 'italic': TextStyle(fontStyle: FontStyle.italic),
/// }
/// ```
/// then, the text `This is <bold>bold</bold> and <italic>italic</italic>`
/// will be parsed and the word `bold` will be bold and the word `italic`
/// will be italic in the RichText widget.
final Map<String, TextStyle> definedStyle;
/// Style name to use for the text.
/// If no style is defined and no default style is defined, the text will be
/// displayed with the default style of the RichText widget.
final String? styleName;
/// Returns the style to use for the given style name.
/// If no style is defined for the given style name, the default style is
/// returned. If no default style is defined, the default style of the
/// RichText widget is returned.
TextStyle get style {
if (definedStyle.containsKey(styleName)) {
return definedStyle[styleName]!;
@ -46,11 +72,47 @@ class RichTextStyleParameter {
);
}
/// {@template rich_text_node}
/// Rich text node.
///
/// Used as a node in the tree of the RichText widget.
/// {@endtemplate}
class RichTextNode {
RichTextNode(this.nodes);
/// {@macro rich_text_node}
const RichTextNode(this.nodes);
/// List of nodes.
final List<RichTextNode> nodes;
/// Returns a RichTextNode from the given content.
/// If the content contains a match with the given regex, the content is
/// split into multiple nodes. If the content does not contain a match with
/// the given regex, a leaf node is returned.
///
/// Example:
/// ```dart
/// RichTextNode.from(
/// 'This is <bold>bold</bold> and <italic>italic</italic>',
/// RegExp(r'<(\w+)>(.*?)</\1>'),
/// RichTextStyleParameter(
/// TextStyle(fontWeight: FontWeight.w400),
/// {'bold': TextStyle(fontWeight: FontWeight.bold)},
/// {'italic': TextStyle(fontStyle: FontStyle.italic)},
/// ),
/// );
/// ```
/// will return a RichTextNode with 5 nodes:
/// - `This is `
/// - `<bold>bold</bold>`
/// - ` and `
/// - `<italic>italic</italic>`
/// - `` (empty string)
///
/// The first node is a leaf node with the default style of the RichText
/// widget. The second node is a node with bold paramters. The third node is
/// a leaf node with the default style of the RichText widget.
/// The fourth node is a node italic parameters. The fifth node is a
/// leaf node with the default style of the RichText widget.
static RichTextNode from(
String content,
RegExp regex,
@ -88,6 +150,11 @@ class RichTextNode {
}
}
/// Returns an InlineSpan from the given RichTextNode.
/// The given RichTextParser is used to convert the RichTextNode to an
/// InlineSpan.
///
/// InlineSpan is used to display text in the RichText widget.
InlineSpan toInlineSpan(RichTextParser parser) {
final children = <InlineSpan>[];
for (final node in nodes) {
@ -97,10 +164,17 @@ class RichTextNode {
}
}
/// {@template rich_text_leaf}
/// Rich text leaf.
/// {@endtemplate}
class RichTextLeaf extends RichTextNode {
RichTextLeaf(this.style, this.content) : super([]);
/// {@macro rich_text_leaf}
const RichTextLeaf(this.style, this.content) : super(const []);
/// Style to use for the text.
final TextStyle style;
/// Text content.
final String content;
@override
@ -108,13 +182,26 @@ class RichTextLeaf extends RichTextNode {
parser.nodeBuilder.call(content, style);
}
/// {@template rich_text_parser}
/// Rich text parser.
/// {@endtemplate}
class RichTextParser {
/// {@macro rich_text_parser}
const RichTextParser({required this.nodeBuilder});
/// Returns a default RichTextParser.
/// The default RichTextParser uses the given nodeBuilder to convert a
/// RichTextNode to an InlineSpan.
///
/// By default, the nodeBuilder returns a TextSpan with the given content
/// and style.
factory RichTextParser.defaultBuilder() => RichTextParser(
nodeBuilder: (content, style) => TextSpan(
text: content,
style: style,
),
);
/// Converts the given RichTextNode to an InlineSpan.
final InlineSpan Function(String content, TextStyle style) nodeBuilder;
}

View File

@ -39,8 +39,8 @@ abstract class TextInputComponent extends Component
this.hint,
this.normalStyle,
this.focusedStyle,
this.errorStyle,
this.disableStyle,
this.invalidStyle,
this.disabledStyle,
this.controller,
this.focusNode,
this.keyboardType,
@ -156,10 +156,11 @@ abstract class TextInputComponent extends Component
final bool Function(String)? validator;
final String? Function(String)? onError;
// Styles
final TextInputStyle? normalStyle;
final TextInputStyle? focusedStyle;
final TextInputStyle? errorStyle;
final TextInputStyle? disableStyle;
final TextInputStyle? invalidStyle;
final TextInputStyle? disabledStyle;
final bool? expand;

View File

@ -18,8 +18,8 @@ abstract class $TextInputComponentCWProxy {
TextInputComponent hint(TextWrapper? hint);
TextInputComponent normalStyle(TextInputStyle? normalStyle);
TextInputComponent focusedStyle(TextInputStyle? focusedStyle);
TextInputComponent errorStyle(TextInputStyle? errorStyle);
TextInputComponent disableStyle(TextInputStyle? disableStyle);
TextInputComponent invalidStyle(TextInputStyle? invalidStyle);
TextInputComponent disabledStyle(TextInputStyle? disabledStyle);
TextInputComponent controller(TextEditingController? controller);
TextInputComponent focusNode(FocusNode? focusNode);
TextInputComponent keyboardType(TextInputType? keyboardType);
@ -96,8 +96,8 @@ abstract class $TextInputComponentCWProxy {
TextWrapper? hint,
TextInputStyle? normalStyle,
TextInputStyle? focusedStyle,
TextInputStyle? errorStyle,
TextInputStyle? disableStyle,
TextInputStyle? invalidStyle,
TextInputStyle? disabledStyle,
TextEditingController? controller,
FocusNode? focusNode,
TextInputType? keyboardType,

View File

@ -23,7 +23,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
this.hintStyle,
this.backgroundColors,
this.borderColors,
this.boxShadow,
this.shadow,
this.radius,
this.inputStyle,
this.iconColor,
@ -44,7 +44,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
final MultiColor? backgroundColors;
final Color? borderColors;
final BoxShadow? boxShadow;
final BoxShadow? shadow;
final BorderRadiusGeometry? radius;
final TextStyle? inputStyle;
@ -60,7 +60,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
hintStyle: b.hintStyle,
backgroundColors: b.backgroundColors,
borderColors: b.borderColors,
boxShadow: b.boxShadow,
shadow: b.shadow,
radius: b.radius,
inputStyle: b.inputStyle,
iconColor: b.iconColor,
@ -87,7 +87,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
MultiColor.lerp(a.backgroundColors, b.backgroundColors, t),
radius: BorderRadiusGeometry.lerp(a.radius, b.radius, t),
borderColors: Color.lerp(a.borderColors, b.borderColors, t),
boxShadow: BoxShadow.lerp(a.boxShadow, b.boxShadow, t),
shadow: BoxShadow.lerp(a.shadow, b.shadow, t),
inputStyle: TextStyle.lerp(a.inputStyle, b.inputStyle, t),
prefixStyle: TextStyle.lerp(a.prefixStyle, b.prefixStyle, t),
suffixStyle: TextStyle.lerp(a.suffixStyle, b.suffixStyle, t),
@ -107,7 +107,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
TextStyle? hintStyle,
MultiColor? backgroundColors,
Color? borderColors,
BoxShadow? boxShadow,
BoxShadow? shadow,
BorderRadiusGeometry? radius,
TextStyle? inputStyle,
Color? iconColor,
@ -122,7 +122,7 @@ class TextInputStyle extends ThemeStyle<TextInputStyle> {
backgroundColors: backgroundColors ?? this.backgroundColors,
radius: radius ?? this.radius,
borderColors: borderColors ?? this.borderColors,
boxShadow: boxShadow ?? this.boxShadow,
shadow: shadow ?? this.shadow,
inputStyle: inputStyle ?? this.inputStyle,
prefixStyle: prefixStyle ?? this.prefixStyle,
suffixStyle: suffixStyle ?? this.suffixStyle,

View File

@ -0,0 +1,72 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
const _titlesLineSpacing = 5.0;
class PortfolioCardTitles extends StatelessWidget {
const PortfolioCardTitles({
this.axis,
this.title,
this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
});
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: axis == Axis.horizontal
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [
if (title != null) ...[
CardText.fromWrapper(
title!,
style: titleStyle,
textType: TextType.title,
),
],
if (subtitle != null) ...[
const Gap(_titlesLineSpacing),
CardText.fromWrapper(
subtitle!,
style: subtitleStyle,
textType: TextType.subtitle,
),
],
],
);
}

View File

@ -0,0 +1,71 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_titles.dart';
const _avatarAndTitlesSpacing = 25.0;
class SkillCardHorizontalHeader extends StatelessWidget {
const SkillCardHorizontalHeader({
this.icons,
this.axis,
this.title,
this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
});
/// The icons of the card header.
final List<Widget>? icons;
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override
Widget build(BuildContext context) => Row(
children: [
if (icons?.first != null) ...[
icons!.first,
const Gap(_avatarAndTitlesSpacing),
],
Expanded(
child: SkillCardTitles(
axis: axis,
title: title,
subtitle: subtitle,
titleStyle: titleStyle,
subtitleStyle: subtitleStyle,
),
),
],
);
}

View File

@ -0,0 +1,43 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
const _iconSpacing = 25.0;
class SkillCardIcons extends StatelessWidget {
const SkillCardIcons({
super.key,
this.icons,
});
/// The icons of the card header.
final List<Widget>? icons;
@override
Widget build(BuildContext context) {
final result = <Widget>[];
for (final widget in icons ?? List<Widget>.empty()) {
result.addAll([widget, const Gap(_iconSpacing)]);
}
result.removeLast();
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: result,
);
}
}

View File

@ -0,0 +1,72 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
const _titlesLineSpacing = 5.0;
class SkillCardTitles extends StatelessWidget {
const SkillCardTitles({
this.axis,
this.title,
this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
});
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: axis == Axis.horizontal
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [
if (title != null) ...[
CardText.fromWrapper(
title!,
style: titleStyle,
textType: TextType.title,
),
],
if (subtitle != null) ...[
const Gap(_titlesLineSpacing),
CardText.fromWrapper(
subtitle!,
style: subtitleStyle,
textType: TextType.subtitle,
),
],
],
);
}

View File

@ -0,0 +1,72 @@
// Copyright (C) 2023 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_components/wyatt_ui_components.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_icons.dart';
import 'package:wyatt_ui_kit/src/components/cards/skill_card/widgets/skill_card_titles.dart';
const _avatarAndTitlesSpacing = 25.0;
class SkillCardVerticalHeader extends StatelessWidget {
const SkillCardVerticalHeader({
this.icons,
this.axis,
this.title,
this.subtitle,
this.titleStyle,
this.subtitleStyle,
super.key,
});
/// The icons of the card header.
final List<Widget>? icons;
/// The axis of the card header.
final Axis? axis;
/// The title of the card.
final TextWrapper? title;
/// The subtitle of the card.
final TextWrapper? subtitle;
/// Styles the title of the card.
final TextStyle? titleStyle;
/// Styles the subtitle of the card.
final TextStyle? subtitleStyle;
@override
Widget build(BuildContext context) => Column(
children: [
if (icons != null && icons!.isNotEmpty) ...[
SkillCardIcons(
icons: icons,
),
const Gap(_avatarAndTitlesSpacing),
],
SkillCardTitles(
axis: axis,
title: title,
subtitle: subtitle,
titleStyle: titleStyle,
subtitleStyle: subtitleStyle,
),
],
);
}