Huh...
+There's nothing here! Want to be the first to comment?
+diff --git a/.gitignore b/.gitignore
index 016b59e..b67e3c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,6 @@ pnpm-debug.log*
# jetbrains setting folder
.idea/
+
+# dont grab database files you dont need that
+local.db
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 3662b37..1170042 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,12 @@
{
- "typescript.tsdk": "node_modules/typescript/lib"
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "sqltools.useNodeRuntime": true,
+ "sqltools.connections": [
+ {
+ "previewLimit": 50,
+ "driver": "SQLite",
+ "database": "./guestbook.db",
+ "name": "test"
+ }
+ ]
}
\ No newline at end of file
diff --git a/astro.config.mjs b/astro.config.mjs
index 34eb68b..cdc084c 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -3,8 +3,8 @@ import { defineConfig } from 'astro/config';
import { modifiedTime } from './src/utils/lastModified.mjs';
import mdx from "@astrojs/mdx";
import db from "@astrojs/db";
-
import node from "@astrojs/node";
+import devOnlyRoutes from '@fujocoded/astro-dev-only';
// https://astro.build/config
export default defineConfig({
@@ -13,7 +13,14 @@ export default defineConfig({
remarkPlugins: [modifiedTime],
smartypants: false,
},
- integrations: [mdx(), db()],
+ integrations: [
+ mdx(),
+ db(),
+ devOnlyRoutes({
+ // dryRun: true,
+ routePatterns: ["/guestbook/admin"]
+ }),
+ ],
adapter: node({
mode: "standalone",
}),
diff --git a/bun.lock b/bun.lock
index 8966634..04b3c2a 100644
--- a/bun.lock
+++ b/bun.lock
@@ -6,11 +6,11 @@
"dependencies": {
"@astrojs/db": "^0.16.1",
"@astrojs/mdx": "^4.3.3",
- "@astrojs/node": "^9.3.3",
+ "@astrojs/node": "^9.4.0",
"@astrojs/rss": "4.0.12",
+ "@fujocoded/astro-dev-only": "0.0.3",
"astro": "5.12.3",
"astro-breadcrumbs": "^3.3.1",
- "bcryptjs": "^3.0.2",
"dayjs": "^1.11.13",
"markdown-it": "^14.1.0",
"node-html-parser": "^7.0.1",
@@ -18,7 +18,7 @@
},
"devDependencies": {
"@types/markdown-it": "^14.1.2",
- "@types/node": "^22.17.0",
+ "@types/node": "^22.17.1",
"@types/sanitize-html": "^2.16.0",
},
},
@@ -34,7 +34,7 @@
"@astrojs/mdx": ["@astrojs/mdx@4.3.3", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.5", "@mdx-js/mdx": "^3.1.0", "acorn": "^8.14.1", "es-module-lexer": "^1.6.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "kleur": "^4.1.5", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.4", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-+9+xGP2TBXxcm84cpiq4S9JbuHOHM1fcvREfqW7VHxlUyfUQPByoJ9YYliqHkLS6BMzG+O/+o7n8nguVhuEv4w=="],
- "@astrojs/node": ["@astrojs/node@9.3.3", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.1", "send": "^1.2.0", "server-destroy": "^1.0.1" }, "peerDependencies": { "astro": "^5.3.0" } }, "sha512-5jVuDbSxrY7rH7H+6QoRiN78AITLobYXWu+t1A2wRaFPKywaXNr8YHSXfOE4i2YN4c+VqMCv83SjZLWjTK6f9w=="],
+ "@astrojs/node": ["@astrojs/node@9.4.0", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.1", "send": "^1.2.0", "server-destroy": "^1.0.1" }, "peerDependencies": { "astro": "^5.3.0" } }, "sha512-Gxs0iVUvOmQmK+H1DBoabcgvdSDg277SwbujRv2cUBlnpcOTJQDFRhRvyJ7G+Zkd06/jhRphsTTmmrBY0PqI4g=="],
"@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
@@ -106,6 +106,8 @@
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.8", "", { "os": "win32", "cpu": "x64" }, "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw=="],
+ "@fujocoded/astro-dev-only": ["@fujocoded/astro-dev-only@0.0.3", "", {}, "sha512-BOLYZcivrJVUA60d4R2+yEGwDJZ+3Z/zndLACxk6YpClu5ETl0adghwCCt9yIHsq79KDx/Or8LH2aqS6fVlQbg=="],
+
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="],
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="],
@@ -262,7 +264,7 @@
"@types/nlcst": ["@types/nlcst@2.0.3", "", { "dependencies": { "@types/unist": "*" } }, "sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA=="],
- "@types/node": ["@types/node@22.17.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ=="],
+ "@types/node": ["@types/node@22.17.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-y3tBaz+rjspDTylNjAX37jEC3TETEFGNJL6uQDxwF9/8GLLIjW1rvVHlynyuUKMnMr1Roq8jOv3vkopBjC4/VA=="],
"@types/sanitize-html": ["@types/sanitize-html@2.16.0", "", { "dependencies": { "htmlparser2": "^8.0.0" } }, "sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw=="],
@@ -304,8 +306,6 @@
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
- "bcryptjs": ["bcryptjs@3.0.2", "", { "bin": { "bcrypt": "bin/bcrypt" } }, "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog=="],
-
"blob-to-buffer": ["blob-to-buffer@1.2.9", "", {}, "sha512-BF033y5fN6OCofD3vgHmNtwZWRcq9NLyyxyILx9hfMy1sXYy4ojFl765hJ2lP0YaN2fuxPaLO2Vzzoxy0FLFFA=="],
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
@@ -952,6 +952,10 @@
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
+ "@types/fontkit/@types/node": ["@types/node@22.17.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ=="],
+
+ "@types/ws/@types/node": ["@types/node@22.17.0", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ=="],
+
"ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
diff --git a/package.json b/package.json
index 8864d8a..68fe9ad 100644
--- a/package.json
+++ b/package.json
@@ -4,18 +4,18 @@
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
- "build": "astro build",
+ "build": "astro build --remote",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/db": "^0.16.1",
"@astrojs/mdx": "^4.3.3",
- "@astrojs/node": "^9.3.3",
+ "@astrojs/node": "^9.4.0",
"@astrojs/rss": "4.0.12",
+ "@fujocoded/astro-dev-only": "0.0.3",
"astro": "5.12.3",
"astro-breadcrumbs": "^3.3.1",
- "bcryptjs": "^3.0.2",
"dayjs": "^1.11.13",
"markdown-it": "^14.1.0",
"node-html-parser": "^7.0.1",
@@ -23,7 +23,7 @@
},
"devDependencies": {
"@types/markdown-it": "^14.1.2",
- "@types/node": "^22.17.0",
+ "@types/node": "^22.17.1",
"@types/sanitize-html": "^2.16.0"
}
}
diff --git a/src/actions/guestbook.ts b/src/actions/guestbook.ts
index 97eaf5a..8ab6e4a 100644
--- a/src/actions/guestbook.ts
+++ b/src/actions/guestbook.ts
@@ -1,6 +1,6 @@
import { ActionError, defineAction } from "astro:actions";
import { z } from "astro:content";
-import { db, eq, Guestbook } from "astro:db";
+import { db, eq, Guestbook, isDbError } from "astro:db";
import sanitize from "sanitize-html";
export const guestbook = {
@@ -12,42 +12,92 @@ export const guestbook = {
message: z.string().min(1, "Can't be that short..."),
}),
handler: async ({ username, website, message }) => {
- // figure out how to add line breaks and THEN sanitize message
- const addLine = message.replaceAll("/n", "
");
- sanitize(addLine);
+ const addLine = message.replaceAll(/\r?\n/g, "
");
+ const sanitized = sanitize(addLine, { allowedTags: ["br"] });
- const entry = await db.insert(Guestbook).values({
- username,
- website,
- message,
- }).returning();
-
- return entry[0];
+ try {
+ const entry = await db.insert(Guestbook).values({
+ username,
+ website,
+ message: sanitized,
+ }).returning();
+
+ return entry[0];
+ } catch (e) {
+ if (isDbError(e)) {
+ return new Response(`Cannot insert entry\n\n${e.message}`, { status: 400 });
+ }
+ return new Response('An unexpected error occurred', { status: 500 });
+ }
},
}),
- reply: defineAction({
- accept: "form",
- input: z.object({
- id: z.number(),
- reply: z.string(),
+ ...import.meta.env.DEV && {
+ reply: defineAction({
+ accept: "form",
+ input: z.object({
+ id: z.coerce.number(),
+ reply: z.string(),
+ }),
+ handler: async ({ id, reply }) => {
+ if (!import.meta.env.DEV) {
+ throw new ActionError({ code: "UNAUTHORIZED" });
+ }
+
+ const entry = await db.select().from(Guestbook).where(eq(Guestbook.id, id));
+ if (!entry) {
+ throw new ActionError({
+ code: "NOT_FOUND",
+ message: "That entry doesn't exist!"
+ });
+ }
+
+ const addLine = reply.replaceAll(/\r?\n/g, "
");
+ const sanitized = sanitize(addLine, { allowedTags: ["br"] });
+
+ try {
+ const update = await db.update(Guestbook).set({
+ reply: sanitized,
+ updated: new Date(),
+ }).where(eq(Guestbook.id, id)).returning();
+
+ return update[0];
+ } catch (e) {
+ if (isDbError(e)) {
+ return new Response(`Cannot update entry\n\n${e.message}`, { status: 400 });
+ }
+ return new Response('An unexpected error occurred', { status: 500 });
+ }
+ },
}),
- handler: async ({ id, reply }, context) => {
- if (context.url.hostname !== "127.0.0.1" || "localhost") {
- throw new ActionError({ code: "UNAUTHORIZED" });
- }
+ deleteEntry: defineAction({
+ accept: "form",
+ input: z.object({
+ id: z.coerce.number()
+ }),
+ handler: async ({ id }) => {
+ if (!import.meta.env.DEV) {
+ throw new ActionError({ code: "UNAUTHORIZED" });
+ }
+
+ const entry = await db.select().from(Guestbook).where(eq(Guestbook.id, id));
+ if (!entry) {
+ throw new ActionError({
+ code: "NOT_FOUND",
+ message: "That entry doesn't exist!"
+ });
+ }
- const entry = await db.select().from(Guestbook).where(eq(Guestbook.id, id));
- if (!entry) {
- throw new ActionError({
- code: "NOT_FOUND",
- message: "That entry doesn't exist!"
- });
- }
-
- // sanitize reply here
-
- const update = await db.update(Guestbook).set({ reply }).where(eq(Guestbook.id, id)).returning();
- return update[0];
- },
- }),
+ try {
+ const entry = await db.delete(Guestbook).where(eq(Guestbook.id, id)).returning();
+
+ return entry[0];
+ } catch (e) {
+ if (isDbError(e)) {
+ return new Response(`Cannot update entry\n\n${e.message}`, { status: 400 });
+ }
+ return new Response('An unexpected error occurred', { status: 500 });
+ }
+ },
+ }),
+ },
};
\ No newline at end of file
diff --git a/src/assets/acnl-bulletin.png b/src/assets/acnl-bulletin.png
new file mode 100644
index 0000000..0ef22db
Binary files /dev/null and b/src/assets/acnl-bulletin.png differ
diff --git a/src/assets/buttons.png b/src/assets/guild-bbs-buttons.png
similarity index 100%
rename from src/assets/buttons.png
rename to src/assets/guild-bbs-buttons.png
diff --git a/src/assets/moon-bullet.gif b/src/assets/moon-bullet.gif
new file mode 100644
index 0000000..29a3cac
Binary files /dev/null and b/src/assets/moon-bullet.gif differ
diff --git a/src/assets/border.png b/src/assets/pmd-border.png
similarity index 100%
rename from src/assets/border.png
rename to src/assets/pmd-border.png
diff --git a/src/assets/frame.png b/src/assets/pmd-frame.png
similarity index 100%
rename from src/assets/frame.png
rename to src/assets/pmd-frame.png
diff --git a/src/assets/star-bullet.gif b/src/assets/star-bullet.gif
new file mode 100644
index 0000000..2947b89
Binary files /dev/null and b/src/assets/star-bullet.gif differ
diff --git a/src/components/Dialog.astro b/src/components/Dialog.astro
new file mode 100644
index 0000000..fd1010b
--- /dev/null
+++ b/src/components/Dialog.astro
@@ -0,0 +1,90 @@
+---
+interface Props {
+ id?: string;
+ title?: string;
+ class?: string;
+}
+
+const { id, title, class: className, ...rest } = Astro.props;
+---
+
+
+
+
\ No newline at end of file
diff --git a/src/components/Entries.astro b/src/components/Entries.astro
index a9f25da..25312ac 100644
--- a/src/components/Entries.astro
+++ b/src/components/Entries.astro
@@ -1,6 +1,7 @@
---
import { db, desc, Guestbook } from "astro:db";
import formatDate from "@/utils/formatDate";
+import pikachu from "$/images/portrait-0025.png";
const entries = await db.select().from(Guestbook).orderBy(desc(Guestbook.published));
---
@@ -20,13 +21,14 @@ const entries = await db.select().from(Guestbook).orderBy(desc(Guestbook.publish
- {entry.message}
+
There's nothing here! Want to be the first to comment?
+