feat(admin): scene-inputs editor in /admin/projects scene list (reuse SceneInputsEditor)
The per-scene inputs (content elements) editor existed only on /admin/templates (SceneColorEditor). /admin/projects → «صحنهها» used the older ProjectScenes which had no inputs panel, so admins couldn't see/edit a scene's inputs there. Export SceneInputsEditor and add an «ورودیها» expander per scene row in ProjectScenes (GET/POST/PUT/DELETE /v1/scene-elements, 15 element types). Verified c1 → 6 inputs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
|
||||
import { FileUploadField } from "@/components/admin/FileUploadField";
|
||||
import { ProjectScanImport } from "@/components/admin/ProjectScanImport";
|
||||
import { SceneInputsEditor } from "@/components/admin/SceneColorEditor";
|
||||
|
||||
// ── styles ───────────────────────────────────────────────────────────────────
|
||||
const inp = "rounded-lg border border-[#262b40] bg-[#0c0e1a] px-2.5 py-1.5 text-sm text-gray-100 outline-none focus:border-indigo-500";
|
||||
@@ -95,6 +96,7 @@ function ScenesTab({ projectId }: { projectId: string }) {
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const [scanOpen, setScanOpen] = useState(false);
|
||||
const [inputsFor, setInputsFor] = useState<string | null>(null);
|
||||
const base = "/api/admin/resource/scenes";
|
||||
|
||||
const load = useCallback(async () => {
|
||||
@@ -163,18 +165,33 @@ function ScenesTab({ projectId }: { projectId: string }) {
|
||||
) : (
|
||||
<ul className="space-y-1.5">
|
||||
{rows.map((s) => (
|
||||
<li key={s.id} className="flex items-center justify-between rounded-lg border border-[#1e2235] bg-[#0c0e1a] px-3 py-2">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className="text-[10px] text-gray-600">#{s.sort}</span>
|
||||
<span className="truncate text-sm text-gray-200">{s.title}</span>
|
||||
<code className="truncate rounded bg-[#1e2235] px-1.5 py-0.5 text-[10px] text-indigo-300" dir="ltr">{s.key}</code>
|
||||
<span className="rounded bg-[#1e2235] px-1.5 py-0.5 text-[10px] text-gray-400">{SCENE_TYPES.find((t) => t.v === s.scene_type)?.l ?? s.scene_type}</span>
|
||||
{!s.is_active && <span className="rounded bg-gray-500/15 px-1.5 py-0.5 text-[10px] text-gray-400">غیرفعال</span>}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
<button className={ghost} onClick={() => { setEditId(s.id); setDraft(sceneToDraft(s)); }}>ویرایش</button>
|
||||
<button className={del} onClick={() => remove(s)}>حذف</button>
|
||||
<li key={s.id} className="rounded-lg border border-[#1e2235] bg-[#0c0e1a]">
|
||||
<div className="flex items-center justify-between px-3 py-2">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className="text-[10px] text-gray-600">#{s.sort}</span>
|
||||
<span className="truncate text-sm text-gray-200">{s.title}</span>
|
||||
<code className="truncate rounded bg-[#1e2235] px-1.5 py-0.5 text-[10px] text-indigo-300" dir="ltr">{s.key}</code>
|
||||
<span className="rounded bg-[#1e2235] px-1.5 py-0.5 text-[10px] text-gray-400">{SCENE_TYPES.find((t) => t.v === s.scene_type)?.l ?? s.scene_type}</span>
|
||||
{!s.is_active && <span className="rounded bg-gray-500/15 px-1.5 py-0.5 text-[10px] text-gray-400">غیرفعال</span>}
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
<button
|
||||
className={inputsFor === s.id
|
||||
? "rounded-lg border border-indigo-500 bg-indigo-500/15 px-2.5 py-1 text-xs text-indigo-200"
|
||||
: "rounded-lg border border-[#262b40] px-2.5 py-1 text-xs text-gray-300 hover:bg-[#161a2e]"}
|
||||
onClick={() => setInputsFor((cur) => (cur === s.id ? null : s.id))}
|
||||
>
|
||||
ورودیها
|
||||
</button>
|
||||
<button className={ghost} onClick={() => { setEditId(s.id); setDraft(sceneToDraft(s)); }}>ویرایش</button>
|
||||
<button className={del} onClick={() => remove(s)}>حذف</button>
|
||||
</div>
|
||||
</div>
|
||||
{inputsFor === s.id && (
|
||||
<div className="border-t border-[#1e2235] p-3">
|
||||
<SceneInputsEditor sceneId={s.id} setError={setErr} />
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -737,7 +737,7 @@ const ELEMENT_TYPES = [
|
||||
"DropDown", "Fill", "Color", "Number", "Date", "Toggle", "Slider", "Counter", "Hidden",
|
||||
];
|
||||
|
||||
function SceneInputsEditor({
|
||||
export function SceneInputsEditor({
|
||||
sceneId,
|
||||
setError,
|
||||
}: {
|
||||
|
||||
Reference in New Issue
Block a user