@meeovi/layer-shared 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 (327) hide show
  1. package/README.md +0 -0
  2. package/app/components/Gallery/Gallery.vue +187 -0
  3. package/app/components/Gallery/__tests__/Gallery.spec.ts +14 -0
  4. package/app/components/Heading/Heading.vue +14 -0
  5. package/app/components/Heading/__tests__/Heading.spec.ts +14 -0
  6. package/app/components/Heading/types.ts +5 -0
  7. package/app/components/media/audioGallery.vue +70 -0
  8. package/app/components/media/dragDropUpload.vue +67 -0
  9. package/app/components/media/fullscreenMediaModal.vue +66 -0
  10. package/app/components/media/imageCard.vue +65 -0
  11. package/app/components/media/imageGallery.vue +40 -0
  12. package/app/components/media/mediaCard.vue +89 -0
  13. package/app/components/media/mediaCarousel.vue +65 -0
  14. package/app/components/media/mediaFolderSidebar.vue +72 -0
  15. package/app/components/media/mediaPlayer.vue +40 -0
  16. package/app/components/media/mediaSearchBar.vue +16 -0
  17. package/app/components/media/videoGallery.vue +77 -0
  18. package/app/components/ui/AccordionItem/AccordionItem.vue +24 -0
  19. package/app/components/ui/AccordionItem/__tests__/AccordionItem.spec.ts +14 -0
  20. package/app/components/ui/AccordionItem/types.ts +5 -0
  21. package/app/components/ui/Alert/Alert.vue +34 -0
  22. package/app/components/ui/Alert/types.ts +5 -0
  23. package/app/components/ui/Breadcrumbs/Breadcrumbs.vue +76 -0
  24. package/app/components/ui/Breadcrumbs/__tests__/Breadcrumbs.spec.ts +14 -0
  25. package/app/components/ui/Breadcrumbs/types.ts +8 -0
  26. package/app/components/ui/CartProductCard/CartProductCard.vue +66 -0
  27. package/app/components/ui/CartProductCard/types.ts +18 -0
  28. package/app/components/ui/CategoryCard/CategoryCard.vue +41 -0
  29. package/app/components/ui/CategoryCard/types.ts +9 -0
  30. package/app/components/ui/Display/Display.vue +55 -0
  31. package/app/components/ui/Display/types.ts +12 -0
  32. package/app/components/ui/Divider/Divider.vue +3 -0
  33. package/app/components/ui/Divider/__tests__/Divider.spec.tsx +10 -0
  34. package/app/components/ui/Footer.vue +92 -0
  35. package/app/components/ui/Form/FormHelperText.vue +5 -0
  36. package/app/components/ui/Form/FormLabel.vue +5 -0
  37. package/app/components/ui/Form/FormPasswordInput.vue +15 -0
  38. package/app/components/ui/Form/__tests__/FormHelperText.spec.ts +10 -0
  39. package/app/components/ui/Form/__tests__/FormLabel.spec.ts +10 -0
  40. package/app/components/ui/Hero/Hero.vue +44 -0
  41. package/app/components/ui/Hero/types.ts +10 -0
  42. package/app/components/ui/Modal/Modal.vue +19 -0
  43. package/app/components/ui/Modal/types.ts +8 -0
  44. package/app/components/ui/Motionable.vue +45 -0
  45. package/app/components/ui/NavbarBottom.vue +63 -0
  46. package/app/components/ui/NavbarTop.vue +25 -0
  47. package/app/components/ui/Overlay/Overlay.vue +14 -0
  48. package/app/components/ui/Overlay/__tests__/Overlay.spec.ts +14 -0
  49. package/app/components/ui/Overlay/types.ts +3 -0
  50. package/app/components/ui/PageBuilder.vue +39 -0
  51. package/app/components/ui/PageContainer.vue +5 -0
  52. package/app/components/ui/Pagination/Pagination.vue +151 -0
  53. package/app/components/ui/Pagination/__tests__/Pagination.spec.ts +17 -0
  54. package/app/components/ui/Pagination/types.ts +6 -0
  55. package/app/components/ui/ProductCard/ProductCard.vue +55 -0
  56. package/app/components/ui/ProductCard/__tests__/ProductCard.spec.ts +16 -0
  57. package/app/components/ui/ProductCard/types.ts +12 -0
  58. package/app/components/ui/ProductCardHorizontal/ProductCardHorizontal.vue +34 -0
  59. package/app/components/ui/ProductCardHorizontal/__tests__/ProductCardHorizontal.spec.ts +36 -0
  60. package/app/components/ui/ProductCardHorizontal/types.ts +8 -0
  61. package/app/components/ui/PurchaseCard/PurchaseCard.vue +109 -0
  62. package/app/components/ui/PurchaseCard/__tests__/PurchaseCard.spec.ts +15 -0
  63. package/app/components/ui/PurchaseCard/types.ts +5 -0
  64. package/app/components/ui/QuantitySelector/QuantitySelector.vue +69 -0
  65. package/app/components/ui/QuantitySelector/__tests__/QuantitySelector.spec.ts +15 -0
  66. package/app/components/ui/QuantitySelector/types.ts +5 -0
  67. package/app/components/ui/RadialProgress.vue +44 -0
  68. package/app/components/ui/Review/Review.vue +57 -0
  69. package/app/components/ui/Review/__tests__/Review.spec.ts +15 -0
  70. package/app/components/ui/Review/types.ts +5 -0
  71. package/app/components/ui/ScrollTop.vue +82 -0
  72. package/app/components/ui/Search.vue +54 -0
  73. package/app/components/ui/Tag/Tag.vue +38 -0
  74. package/app/components/ui/Tag/__tests__/Tag.spec.ts +10 -0
  75. package/app/components/ui/Tag/types.ts +16 -0
  76. package/app/components/ui/VsfLogo.vue +7 -0
  77. package/app/components/ui/forms/BooleanInput.vue +34 -0
  78. package/app/components/ui/forms/DateTime.vue +44 -0
  79. package/app/components/ui/forms/DirectusFormElement.vue +60 -0
  80. package/app/components/ui/forms/DynamicTableElement.vue +57 -0
  81. package/app/components/ui/forms/FileInput.vue +85 -0
  82. package/app/components/ui/forms/FormField.vue +34 -0
  83. package/app/components/ui/forms/RelationSelect.vue +63 -0
  84. package/app/components/ui/forms/RepeaterInput.vue +121 -0
  85. package/app/components/ui/forms/SelectInput.vue +65 -0
  86. package/app/components/ui/forms/TextArea.vue +59 -0
  87. package/app/components/ui/forms/TextInput.vue +42 -0
  88. package/app/components/ui/forms/TiptapEditor.vue +136 -0
  89. package/app/components/ui/forms/[collection].vue +22 -0
  90. package/app/components/ui/studio/builder.vue +57 -0
  91. package/app/components/ui/studio/document.vue +69 -0
  92. package/app/components/ui/studio/email.vue +57 -0
  93. package/app/composables/globals/uploadFiles.js +41 -0
  94. package/app/composables/globals/useAdminTable.ts +12 -0
  95. package/app/composables/globals/useCustomFetch.ts +13 -0
  96. package/app/composables/globals/useDirectusField.ts +144 -0
  97. package/app/composables/globals/useDirectusForm.ts +70 -0
  98. package/app/composables/globals/useDirectusSchema.js +9 -0
  99. package/app/composables/globals/useFileManager.ts +76 -0
  100. package/app/composables/globals/useLivePreview.ts +17 -0
  101. package/app/composables/globals/useLoading.ts +23 -0
  102. package/app/composables/globals/useNavigation.js +19 -0
  103. package/app/composables/globals/useNotifications.ts +153 -0
  104. package/app/composables/globals/usePages.js +36 -0
  105. package/app/composables/globals/useRichText.ts +33 -0
  106. package/app/composables/globals/useServerRootMixin.ts +19 -0
  107. package/app/composables/globals/useVisualEditing.ts +38 -0
  108. package/app/composables/media/useFile.ts +6 -0
  109. package/app/composables/media/useMediaCenter.ts +353 -0
  110. package/app/composables/media/useVideojs.ts +45 -0
  111. package/app/composables/registry.ts +13 -0
  112. package/app/composables/types.ts +12 -0
  113. package/app/composables/useContent.ts +13 -0
  114. package/app/composables/useDirectusRequest.ts +32 -0
  115. package/app/stores/index.ts +0 -0
  116. package/app/types/api/global-search.ts +8 -0
  117. package/app/types/blocks/block-button-group.ts +7 -0
  118. package/app/types/blocks/block-button.ts +14 -0
  119. package/app/types/blocks/block-column.ts +20 -0
  120. package/app/types/blocks/block-cta.ts +10 -0
  121. package/app/types/blocks/block-divider.ts +4 -0
  122. package/app/types/blocks/block-faq.ts +12 -0
  123. package/app/types/blocks/block-form.ts +8 -0
  124. package/app/types/blocks/block-gallery.ts +14 -0
  125. package/app/types/blocks/block-hero.ts +12 -0
  126. package/app/types/blocks/block-html.ts +4 -0
  127. package/app/types/blocks/block-logocloud.ts +14 -0
  128. package/app/types/blocks/block-quote.ts +11 -0
  129. package/app/types/blocks/block-richtext.ts +7 -0
  130. package/app/types/blocks/block-steps.ts +22 -0
  131. package/app/types/blocks/block-team.ts +6 -0
  132. package/app/types/blocks/block-testimonial.ts +14 -0
  133. package/app/types/blocks/block-video.ts +10 -0
  134. package/app/types/blocks/block.ts +49 -0
  135. package/app/types/blocks/index.ts +18 -0
  136. package/app/types/componentMap.ts +15 -0
  137. package/app/types/content/category.ts +11 -0
  138. package/app/types/content/form.ts +20 -0
  139. package/app/types/content/index.ts +6 -0
  140. package/app/types/content/page.ts +76 -0
  141. package/app/types/content/post.ts +39 -0
  142. package/app/types/content/team.ts +16 -0
  143. package/app/types/content/testimonial.ts +19 -0
  144. package/app/types/directus.d.ts +47 -0
  145. package/app/types/env.d.ts +8 -0
  146. package/app/types/help/index.ts +53 -0
  147. package/app/types/index.d.ts +9 -0
  148. package/app/types/index.ts +7 -0
  149. package/app/types/meta/analytics.ts +18 -0
  150. package/app/types/meta/config.ts +21 -0
  151. package/app/types/meta/globals.ts +30 -0
  152. package/app/types/meta/index.ts +6 -0
  153. package/app/types/meta/navigation.ts +32 -0
  154. package/app/types/meta/redirect.ts +13 -0
  155. package/app/types/meta/seo.ts +19 -0
  156. package/app/types/os/contact.ts +23 -0
  157. package/app/types/os/conversation.ts +25 -0
  158. package/app/types/os/index.ts +16 -0
  159. package/app/types/os/organization.ts +54 -0
  160. package/app/types/os/os-activity.ts +28 -0
  161. package/app/types/os/os-deal.ts +45 -0
  162. package/app/types/os/os-expense.ts +22 -0
  163. package/app/types/os/os-invoice.ts +48 -0
  164. package/app/types/os/os-item.ts +18 -0
  165. package/app/types/os/os-payment.ts +29 -0
  166. package/app/types/os/os-project.ts +47 -0
  167. package/app/types/os/os-proposal.ts +84 -0
  168. package/app/types/os/os-settings.ts +19 -0
  169. package/app/types/os/os-subscription.ts +12 -0
  170. package/app/types/os/os-task.ts +34 -0
  171. package/app/types/os/os-tax-rate.ts +13 -0
  172. package/app/types/pageComponentMap.ts +8 -0
  173. package/app/types/schema.d.ts +39 -0
  174. package/app/types/schema.ts +151 -0
  175. package/app/types/system/file.ts +46 -0
  176. package/app/types/system/folder.ts +8 -0
  177. package/app/types/system/index.ts +4 -0
  178. package/app/types/system/role.ts +21 -0
  179. package/app/types/system/user.ts +56 -0
  180. package/app/utils/Timer.js +44 -0
  181. package/app/utils/billing-address.ts +24 -0
  182. package/app/utils/color.ts +14 -0
  183. package/app/utils/currency.ts +29 -0
  184. package/app/utils/embed.ts +57 -0
  185. package/app/utils/errors.ts +9 -0
  186. package/app/utils/fieldRegistry.js +89 -0
  187. package/app/utils/fonts.ts +24 -0
  188. package/app/utils/formkit.ts +75 -0
  189. package/app/utils/icons.ts +62 -0
  190. package/app/utils/index.js +0 -0
  191. package/app/utils/links.ts +28 -0
  192. package/app/utils/lodash.ts +33 -0
  193. package/app/utils/markdown.ts +9 -0
  194. package/app/utils/math.ts +25 -0
  195. package/app/utils/navigation.ts +11 -0
  196. package/app/utils/objects.ts +11 -0
  197. package/app/utils/paths.ts +21 -0
  198. package/app/utils/relations.ts +33 -0
  199. package/app/utils/strings.ts +113 -0
  200. package/app/utils/time.ts +148 -0
  201. package/app/utils/url.ts +22 -0
  202. package/app/utils/user-name.ts +21 -0
  203. package/app/utils/video/README.md +51 -0
  204. package/app/utils/video/playlist.js +0 -0
  205. package/dist/api/global-search.d.ts +8 -0
  206. package/dist/api/global-search.js +1 -0
  207. package/dist/blocks/block-button-group.d.ts +6 -0
  208. package/dist/blocks/block-button-group.js +1 -0
  209. package/dist/blocks/block-button.d.ts +13 -0
  210. package/dist/blocks/block-button.js +1 -0
  211. package/dist/blocks/block-column.d.ts +18 -0
  212. package/dist/blocks/block-column.js +1 -0
  213. package/dist/blocks/block-cta.d.ts +11 -0
  214. package/dist/blocks/block-cta.js +1 -0
  215. package/dist/blocks/block-divider.d.ts +4 -0
  216. package/dist/blocks/block-divider.js +1 -0
  217. package/dist/blocks/block-faq.d.ts +11 -0
  218. package/dist/blocks/block-faq.js +1 -0
  219. package/dist/blocks/block-form.d.ts +7 -0
  220. package/dist/blocks/block-form.js +1 -0
  221. package/dist/blocks/block-gallery.d.ts +13 -0
  222. package/dist/blocks/block-gallery.js +1 -0
  223. package/dist/blocks/block-hero.d.ts +11 -0
  224. package/dist/blocks/block-hero.js +1 -0
  225. package/dist/blocks/block-html.d.ts +4 -0
  226. package/dist/blocks/block-html.js +1 -0
  227. package/dist/blocks/block-logocloud.d.ts +13 -0
  228. package/dist/blocks/block-logocloud.js +1 -0
  229. package/dist/blocks/block-quote.d.ts +10 -0
  230. package/dist/blocks/block-quote.js +1 -0
  231. package/dist/blocks/block-richtext.d.ts +7 -0
  232. package/dist/blocks/block-richtext.js +1 -0
  233. package/dist/blocks/block-steps.d.ts +21 -0
  234. package/dist/blocks/block-steps.js +1 -0
  235. package/dist/blocks/block-team.d.ts +6 -0
  236. package/dist/blocks/block-team.js +1 -0
  237. package/dist/blocks/block-testimonial.d.ts +13 -0
  238. package/dist/blocks/block-testimonial.js +1 -0
  239. package/dist/blocks/block-video.d.ts +9 -0
  240. package/dist/blocks/block-video.js +1 -0
  241. package/dist/blocks/block.d.ts +17 -0
  242. package/dist/blocks/block.js +1 -0
  243. package/dist/blocks/index.d.ts +18 -0
  244. package/dist/blocks/index.js +1 -0
  245. package/dist/componentMap.d.ts +6 -0
  246. package/dist/componentMap.js +8 -0
  247. package/dist/content/category.d.ts +10 -0
  248. package/dist/content/category.js +1 -0
  249. package/dist/content/form.d.ts +21 -0
  250. package/dist/content/form.js +1 -0
  251. package/dist/content/index.d.ts +6 -0
  252. package/dist/content/index.js +1 -0
  253. package/dist/content/page.d.ts +38 -0
  254. package/dist/content/page.js +1 -0
  255. package/dist/content/post.d.ts +38 -0
  256. package/dist/content/post.js +1 -0
  257. package/dist/content/team.d.ts +17 -0
  258. package/dist/content/team.js +1 -0
  259. package/dist/content/testimonial.d.ts +18 -0
  260. package/dist/content/testimonial.js +1 -0
  261. package/dist/help/index.d.ts +51 -0
  262. package/dist/help/index.js +1 -0
  263. package/dist/index.d.ts +7 -0
  264. package/dist/index.js +1 -0
  265. package/dist/meta/analytics.d.ts +21 -0
  266. package/dist/meta/analytics.js +1 -0
  267. package/dist/meta/config.d.ts +22 -0
  268. package/dist/meta/config.js +1 -0
  269. package/dist/meta/globals.d.ts +33 -0
  270. package/dist/meta/globals.js +1 -0
  271. package/dist/meta/index.d.ts +6 -0
  272. package/dist/meta/index.js +1 -0
  273. package/dist/meta/navigation.d.ts +31 -0
  274. package/dist/meta/navigation.js +1 -0
  275. package/dist/meta/redirect.d.ts +12 -0
  276. package/dist/meta/redirect.js +1 -0
  277. package/dist/meta/seo.d.ts +19 -0
  278. package/dist/meta/seo.js +1 -0
  279. package/dist/os/contact.d.ts +22 -0
  280. package/dist/os/contact.js +1 -0
  281. package/dist/os/conversation.d.ts +23 -0
  282. package/dist/os/conversation.js +1 -0
  283. package/dist/os/index.d.ts +16 -0
  284. package/dist/os/index.js +1 -0
  285. package/dist/os/organization.d.ts +51 -0
  286. package/dist/os/organization.js +1 -0
  287. package/dist/os/os-activity.d.ts +26 -0
  288. package/dist/os/os-activity.js +1 -0
  289. package/dist/os/os-deal.d.ts +42 -0
  290. package/dist/os/os-deal.js +1 -0
  291. package/dist/os/os-expense.d.ts +21 -0
  292. package/dist/os/os-expense.js +1 -0
  293. package/dist/os/os-invoice.d.ts +46 -0
  294. package/dist/os/os-invoice.js +1 -0
  295. package/dist/os/os-item.d.ts +17 -0
  296. package/dist/os/os-item.js +1 -0
  297. package/dist/os/os-payment.d.ts +27 -0
  298. package/dist/os/os-payment.js +1 -0
  299. package/dist/os/os-project.d.ts +45 -0
  300. package/dist/os/os-project.js +1 -0
  301. package/dist/os/os-proposal.d.ts +61 -0
  302. package/dist/os/os-proposal.js +1 -0
  303. package/dist/os/os-settings.d.ts +17 -0
  304. package/dist/os/os-settings.js +1 -0
  305. package/dist/os/os-subscription.d.ts +12 -0
  306. package/dist/os/os-subscription.js +1 -0
  307. package/dist/os/os-task.d.ts +32 -0
  308. package/dist/os/os-task.js +1 -0
  309. package/dist/os/os-tax-rate.d.ts +12 -0
  310. package/dist/os/os-tax-rate.js +1 -0
  311. package/dist/pageComponentMap.d.ts +2 -0
  312. package/dist/pageComponentMap.js +7 -0
  313. package/dist/schema.d.ts +78 -0
  314. package/dist/schema.js +1 -0
  315. package/dist/system/file.d.ts +47 -0
  316. package/dist/system/file.js +1 -0
  317. package/dist/system/folder.d.ts +8 -0
  318. package/dist/system/folder.js +1 -0
  319. package/dist/system/index.d.ts +4 -0
  320. package/dist/system/index.js +1 -0
  321. package/dist/system/role.d.ts +20 -0
  322. package/dist/system/role.js +1 -0
  323. package/dist/system/user.d.ts +57 -0
  324. package/dist/system/user.js +1 -0
  325. package/nuxt.config.ts +5 -0
  326. package/package.json +42 -0
  327. package/tsconfig.json +15 -0
