diff options
| author | Valentin Popov <valentin@popov.link> | 2025-06-14 22:25:16 +0300 | 
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2025-06-14 22:25:16 +0300 | 
| commit | a81117972d39df35574bbab809bb590abc874761 (patch) | |
| tree | 41cb25172c7603d2ea0dc275f8d90c72d83bf5a1 | |
| parent | 3d0f4857465e55815809719a4a4438e8a3cd16a0 (diff) | |
| download | popov.link-a81117972d39df35574bbab809bb590abc874761.tar.xz popov.link-a81117972d39df35574bbab809bb590abc874761.zip | |
feat: implement Open Graph image generation and enhance configuration
- Added ogImages integration to generate Open Graph images for blog posts.
- Updated configuration to include Open Graph settings and default preview image.
- Refactored Head component to utilize new preview property for Open Graph meta tags.
- Enhanced blog post schema to include preview image for structured data representation.
- Introduced utility functions for creating Open Graph images with dynamic content.
48 files changed, 1650 insertions, 164 deletions
| diff --git a/astro.config.mjs b/astro.config.mjs index 07e5d30..bbf2ac0 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,11 +1,12 @@  import { defineConfig } from "astro/config";  import { remarkReadingTime } from "./src/plugins/remarkReadingTime"; +import ogImages from "./src/integrations/ogImages";  import sitemap from "@astrojs/sitemap";  export default defineConfig({  	site: "https://popov.link",  	output: "static", -	integrations: [sitemap()], +	integrations: [sitemap(), ogImages()],  	build: {  		inlineStylesheets: "always",  	}, diff --git a/package-lock.json b/package-lock.json index 88140c5..bbd8f34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,15 +11,22 @@          "@astrojs/check": "^0.9.4",          "@astrojs/rss": "^4.0.12",          "@astrojs/sitemap": "^3.4.1", +        "@resvg/resvg-js": "^2.6.2",          "astro": "^5.9.0",          "autoprefixer": "^10.4.21",          "cssnano": "^7.0.7",          "cssnano-preset-advanced": "^7.0.7",          "dayjs": "^1.11.13", +        "geist": "^1.4.2", +        "globby": "^14.1.0", +        "gray-matter": "^4.0.3",          "mdast-util-to-string": "^4.0.0",          "reading-time": "^1.5.0",          "sass": "^1.89.1", +        "satori": "^0.15.2", +        "satori-html": "^0.3.2",          "schema-dts": "^1.1.5", +        "sharp": "^0.34.2",          "typescript": "^5"        },        "devDependencies": { @@ -710,9 +717,9 @@        }      },      "node_modules/@img/sharp-darwin-arm64": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", -      "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz", +      "integrity": "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==",        "cpu": [          "arm64"        ], @@ -728,13 +735,13 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-darwin-arm64": "1.0.4" +        "@img/sharp-libvips-darwin-arm64": "1.1.0"        }      },      "node_modules/@img/sharp-darwin-x64": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", -      "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz", +      "integrity": "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==",        "cpu": [          "x64"        ], @@ -750,13 +757,13 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-darwin-x64": "1.0.4" +        "@img/sharp-libvips-darwin-x64": "1.1.0"        }      },      "node_modules/@img/sharp-libvips-darwin-arm64": { -      "version": "1.0.4", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", -      "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz", +      "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==",        "cpu": [          "arm64"        ], @@ -770,9 +777,9 @@        }      },      "node_modules/@img/sharp-libvips-darwin-x64": { -      "version": "1.0.4", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", -      "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz", +      "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==",        "cpu": [          "x64"        ], @@ -786,9 +793,9 @@        }      },      "node_modules/@img/sharp-libvips-linux-arm": { -      "version": "1.0.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", -      "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz", +      "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==",        "cpu": [          "arm"        ], @@ -802,9 +809,9 @@        }      },      "node_modules/@img/sharp-libvips-linux-arm64": { -      "version": "1.0.4", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", -      "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz", +      "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==",        "cpu": [          "arm64"        ], @@ -817,10 +824,26 @@          "url": "https://opencollective.com/libvips"        }      }, +    "node_modules/@img/sharp-libvips-linux-ppc64": { +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz", +      "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", +      "cpu": [ +        "ppc64" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "linux" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    },      "node_modules/@img/sharp-libvips-linux-s390x": { -      "version": "1.0.4", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", -      "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz", +      "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==",        "cpu": [          "s390x"        ], @@ -834,9 +857,9 @@        }      },      "node_modules/@img/sharp-libvips-linux-x64": { -      "version": "1.0.4", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", -      "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz", +      "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==",        "cpu": [          "x64"        ], @@ -850,9 +873,9 @@        }      },      "node_modules/@img/sharp-libvips-linuxmusl-arm64": { -      "version": "1.0.4", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", -      "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz", +      "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==",        "cpu": [          "arm64"        ], @@ -866,9 +889,9 @@        }      },      "node_modules/@img/sharp-libvips-linuxmusl-x64": { -      "version": "1.0.4", -      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", -      "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz", +      "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==",        "cpu": [          "x64"        ], @@ -882,9 +905,9 @@        }      },      "node_modules/@img/sharp-linux-arm": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", -      "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz", +      "integrity": "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==",        "cpu": [          "arm"        ], @@ -900,13 +923,13 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-linux-arm": "1.0.5" +        "@img/sharp-libvips-linux-arm": "1.1.0"        }      },      "node_modules/@img/sharp-linux-arm64": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", -      "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz", +      "integrity": "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==",        "cpu": [          "arm64"        ], @@ -922,13 +945,13 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-linux-arm64": "1.0.4" +        "@img/sharp-libvips-linux-arm64": "1.1.0"        }      },      "node_modules/@img/sharp-linux-s390x": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", -      "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz", +      "integrity": "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==",        "cpu": [          "s390x"        ], @@ -944,13 +967,13 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-linux-s390x": "1.0.4" +        "@img/sharp-libvips-linux-s390x": "1.1.0"        }      },      "node_modules/@img/sharp-linux-x64": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", -      "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz", +      "integrity": "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==",        "cpu": [          "x64"        ], @@ -966,13 +989,13 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-linux-x64": "1.0.4" +        "@img/sharp-libvips-linux-x64": "1.1.0"        }      },      "node_modules/@img/sharp-linuxmusl-arm64": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", -      "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz", +      "integrity": "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==",        "cpu": [          "arm64"        ], @@ -988,13 +1011,13 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" +        "@img/sharp-libvips-linuxmusl-arm64": "1.1.0"        }      },      "node_modules/@img/sharp-linuxmusl-x64": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", -      "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz", +      "integrity": "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==",        "cpu": [          "x64"        ], @@ -1010,20 +1033,20 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-libvips-linuxmusl-x64": "1.0.4" +        "@img/sharp-libvips-linuxmusl-x64": "1.1.0"        }      },      "node_modules/@img/sharp-wasm32": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", -      "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz", +      "integrity": "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==",        "cpu": [          "wasm32"        ],        "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",        "optional": true,        "dependencies": { -        "@emnapi/runtime": "^1.2.0" +        "@emnapi/runtime": "^1.4.3"        },        "engines": {          "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -1032,10 +1055,29 @@          "url": "https://opencollective.com/libvips"        }      }, +    "node_modules/@img/sharp-win32-arm64": { +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz", +      "integrity": "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==", +      "cpu": [ +        "arm64" +      ], +      "license": "Apache-2.0 AND LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "win32" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    },      "node_modules/@img/sharp-win32-ia32": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", -      "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz", +      "integrity": "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==",        "cpu": [          "ia32"        ], @@ -1052,9 +1094,9 @@        }      },      "node_modules/@img/sharp-win32-x64": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", -      "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz", +      "integrity": "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==",        "cpu": [          "x64"        ], @@ -1076,6 +1118,149 @@        "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",        "license": "MIT"      }, +    "node_modules/@next/env": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.3.tgz", +      "integrity": "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw==", +      "license": "MIT", +      "peer": true +    }, +    "node_modules/@next/swc-darwin-arm64": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.3.tgz", +      "integrity": "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg==", +      "cpu": [ +        "arm64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@next/swc-darwin-x64": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.3.tgz", +      "integrity": "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw==", +      "cpu": [ +        "x64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@next/swc-linux-arm64-gnu": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.3.tgz", +      "integrity": "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw==", +      "cpu": [ +        "arm64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "linux" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@next/swc-linux-arm64-musl": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.3.tgz", +      "integrity": "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA==", +      "cpu": [ +        "arm64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "linux" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@next/swc-linux-x64-gnu": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz", +      "integrity": "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==", +      "cpu": [ +        "x64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "linux" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@next/swc-linux-x64-musl": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz", +      "integrity": "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==", +      "cpu": [ +        "x64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "linux" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@next/swc-win32-arm64-msvc": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.3.tgz", +      "integrity": "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ==", +      "cpu": [ +        "arm64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "win32" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@next/swc-win32-x64-msvc": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.3.tgz", +      "integrity": "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw==", +      "cpu": [ +        "x64" +      ], +      "license": "MIT", +      "optional": true, +      "os": [ +        "win32" +      ], +      "peer": true, +      "engines": { +        "node": ">= 10" +      } +    },      "node_modules/@nodelib/fs.scandir": {        "version": "2.1.5",        "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1413,6 +1598,221 @@          "url": "https://opencollective.com/parcel"        }      }, +    "node_modules/@resvg/resvg-js": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js/-/resvg-js-2.6.2.tgz", +      "integrity": "sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==", +      "license": "MPL-2.0", +      "engines": { +        "node": ">= 10" +      }, +      "optionalDependencies": { +        "@resvg/resvg-js-android-arm-eabi": "2.6.2", +        "@resvg/resvg-js-android-arm64": "2.6.2", +        "@resvg/resvg-js-darwin-arm64": "2.6.2", +        "@resvg/resvg-js-darwin-x64": "2.6.2", +        "@resvg/resvg-js-linux-arm-gnueabihf": "2.6.2", +        "@resvg/resvg-js-linux-arm64-gnu": "2.6.2", +        "@resvg/resvg-js-linux-arm64-musl": "2.6.2", +        "@resvg/resvg-js-linux-x64-gnu": "2.6.2", +        "@resvg/resvg-js-linux-x64-musl": "2.6.2", +        "@resvg/resvg-js-win32-arm64-msvc": "2.6.2", +        "@resvg/resvg-js-win32-ia32-msvc": "2.6.2", +        "@resvg/resvg-js-win32-x64-msvc": "2.6.2" +      } +    }, +    "node_modules/@resvg/resvg-js-android-arm-eabi": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm-eabi/-/resvg-js-android-arm-eabi-2.6.2.tgz", +      "integrity": "sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==", +      "cpu": [ +        "arm" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "android" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-android-arm64": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-android-arm64/-/resvg-js-android-arm64-2.6.2.tgz", +      "integrity": "sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==", +      "cpu": [ +        "arm64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "android" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-darwin-arm64": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-arm64/-/resvg-js-darwin-arm64-2.6.2.tgz", +      "integrity": "sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==", +      "cpu": [ +        "arm64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-darwin-x64": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-darwin-x64/-/resvg-js-darwin-x64-2.6.2.tgz", +      "integrity": "sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==", +      "cpu": [ +        "x64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-linux-arm-gnueabihf": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm-gnueabihf/-/resvg-js-linux-arm-gnueabihf-2.6.2.tgz", +      "integrity": "sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==", +      "cpu": [ +        "arm" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-linux-arm64-gnu": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-gnu/-/resvg-js-linux-arm64-gnu-2.6.2.tgz", +      "integrity": "sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==", +      "cpu": [ +        "arm64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-linux-arm64-musl": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-arm64-musl/-/resvg-js-linux-arm64-musl-2.6.2.tgz", +      "integrity": "sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==", +      "cpu": [ +        "arm64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-linux-x64-gnu": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-gnu/-/resvg-js-linux-x64-gnu-2.6.2.tgz", +      "integrity": "sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==", +      "cpu": [ +        "x64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-linux-x64-musl": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-linux-x64-musl/-/resvg-js-linux-x64-musl-2.6.2.tgz", +      "integrity": "sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==", +      "cpu": [ +        "x64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-win32-arm64-msvc": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-arm64-msvc/-/resvg-js-win32-arm64-msvc-2.6.2.tgz", +      "integrity": "sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==", +      "cpu": [ +        "arm64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "win32" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-win32-ia32-msvc": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-ia32-msvc/-/resvg-js-win32-ia32-msvc-2.6.2.tgz", +      "integrity": "sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==", +      "cpu": [ +        "ia32" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "win32" +      ], +      "engines": { +        "node": ">= 10" +      } +    }, +    "node_modules/@resvg/resvg-js-win32-x64-msvc": { +      "version": "2.6.2", +      "resolved": "https://registry.npmjs.org/@resvg/resvg-js-win32-x64-msvc/-/resvg-js-win32-x64-msvc-2.6.2.tgz", +      "integrity": "sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==", +      "cpu": [ +        "x64" +      ], +      "license": "MPL-2.0", +      "optional": true, +      "os": [ +        "win32" +      ], +      "engines": { +        "node": ">= 10" +      } +    },      "node_modules/@rollup/pluginutils": {        "version": "5.1.4",        "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz", @@ -1768,10 +2168,45 @@        "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",        "license": "MIT"      }, +    "node_modules/@shuding/opentype.js": { +      "version": "1.4.0-beta.0", +      "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", +      "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==", +      "license": "MIT", +      "dependencies": { +        "fflate": "^0.7.3", +        "string.prototype.codepointat": "^0.2.1" +      }, +      "bin": { +        "ot": "bin/ot" +      }, +      "engines": { +        "node": ">= 8.0.0" +      } +    }, +    "node_modules/@sindresorhus/merge-streams": { +      "version": "2.3.0", +      "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", +      "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", +      "license": "MIT", +      "engines": { +        "node": ">=18" +      }, +      "funding": { +        "url": "https://github.com/sponsors/sindresorhus" +      } +    }, +    "node_modules/@swc/counter": { +      "version": "0.1.3", +      "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", +      "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", +      "license": "Apache-2.0", +      "peer": true +    },      "node_modules/@swc/helpers": { -      "version": "0.5.17", -      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", -      "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", +      "version": "0.5.15", +      "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", +      "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",        "license": "Apache-2.0",        "dependencies": {          "tslib": "^2.8.0" @@ -2205,6 +2640,417 @@          "sharp": "^0.33.3"        }      }, +    "node_modules/astro/node_modules/@img/sharp-darwin-arm64": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", +      "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", +      "cpu": [ +        "arm64" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-darwin-arm64": "1.0.4" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-darwin-x64": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", +      "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", +      "cpu": [ +        "x64" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-darwin-x64": "1.0.4" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-darwin-arm64": { +      "version": "1.0.4", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", +      "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", +      "cpu": [ +        "arm64" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-darwin-x64": { +      "version": "1.0.4", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", +      "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", +      "cpu": [ +        "x64" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "darwin" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-linux-arm": { +      "version": "1.0.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", +      "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", +      "cpu": [ +        "arm" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "linux" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-linux-arm64": { +      "version": "1.0.4", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", +      "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", +      "cpu": [ +        "arm64" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "linux" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-linux-s390x": { +      "version": "1.0.4", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", +      "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", +      "cpu": [ +        "s390x" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "linux" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-linux-x64": { +      "version": "1.0.4", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", +      "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", +      "cpu": [ +        "x64" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "linux" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-linuxmusl-arm64": { +      "version": "1.0.4", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", +      "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", +      "cpu": [ +        "arm64" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "linux" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-libvips-linuxmusl-x64": { +      "version": "1.0.4", +      "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", +      "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", +      "cpu": [ +        "x64" +      ], +      "license": "LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "linux" +      ], +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-linux-arm": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", +      "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", +      "cpu": [ +        "arm" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-linux-arm": "1.0.5" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-linux-arm64": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", +      "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", +      "cpu": [ +        "arm64" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-linux-arm64": "1.0.4" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-linux-s390x": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", +      "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", +      "cpu": [ +        "s390x" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-linux-s390x": "1.0.4" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-linux-x64": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", +      "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", +      "cpu": [ +        "x64" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-linux-x64": "1.0.4" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-linuxmusl-arm64": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", +      "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", +      "cpu": [ +        "arm64" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-linuxmusl-x64": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", +      "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", +      "cpu": [ +        "x64" +      ], +      "license": "Apache-2.0", +      "optional": true, +      "os": [ +        "linux" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-libvips-linuxmusl-x64": "1.0.4" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-wasm32": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", +      "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", +      "cpu": [ +        "wasm32" +      ], +      "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", +      "optional": true, +      "dependencies": { +        "@emnapi/runtime": "^1.2.0" +      }, +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-win32-ia32": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", +      "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", +      "cpu": [ +        "ia32" +      ], +      "license": "Apache-2.0 AND LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "win32" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/@img/sharp-win32-x64": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", +      "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", +      "cpu": [ +        "x64" +      ], +      "license": "Apache-2.0 AND LGPL-3.0-or-later", +      "optional": true, +      "os": [ +        "win32" +      ], +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      } +    }, +    "node_modules/astro/node_modules/detect-libc": { +      "version": "2.0.4", +      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", +      "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", +      "license": "Apache-2.0", +      "optional": true, +      "engines": { +        "node": ">=8" +      } +    }, +    "node_modules/astro/node_modules/sharp": { +      "version": "0.33.5", +      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", +      "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", +      "hasInstallScript": true, +      "license": "Apache-2.0", +      "optional": true, +      "dependencies": { +        "color": "^4.2.3", +        "detect-libc": "^2.0.3", +        "semver": "^7.6.3" +      }, +      "engines": { +        "node": "^18.17.0 || ^20.3.0 || >=21.0.0" +      }, +      "funding": { +        "url": "https://opencollective.com/libvips" +      }, +      "optionalDependencies": { +        "@img/sharp-darwin-arm64": "0.33.5", +        "@img/sharp-darwin-x64": "0.33.5", +        "@img/sharp-libvips-darwin-arm64": "1.0.4", +        "@img/sharp-libvips-darwin-x64": "1.0.4", +        "@img/sharp-libvips-linux-arm": "1.0.5", +        "@img/sharp-libvips-linux-arm64": "1.0.4", +        "@img/sharp-libvips-linux-s390x": "1.0.4", +        "@img/sharp-libvips-linux-x64": "1.0.4", +        "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", +        "@img/sharp-libvips-linuxmusl-x64": "1.0.4", +        "@img/sharp-linux-arm": "0.33.5", +        "@img/sharp-linux-arm64": "0.33.5", +        "@img/sharp-linux-s390x": "0.33.5", +        "@img/sharp-linux-x64": "0.33.5", +        "@img/sharp-linuxmusl-arm64": "0.33.5", +        "@img/sharp-linuxmusl-x64": "0.33.5", +        "@img/sharp-wasm32": "0.33.5", +        "@img/sharp-win32-ia32": "0.33.5", +        "@img/sharp-win32-x64": "0.33.5" +      } +    },      "node_modules/autoprefixer": {        "version": "10.4.21",        "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", @@ -2388,6 +3234,18 @@          "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"        }      }, +    "node_modules/busboy": { +      "version": "1.6.0", +      "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", +      "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", +      "peer": true, +      "dependencies": { +        "streamsearch": "^1.1.0" +      }, +      "engines": { +        "node": ">=10.16.0" +      } +    },      "node_modules/camelcase": {        "version": "8.0.0",        "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", @@ -2400,6 +3258,15 @@          "url": "https://github.com/sponsors/sindresorhus"        }      }, +    "node_modules/camelize": { +      "version": "1.0.1", +      "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", +      "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", +      "license": "MIT", +      "funding": { +        "url": "https://github.com/sponsors/ljharb" +      } +    },      "node_modules/caniuse-api": {        "version": "3.0.0",        "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", @@ -2413,9 +3280,9 @@        }      },      "node_modules/caniuse-lite": { -      "version": "1.0.30001722", -      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001722.tgz", -      "integrity": "sha512-DCQHBBZtiK6JVkAGw7drvAMK0Q0POD/xZvEmDp6baiMMP6QXXk9HpD6mNYBZWhOPG6LvIDb82ITqtWjhDckHCA==", +      "version": "1.0.30001723", +      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz", +      "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==",        "funding": [          {            "type": "opencollective", @@ -2526,6 +3393,13 @@          "url": "https://github.com/sponsors/sindresorhus"        }      }, +    "node_modules/client-only": { +      "version": "0.0.1", +      "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", +      "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", +      "license": "MIT", +      "peer": true +    },      "node_modules/cliui": {        "version": "8.0.1",        "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2636,7 +3510,6 @@        "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",        "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",        "license": "MIT", -      "optional": true,        "dependencies": {          "color-convert": "^2.0.1",          "color-string": "^1.9.0" @@ -2668,7 +3541,6 @@        "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",        "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",        "license": "MIT", -      "optional": true,        "dependencies": {          "color-name": "^1.0.0",          "simple-swizzle": "^0.2.2" @@ -2738,6 +3610,27 @@          "uncrypto": "^0.1.3"        }      }, +    "node_modules/css-background-parser": { +      "version": "0.1.0", +      "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz", +      "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==", +      "license": "MIT" +    }, +    "node_modules/css-box-shadow": { +      "version": "1.0.0-3", +      "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz", +      "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==", +      "license": "MIT" +    }, +    "node_modules/css-color-keywords": { +      "version": "1.0.0", +      "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", +      "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", +      "license": "ISC", +      "engines": { +        "node": ">=4" +      } +    },      "node_modules/css-declaration-sorter": {        "version": "7.2.0",        "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", @@ -2750,6 +3643,15 @@          "postcss": "^8.0.9"        }      }, +    "node_modules/css-gradient-parser": { +      "version": "0.0.16", +      "resolved": "https://registry.npmjs.org/css-gradient-parser/-/css-gradient-parser-0.0.16.tgz", +      "integrity": "sha512-3O5QdqgFRUbXvK1x5INf1YkBz1UKSWqrd63vWsum8MNHDBYD5urm3QtxZbKU259OrEXNM26lP/MPY3d1IGkBgA==", +      "license": "MIT", +      "engines": { +        "node": ">=16" +      } +    },      "node_modules/css-select": {        "version": "5.1.0",        "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", @@ -2766,6 +3668,17 @@          "url": "https://github.com/sponsors/fb55"        }      }, +    "node_modules/css-to-react-native": { +      "version": "3.2.0", +      "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", +      "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", +      "license": "MIT", +      "dependencies": { +        "camelize": "^1.0.0", +        "css-color-keywords": "^1.0.0", +        "postcss-value-parser": "^4.0.2" +      } +    },      "node_modules/css-tree": {        "version": "2.3.1",        "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", @@ -2957,9 +3870,9 @@        }      },      "node_modules/decode-named-character-reference": { -      "version": "1.1.0", -      "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", -      "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", +      "version": "1.2.0", +      "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", +      "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==",        "license": "MIT",        "dependencies": {          "character-entities": "^2.0.0" @@ -3132,9 +4045,9 @@        }      },      "node_modules/electron-to-chromium": { -      "version": "1.5.166", -      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.166.tgz", -      "integrity": "sha512-QPWqHL0BglzPYyJJ1zSSmwFFL6MFXhbACOCcsCdUMCkzPdS9/OIBVxg516X/Ado2qwAq8k0nJJ7phQPCqiaFAw==", +      "version": "1.5.167", +      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.167.tgz", +      "integrity": "sha512-LxcRvnYO5ez2bMOFpbuuVuAI5QNeY1ncVytE/KXaL6ZNfzX1yPlAO0nSOyIHx2fVAuUprMqPs/TdVhUFZy7SIQ==",        "license": "ISC"      },      "node_modules/emmet": { @@ -3159,6 +4072,15 @@        "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",        "license": "MIT"      }, +    "node_modules/emoji-regex-xs": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-2.0.1.tgz", +      "integrity": "sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==", +      "license": "MIT", +      "engines": { +        "node": ">=10.0.0" +      } +    },      "node_modules/entities": {        "version": "6.0.1",        "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -3226,6 +4148,12 @@          "node": ">=6"        }      }, +    "node_modules/escape-html": { +      "version": "1.0.3", +      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", +      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", +      "license": "MIT" +    },      "node_modules/escape-string-regexp": {        "version": "5.0.0",        "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", @@ -3238,6 +4166,19 @@          "url": "https://github.com/sponsors/sindresorhus"        }      }, +    "node_modules/esprima": { +      "version": "4.0.1", +      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", +      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", +      "license": "BSD-2-Clause", +      "bin": { +        "esparse": "bin/esparse.js", +        "esvalidate": "bin/esvalidate.js" +      }, +      "engines": { +        "node": ">=4" +      } +    },      "node_modules/estree-walker": {        "version": "3.0.3",        "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -3259,6 +4200,18 @@        "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",        "license": "MIT"      }, +    "node_modules/extend-shallow": { +      "version": "2.0.1", +      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", +      "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", +      "license": "MIT", +      "dependencies": { +        "is-extendable": "^0.1.0" +      }, +      "engines": { +        "node": ">=0.10.0" +      } +    },      "node_modules/fast-deep-equal": {        "version": "3.1.3",        "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3338,6 +4291,12 @@          }        }      }, +    "node_modules/fflate": { +      "version": "0.7.4", +      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", +      "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==", +      "license": "MIT" +    },      "node_modules/fill-range": {        "version": "7.1.1",        "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3413,6 +4372,15 @@          "node": "^8.16.0 || ^10.6.0 || >=11.0.0"        }      }, +    "node_modules/geist": { +      "version": "1.4.2", +      "resolved": "https://registry.npmjs.org/geist/-/geist-1.4.2.tgz", +      "integrity": "sha512-OQUga/KUc8ueijck6EbtT07L4tZ5+TZgjw8PyWfxo16sL5FWk7gNViPNU8hgCFjy6bJi9yuTP+CRpywzaGN8zw==", +      "license": "SIL OPEN FONT LICENSE", +      "peerDependencies": { +        "next": ">=13.2.0" +      } +    },      "node_modules/get-caller-file": {        "version": "2.0.5",        "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -3452,6 +4420,63 @@          "node": ">= 6"        }      }, +    "node_modules/globby": { +      "version": "14.1.0", +      "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", +      "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", +      "license": "MIT", +      "dependencies": { +        "@sindresorhus/merge-streams": "^2.1.0", +        "fast-glob": "^3.3.3", +        "ignore": "^7.0.3", +        "path-type": "^6.0.0", +        "slash": "^5.1.0", +        "unicorn-magic": "^0.3.0" +      }, +      "engines": { +        "node": ">=18" +      }, +      "funding": { +        "url": "https://github.com/sponsors/sindresorhus" +      } +    }, +    "node_modules/gray-matter": { +      "version": "4.0.3", +      "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", +      "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", +      "license": "MIT", +      "dependencies": { +        "js-yaml": "^3.13.1", +        "kind-of": "^6.0.2", +        "section-matter": "^1.0.0", +        "strip-bom-string": "^1.0.0" +      }, +      "engines": { +        "node": ">=6.0" +      } +    }, +    "node_modules/gray-matter/node_modules/argparse": { +      "version": "1.0.10", +      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", +      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", +      "license": "MIT", +      "dependencies": { +        "sprintf-js": "~1.0.2" +      } +    }, +    "node_modules/gray-matter/node_modules/js-yaml": { +      "version": "3.14.1", +      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", +      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", +      "license": "MIT", +      "dependencies": { +        "argparse": "^1.0.7", +        "esprima": "^4.0.0" +      }, +      "bin": { +        "js-yaml": "bin/js-yaml.js" +      } +    },      "node_modules/h3": {        "version": "1.15.3",        "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.3.tgz", @@ -3656,6 +4681,18 @@          "url": "https://opencollective.com/unified"        }      }, +    "node_modules/hex-rgb": { +      "version": "4.3.0", +      "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz", +      "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==", +      "license": "MIT", +      "engines": { +        "node": ">=6" +      }, +      "funding": { +        "url": "https://github.com/sponsors/sindresorhus" +      } +    },      "node_modules/html-escaper": {        "version": "3.0.3",        "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", @@ -3678,6 +4715,15 @@        "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",        "license": "BSD-2-Clause"      }, +    "node_modules/ignore": { +      "version": "7.0.5", +      "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", +      "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", +      "license": "MIT", +      "engines": { +        "node": ">= 4" +      } +    },      "node_modules/immutable": {        "version": "5.1.3",        "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", @@ -3707,8 +4753,7 @@        "version": "0.3.2",        "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",        "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", -      "license": "MIT", -      "optional": true +      "license": "MIT"      },      "node_modules/is-docker": {        "version": "3.0.0", @@ -3725,6 +4770,15 @@          "url": "https://github.com/sponsors/sindresorhus"        }      }, +    "node_modules/is-extendable": { +      "version": "0.1.1", +      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", +      "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", +      "license": "MIT", +      "engines": { +        "node": ">=0.10.0" +      } +    },      "node_modules/is-extglob": {        "version": "2.1.1",        "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3833,6 +4887,15 @@        "integrity": "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==",        "license": "MIT"      }, +    "node_modules/kind-of": { +      "version": "6.0.3", +      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", +      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", +      "license": "MIT", +      "engines": { +        "node": ">=0.10.0" +      } +    },      "node_modules/kleur": {        "version": "4.1.5",        "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -3854,6 +4917,25 @@          "url": "https://github.com/sponsors/antonk52"        }      }, +    "node_modules/linebreak": { +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", +      "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", +      "license": "MIT", +      "dependencies": { +        "base64-js": "0.0.8", +        "unicode-trie": "^2.0.0" +      } +    }, +    "node_modules/linebreak/node_modules/base64-js": { +      "version": "0.0.8", +      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", +      "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", +      "license": "MIT", +      "engines": { +        "node": ">= 0.4" +      } +    },      "node_modules/lodash": {        "version": "4.17.21",        "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -4794,6 +5876,90 @@          "node": ">= 10"        }      }, +    "node_modules/next": { +      "version": "15.3.3", +      "resolved": "https://registry.npmjs.org/next/-/next-15.3.3.tgz", +      "integrity": "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw==", +      "license": "MIT", +      "peer": true, +      "dependencies": { +        "@next/env": "15.3.3", +        "@swc/counter": "0.1.3", +        "@swc/helpers": "0.5.15", +        "busboy": "1.6.0", +        "caniuse-lite": "^1.0.30001579", +        "postcss": "8.4.31", +        "styled-jsx": "5.1.6" +      }, +      "bin": { +        "next": "dist/bin/next" +      }, +      "engines": { +        "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" +      }, +      "optionalDependencies": { +        "@next/swc-darwin-arm64": "15.3.3", +        "@next/swc-darwin-x64": "15.3.3", +        "@next/swc-linux-arm64-gnu": "15.3.3", +        "@next/swc-linux-arm64-musl": "15.3.3", +        "@next/swc-linux-x64-gnu": "15.3.3", +        "@next/swc-linux-x64-musl": "15.3.3", +        "@next/swc-win32-arm64-msvc": "15.3.3", +        "@next/swc-win32-x64-msvc": "15.3.3", +        "sharp": "^0.34.1" +      }, +      "peerDependencies": { +        "@opentelemetry/api": "^1.1.0", +        "@playwright/test": "^1.41.2", +        "babel-plugin-react-compiler": "*", +        "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", +        "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", +        "sass": "^1.3.0" +      }, +      "peerDependenciesMeta": { +        "@opentelemetry/api": { +          "optional": true +        }, +        "@playwright/test": { +          "optional": true +        }, +        "babel-plugin-react-compiler": { +          "optional": true +        }, +        "sass": { +          "optional": true +        } +      } +    }, +    "node_modules/next/node_modules/postcss": { +      "version": "8.4.31", +      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", +      "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", +      "funding": [ +        { +          "type": "opencollective", +          "url": "https://opencollective.com/postcss/" +        }, +        { +          "type": "tidelift", +          "url": "https://tidelift.com/funding/github/npm/postcss" +        }, +        { +          "type": "github", +          "url": "https://github.com/sponsors/ai" +        } +      ], +      "license": "MIT", +      "peer": true, +      "dependencies": { +        "nanoid": "^3.3.6", +        "picocolors": "^1.0.0", +        "source-map-js": "^1.0.2" +      }, +      "engines": { +        "node": "^10 || ^12 || >=14" +      } +    },      "node_modules/nlcst-to-string": {        "version": "4.0.0",        "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", @@ -4971,6 +6137,16 @@        "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",        "license": "MIT"      }, +    "node_modules/parse-css-color": { +      "version": "0.2.1", +      "resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz", +      "integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==", +      "license": "MIT", +      "dependencies": { +        "color-name": "^1.1.4", +        "hex-rgb": "^4.1.0" +      } +    },      "node_modules/parse-latin": {        "version": "7.0.0",        "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", @@ -5007,6 +6183,18 @@        "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",        "license": "MIT"      }, +    "node_modules/path-type": { +      "version": "6.0.0", +      "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", +      "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", +      "license": "MIT", +      "engines": { +        "node": ">=18" +      }, +      "funding": { +        "url": "https://github.com/sponsors/sindresorhus" +      } +    },      "node_modules/picocolors": {        "version": "1.1.1",        "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -5639,6 +6827,29 @@        "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",        "license": "MIT"      }, +    "node_modules/react": { +      "version": "19.1.0", +      "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", +      "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", +      "license": "MIT", +      "peer": true, +      "engines": { +        "node": ">=0.10.0" +      } +    }, +    "node_modules/react-dom": { +      "version": "19.1.0", +      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", +      "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", +      "license": "MIT", +      "peer": true, +      "dependencies": { +        "scheduler": "^0.26.0" +      }, +      "peerDependencies": { +        "react": "^19.1.0" +      } +    },      "node_modules/readdirp": {        "version": "4.1.2",        "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -6024,18 +7235,69 @@          "suf-log": "^2.5.3"        }      }, +    "node_modules/satori": { +      "version": "0.15.2", +      "resolved": "https://registry.npmjs.org/satori/-/satori-0.15.2.tgz", +      "integrity": "sha512-vu/49vdc8MzV5jUchs3TIRDCOkOvMc1iJ11MrZvhg9tE4ziKIEIBjBZvies6a9sfM2vQ2gc3dXeu6rCK7AztHA==", +      "license": "MPL-2.0", +      "dependencies": { +        "@shuding/opentype.js": "1.4.0-beta.0", +        "css-background-parser": "^0.1.0", +        "css-box-shadow": "1.0.0-3", +        "css-gradient-parser": "^0.0.16", +        "css-to-react-native": "^3.0.0", +        "emoji-regex-xs": "^2.0.1", +        "escape-html": "^1.0.3", +        "linebreak": "^1.1.0", +        "parse-css-color": "^0.2.1", +        "postcss-value-parser": "^4.2.0", +        "yoga-wasm-web": "^0.3.3" +      }, +      "engines": { +        "node": ">=16" +      } +    }, +    "node_modules/satori-html": { +      "version": "0.3.2", +      "resolved": "https://registry.npmjs.org/satori-html/-/satori-html-0.3.2.tgz", +      "integrity": "sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==", +      "license": "MIT", +      "dependencies": { +        "ultrahtml": "^1.2.0" +      } +    },      "node_modules/sax": {        "version": "1.4.1",        "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",        "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",        "license": "ISC"      }, +    "node_modules/scheduler": { +      "version": "0.26.0", +      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", +      "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", +      "license": "MIT", +      "peer": true +    },      "node_modules/schema-dts": {        "version": "1.1.5",        "resolved": "https://registry.npmjs.org/schema-dts/-/schema-dts-1.1.5.tgz",        "integrity": "sha512-RJr9EaCmsLzBX2NDiO5Z3ux2BVosNZN5jo0gWgsyKvxKIUL5R3swNvoorulAeL9kLB0iTSX7V6aokhla2m7xbg==",        "license": "Apache-2.0"      }, +    "node_modules/section-matter": { +      "version": "1.0.0", +      "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", +      "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", +      "license": "MIT", +      "dependencies": { +        "extend-shallow": "^2.0.1", +        "kind-of": "^6.0.0" +      }, +      "engines": { +        "node": ">=4" +      } +    },      "node_modules/semver": {        "version": "7.7.2",        "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -6049,16 +7311,15 @@        }      },      "node_modules/sharp": { -      "version": "0.33.5", -      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", -      "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", +      "version": "0.34.2", +      "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.2.tgz", +      "integrity": "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==",        "hasInstallScript": true,        "license": "Apache-2.0", -      "optional": true,        "dependencies": {          "color": "^4.2.3", -        "detect-libc": "^2.0.3", -        "semver": "^7.6.3" +        "detect-libc": "^2.0.4", +        "semver": "^7.7.2"        },        "engines": {          "node": "^18.17.0 || ^20.3.0 || >=21.0.0" @@ -6067,25 +7328,27 @@          "url": "https://opencollective.com/libvips"        },        "optionalDependencies": { -        "@img/sharp-darwin-arm64": "0.33.5", -        "@img/sharp-darwin-x64": "0.33.5", -        "@img/sharp-libvips-darwin-arm64": "1.0.4", -        "@img/sharp-libvips-darwin-x64": "1.0.4", -        "@img/sharp-libvips-linux-arm": "1.0.5", -        "@img/sharp-libvips-linux-arm64": "1.0.4", -        "@img/sharp-libvips-linux-s390x": "1.0.4", -        "@img/sharp-libvips-linux-x64": "1.0.4", -        "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", -        "@img/sharp-libvips-linuxmusl-x64": "1.0.4", -        "@img/sharp-linux-arm": "0.33.5", -        "@img/sharp-linux-arm64": "0.33.5", -        "@img/sharp-linux-s390x": "0.33.5", -        "@img/sharp-linux-x64": "0.33.5", -        "@img/sharp-linuxmusl-arm64": "0.33.5", -        "@img/sharp-linuxmusl-x64": "0.33.5", -        "@img/sharp-wasm32": "0.33.5", -        "@img/sharp-win32-ia32": "0.33.5", -        "@img/sharp-win32-x64": "0.33.5" +        "@img/sharp-darwin-arm64": "0.34.2", +        "@img/sharp-darwin-x64": "0.34.2", +        "@img/sharp-libvips-darwin-arm64": "1.1.0", +        "@img/sharp-libvips-darwin-x64": "1.1.0", +        "@img/sharp-libvips-linux-arm": "1.1.0", +        "@img/sharp-libvips-linux-arm64": "1.1.0", +        "@img/sharp-libvips-linux-ppc64": "1.1.0", +        "@img/sharp-libvips-linux-s390x": "1.1.0", +        "@img/sharp-libvips-linux-x64": "1.1.0", +        "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", +        "@img/sharp-libvips-linuxmusl-x64": "1.1.0", +        "@img/sharp-linux-arm": "0.34.2", +        "@img/sharp-linux-arm64": "0.34.2", +        "@img/sharp-linux-s390x": "0.34.2", +        "@img/sharp-linux-x64": "0.34.2", +        "@img/sharp-linuxmusl-arm64": "0.34.2", +        "@img/sharp-linuxmusl-x64": "0.34.2", +        "@img/sharp-wasm32": "0.34.2", +        "@img/sharp-win32-arm64": "0.34.2", +        "@img/sharp-win32-ia32": "0.34.2", +        "@img/sharp-win32-x64": "0.34.2"        }      },      "node_modules/sharp/node_modules/detect-libc": { @@ -6093,7 +7356,6 @@        "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",        "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",        "license": "Apache-2.0", -      "optional": true,        "engines": {          "node": ">=8"        } @@ -6119,7 +7381,6 @@        "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",        "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",        "license": "MIT", -      "optional": true,        "dependencies": {          "is-arrayish": "^0.3.1"        } @@ -6155,6 +7416,18 @@        "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",        "license": "MIT"      }, +    "node_modules/slash": { +      "version": "5.1.0", +      "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", +      "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", +      "license": "MIT", +      "engines": { +        "node": ">=14.16" +      }, +      "funding": { +        "url": "https://github.com/sponsors/sindresorhus" +      } +    },      "node_modules/smol-toml": {        "version": "1.3.4",        "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.4.tgz", @@ -6186,12 +7459,27 @@          "url": "https://github.com/sponsors/wooorm"        }      }, +    "node_modules/sprintf-js": { +      "version": "1.0.3", +      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", +      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", +      "license": "BSD-3-Clause" +    },      "node_modules/stream-replace-string": {        "version": "2.0.0",        "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz",        "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==",        "license": "MIT"      }, +    "node_modules/streamsearch": { +      "version": "1.1.0", +      "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", +      "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", +      "peer": true, +      "engines": { +        "node": ">=10.0.0" +      } +    },      "node_modules/string-width": {        "version": "7.2.0",        "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -6209,6 +7497,12 @@          "url": "https://github.com/sponsors/sindresorhus"        }      }, +    "node_modules/string.prototype.codepointat": { +      "version": "0.2.1", +      "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", +      "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==", +      "license": "MIT" +    },      "node_modules/stringify-entities": {        "version": "4.0.4",        "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -6238,6 +7532,15 @@          "url": "https://github.com/chalk/strip-ansi?sponsor=1"        }      }, +    "node_modules/strip-bom-string": { +      "version": "1.0.0", +      "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", +      "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", +      "license": "MIT", +      "engines": { +        "node": ">=0.10.0" +      } +    },      "node_modules/strnum": {        "version": "2.1.1",        "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", @@ -6250,6 +7553,30 @@        ],        "license": "MIT"      }, +    "node_modules/styled-jsx": { +      "version": "5.1.6", +      "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", +      "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", +      "license": "MIT", +      "peer": true, +      "dependencies": { +        "client-only": "0.0.1" +      }, +      "engines": { +        "node": ">= 12.0.0" +      }, +      "peerDependencies": { +        "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" +      }, +      "peerDependenciesMeta": { +        "@babel/core": { +          "optional": true +        }, +        "babel-plugin-macros": { +          "optional": true +        } +      } +    },      "node_modules/stylehacks": {        "version": "7.0.5",        "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.5.tgz", @@ -6477,6 +7804,18 @@          "tiny-inflate": "^1.0.0"        }      }, +    "node_modules/unicorn-magic": { +      "version": "0.3.0", +      "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", +      "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", +      "license": "MIT", +      "engines": { +        "node": ">=18" +      }, +      "funding": { +        "url": "https://github.com/sponsors/sindresorhus" +      } +    },      "node_modules/unified": {        "version": "11.0.5",        "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -7440,10 +8779,16 @@          "url": "https://github.com/sponsors/sindresorhus"        }      }, +    "node_modules/yoga-wasm-web": { +      "version": "0.3.3", +      "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz", +      "integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==", +      "license": "MIT" +    },      "node_modules/zod": { -      "version": "3.25.62", -      "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.62.tgz", -      "integrity": "sha512-YCxsr4DmhPcrKPC9R1oBHQNlQzlJEyPAId//qTau/vBee9uO8K6prmRq4eMkOyxvBfH4wDPIPdLx9HVMWIY3xA==", +      "version": "3.25.64", +      "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.64.tgz", +      "integrity": "sha512-hbP9FpSZf7pkS7hRVUrOjhwKJNyampPgtXKc3AN6DsWtoHsg2Sb4SQaS4Tcay380zSwd2VPo9G9180emBACp5g==",        "license": "MIT",        "funding": {          "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 491e972..57ffef3 100644 --- a/package.json +++ b/package.json @@ -23,15 +23,22 @@      "@astrojs/check": "^0.9.4",      "@astrojs/rss": "^4.0.12",      "@astrojs/sitemap": "^3.4.1", +    "@resvg/resvg-js": "^2.6.2",      "astro": "^5.9.0",      "autoprefixer": "^10.4.21",      "cssnano": "^7.0.7",      "cssnano-preset-advanced": "^7.0.7",      "dayjs": "^1.11.13", +    "geist": "^1.4.2", +    "globby": "^14.1.0", +    "gray-matter": "^4.0.3",      "mdast-util-to-string": "^4.0.0",      "reading-time": "^1.5.0",      "sass": "^1.89.1", +    "satori": "^0.15.2", +    "satori-html": "^0.3.2",      "schema-dts": "^1.1.5", +    "sharp": "^0.34.2",      "typescript": "^5"    },    "devDependencies": { diff --git a/public/images/preview/.gitignore b/public/images/preview/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/public/images/preview/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore
\ No newline at end of file diff --git a/src/assets/JetBrainsMono/JetBrainsMono-Bold.ttf b/src/assets/JetBrainsMono/JetBrainsMono-Bold.ttfBinary files differ new file mode 100644 index 0000000..8c93043 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-Bold.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-BoldItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-BoldItalic.ttfBinary files differ new file mode 100644 index 0000000..1ddf216 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-BoldItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-ExtraBold.ttf b/src/assets/JetBrainsMono/JetBrainsMono-ExtraBold.ttfBinary files differ new file mode 100644 index 0000000..435d7a7 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-ExtraBold.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-ExtraBoldItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-ExtraBoldItalic.ttfBinary files differ new file mode 100644 index 0000000..79e616e --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-ExtraBoldItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-ExtraLight.ttf b/src/assets/JetBrainsMono/JetBrainsMono-ExtraLight.ttfBinary files differ new file mode 100644 index 0000000..c131cbf --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-ExtraLight.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-ExtraLightItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-ExtraLightItalic.ttfBinary files differ new file mode 100644 index 0000000..a768985 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-ExtraLightItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-Italic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-Italic.ttfBinary files differ new file mode 100644 index 0000000..ccc9d6a --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-Italic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-Light.ttf b/src/assets/JetBrainsMono/JetBrainsMono-Light.ttfBinary files differ new file mode 100644 index 0000000..15f15a2 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-Light.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-LightItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-LightItalic.ttfBinary files differ new file mode 100644 index 0000000..506208f --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-LightItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-Medium.ttf b/src/assets/JetBrainsMono/JetBrainsMono-Medium.ttfBinary files differ new file mode 100644 index 0000000..9767115 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-Medium.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-MediumItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-MediumItalic.ttfBinary files differ new file mode 100644 index 0000000..415a9e3 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-MediumItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-Regular.ttf b/src/assets/JetBrainsMono/JetBrainsMono-Regular.ttfBinary files differ new file mode 100644 index 0000000..dff66cc --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-Regular.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-SemiBold.ttf b/src/assets/JetBrainsMono/JetBrainsMono-SemiBold.ttfBinary files differ new file mode 100644 index 0000000..a70e69b --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-SemiBold.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-SemiBoldItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-SemiBoldItalic.ttfBinary files differ new file mode 100644 index 0000000..968602e --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-SemiBoldItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-Thin.ttf b/src/assets/JetBrainsMono/JetBrainsMono-Thin.ttfBinary files differ new file mode 100644 index 0000000..7dbe2ac --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-Thin.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMono-ThinItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMono-ThinItalic.ttfBinary files differ new file mode 100644 index 0000000..c6ad6c2 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMono-ThinItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-Bold.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-Bold.ttfBinary files differ new file mode 100644 index 0000000..f78f84f --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-Bold.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-BoldItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-BoldItalic.ttfBinary files differ new file mode 100644 index 0000000..9fb8c83 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-BoldItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraBold.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraBold.ttfBinary files differ new file mode 100644 index 0000000..fe5be6a --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraBold.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraBoldItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraBoldItalic.ttfBinary files differ new file mode 100644 index 0000000..59fc980 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraBoldItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraLight.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraLight.ttfBinary files differ new file mode 100644 index 0000000..6da7b75 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraLight.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraLightItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraLightItalic.ttfBinary files differ new file mode 100644 index 0000000..5733efc --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-ExtraLightItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-Italic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-Italic.ttfBinary files differ new file mode 100644 index 0000000..4e9c380 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-Italic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-Light.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-Light.ttfBinary files differ new file mode 100644 index 0000000..0b79b0c --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-Light.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-LightItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-LightItalic.ttfBinary files differ new file mode 100644 index 0000000..b5e0842 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-LightItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-Medium.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-Medium.ttfBinary files differ new file mode 100644 index 0000000..1454372 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-Medium.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-MediumItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-MediumItalic.ttfBinary files differ new file mode 100644 index 0000000..8d63c6c --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-MediumItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-Regular.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-Regular.ttfBinary files differ new file mode 100644 index 0000000..70d2ec9 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-Regular.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-SemiBold.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-SemiBold.ttfBinary files differ new file mode 100644 index 0000000..ce60a88 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-SemiBold.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-SemiBoldItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-SemiBoldItalic.ttfBinary files differ new file mode 100644 index 0000000..3b3f8f6 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-SemiBoldItalic.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-Thin.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-Thin.ttfBinary files differ new file mode 100644 index 0000000..bea837e --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-Thin.ttf diff --git a/src/assets/JetBrainsMono/JetBrainsMonoNL-ThinItalic.ttf b/src/assets/JetBrainsMono/JetBrainsMonoNL-ThinItalic.ttfBinary files differ new file mode 100644 index 0000000..f0bfed7 --- /dev/null +++ b/src/assets/JetBrainsMono/JetBrainsMonoNL-ThinItalic.ttf diff --git a/src/components/Head.astro b/src/components/Head.astro index 0026886..3fded95 100644 --- a/src/components/Head.astro +++ b/src/components/Head.astro @@ -1,16 +1,18 @@  ---  import type { WithContext, Thing } from "schema-dts";  import JsonLd from "./JsonLd.astro"; -import OpenGraph from "./OpenGraph.astro";  type Props = {  	readonly description: string; -	readonly title: string; +	readonly preview: string;  	readonly schema: WithContext<Thing>; +	readonly title: string;  }; -const canonicalURL = new URL(Astro.url.pathname, Astro.site); -const { description, title, schema } = Astro.props; +const { description, preview, schema, title } = Astro.props; + +const canonicalUrl = new URL(Astro.url.pathname, Astro.site); +const previewUrl = new URL(preview, Astro.site);  ---  <head> @@ -24,7 +26,7 @@ const { description, title, schema } = Astro.props;  	<link href="/feed.xml" rel="alternate" title="RSS" type="application/atom+xml" />  	<link href="/sitemap-index.xml" rel="sitemap" /> -	<link href={canonicalURL} rel="canonical" /> +	<link href={canonicalUrl} rel="canonical" />  	<title>{title}</title> @@ -35,6 +37,18 @@ const { description, title, schema } = Astro.props;  	<link rel="manifest" href="/manifest.json" />  	<meta name="theme-color" content="#ffffff" /> -	<OpenGraph title={title} description={description} /> +	<!-- Open Graph --> +	<meta property="og:type" content="website" /> +	<meta property="og:title" content={title} /> +	<meta property="og:description" content={description} /> +	<meta property="og:image" content={previewUrl} /> +	<meta property="og:url" content={canonicalUrl} /> + +	<!-- Twitter Cards --> +	<meta name="twitter:card" content="summary_large_image" /> +	<meta name="twitter:title" content={title} /> +	<meta name="twitter:description" content={description} /> +	<meta name="twitter:image" content={previewUrl} /> +  	<JsonLd schema={schema} />  </head> diff --git a/src/components/OpenGraph.astro b/src/components/OpenGraph.astro deleted file mode 100644 index 6ca1856..0000000 --- a/src/components/OpenGraph.astro +++ /dev/null @@ -1,26 +0,0 @@ ---- -import { config } from "../config"; - -type Props = { -	readonly description: string; -	readonly title: string; -}; - -const canonicalURL = new URL(Astro.url.pathname, Astro.site); -const { description, title } = Astro.props; - -const image = new URL(config.posts.defaultImage, Astro.site).toString(); ---- - -<!-- Open Graph --> -<meta property="og:type" content="website" /> -<meta property="og:title" content={title} /> -<meta property="og:description" content={description} /> -<meta property="og:image" content={image} /> -<meta property="og:url" content={canonicalURL} /> - -<!-- Twitter Cards --> -<meta name="twitter:card" content="summary_large_image" /> -<meta name="twitter:title" content={title} /> -<meta name="twitter:description" content={description} /> -<meta name="twitter:image" content={image} /> diff --git a/src/config.ts b/src/config.ts index a1b0c15..d0c98ea 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,10 +1,29 @@  export const config = {  	author: {  		name: "Valentin Popov", +		email: "valentin@popov.link",  		url: "https://popov.link/",  		sameAs: ["https://www.linkedin.com/in/valentineus/", "https://github.com/valentineus"],  	}, -	posts: { -		defaultImage: "/images/photo.png", + +	// Open Graph +	og: { +		color: { +			bg: "#181818", +			bgCode: "#3b3d42", +			blossom: "#6da13f", +			text: "#dee2e6", +		}, +		defaultPreview: "/images/photo.png", +		dimensions: { +			height: 630, +			width: 1200, +		}, +		fonts: { +			bold: "./src/assets/JetBrainsMono/JetBrainsMono-Bold.ttf", +			regular: "./src/assets/JetBrainsMono/JetBrainsMono-Regular.ttf", +		}, +		photo: "./public/images/photo.png", +		website: "popov.link",  	},  }; diff --git a/src/integrations/ogImages.ts b/src/integrations/ogImages.ts new file mode 100644 index 0000000..5d9146c --- /dev/null +++ b/src/integrations/ogImages.ts @@ -0,0 +1,47 @@ +import type { AstroIntegration } from "astro"; +import { createOgImage } from "../utils/createOgImage"; +import { globby } from "globby"; +import fs from "fs/promises"; +import matter from "gray-matter"; +import path from "path"; + +const postsDir = path.resolve("./src/content/blog"); +const outDir = path.resolve("./public/images/preview"); + +export default function ogImageGenerator(): AstroIntegration { +	return { +		name: "og-images", +		hooks: { +			"astro:build:setup": async ({ logger }) => { +				await fs.mkdir(outDir, { recursive: true }); +				const mdFiles = await globby("*.md", { cwd: postsDir }); +				logger.info(`${mdFiles.length} posts found`); + +				const results = await Promise.allSettled( +					mdFiles.map(async (file) => { +						const slug = file.replace(/\.md$/, ""); +						const content = await fs.readFile(path.join(postsDir, file), "utf-8"); +						const { data } = matter(content); + +						const png = await createOgImage(data.title, data.datePublished); +						const outPath = path.join(outDir, `${slug}.png`); +						await fs.writeFile(outPath, png); + +						logger.info(`OG image created: ${slug}`); +					}) +				); + +				results.forEach((r) => { +					if (r.status === "rejected") { +						logger.error(`Error for ${r.reason.slug}: ${r.reason.message}`); +					} +				}); + +				const failures = results.filter((r) => r.status === "rejected"); +				if (failures.length) { +					throw new Error(`Failed to generate OG images for ${failures.length} posts`); +				} +			}, +		}, +	}; +} diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 216287e..ed3baeb 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -7,16 +7,17 @@ import "../scss/global.scss";  type Props = {  	readonly description: string; -	readonly title: string;  	readonly lang: string; +	readonly preview: string;  	readonly schema: WithContext<Thing>; +	readonly title: string;  }; -const { title, description, lang, schema } = Astro.props; +const { description, lang, preview, schema, title } = Astro.props;  ---  <html lang={lang}> -	<Head title={title} description={description} schema={schema} /> +	<Head title={title} description={description} preview={preview} schema={schema} />  	<body>  		<main> diff --git a/src/pages/404.astro b/src/pages/404.astro index cb3fca1..3ec9feb 100644 --- a/src/pages/404.astro +++ b/src/pages/404.astro @@ -1,9 +1,11 @@  --- +import { config } from "../config";  import Layout from "../layouts/BaseLayout.astro";  import pageSchema from "../utils/schemas/pageSchema";  const title = "404 — Page Not Found | Valentin Popov";  const description = "The page you're looking for doesn't exist!"; +const preview = config.og.defaultPreview;  const lang = "en";  const schema = pageSchema({ @@ -15,7 +17,7 @@ const schema = pageSchema({  });  --- -<Layout title={title} description={description} lang={lang} schema={schema}> +<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>  	<div style={{ "text-align": "center" }}>  		<h1>404</h1>  		<p><strong>Page not found</strong></p> diff --git a/src/pages/blog/[...slug].astro b/src/pages/blog/[...slug].astro index e347eda..d12ff05 100644 --- a/src/pages/blog/[...slug].astro +++ b/src/pages/blog/[...slug].astro @@ -25,6 +25,7 @@ const { Content, remarkPluginFrontmatter } = await post.render();  const description = post.data.description;  const isBasedOn = post.data.basedOn;  const lang = post.data.lang; +const preview = `/images/preview/${post.slug}.png`;  const slug = post.slug;  const title = post.data.title; @@ -34,13 +35,14 @@ const formattedDate = dayjs(post.data.datePublished.toString()).format("MMMM DD,  const schema = blogPostSchema({  	siteUrl: new URL("/", Astro.site).toString(), -	title, -	description, -	slug, -	datePublished,  	dateModified, -	lang, +	datePublished, +	description,  	isBasedOn, +	lang, +	preview, +	slug, +	title,  });  --- @@ -52,7 +54,7 @@ const schema = blogPostSchema({  	}  </style> -<Layout title={title} description={description} lang={lang} schema={schema}> +<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>  	<article>  		<header>  			<h1>{title}</h1> diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index de5a0a9..3a27111 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -1,9 +1,10 @@  ---  import type { CollectionEntry } from "astro:content"; +import { config } from "../../config";  import { getCollection } from "astro:content"; +import blogSchema from "../../utils/schemas/blogSchema";  import Layout from "../../layouts/BaseLayout.astro";  import PostElement from "../../components/PostElement.astro"; -import blogSchema from "../../utils/schemas/blogSchema";  import RSSIcon from "../../components/Icons/RSS.astro";  const posts = await getCollection("blog", ({ data }) => { @@ -25,6 +26,7 @@ const years = Object.keys(postsByYear).sort((a, b) => Number(b) - Number(a));  const title = "Valentin Popov's Blog | Software Development, Leadership & Open-Source";  const description = "Explore Valentin Popov's blog on software development, tech leadership, and open-source experiments. Stay updated with in-depth tutorials and expert insights."; +const preview = config.og.defaultPreview;  const lang = "en";  const schema = blogSchema({ @@ -34,7 +36,7 @@ const schema = blogSchema({  });  --- -<Layout title={title} description={description} lang={lang} schema={schema}> +<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>  	<section>  		<h1>  			Blog posts diff --git a/src/pages/index.astro b/src/pages/index.astro index b72c55a..b235b9b 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,12 +1,14 @@  --- -import Layout from "../layouts/BaseLayout.astro"; +import { config } from "../config";  import LatestPostsSection from "../components/Sections/LatestPosts.astro"; +import Layout from "../layouts/BaseLayout.astro"; +import pageSchema from "../utils/schemas/pageSchema";  import SocialLinksSection from "../components/Sections/SocialLinks.astro";  import WelcomeSection from "../components/Sections/Welcome.astro"; -import pageSchema from "../utils/schemas/pageSchema";  const title = "Valentin Popov – Software Developer & Team Lead | Tech Insights";  const description = "Blog by Valentin Popov — software developer and team lead writing about code, side projects, digital tools, and fun experiments."; +const preview = config.og.defaultPreview;  const lang = "en";  const schema = pageSchema({ @@ -18,7 +20,7 @@ const schema = pageSchema({  });  --- -<Layout title={title} description={description} lang={lang} schema={schema}> +<Layout title={title} description={description} preview={preview} lang={lang} schema={schema}>  	<WelcomeSection />  	<SocialLinksSection />  	<LatestPostsSection /> diff --git a/src/utils/createOgImage.ts b/src/utils/createOgImage.ts new file mode 100644 index 0000000..da2cece --- /dev/null +++ b/src/utils/createOgImage.ts @@ -0,0 +1,52 @@ +import { config } from "../config"; +import { html } from "satori-html"; +import { resources } from "./ogResources"; +import { Resvg } from "@resvg/resvg-js"; +import dayjs from "dayjs"; +import satori from "satori"; + +export async function createOgImage(title: string, datePublished: Date): Promise<Buffer> { +	const formattedDate = dayjs(datePublished).format("MMMM DD, YYYY"); + +	const markup = await satori( +		html(` +<div tw="flex flex-col w-full h-full" style="background-color: ${config.og.color.bg}"> +	<div tw="flex flex-col w-full h-4/5 p-10 justify-center"> +		<div tw="text-2xl mb-6" style="color: ${config.og.color.text}">${formattedDate}</div> +		<div tw="flex text-6xl w-full font-bold" style="color: ${config.og.color.text}">${title}</div> +	</div> +	<div tw="w-full h-1/5 flex p-10 items-center justify-between text-2xl" style="border-top: 1px solid ${config.og.color.bgCode}"> +		<div tw="flex items-center"> +			<span tw="ml-3" style="color: ${config.og.color.text}">${config.og.website.toLocaleUpperCase()}</span> +		</div> +		<div tw="flex items-center"> +			<img src="${resources.photoBase64}" tw="w-15 h-15 rounded-full" /> +			<div tw="flex flex-col ml-4"> +				<span style="color: ${config.og.color.text}">${config.author.name}</span> +				<span style="color: ${config.og.color.blossom}">${config.author.email}</span> +			</div> +		</div> +	</div> +</div> +`), +		{ +			width: config.og.dimensions.width, +			height: config.og.dimensions.height, +			fonts: [ +				{ +					name: "Inter", +					data: resources.fonts.regular, +					weight: 400, +				}, +				{ +					name: "Inter", +					data: resources.fonts.bold, +					weight: 700, +				}, +			], +		} +	); + +	const image = new Resvg(markup, { fitTo: { mode: "width", value: config.og.dimensions.width } }); +	return image.render().asPng(); +} diff --git a/src/utils/ogResources.ts b/src/utils/ogResources.ts new file mode 100644 index 0000000..8049fb2 --- /dev/null +++ b/src/utils/ogResources.ts @@ -0,0 +1,15 @@ +import { config } from "../config"; +import fs from "fs/promises"; +import path from "path"; +import sharp from "sharp"; + +export const resources = { +	fonts: { +		regular: await fs.readFile(path.resolve(config.og.fonts.regular)), +		bold: await fs.readFile(path.resolve(config.og.fonts.bold)), +	}, +	photoBase64: await (async () => { +		const buf = await fs.readFile(path.resolve(config.og.photo)); +		return "data:image/png;base64," + (await sharp(buf).resize(120, 120).png({ quality: 95 }).toBuffer()).toString("base64"); +	})(), +}; diff --git a/src/utils/schemas/blogPostSchema.ts b/src/utils/schemas/blogPostSchema.ts index 9e43478..87e1bf2 100644 --- a/src/utils/schemas/blogPostSchema.ts +++ b/src/utils/schemas/blogPostSchema.ts @@ -7,18 +7,19 @@ export type BlogPostSchemaParams = {  	readonly description: string;  	readonly isBasedOn?: string;  	readonly lang: string; +	readonly preview: string;  	readonly siteUrl: string;  	readonly slug: string;  	readonly title: string;  }; -export default ({ siteUrl, slug, title, description, datePublished, dateModified, lang, isBasedOn }: BlogPostSchemaParams): WithContext<BlogPosting> => ({ +export default ({ siteUrl, slug, title, description, preview, datePublished, dateModified, lang, isBasedOn }: BlogPostSchemaParams): WithContext<BlogPosting> => ({  	"@context": "https://schema.org",  	"@type": "BlogPosting",  	"url": new URL(`/blog/${slug}`, siteUrl).toString(),  	"headline": title,  	"description": description, -	"image": new URL(config.posts.defaultImage, siteUrl).toString(), +	"image": new URL(preview, siteUrl).toString(),  	"datePublished": datePublished,  	"dateModified": dateModified,  	"inLanguage": lang, | 
