Cory McWilliams
ae2015a604
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4669 ed5197a5-7fde-0310-b194-c3ffbd925b24
149 lines
4.8 KiB
JavaScript
149 lines
4.8 KiB
JavaScript
import * as commonmark from './commonmark.min.js';
|
|
|
|
function escape(text) {
|
|
return (text ?? '').replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>');
|
|
}
|
|
|
|
function escapeAttribute(text) {
|
|
return (text ?? '').replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
|
|
}
|
|
|
|
function markdown(md) {
|
|
let reader = new commonmark.Parser({safe: true});
|
|
let writer = new commonmark.HtmlRenderer();
|
|
let parsed = reader.parse(md || '');
|
|
let walker = parsed.walker();
|
|
let event, node;
|
|
while ((event = walker.next())) {
|
|
node = event.node;
|
|
if (event.entering) {
|
|
if (node.type == 'image') {
|
|
if (node.destination.startsWith('&')) {
|
|
node.destination = '/' + node.destination + '/view';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return writer.render(parsed);
|
|
}
|
|
|
|
export async function render_blog_post_html(blog_post) {
|
|
let blob = utf8Decode(await ssb.blobGet(blog_post.blog));
|
|
return `<!DOCTYPE html>
|
|
<html>
|
|
<body>
|
|
<div>
|
|
<div><a href="../ssb/#${escapeAttribute(blog_post.author)}">${escape(blog_post.name)}</a> ${escape(new Date(blog_post.timestamp).toString())}</div>
|
|
<div>${markdown(blob)}</div>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
`;
|
|
}
|
|
|
|
function render_blog_post(blog_post) {
|
|
return `
|
|
<div>
|
|
<h2><a href="../ssb/#${escapeAttribute(blog_post.id)}">${escape(blog_post.title)}</a></h2>
|
|
<div><a href="../ssb/#${escapeAttribute(blog_post.author)}">${escape(blog_post.name)}</a> ${escape(new Date(blog_post.timestamp).toString())}</div>
|
|
<div>${markdown(blog_post.summary)}</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
export function render_html(blogs) {
|
|
return `<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>🪵Tilde Blog</title>
|
|
<link href="./atom" type="application/atom+xml" rel="alternate" title="🪵Tilde Blog"/>
|
|
<style>
|
|
html {
|
|
background-color: #ccc;
|
|
}
|
|
</style>
|
|
<base target="_blank">
|
|
</head>
|
|
<body>
|
|
<div style="display: flex; flex-direction: row; align-items: center; gap: 1em">
|
|
<h1>🪵Tilde Blog</h1>
|
|
<div style="font-size: xx-small; vertical-align: middle"><a href="/~cory/blog/atom">atom feed</a></div>
|
|
</div>
|
|
${blogs.map(blog_post => render_blog_post(blog_post)).join('\n')}
|
|
</body>
|
|
</html>`;
|
|
}
|
|
|
|
function render_blog_post_atom(blog_post) {
|
|
return `<entry>
|
|
<title>${escape(blog_post.title)}</title>
|
|
<link href="https://tildefriends.net/~cory/ssb/#${blog_post.id}" />
|
|
<id>${blog_post.id}</id>
|
|
<published>${escape(new Date(blog_post.timestamp).toString())}</published>
|
|
<summary>${escape(blog_post.summary)}</summary>
|
|
<author>
|
|
<name>${escape(blog_post.name)}</name>
|
|
<feed>${escape(blog_post.author)}</feed>
|
|
</author>
|
|
</entry>`;
|
|
}
|
|
|
|
export function render_atom(blogs) {
|
|
return `<?xml version="1.0" encoding="utf-8"?>
|
|
<feed xmlns="http://www.w3.org/2005/Atom">
|
|
<title>🪵Tilde Blog</title>
|
|
<subtitle>A subtitle.</subtitle>
|
|
<link href="https://tildefriends.net/~cory/blog/atom" rel="self"/>
|
|
<link href="https://tildefriends.net/~cory/blog/"/>
|
|
<id>https://www.tildefriends.net/~cory/blog/</id>
|
|
<updated>${new Date().toString()}</updated>
|
|
${blogs.map(blog_post => render_blog_post_atom(blog_post)).join('\n')}
|
|
</feed>`;
|
|
}
|
|
|
|
export async function get_posts() {
|
|
let blogs = [];
|
|
await ssb.sqlAsync(`
|
|
WITH
|
|
blogs AS (
|
|
SELECT
|
|
messages.author,
|
|
messages.id,
|
|
json_extract(messages.content, '$.title') AS title,
|
|
json_extract(messages.content, '$.summary') AS summary,
|
|
json_extract(messages.content, '$.blog') AS blog,
|
|
messages.timestamp
|
|
FROM messages_fts('blog')
|
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
|
WHERE json_extract(messages.content, '$.type') = 'blog'),
|
|
public AS (
|
|
SELECT author FROM (
|
|
SELECT
|
|
messages.author,
|
|
RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank,
|
|
json_extract(messages.content, '$.publicWebHosting') AS is_public
|
|
FROM messages_fts('about')
|
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
|
WHERE json_extract(messages.content, '$.type') = 'about' AND is_public IS NOT NULL)
|
|
WHERE author_rank = 1 AND is_public),
|
|
names AS (
|
|
SELECT author, name FROM (
|
|
SELECT
|
|
messages.author,
|
|
RANK() OVER (PARTITION BY messages.author ORDER BY messages.sequence DESC) AS author_rank,
|
|
json_extract(messages.content, '$.name') AS name
|
|
FROM messages_fts('about')
|
|
JOIN messages ON messages.rowid = messages_fts.rowid
|
|
WHERE json_extract(messages.content, '$.type') = 'about' AND
|
|
json_extract(messages.content, '$.about') = messages.author AND
|
|
name IS NOT NULL)
|
|
WHERE author_rank = 1)
|
|
SELECT blogs.*, names.name FROM blogs
|
|
JOIN public ON public.author = blogs.author
|
|
LEFT OUTER JOIN names ON names.author = blogs.author
|
|
ORDER BY blogs.timestamp DESC LIMIT 20
|
|
`, [], function(row) {
|
|
blogs.push(row);
|
|
});
|
|
return blogs;
|
|
} |