Add image comparison feature similar to imgsli

pull/268/head
zanllp 2023-06-26 10:16:36 +08:00
parent 6c20435904
commit 7cf69bd790
46 changed files with 568 additions and 245 deletions

View File

@ -15,8 +15,8 @@
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Infinite Image Browsing</title>
<script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-5716a5d2.js"></script>
<link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-8961c2b3.css">
<script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-837602c1.js"></script>
<link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-ae43cab2.css">
</head>
<body>

1
vue/components.d.ts vendored
View File

@ -15,6 +15,7 @@ declare module '@vue/runtime-core' {
AButton: typeof import('ant-design-vue/es')['Button']
ACollapse: typeof import('ant-design-vue/es')['Collapse']
ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
ADrawer: typeof import('ant-design-vue/es')['Drawer']
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']

View File

@ -1 +0,0 @@
import{d as R,l as U,o as r,y as _,c as l,n as a,r as e,s as y,p as b,t as E,v as h,x as q,m as M,H as u,K as S,N as L,O as H,V as K}from"./index-5716a5d2.js";import{a as Q,f as j,L as J,R as W,b as X,S as Y}from"./fullScreenContextMenu-792aa198.js";import{t as Z}from"./hook-735191b8.js";import{g as ee}from"./db-1ccd7546.js";import{u as te}from"./hook-9ffbde00.js";const se={class:"hint"},ie={key:1,class:"preview-switch"},le=R({__name:"MatchedImageGrid",props:{tabIdx:{},paneIdx:{},selectedTagIds:{},id:{}},setup(V){const m=V,{queue:p,images:s,onContextMenuClickU:f,stackViewEl:T,previewIdx:n,previewing:v,onPreviewVisibleChange:z,previewImgMove:g,canPreview:I,itemSize:k,gridItems:$,showGenInfo:o,imageGenInfo:w,q:B,multiSelectedIdxs:D,onFileItemClick:F,scroller:C,showMenuIdx:d,onFileDragStart:G}=te();return U(()=>m.selectedTagIds,async()=>{var t;const{res:c}=p.pushAction(()=>ee(m.selectedTagIds));s.value=await c,(t=C.value)==null||t.scrollToItem(0)},{immediate:!0}),(c,t)=>{const N=L,A=H,O=Y;return r(),_("div",{class:"container",ref_key:"stackViewEl",ref:T},[l(O,{size:"large",spinning:!e(p).isIdle},{default:a(()=>[l(A,{visible:e(o),"onUpdate:visible":t[1]||(t[1]=i=>y(o)?o.value=i:null),width:"70vw","mask-closable":"",onOk:t[2]||(t[2]=i=>o.value=!1)},{cancelText:a(()=>[]),default:a(()=>[l(N,{active:"",loading:!e(B).isIdle},{default:a(()=>[b("div",{style:{width:"100%","word-break":"break-all","white-space":"pre-line","max-height":"70vh",overflow:"auto"},onDblclick:t[0]||(t[0]=i=>e(E)(e(w)))},[b("div",se,h(c.$t("doubleClickToCopy")),1),q(" "+h(e(w)),1)],32)]),_:1},8,["loading"])]),_:1},8,["visible"]),e(s)?(r(),M(e(Q),{key:0,ref_key:"scroller",ref:C,class:"file-list",items:e(s),"item-size":e(k).first,"key-field":"fullpath","item-secondary-size":e(k).second,gridItems:e($)},{default:a(({item:i,index:x})=>[l(j,{idx:x,file:i,"show-menu-idx":e(d),"onUpdate:showMenuIdx":t[3]||(t[3]=P=>y(d)?d.value=P:null),onDragstart:e(G),onFileItemClick:e(F),"full-screen-preview-image-url":e(s)[e(n)]?e(Z)(e(s)[e(n)]):"",selected:e(D).includes(x),onContextMenuClick:e(f),onPreviewVisibleChange:e(z)},null,8,["idx","file","show-menu-idx","onDragstart","onFileItemClick","full-screen-preview-image-url","selected","onContextMenuClick","onPreviewVisibleChange"])]),_:1},8,["items","item-size","item-secondary-size","gridItems"])):u("",!0),e(v)?(r(),_("div",ie,[l(e(J),{onClick:t[4]||(t[4]=i=>e(g)("prev")),class:S({disable:!e(I)("prev")})},null,8,["class"]),l(e(W),{onClick:t[5]||(t[5]=i=>e(g)("next")),class:S({disable:!e(I)("next")})},null,8,["class"])])):u("",!0)]),_:1},8,["spinning"]),e(v)&&e(s)&&e(s)[e(n)]?(r(),M(X,{key:0,file:e(s)[e(n)],idx:e(n),onContextMenuClick:e(f)},null,8,["file","idx","onContextMenuClick"])):u("",!0)],512)}}});const ce=K(le,[["__scopeId","data-v-448d483e"]]);export{ce as default};

View File

@ -0,0 +1 @@
.preview-switch[data-v-2cae0a95]{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;z-index:11111;pointer-events:none}.preview-switch>*[data-v-2cae0a95]{color:#fff;margin:16px;font-size:4em;pointer-events:all;cursor:pointer}.preview-switch>*.disable[data-v-2cae0a95]{opacity:0;pointer-events:none;cursor:none}.container[data-v-2cae0a95]{background:var(--zp-secondary-background)}.container .file-list[data-v-2cae0a95]{list-style:none;padding:8px;height:100%;overflow:auto;height:var(--pane-max-height);width:100%}

View File

@ -1 +0,0 @@
.preview-switch[data-v-448d483e]{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;z-index:11111;pointer-events:none}.preview-switch>*[data-v-448d483e]{color:#fff;margin:16px;font-size:4em;pointer-events:all;cursor:pointer}.preview-switch>*.disable[data-v-448d483e]{opacity:0;pointer-events:none;cursor:none}.container[data-v-448d483e]{background:var(--zp-secondary-background)}.container .file-list[data-v-448d483e]{list-style:none;padding:8px;height:100%;overflow:auto;height:var(--pane-max-height);width:100%}

View File

@ -0,0 +1 @@
import{d as R,l as U,o as r,y as _,c as n,n as a,r as e,s as y,p as b,t as L,v as h,x as q,m as M,K as Q,H as u,L as S,O as H,Q as K,W}from"./index-837602c1.js";import{a as j,f as J,L as X,R as Y,b as Z,S as ee}from"./fullScreenContextMenu-f56d0b68.js";import"./hook-594118df.js";import{g as se}from"./db-90ebe1a2.js";import{u as te}from"./hook-0b66e22e.js";const ie={class:"hint"},ne={key:1,class:"preview-switch"},le=R({__name:"MatchedImageGrid",props:{tabIdx:{},paneIdx:{},selectedTagIds:{},id:{}},setup(V){const m=V,{queue:p,images:t,onContextMenuClickU:g,stackViewEl:D,previewIdx:l,previewing:v,onPreviewVisibleChange:T,previewImgMove:f,canPreview:I,itemSize:k,gridItems:z,showGenInfo:o,imageGenInfo:w,q:F,multiSelectedIdxs:$,onFileItemClick:B,scroller:C,showMenuIdx:d,onFileDragStart:G,onFileDragEnd:A}=te();return U(()=>m.selectedTagIds,async()=>{var s;const{res:c}=p.pushAction(()=>se(m.selectedTagIds));t.value=await c,(s=C.value)==null||s.scrollToItem(0)},{immediate:!0}),(c,s)=>{const E=H,N=K,O=ee;return r(),_("div",{class:"container",ref_key:"stackViewEl",ref:D},[n(O,{size:"large",spinning:!e(p).isIdle},{default:a(()=>[n(N,{visible:e(o),"onUpdate:visible":s[1]||(s[1]=i=>y(o)?o.value=i:null),width:"70vw","mask-closable":"",onOk:s[2]||(s[2]=i=>o.value=!1)},{cancelText:a(()=>[]),default:a(()=>[n(E,{active:"",loading:!e(F).isIdle},{default:a(()=>[b("div",{style:{width:"100%","word-break":"break-all","white-space":"pre-line","max-height":"70vh",overflow:"auto"},onDblclick:s[0]||(s[0]=i=>e(L)(e(w)))},[b("div",ie,h(c.$t("doubleClickToCopy")),1),q(" "+h(e(w)),1)],32)]),_:1},8,["loading"])]),_:1},8,["visible"]),e(t)?(r(),M(e(j),{key:0,ref_key:"scroller",ref:C,class:"file-list",items:e(t),"item-size":e(k).first,"key-field":"fullpath","item-secondary-size":e(k).second,gridItems:e(z)},{default:a(({item:i,index:x})=>[n(J,{idx:x,file:i,"show-menu-idx":e(d),"onUpdate:showMenuIdx":s[3]||(s[3]=P=>y(d)?d.value=P:null),onDragstart:e(G),onDragend:e(A),onFileItemClick:e(B),"full-screen-preview-image-url":e(t)[e(l)]?e(Q)(e(t)[e(l)]):"",selected:e($).includes(x),onContextMenuClick:e(g),onPreviewVisibleChange:e(T)},null,8,["idx","file","show-menu-idx","onDragstart","onDragend","onFileItemClick","full-screen-preview-image-url","selected","onContextMenuClick","onPreviewVisibleChange"])]),_:1},8,["items","item-size","item-secondary-size","gridItems"])):u("",!0),e(v)?(r(),_("div",ne,[n(e(X),{onClick:s[4]||(s[4]=i=>e(f)("prev")),class:S({disable:!e(I)("prev")})},null,8,["class"]),n(e(Y),{onClick:s[5]||(s[5]=i=>e(f)("next")),class:S({disable:!e(I)("next")})},null,8,["class"])])):u("",!0)]),_:1},8,["spinning"]),e(v)&&e(t)&&e(t)[e(l)]?(r(),M(Z,{key:0,file:e(t)[e(l)],idx:e(l),onContextMenuClick:e(g)},null,8,["file","idx","onContextMenuClick"])):u("",!0)],512)}}});const ue=W(le,[["__scopeId","data-v-2cae0a95"]]);export{ue as default};

View File

@ -0,0 +1 @@
import{d as W,Z as $,ay as Z,br as j,bs as J,o,y as k,c as r,r as e,bx as X,m,n as d,x as b,v,H as f,s as B,p as V,t as Y,K as ee,L as A,bv as ne,ag as se,T as te,U as ae,O as ie,Q as le,W as oe}from"./index-837602c1.js";import{a as re,f as de,L as ue,R as ce,b as pe,S as me}from"./fullScreenContextMenu-f56d0b68.js";/* empty css */import"./hook-594118df.js";import{a as U,c as ve,e as fe,u as ge}from"./db-90ebe1a2.js";import{u as ke}from"./hook-0b66e22e.js";const be={key:0,class:"search-bar"},ye={class:"hint"},we={key:1,class:"preview-switch"},Ce=W({__name:"SubstrSearch",setup(Ie){const{queue:l,images:a,onContextMenuClickU:y,stackViewEl:F,previewIdx:u,previewing:w,onPreviewVisibleChange:E,previewImgMove:C,canPreview:I,itemSize:_,gridItems:R,showGenInfo:c,imageGenInfo:x,q:T,multiSelectedIdxs:K,onFileItemClick:L,scroller:h,showMenuIdx:g,onFileDragStart:N,onFileDragEnd:O}=ke(),p=$(""),s=$();Z(async()=>{s.value=await U(),s.value.img_count&&s.value.expired&&S()});const S=j(()=>l.pushAction(async()=>(await ge(),s.value=await U(),s.value)).res),M=async()=>{var t;a.value=await l.pushAction(()=>fe(p.value)).res,(t=h.value)==null||t.scrollToItem(0),a.value.length||ne.info(se("fuzzy-search-noResults"))};return J("return-to-iib",async()=>{const t=await l.pushAction(ve).res;s.value.expired=t.expired}),(t,n)=>{const P=te,z=ae,q=ie,G=le,H=me;return o(),k("div",{class:"container",ref_key:"stackViewEl",ref:F},[s.value?(o(),k("div",be,[r(P,{value:p.value,"onUpdate:value":n[0]||(n[0]=i=>p.value=i),placeholder:t.$t("fuzzy-search-placeholder"),disabled:!e(l).isIdle,onKeydown:X(M,["enter"])},null,8,["value","placeholder","disabled","onKeydown"]),s.value.expired||!s.value.img_count?(o(),m(z,{key:0,onClick:e(S),loading:!e(l).isIdle,type:"primary"},{default:d(()=>[b(v(s.value.img_count===0?t.$t("generateIndexHint"):t.$t("UpdateIndex")),1)]),_:1},8,["onClick","loading"])):(o(),m(z,{key:1,type:"primary",onClick:M,loading:!e(l).isIdle,disabled:!p.value},{default:d(()=>[b(v(t.$t("search")),1)]),_:1},8,["loading","disabled"]))])):f("",!0),r(H,{size:"large",spinning:!e(l).isIdle},{default:d(()=>[r(G,{visible:e(c),"onUpdate:visible":n[2]||(n[2]=i=>B(c)?c.value=i:null),width:"70vw","mask-closable":"",onOk:n[3]||(n[3]=i=>c.value=!1)},{cancelText:d(()=>[]),default:d(()=>[r(q,{active:"",loading:!e(T).isIdle},{default:d(()=>[V("div",{style:{width:"100%","word-break":"break-all","white-space":"pre-line","max-height":"70vh",overflow:"auto"},onDblclick:n[1]||(n[1]=i=>e(Y)(e(x)))},[V("div",ye,v(t.$t("doubleClickToCopy")),1),b(" "+v(e(x)),1)],32)]),_:1},8,["loading"])]),_:1},8,["visible"]),e(a)?(o(),m(e(re),{key:0,ref_key:"scroller",ref:h,class:"file-list",items:e(a),"item-size":e(_).first,"key-field":"fullpath","item-secondary-size":e(_).second,gridItems:e(R)},{default:d(({item:i,index:D})=>[r(de,{idx:D,file:i,"show-menu-idx":e(g),"onUpdate:showMenuIdx":n[4]||(n[4]=Q=>B(g)?g.value=Q:null),onFileItemClick:e(L),"full-screen-preview-image-url":e(a)[e(u)]?e(ee)(e(a)[e(u)]):"",selected:e(K).includes(D),onContextMenuClick:e(y),onDragstart:e(N),onDragend:e(O),onPreviewVisibleChange:e(E)},null,8,["idx","file","show-menu-idx","onFileItemClick","full-screen-preview-image-url","selected","onContextMenuClick","onDragstart","onDragend","onPreviewVisibleChange"])]),_:1},8,["items","item-size","item-secondary-size","gridItems"])):f("",!0),e(w)?(o(),k("div",we,[r(e(ue),{onClick:n[5]||(n[5]=i=>e(C)("prev")),class:A({disable:!e(I)("prev")})},null,8,["class"]),r(e(ce),{onClick:n[6]||(n[6]=i=>e(C)("next")),class:A({disable:!e(I)("next")})},null,8,["class"])])):f("",!0)]),_:1},8,["spinning"]),e(w)&&e(a)&&e(a)[e(u)]?(o(),m(pe,{key:1,file:e(a)[e(u)],idx:e(u),onContextMenuClick:e(y)},null,8,["file","idx","onContextMenuClick"])):f("",!0)],512)}}});const De=oe(Ce,[["__scopeId","data-v-bf9bdccd"]]);export{De as default};

View File

@ -0,0 +1 @@
.search-bar[data-v-bf9bdccd]{padding:8px;display:flex}.preview-switch[data-v-bf9bdccd]{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;z-index:11111;pointer-events:none}.preview-switch>*[data-v-bf9bdccd]{color:#fff;margin:16px;font-size:4em;pointer-events:all;cursor:pointer}.preview-switch>*.disable[data-v-bf9bdccd]{opacity:0;pointer-events:none;cursor:none}.container[data-v-bf9bdccd]{background:var(--zp-secondary-background)}.container .file-list[data-v-bf9bdccd]{list-style:none;padding:8px;height:100%;overflow:auto;height:var(--pane-max-height);width:100%}

View File

@ -1 +0,0 @@
import{d as Q,Y as $,ax as Y,bq as j,br as J,o,y as k,c as r,r as e,bw as W,m,n as u,x as w,v,H as f,s as B,p as A,t as X,K as D,bu as Z,af as ee,R as te,T as se,N as ae,O as ne,V as ie}from"./index-5716a5d2.js";import{a as le,f as oe,L as re,R as ue,b as de,S as ce}from"./fullScreenContextMenu-792aa198.js";/* empty css */import{t as pe}from"./hook-735191b8.js";import{a as U,c as me,e as ve,u as fe}from"./db-1ccd7546.js";import{u as ge}from"./hook-9ffbde00.js";const ke={key:0,class:"search-bar"},we={class:"hint"},ye={key:1,class:"preview-switch"},be=Q({__name:"SubstrSearch",setup(Ce){const{queue:l,images:n,onContextMenuClickU:y,stackViewEl:F,previewIdx:d,previewing:b,onPreviewVisibleChange:R,previewImgMove:C,canPreview:I,itemSize:_,gridItems:E,showGenInfo:c,imageGenInfo:x,q:N,multiSelectedIdxs:T,onFileItemClick:q,scroller:h,showMenuIdx:g,onFileDragStart:K}=ge(),p=$(""),s=$();Y(async()=>{s.value=await U(),s.value.img_count&&s.value.expired&&S()});const S=j(()=>l.pushAction(async()=>(await fe(),s.value=await U(),s.value)).res),M=async()=>{var a;n.value=await l.pushAction(()=>ve(p.value)).res,(a=h.value)==null||a.scrollToItem(0),n.value.length||Z.info(ee("fuzzy-search-noResults"))};return J("return-to-iib",async()=>{const a=await l.pushAction(me).res;s.value.expired=a.expired}),(a,t)=>{const O=te,z=se,P=ae,G=ne,L=ce;return o(),k("div",{class:"container",ref_key:"stackViewEl",ref:F},[s.value?(o(),k("div",ke,[r(O,{value:p.value,"onUpdate:value":t[0]||(t[0]=i=>p.value=i),placeholder:a.$t("fuzzy-search-placeholder"),disabled:!e(l).isIdle,onKeydown:W(M,["enter"])},null,8,["value","placeholder","disabled","onKeydown"]),s.value.expired||!s.value.img_count?(o(),m(z,{key:0,onClick:e(S),loading:!e(l).isIdle,type:"primary"},{default:u(()=>[w(v(s.value.img_count===0?a.$t("generateIndexHint"):a.$t("UpdateIndex")),1)]),_:1},8,["onClick","loading"])):(o(),m(z,{key:1,type:"primary",onClick:M,loading:!e(l).isIdle,disabled:!p.value},{default:u(()=>[w(v(a.$t("search")),1)]),_:1},8,["loading","disabled"]))])):f("",!0),r(L,{size:"large",spinning:!e(l).isIdle},{default:u(()=>[r(G,{visible:e(c),"onUpdate:visible":t[2]||(t[2]=i=>B(c)?c.value=i:null),width:"70vw","mask-closable":"",onOk:t[3]||(t[3]=i=>c.value=!1)},{cancelText:u(()=>[]),default:u(()=>[r(P,{active:"",loading:!e(N).isIdle},{default:u(()=>[A("div",{style:{width:"100%","word-break":"break-all","white-space":"pre-line","max-height":"70vh",overflow:"auto"},onDblclick:t[1]||(t[1]=i=>e(X)(e(x)))},[A("div",we,v(a.$t("doubleClickToCopy")),1),w(" "+v(e(x)),1)],32)]),_:1},8,["loading"])]),_:1},8,["visible"]),e(n)?(o(),m(e(le),{key:0,ref_key:"scroller",ref:h,class:"file-list",items:e(n),"item-size":e(_).first,"key-field":"fullpath","item-secondary-size":e(_).second,gridItems:e(E)},{default:u(({item:i,index:V})=>[r(oe,{idx:V,file:i,"show-menu-idx":e(g),"onUpdate:showMenuIdx":t[4]||(t[4]=H=>B(g)?g.value=H:null),onFileItemClick:e(q),"full-screen-preview-image-url":e(n)[e(d)]?e(pe)(e(n)[e(d)]):"",selected:e(T).includes(V),onContextMenuClick:e(y),onDragstart:e(K),onPreviewVisibleChange:e(R)},null,8,["idx","file","show-menu-idx","onFileItemClick","full-screen-preview-image-url","selected","onContextMenuClick","onDragstart","onPreviewVisibleChange"])]),_:1},8,["items","item-size","item-secondary-size","gridItems"])):f("",!0),e(b)?(o(),k("div",ye,[r(e(re),{onClick:t[5]||(t[5]=i=>e(C)("prev")),class:D({disable:!e(I)("prev")})},null,8,["class"]),r(e(ue),{onClick:t[6]||(t[6]=i=>e(C)("next")),class:D({disable:!e(I)("next")})},null,8,["class"])])):f("",!0)]),_:1},8,["spinning"]),e(b)&&e(n)&&e(n)[e(d)]?(o(),m(de,{key:1,file:e(n)[e(d)],idx:e(d),onContextMenuClick:e(y)},null,8,["file","idx","onContextMenuClick"])):f("",!0)],512)}}});const ze=ie(be,[["__scopeId","data-v-a2e6e698"]]);export{ze as default};

View File

@ -1 +0,0 @@
.search-bar[data-v-a2e6e698]{padding:8px;display:flex}.preview-switch[data-v-a2e6e698]{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;z-index:11111;pointer-events:none}.preview-switch>*[data-v-a2e6e698]{color:#fff;margin:16px;font-size:4em;pointer-events:all;cursor:pointer}.preview-switch>*.disable[data-v-a2e6e698]{opacity:0;pointer-events:none;cursor:none}.container[data-v-a2e6e698]{background:var(--zp-secondary-background)}.container .file-list[data-v-a2e6e698]{list-style:none;padding:8px;height:100%;overflow:auto;height:var(--pane-max-height);width:100%}

1
vue/dist/assets/TagSearch-041d8060.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{cs as I,ct as _,c2 as A,aL as P,b5 as m,cu as y,b7 as b,cv as C,b3 as E,bn as R,c8 as a}from"./index-5716a5d2.js";function O(t){return function(n){return n==null?void 0:n[t]}}var D=1,M=2;function T(t,n,e,s){var r=e.length,c=r,d=!s;if(t==null)return!c;for(t=Object(t);r--;){var i=e[r];if(d&&i[2]?i[1]!==t[i[0]]:!(i[0]in t))return!1}for(;++r<c;){i=e[r];var u=i[0],o=t[u],f=i[1];if(d&&i[2]){if(o===void 0&&!(u in t))return!1}else{var g=new I;if(s)var p=s(o,f,u,t,n,g);if(!(p===void 0?_(f,o,D|M,s,g):p))return!1}}return!0}function h(t){return t===t&&!A(t)}function L(t){for(var n=P(t),e=n.length;e--;){var s=n[e],r=t[s];n[e]=[s,r,h(r)]}return n}function l(t,n){return function(e){return e==null?!1:e[t]===n&&(n!==void 0||t in Object(e))}}function S(t){var n=L(t);return n.length==1&&n[0][2]?l(n[0][0],n[0][1]):function(e){return e===t||T(e,t,n)}}function v(t,n,e){var s=t==null?void 0:m(t,n);return s===void 0?e:s}var x=1,G=2;function F(t,n){return y(t)&&h(n)?l(b(t),n):function(e){var s=v(e,t);return s===void 0&&s===n?C(e,t):_(n,s,x|G)}}function B(t){return function(n){return m(n,t)}}function K(t){return y(t)?O(b(t)):B(t)}function U(t){return typeof t=="function"?t:t==null?E:typeof t=="object"?R(t)?F(t[0],t[1]):S(t):K(t)}const $=async()=>(await a.get("/db/basic_info")).data,q=async()=>(await a.get("/db/expired_dirs")).data,H=async()=>{await a.post("/db/update_image_data",{},{timeout:1/0})},J=async t=>(await a.post("/db/match_images_by_tags",t)).data,Q=async t=>(await a.post("/db/add_custom_tag",t)).data,W=async t=>(await a.post("/db/toggle_custom_tag_to_img",t)).data,X=async t=>{await a.post("/db/remove_custom_tag",t)},Y=async t=>(await a.get("/db/img_selected_custom_tag",{params:{path:t}})).data,Z=async t=>(await a.get("/db/search_by_substr",{params:{substr:t}})).data,w="/db/scanned_paths",z=async t=>{await a.post(w,{path:t})},k=async t=>{await a.delete(w,{data:{path:t}})};export{$ as a,U as b,q as c,Q as d,Z as e,Y as f,J as g,k as h,z as i,X as r,W as t,H as u};

1
vue/dist/assets/db-90ebe1a2.js vendored Normal file
View File

@ -0,0 +1 @@
import{cn as I,co as _,bX as A,aM as P,b6 as m,cp as y,b8 as b,cq as C,b4 as E,bo as R,c1 as a}from"./index-837602c1.js";function M(t){return function(n){return n==null?void 0:n[t]}}var O=1,D=2;function T(t,n,e,s){var r=e.length,c=r,d=!s;if(t==null)return!c;for(t=Object(t);r--;){var i=e[r];if(d&&i[2]?i[1]!==t[i[0]]:!(i[0]in t))return!1}for(;++r<c;){i=e[r];var o=i[0],u=t[o],f=i[1];if(d&&i[2]){if(u===void 0&&!(o in t))return!1}else{var g=new I;if(s)var p=s(u,f,o,t,n,g);if(!(p===void 0?_(f,u,O|D,s,g):p))return!1}}return!0}function h(t){return t===t&&!A(t)}function S(t){for(var n=P(t),e=n.length;e--;){var s=n[e],r=t[s];n[e]=[s,r,h(r)]}return n}function l(t,n){return function(e){return e==null?!1:e[t]===n&&(n!==void 0||t in Object(e))}}function L(t){var n=S(t);return n.length==1&&n[0][2]?l(n[0][0],n[0][1]):function(e){return e===t||T(e,t,n)}}function x(t,n,e){var s=t==null?void 0:m(t,n);return s===void 0?e:s}var G=1,v=2;function F(t,n){return y(t)&&h(n)?l(b(t),n):function(e){var s=x(e,t);return s===void 0&&s===n?C(e,t):_(n,s,G|v)}}function B(t){return function(n){return m(n,t)}}function q(t){return y(t)?M(b(t)):B(t)}function N(t){return typeof t=="function"?t:t==null?E:typeof t=="object"?R(t)?F(t[0],t[1]):L(t):q(t)}const U=async()=>(await a.get("/db/basic_info")).data,$=async()=>(await a.get("/db/expired_dirs")).data,X=async()=>{await a.post("/db/update_image_data",{},{timeout:1/0})},H=async t=>(await a.post("/db/match_images_by_tags",t)).data,J=async t=>(await a.post("/db/add_custom_tag",t)).data,Q=async t=>(await a.post("/db/toggle_custom_tag_to_img",t)).data,W=async t=>{await a.post("/db/remove_custom_tag",t)},Y=async t=>(await a.get("/db/img_selected_custom_tag",{params:{path:t}})).data,Z=async t=>(await a.get("/db/search_by_substr",{params:{substr:t}})).data,w="/db/scanned_paths",z=async t=>{await a.post(w,{path:t})},k=async t=>{await a.delete(w,{data:{path:t}})};export{U as a,N as b,$ as c,J as d,Z as e,Y as f,H as g,k as h,z as i,W as r,Q as t,X as u};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
vue/dist/assets/hook-0b66e22e.js vendored Normal file
View File

@ -0,0 +1 @@
import{Z as l,bq as q,b4 as y}from"./index-837602c1.js";import{u as D,b as E,f as P,c as z,d as G,e as Q,g as R}from"./hook-594118df.js";const H=()=>{const e=l(),c=q(),o=l(),t={tabIdx:-1,target:"local",paneIdx:-1,walkMode:!1},{stackViewEl:r,multiSelectedIdxs:u,stack:m}=D({images:e}).toRefs(),{itemSize:f,gridItems:v}=E(t),{showMenuIdx:p}=P(),{onFileDragStart:I,onFileDragEnd:d}=z(),{showGenInfo:g,imageGenInfo:w,q:x,onContextMenuClick:i,onFileItemClick:k}=G(t,{openNext:y}),{previewIdx:F,previewing:M,onPreviewVisibleChange:b,previewImgMove:h,canPreview:C}=Q(t,{scroller:o,files:e}),S=async(n,s,a)=>{m.value=[{curr:"",files:e.value}],await i(n,s,a)};return R("removeFiles",async({paths:n})=>{var s;e.value=(s=e.value)==null?void 0:s.filter(a=>!n.includes(a.fullpath))}),{scroller:o,queue:c,images:e,onContextMenuClickU:S,stackViewEl:r,previewIdx:F,previewing:M,onPreviewVisibleChange:b,previewImgMove:h,canPreview:C,itemSize:f,gridItems:v,showGenInfo:g,imageGenInfo:w,q:x,onContextMenuClick:i,onFileItemClick:k,showMenuIdx:p,multiSelectedIdxs:u,onFileDragStart:I,onFileDragEnd:d}};export{H as u};

2
vue/dist/assets/hook-594118df.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{Y as c,bp as S,b3 as y}from"./index-5716a5d2.js";import{u as q,b as P,f as z,c as D,d as E,e as G,h as Q}from"./hook-735191b8.js";const A=()=>{const e=c(),l=S(),o=c(),t={tabIdx:-1,target:"local",paneIdx:-1,walkMode:!1},{stackViewEl:r,multiSelectedIdxs:u,stack:m}=q({images:e}).toRefs(),{itemSize:f,gridItems:p}=P(t),{showMenuIdx:v}=z(),{onFileDragStart:I}=D(),{showGenInfo:d,imageGenInfo:w,q:g,onContextMenuClick:i,onFileItemClick:x}=E(t,{openNext:y}),{previewIdx:k,previewing:h,onPreviewVisibleChange:M,previewImgMove:b,canPreview:C}=G(t,{scroller:o,files:e}),F=async(a,s,n)=>{m.value=[{curr:"",files:e.value}],await i(a,s,n)};return Q("removeFiles",async({paths:a})=>{var s;e.value=(s=e.value)==null?void 0:s.filter(n=>!a.includes(n.fullpath))}),{scroller:o,queue:l,images:e,onContextMenuClickU:F,stackViewEl:r,previewIdx:k,previewing:h,onPreviewVisibleChange:M,previewImgMove:b,canPreview:C,itemSize:f,gridItems:p,showGenInfo:d,imageGenInfo:w,q:g,onContextMenuClick:i,onFileItemClick:x,showMenuIdx:v,multiSelectedIdxs:u,onFileDragStart:I}};export{A as u};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

184
vue/dist/assets/index-837602c1.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
vue/dist/assets/stackView-0955bb0d.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
.ant-breadcrumb{box-sizing:border-box;margin:0;padding:0;color:#000000d9;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum";color:#00000073;font-size:14px}.ant-breadcrumb .anticon{font-size:14px}.ant-breadcrumb a{color:#00000073;transition:color .3s}.ant-breadcrumb a:hover{color:#de632f}.ant-breadcrumb>span:last-child{color:#000000d9}.ant-breadcrumb>span:last-child a{color:#000000d9}.ant-breadcrumb>span:last-child .ant-breadcrumb-separator{display:none}.ant-breadcrumb-separator{margin:0 8px;color:#00000073}.ant-breadcrumb-link>.anticon+span,.ant-breadcrumb-link>.anticon+a{margin-left:4px}.ant-breadcrumb-overlay-link>.anticon{margin-left:4px}.ant-breadcrumb-rtl{direction:rtl}.ant-breadcrumb-rtl:before{display:table;content:""}.ant-breadcrumb-rtl:after{display:table;clear:both;content:""}.ant-breadcrumb-rtl>span{float:right}.ant-breadcrumb-rtl .ant-breadcrumb-link>.anticon+span,.ant-breadcrumb-rtl .ant-breadcrumb-link>.anticon+a{margin-right:4px;margin-left:0}.ant-breadcrumb-rtl .ant-breadcrumb-overlay-link>.anticon{margin-right:4px;margin-left:0}.nprogress{pointer-events:none}.nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}.nprogress .peg{display:block;position:absolute;right:0px;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translate(0px,-4px);-ms-transform:rotate(3deg) translate(0px,-4px);transform:rotate(3deg) translateY(-4px)}.nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}.nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:solid 2px transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent .nprogress .spinner,.nprogress-custom-parent .nprogress .bar{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes nprogress-spinner{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preview-switch[data-v-0ec31c23]{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;z-index:11111;pointer-events:none}.preview-switch>*[data-v-0ec31c23]{color:#fff;margin:16px;font-size:4em;pointer-events:all;cursor:pointer}.preview-switch>*.disable[data-v-0ec31c23]{opacity:0;pointer-events:none;cursor:none}.breadcrumb[data-v-0ec31c23]{display:flex;align-items:center}.breadcrumb>*[data-v-0ec31c23]{margin-right:4px}.container[data-v-0ec31c23]{background:var(--zp-secondary-background);height:var(--pane-max-height)}.location-bar[data-v-0ec31c23]{padding:4px 16px;background:var(--zp-primary-background);border-bottom:1px solid var(--zp-border);display:flex;align-items:center;justify-content:space-between}.location-bar .actions[data-v-0ec31c23]{display:flex;align-items:center;flex-shrink:0}.location-bar a.opt[data-v-0ec31c23]{margin-left:8px}.view[data-v-0ec31c23]{padding:8px;height:calc(100vh - 48px)}.view .file-list[data-v-0ec31c23]{list-style:none;padding:8px;height:100%;overflow:auto}.hint[data-v-0ec31c23]{padding:4px;border:4px;background:var(--zp-secondary-background);border:1px solid var(--zp-border)}
.ant-breadcrumb{box-sizing:border-box;margin:0;padding:0;color:#000000d9;font-variant:tabular-nums;line-height:1.5715;list-style:none;font-feature-settings:"tnum";color:#00000073;font-size:14px}.ant-breadcrumb .anticon{font-size:14px}.ant-breadcrumb a{color:#00000073;transition:color .3s}.ant-breadcrumb a:hover{color:#de632f}.ant-breadcrumb>span:last-child{color:#000000d9}.ant-breadcrumb>span:last-child a{color:#000000d9}.ant-breadcrumb>span:last-child .ant-breadcrumb-separator{display:none}.ant-breadcrumb-separator{margin:0 8px;color:#00000073}.ant-breadcrumb-link>.anticon+span,.ant-breadcrumb-link>.anticon+a{margin-left:4px}.ant-breadcrumb-overlay-link>.anticon{margin-left:4px}.ant-breadcrumb-rtl{direction:rtl}.ant-breadcrumb-rtl:before{display:table;content:""}.ant-breadcrumb-rtl:after{display:table;clear:both;content:""}.ant-breadcrumb-rtl>span{float:right}.ant-breadcrumb-rtl .ant-breadcrumb-link>.anticon+span,.ant-breadcrumb-rtl .ant-breadcrumb-link>.anticon+a{margin-right:4px;margin-left:0}.ant-breadcrumb-rtl .ant-breadcrumb-overlay-link>.anticon{margin-right:4px;margin-left:0}.nprogress{pointer-events:none}.nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px}.nprogress .peg{display:block;position:absolute;right:0px;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1;-webkit-transform:rotate(3deg) translate(0px,-4px);-ms-transform:rotate(3deg) translate(0px,-4px);transform:rotate(3deg) translateY(-4px)}.nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px}.nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:solid 2px transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner .4s linear infinite;animation:nprogress-spinner .4s linear infinite}.nprogress-custom-parent{overflow:hidden;position:relative}.nprogress-custom-parent .nprogress .spinner,.nprogress-custom-parent .nprogress .bar{position:absolute}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes nprogress-spinner{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.preview-switch[data-v-e4015e72]{position:fixed;top:0;bottom:0;left:0;right:0;display:flex;align-items:center;justify-content:space-between;z-index:11111;pointer-events:none}.preview-switch>*[data-v-e4015e72]{color:#fff;margin:16px;font-size:4em;pointer-events:all;cursor:pointer}.preview-switch>*.disable[data-v-e4015e72]{opacity:0;pointer-events:none;cursor:none}.breadcrumb[data-v-e4015e72]{display:flex;align-items:center}.breadcrumb>*[data-v-e4015e72]{margin-right:4px}.container[data-v-e4015e72]{background:var(--zp-secondary-background);height:var(--pane-max-height)}.location-bar[data-v-e4015e72]{padding:4px 16px;background:var(--zp-primary-background);border-bottom:1px solid var(--zp-border);display:flex;align-items:center;justify-content:space-between}.location-bar .actions[data-v-e4015e72]{display:flex;align-items:center;flex-shrink:0}.location-bar a.opt[data-v-e4015e72]{margin-left:8px}.view[data-v-e4015e72]{padding:8px;height:calc(100vh - 48px)}.view .file-list[data-v-e4015e72]{list-style:none;padding:8px;height:100%;overflow:auto}.hint[data-v-e4015e72]{padding:4px;border:4px;background:var(--zp-secondary-background);border:1px solid var(--zp-border)}

4
vue/dist/index.html vendored
View File

@ -7,8 +7,8 @@
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Infinite Image Browsing</title>
<script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-5716a5d2.js"></script>
<link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-8961c2b3.css">
<script type="module" crossorigin src="/infinite_image_browsing/fe-static/assets/index-837602c1.js"></script>
<link rel="stylesheet" href="/infinite_image_browsing/fe-static/assets/index-ae43cab2.css">
</head>
<body>

View File

@ -145,15 +145,21 @@ const zh = {
edit: '编辑',
document: '文档',
multiSelectTips: '您可以按住 Shift、Ctrl 或 Cmd 键,然后单击文件来进行多选删除/移动操作',
copyLocationUrlSuccessMsg: "复制完成,你可以通过复制的链接直接打开当前文件夹",
share: '分享'
copyLocationUrlSuccessMsg: '复制完成,你可以通过复制的链接直接打开当前文件夹',
share: '分享',
dragImageHere: '拖拽图像到这里',
imgCompare: '图像对比'
}
const en: Record<keyof typeof zh, string> = {
//! MissingTranslations: "Mark missing translations like this""shortcutKey": "Keyboard Shortcuts",
//! MissingTranslations
imgCompare: 'Image Comparison',
share: 'Share',
copyLocationUrlSuccessMsg: 'Copy completed, you can directly open the current folder through the copied link',
multiSelectTips: 'You can hold down the Shift, Ctrl, or Cmd key and then click on files to perform batch delete/move operations',
dragImageHere: 'Drag image here',
copyLocationUrlSuccessMsg:
'Copy completed, you can directly open the current folder through the copied link',
multiSelectTips:
'You can hold down the Shift, Ctrl, or Cmd key and then click on files to perform batch delete/move operations',
document: 'Document',
copy: 'Copy',
edit: 'Edit',

View File

@ -0,0 +1,124 @@
<script setup lang="ts">
import { useImgSliStore } from '@/store/useImgSli'
import { isFileTransferData, toRawFileUrl } from '@/page/fileTransfer/util'
import { CloseCircleOutlined } from '@/icon'
import { isImageFile } from '@/util'
import { storeToRefs } from 'pinia'
const sliStore = useImgSliStore()
const { left, right } = storeToRefs(sliStore)
const onImageDrop = async (e: DragEvent, side: 'left' | 'right') => {
const data = JSON.parse(e.dataTransfer?.getData('text') ?? '{}')
if (isFileTransferData(data)) {
const img = data.nodes[0]
if (!isImageFile(img.name)) {
return
}
sliStore[side] = img
}
}
const onCancel = () => {
sliStore.left = undefined
sliStore.right = undefined
}
</script>
<template>
<Transition>
<div class="dragging-port-wrap" v-if="sliStore.fileDragging || left || right">
<h2>{{ $t('imgCompare') }}</h2>
<div class="content">
<div class="left port" @dragover.prevent @drop.prevent="onImageDrop($event, 'left')">
<div v-if="left" class="img-wrap">
<AImage :src="toRawFileUrl(left)" />
<CloseCircleOutlined class="close" @click="left = undefined" />
</div>
<div v-else>
{{ $t('dragImageHere') }}
</div>
</div>
<div style="padding: 16px" />
<div class="right port" @dragover.prevent @drop.prevent="onImageDrop($event, 'right')">
<div v-if="right" class="img-wrap">
<AImage :src="toRawFileUrl(right)" />
<CloseCircleOutlined class="close" @click="right = undefined" />
</div>
<div v-else>
{{ $t('dragImageHere') }}
</div>
</div>
</div>
<div>
<AButton type="primary" @click="sliStore.drawerVisible = true">Confirm</AButton>
<AButton style="margin-left: 16px;" @click="onCancel">Cancel</AButton>
</div>
</div>
</Transition>
</template>
<style scoped lang="scss">
.dragging-port-wrap {
position: fixed;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
background: var(--zp-primary-background);
box-shadow: 0 0 4px var(--zp-secondary);
border-radius: 8px;
padding: 16px 32px;
.content {
display: flex;
align-items: center;
margin: 8px 0;
.port {
display: flex;
align-items: center;
justify-content: center;
width: 128px;
height: 128px;
border-radius: 8px;
border: 1px solid var(--zp-tertiary);
.img-wrap {
position: relative;
:deep() {
width: 128px;
height: 128px;
object-fit: contain;
}
.close {
position: absolute;
top: 0;
right: 0;
transform: translate(50%, -50%);
font-size: 1.5em;
background: white;
border-radius: 100%;
color: black;
z-index: 999;
cursor: pointer;
}
}
}
}
}
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>

View File

@ -0,0 +1,66 @@
<script setup lang="ts">
// @ts-ignore
import { Splitpanes, Pane } from 'splitpanes'
import DraggingPort from './DraggingPort.vue'
import { useImgSliStore } from '@/store/useImgSli'
import ImgSliSide from './ImgSliSide.vue'
const sli = useImgSliStore()
const onResize = ([{ size }]: { size: number }[]) => {
sli.splitPercent = size
}
</script>
<template>
<ADrawer width="100vw" v-model:visible="sli.drawerVisible" destroy-on-close class="img-sli">
<splitpanes class="default-theme" @resize="onResize">
<pane>
<ImgSliSide side="left" />
</pane>
<pane>
<ImgSliSide side="right" />
</pane>
</splitpanes>
</ADrawer>
<DraggingPort />
</template>
<style lang="scss">
.img-sli .default-theme {
.splitpanes {
background-color: #f8f8f8;
}
.splitpanes__splitter {
background-color: #ccc;
position: relative;
width: 2px;
}
.splitpanes__splitter:before {
content: '';
position: absolute;
left: 0;
top: 0;
transition: opacity 0.4s;
opacity: 0;
z-index: 1;
}
.splitpanes__splitter:hover:before {
opacity: 1;
}
.splitpanes--vertical>.splitpanes__splitter:before {
left: -30px;
right: -30px;
height: 100%;
}
.splitpanes--horizontal>.splitpanes__splitter:before {
top: -30px;
bottom: -30px;
width: 100%;
}
}</style>

View File

@ -0,0 +1,49 @@
<script setup lang="ts">
import { useImgSliStore } from '@/store/useImgSli'
import { toRawFileUrl } from '../fileTransfer/util'
import { computed } from 'vue'
const props = defineProps<{ side: 'left' | 'right' }>()
const sli = useImgSliStore()
const style = computed(() => {
let x = ''
const width = document.body.getBoundingClientRect().width - 48 - 7
const per = sli.splitPercent
if (props.side === 'left') {
x = `calc(50% - ${(per - 50) / 100 * width}px)`
} else {
x = `calc(-50% - ${(per - 50) / 100 * width}px)`
}
return `${sli.maxEdge === 'width' ? 'width:100%' : 'height:100%'};transform: translate(${x}, -50%)`
})
</script>
<template>
<div class="container" v-if="sli?.[side]">
<img class="img" :class="[side]" :style="style" :src="toRawFileUrl(sli[side]!)" />
</div>
</template>
<style lang="scss" scoped>
.container {
position: relative;
user-select: none;
height: 100%;
.img {
position: absolute;
top: 50%;
}
.left {
transform: translate(50%, -50%);
right: 0;
}
.right {
transform: translate(-50%, -50%);
left: 0;
}
}
</style>

View File

@ -9,6 +9,8 @@ import { debounce, uniqueId } from 'lodash-es'
import edgeTrigger from './edgeTrigger.vue'
import { t } from '@/i18n'
import { tryOnMounted, useDocumentVisibility, type Fn } from '@vueuse/core'
import ImgSliDrawer from '../ImgSli/ImgSliDrawer.vue'
const global = useGlobalStore()
@ -79,8 +81,8 @@ const emitReturnToIIB = debounce(() => globalEvents.emit('return-to-iib'), 100)
tryOnMounted(async () => {
const par = window.parent as Window & { get_uiCurrentTabContent (): undefined | HTMLButtonElement, onUiTabChange (cb: Fn): void }
if (!await asyncCheck(() => par?.onUiTabChange, 200, 30_000)) {
console.log('watch tab change failed');
return
console.log('watch tab change failed')
return
}
par.onUiTabChange(() => {
const el = par.get_uiCurrentTabContent()
@ -104,6 +106,7 @@ watch(useDocumentVisibility(), v => v && emitReturnToIIB())
</edge-trigger>
</pane>
</splitpanes>
<img-sli-drawer />
</div>
</template>
<style scoped lang="scss">

View File

@ -29,7 +29,8 @@ const {
onFileItemClick,
scroller,
showMenuIdx,
onFileDragStart
onFileDragStart,
onFileDragEnd
} = useImageSearch()
const props = defineProps<{
@ -86,6 +87,7 @@ watch(
:file="file"
v-model:show-menu-idx="showMenuIdx"
@dragstart="onFileDragStart"
@dragend="onFileDragEnd"
@file-item-click="onFileItemClick"
:full-screen-preview-image-url="
images[previewIdx] ? toRawFileUrl(images[previewIdx]) : ''

View File

@ -31,7 +31,8 @@ const {
onFileItemClick,
scroller,
showMenuIdx,
onFileDragStart
onFileDragStart,
onFileDragEnd
} = useImageSearch()
const substr = ref('')
@ -99,7 +100,7 @@ useGlobalEventListen('return-to-iib', async () => {
<file-item-cell :idx="idx" :file="file" v-model:show-menu-idx="showMenuIdx" @file-item-click="onFileItemClick"
:full-screen-preview-image-url="images[previewIdx] ? toRawFileUrl(images[previewIdx]) : ''"
:selected="multiSelectedIdxs.includes(idx)" @context-menu-click="onContextMenuClickU"
@dragstart="onFileDragStart"
@dragstart="onFileDragStart" @dragend="onFileDragEnd"
@preview-visible-change="onPreviewVisibleChange" />
</template>
</RecycleScroller>

View File

@ -21,7 +21,7 @@ export const useImageSearch = () => {
const { stackViewEl, multiSelectedIdxs, stack } = useHookShareState({ images }).toRefs()
const { itemSize, gridItems } = useFilesDisplay(propsMock)
const { showMenuIdx } = useMobileOptimization()
const { onFileDragStart } = useFileTransfer() // for reset selected
const { onFileDragStart, onFileDragEnd } = useFileTransfer()
const {
showGenInfo,
imageGenInfo,
@ -63,6 +63,7 @@ export const useImageSearch = () => {
onFileItemClick,
showMenuIdx,
multiSelectedIdxs,
onFileDragStart
onFileDragStart,
onFileDragEnd
}
}

View File

@ -27,6 +27,7 @@ const emit = defineEmits<{
(type: 'update:showMenuIdx', v: number): void
(type: 'fileItemClick', event: MouseEvent, file: FileNodeInfo, idx: number): void
(type: 'dragstart', event: DragEvent, idx: number): void
(type: 'dragend', event: DragEvent, idx: number): void
(type: 'previewVisibleChange', value: boolean, last: boolean): void
(type: 'contextMenuClick', e: MenuInfo, file: FileNodeInfo, idx: number): void
}>()
@ -71,6 +72,7 @@ const imageSrc = computed(() => {
:key="file.name"
draggable="true"
@dragstart="emit('dragstart', $event, idx)"
@dragend="emit('dragend', $event, idx)"
@contextmenu="onRightClick"
@click.capture="emit('fileItemClick', $event, file, idx)"
>

View File

@ -1,4 +1,5 @@
import { useGlobalStore, type FileTransferTabPane, type Shortcut } from '@/store/useGlobalStore'
import { useImgSliStore } from '@/store/useImgSli'
import { onLongPress, useElementSize } from '@vueuse/core'
import { ref, computed, watch, onMounted, h, type Ref } from 'vue'
import { gradioApp, parentWindow } from '@/util'
@ -30,21 +31,14 @@ import type { MenuInfo } from 'ant-design-vue/lib/menu/src/interface'
import { t } from '@/i18n'
import { DatabaseOutlined } from '@/icon'
import { addScannedPath, removeScannedPath, toggleCustomTagToImg } from '@/api/db'
import { FileTransferData, isFileTransferData, toRawFileUrl } from './util'
export * from './util'
export const stackCache = new Map<string, Page[]>()
const global = useGlobalStore()
const sli = useImgSliStore()
const imgTransferBus = new BroadcastChannel('iib-image-transfer-bus')
const encode = encodeURIComponent
export const toRawFileUrl = (file: FileNodeInfo, download = false) =>
`/infinite_image_browsing/file?path=${encode(file.fullpath)}&t=${encode(file.date)}${
download ? `&disposition=${encode(file.name)}` : ''
}`
export const toImageThumbnailUrl = (file: FileNodeInfo, size: string) =>
`/infinite_image_browsing/image-thumbnail?path=${encode(file.fullpath)}&size=${size}&t=${encode(
file.date
)}`
export const { eventEmitter: events, useEventListen } = typedEventEmitter<{
removeFiles(_: { paths: string[]; loc: string }): void
addFiles(_: { files: FileNodeInfo[]; loc: string }): void
@ -646,6 +640,7 @@ export function useFilesDisplay(props: Props) {
itemSize
}
}
const multiSelectTips = () =>
h(
'p',
@ -653,11 +648,12 @@ const multiSelectTips = () =>
style: {
background: 'var(--zp-secondary-background)',
padding: '8px',
borderLeft: '4px solid var(--primary-color)',
borderLeft: '4px solid var(--primary-color)'
}
},
`Tips: ${t('multiSelectTips')}`
)
export function useFileTransfer() {
const { currLocation, sortedFiles, currPage, multiSelectedIdxs, eventEmitter } =
useHookShareState().toRefs()
@ -670,6 +666,7 @@ export function useFileTransfer() {
const onFileDragStart = (e: DragEvent, idx: number) => {
const file = cloneDeep(sortedFiles.value[idx])
sli.fileDragging = true
console.log('onFileDragStart set drag file ', e, idx, file)
const files = [file]
let includeDir = file.type === 'dir'
@ -678,25 +675,26 @@ export function useFileTransfer() {
files.push(...selectedFiles)
includeDir = selectedFiles.some((v) => v.type === 'dir')
}
const data: FileTransferData = {
includeDir,
loc: currLocation.value || 'search-result',
path: uniqBy(files, 'fullpath').map((f) => f.fullpath),
nodes: uniqBy(files, 'fullpath'),
__id: 'FileTransferData'
}
e.dataTransfer!.setData(
'text/plain',
JSON.stringify({
includeDir,
loc: currLocation.value || 'search-result',
path: uniqBy(files, 'fullpath').map((f) => f.fullpath)
})
JSON.stringify(data)
)
}
const onFileDragEnd = () => {
sli.fileDragging = false
}
const onDrop = async (e: DragEvent) => {
type Data = {
path: string[]
loc: string
includeDir: boolean
}
const data = JSON.parse(e.dataTransfer?.getData('text') || '{}') as Data
console.log(data)
if (data.path && typeof data.includeDir !== 'undefined' && data.loc) {
const data = JSON.parse(e.dataTransfer?.getData('text') ?? '{}')
if (isFileTransferData(data)) {
const toPath = currLocation.value
if (data.loc === toPath) {
return
@ -724,7 +722,8 @@ export function useFileTransfer() {
return {
onFileDragStart,
onDrop,
multiSelectedIdxs
multiSelectedIdxs,
onFileDragEnd
}
}

View File

@ -65,7 +65,7 @@ const {
onScroll,
} = useFilesDisplay(props)
const { onDrop, onFileDragStart } = useFileTransfer()
const { onDrop, onFileDragStart, onFileDragEnd } = useFileTransfer()
const { onFileItemClick, onContextMenuClick, showGenInfo, imageGenInfo, q } = useFileItemActions(
props,
{ openNext }
@ -199,7 +199,7 @@ watch(
<file-item :idx="idx" :file="file"
:full-screen-preview-image-url="sortedFiles[previewIdx] ? toRawFileUrl(sortedFiles[previewIdx]) : ''"
v-model:show-menu-idx="showMenuIdx" :selected="multiSelectedIdxs.includes(idx)" :view-mode="viewMode"
@file-item-click="onFileItemClick" @dragstart="onFileDragStart"
@file-item-click="onFileItemClick" @dragstart="onFileDragStart" @dragend=" onFileDragEnd"
@preview-visible-change="onPreviewVisibleChange" @context-menu-click="onContextMenuClick" />
</template>
<template v-if="props.walkModePath" #after>

View File

@ -0,0 +1,23 @@
import type { FileNodeInfo } from '@/api/files'
const encode = encodeURIComponent
export const toRawFileUrl = (file: FileNodeInfo, download = false) =>
`/infinite_image_browsing/file?path=${encode(file.fullpath)}&t=${encode(file.date)}${
download ? `&disposition=${encode(file.name)}` : ''
}`
export const toImageThumbnailUrl = (file: FileNodeInfo, size: string) =>
`/infinite_image_browsing/image-thumbnail?path=${encode(file.fullpath)}&size=${size}&t=${encode(
file.date
)}`
export type FileTransferData = {
path: string[]
loc: string
includeDir: boolean
nodes: FileNodeInfo[]
__id: 'FileTransferData'
}
export const isFileTransferData = (v: any): v is FileTransferData =>
typeof v === 'object' && v.__id === 'FileTransferData'

View File

@ -0,0 +1,32 @@
import { FileNodeInfo } from '@/api/files'
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { asyncComputed } from '@vueuse/core'
import { createImage } from '@/util'
import { toRawFileUrl } from '@/page/fileTransfer/util'
export const useImgSliStore = defineStore('useImgSliStore', () => {
const splitPercent = ref(50)
const fileDragging = ref(false)
const drawerVisible = ref(false)
const left = ref<FileNodeInfo>()
const right = ref<FileNodeInfo>()
const maxEdge = asyncComputed(async () => {
if (!left.value) {
return 'width'
}
const l = await createImage(toRawFileUrl(left.value))
const aspectRatio = l.width / l.height
const clientAR = document.body.clientWidth / document.body.clientHeight
return aspectRatio > clientAR ? 'width' : 'height'
})
return {
drawerVisible,
splitPercent,
fileDragging,
left,
right,
maxEdge
}
})

View File

@ -31,7 +31,11 @@ export const getTabIdxInSDWebui = () => {
}
export const switch2IBB = () => {
gradioApp().querySelector('#tabs')!.querySelectorAll('button')[getTabIdxInSDWebui()].click()
try {
gradioApp().querySelector('#tabs')!.querySelectorAll('button')[getTabIdxInSDWebui()].click()
} catch (error) {
console.error(error)
}
}
export const asyncCheck = async <T>(getter: () => T, checkSize = 100, timeout = 1000) => {
@ -154,3 +158,13 @@ export function removeQueryParams(keys: string[]): string {
// 返回新的 URL
return newUrl
}
export const createImage = (src: string) => {
return new Promise<HTMLImageElement>((resolve, reject) => {
const img = new Image()
img.onload = () => resolve(img)
img.onerror = err => reject(err)
img.src = src
})
}