Skip to content
This repository was archived by the owner on Dec 20, 2023. It is now read-only.

Commit eb48e6b

Browse files
feat: preview other file type than images
1 parent 9de9f1e commit eb48e6b

File tree

5 files changed

+41
-21
lines changed

5 files changed

+41
-21
lines changed

src/module.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export default defineNuxtModule({
5050
})
5151
})
5252

53+
// we need to locate the root public dir
5354
nuxt.options.runtimeConfig.mediaViewer = {
5455
publicRoot: resolve(nuxt.options.rootDir, 'public')
5556
}

src/runtime/components/MediaGalleryItem.vue

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,42 @@
11
<script setup lang="ts">
2-
import { keyToPath } from '../shared'
2+
import { onMounted, ref } from 'vue'
3+
import { keyToPath, type AssetStats } from '../shared'
34
45
const props = defineProps<{
56
assetKey: string
67
}>()
78
8-
function onImageError (event: Event) {
9-
// fetch asset stats
10-
console.log(props.assetKey, event)
9+
const isImage = ref(true)
10+
const fileStat = ref<AssetStats>()
1111
12-
// show an icon from the mimetype
13-
}
12+
onMounted(() => {
13+
// check if image loads, the @error.once seems to be cached
14+
const image = new Image()
15+
image.onerror = async () => {
16+
image.onerror = null
17+
fileStat.value = await $fetch(`/_media-viewer/stats?key=${props.assetKey}`)
18+
isImage.value = false
19+
}
20+
image.src = keyToPath(props.assetKey)
21+
})
1422
</script>
1523

1624
<template>
17-
<NuxtLink :key="assetKey" :to="`#${assetKey}`" class="transition-all hover:scale-150">
25+
<NuxtLink :key="props.assetKey" :to="`#${props.assetKey}`" class="transition-all prevent-drag hover:scale-150">
1826
<img
19-
:src="`${keyToPath(assetKey, true)}?h=300`"
20-
:title="keyToPath(assetKey)"
27+
v-if="isImage"
28+
:src="`${keyToPath(props.assetKey, true)}?h=300`"
29+
:title="keyToPath(props.assetKey)"
2130
width="100"
2231
loading="lazy"
2332
decoding="async"
2433
draggable="false"
2534
class="prevent-drag rounded border select-none pointer-events-none border-slate-100 w-[150px] h-[150px] preview bg-white object-scale-down"
26-
@error.once="onImageError"
2735
>
36+
<div v-else class="rounded flex flex-col justify-center border select-none pointer-events-none border-slate-100 w-[150px] h-[150px] preview bg-white object-scale-down">
37+
<div class="truncate w-full text-center">{{ fileStat?.name }}</div>
38+
<div class="truncate w-full text-center text-sm text-slate-400">{{ fileStat?.mimetype }}</div>
39+
</div>
2840
</NuxtLink>
2941
</template>
3042

src/runtime/components/MediaPreviewImage.vue

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
import { ref, computed, inject, watchEffect, onBeforeUnmount, watch } from 'vue'
33
// @ts-ignore
44
import { useRoute } from '#app'
5-
import { keyToPath } from '../shared'
5+
import { keyToPath, PreviewState } from '../shared'
66
77
const route = useRoute()
88
99
const imageRef = ref()
1010
const mode = ref<'scale' | 'real'>('scale')
1111
const selectedAssetKey = computed(() => route.hash ? route.hash.substring(1) : '')
1212
13-
const previewState = inject<any>('previewState')
13+
const previewState = inject<PreviewState>('previewState')
14+
const isImage = computed(() => previewState?.stats?.mimetype?.startsWith('image/'))
1415
1516
const dragging = ref(false)
1617
const offsetX = ref(0)
@@ -60,18 +61,22 @@ watch(mode, () => {
6061

6162
<template>
6263
<div class="relative overflow-hidden rounded-l border-slate-100 border-r preview w-7/12 flex items-center justify-center">
64+
<div v-if="!isImage" class="rounded flex flex-col justify-center border select-none pointer-events-none border-slate-100 w-[150px] h-[150px] bg-white object-scale-down">
65+
<div class="truncate w-full text-center">{{ previewState?.stats?.name }}</div>
66+
<div class="truncate w-full text-center text-sm text-slate-400">{{ previewState?.stats?.mimetype }}</div>
67+
</div>
6368
<span
64-
v-if="mode === 'real'"
69+
v-else-if="mode === 'real'"
6570
ref="imageRef"
6671
class="prevent-drag block absolute max-w-none origin-top-left hover:cursor-grab active:cursor-grabbing"
6772
tabindex="0"
6873
:style="{
6974
left: `${offsetX}px`,
7075
top: `${offsetY}px`,
71-
width: `${previewState.targetWidth}px`,
72-
height: `${previewState.targetHeight}px`,
76+
width: `${previewState?.targetWidth ?? 0}px`,
77+
height: `${previewState?.targetHeight ?? 0}px`,
7378
}"
74-
v-html="previewState.snippet"
79+
v-html="previewState?.snippet"
7580
/>
7681
<img
7782
v-else
@@ -83,23 +88,25 @@ watch(mode, () => {
8388
<div>
8489
<button
8590
type="button"
86-
class=" text-sm py-1 px-3 rounded-l border-r-0 border border-slate-100 hover:bg-indigo-400 hover:text-white"
91+
class=" text-sm py-1 px-3 rounded-l border-r-0 border border-slate-100 disabled:opacity-60 disabled:cursor-not-allowed active:hover:bg-indigo-400 active:hover:text-white"
8792
:class="[
8893
mode === 'scale' && 'bg-indigo-400 text-white',
8994
mode !== 'scale' && 'bg-white',
9095
]"
9196
@click="mode = 'scale'"
97+
:disabled="!isImage"
9298
>
9399
Overview
94100
</button>
95101
<button
96102
type="button"
97-
class=" text-sm py-1 px-3 rounded-r bg-white border border-slate-100 hover:bg-indigo-400 hover:text-white"
103+
class=" text-sm py-1 px-3 rounded-r bg-white border border-slate-100 disabled:opacity-60 disabled:cursor-not-allowed active:hover:bg-indigo-400 active:hover:text-white"
98104
:class="[
99105
mode === 'real' && 'bg-indigo-400 text-white',
100106
mode !== 'real' && 'bg-white',
101107
]"
102108
@click="mode = 'real'"
109+
:disabled="!isImage"
103110
>
104111
Realtime preview
105112
</button>

src/runtime/pages/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const directoriesKeysPrefix = computed(() => {
3333
return parts.join(':')
3434
})
3535
.reduce((acc, item) => {
36-
if (!acc.includes(item)) {
36+
if (item !== 'root:public' && !acc.includes(item)) {
3737
acc.push(item)
3838
}
3939
return acc

src/runtime/shared/keys.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// replace an unstorage key 'root:public:xxx' to a path '/xxx
22
export function keyToPath (key: string, ipxPrefix?: boolean): string {
33
return key.replace(/:/g, '/').replace(
4-
'root/public/',
5-
ipxPrefix ? '/_ipx/' : '/'
4+
'root/public',
5+
ipxPrefix ? '/_ipx' : ''
66
)
77
}

0 commit comments

Comments
 (0)