feat(i18n) : add personal languages and compact weapon exports
CI / Verify (push) Successful in 1m18s
CI / Build immutable images and deploy (push) Successful in 1m57s

This commit is contained in:
2026-09-14 16:44:44 +07:00 Unverified
parent f214d330f0
commit e0794822b1
72 changed files with 4199 additions and 1011 deletions
+3 -2
View File
@@ -1,3 +1,4 @@
import { Localized } from "@/components/i18n/text";
import Link from "next/link";
import Image from "next/image";
import { ArrowLeftIcon } from "lucide-react";
@@ -65,7 +66,7 @@ export default async function StructuredEditorPage({
<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
<Localized attributes={{ "aria-label": "กลับ Dashboard" }}><Button
variant="outline"
size="icon"
render={<Link href="/admin" />}
@@ -73,7 +74,7 @@ export default async function StructuredEditorPage({
aria-label="กลับ Dashboard"
>
<ArrowLeftIcon />
</Button>
</Button></Localized>
<div className="relative size-16 shrink-0 overflow-hidden rounded-lg border">
<Image src={guide.coverUrl} alt={guide.name} fill sizes="64px" className="object-cover" />
</div>
+4 -3
View File
@@ -1,3 +1,4 @@
import { Localized, Text } from "@/components/i18n/text";
import Image from "next/image";
import Link from "next/link";
import { ArrowLeftIcon, ArrowUpRightIcon } from "lucide-react";
@@ -40,14 +41,14 @@ export default async function GuideOverviewPage({ params }: { params: Promise<{
<AdminHeader />
<main className="mx-auto flex w-full max-w-6xl flex-col gap-8 p-4 sm:p-6 lg:p-8">
<header className="flex flex-wrap items-center gap-4">
<Button variant="outline" size="icon" render={<Link href="/admin" />} nativeButton={false} aria-label="กลับ Dashboard">
<Localized attributes={{ "aria-label": "กลับ Dashboard" }}><Button variant="outline" size="icon" render={<Link href="/admin" />} nativeButton={false} aria-label="กลับ Dashboard">
<ArrowLeftIcon />
</Button>
</Button></Localized>
<div className="relative size-16 overflow-hidden rounded-lg border">
<Image src={guide.coverUrl} alt={guide.name} fill sizes="64px" className="object-cover" />
</div>
<div className="min-w-0 flex-1">
<p className="text-sm text-muted-foreground">เลือกส่วนที่ต้องการแก้ไข</p>
<p className="text-sm text-muted-foreground"><Text message="เลือกส่วนที่ต้องการแก้ไข" /></p>
<h1 className="font-heading text-3xl font-semibold">{guide.name}</h1>
<EditorPresence guideId={guide.id} section="Overview" />
</div>
+3 -2
View File
@@ -1,3 +1,4 @@
import { Localized, Text } from "@/components/i18n/text";
import Link from "next/link";
import { ArrowLeftIcon } from "lucide-react";
import { redirect } from "next/navigation";
@@ -19,8 +20,8 @@ export default async function CreateGuidePage() {
<AdminHeader />
<main className="mx-auto flex w-full max-w-7xl flex-col gap-8 p-4 sm:p-6 lg:p-8">
<header className="flex items-center gap-4">
<Button variant="outline" size="icon" render={<Link href="/admin" />} nativeButton={false} aria-label="กลับ Dashboard"><ArrowLeftIcon /></Button>
<div><p className="text-sm text-muted-foreground">Catalog ล่าสุดจาก Lunaris</p><h1 className="font-heading text-3xl font-semibold">สร้าง Guide ใหม่</h1></div>
<Localized attributes={{ "aria-label": "กลับ Dashboard" }}><Button variant="outline" size="icon" render={<Link href="/admin" />} nativeButton={false} aria-label="กลับ Dashboard"><ArrowLeftIcon /></Button></Localized>
<div><p className="text-sm text-muted-foreground"><Text message="Catalog ล่าสุดจาก Lunaris" /></p><h1 className="font-heading text-3xl font-semibold"><Text message="สร้าง Guide ใหม่" /></h1></div>
</header>
<CreateGuideFlow characters={catalog.characters} existingKeys={guides.map((guide) => guide.characterKey)} />
</main>
+4 -5
View File
@@ -1,3 +1,4 @@
import { Text } from "@/components/i18n/text";
import { redirect } from "next/navigation";
import { connection } from "next/server";
@@ -29,13 +30,11 @@ export default async function OverviewImagePage() {
<AdminHeader />
<main className="mx-auto flex w-full max-w-7xl flex-col gap-8 p-4 sm:p-6 lg:p-8">
<header>
<p className="text-sm font-medium text-primary">Image generator</p>
<p className="text-sm font-medium text-primary"><Text message="Image generator" /></p>
<h1 className="font-heading text-3xl font-semibold">
สร้างภาพ Overview
</h1>
<Text message="สร้างภาพ Overview" /></h1>
<p className="mt-2 text-muted-foreground">
สร้างและดาวน์โหลดภาพ PNG ขนาด 3000×3000 โดยไม่เปลี่ยนภาพใน Guide
</p>
<Text message="สร้างและดาวน์โหลดภาพ PNG ขนาด 3000×3000 โดยไม่เปลี่ยนภาพใน Guide" /></p>
</header>
<OverviewImageGenerator
characters={catalog.characters.map((character) => ({
+3 -2
View File
@@ -1,3 +1,4 @@
import { Text } from "@/components/i18n/text";
import { redirect } from "next/navigation";
import { connection } from "next/server";
@@ -20,8 +21,8 @@ export default async function GlossaryPage() {
<AdminHeader />
<main className="mx-auto flex w-full max-w-4xl flex-col gap-8 p-4 sm:p-6 lg:p-8">
<header>
<p className="text-sm font-medium text-primary">Search shortcuts</p>
<h1 className="font-heading text-3xl font-semibold">Glossary Manager</h1>
<p className="text-sm font-medium text-primary"><Text message="Search shortcuts" /></p>
<h1 className="font-heading text-3xl font-semibold"><Text message="Glossary Manager" /></h1>
</header>
<GlossaryManager aliases={aliases} catalogs={{
character: catalog.characters,
+4 -3
View File
@@ -1,3 +1,4 @@
import { Text } from "@/components/i18n/text";
import { redirect } from "next/navigation";
import { connection } from "next/server";
@@ -22,9 +23,9 @@ export default async function AdminPage() {
<AdminHeader />
<main className="mx-auto flex w-full max-w-7xl flex-col gap-8 p-4 sm:p-6 lg:p-8">
<header>
<p className="text-sm font-medium text-primary">Content workspace</p>
<h1 className="font-heading text-3xl font-semibold">Guide Dashboard</h1>
<p className="mt-2 text-muted-foreground">จัดการ Guide แบบภาพ-first และบันทึกขึ้นเว็บไซต์ทันที</p>
<p className="text-sm font-medium text-primary"><Text message="Content workspace" /></p>
<h1 className="font-heading text-3xl font-semibold"><Text message="Guide Dashboard" /></h1>
<p className="mt-2 text-muted-foreground"><Text message="จัดการ Guide แบบภาพ-first และบันทึกขึ้นเว็บไซต์ทันที" /></p>
</header>
<StructuredDashboard guides={guides} trash={trash} catalogVersion={catalogVersion} />
</main>
+4 -4
View File
@@ -1,3 +1,4 @@
import { Text } from "@/components/i18n/text";
import { asc } from "drizzle-orm";
import { redirect } from "next/navigation";
import { connection } from "next/server";
@@ -28,11 +29,10 @@ export default async function RegisterPage() {
<AdminHeader />
<main className="mx-auto flex w-full max-w-7xl flex-col gap-6 p-4 sm:p-6 lg:p-8">
<header>
<p className="text-sm font-medium text-primary">Admin access</p>
<h1 className="font-heading text-3xl font-semibold">จัดการบัญชี</h1>
<p className="text-sm font-medium text-primary"><Text message="Admin access" /></p>
<h1 className="font-heading text-3xl font-semibold"><Text message="จัดการบัญชี" /></h1>
<p className="mt-2 text-muted-foreground">
สร้างบัญชีให้ผู้ดูแลคนอื่น หรือลบบัญชีที่ไม่ต้องใช้งานแล้ว
</p>
<Text message="สร้างบัญชีให้ผู้ดูแลคนอื่น หรือลบบัญชีที่ไม่ต้องใช้งานแล้ว" /></p>
</header>
<RegisterCard accounts={accounts} currentUserId={session.user.id} />
</main>