@zenith-open/zenithcms-admin 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/assets/ApiExplorerPage-UJpoKRI0.js +42 -0
- package/dist/assets/ApiExplorerPage-UJpoKRI0.js.map +1 -0
- package/dist/assets/AuditLogPage-8xYlRl1I.js +1 -0
- package/dist/assets/AuditLogPage-8xYlRl1I.js.map +1 -0
- package/dist/assets/BlockBuilderPage-DcOo3Vnt.js +1 -0
- package/dist/assets/BlockBuilderPage-DcOo3Vnt.js.map +1 -0
- package/dist/assets/BuilderPage-Iu8F_bN1.js +1 -0
- package/dist/assets/BuilderPage-Iu8F_bN1.js.map +1 -0
- package/dist/assets/CollectionHooksPage-Dn_ujtlp.js +7 -0
- package/dist/assets/CollectionHooksPage-Dn_ujtlp.js.map +1 -0
- package/dist/assets/CollectionsPage-BSPHf7H2.js +1 -0
- package/dist/assets/CollectionsPage-BSPHf7H2.js.map +1 -0
- package/dist/assets/ComponentBuilderPage-CT6S12LA.js +14 -0
- package/dist/assets/ComponentBuilderPage-CT6S12LA.js.map +1 -0
- package/dist/assets/DashboardBuilder-Cbi9Ddiu.js +1 -0
- package/dist/assets/DashboardBuilder-Cbi9Ddiu.js.map +1 -0
- package/dist/assets/EmptyState-X_SXKpQY.js +1 -0
- package/dist/assets/EmptyState-X_SXKpQY.js.map +1 -0
- package/dist/assets/MediaLibrary-BzXE95xo.js +1 -0
- package/dist/assets/MediaLibrary-BzXE95xo.js.map +1 -0
- package/dist/assets/PluginsPage-5YRpbP-N.js +10 -0
- package/dist/assets/PluginsPage-5YRpbP-N.js.map +1 -0
- package/dist/assets/RedirectsPage-D_4jAdaI.js +1 -0
- package/dist/assets/RedirectsPage-D_4jAdaI.js.map +1 -0
- package/dist/assets/SchemaBuilderPage-EFA5XIAa.js +14 -0
- package/dist/assets/SchemaBuilderPage-EFA5XIAa.js.map +1 -0
- package/dist/assets/SettingsPage-BRpcMw48.js +33 -0
- package/dist/assets/SettingsPage-BRpcMw48.js.map +1 -0
- package/dist/assets/SetupWizard-D57HIkrs.js +62 -0
- package/dist/assets/SetupWizard-D57HIkrs.js.map +1 -0
- package/dist/assets/SpatialEditor-CPgS7Zrd.js +3 -0
- package/dist/assets/SpatialEditor-CPgS7Zrd.js.map +1 -0
- package/dist/assets/TemplatesPage-B-nNYv3o.js +1 -0
- package/dist/assets/TemplatesPage-B-nNYv3o.js.map +1 -0
- package/dist/assets/TrashPage-Ccusal1w.js +1 -0
- package/dist/assets/TrashPage-Ccusal1w.js.map +1 -0
- package/dist/assets/index-ChcKY5Xe.js +11 -0
- package/dist/assets/index-ChcKY5Xe.js.map +1 -0
- package/dist/assets/index-CxhwdV2K.css +1 -0
- package/dist/assets/login-bg.png +0 -0
- package/dist/assets/rolldown-runtime-CNC7AqOf.js +1 -0
- package/dist/assets/useUnsavedGuard-CMMKQT9a.js +1 -0
- package/dist/assets/useUnsavedGuard-CMMKQT9a.js.map +1 -0
- package/dist/assets/utils-fgvbH6CB.js +1 -0
- package/dist/assets/utils-fgvbH6CB.js.map +1 -0
- package/dist/assets/vendor-C-9IqjvY.js +1 -0
- package/dist/assets/vendor-C-9IqjvY.js.map +1 -0
- package/dist/assets/vendor-forms-BnBLxarY.js +1 -0
- package/dist/assets/vendor-forms-BnBLxarY.js.map +1 -0
- package/dist/assets/vendor-react-DQVTOTFO.js +195 -0
- package/dist/assets/vendor-react-DQVTOTFO.js.map +1 -0
- package/dist/favicon.svg +1 -0
- package/dist/icons.svg +24 -0
- package/dist/index.html +30 -0
- package/dist/logo/zenith.svg +9 -0
- package/dist/sw.js +3 -0
- package/dist/sw.js.map +1 -0
- package/dist/workbox-9c191d2f.js +3 -0
- package/dist/workbox-9c191d2f.js.map +1 -0
- package/dist/zenith.svg +9 -0
- package/package.json +60 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{C as t,E as n,F as r,G as i,Hn as a,Ln as o,Mt as s,Q as c,T as l,an as u,hr as d,ir as ee,l as f,mr as p,rr as m,sn as h,u as g,vr as _,w as te,xr as v,zt as ne}from"./vendor-react-DQVTOTFO.js";import{a as y,o as b,t as x}from"./utils-fgvbH6CB.js";import{_ as re,p as S}from"./index-ChcKY5Xe.js";var C=e(v(),1),w=_(),T=[{name:`beforeValidate`,label:`Before Validate`,description:`Runs before document validation. Use to sanitize or enrich input data.`,event:`beforeValidate`,hasReturn:!0},{name:`beforeCreate`,label:`Before Create`,description:`Runs after validation, before document is saved. Use to set computed fields.`,event:`beforeCreate`,hasReturn:!0},{name:`afterCreate`,label:`After Create`,description:`Runs after document is created. Use for side effects like notifications.`,event:`afterCreate`,hasReturn:!1},{name:`beforeUpdate`,label:`Before Update`,description:`Runs after validation, before document is updated.`,event:`beforeUpdate`,hasReturn:!0},{name:`afterUpdate`,label:`After Update`,description:`Runs after document is updated. Use for cache invalidation, sync.`,event:`afterUpdate`,hasReturn:!1},{name:`beforeDelete`,label:`Before Delete`,description:`Runs before document deletion. Use to prevent deletion or cascade.`,event:`beforeDelete`,hasReturn:!1},{name:`afterDelete`,label:`After Delete`,description:`Runs after document is deleted. Use for cleanup.`,event:`afterDelete`,hasReturn:!1},{name:`afterRead`,label:`After Read`,description:`Runs after document is read. Use to transform output data.`,event:`afterRead`,hasReturn:!0},{name:`afterError`,label:`After Error`,description:`Runs when an error occurs during any lifecycle event.`,event:`afterError`,hasReturn:!1}],E=[`get`,`post`,`put`,`patch`,`delete`],D=`(data, user, context) => {
|
|
2
|
+
// Your hook logic here
|
|
3
|
+
// data: the document data being processed
|
|
4
|
+
// user: the authenticated user performing the action
|
|
5
|
+
// context: { hookType: string /* additional context */ }
|
|
6
|
+
return data;
|
|
7
|
+
}`,O=({value:e,onChange:t,theme:n,height:r=`160px`})=>(0,w.jsx)(`textarea`,{value:e,onChange:e=>t(e.target.value),spellCheck:!1,className:x(`w-full border rounded-none-none px-4 py-3 font-mono text-sm leading-relaxed resize-y outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all`,n===`dark`?`bg-app border-z-border text-z-secondary focus:border-z-border/50`:`bg-z-accent border-z-border text-z-secondary focus:border-z-border`),style:{minHeight:r,fontFamily:`ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace`}}),k=()=>{let{slug:e}=d(),_=p(),{theme:v}=y(),[k,A]=(0,C.useState)(null),[ie,j]=(0,C.useState)(!0),[M,N]=(0,C.useState)(!1),[P,F]=(0,C.useState)(null),[I,L]=(0,C.useState)({}),[R,z]=(0,C.useState)([]),[B,V]=(0,C.useState)(!1),[H,U]=(0,C.useState)({}),[W,G]=(0,C.useState)([]),[K,q]=(0,C.useState)(!1),J=()=>JSON.stringify(I)!==JSON.stringify(H)||JSON.stringify(R)!==JSON.stringify(W)||B!==K,[ae,oe]=(0,C.useState)([]),{data:Y,isLoading:X}=re(),Z=(0,C.useCallback)(async()=>{if(Y){j(!0);try{let t=(Y.collections||[]).find(t=>t.slug===e);if(!t){f.error(`Collection not found`),_(`/collections`);return}let n=t.hooks||{},r=t.endpoints||[];A({slug:t.slug,name:t.label||t.name||t.slug,hooks:n,endpoints:r,access:t.access,publicRead:!!t.publicRead}),L(n),z(r),V(!!t.publicRead),U(n),G(r),q(!!t.publicRead);let i=(t.fields||[]).filter(e=>![`row`,`tabs`,`ui`,`collapsible`].includes(e.type));oe(i.map(e=>({name:e.name,type:e.type,label:e.label||e.name})));let a={};i.forEach(e=>{e.hooks&&(a[e.name]={beforeChange:e.hooks.beforeChange||``,afterRead:e.hooks.afterRead||``,validate:e.hooks.validate||``})})}catch(e){console.error(`Failed to load collection config`,e),f.error(`Failed to load collection configuration`)}finally{j(!1)}}},[e,_,Y]);(0,C.useEffect)(()=>{X||Z()},[Z,Y,X]);let se=async()=>{if(J()){N(!0);try{await b.patch(`/system/collections/${e}`,{hooks:I,endpoints:R,publicRead:B}),U(I),G(R),q(B),f.success(`Collection configuration saved`)}catch(e){f.error(e?.response?.data?.error||`Failed to save configuration`)}finally{N(!1)}}},ce=e=>{I[e]||(L(t=>({...t,[e]:D})),F(e))},le=(e,t)=>{L(n=>({...n,[e]:t}))},ue=e=>{L(t=>{let n={...t};return delete n[e],n}),P===e&&F(null)},de=()=>{z(e=>[...e,{path:``,method:`get`,description:``}])},Q=(e,t,n)=>{z(r=>r.map((r,i)=>i===e?{...r,[t]:n}:r))},fe=e=>{z(t=>t.filter((t,n)=>n!==e))},$=T.filter(e=>I[e.name]);return ie?(0,w.jsx)(`div`,{className:`min-h-[80vh] flex items-center justify-center`,children:(0,w.jsx)(o,{size:32,className:`text-z-secondary animate-spin`})}):(0,w.jsxs)(`div`,{className:`flex flex-col h-[calc(100vh-64px)] overflow-hidden`,children:[(0,w.jsx)(S,{title:`${e} hooks`,actions:(0,w.jsxs)(`button`,{onClick:se,disabled:M||!J(),className:`flex items-center justify-center gap-3 px-8 py-4 rounded-none-none text-sm font-semibold transition-all shadow-sm active:scale-95 disabled:opacity-50 bg-z-accent text-z-logo-text hover:bg-z-accent`,children:[M?(0,w.jsx)(o,{size:14,className:`animate-spin`}):(0,w.jsx)(i,{size:14}),`Save Configuration`]})}),(0,w.jsx)(`div`,{className:x(`flex-1 overflow-y-auto p-6 md:p-10 space-y-8 transition-colors duration-500`,v===`dark`?`bg-app text-z-primary`:`bg-[#fafafa] text-z-primary`),children:(0,w.jsx)(`div`,{className:`max-w-[1400px] mx-auto space-y-8`,children:(0,w.jsxs)(`div`,{className:`grid grid-cols-1 xl:grid-cols-3 gap-8`,children:[(0,w.jsxs)(`div`,{className:`xl:col-span-1 space-y-6`,children:[(0,w.jsxs)(`div`,{className:x(`p-5 border rounded-none-none`,v===`dark`?`bg-z-panel/5 border-z-border`:`bg-z-panel border-z-border shadow-sm`),children:[(0,w.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,w.jsx)(s,{size:14,className:`text-z-secondary`}),(0,w.jsx)(`span`,{className:`text-sm font-semibold`,children:`Public Read Access`})]}),(0,w.jsx)(`button`,{onClick:()=>V(!B),className:`text-z-secondary hover:text-z-secondary transition-colors`,children:B?(0,w.jsx)(te,{size:28}):(0,w.jsx)(l,{size:28,className:`text-z-secondary`})})]}),(0,w.jsx)(`p`,{className:`text-sm text-z-secondary font-bold mt-2`,children:`Allow unauthenticated access to read this collection`})]}),(0,w.jsxs)(`div`,{className:x(`border rounded-none-none overflow-hidden`,v===`dark`?`bg-z-panel/5 border-z-border`:`bg-z-panel border-z-border shadow-sm`),children:[(0,w.jsx)(`div`,{className:`px-5 py-3 border-b border-z-border`,children:(0,w.jsx)(`span`,{className:`text-sm font-semibold text-z-muted`,children:`Available Lifecycle Hooks`})}),(0,w.jsx)(`div`,{className:`divide-y divide-z-border`,children:T.map(e=>{let t=!!I[e.name];return(0,w.jsxs)(`div`,{className:x(`px-5 py-3 flex items-center justify-between transition-colors`,t?`bg-z-hover`:v===`dark`?`hover:bg-z-panel`:`hover:bg-[var(--z-bg-input)]`),children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-2`,children:[t&&(0,w.jsx)(`div`,{className:`w-1.5 h-1.5 rounded-none-none bg-z-border`}),(0,w.jsx)(`span`,{className:x(`text-sm font-semibold `,`text-z-secondary`),children:e.label})]}),!t&&(0,w.jsx)(`button`,{onClick:()=>ce(e.name),className:`text-z-secondary hover:text-z-secondary transition-colors`,title:`Add ${e.label} hook`,children:(0,w.jsx)(c,{size:14})})]},e.name)})})]}),(0,w.jsxs)(`div`,{className:x(`p-5 border rounded-none-none space-y-3`,v===`dark`?`bg-z-panel/5 border-z-border`:`bg-z-panel border-z-border shadow-sm`),children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,w.jsx)(n,{size:12,className:`text-z-secondary`}),(0,w.jsx)(`span`,{className:`text-sm font-semibold text-z-muted`,children:`Runtime Info`})]}),(0,w.jsxs)(`div`,{className:`space-y-2`,children:[(0,w.jsxs)(`div`,{className:`flex justify-between`,children:[(0,w.jsx)(`span`,{className:`text-sm text-z-secondary font-bold`,children:`Active Hooks`}),(0,w.jsx)(`span`,{className:`text-sm text-z-secondary font-semibold`,children:$.length})]}),(0,w.jsxs)(`div`,{className:`flex justify-between`,children:[(0,w.jsx)(`span`,{className:`text-sm text-z-secondary font-bold`,children:`Custom Endpoints`}),(0,w.jsx)(`span`,{className:`text-sm text-z-secondary font-semibold`,children:R.length})]}),(0,w.jsxs)(`div`,{className:`flex justify-between`,children:[(0,w.jsx)(`span`,{className:`text-sm text-z-secondary font-bold`,children:`Fields`}),(0,w.jsx)(`span`,{className:`text-sm text-z-secondary font-semibold`,children:ae.length})]})]})]})]}),(0,w.jsxs)(`div`,{className:`xl:col-span-2 space-y-8`,children:[(0,w.jsxs)(`div`,{className:`space-y-4`,children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-3 border-b border-z-border pb-4`,children:[(0,w.jsx)(g,{size:16,className:`text-z-secondary`}),(0,w.jsx)(`h2`,{className:`text-sm font-semibold`,children:`Collection Lifecycle Hooks`}),(0,w.jsxs)(`span`,{className:`text-sm text-z-secondary font-bold ml-auto`,children:[$.length,` active`]})]}),$.length===0?(0,w.jsxs)(`div`,{className:x(`p-8 border border-dashed rounded-none-none text-center space-y-3`,`border-z-border`),children:[(0,w.jsx)(a,{size:32,className:`mx-auto text-z-secondary`}),(0,w.jsx)(`p`,{className:`text-sm font-semibold text-z-secondary`,children:`No hooks configured`}),(0,w.jsx)(`p`,{className:`text-sm text-z-secondary`,children:`Click + in the sidebar to add lifecycle hooks`})]}):(0,w.jsx)(ee,{children:$.map(e=>{let n=P===e.name;return(0,w.jsxs)(m.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},exit:{opacity:0,y:-8},className:x(`border rounded-none-none overflow-hidden`,v===`dark`?`bg-z-panel/5 border-z-border`:`bg-z-panel border-z-border shadow-sm`),children:[(0,w.jsxs)(`button`,{onClick:()=>F(n?null:e.name),className:x(`w-full px-5 py-4 flex items-center justify-between transition-colors`,n?v===`dark`?`bg-z-hover`:`bg-[var(--z-bg-input)]`:v===`dark`?`hover:bg-z-panel`:`hover:bg-[var(--z-bg-input)]`),children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-3`,children:[n?(0,w.jsx)(h,{size:14,className:`text-z-secondary`}):(0,w.jsx)(u,{size:14,className:`text-z-secondary`}),(0,w.jsx)(ne,{size:14,className:`text-z-secondary`}),(0,w.jsxs)(`div`,{className:`flex flex-col items-start`,children:[(0,w.jsx)(`span`,{className:`text-sm font-semibold text-z-primary`,children:e.label}),(0,w.jsx)(`span`,{className:`text-sm text-z-secondary font-bold`,children:e.event})]})]}),(0,w.jsx)(`button`,{onClick:t=>{t.stopPropagation(),ue(e.name)},className:`p-2 text-z-secondary hover:text-red-400 transition-colors`,title:`Remove hook`,children:(0,w.jsx)(t,{size:14})})]}),n&&(0,w.jsxs)(`div`,{className:`px-5 pb-5 space-y-3`,children:[(0,w.jsx)(`p`,{className:`text-sm text-z-muted font-bold`,children:e.description}),(0,w.jsx)(O,{value:I[e.name],onChange:t=>le(e.name,t),theme:v,height:`200px`})]})]},e.name)})})]}),(0,w.jsxs)(`div`,{className:`space-y-4`,children:[(0,w.jsxs)(`div`,{className:`flex items-center justify-between border-b border-z-border pb-4`,children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,w.jsx)(s,{size:16,className:`text-z-secondary`}),(0,w.jsx)(`h2`,{className:`text-sm font-semibold`,children:`Custom Endpoints`}),(0,w.jsxs)(`span`,{className:`text-sm text-z-secondary font-bold`,children:[R.length,` defined`]})]}),(0,w.jsxs)(`button`,{onClick:de,className:`flex items-center gap-2 px-3 py-1.5 border border-z-border hover:border-z-active-border hover:bg-z-hover text-sm font-semibold transition-all text-z-secondary hover:text-z-primary`,children:[(0,w.jsx)(c,{size:10}),`Add Endpoint`]})]}),R.length===0?(0,w.jsxs)(`div`,{className:x(`p-8 border border-dashed rounded-none-none text-center space-y-3`,`border-z-border`),children:[(0,w.jsx)(s,{size:32,className:`mx-auto text-z-secondary`}),(0,w.jsx)(`p`,{className:`text-sm font-semibold text-z-secondary`,children:`No custom endpoints`}),(0,w.jsx)(`p`,{className:`text-sm text-z-secondary`,children:`Add custom API endpoints for this collection`})]}):(0,w.jsx)(`div`,{className:`space-y-4`,children:R.map((e,n)=>(0,w.jsxs)(`div`,{className:x(`p-5 border rounded-none-none space-y-4`,v===`dark`?`bg-z-panel/5 border-z-border`:`bg-z-panel border-z-border shadow-sm`),children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,w.jsx)(`select`,{value:e.method,onChange:e=>Q(n,`method`,e.target.value),className:x(`bg-z-input border-z-border text-z-primary text-sm font-semibold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black py-1.5 px-3 rounded-none-none focus:border-z-active-border`,`border-z-border text-z-secondary`),children:E.map(e=>(0,w.jsx)(`option`,{value:e,children:e},e))}),(0,w.jsx)(`input`,{type:`text`,value:e.path,onChange:e=>Q(n,`path`,e.target.value),placeholder:`/custom-path`,className:x(`flex-1 border rounded-none-none py-2 px-3 text-sm font-mono transition-all outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black`,`bg-z-input border-z-border text-z-primary focus:border-z-active-border`)}),(0,w.jsx)(`button`,{onClick:()=>fe(n),className:`p-2 text-z-secondary hover:text-red-400 transition-colors`,children:(0,w.jsx)(t,{size:14})})]}),(0,w.jsx)(`input`,{type:`text`,value:e.description,onChange:e=>Q(n,`description`,e.target.value),placeholder:`Brief description of this endpoint...`,className:x(`w-full border rounded-none-none py-2 px-3 text-sm transition-all outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black`,`bg-z-input border-z-border text-z-primary focus:border-z-active-border`)})]},n))})]}),(0,w.jsxs)(`div`,{className:x(`p-6 border rounded-none-none space-y-4`,v===`dark`?`bg-z-hover border-z-border/10`:`bg-[var(--z-bg-input)] border-z-border`),children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,w.jsx)(r,{size:14,className:`text-z-secondary`}),(0,w.jsx)(`span`,{className:`text-sm font-semibold text-z-secondary`,children:`Developer Notes`})]}),(0,w.jsxs)(`ul`,{className:`space-y-2 text-sm text-z-muted font-bold leading-relaxed`,children:[(0,w.jsx)(`li`,{children:`• Hooks are stored as JSON configuration and executed server-side`}),(0,w.jsxs)(`li`,{children:[`• `,(0,w.jsx)(`code`,{className:`text-z-secondary font-mono`,children:`before*`}),` hooks can modify data by returning the modified value`]}),(0,w.jsxs)(`li`,{children:[`• `,(0,w.jsx)(`code`,{className:`text-z-secondary font-mono`,children:`after*`}),` hooks are for side effects (fire-and-forget)`]}),(0,w.jsxs)(`li`,{children:[`• Custom endpoints are mounted at `,(0,w.jsxs)(`code`,{className:`text-z-secondary font-mono`,children:[`/api/v1/`,e,`/your-path`]})]}),(0,w.jsxs)(`li`,{children:[`• Access `,(0,w.jsx)(`code`,{className:`text-z-secondary font-mono`,children:`req.zenith.adapter`}),` for database operations`]})]})]})]})]})})})]})};export{k as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionHooksPage-Dn_ujtlp.js","names":[],"sources":["../../src/pages/CollectionHooksPage.tsx"],"sourcesContent":["import React, { useEffect, useState, useCallback } from 'react'\nimport { useParams, useNavigate, Link } from 'react-router-dom'\nimport {\n ArrowLeft,\n Save,\n Loader2,\n Code2,\n Plus,\n Trash2,\n Shield,\n Globe,\n Zap,\n ChevronDown,\n ChevronRight,\n FileCode,\n Terminal,\n ToggleLeft,\n ToggleRight,\n} from 'lucide-react'\nimport { motion, AnimatePresence } from 'framer-motion'\nimport { cn } from '../lib/utils'\nimport api from '../lib/api'\nimport toast from 'react-hot-toast'\nimport { useTheme } from '../context/ThemeContext'\nimport { useSystemMetadata } from '../hooks/useQueries'\nimport { PageHeader } from '../components/ui/PageHeader'\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\ninterface HookEntry {\n name: string\n label: string\n description: string\n event: string\n hasReturn: boolean\n}\n\ninterface EndpointEntry {\n path: string\n method: 'get' | 'post' | 'put' | 'patch' | 'delete'\n description: string\n}\n\ninterface CollectionConfig {\n slug: string\n name: string\n hooks?: Record<string, string>\n endpoints?: EndpointEntry[]\n access?: Record<string, string>\n publicRead?: boolean\n}\n\n// ── Available hooks ───────────────────────────────────────────────────────────\n\nconst COLLECTION_HOOKS: HookEntry[] = [\n { name: 'beforeValidate', label: 'Before Validate', description: 'Runs before document validation. Use to sanitize or enrich input data.', event: 'beforeValidate', hasReturn: true },\n { name: 'beforeCreate', label: 'Before Create', description: 'Runs after validation, before document is saved. Use to set computed fields.', event: 'beforeCreate', hasReturn: true },\n { name: 'afterCreate', label: 'After Create', description: 'Runs after document is created. Use for side effects like notifications.', event: 'afterCreate', hasReturn: false },\n { name: 'beforeUpdate', label: 'Before Update', description: 'Runs after validation, before document is updated.', event: 'beforeUpdate', hasReturn: true },\n { name: 'afterUpdate', label: 'After Update', description: 'Runs after document is updated. Use for cache invalidation, sync.', event: 'afterUpdate', hasReturn: false },\n { name: 'beforeDelete', label: 'Before Delete', description: 'Runs before document deletion. Use to prevent deletion or cascade.', event: 'beforeDelete', hasReturn: false },\n { name: 'afterDelete', label: 'After Delete', description: 'Runs after document is deleted. Use for cleanup.', event: 'afterDelete', hasReturn: false },\n { name: 'afterRead', label: 'After Read', description: 'Runs after document is read. Use to transform output data.', event: 'afterRead', hasReturn: true },\n { name: 'afterError', label: 'After Error', description: 'Runs when an error occurs during any lifecycle event.', event: 'afterError', hasReturn: false },\n]\n\nconst HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete'] as const\n\nconst HOOK_TEMPLATE = `(data, user, context) => {\n // Your hook logic here\n // data: the document data being processed\n // user: the authenticated user performing the action\n // context: { hookType: string /* additional context */ }\n return data;\n}`\n\n// const ENDPOINT_TEMPLATE = `(req, res) => {\n// // Custom endpoint logic\n// // req: Express request object (includes zenith adapter via req.zenith.adapter)\n// // res: Express response object\n// res.json({ message: 'Hello from custom endpoint' });\n// }`\n\n// ── Code Editor Component ─────────────────────────────────────────────────────\n\ninterface CodeEditorProps {\n value: string\n onChange: (value: string) => void\n theme: 'light' | 'dark'\n height?: string\n}\n\nconst CodeEditor: React.FC<CodeEditorProps> = ({ value, onChange, theme, height = '160px' }) => {\n return (\n <textarea\n value={value}\n onChange={(e) => onChange(e.target.value)}\n spellCheck={false}\n className={cn(\n 'w-full border rounded-none-none px-4 py-3 font-mono text-sm leading-relaxed resize-y outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all',\n theme === 'dark'\n ? 'bg-app border-z-border text-z-secondary focus:border-z-border/50'\n : 'bg-z-accent border-z-border text-z-secondary focus:border-z-border'\n )}\n style={{ minHeight: height, fontFamily: 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace' }}\n />\n )\n}\n\n// ── Main Component ────────────────────────────────────────────────────────────\n\nconst CollectionHooksPage: React.FC = () => {\n const { slug } = useParams<{ slug: string }>()\n const navigate = useNavigate()\n const { theme } = useTheme()\n\n const [collection, setCollection] = useState<CollectionConfig | null>(null)\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [expandedHook, setExpandedHook] = useState<string | null>(null)\n\n // Local state for hooks and endpoints\n const [hooks, setHooks] = useState<Record<string, string>>({})\n const [endpoints, setEndpoints] = useState<EndpointEntry[]>([])\n const [publicRead, setPublicRead] = useState(false)\n\n // Dirty tracking\n const [originalHooks, setOriginalHooks] = useState<Record<string, string>>({})\n const [originalEndpoints, setOriginalEndpoints] = useState<EndpointEntry[]>([])\n const [originalPublicRead, setOriginalPublicRead] = useState(false)\n\n const isDirty = () => {\n return JSON.stringify(hooks) !== JSON.stringify(originalHooks) ||\n JSON.stringify(endpoints) !== JSON.stringify(originalEndpoints) ||\n publicRead !== originalPublicRead\n }\n\n // Field-level hooks state (unused, commented out to fix TS6133)\n // const [fieldHooks, setFieldHooks] = useState<Record<string, { beforeChange: string; afterRead: string; validate: string }>>({})\n // const [originalFieldHooks, setOriginalFieldHooks] = useState<Record<string, { beforeChange: string; afterRead: string; validate: string }>>({})\n\n const [fields, setFields] = useState<Array<{ name: string; type: string; label?: string }>>([])\n\n const { data: healthData, isLoading: healthLoading } = useSystemMetadata()\n\n const fetchCollectionConfig = useCallback(async () => {\n if (!healthData) return\n setLoading(true)\n try {\n // Use healthData which comes from the tenant-isolated useSystemMetadata hook\n const cols = healthData.collections || []\n const col = cols.find((c: any) => c.slug === slug)\n\n if (!col) {\n toast.error('Collection not found')\n navigate('/collections')\n return\n }\n\n const hooksConfig = col.hooks || {}\n const endpointsConfig = col.endpoints || []\n\n setCollection({ slug: col.slug, name: col.label || col.name || col.slug, hooks: hooksConfig, endpoints: endpointsConfig, access: col.access, publicRead: !!col.publicRead })\n setHooks(hooksConfig)\n setEndpoints(endpointsConfig)\n setPublicRead(!!col.publicRead)\n setOriginalHooks(hooksConfig)\n setOriginalEndpoints(endpointsConfig)\n setOriginalPublicRead(!!col.publicRead)\n\n // Extract fields and their hooks\n const colFields = (col.fields || []).filter((f: any) => !['row', 'tabs', 'ui', 'collapsible'].includes(f.type))\n setFields(colFields.map((f: any) => ({ name: f.name, type: f.type, label: f.label || f.name })))\n\n const fh: any = {}\n colFields.forEach((f: any) => {\n if (f.hooks) {\n fh[f.name] = {\n beforeChange: f.hooks.beforeChange || '',\n afterRead: f.hooks.afterRead || '',\n validate: f.hooks.validate || '',\n }\n }\n })\n // setFieldHooks(fh)\n // setOriginalFieldHooks(fh)\n } catch (err) {\n console.error('Failed to load collection config', err)\n toast.error('Failed to load collection configuration')\n } finally {\n setLoading(false)\n }\n }, [slug, navigate, healthData])\n\n useEffect(() => {\n if (!healthLoading) {\n fetchCollectionConfig()\n }\n }, [fetchCollectionConfig, healthData, healthLoading])\n\n const handleSave = async () => {\n if (!isDirty()) return\n setSaving(true)\n try {\n await api.patch(`/system/collections/${slug}`, {\n hooks,\n endpoints,\n publicRead,\n })\n setOriginalHooks(hooks)\n setOriginalEndpoints(endpoints)\n setOriginalPublicRead(publicRead)\n toast.success('Collection configuration saved')\n } catch (err: any) {\n toast.error(err?.response?.data?.error || 'Failed to save configuration')\n } finally {\n setSaving(false)\n }\n }\n\n const handleAddHook = (hookName: string) => {\n if (hooks[hookName]) return\n setHooks(prev => ({\n ...prev,\n [hookName]: HOOK_TEMPLATE,\n }))\n setExpandedHook(hookName)\n }\n\n const handleUpdateHook = (hookName: string, code: string) => {\n setHooks(prev => ({ ...prev, [hookName]: code }))\n }\n\n const handleRemoveHook = (hookName: string) => {\n setHooks(prev => {\n const next = { ...prev }\n delete next[hookName]\n return next\n })\n if (expandedHook === hookName) setExpandedHook(null)\n }\n\n const handleAddEndpoint = () => {\n setEndpoints(prev => [...prev, { path: '', method: 'get', description: '' }])\n }\n\n const handleUpdateEndpoint = (idx: number, key: keyof EndpointEntry, value: string) => {\n setEndpoints(prev => prev.map((e, i) => i === idx ? { ...e, [key]: value } : e))\n }\n\n const handleRemoveEndpoint = (idx: number) => {\n setEndpoints(prev => prev.filter((_, i) => i !== idx))\n }\n\n const activeHooks = COLLECTION_HOOKS.filter(h => hooks[h.name])\n\n if (loading) {\n return (\n <div className=\"min-h-[80vh] flex items-center justify-center\">\n <Loader2 size={32} className=\"text-z-secondary animate-spin\" />\n </div>\n )\n }\n\n return (\n <div className=\"flex flex-col h-[calc(100vh-64px)] overflow-hidden\">\n <PageHeader\n title={`${slug} hooks`}\n actions={\n <button\n onClick={handleSave}\n disabled={saving || !isDirty()}\n className=\"flex items-center justify-center gap-3 px-8 py-4 rounded-none-none text-sm font-semibold transition-all shadow-sm active:scale-95 disabled:opacity-50 bg-z-accent text-z-logo-text hover:bg-z-accent\"\n >\n {saving ? <Loader2 size={14} className=\"animate-spin\" /> : <Save size={14} />}\n Save Configuration\n </button>\n }\n />\n <div className={cn(\n 'flex-1 overflow-y-auto p-6 md:p-10 space-y-8 transition-colors duration-500',\n theme === 'dark' ? 'bg-app text-z-primary' : 'bg-[#fafafa] text-z-primary'\n )}>\n <div className=\"max-w-[1400px] mx-auto space-y-8\">\n <div className=\"grid grid-cols-1 xl:grid-cols-3 gap-8\">\n {/* Sidebar: Available hooks + Settings */}\n <div className=\"xl:col-span-1 space-y-6\">\n {/* Public Read Toggle */}\n <div className={cn(\n 'p-5 border rounded-none-none',\n theme === 'dark' ? 'bg-z-panel/5 border-z-border' : 'bg-z-panel border-z-border shadow-sm'\n )}>\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Globe size={14} className=\"text-z-secondary\" />\n <span className=\"text-sm font-semibold\">Public Read Access</span>\n </div>\n <button\n onClick={() => setPublicRead(!publicRead)}\n className=\"text-z-secondary hover:text-z-secondary transition-colors\"\n >\n {publicRead ? <ToggleRight size={28} /> : <ToggleLeft size={28} className=\"text-z-secondary\" />}\n </button>\n </div>\n <p className=\"text-sm text-z-secondary font-bold mt-2\">\n Allow unauthenticated access to read this collection\n </p>\n </div>\n\n {/* Available hooks to add */}\n <div className={cn(\n 'border rounded-none-none overflow-hidden',\n theme === 'dark' ? 'bg-z-panel/5 border-z-border' : 'bg-z-panel border-z-border shadow-sm'\n )}>\n <div className=\"px-5 py-3 border-b border-z-border\">\n <span className=\"text-sm font-semibold text-z-muted\">Available Lifecycle Hooks</span>\n </div>\n <div className=\"divide-y divide-z-border\">\n {COLLECTION_HOOKS.map(hook => {\n const isActive = !!hooks[hook.name]\n return (\n <div\n key={hook.name}\n className={cn(\n 'px-5 py-3 flex items-center justify-between transition-colors',\n isActive\n ? 'bg-z-hover'\n : theme === 'dark' ? 'hover:bg-z-panel' : 'hover:bg-[var(--z-bg-input)]'\n )}\n >\n <div className=\"flex items-center gap-2\">\n {isActive && <div className=\"w-1.5 h-1.5 rounded-none-none bg-z-border\" />}\n <span className={cn(\n 'text-sm font-semibold ',\n isActive ? 'text-z-secondary' : 'text-z-secondary'\n )}>\n {hook.label}\n </span>\n </div>\n {!isActive && (\n <button\n onClick={() => handleAddHook(hook.name)}\n className=\"text-z-secondary hover:text-z-secondary transition-colors\"\n title={`Add ${hook.label} hook`}\n >\n <Plus size={14} />\n </button>\n )}\n </div>\n )\n })}\n </div>\n </div>\n\n {/* Quick info */}\n <div className={cn(\n 'p-5 border rounded-none-none space-y-3',\n theme === 'dark' ? 'bg-z-panel/5 border-z-border' : 'bg-z-panel border-z-border shadow-sm'\n )}>\n <div className=\"flex items-center gap-2\">\n <Terminal size={12} className=\"text-z-secondary\" />\n <span className=\"text-sm font-semibold text-z-muted\">Runtime Info</span>\n </div>\n <div className=\"space-y-2\">\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-z-secondary font-bold\">Active Hooks</span>\n <span className=\"text-sm text-z-secondary font-semibold\">{activeHooks.length}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-z-secondary font-bold\">Custom Endpoints</span>\n <span className=\"text-sm text-z-secondary font-semibold\">{endpoints.length}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-sm text-z-secondary font-bold\">Fields</span>\n <span className=\"text-sm text-z-secondary font-semibold\">{fields.length}</span>\n </div>\n </div>\n </div>\n </div>\n\n {/* Main content: Active hooks + Endpoints */}\n <div className=\"xl:col-span-2 space-y-8\">\n {/* Collection Lifecycle Hooks */}\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-3 border-b border-z-border pb-4\">\n <Zap size={16} className=\"text-z-secondary\" />\n <h2 className=\"text-sm font-semibold\">Collection Lifecycle Hooks</h2>\n <span className=\"text-sm text-z-secondary font-bold ml-auto\">\n {activeHooks.length} active\n </span>\n </div>\n\n {activeHooks.length === 0 ? (\n <div className={cn(\n 'p-8 border border-dashed rounded-none-none text-center space-y-3',\n 'border-z-border'\n )}>\n <Code2 size={32} className=\"mx-auto text-z-secondary\" />\n <p className=\"text-sm font-semibold text-z-secondary\">\n No hooks configured\n </p>\n <p className=\"text-sm text-z-secondary\">\n Click + in the sidebar to add lifecycle hooks\n </p>\n </div>\n ) : (\n <AnimatePresence>\n {activeHooks.map(hook => {\n const isOpen = expandedHook === hook.name\n return (\n <motion.div\n key={hook.name}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n className={cn(\n 'border rounded-none-none overflow-hidden',\n theme === 'dark' ? 'bg-z-panel/5 border-z-border' : 'bg-z-panel border-z-border shadow-sm'\n )}\n >\n <button\n onClick={() => setExpandedHook(isOpen ? null : hook.name)}\n className={cn(\n 'w-full px-5 py-4 flex items-center justify-between transition-colors',\n isOpen\n ? theme === 'dark' ? 'bg-z-hover' : 'bg-[var(--z-bg-input)]'\n : theme === 'dark' ? 'hover:bg-z-panel' : 'hover:bg-[var(--z-bg-input)]'\n )}\n >\n <div className=\"flex items-center gap-3\">\n {isOpen ? <ChevronDown size={14} className=\"text-z-secondary\" /> : <ChevronRight size={14} className=\"text-z-secondary\" />}\n <FileCode size={14} className=\"text-z-secondary\" />\n <div className=\"flex flex-col items-start\">\n <span className=\"text-sm font-semibold text-z-primary\">{hook.label}</span>\n <span className=\"text-sm text-z-secondary font-bold\">{hook.event}</span>\n </div>\n </div>\n <button\n onClick={(e) => { e.stopPropagation(); handleRemoveHook(hook.name) }}\n className=\"p-2 text-z-secondary hover:text-red-400 transition-colors\"\n title=\"Remove hook\"\n >\n <Trash2 size={14} />\n </button>\n </button>\n {isOpen && (\n <div className=\"px-5 pb-5 space-y-3\">\n <p className=\"text-sm text-z-muted font-bold\">\n {hook.description}\n </p>\n <CodeEditor\n value={hooks[hook.name]}\n onChange={(code) => handleUpdateHook(hook.name, code)}\n theme={theme}\n height=\"200px\"\n />\n </div>\n )}\n </motion.div>\n )\n })}\n </AnimatePresence>\n )}\n </div>\n\n {/* Custom Endpoints */}\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between border-b border-z-border pb-4\">\n <div className=\"flex items-center gap-3\">\n <Globe size={16} className=\"text-z-secondary\" />\n <h2 className=\"text-sm font-semibold\">Custom Endpoints</h2>\n <span className=\"text-sm text-z-secondary font-bold\">\n {endpoints.length} defined\n </span>\n </div>\n <button\n onClick={handleAddEndpoint}\n className=\"flex items-center gap-2 px-3 py-1.5 border border-z-border hover:border-z-active-border hover:bg-z-hover text-sm font-semibold transition-all text-z-secondary hover:text-z-primary\"\n >\n <Plus size={10} />\n Add Endpoint\n </button>\n </div>\n\n {endpoints.length === 0 ? (\n <div className={cn(\n 'p-8 border border-dashed rounded-none-none text-center space-y-3',\n 'border-z-border'\n )}>\n <Globe size={32} className=\"mx-auto text-z-secondary\" />\n <p className=\"text-sm font-semibold text-z-secondary\">\n No custom endpoints\n </p>\n <p className=\"text-sm text-z-secondary\">\n Add custom API endpoints for this collection\n </p>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {endpoints.map((ep, idx) => (\n <div\n key={idx}\n className={cn(\n 'p-5 border rounded-none-none space-y-4',\n theme === 'dark' ? 'bg-z-panel/5 border-z-border' : 'bg-z-panel border-z-border shadow-sm'\n )}\n >\n <div className=\"flex items-center gap-3\">\n <select\n value={ep.method}\n onChange={(e) => handleUpdateEndpoint(idx, 'method', e.target.value)}\n className={cn(\n 'bg-z-input border-z-border text-z-primary text-sm font-semibold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black py-1.5 px-3 rounded-none-none focus:border-z-active-border',\n theme === 'dark' ? 'border-z-border text-z-secondary' : 'border-z-border text-z-secondary'\n )}\n >\n {HTTP_METHODS.map(m => (\n <option key={m} value={m}>{m}</option>\n ))}\n </select>\n <input\n type=\"text\"\n value={ep.path}\n onChange={(e) => handleUpdateEndpoint(idx, 'path', e.target.value)}\n placeholder=\"/custom-path\"\n className={cn(\n 'flex-1 border rounded-none-none py-2 px-3 text-sm font-mono transition-all outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black',\n 'bg-z-input border-z-border text-z-primary focus:border-z-active-border'\n )}\n />\n <button\n onClick={() => handleRemoveEndpoint(idx)}\n className=\"p-2 text-z-secondary hover:text-red-400 transition-colors\"\n >\n <Trash2 size={14} />\n </button>\n </div>\n <input\n type=\"text\"\n value={ep.description}\n onChange={(e) => handleUpdateEndpoint(idx, 'description', e.target.value)}\n placeholder=\"Brief description of this endpoint...\"\n className={cn(\n 'w-full border rounded-none-none py-2 px-3 text-sm transition-all outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black',\n 'bg-z-input border-z-border text-z-primary focus:border-z-active-border'\n )}\n />\n </div>\n ))}\n </div>\n )}\n </div>\n\n {/* Info card */}\n <div className={cn(\n 'p-6 border rounded-none-none space-y-4',\n theme === 'dark' ? 'bg-z-hover border-z-border/10' : 'bg-[var(--z-bg-input)] border-z-border'\n )}>\n <div className=\"flex items-center gap-3\">\n <Shield size={14} className=\"text-z-secondary\" />\n <span className=\"text-sm font-semibold text-z-secondary\">Developer Notes</span>\n </div>\n <ul className=\"space-y-2 text-sm text-z-muted font-bold leading-relaxed\">\n <li>• Hooks are stored as JSON configuration and executed server-side</li>\n <li>• <code className=\"text-z-secondary font-mono\">before*</code> hooks can modify data by returning the modified value</li>\n <li>• <code className=\"text-z-secondary font-mono\">after*</code> hooks are for side effects (fire-and-forget)</li>\n <li>• Custom endpoints are mounted at <code className=\"text-z-secondary font-mono\">/api/v1/{slug}/your-path</code></li>\n <li>• Access <code className=\"text-z-secondary font-mono\">req.zenith.adapter</code> for database operations</li>\n </ul>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default CollectionHooksPage\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{C as t,F as n,H as r,Hn as i,Ln as a,Q as o,Rn as s,Wt as c,cn as l,cr as ee,l as u,mr as d,rr as f,u as p,vr as m,wn as h,xr as g}from"./vendor-react-DQVTOTFO.js";import{a as _,o as v,t as y}from"./utils-fgvbH6CB.js";import{_ as te,p as ne}from"./index-ChcKY5Xe.js";var b=e(g(),1),x=m(),S=()=>{let{theme:e}=_(),m=d(),[g,S]=(0,b.useState)([]),[C,w]=(0,b.useState)(!0),[T,E]=(0,b.useState)(``),[D,O]=(0,b.useState)({}),{data:k,isLoading:A}=te();(0,b.useEffect)(()=>{A||(async()=>{if(k)try{let e=await v.get(`/system/counts`).catch(()=>null);S((k.collections||[]).map(e=>({...e,label:e.label||e.name||e.slug||`Unnamed Collection`}))),O(e?.data?.data||{})}catch(e){console.error(`Critical Registry Synchronization Failure`,e),u.error(`Failed to load collections`)}finally{w(!1)}})()},[k,A]);let j=g.filter(e=>{let t=(e.label||``).toLowerCase(),n=(e.slug||``).toLowerCase(),r=T.toLowerCase();return t.includes(r)||n.includes(r)}),[M,N]=(0,b.useState)(!1),[P,F]=(0,b.useState)(``),[I,L]=(0,b.useState)(!1),[R,z]=(0,b.useState)(null),B=async()=>{if(P){L(!0),z(null);try{z((await v.post(`/system/ai-architect`,{prompt:P})).data?.data?.schema||{error:`Failed to parse schema.`})}catch{z({error:`Failed to connect to AI Architect.`})}finally{L(!1)}}},[V,H]=(0,b.useState)(!1),[U,W]=(0,b.useState)(!1),[G,K]=(0,b.useState)(``),[q,J]=(0,b.useState)(``),[Y,X]=(0,b.useState)(!0),[Z,Q]=(0,b.useState)([{name:`title`,type:`text`,required:!0,options:``,relationTo:``}]),re=e=>{K(e),J(e.toLowerCase().trim().replace(/\s+/g,`-`).replace(/[^a-z0-9-]/g,``))},ie=()=>{Q([...Z,{name:``,type:`text`,required:!1,options:``,relationTo:``}])},ae=e=>{Q(Z.filter((t,n)=>n!==e))},$=(e,t,n)=>{Q(Z.map((r,i)=>i===e?{...r,[t]:n}:r))};return C?(0,x.jsx)(`div`,{className:`flex items-center justify-center min-h-screen`,children:(0,x.jsx)(a,{className:`animate-spin text-z-secondary `,size:32})}):(0,x.jsxs)(`div`,{className:`flex flex-col h-[calc(100vh-64px)] overflow-hidden`,children:[(0,x.jsx)(ne,{title:`Content Assets`,actions:(0,x.jsxs)(`div`,{className:`flex items-center gap-4 w-full md:w-auto flex-wrap`,children:[(0,x.jsxs)(`button`,{onClick:()=>H(!0),className:`flex items-center gap-2 px-6 py-4 bg-z-accent text-z-logo-text text-sm font-semibold hover:bg-z-accent transition-colors shadow-lg shadow-sm`,children:[(0,x.jsx)(o,{size:14}),`Create Collection`]}),(0,x.jsxs)(`button`,{onClick:()=>N(!0),className:y(`flex items-center gap-2 px-6 py-4 text-sm font-semibold transition-colors`,`bg-z-panel hover:bg-z-hover text-z-primary border-z-border`),children:[(0,x.jsx)(p,{size:14,className:`text-z-active-text`}),`AI Architect`]}),(0,x.jsxs)(`div`,{className:`relative w-full md:w-80`,children:[(0,x.jsx)(r,{className:`absolute left-4 top-1/2 -translate-y-1/2 text-z-secondary`,size:14}),(0,x.jsx)(`input`,{type:`text`,placeholder:`FILTER_COLLECTIONS...`,value:T,onChange:e=>E(e.target.value),className:y(`w-full border rounded-none-none py-4 pl-12 pr-4 text-sm font-semibold transition-all outline-none `,e===`dark`?`bg-z-hover border-z-border text-z-primary focus:border-z-accent/50 focus:bg-z-hover`:`bg-z-panel border-z-border focus:border-z-accent/50`)})]})]})}),(0,x.jsxs)(`div`,{className:y(`flex-1 overflow-y-auto p-6 md:p-10 space-y-10 transition-colors duration-500`,e===`dark`?`bg-app text-z-primary`:`bg-[#fafafa] text-z-primary`),children:[(0,x.jsx)(`div`,{className:`grid grid-cols-1 md:grid-cols-3 gap-6`,children:[{label:`Total Records`,value:String(Object.values(D).reduce((e,t)=>e+t,0)),icon:h,sub:`Global Synchronization`},{label:`Schema Health`,value:`100%`,icon:n,sub:`Optimal Performance`},{label:`Latency`,value:`14ms`,icon:p,sub:`Neural Processing`}].map((t,n)=>(0,x.jsxs)(`div`,{className:y(`p-8 border rounded-none-none flex flex-col gap-4 transition-all relative overflow-hidden group`,e===`dark`?`bg-z-panel border-z-border`:`bg-z-panel border-z-border shadow-sm shadow-sm`),children:[(0,x.jsx)(`div`,{className:`absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity`,children:(0,x.jsx)(t.icon,{size:80})}),(0,x.jsx)(`span`,{className:`text-sm font-semibold text-z-secondary`,children:t.label}),(0,x.jsxs)(`div`,{className:`flex items-baseline gap-3`,children:[(0,x.jsx)(`span`,{className:`text-4xl font-semibold`,children:t.value}),(0,x.jsx)(`span`,{className:`text-sm font-bold text-z-secondary `,children:t.sub})]})]},n))}),(0,x.jsx)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6`,children:j.map((e,t)=>(0,x.jsx)(f.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:t*.05},children:(0,x.jsxs)(`div`,{onClick:()=>m(`/collections/${e.slug}`),className:y(`group p-8 border flex flex-col items-center text-center gap-5 transition-all duration-500 relative overflow-hidden cursor-pointer`,`bg-z-panel backdrop-blur-xl border-z-border shadow-sm hover:scale-[1.02] hover:border-z-active-border hover:shadow-premium`),children:[(0,x.jsx)(`div`,{className:`absolute inset-0 bg-gradient-to-br from-z-accent/0 to-z-accent/0 group-hover:from-z-accent/5 group-hover:to-transparent transition-all duration-500`}),(0,x.jsx)(`div`,{className:y(`w-14 h-14 rounded-full flex items-center justify-center transition-all duration-500 relative z-10`,`bg-z-hover text-z-muted group-hover:bg-z-active-bg group-hover:text-z-active-text`),children:(0,x.jsx)(s,{size:24,strokeWidth:1.5})}),(0,x.jsxs)(`div`,{className:`relative z-10 flex flex-col items-center w-full`,children:[(0,x.jsx)(`h3`,{className:`text-xl font-black tracking-tight leading-none mb-3 group-hover:text-z-active-text transition-colors duration-500`,children:e.label.replace(/-/g,` `)}),(0,x.jsx)(`div`,{className:`flex items-center justify-center mb-4`,children:(0,x.jsxs)(`span`,{className:`px-2.5 py-1 rounded-full text-[9px] font-black uppercase tracking-widest bg-z-hover text-z-primary`,children:[D[e.slug]||0,` Entries`]})}),(0,x.jsxs)(`p`,{className:`text-[11px] font-medium text-z-secondary leading-relaxed max-w-[90%]`,children:[`Manage and organize your `,e.label.toLowerCase(),` documents.`]})]}),(0,x.jsx)(`div`,{className:`w-full flex items-center justify-center pt-5 mt-auto border-t border-z-border/50 relative z-10`,children:(0,x.jsxs)(ee,{to:`/collections/${e.slug}/hooks`,onClick:e=>e.stopPropagation(),className:`flex items-center gap-1.5 text-[10px] font-black uppercase tracking-widest text-z-secondary hover:text-z-active-text transition-colors duration-300`,children:[(0,x.jsx)(i,{size:12}),`Manage Hooks`]})})]})},e.slug))}),M&&(0,x.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-[var(--z-bg-modal)] backdrop-blur-sm p-4`,children:(0,x.jsxs)(`div`,{className:y(`w-full max-w-3xl p-8 border shadow-2xl relative`,`bg-z-panel border-z-border`),children:[(0,x.jsx)(`button`,{onClick:()=>N(!1),className:`absolute top-4 right-4 text-z-secondary hover:text-z-primary`}),(0,x.jsxs)(`h2`,{className:`text-2xl font-semibold mb-4 flex items-center gap-2`,children:[(0,x.jsx)(p,{className:`text-z-secondary `}),` AI Schema Architect`]}),(0,x.jsx)(`p`,{className:`text-sm font-bold text-z-secondary mb-6`,children:`Describe the collection you want to create and let AI build the schema configuration.`}),(0,x.jsx)(`textarea`,{value:P,onChange:e=>F(e.target.value),placeholder:`e.g., I need a blog post collection with title, content, cover image, seo metadata, and a category dropdown...`,className:y(`w-full h-32 p-4 mb-4 font-mono text-sm border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black focus:ring-2 focus:ring-z-active-border resize-none`,e===`dark`?`bg-app border-z-border`:`bg-z-input border-z-border`)}),(0,x.jsxs)(`button`,{onClick:B,disabled:I,className:`w-full py-4 bg-z-accent hover:bg-z-base text-z-primary font-semibold flex items-center justify-center gap-2`,children:[I?(0,x.jsx)(a,{className:`animate-spin`,size:16}):(0,x.jsx)(c,{size:16}),I?`Synthesizing Architecture...`:`Generate Schema`]}),R&&(0,x.jsxs)(`div`,{className:`mt-6 border-t border-z-border pt-6`,children:[(0,x.jsx)(`p`,{className:`text-sm font-bold text-z-muted mb-2`,children:`Generated Schema Configuration (Copy to cms.config.ts)`}),(0,x.jsxs)(`div`,{className:`relative`,children:[(0,x.jsx)(`pre`,{className:`p-4 bg-[var(--z-bg-code)] text-z-muted text-xs font-mono overflow-auto max-h-64 border border-z-border`,children:JSON.stringify(R,null,2)}),(0,x.jsx)(`button`,{onClick:()=>navigator.clipboard.writeText(JSON.stringify(R,null,2)),className:`absolute top-2 right-2 px-3 py-1 bg-z-hover hover:bg-z-panel border border-z-border text-sm font-semibold text-z-primary`,children:`Copy`})]})]})]})}),V&&(0,x.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-[var(--z-bg-modal)] backdrop-blur-md p-4 overflow-y-auto`,children:(0,x.jsxs)(`div`,{className:y(`w-full max-w-4xl p-10 border shadow-2xl relative my-8`,`bg-z-panel border-z-border text-z-primary`),children:[(0,x.jsx)(`button`,{onClick:()=>H(!1),className:`absolute top-6 right-6 w-8 h-8 flex items-center justify-center bg-z-hover hover:bg-z-panel rounded-none-none border border-z-border transition-colors text-z-muted hover:text-z-primary`}),(0,x.jsxs)(`h2`,{className:`text-3xl font-semibold mb-4 flex items-center gap-3`,children:[(0,x.jsx)(c,{className:`text-z-secondary animate-pulse`}),` Visual Schema Builder`]}),(0,x.jsx)(`p`,{className:`text-sm font-semibold text-z-secondary mb-8 border-b border-z-border pb-4`,children:`Define collection specifications, fields, types, and constraints visually without writing code.`}),(0,x.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-6 mb-8`,children:[(0,x.jsxs)(`div`,{className:`space-y-2`,children:[(0,x.jsx)(`label`,{className:`text-sm font-semibold text-z-secondary block`,children:`Collection Name`}),(0,x.jsx)(`input`,{type:`text`,name:`name`,value:G,onChange:e=>re(e.target.value),placeholder:`e.g. Review`,className:y(`w-full px-4 py-3 text-sm font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all `,`bg-z-input border-z-border text-z-primary`)})]}),(0,x.jsxs)(`div`,{className:`space-y-2`,children:[(0,x.jsx)(`label`,{className:`text-sm font-semibold text-z-secondary block`,children:`Slug`}),(0,x.jsx)(`input`,{type:`text`,name:`slug`,value:q,onChange:e=>J(e.target.value),placeholder:`e.g. reviews`,className:y(`w-full px-4 py-3 text-sm font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all lowercase `,e===`dark`?`bg-app border-z-border text-z-muted`:`bg-z-input border-z-border text-z-secondary`)})]})]}),(0,x.jsxs)(`div`,{className:`flex items-center gap-3 mb-8 px-2`,children:[(0,x.jsx)(`input`,{type:`checkbox`,id:`enable-drafts-checkbox`,checked:Y,onChange:e=>X(e.target.checked),className:`w-4 h-4 text-z-secondary focus:ring-z-active-border border-z-border-strong rounded-none-none bg-app`}),(0,x.jsx)(`label`,{htmlFor:`enable-drafts-checkbox`,className:`text-sm font-semibold text-z-muted cursor-pointer select-none`,children:`Enable Draft/Publish Workflow`})]}),(0,x.jsxs)(`div`,{className:`space-y-6`,children:[(0,x.jsxs)(`div`,{className:`flex items-center justify-between border-b border-z-border pb-3`,children:[(0,x.jsx)(`h3`,{className:`text-xs font-semibold text-z-muted`,children:`Field Definitions`}),(0,x.jsxs)(`button`,{onClick:ie,className:`px-4 py-2 border border-dashed border-z-border/30 text-z-secondary hover:bg-z-hover text-sm font-semibold transition-all flex items-center gap-2`,children:[(0,x.jsx)(o,{size:12}),` Add Field`]})]}),(0,x.jsx)(`div`,{className:`space-y-4 max-h-[30vh] overflow-y-auto pr-2 custom-scrollbar`,children:Z.map((n,r)=>(0,x.jsxs)(`div`,{className:y(`p-5 border rounded-none-none grid grid-cols-1 md:grid-cols-4 gap-4 items-center relative group/field`,e===`dark`?`bg-app border-z-border`:`bg-z-input border-z-border shadow-sm`),children:[(0,x.jsxs)(`div`,{className:`space-y-2`,children:[(0,x.jsx)(`label`,{className:`text-sm font-semibold text-z-secondary block`,children:`Field Name`}),(0,x.jsx)(`input`,{type:`text`,name:`field-name-${r}`,value:n.name,onChange:e=>$(r,`name`,e.target.value),placeholder:`e.g. rating`,className:y(`w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all lowercase font-mono`,e===`dark`?`bg-app border-z-border text-z-primary`:`bg-z-panel border-z-border`)})]}),(0,x.jsxs)(`div`,{className:`space-y-2`,children:[(0,x.jsx)(`label`,{className:`text-sm font-semibold text-z-secondary block`,children:`Type`}),(0,x.jsxs)(`select`,{value:n.type,onChange:e=>$(r,`type`,e.target.value),className:y(`w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all`,e===`dark`?`bg-app border-z-border text-z-primary`:`bg-z-panel border-z-border`),children:[(0,x.jsx)(`option`,{value:`text`,children:`Text`}),(0,x.jsx)(`option`,{value:`number`,children:`Number`}),(0,x.jsx)(`option`,{value:`richtext`,children:`Rich Text`}),(0,x.jsx)(`option`,{value:`media`,children:`Media`}),(0,x.jsx)(`option`,{value:`checkbox`,children:`Boolean`}),(0,x.jsx)(`option`,{value:`select`,children:`Dropdown Select`}),(0,x.jsx)(`option`,{value:`relationship`,children:`Relationship`})]})]}),n.type===`select`?(0,x.jsxs)(`div`,{className:`space-y-2`,children:[(0,x.jsx)(`label`,{className:`text-sm font-semibold text-z-secondary block`,children:`Options (Comma separated)`}),(0,x.jsx)(`input`,{type:`text`,value:n.options||``,onChange:e=>$(r,`options`,e.target.value),placeholder:`e.g. red, blue, green`,className:y(`w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all`,e===`dark`?`bg-app border-z-border text-z-primary`:`bg-z-panel border-z-border`)})]}):n.type===`relationship`?(0,x.jsxs)(`div`,{className:`space-y-2`,children:[(0,x.jsx)(`label`,{className:`text-sm font-semibold text-z-secondary block`,children:`Relate To Collection`}),(0,x.jsxs)(`select`,{value:n.relationTo||``,onChange:e=>$(r,`relationTo`,e.target.value),className:y(`w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all`,e===`dark`?`bg-app border-z-border text-z-primary`:`bg-z-panel border-z-border`),children:[(0,x.jsx)(`option`,{value:``,children:`Select Target...`}),(0,x.jsx)(`option`,{value:`users`,children:`Users`}),g.map(e=>(0,x.jsx)(`option`,{value:e.slug,children:e.label},e.slug))]})]}):(0,x.jsxs)(`div`,{className:`flex items-center gap-3 pt-6`,children:[(0,x.jsx)(`input`,{type:`checkbox`,id:`required-checkbox-${r}`,checked:!!n.required,onChange:e=>$(r,`required`,e.target.checked),className:`w-3.5 h-3.5 text-z-secondary focus:ring-z-active-border border-z-border-strong rounded-none-none bg-app`}),(0,x.jsx)(`label`,{htmlFor:`required-checkbox-${r}`,className:`text-sm font-semibold text-z-muted cursor-pointer select-none`,children:`Required Field`})]}),(0,x.jsx)(`div`,{className:`flex justify-end pt-5 md:pt-0`,children:(0,x.jsx)(`button`,{onClick:()=>ae(r),disabled:Z.length===1,className:`p-2 border border-transparent hover:border-red-500/30 hover:bg-red-500/5 text-z-secondary hover:text-red-500 transition-colors disabled:opacity-20`,children:(0,x.jsx)(t,{size:14})})})]},r))})]}),(0,x.jsxs)(`div`,{className:`mt-10 pt-8 border-t border-z-border flex justify-end gap-4`,children:[(0,x.jsx)(`button`,{onClick:()=>H(!1),className:y(`px-6 py-3 font-semibold text-sm transition-all leading-none border`,e===`dark`?`bg-z-hover border-z-border text-z-muted hover:text-z-primary`:`bg-z-panel border-z-border text-z-muted hover:text-z-primary`),children:`Cancel`}),(0,x.jsxs)(`button`,{onClick:async()=>{if(!G||!q||Z.length===0){u.error(`Please enter a collection name and add at least one field.`);return}if(Z.some(e=>!e.name)){u.error(`All fields must have a name.`);return}W(!0);try{await v.post(`/system/collections`,{name:G,slug:q,drafts:Y,fields:Z.map(e=>({name:e.name.toLowerCase().trim().replace(/\s+/g,`_`).replace(/[^a-z0-9_]/g,``),type:e.type,required:!!e.required,...e.type===`select`&&e.options&&{options:e.options.split(`,`).map(e=>({label:e.trim(),value:e.trim()})).filter(e=>e.value)},...e.type===`relationship`&&e.relationTo&&{relationTo:e.relationTo}}))}),u.success(`Collection created successfully! Reloading...`),H(!1),setTimeout(()=>{window.location.reload()},1500)}catch(e){u.error(e.response?.data?.message||`Failed to create collection.`)}finally{W(!1)}},disabled:U,className:`px-8 py-3 bg-z-accent hover:bg-z-base text-z-primary rounded-none-none text-sm font-semibold shadow-xl shadow-[var(--z-border)] transition-all flex items-center gap-2 leading-none`,children:[U?(0,x.jsx)(a,{size:12,className:`animate-spin`}):(0,x.jsx)(l,{size:12}),`Create Content Type`]})]})]})})]})]})};export{S as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionsPage-BSPHf7H2.js","names":[],"sources":["../../src/pages/CollectionsPage.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react'\nimport {\n Database,\n Layers,\n ArrowRight,\n Search,\n Activity,\n Shield,\n Zap,\n Loader2,\n Plus,\n Trash2,\n Check,\n Code2,\n} from 'lucide-react'\nimport { Link, useNavigate } from 'react-router-dom'\nimport { motion } from 'framer-motion'\nimport { cn } from '../lib/utils'\nimport api from '../lib/api'\nimport toast from 'react-hot-toast'\nimport { useTheme } from '../context/ThemeContext'\nimport { useSystemMetadata } from '../hooks/useQueries'\nimport { PageHeader } from '../components/ui/PageHeader'\n\nconst CollectionsPage: React.FC = () => {\n const { theme } = useTheme()\n const navigate = useNavigate()\n // --- REGISTRY STATE: CONTENT INFRASTRUCTURE ---\n const [collections, setCollections] = useState<any[]>([])\n const [loading, setLoading] = useState(true)\n const [searchQuery, setSearchQuery] = useState('')\n const [stats, setStats] = useState<any>({})\n\n /**\n * REGISTRY HARVEST: SYNCHRONIZE CONTENT NODES\n * Orchestrates parallel retrieval of system health (for schema/labels)\n * and record counts for each collection node.\n */\n const { data: healthData, isLoading: healthLoading } = useSystemMetadata()\n\n useEffect(() => {\n const fetchCounts = async () => {\n if (!healthData) return\n try {\n const countsRes = await api.get('/system/counts').catch(() => null)\n \n const rawCollections = healthData.collections || []\n\n const processedCollections = rawCollections.map((c: any) => ({\n ...c,\n label: c.label || c.name || c.slug || 'Unnamed Collection',\n }))\n\n setCollections(processedCollections)\n setStats(countsRes?.data?.data || {})\n } catch (error) {\n console.error('Critical Registry Synchronization Failure', error)\n toast.error('Failed to load collections')\n } finally {\n setLoading(false)\n }\n }\n\n if (!healthLoading) {\n fetchCounts()\n }\n }, [healthData, healthLoading])\n\n /**\n * SEARCH & FILTER LOGIC: CLIENT-SIDE MATRIX REDUCTION\n */\n const filteredCollections = collections.filter((col) => {\n const label = (col.label || '').toLowerCase()\n const slug = (col.slug || '').toLowerCase()\n const query = searchQuery.toLowerCase()\n return label.includes(query) || slug.includes(query)\n })\n\n const [isAIModalOpen, setIsAIModalOpen] = useState(false)\n const [aiPrompt, setAiPrompt] = useState('')\n const [aiLoading, setAiLoading] = useState(false)\n const [aiResult, setAiResult] = useState<any>(null)\n\n const handleAIGenerate = async () => {\n if (!aiPrompt) return\n setAiLoading(true)\n setAiResult(null)\n try {\n const res = await api.post('/system/ai-architect', { prompt: aiPrompt })\n setAiResult(res.data?.data?.schema || { error: 'Failed to parse schema.' })\n } catch (e) {\n setAiResult({ error: 'Failed to connect to AI Architect.' })\n } finally {\n setAiLoading(false)\n }\n }\n\n // --- VISUAL CONTENT-TYPE BUILDER STATE ---\n const [isVisualModalOpen, setIsVisualModalOpen] = useState(false)\n const [visualLoading, setVisualLoading] = useState(false)\n const [newColName, setNewColName] = useState('')\n const [newColSlug, setNewColSlug] = useState('')\n const [newColDrafts, setNewColDrafts] = useState(true)\n const [newColFields, setNewColFields] = useState<any[]>([\n { name: 'title', type: 'text', required: true, options: '', relationTo: '' },\n ])\n\n const handleNameChange = (name: string) => {\n setNewColName(name)\n setNewColSlug(\n name\n .toLowerCase()\n .trim()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-]/g, '')\n )\n }\n\n const handleAddField = () => {\n setNewColFields([\n ...newColFields,\n { name: '', type: 'text', required: false, options: '', relationTo: '' },\n ])\n }\n\n const handleRemoveField = (index: number) => {\n setNewColFields(newColFields.filter((_, idx) => idx !== index))\n }\n\n const handleFieldChange = (index: number, key: string, value: any) => {\n setNewColFields(\n newColFields.map((field, idx) => {\n if (idx === index) {\n return { ...field, [key]: value }\n }\n return field\n })\n )\n }\n\n const handleCreateCollection = async () => {\n if (!newColName || !newColSlug || newColFields.length === 0) {\n toast.error('Please enter a collection name and add at least one field.')\n return\n }\n if (newColFields.some((f) => !f.name)) {\n toast.error('All fields must have a name.')\n return\n }\n\n setVisualLoading(true)\n try {\n await api.post('/system/collections', {\n name: newColName,\n slug: newColSlug,\n drafts: newColDrafts,\n fields: newColFields.map((f) => ({\n name: f.name\n .toLowerCase()\n .trim()\n .replace(/\\s+/g, '_')\n .replace(/[^a-z0-9_]/g, ''),\n type: f.type,\n required: !!f.required,\n ...(f.type === 'select' &&\n f.options && {\n options: f.options\n .split(',')\n .map((o: string) => ({ label: o.trim(), value: o.trim() }))\n .filter((o: any) => o.value),\n }),\n ...(f.type === 'relationship' && f.relationTo && { relationTo: f.relationTo }),\n })),\n })\n toast.success('Collection created successfully! Reloading...')\n setIsVisualModalOpen(false)\n setTimeout(() => {\n window.location.reload()\n }, 1500)\n } catch (err: any) {\n toast.error(err.response?.data?.message || 'Failed to create collection.')\n } finally {\n setVisualLoading(false)\n }\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center min-h-screen\">\n <Loader2 className=\"animate-spin text-z-secondary \" size={32} />\n </div>\n )\n }\n\n return (\n <div className=\"flex flex-col h-[calc(100vh-64px)] overflow-hidden\">\n <PageHeader\n title=\"Content Assets\"\n actions={\n <div className=\"flex items-center gap-4 w-full md:w-auto flex-wrap\">\n <button\n onClick={() => setIsVisualModalOpen(true)}\n className=\"flex items-center gap-2 px-6 py-4 bg-z-accent text-z-logo-text text-sm font-semibold hover:bg-z-accent transition-colors shadow-lg shadow-sm\"\n >\n <Plus size={14} />\n Create Collection\n </button>\n\n <button\n onClick={() => setIsAIModalOpen(true)}\n className={cn(\n \"flex items-center gap-2 px-6 py-4 text-sm font-semibold transition-colors\",\n 'bg-z-panel hover:bg-z-hover text-z-primary border-z-border'\n )}\n >\n <Zap size={14} className=\"text-z-active-text\" />\n AI Architect\n </button>\n\n <div className=\"relative w-full md:w-80\">\n <Search className=\"absolute left-4 top-1/2 -translate-y-1/2 text-z-secondary\" size={14} />\n <input\n type=\"text\"\n placeholder=\"FILTER_COLLECTIONS...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className={cn(\n 'w-full border rounded-none-none py-4 pl-12 pr-4 text-sm font-semibold transition-all outline-none ',\n theme === 'dark'\n ? 'bg-z-hover border-z-border text-z-primary focus:border-z-accent/50 focus:bg-z-hover'\n : 'bg-z-panel border-z-border focus:border-z-accent/50'\n )}\n />\n </div>\n </div>\n }\n />\n <div className={cn(\n 'flex-1 overflow-y-auto p-6 md:p-10 space-y-10 transition-colors duration-500',\n theme === 'dark' ? 'bg-app text-z-primary' : 'bg-[#fafafa] text-z-primary'\n )}>\n {/* System Integrity Grid */}\n <div className=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n {[\n {\n label: 'Total Records',\n value: String(Object.values(stats).reduce((a: number, b: number) => a + b, 0)),\n icon: Activity,\n sub: 'Global Synchronization',\n },\n { label: 'Schema Health', value: '100%', icon: Shield, sub: 'Optimal Performance' },\n { label: 'Latency', value: '14ms', icon: Zap, sub: 'Neural Processing' },\n ].map((item, i) => (\n <div\n key={i}\n className={cn(\n 'p-8 border rounded-none-none flex flex-col gap-4 transition-all relative overflow-hidden group',\n theme === 'dark'\n ? 'bg-z-panel border-z-border'\n : 'bg-z-panel border-z-border shadow-sm shadow-sm'\n )}\n >\n <div className=\"absolute top-0 right-0 p-4 opacity-5 group-hover:opacity-10 transition-opacity\">\n <item.icon size={80} />\n </div>\n <span className=\"text-sm font-semibold text-z-secondary\">\n {item.label}\n </span>\n <div className=\"flex items-baseline gap-3\">\n <span className=\"text-4xl font-semibold\">\n {item.value}\n </span>\n <span className=\"text-sm font-bold text-z-secondary \">\n {item.sub}\n </span>\n </div>\n </div>\n ))}\n </div>\n\n {/* Collection Matrix */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-6\">\n {filteredCollections.map((col, i) => (\n <motion.div\n initial={{ opacity: 0, y: 20 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ delay: i * 0.05 }}\n key={col.slug}\n >\n <div\n onClick={() => navigate(`/collections/${col.slug}`)}\n className={cn(\n 'group p-8 border flex flex-col items-center text-center gap-5 transition-all duration-500 relative overflow-hidden cursor-pointer',\n 'bg-z-panel backdrop-blur-xl border-z-border shadow-sm hover:scale-[1.02] hover:border-z-active-border hover:shadow-premium'\n )}\n >\n {/* Micro-animation gradient background */}\n <div className=\"absolute inset-0 bg-gradient-to-br from-z-accent/0 to-z-accent/0 group-hover:from-z-accent/5 group-hover:to-transparent transition-all duration-500\" />\n \n <div\n className={cn(\n 'w-14 h-14 rounded-full flex items-center justify-center transition-all duration-500 relative z-10',\n 'bg-z-hover text-z-muted group-hover:bg-z-active-bg group-hover:text-z-active-text'\n )}\n >\n <Layers size={24} strokeWidth={1.5} />\n </div>\n\n <div className=\"relative z-10 flex flex-col items-center w-full\">\n <h3 className=\"text-xl font-black tracking-tight leading-none mb-3 group-hover:text-z-active-text transition-colors duration-500\">\n {col.label.replace(/-/g, ' ')}\n </h3>\n <div className=\"flex items-center justify-center mb-4\">\n <span className=\"px-2.5 py-1 rounded-full text-[9px] font-black uppercase tracking-widest bg-z-hover text-z-primary\">\n {stats[col.slug] || 0} Entries\n </span>\n </div>\n <p className=\"text-[11px] font-medium text-z-secondary leading-relaxed max-w-[90%]\">\n Manage and organize your {col.label.toLowerCase()} documents.\n </p>\n </div>\n\n <div className=\"w-full flex items-center justify-center pt-5 mt-auto border-t border-z-border/50 relative z-10\">\n <Link\n to={`/collections/${col.slug}/hooks`}\n onClick={(e) => e.stopPropagation()}\n className=\"flex items-center gap-1.5 text-[10px] font-black uppercase tracking-widest text-z-secondary hover:text-z-active-text transition-colors duration-300\"\n >\n <Code2 size={12} />\n Manage Hooks\n </Link>\n </div>\n </div>\n </motion.div>\n ))}\n </div>\n\n {isAIModalOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-[var(--z-bg-modal)] backdrop-blur-sm p-4\">\n <div\n className={cn(\n 'w-full max-w-3xl p-8 border shadow-2xl relative',\n 'bg-z-panel border-z-border'\n )}\n >\n <button\n onClick={() => setIsAIModalOpen(false)}\n className=\"absolute top-4 right-4 text-z-secondary hover:text-z-primary\"\n >\n \n </button>\n <h2 className=\"text-2xl font-semibold mb-4 flex items-center gap-2\">\n <Zap className=\"text-z-secondary \" /> AI Schema Architect\n </h2>\n <p className=\"text-sm font-bold text-z-secondary mb-6\">\n Describe the collection you want to create and let AI build the schema configuration.\n </p>\n\n <textarea\n value={aiPrompt}\n onChange={(e) => setAiPrompt(e.target.value)}\n placeholder=\"e.g., I need a blog post collection with title, content, cover image, seo metadata, and a category dropdown...\"\n className={cn(\n 'w-full h-32 p-4 mb-4 font-mono text-sm border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black focus:ring-2 focus:ring-z-active-border resize-none',\n theme === 'dark' ? 'bg-app border-z-border' : 'bg-z-input border-z-border'\n )}\n />\n\n <button\n onClick={handleAIGenerate}\n disabled={aiLoading}\n className=\"w-full py-4 bg-z-accent hover:bg-z-base text-z-primary font-semibold flex items-center justify-center gap-2\"\n >\n {aiLoading ? <Loader2 className=\"animate-spin\" size={16} /> : <Database size={16} />}\n {aiLoading ? 'Synthesizing Architecture...' : 'Generate Schema'}\n </button>\n\n {aiResult && (\n <div className=\"mt-6 border-t border-z-border pt-6\">\n <p className=\"text-sm font-bold text-z-muted mb-2\">\n Generated Schema Configuration (Copy to cms.config.ts)\n </p>\n <div className=\"relative\">\n <pre className=\"p-4 bg-[var(--z-bg-code)] text-z-muted text-xs font-mono overflow-auto max-h-64 border border-z-border\">\n {JSON.stringify(aiResult, null, 2)}\n </pre>\n <button\n onClick={() => navigator.clipboard.writeText(JSON.stringify(aiResult, null, 2))}\n className=\"absolute top-2 right-2 px-3 py-1 bg-z-hover hover:bg-z-panel border border-z-border text-sm font-semibold text-z-primary\"\n >\n Copy\n </button>\n </div>\n </div>\n )}\n </div>\n </div>\n )}\n {isVisualModalOpen && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-[var(--z-bg-modal)] backdrop-blur-md p-4 overflow-y-auto\">\n <div\n className={cn(\n 'w-full max-w-4xl p-10 border shadow-2xl relative my-8',\n 'bg-z-panel border-z-border text-z-primary'\n )}\n >\n <button\n onClick={() => setIsVisualModalOpen(false)}\n className=\"absolute top-6 right-6 w-8 h-8 flex items-center justify-center bg-z-hover hover:bg-z-panel rounded-none-none border border-z-border transition-colors text-z-muted hover:text-z-primary\"\n >\n \n </button>\n <h2 className=\"text-3xl font-semibold mb-4 flex items-center gap-3\">\n <Database className=\"text-z-secondary animate-pulse\" /> Visual Schema Builder\n </h2>\n <p className=\"text-sm font-semibold text-z-secondary mb-8 border-b border-z-border pb-4\">\n Define collection specifications, fields, types, and constraints visually without\n writing code.\n </p>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6 mb-8\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-z-secondary block\">\n Collection Name\n </label>\n <input\n type=\"text\"\n name=\"name\"\n value={newColName}\n onChange={(e) => handleNameChange(e.target.value)}\n placeholder=\"e.g. Review\"\n className={cn(\n 'w-full px-4 py-3 text-sm font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all ',\n 'bg-z-input border-z-border text-z-primary'\n )}\n />\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-z-secondary block\">\n Slug\n </label>\n <input\n type=\"text\"\n name=\"slug\"\n value={newColSlug}\n onChange={(e) => setNewColSlug(e.target.value)}\n placeholder=\"e.g. reviews\"\n className={cn(\n 'w-full px-4 py-3 text-sm font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all lowercase ',\n theme === 'dark'\n ? 'bg-app border-z-border text-z-muted'\n : 'bg-z-input border-z-border text-z-secondary'\n )}\n />\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 mb-8 px-2\">\n <input\n type=\"checkbox\"\n id=\"enable-drafts-checkbox\"\n checked={newColDrafts}\n onChange={(e) => setNewColDrafts(e.target.checked)}\n className=\"w-4 h-4 text-z-secondary focus:ring-z-active-border border-z-border-strong rounded-none-none bg-app\"\n />\n <label\n htmlFor=\"enable-drafts-checkbox\"\n className=\"text-sm font-semibold text-z-muted cursor-pointer select-none\"\n >\n Enable Draft/Publish Workflow\n </label>\n </div>\n\n <div className=\"space-y-6\">\n <div className=\"flex items-center justify-between border-b border-z-border pb-3\">\n <h3 className=\"text-xs font-semibold text-z-muted\">\n Field Definitions\n </h3>\n <button\n onClick={handleAddField}\n className=\"px-4 py-2 border border-dashed border-z-border/30 text-z-secondary hover:bg-z-hover text-sm font-semibold transition-all flex items-center gap-2\"\n >\n <Plus size={12} /> Add Field\n </button>\n </div>\n\n <div className=\"space-y-4 max-h-[30vh] overflow-y-auto pr-2 custom-scrollbar\">\n {newColFields.map((field, index) => (\n <div\n key={index}\n className={cn(\n 'p-5 border rounded-none-none grid grid-cols-1 md:grid-cols-4 gap-4 items-center relative group/field',\n theme === 'dark'\n ? 'bg-app border-z-border'\n : 'bg-z-input border-z-border shadow-sm'\n )}\n >\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-z-secondary block\">\n Field Name\n </label>\n <input\n type=\"text\"\n name={`field-name-${index}`}\n value={field.name}\n onChange={(e) => handleFieldChange(index, 'name', e.target.value)}\n placeholder=\"e.g. rating\"\n className={cn(\n 'w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all lowercase font-mono',\n theme === 'dark'\n ? 'bg-app border-z-border text-z-primary'\n : 'bg-z-panel border-z-border'\n )}\n />\n </div>\n\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-z-secondary block\">\n Type\n </label>\n <select\n value={field.type}\n onChange={(e) => handleFieldChange(index, 'type', e.target.value)}\n className={cn(\n 'w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all',\n theme === 'dark'\n ? 'bg-app border-z-border text-z-primary'\n : 'bg-z-panel border-z-border'\n )}\n >\n <option value=\"text\">Text</option>\n <option value=\"number\">Number</option>\n <option value=\"richtext\">Rich Text</option>\n <option value=\"media\">Media</option>\n <option value=\"checkbox\">Boolean</option>\n <option value=\"select\">Dropdown Select</option>\n <option value=\"relationship\">Relationship</option>\n </select>\n </div>\n\n {field.type === 'select' ? (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-z-secondary block\">\n Options (Comma separated)\n </label>\n <input\n type=\"text\"\n value={field.options || ''}\n onChange={(e) => handleFieldChange(index, 'options', e.target.value)}\n placeholder=\"e.g. red, blue, green\"\n className={cn(\n 'w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all',\n theme === 'dark'\n ? 'bg-app border-z-border text-z-primary'\n : 'bg-z-panel border-z-border'\n )}\n />\n </div>\n ) : field.type === 'relationship' ? (\n <div className=\"space-y-2\">\n <label className=\"text-sm font-semibold text-z-secondary block\">\n Relate To Collection\n </label>\n <select\n value={field.relationTo || ''}\n onChange={(e) => handleFieldChange(index, 'relationTo', e.target.value)}\n className={cn(\n 'w-full px-3 py-2 text-xs font-bold border rounded-none-none focus:ring-2 focus:ring-z-active-border outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-all',\n theme === 'dark'\n ? 'bg-app border-z-border text-z-primary'\n : 'bg-z-panel border-z-border'\n )}\n >\n <option value=\"\">Select Target...</option>\n <option value=\"users\">Users</option>\n {collections.map((c) => (\n <option key={c.slug} value={c.slug}>\n {c.label}\n </option>\n ))}\n </select>\n </div>\n ) : (\n <div className=\"flex items-center gap-3 pt-6\">\n <input\n type=\"checkbox\"\n id={`required-checkbox-${index}`}\n checked={!!field.required}\n onChange={(e) => handleFieldChange(index, 'required', e.target.checked)}\n className=\"w-3.5 h-3.5 text-z-secondary focus:ring-z-active-border border-z-border-strong rounded-none-none bg-app\"\n />\n <label\n htmlFor={`required-checkbox-${index}`}\n className=\"text-sm font-semibold text-z-muted cursor-pointer select-none\"\n >\n Required Field\n </label>\n </div>\n )}\n\n <div className=\"flex justify-end pt-5 md:pt-0\">\n <button\n onClick={() => handleRemoveField(index)}\n disabled={newColFields.length === 1}\n className=\"p-2 border border-transparent hover:border-red-500/30 hover:bg-red-500/5 text-z-secondary hover:text-red-500 transition-colors disabled:opacity-20\"\n >\n <Trash2 size={14} />\n </button>\n </div>\n </div>\n ))}\n </div>\n </div>\n\n <div className=\"mt-10 pt-8 border-t border-z-border flex justify-end gap-4\">\n <button\n onClick={() => setIsVisualModalOpen(false)}\n className={cn(\n 'px-6 py-3 font-semibold text-sm transition-all leading-none border',\n theme === 'dark'\n ? 'bg-z-hover border-z-border text-z-muted hover:text-z-primary'\n : 'bg-z-panel border-z-border text-z-muted hover:text-z-primary'\n )}\n >\n Cancel\n </button>\n <button\n onClick={handleCreateCollection}\n disabled={visualLoading}\n className=\"px-8 py-3 bg-z-accent hover:bg-z-base text-z-primary rounded-none-none text-sm font-semibold shadow-xl shadow-[var(--z-border)] transition-all flex items-center gap-2 leading-none\"\n >\n {visualLoading ? (\n <Loader2 size={12} className=\"animate-spin\" />\n ) : (\n <Check size={12} />\n )}\n Create Content Type\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default CollectionsPage\n"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{$n as t,Bt as n,C as r,G as i,Jt as a,Ln as o,Mn as s,Q as c,Ut as l,Vt as u,Zt as d,an as f,cn as p,d as m,fn as h,ir as g,l as _,rr as v,vr as y,xr as b}from"./vendor-react-DQVTOTFO.js";import{a as x,o as S,t as C}from"./utils-fgvbH6CB.js";import{m as w,s as T}from"./index-ChcKY5Xe.js";var E=e(b(),1),D=y(),O=[`text`,`textarea`,`number`,`boolean`,`richtext`,`date`,`email`,`media`,`relation`,`color`,`array`,`group`,`blocks`,`dz`,`select`,`json`,`slug`,`code`,`password`],k=[`General`,`Layout`,`Content`,`Commerce`,`Media`,`Social`,`Navigation`,`Forms`],A=({activeComponent:e,setActiveComponent:n,showPreview:i,generateJSON:o,generateTS:s,copied:u,setCopied:d,dark:f})=>{let m=C(`w-full border p-3 text-sm font-bold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-colors rounded-none shadow-sm`,`z-input`),h=()=>{n({...e,fields:[...e.fields,{name:``,type:`text`}]})},_=(t,r,i)=>{let a=[...e.fields];a[t]={...a[t],[r]:i},n({...e,fields:a})},y=t=>{let r=[...e.fields];r.splice(t,1),n({...e,fields:r})};return(0,D.jsxs)(v.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},exit:{opacity:0},className:`space-y-6`,children:[(0,D.jsxs)(`div`,{className:C(`p-6 border rounded-none space-y-4 shadow-sm transition-all`,`z-panel`),children:[(0,D.jsx)(`h3`,{className:`text-sm font-semibold text-z-secondary border-b border-z-border/20 pb-2`,children:`General Info`}),(0,D.jsxs)(`div`,{className:`grid grid-cols-1 md:grid-cols-2 gap-4`,children:[(0,D.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,D.jsx)(`label`,{className:`text-sm font-bold text-z-secondary block`,children:`Display Name`}),(0,D.jsx)(`input`,{type:`text`,value:e.displayName,onChange:t=>n({...e,displayName:t.target.value}),className:m,placeholder:`e.g. Hero Section`})]}),(0,D.jsxs)(`div`,{className:`space-y-1.5`,children:[(0,D.jsx)(`label`,{className:`text-sm font-bold text-z-secondary block`,children:`Category`}),(0,D.jsx)(`select`,{value:e.category,onChange:t=>n({...e,category:t.target.value}),className:C(m,`cursor-pointer`),children:k.map(e=>(0,D.jsx)(`option`,{value:e,className:`text-z-primary`,children:e},e))})]}),(0,D.jsxs)(`div`,{className:`space-y-1.5 col-span-2`,children:[(0,D.jsx)(`label`,{className:`text-sm font-bold text-z-secondary block`,children:`Component Slug (API ID)`}),(0,D.jsx)(`input`,{type:`text`,value:e.slug,onChange:t=>n({...e,slug:t.target.value.toLowerCase().replace(/[^a-z0-9_-]/g,``)}),disabled:!!e.id,className:C(m,`font-mono disabled:opacity-50`),placeholder:`e.g. hero-section`})]}),(0,D.jsxs)(`div`,{className:`space-y-1.5 col-span-2`,children:[(0,D.jsx)(`label`,{className:`text-sm font-bold text-z-secondary block`,children:`Description`}),(0,D.jsx)(`input`,{type:`text`,value:e.description,onChange:t=>n({...e,description:t.target.value}),className:m,placeholder:`Brief description of this component...`})]})]})]}),(0,D.jsxs)(`div`,{className:C(`p-6 border rounded-none shadow-sm transition-all`,`z-panel`),children:[(0,D.jsxs)(`div`,{className:`flex items-center justify-between mb-5 border-b border-z-border/20 pb-2`,children:[(0,D.jsx)(`h3`,{className:`text-sm font-semibold text-z-secondary `,children:`Fields Configuration`}),(0,D.jsxs)(`button`,{onClick:h,className:`flex items-center gap-1.5 text-sm font-semibold text-z-secondary hover:text-z-primary hover:bg-z-active-bg px-3 py-1.5 bg-z-panel rounded-none transition-all`,children:[(0,D.jsx)(c,{size:12}),` Add Field`]})]}),(0,D.jsx)(`div`,{className:`space-y-3`,children:(0,D.jsx)(g,{children:e.fields.map((e,t)=>(0,D.jsxs)(v.div,{layout:!0,initial:{opacity:0,y:8},animate:{opacity:1,y:0},exit:{opacity:0},className:C(`flex items-center gap-3 p-3.5 border rounded-none group shadow-sm transition-all`,f?`bg-z-panel backdrop-blur-sm border-z-border hover:border-z-active-border`:`bg-z-input border-z-border hover:border-z-border-strong`),children:[(0,D.jsx)(`input`,{type:`text`,value:e.name,onChange:e=>_(t,`name`,e.target.value.toLowerCase().replace(/[^a-z0-9_]/g,``)),placeholder:`field_name`,className:`flex-1 bg-transparent border-b border-transparent focus:border-z-accent text-sm font-mono outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black py-1 transition-colors`}),(0,D.jsx)(`select`,{value:e.type,onChange:e=>_(t,`type`,e.target.value),className:`w-36 bg-transparent border-b border-transparent focus:border-z-accent text-sm font-semibold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black py-1 transition-colors cursor-pointer`,children:O.map(e=>(0,D.jsx)(`option`,{value:e,className:`text-z-primary`,children:e},e))}),(0,D.jsxs)(`label`,{className:`flex items-center gap-2 text-sm font-semibold text-z-muted`,children:[(0,D.jsx)(`input`,{type:`checkbox`,checked:e.required||!1,onChange:e=>_(t,`required`,e.target.checked),className:`accent-z-accent`}),`Req`]}),(0,D.jsx)(`button`,{onClick:()=>y(t),className:`text-red-500/40 hover:text-red-500 transition-colors p-1.5 rounded-none opacity-0 group-hover:opacity-100`,children:(0,D.jsx)(r,{size:14})})]},t))})})]}),i&&(0,D.jsxs)(`div`,{className:C(`p-6 border rounded-none shadow-sm transition-all`,`z-panel`),children:[(0,D.jsxs)(`div`,{className:`flex items-center justify-between mb-4`,children:[(0,D.jsxs)(`h3`,{className:`text-sm font-semibold text-z-active-text flex items-center gap-2`,children:[(0,D.jsx)(t,{size:12}),` Live JSON Preview`]}),(0,D.jsxs)(`div`,{className:`flex gap-2`,children:[(0,D.jsxs)(`button`,{onClick:()=>{navigator.clipboard.writeText(o()),d(!0),setTimeout(()=>d(!1),2e3)},className:C(`flex items-center gap-1.5 px-3 py-1.5 border text-sm font-semibold rounded-none transition-all`,f?`border-z-border hover:bg-z-hover`:`border-z-border hover:bg-[var(--z-bg-input)]`),children:[u?(0,D.jsx)(p,{size:12,className:`text-z-secondary `}):(0,D.jsx)(a,{size:12}),` Copy JSON`]}),(0,D.jsxs)(`button`,{onClick:()=>{let t=new Blob([s()],{type:`text/typescript`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`${e.slug||`component`}.ts`,r.click()},className:C(`flex items-center gap-1.5 px-3 py-1.5 border text-sm font-semibold rounded-none transition-all text-z-active-text border-z-active-border hover:bg-z-active-bg`),children:[(0,D.jsx)(l,{size:12}),` TypeScript`]})]})]}),(0,D.jsx)(`pre`,{className:C(`text-sm font-mono overflow-auto max-h-64 p-4 rounded-none text-z-secondary shadow-inner border`,f?`bg-z-popover border-z-border`:`bg-z-accent border-z-border`),children:o()})]})]},`visual`)},j=({codeImport:e,setCodeImport:t,handleCodeImport:n,handleRegisterCode:r,dark:a})=>(0,D.jsx)(v.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},exit:{opacity:0},className:`space-y-4`,children:(0,D.jsxs)(`div`,{className:C(`p-6 border rounded-none shadow-sm transition-all`,`z-panel`),children:[(0,D.jsxs)(`h3`,{className:`text-sm font-semibold text-z-active-text mb-1 flex items-center gap-2`,children:[(0,D.jsx)(d,{size:12}),` Import from Code / JSON`]}),(0,D.jsx)(`p`,{className:C(`text-sm mb-4 font-medium`,a?`text-z-muted`:`text-z-secondary`),children:`Paste a JSON component definition, a TypeScript interface, or a raw fields array. The parser will auto-detect the format.`}),(0,D.jsxs)(`div`,{className:C(`p-4 rounded-none text-sm font-mono mb-4 text-z-secondary border shadow-inner`,a?`bg-z-popover border-z-border`:`bg-z-accent border-z-border`),children:[(0,D.jsx)(`p`,{className:`text-z-secondary mb-2`,children:`// JSON format (recommended)`}),`{
|
|
2
|
+
"slug": "hero-section",
|
|
3
|
+
"displayName": "Hero Section",
|
|
4
|
+
"category": "Layout",
|
|
5
|
+
"description": "Full-width hero with CTA",
|
|
6
|
+
"fields": [
|
|
7
|
+
{ "name": "headline", "type": "text", "required": true },
|
|
8
|
+
{ "name": "subtext", "type": "textarea" },
|
|
9
|
+
{ "name": "backgroundImage", "type": "media" },
|
|
10
|
+
{ "name": "ctaLabel", "type": "text" },
|
|
11
|
+
{ "name": "ctaUrl", "type": "text" }
|
|
12
|
+
]
|
|
13
|
+
}`]}),(0,D.jsx)(`textarea`,{rows:12,value:e,onChange:e=>t(e.target.value),placeholder:`Paste JSON or TypeScript interface here...`,className:C(`w-full border p-4 text-sm font-mono outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black rounded-none placeholder:text-z-secondary resize-none shadow-inner`,a?`bg-z-panel backdrop-blur-sm border-z-border focus:border-z-accent/50 text-z-primary`:`bg-z-input border-z-border focus:border-z-accent text-z-primary`)}),(0,D.jsxs)(`div`,{className:`flex gap-3 mt-4`,children:[(0,D.jsxs)(`button`,{onClick:n,disabled:!e.trim(),className:`flex items-center gap-2 px-5 py-2.5 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all disabled:opacity-40 shadow-sm`,children:[(0,D.jsx)(f,{size:14}),` Import to Visual Editor`]}),(0,D.jsxs)(`button`,{onClick:r,disabled:!e.trim(),className:`flex items-center gap-2 px-5 py-2.5 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all disabled:opacity-40 shadow-sm`,title:`Save directly to database without going through visual editor`,children:[(0,D.jsx)(i,{size:14}),` Register Directly`]}),(0,D.jsxs)(`button`,{onClick:()=>t(``),className:C(`flex items-center gap-2 px-4 py-2.5 border text-sm font-semibold rounded-none transition-all`,a?`border-z-border hover:bg-z-hover`:`border-z-border hover:bg-[var(--z-bg-input)]`),children:[(0,D.jsx)(m,{size:14}),` Clear`]})]})]})},`code`),M=({aiPrompt:e,setAiPrompt:t,isAIGenerating:n,handleAIGenerate:r,dark:i})=>(0,D.jsx)(v.div,{initial:{opacity:0,y:8},animate:{opacity:1,y:0},exit:{opacity:0},className:`space-y-4`,children:(0,D.jsxs)(`div`,{className:C(`p-6 border rounded-none shadow-sm transition-all`,`z-panel`),children:[(0,D.jsxs)(`h3`,{className:`text-sm font-semibold text-z-active-text mb-1 flex items-center gap-2`,children:[(0,D.jsx)(s,{size:12}),` AI Component Architect`]}),(0,D.jsx)(`p`,{className:C(`text-sm mb-6 font-medium`,i?`text-z-muted`:`text-z-secondary`),children:`Describe a component and the AI will generate its complete field schema. Works best with detailed descriptions.`}),(0,D.jsxs)(`div`,{className:`space-y-4`,children:[(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`label`,{className:`text-sm font-semibold text-z-secondary block mb-2`,children:`Describe your component`}),(0,D.jsx)(`textarea`,{rows:5,value:e,onChange:e=>t(e.target.value),placeholder:`e.g. "A pricing card component with a plan name, price per month, list of up to 5 feature bullets, a CTA button label, a highlighted/featured boolean flag, and a color accent picker."`,className:C(`w-full border p-4 text-sm outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black rounded-none placeholder:text-z-secondary resize-none shadow-inner`,i?`bg-z-panel backdrop-blur-sm border-z-border focus:border-z-accent/50 text-z-primary`:`bg-z-input border-z-border focus:border-z-accent text-z-primary`)})]}),(0,D.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:[`Navigation bar with logo, links array, and CTA button`,`Product card with image, name, price, and discount badge`,`Team member card with photo, name, role, bio, and social links`,`Testimonial with quote, author, avatar, rating, and company`].map(e=>(0,D.jsxs)(`button`,{onClick:()=>t(e),className:C(`text-sm font-semibold px-3 py-1.5 border rounded-none transition-all`,i?`border-z-border text-z-secondary hover:text-z-primary hover:border-z-accent/50 hover:bg-z-active-bg`:`border-z-border text-z-secondary hover:text-z-primary hover:border-z-active-border`),children:[e.slice(0,40),`...`]},e))}),(0,D.jsx)(`button`,{disabled:n||!e.trim(),onClick:r,className:`w-full py-4 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold flex justify-center items-center gap-2 transition-all rounded-none disabled:opacity-50 shadow-sm`,children:n?(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)(o,{size:14,className:`animate-spin`}),` Generating with AI...`]}):(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)(s,{size:14}),` Generate Component`]})})]})]})},`ai`),N=()=>{let{theme:e}=x(),t=e===`dark`,[l,f]=(0,E.useState)([]),[p,m]=(0,E.useState)(!0),[y,b]=(0,E.useState)(!1),[O,k]=(0,E.useState)(null),[N,P]=(0,E.useState)(`visual`),[F,I]=(0,E.useState)(``),[L,R]=(0,E.useState)(``),[z,B]=(0,E.useState)(!1),[V,H]=(0,E.useState)(!1),[U,W]=(0,E.useState)(!1);(0,E.useEffect)(()=>{G()},[]);let G=async()=>{m(!0);try{f((await S.get(`/system/components`)).data.data||[])}catch{_.error(`Failed to load components`)}finally{m(!1)}},K=()=>{k({id:``,slug:``,displayName:``,category:`General`,icon:`Box`,description:``,fields:[{name:`title`,type:`text`}]}),P(`visual`)},q=async()=>{if(!O||!O.slug||!O.displayName){_.error(`Slug and Display Name are required`);return}b(!0);try{if(O.id)await S.put(`/system/components/${O.id}`,O),_.success(`Component updated successfully`);else{let{id:e,...t}=O;await S.post(`/system/components`,t),_.success(`Component created successfully`)}T(),G(),k(null)}catch(e){_.error(e.response?.data?.message||`Failed to save component`)}finally{b(!1)}},J=async e=>{if(await w({message:`Delete this component? This may break pages currently using it.`}))try{await S.delete(`/system/components/${e}`),_.success(`Component deleted`),T(),O?.id===e&&k(null),G()}catch{_.error(`Failed to delete component`)}},Y=async e=>{try{await S.post(`/system/components/${e}/duplicate`),_.success(`Component duplicated`),T(),G()}catch{_.error(`Failed to duplicate component`)}};return C(`w-full border p-3 text-sm font-bold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-colors rounded-none`,`bg-z-input border-z-border focus:border-z-border text-z-primary`),(0,D.jsxs)(`div`,{className:C(`flex h-[calc(100vh-64px)] overflow-hidden`,t?`bg-app`:`bg-[var(--z-bg-input)]`),children:[(0,D.jsxs)(`div`,{className:C(`w-64 border-r shrink-0 flex flex-col`,`border-z-border bg-z-panel`),children:[(0,D.jsxs)(`div`,{className:`p-4 border-b border-inherit flex items-center justify-between`,children:[(0,D.jsxs)(`h2`,{className:`text-sm font-semibold flex items-center gap-2`,children:[(0,D.jsx)(h,{size:14,className:`text-z-secondary `}),` Components`]}),(0,D.jsx)(`button`,{onClick:K,className:`p-1.5 hover:bg-z-panel text-z-secondary rounded-none transition-colors`,children:(0,D.jsx)(c,{size:14})})]}),(0,D.jsxs)(`div`,{className:`flex-1 overflow-auto p-2 space-y-1`,children:[p?(0,D.jsx)(`div`,{className:`p-4 flex justify-center`,children:(0,D.jsx)(o,{className:`animate-spin text-z-muted`,size:16})}):l.map(e=>(0,D.jsxs)(`div`,{className:`group flex items-center gap-2 relative`,children:[(0,D.jsx)(`button`,{onClick:()=>{k(e),P(`visual`)},className:C(`flex-1 text-left px-3 py-2 text-sm font-bold transition-colors overflow-hidden text-ellipsis whitespace-nowrap rounded-none`,O?.id===e.id?`bg-z-border text-z-primary`:t?`text-z-muted hover:bg-z-hover hover:text-z-primary`:`text-z-secondary hover:bg-[var(--z-bg-input)] hover:text-z-primary`),children:e.displayName}),(0,D.jsxs)(`div`,{className:`absolute right-2 opacity-0 group-hover:opacity-100 transition-opacity flex items-center gap-1`,children:[(0,D.jsx)(`button`,{onClick:t=>{t.stopPropagation(),Y(e.id)},className:`p-1 text-z-muted hover:text-z-secondary transition-colors`,title:`Duplicate`,children:(0,D.jsx)(a,{size:12})}),(0,D.jsx)(`button`,{onClick:t=>{t.stopPropagation(),J(e.id)},className:`p-1 text-z-muted hover:text-red-500 transition-colors`,title:`Delete`,children:(0,D.jsx)(r,{size:12})})]})]},e.id)),!p&&l.length===0&&(0,D.jsx)(`div`,{className:`p-4 text-center text-sm text-z-secondary`,children:`No components found`})]})]}),(0,D.jsx)(`div`,{className:`flex-1 overflow-auto bg-inherit relative custom-editor-scrollbar`,children:O?(0,D.jsxs)(v.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},className:`max-w-4xl mx-auto p-8 space-y-6`,children:[(0,D.jsxs)(`div`,{className:`flex items-center justify-between pb-6 border-b border-z-border`,children:[(0,D.jsxs)(`div`,{children:[(0,D.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,D.jsx)(`a`,{href:`/`,className:`text-z-secondary hover:text-z-primary transition-colors`,children:(0,D.jsxs)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`20`,height:`20`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,className:`lucide lucide-arrow-left`,children:[(0,D.jsx)(`path`,{d:`m12 19-7-7 7-7`}),(0,D.jsx)(`path`,{d:`M19 12H5`})]})}),(0,D.jsx)(`h1`,{className:`text-2xl font-semibold`,children:`Component Builder`})]}),(0,D.jsx)(`p`,{className:C(`text-sm font-bold mt-1 ml-8`,`text-z-secondary`),children:O.id?`Editing existing component`:`Creating new component`})]}),(0,D.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,D.jsxs)(`button`,{onClick:()=>W(!U),className:C(`flex items-center gap-2 px-4 py-2.5 border text-sm font-semibold rounded-none transition-all shadow-sm`,t?`bg-z-panel backdrop-blur-md border-z-border hover:border-z-active-border`:`bg-z-panel border-z-border hover:bg-[var(--z-bg-input)]`),children:[U?(0,D.jsx)(u,{size:14}):(0,D.jsx)(n,{size:14}),U?`Hide`:`Preview`]}),(0,D.jsxs)(`button`,{onClick:q,disabled:y,className:`flex items-center gap-2 px-6 py-2.5 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold shadow-sm rounded-none transition-all disabled:opacity-50`,children:[y?(0,D.jsx)(o,{size:14,className:`animate-spin`}):(0,D.jsx)(i,{size:14}),`Save Component`]})]})]}),(0,D.jsx)(`div`,{className:C(`flex items-center gap-1 p-1 border rounded-none w-fit shadow-sm`,`z-panel`),children:[{key:`visual`,label:`Visual Editor`,icon:h},{key:`code`,label:`Code / JSON Import`,icon:d},{key:`ai`,label:`AI Generate`,icon:s}].map(e=>{let n=e.icon;return(0,D.jsxs)(`button`,{onClick:()=>P(e.key),className:C(`flex items-center gap-2 px-4 py-2 text-sm font-semibold rounded-none transition-all`,N===e.key?`bg-z-accent text-z-logo-text shadow-sm`:t?`text-z-secondary hover:text-z-secondary`:`text-z-secondary hover:text-z-primary`),children:[(0,D.jsx)(n,{size:12}),` `,e.label]},e.key)})}),(0,D.jsxs)(g,{mode:`wait`,children:[N===`visual`&&(0,D.jsx)(A,{activeComponent:O,setActiveComponent:k,showPreview:U,generateJSON:()=>O?JSON.stringify({slug:O.slug,displayName:O.displayName,category:O.category,description:O.description,fields:O.fields},null,2):`{}`,generateTS:()=>{if(!O)return``;let e=O.displayName.replace(/\s+/g,``)||`Component`,t={text:`string`,textarea:`string`,email:`string`,password:`string`,slug:`string`,code:`string`,color:`string`,number:`number`,checkbox:`boolean`,date:`Date`,media:`MediaItem`,relation:`string | null`,richtext:`string`,json:`any`,array:`any[]`,blocks:`Block[]`,group:`any`,select:`string`};return`interface ${e} {\n${O.fields.map(e=>{let n=t[e.type]||`unknown`;return` ${e.name}: ${n}`}).join(`
|
|
14
|
+
`)}\n}`},copied:V,setCopied:H,dark:t}),N===`code`&&(0,D.jsx)(j,{codeImport:F,setCodeImport:I,handleCodeImport:()=>{try{let e=null,t=F.trim();if(t.startsWith(`{`)||t.startsWith(`[`))e=JSON.parse(t.startsWith(`[`)?`{"fields":${t}}`:t);else if(t.includes(`interface`)||t.includes(`type `)){e={fields:[...t.matchAll(/(\w+)\??:\s*(string|number|boolean|Date|any|object|unknown)(?:\[\])?/g)].map(e=>({name:e[1],type:e[2]===`string`?`text`:e[2]===`number`?`number`:e[2]===`boolean`?`checkbox`:`json`}))};let n=t.match(/interface\s+(\w+)/);n&&(e.displayName=n[1],e.slug=n[1].replace(/([A-Z])/g,`-$1`).toLowerCase().replace(/^-/,``))}e&&e.fields&&Array.isArray(e.fields)?(k({id:``,slug:e.slug||``,displayName:e.displayName||e.name||``,category:e.category||`General`,icon:`Box`,description:e.description||``,fields:e.fields}),P(`visual`),_.success(`Imported ${e.fields.length} fields from code`)):_.error(`Could not parse fields. Use JSON format: { "slug": "...", "displayName": "...", "fields": [...] }`)}catch(e){_.error(`Parse error: ${e instanceof Error?e.message:String(e)}`)}},handleRegisterCode:async()=>{try{let e=JSON.parse(F),t=await S.post(`/system/components/register-code`,e);_.success(`Component registered from code!`),T(),G(),I(``),P(`visual`);let n=t.data?.data;n&&k(n)}catch(e){_.error(e.response?.data?.message||(e instanceof Error?e.message:String(e))||`Failed to register component`)}},dark:t}),N===`ai`&&(0,D.jsx)(M,{aiPrompt:L,setAiPrompt:R,isAIGenerating:z,handleAIGenerate:async()=>{if(!L)return _.error(`Enter a prompt`);B(!0);try{let e=(await S.post(`/system/ai-architect`,{prompt:`Generate a reusable UI component schema (as JSON with slug, displayName, category, description, and fields array). Component description: ${L}`})).data?.data;e&&e.fields?(k({id:``,slug:e.slug||``,displayName:e.displayName||e.name||``,category:e.category||`General`,icon:`Box`,description:e.description||``,fields:e.fields}),P(`visual`),_.success(`AI generated component schema!`)):_.error(`AI did not return a valid component schema`)}catch(e){_.error(e.response?.data?.error?.message||`AI generation failed`)}finally{B(!1)}},dark:t})]})]}):(0,D.jsx)(`div`,{className:`h-full flex items-center justify-center`,children:(0,D.jsxs)(`div`,{className:`text-center space-y-5 max-w-md px-8`,children:[(0,D.jsx)(`div`,{className:`w-16 h-16 mx-auto rounded-none bg-z-panel border border-z-border flex items-center justify-center shadow-sm`,children:(0,D.jsx)(h,{size:28,className:`text-z-active-text`,strokeWidth:1.5})}),(0,D.jsx)(`div`,{className:`flex items-center justify-center mb-6`,children:(0,D.jsxs)(`a`,{href:`/`,className:`flex items-center gap-2 text-sm font-semibold text-z-secondary hover:text-z-primary transition-colors`,children:[(0,D.jsxs)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,className:`lucide lucide-arrow-left`,children:[(0,D.jsx)(`path`,{d:`m12 19-7-7 7-7`}),(0,D.jsx)(`path`,{d:`M19 12H5`})]}),`Back to Dashboard`]})}),(0,D.jsxs)(`div`,{children:[(0,D.jsx)(`p`,{className:`text-[14px] font-semibold`,children:`Component Builder`}),(0,D.jsx)(`p`,{className:C(`text-sm font-medium mt-2 leading-relaxed`,`text-z-secondary`),children:`Create reusable components like Navbars, Cards, and Hero Sections to use in Dynamic Zones and Blocks. Import from JSON, TypeScript interfaces, or let AI generate them.`})]}),(0,D.jsxs)(`div`,{className:`flex gap-3 justify-center`,children:[(0,D.jsxs)(`button`,{onClick:K,className:`flex items-center gap-2 px-5 py-3 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all shadow-sm`,children:[(0,D.jsx)(c,{size:14}),` New Component`]}),(0,D.jsxs)(`button`,{onClick:()=>{K(),setTimeout(()=>P(`ai`),50)},className:`flex items-center gap-2 px-5 py-3 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all shadow-sm`,children:[(0,D.jsx)(s,{size:14}),` AI Generate`]})]})]})})})]})};export{N as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ComponentBuilderPage-CT6S12LA.js","names":[],"sources":["../../src/pages/component-builder/BuilderVisualTab.tsx","../../src/pages/component-builder/BuilderCodeTab.tsx","../../src/pages/component-builder/BuilderAITab.tsx","../../src/pages/ComponentBuilderPage.tsx"],"sourcesContent":["import React from 'react'\nimport { motion, AnimatePresence } from 'framer-motion'\nimport { Plus, Trash2, Check, Copy, Download, Braces } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nconst FIELD_TYPES = [\n 'text', 'textarea', 'number', 'boolean', 'richtext', 'date',\n 'email', 'media', 'relation', 'color', 'array', 'group', 'blocks', 'dz',\n 'select', 'json', 'slug', 'code', 'password',\n]\n\nconst CATEGORIES = ['General', 'Layout', 'Content', 'Commerce', 'Media', 'Social', 'Navigation', 'Forms']\n\nexport const BuilderVisualTab = ({\n activeComponent,\n setActiveComponent,\n showPreview,\n generateJSON,\n generateTS,\n copied,\n setCopied,\n dark\n}: any) => {\n const inputCls = cn(\n 'w-full border p-3 text-sm font-bold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-colors rounded-none shadow-sm',\n 'z-input'\n )\n\n const addField = () => {\n setActiveComponent({\n ...activeComponent,\n fields: [...activeComponent.fields, { name: '', type: 'text' }]\n })\n }\n\n const updateField = (index: number, key: string, value: any) => {\n const newFields = [...activeComponent.fields]\n newFields[index] = { ...newFields[index], [key]: value }\n setActiveComponent({ ...activeComponent, fields: newFields })\n }\n\n const removeField = (index: number) => {\n const newFields = [...activeComponent.fields]\n newFields.splice(index, 1)\n setActiveComponent({ ...activeComponent, fields: newFields })\n }\n\n return (\n <motion.div key=\"visual\" initial={{ opacity: 0, y: 8 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }} className=\"space-y-6\">\n {/* General info */}\n <div className={cn('p-6 border rounded-none space-y-4 shadow-sm transition-all', 'z-panel')}>\n <h3 className=\"text-sm font-semibold text-z-secondary border-b border-z-border/20 pb-2\">General Info</h3>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-bold text-z-secondary block\">Display Name</label>\n <input type=\"text\" value={activeComponent.displayName} onChange={(e) => setActiveComponent({ ...activeComponent, displayName: e.target.value })} className={inputCls} placeholder=\"e.g. Hero Section\" />\n </div>\n <div className=\"space-y-1.5\">\n <label className=\"text-sm font-bold text-z-secondary block\">Category</label>\n <select value={activeComponent.category} onChange={(e) => setActiveComponent({ ...activeComponent, category: e.target.value })} className={cn(inputCls, 'cursor-pointer')}>\n {CATEGORIES.map(c => <option key={c} value={c} className=\"text-z-primary\">{c}</option>)}\n </select>\n </div>\n <div className=\"space-y-1.5 col-span-2\">\n <label className=\"text-sm font-bold text-z-secondary block\">Component Slug (API ID)</label>\n <input type=\"text\" value={activeComponent.slug} onChange={(e) => setActiveComponent({ ...activeComponent, slug: e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, '') })} disabled={!!activeComponent.id} className={cn(inputCls, 'font-mono disabled:opacity-50')} placeholder=\"e.g. hero-section\" />\n </div>\n <div className=\"space-y-1.5 col-span-2\">\n <label className=\"text-sm font-bold text-z-secondary block\">Description</label>\n <input type=\"text\" value={activeComponent.description} onChange={(e) => setActiveComponent({ ...activeComponent, description: e.target.value })} className={inputCls} placeholder=\"Brief description of this component...\" />\n </div>\n </div>\n </div>\n\n {/* Fields */}\n <div className={cn('p-6 border rounded-none shadow-sm transition-all', 'z-panel')}>\n <div className=\"flex items-center justify-between mb-5 border-b border-z-border/20 pb-2\">\n <h3 className=\"text-sm font-semibold text-z-secondary \">Fields Configuration</h3>\n <button onClick={addField} className=\"flex items-center gap-1.5 text-sm font-semibold text-z-secondary hover:text-z-primary hover:bg-z-active-bg px-3 py-1.5 bg-z-panel rounded-none transition-all\">\n <Plus size={12} /> Add Field\n </button>\n </div>\n <div className=\"space-y-3\">\n <AnimatePresence>\n {activeComponent.fields.map((field: any, idx: number) => (\n <motion.div\n key={idx}\n layout\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0 }}\n className={cn('flex items-center gap-3 p-3.5 border rounded-none group shadow-sm transition-all', dark ? 'bg-z-panel backdrop-blur-sm border-z-border hover:border-z-active-border' : 'bg-z-input border-z-border hover:border-z-border-strong')}\n >\n <input\n type=\"text\"\n value={field.name}\n onChange={e => updateField(idx, 'name', e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, ''))}\n placeholder=\"field_name\"\n className=\"flex-1 bg-transparent border-b border-transparent focus:border-z-accent text-sm font-mono outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black py-1 transition-colors\"\n />\n <select\n value={field.type}\n onChange={e => updateField(idx, 'type', e.target.value)}\n className=\"w-36 bg-transparent border-b border-transparent focus:border-z-accent text-sm font-semibold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black py-1 transition-colors cursor-pointer\"\n >\n {FIELD_TYPES.map(t => <option key={t} value={t} className=\"text-z-primary\">{t}</option>)}\n </select>\n <label className=\"flex items-center gap-2 text-sm font-semibold text-z-muted\">\n <input type=\"checkbox\" checked={field.required || false} onChange={e => updateField(idx, 'required', e.target.checked)} className=\"accent-z-accent\" />\n Req\n </label>\n <button onClick={() => removeField(idx)} className=\"text-red-500/40 hover:text-red-500 transition-colors p-1.5 rounded-none opacity-0 group-hover:opacity-100\">\n <Trash2 size={14} />\n </button>\n </motion.div>\n ))}\n </AnimatePresence>\n </div>\n </div>\n\n {showPreview && (\n <div className={cn('p-6 border rounded-none shadow-sm transition-all', 'z-panel')}>\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-semibold text-z-active-text flex items-center gap-2\">\n <Braces size={12} /> Live JSON Preview\n </h3>\n <div className=\"flex gap-2\">\n <button\n onClick={() => { navigator.clipboard.writeText(generateJSON()); setCopied(true); setTimeout(() => setCopied(false), 2000) }}\n className={cn('flex items-center gap-1.5 px-3 py-1.5 border text-sm font-semibold rounded-none transition-all', dark ? 'border-z-border hover:bg-z-hover' : 'border-z-border hover:bg-[var(--z-bg-input)]')}\n >\n {copied ? <Check size={12} className=\"text-z-secondary \" /> : <Copy size={12} />} Copy JSON\n </button>\n <button\n onClick={() => { const blob = new Blob([generateTS()], { type: 'text/typescript' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${activeComponent.slug || 'component'}.ts`; a.click() }}\n className={cn('flex items-center gap-1.5 px-3 py-1.5 border text-sm font-semibold rounded-none transition-all text-z-active-text border-z-active-border hover:bg-z-active-bg')}\n >\n <Download size={12} /> TypeScript\n </button>\n </div>\n </div>\n <pre className={cn('text-sm font-mono overflow-auto max-h-64 p-4 rounded-none text-z-secondary shadow-inner border', dark ? 'bg-z-popover border-z-border' : 'bg-z-accent border-z-border')}>{generateJSON()}</pre>\n </div>\n )}\n </motion.div>\n )\n}\n","import React from 'react'\nimport { motion } from 'framer-motion'\nimport { Code, ChevronRight, Save, X } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport const BuilderCodeTab = ({\n codeImport,\n setCodeImport,\n handleCodeImport,\n handleRegisterCode,\n dark\n}: any) => {\n return (\n <motion.div key=\"code\" initial={{ opacity: 0, y: 8 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }} className=\"space-y-4\">\n <div className={cn('p-6 border rounded-none shadow-sm transition-all', 'z-panel')}>\n <h3 className=\"text-sm font-semibold text-z-active-text mb-1 flex items-center gap-2\">\n <Code size={12} /> Import from Code / JSON\n </h3>\n <p className={cn('text-sm mb-4 font-medium', dark ? 'text-z-muted' : 'text-z-secondary')}>\n Paste a JSON component definition, a TypeScript interface, or a raw fields array. The parser will auto-detect the format.\n </p>\n\n {/* Format examples */}\n <div className={cn('p-4 rounded-none text-sm font-mono mb-4 text-z-secondary border shadow-inner', dark ? 'bg-z-popover border-z-border' : 'bg-z-accent border-z-border')}>\n <p className=\"text-z-secondary mb-2\">// JSON format (recommended)</p>\n {`{\n \"slug\": \"hero-section\",\n \"displayName\": \"Hero Section\",\n \"category\": \"Layout\",\n \"description\": \"Full-width hero with CTA\",\n \"fields\": [\n { \"name\": \"headline\", \"type\": \"text\", \"required\": true },\n { \"name\": \"subtext\", \"type\": \"textarea\" },\n { \"name\": \"backgroundImage\", \"type\": \"media\" },\n { \"name\": \"ctaLabel\", \"type\": \"text\" },\n { \"name\": \"ctaUrl\", \"type\": \"text\" }\n ]\n}`}\n </div>\n\n <textarea\n rows={12}\n value={codeImport}\n onChange={e => setCodeImport(e.target.value)}\n placeholder='Paste JSON or TypeScript interface here...'\n className={cn('w-full border p-4 text-sm font-mono outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black rounded-none placeholder:text-z-secondary resize-none shadow-inner', dark ? 'bg-z-panel backdrop-blur-sm border-z-border focus:border-z-accent/50 text-z-primary' : 'bg-z-input border-z-border focus:border-z-accent text-z-primary')}\n />\n\n <div className=\"flex gap-3 mt-4\">\n <button\n onClick={handleCodeImport}\n disabled={!codeImport.trim()}\n className=\"flex items-center gap-2 px-5 py-2.5 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all disabled:opacity-40 shadow-sm\"\n >\n <ChevronRight size={14} /> Import to Visual Editor\n </button>\n <button\n onClick={handleRegisterCode}\n disabled={!codeImport.trim()}\n className=\"flex items-center gap-2 px-5 py-2.5 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all disabled:opacity-40 shadow-sm\"\n title=\"Save directly to database without going through visual editor\"\n >\n <Save size={14} /> Register Directly\n </button>\n <button\n onClick={() => setCodeImport('')}\n className={cn('flex items-center gap-2 px-4 py-2.5 border text-sm font-semibold rounded-none transition-all', dark ? 'border-z-border hover:bg-z-hover' : 'border-z-border hover:bg-[var(--z-bg-input)]')}\n >\n <X size={14} /> Clear\n </button>\n </div>\n </div>\n </motion.div>\n )\n}\n","import React from 'react'\nimport { motion } from 'framer-motion'\nimport { Sparkles, Loader2 } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport const BuilderAITab = ({\n aiPrompt,\n setAiPrompt,\n isAIGenerating,\n handleAIGenerate,\n dark\n}: any) => {\n return (\n <motion.div key=\"ai\" initial={{ opacity: 0, y: 8 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0 }} className=\"space-y-4\">\n <div className={cn('p-6 border rounded-none shadow-sm transition-all', 'z-panel')}>\n <h3 className=\"text-sm font-semibold text-z-active-text mb-1 flex items-center gap-2\">\n <Sparkles size={12} /> AI Component Architect\n </h3>\n <p className={cn('text-sm mb-6 font-medium', dark ? 'text-z-muted' : 'text-z-secondary')}>\n Describe a component and the AI will generate its complete field schema. Works best with detailed descriptions.\n </p>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-semibold text-z-secondary block mb-2\">Describe your component</label>\n <textarea\n rows={5}\n value={aiPrompt}\n onChange={e => setAiPrompt(e.target.value)}\n placeholder='e.g. \"A pricing card component with a plan name, price per month, list of up to 5 feature bullets, a CTA button label, a highlighted/featured boolean flag, and a color accent picker.\"'\n className={cn('w-full border p-4 text-sm outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black rounded-none placeholder:text-z-secondary resize-none shadow-inner', dark ? 'bg-z-panel backdrop-blur-sm border-z-border focus:border-z-accent/50 text-z-primary' : 'bg-z-input border-z-border focus:border-z-accent text-z-primary')}\n />\n </div>\n\n {/* Prompt suggestions */}\n <div className=\"flex flex-wrap gap-2\">\n {[\n 'Navigation bar with logo, links array, and CTA button',\n 'Product card with image, name, price, and discount badge',\n 'Team member card with photo, name, role, bio, and social links',\n 'Testimonial with quote, author, avatar, rating, and company',\n ].map(suggestion => (\n <button\n key={suggestion}\n onClick={() => setAiPrompt(suggestion)}\n className={cn('text-sm font-semibold px-3 py-1.5 border rounded-none transition-all', dark ? 'border-z-border text-z-secondary hover:text-z-primary hover:border-z-accent/50 hover:bg-z-active-bg' : 'border-z-border text-z-secondary hover:text-z-primary hover:border-z-active-border')}\n >\n {suggestion.slice(0, 40)}...\n </button>\n ))}\n </div>\n\n <button\n disabled={isAIGenerating || !aiPrompt.trim()}\n onClick={handleAIGenerate}\n className=\"w-full py-4 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold flex justify-center items-center gap-2 transition-all rounded-none disabled:opacity-50 shadow-sm\"\n >\n {isAIGenerating\n ? <><Loader2 size={14} className=\"animate-spin\" /> Generating with AI...</>\n : <><Sparkles size={14} /> Generate Component</>\n }\n </button>\n </div>\n </div>\n </motion.div>\n )\n}\n","import React, { useState, useEffect } from 'react'\nimport { motion, AnimatePresence } from 'framer-motion'\nimport {\n Plus, Box, Save, Loader2, Trash2, Copy, Code, Sparkles, Eye, EyeOff,\n ChevronRight, Check, X, Braces, Download\n} from 'lucide-react'\nimport { useTheme } from '../context/ThemeContext'\nimport { cn } from '../lib/utils'\nimport api from '../lib/api'\nimport { confirm } from '../store/confirmStore'\nimport toast from 'react-hot-toast'\nimport type { CustomComponent } from '../hooks/useCustomComponents'\nimport { invalidateCustomComponentsCache } from '../hooks/useCustomComponents'\nimport { BuilderVisualTab } from './component-builder/BuilderVisualTab'\nimport { BuilderCodeTab } from './component-builder/BuilderCodeTab'\nimport { BuilderAITab } from './component-builder/BuilderAITab'\n\n\n\n\n\n\ntype EditorTab = 'visual' | 'code' | 'ai'\n\nconst ComponentBuilderPage: React.FC = () => {\n const { theme } = useTheme()\n const dark = theme === 'dark'\n const [components, setComponents] = useState<CustomComponent[]>([])\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [activeComponent, setActiveComponent] = useState<CustomComponent | null>(null)\n const [activeTab, setActiveTab] = useState<EditorTab>('visual')\n const [codeImport, setCodeImport] = useState('')\n const [aiPrompt, setAiPrompt] = useState('')\n const [isAIGenerating, setIsAIGenerating] = useState(false)\n const [copied, setCopied] = useState(false)\n const [showPreview, setShowPreview] = useState(false)\n\n useEffect(() => {\n loadComponents()\n }, [])\n\n const loadComponents = async () => {\n setLoading(true)\n try {\n const res = await api.get('/system/components')\n setComponents(res.data.data || [])\n } catch {\n toast.error('Failed to load components')\n } finally {\n setLoading(false)\n }\n }\n\n const handleCreateNew = () => {\n setActiveComponent({\n id: '',\n slug: '',\n displayName: '',\n category: 'General',\n icon: 'Box',\n description: '',\n fields: [{ name: 'title', type: 'text' }]\n })\n setActiveTab('visual')\n }\n\n const handleSave = async () => {\n if (!activeComponent || !activeComponent.slug || !activeComponent.displayName) {\n toast.error('Slug and Display Name are required')\n return\n }\n setSaving(true)\n try {\n if (activeComponent.id) {\n await api.put(`/system/components/${activeComponent.id}`, activeComponent)\n toast.success('Component updated successfully')\n } else {\n const { id, ...dataToPost } = activeComponent\n await api.post('/system/components', dataToPost)\n toast.success('Component created successfully')\n }\n invalidateCustomComponentsCache()\n loadComponents()\n setActiveComponent(null)\n } catch (err: any) {\n toast.error(err.response?.data?.message || 'Failed to save component')\n } finally {\n setSaving(false)\n }\n }\n\n const handleDelete = async (id: string) => {\n if (!await confirm({ message: 'Delete this component? This may break pages currently using it.' })) return\n try {\n await api.delete(`/system/components/${id}`)\n toast.success('Component deleted')\n invalidateCustomComponentsCache()\n if (activeComponent?.id === id) setActiveComponent(null)\n loadComponents()\n } catch {\n toast.error('Failed to delete component')\n }\n }\n\n const handleDuplicate = async (id: string) => {\n try {\n await api.post(`/system/components/${id}/duplicate`)\n toast.success('Component duplicated')\n invalidateCustomComponentsCache()\n loadComponents()\n } catch {\n toast.error('Failed to duplicate component')\n }\n }\n\n // ── Code Import: parse JSON / TypeScript interface ──────────────────────────\n const handleCodeImport = () => {\n try {\n // Try JSON parse first\n let parsed: any = null\n const trimmed = codeImport.trim()\n\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n const jsonData = JSON.parse(trimmed.startsWith('[') ? `{\"fields\":${trimmed}}` : trimmed)\n parsed = jsonData\n } else if (trimmed.includes('interface') || trimmed.includes('type ')) {\n // Parse TypeScript interface\n const fieldMatches = [...trimmed.matchAll(/(\\w+)\\??:\\s*(string|number|boolean|Date|any|object|unknown)(?:\\[\\])?/g)]\n parsed = {\n fields: fieldMatches.map(m => ({\n name: m[1],\n type: m[2] === 'string' ? 'text' : m[2] === 'number' ? 'number' : m[2] === 'boolean' ? 'checkbox' : 'json'\n }))\n }\n // Try to extract interface name\n const nameMatch = trimmed.match(/interface\\s+(\\w+)/)\n if (nameMatch) {\n parsed.displayName = nameMatch[1]\n parsed.slug = nameMatch[1].replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '')\n }\n }\n\n if (parsed && parsed.fields && Array.isArray(parsed.fields)) {\n setActiveComponent({\n id: '',\n slug: parsed.slug || '',\n displayName: parsed.displayName || parsed.name || '',\n category: parsed.category || 'General',\n icon: 'Box',\n description: parsed.description || '',\n fields: parsed.fields,\n })\n setActiveTab('visual')\n toast.success(`Imported ${parsed.fields.length} fields from code`)\n } else {\n toast.error('Could not parse fields. Use JSON format: { \"slug\": \"...\", \"displayName\": \"...\", \"fields\": [...] }')\n }\n } catch (err: any) {\n toast.error(`Parse error: ${(err instanceof Error ? err.message : String(err))}`)\n }\n }\n\n // ── Register via code (backend endpoint) ───────────────────────────────────\n const handleRegisterCode = async () => {\n try {\n const parsed = JSON.parse(codeImport)\n const res = await api.post('/system/components/register-code', parsed)\n toast.success('Component registered from code!')\n invalidateCustomComponentsCache()\n loadComponents()\n setCodeImport('')\n setActiveTab('visual')\n const comp = res.data?.data\n if (comp) setActiveComponent(comp)\n } catch (err: any) {\n toast.error(err.response?.data?.message || (err instanceof Error ? err.message : String(err)) || 'Failed to register component')\n }\n }\n\n // ── AI Generate ────────────────────────────────────────────────────────────\n const handleAIGenerate = async () => {\n if (!aiPrompt) return toast.error('Enter a prompt')\n setIsAIGenerating(true)\n try {\n const res = await api.post('/system/ai-architect', {\n prompt: `Generate a reusable UI component schema (as JSON with slug, displayName, category, description, and fields array). Component description: ${aiPrompt}`\n })\n const schema = res.data?.data\n if (schema && schema.fields) {\n setActiveComponent({\n id: '',\n slug: schema.slug || '',\n displayName: schema.displayName || schema.name || '',\n category: schema.category || 'General',\n icon: 'Box',\n description: schema.description || '',\n fields: schema.fields,\n })\n setActiveTab('visual')\n toast.success('AI generated component schema!')\n } else {\n toast.error('AI did not return a valid component schema')\n }\n } catch (err: any) {\n toast.error(err.response?.data?.error?.message || 'AI generation failed')\n } finally {\n setIsAIGenerating(false)\n }\n }\n\n // ── Generate JSON preview ──────────────────────────────────────────────────\n const generateJSON = () => {\n if (!activeComponent) return '{}'\n return JSON.stringify({\n slug: activeComponent.slug,\n displayName: activeComponent.displayName,\n category: activeComponent.category,\n description: activeComponent.description,\n fields: activeComponent.fields,\n }, null, 2)\n }\n\n // ── Generate TypeScript Interface ─────────────────────────────────────────\n const generateTS = () => {\n if (!activeComponent) return ''\n const typeName = activeComponent.displayName.replace(/\\s+/g, '') || 'Component'\n const typeMap: Record<string, string> = {\n text: 'string', textarea: 'string', email: 'string', password: 'string',\n slug: 'string', code: 'string', color: 'string',\n number: 'number', checkbox: 'boolean',\n date: 'Date', media: 'MediaItem', relation: 'string | null',\n richtext: 'string', json: 'any',\n array: 'any[]', blocks: 'Block[]', group: 'any',\n select: 'string',\n }\n const fields = activeComponent.fields.map(f => {\n const ts = typeMap[f.type] || 'unknown'\n return ` ${f.name}: ${ts}`\n }).join('\\n')\n return `interface ${typeName} {\\n${fields}\\n}`\n }\n\n const inputCls = cn(\n 'w-full border p-3 text-sm font-bold outline-none focus-visible:ring-2 focus-visible:ring-z-active-border focus-visible:ring-offset-1 focus-visible:ring-offset-black transition-colors rounded-none',\n 'bg-z-input border-z-border focus:border-z-border text-z-primary'\n )\n\n return (\n <div className={cn('flex h-[calc(100vh-64px)] overflow-hidden', dark ? 'bg-app' : 'bg-[var(--z-bg-input)]')}>\n {/* ── Sidebar List ──────────────────────────────────────────────── */}\n <div className={cn('w-64 border-r shrink-0 flex flex-col', 'border-z-border bg-z-panel')}>\n <div className=\"p-4 border-b border-inherit flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold flex items-center gap-2\">\n <Box size={14} className=\"text-z-secondary \" /> Components\n </h2>\n <button\n onClick={handleCreateNew}\n className=\"p-1.5 hover:bg-z-panel text-z-secondary rounded-none transition-colors\"\n >\n <Plus size={14} />\n </button>\n </div>\n <div className=\"flex-1 overflow-auto p-2 space-y-1\">\n {loading ? (\n <div className=\"p-4 flex justify-center\"><Loader2 className=\"animate-spin text-z-muted\" size={16} /></div>\n ) : components.map(c => (\n <div key={c.id} className=\"group flex items-center gap-2 relative\">\n <button\n onClick={() => { setActiveComponent(c); setActiveTab('visual') }}\n className={cn(\n 'flex-1 text-left px-3 py-2 text-sm font-bold transition-colors overflow-hidden text-ellipsis whitespace-nowrap rounded-none',\n activeComponent?.id === c.id\n ? 'bg-z-border text-z-primary'\n : dark ? 'text-z-muted hover:bg-z-hover hover:text-z-primary' : 'text-z-secondary hover:bg-[var(--z-bg-input)] hover:text-z-primary'\n )}\n >\n {c.displayName}\n </button>\n <div className=\"absolute right-2 opacity-0 group-hover:opacity-100 transition-opacity flex items-center gap-1\">\n <button\n onClick={(e) => { e.stopPropagation(); handleDuplicate(c.id) }}\n className=\"p-1 text-z-muted hover:text-z-secondary transition-colors\"\n title=\"Duplicate\"\n >\n <Copy size={12} />\n </button>\n <button\n onClick={(e) => { e.stopPropagation(); handleDelete(c.id) }}\n className=\"p-1 text-z-muted hover:text-red-500 transition-colors\"\n title=\"Delete\"\n >\n <Trash2 size={12} />\n </button>\n </div>\n </div>\n ))}\n {!loading && components.length === 0 && (\n <div className=\"p-4 text-center text-sm text-z-secondary\">\n No components found\n </div>\n )}\n </div>\n </div>\n\n {/* ── Editor Main ────────────────────────────────────────────────── */}\n <div className=\"flex-1 overflow-auto bg-inherit relative custom-editor-scrollbar\">\n {activeComponent ? (\n <motion.div\n initial={{ opacity: 0, y: 10 }}\n animate={{ opacity: 1, y: 0 }}\n className=\"max-w-4xl mx-auto p-8 space-y-6\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between pb-6 border-b border-z-border\">\n <div>\n <div className=\"flex items-center gap-3\">\n <a href=\"/\" className=\"text-z-secondary hover:text-z-primary transition-colors\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"lucide lucide-arrow-left\"><path d=\"m12 19-7-7 7-7\"/><path d=\"M19 12H5\"/></svg>\n </a>\n <h1 className=\"text-2xl font-semibold\">Component Builder</h1>\n </div>\n <p className={cn('text-sm font-bold mt-1 ml-8', 'text-z-secondary')}>\n {activeComponent.id ? 'Editing existing component' : 'Creating new component'}\n </p>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => setShowPreview(!showPreview)}\n className={cn('flex items-center gap-2 px-4 py-2.5 border text-sm font-semibold rounded-none transition-all shadow-sm', dark ? 'bg-z-panel backdrop-blur-md border-z-border hover:border-z-active-border' : 'bg-z-panel border-z-border hover:bg-[var(--z-bg-input)]')}\n >\n {showPreview ? <EyeOff size={14} /> : <Eye size={14} />}\n {showPreview ? 'Hide' : 'Preview'}\n </button>\n <button\n onClick={handleSave}\n disabled={saving}\n className=\"flex items-center gap-2 px-6 py-2.5 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold shadow-sm rounded-none transition-all disabled:opacity-50\"\n >\n {saving ? <Loader2 size={14} className=\"animate-spin\" /> : <Save size={14} />}\n Save Component\n </button>\n </div>\n </div>\n\n {/* Tab navigation */}\n <div className={cn('flex items-center gap-1 p-1 border rounded-none w-fit shadow-sm', 'z-panel')}>\n {([\n { key: 'visual', label: 'Visual Editor', icon: Box },\n { key: 'code', label: 'Code / JSON Import', icon: Code },\n { key: 'ai', label: 'AI Generate', icon: Sparkles },\n ] as { key: EditorTab; label: string; icon: React.ElementType }[]).map(tab => {\n const Icon = tab.icon\n return (\n <button\n key={tab.key}\n onClick={() => setActiveTab(tab.key)}\n className={cn(\n 'flex items-center gap-2 px-4 py-2 text-sm font-semibold rounded-none transition-all',\n activeTab === tab.key\n ? 'bg-z-accent text-z-logo-text shadow-sm'\n : dark ? 'text-z-secondary hover:text-z-secondary' : 'text-z-secondary hover:text-z-primary'\n )}\n >\n <Icon size={12} /> {tab.label}\n </button>\n )\n })}\n </div>\n\n {/* ── Visual Editor ───────────────────────────────────────────── */}\n <AnimatePresence mode=\"wait\">\n {activeTab === 'visual' && (\n <BuilderVisualTab\n activeComponent={activeComponent}\n setActiveComponent={setActiveComponent}\n showPreview={showPreview}\n generateJSON={generateJSON}\n generateTS={generateTS}\n copied={copied}\n setCopied={setCopied}\n dark={dark}\n />\n )}\n\n {/* ── Code / JSON Import Tab ───────────────────────────────── */}\n {activeTab === 'code' && (\n <BuilderCodeTab\n codeImport={codeImport}\n setCodeImport={setCodeImport}\n handleCodeImport={handleCodeImport}\n handleRegisterCode={handleRegisterCode}\n dark={dark}\n />\n )}\n\n {/* ── AI Generate Tab ─────────────────────────────────────── */}\n {activeTab === 'ai' && (\n <BuilderAITab\n aiPrompt={aiPrompt}\n setAiPrompt={setAiPrompt}\n isAIGenerating={isAIGenerating}\n handleAIGenerate={handleAIGenerate}\n dark={dark}\n />\n )}\n </AnimatePresence>\n </motion.div>\n ) : (\n <div className=\"h-full flex items-center justify-center\">\n <div className=\"text-center space-y-5 max-w-md px-8\">\n <div className=\"w-16 h-16 mx-auto rounded-none bg-z-panel border border-z-border flex items-center justify-center shadow-sm\">\n <Box size={28} className=\"text-z-active-text\" strokeWidth={1.5} />\n </div>\n <div className=\"flex items-center justify-center mb-6\">\n <a href=\"/\" className=\"flex items-center gap-2 text-sm font-semibold text-z-secondary hover:text-z-primary transition-colors\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"lucide lucide-arrow-left\"><path d=\"m12 19-7-7 7-7\"/><path d=\"M19 12H5\"/></svg>\n Back to Dashboard\n </a>\n </div>\n <div>\n <p className=\"text-[14px] font-semibold\">Component Builder</p>\n <p className={cn('text-sm font-medium mt-2 leading-relaxed', 'text-z-secondary')}>\n Create reusable components like Navbars, Cards, and Hero Sections to use in Dynamic Zones and Blocks.\n Import from JSON, TypeScript interfaces, or let AI generate them.\n </p>\n </div>\n <div className=\"flex gap-3 justify-center\">\n <button onClick={handleCreateNew} className=\"flex items-center gap-2 px-5 py-3 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all shadow-sm\">\n <Plus size={14} /> New Component\n </button>\n <button onClick={() => { handleCreateNew(); setTimeout(() => setActiveTab('ai'), 50) }} className=\"flex items-center gap-2 px-5 py-3 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold rounded-none transition-all shadow-sm\">\n <Sparkles size={14} /> AI Generate\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n </div>\n )\n}\n\nexport default ComponentBuilderPage\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{$t as t,Ct as n,Dt as r,En as i,Et as a,Gn as o,Jn as s,Ln as c,Lt as ee,Mt as te,Q as l,Rn as u,Wt as d,X as f,_n as p,cr as m,h,ir as ne,mr as re,rr as g,u as _,vr as v,wn as y,xr as b}from"./vendor-react-DQVTOTFO.js";import{a as x,o as S,t as C}from"./utils-fgvbH6CB.js";import{p as ie}from"./index-ChcKY5Xe.js";var w=e(b(),1),T=v(),E=w.memo(function({title:e,icon:t,action:n,children:r,className:i,noPadding:a}){let{theme:o}=x();return(0,T.jsxs)(`div`,{className:C(`flex flex-col border z-panel backdrop-blur-md shadow-sm`,i),style:{background:`var(--z-bg-panel)`,borderColor:`var(--z-border)`},children:[(e||n)&&(0,T.jsxs)(`div`,{className:`flex items-center justify-between px-5 py-4 border-b shrink-0 border-z-border`,children:[(0,T.jsxs)(`div`,{className:`flex items-center gap-2.5`,children:[t&&(0,T.jsx)(`span`,{className:`text-z-secondary`,children:t}),e&&(0,T.jsx)(`h2`,{className:`text-sm font-semibold text-z-secondary`,children:e})]}),n&&(0,T.jsx)(`div`,{children:n})]}),(0,T.jsx)(`div`,{className:C(`flex-1 min-h-0`,!a&&`p-5`),children:r})]})}),D=class extends w.Component{constructor(e){super(e),this.state={hasError:!1}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){console.error(`Widget caught error:`,e,t)}render(){return this.state.hasError?(0,T.jsxs)(`div`,{className:`flex flex-col items-center justify-center p-4 border border-red-500/20 bg-red-500/10 rounded-none min-h-[100px] h-full`,children:[(0,T.jsx)(i,{className:`text-red-500 mb-2`,size:24}),(0,T.jsx)(`span`,{className:`text-xs font-bold text-red-500`,children:`Widget Error`}),(0,T.jsx)(`span`,{className:`text-sm text-red-400 mt-1 truncate max-w-full px-2`,children:this.state.error?.message||`Failed to render`})]}):this.props.children}};function ae(e){let t=Math.floor((Date.now()-new Date(e).getTime())/1e3);return t<60?`${t}s ago`:t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:`${Math.floor(t/86400)}d ago`}function O(e){if(e==null)return`—`;let t=Math.floor(e/86400),n=Math.floor(e%86400/3600),r=Math.floor(e%3600/60),i=Math.floor(e%60);return t>0?`${t}d ${n}h ${r}m`:n>0?`${n}h ${r}m ${i}s`:`${r}m ${i}s`}var oe={create:`text-z-active-text bg-z-active-bg`,update:`text-z-active-text bg-z-active-bg`,delete:`text-rose-400 bg-rose-500/10`,login:`text-sky-400 bg-sky-500/10`,logout:`text-z-muted bg-z-panel`},k=[`bg-z-accent`,`bg-z-accent`,`bg-sky-600`,`bg-amber-600`,`bg-rose-600`,`bg-z-accent`],A=w.memo(function({label:e,value:t,sub:n,icon:r,accent:i,loading:a}){let{theme:o}=x(),s=i===`purple`||i===`emerald`?`text-z-active-text`:i===`red`?`text-rose-400`:`text-z-primary`;return(0,T.jsxs)(`div`,{className:C(`flex flex-col justify-between gap-2 p-5 border transition-colors z-panel backdrop-blur-md shadow-sm`),style:{background:`var(--z-bg-panel)`,borderColor:`var(--z-border)`},children:[(0,T.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,T.jsx)(`span`,{className:`text-sm font-semibold text-z-secondary`,children:e}),(0,T.jsx)(r,{size:13,className:`text-z-secondary`})]}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`span`,{className:C(`text-2xl font-semibold leading-none tabular-nums`,s),children:a?(0,T.jsx)(`span`,{className:`text-z-secondary text-base`,children:`—`}):t}),n&&(0,T.jsx)(`p`,{className:`text-sm text-z-secondary mt-1`,children:n})]})]})});function j({env:e}){if(!e)return null;let t=e===`production`;return(0,T.jsxs)(`span`,{className:C(`inline-flex items-center gap-1.5 px-2.5 py-1 text-sm font-semibold border`,t?`bg-rose-500/10 border-rose-500/20 text-rose-400`:`bg-amber-500/10 border-amber-500/20 text-amber-400`),children:[(0,T.jsx)(`span`,{className:C(`w-1.5 h-1.5 rounded-full`,t?`bg-rose-400 animate-pulse`:`bg-amber-400`)}),e]})}function M(){let{theme:e}=x(),v=re(),[b,M]=(0,w.useState)(null),[N,P]=(0,w.useState)(null),[F,se]=(0,w.useState)([]),[I,ce]=(0,w.useState)(null),[L,le]=(0,w.useState)([]),[R,z]=(0,w.useState)(`—`),[B,V]=(0,w.useState)(null),[H,U]=(0,w.useState)([]),[W,G]=(0,w.useState)(null),[K,q]=(0,w.useState)(null),[J,Y]=(0,w.useState)(!0);(0,w.useEffect)(()=>{let e=setInterval(()=>{M(e=>e&&e.uptime!=null?{...e,uptime:e.uptime+1}:e)},1e3);return()=>clearInterval(e)},[]);let X=(0,w.useCallback)(async()=>{Y(!0);try{let e=performance.now(),t=await Promise.allSettled([S.get(`/system/health`),S.get(`/system/audit-logs?limit=8`),S.get(`/system/audit-logs/stats`),S.get(`/system/schemas`),S.get(`/system/counts`),S.get(`/media?pageSize=1&sort=-createdAt`),S.get(`/presence`)]);t[0].status===`fulfilled`&&(P(Math.round(performance.now()-e)),M(t[0].value.data?.data||null)),t[1].status===`fulfilled`&&se(t[1].value.data?.data||[]),t[2].status===`fulfilled`&&ce(t[2].value.data?.data||null);let n=t[4].status===`fulfilled`&&t[4].value.data?.data||{};if(t[3].status===`fulfilled`){let e=t[3].value.data?.data;le((e?.collections||(Array.isArray(e)?e:[])).map(e=>({name:e.slug||e.name,label:e.label||e.labels?.plural||e.slug||e.name,count:n[e.slug||e.name],drafts:!!e.drafts,icon:e.admin?.icon})));let r=Object.entries(n).filter(([e])=>!e.startsWith(`z_`)).reduce((e,[,t])=>e+t,0);z(r>0?r.toLocaleString():`0`),n.users==null?n.z_users==null?n.members!=null&&G(n.members):G(n.z_users):G(n.users)}if(t[5].status===`fulfilled`){let e=t[5].value.data?.meta?.pagination;V(e?.total??t[5].value.data?.data?.length??null)}t[6].status===`fulfilled`&&U(t[6].value.data?.data||[])}catch{}finally{Y(!1)}},[]);(0,w.useEffect)(()=>{X();let e=setInterval(()=>{let e=performance.now();S.get(`/system/health`).then(t=>{P(Math.round(performance.now()-e)),M(e=>{let n=t.data?.data||null;return e&&n&&n.uptime?{...n,uptime:Math.max(e.uptime,n.uptime)}:n})}).catch(()=>{}),S.get(`/presence`).then(e=>{let t=e.data?.data||[];U(t),G(e=>e===null?t.length:Math.max(e,t.length))}).catch(()=>{})},3e3);return()=>clearInterval(e)},[X]),(0,w.useEffect)(()=>{let e=()=>{S.post(`/presence/heartbeat`,{collection:`dashboard`,documentId:`dashboard`}).catch(()=>{})};e();let t=setInterval(e,3e4);return()=>clearInterval(t)},[]);let Z=b?.status===`ok`,Q=b?.database===`ok`;if(J)return(0,T.jsxs)(`div`,{className:`h-full w-full flex flex-col items-center justify-center gap-4`,children:[(0,T.jsx)(c,{size:26,className:`animate-spin text-z-secondary`,strokeWidth:1.5}),(0,T.jsx)(`p`,{className:`text-sm font-semibold text-z-secondary animate-pulse`,children:`Loading…`})]});let $=e===`dark`?`bg-z-hover hover:bg-z-panel/[0.08] text-z-secondary border border-z-border shadow-sm`:`bg-z-panel/65 backdrop-blur-[12px] hover:bg-z-panel/85 text-z-primary border border-z-border shadow-sm`,ue=[{label:`New Content`,icon:l,path:`/collections`,color:$},{label:`Media Library`,icon:a,path:`/media`,color:$},{label:`API Explorer`,icon:_,path:`/settings?tab=api-explorer`,color:$},{label:`Schema Builder`,icon:u,path:`/schema-builder`,color:$},{label:`API Keys`,icon:n,path:`/settings?tab=keys`,color:$},{label:`Audit Log`,icon:r,path:`/audit-log`,color:$}];return(0,T.jsx)(`div`,{className:`min-h-full transition-colors duration-300`,children:(0,T.jsxs)(`div`,{className:`p-6 space-y-5 max-w-screen-2xl mx-auto`,children:[(0,T.jsx)(ie,{title:`Dashboard`,description:`System overview for your Zenith CMS workspace.`,icon:(0,T.jsx)(y,{size:20}),actions:(0,T.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,T.jsx)(j,{env:b?.environment}),b?.version&&(0,T.jsxs)(`span`,{className:`text-sm font-semibold text-z-secondary`,children:[`v`,b.version]})]})}),(0,T.jsx)(D,{children:(0,T.jsxs)(`div`,{className:`grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3`,children:[(0,T.jsx)(A,{label:`Content Records`,value:R,icon:ee}),(0,T.jsx)(A,{label:`Collections`,value:String(L.length||`—`),icon:d}),(0,T.jsx)(A,{label:`Media Files`,value:B==null?`—`:B.toLocaleString(),icon:a}),(0,T.jsx)(A,{label:`Team Members`,value:W==null?`—`:String(W),sub:H.length>0?`${H.length} online now`:void 0,icon:h}),(0,T.jsx)(A,{label:`API Latency`,value:N==null?`—`:`${N}ms`,sub:b?Z?`System Operational`:`System Degraded`:void 0,icon:f,accent:b?N!=null&&N<300?`emerald`:`red`:void 0}),(0,T.jsx)(A,{label:`Database`,value:b?.database||(b?`Connected`:`—`),sub:Q?`Status: Operational`:`Status: Degraded`,icon:y,accent:b?Q?`emerald`:`red`:void 0})]})}),I&&(0,T.jsx)(D,{children:(0,T.jsxs)(`div`,{className:`grid grid-cols-2 sm:grid-cols-3 gap-3`,children:[(0,T.jsx)(A,{label:`Total Events`,value:I.total.toLocaleString(),icon:r}),(0,T.jsx)(A,{label:`Successful Ops`,value:I.success.toLocaleString(),icon:s,accent:`emerald`}),(0,T.jsx)(A,{label:`Failed Ops`,value:I.failed.toLocaleString(),icon:o,accent:I.failed>0?`red`:void 0})]})}),(0,T.jsx)(E,{title:`Quick Actions`,icon:(0,T.jsx)(_,{size:13}),children:(0,T.jsx)(`div`,{className:`grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-2`,children:ue.map(e=>(0,T.jsxs)(`button`,{onClick:()=>v(e.path),className:C(`flex items-center gap-2.5 px-3 py-2.5 text-sm font-semibold tracking-wide transition-all`,e.color),children:[(0,T.jsx)(e.icon,{size:14}),e.label]},e.label))})}),(0,T.jsxs)(`div`,{className:`grid grid-cols-1 lg:grid-cols-2 gap-5`,children:[(0,T.jsx)(E,{title:`Collections`,icon:(0,T.jsx)(d,{size:13}),noPadding:!0,action:(0,T.jsxs)(m,{to:`/schema-builder`,className:C(`text-sm font-semibold flex items-center gap-1 transition-colors`,e===`dark`?`text-z-secondary hover:text-z-secondary`:`text-z-muted hover:text-z-primary`),children:[`Manage `,(0,T.jsx)(p,{size:11})]}),children:L.length===0?(0,T.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-14 gap-4 px-6`,children:[(0,T.jsx)(d,{size:32,className:`text-z-primary`,strokeWidth:1}),(0,T.jsxs)(`div`,{className:`text-center`,children:[(0,T.jsx)(`p`,{className:`text-sm font-bold text-z-muted`,children:`No collections yet`}),(0,T.jsx)(`p`,{className:`text-sm text-z-secondary mt-1`,children:`Create your first collection to start managing content.`})]}),(0,T.jsx)(m,{to:`/schema-builder`,className:`px-5 py-2.5 bg-z-accent hover:brightness-110 text-z-logo-text text-sm font-semibold transition-colors`,children:`+ Create Collection`})]}):(0,T.jsxs)(`div`,{children:[L.slice(0,8).map(t=>(0,T.jsxs)(m,{to:`/collections/${t.name}`,className:C(`flex items-center justify-between px-5 py-3 group transition-colors border-b last:border-b-0`,e===`dark`?`border-z-border hover:bg-z-hover`:`border-z-border hover:bg-[var(--z-bg-input)]`),children:[(0,T.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,T.jsx)(`div`,{className:C(`w-6 h-6 flex items-center justify-center border text-z-secondary`,e===`dark`?`bg-z-hover border-z-border`:`bg-z-input border-z-border`),children:(0,T.jsx)(u,{size:11})}),(0,T.jsxs)(`div`,{children:[(0,T.jsx)(`span`,{className:C(`text-sm font-bold capitalize`,`text-z-primary`),children:t.label||t.name}),t.drafts&&(0,T.jsx)(`span`,{className:`ml-2 text-sm font-semibold text-amber-500 bg-amber-500/10 px-1.5 py-0.5`,children:`Drafts`})]})]}),(0,T.jsxs)(`div`,{className:`flex items-center gap-3`,children:[t.count!=null&&(0,T.jsx)(`span`,{className:`text-sm font-semibold tabular-nums text-z-secondary`,children:t.count.toLocaleString()}),(0,T.jsx)(p,{size:12,className:C(`transition-transform group-hover:translate-x-0.5`,e===`dark`?`text-z-primary`:`text-z-secondary`)})]})]},t.name)),L.length>8&&(0,T.jsx)(`div`,{className:C(`px-5 py-3 border-t`,`border-z-border`),children:(0,T.jsxs)(m,{to:`/schema-builder`,className:`text-sm font-semibold text-z-secondary hover:text-z-active-text transition-colors`,children:[`+`,L.length-8,` more collections →`]})}),(0,T.jsx)(`div`,{className:C(`px-5 py-3 border-t`,`border-z-border`),children:(0,T.jsxs)(m,{to:`/schema-builder`,className:`flex items-center gap-1.5 text-sm font-semibold text-z-secondary hover:text-z-active-text transition-colors w-fit`,children:[(0,T.jsx)(l,{size:11}),` New Collection`]})})]})}),(0,T.jsx)(E,{title:`Recent Activity`,icon:(0,T.jsx)(r,{size:13}),noPadding:!0,action:(0,T.jsxs)(m,{to:`/audit-log`,className:C(`text-sm font-semibold flex items-center gap-1 transition-colors`,e===`dark`?`text-z-secondary hover:text-z-secondary`:`text-z-muted hover:text-z-primary`),children:[`Full Log `,(0,T.jsx)(p,{size:11})]}),children:F.length===0?(0,T.jsxs)(`div`,{className:`flex flex-col items-center justify-center py-14 gap-2`,children:[(0,T.jsx)(r,{size:28,className:`text-z-primary`,strokeWidth:1}),(0,T.jsx)(`p`,{className:`text-sm text-z-secondary`,children:`No activity recorded yet.`})]}):(0,T.jsx)(`div`,{children:F.map(t=>{let n=t.userEmail||t.user?.email||`System`,r=n===`System`?`SY`:n.slice(0,2).toUpperCase(),i=n.charCodeAt(0)%k.length,a=(t.collectionName||t.collection||`system`).replace(/-/g,` `),o=t.status===`failed`;return(0,T.jsxs)(`div`,{onClick:()=>v(`/audit-log`),className:C(`flex items-center gap-3 px-5 py-3 cursor-pointer transition-colors border-b last:border-b-0`,e===`dark`?`border-z-border hover:bg-z-hover`:`border-z-border hover:bg-[var(--z-bg-input)]`,o&&(e===`dark`?`bg-rose-500/[0.03]`:`bg-rose-50/50`)),children:[(0,T.jsx)(`div`,{className:C(`w-6 h-6 flex items-center justify-center text-z-primary text-sm font-semibold shrink-0`,k[i]),children:r}),(0,T.jsx)(`span`,{className:C(`inline-flex px-1.5 py-0.5 text-sm font-semibold shrink-0`,o?`text-rose-400 bg-rose-500/10`:oe[t.action?.toLowerCase()]||`text-z-muted bg-z-panel`),children:t.action}),(0,T.jsx)(`span`,{className:C(`text-sm font-medium flex-1 truncate capitalize`,e===`dark`?`text-z-muted`:`text-z-secondary`),children:a}),(0,T.jsx)(`span`,{className:`text-sm text-z-secondary shrink-0 tabular-nums`,children:ae(t.timestamp)})]},t._id)})})})]}),(0,T.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-2 gap-5`,children:[(0,T.jsx)(E,{title:`Who's Online`,icon:(0,T.jsx)(h,{size:13}),children:H.length===0?(0,T.jsxs)(`div`,{className:`flex items-center gap-2.5`,children:[(0,T.jsx)(`div`,{className:C(`w-2 h-2 rounded-full`,e===`dark`?`bg-z-border`:`bg-[var(--z-border)]`)}),(0,T.jsx)(`p`,{className:`text-sm text-z-secondary`,children:`No one else is online right now.`})]}):(0,T.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,T.jsx)(`div`,{className:`flex items-center -space-x-2.5`,children:H.map((t,n)=>{let r=(t.email||t.userId||`Unknown`).split(`@`)[0],i=r.slice(0,2).toUpperCase(),a=t.collection?t.collection.replace(/-/g,` `):null,o=t.color||k[n%k.length],s=o.startsWith(`#`),c=a?`Editing ${a}`:`Browsing`;return(0,T.jsxs)(`div`,{className:`relative group cursor-default`,style:{zIndex:K===(t.userId||String(n))?50:H.length-n},onMouseEnter:()=>q(t.userId||String(n)),onMouseLeave:()=>q(null),children:[(0,T.jsx)(`div`,{className:`w-9 h-9 rounded-full flex items-center justify-center text-white text-xs font-bold transition-transform group-hover:-translate-y-1 group-hover:scale-110`,style:{backgroundColor:s?o:void 0,boxShadow:s?`0 0 0 3px ${o}55, 0 0 0 5px ${e===`dark`?`#18181b`:`#fff`}`:`0 0 0 3px var(--z-accent), 0 0 0 5px ${e===`dark`?`#18181b`:`#fff`}`},children:(0,T.jsx)(`span`,{className:C(!s&&o),children:i})}),(0,T.jsx)(`span`,{className:`absolute -bottom-0.5 -right-0.5 w-3 h-3 rounded-full border-2 animate-pulse`,style:{backgroundColor:s?o:`var(--z-accent)`,borderColor:e===`dark`?`#18181b`:`#fff`}}),(0,T.jsx)(ne,{children:K===(t.userId||String(n))&&(0,T.jsxs)(g.div,{initial:{opacity:0,y:5,scale:.95},animate:{opacity:1,y:0,scale:1},exit:{opacity:0,y:5,scale:.95},transition:{duration:.12},className:`absolute top-full mt-3 left-1/2 -translate-x-1/2 z-[999] whitespace-nowrap pointer-events-none`,children:[(0,T.jsxs)(`div`,{className:C(`px-3 py-2 rounded-xl shadow-2xl text-xs font-medium flex items-center gap-2`,e===`dark`?`bg-[#18181b] text-z-primary border border-z-border shadow-black/60`:`bg-white text-z-primary border shadow-lg`),children:[(0,T.jsx)(`div`,{className:`w-2.5 h-2.5 rounded-full shrink-0 animate-pulse`,style:{backgroundColor:s?o:`var(--z-accent)`}}),(0,T.jsx)(`span`,{className:`font-semibold`,children:r}),(0,T.jsx)(`span`,{className:`text-z-muted font-normal border-l border-z-border pl-2`,children:c})]}),(0,T.jsx)(`div`,{className:C(`absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 rotate-45`,e===`dark`?`bg-[#18181b] border-l border-t border-z-border`:`bg-white border-l border-t border-gray-200`)})]})})]},t.userId||n)})}),(0,T.jsxs)(`span`,{className:`text-sm text-z-secondary font-medium`,children:[H.length,` `,H.length===1?`person`:`people`,` online`]})]})}),(0,T.jsx)(E,{title:`System Status`,icon:(0,T.jsx)(te,{size:13}),children:(0,T.jsxs)(`div`,{className:`space-y-3`,children:[[{label:`REST API`,ok:Z,detail:N==null?`Checking…`:`${N}ms latency`},{label:`Database`,ok:Q,detail:b?.database||`Unknown`},{label:`Memory`,ok:!0,detail:b?.memory?.heapUsed?`${b.memory.heapUsed} / ${b.memory.heapTotal} heap`:`—`}].map(e=>(0,T.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,T.jsxs)(`div`,{className:`flex items-center gap-2`,children:[e.ok?(0,T.jsx)(s,{size:13,className:`text-z-active-text shrink-0`}):(0,T.jsx)(i,{size:13,className:`text-rose-400 shrink-0`}),(0,T.jsx)(`span`,{className:C(`text-sm font-bold`,`text-z-secondary`),children:e.label})]}),(0,T.jsx)(`span`,{className:`text-sm text-z-secondary`,children:e.detail})]},e.label)),b?.uptime!=null&&(0,T.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,T.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,T.jsx)(t,{size:13,className:`text-z-secondary shrink-0`}),(0,T.jsx)(`span`,{className:C(`text-sm font-bold`,`text-z-secondary`),children:`Uptime`})]}),(0,T.jsx)(`span`,{className:`text-sm text-z-secondary`,children:O(b.uptime)})]})]})})]})]})})}export{M as default};
|