Initial commit

This commit is contained in:
root
2025-12-21 09:57:09 -05:00
committed by Sebastian Krupinski
commit 8ac20d8b45
38 changed files with 4677 additions and 0 deletions

View File

@@ -0,0 +1,182 @@
<script setup lang="ts">
import { computed } from 'vue'
import { FileCollectionObject } from '@FileManager/models/collection'
import { FileEntityObject } from '@FileManager/models/entity'
import { getFileIcon, formatSize, formatDate } from '@/utils/fileHelpers'
const props = defineProps<{
selectedItems: (FileCollectionObject | FileEntityObject)[]
}>()
const emit = defineEmits<{
'close': []
}>()
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?.['@type'] === 'files.collection'
)
const isEntity = computed(() =>
selectedItem.value?.['@type'] === 'files.entity'
)
const entity = computed(() =>
isEntity.value ? selectedItem.value as FileEntityObject : 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['@type'] === 'files.entity') {
return sum + ((item as FileEntityObject).size || 0)
}
return sum
}, 0)
})
</script>
<template>
<v-navigation-drawer
:model-value="hasSelection"
:key="selectedItems.map(i => i.id).join(',')"
location="right"
width="320"
temporary
class="files-info-panel"
>
<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.label }}</div>
<div class="text-caption text-grey">
{{ isCollection ? 'Folder' : entity?.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?.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.size) }}</v-list-item-subtitle>
</v-list-item>
<!-- Created -->
<v-list-item v-if="selectedItem.createdOn">
<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.createdOn) }}</v-list-item-subtitle>
</v-list-item>
<!-- Modified -->
<v-list-item v-if="selectedItem.modifiedOn">
<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.modifiedOn) }}</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.id }}
</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['@type'] === 'files.collection').length }} folders,
{{ selectedItems.filter(i => i['@type'] === 'files.entity').length }} files
</v-list-item-subtitle>
</v-list-item>
</v-list>
</template>
</div>
</v-navigation-drawer>
</template>
<style scoped>
.files-info-panel {
border-left: 1px solid rgb(var(--v-border-color)) !important;
}
</style>