diff --git a/packages/wyatt_ui_components/lib/src/core/utils/text_wrapper.dart b/packages/wyatt_ui_components/lib/src/core/utils/text_wrapper.dart
index bed9dd99..1a1eac95 100644
--- a/packages/wyatt_ui_components/lib/src/core/utils/text_wrapper.dart
+++ b/packages/wyatt_ui_components/lib/src/core/utils/text_wrapper.dart
@@ -121,4 +121,11 @@ class TextWrapper {
/// that, the selection color defaults to [DefaultSelectionStyle.defaultColor]
/// (semi-transparent grey).
final Color? selectionColor;
+
+ @override
+ String toString() => 'TextWrapper(data: $data, style: $style, '
+ 'gradientColors: $gradientColors, textAlign: $textAlign, '
+ 'textDirection: $textDirection, softWrap: $softWrap, '
+ 'overflow: $overflow, maxLines: $maxLines, '
+ 'selectionColor: $selectionColor)';
}
diff --git a/packages/wyatt_ui_components/lib/src/data/theme_extensions/button_theme_extension/symbol_button_theme_extension_default.dart b/packages/wyatt_ui_components/lib/src/data/theme_extensions/button_theme_extension/symbol_button_theme_extension_default.dart
index 4a781f13..3a36930f 100644
--- a/packages/wyatt_ui_components/lib/src/data/theme_extensions/button_theme_extension/symbol_button_theme_extension_default.dart
+++ b/packages/wyatt_ui_components/lib/src/data/theme_extensions/button_theme_extension/symbol_button_theme_extension_default.dart
@@ -40,8 +40,7 @@ class SymbolButtonThemeExtensionDefault extends SymbolButtonThemeExtension {
final textColor = MultiColor.single(theme.textTheme.bodyMedium?.color);
final style = SymbolButtonStyle(
- labelStyle:
- theme.textTheme.labelLarge?.copyWith(color: textColor.color),
+ labelStyle: theme.textTheme.labelLarge?.copyWith(color: textColor.color),
dimension: theme.buttonTheme.height * 1.5,
radius: (theme.buttonTheme.shape is RoundedRectangleBorder)
? (theme.buttonTheme.shape as RoundedRectangleBorder).borderRadius
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/cards.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/cards.dart
index a7840347..6a1cc1a5 100644
--- a/packages/wyatt_ui_components/lib/src/domain/entities/cards/cards.dart
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/cards.dart
@@ -17,5 +17,6 @@
export './card_component.dart';
export './information_card_component.dart';
export './portfolio_card_component.dart';
+export './pricing_card_component.dart';
export './quote_card_component.dart';
export './skill_card_component.dart';
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/pricing_card_component.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/pricing_card_component.dart
new file mode 100644
index 00000000..15961dd0
--- /dev/null
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/pricing_card_component.dart
@@ -0,0 +1,99 @@
+// 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 .
+
+import 'package:flutter/widgets.dart';
+import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
+import 'package:wyatt_ui_components/wyatt_ui_components.dart';
+
+part 'pricing_card_component.g.dart';
+
+class PricingLine {
+ const PricingLine({
+ required this.data,
+ this.icon,
+ });
+
+ final TextWrapper data;
+ final Widget? icon;
+
+ @override
+ String toString() => 'PricingLine(data: $data, icon: $icon)';
+}
+
+class Pricing {
+ const Pricing({
+ required this.price,
+ this.period,
+ this.hasAsterisk = false,
+ });
+
+ final TextWrapper price;
+ final TextWrapper? period;
+
+ /// If [hasAsterisk] is true then the price will be displayed with
+ /// an asterisk to emphasize that it is a special price.
+ final bool hasAsterisk;
+}
+
+@ComponentProxyExtension()
+abstract class PricingCardComponent extends CardComponent
+ with CopyWithMixin<$PricingCardComponentCWProxy> {
+ const PricingCardComponent({
+ this.axis,
+ this.title,
+ this.pricing,
+ this.description,
+ this.features,
+ this.cta,
+ 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;
+
+ /// Title of the card
+ ///
+ /// If [axis] is [Axis.vertical] then icon of the title will be displayed
+ /// above the title.
+ final PricingLine? title;
+
+ /// Pricing of the card
+ final Pricing? pricing;
+
+ /// Description of the card
+ final TextWrapper? description;
+
+ /// List of special features of the card
+ final List? features;
+
+ /// CTA of the card
+ final Widget? cta;
+}
diff --git a/packages/wyatt_ui_components/lib/src/domain/entities/cards/pricing_card_component.g.dart b/packages/wyatt_ui_components/lib/src/domain/entities/cards/pricing_card_component.g.dart
new file mode 100644
index 00000000..3f39a445
--- /dev/null
+++ b/packages/wyatt_ui_components/lib/src/domain/entities/cards/pricing_card_component.g.dart
@@ -0,0 +1,50 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'pricing_card_component.dart';
+
+// **************************************************************************
+// ComponentProxyGenerator
+// **************************************************************************
+
+abstract class $PricingCardComponentCWProxy {
+ PricingCardComponent axis(Axis? axis);
+ PricingCardComponent title(PricingLine? title);
+ PricingCardComponent pricing(Pricing? pricing);
+ PricingCardComponent description(TextWrapper? description);
+ PricingCardComponent features(List? features);
+ PricingCardComponent cta(Widget? cta);
+ PricingCardComponent radius(BorderRadiusGeometry? radius);
+ PricingCardComponent padding(EdgeInsetsGeometry? padding);
+ PricingCardComponent borderColors(MultiColor? borderColors);
+ PricingCardComponent backgroundColors(MultiColor? backgroundColors);
+ PricingCardComponent stroke(double? stroke);
+ PricingCardComponent minSize(Size? minSize);
+ PricingCardComponent maxSize(Size? maxSize);
+ PricingCardComponent shadow(BoxShadow? shadow);
+ PricingCardComponent titleStyle(TextStyle? titleStyle);
+ PricingCardComponent subtitleStyle(TextStyle? subtitleStyle);
+ PricingCardComponent bodyStyle(TextStyle? bodyStyle);
+ PricingCardComponent background(Widget? background);
+ PricingCardComponent key(Key? key);
+ PricingCardComponent call({
+ Axis? axis,
+ PricingLine? title,
+ Pricing? pricing,
+ TextWrapper? description,
+ List? features,
+ Widget? cta,
+ 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,
+ });
+}
diff --git a/packages/wyatt_ui_kit/example/lib/cards/cards.dart b/packages/wyatt_ui_kit/example/lib/cards/cards.dart
index 9037385f..5f685a09 100644
--- a/packages/wyatt_ui_kit/example/lib/cards/cards.dart
+++ b/packages/wyatt_ui_kit/example/lib/cards/cards.dart
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:wyatt_ui_kit_example/cards/information_card/information_cards.dart';
import 'package:wyatt_ui_kit_example/cards/portfolio_card/portfolio_cards.dart';
+import 'package:wyatt_ui_kit_example/cards/pricing_card/pricing_cards.dart';
import 'package:wyatt_ui_kit_example/cards/quote_card/quote_cards.dart';
import 'package:wyatt_ui_kit_example/cards/skill_card/skill_cards.dart';
import 'package:wyatt_ui_kit_example/demo_page.dart';
@@ -24,6 +25,8 @@ class Cards extends DemoPage {
),
),
const Gap(20),
+ const PricingCards(),
+ const Gap(20),
const InformationCards(),
const Gap(20),
const PortfolioCards(),
diff --git a/packages/wyatt_ui_kit/example/lib/cards/pricing_card/pricing_cards.dart b/packages/wyatt_ui_kit/example/lib/cards/pricing_card/pricing_cards.dart
new file mode 100644
index 00000000..b7e52425
--- /dev/null
+++ b/packages/wyatt_ui_kit/example/lib/cards/pricing_card/pricing_cards.dart
@@ -0,0 +1,148 @@
+// 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 .
+
+import 'package:flutter/material.dart';
+import 'package:gap/gap.dart';
+import 'package:wyatt_ui_components/wyatt_ui_components.dart';
+import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
+import 'package:wyatt_ui_kit_example/theme/constants.dart';
+
+class PricingCards extends StatelessWidget {
+ const PricingCards({super.key});
+
+ @override
+ Widget build(BuildContext context) => Column(
+ children: [
+ Text(
+ 'Pricing Cards',
+ style: Theme.of(context).textTheme.titleMedium,
+ ),
+ const Gap(20),
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ PricingCard(
+ title: const PricingLine(
+ data: TextWrapper('Lorem Ipsum'),
+ icon: Icon(
+ Icons.ac_unit_rounded,
+ ),
+ ),
+ pricing: const Pricing(
+ price: TextWrapper('450€'),
+ period: TextWrapper('/ jour'),
+ hasAsterisk: true,
+ ),
+ description: const TextWrapper(
+ 'Cupidatat reprehenderit aliqua eiusmod Lorem. '
+ 'Qui ipsum id ea ea nulla labore aute ullamco aute '
+ 'quis elit ut amet velit. Incididunt fugiat proident '
+ 'proident deserunt tempor Lorem cillum qui do '
+ 'ullamco Lorem magna ipsum. Ullamco cupidatat velit '),
+ features: const [
+ PricingLine(
+ icon: Icon(
+ Icons.ac_unit_rounded,
+ ),
+ data: TextWrapper(
+ 'Nulla labore aliquip dolor aliqua elit anim quis non officia laboris ad.',
+ ),
+ ),
+ PricingLine(
+ icon: Icon(
+ Icons.ac_unit_rounded,
+ ),
+ data: TextWrapper(
+ 'Eu pariatur non et sint minim aute pariatur amet officia.',
+ ),
+ ),
+ ],
+ cta: context.components.flatButtonComponent.call(
+ label: const TextWrapper(
+ 'Contactez-nous',
+ style: TextStyle(color: Colors.white),
+ ),
+ normalStyle: FlatButtonThemeExtensionImpl.dark(
+ theme: Theme.of(context),
+ ).normalStyle?.copyWith(
+ backgroundColors:
+ const MultiColor(Constants.blueBtnGradient),
+ borderColors:
+ const MultiColor(Constants.blueBtnGradient),
+ ),
+ ),
+ ),
+ const Gap(20),
+ PricingCard(
+ title: const PricingLine(
+ data: TextWrapper('Lorem Ipsum'),
+ icon: Icon(
+ Icons.ac_unit_rounded,
+ ),
+ ),
+ pricing: const Pricing(
+ price: TextWrapper('350€'),
+ period: TextWrapper('/ jour'),
+ hasAsterisk: true,
+ ),
+ features: const [
+ PricingLine(
+ icon: Icon(
+ Icons.ac_unit_rounded,
+ ),
+ data: TextWrapper(
+ 'Nulla labore aliquip dolor aliqua elit anim quis non officia laboris ad.',
+ ),
+ ),
+ PricingLine(
+ icon: Icon(
+ Icons.ac_unit_rounded,
+ ),
+ data: TextWrapper(
+ 'Eu pariatur non et sint minim aute pariatur amet officia.',
+ ),
+ ),
+ PricingLine(
+ icon: Icon(
+ Icons.ac_unit_rounded,
+ ),
+ data: TextWrapper(
+ 'Nulla labore aliquip dolor aliqua elit anim quis non officia laboris ad.',
+ ),
+ ),
+ ],
+ cta: context.components.flatButtonComponent.call(
+ label: const TextWrapper(
+ 'Contactez-nous',
+ style: TextStyle(color: Colors.white),
+ ),
+ normalStyle: FlatButtonThemeExtensionImpl.dark(
+ theme: Theme.of(context),
+ ).normalStyle?.copyWith(
+ backgroundColors:
+ const MultiColor(Constants.purpleGradient),
+ borderColors:
+ const MultiColor(Constants.purpleGradient),
+ ),
+ ),
+ ),
+ ],
+ ),
+ const Gap(20),
+ ],
+ );
+}
diff --git a/packages/wyatt_ui_kit/example/lib/rich_text_builders/rich_text_builders.dart b/packages/wyatt_ui_kit/example/lib/rich_text_builders/rich_text_builders.dart
index ef82c3f5..e85bfcfc 100644
--- a/packages/wyatt_ui_kit/example/lib/rich_text_builders/rich_text_builders.dart
+++ b/packages/wyatt_ui_kit/example/lib/rich_text_builders/rich_text_builders.dart
@@ -27,7 +27,7 @@ class RichTextBuilders extends DemoPage {
@override
Widget build(BuildContext context) => SelectionArea(
- child: ListView(
+ child: ListView(
cacheExtent: 1000,
children: [
const Gap(20),
@@ -61,5 +61,5 @@ class RichTextBuilders extends DemoPage {
const Gap(20),
],
),
- );
+ );
}
diff --git a/packages/wyatt_ui_kit/example/lib/theme/constants.dart b/packages/wyatt_ui_kit/example/lib/theme/constants.dart
index 33152394..bf42912b 100644
--- a/packages/wyatt_ui_kit/example/lib/theme/constants.dart
+++ b/packages/wyatt_ui_kit/example/lib/theme/constants.dart
@@ -25,6 +25,9 @@ abstract class Constants {
static const blue3 = Color(0xFF1A84F7);
static const blue4 = Color(0xFF1344E4);
+ static const blue1Btn = Color(0xFF3C97FB);
+ static const blue2Btn = Color(0xFF446DF4);
+
static const grey1 = Color(0xFF60656A);
static const grey2 = Color(0xFF383C40);
@@ -37,10 +40,15 @@ abstract class Constants {
static const red1 = Color(0xFFFB5E3C);
static const red2 = Color(0xFFF44464);
+ static const purple1 = Color(0xFFB79EFF);
+ static const purple2 = Color(0xFF6865F2);
+
static const blueGradient = [blue1, blue2];
+ static const blueBtnGradient = [blue1Btn, blue2Btn];
static const blueDarkGradient = [blue3, blue4];
static const greyGradient = [grey1, grey2];
static const greyDarkGradient = [grey3, grey4];
static const greenGradient = [green1, green2];
static const redGradient = [red1, red2];
+ static const purpleGradient = [purple1, purple2];
}
diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/cards.dart b/packages/wyatt_ui_kit/lib/src/components/cards/cards.dart
index cfd0f523..2b5be8f3 100644
--- a/packages/wyatt_ui_kit/lib/src/components/cards/cards.dart
+++ b/packages/wyatt_ui_kit/lib/src/components/cards/cards.dart
@@ -16,5 +16,6 @@
export './information_card/information_card.dart';
export './portfolio_card/portfolio_card.dart';
+export './pricing_card/pricing_card.dart';
export './quote_card/quote_card.dart';
export './skill_card/skill_card.dart';
diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/pricing_card.dart b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/pricing_card.dart
new file mode 100644
index 00000000..46719484
--- /dev/null
+++ b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/pricing_card.dart
@@ -0,0 +1,136 @@
+// 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 .
+
+import 'package:flutter/material.dart';
+import 'package:gap/gap.dart';
+import 'package:wyatt_component_copy_with_extension/wyatt_component_copy_with_extension.dart';
+import 'package:wyatt_ui_components/wyatt_ui_components.dart';
+import 'package:wyatt_ui_kit/src/components/cards/pricing_card/widgets/pricing_card_features.dart';
+import 'package:wyatt_ui_kit/src/components/cards/pricing_card/widgets/pricing_card_titles.dart';
+import 'package:wyatt_ui_kit/src/components/cards/widgets/card_text.dart';
+import 'package:wyatt_ui_kit/src/components/cards/widgets/card_wrapper.dart';
+import 'package:wyatt_ui_kit/src/core/design_system/colors.dart';
+import 'package:wyatt_ui_kit/wyatt_ui_kit.dart';
+
+part 'pricing_card.g.dart';
+
+const _bodyTopSpacing = 25.0;
+
+@ComponentCopyWithExtension()
+class PricingCard extends PricingCardComponent with $PricingCardCWMixin {
+ const PricingCard({
+ super.axis,
+ super.title,
+ super.pricing,
+ super.description,
+ super.features,
+ super.cta,
+ 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,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ final themeTitleStyle = ThemeHelper.maybeGetElement(
+ [
+ titleStyle,
+ Theme.of(context).extension()?.titleStyle,
+ CardThemeExtensionDefault.from(Theme.of(context)).titleStyle,
+ ],
+ );
+
+ final themePricingStyle = ThemeHelper.maybeGetElement(
+ [
+ pricing?.price.style,
+ context.textTheme.bodyMedium
+ ?.copyWith(fontSize: 50, fontWeight: FontWeight.bold),
+ ],
+ );
+
+ final themePeriodStyle = ThemeHelper.maybeGetElement(
+ [
+ subtitleStyle,
+ context.textTheme.bodyMedium?.copyWith(
+ fontSize: 20,
+ fontWeight: FontWeight.w600,
+ color: WyattColors.gray1,
+ ),
+ ],
+ );
+
+ final themeBodyStyle = ThemeHelper.maybeGetElement(
+ [
+ bodyStyle,
+ Theme.of(context).extension()?.bodyStyle,
+ CardThemeExtensionDefault.from(Theme.of(context)).bodyStyle,
+ ],
+ );
+
+ return CardWrapper(
+ background: background,
+ padding: padding,
+ radius: radius,
+ backgroundColors: backgroundColors,
+ borderColors: borderColors,
+ shadow: shadow,
+ stroke: stroke,
+ maxSize: maxSize,
+ minSize: minSize,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ PricingCardTitles(
+ axis: axis,
+ title: title,
+ pricing: pricing,
+ titleStyle: themeTitleStyle,
+ pricingStyle: themePricingStyle,
+ periodStyle: themePeriodStyle,
+ ),
+ const Gap(_bodyTopSpacing),
+ if (description != null) ...[
+ CardText.fromWrapper(
+ description!,
+ style: themeBodyStyle,
+ ),
+ const Gap(_bodyTopSpacing),
+ ],
+ if (features != null) ...[
+ PricingCardFeatures(
+ features: features,
+ bodyStyle: themeBodyStyle,
+ ),
+ const Gap(_bodyTopSpacing),
+ ],
+ if (cta != null) ...[
+ SelectionContainer.disabled(child: cta!),
+ ],
+ ],
+ ),
+ );
+ }
+}
diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/pricing_card.g.dart b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/pricing_card.g.dart
new file mode 100644
index 00000000..25c82ed3
--- /dev/null
+++ b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/pricing_card.g.dart
@@ -0,0 +1,102 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'pricing_card.dart';
+
+// **************************************************************************
+// ComponentCopyWithGenerator
+// **************************************************************************
+
+class $PricingCardCWProxyImpl implements $PricingCardComponentCWProxy {
+ const $PricingCardCWProxyImpl(this._value);
+ final PricingCard _value;
+ @override
+ PricingCard axis(Axis? axis) => this(axis: axis);
+ @override
+ PricingCard title(PricingLine? title) => this(title: title);
+ @override
+ PricingCard pricing(Pricing? pricing) => this(pricing: pricing);
+ @override
+ PricingCard description(TextWrapper? description) =>
+ this(description: description);
+ @override
+ PricingCard features(List? features) => this(features: features);
+ @override
+ PricingCard cta(Widget? cta) => this(cta: cta);
+ @override
+ PricingCard radius(BorderRadiusGeometry? radius) => this(radius: radius);
+ @override
+ PricingCard padding(EdgeInsetsGeometry? padding) => this(padding: padding);
+ @override
+ PricingCard borderColors(MultiColor? borderColors) =>
+ this(borderColors: borderColors);
+ @override
+ PricingCard backgroundColors(MultiColor? backgroundColors) =>
+ this(backgroundColors: backgroundColors);
+ @override
+ PricingCard stroke(double? stroke) => this(stroke: stroke);
+ @override
+ PricingCard minSize(Size? minSize) => this(minSize: minSize);
+ @override
+ PricingCard maxSize(Size? maxSize) => this(maxSize: maxSize);
+ @override
+ PricingCard shadow(BoxShadow? shadow) => this(shadow: shadow);
+ @override
+ PricingCard titleStyle(TextStyle? titleStyle) => this(titleStyle: titleStyle);
+ @override
+ PricingCard subtitleStyle(TextStyle? subtitleStyle) =>
+ this(subtitleStyle: subtitleStyle);
+ @override
+ PricingCard bodyStyle(TextStyle? bodyStyle) => this(bodyStyle: bodyStyle);
+ @override
+ PricingCard background(Widget? background) => this(background: background);
+ @override
+ PricingCard key(Key? key) => this(key: key);
+ @override
+ PricingCard call({
+ Axis? axis,
+ PricingLine? title,
+ Pricing? pricing,
+ TextWrapper? description,
+ List? features,
+ Widget? cta,
+ 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,
+ }) =>
+ PricingCard(
+ axis: axis ?? _value.axis,
+ title: title ?? _value.title,
+ pricing: pricing ?? _value.pricing,
+ description: description ?? _value.description,
+ features: features ?? _value.features,
+ cta: cta ?? _value.cta,
+ radius: radius ?? _value.radius,
+ padding: padding ?? _value.padding,
+ borderColors: borderColors ?? _value.borderColors,
+ backgroundColors: backgroundColors ?? _value.backgroundColors,
+ stroke: stroke ?? _value.stroke,
+ minSize: minSize ?? _value.minSize,
+ maxSize: maxSize ?? _value.maxSize,
+ shadow: shadow ?? _value.shadow,
+ titleStyle: titleStyle ?? _value.titleStyle,
+ subtitleStyle: subtitleStyle ?? _value.subtitleStyle,
+ bodyStyle: bodyStyle ?? _value.bodyStyle,
+ background: background ?? _value.background,
+ key: key ?? _value.key,
+ );
+}
+
+mixin $PricingCardCWMixin on Component {
+ $PricingCardComponentCWProxy get copyWith =>
+ $PricingCardCWProxyImpl(this as PricingCard);
+}
diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/widgets/pricing_card_features.dart b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/widgets/pricing_card_features.dart
new file mode 100644
index 00000000..390d8bfb
--- /dev/null
+++ b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/widgets/pricing_card_features.dart
@@ -0,0 +1,61 @@
+// 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 .
+
+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';
+
+class PricingCardFeatures extends StatelessWidget {
+ const PricingCardFeatures({
+ super.key,
+ this.features,
+ this.bodyStyle,
+ });
+
+ /// List of special features of the card
+ final List? features;
+
+ /// Body style of the card.
+ final TextStyle? bodyStyle;
+
+ @override
+ Widget build(BuildContext context) => Column(
+ children: features!
+ .map(
+ (feature) => Padding(
+ padding: EdgeInsets.only(
+ top: features?.indexOf(feature) == 0 ? 0 : 10,
+ ),
+ child: Row(
+ children: [
+ if (feature.icon != null) ...[
+ feature.icon!,
+ ],
+ const Gap(10),
+ Expanded(
+ child: CardText.fromWrapper(
+ feature.data,
+ style: bodyStyle,
+ ),
+ ),
+ ],
+ ),
+ ),
+ )
+ .toList(),
+ );
+}
diff --git a/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/widgets/pricing_card_titles.dart b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/widgets/pricing_card_titles.dart
new file mode 100644
index 00000000..4ecd2ac2
--- /dev/null
+++ b/packages/wyatt_ui_kit/lib/src/components/cards/pricing_card/widgets/pricing_card_titles.dart
@@ -0,0 +1,139 @@
+// 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 .
+
+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;
+const _bodyTopSpacing = 25.0;
+
+class PricingCardTitles extends StatelessWidget {
+ const PricingCardTitles({
+ this.axis,
+ this.title,
+ this.pricing,
+ this.titleStyle,
+ this.pricingStyle,
+ this.periodStyle,
+ super.key,
+ });
+
+ /// The axis of the card header.
+ final Axis? axis;
+
+ /// Title of the card
+ ///
+ /// If [axis] is [Axis.vertical] then icon of the title will be displayed
+ /// above the title.
+ final PricingLine? title;
+
+ /// Pricing of the card
+ final Pricing? pricing;
+
+ /// Styles the title of the card.
+ final TextStyle? titleStyle;
+
+ /// Styles the pricing of the card.
+ final TextStyle? pricingStyle;
+
+ /// Styles the period of the card.
+ final TextStyle? periodStyle;
+
+ @override
+ Widget build(BuildContext context) {
+ final price = (pricing != null)
+ ? CardText.fromWrapper(
+ pricing!.price,
+ style: pricingStyle,
+ textType: TextType.title,
+ )
+ : null;
+
+ final period = ((pricing != null) && (pricing?.period != null))
+ ? CardText.fromWrapper(
+ pricing!.period!,
+ style: periodStyle,
+ textType: TextType.subtitle,
+ )
+ : null;
+
+ return Column(
+ children: [
+ if (title != null) ...[
+ if (axis == Axis.vertical) ...[
+ if (title?.icon != null) ...[
+ title!.icon!,
+ const Gap(_titlesLineSpacing),
+ ],
+ CardText.fromWrapper(
+ title!.data,
+ style: titleStyle,
+ textType: TextType.title,
+ ),
+ const Gap(_bodyTopSpacing),
+ ] else ...[
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ if (title?.icon != null) ...[
+ title!.icon!,
+ const Gap(_titlesLineSpacing),
+ ],
+ CardText.fromWrapper(
+ title!.data,
+ style: titleStyle,
+ textType: TextType.title,
+ ),
+ ],
+ ),
+ const Gap(_bodyTopSpacing),
+ ]
+ ],
+ RichText(
+ text: TextSpan(
+ children: [
+ if (price != null) ...[
+ TextSpan(
+ text: price.text.data,
+ style: price.text.style,
+ )
+ ],
+ if (pricing?.hasAsterisk ?? false) ...[
+ WidgetSpan(
+ child: Transform.translate(
+ offset: const Offset(5, -15),
+ child: const Text(
+ '* ',
+ style: TextStyle(fontSize: 18),
+ ),
+ ),
+ ),
+ ],
+ if (period != null) ...[
+ TextSpan(
+ text: period.text.data,
+ style: period.text.style,
+ )
+ ],
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/packages/wyatt_ui_kit/lib/src/data/theme_extensions/card_theme_extension_impl.dart b/packages/wyatt_ui_kit/lib/src/data/theme_extensions/card_theme_extension_impl.dart
index 294a0d7e..1439087b 100644
--- a/packages/wyatt_ui_kit/lib/src/data/theme_extensions/card_theme_extension_impl.dart
+++ b/packages/wyatt_ui_kit/lib/src/data/theme_extensions/card_theme_extension_impl.dart
@@ -50,7 +50,10 @@ class CardThemeExtensionImpl extends CardThemeExtension {
stroke: 1,
backgroundColors: const MultiColor.single(WyattColors.light),
borderColors: WyattColors.lightGradient,
- titleStyle: theme.textTheme.titleLarge,
+ titleStyle: theme.textTheme.titleLarge?.copyWith(
+ fontSize: 26,
+ fontWeight: FontWeight.w600,
+ ),
subtitleStyle: theme.textTheme.titleMedium,
bodyStyle: theme.textTheme.bodyMedium?.copyWith(
height: 1.5,
@@ -76,7 +79,10 @@ class CardThemeExtensionImpl extends CardThemeExtension {
stroke: 1,
backgroundColors: WyattColors.grayBgOpacityGradient,
borderColors: WyattColors.grayGradient,
- titleStyle: theme.textTheme.titleLarge,
+ titleStyle: theme.textTheme.titleLarge?.copyWith(
+ fontSize: 26,
+ fontWeight: FontWeight.w600,
+ ),
subtitleStyle: theme.textTheme.titleMedium,
bodyStyle: theme.textTheme.bodyMedium?.copyWith(
height: 1.5,