@pyreweb/fabric 1.2.6

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 (210) hide show
  1. package/README.md +119 -0
  2. package/dist/fabric.cjs.js +18109 -0
  3. package/dist/fabric.css +2180 -0
  4. package/dist/fabric.esm.js +18062 -0
  5. package/dist/fabric.min.js +18112 -0
  6. package/dist/types/components/atoms/FAvatar/FAvatar.test.d.ts +1 -0
  7. package/dist/types/components/atoms/FBadge/FBadge.test.d.ts +1 -0
  8. package/dist/types/components/atoms/FButton/FButton.test.d.ts +1 -0
  9. package/dist/types/components/atoms/FCheckbox/FCheckbox.test.d.ts +1 -0
  10. package/dist/types/components/atoms/FDivider/FDivider.test.d.ts +1 -0
  11. package/dist/types/components/atoms/FIcon/FIcon.test.d.ts +1 -0
  12. package/dist/types/components/atoms/FInput/FInput.test.d.ts +1 -0
  13. package/dist/types/components/atoms/FLoader/FLoader.test.d.ts +1 -0
  14. package/dist/types/components/atoms/FRadio/FRadio.test.d.ts +1 -0
  15. package/dist/types/components/atoms/FTextarea/FTextarea.test.d.ts +1 -0
  16. package/dist/types/components/atoms/FToggle/FToggle.test.d.ts +1 -0
  17. package/dist/types/components/atoms/FTypography/FTypography.test.d.ts +1 -0
  18. package/dist/types/components/atoms/index.d.ts +13 -0
  19. package/dist/types/components/molecules/FAccordionItem/FAccordionItem.test.d.ts +1 -0
  20. package/dist/types/components/molecules/FAlert/FAlert.test.d.ts +1 -0
  21. package/dist/types/components/molecules/FBreadcrumb/FBreadcrumb.test.d.ts +1 -0
  22. package/dist/types/components/molecules/FButtonGroup/FButtonGroup.test.d.ts +1 -0
  23. package/dist/types/components/molecules/FCard/FCard.test.d.ts +1 -0
  24. package/dist/types/components/molecules/FDatePicker/FDatePicker.test.d.ts +1 -0
  25. package/dist/types/components/molecules/FEmptyState/FEmptyState.test.d.ts +1 -0
  26. package/dist/types/components/molecules/FFilePreview/FFilePreview.test.d.ts +1 -0
  27. package/dist/types/components/molecules/FFormField/FFormField.test.d.ts +1 -0
  28. package/dist/types/components/molecules/FListItem/FListItem.test.d.ts +1 -0
  29. package/dist/types/components/molecules/FPagination/FPagination.test.d.ts +1 -0
  30. package/dist/types/components/molecules/FSearchBar/FSearchBar.test.d.ts +1 -0
  31. package/dist/types/components/molecules/FSelect/FSelect.test.d.ts +1 -0
  32. package/dist/types/components/molecules/FStatCard/FStatCard.test.d.ts +1 -0
  33. package/dist/types/components/molecules/FTabs/FTabs.test.d.ts +1 -0
  34. package/dist/types/components/molecules/FToast/FToast.test.d.ts +1 -0
  35. package/dist/types/components/molecules/index.d.ts +18 -0
  36. package/dist/types/components/organisms/FActivityFeed/FActivityFeed.test.d.ts +1 -0
  37. package/dist/types/components/organisms/FDataTable/FDataTable.test.d.ts +1 -0
  38. package/dist/types/components/organisms/FDrawer/FDrawer.test.d.ts +1 -0
  39. package/dist/types/components/organisms/FFileUpload/FFileUpload.test.d.ts +1 -0
  40. package/dist/types/components/organisms/FFilterSidebar/FFilterSidebar.test.d.ts +1 -0
  41. package/dist/types/components/organisms/FForm/FForm.test.d.ts +1 -0
  42. package/dist/types/components/organisms/FModal/FModal.test.d.ts +1 -0
  43. package/dist/types/components/organisms/FNavigationSidebar/FNavigationSidebar.test.d.ts +1 -0
  44. package/dist/types/components/organisms/FOnboardingStepper/FOnboardingStepper.test.d.ts +1 -0
  45. package/dist/types/components/organisms/FOnboardingStepper/FStepperProgress.test.d.ts +1 -0
  46. package/dist/types/components/organisms/FPageHeader/FPageHeader.test.d.ts +1 -0
  47. package/dist/types/components/organisms/FProfileSection/FProfileSection.test.d.ts +1 -0
  48. package/dist/types/components/organisms/FToastProvider/FToastProvider.test.d.ts +1 -0
  49. package/dist/types/components/organisms/FUserMenu/FUserMenu.test.d.ts +1 -0
  50. package/dist/types/components/organisms/index.d.ts +14 -0
  51. package/dist/types/components/utils/FThemeProvider.test.d.ts +1 -0
  52. package/dist/types/components/utils/index.d.ts +2 -0
  53. package/dist/types/components.d.ts +602 -0
  54. package/dist/types/composables/index.d.ts +12 -0
  55. package/dist/types/composables/useDataTableState.d.ts +106 -0
  56. package/dist/types/composables/useDataTableState.test.d.ts +1 -0
  57. package/dist/types/composables/useFormValidation.d.ts +49 -0
  58. package/dist/types/composables/useFormValidation.test.d.ts +1 -0
  59. package/dist/types/composables/useSidebarState.d.ts +65 -0
  60. package/dist/types/composables/useSidebarState.test.d.ts +1 -0
  61. package/dist/types/index.d.ts +19 -0
  62. package/dist/types/types.d.ts +529 -0
  63. package/package.json +100 -0
  64. package/src/components/atoms/FAvatar/FAvatar.stories.js +100 -0
  65. package/src/components/atoms/FAvatar/FAvatar.test.ts +95 -0
  66. package/src/components/atoms/FAvatar/FAvatar.vue +190 -0
  67. package/src/components/atoms/FBadge/FBadge.stories.js +129 -0
  68. package/src/components/atoms/FBadge/FBadge.test.ts +93 -0
  69. package/src/components/atoms/FBadge/FBadge.vue +103 -0
  70. package/src/components/atoms/FButton/FButton.stories.js +122 -0
  71. package/src/components/atoms/FButton/FButton.test.ts +98 -0
  72. package/src/components/atoms/FButton/FButton.vue +147 -0
  73. package/src/components/atoms/FCheckbox/FCheckbox.stories.js +96 -0
  74. package/src/components/atoms/FCheckbox/FCheckbox.test.ts +64 -0
  75. package/src/components/atoms/FCheckbox/FCheckbox.vue +76 -0
  76. package/src/components/atoms/FDivider/FDivider.stories.js +104 -0
  77. package/src/components/atoms/FDivider/FDivider.test.ts +80 -0
  78. package/src/components/atoms/FDivider/FDivider.vue +117 -0
  79. package/src/components/atoms/FIcon/FIcon.stories.js +189 -0
  80. package/src/components/atoms/FIcon/FIcon.test.ts +99 -0
  81. package/src/components/atoms/FIcon/FIcon.vue +192 -0
  82. package/src/components/atoms/FInput/FInput.stories.js +119 -0
  83. package/src/components/atoms/FInput/FInput.test.ts +79 -0
  84. package/src/components/atoms/FInput/FInput.vue +88 -0
  85. package/src/components/atoms/FLoader/FLoader.stories.js +109 -0
  86. package/src/components/atoms/FLoader/FLoader.test.ts +66 -0
  87. package/src/components/atoms/FLoader/FLoader.vue +97 -0
  88. package/src/components/atoms/FRadio/FRadio.stories.js +105 -0
  89. package/src/components/atoms/FRadio/FRadio.test.ts +75 -0
  90. package/src/components/atoms/FRadio/FRadio.vue +119 -0
  91. package/src/components/atoms/FTextarea/FTextarea.stories.js +126 -0
  92. package/src/components/atoms/FTextarea/FTextarea.test.ts +94 -0
  93. package/src/components/atoms/FTextarea/FTextarea.vue +156 -0
  94. package/src/components/atoms/FToggle/FToggle.stories.js +108 -0
  95. package/src/components/atoms/FToggle/FToggle.test.ts +96 -0
  96. package/src/components/atoms/FToggle/FToggle.vue +123 -0
  97. package/src/components/atoms/FTypography/FTypography.stories.js +127 -0
  98. package/src/components/atoms/FTypography/FTypography.test.ts +93 -0
  99. package/src/components/atoms/FTypography/FTypography.vue +78 -0
  100. package/src/components/atoms/index.ts +27 -0
  101. package/src/components/molecules/FAccordionItem/FAccordionItem.stories.js +71 -0
  102. package/src/components/molecules/FAccordionItem/FAccordionItem.test.ts +61 -0
  103. package/src/components/molecules/FAccordionItem/FAccordionItem.vue +105 -0
  104. package/src/components/molecules/FAlert/FAlert.stories.js +87 -0
  105. package/src/components/molecules/FAlert/FAlert.test.ts +59 -0
  106. package/src/components/molecules/FAlert/FAlert.vue +108 -0
  107. package/src/components/molecules/FBreadcrumb/FBreadcrumb.stories.js +90 -0
  108. package/src/components/molecules/FBreadcrumb/FBreadcrumb.test.ts +76 -0
  109. package/src/components/molecules/FBreadcrumb/FBreadcrumb.vue +117 -0
  110. package/src/components/molecules/FButtonGroup/FButtonGroup.stories.js +82 -0
  111. package/src/components/molecules/FButtonGroup/FButtonGroup.test.ts +44 -0
  112. package/src/components/molecules/FButtonGroup/FButtonGroup.vue +31 -0
  113. package/src/components/molecules/FCard/FCard.stories.js +136 -0
  114. package/src/components/molecules/FCard/FCard.test.ts +87 -0
  115. package/src/components/molecules/FCard/FCard.vue +75 -0
  116. package/src/components/molecules/FDatePicker/FDatePicker.stories.js +305 -0
  117. package/src/components/molecules/FDatePicker/FDatePicker.test.ts +282 -0
  118. package/src/components/molecules/FDatePicker/FDatePicker.vue +750 -0
  119. package/src/components/molecules/FEmptyState/FEmptyState.stories.js +98 -0
  120. package/src/components/molecules/FEmptyState/FEmptyState.test.ts +82 -0
  121. package/src/components/molecules/FEmptyState/FEmptyState.vue +89 -0
  122. package/src/components/molecules/FFilePreview/FFilePreview.stories.js +130 -0
  123. package/src/components/molecules/FFilePreview/FFilePreview.test.ts +70 -0
  124. package/src/components/molecules/FFilePreview/FFilePreview.vue +125 -0
  125. package/src/components/molecules/FFormField/FFormField.stories.js +149 -0
  126. package/src/components/molecules/FFormField/FFormField.test.ts +85 -0
  127. package/src/components/molecules/FFormField/FFormField.vue +107 -0
  128. package/src/components/molecules/FListItem/FListItem.stories.js +158 -0
  129. package/src/components/molecules/FListItem/FListItem.test.ts +93 -0
  130. package/src/components/molecules/FListItem/FListItem.vue +113 -0
  131. package/src/components/molecules/FPagination/FPagination.stories.js +132 -0
  132. package/src/components/molecules/FPagination/FPagination.test.ts +79 -0
  133. package/src/components/molecules/FPagination/FPagination.vue +206 -0
  134. package/src/components/molecules/FSearchBar/FSearchBar.stories.js +129 -0
  135. package/src/components/molecules/FSearchBar/FSearchBar.test.ts +81 -0
  136. package/src/components/molecules/FSearchBar/FSearchBar.vue +180 -0
  137. package/src/components/molecules/FSelect/FSelect.stories.js +333 -0
  138. package/src/components/molecules/FSelect/FSelect.test.ts +478 -0
  139. package/src/components/molecules/FSelect/FSelect.vue +551 -0
  140. package/src/components/molecules/FStatCard/FStatCard.stories.js +144 -0
  141. package/src/components/molecules/FStatCard/FStatCard.test.ts +78 -0
  142. package/src/components/molecules/FStatCard/FStatCard.vue +106 -0
  143. package/src/components/molecules/FTabs/FTab.vue +63 -0
  144. package/src/components/molecules/FTabs/FTabs.stories.js +277 -0
  145. package/src/components/molecules/FTabs/FTabs.test.ts +264 -0
  146. package/src/components/molecules/FTabs/FTabs.vue +273 -0
  147. package/src/components/molecules/FToast/FToast.stories.js +150 -0
  148. package/src/components/molecules/FToast/FToast.test.ts +157 -0
  149. package/src/components/molecules/FToast/FToast.vue +283 -0
  150. package/src/components/molecules/index.ts +37 -0
  151. package/src/components/organisms/FActivityFeed/FActivityFeed.stories.js +217 -0
  152. package/src/components/organisms/FActivityFeed/FActivityFeed.test.ts +134 -0
  153. package/src/components/organisms/FActivityFeed/FActivityFeed.vue +589 -0
  154. package/src/components/organisms/FDataTable/FDataTable.stories.js +370 -0
  155. package/src/components/organisms/FDataTable/FDataTable.test.ts +248 -0
  156. package/src/components/organisms/FDataTable/FDataTable.vue +808 -0
  157. package/src/components/organisms/FDrawer/FDrawer.stories.js +296 -0
  158. package/src/components/organisms/FDrawer/FDrawer.test.ts +142 -0
  159. package/src/components/organisms/FDrawer/FDrawer.vue +303 -0
  160. package/src/components/organisms/FFileUpload/FFileUpload.stories.js +162 -0
  161. package/src/components/organisms/FFileUpload/FFileUpload.test.ts +103 -0
  162. package/src/components/organisms/FFileUpload/FFileUpload.vue +616 -0
  163. package/src/components/organisms/FFilterSidebar/FFilterSidebar.stories.js +161 -0
  164. package/src/components/organisms/FFilterSidebar/FFilterSidebar.test.ts +92 -0
  165. package/src/components/organisms/FFilterSidebar/FFilterSidebar.vue +458 -0
  166. package/src/components/organisms/FForm/FForm.stories.js +270 -0
  167. package/src/components/organisms/FForm/FForm.test.ts +63 -0
  168. package/src/components/organisms/FForm/FForm.vue +19 -0
  169. package/src/components/organisms/FModal/FModal.stories.js +227 -0
  170. package/src/components/organisms/FModal/FModal.test.ts +181 -0
  171. package/src/components/organisms/FModal/FModal.vue +319 -0
  172. package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.stories.js +176 -0
  173. package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.test.ts +95 -0
  174. package/src/components/organisms/FNavigationSidebar/FNavigationSidebar.vue +577 -0
  175. package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.stories.js +197 -0
  176. package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.test.ts +114 -0
  177. package/src/components/organisms/FOnboardingStepper/FOnboardingStepper.vue +212 -0
  178. package/src/components/organisms/FOnboardingStepper/FStepperProgress.stories.js +122 -0
  179. package/src/components/organisms/FOnboardingStepper/FStepperProgress.test.ts +130 -0
  180. package/src/components/organisms/FOnboardingStepper/FStepperProgress.vue +146 -0
  181. package/src/components/organisms/FPageHeader/FPageHeader.stories.js +142 -0
  182. package/src/components/organisms/FPageHeader/FPageHeader.test.ts +83 -0
  183. package/src/components/organisms/FPageHeader/FPageHeader.vue +241 -0
  184. package/src/components/organisms/FProfileSection/FProfileSection.stories.js +190 -0
  185. package/src/components/organisms/FProfileSection/FProfileSection.test.ts +85 -0
  186. package/src/components/organisms/FProfileSection/FProfileSection.vue +562 -0
  187. package/src/components/organisms/FToastProvider/FToastProvider.stories.js +290 -0
  188. package/src/components/organisms/FToastProvider/FToastProvider.test.ts +215 -0
  189. package/src/components/organisms/FToastProvider/FToastProvider.vue +214 -0
  190. package/src/components/organisms/FUserMenu/FUserMenu.stories.js +170 -0
  191. package/src/components/organisms/FUserMenu/FUserMenu.test.ts +102 -0
  192. package/src/components/organisms/FUserMenu/FUserMenu.vue +407 -0
  193. package/src/components/organisms/index.ts +29 -0
  194. package/src/components/utils/FThemeProvider.stories.js +236 -0
  195. package/src/components/utils/FThemeProvider.test.ts +244 -0
  196. package/src/components/utils/FThemeProvider.vue +191 -0
  197. package/src/components/utils/index.ts +3 -0
  198. package/src/components.d.ts +602 -0
  199. package/src/composables/README.md +233 -0
  200. package/src/composables/index.ts +25 -0
  201. package/src/composables/useDataTableState.test.ts +378 -0
  202. package/src/composables/useDataTableState.ts +361 -0
  203. package/src/composables/useFormValidation.test.ts +198 -0
  204. package/src/composables/useFormValidation.ts +178 -0
  205. package/src/composables/useSidebarState.test.ts +307 -0
  206. package/src/composables/useSidebarState.ts +201 -0
  207. package/src/env.d.ts +14 -0
  208. package/src/index.ts +167 -0
  209. package/src/styles/tailwind.css +173 -0
  210. package/src/types.ts +740 -0
