This commit is contained in:
parent
01a5619dc5
commit
bfbeabe7ec
@ -121,4 +121,11 @@ class TextWrapper {
|
|||||||
/// that, the selection color defaults to [DefaultSelectionStyle.defaultColor]
|
/// that, the selection color defaults to [DefaultSelectionStyle.defaultColor]
|
||||||
/// (semi-transparent grey).
|
/// (semi-transparent grey).
|
||||||
final Color? selectionColor;
|
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)';
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,7 @@ class SymbolButtonThemeExtensionDefault extends SymbolButtonThemeExtension {
|
|||||||
final textColor = MultiColor.single(theme.textTheme.bodyMedium?.color);
|
final textColor = MultiColor.single(theme.textTheme.bodyMedium?.color);
|
||||||
|
|
||||||
final style = SymbolButtonStyle(
|
final style = SymbolButtonStyle(
|
||||||
labelStyle:
|
labelStyle: theme.textTheme.labelLarge?.copyWith(color: textColor.color),
|
||||||
theme.textTheme.labelLarge?.copyWith(color: textColor.color),
|
|
||||||
dimension: theme.buttonTheme.height * 1.5,
|
dimension: theme.buttonTheme.height * 1.5,
|
||||||
radius: (theme.buttonTheme.shape is RoundedRectangleBorder)
|
radius: (theme.buttonTheme.shape is RoundedRectangleBorder)
|
||||||
? (theme.buttonTheme.shape as RoundedRectangleBorder).borderRadius
|
? (theme.buttonTheme.shape as RoundedRectangleBorder).borderRadius
|
||||||
|
@ -17,5 +17,6 @@
|
|||||||
export './card_component.dart';
|
export './card_component.dart';
|
||||||
export './information_card_component.dart';
|
export './information_card_component.dart';
|
||||||
export './portfolio_card_component.dart';
|
export './portfolio_card_component.dart';
|
||||||
|
export './pricing_card_component.dart';
|
||||||
export './quote_card_component.dart';
|
export './quote_card_component.dart';
|
||||||
export './skill_card_component.dart';
|
export './skill_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 <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;
|
||||||
|
}
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:gap/gap.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/information_card/information_cards.dart';
|
||||||
import 'package:wyatt_ui_kit_example/cards/portfolio_card/portfolio_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/quote_card/quote_cards.dart';
|
||||||
import 'package:wyatt_ui_kit_example/cards/skill_card/skill_cards.dart';
|
import 'package:wyatt_ui_kit_example/cards/skill_card/skill_cards.dart';
|
||||||
import 'package:wyatt_ui_kit_example/demo_page.dart';
|
import 'package:wyatt_ui_kit_example/demo_page.dart';
|
||||||
@ -24,6 +25,8 @@ class Cards extends DemoPage {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Gap(20),
|
const Gap(20),
|
||||||
|
const PricingCards(),
|
||||||
|
const Gap(20),
|
||||||
const InformationCards(),
|
const InformationCards(),
|
||||||
const Gap(20),
|
const Gap(20),
|
||||||
const PortfolioCards(),
|
const PortfolioCards(),
|
||||||
|
@ -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),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
@ -27,7 +27,7 @@ class RichTextBuilders extends DemoPage {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => SelectionArea(
|
Widget build(BuildContext context) => SelectionArea(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
cacheExtent: 1000,
|
cacheExtent: 1000,
|
||||||
children: [
|
children: [
|
||||||
const Gap(20),
|
const Gap(20),
|
||||||
@ -61,5 +61,5 @@ class RichTextBuilders extends DemoPage {
|
|||||||
const Gap(20),
|
const Gap(20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,9 @@ abstract class Constants {
|
|||||||
static const blue3 = Color(0xFF1A84F7);
|
static const blue3 = Color(0xFF1A84F7);
|
||||||
static const blue4 = Color(0xFF1344E4);
|
static const blue4 = Color(0xFF1344E4);
|
||||||
|
|
||||||
|
static const blue1Btn = Color(0xFF3C97FB);
|
||||||
|
static const blue2Btn = Color(0xFF446DF4);
|
||||||
|
|
||||||
static const grey1 = Color(0xFF60656A);
|
static const grey1 = Color(0xFF60656A);
|
||||||
static const grey2 = Color(0xFF383C40);
|
static const grey2 = Color(0xFF383C40);
|
||||||
|
|
||||||
@ -37,10 +40,15 @@ abstract class Constants {
|
|||||||
static const red1 = Color(0xFFFB5E3C);
|
static const red1 = Color(0xFFFB5E3C);
|
||||||
static const red2 = Color(0xFFF44464);
|
static const red2 = Color(0xFFF44464);
|
||||||
|
|
||||||
|
static const purple1 = Color(0xFFB79EFF);
|
||||||
|
static const purple2 = Color(0xFF6865F2);
|
||||||
|
|
||||||
static const blueGradient = [blue1, blue2];
|
static const blueGradient = [blue1, blue2];
|
||||||
|
static const blueBtnGradient = [blue1Btn, blue2Btn];
|
||||||
static const blueDarkGradient = [blue3, blue4];
|
static const blueDarkGradient = [blue3, blue4];
|
||||||
static const greyGradient = [grey1, grey2];
|
static const greyGradient = [grey1, grey2];
|
||||||
static const greyDarkGradient = [grey3, grey4];
|
static const greyDarkGradient = [grey3, grey4];
|
||||||
static const greenGradient = [green1, green2];
|
static const greenGradient = [green1, green2];
|
||||||
static const redGradient = [red1, red2];
|
static const redGradient = [red1, red2];
|
||||||
|
static const purpleGradient = [purple1, purple2];
|
||||||
}
|
}
|
||||||
|
@ -16,5 +16,6 @@
|
|||||||
|
|
||||||
export './information_card/information_card.dart';
|
export './information_card/information_card.dart';
|
||||||
export './portfolio_card/portfolio_card.dart';
|
export './portfolio_card/portfolio_card.dart';
|
||||||
|
export './pricing_card/pricing_card.dart';
|
||||||
export './quote_card/quote_card.dart';
|
export './quote_card/quote_card.dart';
|
||||||
export './skill_card/skill_card.dart';
|
export './skill_card/skill_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 <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!),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
@ -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(),
|
||||||
|
);
|
||||||
|
}
|
@ -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,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -50,7 +50,10 @@ class CardThemeExtensionImpl extends CardThemeExtension {
|
|||||||
stroke: 1,
|
stroke: 1,
|
||||||
backgroundColors: const MultiColor.single(WyattColors.light),
|
backgroundColors: const MultiColor.single(WyattColors.light),
|
||||||
borderColors: WyattColors.lightGradient,
|
borderColors: WyattColors.lightGradient,
|
||||||
titleStyle: theme.textTheme.titleLarge,
|
titleStyle: theme.textTheme.titleLarge?.copyWith(
|
||||||
|
fontSize: 26,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
subtitleStyle: theme.textTheme.titleMedium,
|
subtitleStyle: theme.textTheme.titleMedium,
|
||||||
bodyStyle: theme.textTheme.bodyMedium?.copyWith(
|
bodyStyle: theme.textTheme.bodyMedium?.copyWith(
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
@ -76,7 +79,10 @@ class CardThemeExtensionImpl extends CardThemeExtension {
|
|||||||
stroke: 1,
|
stroke: 1,
|
||||||
backgroundColors: WyattColors.grayBgOpacityGradient,
|
backgroundColors: WyattColors.grayBgOpacityGradient,
|
||||||
borderColors: WyattColors.grayGradient,
|
borderColors: WyattColors.grayGradient,
|
||||||
titleStyle: theme.textTheme.titleLarge,
|
titleStyle: theme.textTheme.titleLarge?.copyWith(
|
||||||
|
fontSize: 26,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
subtitleStyle: theme.textTheme.titleMedium,
|
subtitleStyle: theme.textTheme.titleMedium,
|
||||||
bodyStyle: theme.textTheme.bodyMedium?.copyWith(
|
bodyStyle: theme.textTheme.bodyMedium?.copyWith(
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user