mirror of
https://github.com/docusealco/docuseal
synced 2026-11-11 15:42:32 -05:00
adjust mobile builder
This commit is contained in:
1 parent
d29be7c2cf
commit
3ed15e383b
12 files changed
+521
-638
No files matched your search
@@ -2,7 +2,7 @@
|
|||||||
<div
|
<div
|
||||||
ref="dragContainer"
|
ref="dragContainer"
|
||||||
style="max-width: 1600px"
|
style="max-width: 1600px"
|
||||||
:class="isNativeView ? 'px-4 pt-3 pb-6' : 'mx-auto pl-3 md:pl-4 h-full'"
|
:class="isNativeView ? (isRevisionsView ? 'px-4 pt-3 pb-6' : 'px-4') : 'mx-auto pl-3 md:pl-4 h-full'"
|
||||||
@dragover="onDragover"
|
@dragover="onDragover"
|
||||||
@drop="isDragFile = false"
|
@drop="isDragFile = false"
|
||||||
>
|
>
|
||||||
@@ -25,79 +25,117 @@
|
|||||||
:is-default="defaultFields.includes(toRaw(dragField))"
|
:is-default="defaultFields.includes(toRaw(dragField))"
|
||||||
:is-required="defaultRequiredFields.includes(toRaw(dragField))"
|
:is-required="defaultRequiredFields.includes(toRaw(dragField))"
|
||||||
/>
|
/>
|
||||||
<div
|
<MobileDrawer
|
||||||
v-if="isDocumentsView"
|
v-if="isDocumentsView || (withMobileDrawers && withDocumentsList && isBreakpointLg)"
|
||||||
class="space-y-3"
|
side="left"
|
||||||
|
:inline="isDocumentsView"
|
||||||
|
:open="isDocumentsDrawerOpen"
|
||||||
|
@close="isDocumentsDrawerOpen = false"
|
||||||
>
|
>
|
||||||
<DocumentPreview
|
<div class="pt-3 space-y-3">
|
||||||
v-for="(item, index) in template.schema"
|
<DocumentPreview
|
||||||
:key="item.attachment_uuid"
|
v-for="(item, index) in template.schema"
|
||||||
:with-arrows="template.schema.length > 1"
|
:key="item.attachment_uuid"
|
||||||
:with-visible-controls="true"
|
:with-arrows="template.schema.length > 1"
|
||||||
:item="item"
|
:with-visible-controls="true"
|
||||||
:document="sortedDocuments[index]"
|
:item="item"
|
||||||
:accept-file-types="acceptFileTypes"
|
:document="sortedDocuments[index]"
|
||||||
:with-replace-button="withUploadButton"
|
:accept-file-types="acceptFileTypes"
|
||||||
:with-google-drive="withGoogleDrive"
|
:with-replace-button="withUploadButton"
|
||||||
:authenticity-token="authenticityToken"
|
:with-google-drive="withGoogleDrive"
|
||||||
:editable="editable"
|
:authenticity-token="authenticityToken"
|
||||||
:dynamic-documents="dynamicDocuments"
|
:editable="editable"
|
||||||
:with-dynamic-documents="withDynamicDocuments"
|
:dynamic-documents="dynamicDocuments"
|
||||||
:template="template"
|
:with-dynamic-documents="withDynamicDocuments"
|
||||||
@scroll-to="postNativeEvent('template-builder:scroll-to', { attachment_uuid: item.attachment_uuid }, true)"
|
:template="template"
|
||||||
@remove="onDocumentRemove"
|
@scroll-to="onDrawerScrollTo(item)"
|
||||||
@replace="onDocumentReplace"
|
@remove="onDocumentRemove"
|
||||||
@up="moveDocument(item, -1)"
|
@replace="onDocumentReplace"
|
||||||
@reorder="reorderFields"
|
@up="moveDocument(item, -1)"
|
||||||
@edit="editModalDocumentUuid = item.attachment_uuid"
|
@reorder="reorderFields"
|
||||||
@down="moveDocument(item, 1)"
|
@edit="editModalDocumentUuid = item.attachment_uuid"
|
||||||
@change="save"
|
@down="moveDocument(item, 1)"
|
||||||
/>
|
@change="save"
|
||||||
<Upload
|
/>
|
||||||
v-if="editable && withUploadButton"
|
</div>
|
||||||
:accept-file-types="acceptFileTypes"
|
<div
|
||||||
:authenticity-token="authenticityToken"
|
v-if="editable && (withUploadButton || withAddPageButton)"
|
||||||
:with-google-drive="withGoogleDrive"
|
class="pt-3 space-y-2"
|
||||||
:template-id="template.id"
|
:class="isDocumentsView ? 'pb-6' : 'sticky bottom-0 bg-base-100 pb-3'"
|
||||||
@success="updateFromUpload"
|
>
|
||||||
/>
|
<Upload
|
||||||
</div>
|
v-if="withUploadButton"
|
||||||
<div v-if="isFieldsView">
|
:accept-file-types="acceptFileTypes"
|
||||||
<Fields
|
:authenticity-token="authenticityToken"
|
||||||
ref="fields"
|
:with-google-drive="withGoogleDrive"
|
||||||
:fields="template.fields"
|
:template-id="template.id"
|
||||||
:submitters="template.submitters"
|
@success="updateFromUpload"
|
||||||
:selected-submitter="selectedSubmitter"
|
/>
|
||||||
:with-help="withHelp"
|
<button
|
||||||
:default-submitters="defaultSubmitters"
|
v-if="withAddPageButton"
|
||||||
:draw-field-type="drawFieldType"
|
class="btn btn-outline w-full add-blank-page-button"
|
||||||
:custom-fields="customFields"
|
@click.prevent="addBlankPage"
|
||||||
:with-custom-fields="withCustomFields"
|
>
|
||||||
:with-fields-search="withFieldsSearch"
|
<IconInnerShadowTop
|
||||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
v-if="isLoadingBlankPage"
|
||||||
:with-custom-fields-tab="false"
|
class="animate-spin w-5 h-5"
|
||||||
:template="template"
|
/>
|
||||||
:default-required-fields="defaultRequiredFields"
|
<IconPlus
|
||||||
:detect-custom-fields-index="detectCustomFieldsIndex"
|
v-else
|
||||||
:field-types="fieldTypes"
|
class="w-5 h-5"
|
||||||
:with-fields-detection="withFieldsDetection"
|
/>
|
||||||
:with-detect-existing-fields="withDetectExistingFields"
|
{{ t('add_blank_page') }}
|
||||||
:with-signature-id="withSignatureId"
|
</button>
|
||||||
:with-prefillable="withPrefillable"
|
</div>
|
||||||
:only-defined-fields="onlyDefinedFields"
|
</MobileDrawer>
|
||||||
:editable="editable"
|
<MobileDrawer
|
||||||
:scroll-on-edit="false"
|
v-if="isFieldsView || (withMobileDrawers && withFieldsList && editable)"
|
||||||
@add-field="addField"
|
side="right"
|
||||||
@set-draw="postNativeEvent('template-builder:draw-field', { uuid: $event.field.uuid, option: $event.option }, true)"
|
:inline="isFieldsView"
|
||||||
@remove-field="onRemoveField"
|
:open="isFieldsDrawerOpen"
|
||||||
@remove-submitter="onRemoveSubmitter"
|
:class="{ 'md:hidden': !isMobile }"
|
||||||
@select-submitter="selectedSubmitter = $event"
|
@close="isFieldsDrawerOpen = false"
|
||||||
@set-draw-type="postNativeEvent('template-builder:draw-field', { type: $event }, true)"
|
>
|
||||||
@change-submitter="selectedSubmitter = $event"
|
<div class="pb-6">
|
||||||
@scroll-to-area="onDrawerScrollToArea"
|
<Fields
|
||||||
@rebuild-variables-schema="rebuildVariablesSchema"
|
:with-top-padding="true"
|
||||||
/>
|
:fields="template.fields"
|
||||||
</div>
|
:submitters="template.submitters"
|
||||||
|
:selected-submitter="selectedSubmitter"
|
||||||
|
:with-help="false"
|
||||||
|
: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="onDrawerSetDraw"
|
||||||
|
@remove-field="onRemoveField"
|
||||||
|
@remove-submitter="onRemoveSubmitter"
|
||||||
|
@select-submitter="selectedSubmitter = $event"
|
||||||
|
@set-draw-type="onDrawerSetDrawType"
|
||||||
|
@set-drag="dragField = $event"
|
||||||
|
@set-drag-placeholder="$refs.dragPlaceholder.dragPlaceholder = $event"
|
||||||
|
@drag-end="[dragField = null, $refs.dragPlaceholder.dragPlaceholder = null]"
|
||||||
|
@change-submitter="selectedSubmitter = $event"
|
||||||
|
@scroll-to-area="onDrawerScrollToArea"
|
||||||
|
@rebuild-variables-schema="rebuildVariablesSchema"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</MobileDrawer>
|
||||||
<div
|
<div
|
||||||
v-if="isRevisionsView && !isRevisionsModalOpen"
|
v-if="isRevisionsView && !isRevisionsModalOpen"
|
||||||
class="flex justify-center py-8"
|
class="flex justify-center py-8"
|
||||||
@@ -636,53 +674,7 @@
|
|||||||
@delete-selected-areas="deleteSelectedAreas"
|
@delete-selected-areas="deleteSelectedAreas"
|
||||||
@autodetect-fields="detectFieldsForPage"
|
@autodetect-fields="detectFieldsForPage"
|
||||||
/>
|
/>
|
||||||
<DocumentControls
|
|
||||||
v-if="isBreakpointLg && editable"
|
|
||||||
:with-arrows="template.schema.length > 1"
|
|
||||||
:item="template.schema.find((item) => item.attachment_uuid === document.uuid)"
|
|
||||||
:with-replace-button="withUploadButton"
|
|
||||||
:with-google-drive="withGoogleDrive"
|
|
||||||
:authenticity-token="authenticityToken"
|
|
||||||
:accept-file-types="acceptFileTypes"
|
|
||||||
:document="document"
|
|
||||||
:template="template"
|
|
||||||
class="pb-2 mb-2 border-b border-base-300 border-dashed"
|
|
||||||
@remove="onDocumentRemove"
|
|
||||||
@replace="onDocumentReplace"
|
|
||||||
@up="moveDocument(template.schema.find((item) => item.attachment_uuid === document.uuid), -1)"
|
|
||||||
@down="moveDocument(template.schema.find((item) => item.attachment_uuid === document.uuid), 1)"
|
|
||||||
@change="save"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<div
|
|
||||||
v-if="sortedDocuments.length && isBreakpointLg && editable"
|
|
||||||
class="pb-4 space-y-2"
|
|
||||||
>
|
|
||||||
<Upload
|
|
||||||
v-if="withUploadButton"
|
|
||||||
:template-id="template.id"
|
|
||||||
:accept-file-types="acceptFileTypes"
|
|
||||||
:authenticity-token="authenticityToken"
|
|
||||||
:with-google-drive="withGoogleDrive"
|
|
||||||
@success="updateFromUpload"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
v-if="withAddPageButton"
|
|
||||||
id="add_blank_page_button"
|
|
||||||
class="btn btn-outline w-full mt-4 add-blank-page-button"
|
|
||||||
@click.prevent="addBlankPage"
|
|
||||||
>
|
|
||||||
<IconInnerShadowTop
|
|
||||||
v-if="isLoadingBlankPage"
|
|
||||||
class="animate-spin w-5 h-5"
|
|
||||||
/>
|
|
||||||
<IconPlus
|
|
||||||
v-else
|
|
||||||
class="w-5 h-5"
|
|
||||||
/>
|
|
||||||
{{ t('add_blank_page') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -797,27 +789,52 @@
|
|||||||
@click="[drawField = null, drawOption = null]"
|
@click="[drawField = null, drawOption = null]"
|
||||||
/>
|
/>
|
||||||
</native-action>
|
</native-action>
|
||||||
<MobileDrawField
|
<button
|
||||||
v-if="drawField && (isBreakpointLg || isMobile) && !nativePlatform"
|
v-if="drawField && (isBreakpointLg || isMobile) && !nativePlatform"
|
||||||
:draw-field="drawField"
|
class="btn btn-neutral text-white btn-lg rounded-full no-animation transition-none absolute bottom-4 -left-3 md:-left-4 right-0 mx-auto w-fit z-10 flex-nowrap gap-2 px-5 max-[400px]:px-4"
|
||||||
:fields="template.fields"
|
|
||||||
:submitters="template.submitters"
|
|
||||||
:selected-submitter="selectedSubmitter"
|
|
||||||
:class="{ 'md:hidden': !isMobile }"
|
:class="{ 'md:hidden': !isMobile }"
|
||||||
:editable="editable"
|
style="max-width: calc(100% - 11rem); --btn-focus-scale: 1"
|
||||||
@cancel="[drawField = null, drawOption = null]"
|
@click.prevent="[drawField = null, drawOption = null]"
|
||||||
@change-submitter="[selectedSubmitter = $event, drawField.submitter_uuid = $event.uuid]"
|
>
|
||||||
/>
|
<component
|
||||||
<MobileFields
|
:is="fieldIcons[drawField.type]"
|
||||||
v-if="sortedDocuments.length && !drawField && editable && !nativePlatform"
|
:width="22"
|
||||||
:fields="template.fields"
|
:height="22"
|
||||||
:default-fields="[...defaultRequiredFields, ...defaultFields]"
|
:stroke-width="1.6"
|
||||||
:default-required-fields="defaultRequiredFields"
|
class="flex-shrink-0 max-[400px]:hidden"
|
||||||
:field-types="fieldTypes"
|
/>
|
||||||
|
<span class="truncate normal-case font-normal text-[17px] max-[400px]:text-[15px]">{{ t('draw_field').replace('{field}', fieldNames[drawField.type]) }}</span>
|
||||||
|
<IconX
|
||||||
|
:width="18"
|
||||||
|
:height="18"
|
||||||
|
:stroke-width="2.5"
|
||||||
|
class="flex-shrink-0"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="withMobileDrawers && withDocumentsList && isBreakpointLg"
|
||||||
|
class="btn btn-neutral text-white btn-circle btn-lg absolute bottom-4 left-1 md:left-0 z-10"
|
||||||
|
:title="t('documents')"
|
||||||
|
@click.prevent="isDocumentsDrawerOpen = true"
|
||||||
|
>
|
||||||
|
<IconFiles
|
||||||
|
:width="26"
|
||||||
|
:height="26"
|
||||||
|
:stroke-width="1.6"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="withMobileDrawers && withFieldsList && editable"
|
||||||
|
class="btn btn-neutral text-white btn-circle btn-lg absolute bottom-4 right-4 z-10"
|
||||||
:class="{ 'md:hidden': !isMobile }"
|
:class="{ 'md:hidden': !isMobile }"
|
||||||
:selected-submitter="selectedSubmitter"
|
title="Fields"
|
||||||
@select="startFieldDraw($event)"
|
@click.prevent="isFieldsDrawerOpen = true"
|
||||||
/>
|
>
|
||||||
|
<IconPlus
|
||||||
|
:width="28"
|
||||||
|
:height="28"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<Transition
|
<Transition
|
||||||
enter-active-class="transition-all duration-300 ease-out"
|
enter-active-class="transition-all duration-300 ease-out"
|
||||||
@@ -920,18 +937,16 @@ import Dropzone from './dropzone'
|
|||||||
import HoverDropzone from './hover_dropzone'
|
import HoverDropzone from './hover_dropzone'
|
||||||
import DragPlaceholder from './drag_placeholder'
|
import DragPlaceholder from './drag_placeholder'
|
||||||
import Fields from './fields'
|
import Fields from './fields'
|
||||||
import MobileDrawField from './mobile_draw_field'
|
import MobileDrawer from './mobile_drawer'
|
||||||
import FieldType from './field_type'
|
import FieldType from './field_type'
|
||||||
import Document from './document'
|
import Document from './document'
|
||||||
import Logo from './logo'
|
import Logo from './logo'
|
||||||
import Contenteditable from './contenteditable'
|
import Contenteditable from './contenteditable'
|
||||||
import DocumentPreview from './preview'
|
import DocumentPreview from './preview'
|
||||||
import DocumentControls from './controls'
|
|
||||||
import MobileFields from './mobile_fields'
|
|
||||||
import FieldSubmitter from './field_submitter'
|
import FieldSubmitter from './field_submitter'
|
||||||
import RevisionsModal from './revisions_modal'
|
import RevisionsModal from './revisions_modal'
|
||||||
import DocumentsEditorModal from './documents_editor_modal'
|
import DocumentsEditorModal from './documents_editor_modal'
|
||||||
import { IconPlus, IconUsersPlus, IconDeviceFloppy, IconChevronDown, IconEye, IconWritingSign, IconInnerShadowTop, IconInfoCircle, IconAdjustments, IconDownload, IconHistory, IconX } from '@tabler/icons-vue'
|
import { IconPlus, IconFiles, IconUsersPlus, IconDeviceFloppy, IconChevronDown, IconEye, IconWritingSign, IconInnerShadowTop, IconInfoCircle, IconAdjustments, IconDownload, IconHistory, IconX } from '@tabler/icons-vue'
|
||||||
import { v4 } from 'uuid'
|
import { v4 } from 'uuid'
|
||||||
import { ref, computed, toRaw, defineAsyncComponent } from 'vue'
|
import { ref, computed, toRaw, defineAsyncComponent } from 'vue'
|
||||||
import * as i18n from './i18n'
|
import * as i18n from './i18n'
|
||||||
@@ -955,15 +970,14 @@ export default {
|
|||||||
Document,
|
Document,
|
||||||
Fields,
|
Fields,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
MobileDrawField,
|
MobileDrawer,
|
||||||
IconPlus,
|
IconPlus,
|
||||||
|
IconFiles,
|
||||||
IconWritingSign,
|
IconWritingSign,
|
||||||
MobileFields,
|
|
||||||
Logo,
|
Logo,
|
||||||
Dropzone,
|
Dropzone,
|
||||||
HoverDropzone,
|
HoverDropzone,
|
||||||
DocumentPreview,
|
DocumentPreview,
|
||||||
DocumentControls,
|
|
||||||
IconInnerShadowTop,
|
IconInnerShadowTop,
|
||||||
Contenteditable,
|
Contenteditable,
|
||||||
IconUsersPlus,
|
IconUsersPlus,
|
||||||
@@ -1362,6 +1376,8 @@ export default {
|
|||||||
isDragFile: false,
|
isDragFile: false,
|
||||||
isMathLoaded: false,
|
isMathLoaded: false,
|
||||||
isRevisionsModalOpen: false,
|
isRevisionsModalOpen: false,
|
||||||
|
isDocumentsDrawerOpen: false,
|
||||||
|
isFieldsDrawerOpen: false,
|
||||||
editModalDocumentUuid: null,
|
editModalDocumentUuid: null,
|
||||||
revisions: [],
|
revisions: [],
|
||||||
beforeRevisionSnapshot: null,
|
beforeRevisionSnapshot: null,
|
||||||
@@ -1407,12 +1423,16 @@ export default {
|
|||||||
return this.selectedAreasRef.value[this.selectedAreasRef.value.length - 1]
|
return this.selectedAreasRef.value[this.selectedAreasRef.value.length - 1]
|
||||||
},
|
},
|
||||||
fieldNames: FieldType.computed.fieldNames,
|
fieldNames: FieldType.computed.fieldNames,
|
||||||
|
fieldIcons: FieldType.computed.fieldIcons,
|
||||||
isDocumentsView () {
|
isDocumentsView () {
|
||||||
return this.view === 'documents'
|
return this.view === 'documents'
|
||||||
},
|
},
|
||||||
isFieldsView () {
|
isFieldsView () {
|
||||||
return this.view === 'fields'
|
return this.view === 'fields'
|
||||||
},
|
},
|
||||||
|
withMobileDrawers () {
|
||||||
|
return !this.nativePlatform && !this.isNativeView && this.sortedDocuments.length > 0
|
||||||
|
},
|
||||||
isRevisionsView () {
|
isRevisionsView () {
|
||||||
return this.view === 'revisions'
|
return this.view === 'revisions'
|
||||||
},
|
},
|
||||||
@@ -2406,10 +2426,40 @@ export default {
|
|||||||
postNativeEvent (name, detail, dismiss = false) {
|
postNativeEvent (name, detail, dismiss = false) {
|
||||||
window.webkit?.messageHandlers?.modal?.postMessage({ action: 'dispatch', name, detail: JSON.stringify(detail), dismiss: dismiss ? 'true' : 'false' })
|
window.webkit?.messageHandlers?.modal?.postMessage({ action: 'dispatch', name, detail: JSON.stringify(detail), dismiss: dismiss ? 'true' : 'false' })
|
||||||
},
|
},
|
||||||
|
onDrawerScrollTo (item) {
|
||||||
|
if (this.isNativeView) {
|
||||||
|
this.postNativeEvent('template-builder:scroll-to', { attachment_uuid: item.attachment_uuid }, true)
|
||||||
|
} else {
|
||||||
|
this.isDocumentsDrawerOpen = false
|
||||||
|
this.scrollIntoDocument(item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDrawerSetDraw ({ field, option }) {
|
||||||
|
if (this.isNativeView) {
|
||||||
|
this.postNativeEvent('template-builder:draw-field', { uuid: field.uuid, option }, true)
|
||||||
|
} else {
|
||||||
|
this.isFieldsDrawerOpen = false
|
||||||
|
this.drawField = field
|
||||||
|
this.drawOption = option
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDrawerSetDrawType (type) {
|
||||||
|
if (this.isNativeView) {
|
||||||
|
this.postNativeEvent('template-builder:draw-field', { type }, true)
|
||||||
|
} else {
|
||||||
|
this.isFieldsDrawerOpen = false
|
||||||
|
this.startFieldDraw({ type })
|
||||||
|
}
|
||||||
|
},
|
||||||
onDrawerScrollToArea (area) {
|
onDrawerScrollToArea (area) {
|
||||||
const field = this.template.fields.find((f) => (f.areas || []).includes(area))
|
if (this.isNativeView) {
|
||||||
|
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)
|
this.postNativeEvent('template-builder:select-field', { uuid: field?.uuid, attachment_uuid: area.attachment_uuid, page: area.page, x: area.x, y: area.y }, true)
|
||||||
|
} else {
|
||||||
|
this.isFieldsDrawerOpen = false
|
||||||
|
this.scrollToArea(area)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
syncNative () {
|
syncNative () {
|
||||||
const { schema, documents, fields, submitters } = this.template
|
const { schema, documents, fields, submitters } = this.template
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="flex space-x-2">
|
|
||||||
<Contenteditable
|
|
||||||
class="w-full block mr-6 document-preview-name"
|
|
||||||
:model-value="item.name"
|
|
||||||
:icon-width="16"
|
|
||||||
@update:model-value="onUpdateName"
|
|
||||||
/>
|
|
||||||
<ReplaceButton
|
|
||||||
v-if="withReplaceButton"
|
|
||||||
:template-id="template.id"
|
|
||||||
:accept-file-types="acceptFileTypes"
|
|
||||||
:authenticity-token="authenticityToken"
|
|
||||||
:with-google-drive="withGoogleDrive"
|
|
||||||
:google-drive-file-id="item.google_drive_file_id"
|
|
||||||
@click.stop
|
|
||||||
@success="$emit('replace', { replaceSchemaItem: item, ...$event })"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
v-if="withArrows"
|
|
||||||
class="btn border-base-200 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"
|
|
||||||
style="width: 24px; height: 24px"
|
|
||||||
@click.stop="$emit('up', item)"
|
|
||||||
>
|
|
||||||
↑
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
v-if="withArrows"
|
|
||||||
class="btn border-base-200 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"
|
|
||||||
style="width: 24px; height: 24px"
|
|
||||||
@click.stop="$emit('down', item)"
|
|
||||||
>
|
|
||||||
↓
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn border-base-200 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"
|
|
||||||
style="width: 24px; height: 24px"
|
|
||||||
@click.stop="$emit('remove', item)"
|
|
||||||
>
|
|
||||||
×
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Contenteditable from './contenteditable'
|
|
||||||
import Upload from './upload'
|
|
||||||
import ReplaceButton from './replace'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'DocumentControls',
|
|
||||||
components: {
|
|
||||||
Contenteditable,
|
|
||||||
ReplaceButton
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
item: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
template: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
document: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
acceptFileTypes: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: 'image/*, application/pdf, application/zip, application/json'
|
|
||||||
},
|
|
||||||
withReplaceButton: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
withGoogleDrive: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
authenticityToken: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
withArrows: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['change', 'remove', 'up', 'down', 'replace'],
|
|
||||||
methods: {
|
|
||||||
upload: Upload.methods.upload,
|
|
||||||
onUpdateName (value) {
|
|
||||||
this.item.name = value
|
|
||||||
|
|
||||||
this.$emit('change')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-1 min-h-0">
|
<div class="flex flex-col md:flex-row flex-1 min-h-0">
|
||||||
<div
|
<div
|
||||||
class="flex-1 min-h-0 flex items-center justify-center px-6 py-4"
|
class="flex-1 min-h-0 flex items-center justify-center px-4 md:px-6 py-4"
|
||||||
style="container-type: size"
|
style="container-type: size"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -46,73 +46,75 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-56 flex-none border-l px-4 py-4 space-y-2 flex flex-col">
|
<div class="flex-none px-4 border-t py-3 md:w-56 md:border-t-0 md:border-l md:py-4 md:space-y-2 md:flex md:flex-col">
|
||||||
<button
|
<div class="grid grid-cols-3 gap-2 md:block md:space-y-2">
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
<button
|
||||||
:disabled="!!isProcessing"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
@click.prevent="submit(true)"
|
:disabled="!!isProcessing"
|
||||||
>
|
@click.prevent="submit(true)"
|
||||||
<IconInnerShadowTop
|
>
|
||||||
v-if="isProcessing === 'scan'"
|
<IconInnerShadowTop
|
||||||
class="w-4 h-4 animate-spin"
|
v-if="isProcessing === 'scan'"
|
||||||
/>
|
class="w-4 h-4 animate-spin"
|
||||||
<IconScan
|
/>
|
||||||
v-else
|
<IconScan
|
||||||
class="w-4 h-4"
|
v-else
|
||||||
/>
|
class="w-4 h-4"
|
||||||
{{ t('crop_and_scan') }}
|
/>
|
||||||
</button>
|
{{ t('crop_and_scan') }}
|
||||||
<button
|
</button>
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
<button
|
||||||
:disabled="!!isProcessing"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
@click.prevent="submit(false)"
|
:disabled="!!isProcessing"
|
||||||
>
|
@click.prevent="submit(false)"
|
||||||
<IconInnerShadowTop
|
>
|
||||||
v-if="isProcessing === 'crop'"
|
<IconInnerShadowTop
|
||||||
class="w-4 h-4 animate-spin"
|
v-if="isProcessing === 'crop'"
|
||||||
/>
|
class="w-4 h-4 animate-spin"
|
||||||
<IconCrop
|
/>
|
||||||
v-else
|
<IconCrop
|
||||||
width="22"
|
v-else
|
||||||
height="22"
|
width="22"
|
||||||
style="margin-left: -3px"
|
height="22"
|
||||||
:stroke-width="1.5"
|
style="margin-left: -3px"
|
||||||
/>
|
:stroke-width="1.5"
|
||||||
<span :style="{ 'margin-left': isProcessing === 'crop' ? '0px' : '-3px' }">
|
/>
|
||||||
{{ t('crop') }}
|
<span :style="{ 'margin-left': isProcessing === 'crop' ? '0px' : '-3px' }">
|
||||||
</span>
|
{{ t('crop') }}
|
||||||
</button>
|
</span>
|
||||||
<button
|
</button>
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded"
|
<button
|
||||||
@click.prevent="$emit('cancel')"
|
class="btn btn-sm normal-case font-normal rounded flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
>
|
@click.prevent="$emit('cancel')"
|
||||||
<IconX class="w-4 h-4" />
|
>
|
||||||
{{ t('cancel') }}
|
<IconX class="w-4 h-4" />
|
||||||
</button>
|
{{ t('cancel') }}
|
||||||
<div class="border-t !mt-3 !mb-1" />
|
</button>
|
||||||
<button
|
<div class="hidden md:block border-t !mt-3 !mb-1" />
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded"
|
<button
|
||||||
@click.prevent="rotateCw"
|
class="btn btn-sm normal-case font-normal rounded flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
>
|
@click.prevent="rotateCw"
|
||||||
<IconRotateClockwise class="w-4 h-4" />
|
>
|
||||||
{{ t('rotate') }}
|
<IconRotateClockwise class="w-4 h-4" />
|
||||||
</button>
|
{{ t('rotate') }}
|
||||||
<button
|
</button>
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded"
|
<button
|
||||||
:class="{ 'btn-active': flipH }"
|
class="btn btn-sm normal-case font-normal rounded flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
@click.prevent="toggleFlip('flipH')"
|
:class="{ 'btn-active': flipH }"
|
||||||
>
|
@click.prevent="toggleFlip('flipH')"
|
||||||
<IconFlipVertical class="w-4 h-4" />
|
>
|
||||||
{{ t('flip_horizontal') }}
|
<IconFlipVertical class="w-4 h-4" />
|
||||||
</button>
|
{{ t('flip_horizontal') }}
|
||||||
<button
|
</button>
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded"
|
<button
|
||||||
:class="{ 'btn-active': flipV }"
|
class="btn btn-sm normal-case font-normal rounded flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
@click.prevent="toggleFlip('flipV')"
|
:class="{ 'btn-active': flipV }"
|
||||||
>
|
@click.prevent="toggleFlip('flipV')"
|
||||||
<IconFlipHorizontal class="w-4 h-4" />
|
>
|
||||||
{{ t('flip_vertical') }}
|
<IconFlipHorizontal class="w-4 h-4" />
|
||||||
</button>
|
{{ t('flip_vertical') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
class="modal-box relative flex flex-col p-0 w-full h-full rounded-2xl"
|
class="modal-box relative flex flex-col p-0 w-full h-full rounded-none md:rounded-2xl overflow-x-hidden !max-h-full md:!max-h-[92vh]"
|
||||||
style="max-width: 1240px; max-height: 92vh"
|
style="max-width: 1240px"
|
||||||
>
|
>
|
||||||
<div class="flex justify-between items-center border-b py-2 px-6 font-medium">
|
<div class="flex justify-between items-center border-b py-2 px-6 font-medium">
|
||||||
<span
|
<span
|
||||||
@@ -26,7 +26,9 @@
|
|||||||
@click.prevent="$emit('close')"
|
@click.prevent="$emit('close')"
|
||||||
>×</a>
|
>×</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 min-h-0 relative">
|
<div
|
||||||
|
class="flex flex-col md:flex-row flex-1 min-h-0 relative"
|
||||||
|
>
|
||||||
<CropView
|
<CropView
|
||||||
v-if="cropPageItem"
|
v-if="cropPageItem"
|
||||||
class="absolute inset-0 z-10 bg-base-100"
|
class="absolute inset-0 z-10 bg-base-100"
|
||||||
@@ -53,7 +55,9 @@
|
|||||||
class="contents"
|
class="contents"
|
||||||
:class="{ invisible: cropPageItem || redactPageItem }"
|
:class="{ invisible: cropPageItem || redactPageItem }"
|
||||||
>
|
>
|
||||||
<div class="flex-1 overflow-y-auto px-6 py-4 space-y-4">
|
<div
|
||||||
|
class="flex-1 overflow-y-auto overflow-x-hidden px-4 md:px-6 py-4 space-y-4"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(doc, docIndex) in layout"
|
v-for="(doc, docIndex) in layout"
|
||||||
:key="doc.attachmentUuid"
|
:key="doc.attachmentUuid"
|
||||||
@@ -170,7 +174,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="(!collapsedDocumentsIndex[doc.attachmentUuid] || layout.length === 1) && doc.pages.length"
|
v-if="(!collapsedDocumentsIndex[doc.attachmentUuid] || layout.length === 1) && doc.pages.length"
|
||||||
class="grid grid-cols-4 gap-3"
|
class="grid grid-cols-2 md:grid-cols-4 gap-3"
|
||||||
@dragover.prevent="onGridDragover(docIndex, $event)"
|
@dragover.prevent="onGridDragover(docIndex, $event)"
|
||||||
@drop.prevent="onPageDrop"
|
@drop.prevent="onPageDrop"
|
||||||
>
|
>
|
||||||
@@ -178,7 +182,7 @@
|
|||||||
v-for="(page, pageIndex) in doc.pages"
|
v-for="(page, pageIndex) in doc.pages"
|
||||||
:key="page.id"
|
:key="page.id"
|
||||||
:data-page-id="page.id"
|
:data-page-id="page.id"
|
||||||
class="relative cursor-pointer group"
|
class="relative min-w-0 cursor-pointer group"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
@click="selectedPageId = page.id"
|
@click="selectedPageId = page.id"
|
||||||
@mousedown="onPageMousedown(page, $event)"
|
@mousedown="onPageMousedown(page, $event)"
|
||||||
@@ -245,26 +249,30 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-56 flex-none border-l px-4 py-4 flex flex-col">
|
<div
|
||||||
<div class="space-y-2">
|
class="flex-none px-4 border-t py-3 flex flex-col gap-3 md:w-56 md:border-t-0 md:border-l md:py-4 md:gap-0"
|
||||||
|
>
|
||||||
|
<div class="grid grid-cols-4 gap-2 md:block md:space-y-2">
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
:disabled="!selectedPageId"
|
:disabled="!selectedPageId"
|
||||||
@click.prevent="movePage(-1)"
|
@click.prevent="movePage(-1)"
|
||||||
>
|
>
|
||||||
<IconArrowBackUp class="w-4 h-4" />
|
<IconArrowBackUp class="w-4 h-4" />
|
||||||
{{ t('move_backward') }}
|
<span class="md:hidden">{{ t('backward') }}</span>
|
||||||
|
<span class="hidden md:inline">{{ t('move_backward') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
:disabled="!selectedPageId"
|
:disabled="!selectedPageId"
|
||||||
@click.prevent="movePage(1)"
|
@click.prevent="movePage(1)"
|
||||||
>
|
>
|
||||||
<IconArrowForwardUp class="w-4 h-4" />
|
<IconArrowForwardUp class="w-4 h-4" />
|
||||||
{{ t('move_forward') }}
|
<span class="md:hidden">{{ t('forward') }}</span>
|
||||||
|
<span class="hidden md:inline">{{ t('move_forward') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
:disabled="!selectedPageId"
|
:disabled="!selectedPageId"
|
||||||
@click.prevent="rotatePage"
|
@click.prevent="rotatePage"
|
||||||
>
|
>
|
||||||
@@ -272,7 +280,7 @@
|
|||||||
{{ t('rotate') }}
|
{{ t('rotate') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
:disabled="!selectedPageId || isReplacing"
|
:disabled="!selectedPageId || isReplacing"
|
||||||
@click.prevent="replaceSelected"
|
@click.prevent="replaceSelected"
|
||||||
>
|
>
|
||||||
@@ -303,7 +311,7 @@
|
|||||||
@change="onReplaceDocFilesPicked"
|
@change="onReplaceDocFilesPicked"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
:disabled="!selectedPageId"
|
:disabled="!selectedPageId"
|
||||||
@click.prevent="openRedactView"
|
@click.prevent="openRedactView"
|
||||||
>
|
>
|
||||||
@@ -312,7 +320,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="isSelectedPageCroppable"
|
v-if="isSelectedPageCroppable"
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
@click.prevent="openCropView"
|
@click.prevent="openCropView"
|
||||||
>
|
>
|
||||||
<IconCrop
|
<IconCrop
|
||||||
@@ -326,15 +334,16 @@
|
|||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300 text-red-600"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 text-red-600 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
:disabled="!selectedPageId"
|
:disabled="!selectedPageId"
|
||||||
@click.prevent="removePage"
|
@click.prevent="removePage"
|
||||||
>
|
>
|
||||||
<IconTrashX class="w-4 h-4" />
|
<IconTrashX class="w-4 h-4" />
|
||||||
{{ t('remove_page') }}
|
<span class="md:hidden">{{ t('remove') }}</span>
|
||||||
|
<span class="hidden md:inline">{{ t('remove_page') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-auto space-y-2">
|
<div class="grid grid-cols-2 gap-2 md:block md:mt-auto md:space-y-2">
|
||||||
<Upload
|
<Upload
|
||||||
:template-id="template.id"
|
:template-id="template.id"
|
||||||
:accept-file-types="acceptFileTypes"
|
:accept-file-types="acceptFileTypes"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-1 min-h-0">
|
<div class="flex flex-col md:flex-row flex-1 min-h-0">
|
||||||
<div class="flex-1 overflow-y-auto px-6 py-4">
|
<div class="flex-1 overflow-y-auto overflow-x-hidden px-4 md:px-6 py-4">
|
||||||
<div
|
<div
|
||||||
ref="pageEl"
|
ref="pageEl"
|
||||||
class="relative mx-auto select-none cursor-crosshair"
|
class="relative mx-auto select-none cursor-crosshair"
|
||||||
@@ -48,8 +48,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-56 flex-none border-l px-4 py-4 space-y-2">
|
<div class="flex-none px-4 border-t py-3 md:w-56 md:border-t-0 md:border-l md:py-4 md:space-y-2">
|
||||||
<div class="flex items-center justify-between mb-1">
|
<div class="flex items-center justify-between mb-3 md:mb-1">
|
||||||
<span class="text-sm pl-1">{{ t('color') }}</span>
|
<span class="text-sm pl-1">{{ t('color') }}</span>
|
||||||
<div
|
<div
|
||||||
class="join rounded"
|
class="join rounded"
|
||||||
@@ -69,30 +69,32 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<div class="grid grid-cols-3 gap-2 md:block md:space-y-2">
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
<button
|
||||||
:disabled="!hasRedactions && !wasReset"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
@click.prevent="apply"
|
:disabled="!hasRedactions && !wasReset"
|
||||||
>
|
@click.prevent="apply"
|
||||||
<IconCheck class="w-4 h-4" />
|
>
|
||||||
{{ t('apply') }}
|
<IconCheck class="w-4 h-4" />
|
||||||
</button>
|
{{ t('apply') }}
|
||||||
<div class="border-t !mt-3 !mb-1" />
|
</button>
|
||||||
<button
|
<div class="hidden md:block border-t !mt-3 !mb-1" />
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded disabled:bg-base-300"
|
<button
|
||||||
:disabled="!hasRedactions"
|
class="btn btn-sm normal-case font-normal rounded disabled:bg-base-300 flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
@click.prevent="reset"
|
:disabled="!hasRedactions"
|
||||||
>
|
@click.prevent="reset"
|
||||||
<IconRotate class="w-4 h-4" />
|
>
|
||||||
{{ t('reset') }}
|
<IconRotate class="w-4 h-4" />
|
||||||
</button>
|
{{ t('reset') }}
|
||||||
<button
|
</button>
|
||||||
class="btn btn-sm w-full justify-start normal-case font-normal rounded"
|
<button
|
||||||
@click.prevent="$emit('cancel')"
|
class="btn btn-sm normal-case font-normal rounded flex-col gap-1 h-auto min-h-0 py-2 px-1 text-xs leading-tight whitespace-normal md:flex-row md:gap-2 md:h-8 md:min-h-[2rem] md:py-0 md:px-3 md:text-sm md:whitespace-nowrap md:w-full md:justify-start"
|
||||||
>
|
@click.prevent="$emit('cancel')"
|
||||||
<IconX class="w-4 h-4" />
|
>
|
||||||
{{ t('cancel') }}
|
<IconX class="w-4 h-4" />
|
||||||
</button>
|
{{ t('cancel') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
:style="dragPlaceholderStyle"
|
:style="dragPlaceholderStyle"
|
||||||
:field="field"
|
:field="field"
|
||||||
:with-options="false"
|
:with-options="false"
|
||||||
class="fixed z-20 pointer-events-none"
|
class="fixed z-50 pointer-events-none"
|
||||||
:editable="false"
|
:editable="false"
|
||||||
/>
|
/>
|
||||||
<CustomField
|
<CustomField
|
||||||
@@ -13,13 +13,13 @@
|
|||||||
ref="dragPlaceholder"
|
ref="dragPlaceholder"
|
||||||
:style="dragPlaceholderStyle"
|
:style="dragPlaceholderStyle"
|
||||||
:field="field"
|
:field="field"
|
||||||
class="fixed z-20 pointer-events-none opacity-90"
|
class="fixed z-50 pointer-events-none opacity-90"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-else-if="dragPlaceholder && (isDefault || isRequired) && !isMask && field"
|
v-else-if="dragPlaceholder && (isDefault || isRequired) && !isMask && field"
|
||||||
ref="dragPlaceholder"
|
ref="dragPlaceholder"
|
||||||
:style="[dragPlaceholderStyle, { backgroundColor: backgroundColor }]"
|
:style="[dragPlaceholderStyle, { backgroundColor: backgroundColor }]"
|
||||||
class="fixed z-20 border border-base-300 rounded group default-field fields-list-item pointer-events-none"
|
class="fixed z-50 border border-base-300 rounded group default-field fields-list-item pointer-events-none"
|
||||||
>
|
>
|
||||||
<div class="flex items-center justify-between relative cursor-grab">
|
<div class="flex items-center justify-between relative cursor-grab">
|
||||||
<div class="flex items-center p-1 space-x-1">
|
<div class="flex items-center p-1 space-x-1">
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
<button
|
<button
|
||||||
v-else-if="dragPlaceholder && !isMask && field"
|
v-else-if="dragPlaceholder && !isMask && field"
|
||||||
ref="dragPlaceholder"
|
ref="dragPlaceholder"
|
||||||
class="fixed field-type-button z-20 flex items-center justify-center border border-dashed w-full rounded border-base-content/20 opacity-90 pointer-events-none"
|
class="fixed field-type-button z-50 flex items-center justify-center border border-dashed w-full rounded border-base-content/20 opacity-90 pointer-events-none"
|
||||||
:style="[dragPlaceholderStyle, { backgroundColor }]"
|
:style="[dragPlaceholderStyle, { backgroundColor }]"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -114,6 +114,12 @@
|
|||||||
:title="t('settings')"
|
:title="t('settings')"
|
||||||
class="cursor-pointer flex items-center"
|
class="cursor-pointer flex items-center"
|
||||||
:class="[iconColorClass, { 'pr-1': isMobile }]"
|
:class="[iconColorClass, { 'pr-1': isMobile }]"
|
||||||
|
@touchstart="onHandleTouchstart"
|
||||||
|
@touchmove="onHandleTouchmove"
|
||||||
|
@touchend="onHandleTouchend"
|
||||||
|
@touchcancel="onHandleTouchend"
|
||||||
|
@mousedown="dropdownWasOpen = $event.currentTarget.parentElement.contains($event.currentTarget.getRootNode().activeElement)"
|
||||||
|
@click="dropdownWasOpen && closeDropdown()"
|
||||||
>
|
>
|
||||||
<IconDotsVertical
|
<IconDotsVertical
|
||||||
v-if="isMobile"
|
v-if="isMobile"
|
||||||
@@ -417,9 +423,11 @@ export default {
|
|||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['set-draw', 'remove', 'scroll-to', 'save', 'add-custom-field'],
|
emits: ['set-draw', 'remove', 'scroll-to', 'save', 'add-custom-field', 'touch-drag', 'touch-drag-end'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
touchDrag: null,
|
||||||
|
dropdownWasOpen: false,
|
||||||
isExpandOptions: false,
|
isExpandOptions: false,
|
||||||
isNameFocus: false,
|
isNameFocus: false,
|
||||||
isShowFormulaModal: false,
|
isShowFormulaModal: false,
|
||||||
@@ -471,6 +479,37 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
onHandleTouchstart (e) {
|
||||||
|
if (!this.isMobile) return
|
||||||
|
|
||||||
|
this.touchDrag = { startY: e.touches[0].clientY, moved: false }
|
||||||
|
},
|
||||||
|
onHandleTouchmove (e) {
|
||||||
|
if (!this.touchDrag) return
|
||||||
|
|
||||||
|
const { clientX, clientY } = e.touches[0]
|
||||||
|
|
||||||
|
if (!this.touchDrag.moved && Math.abs(clientY - this.touchDrag.startY) < 6) return
|
||||||
|
|
||||||
|
this.touchDrag.moved = true
|
||||||
|
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
this.$emit('touch-drag', { field: this.field, x: clientX, y: clientY })
|
||||||
|
},
|
||||||
|
onHandleTouchend (e) {
|
||||||
|
if (!this.touchDrag) return
|
||||||
|
|
||||||
|
if (this.touchDrag.moved) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
e.currentTarget.blur()
|
||||||
|
|
||||||
|
this.$emit('touch-drag-end')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.touchDrag = null
|
||||||
|
},
|
||||||
removeArea (area) {
|
removeArea (area) {
|
||||||
this.field.areas.splice(this.field.areas.indexOf(area), 1)
|
this.field.areas.splice(this.field.areas.indexOf(area), 1)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
:class="withStickySubmitters ? 'sticky top-0 z-[1]' : ''"
|
:class="{ 'sticky top-0 z-[1]': withStickySubmitters, 'bg-base-100': withStickySubmitters && ['', null, 'transparent'].includes(backgroundColor), 'pt-3': withTopPadding }"
|
||||||
:style="withStickySubmitters ? { backgroundColor } : {}"
|
:style="withStickySubmitters ? { backgroundColor } : {}"
|
||||||
class="flex items-center gap-1"
|
class="flex items-center gap-1"
|
||||||
>
|
>
|
||||||
@@ -64,6 +64,8 @@
|
|||||||
@remove="removeField"
|
@remove="removeField"
|
||||||
@scroll-to="$emit('scroll-to-area', $event)"
|
@scroll-to="$emit('scroll-to-area', $event)"
|
||||||
@set-draw="$emit('set-draw', $event)"
|
@set-draw="$emit('set-draw', $event)"
|
||||||
|
@touch-drag="onTouchDrag"
|
||||||
|
@touch-drag-end="onTouchDragEnd"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@@ -356,24 +358,16 @@
|
|||||||
width="22"
|
width="22"
|
||||||
class="animate-spin"
|
class="animate-spin"
|
||||||
/>
|
/>
|
||||||
<span
|
<span v-if="analyzingProgress">
|
||||||
v-if="analyzingProgress"
|
|
||||||
class="hidden md:inline"
|
|
||||||
>
|
|
||||||
{{ Math.round(analyzingProgress * 100) }}% {{ t('analyzing_') }}
|
{{ Math.round(analyzingProgress * 100) }}% {{ t('analyzing_') }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span v-else>
|
||||||
v-else
|
|
||||||
class="hidden md:inline"
|
|
||||||
>
|
|
||||||
{{ fieldPagesLoaded }} / {{ numberOfPages }} {{ t('processing_') }}
|
{{ fieldPagesLoaded }} / {{ numberOfPages }} {{ t('processing_') }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<IconSparkles width="22" />
|
<IconSparkles width="22" />
|
||||||
<span
|
<span>
|
||||||
class="hidden md:inline"
|
|
||||||
>
|
|
||||||
{{ t('autodetect_fields') }}
|
{{ t('autodetect_fields') }}
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -518,6 +512,11 @@ export default {
|
|||||||
required: false,
|
required: false,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
withTopPadding: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
fieldTypes: {
|
fieldTypes: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
@@ -829,6 +828,8 @@ export default {
|
|||||||
|
|
||||||
this.save()
|
this.save()
|
||||||
|
|
||||||
|
window.webkit?.messageHandlers?.flash?.postMessage({ style: 'notice', message: this.t('fields_detected').replace('{count}', (data.fields || fields).length) })
|
||||||
|
|
||||||
break
|
break
|
||||||
} else if (data.fields) {
|
} else if (data.fields) {
|
||||||
data.fields.forEach((f) => {
|
data.fields.forEach((f) => {
|
||||||
@@ -884,19 +885,58 @@ export default {
|
|||||||
},
|
},
|
||||||
onFieldDragover (e) {
|
onFieldDragover (e) {
|
||||||
if (this.fieldsDragFieldRef.value) {
|
if (this.fieldsDragFieldRef.value) {
|
||||||
const targetField = e.target.closest('[data-uuid]')
|
this.moveFieldElement(this.fieldsDragFieldRef.value, e.target.closest('[data-uuid]'))
|
||||||
const dragField = this.$refs.fields.querySelector(`[data-uuid="${this.fieldsDragFieldRef.value.uuid}"]`)
|
}
|
||||||
|
},
|
||||||
|
onTouchDrag ({ field, x, y }) {
|
||||||
|
const dragField = this.$refs.fields.querySelector(`[data-uuid="${field.uuid}"]`)
|
||||||
|
|
||||||
if (dragField && targetField && targetField !== dragField) {
|
if (!dragField) return
|
||||||
const fields = Array.from(this.$refs.fields.children)
|
|
||||||
const currentIndex = fields.indexOf(dragField)
|
|
||||||
const targetIndex = fields.indexOf(targetField)
|
|
||||||
|
|
||||||
if (currentIndex < targetIndex) {
|
if (!this.touchPreview) {
|
||||||
targetField.after(dragField)
|
const rect = dragField.getBoundingClientRect()
|
||||||
} else {
|
const el = dragField.cloneNode(true)
|
||||||
targetField.before(dragField)
|
const root = this.$el.getRootNode()
|
||||||
}
|
|
||||||
|
Object.assign(el.style, { position: 'fixed', left: `${rect.left}px`, top: `${rect.top}px`, width: `${rect.width}px`, margin: 0, zIndex: 50, pointerEvents: 'none', opacity: 0.9 })
|
||||||
|
|
||||||
|
;(root === document ? document.body : root).appendChild(el)
|
||||||
|
|
||||||
|
dragField.style.opacity = 0.4
|
||||||
|
|
||||||
|
this.touchPreview = { el, dragField, offsetY: y - rect.top }
|
||||||
|
}
|
||||||
|
|
||||||
|
this.touchPreview.el.style.top = `${y - this.touchPreview.offsetY}px`
|
||||||
|
|
||||||
|
const root = this.$el.getRootNode()
|
||||||
|
const targetField = (root.elementFromPoint ? root : document).elementFromPoint(x, y)?.closest('[data-uuid]')
|
||||||
|
|
||||||
|
if (targetField && this.$refs.fields.contains(targetField)) {
|
||||||
|
this.moveFieldElement(field, targetField)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTouchDragEnd () {
|
||||||
|
if (this.touchPreview) {
|
||||||
|
this.touchPreview.el.remove()
|
||||||
|
this.touchPreview.dragField.style.opacity = ''
|
||||||
|
this.touchPreview = null
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reorderFields()
|
||||||
|
},
|
||||||
|
moveFieldElement (field, targetField) {
|
||||||
|
const dragField = this.$refs.fields.querySelector(`[data-uuid="${field.uuid}"]`)
|
||||||
|
|
||||||
|
if (dragField && targetField && targetField !== dragField) {
|
||||||
|
const fields = Array.from(this.$refs.fields.children)
|
||||||
|
const currentIndex = fields.indexOf(dragField)
|
||||||
|
const targetIndex = fields.indexOf(targetField)
|
||||||
|
|
||||||
|
if (currentIndex < targetIndex) {
|
||||||
|
targetField.after(dragField)
|
||||||
|
} else {
|
||||||
|
targetField.before(dragField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const en = {
|
|||||||
downloading_: 'Downloading...',
|
downloading_: 'Downloading...',
|
||||||
view: 'View',
|
view: 'View',
|
||||||
autodetect_fields: 'Autodetect Fields',
|
autodetect_fields: 'Autodetect Fields',
|
||||||
|
fields_detected: '{count} fields detected',
|
||||||
payment_link: 'Payment link',
|
payment_link: 'Payment link',
|
||||||
strikeout: 'Strikeout',
|
strikeout: 'Strikeout',
|
||||||
draw_strikethrough_the_document: 'Draw strikethrough the document',
|
draw_strikethrough_the_document: 'Draw strikethrough the document',
|
||||||
@@ -101,6 +102,8 @@ const en = {
|
|||||||
documents: 'Documents',
|
documents: 'Documents',
|
||||||
move_forward: 'Move forward',
|
move_forward: 'Move forward',
|
||||||
move_backward: 'Move backward',
|
move_backward: 'Move backward',
|
||||||
|
backward: 'Backward',
|
||||||
|
forward: 'Forward',
|
||||||
remove_page: 'Remove page',
|
remove_page: 'Remove page',
|
||||||
merge_with_previous: 'Merge with previous',
|
merge_with_previous: 'Merge with previous',
|
||||||
merge_with_next: 'Merge with next',
|
merge_with_next: 'Merge with next',
|
||||||
@@ -251,6 +254,7 @@ const es = {
|
|||||||
save_as_custom_field: 'Guardar como personalizado',
|
save_as_custom_field: 'Guardar como personalizado',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Autodetectar campos',
|
autodetect_fields: 'Autodetectar campos',
|
||||||
|
fields_detected: '{count} campos detectados',
|
||||||
analyzing_: 'Analizando...',
|
analyzing_: 'Analizando...',
|
||||||
download: 'Descargar',
|
download: 'Descargar',
|
||||||
downloading_: 'Descargando...',
|
downloading_: 'Descargando...',
|
||||||
@@ -344,6 +348,8 @@ const es = {
|
|||||||
documents: 'Documentos',
|
documents: 'Documentos',
|
||||||
move_forward: 'Mover adelante',
|
move_forward: 'Mover adelante',
|
||||||
move_backward: 'Mover atrás',
|
move_backward: 'Mover atrás',
|
||||||
|
backward: 'Atrás',
|
||||||
|
forward: 'Adelante',
|
||||||
remove_page: 'Eliminar página',
|
remove_page: 'Eliminar página',
|
||||||
merge_with_previous: 'Combinar con el anterior',
|
merge_with_previous: 'Combinar con el anterior',
|
||||||
merge_with_next: 'Combinar con el siguiente',
|
merge_with_next: 'Combinar con el siguiente',
|
||||||
@@ -497,6 +503,7 @@ const it = {
|
|||||||
save_as_custom_field: 'Salva come personalizzato',
|
save_as_custom_field: 'Salva come personalizzato',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Rileva campi',
|
autodetect_fields: 'Rileva campi',
|
||||||
|
fields_detected: '{count} campi rilevati',
|
||||||
analyzing_: 'Analisi...',
|
analyzing_: 'Analisi...',
|
||||||
download: 'Scarica',
|
download: 'Scarica',
|
||||||
downloading_: 'Download in corso...',
|
downloading_: 'Download in corso...',
|
||||||
@@ -593,6 +600,8 @@ const it = {
|
|||||||
documents: 'Documenti',
|
documents: 'Documenti',
|
||||||
move_forward: 'Sposta avanti',
|
move_forward: 'Sposta avanti',
|
||||||
move_backward: 'Sposta indietro',
|
move_backward: 'Sposta indietro',
|
||||||
|
backward: 'Indietro',
|
||||||
|
forward: 'Avanti',
|
||||||
remove_page: 'Rimuovi pagina',
|
remove_page: 'Rimuovi pagina',
|
||||||
merge_with_previous: 'Unisci al precedente',
|
merge_with_previous: 'Unisci al precedente',
|
||||||
merge_with_next: 'Unisci al successivo',
|
merge_with_next: 'Unisci al successivo',
|
||||||
@@ -743,6 +752,7 @@ const pt = {
|
|||||||
save_as_custom_field: 'Salvar como personalizado',
|
save_as_custom_field: 'Salvar como personalizado',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Detectar campos',
|
autodetect_fields: 'Detectar campos',
|
||||||
|
fields_detected: '{count} campos detectados',
|
||||||
analyzing_: 'Analisando...',
|
analyzing_: 'Analisando...',
|
||||||
download: 'Baixar',
|
download: 'Baixar',
|
||||||
downloading_: 'Baixando...',
|
downloading_: 'Baixando...',
|
||||||
@@ -836,6 +846,8 @@ const pt = {
|
|||||||
documents: 'Documentos',
|
documents: 'Documentos',
|
||||||
move_forward: 'Mover para frente',
|
move_forward: 'Mover para frente',
|
||||||
move_backward: 'Mover para trás',
|
move_backward: 'Mover para trás',
|
||||||
|
backward: 'Para trás',
|
||||||
|
forward: 'Para frente',
|
||||||
remove_page: 'Remover página',
|
remove_page: 'Remover página',
|
||||||
merge_with_previous: 'Mesclar com o anterior',
|
merge_with_previous: 'Mesclar com o anterior',
|
||||||
merge_with_next: 'Mesclar com o próximo',
|
merge_with_next: 'Mesclar com o próximo',
|
||||||
@@ -989,6 +1001,7 @@ const fr = {
|
|||||||
save_as_custom_field: 'Enregistrer comme personnalisé',
|
save_as_custom_field: 'Enregistrer comme personnalisé',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Détecter les champs',
|
autodetect_fields: 'Détecter les champs',
|
||||||
|
fields_detected: '{count} champs détectés',
|
||||||
analyzing_: 'Analyse...',
|
analyzing_: 'Analyse...',
|
||||||
download: 'Télécharger',
|
download: 'Télécharger',
|
||||||
downloading_: 'Téléchargement...',
|
downloading_: 'Téléchargement...',
|
||||||
@@ -1085,6 +1098,8 @@ const fr = {
|
|||||||
documents: 'Documents',
|
documents: 'Documents',
|
||||||
move_forward: 'Déplacer en avant',
|
move_forward: 'Déplacer en avant',
|
||||||
move_backward: 'Déplacer en arrière',
|
move_backward: 'Déplacer en arrière',
|
||||||
|
backward: 'Reculer',
|
||||||
|
forward: 'Avancer',
|
||||||
remove_page: 'Supprimer la page',
|
remove_page: 'Supprimer la page',
|
||||||
merge_with_previous: 'Fusionner avec le précédent',
|
merge_with_previous: 'Fusionner avec le précédent',
|
||||||
merge_with_next: 'Fusionner avec le suivant',
|
merge_with_next: 'Fusionner avec le suivant',
|
||||||
@@ -1235,6 +1250,7 @@ const de = {
|
|||||||
save_as_custom_field: 'Als benutzerdefiniert speichern',
|
save_as_custom_field: 'Als benutzerdefiniert speichern',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Felder erkennen',
|
autodetect_fields: 'Felder erkennen',
|
||||||
|
fields_detected: '{count} Felder erkannt',
|
||||||
analyzing_: 'Analysiere...',
|
analyzing_: 'Analysiere...',
|
||||||
download: 'Download',
|
download: 'Download',
|
||||||
downloading_: 'Download...',
|
downloading_: 'Download...',
|
||||||
@@ -1331,6 +1347,8 @@ const de = {
|
|||||||
documents: 'Dokumente',
|
documents: 'Dokumente',
|
||||||
move_forward: 'Nach vorne',
|
move_forward: 'Nach vorne',
|
||||||
move_backward: 'Nach hinten',
|
move_backward: 'Nach hinten',
|
||||||
|
backward: 'Zurück',
|
||||||
|
forward: 'Vorwärts',
|
||||||
remove_page: 'Seite entfernen',
|
remove_page: 'Seite entfernen',
|
||||||
merge_with_previous: 'Mit vorherigem zusammenführen',
|
merge_with_previous: 'Mit vorherigem zusammenführen',
|
||||||
merge_with_next: 'Mit nächstem zusammenführen',
|
merge_with_next: 'Mit nächstem zusammenführen',
|
||||||
@@ -1481,6 +1499,7 @@ const nl = {
|
|||||||
save_as_custom_field: 'Opslaan als aangepast',
|
save_as_custom_field: 'Opslaan als aangepast',
|
||||||
kba: 'KBA',
|
kba: 'KBA',
|
||||||
autodetect_fields: 'Velden detecteren',
|
autodetect_fields: 'Velden detecteren',
|
||||||
|
fields_detected: '{count} velden gedetecteerd',
|
||||||
analyzing_: 'Analyseren...',
|
analyzing_: 'Analyseren...',
|
||||||
download: 'Downloaden',
|
download: 'Downloaden',
|
||||||
downloading_: 'Downloaden...',
|
downloading_: 'Downloaden...',
|
||||||
@@ -1577,6 +1596,8 @@ const nl = {
|
|||||||
documents: 'Documenten',
|
documents: 'Documenten',
|
||||||
move_forward: 'Naar voren',
|
move_forward: 'Naar voren',
|
||||||
move_backward: 'Naar achteren',
|
move_backward: 'Naar achteren',
|
||||||
|
backward: 'Achteruit',
|
||||||
|
forward: 'Vooruit',
|
||||||
remove_page: 'Pagina verwijderen',
|
remove_page: 'Pagina verwijderen',
|
||||||
merge_with_previous: 'Samenvoegen met vorige',
|
merge_with_previous: 'Samenvoegen met vorige',
|
||||||
merge_with_next: 'Samenvoegen met volgende',
|
merge_with_next: 'Samenvoegen met volgende',
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="absolute w-full bottom-0 pr-3 mb-4">
|
|
||||||
<span class="w-full bg-base-200 px-4 py-2 rounded-md inline-flex space-x-2 mx-auto items-center justify-between mb-2 z-20 draw-field-container-mobile">
|
|
||||||
<div class="flex items-center space-x-2">
|
|
||||||
<component
|
|
||||||
:is="fieldIcons[drawField.type]"
|
|
||||||
:width="20"
|
|
||||||
:height="20"
|
|
||||||
class="inline"
|
|
||||||
:stroke-width="1.6"
|
|
||||||
/>
|
|
||||||
<span>{{ t('draw_field').replace('{field}', fieldNames[drawField.type]) }}</span>
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="link block text-center"
|
|
||||||
@click.prevent="$emit('cancel')"
|
|
||||||
>
|
|
||||||
{{ t('cancel') }}
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
<FieldSubmitter
|
|
||||||
:model-value="selectedSubmitter.uuid"
|
|
||||||
:submitters="submitters"
|
|
||||||
:editable="editable"
|
|
||||||
:mobile-view="true"
|
|
||||||
:menu-style="{ backgroundColor: ['', null, 'transparent'].includes(backgroundColor) ? 'white' : backgroundColor }"
|
|
||||||
@new-submitter="save"
|
|
||||||
@remove="removeSubmitter"
|
|
||||||
@name-change="save"
|
|
||||||
@update:model-value="$emit('change-submitter', submitters.find((s) => s.uuid === $event))"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import Field from './field'
|
|
||||||
import FieldType from './field_type'
|
|
||||||
import FieldSubmitter from './field_submitter'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'MobileDrawField',
|
|
||||||
components: {
|
|
||||||
Field,
|
|
||||||
FieldSubmitter
|
|
||||||
},
|
|
||||||
inject: ['save', 't', 'backgroundColor'],
|
|
||||||
props: {
|
|
||||||
drawField: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
editable: {
|
|
||||||
type: Boolean,
|
|
||||||
required: false,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
submitters: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
fields: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
selectedSubmitter: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['change-submitter', 'cancel'],
|
|
||||||
computed: {
|
|
||||||
fieldNames: FieldType.computed.fieldNames,
|
|
||||||
fieldIcons: FieldType.computed.fieldIcons
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
removeSubmitter (submitter) {
|
|
||||||
[...this.fields].forEach((field) => {
|
|
||||||
if (field.submitter_uuid === submitter.uuid) {
|
|
||||||
this.removeField(field, false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
this.submitters.splice(this.submitters.indexOf(submitter), 1)
|
|
||||||
|
|
||||||
if (this.selectedSubmitter === submitter) {
|
|
||||||
this.$emit('change-submitter', this.submitters[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
this.save()
|
|
||||||
},
|
|
||||||
removeField (field, save = true) {
|
|
||||||
this.fields.splice(this.fields.indexOf(field), 1)
|
|
||||||
|
|
||||||
if (save) {
|
|
||||||
this.save()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="inline">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="fixed inset-0 z-40"
|
||||||
|
:class="{ 'pointer-events-none': !open }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 bg-black transition-opacity duration-300"
|
||||||
|
:class="open ? 'opacity-25' : 'opacity-0'"
|
||||||
|
@click="$emit('close')"
|
||||||
|
@dragenter="$emit('close')"
|
||||||
|
@touchmove.prevent
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
ref="panel"
|
||||||
|
class="absolute top-0 bottom-0 bg-base-100 shadow-xl overflow-y-auto overflow-x-hidden overscroll-contain px-4 transition-transform duration-300 ease-out"
|
||||||
|
style="width: 82%; max-width: 340px"
|
||||||
|
:class="[side === 'left' ? 'left-0' : 'right-0', open ? 'translate-x-0' : (side === 'left' ? '-translate-x-full' : 'translate-x-full')]"
|
||||||
|
@touchmove="onPanelTouchmove"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'MobileDrawer',
|
||||||
|
props: {
|
||||||
|
side: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
open: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
inline: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['close'],
|
||||||
|
watch: {
|
||||||
|
open (value) {
|
||||||
|
document.body.style.overflow = value ? 'hidden' : ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeUnmount () {
|
||||||
|
if (this.open) {
|
||||||
|
document.body.style.overflow = ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onPanelTouchmove (e) {
|
||||||
|
if (this.$refs.panel.scrollHeight <= this.$refs.panel.clientHeight) {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
<template>
|
|
||||||
<span class="dropdown dropdown-top dropdown-end absolute bottom-4 right-4 z-10 fields-dropdown-mobile">
|
|
||||||
<label
|
|
||||||
class="btn btn-neutral text-white btn-circle btn-lg group"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<IconPlus
|
|
||||||
class="group-focus:hidden"
|
|
||||||
width="28"
|
|
||||||
height="28"
|
|
||||||
/>
|
|
||||||
<IconX
|
|
||||||
class="hidden group-focus:inline p-3"
|
|
||||||
width="64"
|
|
||||||
height="50"
|
|
||||||
@click="closeDropdown"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<ul
|
|
||||||
tabindex="0"
|
|
||||||
class="dropdown-content menu menu-xs p-2 shadow rounded-box w-52 z-10 mb-3 mt-1.5 bg-base-100"
|
|
||||||
@click="closeDropdown"
|
|
||||||
>
|
|
||||||
<template v-if="submitterDefaultFields.length">
|
|
||||||
<template
|
|
||||||
v-for="field in submitterDefaultFields"
|
|
||||||
:key="field.name"
|
|
||||||
>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="text-sm py-1 px-2"
|
|
||||||
@click.prevent="$emit('select', { name: field.name || '', type: field.type || 'text' })"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="fieldIcons[field.type || 'text']"
|
|
||||||
:stroke-width="1.6"
|
|
||||||
:width="20"
|
|
||||||
/>
|
|
||||||
{{ field.title || field.name }}
|
|
||||||
<span
|
|
||||||
v-if="defaultRequiredFields.includes(field)"
|
|
||||||
:data-tip="t('required')"
|
|
||||||
class="text-red-400 text-2xl tooltip tooltip-left h-6"
|
|
||||||
>
|
|
||||||
*
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<div
|
|
||||||
v-if="fieldTypes.length && submitterDefaultFields.length"
|
|
||||||
class="bg-base-300"
|
|
||||||
style="height: 1px; margin-top: 1px; margin-bottom: 1px"
|
|
||||||
/>
|
|
||||||
<template v-if="fieldTypes.length || !submitterDefaultFields.length">
|
|
||||||
<template
|
|
||||||
v-for="(icon, type) in fieldIconsSorted"
|
|
||||||
:key="type"
|
|
||||||
>
|
|
||||||
<li v-if="fieldTypes.includes(type) || ((withPhone || type != 'phone') && (withPayment || type != 'payment') && (withVerification || type != 'verification') && (withKba || type != 'kba'))">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
class="text-sm py-1 px-2"
|
|
||||||
:class="{ 'active': type === modelValue }"
|
|
||||||
@click.prevent="$emit('select', { type })"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="icon"
|
|
||||||
:stroke-width="1.6"
|
|
||||||
:width="20"
|
|
||||||
/>
|
|
||||||
{{ fieldNames[type] }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</ul>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { IconPlus, IconX } from '@tabler/icons-vue'
|
|
||||||
import FieldType from './field_type'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'MobileFields',
|
|
||||||
components: {
|
|
||||||
IconPlus,
|
|
||||||
IconX
|
|
||||||
},
|
|
||||||
inject: ['withPhone', 'withPayment', 'withVerification', 'withKba', 'backgroundColor', 't'],
|
|
||||||
props: {
|
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
required: false,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
fields: {
|
|
||||||
type: Array,
|
|
||||||
required: false,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
selectedSubmitter: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
fieldTypes: {
|
|
||||||
type: Array,
|
|
||||||
required: false,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
defaultRequiredFields: {
|
|
||||||
type: Array,
|
|
||||||
required: false,
|
|
||||||
default: () => []
|
|
||||||
},
|
|
||||||
defaultFields: {
|
|
||||||
type: Array,
|
|
||||||
required: false,
|
|
||||||
default: () => []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['select'],
|
|
||||||
computed: {
|
|
||||||
...FieldType.computed,
|
|
||||||
submitterFields () {
|
|
||||||
return this.fields.filter((f) => f.submitter_uuid === this.selectedSubmitter.uuid)
|
|
||||||
},
|
|
||||||
submitterDefaultFields () {
|
|
||||||
return this.defaultFields.filter((f) => {
|
|
||||||
return (!f.role || f.role === this.selectedSubmitter.name)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
closeDropdown () {
|
|
||||||
document.activeElement.blur()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
Reference in new issue
Block a user