Files
buzz-sheet/components/admin/admin-command.tsx
T

138 lines
5.2 KiB
TypeScript

"use client";
import { useRouter } from "next/navigation";
import {
BarChart3Icon,
FileTextIcon,
Heading2Icon,
ImageIcon,
LayoutGridIcon,
ListOrderedIcon,
MessageSquareIcon,
Rows3Icon,
SeparatorHorizontalIcon,
Table2Icon,
TextIcon,
UsersIcon,
type LucideIcon,
} from "lucide-react";
import type { AdminNavigation } from "@/components/admin/admin-sidebar";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command";
import type { SerializedBlock } from "@/lib/blocks";
import type { DataSourceSnapshot } from "@/lib/content/types";
import { createEditorBlock } from "@/lib/editor/draft";
const catalog: Array<{
type: string;
label: string;
icon: LucideIcon;
source?: boolean;
media?: boolean;
}> = [
{ type: "profile", label: "โปรไฟล์", icon: LayoutGridIcon },
{ type: "rich-text", label: "ข้อความ", icon: TextIcon },
{ type: "heading", label: "หัวข้อ", icon: Heading2Icon },
{ type: "callout", label: "กล่องหมายเหตุ", icon: MessageSquareIcon },
{ type: "stat-cards", label: "การ์ดค่าสถานะ", icon: LayoutGridIcon },
{ type: "key-value", label: "ข้อมูลกำหนดเอง", icon: Rows3Icon },
{ type: "ranking", label: "อันดับเปรียบเทียบ", icon: ListOrderedIcon, source: true },
{ type: "team-composition", label: "องค์ประกอบทีม", icon: UsersIcon, source: true },
{ type: "rotation", label: "ลำดับคอมโบ", icon: ListOrderedIcon },
{ type: "table", label: "ตารางข้อมูล", icon: Table2Icon, source: true },
{ type: "comparison-chart", label: "กราฟเปรียบเทียบ", icon: BarChart3Icon, source: true },
{ type: "tabs", label: "แท็บ", icon: LayoutGridIcon },
{ type: "accordion", label: "แอคคอร์เดียน", icon: Rows3Icon },
{ type: "section", label: "ส่วนเนื้อหา", icon: Heading2Icon },
{ type: "columns", label: "คอลัมน์", icon: LayoutGridIcon },
{ type: "links", label: "ลิงก์", icon: FileTextIcon },
{ type: "separator", label: "เส้นคั่น", icon: SeparatorHorizontalIcon },
{ type: "image", label: "รูปภาพ", icon: ImageIcon, media: true },
{ type: "gallery", label: "แกลเลอรี", icon: ImageIcon, media: true },
];
export function AdminCommandDialog({
open,
onOpenChange,
navigation,
dataSources,
onInsert,
}: {
open: boolean;
onOpenChange: (open: boolean) => void;
navigation: AdminNavigation;
dataSources: Record<string, DataSourceSnapshot>;
onInsert: (block: SerializedBlock) => void;
}) {
const router = useRouter();
const source = Object.values(dataSources)[0];
return (
<CommandDialog
open={open}
onOpenChange={onOpenChange}
title="คำสั่งตัวแก้ไข"
description="ค้นหาหน้าหรือเพิ่มบล็อก"
className="max-w-xl"
>
<Command>
<CommandInput placeholder="ค้นหาหน้าหรือชนิดบล็อก…" />
<CommandList>
<CommandEmpty>ไม่พบคำสั่งที่ตรงกัน</CommandEmpty>
<CommandGroup heading="ไปยังหน้า">
{navigation.characters.flatMap((character) =>
character.pages.map((page) => (
<CommandItem
key={page.id}
value={`${character.nameTh} ${page.title}`}
onSelect={() => {
onOpenChange(false);
router.push(`/admin/${character.slug}/${page.slug}`);
}}
>
<FileTextIcon aria-hidden="true" />
<span>{character.nameTh} / {page.title}</span>
</CommandItem>
)),
)}
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="เพิ่มบล็อก">
{catalog.map((item) => {
const disabled = (item.source && !source) || item.media;
return (
<CommandItem
key={item.type}
value={`เพิ่ม ${item.label} ${item.type}`}
disabled={disabled}
onSelect={() => {
const block = createEditorBlock(item.type, source);
if (!block) return;
onInsert(block);
onOpenChange(false);
}}
>
<item.icon aria-hidden="true" />
<span>{item.label}</span>
{item.media ? <CommandShortcut>เลือกจากคลังสื่อ</CommandShortcut> : null}
{item.source && !source ? <CommandShortcut>ต้องมีแหล่งข้อมูล</CommandShortcut> : null}
</CommandItem>
);
})}
</CommandGroup>
</CommandList>
</Command>
</CommandDialog>
);
}