| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | import * as commonmark from './commonmark.min.js'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function escape(text) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 	return (text ?? '') | 
					
						
							|  |  |  | 		.replaceAll('&', '&') | 
					
						
							|  |  |  | 		.replaceAll('<', '<') | 
					
						
							|  |  |  | 		.replaceAll('>', '>'); | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function escapeAttribute(text) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 	return (text ?? '') | 
					
						
							|  |  |  | 		.replaceAll('&', '&') | 
					
						
							|  |  |  | 		.replaceAll('<', '<') | 
					
						
							|  |  |  | 		.replaceAll('>', '>') | 
					
						
							|  |  |  | 		.replaceAll('"', '"') | 
					
						
							|  |  |  | 		.replaceAll("'", '''); | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | export async function get_blog_message(id) { | 
					
						
							|  |  |  | 	let message; | 
					
						
							|  |  |  | 	await ssb.sqlAsync( | 
					
						
							|  |  |  | 		'SELECT author, timestamp, content FROM messages WHERE id = ?', | 
					
						
							|  |  |  | 		[id], | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		function (row) { | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | 			let content = JSON.parse(row.content); | 
					
						
							|  |  |  | 			message = { | 
					
						
							|  |  |  | 				author: row.author, | 
					
						
							|  |  |  | 				timestamp: row.timestamp, | 
					
						
							|  |  |  | 				blog: content?.blog, | 
					
						
							|  |  |  | 				title: content?.title, | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | 	if (message) { | 
					
						
							|  |  |  | 		await ssb.sqlAsync( | 
					
						
							|  |  |  | 			`
 | 
					
						
							|  |  |  | 				SELECT json_extract(content, '$.name') AS name | 
					
						
							|  |  |  | 				FROM messages | 
					
						
							|  |  |  | 				WHERE author = ? | 
					
						
							|  |  |  | 				AND json_extract(content, '$.type') = 'about' | 
					
						
							|  |  |  | 				AND json_extract(content, '$.about') = author | 
					
						
							|  |  |  | 				AND name IS NOT NULL | 
					
						
							|  |  |  | 				ORDER BY sequence DESC LIMIT 1 | 
					
						
							|  |  |  | 			`,
 | 
					
						
							|  |  |  | 			[message.author], | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			function (row) { | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | 				message.name = row.name; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return message; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-10 02:23:40 +00:00
										 |  |  | export function markdown(md) { | 
					
						
							| 
									
										
										
										
											2024-11-12 20:43:03 -05:00
										 |  |  | 	let reader = new commonmark.Parser(); | 
					
						
							|  |  |  | 	let writer = new commonmark.HtmlRenderer({safe: true}); | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 	let parsed = reader.parse(md || ''); | 
					
						
							|  |  |  | 	let walker = parsed.walker(); | 
					
						
							|  |  |  | 	let event, node; | 
					
						
							|  |  |  | 	while ((event = walker.next())) { | 
					
						
							|  |  |  | 		node = event.node; | 
					
						
							|  |  |  | 		if (event.entering) { | 
					
						
							| 
									
										
										
										
											2024-01-10 02:23:40 +00:00
										 |  |  | 			if (node.destination?.startsWith('&')) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				node.destination = | 
					
						
							|  |  |  | 					'/' + node.destination + '/view?filename=' + node.firstChild?.literal; | 
					
						
							|  |  |  | 			} else if ( | 
					
						
							|  |  |  | 				node.destination?.startsWith('@') || | 
					
						
							|  |  |  | 				node.destination?.startsWith('%') | 
					
						
							|  |  |  | 			) { | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | 				node.destination = '/~core/ssb/#' + escape(node.destination); | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	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> | 
					
						
							| 
									
										
										
										
											2024-01-10 02:23:40 +00:00
										 |  |  | 			<head> | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | 				<title>🪵Tilde Friends Blog - ${markdown(blog_post.title)}</title> | 
					
						
							| 
									
										
										
										
											2024-01-10 02:23:40 +00:00
										 |  |  | 				<base target="_top"> | 
					
						
							|  |  |  | 			</head> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 			<body> | 
					
						
							| 
									
										
										
										
											2024-01-11 00:33:53 +00:00
										 |  |  | 				<h1><a href="./">🪵Tilde Friends Blog</a></h1> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 				<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> | 
					
						
							| 
									
										
										
										
											2024-01-11 00:50:12 +00:00
										 |  |  | 			<h2><a href="/~${core.app.owner}/${core.app.name}/${escapeAttribute(blog_post.id)}">${escape(blog_post.title)}</a></h2> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 			<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> | 
					
						
							| 
									
										
										
										
											2024-01-02 22:21:13 +00:00
										 |  |  | 				<title>🪵Tilde Friends Blog</title> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 				<link href="./atom" type="application/atom+xml" rel="alternate" title="🪵Tilde Blog"/> | 
					
						
							|  |  |  | 				<style> | 
					
						
							|  |  |  | 					html { | 
					
						
							|  |  |  | 						background-color: #ccc; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				</style> | 
					
						
							| 
									
										
										
										
											2024-01-10 02:23:40 +00:00
										 |  |  | 				<base target="_top"> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 			</head> | 
					
						
							|  |  |  | 			<body> | 
					
						
							|  |  |  | 				<div style="display: flex; flex-direction: row; align-items: center; gap: 1em"> | 
					
						
							| 
									
										
										
										
											2024-01-10 02:23:40 +00:00
										 |  |  | 					<h1>🪵Tilde Friends Blog</h1> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 					<div style="font-size: xx-small; vertical-align: middle"><a href="/~cory/blog/atom">atom feed</a></div> | 
					
						
							|  |  |  | 				</div> | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				${blogs.map((blog_post) => render_blog_post(blog_post)).join('\n')} | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 			</body> | 
					
						
							|  |  |  | 		</html>`; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function render_blog_post_atom(blog_post) { | 
					
						
							|  |  |  | 	return `<entry>
 | 
					
						
							|  |  |  | 		<title>${escape(blog_post.title)}</title> | 
					
						
							| 
									
										
										
										
											2024-01-02 22:21:13 +00:00
										 |  |  | 		<link href="/~cory/ssb/#${blog_post.id}" /> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 		<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> | 
					
						
							| 
									
										
										
										
											2024-01-02 22:21:13 +00:00
										 |  |  | 	<link href="${core.url}/atom" rel="self"/> | 
					
						
							|  |  |  | 	<link href="${core.url}"/> | 
					
						
							|  |  |  | 	<id>${core.url}</id> | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 	<updated>${new Date().toString()}</updated> | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 	${blogs.map((blog_post) => render_blog_post_atom(blog_post)).join('\n')} | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | </feed>`; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export async function get_posts() { | 
					
						
							|  |  |  | 	let blogs = []; | 
					
						
							| 
									
										
										
										
											2024-01-11 01:02:47 +00:00
										 |  |  | 	let ids = await ssb.getIdentities(); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 	await ssb.sqlAsync( | 
					
						
							|  |  |  | 		`
 | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 		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 | 
					
						
							| 
									
										
										
										
											2024-01-11 01:02:47 +00:00
										 |  |  | 		JOIN json_each(?) AS self ON self.value = blogs.author | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 		JOIN public ON public.author = blogs.author | 
					
						
							|  |  |  | 		LEFT OUTER JOIN names ON names.author = blogs.author | 
					
						
							|  |  |  | 		ORDER BY blogs.timestamp DESC LIMIT 20 | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 	`,
 | 
					
						
							|  |  |  | 		[JSON.stringify(ids)], | 
					
						
							|  |  |  | 		function (row) { | 
					
						
							|  |  |  | 			blogs.push(row); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2023-12-09 20:25:49 +00:00
										 |  |  | 	return blogs; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | } |