Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d0c77bf3a3 |
@@ -1,60 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { EntityObject } from '@DocumentsManager/models/entity'
|
||||
import { getFileIcon } from '@/utils/fileHelpers'
|
||||
|
||||
type PreviewSource = (item: { id: string; meta?: Record<string, unknown> }) => string | Blob | Promise<string | Blob>
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
entity: EntityObject
|
||||
source?: PreviewSource
|
||||
size?: number
|
||||
}>(), {
|
||||
source: undefined,
|
||||
size: 32,
|
||||
})
|
||||
|
||||
const failed = ref(false)
|
||||
const url = computed(() => {
|
||||
if (!props.source) return null
|
||||
const result = props.source({
|
||||
id: String(props.entity.identifier ?? ''),
|
||||
meta: { collection: props.entity.collection ? String(props.entity.collection) : null },
|
||||
})
|
||||
return typeof result === 'string' ? result : null
|
||||
})
|
||||
|
||||
watch(url, () => {
|
||||
failed.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="file-preview"
|
||||
:style="{ width: `${size}px`, height: `${size}px` }"
|
||||
>
|
||||
<v-img
|
||||
v-if="url && !failed"
|
||||
:src="url"
|
||||
:alt="entity.properties.label || 'File preview'"
|
||||
contain
|
||||
width="100%"
|
||||
height="100%"
|
||||
@error="failed = true"
|
||||
/>
|
||||
<v-icon v-else :size="size * 0.75" color="grey">{{ getFileIcon(entity) }}</v-icon>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.file-preview {
|
||||
flex: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border-radius: 6px;
|
||||
background-color: rgb(var(--v-theme-surface-variant), 0.4);
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { VNavigationDrawer } from 'vuetify/components'
|
||||
import { CollectionObject } from '@DocumentsManager/models/collection'
|
||||
import { EntityObject } from '@DocumentsManager/models/entity'
|
||||
@@ -8,10 +8,8 @@ import { getFileIcon, formatSize, formatDate } from '@/utils/fileHelpers'
|
||||
const props = withDefaults(defineProps<{
|
||||
selectedItems: (CollectionObject | EntityObject)[]
|
||||
embedded?: boolean
|
||||
previewUrl?: string | null
|
||||
}>(), {
|
||||
embedded: false,
|
||||
previewUrl: null,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -71,13 +69,6 @@ const totalSize = computed(() => {
|
||||
return sum
|
||||
}, 0)
|
||||
})
|
||||
|
||||
const previewFailed = ref(false)
|
||||
const showPreview = computed(() => isEntity.value && !!props.previewUrl && !previewFailed.value)
|
||||
|
||||
watch(() => props.previewUrl, () => {
|
||||
previewFailed.value = false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -103,24 +94,9 @@ watch(() => props.previewUrl, () => {
|
||||
|
||||
<!-- Single item selected -->
|
||||
<template v-if="singleSelection && selectedItem">
|
||||
<!-- Preview/icon and name -->
|
||||
<!-- Icon and name -->
|
||||
<div class="text-center mb-4">
|
||||
<div v-if="showPreview" class="files-info-preview mb-3">
|
||||
<v-img
|
||||
:src="previewUrl!"
|
||||
:alt="selectedItem.properties.label || 'File preview'"
|
||||
aspect-ratio="1.45"
|
||||
contain
|
||||
@error="previewFailed = true"
|
||||
>
|
||||
<template #placeholder>
|
||||
<div class="d-flex fill-height align-center justify-center">
|
||||
<v-progress-circular indeterminate color="primary" size="28" width="2" />
|
||||
</div>
|
||||
</template>
|
||||
</v-img>
|
||||
</div>
|
||||
<v-icon v-else :color="itemIconColor" size="64">{{ itemIcon }}</v-icon>
|
||||
<v-icon :color="itemIconColor" size="64">{{ itemIcon }}</v-icon>
|
||||
<div class="text-h6 mt-2 text-truncate">{{ selectedItem.properties.label || String(selectedItem.identifier ?? '') }}</div>
|
||||
<div class="text-caption text-grey">
|
||||
{{ isCollection ? 'Folder' : entity?.properties.mime || 'File' }}
|
||||
@@ -229,11 +205,4 @@ watch(() => props.previewUrl, () => {
|
||||
overflow-y: auto;
|
||||
background-color: rgb(var(--v-theme-surface));
|
||||
}
|
||||
|
||||
.files-info-preview {
|
||||
overflow: hidden;
|
||||
border: 1px solid rgb(var(--v-border-color));
|
||||
border-radius: 8px;
|
||||
background-color: rgb(var(--v-theme-surface-variant));
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
import { computed } from 'vue'
|
||||
import { CollectionObject } from '@DocumentsManager/models/collection'
|
||||
import { EntityObject } from '@DocumentsManager/models/entity'
|
||||
import { formatSize, formatDate } from '@/utils/fileHelpers'
|
||||
import { getFileIcon, formatSize, formatDate } from '@/utils/fileHelpers'
|
||||
import FileActionsMenu from '@/components/FileActionsMenu.vue'
|
||||
import FilePreview from '@/components/FilePreview.vue'
|
||||
import FilePreviewPopover from '@/components/viewer/FilePreviewPopover.vue'
|
||||
|
||||
type ItemWithType = {
|
||||
@@ -19,7 +18,6 @@ const props = defineProps<{
|
||||
entities: EntityObject[]
|
||||
selectedIds: Set<string>
|
||||
previewSource?: PreviewSource
|
||||
thumbnailSource?: PreviewSource
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -95,12 +93,7 @@ function isCollection(wrapped: ItemWithType): wrapped is { item: CollectionObjec
|
||||
@dblclick.stop="emit('open', wrapped.item)"
|
||||
>
|
||||
<div class="files-details-cell files-details-name">
|
||||
<FilePreview
|
||||
:entity="(wrapped.item as EntityObject)"
|
||||
:source="thumbnailSource"
|
||||
:size="24"
|
||||
class="mr-2"
|
||||
/>
|
||||
<v-icon color="grey" size="small" class="mr-2">{{ getFileIcon(wrapped.item as EntityObject) }}</v-icon>
|
||||
{{ wrapped.item.properties.label || String(wrapped.item.identifier ?? '') }}
|
||||
</div>
|
||||
<div class="files-details-cell files-details-size">{{ formatSize(wrapped.item.properties.size) }}</div>
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { CollectionObject } from '@DocumentsManager/models/collection'
|
||||
import { EntityObject } from '@DocumentsManager/models/entity'
|
||||
import { formatSize } from '@/utils/fileHelpers'
|
||||
import { getFileIcon, formatSize } from '@/utils/fileHelpers'
|
||||
import FileActionsMenu from '@/components/FileActionsMenu.vue'
|
||||
import FilePreview from '@/components/FilePreview.vue'
|
||||
import FilePreviewPopover from '@/components/viewer/FilePreviewPopover.vue'
|
||||
|
||||
type PreviewSource = (item: { id: string; meta?: Record<string, unknown> }) => string | Blob | Promise<string | Blob>
|
||||
|
||||
const props = defineProps<{
|
||||
defineProps<{
|
||||
collections: CollectionObject[]
|
||||
entities: EntityObject[]
|
||||
selectedIds: Set<string>
|
||||
previewSource?: PreviewSource
|
||||
thumbnailSource?: PreviewSource
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -76,9 +74,7 @@ const emit = defineEmits<{
|
||||
@show-details="emit('show-details', $event)"
|
||||
/>
|
||||
</div>
|
||||
<div class="files-grid-thumbnail">
|
||||
<FilePreview :entity="entity" :source="thumbnailSource" :size="64" />
|
||||
</div>
|
||||
<v-icon size="48" color="grey">{{ getFileIcon(entity) }}</v-icon>
|
||||
<div class="files-grid-label">{{ entity.properties.label || String(entity.identifier ?? '') }}</div>
|
||||
<div class="files-grid-size">{{ formatSize(entity.properties.size) }}</div>
|
||||
|
||||
@@ -140,17 +136,6 @@ const emit = defineEmits<{
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.files-grid-thumbnail {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background-color: rgb(var(--v-theme-surface-variant), 0.4);
|
||||
}
|
||||
|
||||
.files-grid-label {
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
import { computed } from 'vue'
|
||||
import { CollectionObject } from '@DocumentsManager/models/collection'
|
||||
import { EntityObject } from '@DocumentsManager/models/entity'
|
||||
import { formatSize } from '@/utils/fileHelpers'
|
||||
import { getFileIcon, formatSize } from '@/utils/fileHelpers'
|
||||
import FileActionsMenu from '@/components/FileActionsMenu.vue'
|
||||
import FilePreview from '@/components/FilePreview.vue'
|
||||
import FilePreviewPopover from '@/components/viewer/FilePreviewPopover.vue'
|
||||
|
||||
type ItemWithType = {
|
||||
@@ -19,7 +18,6 @@ const props = defineProps<{
|
||||
entities: EntityObject[]
|
||||
selectedIds: Set<string>
|
||||
previewSource?: PreviewSource
|
||||
thumbnailSource?: PreviewSource
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -81,11 +79,7 @@ function isCollection(wrapped: ItemWithType): wrapped is { item: CollectionObjec
|
||||
@dblclick.stop="emit('open', wrapped.item)"
|
||||
>
|
||||
<template #prepend>
|
||||
<FilePreview
|
||||
:entity="(wrapped.item as EntityObject)"
|
||||
:source="thumbnailSource"
|
||||
:size="32"
|
||||
/>
|
||||
<v-icon color="grey">{{ getFileIcon(wrapped.item as EntityObject) }}</v-icon>
|
||||
</template>
|
||||
<v-list-item-title>{{ wrapped.item.properties.label || String(wrapped.item.identifier ?? '') }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ formatSize(wrapped.item.properties.size) }}</v-list-item-subtitle>
|
||||
|
||||
+4
-42
@@ -129,42 +129,9 @@ function entityToViewerItem(entity: EntityObject): ViewerItem {
|
||||
}
|
||||
|
||||
function resolveViewerSource(item: ViewerItem): string {
|
||||
return documentManager.getEntityPreviewUrl(
|
||||
item.id,
|
||||
(item.meta?.collection as string | null) ?? null,
|
||||
'fullscreen',
|
||||
)
|
||||
return documentManager.getEntityUrl(item.id, (item.meta?.collection as string | null) ?? null)
|
||||
}
|
||||
|
||||
function resolvePreviewSource(item: ViewerItem): string {
|
||||
return documentManager.getEntityPreviewUrl(
|
||||
item.id,
|
||||
(item.meta?.collection as string | null) ?? null,
|
||||
'inline',
|
||||
)
|
||||
}
|
||||
|
||||
function resolveThumbnailSource(item: ViewerItem): string {
|
||||
return documentManager.getEntityPreviewUrl(
|
||||
item.id,
|
||||
(item.meta?.collection as string | null) ?? null,
|
||||
'thumbnail',
|
||||
)
|
||||
}
|
||||
|
||||
// Preview shown in the info panel sidebar for the current single selection
|
||||
const infoPanelPreviewUrl = computed<string | null>(() => {
|
||||
const items = selection.selectedNodeArray.value
|
||||
if (items.length !== 1) return null
|
||||
const item = items[0]
|
||||
if (!(item instanceof EntityObject)) return null
|
||||
return documentManager.getEntityPreviewUrl(
|
||||
nodeId(item),
|
||||
item.collection ? String(item.collection) : null,
|
||||
'inline',
|
||||
)
|
||||
})
|
||||
|
||||
function downloadViewerItem(item: ViewerItem): void {
|
||||
documentManager.downloadEntity(item.id, (item.meta?.collection as string | null) ?? null)
|
||||
}
|
||||
@@ -815,8 +782,7 @@ onMounted(async () => {
|
||||
:collections="sortedItems.collections"
|
||||
:entities="sortedItems.entities"
|
||||
:selected-ids="selectedIds"
|
||||
:preview-source="resolvePreviewSource"
|
||||
:thumbnail-source="resolveThumbnailSource"
|
||||
:preview-source="resolveViewerSource"
|
||||
@item-click="handleItemClick"
|
||||
@open="handleOpenItem"
|
||||
@edit="handleEditItem"
|
||||
@@ -832,8 +798,7 @@ onMounted(async () => {
|
||||
:collections="sortedItems.collections"
|
||||
:entities="sortedItems.entities"
|
||||
:selected-ids="selectedIds"
|
||||
:preview-source="resolvePreviewSource"
|
||||
:thumbnail-source="resolveThumbnailSource"
|
||||
:preview-source="resolveViewerSource"
|
||||
@item-click="handleItemClick"
|
||||
@open="handleOpenItem"
|
||||
@edit="handleEditItem"
|
||||
@@ -849,8 +814,7 @@ onMounted(async () => {
|
||||
:collections="sortedItems.collections"
|
||||
:entities="sortedItems.entities"
|
||||
:selected-ids="selectedIds"
|
||||
:preview-source="resolvePreviewSource"
|
||||
:thumbnail-source="resolveThumbnailSource"
|
||||
:preview-source="resolveViewerSource"
|
||||
@item-click="handleItemClick"
|
||||
@open="handleOpenItem"
|
||||
@edit="handleEditItem"
|
||||
@@ -866,7 +830,6 @@ onMounted(async () => {
|
||||
v-if="hasSelection && !isMobile"
|
||||
embedded
|
||||
:selected-items="selection.selectedNodeArray.value"
|
||||
:preview-url="infoPanelPreviewUrl"
|
||||
@close="selection.clear()"
|
||||
/>
|
||||
</div>
|
||||
@@ -875,7 +838,6 @@ onMounted(async () => {
|
||||
<FilesInfoPanel
|
||||
v-if="isMobile"
|
||||
:selected-items="selection.selectedNodeArray.value"
|
||||
:preview-url="infoPanelPreviewUrl"
|
||||
@close="selection.clear()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user