···11-import type { Database } from '#/db'
11+import type { Database } from '#/db/index'
22import { Firehose } from '#/firehose/firehose'
3344export class Ingester {
···1919 text: post.text as string,
2020 indexedAt: new Date().toISOString(),
2121 })
2222+ .onConflict((oc) => oc.doNothing())
2223 .execute()
2324 }
2425 }
+32
src/pages/home.ts
···11+import { AtUri } from '@atproto/syntax'
22+import type { Post } from '#/db/schema'
33+import { html } from '../view'
44+import { shell } from './shell'
55+66+export function home(posts: Post[]) {
77+ return shell({
88+ title: 'Home',
99+ content: content(posts),
1010+ })
1111+}
1212+1313+function content(posts: Post[]) {
1414+ return html`<div>
1515+ <h1>Welcome to My Page</h1>
1616+ <p>It's pretty special here.</p>
1717+ <ul>
1818+ ${posts.map((post) => {
1919+ return html`<li>
2020+ <a href="${toBskyLink(post.uri)}" target="_blank">🔗</a>
2121+ ${post.text}
2222+ </li>`
2323+ })}
2424+ </ul>
2525+ <a href="/">Give me more</a>
2626+ </div>`
2727+}
2828+2929+function toBskyLink(uriStr: string) {
3030+ const uri = new AtUri(uriStr)
3131+ return `https://bsky.app/profile/${uri.host}/post/${uri.rkey}`
3232+}
+12
src/pages/shell.ts
···11+import { type Hole, html } from '../view'
22+33+export function shell({ title, content }: { title: string; content: Hole }) {
44+ return html`<html>
55+ <head>
66+ <title>${title}</title>
77+ </head>
88+ <body>
99+ ${content}
1010+ </body>
1111+ </html>`
1212+}
+3-2
src/routes/index.ts
···11import express from 'express'
22import type { AppContext } from '#/config'
33+import { home } from '#/pages/home'
44+import { page } from '#/view'
35import { handler } from './util'
4657export const createRouter = (ctx: AppContext) => {
···911 '/',
1012 handler(async (req, res) => {
1113 const posts = await ctx.db.selectFrom('post').selectAll().orderBy('indexedAt', 'desc').limit(10).execute()
1212- const postTexts = posts.map((row) => row.text)
1313- res.json(postTexts)
1414+ return res.type('html').send(page(home(posts)))
1415 }),
1516 )
1617
+12
src/view.ts
···11+// @ts-ignore
22+import ssr from 'uhtml/ssr'
33+import type initSSR from 'uhtml/types/init-ssr'
44+import type { Hole } from 'uhtml/types/keyed'
55+66+export type { Hole }
77+88+export const { html }: ReturnType<typeof initSSR> = ssr()
99+1010+export function page(hole: Hole) {
1111+ return `<!DOCTYPE html>\n${hole.toDOM().toString()}`
1212+}