da6a407445
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
209 lines
6.8 KiB
Vue
209 lines
6.8 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { VNavigationDrawer } from 'vuetify/components'
|
|
import { CollectionObject } from '@DocumentsManager/models/collection'
|
|
import { EntityObject } from '@DocumentsManager/models/entity'
|
|
import { getFileIcon, formatSize, formatDate } from '@/utils/fileHelpers'
|
|
|
|
const props = withDefaults(defineProps<{
|
|
selectedItems: (CollectionObject | EntityObject)[]
|
|
embedded?: boolean
|
|
}>(), {
|
|
embedded: false,
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
'close': []
|
|
}>()
|
|
|
|
const panelComponent = computed(() => props.embedded ? 'div' : VNavigationDrawer)
|
|
|
|
const panelProps = computed(() => {
|
|
if (props.embedded) {
|
|
return {}
|
|
}
|
|
|
|
return {
|
|
modelValue: hasSelection.value,
|
|
key: props.selectedItems.map(item => String(item.identifier)).join(','),
|
|
location: 'right',
|
|
width: 320,
|
|
temporary: true,
|
|
}
|
|
})
|
|
|
|
const hasSelection = computed(() => props.selectedItems.length > 0)
|
|
const singleSelection = computed(() => props.selectedItems.length === 1)
|
|
const selectedItem = computed(() => props.selectedItems[0] ?? null)
|
|
|
|
const isCollection = computed(() =>
|
|
selectedItem.value instanceof CollectionObject
|
|
)
|
|
|
|
const isEntity = computed(() =>
|
|
selectedItem.value instanceof EntityObject
|
|
)
|
|
|
|
const entity = computed(() =>
|
|
isEntity.value ? selectedItem.value as EntityObject : null
|
|
)
|
|
|
|
// Computed display values
|
|
const itemIcon = computed(() => {
|
|
if (!selectedItem.value) return 'mdi-file'
|
|
if (isCollection.value) return 'mdi-folder'
|
|
return getFileIcon(entity.value!)
|
|
})
|
|
|
|
const itemIconColor = computed(() => {
|
|
if (isCollection.value) return 'amber-darken-2'
|
|
return 'grey'
|
|
})
|
|
|
|
const totalSize = computed(() => {
|
|
if (props.selectedItems.length === 0) return 0
|
|
return props.selectedItems.reduce((sum, item) => {
|
|
if (item instanceof EntityObject) {
|
|
return sum + (item.properties.size || 0)
|
|
}
|
|
return sum
|
|
}, 0)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<component
|
|
:is="panelComponent"
|
|
v-if="!embedded || hasSelection"
|
|
v-bind="panelProps"
|
|
class="files-info-panel"
|
|
:class="{ 'files-info-panel--embedded': embedded }"
|
|
>
|
|
<div class="pa-4">
|
|
<!-- Header -->
|
|
<div class="d-flex align-center mb-4">
|
|
<span class="text-h6">Info</span>
|
|
<v-spacer />
|
|
<v-btn
|
|
icon="mdi-close"
|
|
size="small"
|
|
variant="text"
|
|
@click="emit('close')"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Single item selected -->
|
|
<template v-if="singleSelection && selectedItem">
|
|
<!-- Icon and name -->
|
|
<div class="text-center mb-4">
|
|
<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' }}
|
|
</div>
|
|
</div>
|
|
|
|
<v-divider class="mb-4" />
|
|
|
|
<!-- Details list -->
|
|
<v-list density="compact" class="bg-transparent">
|
|
<!-- Type -->
|
|
<v-list-item>
|
|
<template #prepend>
|
|
<v-icon size="small" class="mr-3">mdi-tag-outline</v-icon>
|
|
</template>
|
|
<v-list-item-title class="text-caption text-grey">Type</v-list-item-title>
|
|
<v-list-item-subtitle>
|
|
{{ isCollection ? 'Folder' : (entity?.properties.mime || 'Unknown') }}
|
|
</v-list-item-subtitle>
|
|
</v-list-item>
|
|
|
|
<!-- Size (only for files) -->
|
|
<v-list-item v-if="isEntity && entity">
|
|
<template #prepend>
|
|
<v-icon size="small" class="mr-3">mdi-harddisk</v-icon>
|
|
</template>
|
|
<v-list-item-title class="text-caption text-grey">Size</v-list-item-title>
|
|
<v-list-item-subtitle>{{ formatSize(entity.properties.size) }}</v-list-item-subtitle>
|
|
</v-list-item>
|
|
|
|
<!-- Created -->
|
|
<v-list-item v-if="selectedItem.created">
|
|
<template #prepend>
|
|
<v-icon size="small" class="mr-3">mdi-calendar-plus</v-icon>
|
|
</template>
|
|
<v-list-item-title class="text-caption text-grey">Created</v-list-item-title>
|
|
<v-list-item-subtitle>{{ formatDate(selectedItem.created) }}</v-list-item-subtitle>
|
|
</v-list-item>
|
|
|
|
<!-- Modified -->
|
|
<v-list-item v-if="selectedItem.modified">
|
|
<template #prepend>
|
|
<v-icon size="small" class="mr-3">mdi-calendar-edit</v-icon>
|
|
</template>
|
|
<v-list-item-title class="text-caption text-grey">Modified</v-list-item-title>
|
|
<v-list-item-subtitle>{{ formatDate(selectedItem.modified) }}</v-list-item-subtitle>
|
|
</v-list-item>
|
|
|
|
<!-- ID -->
|
|
<v-list-item>
|
|
<template #prepend>
|
|
<v-icon size="small" class="mr-3">mdi-identifier</v-icon>
|
|
</template>
|
|
<v-list-item-title class="text-caption text-grey">ID</v-list-item-title>
|
|
<v-list-item-subtitle class="text-truncate" style="font-family: monospace; font-size: 11px;">
|
|
{{ selectedItem.identifier }}
|
|
</v-list-item-subtitle>
|
|
</v-list-item>
|
|
</v-list>
|
|
</template>
|
|
|
|
<!-- Multiple items selected -->
|
|
<template v-else-if="selectedItems.length > 1">
|
|
<div class="text-center mb-4">
|
|
<v-icon color="primary" size="64">mdi-checkbox-multiple-marked</v-icon>
|
|
<div class="text-h6 mt-2">{{ selectedItems.length }} items selected</div>
|
|
</div>
|
|
|
|
<v-divider class="mb-4" />
|
|
|
|
<v-list density="compact" class="bg-transparent">
|
|
<!-- Total size -->
|
|
<v-list-item>
|
|
<template #prepend>
|
|
<v-icon size="small" class="mr-3">mdi-harddisk</v-icon>
|
|
</template>
|
|
<v-list-item-title class="text-caption text-grey">Total Size</v-list-item-title>
|
|
<v-list-item-subtitle>{{ formatSize(totalSize) }}</v-list-item-subtitle>
|
|
</v-list-item>
|
|
|
|
<!-- Item breakdown -->
|
|
<v-list-item>
|
|
<template #prepend>
|
|
<v-icon size="small" class="mr-3">mdi-file-multiple</v-icon>
|
|
</template>
|
|
<v-list-item-title class="text-caption text-grey">Contents</v-list-item-title>
|
|
<v-list-item-subtitle>
|
|
{{ selectedItems.filter(i => i instanceof CollectionObject).length }} folders,
|
|
{{ selectedItems.filter(i => i instanceof EntityObject).length }} files
|
|
</v-list-item-subtitle>
|
|
</v-list-item>
|
|
</v-list>
|
|
</template>
|
|
</div>
|
|
</component>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.files-info-panel {
|
|
border-left: 1px solid rgb(var(--v-border-color)) !important;
|
|
}
|
|
|
|
.files-info-panel--embedded {
|
|
width: 320px;
|
|
flex-shrink: 0;
|
|
overflow-y: auto;
|
|
background-color: rgb(var(--v-theme-surface));
|
|
}
|
|
</style>
|