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 { FileUploadField } from "@/components/admin/FileUploadField";
|
||||||
import { ProjectScanImport } from "@/components/admin/ProjectScanImport";
|
import { ProjectScanImport } from "@/components/admin/ProjectScanImport";
|
||||||
|
import { SceneInputsEditor } from "@/components/admin/SceneColorEditor";
|
||||||
|
|
||||||
// ── styles ───────────────────────────────────────────────────────────────────
|
// ── 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";
|
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 [saving, setSaving] = useState(false);
|
||||||
const [err, setErr] = useState<string | null>(null);
|
const [err, setErr] = useState<string | null>(null);
|
||||||
const [scanOpen, setScanOpen] = useState(false);
|
const [scanOpen, setScanOpen] = useState(false);
|
||||||
|
const [inputsFor, setInputsFor] = useState<string | null>(null);
|
||||||
const base = "/api/admin/resource/scenes";
|
const base = "/api/admin/resource/scenes";
|
||||||
|
|
||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
@@ -163,7 +165,8 @@ function ScenesTab({ projectId }: { projectId: string }) {
|
|||||||
) : (
|
) : (
|
||||||
<ul className="space-y-1.5">
|
<ul className="space-y-1.5">
|
||||||
{rows.map((s) => (
|
{rows.map((s) => (
|
||||||
<li key={s.id} className="flex items-center justify-between rounded-lg border border-[#1e2235] bg-[#0c0e1a] px-3 py-2">
|
<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">
|
<div className="flex min-w-0 items-center gap-2">
|
||||||
<span className="text-[10px] text-gray-600">#{s.sort}</span>
|
<span className="text-[10px] text-gray-600">#{s.sort}</span>
|
||||||
<span className="truncate text-sm text-gray-200">{s.title}</span>
|
<span className="truncate text-sm text-gray-200">{s.title}</span>
|
||||||
@@ -172,9 +175,23 @@ function ScenesTab({ projectId }: { projectId: string }) {
|
|||||||
{!s.is_active && <span className="rounded bg-gray-500/15 px-1.5 py-0.5 text-[10px] text-gray-400">غیرفعال</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>
|
||||||
<div className="flex shrink-0 items-center gap-2">
|
<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={ghost} onClick={() => { setEditId(s.id); setDraft(sceneToDraft(s)); }}>ویرایش</button>
|
||||||
<button className={del} onClick={() => remove(s)}>حذف</button>
|
<button className={del} onClick={() => remove(s)}>حذف</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{inputsFor === s.id && (
|
||||||
|
<div className="border-t border-[#1e2235] p-3">
|
||||||
|
<SceneInputsEditor sceneId={s.id} setError={setErr} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -737,7 +737,7 @@ const ELEMENT_TYPES = [
|
|||||||
"DropDown", "Fill", "Color", "Number", "Date", "Toggle", "Slider", "Counter", "Hidden",
|
"DropDown", "Fill", "Color", "Number", "Date", "Toggle", "Slider", "Counter", "Hidden",
|
||||||
];
|
];
|
||||||
|
|
||||||
function SceneInputsEditor({
|
export function SceneInputsEditor({
|
||||||
sceneId,
|
sceneId,
|
||||||
setError,
|
setError,
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
Reference in New Issue
Block a user