From 0bcdaf373e4a3e3c8a8d6ea8edd576ea66c3d9bb Mon Sep 17 00:00:00 2001 From: Rodney Lab Date: Sat, 30 Nov 2024 08:11:00 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=92=AB=20simplify=20Markdown=20han?= =?UTF-8?q?dling=20and=20update=20to=20Svelte5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 +- README.md | 2 +- package.json | 13 +- pnpm-lock.yaml | 369 ++++++++++++++++++++++++----- src/hooks.server.js | 4 +- src/lib/components/BlogPost.svelte | 5 +- src/lib/utilities/blog.js | 43 ++-- src/routes/+page.js | 15 +- src/routes/+page.svelte | 8 +- src/routes/[slug]/+page.js | 48 +--- src/routes/[slug]/+page.server.js | 60 +++++ src/routes/[slug]/+page.svelte | 7 +- src/routes/contact/+page.svelte | 4 +- src/routes/sitemap.xml/+server.js | 12 +- svelte.config.js | 3 +- 15 files changed, 448 insertions(+), 153 deletions(-) create mode 100644 src/routes/[slug]/+page.server.js diff --git a/CHANGELOG.md b/CHANGELOG.md index f2fd639..616a705 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,8 +26,8 @@ - **dependencies**: 💫 update packages - 💫 revert back to using node for blog content imports - 💫 update package -- 💫 replace sourceing blog posts using node with ESM imports -- 🤗 improve acccessibility +- 💫 replace sourcing blog posts using node with ESM imports +- 🤗 improve accessibility - 💫 switch to iconify for icons - **dependencies**: 💫 update package - 💫 update sitemap script @@ -246,13 +246,13 @@ - **dependencies**: 💫 update packages - **dependencies**: 💫 update packages: - **dependencies**: 💫 update package -- 🔥 optimised scss prepend data only adding varaibles +- 🔥 optimised scss prepend data only adding variables - 🔥 optimised CSS removing unused selectors - **Icon**: 🔥 optimised import of icons - 💫 updated packages - **package.json**: reset dev and preview server ports to 3000 - **static**: 🤖 added robots.txt -- 🤗 corrected a11y atribute +- 🤗 corrected a11y attribute - 🔧 made all blog posts static - 💫 added hooks - **dependencies**: 💫 update package diff --git a/README.md b/README.md index b173fd9..d9b135a 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ npm run build ### `src` -- `hooks.server.js` we define Content Security Policy (CSP) and other HTTP security headers in here, effective for server side rendered apps. See post on SvelteKit static site HTTP headers to see how to set up CSP etc for static sites. +- `hooks.server.js` we define Content Security Policy (CSP) and other HTTP security headers in here, effective for server side rendered apps. See post on SvelteKit static site HTTP headers to see how to set up CSP etc. for static sites. ### `src/components` diff --git a/package.json b/package.json index c789f65..4dd0678 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,7 @@ "format": "prettier --write --plugin=prettier-plugin-svelte .", "generate:images": "node ./generate-responsive-image-data.js", "generate:sitemap": "node ./generate-sitemap.js", - "check:formatting": "prettier --check --plugin=prettier-plugin-svelte .", - "prepare": "husky install" + "check:formatting": "prettier --check --plugin=prettier-plugin-svelte ." }, "devDependencies": { "@commitlint/config-conventional": "^19.6.0", @@ -26,19 +25,18 @@ "@types/object-hash": "^3.0.6", "commitlint": "^19.6.0", "dayjs": "^1.11.13", + "dompurify": "^3.2.1", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.46.0", "front-matter": "^4.0.2", "globals": "^15.12.0", "husky": "^9.1.7", "iconify-icon": "^1.0.8", - "mdsvex": "^0.12.3", "object-hash": "^3.0.0", "postcss": "^8.4.49", "postcss-html": "^1.7.0", "prettier": "~3.4.1", "prettier-plugin-svelte": "^3.3.2", - "reading-time": "1.4.0", "sass": "^1.81.0", "sharp": "^0.33.5", "stylelint": "^16.10.0", @@ -51,7 +49,8 @@ "typescript-eslint": "^8.16.0", "vanilla-lazyload": "^17.9.0", "vite": "^5.4.11", - "vite-imagetools": "^7.0.4" + "vite-imagetools": "^7.0.4", + "yaml": "^2.6.1" }, "repository": { "type": "git", @@ -62,6 +61,8 @@ }, "type": "module", "dependencies": { - "@sveltejs/vite-plugin-svelte": "^4.0.2" + "@rodneylab/parsedown": "^1.4.3", + "@sveltejs/vite-plugin-svelte": "^4.0.2", + "jsdom": "^25.0.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c49b4a..bc850bf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,15 @@ importers: .: dependencies: + '@rodneylab/parsedown': + specifier: ^1.4.3 + version: 1.4.3 '@sveltejs/vite-plugin-svelte': specifier: ^4.0.2 version: 4.0.2(svelte@5.2.8)(vite@5.4.11(@types/node@22.10.0)(sass@1.81.0)) + jsdom: + specifier: ^25.0.1 + version: 25.0.1 devDependencies: '@commitlint/config-conventional': specifier: ^19.6.0 @@ -42,6 +48,9 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.13 + dompurify: + specifier: ^3.2.1 + version: 3.2.1 eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@8.57.1) @@ -60,9 +69,6 @@ importers: iconify-icon: specifier: ^1.0.8 version: 1.0.8 - mdsvex: - specifier: ^0.12.3 - version: 0.12.3(svelte@5.2.8) object-hash: specifier: ^3.0.0 version: 3.0.0 @@ -78,9 +84,6 @@ importers: prettier-plugin-svelte: specifier: ^3.3.2 version: 3.3.2(prettier@3.4.1)(svelte@5.2.8) - reading-time: - specifier: 1.4.0 - version: 1.4.0 sass: specifier: ^1.81.0 version: 1.81.0 @@ -120,6 +123,9 @@ importers: vite-imagetools: specifier: ^7.0.4 version: 7.0.4(rollup@4.27.4) + yaml: + specifier: ^2.6.1 + version: 2.6.1 packages: @@ -638,6 +644,9 @@ packages: '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + '@rodneylab/parsedown@1.4.3': + resolution: {integrity: sha512-b7ys9W18kDnOWBoqzKEoCptsiFYha9S2hzgao5Xl3uG4g9FWRc3MhLQ2EuC9l5CV5yOsL70U1IAQfbCBliNWeQ==} + '@rollup/pluginutils@5.1.3': resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} engines: {node: '>=14.0.0'} @@ -781,8 +790,8 @@ packages: '@types/object-hash@3.0.6': resolution: {integrity: sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w==} - '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} '@typescript-eslint/eslint-plugin@8.16.0': resolution: {integrity: sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==} @@ -868,6 +877,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -903,6 +916,9 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -960,6 +976,10 @@ packages: colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commitlint@19.6.0: resolution: {integrity: sha512-0gOMRBSpnCw3Su0rfVeDqCe4ck/fkhGGC9UxVDeSyyCemFXs4U3BDuwMWvYcw4qsEAkPuDjQNoU8KWyPtHBq/w==} engines: {node: '>=v18'} @@ -1022,10 +1042,18 @@ packages: engines: {node: '>=4'} hasBin: true + cssstyle@4.1.0: + resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} + engines: {node: '>=18'} + dargs@8.1.0: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} @@ -1038,6 +1066,9 @@ packages: supports-color: optional: true + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1045,6 +1076,10 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + detect-libc@1.0.3: resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} engines: {node: '>=0.10'} @@ -1075,6 +1110,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.2.1: + resolution: {integrity: sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==} + domutils@3.1.0: resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} @@ -1245,6 +1283,10 @@ packages: flatted@3.3.2: resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + front-matter@4.0.2: resolution: {integrity: sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==} @@ -1317,6 +1359,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + html-tags@3.3.1: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} @@ -1324,6 +1370,14 @@ packages: htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.5: + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + engines: {node: '>= 14'} + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} @@ -1332,6 +1386,10 @@ packages: iconify-icon@1.0.8: resolution: {integrity: sha512-jvbUKHXf8EnGGArmhlP2IG8VqQLFFyTvTqb9LVL2TKTh7/eCCD1o2HHE9thpbJJb6B8hzhcFb6rOKhvo7reNKA==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1406,6 +1464,9 @@ packages: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} @@ -1434,6 +1495,15 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsdom@25.0.1: + resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^2.11.2 + peerDependenciesMeta: + canvas: + optional: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -1534,11 +1604,6 @@ packages: mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - mdsvex@0.12.3: - resolution: {integrity: sha512-C/uIJamjNo5PHHnR3JHqsBPoLcfUBpzRmAEB6FLMXI/s7XHOceswjDMKqSPEW2WHmYpKm0taZ3U20GSyhMridA==} - peerDependencies: - svelte: ^3.56.0 || ^4.0.0 || ^5.0.0-next.120 - meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} @@ -1555,6 +1620,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1591,6 +1664,9 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + nwsapi@2.2.16: + resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} + object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} @@ -1626,6 +1702,9 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1727,13 +1806,6 @@ packages: engines: {node: '>=14'} hasBin: true - prism-svelte@0.4.7: - resolution: {integrity: sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==} - - prismjs@1.29.0: - resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} - engines: {node: '>=6'} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1745,9 +1817,6 @@ packages: resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} engines: {node: '>= 14.16.0'} - reading-time@1.4.0: - resolution: {integrity: sha512-0I9aP583rqQhm6T6Y+pYgYaM4w649VHgQPC24xSWXpn/4qRs08Zu6KgXRf0da6/k7IHoC6idm76fU6vz4mmzHQ==} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -1778,6 +1847,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -1785,11 +1857,18 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass@1.81.0: resolution: {integrity: sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==} engines: {node: '>=14.0.0'} hasBin: true + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -1954,6 +2033,9 @@ packages: svg-tags@1.0.0: resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + table@6.8.2: resolution: {integrity: sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==} engines: {node: '>=10.0.0'} @@ -1974,6 +2056,13 @@ packages: tinyexec@0.3.1: resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + tldts-core@6.1.64: + resolution: {integrity: sha512-uqnl8vGV16KsyflHOzqrYjjArjfXaU6rMPXYy2/ZWoRKCkXtghgB4VwTDXUG+t0OTGeSewNAG31/x1gCTfLt+Q==} + + tldts@6.1.64: + resolution: {integrity: sha512-ph4AE5BXWIOsSy9stpoeo7bYe/Cy7VfpciIH4RhVZUPItCJmhqWCN0EVzxd8BOHiyNb42vuJc6NWTjJkg91Tuw==} + hasBin: true + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1982,6 +2071,14 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + tough-cookie@5.0.0: + resolution: {integrity: sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==} + engines: {node: '>=16'} + + tr46@5.0.0: + resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==} + engines: {node: '>=18'} + ts-api-utils@1.4.2: resolution: {integrity: sha512-ZF5gQIQa/UmzfvxbHZI3JXN0/Jt+vnAfAviNRAMc491laiK6YCLpCW9ft8oaCRFOTxCZtUTE6XB0ZQAe3olntw==} engines: {node: '>=16'} @@ -2021,9 +2118,6 @@ packages: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} engines: {node: '>=18'} - unist-util-stringify-position@2.0.3: - resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} - uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -2033,9 +2127,6 @@ packages: vanilla-lazyload@17.9.0: resolution: {integrity: sha512-VOuNHn6xCXmC1I/Lz2cB/l1ScpsY2aXcymXzxtbsMmLQ2qiHr2KlBeJ7uf2Su/yqKTLkgdDWahznb/ae5YzZNA==} - vfile-message@2.0.4: - resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} - vite-imagetools@7.0.4: resolution: {integrity: sha512-C9C7b2p/8/TCN2g26tE9haoer2i8K4x0v2RXUiHsIjiz221vQuKItCQ+VyiVCsUMPXfJC/tlZsmCZVBz5jh7uA==} engines: {node: '>=18.0.0'} @@ -2079,6 +2170,26 @@ packages: vite: optional: true + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.0.0: + resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==} + engines: {node: '>=18'} + which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -2103,6 +2214,25 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -2111,6 +2241,11 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yaml@2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + engines: {node: '>= 14'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -2558,6 +2693,8 @@ snapshots: '@polka/url@1.0.0-next.28': {} + '@rodneylab/parsedown@1.4.3': {} + '@rollup/pluginutils@5.1.3(rollup@4.27.4)': dependencies: '@types/estree': 1.0.6 @@ -2678,7 +2815,8 @@ snapshots: '@types/object-hash@3.0.6': {} - '@types/unist@2.0.11': {} + '@types/trusted-types@2.0.7': + optional: true '@typescript-eslint/eslint-plugin@8.16.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)': dependencies: @@ -2779,6 +2917,12 @@ snapshots: acorn@8.14.0: {} + agent-base@7.1.1: + dependencies: + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -2813,6 +2957,8 @@ snapshots: astral-regex@2.0.0: {} + asynckit@0.4.0: {} + axobject-query@4.1.0: {} balanced-match@1.0.2: {} @@ -2869,6 +3015,10 @@ snapshots: colord@2.9.3: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commitlint@19.6.0(@types/node@22.10.0)(typescript@5.7.2): dependencies: '@commitlint/cli': 19.6.0(@types/node@22.10.0)(typescript@5.7.2) @@ -2932,18 +3082,31 @@ snapshots: cssesc@3.0.0: {} + cssstyle@4.1.0: + dependencies: + rrweb-cssom: 0.7.1 + dargs@8.1.0: {} + data-urls@5.0.0: + dependencies: + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + dayjs@1.11.13: {} debug@4.3.7: dependencies: ms: 2.1.3 + decimal.js@10.4.3: {} + deep-is@0.1.4: {} deepmerge@4.3.1: {} + delayed-stream@1.0.0: {} + detect-libc@1.0.3: optional: true @@ -2971,6 +3134,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.2.1: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@3.1.0: dependencies: dom-serializer: 2.0.0 @@ -3192,6 +3359,12 @@ snapshots: flatted@3.3.2: {} + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + front-matter@4.0.2: dependencies: js-yaml: 3.14.1 @@ -3265,6 +3438,10 @@ snapshots: has-flag@4.0.0: {} + html-encoding-sniffer@4.0.0: + dependencies: + whatwg-encoding: 3.1.1 + html-tags@3.3.1: {} htmlparser2@8.0.2: @@ -3274,12 +3451,30 @@ snapshots: domutils: 3.1.0 entities: 4.5.0 + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.5: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + husky@9.1.7: {} iconify-icon@1.0.8: dependencies: '@iconify/types': 2.0.0 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ignore@5.3.2: {} ignore@6.0.2: {} @@ -3328,6 +3523,8 @@ snapshots: is-plain-object@5.0.0: {} + is-potential-custom-element-name@1.0.1: {} + is-reference@3.0.3: dependencies: '@types/estree': 1.0.6 @@ -3353,6 +3550,34 @@ snapshots: dependencies: argparse: 2.0.1 + jsdom@25.0.1: + dependencies: + cssstyle: 4.1.0 + data-urls: 5.0.0 + decimal.js: 10.4.3 + form-data: 4.0.1 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.16 + parse5: 7.2.1 + rrweb-cssom: 0.7.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 5.0.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.0.0 + ws: 8.18.0 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + json-buffer@3.0.1: {} json-parse-even-better-errors@2.3.1: {} @@ -3426,14 +3651,6 @@ snapshots: mdn-data@2.12.2: {} - mdsvex@0.12.3(svelte@5.2.8): - dependencies: - '@types/unist': 2.0.11 - prism-svelte: 0.4.7 - prismjs: 1.29.0 - svelte: 5.2.8 - vfile-message: 2.0.4 - meow@12.1.1: {} meow@13.2.0: {} @@ -3445,6 +3662,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -3470,6 +3693,8 @@ snapshots: normalize-path@3.0.0: {} + nwsapi@2.2.16: {} + object-hash@3.0.0: {} once@1.4.0: @@ -3512,6 +3737,10 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse5@7.2.1: + dependencies: + entities: 4.5.0 + path-exists@4.0.0: {} path-exists@5.0.0: {} @@ -3585,18 +3814,12 @@ snapshots: prettier@3.4.1: {} - prism-svelte@0.4.7: {} - - prismjs@1.29.0: {} - punycode@2.3.1: {} queue-microtask@1.2.3: {} readdirp@4.0.2: {} - reading-time@1.4.0: {} - require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -3635,6 +3858,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.27.4 fsevents: 2.3.3 + rrweb-cssom@0.7.1: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -3643,6 +3868,8 @@ snapshots: dependencies: mri: 1.2.0 + safer-buffer@2.1.2: {} + sass@1.81.0: dependencies: chokidar: 4.0.1 @@ -3651,6 +3878,10 @@ snapshots: optionalDependencies: '@parcel/watcher': 2.5.0 + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + semver@7.6.3: {} set-cookie-parser@2.7.1: {} @@ -3857,6 +4088,8 @@ snapshots: svg-tags@1.0.0: {} + symbol-tree@3.2.4: {} + table@6.8.2: dependencies: ajv: 8.17.1 @@ -3878,12 +4111,26 @@ snapshots: tinyexec@0.3.1: {} + tldts-core@6.1.64: {} + + tldts@6.1.64: + dependencies: + tldts-core: 6.1.64 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 totalist@3.0.1: {} + tough-cookie@5.0.0: + dependencies: + tldts: 6.1.64 + + tr46@5.0.0: + dependencies: + punycode: 2.3.1 + ts-api-utils@1.4.2(typescript@5.7.2): dependencies: typescript: 5.7.2 @@ -3914,10 +4161,6 @@ snapshots: unicorn-magic@0.1.0: {} - unist-util-stringify-position@2.0.3: - dependencies: - '@types/unist': 2.0.11 - uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -3926,11 +4169,6 @@ snapshots: vanilla-lazyload@17.9.0: {} - vfile-message@2.0.4: - dependencies: - '@types/unist': 2.0.11 - unist-util-stringify-position: 2.0.3 - vite-imagetools@7.0.4(rollup@4.27.4): dependencies: '@rollup/pluginutils': 5.1.3(rollup@4.27.4) @@ -3953,6 +4191,23 @@ snapshots: optionalDependencies: vite: 5.4.11(@types/node@22.10.0)(sass@1.81.0) + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@7.0.0: {} + + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@4.0.0: {} + + whatwg-url@14.0.0: + dependencies: + tr46: 5.0.0 + webidl-conversions: 7.0.0 + which@1.3.1: dependencies: isexe: 2.0.0 @@ -3976,10 +4231,18 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@8.18.0: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + y18n@5.0.8: {} yaml@1.10.2: {} + yaml@2.6.1: {} + yargs-parser@21.1.1: {} yargs@17.7.2: diff --git a/src/hooks.server.js b/src/hooks.server.js index fc9f884..03b0e0c 100644 --- a/src/hooks.server.js +++ b/src/hooks.server.js @@ -74,8 +74,8 @@ export async function handle({ event, resolve }) { 'accelerometer=(), autoplay=(), camera=(), document-domain=(), encrypted-media=(), fullscreen=(), gyroscope=(), interest-cohort=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), sync-xhr=(), usb=(), xr-spatial-tracking=(), geolocation=()', ); response.headers.set('X-Content-Type-Options', 'nosniff'); - /* Switch from Content-Security-Policy-Report-Only to Content-Security-Policy once you are satisifed policy is what you want - * on switch comment out the Report-Only line + /* Switch from Content-Security-Policy-Report-Only to Content-Security-Policy once you are satisfied + * policy is what you want on switch comment out the Report-Only line */ response.headers.set('Content-Security-Policy-Report-Only', csp); // response.headers.set('Content-Security-Policy', csp); diff --git a/src/lib/components/BlogPost.svelte b/src/lib/components/BlogPost.svelte index cee43a4..95e8375 100644 --- a/src/lib/components/BlogPost.svelte +++ b/src/lib/components/BlogPost.svelte @@ -2,8 +2,7 @@ import BannerImage from '$lib/components/BannerImage.svelte'; import SEO from '$lib/components/SEO/index.svelte'; - export let imageData; - export let post; + let { imageData, post, sanitisedHtml } = $props(); const { datePublished, @@ -70,3 +69,5 @@

