From 529f720ae18c939099a149675831ba497e57e799 Mon Sep 17 00:00:00 2001 From: Alessandro Pignotti Date: Sat, 19 Oct 2024 11:00:09 +0200 Subject: [PATCH] Introduce blog post tab Posts previews are automatically populated from social data from labs public URLs --- package-lock.json | 133 +++++++++++++++++++++++++++++++++++ package.json | 1 + postcss.config.js | 1 + src/lib/BlogPost.svelte | 9 +++ src/lib/PostsTab.svelte | 14 ++++ src/lib/SideBar.svelte | 4 ++ src/routes/+layout.server.js | 43 +++++++++++ 7 files changed, 205 insertions(+) create mode 100644 src/lib/BlogPost.svelte create mode 100644 src/lib/PostsTab.svelte create mode 100644 src/routes/+layout.server.js diff --git a/package-lock.json b/package-lock.json index c8aca8c..a549dd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@xterm/xterm": "^5.5.0", "autoprefixer": "^10.4.20", "labs": "git@github.com:leaningtech/labs.git", + "node-html-parser": "^6.1.13", "postcss": "^8.4.47", "postcss-discard": "^2.0.0", "svelte": "^4.2.7", @@ -1028,6 +1029,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1221,6 +1228,22 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css-tree": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", @@ -1234,6 +1257,18 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1290,6 +1325,61 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1308,6 +1398,18 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", @@ -1547,6 +1649,15 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, "node_modules/import-meta-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", @@ -1840,6 +1951,16 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-html-parser": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", + "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "dev": true, + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -1864,6 +1985,18 @@ "node": ">=0.10.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", diff --git a/package.json b/package.json index 705ec4d..17b0688 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@xterm/xterm": "^5.5.0", "autoprefixer": "^10.4.20", "labs": "git@github.com:leaningtech/labs.git", + "node-html-parser": "^6.1.13", "postcss": "^8.4.47", "postcss-discard": "^2.0.0", "svelte": "^4.2.7", diff --git a/postcss.config.js b/postcss.config.js index 68dbaac..2cd9025 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -17,6 +17,7 @@ export default { case '.fa-star:before': case '.fa-circle:before': case '.fa-trash-can:before': + case '.fa-book-open:before': return false; } return true; diff --git a/src/lib/BlogPost.svelte b/src/lib/BlogPost.svelte new file mode 100644 index 0000000..c73f026 --- /dev/null +++ b/src/lib/BlogPost.svelte @@ -0,0 +1,9 @@ + +
+ +

{title}

+
diff --git a/src/lib/PostsTab.svelte b/src/lib/PostsTab.svelte new file mode 100644 index 0000000..05f4e64 --- /dev/null +++ b/src/lib/PostsTab.svelte @@ -0,0 +1,14 @@ + +

Blog posts

+
+{#each $page.data.posts as post} + +{/each} +
diff --git a/src/lib/SideBar.svelte b/src/lib/SideBar.svelte index 62e230c..180bc74 100644 --- a/src/lib/SideBar.svelte +++ b/src/lib/SideBar.svelte @@ -4,6 +4,7 @@ import NetworkingTab from './NetworkingTab.svelte'; import CpuTab from './CpuTab.svelte'; import DiskTab from './DiskTab.svelte'; + import PostsTab from './PostsTab.svelte'; import DiscordTab from './DiscordTab.svelte'; import GitHubTab from './GitHubTab.svelte'; import { cpuActivity, diskActivity } from './activities.js' @@ -14,6 +15,7 @@ { icon: 'fas fa-microchip', info: 'CPU', activity: cpuActivity }, { icon: 'fas fa-compact-disc', info: 'Disk', activity: diskActivity }, null, + { icon: 'fas fa-book-open', info: 'Posts', activity: null }, { icon: 'fab fa-discord', info: 'Discord', activity: null }, { icon: 'fab fa-github', info: 'GitHub', activity: null }, ]; @@ -53,6 +55,8 @@ {:else if activeInfo === 'Disk'} + {:else if activeInfo === 'Posts'} + {:else if activeInfo === 'Discord'} {:else if activeInfo === 'GitHub'} diff --git a/src/routes/+layout.server.js b/src/routes/+layout.server.js new file mode 100644 index 0000000..25106b8 --- /dev/null +++ b/src/routes/+layout.server.js @@ -0,0 +1,43 @@ +import { parse } from 'node-html-parser'; +import { read } from '$app/server'; + +var posts = [ + "https://labs.leaningtech.com/blog/join-the-webvm-hackathon", + "https://labs.leaningtech.com/blog/mini-webvm-your-linux-box-from-dockerfile-via-wasm", + "https://labs.leaningtech.com/blog/webvm-virtual-machine-with-networking-via-tailscale", + "https://labs.leaningtech.com/blog/webvm-server-less-x86-virtual-machines-in-the-browser", +]; + +async function getPostData(u) +{ + var ret = { title: null, image: null, url: u }; + var response = await fetch(u); + var str = await response.text(); + var root = parse(str); + var tags = root.getElementsByTagName("meta"); + for(var i=0;i