Image sizes generation
This commit is contained in:
parent
ab2032ff0c
commit
a4ad2d0f21
|
@ -7,6 +7,7 @@ import { isNotEmpty, isValidPayloadImage, isValidPayloadMedia } from "../../../u
|
|||
import {
|
||||
convertAttributesToEndpointAttributes,
|
||||
convertCreditsToEndpointCredits,
|
||||
convertMediaThumbnailToEndpointMediaThumbnail,
|
||||
convertRTCToEndpointRTC,
|
||||
getLanguageId,
|
||||
} from "../../../utils/endpoints";
|
||||
|
@ -77,6 +78,8 @@ export const convertAudioToEndpointAudio = ({
|
|||
...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}),
|
||||
})) ?? [],
|
||||
duration,
|
||||
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
|
||||
...(isValidPayloadImage(thumbnail)
|
||||
? { thumbnail: convertMediaThumbnailToEndpointMediaThumbnail(thumbnail) }
|
||||
: {}),
|
||||
credits: convertCreditsToEndpointCredits(credits),
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
} from "../../../utils/asserts";
|
||||
import {
|
||||
convertAttributesToEndpointAttributes,
|
||||
convertScanToEndpointScanImage,
|
||||
convertSourceToEndpointSource,
|
||||
getDomainFromUrl,
|
||||
} from "../../../utils/endpoints";
|
||||
|
@ -147,29 +148,34 @@ const handleGallery = (gallery: Collectible["gallery"]): EndpointCollectible["ga
|
|||
};
|
||||
|
||||
const handleScans = (scans: Collectible["scans"]): EndpointCollectible["scans"] => {
|
||||
const result =
|
||||
scans?.pages?.flatMap(({ image }) => {
|
||||
if (!isValidPayloadImage(image)) return [];
|
||||
return image;
|
||||
}) ?? [];
|
||||
if (!scans) return;
|
||||
|
||||
const totalCount =
|
||||
Object.keys(scans?.cover ?? {}).length +
|
||||
Object.keys(scans?.dustjacket ?? {}).length +
|
||||
Object.keys(scans?.obi ?? {}).length +
|
||||
result.length;
|
||||
(scans.pages ?? []).length;
|
||||
|
||||
const result =
|
||||
scans?.pages?.flatMap(({ image, page }) => {
|
||||
if (!isValidPayloadImage(image)) return [];
|
||||
return { image, index: page.toString() };
|
||||
}) ?? [];
|
||||
|
||||
if (isValidPayloadImage(scans?.cover?.front)) {
|
||||
result.push(scans.cover.front);
|
||||
result.push({ image: scans.cover.front, index: "cover-front" });
|
||||
}
|
||||
|
||||
if (isValidPayloadImage(scans?.dustjacket?.front)) {
|
||||
result.push(scans.dustjacket.front);
|
||||
result.push({ image: scans.dustjacket.front, index: "dustjacket-front" });
|
||||
}
|
||||
|
||||
const thumbnail = result?.[0];
|
||||
if (!thumbnail || !isValidPayloadImage(thumbnail)) return;
|
||||
return { count: totalCount, thumbnail };
|
||||
if (!thumbnail || !isValidPayloadImage(thumbnail.image)) return;
|
||||
return {
|
||||
count: totalCount,
|
||||
thumbnail: convertScanToEndpointScanImage(thumbnail.image, thumbnail.index),
|
||||
};
|
||||
};
|
||||
|
||||
const handleContents = (contents: Collectible["contents"]): EndpointCollectible["contents"] => {
|
||||
|
|
|
@ -4,7 +4,10 @@ import { EndpointCollectibleScanPage } from "../../../sdk";
|
|||
import { Collectible, Scan } from "../../../types/collections";
|
||||
import { CollectionEndpoint } from "../../../types/payload";
|
||||
import { isDefined, isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
|
||||
import { convertSourceToEndpointSource } from "../../../utils/endpoints";
|
||||
import {
|
||||
convertScanToEndpointScanImage,
|
||||
convertSourceToEndpointSource,
|
||||
} from "../../../utils/endpoints";
|
||||
import { convertImageToEndpointImage } from "../../Images/endpoints/getByID";
|
||||
|
||||
export const getBySlugEndpointScanPage: CollectionEndpoint = {
|
||||
|
@ -51,7 +54,7 @@ export const getBySlugEndpointScanPage: CollectionEndpoint = {
|
|||
const nextIndex = getNextIndex(index, collectible.scans);
|
||||
|
||||
const scanPage: EndpointCollectibleScanPage = {
|
||||
image: { ...image, index },
|
||||
image: convertScanToEndpointScanImage(image, index),
|
||||
parentPages: convertSourceToEndpointSource({ scans: [collectible] }),
|
||||
slug,
|
||||
...(isValidPayloadImage(collectible.thumbnail)
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Collectible } from "../../../types/collections";
|
|||
import { isNotEmpty, isPayloadType, isValidPayloadImage } from "../../../utils/asserts";
|
||||
import {
|
||||
convertCreditsToEndpointCredits,
|
||||
convertScanToEndpointScanImage,
|
||||
convertSourceToEndpointSource,
|
||||
} from "../../../utils/endpoints";
|
||||
import { convertImageToEndpointImage } from "../../Images/endpoints/getByID";
|
||||
|
@ -51,7 +52,7 @@ const handleScans = ({
|
|||
credits: convertCreditsToEndpointCredits(credits),
|
||||
pages:
|
||||
pages?.flatMap(({ image, page }) =>
|
||||
isValidPayloadImage(image) ? { ...image, index: page.toString() } : []
|
||||
isValidPayloadImage(image) ? convertScanToEndpointScanImage(image, page.toString()) : []
|
||||
) ?? [],
|
||||
...(coverEnabled && cover ? { cover: handleCover(cover) } : {}),
|
||||
...(dustjacketEnabled && dustjacket ? { dustjacket: handleDustjacket(dustjacket) } : {}),
|
||||
|
@ -69,25 +70,35 @@ const handleCover = ({
|
|||
insideFront,
|
||||
spine,
|
||||
}: NonNullable<NonNullable<Collectible["scans"]>["cover"]>): EndpointCollectibleScans["cover"] => ({
|
||||
...(isValidPayloadImage(back) ? { back: { ...back, index: "cover-back" } } : {}),
|
||||
...(isValidPayloadImage(flapBack) ? { flapBack: { ...flapBack, index: "cover-flap-back" } } : {}),
|
||||
...(isValidPayloadImage(flapFront)
|
||||
? { flapFront: { ...flapFront, index: "cover-flap-front" } }
|
||||
...(isValidPayloadImage(back)
|
||||
? { back: convertScanToEndpointScanImage(back, "cover-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(flapBack)
|
||||
? { flapBack: convertScanToEndpointScanImage(flapBack, "cover-flap-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(flapFront)
|
||||
? { flapFront: convertScanToEndpointScanImage(flapFront, "cover-flap-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(front)
|
||||
? { front: convertScanToEndpointScanImage(front, "cover-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(front) ? { front: { ...front, index: "cover-front" } } : {}),
|
||||
...(isValidPayloadImage(insideBack)
|
||||
? { insideBack: { ...insideBack, index: "cover-inside-back" } }
|
||||
? { insideBack: convertScanToEndpointScanImage(insideBack, "cover-inside-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFlapBack)
|
||||
? { insideFlapBack: { ...insideFlapBack, index: "cover-inside-flap-back" } }
|
||||
? { insideFlapBack: convertScanToEndpointScanImage(insideFlapBack, "cover-inside-flap-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFlapFront)
|
||||
? { insideFlapFront: { ...insideFlapFront, index: "cover-inside-flap-front" } }
|
||||
? {
|
||||
insideFlapFront: convertScanToEndpointScanImage(insideFlapFront, "cover-inside-flap-front"),
|
||||
}
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFront)
|
||||
? { insideFront: { ...insideFront, index: "cover-inside-front" } }
|
||||
? { insideFront: convertScanToEndpointScanImage(insideFront, "cover-inside-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(spine)
|
||||
? { spine: convertScanToEndpointScanImage(spine, "cover-spine") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(spine) ? { spine: { ...spine, index: "cover-spine" } } : {}),
|
||||
});
|
||||
|
||||
const handleDustjacket = ({
|
||||
|
@ -104,29 +115,45 @@ const handleDustjacket = ({
|
|||
}: NonNullable<
|
||||
NonNullable<Collectible["scans"]>["dustjacket"]
|
||||
>): EndpointCollectibleScans["dustjacket"] => ({
|
||||
...(isValidPayloadImage(back) ? { back: { ...back, index: "dustjacket-back" } } : {}),
|
||||
...(isValidPayloadImage(back)
|
||||
? { back: convertScanToEndpointScanImage(back, "dustjacket-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(flapBack)
|
||||
? { flapBack: { ...flapBack, index: "dustjacket-flap-back" } }
|
||||
? { flapBack: convertScanToEndpointScanImage(flapBack, "dustjacket-flap-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(flapFront)
|
||||
? { flapFront: { ...flapFront, index: "dustjacket-flap-front" } }
|
||||
? { flapFront: convertScanToEndpointScanImage(flapFront, "dustjacket-flap-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(front)
|
||||
? { front: convertScanToEndpointScanImage(front, "dustjacket-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(front) ? { front: { ...front, index: "dustjacket-front" } } : {}),
|
||||
...(isValidPayloadImage(insideBack)
|
||||
? { insideBack: { ...insideBack, index: "dustjacket-inside-back" } }
|
||||
? { insideBack: convertScanToEndpointScanImage(insideBack, "dustjacket-inside-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFlapBack)
|
||||
? { insideFlapBack: { ...insideFlapBack, index: "dustjacket-inside-flap-back" } }
|
||||
? {
|
||||
insideFlapBack: convertScanToEndpointScanImage(
|
||||
insideFlapBack,
|
||||
"dustjacket-inside-flap-back"
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFlapFront)
|
||||
? { insideFlapFront: { ...insideFlapFront, index: "dustjacket-inside-flap-front" } }
|
||||
? {
|
||||
insideFlapFront: convertScanToEndpointScanImage(
|
||||
insideFlapFront,
|
||||
"dustjacket-inside-flap-front"
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFront)
|
||||
? { insideFront: { ...insideFront, index: "dustjacket-inside-front" } }
|
||||
? { insideFront: convertScanToEndpointScanImage(insideFront, "dustjacket-inside-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(spine)
|
||||
? { spine: convertScanToEndpointScanImage(spine, "dustjacket-spine") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(spine) ? { spine: { ...spine, index: "dustjacket-spine" } } : {}),
|
||||
...(isValidPayloadImage(insideSpine)
|
||||
? { insideSpine: { ...insideSpine, index: "dustjacket-inside-spine" } }
|
||||
? { insideSpine: convertScanToEndpointScanImage(insideSpine, "dustjacket-inside-spine") }
|
||||
: {}),
|
||||
});
|
||||
|
||||
|
@ -142,26 +169,32 @@ const handleObi = ({
|
|||
insideSpine,
|
||||
spine,
|
||||
}: NonNullable<NonNullable<Collectible["scans"]>["obi"]>): EndpointCollectibleScans["obi"] => ({
|
||||
...(isValidPayloadImage(back) ? { back: { ...back, index: "obi-back" } } : {}),
|
||||
...(isValidPayloadImage(flapBack) ? { flapBack: { ...flapBack, index: "obi-flap-back" } } : {}),
|
||||
...(isValidPayloadImage(flapFront)
|
||||
? { flapFront: { ...flapFront, index: "obi-flap-front" } }
|
||||
...(isValidPayloadImage(back) ? { back: convertScanToEndpointScanImage(back, "obi-back") } : {}),
|
||||
...(isValidPayloadImage(flapBack)
|
||||
? { flapBack: convertScanToEndpointScanImage(flapBack, "obi-flap-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(flapFront)
|
||||
? { flapFront: convertScanToEndpointScanImage(flapFront, "obi-flap-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(front)
|
||||
? { front: convertScanToEndpointScanImage(front, "obi-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(front) ? { front: { ...front, index: "obi-front" } } : {}),
|
||||
...(isValidPayloadImage(insideBack)
|
||||
? { insideBack: { ...insideBack, index: "obi-inside-back" } }
|
||||
? { insideBack: convertScanToEndpointScanImage(insideBack, "obi-inside-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFlapBack)
|
||||
? { insideFlapBack: { ...insideFlapBack, index: "obi-inside-flap-back" } }
|
||||
? { insideFlapBack: convertScanToEndpointScanImage(insideFlapBack, "obi-inside-flap-back") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFlapFront)
|
||||
? { insideFlapFront: { ...insideFlapFront, index: "obi-inside-flap-front" } }
|
||||
? { insideFlapFront: convertScanToEndpointScanImage(insideFlapFront, "obi-inside-flap-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(insideFront)
|
||||
? { insideFront: { ...insideFront, index: "obi-inside-front" } }
|
||||
? { insideFront: convertScanToEndpointScanImage(insideFront, "obi-inside-front") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(spine)
|
||||
? { spine: convertScanToEndpointScanImage(spine, "obi-spine") }
|
||||
: {}),
|
||||
...(isValidPayloadImage(spine) ? { spine: { ...spine, index: "obi-spine" } } : {}),
|
||||
...(isValidPayloadImage(insideSpine)
|
||||
? { insideSpine: { ...insideSpine, index: "obi-inside-spine" } }
|
||||
? { insideSpine: convertScanToEndpointScanImage(insideSpine, "obi-inside-spine") }
|
||||
: {}),
|
||||
});
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import { Collections } from "../../constants";
|
||||
import { createImageSizesRegenerationEndpoint } from "../../endpoints/imageSizesRegenerationEndpoint";
|
||||
import { attributesField } from "../../fields/attributesField/attributesField";
|
||||
import { creditsField } from "../../fields/creditsField/creditsField";
|
||||
import { rowField } from "../../fields/rowField/rowField";
|
||||
import { translatedFields } from "../../fields/translatedFields/translatedFields";
|
||||
import { createEditor } from "../../utils/editor";
|
||||
import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig";
|
||||
import {
|
||||
buildImageCollectionConfig,
|
||||
generateOpenGraphSize,
|
||||
generateWebpSize,
|
||||
} from "../../utils/imageCollectionConfig";
|
||||
import { getByID } from "./endpoints/getByID";
|
||||
|
||||
const fields = {
|
||||
|
@ -34,18 +39,17 @@ export const Images = buildImageCollectionConfig({
|
|||
},
|
||||
upload: {
|
||||
imageSizes: [
|
||||
{
|
||||
name: "og",
|
||||
height: 750,
|
||||
width: 1125,
|
||||
formatOptions: {
|
||||
format: "jpg",
|
||||
options: { progressive: true, mozjpeg: true, compressionLevel: 9, quality: 60 },
|
||||
},
|
||||
},
|
||||
generateOpenGraphSize(),
|
||||
generateWebpSize(200, 60),
|
||||
generateWebpSize(320, 60),
|
||||
generateWebpSize(480, 70),
|
||||
generateWebpSize(800, 70),
|
||||
generateWebpSize(1280, 85),
|
||||
generateWebpSize(1920, 85),
|
||||
generateWebpSize(2560, 90),
|
||||
],
|
||||
},
|
||||
endpoints: [getByID],
|
||||
endpoints: [getByID, createImageSizesRegenerationEndpoint(Collections.Images)],
|
||||
fields: [
|
||||
translatedFields({
|
||||
name: fields.translations,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
convertAttributesToEndpointAttributes,
|
||||
convertCreditsToEndpointCredits,
|
||||
convertRTCToEndpointRTC,
|
||||
convertSizesToEndpointImageSize,
|
||||
getLanguageId,
|
||||
} from "../../../utils/endpoints";
|
||||
|
||||
|
@ -59,6 +60,7 @@ export const convertImageToEndpointImage = ({
|
|||
filesize,
|
||||
id,
|
||||
credits,
|
||||
sizes,
|
||||
}: Image & PayloadImage): EndpointImage => ({
|
||||
url,
|
||||
width,
|
||||
|
@ -79,4 +81,17 @@ export const convertImageToEndpointImage = ({
|
|||
...(isNotEmpty(description) ? { description: convertRTCToEndpointRTC(description) } : {}),
|
||||
})) ?? [],
|
||||
credits: convertCreditsToEndpointCredits(credits),
|
||||
sizes: convertSizesToEndpointImageSize(
|
||||
[
|
||||
sizes?.["200w"],
|
||||
sizes?.["320w"],
|
||||
sizes?.["480w"],
|
||||
sizes?.["800w"],
|
||||
sizes?.["1280w"],
|
||||
sizes?.["1920w"],
|
||||
sizes?.["2560w"],
|
||||
{ url, width, height, filename, filesize, mimeType },
|
||||
],
|
||||
[200, 320, 480, 800, 1280, 1920, 2560]
|
||||
),
|
||||
});
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import { shownOnlyToAdmin } from "../../accesses/collections/shownOnlyToAdmin";
|
||||
import { Collections } from "../../constants";
|
||||
import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig";
|
||||
import { createImageSizesRegenerationEndpoint } from "../../endpoints/imageSizesRegenerationEndpoint";
|
||||
import {
|
||||
buildImageCollectionConfig,
|
||||
generateOpenGraphSize,
|
||||
generateWebpSize,
|
||||
} from "../../utils/imageCollectionConfig";
|
||||
|
||||
const fields = {
|
||||
filename: "filename",
|
||||
|
@ -16,17 +21,17 @@ export const MediaThumbnails = buildImageCollectionConfig({
|
|||
plural: "Media Thumbnails",
|
||||
},
|
||||
admin: { defaultColumns: [fields.filename, fields.updatedAt], hidden: shownOnlyToAdmin },
|
||||
endpoints: [createImageSizesRegenerationEndpoint(Collections.MediaThumbnails)],
|
||||
upload: {
|
||||
imageSizes: [
|
||||
{
|
||||
name: "og",
|
||||
height: 750,
|
||||
width: 1125,
|
||||
formatOptions: {
|
||||
format: "jpg",
|
||||
options: { progressive: true, mozjpeg: true, compressionLevel: 9, quality: 60 },
|
||||
},
|
||||
},
|
||||
generateOpenGraphSize(),
|
||||
generateWebpSize(200, 60),
|
||||
generateWebpSize(320, 60),
|
||||
generateWebpSize(480, 70),
|
||||
generateWebpSize(800, 70),
|
||||
generateWebpSize(1280, 85),
|
||||
generateWebpSize(1920, 85),
|
||||
generateWebpSize(2560, 90),
|
||||
],
|
||||
},
|
||||
fields: [],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { shownOnlyToAdmin } from "../../accesses/collections/shownOnlyToAdmin";
|
||||
import { Collections } from "../../constants";
|
||||
import { buildImageCollectionConfig } from "../../utils/imageCollectionConfig";
|
||||
import { createImageSizesRegenerationEndpoint } from "../../endpoints/imageSizesRegenerationEndpoint";
|
||||
import { buildImageCollectionConfig, generateWebpSize } from "../../utils/imageCollectionConfig";
|
||||
|
||||
const fields = {
|
||||
filename: "filename",
|
||||
|
@ -19,17 +20,13 @@ export const Scans = buildImageCollectionConfig({
|
|||
defaultColumns: [fields.filename, fields.updatedAt],
|
||||
hidden: shownOnlyToAdmin,
|
||||
},
|
||||
endpoints: [createImageSizesRegenerationEndpoint(Collections.Scans)],
|
||||
upload: {
|
||||
imageSizes: [
|
||||
{
|
||||
name: "og",
|
||||
height: 750,
|
||||
width: 1125,
|
||||
formatOptions: {
|
||||
format: "jpg",
|
||||
options: { progressive: true, mozjpeg: true, compressionLevel: 9, quality: 60 },
|
||||
},
|
||||
},
|
||||
generateWebpSize(200, 60),
|
||||
generateWebpSize(320, 60),
|
||||
generateWebpSize(480, 70),
|
||||
generateWebpSize(800, 70),
|
||||
],
|
||||
},
|
||||
fields: [],
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
import {
|
||||
convertAttributesToEndpointAttributes,
|
||||
convertCreditsToEndpointCredits,
|
||||
convertMediaThumbnailToEndpointMediaThumbnail,
|
||||
convertRTCToEndpointRTC,
|
||||
getLanguageId,
|
||||
} from "../../../utils/endpoints";
|
||||
|
@ -88,7 +89,9 @@ export const convertVideoToEndpointVideo = ({
|
|||
})) ?? [],
|
||||
|
||||
duration,
|
||||
...(isValidPayloadImage(thumbnail) ? { thumbnail } : {}),
|
||||
...(isValidPayloadImage(thumbnail)
|
||||
? { thumbnail: convertMediaThumbnailToEndpointMediaThumbnail(thumbnail) }
|
||||
: {}),
|
||||
...(platformEnabled && isDefined(platform) && isPayloadType(platform.channel)
|
||||
? {
|
||||
platform: {
|
||||
|
|
|
@ -7,6 +7,9 @@ import { afterChangeWebhook } from "../../hooks/afterChangeWebhook";
|
|||
import { getConfigEndpoint } from "./endpoints/getConfigEndpoint";
|
||||
|
||||
const fields = {
|
||||
homeBackgroundImage: "homeBackgroundImage",
|
||||
timelineBackgroundImage: "timelineBackgroundImage",
|
||||
defaultOpenGraphImage: "defaultOpenGraphImage",
|
||||
homeFolders: "homeFolders",
|
||||
homeFoldersDarkThumbnail: "darkThumbnail",
|
||||
homeFoldersLightThumbnail: "lightThumbnail",
|
||||
|
@ -32,6 +35,26 @@ export const WebsiteConfig: GlobalConfig = {
|
|||
afterChange: [afterChangeWebhook],
|
||||
},
|
||||
fields: [
|
||||
rowField([
|
||||
{
|
||||
name: fields.homeBackgroundImage,
|
||||
type: "upload",
|
||||
relationTo: Collections.Images,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: fields.timelineBackgroundImage,
|
||||
type: "upload",
|
||||
relationTo: Collections.Images,
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: fields.defaultOpenGraphImage,
|
||||
type: "upload",
|
||||
relationTo: Collections.Images,
|
||||
required: true,
|
||||
},
|
||||
]),
|
||||
{
|
||||
name: fields.homeFolders,
|
||||
admin: {
|
||||
|
|
|
@ -20,7 +20,13 @@ export const getConfigEndpoint: CollectionEndpoint = {
|
|||
});
|
||||
}
|
||||
|
||||
const { homeFolders, timeline } = await payload.findGlobal({
|
||||
const {
|
||||
homeFolders,
|
||||
timeline,
|
||||
defaultOpenGraphImage,
|
||||
homeBackgroundImage,
|
||||
timelineBackgroundImage,
|
||||
} = await payload.findGlobal({
|
||||
slug: Collections.WebsiteConfig,
|
||||
});
|
||||
|
||||
|
@ -43,7 +49,11 @@ export const getConfigEndpoint: CollectionEndpoint = {
|
|||
});
|
||||
|
||||
const endpointWebsiteConfig: EndpointWebsiteConfig = {
|
||||
homeFolders:
|
||||
home: {
|
||||
...(isValidPayloadImage(homeBackgroundImage)
|
||||
? { backgroundImage: convertImageToEndpointImage(homeBackgroundImage) }
|
||||
: {}),
|
||||
folders:
|
||||
homeFolders?.flatMap(({ folder, darkThumbnail, lightThumbnail }) => {
|
||||
if (!isPayloadType(folder)) return [];
|
||||
return {
|
||||
|
@ -56,7 +66,11 @@ export const getConfigEndpoint: CollectionEndpoint = {
|
|||
: {}),
|
||||
};
|
||||
}) ?? [],
|
||||
},
|
||||
timeline: {
|
||||
...(isValidPayloadImage(timelineBackgroundImage)
|
||||
? { backgroundImage: convertImageToEndpointImage(timelineBackgroundImage) }
|
||||
: {}),
|
||||
breaks: timeline?.breaks ?? [],
|
||||
eventCount,
|
||||
eras:
|
||||
|
@ -69,6 +83,9 @@ export const getConfigEndpoint: CollectionEndpoint = {
|
|||
};
|
||||
}) ?? [],
|
||||
},
|
||||
...(isValidPayloadImage(defaultOpenGraphImage)
|
||||
? { defaultOpenGraphImage: convertImageToEndpointImage(defaultOpenGraphImage) }
|
||||
: {}),
|
||||
};
|
||||
res.status(200).json(endpointWebsiteConfig);
|
||||
},
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import payload from "payload";
|
||||
import { CollectionEndpoint } from "../types/payload";
|
||||
|
||||
export const createImageSizesRegenerationEndpoint = (
|
||||
collection: "images" | "scans" | "media-thumbnails"
|
||||
): CollectionEndpoint => ({
|
||||
path: `/regenerate`,
|
||||
method: "get",
|
||||
handler: async (req, res) => {
|
||||
if (!req.user) {
|
||||
return res.status(403).send({
|
||||
errors: [
|
||||
{
|
||||
message: "You are not allowed to perform this action.",
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
const result = await payload.find({
|
||||
collection,
|
||||
pagination: false,
|
||||
});
|
||||
|
||||
for (const { id, filename } of result.docs) {
|
||||
console.log("Handling", id);
|
||||
|
||||
if (!filename) {
|
||||
throw new Error("No filename!");
|
||||
}
|
||||
|
||||
await payload.update({
|
||||
collection,
|
||||
id,
|
||||
filePath: `./uploads/${collection}/${filename}`,
|
||||
data: {},
|
||||
});
|
||||
}
|
||||
|
||||
res.status(200).send({ message: `Regenerated sizes for ${result.docs.length} images!` });
|
||||
},
|
||||
});
|
|
@ -1,22 +1,8 @@
|
|||
import { Props } from "payload/components/views/Cell";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
import { isUndefined } from "../../utils/asserts";
|
||||
|
||||
const Image = styled.img`
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
object-fit: contain;
|
||||
transition: 0.2s transform;
|
||||
transition-timing-function: cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||
position: absolute;
|
||||
transform: translateY(-50%) scale(1);
|
||||
&:hover {
|
||||
transform: translateY(-50%) scale(3);
|
||||
}
|
||||
`;
|
||||
|
||||
export const Cell = ({ cellData, field, rowData, collection }: Props): JSX.Element => {
|
||||
const [imageURL, setImageURL] = useState<string>();
|
||||
useEffect(() => {
|
||||
|
@ -34,5 +20,13 @@ export const Cell = ({ cellData, field, rowData, collection }: Props): JSX.Eleme
|
|||
[collection.slug, rowData.id]
|
||||
);
|
||||
|
||||
return <Link to={link}>{imageURL ? <Image src={imageURL} /> : "<No Image>"}</Link>;
|
||||
return (
|
||||
<Link to={link}>
|
||||
{imageURL ? (
|
||||
<img className="thumbnail thumbnail--size-small file__thumbnail" src={imageURL} />
|
||||
) : (
|
||||
"<No Image>"
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
|
26
src/sdk.ts
26
src/sdk.ts
|
@ -53,11 +53,15 @@ export type EndpointFolder = {
|
|||
};
|
||||
|
||||
export type EndpointWebsiteConfig = {
|
||||
homeFolders: (EndpointFolder & {
|
||||
home: {
|
||||
backgroundImage?: EndpointImage;
|
||||
folders: (EndpointFolder & {
|
||||
lightThumbnail?: EndpointImage;
|
||||
darkThumbnail?: EndpointImage;
|
||||
})[];
|
||||
};
|
||||
timeline: {
|
||||
backgroundImage?: EndpointImage;
|
||||
breaks: number[];
|
||||
eventCount: number;
|
||||
eras: {
|
||||
|
@ -66,6 +70,7 @@ export type EndpointWebsiteConfig = {
|
|||
name: string;
|
||||
}[];
|
||||
};
|
||||
defaultOpenGraphImage?: EndpointImage;
|
||||
};
|
||||
|
||||
export type EndpointRecorder = {
|
||||
|
@ -176,7 +181,7 @@ export type EndpointCollectible = {
|
|||
backgroundImage?: EndpointImage;
|
||||
nature: CollectibleNature;
|
||||
gallery?: { count: number; thumbnail: EndpointImage };
|
||||
scans?: { count: number; thumbnail: PayloadImage };
|
||||
scans?: { count: number; thumbnail: EndpointScanImage };
|
||||
urls: { url: string; label: string }[];
|
||||
price?: {
|
||||
amount: number;
|
||||
|
@ -341,6 +346,7 @@ export type EndpointCollectibleScanPage = {
|
|||
|
||||
export type EndpointScanImage = PayloadImage & {
|
||||
index: string;
|
||||
sizes: EndpointImageSize[];
|
||||
};
|
||||
|
||||
export type TableOfContentEntry = {
|
||||
|
@ -405,18 +411,26 @@ export type EndpointMedia = {
|
|||
credits: EndpointCredit[];
|
||||
};
|
||||
|
||||
export type EndpointImageSize = {
|
||||
width: number;
|
||||
height: number;
|
||||
url: string;
|
||||
wSize: number;
|
||||
};
|
||||
|
||||
export type EndpointImage = EndpointMedia & {
|
||||
width: number;
|
||||
height: number;
|
||||
sizes: EndpointImageSize[];
|
||||
};
|
||||
|
||||
export type EndpointAudio = EndpointMedia & {
|
||||
thumbnail?: PayloadImage;
|
||||
thumbnail?: EndpointMediaThumbnail;
|
||||
duration: number;
|
||||
};
|
||||
|
||||
export type EndpointVideo = EndpointMedia & {
|
||||
thumbnail?: PayloadImage;
|
||||
thumbnail?: EndpointMediaThumbnail;
|
||||
subtitles: {
|
||||
language: string;
|
||||
url: string;
|
||||
|
@ -436,6 +450,10 @@ export type EndpointVideo = EndpointMedia & {
|
|||
duration: number;
|
||||
};
|
||||
|
||||
export type EndpointMediaThumbnail = PayloadImage & {
|
||||
sizes: EndpointImageSize[];
|
||||
};
|
||||
|
||||
export type PayloadMedia = {
|
||||
url: string;
|
||||
mimeType: string;
|
||||
|
|
|
@ -159,6 +159,62 @@ export interface Image {
|
|||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"200w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"320w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"480w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"800w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"1280w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"1920w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"2560w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
};
|
||||
}
|
||||
/**
|
||||
|
@ -573,7 +629,31 @@ export interface Scan {
|
|||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
og?: {
|
||||
"200w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"320w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"480w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"800w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
|
@ -677,6 +757,62 @@ export interface MediaThumbnail {
|
|||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"200w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"320w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"480w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"800w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"1280w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"1920w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
"2560w"?: {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
};
|
||||
}
|
||||
/**
|
||||
|
@ -923,6 +1059,9 @@ export interface PayloadMigration {
|
|||
*/
|
||||
export interface WebsiteConfig {
|
||||
id: string;
|
||||
homeBackgroundImage: string | Image;
|
||||
timelineBackgroundImage: string | Image;
|
||||
defaultOpenGraphImage: string | Image;
|
||||
homeFolders?:
|
||||
| {
|
||||
lightThumbnail?: string | Image | null;
|
||||
|
|
|
@ -60,3 +60,32 @@ export const isPayloadArrayType = <T extends Object>(
|
|||
export const isPublished = <T extends { _status?: ("draft" | "published") | null }>(
|
||||
object: T
|
||||
): boolean => object._status === "published";
|
||||
|
||||
export type ImageSize = {
|
||||
url?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
mimeType?: string | null;
|
||||
filesize?: number | null;
|
||||
filename?: string | null;
|
||||
};
|
||||
|
||||
export type ValidImageSize = {
|
||||
url: string;
|
||||
width: number;
|
||||
height: number;
|
||||
mimeType: string;
|
||||
filesize: number;
|
||||
filename: string;
|
||||
};
|
||||
|
||||
export const isValidImageSize = (size: ImageSize | undefined): size is ValidImageSize => {
|
||||
if (isUndefined(size)) return false;
|
||||
if (isUndefined(size.url)) return false;
|
||||
if (isUndefined(size.width)) return false;
|
||||
if (isUndefined(size.height)) return false;
|
||||
if (isUndefined(size.mimeType)) return false;
|
||||
if (isUndefined(size.filesize)) return false;
|
||||
if (isUndefined(size.filename)) return false;
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { GeneratedTypes } from "payload";
|
||||
import { CollectionConfig } from "payload/types";
|
||||
import { Collections } from "../constants";
|
||||
import { formatToPascalCase } from "./string";
|
||||
|
||||
type CollectionConfigWithPlugins = CollectionConfig;
|
||||
|
@ -8,7 +8,7 @@ export type BuildCollectionConfig = Omit<
|
|||
CollectionConfigWithPlugins,
|
||||
"slug" | "typescript" | "labels"
|
||||
> & {
|
||||
slug: Collections;
|
||||
slug: keyof GeneratedTypes["collections"];
|
||||
labels: { singular: string; plural: string };
|
||||
};
|
||||
|
||||
|
|
|
@ -22,9 +22,13 @@ import {
|
|||
import {
|
||||
EndpointAttribute,
|
||||
EndpointCredit,
|
||||
EndpointImageSize,
|
||||
EndpointMediaThumbnail,
|
||||
EndpointRole,
|
||||
EndpointScanImage,
|
||||
EndpointSource,
|
||||
EndpointTag,
|
||||
PayloadImage,
|
||||
} from "../sdk";
|
||||
import {
|
||||
Audio,
|
||||
|
@ -34,18 +38,23 @@ import {
|
|||
Folder,
|
||||
Image,
|
||||
Language,
|
||||
MediaThumbnail,
|
||||
NumberBlock,
|
||||
Scan,
|
||||
Tag,
|
||||
TagsBlock,
|
||||
TextBlock,
|
||||
Video,
|
||||
} from "../types/collections";
|
||||
import {
|
||||
ImageSize,
|
||||
ValidImageSize,
|
||||
isDefined,
|
||||
isEmpty,
|
||||
isPayloadArrayType,
|
||||
isPayloadType,
|
||||
isPublished,
|
||||
isValidImageSize,
|
||||
isValidPayloadImage,
|
||||
isValidPayloadMedia,
|
||||
} from "./asserts";
|
||||
|
@ -272,3 +281,90 @@ const convertAttributeToEndpointAttribute = (
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const convertSizesToEndpointImageSize = (
|
||||
sizes: (ImageSize | undefined)[],
|
||||
targetSizes: number[]
|
||||
): EndpointImageSize[] => {
|
||||
if (!sizes) return [];
|
||||
const processedSizes = sizes.filter(isValidImageSize);
|
||||
|
||||
const targetBins: { min: number; target: number; max: number; image: ValidImageSize }[] = [];
|
||||
for (let index = 0; index < targetSizes.length; index++) {
|
||||
const previous = targetSizes[index - 1];
|
||||
const current = targetSizes[index]!;
|
||||
const next = targetSizes[index + 1];
|
||||
|
||||
const min = previous ? previous + (current - previous) / 2 : 0;
|
||||
const max = next ? current + (next - current) / 2 : Infinity;
|
||||
|
||||
const images = processedSizes
|
||||
.filter(({ width }) => width > min && width <= max)
|
||||
.sort((a, b) => a.filesize - b.filesize);
|
||||
|
||||
const smallestImage = images[0];
|
||||
if (!smallestImage) continue;
|
||||
|
||||
targetBins.push({ min, target: current, max, image: smallestImage });
|
||||
}
|
||||
|
||||
return targetBins.map(({ target, image: { height, width, url } }) => ({
|
||||
width,
|
||||
height,
|
||||
url,
|
||||
wSize: target,
|
||||
}));
|
||||
};
|
||||
|
||||
export const convertScanToEndpointScanImage = (
|
||||
{ url, width, height, mimeType, filename, filesize, sizes }: Scan & PayloadImage,
|
||||
index: string
|
||||
): EndpointScanImage => ({
|
||||
index,
|
||||
url,
|
||||
width,
|
||||
height,
|
||||
filename,
|
||||
filesize,
|
||||
mimeType,
|
||||
sizes: convertSizesToEndpointImageSize(
|
||||
[
|
||||
sizes?.["200w"],
|
||||
sizes?.["320w"],
|
||||
sizes?.["480w"],
|
||||
sizes?.["800w"],
|
||||
{ url, width, height, filename, filesize, mimeType },
|
||||
],
|
||||
[200, 320, 480, 800]
|
||||
),
|
||||
});
|
||||
|
||||
export const convertMediaThumbnailToEndpointMediaThumbnail = ({
|
||||
url,
|
||||
width,
|
||||
height,
|
||||
mimeType,
|
||||
filename,
|
||||
filesize,
|
||||
sizes,
|
||||
}: MediaThumbnail & PayloadImage): EndpointMediaThumbnail => ({
|
||||
url,
|
||||
width,
|
||||
height,
|
||||
filename,
|
||||
filesize,
|
||||
mimeType,
|
||||
sizes: convertSizesToEndpointImageSize(
|
||||
[
|
||||
sizes?.["200w"],
|
||||
sizes?.["320w"],
|
||||
sizes?.["480w"],
|
||||
sizes?.["800w"],
|
||||
sizes?.["1280w"],
|
||||
sizes?.["1920w"],
|
||||
sizes?.["2560w"],
|
||||
{ url, width, height, filename, filesize, mimeType },
|
||||
],
|
||||
[200, 320, 480, 800, 1280, 1920, 2560]
|
||||
),
|
||||
});
|
||||
|
|
|
@ -49,3 +49,35 @@ export const buildImageCollectionConfig = ({
|
|||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const generateOpenGraphSize = (): ImageSize => ({
|
||||
name: "og",
|
||||
withoutEnlargement: true,
|
||||
height: 1200,
|
||||
width: 1200,
|
||||
fit: "inside",
|
||||
formatOptions: {
|
||||
format: "jpg",
|
||||
options: {
|
||||
quality: 50,
|
||||
optimizeScans: true,
|
||||
quantizationTable: 2,
|
||||
force: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const generateWebpSize = (maxWidth: number, quality: number): ImageSize => ({
|
||||
name: `${maxWidth}w`,
|
||||
withoutEnlargement: true,
|
||||
width: maxWidth,
|
||||
fit: "inside",
|
||||
formatOptions: {
|
||||
format: "webp",
|
||||
options: {
|
||||
quality,
|
||||
alphaQuality: quality,
|
||||
force: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue