Merge pull request #207 from bartvdbraak/feat/dynamic-og-images

Add Dynamic OG image creation and Geist font, refactoring layout
This commit is contained in:
Bart van der Braak 2024-01-22 12:42:48 +01:00 committed by GitHub
commit aec93f333e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 942 additions and 367 deletions

1
.gitignore vendored
View file

@ -8,3 +8,4 @@ node_modules
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.vercel

View file

@ -14,23 +14,23 @@
"prepare": "npx husky install && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
"@sveltejs/adapter-vercel": "^4.0.4",
"@sveltejs/adapter-vercel": "^4.0.5",
"@sveltejs/enhanced-img": "^0.1.8",
"@sveltejs/kit": "^2.3.2",
"@sveltejs/kit": "^2.3.4",
"@sveltejs/vite-plugin-svelte": "^3.0.1",
"@typescript-eslint/eslint-plugin": "^6.18.1",
"@typescript-eslint/parser": "^6.18.1",
"autoprefixer": "^10.4.16",
"@typescript-eslint/eslint-plugin": "^6.19.0",
"@typescript-eslint/parser": "^6.19.0",
"autoprefixer": "^10.4.17",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1",
"lint-staged": "^15.2.0",
"postcss": "^8.4.33",
"postcss-load-config": "^5.0.2",
"prettier": "^3.2.2",
"prettier": "^3.2.4",
"prettier-plugin-svelte": "^3.1.2",
"prettier-plugin-tailwindcss": "^0.5.11",
"svelte": "^4.2.8",
"svelte": "^4.2.9",
"svelte-check": "^3.6.3",
"tailwindcss": "^3.4.1",
"tslib": "^2.6.2",
@ -38,13 +38,17 @@
"vite": "^5.0.11"
},
"dependencies": {
"@resvg/resvg-js": "^2.6.0",
"@types/node": "^20.11.5",
"@vercel/analytics": "^1.1.1",
"@vercel/speed-insights": "^1.0.3",
"@vercel/speed-insights": "^1.0.4",
"bits-ui": "^0.14.0",
"clsx": "^2.1.0",
"lucide-svelte": "^0.312.0",
"mode-watcher": "^0.1.2",
"radix-icons-svelte": "^1.2.1",
"satori": "^0.10.11",
"satori-html": "^0.3.2",
"svelte-wrap-balancer": "^0.0.4",
"tailwind-merge": "^2.2.0",
"tailwind-variants": "^0.1.20"

View file

@ -5,15 +5,21 @@ settings:
excludeLinksFromLockfile: false
dependencies:
'@resvg/resvg-js':
specifier: ^2.6.0
version: 2.6.0
'@types/node':
specifier: ^20.11.5
version: 20.11.5
'@vercel/analytics':
specifier: ^1.1.1
version: 1.1.1
'@vercel/speed-insights':
specifier: ^1.0.3
version: 1.0.3
specifier: ^1.0.4
version: 1.0.4
bits-ui:
specifier: ^0.14.0
version: 0.14.0(svelte@4.2.8)
version: 0.14.0(svelte@4.2.9)
clsx:
specifier: ^2.1.0
version: 2.1.0
@ -22,10 +28,16 @@ dependencies:
version: 0.312.0(svelte@4.2.8)
mode-watcher:
specifier: ^0.1.2
version: 0.1.2(svelte@4.2.8)
version: 0.1.2(svelte@4.2.9)
radix-icons-svelte:
specifier: ^1.2.1
version: 1.2.1
satori:
specifier: ^0.10.11
version: 0.10.11
satori-html:
specifier: ^0.3.2
version: 0.3.2
svelte-wrap-balancer:
specifier: ^0.0.4
version: 0.0.4
@ -38,26 +50,26 @@ dependencies:
devDependencies:
'@sveltejs/adapter-vercel':
specifier: ^4.0.4
version: 4.0.4(@sveltejs/kit@2.3.2)
specifier: ^4.0.5
version: 4.0.5(@sveltejs/kit@2.3.4)
'@sveltejs/enhanced-img':
specifier: ^0.1.8
version: 0.1.8(svelte@4.2.8)
version: 0.1.8(svelte@4.2.9)
'@sveltejs/kit':
specifier: ^2.3.2
version: 2.3.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.8)(vite@5.0.11)
specifier: ^2.3.4
version: 2.3.4(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.11)
'@sveltejs/vite-plugin-svelte':
specifier: ^3.0.1
version: 3.0.1(svelte@4.2.8)(vite@5.0.11)
version: 3.0.1(svelte@4.2.9)(vite@5.0.11)
'@typescript-eslint/eslint-plugin':
specifier: ^6.18.1
version: 6.18.1(@typescript-eslint/parser@6.18.1)(eslint@8.56.0)(typescript@5.3.3)
specifier: ^6.19.0
version: 6.19.0(@typescript-eslint/parser@6.19.0)(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/parser':
specifier: ^6.18.1
version: 6.18.1(eslint@8.56.0)(typescript@5.3.3)
specifier: ^6.19.0
version: 6.19.0(eslint@8.56.0)(typescript@5.3.3)
autoprefixer:
specifier: ^10.4.16
version: 10.4.16(postcss@8.4.33)
specifier: ^10.4.17
version: 10.4.17(postcss@8.4.33)
eslint:
specifier: ^8.56.0
version: 8.56.0
@ -66,7 +78,7 @@ devDependencies:
version: 9.1.0(eslint@8.56.0)
eslint-plugin-svelte:
specifier: ^2.35.1
version: 2.35.1(eslint@8.56.0)(svelte@4.2.8)
version: 2.35.1(eslint@8.56.0)(svelte@4.2.9)
lint-staged:
specifier: ^15.2.0
version: 15.2.0
@ -77,20 +89,20 @@ devDependencies:
specifier: ^5.0.2
version: 5.0.2(postcss@8.4.33)
prettier:
specifier: ^3.2.2
version: 3.2.2
specifier: ^3.2.4
version: 3.2.4
prettier-plugin-svelte:
specifier: ^3.1.2
version: 3.1.2(prettier@3.2.2)(svelte@4.2.8)
version: 3.1.2(prettier@3.2.4)(svelte@4.2.9)
prettier-plugin-tailwindcss:
specifier: ^0.5.11
version: 0.5.11(prettier-plugin-svelte@3.1.2)(prettier@3.2.2)
version: 0.5.11(prettier-plugin-svelte@3.1.2)(prettier@3.2.4)
svelte:
specifier: ^4.2.8
version: 4.2.8
specifier: ^4.2.9
version: 4.2.9
svelte-check:
specifier: ^3.6.3
version: 3.6.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.8)
version: 3.6.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9)
tailwindcss:
specifier: ^3.4.1
version: 3.4.1
@ -102,7 +114,7 @@ devDependencies:
version: 5.3.3
vite:
specifier: ^5.0.11
version: 5.0.11
version: 5.0.11(@types/node@20.11.5)
packages:
@ -666,7 +678,7 @@ packages:
- supports-color
dev: true
/@melt-ui/svelte@0.68.0(svelte@4.2.8):
/@melt-ui/svelte@0.68.0(svelte@4.2.9):
resolution: {integrity: sha512-/QvA98hnYEodZtHJ71+ocum/WWp30hVNt3F8uiZKnNYwZDaiQYjlyR9AaGKYcZLCe6R68op1mfCzc0kTzJilyA==}
peerDependencies:
svelte: '>=3 <5'
@ -677,7 +689,7 @@ packages:
dequal: 2.0.3
focus-trap: 7.5.4
nanoid: 5.0.4
svelte: 4.2.8
svelte: 4.2.9
dev: false
/@nodelib/fs.scandir@2.1.5:
@ -708,6 +720,132 @@ packages:
resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==}
dev: true
/@resvg/resvg-js-android-arm-eabi@2.6.0:
resolution: {integrity: sha512-lJnZ/2P5aMocrFMW7HWhVne5gH82I8xH6zsfH75MYr4+/JOaVcGCTEQ06XFohGMdYRP3v05SSPLPvTM/RHjxfA==}
engines: {node: '>= 10'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-android-arm64@2.6.0:
resolution: {integrity: sha512-N527f529bjMwYWShZYfBD60dXA4Fux+D695QsHQ93BDYZSHUoOh1CUGUyICevnTxs7VgEl98XpArmUWBZQVMfQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-darwin-arm64@2.6.0:
resolution: {integrity: sha512-MabUKLVayEwlPo0mIqAmMt+qESN8LltCvv5+GLgVga1avpUrkxj/fkU1TKm8kQegutUjbP/B0QuMuUr0uhF8ew==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-darwin-x64@2.6.0:
resolution: {integrity: sha512-zrFetdnSw/suXjmyxSjfDV7i61hahv6DDG6kM7BYN2yJ3Es5+BZtqYZTcIWogPJedYKmzN1YTMWGd/3f0ubFiA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-linux-arm-gnueabihf@2.6.0:
resolution: {integrity: sha512-sH4gxXt7v7dGwjGyzLwn7SFGvwZG6DQqLaZ11MmzbCwd9Zosy1TnmrMJfn6TJ7RHezmQMgBPi18bl55FZ1AT4A==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-linux-arm64-gnu@2.6.0:
resolution: {integrity: sha512-fCyMncqCJtrlANADIduYF4IfnWQ295UKib7DAxFXQhBsM9PLDTpizr0qemZcCNadcwSVHnAIzL4tliZhCM8P6A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-linux-arm64-musl@2.6.0:
resolution: {integrity: sha512-ouLjTgBQHQyxLht4FdMPTvuY8xzJigM9EM2Tlu0llWkN1mKyTQrvYWi6TA6XnKdzDJHy7ZLpWpjZi7F5+Pg+Vg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-linux-x64-gnu@2.6.0:
resolution: {integrity: sha512-n3zC8DWsvxC1AwxpKFclIPapDFibs5XdIRoV/mcIlxlh0vseW1F49b97F33BtJQRmlntsqqN6GMMqx8byB7B+Q==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-linux-x64-musl@2.6.0:
resolution: {integrity: sha512-n4tasK1HOlAxdTEROgYA1aCfsEKk0UOFDNd/AQTTZlTmCbHKXPq+O8npaaKlwXquxlVK8vrkcWbksbiGqbCAcw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-win32-arm64-msvc@2.6.0:
resolution: {integrity: sha512-X2+EoBJFwDI5LDVb51Sk7ldnVLitMGr9WwU/i21i3fAeAXZb3hM16k67DeTy16OYkT2dk/RfU1tP1wG+rWbz2Q==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-win32-ia32-msvc@2.6.0:
resolution: {integrity: sha512-L7oevWjQoUgK5W1fCKn0euSVemhDXVhrjtwqpc7MwBKKimYeiOshO1Li1pa8bBt5PESahenhWgdB6lav9O0fEg==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js-win32-x64-msvc@2.6.0:
resolution: {integrity: sha512-8lJlghb+Unki5AyKgsnFbRJwkEj9r1NpwyuBG8yEJiG1W9eEGl03R3I7bsVa3haof/3J1NlWf0rzSa1G++A2iw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/@resvg/resvg-js@2.6.0:
resolution: {integrity: sha512-Tf3YpbBKcQn991KKcw/vg7vZf98v01seSv6CVxZBbRkL/xyjnoYB6KgrFL6zskT1A4dWC/vg77KyNOW+ePaNlA==}
engines: {node: '>= 10'}
optionalDependencies:
'@resvg/resvg-js-android-arm-eabi': 2.6.0
'@resvg/resvg-js-android-arm64': 2.6.0
'@resvg/resvg-js-darwin-arm64': 2.6.0
'@resvg/resvg-js-darwin-x64': 2.6.0
'@resvg/resvg-js-linux-arm-gnueabihf': 2.6.0
'@resvg/resvg-js-linux-arm64-gnu': 2.6.0
'@resvg/resvg-js-linux-arm64-musl': 2.6.0
'@resvg/resvg-js-linux-x64-gnu': 2.6.0
'@resvg/resvg-js-linux-x64-musl': 2.6.0
'@resvg/resvg-js-win32-arm64-msvc': 2.6.0
'@resvg/resvg-js-win32-ia32-msvc': 2.6.0
'@resvg/resvg-js-win32-x64-msvc': 2.6.0
dev: false
/@rollup/pluginutils@4.2.1:
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
engines: {node: '>= 8.0.0'}
@ -834,12 +972,21 @@ packages:
dev: true
optional: true
/@sveltejs/adapter-vercel@4.0.4(@sveltejs/kit@2.3.2):
resolution: {integrity: sha512-2MMThT6eROTqAGmx81Xv+tafhpetQfRUDIsboFiGgkFoaxcmoTzW4t9GyXZdMY8xl1YOdvAnZXcCgacYzmVWVw==}
/@shuding/opentype.js@1.4.0-beta.0:
resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==}
engines: {node: '>= 8.0.0'}
hasBin: true
dependencies:
fflate: 0.7.4
string.prototype.codepointat: 0.2.1
dev: false
/@sveltejs/adapter-vercel@4.0.5(@sveltejs/kit@2.3.4):
resolution: {integrity: sha512-SABZvRry8pUggFrBLbIi88dCH5gP3M0O/8HvvLjOTCwTVn3E8H1ppJ8ujhj8xNuoi4rm9JVy6qYSYp2EsgOugw==}
peerDependencies:
'@sveltejs/kit': ^2.0.0
dependencies:
'@sveltejs/kit': 2.3.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.8)(vite@5.0.11)
'@sveltejs/kit': 2.3.4(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.11)
'@vercel/nft': 0.26.2
esbuild: 0.19.11
transitivePeerDependencies:
@ -847,19 +994,19 @@ packages:
- supports-color
dev: true
/@sveltejs/enhanced-img@0.1.8(svelte@4.2.8):
/@sveltejs/enhanced-img@0.1.8(svelte@4.2.9):
resolution: {integrity: sha512-0cLVR9KiO0/t3VVm64OM7bPHTkdaT2aaz1rwoAhao+EBXR3vMvLoYXLHvz8o9/552PSV8G844RkH7qkGc3YAiQ==}
dependencies:
magic-string: 0.30.5
svelte-parse-markup: 0.1.2(svelte@4.2.8)
svelte-parse-markup: 0.1.2(svelte@4.2.9)
vite-imagetools: 6.2.9
transitivePeerDependencies:
- rollup
- svelte
dev: true
/@sveltejs/kit@2.3.2(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.8)(vite@5.0.11):
resolution: {integrity: sha512-AzGWV1TyUSkBuciy06E5NegXndIEgTthDtllv80qynEJFh8bZD62ZxLajiQLOsKGqRDilEQyshDARQxjIqiaqg==}
/@sveltejs/kit@2.3.4(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.11):
resolution: {integrity: sha512-Q4rXMMLSv38IeiVJhA3M0M0t6M8zNXsjj2xhUkWlxhkKu+cRqOL/vyFTuJ+5aiQlmMzCGq1yqFnHoc6R0NZ7gQ==}
engines: {node: '>=18.13'}
hasBin: true
requiresBuild: true
@ -868,7 +1015,7 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.3
dependencies:
'@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.8)(vite@5.0.11)
'@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.9)(vite@5.0.11)
'@types/cookie': 0.6.0
cookie: 0.6.0
devalue: 4.3.2
@ -880,12 +1027,12 @@ packages:
sade: 1.8.1
set-cookie-parser: 2.6.0
sirv: 2.0.4
svelte: 4.2.8
svelte: 4.2.9
tiny-glob: 0.2.9
vite: 5.0.11
vite: 5.0.11(@types/node@20.11.5)
dev: true
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.8)(vite@5.0.11):
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.11):
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
@ -893,29 +1040,29 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
dependencies:
'@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.8)(vite@5.0.11)
'@sveltejs/vite-plugin-svelte': 3.0.1(svelte@4.2.9)(vite@5.0.11)
debug: 4.3.4
svelte: 4.2.8
vite: 5.0.11
svelte: 4.2.9
vite: 5.0.11(@types/node@20.11.5)
transitivePeerDependencies:
- supports-color
dev: true
/@sveltejs/vite-plugin-svelte@3.0.1(svelte@4.2.8)(vite@5.0.11):
/@sveltejs/vite-plugin-svelte@3.0.1(svelte@4.2.9)(vite@5.0.11):
resolution: {integrity: sha512-CGURX6Ps+TkOovK6xV+Y2rn8JKa8ZPUHPZ/NKgCxAmgBrXReavzFl8aOSCj3kQ1xqT7yGJj53hjcV/gqwDAaWA==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
dependencies:
'@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.8)(vite@5.0.11)
'@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.1)(svelte@4.2.9)(vite@5.0.11)
debug: 4.3.4
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.5
svelte: 4.2.8
svelte-hmr: 0.15.3(svelte@4.2.8)
vite: 5.0.11
svelte: 4.2.9
svelte-hmr: 0.15.3(svelte@4.2.9)
vite: 5.0.11(@types/node@20.11.5)
vitefu: 0.2.5(vite@5.0.11)
transitivePeerDependencies:
- supports-color
@ -938,6 +1085,11 @@ packages:
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
dev: true
/@types/node@20.11.5:
resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==}
dependencies:
undici-types: 5.26.5
/@types/pug@2.0.10:
resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==}
dev: true
@ -946,8 +1098,8 @@ packages:
resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==}
dev: true
/@typescript-eslint/eslint-plugin@6.18.1(@typescript-eslint/parser@6.18.1)(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==}
/@typescript-eslint/eslint-plugin@6.19.0(@typescript-eslint/parser@6.19.0)(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
'@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
@ -958,11 +1110,11 @@ packages:
optional: true
dependencies:
'@eslint-community/regexpp': 4.10.0
'@typescript-eslint/parser': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/scope-manager': 6.18.1
'@typescript-eslint/type-utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.18.1
'@typescript-eslint/parser': 6.19.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/scope-manager': 6.19.0
'@typescript-eslint/type-utils': 6.19.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/utils': 6.19.0(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.19.0
debug: 4.3.4
eslint: 8.56.0
graphemer: 1.4.0
@ -975,8 +1127,8 @@ packages:
- supports-color
dev: true
/@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==}
/@typescript-eslint/parser@6.19.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-1DyBLG5SH7PYCd00QlroiW60YJ4rWMuUGa/JBV0iZuqi4l4IK3twKPq5ZkEebmGqRjXWVgsUzfd3+nZveewgow==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
@ -985,10 +1137,10 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 6.18.1
'@typescript-eslint/types': 6.18.1
'@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.18.1
'@typescript-eslint/scope-manager': 6.19.0
'@typescript-eslint/types': 6.19.0
'@typescript-eslint/typescript-estree': 6.19.0(typescript@5.3.3)
'@typescript-eslint/visitor-keys': 6.19.0
debug: 4.3.4
eslint: 8.56.0
typescript: 5.3.3
@ -996,16 +1148,16 @@ packages:
- supports-color
dev: true
/@typescript-eslint/scope-manager@6.18.1:
resolution: {integrity: sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==}
/@typescript-eslint/scope-manager@6.19.0:
resolution: {integrity: sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.18.1
'@typescript-eslint/visitor-keys': 6.18.1
'@typescript-eslint/types': 6.19.0
'@typescript-eslint/visitor-keys': 6.19.0
dev: true
/@typescript-eslint/type-utils@6.18.1(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==}
/@typescript-eslint/type-utils@6.19.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
@ -1014,8 +1166,8 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
'@typescript-eslint/utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
'@typescript-eslint/typescript-estree': 6.19.0(typescript@5.3.3)
'@typescript-eslint/utils': 6.19.0(eslint@8.56.0)(typescript@5.3.3)
debug: 4.3.4
eslint: 8.56.0
ts-api-utils: 1.0.3(typescript@5.3.3)
@ -1024,13 +1176,13 @@ packages:
- supports-color
dev: true
/@typescript-eslint/types@6.18.1:
resolution: {integrity: sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==}
/@typescript-eslint/types@6.19.0:
resolution: {integrity: sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==}
engines: {node: ^16.0.0 || >=18.0.0}
dev: true
/@typescript-eslint/typescript-estree@6.18.1(typescript@5.3.3):
resolution: {integrity: sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==}
/@typescript-eslint/typescript-estree@6.19.0(typescript@5.3.3):
resolution: {integrity: sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
typescript: '*'
@ -1038,8 +1190,8 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 6.18.1
'@typescript-eslint/visitor-keys': 6.18.1
'@typescript-eslint/types': 6.19.0
'@typescript-eslint/visitor-keys': 6.19.0
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
@ -1051,8 +1203,8 @@ packages:
- supports-color
dev: true
/@typescript-eslint/utils@6.18.1(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==}
/@typescript-eslint/utils@6.19.0(eslint@8.56.0)(typescript@5.3.3):
resolution: {integrity: sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==}
engines: {node: ^16.0.0 || >=18.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
@ -1060,9 +1212,9 @@ packages:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.56.0)
'@types/json-schema': 7.0.15
'@types/semver': 7.5.6
'@typescript-eslint/scope-manager': 6.18.1
'@typescript-eslint/types': 6.18.1
'@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
'@typescript-eslint/scope-manager': 6.19.0
'@typescript-eslint/types': 6.19.0
'@typescript-eslint/typescript-estree': 6.19.0(typescript@5.3.3)
eslint: 8.56.0
semver: 7.5.4
transitivePeerDependencies:
@ -1070,11 +1222,11 @@ packages:
- typescript
dev: true
/@typescript-eslint/visitor-keys@6.18.1:
resolution: {integrity: sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==}
/@typescript-eslint/visitor-keys@6.19.0:
resolution: {integrity: sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==}
engines: {node: ^16.0.0 || >=18.0.0}
dependencies:
'@typescript-eslint/types': 6.18.1
'@typescript-eslint/types': 6.19.0
eslint-visitor-keys: 3.4.3
dev: true
@ -1110,8 +1262,8 @@ packages:
- supports-color
dev: true
/@vercel/speed-insights@1.0.3:
resolution: {integrity: sha512-bKIt0HDdF6hP2bJZyS+za3k6sKeAXNRLSIUbwVwvyvKdsHBWS6ILBvmD1wXHZZyTqjU1TP7dTE/F6lHM6rBdKA==}
/@vercel/speed-insights@1.0.4:
resolution: {integrity: sha512-Q7O0bnV11KUqNKAKA984YWIGxCjqgOuJdwH1cdItqlkUVTLbIm8BhObro6hJobGMSUHm+z7xjQ0YbC8ps1ekDg==}
requiresBuild: true
dev: false
@ -1226,15 +1378,15 @@ packages:
resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==}
dev: true
/autoprefixer@10.4.16(postcss@8.4.33):
resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==}
/autoprefixer@10.4.17(postcss@8.4.33):
resolution: {integrity: sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
dependencies:
browserslist: 4.22.2
caniuse-lite: 1.0.30001576
caniuse-lite: 1.0.30001578
fraction.js: 4.3.7
normalize-range: 0.1.2
picocolors: 1.0.0
@ -1242,14 +1394,19 @@ packages:
postcss-value-parser: 4.2.0
dev: true
/axobject-query@3.2.1:
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
/axobject-query@4.0.0:
resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==}
dependencies:
dequal: 2.0.3
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
/base64-js@0.0.8:
resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==}
engines: {node: '>= 0.4'}
dev: false
/binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
@ -1260,15 +1417,15 @@ packages:
file-uri-to-path: 1.0.0
dev: true
/bits-ui@0.14.0(svelte@4.2.8):
/bits-ui@0.14.0(svelte@4.2.9):
resolution: {integrity: sha512-S1LNwp/Sge1Ro1g0iJ+msIUeJYmoNhXBFShnLDOUOKQe3JG1wd027KxZnVd7db6UWr1IqlJdd4/bbB7NYXeYDw==}
peerDependencies:
svelte: ^4.0.0
dependencies:
'@internationalized/date': 3.5.1
'@melt-ui/svelte': 0.68.0(svelte@4.2.8)
'@melt-ui/svelte': 0.68.0(svelte@4.2.9)
nanoid: 5.0.4
svelte: 4.2.8
svelte: 4.2.9
dev: false
/brace-expansion@1.1.11:
@ -1294,8 +1451,8 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
caniuse-lite: 1.0.30001576
electron-to-chromium: 1.4.630
caniuse-lite: 1.0.30001578
electron-to-chromium: 1.4.637
node-releases: 2.0.14
update-browserslist-db: 1.0.13(browserslist@4.22.2)
dev: true
@ -1313,8 +1470,12 @@ packages:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
/caniuse-lite@1.0.30001576:
resolution: {integrity: sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==}
/camelize@1.0.1:
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
dev: false
/caniuse-lite@1.0.30001578:
resolution: {integrity: sha512-J/jkFgsQ3NEl4w2lCoM9ZPxrD+FoBNJ7uJUpGVjIg/j0OwJosWM36EPDv+Yyi0V4twBk9pPmlFS+PLykgEvUmg==}
dev: true
/chalk@4.1.2:
@ -1441,6 +1602,27 @@ packages:
shebang-command: 2.0.0
which: 2.0.2
/css-background-parser@0.1.0:
resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==}
dev: false
/css-box-shadow@1.0.0-3:
resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==}
dev: false
/css-color-keywords@1.0.0:
resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==}
engines: {node: '>=4'}
dev: false
/css-to-react-native@3.2.0:
resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==}
dependencies:
camelize: 1.0.1
css-color-keywords: 1.0.0
postcss-value-parser: 4.2.0
dev: false
/css-tree@2.3.1:
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
@ -1519,13 +1701,12 @@ packages:
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
/electron-to-chromium@1.4.630:
resolution: {integrity: sha512-osHqhtjojpCsACVnuD11xO5g9xaCyw7Qqn/C2KParkMv42i8jrJJgx3g7mkHfpxwhy9MnOJr8+pKOdZ7qzgizg==}
/electron-to-chromium@1.4.637:
resolution: {integrity: sha512-G7j3UCOukFtxVO1vWrPQUoDk3kL70mtvjc/DC/k2o7lE0wAdq+Vwp1ipagOow+BH0uVztFysLWbkM/RTIrbK3w==}
dev: true
/emoji-regex@10.3.0:
resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==}
dev: true
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@ -1573,6 +1754,10 @@ packages:
engines: {node: '>=6'}
dev: true
/escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
dev: false
/escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
@ -1596,7 +1781,7 @@ packages:
eslint: 8.56.0
dev: true
/eslint-plugin-svelte@2.35.1(eslint@8.56.0)(svelte@4.2.8):
/eslint-plugin-svelte@2.35.1(eslint@8.56.0)(svelte@4.2.9):
resolution: {integrity: sha512-IF8TpLnROSGy98Z3NrsKXWDSCbNY2ReHDcrYTuXZMbfX7VmESISR78TWgO9zdg4Dht1X8coub5jKwHzP0ExRug==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
@ -1618,8 +1803,8 @@ packages:
postcss-safe-parser: 6.0.0(postcss@8.4.33)
postcss-selector-parser: 6.0.15
semver: 7.5.4
svelte: 4.2.8
svelte-eslint-parser: 0.33.1(svelte@4.2.8)
svelte: 4.2.9
svelte-eslint-parser: 0.33.1(svelte@4.2.9)
transitivePeerDependencies:
- supports-color
- ts-node
@ -1777,6 +1962,10 @@ packages:
dependencies:
reusify: 1.0.4
/fflate@0.7.4:
resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==}
dev: false
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -1962,6 +2151,11 @@ packages:
dependencies:
function-bind: 1.1.2
/hex-rgb@4.3.0:
resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==}
engines: {node: '>=6'}
dev: false
/https-proxy-agent@5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
@ -2142,6 +2336,13 @@ packages:
resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==}
engines: {node: '>=14'}
/linebreak@1.1.0:
resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==}
dependencies:
base64-js: 0.0.8
unicode-trie: 2.0.0
dev: false
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@ -2217,7 +2418,7 @@ packages:
peerDependencies:
svelte: '>=3 <5'
dependencies:
svelte: 4.2.8
svelte: 4.2.9
dev: false
/magic-string@0.30.5:
@ -2319,12 +2520,12 @@ packages:
hasBin: true
dev: true
/mode-watcher@0.1.2(svelte@4.2.8):
/mode-watcher@0.1.2(svelte@4.2.9):
resolution: {integrity: sha512-XTdPCdqC3kqSvB+Q262Kor983YJkkB2Z3vj9uqg5IqKQpOdiz+xB99Jihp8sWbyM67drC7KKp0Nt5FzCypZi2g==}
peerDependencies:
svelte: ^4.0.0
dependencies:
svelte: 4.2.8
svelte: 4.2.9
dev: false
/mri@1.2.0:
@ -2471,6 +2672,10 @@ packages:
p-limit: 3.1.0
dev: true
/pako@0.2.9:
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
dev: false
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@ -2478,6 +2683,13 @@ packages:
callsites: 3.1.0
dev: true
/parse-css-color@0.2.1:
resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==}
dependencies:
color-name: 1.1.4
hex-rgb: 4.3.0
dev: false
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -2660,17 +2872,17 @@ packages:
engines: {node: '>= 0.8.0'}
dev: true
/prettier-plugin-svelte@3.1.2(prettier@3.2.2)(svelte@4.2.8):
/prettier-plugin-svelte@3.1.2(prettier@3.2.4)(svelte@4.2.9):
resolution: {integrity: sha512-7xfMZtwgAWHMT0iZc8jN4o65zgbAQ3+O32V6W7pXrqNvKnHnkoyQCGCbKeUyXKZLbYE0YhFRnamfxfkEGxm8qA==}
peerDependencies:
prettier: ^3.0.0
svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0
dependencies:
prettier: 3.2.2
svelte: 4.2.8
prettier: 3.2.4
svelte: 4.2.9
dev: true
/prettier-plugin-tailwindcss@0.5.11(prettier-plugin-svelte@3.1.2)(prettier@3.2.2):
/prettier-plugin-tailwindcss@0.5.11(prettier-plugin-svelte@3.1.2)(prettier@3.2.4):
resolution: {integrity: sha512-AvI/DNyMctyyxGOjyePgi/gqj5hJYClZ1avtQvLlqMT3uDZkRbi4HhGUpok3DRzv9z7Lti85Kdj3s3/1CeNI0w==}
engines: {node: '>=14.21.3'}
peerDependencies:
@ -2719,12 +2931,12 @@ packages:
prettier-plugin-twig-melody:
optional: true
dependencies:
prettier: 3.2.2
prettier-plugin-svelte: 3.1.2(prettier@3.2.2)(svelte@4.2.8)
prettier: 3.2.4
prettier-plugin-svelte: 3.1.2(prettier@3.2.4)(svelte@4.2.9)
dev: true
/prettier@3.2.2:
resolution: {integrity: sha512-HTByuKZzw7utPiDO523Tt2pLtEyK7OibUD9suEJQrPUCYQqrHr74GGX6VidMrovbf/I50mPqr8j/II6oBAuc5A==}
/prettier@3.2.4:
resolution: {integrity: sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==}
engines: {node: '>=14'}
hasBin: true
dev: true
@ -2861,6 +3073,28 @@ packages:
rimraf: 2.7.1
dev: true
/satori-html@0.3.2:
resolution: {integrity: sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==}
dependencies:
ultrahtml: 1.5.2
dev: false
/satori@0.10.11:
resolution: {integrity: sha512-yLm1xPRPZUaKcBZJ6nmezoJjHB4MqV8x7Mu0PyZUJodRWRDD27UbeMwzuY9LEGG57WYLO4CQsGPlbHWV1Ex9TQ==}
engines: {node: '>=16'}
dependencies:
'@shuding/opentype.js': 1.4.0-beta.0
css-background-parser: 0.1.0
css-box-shadow: 1.0.0-3
css-to-react-native: 3.2.0
emoji-regex: 10.3.0
escape-html: 1.0.3
linebreak: 1.1.0
parse-css-color: 0.2.1
postcss-value-parser: 4.2.0
yoga-wasm-web: 0.3.3
dev: false
/semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true
@ -3014,6 +3248,10 @@ packages:
strip-ansi: 7.1.0
dev: true
/string.prototype.codepointat@0.2.1:
resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==}
dev: false
/string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
@ -3073,7 +3311,7 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
/svelte-check@3.6.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.8):
/svelte-check@3.6.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9):
resolution: {integrity: sha512-Q2nGnoysxUnB9KjnjpQLZwdjK62DHyW6nuH/gm2qteFnDk0lCehe/6z8TsIvYeKjC6luKaWxiNGyOcWiLLPSwA==}
hasBin: true
peerDependencies:
@ -3085,8 +3323,8 @@ packages:
import-fresh: 3.3.0
picocolors: 1.0.0
sade: 1.8.1
svelte: 4.2.8
svelte-preprocess: 5.1.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.8)(typescript@5.3.3)
svelte: 4.2.9
svelte-preprocess: 5.1.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9)(typescript@5.3.3)
typescript: 5.3.3
transitivePeerDependencies:
- '@babel/core'
@ -3100,7 +3338,7 @@ packages:
- sugarss
dev: true
/svelte-eslint-parser@0.33.1(svelte@4.2.8):
/svelte-eslint-parser@0.33.1(svelte@4.2.9):
resolution: {integrity: sha512-vo7xPGTlKBGdLH8T5L64FipvTrqv3OQRx9d2z5X05KKZDlF4rQk8KViZO4flKERY+5BiVdOh7zZ7JGJWo5P0uA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@ -3114,27 +3352,27 @@ packages:
espree: 9.6.1
postcss: 8.4.33
postcss-scss: 4.0.9(postcss@8.4.33)
svelte: 4.2.8
svelte: 4.2.9
dev: true
/svelte-hmr@0.15.3(svelte@4.2.8):
/svelte-hmr@0.15.3(svelte@4.2.9):
resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==}
engines: {node: ^12.20 || ^14.13.1 || >= 16}
peerDependencies:
svelte: ^3.19.0 || ^4.0.0
dependencies:
svelte: 4.2.8
svelte: 4.2.9
dev: true
/svelte-parse-markup@0.1.2(svelte@4.2.8):
/svelte-parse-markup@0.1.2(svelte@4.2.9):
resolution: {integrity: sha512-DycY7DJr7VqofiJ63ut1/NEG92HrWWL56VWITn/cJCu+LlZhMoBkBXT4opUitPEEwbq1nMQbv4vTKUfbOqIW1g==}
peerDependencies:
svelte: ^3.0.0 || ^4.0.0
dependencies:
svelte: 4.2.8
svelte: 4.2.9
dev: true
/svelte-preprocess@5.1.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.8)(typescript@5.3.3):
/svelte-preprocess@5.1.3(postcss-load-config@5.0.2)(postcss@8.4.33)(svelte@4.2.9)(typescript@5.3.3):
resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==}
engines: {node: '>= 16.0.0', pnpm: ^8.0.0}
requiresBuild: true
@ -3179,7 +3417,7 @@ packages:
postcss-load-config: 5.0.2(postcss@8.4.33)
sorcery: 0.11.0
strip-indent: 3.0.0
svelte: 4.2.8
svelte: 4.2.9
typescript: 5.3.3
dev: true
@ -3187,16 +3425,17 @@ packages:
resolution: {integrity: sha512-o+WbHrl426YLDUMgNWJ0yKImmecZ6rFI6WFsrMx7YgsgdaZjtJX0d373TbJ35lzeBqsnMvjdRptl12qE0Mbe9w==}
dev: false
/svelte@4.2.8:
resolution: {integrity: sha512-hU6dh1MPl8gh6klQZwK/n73GiAHiR95IkFsesLPbMeEZi36ydaXL/ZAb4g9sayT0MXzpxyZjR28yderJHxcmYA==}
/svelte@4.2.9:
resolution: {integrity: sha512-hsoB/WZGEPFXeRRLPhPrbRz67PhP6sqYgvwcAs+gWdSQSvNDw+/lTeUJSWe5h2xC97Fz/8QxAOqItwBzNJPU8w==}
engines: {node: '>=16'}
dependencies:
'@ampproject/remapping': 2.2.1
'@jridgewell/sourcemap-codec': 1.4.15
'@jridgewell/trace-mapping': 0.3.21
'@types/estree': 1.0.5
acorn: 8.11.3
aria-query: 5.3.0
axobject-query: 3.2.1
axobject-query: 4.0.0
code-red: 1.0.4
css-tree: 2.3.1
estree-walker: 3.0.3
@ -3293,6 +3532,10 @@ packages:
globrex: 0.1.2
dev: true
/tiny-inflate@1.0.3:
resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==}
dev: false
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@ -3346,6 +3589,20 @@ packages:
hasBin: true
dev: true
/ultrahtml@1.5.2:
resolution: {integrity: sha512-qh4mBffhlkiXwDAOxvSGxhL0QEQsTbnP9BozOK3OYPEGvPvdWzvAUaXNtUSMdNsKDtuyjEbyVUPFZ52SSLhLqw==}
dev: false
/undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
/unicode-trie@2.0.0:
resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==}
dependencies:
pako: 0.2.9
tiny-inflate: 1.0.3
dev: false
/update-browserslist-db@1.0.13(browserslist@4.22.2):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
hasBin: true
@ -3376,7 +3633,7 @@ packages:
- rollup
dev: true
/vite@5.0.11:
/vite@5.0.11(@types/node@20.11.5):
resolution: {integrity: sha512-XBMnDjZcNAw/G1gEiskiM1v6yzM4GE5aMGvhWTlHAYYhxb7S3/V1s3m2LDHa8Vh6yIWYYB0iJwsEaS523c4oYA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@ -3404,6 +3661,7 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 20.11.5
esbuild: 0.19.11
postcss: 8.4.33
rollup: 4.9.5
@ -3419,7 +3677,7 @@ packages:
vite:
optional: true
dependencies:
vite: 5.0.11
vite: 5.0.11(@types/node@20.11.5)
dev: true
/webidl-conversions@3.0.1:
@ -3492,3 +3750,7 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
/yoga-wasm-web@0.3.3:
resolution: {integrity: sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA==}
dev: false

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View file

@ -0,0 +1,57 @@
<script lang="ts">
import { onMount } from 'svelte';
export let images: { src: string; alt: string; style?: string }[] = [];
let index = 0;
/* global NodeJS */
let interval: string | number | NodeJS.Timeout | undefined;
const start = () => (interval = setInterval(() => (index = (index + 1) % images.length), 8000));
const stop = () => clearInterval(interval);
onMount(() => {
start();
return () => stop();
});
function handleMarkerClick(i: number) {
stop();
index = i;
}
</script>
<div class="relative h-[500px]">
{#each images as img, i}
<enhanced:img
src={img.src}
alt={img.alt}
class:current-img={index === i}
class="absolute inset-0 h-full w-full rounded-xl object-cover opacity-0 transition-opacity duration-1000 ease-out {img.style}"
/>
{/each}
<div class="absolute bottom-[5%] left-[50%] grid translate-x-[-50%] grid-flow-col gap-2">
{#each images as _, i (_.src)}
<button on:click={() => handleMarkerClick(i)} aria-label="select image">
<svg height="20" width="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<circle
cx="8"
cy="8"
r="8"
class:current-marker={index === i}
class="transition-fill fill-gray-500 duration-500 ease-out"
/>
</svg>
</button>
{/each}
</div>
</div>
<style>
.current-img {
opacity: 1;
}
.current-marker {
fill: white;
}
</style>

View file

@ -1,33 +0,0 @@
<script>
import { onMount } from 'svelte';
import catImg from '$lib/assets/root-cat.jpg?enhanced';
import meImg from '$lib/assets/root-me.jpg?enhanced';
const images = [
{ src: meImg, alt: 'Portrait of Bart van der Braak', style: 'object-[50%_10%]' },
{ src: catImg, alt: 'Noire yawning cat and a bottle of whiskey with glass', style: '' }
];
let currentIndex = 0;
let currentImage = images[currentIndex];
onMount(() => {
const interval = setInterval(() => {
currentIndex = (currentIndex + 1) % images.length;
currentImage = images[currentIndex];
}, 15000);
return () => clearInterval(interval);
});
</script>
<div class="relative h-full min-h-96 w-full md:min-h-44">
{#each images as image}
<enhanced:img
src={image.src}
alt={image.alt}
class="absolute left-0 top-0 h-full w-full rounded-xl object-cover transition-opacity duration-1000 {image.style}"
style:opacity={image === currentImage ? 1 : 0}
/>
{/each}
</div>

View file

@ -1,9 +1,11 @@
export { default as Metadata } from './metadata.svelte';
export { default as SiteFooter } from './site-footer.svelte';
export { default as SiteNavBar } from './site-navbar.svelte';
export { default as SiteHeader } from './site-header.svelte';
export { default as TailwindIndicator } from './tailwind-indicator.svelte';
export { default as ModeToggle } from './mode-toggle.svelte';
export { default as ImageFade } from './image-fade.svelte';
export { default as ImageFadeCarousel } from './image-fade-carousel.svelte';
export { default as OgImage } from './opengraph-image.svelte';
export * from './icons';
export * from './nav';

View file

@ -4,29 +4,33 @@
export let title: string = siteConfig.name;
$: title = $page.data?.title ? `${$page.data.title} — ${siteConfig.name}` : siteConfig.name;
$: title = $page.data?.name ? `${$page.data.name} — ${siteConfig.name}` : siteConfig.name;
$: description = $page.data?.subTitle ?? siteConfig.description;
$: ogImage = encodeURI(
`${siteConfig.ogImage}?title=${$page.data.title}&subTitle=${$page.data.subTitle}`
);
</script>
<svelte:head>
<title>{title}</title>
<meta name="description" content={siteConfig.description} />
<meta name="description" content={description} />
<meta name="keywords" content={siteConfig.keywords} />
<meta name="author" content="Bart van der Braak" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content={siteConfig.url} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={siteConfig.description} />
<meta name="twitter:image" content={siteConfig.ogImage} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={ogImage} />
<meta name="twitter:image:alt" content={siteConfig.name} />
<meta name="twitter:creator" content="Bart van der Braak" />
<meta property="og:title" content={title} />
<meta property="og:type" content="article" />
<meta property="og:url" content={siteConfig.url + $page.url.pathname} />
<meta property="og:image" content={siteConfig.ogImage} />
<meta property="og:image" content={ogImage} />
<meta property="og:image:alt" content={siteConfig.name} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:description" content={siteConfig.description} />
<meta property="og:description" content={description} />
<meta property="og:site_name" content={siteConfig.name} />
<meta property="og:locale" content="EN_US" />
</svelte:head>

View file

@ -0,0 +1,32 @@
<script lang="ts">
import { Icons } from '.';
export let title: string = 'I made this for you';
export let subTitle: string =
'Featuring current work and studies in a SvelteKit-based portfolio.';
export let imageData: string = '';
</script>
<div class="flex h-full w-full items-center justify-center bg-black px-24">
<div class="flex flex-row items-center rounded-lg shadow-md">
<div class="flex w-7/12 flex-col">
<Icons.logo />
<h2 class="mb-0 text-6xl font-bold leading-tight tracking-tighter text-white">{title}</h2>
<p class="mt-0 text-3xl font-thin text-gray-400">
{subTitle}
</p>
</div>
<div class="mb--50 mt-0 flex w-5/12">
<img class="rounded-xl" src={`data:image/jpeg;base64,${imageData}`} width={400} alt="" />
</div>
</div>
</div>
<style>
h2 {
font-family: 'Geist Bold', 'Geist Sans';
}
p {
font-family: 'Geist Regular', 'Geist Sans';
}
</style>

View file

@ -1,52 +1,12 @@
<script lang="ts">
import { Icons, ModeToggle, MainNav, MobileNav } from '$lib/components/site';
import { siteConfig } from '$lib/config/site';
import { cn } from '$lib/utils';
import { buttonVariants } from '../ui/button';
import * as PageHeader from './page-header';
export let title: string, subTitle: string;
</script>
<header
class="sticky top-0 z-50 w-full border-b bg-background/95 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/60"
>
<div class="container flex h-14 items-center">
<a href="/" class="mr-6 flex items-center space-x-2">
<span class="sr-only">Logo (return home)</span>
<Icons.logo />
</a>
<MainNav />
<div class="flex flex-1 items-center justify-between space-x-2 sm:space-x-4 md:justify-end">
<nav class="flex">
<a href={siteConfig.links.gitHubProfile} target="_blank" rel="noopener noreferrer">
<div
class={cn(
buttonVariants({
size: 'sm',
variant: 'ghost'
}),
'h-9 w-9 px-0'
)}
>
<Icons.gitHub class="h-4 w-4" />
<span class="sr-only">GitHub</span>
</div>
</a>
<a href={siteConfig.links.linkedIn} target="_blank" rel="noreferrer">
<div
class={cn(
buttonVariants({
size: 'sm',
variant: 'ghost'
}),
'h-9 w-9 px-0'
)}
>
<Icons.linkedIn class="h-4 w-4" />
<span class="sr-only">LinkedIn</span>
</div>
</a>
<ModeToggle />
</nav>
</div>
<MobileNav />
</div>
</header>
<PageHeader.Root class="pb-8">
<PageHeader.Heading>{title}</PageHeader.Heading>
<PageHeader.Description>
{subTitle}
</PageHeader.Description>
<slot />
</PageHeader.Root>

View file

@ -0,0 +1,52 @@
<script lang="ts">
import { Icons, ModeToggle, MainNav, MobileNav } from '$lib/components/site';
import { siteConfig } from '$lib/config/site';
import { cn } from '$lib/utils';
import { buttonVariants } from '../ui/button';
</script>
<header
class="sticky top-0 z-50 w-full border-b bg-background/95 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/60"
>
<div class="container flex h-14 items-center">
<a href="/" class="mr-6 flex items-center space-x-2">
<span class="sr-only">Logo (return home)</span>
<Icons.logo />
</a>
<MainNav />
<div class="flex flex-1 items-center justify-between space-x-2 sm:space-x-4 md:justify-end">
<nav class="flex">
<a href={siteConfig.links.gitHubProfile} target="_blank" rel="noopener noreferrer">
<div
class={cn(
buttonVariants({
size: 'sm',
variant: 'ghost'
}),
'h-9 w-9 px-0'
)}
>
<Icons.gitHub class="h-4 w-4" />
<span class="sr-only">GitHub</span>
</div>
</a>
<a href={siteConfig.links.linkedIn} target="_blank" rel="noreferrer">
<div
class={cn(
buttonVariants({
size: 'sm',
variant: 'ghost'
}),
'h-9 w-9 px-0'
)}
>
<Icons.linkedIn class="h-4 w-4" />
<span class="sr-only">LinkedIn</span>
</div>
</a>
<ModeToggle />
</nav>
</div>
<MobileNav />
</div>
</header>

View file

@ -1,8 +1,8 @@
export const siteConfig = {
name: 'hellob.art',
author: 'Bart van der Braak',
url: 'https://hellob.art',
ogImage: 'https://hellob.art/og.png',
url: import.meta.env.VERCEL_URL,
ogImage: `https://${import.meta.env.VERCEL_URL}/og.png`,
description: 'Personal website of Bart van der Braak, DevOps/Platform Engineer at Triple.',
links: {
twitter: 'https://twitter.com/bartvdbraak',

View file

@ -1,23 +1,23 @@
<script lang="ts">
import { page } from '$app/stores';
import * as PageHeader from '$lib/components/site/page-header';
import { buttonVariants } from '$lib/components/ui/button';
import { cn } from '$lib/utils';
import johnTravoltaGif from '$lib/assets/john-travolta.gif';
import { page } from '$app/stores';
import { SiteHeader } from '$lib/components/site';
</script>
<div class="container relative max-w-[980px] pb-10">
<PageHeader.Root>
<PageHeader.Heading>{$page.error?.message}</PageHeader.Heading>
<PageHeader.Description>This page is not available.</PageHeader.Description>
<p class="text-sm text-orange-700 dark:text-orange-400">
You can try going back to the home page.
</p>
<div class="flex w-full items-center justify-center space-x-4 py-4">
<a href="/" class={cn(buttonVariants())}> Return Home </a>
</div>
</PageHeader.Root>
<section class="flex">
<img src={johnTravoltaGif} alt="John travolta unable to find your page" class="mx-auto w-1/2" />
</section>
</div>
<SiteHeader
title={`${$page.error?.message}`}
subTitle={`This page is currently unavailable. Please try again later.`}
>
<p class="text-sm text-orange-700 dark:text-orange-400">
You can try going back to the home page.
</p>
<div class="flex w-full items-center justify-center space-x-4 py-4">
<a href="/" class={cn(buttonVariants())}> Return Home </a>
</div>
</SiteHeader>
<section class="flex">
<img src={johnTravoltaGif} alt="John travolta unable to find your page" class="mx-auto w-1/2" />
</section>

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { dev } from '$app/environment';
import { Metadata, SiteFooter, SiteHeader, TailwindIndicator } from '$lib/components/site';
import { Metadata, SiteFooter, SiteNavBar, TailwindIndicator } from '$lib/components/site';
import '../styles/globals.css';
import { ModeWatcher } from 'mode-watcher';
import { fly } from 'svelte/transition';
@ -17,10 +17,10 @@
<Metadata />
<div class="relative flex min-h-screen flex-col" id="page">
<SiteHeader />
<main class="mb-4 flex-1">
<SiteNavBar />
<main class="container relative mb-4 max-w-[980px] flex-1">
{#key data.url}
<div in:fly={{ x: -200, duration: 200, delay: 200 }} out:fly={{ x: 200, duration: 200 }}>
<div in:fly={{ x: -200, duration: 200, delay: 100 }} out:fly={{ x: 200, duration: 100 }}>
<slot />
</div>
{/key}

View file

@ -1,81 +1,85 @@
<script lang="ts">
import * as PageHeader from '$lib/components/site/page-header';
import { ImageFade } from '$lib/components/site';
import { Icons } from '$lib/components/site/icons';
import { page } from '$app/stores';
import { Icons, ImageFadeCarousel, SiteHeader } from '$lib/components/site';
import { buttonVariants } from '$lib/components/ui/button';
import { siteConfig } from '$lib/config/site';
import { cn } from '$lib/utils';
import catImg from '$lib/assets/root-cat.jpg?enhanced';
import meImg from '$lib/assets/root-me.jpg?enhanced';
const images = [
{ src: meImg, alt: 'Portrait of Bart van der Braak', style: 'object-[50%_10%]' },
{ src: catImg, alt: 'Noire yawning cat and a bottle of whiskey with glass', style: '' }
];
$: title = $page.data.title;
$: subTitle = $page.data.subTitle;
</script>
<div class="container relative max-w-[980px] pb-10">
<PageHeader.Root class="pb-8">
<PageHeader.Heading>I made this for you</PageHeader.Heading>
<PageHeader.Description>
Featuring current work and studies in a SvelteKit-based portfolio.
</PageHeader.Description>
<p class="text-center text-sm text-green-700 dark:text-green-400">
Inspired by others, I share my open-source derived work with the community.
</p>
<div class="flex w-full items-center justify-center space-x-4 py-4 md:pb-10">
<a href="/projects" class={cn(buttonVariants())}> My Projects </a>
<a
target="_blank"
rel="noreferrer"
href={siteConfig.links.gitHubProfile}
class={cn(buttonVariants({ variant: 'outline' }))}
>
<Icons.gitHub class="mr-2 h-4 w-4" />
GitHub
</a>
</div>
</PageHeader.Root>
<section class="flex">
<div class="border-grey/15 relative border-y pb-16 pt-10 dark:border-white/20">
<SiteHeader {title} {subTitle}>
<p class="text-center text-sm text-green-700 dark:text-green-400">
Inspired by others, I share my open-source derived work with the community.
</p>
<div class="flex w-full items-center justify-center space-x-4 py-4 md:pb-10">
<a href="/projects" class={cn(buttonVariants())}> My Projects </a>
<a
target="_blank"
rel="noreferrer"
href={siteConfig.links.gitHubProfile}
class={cn(buttonVariants({ variant: 'outline' }))}
>
<Icons.gitHub class="mr-2 h-4 w-4" />
GitHub
</a>
</div>
</SiteHeader>
<section class="flex">
<div class="border-grey/15 relative border-t pb-16 pt-10 dark:border-white/20">
<div
class="pointer-events-none absolute left-[00%] top-0 h-40 w-[100%] select-none overflow-hidden"
>
<div
class="pointer-events-none absolute left-[00%] top-0 h-40 w-[100%] select-none overflow-hidden"
>
<div
class="absolute left-0 top-40 h-96 w-full -translate-y-full [background-image:radial-gradient(closest-side,rgba(123,175,224,0.12)_0%,transparent_100%)]"
></div>
class="absolute left-0 top-40 h-96 w-full -translate-y-full [background-image:radial-gradient(closest-side,rgba(123,175,224,0.12)_0%,transparent_100%)]"
></div>
</div>
<sup class="mb-1 text-base text-blue-400 empty:hidden">Introduction</sup>
<h2 class="text-5xl font-bold">
Building confidence and containers<span class="text-blue-400">.</span>
</h2>
<div class="text-md mt-12 flex flex-col gap-8 md:flex-row">
<div class="flex-1 empty:hidden">
<p>
I'm a DevOps and Platform Engineering enthusiast from Zaandam, The Netherlands. Started my
journey in Information Sciences at the Vrije Universiteit Amsterdam, quickly learning and
adopting Python, Javascript and Linux. These days, I'm also working alot with Terraform,
Bicep, and Kubernetes, creating cloud infra solutions that are sustainable.
</p>
<p class="mt-2">
Over at <a
target="_blank"
rel="noreferrer"
class="font-medium underline underline-offset-4"
href="https://www.wearetriple.com">Triple</a
>, my role involves providing services to clients including HEINEKEN, BAM, and citizenM. I
utilize tools like Akamai, Azure, Azure DevOps and SendGrid to create and maintain robust,
scalable cloud infrastructures. For operational purposes, I employ technologies like
SaltStack, PRTG, and LogicMonitor.
</p>
<p class="mt-2">
I love to work on personal projects or playing games with friends. Beyond the screens, you
can catch me vibing to vinyl, watching movies, hitting concerts and festivals.
</p>
<p class="mt-2">
When the dust settles, my life is all about sharing laughs with my oversized cat and with
my amazing girlfriend. I also enjoy a good whiskey, and I'm always up for a chat or down
to help.
</p>
</div>
<sup class="mb-1 text-base text-blue-400 empty:hidden">Introduction</sup>
<h2 class="text-5xl font-bold">
Building confidence and containers<span class="text-blue-400">.</span>
</h2>
<div class="text-md mt-12 flex flex-col gap-8 md:flex-row">
<div class="flex-1 empty:hidden">
<p>
I'm a DevOps and Platform Engineering enthusiast from Zaandam, The Netherlands. Started
my journey in Information Sciences at the Vrije Universiteit Amsterdam, quickly learning
and adopting Python, Javascript and Linux. These days, I'm also working alot with
Terraform, Bicep, and Kubernetes, creating cloud infra solutions that are sustainable.
</p>
<p class="mt-2">
Over at <a
target="_blank"
rel="noreferrer"
class="font-medium underline underline-offset-4"
href="https://www.wearetriple.com">Triple</a
>, my role involves providing services to clients including HEINEKEN, BAM, and citizenM.
I utilize tools like Akamai, Azure, Azure DevOps and SendGrid to create and maintain
robust, scalable cloud infrastructures. For operational purposes, I employ technologies
like SaltStack, PRTG, and LogicMonitor.
</p>
<p class="mt-2">
I love to work on personal projects or playing games with friends. Beyond the screens,
you can catch me vibing to vinyl, watching movies, hitting concerts and festivals.
</p>
<p class="mt-2">
When the dust settles, my life is all about sharing laughs with my oversized cat and
with my amazing girlfriend. I also enjoy a good whiskey, and I'm always up for a chat or
down to help.
</p>
</div>
<div class="flex-1">
<ImageFade />
</div>
<div class="flex-1">
<ImageFadeCarousel {images} />
</div>
</div>
</section>
</div>
</div>
</section>

View file

@ -1,6 +1,8 @@
/** @type {import('./$types').PageLoad} */
export function load() {
return {
title: `Home`
name: `Home`,
title: `I made this for you`,
subTitle: `Featuring current work and studies in a SvelteKit-based portfolio.`
};
}

View file

@ -0,0 +1,53 @@
import satori from 'satori';
import { Resvg } from '@resvg/resvg-js';
import { html } from 'satori-html';
import { OgImage } from '$lib/components/site';
import GeistRegular from '$lib/assets/og/Geist-Regular.woff';
import GeistBold from '$lib/assets/og/Geist-Bold.woff';
import imageData from '$lib/assets/og/me-inline.jpg?base64';
const height = 630;
const width = 1200;
/** @type {import('./$types').RequestHandler} */
export const GET = async ({ url }) => {
const title = url.searchParams.get('title') ?? undefined;
const subTitle = url.searchParams.get('subTitle') ?? undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = (OgImage as any).render({ title, subTitle, imageData });
const element = html(`${result.html}<style>${result.css.code}</style>`);
const svg = await satori(element, {
fonts: [
{
name: 'Geist Regular',
data: Buffer.from(GeistRegular),
weight: 100
},
{
name: 'Geist Bold',
data: Buffer.from(GeistBold),
weight: 700
}
],
height,
width
});
const resvg = new Resvg(svg, {
fitTo: {
mode: 'width',
value: width
}
});
const image = resvg.render();
return new Response(image.asPng(), {
headers: {
'content-type': 'image/png',
'cache-control': 'public, max-age=86400, immutable'
}
});
};

7
src/routes/og.png/env.d.ts vendored Normal file
View file

@ -0,0 +1,7 @@
/// <reference types="vite/client" />
/// <reference types="vite/types/importMeta" />
declare module '*?base64' {
const src: string;
export default src;
}

View file

@ -0,0 +1,11 @@
<script>
import { OgImage } from '$lib/components/site';
import meInline from '$lib/assets/og/me-inline.jpg';
import fs from 'fs';
import path from 'path';
const imageData = fs.readFileSync(path.join(process.cwd(), meInline), 'base64');
</script>
<section class="h-[630px] w-[1200px]">
<OgImage {imageData} />
</section>

View file

@ -1,17 +1,14 @@
<script lang="ts">
import * as PageHeader from '$lib/components/site/page-header';
import { Projects } from '$lib/components/site/projects';
import { page } from '$app/stores';
import { SiteHeader } from '$lib/components/site';
$: title = $page.data.title;
$: subTitle = $page.data.subTitle;
</script>
<div class="container relative max-w-[980px]">
<PageHeader.Root class="pb-8">
<PageHeader.Heading>Projects I've realized</PageHeader.Heading>
<PageHeader.Description>
Explore some of the projects I worked on in the past.
</PageHeader.Description>
</PageHeader.Root>
<SiteHeader {title} {subTitle} />
<section class="flex justify-center">
<Projects />
</section>
</div>
<section class="flex justify-center">
<Projects />
</section>

View file

@ -1,6 +1,8 @@
/** @type {import('./$types').PageLoad} */
export function load() {
return {
title: `Projects`
name: `Projects`,
title: `Projects Ive realized`,
subTitle: `Explore some of the projects I worked on in the past.`
};
}

View file

@ -31,7 +31,7 @@ export async function GET() {
* @returns {string} robots.txt content.
*/
function generateRobotsTxt(siteUrl: string, config: { agent: string; disallow: string[] }[]) {
return `Sitemap: ${siteUrl}/sitemap.xml
return `Sitemap: https://${siteUrl}/sitemap.xml
# https://developers.google.com/search/docs/advanced/sitemaps/build-sitemap#addsitemap
# https://www.robotstxt.org/robotstxt.html

View file

@ -1,17 +1,14 @@
<script lang="ts">
import * as PageHeader from '$lib/components/site/page-header';
import { Timeline } from '$lib/components/site/timeline';
import { page } from '$app/stores';
import { SiteHeader } from '$lib/components/site';
$: title = $page.data.title;
$: subTitle = $page.data.subTitle;
</script>
<div class="container relative max-w-[980px]">
<PageHeader.Root class="pb-8">
<PageHeader.Heading>Experiences through time</PageHeader.Heading>
<PageHeader.Description>
Achievements in my education, career and personal life.
</PageHeader.Description>
</PageHeader.Root>
<SiteHeader {title} {subTitle} />
<section>
<Timeline />
</section>
</div>
<section>
<Timeline />
</section>

View file

@ -1,6 +1,8 @@
/** @type {import('./$types').PageLoad} */
export function load() {
return {
title: `Timeline`
name: `Timeline`,
title: `Experiences through time`,
subTitle: `Achievements in my education, career and personal life.`
};
}

View file

@ -1,17 +1,14 @@
<script lang="ts">
import * as PageHeader from '$lib/components/site/page-header';
import { Tools } from '$lib/components/site/tools';
import { page } from '$app/stores';
import { SiteHeader } from '$lib/components/site';
$: title = $page.data.title;
$: subTitle = $page.data.subTitle;
</script>
<div class="container relative max-w-[980px]">
<PageHeader.Root class="pb-8">
<PageHeader.Heading>Inside my toolbox</PageHeader.Heading>
<PageHeader.Description>
Tools, applications, and software that fuels my development and operations work.
</PageHeader.Description>
</PageHeader.Root>
<SiteHeader {title} {subTitle} />
<section class="flex justify-center">
<Tools />
</section>
</div>
<section class="flex justify-center">
<Tools />
</section>

View file

@ -1,6 +1,8 @@
/** @type {import('./$types').PageLoad} */
export function load() {
return {
title: `Tools`
name: `Tools`,
title: `Inside my toolbox`,
subTitle: `Tools, applications, and software that fuels my development and operations work.`
};
}

View file

@ -1,10 +1,11 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--font-geist-sans: 'Geist Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
@ -89,6 +90,40 @@
-webkit-tap-highlight-color: rgba(128, 128, 128, 0.5);
}
/* Font face Geist font */
@font-face {
font-family: 'Geist Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url('/fonts/Geist/Geist-Regular.woff2') format('woff2');
}
@font-face {
font-family: 'Geist Sans';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('/fonts/Geist/Geist-Medium.woff2') format('woff2');
}
@font-face {
font-family: 'Geist Sans';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url('/fonts/Geist/Geist-SemiBold.woff2') format('woff2');
}
@font-face {
font-family: 'Geist Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url('/fonts/Geist/Geist-Bold.woff2') format('woff2');
}
/* === Scrollbars === */
::-webkit-scrollbar {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,92 @@
Geist Sans and Geist Mono Font
(C) 2023 Vercel, made in collaboration with basement.studio
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is available with a FAQ at: http://scripts.sil.org/OFL and copied below
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION AND CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

View file

@ -17,7 +17,7 @@ const config = {
colors: {
border: 'hsl(var(--border) / <alpha-value>)',
input: 'hsl(var(--input) / <alpha-value>)',
ring: 'hsl(var(--ring) / <alpha-value>)',
ring: 'hsl(var(--ring))',
background: 'hsl(var(--background) / <alpha-value>)',
foreground: 'hsl(var(--foreground) / <alpha-value>)',
primary: {
@ -55,7 +55,7 @@ const config = {
sm: 'calc(var(--radius) - 4px)'
},
fontFamily: {
sans: [...fontFamily.sans]
sans: ['var(--font-geist-sans)', ...fontFamily.sans]
}
}
}

View file

@ -1,13 +1,46 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { enhancedImages } from '@sveltejs/enhanced-img';
import { defineConfig } from 'vite';
import fs from 'fs';
export default defineConfig({
plugins: [enhancedImages(), sveltekit()],
ssr: {
noExternal: ['three']
},
plugins: [base64(), enhancedImages(), rawFonts(['.woff']), sveltekit()],
define: {
'import.meta.env.VERCEL_ANALYTICS_ID': JSON.stringify(process.env.VERCEL_ANALYTICS_ID)
'import.meta.env.VERCEL_URL': JSON.stringify(process.env.VERCEL_URL)
}
});
function rawFonts(ext: string[]) {
return {
name: 'vite-plugin-raw-fonts',
transform(_code: string, id: string) {
if (ext.some((e) => id.endsWith(e))) {
const buffer = fs.readFileSync(id);
return { code: `export default ${JSON.stringify(buffer)}`, map: null };
}
}
};
}
function base64() {
return {
name: 'vite-plugin-base64-loader',
// transform(_code: string, id: string) {
// const [path, query] = id.split('?');
// if (query === 'base64' && ext.some((e) => id.endsWith(e))) {
// const base64 = fs.readFileSync(path, { encoding: 'base64' });
// return { code: `export default ${JSON.stringify(base64)}`, map: null };
// }
// }
transform(_code: string, id: string) {
const [path, query] = id.split('?');
if (query !== 'base64') {
return null;
}
const base64 = fs.readFileSync(path, { encoding: 'base64' });
return { code: `export default ${JSON.stringify(base64)}`, map: null };
}
};
}