Compare commits

..

10 Commits

Author SHA1 Message Date
Bethlenfalvi, Lorinc (ext)
ad775e4f77 changed assets to contabo
Some checks failed
Deploy to GitHub Pages / build (push) Failing after 7m25s
Deploy to GitHub Pages / deploy (push) Has been skipped
2025-03-19 09:41:41 +01:00
Bethlenfalvi, Lorinc (ext)
c4c9959516 added fortune and fixed patreon button 2025-01-31 10:15:36 +01:00
8f63b56619 Improved images 2025-01-30 23:17:41 +00:00
16bc996103 removed stray hide_name reference 2025-01-30 23:06:47 +00:00
6174a406ec fixed typo 2025-01-30 23:01:40 +00:00
75e08d3493 Added Projects page 2025-01-30 22:57:08 +00:00
4a481defb9 temporary projects page 2025-01-30 21:40:47 +00:00
50201ec1fe further improvements 2025-01-30 20:48:44 +00:00
99dba7d0c3 Fixed some bugs and added contact info 2025-01-30 20:38:38 +00:00
Bethlenfalvi, Lorinc (ext)
6ba363c2c9 patreon 2025-01-29 20:33:35 +01:00
22 changed files with 509 additions and 232 deletions

346
package-lock.json generated
View File

