From c4fcf3f9967977048a30d1aa20d6efb5281d9f3a Mon Sep 17 00:00:00 2001 From: gunshiz Date: Sat, 29 Aug 2026 17:25:36 +0000 Subject: [PATCH] fix(admin): repair layout and character artwork --- README.md | 2 +- app/admin/[character]/[page]/page.tsx | 3 +- app/admin/[character]/page.tsx | 3 +- app/admin/create/page.tsx | 18 +++-- app/admin/loading.tsx | 6 +- app/admin/page.tsx | 16 +++-- app/admin/templates/page.tsx | 34 +--------- components/admin/admin-header.tsx | 81 +++++++++++++++++++++++ components/admin/guide-section-editor.tsx | 2 +- components/admin/media-uploader.tsx | 1 + components/public/site-header.tsx | 2 +- lib/catalog/sync.ts | 8 +-- 12 files changed, 120 insertions(+), 56 deletions(-) create mode 100644 components/admin/admin-header.tsx diff --git a/README.md b/README.md index f3ed0ad..a6bc7d5 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ formula fixtures. Their guide text and media are not imported or published. | `/register` | Temporary administrator account bootstrap | | `/admin` | Character and page overview | | `/admin/[character]/[page]` | Visual page editor | -| `/admin/templates` | Apply reusable guide templates | +| `/admin/create` | Create a structured guide from the synced character catalog | | `/media/[id]` | Authorized same-origin media response | | `/api/health` | Liveness response | | `/api/health?ready=1` | PostgreSQL and Redis readiness response | diff --git a/app/admin/[character]/[page]/page.tsx b/app/admin/[character]/[page]/page.tsx index 00bb154..2376607 100644 --- a/app/admin/[character]/[page]/page.tsx +++ b/app/admin/[character]/[page]/page.tsx @@ -4,6 +4,7 @@ import { notFound, redirect } from "next/navigation"; import { connection } from "next/server"; import { GuideSectionEditor } from "@/components/admin/guide-section-editor"; +import { AdminHeader } from "@/components/admin/admin-header"; import { Button } from "@/components/ui/button"; import { getAdminSession } from "@/lib/auth/server"; import { getActiveCatalog, getGuideByCharacterKey, getPublicGuide } from "@/lib/guides/queries"; @@ -19,5 +20,5 @@ export default async function StructuredEditorPage({ params }: { params: Promise if (!guide) notFound(); const [catalog, content] = await Promise.all([getActiveCatalog(), getPublicGuide(guide.slug)]); if (!catalog || !content) notFound(); - return

{guide.name}

{guide.sections.find((section) => section.slug === page)?.title ?? page}

({ id: group.id, name: group.name, rows: group.rows.map((row) => ({ firstArtifactKey: row.firstArtifactKey, secondArtifactKey: row.secondArtifactKey, percent: row.percent })) })), artifactProfile: content.artifactProfile, constellations: content.constellations, teams: content.teams.map((team) => ({ title: team.title, rotationSeconds: team.rotationSeconds, combo: team.combo, members: team.members.map((member) => ({ characterKey: member.characterKey, damage: member.damage })) })), extras: content.extras.map((section) => ({ title: section.title, rows: section.rows.map((row) => ({ mediaId: row.mediaId, heading: row.heading, body: row.body, percent: row.percent, imageUrl: row.imageUrl })) })) }} />
; + return

{guide.name}

{guide.sections.find((section) => section.slug === page)?.title ?? page}

