From fb4511b1e506c5d419b7ab8db2abddad50fde293 Mon Sep 17 00:00:00 2001 From: gunshiz Date: Sun, 30 Aug 2026 05:48:17 +0000 Subject: [PATCH] feat(admin): show character portrait in editor headers --- app/admin/[character]/[page]/page.tsx | 3 ++- app/admin/[character]/page.tsx | 4 ++-- lib/guides/queries.ts | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/admin/[character]/[page]/page.tsx b/app/admin/[character]/[page]/page.tsx index 0059ef0..856a8fb 100644 --- a/app/admin/[character]/[page]/page.tsx +++ b/app/admin/[character]/[page]/page.tsx @@ -6,6 +6,7 @@ import { connection } from "next/server"; import { GuideSectionEditor } from "@/components/admin/guide-section-editor"; import { GuideSectionNav } from "@/components/admin/guide-section-nav"; import { AdminHeader } from "@/components/admin/admin-header"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { getAdminSession } from "@/lib/auth/server"; import { getActiveCatalog, getGuideByCharacterKey, getPublicGuide } from "@/lib/guides/queries"; @@ -21,5 +22,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}

item.key === guide.characterKey)?.constellations ?? []} initial={{ weapons: content.weapons, artifactGroups: content.artifactGroups.map((group) => ({ 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, weaponKey: member.weaponKey, artifactKey: member.artifactKey, constellation: member.constellation, refinement: member.refinement, 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}

{content.character.name.slice(0, 2).toUpperCase()}
item.key === guide.characterKey)?.constellations ?? []} initial={{ weapons: content.weapons, artifactGroups: content.artifactGroups.map((group) => ({ 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, weaponKey: member.weaponKey, artifactKey: member.artifactKey, constellation: member.constellation, refinement: member.refinement, 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 d0dd342..f523bbd 100644 --- a/app/admin/[character]/page.tsx +++ b/app/admin/[character]/page.tsx @@ -1,4 +1,3 @@ -import Image from "next/image"; import Link from "next/link"; import { ArrowLeftIcon, BoxesIcon, GemIcon, SparklesIcon, SwordsIcon, UsersIcon } from "lucide-react"; import { notFound, redirect } from "next/navigation"; @@ -6,6 +5,7 @@ import { connection } from "next/server"; import { Button } from "@/components/ui/button"; import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { AdminHeader } from "@/components/admin/admin-header"; import { GuideOverviewForm } from "@/components/admin/guide-overview-form"; import { GuideSectionNav } from "@/components/admin/guide-section-nav"; @@ -25,5 +25,5 @@ export default async function GuideOverviewPage({ params }: { params: Promise<{ const { character } = await params; const guide = await getGuideByCharacterKey(character); if (!guide) notFound(); - return
{guide.name}

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

{guide.name}

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

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

{guide.name}

{guide.character.name.slice(0, 2).toUpperCase()}
{sections.map(({ slug, title, description, icon: Icon }) => {title}{description})}Extra sectionsส่วนเสริมแบบภาพ หัวข้อ ข้อความสั้น และเปอร์เซ็นต์
; } diff --git a/lib/guides/queries.ts b/lib/guides/queries.ts index 7cb5a2a..155fd42 100644 --- a/lib/guides/queries.ts +++ b/lib/guides/queries.ts @@ -64,14 +64,15 @@ export async function listGuideCards(includeTrash = false) { export async function getGuideByCharacterKey(characterKey: string) { const [row] = await getDb() - .select({ guide: guides, cover: media }) + .select({ guide: guides, cover: media, character: catalogCharacters }) .from(guides) .innerJoin(media, eq(media.id, guides.coverMediaId)) + .innerJoin(catalogCharacters, and(eq(catalogCharacters.version, guides.catalogVersion), eq(catalogCharacters.key, guides.characterKey))) .where(and(eq(guides.characterKey, characterKey), isNull(guides.trashedAt))) .limit(1); if (!row) return null; const sections = await getDb().select().from(guideSections).where(eq(guideSections.guideId, row.guide.id)).orderBy(asc(guideSections.sortOrder)); - return { ...row.guide, coverUrl: publicMediaUrl(row.cover.objectKey), sections }; + return { ...row.guide, coverUrl: publicMediaUrl(row.cover.objectKey), character: catalogCharacterWithUrls(row.character), sections }; } export async function getPublicGuide(slug: string) {