@@ -8,19 +8,19 @@
"name": "www-lbfalvy-com", "name": "www-lbfalvy-com",
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@astrojs/mdx": "^4.0.7", "@astrojs/mdx": "^4.0.8",
"@astrojs/react": "^4.1.6", "@astrojs/react": "^4.2.0",
"@astrojs/rss": "^4.0.11", "@astrojs/rss": "^4.0.11",
"@astrojs/sitemap": "^3.2.1", "@astrojs/sitemap": "^3.2.1",
"@astrojs/svelte": "^7.0.4", "@astrojs/svelte": "^7.0.4",
"@js-temporal/polyfill": "^0.4.4", "@js-temporal/polyfill": "^0.4.4",
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.1",
"astro": "^5.1.9", "astro": "^5.2.1",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0", "rehype-slug": "^6.0.0",
"remark-toc": "^9.0.0", "remark-toc": "^9.0.0",
"shiki": "^2.1.0", "shiki": "^2.2.0",
"svelte": "^5.19.3", "svelte": "^5.19.6",
"tailwindcss": "^4.0.0", "tailwindcss": "^4.0.0",
"typescript": "^5.7.3" "typescript": "^5.7.3"
} }
@@ -45,15 +45,15 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@astrojs/internal-helpers": { "node_modules/@astrojs/internal-helpers": {
"version": "0.4.2", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.4.2.tgz", "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.5.0.tgz",
"integrity": "sha512-EdDWkC3JJVcpGpqJAU/5hSk2LKXyG3mNGkzGoAuyK+xoPHbaVdSuIWoN1QTnmK3N/gGfaaAfM8gO2KDCAW7S3w==", "integrity": "sha512-CgB5ZaZO1PFG+rbjF3HnA7G6gIBjJ070xb7bUjeu5Gqqufma+t6fpuRWMXnK2iEO3zVyX7e/xplPlqtFKy/lvw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@astrojs/markdown-remark": { "node_modules/@astrojs/markdown-remark": {
"version": "6.0.2", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.0.2.tgz", "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.1.0.tgz",
"integrity": "sha512-aAoHGVRK3rebCYbaLjyyR+3VeAuTz4q49syUxJP29Oo5yZHdy4cCAXRqLBdr9mJVlxCUUjZiF0Dau6YBf65SGg==", "integrity": "sha512-emZNNSTPGgPc3V399Cazpp5+snogjaF04ocOSQn9vy3Kw/eIC4vTQjXOrWDEoSEy+AwPDZX9bQ4wd3bxhpmGgQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@astrojs/prism": "3.2.0", "@astrojs/prism": "3.2.0",
@@ -69,7 +69,8 @@
"remark-parse": "^11.0.0", "remark-parse": "^11.0.0",
"remark-rehype": "^11.1.1", "remark-rehype": "^11.1.1",
"remark-smartypants": "^3.0.2", "remark-smartypants": "^3.0.2",
"shiki": "^1.26.2", "shiki": "^1.29.1",
"smol-toml": "^1.3.1",
"unified": "^11.0.5", "unified": "^11.0.5",
"unist-util-remove-position": "^5.0.0", "unist-util-remove-position": "^5.0.0",
"unist-util-visit": "^5.0.0", "unist-util-visit": "^5.0.0",
@@ -78,62 +79,62 @@
} }
}, },
"node_modules/@astrojs/markdown-remark/node_modules/@shikijs/core": { "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/core": {
"version": "1.29.1", "version": "1.29.2",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.29.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.29.2.tgz",
"integrity": "sha512-Mo1gGGkuOYjDu5H8YwzmOuly9vNr8KDVkqj9xiKhhhFS8jisAtDSEWB9hzqRHLVQgFdA310e8XRJcW4tYhRB2A==", "integrity": "sha512-vju0lY9r27jJfOY4Z7+Rt/nIOjzJpZ3y+nYpqtUZInVoXQ/TJZcfGnNOGnKjFdVZb8qexiCuSlZRKcGfhhTTZQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/engine-javascript": "1.29.1", "@shikijs/engine-javascript": "1.29.2",
"@shikijs/engine-oniguruma": "1.29.1", "@shikijs/engine-oniguruma": "1.29.2",
"@shikijs/types": "1.29.1", "@shikijs/types": "1.29.2",
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"hast-util-to-html": "^9.0.4" "hast-util-to-html": "^9.0.4"
} }
}, },
"node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-javascript": { "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-javascript": {
"version": "1.29.1", "version": "1.29.2",
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.29.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-1.29.2.tgz",
"integrity": "sha512-Hpi8k9x77rCQ7F/7zxIOUruNkNidMyBnP5qAGbLFqg4kRrg1HZhkB8btib5EXbQWTtLb5gBHOdBwshk20njD7Q==", "integrity": "sha512-iNEZv4IrLYPv64Q6k7EPpOCE/nuvGiKl7zxdq0WFuRPF5PAE9PRo2JGq/d8crLusM59BRemJ4eOqrFrC4wiQ+A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "1.29.1", "@shikijs/types": "1.29.2",
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
"oniguruma-to-es": "^2.2.0" "oniguruma-to-es": "^2.2.0"
} }
}, },
"node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-oniguruma": { "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-oniguruma": {
"version": "1.29.1", "version": "1.29.2",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.29.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-1.29.2.tgz",
"integrity": "sha512-gSt2WhLNgEeLstcweQOSp+C+MhOpTsgdNXRqr3zP6M+BUBZ8Md9OU2BYwUYsALBxHza7hwaIWtFHjQ/aOOychw==", "integrity": "sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "1.29.1", "@shikijs/types": "1.29.2",
"@shikijs/vscode-textmate": "^10.0.1" "@shikijs/vscode-textmate": "^10.0.1"
} }
}, },
"node_modules/@astrojs/markdown-remark/node_modules/@shikijs/langs": { "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/langs": {
"version": "1.29.1", "version": "1.29.2",
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-1.29.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-1.29.2.tgz",
"integrity": "sha512-iERn4HlyuT044/FgrvLOaZgKVKf3PozjKjyV/RZ5GnlyYEAZFcgwHGkYboeBv2IybQG1KVS/e7VGgiAU4JY2Gw==", "integrity": "sha512-FIBA7N3LZ+223U7cJDUYd5shmciFQlYkFXlkKVaHsCPgfVLiO+e12FmQE6Tf9vuyEsFe3dIl8qGWKXgEHL9wmQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "1.29.1" "@shikijs/types": "1.29.2"
} }
}, },
"node_modules/@astrojs/markdown-remark/node_modules/@shikijs/themes": { "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/themes": {
"version": "1.29.1", "version": "1.29.2",
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-1.29.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-1.29.2.tgz",
"integrity": "sha512-lb11zf72Vc9uxkl+aec2oW1HVTHJ2LtgZgumb4Rr6By3y/96VmlU44bkxEb8WBWH3RUtbqAJEN0jljD9cF7H7g==", "integrity": "sha512-i9TNZlsq4uoyqSbluIcZkmPL9Bfi3djVxRnofUHwvx/h6SRW3cwgBC5SML7vsDcWyukY0eCzVN980rqP6qNl9g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "1.29.1" "@shikijs/types": "1.29.2"
} }
}, },
"node_modules/@astrojs/markdown-remark/node_modules/@shikijs/types": { "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/types": {
"version": "1.29.1", "version": "1.29.2",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.29.1.tgz", "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-1.29.2.tgz",
"integrity": "sha512-aBqAuhYRp5vSir3Pc9+QPu9WESBOjUo03ao0IHLC4TyTioSsp/SkbAZSrIH4ghYYC1T1KTEpRSBa83bas4RnPA==", "integrity": "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
@@ -141,28 +142,28 @@
} }
}, },
"node_modules/@astrojs/markdown-remark/node_modules/shiki": { "node_modules/@astrojs/markdown-remark/node_modules/shiki": {
"version": "1.29.1", "version": "1.29.2",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.29.1.tgz", "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.29.2.tgz",
"integrity": "sha512-TghWKV9pJTd/N+IgAIVJtr0qZkB7FfFCUrrEJc0aRmZupo3D1OCVRknQWVRVA7AX/M0Ld7QfoAruPzr3CnUJuw==", "integrity": "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/core": "1.29.1", "@shikijs/core": "1.29.2",
"@shikijs/engine-javascript": "1.29.1", "@shikijs/engine-javascript": "1.29.2",
"@shikijs/engine-oniguruma": "1.29.1", "@shikijs/engine-oniguruma": "1.29.2",
"@shikijs/langs": "1.29.1", "@shikijs/langs": "1.29.2",
"@shikijs/themes": "1.29.1", "@shikijs/themes": "1.29.2",
"@shikijs/types": "1.29.1", "@shikijs/types": "1.29.2",
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
"@types/hast": "^3.0.4" "@types/hast": "^3.0.4"
} }
}, },
"node_modules/@astrojs/mdx": { "node_modules/@astrojs/mdx": {
"version": "4.0.7", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.0.7.tgz", "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.0.8.tgz",
"integrity": "sha512-d3PopBTbbCoX3QOmSLYXW6YCZ0dkhNaeP9/Liz9BhEekflMc9IvBjbtNFf1WCEatsl4LLGftyDisfMM3F3LGMA==", "integrity": "sha512-/aiLr2yQ55W9AbpyOgfMtFXk7g2t7XoWdC2Avps/NqxAx4aYONDLneX43D79QwgqdjFhin7o3cIPp/vVppMbaA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@astrojs/markdown-remark": "6.0.2", "@astrojs/markdown-remark": "6.1.0",
"@mdx-js/mdx": "^3.1.0", "@mdx-js/mdx": "^3.1.0",
"acorn": "^8.14.0", "acorn": "^8.14.0",
"es-module-lexer": "^1.6.0", "es-module-lexer": "^1.6.0",
@@ -196,9 +197,9 @@
} }
}, },
"node_modules/@astrojs/react": { "node_modules/@astrojs/react": {
"version": "4.1.6", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@astrojs/react/-/react-4.1.6.tgz", "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-4.2.0.tgz",
"integrity": "sha512-lMBO+Va4JbLsXviagT9/ZmliwfQGmsiw4rvI4yusPZijQek3q5yfEnQor5XWNcErrkazjjNxY9BFO5f/eSfqmw==", "integrity": "sha512-2OccnYFK+mLuy9GpJqPM3BQGvvemnXNeww+nBVYFuiH04L7YIdfg4Gq0LT7v/BraiuADV5uTl9VhTDL/ZQPAhw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
@@ -1739,62 +1740,62 @@
] ]
}, },
"node_modules/@shikijs/core": { "node_modules/@shikijs/core": {
"version": "2.1.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.2.0.tgz",
"integrity": "sha512-v795KDmvs+4oV0XD05YLzfDMe9ISBgNjtFxP4PAEv5DqyeghO1/TwDqs9ca5/E6fuO95IcAcWqR6cCX9TnqLZA==", "integrity": "sha512-U+vpKdsQDWuX3fPTCkSc8XPX9dCaS+r+qEP1XhnU30yxRFo2OxHJmY2H5rO1q+v0zB5R2vobsxEFt5uPf31CGQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/engine-javascript": "2.1.0", "@shikijs/engine-javascript": "2.2.0",
"@shikijs/engine-oniguruma": "2.1.0", "@shikijs/engine-oniguruma": "2.2.0",
"@shikijs/types": "2.1.0", "@shikijs/types": "2.2.0",
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"hast-util-to-html": "^9.0.4" "hast-util-to-html": "^9.0.4"
} }
}, },
"node_modules/@shikijs/engine-javascript": { "node_modules/@shikijs/engine-javascript": {
"version": "2.1.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.2.0.tgz",
"integrity": "sha512-cgIUdAliOsoaa0rJz/z+jvhrpRd+fVAoixVFEVxUq5FA+tHgBZAIfVJSgJNVRj2hs/wZ1+4hMe82eKAThVh0nQ==", "integrity": "sha512-96SpZ4V3UVMtpSPR5QpmU395CNrQiRPszXK62m8gKR2HMA0653ruce7omS5eX6EyAyFSYHvBWtTuspiIsHpu4A==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "2.1.0", "@shikijs/types": "2.2.0",
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
"oniguruma-to-es": "^2.3.0" "oniguruma-to-es": "^2.3.0"
} }
}, },
"node_modules/@shikijs/engine-oniguruma": { "node_modules/@shikijs/engine-oniguruma": {
"version": "2.1.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.2.0.tgz",
"integrity": "sha512-Ujik33wEDqgqY2WpjRDUBECGcKPv3eGGkoXPujIXvokLaRmGky8NisSk8lHUGeSFxo/Cz5sgFej9sJmA9yeepg==", "integrity": "sha512-wowCKwkvPFFMXFkiKK/a2vs5uTCc0W9+O9Xcu/oqFP6VoDFe14T8u/D+Rl4dCJJSOyeynP9mxNPJ82T5JHTNCw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "2.1.0", "@shikijs/types": "2.2.0",
"@shikijs/vscode-textmate": "^10.0.1" "@shikijs/vscode-textmate": "^10.0.1"
} }
}, },
"node_modules/@shikijs/langs": { "node_modules/@shikijs/langs": {
"version": "2.1.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.2.0.tgz",
"integrity": "sha512-Jn0gS4rPgerMDPj1ydjgFzZr5fAIoMYz4k7ZT3LJxWWBWA6lokK0pumUwVtb+MzXtlpjxOaQejLprmLbvMZyww==", "integrity": "sha512-RSWLH3bnoyG6O1kZ2msh5jOkKKp8eENwyT30n62vUtXfp5cxkF/bpWPpO+p4+GAPhL2foBWR2kOerwkKG0HXlQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "2.1.0" "@shikijs/types": "2.2.0"
} }
}, },
"node_modules/@shikijs/themes": { "node_modules/@shikijs/themes": {
"version": "2.1.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.2.0.tgz",
"integrity": "sha512-oS2mU6+bz+8TKutsjBxBA7Z3vrQk21RCmADLpnu8cy3tZD6Rw0FKqDyXNtwX52BuIDKHxZNmRlTdG3vtcYv3NQ==", "integrity": "sha512-8Us9ZF2mV9kuh+4ySJ9MzrUDIpc2RIkRfKBZclkliW1z9a0PlGU2U7fCkItZZHpR5e4/ft5BzuO+GDqombC6Aw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/types": "2.1.0" "@shikijs/types": "2.2.0"
} }
}, },
"node_modules/@shikijs/types": { "node_modules/@shikijs/types": {
"version": "2.1.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.2.0.tgz",
"integrity": "sha512-OFOdHA6VEVbiQvepJ8yqicC6VmBrKxFFhM2EsHHrZESqLVAXOSeRDiuSYV185lIgp15TVic5vYBYNhTsk1xHLg==", "integrity": "sha512-wkZZKs80NtW5Jp/7ONI1j7EdXSatX2BKMS7I01wliDa09gJKHkZyVqlEMRka/mjT5Qk9WgAyitoCKgGgbsP/9g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
@@ -1846,51 +1847,42 @@
} }
}, },
"node_modules/@tailwindcss/node": { "node_modules/@tailwindcss/node": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.0.1.tgz",
"integrity": "sha512-tfG2uBvo6j6kDIPmntxwXggCOZAt7SkpAXJ6pTIYirNdk5FBqh/CZZ9BZPpgcl/tNFLs6zc4yghM76sqiELG9g==", "integrity": "sha512-lc+ly6PKHqgCVl7eO8D2JlV96Lks5bmL6pdtM6UasyUHLU2zmrOqU6jfgln120IVnCh3VC8GG/ca24xVTtSokw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"enhanced-resolve": "^5.18.0", "enhanced-resolve": "^5.18.0",
"jiti": "^2.4.2", "jiti": "^2.4.2",
"tailwindcss": "4.0.0" "tailwindcss": "4.0.1"
}
},
"node_modules/@tailwindcss/node/node_modules/jiti": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
"integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
} }
}, },
"node_modules/@tailwindcss/oxide": { "node_modules/@tailwindcss/oxide": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.1.tgz",
"integrity": "sha512-W3FjpJgy4VV1JiL7iBYDf2n/WkeDg1Il+0Q7eWnqPyvkPPCo/Mbwc5BiaT7dfBNV6tQKAhVE34rU5xl8pSl50w==", "integrity": "sha512-3z1SpWoDeaA6K6jd92CRrGyDghOcRILEgyWVHRhaUm/tcpiazwJpU9BSG0xB7GGGnl9capojaC+zme/nKsZd/w==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 10" "node": ">= 10"
}, },
"optionalDependencies": { "optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "4.0.0", "@tailwindcss/oxide-android-arm64": "4.0.1",
"@tailwindcss/oxide-darwin-arm64": "4.0.0", "@tailwindcss/oxide-darwin-arm64": "4.0.1",
"@tailwindcss/oxide-darwin-x64": "4.0.0", "@tailwindcss/oxide-darwin-x64": "4.0.1",
"@tailwindcss/oxide-freebsd-x64": "4.0.0", "@tailwindcss/oxide-freebsd-x64": "4.0.1",
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.1",
"@tailwindcss/oxide-linux-arm64-gnu": "4.0.0", "@tailwindcss/oxide-linux-arm64-gnu": "4.0.1",
"@tailwindcss/oxide-linux-arm64-musl": "4.0.0", "@tailwindcss/oxide-linux-arm64-musl": "4.0.1",
"@tailwindcss/oxide-linux-x64-gnu": "4.0.0", "@tailwindcss/oxide-linux-x64-gnu": "4.0.1",
"@tailwindcss/oxide-linux-x64-musl": "4.0.0", "@tailwindcss/oxide-linux-x64-musl": "4.0.1",
"@tailwindcss/oxide-win32-arm64-msvc": "4.0.0", "@tailwindcss/oxide-win32-arm64-msvc": "4.0.1",
"@tailwindcss/oxide-win32-x64-msvc": "4.0.0" "@tailwindcss/oxide-win32-x64-msvc": "4.0.1"
} }
}, },
"node_modules/@tailwindcss/oxide-android-arm64": { "node_modules/@tailwindcss/oxide-android-arm64": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.1.tgz",
"integrity": "sha512-EAhjU0+FIdyGPR+7MbBWubLLPtmOu+p7c2egTTFBRk/n//zYjNvVK0WhcBK5Y7oUB5mo4EjA2mCbY7dcEMWSRw==", "integrity": "sha512-eP/rI9WaAElpeiiHDqGtDqga9iDsOClXxIqdHayHsw93F24F03b60CwgGhrGF9Io/EuWIpz3TMRhPVOLhoXivw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1904,9 +1896,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-darwin-arm64": { "node_modules/@tailwindcss/oxide-darwin-arm64": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.1.tgz",
"integrity": "sha512-hdz4xnSWS11cIp+7ye+3dGHqs0X33z+BXXTtgPOguDWVa+TdXUzwxonklSzf5wlJFuot3dv5eWzhlNai0oYYQg==", "integrity": "sha512-jZVUo0kNd1IjxdCYwg4dwegDNsq7PoUx4LM814RmgY3gfJ63Y6GlpJXHOpd5FLv1igpeZox5LzRk2oz8MQoJwQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1920,9 +1912,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-darwin-x64": { "node_modules/@tailwindcss/oxide-darwin-x64": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.1.tgz",
"integrity": "sha512-+dOUUaXTkPKKhtUI9QtVaYg+MpmLh2CN0dHohiYXaBirEyPMkjaT0zbRgzQlNnQWjCVVXPQluIEb0OMEjSTH+Q==", "integrity": "sha512-E31wHiIf4LB0aKRohrS4U6XfFSACCL9ifUFfPQ16FhcBIL4wU5rcBidvWvT9TQFGPkpE69n5dyXUcqiMrnF/Ig==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1936,9 +1928,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-freebsd-x64": { "node_modules/@tailwindcss/oxide-freebsd-x64": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.1.tgz",
"integrity": "sha512-CJhGDhxnrmu4SwyC62fA+wP24MhA/TZlIhRHqg1kRuIHoGoVR2uSSm1qxTxU37tSSZj8Up0q6jsBJCAP4k7rgQ==", "integrity": "sha512-8/3ZKLMYqgAsBzTeczOKWtT4geF02g9S7cntY5gvqQZ4E0ImX724cHcZJi9k6fkE6aLbvwxxHxaShFvRxblwKQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1952,9 +1944,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.1.tgz",
"integrity": "sha512-Wy7Av0xzXfY2ujZBcYy4+7GQm25/J1iHvlQU2CfwdDCuPWfIjYzR6kggz+uVdSJyKV2s64znchBxRE8kV4uXSA==", "integrity": "sha512-EYjbh225klQfWzy6LeIAfdjHCK+p71yLV/GjdPNW47Bfkkq05fTzIhHhCgshUvNp78EIA33iQU+ktWpW06NgHw==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1968,9 +1960,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": { "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.1.tgz",
"integrity": "sha512-srwBo2l6pvM0swBntc1ucuhGsfFOLkqPRFQ3dWARRTfSkL1U9nAsob2MKc/n47Eva/W9pZZgMOuf7rDw8pK1Ew==", "integrity": "sha512-PrX2SwIqWNP5cYeSyQfrhbk4ffOM338T6CrEwIAGvLPoUZiklt19yknlsBme6bReSw7TSAMy+8KFdLLi5fcWNQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1984,9 +1976,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-linux-arm64-musl": { "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.1.tgz",
"integrity": "sha512-abhusswkduYWuezkBmgo0K0/erGq3M4Se5xP0fhc/0dKs0X/rJUYYCFWntHb3IGh3aVzdQ0SXJs93P76DbUqtw==", "integrity": "sha512-iuoFGhKDojtfloi5uj6MIk4kxEOGcsAk/kPbZItF9Dp7TnzVhxo2U/718tXhxGrg6jSL3ST3cQHIjA6yw3OeXw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2000,9 +1992,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-linux-x64-gnu": { "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.1.tgz",
"integrity": "sha512-hGtRYIUEx377/HlU49+jvVKKwU1MDSKYSMMs0JFO2Wp7LGxk5+0j5+RBk9NFnmp/lbp32yPTgIOO5m1BmDq36A==", "integrity": "sha512-pNUrGQYyE8RK+N9yvkPmHnlKDfFbni9A3lsi37u4RoA/6Yn+zWVoegvAQMZu3w+jqnpb2A/bYJ+LumcclUZ3yg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2016,9 +2008,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-linux-x64-musl": { "node_modules/@tailwindcss/oxide-linux-x64-musl": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.1.tgz",
"integrity": "sha512-7xgQgSAThs0I14VAgmxpJnK6XFSZBxHMGoDXkLyYkEnu+8WRQMbCP93dkCUn2PIv+Q+JulRgc00PJ09uORSLXQ==", "integrity": "sha512-xSGWaDcT6SJ75su9zWXj8GYb2jM/przXwZGH96RTS7HGDIoI1tvgpls88YajG5Sx7hXaqAWCufjw5L/dlu+lzg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2032,9 +2024,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.1.tgz",
"integrity": "sha512-qEcgTIPcWY5ZE7f6VxQ/JPrSFMcehzVIlZj7sGE3mVd5YWreAT+Fl1vSP8q2pjnWXn0avZG3Iw7a2hJQAm+fTQ==", "integrity": "sha512-BUNL2isUZ2yWnbplPddggJpZxsqGHPZ1RJAYpu63W4znUnKCzI4m/jiy0WpyYqqOKL9jDM5q0QdsQ9mc3aw5YQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -2048,9 +2040,9 @@
} }
}, },
"node_modules/@tailwindcss/oxide-win32-x64-msvc": { "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.1.tgz",
"integrity": "sha512-bqT0AY8RXb8GMDy28JtngvqaOSB2YixbLPLvUo6I6lkvvUwA6Eqh2Tj60e2Lh7O/k083f8tYiB0WEK4wmTI7Jg==", "integrity": "sha512-ZtcVu+XXOddGsPlvO5nh2fnbKmwly2C07ZB1lcYCf/b8qIWF04QY9o6vy6/+6ioLRfbp3E7H/ipFio38DZX4oQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -2064,15 +2056,15 @@
} }
}, },
"node_modules/@tailwindcss/vite": { "node_modules/@tailwindcss/vite": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.0.1.tgz",
"integrity": "sha512-4uukMiU9gHui8KMPMdWic5SP1O/tmQ1NFSRNrQWmcop5evAVl/LZ6/LuWL3quEiecp2RBcRWwqJrG+mFXlRlew==", "integrity": "sha512-ZkwMBA7uR+nyrafIZI8ce3PduE0dDVFVmxmInCUPTN17Jgy6RfEPXzqtL5fz658eDDxKa5xZ+gmiTt+5AMD0pw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@tailwindcss/node": "^4.0.0", "@tailwindcss/node": "^4.0.1",
"@tailwindcss/oxide": "^4.0.0", "@tailwindcss/oxide": "^4.0.1",
"lightningcss": "^1.29.1", "lightningcss": "^1.29.1",
"tailwindcss": "4.0.0" "tailwindcss": "4.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"vite": "^5.2.0 || ^6" "vite": "^5.2.0 || ^6"
@@ -2442,14 +2434,14 @@
} }
}, },
"node_modules/astro": { "node_modules/astro": {
"version": "5.1.9", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/astro/-/astro-5.1.9.tgz", "resolved": "https://registry.npmjs.org/astro/-/astro-5.2.1.tgz",
"integrity": "sha512-QB3MH7Ul3gEvmHXEfvPkGpTZyyB/TBKQbm0kTHpo0BTEB7BvaY+wrcWiGEJBVDpVdEAKY9fM3zrJ0c7hZSXVlw==", "integrity": "sha512-OYR2kUo9EqX6OYZ1OmM14xP8mjFwgrk1FzIr+3K3tS0gCCKJsXtfboCUhX3lODZFIsmY/on7NPZd+2PURA0R2Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@astrojs/compiler": "^2.10.3", "@astrojs/compiler": "^2.10.3",
"@astrojs/internal-helpers": "0.4.2", "@astrojs/internal-helpers": "0.5.0",
"@astrojs/markdown-remark": "6.0.2", "@astrojs/markdown-remark": "6.1.0",
"@astrojs/telemetry": "3.2.0", "@astrojs/telemetry": "3.2.0",
"@oslojs/encoding": "^1.1.0", "@oslojs/encoding": "^1.1.0",
"@rollup/pluginutils": "^5.1.4", "@rollup/pluginutils": "^5.1.4",
@@ -2497,7 +2489,7 @@
"unist-util-visit": "^5.0.0", "unist-util-visit": "^5.0.0",
"unstorage": "^1.14.4", "unstorage": "^1.14.4",
"vfile": "^6.0.3", "vfile": "^6.0.3",
"vite": "^6.0.9", "vite": "^6.0.11",
"vitefu": "^1.0.5", "vitefu": "^1.0.5",
"which-pm": "^3.0.0", "which-pm": "^3.0.0",
"xxhash-wasm": "^1.1.0", "xxhash-wasm": "^1.1.0",
@@ -4058,14 +4050,12 @@
} }
}, },
"node_modules/jiti": { "node_modules/jiti": {
"version": "1.21.7", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"license": "MIT", "license": "MIT",
"optional": true,
"peer": true,
"bin": { "bin": {
"jiti": "bin/jiti.js" "jiti": "lib/jiti-cli.mjs"
} }
}, },
"node_modules/js-tokens": { "node_modules/js-tokens": {
@@ -6557,17 +6547,17 @@
} }
}, },
"node_modules/shiki": { "node_modules/shiki": {
"version": "2.1.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-2.1.0.tgz", "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.2.0.tgz",
"integrity": "sha512-yvKPdNGLXZv7WC4bl7JBbU3CEcUxnBanvMez8MG3gZXKpClGL4bHqFyLhTx+2zUvbjClUANs/S22HXb7aeOgmA==", "integrity": "sha512-3uoZBmc+zpd2JOEeTvKP/vK5UVDDe8YiigkT9flq+MV5Z1MKFiUXfbLIvHfqcJ+V90StDiP1ckN97z1WlhC6cQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@shikijs/core": "2.1.0", "@shikijs/core": "2.2.0",
"@shikijs/engine-javascript": "2.1.0", "@shikijs/engine-javascript": "2.2.0",
"@shikijs/engine-oniguruma": "2.1.0", "@shikijs/engine-oniguruma": "2.2.0",
"@shikijs/langs": "2.1.0", "@shikijs/langs": "2.2.0",
"@shikijs/themes": "2.1.0", "@shikijs/themes": "2.2.0",
"@shikijs/types": "2.1.0", "@shikijs/types": "2.2.0",
"@shikijs/vscode-textmate": "^10.0.1", "@shikijs/vscode-textmate": "^10.0.1",
"@types/hast": "^3.0.4" "@types/hast": "^3.0.4"
} }
@@ -6613,6 +6603,18 @@
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/smol-toml": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.3.1.tgz",
"integrity": "sha512-tEYNll18pPKHroYSmLLrksq233j021G0giwW7P3D24jC54pQ5W5BXMsQ/Mvw1OJCmEYDgY+lrzT+3nNUtoNfXQ==",
"license": "BSD-3-Clause",
"engines": {
"node": ">= 18"
},
"funding": {
"url": "https://github.com/sponsors/cyyynthia"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.7.4", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
@@ -6724,9 +6726,9 @@
} }
}, },
"node_modules/svelte": { "node_modules/svelte": {
"version": "5.19.3", "version": "5.19.6",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.19.3.tgz", "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.19.6.tgz",
"integrity": "sha512-rb/bkYG9jq67OCWikMvaPnfOobyGn0JizVDwHpdeBtLiNXPMcoA9GTFC3BhptP7xGNquUU8J5GiS7PlGlfDAFA==", "integrity": "sha512-6ydekB3qyqUal+UhfMjmVOjRGtxysR8vuiMhi2nwuBtPJWnctVlsGspjVFB05qmR+TXI1emuqtZt81c0XiFleA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.3.0", "@ampproject/remapping": "^2.3.0",
@@ -6763,9 +6765,9 @@
} }
}, },
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "4.0.0", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.1.tgz",
"integrity": "sha512-ULRPI3A+e39T7pSaf1xoi58AqqJxVCLg8F/uM5A3FadUbnyDTgltVnXJvdkTjwCOGA6NazqHVcwPJC5h2vRYVQ==", "integrity": "sha512-UK5Biiit/e+r3i0O223bisoS5+y7ZT1PM8Ojn0MxRHzXN1VPZ2KY6Lo6fhu1dOfCfyUAlK7Lt6wSxowRabATBw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/tapable": { "node_modules/tapable": {

View File

@@ -9,19 +9,19 @@
"astro": "astro" "astro": "astro"
}, },
"dependencies": { "dependencies": {
"@astrojs/mdx": "^4.0.7", "@astrojs/mdx": "^4.0.8",
"@astrojs/react": "^4.1.6", "@astrojs/react": "^4.2.0",
"@astrojs/rss": "^4.0.11", "@astrojs/rss": "^4.0.11",
"@astrojs/sitemap": "^3.2.1", "@astrojs/sitemap": "^3.2.1",
"@astrojs/svelte": "^7.0.4", "@astrojs/svelte": "^7.0.4",
"@js-temporal/polyfill": "^0.4.4", "@js-temporal/polyfill": "^0.4.4",
"@tailwindcss/vite": "^4.0.0", "@tailwindcss/vite": "^4.0.1",
"astro": "^5.1.9", "astro": "^5.2.1",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0", "rehype-slug": "^6.0.0",
"remark-toc": "^9.0.0", "remark-toc": "^9.0.0",
"shiki": "^2.1.0", "shiki": "^2.2.0",
"svelte": "^5.19.3", "svelte": "^5.19.6",
"tailwindcss": "^4.0.0", "tailwindcss": "^4.0.0",
"typescript": "^5.7.3" "typescript": "^5.7.3"
} }

