@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,34 @@
1
+ <template>
2
+ <td
3
+ :class="[
4
+ 'px-3',
5
+ 'py-3.5',
6
+ 'border-t',
7
+ 'border-border-neutral-subtle',
8
+ 'text-sm',
9
+ fitToContent ? 'w-[1%]' : 'w-auto',
10
+ to ? 'hover:cursor-pointer' : undefined
11
+ ]"
12
+ @click="handleNavigation"
13
+ >
14
+ <slot />
15
+ </td>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ // Props
20
+ const props = defineProps({
21
+ fitToContent: {
22
+ type: Boolean as PropType<boolean>,
23
+ default: false,
24
+ },
25
+ to: String as PropType<string>,
26
+ })
27
+
28
+ // Navigation handler
29
+ const handleNavigation = () => {
30
+ if (props.to) {
31
+ navigateTo(props.to)
32
+ }
33
+ }
34
+ </script>
@@ -0,0 +1,7 @@
1
+ <template>
2
+ <TableCell fitToContent>
3
+ <div class="flex gap-2">
4
+ <slot />
5
+ </div>
6
+ </TableCell>
7
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <thead class="text-left text-text-neutral-subtle">
3
+ <slot />
4
+ </thead>
5
+ </template>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <th
3
+ :class="[
4
+ 'px-3',
5
+ 'py-3.5',
6
+ 'border-b',
7
+ 'border-border-neutral-subtle',
8
+ 'font-semibold',
9
+ 'text-sm',
10
+ 'whitespace-nowrap',
11
+ ]"
12
+ >
13
+ <slot />
14
+ </th>
15
+ </template>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <tr :class="isHoverable && 'hover:bg-background-neutral-subtlest'">
3
+ <slot />
4
+ </tr>
5
+ </template>
6
+ <script setup lang="ts">
7
+ // Props
8
+ defineProps({
9
+ isHoverable: {
10
+ type: Boolean as PropType<boolean>,
11
+ default: false,
12
+ },
13
+ })
14
+ </script>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ 'flex',
5
+ 'flex-col',
6
+ 'gap-3',
7
+ 'w-full',
8
+ ]"
9
+ >
10
+ <slot />
11
+ </div>
12
+ </template>
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ 'flex',
5
+ 'items-center',
6
+ 'gap-2',
7
+ 'px-3',
8
+ 'hover:cursor-pointer',
9
+ 'group',
10
+ styleClass
11
+ ]"
12
+ >
13
+ <MdiIcon
14
+ v-if="decoration === TabDecoration.ICON"
15
+ size="20"
16
+ preserveAspectRatio="xMidYMid meet"
17
+ :class="[
18
+ 'min-w-[20px]'
19
+ ]"
20
+ :icon
21
+ />
22
+
23
+ <template v-if="decoration === TabDecoration.IMAGE">
24
+ <img
25
+ v-if="imgUrl && isImageLoaded"
26
+ :src="imgUrl"
27
+ alt="Tab decoration"
28
+ class="w-[20px] h-[20px] rounded"
29
+ @load="handleImageLoad"
30
+ @error="handleImageError"
31
+ >
32
+ <img
33
+ v-else
34
+ :src="missingImagePlaceholder"
35
+ alt="Tab decoration"
36
+ class="w-[20px] h-[20px] rounded"
37
+ >
38
+ </template>
39
+
40
+ <span
41
+ :class="[
42
+ 'text-sm',
43
+ 'font-semibold',
44
+ ]"
45
+ >
46
+ {{ text }}
47
+ </span>
48
+
49
+ <Badge
50
+ v-if="computedBadgeValue"
51
+ :text="computedBadgeValue"
52
+ :styleType="active ? BadgeStyle.FILLED : BadgeStyle.FLAT"
53
+ :color="active ? ColorAccent.PRIMARY_BRAND : ColorAccent.NEUTRAL"
54
+ :shape="BadgeShape.PILL"
55
+ :class="[
56
+ !props.active && tabStyle !== TabStyle.PILL_MONOCRHOME && 'group-hover:bg-background-primary-brand-subtle-active',
57
+ ]"
58
+ />
59
+ </div>
60
+ </template>
61
+ <script setup lang="ts">
62
+ // Imports
63
+ import missingImagePlaceholder from "@/assets/images/placeholders/missing-image-placeholder.png"
64
+
65
+ // Props
66
+ const props = defineProps({
67
+ tabStyle: {
68
+ type: String as PropType<TabStyle>,
69
+ default: TabStyle.UNDERLINE,
70
+ validator: (value: TabStyle) => Object.values(TabStyle).includes(value),
71
+ },
72
+ text: {
73
+ type: String as PropType<string>,
74
+ default: 'Tab text',
75
+ },
76
+ decoration: {
77
+ type: String as PropType<TabDecoration>,
78
+ default: TabDecoration.NONE,
79
+ validator: (value: TabDecoration) => Object.values(TabDecoration).includes(value),
80
+ },
81
+ icon: {
82
+ type: String as PropType<any>,
83
+ default: 'mdiHelp',
84
+ },
85
+ imgUrl: String as PropType<string>,
86
+ active: {
87
+ type: Boolean as PropType<boolean>,
88
+ default: false,
89
+ },
90
+ badgeValue: [String, Number] as PropType<string | number>,
91
+ })
92
+
93
+ // States
94
+ const isImageLoaded = ref(true)
95
+
96
+ // Handlers for image load and error
97
+ const handleImageLoad = () => {
98
+ isImageLoaded.value = true
99
+ }
100
+
101
+ const handleImageError = () => {
102
+ isImageLoaded.value = false
103
+ }
104
+
105
+ // Computed Tailwind Classes
106
+ const styleClass = computed(() => {
107
+ const styleVariants = {
108
+ [TabStyle.UNDERLINE]: [
109
+ 'min-h-[52px]',
110
+ 'border-b-2',
111
+ props.active ?
112
+ 'border-b-border-primary-brand-default text-text-primary-brand-active'
113
+ : 'border-b-border-inactive text-text-neutral-inactive, hover:text-text-primary-brand-hover hover:border-b-border-primary-brand-hover',
114
+ ],
115
+ [TabStyle.PILL]: [
116
+ 'min-h-[40px]',
117
+ 'rounded',
118
+ props.active ?
119
+ 'text-text-primary-brand-active bg-background-primary-brand-subtle-active'
120
+ : 'text-text-neutral-inactive hover:text-text-primary-brand-hover',
121
+ ],
122
+ [TabStyle.PILL_MONOCRHOME]: [
123
+ 'min-h-[40px]',
124
+ 'rounded',
125
+ props.active ?
126
+ 'text-text-neutral-on-monochrome-active-bg bg-background-neutral-active'
127
+ : 'text-text-neutral-inactive hover:text-text-neutral-on-monochrome-hover-bg',
128
+ ],
129
+ }
130
+ return styleVariants[props.tabStyle as TabStyle] || [
131
+ 'min-h-[52px]',
132
+ 'border-b-2',
133
+ props.active ?
134
+ 'border-b-border-primary-brand-default text-text-primary-brand-active'
135
+ : 'border-b-border-inactive text-text-neutral-inactive, hover:text-text-primary-brand-hover hover:border-b-border-primary-brand-hover',
136
+ ]
137
+ })
138
+
139
+ // Computed functions
140
+ const computedBadgeValue = computed(() => {
141
+ if (props.badgeValue === null || props.badgeValue === undefined) return null
142
+
143
+ return typeof props.badgeValue === 'number' ? props.badgeValue.toString() : props.badgeValue
144
+ })
145
+ </script>
@@ -0,0 +1,64 @@
1
+ <template>
2
+ <div class="flex flex-wrap">
3
+ <Tab
4
+ v-for="(tab, index) in tabs"
5
+ :key="index"
6
+ :text="tab.text"
7
+ :icon="tab.icon"
8
+ :imgUrl="tab.imgUrl"
9
+ :badgeValue="tab.badgeValue"
10
+ :active="index === activeIndex"
11
+ :tabStyle
12
+ :decoration
13
+ @click="handleTabClick(index, tab.to)"
14
+ />
15
+ </div>
16
+ </template>
17
+
18
+ <script setup lang="ts">
19
+ // Props
20
+ const props = defineProps({
21
+ tabs: {
22
+ type: Array as PropType<TabItem[]>,
23
+ default: () => [
24
+ {
25
+ text: 'Tab 1',
26
+ },
27
+ {
28
+ text: 'Tab 2',
29
+ },
30
+ {
31
+ text: 'Tab 3',
32
+ },
33
+ ],
34
+ },
35
+ modelValue: {
36
+ type: Number as PropType<number>,
37
+ default: 0,
38
+ },
39
+ tabStyle: String as PropType<TabStyle>,
40
+ decoration: String as PropType<TabDecoration>,
41
+ })
42
+
43
+ // Local
44
+ const activeIndex = ref(props.modelValue)
45
+
46
+ // Emit Event
47
+ const emit = defineEmits(['update:modelValue'])
48
+
49
+ // Methods
50
+ const handleTabClick = (index: number, to?: string) => {
51
+ if(to) { // If the to is provided, navigate to the route
52
+ navigateTo(to)
53
+ return
54
+ }
55
+
56
+ activeIndex.value = index
57
+ emit('update:modelValue', index)
58
+ }
59
+
60
+ // Watchers
61
+ watch(() => props.modelValue, (newVal) => {
62
+ activeIndex.value = newVal
63
+ })
64
+ </script>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div class="flex flex-col gap-6 w-full">
3
+ <slot />
4
+ </div>
5
+ </template>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div class="flex flex-col gap-6 w-full">
3
+ <slot />
4
+ </div>
5
+ </template>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <transition
3
+ enter-active-class="transition-all duration-300 ease-out"
4
+ enter-from-class="translate-x-full opacity-0"
5
+ enter-to-class="translate-x-0 opacity-100"
6
+ leave-active-class="transition-all duration-300 ease-in"
7
+ leave-from-class="translate-x-0 opacity-100"
8
+ leave-to-class="translate-x-full opacity-0"
9
+ >
10
+ <slot></slot>
11
+ </transition>
12
+ </template>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <transition
3
+ enter-active-class="transition-all duration-300 ease-in-out"
4
+ enter-from-class="max-h-0 opacity-0"
5
+ enter-to-class="max-h-96 opacity-100"
6
+ leave-active-class="transition-all duration-300 ease-in-out"
7
+ leave-from-class="max-h-96 opacity-100"
8
+ leave-to-class="max-h-0 opacity-0"
9
+ >
10
+ <div class="overflow-hidden">
11
+ <slot></slot>
12
+ </div>
13
+ </transition>
14
+ </template>
@@ -0,0 +1,113 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ 'flex',
5
+ spacingClass,
6
+ !role && 'items-center',
7
+ layoutOrientation === Orientation.VERTICAL && 'flex-col',
8
+ detailsOrientation === Orientation.HORIZONTAL && 'items-center',
9
+ layoutOrientation === Orientation.VERTICAL && verticalLayoutAlign === Align.CENTER && 'items-center text-center'
10
+ ]"
11
+ >
12
+ <Avatar
13
+ :displayName="name"
14
+ :size
15
+ :shape
16
+ :imgUrl
17
+ />
18
+
19
+ <div
20
+ :class="[
21
+ 'flex',
22
+ detailsOrientation === Orientation.VERTICAL ? 'flex-col gap-1' : 'gap-2',
23
+ ]"
24
+ >
25
+ <span
26
+ :class="[
27
+ 'font-semibold',
28
+ nameClass
29
+ ]"
30
+ >
31
+ {{ name }}
32
+ </span>
33
+ <span
34
+ v-if="detailsOrientation == Orientation.HORIZONTAL"
35
+ class="text-border-default"
36
+ >
37
+ |
38
+ </span>
39
+ <span
40
+ v-if="role"
41
+ :class="[
42
+ 'text-text-neutral-subtle',
43
+ detailsOrientation === Orientation.VERTICAL ? roleClass : nameClass,
44
+ ]"
45
+ >
46
+ {{ role }}
47
+ </span>
48
+ </div>
49
+ </div>
50
+ </template>
51
+ <script setup lang="ts">
52
+ // Props
53
+ const props = defineProps({
54
+ name: {
55
+ type: String as PropType<string>,
56
+ default: 'John Doe'
57
+ },
58
+ role: String as PropType<string>,
59
+ imgUrl: String as PropType<string>,
60
+ layoutOrientation: {
61
+ type: String as PropType<Orientation>,
62
+ default: Orientation.HORIZONTAL,
63
+ validator: (value: Orientation) => Object.values(Orientation).includes(value)
64
+ },
65
+ detailsOrientation: {
66
+ type: String as PropType<Orientation>,
67
+ default: Orientation.VERTICAL,
68
+ validator: (value: Orientation) => Object.values(Orientation).includes(value)
69
+ },
70
+ verticalLayoutAlign: {
71
+ type: String as PropType<Align.LEFT | Align.CENTER>,
72
+ default: Align.LEFT,
73
+ validator: (value: Align) => [Align.LEFT, Align.CENTER].includes(value)
74
+ },
75
+ shape: {
76
+ type: String as PropType<AvatarShape>,
77
+ default: AvatarShape.CIRCLE,
78
+ validator: (value: AvatarShape) => Object.values(AvatarShape).includes(value),
79
+ },
80
+ size: {
81
+ type: String as PropType<AvatarSize.XS | AvatarSize.SM | AvatarSize.MD>,
82
+ default: AvatarSize.SM,
83
+ validator: (value: AvatarSize) => [AvatarSize.XS, AvatarSize.SM, AvatarSize.MD].includes(value),
84
+ },
85
+ })
86
+
87
+ const spacingClass = computed(() => {
88
+ const variants = {
89
+ [AvatarSize.XS]: 'gap-2',
90
+ [AvatarSize.SM]: 'gap-2',
91
+ [AvatarSize.MD]: 'gap-3',
92
+ }
93
+ return variants[props.size as AvatarSize.XS | AvatarSize.SM | AvatarSize.MD] || 'gap-2'
94
+ })
95
+
96
+ const nameClass = computed(() => {
97
+ const variants = {
98
+ [AvatarSize.XS]: 'text-xs',
99
+ [AvatarSize.SM]: 'text-sm',
100
+ [AvatarSize.MD]: 'text-base',
101
+ }
102
+ return variants[props.size as AvatarSize.XS | AvatarSize.SM | AvatarSize.MD] || 'text-sm'
103
+ })
104
+
105
+ const roleClass = computed(() => {
106
+ const variants = {
107
+ [AvatarSize.XS]: 'text-xs',
108
+ [AvatarSize.SM]: 'text-xs',
109
+ [AvatarSize.MD]: 'text-sm',
110
+ }
111
+ return variants[props.size as AvatarSize.XS | AvatarSize.SM | AvatarSize.MD] || 'text-xs'
112
+ })
113
+ </script>
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <div
3
+ :class="[
4
+ 'inline-flex items-center font-semibold',
5
+ isInteractive && 'group hover:cursor-pointer',
6
+ containerClass
7
+ ]"
8
+ >
9
+ <Avatar
10
+ :displayName
11
+ :imgUrl
12
+ :size="avatarSize ? avatarSize : size"
13
+ :shape
14
+ :class="`${isInteractive && 'group-hover:border-2 group-hover:border-border-primary-brand-default'}`"
15
+ />
16
+ <span>{{ trimText(displayName, 20) }}</span>
17
+ </div>
18
+ </template>
19
+ <script setup lang="ts">
20
+ // Props
21
+ const props = defineProps({
22
+ displayName: {
23
+ type: String as PropType<string>,
24
+ default: 'Test username',
25
+ },
26
+ shape: {
27
+ type: String as PropType<AvatarShape>,
28
+ default: AvatarShape.CIRCLE,
29
+ validator: (value: AvatarShape) => Object.values(AvatarShape).includes(value),
30
+ },
31
+ size: {
32
+ type: String as PropType<AvatarSize.XS | AvatarSize.SM | AvatarSize.MD>,
33
+ default: AvatarSize.XS,
34
+ validator: (value: AvatarSize) => [AvatarSize.XS, AvatarSize.SM, AvatarSize.MD].includes(value),
35
+ },
36
+ avatarSize: String as PropType<AvatarSize.XS | AvatarSize.SM | AvatarSize.MD>,
37
+ isInteractive: {
38
+ type: Boolean as PropType<boolean>,
39
+ default: false,
40
+ },
41
+ imgUrl: String as PropType<string>,
42
+ })
43
+
44
+ // Computed classes
45
+ const containerClass = computed(() => {
46
+ const variants = {
47
+ [AvatarSize.XS]: 'text-xs gap-2',
48
+ [AvatarSize.SM]: 'text-sm gap-2',
49
+ [AvatarSize.MD]: 'gap-3',
50
+ }
51
+ return variants[props.size as AvatarSize.XS | AvatarSize.SM | AvatarSize.MD] || 'gap-2'
52
+ })
53
+ </script>
@@ -0,0 +1,12 @@
1
+ export const useAccordion = () => {
2
+ const isOpen = ref(false)
3
+
4
+ const toggle = () => {
5
+ isOpen.value = !isOpen.value
6
+ }
7
+
8
+ return {
9
+ isOpen,
10
+ toggle
11
+ }
12
+ }
@@ -0,0 +1,9 @@
1
+ export const useDarkMode = () => {
2
+ const isDark = useDark()
3
+ const toggleDark = useToggle(isDark)
4
+
5
+ return {
6
+ isDark,
7
+ toggleDark
8
+ }
9
+ }
@@ -0,0 +1,25 @@
1
+
2
+ export const useDropdownMenu = () => {
3
+ const isDropdownMenuOpen = ref(false)
4
+
5
+ const toggleDropdownMenu = () => {
6
+ isDropdownMenuOpen.value = !isDropdownMenuOpen.value
7
+ }
8
+
9
+ const closeDropdownMenu = () => {
10
+ isDropdownMenuOpen.value = false
11
+ }
12
+
13
+ const closeDropdownOnClickOutside = (elementRef: Ref<HTMLElement | null>) => {
14
+ useClickOutside(elementRef, () => {
15
+ closeDropdownMenu()
16
+ })
17
+ }
18
+
19
+ return {
20
+ isDropdownMenuOpen,
21
+ toggleDropdownMenu,
22
+ closeDropdownOnClickOutside,
23
+ closeDropdownMenu
24
+ }
25
+ }