diff --git a/.vscode/settings.json b/.vscode/settings.json index d21d96a..f6eacf4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,7 @@ "editor.codeActionsOnSave": { "quickfix.biome": "explicit" }, - "astro.content-intellisense": true, + "astro.content-intellisense": false, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, diff --git a/astro.config.ts b/astro.config.ts index 9294760..9df74d5 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -21,9 +21,6 @@ export default defineConfig({ domains: ['localhost', '127.0.0.1'], service: !options.isProd() ? { entrypoint: './plugins/resize', config: {} } : undefined, }, - experimental: { - contentIntellisense: true, - }, env: { schema: { // Postgres Database diff --git a/package-lock.json b/package-lock.json index 3815e6e..21e7a7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "astro": "^5.0.1", "drizzle-orm": "^0.37.0", "fuse.js": "^7.0.0", + "glob": "^11.0.0", "lodash": "^4.17.21", "luxon": "^3.5.0", "marked": "^15.0.3", @@ -1276,7 +1277,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -1294,14 +1294,12 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -1319,7 +1317,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -2553,7 +2550,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/balloon-css": { @@ -2622,7 +2618,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -2940,7 +2935,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -3231,7 +3225,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, "license": "MIT" }, "node_modules/ee-first": { @@ -3640,7 +3633,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", @@ -3717,7 +3709,6 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", - "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -4256,14 +4247,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/jackspeak": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -4379,7 +4368,6 @@ "version": "11.0.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", - "dev": true, "license": "ISC", "engines": { "node": "20 || >=22" @@ -5544,7 +5532,6 @@ "version": "10.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -5560,7 +5547,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -5773,7 +5759,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parse-entities": { @@ -5852,7 +5837,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -5862,7 +5846,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", @@ -6964,7 +6947,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -6977,7 +6959,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7001,7 +6982,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -7106,7 +7086,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -7121,7 +7100,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7131,14 +7109,12 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -7181,7 +7157,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -7194,7 +7169,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8343,7 +8317,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -8413,7 +8386,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -8431,7 +8403,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8441,7 +8412,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -8457,14 +8427,12 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -8479,7 +8447,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" diff --git a/package.json b/package.json index 6cf867f..de013af 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "astro": "^5.0.1", "drizzle-orm": "^0.37.0", "fuse.js": "^7.0.0", + "glob": "^11.0.0", "lodash": "^4.17.21", "luxon": "^3.5.0", "marked": "^15.0.3", diff --git a/plugins/images.ts b/plugins/images.ts index 305426c..f3f9890 100644 --- a/plugins/images.ts +++ b/plugins/images.ts @@ -1,9 +1,13 @@ import type { Literal, Node, Parent } from 'unist'; import { selectAll } from 'unist-util-select'; import options from '../options'; -import { imageMetadata } from '../src/helpers/images'; import { urlJoin } from '../src/helpers/tools'; +type LinkNode = Node & { + url: string; + children?: ImageNode[]; +}; + type ImageNode = Parent & { url: string; alt: string; @@ -13,23 +17,25 @@ type ImageNode = Parent & { attributes: (Literal & { name: string })[]; }; -type LinkNode = Node & { - url: string; - children?: ImageNode[]; -}; - export const astroImage = () => { - return async (tree: Node) => { + return (tree: Node) => { // Find all the image node. - const imageNodes = selectAll('image', tree) - .map((node) => node as ImageNode) - .filter((imageNode) => !imageNode.url.startsWith('http')) - .map(transformAstroImage); - - // Process image with blur metadata. - await Promise.all(imageNodes); - // Find all the image link nodes and replace the relative links. + selectAll('image', tree) + .map((node) => node as ImageNode) + .filter((imageNode) => imageNode.url.startsWith('/')) + .map((imageNode) => { + imageNode.type = 'mdxJsxFlowElement'; + imageNode.name = 'Image'; + + imageNode.attributes = [ + { type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt }, + { type: 'mdxJsxAttribute', name: 'src', value: imageNode.url }, + { type: 'mdxJsxAttribute', name: 'width', value: imageNode.width }, + { type: 'mdxJsxAttribute', name: 'height', value: imageNode.height }, + ]; + }); + for (const node of selectAll('link', tree)) { const link = node as LinkNode; if (link.children !== undefined && link.children.length !== 0) { @@ -42,34 +48,3 @@ export const astroImage = () => { return tree; }; }; - -const transformAstroImage = async (imageNode: ImageNode) => { - imageNode.type = 'mdxJsxFlowElement'; - imageNode.name = 'Image'; - - try { - const metadata = await imageMetadata(imageNode.url); - if (metadata == null) { - throw new Error(`Failed to get image metadata: ${imageNode.url}`); - } - - imageNode.attributes = [ - { type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt }, - { type: 'mdxJsxAttribute', name: 'src', value: metadata.src }, - { type: 'mdxJsxAttribute', name: 'width', value: imageNode.width ?? metadata.width }, - { type: 'mdxJsxAttribute', name: 'height', value: imageNode.height ?? metadata.height }, - { type: 'mdxJsxAttribute', name: 'blurDataURL', value: metadata.blurDataURL }, - { type: 'mdxJsxAttribute', name: 'blurWidth', value: metadata.blurWidth }, - { type: 'mdxJsxAttribute', name: 'blurHeight', value: metadata.blurHeight }, - ]; - } catch (error) { - imageNode.attributes = [ - { type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt }, - { - type: 'mdxJsxAttribute', - name: 'src', - value: imageNode.url.startsWith('/') ? urlJoin(options.assetsPrefix(), imageNode.url) : imageNode.url, - }, - ]; - } -}; diff --git a/src/components/image/Image.astro b/src/components/image/Image.astro index af90ae1..f6ea08e 100644 --- a/src/components/image/Image.astro +++ b/src/components/image/Image.astro @@ -1,12 +1,22 @@ --- import { blurStyle, type Image } from '@/helpers/images'; import options from '@/options'; +import { getEntry } from 'astro:content'; interface Props extends Image { alt: string; } -const { alt, src, width, height } = Astro.props; +let { alt, src, width, height, blurDataURL, blurWidth, blurHeight } = Astro.props; +if (src.startsWith('/')) { + const image = await getEntry('images', src); + src = image.data.src; + width = image.data.width; + height = image.data.height; + blurDataURL = image.data.blurDataURL; + blurWidth = image.data.blurWidth; + blurHeight = image.data.blurHeight; +} --- diff --git a/src/components/image/UnstyledImage.astro b/src/components/image/UnstyledImage.astro index 4dc52c2..958b1bf 100644 --- a/src/components/image/UnstyledImage.astro +++ b/src/components/image/UnstyledImage.astro @@ -1,11 +1,16 @@ --- import type { Image } from '@/helpers/images'; +import { getEntry } from 'astro:content'; interface Props extends Image { alt: string; } -const { alt, src } = Astro.props; +let { alt, src } = Astro.props; +if (src.startsWith('/')) { + const image = await getEntry('images', src); + src = image.data.src; +} --- diff --git a/src/content.config.ts b/src/content.config.ts index 2c9059f..91880e1 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -3,6 +3,8 @@ import { urlJoin } from '@/helpers/tools'; import options from '@/options'; import { glob } from 'astro/loaders'; import { defineCollection, z } from 'astro:content'; +import { glob as Glob } from 'glob'; +import path from 'node:path'; export const defaultCover = '/images/default-cover.jpg'; @@ -16,12 +18,7 @@ const slug = () => .max(200) .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/i, 'Invalid slug'); -const image = (fallbackImage: string) => - z - .string() - .optional() - .default(fallbackImage) - .transform((file) => imageMetadata(file)); +const image = (fallbackImage: string) => z.string().optional().default(fallbackImage); // The default toc heading level. const toc = () => @@ -47,6 +44,27 @@ const toc = () => message: 'minHeadingLevel must be less than or equal to maxHeadingLevel', }); +// Images Collection +const imagesCollection = defineCollection({ + loader: async () => { + const publicDirectory = path.join(process.cwd(), 'public'); + const imagePaths = await Glob(path.join(publicDirectory, '**/*.{jpg,jpeg,gif,svg,png,webp}')); + const metas = imagePaths + .map((imagePath) => imagePath.substring(publicDirectory.length)) + .map(async (imagePath) => ({ id: imagePath, ...(await imageMetadata(imagePath)) })); + + return Promise.all(metas); + }, + schema: z.object({ + src: z.string(), + width: z.union([z.string(), z.number()]), + height: z.union([z.string(), z.number()]), + blurDataURL: z.string(), + blurWidth: z.number(), + blurHeight: z.number(), + }), +}); + // Categories Collection const categoriesCollection = defineCollection({ loader: glob({ pattern: '**\/[^_]*.yml', base: './src/content/categories' }), @@ -132,4 +150,5 @@ export const collections = { pages: pagesCollection, posts: postsCollection, tags: tagsCollection, + images: imagesCollection, }; diff --git a/src/helpers/schema.ts b/src/helpers/schema.ts index bcc284f..fb0dc15 100644 --- a/src/helpers/schema.ts +++ b/src/helpers/schema.ts @@ -1,9 +1,11 @@ import { defaultCover } from '@/content.config'; +import type { Image } from '@/helpers/images'; import options from '@/options'; import { getCollection, getEntry, render, type RenderResult } from 'astro:content'; import { pinyin } from 'pinyin-pro'; // Import the collections from the astro content. +const imagesCollection = await getCollection('images'); const categoriesCollection = await getCollection('categories'); const friendsCollection = await getCollection('friends'); const pagesCollection = await getCollection('pages'); @@ -11,17 +13,20 @@ const postsCollection = await getCollection('posts'); const tagsCollection = await getCollection('tags'); // Redefine the types from the astro content. -export type Category = (typeof categoriesCollection)[number]['data'] & { +export type Category = Omit<(typeof categoriesCollection)[number]['data'], 'cover'> & { + cover: Image; counts: number; permalink: string; }; export type Friend = (typeof friendsCollection)[number]['data'][number]; -export type Page = (typeof pagesCollection)[number]['data'] & { +export type Page = Omit<(typeof pagesCollection)[number]['data'], 'cover'> & { + cover: Image; slug: string; permalink: string; render: () => Promise; }; -export type Post = (typeof postsCollection)[number]['data'] & { +export type Post = Omit<(typeof postsCollection)[number]['data'], 'cover'> & { + cover: Image; slug: string; permalink: string; render: () => Promise; @@ -33,36 +38,46 @@ export type Tag = (typeof tagsCollection)[number]['data'][number] & { counts: nu export const friends: Friend[] = friendsCollection.flatMap((friends) => friends.data); // Override the website for local debugging -export const pages: Page[] = pagesCollection - .filter((page) => page.data.published || !options.isProd()) - .map((page) => ({ - slug: page.id, - permalink: `/${page.id}`, - render: async () => await render(await getEntry('pages', page.id)), - ...page.data, - })); -export const posts: Post[] = postsCollection - .filter((post) => post.data.published || !options.isProd()) - .map((post) => ({ - slug: post.id, - permalink: `/posts/${post.id}`, - render: async () => await render(await getEntry('posts', post.id)), - raw: async () => { - const entry = await getEntry('posts', post.id); - return entry.body; - }, - ...post.data, - })) - .sort((left: Post, right: Post) => { - const a = left.date.getTime(); - const b = right.date.getTime(); - return options.settings.post.sort === 'asc' ? a - b : b - a; - }); -export const categories: Category[] = categoriesCollection.map((cat) => ({ - counts: posts.filter((post) => post.category === cat.data.name).length, - permalink: `/cats/${cat.data.slug}`, - ...cat.data, -})); +export const pages: Page[] = await Promise.all( + pagesCollection + .filter((page) => page.data.published || !options.isProd()) + .map(async (page) => ({ + ...page.data, + cover: (await getEntry('images', page.data.cover)).data, + slug: page.id, + permalink: `/${page.id}`, + render: async () => await render(await getEntry('pages', page.id)), + })), +); +export const posts: Post[] = ( + await Promise.all( + postsCollection + .filter((post) => post.data.published || !options.isProd()) + .map(async (post) => ({ + ...post.data, + cover: (await getEntry('images', post.data.cover)).data, + slug: post.id, + permalink: `/posts/${post.id}`, + render: async () => await render(await getEntry('posts', post.id)), + raw: async () => { + const entry = await getEntry('posts', post.id); + return entry.body; + }, + })), + ) +).sort((left: Post, right: Post) => { + const a = left.date.getTime(); + const b = right.date.getTime(); + return options.settings.post.sort === 'asc' ? a - b : b - a; +}); +export const categories: Category[] = await Promise.all( + categoriesCollection.map(async (cat) => ({ + ...cat.data, + cover: (await getEntry('images', cat.data.cover)).data, + counts: posts.filter((post) => post.category === cat.data.name).length, + permalink: `/cats/${cat.data.slug}`, + })), +); export const tags: Tag[] = tagsCollection.flatMap((tags) => { return tags.data.map((tag) => ({ counts: posts.filter((post) => post.tags.includes(tag.name)).length,