diff --git a/Dockerfile b/Dockerfile index 14f5cfe..c474d59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:latest as node +FROM node:latest AS node USER node WORKDIR /usr/src/app @@ -10,3 +10,4 @@ RUN ["npx", "astro", "build"] FROM ghcr.io/static-web-server/static-web-server:latest WORKDIR / COPY --from=node /usr/src/app/dist /public +ENV SERVER_REDIRECT_TRAILING_SLASH=false diff --git a/astro.config.ts b/astro.config.ts index 31f768e..299a775 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from "astro/config"; +import { defineConfig, fontProviders } from "astro/config"; import sitemap from "@astrojs/sitemap"; import rehypeExternalLinks from "rehype-external-links"; import mdx from "@astrojs/mdx"; @@ -31,4 +31,23 @@ export default defineConfig({ }, }, }, + redirects: { + "/archive": "/projects/archive", + }, + experimental: { + fonts: [ + { + provider: fontProviders.fontsource(), + name: "Outfit", + cssVariable: "--font-outfit", + weights: ["100 900"], + }, + { + provider: fontProviders.fontsource(), + name: "Red Hat Mono", + cssVariable: "--font-red-hat-mono", + weights: ["300 700"], + }, + ], + }, }); diff --git a/package-lock.json b/package-lock.json index 6429d96..6682207 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,23 +9,21 @@ "version": "0.0.1", "dependencies": { "@astrojs/check": "0.9.4", - "@astrojs/mdx": "^4.1.1", + "@astrojs/mdx": "^4.2.6", "@astrojs/rss": "^4.0.11", - "@astrojs/sitemap": "3.2.1", - "@fontsource-variable/outfit": "^5.2.5", - "@fontsource-variable/red-hat-mono": "^5.2.5", - "@tailwindcss/vite": "^4.0.13", - "astro": "^5.4.3", + "@astrojs/sitemap": "3.3.1", + "@tailwindcss/vite": "^4.1.5", + "astro": "^5.7.10", "astro-icon": "^1.1.5", "rehype-external-links": "^3.0.0", - "tailwindcss": "^4.0.13", - "typescript": "^5.8.2" + "tailwindcss": "^4.1.5", + "typescript": "^5.8.3" }, "devDependencies": { "@iconify-json/mdi": "^1.2.3", "@tailwindcss/typography": "^0.5.16", - "@types/node": "^22.13.10", - "npm-check-updates": "^17.1.15", + "@types/node": "^22.15.3", + "npm-check-updates": "^18.0.1", "prettier": "^3.5.3", "prettier-plugin-astro": "^0.14.1", "prettier-plugin-tailwindcss": "^0.6.11" @@ -72,9 +70,9 @@ } }, "node_modules/@astrojs/compiler": { - "version": "2.10.4", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.10.4.tgz", - "integrity": "sha512-86B3QGagP99MvSNwuJGiYSBHnh8nLvm2Q1IFI15wIUJJsPeQTO3eb2uwBmrqRsXykeR/mBzH8XCgz5AAt1BJrQ==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.11.0.tgz", + "integrity": "sha512-zZOO7i+JhojO8qmlyR/URui6LyfHJY6m+L9nwyX5GiKD78YoRaZ5tzz6X0fkl+5bD3uwlDHayf6Oe8Fu36RKNg==", "license": "MIT" }, "node_modules/@astrojs/internal-helpers": { @@ -125,9 +123,9 @@ } }, "node_modules/@astrojs/markdown-remark": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.2.1.tgz", - "integrity": "sha512-qtQXfZXeG84XSH9bMgG2e/kZfA4J7U19PKjhmFDNsKX47nautSHC0DitvxaWgQFSED66k6hWKDHLq3VKHCy/rg==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.1.tgz", + "integrity": "sha512-c5F5gGrkczUaTVgmMW9g1YMJGzOtRvjjhw6IfGuxarM6ct09MpwysP10US729dy07gg8y+ofVifezvP3BNsWZg==", "license": "MIT", "dependencies": { "@astrojs/internal-helpers": "0.6.1", @@ -144,7 +142,7 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.1", "remark-smartypants": "^3.0.2", - "shiki": "^1.29.2", + "shiki": "^3.0.0", "smol-toml": "^1.3.1", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", @@ -154,14 +152,14 @@ } }, "node_modules/@astrojs/mdx": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.1.1.tgz", - "integrity": "sha512-zz/x7wL4nQukG4XKZONainVr31uArB/Jnbq0NvhOGw2LCDhVQ6d9yIYxma5hJ8PU5QjLu8bWHz7ZGRD37GBWJw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.2.6.tgz", + "integrity": "sha512-0i/GmOm6d0qq1/SCfcUgY/IjDc/bS0i42u7h85TkPFBmlFOcBZfkYhR5iyz6hZLwidvJOEq5yGfzt9B1Azku4w==", "license": "MIT", "dependencies": { - "@astrojs/markdown-remark": "6.2.1", + "@astrojs/markdown-remark": "6.3.1", "@mdx-js/mdx": "^3.1.0", - "acorn": "^8.14.0", + "acorn": "^8.14.1", "es-module-lexer": "^1.6.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", @@ -203,24 +201,24 @@ } }, "node_modules/@astrojs/sitemap": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.2.1.tgz", - "integrity": "sha512-uxMfO8f7pALq0ADL6Lk68UV6dNYjJ2xGUzyjjVj60JLBs5a6smtlkBYv3tQ0DzoqwS7c9n4FUx5lgv0yPo/fgA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.3.1.tgz", + "integrity": "sha512-GRnDUCTviBSNfXJ0Jmur+1/C+z3g36jy79VyYggfe1uNyEYSTcmAfTTCmbytrRvJRNyJJnSfB/77Gnm9PiXRRg==", "license": "MIT", "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", - "zod": "^3.23.8" + "zod": "^3.24.2" } }, "node_modules/@astrojs/telemetry": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.2.0.tgz", - "integrity": "sha512-wxhSKRfKugLwLlr4OFfcqovk+LIFtKwLyGPqMsv+9/ibqqnW3Gv7tBhtKEb0gAyUAC4G9BTVQeQahqnQAhd6IQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.2.1.tgz", + "integrity": "sha512-SSVM820Jqc6wjsn7qYfV9qfeQvePtVc1nSofhyap7l0/iakUKywj3hfy3UJAOV4sGV4Q/u450RD4AaCaFvNPlg==", "license": "MIT", "dependencies": { - "ci-info": "^4.1.0", - "debug": "^4.3.7", + "ci-info": "^4.2.0", + "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", @@ -286,6 +284,17 @@ "node": ">=6.9.0" } }, + "node_modules/@capsizecss/unpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@capsizecss/unpack/-/unpack-2.4.0.tgz", + "integrity": "sha512-GrSU71meACqcmIUxPYOJvGKF0yryjN/L1aCuE9DViCTJI7bfkjgYDPD1zbNDcINJwSSP6UaBZY9GAbYDO7re0Q==", + "license": "MIT", + "dependencies": { + "blob-to-buffer": "^1.2.8", + "cross-fetch": "^3.0.4", + "fontkit": "^2.0.2" + } + }, "node_modules/@emmetio/abbreviation": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", @@ -751,24 +760,6 @@ "node": ">=18" } }, - "node_modules/@fontsource-variable/outfit": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@fontsource-variable/outfit/-/outfit-5.2.5.tgz", - "integrity": "sha512-MejrIp6Cbmd3u5AZtsot8kmhZiyQM5CATsdcBB2hktYIrv5CVekRSUmFDXL4FpF7K70IvFp2ZMfImm5VhnVf7Q==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource-variable/red-hat-mono": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@fontsource-variable/red-hat-mono/-/red-hat-mono-5.2.5.tgz", - "integrity": "sha512-BP2zCfaBvjvx/+ijLYH6joqQ7aZyM5XecNuXSPUQ3G05fjU3q2MfEPT8CjIQ6LgsSpCxWOmrdlxOofDb/8pp2g==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, "node_modules/@iconify-json/mdi": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@iconify-json/mdi/-/mdi-1.2.3.tgz", @@ -1557,65 +1548,63 @@ ] }, "node_modules/@shikijs/core": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.29.2.tgz", - "integrity": "sha512-vju0lY9r27jJfOY4Z7+Rt/nIOjzJpZ3y+nYpqtUZInVoXQ/TJZcfGnNOGnKjFdVZb8qexiCuSlZRKcGfhhTTZQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.2.1.tgz", + "integrity": "sha512-FhsdxMWYu/C11sFisEp7FMGBtX/OSSbnXZDMBhGuUDBNTdsoZlMSgQv5f90rwvzWAdWIW6VobD+G3IrazxA6dQ==", "license": "MIT", "dependencies": { - "@shikijs/engine-javascript": "1.29.2", - "@shikijs/engine-oniguruma": "1.29.2", - "@shikijs/types": "1.29.2", - "@shikijs/vscode-textmate": "^10.0.1", + "@shikijs/types": "3.2.1", + "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", - "hast-util-to-html": "^9.0.4" + "hast-util-to-html": "^9.0.5" } }, "node_modules/@shikijs/engine-javascript": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.29.2.tgz", - "integrity": "sha512-iNEZv4IrLYPv64Q6k7EPpOCE/nuvGiKl7zxdq0WFuRPF5PAE9PRo2JGq/d8crLusM59BRemJ4eOqrFrC4wiQ+A==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.2.1.tgz", + "integrity": "sha512-eMdcUzN3FMQYxOmRf2rmU8frikzoSHbQDFH2hIuXsrMO+IBOCI9BeeRkCiBkcLDHeRKbOCtYMJK3D6U32ooU9Q==", "license": "MIT", "dependencies": { - "@shikijs/types": "1.29.2", - "@shikijs/vscode-textmate": "^10.0.1", - "oniguruma-to-es": "^2.2.0" + "@shikijs/types": "3.2.1", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.1.0" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.29.2.tgz", - "integrity": "sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.2.1.tgz", + "integrity": "sha512-wZZAkayEn6qu2+YjenEoFqj0OyQI64EWsNR6/71d1EkG4sxEOFooowKivsWPpaWNBu3sxAG+zPz5kzBL/SsreQ==", "license": "MIT", "dependencies": { - "@shikijs/types": "1.29.2", - "@shikijs/vscode-textmate": "^10.0.1" + "@shikijs/types": "3.2.1", + "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-1.29.2.tgz", - "integrity": "sha512-FIBA7N3LZ+223U7cJDUYd5shmciFQlYkFXlkKVaHsCPgfVLiO+e12FmQE6Tf9vuyEsFe3dIl8qGWKXgEHL9wmQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.2.1.tgz", + "integrity": "sha512-If0iDHYRSGbihiA8+7uRsgb1er1Yj11pwpX1c6HLYnizDsKAw5iaT3JXj5ZpaimXSWky/IhxTm7C6nkiYVym+A==", "license": "MIT", "dependencies": { - "@shikijs/types": "1.29.2" + "@shikijs/types": "3.2.1" } }, "node_modules/@shikijs/themes": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-1.29.2.tgz", - "integrity": "sha512-i9TNZlsq4uoyqSbluIcZkmPL9Bfi3djVxRnofUHwvx/h6SRW3cwgBC5SML7vsDcWyukY0eCzVN980rqP6qNl9g==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.2.1.tgz", + "integrity": "sha512-k5DKJUT8IldBvAm8WcrDT5+7GA7se6lLksR+2E3SvyqGTyFMzU2F9Gb7rmD+t+Pga1MKrYFxDIeyWjMZWM6uBQ==", "license": "MIT", "dependencies": { - "@shikijs/types": "1.29.2" + "@shikijs/types": "3.2.1" } }, "node_modules/@shikijs/types": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.29.2.tgz", - "integrity": "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.2.1.tgz", + "integrity": "sha512-/NTWAk4KE2M8uac0RhOsIhYQf4pdU0OywQuYDGIGAJ6Mjunxl2cGiuLkvu4HLCMn+OTTLRWkjZITp+aYJv60yA==", "license": "MIT", "dependencies": { - "@shikijs/vscode-textmate": "^10.0.1", + "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, @@ -1625,43 +1614,54 @@ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, + "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==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@tailwindcss/node": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.13.tgz", - "integrity": "sha512-P9TmtE9Vew0vv5FwyD4bsg/dHHsIsAuUXkenuGUc5gm8fYgaxpdoxIKngCyEMEQxyCKR8PQY5V5VrrKNOx7exg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.5.tgz", + "integrity": "sha512-CBhSWo0vLnWhXIvpD0qsPephiaUYfHUX3U9anwDaHZAeuGpTiB3XmsxPAN6qX7bFhipyGBqOa1QYQVVhkOUGxg==", "license": "MIT", "dependencies": { "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", - "tailwindcss": "4.0.13" + "lightningcss": "1.29.2", + "tailwindcss": "4.1.5" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.13.tgz", - "integrity": "sha512-pTH3Ex5zAWC9LbS+WsYAFmkXQW3NRjmvxkKJY3NP1x0KHBWjz0Q2uGtdGMJzsa0EwoZ7wq9RTbMH1UNPceCpWw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.5.tgz", + "integrity": "sha512-1n4br1znquEvyW/QuqMKQZlBen+jxAbvyduU87RS8R3tUSvByAkcaMTkJepNIrTlYhD+U25K4iiCIxE6BGdRYA==", "license": "MIT", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.0.13", - "@tailwindcss/oxide-darwin-arm64": "4.0.13", - "@tailwindcss/oxide-darwin-x64": "4.0.13", - "@tailwindcss/oxide-freebsd-x64": "4.0.13", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.13", - "@tailwindcss/oxide-linux-arm64-gnu": "4.0.13", - "@tailwindcss/oxide-linux-arm64-musl": "4.0.13", - "@tailwindcss/oxide-linux-x64-gnu": "4.0.13", - "@tailwindcss/oxide-linux-x64-musl": "4.0.13", - "@tailwindcss/oxide-win32-arm64-msvc": "4.0.13", - "@tailwindcss/oxide-win32-x64-msvc": "4.0.13" + "@tailwindcss/oxide-android-arm64": "4.1.5", + "@tailwindcss/oxide-darwin-arm64": "4.1.5", + "@tailwindcss/oxide-darwin-x64": "4.1.5", + "@tailwindcss/oxide-freebsd-x64": "4.1.5", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.5", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.5", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.5", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.5", + "@tailwindcss/oxide-linux-x64-musl": "4.1.5", + "@tailwindcss/oxide-wasm32-wasi": "4.1.5", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.5", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.5" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.13.tgz", - "integrity": "sha512-+9zmwaPQ8A9ycDcdb+hRkMn6NzsmZ4YJBsW5Xqq5EdOu9xlIgmuMuJauVzDPB5BSbIWfhPdZ+le8NeRZpl1coA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.5.tgz", + "integrity": "sha512-LVvM0GirXHED02j7hSECm8l9GGJ1RfgpWCW+DRn5TvSaxVsv28gRtoL4aWKGnXqwvI3zu1GABeDNDVZeDPOQrw==", "cpu": [ "arm64" ], @@ -1675,9 +1675,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.13.tgz", - "integrity": "sha512-Bj1QGlEJSjs/205CIRfb5/jeveOqzJ4pFMdRxu0gyiYWxBRyxsExXqaD+7162wnLP/EDKh6S1MC9E/1GwEhLtA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.5.tgz", + "integrity": "sha512-//TfCA3pNrgnw4rRJOqavW7XUk8gsg9ddi8cwcsWXp99tzdBAZW0WXrD8wDyNbqjW316Pk2hiN/NJx/KWHl8oA==", "cpu": [ "arm64" ], @@ -1691,9 +1691,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.13.tgz", - "integrity": "sha512-lRTkxjTpMGXhLLM5GjZ0MtjPczMuhAo9j7PeSsaU6Imkm7W7RbrXfT8aP934kS7cBBV+HKN5U19Z0WWaORfb8Q==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.5.tgz", + "integrity": "sha512-XQorp3Q6/WzRd9OalgHgaqgEbjP3qjHrlSUb5k1EuS1Z9NE9+BbzSORraO+ecW432cbCN7RVGGL/lSnHxcd+7Q==", "cpu": [ "x64" ], @@ -1707,9 +1707,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.13.tgz", - "integrity": "sha512-p/YLyKhs+xFibVeAPlpMGDVMKgjChgzs12VnDFaaqRSJoOz+uJgRSKiir2tn50e7Nm4YYw35q/DRBwpDBNo1MQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.5.tgz", + "integrity": "sha512-bPrLWbxo8gAo97ZmrCbOdtlz/Dkuy8NK97aFbVpkJ2nJ2Jo/rsCbu0TlGx8joCuA3q6vMWTSn01JY46iwG+clg==", "cpu": [ "x64" ], @@ -1723,9 +1723,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.13.tgz", - "integrity": "sha512-Ua/5ydE/QOTX8jHuc7M9ICWnaLi6K2MV/r+Ws2OppsOjy8tdlPbqYainJJ6Kl7ofm524K+4Fk9CQITPzeIESPw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.5.tgz", + "integrity": "sha512-1gtQJY9JzMAhgAfvd/ZaVOjh/Ju/nCoAsvOVJenWZfs05wb8zq+GOTnZALWGqKIYEtyNpCzvMk+ocGpxwdvaVg==", "cpu": [ "arm" ], @@ -1739,9 +1739,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.13.tgz", - "integrity": "sha512-/W1+Q6tBAVgZWh/bhfOHo4n7Ryh6E7zYj4bJd9SRbkPyLtRioyK3bi6RLuDj57sa7Amk/DeomSV9iycS0xqIPA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.5.tgz", + "integrity": "sha512-dtlaHU2v7MtdxBXoqhxwsWjav7oim7Whc6S9wq/i/uUMTWAzq/gijq1InSgn2yTnh43kR+SFvcSyEF0GCNu1PQ==", "cpu": [ "arm64" ], @@ -1755,9 +1755,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.13.tgz", - "integrity": "sha512-GQj6TWevNxwsYw20FdT2r2d1f7uiRsF07iFvNYxPIvIyPEV74eZ0zgFEsAH1daK1OxPy+LXdZ4grV17P5tVzhQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.5.tgz", + "integrity": "sha512-fg0F6nAeYcJ3CriqDT1iVrqALMwD37+sLzXs8Rjy8Z1ZHshJoYceodfyUwGJEsQoTyWbliFNRs2wMQNXtT7MVA==", "cpu": [ "arm64" ], @@ -1771,9 +1771,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.13.tgz", - "integrity": "sha512-sQRH09faifF9w9WS6TKDWr1oLi4hoPx0EIWXZHQK/jcjarDpXGQ2DbF0KnALJCwWBxOIP/1nrmU01fZwwMzY3g==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.5.tgz", + "integrity": "sha512-SO+F2YEIAHa1AITwc8oPwMOWhgorPzzcbhWEb+4oLi953h45FklDmM8dPSZ7hNHpIk9p/SCZKUYn35t5fjGtHA==", "cpu": [ "x64" ], @@ -1787,9 +1787,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.13.tgz", - "integrity": "sha512-Or1N8DIF3tP+LsloJp+UXLTIMMHMUcWXFhJLCsM4T7MzFzxkeReewRWXfk5mk137cdqVeUEH/R50xAhY1mOkTQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.5.tgz", + "integrity": "sha512-6UbBBplywkk/R+PqqioskUeXfKcBht3KU7juTi1UszJLx0KPXUo10v2Ok04iBJIaDPkIFkUOVboXms5Yxvaz+g==", "cpu": [ "x64" ], @@ -1802,10 +1802,39 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.5.tgz", + "integrity": "sha512-hwALf2K9FHuiXTPqmo1KeOb83fTRNbe9r/Ixv9ZNQ/R24yw8Ge1HOWDDgTdtzntIaIUJG5dfXCf4g9AD4RiyhQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.9", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.13.tgz", - "integrity": "sha512-u2mQyqCFrr9vVTP6sfDRfGE6bhOX3/7rInehzxNhHX1HYRIx09H3sDdXzTxnZWKOjIg3qjFTCrYFUZckva5PIg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.5.tgz", + "integrity": "sha512-oDKncffWzaovJbkuR7/OTNFRJQVdiw/n8HnzaCItrNQUeQgjy7oUiYpsm9HUBgpmvmDpSSbGaCa2Evzvk3eFmA==", "cpu": [ "arm64" ], @@ -1819,9 +1848,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.13.tgz", - "integrity": "sha512-sOEc4iCanp1Yqyeu9suQcEzfaUcHnqjBUgDg0ZXpjUMUwdSi37S1lu1RGoV1BYInvvGu3y3HHTmvsSfDhx2L8w==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.5.tgz", + "integrity": "sha512-WiR4dtyrFdbb+ov0LK+7XsFOsG+0xs0PKZKkt41KDn9jYpO7baE3bXiudPVkTqUEwNfiglCygQHl2jklvSBi7Q==", "cpu": [ "x64" ], @@ -1851,15 +1880,14 @@ } }, "node_modules/@tailwindcss/vite": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.13.tgz", - "integrity": "sha512-0XTd/NoVUAktIDaA4MdXhve0QWYh7WlZg20EHCuBFR80F8FhbVkRX+AY5cjbUP/IO2itHzt0iHc0iSE5kBUMhQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.5.tgz", + "integrity": "sha512-FE1stRoqdHSb7RxesMfCXE8icwI1W6zGE/512ae3ZDrpkQYTTYeSyUJPRCjZd8CwVAhpDUbi1YR8pcZioFJQ/w==", "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.0.13", - "@tailwindcss/oxide": "4.0.13", - "lightningcss": "1.29.2", - "tailwindcss": "4.0.13" + "@tailwindcss/node": "4.1.5", + "@tailwindcss/oxide": "4.1.5", + "tailwindcss": "4.1.5" }, "peerDependencies": { "vite": "^5.2.0 || ^6" @@ -1883,12 +1911,6 @@ "@types/estree": "*" } }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "license": "MIT" - }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -1953,12 +1975,12 @@ } }, "node_modules/@types/node": { - "version": "22.13.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz", - "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==", + "version": "22.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", + "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==", "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~6.21.0" } }, "node_modules/@types/sax": { @@ -2093,9 +2115,9 @@ "license": "MIT" }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2269,26 +2291,26 @@ } }, "node_modules/astro": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/astro/-/astro-5.4.3.tgz", - "integrity": "sha512-GKkOJQCHLx6CrPoghGhj7824WDSvIuuc+HTVjfjMPdB9axp238iJLByREJNDaSdzMeR/lC13xvBiUnKvcYyEIA==", + "version": "5.7.10", + "resolved": "https://registry.npmjs.org/astro/-/astro-5.7.10.tgz", + "integrity": "sha512-9TQcFZqP2w6//JXXUHfw8/5PX7KUx9EkG5O3m+hISuyeUztvjY1q5+p7+C5HiXyg24Zs3KkpieoL5BGRXGCAGA==", "license": "MIT", "dependencies": { - "@astrojs/compiler": "^2.10.4", + "@astrojs/compiler": "^2.11.0", "@astrojs/internal-helpers": "0.6.1", - "@astrojs/markdown-remark": "6.2.1", - "@astrojs/telemetry": "3.2.0", + "@astrojs/markdown-remark": "6.3.1", + "@astrojs/telemetry": "3.2.1", + "@capsizecss/unpack": "^2.4.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.1.4", - "@types/cookie": "^0.6.0", - "acorn": "^8.14.0", + "acorn": "^8.14.1", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", - "ci-info": "^4.1.0", + "ci-info": "^4.2.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", - "cookie": "^0.7.2", + "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.0", "deterministic-object-hash": "^2.0.2", @@ -2311,26 +2333,27 @@ "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", - "package-manager-detector": "^1.0.0", + "package-manager-detector": "^1.1.0", "picomatch": "^4.0.2", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.1", - "shiki": "^1.29.2", + "shiki": "^3.2.1", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.12", "tsconfck": "^3.1.5", - "ultrahtml": "^1.5.3", + "ultrahtml": "^1.6.0", + "unifont": "~0.4.1", "unist-util-visit": "^5.0.0", "unstorage": "^1.15.0", "vfile": "^6.0.3", - "vite": "^6.2.0", + "vite": "^6.3.4", "vitefu": "^1.0.6", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.1", "zod": "^3.24.2", - "zod-to-json-schema": "^3.24.3", + "zod-to-json-schema": "^3.24.5", "zod-to-ts": "^1.2.0" }, "bin": { @@ -2361,9 +2384,9 @@ } }, "node_modules/astro/node_modules/package-manager-detector": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.0.0.tgz", - "integrity": "sha512-7elnH+9zMsRo7aS72w6MeRugTpdRvInmEB4Kmm9BVvPw/SLG8gXUGQ+4wF0Mys0RSWPz0B9nuBbDe8vFeA2sfg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.1.0.tgz", + "integrity": "sha512-Y8f9qUlBzW8qauJjd/eu6jlpJZsuPJm2ZAV0cDVd420o4EdpH5RPdoCv+60/TdJflGatr4sDfpAL6ArWZbM5tA==", "license": "MIT" }, "node_modules/asynckit": { @@ -2408,6 +2431,46 @@ "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/blob-to-buffer": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/blob-to-buffer/-/blob-to-buffer-1.2.9.tgz", + "integrity": "sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -2448,6 +2511,15 @@ "node": ">=8" } }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -2611,9 +2683,9 @@ } }, "node_modules/ci-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.1.0.tgz", - "integrity": "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", + "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", "funding": [ { "type": "github", @@ -2724,6 +2796,15 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -2830,12 +2911,12 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=18" } }, "node_modules/cookie-es": { @@ -2844,6 +2925,15 @@ "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", "license": "MIT" }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/crossws": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.4.tgz", @@ -3039,6 +3129,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "license": "MIT" + }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -3549,9 +3645,9 @@ } }, "node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "license": "MIT", "peerDependencies": { "picomatch": "^3 || ^4" @@ -3603,6 +3699,23 @@ } } }, + "node_modules/fontkit": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", + "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.12", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "dfa": "^1.2.0", + "fast-deep-equal": "^3.1.3", + "restructure": "^3.0.0", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.4.0", + "unicode-trie": "^2.0.0" + } + }, "node_modules/form-data": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", @@ -5917,6 +6030,26 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-fetch-native": { "version": "1.6.6", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", @@ -5939,9 +6072,9 @@ } }, "node_modules/npm-check-updates": { - "version": "17.1.15", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.15.tgz", - "integrity": "sha512-miATvKu5rjec/1wxc5TGDjpsucgtCHwRVZorZpDkS6NzdWXfnUWlN4abZddWb7XSijAuBNzzYglIdTm9SbgMVg==", + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-18.0.1.tgz", + "integrity": "sha512-MO7mLp/8nm6kZNLLyPgz4gHmr9tLoU+pWPLdXuGAx+oZydBHkHWN0ibTonsrfwC2WEQNIQxuZagYwB67JQpAuw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5976,6 +6109,12 @@ "ufo": "^1.5.4" } }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5985,15 +6124,22 @@ "wrappy": "1" } }, + "node_modules/oniguruma-parser": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.5.4.tgz", + "integrity": "sha512-yNxcQ8sKvURiTwP0mV6bLQCYE7NKfKRRWunhbZnXgxSmB1OXa1lHrN3o4DZd+0Si0kU5blidK7BcROO8qv5TZA==", + "license": "MIT" + }, "node_modules/oniguruma-to-es": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-2.3.0.tgz", - "integrity": "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.1.0.tgz", + "integrity": "sha512-SNwG909cSLo4vPyyPbU/VJkEc9WOXqu2ycBlfd1UCXLqk1IijcQktSBb2yRQ2UFPsDhpkaf+C1dtT3PkLK/yWA==", "license": "MIT", "dependencies": { "emoji-regex-xs": "^1.0.0", - "regex": "^5.1.1", - "regex-recursion": "^5.1.1" + "oniguruma-parser": "^0.5.4", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" } }, "node_modules/p-limit": { @@ -6048,6 +6194,12 @@ "quansync": "^0.2.7" } }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, "node_modules/parse-entities": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", @@ -6510,21 +6662,20 @@ } }, "node_modules/regex": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/regex/-/regex-5.1.1.tgz", - "integrity": "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", + "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" } }, "node_modules/regex-recursion": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-5.1.1.tgz", - "integrity": "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", "license": "MIT", "dependencies": { - "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, @@ -6747,6 +6898,12 @@ "node": ">=0.10.0" } }, + "node_modules/restructure": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", + "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==", + "license": "MIT" + }, "node_modules/retext": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/retext/-/retext-9.0.0.tgz", @@ -6961,18 +7118,18 @@ } }, "node_modules/shiki": { - "version": "1.29.2", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.29.2.tgz", - "integrity": "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.2.1.tgz", + "integrity": "sha512-VML/2o1/KGYkEf/stJJ+s9Ypn7jUKQPomGLGYso4JJFMFxVDyPNsjsI3MB3KLjlMOeH44gyaPdXC6rik2WXvUQ==", "license": "MIT", "dependencies": { - "@shikijs/core": "1.29.2", - "@shikijs/engine-javascript": "1.29.2", - "@shikijs/engine-oniguruma": "1.29.2", - "@shikijs/langs": "1.29.2", - "@shikijs/themes": "1.29.2", - "@shikijs/types": "1.29.2", - "@shikijs/vscode-textmate": "^10.0.1", + "@shikijs/core": "3.2.1", + "@shikijs/engine-javascript": "3.2.1", + "@shikijs/engine-oniguruma": "3.2.1", + "@shikijs/langs": "3.2.1", + "@shikijs/themes": "3.2.1", + "@shikijs/types": "3.2.1", + "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, @@ -7166,9 +7323,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.13.tgz", - "integrity": "sha512-gbvFrB0fOsTv/OugXWi2PtflJ4S6/ctu6Mmn3bCftmLY/6xRsQVEJPgIIpABwpZ52DpONkCA3bEj5b54MHxF2Q==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.5.tgz", + "integrity": "sha512-nYtSPfWGDiWgCkwQG/m+aX83XCwf62sBgg3bIlNiiOcggnS1x3uVRDAuyelBFL+vJdOPPCGElxv9DjHJjRHiVA==", "license": "MIT" }, "node_modules/tapable": { @@ -7206,6 +7363,12 @@ "node": ">=8" } }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, "node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", @@ -7213,12 +7376,12 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -7240,6 +7403,12 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -7284,8 +7453,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/type-fest": { "version": "4.36.0", @@ -7306,9 +7474,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -7334,9 +7502,9 @@ "license": "MIT" }, "node_modules/ultrahtml": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz", - "integrity": "sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", + "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", "license": "MIT" }, "node_modules/uncrypto": { @@ -7355,11 +7523,31 @@ } }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -7379,6 +7567,35 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unifont": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.4.1.tgz", + "integrity": "sha512-zKSY9qO8svWYns+FGKjyVdLvpGPwqmsCjeJLN1xndMiqxHWBAhoWDMYMG960MxeV48clBmG+fDP59dHY1VoZvg==", + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0", + "ohash": "^2.0.0" + } + }, + "node_modules/unifont/node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/unifont/node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "license": "CC0-1.0" + }, "node_modules/unist-util-find-after": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz", @@ -7657,14 +7874,17 @@ } }, "node_modules/vite": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz", - "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", "license": "MIT", "dependencies": { "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", "postcss": "^8.5.3", - "rollup": "^4.30.1" + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" @@ -7992,6 +8212,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -8013,6 +8239,16 @@ "node": ">=18" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", @@ -8312,9 +8548,9 @@ } }, "node_modules/zod-to-json-schema": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz", - "integrity": "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==", + "version": "3.24.5", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", + "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", "license": "ISC", "peerDependencies": { "zod": "^3.24.1" diff --git a/package.json b/package.json index 04f7784..c88ab5a 100644 --- a/package.json +++ b/package.json @@ -13,25 +13,23 @@ }, "dependencies": { "@astrojs/check": "0.9.4", - "@astrojs/mdx": "^4.1.1", + "@astrojs/mdx": "^4.2.6", "@astrojs/rss": "^4.0.11", - "@astrojs/sitemap": "3.2.1", - "@fontsource-variable/outfit": "^5.2.5", - "@fontsource-variable/red-hat-mono": "^5.2.5", - "@tailwindcss/vite": "^4.0.13", - "astro": "^5.4.3", + "@astrojs/sitemap": "3.3.1", + "@tailwindcss/vite": "^4.1.5", + "astro": "^5.7.10", "astro-icon": "^1.1.5", "rehype-external-links": "^3.0.0", - "tailwindcss": "^4.0.13", - "typescript": "^5.8.2" + "tailwindcss": "^4.1.5", + "typescript": "^5.8.3" }, "devDependencies": { "@iconify-json/mdi": "^1.2.3", "@tailwindcss/typography": "^0.5.16", - "@types/node": "^22.13.10", + "@types/node": "^22.15.3", + "npm-check-updates": "^18.0.1", "prettier": "^3.5.3", "prettier-plugin-astro": "^0.14.1", - "prettier-plugin-tailwindcss": "^0.6.11", - "npm-check-updates": "^17.1.15" + "prettier-plugin-tailwindcss": "^0.6.11" } } diff --git a/src/components/Article.astro b/src/components/Article.astro index 0c35777..dbfb523 100644 --- a/src/components/Article.astro +++ b/src/components/Article.astro @@ -9,15 +9,28 @@ import RelatedArticles from "@components/RelatedArticles.astro"; const { article, isPost = false } = Astro.props; const { Content } = await article.render(); -let datesMatch = false; -if (article.data.date.getTime() == article.data.updated?.getTime()) { - datesMatch = true; +interface NameAndUrl { + name: string; + url: string; } -const listFormatter = new Intl.ListFormat("en-GB", { - style: "long", - type: "conjunction", -}); +function formatNamesWithLinks(namesAndUrls: NameAndUrl[]) { + const listFormatter = new Intl.ListFormat("en-GB", { + style: "long", + type: "conjunction", + }); + + const linkedNames = namesAndUrls.map((item: NameAndUrl) => { + return `${item.name}`; + }); + + return listFormatter.format(linkedNames); +} + +let formattedList: string | null = null; +if (article.data.extraAuthors && article.data.extraAuthors.length !== 0) { + formattedList = formatNamesWithLinks(article.data.extraAuthors); +} --- { - datesMatch ? ( + !article.data.updated ? (

@@ -70,9 +83,7 @@ const listFormatter = new Intl.ListFormat("en-GB", { article.data.extraAuthors ? (
-

- {listFormatter.format(article.data.extraAuthors)} -

+

) : null } @@ -80,7 +91,7 @@ const listFormatter = new Intl.ListFormat("en-GB", { article.data.tags ? (
- {article.data.tags.map((tag: any) => ( + {article.data.tags.map((tag: string) => (
{link}
diff --git a/src/components/CvProjects.astro b/src/components/CvProjects.astro new file mode 100644 index 0000000..5b639d6 --- /dev/null +++ b/src/components/CvProjects.astro @@ -0,0 +1,91 @@ +--- +import Link from "@components/Link.astro"; +import { createSlug } from "@lib/utils"; + +const projects = [ + { + id: 1, + name: "MUST FIND BEANS", + description: + "A fast-paced first person shooter set following the realization that you’re all out of beans. The problem is, you’re nearing the end of cooking all the other items and you can’t just not have them. Without beans, the day just won’t be started off right.", + tags: ["Godot", "Blender", "GIMP", "Steamworks"], + link: "/projects/must-find-beans", + done: false, + }, + { + id: 2, + name: "troylusty.com", + description: + "My personal website made using Astro as a way to show off my portfolio of work and display blog posts.", + tags: [ + "Astro", + "Tailwind CSS", + "TypeScript", + "Self-hosted Forgejo Actions", + "Docker", + ], + link: "https://code.troylusty.com/troy/troylusty.com", + done: true, + }, + { + id: 3, + name: "Artwork", + description: + "A collection of digital artwork created with a variety of tools.", + tags: ["Blender", "Cinema 4D", "DaVinci Resolve"], + link: "/projects", + done: true, + }, + { + id: 4, + name: "Packard", + description: + "Packard is a simple terminal based RSS aggregator meant to allow you to take a quick glance at what’s occurring in topics you care about.", + tags: ["Rust", "Tokio", "Clap", "NixOS Flake"], + link: "/projects/packard", + done: true, + }, +]; +const sortedProjects = [...projects].sort((a, b) => a.id - b.id); +--- + +
    + { + sortedProjects.map((project) => ( +
  1. +
    +
    + <> +

    + + {project.done ? ( + + ) : ( + + )} + {project.name} + +

    +

    {project.description}

    + +
    +
    +
    +
  2. + )) + } +
diff --git a/src/components/Gallery.astro b/src/components/Gallery.astro new file mode 100644 index 0000000..ded6c03 --- /dev/null +++ b/src/components/Gallery.astro @@ -0,0 +1,33 @@ +--- +import { Image } from "astro:assets"; +import type { ImageMetadata } from "astro"; + +interface Item { + src: ImageMetadata; + alt: string; +} + +interface Props { + items: Item[]; +} + +const { items } = Astro.props as Props; +--- + +
+ { + items.map((item: Item) => ( +
+ {item.src && ( + {item.alt} + )} +
+ )) + } +
diff --git a/src/components/Head.astro b/src/components/Head.astro index d06e5ee..604b40c 100644 --- a/src/components/Head.astro +++ b/src/components/Head.astro @@ -2,6 +2,7 @@ import { SITE } from "@consts"; import gradient from "../../public/assets/gradient.avif"; import { ClientRouter } from "astro:transitions"; +import { Font } from "astro:assets"; interface Props { title: string; @@ -20,9 +21,6 @@ let { tags } = Astro.props; if (typeof tags !== "undefined") { tags = SITE.KEYWORDS.concat(tags); } - -import outfit from "@fontsource-variable/outfit/files/outfit-latin-wght-normal.woff2?url"; -import redhatmono from "@fontsource-variable/red-hat-mono/files/red-hat-mono-latin-wght-normal.woff2?url"; --- @@ -96,18 +94,6 @@ import redhatmono from "@fontsource-variable/red-hat-mono/files/red-hat-mono-lat - - + + diff --git a/src/components/Hero.astro b/src/components/Hero.astro index fedd33c..37c5127 100644 --- a/src/components/Hero.astro +++ b/src/components/Hero.astro @@ -5,26 +5,26 @@ Troy Lusty Digital Designer -
I am in my final year of studying on a Game Arts and Design BA (Hons) degree and on the side I manage online operations for a family run outdoor apparel business. -
-
+

Think I could help with a project you're working on? Send me a message -

+

diff --git a/src/components/Prose.astro b/src/components/Prose.astro index af7f2e1..5579267 100644 --- a/src/components/Prose.astro +++ b/src/components/Prose.astro @@ -1,5 +1,5 @@
diff --git a/src/components/RelatedArticles.astro b/src/components/RelatedArticles.astro index e9bd91a..c2680c1 100644 --- a/src/components/RelatedArticles.astro +++ b/src/components/RelatedArticles.astro @@ -19,7 +19,7 @@ const next = items[(index + 1) % items.length]; { items.length > 1 ? ( -
+

{collection.data.description}

diff --git a/src/components/ShowcaseProject.astro b/src/components/ShowcaseProject.astro index 14e98be..2032397 100644 --- a/src/components/ShowcaseProject.astro +++ b/src/components/ShowcaseProject.astro @@ -1,8 +1,9 @@ --- import { Image } from "astro:assets"; +import type { CollectionEntry } from "astro:content"; type Props = { - collection: any; + collection: CollectionEntry<"projects">; }; const { collection } = Astro.props; @@ -21,6 +22,13 @@ const { collection } = Astro.props; fit="cover" />
+
+

+ {collection.data.title} +

+
diff --git a/src/components/Slideshow.astro b/src/components/Slideshow.astro index c00115f..3a2133c 100644 --- a/src/components/Slideshow.astro +++ b/src/components/Slideshow.astro @@ -1,9 +1,10 @@ --- import { Image } from "astro:assets"; +import type { CollectionEntry } from "astro:content"; interface Props { + images: CollectionEntry<"projects">[]; interval?: number; - images: any; } const { interval = 3000, images } = Astro.props; @@ -30,6 +31,11 @@ const { interval = 3000, images } = Astro.props; class="h-full w-full rounded-sm object-cover transition-all duration-300 group-hover:brightness-50" loading="eager" /> +
+

+ {image.data.title} +

+
)) diff --git a/src/consts.ts b/src/consts.ts index 999b51d..8d4b529 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -34,6 +34,11 @@ export const SITE: Site = { href: "/sitemap-index.xml", icon: "mdi:sitemap", }, + { + name: "Curriculum vitae", + href: "/cv", + icon: "mdi:trophy", + }, { name: "Email", href: "mailto:hello@troylusty.com", @@ -59,10 +64,6 @@ export const SITE: Site = { name: "Posts", href: "/posts", }, - { - name: "CV", - href: "/cv", - }, ], }; @@ -70,25 +71,6 @@ export const HOME: Metadata = { TITLE: "Troy Lusty", DESCRIPTION: "Hi, my name is Troy and I'm a student 3D artist currently studying in my second year of an FdA Games and Interactive Design course in the UK.", - HOMESETTINGS: { - NUM_POSTS_ON_HOMEPAGE: 2, - NUM_PROJECTS_ON_HOMEPAGE: 6, - }, -}; - -export const CV: Metadata = { - TITLE: "Troy Lusty", - DESCRIPTION: "Curriculum vitae.", -}; - -export const POSTS: Metadata = { - TITLE: "Posts", - DESCRIPTION: "A collection of articles on topics I am passionate about.", -}; - -export const WORK: Metadata = { - TITLE: "Work", - DESCRIPTION: "Where I have worked and what I have done.", }; export const PROJECTS: Metadata = { @@ -96,3 +78,18 @@ export const PROJECTS: Metadata = { DESCRIPTION: "A collection of my projects, with links to repositories and demos.", }; + +export const POSTS: Metadata = { + TITLE: "Posts", + DESCRIPTION: "A collection of articles on topics I am passionate about.", +}; + +export const ABOUT: Metadata = { + TITLE: "About", + DESCRIPTION: "About me.", +}; + +export const CV: Metadata = { + TITLE: "Troy Lusty", + DESCRIPTION: "Curriculum vitae.", +}; diff --git a/src/content/config.ts b/src/content/config.ts index d721db0..05cc014 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -16,7 +16,14 @@ const posts = defineCollection({ alt: z.string(), }), tags: z.array(z.string()), - extraAuthors: z.array(z.string()).optional(), + extraAuthors: z + .array( + z.object({ + name: z.string().min(1), + url: z.string().url(), + }), + ) + .optional(), categories: z.array(z.string()), }) .merge(rssSchema), @@ -37,11 +44,18 @@ const projects = defineCollection({ alt: z.string(), }), tags: z.array(z.string()), - extraAuthors: z.array(z.string()).optional(), + extraAuthors: z + .array( + z.object({ + name: z.string().min(1), + url: z.string().url(), + }), + ) + .optional(), categories: z.array(z.string()), featured: z.boolean().optional(), collection: z.boolean().optional(), - includeHero: z.boolean().optional(), + rank: z.number().positive().optional(), }) .merge(rssSchema), }); diff --git a/src/content/posts/website/index.mdx b/src/content/posts/website/index.mdx new file mode 100644 index 0000000..1b22b0f --- /dev/null +++ b/src/content/posts/website/index.mdx @@ -0,0 +1,212 @@ +--- +title: "Website" +date: 2025-04-25 +description: "An overview of what I am using to host my digital content." +image: + url: "showcase.webp" + alt: "Website showcase" +categories: ["personal"] +tags: ["self-host", "forgejo", "docker", "vps"] +draft: true +--- + +This post will outline my workflow of using a self-hosted Forgejo instance and Actions runner to automatically deploy my personal site and any software releases, all without having to rely on another provider. + +![Website showcase](showcase.webp) + +## Steps + +### Private image access login? + +```sh +echo '' | docker login code.troylusty.com -u troy --password-stdin +``` + +```sh +echo $(htpasswd -nB user) | sed -e s/\\$/\\$\\$/g +``` + +### Aliases for updating VPS and pruning Docker + +```sh +echo 'alias dockerclean="docker system prune -a --volumes"' >> .bashrc +echo 'alias updateall="sudo apt update && sudo apt upgrade && sudo apt autoremove"' >> .bashrc +``` + +Thanks to [Tech Tales](https://tech-tales.blog/posts/2025/01-forgejo-runner-update) for the clean instructions on how to setup an Actions runner with Forgejo. + +```sh +docker compose run --rm forgejo-runner 'forgejo-runner' 'generate-config' > forgejo-runner/config.yml +``` + +Setup `container.docker_host: "unix:///var/run/docker.sock"` and `container.network: "forgejo"` and any labels such as `runner.labels: ["ubuntu-latest:docker://gitea/runner-images:ubuntu-latest"]` + +``` +docker compose run --rm -it forgejo-runner 'forgejo-runner' 'register' +``` + +Input `http://forgejo:3000` as the domain since forgejo is the container name in Docker and port 3000 is its relevant port. + +## Docker compose + +```yaml +services: + traefik: + image: traefik:latest + container_name: traefik + command: + - "--providers.docker" + - "--providers.docker.exposedbydefault=false" + - "--entryPoints.websecure.address=:443" + - "--certificatesresolvers.myresolver.acme.tlschallenge=true" + - "--certificatesresolvers.myresolver.acme.email=traefik@troylusty.com" + - "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" + - "--entrypoints.web.address=:80" + - "--entrypoints.web.http.redirections.entrypoint.to=websecure" + - "--entrypoints.web.http.redirections.entrypoint.scheme=https" + - "--ping=true" + labels: + - "traefik.enable=true" + - "com.centurylinklabs.watchtower.enable=true" + - "traefik.http.middlewares.securityHeaders.headers.stsSeconds=31536000" + - "traefik.http.middlewares.securityHeaders.headers.stsIncludeSubdomains=true" + - "traefik.http.middlewares.securityHeaders.headers.frameDeny=true" + - "traefik.http.middlewares.securityHeaders.headers.contentTypeNosniff=true" + - "traefik.http.middlewares.securityHeaders.headers.contentSecurityPolicy=default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; base-uri 'none'; form-action 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requests" + - "traefik.http.middlewares.securityHeaders.headers.referrerPolicy=no-referrer" + - "traefik.http.middlewares.securityHeaders.headers.permissionsPolicy=accelerometer=(), autoplay=(), camera=(), cross-origin-isolated=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(self), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(), gamepad=(), hid=(), idle-detection=(), interest-cohort=(), serial=(), unload=()" + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - letsencrypt:/letsencrypt + restart: unless-stopped + networks: + - traefik + healthcheck: + test: ["CMD", "traefik", "healthcheck", "--ping"] + depends_on: + watchtower: + condition: service_healthy + + watchtower: + image: containrrr/watchtower:latest + command: --label-enable --interval 1800 --rolling-restart --cleanup --remove-volumes + container_name: watchtower + networks: + - traefik + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /home/troy/.docker/config.json:/config.json + restart: unless-stopped + healthcheck: + test: ["CMD", "/watchtower", "--health-check"] + + personalsite: + image: code.troylusty.com/troy/troylusty.com:latest + container_name: personalsite + labels: + - "traefik.enable=true" + - "traefik.http.routers.personalsite.rule=Host(`troylusty.com`)" + - "traefik.http.routers.personalsite.entrypoints=websecure" + - "traefik.http.routers.personalsite.tls.certresolver=myresolver" + - "com.centurylinklabs.watchtower.enable=true" + - "traefik.http.routers.personalsite.middlewares=securityHeaders" + restart: unless-stopped + networks: + - traefik + depends_on: + traefik: + condition: service_healthy + + zolapress: + image: code.troylusty.com/troy/zolapress:latest + container_name: zolapress + profiles: + - donotstart + labels: + - "traefik.enable=true" + - "traefik.http.routers.zolapress.rule=Host(`edu.troylusty.com`)" + - "traefik.http.routers.zolapress.entrypoints=websecure" + - "traefik.http.routers.zolapress.tls.certresolver=myresolver" + - "com.centurylinklabs.watchtower.enable=true" + - "traefik.http.middlewares.auth.basicauth.users=troy:$$2y$$05$$fgVNzDsxXDq4co3aTh/OMOKZdLzUiM9XPEU5DXCivc9sYUZy/oq1W" + - "traefik.http.routers.zolapress.middlewares=securityHeaders, auth" + restart: unless-stopped + networks: + - traefik + depends_on: + traefik: + condition: service_healthy + + unduck: + image: code.troylusty.com/troy/unduck:latest + container_name: unduck + labels: + - "traefik.enable=true" + - "traefik.http.routers.unduck.rule=Host(`unduck.troylusty.com`)" + - "traefik.http.routers.unduck.entrypoints=websecure" + - "traefik.http.routers.unduck.tls.certresolver=myresolver" + - "com.centurylinklabs.watchtower.enable=true" + - "traefik.http.routers.unduck.middlewares=securityHeaders" + restart: unless-stopped + networks: + - traefik + depends_on: + traefik: + condition: service_healthy + + forgejo: + image: codeberg.org/forgejo/forgejo:10 + container_name: forgejo + restart: unless-stopped + networks: + - traefik + - forgejo + labels: + - "traefik.enable=true" + - "traefik.http.routers.forgejo.rule=Host(`code.troylusty.com`)" + - "traefik.http.routers.forgejo.entrypoints=websecure" + - "traefik.http.routers.forgejo.tls.certresolver=myresolver" + - "com.centurylinklabs.watchtower.enable=true" + - "traefik.http.routers.forgejo.middlewares=securityHeaders" + - "traefik.http.services.forgejo.loadbalancer.server.port=3000" + - "traefik.docker.network=traefik" + volumes: + - ./forgejo:/data + ports: + - "2222:22" + depends_on: + traefik: + condition: service_healthy + + forgejo-runner: + image: code.forgejo.org/forgejo/runner:6.0.1 + container_name: forgejo-runner + user: 0:0 + depends_on: + forgejo: + condition: service_started + networks: + - forgejo + labels: + - "com.centurylinklabs.watchtower.enable=true" + volumes: + - ./forgejo-runner:/data + - ./forgejo-runner/config.yml:/data/config.yml + - /var/run/docker.sock:/var/run/docker.sock + restart: unless-stopped + command: forgejo-runner -c /data/config.yml daemon + +networks: + traefik: + external: false + name: traefik + forgejo: + external: false + name: forgejo + +volumes: + letsencrypt: +``` diff --git a/src/content/posts/website/showcase.webp b/src/content/posts/website/showcase.webp new file mode 100644 index 0000000..628157a Binary files /dev/null and b/src/content/posts/website/showcase.webp differ diff --git a/src/content/projects/3d-package-design/glowing-box-animation.webm b/src/content/projects/3d-package-design/glowing-box-animation.webm deleted file mode 100644 index 82478ca..0000000 Binary files a/src/content/projects/3d-package-design/glowing-box-animation.webm and /dev/null differ diff --git a/src/content/projects/3d-package-design/index.mdx b/src/content/projects/3d-package-design/index.mdx deleted file mode 100644 index 72fe961..0000000 --- a/src/content/projects/3d-package-design/index.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: "3D Package Design" -description: "3D Package Design inspired by the work of Derek Elliott." -date: 2020-08-16 -updated: 2020-08-16 -image: - { url: "troy-lusty-3d-package-design.avif", alt: "3D package design frame" } -tags: ["blender"] -categories: ["personal"] ---- - -import glowing_box_animation from "glowing-box-animation.webm"; - -3D Package Design inspired from [video](https://www.youtube.com/watch?v=4SRwODk0oOU) by Derek Elliott. -This was the final product from my first attempt at some simple animation within Blender done sometime in August of 2020. - - - -_Animation_ - -![3D package design frame](troy-lusty-3d-package-design.avif) diff --git a/src/content/projects/3d-package-design/troy-lusty-3d-package-design.avif b/src/content/projects/3d-package-design/troy-lusty-3d-package-design.avif deleted file mode 100644 index b30702e..0000000 Binary files a/src/content/projects/3d-package-design/troy-lusty-3d-package-design.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/29ff3-alwd-introarea-24042023.jpg b/src/content/projects/a-long-way-down/29ff3-alwd-introarea-24042023.jpg new file mode 100644 index 0000000..bc8906a Binary files /dev/null and b/src/content/projects/a-long-way-down/29ff3-alwd-introarea-24042023.jpg differ diff --git a/src/content/projects/a-long-way-down/Screenshot from 2023-03-01 20-02-00.jpg b/src/content/projects/a-long-way-down/Screenshot from 2023-03-01 20-02-00.jpg new file mode 100755 index 0000000..26afdea Binary files /dev/null and b/src/content/projects/a-long-way-down/Screenshot from 2023-03-01 20-02-00.jpg differ diff --git a/src/content/projects/a-long-way-down/Screenshot from 2023-03-07 15-30-43.png b/src/content/projects/a-long-way-down/Screenshot from 2023-03-07 15-30-43.png new file mode 100755 index 0000000..ab76526 Binary files /dev/null and b/src/content/projects/a-long-way-down/Screenshot from 2023-03-07 15-30-43.png differ diff --git a/src/content/projects/a-long-way-down/Screenshot_20230402_222043.png b/src/content/projects/a-long-way-down/Screenshot_20230402_222043.png new file mode 100644 index 0000000..1b5b145 Binary files /dev/null and b/src/content/projects/a-long-way-down/Screenshot_20230402_222043.png differ diff --git a/src/content/projects/a-long-way-down/alwd-alternate-night-lighting.avif b/src/content/projects/a-long-way-down/alwd-alternate-night-lighting.avif deleted file mode 100644 index 6e026e8..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-alternate-night-lighting.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-early-environment-stage.avif b/src/content/projects/a-long-way-down/alwd-early-environment-stage.avif deleted file mode 100644 index d774d5e..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-early-environment-stage.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-early-forest.avif b/src/content/projects/a-long-way-down/alwd-early-forest.avif deleted file mode 100644 index 34af8fa..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-early-forest.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-img1.avif b/src/content/projects/a-long-way-down/alwd-img1.avif deleted file mode 100644 index db04c5c..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-img1.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-img1.jpg b/src/content/projects/a-long-way-down/alwd-img1.jpg new file mode 100755 index 0000000..a826ae1 Binary files /dev/null and b/src/content/projects/a-long-way-down/alwd-img1.jpg differ diff --git a/src/content/projects/a-long-way-down/alwd-img2.avif b/src/content/projects/a-long-way-down/alwd-img2.avif deleted file mode 100644 index 90d37ca..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-img2.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-img2.jpg b/src/content/projects/a-long-way-down/alwd-img2.jpg new file mode 100755 index 0000000..6dde1ad Binary files /dev/null and b/src/content/projects/a-long-way-down/alwd-img2.jpg differ diff --git a/src/content/projects/a-long-way-down/alwd-img3.avif b/src/content/projects/a-long-way-down/alwd-img3.avif deleted file mode 100644 index 32be074..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-img3.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-img3.jpg b/src/content/projects/a-long-way-down/alwd-img3.jpg new file mode 100755 index 0000000..dc5f1ff Binary files /dev/null and b/src/content/projects/a-long-way-down/alwd-img3.jpg differ diff --git a/src/content/projects/a-long-way-down/alwd-img4.avif b/src/content/projects/a-long-way-down/alwd-img4.avif deleted file mode 100644 index c8d385d..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-img4.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-img4.jpg b/src/content/projects/a-long-way-down/alwd-img4.jpg new file mode 100755 index 0000000..89cbd8e Binary files /dev/null and b/src/content/projects/a-long-way-down/alwd-img4.jpg differ diff --git a/src/content/projects/a-long-way-down/alwd-img5.avif b/src/content/projects/a-long-way-down/alwd-img5.avif deleted file mode 100644 index 8ede51f..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-img5.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-img5.jpg b/src/content/projects/a-long-way-down/alwd-img5.jpg new file mode 100755 index 0000000..b385f68 Binary files /dev/null and b/src/content/projects/a-long-way-down/alwd-img5.jpg differ diff --git a/src/content/projects/a-long-way-down/alwd-img6.avif b/src/content/projects/a-long-way-down/alwd-img6.avif deleted file mode 100644 index 39fa49d..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-img6.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/alwd-img6.jpg b/src/content/projects/a-long-way-down/alwd-img6.jpg new file mode 100755 index 0000000..b56643d Binary files /dev/null and b/src/content/projects/a-long-way-down/alwd-img6.jpg differ diff --git a/src/content/projects/a-long-way-down/alwd-style-experiment.avif b/src/content/projects/a-long-way-down/alwd-style-experiment.avif deleted file mode 100644 index 0a4b683..0000000 Binary files a/src/content/projects/a-long-way-down/alwd-style-experiment.avif and /dev/null differ diff --git a/src/content/projects/a-long-way-down/index.mdx b/src/content/projects/a-long-way-down/index.mdx index 3c86478..9f5f022 100644 --- a/src/content/projects/a-long-way-down/index.mdx +++ b/src/content/projects/a-long-way-down/index.mdx @@ -1,66 +1,70 @@ --- -title: "A Long Way Down (Demo)" +title: "A Long Way Down" description: "A short, atmospheric linear adventure created for my FdA Games and Interactive Design degree." date: 2023-05-11 -updated: 2023-05-11 featured: true -image: { url: "alwd-img1.avif", alt: "A Long Way Down Intro Showcase" } +image: { url: "alwd-img1.jpg", alt: "A Long Way Down Intro Showcase" } tags: ["unreal engine", "blender", "inkscape"] categories: ["education"] -includeHero: true -extraAuthors: ["Sam Griffiths"] +extraAuthors: [{ name: "Sam Griffiths", url: "https://samgriffiths.dev" }] --- +import Gallery from "@components/Gallery.astro"; + +import image1 from "alwd-img1.jpg"; +import image2 from "alwd-img2.jpg"; +import image3 from "alwd-img3.jpg"; +import image4 from "alwd-img4.jpg"; +import image5 from "alwd-img5.jpg"; +import image6 from "alwd-img6.jpg"; +import image7 from "29ff3-alwd-introarea-24042023.jpg"; +import image8 from "Screenshot_20230402_222043.png"; +import image9 from "Screenshot from 2023-03-07 15-30-43.png"; +import image10 from "Screenshot from 2023-03-01 20-02-00.jpg"; + import alongwaydown_demo_walkthrough from "alongwaydown-demo-walkthrough.webm"; -A Long Way Down is a short, atmospheric linear adventure created alongside my friend [Sam](https://samgriffiths.dev) as a project for our FdA Games and Interactive Design degree. It is the follow up project to our previous work: [Nightmare](/projects/nightmare). Currently the [demo](https://samandtroy.itch.io/alongwaydown) is available on Itch.io. +A Long Way Down is a short, atmospheric linear adventure created alongside my friend Sam as a project for our FdA Games and Interactive Design degree. My role was art direction including the lighting, level design, and majority of asset creation for the project. This is the follow up project to our previous work: [Nightmare](#nightmare), and was made to be an evolutionary improvement of it. Currently the [demo](https://samandtroy.itch.io/alongwaydown) is available to download and play on Itch.io. -
diff --git a/src/pages/tags/index.astro b/src/pages/tags/index.astro index 484cae3..211f55d 100644 --- a/src/pages/tags/index.astro +++ b/src/pages/tags/index.astro @@ -4,13 +4,16 @@ import { SITE } from "@consts"; import Layout from "@layouts/Layout.astro"; import { createSlug } from "@lib/utils"; -function freqSort(items: Array) { - var cnts = items.reduce(function (obj: any, val) { - obj[val] = (obj[val] || 0) + 1; - return obj; - }, {}); - var sorted = Object.keys(cnts).sort(function (a, b) { - return cnts[b] - cnts[a]; +function freqSort(items: Array): string[] { + const counts: { [key: string]: number } = items.reduce( + (obj: { [key: string]: number }, val: string) => { + obj[val] = (obj[val] || 0) + 1; + return obj; + }, + {}, + ); + const sorted: string[] = Object.keys(counts).sort((a: string, b: string) => { + return counts[b] - counts[a]; }); return sorted; } @@ -37,7 +40,7 @@ const allTagsSorted = freqSort(allTags); class="text-tertiary animate-reveal flex flex-wrap items-center gap-2 opacity-0 [animation-delay:0.1s]" > { - allTagsSorted.map((tag: any) => ( + allTagsSorted.map((tag: string) => (