Better attachment view page

This commit is contained in:
LittleSheep 2024-10-04 20:21:01 +08:00
parent a0cf66d2e1
commit 6693acb24a
3 changed files with 86 additions and 63 deletions

View File

@ -18,7 +18,7 @@
</v-row> </v-row>
</v-sheet> </v-sheet>
<v-img v-else-if="item.mimetype.split('/')[0] == 'image'" :src="getAttachmentUrl(item.rid)" :alt="item.alt" <v-img v-else-if="item.mimetype.split('/')[0] == 'image'" :src="getAttachmentUrl(item.rid)" :alt="item.alt"
class="w-full h-full" cover /> class="w-full h-full" :cover="!props.noCover" />
<video v-else-if="item.mimetype.split('/')[0] == 'video'" :src="getAttachmentUrl(item.rid)" class="w-full h-full" <video v-else-if="item.mimetype.split('/')[0] == 'video'" :src="getAttachmentUrl(item.rid)" class="w-full h-full"
controls @click.stop /> controls @click.stop />
<v-sheet v-else color="rgba(0, 0, 0, .4)" height="calc(100% + 24px)" class="p-5"> <v-sheet v-else color="rgba(0, 0, 0, .4)" height="calc(100% + 24px)" class="p-5">
@ -49,7 +49,7 @@
<script setup lang="ts"> <script setup lang="ts">
const config = useRuntimeConfig() const config = useRuntimeConfig()
const props = defineProps<{ item: any }>() const props = defineProps<{ item: any, noCover?: boolean }>()
const item = computed(() => props.item) const item = computed(() => props.item)

24
layouts/minimal.vue Normal file
View File

@ -0,0 +1,24 @@
<template>
<v-system-bar flat color="primary" class="px-5 flex justify-center">
<v-btn icon="mdi-arrow-left" variant="text" color="white" size="x-small" class="mt-[2px]" @click="goBack" />
<h2 class="mt-1">Solsynth LLC</h2>
<v-spacer />
</v-system-bar>
<v-main>
<slot />
</v-main>
</template>
<script setup lang="ts">
const router = useRouter()
function goBack() {
if (window.history.length > 0) {
router.go(-1)
} else {
navigateTo("/")
}
}
</script>

View File

