Vue 3 better animation (#257)
* vue-3-better-animation * Working on migration to vueuse/motion * Form sidebar animations * Clean code * Added animations for modal * Finished implementing better animations --------- Co-authored-by: Forms Dev <chirag+new@notionforms.io>
This commit is contained in:
@@ -49,27 +49,25 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-full flex grow overflow-y-scroll relative">
|
||||
<div class="relative w-full shrink-0 overflow-y-scroll border-r md:w-1/2 md:max-w-sm lg:w-2/5">
|
||||
<div class="w-full flex grow overflow-y-scroll relative bg-gray-50">
|
||||
<div class="relative w-full bg-white shrink-0 overflow-y-scroll border-r md:w-1/2 md:max-w-sm lg:w-2/5">
|
||||
<div class="border-b bg-blue-50 p-5 text-nt-blue-dark md:hidden">
|
||||
Please create this form on a device with a larger screen. That will allow you to preview your form changes.
|
||||
</div>
|
||||
|
||||
<form-information/>
|
||||
<form-structure/>
|
||||
<form-customization/>
|
||||
<form-notifications/>
|
||||
<form-about-submission/>
|
||||
<form-information />
|
||||
<form-structure />
|
||||
<form-customization />
|
||||
<form-notifications />
|
||||
<form-about-submission />
|
||||
<form-access />
|
||||
<form-security-privacy/>
|
||||
<form-security-privacy />
|
||||
<form-custom-seo />
|
||||
<form-custom-code/>
|
||||
<form-custom-code />
|
||||
</div>
|
||||
|
||||
<form-editor-preview />
|
||||
|
||||
<form-field-edit-sidebar />
|
||||
<add-form-block-sidebar />
|
||||
<form-editor-sidebar />
|
||||
|
||||
<!-- Form Error Modal -->
|
||||
<form-error-modal
|
||||
@@ -86,12 +84,11 @@
|
||||
|
||||
<script>
|
||||
import { computed } from 'vue'
|
||||
import { useAuthStore } from '../../../../stores/auth';
|
||||
import { useFormsStore } from '../../../../stores/forms';
|
||||
import { useWorkingFormStore } from '../../../../stores/working_form';
|
||||
import { useWorkspacesStore } from '../../../../stores/workspaces';
|
||||
import AddFormBlockSidebar from './form-components/AddFormBlockSidebar.vue'
|
||||
import FormFieldEditSidebar from '../fields/FormFieldEditSidebar.vue'
|
||||
import { useAuthStore } from '../../../../stores/auth'
|
||||
import { useFormsStore } from '../../../../stores/forms'
|
||||
import { useWorkingFormStore } from '../../../../stores/working_form'
|
||||
import { useWorkspacesStore } from '../../../../stores/workspaces'
|
||||
import FormEditorSidebar from './form-components/FormEditorSidebar.vue'
|
||||
import FormErrorModal from './form-components/FormErrorModal.vue'
|
||||
import FormInformation from './form-components/FormInformation.vue'
|
||||
import FormStructure from './form-components/FormStructure.vue'
|
||||
@@ -109,8 +106,7 @@ import fieldsLogic from '../../../../mixins/forms/fieldsLogic.js'
|
||||
export default {
|
||||
name: 'FormEditor',
|
||||
components: {
|
||||
AddFormBlockSidebar,
|
||||
FormFieldEditSidebar,
|
||||
FormEditorSidebar,
|
||||
FormEditorPreview,
|
||||
FormNotifications,
|
||||
FormAboutSubmission,
|
||||
@@ -156,7 +152,7 @@ export default {
|
||||
formsStore,
|
||||
workingFormStore,
|
||||
workspacesStore,
|
||||
user : computed(() => authStore.user)
|
||||
user: computed(() => authStore.user)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div v-if="showSidebar"
|
||||
class="absolute shadow-lg shadow-blue-800/30 top-0 h-[calc(100vh-45px)] right-0 lg:shadow-none lg:relative bg-white w-full md:w-1/2 lg:w-2/5 border-l overflow-y-scroll md:max-w-[20rem] flex-shrink-0"
|
||||
>
|
||||
<div>
|
||||
<div class="p-4 border-b sticky top-0 z-10 bg-white">
|
||||
<div class="flex">
|
||||
<button class="text-gray-500 hover:text-gray-900 cursor-pointer" @click.prevent="closeSidebar">
|
||||
@@ -69,7 +67,7 @@ import { computed } from 'vue'
|
||||
import { useWorkingFormStore } from '../../../../../stores/working_form'
|
||||
|
||||
export default {
|
||||
name: 'AddFormBlockSidebar',
|
||||
name: 'AddFormBlock',
|
||||
components: {},
|
||||
props: {},
|
||||
|
||||
@@ -77,8 +75,7 @@ export default {
|
||||
const workingFormStore = useWorkingFormStore()
|
||||
return {
|
||||
workingFormStore,
|
||||
selectedFieldIndex : computed(() => workingFormStore.selectedFieldIndex),
|
||||
showAddFieldSidebar : computed(() => workingFormStore.showAddFieldSidebar)
|
||||
selectedFieldIndex : computed(() => workingFormStore.selectedFieldIndex)
|
||||
}
|
||||
},
|
||||
|
||||
@@ -183,9 +180,6 @@ export default {
|
||||
this.workingFormStore.set(value)
|
||||
}
|
||||
},
|
||||
showSidebar () {
|
||||
return (this.form && this.showAddFieldSidebar) ?? false
|
||||
},
|
||||
|
||||
defaultBlockNames () {
|
||||
return {
|
||||
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<editor-right-sidebar :show="form && (showEditFieldSidebar || showAddFieldSidebar)">
|
||||
<transition mode="out-in">
|
||||
<form-field-edit v-if="showEditFieldSidebar" :key="editFieldIndex" v-motion-fade="'fade'" />
|
||||
<add-form-block v-else-if="showAddFieldSidebar" v-motion-fade="'fade'" />
|
||||
</transition>
|
||||
</editor-right-sidebar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed } from 'vue'
|
||||
import { useWorkingFormStore } from '../../../../../stores/working_form'
|
||||
import EditorRightSidebar from '../../../editors/EditorRightSidebar.vue'
|
||||
import FormFieldEdit from '../../fields/FormFieldEdit.vue'
|
||||
import AddFormBlock from './AddFormBlock.vue'
|
||||
|
||||
export default {
|
||||
name: 'FormEditorSidebar',
|
||||
components: { EditorRightSidebar, AddFormBlock, FormFieldEdit },
|
||||
props: {},
|
||||
setup () {
|
||||
const workingFormStore = useWorkingFormStore()
|
||||
return {
|
||||
workingFormStore,
|
||||
editFieldIndex: computed(() => workingFormStore.selectedFieldIndex),
|
||||
showEditFieldSidebar: computed(() => workingFormStore.showEditFieldSidebar),
|
||||
showAddFieldSidebar: computed(() => workingFormStore.showAddFieldSidebar)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
form: {
|
||||
get () {
|
||||
return this.workingFormStore.content
|
||||
},
|
||||
/* We add a setter */
|
||||
set (value) {
|
||||
this.workingFormStore.set(value)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
mounted () {
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
</script>
|
||||
@@ -6,13 +6,13 @@
|
||||
</div>
|
||||
<SelectInput v-model="content.operator" class="w-full" :options="operators"
|
||||
:name="'operator_'+property.id" placeholder="Comparison operator"
|
||||
@input="operatorChanged()"
|
||||
@update:modelValue="operatorChanged()"
|
||||
/>
|
||||
|
||||
<template v-if="hasInput">
|
||||
<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))"
|
||||
@update:modelValue="emitInput()"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
@@ -131,7 +131,7 @@ export default {
|
||||
} else if (typeof this.content.value === 'boolean' || typeof this.content.value === 'object') {
|
||||
this.content.value = null
|
||||
}
|
||||
this.$emit('input', this.castContent(this.content))
|
||||
this.emitInput()
|
||||
},
|
||||
needsInput () {
|
||||
const operator = this.selectedOperator()
|
||||
@@ -165,6 +165,9 @@ export default {
|
||||
return key.split('_').map(function (item) {
|
||||
return item.charAt(0).toUpperCase() + item.substring(1)
|
||||
}).join(' ')
|
||||
},
|
||||
emitInput () {
|
||||
this.$emit('update:modelValue', this.castContent(this.content))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<query-builder v-model="query" :rules="rules" :config="config" @input="onChange">
|
||||
<query-builder v-model="query" :rules="rules" :config="config" @update:modelValue="onChange">
|
||||
<template #groupOperator="props">
|
||||
<div class="query-builder-group-slot__group-selection flex items-center px-5 border-b py-1 mb-1 flex">
|
||||
<p class="mr-2 font-semibold">
|
||||
@@ -7,13 +7,13 @@
|
||||
</p>
|
||||
<select-input
|
||||
wrapper-class="relative"
|
||||
:value="props.currentOperator"
|
||||
:model-value="props.currentOperator"
|
||||
:options="props.operators"
|
||||
emit-key="identifier"
|
||||
option-key="identifier"
|
||||
name="operator-input"
|
||||
margin-bottom=""
|
||||
@input="props.updateCurrentOperator($event)"
|
||||
@update:modelValue="props.updateCurrentOperator($event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -23,17 +23,17 @@
|
||||
<template #rule="ruleCtrl">
|
||||
<component
|
||||
:is="ruleCtrl.ruleComponent"
|
||||
:value="ruleCtrl.ruleData"
|
||||
@input="ruleCtrl.updateRuleData"
|
||||
:model-value="ruleCtrl.ruleData"
|
||||
@update:modelValue="ruleCtrl.updateRuleData"
|
||||
/>
|
||||
</template>
|
||||
</query-builder>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
import QueryBuilder from 'query-builder-vue-3'
|
||||
import ColumnCondition from './ColumnCondition.vue'
|
||||
import Vue from 'vue'
|
||||
import GroupControlSlot from './GroupControlSlot.vue'
|
||||
|
||||
export default {
|
||||
@@ -66,7 +66,8 @@ export default {
|
||||
identifier: property.id,
|
||||
name: property.name,
|
||||
component: (function () {
|
||||
return Vue.extend(ColumnCondition).extend({
|
||||
return defineComponent({
|
||||
extends: ColumnCondition,
|
||||
computed: {
|
||||
property () {
|
||||
return property
|
||||
@@ -111,7 +112,7 @@ export default {
|
||||
|
||||
methods: {
|
||||
onChange () {
|
||||
this.$emit('input', this.query)
|
||||
this.$emit('update:modelValue', this.query)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProTag from '../../../../common/ProTag.vue'
|
||||
import ConditionEditor from './ConditionEditor.vue'
|
||||
import Modal from '../../../../Modal.vue'
|
||||
import SelectInput from '../../../../forms/SelectInput.vue'
|
||||
@@ -75,7 +74,7 @@ import clonedeep from 'clone-deep'
|
||||
|
||||
export default {
|
||||
name: 'FormBlockLogicEditor',
|
||||
components: { SelectInput, Modal, ProTag, ConditionEditor },
|
||||
components: { SelectInput, Modal, ConditionEditor },
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div v-if="showSidebar"
|
||||
class="absolute shadow-lg shadow-blue-800/30 top-0 h-[calc(100vh-45px)] right-0 lg:shadow-none lg:relative bg-white w-full md:w-1/2 lg:w-2/5 border-l overflow-y-scroll md:max-w-[20rem] flex-shrink-0 overflow-x-hidden"
|
||||
>
|
||||
<div>
|
||||
<div class="p-4 border-b sticky top-0 z-10 bg-white">
|
||||
<button v-if="!field" class="text-gray-500 hover:text-gray-900 cursor-pointer" @click.prevent="closeSidebar">
|
||||
<svg class="h-6 w-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -78,15 +76,14 @@ import FieldOptions from './components/FieldOptions.vue'
|
||||
import BlockOptions from './components/BlockOptions.vue'
|
||||
|
||||
export default {
|
||||
name: 'FormFieldEditSidebar',
|
||||
name: 'FormFieldEdit',
|
||||
components: { ChangeFieldType, FieldOptions, BlockOptions },
|
||||
props: {},
|
||||
setup () {
|
||||
const workingFormStore = useWorkingFormStore()
|
||||
return {
|
||||
workingFormStore,
|
||||
selectedFieldIndex : computed(() => workingFormStore.selectedFieldIndex),
|
||||
showEditFieldSidebar : computed(() => workingFormStore.showEditFieldSidebar)
|
||||
selectedFieldIndex : computed(() => workingFormStore.selectedFieldIndex)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -108,9 +105,6 @@ export default {
|
||||
field () {
|
||||
return (this.form && this.selectedFieldIndex !== null) ? this.form.properties[this.selectedFieldIndex] : null
|
||||
},
|
||||
showSidebar () {
|
||||
return (this.form && this.selectedFieldIndex !== null) ? (this.form.properties[this.selectedFieldIndex] && this.showEditFieldSidebar) : false
|
||||
},
|
||||
isBlockField () {
|
||||
return this.field && this.field.type.startsWith('nf')
|
||||
},
|
||||
@@ -86,17 +86,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Logic Block -->
|
||||
<form-block-logic-editor class="py-2 px-4 border-b" :form="form" :field="field" />
|
||||
<!-- <form-block-logic-editor class="py-2 px-4 border-b" :form="form" :field="field" />-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CodeInput from '../../../../forms/CodeInput.vue'
|
||||
const FormBlockLogicEditor = () => import('../../components/form-logic-components/FormBlockLogicEditor.vue')
|
||||
|
||||
export default {
|
||||
name: 'BlockOptions',
|
||||
components: { FormBlockLogicEditor, CodeInput },
|
||||
components: { CodeInput },
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<dropdown dusk="nav-dropdown" v-if="changeTypeOptions.length > 0">
|
||||
<dropdown v-if="changeTypeOptions.length > 0" dusk="nav-dropdown">
|
||||
<template #trigger="{toggle}">
|
||||
<v-button class="relative" :class="btnClasses" size="small" color="light-gray" @click="toggle">
|
||||
<v-button class="relative" :class="btnClasses" size="small" color="light-gray" @click.stop="toggle">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="h-4 w-4 text-blue-600 inline mr-1 -mt-1">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M7.5 21L3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5" />
|
||||
</svg>
|
||||
@@ -9,7 +9,7 @@
|
||||
</v-button>
|
||||
</template>
|
||||
|
||||
<a href="#" v-for="(op, index) in changeTypeOptions" :key="index"
|
||||
<a v-for="(op, index) in changeTypeOptions" :key="index" href="#"
|
||||
class="block px-4 py-2 text-md text-gray-700 dark:text-white hover:bg-gray-100 hover:text-gray-900 dark:text-gray-100 dark:hover:text-white dark:hover:bg-gray-600 flex items-center"
|
||||
@click.prevent="changeType(op.value)"
|
||||
>
|
||||
@@ -23,7 +23,7 @@ import Dropdown from '../../../../common/Dropdown.vue'
|
||||
|
||||
export default {
|
||||
name: 'ChangeFieldType',
|
||||
components: {Dropdown},
|
||||
components: { Dropdown },
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
@@ -34,25 +34,25 @@ export default {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
|
||||
computed: {
|
||||
changeTypeOptions() {
|
||||
var newTypes = []
|
||||
changeTypeOptions () {
|
||||
let newTypes = []
|
||||
if (['text', 'email', 'phone', 'number'].includes(this.field.type)) {
|
||||
newTypes = [
|
||||
{'name': 'Text Input', 'value': 'text'},
|
||||
{'name': 'Email Input', 'value': 'email'},
|
||||
{'name': 'Phone Input', 'value': 'phone'},
|
||||
{'name': 'Number Input', 'value': 'number'}
|
||||
{ name: 'Text Input', value: 'text' },
|
||||
{ name: 'Email Input', value: 'email' },
|
||||
{ name: 'Phone Input', value: 'phone' },
|
||||
{ name: 'Number Input', value: 'number' }
|
||||
]
|
||||
}
|
||||
if (['select', 'multi_select'].includes(this.field.type)) {
|
||||
newTypes = [
|
||||
{'name': 'Select Input', 'value': 'select'},
|
||||
{'name': 'Multi-Select Input', 'value': 'multi_select'}
|
||||
{ name: 'Select Input', value: 'select' },
|
||||
{ name: 'Multi-Select Input', value: 'multi_select' }
|
||||
]
|
||||
}
|
||||
return newTypes.filter((item) => {
|
||||
@@ -68,11 +68,11 @@ export default {
|
||||
|
||||
watch: {},
|
||||
|
||||
mounted() {
|
||||
mounted () {
|
||||
},
|
||||
|
||||
methods: {
|
||||
changeType(newType) {
|
||||
changeType (newType) {
|
||||
if (newType) {
|
||||
this.$emit('changeType', newType)
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@
|
||||
<file-input v-else-if="field.type==='files'" name="prefill" class="mt-4"
|
||||
:form="field"
|
||||
label="Pre-filled file"
|
||||
:multiple="field.multiple===true" :moveToFormAssets="true"
|
||||
:multiple="field.multiple===true" :move-to-form-assets="true"
|
||||
/>
|
||||
<text-input v-else-if="!['files', 'signature'].includes(field.type)" name="prefill" class="mt-3"
|
||||
:form="field"
|
||||
@@ -382,7 +382,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Logic Block -->
|
||||
<form-block-logic-editor class="py-2 px-4 border-b" :form="form" :field="field" />
|
||||
<!-- <form-block-logic-editor class="py-2 px-4 border-b" :form="form" :field="field" />-->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -391,11 +391,9 @@ import timezones from '../../../../../../data/timezones.json'
|
||||
import countryCodes from '../../../../../../data/country_codes.json'
|
||||
import CountryFlag from 'vue-country-flag-next'
|
||||
|
||||
const FormBlockLogicEditor = () => import('../../components/form-logic-components/FormBlockLogicEditor.vue')
|
||||
|
||||
export default {
|
||||
name: 'FieldOptions',
|
||||
components: { FormBlockLogicEditor, CountryFlag },
|
||||
components: { CountryFlag },
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
@@ -533,7 +531,7 @@ export default {
|
||||
this.field.hidden = true
|
||||
}
|
||||
},
|
||||
initRating() {
|
||||
initRating () {
|
||||
if (this.field.is_rating) {
|
||||
this.$set(this.field, 'is_scale', false)
|
||||
if (!this.field.rating_max_value) {
|
||||
|
||||
Reference in New Issue
Block a user