78405b644d
CI / test (push) Has been cancelled
Two complaints, one root cause: the FrameCard was floating in the slide with a min-height-padded preview, so (1) photos got top/bottom gray bars instead of fitting their container, and (2) there was a fat empty gap between the card body and the bottom nav. Restructured the large card to flex-fill its slide: - preview hugs the photo's intrinsic aspect ratio (img with width:100% height:auto); no min-height, no aspect-ratio override → no letterbox - card body has flex:1, info pinned at top, Add Photo button pinned at bottom via margin-top:auto and width:100% - HomeView main / single-card / carousel all flex:1 down through the layout so the slide gets the full available height - empty-state placeholder still reserves the device's aspect so the card doesn't jump while images load Result: the photo fills its container left/right with no bars; the body absorbs all remaining space below, with the action button always sitting just above the bottom nav. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 line
13 KiB
JavaScript
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-aP_uBWCi.js";import{i as O,n as k,r as ee,t as A}from"./BaseBottomSheet-CXcLrct9.js";import{t as j}from"./DevicePicker-MIsIaweQ.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 "+ Add Photo" 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}; |