87 lines
3.7 KiB
Text
87 lines
3.7 KiB
Text
---
|
|
import { getCollection } from 'astro:content';
|
|
import Layout from '../layouts/Layout.astro';
|
|
import { getApprovedEntries, type GuestbookEntry } from '../lib/db';
|
|
import { formatDate, formatListItem, escapeHtml } from '../lib/format';
|
|
import { organizePostsByCategory, getSlug, enrichPostsWithDates } from '../lib/md';
|
|
import { getTxtFiles } from '../lib/txt';
|
|
import { DEFAULT_CATEGORY, SECTIONS, SUBDOMAINS } from '../lib/consts';
|
|
|
|
const rawPosts = await getCollection('md');
|
|
const posts = enrichPostsWithDates(rawPosts);
|
|
const { grouped, categories: sortedCategories } = organizePostsByCategory(posts);
|
|
|
|
const bookmarksCollection = await getCollection('bookmarks');
|
|
const bookmarks = bookmarksCollection
|
|
.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
|
|
|
|
const txtFiles = getTxtFiles();
|
|
|
|
let guestbookEntries: GuestbookEntry[] = [];
|
|
try {
|
|
guestbookEntries = await getApprovedEntries();
|
|
} catch {
|
|
// DB not available during dev without env vars
|
|
}
|
|
|
|
const urls = [
|
|
...posts.map(post => ({ url: `/${getSlug(post.id)}`, date: post.dates.created.getTime() })),
|
|
...txtFiles.map(f => ({ url: `/${f.name}`, date: f.date.getTime() })),
|
|
].sort((a, b) => b.date - a.date).map(e => e.url).concat(SUBDOMAINS);
|
|
---
|
|
<Layout title="lewis m.w." isHome urls={urls}>
|
|
|
|
{sortedCategories.map(category => {
|
|
const categoryPosts = grouped[category];
|
|
const isDefault = category === DEFAULT_CATEGORY;
|
|
return (
|
|
<section data-section={category}>
|
|
{!isDefault && <a class="section-label" href={`?just=${category}`}>{category}</a>}
|
|
<div class="entry-list" set:html={categoryPosts.map(post =>
|
|
`<span class="entry">${formatListItem(post.dates.created, `/${getSlug(post.id)}`, post.data.title, { pinned: post.data.pinned })}</span>`
|
|
).join('')} />
|
|
</section>
|
|
);
|
|
})}
|
|
|
|
<section data-section={SECTIONS.plaintext}>
|
|
<a class="section-label" href={`?just=${SECTIONS.plaintext}`}>{SECTIONS.plaintext}</a>
|
|
<div class="entry-list" set:html={txtFiles.map(f => {
|
|
const name = f.name.replace(/\.txt$/, '');
|
|
return `<span class="entry">${formatListItem(f.date, `/${f.name}`, name, { pinned: f.pinned })}</span>`;
|
|
}).join('')} />
|
|
</section>
|
|
|
|
<section data-section={SECTIONS.bookmarks}>
|
|
<a class="section-label" href={`?just=${SECTIONS.bookmarks}`}>{SECTIONS.bookmarks}</a>
|
|
<div class="entry-list" set:html={bookmarks.map(b =>
|
|
`<span class="entry">${formatListItem(b.data.date, b.data.url, b.data.title)}</span>`
|
|
).join('')} />
|
|
</section>
|
|
|
|
<section data-section={SECTIONS.guestbook}>
|
|
<a class="section-label" href={`?just=${SECTIONS.guestbook}`}>{SECTIONS.guestbook}</a>
|
|
<div class="guestbook-entries" set:html={guestbookEntries.map(e => {
|
|
const safeName = escapeHtml(e.name);
|
|
const safeMessage = escapeHtml(e.message.replace(/\n/g, ' '));
|
|
const nameHtml = e.url ? `<a href="${escapeHtml(e.url)}"><b>${safeName}</b></a>` : `<b>${safeName}</b>`;
|
|
return `<span class="guestbook-entry"><span class="list-meta"><span class="muted">${formatDate(e.createdAt)}</span> </span><span>${nameHtml} ${safeMessage}</span></span>`;
|
|
}).join('')} /></div>
|
|
<form id="guestbook-form" class="guestbook-form">
|
|
<label class="sr-only" for="gb-name">name</label>
|
|
<input id="gb-name" type="text" name="name" placeholder="name" required maxlength="100" /><br />
|
|
<label class="sr-only" for="gb-message">message</label>
|
|
<input id="gb-message" type="text" name="message" placeholder="message" required maxlength="500" /><br />
|
|
<label class="sr-only" for="gb-url">url</label>
|
|
<input id="gb-url" type="url" name="url" placeholder="url (optional)" maxlength="200" /><br />
|
|
<button type="submit">sign</button>
|
|
<span id="guestbook-status"></span>
|
|
</form>
|
|
</section>
|
|
|
|
<script>
|
|
import { initGuestbookForm } from '../scripts/guestbook-sign';
|
|
initGuestbookForm();
|
|
|
|
</script>
|
|
</Layout>
|