{title}

+ +{@html sanitisedHtml} diff --git a/src/lib/utilities/blog.js b/src/lib/utilities/blog.js index 1c17caa..6f947ec 100644 --- a/src/lib/utilities/blog.js +++ b/src/lib/utilities/blog.js @@ -1,4 +1,5 @@ -import { compile } from 'mdsvex'; +import { parse } from 'yaml'; + export const BLOG_PATH = 'src/content/blog'; /** @@ -42,26 +43,22 @@ export async function getPostsContent() { } } -/** - * Returns an array of post metadata, with optional post body too. Array is sort in reverse - * chrononological order - * @param {{slug: string; content: string;}[]} postsContent - - * @param {boolean} body - if true the HTML post body is returned as well as meta - */ -export const getPosts = async (postsContent, body = false) => { - const postPromises = postsContent.map(async (element) => { - const { content, slug } = element; - const transformedContent = await compile(content); - const { datePublished, lastUpdated, postTitle, seoMetaDescription } = - /** @type {{datePublished: string; lastUpdated: string; postTitle: string; seoMetaDescription: string;}} */ ( - transformedContent.data.fm - ); - let resultElement = { datePublished, lastUpdated, postTitle, seoMetaDescription, slug }; - if (body) { - resultElement = { ...resultElement, body: transformedContent.code }; - } - return resultElement; - }); - const result = await Promise.all(postPromises); - return result.sort((a, b) => Date.parse(b.datePublished) - Date.parse(a.datePublished)); +export const separateFrontmatter = (markdown) => { + const frontmatterStartIndex = markdown.indexOf('---') + 3; + const frontmatterEndIndex = markdown.indexOf('---', frontmatterStartIndex); + + if (frontmatterStartIndex !== -1 && frontmatterEndIndex !== -1) { + const parsedFrontmatter = parse(markdown.slice(frontmatterStartIndex, frontmatterEndIndex)); + + return { + frontmatter: parsedFrontmatter, + markdownBody: markdown.slice(frontmatterEndIndex + 3).trim(), + }; + } + + // assume there is no frontmatter + return { + frontmatter: null, + markdownBody: markdown, + }; }; diff --git a/src/routes/+page.js b/src/routes/+page.js index b256295..626bf79 100644 --- a/src/routes/+page.js +++ b/src/routes/+page.js @@ -1,12 +1,21 @@ +import { separateFrontmatter } from '$lib/utilities/blog'; + /** @type {import('./$types').PageLoad} */ export async function load() { const mdModules = import.meta.glob('../content/blog/**/index.md'); const posts = await Promise.all( Object.keys(mdModules).map(async (path) => { const slug = path.split('/').at(-2); - const { metadata } = await mdModules[path](); - const { datePublished, lastUpdated, postTitle, seoMetaDescription } = metadata; - return { datePublished, lastUpdated, postTitle, seoMetaDescription, slug }; + const markdown = (await import(`../content/blog/${slug}/index.md?raw`)).default; + const { frontmatter } = separateFrontmatter(markdown); + const { datePublished, lastUpdated, postTitle, seoMetaDescription } = frontmatter; + return { + datePublished, + lastUpdated, + postTitle, + seoMetaDescription, + slug, + }; }), ); return { posts }; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 587225c..7be03d9 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -9,8 +9,8 @@ import website from '$lib/config/website'; /** @type {import('./$types').PageData} */ - export let data; - const { posts } = data; + let { data } = $props(); + let { posts } = $derived(data); const { author, siteUrl } = website; @@ -68,8 +68,8 @@
-

Climate — Sveltekit Starter

-

SvelteKit MDsveX (Markdown for Svelte) Blog

+

Climate — SvelteKit Starter

+

SvelteKit Markdown Blog

About me

diff --git a/src/routes/[slug]/+page.js b/src/routes/[slug]/+page.js index 154ab94..a7497f6 100644 --- a/src/routes/[slug]/+page.js +++ b/src/routes/[slug]/+page.js @@ -1,49 +1,9 @@ -import readingTime from 'reading-time'; - /** @type {import('./$types').PageLoad} */ -export async function load({ params, url }) { - const { slug } = params; - const { pathname } = url; - - const postPromise = import(`../../content/blog/${slug}/index.md`); - const imageDataPromise = import(`../../lib/generated/posts/${pathname.slice(1)}.js`); - - const [postResult, imageDataResult] = await Promise.all([postPromise, imageDataPromise]); - const { default: page, metadata } = postResult; - const { default: imageData } = imageDataResult; - - if (!page) { - return { - status: 404, - }; - } - - const { - datePublished, - featuredImage, - featuredImageAlt, - ogImage, - ogSquareImage, - postTitle, - seoMetaDescription, - twitterImage, - } = metadata; +export async function load({ data }) { + const { imageData } = data; return { - post: { - datePublished, - featuredImage, - featuredImageAlt, - ogImage, - ogSquareImage, - postTitle, - seoMetaDescription, - timeToRead: Math.ceil(readingTime(page).minutes), - twitterImage, - slug, - }, - slug, - imageData, - page, + ...data, + imageData: JSON.parse(imageData), }; } diff --git a/src/routes/[slug]/+page.server.js b/src/routes/[slug]/+page.server.js new file mode 100644 index 0000000..6b68550 --- /dev/null +++ b/src/routes/[slug]/+page.server.js @@ -0,0 +1,60 @@ +import { markdown_to_html as markdownToHtml } from '@rodneylab/parsedown'; +import createDOMPurify from 'dompurify'; +import { JSDOM } from 'jsdom'; +import { separateFrontmatter } from '../../lib/utilities/blog'; + +export const prerender = true; + +const { window } = new JSDOM(''); +const DOMPurify = createDOMPurify(window); + +/** @type {import('./$types').PageLoad} */ +export async function load({ params, url }) { + const { slug } = params; + const { pathname } = url; + + const imageDataPromise = import(`../../lib/generated/posts/${pathname.slice(1)}.js`); + const markdown = (await import(`../../content/blog/${slug}/index.md?raw`)).default; + + if (!markdown) { + return { + status: 404, + }; + } + const { frontmatter, markdownBody } = separateFrontmatter(markdown); + const { html, statistics } = await markdownToHtml(markdownBody); + const sanitisedHtml = DOMPurify.sanitize(html); + + const [imageDataResult] = await Promise.all([imageDataPromise]); + const { default: imageData } = imageDataResult; + + const { + datePublished, + featuredImage, + featuredImageAlt, + ogImage, + ogSquareImage, + postTitle, + seoMetaDescription, + twitterImage, + } = frontmatter; + + return { + post: { + datePublished, + featuredImage, + featuredImageAlt, + ogImage, + ogSquareImage, + postTitle, + seoMetaDescription, + timeToRead: statistics.reading_time, + twitterImage, + slug, + }, + slug, + sanitisedHtml, + statistics, + imageData: JSON.stringify(imageData), + }; +} diff --git a/src/routes/[slug]/+page.svelte b/src/routes/[slug]/+page.svelte index f8d5d62..524fc3f 100644 --- a/src/routes/[slug]/+page.svelte +++ b/src/routes/[slug]/+page.svelte @@ -6,14 +6,13 @@ import lazyload from 'vanilla-lazyload'; /** @type {import('./$types').PageData} */ - export let data; + let { data } = $props(); - const { page, post, imageData } = data; + let { sanitisedHtml, imageData, post } = $derived(data); if (browser && !document.lazyloadInstance) { document.lazyloadInstance = new lazyload(); } - - + diff --git a/src/routes/contact/+page.svelte b/src/routes/contact/+page.svelte index c69e69c..84c01a9 100644 --- a/src/routes/contact/+page.svelte +++ b/src/routes/contact/+page.svelte @@ -7,6 +7,8 @@ import TelegramIcon from '$lib/components/Icons/Telegram.svelte'; import TwitterIcon from '$lib/components/Icons/Twitter.svelte'; import website from '$lib/config/website'; + import SEO from '$lib/components/SEO/index.svelte'; + const { contactEmail, facebookPageName, @@ -15,8 +17,6 @@ twitterUsername, wireUsername, } = website; - import SEO from '$lib/components/SEO/index.svelte'; - let title = 'Contact'; let metadescription = 'Get in touch with Rodneylab, the developer of Climate SvelteKit Starter.'; const breadcrumbs = [ diff --git a/src/routes/sitemap.xml/+server.js b/src/routes/sitemap.xml/+server.js index bf949f4..5562c02 100644 --- a/src/routes/sitemap.xml/+server.js +++ b/src/routes/sitemap.xml/+server.js @@ -1,5 +1,6 @@ import website from '$lib/config/website'; import { error } from '@sveltejs/kit'; +import { separateFrontmatter } from '../../lib/utilities/blog'; export const prerender = true; @@ -48,9 +49,14 @@ export async function GET({ setHeaders }) { const posts = await Promise.all( Object.keys(mdModules).map(async (path) => { const slug = path.split('/').at(-2); - const { metadata } = await mdModules[path](); - const { lastUpdated } = metadata; - return { lastUpdated, slug }; + const markdown = (await import(`../../content/blog/${slug}/index.md?raw`)).default; + const { + frontmatter: { lastUpdated }, + } = separateFrontmatter(markdown); + return { + lastUpdated, + slug, + }; }), ); diff --git a/svelte.config.js b/svelte.config.js index dc1312a..1cce5c3 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,11 +1,10 @@ /** @type {import('@sveltejs/kit').Config} */ import adapter from '@sveltejs/adapter-static'; -import { mdsvex } from 'mdsvex'; import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; const config = { extensions: ['.svelte', '.md', '.svelte.md'], - preprocess: [vitePreprocess({}), mdsvex({ extensions: ['.svelte.md', '.md', '.svx'] })], + preprocess: [vitePreprocess({})], kit: { adapter: adapter({ precompress: true }), },