Skip to content

Commit d0492ff

Browse files
committed
feat: DrupalImage component for rendering responsive images hosted by Drupal
1 parent 9b60e4e commit d0492ff

File tree

6 files changed

+118
-3
lines changed

6 files changed

+118
-3
lines changed

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { useImageUrl } from './composables/index.js';
2+
import { DrupalImage } from './runtime/components/index.js';
3+
import type { ImageStyle } from './types/index.js';
24

3-
export { useImageUrl };
5+
export { useImageUrl, DrupalImage };
6+
export type { ImageStyle };
47

58
// Export the module as default export
69
export { default } from './module.js';

src/module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ export default defineNuxtModule<ModuleOptions>({
1616
setup(options, nuxt) {
1717
const resolver = createResolver(import.meta.url)
1818

19-
// Add composables auto-import
19+
// Add composables and components auto-import
2020
nuxt.hook('imports:dirs', (dirs) => {
2121
dirs.push(resolver.resolve('./composables'))
22+
dirs.push(resolver.resolve('./runtime/components'))
2223
})
2324

2425
// Add plugin to support Nuxt 2 with Bridge
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<template>
2+
<picture>
3+
<source :data-srcset="srcSetWebp" type="image/webp" sizes="auto">
4+
<source :data-srcset="srcSetDefault" type="image/jpeg" sizes="auto">
5+
<img
6+
ref="img"
7+
data-sizes="auto"
8+
:alt="alt || altFallback"
9+
:width="width || undefined"
10+
:height="height || undefined"
11+
class="lazyload"
12+
src="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
13+
>
14+
</picture>
15+
</template>
16+
17+
<script lang="ts" setup>
18+
import { computed, ref, watch } from 'vue'
19+
import type { Ref } from 'vue'
20+
import { useImageUrl } from '../../composables/index.js'
21+
import type { ImageStyle } from '../../types/index.js'
22+
23+
const img: Ref<HTMLImageElement | null> = ref(null)
24+
const imageStyleBase = 'default'
25+
26+
export interface Props {
27+
uri: string
28+
width?: number | null
29+
height?: number | null
30+
alt?: string
31+
altFallback?: string
32+
sizes?: string
33+
imageStyles?: ImageStyle[]
34+
}
35+
36+
const props = withDefaults(defineProps<Props>(), {
37+
width: null,
38+
height: null,
39+
alt: '',
40+
altFallback: '',
41+
sizes: '100vw',
42+
imageStyles: () => {
43+
return [
44+
{ name: `${imageStyleBase}_xs`, width: 320 },
45+
{ name: `${imageStyleBase}_s`, width: 640 },
46+
{ name: `${imageStyleBase}_m`, width: 960 },
47+
{ name: `${imageStyleBase}_l`, width: 1280 },
48+
{ name: `${imageStyleBase}_xl`, width: 1440 },
49+
{ name: `${imageStyleBase}_xxl`, width: 1920 },
50+
{ name: `${imageStyleBase}_xxxl`, width: 2560 }
51+
]
52+
}
53+
})
54+
55+
const srcSetWebp = computed(() => {
56+
return srcSet('.webp')
57+
})
58+
59+
const srcSetDefault = computed(() => {
60+
return srcSet()
61+
})
62+
63+
function srcSet (suffix: string = ''): string {
64+
const srcSet: string[] = []
65+
props.imageStyles.forEach((imageStyle) => {
66+
const imageUrl = buildImageUrl(imageStyle, suffix)
67+
if (typeof imageUrl === 'string') {
68+
srcSet.push(imageUrl)
69+
}
70+
})
71+
return srcSet.join(', ')
72+
}
73+
74+
function buildImageUrl (style: ImageStyle, suffix: string = ''): string|null {
75+
if (typeof props.uri === 'string') {
76+
return `${useImageUrl(props.uri, style.name)}${suffix} ${
77+
style.width
78+
}w`
79+
}
80+
return null
81+
}
82+
83+
watch(
84+
() => props.uri,
85+
() => {
86+
img.value?.classList.add('lazyload')
87+
}
88+
)
89+
</script>
90+
91+
<style scoped>
92+
picture,
93+
img {
94+
display: block;
95+
width: 100%;
96+
}
97+
</style>

src/runtime/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as DrupalImage } from './DrupalImage.vue'

src/runtime/plugin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import useImageUrl from '../composables/useImageUrl.js';
2+
import { DrupalImage } from './components/index.js';
23

34
// Type declarations for Nuxt plugin system
45
declare const defineNuxtPlugin: (fn: (nuxtApp: any) => void) => any
56

67
export default defineNuxtPlugin((nuxtApp: any) => {
7-
// Make composables available via the nuxtApp instance
8+
// Make composables and components available via the nuxtApp instance
89
// This is mainly for Nuxt 2 compatibility
910
nuxtApp.provide('useImageUrl', useImageUrl)
11+
nuxtApp.vueApp?.component('DrupalImage', DrupalImage)
1012
})

src/types/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Type definitions for the nuxt-drupal-image package
3+
*/
4+
5+
/**
6+
* Represents an image style configuration
7+
*/
8+
export interface ImageStyle {
9+
name: string;
10+
width: number;
11+
}

0 commit comments

Comments
 (0)