@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,285 @@
1
+ <template>
2
+ <div
3
+ v-if="isLoading"
4
+ :class="[
5
+ 'w-full',
6
+ isFullScreen && 'h-screen',
7
+ 'flex',
8
+ 'justify-center',
9
+ 'items-center',
10
+ 'px-content-side-padding',
11
+ 'py-4',
12
+ containerClass
13
+ ]"
14
+ >
15
+ <Loading
16
+ :isLoading
17
+ :text="loadingText"
18
+ :spinnerSize
19
+ />
20
+ </div>
21
+ <div
22
+ v-if="!isLoading && error"
23
+ :class="[
24
+ 'w-full',
25
+ 'px-content-side-padding',
26
+ isFullScreen ? 'py-[10vw] md:py-[20vw]' : 'px-content-side-padding py-8',
27
+ 'flex',
28
+ 'flex-col',
29
+ isSpaced ? 'gap-4' : 'gap-2',
30
+ 'items-center',
31
+ 'justify-center',
32
+ containerClass
33
+ ]"
34
+ >
35
+ <ContainedIcon
36
+ v-if="!$slots['graphic']"
37
+ :color="ColorAccent.DANGER"
38
+ icon="mdiAlertCircleOutline"
39
+ :size="iconContainerSize"
40
+ />
41
+
42
+ <!-- Can be used to replace default content icon -->
43
+ <slot name="graphic" />
44
+
45
+ <div
46
+ :class="[
47
+ 'flex',
48
+ 'flex-col',
49
+ isSpaced ? 'gap-3' : 'gap-2',
50
+ 'items-center',
51
+ 'w-full',
52
+ 'max-w-[800px]',
53
+ ]"
54
+ >
55
+ <h1 :class="titleClass">
56
+ {{ title }}
57
+ </h1>
58
+ <p :class="errorTextClass">
59
+ {{ error }}
60
+ </p>
61
+ </div>
62
+
63
+ <p :class="helpTextClass">
64
+ {{ helpText }}
65
+ </p>
66
+
67
+ <div
68
+ :class="[
69
+ 'w-full',
70
+ 'flex',
71
+ 'gap-3',
72
+ isSpaced ? 'mt-6' : 'mt-4',
73
+ 'items-center',
74
+ 'justify-center',
75
+ 'flex-col',
76
+ 'md:flex-row'
77
+ ]"
78
+ >
79
+ <template v-if="!$slots['actions']">
80
+ <ActionButton
81
+ v-if="hasGoBackButton"
82
+ :actionType="ButtonActionType.LINK"
83
+ :styleType="hasRetryButton ? ButtonStyleType.NEUTRAL_FILLED : undefined"
84
+ :text="goBackText"
85
+ :icon="goBackIcon"
86
+ :iconPosition="IconPosition.LEFT"
87
+ :size="buttonSize"
88
+ :to="goBackLink"
89
+ isMobileFullWidth
90
+ />
91
+
92
+ <template v-if="hasRetryButton">
93
+ <ActionButton
94
+ v-if="!retryLocked"
95
+ :text="retryButtonText"
96
+ :size="buttonSize"
97
+ :iconPosition="IconPosition.LEFT"
98
+ icon="mdiRefresh"
99
+ class="self-center"
100
+ :disabled="isRetryButtonDisabled"
101
+ isMobileFullWidth
102
+ @click="handleRetry"
103
+ />
104
+
105
+ <p v-else class="text-xs text-text-neutral-subtle mt-4">
106
+ {{ retryLimitReachedText }}
107
+ </p>
108
+ </template>
109
+ </template>
110
+
111
+ <!-- Can be used to replace default actions -->
112
+ <slot name="actions" />
113
+ </div>
114
+ </div>
115
+ </template>
116
+
117
+ <script setup lang="ts">
118
+ // Props
119
+ const props = defineProps({
120
+ isLoading: {
121
+ type: Boolean as PropType<boolean>,
122
+ default: true,
123
+ },
124
+ loadingText: {
125
+ type: String as PropType<string>,
126
+ default: "Loading",
127
+ },
128
+ error: {
129
+ type: [String, null] as PropType<string | null>,
130
+ default: null,
131
+ },
132
+ title: {
133
+ type: String as PropType<string>,
134
+ default: "Oops! Something went wrong!",
135
+ },
136
+ helpText: {
137
+ type: String as PropType<string>,
138
+ default: "Please try again or report the error to us. Thank you!",
139
+ },
140
+ hasGoBackButton: {
141
+ type: Boolean as PropType<boolean>,
142
+ default: true,
143
+ },
144
+ goBackText: {
145
+ type: String as PropType<string>,
146
+ default: "Go back",
147
+ },
148
+ goBackLink: {
149
+ type: String as PropType<string>,
150
+ default: "/",
151
+ },
152
+ goBackIcon: {
153
+ type: String as PropType<string>,
154
+ default: "mdiKeyboardBackspace",
155
+ },
156
+ hasRetryButton: {
157
+ type: Boolean as PropType<boolean>,
158
+ default: false,
159
+ },
160
+ retryText: {
161
+ type: String as PropType<string>,
162
+ default: 'Try again',
163
+ },
164
+ retryLimitReachedText: {
165
+ type: String as PropType<string>,
166
+ default: 'Retry limit reached. Please refresh the page or contact support.',
167
+ },
168
+ cooldownText: {
169
+ type: String as PropType<string>,
170
+ default: 'Retry in',
171
+ },
172
+ maxRetryCycles: {
173
+ type: Number as PropType<number>,
174
+ default: 2,
175
+ },
176
+ maxRetries: {
177
+ type: Number as PropType<number>,
178
+ default: 3,
179
+ },
180
+ cooldownSeconds: {
181
+ type: Number as PropType<number>,
182
+ default: 60,
183
+ },
184
+ isFullScreen: {
185
+ type: Boolean as PropType<boolean>,
186
+ default: true,
187
+ },
188
+ spinnerSize: String as PropType<LoadingSpinnerSize>,
189
+ iconContainerSize: {
190
+ type: String as PropType<IconContainerSize>,
191
+ default: IconContainerSize.XXL,
192
+ validator: (value: IconContainerSize) => Object.values(IconContainerSize).includes(value),
193
+ },
194
+ buttonSize: String as PropType<ButtonSize>,
195
+ isSpaced: {
196
+ type: Boolean as PropType<boolean>,
197
+ default: true,
198
+ },
199
+ titleClass: {
200
+ type: String as PropType<string>,
201
+ default: 'font-semibold text-xl md:text-2xl text-center leading-6',
202
+ },
203
+ errorTextClass: {
204
+ type: String as PropType<string>,
205
+ default: 'text-text-neutral-subtle font-semibold text-center',
206
+ },
207
+ helpTextClass: {
208
+ type: String as PropType<string>,
209
+ default: 'text-center',
210
+ },
211
+ containerClass: {
212
+ type: String as PropType<string>,
213
+ default: "py-20",
214
+ },
215
+ })
216
+
217
+ // Emits
218
+ const emit = defineEmits(['retry'])
219
+
220
+ // Retry state
221
+ const { count: retryCount, inc: incrementRetry, reset: resetRetry } = useCounter()
222
+ const cycleCount = ref(0)
223
+ const isCoolingDown = ref(false)
224
+ const retryLocked = computed(() => cycleCount.value >= props.maxRetryCycles)
225
+ const remainingSeconds = ref(props.cooldownSeconds)
226
+ const temporarilyDisabled = ref(false)
227
+
228
+ // Retry button text
229
+ const retryButtonText = computed(() => {
230
+ if (isCoolingDown.value) {
231
+ return `${props.cooldownText} ${remainingSeconds.value}s`
232
+ }
233
+
234
+ return props.retryText
235
+ })
236
+
237
+ // Combined disabled state
238
+ const isRetryButtonDisabled = computed(() =>
239
+ isCoolingDown.value ||
240
+ retryCount.value >= props.maxRetries ||
241
+ temporarilyDisabled.value
242
+ )
243
+
244
+ // Cooldown countdown timer
245
+ const { pause, resume } = useIntervalFn(() => {
246
+ if (remainingSeconds.value <= 1) {
247
+ pause()
248
+ isCoolingDown.value = false
249
+ remainingSeconds.value = props.cooldownSeconds
250
+ resetRetry()
251
+ cycleCount.value++
252
+ } else {
253
+ remainingSeconds.value--
254
+ }
255
+ }, 1000, { immediate: false })
256
+
257
+ // Retry click handler
258
+ const handleRetryInternal = () => {
259
+ if (isRetryButtonDisabled.value || retryLocked.value) return
260
+
261
+ incrementRetry()
262
+ emit('retry')
263
+
264
+ // UX lockout for 1s after click
265
+ temporarilyDisabled.value = true
266
+ setTimeout(() => {
267
+ temporarilyDisabled.value = false
268
+ }, 1000)
269
+
270
+ if (retryCount.value >= props.maxRetries) {
271
+ isCoolingDown.value = true
272
+ remainingSeconds.value = props.cooldownSeconds
273
+ resume()
274
+ }
275
+ }
276
+
277
+ // Debounced handler to prevent spam clicking
278
+ const handleRetry = useDebounceFn(handleRetryInternal, 500, {
279
+ maxWait: 500,
280
+ })
281
+
282
+ onUnmounted(() => {
283
+ pause()
284
+ })
285
+ </script>
@@ -0,0 +1,149 @@
1
+ <template>
2
+ <ModalDialog
3
+ :modelValue
4
+ :closeOnClickOutside
5
+ :hasCornerCloseButton
6
+ :cardClasses
7
+ @update:modelValue="updateModelValue"
8
+ >
9
+ <ModalContent class="!gap-6 items-center">
10
+ <template v-if="orientation === Orientation.VERTICAL">
11
+ <ContainedIcon
12
+ :color="ColorAccent.DANGER"
13
+ :size="IconContainerSize.XL"
14
+ :icon
15
+ />
16
+
17
+ <ModalHeaderGroup centered>
18
+ <ModalTitle :title />
19
+ <ModalDescription v-if="description">
20
+ {{ description }}
21
+ </ModalDescription>
22
+ </ModalHeaderGroup>
23
+ </template>
24
+ <template v-else>
25
+ <div class="w-full flex gap-4 flex-col sm:flex-row items-center sm:items-start">
26
+ <ContainedIcon
27
+ :color="ColorAccent.DANGER"
28
+ :size="IconContainerSize.LG"
29
+ :icon
30
+ />
31
+
32
+ <ModalHeaderGroup centered class="sm:text-left">
33
+ <ModalTitle :title class="sm:max-w-[450px]" />
34
+ <ModalDescription v-if="description">
35
+ {{ description }}
36
+ </ModalDescription>
37
+ </ModalHeaderGroup>
38
+ </div>
39
+ </template>
40
+
41
+ <slot />
42
+
43
+ <ModalActions
44
+ v-if="showModalActions"
45
+ :class="[
46
+ orientation === Orientation.HORIZONTAL ? 'justify-end' : '',
47
+ ]"
48
+ >
49
+ <ActionButton
50
+ :text="buttonCloseText"
51
+ :class="[
52
+ orientation === Orientation.HORIZONTAL ? 'w-full md:w-auto' : 'w-full'
53
+ ]"
54
+ @click="handleClose"
55
+ />
56
+ <ActionButton
57
+ :styleType="ButtonStyleType.DELETE_FILLED"
58
+ :iconPosition="buttonActionIcon ? IconPosition.LEFT : IconPosition.NONE"
59
+ :icon="buttonActionIcon"
60
+ :text="buttonActionText"
61
+ :isLoading
62
+ :loadingText
63
+ :class="[
64
+ orientation === Orientation.HORIZONTAL ? 'w-full md:w-auto' : 'w-full'
65
+ ]"
66
+ @click="handleMainAction"
67
+ />
68
+ </ModalActions>
69
+ </ModalContent>
70
+ </ModalDialog>
71
+ </template>
72
+
73
+ <script setup lang="ts">
74
+ // Props
75
+ defineProps({
76
+ modelValue: {
77
+ type: Boolean as PropType<boolean>,
78
+ default: false,
79
+ },
80
+ icon: {
81
+ type: String as PropType<any>,
82
+ default: 'mdiAlertOutline',
83
+ },
84
+ title: {
85
+ type: String as PropType<string>,
86
+ default: 'Modal title',
87
+ },
88
+ description: String as PropType<string>,
89
+ buttonCloseText: {
90
+ type: String as PropType<string>,
91
+ default: 'Cancel',
92
+ },
93
+ buttonActionText: {
94
+ type: String as PropType<string>,
95
+ default: 'Delete',
96
+ },
97
+ buttonActionIcon: {
98
+ type: String as PropType<any>,
99
+ default: 'mdiDeleteForeverOutline',
100
+ },
101
+ isLoading: {
102
+ type: Boolean as PropType<boolean>,
103
+ default: false,
104
+ },
105
+ loadingText: {
106
+ type: String as PropType<string>,
107
+ default: 'Processing...',
108
+ },
109
+ orientation: {
110
+ type: String as PropType<Orientation>,
111
+ default: Orientation.HORIZONTAL,
112
+ validator: (value: Orientation) => Object.values(Orientation).includes(value),
113
+ },
114
+ cardClasses: {
115
+ type: String as PropType<string>,
116
+ default: 'max-w-[520px]',
117
+ },
118
+ closeOnClickOutside: {
119
+ type: Boolean as PropType<boolean>,
120
+ default: false,
121
+ },
122
+ hasCornerCloseButton: {
123
+ type: Boolean as PropType<boolean>,
124
+ default: false,
125
+ },
126
+ showModalActions: {
127
+ type: Boolean as PropType<boolean>,
128
+ default: true,
129
+ },
130
+ })
131
+
132
+ // Emits
133
+ const emit = defineEmits(['update:modelValue', 'close', 'action'])
134
+
135
+ // Handlers
136
+ const updateModelValue = (value: boolean) => {
137
+ emit('update:modelValue', value)
138
+ }
139
+
140
+ const handleClose = () => {
141
+ updateModelValue(false)
142
+ emit('close')
143
+ }
144
+
145
+ const handleMainAction = () => {
146
+ emit('action')
147
+ updateModelValue(false)
148
+ }
149
+ </script>
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <ModalDialog
3
+ :modelValue
4
+ :closeOnClickOutside
5
+ :hasCornerCloseButton
6
+ :cardClasses
7
+ @update:modelValue="updateModelValue"
8
+ >
9
+ <ModalContent class="!gap-6 items-center">
10
+ <template v-if="orientation === Orientation.VERTICAL">
11
+ <ContainedIcon
12
+ :color="ColorAccent.INFO"
13
+ :size="IconContainerSize.XL"
14
+ :icon
15
+ />
16
+
17
+ <ModalHeaderGroup centered>
18
+ <ModalTitle :title />
19
+ <ModalDescription v-if="description">
20
+ {{ description }}
21
+ </ModalDescription>
22
+ </ModalHeaderGroup>
23
+ </template>
24
+ <template v-else>
25
+ <div class="w-full flex gap-4 flex-col sm:flex-row items-center sm:items-start">
26
+ <ContainedIcon
27
+ :color="ColorAccent.INFO"
28
+ :size="IconContainerSize.LG"
29
+ :icon
30
+ />
31
+
32
+ <ModalHeaderGroup centered class="sm:text-left">
33
+ <ModalTitle :title />
34
+ <ModalDescription v-if="description">
35
+ {{ description }}
36
+ </ModalDescription>
37
+ </ModalHeaderGroup>
38
+ </div>
39
+ </template>
40
+
41
+ <slot />
42
+
43
+ <ModalActions
44
+ v-if="showModalActions"
45
+ :class="{
46
+ 'justify-end': orientation === Orientation.HORIZONTAL,
47
+ }"
48
+ >
49
+ <ActionButton
50
+ :text="buttonCloseText"
51
+ :class="[
52
+ orientation === Orientation.HORIZONTAL ? 'w-full md:w-auto' : 'w-full',
53
+ ]"
54
+ @click="handleClose"
55
+ />
56
+ <ActionButton
57
+ :styleType="ButtonStyleType.PRIMARY_BRAND_FILLED"
58
+ :iconPosition="buttonActionIcon ? IconPosition.RIGHT : IconPosition.NONE"
59
+ :icon="buttonActionIcon"
60
+ :text="buttonActionText"
61
+ :isLoading
62
+ :loadingText
63
+ :class="[
64
+ orientation === Orientation.HORIZONTAL ? 'w-full md:w-auto' : 'w-full'
65
+ ]"
66
+ @click="handleMainAction"
67
+ />
68
+ </ModalActions>
69
+ </ModalContent>
70
+ </ModalDialog>
71
+ </template>
72
+
73
+ <script setup lang="ts">
74
+ // Props
75
+ defineProps({
76
+ modelValue: {
77
+ type: Boolean as PropType<boolean>,
78
+ default: false,
79
+ },
80
+ icon: {
81
+ type: String as PropType<any>,
82
+ default: 'mdiInformationOutline',
83
+ },
84
+ title: {
85
+ type: String as PropType<string>,
86
+ default: 'Modal title',
87
+ },
88
+ description: String as PropType<string>,
89
+ buttonCloseText: {
90
+ type: String as PropType<string>,
91
+ default: 'Close',
92
+ },
93
+ buttonActionText: String as PropType<string>,
94
+ buttonActionIcon: String as PropType<any>,
95
+ isLoading: {
96
+ type: Boolean as PropType<boolean>,
97
+ default: false,
98
+ },
99
+ loadingText: {
100
+ type: String as PropType<string>,
101
+ default: 'Processing...',
102
+ },
103
+ orientation: {
104
+ type: String as PropType<Orientation>,
105
+ default: Orientation.VERTICAL,
106
+ validator: (value: Orientation) => Object.values(Orientation).includes(value),
107
+ },
108
+ cardClasses: {
109
+ type: String as PropType<string>,
110
+ default: 'max-w-[520px]',
111
+ },
112
+ closeOnClickOutside: {
113
+ type: Boolean as PropType<boolean>,
114
+ default: false,
115
+ },
116
+ hasCornerCloseButton: {
117
+ type: Boolean as PropType<boolean>,
118
+ default: false,
119
+ },
120
+ showModalActions: {
121
+ type: Boolean as PropType<boolean>,
122
+ default: true,
123
+ },
124
+ })
125
+
126
+ // Emits
127
+ const emit = defineEmits(['update:modelValue', 'close', 'action'])
128
+
129
+ // Handlers
130
+ const updateModelValue = (value: boolean) => {
131
+ emit('update:modelValue', value)
132
+ }
133
+
134
+ const handleClose = () => {
135
+ updateModelValue(false)
136
+ emit('close')
137
+ }
138
+
139
+ const handleMainAction = () => {
140
+ emit('action')
141
+ updateModelValue(false)
142
+ }
143
+ </script>
@@ -0,0 +1,22 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ 'flex',
5
+ 'gap-4',
6
+ 'w-full',
7
+ reverseOnMobile ? 'flex-col-reverse md:flex-row' : 'flex-col md:flex-row'
8
+ ]"
9
+ >
10
+ <slot />
11
+ </div>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ // Props
16
+ defineProps({
17
+ reverseOnMobile: {
18
+ type: Boolean as PropType<boolean>,
19
+ default: true,
20
+ },
21
+ })
22
+ </script>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div class="flex flex-col gap-5">
3
+ <slot />
4
+ </div>
5
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <p class="text-text-neutral-subtle text-sm">
3
+ <slot />
4
+ </p>
5
+ </template>