From 6e550c0d5b9d9edccea68bee06ab5c014a6d6c85 Mon Sep 17 00:00:00 2001 From: philipcheung Date: Sat, 12 Sep 2026 10:04:23 +0800 Subject: [PATCH] Add image upload to site settings with old-file cleanup --- src/data/settings-fields.ts | 6 ++--- src/pages/admin/settings.astro | 43 ++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/data/settings-fields.ts b/src/data/settings-fields.ts index caf281c..bfb7438 100644 --- a/src/data/settings-fields.ts +++ b/src/data/settings-fields.ts @@ -1,4 +1,4 @@ -export type FieldType = "text" | "textarea" | "url"; +export type FieldType = "text" | "textarea" | "url" | "image"; export type SettingsField = { key: string; @@ -39,7 +39,7 @@ export const SETTINGS_GROUPS: SettingsGroup[] = [ { key: "hero_subtitle", label: "副標題", type: "textarea" }, { key: "hero_primary_cta", label: "主要按鈕文字" }, { key: "hero_secondary_cta", label: "次要按鈕文字" }, - { key: "hero_image", label: "主視覺圖片 URL", type: "url", placeholder: "https://..." }, + { key: "hero_image", label: "主視覺圖片", type: "image" }, ], }, { @@ -47,7 +47,7 @@ export const SETTINGS_GROUPS: SettingsGroup[] = [ fields: [ { key: "seo_default_title", label: "預設標題" }, { key: "seo_default_description", label: "預設描述", type: "textarea" }, - { key: "og_image", label: "分享圖片 URL (OG image)", type: "url", placeholder: "https://..." }, + { key: "og_image", label: "分享圖片 (OG image)", type: "image" }, ], }, ]; diff --git a/src/pages/admin/settings.astro b/src/pages/admin/settings.astro index 3c30ce1..ae85aae 100644 --- a/src/pages/admin/settings.astro +++ b/src/pages/admin/settings.astro @@ -1,16 +1,25 @@ --- import AdminLayout from "../../layouts/AdminLayout.astro"; +import ImageField from "../../components/admin/ImageField.astro"; import { ALL_SETTING_KEYS, SETTINGS_GROUPS } from "../../data/settings-fields"; import { siteSettings } from "../../db/schema"; import { getSettings } from "../../data/content"; import { getDb } from "../../lib/db"; import { getEnv } from "../../lib/env"; import { parseForm } from "../../lib/form"; +import { deleteMedia } from "../../lib/media"; import { settingsInput } from "../../schemas"; export const prerender = false; -const db = getDb(getEnv().DB); +const env = getEnv(); +const db = getDb(env.DB); + +const IMAGE_SETTING_KEYS = new Set( + SETTINGS_GROUPS.flatMap((g) => + g.fields.filter((f) => f.type === "image").map((f) => f.key), + ), +); let saved = false; let error = ""; @@ -21,6 +30,7 @@ if (Astro.request.method === "POST") { if (!parsed.ok) { error = Object.values(parsed.errors)[0] ?? "設定有誤。"; } else { + const before = await getSettings(db); const now = new Date(); const submitted = new Set( [...form.keys()].filter((k) => ALL_SETTING_KEYS.includes(k)), @@ -28,6 +38,9 @@ if (Astro.request.method === "POST") { for (const key of ALL_SETTING_KEYS) { if (!submitted.has(key)) continue; const value = String((parsed.data as Record)[key] ?? ""); + if (IMAGE_SETTING_KEYS.has(key) && before[key] !== value) { + await deleteMedia(env, before[key]); + } await db .insert(siteSettings) .values({ key, value, updatedAt: now }) @@ -56,11 +69,31 @@ const settings = await getSettings(db);
{group.fields.map((f) => (
- - {f.type === "textarea" ? ( - + {f.type === "image" ? ( + ) : ( - + <> + + {f.type === "textarea" ? ( + + ) : ( + + )} + )}
))}