feat(ui): add pricing card
Some checks failed
continuous-integration/drone/pr Build is failing

This commit is contained in:
Hugo Pointcheval 2023-04-28 18:40:40 +02:00
parent 01a5619dc5
commit bfbeabe7ec
Signed by: hugo
GPG Key ID: 3AAC487E131E00BC
15 changed files with 766 additions and 6 deletions

View File

@ -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)';
}

View File

@ -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

View File

@ -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';

View File

@ -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 <https://www.gnu.org/licenses/>.
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<PricingLine>? features;
/// CTA of the card
final Widget? cta;
}

View File

@ -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<PricingLine>? 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<PricingLine>? 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,
});
}

View File

@ -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(),

View File

@ -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 <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/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),
],
);
}

View File

@ -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),
],
),
);
);
}

View File

@ -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];
}

View File

@ -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';

View File

@ -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 <https://www.gnu.org/licenses/>.
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<TextStyle, TextStyle>(
[
titleStyle,
Theme.of(context).extension<CardThemeExtension>()?.titleStyle,
CardThemeExtensionDefault.from(Theme.of(context)).titleStyle,
],
);
final themePricingStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
[
pricing?.price.style,
context.textTheme.bodyMedium
?.copyWith(fontSize: 50, fontWeight: FontWeight.bold),
],
);
final themePeriodStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
[
subtitleStyle,
context.textTheme.bodyMedium?.copyWith(
fontSize: 20,
fontWeight: FontWeight.w600,
color: WyattColors.gray1,
),
],
);
final themeBodyStyle = ThemeHelper.maybeGetElement<TextStyle, TextStyle>(
[
bodyStyle,
Theme.of(context).extension<CardThemeExtension>()?.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!),
],
],
),
);
}
}

View File

@ -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<PricingLine>? 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<PricingLine>? 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);
}

View File

@ -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 <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';
class PricingCardFeatures extends StatelessWidget {
const PricingCardFeatures({
super.key,
this.features,
this.bodyStyle,
});
/// List of special features of the card
final List<PricingLine>? 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(),
);
}

View File

@ -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 <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;
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,
)
],
],
),
),
],
);
}
}

View File

@ -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,