@bobbykim/manguito-cms-admin 0.5.0 → 0.5.2
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/assets/{ChangePasswordView-RhnQhTpj.js → ChangePasswordView-v3tSL_0C.js} +1 -1
- package/dist/assets/ContentFormView-DneaTAaq.js +1 -0
- package/dist/assets/{ContentListView-52Vdrqg6.js → ContentListView-i3MwjmNq.js} +1 -1
- package/dist/assets/{ContentSettingsView-vDV6xaxT.js → ContentSettingsView-4cpotfsZ.js} +1 -1
- package/dist/assets/{LoginView-y0TQTfvj.js → LoginView-BObIe0zr.js} +1 -1
- package/dist/assets/{MediaDetailView-CFGRX94J.js → MediaDetailView-BKTDY6Ne.js} +1 -1
- package/dist/assets/MediaLibraryView-DojOE-wL.js +1 -0
- package/dist/assets/MediaThumbnail-Ckiw3oQ9.js +1 -0
- package/dist/assets/TaxonomyFormView-Chd_LUly.js +1 -0
- package/dist/assets/{TaxonomyListView-COqfCnDR.js → TaxonomyListView-Cy3iI1oC.js} +1 -1
- package/dist/assets/{UserFormView-G2pzRNAl.js → UserFormView-B2m4OdJV.js} +1 -1
- package/dist/assets/{UserListView-BlP10YCt.js → UserListView-z6weJ8UF.js} +1 -1
- package/dist/assets/field-defaults-DLoPESiE.js +97 -0
- package/dist/assets/{index-ivedPYqQ.css → index-C4qBpxpk.css} +1 -1
- package/dist/assets/{index-GvXDeXi5.js → index-stKCwnA4.js} +2 -2
- package/dist/assets/{useNotification-DXsAIQaa.js → useNotification-BdRk9gQY.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +2 -2
- package/src/components/fields/MediaUpload.vue +5 -19
- package/src/components/shared/MediaSelectModal.vue +4 -21
- package/src/components/shared/MediaThumbnail.vue +108 -0
- package/src/components/shared/__tests__/MediaThumbnail.test.ts +118 -0
- package/src/utils/__tests__/file-kind.test.ts +102 -0
- package/src/utils/__tests__/taxonomy-form.test.ts +17 -18
- package/src/utils/file-kind.ts +83 -0
- package/src/utils/taxonomy-form.ts +7 -15
- package/src/views/media/MediaLibraryView.vue +7 -22
- package/src/views/taxonomy/TaxonomyFormView.vue +2 -27
- package/src/views/taxonomy/__tests__/TaxonomyFormView.test.ts +71 -0
- package/dist/assets/ContentFormView-Ch9JVUWn.js +0 -1
- package/dist/assets/MediaLibraryView-WCKhSv_6.js +0 -1
- package/dist/assets/TaxonomyFormView-B2__-WRX.js +0 -1
- package/dist/assets/field-defaults-BTA4TEHe.js +0 -97
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{B as e,E as t,O as n,P as r,W as i,c as a,ct as o,d as s,g as c,h as ee,i as l,j as te,l as ne,lt as u,m as d,s as re,u as f,ut as p,w as ie}from"./schema-B-RKX_ep.js";import{c as ae,d as oe,n as se,r as ce,t as le,u as ue}from"./index-GvXDeXi5.js";import{t as de}from"./useNotification-DXsAIQaa.js";import{t as fe}from"./ConfirmDialog-B7nxdDge.js";import{t as pe}from"./useTabIndicator-CvEsGBJh.js";import{t as me}from"./Pagination-BIf7mQy7.js";import{t as he}from"./media-DvQfZD4o.js";var m={class:`mb-[18px] flex flex-wrap items-center justify-between gap-4`},ge={key:0},_e={key:0,class:`mb-5 rounded-md border border-gray-200 bg-white p-4 shadow-sm`},ve={key:0,class:`space-y-3`},ye={class:`text-sm font-medium text-gray-700`},be={class:`flex gap-2`},xe=[`disabled`],Se={key:1,class:`space-y-2`},Ce={class:`text-sm text-gray-500`},we={class:`flex items-center gap-2`},h={class:`h-2 flex-1 overflow-hidden rounded-full bg-gray-100`},g={class:`w-8 shrink-0 text-right text-xs text-gray-500`},_={key:2,class:`mt-2 text-sm text-red-600`,role:`alert`},v=[`data-tab`,`onClick`],y={key:1,class:`mb-3 flex items-center gap-3`},b={class:`flex cursor-pointer items-center gap-2 text-sm text-gray-600`},x=[`checked`,`indeterminate`],S={key:2,class:`grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6`},C={key:3,class:`rounded-2xl border border-dashed border-gray-300 p-12 text-center`},w={class:`text-sm text-muted`},T={key:4,class:`grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6`},E=[`checked`,`onChange`],D=[`aria-label`,`onClick`],O=[`src`,`alt`],k={key:1,class:`flex h-full w-full flex-col items-center justify-center gap-1 bg-gray-50 p-1 text-gray-400`},Te={class:`text-3xl`,"aria-hidden":`true`},Ee={class:`max-w-full truncate text-center text-xs`},De={class:`text-xs text-gray-300`},Oe={key:5,class:`mt-5 flex justify-center`},A=20,j=c({__name:`MediaLibraryView`,setup(c){let j=ae(),M=le(),{can:N}=se(),P=de(),ke=ce(),F=he(),I=e(`all`),L=re(()=>I.value===`orphaned`),Ae=[{value:`all`,label:`All`},{value:`image`,label:`Images`},{value:`video`,label:`Videos`},{value:`file`,label:`PDFs`},{value:`orphaned`,label:`Orphaned`}],R=e(null),{left:je,width:Me}=pe(R,I),z=e([]),B=e(0),V=e(1),H=e(!1);function Ne(e,t){let n=new URLSearchParams({page:String(t),per_page:String(A)});return e===`orphaned`?n.set(`orphaned`,`true`):e!==`all`&&n.set(`type`,e),`/media?${n.toString()}`}async function U(e,t){H.value=!0;let n=await M.get(Ne(e,t));H.value=!1,n.ok&&(z.value=n.data,B.value=n.meta?.total??n.data.length,F.setItems(n.data))}ie(()=>{U(I.value,V.value)}),te(I,e=>{V.value=1,W.value.clear(),U(e,1)});function Pe(e){V.value=e,U(I.value,e)}function Fe(e){j.push({name:`media-detail`,params:{id:e}})}let W=e(new Set),G=e(!1);function Ie(e){W.value.has(e)?W.value.delete(e):W.value.add(e)}function Le(){W.value.size===z.value.length?W.value.clear():W.value=new Set(z.value.map(e=>e.id))}async function Re(){G.value=!1;let e=[...W.value];for(let t of e)await M.del(`/media/${t}`),F.removeItem(t);z.value=z.value.filter(t=>!e.includes(t.id)),B.value=Math.max(0,B.value-e.length),W.value.clear(),P.success(`Deleted ${e.length} item${e.length===1?``:`s`}.`)}let K=e(`idle`),q=e(null),J=e(`file`),Y=e(``),X=e(0),Z=e(``),Q=e(null);function ze(e){return e.type.startsWith(`image/`)?`image`:e.type.startsWith(`video/`)?`video`:`file`}function Be(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function Ve(e){let t=e.target.files?.[0];t&&(e.target.value=``,q.value=t,J.value=ze(t),Y.value=``,Z.value=``,J.value===`image`?$(t):K.value=`alt-collect`)}function He(e,t){return new Promise((n,r)=>{let i=new FormData;i.append(`file`,e),t&&i.append(`alt`,t);let a=new XMLHttpRequest;a.withCredentials=!0,a.open(`POST`,`/admin/api/media/${J.value}`),a.upload.onprogress=e=>{e.lengthComputable&&(X.value=Math.round(e.loaded/e.total*100))},a.onload=()=>{try{let e=JSON.parse(a.responseText);e.ok&&e.data?n(e.data):r(Error(e.error?.message??`Upload failed`))}catch{r(Error(`Invalid server response`))}},a.onerror=()=>r(Error(`Network error`)),a.send(i)})}async function Ue(e,t){let n=new URLSearchParams({type:J.value,filename:e.name,mime_type:e.type}),r=await(await fetch(`/admin/api/media/presigned-url?${n.toString()}`,{credentials:`include`})).json();if(!r.ok||!r.data)throw Error(r.error?.message??`Failed to get upload URL`);let{upload_url:i,media_id:a,method:o,fields:s}=r.data;await new Promise((t,n)=>{let r=new XMLHttpRequest;if(r.upload.onprogress=e=>{e.lengthComputable&&(X.value=Math.round(e.loaded/e.total*100))},r.onload=()=>r.status>=200&&r.status<300?t():n(Error(`Storage upload failed (${r.status})`)),r.onerror=()=>n(Error(`Network error`)),o===`POST`&&s){let t=new FormData;for(let[e,n]of Object.entries(s))t.append(e,n);t.append(`file`,e),r.open(`POST`,i),r.send(t)}else r.open(`PUT`,i),r.send(e)});let c=await(await fetch(`/admin/api/media/confirm/${a}`,{method:`POST`,credentials:`include`,headers:{"Content-Type":`application/json`},body:JSON.stringify({alt:t})})).json();if(!c.ok||!c.data)throw Error(c.error?.message??`Upload confirmation failed`);return c.data}async function $(e){K.value=`uploading`,X.value=0,Z.value=``;try{let t=Y.value.trim(),n=ke.presignedUploads?await Ue(e,t):await He(e,t);z.value=[n,...z.value],B.value+=1,F.setItem(n),P.success(`Upload complete.`)}catch(e){Z.value=e instanceof Error?e.message:`Upload failed`}finally{K.value=`idle`,q.value=null}}function We(){q.value&&$(q.value)}function Ge(){q.value=null,Y.value=``,Z.value=``,K.value=`idle`}return(e,c)=>(t(),s(`div`,null,[a(`div`,m,[c[5]||=a(`h1`,{class:`text-[26px] font-bold tracking-tight text-ink`},`Media library`,-1),i(N)(`media:create`)?(t(),s(`div`,ge,[a(`input`,{ref_key:`fileInputRef`,ref:Q,type:`file`,class:`hidden`,accept:`image/*,video/*,application/pdf,.pdf`,onChange:Ve},null,544),a(`button`,{type:`button`,class:`inline-flex items-center gap-1.75 rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)]`,onClick:c[0]||=e=>Q.value?.click()},[...c[4]||=[a(`svg`,{width:`16`,height:`16`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.9`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[a(`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`}),a(`path`,{d:`M17 8l-5-5-5 5`}),a(`path`,{d:`M12 3v12`})],-1),d(` Upload `,-1)]])])):f(``,!0)]),K.value===`idle`?f(``,!0):(t(),s(`div`,_e,[K.value===`alt-collect`?(t(),s(`div`,ve,[a(`p`,ye,p(q.value?.name),1),a(`div`,null,[c[6]||=a(`label`,{for:`upload-alt`,class:`block text-xs text-gray-600`},[d(` Alt text `),a(`span`,{class:`text-red-500`},`*`)],-1),r(a(`input`,{id:`upload-alt`,"onUpdate:modelValue":c[1]||=e=>Y.value=e,type:`text`,placeholder:`Describe this file`,class:`mt-0.5 block w-full rounded-md border border-gray-300 px-3 py-1.5 text-sm shadow-sm focus:border-indigo-400 focus:outline-none focus:ring-2 focus:ring-indigo-200`},null,512),[[ue,Y.value]])]),a(`div`,be,[a(`button`,{type:`button`,class:`rounded-md px-3 py-1.5 text-sm text-gray-600 ring-1 ring-inset ring-gray-300 hover:bg-gray-50`,onClick:Ge},` Cancel `),a(`button`,{type:`button`,disabled:!Y.value.trim(),class:`rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-indigo-700 disabled:cursor-not-allowed disabled:opacity-50`,onClick:We},` Upload `,8,xe)])])):K.value===`uploading`?(t(),s(`div`,Se,[a(`p`,Ce,`Uploading`+p(q.value?` ${q.value.name}`:`…`),1),a(`div`,we,[a(`div`,h,[a(`div`,{class:`h-2 rounded-full bg-indigo-600 transition-all duration-150`,style:u({width:`${X.value}%`})},null,4)]),a(`span`,g,p(X.value)+`%`,1)])])):f(``,!0),Z.value?(t(),s(`p`,_,p(Z.value),1)):f(``,!0)])),a(`div`,{ref_key:`tabBarRef`,ref:R,class:`relative mb-[22px] flex gap-0 overflow-x-auto border-b border-card-border`},[(t(),s(l,null,n(Ae,e=>a(`button`,{key:e.value,"data-tab":e.value,type:`button`,class:o([`mr-[22px] whitespace-nowrap bg-none px-0.5 py-[11px] text-sm transition-colors`,I.value===e.value?`font-semibold text-indigo-600`:`font-medium text-faint hover:text-[#8A8A9E]`]),onClick:t=>I.value=e.value},p(e.label),11,v)),64)),a(`div`,{class:`absolute bottom-[-1px] h-[2px] rounded-full bg-indigo-600 transition-[left,width] duration-300`,style:u({left:`${i(je)}px`,width:`${i(Me)}px`})},null,4)],512),L.value&&z.value.length>0&&i(N)(`media:delete`)?(t(),s(`div`,y,[a(`label`,b,[a(`input`,{type:`checkbox`,checked:W.value.size===z.value.length&&z.value.length>0,indeterminate:W.value.size>0&&W.value.size<z.value.length,class:`rounded border-gray-300 text-indigo-600 focus:ring-indigo-500`,onChange:Le},null,40,x),c[7]||=d(` Select all `,-1)]),W.value.size>0?(t(),s(`button`,{key:0,type:`button`,class:`rounded-md bg-red-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-red-700`,onClick:c[2]||=e=>G.value=!0},` Delete `+p(W.value.size)+` selected `,1)):f(``,!0)])):f(``,!0),H.value?(t(),s(`div`,S,[(t(),s(l,null,n(12,e=>a(`div`,{key:e,class:`aspect-square animate-pulse rounded-[14px] bg-gray-100`})),64))])):z.value.length===0?(t(),s(`div`,C,[a(`p`,w,p(L.value?`No orphaned files.`:`No media files yet.`),1)])):(t(),s(`div`,T,[(t(!0),s(l,null,n(z.value,e=>(t(),s(`div`,{key:e.id,class:`group relative aspect-square`},[L.value&&i(N)(`media:delete`)?(t(),s(`label`,{key:0,class:`absolute left-1.5 top-1.5 z-10 cursor-pointer`,onClick:c[3]||=oe(()=>{},[`stop`])},[a(`input`,{type:`checkbox`,checked:W.value.has(e.id),class:`rounded border-gray-300 bg-white text-indigo-600 shadow focus:ring-indigo-500`,onChange:t=>Ie(e.id)},null,40,E)])):f(``,!0),a(`button`,{type:`button`,class:`h-full w-full overflow-hidden rounded-[14px] border border-card-border shadow-[0_1px_2px_rgba(24,24,48,0.04),0_8px_22px_rgba(24,24,48,0.05)] transition-all hover:-translate-y-[3px] hover:shadow-[0_12px_30px_rgba(24,24,48,0.12)] focus:outline-none focus:ring-2 focus:ring-indigo-500`,"aria-label":`View ${e.alt??e.url.split(`/`).pop()}`,onClick:t=>Fe(e.id)},[e.type===`image`?(t(),s(`img`,{key:0,src:e.url,alt:e.alt??``,class:`h-full w-full object-cover`,loading:`lazy`},null,8,O)):(t(),s(`div`,k,[a(`span`,Te,p(e.type===`video`?`▶`:`📄`),1),a(`span`,Ee,p(e.url.split(`/`).pop()),1),a(`span`,De,p(Be(e.file_size)),1)]))],8,D)]))),128))])),!H.value&&B.value>A?(t(),s(`div`,Oe,[ee(me,{total:B.value,page:V.value,"per-page":A,"onUpdate:page":Pe},null,8,[`total`,`page`])])):f(``,!0),G.value?(t(),ne(fe,{key:6,message:`Permanently delete ${W.value.size} file${W.value.size===1?``:`s`}? This cannot be undone.`,"on-confirm":Re,"on-cancel":()=>G.value=!1},null,8,[`message`,`on-cancel`])):f(``,!0)]))}});export{j as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as e,B as t,E as n,O as r,W as i,c as a,d as o,g as s,i as ee,j as c,l,s as u,t as te,u as d,ut as f,w as ne}from"./schema-B-RKX_ep.js";import{c as re,n as ie,s as ae,t as oe}from"./index-GvXDeXi5.js";import{a as se,c as ce,i as le,l as p,n as ue,o as de,s as m,t as h,u as g}from"./field-defaults-BTA4TEHe.js";import{t as _}from"./useNotification-DXsAIQaa.js";import{t as v}from"./ConfirmDialog-B7nxdDge.js";import{t as y}from"./taxonomy-DC-6wyg3.js";function b(e){return e.field_type===`programmatic`?!1:e.db_column!==null&&!e.db_column.junction}function fe(e,t){let n={};for(let r of e)b(r)&&(n[r.name]=t?.[r.name]??h(r));return n}var x={key:0,class:`flex items-center justify-center py-20`},S={key:1,class:`py-12 text-center text-sm text-gray-500`},C={key:2},w={class:`mb-6 flex items-start justify-between gap-4`},T={class:`text-xs font-medium uppercase tracking-wide text-gray-400`},E={class:`text-[26px] font-bold tracking-tight text-ink`},D={class:`flex shrink-0 items-center gap-2`},O=[`disabled`],k=[`disabled`],A={class:`space-y-5`},j={key:0,class:`mt-4 text-sm text-red-600`,role:`alert`},M=s({__name:`TaxonomyFormView`,setup(s){let h=ae(),b=re(),M=oe(),{can:N}=ie(),{errors:P,validate:F,mergeServerErrors:I,clearErrors:L,setError:R}=g(),z=_(),pe=te(),B=y(),V=u(()=>h.params.type),H=u(()=>h.params.id),U=u(()=>!!H.value),W=u(()=>pe.taxonomyTypes[V.value]),G=u(()=>W.value?.fields??[]),K=t(null),q=t({}),J=t(!0),Y=t(!1),X=t(``),Z=t(!1),me={"text/plain":p,"text/rich":ce,integer:m,float:m,boolean:de,date:se,enum:le,programmatic:ue};function he(e){let t=e.field_type;return me[t]??p}function Q(e){q.value=fe(G.value,e)}function ge(e,t){q.value[e]=t}async function $(e){let t=await M.get(`/taxonomy/${V.value}/${e}`);t.ok?(K.value=t.data,Q(t.data)):X.value=t.error.message}ne(async()=>{if(!W.value){J.value=!1;return}U.value&&H.value?await $(H.value):Q(),J.value=!1}),c(H,async(e,t)=>{e!==t&&(J.value=!0,L(),e?await $(e):(K.value=null,Q()),J.value=!1)});async function _e(){if(!F(G.value,q.value))return;Y.value=!0,X.value=``;let e=U.value?await M.patch(`/taxonomy/${V.value}/${H.value}`,q.value):await M.post(`/taxonomy/${V.value}`,q.value);if(Y.value=!1,!e.ok){let t=e.error;t.code===`PUBLISH_VALIDATION_ERROR`&&t.details?I(t.details):t.code===`SLUG_CONFLICT`?R(`slug`,`This slug is already taken.`):X.value=t.message;return}K.value=e.data,B.invalidate(V.value),z.success(`Saved.`),U.value||b.replace({name:`taxonomy-edit`,params:{type:V.value,id:String(e.data.id)}})}async function ve(){Z.value=!1,Y.value=!0;let e=await M.del(`/taxonomy/${V.value}/${H.value}`);if(Y.value=!1,!e.ok){X.value=e.error.message;return}B.invalidate(V.value),b.push({name:`taxonomy-list`,params:{type:V.value}})}let ye=u(()=>{if(!U.value)return`New ${W.value?.label??``}`;let e=G.value.find(e=>e.field_type===`text/plain`);return e?String(K.value?.[e.name]??``):W.value?.label??``});return(t,s)=>J.value?(n(),o(`div`,x,[...s[1]||=[a(`span`,{class:`inline-block h-6 w-6 animate-spin rounded-full border-2 border-indigo-600 border-t-transparent`,"aria-hidden":`true`},null,-1)]])):W.value?(n(),o(`div`,C,[a(`div`,w,[a(`div`,null,[a(`p`,T,f(W.value.label),1),a(`h1`,E,f(ye.value),1)]),a(`div`,D,[i(N)(`taxonomy:delete`)&&U.value?(n(),o(`button`,{key:0,type:`button`,disabled:Y.value,class:`rounded-md px-3 py-2 text-sm font-medium text-red-600 ring-1 ring-inset ring-red-300 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-50`,onClick:s[0]||=e=>Z.value=!0},` Delete `,8,O)):d(``,!0),(U.value?i(N)(`taxonomy:edit`):i(N)(`taxonomy:create`))?(n(),o(`button`,{key:1,type:`button`,disabled:Y.value,class:`rounded-[11px] bg-indigo-600 px-4 py-2.5 text-[13.5px] font-semibold text-white shadow-[0_3px_10px_rgba(91,87,232,0.3)] transition-all hover:bg-indigo-700 hover:shadow-[0_6px_18px_rgba(91,87,232,0.4)] disabled:cursor-not-allowed disabled:opacity-50`,onClick:_e},f(Y.value?`Saving…`:`Save`),9,k)):d(``,!0)])]),a(`div`,A,[(n(!0),o(ee,null,r(G.value,t=>(n(),l(e(he(t)),{key:t.name,field:t,"model-value":q.value[t.name],error:i(P)[t.name],disabled:Y.value,"onUpdate:modelValue":e=>ge(t.name,e)},null,8,[`field`,`model-value`,`error`,`disabled`,`onUpdate:modelValue`]))),128))]),X.value?(n(),o(`p`,j,f(X.value),1)):d(``,!0),Z.value?(n(),l(v,{key:1,message:`Are you sure you want to delete this term? This action cannot be undone.`,"on-confirm":ve,"on-cancel":()=>Z.value=!1},null,8,[`on-cancel`])):d(``,!0)])):(n(),o(`div`,S,` Taxonomy type not found. `))}});export{M as default};
|