View File

@@ -67,10 +67,10 @@
m-1 p-2 hover:bg-shade m-1 p-2 hover:bg-shade
"> ">
<h2 class="font-bold">{post.data.title}</h2> <h2 class="font-bold">{post.data.title}</h2>
<address class="inline-block post-meta col-start-2 md:ml-3"> <address class="inline-block post-meta col-start-2 md:ml-3 whitespace-nowrap">
{post.data.author} {post.data.author}
</address> </address>
<div class="inline-block post-meta col-start-3 lg:ml-1"> <div class="inline-block post-meta col-start-3 lg:ml-1 whitespace-nowrap">
<Time datetime={post.data.pubDate} /> <Time datetime={post.data.pubDate} />
</div> </div>
<div class="col-span-3">{post.data.summary}</div> <div class="col-span-3">{post.data.summary}</div>

103
src/components/Fortune.tsx Normal file
View File

@@ -0,0 +1,103 @@
import React from "react"
const messages = [
"Test message, please ignore",
"Often when people ask difficult questions they don't actually need the answer but rather \
fail to fully understand their situation, take one too many steps in imitating \
familiar solutions, and end up asking the wrong question. This is known as the X/Y problem. \
\n\n\
On the other hand, just blurting \"X/Y!\" in response to any difficult question is \
less useful than direct answers to the bad question. In remembering my learning journey, \
when I'm posed a difficult technical question I like to ask back:\
\n\n\
> This is a difficult problem with no perfect solution, and it's often easy to avoid it altogether.\n\
> Is there any more context to this?",
"This airplane is the choice of professional pilots! \
The first thing we advise you to do is turn the yoke upside down, it's much more ergonomic like that. \
Also, you probably want to rip out the altimeter and replace it with a custom one that has more features. \
And bring your own GPS unit and tape it to the windshield, because this plane doesn't have one by default. \
And of course, remember that unlike in your car, 'left' actually means right in this plane. \
This is the professional way. Ah yes, when you fly over Canada, \
you will see a blinking warning sign telling you that you're out of fuel. \
That's just a small glitch caused by metric/imperial confusion. \
It has been known for 23 years but we haven't quite gotten around to fixing it yet. \
Don't worry, this plane is still excellent for professional pilots. \
If you feel otherwise, you are probably not a real professional.",
"Create React App doesn't support including source files from outside the src folder, or following symlinks.",
"Seven million years have passed since the first machines were erected by man. \
This once-holy land, now cursed with laze and oil, metals, \
hoped to fulfill menial tasks of increasingly insignificant bother. When bother became microcosmic, \
we tackled problems past the point of physical inconvenience: First, our sadness was tackled. \
Feelings injected into our daily routing, tricked the senses with light and sound. \
Fear was tackled next - information on everything, transparency to nothing, \
a false promise built on a whim by those with real power, power to produce comforting lies. \
Then our soul, ideals sold on providence and grandeur in a post-religion world, \
people found faith in new gods residing within the computer, scriptures in everyone's pocket, \
words of this holy book code, powerful enough to shift the seas without anyone noticing the gentle pull \
of its immeasurable strength. \
\n\n\
There once was a way for all the world to unify into one space, \
this coalescence led to the destruction of everything. \
\n\n\
@pukicho",
"The quickest way to oust yourself as a foreigner in England is to mention a place.",
"My informant at https://martinteoharov.com/ has an important message for you",
]
function break_lines(input: string, width: number): string {
return input
.split("\n")
.flatMap(l => {
let ret: string[] = [];
while (width < l.length) {
let split_point = l.lastIndexOf(" ", width);
if (split_point < 0) {
ret.push(l.slice(0, width));
l = l.slice(width);
} else {
ret.push(l.slice(0, split_point));
l = l.slice(split_point + 1);
}
}
ret.push(l);
return ret;
})
.join("\n")
}
export default function Fortune(): React.ReactElement {
const id = Math.floor(Math.random() * messages.length);
window.localStorage.setItem("martinRefShown", id === 6 ? "yes" : "no");
const text = break_lines(messages[id], 60);
const width = text.split("\n").map(s => s.length).reduce((acc, l) => Math.max(acc, l))
return <>
<pre>
{" " + "_".repeat(width + 2) + "\n"}
{text.split("\n").map((l, i, a) => {
let [s, e] = a.length === 1 ? ["(", ")"]
: i === 0 ? ["/", "\\"]
: i + 1 === a.length ? ["\\", "/"]
: ["|", "|"]
return s + " " + l.padEnd(width) + " " + e + "\n"
})}
{" " + "-".repeat(width + 2)}
{`
l
l
.--.
|o_o |
|:_/ |
// l l
(| | )
/bl_ _/bl
l___)=(___/
`.replaceAll("b", "`").replaceAll("l", "\\")}
</pre>
</>
}

