Improve Templates (#183)

* Improve Templates

* Fix test case

* Update AI GenerateTemplate

* update openai client and GPT completer

* composer.lock

* Update types and list json with script

* Template changes

* fix on draft template

* Finish opnform templates

---------

Co-authored-by: Forms Dev <chirag+new@notionforms.io>
Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Chirag Chhatrala
2023-09-08 16:30:28 +05:30
committed by GitHub
parent d93eca7410
commit 8e47b49e9a
36 changed files with 3130 additions and 1381 deletions

View File

@@ -1,70 +0,0 @@
<template>
<modal :show="show" @close="$emit('close')">
<template #icon>
<svg class="w-10 h-10 text-blue" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17 27C16.0681 27 15.6022 27 15.2346 26.8478C14.7446 26.6448 14.3552 26.2554 14.1522 25.7654C14 25.3978 14 24.9319 14 24V17.2C14 16.0799 14 15.5198 14.218 15.092C14.4097 14.7157 14.7157 14.4097 15.092 14.218C15.5198 14 16.0799 14 17.2 14H24C24.9319 14 25.3978 14 25.7654 14.1522C26.2554 14.3552 26.6448 14.7446 26.8478 15.2346C27 15.6022 27 16.0681 27 17M24.2 34H30.8C31.9201 34 32.4802 34 32.908 33.782C33.2843 33.5903 33.5903 33.2843 33.782 32.908C34 32.4802 34 31.9201 34 30.8V24.2C34 23.0799 34 22.5198 33.782 22.092C33.5903 21.7157 33.2843 21.4097 32.908 21.218C32.4802 21 31.9201 21 30.8 21H24.2C23.0799 21 22.5198 21 22.092 21.218C21.7157 21.4097 21.4097 21.7157 21.218 22.092C21 22.5198 21 23.0799 21 24.2V30.8C21 31.9201 21 32.4802 21.218 32.908C21.4097 33.2843 21.7157 33.5903 22.092 33.782C22.5198 34 23.0799 34 24.2 34Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</template>
<template #title>
Create template
</template>
<div class="p-4">
<p>
New template will be create from your form <span class="font-semibold">{{form.title}}</span>.
Template will be public for all to create form quickly.
</p>
<form @submit.prevent="createTemplate" @keydown="templateForm.onKeydown($event)" class="mt-6">
<div class="-m-6">
<div class="border-t py-4 px-6">
<text-input name="name" :form="templateForm" class="mt-4" label="Title" :required="true" />
<text-input name="slug" :form="templateForm" class="mt-4" label="Slug" :required="true" />
<rich-text-area-input name="description" :form="templateForm" class="mt-4" label="Description" :required="true" />
<text-input name="image_url" :form="templateForm" class="mt-4" label="Image" :required="true" />
<questions-editor name="questions" :form="templateForm" class="mt-4" label="Frequently asked questions" />
</div>
<div class="flex justify-end mt-4 pb-5 px-6">
<v-button class="mr-2" :loading="templateForm.busy">Create</v-button>
<v-button color="white" @click.prevent="$emit('close')">Close</v-button>
</div>
</div>
</form>
</div>
</modal>
</template>
<script>
import Form from 'vform'
import QuestionsEditor from '../../templates/QuestionsEditor.vue';
export default {
name: 'CreateTemplateModal',
components: { QuestionsEditor },
props: {
show: { type: Boolean, required: true },
form: { type: Object, required: true }
},
data: () => ({
templateForm: new Form({
name: '',
slug: '',
description: '',
image_url: '',
})
}),
computed: {},
methods: {
async createTemplate() {
this.templateForm.form = this.form
await this.templateForm.post('/api/templates').then((response) => {
this.alertSuccess('Template was successfully created.')
this.$emit('close')
});
}
}
}
</script>

View File

@@ -69,7 +69,7 @@
</a>
<a href="#" v-if="user.template_editor"
class="block 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="showCreateTemplateModal=true"
@click.prevent="showFormTemplateModal=true"
>
<svg class="w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
stroke="currentColor" stroke-width="2">
@@ -117,7 +117,7 @@
</div>
</modal>
<create-template-modal :form="form" :show="showCreateTemplateModal" @close="showCreateTemplateModal=false"/>
<form-template-modal :form="form" :show="showFormTemplateModal" @close="showFormTemplateModal=false"/>
</div>
</template>
@@ -125,11 +125,11 @@
import axios from 'axios'
import {mapGetters, mapState} from 'vuex'
import Dropdown from '../../../common/Dropdown.vue'
import CreateTemplateModal from '../CreateTemplateModal.vue'
import FormTemplateModal from '../../../open/forms/components/templates/FormTemplateModal.vue'
export default {
name: 'ExtraMenu',
components: { Dropdown, CreateTemplateModal },
components: { Dropdown, FormTemplateModal },
props: {
form: { type: Object, required: true },
isMainPage: { type: Boolean, required: false, default: false }
@@ -139,7 +139,7 @@ export default {
loadingDuplicate: false,
loadingDelete: false,
showDeleteFormModal: false,
showCreateTemplateModal: false
showFormTemplateModal: false
}),
computed: {

View File

@@ -0,0 +1,80 @@
<template>
<div v-if="template" class="relative group">
<div v-if="template.is_new" class="absolute top-0 right-0 p-3 z-10">
<span
class="inline-flex items-center gap-1 rounded-full bg-blue-500 px-2 py-1 text-xs font-medium text-white"
>
<svg aria-hidden="true" class="h-3 w-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor"
>
<path fill-rule="evenodd"
d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z"
clip-rule="evenodd"
/>
</svg>
New
</span>
</div>
<div class="aspect-[4/3] rounded-lg shadow-sm overflow-hidden">
<img class="group-hover:scale-110 transition-all duration-200 h-full object-cover w-full"
:src="template.image_url" alt=""
>
</div>
<p
class="text-lg font-semibold leading-tight tracking-tight text-gray-900 mt-4 group-hover:text-blue-500 transition-all duration-150"
>
{{ template.name }}
</p>
<p class="line-clamp-2 mt-2 text-sm font-normal text-gray-600">
{{ cleanQuotes(template.short_description) }}
</p>
<template-tags :slug="template.slug"
class="flex mt-4 items-center flex-wrap gap-3"
/>
<router-link :to="{params:{slug:template.slug},name:'templates.show'}" title="">
<span class="absolute inset-0" aria-hidden="true" />
</router-link>
</div>
</template>
<script>
import store from '~/store'
import TemplateTags from './TemplateTags.vue'
export default {
components: { TemplateTags },
props: {
slug: {
type: String,
required: true
}
},
data: () => ({}),
computed: {
template () {
return this.$store.getters['open/templates/getBySlug'](this.slug)
}
},
watch: {
slug () {
store.dispatch('open/templates/loadTemplate', this.slug)
}
},
mounted () {
store.dispatch('open/templates/loadTemplate', this.slug)
},
methods: {
cleanQuotes (str) {
// Remove starting and ending quotes if any
return (str) ? str.replace(/^"/, '').replace(/"$/, '') : ''
}
}
}
</script>

View File

@@ -0,0 +1,74 @@
<template>
<div v-if="template">
<template v-if="displayAll">
<span v-if="template.is_new"
class="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-white bg-blue-500 rounded-full"
>
<svg aria-hidden="true" class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
fill="currentColor"
>
<path fill-rule="evenodd"
d="M5 2a1 1 0 011 1v1h1a1 1 0 010 2H6v1a1 1 0 01-2 0V6H3a1 1 0 010-2h1V3a1 1 0 011-1zm0 10a1 1 0 011 1v1h1a1 1 0 110 2H6v1a1 1 0 11-2 0v-1H3a1 1 0 110-2h1v-1a1 1 0 011-1zM12 2a1 1 0 01.967.744L14.146 7.2 17.5 9.134a1 1 0 010 1.732l-3.354 1.935-1.18 4.455a1 1 0 01-1.933 0L9.854 12.8 6.5 10.866a1 1 0 010-1.732l3.354-1.935 1.18-4.455A1 1 0 0112 2z"
clip-rule="evenodd"
/>
</svg>
New
</span>
<span v-for="item in types"
class="inline-flex items-center rounded-full bg-gray-50 dark:bg-gray-800 dark:text-gray-400 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
>
{{ item }}
</span>
<span v-for="item in industries"
class="inline-flex items-center rounded-full bg-blue-50 dark:bg-blue-900 dark:text-gray-400 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"
>
{{ item }}
</span>
</template>
<template v-else>
<span v-if="types.length > 0"
class="inline-flex items-center rounded-full bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
>
{{ types[0] }} <template v-if="types.length > 1">+{{ types.length - 1 }}</template>
</span>
<span v-if="industries.length > 0"
class="inline-flex items-center rounded-full bg-blue-50 px-2 py-1 text-xs font-medium text-blue-700 ring-1 ring-inset ring-blue-700/10"
>
{{ industries[0] }} <template v-if="industries.length > 1">+{{ industries.length - 1 }}</template>
</span>
</template>
</div>
</template>
<script>
export default {
props: {
slug: {
type: String,
required: true
},
displayAll: {
type: Boolean,
default: false
}
},
data: () => ({}),
computed: {
template () {
return this.$store.getters['open/templates/getBySlug'](this.slug)
},
types () {
if (!this.template) return null
return this.$store.getters['open/templates/getTemplateTypes'](this.template.types)
},
industries () {
if (!this.template) return null
return this.$store.getters['open/templates/getTemplateIndustries'](this.template.industries)
}
},
methods: {}
}
</script>

View File

@@ -0,0 +1,70 @@
<template>
<div class="mx-auto mb-12 max-w-7xl px-6 lg:px-8">
<div class="mx-auto max-w-2xl text-center">
<h2 class="text-lg font-semibold leading-8 tracking-tight text-blue-500 ">Single or multi-page forms</h2>
<p class="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">Discover our beautiful templates</p>
<p class="mt-3 px-8 text-center text-lg text-gray-400 ">If you need inspiration, checkout our templates.</p>
</div>
<div class="my-3 flex justify-center">
<router-link :to="{name:'templates'}">
See all templates
<svg class="h-4 w-4 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd"
d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</router-link>
</div>
<div v-if="templates.length > 0"
class="w-full inline-flex flex-nowrap overflow-hidden [mask-image:_linear-gradient(to_right,transparent_0,_black_128px,_black_calc(100%-128px),transparent_100%)]"
>
<ul ref="templates-slider" class="flex justify-center md:justify-start animate-infinite-scroll">
<li v-for="(template, i) in templates" :key="template.id" class="mx-4 w-72 h-auto">
<single-template :slug="template.slug" />
</li>
</ul>
</div>
</div>
</template>
<script>
import store from '~/store'
import { mapGetters, mapState } from 'vuex'
import SingleTemplate from '../templates/SingleTemplate.vue'
export default {
components: { SingleTemplate },
props: { },
data: () => ({}),
computed: {
...mapState({
templates: state => state['open/templates'].content
})
},
watch: {
templates () {
this.$nextTick(() => {
this.setInfinite()
})
}
},
mounted() {
store.dispatch('open/templates/loadWithLimit', 10)
},
methods: {
setInfinite() {
let ul = this.$refs['templates-slider']
if(ul){
ul.insertAdjacentHTML('afterend', ul.outerHTML)
ul.nextSibling.setAttribute('aria-hidden', 'true')
}
}
}
}
</script>