Merge branch 'vue-3' into vue-3
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<a v-if="href" :class="btnClasses" :href="href" :target="target">
|
||||
<slot />
|
||||
</a>
|
||||
<button v-else-if="!to" :type="nativeType" :disabled="loading" :class="btnClasses"
|
||||
<button v-else-if="!to" :type="nativeType" :disabled="loading?true:null" :class="btnClasses"
|
||||
@click="onClick($event)"
|
||||
>
|
||||
<template v-if="!loading">
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<input-wrapper v-bind="$props">
|
||||
<input-wrapper v-bind="inputWrapperProps">
|
||||
<template #label>
|
||||
<span />
|
||||
</template>
|
||||
|
||||
<v-checkbox :id="id?id:name" v-model="compVal" :disabled="disabled" :name="name">
|
||||
<v-checkbox :id="id?id:name" v-model="compVal" :disabled="disabled?true:null" :name="name">
|
||||
<slot name="label">
|
||||
{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span>
|
||||
</slot>
|
||||
@@ -34,18 +34,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -13,7 +13,7 @@
|
||||
<div
|
||||
:class="[theme.CodeInput.input,{ '!ring-red-500 !ring-2': hasError, '!cursor-not-allowed !bg-gray-200':disabled }]"
|
||||
>
|
||||
<codemirror :id="id?id:name" v-model="compVal" :disabled="disabled"
|
||||
<codemirror :id="id?id:name" v-model="compVal" :disabled="disabled?true:null"
|
||||
:options="cmOptions"
|
||||
:style="inputStyle" :name="name"
|
||||
:placeholder="placeholder"
|
||||
@@ -44,18 +44,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<input-wrapper v-bind="$props">
|
||||
<input-wrapper v-bind="inputWrapperProps">
|
||||
<template #label>
|
||||
<span />
|
||||
</template>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input :id="id?id:name" v-model="compVal" :disabled="disabled"
|
||||
<input :id="id?id:name" v-model="compVal" :disabled="disabled?true:null"
|
||||
type="color" class="mr-2"
|
||||
:name="name"
|
||||
>
|
||||
@@ -37,13 +37,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const { compVal, inputStyle, hasValidation, hasError } = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
|
||||
<div class="flex" v-if="!dateRange">
|
||||
<input :type="useTime ? 'datetime-local' : 'date'" :id="id?id:name" v-model="fromDate" :class="inputClasses"
|
||||
:disabled="disabled"
|
||||
<div v-if="!dateRange" class="flex">
|
||||
<input :id="id?id:name" v-model="fromDate" :type="useTime ? 'datetime-local' : 'date'" :class="inputClasses"
|
||||
:disabled="disabled?true:null"
|
||||
:style="inputStyle" :name="name" data-date-format="YYYY-MM-DD"
|
||||
:min="setMinDate" :max="setMaxDate"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<div :class="inputClasses" v-else>
|
||||
<div v-else :class="inputClasses">
|
||||
<div class="flex -mx-2">
|
||||
<p class="text-gray-900 px-4">From</p>
|
||||
<input :type="useTime ? 'datetime-local' : 'date'" :id="id?id:name" v-model="fromDate" :disabled="disabled"
|
||||
<p class="text-gray-900 px-4">
|
||||
From
|
||||
</p>
|
||||
<input :id="id?id:name" v-model="fromDate" :type="useTime ? 'datetime-local' : 'date'" :disabled="disabled?true:null"
|
||||
:style="inputStyle" :name="name" data-date-format="YYYY-MM-DD"
|
||||
class="flex-grow border-transparent focus:outline-none "
|
||||
:min="setMinDate" :max="setMaxDate"
|
||||
/>
|
||||
<p class="text-gray-900 px-4">To</p>
|
||||
<input v-if="dateRange" :type="useTime ? 'datetime-local' : 'date'" :id="id?id:name" v-model="toDate"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<p class="text-gray-900 px-4">
|
||||
To
|
||||
</p>
|
||||
<input v-if="dateRange" :id="id?id:name" v-model="toDate" :type="useTime ? 'datetime-local' : 'date'"
|
||||
:disabled="disabled?true:null"
|
||||
:style="inputStyle" :name="name" class="flex-grow border-transparent focus:outline-none"
|
||||
:min="setMinDate" :max="setMaxDate"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -42,7 +46,7 @@
|
||||
<script>
|
||||
import { inputProps, useFormInput } from './useFormInput.js'
|
||||
import InputWrapper from './components/InputWrapper.vue'
|
||||
import {fixedClasses} from '../../plugins/config/vue-tailwind/datePicker.js'
|
||||
import { fixedClasses } from '../../plugins/config/vue-tailwind/datePicker.js'
|
||||
|
||||
export default {
|
||||
name: 'DateInput',
|
||||
@@ -51,25 +55,15 @@ export default {
|
||||
|
||||
props: {
|
||||
...inputProps,
|
||||
withTime: {type: Boolean, default: false},
|
||||
dateRange: {type: Boolean, default: false},
|
||||
disablePastDates: {type: Boolean, default: false},
|
||||
disableFutureDates: {type: Boolean, default: false}
|
||||
withTime: { type: Boolean, default: false },
|
||||
dateRange: { type: Boolean, default: false },
|
||||
disablePastDates: { type: Boolean, default: false },
|
||||
disableFutureDates: { type: Boolean, default: false }
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -80,22 +74,22 @@ export default {
|
||||
}),
|
||||
|
||||
computed: {
|
||||
inputClasses() {
|
||||
inputClasses () {
|
||||
let str = 'border border-gray-300 dark:bg-notion-dark-light dark:border-gray-600 dark:placeholder-gray-500 dark:text-gray-300 flex-1 focus:border-transparent focus:outline-none focus:ring-2 focus:ring-opacity-100 placeholder-gray-400 px-4 py-2 rounded-lg shadow-sm text-base text-black text-gray-700'
|
||||
str += this.dateRange ? ' w-50' : ' w-full'
|
||||
str += this.disabled ? ' !cursor-not-allowed !bg-gray-200' : ''
|
||||
return str
|
||||
},
|
||||
useTime() {
|
||||
useTime () {
|
||||
return this.withTime && !this.dateRange
|
||||
},
|
||||
setMinDate() {
|
||||
setMinDate () {
|
||||
if (this.disablePastDates) {
|
||||
return new Date().toISOString().split('T')[0]
|
||||
}
|
||||
return false
|
||||
},
|
||||
setMaxDate() {
|
||||
setMaxDate () {
|
||||
if (this.disableFutureDates) {
|
||||
return new Date().toISOString().split('T')[0]
|
||||
}
|
||||
@@ -105,16 +99,16 @@ export default {
|
||||
|
||||
watch: {
|
||||
color: {
|
||||
handler() {
|
||||
handler () {
|
||||
this.setInputColor()
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
fromDate: {
|
||||
handler(val) {
|
||||
handler (val) {
|
||||
if (this.dateRange) {
|
||||
if (!Array.isArray(this.compVal)) {
|
||||
this.compVal = [];
|
||||
this.compVal = []
|
||||
}
|
||||
this.compVal[0] = this.dateToUTC(val)
|
||||
} else {
|
||||
@@ -124,10 +118,10 @@ export default {
|
||||
immediate: false
|
||||
},
|
||||
toDate: {
|
||||
handler(val) {
|
||||
handler (val) {
|
||||
if (this.dateRange) {
|
||||
if (!Array.isArray(this.compVal)) {
|
||||
this.compVal = [null];
|
||||
this.compVal = [null]
|
||||
}
|
||||
this.compVal[1] = this.dateToUTC(val)
|
||||
} else {
|
||||
@@ -138,7 +132,7 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
mounted () {
|
||||
if (this.compVal) {
|
||||
if (Array.isArray(this.compVal)) {
|
||||
this.fromDate = this.compVal[0] ?? null
|
||||
@@ -158,17 +152,17 @@ export default {
|
||||
* @param event
|
||||
* @returns {boolean}
|
||||
*/
|
||||
onEnterPress(event) {
|
||||
onEnterPress (event) {
|
||||
event.preventDefault()
|
||||
return false
|
||||
},
|
||||
setInputColor() {
|
||||
setInputColor () {
|
||||
if (this.$refs.datepicker) {
|
||||
const dateInput = this.$refs.datepicker.$el.getElementsByTagName('input')[0]
|
||||
dateInput.style.setProperty('--tw-ring-color', this.color)
|
||||
}
|
||||
},
|
||||
dateToUTC(val) {
|
||||
dateToUTC (val) {
|
||||
if (!val) {
|
||||
return null
|
||||
}
|
||||
@@ -177,7 +171,7 @@ export default {
|
||||
}
|
||||
return new Date(val).toISOString()
|
||||
},
|
||||
dateToLocal(val) {
|
||||
dateToLocal (val) {
|
||||
if (!val) {
|
||||
return null
|
||||
}
|
||||
@@ -187,7 +181,7 @@ export default {
|
||||
String(dateObj.getDate()).padStart(2, '0')
|
||||
if (this.useTime) {
|
||||
dateStr += 'T' + String(dateObj.getHours()).padStart(2, '0') + ':' +
|
||||
String(dateObj.getMinutes()).padStart(2, '0');
|
||||
String(dateObj.getMinutes()).padStart(2, '0')
|
||||
}
|
||||
return dateStr
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -94,18 +94,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -51,18 +51,8 @@ export default {
|
||||
multiple: { type: Boolean, default: false }
|
||||
},
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -71,10 +61,10 @@ export default {
|
||||
computed: {},
|
||||
methods: {
|
||||
onSelect (value) {
|
||||
if(this.disabled){
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (this.multiple) {
|
||||
const emitValue = Array.isArray(this.compVal) ? [...this.compVal] : []
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -121,18 +121,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -155,8 +145,8 @@ export default {
|
||||
showUploadModal: {
|
||||
handler (val) {
|
||||
document.removeEventListener('paste', this.onUploadPasteEvent)
|
||||
if(this.showUploadModal){
|
||||
document.addEventListener("paste", this.onUploadPasteEvent)
|
||||
if (this.showUploadModal) {
|
||||
document.addEventListener('paste', this.onUploadPasteEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +166,7 @@ export default {
|
||||
this.droppedFiles(e.dataTransfer.files)
|
||||
},
|
||||
onUploadPasteEvent (e) {
|
||||
if(!this.showUploadModal) return
|
||||
if (!this.showUploadModal) return
|
||||
this.uploadDragoverEvent = false
|
||||
this.uploadDragoverTracking = false
|
||||
this.droppedFiles(e.clipboardData.files)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -9,7 +9,7 @@
|
||||
<div :id="id ? id : name" :name="name" :style="inputStyle" class="flex items-center">
|
||||
<v-select v-model="selectedCountryCode" class="w-[130px]" dropdown-class="w-[300px]" input-class="rounded-r-none"
|
||||
:data="countries"
|
||||
:disabled="disabled || countries.length===1" :searchable="true" :search-keys="['name']" :option-key="'code'" :color="color"
|
||||
:disabled="(disabled || countries.length===1)?true:null" :searchable="true" :search-keys="['name']" :option-key="'code'" :color="color"
|
||||
:has-error="hasValidation && form.errors.has(name)"
|
||||
:placeholder="'Select a country'" :uppercase-labels="true" :theme="theme" @update:model-value="onChangeCountryCode"
|
||||
>
|
||||
@@ -27,9 +27,9 @@
|
||||
</div>
|
||||
</template>
|
||||
</v-select>
|
||||
<input v-model="inputVal" type="text" class="inline-flex-grow !border-l-0 !rounded-l-none" :disabled="disabled"
|
||||
:class="[theme.default.input, { '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200': disabled }]"
|
||||
:placeholder="placeholder" :style="inputStyle" @update:model-value="onInput"
|
||||
<input v-model="inputVal" type="text" class="inline-flex-grow !border-l-0 !rounded-l-none" :disabled="disabled?true:null"
|
||||
:class="[theme.default.input, { '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200': disabled }]"
|
||||
:placeholder="placeholder" :style="inputStyle" @update:model-value="onInput"
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
<template #error>
|
||||
<slot name="error" />
|
||||
</template>
|
||||
|
||||
</input-wrapper>
|
||||
</template>
|
||||
|
||||
@@ -61,18 +60,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
|
||||
|
||||
<div class="stars-outer">
|
||||
<div v-for="i in numberOfStars" :key="i"
|
||||
class="cursor-pointer inline-block text-gray-200 dark:text-gray-800"
|
||||
@@ -46,22 +45,11 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
data () {
|
||||
return {
|
||||
hoverRating: -1
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
|
||||
<vue-editor :id="id?id:name" ref="editor" v-model="compVal" :disabled="disabled"
|
||||
<vue-editor :id="id?id:name" ref="editor" v-model="compVal" :disabled="disabled?true:null"
|
||||
:placeholder="placeholder" :class="[{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }, theme.RichTextAreaInput.input]"
|
||||
:editor-toolbar="editorToolbar" class="rich-editor resize-y"
|
||||
:style="inputStyle"
|
||||
@@ -41,25 +41,15 @@ export default {
|
||||
[{ header: 1 }, { header: 2 }],
|
||||
['bold', 'italic', 'underline', 'link'],
|
||||
[{ list: 'ordered' }, { list: 'bullet' }],
|
||||
[{color: []}]
|
||||
[{ color: [] }]
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -41,18 +41,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -62,7 +52,7 @@ export default {
|
||||
|
||||
computed: {
|
||||
scaleList () {
|
||||
let list = []
|
||||
const list = []
|
||||
for (let i = this.minScale; i <= this.maxScale; i += this.stepScale) {
|
||||
list.push(i)
|
||||
}
|
||||
@@ -89,7 +79,7 @@ export default {
|
||||
},
|
||||
|
||||
mounted () {
|
||||
if (this.compVal && typeof this.compVal === 'string'){
|
||||
if (this.compVal && typeof this.compVal === 'string') {
|
||||
this.compVal = parseInt(this.compVal)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -21,7 +21,7 @@
|
||||
:theme="theme"
|
||||
:has-error="hasValidation && form.errors.has(name)"
|
||||
:allow-creation="allowCreation"
|
||||
:disabled="disabled"
|
||||
:disabled="disabled?true:null"
|
||||
:help="help"
|
||||
:help-position="helpPosition"
|
||||
|
||||
@@ -97,20 +97,11 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
additionalOptions: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
@@ -18,7 +18,7 @@
|
||||
<a :class="theme.default.help" href="#" @click.prevent="clear">Clear</a>
|
||||
</small>
|
||||
</template>
|
||||
|
||||
|
||||
<template #error>
|
||||
<slot name="error" />
|
||||
</template>
|
||||
@@ -39,18 +39,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
|
||||
<textarea :id="id?id:name" v-model="compVal" :disabled="disabled"
|
||||
<textarea :id="id?id:name" v-model="compVal" :disabled="disabled?true:null"
|
||||
:class="[theme.default.input,{ '!ring-red-500 !ring-2': hasValidation && form.errors.has(name), '!cursor-not-allowed !bg-gray-200':disabled }]"
|
||||
class="resize-y"
|
||||
:name="name" :style="inputStyle"
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<template v-if="maxCharLimit && showCharLimit" #bottom_after_help>
|
||||
<small :class="theme.default.help">
|
||||
{{ charCount }}/{{ maxCharLimit }}
|
||||
{{ charCount }}/{{ maxCharLimit }}
|
||||
</small>
|
||||
</template>
|
||||
|
||||
@@ -38,25 +38,17 @@ export default {
|
||||
props: {
|
||||
...inputProps,
|
||||
maxCharLimit: { type: Number, required: false, default: null },
|
||||
showCharLimit: { type: Boolean, required: false, default: false },
|
||||
showCharLimit: { type: Boolean, required: false, default: false }
|
||||
},
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context)
|
||||
|
||||
setup (props, context) {
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
charCount() {
|
||||
charCount () {
|
||||
return (this.compVal) ? this.compVal.length : 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<input-wrapper
|
||||
v-bind="$props"
|
||||
v-bind="inputWrapperProps"
|
||||
>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
|
||||
<input :id="id?id:name" v-model="compVal" :disabled="disabled"
|
||||
<input :id="id?id:name" v-model="compVal" :disabled="disabled?true:null"
|
||||
:type="nativeType"
|
||||
:pattern="pattern"
|
||||
:style="inputStyle"
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<template v-if="maxCharLimit && showCharLimit" #bottom_after_help>
|
||||
<small :class="theme.default.help">
|
||||
{{ charCount }}/{{ maxCharLimit }}
|
||||
{{ charCount }}/{{ maxCharLimit }}
|
||||
</small>
|
||||
</template>
|
||||
|
||||
@@ -48,13 +48,6 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
} = useFormInput(props, context, props.nativeType === 'file' ? 'file-' : null)
|
||||
|
||||
const onChange = (event) => {
|
||||
if (props.nativeType !== 'file') return
|
||||
|
||||
@@ -69,10 +62,9 @@ export default {
|
||||
}
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context, props.nativeType === 'file' ? 'file-' : null),
|
||||
onEnterPress,
|
||||
onChange
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<input-wrapper v-bind="$props">
|
||||
<input-wrapper v-bind="inputWrapperProps">
|
||||
<template #label>
|
||||
<span />
|
||||
</template>
|
||||
|
||||
<div class="flex">
|
||||
<v-switch :id="id?id:name" v-model="compVal" class="inline-block mr-2" :disabled="disabled" />
|
||||
<v-switch :id="id?id:name" v-model="compVal" class="inline-block mr-2" :disabled="disabled?true:null" />
|
||||
<slot name="label">
|
||||
<span>{{ label }} <span v-if="required" class="text-red-500 required-dot">*</span></span>
|
||||
</slot>
|
||||
@@ -34,13 +34,8 @@ export default {
|
||||
},
|
||||
|
||||
setup (props, context) {
|
||||
const { compVal, inputStyle, hasValidation, hasError } = useFormInput(props, context)
|
||||
|
||||
return {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
...useFormInput(props, context)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -38,12 +38,12 @@ export default {
|
||||
props: {
|
||||
id: { type: String, required: false },
|
||||
name: { type: String, required: false },
|
||||
theme: { type: Object, required: true },
|
||||
label: { type: String, required: false },
|
||||
form: { type: Object, required: false },
|
||||
theme: { type: Object, required: true },
|
||||
wrapperClass: { type: String, required: false },
|
||||
inputStyle: { type: Object, required: false },
|
||||
help: { type: String, required: false },
|
||||
label: { type: String, required: false },
|
||||
helpPosition: { type: String, default: 'below_input' },
|
||||
uppercaseLabels: { type: Boolean, default: true },
|
||||
hideFieldName: { type: Boolean, default: true },
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
type="checkbox"
|
||||
:class="sizeClasses"
|
||||
class="rounded border-gray-500 cursor-pointer"
|
||||
:disabled="disabled"
|
||||
:disabled="disabled?true:null"
|
||||
@click="handleClick"
|
||||
>
|
||||
<label :for="id || name" class="text-gray-700 dark:text-gray-300 ml-2" :class="{'!cursor-not-allowed':disabled}">
|
||||
|
||||
17
resources/js/components/forms/useFormInput.js
vendored
17
resources/js/components/forms/useFormInput.js
vendored
@@ -6,6 +6,7 @@ export const inputProps = {
|
||||
name: { type: String, required: true },
|
||||
label: { type: String, required: false },
|
||||
form: { type: Object, required: false },
|
||||
theme: { type: Object, default: () => themes.default },
|
||||
modelValue: { required: false },
|
||||
required: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false },
|
||||
@@ -14,7 +15,6 @@ export const inputProps = {
|
||||
hideFieldName: { type: Boolean, default: false },
|
||||
help: { type: String, default: null },
|
||||
helpPosition: { type: String, default: 'below_input' },
|
||||
theme: { type: Object, default: () => themes.default },
|
||||
color: { type: String, default: '#3B82F6' },
|
||||
wrapperClass: { type: String, default: 'relative mb-3' }
|
||||
}
|
||||
@@ -58,11 +58,21 @@ export function useFormInput (props, context, formPrefixKey = null) {
|
||||
}
|
||||
})
|
||||
|
||||
const inputWrapperProps = computed(() => {
|
||||
const wrapperProps = {}
|
||||
Object.keys(inputProps).forEach((key) => {
|
||||
if (!['modelValue', 'disabled', 'placeholder', 'color'].includes(key)) {
|
||||
wrapperProps[key] = props[key]
|
||||
}
|
||||
})
|
||||
return wrapperProps
|
||||
})
|
||||
|
||||
// Watch for changes in props.modelValue and update the local content
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (content.value !== newValue){
|
||||
if (content.value !== newValue) {
|
||||
content.value = newValue
|
||||
}
|
||||
}
|
||||
@@ -72,6 +82,7 @@ export function useFormInput (props, context, formPrefixKey = null) {
|
||||
compVal,
|
||||
inputStyle,
|
||||
hasValidation,
|
||||
hasError
|
||||
hasError,
|
||||
inputWrapperProps
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<button :type="nativeType" :disabled="loading" :class="`py-${sizes['p-y']} px-${sizes['p-x']} text-${sizes['font']} ${theme.Button.body}`" :style="buttonStyle"
|
||||
<button :type="nativeType" :disabled="loading?true:null" :class="`py-${sizes['p-y']} px-${sizes['p-x']} text-${sizes['font']} ${theme.Button.body}`" :style="buttonStyle"
|
||||
class="btn" @click="$emit('click',$event)"
|
||||
>
|
||||
<template v-if="!loading">
|
||||
|
||||
@@ -12,8 +12,9 @@
|
||||
@click.prevent="openAddFieldSidebar"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3"
|
||||
stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/>
|
||||
stroke="currentColor" class="w-5 h-5"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="p-2 text-gray-300 hover:text-blue-500 cursor-pointer" role="button"
|
||||
@@ -50,7 +51,7 @@
|
||||
</div>
|
||||
<component :is="getFieldComponents" v-if="getFieldComponents"
|
||||
v-bind="inputProperties(field)" :required="isFieldRequired"
|
||||
:disabled="isFieldDisabled"
|
||||
:disabled="isFieldDisabled?true:null"
|
||||
/>
|
||||
<template v-else>
|
||||
<div v-if="field.type === 'nf-text' && field.content" :id="field.id" :key="field.id"
|
||||
@@ -79,7 +80,7 @@
|
||||
|
||||
<script>
|
||||
import { computed } from 'vue'
|
||||
import { useWorkingFormStore } from '../../../stores/working_form';
|
||||
import { useWorkingFormStore } from '../../../stores/working_form'
|
||||
import FormLogicPropertyResolver from '../../../forms/FormLogicPropertyResolver.js'
|
||||
import FormPendingSubmissionKey from '../../../mixins/forms/form-pending-submission-key.js'
|
||||
|
||||
@@ -112,24 +113,24 @@ export default {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
adminPreview: {type: Boolean, default: false} // If used in FormEditorPreview
|
||||
adminPreview: { type: Boolean, default: false } // If used in FormEditorPreview
|
||||
},
|
||||
|
||||
setup () {
|
||||
const workingFormStore = useWorkingFormStore()
|
||||
return {
|
||||
workingFormStore,
|
||||
selectedFieldIndex : computed(() => workingFormStore.selectedFieldIndex),
|
||||
showEditFieldSidebar : computed(() => workingFormStore.showEditFieldSidebar)
|
||||
selectedFieldIndex: computed(() => workingFormStore.selectedFieldIndex),
|
||||
showEditFieldSidebar: computed(() => workingFormStore.showEditFieldSidebar)
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
|
||||
computed: {
|
||||
fieldComponents() {
|
||||
fieldComponents () {
|
||||
return {
|
||||
text: 'TextInput',
|
||||
number: 'TextInput',
|
||||
@@ -146,7 +147,7 @@ export default {
|
||||
/**
|
||||
* Get the right input component for the field/options combination
|
||||
*/
|
||||
getFieldComponents() {
|
||||
getFieldComponents () {
|
||||
const field = this.field
|
||||
if (field.type === 'text' && field.multi_lines) {
|
||||
return 'TextAreaInput'
|
||||
@@ -174,27 +175,27 @@ export default {
|
||||
}
|
||||
return this.fieldComponents[field.type]
|
||||
},
|
||||
isPublicFormPage() {
|
||||
isPublicFormPage () {
|
||||
return this.$route.name === 'forms.show_public'
|
||||
},
|
||||
isFieldHidden() {
|
||||
isFieldHidden () {
|
||||
return !this.showHidden && this.shouldBeHidden
|
||||
},
|
||||
shouldBeHidden() {
|
||||
shouldBeHidden () {
|
||||
return (new FormLogicPropertyResolver(this.field, this.dataFormValue)).isHidden()
|
||||
},
|
||||
isFieldRequired() {
|
||||
isFieldRequired () {
|
||||
return (new FormLogicPropertyResolver(this.field, this.dataFormValue)).isRequired()
|
||||
},
|
||||
isFieldDisabled() {
|
||||
isFieldDisabled () {
|
||||
return (new FormLogicPropertyResolver(this.field, this.dataFormValue)).isDisabled()
|
||||
},
|
||||
beingEdited() {
|
||||
beingEdited () {
|
||||
return this.adminPreview && this.showEditFieldSidebar && this.form.properties.findIndex((item) => {
|
||||
return item.id === this.field.id
|
||||
}) === this.selectedFieldIndex
|
||||
},
|
||||
selectionFieldsOptions() {
|
||||
selectionFieldsOptions () {
|
||||
// For auto update hidden options
|
||||
let fieldsOptions = []
|
||||
|
||||
@@ -209,27 +210,27 @@ export default {
|
||||
|
||||
return fieldsOptions
|
||||
},
|
||||
fieldSideBarOpened() {
|
||||
fieldSideBarOpened () {
|
||||
return this.adminPreview && (this.form && this.selectedFieldIndex !== null) ? (this.form.properties[this.selectedFieldIndex] && this.showEditFieldSidebar) : false
|
||||
}
|
||||
},
|
||||
|
||||
watch: {},
|
||||
|
||||
mounted() {
|
||||
mounted () {
|
||||
},
|
||||
|
||||
methods: {
|
||||
editFieldOptions() {
|
||||
editFieldOptions () {
|
||||
this.workingFormStore.openSettingsForField(this.field)
|
||||
},
|
||||
openAddFieldSidebar() {
|
||||
openAddFieldSidebar () {
|
||||
this.workingFormStore.openAddFieldSidebar(this.field)
|
||||
},
|
||||
/**
|
||||
* Get the right input component for the field/options combination
|
||||
*/
|
||||
getFieldClasses() {
|
||||
getFieldClasses () {
|
||||
let classes = ''
|
||||
if (this.adminPreview) {
|
||||
classes += '-mx-4 px-4 -my-1 py-1 group/nffield relative transition-colors'
|
||||
@@ -240,7 +241,7 @@ export default {
|
||||
}
|
||||
return classes
|
||||
},
|
||||
getFieldWidthClasses(field) {
|
||||
getFieldWidthClasses (field) {
|
||||
if (!field.width || field.width === 'full') return 'w-full px-2'
|
||||
else if (field.width === '1/2') {
|
||||
return 'w-full sm:w-1/2 px-2'
|
||||
@@ -254,7 +255,7 @@ export default {
|
||||
return 'w-full sm:w-3/4 px-2'
|
||||
}
|
||||
},
|
||||
getFieldAlignClasses(field) {
|
||||
getFieldAlignClasses (field) {
|
||||
if (!field.align || field.align === 'left') return 'text-left'
|
||||
else if (field.align === 'right') {
|
||||
return 'text-right'
|
||||
@@ -267,7 +268,7 @@ export default {
|
||||
/**
|
||||
* Get the right input component options for the field/options
|
||||
*/
|
||||
inputProperties(field) {
|
||||
inputProperties (field) {
|
||||
const inputProperties = {
|
||||
key: field.id,
|
||||
name: field.id,
|
||||
@@ -277,7 +278,7 @@ export default {
|
||||
placeholder: field.placeholder,
|
||||
help: field.help,
|
||||
helpPosition: (field.help_position) ? field.help_position : 'below_input',
|
||||
uppercaseLabels: this.form.uppercase_labels == 1 || this.form.uppercase_labels == true,
|
||||
uppercaseLabels: this.form.uppercase_labels == 1 || this.form.uppercase_labels == true,
|
||||
theme: this.theme,
|
||||
maxCharLimit: (field.max_char_limit) ? parseInt(field.max_char_limit) : 2000,
|
||||
showCharLimit: field.show_char_limit || false
|
||||
@@ -309,7 +310,7 @@ export default {
|
||||
} else if (field.type === 'files' || (field.type === 'url' && field.file_upload)) {
|
||||
inputProperties.multiple = (field.multiple !== undefined && field.multiple)
|
||||
inputProperties.mbLimit = 5
|
||||
inputProperties.accept = (this.form.is_pro && field.allowed_file_types) ? field.allowed_file_types : ""
|
||||
inputProperties.accept = (this.form.is_pro && field.allowed_file_types) ? field.allowed_file_types : ''
|
||||
} else if (field.type === 'number' && field.is_rating) {
|
||||
inputProperties.numberOfStars = parseInt(field.rating_max_value)
|
||||
} else if (field.type === 'number' && field.is_scale) {
|
||||
@@ -323,7 +324,7 @@ export default {
|
||||
}
|
||||
|
||||
return inputProperties
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
<toggle-switch-input :value="value.hide_title" name="hide_title" class="mt-4"
|
||||
label="Hide Form Title"
|
||||
:disabled="form.hide_title===true"
|
||||
:disabled="(form.hide_title===true)?true:null"
|
||||
:help="hideTitleHelp"
|
||||
@update:model-value="onChangeHideTitle"
|
||||
/>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
Submission confirmation
|
||||
<pro-tag />
|
||||
</h2>
|
||||
<toggle-switch-input :disabled="emailSubmissionConfirmationField===null" name="send_submission_confirmation"
|
||||
<toggle-switch-input :disabled="(emailSubmissionConfirmationField===null)?true:null" name="send_submission_confirmation"
|
||||
:form="form" class="mt-4"
|
||||
label="Send submission confirmation" :help="emailSubmissionConfirmationHelp"
|
||||
/>
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
/>
|
||||
|
||||
<template v-if="hasInput">
|
||||
<component :is="inputComponentData.component" v-model="content.value" class="w-full"
|
||||
:name="'value_'+property.id" v-bind="inputComponentData" placeholder="Filter Value"
|
||||
<component v-bind="inputComponentData" :is="inputComponentData.component" v-model="content.value" class="w-full"
|
||||
:name="'value_'+property.id" placeholder="Filter Value"
|
||||
@input="$emit('input',castContent(content))"
|
||||
/>
|
||||
</template>
|
||||
@@ -62,7 +62,7 @@ export default {
|
||||
}
|
||||
|
||||
if (['select', 'multi_select'].includes(this.property.type)) {
|
||||
componentData.multiple = false;
|
||||
componentData.multiple = false
|
||||
componentData.options = this.property[this.property.type].options.map(option => {
|
||||
return {
|
||||
name: option.name,
|
||||
@@ -97,7 +97,7 @@ export default {
|
||||
|
||||
this.content.property_meta = {
|
||||
id: this.property.id,
|
||||
type: this.property.type,
|
||||
type: this.property.type
|
||||
}
|
||||
this.isMounted = true
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
option-key="identifier"
|
||||
name="group-control-slot-rule"
|
||||
/>
|
||||
<v-button class="ml-1 mt-1" color="blue" size="small" :disabled="selectedRule === ''" @click="addRule">
|
||||
<v-button class="ml-1 mt-1" color="blue" size="small" :disabled="(selectedRule === '')?true:null" @click="addRule">
|
||||
Add Condition
|
||||
</v-button>
|
||||
<v-button class="ml-1 mt-1" color="outline-blue" size="small" @click="groupCtrl.newGroup">
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
<template>
|
||||
<modal :show="show" @close="$emit('close')" :closeable="!aiForm.busy">
|
||||
<modal :show="show" :closeable="!aiForm.busy" @close="$emit('close')">
|
||||
<template #icon>
|
||||
<template v-if="state=='default'">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-10 h-10 text-blue">
|
||||
<path fill-rule="evenodd"
|
||||
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
|
||||
clip-rule="evenodd"/>
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
<template v-else-if="state=='ai'">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
|
||||
<path fill-rule="evenodd"
|
||||
d="M14.615 1.595a.75.75 0 01.359.852L12.982 9.75h7.268a.75.75 0 01.548 1.262l-10.5 11.25a.75.75 0 01-1.272-.71l1.992-7.302H3.75a.75.75 0 01-.548-1.262l10.5-11.25a.75.75 0 01.913-.143z"
|
||||
clip-rule="evenodd"/>
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
</template>
|
||||
@@ -24,38 +26,48 @@
|
||||
AI-powered form generator
|
||||
</template>
|
||||
</template>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-8" v-if="state=='default'">
|
||||
<div class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50"
|
||||
@click="$emit('close')" v-track.select_form_base="{base:'contact-form'}">
|
||||
<div v-if="state=='default'" class="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-8">
|
||||
<div v-track.select_form_base="{base:'contact-form'}"
|
||||
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50" @click="$emit('close')"
|
||||
>
|
||||
<div class="p-4">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
|
||||
<path d="M1.5 8.67v8.58a3 3 0 003 3h15a3 3 0 003-3V8.67l-8.928 5.493a3 3 0 01-3.144 0L1.5 8.67z"/>
|
||||
<path d="M22.5 6.908V6.75a3 3 0 00-3-3h-15a3 3 0 00-3 3v.158l9.714 5.978a1.5 1.5 0 001.572 0L22.5 6.908z"/>
|
||||
<path d="M1.5 8.67v8.58a3 3 0 003 3h15a3 3 0 003-3V8.67l-8.928 5.493a3 3 0 01-3.144 0L1.5 8.67z" />
|
||||
<path d="M22.5 6.908V6.75a3 3 0 00-3-3h-15a3 3 0 00-3 3v.158l9.714 5.978a1.5 1.5 0 001.572 0L22.5 6.908z" />
|
||||
</svg>
|
||||
</div>
|
||||
<p class="font-medium">Start from a simple contact form</p>
|
||||
<p class="font-medium">
|
||||
Start from a simple contact form
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="aiFeaturesEnabled" v-track.select_form_base="{base:'ai'}"
|
||||
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50" @click="state='ai'">
|
||||
class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50" @click="state='ai'"
|
||||
>
|
||||
<div class="p-4 relative">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
|
||||
<path fill-rule="evenodd"
|
||||
d="M14.615 1.595a.75.75 0 01.359.852L12.982 9.75h7.268a.75.75 0 01.548 1.262l-10.5 11.25a.75.75 0 01-1.272-.71l1.992-7.302H3.75a.75.75 0 01-.548-1.262l10.5-11.25a.75.75 0 01.913-.143z"
|
||||
clip-rule="evenodd"/>
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="font-medium text-blue-700">Use our AI to create the form</p>
|
||||
<p class="font-medium text-blue-700">
|
||||
Use our AI to create the form
|
||||
</p>
|
||||
<span class="text-xs text-gray-500">(1 min)</span>
|
||||
</div>
|
||||
<div class="rounded-md border p-4 flex flex-col items-center cursor-pointer hover:bg-gray-50 relative">
|
||||
<div class="p-4 relative">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-8 h-8 text-blue-500">
|
||||
<path
|
||||
d="M11.25 5.337c0-.355-.186-.676-.401-.959a1.647 1.647 0 01-.349-1.003c0-1.036 1.007-1.875 2.25-1.875S15 2.34 15 3.375c0 .369-.128.713-.349 1.003-.215.283-.401.604-.401.959 0 .332.278.598.61.578 1.91-.114 3.79-.342 5.632-.676a.75.75 0 01.878.645 49.17 49.17 0 01.376 5.452.657.657 0 01-.66.664c-.354 0-.675-.186-.958-.401a1.647 1.647 0 00-1.003-.349c-1.035 0-1.875 1.007-1.875 2.25s.84 2.25 1.875 2.25c.369 0 .713-.128 1.003-.349.283-.215.604-.401.959-.401.31 0 .557.262.534.571a48.774 48.774 0 01-.595 4.845.75.75 0 01-.61.61c-1.82.317-3.673.533-5.555.642a.58.58 0 01-.611-.581c0-.355.186-.676.401-.959.221-.29.349-.634.349-1.003 0-1.035-1.007-1.875-2.25-1.875s-2.25.84-2.25 1.875c0 .369.128.713.349 1.003.215.283.401.604.401.959a.641.641 0 01-.658.643 49.118 49.118 0 01-4.708-.36.75.75 0 01-.645-.878c.293-1.614.504-3.257.629-4.924A.53.53 0 005.337 15c-.355 0-.676.186-.959.401-.29.221-.634.349-1.003.349-1.036 0-1.875-1.007-1.875-2.25s.84-2.25 1.875-2.25c.369 0 .713.128 1.003.349.283.215.604.401.959.401a.656.656 0 00.659-.663 47.703 47.703 0 00-.31-4.82.75.75 0 01.83-.832c1.343.155 2.703.254 4.077.294a.64.64 0 00.657-.642z"/>
|
||||
d="M11.25 5.337c0-.355-.186-.676-.401-.959a1.647 1.647 0 01-.349-1.003c0-1.036 1.007-1.875 2.25-1.875S15 2.34 15 3.375c0 .369-.128.713-.349 1.003-.215.283-.401.604-.401.959 0 .332.278.598.61.578 1.91-.114 3.79-.342 5.632-.676a.75.75 0 01.878.645 49.17 49.17 0 01.376 5.452.657.657 0 01-.66.664c-.354 0-.675-.186-.958-.401a1.647 1.647 0 00-1.003-.349c-1.035 0-1.875 1.007-1.875 2.25s.84 2.25 1.875 2.25c.369 0 .713-.128 1.003-.349.283-.215.604-.401.959-.401.31 0 .557.262.534.571a48.774 48.774 0 01-.595 4.845.75.75 0 01-.61.61c-1.82.317-3.673.533-5.555.642a.58.58 0 01-.611-.581c0-.355.186-.676.401-.959.221-.29.349-.634.349-1.003 0-1.035-1.007-1.875-2.25-1.875s-2.25.84-2.25 1.875c0 .369.128.713.349 1.003.215.283.401.604.401.959a.641.641 0 01-.658.643 49.118 49.118 0 01-4.708-.36.75.75 0 01-.645-.878c.293-1.614.504-3.257.629-4.924A.53.53 0 005.337 15c-.355 0-.676.186-.959.401-.29.221-.634.349-1.003.349-1.036 0-1.875-1.007-1.875-2.25s.84-2.25 1.875-2.25c.369 0 .713.128 1.003.349.283.215.604.401.959.401a.656.656 0 00.659-.663 47.703 47.703 0 00-.31-4.82.75.75 0 01.83-.832c1.343.155 2.703.254 4.077.294a.64.64 0 00.657-.642z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p class="font-medium">Start from a template</p>
|
||||
<router-link :to="{name:'templates'}" v-track.select_form_base="{base:'template'}" class="absolute inset-0"/>
|
||||
<p class="font-medium">
|
||||
Start from a template
|
||||
</p>
|
||||
<router-link v-track.select_form_base="{base:'template'}" :to="{name:'templates'}" class="absolute inset-0" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="state=='ai'">
|
||||
@@ -65,26 +77,29 @@
|
||||
</svg>
|
||||
Back
|
||||
</a>
|
||||
<text-area-input label="Form Description" :disabled="loading" :form="aiForm" name="form_prompt" help="Give us a description of the form you want to build (the more details the better)"
|
||||
placeholder="A simple contact form, with a name, email and message field" />
|
||||
<v-button class="w-full" @click.prevent="generateForm" :loading="loading">
|
||||
<text-area-input label="Form Description" :disabled="loading?true:null" :form="aiForm" name="form_prompt" help="Give us a description of the form you want to build (the more details the better)"
|
||||
placeholder="A simple contact form, with a name, email and message field"
|
||||
/>
|
||||
<v-button class="w-full" :loading="loading" @click.prevent="generateForm">
|
||||
Generate a form
|
||||
</v-button>
|
||||
<p class="text-gray-500 text-xs text-center mt-1">~60 sec</p>
|
||||
<p class="text-gray-500 text-xs text-center mt-1">
|
||||
~60 sec
|
||||
</p>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Loader from "../../../common/Loader.vue";
|
||||
import Form from "vform";
|
||||
import axios from "axios";
|
||||
import Loader from '../../../common/Loader.vue'
|
||||
import Form from 'vform'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'CreateFormBaseModal',
|
||||
components: {Loader},
|
||||
components: { Loader },
|
||||
props: {
|
||||
show: {type: Boolean, required: true},
|
||||
show: { type: Boolean, required: true }
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
@@ -92,17 +107,17 @@ export default {
|
||||
aiForm: new Form({
|
||||
form_prompt: ''
|
||||
}),
|
||||
loading: false,
|
||||
loading: false
|
||||
}),
|
||||
|
||||
computed: {
|
||||
aiFeaturesEnabled() {
|
||||
aiFeaturesEnabled () {
|
||||
return window.config.ai_features_enabled
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
generateForm() {
|
||||
generateForm () {
|
||||
if (this.loading) return
|
||||
|
||||
this.loading = true
|
||||
@@ -115,7 +130,7 @@ export default {
|
||||
this.state = 'default'
|
||||
})
|
||||
},
|
||||
fetchGeneratedForm(generationId) {
|
||||
fetchGeneratedForm (generationId) {
|
||||
// check every 4 seconds if form is generated
|
||||
setTimeout(() => {
|
||||
axios.get('/api/forms/ai/' + generationId).then(response => {
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
<div class="border-t mt-4 -mx-4" />
|
||||
<toggle-switch-input v-model="advancedOptions.hide_title" name="hide_title" class="mt-4"
|
||||
label="Hide Form Title"
|
||||
:disabled="form.hide_title===true"
|
||||
:disabled="(form.hide_title===true)?true:null"
|
||||
:help="hideTitleHelp"
|
||||
/>
|
||||
<color-input v-model="advancedOptions.bgcolor" name="bgcolor" class="mt-4"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<modal :show="show" max-width="lg" @close="close">
|
||||
<text-input ref="companyName" label="Company Name" name="name" :required="true" :form="form" help="Name that will appear on invoices" />
|
||||
<text-input label="Email" name="email" native-type="email" :required="true" :form="form" help="Where invoices will be sent" />
|
||||
<v-button :loading="form.busy || loading" :disabled="form.busy || loading" class="mt-6 block mx-auto"
|
||||
@click="saveDetails" :arrow="true"
|
||||
<v-button :loading="form.busy || loading" :disabled="(form.busy || loading)?true:null" class="mt-6 block mx-auto"
|
||||
:arrow="true" @click="saveDetails"
|
||||
>
|
||||
Go to checkout
|
||||
</v-button>
|
||||
@@ -38,7 +38,7 @@ export default {
|
||||
setup () {
|
||||
const authStore = useAuthStore()
|
||||
return {
|
||||
user : computed(() => authStore.user)
|
||||
user: computed(() => authStore.user)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -50,6 +50,8 @@ export default {
|
||||
loading: false
|
||||
}),
|
||||
|
||||
computed: {},
|
||||
|
||||
watch: {
|
||||
user () {
|
||||
this.updateUser()
|
||||
@@ -71,7 +73,7 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateUser() {
|
||||
updateUser () {
|
||||
if (this.user) {
|
||||
this.form.name = this.user.name
|
||||
this.form.email = this.user.email
|
||||
@@ -94,8 +96,6 @@ export default {
|
||||
close () {
|
||||
this.$emit('close')
|
||||
}
|
||||
},
|
||||
|
||||
computed: {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user