diff --git a/src/content/config.ts b/src/content/config.ts index aea1cb2..1ed0121 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -42,4 +42,13 @@ const links = defineCollection({ }), }); -export const collections = { blog, coffee, links }; +const guestbook = defineCollection({ + type: "content", + schema: z.object({ + display_name: z.string(), + date: z.coerce.date(), + website: z.string().url().optional(), + }), +}); + +export const collections = { blog, coffee, links, guestbook }; diff --git a/src/content/guestbook/2026-03-09-bunny.md b/src/content/guestbook/2026-03-09-bunny.md new file mode 100644 index 0000000..339e1c3 --- /dev/null +++ b/src/content/guestbook/2026-03-09-bunny.md @@ -0,0 +1,5 @@ +--- +display_name: bunny +date: 2026-03-09 +--- +hii latte! i appreciate you always :3 diff --git a/src/content/guestbook/2026-03-10-isy.md b/src/content/guestbook/2026-03-10-isy.md new file mode 100644 index 0000000..dec6571 --- /dev/null +++ b/src/content/guestbook/2026-03-10-isy.md @@ -0,0 +1,5 @@ +--- +display_name: Isy +date: 2026-03-10 +--- +hii latte! i appreciate you more :3 diff --git a/src/pages/guestbook.astro b/src/pages/guestbook.astro index 48f5725..3bfac53 100644 --- a/src/pages/guestbook.astro +++ b/src/pages/guestbook.astro @@ -1,22 +1,11 @@ --- -export const prerender = false; +export const prerender = true; import BaseLayout from '../layouts/BaseLayout.astro'; -import { getApprovedEntries } from '../lib/guestbook'; +import { getCollection } from 'astro:content'; -const pageParam = parseInt(Astro.url.searchParams.get('page') ?? '1', 10); -const page = isNaN(pageParam) || pageParam < 1 ? 1 : pageParam; - -const { entries, total, hasMore } = getApprovedEntries(page); - -const submitted = Astro.url.searchParams.get('submitted') === 'true'; -const errorParam = Astro.url.searchParams.get('error'); - -const errorMessages: Record = { - rate_limit: 'You\'ve submitted too many messages recently. Please wait a while before trying again.', - invalid: 'Your submission could not be processed. Please check all fields and try again.', -}; -const errorMsg = errorParam ? (errorMessages[errorParam] ?? decodeURIComponent(errorParam)) : null; +const rawEntries = await getCollection('guestbook'); +const entries = rawEntries.sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); --- - -
-
- - Leave a message - - -
-

- Messages are reviewed before being published. Please don't include personal or - sensitive information — this is a public guestbook. -

- - {submitted && ( - - )} - - {errorMsg && ( - - )} - -
- - - -
- - -
- -
- - - Plain text only. Max 1000 characters. -
- -
- - - Only https:// links. Leave blank if you don't have one. -
- - - -
- -
-
-
-
+ +
+

+ Want to leave a message? Send an email to + latte@hiddenden.cafe + and it might end up here. +

- +

Messages - {total > 0 && ({total})} + ({entries.length})