@@ -0,0 +1,241 @@
1
+ <template>
2
+ <header :class="headerClasses">
3
+ <!-- Breadcrumb section -->
4
+ <div v-if="showBreadcrumb" class="mb-4">
5
+ <f-breadcrumb
6
+ :items="breadcrumbItems"
7
+ :separator-icon="breadcrumbSeparatorIcon"
8
+ :aria-label="breadcrumbAriaLabel"
9
+ @navigate="handleBreadcrumbNavigate"
10
+ />
11
+ </div>
12
+
13
+ <!-- Main header content -->
14
+ <div :class="contentClasses">
15
+ <!-- Left section: Avatar + Title -->
16
+ <div :class="titleSectionClasses">
17
+ <!-- Avatar (optional) -->
18
+ <f-avatar
19
+ v-if="showAvatar"
20
+ :src="avatarSrc"
21
+ :alt="avatarAlt"
22
+ :initials="avatarInitials"
23
+ :name="avatarName"
24
+ :size="avatarSize"
25
+ :shape="avatarShape"
26
+ :status="avatarStatus"
27
+ class="flex-shrink-0"
28
+ />
29
+
30
+ <!-- Title and subtitle -->
31
+ <div class="flex-1 min-w-0">
32
+ <f-typography :variant="titleVariant" :truncate="truncateTitle">
33
+ <slot name="title">{{ title }}</slot>
34
+ </f-typography>
35
+ <f-typography
36
+ v-if="subtitle || $slots.subtitle"
37
+ variant="body"
38
+ tag="p"
39
+ class="text-neutral-500 mt-1"
40
+ >
41
+ <slot name="subtitle">{{ subtitle }}</slot>
42
+ </f-typography>
43
+ </div>
44
+ </div>
45
+
46
+ <!-- Right section: Actions -->
47
+ <div v-if="$slots.actions" :class="actionsClasses">
48
+ <slot name="actions" />
49
+ </div>
50
+ </div>
51
+ </header>
52
+ </template>
53
+
54
+ <script>
55
+ import FBreadcrumb from '../../molecules/FBreadcrumb/FBreadcrumb.vue';
56
+ import FTypography from '../../atoms/FTypography/FTypography.vue';
57
+ import FAvatar from '../../atoms/FAvatar/FAvatar.vue';
58
+
59
+ export default {
60
+ name: 'FPageHeader',
61
+ components: {
62
+ FBreadcrumb,
63
+ FTypography,
64
+ FAvatar
65
+ },
66
+ props: {
67
+ /**
68
+ * Page title
69
+ */
70
+ title: {
71
+ type: String,
72
+ default: ''
73
+ },
74
+ /**
75
+ * Page subtitle (optional description under the title)
76
+ */
77
+ subtitle: {
78
+ type: String,
79
+ default: ''
80
+ },
81
+ /**
82
+ * Title typography variant
83
+ */
84
+ titleVariant: {
85
+ type: String,
86
+ default: 'h1',
87
+ validator: (value) => ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(value)
88
+ },
89
+ /**
90
+ * Truncate title if it overflows
91
+ */
92
+ truncateTitle: {
93
+ type: Boolean,
94
+ default: false
95
+ },
96
+ /**
97
+ * Breadcrumb items array
98
+ * Each item: { label: string, href?: string, icon?: string }
99
+ */
100
+ breadcrumbItems: {
101
+ type: Array,
102
+ default: () => []
103
+ },
104
+ /**
105
+ * Breadcrumb separator icon
106
+ */
107
+ breadcrumbSeparatorIcon: {
108
+ type: String,
109
+ default: 'chevron-right'
110
+ },
111
+ /**
112
+ * Breadcrumb ARIA label
113
+ */
114
+ breadcrumbAriaLabel: {
115
+ type: String,
116
+ default: "Fil d'Ariane"
117
+ },
118
+ /**
119
+ * Avatar image source URL
120
+ */
121
+ avatarSrc: {
122
+ type: String,
123
+ default: ''
124
+ },
125
+ /**
126
+ * Avatar alt text
127
+ */
128
+ avatarAlt: {
129
+ type: String,
130
+ default: ''
131
+ },
132
+ /**
133
+ * Avatar initials (used when no image)
134
+ */
135
+ avatarInitials: {
136
+ type: String,
137
+ default: ''
138
+ },
139
+ /**
140
+ * Avatar name (used to compute initials if no initials provided)
141
+ */
142
+ avatarName: {
143
+ type: String,
144
+ default: ''
145
+ },
146
+ /**
147
+ * Avatar size
148
+ */
149
+ avatarSize: {
150
+ type: String,
151
+ default: 'lg',
152
+ validator: (value) => ['xs', 'sm', 'md', 'lg', 'xl'].includes(value)
153
+ },
154
+ /**
155
+ * Avatar shape
156
+ */
157
+ avatarShape: {
158
+ type: String,
159
+ default: 'circle',
160
+ validator: (value) => ['circle', 'square'].includes(value)
161
+ },
162
+ /**
163
+ * Avatar status indicator
164
+ */
165
+ avatarStatus: {
166
+ type: String,
167
+ default: null,
168
+ validator: (value) =>
169
+ [null, 'online', 'busy', 'away', 'offline'].includes(value)
170
+ },
171
+ /**
172
+ * Visual separator below the header
173
+ */
174
+ separator: {
175
+ type: Boolean,
176
+ default: false
177
+ }
178
+ },
179
+ computed: {
180
+ /**
181
+ * Check if breadcrumb should be displayed
182
+ */
183
+ showBreadcrumb() {
184
+ return this.breadcrumbItems && this.breadcrumbItems.length > 0;
185
+ },
186
+ /**
187
+ * Check if avatar should be displayed
188
+ */
189
+ showAvatar() {
190
+ return this.avatarSrc || this.avatarInitials || this.avatarName;
191
+ },
192
+ /**
193
+ * Main header container classes
194
+ */
195
+ headerClasses() {
196
+ const baseClasses = 'w-full';
197
+ const paddingClasses = 'pb-4';
198
+ const separatorClasses = this.separator
199
+ ? 'border-b border-neutral-200'
200
+ : '';
201
+
202
+ return [baseClasses, paddingClasses, separatorClasses]
203
+ .filter(Boolean)
204
+ .join(' ');
205
+ },
206
+ /**
207
+ * Content section classes (title + actions)
208
+ */
209
+ contentClasses() {
210
+ return [
211
+ 'flex',
212
+ 'flex-col',
213
+ 'sm:flex-row',
214
+ 'sm:items-center',
215
+ 'sm:justify-between',
216
+ 'gap-4'
217
+ ].join(' ');
218
+ },
219
+ /**
220
+ * Title section classes (avatar + title)
221
+ */
222
+ titleSectionClasses() {
223
+ return 'flex items-center gap-4 min-w-0 flex-1';
224
+ },
225
+ /**
226
+ * Actions section classes
227
+ */
228
+ actionsClasses() {
229
+ return 'flex-shrink-0 self-start sm:self-center';
230
+ }
231
+ },
232
+ methods: {
233
+ /**
234
+ * Handle breadcrumb navigation event
235
+ */
236
+ handleBreadcrumbNavigate(payload) {
237
+ this.$emit('breadcrumb-navigate', payload);
238
+ }
239
+ }
240
+ };
241
+ </script>
@@ -0,0 +1,190 @@
1
+ import FProfileSection from './FProfileSection.vue';
2
+ import FButton from '../../atoms/FButton/FButton.vue';
3
+ import FBadge from '../../atoms/FBadge/FBadge.vue';
4
+ import FStatCard from '../../molecules/FStatCard/FStatCard.vue';
5
+
6
+ export default {
7
+ title: 'Organisms/FProfileSection',
8
+ component: FProfileSection,
9
+ tags: ['autodocs'],
10
+ argTypes: {
11
+ name: {
12
+ control: 'text',
13
+ description: "Nom de l'utilisateur"
14
+ },
15
+ email: {
16
+ control: 'text',
17
+ description: 'Email'
18
+ },
19
+ role: {
20
+ control: 'text',
21
+ description: 'Rôle/Titre'
22
+ },
23
+ avatarSrc: {
24
+ control: 'text',
25
+ description: "URL de l'avatar"
26
+ },
27
+ avatarSize: {
28
+ control: { type: 'select' },
29
+ options: ['sm', 'md', 'lg', 'xl'],
30
+ description: "Taille de l'avatar"
31
+ },
32
+ layout: {
33
+ control: { type: 'select' },
34
+ options: ['horizontal', 'vertical'],
35
+ description: 'Disposition'
36
+ },
37
+ bordered: {
38
+ control: 'boolean',
39
+ description: 'Afficher une bordure'
40
+ }
41
+ }
42
+ };
43
+
44
+ const Template = (args, { argTypes }) => ({
45
+ components: { FProfileSection },
46
+ props: Object.keys(argTypes),
47
+ template: '<FProfileSection v-bind="$props" />'
48
+ });
49
+
50
+ export const Default = Template.bind({});
51
+ Default.args = {
52
+ name: 'Jean Dupont',
53
+ email: 'jean.dupont@example.com',
54
+ role: 'Développeur Senior'
55
+ };
56
+
57
+ export const WithAvatar = Template.bind({});
58
+ WithAvatar.args = {
59
+ name: 'Marie Martin',
60
+ email: 'marie@example.com',
61
+ role: 'Product Manager',
62
+ avatarSrc: 'https://i.pravatar.cc/150?img=5'
63
+ };
64
+
65
+ export const Vertical = Template.bind({});
66
+ Vertical.args = {
67
+ name: 'Pierre Durand',
68
+ email: 'pierre@example.com',
69
+ role: 'Designer UX',
70
+ layout: 'vertical'
71
+ };
72
+
73
+ export const WithActions = () => ({
74
+ components: { FProfileSection, FButton },
75
+ template: `
76
+ <FProfileSection
77
+ name="Sophie Petit"
78
+ email="sophie@example.com"
79
+ role="Chef de projet"
80
+ >
81
+ <template #actions>
82
+ <FButton variant="outline" size="sm">Message</FButton>
83
+ <FButton variant="primary" size="sm">Suivre</FButton>
84
+ </template>
85
+ </FProfileSection>
86
+ `
87
+ });
88
+
89
+ export const WithDetails = () => ({
90
+ components: { FProfileSection, FBadge },
91
+ template: `
92
+ <FProfileSection
93
+ name="Lucas Bernard"
94
+ email="lucas@example.com"
95
+ role="Développeur Full Stack"
96
+ >
97
+ <template #details>
98
+ <div class="flex gap-2 mt-2">
99
+ <FBadge content="React" variant="primary" size="sm" />
100
+ <FBadge content="Vue" variant="primary" size="sm" />
101
+ <FBadge content="Node.js" variant="primary" size="sm" />
102
+ </div>
103
+ </template>
104
+ </FProfileSection>
105
+ `
106
+ });
107
+
108
+ export const WithStats = () => ({
109
+ components: { FProfileSection, FButton },
110
+ template: `
111
+ <FProfileSection
112
+ name="Emma Leroy"
113
+ email="emma@example.com"
114
+ role="Lead Developer"
115
+ avatarSize="xl"
116
+ >
117
+ <template #stats>
118
+ <div class="flex gap-6 mt-4 pt-4 border-t border-neutral-100">
119
+ <div class="text-center">
120
+ <p class="text-2xl font-bold text-neutral-800">142</p>
121
+ <p class="text-sm text-neutral-500">Projets</p>
122
+ </div>
123
+ <div class="text-center">
124
+ <p class="text-2xl font-bold text-neutral-800">89</p>
125
+ <p class="text-sm text-neutral-500">Followers</p>
126
+ </div>
127
+ <div class="text-center">
128
+ <p class="text-2xl font-bold text-neutral-800">56</p>
129
+ <p class="text-sm text-neutral-500">Following</p>
130
+ </div>
131
+ </div>
132
+ </template>
133
+ <template #actions>
134
+ <FButton variant="primary">Modifier le profil</FButton>
135
+ </template>
136
+ </FProfileSection>
137
+ `
138
+ });
139
+
140
+ export const Bordered = Template.bind({});
141
+ Bordered.args = {
142
+ name: 'Thomas Martin',
143
+ email: 'thomas@example.com',
144
+ role: 'DevOps Engineer',
145
+ bordered: true
146
+ };
147
+
148
+ export const Complete = () => ({
149
+ components: { FProfileSection, FButton, FBadge },
150
+ template: `
151
+ <FProfileSection
152
+ name="Claire Dubois"
153
+ email="claire.dubois@example.com"
154
+ role="Directrice Technique"
155
+ avatarSrc="https://i.pravatar.cc/150?img=1"
156
+ avatarSize="xl"
157
+ bordered
158
+ >
159
+ <template #details>
160
+ <div class="flex items-center gap-2 mt-1">
161
+ <FBadge content="Admin" variant="primary" size="sm" />
162
+ <FBadge content="Vérifié" variant="success" size="sm" />
163
+ </div>
164
+ <p class="text-sm text-neutral-500 mt-2">
165
+ Paris, France • Membre depuis janvier 2020
166
+ </p>
167
+ </template>
168
+ <template #stats>
169
+ <div class="flex gap-6 mt-4 pt-4 border-t border-neutral-100">
170
+ <div class="text-center">
171
+ <p class="text-xl font-bold">245</p>
172
+ <p class="text-xs text-neutral-500">Projets</p>
173
+ </div>
174
+ <div class="text-center">
175
+ <p class="text-xl font-bold">1.2k</p>
176
+ <p class="text-xs text-neutral-500">Contributions</p>
177
+ </div>
178
+ <div class="text-center">
179
+ <p class="text-xl font-bold">98%</p>
180
+ <p class="text-xs text-neutral-500">Complétion</p>
181
+ </div>
182
+ </div>
183
+ </template>
184
+ <template #actions>
185
+ <FButton variant="outline" size="sm">Paramètres</FButton>
186
+ <FButton variant="primary" size="sm">Modifier</FButton>
187
+ </template>
188
+ </FProfileSection>
189
+ `
190
+ });
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import FProfileSection from './FProfileSection.vue';
4
+
5
+ describe('FProfileSection', () => {
6
+ it('renders correctly with required props', () => {
7
+ const wrapper = mount(FProfileSection, {
8
+ propsData: { name: 'John Doe' }
9
+ });
10
+ expect(wrapper.text()).toContain('John Doe');
11
+ });
12
+
13
+ it('displays name', () => {
14
+ const wrapper = mount(FProfileSection, {
15
+ propsData: { name: 'Jane Smith' }
16
+ });
17
+ expect(wrapper.text()).toContain('Jane Smith');
18
+ });
19
+
20
+ it('displays email when provided', () => {
21
+ const wrapper = mount(FProfileSection, {
22
+ propsData: { name: 'John', email: 'john@example.com' }
23
+ });
24
+ expect(wrapper.text()).toContain('john@example.com');
25
+ });
26
+
27
+ it('displays role/title when provided', () => {
28
+ const wrapper = mount(FProfileSection, {
29
+ propsData: { name: 'John', role: 'Developer' }
30
+ });
31
+ expect(wrapper.text()).toContain('Developer');
32
+ });
33
+
34
+ it('displays avatar', () => {
35
+ const wrapper = mount(FProfileSection, {
36
+ propsData: { name: 'John Doe' }
37
+ });
38
+ expect(wrapper.findComponent({ name: 'FAvatar' }).exists()).toBe(true);
39
+ });
40
+
41
+ it('uses avatar src when provided', () => {
42
+ const wrapper = mount(FProfileSection, {
43
+ propsData: { name: 'John', avatarSrc: 'https://example.com/avatar.jpg' }
44
+ });
45
+ expect(wrapper.findComponent({ name: 'FAvatar' }).exists()).toBe(true);
46
+ });
47
+
48
+ it('renders actions slot', () => {
49
+ const wrapper = mount(FProfileSection, {
50
+ propsData: { name: 'John' },
51
+ slots: { actions: '<button>Edit</button>' }
52
+ });
53
+ expect(wrapper.html()).toContain('Edit');
54
+ });
55
+
56
+ it('renders details slot', () => {
57
+ const wrapper = mount(FProfileSection, {
58
+ propsData: { name: 'John' },
59
+ slots: { details: '<p>Extra info</p>' }
60
+ });
61
+ expect(wrapper.html()).toContain('Extra info');
62
+ });
63
+
64
+ it('renders stats slot', () => {
65
+ const wrapper = mount(FProfileSection, {
66
+ propsData: { name: 'John' },
67
+ slots: { stats: '<div>10 projects</div>' }
68
+ });
69
+ expect(wrapper.html()).toContain('10 projects');
70
+ });
71
+
72
+ it('applies layout classes', () => {
73
+ const wrapper = mount(FProfileSection, {
74
+ propsData: { name: 'John', layout: 'horizontal' }
75
+ });
76
+ expect(wrapper.exists()).toBe(true);
77
+ });
78
+
79
+ it('applies bordered class when bordered is true', () => {
80
+ const wrapper = mount(FProfileSection, {
81
+ propsData: { name: 'John', bordered: true }
82
+ });
83
+ expect(wrapper.classes().join(' ')).toContain('border');
84
+ });
85
+ });