feat(guide) : improve extra cards and navigation
CI / Verify (push) Successful in 1m25s
CI / Build immutable images and deploy (push) Failing after 50s

This commit is contained in:
2026-09-04 22:40:27 +07:00 Unverified
parent 5f74ce1de6
commit ced9b41737
16 changed files with 3780 additions and 224 deletions
-17
View File
@@ -1,17 +0,0 @@
import { SiteHeader } from "@/components/public/site-header";
import { Skeleton } from "@/components/ui/skeleton";
export default function GuideLoading() {
return (
<div className="min-h-svh">
<SiteHeader />
<div className="border-b p-4"><Skeleton className="mx-auto h-16 max-w-7xl" /></div>
<main className="mx-auto max-w-5xl space-y-5 px-4 py-10">
<Skeleton className="h-72 w-full" />
<Skeleton className="h-8 w-1/3" />
<Skeleton className="h-28 w-full" />
<Skeleton className="h-80 w-full" />
</main>
</div>
);
}
+1 -1
View File
@@ -22,5 +22,5 @@ export default async function StructuredEditorPage({ params }: { params: Promise
const [catalog, content] = await Promise.all([getActiveCatalog(), getAdminGuideContent(guide.slug)]);
if (!catalog || !content) notFound();
const guideCharacter = catalog.characters.find((item) => item.key === guide.characterKey);
return <div className="min-h-svh"><AdminHeader /><main className="mx-auto flex w-full max-w-6xl flex-col gap-6 p-4 sm:p-6 lg:p-8"><header className="flex items-center gap-4"><Button variant="outline" size="icon" render={<Link href={`/admin/${character}`} />} nativeButton={false} aria-label="กลับหน้า Guide"><ArrowLeftIcon /></Button><div className="min-w-0"><p className="text-sm text-muted-foreground">{guide.name}</p><h1 className="whitespace-nowrap font-heading text-3xl font-semibold">{guide.sections.find((section) => section.slug === page)?.title ?? page}</h1></div></header><GuideSectionNav characterKey={guide.characterKey} current={page as (typeof sections)[number]} /><GuideSectionEditor section={page as (typeof sections)[number]} guide={guide} weapons={catalog.weapons} artifacts={catalog.artifacts} characters={catalog.characters} catalogConstellations={guideCharacter?.constellations ?? []} catalogTalents={guideCharacter?.talents ?? []} initial={{ sectionNote: guide.sections.find((section) => section.slug === page)?.note ?? null, weaponGroups: content.weaponGroups, 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, note: row.note })) })), artifactProfile: content.artifactProfile, constellationGroups: content.constellationGroups.map((group) => ({ id: group.id, note: group.note, rows: group.rows })), teams: content.teams.map((team) => ({ id: team.id, title: team.title, rotationSeconds: team.rotationSeconds, combo: team.combo, members: team.members.map((member) => ({ characterKey: member.characterKey, weaponKey: member.weaponKey, artifactKey: member.artifactKey, secondArtifactKey: member.secondArtifactKey, constellation: member.constellation, refinement: member.refinement, damage: member.damage })) })), extras: content.extras.map((section) => ({ id: section.id, title: section.title, rows: section.rows.map((row) => ({ id: row.id, mediaId: row.mediaId, heading: row.heading, body: row.body, percent: row.percent, backgroundColor: row.backgroundColor, textColor: row.textColor, imageUrl: row.imageUrl, imageWidth: row.imageWidth, imageHeight: row.imageHeight })) })) }} /></main></div>;
return <div className="min-h-svh"><AdminHeader /><main className="mx-auto flex w-full max-w-6xl flex-col gap-6 p-4 sm:p-6 lg:p-8"><header className="flex items-center gap-4"><Button variant="outline" size="icon" render={<Link href={`/admin/${character}`} />} nativeButton={false} aria-label="กลับหน้า Guide"><ArrowLeftIcon /></Button><div className="min-w-0"><p className="text-sm text-muted-foreground">{guide.name}</p><h1 className="whitespace-nowrap font-heading text-3xl font-semibold">{guide.sections.find((section) => section.slug === page)?.title ?? page}</h1></div></header><GuideSectionNav characterKey={guide.characterKey} current={page as (typeof sections)[number]} /><GuideSectionEditor section={page as (typeof sections)[number]} guide={guide} weapons={catalog.weapons} artifacts={catalog.artifacts} characters={catalog.characters} catalogConstellations={guideCharacter?.constellations ?? []} catalogTalents={guideCharacter?.talents ?? []} initial={{ sectionNote: guide.sections.find((section) => section.slug === page)?.note ?? null, weaponGroups: content.weaponGroups, 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, note: row.note })) })), artifactProfile: content.artifactProfile, constellationGroups: content.constellationGroups.map((group) => ({ id: group.id, note: group.note, rows: group.rows })), teams: content.teams.map((team) => ({ id: team.id, title: team.title, rotationSeconds: team.rotationSeconds, combo: team.combo, members: team.members.map((member) => ({ characterKey: member.characterKey, weaponKey: member.weaponKey, artifactKey: member.artifactKey, secondArtifactKey: member.secondArtifactKey, constellation: member.constellation, refinement: member.refinement, damage: member.damage })) })), extras: content.extras.map((section) => ({ id: section.id, title: section.title, rows: section.rows.map((row) => ({ id: row.id, mediaId: row.mediaId, heading: row.heading, body: row.body, percent: row.percent, backgroundColor: row.backgroundColor, highlights: row.highlights, imageUrl: row.imageUrl, imageWidth: row.imageWidth, imageHeight: row.imageHeight })) })) }} /></main></div>;
}
-14
View File
@@ -1,14 +0,0 @@
import { Skeleton } from "@/components/ui/skeleton";
export default function AdminLoading() {
return (
<div className="min-h-svh">
<Skeleton className="h-16 w-full rounded-none" />
<div className="mx-auto flex w-full max-w-7xl flex-col gap-5 p-6">
<Skeleton className="h-12 w-full" />
<Skeleton className="h-36 w-full" />
<Skeleton className="h-72 w-full" />
</div>
</div>
);
}
-12
View File
@@ -130,11 +130,6 @@
}
}
::view-transition-group(.guide-nav-pill) {
animation-duration: 220ms;
animation-timing-function: ease-in-out;
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
@@ -144,11 +139,4 @@
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
::view-transition-old(*),
::view-transition-new(*),
::view-transition-group(*) {
animation-delay: 0s !important;
animation-duration: 0.01ms !important;
}
}
-19
View File
@@ -1,19 +0,0 @@
import { DirectorySkeleton } from "@/components/public/directory-skeleton";
import { SiteHeader } from "@/components/public/site-header";
import { Skeleton } from "@/components/ui/skeleton";
export default function Loading() {
return (
<div className="min-h-svh">
<SiteHeader />
<main className="mx-auto w-full max-w-7xl space-y-8 px-4 py-10 sm:px-6 sm:py-14">
<div className="space-y-3">
<Skeleton className="h-4 w-32" />
<Skeleton className="h-10 w-full max-w-2xl" />
<Skeleton className="h-6 w-full max-w-xl" />
</div>
<DirectorySkeleton />
</main>
</div>
);
}