admin page

This commit is contained in:
koreacomp5
2025-10-29 22:56:34 +09:00
parent 53b6376966
commit da6b396acc
6 changed files with 307 additions and 49 deletions

View File

@@ -0,0 +1,82 @@
"use client";
import { useState } from "react";
type MenuItem = { id: string; label: string; path: string; visible: boolean; order: number };
const initialMenus: MenuItem[] = [
{ id: "1", label: "홈", path: "/", visible: true, order: 1 },
{ id: "2", label: "게시판", path: "/boards", visible: true, order: 2 },
{ id: "3", label: "쿠폰", path: "/coupons", visible: false, order: 3 },
];
export default function AdminMenusPage() {
const [menus, setMenus] = useState<MenuItem[]>(initialMenus);
const [form, setForm] = useState<{ label: string; path: string; visible: boolean }>({ label: "", path: "", visible: true });
function addMenu() {
if (!form.label.trim() || !form.path.trim()) return;
const next: MenuItem = { id: crypto.randomUUID(), label: form.label, path: form.path, visible: form.visible, order: menus.length + 1 };
setMenus((m) => [...m, next]);
setForm({ label: "", path: "", visible: true });
}
function removeMenu(id: string) {
setMenus((m) => m.filter((x) => x.id !== id));
}
function toggleVisible(id: string) {
setMenus((m) => m.map((x) => (x.id === id ? { ...x, visible: !x.visible } : x)));
}
return (
<div className="space-y-6">
<header className="flex items-center justify-between">
<h1 className="text-xl md:text-2xl font-bold text-neutral-900"> </h1>
</header>
{/* 추가 폼 */}
<section className="rounded-xl bg-white border border-neutral-200 overflow-hidden">
<div className="px-4 py-3 border-b border-neutral-200 text-sm font-medium"> </div>
<div className="p-4 grid grid-cols-1 md:grid-cols-[240px_1fr_auto] gap-3 items-center">
<input className="h-10 rounded-md border border-neutral-300 px-3 text-sm" placeholder="이름" value={form.label} onChange={(e) => setForm({ ...form, label: e.target.value })} />
<input className="h-10 rounded-md border border-neutral-300 px-3 text-sm" placeholder="경로 (/path)" value={form.path} onChange={(e) => setForm({ ...form, path: e.target.value })} />
<div className="flex items-center gap-3">
<label className="flex items-center gap-1 text-sm text-neutral-700">
<input type="checkbox" checked={form.visible} onChange={(e) => setForm({ ...form, visible: e.target.checked })} />
</label>
<button className="h-10 px-4 rounded-md bg-neutral-900 text-white text-sm hover:bg-neutral-800" onClick={addMenu}></button>
</div>
</div>
</section>
{/* 목록 */}
<section className="rounded-xl bg-white border border-neutral-200 overflow-hidden">
<div className="px-4 py-2 text-xs text-neutral-500 border-b border-neutral-200 grid grid-cols-[60px_1fr_1fr_120px_120px]">
<div>#</div>
<div></div>
<div></div>
<div className="text-center"></div>
<div className="text-right"></div>
</div>
<ul className="divide-y divide-neutral-100">
{menus.sort((a, b) => a.order - b.order).map((m, idx) => (
<li key={m.id} className="px-4 py-3 grid grid-cols-[60px_1fr_1fr_120px_120px] items-center">
<div className="text-sm text-neutral-500">{idx + 1}</div>
<div className="truncate text-sm">{m.label}</div>
<div className="truncate text-sm text-neutral-700">{m.path}</div>
<div className="text-center">
<button onClick={() => toggleVisible(m.id)} className={`h-7 px-3 rounded-full text-xs border ${m.visible ? "bg-neutral-900 text-white border-neutral-900" : "bg-white text-neutral-700 border-neutral-300 hover:bg-neutral-100"}`}>{m.visible ? "표시" : "숨김"}</button>
</div>
<div className="text-right">
<button onClick={() => removeMenu(m.id)} className="h-7 px-3 rounded-md border border-neutral-300 text-xs hover:bg-neutral-100"></button>
</div>
</li>
))}
</ul>
</section>
</div>
);
}