diff --git a/package-lock.json b/package-lock.json index 7f5fe3f..48c36ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,17 @@ "name": "fredboniface.co.uk-svelte", "version": "0.0.1", "dependencies": { - "mongodb": "^5.7.0" + "marked": "^7.0.3", + "mongodb": "^5.7.0", + "sanitize-html": "^2.11.0" }, "devDependencies": { "@playwright/test": "^1.28.1", "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/adapter-node": "^1.3.1", "@sveltejs/kit": "^1.20.4", + "@types/node": "^20.5.1", + "@types/sanitize-html": "^2.9.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "eslint": "^8.28.0", @@ -916,9 +920,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", - "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==" + "version": "20.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", + "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" }, "node_modules/@types/pug": { "version": "2.0.6", @@ -932,6 +936,15 @@ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", "dev": true }, + "node_modules/@types/sanitize-html": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.9.0.tgz", + "integrity": "sha512-4fP/kEcKNj2u39IzrxWYuf/FnCCwwQCpif6wwY6ROUS1EPRIfWJjGkY3HIowY1EX/VbX5e86yq8AAE7UPMgATg==", + "dev": true, + "dependencies": { + "htmlparser2": "^8.0.0" + } + }, "node_modules/@types/semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", @@ -1674,7 +1687,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1736,6 +1748,68 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es6-promise": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", @@ -1783,7 +1857,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -2282,6 +2355,24 @@ "node": ">=8" } }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -2431,6 +2522,14 @@ "node": ">=8" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-reference": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.1.tgz", @@ -2585,6 +2684,17 @@ "node": ">=12" } }, + "node_modules/marked": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-7.0.3.tgz", + "integrity": "sha512-ev2uM40p0zQ/GbvqotfKcSWEa59fJwluGZj5dcaUOwDRrB1F3dncdXy8NWUApk4fi8atU3kTBOwjyjZ0ud0dxw==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 16" + } + }, "node_modules/mdn-data": { "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", @@ -2777,7 +2887,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, "funding": [ { "type": "github", @@ -2880,6 +2989,11 @@ "node": ">=6" } }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2951,8 +3065,7 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -2993,7 +3106,6 @@ "version": "8.4.28", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3344,6 +3456,19 @@ "rimraf": "bin.js" } }, + "node_modules/sanitize-html": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.11.0.tgz", + "integrity": "sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, "node_modules/saslprep": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", @@ -3468,7 +3593,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, "engines": { "node": ">=0.10.0" } diff --git a/package.json b/package.json index 2fe8e3e..4dcb81d 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/adapter-node": "^1.3.1", "@sveltejs/kit": "^1.20.4", + "@types/node": "^20.5.1", + "@types/sanitize-html": "^2.9.0", "@typescript-eslint/eslint-plugin": "^5.45.0", "@typescript-eslint/parser": "^5.45.0", "eslint": "^8.28.0", @@ -36,6 +38,8 @@ }, "type": "module", "dependencies": { - "mongodb": "^5.7.0" + "marked": "^7.0.3", + "mongodb": "^5.7.0", + "sanitize-html": "^2.11.0" } } diff --git a/src/lib/database/mongo.ts b/src/lib/database/mongo.ts index 12e106e..ea7d221 100644 --- a/src/lib/database/mongo.ts +++ b/src/lib/database/mongo.ts @@ -6,7 +6,7 @@ let dbClient: MongoClient | null = null; export async function mongoConnect() { if (!dbClient) { - dbClient = await MongoClient.connect(MongoUri) + dbClient = await MongoClient.connect(MongoUri); } - return dbClient -} \ No newline at end of file + return dbClient; +} diff --git a/src/lib/posts/PostsSummary.svelte b/src/lib/posts/PostsSummary.svelte index dab0f21..e59bc84 100644 --- a/src/lib/posts/PostsSummary.svelte +++ b/src/lib/posts/PostsSummary.svelte @@ -1,17 +1,17 @@ -
-

{article.title}

-

{article.summary}

-
-
+
+

{article.title}

+

{article.summary}

