Skip to content

Commit 529f720

Browse files
committed
Introduce blog post tab
Posts previews are automatically populated from social data from labs public URLs
1 parent 71715e5 commit 529f720

File tree

7 files changed

+205
-0
lines changed

7 files changed

+205
-0
lines changed

package-lock.json

Lines changed: 133 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@xterm/xterm": "^5.5.0",
2020
"autoprefixer": "^10.4.20",
2121
"labs": "[email protected]:leaningtech/labs.git",
22+
"node-html-parser": "^6.1.13",
2223
"postcss": "^8.4.47",
2324
"postcss-discard": "^2.0.0",
2425
"svelte": "^4.2.7",

postcss.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default {
1717
case '.fa-star:before':
1818
case '.fa-circle:before':
1919
case '.fa-trash-can:before':
20+
case '.fa-book-open:before':
2021
return false;
2122
}
2223
return true;

src/lib/BlogPost.svelte

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<script>
2+
export let title;
3+
export let image;
4+
export let url;
5+
</script>
6+
<a href={url} target="_blank"><div class="bg-neutral-700 hover:bg-neutral-500 p-2 rounded-md">
7+
<img class="w-56 h-32 object-fit" src={image}>
8+
<h2 class="text-sm font-bold">{title}</h2>
9+
</div></a>

src/lib/PostsTab.svelte

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script>
2+
import BlogPost from './BlogPost.svelte';
3+
import { page } from '$app/stores';
4+
</script>
5+
<h1 class="text-lg font-bold">Blog posts</h1>
6+
<div class="overflow-y-scroll scrollbar flex flex-col gap-2">
7+
{#each $page.data.posts as post}
8+
<BlogPost
9+
title={post.title}
10+
image={post.image}
11+
url={post.url}
12+
/>
13+
{/each}
14+
</div>

src/lib/SideBar.svelte

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import NetworkingTab from './NetworkingTab.svelte';
55
import CpuTab from './CpuTab.svelte';
66
import DiskTab from './DiskTab.svelte';
7+
import PostsTab from './PostsTab.svelte';
78
import DiscordTab from './DiscordTab.svelte';
89
import GitHubTab from './GitHubTab.svelte';
910
import { cpuActivity, diskActivity } from './activities.js'
@@ -14,6 +15,7 @@
1415
{ icon: 'fas fa-microchip', info: 'CPU', activity: cpuActivity },
1516
{ icon: 'fas fa-compact-disc', info: 'Disk', activity: diskActivity },
1617
null,
18+
{ icon: 'fas fa-book-open', info: 'Posts', activity: null },
1719
{ icon: 'fab fa-discord', info: 'Discord', activity: null },
1820
{ icon: 'fab fa-github', info: 'GitHub', activity: null },
1921
];
@@ -53,6 +55,8 @@
5355
<CpuTab/>
5456
{:else if activeInfo === 'Disk'}
5557
<DiskTab on:reset/>
58+
{:else if activeInfo === 'Posts'}
59+
<PostsTab/>
5660
{:else if activeInfo === 'Discord'}
5761
<DiscordTab/>
5862
{:else if activeInfo === 'GitHub'}

src/routes/+layout.server.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { parse } from 'node-html-parser';
2+
import { read } from '$app/server';
3+
4+
var posts = [
5+
"https://labs.leaningtech.com/blog/join-the-webvm-hackathon",
6+
"https://labs.leaningtech.com/blog/mini-webvm-your-linux-box-from-dockerfile-via-wasm",
7+
"https://labs.leaningtech.com/blog/webvm-virtual-machine-with-networking-via-tailscale",
8+
"https://labs.leaningtech.com/blog/webvm-server-less-x86-virtual-machines-in-the-browser",
9+
];
10+
11+
async function getPostData(u)
12+
{
13+
var ret = { title: null, image: null, url: u };
14+
var response = await fetch(u);
15+
var str = await response.text();
16+
var root = parse(str);
17+
var tags = root.getElementsByTagName("meta");
18+
for(var i=0;i<tags.length;i++)
19+
{
20+
var metaName = tags[i].getAttribute("property");
21+
var metaContent = tags[i].getAttribute("content");
22+
switch(metaName)
23+
{
24+
case "og:title":
25+
ret.title = metaContent;
26+
break;
27+
case "og:image":
28+
ret.image = metaContent;
29+
break;
30+
}
31+
}
32+
return ret;
33+
}
34+
35+
export async function load()
36+
{
37+
var ret = [];
38+
for(var i=0;i<posts.length;i++)
39+
{
40+
ret.push(await getPostData(posts[i]));
41+
}
42+
return { posts: ret };
43+
}

0 commit comments

Comments
 (0)