@ -1,69 +1,82 @@
<template> <template>
<v-container class="content-container mx-auto"> <v-row class="h-[calc(100vh-24px)]" no-gutters>
<div class="mt-3 mb-4.5 mx-[2.5ch] flex flex-row gap-4 items-center"> <v-col cols="12" md="8">
<nuxt-link :to="`/users/${attachment.account?.name}`"> <div class="h-full w-full flex justify-center items-center" :class="isMediumScreen ? 'flex-row' : 'flex-col'">
<v-avatar :image="attachment.account?.avatar" /> <div class="flex-grow-1 w-full">
</nuxt-link> <attachment-renderer :item="attachment" no-cover />
<div class="flex flex-col"> </div>
<span class="text-xs">Uploaded by</span> <v-divider v-if="isMediumScreen" vertical />
<span>{{ attachment.account?.nick }} <span class="text-xs">@{{ attachment.account?.name }}</span></span> <v-divider v-else />
</div> </div>
</div> </v-col>
<v-col cols="12" md="4" class="px-5 pt-3">
<h2 class="section-header">Preview</h2> <div class="mt-3 mb-4.5 mx-[2.5ch] flex flex-row gap-4 items-center">
<v-card class="mb-5"> <nuxt-link :to="`/users/${attachment.account?.name}`">
<attachment-renderer :item="attachment" /> <v-avatar :image="attachment.account?.avatar" />
</v-card> </nuxt-link>
<h2 class="section-header">Metadata</h2>
<v-card class="mb-5">
<v-card-text class="flex flex-col gap-4">
<div class="flex flex-col" v-if="attachment?.alt">
<span class="text-xs font-bold">Alternative</span>
<span class="text-truncate">{{ attachment?.alt }}</span>
</div>
<div class="flex flex-col"> <div class="flex flex-col">
<span class="text-xs font-bold">Original File Name</span> <span class="text-xs">Uploaded by</span>
<span class="text-truncate">{{ attachment?.name }}</span> <span>{{ attachment.account?.nick }} <span class="text-xs">@{{ attachment.account?.name }}</span></span>
</div> </div>
<div class="flex flex-col"> </div>
<span class="text-xs font-bold">Size</span>
<span>{{ formatBytes(attachment?.size) }}</span> <v-card class="mb-5">
</div> <v-card-text class="flex flex-col gap-4">
<div class="flex flex-col" v-if="attachment?.metadata?.ratio"> <div class="flex flex-col" v-if="attachment?.alt">
<span class="text-xs font-bold">Aspect Ratio</span> <span class="text-xs font-bold">Alternative</span>
<span> <span class="text-truncate">{{ attachment?.alt }}</span>
</div>
<div class="flex flex-col">
<span class="text-xs font-bold">Original File Name</span>
<span class="text-truncate">{{ attachment?.name }}</span>
</div>
<div class="flex flex-col">
<span class="text-xs font-bold">Size</span>
<span>{{ formatBytes(attachment?.size) }}</span>
</div>
<div class="flex flex-col" v-if="attachment?.metadata?.ratio">
<span class="text-xs font-bold">Aspect Ratio</span>
<span>
{{ attachment?.metadata?.width }}x{{ attachment?.metadata?.height }} {{ attachment?.metadata?.width }}x{{ attachment?.metadata?.height }}
{{ attachment?.metadata?.ratio.toFixed(2) }} {{ attachment?.metadata?.ratio.toFixed(2) }}
</span> </span>
</div> </div>
<div class="flex flex-col" v-if="attachment?.mimetype"> <div class="flex flex-col" v-if="attachment?.mimetype">
<span class="text-xs font-bold">Mimetype</span> <span class="text-xs font-bold">Mimetype</span>
<span>{{ attachment?.mimetype }}</span> <span>{{ attachment?.mimetype }}</span>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<span class="text-xs font-bold">Raw Data</span> <span class="text-xs font-bold">Raw Data</span>
<v-code class="font-mono mt-1">{{ JSON.stringify(attachment.metadata, null, 4) }}</v-code> <v-code class="font-mono mt-1">{{ JSON.stringify(attachment.metadata, null, 4) }}</v-code>
</div> </div>
</v-card-text> </v-card-text>
</v-card> </v-card>
<div class="text-xs text-grey flex flex-col mx-[2.5ch]"> <div class="text-xs text-grey flex flex-col mx-[2.5ch]">
<span>Solar Network Attachment Web Preview</span> <span>Solar Network Attachment Web Preview</span>
<span>Powered by <a class="underline" target="_blank" href="https://git.solsynth.dev/Hydrogen/Paperclip">Hydrogen.Paperclip</a></span> <span>Powered by <a class="underline" target="_blank" href="https://git.solsynth.dev/Hydrogen/Paperclip">Hydrogen.Paperclip</a></span>
</div> </div>
</v-container> </v-col>
</v-row>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useDisplay } from "vuetify"
const route = useRoute() const route = useRoute()
const config = useRuntimeConfig() const config = useRuntimeConfig()
const firstImage = ref<string | null>() const firstImage = ref<string | null>()
const firstVideo = ref<string | null>() const firstVideo = ref<string | null>()
const isMediumScreen = useDisplay().mdAndUp
const { data: attachment } = await useFetch<any>(`${config.public.solarNetworkApi}/cgi/uc/attachments/${route.params.id}/meta`) const { data: attachment } = await useFetch<any>(`${config.public.solarNetworkApi}/cgi/uc/attachments/${route.params.id}/meta`)
definePageMeta({
layout: "minimal",
})
if (!attachment.value) { if (!attachment.value) {
throw createError({ throw createError({
statusCode: 404, statusCode: 404,
@ -117,17 +130,3 @@ function formatBytes(bytes: number, decimals = 2) {
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`
} }
</script> </script>
<style scoped>
.content-container {
max-width: 70ch !important;
}
.section-header {
margin-left: 2.5ch;
margin-right: 2.5ch;
margin-bottom: 8px;
@apply text-lg;
}
</style>