View File

@@ -4,14 +4,11 @@ import { defineCollection, z } from 'astro:content';
import { isValidTime } from './utils/time'; import { isValidTime } from './utils/time';
const blog = defineCollection({ const blog = defineCollection({
// Load Markdown and MDX files in the `src/content/blog/` directory.
loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }), loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
// Type-check frontmatter using a schema
schema: z.object({ schema: z.object({
title: z.string(), title: z.string(),
summary: z.string(), summary: z.string(),
image: z.string().optional(), image: z.string().optional(),
// Transform string to ZonedDateTime object
pubDate: z.string().refine(isValidTime), pubDate: z.string().refine(isValidTime),
updatedDate: z.string().refine(isValidTime).optional(), updatedDate: z.string().refine(isValidTime).optional(),
unlisted: z.boolean().optional(), unlisted: z.boolean().optional(),
@@ -20,4 +17,13 @@ const blog = defineCollection({
}), }),
}); });
export const collections = { blog }; const projects = defineCollection({
loader: glob({ base: './src/content/projects', pattern: '**/*.{md,mdx}' }),
schema: z.object({
name: z.string(),
url: z.string(),
image: z.string().optional(),
})
})
export const collections = { blog, projects };

View File

@@ -4,7 +4,7 @@ author: lbfalvy
tags: [programming, rust, langdev] tags: [programming, rust, langdev]
pubDate: 2025-01-29T11:27Z[UTC] pubDate: 2025-01-29T11:27Z[UTC]
summary: On the state of async Rust, limitations of the type system, and Iterator::map summary: On the state of async Rust, limitations of the type system, and Iterator::map
image: https://assets-for-gh-pages.gb-lon-1.linodeobjects.com/Screenshot%202025-01-29%20170323.png image: https://eu2.contabostorage.com/b5fca1793241407290cf2335ba076411:assets/lbfalvy_com/Screenshot 2025-01-29 170323.png
unlisted: false unlisted: false
--- ---
import Graphic from "../../components/Graphic.astro" import Graphic from "../../components/Graphic.astro"
@@ -20,7 +20,7 @@ In synchronous rust, `Iterator::map` takes an `FnMut`, a function which can only
fn map<B, F>(self, f: F) -> Map<Self, F> where F: FnMut(Self::Item) -> B; fn map<B, F>(self, f: F) -> Map<Self, F> where F: FnMut(Self::Item) -> B;
} }
``` ```
<p slot="label">source (modified): https://doc.rust-lang.org/src/core/iter/traits/iterator.rs.html#745</p> <p slot="label">modified from the standard library</p>
</Graphic> </Graphic>
The async equivalent however has to take a function that returns some type that implements `Future` because that's how you statically type an asynchronous function, you parameterize on the state machine the compiler will eventually generate for its paused data. This is again perfectly normal, C++ coroutines do the same as I'm pretty sure every other language that supports any kind of stack-allocated coroutine has to. The problem emerges from lifetimes, because in order for that Future to hold onto a mutable reference, the async equivalent of map (which happens to be called `StreamExt::then` for reference) has to not only guarantee that the callback will not be running when its next called, but that its return value (the `Future` instance) will not exist (either because it's finished or because it's been freed) by the time the function is called again. The async equivalent however has to take a function that returns some type that implements `Future` because that's how you statically type an asynchronous function, you parameterize on the state machine the compiler will eventually generate for its paused data. This is again perfectly normal, C++ coroutines do the same as I'm pretty sure every other language that supports any kind of stack-allocated coroutine has to. The problem emerges from lifetimes, because in order for that Future to hold onto a mutable reference, the async equivalent of map (which happens to be called `StreamExt::then` for reference) has to not only guarantee that the callback will not be running when its next called, but that its return value (the `Future` instance) will not exist (either because it's finished or because it's been freed) by the time the function is called again.
@@ -41,7 +41,7 @@ The async equivalent however has to take a function that returns some type that
<p slot="label">source (modified): https://docs.rs/futures-util/0.3.31/src/futures_util/stream/stream/mod.rs.html#488</p> <p slot="label">source (modified): https://docs.rs/futures-util/0.3.31/src/futures_util/stream/stream/mod.rs.html#488</p>
</Graphic> </Graphic>
The type of the callback then _should be_ **some function which for any lifetime `'a` returns some type is valid for the same lifetime `'a`**. The type of the return value is parametric! The type of the callback then _should be_ **some function which for any lifetime `'a` returns some type that is valid for the same lifetime `'a`**. The type of the return value is parametric!
Since structs and functions can only be parametric on concrete types, not generics, a callback whose return type has a different contract depending on how you called the function is illegal on general. So if you want to access mutable data in an async stream, you have to make an ad-hoc `Mutex<&mut T>` right there on the stack which the closure and its return value can capture by shared reference and then immediately lock for its entire runtime. Streams are lazy and a new value will not be pulled until the current one is finished so this mutex can never ever be contested, but there is no way at all to explain this to the type system. Since structs and functions can only be parametric on concrete types, not generics, a callback whose return type has a different contract depending on how you called the function is illegal on general. So if you want to access mutable data in an async stream, you have to make an ad-hoc `Mutex<&mut T>` right there on the stack which the closure and its return value can capture by shared reference and then immediately lock for its entire runtime. Streams are lazy and a new value will not be pulled until the current one is finished so this mutex can never ever be contested, but there is no way at all to explain this to the type system.