({ id: group.id, name: group.name, rows: group.rows.map((row) => ({ firstArtifactKey: row.firstArtifactKey, secondArtifactKey: row.secondArtifactKey, percent: row.percent })) })), artifactProfile: content.artifactProfile, constellations: content.constellations, teams: content.teams.map((team) => ({ title: team.title, rotationSeconds: team.rotationSeconds, combo: team.combo, members: team.members.map((member) => ({ characterKey: member.characterKey, damage: member.damage })) })), extras: content.extras.map((section) => ({ title: section.title, rows: section.rows.map((row) => ({ mediaId: row.mediaId, heading: row.heading, body: row.body, percent: row.percent, imageUrl: row.imageUrl })) })) }} />
; } diff --git a/app/admin/[character]/page.tsx b/app/admin/[character]/page.tsx index bce3b12..00db604 100644 --- a/app/admin/[character]/page.tsx +++ b/app/admin/[character]/page.tsx @@ -6,6 +6,7 @@ import { connection } from "next/server"; import { Button } from "@/components/ui/button"; import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { AdminHeader } from "@/components/admin/admin-header"; import { GuideOverviewForm } from "@/components/admin/guide-overview-form"; import { getAdminSession } from "@/lib/auth/server"; import { getGuideByCharacterKey } from "@/lib/guides/queries"; @@ -23,5 +24,5 @@ export default async function GuideOverviewPage({ params }: { params: Promise<{ const { character } = await params; const guide = await getGuideByCharacterKey(character); if (!guide) notFound(); - return
{guide.name}

Where do you want to edit?

{guide.name}

{sections.map(({ slug, title, description, icon: Icon }) => {title}{description})}Extra sectionsส่วนเสริมแบบภาพ หัวข้อ ข้อความสั้น และเปอร์เซ็นต์
; + return
{guide.name}

เลือกส่วนที่ต้องการแก้ไข

{guide.name}

{sections.map(({ slug, title, description, icon: Icon }) => {title}{description})}Extra sectionsส่วนเสริมแบบภาพ หัวข้อ ข้อความสั้น และเปอร์เซ็นต์
; } diff --git a/app/admin/create/page.tsx b/app/admin/create/page.tsx index e381502..e1ca986 100644 --- a/app/admin/create/page.tsx +++ b/app/admin/create/page.tsx @@ -4,6 +4,7 @@ import { redirect } from "next/navigation"; import { connection } from "next/server"; import { CreateGuideFlow } from "@/components/admin/create-guide-flow"; +import { AdminHeader } from "@/components/admin/admin-header"; import { Button } from "@/components/ui/button"; import { getAdminSession } from "@/lib/auth/server"; import { getActiveCatalog, listGuideCards } from "@/lib/guides/queries"; @@ -14,12 +15,15 @@ export default async function CreateGuidePage() { const [catalog, guides] = await Promise.all([getActiveCatalog(), listGuideCards()]); if (!catalog) redirect("/admin?sync=required"); return ( -
-
- -

Catalog {catalog.version}

สร้าง Guide ใหม่

-
- guide.characterKey)} /> -
+
+ +
+
+ +

Catalog {catalog.version}

สร้าง Guide ใหม่

+
+ guide.characterKey)} /> +
+
); } diff --git a/app/admin/loading.tsx b/app/admin/loading.tsx index 0c1f900..6c5abc0 100644 --- a/app/admin/loading.tsx +++ b/app/admin/loading.tsx @@ -2,9 +2,9 @@ import { Skeleton } from "@/components/ui/skeleton"; export default function AdminLoading() { return ( -
- -
+
+ +
diff --git a/app/admin/page.tsx b/app/admin/page.tsx index bcd74fa..6e8103e 100644 --- a/app/admin/page.tsx +++ b/app/admin/page.tsx @@ -2,6 +2,7 @@ import { redirect } from "next/navigation"; import { connection } from "next/server"; import { StructuredDashboard } from "@/components/admin/structured-dashboard"; +import { AdminHeader } from "@/components/admin/admin-header"; import { getAdminSession } from "@/lib/auth/server"; import { getActiveCatalog, getLatestCatalogSyncJob, listGuideCards } from "@/lib/guides/queries"; @@ -15,9 +16,16 @@ export default async function AdminPage() { getActiveCatalog(), ]); return ( -
-

Buzz Sheet Admin

Guide Dashboard

จัดการ Guide แบบภาพ-first และบันทึกขึ้นเว็บไซต์ทันที

- -
+
+ +
+
+

Content workspace

+

Guide Dashboard

+

จัดการ Guide แบบภาพ-first และบันทึกขึ้นเว็บไซต์ทันที

+
+ +
+
); } diff --git a/app/admin/templates/page.tsx b/app/admin/templates/page.tsx index a093700..9a370c3 100644 --- a/app/admin/templates/page.tsx +++ b/app/admin/templates/page.tsx @@ -1,37 +1,5 @@ import { redirect } from "next/navigation"; -import { connection } from "next/server"; - -import { AdminSidebar } from "@/components/admin/admin-sidebar"; -import { LiveRefresh } from "@/components/live-refresh"; -import { TemplateGallery } from "@/components/admin/template-gallery"; -import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; -import { getAdminSession } from "@/lib/auth/server"; -import { loadAdminNavigation } from "@/lib/content/loaders"; -import { builtInTemplates } from "@/lib/templates"; export default async function TemplatesPage() { - await connection(); - if (!(await getAdminSession())) redirect("/admin/login"); - const navigation = await loadAdminNavigation(); - - return ( - - {process.env.BUZZ_DEMO_MODE === "true" ? null : ( - - )} - - -
- -
-

เทมเพลตคู่มือ

-

โครงสร้างเริ่มต้นที่คัดมาจากรูปแบบคู่มือทั้งห้า

-
-
-
- -
-
-
- ); + redirect("/admin/create"); } diff --git a/components/admin/admin-header.tsx b/components/admin/admin-header.tsx new file mode 100644 index 0000000..3ce5f87 --- /dev/null +++ b/components/admin/admin-header.tsx @@ -0,0 +1,81 @@ +"use client"; + +import Link from "next/link"; +import { usePathname, useRouter } from "next/navigation"; +import { + BookOpenIcon, + ExternalLinkIcon, + LayoutDashboardIcon, + LogOutIcon, + PlusIcon, +} from "lucide-react"; + +import { Button } from "@/components/ui/button"; +import { authClient } from "@/lib/auth/client"; + +export function AdminHeader() { + const pathname = usePathname(); + const router = useRouter(); + + return ( +
+
+ + + + Buzz Sheet Admin + + +
+
+ ); +} diff --git a/components/admin/guide-section-editor.tsx b/components/admin/guide-section-editor.tsx index d099b0d..23dafe2 100644 --- a/components/admin/guide-section-editor.tsx +++ b/components/admin/guide-section-editor.tsx @@ -87,7 +87,7 @@ export function GuideSectionEditor(props: GuideSectionEditorProps) { {props.section === "constellations" ? : null} {props.section === "team" ? : null} {props.section === "extra" ? : null} - {index > 0 ? : Overview}{SECTION_LABELS[props.section]}{index < SECTION_ORDER.length - 1 ? : null} + {index > 0 ? : Overview}{SECTION_LABELS[props.section]}{index < SECTION_ORDER.length - 1 ? : null}
); } diff --git a/components/admin/media-uploader.tsx b/components/admin/media-uploader.tsx index 9feed6c..00b02e3 100644 --- a/components/admin/media-uploader.tsx +++ b/components/admin/media-uploader.tsx @@ -74,6 +74,7 @@ export function MediaUploader({ className="w-full" disabled={busy} render={