@hanzo/ui 5.3.43 → 5.5.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/dist/dash/crud.js +2 -0
- package/dist/dash/crud.mjs +2 -0
- package/dist/dash/form.js +2 -0
- package/dist/dash/form.mjs +2 -0
- package/dist/dash/header.js +2 -0
- package/dist/dash/header.mjs +2 -0
- package/dist/dash/index.js +3 -0
- package/dist/dash/index.mjs +3 -0
- package/dist/dash/layout.js +2 -0
- package/dist/dash/layout.mjs +2 -0
- package/dist/dash/sidebar.js +3 -0
- package/dist/dash/sidebar.mjs +3 -0
- package/dist/dash/table.js +2 -0
- package/dist/dash/table.mjs +2 -0
- package/dist/src/dash/crud.d.ts +37 -0
- package/dist/src/dash/crud.d.ts.map +1 -0
- package/dist/src/dash/crud.js +74 -0
- package/dist/src/dash/form.d.ts +52 -0
- package/dist/src/dash/form.d.ts.map +1 -0
- package/dist/src/dash/form.js +90 -0
- package/dist/src/dash/header.d.ts +28 -0
- package/dist/src/dash/header.d.ts.map +1 -0
- package/dist/src/dash/header.js +24 -0
- package/dist/src/dash/index.d.ts +21 -0
- package/dist/src/dash/index.d.ts.map +1 -0
- package/dist/src/dash/index.js +20 -0
- package/dist/src/dash/layout.d.ts +16 -0
- package/dist/src/dash/layout.d.ts.map +1 -0
- package/dist/src/dash/layout.js +8 -0
- package/dist/src/dash/sidebar.d.ts +31 -0
- package/dist/src/dash/sidebar.d.ts.map +1 -0
- package/dist/src/dash/sidebar.js +26 -0
- package/dist/src/dash/table.d.ts +50 -0
- package/dist/src/dash/table.d.ts.map +1 -0
- package/dist/src/dash/table.js +88 -0
- package/package.json +12 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var $=require('react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var $__namespace=/*#__PURE__*/_interopNamespace($);var I=Object.defineProperty;var c=(e,r)=>I(e,"name",{value:r,configurable:true});function n(...e){return tailwindMerge.twMerge(clsx.clsx(e))}c(n,"cn");function Z({columns:e,data:r,rowKey:h,selectable:i=false,selectedKeys:m,onSelectionChange:p,searchable:y=false,searchPlaceholder:b="Search...",totalRows:o,page:u=0,pageSize:P=20,onPageChange:F,onPageSizeChange:D,actions:V,loading:q=false,emptyMessage:d="No data",className:l}){let[a,g]=$__namespace.useState(""),[w,K]=$__namespace.useState(null),z=$__namespace.useMemo(()=>{if(!a)return r;let t=a.toLowerCase();return r.filter(f=>e.some(M=>(M.cell?"":String(f[M.id]??"")).toLowerCase().includes(t)))},[r,a,e]),j=$__namespace.useMemo(()=>{if(!w)return z;let{column:t,direction:f}=w;return [...z].sort((M,T)=>{let H=M[t],Q=T[t];if(H==null&&Q==null)return 0;if(H==null)return 1;if(Q==null)return -1;let Y=String(H).localeCompare(String(Q),void 0,{numeric:true});return f==="asc"?Y:-Y})},[z,w]),O=o??j.length,E=Math.max(1,Math.ceil(O/P)),L=F?j:j.slice(u*P,(u+1)*P),C=m??new Set,W=L.length>0&&L.every(t=>C.has(h(t)));function _(){p&&p(W?new Set:new Set(L.map(h)));}c(_,"toggleAll");function A(t){if(!p)return;let f=new Set(C);f.has(t)?f.delete(t):f.add(t),p(f);}c(A,"toggleRow");function G(t){K(f=>f?.column===t?f.direction==="asc"?{column:t,direction:"desc"}:null:{column:t,direction:"asc"});}c(G,"handleSort");let x=V?[...e,{id:"__actions",header:"",width:"auto"}]:e;return jsxRuntime.jsxs("div",{className:n("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)]",l),children:[(y||i)&&jsxRuntime.jsxs("div",{className:"flex items-center gap-3 border-b border-[var(--dash-border)] px-4 py-3",children:[y&&jsxRuntime.jsx("input",{type:"text",placeholder:b,value:a,onChange:t=>g(t.target.value),className:n("h-8 w-64 max-w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]")}),i&&C.size>0&&jsxRuntime.jsxs("span",{className:"text-xs text-[var(--dash-text-muted)]",children:[C.size," selected"]})]}),jsxRuntime.jsx("div",{className:"overflow-x-auto",children:jsxRuntime.jsxs("table",{className:"w-full text-sm",children:[jsxRuntime.jsx("thead",{children:jsxRuntime.jsxs("tr",{className:"border-b border-[var(--dash-border)]",children:[i&&jsxRuntime.jsx("th",{className:"w-10 px-4 py-2.5",children:jsxRuntime.jsx("input",{type:"checkbox",checked:W,onChange:_,className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),x.map(t=>jsxRuntime.jsx("th",{style:t.width?{width:t.width}:void 0,className:n("px-4 py-2.5 text-[var(--dash-text-dim)] font-medium",t.align==="center"&&"text-center",t.align==="right"&&"text-right",!t.align&&"text-left",t.sortable&&"cursor-pointer select-none hover:text-[var(--dash-text-muted)]"),onClick:t.sortable?()=>G(t.id):void 0,children:jsxRuntime.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.header,t.sortable&&w?.column===t.id&&jsxRuntime.jsx("span",{className:"text-[10px]",children:w.direction==="asc"?"\u2191":"\u2193"})]})},t.id))]})}),jsxRuntime.jsx("tbody",{children:q?jsxRuntime.jsx("tr",{children:jsxRuntime.jsx("td",{colSpan:x.length+(i?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:"Loading..."})}):L.length===0?jsxRuntime.jsx("tr",{children:jsxRuntime.jsx("td",{colSpan:x.length+(i?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:d})}):L.map(t=>{let f=h(t),M=C.has(f);return jsxRuntime.jsxs("tr",{className:n("border-b border-[var(--dash-border)] transition-colors",M?"bg-[var(--dash-surface-active)]":"hover:bg-[var(--dash-surface-hover)]"),children:[i&&jsxRuntime.jsx("td",{className:"w-10 px-4 py-2.5",children:jsxRuntime.jsx("input",{type:"checkbox",checked:M,onChange:()=>A(f),className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),e.map(T=>jsxRuntime.jsx("td",{className:n("px-4 py-2.5",T.align==="center"&&"text-center",T.align==="right"&&"text-right"),children:T.cell?T.cell(t):String(t[T.id]??"")},T.id)),V&&jsxRuntime.jsx("td",{className:"px-4 py-2.5 text-right",children:V(t)})]},f)})})]})}),E>1&&jsxRuntime.jsxs("div",{className:"flex items-center justify-between border-t border-[var(--dash-border)] px-4 py-2.5 text-xs text-[var(--dash-text-muted)]",children:[jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsx("span",{children:"Rows per page"}),jsxRuntime.jsx("select",{value:P,onChange:t=>D?.(Number(t.target.value)),className:"h-7 rounded border border-[var(--dash-border)] bg-[var(--dash-bg)] px-2 text-xs text-[var(--dash-text)] focus:outline-none",children:[10,20,50,100].map(t=>jsxRuntime.jsx("option",{value:t,children:t},t))})]}),jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsxs("span",{children:["Page ",u+1," of ",E]}),jsxRuntime.jsx("button",{type:"button",disabled:u===0,onClick:()=>F?.(u-1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),jsxRuntime.jsx("button",{type:"button",disabled:u>=E-1,onClick:()=>F?.(u+1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})]})}c(Z,"Table");function U({title:e,fields:r,values:h,onSubmit:i,onCancel:m,submitLabel:p="Save",cancelLabel:y="Cancel",loading:b=false,className:o}){let[u,P]=$__namespace.useState(()=>{let d={};for(let l of r)d[l.name]=h?.[l.name]??l.defaultValue??(l.type==="toggle"?false:"");return d}),[F,D]=$__namespace.useState({});function V(d,l){P(a=>({...a,[d]:l})),D(a=>{if(!a[d])return a;let g={...a};return delete g[d],g});}c(V,"setValue");async function q(d){d.preventDefault();let l={};for(let a of r){let g=u[a.name];if(a.required&&(g===""||g===null||g===void 0)&&(l[a.name]=`${a.label} is required`),a.validate){let w=a.validate(g);w&&(l[a.name]=w);}}if(Object.keys(l).length>0){D(l);return}await i(u);}return c(q,"handleSubmit"),jsxRuntime.jsxs("form",{onSubmit:q,className:n("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6",o),children:[e&&jsxRuntime.jsx("h3",{className:"mb-4 text-lg font-semibold text-[var(--dash-text)]",children:e}),jsxRuntime.jsx("div",{className:"space-y-4",children:r.map(d=>jsxRuntime.jsx(re,{field:d,value:u[d.name],error:F[d.name],onChange:l=>V(d.name,l)},d.name))}),jsxRuntime.jsxs("div",{className:"mt-6 flex items-center gap-3",children:[jsxRuntime.jsx("button",{type:"submit",disabled:b,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]","disabled:opacity-50 disabled:cursor-not-allowed"),children:b?"Saving...":p}),m&&jsxRuntime.jsx("button",{type:"button",onClick:m,disabled:b,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:y})]})]})}c(U,"Form");var J=n("w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 py-2 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","disabled:opacity-50 disabled:cursor-not-allowed","transition-colors");function re({field:e,value:r,error:h,onChange:i}){let m=`dash-field-${e.name}`,p=jsxRuntime.jsxs("label",{htmlFor:m,className:"mb-1 block text-sm font-medium text-[var(--dash-text)]",children:[e.label,e.required&&jsxRuntime.jsx("span",{className:"ml-0.5 text-[var(--dash-error)]",children:"*"})]}),y=e.description?jsxRuntime.jsx("p",{className:"mt-1 text-xs text-[var(--dash-text-dim)]",children:e.description}):null,b=h?jsxRuntime.jsx("p",{className:"mt-1 text-xs text-[var(--dash-error)]",children:h}):null;switch(e.type){case "text":case "email":case "password":case "number":return jsxRuntime.jsxs("div",{children:[p,jsxRuntime.jsx("input",{id:m,type:e.type,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,onChange:o=>i(e.type==="number"?Number(o.target.value):o.target.value),className:n(J,h&&"border-[var(--dash-error)]")}),y,b]});case "textarea":return jsxRuntime.jsxs("div",{children:[p,jsxRuntime.jsx("textarea",{id:m,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,rows:e.rows??3,onChange:o=>i(o.target.value),className:n(J,"resize-y",h&&"border-[var(--dash-error)]")}),y,b]});case "select":case "relation":return jsxRuntime.jsxs("div",{children:[p,jsxRuntime.jsxs("select",{id:m,value:String(r??""),disabled:e.disabled,onChange:o=>i(o.target.value),className:n(J,h&&"border-[var(--dash-error)]"),children:[jsxRuntime.jsx("option",{value:"",children:e.placeholder??"Select..."}),(e.options??[]).map(o=>jsxRuntime.jsx("option",{value:o.value,children:o.label},o.value))]}),y,b]});case "toggle":return jsxRuntime.jsxs("div",{className:"flex items-center gap-3",children:[jsxRuntime.jsx("button",{id:m,type:"button",role:"switch","aria-checked":!!r,disabled:e.disabled,onClick:()=>i(!r),className:n("relative inline-flex h-5 w-9 flex-shrink-0 rounded-full transition-colors","focus:outline-none focus:ring-2 focus:ring-[var(--dash-primary)] focus:ring-offset-2 focus:ring-offset-[var(--dash-surface)]",r?"bg-[var(--dash-primary)]":"bg-[var(--dash-border)]",e.disabled&&"opacity-50 cursor-not-allowed"),children:jsxRuntime.jsx("span",{className:n("pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",r?"translate-x-4":"translate-x-0.5","mt-0.5")})}),jsxRuntime.jsx("label",{htmlFor:m,className:"text-sm text-[var(--dash-text)]",children:e.label}),y,b]});case "json":return jsxRuntime.jsxs("div",{children:[p,jsxRuntime.jsx("textarea",{id:m,value:typeof r=="string"?r:JSON.stringify(r,null,2),placeholder:e.placeholder??"{}",disabled:e.disabled,rows:e.rows??6,onChange:o=>{try{i(JSON.parse(o.target.value));}catch{i(o.target.value);}},className:n(J,"font-mono text-xs resize-y",h&&"border-[var(--dash-error)]")}),y,b]});case "file":return jsxRuntime.jsxs("div",{children:[p,jsxRuntime.jsx("input",{id:m,type:"file",accept:e.accept,disabled:e.disabled,onChange:o=>{let u=o.target.files?.[0];u&&i(u);},className:n("w-full text-sm text-[var(--dash-text-muted)]","file:mr-3 file:rounded-[var(--dash-radius-sm)] file:border-0 file:bg-[var(--dash-primary)] file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-[var(--dash-primary-text)]","file:cursor-pointer hover:file:bg-[var(--dash-primary-hover)]")}),y,b]});default:return null}}c(re,"FieldRenderer");function we({resourceName:e,resourceNamePlural:r,columns:h,data:i,rowKey:m,fields:p,rowToValues:y,onCreate:b,onUpdate:o,onDelete:u,canCreate:P=true,canEdit:F=true,canDelete:D=true,tableProps:V,loading:q=false,className:d}){let l=r??`${e}s`,[a,g]=$__namespace.useState("list"),[w,K]=$__namespace.useState(null),[z,j]=$__namespace.useState({}),[O,E]=$__namespace.useState(null),[L,C]=$__namespace.useState(false);function W(x){let t=m(x);K(t),j(y?y(x):x),g("edit");}c(W,"handleEdit");function _(x){E(m(x));}c(_,"handleDeleteConfirm");async function A(){if(!(!O||!u)){C(true);try{await u(O);}finally{C(false),E(null);}}}c(A,"confirmDelete");function G(x){return jsxRuntime.jsxs("div",{className:"flex items-center justify-end gap-1",children:[F&&o&&jsxRuntime.jsx("button",{type:"button",onClick:()=>W(x),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors",children:"Edit"}),D&&u&&jsxRuntime.jsx("button",{type:"button",onClick:()=>_(x),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-error)] hover:bg-[var(--dash-error-dim)] transition-colors",children:"Delete"})]})}return c(G,"actionsRenderer"),a==="list"?jsxRuntime.jsxs("div",{className:n("space-y-4",d),children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between",children:[jsxRuntime.jsx("h2",{className:"text-xl font-semibold text-[var(--dash-text)]",children:l}),P&&b&&jsxRuntime.jsxs("button",{type:"button",onClick:()=>{K(null),j({}),g("create");},className:n("rounded-[var(--dash-radius)] px-3 py-1.5 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]"),children:["Create ",e]})]}),jsxRuntime.jsx(Z,{columns:h,data:i,rowKey:m,actions:F||D?G:void 0,loading:q,searchable:true,emptyMessage:`No ${l.toLowerCase()} found`,...V}),O!==null&&jsxRuntime.jsx(ae,{resourceName:e,loading:L,onConfirm:A,onCancel:()=>E(null)})]}):jsxRuntime.jsxs("div",{className:n("space-y-4",d),children:[jsxRuntime.jsxs("button",{type:"button",onClick:()=>g("list"),className:"inline-flex items-center gap-1 text-sm text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:[jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),"Back to ",l]}),jsxRuntime.jsx(U,{title:a==="create"?`Create ${e}`:`Edit ${e}`,fields:p,values:a==="edit"?z:void 0,loading:L,submitLabel:a==="create"?"Create":"Save changes",onCancel:()=>g("list"),onSubmit:async x=>{C(true);try{a==="create"&&b?await b(x):a==="edit"&&w&&o&&await o(w,x),g("list");}finally{C(false);}}})]})}c(we,"Crud");function ae({resourceName:e,loading:r,onConfirm:h,onCancel:i}){return jsxRuntime.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60",children:jsxRuntime.jsxs("div",{className:"w-full max-w-sm rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6 shadow-lg",children:[jsxRuntime.jsxs("h3",{className:"text-lg font-semibold text-[var(--dash-text)]",children:["Delete ",e,"?"]}),jsxRuntime.jsxs("p",{className:"mt-2 text-sm text-[var(--dash-text-muted)]",children:["This action cannot be undone. The ",e.toLowerCase()," will be permanently removed."]}),jsxRuntime.jsxs("div",{className:"mt-6 flex items-center justify-end gap-3",children:[jsxRuntime.jsx("button",{type:"button",onClick:i,disabled:r,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:"Cancel"}),jsxRuntime.jsx("button",{type:"button",onClick:h,disabled:r,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-error)] text-white","hover:bg-red-600","disabled:opacity-50 disabled:cursor-not-allowed"),children:r?"Deleting...":"Delete"})]})]})})}c(ae,"DeleteDialog");exports.Crud=we;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import*as $ from'react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsxs,jsx}from'react/jsx-runtime';var I=Object.defineProperty;var c=(e,r)=>I(e,"name",{value:r,configurable:true});function n(...e){return twMerge(clsx(e))}c(n,"cn");function Z({columns:e,data:r,rowKey:h,selectable:i=false,selectedKeys:m,onSelectionChange:p,searchable:y=false,searchPlaceholder:b="Search...",totalRows:o,page:u=0,pageSize:P=20,onPageChange:F,onPageSizeChange:D,actions:V,loading:q=false,emptyMessage:d="No data",className:l}){let[a,g]=$.useState(""),[w,K]=$.useState(null),z=$.useMemo(()=>{if(!a)return r;let t=a.toLowerCase();return r.filter(f=>e.some(M=>(M.cell?"":String(f[M.id]??"")).toLowerCase().includes(t)))},[r,a,e]),j=$.useMemo(()=>{if(!w)return z;let{column:t,direction:f}=w;return [...z].sort((M,T)=>{let H=M[t],Q=T[t];if(H==null&&Q==null)return 0;if(H==null)return 1;if(Q==null)return -1;let Y=String(H).localeCompare(String(Q),void 0,{numeric:true});return f==="asc"?Y:-Y})},[z,w]),O=o??j.length,E=Math.max(1,Math.ceil(O/P)),L=F?j:j.slice(u*P,(u+1)*P),C=m??new Set,W=L.length>0&&L.every(t=>C.has(h(t)));function _(){p&&p(W?new Set:new Set(L.map(h)));}c(_,"toggleAll");function A(t){if(!p)return;let f=new Set(C);f.has(t)?f.delete(t):f.add(t),p(f);}c(A,"toggleRow");function G(t){K(f=>f?.column===t?f.direction==="asc"?{column:t,direction:"desc"}:null:{column:t,direction:"asc"});}c(G,"handleSort");let x=V?[...e,{id:"__actions",header:"",width:"auto"}]:e;return jsxs("div",{className:n("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)]",l),children:[(y||i)&&jsxs("div",{className:"flex items-center gap-3 border-b border-[var(--dash-border)] px-4 py-3",children:[y&&jsx("input",{type:"text",placeholder:b,value:a,onChange:t=>g(t.target.value),className:n("h-8 w-64 max-w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]")}),i&&C.size>0&&jsxs("span",{className:"text-xs text-[var(--dash-text-muted)]",children:[C.size," selected"]})]}),jsx("div",{className:"overflow-x-auto",children:jsxs("table",{className:"w-full text-sm",children:[jsx("thead",{children:jsxs("tr",{className:"border-b border-[var(--dash-border)]",children:[i&&jsx("th",{className:"w-10 px-4 py-2.5",children:jsx("input",{type:"checkbox",checked:W,onChange:_,className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),x.map(t=>jsx("th",{style:t.width?{width:t.width}:void 0,className:n("px-4 py-2.5 text-[var(--dash-text-dim)] font-medium",t.align==="center"&&"text-center",t.align==="right"&&"text-right",!t.align&&"text-left",t.sortable&&"cursor-pointer select-none hover:text-[var(--dash-text-muted)]"),onClick:t.sortable?()=>G(t.id):void 0,children:jsxs("span",{className:"inline-flex items-center gap-1",children:[t.header,t.sortable&&w?.column===t.id&&jsx("span",{className:"text-[10px]",children:w.direction==="asc"?"\u2191":"\u2193"})]})},t.id))]})}),jsx("tbody",{children:q?jsx("tr",{children:jsx("td",{colSpan:x.length+(i?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:"Loading..."})}):L.length===0?jsx("tr",{children:jsx("td",{colSpan:x.length+(i?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:d})}):L.map(t=>{let f=h(t),M=C.has(f);return jsxs("tr",{className:n("border-b border-[var(--dash-border)] transition-colors",M?"bg-[var(--dash-surface-active)]":"hover:bg-[var(--dash-surface-hover)]"),children:[i&&jsx("td",{className:"w-10 px-4 py-2.5",children:jsx("input",{type:"checkbox",checked:M,onChange:()=>A(f),className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),e.map(T=>jsx("td",{className:n("px-4 py-2.5",T.align==="center"&&"text-center",T.align==="right"&&"text-right"),children:T.cell?T.cell(t):String(t[T.id]??"")},T.id)),V&&jsx("td",{className:"px-4 py-2.5 text-right",children:V(t)})]},f)})})]})}),E>1&&jsxs("div",{className:"flex items-center justify-between border-t border-[var(--dash-border)] px-4 py-2.5 text-xs text-[var(--dash-text-muted)]",children:[jsxs("div",{className:"flex items-center gap-2",children:[jsx("span",{children:"Rows per page"}),jsx("select",{value:P,onChange:t=>D?.(Number(t.target.value)),className:"h-7 rounded border border-[var(--dash-border)] bg-[var(--dash-bg)] px-2 text-xs text-[var(--dash-text)] focus:outline-none",children:[10,20,50,100].map(t=>jsx("option",{value:t,children:t},t))})]}),jsxs("div",{className:"flex items-center gap-2",children:[jsxs("span",{children:["Page ",u+1," of ",E]}),jsx("button",{type:"button",disabled:u===0,onClick:()=>F?.(u-1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),jsx("button",{type:"button",disabled:u>=E-1,onClick:()=>F?.(u+1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})]})}c(Z,"Table");function U({title:e,fields:r,values:h,onSubmit:i,onCancel:m,submitLabel:p="Save",cancelLabel:y="Cancel",loading:b=false,className:o}){let[u,P]=$.useState(()=>{let d={};for(let l of r)d[l.name]=h?.[l.name]??l.defaultValue??(l.type==="toggle"?false:"");return d}),[F,D]=$.useState({});function V(d,l){P(a=>({...a,[d]:l})),D(a=>{if(!a[d])return a;let g={...a};return delete g[d],g});}c(V,"setValue");async function q(d){d.preventDefault();let l={};for(let a of r){let g=u[a.name];if(a.required&&(g===""||g===null||g===void 0)&&(l[a.name]=`${a.label} is required`),a.validate){let w=a.validate(g);w&&(l[a.name]=w);}}if(Object.keys(l).length>0){D(l);return}await i(u);}return c(q,"handleSubmit"),jsxs("form",{onSubmit:q,className:n("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6",o),children:[e&&jsx("h3",{className:"mb-4 text-lg font-semibold text-[var(--dash-text)]",children:e}),jsx("div",{className:"space-y-4",children:r.map(d=>jsx(re,{field:d,value:u[d.name],error:F[d.name],onChange:l=>V(d.name,l)},d.name))}),jsxs("div",{className:"mt-6 flex items-center gap-3",children:[jsx("button",{type:"submit",disabled:b,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]","disabled:opacity-50 disabled:cursor-not-allowed"),children:b?"Saving...":p}),m&&jsx("button",{type:"button",onClick:m,disabled:b,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:y})]})]})}c(U,"Form");var J=n("w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 py-2 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","disabled:opacity-50 disabled:cursor-not-allowed","transition-colors");function re({field:e,value:r,error:h,onChange:i}){let m=`dash-field-${e.name}`,p=jsxs("label",{htmlFor:m,className:"mb-1 block text-sm font-medium text-[var(--dash-text)]",children:[e.label,e.required&&jsx("span",{className:"ml-0.5 text-[var(--dash-error)]",children:"*"})]}),y=e.description?jsx("p",{className:"mt-1 text-xs text-[var(--dash-text-dim)]",children:e.description}):null,b=h?jsx("p",{className:"mt-1 text-xs text-[var(--dash-error)]",children:h}):null;switch(e.type){case "text":case "email":case "password":case "number":return jsxs("div",{children:[p,jsx("input",{id:m,type:e.type,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,onChange:o=>i(e.type==="number"?Number(o.target.value):o.target.value),className:n(J,h&&"border-[var(--dash-error)]")}),y,b]});case "textarea":return jsxs("div",{children:[p,jsx("textarea",{id:m,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,rows:e.rows??3,onChange:o=>i(o.target.value),className:n(J,"resize-y",h&&"border-[var(--dash-error)]")}),y,b]});case "select":case "relation":return jsxs("div",{children:[p,jsxs("select",{id:m,value:String(r??""),disabled:e.disabled,onChange:o=>i(o.target.value),className:n(J,h&&"border-[var(--dash-error)]"),children:[jsx("option",{value:"",children:e.placeholder??"Select..."}),(e.options??[]).map(o=>jsx("option",{value:o.value,children:o.label},o.value))]}),y,b]});case "toggle":return jsxs("div",{className:"flex items-center gap-3",children:[jsx("button",{id:m,type:"button",role:"switch","aria-checked":!!r,disabled:e.disabled,onClick:()=>i(!r),className:n("relative inline-flex h-5 w-9 flex-shrink-0 rounded-full transition-colors","focus:outline-none focus:ring-2 focus:ring-[var(--dash-primary)] focus:ring-offset-2 focus:ring-offset-[var(--dash-surface)]",r?"bg-[var(--dash-primary)]":"bg-[var(--dash-border)]",e.disabled&&"opacity-50 cursor-not-allowed"),children:jsx("span",{className:n("pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",r?"translate-x-4":"translate-x-0.5","mt-0.5")})}),jsx("label",{htmlFor:m,className:"text-sm text-[var(--dash-text)]",children:e.label}),y,b]});case "json":return jsxs("div",{children:[p,jsx("textarea",{id:m,value:typeof r=="string"?r:JSON.stringify(r,null,2),placeholder:e.placeholder??"{}",disabled:e.disabled,rows:e.rows??6,onChange:o=>{try{i(JSON.parse(o.target.value));}catch{i(o.target.value);}},className:n(J,"font-mono text-xs resize-y",h&&"border-[var(--dash-error)]")}),y,b]});case "file":return jsxs("div",{children:[p,jsx("input",{id:m,type:"file",accept:e.accept,disabled:e.disabled,onChange:o=>{let u=o.target.files?.[0];u&&i(u);},className:n("w-full text-sm text-[var(--dash-text-muted)]","file:mr-3 file:rounded-[var(--dash-radius-sm)] file:border-0 file:bg-[var(--dash-primary)] file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-[var(--dash-primary-text)]","file:cursor-pointer hover:file:bg-[var(--dash-primary-hover)]")}),y,b]});default:return null}}c(re,"FieldRenderer");function we({resourceName:e,resourceNamePlural:r,columns:h,data:i,rowKey:m,fields:p,rowToValues:y,onCreate:b,onUpdate:o,onDelete:u,canCreate:P=true,canEdit:F=true,canDelete:D=true,tableProps:V,loading:q=false,className:d}){let l=r??`${e}s`,[a,g]=$.useState("list"),[w,K]=$.useState(null),[z,j]=$.useState({}),[O,E]=$.useState(null),[L,C]=$.useState(false);function W(x){let t=m(x);K(t),j(y?y(x):x),g("edit");}c(W,"handleEdit");function _(x){E(m(x));}c(_,"handleDeleteConfirm");async function A(){if(!(!O||!u)){C(true);try{await u(O);}finally{C(false),E(null);}}}c(A,"confirmDelete");function G(x){return jsxs("div",{className:"flex items-center justify-end gap-1",children:[F&&o&&jsx("button",{type:"button",onClick:()=>W(x),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors",children:"Edit"}),D&&u&&jsx("button",{type:"button",onClick:()=>_(x),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-error)] hover:bg-[var(--dash-error-dim)] transition-colors",children:"Delete"})]})}return c(G,"actionsRenderer"),a==="list"?jsxs("div",{className:n("space-y-4",d),children:[jsxs("div",{className:"flex items-center justify-between",children:[jsx("h2",{className:"text-xl font-semibold text-[var(--dash-text)]",children:l}),P&&b&&jsxs("button",{type:"button",onClick:()=>{K(null),j({}),g("create");},className:n("rounded-[var(--dash-radius)] px-3 py-1.5 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]"),children:["Create ",e]})]}),jsx(Z,{columns:h,data:i,rowKey:m,actions:F||D?G:void 0,loading:q,searchable:true,emptyMessage:`No ${l.toLowerCase()} found`,...V}),O!==null&&jsx(ae,{resourceName:e,loading:L,onConfirm:A,onCancel:()=>E(null)})]}):jsxs("div",{className:n("space-y-4",d),children:[jsxs("button",{type:"button",onClick:()=>g("list"),className:"inline-flex items-center gap-1 text-sm text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:[jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),"Back to ",l]}),jsx(U,{title:a==="create"?`Create ${e}`:`Edit ${e}`,fields:p,values:a==="edit"?z:void 0,loading:L,submitLabel:a==="create"?"Create":"Save changes",onCancel:()=>g("list"),onSubmit:async x=>{C(true);try{a==="create"&&b?await b(x):a==="edit"&&w&&o&&await o(w,x),g("list");}finally{C(false);}}})]})}c(we,"Crud");function ae({resourceName:e,loading:r,onConfirm:h,onCancel:i}){return jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60",children:jsxs("div",{className:"w-full max-w-sm rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6 shadow-lg",children:[jsxs("h3",{className:"text-lg font-semibold text-[var(--dash-text)]",children:["Delete ",e,"?"]}),jsxs("p",{className:"mt-2 text-sm text-[var(--dash-text-muted)]",children:["This action cannot be undone. The ",e.toLowerCase()," will be permanently removed."]}),jsxs("div",{className:"mt-6 flex items-center justify-end gap-3",children:[jsx("button",{type:"button",onClick:i,disabled:r,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:"Cancel"}),jsx("button",{type:"button",onClick:h,disabled:r,className:n("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-error)] text-white","hover:bg-red-600","disabled:opacity-50 disabled:cursor-not-allowed"),children:r?"Deleting...":"Delete"})]})]})})}c(ae,"DeleteDialog");export{we as Crud};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var f=require('react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var f__namespace=/*#__PURE__*/_interopNamespace(f);var R=Object.defineProperty;var h=(e,a)=>R(e,"name",{value:a,configurable:true});function i(...e){return tailwindMerge.twMerge(clsx.clsx(e))}h(i,"cn");function J({title:e,fields:a,values:m,onSubmit:u,onCancel:l,submitLabel:b="Save",cancelLabel:p="Cancel",loading:d=false,className:r}){let[g,N]=f__namespace.useState(()=>{let s={};for(let o of a)s[o.name]=m?.[o.name]??o.defaultValue??(o.type==="toggle"?false:"");return s}),[k,y]=f__namespace.useState({});function F(s,o){N(n=>({...n,[s]:o})),y(n=>{if(!n[s])return n;let v={...n};return delete v[s],v});}h(F,"setValue");async function S(s){s.preventDefault();let o={};for(let n of a){let v=g[n.name];if(n.required&&(v===""||v===null||v===void 0)&&(o[n.name]=`${n.label} is required`),n.validate){let w=n.validate(v);w&&(o[n.name]=w);}}if(Object.keys(o).length>0){y(o);return}await u(g);}return h(S,"handleSubmit"),jsxRuntime.jsxs("form",{onSubmit:S,className:i("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6",r),children:[e&&jsxRuntime.jsx("h3",{className:"mb-4 text-lg font-semibold text-[var(--dash-text)]",children:e}),jsxRuntime.jsx("div",{className:"space-y-4",children:a.map(s=>jsxRuntime.jsx(E,{field:s,value:g[s.name],error:k[s.name],onChange:o=>F(s.name,o)},s.name))}),jsxRuntime.jsxs("div",{className:"mt-6 flex items-center gap-3",children:[jsxRuntime.jsx("button",{type:"submit",disabled:d,className:i("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]","disabled:opacity-50 disabled:cursor-not-allowed"),children:d?"Saving...":b}),l&&jsxRuntime.jsx("button",{type:"button",onClick:l,disabled:d,className:i("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:p})]})]})}h(J,"Form");var x=i("w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 py-2 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","disabled:opacity-50 disabled:cursor-not-allowed","transition-colors");function E({field:e,value:a,error:m,onChange:u}){let l=`dash-field-${e.name}`,b=jsxRuntime.jsxs("label",{htmlFor:l,className:"mb-1 block text-sm font-medium text-[var(--dash-text)]",children:[e.label,e.required&&jsxRuntime.jsx("span",{className:"ml-0.5 text-[var(--dash-error)]",children:"*"})]}),p=e.description?jsxRuntime.jsx("p",{className:"mt-1 text-xs text-[var(--dash-text-dim)]",children:e.description}):null,d=m?jsxRuntime.jsx("p",{className:"mt-1 text-xs text-[var(--dash-error)]",children:m}):null;switch(e.type){case "text":case "email":case "password":case "number":return jsxRuntime.jsxs("div",{children:[b,jsxRuntime.jsx("input",{id:l,type:e.type,value:String(a??""),placeholder:e.placeholder,disabled:e.disabled,onChange:r=>u(e.type==="number"?Number(r.target.value):r.target.value),className:i(x,m&&"border-[var(--dash-error)]")}),p,d]});case "textarea":return jsxRuntime.jsxs("div",{children:[b,jsxRuntime.jsx("textarea",{id:l,value:String(a??""),placeholder:e.placeholder,disabled:e.disabled,rows:e.rows??3,onChange:r=>u(r.target.value),className:i(x,"resize-y",m&&"border-[var(--dash-error)]")}),p,d]});case "select":case "relation":return jsxRuntime.jsxs("div",{children:[b,jsxRuntime.jsxs("select",{id:l,value:String(a??""),disabled:e.disabled,onChange:r=>u(r.target.value),className:i(x,m&&"border-[var(--dash-error)]"),children:[jsxRuntime.jsx("option",{value:"",children:e.placeholder??"Select..."}),(e.options??[]).map(r=>jsxRuntime.jsx("option",{value:r.value,children:r.label},r.value))]}),p,d]});case "toggle":return jsxRuntime.jsxs("div",{className:"flex items-center gap-3",children:[jsxRuntime.jsx("button",{id:l,type:"button",role:"switch","aria-checked":!!a,disabled:e.disabled,onClick:()=>u(!a),className:i("relative inline-flex h-5 w-9 flex-shrink-0 rounded-full transition-colors","focus:outline-none focus:ring-2 focus:ring-[var(--dash-primary)] focus:ring-offset-2 focus:ring-offset-[var(--dash-surface)]",a?"bg-[var(--dash-primary)]":"bg-[var(--dash-border)]",e.disabled&&"opacity-50 cursor-not-allowed"),children:jsxRuntime.jsx("span",{className:i("pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",a?"translate-x-4":"translate-x-0.5","mt-0.5")})}),jsxRuntime.jsx("label",{htmlFor:l,className:"text-sm text-[var(--dash-text)]",children:e.label}),p,d]});case "json":return jsxRuntime.jsxs("div",{children:[b,jsxRuntime.jsx("textarea",{id:l,value:typeof a=="string"?a:JSON.stringify(a,null,2),placeholder:e.placeholder??"{}",disabled:e.disabled,rows:e.rows??6,onChange:r=>{try{u(JSON.parse(r.target.value));}catch{u(r.target.value);}},className:i(x,"font-mono text-xs resize-y",m&&"border-[var(--dash-error)]")}),p,d]});case "file":return jsxRuntime.jsxs("div",{children:[b,jsxRuntime.jsx("input",{id:l,type:"file",accept:e.accept,disabled:e.disabled,onChange:r=>{let g=r.target.files?.[0];g&&u(g);},className:i("w-full text-sm text-[var(--dash-text-muted)]","file:mr-3 file:rounded-[var(--dash-radius-sm)] file:border-0 file:bg-[var(--dash-primary)] file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-[var(--dash-primary-text)]","file:cursor-pointer hover:file:bg-[var(--dash-primary-hover)]")}),p,d]});default:return null}}h(E,"FieldRenderer");exports.Form=J;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import*as f from'react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsxs,jsx}from'react/jsx-runtime';var R=Object.defineProperty;var h=(e,a)=>R(e,"name",{value:a,configurable:true});function i(...e){return twMerge(clsx(e))}h(i,"cn");function J({title:e,fields:a,values:m,onSubmit:u,onCancel:l,submitLabel:b="Save",cancelLabel:p="Cancel",loading:d=false,className:r}){let[g,N]=f.useState(()=>{let s={};for(let o of a)s[o.name]=m?.[o.name]??o.defaultValue??(o.type==="toggle"?false:"");return s}),[k,y]=f.useState({});function F(s,o){N(n=>({...n,[s]:o})),y(n=>{if(!n[s])return n;let v={...n};return delete v[s],v});}h(F,"setValue");async function S(s){s.preventDefault();let o={};for(let n of a){let v=g[n.name];if(n.required&&(v===""||v===null||v===void 0)&&(o[n.name]=`${n.label} is required`),n.validate){let w=n.validate(v);w&&(o[n.name]=w);}}if(Object.keys(o).length>0){y(o);return}await u(g);}return h(S,"handleSubmit"),jsxs("form",{onSubmit:S,className:i("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6",r),children:[e&&jsx("h3",{className:"mb-4 text-lg font-semibold text-[var(--dash-text)]",children:e}),jsx("div",{className:"space-y-4",children:a.map(s=>jsx(E,{field:s,value:g[s.name],error:k[s.name],onChange:o=>F(s.name,o)},s.name))}),jsxs("div",{className:"mt-6 flex items-center gap-3",children:[jsx("button",{type:"submit",disabled:d,className:i("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]","disabled:opacity-50 disabled:cursor-not-allowed"),children:d?"Saving...":b}),l&&jsx("button",{type:"button",onClick:l,disabled:d,className:i("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:p})]})]})}h(J,"Form");var x=i("w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 py-2 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","disabled:opacity-50 disabled:cursor-not-allowed","transition-colors");function E({field:e,value:a,error:m,onChange:u}){let l=`dash-field-${e.name}`,b=jsxs("label",{htmlFor:l,className:"mb-1 block text-sm font-medium text-[var(--dash-text)]",children:[e.label,e.required&&jsx("span",{className:"ml-0.5 text-[var(--dash-error)]",children:"*"})]}),p=e.description?jsx("p",{className:"mt-1 text-xs text-[var(--dash-text-dim)]",children:e.description}):null,d=m?jsx("p",{className:"mt-1 text-xs text-[var(--dash-error)]",children:m}):null;switch(e.type){case "text":case "email":case "password":case "number":return jsxs("div",{children:[b,jsx("input",{id:l,type:e.type,value:String(a??""),placeholder:e.placeholder,disabled:e.disabled,onChange:r=>u(e.type==="number"?Number(r.target.value):r.target.value),className:i(x,m&&"border-[var(--dash-error)]")}),p,d]});case "textarea":return jsxs("div",{children:[b,jsx("textarea",{id:l,value:String(a??""),placeholder:e.placeholder,disabled:e.disabled,rows:e.rows??3,onChange:r=>u(r.target.value),className:i(x,"resize-y",m&&"border-[var(--dash-error)]")}),p,d]});case "select":case "relation":return jsxs("div",{children:[b,jsxs("select",{id:l,value:String(a??""),disabled:e.disabled,onChange:r=>u(r.target.value),className:i(x,m&&"border-[var(--dash-error)]"),children:[jsx("option",{value:"",children:e.placeholder??"Select..."}),(e.options??[]).map(r=>jsx("option",{value:r.value,children:r.label},r.value))]}),p,d]});case "toggle":return jsxs("div",{className:"flex items-center gap-3",children:[jsx("button",{id:l,type:"button",role:"switch","aria-checked":!!a,disabled:e.disabled,onClick:()=>u(!a),className:i("relative inline-flex h-5 w-9 flex-shrink-0 rounded-full transition-colors","focus:outline-none focus:ring-2 focus:ring-[var(--dash-primary)] focus:ring-offset-2 focus:ring-offset-[var(--dash-surface)]",a?"bg-[var(--dash-primary)]":"bg-[var(--dash-border)]",e.disabled&&"opacity-50 cursor-not-allowed"),children:jsx("span",{className:i("pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",a?"translate-x-4":"translate-x-0.5","mt-0.5")})}),jsx("label",{htmlFor:l,className:"text-sm text-[var(--dash-text)]",children:e.label}),p,d]});case "json":return jsxs("div",{children:[b,jsx("textarea",{id:l,value:typeof a=="string"?a:JSON.stringify(a,null,2),placeholder:e.placeholder??"{}",disabled:e.disabled,rows:e.rows??6,onChange:r=>{try{u(JSON.parse(r.target.value));}catch{u(r.target.value);}},className:i(x,"font-mono text-xs resize-y",m&&"border-[var(--dash-error)]")}),p,d]});case "file":return jsxs("div",{children:[b,jsx("input",{id:l,type:"file",accept:e.accept,disabled:e.disabled,onChange:r=>{let g=r.target.files?.[0];g&&u(g);},className:i("w-full text-sm text-[var(--dash-text-muted)]","file:mr-3 file:rounded-[var(--dash-radius-sm)] file:border-0 file:bg-[var(--dash-primary)] file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-[var(--dash-primary-text)]","file:cursor-pointer hover:file:bg-[var(--dash-primary-hover)]")}),p,d]});default:return null}}h(E,"FieldRenderer");export{J as Form};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var r=require('react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var r__namespace=/*#__PURE__*/_interopNamespace(r);var k=Object.defineProperty;var o=(a,n)=>k(a,"name",{value:n,configurable:true});function v(...a){return tailwindMerge.twMerge(clsx.clsx(a))}o(v,"cn");function W({breadcrumbs:a,searchPlaceholder:n="Search...",onSearch:u,avatarUrl:i,userName:l,userDropdown:m,onToggleTheme:p,theme:f="dark",actions:g,className:b}){let[c,x]=r__namespace.useState(false),h=r__namespace.useRef(null);return r__namespace.useEffect(()=>{if(!c)return;function t(d){h.current&&!h.current.contains(d.target)&&x(false);}return o(t,"handleClick"),document.addEventListener("mousedown",t),()=>document.removeEventListener("mousedown",t)},[c]),jsxRuntime.jsxs("div",{className:v("flex h-[var(--dash-header-height)] items-center gap-4 px-4","bg-[var(--dash-surface)] text-[var(--dash-text)]",b),children:[a&&a.length>0&&jsxRuntime.jsx("nav",{className:"flex items-center gap-1 text-sm","aria-label":"Breadcrumb",children:a.map((t,d)=>jsxRuntime.jsxs(r__namespace.Fragment,{children:[d>0&&jsxRuntime.jsx("span",{className:"text-[var(--dash-text-dim)]",children:"/"}),t.href?jsxRuntime.jsx("a",{href:t.href,className:"text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:t.label}):jsxRuntime.jsx("span",{className:"text-[var(--dash-text)]",children:t.label})]},d))}),jsxRuntime.jsx("div",{className:"flex-1"}),u&&jsxRuntime.jsxs("div",{className:"relative hidden sm:block",children:[jsxRuntime.jsxs("svg",{className:"absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--dash-text-dim)]",width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:[jsxRuntime.jsx("circle",{cx:"7",cy:"7",r:"5.5",stroke:"currentColor",strokeWidth:"1.5"}),jsxRuntime.jsx("path",{d:"M11 11l3 3",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}),jsxRuntime.jsx("input",{type:"text",placeholder:n,onChange:t=>u(t.target.value),className:v("h-8 w-56 rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] pl-8 pr-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","transition-colors")})]}),g,p&&jsxRuntime.jsx("button",{type:"button",onClick:p,className:"rounded-[var(--dash-radius-sm)] p-1.5 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors","aria-label":`Switch to ${f==="dark"?"light":"dark"} mode`,children:f==="dark"?jsxRuntime.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[jsxRuntime.jsx("circle",{cx:"8",cy:"8",r:"3.5",stroke:"currentColor",strokeWidth:"1.5"}),jsxRuntime.jsx("path",{d:"M8 1v2M8 13v2M1 8h2M13 8h2M3.05 3.05l1.41 1.41M11.54 11.54l1.41 1.41M3.05 12.95l1.41-1.41M11.54 4.46l1.41-1.41",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}):jsxRuntime.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M14 9.5A6.5 6.5 0 016.5 2 5.5 5.5 0 1014 9.5z",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),(i||l)&&jsxRuntime.jsxs("div",{className:"relative",ref:h,children:[jsxRuntime.jsx("button",{type:"button",onClick:()=>x(t=>!t),className:"flex items-center gap-2 rounded-[var(--dash-radius-sm)] p-1 hover:bg-[var(--dash-surface-hover)] transition-colors",children:i?jsxRuntime.jsx("img",{src:i,alt:l??"User",className:"h-7 w-7 rounded-full object-cover"}):jsxRuntime.jsx("div",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-[var(--dash-primary)] text-xs font-medium text-[var(--dash-primary-text)]",children:(l??"?")[0].toUpperCase()})}),c&&m&&jsxRuntime.jsx("div",{className:"absolute right-0 top-full z-50 mt-1 min-w-48 rounded-[var(--dash-radius)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 shadow-lg",children:m})]})]})}o(W,"Header");exports.Header=W;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import*as r from'react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsxs,jsx}from'react/jsx-runtime';var k=Object.defineProperty;var o=(a,n)=>k(a,"name",{value:n,configurable:true});function v(...a){return twMerge(clsx(a))}o(v,"cn");function W({breadcrumbs:a,searchPlaceholder:n="Search...",onSearch:u,avatarUrl:i,userName:l,userDropdown:m,onToggleTheme:p,theme:f="dark",actions:g,className:b}){let[c,x]=r.useState(false),h=r.useRef(null);return r.useEffect(()=>{if(!c)return;function t(d){h.current&&!h.current.contains(d.target)&&x(false);}return o(t,"handleClick"),document.addEventListener("mousedown",t),()=>document.removeEventListener("mousedown",t)},[c]),jsxs("div",{className:v("flex h-[var(--dash-header-height)] items-center gap-4 px-4","bg-[var(--dash-surface)] text-[var(--dash-text)]",b),children:[a&&a.length>0&&jsx("nav",{className:"flex items-center gap-1 text-sm","aria-label":"Breadcrumb",children:a.map((t,d)=>jsxs(r.Fragment,{children:[d>0&&jsx("span",{className:"text-[var(--dash-text-dim)]",children:"/"}),t.href?jsx("a",{href:t.href,className:"text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:t.label}):jsx("span",{className:"text-[var(--dash-text)]",children:t.label})]},d))}),jsx("div",{className:"flex-1"}),u&&jsxs("div",{className:"relative hidden sm:block",children:[jsxs("svg",{className:"absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--dash-text-dim)]",width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:[jsx("circle",{cx:"7",cy:"7",r:"5.5",stroke:"currentColor",strokeWidth:"1.5"}),jsx("path",{d:"M11 11l3 3",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}),jsx("input",{type:"text",placeholder:n,onChange:t=>u(t.target.value),className:v("h-8 w-56 rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] pl-8 pr-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","transition-colors")})]}),g,p&&jsx("button",{type:"button",onClick:p,className:"rounded-[var(--dash-radius-sm)] p-1.5 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors","aria-label":`Switch to ${f==="dark"?"light":"dark"} mode`,children:f==="dark"?jsxs("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[jsx("circle",{cx:"8",cy:"8",r:"3.5",stroke:"currentColor",strokeWidth:"1.5"}),jsx("path",{d:"M8 1v2M8 13v2M1 8h2M13 8h2M3.05 3.05l1.41 1.41M11.54 11.54l1.41 1.41M3.05 12.95l1.41-1.41M11.54 4.46l1.41-1.41",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}):jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M14 9.5A6.5 6.5 0 016.5 2 5.5 5.5 0 1014 9.5z",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),(i||l)&&jsxs("div",{className:"relative",ref:h,children:[jsx("button",{type:"button",onClick:()=>x(t=>!t),className:"flex items-center gap-2 rounded-[var(--dash-radius-sm)] p-1 hover:bg-[var(--dash-surface-hover)] transition-colors",children:i?jsx("img",{src:i,alt:l??"User",className:"h-7 w-7 rounded-full object-cover"}):jsx("div",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-[var(--dash-primary)] text-xs font-medium text-[var(--dash-primary-text)]",children:(l??"?")[0].toUpperCase()})}),c&&m&&jsx("div",{className:"absolute right-0 top-full z-50 mt-1 min-w-48 rounded-[var(--dash-radius)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 shadow-lg",children:m})]})]})}o(W,"Header");export{W as Header};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime'),q=require('react');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var q__namespace=/*#__PURE__*/_interopNamespace(q);var ie=Object.defineProperty;var i=(e,r)=>ie(e,"name",{value:r,configurable:true});function a(...e){return tailwindMerge.twMerge(clsx.clsx(e))}i(a,"cn");function ce({sidebar:e,header:r,children:l,sidebarCollapsed:s=false,onSidebarCollapse:n,className:c}){return jsxRuntime.jsxs("div",{className:a("flex h-screen overflow-hidden","bg-[var(--dash-bg)] text-[var(--dash-text)]",c),children:[jsxRuntime.jsx("aside",{className:a("flex-shrink-0 overflow-y-auto overflow-x-hidden transition-[width] duration-200","border-r border-[var(--dash-border)] bg-[var(--dash-surface)]",s?"w-[var(--dash-sidebar-collapsed-width)]":"w-[var(--dash-sidebar-width)]"),children:e}),jsxRuntime.jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[r&&jsxRuntime.jsx("header",{className:"flex-shrink-0 border-b border-[var(--dash-border)] bg-[var(--dash-surface)]",children:r}),jsxRuntime.jsx("main",{className:"flex-1 overflow-y-auto p-6",children:l})]}),!s&&jsxRuntime.jsx("div",{className:"fixed inset-0 z-40 bg-black/60 lg:hidden",onClick:()=>n?.(true)})]})}i(ce,"Layout");function ue({size:e=28}){return jsxRuntime.jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsxRuntime.jsx("path",{d:"M4 4h4v6h8V4h4v16h-4v-6H8v6H4V4z",fill:"currentColor"})})}i(ue,"HanzoMark");function he({logo:e,groups:r,userMenu:l,collapsed:s=false,onToggleCollapse:n,onNavigate:c,className:o}){return jsxRuntime.jsxs("nav",{className:a("flex h-full flex-col","bg-[var(--dash-surface)] text-[var(--dash-text)]",o),children:[jsxRuntime.jsxs("div",{className:a("flex h-[var(--dash-header-height)] items-center border-b border-[var(--dash-border)]",s?"justify-center px-2":"px-4"),children:[e??jsxRuntime.jsx(ue,{}),!s&&n&&jsxRuntime.jsx("button",{type:"button",onClick:n,className:"ml-auto rounded p-1 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]","aria-label":"Collapse sidebar",children:jsxRuntime.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),s&&n&&jsxRuntime.jsx("button",{type:"button",onClick:n,className:"absolute -right-3 top-4 z-50 hidden rounded-full border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 text-[var(--dash-text-dim)] hover:text-[var(--dash-text)] lg:flex","aria-label":"Expand sidebar",children:jsxRuntime.jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]}),jsxRuntime.jsx("div",{className:"flex-1 overflow-y-auto py-2",children:r.map((m,d)=>jsxRuntime.jsx(me,{group:m,collapsed:s,onNavigate:c},d))}),l&&jsxRuntime.jsx("div",{className:"border-t border-[var(--dash-border)] p-2",children:l})]})}i(he,"Sidebar");function me({group:e,collapsed:r,onNavigate:l}){let[s,n]=q__namespace.useState(e.defaultOpen!==false),c=e.collapsible!==false&&!!e.title;return jsxRuntime.jsxs("div",{className:"mb-1",children:[e.title&&!r&&jsxRuntime.jsxs("button",{type:"button",onClick:()=>c&&n(o=>!o),className:a("flex w-full items-center px-4 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-[var(--dash-text-dim)]",c&&"cursor-pointer hover:text-[var(--dash-text-muted)]"),children:[jsxRuntime.jsx("span",{className:"flex-1 text-left",children:e.title}),c&&jsxRuntime.jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",className:a("transition-transform",s?"rotate-0":"-rotate-90"),children:jsxRuntime.jsx("path",{d:"M4 6l4 4 4-4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),(s||r)&&jsxRuntime.jsx("ul",{className:"space-y-0.5 px-2",children:e.items.map(o=>jsxRuntime.jsx("li",{children:jsxRuntime.jsxs("button",{type:"button",onClick:()=>l?.(o.href),title:r?o.label:void 0,className:a("flex w-full items-center gap-2 rounded-[var(--dash-radius-sm)] px-2 py-1.5 text-sm transition-colors",o.active?"bg-[var(--dash-primary)] text-[var(--dash-primary-text)]":"text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]",r&&"justify-center px-0"),children:[o.icon&&jsxRuntime.jsx("span",{className:"flex h-5 w-5 items-center justify-center flex-shrink-0",children:o.icon}),!r&&jsxRuntime.jsx("span",{className:"flex-1 truncate text-left",children:o.label}),!r&&o.badge!==void 0&&jsxRuntime.jsx("span",{className:"ml-auto rounded-full bg-[var(--dash-primary)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--dash-primary-text)]",children:o.badge})]})},o.href))})]})}i(me,"SidebarGroup");function ve({breadcrumbs:e,searchPlaceholder:r="Search...",onSearch:l,avatarUrl:s,userName:n,userDropdown:c,onToggleTheme:o,theme:m="dark",actions:d,className:v}){let[C,R]=q__namespace.useState(false),S=q__namespace.useRef(null);return q__namespace.useEffect(()=>{if(!C)return;function b(M){S.current&&!S.current.contains(M.target)&&R(false);}return i(b,"handleClick"),document.addEventListener("mousedown",b),()=>document.removeEventListener("mousedown",b)},[C]),jsxRuntime.jsxs("div",{className:a("flex h-[var(--dash-header-height)] items-center gap-4 px-4","bg-[var(--dash-surface)] text-[var(--dash-text)]",v),children:[e&&e.length>0&&jsxRuntime.jsx("nav",{className:"flex items-center gap-1 text-sm","aria-label":"Breadcrumb",children:e.map((b,M)=>jsxRuntime.jsxs(q__namespace.Fragment,{children:[M>0&&jsxRuntime.jsx("span",{className:"text-[var(--dash-text-dim)]",children:"/"}),b.href?jsxRuntime.jsx("a",{href:b.href,className:"text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:b.label}):jsxRuntime.jsx("span",{className:"text-[var(--dash-text)]",children:b.label})]},M))}),jsxRuntime.jsx("div",{className:"flex-1"}),l&&jsxRuntime.jsxs("div",{className:"relative hidden sm:block",children:[jsxRuntime.jsxs("svg",{className:"absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--dash-text-dim)]",width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:[jsxRuntime.jsx("circle",{cx:"7",cy:"7",r:"5.5",stroke:"currentColor",strokeWidth:"1.5"}),jsxRuntime.jsx("path",{d:"M11 11l3 3",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}),jsxRuntime.jsx("input",{type:"text",placeholder:r,onChange:b=>l(b.target.value),className:a("h-8 w-56 rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] pl-8 pr-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","transition-colors")})]}),d,o&&jsxRuntime.jsx("button",{type:"button",onClick:o,className:"rounded-[var(--dash-radius-sm)] p-1.5 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors","aria-label":`Switch to ${m==="dark"?"light":"dark"} mode`,children:m==="dark"?jsxRuntime.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[jsxRuntime.jsx("circle",{cx:"8",cy:"8",r:"3.5",stroke:"currentColor",strokeWidth:"1.5"}),jsxRuntime.jsx("path",{d:"M8 1v2M8 13v2M1 8h2M13 8h2M3.05 3.05l1.41 1.41M11.54 11.54l1.41 1.41M3.05 12.95l1.41-1.41M11.54 4.46l1.41-1.41",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}):jsxRuntime.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M14 9.5A6.5 6.5 0 016.5 2 5.5 5.5 0 1014 9.5z",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),(s||n)&&jsxRuntime.jsxs("div",{className:"relative",ref:S,children:[jsxRuntime.jsx("button",{type:"button",onClick:()=>R(b=>!b),className:"flex items-center gap-2 rounded-[var(--dash-radius-sm)] p-1 hover:bg-[var(--dash-surface-hover)] transition-colors",children:s?jsxRuntime.jsx("img",{src:s,alt:n??"User",className:"h-7 w-7 rounded-full object-cover"}):jsxRuntime.jsx("div",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-[var(--dash-primary)] text-xs font-medium text-[var(--dash-primary-text)]",children:(n??"?")[0].toUpperCase()})}),C&&c&&jsxRuntime.jsx("div",{className:"absolute right-0 top-full z-50 mt-1 min-w-48 rounded-[var(--dash-radius)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 shadow-lg",children:c})]})]})}i(ve,"Header");function te({columns:e,data:r,rowKey:l,selectable:s=false,selectedKeys:n,onSelectionChange:c,searchable:o=false,searchPlaceholder:m="Search...",totalRows:d,page:v=0,pageSize:C=20,onPageChange:R,onPageSizeChange:S,actions:b,loading:M=false,emptyMessage:f="No data",className:x}){let[u,w]=q__namespace.useState(""),[L,A]=q__namespace.useState(null),G=q__namespace.useMemo(()=>{if(!u)return r;let t=u.toLowerCase();return r.filter(k=>e.some(O=>(O.cell?"":String(k[O.id]??"")).toLowerCase().includes(t)))},[r,u,e]),W=q__namespace.useMemo(()=>{if(!L)return G;let{column:t,direction:k}=L;return [...G].sort((O,E)=>{let Z=O[t],ee=E[t];if(Z==null&&ee==null)return 0;if(Z==null)return 1;if(ee==null)return -1;let se=String(Z).localeCompare(String(ee),void 0,{numeric:true});return k==="asc"?se:-se})},[G,L]),I=d??W.length,z=Math.max(1,Math.ceil(I/C)),j=R?W:W.slice(v*C,(v+1)*C),F=n??new Set,J=j.length>0&&j.every(t=>F.has(l(t)));function U(){c&&c(J?new Set:new Set(j.map(l)));}i(U,"toggleAll");function X(t){if(!c)return;let k=new Set(F);k.has(t)?k.delete(t):k.add(t),c(k);}i(X,"toggleRow");function Y(t){A(k=>k?.column===t?k.direction==="asc"?{column:t,direction:"desc"}:null:{column:t,direction:"asc"});}i(Y,"handleSort");let N=b?[...e,{id:"__actions",header:"",width:"auto"}]:e;return jsxRuntime.jsxs("div",{className:a("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)]",x),children:[(o||s)&&jsxRuntime.jsxs("div",{className:"flex items-center gap-3 border-b border-[var(--dash-border)] px-4 py-3",children:[o&&jsxRuntime.jsx("input",{type:"text",placeholder:m,value:u,onChange:t=>w(t.target.value),className:a("h-8 w-64 max-w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]")}),s&&F.size>0&&jsxRuntime.jsxs("span",{className:"text-xs text-[var(--dash-text-muted)]",children:[F.size," selected"]})]}),jsxRuntime.jsx("div",{className:"overflow-x-auto",children:jsxRuntime.jsxs("table",{className:"w-full text-sm",children:[jsxRuntime.jsx("thead",{children:jsxRuntime.jsxs("tr",{className:"border-b border-[var(--dash-border)]",children:[s&&jsxRuntime.jsx("th",{className:"w-10 px-4 py-2.5",children:jsxRuntime.jsx("input",{type:"checkbox",checked:J,onChange:U,className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),N.map(t=>jsxRuntime.jsx("th",{style:t.width?{width:t.width}:void 0,className:a("px-4 py-2.5 text-[var(--dash-text-dim)] font-medium",t.align==="center"&&"text-center",t.align==="right"&&"text-right",!t.align&&"text-left",t.sortable&&"cursor-pointer select-none hover:text-[var(--dash-text-muted)]"),onClick:t.sortable?()=>Y(t.id):void 0,children:jsxRuntime.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.header,t.sortable&&L?.column===t.id&&jsxRuntime.jsx("span",{className:"text-[10px]",children:L.direction==="asc"?"\u2191":"\u2193"})]})},t.id))]})}),jsxRuntime.jsx("tbody",{children:M?jsxRuntime.jsx("tr",{children:jsxRuntime.jsx("td",{colSpan:N.length+(s?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:"Loading..."})}):j.length===0?jsxRuntime.jsx("tr",{children:jsxRuntime.jsx("td",{colSpan:N.length+(s?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:f})}):j.map(t=>{let k=l(t),O=F.has(k);return jsxRuntime.jsxs("tr",{className:a("border-b border-[var(--dash-border)] transition-colors",O?"bg-[var(--dash-surface-active)]":"hover:bg-[var(--dash-surface-hover)]"),children:[s&&jsxRuntime.jsx("td",{className:"w-10 px-4 py-2.5",children:jsxRuntime.jsx("input",{type:"checkbox",checked:O,onChange:()=>X(k),className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),e.map(E=>jsxRuntime.jsx("td",{className:a("px-4 py-2.5",E.align==="center"&&"text-center",E.align==="right"&&"text-right"),children:E.cell?E.cell(t):String(t[E.id]??"")},E.id)),b&&jsxRuntime.jsx("td",{className:"px-4 py-2.5 text-right",children:b(t)})]},k)})})]})}),z>1&&jsxRuntime.jsxs("div",{className:"flex items-center justify-between border-t border-[var(--dash-border)] px-4 py-2.5 text-xs text-[var(--dash-text-muted)]",children:[jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsx("span",{children:"Rows per page"}),jsxRuntime.jsx("select",{value:C,onChange:t=>S?.(Number(t.target.value)),className:"h-7 rounded border border-[var(--dash-border)] bg-[var(--dash-bg)] px-2 text-xs text-[var(--dash-text)] focus:outline-none",children:[10,20,50,100].map(t=>jsxRuntime.jsx("option",{value:t,children:t},t))})]}),jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsxs("span",{children:["Page ",v+1," of ",z]}),jsxRuntime.jsx("button",{type:"button",disabled:v===0,onClick:()=>R?.(v-1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),jsxRuntime.jsx("button",{type:"button",disabled:v>=z-1,onClick:()=>R?.(v+1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})]})}i(te,"Table");function ae({title:e,fields:r,values:l,onSubmit:s,onCancel:n,submitLabel:c="Save",cancelLabel:o="Cancel",loading:m=false,className:d}){let[v,C]=q__namespace.useState(()=>{let f={};for(let x of r)f[x.name]=l?.[x.name]??x.defaultValue??(x.type==="toggle"?false:"");return f}),[R,S]=q__namespace.useState({});function b(f,x){C(u=>({...u,[f]:x})),S(u=>{if(!u[f])return u;let w={...u};return delete w[f],w});}i(b,"setValue");async function M(f){f.preventDefault();let x={};for(let u of r){let w=v[u.name];if(u.required&&(w===""||w===null||w===void 0)&&(x[u.name]=`${u.label} is required`),u.validate){let L=u.validate(w);L&&(x[u.name]=L);}}if(Object.keys(x).length>0){S(x);return}await s(v);}return i(M,"handleSubmit"),jsxRuntime.jsxs("form",{onSubmit:M,className:a("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6",d),children:[e&&jsxRuntime.jsx("h3",{className:"mb-4 text-lg font-semibold text-[var(--dash-text)]",children:e}),jsxRuntime.jsx("div",{className:"space-y-4",children:r.map(f=>jsxRuntime.jsx(pe,{field:f,value:v[f.name],error:R[f.name],onChange:x=>b(f.name,x)},f.name))}),jsxRuntime.jsxs("div",{className:"mt-6 flex items-center gap-3",children:[jsxRuntime.jsx("button",{type:"submit",disabled:m,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]","disabled:opacity-50 disabled:cursor-not-allowed"),children:m?"Saving...":c}),n&&jsxRuntime.jsx("button",{type:"button",onClick:n,disabled:m,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:o})]})]})}i(ae,"Form");var Q=a("w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 py-2 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","disabled:opacity-50 disabled:cursor-not-allowed","transition-colors");function pe({field:e,value:r,error:l,onChange:s}){let n=`dash-field-${e.name}`,c=jsxRuntime.jsxs("label",{htmlFor:n,className:"mb-1 block text-sm font-medium text-[var(--dash-text)]",children:[e.label,e.required&&jsxRuntime.jsx("span",{className:"ml-0.5 text-[var(--dash-error)]",children:"*"})]}),o=e.description?jsxRuntime.jsx("p",{className:"mt-1 text-xs text-[var(--dash-text-dim)]",children:e.description}):null,m=l?jsxRuntime.jsx("p",{className:"mt-1 text-xs text-[var(--dash-error)]",children:l}):null;switch(e.type){case "text":case "email":case "password":case "number":return jsxRuntime.jsxs("div",{children:[c,jsxRuntime.jsx("input",{id:n,type:e.type,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,onChange:d=>s(e.type==="number"?Number(d.target.value):d.target.value),className:a(Q,l&&"border-[var(--dash-error)]")}),o,m]});case "textarea":return jsxRuntime.jsxs("div",{children:[c,jsxRuntime.jsx("textarea",{id:n,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,rows:e.rows??3,onChange:d=>s(d.target.value),className:a(Q,"resize-y",l&&"border-[var(--dash-error)]")}),o,m]});case "select":case "relation":return jsxRuntime.jsxs("div",{children:[c,jsxRuntime.jsxs("select",{id:n,value:String(r??""),disabled:e.disabled,onChange:d=>s(d.target.value),className:a(Q,l&&"border-[var(--dash-error)]"),children:[jsxRuntime.jsx("option",{value:"",children:e.placeholder??"Select..."}),(e.options??[]).map(d=>jsxRuntime.jsx("option",{value:d.value,children:d.label},d.value))]}),o,m]});case "toggle":return jsxRuntime.jsxs("div",{className:"flex items-center gap-3",children:[jsxRuntime.jsx("button",{id:n,type:"button",role:"switch","aria-checked":!!r,disabled:e.disabled,onClick:()=>s(!r),className:a("relative inline-flex h-5 w-9 flex-shrink-0 rounded-full transition-colors","focus:outline-none focus:ring-2 focus:ring-[var(--dash-primary)] focus:ring-offset-2 focus:ring-offset-[var(--dash-surface)]",r?"bg-[var(--dash-primary)]":"bg-[var(--dash-border)]",e.disabled&&"opacity-50 cursor-not-allowed"),children:jsxRuntime.jsx("span",{className:a("pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",r?"translate-x-4":"translate-x-0.5","mt-0.5")})}),jsxRuntime.jsx("label",{htmlFor:n,className:"text-sm text-[var(--dash-text)]",children:e.label}),o,m]});case "json":return jsxRuntime.jsxs("div",{children:[c,jsxRuntime.jsx("textarea",{id:n,value:typeof r=="string"?r:JSON.stringify(r,null,2),placeholder:e.placeholder??"{}",disabled:e.disabled,rows:e.rows??6,onChange:d=>{try{s(JSON.parse(d.target.value));}catch{s(d.target.value);}},className:a(Q,"font-mono text-xs resize-y",l&&"border-[var(--dash-error)]")}),o,m]});case "file":return jsxRuntime.jsxs("div",{children:[c,jsxRuntime.jsx("input",{id:n,type:"file",accept:e.accept,disabled:e.disabled,onChange:d=>{let v=d.target.files?.[0];v&&s(v);},className:a("w-full text-sm text-[var(--dash-text-muted)]","file:mr-3 file:rounded-[var(--dash-radius-sm)] file:border-0 file:bg-[var(--dash-primary)] file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-[var(--dash-primary-text)]","file:cursor-pointer hover:file:bg-[var(--dash-primary-hover)]")}),o,m]});default:return null}}i(pe,"FieldRenderer");function be({resourceName:e,resourceNamePlural:r,columns:l,data:s,rowKey:n,fields:c,rowToValues:o,onCreate:m,onUpdate:d,onDelete:v,canCreate:C=true,canEdit:R=true,canDelete:S=true,tableProps:b,loading:M=false,className:f}){let x=r??`${e}s`,[u,w]=q__namespace.useState("list"),[L,A]=q__namespace.useState(null),[G,W]=q__namespace.useState({}),[I,z]=q__namespace.useState(null),[j,F]=q__namespace.useState(false);function J(N){let t=n(N);A(t),W(o?o(N):N),w("edit");}i(J,"handleEdit");function U(N){z(n(N));}i(U,"handleDeleteConfirm");async function X(){if(!(!I||!v)){F(true);try{await v(I);}finally{F(false),z(null);}}}i(X,"confirmDelete");function Y(N){return jsxRuntime.jsxs("div",{className:"flex items-center justify-end gap-1",children:[R&&d&&jsxRuntime.jsx("button",{type:"button",onClick:()=>J(N),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors",children:"Edit"}),S&&v&&jsxRuntime.jsx("button",{type:"button",onClick:()=>U(N),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-error)] hover:bg-[var(--dash-error-dim)] transition-colors",children:"Delete"})]})}return i(Y,"actionsRenderer"),u==="list"?jsxRuntime.jsxs("div",{className:a("space-y-4",f),children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between",children:[jsxRuntime.jsx("h2",{className:"text-xl font-semibold text-[var(--dash-text)]",children:x}),C&&m&&jsxRuntime.jsxs("button",{type:"button",onClick:()=>{A(null),W({}),w("create");},className:a("rounded-[var(--dash-radius)] px-3 py-1.5 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]"),children:["Create ",e]})]}),jsxRuntime.jsx(te,{columns:l,data:s,rowKey:n,actions:R||S?Y:void 0,loading:M,searchable:true,emptyMessage:`No ${x.toLowerCase()} found`,...b}),I!==null&&jsxRuntime.jsx(fe,{resourceName:e,loading:j,onConfirm:X,onCancel:()=>z(null)})]}):jsxRuntime.jsxs("div",{className:a("space-y-4",f),children:[jsxRuntime.jsxs("button",{type:"button",onClick:()=>w("list"),className:"inline-flex items-center gap-1 text-sm text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:[jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),"Back to ",x]}),jsxRuntime.jsx(ae,{title:u==="create"?`Create ${e}`:`Edit ${e}`,fields:c,values:u==="edit"?G:void 0,loading:j,submitLabel:u==="create"?"Create":"Save changes",onCancel:()=>w("list"),onSubmit:async N=>{F(true);try{u==="create"&&m?await m(N):u==="edit"&&L&&d&&await d(L,N),w("list");}finally{F(false);}}})]})}i(be,"Crud");function fe({resourceName:e,loading:r,onConfirm:l,onCancel:s}){return jsxRuntime.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60",children:jsxRuntime.jsxs("div",{className:"w-full max-w-sm rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6 shadow-lg",children:[jsxRuntime.jsxs("h3",{className:"text-lg font-semibold text-[var(--dash-text)]",children:["Delete ",e,"?"]}),jsxRuntime.jsxs("p",{className:"mt-2 text-sm text-[var(--dash-text-muted)]",children:["This action cannot be undone. The ",e.toLowerCase()," will be permanently removed."]}),jsxRuntime.jsxs("div",{className:"mt-6 flex items-center justify-end gap-3",children:[jsxRuntime.jsx("button",{type:"button",onClick:s,disabled:r,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:"Cancel"}),jsxRuntime.jsx("button",{type:"button",onClick:l,disabled:r,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-error)] text-white","hover:bg-red-600","disabled:opacity-50 disabled:cursor-not-allowed"),children:r?"Deleting...":"Delete"})]})]})})}i(fe,"DeleteDialog");
|
|
3
|
+
exports.Crud=be;exports.Form=ae;exports.Header=ve;exports.Layout=ce;exports.Sidebar=he;exports.Table=te;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsxs,jsx}from'react/jsx-runtime';import*as q from'react';var ie=Object.defineProperty;var i=(e,r)=>ie(e,"name",{value:r,configurable:true});function a(...e){return twMerge(clsx(e))}i(a,"cn");function ce({sidebar:e,header:r,children:l,sidebarCollapsed:s=false,onSidebarCollapse:n,className:c}){return jsxs("div",{className:a("flex h-screen overflow-hidden","bg-[var(--dash-bg)] text-[var(--dash-text)]",c),children:[jsx("aside",{className:a("flex-shrink-0 overflow-y-auto overflow-x-hidden transition-[width] duration-200","border-r border-[var(--dash-border)] bg-[var(--dash-surface)]",s?"w-[var(--dash-sidebar-collapsed-width)]":"w-[var(--dash-sidebar-width)]"),children:e}),jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[r&&jsx("header",{className:"flex-shrink-0 border-b border-[var(--dash-border)] bg-[var(--dash-surface)]",children:r}),jsx("main",{className:"flex-1 overflow-y-auto p-6",children:l})]}),!s&&jsx("div",{className:"fixed inset-0 z-40 bg-black/60 lg:hidden",onClick:()=>n?.(true)})]})}i(ce,"Layout");function ue({size:e=28}){return jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsx("path",{d:"M4 4h4v6h8V4h4v16h-4v-6H8v6H4V4z",fill:"currentColor"})})}i(ue,"HanzoMark");function he({logo:e,groups:r,userMenu:l,collapsed:s=false,onToggleCollapse:n,onNavigate:c,className:o}){return jsxs("nav",{className:a("flex h-full flex-col","bg-[var(--dash-surface)] text-[var(--dash-text)]",o),children:[jsxs("div",{className:a("flex h-[var(--dash-header-height)] items-center border-b border-[var(--dash-border)]",s?"justify-center px-2":"px-4"),children:[e??jsx(ue,{}),!s&&n&&jsx("button",{type:"button",onClick:n,className:"ml-auto rounded p-1 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]","aria-label":"Collapse sidebar",children:jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),s&&n&&jsx("button",{type:"button",onClick:n,className:"absolute -right-3 top-4 z-50 hidden rounded-full border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 text-[var(--dash-text-dim)] hover:text-[var(--dash-text)] lg:flex","aria-label":"Expand sidebar",children:jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]}),jsx("div",{className:"flex-1 overflow-y-auto py-2",children:r.map((m,d)=>jsx(me,{group:m,collapsed:s,onNavigate:c},d))}),l&&jsx("div",{className:"border-t border-[var(--dash-border)] p-2",children:l})]})}i(he,"Sidebar");function me({group:e,collapsed:r,onNavigate:l}){let[s,n]=q.useState(e.defaultOpen!==false),c=e.collapsible!==false&&!!e.title;return jsxs("div",{className:"mb-1",children:[e.title&&!r&&jsxs("button",{type:"button",onClick:()=>c&&n(o=>!o),className:a("flex w-full items-center px-4 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-[var(--dash-text-dim)]",c&&"cursor-pointer hover:text-[var(--dash-text-muted)]"),children:[jsx("span",{className:"flex-1 text-left",children:e.title}),c&&jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",className:a("transition-transform",s?"rotate-0":"-rotate-90"),children:jsx("path",{d:"M4 6l4 4 4-4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),(s||r)&&jsx("ul",{className:"space-y-0.5 px-2",children:e.items.map(o=>jsx("li",{children:jsxs("button",{type:"button",onClick:()=>l?.(o.href),title:r?o.label:void 0,className:a("flex w-full items-center gap-2 rounded-[var(--dash-radius-sm)] px-2 py-1.5 text-sm transition-colors",o.active?"bg-[var(--dash-primary)] text-[var(--dash-primary-text)]":"text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]",r&&"justify-center px-0"),children:[o.icon&&jsx("span",{className:"flex h-5 w-5 items-center justify-center flex-shrink-0",children:o.icon}),!r&&jsx("span",{className:"flex-1 truncate text-left",children:o.label}),!r&&o.badge!==void 0&&jsx("span",{className:"ml-auto rounded-full bg-[var(--dash-primary)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--dash-primary-text)]",children:o.badge})]})},o.href))})]})}i(me,"SidebarGroup");function ve({breadcrumbs:e,searchPlaceholder:r="Search...",onSearch:l,avatarUrl:s,userName:n,userDropdown:c,onToggleTheme:o,theme:m="dark",actions:d,className:v}){let[C,R]=q.useState(false),S=q.useRef(null);return q.useEffect(()=>{if(!C)return;function b(M){S.current&&!S.current.contains(M.target)&&R(false);}return i(b,"handleClick"),document.addEventListener("mousedown",b),()=>document.removeEventListener("mousedown",b)},[C]),jsxs("div",{className:a("flex h-[var(--dash-header-height)] items-center gap-4 px-4","bg-[var(--dash-surface)] text-[var(--dash-text)]",v),children:[e&&e.length>0&&jsx("nav",{className:"flex items-center gap-1 text-sm","aria-label":"Breadcrumb",children:e.map((b,M)=>jsxs(q.Fragment,{children:[M>0&&jsx("span",{className:"text-[var(--dash-text-dim)]",children:"/"}),b.href?jsx("a",{href:b.href,className:"text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:b.label}):jsx("span",{className:"text-[var(--dash-text)]",children:b.label})]},M))}),jsx("div",{className:"flex-1"}),l&&jsxs("div",{className:"relative hidden sm:block",children:[jsxs("svg",{className:"absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--dash-text-dim)]",width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:[jsx("circle",{cx:"7",cy:"7",r:"5.5",stroke:"currentColor",strokeWidth:"1.5"}),jsx("path",{d:"M11 11l3 3",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}),jsx("input",{type:"text",placeholder:r,onChange:b=>l(b.target.value),className:a("h-8 w-56 rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] pl-8 pr-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","transition-colors")})]}),d,o&&jsx("button",{type:"button",onClick:o,className:"rounded-[var(--dash-radius-sm)] p-1.5 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors","aria-label":`Switch to ${m==="dark"?"light":"dark"} mode`,children:m==="dark"?jsxs("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:[jsx("circle",{cx:"8",cy:"8",r:"3.5",stroke:"currentColor",strokeWidth:"1.5"}),jsx("path",{d:"M8 1v2M8 13v2M1 8h2M13 8h2M3.05 3.05l1.41 1.41M11.54 11.54l1.41 1.41M3.05 12.95l1.41-1.41M11.54 4.46l1.41-1.41",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})]}):jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M14 9.5A6.5 6.5 0 016.5 2 5.5 5.5 0 1014 9.5z",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),(s||n)&&jsxs("div",{className:"relative",ref:S,children:[jsx("button",{type:"button",onClick:()=>R(b=>!b),className:"flex items-center gap-2 rounded-[var(--dash-radius-sm)] p-1 hover:bg-[var(--dash-surface-hover)] transition-colors",children:s?jsx("img",{src:s,alt:n??"User",className:"h-7 w-7 rounded-full object-cover"}):jsx("div",{className:"flex h-7 w-7 items-center justify-center rounded-full bg-[var(--dash-primary)] text-xs font-medium text-[var(--dash-primary-text)]",children:(n??"?")[0].toUpperCase()})}),C&&c&&jsx("div",{className:"absolute right-0 top-full z-50 mt-1 min-w-48 rounded-[var(--dash-radius)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 shadow-lg",children:c})]})]})}i(ve,"Header");function te({columns:e,data:r,rowKey:l,selectable:s=false,selectedKeys:n,onSelectionChange:c,searchable:o=false,searchPlaceholder:m="Search...",totalRows:d,page:v=0,pageSize:C=20,onPageChange:R,onPageSizeChange:S,actions:b,loading:M=false,emptyMessage:f="No data",className:x}){let[u,w]=q.useState(""),[L,A]=q.useState(null),G=q.useMemo(()=>{if(!u)return r;let t=u.toLowerCase();return r.filter(k=>e.some(O=>(O.cell?"":String(k[O.id]??"")).toLowerCase().includes(t)))},[r,u,e]),W=q.useMemo(()=>{if(!L)return G;let{column:t,direction:k}=L;return [...G].sort((O,E)=>{let Z=O[t],ee=E[t];if(Z==null&&ee==null)return 0;if(Z==null)return 1;if(ee==null)return -1;let se=String(Z).localeCompare(String(ee),void 0,{numeric:true});return k==="asc"?se:-se})},[G,L]),I=d??W.length,z=Math.max(1,Math.ceil(I/C)),j=R?W:W.slice(v*C,(v+1)*C),F=n??new Set,J=j.length>0&&j.every(t=>F.has(l(t)));function U(){c&&c(J?new Set:new Set(j.map(l)));}i(U,"toggleAll");function X(t){if(!c)return;let k=new Set(F);k.has(t)?k.delete(t):k.add(t),c(k);}i(X,"toggleRow");function Y(t){A(k=>k?.column===t?k.direction==="asc"?{column:t,direction:"desc"}:null:{column:t,direction:"asc"});}i(Y,"handleSort");let N=b?[...e,{id:"__actions",header:"",width:"auto"}]:e;return jsxs("div",{className:a("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)]",x),children:[(o||s)&&jsxs("div",{className:"flex items-center gap-3 border-b border-[var(--dash-border)] px-4 py-3",children:[o&&jsx("input",{type:"text",placeholder:m,value:u,onChange:t=>w(t.target.value),className:a("h-8 w-64 max-w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]")}),s&&F.size>0&&jsxs("span",{className:"text-xs text-[var(--dash-text-muted)]",children:[F.size," selected"]})]}),jsx("div",{className:"overflow-x-auto",children:jsxs("table",{className:"w-full text-sm",children:[jsx("thead",{children:jsxs("tr",{className:"border-b border-[var(--dash-border)]",children:[s&&jsx("th",{className:"w-10 px-4 py-2.5",children:jsx("input",{type:"checkbox",checked:J,onChange:U,className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),N.map(t=>jsx("th",{style:t.width?{width:t.width}:void 0,className:a("px-4 py-2.5 text-[var(--dash-text-dim)] font-medium",t.align==="center"&&"text-center",t.align==="right"&&"text-right",!t.align&&"text-left",t.sortable&&"cursor-pointer select-none hover:text-[var(--dash-text-muted)]"),onClick:t.sortable?()=>Y(t.id):void 0,children:jsxs("span",{className:"inline-flex items-center gap-1",children:[t.header,t.sortable&&L?.column===t.id&&jsx("span",{className:"text-[10px]",children:L.direction==="asc"?"\u2191":"\u2193"})]})},t.id))]})}),jsx("tbody",{children:M?jsx("tr",{children:jsx("td",{colSpan:N.length+(s?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:"Loading..."})}):j.length===0?jsx("tr",{children:jsx("td",{colSpan:N.length+(s?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:f})}):j.map(t=>{let k=l(t),O=F.has(k);return jsxs("tr",{className:a("border-b border-[var(--dash-border)] transition-colors",O?"bg-[var(--dash-surface-active)]":"hover:bg-[var(--dash-surface-hover)]"),children:[s&&jsx("td",{className:"w-10 px-4 py-2.5",children:jsx("input",{type:"checkbox",checked:O,onChange:()=>X(k),className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),e.map(E=>jsx("td",{className:a("px-4 py-2.5",E.align==="center"&&"text-center",E.align==="right"&&"text-right"),children:E.cell?E.cell(t):String(t[E.id]??"")},E.id)),b&&jsx("td",{className:"px-4 py-2.5 text-right",children:b(t)})]},k)})})]})}),z>1&&jsxs("div",{className:"flex items-center justify-between border-t border-[var(--dash-border)] px-4 py-2.5 text-xs text-[var(--dash-text-muted)]",children:[jsxs("div",{className:"flex items-center gap-2",children:[jsx("span",{children:"Rows per page"}),jsx("select",{value:C,onChange:t=>S?.(Number(t.target.value)),className:"h-7 rounded border border-[var(--dash-border)] bg-[var(--dash-bg)] px-2 text-xs text-[var(--dash-text)] focus:outline-none",children:[10,20,50,100].map(t=>jsx("option",{value:t,children:t},t))})]}),jsxs("div",{className:"flex items-center gap-2",children:[jsxs("span",{children:["Page ",v+1," of ",z]}),jsx("button",{type:"button",disabled:v===0,onClick:()=>R?.(v-1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),jsx("button",{type:"button",disabled:v>=z-1,onClick:()=>R?.(v+1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})]})}i(te,"Table");function ae({title:e,fields:r,values:l,onSubmit:s,onCancel:n,submitLabel:c="Save",cancelLabel:o="Cancel",loading:m=false,className:d}){let[v,C]=q.useState(()=>{let f={};for(let x of r)f[x.name]=l?.[x.name]??x.defaultValue??(x.type==="toggle"?false:"");return f}),[R,S]=q.useState({});function b(f,x){C(u=>({...u,[f]:x})),S(u=>{if(!u[f])return u;let w={...u};return delete w[f],w});}i(b,"setValue");async function M(f){f.preventDefault();let x={};for(let u of r){let w=v[u.name];if(u.required&&(w===""||w===null||w===void 0)&&(x[u.name]=`${u.label} is required`),u.validate){let L=u.validate(w);L&&(x[u.name]=L);}}if(Object.keys(x).length>0){S(x);return}await s(v);}return i(M,"handleSubmit"),jsxs("form",{onSubmit:M,className:a("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6",d),children:[e&&jsx("h3",{className:"mb-4 text-lg font-semibold text-[var(--dash-text)]",children:e}),jsx("div",{className:"space-y-4",children:r.map(f=>jsx(pe,{field:f,value:v[f.name],error:R[f.name],onChange:x=>b(f.name,x)},f.name))}),jsxs("div",{className:"mt-6 flex items-center gap-3",children:[jsx("button",{type:"submit",disabled:m,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]","disabled:opacity-50 disabled:cursor-not-allowed"),children:m?"Saving...":c}),n&&jsx("button",{type:"button",onClick:n,disabled:m,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:o})]})]})}i(ae,"Form");var Q=a("w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 py-2 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]","disabled:opacity-50 disabled:cursor-not-allowed","transition-colors");function pe({field:e,value:r,error:l,onChange:s}){let n=`dash-field-${e.name}`,c=jsxs("label",{htmlFor:n,className:"mb-1 block text-sm font-medium text-[var(--dash-text)]",children:[e.label,e.required&&jsx("span",{className:"ml-0.5 text-[var(--dash-error)]",children:"*"})]}),o=e.description?jsx("p",{className:"mt-1 text-xs text-[var(--dash-text-dim)]",children:e.description}):null,m=l?jsx("p",{className:"mt-1 text-xs text-[var(--dash-error)]",children:l}):null;switch(e.type){case "text":case "email":case "password":case "number":return jsxs("div",{children:[c,jsx("input",{id:n,type:e.type,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,onChange:d=>s(e.type==="number"?Number(d.target.value):d.target.value),className:a(Q,l&&"border-[var(--dash-error)]")}),o,m]});case "textarea":return jsxs("div",{children:[c,jsx("textarea",{id:n,value:String(r??""),placeholder:e.placeholder,disabled:e.disabled,rows:e.rows??3,onChange:d=>s(d.target.value),className:a(Q,"resize-y",l&&"border-[var(--dash-error)]")}),o,m]});case "select":case "relation":return jsxs("div",{children:[c,jsxs("select",{id:n,value:String(r??""),disabled:e.disabled,onChange:d=>s(d.target.value),className:a(Q,l&&"border-[var(--dash-error)]"),children:[jsx("option",{value:"",children:e.placeholder??"Select..."}),(e.options??[]).map(d=>jsx("option",{value:d.value,children:d.label},d.value))]}),o,m]});case "toggle":return jsxs("div",{className:"flex items-center gap-3",children:[jsx("button",{id:n,type:"button",role:"switch","aria-checked":!!r,disabled:e.disabled,onClick:()=>s(!r),className:a("relative inline-flex h-5 w-9 flex-shrink-0 rounded-full transition-colors","focus:outline-none focus:ring-2 focus:ring-[var(--dash-primary)] focus:ring-offset-2 focus:ring-offset-[var(--dash-surface)]",r?"bg-[var(--dash-primary)]":"bg-[var(--dash-border)]",e.disabled&&"opacity-50 cursor-not-allowed"),children:jsx("span",{className:a("pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform",r?"translate-x-4":"translate-x-0.5","mt-0.5")})}),jsx("label",{htmlFor:n,className:"text-sm text-[var(--dash-text)]",children:e.label}),o,m]});case "json":return jsxs("div",{children:[c,jsx("textarea",{id:n,value:typeof r=="string"?r:JSON.stringify(r,null,2),placeholder:e.placeholder??"{}",disabled:e.disabled,rows:e.rows??6,onChange:d=>{try{s(JSON.parse(d.target.value));}catch{s(d.target.value);}},className:a(Q,"font-mono text-xs resize-y",l&&"border-[var(--dash-error)]")}),o,m]});case "file":return jsxs("div",{children:[c,jsx("input",{id:n,type:"file",accept:e.accept,disabled:e.disabled,onChange:d=>{let v=d.target.files?.[0];v&&s(v);},className:a("w-full text-sm text-[var(--dash-text-muted)]","file:mr-3 file:rounded-[var(--dash-radius-sm)] file:border-0 file:bg-[var(--dash-primary)] file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-[var(--dash-primary-text)]","file:cursor-pointer hover:file:bg-[var(--dash-primary-hover)]")}),o,m]});default:return null}}i(pe,"FieldRenderer");function be({resourceName:e,resourceNamePlural:r,columns:l,data:s,rowKey:n,fields:c,rowToValues:o,onCreate:m,onUpdate:d,onDelete:v,canCreate:C=true,canEdit:R=true,canDelete:S=true,tableProps:b,loading:M=false,className:f}){let x=r??`${e}s`,[u,w]=q.useState("list"),[L,A]=q.useState(null),[G,W]=q.useState({}),[I,z]=q.useState(null),[j,F]=q.useState(false);function J(N){let t=n(N);A(t),W(o?o(N):N),w("edit");}i(J,"handleEdit");function U(N){z(n(N));}i(U,"handleDeleteConfirm");async function X(){if(!(!I||!v)){F(true);try{await v(I);}finally{F(false),z(null);}}}i(X,"confirmDelete");function Y(N){return jsxs("div",{className:"flex items-center justify-end gap-1",children:[R&&d&&jsx("button",{type:"button",onClick:()=>J(N),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors",children:"Edit"}),S&&v&&jsx("button",{type:"button",onClick:()=>U(N),className:"rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-error)] hover:bg-[var(--dash-error-dim)] transition-colors",children:"Delete"})]})}return i(Y,"actionsRenderer"),u==="list"?jsxs("div",{className:a("space-y-4",f),children:[jsxs("div",{className:"flex items-center justify-between",children:[jsx("h2",{className:"text-xl font-semibold text-[var(--dash-text)]",children:x}),C&&m&&jsxs("button",{type:"button",onClick:()=>{A(null),W({}),w("create");},className:a("rounded-[var(--dash-radius)] px-3 py-1.5 text-sm font-medium transition-colors","bg-[var(--dash-primary)] text-[var(--dash-primary-text)]","hover:bg-[var(--dash-primary-hover)]"),children:["Create ",e]})]}),jsx(te,{columns:l,data:s,rowKey:n,actions:R||S?Y:void 0,loading:M,searchable:true,emptyMessage:`No ${x.toLowerCase()} found`,...b}),I!==null&&jsx(fe,{resourceName:e,loading:j,onConfirm:X,onCancel:()=>z(null)})]}):jsxs("div",{className:a("space-y-4",f),children:[jsxs("button",{type:"button",onClick:()=>w("list"),className:"inline-flex items-center gap-1 text-sm text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors",children:[jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),"Back to ",x]}),jsx(ae,{title:u==="create"?`Create ${e}`:`Edit ${e}`,fields:c,values:u==="edit"?G:void 0,loading:j,submitLabel:u==="create"?"Create":"Save changes",onCancel:()=>w("list"),onSubmit:async N=>{F(true);try{u==="create"&&m?await m(N):u==="edit"&&L&&d&&await d(L,N),w("list");}finally{F(false);}}})]})}i(be,"Crud");function fe({resourceName:e,loading:r,onConfirm:l,onCancel:s}){return jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60",children:jsxs("div",{className:"w-full max-w-sm rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6 shadow-lg",children:[jsxs("h3",{className:"text-lg font-semibold text-[var(--dash-text)]",children:["Delete ",e,"?"]}),jsxs("p",{className:"mt-2 text-sm text-[var(--dash-text-muted)]",children:["This action cannot be undone. The ",e.toLowerCase()," will be permanently removed."]}),jsxs("div",{className:"mt-6 flex items-center justify-end gap-3",children:[jsx("button",{type:"button",onClick:s,disabled:r,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","border border-[var(--dash-border)] text-[var(--dash-text-muted)]","hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]"),children:"Cancel"}),jsx("button",{type:"button",onClick:l,disabled:r,className:a("rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors","bg-[var(--dash-error)] text-white","hover:bg-red-600","disabled:opacity-50 disabled:cursor-not-allowed"),children:r?"Deleting...":"Delete"})]})]})})}i(fe,"DeleteDialog");
|
|
3
|
+
export{be as Crud,ae as Form,ve as Header,ce as Layout,he as Sidebar,te as Table};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');var n=Object.defineProperty;var r=(e,a)=>n(e,"name",{value:a,configurable:true});function d(...e){return tailwindMerge.twMerge(clsx.clsx(e))}r(d,"cn");function N({sidebar:e,header:a,children:t,sidebarCollapsed:s=false,onSidebarCollapse:i,className:c}){return jsxRuntime.jsxs("div",{className:d("flex h-screen overflow-hidden","bg-[var(--dash-bg)] text-[var(--dash-text)]",c),children:[jsxRuntime.jsx("aside",{className:d("flex-shrink-0 overflow-y-auto overflow-x-hidden transition-[width] duration-200","border-r border-[var(--dash-border)] bg-[var(--dash-surface)]",s?"w-[var(--dash-sidebar-collapsed-width)]":"w-[var(--dash-sidebar-width)]"),children:e}),jsxRuntime.jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[a&&jsxRuntime.jsx("header",{className:"flex-shrink-0 border-b border-[var(--dash-border)] bg-[var(--dash-surface)]",children:a}),jsxRuntime.jsx("main",{className:"flex-1 overflow-y-auto p-6",children:t})]}),!s&&jsxRuntime.jsx("div",{className:"fixed inset-0 z-40 bg-black/60 lg:hidden",onClick:()=>i?.(true)})]})}r(N,"Layout");exports.Layout=N;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsxs,jsx}from'react/jsx-runtime';var n=Object.defineProperty;var r=(e,a)=>n(e,"name",{value:a,configurable:true});function d(...e){return twMerge(clsx(e))}r(d,"cn");function N({sidebar:e,header:a,children:t,sidebarCollapsed:s=false,onSidebarCollapse:i,className:c}){return jsxs("div",{className:d("flex h-screen overflow-hidden","bg-[var(--dash-bg)] text-[var(--dash-text)]",c),children:[jsx("aside",{className:d("flex-shrink-0 overflow-y-auto overflow-x-hidden transition-[width] duration-200","border-r border-[var(--dash-border)] bg-[var(--dash-surface)]",s?"w-[var(--dash-sidebar-collapsed-width)]":"w-[var(--dash-sidebar-width)]"),children:e}),jsxs("div",{className:"flex flex-1 flex-col overflow-hidden",children:[a&&jsx("header",{className:"flex-shrink-0 border-b border-[var(--dash-border)] bg-[var(--dash-surface)]",children:a}),jsx("main",{className:"flex-1 overflow-y-auto p-6",children:t})]}),!s&&jsx("div",{className:"fixed inset-0 z-40 bg-black/60 lg:hidden",onClick:()=>i?.(true)})]})}r(N,"Layout");export{N as Layout};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var u=require('react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var u__namespace=/*#__PURE__*/_interopNamespace(u);var p=Object.defineProperty;var n=(t,r)=>p(t,"name",{value:r,configurable:true});function i(...t){return tailwindMerge.twMerge(clsx.clsx(t))}n(i,"cn");function b({size:t=28}){return jsxRuntime.jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsxRuntime.jsx("path",{d:"M4 4h4v6h8V4h4v16h-4v-6H8v6H4V4z",fill:"currentColor"})})}n(b,"HanzoMark");function L({logo:t,groups:r,userMenu:v,collapsed:o=false,onToggleCollapse:s,onNavigate:l,className:a}){return jsxRuntime.jsxs("nav",{className:i("flex h-full flex-col","bg-[var(--dash-surface)] text-[var(--dash-text)]",a),children:[jsxRuntime.jsxs("div",{className:i("flex h-[var(--dash-header-height)] items-center border-b border-[var(--dash-border)]",o?"justify-center px-2":"px-4"),children:[t??jsxRuntime.jsx(b,{}),!o&&s&&jsxRuntime.jsx("button",{type:"button",onClick:s,className:"ml-auto rounded p-1 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]","aria-label":"Collapse sidebar",children:jsxRuntime.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),o&&s&&jsxRuntime.jsx("button",{type:"button",onClick:s,className:"absolute -right-3 top-4 z-50 hidden rounded-full border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 text-[var(--dash-text-dim)] hover:text-[var(--dash-text)] lg:flex","aria-label":"Expand sidebar",children:jsxRuntime.jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]}),jsxRuntime.jsx("div",{className:"flex-1 overflow-y-auto py-2",children:r.map((h,c)=>jsxRuntime.jsx(m,{group:h,collapsed:o,onNavigate:l},c))}),v&&jsxRuntime.jsx("div",{className:"border-t border-[var(--dash-border)] p-2",children:v})]})}n(L,"Sidebar");function m({group:t,collapsed:r,onNavigate:v}){let[o,s]=u__namespace.useState(t.defaultOpen!==false),l=t.collapsible!==false&&!!t.title;return jsxRuntime.jsxs("div",{className:"mb-1",children:[t.title&&!r&&jsxRuntime.jsxs("button",{type:"button",onClick:()=>l&&s(a=>!a),className:i("flex w-full items-center px-4 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-[var(--dash-text-dim)]",l&&"cursor-pointer hover:text-[var(--dash-text-muted)]"),children:[jsxRuntime.jsx("span",{className:"flex-1 text-left",children:t.title}),l&&jsxRuntime.jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",className:i("transition-transform",o?"rotate-0":"-rotate-90"),children:jsxRuntime.jsx("path",{d:"M4 6l4 4 4-4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),(o||r)&&jsxRuntime.jsx("ul",{className:"space-y-0.5 px-2",children:t.items.map(a=>jsxRuntime.jsx("li",{children:jsxRuntime.jsxs("button",{type:"button",onClick:()=>v?.(a.href),title:r?a.label:void 0,className:i("flex w-full items-center gap-2 rounded-[var(--dash-radius-sm)] px-2 py-1.5 text-sm transition-colors",a.active?"bg-[var(--dash-primary)] text-[var(--dash-primary-text)]":"text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]",r&&"justify-center px-0"),children:[a.icon&&jsxRuntime.jsx("span",{className:"flex h-5 w-5 items-center justify-center flex-shrink-0",children:a.icon}),!r&&jsxRuntime.jsx("span",{className:"flex-1 truncate text-left",children:a.label}),!r&&a.badge!==void 0&&jsxRuntime.jsx("span",{className:"ml-auto rounded-full bg-[var(--dash-primary)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--dash-primary-text)]",children:a.badge})]})},a.href))})]})}n(m,"SidebarGroup");
|
|
3
|
+
exports.Sidebar=L;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import*as u from'react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsxs,jsx}from'react/jsx-runtime';var p=Object.defineProperty;var n=(t,r)=>p(t,"name",{value:r,configurable:true});function i(...t){return twMerge(clsx(t))}n(i,"cn");function b({size:t=28}){return jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsx("path",{d:"M4 4h4v6h8V4h4v16h-4v-6H8v6H4V4z",fill:"currentColor"})})}n(b,"HanzoMark");function L({logo:t,groups:r,userMenu:v,collapsed:o=false,onToggleCollapse:s,onNavigate:l,className:a}){return jsxs("nav",{className:i("flex h-full flex-col","bg-[var(--dash-surface)] text-[var(--dash-text)]",a),children:[jsxs("div",{className:i("flex h-[var(--dash-header-height)] items-center border-b border-[var(--dash-border)]",o?"justify-center px-2":"px-4"),children:[t??jsx(b,{}),!o&&s&&jsx("button",{type:"button",onClick:s,className:"ml-auto rounded p-1 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]","aria-label":"Collapse sidebar",children:jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),o&&s&&jsx("button",{type:"button",onClick:s,className:"absolute -right-3 top-4 z-50 hidden rounded-full border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 text-[var(--dash-text-dim)] hover:text-[var(--dash-text)] lg:flex","aria-label":"Expand sidebar",children:jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]}),jsx("div",{className:"flex-1 overflow-y-auto py-2",children:r.map((h,c)=>jsx(m,{group:h,collapsed:o,onNavigate:l},c))}),v&&jsx("div",{className:"border-t border-[var(--dash-border)] p-2",children:v})]})}n(L,"Sidebar");function m({group:t,collapsed:r,onNavigate:v}){let[o,s]=u.useState(t.defaultOpen!==false),l=t.collapsible!==false&&!!t.title;return jsxs("div",{className:"mb-1",children:[t.title&&!r&&jsxs("button",{type:"button",onClick:()=>l&&s(a=>!a),className:i("flex w-full items-center px-4 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-[var(--dash-text-dim)]",l&&"cursor-pointer hover:text-[var(--dash-text-muted)]"),children:[jsx("span",{className:"flex-1 text-left",children:t.title}),l&&jsx("svg",{width:"12",height:"12",viewBox:"0 0 16 16",fill:"none",className:i("transition-transform",o?"rotate-0":"-rotate-90"),children:jsx("path",{d:"M4 6l4 4 4-4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),(o||r)&&jsx("ul",{className:"space-y-0.5 px-2",children:t.items.map(a=>jsx("li",{children:jsxs("button",{type:"button",onClick:()=>v?.(a.href),title:r?a.label:void 0,className:i("flex w-full items-center gap-2 rounded-[var(--dash-radius-sm)] px-2 py-1.5 text-sm transition-colors",a.active?"bg-[var(--dash-primary)] text-[var(--dash-primary-text)]":"text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]",r&&"justify-center px-0"),children:[a.icon&&jsx("span",{className:"flex h-5 w-5 items-center justify-center flex-shrink-0",children:a.icon}),!r&&jsx("span",{className:"flex-1 truncate text-left",children:a.label}),!r&&a.badge!==void 0&&jsx("span",{className:"ml-auto rounded-full bg-[var(--dash-primary)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--dash-primary-text)]",children:a.badge})]})},a.href))})]})}n(m,"SidebarGroup");
|
|
3
|
+
export{L as Sidebar};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
'use strict';var u=require('react'),clsx=require('clsx'),tailwindMerge=require('tailwind-merge'),jsxRuntime=require('react/jsx-runtime');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var u__namespace=/*#__PURE__*/_interopNamespace(u);var J=Object.defineProperty;var i=(s,h)=>J(s,"name",{value:h,configurable:true});function c(...s){return tailwindMerge.twMerge(clsx.clsx(s))}i(c,"cn");function ee({columns:s,data:h,rowKey:f,selectable:l=false,selectedKeys:j,onSelectionChange:m,searchable:L=false,searchPlaceholder:z="Search...",totalRows:B,page:o=0,pageSize:g=20,onPageChange:w,onPageSizeChange:V,actions:y,loading:W=false,emptyMessage:_="No data",className:q}){let[x,A]=u__namespace.useState(""),[p,D]=u__namespace.useState(null),N=u__namespace.useMemo(()=>{if(!x)return h;let e=x.toLowerCase();return h.filter(r=>s.some(d=>(d.cell?"":String(r[d.id]??"")).toLowerCase().includes(e)))},[h,x,s]),k=u__namespace.useMemo(()=>{if(!p)return N;let{column:e,direction:r}=p;return [...N].sort((d,n)=>{let C=d[e],T=n[e];if(C==null&&T==null)return 0;if(C==null)return 1;if(T==null)return -1;let P=String(C).localeCompare(String(T),void 0,{numeric:true});return r==="asc"?P:-P})},[N,p]),E=B??k.length,S=Math.max(1,Math.ceil(E/g)),b=w?k:k.slice(o*g,(o+1)*g),v=j??new Set,M=b.length>0&&b.every(e=>v.has(f(e)));function F(){m&&m(M?new Set:new Set(b.map(f)));}i(F,"toggleAll");function G(e){if(!m)return;let r=new Set(v);r.has(e)?r.delete(e):r.add(e),m(r);}i(G,"toggleRow");function H(e){D(r=>r?.column===e?r.direction==="asc"?{column:e,direction:"desc"}:null:{column:e,direction:"asc"});}i(H,"handleSort");let R=y?[...s,{id:"__actions",header:"",width:"auto"}]:s;return jsxRuntime.jsxs("div",{className:c("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)]",q),children:[(L||l)&&jsxRuntime.jsxs("div",{className:"flex items-center gap-3 border-b border-[var(--dash-border)] px-4 py-3",children:[L&&jsxRuntime.jsx("input",{type:"text",placeholder:z,value:x,onChange:e=>A(e.target.value),className:c("h-8 w-64 max-w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]")}),l&&v.size>0&&jsxRuntime.jsxs("span",{className:"text-xs text-[var(--dash-text-muted)]",children:[v.size," selected"]})]}),jsxRuntime.jsx("div",{className:"overflow-x-auto",children:jsxRuntime.jsxs("table",{className:"w-full text-sm",children:[jsxRuntime.jsx("thead",{children:jsxRuntime.jsxs("tr",{className:"border-b border-[var(--dash-border)]",children:[l&&jsxRuntime.jsx("th",{className:"w-10 px-4 py-2.5",children:jsxRuntime.jsx("input",{type:"checkbox",checked:M,onChange:F,className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),R.map(e=>jsxRuntime.jsx("th",{style:e.width?{width:e.width}:void 0,className:c("px-4 py-2.5 text-[var(--dash-text-dim)] font-medium",e.align==="center"&&"text-center",e.align==="right"&&"text-right",!e.align&&"text-left",e.sortable&&"cursor-pointer select-none hover:text-[var(--dash-text-muted)]"),onClick:e.sortable?()=>H(e.id):void 0,children:jsxRuntime.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.header,e.sortable&&p?.column===e.id&&jsxRuntime.jsx("span",{className:"text-[10px]",children:p.direction==="asc"?"\u2191":"\u2193"})]})},e.id))]})}),jsxRuntime.jsx("tbody",{children:W?jsxRuntime.jsx("tr",{children:jsxRuntime.jsx("td",{colSpan:R.length+(l?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:"Loading..."})}):b.length===0?jsxRuntime.jsx("tr",{children:jsxRuntime.jsx("td",{colSpan:R.length+(l?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:_})}):b.map(e=>{let r=f(e),d=v.has(r);return jsxRuntime.jsxs("tr",{className:c("border-b border-[var(--dash-border)] transition-colors",d?"bg-[var(--dash-surface-active)]":"hover:bg-[var(--dash-surface-hover)]"),children:[l&&jsxRuntime.jsx("td",{className:"w-10 px-4 py-2.5",children:jsxRuntime.jsx("input",{type:"checkbox",checked:d,onChange:()=>G(r),className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),s.map(n=>jsxRuntime.jsx("td",{className:c("px-4 py-2.5",n.align==="center"&&"text-center",n.align==="right"&&"text-right"),children:n.cell?n.cell(e):String(e[n.id]??"")},n.id)),y&&jsxRuntime.jsx("td",{className:"px-4 py-2.5 text-right",children:y(e)})]},r)})})]})}),S>1&&jsxRuntime.jsxs("div",{className:"flex items-center justify-between border-t border-[var(--dash-border)] px-4 py-2.5 text-xs text-[var(--dash-text-muted)]",children:[jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsx("span",{children:"Rows per page"}),jsxRuntime.jsx("select",{value:g,onChange:e=>V?.(Number(e.target.value)),className:"h-7 rounded border border-[var(--dash-border)] bg-[var(--dash-bg)] px-2 text-xs text-[var(--dash-text)] focus:outline-none",children:[10,20,50,100].map(e=>jsxRuntime.jsx("option",{value:e,children:e},e))})]}),jsxRuntime.jsxs("div",{className:"flex items-center gap-2",children:[jsxRuntime.jsxs("span",{children:["Page ",o+1," of ",S]}),jsxRuntime.jsx("button",{type:"button",disabled:o===0,onClick:()=>w?.(o-1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),jsxRuntime.jsx("button",{type:"button",disabled:o>=S-1,onClick:()=>w?.(o+1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsxRuntime.jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsxRuntime.jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})]})}i(ee,"Table");exports.Table=ee;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import*as u from'react';import {clsx}from'clsx';import {twMerge}from'tailwind-merge';import {jsxs,jsx}from'react/jsx-runtime';var J=Object.defineProperty;var i=(s,h)=>J(s,"name",{value:h,configurable:true});function c(...s){return twMerge(clsx(s))}i(c,"cn");function ee({columns:s,data:h,rowKey:f,selectable:l=false,selectedKeys:j,onSelectionChange:m,searchable:L=false,searchPlaceholder:z="Search...",totalRows:B,page:o=0,pageSize:g=20,onPageChange:w,onPageSizeChange:V,actions:y,loading:W=false,emptyMessage:_="No data",className:q}){let[x,A]=u.useState(""),[p,D]=u.useState(null),N=u.useMemo(()=>{if(!x)return h;let e=x.toLowerCase();return h.filter(r=>s.some(d=>(d.cell?"":String(r[d.id]??"")).toLowerCase().includes(e)))},[h,x,s]),k=u.useMemo(()=>{if(!p)return N;let{column:e,direction:r}=p;return [...N].sort((d,n)=>{let C=d[e],T=n[e];if(C==null&&T==null)return 0;if(C==null)return 1;if(T==null)return -1;let P=String(C).localeCompare(String(T),void 0,{numeric:true});return r==="asc"?P:-P})},[N,p]),E=B??k.length,S=Math.max(1,Math.ceil(E/g)),b=w?k:k.slice(o*g,(o+1)*g),v=j??new Set,M=b.length>0&&b.every(e=>v.has(f(e)));function F(){m&&m(M?new Set:new Set(b.map(f)));}i(F,"toggleAll");function G(e){if(!m)return;let r=new Set(v);r.has(e)?r.delete(e):r.add(e),m(r);}i(G,"toggleRow");function H(e){D(r=>r?.column===e?r.direction==="asc"?{column:e,direction:"desc"}:null:{column:e,direction:"asc"});}i(H,"handleSort");let R=y?[...s,{id:"__actions",header:"",width:"auto"}]:s;return jsxs("div",{className:c("rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)]",q),children:[(L||l)&&jsxs("div",{className:"flex items-center gap-3 border-b border-[var(--dash-border)] px-4 py-3",children:[L&&jsx("input",{type:"text",placeholder:z,value:x,onChange:e=>A(e.target.value),className:c("h-8 w-64 max-w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 text-sm text-[var(--dash-text)]","placeholder:text-[var(--dash-text-dim)]","focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]")}),l&&v.size>0&&jsxs("span",{className:"text-xs text-[var(--dash-text-muted)]",children:[v.size," selected"]})]}),jsx("div",{className:"overflow-x-auto",children:jsxs("table",{className:"w-full text-sm",children:[jsx("thead",{children:jsxs("tr",{className:"border-b border-[var(--dash-border)]",children:[l&&jsx("th",{className:"w-10 px-4 py-2.5",children:jsx("input",{type:"checkbox",checked:M,onChange:F,className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),R.map(e=>jsx("th",{style:e.width?{width:e.width}:void 0,className:c("px-4 py-2.5 text-[var(--dash-text-dim)] font-medium",e.align==="center"&&"text-center",e.align==="right"&&"text-right",!e.align&&"text-left",e.sortable&&"cursor-pointer select-none hover:text-[var(--dash-text-muted)]"),onClick:e.sortable?()=>H(e.id):void 0,children:jsxs("span",{className:"inline-flex items-center gap-1",children:[e.header,e.sortable&&p?.column===e.id&&jsx("span",{className:"text-[10px]",children:p.direction==="asc"?"\u2191":"\u2193"})]})},e.id))]})}),jsx("tbody",{children:W?jsx("tr",{children:jsx("td",{colSpan:R.length+(l?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:"Loading..."})}):b.length===0?jsx("tr",{children:jsx("td",{colSpan:R.length+(l?1:0),className:"px-4 py-8 text-center text-[var(--dash-text-dim)]",children:_})}):b.map(e=>{let r=f(e),d=v.has(r);return jsxs("tr",{className:c("border-b border-[var(--dash-border)] transition-colors",d?"bg-[var(--dash-surface-active)]":"hover:bg-[var(--dash-surface-hover)]"),children:[l&&jsx("td",{className:"w-10 px-4 py-2.5",children:jsx("input",{type:"checkbox",checked:d,onChange:()=>G(r),className:"h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]"})}),s.map(n=>jsx("td",{className:c("px-4 py-2.5",n.align==="center"&&"text-center",n.align==="right"&&"text-right"),children:n.cell?n.cell(e):String(e[n.id]??"")},n.id)),y&&jsx("td",{className:"px-4 py-2.5 text-right",children:y(e)})]},r)})})]})}),S>1&&jsxs("div",{className:"flex items-center justify-between border-t border-[var(--dash-border)] px-4 py-2.5 text-xs text-[var(--dash-text-muted)]",children:[jsxs("div",{className:"flex items-center gap-2",children:[jsx("span",{children:"Rows per page"}),jsx("select",{value:g,onChange:e=>V?.(Number(e.target.value)),className:"h-7 rounded border border-[var(--dash-border)] bg-[var(--dash-bg)] px-2 text-xs text-[var(--dash-text)] focus:outline-none",children:[10,20,50,100].map(e=>jsx("option",{value:e,children:e},e))})]}),jsxs("div",{className:"flex items-center gap-2",children:[jsxs("span",{children:["Page ",o+1," of ",S]}),jsx("button",{type:"button",disabled:o===0,onClick:()=>w?.(o-1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M10 4L6 8l4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}),jsx("button",{type:"button",disabled:o>=S-1,onClick:()=>w?.(o+1),className:"rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed",children:jsx("svg",{width:"14",height:"14",viewBox:"0 0 16 16",fill:"none",children:jsx("path",{d:"M6 4l4 4-4 4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})]})}i(ee,"Table");export{ee as Table};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Column, type TableProps } from './table';
|
|
2
|
+
import { type FieldDef } from './form';
|
|
3
|
+
export interface CrudProps<T> {
|
|
4
|
+
/** Resource name (e.g. "User", "API Key") used in UI labels */
|
|
5
|
+
resourceName: string;
|
|
6
|
+
/** Plural resource name (defaults to resourceName + "s") */
|
|
7
|
+
resourceNamePlural?: string;
|
|
8
|
+
/** Column definitions for the list table */
|
|
9
|
+
columns: Column<T>[];
|
|
10
|
+
/** Row data */
|
|
11
|
+
data: T[];
|
|
12
|
+
/** Unique key extractor per row */
|
|
13
|
+
rowKey: (row: T) => string;
|
|
14
|
+
/** Field definitions for create/edit form */
|
|
15
|
+
fields: FieldDef[];
|
|
16
|
+
/** Convert a row to form values for editing */
|
|
17
|
+
rowToValues?: (row: T) => Record<string, unknown>;
|
|
18
|
+
/** Called when creating a new record */
|
|
19
|
+
onCreate?: (values: Record<string, unknown>) => Promise<void>;
|
|
20
|
+
/** Called when updating an existing record */
|
|
21
|
+
onUpdate?: (key: string, values: Record<string, unknown>) => Promise<void>;
|
|
22
|
+
/** Called when deleting a record */
|
|
23
|
+
onDelete?: (key: string) => Promise<void>;
|
|
24
|
+
/** Whether create is available */
|
|
25
|
+
canCreate?: boolean;
|
|
26
|
+
/** Whether edit is available */
|
|
27
|
+
canEdit?: boolean;
|
|
28
|
+
/** Whether delete is available */
|
|
29
|
+
canDelete?: boolean;
|
|
30
|
+
/** Pass-through Table props */
|
|
31
|
+
tableProps?: Partial<TableProps<T>>;
|
|
32
|
+
/** Loading state */
|
|
33
|
+
loading?: boolean;
|
|
34
|
+
className?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare function Crud<T>({ resourceName, resourceNamePlural, columns, data, rowKey, fields, rowToValues, onCreate, onUpdate, onDelete, canCreate, canEdit, canDelete, tableProps, loading, className, }: CrudProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
//# sourceMappingURL=crud.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../../src/dash/crud.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAS,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAM5C,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAA;IACpB,4DAA4D;IAC5D,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;IACpB,eAAe;IACf,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,mCAAmC;IACnC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAA;IAC1B,6CAA6C;IAC7C,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjD,wCAAwC;IACxC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7D,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,oCAAoC;IACpC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACzC,kCAAkC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,gCAAgC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kCAAkC;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IACnC,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAQD,wBAAgB,IAAI,CAAC,CAAC,EAAE,EACtB,YAAY,EACZ,kBAAkB,EAClB,OAAO,EACP,IAAI,EACJ,MAAM,EACN,MAAM,EACN,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,SAAgB,EAChB,OAAc,EACd,SAAgB,EAChB,UAAU,EACV,OAAe,EACf,SAAS,GACV,EAAE,SAAS,CAAC,CAAC,CAAC,2CAgJd"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../utils';
|
|
5
|
+
import { Table } from './table';
|
|
6
|
+
import { Form } from './form';
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
/* Component */
|
|
9
|
+
/* ------------------------------------------------------------------ */
|
|
10
|
+
export function Crud({ resourceName, resourceNamePlural, columns, data, rowKey, fields, rowToValues, onCreate, onUpdate, onDelete, canCreate = true, canEdit = true, canDelete = true, tableProps, loading = false, className, }) {
|
|
11
|
+
const plural = resourceNamePlural ?? `${resourceName}s`;
|
|
12
|
+
const [view, setView] = React.useState('list');
|
|
13
|
+
const [editingKey, setEditingKey] = React.useState(null);
|
|
14
|
+
const [editValues, setEditValues] = React.useState({});
|
|
15
|
+
const [deleteKey, setDeleteKey] = React.useState(null);
|
|
16
|
+
const [submitting, setSubmitting] = React.useState(false);
|
|
17
|
+
/* ------ edit ------ */
|
|
18
|
+
function handleEdit(row) {
|
|
19
|
+
const key = rowKey(row);
|
|
20
|
+
setEditingKey(key);
|
|
21
|
+
setEditValues(rowToValues ? rowToValues(row) : row);
|
|
22
|
+
setView('edit');
|
|
23
|
+
}
|
|
24
|
+
/* ------ delete confirm ------ */
|
|
25
|
+
function handleDeleteConfirm(row) {
|
|
26
|
+
setDeleteKey(rowKey(row));
|
|
27
|
+
}
|
|
28
|
+
async function confirmDelete() {
|
|
29
|
+
if (!deleteKey || !onDelete)
|
|
30
|
+
return;
|
|
31
|
+
setSubmitting(true);
|
|
32
|
+
try {
|
|
33
|
+
await onDelete(deleteKey);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
setSubmitting(false);
|
|
37
|
+
setDeleteKey(null);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/* ------ actions column ------ */
|
|
41
|
+
function actionsRenderer(row) {
|
|
42
|
+
return (_jsxs("div", { className: "flex items-center justify-end gap-1", children: [canEdit && onUpdate && (_jsx("button", { type: "button", onClick: () => handleEdit(row), className: "rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors", children: "Edit" })), canDelete && onDelete && (_jsx("button", { type: "button", onClick: () => handleDeleteConfirm(row), className: "rounded-[var(--dash-radius-sm)] px-2 py-1 text-xs text-[var(--dash-error)] hover:bg-[var(--dash-error-dim)] transition-colors", children: "Delete" }))] }));
|
|
43
|
+
}
|
|
44
|
+
/* ------ list view ------ */
|
|
45
|
+
if (view === 'list') {
|
|
46
|
+
return (_jsxs("div", { className: cn('space-y-4', className), children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-xl font-semibold text-[var(--dash-text)]", children: plural }), canCreate && onCreate && (_jsxs("button", { type: "button", onClick: () => {
|
|
47
|
+
setEditingKey(null);
|
|
48
|
+
setEditValues({});
|
|
49
|
+
setView('create');
|
|
50
|
+
}, className: cn('rounded-[var(--dash-radius)] px-3 py-1.5 text-sm font-medium transition-colors', 'bg-[var(--dash-primary)] text-[var(--dash-primary-text)]', 'hover:bg-[var(--dash-primary-hover)]'), children: ["Create ", resourceName] }))] }), _jsx(Table, { columns: columns, data: data, rowKey: rowKey, actions: (canEdit || canDelete) ? actionsRenderer : undefined, loading: loading, searchable: true, emptyMessage: `No ${plural.toLowerCase()} found`, ...tableProps }), deleteKey !== null && (_jsx(DeleteDialog, { resourceName: resourceName, loading: submitting, onConfirm: confirmDelete, onCancel: () => setDeleteKey(null) }))] }));
|
|
51
|
+
}
|
|
52
|
+
/* ------ create / edit view ------ */
|
|
53
|
+
return (_jsxs("div", { className: cn('space-y-4', className), children: [_jsxs("button", { type: "button", onClick: () => setView('list'), className: "inline-flex items-center gap-1 text-sm text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors", children: [_jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M10 4L6 8l4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }), "Back to ", plural] }), _jsx(Form, { title: view === 'create' ? `Create ${resourceName}` : `Edit ${resourceName}`, fields: fields, values: view === 'edit' ? editValues : undefined, loading: submitting, submitLabel: view === 'create' ? 'Create' : 'Save changes', onCancel: () => setView('list'), onSubmit: async (vals) => {
|
|
54
|
+
setSubmitting(true);
|
|
55
|
+
try {
|
|
56
|
+
if (view === 'create' && onCreate) {
|
|
57
|
+
await onCreate(vals);
|
|
58
|
+
}
|
|
59
|
+
else if (view === 'edit' && editingKey && onUpdate) {
|
|
60
|
+
await onUpdate(editingKey, vals);
|
|
61
|
+
}
|
|
62
|
+
setView('list');
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
setSubmitting(false);
|
|
66
|
+
}
|
|
67
|
+
} })] }));
|
|
68
|
+
}
|
|
69
|
+
/* ------------------------------------------------------------------ */
|
|
70
|
+
/* DeleteDialog (internal) */
|
|
71
|
+
/* ------------------------------------------------------------------ */
|
|
72
|
+
function DeleteDialog({ resourceName, loading, onConfirm, onCancel, }) {
|
|
73
|
+
return (_jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60", children: _jsxs("div", { className: "w-full max-w-sm rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6 shadow-lg", children: [_jsxs("h3", { className: "text-lg font-semibold text-[var(--dash-text)]", children: ["Delete ", resourceName, "?"] }), _jsxs("p", { className: "mt-2 text-sm text-[var(--dash-text-muted)]", children: ["This action cannot be undone. The ", resourceName.toLowerCase(), " will be permanently removed."] }), _jsxs("div", { className: "mt-6 flex items-center justify-end gap-3", children: [_jsx("button", { type: "button", onClick: onCancel, disabled: loading, className: cn('rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors', 'border border-[var(--dash-border)] text-[var(--dash-text-muted)]', 'hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]'), children: "Cancel" }), _jsx("button", { type: "button", onClick: onConfirm, disabled: loading, className: cn('rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors', 'bg-[var(--dash-error)] text-white', 'hover:bg-red-600', 'disabled:opacity-50 disabled:cursor-not-allowed'), children: loading ? 'Deleting...' : 'Delete' })] })] }) }));
|
|
74
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export type FieldType = 'text' | 'number' | 'email' | 'password' | 'select' | 'toggle' | 'textarea' | 'json' | 'relation' | 'file';
|
|
2
|
+
export interface FieldOption {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}
|
|
6
|
+
export interface FieldDef {
|
|
7
|
+
/** Field key (maps to form value key) */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Display label */
|
|
10
|
+
label: string;
|
|
11
|
+
/** Field type */
|
|
12
|
+
type: FieldType;
|
|
13
|
+
/** Placeholder text */
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
/** Description shown below field */
|
|
16
|
+
description?: string;
|
|
17
|
+
/** Whether the field is required */
|
|
18
|
+
required?: boolean;
|
|
19
|
+
/** Select options (for type=select or type=relation) */
|
|
20
|
+
options?: FieldOption[];
|
|
21
|
+
/** Default value */
|
|
22
|
+
defaultValue?: unknown;
|
|
23
|
+
/** Disabled */
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
/** File accept pattern (for type=file) */
|
|
26
|
+
accept?: string;
|
|
27
|
+
/** Number of textarea rows */
|
|
28
|
+
rows?: number;
|
|
29
|
+
/** Zod-style validation function. Return error string or null. */
|
|
30
|
+
validate?: (value: unknown) => string | null;
|
|
31
|
+
}
|
|
32
|
+
export interface FormProps {
|
|
33
|
+
/** Form title */
|
|
34
|
+
title?: string;
|
|
35
|
+
/** Field definitions */
|
|
36
|
+
fields: FieldDef[];
|
|
37
|
+
/** Initial values */
|
|
38
|
+
values?: Record<string, unknown>;
|
|
39
|
+
/** Called on submit with validated values */
|
|
40
|
+
onSubmit: (values: Record<string, unknown>) => void | Promise<void>;
|
|
41
|
+
/** Called on cancel */
|
|
42
|
+
onCancel?: () => void;
|
|
43
|
+
/** Submit button label */
|
|
44
|
+
submitLabel?: string;
|
|
45
|
+
/** Cancel button label */
|
|
46
|
+
cancelLabel?: string;
|
|
47
|
+
/** Loading state */
|
|
48
|
+
loading?: boolean;
|
|
49
|
+
className?: string;
|
|
50
|
+
}
|
|
51
|
+
export declare function Form({ title, fields, values: initialValues, onSubmit, onCancel, submitLabel, cancelLabel, loading, className, }: FormProps): import("react/jsx-runtime").JSX.Element;
|
|
52
|
+
//# sourceMappingURL=form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../../src/dash/form.tsx"],"names":[],"mappings":"AASA,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,QAAQ,GACR,OAAO,GACP,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,MAAM,GACN,UAAU,GACV,MAAM,CAAA;AAEV,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB;IACjB,IAAI,EAAE,SAAS,CAAA;IACf,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,wDAAwD;IACxD,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;IACvB,oBAAoB;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,eAAe;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,CAAA;CAC7C;AAED,MAAM,WAAW,SAAS;IACxB,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wBAAwB;IACxB,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,6CAA6C;IAC7C,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnE,uBAAuB;IACvB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;IACrB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD,wBAAgB,IAAI,CAAC,EACnB,KAAK,EACL,MAAM,EACN,MAAM,EAAE,aAAa,EACrB,QAAQ,EACR,QAAQ,EACR,WAAoB,EACpB,WAAsB,EACtB,OAAe,EACf,SAAS,GACV,EAAE,SAAS,2CAmGX"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../utils';
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Component */
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
export function Form({ title, fields, values: initialValues, onSubmit, onCancel, submitLabel = 'Save', cancelLabel = 'Cancel', loading = false, className, }) {
|
|
9
|
+
const [values, setValues] = React.useState(() => {
|
|
10
|
+
const init = {};
|
|
11
|
+
for (const f of fields) {
|
|
12
|
+
init[f.name] = initialValues?.[f.name] ?? f.defaultValue ?? (f.type === 'toggle' ? false : '');
|
|
13
|
+
}
|
|
14
|
+
return init;
|
|
15
|
+
});
|
|
16
|
+
const [errors, setErrors] = React.useState({});
|
|
17
|
+
function setValue(name, value) {
|
|
18
|
+
setValues((prev) => ({ ...prev, [name]: value }));
|
|
19
|
+
setErrors((prev) => {
|
|
20
|
+
if (!prev[name])
|
|
21
|
+
return prev;
|
|
22
|
+
const next = { ...prev };
|
|
23
|
+
delete next[name];
|
|
24
|
+
return next;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async function handleSubmit(e) {
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
// Validate
|
|
30
|
+
const errs = {};
|
|
31
|
+
for (const f of fields) {
|
|
32
|
+
const v = values[f.name];
|
|
33
|
+
if (f.required && (v === '' || v === null || v === undefined)) {
|
|
34
|
+
errs[f.name] = `${f.label} is required`;
|
|
35
|
+
}
|
|
36
|
+
if (f.validate) {
|
|
37
|
+
const err = f.validate(v);
|
|
38
|
+
if (err)
|
|
39
|
+
errs[f.name] = err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (Object.keys(errs).length > 0) {
|
|
43
|
+
setErrors(errs);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
await onSubmit(values);
|
|
47
|
+
}
|
|
48
|
+
return (_jsxs("form", { onSubmit: handleSubmit, className: cn('rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-6', className), children: [title && (_jsx("h3", { className: "mb-4 text-lg font-semibold text-[var(--dash-text)]", children: title })), _jsx("div", { className: "space-y-4", children: fields.map((field) => (_jsx(FieldRenderer, { field: field, value: values[field.name], error: errors[field.name], onChange: (v) => setValue(field.name, v) }, field.name))) }), _jsxs("div", { className: "mt-6 flex items-center gap-3", children: [_jsx("button", { type: "submit", disabled: loading, className: cn('rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors', 'bg-[var(--dash-primary)] text-[var(--dash-primary-text)]', 'hover:bg-[var(--dash-primary-hover)]', 'disabled:opacity-50 disabled:cursor-not-allowed'), children: loading ? 'Saving...' : submitLabel }), onCancel && (_jsx("button", { type: "button", onClick: onCancel, disabled: loading, className: cn('rounded-[var(--dash-radius)] px-4 py-2 text-sm font-medium transition-colors', 'border border-[var(--dash-border)] text-[var(--dash-text-muted)]', 'hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]'), children: cancelLabel }))] })] }));
|
|
49
|
+
}
|
|
50
|
+
/* ------------------------------------------------------------------ */
|
|
51
|
+
/* FieldRenderer (internal) */
|
|
52
|
+
/* ------------------------------------------------------------------ */
|
|
53
|
+
const inputBase = cn('w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 py-2 text-sm text-[var(--dash-text)]', 'placeholder:text-[var(--dash-text-dim)]', 'focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]', 'disabled:opacity-50 disabled:cursor-not-allowed', 'transition-colors');
|
|
54
|
+
function FieldRenderer({ field, value, error, onChange, }) {
|
|
55
|
+
const id = `dash-field-${field.name}`;
|
|
56
|
+
const labelEl = (_jsxs("label", { htmlFor: id, className: "mb-1 block text-sm font-medium text-[var(--dash-text)]", children: [field.label, field.required && _jsx("span", { className: "ml-0.5 text-[var(--dash-error)]", children: "*" })] }));
|
|
57
|
+
const descEl = field.description ? (_jsx("p", { className: "mt-1 text-xs text-[var(--dash-text-dim)]", children: field.description })) : null;
|
|
58
|
+
const errEl = error ? (_jsx("p", { className: "mt-1 text-xs text-[var(--dash-error)]", children: error })) : null;
|
|
59
|
+
switch (field.type) {
|
|
60
|
+
case 'text':
|
|
61
|
+
case 'email':
|
|
62
|
+
case 'password':
|
|
63
|
+
case 'number':
|
|
64
|
+
return (_jsxs("div", { children: [labelEl, _jsx("input", { id: id, type: field.type, value: String(value ?? ''), placeholder: field.placeholder, disabled: field.disabled, onChange: (e) => onChange(field.type === 'number' ? Number(e.target.value) : e.target.value), className: cn(inputBase, error && 'border-[var(--dash-error)]') }), descEl, errEl] }));
|
|
65
|
+
case 'textarea':
|
|
66
|
+
return (_jsxs("div", { children: [labelEl, _jsx("textarea", { id: id, value: String(value ?? ''), placeholder: field.placeholder, disabled: field.disabled, rows: field.rows ?? 3, onChange: (e) => onChange(e.target.value), className: cn(inputBase, 'resize-y', error && 'border-[var(--dash-error)]') }), descEl, errEl] }));
|
|
67
|
+
case 'select':
|
|
68
|
+
case 'relation':
|
|
69
|
+
return (_jsxs("div", { children: [labelEl, _jsxs("select", { id: id, value: String(value ?? ''), disabled: field.disabled, onChange: (e) => onChange(e.target.value), className: cn(inputBase, error && 'border-[var(--dash-error)]'), children: [_jsx("option", { value: "", children: field.placeholder ?? 'Select...' }), (field.options ?? []).map((opt) => (_jsx("option", { value: opt.value, children: opt.label }, opt.value)))] }), descEl, errEl] }));
|
|
70
|
+
case 'toggle':
|
|
71
|
+
return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("button", { id: id, type: "button", role: "switch", "aria-checked": Boolean(value), disabled: field.disabled, onClick: () => onChange(!value), className: cn('relative inline-flex h-5 w-9 flex-shrink-0 rounded-full transition-colors', 'focus:outline-none focus:ring-2 focus:ring-[var(--dash-primary)] focus:ring-offset-2 focus:ring-offset-[var(--dash-surface)]', value ? 'bg-[var(--dash-primary)]' : 'bg-[var(--dash-border)]', field.disabled && 'opacity-50 cursor-not-allowed'), children: _jsx("span", { className: cn('pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transition-transform', value ? 'translate-x-4' : 'translate-x-0.5', 'mt-0.5') }) }), _jsx("label", { htmlFor: id, className: "text-sm text-[var(--dash-text)]", children: field.label }), descEl, errEl] }));
|
|
72
|
+
case 'json':
|
|
73
|
+
return (_jsxs("div", { children: [labelEl, _jsx("textarea", { id: id, value: typeof value === 'string' ? value : JSON.stringify(value, null, 2), placeholder: field.placeholder ?? '{}', disabled: field.disabled, rows: field.rows ?? 6, onChange: (e) => {
|
|
74
|
+
try {
|
|
75
|
+
onChange(JSON.parse(e.target.value));
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
onChange(e.target.value);
|
|
79
|
+
}
|
|
80
|
+
}, className: cn(inputBase, 'font-mono text-xs resize-y', error && 'border-[var(--dash-error)]') }), descEl, errEl] }));
|
|
81
|
+
case 'file':
|
|
82
|
+
return (_jsxs("div", { children: [labelEl, _jsx("input", { id: id, type: "file", accept: field.accept, disabled: field.disabled, onChange: (e) => {
|
|
83
|
+
const file = e.target.files?.[0];
|
|
84
|
+
if (file)
|
|
85
|
+
onChange(file);
|
|
86
|
+
}, className: cn('w-full text-sm text-[var(--dash-text-muted)]', 'file:mr-3 file:rounded-[var(--dash-radius-sm)] file:border-0 file:bg-[var(--dash-primary)] file:px-3 file:py-1.5 file:text-sm file:font-medium file:text-[var(--dash-primary-text)]', 'file:cursor-pointer hover:file:bg-[var(--dash-primary-hover)]') }), descEl, errEl] }));
|
|
87
|
+
default:
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface BreadcrumbItem {
|
|
3
|
+
label: string;
|
|
4
|
+
href?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface HeaderProps {
|
|
7
|
+
/** Breadcrumb trail */
|
|
8
|
+
breadcrumbs?: BreadcrumbItem[];
|
|
9
|
+
/** Search input placeholder */
|
|
10
|
+
searchPlaceholder?: string;
|
|
11
|
+
/** Called when search query changes */
|
|
12
|
+
onSearch?: (query: string) => void;
|
|
13
|
+
/** User avatar URL */
|
|
14
|
+
avatarUrl?: string;
|
|
15
|
+
/** User display name */
|
|
16
|
+
userName?: string;
|
|
17
|
+
/** Dropdown menu rendered on avatar click */
|
|
18
|
+
userDropdown?: React.ReactNode;
|
|
19
|
+
/** Toggle dark/light theme */
|
|
20
|
+
onToggleTheme?: () => void;
|
|
21
|
+
/** Current theme */
|
|
22
|
+
theme?: 'dark' | 'light';
|
|
23
|
+
/** Extra actions (buttons, etc.) rendered right of search */
|
|
24
|
+
actions?: React.ReactNode;
|
|
25
|
+
className?: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function Header({ breadcrumbs, searchPlaceholder, onSearch, avatarUrl, userName, userDropdown, onToggleTheme, theme, actions, className, }: HeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
//# sourceMappingURL=header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../../src/dash/header.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,uBAAuB;IACvB,WAAW,CAAC,EAAE,cAAc,EAAE,CAAA;IAC9B,+BAA+B;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC9B,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACxB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD,wBAAgB,MAAM,CAAC,EACrB,WAAW,EACX,iBAA+B,EAC/B,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,KAAc,EACd,OAAO,EACP,SAAS,GACV,EAAE,WAAW,2CAmIb"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../utils';
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Component */
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
export function Header({ breadcrumbs, searchPlaceholder = 'Search...', onSearch, avatarUrl, userName, userDropdown, onToggleTheme, theme = 'dark', actions, className, }) {
|
|
9
|
+
const [dropdownOpen, setDropdownOpen] = React.useState(false);
|
|
10
|
+
const dropdownRef = React.useRef(null);
|
|
11
|
+
// Close dropdown on outside click
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
if (!dropdownOpen)
|
|
14
|
+
return;
|
|
15
|
+
function handleClick(e) {
|
|
16
|
+
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
17
|
+
setDropdownOpen(false);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
document.addEventListener('mousedown', handleClick);
|
|
21
|
+
return () => document.removeEventListener('mousedown', handleClick);
|
|
22
|
+
}, [dropdownOpen]);
|
|
23
|
+
return (_jsxs("div", { className: cn('flex h-[var(--dash-header-height)] items-center gap-4 px-4', 'bg-[var(--dash-surface)] text-[var(--dash-text)]', className), children: [breadcrumbs && breadcrumbs.length > 0 && (_jsx("nav", { className: "flex items-center gap-1 text-sm", "aria-label": "Breadcrumb", children: breadcrumbs.map((crumb, i) => (_jsxs(React.Fragment, { children: [i > 0 && (_jsx("span", { className: "text-[var(--dash-text-dim)]", children: "/" })), crumb.href ? (_jsx("a", { href: crumb.href, className: "text-[var(--dash-text-muted)] hover:text-[var(--dash-text)] transition-colors", children: crumb.label })) : (_jsx("span", { className: "text-[var(--dash-text)]", children: crumb.label }))] }, i))) })), _jsx("div", { className: "flex-1" }), onSearch && (_jsxs("div", { className: "relative hidden sm:block", children: [_jsxs("svg", { className: "absolute left-2.5 top-1/2 -translate-y-1/2 text-[var(--dash-text-dim)]", width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [_jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5" }), _jsx("path", { d: "M11 11l3 3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] }), _jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch(e.target.value), className: cn('h-8 w-56 rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] pl-8 pr-3 text-sm text-[var(--dash-text)]', 'placeholder:text-[var(--dash-text-dim)]', 'focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]', 'transition-colors') })] })), actions, onToggleTheme && (_jsx("button", { type: "button", onClick: onToggleTheme, className: "rounded-[var(--dash-radius-sm)] p-1.5 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)] transition-colors", "aria-label": `Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`, children: theme === 'dark' ? (_jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [_jsx("circle", { cx: "8", cy: "8", r: "3.5", stroke: "currentColor", strokeWidth: "1.5" }), _jsx("path", { d: "M8 1v2M8 13v2M1 8h2M13 8h2M3.05 3.05l1.41 1.41M11.54 11.54l1.41 1.41M3.05 12.95l1.41-1.41M11.54 4.46l1.41-1.41", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })] })) : (_jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M14 9.5A6.5 6.5 0 016.5 2 5.5 5.5 0 1014 9.5z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })) })), (avatarUrl || userName) && (_jsxs("div", { className: "relative", ref: dropdownRef, children: [_jsx("button", { type: "button", onClick: () => setDropdownOpen((o) => !o), className: "flex items-center gap-2 rounded-[var(--dash-radius-sm)] p-1 hover:bg-[var(--dash-surface-hover)] transition-colors", children: avatarUrl ? (_jsx("img", { src: avatarUrl, alt: userName ?? 'User', className: "h-7 w-7 rounded-full object-cover" })) : (_jsx("div", { className: "flex h-7 w-7 items-center justify-center rounded-full bg-[var(--dash-primary)] text-xs font-medium text-[var(--dash-primary-text)]", children: (userName ?? '?')[0].toUpperCase() })) }), dropdownOpen && userDropdown && (_jsx("div", { className: "absolute right-0 top-full z-50 mt-1 min-w-48 rounded-[var(--dash-radius)] border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 shadow-lg", children: userDropdown }))] }))] }));
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hanzo/ui/dash
|
|
3
|
+
*
|
|
4
|
+
* Shared dash UI foundation. Dark-themed layout, navigation,
|
|
5
|
+
* data table, form builder, and CRUD components.
|
|
6
|
+
*
|
|
7
|
+
* Design tokens in tokens.css work in both React and Svelte.
|
|
8
|
+
*/
|
|
9
|
+
export { Layout } from './layout';
|
|
10
|
+
export type { LayoutProps } from './layout';
|
|
11
|
+
export { Sidebar } from './sidebar';
|
|
12
|
+
export type { SidebarProps, NavItem, NavGroup } from './sidebar';
|
|
13
|
+
export { Header } from './header';
|
|
14
|
+
export type { HeaderProps, BreadcrumbItem } from './header';
|
|
15
|
+
export { Table } from './table';
|
|
16
|
+
export type { TableProps, Column } from './table';
|
|
17
|
+
export { Form } from './form';
|
|
18
|
+
export type { FormProps, FieldDef, FieldType, FieldOption } from './form';
|
|
19
|
+
export { Crud } from './crud';
|
|
20
|
+
export type { CrudProps } from './crud';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dash/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAG3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAGhE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAG3D,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAGjD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC7B,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AAGzE,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC7B,YAAY,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hanzo/ui/dash
|
|
3
|
+
*
|
|
4
|
+
* Shared dash UI foundation. Dark-themed layout, navigation,
|
|
5
|
+
* data table, form builder, and CRUD components.
|
|
6
|
+
*
|
|
7
|
+
* Design tokens in tokens.css work in both React and Svelte.
|
|
8
|
+
*/
|
|
9
|
+
// Layout
|
|
10
|
+
export { Layout } from './layout';
|
|
11
|
+
// Sidebar
|
|
12
|
+
export { Sidebar } from './sidebar';
|
|
13
|
+
// Header
|
|
14
|
+
export { Header } from './header';
|
|
15
|
+
// Data Table
|
|
16
|
+
export { Table } from './table';
|
|
17
|
+
// Form
|
|
18
|
+
export { Form } from './form';
|
|
19
|
+
// CRUD
|
|
20
|
+
export { Crud } from './crud';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface LayoutProps {
|
|
3
|
+
/** Sidebar element (use Sidebar) */
|
|
4
|
+
sidebar: React.ReactNode;
|
|
5
|
+
/** Top header element (use Header) */
|
|
6
|
+
header?: React.ReactNode;
|
|
7
|
+
/** Main content */
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
/** Whether the sidebar is collapsed */
|
|
10
|
+
sidebarCollapsed?: boolean;
|
|
11
|
+
/** Callback when sidebar collapse state changes */
|
|
12
|
+
onSidebarCollapse?: (collapsed: boolean) => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function Layout({ sidebar, header, children, sidebarCollapsed, onSidebarCollapse, className, }: LayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/dash/layout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,sCAAsC;IACtC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,mBAAmB;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,mDAAmD;IACnD,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;IAChD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,MAAM,EACN,QAAQ,EACR,gBAAwB,EACxB,iBAAiB,EACjB,SAAS,GACV,EAAE,WAAW,2CAyCb"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../../utils';
|
|
4
|
+
export function Layout({ sidebar, header, children, sidebarCollapsed = false, onSidebarCollapse, className, }) {
|
|
5
|
+
return (_jsxs("div", { className: cn('flex h-screen overflow-hidden', 'bg-[var(--dash-bg)] text-[var(--dash-text)]', className), children: [_jsx("aside", { className: cn('flex-shrink-0 overflow-y-auto overflow-x-hidden transition-[width] duration-200', 'border-r border-[var(--dash-border)] bg-[var(--dash-surface)]', sidebarCollapsed
|
|
6
|
+
? 'w-[var(--dash-sidebar-collapsed-width)]'
|
|
7
|
+
: 'w-[var(--dash-sidebar-width)]'), children: sidebar }), _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [header && (_jsx("header", { className: "flex-shrink-0 border-b border-[var(--dash-border)] bg-[var(--dash-surface)]", children: header })), _jsx("main", { className: "flex-1 overflow-y-auto p-6", children: children })] }), !sidebarCollapsed && (_jsx("div", { className: "fixed inset-0 z-40 bg-black/60 lg:hidden", onClick: () => onSidebarCollapse?.(true) }))] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface NavItem {
|
|
3
|
+
label: string;
|
|
4
|
+
href: string;
|
|
5
|
+
icon?: React.ReactNode;
|
|
6
|
+
badge?: string | number;
|
|
7
|
+
active?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface NavGroup {
|
|
10
|
+
title?: string;
|
|
11
|
+
items: NavItem[];
|
|
12
|
+
collapsible?: boolean;
|
|
13
|
+
defaultOpen?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface SidebarProps {
|
|
16
|
+
/** Logo or brand element rendered at the top */
|
|
17
|
+
logo?: React.ReactNode;
|
|
18
|
+
/** Navigation groups */
|
|
19
|
+
groups: NavGroup[];
|
|
20
|
+
/** User menu rendered at the bottom */
|
|
21
|
+
userMenu?: React.ReactNode;
|
|
22
|
+
/** Whether the sidebar is collapsed (icon-only mode) */
|
|
23
|
+
collapsed?: boolean;
|
|
24
|
+
/** Toggle collapse */
|
|
25
|
+
onToggleCollapse?: () => void;
|
|
26
|
+
/** Called when a nav item is clicked */
|
|
27
|
+
onNavigate?: (href: string) => void;
|
|
28
|
+
className?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function Sidebar({ logo, groups, userMenu, collapsed, onToggleCollapse, onNavigate, className, }: SidebarProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
//# sourceMappingURL=sidebar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../../src/dash/sidebar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,wBAAwB;IACxB,MAAM,EAAE,QAAQ,EAAE,CAAA;IAClB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sBAAsB;IACtB,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC7B,wCAAwC;IACxC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AA2BD,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,SAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,SAAS,GACV,EAAE,YAAY,2CA+Dd"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../utils';
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Hanzo H mark (default logo) */
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
function HanzoMark({ size = 28 }) {
|
|
9
|
+
return (_jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M4 4h4v6h8V4h4v16h-4v-6H8v6H4V4z", fill: "currentColor" }) }));
|
|
10
|
+
}
|
|
11
|
+
/* ------------------------------------------------------------------ */
|
|
12
|
+
/* Component */
|
|
13
|
+
/* ------------------------------------------------------------------ */
|
|
14
|
+
export function Sidebar({ logo, groups, userMenu, collapsed = false, onToggleCollapse, onNavigate, className, }) {
|
|
15
|
+
return (_jsxs("nav", { className: cn('flex h-full flex-col', 'bg-[var(--dash-surface)] text-[var(--dash-text)]', className), children: [_jsxs("div", { className: cn('flex h-[var(--dash-header-height)] items-center border-b border-[var(--dash-border)]', collapsed ? 'justify-center px-2' : 'px-4'), children: [logo ?? _jsx(HanzoMark, {}), !collapsed && onToggleCollapse && (_jsx("button", { type: "button", onClick: onToggleCollapse, className: "ml-auto rounded p-1 text-[var(--dash-text-dim)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]", "aria-label": "Collapse sidebar", children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M10 4L6 8l4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })), collapsed && onToggleCollapse && (_jsx("button", { type: "button", onClick: onToggleCollapse, className: "absolute -right-3 top-4 z-50 hidden rounded-full border border-[var(--dash-border)] bg-[var(--dash-surface)] p-1 text-[var(--dash-text-dim)] hover:text-[var(--dash-text)] lg:flex", "aria-label": "Expand sidebar", children: _jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M6 4l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }))] }), _jsx("div", { className: "flex-1 overflow-y-auto py-2", children: groups.map((group, gi) => (_jsx(SidebarGroup, { group: group, collapsed: collapsed, onNavigate: onNavigate }, gi))) }), userMenu && (_jsx("div", { className: "border-t border-[var(--dash-border)] p-2", children: userMenu }))] }));
|
|
16
|
+
}
|
|
17
|
+
/* ------------------------------------------------------------------ */
|
|
18
|
+
/* SidebarGroup (internal) */
|
|
19
|
+
/* ------------------------------------------------------------------ */
|
|
20
|
+
function SidebarGroup({ group, collapsed, onNavigate, }) {
|
|
21
|
+
const [open, setOpen] = React.useState(group.defaultOpen !== false);
|
|
22
|
+
const isCollapsible = group.collapsible !== false && !!group.title;
|
|
23
|
+
return (_jsxs("div", { className: "mb-1", children: [group.title && !collapsed && (_jsxs("button", { type: "button", onClick: () => isCollapsible && setOpen((o) => !o), className: cn('flex w-full items-center px-4 py-1.5 text-[11px] font-semibold uppercase tracking-wider text-[var(--dash-text-dim)]', isCollapsible && 'cursor-pointer hover:text-[var(--dash-text-muted)]'), children: [_jsx("span", { className: "flex-1 text-left", children: group.title }), isCollapsible && (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", className: cn('transition-transform', open ? 'rotate-0' : '-rotate-90'), children: _jsx("path", { d: "M4 6l4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }))] })), (open || collapsed) && (_jsx("ul", { className: "space-y-0.5 px-2", children: group.items.map((item) => (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => onNavigate?.(item.href), title: collapsed ? item.label : undefined, className: cn('flex w-full items-center gap-2 rounded-[var(--dash-radius-sm)] px-2 py-1.5 text-sm transition-colors', item.active
|
|
24
|
+
? 'bg-[var(--dash-primary)] text-[var(--dash-primary-text)]'
|
|
25
|
+
: 'text-[var(--dash-text-muted)] hover:bg-[var(--dash-surface-hover)] hover:text-[var(--dash-text)]', collapsed && 'justify-center px-0'), children: [item.icon && (_jsx("span", { className: "flex h-5 w-5 items-center justify-center flex-shrink-0", children: item.icon })), !collapsed && _jsx("span", { className: "flex-1 truncate text-left", children: item.label }), !collapsed && item.badge !== undefined && (_jsx("span", { className: "ml-auto rounded-full bg-[var(--dash-primary)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--dash-primary-text)]", children: item.badge }))] }) }, item.href))) }))] }));
|
|
26
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface Column<T> {
|
|
3
|
+
id: string;
|
|
4
|
+
header: string;
|
|
5
|
+
/** Render cell content. Falls back to (row as any)[id]. */
|
|
6
|
+
cell?: (row: T) => React.ReactNode;
|
|
7
|
+
/** Enable sorting on this column */
|
|
8
|
+
sortable?: boolean;
|
|
9
|
+
/** Width hint (CSS value) */
|
|
10
|
+
width?: string;
|
|
11
|
+
/** Alignment */
|
|
12
|
+
align?: 'left' | 'center' | 'right';
|
|
13
|
+
}
|
|
14
|
+
export interface TableProps<T> {
|
|
15
|
+
/** Column definitions */
|
|
16
|
+
columns: Column<T>[];
|
|
17
|
+
/** Row data */
|
|
18
|
+
data: T[];
|
|
19
|
+
/** Unique key extractor per row */
|
|
20
|
+
rowKey: (row: T) => string;
|
|
21
|
+
/** Enable row selection checkboxes */
|
|
22
|
+
selectable?: boolean;
|
|
23
|
+
/** Currently selected row keys */
|
|
24
|
+
selectedKeys?: Set<string>;
|
|
25
|
+
/** Called when selection changes */
|
|
26
|
+
onSelectionChange?: (keys: Set<string>) => void;
|
|
27
|
+
/** Searchable - shows search input above table */
|
|
28
|
+
searchable?: boolean;
|
|
29
|
+
/** Search placeholder */
|
|
30
|
+
searchPlaceholder?: string;
|
|
31
|
+
/** Pagination: total rows available (may exceed data.length for server pagination) */
|
|
32
|
+
totalRows?: number;
|
|
33
|
+
/** Current page (0-indexed) */
|
|
34
|
+
page?: number;
|
|
35
|
+
/** Rows per page */
|
|
36
|
+
pageSize?: number;
|
|
37
|
+
/** Called when page changes */
|
|
38
|
+
onPageChange?: (page: number) => void;
|
|
39
|
+
/** Called when page size changes */
|
|
40
|
+
onPageSizeChange?: (size: number) => void;
|
|
41
|
+
/** Actions column renderer (edit, delete buttons etc.) */
|
|
42
|
+
actions?: (row: T) => React.ReactNode;
|
|
43
|
+
/** Loading state */
|
|
44
|
+
loading?: boolean;
|
|
45
|
+
/** Empty state message */
|
|
46
|
+
emptyMessage?: string;
|
|
47
|
+
className?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function Table<T>({ columns, data, rowKey, selectable, selectedKeys, onSelectionChange, searchable, searchPlaceholder, totalRows, page, pageSize, onPageChange, onPageSizeChange, actions, loading, emptyMessage, className, }: TableProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
//# sourceMappingURL=table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/dash/table.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,MAAM,WAAW,MAAM,CAAC,CAAC;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IAClC,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;IACpB,eAAe;IACf,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,mCAAmC;IACnC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAA;IAC1B,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kCAAkC;IAClC,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC1B,oCAAoC;IACpC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,CAAA;IAC/C,kDAAkD;IAClD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,yBAAyB;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+BAA+B;IAC/B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACrC,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC,0DAA0D;IAC1D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,CAAC,SAAS,CAAA;IACrC,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAQD,wBAAgB,KAAK,CAAC,CAAC,EAAE,EACvB,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,UAAkB,EAClB,iBAA+B,EAC/B,SAAS,EACT,IAAQ,EACR,QAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,OAAO,EACP,OAAe,EACf,YAAwB,EACxB,SAAS,GACV,EAAE,UAAU,CAAC,CAAC,CAAC,2CAyPf"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../utils';
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Component */
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
export function Table({ columns, data, rowKey, selectable = false, selectedKeys, onSelectionChange, searchable = false, searchPlaceholder = 'Search...', totalRows, page = 0, pageSize = 20, onPageChange, onPageSizeChange, actions, loading = false, emptyMessage = 'No data', className, }) {
|
|
9
|
+
const [search, setSearch] = React.useState('');
|
|
10
|
+
const [sort, setSort] = React.useState(null);
|
|
11
|
+
/* ---------- filtering ---------- */
|
|
12
|
+
const filtered = React.useMemo(() => {
|
|
13
|
+
if (!search)
|
|
14
|
+
return data;
|
|
15
|
+
const q = search.toLowerCase();
|
|
16
|
+
return data.filter((row) => columns.some((col) => {
|
|
17
|
+
const val = col.cell ? '' : String(row[col.id] ?? '');
|
|
18
|
+
return val.toLowerCase().includes(q);
|
|
19
|
+
}));
|
|
20
|
+
}, [data, search, columns]);
|
|
21
|
+
/* ---------- sorting ---------- */
|
|
22
|
+
const sorted = React.useMemo(() => {
|
|
23
|
+
if (!sort)
|
|
24
|
+
return filtered;
|
|
25
|
+
const { column, direction } = sort;
|
|
26
|
+
return [...filtered].sort((a, b) => {
|
|
27
|
+
const av = a[column];
|
|
28
|
+
const bv = b[column];
|
|
29
|
+
if (av == null && bv == null)
|
|
30
|
+
return 0;
|
|
31
|
+
if (av == null)
|
|
32
|
+
return 1;
|
|
33
|
+
if (bv == null)
|
|
34
|
+
return -1;
|
|
35
|
+
const cmp = String(av).localeCompare(String(bv), undefined, { numeric: true });
|
|
36
|
+
return direction === 'asc' ? cmp : -cmp;
|
|
37
|
+
});
|
|
38
|
+
}, [filtered, sort]);
|
|
39
|
+
/* ---------- pagination ---------- */
|
|
40
|
+
const total = totalRows ?? sorted.length;
|
|
41
|
+
const totalPages = Math.max(1, Math.ceil(total / pageSize));
|
|
42
|
+
const rows = onPageChange ? sorted : sorted.slice(page * pageSize, (page + 1) * pageSize);
|
|
43
|
+
/* ---------- selection ---------- */
|
|
44
|
+
const selected = selectedKeys ?? new Set();
|
|
45
|
+
const allSelected = rows.length > 0 && rows.every((r) => selected.has(rowKey(r)));
|
|
46
|
+
function toggleAll() {
|
|
47
|
+
if (!onSelectionChange)
|
|
48
|
+
return;
|
|
49
|
+
if (allSelected) {
|
|
50
|
+
onSelectionChange(new Set());
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
onSelectionChange(new Set(rows.map(rowKey)));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function toggleRow(key) {
|
|
57
|
+
if (!onSelectionChange)
|
|
58
|
+
return;
|
|
59
|
+
const next = new Set(selected);
|
|
60
|
+
if (next.has(key)) {
|
|
61
|
+
next.delete(key);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
next.add(key);
|
|
65
|
+
}
|
|
66
|
+
onSelectionChange(next);
|
|
67
|
+
}
|
|
68
|
+
function handleSort(colId) {
|
|
69
|
+
setSort((prev) => {
|
|
70
|
+
if (prev?.column === colId) {
|
|
71
|
+
return prev.direction === 'asc' ? { column: colId, direction: 'desc' } : null;
|
|
72
|
+
}
|
|
73
|
+
return { column: colId, direction: 'asc' };
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const allColumns = actions
|
|
77
|
+
? [...columns, { id: '__actions', header: '', width: 'auto' }]
|
|
78
|
+
: columns;
|
|
79
|
+
return (_jsxs("div", { className: cn('rounded-[var(--dash-radius-lg)] border border-[var(--dash-border)] bg-[var(--dash-surface)]', className), children: [(searchable || selectable) && (_jsxs("div", { className: "flex items-center gap-3 border-b border-[var(--dash-border)] px-4 py-3", children: [searchable && (_jsx("input", { type: "text", placeholder: searchPlaceholder, value: search, onChange: (e) => setSearch(e.target.value), className: cn('h-8 w-64 max-w-full rounded-[var(--dash-radius-sm)] border border-[var(--dash-border)] bg-[var(--dash-bg)] px-3 text-sm text-[var(--dash-text)]', 'placeholder:text-[var(--dash-text-dim)]', 'focus:border-[var(--dash-primary)] focus:outline-none focus:ring-1 focus:ring-[var(--dash-primary)]') })), selectable && selected.size > 0 && (_jsxs("span", { className: "text-xs text-[var(--dash-text-muted)]", children: [selected.size, " selected"] }))] })), _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-[var(--dash-border)]", children: [selectable && (_jsx("th", { className: "w-10 px-4 py-2.5", children: _jsx("input", { type: "checkbox", checked: allSelected, onChange: toggleAll, className: "h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]" }) })), allColumns.map((col) => (_jsx("th", { style: col.width ? { width: col.width } : undefined, className: cn('px-4 py-2.5 text-[var(--dash-text-dim)] font-medium', col.align === 'center' && 'text-center', col.align === 'right' && 'text-right', !col.align && 'text-left', col.sortable && 'cursor-pointer select-none hover:text-[var(--dash-text-muted)]'), onClick: col.sortable ? () => handleSort(col.id) : undefined, children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [col.header, col.sortable && sort?.column === col.id && (_jsx("span", { className: "text-[10px]", children: sort.direction === 'asc' ? '\u2191' : '\u2193' }))] }) }, col.id)))] }) }), _jsx("tbody", { children: loading ? (_jsx("tr", { children: _jsx("td", { colSpan: allColumns.length + (selectable ? 1 : 0), className: "px-4 py-8 text-center text-[var(--dash-text-dim)]", children: "Loading..." }) })) : rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: allColumns.length + (selectable ? 1 : 0), className: "px-4 py-8 text-center text-[var(--dash-text-dim)]", children: emptyMessage }) })) : (rows.map((row) => {
|
|
80
|
+
const key = rowKey(row);
|
|
81
|
+
const isSelected = selected.has(key);
|
|
82
|
+
return (_jsxs("tr", { className: cn('border-b border-[var(--dash-border)] transition-colors', isSelected
|
|
83
|
+
? 'bg-[var(--dash-surface-active)]'
|
|
84
|
+
: 'hover:bg-[var(--dash-surface-hover)]'), children: [selectable && (_jsx("td", { className: "w-10 px-4 py-2.5", children: _jsx("input", { type: "checkbox", checked: isSelected, onChange: () => toggleRow(key), className: "h-4 w-4 rounded border-[var(--dash-border)] accent-[var(--dash-primary)]" }) })), columns.map((col) => (_jsx("td", { className: cn('px-4 py-2.5', col.align === 'center' && 'text-center', col.align === 'right' && 'text-right'), children: col.cell
|
|
85
|
+
? col.cell(row)
|
|
86
|
+
: String(row[col.id] ?? '') }, col.id))), actions && (_jsx("td", { className: "px-4 py-2.5 text-right", children: actions(row) }))] }, key));
|
|
87
|
+
})) })] }) }), totalPages > 1 && (_jsxs("div", { className: "flex items-center justify-between border-t border-[var(--dash-border)] px-4 py-2.5 text-xs text-[var(--dash-text-muted)]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { children: "Rows per page" }), _jsx("select", { value: pageSize, onChange: (e) => onPageSizeChange?.(Number(e.target.value)), className: "h-7 rounded border border-[var(--dash-border)] bg-[var(--dash-bg)] px-2 text-xs text-[var(--dash-text)] focus:outline-none", children: [10, 20, 50, 100].map((n) => (_jsx("option", { value: n, children: n }, n))) })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("span", { children: ["Page ", page + 1, " of ", totalPages] }), _jsx("button", { type: "button", disabled: page === 0, onClick: () => onPageChange?.(page - 1), className: "rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed", children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M10 4L6 8l4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) }), _jsx("button", { type: "button", disabled: page >= totalPages - 1, onClick: () => onPageChange?.(page + 1), className: "rounded p-1 hover:bg-[var(--dash-surface-hover)] disabled:opacity-30 disabled:cursor-not-allowed", children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M6 4l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }))] }));
|
|
88
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.1",
|
|
4
4
|
"description": "Multi-framework UI library with React, Vue, Svelte, and React Native support. Based on shadcn/ui with comprehensive framework coverage.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org/",
|
|
@@ -255,6 +255,17 @@
|
|
|
255
255
|
"import": "./dist/drawer.mjs",
|
|
256
256
|
"require": "./dist/drawer.js"
|
|
257
257
|
},
|
|
258
|
+
"./dash": {
|
|
259
|
+
"types": "./dist/dash/index.d.ts",
|
|
260
|
+
"import": "./dist/dash/index.mjs",
|
|
261
|
+
"require": "./dist/dash/index.js"
|
|
262
|
+
},
|
|
263
|
+
"./dash/tokens.css": "./src/dash/tokens.css",
|
|
264
|
+
"./dash/*": {
|
|
265
|
+
"types": "./dist/dash/*.d.ts",
|
|
266
|
+
"import": "./dist/dash/*.mjs",
|
|
267
|
+
"require": "./dist/dash/*.js"
|
|
268
|
+
},
|
|
258
269
|
"./billing": {
|
|
259
270
|
"types": "./dist/billing/index.d.ts",
|
|
260
271
|
"import": "./dist/billing/index.mjs",
|