A simple AtProto app to read pet.mewsse.link records on my PDS.

Front render

Mewsse 9f299071 197a66ae

Changed files
+82 -60
src
+20 -20
src/lib/logger.ts
···
interface logLevelgInterface {
-
[key:string]: number
+
[key: string]: number
}
export const logger = {
-
debug: logDebug,
-
info: logInfo,
-
warn: logWarn,
-
error: logError,
-
fatal: logFatal
+
debug: logDebug,
+
info: logInfo,
+
warn: logWarn,
+
error: logError,
+
fatal: logFatal
}
-
export const logLevel:logLevelgInterface = {
-
DEBUG: 5,
-
INFO: 4,
-
WARN: 3,
-
ERROR: 2,
-
FATAL: 1,
+
export const logLevel: logLevelgInterface = {
+
DEBUG: 5,
+
INFO: 4,
+
WARN: 3,
+
ERROR: 2,
+
FATAL: 1,
} as const
export function log(level: number, type: string, message: any): void {
-
const envLevel = process.env.LOG_LEVEL ? logLevel[process.env.LOG_LEVEL] : logLevel.INFO
-
if (level > envLevel) return
+
const envLevel = process.env.LOG_LEVEL ? logLevel[process.env.LOG_LEVEL] : logLevel.INFO
+
if (level > envLevel) return
-
console.log(`${type} ${new Date().toISOString()}: ${message}`)
+
console.log(`${type} ${new Date().toISOString()}: ${message}`)
}
function logDebug(message: any): void {
-
log(logLevel.DEBUG, "[DEBUG]", message)
+
log(logLevel.DEBUG, "[DEBUG]", message)
}
function logInfo(message: any): void {
-
log(logLevel.INFO, "[INFO]", message)
+
log(logLevel.INFO, "[INFO]", message)
}
function logWarn(message: any): void {
-
log(logLevel.WARN, "[WARN]", message)
+
log(logLevel.WARN, "[WARN]", message)
}
function logError(message: any): void {
-
log(logLevel.ERROR, "[WARN]", message)
+
log(logLevel.ERROR, "[WARN]", message)
}
function logFatal(message: any): void {
-
log(logLevel.ERROR, "[WARN]", message)
+
log(logLevel.ERROR, "[WARN]", message)
}
+45 -3
src/routes.ts
···
import { Eta } from "eta"
import type { Database } from './db.ts'
+
import { IncomingMessage, ServerResponse } from "node:http"
export const createRoutes = (router: Router, db: Database) => {
const eta = new Eta({ views: path.join(import.meta.dirname, "views") })
+
const itemPerPages = parseInt(process.env.ITEM_PER_PAGES || "10", 10)
-
router.get('/', async (req, res) => {
+
async function renderPage (
+
req:IncomingMessage,
+
res:ServerResponse<IncomingMessage>,
+
params:{[key:string]: string} | undefined
+
) {
+
const offset = params ? parseInt(params?.page, 10) - 1 : 0
+
const links = await db
.selectFrom("links")
.selectAll()
.orderBy("createdAt", "desc")
-
.limit(10)
+
.offset(offset)
+
.limit(itemPerPages)
.execute()
-
const body = eta.render("./main", { items: links, pages: [] })
+
+
const totalLink = await db
+
.selectFrom("links")
+
.select(db.fn.countAll().as("count"))
+
.executeTakeFirstOrThrow()
+
+
const pages = Math.ceil(parseInt(totalLink.count.toString(), 10) / itemPerPages)
+
+
const body = eta.render("./main", {
+
items: links,
+
pages: Array.from(Array(pages).keys()),
+
selected: parseInt(params?.page || "0", 10)
+
})
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(body)
+
}
+
+
router.get('/', async (req, res, params) => {
+
await renderPage(req, res, params)
})
router.get('/page/{page:number}', async (req, res, params) => {
+
await renderPage(req, res, params)
+
})
+
+
router.get('/feed.atom', async (req, res, params) => {
+
const links = await db
+
.selectFrom("links")
+
.selectAll()
+
.orderBy("createdAt", "desc")
+
.limit(20)
+
.execute()
+
+
const date = new Date(links[0].createdAt);
+
+
const body = eta.render("./feed", { items: links, date })
+
res.writeHead(200, { 'Content-Type': 'application/atom+xml' })
+
res.end(body)
+
res.end()
})
}
+6 -6
src/views/feed.eta
···
<% it.items.forEach(function (item) { %>
<entry>
<title><%= item.title %></title>
-
<link rel="alternate" type="text/html" href="<%= item.url %>"/>
-
<id><%= item.url %></id>
-
<published><%= new Date(item.date).toISOString() %></published>
-
<updated><%= new Date(item.date).toISOString() %></updated>
+
<link rel="alternate" type="text/html" href="<%= item.link %>"/>
+
<id><%= item.link %></id>
+
<published><%= new Date(item.createdAt).toISOString() %></published>
+
<updated><%= new Date(item.createdAt).toISOString() %></updated>
<content type="html">
<![CDATA[
-
<h2><a href="<%= item.url %>"><%= item.title %></a></h2>
+
<h2><a href="<%= item.link %>"><%= item.title %></a></h2>
<% if (item.description) { %>
<p><%~ item.description %></p>
<% } %>
<% if (item.image) { %>
-
<img src="<%= item.image %>" />
+
<img src="<%= item.image %>" <% if (item.alt){ %>alt="<%= item.alt %>"<% } %> />
<% } %>
]]>
</content>
+6 -6
src/views/link.eta
···
<div class="item <% if (it.nsfw) { %>nsfw<% } %> <% if (it.big) { %>big<% } %>">
<section>
-
<h2><a href="<%= it.url %>"><%= it.title %></a></h2>
+
<h2><a href="<%= it.link %>"><%= it.title %></a></h2>
<% if (it.description) { %>
<div class="description"><%~ it.description %></div>
<% } %>
</section>
<% if (it.nsfw) { %>
-
<label class="aside <% if (!it.image) { %>empty<% } %>" target="<%= it.id %>">
-
<input type="checkbox" id="<%= it.id %>">
+
<label class="aside <% if (!it.image) { %>empty<% } %>" target="<%= it.rkey %>">
+
<input type="checkbox" id="<%= it.rkey %>">
<% if (it.image) { %>
-
<img src="<%= it.image %>">
+
<img src="<%= it.image %>" <% if (it.alt) { %>alt="<%= it.alt %>"<% } %>>
<% } %>
</label>
<% } else { %>
-
<a class="aside <% if (!it.image) { %>empty<% } %>" href="<%= it.url %>">
+
<a class="aside <% if (!it.image) { %>empty<% } %>" href="<%= it.link %>">
<% if (it.image) { %>
-
<img src="<%= it.image %>">
+
<img src="<%= it.image %>" <% if (it.alt) { %>alt="<%= it.alt %>"<% } %>>
<% } %>
</a>
<% } %>
+5 -25
src/views/pagination.eta
···
<ul>
<% if (it.selected > 0) { %>
-
<% if (it.dir) {%>
-
<li><a href="/<%=it.dir%>/<% if (it.selected > 2) { %>/page-<%= it.selected %>.html<% } %>">Previous</a></li>
-
<% } else { %>
-
<li><a href="/<% if (it.selected > 2) { %>pages/page-<%= it.selected %>.html<% } %>">Previous</a></li>
-
<% } %>
+
<li><a href="/<% if (it.selected > 2) { %>page/<%= it.selected %><% } %>">Previous</a></li>
<% } %>
<% if(it.pages.length > 4 && it.selected > 2) { %>
-
<% if (it.dir) {%>
-
<li><a href="/<%=it.dir%>">1</a></li>
-
<% } else { %>
-
<li><a href="/">1</a></li>
-
<% } %>
+
<li><a href="/">1</a></li>
<li>...</li>
<% } %>
···
<% if (page + it.selected - 2 == it.selected) { %>
<li class="selected"><%= it.selected - 2 + page + 1%></li>
<% } else { %>
-
<% if (it.dir) {%>
-
<li><a href="/<%=it.dir%>/<% if (page > 1) { %>page-<%= it.selected + page + 1 - 2%>.html<% } %>"><%= it.selected + page + 1 - 2%></a></li>
-
<% } else { %>
-
<li><a href="/<% if (page > 1) { %>pages/page-<%= it.selected + page + 1 - 2%>.html<% } %>"><%= it.selected + page + 1 - 2%></a></li>
-
<% } %>
+
<li><a href="/<% if (page > 0) { %>page/<%= it.selected + page + 1 - 2%><% } %>"><%= it.selected + page + 1 - 2%></a></li>
<% } %>
<% } %>
<% }) %>
<% if(it.pages.length > 4 && it.selected < it.pages.length-3) { %>
<li>...</li>
-
<% if (it.dir) {%>
-
<li><a href="/<%=it.dir%>/page-<%= it.pages.length %>.html"><%= it.pages.length %></a></li>
-
<% } else { %>
-
<li><a href="/pages/page-<%= it.pages.length %>.html"><%= it.pages.length %></a></li>
-
<% } %>
+
<li><a href="/page/<%= it.pages.length %>"><%= it.pages.length %></a></li>
<% } %>
<% if (it.selected+1 < it.pages.length) { %>
-
<% if (it.dir) {%>
-
<li><a href="/<%=it.dir%>/page-<%= it.selected + 2%>.html">Next</a></li>
-
<% } else { %>
-
<li><a href="/pages/page-<%= it.selected + 2%>.html">Next</a></li>
-
<% } %>
+
<li><a href="/page/<%= it.selected + 2%>">Next</a></li>
<% } %>
</ul>