View File

@@ -0,0 +1,6 @@
---
name: Orchid
url: https://github.com/lbfalvy/orchid
image: https://raw.githubusercontent.com/lbfalvy/orchid/refs/heads/master/icon.svg
---
An embeddable functional scripting language I've been developing for many years now both as a recreational activity and to learn Rust.

View File

@@ -0,0 +1,6 @@
---
name: f.engine
url: https://lbfalvy.github.io/f.engine/
image: https://eu2.contabostorage.com/b5fca1793241407290cf2335ba076411:assets/lbfalvy_com/f-engine.png
---
A small lambda calculus executor made in Javascript to demonstrate lambda calc to my friends. It works with repeated string splicing so it gets very slow.

View File

@@ -0,0 +1,5 @@
---
name: Mockable Timer
url: https://github.com/lbfalvy/mockable-timer
---
An API that replaces `Date.now()`, `setTimeout` and `setImmediate` for dependency injection, and a carefully crafted mock implementation with an easy to use interface.

View File

@@ -0,0 +1,5 @@
---
name: React Context Menu
url: https://www.npmjs.com/package/@lbfalvy/react-context-menu
---
A multilevel custom context menu for React. The API relies on React context so that menus can be combined within nested containers

View File

@@ -0,0 +1,5 @@
---
name: Simple RTR
url: https://github.com/lbfalvy/buffered-dispatch
---
A library for Refresh Token Rotation that can scale to many concurrent open tabs without a service worker.

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="600" height="530" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="m135.72 44.03c66.496 49.921 138.02 151.14 164.28 205.46 26.262-54.316 97.782-155.54 164.28-205.46 47.98-36.021 125.72-63.892 125.72 24.795 0 17.712-10.155 148.79-16.111 170.07-20.703 73.984-96.144 92.854-163.25 81.433 117.3 19.964 147.14 86.092 82.697 152.22-122.39 125.59-175.91-31.511-189.63-71.766-2.514-7.3797-3.6904-10.832-3.7077-7.8964-0.0174-2.9357-1.1937 0.51669-3.7077 7.8964-13.714 40.255-67.233 197.36-189.63 71.766-64.444-66.128-34.605-132.26 82.697-152.22-67.108 11.421-142.55-7.4491-163.25-81.433-5.9562-21.282-16.111-152.36-16.111-170.07 0-88.687 77.742-60.816 125.72-24.795z" fill="#1185fe"/>
</svg>

