diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..d2419a3 --- /dev/null +++ b/TODO.md @@ -0,0 +1,3 @@ +- Search +- Tag count +- Link in contact to status monitor diff --git a/astro.config.mjs b/astro.config.mjs index b83bba2..56aa4ac 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,17 +1,22 @@ // @ts-check -import { defineConfig } from 'astro/config' +import { rehypeHeadingIds } from '@astrojs/markdown-remark' import mdx from '@astrojs/mdx' - import sitemap from '@astrojs/sitemap' +import svelte from '@astrojs/svelte' +import { defineConfig } from 'astro/config' +import rehypeAutolinkHeadings from 'rehype-autolink-headings' +import Icons from 'unplugin-icons/vite' import { remarkReadingTime } from './readingTime' -import svelte from '@astrojs/svelte'; - // https://astro.build/config export default defineConfig({ site: 'https://example.com', integrations: [mdx(), sitemap(), svelte()], markdown: { + rehypePlugins: [rehypeHeadingIds, [rehypeAutolinkHeadings, { behavior: 'wrap' }]], remarkPlugins: [remarkReadingTime], }, -}) \ No newline at end of file + vite: { + plugins: [Icons({ compiler: 'astro' })], + }, +}) diff --git a/package.json b/package.json index 5a8454d..49333c6 100644 --- a/package.json +++ b/package.json @@ -8,22 +8,26 @@ "preview": "astro preview", "start": "astro dev" }, - "dependencies": {}, "devDependencies": { "@astrojs/check": "^0.9.4", + "@astrojs/markdown-remark": "^5.3.0", "@astrojs/mdx": "^3.1.9", "@astrojs/rss": "^4.0.9", "@astrojs/sitemap": "^3.2.1", "@astrojs/svelte": "^6.0.2", "@fontsource-variable/jost": "^5.1.1", "@fontsource-variable/playfair-display": "^5.1.0", + "@iconify-json/ion": "^1.2.1", "astro": "^4.16.13", "mdast-util-to-string": "^4.0.0", "reading-time": "^1.5.0", + "rehype-autolink-headings": "^7.1.0", + "remark-toc": "^9.0.0", "sass": "^1.81.0", "sharp": "^0.33.5", "svelte": "^5.2.7", - "typescript": "^5.6.3" + "typescript": "^5.6.3", + "unplugin-icons": "^0.20.2" }, "packageManager": "pnpm@9.12.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8016f09..f848e12 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@astrojs/check': specifier: ^0.9.4 version: 0.9.4(typescript@5.6.3) + '@astrojs/markdown-remark': + specifier: ^5.3.0 + version: 5.3.0 '@astrojs/mdx': specifier: ^3.1.9 version: 3.1.9(astro@4.16.13(rollup@4.27.3)(sass@1.81.0)(stylus@0.64.0)(typescript@5.6.3)) @@ -29,6 +32,9 @@ importers: '@fontsource-variable/playfair-display': specifier: ^5.1.0 version: 5.1.0 + '@iconify-json/ion': + specifier: ^1.2.1 + version: 1.2.1 astro: specifier: ^4.16.13 version: 4.16.13(rollup@4.27.3)(sass@1.81.0)(stylus@0.64.0)(typescript@5.6.3) @@ -38,6 +44,12 @@ importers: reading-time: specifier: ^1.5.0 version: 1.5.0 + rehype-autolink-headings: + specifier: ^7.1.0 + version: 7.1.0 + remark-toc: + specifier: ^9.0.0 + version: 9.0.0 sass: specifier: ^1.81.0 version: 1.81.0 @@ -50,6 +62,9 @@ importers: typescript: specifier: ^5.6.3 version: 5.6.3 + unplugin-icons: + specifier: ^0.20.2 + version: 0.20.2(svelte@5.2.7) packages: @@ -60,6 +75,15 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@antfu/install-pkg@0.4.1': + resolution: {integrity: sha512-T7yB5QNG29afhWVkVq7XeIMBa5U/vs9mX69YqayXypPRmYzUmzwnYltplHmPtZ4HPCn+sQKeXW8I47wCbuBOjw==} + + '@antfu/install-pkg@0.5.0': + resolution: {integrity: sha512-dKnk2xlAyC7rvTkpkHmu+Qy/2Zc3Vm/l8PtNyIOGDBtXPY3kThfU4ORNEp3V7SXw5XSOb+tOJaUYpfquPzL/Tg==} + + '@antfu/utils@0.7.10': + resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} + '@astrojs/check@0.9.4': resolution: {integrity: sha512-IOheHwCtpUfvogHHsvu0AbeRZEnjJg3MopdLddkJE70mULItS/Vh37BHcI00mcOJcH1vhD3odbpvWokpxam7xA==} hasBin: true @@ -369,6 +393,15 @@ packages: '@fontsource-variable/playfair-display@5.1.0': resolution: {integrity: sha512-51UJAHznXiGkchEOT5AYFuIy9N9m1JE7YxcdOtY0H4SKgzK9YYGKpeCXv3dz2e1gAd+BP2TyR0QXNnVjgeCbgw==} + '@iconify-json/ion@1.2.1': + resolution: {integrity: sha512-33jiBdtP8+uBV0KRz8Z9g54QFujzssiT9W6wdNuY61VQM1s3cvoAX89yiczRs4/6b2xJE5vqqvsEJAQPqfY5JA==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@2.1.33': + resolution: {integrity: sha512-jP9h6v/g0BIZx0p7XGJJVtkVnydtbgTgt9mVNcGDYwaa7UhdHdI9dvoq+gKj9sijMSJKxUPEG2JyjsgXjxL7Kw==} + '@img/sharp-darwin-arm64@0.33.5': resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -777,6 +810,9 @@ packages: '@types/sax@1.2.7': resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + '@types/ungap__structured-clone@1.2.0': + resolution: {integrity: sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -980,6 +1016,9 @@ packages: common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1226,6 +1265,9 @@ packages: hast-util-from-parse5@8.0.2: resolution: {integrity: sha512-SfMzfdAi/zAoZ1KkFEyyeXBn7u/ShQrfd675ZEE9M3qj+PMFX05xubzRyF76CCSJu8au9jgVxDV1+okFvgZU4A==} + hast-util-heading-rank@3.0.0: + resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} @@ -1393,10 +1435,17 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + load-yaml-file@0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} engines: {node: '>=6'} + local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} @@ -1487,6 +1536,9 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdast-util-toc@7.1.0: + resolution: {integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1612,6 +1664,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mlly@1.7.3: + resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} + mrmime@2.0.0: resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} engines: {node: '>=10'} @@ -1681,6 +1736,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@0.2.5: + resolution: {integrity: sha512-3dS7y28uua+UDbRCLBqltMBrbI+A5U2mI9YuxHRxIWYmLj3DwntEBmERYzIAQ4DMeuCUOBSak7dBHHoXKpOTYQ==} + parse-entities@4.0.1: resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} @@ -1708,6 +1766,9 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1727,6 +1788,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@1.2.1: + resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + postcss@8.4.49: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} @@ -1782,6 +1846,9 @@ packages: regex@5.0.2: resolution: {integrity: sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==} + rehype-autolink-headings@7.1.0: + resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} + rehype-parse@9.0.1: resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} @@ -1816,6 +1883,9 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + remark-toc@9.0.0: + resolution: {integrity: sha512-KJ9txbo33GjDAV1baHFze7ij4G8c7SGYoY8Kzsm2gzFpbhL/bSoVpMMzGa3vrNDSWASNd/3ppAqL7cP2zD6JIA==} + request-light@0.5.8: resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} @@ -2026,6 +2096,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -2059,6 +2132,33 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unplugin-icons@0.20.2: + resolution: {integrity: sha512-Ak6TKAiO812aIUrCelrBSTQbYC4FiqawnFrAusP/hjmB8f9cAug9jr381ItvLl+Asi4IVcjoOiPbpy9CfFGKvQ==} + peerDependencies: + '@svgr/core': '>=7.0.0' + '@svgx/core': ^1.0.1 + '@vue/compiler-sfc': ^3.0.2 || ^2.7.0 + svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 + vue-template-compiler: ^2.6.12 + vue-template-es2015-compiler: ^1.9.0 + peerDependenciesMeta: + '@svgr/core': + optional: true + '@svgx/core': + optional: true + '@vue/compiler-sfc': + optional: true + svelte: + optional: true + vue-template-compiler: + optional: true + vue-template-es2015-compiler: + optional: true + + unplugin@1.16.0: + resolution: {integrity: sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==} + engines: {node: '>=14.0.0'} + update-browserslist-db@1.1.1: resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true @@ -2222,6 +2322,9 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + which-pm-runs@1.1.0: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} @@ -2316,6 +2419,18 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@antfu/install-pkg@0.4.1': + dependencies: + package-manager-detector: 0.2.5 + tinyexec: 0.3.1 + + '@antfu/install-pkg@0.5.0': + dependencies: + package-manager-detector: 0.2.5 + tinyexec: 0.3.1 + + '@antfu/utils@0.7.10': {} + '@astrojs/check@0.9.4(typescript@5.6.3)': dependencies: '@astrojs/language-server': 2.15.4(typescript@5.6.3) @@ -2668,6 +2783,24 @@ snapshots: '@fontsource-variable/playfair-display@5.1.0': {} + '@iconify-json/ion@1.2.1': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@2.1.33': + dependencies: + '@antfu/install-pkg': 0.4.1 + '@antfu/utils': 0.7.10 + '@iconify/types': 2.0.0 + debug: 4.3.7 + kolorist: 1.8.0 + local-pkg: 0.5.1 + mlly: 1.7.3 + transitivePeerDependencies: + - supports-color + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.4 @@ -3048,6 +3181,8 @@ snapshots: dependencies: '@types/node': 17.0.45 + '@types/ungap__structured-clone@1.2.0': {} + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -3324,6 +3459,8 @@ snapshots: common-ancestor-path@1.0.1: {} + confbox@0.1.8: {} + convert-source-map@2.0.0: {} cookie@0.7.2: {} @@ -3591,6 +3728,10 @@ snapshots: vfile-location: 5.0.3 web-namespaces: 2.0.1 + hast-util-heading-rank@3.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-is-element@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -3797,6 +3938,8 @@ snapshots: kleur@4.1.5: {} + kolorist@1.8.0: {} + load-yaml-file@0.2.0: dependencies: graceful-fs: 4.2.11 @@ -3804,6 +3947,11 @@ snapshots: pify: 4.0.1 strip-bom: 3.0.0 + local-pkg@0.5.1: + dependencies: + mlly: 1.7.3 + pkg-types: 1.2.1 + locate-character@3.0.0: {} locate-path@5.0.0: @@ -4013,6 +4161,16 @@ snapshots: dependencies: '@types/mdast': 4.0.4 + mdast-util-toc@7.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/ungap__structured-clone': 1.2.0 + '@ungap/structured-clone': 1.2.0 + github-slugger: 2.0.0 + mdast-util-to-string: 4.0.0 + unist-util-is: 6.0.0 + unist-util-visit: 5.0.0 + merge2@1.4.1: {} micromark-core-commonmark@2.0.2: @@ -4296,6 +4454,13 @@ snapshots: minipass@7.1.2: optional: true + mlly@1.7.3: + dependencies: + acorn: 8.14.0 + pathe: 1.1.2 + pkg-types: 1.2.1 + ufo: 1.5.4 + mrmime@2.0.0: {} ms@2.1.3: {} @@ -4366,6 +4531,8 @@ snapshots: package-json-from-dist@1.0.1: optional: true + package-manager-detector@0.2.5: {} + parse-entities@4.0.1: dependencies: '@types/unist': 2.0.11 @@ -4408,6 +4575,8 @@ snapshots: minipass: 7.1.2 optional: true + pathe@1.1.2: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -4420,6 +4589,12 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@1.2.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.3 + pathe: 1.1.2 + postcss@8.4.49: dependencies: nanoid: 3.3.7 @@ -4490,6 +4665,15 @@ snapshots: dependencies: regex-utilities: 2.3.0 + rehype-autolink-headings@7.1.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.2.0 + hast-util-heading-rank: 3.0.0 + hast-util-is-element: 3.0.0 + unified: 11.0.5 + unist-util-visit: 5.0.0 + rehype-parse@9.0.1: dependencies: '@types/hast': 3.0.4 @@ -4571,6 +4755,11 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 + remark-toc@9.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-toc: 7.1.0 + request-light@0.5.8: {} request-light@0.7.0: {} @@ -4834,6 +5023,8 @@ snapshots: typescript@5.6.3: {} + ufo@1.5.4: {} + unified@11.0.5: dependencies: '@types/unist': 3.0.3 @@ -4890,6 +5081,25 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 + unplugin-icons@0.20.2(svelte@5.2.7): + dependencies: + '@antfu/install-pkg': 0.5.0 + '@antfu/utils': 0.7.10 + '@iconify/utils': 2.1.33 + debug: 4.3.7 + kolorist: 1.8.0 + local-pkg: 0.5.1 + unplugin: 1.16.0 + optionalDependencies: + svelte: 5.2.7 + transitivePeerDependencies: + - supports-color + + unplugin@1.16.0: + dependencies: + acorn: 8.14.0 + webpack-virtual-modules: 0.6.2 + update-browserslist-db@1.1.1(browserslist@4.24.2): dependencies: browserslist: 4.24.2 @@ -5036,6 +5246,8 @@ snapshots: web-namespaces@2.0.1: {} + webpack-virtual-modules@0.6.2: {} + which-pm-runs@1.1.0: {} which-pm@3.0.0: diff --git a/src/components/BaseHead.astro b/src/components/BaseHead.astro index 0e0e173..61842a3 100644 --- a/src/components/BaseHead.astro +++ b/src/components/BaseHead.astro @@ -3,7 +3,7 @@ import '@fontsource-variable/jost' import '@fontsource-variable/playfair-display' import '../styles/preflight.css' -import '../styles/global.css' +import '../styles/global.scss' interface Props { image?: string @@ -44,3 +44,6 @@ const description = 'Welcome to my website!' + + diff --git a/src/components/FormattedDate.astro b/src/components/FormattedDate.astro index 1bcce73..ecf8110 100644 --- a/src/components/FormattedDate.astro +++ b/src/components/FormattedDate.astro @@ -1,17 +1,17 @@ --- interface Props { - date: Date; + date: Date } -const { date } = Astro.props; +const { date } = Astro.props --- diff --git a/src/components/Links.astro b/src/components/Links.astro new file mode 100644 index 0000000..90112f2 --- /dev/null +++ b/src/components/Links.astro @@ -0,0 +1,51 @@ +--- +import FingerPrint from '~icons/ion/finger-print' +import ChatBubbles from '~icons/ion/chatbubbles-outline' +import Mail from '~icons/ion/mail-outline' +import Heart from '~icons/ion/heart' +import Github from '~icons/ion/logo-github' +import Trending from '~icons/ion/trending-up' + +const links: { label: string; url: string; icon: astroHTML.JSX.Element }[] = [ + { label: 'Say hi@nicco.io', url: 'mailto:hi@nicco.io', icon: Mail }, + { label: 'Chat on discord', url: 'https://discord.gg/wS7RpYTYd2', icon: ChatBubbles }, + { label: 'GitHub', url: 'https://github.com/cupcakearmy', icon: Github }, + { label: 'Support my work', url: 'https://github.com/sponsors/cupcakearmy', icon: Heart }, + { label: 'Traffic', url: 'https://spectare.nicco.io/share/HYgOcrlfHxGB9RAR/nicco.io', icon: Trending }, + { label: 'Privacy', url: '/privacy', icon: FingerPrint }, +] +--- + + + + diff --git a/src/components/Nav.astro b/src/components/Nav.astro index dde13dc..92c8911 100644 --- a/src/components/Nav.astro +++ b/src/components/Nav.astro @@ -5,7 +5,7 @@ const routes = [ { name: 'About', href: '/about' }, { name: 'Projects', href: '/projects' }, { name: 'Blog', href: '/blog' }, - { name: 'Contact', href: '/contact' }, + { name: 'Rest', href: '/rest' }, ] --- diff --git a/src/components/PostAttributes.astro b/src/components/PostAttributes.astro index 63a1b52..6ea626c 100644 --- a/src/components/PostAttributes.astro +++ b/src/components/PostAttributes.astro @@ -1,32 +1,28 @@ --- import type { CollectionEntry } from 'astro:content' +import type { ReadTimeResults } from 'reading-time' import FormattedDate from './FormattedDate.astro' +import ReadingTime from './ReadingTime.astro' -export type Props = { - post: CollectionEntry<'blog'> - full?: boolean -} +type Props = { + readingTime: ReadTimeResults +} & Pick['data'], 'date' | 'updatedDate'> -const { post, full = false } = Astro.props - -const { remarkPluginFrontmatter } = await post.render() +const { updatedDate, date, readingTime } = Astro.props ---
-
- +
+ { - full && post.data.updatedDate && post.data.date !== post.data.updatedDate && ( - <> -
- - Last update: - - + updatedDate && date !== updatedDate && ( +
+ Updated: +
) }
-
~ {remarkPluginFrontmatter.readingTime.minutes.toFixed(0)} min
+
diff --git a/src/components/PostPreview.astro b/src/components/PostPreview.astro index 20e8355..731cfc0 100644 --- a/src/components/PostPreview.astro +++ b/src/components/PostPreview.astro @@ -9,15 +9,20 @@ export type Props = { } const { post } = Astro.props +const { remarkPluginFrontmatter } = await post.render() ---
{post.data.coverImage && } - +

{post.data.title}

- ({ count: 1, name: tag, href: `/tag/${tag}` }))} /> + ({ name: tag, href: `/tag/${tag}` }))} />
diff --git a/src/components/Tag.astro b/src/components/Tag.astro index dd0ed44..2479170 100644 --- a/src/components/Tag.astro +++ b/src/components/Tag.astro @@ -2,7 +2,7 @@ export type Props = { name: string href: string - count: number + count?: number } const { name, href, count } = Astro.props @@ -11,7 +11,7 @@ const { name, href, count } = Astro.props
{name} - {count} + {count && {count}}
diff --git a/src/components/Toc.astro b/src/components/Toc.astro new file mode 100644 index 0000000..77d4ef6 --- /dev/null +++ b/src/components/Toc.astro @@ -0,0 +1,47 @@ +--- +import type { MarkdownHeading } from 'astro' + +type Props = { headings: MarkdownHeading[] } + +const { headings } = Astro.props +--- + +
+ Outline + { + headings.map(({ slug, text, depth }) => ( +
+ + {text} +
+ )) + } +
+ + diff --git a/src/content/blog/a-sane-and-efficient-guide-for-consuming-graphql-endpoints-in-typescript.md b/src/content/blog/a-sane-and-efficient-guide-for-consuming-graphql-endpoints-in-typescript.md index ddfb3a0..e27e4b8 100644 --- a/src/content/blog/a-sane-and-efficient-guide-for-consuming-graphql-endpoints-in-typescript.md +++ b/src/content/blog/a-sane-and-efficient-guide-for-consuming-graphql-endpoints-in-typescript.md @@ -16,18 +16,6 @@ Lets dive deeper 🤿. I created a tiny [companion repository](https://github.com/cupcakearmy/blog-typescript-graphql) if you want to check out the code and try it out. Or check out the [finished demo](https://blog-typescript-graphql.vercel.app/). -
- -![](images/clayton-robbins-Ru09fQONJWo-unsplash-1024x683.jpg) - -
- -Photo by [Clayton Robbins](https://unsplash.com/@claytonrobbins?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/@claytonrobbins?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) - -
- -
- ## Intro First we need to decide on what do we want (and probably need) @@ -50,7 +38,7 @@ The setup will be be for VSCode. For that we first install the [GraphQL extensio We need to add a `.graphqlrc.yml` file at the root with the following content: -``` +```yaml schema: https://api.spacex.land/graphql/ ``` @@ -68,7 +56,7 @@ We want to take our endpoint, generate types and queries from it that can then b There is this amazing project called `@graphql-codegen` which is a collection of tools for helping you generating various things from GraphQL. Let's install: -``` +```bash # Generators pnpm i -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-graphql-request # For the SDK @@ -79,17 +67,17 @@ I will assume my GraphQL stuff will live under `./src/lib/gql` We will create a top level configuration file to handle all of our generation step called `codegen.yaml`. Ignore the `config` option for now, I will explain that later -``` +```yaml schema: https://api.spacex.land/graphql/ -documents: "src/**/*.graphql" +documents: 'src/**/*.graphql' generates: ./src/lib/gql/gen.ts: plugins: - - "@graphql-codegen/typescript" - - "@graphql-codegen/typescript-operations" - - "@graphql-codegen/typescript-graphql-request" + - '@graphql-codegen/typescript' + - '@graphql-codegen/typescript-operations' + - '@graphql-codegen/typescript-graphql-request' config: - maybeValue: "T" + maybeValue: 'T' typesPrefix: GQL immutableTypes: true useTypeImports: true @@ -104,7 +92,7 @@ The property `schema` does not need an explanation. Now let's create a `src/lib/gql/root.graphql` file and write some queries, all autocompleted of course! -``` +```gql query LaunchpadsMany { launchpads(limit: 10) { id @@ -131,7 +119,7 @@ query LaunchByYear($year: String!) { ### Let magic do it's thing -``` +```bash pnpm exec graphql-codegen ``` @@ -139,7 +127,7 @@ This will look at all our custom queries and mutations and generate us a ready t ### Leverage the new SDK -``` +```ts // src/lib/gql/index.ts import { GraphQLClient } from 'graphql-request' @@ -149,7 +137,7 @@ const client = new GraphQLClient('https://api.spacex.land/graphql/') export const SDK = getSdk(client) ``` -``` +```ts import { SDK } from '$lib/gql' const data = await SDK.LaunchByYear({ year: '2021' }) @@ -157,7 +145,7 @@ const data = await SDK.LaunchByYear({ year: '2021' }) You can also use the generated types to explicitly set them -``` +```ts import { SDK } from '$lib/gql' import type { GQLLaunchByYearQuery } from '$lib/gql/gen' @@ -170,7 +158,7 @@ Every thing is typed now, I can't pass a number to the `year` variable or use re I promised I would come back to it at some point. -``` +```yaml schema: ... generates: ... diff --git a/src/content/blog/leaving-nextcloud-from-heaven-to-the-depths-of-seafile.md b/src/content/blog/leaving-nextcloud-from-heaven-to-the-depths-of-seafile.md index 9f15dbd..934bd92 100644 --- a/src/content/blog/leaving-nextcloud-from-heaven-to-the-depths-of-seafile.md +++ b/src/content/blog/leaving-nextcloud-from-heaven-to-the-depths-of-seafile.md @@ -1,6 +1,7 @@ --- title: 'Leaving Nextcloud: From heaven to the depths of Seafile' date: '2021-03-23' +updatedDate: '2021-03-27' categories: - 'general' tags: diff --git a/src/content/blog/why-i-love-js-but-sometimes-i-feel-we-shoot-ourself-in-the-foot.md b/src/content/blog/why-i-love-js-but-sometimes-i-feel-we-shoot-ourself-in-the-foot.md index 092d154..a80c60a 100644 --- a/src/content/blog/why-i-love-js-but-sometimes-i-feel-we-shoot-ourself-in-the-foot.md +++ b/src/content/blog/why-i-love-js-but-sometimes-i-feel-we-shoot-ourself-in-the-foot.md @@ -1,8 +1,8 @@ --- -title: "Why I love JS but sometimes I feel we shoot ourself in the foot." -date: "2020-05-29" -categories: - - "general" +title: 'Why I love JS but sometimes I feel we shoot ourself in the foot.' +date: '2020-05-29' +categories: + - 'general' --- Let's start by saying this: I absolutely love JS & Typescript, they are my favourite languages and I would not want to live without them. @@ -19,7 +19,7 @@ So an economist might think: "Why is this bad? Competition is always good as it What is the consequence of this? Many abandoned, half-finished packages that need to be rewritten every now and then only to be left unmaintained again. Let the cycle repeat itself... -## Bundle work! Not disperse it +## Bundle work! Don't disperse it What if instead of reinventing the wheel over and over again we tune the wheel we have so that it becomes the best, most versatile wheel for everyone. Fragmentation is always a huge amount of work and leads to half-backed projects that always have some downsides. From that downside a new project is born and again, the cycle continues. diff --git a/src/content/page/projects.md b/src/content/page/projects.md new file mode 100644 index 0000000..2be69d6 --- /dev/null +++ b/src/content/page/projects.md @@ -0,0 +1,6 @@ +--- +title: Projects +date: '2024-11-29' +--- + +To be filled :) diff --git a/src/content/page/rest.mdx b/src/content/page/rest.mdx new file mode 100644 index 0000000..ec093a6 --- /dev/null +++ b/src/content/page/rest.mdx @@ -0,0 +1,7 @@ +--- +title: Rest +date: '2024-11-29' +--- +import ContactLinks from '../../components/Links.astro' + + diff --git a/src/layouts/BlogPost.astro b/src/layouts/BlogPost.astro index c90900e..074adfd 100644 --- a/src/layouts/BlogPost.astro +++ b/src/layouts/BlogPost.astro @@ -1,36 +1,30 @@ --- -import type { CollectionEntry } from 'astro:content' -import FormattedDate from '../components/FormattedDate.astro' +import type { MarkdownHeading } from 'astro' import { Image } from 'astro:assets' -import Root from './Root.astro' +import type { CollectionEntry } from 'astro:content' +import type { ReadTimeResults } from 'reading-time' +import PostAttributes from '../components/PostAttributes.astro' +import Tags from '../components/Tags.astro' +import Toc from '../components/Toc.astro' +import PageWithTitle from './PageWithTitle.astro' -type Props = CollectionEntry<'blog'>['data'] +type Props = CollectionEntry<'blog'>['data'] & { headings: MarkdownHeading[]; readingTime: ReadTimeResults } -const { title, updatedDate, date, tags, coverImage } = Astro.props +const { title, updatedDate, date, tags, coverImage, headings, readingTime } = Astro.props --- - +
-
- {coverImage && } -
-
-
-
- - { - updatedDate && ( -
- Last updated on -
- ) - } -
-

{title}

- {tags.map((tag) => {tag})} -
-
- -
+ + + {coverImage && } + ({ name: t, href: `/tag/${t}` }))} /> +
-
+ + + diff --git a/src/pages/blog/[...slug].astro b/src/pages/blog/[...slug].astro index 55cc086..0fa351f 100644 --- a/src/pages/blog/[...slug].astro +++ b/src/pages/blog/[...slug].astro @@ -11,9 +11,25 @@ export async function getStaticPaths() { } const post = Astro.props -const { Content } = await post.render() +const { Content, headings, remarkPluginFrontmatter } = await post.render() --- - + + + diff --git a/src/pages/tag/[...tag].astro b/src/pages/tag/[...tag].astro index acf226c..05f97ac 100644 --- a/src/pages/tag/[...tag].astro +++ b/src/pages/tag/[...tag].astro @@ -1,7 +1,7 @@ --- import { getCollection } from 'astro:content' import PostList from '../../components/PostList.astro' -import Root from '../../layouts/Root.astro' +import PageWithTitle from '../../layouts/PageWithTitle.astro' export async function getStaticPaths() { const posts = await getCollection('blog') @@ -22,7 +22,6 @@ const params = Astro.params const { posts } = Astro.props --- - -

{params.tag}

+ -
+ diff --git a/src/styles/global.css b/src/styles/global.scss similarity index 87% rename from src/styles/global.css rename to src/styles/global.scss index 7457174..9e4e8e7 100644 --- a/src/styles/global.css +++ b/src/styles/global.scss @@ -58,6 +58,13 @@ h6 { line-height: 1.2; } +h2 { + font-size: 1.5rem; +} +h3 { + font-size: 1.25rem; +} + p { text-align: justify; line-height: 1.5; @@ -72,7 +79,18 @@ a { text-decoration: none; } +p a, +.toc a { + border-bottom: 0.125em solid var(--clr-primary); +} + svg { fill: currentColor; height: auto; } + +pre { + padding: 1rem; + margin: 1rem 0; + display: block; +} diff --git a/tsconfig.json b/tsconfig.json index 6e224ec..bf3224d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "astro/tsconfigs/strictest", "compilerOptions": { - "strictNullChecks": true + "strictNullChecks": true, + "types": ["unplugin-icons/types/astro"] } }