@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.
- package/README.md +0 -0
- package/app/components/Gallery/Gallery.vue +187 -0
- package/app/components/Gallery/__tests__/Gallery.spec.ts +14 -0
- package/app/components/Heading/Heading.vue +14 -0
- package/app/components/Heading/__tests__/Heading.spec.ts +14 -0
- package/app/components/Heading/types.ts +5 -0
- package/app/components/media/audioGallery.vue +70 -0
- package/app/components/media/dragDropUpload.vue +67 -0
- package/app/components/media/fullscreenMediaModal.vue +66 -0
- package/app/components/media/imageCard.vue +65 -0
- package/app/components/media/imageGallery.vue +40 -0
- package/app/components/media/mediaCard.vue +89 -0
- package/app/components/media/mediaCarousel.vue +65 -0
- package/app/components/media/mediaFolderSidebar.vue +72 -0
- package/app/components/media/mediaPlayer.vue +40 -0
- package/app/components/media/mediaSearchBar.vue +16 -0
- package/app/components/media/videoGallery.vue +77 -0
- package/app/components/ui/AccordionItem/AccordionItem.vue +24 -0
- package/app/components/ui/AccordionItem/__tests__/AccordionItem.spec.ts +14 -0
- package/app/components/ui/AccordionItem/types.ts +5 -0
- package/app/components/ui/Alert/Alert.vue +34 -0
- package/app/components/ui/Alert/types.ts +5 -0
- package/app/components/ui/Breadcrumbs/Breadcrumbs.vue +76 -0
- package/app/components/ui/Breadcrumbs/__tests__/Breadcrumbs.spec.ts +14 -0
- package/app/components/ui/Breadcrumbs/types.ts +8 -0
- package/app/components/ui/CartProductCard/CartProductCard.vue +66 -0
- package/app/components/ui/CartProductCard/types.ts +18 -0
- package/app/components/ui/CategoryCard/CategoryCard.vue +41 -0
- package/app/components/ui/CategoryCard/types.ts +9 -0
- package/app/components/ui/Display/Display.vue +55 -0
- package/app/components/ui/Display/types.ts +12 -0
- package/app/components/ui/Divider/Divider.vue +3 -0
- package/app/components/ui/Divider/__tests__/Divider.spec.tsx +10 -0
- package/app/components/ui/Footer.vue +92 -0
- package/app/components/ui/Form/FormHelperText.vue +5 -0
- package/app/components/ui/Form/FormLabel.vue +5 -0
- package/app/components/ui/Form/FormPasswordInput.vue +15 -0
- package/app/components/ui/Form/__tests__/FormHelperText.spec.ts +10 -0
- package/app/components/ui/Form/__tests__/FormLabel.spec.ts +10 -0
- package/app/components/ui/Hero/Hero.vue +44 -0
- package/app/components/ui/Hero/types.ts +10 -0
- package/app/components/ui/Modal/Modal.vue +19 -0
- package/app/components/ui/Modal/types.ts +8 -0
- package/app/components/ui/Motionable.vue +45 -0
- package/app/components/ui/NavbarBottom.vue +63 -0
- package/app/components/ui/NavbarTop.vue +25 -0
- package/app/components/ui/Overlay/Overlay.vue +14 -0
- package/app/components/ui/Overlay/__tests__/Overlay.spec.ts +14 -0
- package/app/components/ui/Overlay/types.ts +3 -0
- package/app/components/ui/PageBuilder.vue +39 -0
- package/app/components/ui/PageContainer.vue +5 -0
- package/app/components/ui/Pagination/Pagination.vue +151 -0
- package/app/components/ui/Pagination/__tests__/Pagination.spec.ts +17 -0
- package/app/components/ui/Pagination/types.ts +6 -0
- package/app/components/ui/ProductCard/ProductCard.vue +55 -0
- package/app/components/ui/ProductCard/__tests__/ProductCard.spec.ts +16 -0
- package/app/components/ui/ProductCard/types.ts +12 -0
- package/app/components/ui/ProductCardHorizontal/ProductCardHorizontal.vue +34 -0
- package/app/components/ui/ProductCardHorizontal/__tests__/ProductCardHorizontal.spec.ts +36 -0
- package/app/components/ui/ProductCardHorizontal/types.ts +8 -0
- package/app/components/ui/PurchaseCard/PurchaseCard.vue +109 -0
- package/app/components/ui/PurchaseCard/__tests__/PurchaseCard.spec.ts +15 -0
- package/app/components/ui/PurchaseCard/types.ts +5 -0
- package/app/components/ui/QuantitySelector/QuantitySelector.vue +69 -0
- package/app/components/ui/QuantitySelector/__tests__/QuantitySelector.spec.ts +15 -0
- package/app/components/ui/QuantitySelector/types.ts +5 -0
- package/app/components/ui/RadialProgress.vue +44 -0
- package/app/components/ui/Review/Review.vue +57 -0
- package/app/components/ui/Review/__tests__/Review.spec.ts +15 -0
- package/app/components/ui/Review/types.ts +5 -0
- package/app/components/ui/ScrollTop.vue +82 -0
- package/app/components/ui/Search.vue +54 -0
- package/app/components/ui/Tag/Tag.vue +38 -0
- package/app/components/ui/Tag/__tests__/Tag.spec.ts +10 -0
- package/app/components/ui/Tag/types.ts +16 -0
- package/app/components/ui/VsfLogo.vue +7 -0
- package/app/components/ui/forms/BooleanInput.vue +34 -0
- package/app/components/ui/forms/DateTime.vue +44 -0
- package/app/components/ui/forms/DirectusFormElement.vue +60 -0
- package/app/components/ui/forms/DynamicTableElement.vue +57 -0
- package/app/components/ui/forms/FileInput.vue +85 -0
- package/app/components/ui/forms/FormField.vue +34 -0
- package/app/components/ui/forms/RelationSelect.vue +63 -0
- package/app/components/ui/forms/RepeaterInput.vue +121 -0
- package/app/components/ui/forms/SelectInput.vue +65 -0
- package/app/components/ui/forms/TextArea.vue +59 -0
- package/app/components/ui/forms/TextInput.vue +42 -0
- package/app/components/ui/forms/TiptapEditor.vue +136 -0
- package/app/components/ui/forms/[collection].vue +22 -0
- package/app/components/ui/studio/builder.vue +57 -0
- package/app/components/ui/studio/document.vue +69 -0
- package/app/components/ui/studio/email.vue +57 -0
- package/app/composables/globals/uploadFiles.js +41 -0
- package/app/composables/globals/useAdminTable.ts +12 -0
- package/app/composables/globals/useCustomFetch.ts +13 -0
- package/app/composables/globals/useDirectusField.ts +144 -0
- package/app/composables/globals/useDirectusForm.ts +70 -0
- package/app/composables/globals/useDirectusSchema.js +9 -0
- package/app/composables/globals/useFileManager.ts +76 -0
- package/app/composables/globals/useLivePreview.ts +17 -0
- package/app/composables/globals/useLoading.ts +23 -0
- package/app/composables/globals/useNavigation.js +19 -0
- package/app/composables/globals/useNotifications.ts +153 -0
- package/app/composables/globals/usePages.js +36 -0
- package/app/composables/globals/useRichText.ts +33 -0
- package/app/composables/globals/useServerRootMixin.ts +19 -0
- package/app/composables/globals/useVisualEditing.ts +38 -0
- package/app/composables/media/useFile.ts +6 -0
- package/app/composables/media/useMediaCenter.ts +353 -0
- package/app/composables/media/useVideojs.ts +45 -0
- package/app/composables/registry.ts +13 -0
- package/app/composables/types.ts +12 -0
- package/app/composables/useContent.ts +13 -0
- package/app/composables/useDirectusRequest.ts +32 -0
- package/app/stores/index.ts +0 -0
- package/app/types/api/global-search.ts +8 -0
- package/app/types/blocks/block-button-group.ts +7 -0
- package/app/types/blocks/block-button.ts +14 -0
- package/app/types/blocks/block-column.ts +20 -0
- package/app/types/blocks/block-cta.ts +10 -0
- package/app/types/blocks/block-divider.ts +4 -0
- package/app/types/blocks/block-faq.ts +12 -0
- package/app/types/blocks/block-form.ts +8 -0
- package/app/types/blocks/block-gallery.ts +14 -0
- package/app/types/blocks/block-hero.ts +12 -0
- package/app/types/blocks/block-html.ts +4 -0
- package/app/types/blocks/block-logocloud.ts +14 -0
- package/app/types/blocks/block-quote.ts +11 -0
- package/app/types/blocks/block-richtext.ts +7 -0
- package/app/types/blocks/block-steps.ts +22 -0
- package/app/types/blocks/block-team.ts +6 -0
- package/app/types/blocks/block-testimonial.ts +14 -0
- package/app/types/blocks/block-video.ts +10 -0
- package/app/types/blocks/block.ts +49 -0
- package/app/types/blocks/index.ts +18 -0
- package/app/types/componentMap.ts +15 -0
- package/app/types/content/category.ts +11 -0
- package/app/types/content/form.ts +20 -0
- package/app/types/content/index.ts +6 -0
- package/app/types/content/page.ts +76 -0
- package/app/types/content/post.ts +39 -0
- package/app/types/content/team.ts +16 -0
- package/app/types/content/testimonial.ts +19 -0
- package/app/types/directus.d.ts +47 -0
- package/app/types/env.d.ts +8 -0
- package/app/types/help/index.ts +53 -0
- package/app/types/index.d.ts +9 -0
- package/app/types/index.ts +7 -0
- package/app/types/meta/analytics.ts +18 -0
- package/app/types/meta/config.ts +21 -0
- package/app/types/meta/globals.ts +30 -0
- package/app/types/meta/index.ts +6 -0
- package/app/types/meta/navigation.ts +32 -0
- package/app/types/meta/redirect.ts +13 -0
- package/app/types/meta/seo.ts +19 -0
- package/app/types/os/contact.ts +23 -0
- package/app/types/os/conversation.ts +25 -0
- package/app/types/os/index.ts +16 -0
- package/app/types/os/organization.ts +54 -0
- package/app/types/os/os-activity.ts +28 -0
- package/app/types/os/os-deal.ts +45 -0
- package/app/types/os/os-expense.ts +22 -0
- package/app/types/os/os-invoice.ts +48 -0
- package/app/types/os/os-item.ts +18 -0
- package/app/types/os/os-payment.ts +29 -0
- package/app/types/os/os-project.ts +47 -0
- package/app/types/os/os-proposal.ts +84 -0
- package/app/types/os/os-settings.ts +19 -0
- package/app/types/os/os-subscription.ts +12 -0
- package/app/types/os/os-task.ts +34 -0
- package/app/types/os/os-tax-rate.ts +13 -0
- package/app/types/pageComponentMap.ts +8 -0
- package/app/types/schema.d.ts +39 -0
- package/app/types/schema.ts +151 -0
- package/app/types/system/file.ts +46 -0
- package/app/types/system/folder.ts +8 -0
- package/app/types/system/index.ts +4 -0
- package/app/types/system/role.ts +21 -0
- package/app/types/system/user.ts +56 -0
- package/app/utils/Timer.js +44 -0
- package/app/utils/billing-address.ts +24 -0
- package/app/utils/color.ts +14 -0
- package/app/utils/currency.ts +29 -0
- package/app/utils/embed.ts +57 -0
- package/app/utils/errors.ts +9 -0
- package/app/utils/fieldRegistry.js +89 -0
- package/app/utils/fonts.ts +24 -0
- package/app/utils/formkit.ts +75 -0
- package/app/utils/icons.ts +62 -0
- package/app/utils/index.js +0 -0
- package/app/utils/links.ts +28 -0
- package/app/utils/lodash.ts +33 -0
- package/app/utils/markdown.ts +9 -0
- package/app/utils/math.ts +25 -0
- package/app/utils/navigation.ts +11 -0
- package/app/utils/objects.ts +11 -0
- package/app/utils/paths.ts +21 -0
- package/app/utils/relations.ts +33 -0
- package/app/utils/strings.ts +113 -0
- package/app/utils/time.ts +148 -0
- package/app/utils/url.ts +22 -0
- package/app/utils/user-name.ts +21 -0
- package/app/utils/video/README.md +51 -0
- package/app/utils/video/playlist.js +0 -0
- package/dist/api/global-search.d.ts +8 -0
- package/dist/api/global-search.js +1 -0
- package/dist/blocks/block-button-group.d.ts +6 -0
- package/dist/blocks/block-button-group.js +1 -0
- package/dist/blocks/block-button.d.ts +13 -0
- package/dist/blocks/block-button.js +1 -0
- package/dist/blocks/block-column.d.ts +18 -0
- package/dist/blocks/block-column.js +1 -0
- package/dist/blocks/block-cta.d.ts +11 -0
- package/dist/blocks/block-cta.js +1 -0
- package/dist/blocks/block-divider.d.ts +4 -0
- package/dist/blocks/block-divider.js +1 -0
- package/dist/blocks/block-faq.d.ts +11 -0
- package/dist/blocks/block-faq.js +1 -0
- package/dist/blocks/block-form.d.ts +7 -0
- package/dist/blocks/block-form.js +1 -0
- package/dist/blocks/block-gallery.d.ts +13 -0
- package/dist/blocks/block-gallery.js +1 -0
- package/dist/blocks/block-hero.d.ts +11 -0
- package/dist/blocks/block-hero.js +1 -0
- package/dist/blocks/block-html.d.ts +4 -0
- package/dist/blocks/block-html.js +1 -0
- package/dist/blocks/block-logocloud.d.ts +13 -0
- package/dist/blocks/block-logocloud.js +1 -0
- package/dist/blocks/block-quote.d.ts +10 -0
- package/dist/blocks/block-quote.js +1 -0
- package/dist/blocks/block-richtext.d.ts +7 -0
- package/dist/blocks/block-richtext.js +1 -0
- package/dist/blocks/block-steps.d.ts +21 -0
- package/dist/blocks/block-steps.js +1 -0
- package/dist/blocks/block-team.d.ts +6 -0
- package/dist/blocks/block-team.js +1 -0
- package/dist/blocks/block-testimonial.d.ts +13 -0
- package/dist/blocks/block-testimonial.js +1 -0
- package/dist/blocks/block-video.d.ts +9 -0
- package/dist/blocks/block-video.js +1 -0
- package/dist/blocks/block.d.ts +17 -0
- package/dist/blocks/block.js +1 -0
- package/dist/blocks/index.d.ts +18 -0
- package/dist/blocks/index.js +1 -0
- package/dist/componentMap.d.ts +6 -0
- package/dist/componentMap.js +8 -0
- package/dist/content/category.d.ts +10 -0
- package/dist/content/category.js +1 -0
- package/dist/content/form.d.ts +21 -0
- package/dist/content/form.js +1 -0
- package/dist/content/index.d.ts +6 -0
- package/dist/content/index.js +1 -0
- package/dist/content/page.d.ts +38 -0
- package/dist/content/page.js +1 -0
- package/dist/content/post.d.ts +38 -0
- package/dist/content/post.js +1 -0
- package/dist/content/team.d.ts +17 -0
- package/dist/content/team.js +1 -0
- package/dist/content/testimonial.d.ts +18 -0
- package/dist/content/testimonial.js +1 -0
- package/dist/help/index.d.ts +51 -0
- package/dist/help/index.js +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -0
- package/dist/meta/analytics.d.ts +21 -0
- package/dist/meta/analytics.js +1 -0
- package/dist/meta/config.d.ts +22 -0
- package/dist/meta/config.js +1 -0
- package/dist/meta/globals.d.ts +33 -0
- package/dist/meta/globals.js +1 -0
- package/dist/meta/index.d.ts +6 -0
- package/dist/meta/index.js +1 -0
- package/dist/meta/navigation.d.ts +31 -0
- package/dist/meta/navigation.js +1 -0
- package/dist/meta/redirect.d.ts +12 -0
- package/dist/meta/redirect.js +1 -0
- package/dist/meta/seo.d.ts +19 -0
- package/dist/meta/seo.js +1 -0
- package/dist/os/contact.d.ts +22 -0
- package/dist/os/contact.js +1 -0
- package/dist/os/conversation.d.ts +23 -0
- package/dist/os/conversation.js +1 -0
- package/dist/os/index.d.ts +16 -0
- package/dist/os/index.js +1 -0
- package/dist/os/organization.d.ts +51 -0
- package/dist/os/organization.js +1 -0
- package/dist/os/os-activity.d.ts +26 -0
- package/dist/os/os-activity.js +1 -0
- package/dist/os/os-deal.d.ts +42 -0
- package/dist/os/os-deal.js +1 -0
- package/dist/os/os-expense.d.ts +21 -0
- package/dist/os/os-expense.js +1 -0
- package/dist/os/os-invoice.d.ts +46 -0
- package/dist/os/os-invoice.js +1 -0
- package/dist/os/os-item.d.ts +17 -0
- package/dist/os/os-item.js +1 -0
- package/dist/os/os-payment.d.ts +27 -0
- package/dist/os/os-payment.js +1 -0
- package/dist/os/os-project.d.ts +45 -0
- package/dist/os/os-project.js +1 -0
- package/dist/os/os-proposal.d.ts +61 -0
- package/dist/os/os-proposal.js +1 -0
- package/dist/os/os-settings.d.ts +17 -0
- package/dist/os/os-settings.js +1 -0
- package/dist/os/os-subscription.d.ts +12 -0
- package/dist/os/os-subscription.js +1 -0
- package/dist/os/os-task.d.ts +32 -0
- package/dist/os/os-task.js +1 -0
- package/dist/os/os-tax-rate.d.ts +12 -0
- package/dist/os/os-tax-rate.js +1 -0
- package/dist/pageComponentMap.d.ts +2 -0
- package/dist/pageComponentMap.js +7 -0
- package/dist/schema.d.ts +78 -0
- package/dist/schema.js +1 -0
- package/dist/system/file.d.ts +47 -0
- package/dist/system/file.js +1 -0
- package/dist/system/folder.d.ts +8 -0
- package/dist/system/folder.js +1 -0
- package/dist/system/index.d.ts +4 -0
- package/dist/system/index.js +1 -0
- package/dist/system/role.d.ts +20 -0
- package/dist/system/role.js +1 -0
- package/dist/system/user.d.ts +57 -0
- package/dist/system/user.js +1 -0
- package/nuxt.config.ts +5 -0
- package/package.json +42 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:class="[
|
|
4
|
+
'inline-flex items-center justify-center',
|
|
5
|
+
strong ? 'font-medium rounded-none' : 'rounded-md font-normal',
|
|
6
|
+
getVariantClasses,
|
|
7
|
+
sizeClasses,
|
|
8
|
+
]"
|
|
9
|
+
data-testid="tag"
|
|
10
|
+
>
|
|
11
|
+
<slot />
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { type TagProps, TagSize } from '~/components/ui/Tag/types';
|
|
16
|
+
|
|
17
|
+
const props = withDefaults(defineProps<TagProps>(), {
|
|
18
|
+
variant: 'primary',
|
|
19
|
+
strong: false,
|
|
20
|
+
size: 'base',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const sizeClasses = computed(() => (props.size === TagSize.sm ? 'text-xs p-1 gap-1' : 'text-sm p-1.5 gap-1.5'));
|
|
24
|
+
|
|
25
|
+
const getVariantClasses = computed(() => {
|
|
26
|
+
switch (props.variant) {
|
|
27
|
+
case 'secondary': {
|
|
28
|
+
return ['text-white', props.strong ? 'bg-secondary-800' : 'bg-secondary-100'];
|
|
29
|
+
}
|
|
30
|
+
case 'negative': {
|
|
31
|
+
return ['text-negative-800', props.strong ? 'bg-negative-600' : 'bg-negative-100'];
|
|
32
|
+
}
|
|
33
|
+
default: {
|
|
34
|
+
return ['text-primary-800', props.strong ? 'bg-primary-600' : 'bg-primary-100'];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
</script>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export enum TagVariant {
|
|
2
|
+
primary = 'primary',
|
|
3
|
+
secondary = 'secondary',
|
|
4
|
+
negative = 'negative',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export enum TagSize {
|
|
8
|
+
sm = 'sm',
|
|
9
|
+
base = 'base',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface TagProps {
|
|
13
|
+
size?: `${TagSize}`;
|
|
14
|
+
strong?: boolean;
|
|
15
|
+
variant?: `${TagVariant}`;
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="fill-current h-full w-auto" viewBox="0 0 205 28">
|
|
3
|
+
<path
|
|
4
|
+
d="M150.233 11.135h-2.65v3.12h2.65v9.104h3.701v-9.104h3.175v-3.12h-3.175v-.67c0-.462.144-.805.434-1.028s.716-.335 1.279-.335a6.7 6.7 0 0 1 .697.035 7.54 7.54 0 0 1 .765.127V6.167a7.8 7.8 0 0 0-.925-.162 8.49 8.49 0 0 0-1.04-.069c-1.583 0-2.798.385-3.643 1.155s-1.268 1.872-1.268 3.304v.739zM85.84 20.886l2.193-2.889a11.33 11.33 0 0 0 2.696 1.71 6.67 6.67 0 0 0 2.627.531c.898 0 1.603-.139 2.113-.416s.765-.662.765-1.155a1.23 1.23 0 0 0-.124-.587 1.19 1.19 0 0 0-.389-.453c-.343-.246-.91-.439-1.702-.578l-3.518-.624c-1.295-.231-2.292-.732-2.992-1.502s-1.051-1.748-1.051-2.935c0-1.556.582-2.784 1.747-3.686s2.768-1.352 4.808-1.352a11.02 11.02 0 0 1 3.598.624 10.03 10.03 0 0 1 3.118 1.687l-2.079 2.935a9.56 9.56 0 0 0-2.456-1.456 6.78 6.78 0 0 0-2.456-.462c-.792 0-1.42.127-1.885.381s-.697.597-.697 1.028a1.11 1.11 0 0 0 .106.525 1.09 1.09 0 0 0 .339.411c.297.224.781.389 1.451.497l3.312.555c1.538.247 2.707.763 3.506 1.548s1.199 1.802 1.199 3.05c0 1.633-.628 2.927-1.884 3.882s-2.965 1.433-5.128 1.433a10.81 10.81 0 0 1-3.826-.716 11.23 11.23 0 0 1-3.392-1.987zm-41.755 2.473L37.621 7.183h4.249l4.546 12.039 4.637-12.039h4.089l-6.556 16.175h-4.5zM58.59 11.135v7.025a2.12 2.12 0 0 0 .133.868c.104.276.265.528.472.738a2.08 2.08 0 0 0 .729.478c.273.106.566.151.858.134a2.95 2.95 0 0 0 1.256-.254 2.47 2.47 0 0 0 .914-.716v-8.273h3.7v12.224h-3.7v-.832a5.06 5.06 0 0 1-1.496.786 5.49 5.49 0 0 1-1.747.277c-1.416 0-2.574-.462-3.472-1.387s-1.348-2.103-1.348-3.535v-7.533h3.7zm19.085 12.016c.856-.327 1.649-.804 2.341-1.41l-2.444-2.195a3 3 0 0 1-1.051.682 3.71 3.71 0 0 1-1.37.243 3.1 3.1 0 0 1-1.827-.543 3.22 3.22 0 0 1-1.142-1.398h8.612v-.924a7.64 7.64 0 0 0-.457-2.669 6.3 6.3 0 0 0-1.268-2.114c-.559-.605-1.237-1.087-1.99-1.413a5.85 5.85 0 0 0-2.384-.482c-.85-.007-1.693.159-2.479.485a6.12 6.12 0 0 0-1.999 1.34 6.34 6.34 0 0 0-1.336 2.022 6.33 6.33 0 0 0-.491 2.484 6.08 6.08 0 0 0 .514 2.484 6.36 6.36 0 0 0 1.394 2.022 6.34 6.34 0 0 0 2.09 1.34 6.87 6.87 0 0 0 2.581.485 7.84 7.84 0 0 0 2.707-.439zm-4.626-8.665a2.51 2.51 0 0 1 1.576-.508c.566-.009 1.119.178 1.565.532a2.96 2.96 0 0 1 .971 1.41h-5.048c.151-.568.479-1.07.937-1.433zm29.9-.232v5.384c0 1.279.369 2.246 1.108 2.9s1.831.982 3.278.982c.436-.007.871-.041 1.302-.104a7.58 7.58 0 0 0 1.28-.266v-3.027a5.86 5.86 0 0 1-.846.196c-.272.04-.547.059-.822.058-.594 0-1.009-.112-1.245-.335s-.354-.604-.354-1.144v-4.645h3.381v-3.12h-3.381v-3.95l-3.701.809v3.143h-2.444v3.12h2.444zm7.972 3.004c-.004-.855.171-1.702.514-2.484.33-.759.804-1.446 1.394-2.022.602-.58 1.307-1.039 2.078-1.352a6.9 6.9 0 0 1 5.14 0 6.55 6.55 0 0 1 2.079 1.352 6.38 6.38 0 0 1 1.393 2.022c.339.783.514 1.629.514 2.484s-.175 1.701-.514 2.484a6.37 6.37 0 0 1-1.393 2.022 6.39 6.39 0 0 1-2.079 1.34 7.05 7.05 0 0 1-5.14 0 6.37 6.37 0 0 1-2.078-1.34 6.37 6.37 0 0 1-1.394-2.022c-.343-.782-.518-1.629-.514-2.484zm6.556 3.097a2.76 2.76 0 0 0 1.14-.226 2.8 2.8 0 0 0 .951-.676c.55-.6.856-1.388.856-2.207s-.306-1.607-.856-2.207a2.9 2.9 0 0 0-.955-.666c-.359-.155-.745-.235-1.136-.235a2.87 2.87 0 0 0-1.136.235 2.92 2.92 0 0 0-.954.666c-.55.6-.856 1.388-.856 2.207s.306 1.607.856 2.207a2.81 2.81 0 0 0 .95.676 2.77 2.77 0 0 0 1.14.226zm8.292-9.22v12.224h3.701v-7.764a3.33 3.33 0 0 1 1.199-1.132c.492-.277 1.047-.42 1.61-.416.315-.001.629.034.937.104a4.55 4.55 0 0 1 .822.266v-3.258a1.36 1.36 0 0 0-.548-.22c-.28-.045-.562-.072-.845-.081-.616-.009-1.226.126-1.782.393a4.21 4.21 0 0 0-1.393 1.109v-1.225h-3.701zm20.49 10.606a7.75 7.75 0 0 1-2.341 1.41c-.871.304-1.787.453-2.708.439a6.87 6.87 0 0 1-2.581-.485 6.35 6.35 0 0 1-2.09-1.34c-.59-.576-1.064-1.262-1.393-2.022a6.08 6.08 0 0 1-.514-2.484c-.005-.853.162-1.699.491-2.484a6.35 6.35 0 0 1 1.336-2.022 6.01 6.01 0 0 1 1.999-1.34 6.33 6.33 0 0 1 2.478-.485 5.85 5.85 0 0 1 2.385.482c.753.326 1.43.807 1.99 1.413.557.613.988 1.332 1.268 2.114a7.65 7.65 0 0 1 .456 2.669v.924h-8.611a3.22 3.22 0 0 0 1.142 1.398 3.11 3.11 0 0 0 1.827.543 3.71 3.71 0 0 0 1.371-.243c.393-.15.751-.383 1.051-.682l2.444 2.195zm-5.391-7.764a2.51 2.51 0 0 0-1.576.508c-.458.362-.786.865-.937 1.433h5.049c-.179-.557-.517-1.047-.971-1.41a2.46 2.46 0 0 0-1.565-.532zm17.794 9.382V11.135h3.701v1.225a4.21 4.21 0 0 1 1.393-1.109c.556-.267 1.166-.402 1.782-.393.283.009.565.036.845.081a1.36 1.36 0 0 1 .548.22v3.258a4.49 4.49 0 0 0-.823-.266 4.21 4.21 0 0 0-.936-.104c-.563-.004-1.118.139-1.61.416a3.33 3.33 0 0 0-1.199 1.132v7.764h-3.701zm9.377-8.585a6.08 6.08 0 0 0-.514 2.484 6.08 6.08 0 0 0 .514 2.484c.329.759.803 1.446 1.393 2.022a6.37 6.37 0 0 0 2.079 1.34c1.653.647 3.486.647 5.139 0a6.37 6.37 0 0 0 2.079-1.34c.59-.576 1.064-1.262 1.393-2.022.339-.783.514-1.629.514-2.484s-.175-1.701-.514-2.484a6.38 6.38 0 0 0-1.393-2.022 6.54 6.54 0 0 0-2.079-1.352c-1.65-.662-3.488-.662-5.139 0a6.54 6.54 0 0 0-2.079 1.352 6.38 6.38 0 0 0-1.393 2.022zm7.181 5.355a2.76 2.76 0 0 1-1.14.226 2.76 2.76 0 0 1-1.139-.226c-.36-.155-.684-.386-.95-.676-.551-.6-.857-1.388-.857-2.207a3.26 3.26 0 0 1 .857-2.207 2.88 2.88 0 0 1 2.09-.901c.391 0 .776.08 1.136.235a2.91 2.91 0 0 1 .954.666c.55.6.856 1.388.856 2.207s-.306 1.607-.856 2.207a2.79 2.79 0 0 1-.951.676zm7.152-8.994h3.701v.832c.452-.344.957-.61 1.496-.786a5.5 5.5 0 0 1 1.747-.277c1.417 0 2.574.462 3.472 1.386s1.348 2.103 1.348 3.535v7.533h-3.7v-7.025a2.14 2.14 0 0 0-.133-.868 2.12 2.12 0 0 0-.473-.738 2.07 2.07 0 0 0-.729-.478 2.06 2.06 0 0 0-.858-.135 2.95 2.95 0 0 0-1.256.254 2.47 2.47 0 0 0-.914.716v8.272h-3.701V11.135zm15.214 3.119v5.384c-.001 1.279.369 2.246 1.107 2.9s1.831.982 3.278.982c.436-.007.871-.041 1.302-.104a7.56 7.56 0 0 0 1.279-.266v-3.027a5.82 5.82 0 0 1-.845.196c-.272.04-.547.059-.822.058-.594 0-1.009-.112-1.245-.335s-.354-.604-.354-1.144v-4.645h3.381v-3.12h-3.381v-3.95l-3.7.809v3.143h-2.445v3.12h2.445zM12.458.942c-.247.155-.489.401-.974.891l-.881.985c-.508.827-.508 1.874 0 2.701.154.25.396.495.88.985h0c.485.49.727.735.974.891.817.514 1.852.514 2.67 0 .247-.155.489-.401.974-.891l.881-.985c.508-.827.508-1.874 0-2.701-.153-.25-.396-.495-.88-.985s-.727-.735-.974-.891c-.817-.514-1.853-.514-2.67 0zm3.189 15.339l5.64-5.705c.234-.236.511-.424.816-.552a2.49 2.49 0 0 1 1.926 0 2.5 2.5 0 0 1 .816.552l2.834 2.867-13.839 14-13.84-14 2.864-2.897c.234-.236.511-.424.816-.552a2.49 2.49 0 0 1 1.925 0 2.51 2.51 0 0 1 .816.552l5.669 5.735c.234.236.511.424.816.552s.632.194.963.194a2.49 2.49 0 0 0 .963-.194 2.51 2.51 0 0 0 .816-.552z"
|
|
5
|
+
/>
|
|
6
|
+
</svg>
|
|
7
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
|
|
3
|
+
const props = withDefaults(defineProps<{
|
|
4
|
+
modelValue?: boolean
|
|
5
|
+
label?: string
|
|
6
|
+
autoGenerated?: boolean
|
|
7
|
+
}>(), {
|
|
8
|
+
modelValue: false,
|
|
9
|
+
label: '',
|
|
10
|
+
autoGenerated: false,
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const emit = defineEmits(['update:modelValue'])
|
|
14
|
+
|
|
15
|
+
const model = ref<boolean>(props.modelValue ?? false)
|
|
16
|
+
|
|
17
|
+
watch(model, (v) => emit('update:modelValue', v))
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div style="display:flex;align-items:center;gap:8px">
|
|
22
|
+
<v-switch
|
|
23
|
+
v-model="model"
|
|
24
|
+
:label="props.label || (model ? 'True' : 'False')"
|
|
25
|
+
inset
|
|
26
|
+
hide-details
|
|
27
|
+
/>
|
|
28
|
+
<span v-if="props.autoGenerated" class="auto-badge">Auto</span>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<style scoped>
|
|
33
|
+
.auto-badge{font-size:12px;padding:4px 6px;border-radius:4px;background:#eee;color:#333}
|
|
34
|
+
</style>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(defineProps<{
|
|
5
|
+
defaultValue?: string
|
|
6
|
+
label?: string
|
|
7
|
+
width?: string | null
|
|
8
|
+
field: string
|
|
9
|
+
required?: boolean
|
|
10
|
+
options?: Record<string, any> | null
|
|
11
|
+
modelValue?: string
|
|
12
|
+
autoGenerated?: boolean
|
|
13
|
+
}>(), {
|
|
14
|
+
required: false,
|
|
15
|
+
options: null,
|
|
16
|
+
width: null,
|
|
17
|
+
autoGenerated: false,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const emit = defineEmits(['update:modelValue'])
|
|
21
|
+
|
|
22
|
+
const fieldWidth = props.width === 'full' ? '100%' : '50%'
|
|
23
|
+
|
|
24
|
+
const dateTimeValue = computed({
|
|
25
|
+
get() {
|
|
26
|
+
return props.modelValue || props.defaultValue || ''
|
|
27
|
+
},
|
|
28
|
+
set(value) {
|
|
29
|
+
emit('update:modelValue', value)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<div :style="'width: ' + fieldWidth + '; display:flex; align-items:center; gap:8px'">
|
|
36
|
+
<v-text-field :name="field" v-model="dateTimeValue" type="datetime-local" :required="required" :label="label" style="flex:1" />
|
|
37
|
+
<span v-if="props.autoGenerated" class="auto-badge">Auto</span>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
41
|
+
<style scoped>
|
|
42
|
+
.auto-badge{font-size:12px;padding:4px 6px;border-radius:4px;background:#eee;color:#333}
|
|
43
|
+
input {width:100%;}
|
|
44
|
+
</style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="loading">Loading form…</div>
|
|
3
|
+
|
|
4
|
+
<form v-else @submit.prevent="submit" class="space-y-4">
|
|
5
|
+
<FormField v-for="field in schema" :key="field.key" :field="field" :form="engine.form" />
|
|
6
|
+
|
|
7
|
+
<button type="submit" class="btn-primary">
|
|
8
|
+
{{ submitLabel || 'Submit' }}
|
|
9
|
+
</button>
|
|
10
|
+
</form>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import {
|
|
15
|
+
ref,
|
|
16
|
+
onMounted
|
|
17
|
+
} from 'vue';
|
|
18
|
+
import {
|
|
19
|
+
useVueDirectus
|
|
20
|
+
} from '@meeovi/directus-client';
|
|
21
|
+
import {
|
|
22
|
+
generateFieldSchema,
|
|
23
|
+
createFormEngine
|
|
24
|
+
} from '@meeovi/directus-client';
|
|
25
|
+
|
|
26
|
+
const props = defineProps < {
|
|
27
|
+
collection: string;
|
|
28
|
+
submitLabel ? : string;
|
|
29
|
+
} > ();
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits(['submitted']);
|
|
32
|
+
|
|
33
|
+
const directus = useVueDirectus();
|
|
34
|
+
const loading = ref(true);
|
|
35
|
+
const schema = ref < any[] > ([]);
|
|
36
|
+
const engine = ref < any > (null);
|
|
37
|
+
|
|
38
|
+
onMounted(async () => {
|
|
39
|
+
const fields = await directus.client.request(
|
|
40
|
+
directus.readFieldsByCollection(props.collection)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
schema.value = generateFormSchema(fields);
|
|
44
|
+
|
|
45
|
+
engine.value = createFormEngine(
|
|
46
|
+
props.collection,
|
|
47
|
+
fields,
|
|
48
|
+
directus, {
|
|
49
|
+
clearOnSuccess: false
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
loading.value = false;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
async function submit() {
|
|
57
|
+
const result = await engine.value.submit();
|
|
58
|
+
emit('submitted', result);
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
ref,
|
|
4
|
+
onMounted
|
|
5
|
+
} from 'vue';
|
|
6
|
+
import {
|
|
7
|
+
useVueDirectus
|
|
8
|
+
} from '@meeovi/directus-client';
|
|
9
|
+
import {
|
|
10
|
+
generateTableSchema
|
|
11
|
+
} from '@meeovi/directus-client';
|
|
12
|
+
|
|
13
|
+
const props = defineProps < {
|
|
14
|
+
collection: string;
|
|
15
|
+
} > ();
|
|
16
|
+
|
|
17
|
+
const directus = useVueDirectus();
|
|
18
|
+
const loading = ref(true);
|
|
19
|
+
const rows = ref < any[] > ([]);
|
|
20
|
+
const columns = ref < any[] > ([]);
|
|
21
|
+
|
|
22
|
+
onMounted(async () => {
|
|
23
|
+
const fields = await directus.client.request(
|
|
24
|
+
directus.readFieldsByCollection(props.collection)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
columns.value = generateTableSchema(fields);
|
|
28
|
+
|
|
29
|
+
rows.value = await directus.client.request(
|
|
30
|
+
directus.readItems(props.collection)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
loading.value = false;
|
|
34
|
+
});
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<div v-if="loading">Loading table…</div>
|
|
39
|
+
|
|
40
|
+
<table v-else class="auto-table">
|
|
41
|
+
<thead>
|
|
42
|
+
<tr>
|
|
43
|
+
<th v-for="col in columns" :key="col.key">
|
|
44
|
+
{{ col.label }}
|
|
45
|
+
</th>
|
|
46
|
+
</tr>
|
|
47
|
+
</thead>
|
|
48
|
+
|
|
49
|
+
<tbody>
|
|
50
|
+
<tr v-for="row in rows" :key="row.id">
|
|
51
|
+
<td v-for="col in columns" :key="col.key">
|
|
52
|
+
{{ row[col.key] }}
|
|
53
|
+
</td>
|
|
54
|
+
</tr>
|
|
55
|
+
</tbody>
|
|
56
|
+
</table>
|
|
57
|
+
</template>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(defineProps<{
|
|
5
|
+
defaultValue?: string
|
|
6
|
+
label?: string
|
|
7
|
+
options?: Record<string, any> | null
|
|
8
|
+
width?: string | null
|
|
9
|
+
field: string
|
|
10
|
+
required?: boolean
|
|
11
|
+
modelValue?: any
|
|
12
|
+
autoGenerated?: boolean
|
|
13
|
+
}>(), {
|
|
14
|
+
required: false,
|
|
15
|
+
options: null,
|
|
16
|
+
width: null,
|
|
17
|
+
autoGenerated: false,
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const emit = defineEmits(['update:modelValue'])
|
|
21
|
+
|
|
22
|
+
const fieldWidth = props.width === 'full' ? '100%' : '50%'
|
|
23
|
+
|
|
24
|
+
const fileInput = ref(null)
|
|
25
|
+
const selectedFile = ref<File[] | null>(null)
|
|
26
|
+
|
|
27
|
+
const fileInputValue = computed({
|
|
28
|
+
get() {
|
|
29
|
+
return props.modelValue || props.defaultValue || null
|
|
30
|
+
},
|
|
31
|
+
set(value) {
|
|
32
|
+
selectedFile.value = value
|
|
33
|
+
|
|
34
|
+
// If we have a file, prepare it for upload
|
|
35
|
+
if (value && value.length > 0) {
|
|
36
|
+
const file = value[0]
|
|
37
|
+
|
|
38
|
+
// Create FormData for file upload
|
|
39
|
+
const formData = new FormData()
|
|
40
|
+
formData.append('file', file)
|
|
41
|
+
|
|
42
|
+
// Store the file object to be used during form submission
|
|
43
|
+
emit('update:modelValue', {
|
|
44
|
+
file: file,
|
|
45
|
+
formData: formData,
|
|
46
|
+
fileName: file.name,
|
|
47
|
+
fileType: file.type,
|
|
48
|
+
fileSize: file.size
|
|
49
|
+
})
|
|
50
|
+
} else {
|
|
51
|
+
emit('update:modelValue', null)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
</script>
|
|
56
|
+
|
|
57
|
+
<template>
|
|
58
|
+
<div :style="'width: ' + fieldWidth + '; display:flex; align-items:center; gap:8px'">
|
|
59
|
+
<v-file-input
|
|
60
|
+
ref="fileInput"
|
|
61
|
+
clearable
|
|
62
|
+
density="compact"
|
|
63
|
+
:name="field"
|
|
64
|
+
v-model="fileInputValue"
|
|
65
|
+
:label="label"
|
|
66
|
+
:required="required"
|
|
67
|
+
variant="solo-inverted"
|
|
68
|
+
accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.csv,.txt"
|
|
69
|
+
prepend-icon="fas:fa fa-paperclip"
|
|
70
|
+
:hint="selectedFile && selectedFile.length ? `${selectedFile.length} file(s) selected` : 'No file selected'"
|
|
71
|
+
persistent-hint
|
|
72
|
+
/>
|
|
73
|
+
<span v-if="props.autoGenerated" class="auto-badge">Auto</span>
|
|
74
|
+
</div>
|
|
75
|
+
</template>
|
|
76
|
+
|
|
77
|
+
<style scoped>
|
|
78
|
+
input {
|
|
79
|
+
width: 100%;
|
|
80
|
+
}
|
|
81
|
+
</style>
|
|
82
|
+
|
|
83
|
+
<style scoped>
|
|
84
|
+
.auto-badge{font-size:12px;padding:4px 6px;border-radius:4px;background:#eee;color:#333}
|
|
85
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
widgetRegistry
|
|
4
|
+
} from '@meeovi/directus-client';
|
|
5
|
+
|
|
6
|
+
const props = defineProps < {
|
|
7
|
+
field: any;
|
|
8
|
+
form: Record < string,
|
|
9
|
+
any > ;
|
|
10
|
+
} > ();
|
|
11
|
+
|
|
12
|
+
const widget = widgetRegistry[props.field.widget];
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<div v-if="widget">
|
|
17
|
+
<!-- Basic text input -->
|
|
18
|
+
<TextInput v-if="widget.component === 'TextInput'" v-model="form[field.key]" :label="field.key" />
|
|
19
|
+
|
|
20
|
+
<!-- Dropdown -->
|
|
21
|
+
<SelectInput v-else-if="widget.component === 'SelectInput'" v-model="form[field.key]"
|
|
22
|
+
:options="field.options?.choices" :label="field.key" />
|
|
23
|
+
|
|
24
|
+
<!-- Repeater -->
|
|
25
|
+
<RepeaterInput v-else-if="widget.component === 'RepeaterInput'" v-model="form[field.key]" :fields="field.fields"
|
|
26
|
+
:label="field.key" />
|
|
27
|
+
|
|
28
|
+
<!-- File upload -->
|
|
29
|
+
<FileInput v-else-if="widget.component === 'FileInput'" v-model="form[field.key]" :label="field.key" />
|
|
30
|
+
|
|
31
|
+
<!-- Fallback -->
|
|
32
|
+
<TextInput v-else v-model="form[field.key]" :label="field.key" />
|
|
33
|
+
</div>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-select v-model="internalValue" :items="options" :label="label" :multiple="multiple" item-title="display"
|
|
3
|
+
item-value="id" clearable />
|
|
4
|
+
</template>
|
|
5
|
+
|
|
6
|
+
<script setup>
|
|
7
|
+
import {
|
|
8
|
+
ref,
|
|
9
|
+
onMounted,
|
|
10
|
+
computed
|
|
11
|
+
} from "vue";
|
|
12
|
+
|
|
13
|
+
const props = defineProps({
|
|
14
|
+
modelValue: {
|
|
15
|
+
type: [String, Array],
|
|
16
|
+
default: null
|
|
17
|
+
},
|
|
18
|
+
collection: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true
|
|
21
|
+
}, // related collection name
|
|
22
|
+
label: {
|
|
23
|
+
type: String,
|
|
24
|
+
default: ""
|
|
25
|
+
},
|
|
26
|
+
multiple: {
|
|
27
|
+
type: Boolean,
|
|
28
|
+
default: false
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
33
|
+
const {
|
|
34
|
+
$directus,
|
|
35
|
+
$readItems
|
|
36
|
+
} = useNuxtApp();
|
|
37
|
+
|
|
38
|
+
const internalValue = computed({
|
|
39
|
+
get: () => props.modelValue,
|
|
40
|
+
set: (v) => emit("update:modelValue", v),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const options = ref([]);
|
|
44
|
+
|
|
45
|
+
onMounted(async () => {
|
|
46
|
+
try {
|
|
47
|
+
const {
|
|
48
|
+
data
|
|
49
|
+
} = await $directus.request(
|
|
50
|
+
$readItems(props.collection, {
|
|
51
|
+
limit: 50, // adjust as needed
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
// Map to display-friendly format
|
|
55
|
+
options.value = data.map((item) => ({
|
|
56
|
+
id: item.id,
|
|
57
|
+
display: item.name || item.title || `Item ${item.id}`,
|
|
58
|
+
}));
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error("Failed to load relation options:", err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
</script>
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed, watch } from 'vue'
|
|
3
|
+
import DirectusFormElement from './DirectusFormElement.vue'
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(defineProps<{
|
|
6
|
+
modelValue?: any
|
|
7
|
+
field: string
|
|
8
|
+
label?: string
|
|
9
|
+
options?: Record<string, any>
|
|
10
|
+
required?: boolean
|
|
11
|
+
width?: string | null
|
|
12
|
+
autoGenerated?: boolean
|
|
13
|
+
}>(), {
|
|
14
|
+
options: () => ({} as Record<string, any>),
|
|
15
|
+
label: '',
|
|
16
|
+
required: false,
|
|
17
|
+
width: null,
|
|
18
|
+
autoGenerated: false,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const emit = defineEmits(['update:modelValue'])
|
|
22
|
+
|
|
23
|
+
const items = ref<Array<any>>(Array.isArray(props.modelValue) ? JSON.parse(JSON.stringify(props.modelValue)) : [])
|
|
24
|
+
const jsonMode = ref(false)
|
|
25
|
+
|
|
26
|
+
watch(() => props.modelValue, (v) => {
|
|
27
|
+
items.value = Array.isArray(v) ? JSON.parse(JSON.stringify(v)) : []
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const createEmptyItem = () => {
|
|
31
|
+
const fields = (props.options && Array.isArray(props.options.fields)) ? props.options.fields : null
|
|
32
|
+
if (!fields) return ''
|
|
33
|
+
const obj: Record<string, any> = {}
|
|
34
|
+
for (const f of fields) {
|
|
35
|
+
obj[f.field] = f.schema?.default_value ?? ''
|
|
36
|
+
}
|
|
37
|
+
return obj
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const addItem = () => {
|
|
41
|
+
items.value.push(createEmptyItem())
|
|
42
|
+
emit('update:modelValue', items.value)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const removeItem = (idx: number) => {
|
|
46
|
+
items.value.splice(idx, 1)
|
|
47
|
+
emit('update:modelValue', items.value)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const updateItem = (idx: number, val: any) => {
|
|
51
|
+
items.value[idx] = val
|
|
52
|
+
emit('update:modelValue', items.value)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const toggleJson = () => {
|
|
56
|
+
jsonMode.value = !jsonMode.value
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Handle textarea input for JSON mode in script (typed), avoiding template typing issues.
|
|
61
|
+
*/
|
|
62
|
+
const onJsonInput = (e: Event) => {
|
|
63
|
+
const target = e.target as HTMLTextAreaElement | null
|
|
64
|
+
if (!target) return
|
|
65
|
+
const text = target.value
|
|
66
|
+
try {
|
|
67
|
+
const parsed = JSON.parse(text)
|
|
68
|
+
emit('update:modelValue', parsed)
|
|
69
|
+
items.value = Array.isArray(parsed) ? parsed : []
|
|
70
|
+
} catch (err) {
|
|
71
|
+
// ignore invalid json until saved
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<div :style="'width: ' + (props.width === 'full' ? '100%' : '50%')">
|
|
78
|
+
<label style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px">
|
|
79
|
+
<span>{{ props.label || props.field }}</span>
|
|
80
|
+
<button type="button" @click="toggleJson" style="font-size:12px">{{ jsonMode ? 'Edit Items' : 'Edit JSON' }}</button>
|
|
81
|
+
</label>
|
|
82
|
+
|
|
83
|
+
<div v-if="!jsonMode">
|
|
84
|
+
<div v-for="(it, idx) in items" :key="idx" style="border:1px solid #eee;padding:8px;margin-bottom:8px">
|
|
85
|
+
<div style="display:flex;flex-direction:column;gap:8px">
|
|
86
|
+
<template v-if="props.options && Array.isArray(props.options.fields) && props.options.fields.length">
|
|
87
|
+
<DirectusFormElement
|
|
88
|
+
v-for="sub in props.options.fields"
|
|
89
|
+
:key="sub.field"
|
|
90
|
+
:field="sub"
|
|
91
|
+
v-model="items[idx][sub.field]"
|
|
92
|
+
/>
|
|
93
|
+
</template>
|
|
94
|
+
<template v-else>
|
|
95
|
+
<div style="display:flex;gap:8px;align-items:center;margin-bottom:6px">
|
|
96
|
+
<input type="text" v-model="items[idx]" @input="updateItem(idx, items[idx])" style="flex:1;padding:8px" />
|
|
97
|
+
</div>
|
|
98
|
+
</template>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div style="display:flex;justify-content:flex-end;margin-top:8px">
|
|
102
|
+
<button type="button" @click="removeItem(idx)" style="padding:6px">Remove</button>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<button type="button" @click="addItem" style="padding:6px">Add item</button>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div v-else>
|
|
110
|
+
<textarea
|
|
111
|
+
style="width:100%;min-height:200px;padding:8px"
|
|
112
|
+
:value="JSON.stringify(items, null, 2)"
|
|
113
|
+
@input="onJsonInput"
|
|
114
|
+
></textarea>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</template>
|
|
118
|
+
|
|
119
|
+
<style scoped>
|
|
120
|
+
button{cursor:pointer}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
interface Choice {
|
|
5
|
+
text: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const props = withDefaults(defineProps<{
|
|
10
|
+
defaultValue?: string
|
|
11
|
+
label?: string
|
|
12
|
+
options?: Record<string, any>
|
|
13
|
+
width?: string | null
|
|
14
|
+
field: string
|
|
15
|
+
required?: boolean
|
|
16
|
+
modelValue?: string
|
|
17
|
+
autoGenerated?: boolean
|
|
18
|
+
}>(), {
|
|
19
|
+
required: false,
|
|
20
|
+
options: {},
|
|
21
|
+
width: null,
|
|
22
|
+
autoGenerated: false,
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const emit = defineEmits(['update:modelValue'])
|
|
26
|
+
|
|
27
|
+
const fieldWidth = props.width === 'full' ? '100%' : '50%'
|
|
28
|
+
|
|
29
|
+
const selectValue = computed({
|
|
30
|
+
get() {
|
|
31
|
+
return props.modelValue || props.defaultValue || ''
|
|
32
|
+
},
|
|
33
|
+
set(value) {
|
|
34
|
+
emit('update:modelValue', value)
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// Transform options for v-select
|
|
39
|
+
const items = computed(() => {
|
|
40
|
+
return props.options?.choices?.map((choice: Choice) => ({
|
|
41
|
+
title: choice.text,
|
|
42
|
+
value: choice.value
|
|
43
|
+
})) || []
|
|
44
|
+
})
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<template>
|
|
48
|
+
<div :style="'width: ' + fieldWidth + '; display:flex; align-items:center; gap:8px'">
|
|
49
|
+
<v-select
|
|
50
|
+
:name="field"
|
|
51
|
+
v-model="selectValue"
|
|
52
|
+
:items="items"
|
|
53
|
+
:label="label"
|
|
54
|
+
:required="required"
|
|
55
|
+
variant="solo-inverted"
|
|
56
|
+
density="compact"
|
|
57
|
+
style="flex:1"
|
|
58
|
+
/>
|
|
59
|
+
<span v-if="props.autoGenerated" class="auto-badge">Auto</span>
|
|
60
|
+
</div>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
<style scoped>
|
|
64
|
+
.auto-badge{font-size:12px;padding:4px 6px;border-radius:4px;background:#eee;color:#333}
|
|
65
|
+
</style>
|