After

Width:  |  Height:  |  Size: 745 B

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 94.33">
<defs>
<style>
.cls-1 {
fill: #fff;
}
</style>
</defs>
<path class="cls-1" d="M11.5,13.79c0-3.35,2.49-5.62,6.38-5.62h18.59c16.86,0,28.32,9.29,28.32,22.91s-11.35,23.34-28.32,23.34h-2.59c-6.49,0-9.84,3.35-9.84,8.75v15.24c0,4.32-2.49,7.02-6.27,7.02s-6.27-2.7-6.27-7.02V13.79ZM24.04,33.14c0,6.81,3.46,10.05,10.05,10.05h1.62c9.3,0,16.1-3.78,16.1-12.1s-6.81-12.1-16.1-12.1h-1.62c-6.59,0-10.05,3.24-10.05,10.05v4.11ZM64.79,79.5c0,3.57,2.49,5.94,6.27,5.94,2.49,0,4.76-1.62,6.05-4.97l2.27-6.05c1.84-4.86,5.08-7.13,8.65-7.13h20.54c3.57,0,6.81,2.27,8.65,7.13l2.27,6.05c1.3,3.35,3.57,4.97,6.05,4.97,3.78,0,6.27-2.38,6.27-5.94,0-.97-.22-2.16-.65-3.35l-24.54-63.76c-1.51-3.89-4.97-5.84-8.32-5.84s-6.81,1.95-8.32,5.84l-24.54,63.76c-.43,1.19-.65,2.38-.65,3.35ZM88.67,50.54c0-1.19.32-2.27.86-3.89l4.65-12.86c.86-2.49,2.38-3.67,4.11-3.67s3.24,1.19,4.11,3.67l4.65,12.86c.54,1.62.86,2.7.86,3.89,0,3.24-1.84,5.51-6.7,5.51h-5.84c-4.86,0-6.7-2.27-6.7-5.51ZM127.69,14.01c0-3.46,2.49-5.84,6.49-5.84h49.72c4,0,6.49,2.38,6.49,5.84s-2.49,5.84-6.49,5.84h-8.32c-6.59,0-10.16,3.35-10.16,11.02v47.44c0,4.43-2.49,7.13-6.38,7.13s-6.38-2.7-6.38-7.13V30.87c0-7.67-3.57-11.02-10.16-11.02h-8.32c-4,0-6.49-2.38-6.49-5.84ZM202.06,78.42c0,4.32,2.49,7.02,6.27,7.02s6.27-2.7,6.27-7.02v-17.18c0-4.86,2.81-6.92,6.27-6.92h.87c2.27,0,4.54,1.4,5.94,3.46l16.43,24.1c1.51,2.27,3.46,3.57,5.94,3.57,3.24,0,5.84-2.7,5.84-5.94,0-1.3-.43-2.7-1.4-4.11l-10.92-15.35c-1.3-1.84-1.84-3.35-1.84-4.65,0-2.7,2.38-4.65,5.19-6.7,5.08-3.78,10.59-8.75,10.59-18.26,0-13.29-10.38-22.26-27.45-22.26h-21.72c-3.89,0-6.27,2.27-6.27,5.62v64.63ZM214.59,32.17v-3.24c0-7.02,3.68-9.94,9.3-9.94h5.4c9.29,0,15.24,3.46,15.24,11.46s-6.27,11.67-15.56,11.67h-5.08c-5.62,0-9.3-2.92-9.3-9.94ZM273.5,78.21V13.79c0-3.35,2.38-5.62,6.27-5.62h40.86c3.89,0,6.27,2.27,6.27,5.62s-2.38,5.62-6.27,5.62h-25.83c-5.08,0-8.76,3.03-8.76,8.75v2.38c0,5.73,3.68,8.75,8.76,8.75h20c3.89,0,6.27,2.27,6.27,5.62s-2.38,5.62-6.27,5.62h-19.24c-5.08,0-9.51,3.13-9.51,9.51v3.03c0,6.38,4.43,9.51,9.51,9.51h25.08c3.89,0,6.27,2.27,6.27,5.62s-2.38,5.62-6.27,5.62h-40.86c-3.89,0-6.27-2.27-6.27-5.62ZM334.35,46c0-23.34,17.51-39.45,38.05-39.45s38.05,16.1,38.05,39.45-17.51,39.45-38.05,39.45-38.05-16.1-38.05-39.45ZM348.62,46c0,16.43,9.73,26.91,23.78,26.91s23.78-10.48,23.78-26.91-9.73-26.91-23.78-26.91-23.78,10.37-23.78,26.91ZM425.47,78.42c0,4.32,2.49,7.02,6.27,7.02s6.27-2.7,6.27-7.02v-33.07c0-4,2.38-5.94,4.86-5.94,1.95,0,3.57,1.08,4.76,3.03l20.75,34.69c2.81,4.76,5.4,8.32,10.7,8.32s8.76-3.67,8.76-9.62V13.58c0-4.32-2.49-7.02-6.27-7.02s-6.27,2.7-6.27,7.02v33.07c0,4-2.38,5.94-4.86,5.94-1.94,0-3.57-1.08-4.76-3.03l-20.75-34.69c-2.81-4.76-5.4-8.32-10.7-8.32s-8.76,3.67-8.76,9.62v62.25Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1,24 +1,60 @@
--- ---
import type { CollectionEntry } from 'astro:content'; import type { CollectionEntry } from "astro:content";
import Main from './Main.astro'; import Main from "./Main.astro";
import Time from '../components/Time.svelte'; import Time from "../components/Time.svelte";
import { Image } from "astro:assets";
import patreonWordmark from "../icons/PATREON_WORDMARK_1_WHITE_RGB.svg";
type Props = CollectionEntry<'blog'>['data']; type Props = CollectionEntry<"blog">["data"];
const { title, author, summary, pubDate, updatedDate, image } = Astro.props; const { title, author, summary, pubDate, updatedDate, image } = Astro.props;
--- ---
<Main title={title} description={summary} image={image}> <Main title={title} description={summary} image={image}>
<article class="m-5 mt-3"> <article class="m-5 mt-3">
<header class="lg:grid grid-cols-[auto_auto_minmax(300px,_1fr)] grid-rows-[auto_auto]"> <header
class="lg:grid grid-cols-[auto_auto_minmax(300px,_1fr)] grid-rows-[auto_auto]"
>
<h2 class="font-bold row-span-2 text-2xl m-2 mt-3">{title}</h2> <h2 class="font-bold row-span-2 text-2xl m-2 mt-3">{title}</h2>
<address class="post-meta inline-block col-start-2">{author}</address> <address class="post-meta inline-block col-start-2">{author}</address>
<Time client:load datetime={pubDate} /> <Time client:load datetime={pubDate} />
<div class="italic tracking-[3px] text-emph-fg col-start-2 col-span-2 m-2 mt-0">{summary}</div> <div
{updatedDate && <div>Amended <Time datetime={updatedDate} /></div>} class="italic tracking-[3px] text-emph-fg col-start-2 col-span-2 m-2 mt-0"
>
{summary}
</div>
{
updatedDate && (
<div>
Amended <Time datetime={updatedDate} />
</div>
)
}
</header> </header>
<hr class="mb-3"> <hr class="mb-3" />
<main class="max-w-[100ch] font-prose post-content"> <main class="max-w-[100ch] font-prose post-content">
<slot /> <slot />
</main> </main>
<footer class="mt-20">
<p class="post-meta">
I pledge to spend all the extra free time on silly experiments.
</p>
<a href="https://ko-fi.com/D1D4AFWZX" target="_blank">
<img
class="inline-block border-0 h-[24px]"
src="https://storage.ko-fi.com/cdn/kofi1.png?v=6"
alt="Buy Me a Coffee at ko-fi.com"
/>
</a>
<a
href="https://patreon.com/lbfalvy?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink"
>
<Image
class="inline-block border-0 h-[16px] w-[90px] object-cover ml-3"
src={patreonWordmark}
alt="Support me on Patreon"
/>
</a>
</footer>
</article> </article>
</Main> </Main>

