PageSourceSearch

https://snew.ai/assets/TemplatesAdminPage-BJcz6QEq.js

js snew.ai collected 2026-10-05 15:08:36 UTC 13,964 bytes, 1 lines download raw bytes

1import{r as l,j as t}from"./index-L9AYrVUw.js";import{T as F,a as G,b as N,c as C}from"./tabs-CmDZA0dx.js";import{I}from"./App-DyVHSnY3.js";import{T as V}from"./textarea-DQFi_3KT.js";import{B as P}from"./button-Bt8F5TkE.js";import{c as j}from"./locale-Cctu0V3Y.js";import{B as Y}from"./badge-C4DB55EV.js";import{A as S,a as E,b as D,c as w}from"./accordion-BTNqDhuz.js";import{l as z,c as H,a6 as q,dx as _,dt as U,dq as k,dm as L,g as y,ae as g,u as p,bf as O,f_ as K}from"./PlanAccessModal-P_W2GThH.js";import{i as Q}from"./ArrowCounterClockwise.es-B3mF2JQM.js";import{m as W}from"./FloppyDisk.es-DCGe340Q.js";import{P as X,a as Z}from"./poseTypes-Bm7PS-WL.js";import{T as A}from"./ThumbnailEditor-YRZUnO5t.js";import"./index-BKpKuXmL.js";import"./index-Eo00qZvG.js";import"./productFunnel-DiJFcMU2.js";import"./FloatingTopMenu-CIhwk2RR.js";import"./SnewLogo-Cg53XTnQ.js";import"./index-p7aFGi8o.js";import"./Trash.es-D2Zs5Rpt.js";import"./dissolve-CQo8GAUH.js";import"./Spinner.es-C_ZGu2no.js";import"./UploadSimple.es-BDJIa312.js";import"./CaretUp.es-D42dYZU2.js";const M=l.forwardRef(({className:s,...e},a)=>t.jsx("div",{ref:a,className:j("rounded-lg border bg-card text-card-foreground shadow-sm",s),...e}));M.displayName="Card";const ee=l.forwardRef(({className:s,...e},a)=>t.jsx("div",{ref:a,className:j("flex flex-col space-y-1.5 p-6",s),...e}));ee.displayName="CardHeader";const te=l.forwardRef(({className:s,...e},a)=>t.jsx("h3",{ref:a,className:j("text-2xl font-medium leading-none tracking-tight",s),...e}));te.displayName="CardTitle";const se=l.forwardRef(({className:s,...e},a)=>t.jsx("p",{ref:a,className:j("text-sm text-muted-foreground",s),...e}));se.displayName="CardDescription";const ae=l.forwardRef(({className:s,...e},a)=>t.jsx("div",{ref:a,className:j("p-6 pt-0",s),...e}));ae.displayName="CardContent";const ie=l.forwardRef(({className:s,...e},a)=>t.jsx("div",{ref:a,className:j("flex items-center p-6 pt-0",s),...e}));ie.displayName="CardFooter";const re={photography:"Photography",composition:"Composition",action:"Action",lifestyle:"Lifestyle"},ne=["photography","composition","action","lifestyle"],oe=[{key:"lighting",label:"Lighting"},{key:"composition",label:"Composition"},{key:"mood",label:"Mood"},{key:"colorPalette",label:"Color palette"},{key:"textureDetail",label:"Texture & detail"},{key:"cameraStyle",label:"Camera style"},{key:"additionalDetails",label:"Additional details"}];function $e(){const[,s]=l.useState(0),[e,a]=l.useState("");l.useEffect(()=>(z().catch(()=>{}),H(()=>s(c=>c+1))),[]);const n=l.useCallback(r=>!e||r.toLowerCase().includes(e.toLowerCase()),[e]);return l.useEffect(()=>{document.title="Templates Admin — Snew"},[]),t.jsxs("div",{className:"mx-auto max-w-5xl px-6 py-10 space-y-6",children:[t.jsxs("header",{className:"space-y-2",children:[t.jsx("h1",{className:"text-2xl font-semibold tracking-tight",children:"Templates Admin"}),t.jsx("p",{className:"text-sm text-muted-foreground",children:"Edit any catalog item below. Changes are saved to Lovable Cloud and reflect across the entire app."})]}),t.jsxs("div",{className:"relative",children:[t.jsx(q,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground"}),t.jsx(I,{placeholder:"Search by name, id, description…",value:e,onChange:r=>a(r.target.value),className:"pl-9"})]}),t.jsxs(F,{defaultValue:"scenes",children:[t.jsxs(G,{className:"grid w-full grid-cols-4",children:[t.jsxs(N,{value:"scenes",children:["Scenes (",_.length,")"]}),t.jsxs(N,{value:"poses",children:["Poses (",U.length,")"]}),t.jsxs(N,{value:"personas",children:["Personas (",k.length,")"]}),t.jsxs(N,{value:"video",children:["Video presets (",L.length,")"]})]}),t.jsx(C,{value:"scenes",className:"mt-4 space-y-6",children:ne.map(r=>{const c=_.filter(o=>o.category===r&&(n(o.name)||n(o.id)||n(o.description)));return c.length?t.jsxs("section",{className:"space-y-2",children:[t.jsxs("h2",{className:"text-sm font-medium text-muted-foreground",children:[re[r]," (",c.length,")"]}),t.jsx(S,{type:"multiple",className:"space-y-2",children:c.map(o=>t.jsx(le,{scene:o},o.id))})]},r):null})}),t.jsx(C,{value:"poses",className:"mt-4 space-y-6",children:X.map(r=>{const c=U.filter(o=>o.category===r&&(n(o.name)||n(o.id)||n(o.description)));return c.length?t.jsxs("section",{className:"space-y-2",children:[t.jsxs("h2",{className:"text-sm font-medium text-muted-foreground",children:[Z[r]," (",c.length,")"]}),t.jsx(S,{type:"multiple",className:"space-y-2",children:c.map(o=>t.jsx(de,{pose:o},o.id))})]},r):null})}),t.jsxs(C,{value:"personas",className:"mt-4 space-y-6",children:[t.jsx($,{title:"Named personas",items:k.filter(r=>r.category==="named"&&(n(r.name)||n(r.id)||n(r.description)))}),t.jsx($,{title:"Generic personas",items:k.filter(r=>r.category==="generic"&&(n(r.name)||n(r.id)||n(r.description)))})]}),t.jsx(C,{value:"video",className:"mt-4 space-y-2",children:t.jsx(S,{type:"multiple",className:"space-y-2",children:L.filter(r=>n(r.label)||n(r.id)).map(r=>
1t.jsx(pe,{id:r.id,label:r.label},r.id))})})]})]})}function T({kind:s,id:e,name:a,description:n}){const r=!!y(s,e);return t.jsxs("div",{className:"flex flex-col items-start gap-1 text-left",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"text-sm font-medium",children:a}),t.jsx("code",{className:"text-[10px] text-muted-foreground",children:e}),r&&t.jsx(Y,{variant:"secondary",className:"text-[10px]",children:"edited"})]}),n&&t.jsx("span",{className:"text-xs text-muted-foreground",children:n})]})}function R({onSave:s,onReset:e,dirty:a,hasOverride:n}){return t.jsxs("div",{className:"flex items-center justify-end gap-2 pt-2",children:[t.jsxs(P,{variant:"ghost",size:"sm",onClick:e,disabled:!n,children:[t.jsx(Q,{className:"h-3.5 w-3.5 mr-1"})," Reset to default"]}),t.jsxs(P,{size:"sm",onClick:s,disabled:!a,children:[t.jsx(W,{className:"h-3.5 w-3.5 mr-1"})," Save"]})]})}function u({label:s,value:e,onChange:a,multiline:n}){return t.jsxs("label",{className:"grid grid-cols-[160px_1fr] items-start gap-3 text-sm",children:[t.jsx("span",{className:"pt-2 text-xs font-medium text-muted-foreground",children:s}),n?t.jsx(V,{value:e,onChange:r=>a(r.target.value),rows:2,className:"text-xs"}):t.jsx(I,{value:e,onChange:r=>a(r.target.value),className:"text-xs"})]})}function le({scene:s}){const[e,a]=l.useState(()=>structuredClone(s));l.useEffect(()=>a(structuredClone(s)),[s]);const n=JSON.stringify(e)!==JSON.stringify(s),r=!!y("scene",s.id),c=async()=>{try{await g("scene",s.id,{name:e.name,description:e.description,thumbnailUrl:e.thumbnailUrl,modifiers:e.modifiers,negativeModifiers:e.negativeModifiers}),p.success(`${e.name} saved`)}catch(i){p.error("Save failed: "+i.message)}},o=async()=>{try{await O("scene",s.id),p.success("Reset to default")}catch(i){p.error(i.message)}},h=async i=>{a({...e,thumbnailUrl:i});try{await g("scene",s.id,{name:e.name,description:e.description,thumbnailUrl:i,modifiers:e.modifiers,negativeModifiers:e.negativeModifiers})}catch(m){p.error("Could not save thumbnail: "+m.message)}};return t.jsxs(E,{value:s.id,className:"border rounded-md px-3",children:[t.jsx(D,{className:"hover:no-underline",children:t.jsx(T,{kind:"scene",id:s.id,name:s.name,description:s.description})}),t.jsxs(w,{className:"space-y-3 pt-2",children:[t.jsx(A,{kind:"scene",itemId:s.id,itemName:e.name,promptSeed:`${e.name}. ${e.description}. ${e.modifiers.composition} ${e.modifiers.mood}`,value:e.thumbnailUrl,onChange:h}),t.jsx(u,{label:"Name",value:e.name,onChange:i=>a({...e,name:i})}),t.jsx(u,{label:"Description",value:e.description,onChange:i=>a({...e,description:i})}),t.jsxs("div",{className:"space-y-2 rounded-md bg-muted/30 p-3",children:[t.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Structured prompt slots"}),oe.map(i=>t.jsx(u,{label:i.label,multiline:!0,value:e.modifiers[i.key],onChange:m=>a({...e,modifiers:{...e.modifiers,[i.key]:m}})},i.key))]}),t.jsx(u,{label:"Negative prompts",multiline:!0,value:e.negativeModifiers??"",onChange:i=>a({...e,negativeModifiers:i})}),t.jsx(R,{onSave:c,onReset:o,dirty:n,hasOverride:r})]})]})}function de({pose:s}){const[e,a]=l.useState(()=>({...s}));l.useEffect(()=>a({...s}),[s]);const n=JSON.stringify(e)!==JSON.stringify(s),r=!!y("pose",s.id),c=async()=>{try{await g("pose",s.id,{name:e.name,description:e.description,thumbnailUrl:e.thumbnailUrl,promptDescription:e.promptDescription}),p.success(`${e.name} saved`)}catch(i){p.error(i.message)}},o=async()=>{await O("pose",s.id),p.success("Reset to default")},h=async i=>{a({...e,thumbnailUrl:i});try{await g("pose",s.id,{name:e.name,description:e.description,thumbnailUrl:i,promptDescription:e.promptDescription})}catch(m){p.error("Could not save thumbnail: "+m.message)}};return t.jsxs(E,{value:s.id,className:"border rounded-md px-3",children:[t.jsx(D,{className:"hover:no-underline",children:t.jsx(T,{kind:"pose",id:s.id,name:s.name,description:s.description})}),t.jsxs(w,{className:"space-y-3 pt-2",children:[t.jsx(A,{kind:"pose",itemId:s.id,itemName:e.name,promptSeed:`${e.name}. ${e.promptDescription}`,value:e.thumbnailUrl,onChange:h}),t.jsx(u,{label:"Name",value:e.name,onChange:i=>a({...e,name:i})}),t.jsx(u,{label:"Description",value:e.description,onChange:i=>a({...e,description:i})}),t.jsx(u,{label:"Prompt description",multiline:!0,value:e.promptDescription,onChange:i=>a({...e,promptDescription:i})}),t.jsx(R,{onSave:c,onReset:o,dirty:n,hasOverride:r})]})]})}function $({title:s,items:e}){return e.length?t.jsxs("section",{className:"space-y-2",children:[t.jsxs("h2",{className:"text-sm font-medium text-muted-foreground",children:[s," (",e.length,")"]}),t.jsx(S,{type:"multiple",className:"space-y-2",children:e.map(a=>t.jsx(ce,{persona:a},a.id))})]}):null}function ce({persona:s}){const[e,a]=l.useState(()=>structuredClone(s));l.useEffect(()=>a(structuredClone(s)),[s]);const n=JSON.stringify(e)!==JSON.stringify(s),r=!!y("persona",s.id),c=async()=>{try{const i={name:e.name,description:e.description,thumbnailUrl:e.thumbnailUrl};e.attributes?i.attributes=e.attributes:i.promptDescription=e.promptDescription,await g("persona",s.id,i),p.success(`${e.name}
1 saved`)}catch(i){p.error(i.message)}},o=async()=>{await O("persona",s.id),p.success("Reset to default")},h=async i=>{a({...e,thumbnailUrl:i});try{const m={name:e.name,description:e.description,thumbnailUrl:i};e.attributes?m.attributes=e.attributes:m.promptDescription=e.promptDescription,await g("persona",s.id,m)}catch(m){p.error("Could not save thumbnail: "+m.message)}};return t.jsxs(E,{value:s.id,className:"border rounded-md px-3",children:[t.jsx(D,{className:"hover:no-underline",children:t.jsx(T,{kind:"persona",id:s.id,name:s.name,description:s.description})}),t.jsxs(w,{className:"space-y-3 pt-2",children:[t.jsx(A,{kind:"persona",itemId:s.id,itemName:e.name,promptSeed:`Portrait of ${e.name}. ${e.promptDescription}`,value:e.thumbnailUrl,onChange:h}),t.jsx(u,{label:"Display name",value:e.name,onChange:i=>a({...e,name:i})}),t.jsx(u,{label:"Description",value:e.description,onChange:i=>a({...e,description:i})}),e.attributes?t.jsxs("div",{className:"space-y-2 rounded-md bg-muted/30 p-3",children:[t.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Structured attributes (named persona)"}),Object.keys(e.attributes).map(i=>t.jsx(u,{label:i,value:String(e.attributes[i]??""),onChange:m=>{const v={...e.attributes};v[i]=i==="age"?Number(m)||0:m,a({...e,attributes:v})}},i)),t.jsx("p",{className:"text-[11px] text-muted-foreground",children:"The prompt is rebuilt automatically from these attributes on save."})]}):t.jsx(u,{label:"Prompt description",multiline:!0,value:e.promptDescription,onChange:i=>a({...e,promptDescription:i})}),t.jsxs(M,{className:"bg-muted/20 p-3",children:[t.jsx("p",{className:"text-[11px] text-muted-foreground mb-1",children:"Current generated prompt"}),t.jsx("p",{className:"text-xs font-mono leading-relaxed",children:s.promptDescription})]}),t.jsx(R,{onSave:c,onReset:o,dirty:n,hasOverride:r})]})]})}function me(s){return(K(s,"{productName}")??[]).map(a=>typeof a=="string"?{kind:"text",text:a}:{kind:"slot",id:a.id,label:a.label,options:[...a.options]})}function pe({id:s,label:e}){const a=y("video_preset",s),n=l.useMemo(()=>a!=null&&a.data&&Array.isArray(a.data.segments)?a.data.segments.map(d=>typeof d=="string"?{kind:"text",text:d}:{kind:"slot",id:d.id,label:d.label,options:d.options}):me(s),[s,a]),[r,c]=l.useState(e),[o,h]=l.useState(n);l.useEffect(()=>h(n),[n]);const i=JSON.stringify(n)!==JSON.stringify(o)||r!==e,m=!!a,v=async()=>{try{const d=o.map(x=>x.kind==="text"?x.text:{id:x.id,label:x.label,options:x.options});await g("video_preset",s,{label:r,segments:d}),p.success(`${r} saved`)}catch(d){p.error(d.message)}},J=async()=>{await O("video_preset",s),p.success("Reset to default")};return t.jsxs(E,{value:s,className:"border rounded-md px-3",children:[t.jsx(D,{className:"hover:no-underline",children:t.jsx(T,{kind:"video_preset",id:s,name:e,description:"Structured video prompt template"})}),t.jsxs(w,{className:"space-y-3 pt-2",children:[t.jsx(u,{label:"Label",value:r,onChange:c}),t.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Use ",t.jsx("code",{children:"{productName}"})," as a placeholder where the product name should appear."]}),t.jsx("div",{className:"space-y-2 rounded-md bg-muted/30 p-3",children:o.map((d,x)=>t.jsx("div",{className:"space-y-1",children:d.kind==="text"?t.jsx(u,{label:`Text #${x+1}`,value:d.text,onChange:b=>{const f=[...o];f[x]={...d,text:b},h(f)}}):t.jsxs("div",{className:"space-y-1 border-l-2 border-primary/30 pl-2",children:[t.jsx(u,{label:`Slot ${d.id} · default`,value:d.label,onChange:b=>{const f=[...o];f[x]={...d,label:b},h(f)}}),t.jsx(u,{label:"Options (comma-sep.)",value:d.options.join(", "),onChange:b=>{const f=[...o];f[x]={...d,options:b.split(",").map(B=>B.trim()).filter(Boolean)},h(f)}})]})},x))}),t.jsx(R,{onSave:v,onReset:J,dirty:i,hasOverride:m})]})]})}export{$e as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.