mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 06:42:32 -05:00
add builder drawer
This commit is contained in:
1 parent
79f72c92b3
commit
d29be7c2cf
12 files changed
+299
-57
No files matched your search
@@ -4,12 +4,9 @@ class TemplatesVersionsController < ApplicationController
|
||||
load_and_authorize_resource :template
|
||||
|
||||
def index
|
||||
@versions = @template.template_versions.order(id: :desc).preload(:author)
|
||||
versions = @template.template_versions.order(id: :desc).preload(:author)
|
||||
|
||||
respond_to do |format|
|
||||
format.json { render json: @versions.as_json(TemplateVersions::SERIALIZE_PARAMS) }
|
||||
format.html
|
||||
end
|
||||
render json: versions.as_json(TemplateVersions::SERIALIZE_PARAMS)
|
||||
end
|
||||
|
||||
def show
|
||||
|
||||
@@ -189,6 +189,10 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
||||
connectedCallback () {
|
||||
document.addEventListener('turbo:submit-end', this.onSubmit)
|
||||
document.addEventListener('template-builder:update', this.onSheetSubmit)
|
||||
document.addEventListener('template-builder:sync', this.onSync)
|
||||
document.addEventListener('template-builder:scroll-to', this.onScrollTo)
|
||||
document.addEventListener('template-builder:select-field', this.onSelectField)
|
||||
document.addEventListener('template-builder:draw-field', this.onDrawField)
|
||||
document.addEventListener('turbo:before-cache', this.onBeforeCache)
|
||||
|
||||
this.appElem = document.createElement('div')
|
||||
@@ -233,7 +237,8 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
||||
currencies: (this.dataset.currencies || '').split(',').filter(Boolean),
|
||||
acceptFileTypes: this.dataset.acceptFileTypes,
|
||||
showTourStartForm: this.dataset.showTourStartForm === 'true',
|
||||
nativePlatform: this.dataset.nativePlatform
|
||||
nativePlatform: this.dataset.nativePlatform,
|
||||
view: this.dataset.view
|
||||
})
|
||||
|
||||
this.component = this.app.mount(this.appElem)
|
||||
@@ -257,6 +262,40 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
||||
this.applySubmission(e.detail.form, e.detail.action, e.detail.body, {})
|
||||
}
|
||||
|
||||
onSync = (e) => {
|
||||
const { schema, documents, fields, submitters } = e.detail
|
||||
|
||||
Object.assign(this.component.template, { schema, documents, fields, submitters })
|
||||
}
|
||||
|
||||
onScrollTo = (e) => {
|
||||
this.component.scrollIntoDocument(e.detail)
|
||||
}
|
||||
|
||||
onSelectField = (e) => {
|
||||
const { uuid, attachment_uuid: attachmentUuid, page, x, y } = e.detail
|
||||
const field = this.component.template.fields.find((f) => f.uuid === uuid)
|
||||
const areas = field?.areas || []
|
||||
const area = areas.find((a) => a.attachment_uuid === attachmentUuid && a.page === page && a.x === x && a.y === y) || areas[0]
|
||||
|
||||
if (area) this.component.scrollToArea(area)
|
||||
}
|
||||
|
||||
onDrawField = (e) => {
|
||||
const { uuid, type, option } = e.detail
|
||||
|
||||
if (uuid) {
|
||||
const field = this.component.template.fields.find((f) => f.uuid === uuid)
|
||||
|
||||
if (field) {
|
||||
this.component.drawField = field
|
||||
this.component.drawOption = option || null
|
||||
}
|
||||
} else if (type) {
|
||||
this.component.startFieldDraw({ type })
|
||||
}
|
||||
}
|
||||
|
||||
applySubmission (formId, action, body, data) {
|
||||
if (formId === 'submitters_form') {
|
||||
this.component.template.submitters = JSON.parse(body).submitters
|
||||
@@ -294,6 +333,10 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
||||
disconnectedCallback () {
|
||||
document.removeEventListener('turbo:submit-end', this.onSubmit)
|
||||
document.removeEventListener('template-builder:update', this.onSheetSubmit)
|
||||
document.removeEventListener('template-builder:sync', this.onSync)
|
||||
document.removeEventListener('template-builder:scroll-to', this.onScrollTo)
|
||||
document.removeEventListener('template-builder:select-field', this.onSelectField)
|
||||
document.removeEventListener('template-builder:draw-field', this.onDrawField)
|
||||
document.removeEventListener('turbo:before-cache', this.onBeforeCache)
|
||||
|
||||
this.app?.unmount()
|
||||
|
||||
@@ -21,6 +21,8 @@ export default class extends HTMLElement {
|
||||
title: this.dataset.label || target?.textContent.trim(),
|
||||
icon: this.dataset.icon,
|
||||
placement: this.dataset.placement || 'menu',
|
||||
side: this.dataset.side,
|
||||
view: this.dataset.view,
|
||||
section: this.dataset.section,
|
||||
menu: this.dataset.menu,
|
||||
menuIcon: this.dataset.menuIcon,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div
|
||||
ref="dragContainer"
|
||||
style="max-width: 1600px"
|
||||
class="mx-auto pl-3 md:pl-4 h-full"
|
||||
:class="isNativeView ? 'px-4 pt-3 pb-6' : 'mx-auto pl-3 md:pl-4 h-full'"
|
||||
@dragover="onDragover"
|
||||
@drop="isDragFile = false"
|
||||
>
|
||||
@@ -25,6 +25,85 @@
|
||||
:is-default="defaultFields.includes(toRaw(dragField))"
|
||||
:is-required="defaultRequiredFields.includes(toRaw(dragField))"
|
||||
/>
|
||||
<div
|
||||
v-if="isDocumentsView"
|
||||
class="space-y-3"
|
||||
>
|
||||
<DocumentPreview
|
||||
v-for="(item, index) in template.schema"
|
||||
:key="item.attachment_uuid"
|
||||
:with-arrows="template.schema.length > 1"
|
||||
:with-visible-controls="true"
|
||||
:item="item"
|
||||
:document="sortedDocuments[index]"
|
||||
:accept-file-types="acceptFileTypes"
|
||||
:with-replace-button="withUploadButton"
|
||||
:with-google-drive="withGoogleDrive"
|
||||
:authenticity-token="authenticityToken"
|
||||
:editable="editable"
|
||||
:dynamic-documents="dynamicDocuments"
|
||||
:with-dynamic-documents="withDynamicDocuments"
|
||||
:template="template"
|
||||
@scroll-to="postNativeEvent('template-builder:scroll-to', { attachment_uuid: item.attachment_uuid }, true)"
|
||||
@remove="onDocumentRemove"
|
||||
@replace="onDocumentReplace"
|
||||
@up="moveDocument(item, -1)"
|
||||
@reorder="reorderFields"
|
||||
@edit="editModalDocumentUuid = item.attachment_uuid"
|
||||
@down="moveDocument(item, 1)"
|
||||
@change="save"
|
||||
/>
|
||||
<Upload
|
||||
v-if="editable && withUploadButton"
|
||||
:accept-file-types="acceptFileTypes"
|
||||
:authenticity-token="authenticityToken"
|
||||
:with-google-drive="withGoogleDrive"
|
||||
:template-id="template.id"
|
||||
@success="updateFromUpload"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isFieldsView">
|
||||
<Fields
|
||||
ref="fields"
|
||||
:fields="template.fields"
|
||||
:submitters="template.submitters"
|
||||
:selected-submitter="selectedSubmitter"
|
||||
:with-help="withHelp"
|
||||
:default-submitters="defaultSubmitters"
|
||||
:draw-field-type="drawFieldType"
|
||||
:custom-fields="customFields"
|
||||
:with-custom-fields="withCustomFields"
|
||||
:with-fields-search="withFieldsSearch"
|
||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
||||
:with-custom-fields-tab="false"
|
||||
:template="template"
|
||||
:default-required-fields="defaultRequiredFields"
|
||||
:detect-custom-fields-index="detectCustomFieldsIndex"
|
||||
:field-types="fieldTypes"
|
||||
:with-fields-detection="withFieldsDetection"
|
||||
:with-detect-existing-fields="withDetectExistingFields"
|
||||
:with-signature-id="withSignatureId"
|
||||
:with-prefillable="withPrefillable"
|
||||
:only-defined-fields="onlyDefinedFields"
|
||||
:editable="editable"
|
||||
:scroll-on-edit="false"
|
||||
@add-field="addField"
|
||||
@set-draw="postNativeEvent('template-builder:draw-field', { uuid: $event.field.uuid, option: $event.option }, true)"
|
||||
@remove-field="onRemoveField"
|
||||
@remove-submitter="onRemoveSubmitter"
|
||||
@select-submitter="selectedSubmitter = $event"
|
||||
@set-draw-type="postNativeEvent('template-builder:draw-field', { type: $event }, true)"
|
||||
@change-submitter="selectedSubmitter = $event"
|
||||
@scroll-to-area="onDrawerScrollToArea"
|
||||
@rebuild-variables-schema="rebuildVariablesSchema"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isRevisionsView && !isRevisionsModalOpen"
|
||||
class="flex justify-center py-8"
|
||||
>
|
||||
<IconInnerShadowTop class="w-6 h-6 animate-spin" />
|
||||
</div>
|
||||
<div
|
||||
v-if="pendingFieldAttachmentUuids.length && editable"
|
||||
class="top-1.5 sticky h-0 z-20 max-w-2xl mx-auto"
|
||||
@@ -75,7 +154,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="$slots.buttons || withTitle"
|
||||
v-if="($slots.buttons || withTitle) && !isNativeView"
|
||||
id="title_container"
|
||||
class="flex justify-between py-1.5 items-center pr-4 top-0 z-10 title-container"
|
||||
:class="{ sticky: withStickySubmitters || isBreakpointLg, hidden: !!nativePlatform }"
|
||||
@@ -325,7 +404,7 @@
|
||||
>
|
||||
<a
|
||||
v-if="!!nativePlatform"
|
||||
:href="`/templates/${template.id}/versions`"
|
||||
:href="`/templates/${template.id}/edit?view=revisions`"
|
||||
data-turbo-frame="modal"
|
||||
/>
|
||||
<button
|
||||
@@ -390,6 +469,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!isNativeView"
|
||||
id="main_container"
|
||||
class="flex main-container"
|
||||
:class="($slots.buttons || withTitle) && !nativePlatform ? (isMobile ? 'max-h-[calc(100%_-_60px)]' : 'md:max-h-[calc(100%_-_60px)]') : (isMobile ? 'max-h-[100%]' : 'md:max-h-[100%]')"
|
||||
@@ -685,9 +765,40 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sticky bottom-0 z-10">
|
||||
<div
|
||||
v-if="!isNativeView"
|
||||
class="sticky bottom-0 z-10"
|
||||
>
|
||||
<native-action
|
||||
v-if="nativePlatform && withDocumentsList && isBreakpointLg && sortedDocuments.length"
|
||||
data-placement="drawer"
|
||||
data-side="leading"
|
||||
data-icon="files"
|
||||
data-native="drawer"
|
||||
:data-label="t('documents')"
|
||||
data-view="documents"
|
||||
/>
|
||||
<native-action
|
||||
v-if="nativePlatform && withFieldsList && isBreakpointLg && sortedDocuments.length && editable"
|
||||
data-placement="drawer"
|
||||
data-side="trailing"
|
||||
data-icon="plus"
|
||||
data-native="drawer"
|
||||
:data-label="'Fields'"
|
||||
data-view="fields"
|
||||
/>
|
||||
<native-action
|
||||
v-if="nativePlatform && drawField && (isBreakpointLg || isMobile)"
|
||||
data-placement="draw"
|
||||
:data-label="t('draw_field').replace('{field}', fieldNames[drawField.type])"
|
||||
>
|
||||
<button
|
||||
class="hidden"
|
||||
@click="[drawField = null, drawOption = null]"
|
||||
/>
|
||||
</native-action>
|
||||
<MobileDrawField
|
||||
v-if="drawField && (isBreakpointLg || isMobile)"
|
||||
v-if="drawField && (isBreakpointLg || isMobile) && !nativePlatform"
|
||||
:draw-field="drawField"
|
||||
:fields="template.fields"
|
||||
:submitters="template.submitters"
|
||||
@@ -698,7 +809,7 @@
|
||||
@change-submitter="[selectedSubmitter = $event, drawField.submitter_uuid = $event.uuid]"
|
||||
/>
|
||||
<MobileFields
|
||||
v-if="sortedDocuments.length && !drawField && editable"
|
||||
v-if="sortedDocuments.length && !drawField && editable && !nativePlatform"
|
||||
:fields="template.fields"
|
||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
||||
:default-required-fields="defaultRequiredFields"
|
||||
@@ -784,8 +895,9 @@
|
||||
:template="template"
|
||||
:revisions="revisions"
|
||||
:locale="locale"
|
||||
:inline="isRevisionsView"
|
||||
@close="isRevisionsModalOpen = false"
|
||||
@apply="onRevisionApply"
|
||||
@apply="isRevisionsView ? postNativeEvent('template-builder:apply-revision', $event, true) : onRevisionApply($event)"
|
||||
/>
|
||||
<DocumentsEditorModal
|
||||
v-if="editModalDocumentUuid"
|
||||
@@ -809,6 +921,7 @@ import HoverDropzone from './hover_dropzone'
|
||||
import DragPlaceholder from './drag_placeholder'
|
||||
import Fields from './fields'
|
||||
import MobileDrawField from './mobile_draw_field'
|
||||
import FieldType from './field_type'
|
||||
import Document from './document'
|
||||
import Logo from './logo'
|
||||
import Contenteditable from './contenteditable'
|
||||
@@ -887,6 +1000,7 @@ export default {
|
||||
withFormula: this.withFormula,
|
||||
withConditions: this.withConditions,
|
||||
nativePlatform: this.nativePlatform,
|
||||
isMobile: this.isMobile,
|
||||
withCustomFields: this.withCustomFields,
|
||||
isInlineSize: this.isInlineSize,
|
||||
defaultDrawFieldType: this.defaultDrawFieldType,
|
||||
@@ -1109,6 +1223,11 @@ export default {
|
||||
required: false,
|
||||
default: ''
|
||||
},
|
||||
view: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ''
|
||||
},
|
||||
withFieldsSearch: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
@@ -1287,6 +1406,19 @@ export default {
|
||||
lastSelectedArea () {
|
||||
return this.selectedAreasRef.value[this.selectedAreasRef.value.length - 1]
|
||||
},
|
||||
fieldNames: FieldType.computed.fieldNames,
|
||||
isDocumentsView () {
|
||||
return this.view === 'documents'
|
||||
},
|
||||
isFieldsView () {
|
||||
return this.view === 'fields'
|
||||
},
|
||||
isRevisionsView () {
|
||||
return this.view === 'revisions'
|
||||
},
|
||||
isNativeView () {
|
||||
return this.isDocumentsView || this.isFieldsView || this.isRevisionsView
|
||||
},
|
||||
isMobile () {
|
||||
const isMobileSafariIos = 'ontouchstart' in window && navigator.maxTouchPoints > 0 && /AppleWebKit/i.test(navigator.userAgent)
|
||||
|
||||
@@ -1472,6 +1604,10 @@ export default {
|
||||
this.selectedSubmitter = this.template.submitters[0]
|
||||
},
|
||||
mounted () {
|
||||
if (this.isRevisionsView) {
|
||||
this.openRevisionsModal()
|
||||
}
|
||||
|
||||
this.undoStack = [JSON.stringify(this.template)]
|
||||
this.redoStack = []
|
||||
|
||||
@@ -2265,7 +2401,25 @@ export default {
|
||||
scrollIntoDocument (item) {
|
||||
const ref = this.documentRefs.find((e) => e.document.uuid === item.attachment_uuid)
|
||||
|
||||
ref.$el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
ref?.$el.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||
},
|
||||
postNativeEvent (name, detail, dismiss = false) {
|
||||
window.webkit?.messageHandlers?.modal?.postMessage({ action: 'dispatch', name, detail: JSON.stringify(detail), dismiss: dismiss ? 'true' : 'false' })
|
||||
},
|
||||
onDrawerScrollToArea (area) {
|
||||
const field = this.template.fields.find((f) => (f.areas || []).includes(area))
|
||||
|
||||
this.postNativeEvent('template-builder:select-field', { uuid: field?.uuid, attachment_uuid: area.attachment_uuid, page: area.page, x: area.x, y: area.y }, true)
|
||||
},
|
||||
syncNative () {
|
||||
const { schema, documents, fields, submitters } = this.template
|
||||
const detail = JSON.stringify({ schema, documents, fields, submitters })
|
||||
|
||||
if (this.isNativeView) {
|
||||
window.webkit?.messageHandlers?.modal?.postMessage({ action: 'dispatch', name: 'template-builder:sync', detail, dismiss: 'false' })
|
||||
} else {
|
||||
window.webkit?.messageHandlers?.native?.postMessage({ type: 'drawer', op: 'sync', detail })
|
||||
}
|
||||
},
|
||||
clearDrawField () {
|
||||
this.drawField = null
|
||||
@@ -3651,6 +3805,10 @@ export default {
|
||||
|
||||
this.pushUndo()
|
||||
|
||||
if (this.nativePlatform) {
|
||||
this.syncNative()
|
||||
}
|
||||
|
||||
if (!this.autosave && !force) {
|
||||
return Promise.resolve({})
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
{{ value }}
|
||||
</span>
|
||||
<span
|
||||
v-if="withButton"
|
||||
v-if="withButton && !isMobile"
|
||||
class="relative inline"
|
||||
:class="{ 'peer-focus:hidden': hideIcon, 'peer-focus:invisible': !hideIcon }"
|
||||
>
|
||||
@@ -48,7 +48,7 @@ export default {
|
||||
components: {
|
||||
IconPencil
|
||||
},
|
||||
inject: ['t'],
|
||||
inject: ['t', 'isMobile'],
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
:menu-classes="'mt-1.5'"
|
||||
:menu-style="{ backgroundColor: dropdownBgColor }"
|
||||
@update:model-value="[maybeUpdateOptions(), $emit('save')]"
|
||||
@click="scrollToFirstArea"
|
||||
@click="scrollOnEdit && scrollToFirstArea()"
|
||||
/>
|
||||
<Contenteditable
|
||||
ref="name"
|
||||
@@ -29,7 +29,7 @@
|
||||
:icon-inline="true"
|
||||
:icon-width="18"
|
||||
:icon-stroke-width="1.6"
|
||||
@focus="[onNameFocus(), scrollToFirstArea()]"
|
||||
@focus="[onNameFocus(), scrollOnEdit && scrollToFirstArea()]"
|
||||
@blur="onNameBlur"
|
||||
/>
|
||||
</div>
|
||||
@@ -60,7 +60,8 @@
|
||||
<button
|
||||
v-if="field && !field.areas?.length"
|
||||
:title="t('draw')"
|
||||
class="relative cursor-pointer text-transparent group-hover:text-base-content"
|
||||
class="relative cursor-pointer"
|
||||
:class="iconColorClass"
|
||||
@click="$emit('set-draw', { field })"
|
||||
>
|
||||
<IconNewSection
|
||||
@@ -70,7 +71,8 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="field.preferences?.formula"
|
||||
class="relative cursor-pointer text-transparent group-hover:text-base-content"
|
||||
class="relative cursor-pointer"
|
||||
:class="iconColorClass"
|
||||
:title="t('formula')"
|
||||
@click="isShowFormulaModal = true"
|
||||
>
|
||||
@@ -81,7 +83,8 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="field.conditions?.length"
|
||||
class="relative cursor-pointer text-transparent group-hover:text-base-content"
|
||||
class="relative cursor-pointer"
|
||||
:class="iconColorClass"
|
||||
:title="t('condition')"
|
||||
@click="isShowConditionsModal = true"
|
||||
>
|
||||
@@ -109,9 +112,17 @@
|
||||
<label
|
||||
tabindex="0"
|
||||
:title="t('settings')"
|
||||
class="cursor-pointer text-transparent group-hover:text-base-content"
|
||||
class="cursor-pointer flex items-center"
|
||||
:class="[iconColorClass, { 'pr-1': isMobile }]"
|
||||
>
|
||||
<IconDotsVertical
|
||||
v-if="isMobile"
|
||||
:width="18"
|
||||
:height="18"
|
||||
:stroke-width="1.6"
|
||||
/>
|
||||
<IconSettings
|
||||
v-else
|
||||
:width="18"
|
||||
:stroke-width="1.6"
|
||||
/>
|
||||
@@ -143,10 +154,28 @@
|
||||
@save="$emit('save')"
|
||||
@scroll-to="$emit('scroll-to', $event)"
|
||||
/>
|
||||
<li
|
||||
v-if="isMobile"
|
||||
class="field-settings-remove"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
class="text-sm py-1 px-2 text-red-600"
|
||||
@click.prevent="$emit('remove', field)"
|
||||
>
|
||||
<IconTrashX
|
||||
:width="20"
|
||||
:stroke-width="1.6"
|
||||
/>
|
||||
{{ t('remove') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<button
|
||||
class="relative text-transparent group-hover:text-base-content pr-1 field-remove-button"
|
||||
v-if="!isMobile"
|
||||
class="relative pr-1 field-remove-button"
|
||||
:class="iconColorClass"
|
||||
:title="t('remove')"
|
||||
@click="$emit('remove', field)"
|
||||
>
|
||||
@@ -324,7 +353,7 @@ import FormulaModal from './formula_modal'
|
||||
import FontModal from './font_modal'
|
||||
import ConditionsModal from './conditions_modal'
|
||||
import DescriptionModal from './description_modal'
|
||||
import { IconRouteAltLeft, IconMathFunction, IconNewSection, IconTrashX, IconSettings, IconChevronDown } from '@tabler/icons-vue'
|
||||
import { IconRouteAltLeft, IconMathFunction, IconNewSection, IconTrashX, IconSettings, IconDotsVertical, IconChevronDown } from '@tabler/icons-vue'
|
||||
import { v4 } from 'uuid'
|
||||
|
||||
export default {
|
||||
@@ -332,6 +361,7 @@ export default {
|
||||
components: {
|
||||
Contenteditable,
|
||||
IconSettings,
|
||||
IconDotsVertical,
|
||||
FieldSettings,
|
||||
PaymentSettings,
|
||||
IconChevronDown,
|
||||
@@ -345,12 +375,17 @@ export default {
|
||||
IconMathFunction,
|
||||
FieldType
|
||||
},
|
||||
inject: ['template', 'backgroundColor', 'selectedAreasRef', 't', 'locale', 'getFieldTypeIndex', 'dateFormats'],
|
||||
inject: ['template', 'backgroundColor', 'selectedAreasRef', 't', 'locale', 'getFieldTypeIndex', 'dateFormats', 'isMobile'],
|
||||
props: {
|
||||
field: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
scrollOnEdit: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
withSignatureId: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
@@ -396,6 +431,9 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iconColorClass () {
|
||||
return this.isMobile ? 'text-base-content' : 'text-transparent group-hover:text-base-content'
|
||||
},
|
||||
fieldNames: FieldType.computed.fieldNames,
|
||||
fieldLabels: FieldType.computed.fieldLabels,
|
||||
dropdownBgColor () {
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
:key="field.uuid"
|
||||
:data-uuid="field.uuid"
|
||||
:field="field"
|
||||
:scroll-on-edit="scrollOnEdit"
|
||||
:type-index="getFieldTypeIndex(field)"
|
||||
:editable="editable"
|
||||
:with-signature-id="withSignatureId"
|
||||
@@ -482,6 +483,11 @@ export default {
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
scrollOnEdit: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
defaultFields: {
|
||||
type: Array,
|
||||
required: false,
|
||||
|
||||
@@ -98,6 +98,7 @@ const en = {
|
||||
add_documents_or_images: 'Add documents or images',
|
||||
add_a_new_document: 'Add a new document',
|
||||
edit_documents: 'Edit documents',
|
||||
documents: 'Documents',
|
||||
move_forward: 'Move forward',
|
||||
move_backward: 'Move backward',
|
||||
remove_page: 'Remove page',
|
||||
@@ -340,6 +341,7 @@ const es = {
|
||||
add_documents_or_images: 'Agregar documentos o imágenes',
|
||||
add_a_new_document: 'Agregar un nuevo documento',
|
||||
edit_documents: 'Editar documentos',
|
||||
documents: 'Documentos',
|
||||
move_forward: 'Mover adelante',
|
||||
move_backward: 'Mover atrás',
|
||||
remove_page: 'Eliminar página',
|
||||
@@ -588,6 +590,7 @@ const it = {
|
||||
add_documents_or_images: 'Aggiungi documenti o immagini',
|
||||
add_a_new_document: 'Aggiungi un nuovo documento',
|
||||
edit_documents: 'Modifica documenti',
|
||||
documents: 'Documenti',
|
||||
move_forward: 'Sposta avanti',
|
||||
move_backward: 'Sposta indietro',
|
||||
remove_page: 'Rimuovi pagina',
|
||||
@@ -830,6 +833,7 @@ const pt = {
|
||||
add_documents_or_images: 'Adicionar documentos ou imagens',
|
||||
add_a_new_document: 'Adicionar um novo documento',
|
||||
edit_documents: 'Editar documentos',
|
||||
documents: 'Documentos',
|
||||
move_forward: 'Mover para frente',
|
||||
move_backward: 'Mover para trás',
|
||||
remove_page: 'Remover página',
|
||||
@@ -1078,6 +1082,7 @@ const fr = {
|
||||
add_documents_or_images: 'Ajouter des documents ou des images',
|
||||
add_a_new_document: 'Ajouter un nouveau document',
|
||||
edit_documents: 'Modifier les documents',
|
||||
documents: 'Documents',
|
||||
move_forward: 'Déplacer en avant',
|
||||
move_backward: 'Déplacer en arrière',
|
||||
remove_page: 'Supprimer la page',
|
||||
@@ -1323,6 +1328,7 @@ const de = {
|
||||
add_documents_or_images: 'Dokumente oder Bilder hinzufügen',
|
||||
add_a_new_document: 'Neues Dokument hinzufügen',
|
||||
edit_documents: 'Dokumente bearbeiten',
|
||||
documents: 'Dokumente',
|
||||
move_forward: 'Nach vorne',
|
||||
move_backward: 'Nach hinten',
|
||||
remove_page: 'Seite entfernen',
|
||||
@@ -1568,6 +1574,7 @@ const nl = {
|
||||
add_documents_or_images: 'Documenten of afbeeldingen toevoegen',
|
||||
add_a_new_document: 'Nieuw document toevoegen',
|
||||
edit_documents: 'Documenten bewerken',
|
||||
documents: 'Documenten',
|
||||
move_forward: 'Naar voren',
|
||||
move_backward: 'Naar achteren',
|
||||
remove_page: 'Pagina verwijderen',
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
:authenticity-token="authenticityToken"
|
||||
:with-google-drive="withGoogleDrive"
|
||||
:google-drive-file-id="item.google_drive_file_id"
|
||||
class="opacity-0 group-hover:opacity-100 has-[label:focus]:opacity-100"
|
||||
:class="{ 'opacity-0 group-hover:opacity-100 has-[label:focus]:opacity-100': !withVisibleControls }"
|
||||
@click.stop
|
||||
@success="$emit('replace', { replaceSchemaItem: item, ...$event })"
|
||||
/>
|
||||
@@ -49,7 +49,7 @@
|
||||
>
|
||||
<span
|
||||
class="dropdown dropdown-end group-hover:opacity-100 has-[label:focus]:opacity-100"
|
||||
:class="{ 'dropdown-open': isMakeDynamicLoading, 'opacity-0': !isMakeDynamicLoading }"
|
||||
:class="{ 'dropdown-open': isMakeDynamicLoading, 'opacity-0': !isMakeDynamicLoading && !withVisibleControls }"
|
||||
@mouseenter="renderDropdown = true"
|
||||
@touchstart="renderDropdown = true"
|
||||
>
|
||||
@@ -137,7 +137,8 @@
|
||||
</span>
|
||||
<div
|
||||
v-if="withArrows"
|
||||
class="flex flex-col space-y-1 opacity-0 group-hover:opacity-100"
|
||||
class="flex flex-col space-y-1"
|
||||
:class="{ 'opacity-0 group-hover:opacity-100': !withVisibleControls }"
|
||||
>
|
||||
<button
|
||||
class="btn border-gray-300 bg-white text-base-content btn-xs rounded hover:text-base-100 hover:bg-base-content hover:border-base-content w-full transition-colors document-control-button"
|
||||
@@ -222,6 +223,11 @@ export default {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
withVisibleControls: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
template: {
|
||||
type: Object,
|
||||
required: true
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
<template>
|
||||
<div class="modal modal-open items-start !animate-none overflow-y-auto">
|
||||
<div :class="{ 'modal modal-open items-start !animate-none overflow-y-auto': !inline }">
|
||||
<div
|
||||
v-if="!inline"
|
||||
class="absolute top-0 bottom-0 right-0 left-0"
|
||||
@click.prevent="$emit('close')"
|
||||
/>
|
||||
<div class="modal-box pt-4 pb-6 mt-20 w-full">
|
||||
<div class="flex justify-between items-center border-b pb-2 mb-3 font-medium">
|
||||
<div :class="{ 'modal-box pt-4 pb-6 mt-20 w-full': !inline }">
|
||||
<div
|
||||
v-if="!inline"
|
||||
class="flex justify-between items-center border-b pb-2 mb-3 font-medium"
|
||||
>
|
||||
<span>{{ t('revisions') }}</span>
|
||||
<a
|
||||
href="#"
|
||||
@@ -72,6 +76,11 @@ export default {
|
||||
locale: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
inline: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['close', 'apply'],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% content_for(:native_title, @template.name) if turbo_native_app? %>
|
||||
<% content_for(:native_title, params[:view] == 'revisions' ? t('revisions') : @template.name) if turbo_native_app? %>
|
||||
<% if !turbo_native_app? && (current_user.created_at > 2.weeks.ago || params[:tour] == 'true') %>
|
||||
<% user_config = current_user.user_configs.find_or_initialize_by(key: UserConfig::SHOW_APP_TOUR) %>
|
||||
<% @show_tour_start_form = user_config.new_record? && !params.key?(:tour) %>
|
||||
@@ -10,4 +10,4 @@
|
||||
<% account_configs = current_account.account_configs.where(key: [AccountConfig::TEMPLATE_CUSTOM_FIELDS_KEY, AccountConfig::TEMPLATE_DATE_FORMATS_KEY]).to_a %>
|
||||
<% custom_fields = account_configs.find { |e| e.key == AccountConfig::TEMPLATE_CUSTOM_FIELDS_KEY }&.value || [] %>
|
||||
<% date_formats = account_configs.find { |e| e.key == AccountConfig::TEMPLATE_DATE_FORMATS_KEY }&.value || [] %>
|
||||
<template-builder data-native-platform="<%= turbo_native_ios? ? 'ios' : (turbo_native_android? ? 'android' : '') %>" class="grid" data-template="<%= @template_data.to_json %>" data-custom-fields="<%= custom_fields.to_json %>" data-date-formats="<%= date_formats.to_json %>" data-with-sign-yourself-button="<%= !@template.archived_at? %>" data-with-fields-detection="true" data-with-send-button="<%= !@template.archived_at? && can?(:create, @template.submissions.new(account: current_account)) %>" data-with-revisions-menu="<%= @template.template_versions.exists? %>" data-locale="<%= I18n.locale %>" data-show-tour-start-form="<%= @show_tour_start_form %>"></template-builder>
|
||||
<template-builder data-view="<%= params[:view] %>" data-native-platform="<%= turbo_native_ios? ? 'ios' : (turbo_native_android? ? 'android' : '') %>" class="grid" data-template="<%= @template_data.to_json %>" data-custom-fields="<%= custom_fields.to_json %>" data-date-formats="<%= date_formats.to_json %>" data-with-sign-yourself-button="<%= !@template.archived_at? %>" data-with-fields-detection="true" data-with-send-button="<%= !@template.archived_at? && can?(:create, @template.submissions.new(account: current_account)) %>" data-with-revisions-menu="<%= @template.template_versions.exists? %>" data-locale="<%= I18n.locale %>" data-show-tour-start-form="<%= @show_tour_start_form %>"></template-builder>
|
||||
@@ -1,24 +0,0 @@
|
||||
<%= render 'shared/turbo_modal', title: t('revisions') do %>
|
||||
<ul class="space-y-1.5">
|
||||
<% @versions.each do |version| %>
|
||||
<li>
|
||||
<native-event class="group flex justify-between items-center gap-2 w-full rounded-lg p-3 border border-dashed border-base-200 cursor-pointer" data-name="template-builder:apply-revision" data-src="<%= template_version_path(@template, version) %>">
|
||||
<div class="flex flex-col min-w-0">
|
||||
<span><%= l(version.created_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %></span>
|
||||
<span class="-ml-0.5 flex items-center space-x-1 text-xs text-base-content/60 mt-0.5">
|
||||
<%= svg_icon('user', class: 'w-3.5 h-3.5 flex-shrink-0') %>
|
||||
<span class="truncate"><%= version.author.full_name.presence || version.author.email %></span>
|
||||
</span>
|
||||
</div>
|
||||
<span class="btn btn-sm btn-neutral text-white pointer-events-none flex-shrink-0">
|
||||
<span class="group-data-[loading]:hidden"><%= t('view') %></span>
|
||||
<%= svg_icon('loader', class: 'w-4 h-4 animate-spin hidden group-data-[loading]:block') %>
|
||||
</span>
|
||||
</native-event>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if @versions.empty? %>
|
||||
<li class="py-4 text-center text-base-content/60"><%= t('no_revisions_yet') %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
Reference in new issue
Block a user