@@ -0,0 +1,70 @@
1
+ import { ref, provide } from 'vue'
2
+ import type { Ref } from 'vue'
3
+
4
+ export function useDirectusForm(collectionName: string, fieldsRef: Ref<any[]>, opts?: { clearOnSuccess?: boolean, closeDialogRef?: Ref<boolean> }) {
5
+ const form = ref<Record<string, any>>({})
6
+ const formError = ref<string | null>(null)
7
+ const formSuccess = ref<string | null>(null)
8
+
9
+ // provide form context for DirectusFormElement children
10
+ provide('directusForm', {
11
+ form,
12
+ fields: fieldsRef,
13
+ })
14
+
15
+ const submitForm = async () => {
16
+ formError.value = null
17
+ formSuccess.value = null
18
+
19
+ // Validate form data against field validation rules
20
+ for (const field of fieldsRef.value) {
21
+ if (field.meta?.validation) {
22
+ try {
23
+ const validation = field.meta.validation
24
+ if (validation._and) {
25
+ for (const rule of validation._and) {
26
+ const fieldName = Object.keys(rule)[0]
27
+ if (!fieldName) continue
28
+ const ruleDef = (rule as any)[fieldName]
29
+ if (ruleDef && ruleDef._regex) {
30
+ const regex = new RegExp(ruleDef._regex)
31
+ const valueToTest = String(form.value[field.field] ?? '')
32
+ if (!regex.test(valueToTest)) {
33
+ formError.value = field.meta.validation_message || field.meta.field + ' failed validation'
34
+ console.error(
35
+ `Validation failed for ${field.field}: ${field.meta.validation_message || 'Invalid format'}`)
36
+ return // Stop submission if validation fails
37
+ }
38
+ }
39
+ }
40
+ }
41
+ } catch (err) {
42
+ console.error(`Error parsing validation for ${field.field}:`, err)
43
+ }
44
+ }
45
+ }
46
+
47
+ const { $directus, $createItem } = useNuxtApp() as any
48
+ const result = await $directus.request($createItem(collectionName, form.value))
49
+ if (result.error) {
50
+ formError.value = result.error.message
51
+ console.error(`Error creating ${collectionName}:`, result.error)
52
+ return // Stop submission if error occurs
53
+ }
54
+ formSuccess.value = `${collectionName} created successfully`
55
+
56
+ if (opts?.clearOnSuccess) {
57
+ form.value = {}
58
+ }
59
+ if (opts?.closeDialogRef) {
60
+ try { opts.closeDialogRef.value = false } catch (e) {}
61
+ }
62
+ }
63
+
64
+ return {
65
+ form,
66
+ formError,
67
+ formSuccess,
68
+ submitForm,
69
+ }
70
+ }
@@ -0,0 +1,9 @@
1
+ export async function useDirectusSchema(collection) {
2
+ const config = useRuntimeConfig()
3
+
4
+ return await $fetch(`${config.public.directus.url}/fields/${collection}`, {
5
+ headers: {
6
+ Authorization: `Bearer ${config.public.directus.auth.token}`
7
+ }
8
+ })
9
+ }
@@ -0,0 +1,76 @@
1
+ export interface FileManagerConfig {
2
+ maxSize?: number
3
+ allowedTypes?: string[]
4
+ onProgress?: (progress: number) => void
5
+ onSuccess?: (file: any) => void
6
+ onError?: (error: Error) => void
7
+ }
8
+
9
+ export function useFileManager(config: FileManagerConfig = {}) {
10
+ const uploading = ref(false)
11
+ const progress = ref(0)
12
+ const error = ref<string | null>(null)
13
+
14
+ const uploadToServer = async (file: File): Promise<any> => {
15
+ if (config.maxSize && file.size > config.maxSize) {
16
+ const errorMsg = `File size exceeds ${formatFileSize(config.maxSize)}`
17
+ error.value = errorMsg
18
+ config.onError?.(new Error(errorMsg))
19
+ throw new Error(errorMsg)
20
+ }
21
+
22
+ if (config.allowedTypes && !config.allowedTypes.includes(file.type)) {
23
+ const errorMsg = 'File type not allowed'
24
+ error.value = errorMsg
25
+ config.onError?.(new Error(errorMsg))
26
+ throw new Error(errorMsg)
27
+ }
28
+
29
+ const formData = new FormData()
30
+ formData.append('file', file)
31
+
32
+ uploading.value = true
33
+ progress.value = 0
34
+ error.value = null
35
+
36
+ try {
37
+ const response = await $fetch('/api/file/upload', {
38
+ method: 'POST',
39
+ body: formData
40
+ })
41
+ config.onSuccess?.(response.file)
42
+ return response.file
43
+ } catch (err: any) {
44
+ const errorMsg = err.data?.message || 'Upload failed'
45
+ error.value = errorMsg
46
+ config.onError?.(new Error(errorMsg))
47
+ throw err
48
+ } finally {
49
+ uploading.value = false
50
+ }
51
+ }
52
+
53
+ const uploadMultipleFiles = async (files: FileList | File[]): Promise<any[]> => {
54
+ const fileArray = Array.from(files)
55
+ const results = []
56
+
57
+ for (const file of fileArray) {
58
+ try {
59
+ const result = await uploadToServer(file)
60
+ results.push(result)
61
+ } catch (err: any) {
62
+ results.push({ error: err.message })
63
+ }
64
+ }
65
+
66
+ return results
67
+ }
68
+
69
+ return {
70
+ uploading: readonly(uploading),
71
+ progress: readonly(progress),
72
+ error: readonly(error),
73
+ uploadToServer,
74
+ uploadMultipleFiles
75
+ }
76
+ }
@@ -0,0 +1,17 @@
1
+ export function useLivePreview() {
2
+ return usePreviewMode({
3
+ // Enable preview mode when both preview and token params exist in URL
4
+ shouldEnable: () => {
5
+ const route = useRoute();
6
+ return !!route.query.preview && !!route.query.token;
7
+ },
8
+
9
+ // Store the token from the URL for use in API calls
10
+ getState: (currentState) => {
11
+ const route = useRoute();
12
+ return {
13
+ token: route.query.token || currentState.token,
14
+ };
15
+ },
16
+ });
17
+ }
@@ -0,0 +1,23 @@
1
+ // composables/useLoading.ts
2
+ export const useLoading = () => {
3
+ const loading = ref(false)
4
+ const loadingText = ref('')
5
+
6
+ const startLoading = (text = 'Loading...') => {
7
+ loading.value = true
8
+ loadingText.value = text
9
+ }
10
+
11
+ const stopLoading = () => {
12
+ loading.value = false
13
+ loadingText.value = ''
14
+ }
15
+
16
+ return {
17
+ loading,
18
+ loadingText,
19
+ startLoading,
20
+ stopLoading
21
+ }
22
+ }
23
+
@@ -0,0 +1,19 @@
1
+ import { useRuntimeConfig } from 'nuxt/config';
2
+
3
+ export const getNavigation = async (id) => {
4
+ const config = useRuntimeConfig();
5
+ //const credentials = btoa(`${config.public.WP_API_EMAIL}:${config.public.WORDPRESS_TOKEN}`);
6
+
7
+ try {
8
+ const navigation = await $fetch(`${config.public.wordpressUrl}/wp-json/wp/v2/navigations/${id}`, {
9
+ headers: {
10
+ 'Authorization': `Basic ${config.public.wordpressToken}`, // Basic Auth Header
11
+ 'Content-Type': 'application/json'
12
+ }
13
+ });
14
+ return navigation;
15
+ } catch (error) {
16
+ console.error('Error fetching navigation:', error);
17
+ return [];
18
+ }
19
+ };
@@ -0,0 +1,153 @@
1
+ import { ref, onMounted } from 'vue'
2
+ import { useAsyncData, useNuxtApp } from '#imports'
3
+
4
+ export interface Notification {
5
+ id: string
6
+ title: string
7
+ content: string
8
+ date: string
9
+ type: 'order' | 'account' | 'social' | 'system'
10
+ isRead: boolean
11
+ source: 'magento' | 'directus'
12
+ payload?: any
13
+ }
14
+
15
+ export function useNotifications() {
16
+ const notifications = ref<Notification[]>([])
17
+ const unreadCount = ref(0)
18
+ const { $directus, $readItems, $updateItem } = useNuxtApp() as any
19
+
20
+ // Fetch notifications from Directus
21
+ const fetchDirectusNotifications = async () => {
22
+ try {
23
+ const { data } = await useAsyncData<any[]>('directusNotifications', () => {
24
+ return $directus.request($readItems('notifications', {
25
+ filter: {
26
+ recipient: { _eq: 'current_user' }
27
+ },
28
+ sort: ['-date_created']
29
+ }))
30
+ })
31
+
32
+ if (data.value) {
33
+ const formattedNotifications: Notification[] = data.value.map((notification: any) => ({
34
+ id: String(notification.id),
35
+ title: String(notification.subject),
36
+ content: String(notification.message),
37
+ date: String(notification.timestamp),
38
+ type: (['order', 'account', 'social', 'system'].includes(notification.collection) ? notification.collection : 'system') as Notification['type'],
39
+ isRead: notification.status === 'read',
40
+ source: 'directus',
41
+ payload: notification.item
42
+ }))
43
+ notifications.value = [...notifications.value, ...formattedNotifications]
44
+ }
45
+ } catch (error) {
46
+ console.error('Error fetching Directus notifications:', error)
47
+ }
48
+ }
49
+
50
+ // Fetch notifications from Magento
51
+ const fetchMagentoNotifications = async () => {
52
+ try {
53
+ // Replace with your Magento API endpoint
54
+ const response = await fetch('/api/magento/notifications')
55
+ if (!response.ok) {
56
+ const text = await response.text().catch(() => '')
57
+ console.error('Magento notifications fetch failed', { status: response.status, body: text })
58
+ return
59
+ }
60
+
61
+ const data = await response.json()
62
+
63
+ const formattedNotifications: Notification[] = data.map((notification: any) => ({
64
+ id: String(notification.id),
65
+ title: String(notification.title),
66
+ content: String(notification.message),
67
+ date: String(notification.created_at),
68
+ type: (['order', 'account', 'social', 'system'].includes(notification.type) ? notification.type : 'system') as Notification['type'],
69
+ isRead: Boolean(notification.is_read),
70
+ source: 'magento',
71
+ payload: notification.payload
72
+ }))
73
+ notifications.value = [...notifications.value, ...formattedNotifications]
74
+ } catch (error: any) {
75
+ console.error('Error fetching Magento notifications:', error?.message ?? String(error))
76
+ }
77
+ }
78
+
79
+ // Mark notification as read
80
+ const markAsRead = async (notificationId: string, source: 'magento' | 'directus') => {
81
+ try {
82
+ if (source === 'directus') {
83
+ await $directus.request($updateItem('notifications', notificationId, {
84
+ status: 'read'
85
+ }))
86
+ } else {
87
+ // Update Magento notification
88
+ await fetch(`/api/magento/notifications/${notificationId}/read`, {
89
+ method: 'POST'
90
+ })
91
+ }
92
+
93
+ // Update local state
94
+ const notification = notifications.value.find(n => n.id === notificationId)
95
+ if (notification) {
96
+ notification.isRead = true
97
+ unreadCount.value = Math.max(0, unreadCount.value - 1)
98
+ }
99
+ } catch (error) {
100
+ console.error('Error marking notification as read:', error)
101
+ }
102
+ }
103
+
104
+ // Mark all notifications as read
105
+ const markAllAsRead = async () => {
106
+ try {
107
+ // Update Directus notifications
108
+ await $directus.request($updateItem('notifications', {
109
+ filter: {
110
+ recipient: { _eq: 'current_user' },
111
+ status: { _eq: 'inbox' }
112
+ },
113
+ data: {
114
+ status: 'read'
115
+ }
116
+ }))
117
+
118
+ // Update Magento notifications
119
+ await fetch('/api/magento/notifications/read-all', {
120
+ method: 'POST'
121
+ })
122
+
123
+ // Update local state
124
+ notifications.value.forEach(notification => {
125
+ notification.isRead = true
126
+ })
127
+ unreadCount.value = 0
128
+ } catch (error) {
129
+ console.error('Error marking all notifications as read:', error)
130
+ }
131
+ }
132
+
133
+ // Calculate unread count
134
+ const updateUnreadCount = () => {
135
+ unreadCount.value = notifications.value.filter(n => !n.isRead).length
136
+ }
137
+
138
+ onMounted(async () => {
139
+ await Promise.all([
140
+ fetchDirectusNotifications(),
141
+ fetchMagentoNotifications()
142
+ ])
143
+ updateUnreadCount()
144
+ })
145
+
146
+ return {
147
+ notifications,
148
+ unreadCount,
149
+ markAsRead,
150
+ markAllAsRead,
151
+ updateUnreadCount
152
+ }
153
+ }
@@ -0,0 +1,36 @@
1
+ // composables/usePages.js
2
+ import { ref } from 'vue';
3
+ import { useRuntimeConfig } from 'nuxt/config';
4
+
5
+ export function usePages() {
6
+ const config = useRuntimeConfig();
7
+ const pages = ref({});
8
+
9
+ const fetchPages = async (pageSlugsOrIds) => {
10
+ try {
11
+ const allPages = await $fetch(`${config.public.wordpressUrl}/wp-json/wp/v2/pages`, {
12
+ headers: {
13
+ 'Content-Type': 'application/json',
14
+ 'Authorization': `Bearer ${config.public.wordpressToken}`
15
+ }
16
+ });
17
+
18
+ pageSlugsOrIds.forEach(slugOrId => {
19
+ const specificPage = allPages.find(page => page.slug === slugOrId || page.id === slugOrId);
20
+
21
+ if (specificPage) {
22
+ pages.value[slugOrId] = specificPage;
23
+ } else {
24
+ console.warn(`Page "${slugOrId}" not found`);
25
+ }
26
+ });
27
+ } catch (error) {
28
+ console.error('Error fetching pages:', error);
29
+ }
30
+ };
31
+
32
+ return {
33
+ pages,
34
+ fetchPages,
35
+ };
36
+ }
@@ -0,0 +1,33 @@
1
+ import { RichText } from '@atproto/api'
2
+
3
+ // creating richtext
4
+ const rt = new RichText({
5
+ text: 'Hello @alice.com, check out this link: https://example.com',
6
+ })
7
+ await rt.detectFacets(agent) // automatically detects mentions and links
8
+ const postRecord = {
9
+ $type: 'app.bsky.feed.post',
10
+ text: rt.text,
11
+ facets: rt.facets,
12
+ createdAt: new Date().toISOString(),
13
+ }
14
+
15
+ // rendering as markdown
16
+ let markdown = ''
17
+ for (const segment of rt.segments()) {
18
+ if (segment.isLink()) {
19
+ markdown += `[${segment.text}](${segment.link?.uri})`
20
+ } else if (segment.isMention()) {
21
+ markdown += `[${segment.text}](https://my-bsky-app.com/user/${segment.mention?.did})`
22
+ } else {
23
+ markdown += segment.text
24
+ }
25
+ }
26
+
27
+ // calculating string lengths
28
+ const rt2 = new RichText({ text: 'Hello' })
29
+ console.log(rt2.length) // => 5
30
+ console.log(rt2.graphemeLength) // => 5
31
+ const rt3 = new RichText({ text: '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง' })
32
+ console.log(rt3.length) // => 25
33
+ console.log(rt3.graphemeLength) // => 1
@@ -0,0 +1,19 @@
1
+ import { createServerRootMixin } from 'vue-instantsearch/vue3/es'
2
+
3
+ export default function useServerRootMixin (indexName: string) {
4
+ const nuxtApp = useNuxtApp()
5
+ const searchClient = useMeilisearch()
6
+
7
+ const serverRootMixin = ref(createServerRootMixin({
8
+ searchClient,
9
+ indexName
10
+ }))
11
+
12
+ // Install SSR mixin
13
+ nuxtApp.vueApp.mixin(serverRootMixin.value)
14
+ // TODO: ensure mixin is only installed once
15
+
16
+ return {
17
+ instantsearch: serverRootMixin.value.data().instantsearch
18
+ }
19
+ }
@@ -0,0 +1,38 @@
1
+ import { apply as applyVisualEditing, setAttr } from '@directus/visual-editing';
2
+ import type { PrimaryKey } from '@directus/types';
3
+
4
+ interface ApplyOptions {
5
+ directusUrl: string;
6
+ elements?: HTMLElement[] | HTMLElement;
7
+ onSaved?: (data: { collection?: string; item?: PrimaryKey | null; payload?: Record<string, any> }) => void;
8
+ customClass?: string;
9
+ }
10
+ export default function useVisualEditing() {
11
+ // Use useState for state that persists across navigation
12
+ const isVisualEditingEnabled = useState('visual-editing-enabled', () => false);
13
+ const route = useRoute();
14
+ const {
15
+ public: { enableVisualEditing, directusUrl },
16
+ } = useRuntimeConfig();
17
+
18
+ // Check query param on composable initialization.
19
+ if (route.query['visual-editing'] === 'true' && enableVisualEditing) {
20
+ isVisualEditingEnabled.value = true;
21
+ } else if (route.query['visual-editing'] === 'false') {
22
+ isVisualEditingEnabled.value = false;
23
+ }
24
+
25
+ const apply = (options: Pick<ApplyOptions, 'elements' | 'onSaved' | 'customClass'>) => {
26
+ if (!isVisualEditingEnabled.value) return;
27
+ applyVisualEditing({
28
+ ...options,
29
+ directusUrl,
30
+ });
31
+ };
32
+
33
+ return {
34
+ isVisualEditingEnabled,
35
+ apply,
36
+ setAttr,
37
+ };
38
+ }
@@ -0,0 +1,6 @@
1
+ import type { FilePlugin } from '../../types/index.d'
2
+
3
+ export function useFile() {
4
+ const { $file } = useNuxtApp()
5
+ return $file as FilePlugin
6
+ }