transform form with components
This commit is contained in:
parent
90dd03882f
commit
0d4a468014
|
@ -3,75 +3,53 @@
|
||||||
<div class="col-span-3 flex flex-col gap-4 lg:gap-6">
|
<div class="col-span-3 flex flex-col gap-4 lg:gap-6">
|
||||||
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700" for="heading">Heading</label>
|
<InputForm id="heading" label="Heading" v-model="heading" />
|
||||||
<input type="text" class="mt-2 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-model="heading" id="heading">
|
<RangeForm id="heading-size" min="1" max="10" step="0.1" v-model="headingSize" />
|
||||||
<input type="range" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" min="1" max="10" step="0.1" v-model="headingSize" id="heading-size">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-6">
|
<div class="py-6">
|
||||||
<label class="block text-sm font-medium text-gray-700" for="subheading">Subheading</label>
|
<TextareaForm id="subheading" label="Subheading" v-model="subheading" />
|
||||||
<textarea class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-model="subheading" id="subheading"></textarea>
|
<RangeForm id="subheading-size" min="1" max="10" step="0.1" v-model="subheadingSize" />
|
||||||
<input type="range" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" min="1" max="10" step="0.1" v-model="subheadingSize" id="subheading-size">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pb-6">
|
<div class="pb-6">
|
||||||
<label class="block text-sm font-medium text-gray-700" for="subheading">Font</label>
|
<SelectForm id="font" :items="fonts" label="Font" v-model="font" />
|
||||||
|
|
||||||
<select v-model="font" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
|
|
||||||
<option v-for="font in fonts" :key="font.value" :value="font.value" v-text="font.label"></option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="text-center stroke-gray-400">
|
<div class="text-center stroke-gray-400">
|
||||||
<button v-on:click="headingAlign = 'left'">
|
<AlignForm v-model="headingAlign" />
|
||||||
<svg class="inline border-gray-400 rounded-md" :class="{border: headingAlign === 'left'}" height="40" viewBox="0 0 21 21" width="40" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="m4.5 6.5h12"/><path d="m4.498 10.5h5.997"/><path d="m4.5 14.5h9.995"/></g></svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button v-on:click="headingAlign = 'center'">
|
|
||||||
<svg class="inline border-gray-400 rounded-md" :class="{border: headingAlign === 'center'}" height="40" viewBox="0 0 21 21" width="40" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="m4.5 6.5h12"/><path d="m7.498 10.5h5.997"/><path d="m5.5 14.5h9.995"/></g></svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button v-on:click="headingAlign = 'right'">
|
|
||||||
<svg class="inline border-gray-400 rounded-md" :class="{border: headingAlign === 'right'}" height="40" viewBox="0 0 21 21" width="40" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="m4.5 6.5h12"/><path d="m10.498 10.5h5.997"/><path d="m6.5 14.5h9.995"/></g></svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700" for="author">Author</label>
|
<InputForm id="author" label="Author" v-model="author" />
|
||||||
<input type="text" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-model="author" id="author">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-6">
|
<div class="py-6">
|
||||||
<label class="block text-sm font-medium text-gray-700" for="avatar">Avatar</label>
|
<FileForm id="avatar" label="Avatar" v-model="avatar" />
|
||||||
<input type="file" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-on:change="updateAvatar" id="avatar">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700" for="logo">Logo</label>
|
<FileForm id="logo" label="Logo" v-model="logo" />
|
||||||
<input type="file" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-on:change="updateLogo" id="logo">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-span-3 px-10 flex flex-col gap-4 lg:gap-6">
|
<div class="col-span-3 px-10 flex flex-col gap-4 lg:gap-6">
|
||||||
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700" for="text-color">Text color</label>
|
<InputForm id="text-color" label="Text color" type="color" v-model="textColor" />
|
||||||
<input type="color" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-model="textColor" id="text-color">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-6">
|
<div class="py-6">
|
||||||
<label class="block text-sm font-medium text-gray-700" for="background">Background</label>
|
<FileForm id="background" label="Background" v-model="background" />
|
||||||
<input type="file" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-on:change="updateBackground" id="background">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700" for="background-hover">Background hover</label>
|
<InputForm id="background-hover" label="Background hover" type="color" v-model="backgroundHover" />
|
||||||
<input type="color" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-model="backgroundHover" id="background-hover">
|
<RangeForm id="background-hover-opacity" min="0" max="1" step="0.05" v-model="backgroundHoverOpacity" />
|
||||||
<input type="range" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" min="0" max="1" step="0.1" v-model="backgroundHoverOpacity" id="background-hover-opacity">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
<div class="drop-shadow-md rounded-md border border-zinc-300 p-5">
|
||||||
|
@ -79,17 +57,15 @@
|
||||||
<label class="block text-sm font-medium text-gray-700" for="width">Size and quality</label>
|
<label class="block text-sm font-medium text-gray-700" for="width">Size and quality</label>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-x-4">
|
<div class="grid grid-cols-2 gap-x-4">
|
||||||
<input type="number" class="mt-1 inline rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-model="width" id="width">
|
<InputForm id="width" type="number" v-model="width" />
|
||||||
<input type="number" class="mt-1 inline rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" v-model="height">
|
<InputForm id="height" type="number" v-model="height" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="range" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" min="0" max="1" step="0.1" v-model="quality">
|
<RangeForm id="quality" min="0" max="1" step="0.05" v-model="quality" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-medium text-gray-700" for="width">Box padding</label>
|
<RangeForm id="content-padding" min="2.5" max="10" step="0.05" v-model="contentPadding" label="Box padding" />
|
||||||
|
|
||||||
<input type="range" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" min="2.5" max="10" step="0.1" v-model="contentPadding">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -115,13 +91,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-md text-center" role="group">
|
<div class="text-center">
|
||||||
<button type="button" class="px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-l-lg hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-blue-500 dark:focus:text-white" v-on:click="downloadAsPng">
|
<DownloadButton v-on:click="downloadAsPng" class="rounded-l-md" label="PNG"/>
|
||||||
PNG
|
<DownloadButton v-on:click="downloadAsJpeg" class="rounded-r-md" label="JPEG"/>
|
||||||
</button>
|
|
||||||
<button type="button" class="px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-r-md hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-blue-500 dark:focus:text-white" v-on:click="downloadAsJpeg">
|
|
||||||
JPEG
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -153,10 +125,25 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { hexToRgb } from '../util/color'
|
import { hexToRgb } from '../util/color'
|
||||||
import { toBase64 } from '../util/file'
|
|
||||||
import { toPng, toJpeg } from 'html-to-image'
|
import { toPng, toJpeg } from 'html-to-image'
|
||||||
|
import InputForm from '../ui/InputForm'
|
||||||
|
import RangeForm from '../ui/RangeForm'
|
||||||
|
import TextareaForm from '../ui/TextareaForm'
|
||||||
|
import FileForm from '../ui/FileForm'
|
||||||
|
import SelectForm from '../ui/SelectForm'
|
||||||
|
import AlignForm from '../ui/AlignForm'
|
||||||
|
import DownloadButton from '../ui/DownloadButton'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
InputForm,
|
||||||
|
RangeForm,
|
||||||
|
TextareaForm,
|
||||||
|
FileForm,
|
||||||
|
SelectForm,
|
||||||
|
AlignForm,
|
||||||
|
DownloadButton,
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
author: localStorage.getItem('author'),
|
author: localStorage.getItem('author'),
|
||||||
|
@ -239,15 +226,6 @@ export default {
|
||||||
padding: `${this.contentPadding}em`,
|
padding: `${this.contentPadding}em`,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async updateBackground(event) {
|
|
||||||
this.background = await this.convertFileToBase64(event.target.files)
|
|
||||||
},
|
|
||||||
async updateLogo(event) {
|
|
||||||
this.logo = await this.convertFileToBase64(event.target.files)
|
|
||||||
},
|
|
||||||
async updateAvatar(event) {
|
|
||||||
this.avatar = await this.convertFileToBase64(event.target.files)
|
|
||||||
},
|
|
||||||
downloadAsPng() {
|
downloadAsPng() {
|
||||||
return this.download(toPng, 'image.png')
|
return this.download(toPng, 'image.png')
|
||||||
},
|
},
|
||||||
|
@ -275,13 +253,6 @@ export default {
|
||||||
console.error('oops, something went wrong!', error);
|
console.error('oops, something went wrong!', error);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async convertFileToBase64(files) {
|
|
||||||
if (files.length) {
|
|
||||||
return await toBase64(files[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
updateOgMaxWidth() {
|
updateOgMaxWidth() {
|
||||||
this.$refs.og.style.display = 'none'
|
this.$refs.og.style.display = 'none'
|
||||||
this.ogMaxWidth = this.$refs.ogwrapper.offsetWidth
|
this.ogMaxWidth = this.$refs.ogwrapper.offsetWidth
|
||||||
|
|
32
src/ui/AlignForm.vue
Normal file
32
src/ui/AlignForm.vue
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<template>
|
||||||
|
<button v-on:click="update('left')">
|
||||||
|
<svg class="inline border-gray-400 rounded-md" :class="{border: modelValue === 'left'}" height="40" viewBox="0 0 21 21" width="40" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="m4.5 6.5h12"/><path d="m4.498 10.5h5.997"/><path d="m4.5 14.5h9.995"/></g></svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button v-on:click="update('center')">
|
||||||
|
<svg class="inline border-gray-400 rounded-md" :class="{border: modelValue === 'center'}" height="40" viewBox="0 0 21 21" width="40" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="m4.5 6.5h12"/><path d="m7.498 10.5h5.997"/><path d="m5.5 14.5h9.995"/></g></svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button v-on:click="update('right')">
|
||||||
|
<svg class="inline border-gray-400 rounded-md" :class="{border: modelValue === 'right'}" height="40" viewBox="0 0 21 21" width="40" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"><path d="m4.5 6.5h12"/><path d="m10.498 10.5h5.997"/><path d="m6.5 14.5h9.995"/></g></svg>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
methods: {
|
||||||
|
update(value) {
|
||||||
|
this.$emit('update:modelValue', value)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
24
src/ui/DownloadButton.vue
Normal file
24
src/ui/DownloadButton.vue
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-blue-500 dark:focus:text-white" v-on:click="downloadAsJpeg"
|
||||||
|
:class="class"
|
||||||
|
v-text="label"
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
43
src/ui/FileForm.vue
Normal file
43
src/ui/FileForm.vue
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<template>
|
||||||
|
<label class="block text-sm font-medium text-gray-700" :for="id" v-if="label" v-text="label"></label>
|
||||||
|
<input
|
||||||
|
class="mt-2 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
|
type="file"
|
||||||
|
:id="id"
|
||||||
|
:class="class"
|
||||||
|
@change="convertFileToBase64($event.target.files)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { toBase64 } from '../util/file'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
methods: {
|
||||||
|
async convertFileToBase64(files) {
|
||||||
|
if (files.length) {
|
||||||
|
const value = await toBase64(files[0])
|
||||||
|
|
||||||
|
this.$emit('update:modelValue', value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
39
src/ui/InputForm.vue
Normal file
39
src/ui/InputForm.vue
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<template>
|
||||||
|
<label class="block text-sm font-medium text-gray-700" :for="id" v-if="label" v-text="label"></label>
|
||||||
|
<input
|
||||||
|
class="mt-2 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
|
:type="type"
|
||||||
|
:id="id"
|
||||||
|
:value="modelValue"
|
||||||
|
:class="class"
|
||||||
|
@change="$emit('change', $event)"
|
||||||
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'text'
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
"class": {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
}
|
||||||
|
</script>
|
51
src/ui/RangeForm.vue
Normal file
51
src/ui/RangeForm.vue
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<label class="block text-sm font-medium text-gray-700" :for="id" v-if="label" v-text="label"></label>
|
||||||
|
<input
|
||||||
|
class="mt-2 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
|
type="range"
|
||||||
|
:min="min"
|
||||||
|
:max="max"
|
||||||
|
:step="step"
|
||||||
|
:id="id"
|
||||||
|
:class="class"
|
||||||
|
:value="modelValue"
|
||||||
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: 100,
|
||||||
|
},
|
||||||
|
step: {
|
||||||
|
type: Number,
|
||||||
|
required: false,
|
||||||
|
default: 0.1,
|
||||||
|
},
|
||||||
|
"class": {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
}
|
||||||
|
</script>
|
38
src/ui/SelectForm.vue
Normal file
38
src/ui/SelectForm.vue
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<label class="block text-sm font-medium text-gray-700" :for="id" v-if="label" v-text="label"></label>
|
||||||
|
<select
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
|
:id="id"
|
||||||
|
:class="class"
|
||||||
|
:value="modelValue"
|
||||||
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
|
>
|
||||||
|
<option v-for="item in items" :key="item.value" :value="item.value" v-text="item.label"></option>
|
||||||
|
</select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
"class": {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
}
|
||||||
|
</script>
|
37
src/ui/TextareaForm.vue
Normal file
37
src/ui/TextareaForm.vue
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<label class="block text-sm font-medium text-gray-700" :for="id" v-if="label" v-text="label"></label>
|
||||||
|
<textarea
|
||||||
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
|
:id="id"
|
||||||
|
:class="class"
|
||||||
|
:value="modelValue"
|
||||||
|
@input="$emit('update:modelValue', $event.target.value)"
|
||||||
|
></textarea>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
modelValue: {
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
defaut: 'text'
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
"class": {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['update:modelValue'],
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in a new issue