@meistrari/tela-build 1.46.0 → 1.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -85,6 +85,28 @@ const isPageInputFocused = ref(false)
|
|
|
85
85
|
const isProgrammaticScroll = ref(false)
|
|
86
86
|
|
|
87
87
|
const scale = ref(props.initialScale ?? (props.variant === 'minimal' ? 1 : 0.75))
|
|
88
|
+
|
|
89
|
+
const IMAGE_BASE_WIDTH_DEFAULT = 480
|
|
90
|
+
const IMAGE_BASE_WIDTH_MINIMAL = 256
|
|
91
|
+
const isImage = computed(() => !!props.file.fileType?.startsWith('image/'))
|
|
92
|
+
const imageBaseWidth = computed(() => (props.variant === 'minimal' ? IMAGE_BASE_WIDTH_MINIMAL : IMAGE_BASE_WIDTH_DEFAULT))
|
|
93
|
+
const imageDisplayWidth = computed(() => Math.round(imageBaseWidth.value * scale.value))
|
|
94
|
+
|
|
95
|
+
const imageWrapperStyle = computed(() => {
|
|
96
|
+
if (!isImage.value) {
|
|
97
|
+
return { width: props.variant === 'minimal' ? '256px' : '446px', maxWidth: '100%' }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (props.variant === 'minimal') {
|
|
101
|
+
return { width: `${Math.round(scale.value * 100)}%`, maxWidth: 'none' }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
width: `${imageDisplayWidth.value}px`,
|
|
106
|
+
maxWidth: scale.value > 1 ? 'none' : '100%',
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
88
110
|
const scrollContainerRef = ref<HTMLElement | null>(null)
|
|
89
111
|
const isDragging = ref(false)
|
|
90
112
|
const dragEnabled = ref(false)
|
|
@@ -545,7 +567,6 @@ function setupPdfObserver() {
|
|
|
545
567
|
pdfObserver.value.observe(el)
|
|
546
568
|
}
|
|
547
569
|
|
|
548
|
-
// Render first pages immediately — don't wait for async observer callback
|
|
549
570
|
visiblePages.value.add(1)
|
|
550
571
|
void renderVisiblePages()
|
|
551
572
|
}
|
|
@@ -669,12 +690,19 @@ watch(() => props.file, async (newFile, oldFile) => {
|
|
|
669
690
|
pdfDocHandle.value = null
|
|
670
691
|
pdfLoadError.value = null
|
|
671
692
|
|
|
693
|
+
dragEnabled.value = false
|
|
694
|
+
isDragging.value = false
|
|
695
|
+
|
|
672
696
|
if (!newFile) {
|
|
673
697
|
fileUrl.value = undefined
|
|
674
698
|
isLoading.value = false
|
|
675
699
|
return
|
|
676
700
|
}
|
|
677
701
|
|
|
702
|
+
scale.value = newFile.fileType?.startsWith('image/')
|
|
703
|
+
? (props.initialScale ?? 1)
|
|
704
|
+
: (props.initialScale ?? (props.variant === 'minimal' ? 1 : 0.75))
|
|
705
|
+
|
|
678
706
|
isLoading.value = true
|
|
679
707
|
error.value = null
|
|
680
708
|
|
|
@@ -897,8 +925,6 @@ watch([() => props.highlightText, () => props.highlightPage, () => props.highlig
|
|
|
897
925
|
if (pdfDocHandle.value) {
|
|
898
926
|
await reRenderAllPdfPages()
|
|
899
927
|
}
|
|
900
|
-
// When doc isn't loaded yet, keep pendingScrollPage — it will be
|
|
901
|
-
// consumed by reRenderAllPdfPages().finally once the PDF renders.
|
|
902
928
|
})
|
|
903
929
|
</script>
|
|
904
930
|
|
|
@@ -906,10 +932,10 @@ watch([() => props.highlightText, () => props.highlightPage, () => props.highlig
|
|
|
906
932
|
<div
|
|
907
933
|
relative
|
|
908
934
|
:data-pdf-preview="props.file.fileType === 'application/pdf'"
|
|
909
|
-
:data-has-tabs="props.segmentTab && props.file.fileType !== 'application/pdf'"
|
|
935
|
+
:data-has-tabs="props.segmentTab === 'processed' && props.file.fileType !== 'application/pdf'"
|
|
910
936
|
:class="cn('group', {
|
|
911
|
-
'data-[has-tabs=true]:pt-88px data-[pdf-preview=false]:pt-
|
|
912
|
-
'data-[has-tabs=true]:pt-42px data-[pdf-preview=false]:pt-
|
|
937
|
+
'data-[has-tabs=true]:pt-88px data-[pdf-preview=false]:pt-0px': variant === 'default',
|
|
938
|
+
'data-[has-tabs=true]:pt-42px data-[pdf-preview=false]:pt-0px': variant === 'minimal',
|
|
913
939
|
})"
|
|
914
940
|
overflow-y-auto no-scrollbar
|
|
915
941
|
@mouseenter="handleContainerMouseEnter"
|
|
@@ -1119,7 +1145,7 @@ watch([() => props.highlightText, () => props.highlightPage, () => props.highlig
|
|
|
1119
1145
|
<!-- PDF Content -->
|
|
1120
1146
|
<template v-else-if="props.file.fileType === 'application/pdf'">
|
|
1121
1147
|
<Motion
|
|
1122
|
-
relative
|
|
1148
|
+
relative mb--48px
|
|
1123
1149
|
class="group"
|
|
1124
1150
|
:initial="{ opacity: 0, filter: 'blur(4px)', pointerEvents: 'none' }"
|
|
1125
1151
|
:animate="{ opacity: 1, filter: 'blur(0px)', pointerEvents: 'auto' }"
|
|
@@ -1205,21 +1231,29 @@ watch([() => props.highlightText, () => props.highlightPage, () => props.highlig
|
|
|
1205
1231
|
|| props.file.fileType?.startsWith('video/')
|
|
1206
1232
|
|| props.file.fileType?.startsWith('audio/')"
|
|
1207
1233
|
>
|
|
1208
|
-
<div
|
|
1209
|
-
mx-auto
|
|
1210
|
-
flex items-center justify-center
|
|
1211
|
-
:class="cn('h-[calc(100%-56px)]', {
|
|
1212
|
-
'w-446px': variant === 'default',
|
|
1213
|
-
'w-256px': variant === 'minimal',
|
|
1214
|
-
})"
|
|
1215
|
-
>
|
|
1234
|
+
<div relative h-full w-full mb--48px>
|
|
1216
1235
|
<div
|
|
1217
|
-
|
|
1218
|
-
|
|
1236
|
+
ref="scrollContainerRef"
|
|
1237
|
+
absolute inset-0 select-none overflow-auto no-scrollbar flex
|
|
1238
|
+
class="[justify-content:safe_center] [align-items:safe_center]"
|
|
1239
|
+
:class="cn(
|
|
1240
|
+
variant === 'minimal' ? 'px-16px py-16px' : 'px-46px py-24px',
|
|
1241
|
+
isImage && dragEnabled ? (isDragging ? 'cursor-grabbing' : 'cursor-grab') : 'cursor-default',
|
|
1242
|
+
)"
|
|
1243
|
+
@mousedown="handleMouseDown"
|
|
1244
|
+
@mousemove="handleMouseMove"
|
|
1245
|
+
@mouseup="handleMouseUp"
|
|
1246
|
+
@mouseleave="handleMouseLeave"
|
|
1219
1247
|
>
|
|
1220
|
-
<
|
|
1221
|
-
|
|
1222
|
-
|
|
1248
|
+
<div
|
|
1249
|
+
flex-shrink-0 border-0.5px rounded-12px overflow-hidden
|
|
1250
|
+
class="border-[#000]/8 box-shadow-[0_3px_24px_0_rgba(214,218,224,0.24),0_12px_52px_0_rgba(214,218,224,0.16)]"
|
|
1251
|
+
:style="imageWrapperStyle"
|
|
1252
|
+
>
|
|
1253
|
+
<img v-if="props.file.fileType?.startsWith('image/')" :src="fileUrl!" width="100%" :alt="props.file.fileName" :draggable="false">
|
|
1254
|
+
<video v-else-if="props.file.fileType?.startsWith('video/')" :src="fileUrl!" width="100%" controls />
|
|
1255
|
+
<audio v-else-if="props.file.fileType?.startsWith('audio/')" :src="fileUrl!" controls style="width: 100%;" />
|
|
1256
|
+
</div>
|
|
1223
1257
|
</div>
|
|
1224
1258
|
</div>
|
|
1225
1259
|
</template>
|
|
@@ -57,11 +57,13 @@ onMounted(() => {
|
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
const isPdf = computed(() => props.file.fileType === 'application/pdf')
|
|
60
|
+
const isImage = computed(() => !!props.file.fileType?.startsWith('image/'))
|
|
61
|
+
const canZoom = computed(() => (isPdf.value ? props.totalPages > 0 : isImage.value))
|
|
60
62
|
|
|
61
63
|
const actions = computed(() => ({
|
|
62
|
-
zoomIn: props.variant === 'default' &&
|
|
63
|
-
zoomOut: props.variant === 'default' &&
|
|
64
|
-
handMode: props.variant === 'default' && isPdf.value && props.segmentTab !== 'processed',
|
|
64
|
+
zoomIn: props.variant === 'default' && canZoom.value && props.segmentTab !== 'processed',
|
|
65
|
+
zoomOut: props.variant === 'default' && canZoom.value && props.segmentTab !== 'processed',
|
|
66
|
+
handMode: props.variant === 'default' && (isPdf.value || isImage.value) && props.segmentTab !== 'processed',
|
|
65
67
|
fullscreen: showFullscreenButton.value,
|
|
66
68
|
}))
|
|
67
69
|
|
|
@@ -130,7 +132,7 @@ const computedWidthContent = computed(() => {
|
|
|
130
132
|
<div flex items-center justify-center gap-4px>
|
|
131
133
|
<TelaTooltipGroup>
|
|
132
134
|
<div flex items-center justify-center gap-2px>
|
|
133
|
-
<template v-if="variant === 'minimal'
|
|
135
|
+
<template v-if="variant === 'minimal'">
|
|
134
136
|
<TelaTooltipGroupTrigger variant="multiline">
|
|
135
137
|
<button
|
|
136
138
|
w-40px h-40px
|
|
@@ -303,7 +305,7 @@ const computedWidthContent = computed(() => {
|
|
|
303
305
|
</div>
|
|
304
306
|
</template>
|
|
305
307
|
|
|
306
|
-
<template v-if="variant === 'default'
|
|
308
|
+
<template v-if="variant === 'default'">
|
|
307
309
|
<div aria-hidden h-24px w-0.5px class="bg-white/16" />
|
|
308
310
|
|
|
309
311
|
<div pl-12px pr-14px>
|
|
@@ -91,9 +91,9 @@ const firstColumnWidth = computed(() => {
|
|
|
91
91
|
return '82px'
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
const minWidth =
|
|
94
|
+
const minWidth = 56
|
|
95
95
|
const maxLength = Math.max(...allTexts.map(text => text.length))
|
|
96
|
-
const charWidth = 7
|
|
96
|
+
const charWidth = 7
|
|
97
97
|
|
|
98
98
|
const width = Math.max(minWidth, maxLength * charWidth)
|
|
99
99
|
|
|
@@ -28,7 +28,7 @@ function selectTab(value: string) {
|
|
|
28
28
|
|
|
29
29
|
<template>
|
|
30
30
|
<div
|
|
31
|
-
rounded-full flex items-center gap-2px select-none p-2px min-w-68px bg-
|
|
31
|
+
rounded-full flex items-center gap-2px select-none p-2px min-w-68px bg-lowered
|
|
32
32
|
:class="[
|
|
33
33
|
props.size === 'small' ? 'min-h-24px' : 'min-h-28px',
|
|
34
34
|
props.disabled && 'opacity-50 pointer-events-none cursor-not-allowed',
|
|
@@ -47,11 +47,11 @@ function selectTab(value: string) {
|
|
|
47
47
|
:disabled="props.disabled"
|
|
48
48
|
@click="selectTab(option.value)"
|
|
49
49
|
>
|
|
50
|
-
<span relative z-10 :class="modelValue === option.value ? 'text-
|
|
50
|
+
<span relative z-10 :class="modelValue === option.value ? 'text-primary' : 'text-secondary'">{{ option.label }}</span>
|
|
51
51
|
<Motion
|
|
52
52
|
v-if="modelValue === option.value"
|
|
53
53
|
:layout-id="`${uniqueId}-tab-indicator`"
|
|
54
|
-
absolute z-0 inset-0 bg
|
|
54
|
+
absolute z-0 inset-0 bg shadow-tab rounded-inherit size-full
|
|
55
55
|
:transition="{ duration: 0.3, type: 'spring', bounce: 0 }"
|
|
56
56
|
/>
|
|
57
57
|
</button>
|