new Cloudinary image logic - schema, validation,
This commit is contained in:
parent
c78de3ec28
commit
6ac2261cf1
|
@ -4,7 +4,9 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"validate": "node ./tests/ValidateServices.js",
|
"validate:images": "node ./tests/validateImages.js",
|
||||||
|
"validate:services": "node ./tests/ValidateServices.js",
|
||||||
|
"validate": "pnpm run validate:services && validate:images",
|
||||||
"dev": "pnpm run validate && vite dev --mode development",
|
"dev": "pnpm run validate && vite dev --mode development",
|
||||||
"build": "pnpm run validate && vite build",
|
"build": "pnpm run validate && vite build",
|
||||||
"build-dev": "pnpm run validate && vite build --mode development",
|
"build-dev": "pnpm run validate && vite build --mode development",
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"example_image": {
|
||||||
|
"publicId": "example_image",
|
||||||
|
"transformations": [
|
||||||
|
{ "width": 1200, "height": 627, "crop": "fill", "quality": "auto", "format": "auto" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"another_image": {
|
||||||
|
"publicId": "another_image",
|
||||||
|
"transformations": [
|
||||||
|
{ "width": 800, "height": 600, "crop": "fill", "quality": "auto", "format": "auto" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,49 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "../schema-categories.json",
|
|
||||||
"title": "Vakuslim 48 - zeštíhlující procedura",
|
|
||||||
"description": "A description of a description",
|
|
||||||
"id": "depilace",
|
|
||||||
"image": "",
|
|
||||||
"services": [
|
|
||||||
{
|
|
||||||
"title": "Ošetření horních končetin",
|
|
||||||
"description": "Diagnostika pleti, odlíčení tonizace",
|
|
||||||
"id": "vakuslim-48-zestihlujici-procedura-horni-koncetiny",
|
|
||||||
"image": "",
|
|
||||||
"price": 600,
|
|
||||||
"duration": 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "1 ošetření spodní části těla (břicho, boky, dolní končetiny)",
|
|
||||||
"description": "Diagnostika pleti, odlíčení tonizace",
|
|
||||||
"id": "vakuslim-48-zestihlujici-procedura-spodni-cast-tela",
|
|
||||||
"image": "",
|
|
||||||
"price": 800,
|
|
||||||
"duration": 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "1 ošetření komplet horní-dolní části",
|
|
||||||
"description": "Diagnostika pleti, odlíčení tonizace",
|
|
||||||
"id": "vakuslim-48-zestihlujici-procedura-komplet-horni-dolni-cast",
|
|
||||||
"image": "",
|
|
||||||
"price": 1200,
|
|
||||||
"duration": 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "6 ošetření předplatné kompet",
|
|
||||||
"description": "Diagnostika pleti, odlíčení tonizace",
|
|
||||||
"id": "vakuslim-48-zestihlujici-procedura-6-o-setreni-predplatne-kompet",
|
|
||||||
"image": "",
|
|
||||||
"price": 6600,
|
|
||||||
"duration": 120
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "12 ošetření předplatné komplet",
|
|
||||||
"description": "Diagnostika pleti, odlíčení tonizace",
|
|
||||||
"id": "vakuslim-48-zestihlujici-procedura-12-o-setreni-predplatne-komplet",
|
|
||||||
"image": "",
|
|
||||||
"price": 11000,
|
|
||||||
"duration": 120
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// imageService.ts
|
||||||
|
import cloudinary from 'cloudinary';
|
||||||
|
import imagesData from '$content/images.json';
|
||||||
|
|
||||||
|
cloudinary.v2.config({
|
||||||
|
cloud_name: import.meta.env.VITE_CLOUDINARY_CLOUD_NAME,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getCloudinaryImageUrl = (publicId: string, options: cloudinary.UploadApiOptions = {}) => {
|
||||||
|
const imageData = imagesData[publicId];
|
||||||
|
if (!imageData) {
|
||||||
|
throw new Error(`Image with public ID ${publicId} not found in images.json`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const transformationOptions = {
|
||||||
|
...options,
|
||||||
|
...imageData.transformations,
|
||||||
|
};
|
||||||
|
|
||||||
|
return cloudinary.v2.url(publicId, transformationOptions);
|
||||||
|
};
|
|
@ -0,0 +1,49 @@
|
||||||
|
// uploadImages.ts
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import cloudinary from 'cloudinary';
|
||||||
|
import matter from 'gray-matter';
|
||||||
|
|
||||||
|
cloudinary.v2.config({
|
||||||
|
cloud_name: import.meta.env.VITE_CLOUDINARY_CLOUD_NAME,
|
||||||
|
api_key: import.meta.env.VITE_CLOUDINARY_API_KEY,
|
||||||
|
api_secret: import.meta.env.VITE_CLOUDINARY_API_SECRET,
|
||||||
|
});
|
||||||
|
|
||||||
|
const contentDir = 'src/content';
|
||||||
|
const imagesJsonPath = 'src/content/images.json';
|
||||||
|
|
||||||
|
async function uploadImages() {
|
||||||
|
const imagesData = {};
|
||||||
|
|
||||||
|
// Read all Markdown files in the content directory
|
||||||
|
const mdFiles = fs.readdirSync(contentDir).filter((file) => file.endsWith('.md'));
|
||||||
|
|
||||||
|
for (const mdFile of mdFiles) {
|
||||||
|
const mdFilePath = path.join(contentDir, mdFile);
|
||||||
|
const mdContent = fs.readFileSync(mdFilePath, 'utf-8');
|
||||||
|
const { data, content } = matter(mdContent);
|
||||||
|
|
||||||
|
// Extract relative image paths from the Markdown content
|
||||||
|
const imagePaths = content.match(/\!\[.*?\]\((.*?)\)/g) || [];
|
||||||
|
|
||||||
|
for (const imagePath of imagePaths) {
|
||||||
|
const relativeImagePath = imagePath.match(/\((.*?)\)/)[1];
|
||||||
|
const imageFilePath = path.join(contentDir, relativeImagePath);
|
||||||
|
|
||||||
|
// Upload the image to Cloudinary
|
||||||
|
const uploadResult = await cloudinary.v2.uploader.upload(imageFilePath);
|
||||||
|
|
||||||
|
// Add the image metadata to the imagesData object
|
||||||
|
imagesData[uploadResult.public_id] = {
|
||||||
|
publicId: uploadResult.public_id,
|
||||||
|
// Add any desired transformation options here
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the imagesData to the images.json file
|
||||||
|
fs.writeFileSync(imagesJsonPath, JSON.stringify(imagesData, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadImages();
|
|
@ -0,0 +1,32 @@
|
||||||
|
import cloudinary from 'cloudinary';
|
||||||
|
import imagesData from '$content/images.json';
|
||||||
|
import { env } from '$env/dynamic/private';
|
||||||
|
|
||||||
|
|
||||||
|
cloudinary.v2.config({
|
||||||
|
cloud_name: env.CLOUDINARY_CLOUD_NAME,
|
||||||
|
api_key: env.CLOUDINARY_API_KEY,
|
||||||
|
api_secret: env.CLOUDINARY_API_SECRET,
|
||||||
|
});
|
||||||
|
|
||||||
|
async function validateImages() {
|
||||||
|
const invalidImages = [];
|
||||||
|
|
||||||
|
for (const publicId in imagesData) {
|
||||||
|
try {
|
||||||
|
// Check if the image exists on Cloudinary
|
||||||
|
await cloudinary.v2.api.resource(publicId);
|
||||||
|
} catch (error) {
|
||||||
|
invalidImages.push(publicId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidImages.length > 0) {
|
||||||
|
console.error(`The following images are missing or invalid on Cloudinary: ${invalidImages.join(', ')}`);
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
console.log('All images are valid on Cloudinary.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateImages();
|
Loading…
Reference in New Issue