almost done

This commit is contained in:
Niccolo Borgioli 2024-11-29 17:58:26 +01:00
parent 44efa2047a
commit ccec3806f2
24 changed files with 479 additions and 106 deletions

3
TODO.md Normal file
View File

@ -0,0 +1,3 @@
- Search
- Tag count
- Link in contact to status monitor

View File

@ -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],
},
})
vite: {
plugins: [Icons({ compiler: 'astro' })],
},
})

View File

@ -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"
}

212
pnpm-lock.yaml generated
View File

@ -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:

View File

@ -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!'
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={new URL(image, Astro.url)} />
<script async defer src="https://spectare.nicco.io/unicorn.js" data-website-id="bc7525c5-6928-49e1-9255-aca296947def"
></script>

View File

@ -1,17 +1,17 @@
---
interface Props {
date: Date;
date: Date
}
const { date } = Astro.props;
const { date } = Astro.props
---
<time datetime={date.toISOString()}>
{
date.toLocaleDateString('en-us', {
year: 'numeric',
month: 'short',
day: 'numeric',
})
}
{
date.toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
})
}
</time>

View File

@ -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 },
]
---
<ul>
{
links.map(({ label, url, icon: Icon }) => {
return (
<li>
<a href={url} target="_blank" rel="noopener noreferrer">
{Icon && <Icon />}
{label}
</a>
</li>
)
})
}
</ul>
<style lang="scss">
ul {
display: flex;
flex-direction: column;
gap: 1rem;
}
a {
display: flex;
gap: 0.5rem;
padding: 0.5rem 0;
transition: var(--animation);
&:hover {
transform: translateX(5%) scale(1.1);
}
}
</style>

View File

@ -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' },
]
---

View File

@ -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<CollectionEntry<'blog'>['data'], 'date' | 'updatedDate'>
const { post, full = false } = Astro.props
const { remarkPluginFrontmatter } = await post.render()
const { updatedDate, date, readingTime } = Astro.props
---
<div class="attributes">
<div>
<FormattedDate date={post.data.date} />
<div class="estimation">
<FormattedDate date={date} />
{
full && post.data.updatedDate && post.data.date !== post.data.updatedDate && (
<>
<br />
<small>
Last update: <FormattedDate date={post.data.updatedDate} />
</small>
</>
updatedDate && date !== updatedDate && (
<div class="updated">
Updated: <FormattedDate date={updatedDate} />
</div>
)
}
</div>
<div>~ {remarkPluginFrontmatter.readingTime.minutes.toFixed(0)} min</div>
<ReadingTime readingTime={readingTime} />
</div>
<style>
@ -36,4 +32,13 @@ const { remarkPluginFrontmatter } = await post.render()
font-weight: 400;
margin-top: -0.125em;
}
.estimation {
display: flex;
align-items: baseline;
gap: 0.5em;
}
.updated {
font-size: 0.75em;
font-style: italic;
}
</style>

View File

@ -9,15 +9,20 @@ export type Props = {
}
const { post } = Astro.props
const { remarkPluginFrontmatter } = await post.render()
---
<section class:list={{ without: !post.data.coverImage }}>
{post.data.coverImage && <Picture src={post.data.coverImage} alt={'foo'} />}
<PostAttributes {post} />
<PostAttributes
date={post.data.date}
updatedDate={post.data.updatedDate}
readingTime={remarkPluginFrontmatter.readingTime}
/>
<h2>
{post.data.title}
</h2>
<Tags tags={post.data.tags.map((tag) => ({ count: 1, name: tag, href: `/tag/${tag}` }))} />
<Tags tags={post.data.tags.map((tag) => ({ name: tag, href: `/tag/${tag}` }))} />
</section>
<style lang="scss">

View File

@ -0,0 +1,9 @@
---
import type { ReadTimeResults } from 'reading-time'
type Props = { readingTime: ReadTimeResults }
const { readingTime } = Astro.props
---
<span>~ {readingTime.minutes.toFixed(0)} min</span>

