@dejwcake/craftable 0.1.9 → 2.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 (126) hide show
  1. package/README.md +117 -3
  2. package/dist/buildMatchPatternFn-BV4I8r8j.js +63 -0
  3. package/dist/buildMatchPatternFn-T5KjFTBQ.cjs +1 -0
  4. package/dist/craftable.css +2 -0
  5. package/dist/cs-B5QMxFrl.js +682 -0
  6. package/dist/cs-MAoetkhe.cjs +1 -0
  7. package/dist/de-BlQ2ZKmc.js +526 -0
  8. package/dist/de-BoVLAn6U.cjs +1 -0
  9. package/dist/en-US-BLvEnhs4.js +443 -0
  10. package/dist/en-US-Dz8vkDZ_.cjs +1 -0
  11. package/dist/en-US-X9gX759i.cjs +1 -0
  12. package/dist/es-DBHDeXHI.cjs +1 -0
  13. package/dist/es-YEqfkBY2.js +437 -0
  14. package/dist/fr-B7MHC2AN.js +407 -0
  15. package/dist/fr-DLs3QoNB.cjs +1 -0
  16. package/dist/hu-BKZPI9jH.cjs +1 -0
  17. package/dist/hu-reoJgNxD.js +425 -0
  18. package/dist/index.cjs +1 -0
  19. package/dist/index.mjs +3866 -0
  20. package/dist/isSameWeek-CC6GX_zp.js +40 -0
  21. package/dist/isSameWeek-Mctj6Tdj.cjs +1 -0
  22. package/dist/pl-B5A0Rjp7.js +628 -0
  23. package/dist/pl-BMyrOO-Q.cjs +1 -0
  24. package/dist/sk-B7JF2MoV.cjs +1 -0
  25. package/dist/sk-Btro3W4S.js +602 -0
  26. package/package.json +68 -40
  27. package/scripts/publish-components.js +118 -0
  28. package/scss/_images.scss +1 -1
  29. package/scss/_variables.scss +13 -6
  30. package/scss/app.scss +4 -4
  31. package/scss/overrides/_alerts.scss +0 -2
  32. package/scss/overrides/_badges.scss +1 -17
  33. package/scss/overrides/_buttons.scss +64 -7
  34. package/scss/overrides/_cards.scss +4 -51
  35. package/scss/overrides/_checkboxes.scss +54 -59
  36. package/scss/overrides/_forms.scss +270 -176
  37. package/scss/overrides/_index.scss +18 -18
  38. package/scss/overrides/_keyframes.scss +6 -4
  39. package/scss/overrides/_layout.scss +24 -30
  40. package/scss/overrides/_media-wysiwyg.scss +9 -111
  41. package/scss/overrides/_modal.scss +0 -18
  42. package/scss/overrides/_multiselect.scss +63 -7
  43. package/scss/overrides/_nav.scss +55 -33
  44. package/scss/overrides/_notifications.scss +6 -1
  45. package/scss/overrides/_pagination.scss +3 -3
  46. package/scss/overrides/_sidebar.scss +84 -0
  47. package/scss/overrides/_tables.scss +52 -37
  48. package/scss/overrides/_text.scss +1 -3
  49. package/scss/overrides/_wysiwyg.scss +151 -48
  50. package/scss/styles/_auth.scss +32 -37
  51. package/scss/styles/_custom.scss +44 -1
  52. package/scss/styles/_index.scss +4 -4
  53. package/scss/styles/_legacy.scss +5 -81
  54. package/scss/styles/_others.scss +232 -337
  55. package/scss/vendor/_index.scss +5 -4
  56. package/src/auth/ActivationError.vue +23 -0
  57. package/src/auth/ActivationForm.vue +69 -0
  58. package/src/auth/ForgotPasswordForm.vue +74 -0
  59. package/src/auth/LoginForm.vue +107 -0
  60. package/src/auth/ResetPasswordForm.vue +122 -0
  61. package/src/components/ConfirmModal.vue +65 -0
  62. package/src/components/UserDetailTooltip.vue +88 -0
  63. package/src/components/form/CkeditorEditor.vue +205 -0
  64. package/src/components/form/FormCheckbox.vue +29 -0
  65. package/src/components/form/FormDatePicker.vue +52 -0
  66. package/src/components/form/FormEmail.vue +17 -0
  67. package/src/components/form/FormInput.vue +31 -0
  68. package/src/components/form/FormLocalizedInput.vue +47 -0
  69. package/src/components/form/FormLocalizedWysiwyg.vue +55 -0
  70. package/src/components/form/FormLocalizedWysiwygSimple.vue +55 -0
  71. package/src/components/form/FormMultiSelect.vue +36 -0
  72. package/src/components/form/FormPasswordConfirm.vue +49 -0
  73. package/src/components/form/FormSelect.vue +35 -0
  74. package/src/components/form/FormSubmit.vue +13 -0
  75. package/src/components/form/FormTextarea.vue +31 -0
  76. package/src/components/form/FormWysiwyg.vue +31 -0
  77. package/src/components/form/FormWysiwygSimple.vue +31 -0
  78. package/src/components/form/LocalizationBar.vue +90 -0
  79. package/src/components/form/MediaUpload.vue +317 -0
  80. package/src/components/form/TiptapEditor.vue +238 -0
  81. package/src/components/listing/BulkCheckboxHeader.vue +18 -0
  82. package/src/components/listing/BulkCheckboxRow.vue +21 -0
  83. package/src/components/listing/BulkOperationsBar.vue +41 -0
  84. package/src/components/listing/DeleteButton.vue +46 -0
  85. package/src/components/listing/EditButton.vue +17 -0
  86. package/src/components/listing/EmptyState.vue +25 -0
  87. package/src/components/listing/ListingHeader.vue +24 -0
  88. package/src/components/listing/Pagination.vue +158 -0
  89. package/src/components/listing/PerPage.vue +15 -0
  90. package/src/components/listing/PublishedAtColumn.vue +226 -0
  91. package/src/components/listing/Search.vue +81 -0
  92. package/src/components/listing/Sortable.vue +28 -0
  93. package/src/components/listing/ToggleSwitch.vue +47 -0
  94. package/src/composables/useAdmin.js +39 -0
  95. package/src/composables/useBaseAuth.js +81 -0
  96. package/src/composables/useBaseForm.js +265 -0
  97. package/src/composables/useBaseListing.js +316 -0
  98. package/src/composables/useResponsiveColumns.js +62 -0
  99. package/src/index.js +62 -0
  100. package/src/translation/TranslationListing.vue +230 -0
  101. package/src/translation/modals/TranslationEditModal.vue +86 -0
  102. package/src/translation/modals/TranslationExportModal.vue +74 -0
  103. package/src/translation/modals/TranslationImportModal.vue +255 -0
  104. package/src/ui/index.js +99 -0
  105. package/src/utils/ckeditorHelpers.js +36 -0
  106. package/src/utils/dateFnsLocale.js +24 -0
  107. package/src/utils/dateFormatters.js +30 -0
  108. package/src/utils/mediaProps.js +14 -0
  109. package/src/utils/notify.js +22 -0
  110. package/dist/admin/Admin.js +0 -42
  111. package/dist/auth/Form.js +0 -15
  112. package/dist/base-components/Form/BaseForm.js +0 -392
  113. package/dist/base-components/Form/BaseUpload.js +0 -188
  114. package/dist/base-components/Form/bootstrap.js +0 -21
  115. package/dist/base-components/Listing/BaseListing.js +0 -454
  116. package/dist/base-components/Listing/components/Pagination.js +0 -105
  117. package/dist/base-components/Listing/components/Sortable.js +0 -48
  118. package/dist/base-components/Listing/components/UserDetailTooltip.js +0 -55
  119. package/dist/index.js +0 -70
  120. package/dist/overrides/trumbowyg.edit-embed-template.js +0 -72
  121. package/dist/overrides/trumbowyg.reupload.js +0 -146
  122. package/dist/overrides/trumbowyg.template.js +0 -67
  123. package/dist/translation/Form.js +0 -15
  124. package/dist/translation/Listing.js +0 -283
  125. package/dist/ui/index.js +0 -33
  126. package/scss/overrides/_switches.scss +0 -25