+
+
\ No newline at end of file + diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 444546c..2b89039 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -35,15 +35,12 @@ diff --git a/src/routes/posts/[slug]/+page.server.ts b/src/routes/posts/[slug]/+page.server.ts index bd910dc..b2efd56 100644 --- a/src/routes/posts/[slug]/+page.server.ts +++ b/src/routes/posts/[slug]/+page.server.ts @@ -1,16 +1,57 @@ -import { mongoConnect } from "$lib/database/mongo"; +import { mongoConnect } from '$lib/database/mongo'; +import { marked } from 'marked'; +import * as path from 'path'; +import sanitizeHtml from 'sanitize-html'; + +import type { Article } from '$lib/posts/types'; +import type { _Renderer } from 'Renderer'; export async function load({ params }) { const slug = params.slug; - const db = await mongoConnect() + const db = await mongoConnect(); const query = { - slug: slug - } - const col = db.db('fredboniface').collection('posts') - const res = col.findOne(query) - const posts = await res + slug: slug + }; + const col = db.db('fredboniface').collection('posts'); + const res = await col.findOne(query); - // Create the `Article` object here and return that rather than doing it on the page. + if (!res) { + throw new Error('Post Not Found'); + } - return {data: JSON.stringify(posts)} + const renderer = new marked.Renderer(); + renderer.image = function (href, title, text) { + const imgPath = path.join('/images/posts', res.slug, href); + return `
+ ${text} +
${title}
+
`; + }; + + const post: Article = { + title: res.title, + author: res.author, + pusblished: res.published, + summary: res.summary, + content: renderMarkdown(res.content, renderer), + slug: res.slug, + tags: res.tags, + date: res.date + }; + + return { data: post }; +} + +function renderMarkdown(md: string, renderer: _Renderer): string { + const rawHtml = marked(md, { renderer }); + console.log(rawHtml) + const sanitizedHtml = sanitizeHtml(rawHtml, { + allowedTags: ['a', 'br', 'code', 'figcaption', 'figure', 'img', 'p', 'pre'], + allowedAttributes: { + 'a': ['href'], + 'img': ['alt', 'class', 'src', 'title'] + } + }); + console.log(sanitizedHtml) + return sanitizedHtml } diff --git a/src/routes/posts/[slug]/+page.svelte b/src/routes/posts/[slug]/+page.svelte index 0e4be0d..486d75e 100644 --- a/src/routes/posts/[slug]/+page.svelte +++ b/src/routes/posts/[slug]/+page.svelte @@ -1,24 +1,109 @@ -
-

{#each post.tags as tag} - {tag} - {/each}
- {post.date}
- {post.author}
-{post.content}

+ +
+
+
+

+ {#each post.tags as tag} + {tag} + {/each}
+ {post.date.toLocaleDateString()}
+ Written by: {post.author} +

+ + {@html post.content} +
+
+
+

HELLO FROM COLUMN 2

+
+
diff --git a/src/routes/posts/tag/[tag]/+page.server.ts b/src/routes/posts/tag/[tag]/+page.server.ts index 2723867..6e280c7 100644 --- a/src/routes/posts/tag/[tag]/+page.server.ts +++ b/src/routes/posts/tag/[tag]/+page.server.ts @@ -1,19 +1,16 @@ -import { mongoConnect } from "$lib/database/mongo"; - +import { mongoConnect } from '$lib/database/mongo'; export async function load({ params }) { const tag = params.tag; - const db = await mongoConnect() + const db = await mongoConnect(); const query = { - tags: { - $in: [ - tag - ] - } + tags: { + $in: [tag] } - const col = db.db('fredboniface').collection('posts') - const res = col.find(query) - const posts = await res.toArray() + }; + const col = db.db('fredboniface').collection('posts'); + const res = col.find(query); + const posts = await res.toArray(); - return {data: JSON.stringify(posts)} + return { data: JSON.stringify(posts) }; } diff --git a/src/routes/posts/tag/[tag]/+page.svelte b/src/routes/posts/tag/[tag]/+page.svelte index 80c4a7c..31227be 100644 --- a/src/routes/posts/tag/[tag]/+page.svelte +++ b/src/routes/posts/tag/[tag]/+page.svelte @@ -1,15 +1,15 @@

Testing

{#each posts as article} - + {/each} diff --git a/src/routes/projects/+page.svelte b/src/routes/projects/+page.svelte index b328825..446acca 100644 --- a/src/routes/projects/+page.svelte +++ b/src/routes/projects/+page.svelte @@ -19,14 +19,14 @@ />

Working full time on the 'iron road', left me wanting a faster way to get the information I - needed. OwlBoard evolved from Athena and grew to provide more - information that frontline rail colleagues need. + needed. OwlBoard evolved from Athena and grew to provide more information + that frontline rail colleagues need.

map-dots


- +

I like to collect data, I am just not always sure what to do with that data. map-dots takes in diff --git a/static/images/posts/sveltekit-dev-ribbon/owlboard-devmode.png b/static/images/posts/sveltekit-dev-ribbon/owlboard-devmode.png new file mode 100644 index 0000000..a93de84 Binary files /dev/null and b/static/images/posts/sveltekit-dev-ribbon/owlboard-devmode.png differ