Images & Media
When a PHP component uses #[Silverback\Uploadable], use useCwaImageResource instead of useCwaResource. It adds computed values for the uploaded file URL, load state, and Imagine filter variants.
Display Component
<!-- app/cwa/components/Image/Image.vue -->
<template>
<div class="relative">
<Transition name="fade">
<NuxtImg
v-if="displayMedia"
:src="contentUrl"
class="w-full h-full object-cover"
@load="handleLoad"
/>
</Transition>
<div
v-if="!displayMedia"
class="w-full h-64 bg-gray-200 animate-pulse rounded"
/>
</div>
</template>
<script setup lang="ts">
import { toRef } from 'vue'
import type { IriProp } from '#cwa/composables/cwa-resource'
import { useCwaImageResource } from '#imports'
const props = defineProps<IriProp>()
const {
getResource,
exposeMeta,
contentUrl,
displayMedia,
handleLoad
} = useCwaImageResource(toRef(props, 'iri'))
const resource = getResource()
defineExpose(exposeMeta)
</script>
Return Values
| Return | Type | Description |
|---|---|---|
getResource | () => Ref<Resource> | Same as useCwaResource |
exposeMeta | object | Pass to defineExpose |
contentUrl | ComputedRef<string | undefined> | Public URL of the uploaded file |
displayMedia | ComputedRef<boolean> | true when contentUrl is set AND the image has loaded |
loaded | Ref<boolean> | Becomes true when handleLoad() is called |
handleLoad | () => void | Call on the <img> element's @load event |
displayMedia prevents showing a broken or partially loaded image. The skeleton shows until both contentUrl exists and the browser fires the load event.
Using a Specific Imagine Filter
Pass imagineFilterName to use a specific image variant as contentUrl:
const { contentUrl, displayMedia, handleLoad } = useCwaImageResource(
toRef(props, 'iri'),
{ imagineFilterName: 'thumbnail' }
)
Without imagineFilterName, contentUrl is the raw uploaded file URL.
Accessing All Imagine Variants
The full map of variants is nested inside _metadata.mediaObjects:
const resource = getResource()
// All variants for the 'file' upload property
const mediaObjects = computed(() => resource.value?.data?._metadata?.mediaObjects?.file)
const thumbnailUrl = mediaObjects.value?.thumbnail?.contentUrl
const heroUrl = mediaObjects.value?.hero?.contentUrl
const originalUrl = mediaObjects.value?.contentUrl
The key under mediaObjects is the PHP property name from #[UploadableField]. Variant keys match the Imagine filter names configured on the PHP entity.
Admin Upload Tab
<!-- app/cwa/components/Image/admin/Image.vue -->
<template>
<div class="p-4">
<CwaUiFormFile
v-model="filenameInputModel"
label="Upload Image"
:disabled="updating"
:file-exists="fileExists"
@change="handleInputChangeFile"
@delete="handleInputDeleteFile"
/>
</div>
</template>
<script setup lang="ts">
import { toRef } from 'vue'
import type { IriProp } from '#cwa/composables/cwa-resource'
import { useCwaResourceManagerTab, useCwaResourceUpload } from '#imports'
const props = defineProps<IriProp>()
const { exposeMeta, iri } = useCwaResourceManagerTab({ name: 'Image', order: 1 })
const {
filenameInputModel,
updating,
fileExists,
handleInputChangeFile,
handleInputDeleteFile
} = useCwaResourceUpload(iri, 'file') // 'file' = the PHP property name
defineExpose(exposeMeta)
</script>
useCwaResourceUpload(iri, propertyName) handles file selection, multipart upload to {iri}/upload, and deletion via PATCH.
Video, PDF, and Other Files
The same pattern works for any file type. For non-image files, displayMedia is true as soon as contentUrl is available (no image load event to wait for):
<template>
<a v-if="contentUrl" :href="contentUrl" download>
Download PDF
</a>
</template>
<script setup lang="ts">
const { getResource, exposeMeta, contentUrl } = useCwaImageResource(toRef(props, 'iri'))
const resource = getResource()
defineExpose(exposeMeta)
</script>
For video:
<video v-if="contentUrl" :src="contentUrl" controls class="w-full" />
Transition While Loading
<style>
.fade-enter-active, .fade-leave-active { transition: opacity 0.3s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>
The <Transition name="fade"> wrapping the <NuxtImg> produces a smooth fade-in once the image loads.