@@ -0,0 +1,205 @@
1
+ <template>
2
+ <div class="ck-editor-wrapper">
3
+ <ckeditor v-model="content" :editor="ClassicEditor" :config="editorConfig" />
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ import { computed, toRaw } from 'vue';
9
+ import {
10
+ ClassicEditor,
11
+ Essentials,
12
+ Bold,
13
+ Italic,
14
+ Underline,
15
+ Strikethrough,
16
+ Heading,
17
+ Paragraph,
18
+ Alignment,
19
+ List,
20
+ Link,
21
+ AutoLink,
22
+ Image,
23
+ ImageToolbar,
24
+ ImageCaption,
25
+ ImageStyle,
26
+ ImageResize,
27
+ ImageInsert,
28
+ ImageInsertViaUrl,
29
+ ImageUpload,
30
+ Table,
31
+ TableToolbar,
32
+ CodeBlock,
33
+ Code,
34
+ SourceEditing,
35
+ BlockQuote,
36
+ HorizontalLine,
37
+ Indent,
38
+ GeneralHtmlSupport,
39
+ Undo,
40
+ FileRepository,
41
+ } from 'ckeditor5';
42
+ import { Ckeditor } from '@ckeditor/ckeditor5-vue';
43
+ import { propagateImageWidths, deepMerge } from '../../utils/ckeditorHelpers.js';
44
+ const axios = window.axios;
45
+
46
+ import 'ckeditor5/ckeditor5.css';
47
+
48
+ const props = defineProps({
49
+ modelValue: { type: String, default: '' },
50
+ config: { type: Object, default: null },
51
+ uploadUrl: { type: String, default: '/admin/wysiwyg-media' },
52
+ });
53
+
54
+ const emit = defineEmits(['update:modelValue', 'media-uploaded']);
55
+
56
+ const content = computed({
57
+ get: () => props.modelValue ?? '',
58
+ set: (val) => emit('update:modelValue', propagateImageWidths(val)),
59
+ });
60
+
61
+ function createUploadAdapterPlugin(editor) {
62
+ editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
63
+ return new CsrfUploadAdapter(loader, props.uploadUrl);
64
+ };
65
+ }
66
+
67
+ class CsrfUploadAdapter {
68
+ constructor(loader, url) {
69
+ this.loader = loader;
70
+ this.url = url;
71
+ }
72
+
73
+ upload() {
74
+ return this.loader.file.then((file) => {
75
+ const formData = new FormData();
76
+ formData.append('fileToUpload', file);
77
+
78
+ return axios
79
+ .post(this.url, formData, {
80
+ headers: { 'Content-Type': 'multipart/form-data' },
81
+ onUploadProgress: (evt) => {
82
+ if (evt.total) {
83
+ this.loader.uploadTotal = evt.total;
84
+ this.loader.uploaded = evt.loaded;
85
+ }
86
+ },
87
+ })
88
+ .then((response) => {
89
+ const url = response.data.file || response.data.url || response.data;
90
+ emit('media-uploaded', response.data);
91
+ return { default: url };
92
+ });
93
+ });
94
+ }
95
+
96
+ abort() {}
97
+ }
98
+
99
+ const defaultConfig = {
100
+ licenseKey: 'GPL',
101
+ plugins: [
102
+ Essentials,
103
+ Bold,
104
+ Italic,
105
+ Underline,
106
+ Strikethrough,
107
+ Heading,
108
+ Paragraph,
109
+ Alignment,
110
+ List,
111
+ Link,
112
+ AutoLink,
113
+ Image,
114
+ ImageToolbar,
115
+ ImageCaption,
116
+ ImageStyle,
117
+ ImageResize,
118
+ ImageInsert,
119
+ ImageInsertViaUrl,
120
+ ImageUpload,
121
+ Table,
122
+ TableToolbar,
123
+ CodeBlock,
124
+ Code,
125
+ SourceEditing,
126
+ BlockQuote,
127
+ HorizontalLine,
128
+ Indent,
129
+ GeneralHtmlSupport,
130
+ Undo,
131
+ FileRepository,
132
+ ],
133
+ extraPlugins: [createUploadAdapterPlugin],
134
+ toolbar: {
135
+ items: [
136
+ 'heading',
137
+ '|',
138
+ 'bold',
139
+ 'italic',
140
+ 'underline',
141
+ 'strikethrough',
142
+ '|',
143
+ 'alignment',
144
+ '|',
145
+ 'bulletedList',
146
+ 'numberedList',
147
+ '|',
148
+ 'blockQuote',
149
+ 'horizontalLine',
150
+ '|',
151
+ 'link',
152
+ 'insertImage',
153
+ 'insertTable',
154
+ '|',
155
+ 'code',
156
+ 'codeBlock',
157
+ '|',
158
+ 'undo',
159
+ 'redo',
160
+ '|',
161
+ 'sourceEditing',
162
+ ],
163
+ shouldNotGroupWhenFull: true,
164
+ },
165
+ image: {
166
+ toolbar: [
167
+ 'imageStyle:inline',
168
+ 'imageStyle:block',
169
+ 'imageStyle:side',
170
+ '|',
171
+ 'toggleImageCaption',
172
+ 'imageTextAlternative',
173
+ '|',
174
+ 'resizeImage',
175
+ ],
176
+ resizeUnit: 'px',
177
+ resizeOptions: [
178
+ { name: 'resizeImage:original', value: null, label: 'Original' },
179
+ { name: 'resizeImage:200', value: '200', label: '200px' },
180
+ { name: 'resizeImage:400', value: '400', label: '400px' },
181
+ { name: 'resizeImage:600', value: '600', label: '600px' },
182
+ ],
183
+ },
184
+ table: {
185
+ contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells'],
186
+ },
187
+ htmlSupport: {
188
+ allow: [{ name: /.*/, attributes: true, classes: true, styles: true }],
189
+ },
190
+ heading: {
191
+ options: [
192
+ { model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
193
+ { model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' },
194
+ { model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' },
195
+ { model: 'heading3', view: 'h3', title: 'Heading 3', class: 'ck-heading_heading3' },
196
+ { model: 'heading4', view: 'h4', title: 'Heading 4', class: 'ck-heading_heading4' },
197
+ ],
198
+ },
199
+ };
200
+
201
+ const editorConfig = computed(() => {
202
+ if (!props.config) return defaultConfig;
203
+ return deepMerge(defaultConfig, toRaw(props.config));
204
+ });
205
+ </script>
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <div class="col-md-9 col-xl-8 offset-md-3">
4
+ <div class="form-check">
5
+ <input
6
+ :id="name"
7
+ class="form-check-input"
8
+ type="checkbox"
9
+ :checked="modelValue"
10
+ :name="name"
11
+ @change="$emit('update:modelValue', $event.target.checked)"
12
+ />
13
+ <label class="form-check-label" :for="name">{{ label }}</label>
14
+ </div>
15
+ <div v-if="error" class="invalid-feedback d-block form-text">{{ error }}</div>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script setup>
21
+ defineProps({
22
+ modelValue: { type: Boolean, default: false },
23
+ name: { type: String, required: true },
24
+ label: { type: String, required: true },
25
+ error: { type: String, default: '' },
26
+ });
27
+
28
+ defineEmits(['update:modelValue']);
29
+ </script>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <div class="input-group flex-nowrap">
6
+ <span class="input-group-text"><i class="fa" :class="icon"></i></span>
7
+ <VueDatePicker
8
+ v-bind="config"
9
+ :id="name"
10
+ :model-value="modelValue"
11
+ class="datepicker-input"
12
+ :class="{ 'is-invalid': error }"
13
+ :name="name"
14
+ :placeholder="placeholder || label"
15
+ :time-config="{
16
+ enableTimePicker: config.enableTimePicker ?? true,
17
+ enableSeconds: config.enableSeconds ?? false,
18
+ }"
19
+ :formats="{ input: config.format }"
20
+ auto-apply
21
+ :locale="config.locale"
22
+ :input-attrs="{ hideInputIcon: true, clearable: false }"
23
+ @update:model-value="$emit('update:modelValue', $event)"
24
+ ></VueDatePicker>
25
+ </div>
26
+ <div v-if="error" class="invalid-feedback d-block form-text">{{ error }}</div>
27
+ </div>
28
+ </div>
29
+ </template>
30
+
31
+ <script setup>
32
+ import { VueDatePicker } from '@vuepic/vue-datepicker';
33
+
34
+ defineProps({
35
+ modelValue: { type: [String, Date, Object], default: '' },
36
+ name: { type: String, required: true },
37
+ label: { type: String, required: true },
38
+ error: { type: String, default: '' },
39
+ config: { type: Object, required: true },
40
+ icon: { type: String, default: 'fa-calendar' },
41
+ placeholder: { type: String, default: '' },
42
+ });
43
+
44
+ defineEmits(['update:modelValue']);
45
+ </script>
46
+
47
+ <style scoped>
48
+ .datepicker-input {
49
+ flex: 1 1 0;
50
+ min-width: 0;
51
+ }
52
+ </style>
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <FormInput v-bind="$props" type="email" @update:model-value="$emit('update:modelValue', $event)" />
3
+ </template>
4
+
5
+ <script setup>
6
+ import FormInput from './FormInput.vue';
7
+
8
+ defineProps({
9
+ modelValue: { type: [String, Number], default: '' },
10
+ name: { type: String, required: true },
11
+ label: { type: String, required: true },
12
+ error: { type: String, default: '' },
13
+ placeholder: { type: String, default: '' },
14
+ });
15
+
16
+ defineEmits(['update:modelValue']);
17
+ </script>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <input
6
+ :id="name"
7
+ :type="type"
8
+ :value="modelValue"
9
+ class="form-control"
10
+ :class="{ 'is-invalid': error }"
11
+ :name="name"
12
+ :placeholder="placeholder || label"
13
+ @input="$emit('update:modelValue', $event.target.value)"
14
+ />
15
+ <div v-if="error" class="invalid-feedback form-text">{{ error }}</div>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script setup>
21
+ defineProps({
22
+ modelValue: { type: [String, Number], default: '' },
23
+ name: { type: String, required: true },
24
+ label: { type: String, required: true },
25
+ error: { type: String, default: '' },
26
+ type: { type: String, default: 'text' },
27
+ placeholder: { type: String, default: '' },
28
+ });
29
+
30
+ defineEmits(['update:modelValue']);
31
+ </script>
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name + '_' + locales[0]" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <div :class="{ 'd-flex gap-2': isFormLocalized }">
6
+ <div
7
+ v-for="locale in locales"
8
+ v-show="shouldShowLangGroup(locale)"
9
+ :key="locale"
10
+ :class="{ 'flex-fill': isFormLocalized }"
11
+ >
12
+ <input
13
+ :id="name + '_' + locale"
14
+ type="text"
15
+ :value="modelValue[locale]"
16
+ class="form-control"
17
+ :class="{ 'is-invalid': errors[name + '_' + locale] }"
18
+ :name="name + '_' + locale"
19
+ :placeholder="isFormLocalized ? locale.toUpperCase() : label"
20
+ @input="onInput(locale, $event.target.value)"
21
+ />
22
+ <div v-if="errors[name + '_' + locale]" class="invalid-feedback d-block form-text">
23
+ {{ errors[name + '_' + locale] }}
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </div>
29
+ </template>
30
+
31
+ <script setup>
32
+ const props = defineProps({
33
+ modelValue: { type: Object, required: true },
34
+ name: { type: String, required: true },
35
+ label: { type: String, required: true },
36
+ errors: { type: Object, default: () => ({}) },
37
+ locales: { type: Array, required: true },
38
+ shouldShowLangGroup: { type: Function, required: true },
39
+ isFormLocalized: { type: Boolean, default: false },
40
+ });
41
+
42
+ const emit = defineEmits(['update:modelValue']);
43
+
44
+ function onInput(locale, value) {
45
+ emit('update:modelValue', { ...props.modelValue, [locale]: value });
46
+ }
47
+ </script>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name + '_' + locales[0]" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <div :class="{ 'd-flex gap-2': isFormLocalized }">
6
+ <div
7
+ v-for="locale in locales"
8
+ v-show="shouldShowLangGroup(locale)"
9
+ :key="locale"
10
+ :class="{ 'flex-fill localized-editor': isFormLocalized }"
11
+ >
12
+ <CkeditorEditor
13
+ :id="name + '_' + locale"
14
+ :model-value="modelValue[locale]"
15
+ :name="name + '_' + locale"
16
+ :upload-url="uploadUrl"
17
+ v-bind="config ? { config } : {}"
18
+ @update:model-value="onInput(locale, $event)"
19
+ ></CkeditorEditor>
20
+ <div v-if="errors[name + '_' + locale]" class="invalid-feedback d-block form-text">
21
+ {{ errors[name + '_' + locale] }}
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <script setup>
30
+ import CkeditorEditor from './CkeditorEditor.vue';
31
+
32
+ const props = defineProps({
33
+ modelValue: { type: Object, required: true },
34
+ name: { type: String, required: true },
35
+ label: { type: String, required: true },
36
+ errors: { type: Object, default: () => ({}) },
37
+ locales: { type: Array, required: true },
38
+ shouldShowLangGroup: { type: Function, required: true },
39
+ isFormLocalized: { type: Boolean, default: false },
40
+ config: { type: Object, default: null },
41
+ uploadUrl: { type: String, default: '/admin/wysiwyg-media' },
42
+ });
43
+
44
+ const emit = defineEmits(['update:modelValue']);
45
+
46
+ function onInput(locale, value) {
47
+ emit('update:modelValue', { ...props.modelValue, [locale]: value });
48
+ }
49
+ </script>
50
+
51
+ <style scoped>
52
+ .localized-editor {
53
+ min-width: 0;
54
+ }
55
+ </style>
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name + '_' + locales[0]" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <div :class="{ 'd-flex gap-2': isFormLocalized }">
6
+ <div
7
+ v-for="locale in locales"
8
+ v-show="shouldShowLangGroup(locale)"
9
+ :key="locale"
10
+ :class="{ 'flex-fill localized-editor': isFormLocalized }"
11
+ >
12
+ <TiptapEditor
13
+ :id="name + '_' + locale"
14
+ :model-value="modelValue[locale]"
15
+ :name="name + '_' + locale"
16
+ :upload-url="uploadUrl"
17
+ v-bind="config ? { config } : {}"
18
+ @update:model-value="onInput(locale, $event)"
19
+ ></TiptapEditor>
20
+ <div v-if="errors[name + '_' + locale]" class="invalid-feedback d-block form-text">
21
+ {{ errors[name + '_' + locale] }}
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <script setup>
30
+ import TiptapEditor from './TiptapEditor.vue';
31
+
32
+ const props = defineProps({
33
+ modelValue: { type: Object, required: true },
34
+ name: { type: String, required: true },
35
+ label: { type: String, required: true },
36
+ errors: { type: Object, default: () => ({}) },
37
+ locales: { type: Array, required: true },
38
+ shouldShowLangGroup: { type: Function, required: true },
39
+ isFormLocalized: { type: Boolean, default: false },
40
+ config: { type: Object, default: null },
41
+ uploadUrl: { type: String, default: '/admin/wysiwyg-media' },
42
+ });
43
+
44
+ const emit = defineEmits(['update:modelValue']);
45
+
46
+ function onInput(locale, value) {
47
+ emit('update:modelValue', { ...props.modelValue, [locale]: value });
48
+ }
49
+ </script>
50
+
51
+ <style scoped>
52
+ .localized-editor {
53
+ min-width: 0;
54
+ }
55
+ </style>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <Multiselect
6
+ :model-value="modelValue"
7
+ :class="{ 'is-invalid': error }"
8
+ :placeholder="placeholder"
9
+ :options="options"
10
+ :multiple="true"
11
+ :label="optionLabel"
12
+ :track-by="trackBy"
13
+ open-direction="bottom"
14
+ @update:model-value="$emit('update:modelValue', $event)"
15
+ ></Multiselect>
16
+ <div v-if="error" class="invalid-feedback d-block form-text">{{ error }}</div>
17
+ </div>
18
+ </div>
19
+ </template>
20
+
21
+ <script setup>
22
+ import Multiselect from 'vue-multiselect';
23
+
24
+ defineProps({
25
+ modelValue: { type: Array, default: () => [] },
26
+ name: { type: String, required: true },
27
+ label: { type: String, required: true },
28
+ error: { type: String, default: '' },
29
+ options: { type: Array, required: true },
30
+ placeholder: { type: String, default: '' },
31
+ trackBy: { type: String, default: 'id' },
32
+ optionLabel: { type: String, default: 'name' },
33
+ });
34
+
35
+ defineEmits(['update:modelValue']);
36
+ </script>
@@ -0,0 +1,49 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label for="password" class="col-md-3 col-form-label text-md-end">{{ translations.password }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <input
6
+ id="password"
7
+ type="password"
8
+ :value="password"
9
+ class="form-control"
10
+ :class="{ 'is-invalid': passwordError }"
11
+ name="password"
12
+ :placeholder="translations.password"
13
+ @input="$emit('update:password', $event.target.value)"
14
+ />
15
+ <div v-if="passwordError" class="invalid-feedback form-text">{{ passwordError }}</div>
16
+ </div>
17
+ </div>
18
+
19
+ <div class="mb-3 row align-items-center">
20
+ <label for="password_confirmation" class="col-md-3 col-form-label text-md-end">{{
21
+ translations.password_repeat
22
+ }}</label>
23
+ <div class="col-md-9 col-xl-8">
24
+ <input
25
+ id="password_confirmation"
26
+ type="password"
27
+ :value="passwordConfirmation"
28
+ class="form-control"
29
+ :class="{ 'is-invalid': confirmationError }"
30
+ name="password_confirmation"
31
+ :placeholder="translations.password"
32
+ @input="$emit('update:passwordConfirmation', $event.target.value)"
33
+ />
34
+ <div v-if="confirmationError" class="invalid-feedback form-text">{{ confirmationError }}</div>
35
+ </div>
36
+ </div>
37
+ </template>
38
+
39
+ <script setup>
40
+ defineProps({
41
+ password: { type: String, default: '' },
42
+ passwordConfirmation: { type: String, default: '' },
43
+ passwordError: { type: String, default: '' },
44
+ confirmationError: { type: String, default: '' },
45
+ translations: { type: Object, required: true },
46
+ });
47
+
48
+ defineEmits(['update:password', 'update:passwordConfirmation']);
49
+ </script>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <Multiselect
6
+ :model-value="modelValue"
7
+ :class="{ 'is-invalid': error }"
8
+ :placeholder="placeholder"
9
+ :options="options"
10
+ :label="optionLabel || undefined"
11
+ :track-by="trackBy || undefined"
12
+ open-direction="bottom"
13
+ @update:model-value="$emit('update:modelValue', $event)"
14
+ ></Multiselect>
15
+ <div v-if="error" class="invalid-feedback d-block form-text">{{ error }}</div>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script setup>
21
+ import Multiselect from 'vue-multiselect';
22
+
23
+ defineProps({
24
+ modelValue: { type: [String, Number, Array, Object], default: '' },
25
+ name: { type: String, required: true },
26
+ label: { type: String, required: true },
27
+ error: { type: String, default: '' },
28
+ options: { type: Array, required: true },
29
+ placeholder: { type: String, default: '' },
30
+ trackBy: { type: String, default: '' },
31
+ optionLabel: { type: String, default: '' },
32
+ });
33
+
34
+ defineEmits(['update:modelValue']);
35
+ </script>
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <button type="submit" class="btn btn-primary submit-btn" :disabled="submitting">
3
+ <i class="fa" :class="submitting ? 'fa-spinner' : 'fa-download'"></i>
4
+ {{ label }}
5
+ </button>
6
+ </template>
7
+
8
+ <script setup>
9
+ defineProps({
10
+ submitting: { type: Boolean, default: false },
11
+ label: { type: String, default: 'Save' },
12
+ });
13
+ </script>
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <div class="mb-3 row align-items-center">
3
+ <label :for="name" class="col-md-3 col-form-label text-md-end">{{ label }}</label>
4
+ <div class="col-md-9 col-xl-8">
5
+ <textarea
6
+ :id="name"
7
+ :value="modelValue"
8
+ class="form-control"
9
+ :class="{ 'is-invalid': error }"
10
+ :name="name"
11
+ :placeholder="placeholder || label"
12
+ :rows="rows"
13
+ @input="$emit('update:modelValue', $event.target.value)"
14
+ ></textarea>
15
+ <div v-if="error" class="invalid-feedback form-text">{{ error }}</div>
16
+ </div>
17
+ </div>
18
+ </template>
19
+
20
+ <script setup>
21
+ defineProps({
22
+ modelValue: { type: String, default: '' },
23
+ name: { type: String, required: true },
24
+ label: { type: String, required: true },
25
+ error: { type: String, default: '' },
26
+ placeholder: { type: String, default: '' },
27
+ rows: { type: [Number, String], default: 3 },
28
+ });
29
+
30
+ defineEmits(['update:modelValue']);
31
+ </script>