View File

@ -33,6 +33,5 @@ const { letters, readable = false, even = false } = Astro.props
div.readable {
letter-spacing: initial;
text-transform: initial;
font-size: 2.25rem;
}
</style>

View File

@ -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
<a {href}>
<div>
{name}
<i>{count}</i>
{count && <i>{count}</i>}
</div>
</a>

47
src/components/Toc.astro Normal file
View File

@ -0,0 +1,47 @@
---
import type { MarkdownHeading } from 'astro'
type Props = { headings: MarkdownHeading[] }
const { headings } = Astro.props
---
<div class="toc">
<b>Outline</b>
{
headings.map(({ slug, text, depth }) => (
<div style={`margin-left: ${depth - 2}rem;`}>
<span>▶</span>
<a href={`#${slug}`}>{text}</a>
</div>
))
}
</div>
<style>
.toc {
margin: 2rem 0;
@media (min-width: 70rem) {
margin: 0;
position: absolute;
left: 45rem;
width: calc(100vw - 50rem);
}
}
span {
font-size: 0.5em;
transform: translateY(-0.8em);
display: inline-block;
}
a {
height: 1.4em;
display: inline-block;
max-width: calc(100% - 1.5rem);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>

View File

@ -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/).
<figure>
![](images/clayton-robbins-Ru09fQONJWo-unsplash-1024x683.jpg)
<figcaption>
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)
</figcaption>
</figure>
## 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:
...

View File

@ -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:

View File

@ -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.

View File

@ -0,0 +1,6 @@
---
title: Projects
date: '2024-11-29'
---
To be filled :)

View File

@ -0,0 +1,7 @@
---
title: Rest
date: '2024-11-29'
---
import ContactLinks from '../../components/Links.astro'
<ContactLinks/>

View File

@ -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
---
<Root>
<PageWithTitle title={title} readable>
<article>
<div class="hero-image">
{coverImage && <Image width={1020} height={510} src={coverImage} alt="" />}
</div>
<div class="prose">
<div class="title">
<div class="date">
<FormattedDate date={date} />
{
updatedDate && (
<div class="last-updated-on">
Last updated on <FormattedDate date={updatedDate} />
</div>
)
}
</div>
<h1>{title}</h1>
{tags.map((tag) => <a href={`/tag/${tag}`}>{tag}</a>)}
<hr />
</div>
<slot />
</div>
<Toc {headings} />
<PostAttributes {date} {updatedDate} {readingTime} />
{coverImage && <Image width={1020} height={510} src={coverImage} alt="" />}
<Tags tags={tags.map((t) => ({ name: t, href: `/tag/${t}` }))} />
<slot />
</article>
</Root>
</PageWithTitle>
<style>
img {
margin: 1rem 0;
}
</style>

View File

@ -11,9 +11,25 @@ export async function getStaticPaths() {
}
const post = Astro.props
const { Content } = await post.render()
const { Content, headings, remarkPluginFrontmatter } = await post.render()
---
<BlogPost {...post.data}>
<BlogPost {...post.data} {headings} readingTime={remarkPluginFrontmatter.readingTime}>
<Content />
</BlogPost>
<style>
:global(p) {
margin: 1rem 0;
}
:global(h2, h3, h4, h5, h6) {
--width: 0.125rem;
--offset: 0.25rem;
margin: 2rem 0 1rem;
margin: 3em 0 0;
border-left: var(--width) solid var(--clr-primary);
padding-left: var(--offset);
margin-left: calc((var(--width) + var(--offset)) * -1);
}
</style>

View File

@ -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
---
<Root>
<h1>{params.tag}</h1>
<PageWithTitle title={params.tag}>
<PostList posts={posts} />
</Root>
</PageWithTitle>

View File

@ -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;
}

View File

@ -1,6 +1,7 @@
{
"extends": "astro/tsconfigs/strictest",
"compilerOptions": {
"strictNullChecks": true
"strictNullChecks": true,
"types": ["unplugin-icons/types/astro"]
}
}