From 33b36bcba339d6ebfd83397c90b5f48824eb7523 Mon Sep 17 00:00:00 2001 From: pooya parsa Date: Tue, 21 Jun 2022 12:10:37 +0200 Subject: [PATCH] feat: cloudimage provider (#523) Co-authored-by: Amr Hamdy --- docs/content/en/4.providers/cloudimage.md | 75 +++++++++++++++++++++++ playground/nuxt.config.ts | 4 ++ playground/providers.ts | 26 ++++++++ src/provider.ts | 1 + src/runtime/providers/cloudimage.ts | 38 ++++++++++++ src/types/module.ts | 1 + test/providers.ts | 18 ++++-- test/unit/providers.test.ts | 13 ++++ 8 files changed, 170 insertions(+), 6 deletions(-) create mode 100644 docs/content/en/4.providers/cloudimage.md create mode 100644 src/runtime/providers/cloudimage.ts diff --git a/docs/content/en/4.providers/cloudimage.md b/docs/content/en/4.providers/cloudimage.md new file mode 100644 index 000000000..7bf092e02 --- /dev/null +++ b/docs/content/en/4.providers/cloudimage.md @@ -0,0 +1,75 @@ +--- +title: Cloudimage Provider +description: 'Nuxt Image has first class integration with Cloudimage' +navigation: + title: Cloudimage +--- + +Integration between [Cloudimage](https://www.cloudimage.io/en/home) and the image module. + +To use this provider you just need to specify the token of your project in cloudimage. + +```js{}[nuxt.config.js] +export default { + image: { + cloudimage: { + token: 'demo' + } + } +} +``` + +**Note:** Current integration uses API `v7`. + +## Options + +You can override default options: + +### `token` + +- Type: **String** (required) +- Default: `demo` + +Your Cloudimage customer token. [register](https://www.cloudimage.io/en/register_page) for a Cloudimage account to get one. The subscription takes less than a minute and is totally free. + +### `baseURL` + +- Type: **String** + +Your uploads base URL. This alows to shorten your origin image URLs. + +```js{}[nuxt.config.js] +export default { + image: { + cloudimage: { + token: 'demo', + baseURL: 'sample.li' // optional + } + } +} +``` + +### `cdnURL` + +- Type: **String** +- Default: `https://{token}.cloudimg.io/v7` + +## Cloudimage modifiers + +Beside the [standard modifiers](/components/nuxt-img#modifiers), also you can pass Cloudimage-specific [Cloudimage-specific transformation](https://docs.cloudimage.io/go/cloudimage-documentation-v7/en/introduction) params to `modifiers` prop. + +## Cloudimage `fit` values + +Beside [the standard values for `fit` property](/components/nuxt-img#fit) of Nuxt image and Nuxt picture, Cloudimage offers the following for extra resizing params: + +* `crop` - Crops the image to specified dimensions (width and height) and keeps proportions. + +* `face` - Crops the image automatically keeping the most prominent face. + +* `fit` - Resizes the image to fit into a specified width and height box, adds padding (image or solid colour) to keep proportions. + +* `cropfit` - Sets crop or fit resize mode depending on the origin and the desired dimensions. + +* `bound` - Resizes to a given width and height box and keeps proportions. Similar to fit but without adding padding. + +* `boundmin` - Resizes an image while bounding the smaller dimension to the desired width or height while keeping proportions. diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index ca0d6686c..182a43280 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -36,6 +36,10 @@ export default { baseURL: 'https://res.cloudinary.com/nuxt/image/upload/' }, contentful: {}, + cloudimage: { + token: 'demo', + baseURL: 'sample.li' + }, fastly: { baseURL: 'https://www.fastly.io' }, diff --git a/playground/providers.ts b/playground/providers.ts index 7148484ad..ef592b861 100644 --- a/playground/providers.ts +++ b/playground/providers.ts @@ -87,6 +87,32 @@ export const providers: Provider[] = [ } ] }, + // Cloudimage + { + name: 'cloudimage', + samples: [ + { + src: 'bag.jpg', + width: 500, + height: 500, + fit: 'contain' + }, + { + src: 'boat.jpg', + width: 800, + height: 800, + quality: 75, + fit: 'cover' + }, + { + src: 'img.jpg', + width: 300, + height: 300, + format: 'webp', + fit: 'fill' + } + ] + }, // Fastly { name: 'fastly', diff --git a/src/provider.ts b/src/provider.ts index d464a631b..decd7bf4b 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -7,6 +7,7 @@ import { ipxSetup } from './ipx' const BuiltInProviders = [ 'cloudinary', 'contentful', + 'cloudimage', 'fastly', 'glide', 'imagekit', diff --git a/src/runtime/providers/cloudimage.ts b/src/runtime/providers/cloudimage.ts new file mode 100644 index 000000000..d77044610 --- /dev/null +++ b/src/runtime/providers/cloudimage.ts @@ -0,0 +1,38 @@ +import { joinURL } from 'ufo' +import type { ProviderGetImage } from 'src' +import { createOperationsGenerator } from '~image' + +const operationsGenerator = createOperationsGenerator({ + keyMap: { + fit: 'func', + quality: 'q', + format: 'force_format' + }, + valueMap: { + fit: { + cover: 'crop', + contain: 'fit', + fill: 'cover', + inside: 'bound', + outside: 'boundmin' + } + }, + joinWith: '&', + formatter: (key, value) => `${key}=${value}` +}) + +// https://docs.cloudimage.io/go/cloudimage-documentation-v7/en/introduction +export const getImage: ProviderGetImage = (src, { + modifiers = {}, + baseURL = '', + token = 'demo', + cdnURL = '' +} = {}) => { + const operations = operationsGenerator(modifiers) + if (!cdnURL) { + cdnURL = `https://${token}.cloudimg.io/v7` + } + return { + url: joinURL(cdnURL, baseURL, src) + (operations ? ('?' + operations) : '') + } +} diff --git a/src/types/module.ts b/src/types/module.ts index 6d27e60fc..18d5fd486 100644 --- a/src/types/module.ts +++ b/src/types/module.ts @@ -42,6 +42,7 @@ export interface CloudinaryOptions { export interface ImageProviders { cloudinary?: Partial contentful?: any + cloudimage?: any fastly?: any glide?: any gumlet?: any diff --git a/test/providers.ts b/test/providers.ts index c33a7ede1..fb7848ca1 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -14,7 +14,8 @@ export const images = [ netlify: { url: '/test.png' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=100&h=100' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?auto=format' }, - contentful: { url: '/test.png' } + contentful: { url: '/test.png' }, + cloudimage: { url: 'https://demo.cloudimg.io/v7/test.png' } }, { args: ['/test.png', { width: 200 }], @@ -31,7 +32,8 @@ export const images = [ netlify: { url: '/test.png?w=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=100' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&auto=format' }, - contentful: { url: '/test.png?w=200' } + contentful: { url: '/test.png?w=200' }, + cloudimage: { url: 'https://demo.cloudimg.io/v7/test.png?width=200' } }, { args: ['/test.png', { height: 200 }], @@ -48,7 +50,8 @@ export const images = [ netlify: { url: '/test.png?h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=100&h=200' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?h=200&auto=format' }, - contentful: { url: '/test.png?h=200' } + contentful: { url: '/test.png?h=200' }, + cloudimage: { url: 'https://demo.cloudimg.io/v7/test.png?height=200' } }, { args: ['/test.png', { width: 200, height: 200 }], @@ -65,7 +68,8 @@ export const images = [ netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&h=200&auto=format' }, - contentful: { url: '/test.png?w=200&h=200' } + contentful: { url: '/test.png?w=200&h=200' }, + cloudimage: { url: 'https://demo.cloudimg.io/v7/test.png?width=200&height=200' } }, { args: ['/test.png', { width: 200, height: 200, fit: 'contain' }], @@ -82,7 +86,8 @@ export const images = [ netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&h=200&fit=fill&auto=format&bg=ffffff' }, - contentful: { url: '/test.png?w=200&h=200&fit=fill' } + contentful: { url: '/test.png?w=200&h=200&fit=fill' }, + cloudimage: { url: 'https://demo.cloudimg.io/v7/test.png?width=200&height=200&func=fit' } }, { args: ['/test.png', { width: 200, height: 200, fit: 'contain', format: 'jpeg' }], @@ -99,7 +104,8 @@ export const images = [ netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill&fm=jpeg' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&h=200&fit=fill&fm=jpg&bg=ffffff' }, - contentful: { url: '/test.png?w=200&h=200&fit=fill&fm=jpg' } + contentful: { url: '/test.png?w=200&h=200&fit=fill&fm=jpg' }, + cloudimage: { url: 'https://demo.cloudimg.io/v7/test.png?width=200&height=200&func=fit&force_format=jpeg' } } ] as const diff --git a/test/unit/providers.test.ts b/test/unit/providers.test.ts index fda5be74d..66b9dc77b 100644 --- a/test/unit/providers.test.ts +++ b/test/unit/providers.test.ts @@ -15,6 +15,7 @@ import * as netlify from '~/runtime/providers/netlify' import * as prismic from '~/runtime/providers/prismic' import * as sanity from '~/runtime/providers/sanity' import * as contentful from '~/runtime/providers/contentful' +import * as cloudimage from '~/runtime/providers/cloudimage' const emptyContext = { options: {} } as any @@ -257,4 +258,16 @@ describe('Providers', () => { expect(generated).toMatchObject(image.contentful) } }) + + test('cloudimage', () => { + const providerOptions = { + token: 'demo' + } + + for (const image of images) { + const [src, modifiers] = image.args + const generated = cloudimage.getImage(src, { modifiers, ...providerOptions }, emptyContext) + expect(generated).toMatchObject(image.cloudimage) + } + }) })