- {entries.length === 0 ? ( -
-

No messages yet. Be the first to leave a note!

-
- ) : ( -
- {entries.map((entry) => ( +
+ {entries.map(async (entry) => { + const { Content } = await entry.render(); + return (
- {entry.website ? ( + {entry.data.website ? ( - {entry.display_name} + {entry.data.display_name} ) : ( - entry.display_name + entry.data.display_name )}
-

{entry.message}

+
- ))} -
- )} - - - {(page > 1 || hasMore) && ( - - )} + ); + })} +
@@ -237,8 +104,7 @@ const errorMsg = errorParam ? (errorMessages[errorParam] ?? decodeURIComponent(e font-size: 0.9rem; } - /* Form */ - .form-section { + .mail-section { background: var(--color-bg-light); border: 1px solid var(--color-surface); border-radius: 8px; @@ -246,191 +112,18 @@ const errorMsg = errorParam ? (errorMessages[errorParam] ?? decodeURIComponent(e margin-bottom: var(--space-lg); } - .form-note { + .mail-note { color: var(--color-text-dim); - font-size: 0.85rem; - margin-bottom: var(--space-md); + font-size: 0.88rem; + margin: 0; } - .compose { - width: 100%; - } - - .compose-toggle { - list-style: none; - cursor: pointer; - display: flex; - align-items: center; - gap: 10px; - color: var(--color-accent-bright); - font-size: 1.1rem; - font-weight: bold; - margin-bottom: var(--space-sm); - user-select: none; - } - - .compose-toggle::-webkit-details-marker { - display: none; - } - - .compose-toggle:focus-visible { - outline: 2px solid var(--color-accent); - outline-offset: 2px; - border-radius: 4px; - } - - .compose-toggle::before { - content: '+'; - display: inline-flex; - align-items: center; - justify-content: center; - width: 1.2em; - height: 1.2em; - border: 1px solid var(--color-accent); - border-radius: 4px; + .mail-note a { color: var(--color-accent); - font-weight: normal; - line-height: 1; } - .compose[open] .compose-toggle::before { - content: '−'; - } - - .compose-body { - margin-top: var(--space-sm); - } - - .guestbook-form { - display: flex; - flex-direction: column; - gap: var(--space-sm); - } - - /* Honeypot: visually hidden but accessible-compatible */ - .hp-field { - position: absolute; - left: -9999px; - width: 1px; - height: 1px; - overflow: hidden; - } - - .field { - display: flex; - flex-direction: column; - gap: 4px; - } - - label { - font-size: 0.88rem; - color: var(--color-text-dim); - } - - .required { - color: var(--color-warm); - margin-left: 2px; - } - - .optional { - color: var(--color-surface); - font-size: 0.82rem; - } - - input[type="text"], - input[type="url"], - textarea { - background: var(--color-bg); - border: 1px solid var(--color-surface); - border-radius: 4px; - color: var(--color-text); - font-family: var(--font-body); - font-size: 0.9rem; - padding: 8px 10px; - width: 100%; - transition: border-color 0.15s; - } - - input:focus, - textarea:focus { - outline: none; - border-color: var(--color-accent); - } - - textarea { - resize: vertical; - min-height: 100px; - } - - .field-hint { - font-size: 0.78rem; - color: var(--color-text-dim); - } - - .consent-field { - margin-top: var(--space-xs); - } - - .consent-label { - display: flex; - align-items: flex-start; - gap: 8px; - cursor: pointer; - font-size: 0.88rem; - color: var(--color-text-dim); - } - - .consent-label input[type="checkbox"] { - margin-top: 3px; - flex-shrink: 0; - accent-color: var(--color-accent); - width: auto; - } - - .form-actions { - margin-top: var(--space-xs); - } - - .btn-submit { - background: var(--color-accent); - color: var(--color-bg); - border: none; - border-radius: 4px; - padding: 8px 20px; - font-family: var(--font-body); - font-size: 0.9rem; - cursor: pointer; - transition: opacity 0.15s; - } - - .btn-submit:hover { - opacity: 0.85; - } - - .btn-submit:focus-visible { - outline: 2px solid var(--color-accent); - outline-offset: 2px; - } - - /* Alerts */ - .alert { - padding: var(--space-sm); - border-radius: 4px; - margin-bottom: var(--space-sm); - border: 1px solid; - font-size: 0.88rem; - } - - .alert-success { - border-color: var(--color-green); - color: var(--color-green); - background: color-mix(in srgb, var(--color-green) 10%, transparent); - } - - .alert-error { - border-color: var(--color-warm); - color: var(--color-warm); - background: color-mix(in srgb, var(--color-warm) 10%, transparent); + .mail-note a:hover { + color: var(--color-accent-bright); } /* Entries */ @@ -485,37 +178,12 @@ const errorMsg = errorParam ? (errorMessages[errorParam] ?? decodeURIComponent(e .entry-message { color: var(--color-text); font-size: 0.9rem; - white-space: pre-wrap; word-break: break-word; line-height: 1.5; } - .empty-state { - background: var(--color-bg-light); - border: 1px solid var(--color-surface); - border-radius: 6px; - padding: var(--space-md); - color: var(--color-text-dim); - font-size: 0.9rem; - text-align: center; - } - - /* Pagination */ - .pagination { - display: flex; - align-items: center; - justify-content: center; - gap: var(--space-md); - margin-top: var(--space-lg); - font-size: 0.88rem; - } - - .page-link { - color: var(--color-accent); - } - - .page-info { - color: var(--color-text-dim); + .entry-message p { + margin: 0; } @media (max-width: 600px) {