Files
pictureFrame-webApp/public/build/assets/LibraryView-B6wq42Vx.js
T
football2801 cbb5bb1ff3
CI / test (push) Has been cancelled
feat: surface orientation-mismatch warning in the library
Each thumbnail now shows a yellow warning triangle in its action stack
when at least one approved device's orientation does not match the
photo's crop orientation. Tap opens the edit flow with that device set
as the crop context, so the existing in-crop-tool indicator can guide
the re-crop. Photos without a stored cropOrientation fall back to
inferring it from the saved cropParams aspect, so older uploads aren't
left blind.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 16:25:55 -04:00

1 line
13 KiB
JavaScript

import{B as e,E as t,H as n,K as r,_ as i,d as a,dt as o,f as s,g as c,h as l,j as u,k as d,l as f,o as p,p as m,pt as h,t as g,u as _,v,z as y}from"./_plugin-vue_export-helper-DVo1OUMD.js";import{a as b,d as x,f as S,i as C,o as w,s as T,u as E}from"./index-DCUs53vX.js";import{i as D,n as O,r as ee,t as k}from"./BaseBottomSheet-CzdI27OS.js";import{t as A}from"./DevicePicker-BjuU2ONb.js";var j={class:`approve-card`},M=[`src`,`alt`],N={class:`approve-card__body`},P={class:`approve-card__from`},F={class:`approve-card__date`},I={key:0,class:`approve-card__status`},L={class:`approve-card__actions`},te=g(v({__name:`ApproveCard`,props:{item:{}},emits:[`updated`],setup(e,{emit:t}){let l=e,u=t,g=b(),v=D(),x=n(!1),S=n(!1),C=n([]),w=f(()=>new Date(l.item.sharedAt).toLocaleDateString(void 0,{month:`short`,day:`numeric`,year:`numeric`}));async function T(){x.value=!1,S.value=!0;try{u(`updated`,await g.approveShared(l.item.id,C.value))}finally{S.value=!1,C.value=[]}}async function E(){S.value=!0;try{u(`updated`,await g.declineShared(l.item.id))}finally{S.value=!1}}return(t,n)=>(d(),m(p,null,[_(`div`,j,[_(`img`,{src:e.item.thumbnailUrl,alt:`Photo from ${e.item.sharedBy}`,class:`approve-card__thumb`,loading:`lazy`},null,8,M),_(`div`,N,[_(`p`,P,[n[3]||=c(`From `,-1),_(`strong`,null,h(e.item.sharedBy),1)]),_(`p`,F,h(w.value),1),e.item.status===`pending`?s(``,!0):(d(),m(`div`,I,[_(`span`,{class:o([`approve-card__badge`,`approve-card__badge--${e.item.status}`])},h(e.item.status),3)])),_(`div`,L,[e.item.status===`pending`||e.item.status===`declined`?(d(),a(O,{key:0,variant:`primary`,size:`sm`,disabled:S.value,onClick:n[0]||=e=>x.value=!0},{default:y(()=>[c(h(e.item.status===`declined`?`Add anyway`:`Add to frame`),1)]),_:1},8,[`disabled`])):s(``,!0),e.item.status===`pending`||e.item.status===`approved`?(d(),a(O,{key:1,variant:`ghost`,size:`sm`,disabled:S.value,onClick:E},{default:y(()=>[c(h(e.item.status===`approved`?`Remove`:`Decline`),1)]),_:1},8,[`disabled`])):s(``,!0)])])]),i(A,{modelValue:x.value,"onUpdate:modelValue":n[1]||=e=>x.value=e,devices:r(v).devices,selected:C.value,uploading:S.value,"confirm-label":`Add to frames`,"onUpdate:selected":n[2]||=e=>C.value=e,onConfirm:T},null,8,[`modelValue`,`devices`,`selected`,`uploading`])],64))}}),[[`__scopeId`,`data-v-6d3dd8b4`]]),R={class:`share-sheet__field`},z=[`onKeydown`],B={key:0,class:`share-sheet__error`},V={key:1,class:`share-sheet__success`},ne=g(v({__name:`ShareSheet`,props:{modelValue:{type:Boolean},imageId:{}},emits:[`update:modelValue`],setup(t,{emit:r}){let o=t,l=b(),u=n(``),f=n(!1),p=n(``),g=n(``);async function v(){if(p.value=``,g.value=``,u.value.trim()){f.value=!0;try{await l.shareImage(o.imageId,u.value.trim()),g.value=`Invite sent to ${u.value.trim()}`,u.value=``}catch(e){p.value=e instanceof Error?e.message:`Failed to send`}finally{f.value=!1}}}return(n,r)=>(d(),a(k,{"model-value":t.modelValue,label:`Share photo`,"onUpdate:modelValue":r[1]||=e=>n.$emit(`update:modelValue`,e)},{default:y(()=>[r[2]||=_(`h2`,{class:`share-sheet__title`},`Share with someone`,-1),r[3]||=_(`p`,{class:`share-sheet__sub`},`They'll get an email and can add it to their frame.`,-1),_(`div`,R,[e(_(`input`,{"onUpdate:modelValue":r[0]||=e=>u.value=e,type:`email`,class:`share-sheet__input`,placeholder:`their@email.com`,autocomplete:`email`,onKeydown:x(S(v,[`prevent`]),[`enter`])},null,40,z),[[E,u.value]])]),p.value?(d(),m(`p`,B,h(p.value),1)):s(``,!0),g.value?(d(),m(`p`,V,h(g.value),1)):s(``,!0),i(O,{variant:`primary`,class:`share-sheet__btn`,disabled:f.value||!u.value.trim(),onClick:v},{default:y(()=>[c(h(f.value?`Sending…`:`Send invite`),1)]),_:1},8,[`disabled`])]),_:1},8,[`model-value`]))}}),[[`__scopeId`,`data-v-24296e7b`]]),re={class:`library`},ie={class:`library__tabs`,role:`tablist`},ae=[`aria-selected`,`onClick`],oe={key:0,class:`library__loading`},se={key:0,class:`library__empty`},ce={key:1,class:`library__grid`},le={class:`library__thumb`},ue=[`src`,`alt`],de={class:`library__thumb-actions`},fe=[`aria-label`,`title`,`onClick`],pe=[`aria-label`,`disabled`,`onClick`],me={key:0,width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},he={key:1,width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"aria-hidden":`true`},ge=[`aria-label`,`onClick`],_e=[`onClick`],ve={key:0,class:`library__approvals`},ye=[`aria-label`,`onClick`],be={key:1,class:`library__locks`},xe=[`aria-label`,`onClick`],Se={width:`10`,height:`10`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},Ce={key:0,d:`M7 11V7a5 5 0 0 1 10 0v4`},H={key:1,d:`M7 11V7a5 5 0 0 1 9.9-1`},we={class:`library__subtabs`,role:`tablist`},Te=[`aria-selected`,`onClick`],Ee={key:0,class:`library__loading`},De={key:1,class:`library__shared-empty`},Oe={class:`library__empty-title`},ke={class:`library__empty-sub`},Ae={key:2,class:`library__shared-list`},je={key:3,class:`library__pagination`},Me=[`disabled`],Ne={class:`library__page-info`},Pe=[`disabled`],Fe={class:`library__sheet-actions`},U=g(v({__name:`LibraryView`,setup(e){let g=T(),v=b(),x=D(),S=ee(),E=C(),A=w(),j=[{id:`all`,label:`All`},{id:`mine`,label:`Mine`},{id:`shared`,label:`Shared`}],M=n(A.query.tab??`all`),N=[{id:`pending`,label:`Pending`},{id:`approved`,label:`Approved`},{id:`declined`,label:`Declined`}],P=n(`pending`),F=n([]),I=n(!1),L=n(1),R=n(1);async function z(e,t=1){I.value=!0;try{let n=await v.fetchSharedImages(e,t);F.value=n.items,L.value=n.page,R.value=n.totalPages}finally{I.value=!1}}function B(e){P.value=e,z(e,1)}function V(e){z(P.value,e)}function U(e){let t=F.value.findIndex(t=>t.id===e.id);t!==-1&&(F.value[t]=e)}t(()=>{v.fetchImages(),x.fetchDevices(),v.fetchPendingCount(),M.value===`shared`&&z(P.value)});let W=f(()=>v.images),G=n(!1),K=n(null);function Ie(e){K.value=e,G.value=!0}let q=n(null);async function J(e,t){if(!q.value){q.value=e.id;try{await S.initEdit(e,t),g.push(`/upload`)}catch{E.show(`Could not load photo for editing`,`error`)}finally{q.value=null}}}function Y(e){if(e.cropOrientation)return e.cropOrientation;let t=e.cropParams;return!t?.natW||!t?.natH?null:t.natW>=t.natH?`landscape`:`portrait`}function X(e){let t=Y(e);if(!t)return null;for(let n of e.approvedDeviceIds){let e=x.devices.find(e=>e.id===n);if(e&&e.orientation!==t)return e}return null}async function Le(e,t){try{t.lockedImageId===e?await x.unlockImage(t.id):await x.lockImage(t.id,e)}catch{E.show(`Failed to update lock`,`error`)}}async function Re(e,t,n){try{await v.setApproval(e,t,n)}catch{E.show(`Failed to update frame approval`,`error`)}}let Z=n(!1),Q=n(null),$=n(!1);function ze(e){Q.value=e,Z.value=!0}async function Be(){if(Q.value){$.value=!0;try{await v.deleteImage(Q.value),Z.value=!1,E.show(`Photo deleted`,`success`)}catch{E.show(`Delete failed`,`error`)}finally{$.value=!1}}}return(e,t)=>(d(),m(`main`,re,[_(`div`,ie,[(d(),m(p,null,u(j,e=>_(`button`,{key:e.id,type:`button`,role:`tab`,"aria-selected":M.value===e.id,class:o([`library__tab`,{"library__tab--active":M.value===e.id}]),onClick:t=>M.value=e.id},h(e.label),11,ae)),64))]),r(v).loading?(d(),m(`div`,oe,`Loading…`)):M.value===`shared`?(d(),m(p,{key:2},[_(`div`,we,[(d(),m(p,null,u(N,e=>_(`button`,{key:e.id,type:`button`,role:`tab`,"aria-selected":P.value===e.id,class:o([`library__subtab`,{"library__subtab--active":P.value===e.id}]),onClick:t=>B(e.id)},h(e.label),11,Te)),64))]),I.value?(d(),m(`div`,Ee,`Loading…`)):F.value.length===0?(d(),m(`div`,De,[t[12]||=l(`<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true" data-v-592ae183><circle cx="18" cy="5" r="3" data-v-592ae183></circle><circle cx="6" cy="12" r="3" data-v-592ae183></circle><circle cx="18" cy="19" r="3" data-v-592ae183></circle><line x1="8.59" y1="13.51" x2="15.42" y2="17.49" data-v-592ae183></line><line x1="15.41" y1="6.51" x2="8.59" y2="10.49" data-v-592ae183></line></svg>`,1),_(`p`,Oe,h(P.value===`pending`?`No pending photos`:P.value===`approved`?`No approved photos`:`No declined photos`),1),_(`p`,ke,h(P.value===`pending`?`Photos shared with you will appear here.`:`Photos you've added to a frame will appear here.`),1)])):(d(),m(`div`,Ae,[(d(!0),m(p,null,u(F.value,e=>(d(),a(te,{key:e.id,item:e,onUpdated:U},null,8,[`item`]))),128))])),R.value>1?(d(),m(`div`,je,[_(`button`,{class:`library__page-btn`,disabled:L.value<=1,onClick:t[0]||=e=>V(L.value-1)},`← Prev`,8,Me),_(`span`,Ne,h(L.value)+` / `+h(R.value),1),_(`button`,{class:`library__page-btn`,disabled:L.value>=R.value,onClick:t[1]||=e=>V(L.value+1)},`Next →`,8,Pe)])):s(``,!0)],64)):(d(),m(p,{key:1},[W.value.length===0?(d(),m(`div`,se,[...t[5]||=[l(`<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true" data-v-592ae183><rect x="3" y="3" width="18" height="18" rx="2" data-v-592ae183></rect><circle cx="8.5" cy="8.5" r="1.5" data-v-592ae183></circle><polyline points="21,15 16,10 5,21" data-v-592ae183></polyline></svg><p class="library__empty-title" data-v-592ae183>No photos yet</p><p class="library__empty-sub" data-v-592ae183>Tap &quot;+ Add Photo&quot; on the home screen to get started.</p>`,3)]])):(d(),m(`div`,ce,[(d(!0),m(p,null,u(W.value,e=>(d(),m(`div`,{key:e.id,class:`library__item`},[_(`div`,le,[_(`img`,{src:e.thumbnailUrl,alt:e.originalFilename,class:`library__img`,loading:`lazy`},null,8,ue),_(`div`,de,[X(e)?(d(),m(`button`,{key:0,class:`library__action-btn library__action-btn--warn`,type:`button`,"aria-label":`Crop orientation does not match ${X(e).name}; tap to re-crop`,title:`Cropped ${Y(e)}, but ${X(e).name} is set to ${X(e).orientation}.`,onClick:t=>J(e,X(e).id)},[...t[6]||=[_(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2.5`,"aria-hidden":`true`},[_(`path`,{d:`M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z`}),_(`line`,{x1:`12`,y1:`9`,x2:`12`,y2:`13`}),_(`line`,{x1:`12`,y1:`17`,x2:`12.01`,y2:`17`})],-1)]],8,fe)):s(``,!0),_(`button`,{class:`library__action-btn`,type:`button`,"aria-label":`Edit ${e.originalFilename}`,disabled:q.value===e.id,onClick:t=>J(e)},[q.value===e.id?(d(),m(`svg`,he,[...t[8]||=[_(`circle`,{cx:`12`,cy:`12`,r:`10`},null,-1),_(`line`,{x1:`12`,y1:`8`,x2:`12`,y2:`12`},null,-1),_(`line`,{x1:`12`,y1:`16`,x2:`12.01`,y2:`16`},null,-1)]])):(d(),m(`svg`,me,[...t[7]||=[_(`path`,{d:`M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7`},null,-1),_(`path`,{d:`M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z`},null,-1)]]))],8,pe),_(`button`,{class:`library__action-btn`,type:`button`,"aria-label":`Share ${e.originalFilename}`,onClick:t=>Ie(e.id)},[...t[9]||=[l(`<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true" data-v-592ae183><circle cx="18" cy="5" r="3" data-v-592ae183></circle><circle cx="6" cy="12" r="3" data-v-592ae183></circle><circle cx="18" cy="19" r="3" data-v-592ae183></circle><line x1="8.59" y1="13.51" x2="15.42" y2="17.49" data-v-592ae183></line><line x1="15.41" y1="6.51" x2="8.59" y2="10.49" data-v-592ae183></line></svg>`,1)]],8,ge),_(`button`,{class:`library__action-btn library__action-btn--danger`,type:`button`,"aria-label":`Delete photo`,onClick:t=>ze(e.id)},[...t[10]||=[l(`<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true" data-v-592ae183><polyline points="3 6 5 6 21 6" data-v-592ae183></polyline><path d="M19 6l-1 14H6L5 6" data-v-592ae183></path><path d="M10 11v6M14 11v6" data-v-592ae183></path><path d="M9 6V4h6v2" data-v-592ae183></path></svg>`,1)]],8,_e)])]),r(x).devices.length>0?(d(),m(`div`,ve,[(d(!0),m(p,null,u(r(x).devices,t=>(d(),m(`button`,{key:t.id,class:o([`library__approval-chip`,{"library__approval-chip--on":e.approvedDeviceIds.includes(t.id)}]),type:`button`,"aria-label":`${e.approvedDeviceIds.includes(t.id)?`Remove from`:`Add to`} ${t.name}`,onClick:n=>Re(e.id,t.id,!e.approvedDeviceIds.includes(t.id))},h(t.name),11,ye))),128))])):s(``,!0),r(x).devices.length>0?(d(),m(`div`,be,[(d(!0),m(p,null,u(r(x).devices.filter(t=>e.approvedDeviceIds.includes(t.id)),n=>(d(),m(`button`,{key:n.id,class:o([`library__lock-chip`,{"library__lock-chip--on":n.lockedImageId===e.id}]),type:`button`,"aria-label":`${n.lockedImageId===e.id?`Unlock from`:`Lock to`} ${n.name}`,onClick:t=>Le(e.id,n)},[(d(),m(`svg`,Se,[t[11]||=_(`rect`,{x:`3`,y:`11`,width:`18`,height:`11`,rx:`2`,ry:`2`},null,-1),n.lockedImageId===e.id?(d(),m(`path`,Ce)):(d(),m(`path`,H))])),c(` `+h(n.name),1)],10,xe))),128))])):s(``,!0)]))),128))]))],64)),K.value===null?s(``,!0):(d(),a(ne,{key:3,modelValue:G.value,"onUpdate:modelValue":t[2]||=e=>G.value=e,"image-id":K.value},null,8,[`modelValue`,`image-id`])),i(k,{modelValue:Z.value,"onUpdate:modelValue":t[4]||=e=>Z.value=e,label:`Delete photo`},{default:y(()=>[t[14]||=_(`h2`,{class:`library__sheet-title`},`Delete this photo?`,-1),t[15]||=_(`p`,{class:`library__sheet-sub`},`It will be removed from all frames.`,-1),_(`div`,Fe,[i(O,{variant:`secondary`,onClick:t[3]||=e=>Z.value=!1},{default:y(()=>[...t[13]||=[c(`Cancel`,-1)]]),_:1}),i(O,{variant:`destructive`,disabled:$.value,onClick:Be},{default:y(()=>[c(h($.value?`Deleting…`:`Delete`),1)]),_:1},8,[`disabled`])])]),_:1},8,[`modelValue`])]))}}),[[`__scopeId`,`data-v-592ae183`]]);export{U as default};