View File

@@ -1,10 +1,11 @@
--- ---
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import NavLink from "../components/NavLink.astro"; import NavLink from "../components/NavLink.astro";
import Layout from "../layouts/Html.astro" import Layout from "../layouts/Html.astro";
import "../styles/global.css"; import "../styles/global.css";
import GhLogo from "../icons/github-mark-white.svg"; import GhLogo from "../icons/github-mark-white.svg";
import RssLogo from "../icons/rss.svg"; import RssLogo from "../icons/rss.svg";
import BskyLogo from "../icons/Bluesky_Logo.svg";
import { SITE_DESCRIPTION, SITE_TITLE } from "../consts"; import { SITE_DESCRIPTION, SITE_TITLE } from "../consts";
interface Props { interface Props {
@@ -18,40 +19,74 @@ const {
description = SITE_DESCRIPTION, description = SITE_DESCRIPTION,
image, image,
} = Astro.props; } = Astro.props;
--- ---
<Layout title={title} description={description} image={image}> <Layout title={title} description={description} image={image}>
<Fragment slot="head"> <Fragment slot="head">
<meta name="theme-color" content="#222" /> <meta name="theme-color" content="#222" />
<link rel="icon" type="image/png" href="https://github.com/lbfalvy.png"/> <link rel="icon" type="image/png" href="https://github.com/lbfalvy.png" />
</Fragment> </Fragment>
<div class=" <div
w-screen h-screen class="w-screen h-screen
flex flex-col flex flex-col
md:grid md:grid
md:grid-rows-[1fr_auto] md:grid-cols-[min-content_auto] md:grid-rows-[1fr_auto] md:grid-cols-[min-content_auto]"
"> >
<header class=" <header
emph-bg whitespace-nowrap md:px-3 py-2 flex flex-col class="emph-bg whitespace-nowrap md:px-3 py-2 flex flex-col
text-right text-right"
"> >
<h1 class="font-bold text-2xl m-2 mr-0 text-wrap lg:text-nowrap">Lawrence Bet…</h1> <h1 class="font-bold text-2xl m-2 mr-0 text-wrap lg:text-nowrap">
<nav class="gutter Lawrence Bet…
</h1>
<nav
class="gutter
flex md:flex-col flex md:flex-col
text-center md:text-right"> text-center md:text-right"
<NavLink href="/" zone="/blog">Blog</NavLink> >
<NavLink href="/projects">Projects</NavLink> <NavLink href="/" zone="/blog">Blog</NavLink>
<NavLink href="/about">About me</NavLink> <NavLink href="/projects">Projects</NavLink>
<NavLink href="/fortune">Fortune</NavLink> <NavLink href="/about">About me</NavLink>
</nav> <NavLink href="/fortune">Fortune</NavLink>
</header> </nav>
<main id="scroll-area" class="md:row-start-1 md:col-start-2 md:row-span-2 md:overflow-y-auto"> </header>
<main
id="scroll-area"
class="md:row-start-1 md:col-start-2 md:row-span-2 md:overflow-y-auto"
>
<slot /> <slot />
</main> </main>
<footer class="md:row-start-2 emph-bg flex justify-center gap-3 py-3"> <footer class="md:row-start-2 emph-bg flex justify-center gap-3 py-3">
<a href="https://github.com/lbfalvy"><Image height="20" width="20" src={GhLogo} alt="Github"/></a> <a href="https://github.com/lbfalvy">
<a href="/rss.xml"><Image height="20" width="20" src={RssLogo} alt="Rss"/></a> <Image
height="20"
width="20"
src={GhLogo}
alt="Github"
loading="eager"
/>
</a>
<a href="/rss.xml">
<Image height="20" width="20" src={RssLogo} alt="Rss" loading="eager" />
</a>
<a href="https://bsky.app/profile/lbfalvy.bsky.social">
<Image
height="20"
width="20"
src={BskyLogo}
alt="BlueSky"
loading="eager"
/>
</a>
<a href="https://fosstodon.org/@lbfalvy">
<img
src="https://cdn.fosstodon.org/site_uploads/files/000/000/007/48/91cda647d1c18689.png"
alt="Fosstodon"
height="20"
width="20"
loading="eager"
/>
</a>
</footer> </footer>
</div> </div>
</Layout> </Layout>
@@ -59,9 +94,9 @@ const {
<script> <script>
const key = `scroll:${window.location.pathname}`; const key = `scroll:${window.location.pathname}`;
const scrollArea = document.getElementById("scroll-area"); const scrollArea = document.getElementById("scroll-area");
scrollArea?.addEventListener('scrollend', () => { scrollArea?.addEventListener("scrollend", () => {
sessionStorage.setItem(key, scrollArea.scrollTop.toString()) sessionStorage.setItem(key, scrollArea.scrollTop.toString());
}) });
const savedPos = sessionStorage.getItem(key); const savedPos = sessionStorage.getItem(key);
if (savedPos) scrollArea!.scrollTop = Number.parseFloat(savedPos); if (savedPos) scrollArea!.scrollTop = Number.parseFloat(savedPos);
</script> </script>

View File

@@ -1,4 +1,5 @@
--- ---
import { Image } from "astro:assets";
import Main from "../layouts/Main.astro"; import Main from "../layouts/Main.astro";
--- ---
@@ -8,7 +9,8 @@ import Main from "../layouts/Main.astro";
description="Lawrence Bethlenfalvy, software engineer" description="Lawrence Bethlenfalvy, software engineer"
> >
<div class="max-w-[80ch] m-5"> <div class="max-w-[80ch] m-5">
<img src='https://github.com/lbfalvy.png' <Image src='https://github.com/lbfalvy.png' loading="eager"
alt="My face" width="120" height="120"
class="rounded-full h-30 float-right m-3 [shape-outside:_ellipse()]" /> class="rounded-full h-30 float-right m-3 [shape-outside:_ellipse()]" />
<p> <p>
My name is Lawrence Bethlenfalvy, I make websites and web-based applications primarily My name is Lawrence Bethlenfalvy, I make websites and web-based applications primarily

8
src/pages/fortune.astro Normal file
View File

@@ -0,0 +1,8 @@
---
import Main from "../layouts/Main.astro";
import Fortune from "../components/Fortune";
---
<Main title="Fortune" description="Wisdom from Tux">
<Fortune client:only="react" />
</Main>

36
src/pages/projects.astro Normal file
View File

@@ -0,0 +1,36 @@
---
import { getCollection, render } from "astro:content";
import Main from "../layouts/Main.astro";
import { Image } from "astro:assets";
const projects = await getCollection("projects");
const projReady = await Promise.all(
projects.map(async (proj) => [proj, (await render(proj)).Content] as const),
);
---
<Main>
<div class="grid xs:grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 max-w-[100ch]">
{
projReady.map(([proj, Content]) => (
<a href={proj.data.url}>
<article class="emph-bg m-3 p-2 text-sm rounded-2xl">
{proj.data.image && <Image
src={proj.data.image}
alt=""
loading="eager"
width="100" height="60"
class="object-center aspect-[16/9] w-full"
/>}
<h2 class="font-bold text-xl italic">
{proj.data.name}
</h2>
<div>
<Content />
</div>
</article>
</a>
))
}
</div>
</Main>

View File

@@ -80,6 +80,7 @@
} }
} }
@theme { @theme {
--breakpoint-xs: 25rem;
--tw-border-style: solid; --tw-border-style: solid;
--color-emph-bg: #181818; --color-emph-bg: #181818;
--color-side-bg: #333; --color-side-bg: #333;
@@ -100,7 +101,6 @@
color: var(--color-faint-fg); color: var(--color-faint-fg);
font-style: italic; font-style: italic;
font-weight: 500; font-weight: 500;
white-space: nowrap;
margin-left: 0.3em; margin-left: 0.3em;
} }
.summary { .summary {

View File

@@ -4,13 +4,18 @@ function lt(one: Temporal.Duration, other: Temporal.DurationLike): boolean {
return Temporal.Duration.compare(one, other) < 0 return Temporal.Duration.compare(one, other) < 0
} }
export function printTime(time: Temporal.ZonedDateTime): string { export function printTime(datetime: Temporal.ZonedDateTime): string {
const delta = time.until(Temporal.Now.zonedDateTimeISO()) const delta = datetime.until(Temporal.Now.zonedDateTimeISO())
if (lt(delta, { minutes: 1 })) return 'now' if (lt(delta, { minutes: 1 })) return 'now'
if (lt(delta, { minutes: 2 })) return '1 minute ago'
if (lt(delta, { hours: 1 })) return `${delta.minutes} minutes ago` if (lt(delta, { hours: 1 })) return `${delta.minutes} minutes ago`
if (lt(delta, { hours: 2 })) return `1 hour ago`
if (lt(delta, { days: 1 })) return `${delta.hours} hours ago` if (lt(delta, { days: 1 })) return `${delta.hours} hours ago`
if (lt(delta, { days: 2 })) return `yesterday`
if (lt(delta, { days: 7 })) return `${delta.round({ smallestUnit: 'days' }).days} days ago` if (lt(delta, { days: 7 })) return `${delta.round({ smallestUnit: 'days' }).days} days ago`
return `at ${time.toPlainDate().toString()} ${time.toPlainTime().toString({ smallestUnit: 'minutes' })}` const date = datetime.toPlainDate().toString();
const time = datetime.toPlainTime().toString({ smallestUnit: 'minutes' });
return `at ${date} ${time}`
} }
export function parseTime(string: string): Temporal.ZonedDateTime { export function parseTime(string: string): Temporal.ZonedDateTime {

View File

@@ -1,5 +0,0 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
}

View File

@@ -12,11 +12,18 @@
"editor.wordWrap": "bounded", "editor.wordWrap": "bounded",
"editor.wordWrapColumn": 80, "editor.wordWrapColumn": 80,
"editor.lineNumbers": "off", "editor.lineNumbers": "off",
"editor.rulers": [],
"editor.quickSuggestions": { "editor.quickSuggestions": {
"comments": "off", "comments": "off",
"strings": "off", "strings": "off",
"other": "off" "other": "off"
} }
} }
},
"extensions": {
"recommendations": [
"bradlc.vscode-tailwindcss",
"svelte.svelte-vscode"
]
} }
} }