feat: switch to Astro DB for guestbook

- Add @astrojs/db integration
- Define Guestbook schema in db/config.ts
- Add seed data for development
- Update db.ts to use astro:db
- Add guestbook section to homepage with form
- Update env vars to use ASTRO_DB_REMOTE_URL
This commit is contained in:
Lewis Wynne 2026-01-23 04:10:51 +00:00
parent 4e2c09b770
commit 79c7aff48b
9 changed files with 365 additions and 37 deletions

View file

@ -5,6 +5,7 @@ import yaml from 'js-yaml';
import bookmarksRaw from '../data/bookmarks.yaml?raw';
import fs from 'node:fs';
import path from 'node:path';
import { getApprovedEntries, type GuestbookEntry } from '../lib/db';
interface Bookmark {
date: string;
@ -35,6 +36,13 @@ const txtFiles: TxtFile[] = fs.existsSync(txtDir)
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime())
: [];
let guestbookEntries: GuestbookEntry[] = [];
try {
guestbookEntries = await getApprovedEntries();
} catch {
// DB not available during dev without env vars
}
function formatDate(date: Date): string {
const d = String(date.getDate()).padStart(2, '0');
const m = String(date.getMonth() + 1).padStart(2, '0');
@ -78,5 +86,47 @@ function extractDomain(url: string): string {
<summary>bookmarks</summary>
<pre set:html={bookmarks.map(b => `<span class="muted">${formatBookmarkDate(b.date)}</span> <a href="${b.url}">${b.title}</a> <span class="muted">(${extractDomain(b.url)})</span>`).join('\n')} />
</details>
<details open>
<summary>guestbook</summary>
<pre set:html={guestbookEntries.length > 0
? guestbookEntries.map(e => `<span class="muted">${formatDate(e.createdAt)}</span> ${e.url ? `<a href="${e.url}">${e.name}</a>` : e.name}: ${e.message}`).join('\n')
: '<span class="muted">no entries yet</span>'} />
<form id="guestbook-form">
<input type="text" name="name" placeholder="name" required maxlength="100" />
<input type="text" name="url" placeholder="url (optional)" maxlength="200" />
<textarea name="message" placeholder="message" required maxlength="500"></textarea>
<button type="submit">sign</button>
</form>
<div id="guestbook-status"></div>
</details>
<script>
const form = document.getElementById('guestbook-form') as HTMLFormElement;
const status = document.getElementById('guestbook-status')!;
form.addEventListener('submit', async (e) => {
e.preventDefault();
const data = Object.fromEntries(new FormData(form));
try {
const res = await fetch('/api/guestbook', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (res.ok) {
status.textContent = 'thanks! your message is pending approval.';
form.reset();
} else {
const err = await res.json();
status.textContent = err.error || 'something went wrong';
}
} catch {
status.textContent = 'failed to submit';
}
});
</script>
</body>
</html>