Files
pictureFrame-webApp/public/build/assets/LibraryView-n4Q9RMCy.js
T
football2801 ca4595873d
CI / test (push) Has been cancelled
fix(frame-card): cap portrait preview to 40dvh so cards stop dominating
Portrait frames (3:5 aspect) at full card width were rendering 600px tall
and pushing the body well off-screen. Cap preview max-height at 40dvh and
switch the img sizing to max-width/max-height: 100% with auto width/height
— photo scales to fit inside the capped preview at its native aspect, with
narrow grey side bars filling the leftover horizontal space. Landscape
frames are short enough that the cap never engages.

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

1 line
13 KiB
JavaScript

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