@imaginario27/air-ui-ds 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/assets/css/defaults.css +55 -0
  2. package/assets/css/main.css +238 -0
  3. package/assets/css/theme/colors.css +106 -0
  4. package/assets/css/theme/primitives.css +105 -0
  5. package/assets/css/theme/ui-theme.css +454 -0
  6. package/assets/images/placeholders/missing-image-placeholder.png +0 -0
  7. package/components/accordions/Accordion.vue +31 -0
  8. package/components/accordions/AccordionGroup.vue +78 -0
  9. package/components/accordions/AccordionItem.vue +39 -0
  10. package/components/action-panels/ActionPanel.vue +49 -0
  11. package/components/alerts/Alert.vue +159 -0
  12. package/components/avatars/Avatar.vue +152 -0
  13. package/components/avatars/AvatarStack.vue +97 -0
  14. package/components/avatars/AvatarStackCounter.vue +74 -0
  15. package/components/badges/Badge.vue +221 -0
  16. package/components/badges/BadgeStack.vue +110 -0
  17. package/components/badges/IconBadge.vue +57 -0
  18. package/components/badges/IconTextBadge.vue +50 -0
  19. package/components/breadcrumbs/Breadcrumbs.vue +54 -0
  20. package/components/buttons/ActionButton.vue +395 -0
  21. package/components/buttons/ActionIconButton.vue +283 -0
  22. package/components/buttons/AlertButton.vue +125 -0
  23. package/components/buttons/AlertIconButton.vue +105 -0
  24. package/components/buttons/PaginationButton.vue +45 -0
  25. package/components/buttons/options/OptionButton.vue +61 -0
  26. package/components/buttons/options/OptionButtonGroup.vue +155 -0
  27. package/components/buttons/options/OptionButtonSlider.vue +154 -0
  28. package/components/buttons/toggle/ToggleButton.vue +142 -0
  29. package/components/buttons/toggle/ToggleButtonGroup.vue +73 -0
  30. package/components/cards/Card.vue +33 -0
  31. package/components/cards/CardActions.vue +5 -0
  32. package/components/cards/CardBody.vue +5 -0
  33. package/components/cards/CardFooter.vue +20 -0
  34. package/components/cards/CardHeader.vue +5 -0
  35. package/components/cards/CardTitle.vue +13 -0
  36. package/components/cards/specific/ContactDetailsCard.vue +47 -0
  37. package/components/cards/specific/FeatureCard.vue +59 -0
  38. package/components/cards/specific/HelpTopicCard.vue +62 -0
  39. package/components/cards/specific/MetricCard.vue +42 -0
  40. package/components/cards/specific/TestimonialCard.vue +57 -0
  41. package/components/cards/specific/subscription/CurrentActiveSubscriptionCard.vue +105 -0
  42. package/components/cards/specific/subscription/SubscriptionPlanCard.vue +178 -0
  43. package/components/cards/specific/subscription/UniqueSubscriptionPlanCard.vue +106 -0
  44. package/components/collapsibles/Collapsible.vue +33 -0
  45. package/components/content/ContentItem.vue +144 -0
  46. package/components/content/ContentItemImage.vue +125 -0
  47. package/components/dividers/Divider.vue +35 -0
  48. package/components/dividers/TextLineDivider.vue +58 -0
  49. package/components/dropdowns/DropdownMenu.vue +207 -0
  50. package/components/dropdowns/DropdownMenuActions.vue +11 -0
  51. package/components/dropdowns/DropdownMenuItem.vue +240 -0
  52. package/components/dropdowns/DropdownSelect.vue +469 -0
  53. package/components/dropdowns/DropdownSelectItem.vue +182 -0
  54. package/components/empty-states/EmptyState.vue +170 -0
  55. package/components/features/Feature.vue +77 -0
  56. package/components/forms/DataDetails.vue +7 -0
  57. package/components/forms/DataDetailsActions.vue +23 -0
  58. package/components/forms/DataDetailsFieldGroup.vue +35 -0
  59. package/components/forms/DataDetailsRow.vue +22 -0
  60. package/components/forms/Form.vue +25 -0
  61. package/components/forms/FormActions.vue +23 -0
  62. package/components/forms/FormFieldGroup.vue +35 -0
  63. package/components/forms/FormRow.vue +22 -0
  64. package/components/forms/fields/ButtonField.vue +119 -0
  65. package/components/forms/fields/CheckboxField.vue +205 -0
  66. package/components/forms/fields/DataField.vue +99 -0
  67. package/components/forms/fields/FileUploadField.vue +326 -0
  68. package/components/forms/fields/InputField.vue +371 -0
  69. package/components/forms/fields/OptionButtonsGroupField.vue +120 -0
  70. package/components/forms/fields/RepeaterField.vue +109 -0
  71. package/components/forms/fields/SearchField.vue +184 -0
  72. package/components/forms/fields/SelectField.vue +233 -0
  73. package/components/forms/fields/SliderField.vue +759 -0
  74. package/components/forms/fields/SwitchField.vue +257 -0
  75. package/components/forms/fields/TextareaField.vue +205 -0
  76. package/components/forms/fields/ToggleButtonsGroupField.vue +65 -0
  77. package/components/forms/fields/radio/RadioButtonField.vue +238 -0
  78. package/components/forms/fields/radio/RadioField.vue +157 -0
  79. package/components/forms/fields/radio/RadioGroupField.vue +156 -0
  80. package/components/icons/ContainedIcon.vue +130 -0
  81. package/components/images/QRCode.vue +124 -0
  82. package/components/layouts/ContainerWrapper.vue +13 -0
  83. package/components/layouts/ContentBody.vue +30 -0
  84. package/components/layouts/Grid.vue +25 -0
  85. package/components/layouts/Heading.vue +159 -0
  86. package/components/layouts/MainContent.vue +26 -0
  87. package/components/layouts/MaxWidthContainer.vue +15 -0
  88. package/components/layouts/Overtitle.vue +25 -0
  89. package/components/layouts/headers/CompactHeader.vue +181 -0
  90. package/components/layouts/headers/PageHeader.vue +102 -0
  91. package/components/layouts/headers/WebAppHeader.vue +54 -0
  92. package/components/layouts/section/Section.vue +90 -0
  93. package/components/layouts/section/SectionBody.vue +12 -0
  94. package/components/layouts/section/SectionHeader.vue +12 -0
  95. package/components/layouts/section/SectionTitle.vue +13 -0
  96. package/components/lists/List.vue +69 -0
  97. package/components/lists/ListItem.vue +58 -0
  98. package/components/loaders/Loading.vue +83 -0
  99. package/components/loaders/LoadingScreen.vue +285 -0
  100. package/components/modals/DangerModalDialog.vue +149 -0
  101. package/components/modals/InfoModalDialog.vue +143 -0
  102. package/components/modals/ModalActions.vue +22 -0
  103. package/components/modals/ModalContent.vue +5 -0
  104. package/components/modals/ModalDescription.vue +5 -0
  105. package/components/modals/ModalDialog.vue +122 -0
  106. package/components/modals/ModalHeaderGroup.vue +19 -0
  107. package/components/modals/ModalHeadings.vue +5 -0
  108. package/components/modals/ModalSubtitle.vue +14 -0
  109. package/components/modals/ModalTitle.vue +14 -0
  110. package/components/modals/SuccessModalDialog.vue +90 -0
  111. package/components/modules/AppLogo.vue +46 -0
  112. package/components/modules/SVGImage.vue +44 -0
  113. package/components/navigation/links/NavLink.vue +112 -0
  114. package/components/navigation/nav-menu/NavFooterMenu.vue +91 -0
  115. package/components/navigation/nav-menu/NavMenu.vue +36 -0
  116. package/components/navigation/nav-menu/NavMenuItem.vue +44 -0
  117. package/components/navigation/nav-sidebar/BottomUserNavBar.vue +83 -0
  118. package/components/navigation/nav-sidebar/NavSidebar.vue +172 -0
  119. package/components/navigation/nav-sidebar/NavSidebarMenu.vue +14 -0
  120. package/components/navigation/nav-sidebar/NavSidebarMenuItem.vue +76 -0
  121. package/components/navigation/nav-sidebar/NavSidebarMenuSectionTitle.vue +54 -0
  122. package/components/navigation/table-of-contents/TableOfContents.vue +35 -0
  123. package/components/navigation/table-of-contents/TableOfContentsItem.vue +40 -0
  124. package/components/navigation/table-of-contents/TableOfContentsSidebar.vue +29 -0
  125. package/components/pagination/ButtonPagination.vue +274 -0
  126. package/components/pagination/RowsPerPage.vue +60 -0
  127. package/components/pagination/SimplePagination.vue +97 -0
  128. package/components/password/SecurePasswordCondition.vue +41 -0
  129. package/components/password/SecurePasswordConditions.vue +83 -0
  130. package/components/placeholders/ContentPlaceholder.vue +41 -0
  131. package/components/popovers/Popover.vue +128 -0
  132. package/components/rating/InteractiveRating.vue +94 -0
  133. package/components/rating/Rating.vue +60 -0
  134. package/components/rating/RatingItem.vue +54 -0
  135. package/components/skeletons/Skeleton.vue +11 -0
  136. package/components/spinners/Spinner.vue +13 -0
  137. package/components/steppers/CircleStepper.vue +122 -0
  138. package/components/steppers/Step.vue +72 -0
  139. package/components/steppers/StepIndicator.vue +228 -0
  140. package/components/steppers/TabStepper.vue +126 -0
  141. package/components/steppers/vertical-stepper/VerticalStep.vue +223 -0
  142. package/components/steppers/vertical-stepper/VerticalStepper.vue +63 -0
  143. package/components/tables/Table.vue +26 -0
  144. package/components/tables/TableBody.vue +5 -0
  145. package/components/tables/TableCell.vue +34 -0
  146. package/components/tables/TableCellActions.vue +7 -0
  147. package/components/tables/TableHeader.vue +5 -0
  148. package/components/tables/TableHeaderCell.vue +15 -0
  149. package/components/tables/TableRow.vue +14 -0
  150. package/components/tables/TableWrapper.vue +12 -0
  151. package/components/tabs/Tab.vue +145 -0
  152. package/components/tabs/TabBar.vue +64 -0
  153. package/components/tabs/TabContent.vue +5 -0
  154. package/components/tabs/TabsContainer.vue +5 -0
  155. package/components/transitions/HorizontalExpansionTransition.vue +12 -0
  156. package/components/transitions/VerticalExpansionTransition.vue +14 -0
  157. package/components/users/Author.vue +113 -0
  158. package/components/users/User.vue +53 -0
  159. package/composables/useAccordion.ts +12 -0
  160. package/composables/useDarkMode.ts +9 -0
  161. package/composables/useDropdownMenu.ts +25 -0
  162. package/composables/useForm.ts +134 -0
  163. package/composables/useFormValidationMode.ts +11 -0
  164. package/composables/useIsMobile.ts +27 -0
  165. package/composables/useMobileSidebar.ts +32 -0
  166. package/composables/useShiki.ts +12 -0
  167. package/composables/useTableOfContents.ts +50 -0
  168. package/composables/useToastifyConfig.ts +7 -0
  169. package/eslint.config.mjs +14 -0
  170. package/models/constants/app.ts +8 -0
  171. package/models/constants/form.ts +22 -0
  172. package/models/enums/alerts.ts +6 -0
  173. package/models/enums/aspect-ratios.ts +9 -0
  174. package/models/enums/avatars.ts +21 -0
  175. package/models/enums/badges.ts +10 -0
  176. package/models/enums/buttons.ts +38 -0
  177. package/models/enums/colors.ts +9 -0
  178. package/models/enums/content.ts +4 -0
  179. package/models/enums/counters.ts +4 -0
  180. package/models/enums/dividers.ts +9 -0
  181. package/models/enums/dropdowns.ts +18 -0
  182. package/models/enums/effects.ts +6 -0
  183. package/models/enums/emptyPlaceholders.ts +5 -0
  184. package/models/enums/formFields.ts +19 -0
  185. package/models/enums/formValidations.ts +4 -0
  186. package/models/enums/headings.ts +11 -0
  187. package/models/enums/icons.ts +22 -0
  188. package/models/enums/images.ts +16 -0
  189. package/models/enums/lists.ts +10 -0
  190. package/models/enums/loaders.ts +15 -0
  191. package/models/enums/navigation.ts +18 -0
  192. package/models/enums/order.ts +10 -0
  193. package/models/enums/orientations.ts +4 -0
  194. package/models/enums/pages.ts +10 -0
  195. package/models/enums/positions.ts +21 -0
  196. package/models/enums/rating.ts +12 -0
  197. package/models/enums/sections.ts +8 -0
  198. package/models/enums/selects.ts +16 -0
  199. package/models/enums/sliders.ts +4 -0
  200. package/models/enums/steppers.ts +20 -0
  201. package/models/enums/tabs.ts +11 -0
  202. package/models/enums/triggers.ts +4 -0
  203. package/models/types/accordions.ts +6 -0
  204. package/models/types/avatars.ts +4 -0
  205. package/models/types/badges.ts +4 -0
  206. package/models/types/buttons.ts +26 -0
  207. package/models/types/dropdowns.ts +20 -0
  208. package/models/types/forms.ts +14 -0
  209. package/models/types/navigation.ts +11 -0
  210. package/models/types/pagination.ts +4 -0
  211. package/models/types/pdfExportTable.ts +6 -0
  212. package/models/types/radio.ts +9 -0
  213. package/models/types/selects.ts +14 -0
  214. package/models/types/steppers.ts +17 -0
  215. package/models/types/tableOfContent.ts +6 -0
  216. package/models/types/tabs.ts +7 -0
  217. package/nuxt.config.ts +40 -0
  218. package/package.json +57 -0
  219. package/plugins/vue3-toastify.ts +14 -0
  220. package/tsconfig.json +7 -0
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <Card
3
+ :class="[
4
+ 'lg:py-7 lg:px-8',
5
+ ]"
6
+ >
7
+ <CardHeader :class="['!flex-col', align === Align.CENTER && 'items-center']">
8
+ <ContainedIcon
9
+ :icon
10
+ :shape="containedIconShape"
11
+ :styleType="containedIconStyleType"
12
+ :color="containedIconColor"
13
+ />
14
+ <CardTitle :title :class="[align === Align.CENTER && 'text-center']"/>
15
+ </CardHeader>
16
+ <CardBody>
17
+ <p :class="['text-sm', align === Align.CENTER && 'text-center']">
18
+ {{ description }}
19
+ </p>
20
+ </CardBody>
21
+ </Card>
22
+ </template>
23
+ <script setup lang="ts">
24
+ // Props
25
+ defineProps({
26
+ title: {
27
+ type: String as PropType<string>,
28
+ default: 'Feature title'
29
+ },
30
+ description: {
31
+ type: String as PropType<string>,
32
+ default: 'Feature description'
33
+ },
34
+ icon: {
35
+ type: String as PropType<any>,
36
+ default: 'mdiHelp'
37
+ },
38
+ containedIconShape: {
39
+ type: String as PropType<IconContainerShape>,
40
+ default: IconContainerShape.CIRCLE,
41
+ validator: (value: IconContainerShape) => Object.values(IconContainerShape).includes(value),
42
+ },
43
+ containedIconStyleType: {
44
+ type: String as PropType<IconContainerStyleType>,
45
+ default: IconContainerStyleType.FILLED,
46
+ validator: (value: IconContainerStyleType) => Object.values(IconContainerStyleType).includes(value),
47
+ },
48
+ containedIconColor: {
49
+ type: String as PropType<ColorAccent>,
50
+ default: ColorAccent.SECONDARY_BRAND,
51
+ validator: (value: ColorAccent) => Object.values(ColorAccent).includes(value),
52
+ },
53
+ align: {
54
+ type: String as PropType<Align.LEFT | Align.CENTER>,
55
+ default: Align.LEFT,
56
+ validator: (value: Align) => [Align.LEFT, Align.CENTER].includes(value),
57
+ }
58
+ })
59
+ </script>
@@ -0,0 +1,62 @@
1
+ <template>
2
+ <Card class="!py-6">
3
+ <CardHeader class="!justify-center items-center flex-col gap-4">
4
+ <!-- Icon -->
5
+ <ContainedIcon
6
+ :icon
7
+ :color="ColorAccent.PRIMARY_BRAND"
8
+ />
9
+
10
+ <!-- Title -->
11
+ <h4 class="font-semibold">
12
+ {{ title }}
13
+ </h4>
14
+ </CardHeader>
15
+ <CardBody>
16
+ <div class="flex flex-col w-full text-center items-center gap-6">
17
+ <p class="text-sm text-text-neutral-subtle">
18
+ {{ description }}
19
+ </p>
20
+ <div class="w-full flex justify-center">
21
+ <ActionButton
22
+ :styleType="ButtonStyleType.NEUTRAL_TRANSPARENT"
23
+ :actionType="ButtonActionType.LINK"
24
+ :iconPosition="IconPosition.RIGHT"
25
+ :icon="buttonIcon"
26
+ :to
27
+ :text="buttonText"
28
+ />
29
+ </div>
30
+ </div>
31
+ </CardBody>
32
+ </Card>
33
+ </template>
34
+ <script setup lang="ts">
35
+ // Props
36
+ defineProps({
37
+ icon: {
38
+ type: String as PropType<any>,
39
+ default: 'mdiHelp'
40
+ },
41
+ title: {
42
+ type: String as PropType<string>,
43
+ default: 'Title'
44
+ },
45
+ description: {
46
+ type: String as PropType<string>,
47
+ default: 'Description'
48
+ },
49
+ to: {
50
+ type: String as PropType<string>,
51
+ default: '/'
52
+ },
53
+ buttonText: {
54
+ type: String as PropType<string>,
55
+ default: 'Learn more'
56
+ },
57
+ buttonIcon: {
58
+ type: String as PropType<any>,
59
+ default: 'mdiArrowRight'
60
+ },
61
+ })
62
+ </script>
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <Card>
3
+ <CardHeader>
4
+ <CardTitle
5
+ :title
6
+ :class="[align === Align.CENTER && 'text-center']"
7
+ />
8
+ </CardHeader>
9
+ <CardBody>
10
+ <div :class="['flex flex-col', align === Align.CENTER && 'text-center']">
11
+ <span class="font-semibold text-2xl md:text-3xl">
12
+ {{ value }}
13
+ </span>
14
+ <p
15
+ v-if="description"
16
+ class="text-text-neutral-subtle text-sm"
17
+ >
18
+ {{ description }}
19
+ </p>
20
+ </div>
21
+ </CardBody>
22
+ </Card>
23
+ </template>
24
+ <script setup lang="ts">
25
+ // Props
26
+ defineProps({
27
+ title: {
28
+ type: String as PropType<string>,
29
+ default: 'Card title'
30
+ },
31
+ value: {
32
+ type: [String, Number] as PropType<string | number>,
33
+ default: 0
34
+ },
35
+ description: String,
36
+ align: {
37
+ type: String as PropType<Align.LEFT | Align.CENTER>,
38
+ default: Align.LEFT,
39
+ validator: (value: Align) => [Align.LEFT, Align.CENTER].includes(value),
40
+ }
41
+ })
42
+ </script>
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <Card class="px-0 py-5 shadow-xl">
3
+ <CardBody class="px-5">
4
+ <Rating
5
+ :value="ratingValue"
6
+ :color="ratingStarColor"
7
+ />
8
+ <p class="text-sm">
9
+ {{ text }}
10
+ </p>
11
+ <Author
12
+ v-if="!isDivided"
13
+ :name="displayName"
14
+ :role
15
+ :imgUrl
16
+ />
17
+ </CardBody>
18
+ <CardFooter
19
+ v-if="isDivided"
20
+ class="px-5"
21
+ >
22
+ <Author
23
+ :name="displayName"
24
+ :role
25
+ :imgUrl
26
+ />
27
+ </CardFooter>
28
+ </Card>
29
+ </template>
30
+ <script setup lang="ts">
31
+ // Props
32
+ defineProps({
33
+ displayName: {
34
+ type: String as PropType<string>,
35
+ default: 'John Doe'
36
+ },
37
+ role: String as PropType<string>,
38
+ imgUrl: String as PropType<string>,
39
+ text: {
40
+ type: String as PropType<string>,
41
+ default: 'Text'
42
+ },
43
+ ratingValue: {
44
+ type: Number as PropType<number>,
45
+ default: 0
46
+ },
47
+ ratingStarColor: {
48
+ type: String as PropType<RatingItemColor>,
49
+ default: RatingItemColor.GOLD,
50
+ validator: (value: RatingItemColor) => Object.values(RatingItemColor).includes(value),
51
+ },
52
+ isDivided: {
53
+ type: Boolean as PropType<boolean>,
54
+ default: false
55
+ },
56
+ })
57
+ </script>
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <Card>
3
+ <CardHeader>
4
+ <CardTitle
5
+ :title="!isPlanCancelled ? title : 'Plan canceled'"
6
+ :class="{ 'text-text-danger': isPlanCancelled }"
7
+ />
8
+ <p
9
+ v-if="!isPlanCancelled"
10
+ class="text-sm"
11
+ >
12
+ Your next invoice is <strong>{{ nextPaymentAmount }}{{ currencySymbol }}</strong>
13
+ and will be sent on {{ nextPaymentDate }}.
14
+ </p>
15
+ <p
16
+ v-else-if="isPlanCancelled"
17
+ class="text-sm"
18
+ >
19
+ Your plan will switch to FREE on {{ nextPaymentDate }}.
20
+ </p>
21
+ </CardHeader>
22
+ <CardBody>
23
+ <div class="flex gap-column-gap justify-between items-end">
24
+ <div class="flex flex-col">
25
+ <span class="text-2xl font-semibold">{{ planName.toUpperCase() }}</span>
26
+ <p
27
+ v-if="!isPlanCancelled"
28
+ class="text-xs text-text-secondary"
29
+ >
30
+ {{ planDescription }}
31
+ </p>
32
+ </div>
33
+ <div class="flex gap-3 flex-col md:flex-row">
34
+ <ActionButton
35
+ :text="changePlanButtonText"
36
+ :styleType="ButtonStyleType.PRIMARY_BRAND_FILLED"
37
+ :actionType="ButtonActionType.LINK"
38
+ :to="changePlanLink"
39
+ class="w-full md:w-auto"
40
+ />
41
+ <ActionButton
42
+ v-if="!isPlanCancelled"
43
+ :text="cancelButtonText"
44
+ class="w-full md:w-auto"
45
+ @click="emit('cancel')"
46
+ />
47
+ <ActionButton
48
+ v-if="isPlanCancelled"
49
+ text="Undo cancellation"
50
+ class="w-full md:w-auto"
51
+ @click="emit('undoCancellation')"
52
+ />
53
+ </div>
54
+ </div>
55
+ </CardBody>
56
+ </Card>
57
+ </template>
58
+ <script setup lang="ts">
59
+ // Props
60
+ defineProps({
61
+ title: {
62
+ type: String as PropType<string>,
63
+ default: 'Current Active Plan'
64
+ },
65
+ nextPaymentAmount: {
66
+ type: Number as PropType<number>,
67
+ default: 0
68
+ },
69
+ nextPaymentDate: {
70
+ type: String as PropType<string>,
71
+ default: '_'
72
+ },
73
+ currencySymbol: {
74
+ type: String as PropType<string>,
75
+ default: '€'
76
+ },
77
+ planName: {
78
+ type: String as PropType<string>,
79
+ default: 'Plan name'
80
+ },
81
+ planDescription: {
82
+ type: String as PropType<string>,
83
+ default: 'Cancel whenever you want'
84
+ },
85
+ changePlanLink: {
86
+ type: String as PropType<string>,
87
+ default: '/'
88
+ },
89
+ changePlanButtonText: {
90
+ type: String as PropType<string>,
91
+ default: 'Change plan'
92
+ },
93
+ cancelButtonText: {
94
+ type: String as PropType<string>,
95
+ default: 'Cancel subscription'
96
+ },
97
+ isPlanCancelled: {
98
+ type: Boolean as PropType<boolean>,
99
+ default: false,
100
+ }
101
+ })
102
+
103
+ // Emits
104
+ const emit = defineEmits(['cancel', 'undoCancellation'])
105
+ </script>
@@ -0,0 +1,178 @@
1
+ <template>
2
+ <Card
3
+ :class="[
4
+ '!gap-5',
5
+ 'lg:py-7 lg:px-8',
6
+ ]"
7
+ >
8
+ <CardHeader class="!flex-col !justify-normal !gap-3 relative">
9
+ <template v-if="isFeatured && !isActive">
10
+ <div class="w-full flex justify-between gap-3">
11
+ <CardTitle
12
+ :title="capitalizeFirstLetter(title)"
13
+ class="text-text-primary-brand-default"
14
+ />
15
+ <Badge
16
+ v-if="isFeatured"
17
+ :text="featuredBadgeText"
18
+ :color="ColorAccent.PRIMARY_BRAND"
19
+ />
20
+ </div>
21
+ </template>
22
+
23
+ <template v-else>
24
+ <CardTitle :title="capitalizeFirstLetter(title)" class="text-text-primary-brand-default"/>
25
+ </template>
26
+
27
+ <span class="text-4xl font-semibold">
28
+ {{ computedAmount }}{{ currencySymbol }}<span class="text-text-neutral-subtle font-normal text-lg">/{{ computedPeriodicity }}</span>
29
+ </span>
30
+
31
+ <MdiIcon
32
+ v-if="isActive && !isFeatured"
33
+ icon="mdiCheckCircle"
34
+ size="24"
35
+ preserveAspectRatio="xMidYMid meet"
36
+ class="active-icon absolute top-0 right-0 text-icon-primary-brand-active"
37
+ />
38
+ </CardHeader>
39
+
40
+ <CardBody class="h-full">
41
+ <div class="flex flex-col gap-7 flex-grow mb-4">
42
+ <p v-if="description" class="text-sm">
43
+ {{ description }}
44
+ </p>
45
+ <List
46
+ v-if="features.length"
47
+ :hasSeparator="hasFeatureListSeparator"
48
+ :class="[!hasFeatureListSeparator && 'gap-5']"
49
+ >
50
+ <ListItem
51
+ v-for="feature in features" :key="feature"
52
+ icon="mdiCheck"
53
+ :spaced="hasFeatureListSeparator"
54
+ >
55
+ {{ feature }}
56
+ </ListItem>
57
+ </List>
58
+ </div>
59
+
60
+ <div
61
+ :class="[
62
+ 'mt-auto flex',
63
+ alignClass
64
+ ]"
65
+ >
66
+ <ActionButton
67
+ v-if="!isActive && showSelectButton"
68
+ :text="selectButtonText"
69
+ :styleType="isFeatured ? featuredButtonStyle : buttonStyle"
70
+ class="w-full md:w-auto"
71
+ />
72
+ </div>
73
+ </CardBody>
74
+ </Card>
75
+ </template>
76
+ <script setup lang="ts">
77
+ // Props
78
+ const props = defineProps({
79
+ isActive: {
80
+ type: Boolean as PropType<boolean>,
81
+ default: false
82
+ },
83
+ isFeatured: {
84
+ type: Boolean as PropType<boolean>,
85
+ default: false
86
+ },
87
+ title: {
88
+ type: String as PropType<string>,
89
+ default: 'Plan name'
90
+ },
91
+ description: String as PropType<string>,
92
+ monthlyAmount: {
93
+ type: Number as PropType<number>,
94
+ default: 0
95
+ },
96
+ yearlyAmount: {
97
+ type: Number as PropType<number>,
98
+ default: 0
99
+ },
100
+ currencySymbol: {
101
+ type: String as PropType<string>,
102
+ default: '€'
103
+ },
104
+ featuredBadgeText: {
105
+ type: String as PropType<string>,
106
+ default: 'Recommended'
107
+ },
108
+ features: {
109
+ type: Array as PropType<Array<string>>,
110
+ default: () => [
111
+ 'Feature 1',
112
+ 'Feature 2',
113
+ 'Feature 3'
114
+ ]
115
+ },
116
+ hasFeatureListSeparator: {
117
+ type: Boolean as PropType<boolean>,
118
+ default: false
119
+ },
120
+ isYearly: {
121
+ type: Boolean as PropType<boolean>,
122
+ default: false
123
+ },
124
+ monthlyText: {
125
+ type: String as PropType<string>,
126
+ default: 'monthly'
127
+ },
128
+ yearlyText: {
129
+ type: String as PropType<string>,
130
+ default: 'yearly'
131
+ },
132
+ showSelectButton: {
133
+ type: Boolean as PropType<boolean>,
134
+ default: true
135
+ },
136
+ selectButtonText: {
137
+ type: String as PropType<string>,
138
+ default: 'Get started today'
139
+ },
140
+ alignSelectButton: {
141
+ type: String as PropType<Align>,
142
+ default: Align.CENTER,
143
+ validator: (value: Align) => Object.values(Align).includes(value),
144
+ },
145
+ buttonStyle: {
146
+ type: String as PropType<ButtonStyleType>,
147
+ default: ButtonStyleType.NEUTRAL_FILLED,
148
+ validator: (value: ButtonStyleType) => Object.values(ButtonStyleType).includes(value),
149
+ },
150
+ featuredButtonStyle: {
151
+ type: String as PropType<ButtonStyleType>,
152
+ default: ButtonStyleType.PRIMARY_BRAND_FILLED,
153
+ validator: (value: ButtonStyleType) => Object.values(ButtonStyleType).includes(value),
154
+ },
155
+ })
156
+
157
+ // Emits
158
+ defineEmits(['update:modelValue'])
159
+
160
+ // Computed classes
161
+ const alignClass = computed(() => {
162
+ const alignVariant: Record<Align, string> = {
163
+ [Align.LEFT]: "justify-start",
164
+ [Align.CENTER]: "justify-center",
165
+ [Align.RIGHT]: "justify-end",
166
+ }
167
+
168
+ return alignVariant[props.alignSelectButton as Align] || "justify-center"
169
+ })
170
+
171
+ // Computed functions
172
+ const computedAmount = computed(() => {
173
+ return props.isYearly
174
+ ? props.yearlyAmount : props.monthlyAmount
175
+ })
176
+
177
+ const computedPeriodicity = computed(() => props.isYearly ? props.yearlyText : props.monthlyText)
178
+ </script>
@@ -0,0 +1,106 @@
1
+ <template>
2
+ <Card
3
+ :class="[
4
+ 'lg:py-7 lg:px-8',
5
+ ]"
6
+ >
7
+ <CardBody class="sm:flex-row">
8
+ <!-- Left column -->
9
+ <div class="w-full sm:w-1/2 md:w-2/3 flex flex-col gap-5">
10
+ <div class="w-full flex flex-col gap-3">
11
+ <CardTitle :title class="text-2xl"/>
12
+ <p>
13
+ {{ description }}
14
+ </p>
15
+ </div>
16
+
17
+ <List :layout="ListLayout.GRID" :cols="2">
18
+ <ListItem
19
+ v-for="item in features" :key="item"
20
+ icon="mdiCheck"
21
+ >
22
+ {{ item }}
23
+ </ListItem>
24
+ </List>
25
+ </div>
26
+
27
+ <!-- Right column -->
28
+ <div
29
+ :class="[
30
+ 'w-full sm:w-1/2 md:w-1/3',
31
+ 'bg-background-neutral-subtlest-on-container-surface',
32
+ 'flex flex-col gap-5 p-8',
33
+ 'justify-center',
34
+ 'items-center',
35
+ 'rounded-lg',
36
+ 'mt-4 md:mt-0',
37
+ ]"
38
+ >
39
+ <!-- Header -->
40
+ <div class="w-full flex flex-col gap-3 text-center">
41
+ <span
42
+ v-if="overtitle"
43
+ class="font-semibold"
44
+ >
45
+ {{ overtitle }}
46
+ </span>
47
+
48
+ <span class="text-4xl font-semibold">
49
+ {{ price }}
50
+ </span>
51
+ </div>
52
+
53
+ <!-- CTA -->
54
+ <div class="w-full flex justify-center">
55
+ <ActionButton
56
+ :styleType="ButtonStyleType.PRIMARY_BRAND_FILLED"
57
+ :text="buttonText"
58
+ @click="emit('click')"
59
+ />
60
+ </div>
61
+
62
+ <!-- Extra info -->
63
+ <div class="text-neutral-subtle text-xs">
64
+ <slot name="additionalInfo" />
65
+ </div>
66
+ </div>
67
+ </CardBody>
68
+ </Card>
69
+ </template>
70
+ <script setup lang="ts">
71
+ defineProps({
72
+ title: {
73
+ type: String as PropType<string>,
74
+ default: 'Plan name'
75
+ },
76
+ description: {
77
+ type: String as PropType<string>,
78
+ default: 'Plan description'
79
+ },
80
+ features: {
81
+ type: Array as PropType<Array<string>>,
82
+ default: () => [
83
+ 'Feature 1',
84
+ 'Feature 2',
85
+ 'Feature 3',
86
+ 'Feature 4',
87
+ 'Feature 5',
88
+ 'Feature 6',
89
+ 'Feature 7',
90
+ 'Feature 8'
91
+ ],
92
+ },
93
+ overtitle: String as PropType<string>,
94
+ price: {
95
+ type: String as PropType<string>,
96
+ default: '0€'
97
+ },
98
+ buttonText: {
99
+ type: String as PropType<string>,
100
+ default: 'Get started today'
101
+ },
102
+ })
103
+
104
+ // Emits
105
+ const emit = defineEmits(['click'])
106
+ </script>
@@ -0,0 +1,33 @@
1
+ <template>
2
+ <div class="w-full flex flex-col gap-2 py-3">
3
+ <div class="collapsible-header flex justify-between gap-4 hover:cursor-pointer" @click="toggle">
4
+ <span class="font-semibold mt-1">
5
+ {{ title }}
6
+ </span>
7
+
8
+ <!-- This button does not have click event because the toggle is being controlled by the accordeon header div-->
9
+ <ActionIconButton
10
+ :icon="isOpen ? 'mdiUnfoldLessHorizontal' : 'mdiUnfoldMoreHorizontal'"
11
+ :styleType="ButtonStyleType.NEUTRAL_OUTLINED"
12
+ :size="ButtonSize.MD"
13
+ />
14
+ </div>
15
+
16
+ <VerticalExpansionTransition v-show="isOpen">
17
+ <slot />
18
+ </VerticalExpansionTransition>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ // Props
24
+ defineProps({
25
+ title: {
26
+ type: String as PropType<string>,
27
+ default: 'Item title'
28
+ },
29
+ })
30
+
31
+ // Composables
32
+ const { isOpen, toggle } = useAccordion()
33
+ </script>