Redesign product detail page and fix icon/cart reactivity bugs
- SingleProduct.vue: rebuild gallery/header/action bar as a self-scrolling layout with a sticky photo, solid-on-scroll header matching PageBar, and a full-screen image preview (blurred overlay, centered thumbnail strip) - Add GallerySlider.vue: pointer-based swipe carousel isolated in an LTR subtree, fixing RTL/transform sign mismatch that caused slide jumps - Fix Icon.vue: icon was read into a plain ref once at setup and never updated on prop change; switch to computed so icon swaps (e.g. cart qty stepper trash/minus toggle) actually re-render - Fix quantity stepper DOM order in SingleProduct.vue/CartItem.vue so plus/minus render correctly under RTL flex - prisma/assign-downloaded-images.js: seed real product photos (FEATURED/ FEATURED_MOBILE/GALLERY/GALLERY_MOBILE) onto the 5 placeholder products
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{d as f,o as v,c as s,l as e,q as u,g as m,h as p,f as o,F as g,r as y,I as P,b as k,e as C,s as b,H as h,j as x,_ as B}from"./index-CmYEpHK9.js";import{P as V}from"./PageBar-D80e377v.js";import{a as w}from"./Spinner.vue_vue_type_style_index_0_lang-CvgYqzhC.js";import{S as I}from"./SectionHead-L1TLZGJP.js";import{P as N}from"./ProductCard-BeFuxqqt.js";import{a as q}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-CDKWZbYq.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-jgMMdODO.js";import"./DialogVant.vue_vue_type_style_index_0_lang-D7yryjTd.js";import"./cartStore-DSCChC_v.js";import"./dialogEmpty1-Caw7F5KL.js";import"./index-DSgZu76n.js";import"./classCallCheck-Ddn4Ym7v.js";const F={class:"coll"},H={key:0,class:"coll__grid"},S={key:1,class:"coll__empty"},j=f({__name:"CollectionView",setup(z){const l=h(),t=m(!1),n=m([]),d=p(()=>l.query.page||"مجموعه"),r=p(()=>n.value.filter(c=>c.collections.some(a=>a.collectionId===l.params.id)));return v(async()=>{t.value=!0;try{n.value=await q.listProducts()}finally{t.value=!1}}),(c,a)=>{const _=b("container");return o(),s("div",F,[e(V,{title:d.value,"back-to":"search"},null,8,["title"]),e(w,{spinning:t.value,tip:"درحال دریافت اطلاعات"},{default:u(()=>[e(_,{class:"coll__body"},{default:u(()=>[e(I,{title:"محصولات این مجموعه",subtitle:"برای دیدن جزئیات، روی محصول ضربه بزنید"}),r.value.length?(o(),s("div",H,[(o(!0),s(g,null,y(r.value,i=>(o(),x(N,{key:i.id,value:i},null,8,["value"]))),128))])):t.value?C("",!0):(o(),s("section",S,[e(P,{icon:"vuesax-linear:box",size:"26"}),a[0]||(a[0]=k("p",null,"در این مجموعه محصولی ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"])])}}}),W=B(j,[["__scopeId","data-v-6fdc1b6f"]]);export{W as default};
|
||||
import{d as f,o as v,c as s,l as e,q as u,g as m,h as p,f as o,F as g,r as y,I as P,b as k,e as C,s as b,H as h,j as x,_ as B}from"./index-gciDsUQi.js";import{P as V}from"./PageBar-uS5upavZ.js";import{a as w}from"./Spinner.vue_vue_type_style_index_0_lang-CkjhJnbV.js";import{S as I}from"./SectionHead-BKOd3BbV.js";import{P as N}from"./ProductCard-CoWnvkjC.js";import{a as q}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-Bz_F3HVn.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-T1ksLsUj.js";import"./DialogVant.vue_vue_type_style_index_0_lang-BM_3o3Fn.js";import"./cartStore-BqvRThaH.js";import"./dialogEmpty1-Caw7F5KL.js";import"./index-B7DBPshJ.js";import"./classCallCheck-C6rD-0r0.js";const F={class:"coll"},H={key:0,class:"coll__grid"},S={key:1,class:"coll__empty"},j=f({__name:"CollectionView",setup(z){const l=h(),t=m(!1),n=m([]),d=p(()=>l.query.page||"مجموعه"),r=p(()=>n.value.filter(c=>c.collections.some(a=>a.collectionId===l.params.id)));return v(async()=>{t.value=!0;try{n.value=await q.listProducts()}finally{t.value=!1}}),(c,a)=>{const _=b("container");return o(),s("div",F,[e(V,{title:d.value,"back-to":"search"},null,8,["title"]),e(w,{spinning:t.value,tip:"درحال دریافت اطلاعات"},{default:u(()=>[e(_,{class:"coll__body"},{default:u(()=>[e(I,{title:"محصولات این مجموعه",subtitle:"برای دیدن جزئیات، روی محصول ضربه بزنید"}),r.value.length?(o(),s("div",H,[(o(!0),s(g,null,y(r.value,i=>(o(),x(N,{key:i.id,value:i},null,8,["value"]))),128))])):t.value?C("",!0):(o(),s("section",S,[e(P,{icon:"vuesax-linear:box",size:"26"}),a[0]||(a[0]=k("p",null,"در این مجموعه محصولی ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"])])}}}),W=B(j,[["__scopeId","data-v-6fdc1b6f"]]);export{W as default};
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
.dash[data-v-b8482634]{background:#fff;min-height:100vh}.dash__bar[data-v-b8482634]{position:fixed;top:0;left:0;right:0;z-index:20;background:#ffffffd1;-webkit-backdrop-filter:blur(18px) saturate(140%);backdrop-filter:blur(18px) saturate(140%);border-bottom:1px solid rgba(28,45,86,.05);box-shadow:0 8px 20px -18px #1c2d568c}.dash__barInner[data-v-b8482634]{max-width:768px;margin:0 auto;padding:10px 16px;display:flex;align-items:center;justify-content:space-between;gap:12px}.dash__brand[data-v-b8482634]{font-size:14.5px;font-weight:800;color:#14161a}.dash__exit[data-v-b8482634]{flex:0 0 auto;width:34px;height:34px;border:0;cursor:pointer;border-radius:11px;display:grid;place-items:center;color:#7a1b33;background:#fbf2f4;transition:transform .18s ease}.dash__exit[data-v-b8482634]:active{transform:scale(.92)}.dash__body[data-v-b8482634]{padding-top:58px;padding-bottom:90px}.dash__reveal[data-v-b8482634]{opacity:0;transform:translate3d(0,14px,0) scale(.98);will-change:transform,opacity}.is-revealed .dash__reveal[data-v-b8482634]{opacity:1;transform:translateZ(0) scale(1);transition:opacity .62s cubic-bezier(.32,.72,0,1) var(--reveal-delay, 0ms),transform .62s cubic-bezier(.32,.72,0,1) var(--reveal-delay, 0ms)}@media (prefers-reduced-motion: reduce){.dash__reveal[data-v-b8482634]{opacity:1;transform:none}.is-revealed .dash__reveal[data-v-b8482634]{transition:none}}.dash__hero[data-v-b8482634]{margin-top:16px;margin-bottom:28px;padding:20px 18px 16px;border-radius:26px;background:linear-gradient(155deg,#14161a,#14161a 55%,#5e1427 130%);color:#fff;box-shadow:0 22px 40px -26px #14161a52}.dash__heroTop[data-v-b8482634]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.dash__heroIdentity[data-v-b8482634]{display:flex;flex-direction:column;gap:3px;min-width:0}.dash__heroName[data-v-b8482634]{font-size:13.5px;font-weight:800}.dash__heroMobile[data-v-b8482634]{font-size:11px;color:#ffffff8c;direction:ltr;text-align:right}.dash__heroSeal[data-v-b8482634]{flex:0 0 auto;padding:5px 12px;border-radius:999px;font-size:10.5px;font-weight:700}.dash__heroSeal.is-debtor[data-v-b8482634]{color:#fff;background:#a33c55}.dash__heroSeal.is-creditor[data-v-b8482634]{color:#14161a;background:#ffffffe6}.dash__heroFigure[data-v-b8482634]{margin-top:20px;display:flex;align-items:baseline;gap:8px}.dash__heroNum[data-v-b8482634]{font-size:34px;font-weight:800;letter-spacing:-.5px}.dash__heroUnit[data-v-b8482634]{font-size:12px;font-weight:600;color:#ffffff9e}.dash__heroDebt[data-v-b8482634]{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:14px;padding-top:13px;border-top:1px solid rgba(255,255,255,.14);font-size:11.5px;color:#ffffff9e}.dash__heroDebt b[data-v-b8482634]{font-size:13px;font-weight:700;color:#fff}.dash__heroDebt i[data-v-b8482634]{font-style:normal;font-size:10.5px;font-weight:600;color:#ffffff9e;padding-inline-start:3px}.dash__invite[data-v-b8482634]{margin-top:16px;padding:26px 20px;border-radius:26px;background:#14161a;color:#fff;display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px}.dash__inviteIcon[data-v-b8482634]{width:46px;height:46px;border-radius:50%;display:grid;place-items:center;background:#ffffff1a;margin-bottom:2px}.dash__invite h3[data-v-b8482634]{margin:0;font-size:14px;font-weight:800}.dash__invite p[data-v-b8482634]{margin:0;font-size:11.5px;color:#fff9;max-width:240px}.dash__inviteCta[data-v-b8482634]{margin-top:6px;padding:10px 22px;border:0;cursor:pointer;border-radius:999px;font-family:inherit;font-size:12px;font-weight:700;color:#14161a;background:#fff;transition:transform .18s ease}.dash__inviteCta[data-v-b8482634]:active{transform:scale(.96)}.dash__rows[data-v-b8482634]{margin-top:0;display:flex;flex-direction:column;gap:9px}.dash__row[data-v-b8482634]{display:flex;align-items:center;gap:12px;padding:13px 14px;border:1px solid #ECEDEF;border-radius:17px;cursor:pointer;background:#fff;font-family:inherit;text-align:right;transition:transform .18s ease,border-color .18s ease}.dash__row[data-v-b8482634]:active{transform:scale(.985);border-color:#7a1b3333}.dash__rowIcon[data-v-b8482634]{flex:0 0 auto;width:38px;height:38px;border-radius:12px;display:grid;place-items:center;color:#7a1b33;background:#fbf2f4}.dash__rowText[data-v-b8482634]{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.dash__rowText b[data-v-b8482634]{font-size:12.5px;font-weight:700;color:#14161a}.dash__rowText small[data-v-b8482634]{font-size:10.5px;color:#8a909c}.dash__rate[data-v-b8482634]{margin-top:14px}
|
||||
@@ -1 +0,0 @@
|
||||
.dash[data-v-a9e43f33]{background:#fff;min-height:100vh}.dash__bar[data-v-a9e43f33]{position:fixed;top:0;left:0;right:0;z-index:20;background:#ffffffe0;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-bottom:1px solid #ECEDEF}.dash__barInner[data-v-a9e43f33]{max-width:768px;margin:0 auto;padding:11px 16px;display:flex;align-items:center;justify-content:space-between;gap:12px}.dash__barTitle[data-v-a9e43f33]{margin:0;font-size:14.5px;font-weight:800;color:#14161a}.dash__barBtn[data-v-a9e43f33]{flex:0 0 auto;width:38px;height:38px;border:0;cursor:pointer;border-radius:12px;display:grid;place-items:center;color:#7a1b33;background:#fbf2f4}.dash__barBtn[data-v-a9e43f33]:active{transform:scale(.94)}.dash__barSpacer[data-v-a9e43f33]{display:block;width:38px;height:38px}.dash__body[data-v-a9e43f33]{padding-top:76px;padding-bottom:90px}.dash__balance[data-v-a9e43f33]{padding:16px;border-radius:20px;background:#14161a;color:#fff;box-shadow:0 14px 30px -22px #14161af2}.dash__balanceHead[data-v-a9e43f33]{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.dash__eyebrow[data-v-a9e43f33]{font-size:11.5px;color:#ffffff9e}.dash__figure[data-v-a9e43f33]{padding-top:5px;font-size:25px;font-weight:800;letter-spacing:-.3px}.dash__unit[data-v-a9e43f33]{font-size:11.5px;font-weight:600;color:#ffffff9e;padding-inline-start:4px}.dash__seal[data-v-a9e43f33]{flex:0 0 auto;padding:5px 12px;border-radius:999px;font-size:10.5px;font-weight:700}.dash__seal.is-debtor[data-v-a9e43f33]{color:#fff;background:#a33c55}.dash__seal.is-creditor[data-v-a9e43f33]{color:#14161a;background:#ffffffe6}.dash__balanceRow[data-v-a9e43f33]{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:16px;padding-top:13px;border-top:1px solid rgba(255,255,255,.13)}.dash__rowLabel[data-v-a9e43f33]{font-size:11.5px;color:#ffffff9e}.dash__rowValue[data-v-a9e43f33]{font-size:13.5px;font-weight:700}.dash__rowValue i[data-v-a9e43f33]{font-style:normal;font-size:10.5px;font-weight:600;color:#ffffff9e;padding-inline-start:3px}.dash__identity[data-v-a9e43f33]{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:13px;padding-top:13px;border-top:1px solid rgba(255,255,255,.13)}.dash__name[data-v-a9e43f33]{font-size:12.5px;font-weight:700}.dash__mobile[data-v-a9e43f33]{font-size:11.5px;color:#ffffff9e;direction:ltr}.dash__invite[data-v-a9e43f33]{display:flex;align-items:center;gap:12px;padding:16px;border:1px solid #ECEDEF;border-radius:20px;background:#fafafa}.dash__inviteIcon[data-v-a9e43f33]{flex:0 0 42px;width:42px;height:42px;border-radius:50%;display:grid;place-items:center;color:#7a1b33;background:#fbf2f4}.dash__inviteCopy[data-v-a9e43f33]{flex:1;min-width:0}.dash__inviteCopy h3[data-v-a9e43f33]{margin:0;font-size:13px;font-weight:800;color:#14161a}.dash__inviteCopy p[data-v-a9e43f33]{margin:4px 0 0;font-size:11.5px;color:#8a909c}.dash__inviteCta[data-v-a9e43f33]{flex:0 0 auto;padding:9px 14px;border:0;cursor:pointer;border-radius:999px;font-family:inherit;font-size:11.5px;font-weight:700;color:#fff;background:#14161a}.dash__section[data-v-a9e43f33]{margin-top:26px}.dash__grid[data-v-a9e43f33]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px}.dash__tile[data-v-a9e43f33]{display:flex;flex-direction:column;align-items:center;gap:8px;padding:14px 6px;border:1px solid #ECEDEF;border-radius:16px;cursor:pointer;background:#fff;font-family:inherit;transition:transform .18s ease}.dash__tile[data-v-a9e43f33]:active{transform:scale(.97)}.dash__tile.is-disabled[data-v-a9e43f33]{opacity:.4}.dash__tileIcon[data-v-a9e43f33]{width:38px;height:38px;border-radius:12px;display:grid;place-items:center;color:#22262e;background:#f4f5f6}.dash__tileTitle[data-v-a9e43f33]{font-size:11px;font-weight:700;color:#22262e}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
.van-dialog__confirm,.van-dialog__cancel{display:none!important}.mDialog.van-dialog{width:min(320px,calc(100vw - 48px));border-radius:26px;background:#fff;box-shadow:0 30px 60px -24px #14161a73;overflow:hidden}.mDialog__body{padding:26px 22px 20px;display:flex;flex-direction:column;align-items:center;text-align:center}.mDialog__art{width:84px;height:84px;border-radius:50%;display:flex;align-items:center;justify-content:center;overflow:hidden;background:#fbf2f4;margin-bottom:18px}.mDialog__art img,.mDialog__art svg,.mDialog__art canvas{width:56px;height:56px;-o-object-fit:contain;object-fit:contain;opacity:1!important}.mDialog__title{font-size:14.5px;font-weight:700;line-height:1.9;color:#14161a}.mDialog__actions{width:100%;display:flex;flex-direction:column;gap:9px;margin-top:22px;font-size:13px;font-weight:700}.mDialog__actions>*{padding:12px;border-radius:14px;cursor:pointer;transition:transform .18s ease,opacity .18s ease}.mDialog__actions>*:active{transform:scale(.97)}.mDialog__actions>*:first-child{color:#fff!important;background:#14161a}.mDialog__actions>*:last-child{color:#8a909c!important;background:none}
|
||||
@@ -1 +0,0 @@
|
||||
.van-dialog__confirm,.van-dialog__cancel{display:none!important}.van-dialog__confirm .van-button__text{color:#1c2d56;font-weight:600;font-size:15px}.van-dialog__cancel .van-button__text{color:#6b7280;font-weight:600;font-size:15px}
|
||||
+1
@@ -0,0 +1 @@
|
||||
import{d as l,j as n,q as c,u as _,am as d,f as r,b as t,z as a,C as o,t as i}from"./index-gciDsUQi.js";const m={class:"mDialog__body"},g={class:"mDialog__art"},u={class:"mDialog__title"},D={class:"mDialog__actions"},h=l({__name:"DialogVant",props:{timeOut:{},text1:{},text2:{},text3:{}},setup(s){return(e,x)=>(r(),n(_(d),{class:"mDialog"},{default:c(()=>[t("div",m,[t("div",g,[a(e.$slots,"img",{},()=>[o(i(s.text2),1)])]),t("div",u,[a(e.$slots,"title",{},()=>[o(i(s.text1),1)])]),t("div",D,[a(e.$slots,"button",{},()=>[o(i(s.text3),1)])])])]),_:3}))}});export{h as _};
|
||||
-1
@@ -1 +0,0 @@
|
||||
import{d as i,j as n,q as r,u as d,aj as c,f,b as t,z as o,C as a,t as l}from"./index-CmYEpHK9.js";const x={class:"my-4"},u={class:"w-full flex justify-center"},m={class:"w-full flex justify-center text-[18px] font-semibold"},_={class:"grid grid-cols-2 border-t border-solid border-[#E5E7EB] pt-4 mx-2 mt-6 font-semibold text-[15px]"},g=i({__name:"DialogVant",props:{timeOut:{},text1:{},text2:{},text3:{}},setup(e){return(s,b)=>(f(),n(d(c),null,{default:r(()=>[t("div",x,[t("div",u,[o(s.$slots,"img",{},()=>[a(l(e.text2),1)])]),t("div",m,[o(s.$slots,"title",{},()=>[a(l(e.text1),1)])]),t("div",_,[o(s.$slots,"button",{},()=>[a(l(e.text3),1)])])])]),_:3}))}});export{g as _};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{d as f,o as g,c as o,l as e,q as c,g as m,f as t,F as p,b as i,r as y,I as b,u as h,e as k,v as P,h as C,s as F,j as x,_ as B}from"./index-CmYEpHK9.js";import{P as V}from"./PageBar-D80e377v.js";import{a as w}from"./Spinner.vue_vue_type_style_index_0_lang-CvgYqzhC.js";import{S}from"./SectionHead-L1TLZGJP.js";import{P as I}from"./ProductCard-BeFuxqqt.js";import{a as N}from"./SingleProduct-CDKWZbYq.js";import{a as $}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./cartStore-DSCChC_v.js";import"./index-DSgZu76n.js";import"./classCallCheck-Ddn4Ym7v.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-jgMMdODO.js";import"./DialogVant.vue_vue_type_style_index_0_lang-D7yryjTd.js";import"./dialogEmpty1-Caw7F5KL.js";const R={class:"favs"},j={class:"favs__grid"},q={key:1,class:"favs__empty"},z=f({__name:"FavoritesView",setup(E){const d=P(),v=N(),a=m(!1),l=m([]),r=C(()=>l.value.filter(u=>v.isFavorite(u.id)));return g(async()=>{a.value=!0;try{l.value=await $.listProducts()}finally{a.value=!1}}),(u,s)=>{const _=F("container");return t(),o("div",R,[e(V,{title:"علاقهمندی","back-to":"userPage::hasSubRoute"}),e(w,{spinning:a.value,tip:"در حال دریافت اطلاعات"},{default:c(()=>[e(_,{class:"favs__body"},{default:c(()=>[r.value.length?(t(),o(p,{key:0},[e(S,{title:"ذخیرهشدهها",subtitle:`${r.value.length} محصول`},null,8,["subtitle"]),i("div",j,[(t(!0),o(p,null,y(r.value,n=>(t(),x(I,{key:n.id,value:n},null,8,["value"]))),128))])],64)):a.value?k("",!0):(t(),o("section",q,[e(b,{icon:"vuesax-linear:heart",size:"26"}),s[1]||(s[1]=i("p",null,"هنوز محصولی را به علاقهمندیها اضافه نکردهاید.",-1)),i("button",{type:"button",class:"favs__emptyCta",onClick:s[0]||(s[0]=n=>h(d).push({name:"home"}))}," دیدن محصولات ")]))]),_:1})]),_:1},8,["spinning"])])}}}),Y=B(z,[["__scopeId","data-v-a8e72280"]]);export{Y as default};
|
||||
import{d as f,o as g,c as o,l as e,q as c,g as m,f as t,F as p,b as i,r as y,I as b,u as h,e as k,v as P,h as C,s as F,j as x,_ as B}from"./index-gciDsUQi.js";import{P as V}from"./PageBar-uS5upavZ.js";import{a as w}from"./Spinner.vue_vue_type_style_index_0_lang-CkjhJnbV.js";import{S}from"./SectionHead-BKOd3BbV.js";import{P as I}from"./ProductCard-CoWnvkjC.js";import{a as N}from"./SingleProduct-Bz_F3HVn.js";import{a as $}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./cartStore-BqvRThaH.js";import"./index-B7DBPshJ.js";import"./classCallCheck-C6rD-0r0.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-T1ksLsUj.js";import"./DialogVant.vue_vue_type_style_index_0_lang-BM_3o3Fn.js";import"./dialogEmpty1-Caw7F5KL.js";const R={class:"favs"},j={class:"favs__grid"},q={key:1,class:"favs__empty"},z=f({__name:"FavoritesView",setup(E){const d=P(),v=N(),a=m(!1),l=m([]),r=C(()=>l.value.filter(u=>v.isFavorite(u.id)));return g(async()=>{a.value=!0;try{l.value=await $.listProducts()}finally{a.value=!1}}),(u,s)=>{const _=F("container");return t(),o("div",R,[e(V,{title:"علاقهمندی","back-to":"userPage::hasSubRoute"}),e(w,{spinning:a.value,tip:"در حال دریافت اطلاعات"},{default:c(()=>[e(_,{class:"favs__body"},{default:c(()=>[r.value.length?(t(),o(p,{key:0},[e(S,{title:"ذخیرهشدهها",subtitle:`${r.value.length} محصول`},null,8,["subtitle"]),i("div",j,[(t(!0),o(p,null,y(r.value,n=>(t(),x(I,{key:n.id,value:n},null,8,["value"]))),128))])],64)):a.value?k("",!0):(t(),o("section",q,[e(b,{icon:"vuesax-linear:heart",size:"26"}),s[1]||(s[1]=i("p",null,"هنوز محصولی را به علاقهمندیها اضافه نکردهاید.",-1)),i("button",{type:"button",class:"favs__emptyCta",onClick:s[0]||(s[0]=n=>h(d).push({name:"home"}))}," دیدن محصولات ")]))]),_:1})]),_:1},8,["spinning"])])}}}),Y=B(z,[["__scopeId","data-v-a8e72280"]]);export{Y as default};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{d,f as o,c as i,l as a,u as c,x as P,y as S,n as b,z as k,j as v,e as y,g as u,A as B,B as E,q as p,F as C,r as L,I,b as N,h as V,s as $,_ as A}from"./index-CmYEpHK9.js";import{P as F}from"./PageBar-D80e377v.js";import{E as z,a as h}from"./Spinner.vue_vue_type_style_index_0_lang-CvgYqzhC.js";import{S as j}from"./SectionHead-L1TLZGJP.js";import{P as q}from"./ProductCard-BeFuxqqt.js";import{a as D}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-CDKWZbYq.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-jgMMdODO.js";import"./DialogVant.vue_vue_type_style_index_0_lang-D7yryjTd.js";import"./cartStore-DSCChC_v.js";import"./dialogEmpty1-Caw7F5KL.js";import"./index-DSgZu76n.js";import"./classCallCheck-Ddn4Ym7v.js";const H={class:"flex justify-center items-center empty"},T=d({__name:"EmptyState",props:{description:{},image:{}},setup(e){return(t,s)=>(o(),i("div",H,[a(c(z),{description:"موردی یافت نشد",image:e.image,class:"h-[200px] w-[200px] opacity-70"},null,8,["image"])]))}}),G="/assets/favoritEmpty-CIK7qR49.svg",K=d({__name:"ScrollFetchSearch",props:{loading:{type:Boolean},flag:{type:Boolean},padding:{}},emits:["fetch"],setup(e,{emit:t}){const s=t,n=P(),r=u(null);return S(r,()=>{s("fetch")},{distance:50}),(l,m)=>(o(),i("main",{class:"flex flex-col flex-1 overflow-auto no-scrollbar w-[100vw] max-w-screen-md m-auto",style:b({paddingTop:e.padding||c(n).headerHeight+"px"}),ref_key:"scrollArea",ref:r},[k(l.$slots,"default"),a(h,{cls:"my-[10px]",spinning:e.loading,indicator:!0,tip:"درحال دریافت اطلاعات"},null,8,["spinning"]),e.flag?(o(),v(T,{key:0,image:c(G)},null,8,["image"])):y("",!0)],4))}});function M(){const e=B({totalPages:0,productList:[],flag:!1});return{productsData:e,getProducts:async(s,n=!1)=>{if(!n){s.value=!0;try{e.productList=await D.listProducts(),e.flag=e.productList.length<1}catch(r){console.log(r)}finally{s.value=!1}}}}}const R={class:"newest"},Z={key:0,class:"newest__grid"},J={key:1,class:"newest__empty"},g=20,O=d({__name:"NewestView",setup(e){const{productsData:t,getProducts:s}=M(),n=u(!1),r=u(!1),l=u(g),m=V(()=>t.productList.slice(0,l.value));E(async()=>{await s(n,!1)});const w=async()=>{if(l.value<t.productList.length){l.value+=g;return}await s(r,!0)};return(Q,f)=>{const x=$("container");return o(),i("div",R,[a(F,{title:"جدیدترین محصولات","back-to":"home"}),a(h,{spinning:n.value,tip:"درحال دریافت اطلاعات"},{default:p(()=>[a(K,{class:"newest__scroll",loading:r.value,flag:c(t).flag,padding:"0px",onFetch:w},{default:p(()=>[a(x,{class:"newest__body"},{default:p(()=>[a(j,{title:"تازهها",subtitle:"آخرین افزودههای مجموعه"}),c(t).productList.length?(o(),i("div",Z,[(o(!0),i(C,null,L(m.value,_=>(o(),v(q,{key:_.id,value:_},null,8,["value"]))),128))])):n.value?y("",!0):(o(),i("section",J,[a(I,{icon:"vuesax-linear:box",size:"26"}),f[0]||(f[0]=N("p",null,"هنوز محصولی در مجموعه ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["loading","flag"])]),_:1},8,["spinning"])])}}}),ue=A(O,[["__scopeId","data-v-ecd416be"]]);export{ue as default};
|
||||
import{d,f as o,c as i,l as a,u as c,x as P,y as S,n as b,z as k,j as v,e as y,g as u,A as B,B as E,q as p,F as C,r as L,I,b as N,h as V,s as $,_ as A}from"./index-gciDsUQi.js";import{P as F}from"./PageBar-uS5upavZ.js";import{E as z,a as h}from"./Spinner.vue_vue_type_style_index_0_lang-CkjhJnbV.js";import{S as j}from"./SectionHead-BKOd3BbV.js";import{P as q}from"./ProductCard-CoWnvkjC.js";import{a as D}from"./client-WIBW0tF5.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./SingleProduct-Bz_F3HVn.js";import"./NotifyVant.vue_vue_type_script_setup_true_lang-T1ksLsUj.js";import"./DialogVant.vue_vue_type_style_index_0_lang-BM_3o3Fn.js";import"./cartStore-BqvRThaH.js";import"./dialogEmpty1-Caw7F5KL.js";import"./index-B7DBPshJ.js";import"./classCallCheck-C6rD-0r0.js";const H={class:"flex justify-center items-center empty"},T=d({__name:"EmptyState",props:{description:{},image:{}},setup(e){return(t,s)=>(o(),i("div",H,[a(c(z),{description:"موردی یافت نشد",image:e.image,class:"h-[200px] w-[200px] opacity-70"},null,8,["image"])]))}}),G="/assets/favoritEmpty-CIK7qR49.svg",K=d({__name:"ScrollFetchSearch",props:{loading:{type:Boolean},flag:{type:Boolean},padding:{}},emits:["fetch"],setup(e,{emit:t}){const s=t,n=P(),r=u(null);return S(r,()=>{s("fetch")},{distance:50}),(l,m)=>(o(),i("main",{class:"flex flex-col flex-1 overflow-auto no-scrollbar w-[100vw] max-w-screen-md m-auto",style:b({paddingTop:e.padding||c(n).headerHeight+"px"}),ref_key:"scrollArea",ref:r},[k(l.$slots,"default"),a(h,{cls:"my-[10px]",spinning:e.loading,indicator:!0,tip:"درحال دریافت اطلاعات"},null,8,["spinning"]),e.flag?(o(),v(T,{key:0,image:c(G)},null,8,["image"])):y("",!0)],4))}});function M(){const e=B({totalPages:0,productList:[],flag:!1});return{productsData:e,getProducts:async(s,n=!1)=>{if(!n){s.value=!0;try{e.productList=await D.listProducts(),e.flag=e.productList.length<1}catch(r){console.log(r)}finally{s.value=!1}}}}}const R={class:"newest"},Z={key:0,class:"newest__grid"},J={key:1,class:"newest__empty"},g=20,O=d({__name:"NewestView",setup(e){const{productsData:t,getProducts:s}=M(),n=u(!1),r=u(!1),l=u(g),m=V(()=>t.productList.slice(0,l.value));E(async()=>{await s(n,!1)});const w=async()=>{if(l.value<t.productList.length){l.value+=g;return}await s(r,!0)};return(Q,f)=>{const x=$("container");return o(),i("div",R,[a(F,{title:"جدیدترین محصولات","back-to":"home"}),a(h,{spinning:n.value,tip:"درحال دریافت اطلاعات"},{default:p(()=>[a(K,{class:"newest__scroll",loading:r.value,flag:c(t).flag,padding:"0px",onFetch:w},{default:p(()=>[a(x,{class:"newest__body"},{default:p(()=>[a(j,{title:"تازهها",subtitle:"آخرین افزودههای مجموعه"}),c(t).productList.length?(o(),i("div",Z,[(o(!0),i(C,null,L(m.value,_=>(o(),v(q,{key:_.id,value:_},null,8,["value"]))),128))])):n.value?y("",!0):(o(),i("section",J,[a(I,{icon:"vuesax-linear:box",size:"26"}),f[0]||(f[0]=N("p",null,"هنوز محصولی در مجموعه ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["loading","flag"])]),_:1},8,["spinning"])])}}}),ue=A(O,[["__scopeId","data-v-ecd416be"]]);export{ue as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{d as a,c as n,l as o,q as i,s as c,f as _,b as e,I as r,_ as f}from"./index-CmYEpHK9.js";import{P as l}from"./PageBar-D80e377v.js";const p={class:"notif"},d={class:"notif__empty"},m=a({__name:"NotificationsView",setup(u){return(x,t)=>{const s=c("container");return _(),n("div",p,[o(l,{title:"اعلانها","back-to":"home"}),o(s,{class:"notif__body"},{default:i(()=>[e("section",d,[o(r,{icon:"vuesax-linear:notification",size:"26"}),t[0]||(t[0]=e("p",null,"اعلانی برای نمایش وجود ندارد.",-1))])]),_:1})])}}}),N=f(m,[["__scopeId","data-v-44d0c9a5"]]);export{N as default};
|
||||
import{d as a,c as n,l as o,q as i,s as c,f as _,b as e,I as r,_ as f}from"./index-gciDsUQi.js";import{P as l}from"./PageBar-uS5upavZ.js";const p={class:"notif"},d={class:"notif__empty"},m=a({__name:"NotificationsView",setup(u){return(x,t)=>{const s=c("container");return _(),n("div",p,[o(l,{title:"اعلانها","back-to":"home"}),o(s,{class:"notif__body"},{default:i(()=>[e("section",d,[o(r,{icon:"vuesax-linear:notification",size:"26"}),t[0]||(t[0]=e("p",null,"اعلانی برای نمایش وجود ندارد.",-1))])]),_:1})])}}}),N=f(m,[["__scopeId","data-v-44d0c9a5"]]);export{N as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{d as r,l as n,ac as p,ad as f,ae as h,af as w,ag as y,ah as g,a4 as x,ai as i,a3 as k,ab as N,E as S,f as V,c as v,u as P,n as b,q as _,b as l,I as B,z as I,C as z,t as C,e as O,g as E}from"./index-CmYEpHK9.js";const[T,U]=k("notify"),q=["lockScroll","position","show","teleport","zIndex"],D=w({},y,{type:i("danger"),color:String,message:x,position:i("top"),className:g,background:String,lockScroll:Boolean});var $=r({name:T,props:D,emits:["update:show"],setup(e,{emit:o,slots:t}){const a=s=>o("update:show",s);return()=>n(h,p({class:[U([e.type]),e.className],style:{color:e.color,background:e.background},overlay:!1,duration:.2,"onUpdate:show":a},f(e,q)),{default:()=>[t.default?t.default():e.message]})}});const j=N($),A={key:0,class:"flex"},F={class:"w-full text-white my-2"},G={class:"w-full flex content-end"},J=r({__name:"NotifyVant",props:{modelValue:{type:Boolean},timeOut:{},text:{},color:{}},emits:["update:modelValue"],setup(e,{emit:o}){const t=E(!0),a=e,s=o;S(()=>a.modelValue,()=>{a.timeOut!==-1&&u()});const u=()=>{setTimeout(()=>{s("update:modelValue",!1)},a.timeOut)};return(d,c)=>e.modelValue?(V(),v("div",A,[n(P(j),{show:t.value,"onUpdate:show":c[0]||(c[0]=m=>t.value=m),style:b(e.color)},{default:_(()=>[l("div",F,[l("div",G,[n(B,{icon:"vuesax-linear:info-circle",class:"ml-[20px] text-white",size:"25"}),l("div",null,[I(d.$slots,"default",{},()=>[z(C(e.text),1)])])])])]),_:3},8,["show","style"])])):O("",!0)}});export{J as _};
|
||||
import{d as r,l as n,af as p,ag as f,ah as h,ai as w,aj as y,ak as g,a4 as x,al as i,a3 as k,ab as N,E as S,f as V,c as v,u as P,n as b,q as _,b as l,I as B,z as I,C as z,t as C,e as O,g as E}from"./index-gciDsUQi.js";const[T,U]=k("notify"),j=["lockScroll","position","show","teleport","zIndex"],q=w({},y,{type:i("danger"),color:String,message:x,position:i("top"),className:g,background:String,lockScroll:Boolean});var D=r({name:T,props:q,emits:["update:show"],setup(e,{emit:o,slots:t}){const a=s=>o("update:show",s);return()=>n(h,p({class:[U([e.type]),e.className],style:{color:e.color,background:e.background},overlay:!1,duration:.2,"onUpdate:show":a},f(e,j)),{default:()=>[t.default?t.default():e.message]})}});const $=N(D),A={key:0,class:"flex"},F={class:"w-full text-white my-2"},G={class:"w-full flex content-end"},J=r({__name:"NotifyVant",props:{modelValue:{type:Boolean},timeOut:{},text:{},color:{}},emits:["update:modelValue"],setup(e,{emit:o}){const t=E(!0),a=e,s=o;S(()=>a.modelValue,()=>{a.timeOut!==-1&&u()});const u=()=>{setTimeout(()=>{s("update:modelValue",!1)},a.timeOut)};return(d,c)=>e.modelValue?(V(),v("div",A,[n(P($),{show:t.value,"onUpdate:show":c[0]||(c[0]=m=>t.value=m),style:b(e.color)},{default:_(()=>[l("div",F,[l("div",G,[n(B,{icon:"vuesax-linear:info-circle",class:"ml-[20px] text-white",size:"25"}),l("div",null,[I(d.$slots,"default",{},()=>[z(C(e.text),1)])])])])]),_:3},8,["show","style"])])):O("",!0)}});export{J as _};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{d as _,c as s,b as a,l as d,I as b,t as u,z as i,f as t,v as p,_ as k}from"./index-CmYEpHK9.js";const h={class:"bar"},f={class:"bar__inner"},m={key:1,class:"bar__spacer","aria-hidden":"true"},B={class:"bar__title"},g={class:"bar__trailing"},v=_({__name:"PageBar",props:{title:{},back:{type:Boolean,default:!0},backTo:{}},setup(e){const o=e,r=p();function l(){o.backTo?r.push({name:o.backTo}):r.back()}return(n,c)=>(t(),s("header",h,[a("div",f,[e.back?(t(),s("button",{key:0,type:"button",class:"bar__btn","aria-label":"بازگشت",onClick:l},[d(b,{icon:"vuesax-linear:arrow-right-1",size:"20"})])):(t(),s("span",m)),a("h1",B,u(e.title),1),a("div",g,[i(n.$slots,"trailing",{},()=>[c[0]||(c[0]=a("span",{class:"bar__spacer","aria-hidden":"true"},null,-1))],!0)])]),i(n.$slots,"below",{},void 0,!0)]))}}),I=k(v,[["__scopeId","data-v-d2d3dfeb"]]);export{I as P};
|
||||
import{d as _,c as s,b as a,l as d,I as b,t as u,z as i,f as t,v as p,_ as k}from"./index-gciDsUQi.js";const h={class:"bar"},f={class:"bar__inner"},m={key:1,class:"bar__spacer","aria-hidden":"true"},B={class:"bar__title"},g={class:"bar__trailing"},v=_({__name:"PageBar",props:{title:{},back:{type:Boolean,default:!0},backTo:{}},setup(e){const o=e,r=p();function l(){o.backTo?r.push({name:o.backTo}):r.back()}return(n,c)=>(t(),s("header",h,[a("div",f,[e.back?(t(),s("button",{key:0,type:"button",class:"bar__btn","aria-label":"بازگشت",onClick:l},[d(b,{icon:"vuesax-linear:arrow-right-1",size:"20"})])):(t(),s("span",m)),a("h1",B,u(e.title),1),a("div",g,[i(n.$slots,"trailing",{},()=>[c[0]||(c[0]=a("span",{class:"bar__spacer","aria-hidden":"true"},null,-1))],!0)])]),i(n.$slots,"below",{},void 0,!0)]))}}),I=k(v,[["__scopeId","data-v-d2d3dfeb"]]);export{I as P};
|
||||
@@ -1 +0,0 @@
|
||||
.pc[data-v-dd58e1ab]{cursor:pointer;border-radius:32px;background:#f4f5f6;padding:16px 14px 15px;text-align:center;transition:transform .2s ease,background .2s ease}.pc[data-v-dd58e1ab]:active{transform:scale(.985)}.pc__art[data-v-dd58e1ab]{position:relative;aspect-ratio:1 / 1;display:flex;align-items:center;justify-content:center}.pc__art img[data-v-dd58e1ab]{max-width:82%;max-height:100%;-o-object-fit:contain;object-fit:contain;-o-object-position:center;object-position:center;display:block}.pc__artEmpty[data-v-dd58e1ab]{width:100%;height:100%;display:grid;place-items:center;color:#8a909c}.pc__fav[data-v-dd58e1ab]{position:absolute;top:0;left:0;width:30px;height:30px;display:grid;place-items:center;border:0;cursor:pointer;border-radius:50%;color:#8a909c;background:#ffffffbf;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);transition:color .18s ease,transform .18s ease}.pc__fav.is-on[data-v-dd58e1ab]{color:#7a1b33;background:#fff}.pc__fav[data-v-dd58e1ab]:active{transform:scale(.9)}.pc__flag[data-v-dd58e1ab]{position:absolute;top:0;right:0;padding:4px 9px;border-radius:999px;font-size:10px;font-weight:700;color:#fff;background:#14161a}.pc__flag--soft[data-v-dd58e1ab]{background:#a33c55}.pc__title[data-v-dd58e1ab]{margin:12px 0 0;font-size:12.5px;font-weight:600;color:#14161a;line-height:1.6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pc__weight[data-v-dd58e1ab]{margin:5px 0 0;font-size:16px;font-weight:700;line-height:1.4;color:#22262e}.pc__weightUnit[data-v-dd58e1ab]{font-size:12px;font-weight:600;color:#5b616e}.pc__meta[data-v-dd58e1ab]{display:flex;align-items:center;justify-content:center;gap:8px;padding-top:5px;font-size:11.5px}.pc__wageOld[data-v-dd58e1ab]{color:#8a909c;text-decoration:line-through}.pc__wage[data-v-dd58e1ab]{color:#e31a1a;font-weight:700}
|
||||
@@ -0,0 +1 @@
|
||||
.pc[data-v-ed785ed2]{cursor:pointer;border-radius:32px;background:#f4f5f6;padding:16px 14px 15px;text-align:center;transition:transform .2s ease,background .2s ease}.pc[data-v-ed785ed2]:active{transform:scale(.985)}.pc__art[data-v-ed785ed2]{position:relative;aspect-ratio:1 / 1;display:flex;align-items:center;justify-content:center}.pc__art img[data-v-ed785ed2]{max-width:82%;max-height:100%;-o-object-fit:contain;object-fit:contain;-o-object-position:center;object-position:center;display:block}.pc__artEmpty[data-v-ed785ed2]{width:100%;height:100%;display:grid;place-items:center;color:#8a909c}.pc__fav[data-v-ed785ed2]{position:absolute;top:0;left:0;width:30px;height:30px;display:grid;place-items:center;border:0;cursor:pointer;border-radius:50%;color:#8a909c;background:#ffffffbf;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);transition:color .18s ease,transform .18s ease}.pc__fav.is-on[data-v-ed785ed2]{color:#7a1b33;background:#fff}.pc__fav[data-v-ed785ed2]:active{transform:scale(.9)}.pc__flag[data-v-ed785ed2]{position:absolute;top:0;right:0;padding:4px 9px;border-radius:999px;font-size:10px;font-weight:700;color:#fff;background:#14161a}.pc__flag--soft[data-v-ed785ed2]{background:#a33c55}.pc__title[data-v-ed785ed2]{margin:12px 0 0;font-size:12px;font-weight:500;color:#14161a;line-height:1.6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pc__weight[data-v-ed785ed2]{margin:5px 0 0;font-size:16px;font-weight:700;line-height:1.4;color:#22262e}.pc__weightUnit[data-v-ed785ed2]{font-size:12px;font-weight:600;color:#5b616e}.pc__meta[data-v-ed785ed2]{display:flex;align-items:center;justify-content:center;gap:8px;padding-top:5px;font-size:11.5px}.pc__wageOld[data-v-ed785ed2]{color:#8a909c;text-decoration:line-through}.pc__wage[data-v-ed785ed2]{color:#e31a1a;font-weight:500;font-size:12px}
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{d as F,k as D,f as t,c as a,F as P,b as o,u as e,w as S,l as p,I as h,X as z,i as N,e as c,t as _,C as V,q as I,j as q,g as E,_ as O}from"./index-CmYEpHK9.js";import{a as U,S as $}from"./SingleProduct-CDKWZbYq.js";import{u as j}from"./cartStore-DSCChC_v.js";import{D as L}from"./index-DSgZu76n.js";const M={class:"pc__art"},T=["alt"],X={key:1,class:"pc__artEmpty","aria-hidden":"true"},A=["aria-label"],G={key:2,class:"pc__flag"},H={key:3,class:"pc__flag pc__flag--soft"},J={class:"pc__title"},K={class:"pc__weight"},Q={key:0,class:"pc__meta"},R={key:0,class:"pc__wageOld"},W={class:"pc__wage"},Y=F({__name:"ProductCard",props:{value:{},wageBefore:{}},setup(d){const w=d,r=U(),{image:v,id:i,title:f,min_gram:y,wage:m,is_exist:b,qty:k,isPreOrder:x}=j(w.value),l=E(!1);function C(){l.value=!0}function g(n){return n%1===0?String(n):n.toFixed(2)}return(n,s)=>{const B=D("lazy");return t(),a(P,null,[o("article",{class:"pc",onClick:C},[o("div",M,[e(v)?S((t(),a("img",{key:0,alt:e(f)},null,8,T)),[[B,e(v)]]):(t(),a("div",X,[p(h,{icon:"vuesax-linear:diamonds",size:"26"})])),o("button",{type:"button",class:N(["pc__fav",{"is-on":e(r).isFavorite(e(i))}]),"aria-label":e(r).isFavorite(e(i))?"حذف از علاقهمندی":"افزودن به علاقهمندی",onClick:s[0]||(s[0]=z(u=>e(r).toggle(e(i)),["stop"]))},[p(h,{icon:e(r).isFavorite(e(i))?"vuesax-linear:heart-fill":"vuesax-linear:heart",size:"16"},null,8,["icon"])],10,A),e(b)?e(x)&&e(k)===0?(t(),a("span",H,"پیشسفارش")):c("",!0):(t(),a("span",G,"ناموجود"))]),o("h3",J,_(e(f)),1),o("p",K,[V(_(e(y))+" ",1),s[3]||(s[3]=o("span",{class:"pc__weightUnit"},"گرم",-1))]),e(m)!=null?(t(),a("div",Q,[d.wageBefore!=null?(t(),a("span",R,"اجرت "+_(g(d.wageBefore))+"٪",1)):c("",!0),o("span",W,_(g(e(m)))+"٪ اجرت",1)])):c("",!0)]),p(e(L),{visible:l.value,"onUpdate:visible":s[2]||(s[2]=u=>l.value=u),placement:"bottom",closable:!1,class:"rtl",height:"100vh",bodyStyle:{padding:0,position:"relative"}},{default:I(()=>[l.value?(t(),q($,{id:e(i),key:e(i),onCloseDrawer:s[1]||(s[1]=u=>l.value=!1)},null,8,["id"])):c("",!0)]),_:1},8,["visible"])],64)}}}),ae=O(Y,[["__scopeId","data-v-dd58e1ab"]]);export{ae as P};
|
||||
import{d as F,k as D,f as t,c as a,F as P,b as o,u as e,w as S,l as p,I as h,X as z,i as N,e as c,t as _,C as V,q as I,j as q,g as E,_ as O}from"./index-gciDsUQi.js";import{a as U,S as $}from"./SingleProduct-Bz_F3HVn.js";import{u as j}from"./cartStore-BqvRThaH.js";import{D as L}from"./index-B7DBPshJ.js";const M={class:"pc__art"},T=["alt"],X={key:1,class:"pc__artEmpty","aria-hidden":"true"},A=["aria-label"],G={key:2,class:"pc__flag"},H={key:3,class:"pc__flag pc__flag--soft"},J={class:"pc__title"},K={class:"pc__weight"},Q={key:0,class:"pc__meta"},R={key:0,class:"pc__wageOld"},W={class:"pc__wage"},Y=F({__name:"ProductCard",props:{value:{},wageBefore:{}},setup(d){const w=d,r=U(),{image:v,id:i,title:f,min_gram:y,wage:m,is_exist:k,qty:b,isPreOrder:x}=j(w.value),l=E(!1);function C(){l.value=!0}function g(n){return n%1===0?String(n):n.toFixed(2)}return(n,s)=>{const B=D("lazy");return t(),a(P,null,[o("article",{class:"pc",onClick:C},[o("div",M,[e(v)?S((t(),a("img",{key:0,alt:e(f)},null,8,T)),[[B,e(v)]]):(t(),a("div",X,[p(h,{icon:"vuesax-linear:diamonds",size:"26"})])),o("button",{type:"button",class:N(["pc__fav",{"is-on":e(r).isFavorite(e(i))}]),"aria-label":e(r).isFavorite(e(i))?"حذف از علاقهمندی":"افزودن به علاقهمندی",onClick:s[0]||(s[0]=z(u=>e(r).toggle(e(i)),["stop"]))},[p(h,{icon:e(r).isFavorite(e(i))?"vuesax-linear:heart-fill":"vuesax-linear:heart",size:"16"},null,8,["icon"])],10,A),e(k)?e(x)&&e(b)===0?(t(),a("span",H,"پیشسفارش")):c("",!0):(t(),a("span",G,"ناموجود"))]),o("h3",J,_(e(f)),1),o("p",K,[V(_(e(y))+" ",1),s[3]||(s[3]=o("span",{class:"pc__weightUnit"},"گرم",-1))]),e(m)!=null?(t(),a("div",Q,[d.wageBefore!=null?(t(),a("span",R,"اجرت "+_(g(d.wageBefore))+"٪",1)):c("",!0),o("span",W,_(g(e(m)))+"٪ اجرت",1)])):c("",!0)]),p(e(L),{visible:l.value,"onUpdate:visible":s[2]||(s[2]=u=>l.value=u),placement:"bottom",closable:!1,class:"rtl",height:"100vh",bodyStyle:{padding:0,position:"relative"}},{default:I(()=>[l.value?(t(),q($,{id:e(i),key:e(i),onCloseDrawer:s[1]||(s[1]=u=>l.value=!1)},null,8,["id"])):c("",!0)]),_:1},8,["visible"])],64)}}}),ae=O(Y,[["__scopeId","data-v-ed785ed2"]]);export{ae as P};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{d as I,D as S,o as E,c as a,l,q as y,g as p,s as V,f as i,b as e,I as f,t,e as _,i as b,h as k,_ as h}from"./index-CmYEpHK9.js";import{P as C}from"./PageBar-D80e377v.js";import{S as N}from"./SectionHead-L1TLZGJP.js";import{a as T}from"./client-WIBW0tF5.js";const g={class:"prof"},B={class:"prof__identity"},D={class:"prof__avatar","aria-hidden":"true"},P={class:"prof__name"},x={key:0,class:"prof__mobile"},R={key:0,class:"prof__block"},w={class:"prof__specs"},F={class:"prof__spec"},z={class:"prof__spec"},M={class:"prof__spec"},O={class:"prof__spec"},U={key:1,class:"prof__empty"},A=I({__name:"ProfileView",setup(L){const c={UNVERIFIED:"احراز نشده",STEP_ONE_SUBMITTED:"مرحله اول ثبت شده",STEP_TWO_SUBMITTED:"مرحله دوم ثبت شده",VERIFIED:"تایید شده"},u=S(),s=p(null),n=p(!1),v=k(()=>{var r;return((r=s.value)==null?void 0:r.verificationStep)==="VERIFIED"});return E(async()=>{if(u.customerId){n.value=!0;try{s.value=await T.getCustomer(u.customerId)}finally{n.value=!1}}}),(r,o)=>{const m=V("container");return i(),a("div",g,[l(C,{title:"اطلاعات کاربری","back-to":"userPage::hasSubRoute"}),l(m,{class:"prof__body"},{default:y(()=>{var d;return[e("section",B,[e("div",D,[l(f,{icon:"vuesax-linear:user",size:"30"})]),e("h2",P,t(((d=s.value)==null?void 0:d.fullName)??"—"),1),s.value?(i(),a("p",x,t(s.value.mobile),1)):_("",!0),s.value?(i(),a("span",{key:1,class:b(["prof__seal",v.value?"is-ok":"is-pending"])},t(c[s.value.verificationStep]??s.value.verificationStep),3)):_("",!0)]),s.value?(i(),a("section",R,[l(N,{title:"مشخصات",subtitle:"اطلاعات ثبتشده حساب شما"}),e("dl",w,[e("div",F,[o[0]||(o[0]=e("dt",null,"نام و نام خانوادگی",-1)),e("dd",null,t(s.value.fullName),1)]),e("div",z,[o[1]||(o[1]=e("dt",null,"تلفن همراه",-1)),e("dd",null,t(s.value.mobile),1)]),e("div",M,[o[2]||(o[2]=e("dt",null,"کد ملی",-1)),e("dd",null,t(s.value.nationalCode),1)]),e("div",O,[o[3]||(o[3]=e("dt",null,"وضعیت احراز هویت",-1)),e("dd",null,t(c[s.value.verificationStep]??s.value.verificationStep),1)])])])):n.value?_("",!0):(i(),a("section",U,[l(f,{icon:"vuesax-linear:user",size:"26"}),o[4]||(o[4]=e("p",null,"اطلاعات حساب در دسترس نیست.",-1))]))]}),_:1})])}}}),G=h(A,[["__scopeId","data-v-7c544fc5"]]);export{G as default};
|
||||
import{d as I,D as S,o as E,c as a,l,q as y,g as p,s as V,f as i,b as e,I as f,t,e as _,i as b,h as k,_ as h}from"./index-gciDsUQi.js";import{P as C}from"./PageBar-uS5upavZ.js";import{S as N}from"./SectionHead-BKOd3BbV.js";import{a as T}from"./client-WIBW0tF5.js";const g={class:"prof"},B={class:"prof__identity"},D={class:"prof__avatar","aria-hidden":"true"},P={class:"prof__name"},x={key:0,class:"prof__mobile"},R={key:0,class:"prof__block"},w={class:"prof__specs"},F={class:"prof__spec"},z={class:"prof__spec"},M={class:"prof__spec"},O={class:"prof__spec"},U={key:1,class:"prof__empty"},A=I({__name:"ProfileView",setup(L){const c={UNVERIFIED:"احراز نشده",STEP_ONE_SUBMITTED:"مرحله اول ثبت شده",STEP_TWO_SUBMITTED:"مرحله دوم ثبت شده",VERIFIED:"تایید شده"},u=S(),s=p(null),n=p(!1),v=k(()=>{var r;return((r=s.value)==null?void 0:r.verificationStep)==="VERIFIED"});return E(async()=>{if(u.customerId){n.value=!0;try{s.value=await T.getCustomer(u.customerId)}finally{n.value=!1}}}),(r,o)=>{const m=V("container");return i(),a("div",g,[l(C,{title:"اطلاعات کاربری","back-to":"userPage::hasSubRoute"}),l(m,{class:"prof__body"},{default:y(()=>{var d;return[e("section",B,[e("div",D,[l(f,{icon:"vuesax-linear:user",size:"30"})]),e("h2",P,t(((d=s.value)==null?void 0:d.fullName)??"—"),1),s.value?(i(),a("p",x,t(s.value.mobile),1)):_("",!0),s.value?(i(),a("span",{key:1,class:b(["prof__seal",v.value?"is-ok":"is-pending"])},t(c[s.value.verificationStep]??s.value.verificationStep),3)):_("",!0)]),s.value?(i(),a("section",R,[l(N,{title:"مشخصات",subtitle:"اطلاعات ثبتشده حساب شما"}),e("dl",w,[e("div",F,[o[0]||(o[0]=e("dt",null,"نام و نام خانوادگی",-1)),e("dd",null,t(s.value.fullName),1)]),e("div",z,[o[1]||(o[1]=e("dt",null,"تلفن همراه",-1)),e("dd",null,t(s.value.mobile),1)]),e("div",M,[o[2]||(o[2]=e("dt",null,"کد ملی",-1)),e("dd",null,t(s.value.nationalCode),1)]),e("div",O,[o[3]||(o[3]=e("dt",null,"وضعیت احراز هویت",-1)),e("dd",null,t(c[s.value.verificationStep]??s.value.verificationStep),1)])])])):n.value?_("",!0):(i(),a("section",U,[l(f,{icon:"vuesax-linear:user",size:"26"}),o[4]||(o[4]=e("p",null,"اطلاعات حساب در دسترس نیست.",-1))]))]}),_:1})])}}}),G=h(A,[["__scopeId","data-v-7c544fc5"]]);export{G as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{p as n,j as d}from"./filters-CLL9nGZ2.js";import{d as l,c as s,i as u,b as a,C as m,t as i,u as c,e as _,h as v,f as r,_ as q}from"./index-CmYEpHK9.js";const f={key:0,class:"rate-strip__value"},y={class:"rate-strip__num"},k={key:1,class:"rate-strip__value rate-strip__value--muted"},x={key:2,class:"rate-strip__time"},B=l({__name:"RateStrip",props:{quote:{},compact:{type:Boolean}},setup(t){const o=t,p=v(()=>o.quote?o.quote.pricePerGramRial.split(".")[0]:"");return(C,e)=>(r(),s("div",{class:u(["rate-strip",{"is-empty":!t.quote,"rate-strip--compact":t.compact}])},[e[1]||(e[1]=a("div",{class:"rate-strip__label"},[a("span",{class:"rate-strip__dot","aria-hidden":"true"}),m(" نرخ طلای ۱۸ عیار ")],-1)),t.quote?(r(),s("div",f,[a("span",y,i(c(n)(p.value)),1),e[0]||(e[0]=a("span",{class:"rate-strip__unit"},"ریال / گرم",-1))])):(r(),s("div",k,"در انتظار اعلام نرخ")),t.quote?(r(),s("div",x,i(c(d)(t.quote.quotedAt)),1)):_("",!0)],2))}}),h=q(B,[["__scopeId","data-v-0b16738e"]]);export{h as R};
|
||||
import{p as n,j as d}from"./filters-CLL9nGZ2.js";import{d as l,c as s,i as u,b as a,C as m,t as i,u as c,e as _,h as v,f as r,_ as q}from"./index-gciDsUQi.js";const f={key:0,class:"rate-strip__value"},y={class:"rate-strip__num"},k={key:1,class:"rate-strip__value rate-strip__value--muted"},x={key:2,class:"rate-strip__time"},B=l({__name:"RateStrip",props:{quote:{},compact:{type:Boolean}},setup(t){const o=t,p=v(()=>o.quote?o.quote.pricePerGramRial.split(".")[0]:"");return(C,e)=>(r(),s("div",{class:u(["rate-strip",{"is-empty":!t.quote,"rate-strip--compact":t.compact}])},[e[1]||(e[1]=a("div",{class:"rate-strip__label"},[a("span",{class:"rate-strip__dot","aria-hidden":"true"}),m(" نرخ طلای ۱۸ عیار ")],-1)),t.quote?(r(),s("div",f,[a("span",y,i(c(n)(p.value)),1),e[0]||(e[0]=a("span",{class:"rate-strip__unit"},"ریال / گرم",-1))])):(r(),s("div",k,"در انتظار اعلام نرخ")),t.quote?(r(),s("div",x,i(c(d)(t.quote.quotedAt)),1)):_("",!0)],2))}}),h=q(B,[["__scopeId","data-v-0b16738e"]]);export{h as R};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{d as v,a0 as h,E as m,f as t,c as l,l as n,I as r,w as f,a1 as b,b as x,a2 as k,e as I,A as w,g as y,_ as C}from"./index-CmYEpHK9.js";const S={class:"si"},V=["placeholder"],B=v({__name:"SearchInput",props:{placeHolder:{}},emits:["search"],setup(i,{emit:d}){const c=d,a=w({clear:!1}),e=y(void 0),s=()=>{c("search",e.value)},u=()=>{e.value=void 0,a.clear=!1,c("search",void 0)},p=h(e,700);return m(p,()=>{e?a.clear=!0:a.clear=!1,s()}),(N,o)=>(t(),l("div",S,[n(r,{icon:"vuesax-linear:search-normal-1",class:"si__icon",size:"18",onClick:s}),f(x("input",{"onUpdate:modelValue":o[0]||(o[0]=_=>e.value=_),class:"si__input",placeholder:i.placeHolder,onKeyup:k(s,["enter"])},null,40,V),[[b,e.value]]),a.clear?(t(),l("button",{key:0,type:"button",class:"si__clear","aria-label":"پاک کردن",onClick:u},[n(r,{icon:"vuesax-linear:add",size:"16"})])):I("",!0)]))}}),D=C(B,[["__scopeId","data-v-8ebd3183"]]);export{D as S};
|
||||
import{d as v,a0 as h,E as m,f as t,c as l,l as n,I as r,w as f,a1 as b,b as x,a2 as k,e as I,A as w,g as y,_ as C}from"./index-gciDsUQi.js";const S={class:"si"},V=["placeholder"],B=v({__name:"SearchInput",props:{placeHolder:{}},emits:["search"],setup(i,{emit:d}){const c=d,a=w({clear:!1}),e=y(void 0),s=()=>{c("search",e.value)},u=()=>{e.value=void 0,a.clear=!1,c("search",void 0)},p=h(e,700);return m(p,()=>{e?a.clear=!0:a.clear=!1,s()}),(N,o)=>(t(),l("div",S,[n(r,{icon:"vuesax-linear:search-normal-1",class:"si__icon",size:"18",onClick:s}),f(x("input",{"onUpdate:modelValue":o[0]||(o[0]=_=>e.value=_),class:"si__input",placeholder:i.placeHolder,onKeyup:k(s,["enter"])},null,40,V),[[b,e.value]]),a.clear?(t(),l("button",{key:0,type:"button",class:"si__clear","aria-label":"پاک کردن",onClick:u},[n(r,{icon:"vuesax-linear:add",size:"16"})])):I("",!0)]))}}),D=C(B,[["__scopeId","data-v-8ebd3183"]]);export{D as S};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
.dd[data-v-9e57de56]{padding:15px;border:1px solid #ECEDEF;border-radius:16px;background:#fff}.dd.is-open[data-v-9e57de56]{border-color:#a33c55}.dd__head[data-v-9e57de56]{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;border:0;padding:0;cursor:pointer;background:none;font-family:inherit;text-align:start}.dd__title[data-v-9e57de56]{margin:0;font-size:13px;font-weight:700;color:#14161a}.dd__chevron[data-v-9e57de56]{flex:0 0 auto;color:#8a909c;transition:transform .2s ease}.dd.is-open .dd__chevron[data-v-9e57de56]{transform:rotate(180deg);color:#7a1b33}.dd__body[data-v-9e57de56]{overflow:hidden;padding-top:15px}.drop-enter-active{animation:drop .2s cubic-bezier(.33,1,.68,1)}.drop-leave-to{animation:drop .2s cubic-bezier(.33,1,.68,1) reverse}@keyframes drop{0%{max-height:0}to{max-height:240px}}.filt[data-v-9651e9da]{background:#fff;min-height:100vh}.filt__body[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:120px 16px 110px;display:flex;flex-direction:column;gap:12px}.filt__chips[data-v-9651e9da]{display:flex;flex-wrap:wrap;gap:8px}.filt__chip[data-v-9651e9da]{padding:8px 14px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.filt__chip.is-on[data-v-9651e9da]{color:#fff;background:#14161a;border-color:#14161a}.filt__chip[data-v-9651e9da]:active{transform:scale(.97)}.filt__empty[data-v-9651e9da]{margin:0;font-size:12px;color:#8a909c}.filt__gram[data-v-9651e9da]{padding:4px 6px 0}.filt__gram[data-v-9651e9da] .ant-slider-track{background-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-handle{border-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-rail{background-color:#ecedef}.filt__gramFigures[data-v-9651e9da]{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:18px}.filt__gramFigure[data-v-9651e9da]{font-size:12px;font-weight:700;color:#14161a}.filt__gramFigure i[data-v-9651e9da]{font-style:normal;font-size:11px;font-weight:600;color:#8a909c;padding-inline-end:4px}.filt__bar[data-v-9651e9da]{position:fixed;bottom:0;left:0;right:0;z-index:5;background:#ffffffeb;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-top:1px solid #ECEDEF;padding-bottom:16px}.filt__barInner[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:12px 16px;display:flex;align-items:center;gap:10px}.filt__clear[data-v-9651e9da],.filt__apply[data-v-9651e9da]{flex:1;padding:13px 18px;border:0;cursor:pointer;border-radius:14px;font-family:inherit;font-size:13px;font-weight:700;transition:transform .15s ease}.filt__clear[data-v-9651e9da]{color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF}.filt__apply[data-v-9651e9da]{color:#fff;background:#14161a}.filt__clear[data-v-9651e9da]:active,.filt__apply[data-v-9651e9da]:active{transform:scale(.98)}.search[data-v-492690a8]{background:#fff;min-height:100vh}.search__barExtra[data-v-492690a8]{max-width:768px;margin:0 auto;padding:0 16px}.search__chips[data-v-492690a8]{display:flex;gap:8px;overflow-x:auto;margin:12px 0 10px -16px;scroll-snap-type:x proximity}.search__chips[data-v-492690a8]:before,.search__chips[data-v-492690a8]:after{content:"";flex:0 0 16px}.search__chip[data-v-492690a8]{scroll-snap-align:start;flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;height:40px;padding:0 18px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:600;white-space:nowrap;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.search__chip.is-on[data-v-492690a8]{color:#fff;background:#14161a;border-color:#14161a}.search__chip--filter.is-on[data-v-492690a8]{background:#7a1b33;border-color:#7a1b33}.search__chip[data-v-492690a8]:active{transform:scale(.97)}.search__body[data-v-492690a8]{padding-top:176px;padding-bottom:90px}.search__body[data-v-492690a8]>*:first-child{margin-top:16px}.search__collections[data-v-492690a8]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-bottom:22px}.search__collection[data-v-492690a8]{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:13px 10px;border-radius:14px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:700;color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF;transition:all .2s ease}.search__collection[data-v-492690a8]:active{transform:scale(.98)}.search__grid[data-v-492690a8]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.search__more[data-v-492690a8]{display:flex;justify-content:center;padding:18px 0 4px}.search__empty[data-v-492690a8]{margin-top:8px;padding:34px 20px;border:1px dashed #ECEDEF;border-radius:18px;display:flex;flex-direction:column;align-items:center;gap:10px;color:#8a909c}.search__empty p[data-v-492690a8]{margin:0;font-size:12.5px}
|
||||
.dd[data-v-9e57de56]{padding:15px;border:1px solid #ECEDEF;border-radius:16px;background:#fff}.dd.is-open[data-v-9e57de56]{border-color:#a33c55}.dd__head[data-v-9e57de56]{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;border:0;padding:0;cursor:pointer;background:none;font-family:inherit;text-align:start}.dd__title[data-v-9e57de56]{margin:0;font-size:13px;font-weight:700;color:#14161a}.dd__chevron[data-v-9e57de56]{flex:0 0 auto;color:#8a909c;transition:transform .2s ease}.dd.is-open .dd__chevron[data-v-9e57de56]{transform:rotate(180deg);color:#7a1b33}.dd__body[data-v-9e57de56]{overflow:hidden;padding-top:15px}.drop-enter-active{animation:drop .2s cubic-bezier(.33,1,.68,1)}.drop-leave-to{animation:drop .2s cubic-bezier(.33,1,.68,1) reverse}@keyframes drop{0%{max-height:0}to{max-height:240px}}.filt[data-v-9651e9da]{background:#fff;min-height:100vh}.filt__body[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:120px 16px 110px;display:flex;flex-direction:column;gap:12px}.filt__chips[data-v-9651e9da]{display:flex;flex-wrap:wrap;gap:8px}.filt__chip[data-v-9651e9da]{padding:8px 14px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12px;font-weight:600;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.filt__chip.is-on[data-v-9651e9da]{color:#fff;background:#14161a;border-color:#14161a}.filt__chip[data-v-9651e9da]:active{transform:scale(.97)}.filt__empty[data-v-9651e9da]{margin:0;font-size:12px;color:#8a909c}.filt__gram[data-v-9651e9da]{padding:4px 6px 0}.filt__gram[data-v-9651e9da] .ant-slider-track{background-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-handle{border-color:#7a1b33}.filt__gram[data-v-9651e9da] .ant-slider-rail{background-color:#ecedef}.filt__gramFigures[data-v-9651e9da]{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:18px}.filt__gramFigure[data-v-9651e9da]{font-size:12px;font-weight:700;color:#14161a}.filt__gramFigure i[data-v-9651e9da]{font-style:normal;font-size:11px;font-weight:600;color:#8a909c;padding-inline-end:4px}.filt__bar[data-v-9651e9da]{position:fixed;bottom:0;left:0;right:0;z-index:5;background:#ffffffeb;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-top:1px solid #ECEDEF;padding-bottom:16px}.filt__barInner[data-v-9651e9da]{max-width:768px;margin:0 auto;padding:12px 16px;display:flex;align-items:center;gap:10px}.filt__clear[data-v-9651e9da],.filt__apply[data-v-9651e9da]{flex:1;padding:13px 18px;border:0;cursor:pointer;border-radius:14px;font-family:inherit;font-size:13px;font-weight:700;transition:transform .15s ease}.filt__clear[data-v-9651e9da]{color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF}.filt__apply[data-v-9651e9da]{color:#fff;background:#14161a}.filt__clear[data-v-9651e9da]:active,.filt__apply[data-v-9651e9da]:active{transform:scale(.98)}.search[data-v-df0a35c2]{background:#fff;min-height:100vh}.search__barExtra[data-v-df0a35c2]{max-width:768px;margin:0 auto;padding:0 16px}.search__chips[data-v-df0a35c2]{display:flex;gap:8px;overflow-x:auto;margin:12px 0 10px -16px;scroll-snap-type:x proximity}.search__chips[data-v-df0a35c2]:before,.search__chips[data-v-df0a35c2]:after{content:"";flex:0 0 16px}.search__chip[data-v-df0a35c2]{scroll-snap-align:start;flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;height:40px;padding:0 18px;border-radius:999px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:600;white-space:nowrap;color:#22262e;background:#fff;border:1px solid #ECEDEF;transition:all .2s ease}.search__chip.is-on[data-v-df0a35c2]{color:#fff;background:#14161a;border-color:#14161a}.search__chip--filter.is-on[data-v-df0a35c2]{background:#7a1b33;border-color:#7a1b33}.search__chip[data-v-df0a35c2]:active{transform:scale(.97)}.search__body[data-v-df0a35c2]{padding-top:176px;padding-bottom:90px}.search__body[data-v-df0a35c2]>*:first-child{margin-top:16px}.search__collections[data-v-df0a35c2]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px;margin-bottom:22px}.search__collection[data-v-df0a35c2]{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:13px 10px;border-radius:14px;cursor:pointer;font-family:inherit;font-size:12.5px;font-weight:700;color:#22262e;background:#f4f5f6;border:1px solid #ECEDEF;transition:all .2s ease}.search__collection[data-v-df0a35c2]:active{transform:scale(.98)}.search__grid[data-v-df0a35c2]{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.search__more[data-v-df0a35c2]{display:flex;justify-content:center;padding:18px 0 4px}.search__empty[data-v-df0a35c2]{margin-top:8px;padding:34px 20px;border:1px dashed #ECEDEF;border-radius:18px;display:flex;flex-direction:column;align-items:center;gap:10px;color:#8a909c}.search__empty p[data-v-df0a35c2]{margin:0;font-size:12.5px}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{d as r,f as t,c as s,b as o,t as a,e as n,C as _,l as d,I as u,_ as b}from"./index-CmYEpHK9.js";const m={class:"sec"},f={class:"sec__text"},x={class:"sec__title"},h={key:0,class:"sec__sub"},k=r({__name:"SectionHead",props:{title:{},subtitle:{},actionLabel:{}},emits:["action"],setup(e,{emit:i}){const l=i;return(p,c)=>(t(),s("header",m,[o("div",f,[o("h2",x,a(e.title),1),e.subtitle?(t(),s("p",h,a(e.subtitle),1)):n("",!0)]),e.actionLabel?(t(),s("button",{key:0,type:"button",class:"sec__action",onClick:c[0]||(c[0]=v=>l("action"))},[_(a(e.actionLabel)+" ",1),d(u,{icon:"vuesax-linear:arrow-left-2",size:"15"})])):n("",!0)]))}}),C=b(k,[["__scopeId","data-v-e5c65b7c"]]);export{C as S};
|
||||
import{d as r,f as t,c as s,b as o,t as a,e as n,C as _,l as d,I as u,_ as b}from"./index-gciDsUQi.js";const m={class:"sec"},f={class:"sec__text"},x={class:"sec__title"},h={key:0,class:"sec__sub"},k=r({__name:"SectionHead",props:{title:{},subtitle:{},actionLabel:{}},emits:["action"],setup(e,{emit:i}){const l=i;return(p,c)=>(t(),s("header",m,[o("div",f,[o("h2",x,a(e.title),1),e.subtitle?(t(),s("p",h,a(e.subtitle),1)):n("",!0)]),e.actionLabel?(t(),s("button",{key:0,type:"button",class:"sec__action",onClick:c[0]||(c[0]=v=>l("action"))},[_(a(e.actionLabel)+" ",1),d(u,{icon:"vuesax-linear:arrow-left-2",size:"15"})])):n("",!0)]))}}),C=b(k,[["__scopeId","data-v-e5c65b7c"]]);export{C as S};
|
||||
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
+6
-6
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
import{d as k,D as A,o as C,c as i,l as r,q as f,j as D,u as m,e as E,g as u,f as l,F as R,b as s,r as w,I as T,t as o,i as p,s as N,_ as L}from"./index-CmYEpHK9.js";import{P}from"./PageBar-D80e377v.js";import{a as M}from"./Spinner.vue_vue_type_style_index_0_lang-CvgYqzhC.js";import{S as O}from"./SectionHead-L1TLZGJP.js";import{j as g,p as B}from"./filters-CLL9nGZ2.js";import{a as I}from"./client-WIBW0tF5.js";import{D as U}from"./index-DSgZu76n.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./classCallCheck-Ddn4Ym7v.js";const V={class:"tx"},$={class:"tx__list"},Y=["onClick"],j={class:"tx__main"},z={class:"tx__head"},F={class:"tx__kind"},G={key:0,class:"tx__note"},H={class:"tx__foot"},q={class:"tx__date"},J={key:1,class:"tx__empty"},K={class:"sheet"},Q={class:"sheet__specs"},W={class:"sheet__spec"},X={class:"sheet__spec"},Z={class:"sheet__spec"},ss={class:"sheet__spec"},es={class:"sheet__spec"},ts=k({__name:"TransactionsView",setup(os){const x={ORDER_STOCK:"سفارش",ORDER_PRE_ORDER:"سفارش ساخت",REPAYMENT_MELTED_GOLD:"طلای آبشده",REPAYMENT_TRANSFER:"حواله",REPAYMENT_CHEQUE:"چک",REPAYMENT_CASH:"پولی",WALLET_BONUS:"پاداش",ADJUSTMENT:"اصلاحیه"},h=A(),_=u(!1),d=u([]),v=u(!1),n=u(null),c=a=>a.direction==="CREDIT",y=a=>a.currency==="GOLD_GRAM"?`${a.amount} گرم`:`${B(a.amount)} ریال`,S=a=>{n.value=a,v.value=!0};return C(async()=>{if(h.customerId){_.value=!0;try{d.value=await I.getLedgerEntries(h.customerId)}finally{_.value=!1}}}),(a,e)=>{const b=N("container");return l(),i("div",V,[r(P,{title:"اسناد","back-to":"userPage::hasSubRoute"}),r(M,{spinning:_.value,tip:"درحال دریافت اطلاعات"},{default:f(()=>[r(b,{class:"tx__body"},{default:f(()=>[d.value.length?(l(),i(R,{key:0},[r(O,{title:"گردش حساب",subtitle:`${d.value.length} سند`},null,8,["subtitle"]),s("div",$,[(l(!0),i(R,null,w(d.value,t=>(l(),i("article",{key:t.id,class:"tx__row",onClick:ns=>S(t)},[s("span",{class:p(["tx__mark",c(t)?"is-in":"is-out"]),"aria-hidden":"true"},[r(T,{icon:c(t)?"vuesax-linear:arrow-down":"vuesax-linear:arrow-up",size:"16"},null,8,["icon"])],2),s("div",j,[s("div",z,[s("h3",F,o(x[t.sourceType]??t.sourceType),1),s("span",{class:p(["tx__amount",c(t)?"is-in":"is-out"])},o(y(t)),3)]),t.note?(l(),i("p",G,o(t.note),1)):E("",!0),s("div",H,[s("span",q,o(m(g)(t.createdAt)),1),s("span",{class:p(["tx__state",{"is-pending":!t.confirmed}])},o(t.confirmed?"تایید شده":"در انتظار تایید"),3)])])],8,Y))),128))])],64)):_.value?E("",!0):(l(),i("section",J,[r(T,{icon:"vuesax-linear:receipt-text",size:"26"}),e[1]||(e[1]=s("p",null,"سندی برای حساب شما ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"]),n.value?(l(),D(m(U),{key:0,visible:v.value,"onUpdate:visible":e[0]||(e[0]=t=>v.value=t),placement:"bottom",closable:!1,height:"420px",class:"rtl",bodyStyle:{padding:0}},{default:f(()=>[s("div",K,[e[7]||(e[7]=s("h3",{class:"sheet__title"},"جزئیات سند",-1)),s("dl",Q,[s("div",W,[e[2]||(e[2]=s("dt",null,"نوع سند",-1)),s("dd",null,o(x[n.value.sourceType]??n.value.sourceType),1)]),s("div",X,[e[3]||(e[3]=s("dt",null,"مبلغ",-1)),s("dd",{class:p(c(n.value)?"is-in":"is-out")},o(y(n.value)),3)]),s("div",Z,[e[4]||(e[4]=s("dt",null,"وضعیت",-1)),s("dd",null,o(n.value.confirmed?"تایید شده":"در انتظار تایید"),1)]),s("div",ss,[e[5]||(e[5]=s("dt",null,"تاریخ",-1)),s("dd",null,o(m(g)(n.value.createdAt)),1)]),s("div",es,[e[6]||(e[6]=s("dt",null,"توضیحات",-1)),s("dd",null,o(n.value.note||"—"),1)])])])]),_:1},8,["visible"])):E("",!0)])}}}),vs=L(ts,[["__scopeId","data-v-83b037a9"]]);export{vs as default};
|
||||
import{d as k,D as A,o as C,c as i,l as r,q as f,j as D,u as m,e as E,g as u,f as l,F as R,b as s,r as w,I as T,t as o,i as p,s as N,_ as L}from"./index-gciDsUQi.js";import{P}from"./PageBar-uS5upavZ.js";import{a as M}from"./Spinner.vue_vue_type_style_index_0_lang-CkjhJnbV.js";import{S as O}from"./SectionHead-BKOd3BbV.js";import{j as g,p as B}from"./filters-CLL9nGZ2.js";import{a as I}from"./client-WIBW0tF5.js";import{D as U}from"./index-B7DBPshJ.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./classCallCheck-C6rD-0r0.js";const V={class:"tx"},$={class:"tx__list"},Y=["onClick"],j={class:"tx__main"},z={class:"tx__head"},F={class:"tx__kind"},G={key:0,class:"tx__note"},H={class:"tx__foot"},q={class:"tx__date"},J={key:1,class:"tx__empty"},K={class:"sheet"},Q={class:"sheet__specs"},W={class:"sheet__spec"},X={class:"sheet__spec"},Z={class:"sheet__spec"},ss={class:"sheet__spec"},es={class:"sheet__spec"},ts=k({__name:"TransactionsView",setup(os){const x={ORDER_STOCK:"سفارش",ORDER_PRE_ORDER:"سفارش ساخت",REPAYMENT_MELTED_GOLD:"طلای آبشده",REPAYMENT_TRANSFER:"حواله",REPAYMENT_CHEQUE:"چک",REPAYMENT_CASH:"پولی",WALLET_BONUS:"پاداش",ADJUSTMENT:"اصلاحیه"},h=A(),_=u(!1),d=u([]),v=u(!1),n=u(null),c=a=>a.direction==="CREDIT",y=a=>a.currency==="GOLD_GRAM"?`${a.amount} گرم`:`${B(a.amount)} ریال`,S=a=>{n.value=a,v.value=!0};return C(async()=>{if(h.customerId){_.value=!0;try{d.value=await I.getLedgerEntries(h.customerId)}finally{_.value=!1}}}),(a,e)=>{const b=N("container");return l(),i("div",V,[r(P,{title:"اسناد","back-to":"userPage::hasSubRoute"}),r(M,{spinning:_.value,tip:"درحال دریافت اطلاعات"},{default:f(()=>[r(b,{class:"tx__body"},{default:f(()=>[d.value.length?(l(),i(R,{key:0},[r(O,{title:"گردش حساب",subtitle:`${d.value.length} سند`},null,8,["subtitle"]),s("div",$,[(l(!0),i(R,null,w(d.value,t=>(l(),i("article",{key:t.id,class:"tx__row",onClick:ns=>S(t)},[s("span",{class:p(["tx__mark",c(t)?"is-in":"is-out"]),"aria-hidden":"true"},[r(T,{icon:c(t)?"vuesax-linear:arrow-down":"vuesax-linear:arrow-up",size:"16"},null,8,["icon"])],2),s("div",j,[s("div",z,[s("h3",F,o(x[t.sourceType]??t.sourceType),1),s("span",{class:p(["tx__amount",c(t)?"is-in":"is-out"])},o(y(t)),3)]),t.note?(l(),i("p",G,o(t.note),1)):E("",!0),s("div",H,[s("span",q,o(m(g)(t.createdAt)),1),s("span",{class:p(["tx__state",{"is-pending":!t.confirmed}])},o(t.confirmed?"تایید شده":"در انتظار تایید"),3)])])],8,Y))),128))])],64)):_.value?E("",!0):(l(),i("section",J,[r(T,{icon:"vuesax-linear:receipt-text",size:"26"}),e[1]||(e[1]=s("p",null,"سندی برای حساب شما ثبت نشده است.",-1))]))]),_:1})]),_:1},8,["spinning"]),n.value?(l(),D(m(U),{key:0,visible:v.value,"onUpdate:visible":e[0]||(e[0]=t=>v.value=t),placement:"bottom",closable:!1,height:"420px",class:"rtl",bodyStyle:{padding:0}},{default:f(()=>[s("div",K,[e[7]||(e[7]=s("h3",{class:"sheet__title"},"جزئیات سند",-1)),s("dl",Q,[s("div",W,[e[2]||(e[2]=s("dt",null,"نوع سند",-1)),s("dd",null,o(x[n.value.sourceType]??n.value.sourceType),1)]),s("div",X,[e[3]||(e[3]=s("dt",null,"مبلغ",-1)),s("dd",{class:p(c(n.value)?"is-in":"is-out")},o(y(n.value)),3)]),s("div",Z,[e[4]||(e[4]=s("dt",null,"وضعیت",-1)),s("dd",null,o(n.value.confirmed?"تایید شده":"در انتظار تایید"),1)]),s("div",ss,[e[5]||(e[5]=s("dt",null,"تاریخ",-1)),s("dd",null,o(m(g)(n.value.createdAt)),1)]),s("div",es,[e[6]||(e[6]=s("dt",null,"توضیحات",-1)),s("dd",null,o(n.value.note||"—"),1)])])])]),_:1},8,["visible"])):E("",!0)])}}}),vs=L(ts,[["__scopeId","data-v-83b037a9"]]);export{vs as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{g as d,u as F,h as i,m as S}from"./index-CmYEpHK9.js";import{a as P}from"./client-WIBW0tF5.js";function W(t){return!t||t.length===0?null:t.reduce((e,s)=>parseFloat(s.defaultWagePercent)<parseFloat(e.defaultWagePercent)?s:e)}function I(t,e){const s=d(t),r=i(()=>{var n,m;return(m=(n=s.value.images)==null?void 0:n[0])==null?void 0:m.url}),o=i(()=>s.value.id),u=i(()=>s.value.title),l=i(()=>s.value.variants),a=d(e??W(F(l))),v=i(()=>a.value?parseFloat(a.value.rashWeightGrams):0),g=i(()=>a.value?parseFloat(a.value.defaultWagePercent):null),x=d(null),h=i(()=>{var n;return((n=a.value)==null?void 0:n.qty)??0}),f=i(()=>{var n;return((n=a.value)==null?void 0:n.isPreOrder)??!1}),y=i(()=>h.value>0||f.value),_=i(()=>s.value.productCode??null),C=d(!1);return{product:s,image:r,id:o,title:u,productCode:_,variants:l,selectedVariant:a,min_gram:v,wage:g,hasDiscountWage:x,qty:h,isPreOrder:f,is_exist:y,has_warranty:C}}const p="appCart";function q(){try{const t=localStorage.getItem(p);return t?JSON.parse(t):[]}catch{return[]}}function c(t){localStorage.setItem(p,JSON.stringify(t))}const G=S("cart",{state:()=>({items:q()}),actions:{async init(){try{const t=await P.listProducts(),e=[];for(const s of this.items){const r=t.find(u=>u.id===s.pid),o=r==null?void 0:r.variants.find(u=>u.id===s.vid);r&&o&&e.push({...s,product:r})}this.items=e,c(this.items)}catch(t){console.log(t)}},addToCart(t){const e=this.find_index(t);e===-1?this.items.push(t):(this.items[e].product=t.product,this.items[e].qty=t.qty),c(this.items)},remove(t){const e=this.find_index(t);e>-1&&this.items.splice(e,1),c(this.items)},updateFeild(t,e,s,r){if(!this.isInCart(s))return!1;const o=e??this.find_index(s);return this.items[o][r]=t,c(this.items),!0},find_index(t){return this.items.findIndex(e=>e.pid===t.pid&&e.vid===t.vid)},isInCart(t){return this.find_index(t)>-1},variant(t){return t.product.variants.find(e=>e.id===t.vid)},total(){return this.items.reduce((t,e)=>{const s=this.variant(e);return t+(s?parseFloat(s.rashWeightGrams)*e.qty:0)},0).toFixed(2)},clear(){this.items=[],c(this.items)}}});export{G as a,I as u};
|
||||
import{g as d,u as F,h as i,m as S}from"./index-gciDsUQi.js";import{a as P}from"./client-WIBW0tF5.js";function W(t){return!t||t.length===0?null:t.reduce((e,s)=>parseFloat(s.defaultWagePercent)<parseFloat(e.defaultWagePercent)?s:e)}function I(t,e){const s=d(t),r=i(()=>{var n,m;return(m=(n=s.value.images)==null?void 0:n[0])==null?void 0:m.url}),o=i(()=>s.value.id),u=i(()=>s.value.title),l=i(()=>s.value.variants),a=d(e??W(F(l))),v=i(()=>a.value?parseFloat(a.value.rashWeightGrams):0),g=i(()=>a.value?parseFloat(a.value.defaultWagePercent):null),x=d(null),h=i(()=>{var n;return((n=a.value)==null?void 0:n.qty)??0}),f=i(()=>{var n;return((n=a.value)==null?void 0:n.isPreOrder)??!1}),y=i(()=>h.value>0||f.value),_=i(()=>s.value.productCode??null),C=d(!1);return{product:s,image:r,id:o,title:u,productCode:_,variants:l,selectedVariant:a,min_gram:v,wage:g,hasDiscountWage:x,qty:h,isPreOrder:f,is_exist:y,has_warranty:C}}const p="appCart";function q(){try{const t=localStorage.getItem(p);return t?JSON.parse(t):[]}catch{return[]}}function c(t){localStorage.setItem(p,JSON.stringify(t))}const G=S("cart",{state:()=>({items:q()}),actions:{async init(){try{const t=await P.listProducts(),e=[];for(const s of this.items){const r=t.find(u=>u.id===s.pid),o=r==null?void 0:r.variants.find(u=>u.id===s.vid);r&&o&&e.push({...s,product:r})}this.items=e,c(this.items)}catch(t){console.log(t)}},addToCart(t){const e=this.find_index(t);e===-1?this.items.push(t):(this.items[e].product=t.product,this.items[e].qty=t.qty),c(this.items)},remove(t){const e=this.find_index(t);e>-1&&this.items.splice(e,1),c(this.items)},updateFeild(t,e,s,r){if(!this.isInCart(s))return!1;const o=e??this.find_index(s);return this.items[o][r]=t,c(this.items),!0},find_index(t){return this.items.findIndex(e=>e.pid===t.pid&&e.vid===t.vid)},isInCart(t){return this.find_index(t)>-1},variant(t){return t.product.variants.find(e=>e.id===t.vid)},total(){return this.items.reduce((t,e)=>{const s=this.variant(e);return t+(s?parseFloat(s.rashWeightGrams)*e.qty:0)},0).toFixed(2)},clear(){this.items=[],c(this.items)}}});export{G as a,I as u};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{c as l}from"./Spinner.vue_vue_type_style_index_0_lang-CvgYqzhC.js";var f=function(n){return setTimeout(n,16)},c=function(n){return clearTimeout(n)};typeof window<"u"&&"requestAnimationFrame"in window&&(f=function(n){return window.requestAnimationFrame(n)},c=function(n){return window.cancelAnimationFrame(n)});var i=0,o=new Map;function u(e){o.delete(e)}function w(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:1;i+=1;var r=i;function a(t){if(t===0)u(r),e();else{var s=f(function(){a(t-1)});o.set(r,s)}}return a(n),r}w.cancel=function(e){var n=o.get(e);return u(n),c(n)};function m(e,n){for(var r=l({},e),a=0;a<n.length;a+=1){var t=n[a];delete r[t]}return r}function p(e,n,r){return Object.defineProperty(e,"prototype",{writable:!1}),e}function v(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}export{p as _,v as a,m as o,w};
|
||||
import{c as l}from"./Spinner.vue_vue_type_style_index_0_lang-CkjhJnbV.js";var f=function(n){return setTimeout(n,16)},c=function(n){return clearTimeout(n)};typeof window<"u"&&"requestAnimationFrame"in window&&(f=function(n){return window.requestAnimationFrame(n)},c=function(n){return window.cancelAnimationFrame(n)});var i=0,o=new Map;function u(e){o.delete(e)}function w(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:1;i+=1;var r=i;function a(t){if(t===0)u(r),e();else{var s=f(function(){a(t-1)});o.set(r,s)}}return a(n),r}w.cancel=function(e){var n=o.get(e);return u(n),c(n)};function m(e,n){for(var r=l({},e),a=0;a<n.length;a+=1){var t=n[a];delete r[t]}return r}function p(e,n,r){return Object.defineProperty(e,"prototype",{writable:!1}),e}function v(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}export{p as _,v as a,m as o,w};
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{a3 as y,d as A,a4 as L,a5 as $,E as p,a6 as w,l as c,g as D,A as N,L as B,a7 as I,p as M,a8 as f,a9 as R,aa as U,ab as Y}from"./index-CmYEpHK9.js";const[C,r,F]=y("pull-refresh"),x=50,G=["pulling","loosing","success"],X={disabled:Boolean,modelValue:Boolean,headHeight:f(x),successText:String,pullingText:String,loosingText:String,loadingText:String,pullDistance:L,successDuration:f(500),animationDuration:f(300)};var j=A({name:C,props:X,emits:["change","refresh","update:modelValue"],setup(s,{emit:d,slots:o}){let u;const g=D(),T=D(),H=$(g),e=N({status:"normal",distance:0,duration:0}),i=U(),P=()=>{if(s.headHeight!==x)return{height:`${s.headHeight}px`}},h=()=>e.status!=="loading"&&e.status!=="success"&&!s.disabled,E=t=>{const a=+(s.pullDistance||s.headHeight);return t>a&&(t<a*2?t=a+(t-a)/2:t=a*1.5+(t-a*2)/4),Math.round(t)},n=(t,a)=>{const l=+(s.pullDistance||s.headHeight);e.distance=t,a?e.status="loading":t===0?e.status="normal":t<l?e.status="pulling":e.status="loosing",d("change",{status:e.status,distance:t})},m=()=>{const{status:t}=e;return t==="normal"?"":s[`${t}Text`]||F(t)},k=()=>{const{status:t,distance:a}=e;if(o[t])return o[t]({distance:a});const l=[];return G.includes(t)&&l.push(c("div",{class:r("text")},[m()])),t==="loading"&&l.push(c(B,{class:r("loading")},{default:m})),l},V=()=>{e.status="success",setTimeout(()=>{n(0)},+s.successDuration)},v=t=>{u=R(H.value)===0,u&&(e.duration=0,i.start(t))},b=t=>{h()&&v(t)},_=t=>{if(h()){u||v(t);const{deltaY:a}=i;i.move(t),u&&a.value>=0&&i.isVertical()&&(I(t),n(E(a.value)))}},S=()=>{u&&i.deltaY.value&&h()&&(e.duration=+s.animationDuration,e.status==="loosing"?(n(+s.headHeight,!0),d("update:modelValue",!0),M(()=>d("refresh"))):n(0))};return p(()=>s.modelValue,t=>{e.duration=+s.animationDuration,t?n(+s.headHeight,!0):o.success||s.successText?V():n(0,!1)}),w("touchmove",_,{target:T}),()=>{var t;const a={transitionDuration:`${e.duration}ms`,transform:e.distance?`translate3d(0,${e.distance}px, 0)`:""};return c("div",{ref:g,class:r()},[c("div",{ref:T,class:r("track"),style:a,onTouchstartPassive:b,onTouchend:S,onTouchcancel:S},[c("div",{class:r("head"),style:P()},[k()]),(t=o.default)==null?void 0:t.call(o)])])}}});const z=Y(j);export{z as P};
|
||||
import{a3 as y,d as A,a4 as L,a5 as $,E as p,a6 as w,l as c,g as D,A as N,L as B,a7 as I,p as M,a8 as f,a9 as R,aa as U,ab as Y}from"./index-gciDsUQi.js";const[C,r,F]=y("pull-refresh"),x=50,G=["pulling","loosing","success"],X={disabled:Boolean,modelValue:Boolean,headHeight:f(x),successText:String,pullingText:String,loosingText:String,loadingText:String,pullDistance:L,successDuration:f(500),animationDuration:f(300)};var j=A({name:C,props:X,emits:["change","refresh","update:modelValue"],setup(s,{emit:d,slots:o}){let u;const g=D(),T=D(),H=$(g),e=N({status:"normal",distance:0,duration:0}),i=U(),P=()=>{if(s.headHeight!==x)return{height:`${s.headHeight}px`}},h=()=>e.status!=="loading"&&e.status!=="success"&&!s.disabled,E=t=>{const a=+(s.pullDistance||s.headHeight);return t>a&&(t<a*2?t=a+(t-a)/2:t=a*1.5+(t-a*2)/4),Math.round(t)},n=(t,a)=>{const l=+(s.pullDistance||s.headHeight);e.distance=t,a?e.status="loading":t===0?e.status="normal":t<l?e.status="pulling":e.status="loosing",d("change",{status:e.status,distance:t})},m=()=>{const{status:t}=e;return t==="normal"?"":s[`${t}Text`]||F(t)},k=()=>{const{status:t,distance:a}=e;if(o[t])return o[t]({distance:a});const l=[];return G.includes(t)&&l.push(c("div",{class:r("text")},[m()])),t==="loading"&&l.push(c(B,{class:r("loading")},{default:m})),l},V=()=>{e.status="success",setTimeout(()=>{n(0)},+s.successDuration)},v=t=>{u=R(H.value)===0,u&&(e.duration=0,i.start(t))},b=t=>{h()&&v(t)},_=t=>{if(h()){u||v(t);const{deltaY:a}=i;i.move(t),u&&a.value>=0&&i.isVertical()&&(I(t),n(E(a.value)))}},S=()=>{u&&i.deltaY.value&&h()&&(e.duration=+s.animationDuration,e.status==="loosing"?(n(+s.headHeight,!0),d("update:modelValue",!0),M(()=>d("refresh"))):n(0))};return p(()=>s.modelValue,t=>{e.duration=+s.animationDuration,t?n(+s.headHeight,!0):o.success||s.successText?V():n(0,!1)}),w("touchmove",_,{target:T}),()=>{var t;const a={transitionDuration:`${e.duration}ms`,transform:e.distance?`translate3d(0,${e.distance}px, 0)`:""};return c("div",{ref:g,class:r()},[c("div",{ref:T,class:r("track"),style:a,onTouchstartPassive:b,onTouchend:S,onTouchcancel:S},[c("div",{class:r("head"),style:P()},[k()]),(t=o.default)==null?void 0:t.call(o)])])}}});const z=Y(j);export{z as P};
|
||||
Vendored
+1
-1
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
Vendored
+13
-13
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -9,8 +9,8 @@
|
||||
<meta name="background-color" content="#1C2D56" />
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
|
||||
<title>طلای منتزر</title>
|
||||
<script type="module" crossorigin src="/assets/index-CmYEpHK9.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-W391hScl.css">
|
||||
<script type="module" crossorigin src="/assets/index-gciDsUQi.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-D-jEuKqG.css">
|
||||
<link rel="manifest" href="/manifest.webmanifest"></head>
|
||||
<body style="background-color: #1C2D56">
|
||||
<div class="bg-white w-screen h-screen fixed"></div>
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import icons from './icons.json'
|
||||
|
||||
interface Props {
|
||||
@@ -14,17 +14,37 @@ interface Props {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: null,
|
||||
})
|
||||
const tempIcon = ref<string>()
|
||||
const refIcon = ref<HTMLSpanElement>()
|
||||
tempIcon.value = (icons as Record<string, string>)[`${props.icon}`]
|
||||
|
||||
onMounted(() => {
|
||||
if (props.size) {
|
||||
const svg = refIcon.value?.children[0] as SVGElement
|
||||
svg.setAttribute('width', props.size as string)
|
||||
svg.setAttribute('height', props.size as string)
|
||||
}
|
||||
})
|
||||
// FIXED: this used to be a plain ref, assigned once at setup —
|
||||
// tempIcon.value = icons[props.icon]
|
||||
// — instead of a computed. Vue reuses the same component instance across
|
||||
// re-renders when an `Icon` sits in the same template position (which every
|
||||
// caller in this app does; none pass a `:key` keyed to the icon name), so
|
||||
// setup only runs once per mount and that assignment never ran again. Any
|
||||
// caller that swaps `icon` on an already-mounted instance — the exact pattern
|
||||
// the cart quantity steppers use, `:icon="qty === 1 ? 'trash' : 'minus'"` —
|
||||
// had its SVG freeze on whichever icon happened to render first and silently
|
||||
// stop tracking the prop after that: incrementing a cart line past 1 never
|
||||
// swapped the frozen trash glyph back to minus, and the reverse (decrementing
|
||||
// back down to 1) never swapped a frozen minus back to trash either. A
|
||||
// computed re-evaluates on every `icon` change, so the markup — and, via the
|
||||
// watcher below, the width/height attributes size() sets on it — now actually
|
||||
// track the prop instead of only reading it once.
|
||||
const tempIcon = computed(() => (icons as Record<string, string>)[`${props.icon}`])
|
||||
|
||||
function applySize() {
|
||||
if (!props.size) return
|
||||
const svg = refIcon.value?.children[0] as SVGElement | undefined
|
||||
svg?.setAttribute('width', props.size as string)
|
||||
svg?.setAttribute('height', props.size as string)
|
||||
}
|
||||
|
||||
// v-html replaces refIcon's children synchronously with the DOM update, but
|
||||
// that update itself is queued — nextTick() waits for it so applySize() finds
|
||||
// the new <svg> already in the DOM rather than the previous one (or none, on
|
||||
// the very first render).
|
||||
watch(tempIcon, () => nextTick(applySize), { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
</div>
|
||||
|
||||
<div class="ci__row">
|
||||
<!-- App-wide stepper order rule (also followed by SingleProduct.vue's
|
||||
.pd__qty): plus on the visual right, minus (or trash at qty 1) on
|
||||
the visual left. The page is RTL, so a plain flex row lays its
|
||||
DOM-first child on the right — plus has to come FIRST in markup,
|
||||
not last, to land there. Keep both steppers' DOM order in sync if
|
||||
either one changes. -->
|
||||
<div class="ci__qty">
|
||||
<button type="button" class="ci__qtyBtn" aria-label="افزودن" @click="increment">
|
||||
<Icon icon="vuesax-linear:add" size="16" />
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
<!--
|
||||
Swipeable image slider — a from-scratch rewrite of the gallery/preview
|
||||
carousel that used to live inline in SingleProduct.vue.
|
||||
|
||||
WHY A REWRITE, NOT A PATCH: the old slider swiped correctly by feel but
|
||||
visibly jumped mid-gesture, in both the inline gallery and the full-screen
|
||||
preview. The root cause was structural, not a tunable number:
|
||||
|
||||
- The whole app sets `direction: rtl !important` on #app (see
|
||||
src/App.vue). Under RTL, a flex row lays its children right-to-left —
|
||||
slide 0 sits at the visual RIGHT edge, not the left.
|
||||
- `transform: translate3d(X%, 0, 0)` is direction-agnostic: a positive X
|
||||
always moves content toward the visual right, in RTL exactly as in LTR.
|
||||
- The old track combined `translate3d(index * 100%, 0, 0)` with the page's
|
||||
ambient RTL flex order. Those two systems don't agree on which way
|
||||
"forward" is, so the settle position after a drag did not line up with
|
||||
where the flex box had actually placed that slide — the visual result
|
||||
was the image overshooting and snapping back, i.e. the reported "jump".
|
||||
|
||||
THE FIX: this component's slider track is an isolated `direction: ltr`
|
||||
subtree (see .gs__track below). Once inside that subtree, slide order,
|
||||
pointer-delta sign and `translateX` sign are all plain, ordinary LTR
|
||||
arithmetic — index 0 first, positive X moves right, done — regardless of
|
||||
what direction the rest of the page is in. The component's own controls
|
||||
(dots, drag gesture) still read as natural "swipe right for previous
|
||||
image" to an RTL user because the *gesture* is still interpreted in screen
|
||||
space; only the slider's internal layout is pinned to LTR so its own maths
|
||||
is self-consistent.
|
||||
|
||||
A few other correctness fixes bundled into the same rewrite, since they were
|
||||
entangled with the same code:
|
||||
- Pointer Events instead of Touch Events: one code path for touch, mouse
|
||||
and pen, with proper pointer capture so a drag that leaves the element
|
||||
(finger sliding off the edge) is still tracked to completion instead of
|
||||
silently stopping — the old touch-only handlers dropped the gesture the
|
||||
moment the finger crossed the element boundary.
|
||||
- Position is settled against the track's OWN measured width
|
||||
(getBoundingClientRect), not against `%` of an assumed-100%-per-slide
|
||||
layout — immune to any box-sizing/padding mismatch between the measured
|
||||
width and the CSS `flex: 0 0 100%` cell width.
|
||||
- One component, two instances (the inline stage and the full-screen
|
||||
preview both render a <GallerySlider>) instead of one set of drag state
|
||||
manually re-entered for two different DOM subtrees via a `source` tag.
|
||||
They stay in sync through `v-model:index`, a plain reactive prop/emit
|
||||
binding — not shared mutable drag variables, which is what the "does a
|
||||
drag started on A leak into B" bug class was ultimately rooted in.
|
||||
-->
|
||||
<template>
|
||||
<div
|
||||
ref="root"
|
||||
class="gs"
|
||||
:class="{ 'is-dragging': dragging }"
|
||||
@pointerdown="onPointerDown"
|
||||
@pointermove="onPointerMove"
|
||||
@pointerup="onPointerUp"
|
||||
@pointercancel="onPointerCancel"
|
||||
@click="onClick"
|
||||
>
|
||||
<div class="gs__track" :style="trackStyle">
|
||||
<div v-for="src in slides" :key="src" class="gs__cell">
|
||||
<img :src="src" :alt="alt" class="gs__img" :class="fitClass" draggable="false" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="showCounter && slides.length > 1" class="gs__counter">{{ index + 1 }}/{{ slides.length }}</div>
|
||||
|
||||
<slot name="dots" :index="index" :go="go" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
slides: string[]
|
||||
alt: string
|
||||
/** `cover` (the inline stage's default) or `contain` (the preview's). */
|
||||
fit?: 'cover' | 'contain'
|
||||
/** Show the built-in "n/N" pill, bottom-start of the slider.
|
||||
*
|
||||
* Off by default. FIXED: both call sites in SingleProduct.vue already
|
||||
* draw their own overlay chrome in that same corner — the inline stage
|
||||
* has .pd__expand there, and the preview has its own top-centre
|
||||
* .pd__previewCounter — so this component's counter used to render on
|
||||
* top of .pd__expand unconditionally, the two pieces of UI visibly
|
||||
* overlapping into illegible stacked text/icons. Neither caller wants
|
||||
* this counter today; a future bare usage that does can opt in. */
|
||||
showCounter?: boolean
|
||||
}>(),
|
||||
{ fit: 'cover', showCounter: false },
|
||||
)
|
||||
|
||||
const index = defineModel<number>('index', { default: 0 })
|
||||
|
||||
const emit = defineEmits<{
|
||||
/** A plain tap — press and release without a real drag. Distinct from a
|
||||
* native `click`, which a touch sequence also fires synthetically on
|
||||
* release even after a drag; consumers that want "open on tap only"
|
||||
* should use this instead of listening for `click` themselves. */
|
||||
(e: 'tap'): void
|
||||
}>()
|
||||
|
||||
const fitClass = computed(() => (props.fit === 'contain' ? 'gs__img--contain' : 'gs__img--cover'))
|
||||
|
||||
const root = ref<HTMLElement | null>(null)
|
||||
|
||||
// ── Drag state ────────────────────────────────────────────────
|
||||
// All local to one instance — the inline stage and the full-screen preview
|
||||
// each mount their own GallerySlider and so each get their own root, dragX,
|
||||
// dragging, etc. Nothing here is shared across instances; only `index` is,
|
||||
// via v-model, which is exactly the one thing that SHOULD stay in sync.
|
||||
const dragging = ref(false)
|
||||
const dragX = ref(0)
|
||||
let pointerId: number | null = null
|
||||
let startX = 0
|
||||
let trackWidth = 0
|
||||
|
||||
// Past this many pixels of travel, the drag counts as a swipe rather than a
|
||||
// tap — used both to decide whether to commit to the next/previous slide and
|
||||
// to suppress the `tap` event so a swipe never also opens the preview.
|
||||
const DRAG_COMMIT_RATIO = 0.18 // fraction of the track's own width
|
||||
const TAP_MAX_PX = 6
|
||||
|
||||
function onPointerDown(e: PointerEvent) {
|
||||
if (props.slides.length < 2 || pointerId !== null) return
|
||||
const el = root.value
|
||||
if (!el) return
|
||||
pointerId = e.pointerId
|
||||
startX = e.clientX
|
||||
trackWidth = el.getBoundingClientRect().width || 1
|
||||
dragX.value = 0
|
||||
dragging.value = true
|
||||
// Pointer capture keeps delivering move/up events to this element even once
|
||||
// the pointer leaves it — the touch-events version of this component lost
|
||||
// the gesture the instant a fast swipe crossed the element's edge.
|
||||
el.setPointerCapture?.(e.pointerId)
|
||||
}
|
||||
|
||||
function onPointerMove(e: PointerEvent) {
|
||||
if (!dragging.value || e.pointerId !== pointerId) return
|
||||
dragX.value = e.clientX - startX
|
||||
}
|
||||
|
||||
function endDrag() {
|
||||
if (!dragging.value) return
|
||||
const dx = dragX.value
|
||||
const ratio = dx / trackWidth
|
||||
|
||||
dragging.value = false
|
||||
pointerId = null
|
||||
dragX.value = 0
|
||||
|
||||
// Screen-space drag direction, translated to an index step. This is the one
|
||||
// place RTL vs. LTR actually matters for *behaviour* (not layout): dragging
|
||||
// a finger to the left (negative dx) is "next image" regardless of the
|
||||
// track's own internal LTR layout, because that is what the gesture means
|
||||
// to the person doing it, in either reading direction.
|
||||
if (ratio <= -DRAG_COMMIT_RATIO && index.value < props.slides.length - 1) index.value++
|
||||
else if (ratio >= DRAG_COMMIT_RATIO && index.value > 0) index.value--
|
||||
|
||||
if (Math.abs(dx) <= TAP_MAX_PX) emit('tap')
|
||||
}
|
||||
|
||||
function onPointerUp(e: PointerEvent) {
|
||||
if (e.pointerId !== pointerId) return
|
||||
endDrag()
|
||||
}
|
||||
|
||||
function onPointerCancel(e: PointerEvent) {
|
||||
if (e.pointerId !== pointerId) return
|
||||
// A cancelled gesture (e.g. the OS takes over for a system swipe) snaps back
|
||||
// to the current slide rather than committing a possibly-partial drag.
|
||||
dragging.value = false
|
||||
pointerId = null
|
||||
dragX.value = 0
|
||||
}
|
||||
|
||||
// A touch sequence still fires a native `click` on release. `onPointerUp`
|
||||
// already emits `tap` for a real tap and has already run by the time `click`
|
||||
// fires, so this handler only needs to swallow the click's default double-
|
||||
// firing — nothing further to do here, but the listener stays as documentation
|
||||
// that `click` is deliberately NOT used for the tap-to-preview affordance
|
||||
// (`tap` is) precisely because `click` also fires after a swipe.
|
||||
function onClick() {
|
||||
/* intentionally empty — see comment above */
|
||||
}
|
||||
|
||||
function go(i: number) {
|
||||
index.value = i
|
||||
}
|
||||
|
||||
// ── Track position ───────────────────────────────────────────
|
||||
// The whole point of isolating this in its own `direction: ltr` subtree (see
|
||||
// .gs__track in <style>): inside it, "index 0 is first" and "positive X moves
|
||||
// right" are both just true, with no page-level RTL to reconcile against.
|
||||
const trackStyle = computed(() => {
|
||||
const base = -index.value * 100
|
||||
const dragPercent = trackWidth ? (dragX.value / trackWidth) * 100 : 0
|
||||
return {
|
||||
transform: `translate3d(${base + dragPercent}%, 0, 0)`,
|
||||
transition: dragging.value ? 'none' : undefined,
|
||||
}
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (pointerId !== null && root.value) {
|
||||
try {
|
||||
root.value.releasePointerCapture(pointerId)
|
||||
} catch {
|
||||
/* element may already be detached */
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.gs {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
touch-action: pan-y;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
// Isolated from the page's `direction: rtl` — see the file header. Everything
|
||||
// under this node uses plain LTR layout and LTR-signed transforms.
|
||||
.gs__track {
|
||||
direction: ltr;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transition: transform 0.42s cubic-bezier(0.22, 0.61, 0.36, 1);
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.gs.is-dragging .gs__track {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.gs__cell {
|
||||
flex: 0 0 100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gs__img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
-webkit-user-drag: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.gs__img--cover {
|
||||
// The inline stage's own padding/background is supplied by the caller
|
||||
// (.pd__stage); this component only sets the fit mode.
|
||||
object-fit: contain;
|
||||
padding: 46px 20px 20px;
|
||||
}
|
||||
|
||||
.gs__img--contain {
|
||||
object-fit: contain;
|
||||
padding: 20px 22px;
|
||||
}
|
||||
|
||||
.gs__counter {
|
||||
position: absolute;
|
||||
bottom: 14px;
|
||||
// Placed with a logical property (so it sits at the trailing edge in the
|
||||
// page's own RTL reading order) — this is UI chrome layered on top of the
|
||||
// slider, not part of the isolated LTR track, so it should still follow the
|
||||
// page's direction like everything else in the app.
|
||||
inset-inline-start: 14px;
|
||||
padding: 4px 9px;
|
||||
border-radius: 999px;
|
||||
font-size: 10.5px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background: rgba(20, 22, 26, 0.45);
|
||||
backdrop-filter: blur(4px);
|
||||
direction: ltr;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
@@ -69,35 +69,40 @@
|
||||
|
||||
<!-- ── Gallery ───────────────────────────────────────── -->
|
||||
<div class="pd__gallery">
|
||||
<div
|
||||
<GallerySlider
|
||||
v-if="hasImages"
|
||||
v-model:index="imageIndex"
|
||||
:slides="slides"
|
||||
:alt="title"
|
||||
class="pd__stage"
|
||||
@touchstart.passive="onTouchStart"
|
||||
@touchmove.passive="onTouchMove"
|
||||
@touchend="onTouchEnd"
|
||||
@tap="openPreview"
|
||||
>
|
||||
<div class="pd__track" :class="{ 'is-dragging': dragging }" :style="{ transform: `translate3d(${trackOffset}, 0, 0)` }">
|
||||
<div v-for="src in slides" :key="src" class="pd__slide">
|
||||
<img :src="src" :alt="title" class="pd__art" />
|
||||
<template #dots="{ index, go }">
|
||||
<!-- The reference's dot rail: vertical, pinned to the trailing
|
||||
edge. -->
|
||||
<div v-if="slides.length > 1" class="pd__rail">
|
||||
<button
|
||||
v-for="(s, i) in slides"
|
||||
:key="s"
|
||||
type="button"
|
||||
class="pd__railDot"
|
||||
:class="{ 'is-on': i === index }"
|
||||
:aria-label="`تصویر ${i + 1}`"
|
||||
@click.stop="go(i)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- The reference's dot rail: vertical, pinned to the trailing edge. -->
|
||||
<div v-if="slides.length > 1" class="pd__rail">
|
||||
<button
|
||||
v-for="(s, i) in slides"
|
||||
:key="s"
|
||||
type="button"
|
||||
class="pd__railDot"
|
||||
:class="{ 'is-on': i === imageIndex }"
|
||||
:aria-label="`تصویر ${i + 1}`"
|
||||
@click="imageIndex = i"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</GallerySlider>
|
||||
<div v-else class="pd__stage pd__stage--empty">
|
||||
<Icon icon="vuesax-linear:diamonds" size="27" />
|
||||
</div>
|
||||
|
||||
<!-- Tap-to-preview affordance, so the full-screen viewer is
|
||||
discoverable without it being the whole stage's only behaviour
|
||||
(the stage still swipes in place). -->
|
||||
<span v-if="hasImages" class="pd__expand" aria-hidden="true">
|
||||
<Icon icon="vuesax-linear:maximize-4" size="15" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- ── Scrolling content ─────────────────────────────── -->
|
||||
@@ -198,7 +203,18 @@
|
||||
it deep-links to its category (a real destination); once it is, it
|
||||
becomes the quantity stepper, which has to live somewhere and this
|
||||
is the slot the layout already gives it. -->
|
||||
<!-- Stepper order rule, the same one CartItem.vue follows: plus on
|
||||
the visual right, minus (or trash at qty 1) on the visual left.
|
||||
The page is RTL, so a plain flex row already lays its DOM-first
|
||||
child on the right — plus has to be FIRST in markup, not last, to
|
||||
land there. (FIXED: this used to be minus/trash, value, plus —
|
||||
the reverse of the intended layout, which put plus on the visual
|
||||
left instead of the right.) -->
|
||||
<div v-if="inCart" class="pd__qty">
|
||||
<button type="button" class="pd__qtyBtn" aria-label="افزایش" @click="increment">
|
||||
<Icon icon="vuesax-linear:add" size="15" />
|
||||
</button>
|
||||
<span class="pd__qtyValue">{{ cartQty }}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="pd__qtyBtn"
|
||||
@@ -207,10 +223,6 @@
|
||||
>
|
||||
<Icon :icon="cartQty === 1 ? 'vuesax-linear:trash' : 'vuesax-linear:minus'" size="15" />
|
||||
</button>
|
||||
<span class="pd__qtyValue">{{ cartQty }}</span>
|
||||
<button type="button" class="pd__qtyBtn" aria-label="افزایش" @click="increment">
|
||||
<Icon icon="vuesax-linear:add" size="15" />
|
||||
</button>
|
||||
</div>
|
||||
<button v-else-if="categoryTitle" type="button" class="pd__pill" @click="goCategory">
|
||||
<Icon icon="vuesax-linear:category" size="17" />
|
||||
@@ -234,6 +246,54 @@
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- ── Full-screen preview ───────────────────────────────── -->
|
||||
<!-- A sibling of .pd, not nested inside it: .pd is the scroll container
|
||||
(overflow-y: auto), and an element positioned fixed/absolute inside it
|
||||
would still be clipped by that overflow in the Drawer mount, the same
|
||||
reason the gallery is sticky rather than fixed. Sitting outside it
|
||||
avoids the problem entirely — this is a real overlay, not something
|
||||
that has to stay in the document's scroll flow. -->
|
||||
<Teleport to="body">
|
||||
<Transition name="pd-preview">
|
||||
<div v-if="previewOpen" class="pd__preview" @click.self="closePreview">
|
||||
<button type="button" class="pd__previewClose" aria-label="بستن" @click="closePreview">
|
||||
<Icon icon="vuesax-linear:add" size="20" />
|
||||
</button>
|
||||
|
||||
<div v-if="slides.length > 1" class="pd__previewCounter">{{ imageIndex + 1 }} / {{ slides.length }}</div>
|
||||
|
||||
<!-- Same slider, a second instance: `v-model:index` is what keeps it
|
||||
in lockstep with the inline gallery above (both read/write the
|
||||
one `imageIndex` ref), not shared drag state — each instance
|
||||
tracks and settles its own gesture independently. -->
|
||||
<GallerySlider
|
||||
v-model:index="imageIndex"
|
||||
:slides="slides"
|
||||
:alt="title"
|
||||
class="pd__previewStage"
|
||||
fit="contain"
|
||||
/>
|
||||
|
||||
<!-- Horizontal thumbnail strip, replacing the old dot row: each
|
||||
frame is the actual photo, so jumping to a specific image is
|
||||
one glance-and-tap instead of counting dots to find it. -->
|
||||
<div v-if="slides.length > 1" class="pd__previewThumbs no-scrollbar">
|
||||
<button
|
||||
v-for="(s, i) in slides"
|
||||
:key="s"
|
||||
type="button"
|
||||
class="pd__previewThumb"
|
||||
:class="{ 'is-on': i === imageIndex }"
|
||||
:aria-label="`تصویر ${i + 1}`"
|
||||
@click="imageIndex = i"
|
||||
>
|
||||
<img :src="s" :alt="`${title} ${i + 1}`" draggable="false" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
|
||||
<NotifyVant :timeOut="3000" v-model="notify" :color="'background-color: #14161A'">
|
||||
<div class="font-bold text-right mb-2">ثبت سفارش</div>
|
||||
<div>محصول با موفقیت به سبد خرید افزوده شد</div>
|
||||
@@ -257,9 +317,10 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue'
|
||||
import { computed, onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import Icon from '../icon/Icon.vue'
|
||||
import GallerySlider from './GallerySlider.vue'
|
||||
import Spinner from '../Spinner.vue'
|
||||
import NotifyVant from '../NotifyVant.vue'
|
||||
import DialogVant from '../DialogVant.vue'
|
||||
@@ -361,48 +422,30 @@ watch(slides, (list) => {
|
||||
if (imageIndex.value > list.length - 1) imageIndex.value = 0
|
||||
})
|
||||
|
||||
// ── Gallery swipe ────────────────────────────────────────────
|
||||
// The slides are stacked on one line and the track is translated to bring the
|
||||
// active one on screen. The page is RTL, so the line runs right-to-left and
|
||||
// slide N sits at +N × 100%: a drag towards the start of the line (negative dx
|
||||
// in screen coordinates) advances to the next image.
|
||||
// ── Gallery ───────────────────────────────────────────────────
|
||||
// The swipe/drag mechanics live in GallerySlider.vue now — see that file's
|
||||
// header for why the old inline implementation was rewritten rather than
|
||||
// patched (it jumped mid-gesture because of an RTL/transform sign mismatch).
|
||||
// The inline stage and the full-screen preview below each mount their own
|
||||
// <GallerySlider>; `imageIndex` is the one thing they share, via v-model, so
|
||||
// picking an image in either place moves both.
|
||||
//
|
||||
// A plain transform slider rather than a carousel library — the app already
|
||||
// pulls swiper in for the home rails, but this is a few lines of maths over
|
||||
// three or four images and does not need one.
|
||||
const dragX = ref(0)
|
||||
const dragging = ref(false)
|
||||
let startX = 0
|
||||
// GallerySlider distinguishes a tap from a swipe itself and emits `tap` only
|
||||
// for the former, so opening the preview needs no drag-jitter bookkeeping here
|
||||
// the way the old inline handlers did.
|
||||
const previewOpen = ref(false)
|
||||
|
||||
// While dragging, the finger's travel is carried as a raw pixel delta on top of
|
||||
// the settled percentage, so the image tracks the thumb instead of snapping.
|
||||
const trackOffset = computed(() =>
|
||||
dragging.value ? `calc(${imageIndex.value * 100}% + ${dragX.value}px)` : `${imageIndex.value * 100}%`,
|
||||
)
|
||||
|
||||
// Past this much travel the swipe commits to the next image; below it the
|
||||
// track springs back to where it started.
|
||||
const SWIPE_COMMIT_PX = 48
|
||||
|
||||
function onTouchStart(e: TouchEvent) {
|
||||
if (slides.value.length < 2) return
|
||||
startX = e.touches[0].clientX
|
||||
dragX.value = 0
|
||||
dragging.value = true
|
||||
function openPreview() {
|
||||
if (!hasImages.value) return
|
||||
previewOpen.value = true
|
||||
// The preview is teleported to <body> and would otherwise let the page (or
|
||||
// the Drawer) scroll behind it.
|
||||
document.body.style.overflow = 'hidden'
|
||||
}
|
||||
|
||||
function onTouchMove(e: TouchEvent) {
|
||||
if (!dragging.value) return
|
||||
dragX.value = e.touches[0].clientX - startX
|
||||
}
|
||||
|
||||
function onTouchEnd() {
|
||||
if (!dragging.value) return
|
||||
const dx = dragX.value
|
||||
dragging.value = false
|
||||
dragX.value = 0
|
||||
if (dx <= -SWIPE_COMMIT_PX && imageIndex.value < slides.value.length - 1) imageIndex.value++
|
||||
else if (dx >= SWIPE_COMMIT_PX && imageIndex.value > 0) imageIndex.value--
|
||||
function closePreview() {
|
||||
previewOpen.value = false
|
||||
document.body.style.overflow = ''
|
||||
}
|
||||
|
||||
const wageLabel = computed(() => {
|
||||
@@ -467,6 +510,13 @@ const goCategory = () => {
|
||||
onBeforeMount(async () => {
|
||||
await productDetail.load()
|
||||
})
|
||||
|
||||
// If the preview is left open when this instance goes away — the drawer is
|
||||
// closed, or the routed page is navigated away from — the body scroll lock it
|
||||
// set would otherwise outlive it and leave the rest of the app unscrollable.
|
||||
onBeforeUnmount(() => {
|
||||
if (previewOpen.value) document.body.style.overflow = ''
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@@ -656,47 +706,12 @@ onBeforeMount(async () => {
|
||||
color: @inkFaint;
|
||||
}
|
||||
|
||||
.pd__track {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
// Settles with the same long decelerate the home screen's reveal uses, so
|
||||
// the two read as one system. Suppressed mid-drag so the image sits under
|
||||
// the finger rather than lagging behind it.
|
||||
transition: transform 0.5s cubic-bezier(0.32, 0.72, 0, 1);
|
||||
will-change: transform;
|
||||
}
|
||||
.pd__track.is-dragging {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.pd__slide {
|
||||
flex: 0 0 100%;
|
||||
height: 100%;
|
||||
// Each slide sits one full width further along the line; with the track
|
||||
// translated by +index × 100% the active one lands on screen.
|
||||
margin-inline-start: -100%;
|
||||
}
|
||||
.pd__slide:first-child {
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
.pd__art {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// `contain`, not `cover`: a piece of jewellery is the subject of its own
|
||||
// photo, so cropping it to fill the frame cut the edges off. Every other
|
||||
// card in the app (ProductCard, ProductPanel, CartItem) uses `contain` for
|
||||
// the same reason — the whole piece has to be visible.
|
||||
object-fit: contain;
|
||||
// Breathing room so the piece does not touch the frame or sit under the
|
||||
// floating controls at the top.
|
||||
padding: 46px 20px 20px;
|
||||
display: block;
|
||||
// Otherwise a drag on the image starts the browser's own image drag and the
|
||||
// touch sequence never reaches touchend.
|
||||
-webkit-user-drag: none;
|
||||
user-select: none;
|
||||
}
|
||||
// The slider's own track/cell/image rules (.gs__track etc.) live in
|
||||
// GallerySlider.vue, which this stage now renders — see that file's header
|
||||
// for why the swipe mechanics were rewritten there instead of staying inline
|
||||
// here. .pd__stage only supplies the sizing shell (height, background) that
|
||||
// the slider fills; .gs__img--cover on that component sets the same padding
|
||||
// and `object-fit: contain` this rule used to.
|
||||
|
||||
// Vertical dot rail on the trailing edge, as in the reference.
|
||||
.pd__rail {
|
||||
@@ -727,6 +742,196 @@ onBeforeMount(async () => {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
// Small tap-to-preview affordance, bottom-start corner of the stage — clear of
|
||||
// the trailing dot rail and the leading controls above it.
|
||||
.pd__expand {
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
inset-inline-start: 12px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 10px;
|
||||
color: #fff;
|
||||
background: rgba(20, 22, 26, 0.35);
|
||||
backdrop-filter: blur(6px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ── Full-screen preview ─────────────────────────────────── */
|
||||
// Teleported to <body> — see the template comment on why this sits outside
|
||||
// .pd rather than nested in it.
|
||||
.pd__preview {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
// FIXED: this was 1000, the exact z-index ant-design-vue's Drawer uses for
|
||||
// its own wrapper (@zindex-modal in its theme, see node_modules/
|
||||
// ant-design-vue/es/style/themes/default.less). Both are teleported to
|
||||
// <body> as siblings, so a tie at the same z-index resolves by DOM order —
|
||||
// fragile and, in the product-card mount (the drawer this component usually
|
||||
// opens inside), it lost: the Drawer's own content, including .pd__bar at
|
||||
// its OWN stacking context z-index of 20, painted on top of the preview
|
||||
// instead of under it — the "چیزی آن پایین بههم ریخته" in the screenshot.
|
||||
// Clearing the modal layer's z-index by a wide margin makes the preview
|
||||
// unconditionally the topmost layer, regardless of which Teleport happened
|
||||
// to mount last.
|
||||
z-index: 2000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// A dim, blurred veil rather than a near-opaque slab: low-alpha black so
|
||||
// whatever is behind it (the product photo mid-transition, the page) still
|
||||
// reads through softly, and `backdrop-filter: blur` on that same layer is
|
||||
// what actually does the softening — this is the frosted-glass look the
|
||||
// header bar and the floating gallery controls elsewhere on this page
|
||||
// already use (see .pd__header.is-solid, .pd__round), not a new material.
|
||||
background: rgba(10, 10, 12, 0.55);
|
||||
backdrop-filter: blur(28px) saturate(140%);
|
||||
}
|
||||
|
||||
.pd__previewClose {
|
||||
position: absolute;
|
||||
top: calc(14px + env(safe-area-inset-top, 0px));
|
||||
inset-inline-end: 14px;
|
||||
z-index: 2;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0. );
|
||||
backdrop-filter: blur(10px);
|
||||
transform: rotate(45deg);
|
||||
transition: transform 0.18s ease, background 0.18s ease;
|
||||
}
|
||||
.pd__previewClose:active {
|
||||
transform: rotate(45deg) scale(0.92);
|
||||
}
|
||||
|
||||
// FIXED: this box spanned the full width of the screen (inset-inline: 0) to
|
||||
// centre its text, and at top:24px/height~18px it vertically overlapped the
|
||||
// close button's box (top:14px, 38px tall — occupying 14–52px) by ~28px. Nothing
|
||||
// visually showed it there since the text itself is centred and narrow, but the
|
||||
// full-width transparent box still intercepted pointer events in that overlap
|
||||
// band, sitting on top of the close button (same z-index, later in the DOM
|
||||
// wins the tie) — a tap that looked like it landed on the button actually hit
|
||||
// this invisible strip instead, which is why the button felt like its hitbox
|
||||
// had drifted below where it was drawn. Text and decoration only, never a
|
||||
// click target, so it should never have been able to steal one.
|
||||
.pd__previewCounter {
|
||||
position: absolute;
|
||||
top: calc(24px + env(safe-area-inset-top, 0px));
|
||||
inset-inline-start: 0;
|
||||
inset-inline-end: 0;
|
||||
z-index: 2;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
direction: ltr;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Sizing shell for the slider it wraps (GallerySlider needs a sized parent —
|
||||
// `flex: 1` here, `height: 54vh` for .pd__stage above); the track/cell/image
|
||||
// rules themselves live in GallerySlider.vue, with `fit="contain"` set in the
|
||||
// template for this instance.
|
||||
.pd__previewStage {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
// Horizontal thumbnail strip, replacing the old dot row (which told you HOW
|
||||
// MANY images there were and which one you were on, but not what any of them
|
||||
// actually showed — jumping to a specific photo meant counting dots). Real
|
||||
// frames of the real photos instead: quicker to scan and to reach with a
|
||||
// single tap, especially past four or five images where dots alone stop being
|
||||
// legible at a glance.
|
||||
.pd__previewThumbs {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
// Centred, not left- or right-anchored: with few thumbnails (the common
|
||||
// case — most products have a handful of photos) a flex row's default
|
||||
// start-alignment left the strip hugging one edge instead of sitting under
|
||||
// the image it belongs to. `justify-content` only affects extra space when
|
||||
// the row is short enough not to need it — once there are enough thumbnails
|
||||
// to overflow, `overflow-x: auto` takes over and this has no effect, so
|
||||
// scrolling to reach the rest still works exactly as before.
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: x proximity;
|
||||
padding: 10px 16px calc(18px + env(safe-area-inset-bottom, 0px));
|
||||
}
|
||||
|
||||
.pd__previewThumb {
|
||||
scroll-snap-align: center;
|
||||
flex: 0 0 auto;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
padding: 6px;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
// FIXED: was a near-invisible tint (rgba(255,255,255,0.06)) — against the
|
||||
// dark preview overlay, a piece shot on a transparent or white background
|
||||
// (the catalogue photos this strip shows) had no surface to sit on and read
|
||||
// as floating in the dark with no edges. Solid white gives every thumbnail
|
||||
// the same real ground the piece was actually photographed against, the way
|
||||
// ProductCard/ProductPanel's own panels do for the exact same reason.
|
||||
background: #fff;
|
||||
// A dim, unselected thumbnail is the resting state; the active one lifts to
|
||||
// full brightness with a ring, so the strip reads as a filmstrip with one
|
||||
// frame in focus rather than a flat, undifferentiated row.
|
||||
opacity: 0.65;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
transition: opacity 0.2s ease, outline-color 0.2s ease, transform 0.18s ease;
|
||||
}
|
||||
.pd__previewThumb:active {
|
||||
transform: scale(0.94);
|
||||
}
|
||||
.pd__previewThumb.is-on {
|
||||
opacity: 1;
|
||||
// Still legible against the thumbnail's own new white background because
|
||||
// `outline-offset: 2px` above pushes the ring OUTSIDE the box — the 2px gap
|
||||
// between the white square and the white ring shows the dark preview
|
||||
// overlay behind it, so the ring reads as floating over dark, not as a
|
||||
// white-on-white line that would vanish.
|
||||
outline-color: #fff;
|
||||
}
|
||||
|
||||
.pd__previewThumb img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// `contain`, not `cover`: with the white background above, the whole piece
|
||||
// should sit fully visible on that ground rather than being cropped to fill
|
||||
// the square — the same reasoning behind `contain` everywhere else in this
|
||||
// app that shows a piece of jewellery (GallerySlider's own `cover`/`contain`
|
||||
// fit is for the full-size stage, where the frame is large enough that
|
||||
// `cover` doesn't lose meaningful detail; a 52px thumbnail has no such room
|
||||
// to spare).
|
||||
object-fit: contain;
|
||||
display: block;
|
||||
-webkit-user-drag: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
// Simple fade + settle for the preview opening/closing, independent of the
|
||||
// gallery's own slide-swipe transition on .pd__track.
|
||||
.pd-preview-enter-active,
|
||||
.pd-preview-leave-active {
|
||||
transition: opacity 0.24s ease;
|
||||
}
|
||||
.pd-preview-enter-from,
|
||||
.pd-preview-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ── Sheet ───────────────────────────────────────────────── */
|
||||
// Rides over the stuck gallery. A higher stacking level than .pd__gallery is
|
||||
// what lets it cover the image instead of scrolling behind it, and the bottom
|
||||
|
||||
Reference in New Issue
Block a user