├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── LICENSE
├── README.md
├── astro.config.mjs
├── index.ts
├── package-lock.json
├── package.json
├── public
├── NotFound.svg
└── favicon.svg
├── src
├── Cloudinary.astro
├── CloudinaryProps.ts
├── env.d.ts
├── index.ts
└── pages
│ └── index.astro
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # build output
2 | dist/
3 | # generated types
4 | .astro/
5 |
6 | # dependencies
7 | node_modules/
8 |
9 | # logs
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 |
16 | # environment variables
17 | .env
18 | .env.production
19 |
20 | # macOS-specific files
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "astro-build.astro-vscode",
4 | "esbenp.prettier-vscode",
5 | "usernamehw.errorlens",
6 | "wix.vscode-import-cost",
7 | "dbaeumer.vscode-eslint",
8 | "bradlc.vscode-tailwindcss",
9 | "streetsidesoftware.code-spell-checker",
10 | "ms-playwright.playwright"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "command": "./node_modules/.bin/astro dev",
6 | "name": "Development server",
7 | "request": "launch",
8 | "type": "node-terminal"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.validate": [
3 | "javascript",
4 | "javascriptreact",
5 | "astro", // Enable .astro
6 | "typescript", // Enable .ts
7 | "typescriptreact" // Enable .tsx
8 | ],
9 | "editor.codeActionsOnSave": {
10 | "source.fixAll.eslint": true
11 | },
12 | "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
13 | "editor.insertSpaces": false,
14 | "editor.detectIndentation": false,
15 | "cSpell.enableFiletypes": ["javascript"],
16 | "cSpell.language": "es,es-ES,en,en-US,en-GB",
17 | "prettier.documentSelectors": ["**/*.astro"]
18 | }
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Eric Risco de la Torre
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # 🚀 Astro Cloudinary Image
4 |
5 | This [Astro](https://astro.build/) component makes it easy to wrap the Cloudinary URL Generator library to dynamically generate and optimize images from the Cloudinary service.
6 |
7 | Pull requests and/or feature requests are very welcome!
8 |
9 | ## 🔥 Motivation
10 |
11 | This project aims to participate in [@midudev](https://www.github.com/midudev) hackathon: [Cloudinary CloudCreate](https://cloudinary.com/blog/cloudinary-cloudcreate-tech-products-hackathon?utm_source=twitter&utm_medium=social-company&utm_campaign=1307&utm_term=194&utm_content=blog_cloudcreate_hackathon), in collaboration with [Cloudinary](https://cloudinary.com/).
12 |
13 | ## 💻 Features
14 |
15 | Below is a short list of features that **Astro Cloudinary Image** offers.
16 |
17 | - ✅ **Crops the image to fit the specified dimensions.**
18 | - ✅ **Scales the image to fill the specified dimensions.**
19 | - ✅ **Scales the image to the specified dimensions.**
20 | - ✅ **Scales the image to fit within the specified dimensions.**
21 | - ✅ **Generates a thumbnail of the image.**
22 | - ✅ **Centers the image around detected faces.**
23 | - ✅ **Automatically detects the subject of the image and centers it.**
24 | - ✅ **Add corner radius from 1px to max (round image)**
25 | - ✅ **Rotate the image**
26 | - ✅ **Applies various effects to the image.**
27 |
28 | ## 🛠️ Installation
29 |
30 | To install Astro Cloudinary Image, run the following command in your terminal:
31 |
32 | ```bash
33 | npm install astro-cloudinary-image
34 | ```
35 |
36 | or if you use yarn:
37 |
38 | ```bash
39 | yarn add astro-cloudinary-image
40 | ```
41 |
42 | or if you use pnpm:
43 |
44 | ```bash
45 | pnpm add astro-cloudinary-image
46 | ```
47 |
48 | ## 💻 How To Use
49 |
50 | 1. In any of your Astro projects, you need to create a `.env` file and add your cloud name on Cloudinary, like:
51 |
52 | ```bash
53 | CLOUDINARY_CLOUD_NAME=XXXXXXX
54 | ```
55 |
56 | Where `XXXXXXX` is your cloud name. Tip: You can find your Cloudinary Cloud Name right on the main Dashboard of your account.
57 |
58 | 2. In any of your Astro pages, import `Cloudinary` and then use the component like:
59 |
60 | ```astro
61 | ---
62 | import { Cloudinary } from 'astro-cloudinary-image';
63 | ---
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | Astro
72 |
73 |
74 |
86 |
87 |
88 | ```
89 | ## 🗺️ Mandatory Props
90 |
91 | 1. `src: string` - The URL of the image to be displayed. This `src` can be a full image url or the Cloudinary identifier on your media library
92 |
93 | 2. `alt: string` - The alt text for the image.
94 |
95 | 3. `errorImage: string` - A URL for a fallback image to display if the src image fails to load.
96 |
97 | ## 🗺️ Optional Props
98 |
99 | 1. `width?: string;` - Sets the width of the image. It accepts a string value that can be a number in pixels (e.g. "100", "50").
100 |
101 | 2. `height?: string;` - Sets the height of the image. It accepts a string value that can be a number in pixels (e.g. "100", "50").
102 |
103 | 3. `resize?:` - Specifies the resizing behavior of the image. It can have one of the following values:
104 |
105 | Resize | Option Description
106 | ------------ | -------------
107 | "crop" | Crops the image to fit the specified dimensions.
108 | "fill" | Scales the image to fill the specified dimensions.
109 | "scale" | Scales the image to the specified dimensions.
110 | "minimumPad" | Scales the image to fit within the specified dimensions, adding padding if necessary.
111 | "fit" | Scales the image to fit within the specified dimensions.
112 | "limitFit" | Scales the image down to fit within the specified dimensions, but doesn't scale it up.
113 | "thumbnail" | Generates a thumbnail of the image.
114 | "limitFill" | Scales the image up or down to fill the specified dimensions, but doesn't crop it.
115 | "minimumFit" | Scales the image up or down to fit within the specified dimensions, but doesn't scale it beyond its original size.
116 | "limitPad" | Scales the image down to fit within the specified dimensions, adding padding if necessary, but doesn't scale it up.
117 | "fillPad" | Scales the image up or down to fill the specified dimensions, adding padding if necessary.
118 |
119 | 4. `Gravity?:` - Specifies the gravity or position of the image. It can have one of the following values:
120 |
121 | Gravity | Option Description
122 | ------------ | -------------
123 | "face" | centers the image around detected faces.
124 | "auto" | automatically detects the subject of the image and centers it.
125 |
126 | 5. `cornerRadius?:` number | "max"; - Specifies the radius of the corners of the image. It accepts a number value that represents the radius in pixels or the string value "max" that sets the maximum possible radius.
127 |
128 | 6. `rotate?:` number; - Rotates the image by a specified angle in degrees.
129 |
130 | 7. `effects?:` - Applies various effects to the image. It can have one or more of the following values:
131 |
132 | Effect | Option Description
133 | ------------ | -------------
134 | "blur" | blurs the image.
135 | "grayscale" | converts the image to grayscale.
136 | "sepia" | adds a sepia tone to the image.
137 | "shadow" | adds a drop shadow to the image.
138 | "colorize" | applies a color overlay to the image.
139 | "oilPaint" | applies an oil painting effect to the image.
140 | "cartoonify" | applies a cartoon effect to the image.
141 | "outline" | adds an outline to the image.
142 | "blackwhite" | converts the image to black and white.
143 | "makeTransparent" | makes the background of the image transparent.
144 | "vectorize" | converts the image to a vector format.
145 | "gradientFade" | applies a gradient fade effect to the image.
146 | "assistColorBlind" | simulates the experience of color blindness.
147 | "backgroundRemoval" | removes the background of the image.
148 | "dropShadow" | adds a drop shadow to the image.
149 |
150 | __**In order to use `backgroundRemoval` you must activate `Cloudinary AI Background Removal` on Addons of your Cloudinary account. The `backgroundRemoval` must be allways the first effect**__
151 |
152 | # ✅ Live Example
153 |
154 | If you want to view live examples of the component, clone this repo and `npm run dev` it.
155 |
156 | ##
157 |
158 | If you want to report any issues or have found a missing feature, please report it on [GitHub](https://github.com/ericrisco/astro-cloudinary-image/issues)!
159 |
160 | Good luck out there, Astronaut. 🚀
161 |
162 |
--------------------------------------------------------------------------------
/astro.config.mjs:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'astro/config';
2 |
3 | // https://astro.build/config
4 | export default defineConfig({});
5 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./src";
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "astro-cloudinary-image",
3 | "version": "0.0.6",
4 | "description": "Adds a Cloudinary image component to Astro",
5 | "homepage": "https://github.com/ericrisco/astro-cloudinary-image#readme",
6 | "bugs": {
7 | "url": "https://github.com/ericrisco/astro-cloudinary-image/issues"
8 | },
9 | "type": "module",
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/ericrisco/astro-cloudinary-image"
13 | },
14 | "exports": {
15 | ".": "./index.ts"
16 | },
17 | "files": [
18 | "src",
19 | "index.ts"
20 | ],
21 | "keywords": [
22 | "astro",
23 | "astro-component",
24 | "cloudinary",
25 | "image",
26 | "images",
27 | "optimization",
28 | "responsive-image",
29 | "astropub"
30 | ],
31 | "author": "Eric Risco de la Torre",
32 | "license": "MIT",
33 | "scripts": {
34 | "dev": "astro dev",
35 | "build": "astro build",
36 | "start": "astro preview",
37 | "format": "prettier -w ./src",
38 | "check:format": "prettier -c ./src",
39 | "release": "standard-version",
40 | "check": "astro check"
41 | },
42 | "devDependencies": {
43 | "astro": "^2.0.14",
44 | "prettier": "^2.8.4",
45 | "prettier-plugin-astro": "^0.8.0",
46 | "standard-version": "^9.5.0"
47 | },
48 | "dependencies": {
49 | "@cloudinary/url-gen": "^1.9.1"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/public/NotFound.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/Cloudinary.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import { Cloudinary } from '@cloudinary/url-gen';
3 | import { imaggaScale, imaggaCrop, crop, fill, scale, minimumPad, fit, pad, limitFit, thumbnail, limitFill, minimumFit, limitPad, fillPad } from "@cloudinary/url-gen/actions/resize";
4 | import { autoGravity, focusOn } from "@cloudinary/url-gen/qualifiers/gravity";
5 | import { FocusOn } from "@cloudinary/url-gen/qualifiers/focusOn";
6 | import { ResizeFillAction } from "@cloudinary/url-gen/actions/resize/ResizeFillAction";
7 | import { byRadius, max } from "@cloudinary/url-gen/actions/roundCorners";
8 | import { byAngle } from "@cloudinary/url-gen/actions/rotate"
9 | import { blur, grayscale, sepia, shadow, colorize, oilPaint, cartoonify, outline, blackwhite, makeTransparent, vectorize, gradientFade, assistColorBlind, backgroundRemoval, dropShadow } from "@cloudinary/url-gen/actions/effect";
10 |
11 | import { type CloudinaryProps } from './CloudinaryProps.js';
12 |
13 | const cloudName = import.meta.env.CLOUDINARY_CLOUD_NAME;
14 |
15 | if(cloudName === undefined || cloudName === null || cloudName === '') {
16 | throw new Error('Cloudinary cloud name is not defined');
17 | }
18 |
19 | const cloudinaryMedia = new Cloudinary({
20 | cloud: {
21 | cloudName: cloudName
22 | }
23 | });
24 |
25 | interface Props extends CloudinaryProps {
26 | src: string;
27 | alt: string;
28 | errorImage: string;
29 | }
30 |
31 | const { ...props } = Astro.props;
32 |
33 | const imageSource = props.src.startsWith('https://')
34 | ? cloudinaryMedia.image(props.src).setDeliveryType('fetch')
35 | : cloudinaryMedia.image(props.src);
36 |
37 | if(props.effects !== undefined && props.effects !== null) {
38 | for(var i=0; i
--------------------------------------------------------------------------------
/src/CloudinaryProps.ts:
--------------------------------------------------------------------------------
1 | export interface CloudinaryProps {
2 |
3 | width?: string;
4 |
5 | height?: string;
6 |
7 | resize?:
8 | | "crop"
9 | | "fill"
10 | | "scale"
11 | | "minimumPad"
12 | | "fit"
13 | | "limitFit"
14 | | "thumbnail"
15 | | "limitFill"
16 | | "minimumFit"
17 | | "limitPad"
18 | | "fillPad";
19 |
20 | gravity?: "face" | "auto";
21 |
22 | cornerRadius?: number | "max";
23 |
24 | rotate?: number;
25 |
26 | effects?: [
27 | | "blur"
28 | | "grayscale"
29 | | "sepia"
30 | | "shadow"
31 | | "colorize"
32 | | "oilPaint"
33 | | "cartoonify"
34 | | "outline"
35 | | "blackwhite"
36 | | "makeTransparent"
37 | | "vectorize"
38 | | "gradientFade"
39 | | "assistColorBlind"
40 | | "removeBackground"
41 | | "backgroundRemoval"
42 | | "dropShadow"
43 | ]
44 |
45 | }
--------------------------------------------------------------------------------
/src/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Cloudinary } from "./Cloudinary.astro";
2 | export type { CloudinaryProps } from "./CloudinaryProps";
3 | export * from "./Cloudinary.astro";
--------------------------------------------------------------------------------
/src/pages/index.astro:
--------------------------------------------------------------------------------
1 | ---
2 | import Cloudinary from "../Cloudinary.astro";
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Astro
12 |
13 |
14 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "astro/tsconfigs/base"
3 | }
4 |
--------------------------------------------------------------------------------