@antontranelis/money-printer 1.0.89 → 1.0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),d=require("react"),nn=require("zustand"),lt=require("zustand/middleware"),an=require("jspdf");var me=typeof document<"u"?document.currentScript:null;const rn=1024,ue=new Map;let F=null,ut=null;function et(e,t){return F||(F=document.createElement("canvas"),ut=F.getContext("2d",{willReadFrequently:!0})),(F.width!==e||F.height!==t)&&(F.width=e,F.height=t),ut}function Te(e){const t=ue.get(e);return t?Promise.resolve(t):new Promise((n,a)=>{const r=new Image;r.onload=()=>{if(ue.size>10){const l=ue.keys().next().value;l&&ue.delete(l)}ue.set(e,r),n(r)},r.onerror=()=>a(new Error("Failed to load image")),r.src=e})}function pt(){ue.clear()}async function bt(e,t=rn){const n=await Te(e),a=Math.max(n.width,n.height);if(a<=t)return e;const r=t/a,l=Math.round(n.width*r),o=Math.round(n.height*r),i=document.createElement("canvas"),s=i.getContext("2d");if(!s)throw new Error("Failed to get canvas context");return i.width=l,i.height=o,s.drawImage(n,0,0,l,o),i.toDataURL("image/jpeg",.9)}async function $e(e,t,n,a=0){const[r,l]=await Promise.all([Te(e),Te(t)]),o=et(r.width,r.height);if(o.clearRect(0,0,r.width,r.height),n>0){const i=a*20;o.save(),o.globalAlpha=n,i>0&&(o.filter=`blur(${i}px)`),o.drawImage(l,0,0,r.width,r.height),o.restore()}return o.drawImage(r,0,0),F.toDataURL("image/png")}async function xt(e,t=.5,n=40){const a=await Te(e),r=et(a.width,a.height);r.clearRect(0,0,a.width,a.height),r.drawImage(a,0,0);const l=r.getImageData(0,0,a.width,a.height),o=l.data,i=new Uint32Array(o.buffer),s=1+t*.8,u=1-t,h=n%360/360;for(let x=0;x<i.length;x++){const f=i[x],g=f&255,v=f>>8&255,I=f>>16&255,m=f>>24&255;if(m===0)continue;let T=(((77*g+150*v+29*I>>8)/255-.5)*s+.5)*255;T<0?T=0:T>255&&(T=255);const k=T/255,E=.12,[L,S,A]=wt(h,E,k),j=g*u+L*t|0,R=v*u+S*t|0,B=I*u+A*t|0;i[x]=m<<24|B<<16|R<<8|j}return r.putImageData(l,0,0),F.toDataURL("image/png")}function on(e,t,n){e/=255,t/=255,n/=255;const a=Math.max(e,t,n),r=Math.min(e,t,n),l=(a+r)/2;let o=0,i=0;if(a!==r){const s=a-r;switch(i=l>.5?s/(2-a-r):s/(a+r),a){case e:o=((t-n)/s+(t<n?6:0))/6;break;case t:o=((n-e)/s+2)/6;break;case n:o=((e-t)/s+4)/6;break}}return[o,i,l]}function wt(e,t,n){if(t===0){const o=Math.round(n*255);return[o,o,o]}const a=(o,i,s)=>(s<0&&(s+=1),s>1&&(s-=1),s<1/6?o+(i-o)*6*s:s<1/2?i:s<2/3?o+(i-o)*(2/3-s)*6:o),r=n<.5?n*(1+t):n+t-n*t,l=2*n-r;return[Math.round(a(l,r,e+1/3)*255),Math.round(a(l,r,e)*255),Math.round(a(l,r,e-1/3)*255)]}const sn=29,cn=5;async function yt(e,t){if(Math.abs(t-sn)<=cn)return e;const n=await Te(e),a=et(n.width,n.height);a.clearRect(0,0,n.width,n.height),a.drawImage(n,0,0);const r=a.getImageData(0,0,n.width,n.height),l=r.data,o=new Uint32Array(l.buffer),i=t%360/360,s=20/360,u=45/360,h=o.length;for(let x=0;x<h;x++){const f=o[x],g=f&255,v=f>>8&255,I=f>>16&255,m=f>>24&255;if(m===0)continue;const[b,T,k]=on(g,v,I);if(T<.08||b<s||b>u)continue;const E=i,L=Math.min(T,.05),[S,A,j]=wt(E,L,k);o[x]=m<<24|j<<16|A<<8|S}return a.putImageData(r,0,0),F.toDataURL("image/png")}const he=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:me&&me.tagName.toUpperCase()==="SCRIPT"&&me.src||new URL("index.cjs",document.baseURI).href}<"u"&&"/"||"/",V={background:`${he}templates/background.webp`,frontFrame:`${he}templates/front_frame.webp`,backFrame:`${he}templates/back_frame.webp`},fe={1:`${he}templates/1.png`,5:`${he}templates/5.png`,10:`${he}templates/10.png`},vt={de:{banner:{1:"EINE STUNDE",5:"FÜNF STUNDEN",10:"ZEHN STUNDEN"}},en:{banner:{1:"ONE HOUR",5:"FIVE HOURS",10:"TEN HOURS"}}},ae=3633,re=1920,De=.5,ln=Math.round(ae*De),un=Math.round(re*De),kt=320,It=335,X={badges:{topLeft:{x:286,y:235},topRight:{x:3340,y:230},bottomLeft:{x:282,y:1665},bottomRight:{x:3345,y:1665}},banner:{centerX:1816,centerY:3820,radius:3610,fontSize:103,color:"#2a3a2a"}},Re=new Map,se=new Map,qe=new Map,Ke=new Map,Fe=new Map;function Tt(e,t,n,a,r,l,o){e.save(),e.font=`900 ${l}px "Times New Roman", Georgia, serif`,e.fillStyle=o,e.textAlign="center",e.textBaseline="middle";const s=e.measureText(t).width/r,u=-Math.PI/2-s/2,h=t.split(""),x=[];for(const g of h)x.push(e.measureText(g).width);let f=u;for(let g=0;g<h.length;g++){const v=h[g],I=x[g],m=f+I/2/r,b=n+r*Math.cos(m),T=a+r*Math.sin(m);e.save(),e.translate(b,T),e.rotate(m+Math.PI/2),e.fillText(v,0,0),e.restore(),f+=I/r}e.restore()}let _={background:null,frontFrame:null,backFrame:null,badges:{1:null,5:null,10:null}};async function dn(){const[e,t,n,a,r,l]=await Promise.all([C(V.background),C(V.frontFrame),C(V.backFrame),C(fe[1]),C(fe[5]),C(fe[10])]);_={background:e,frontFrame:t,backFrame:n,badges:{1:a,5:r,10:l}}}function gn(e,t){const n=Math.round(ae*e),a=Math.round(re*e),r=document.createElement("canvas");r.width=n,r.height=a;const l=r.getContext("2d");if(!l)throw new Error("Failed to get canvas context");l.drawImage(t,0,0,n,a);const o=e<1?.8:.95;return r.toDataURL("image/jpeg",o)}function mn(e,t){const n=Math.round(ae*e),a=Math.round(re*e),r=document.createElement("canvas");r.width=n,r.height=a;const l=r.getContext("2d");if(!l)throw new Error("Failed to get canvas context");const o=kt*e,i=It*e,s=X.badges,u=(h,x)=>{const f=x/2,g=h.x*e-f,v=h.y*e-f;l.drawImage(t,g,v,x,x)};return u(s.topLeft,o),u(s.topRight,o),u(s.bottomLeft,i),u(s.bottomRight,i),r.toDataURL("image/png")}function Et(e,t,n,a=1){const r=vt[n].banner[t];Tt(e,r,X.banner.centerX*a,X.banner.centerY*a,X.banner.radius*a,X.banner.fontSize*a,X.banner.color)}function Pt(e,t,n,a,r,l,o){const i=Math.round(ae*a),s=Math.round(re*a),u=document.createElement("canvas");u.width=i,u.height=s;const h=u.getContext("2d");if(!h)throw new Error("Failed to get canvas context");h.drawImage(r,0,0,i,s);{const f=kt*a,g=It*a,v=X.badges,I=(m,b)=>{const T=b/2,k=m.x*a-T,E=m.y*a-T;h.drawImage(o,k,E,b,b)};I(v.topLeft,f),I(v.topRight,f),I(v.bottomLeft,g),I(v.bottomRight,g)}if(h.drawImage(l,0,0,i,s),n==="front"){const f=vt[t].banner[e];Tt(h,f,X.banner.centerX*a,X.banner.centerY*a,X.banner.radius*a,X.banner.fontSize*a,X.banner.color)}const x=a<1?.8:.95;return u.toDataURL("image/jpeg",x)}async function St(e,t,n){const a=`${e}-${t}-${n}`;if(Re.has(a))return Re.get(a);const r=_.background||await C(V.background),l=n==="front"?_.frontFrame||await C(V.frontFrame):_.backFrame||await C(V.backFrame),o=_.badges[e]||await C(fe[e]),i=Pt(e,t,n,De,r,l,o);return Re.set(a,i),i}async function Ze(e,t,n){const a=`${e}-${t}-${n}`;if(se.has(a))return se.get(a);const r=_.background||await C(V.background),l=n==="front"?_.frontFrame||await C(V.frontFrame):_.backFrame||await C(V.backFrame),o=_.badges[e]||await C(fe[e]),i=Pt(e,t,n,1,r,l,o);if(se.size>4){const s=se.keys().next().value;s&&se.delete(s)}return se.set(a,i),i}function hn(){return{width:ae,height:re}}function Lt(){Re.clear(),se.clear(),qe.clear(),Ke.clear(),Fe.clear()}async function Je(e,t,n="front",a=De){const r=`bg-${a}`;let l=qe.get(r);if(!l){const h=_.background||await C(V.background);l=gn(a,h),qe.set(r,l)}const o=`badges-${e}-${a}`;let i=Ke.get(o);if(!i){const h=_.badges[e]||await C(fe[e]);i=mn(a,h),Ke.set(o,i)}const s=`${n}-${a}`;let u=Fe.get(s);if(!u){const h=n==="front"?_.frontFrame||await C(V.frontFrame):_.backFrame||await C(V.backFrame),x=Math.round(ae*a),f=Math.round(re*a),g=document.createElement("canvas");g.width=x,g.height=f;const v=g.getContext("2d");if(!v)throw new Error("Failed to get canvas context");v.drawImage(h,0,0,x,f),u=g.toDataURL("image/png"),Fe.set(s,u)}return{background:l,badges:i,frame:u}}async function fn(){const e=[1,5,10],t=["de","en"],n=["front","back"],a=[];for(const r of e)for(const l of t)for(const o of n)a.push(St(r,l,o));await Promise.all(a)}const Be=new Map,ce=new Map;function Rt(){ce.clear(),Be.clear(),pt()}async function C(e){return Be.has(e)?Be.get(e):new Promise((t,n)=>{const a=new Image;a.crossOrigin="anonymous",a.onload=()=>{Be.set(e,a),t(a)},a.onerror=n,a.src=e})}function le(e,t,n,a){e.drawImage(t,0,0,n,a)}const pn=29,bn=5;async function Bt(e,t,n,a){if(Math.abs(t-pn)<=bn)return C(e);const r=`${e}:${t}:${n}x${a}`;if(ce.has(r))return C(ce.get(r));const l=await C(e),o=document.createElement("canvas");o.width=n,o.height=a;const i=o.getContext("2d");if(!i)throw new Error("Failed to get canvas context");i.drawImage(l,0,0,n,a);const s=o.toDataURL("image/png"),u=await yt(s,t);if(ce.size>20){const h=ce.keys().next().value;h&&ce.delete(h)}return ce.set(r,u),C(u)}function xn(e,t,n,a,r,l="de"){e.save(),e.beginPath(),e.ellipse(t,n,a,r,0,0,Math.PI*2),e.closePath(),e.setLineDash([20,10]),e.strokeStyle="rgba(100, 100, 100, 0.4)",e.lineWidth=3,e.stroke(),e.restore()}function Ct(e,t,n,a,r,l,o=1,i=0,s=0){e.save(),e.beginPath(),e.ellipse(n,a,r,l,0,0,Math.PI*2),e.closePath(),e.clip();const u=t.width/t.height,h=r/l,x=r*2,f=l*2;let g,v;u>h?(v=f,g=f*u):(g=x,v=x/u),g*=o,v*=o;const I=Math.max(0,(g-x)/2),m=Math.max(0,(v-f)/2),b=n-g/2+i*I,T=a-v/2+s*m;e.drawImage(t,b,T,g,v),e.restore()}function tt(e,t,n,a="#2a3a2a"){e.save(),e.font=`${n.fontSize}px "Times New Roman", serif`,e.textAlign=n.align||"center",e.textBaseline="middle",e.fillStyle=a,n.maxWidth?e.fillText(t,n.x,n.y,n.maxWidth):e.fillText(t,n.x,n.y),e.restore()}function Nt(e,t,n,a="#2a3a2a"){e.save(),e.font=`${n.fontSize}px "Times New Roman", serif`,e.textAlign=n.align||"center",e.textBaseline="top",e.fillStyle=a;const r=n.maxWidth||400,l=n.lineHeight||n.fontSize*1.4,o=t.split(" "),i=[];let s="";for(const x of o){const f=s?`${s} ${x}`:x;e.measureText(f).width>r&&s?(i.push(s),s=x):s=f}s&&i.push(s);const u=i.length*l;let h=n.y-u/2;for(const x of i)e.fillText(x,n.x,h),h+=l;e.restore()}function jt(e,t,n,a,r,l="#2a3a2a"){e.save(),e.font=`${r.fontSize}px "Times New Roman", serif`,e.textAlign=r.align||"center",e.textBaseline="middle",e.fillStyle=l;const o=r.lineHeight||r.fontSize*1.8,i=[t,n,a].filter(Boolean),s=(i.length-1)*o;let u=r.y-s/2;for(const h of i)h&&(e.fillText(h,r.x,u),u+=o);e.restore()}function wn(e,t,n,a="#2a3a2a"){e.save(),e.strokeStyle=a,e.lineWidth=Math.max(2,t.labelFontSize/16),e.beginPath(),e.moveTo(t.x-t.width/2,t.y),e.lineTo(t.x+t.width/2,t.y),e.stroke(),e.font=`${t.labelFontSize}px "Times New Roman", serif`,e.textAlign="center",e.textBaseline="top",e.fillStyle=a,e.fillText(n,t.x,t.y+t.labelFontSize*.3),e.restore()}async function Dt(e,t,n,a,r,l,o,i,s,u=1,h=0,x=0,f=0,g=1,v="de"){const I=e.getContext("2d");if(!I)return;const m=document.createElement("canvas");m.width=i,m.height=s;const b=m.getContext("2d");if(!b)return;b.clearRect(0,0,i,s);const T=await Bt(t,f,i,s);le(b,T,i,s);const k=await C(n);if(le(b,k,i,s),r)try{const S=await C(r);Ct(b,S,o.portrait.x,o.portrait.y,o.portrait.radiusX,o.portrait.radiusY,u,h,x)}catch(S){console.error("Failed to load portrait:",S)}else xn(b,o.portrait.x,o.portrait.y,o.portrait.radiusX,o.portrait.radiusY,v);const E=await C(a);le(b,E,i,s);const L=i/3633;Et(b,g,v,L),l&&tt(b,l,o.namePlate),e.width=i,e.height=s,I.drawImage(m,0,0)}async function At(e,t,n,a,r,l,o,i,s,u,h,x=0,f=1,g="de"){const v=e.getContext("2d");if(!v)return;const I=document.createElement("canvas");I.width=u,I.height=h;const m=I.getContext("2d");if(!m)return;m.clearRect(0,0,u,h);const b=await Bt(t,x,u,h);le(m,b,u,h);const T=await C(n);le(m,T,u,h);const k=await C(a);le(m,k,u,h);const E=u/3633;if(Et(m,f,g,E),s.contactInfo&&(r||l||o)&&jt(m,r,l,o,s.contactInfo),s.description&&i&&Nt(m,i,s.description),r&&tt(m,r,s.namePlate),s.signature){const L=g==="de"?"Unterschrift":"Signature";wn(m,s.signature,L)}e.width=u,e.height=h,v.drawImage(I,0,0)}const yn="money-generator-db",ne="zustand",vn=1;let ke=null;function nt(){return ke||(ke=new Promise((e,t)=>{if(typeof window>"u"||!window.indexedDB){t(new Error("IndexedDB not available"));return}const n=indexedDB.open(yn,vn);n.onerror=()=>{ke=null,t(n.error)},n.onsuccess=()=>{e(n.result)},n.onupgradeneeded=()=>{const a=n.result;a.objectStoreNames.contains(ne)||a.createObjectStore(ne)}}),ke)}async function kn(e){try{const t=await nt();return new Promise((n,a)=>{const o=t.transaction(ne,"readonly").objectStore(ne).get(e);o.onerror=()=>a(o.error),o.onsuccess=()=>n(o.result??null)})}catch(t){return console.error("[IndexedDB] Failed to get item:",t),null}}async function In(e,t){try{const n=await nt();return new Promise((a,r)=>{const i=n.transaction(ne,"readwrite").objectStore(ne).put(t,e);i.onerror=()=>r(i.error),i.onsuccess=()=>a()})}catch(n){console.error("[IndexedDB] Failed to set item:",n)}}async function Tn(e){try{const t=await nt();return new Promise((n,a)=>{const o=t.transaction(ne,"readwrite").objectStore(ne).delete(e);o.onerror=()=>a(o.error),o.onsuccess=()=>n()})}catch(t){console.error("[IndexedDB] Failed to remove item:",t)}}const En={getItem:kn,setItem:In,removeItem:Tn};function Pn(){return(typeof navigator<"u"?navigator.language:"de").toLowerCase().startsWith("de")?"de":"en"}const Ne=Pn(),dt={personalInfo:{name:"",email:"",phone:""},voucherConfig:{hours:1,description:"",language:Ne,templateHue:29},portrait:{original:null,enhanced:null,useEnhanced:!1,zoom:1,panX:0,panY:0,rawImage:null,bgRemovedImage:null,bgRemoved:!1,bgOpacity:0,bgBlur:0,engravingIntensity:0},currentSide:"front",isEnhancing:!1,isExporting:!1,appLanguage:Ne},y=nn.create()(lt.persist(e=>({...dt,setPersonalInfo:t=>e(n=>({personalInfo:{...n.personalInfo,...t}})),setVoucherConfig:t=>e(n=>({voucherConfig:{...n.voucherConfig,...t}})),setPortrait:(t,n=null)=>e(a=>{const r=a.portrait.original||a.portrait.rawImage;return{portrait:{...a.portrait,original:t,enhanced:n,useEnhanced:!1,zoom:r&&t?a.portrait.zoom:1,panX:r&&t?a.portrait.panX:0,panY:r&&t?a.portrait.panY:0}}}),setEnhancedPortrait:t=>e(n=>({portrait:{...n.portrait,enhanced:t,useEnhanced:t!==null}})),toggleUseEnhanced:()=>e(t=>({portrait:{...t.portrait,useEnhanced:t.portrait.enhanced?!t.portrait.useEnhanced:!1}})),setPortraitZoom:t=>e(n=>({portrait:{...n.portrait,zoom:t}})),setPortraitPan:(t,n)=>e(a=>({portrait:{...a.portrait,panX:t,panY:n}})),setPortraitRawImage:t=>e(n=>({portrait:{...n.portrait,rawImage:t}})),setPortraitBgRemoved:(t,n)=>e(a=>({portrait:{...a.portrait,bgRemoved:t,bgRemovedImage:n!==void 0?n:a.portrait.bgRemovedImage}})),setPortraitBgOpacity:t=>e(n=>({portrait:{...n.portrait,bgOpacity:t}})),setPortraitBgBlur:t=>e(n=>({portrait:{...n.portrait,bgBlur:t}})),setPortraitEngravingIntensity:t=>e(n=>({portrait:{...n.portrait,engravingIntensity:t}})),setCurrentSide:t=>e({currentSide:t}),flipSide:()=>e(t=>({currentSide:t.currentSide==="front"?"back":"front"})),setIsEnhancing:t=>e({isEnhancing:t}),setIsExporting:t=>e({isExporting:t}),setAppLanguage:t=>e({appLanguage:t}),setBillLanguage:t=>e(n=>({voucherConfig:{...n.voucherConfig,language:t}})),setHours:t=>e(n=>({voucherConfig:{...n.voucherConfig,hours:t}})),setTemplateHue:t=>(Rt(),Lt(),e(n=>({voucherConfig:{...n.voucherConfig,templateHue:t}}))),reset:()=>e(dt)}),{name:"money-generator-storage",storage:lt.createJSONStorage(()=>En),skipHydration:!0,migrate:e=>{const t=e;return t!=null&&t.voucherConfig&&(t.voucherConfig.templateHue===void 0&&(t.voucherConfig.templateHue=29),t.voucherConfig.hours=1,t.voucherConfig.language=Ne),t&&(t.appLanguage=Ne),t},version:3,partialize:e=>({personalInfo:e.personalInfo,voucherConfig:e.voucherConfig,appLanguage:e.appLanguage,portrait:{original:null,enhanced:null,useEnhanced:e.portrait.useEnhanced,zoom:e.portrait.zoom,panX:e.portrait.panX,panY:e.portrait.panY,rawImage:e.portrait.rawImage,bgRemovedImage:e.portrait.bgRemovedImage,bgRemoved:e.portrait.bgRemoved,bgOpacity:e.portrait.bgOpacity,bgBlur:e.portrait.bgBlur,engravingIntensity:e.portrait.engravingIntensity},currentSide:"front",isEnhancing:!1,isExporting:!1})}));function Sn(){typeof window<"u"&&y.persist.rehydrate()}const Ln={header:{title:"Money Generator",subtitle:"Erstelle deinen persönlichen Zeitgutschein"},form:{personalInfo:{title:"Persönliche Daten",name:"Name",namePlaceholder:"Dein Name",email:"E-Mail",emailPlaceholder:"deine@email.de",phone:"Telefon",phonePlaceholder:"+49 123 456789"},portrait:{title:"Portrait",upload:"Bild hochladen",dragDrop:"oder hierher ziehen",enhance:"Mit AI verbessern",enhancing:"Wird verbessert...",useOriginal:"Original verwenden",useEnhanced:"Verbessertes verwenden",zoom:"Zoom"},voucher:{title:"Gutschein",hours:"Stunden",hourLabel:"Stunde",hoursLabel:"Stunden",description:"Beschreibung",descriptionPlaceholder:"Was kann mit diesem Gutschein eingelöst werden?",billLanguage:"Schein-Sprache",billLanguageGerman:"Deutsch",billLanguageEnglish:"Englisch"},billColor:{title:"Scheinfarbe",label:"Farbton"}},preview:{front:"Vorderseite",back:"Rückseite",flip:"Umdrehen"},export:{button:"Als PDF herunterladen",exporting:"PDF wird erstellt...",success:"Download gestartet!"},bill:{descriptionText:"Für diesen Schein erhältst du {bannerText} meiner Zeit oder ein gleichwertiges Dankeschön.",bannerText:{1:"eine Stunde",5:"fünf Stunden",10:"zehn Stunden"}}},Rn={header:{title:"Money Generator",subtitle:"Create your personal time voucher"},form:{personalInfo:{title:"Personal Information",name:"Name",namePlaceholder:"Your name",email:"Email",emailPlaceholder:"your@email.com",phone:"Phone",phonePlaceholder:"+1 234 567890"},portrait:{title:"Portrait",upload:"Upload image",dragDrop:"or drag and drop",enhance:"Enhance with AI",enhancing:"Enhancing...",useOriginal:"Use original",useEnhanced:"Use enhanced",zoom:"Zoom"},voucher:{title:"Voucher",hours:"Hours",hourLabel:"hour",hoursLabel:"hours",description:"Description",descriptionPlaceholder:"What can be redeemed with this voucher?",billLanguage:"Bill Language",billLanguageGerman:"German",billLanguageEnglish:"English"},billColor:{title:"Bill Color",label:"Hue"}},preview:{front:"Front",back:"Back",flip:"Flip"},export:{button:"Download as PDF",exporting:"Creating PDF...",success:"Download started!"},bill:{descriptionText:"For this voucher, you will receive {bannerText} of my time or an equivalent appreciation in return.",bannerText:{1:"one hour",5:"five hours",10:"ten hours"}}},Bn={de:Ln,en:Rn};function oe(e){return Bn[e]}function at(e,t,n){if(n&&n.trim())return n;const a=oe(e),r=a.bill.bannerText[t]||a.bill.bannerText[1];return a.bill.descriptionText.replace("{bannerText}",r)}function Cn(e){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}function Nn(e){return e.replace(/\D/g,"").length>=6}function jn({focusField:e,onFocused:t,onFormFocusChange:n}={}){const a=y(m=>m.appLanguage),r=y(m=>m.personalInfo),l=y(m=>m.setPersonalInfo),o=oe(a),[i,s]=d.useState(!1),[u,h]=d.useState(!1),x=i&&r.email.trim()&&!Cn(r.email),f=u&&r.phone.trim()&&!Nn(r.phone),g=d.useRef(null),v=d.useRef(null),I=d.useRef(null);return d.useEffect(()=>{if(e){const m=e==="name"?g:e==="email"?v:I;setTimeout(()=>{var b,T;(b=m.current)==null||b.click(),(T=m.current)==null||T.focus(),setTimeout(()=>{var k;(k=m.current)==null||k.scrollIntoView({behavior:"smooth",block:"center"})},300),t==null||t()},100)}},[e,t]),c.jsxs("div",{className:"space-y-4",children:[c.jsxs("div",{className:"form-control",children:[c.jsx("label",{className:"label",children:c.jsx("span",{className:"label-text font-medium",children:o.form.personalInfo.name})}),c.jsx("input",{ref:g,type:"text",name:"name",autoComplete:"name",placeholder:o.form.personalInfo.namePlaceholder,className:"input input-bordered w-full input-md",value:r.name,onChange:m=>l({name:m.target.value}),onFocus:m=>{n==null||n(!0),setTimeout(()=>m.target.scrollIntoView({behavior:"smooth",block:"center"}),300)},onBlur:()=>n==null?void 0:n(!1)})]}),c.jsxs("div",{className:"form-control",children:[c.jsx("label",{className:"label",children:c.jsx("span",{className:"label-text font-medium",children:o.form.personalInfo.email})}),c.jsx("input",{ref:v,type:"email",name:"email",autoComplete:"email",placeholder:o.form.personalInfo.emailPlaceholder,className:`input input-bordered w-full input-md ${x?"input-error":""}`,value:r.email,onChange:m=>l({email:m.target.value}),onFocus:m=>{n==null||n(!0),setTimeout(()=>m.target.scrollIntoView({behavior:"smooth",block:"center"}),300)},onBlur:()=>{s(!0),n==null||n(!1)}}),x&&c.jsx("label",{className:"label",children:c.jsx("span",{className:"label-text-alt text-error",children:a==="de"?"Bitte gib eine gültige E-Mail-Adresse ein":"Please enter a valid email address"})})]}),c.jsxs("div",{className:"form-control",children:[c.jsx("label",{className:"label",children:c.jsx("span",{className:"label-text font-medium",children:o.form.personalInfo.phone})}),c.jsx("input",{ref:I,type:"tel",name:"phone",autoComplete:"tel",placeholder:o.form.personalInfo.phonePlaceholder,className:`input input-bordered w-full input-md ${f?"input-error":""}`,value:r.phone,onChange:m=>l({phone:m.target.value}),onFocus:m=>{n==null||n(!0),setTimeout(()=>m.target.scrollIntoView({behavior:"smooth",block:"center"}),300)},onBlur:()=>{h(!0),n==null||n(!1)}}),f&&c.jsx("label",{className:"label",children:c.jsx("span",{className:"label-text-alt text-error",children:a==="de"?"Bitte gib eine gültige Telefonnummer ein":"Please enter a valid phone number"})})]})]})}const Xe={},Dn="https://api.stability.ai/v1/generation",An="https://api.stability.ai/v2beta/stable-image/edit/remove-background",Ht="stability_api_key";let pe=null;function Hn(e){pe=e}function Mn(){return pe}function Un(){return pe!==null}const On={vintage:"portrait in the style of vintage currency engraving, fine line work, crosshatching, sepia tones, detailed stippling, classic bank note portrait style",engraved:"portrait as detailed intaglio engraving, currency bill style, fine parallel lines, high contrast, official government portrait",currency:"portrait rendered as US dollar bill engraving, official currency portrait style, green tint, fine line engraving technique"},gt=[{width:1024,height:1024},{width:1152,height:896},{width:1216,height:832},{width:1344,height:768},{width:1536,height:640},{width:640,height:1536},{width:768,height:1344},{width:832,height:1216},{width:896,height:1152}];function Yn(e,t){const n=e/t;let a=gt[0],r=1/0;for(const l of gt){const o=l.width/l.height,i=Math.abs(n-o);i<r&&(r=i,a=l)}return a}function Wn(e){return new Promise((t,n)=>{const a=new Image;a.onload=()=>{const r=Yn(a.width,a.height),l=document.createElement("canvas");l.width=r.width,l.height=r.height;const o=l.getContext("2d");if(!o){n(new Error("Failed to get canvas context"));return}const i=a.width/a.height,s=r.width/r.height;let u=0,h=0,x=a.width,f=a.height;i>s?(x=a.height*s,u=(a.width-x)/2):(f=a.width/s,h=(a.height-f)/2),o.drawImage(a,u,h,x,f,0,0,r.width,r.height),t(l.toDataURL("image/png"))},a.onerror=()=>n(new Error("Failed to load image")),a.src=e})}function Mt(e){var o;const t=e.split(","),n=((o=t[0].match(/:(.*?);/))==null?void 0:o[1])||"image/png",a=atob(t[1]),r=a.length,l=new Uint8Array(r);for(let i=0;i<r;i++)l[i]=a.charCodeAt(i);return new Blob([l],{type:n})}function Ae(){var t;const e=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:me&&me.tagName.toUpperCase()==="SCRIPT"&&me.src||new URL("index.cjs",document.baseURI).href}<"u"&&(Xe==null?void 0:Xe.VITE_STABILITY_API_KEY)||typeof process<"u"&&((t=process.env)==null?void 0:t.NEXT_PUBLIC_STABILITY_API_KEY);return e&&e!=="your-api-key-here"?e:typeof localStorage<"u"?localStorage.getItem(Ht):null}function Ut(e){localStorage.setItem(Ht,e)}function Ce(){return pe?!0:Ae()!==null}async function _n(e){const t=Ae();if(!t)throw new Error("No Stability AI API key configured");const{imageDataUrl:n,style:a,strength:r=.35}=e,l=await Wn(n),o=Mt(l),i=new FormData;i.append("init_image",o,"portrait.png"),i.append("init_image_mode","IMAGE_STRENGTH"),i.append("image_strength",String(1-r)),i.append("text_prompts[0][text]",On[a]),i.append("text_prompts[0][weight]","1"),i.append("cfg_scale","7"),i.append("samples","1"),i.append("steps","30");const u=await fetch(`${Dn}/stable-diffusion-xl-1024-v1-0/image-to-image`,{method:"POST",headers:{Authorization:`Bearer ${t}`,Accept:"application/json"},body:i});if(!u.ok){const x=await u.text();throw console.error("Stability AI error:",x),u.status===401?new Error("Invalid API key"):u.status===402?new Error("Insufficient credits"):u.status===429?new Error("Rate limit exceeded. Please try again later."):new Error(`API error: ${u.status}`)}const h=await u.json();if(!h.artifacts||h.artifacts.length===0)throw new Error("No image generated");return`data:image/png;base64,${h.artifacts[0].base64}`}async function Ot(e){if(pe){const o=await fetch(pe,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({imageDataUrl:e})});if(!o.ok){const s=await o.json().catch(()=>({}));throw new Error(s.error||`API error: ${o.status}`)}return(await o.json()).imageDataUrl}const t=Ae();if(!t)throw new Error("No Stability AI API key configured");const n=Mt(e),a=new FormData;a.append("image",n,"image.png"),a.append("output_format","png");const r=await fetch(An,{method:"POST",headers:{Authorization:`Bearer ${t}`,Accept:"image/*"},body:a});if(!r.ok){const o=await r.text();throw console.error("Stability AI remove background error:",o),r.status===401?new Error("Invalid API key"):r.status===402?new Error("Insufficient credits"):r.status===429?new Error("Rate limit exceeded. Please try again later."):new Error(`API error: ${r.status}`)}const l=await r.blob();return new Promise((o,i)=>{const s=new FileReader;s.onload=()=>o(s.result),s.onerror=()=>i(new Error("Failed to read result")),s.readAsDataURL(l)})}function zn(){const[e,t]=d.useState(!1),[n,a]=d.useState(!1),[r,l]=d.useState(null),[o,i]=d.useState(()=>Ce());d.useEffect(()=>{i(Ce());const f=setTimeout(()=>{i(Ce())},150);return()=>clearTimeout(f)},[]);const s=d.useCallback(()=>l(null),[]),u=d.useCallback(f=>{Ut(f),i(!0),l(null)},[]),h=d.useCallback(async(f,g=.5,v=40)=>{t(!0),l(null);try{return await xt(f,g,v)}catch(I){const m=I instanceof Error?I.message:"Enhancement failed";throw l(m),I}finally{t(!1)}},[]),x=d.useCallback(async f=>{a(!0),l(null);try{return await Ot(f)}catch(g){const v=g instanceof Error?g.message:"Background removal failed";throw l(v),g}finally{a(!1)}},[]);return{enhance:h,removeBg:x,isEnhancing:e,isRemovingBg:n,error:r,hasKey:o,setApiKey:u,clearError:s}}function Yt({isOpen:e,onClose:t,onSubmit:n}){const a=y(u=>u.appLanguage),[r,l]=d.useState("");if(!e)return null;const o=u=>{u.preventDefault(),r.trim()&&(n(r.trim()),l(""),t())},s={de:{title:"Stability AI API Key",description:"Um die AI-Bildverbesserung zu nutzen, benötigst du einen Stability AI API Key. Du kannst ihn auf platform.stability.ai erhalten.",placeholder:"sk-...",submit:"Speichern",cancel:"Abbrechen",hint:"Der Key wird lokal in deinem Browser gespeichert."},en:{title:"Stability AI API Key",description:"To use AI image enhancement, you need a Stability AI API key. You can get one at platform.stability.ai.",placeholder:"sk-...",submit:"Save",cancel:"Cancel",hint:"The key is stored locally in your browser."}}[a];return c.jsxs("dialog",{className:"modal modal-open",children:[c.jsxs("div",{className:"modal-box",children:[c.jsx("h3",{className:"font-bold text-lg",children:s.title}),c.jsx("p",{className:"py-4 text-sm opacity-80",children:s.description}),c.jsxs("form",{onSubmit:o,children:[c.jsxs("div",{className:"form-control",children:[c.jsx("input",{type:"password",placeholder:s.placeholder,className:"input input-bordered w-full",value:r,onChange:u=>l(u.target.value),autoFocus:!0}),c.jsx("label",{className:"label",children:c.jsx("span",{className:"label-text-alt",children:s.hint})})]}),c.jsxs("div",{className:"modal-action",children:[c.jsx("button",{type:"button",className:"btn btn-ghost",onClick:t,children:s.cancel}),c.jsx("button",{type:"submit",className:"btn btn-primary",disabled:!r.trim(),children:s.submit})]})]})]}),c.jsx("form",{method:"dialog",className:"modal-backdrop",children:c.jsx("button",{onClick:t,children:"close"})})]})}function Ie({min:e,max:t,step:n,value:a,onChange:r,className:l="",disabled:o=!1}){const i=d.useRef(null),s=d.useRef(null),u=d.useRef(!1),[h,x]=d.useState(!1),f=(a-e)/(t-e)*100,g=d.useCallback(k=>{if(!i.current)return a;const E=i.current.getBoundingClientRect(),L=Math.max(0,Math.min(1,(k-E.left)/E.width)),S=t-e,A=e+L*S,j=Math.round(A/n)*n;return Math.max(e,Math.min(t,j))},[e,t,n,a]),v=d.useCallback(k=>{if(o)return;const E=k.touches[0];s.current={x:E.clientX,y:E.clientY,value:a,decided:!1},u.current=!1},[a,o]),I=d.useCallback(k=>{if(o||!s.current)return;const E=k.touches[0],L=Math.abs(E.clientX-s.current.x),S=Math.abs(E.clientY-s.current.y);if(!s.current.decided){if(L<8&&S<8)return;if(s.current.decided=!0,S>L){s.current=null;return}u.current=!0,x(!0)}if(u.current){const A=g(E.clientX);A!==a&&r(A)}},[o,g,r,a]),m=d.useCallback(k=>{if(s.current&&!s.current.decided){const E=k.changedTouches[0];if(E){const L=g(E.clientX);L!==a&&r(L)}}s.current=null,u.current=!1,x(!1)},[g,r,a]);d.useEffect(()=>{const k=i.current;if(!k)return;const E=L=>{u.current&&L.preventDefault()};return k.addEventListener("touchmove",E,{passive:!1}),()=>{k.removeEventListener("touchmove",E)}},[]);const b=d.useCallback(k=>{if(o)return;const E=g(k.clientX);r(E),x(!0);const L=A=>{const j=g(A.clientX);r(j)},S=()=>{x(!1),document.removeEventListener("mousemove",L),document.removeEventListener("mouseup",S)};document.addEventListener("mousemove",L),document.addEventListener("mouseup",S)},[o,g,r]),T=`calc(10px + (100% - 20px) * ${f/100})`;return c.jsxs("div",{ref:i,className:`relative h-10 flex items-center cursor-pointer overflow-visible ${o?"opacity-50 cursor-not-allowed":""}`,onTouchStart:v,onTouchMove:I,onTouchEnd:m,onMouseDown:b,children:[c.jsx("div",{className:"absolute h-2 bg-base-300 rounded-full inset-x-0"}),c.jsx("div",{className:`absolute h-2 rounded-full transition-colors ${l.includes("range-primary")?"bg-primary":l.includes("range-secondary")?"bg-secondary":"bg-primary"}`,style:{left:0,width:T}}),c.jsx("div",{className:`absolute w-5 h-5 rounded-full bg-base-100 border-2 shadow-md transition-transform ${h?"scale-110":""} ${l.includes("range-primary")?"border-primary":l.includes("range-secondary")?"border-secondary":"border-primary"}`,style:{left:T,transform:"translateX(-50%)"}})]})}function $n(){const e=y(p=>p.appLanguage),t=y(p=>p.portrait),n=y(p=>p.setPortrait),a=y(p=>p.setPortraitZoom),r=y(p=>p.setPortraitPan),l=y(p=>p.setPortraitRawImage),o=y(p=>p.setPortraitBgRemoved),i=y(p=>p.setPortraitBgOpacity),s=y(p=>p.setPortraitBgBlur),u=y(p=>p.setPortraitEngravingIntensity),{enhance:h,removeBg:x,isEnhancing:f,isRemovingBg:g,error:v,hasKey:I,setApiKey:m}=zn(),b=oe(e),T=d.useRef(null),[k,E]=d.useState(!1),[L,S]=d.useState(!1),A=d.useRef(null),j=d.useRef(null),R=t.rawImage,B=t.bgRemovedImage,Y=t.bgRemoved,Z=t.bgOpacity,H=t.bgBlur,O=t.engravingIntensity;d.useEffect(()=>{t.original&&!t.rawImage&&l(t.original)},[t.original,t.rawImage,l]),d.useEffect(()=>()=>{A.current&&clearTimeout(A.current),j.current&&clearTimeout(j.current)},[]);const J=y(p=>p.voucherConfig.templateHue),ie=d.useRef(J),Q=d.useCallback(async p=>{if(!p.type.startsWith("image/"))return;const P=new FileReader;P.onload=async M=>{var W;const D=(W=M.target)==null?void 0:W.result,z=await bt(D);pt(),l(z),n(z),a(1),r(0,0),o(!1,null),i(0),s(0),u(0)},P.readAsDataURL(p)},[n,l,a,r,o,i,s,u]),be=d.useCallback(p=>{p.preventDefault(),E(!1);const P=p.dataTransfer.files[0];P&&Q(P)},[Q]),G=d.useCallback(p=>{p.preventDefault(),E(!0)},[]),ee=d.useCallback(p=>{p.preventDefault(),E(!1)},[]),K=()=>{var p;(p=T.current)==null||p.click()},xe=p=>{var M;const P=(M=p.target.files)==null?void 0:M[0];P&&Q(P)},te=d.useCallback(async(p,P,M)=>{try{return await h(p,P,M)}catch(D){return console.error("Enhancement failed:",D),p}},[h]),Ee=d.useCallback(async p=>{try{const P=await x(p);return o(!0,P),P}catch(P){return console.error("Background removal failed:",P),p}},[x,o]),q=d.useCallback(async()=>{const p=y.getState(),P=p.portrait,M=p.voucherConfig.templateHue;if(!P.rawImage)return;let D;P.bgRemoved&&P.bgRemovedImage?D=await $e(P.bgRemovedImage,P.rawImage,P.bgOpacity,P.bgBlur):D=P.rawImage,P.engravingIntensity>0&&(D=await te(D,P.engravingIntensity,M)),n(D)},[te,n]),we=d.useRef(!1);d.useEffect(()=>{t.rawImage&&!t.original&&!we.current&&(we.current=!0,setTimeout(()=>{q()},0)),t.rawImage||(we.current=!1)},[t.rawImage,t.original,q]),d.useEffect(()=>{if(ie.current===J)return;ie.current=J;const p=y.getState().portrait;p.engravingIntensity>0&&p.rawImage&&(A.current&&clearTimeout(A.current),A.current=setTimeout(q,150))},[J,q]);const ye=async()=>{if(!R)return;if(!Y&&!I){S(!0);return}if(!Y){const P=await Ee(R),M=y.getState(),D=M.portrait,z=M.voucherConfig.templateHue;let W=await $e(P,R,D.bgOpacity,D.bgBlur);D.engravingIntensity>0&&(W=await te(W,D.engravingIntensity,z)),n(W)}else{o(!1,null);const P=y.getState(),M=P.portrait.engravingIntensity,D=P.voucherConfig.templateHue;if(M>0){const z=await te(R,M,D);n(z)}else n(R)}},Ue=p=>{u(p),A.current&&clearTimeout(A.current),R&&(A.current=setTimeout(q,150))},Pe=async p=>{if(m(p),!R)return;const P=await Ee(R),M=y.getState(),D=M.portrait,z=M.voucherConfig.templateHue;let W=await $e(P,R,D.bgOpacity,D.bgBlur);D.engravingIntensity>0&&(W=await te(W,D.engravingIntensity,z)),n(W)},Se=p=>{i(p),j.current&&clearTimeout(j.current),!(!R||!B)&&(j.current=setTimeout(q,150))},ve=p=>{s(p),j.current&&clearTimeout(j.current),!(!R||!B)&&(j.current=setTimeout(q,150))};return c.jsxs("div",{className:"space-y-4",children:[c.jsx("style",{children:`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),u=require("react"),ra=require("zustand"),lt=require("zustand/middleware"),oa=require("jspdf");var me=typeof document<"u"?document.currentScript:null;const ia=1024,de=new Map;let J=null,dt=null;function et(e,t){return J||(J=document.createElement("canvas"),dt=J.getContext("2d",{willReadFrequently:!0})),(J.width!==e||J.height!==t)&&(J.width=e,J.height=t),dt}function Ee(e){const t=de.get(e);return t?Promise.resolve(t):new Promise((a,r)=>{const n=new Image;n.onload=()=>{if(de.size>10){const c=de.keys().next().value;c&&de.delete(c)}de.set(e,n),a(n)},n.onerror=()=>r(new Error("Failed to load image")),n.src=e})}function bt(){de.clear()}async function wt(e,t=ia){const a=await Ee(e),r=Math.max(a.width,a.height);if(r<=t)return e;const n=t/r,c=Math.round(a.width*n),o=Math.round(a.height*n),s=document.createElement("canvas"),i=s.getContext("2d");if(!i)throw new Error("Failed to get canvas context");return s.width=c,s.height=o,i.drawImage(a,0,0,c,o),s.toDataURL("image/jpeg",.9)}async function ze(e,t,a,r=0){const[n,c]=await Promise.all([Ee(e),Ee(t)]),o=et(n.width,n.height);if(o.clearRect(0,0,n.width,n.height),a>0){const s=r*20;o.save(),o.globalAlpha=a,s>0&&(o.filter=`blur(${s}px)`),o.drawImage(c,0,0,n.width,n.height),o.restore()}return o.drawImage(n,0,0),J.toDataURL("image/png")}async function xt(e,t=.5,a=40){const r=await Ee(e),n=et(r.width,r.height);n.clearRect(0,0,r.width,r.height),n.drawImage(r,0,0);const c=n.getImageData(0,0,r.width,r.height),o=c.data,s=new Uint32Array(o.buffer),i=1+t*.8,d=1-t,m=a%360/360;for(let g=0;g<s.length;g++){const h=s[g],p=h&255,k=h>>8&255,E=h>>16&255,w=h>>24&255;if(w===0)continue;let P=(((77*p+150*k+29*E>>8)/255-.5)*i+.5)*255;P<0?P=0:P>255&&(P=255);const y=P/255,I=.12,[S,T,N]=yt(m,I,y),D=p*d+S*t|0,C=k*d+T*t|0,B=E*d+N*t|0;s[g]=w<<24|B<<16|C<<8|D}return n.putImageData(c,0,0),J.toDataURL("image/png")}function sa(e,t,a){e/=255,t/=255,a/=255;const r=Math.max(e,t,a),n=Math.min(e,t,a),c=(r+n)/2;let o=0,s=0;if(r!==n){const i=r-n;switch(s=c>.5?i/(2-r-n):i/(r+n),r){case e:o=((t-a)/i+(t<a?6:0))/6;break;case t:o=((a-e)/i+2)/6;break;case a:o=((e-t)/i+4)/6;break}}return[o,s,c]}function yt(e,t,a){if(t===0){const o=Math.round(a*255);return[o,o,o]}const r=(o,s,i)=>(i<0&&(i+=1),i>1&&(i-=1),i<1/6?o+(s-o)*6*i:i<1/2?s:i<2/3?o+(s-o)*(2/3-i)*6:o),n=a<.5?a*(1+t):a+t-a*t,c=2*a-n;return[Math.round(r(c,n,e+1/3)*255),Math.round(r(c,n,e)*255),Math.round(r(c,n,e-1/3)*255)]}const ca=29,la=5;async function vt(e,t){if(Math.abs(t-ca)<=la)return e;const a=await Ee(e),r=et(a.width,a.height);r.clearRect(0,0,a.width,a.height),r.drawImage(a,0,0);const n=r.getImageData(0,0,a.width,a.height),c=n.data,o=new Uint32Array(c.buffer),s=t%360/360,i=20/360,d=45/360,m=o.length;for(let g=0;g<m;g++){const h=o[g],p=h&255,k=h>>8&255,E=h>>16&255,w=h>>24&255;if(w===0)continue;const[f,P,y]=sa(p,k,E);if(P<.08||f<i||f>d)continue;const I=s,S=Math.min(P,.05),[T,N,D]=yt(I,S,y);o[g]=w<<24|D<<16|N<<8|T}return r.putImageData(n,0,0),J.toDataURL("image/png")}const he=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:me&&me.tagName.toUpperCase()==="SCRIPT"&&me.src||new URL("index.cjs",document.baseURI).href}<"u"&&"/"||"/",V={background:`${he}templates/background.webp`,frontFrame:`${he}templates/front_frame.webp`,backFrame:`${he}templates/back_frame.webp`},pe={1:`${he}templates/1.png`,5:`${he}templates/5.png`,10:`${he}templates/10.png`},kt={de:{banner:{1:"EINE STUNDE",5:"FÜNF STUNDEN",10:"ZEHN STUNDEN"}},en:{banner:{1:"ONE HOUR",5:"FIVE HOURS",10:"TEN HOURS"}}},ne=3633,re=1920,je=.5,da=Math.round(ne*je),ua=Math.round(re*je),It=320,Et=335,$={badges:{topLeft:{x:286,y:235},topRight:{x:3340,y:230},bottomLeft:{x:282,y:1665},bottomRight:{x:3345,y:1665}},banner:{centerX:1816,centerY:3820,radius:3610,fontSize:103,color:"#2a3a2a"}},Se=new Map,se=new Map,qe=new Map,Fe=new Map,Ke=new Map;function Pt(e,t,a,r,n,c,o){e.save(),e.font=`900 ${c}px "Times New Roman", Georgia, serif`,e.fillStyle=o,e.textAlign="center",e.textBaseline="middle";const i=e.measureText(t).width/n,d=-Math.PI/2-i/2,m=t.split(""),g=[];for(const p of m)g.push(e.measureText(p).width);let h=d;for(let p=0;p<m.length;p++){const k=m[p],E=g[p],w=h+E/2/n,f=a+n*Math.cos(w),P=r+n*Math.sin(w);e.save(),e.translate(f,P),e.rotate(w+Math.PI/2),e.fillText(k,0,0),e.restore(),h+=E/n}e.restore()}let Y={background:null,frontFrame:null,backFrame:null,badges:{1:null,5:null,10:null}};async function ga(){const[e,t,a,r,n,c]=await Promise.all([R(V.background),R(V.frontFrame),R(V.backFrame),R(pe[1]),R(pe[5]),R(pe[10])]);Y={background:e,frontFrame:t,backFrame:a,badges:{1:r,5:n,10:c}}}function ma(e,t){const a=Math.round(ne*e),r=Math.round(re*e),n=document.createElement("canvas");n.width=a,n.height=r;const c=n.getContext("2d");if(!c)throw new Error("Failed to get canvas context");c.drawImage(t,0,0,a,r);const o=e<1?.8:.95;return n.toDataURL("image/jpeg",o)}function ha(e,t){const a=Math.round(ne*e),r=Math.round(re*e),n=document.createElement("canvas");n.width=a,n.height=r;const c=n.getContext("2d");if(!c)throw new Error("Failed to get canvas context");const o=It*e,s=Et*e,i=$.badges,d=(m,g)=>{const h=g/2,p=m.x*e-h,k=m.y*e-h;c.drawImage(t,p,k,g,g)};return d(i.topLeft,o),d(i.topRight,o),d(i.bottomLeft,s),d(i.bottomRight,s),n.toDataURL("image/png")}function Tt(e,t,a,r=1){const n=kt[a].banner[t];Pt(e,n,$.banner.centerX*r,$.banner.centerY*r,$.banner.radius*r,$.banner.fontSize*r,$.banner.color)}function Ct(e,t,a,r,n,c,o){const s=Math.round(ne*r),i=Math.round(re*r),d=document.createElement("canvas");d.width=s,d.height=i;const m=d.getContext("2d");if(!m)throw new Error("Failed to get canvas context");m.drawImage(n,0,0,s,i);{const h=It*r,p=Et*r,k=$.badges,E=(w,f)=>{const P=f/2,y=w.x*r-P,I=w.y*r-P;m.drawImage(o,y,I,f,f)};E(k.topLeft,h),E(k.topRight,h),E(k.bottomLeft,p),E(k.bottomRight,p)}if(m.drawImage(c,0,0,s,i),a==="front"){const h=kt[t].banner[e];Pt(m,h,$.banner.centerX*r,$.banner.centerY*r,$.banner.radius*r,$.banner.fontSize*r,$.banner.color)}const g=r<1?.8:.95;return d.toDataURL("image/jpeg",g)}async function Lt(e,t,a){const r=`${e}-${t}-${a}`;if(Se.has(r))return Se.get(r);const n=Y.background||await R(V.background),c=a==="front"?Y.frontFrame||await R(V.frontFrame):Y.backFrame||await R(V.backFrame),o=Y.badges[e]||await R(pe[e]),s=Ct(e,t,a,je,n,c,o);return Se.set(r,s),s}async function Ze(e,t,a){const r=`${e}-${t}-${a}`;if(se.has(r))return se.get(r);const n=Y.background||await R(V.background),c=a==="front"?Y.frontFrame||await R(V.frontFrame):Y.backFrame||await R(V.backFrame),o=Y.badges[e]||await R(pe[e]),s=Ct(e,t,a,1,n,c,o);if(se.size>4){const i=se.keys().next().value;i&&se.delete(i)}return se.set(r,s),s}function pa(){return{width:ne,height:re}}function St(){Se.clear(),se.clear(),qe.clear(),Fe.clear(),Ke.clear()}async function Je(e,t,a="front",r=je){const n=`bg-${r}`;let c=qe.get(n);if(!c){const m=Y.background||await R(V.background);c=ma(r,m),qe.set(n,c)}const o=`badges-${e}-${r}`;let s=Fe.get(o);if(!s){const m=Y.badges[e]||await R(pe[e]);s=ha(r,m),Fe.set(o,s)}const i=`${a}-${r}`;let d=Ke.get(i);if(!d){const m=a==="front"?Y.frontFrame||await R(V.frontFrame):Y.backFrame||await R(V.backFrame),g=Math.round(ne*r),h=Math.round(re*r),p=document.createElement("canvas");p.width=g,p.height=h;const k=p.getContext("2d");if(!k)throw new Error("Failed to get canvas context");k.drawImage(m,0,0,g,h),d=p.toDataURL("image/png"),Ke.set(i,d)}return{background:c,badges:s,frame:d}}async function fa(){const e=[1,5,10],t=["de","en"],a=["front","back"],r=[];for(const n of e)for(const c of t)for(const o of a)r.push(Lt(n,c,o));await Promise.all(r)}const Be=new Map,ce=new Map;function Bt(){ce.clear(),Be.clear(),bt()}async function R(e){return Be.has(e)?Be.get(e):new Promise((t,a)=>{const r=new Image;r.crossOrigin="anonymous",r.onload=()=>{Be.set(e,r),t(r)},r.onerror=a,r.src=e})}function le(e,t,a,r){e.drawImage(t,0,0,a,r)}const ba=29,wa=5;async function Rt(e,t,a,r){if(Math.abs(t-ba)<=wa)return R(e);const n=`${e}:${t}:${a}x${r}`;if(ce.has(n))return R(ce.get(n));const c=await R(e),o=document.createElement("canvas");o.width=a,o.height=r;const s=o.getContext("2d");if(!s)throw new Error("Failed to get canvas context");s.drawImage(c,0,0,a,r);const i=o.toDataURL("image/png"),d=await vt(i,t);if(ce.size>20){const m=ce.keys().next().value;m&&ce.delete(m)}return ce.set(n,d),R(d)}function xa(e,t,a,r,n,c="de"){e.save(),e.beginPath(),e.ellipse(t,a,r,n,0,0,Math.PI*2),e.closePath(),e.setLineDash([20,10]),e.strokeStyle="rgba(100, 100, 100, 0.4)",e.lineWidth=3,e.stroke(),e.restore()}function Dt(e,t,a,r,n,c=1,o=0,s=0){e.save();const i=document.createElement("canvas");i.width=n,i.height=n;const d=i.getContext("2d");if(!d){e.restore();return}const m=t.width/t.height;let g,h;m>1?(h=n,g=n*m):(g=n,h=n/m),g*=c,h*=c;const p=Math.max(0,(g-n)/2),k=Math.max(0,(h-n)/2),E=(n-g)/2+o*p,w=(n-h)/2+s*k;d.filter="grayscale(70%) brightness(1.4) contrast(0.6)",d.drawImage(t,E,w,g,h),d.filter="none",d.globalCompositeOperation="destination-in";const f=d.createRadialGradient(n/2,n/2,0,n/2,n/2,n/2);f.addColorStop(0,"rgba(0,0,0,1)"),f.addColorStop(.5,"rgba(0,0,0,0.8)"),f.addColorStop(.8,"rgba(0,0,0,0.3)"),f.addColorStop(1,"rgba(0,0,0,0)"),d.fillStyle=f,d.fillRect(0,0,n,n),e.globalAlpha=.18,e.drawImage(i,a-n/2,r-n/2),e.globalAlpha=1,e.restore()}function Nt(e,t,a,r,n,c,o=1,s=0,i=0){e.save(),e.beginPath(),e.ellipse(a,r,n,c,0,0,Math.PI*2),e.closePath(),e.clip();const d=t.width/t.height,m=n/c,g=n*2,h=c*2;let p,k;d>m?(k=h,p=h*d):(p=g,k=g/d),p*=o,k*=o;const E=Math.max(0,(p-g)/2),w=Math.max(0,(k-h)/2),f=a-p/2+s*E,P=r-k/2+i*w;e.drawImage(t,f,P,p,k),e.restore()}function tt(e,t,a,r="#2a3a2a"){e.save(),e.font=`${a.fontSize}px "Times New Roman", serif`,e.textAlign=a.align||"center",e.textBaseline="middle",e.fillStyle=r,a.maxWidth?e.fillText(t,a.x,a.y,a.maxWidth):e.fillText(t,a.x,a.y),e.restore()}function jt(e,t,a,r="#2a3a2a"){e.save(),e.font=`${a.fontSize}px "Times New Roman", serif`,e.textAlign=a.align||"center",e.textBaseline="top",e.fillStyle=r;const n=a.maxWidth||400,c=a.lineHeight||a.fontSize*1.4,o=t.split(" "),s=[];let i="";for(const g of o){const h=i?`${i} ${g}`:g;e.measureText(h).width>n&&i?(s.push(i),i=g):i=h}i&&s.push(i);const d=s.length*c;let m=a.y-d/2;for(const g of s)e.fillText(g,a.x,m),m+=c;e.restore()}function Ht(e,t,a,r,n,c="#2a3a2a"){e.save(),e.font=`${n.fontSize}px "Times New Roman", serif`,e.textAlign=n.align||"center",e.textBaseline="middle",e.fillStyle=c;const o=n.lineHeight||n.fontSize*1.8,s=[t,a,r].filter(Boolean),i=(s.length-1)*o;let d=n.y-i/2;for(const m of s)m&&(e.fillText(m,n.x,d),d+=o);e.restore()}function ya(e,t,a,r="#2a3a2a"){e.save(),e.strokeStyle=r,e.lineWidth=Math.max(2,t.labelFontSize/16),e.beginPath(),e.moveTo(t.x-t.width/2,t.y),e.lineTo(t.x+t.width/2,t.y),e.stroke(),e.font=`${t.labelFontSize}px "Times New Roman", serif`,e.textAlign="center",e.textBaseline="top",e.fillStyle=r,e.fillText(a,t.x,t.y+t.labelFontSize*.3),e.restore()}async function At(e,t,a,r,n,c,o,s,i,d=1,m=0,g=0,h=0,p=1,k="de"){const E=e.getContext("2d");if(!E)return;const w=document.createElement("canvas");w.width=s,w.height=i;const f=w.getContext("2d");if(!f)return;f.clearRect(0,0,s,i);const P=await Rt(t,h,s,i);if(le(f,P,s,i),n)try{const T=await R(n),N=i*.6,D=s*.78+70,C=i*.5;Dt(f,T,D,C,N,d,m,g)}catch(T){console.error("Failed to draw watermark:",T)}const y=await R(a);if(le(f,y,s,i),n)try{const T=await R(n);Nt(f,T,o.portrait.x,o.portrait.y,o.portrait.radiusX,o.portrait.radiusY,d,m,g)}catch(T){console.error("Failed to load portrait:",T)}else xa(f,o.portrait.x,o.portrait.y,o.portrait.radiusX,o.portrait.radiusY,k);const I=await R(r);le(f,I,s,i);const S=s/3633;Tt(f,p,k,S),c&&tt(f,c,o.namePlate),e.width=s,e.height=i,E.drawImage(w,0,0)}async function Mt(e,t,a,r,n,c,o,s,i,d,m,g,h=1,p=0,k=0,E=0,w=1,f="de"){const P=e.getContext("2d");if(!P)return;const y=document.createElement("canvas");y.width=m,y.height=g;const I=y.getContext("2d");if(!I)return;I.clearRect(0,0,m,g);const S=await Rt(t,E,m,g);if(le(I,S,m,g),n)try{const C=await R(n),B=g*.6,_=m*.5,G=g*.5;Dt(I,C,_,G,B,h,p,k)}catch(C){console.error("Failed to draw watermark:",C)}const T=await R(a);le(I,T,m,g);const N=await R(r);le(I,N,m,g);const D=m/3633;if(Tt(I,w,f,D),d.contactInfo&&(c||o||s)&&Ht(I,c,o,s,d.contactInfo),d.description&&i&&jt(I,i,d.description),c&&tt(I,c,d.namePlate),d.signature){const C=f==="de"?"Unterschrift":"Signature";ya(I,d.signature,C)}e.width=m,e.height=g,P.drawImage(y,0,0)}const va="money-generator-db",ae="zustand",ka=1;let ke=null;function at(){return ke||(ke=new Promise((e,t)=>{if(typeof window>"u"||!window.indexedDB){t(new Error("IndexedDB not available"));return}const a=indexedDB.open(va,ka);a.onerror=()=>{ke=null,t(a.error)},a.onsuccess=()=>{e(a.result)},a.onupgradeneeded=()=>{const r=a.result;r.objectStoreNames.contains(ae)||r.createObjectStore(ae)}}),ke)}async function Ia(e){try{const t=await at();return new Promise((a,r)=>{const o=t.transaction(ae,"readonly").objectStore(ae).get(e);o.onerror=()=>r(o.error),o.onsuccess=()=>a(o.result??null)})}catch(t){return console.error("[IndexedDB] Failed to get item:",t),null}}async function Ea(e,t){try{const a=await at();return new Promise((r,n)=>{const s=a.transaction(ae,"readwrite").objectStore(ae).put(t,e);s.onerror=()=>n(s.error),s.onsuccess=()=>r()})}catch(a){console.error("[IndexedDB] Failed to set item:",a)}}async function Pa(e){try{const t=await at();return new Promise((a,r)=>{const o=t.transaction(ae,"readwrite").objectStore(ae).delete(e);o.onerror=()=>r(o.error),o.onsuccess=()=>a()})}catch(t){console.error("[IndexedDB] Failed to remove item:",t)}}const Ta={getItem:Ia,setItem:Ea,removeItem:Pa};function Ca(){return(typeof navigator<"u"?navigator.language:"de").toLowerCase().startsWith("de")?"de":"en"}const De=Ca(),ut={personalInfo:{name:"",email:"",phone:""},voucherConfig:{hours:1,description:"",language:De,templateHue:29},portrait:{original:null,enhanced:null,useEnhanced:!1,zoom:1,panX:0,panY:0,rawImage:null,bgRemovedImage:null,bgRemoved:!1,bgOpacity:0,bgBlur:0,engravingIntensity:0},currentSide:"front",isEnhancing:!1,isExporting:!1,appLanguage:De},v=ra.create()(lt.persist(e=>({...ut,setPersonalInfo:t=>e(a=>({personalInfo:{...a.personalInfo,...t}})),setVoucherConfig:t=>e(a=>({voucherConfig:{...a.voucherConfig,...t}})),setPortrait:(t,a=null)=>e(r=>{const n=r.portrait.original||r.portrait.rawImage;return{portrait:{...r.portrait,original:t,enhanced:a,useEnhanced:!1,zoom:n&&t?r.portrait.zoom:1,panX:n&&t?r.portrait.panX:0,panY:n&&t?r.portrait.panY:0}}}),setEnhancedPortrait:t=>e(a=>({portrait:{...a.portrait,enhanced:t,useEnhanced:t!==null}})),toggleUseEnhanced:()=>e(t=>({portrait:{...t.portrait,useEnhanced:t.portrait.enhanced?!t.portrait.useEnhanced:!1}})),setPortraitZoom:t=>e(a=>({portrait:{...a.portrait,zoom:t}})),setPortraitPan:(t,a)=>e(r=>({portrait:{...r.portrait,panX:t,panY:a}})),setPortraitRawImage:t=>e(a=>({portrait:{...a.portrait,rawImage:t}})),setPortraitBgRemoved:(t,a)=>e(r=>({portrait:{...r.portrait,bgRemoved:t,bgRemovedImage:a!==void 0?a:r.portrait.bgRemovedImage}})),setPortraitBgOpacity:t=>e(a=>({portrait:{...a.portrait,bgOpacity:t}})),setPortraitBgBlur:t=>e(a=>({portrait:{...a.portrait,bgBlur:t}})),setPortraitEngravingIntensity:t=>e(a=>({portrait:{...a.portrait,engravingIntensity:t}})),setCurrentSide:t=>e({currentSide:t}),flipSide:()=>e(t=>({currentSide:t.currentSide==="front"?"back":"front"})),setIsEnhancing:t=>e({isEnhancing:t}),setIsExporting:t=>e({isExporting:t}),setAppLanguage:t=>e({appLanguage:t}),setBillLanguage:t=>e(a=>({voucherConfig:{...a.voucherConfig,language:t}})),setHours:t=>e(a=>({voucherConfig:{...a.voucherConfig,hours:t}})),setTemplateHue:t=>(Bt(),St(),e(a=>({voucherConfig:{...a.voucherConfig,templateHue:t}}))),reset:()=>e(ut)}),{name:"money-generator-storage",storage:lt.createJSONStorage(()=>Ta),skipHydration:!0,migrate:e=>{const t=e;return t!=null&&t.voucherConfig&&(t.voucherConfig.templateHue===void 0&&(t.voucherConfig.templateHue=29),t.voucherConfig.hours=1,t.voucherConfig.language=De),t&&(t.appLanguage=De),t},version:3,partialize:e=>({personalInfo:e.personalInfo,voucherConfig:e.voucherConfig,appLanguage:e.appLanguage,portrait:{original:null,enhanced:null,useEnhanced:e.portrait.useEnhanced,zoom:e.portrait.zoom,panX:e.portrait.panX,panY:e.portrait.panY,rawImage:e.portrait.rawImage,bgRemovedImage:e.portrait.bgRemovedImage,bgRemoved:e.portrait.bgRemoved,bgOpacity:e.portrait.bgOpacity,bgBlur:e.portrait.bgBlur,engravingIntensity:e.portrait.engravingIntensity},currentSide:"front",isEnhancing:!1,isExporting:!1})}));function La(){typeof window<"u"&&v.persist.rehydrate()}const Sa={header:{title:"Money Generator",subtitle:"Erstelle deinen persönlichen Zeitgutschein"},form:{personalInfo:{title:"Persönliche Daten",name:"Name",namePlaceholder:"Dein Name",email:"E-Mail",emailPlaceholder:"deine@email.de",phone:"Telefon",phonePlaceholder:"+49 123 456789"},portrait:{title:"Portrait",upload:"Bild hochladen",dragDrop:"oder hierher ziehen",enhance:"Mit AI verbessern",enhancing:"Wird verbessert...",useOriginal:"Original verwenden",useEnhanced:"Verbessertes verwenden",zoom:"Zoom"},voucher:{title:"Gutschein",hours:"Stunden",hourLabel:"Stunde",hoursLabel:"Stunden",description:"Beschreibung",descriptionPlaceholder:"Was kann mit diesem Gutschein eingelöst werden?",billLanguage:"Schein-Sprache",billLanguageGerman:"Deutsch",billLanguageEnglish:"Englisch"},billColor:{title:"Scheinfarbe",label:"Farbton"}},preview:{front:"Vorderseite",back:"Rückseite",flip:"Umdrehen"},export:{button:"Als PDF herunterladen",exporting:"PDF wird erstellt...",success:"Download gestartet!"},bill:{descriptionText:"Für diesen Schein erhältst du {bannerText} meiner Zeit oder ein gleichwertiges Dankeschön.",bannerText:{1:"eine Stunde",5:"fünf Stunden",10:"zehn Stunden"}}},Ba={header:{title:"Money Generator",subtitle:"Create your personal time voucher"},form:{personalInfo:{title:"Personal Information",name:"Name",namePlaceholder:"Your name",email:"Email",emailPlaceholder:"your@email.com",phone:"Phone",phonePlaceholder:"+1 234 567890"},portrait:{title:"Portrait",upload:"Upload image",dragDrop:"or drag and drop",enhance:"Enhance with AI",enhancing:"Enhancing...",useOriginal:"Use original",useEnhanced:"Use enhanced",zoom:"Zoom"},voucher:{title:"Voucher",hours:"Hours",hourLabel:"hour",hoursLabel:"hours",description:"Description",descriptionPlaceholder:"What can be redeemed with this voucher?",billLanguage:"Bill Language",billLanguageGerman:"German",billLanguageEnglish:"English"},billColor:{title:"Bill Color",label:"Hue"}},preview:{front:"Front",back:"Back",flip:"Flip"},export:{button:"Download as PDF",exporting:"Creating PDF...",success:"Download started!"},bill:{descriptionText:"For this voucher, you will receive {bannerText} of my time or an equivalent appreciation in return.",bannerText:{1:"one hour",5:"five hours",10:"ten hours"}}},Ra={de:Sa,en:Ba};function oe(e){return Ra[e]}function nt(e,t,a){if(a&&a.trim())return a;const r=oe(e),n=r.bill.bannerText[t]||r.bill.bannerText[1];return r.bill.descriptionText.replace("{bannerText}",n)}function Da(e){return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)}function Na(e){return e.replace(/\D/g,"").length>=6}function ja({focusField:e,onFocused:t,onFormFocusChange:a}={}){const r=v(w=>w.appLanguage),n=v(w=>w.personalInfo),c=v(w=>w.setPersonalInfo),o=oe(r),[s,i]=u.useState(!1),[d,m]=u.useState(!1),g=s&&n.email.trim()&&!Da(n.email),h=d&&n.phone.trim()&&!Na(n.phone),p=u.useRef(null),k=u.useRef(null),E=u.useRef(null);return u.useEffect(()=>{if(e){const w=e==="name"?p:e==="email"?k:E;setTimeout(()=>{var f,P;(f=w.current)==null||f.click(),(P=w.current)==null||P.focus(),setTimeout(()=>{var y;(y=w.current)==null||y.scrollIntoView({behavior:"smooth",block:"center"})},300),t==null||t()},100)}},[e,t]),l.jsxs("div",{className:"space-y-4",children:[l.jsxs("div",{className:"form-control",children:[l.jsx("label",{className:"label",children:l.jsx("span",{className:"label-text font-medium",children:o.form.personalInfo.name})}),l.jsx("input",{ref:p,type:"text",name:"name",autoComplete:"name",placeholder:o.form.personalInfo.namePlaceholder,className:"input input-bordered w-full input-md",value:n.name,onChange:w=>c({name:w.target.value}),onFocus:w=>{a==null||a(!0),setTimeout(()=>w.target.scrollIntoView({behavior:"smooth",block:"center"}),300)},onBlur:()=>a==null?void 0:a(!1)})]}),l.jsxs("div",{className:"form-control",children:[l.jsx("label",{className:"label",children:l.jsx("span",{className:"label-text font-medium",children:o.form.personalInfo.email})}),l.jsx("input",{ref:k,type:"email",name:"email",autoComplete:"email",placeholder:o.form.personalInfo.emailPlaceholder,className:`input input-bordered w-full input-md ${g?"input-error":""}`,value:n.email,onChange:w=>c({email:w.target.value}),onFocus:w=>{a==null||a(!0),setTimeout(()=>w.target.scrollIntoView({behavior:"smooth",block:"center"}),300)},onBlur:()=>{i(!0),a==null||a(!1)}}),g&&l.jsx("label",{className:"label",children:l.jsx("span",{className:"label-text-alt text-error",children:r==="de"?"Bitte gib eine gültige E-Mail-Adresse ein":"Please enter a valid email address"})})]}),l.jsxs("div",{className:"form-control",children:[l.jsx("label",{className:"label",children:l.jsx("span",{className:"label-text font-medium",children:o.form.personalInfo.phone})}),l.jsx("input",{ref:E,type:"tel",name:"phone",autoComplete:"tel",placeholder:o.form.personalInfo.phonePlaceholder,className:`input input-bordered w-full input-md ${h?"input-error":""}`,value:n.phone,onChange:w=>c({phone:w.target.value}),onFocus:w=>{a==null||a(!0),setTimeout(()=>w.target.scrollIntoView({behavior:"smooth",block:"center"}),300)},onBlur:()=>{m(!0),a==null||a(!1)}}),h&&l.jsx("label",{className:"label",children:l.jsx("span",{className:"label-text-alt text-error",children:r==="de"?"Bitte gib eine gültige Telefonnummer ein":"Please enter a valid phone number"})})]})]})}const $e={},Ha="https://api.stability.ai/v1/generation",Aa="https://api.stability.ai/v2beta/stable-image/edit/remove-background",Ut="stability_api_key";let fe=null;function Ma(e){fe=e}function Ua(){return fe}function _a(){return fe!==null}const Xa={vintage:"portrait in the style of vintage currency engraving, fine line work, crosshatching, sepia tones, detailed stippling, classic bank note portrait style",engraved:"portrait as detailed intaglio engraving, currency bill style, fine parallel lines, high contrast, official government portrait",currency:"portrait rendered as US dollar bill engraving, official currency portrait style, green tint, fine line engraving technique"},gt=[{width:1024,height:1024},{width:1152,height:896},{width:1216,height:832},{width:1344,height:768},{width:1536,height:640},{width:640,height:1536},{width:768,height:1344},{width:832,height:1216},{width:896,height:1152}];function Wa(e,t){const a=e/t;let r=gt[0],n=1/0;for(const c of gt){const o=c.width/c.height,s=Math.abs(a-o);s<n&&(n=s,r=c)}return r}function Ya(e){return new Promise((t,a)=>{const r=new Image;r.onload=()=>{const n=Wa(r.width,r.height),c=document.createElement("canvas");c.width=n.width,c.height=n.height;const o=c.getContext("2d");if(!o){a(new Error("Failed to get canvas context"));return}const s=r.width/r.height,i=n.width/n.height;let d=0,m=0,g=r.width,h=r.height;s>i?(g=r.height*i,d=(r.width-g)/2):(h=r.width/i,m=(r.height-h)/2),o.drawImage(r,d,m,g,h,0,0,n.width,n.height),t(c.toDataURL("image/png"))},r.onerror=()=>a(new Error("Failed to load image")),r.src=e})}function _t(e){var o;const t=e.split(","),a=((o=t[0].match(/:(.*?);/))==null?void 0:o[1])||"image/png",r=atob(t[1]),n=r.length,c=new Uint8Array(n);for(let s=0;s<n;s++)c[s]=r.charCodeAt(s);return new Blob([c],{type:a})}function He(){var t;const e=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:me&&me.tagName.toUpperCase()==="SCRIPT"&&me.src||new URL("index.cjs",document.baseURI).href}<"u"&&($e==null?void 0:$e.VITE_STABILITY_API_KEY)||typeof process<"u"&&((t=process.env)==null?void 0:t.NEXT_PUBLIC_STABILITY_API_KEY);return e&&e!=="your-api-key-here"?e:typeof localStorage<"u"?localStorage.getItem(Ut):null}function Xt(e){localStorage.setItem(Ut,e)}function Re(){return fe?!0:He()!==null}async function Oa(e){const t=He();if(!t)throw new Error("No Stability AI API key configured");const{imageDataUrl:a,style:r,strength:n=.35}=e,c=await Ya(a),o=_t(c),s=new FormData;s.append("init_image",o,"portrait.png"),s.append("init_image_mode","IMAGE_STRENGTH"),s.append("image_strength",String(1-n)),s.append("text_prompts[0][text]",Xa[r]),s.append("text_prompts[0][weight]","1"),s.append("cfg_scale","7"),s.append("samples","1"),s.append("steps","30");const d=await fetch(`${Ha}/stable-diffusion-xl-1024-v1-0/image-to-image`,{method:"POST",headers:{Authorization:`Bearer ${t}`,Accept:"application/json"},body:s});if(!d.ok){const g=await d.text();throw console.error("Stability AI error:",g),d.status===401?new Error("Invalid API key"):d.status===402?new Error("Insufficient credits"):d.status===429?new Error("Rate limit exceeded. Please try again later."):new Error(`API error: ${d.status}`)}const m=await d.json();if(!m.artifacts||m.artifacts.length===0)throw new Error("No image generated");return`data:image/png;base64,${m.artifacts[0].base64}`}async function Wt(e){if(fe){const o=await fetch(fe,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({imageDataUrl:e})});if(!o.ok){const i=await o.json().catch(()=>({}));throw new Error(i.error||`API error: ${o.status}`)}return(await o.json()).imageDataUrl}const t=He();if(!t)throw new Error("No Stability AI API key configured");const a=_t(e),r=new FormData;r.append("image",a,"image.png"),r.append("output_format","png");const n=await fetch(Aa,{method:"POST",headers:{Authorization:`Bearer ${t}`,Accept:"image/*"},body:r});if(!n.ok){const o=await n.text();throw console.error("Stability AI remove background error:",o),n.status===401?new Error("Invalid API key"):n.status===402?new Error("Insufficient credits"):n.status===429?new Error("Rate limit exceeded. Please try again later."):new Error(`API error: ${n.status}`)}const c=await n.blob();return new Promise((o,s)=>{const i=new FileReader;i.onload=()=>o(i.result),i.onerror=()=>s(new Error("Failed to read result")),i.readAsDataURL(c)})}function za(){const[e,t]=u.useState(!1),[a,r]=u.useState(!1),[n,c]=u.useState(null),[o,s]=u.useState(()=>Re());u.useEffect(()=>{s(Re());const h=setTimeout(()=>{s(Re())},150);return()=>clearTimeout(h)},[]);const i=u.useCallback(()=>c(null),[]),d=u.useCallback(h=>{Xt(h),s(!0),c(null)},[]),m=u.useCallback(async(h,p=.5,k=40)=>{t(!0),c(null);try{return await xt(h,p,k)}catch(E){const w=E instanceof Error?E.message:"Enhancement failed";throw c(w),E}finally{t(!1)}},[]),g=u.useCallback(async h=>{r(!0),c(null);try{return await Wt(h)}catch(p){const k=p instanceof Error?p.message:"Background removal failed";throw c(k),p}finally{r(!1)}},[]);return{enhance:m,removeBg:g,isEnhancing:e,isRemovingBg:a,error:n,hasKey:o,setApiKey:d,clearError:i}}function Yt({isOpen:e,onClose:t,onSubmit:a}){const r=v(d=>d.appLanguage),[n,c]=u.useState("");if(!e)return null;const o=d=>{d.preventDefault(),n.trim()&&(a(n.trim()),c(""),t())},i={de:{title:"Stability AI API Key",description:"Um die AI-Bildverbesserung zu nutzen, benötigst du einen Stability AI API Key. Du kannst ihn auf platform.stability.ai erhalten.",placeholder:"sk-...",submit:"Speichern",cancel:"Abbrechen",hint:"Der Key wird lokal in deinem Browser gespeichert."},en:{title:"Stability AI API Key",description:"To use AI image enhancement, you need a Stability AI API key. You can get one at platform.stability.ai.",placeholder:"sk-...",submit:"Save",cancel:"Cancel",hint:"The key is stored locally in your browser."}}[r];return l.jsxs("dialog",{className:"modal modal-open",children:[l.jsxs("div",{className:"modal-box",children:[l.jsx("h3",{className:"font-bold text-lg",children:i.title}),l.jsx("p",{className:"py-4 text-sm opacity-80",children:i.description}),l.jsxs("form",{onSubmit:o,children:[l.jsxs("div",{className:"form-control",children:[l.jsx("input",{type:"password",placeholder:i.placeholder,className:"input input-bordered w-full",value:n,onChange:d=>c(d.target.value),autoFocus:!0}),l.jsx("label",{className:"label",children:l.jsx("span",{className:"label-text-alt",children:i.hint})})]}),l.jsxs("div",{className:"modal-action",children:[l.jsx("button",{type:"button",className:"btn btn-ghost",onClick:t,children:i.cancel}),l.jsx("button",{type:"submit",className:"btn btn-primary",disabled:!n.trim(),children:i.submit})]})]})]}),l.jsx("form",{method:"dialog",className:"modal-backdrop",children:l.jsx("button",{onClick:t,children:"close"})})]})}function Ie({min:e,max:t,step:a,value:r,onChange:n,className:c="",disabled:o=!1}){const s=u.useRef(null),i=u.useRef(null),d=u.useRef(!1),[m,g]=u.useState(!1),h=(r-e)/(t-e)*100,p=u.useCallback(y=>{if(!s.current)return r;const I=s.current.getBoundingClientRect(),S=Math.max(0,Math.min(1,(y-I.left)/I.width)),T=t-e,N=e+S*T,D=Math.round(N/a)*a;return Math.max(e,Math.min(t,D))},[e,t,a,r]),k=u.useCallback(y=>{if(o)return;const I=y.touches[0];i.current={x:I.clientX,y:I.clientY,value:r,decided:!1},d.current=!1},[r,o]),E=u.useCallback(y=>{if(o||!i.current)return;const I=y.touches[0],S=Math.abs(I.clientX-i.current.x),T=Math.abs(I.clientY-i.current.y);if(!i.current.decided){if(S<8&&T<8)return;if(i.current.decided=!0,T>S){i.current=null;return}d.current=!0,g(!0)}if(d.current){const N=p(I.clientX);N!==r&&n(N)}},[o,p,n,r]),w=u.useCallback(y=>{if(i.current&&!i.current.decided){const I=y.changedTouches[0];if(I){const S=p(I.clientX);S!==r&&n(S)}}i.current=null,d.current=!1,g(!1)},[p,n,r]);u.useEffect(()=>{const y=s.current;if(!y)return;const I=S=>{d.current&&S.preventDefault()};return y.addEventListener("touchmove",I,{passive:!1}),()=>{y.removeEventListener("touchmove",I)}},[]);const f=u.useCallback(y=>{if(o)return;const I=p(y.clientX);n(I),g(!0);const S=N=>{const D=p(N.clientX);n(D)},T=()=>{g(!1),document.removeEventListener("mousemove",S),document.removeEventListener("mouseup",T)};document.addEventListener("mousemove",S),document.addEventListener("mouseup",T)},[o,p,n]),P=`calc(10px + (100% - 20px) * ${h/100})`;return l.jsxs("div",{ref:s,className:`relative h-10 flex items-center cursor-pointer overflow-visible ${o?"opacity-50 cursor-not-allowed":""}`,onTouchStart:k,onTouchMove:E,onTouchEnd:w,onMouseDown:f,children:[l.jsx("div",{className:"absolute h-2 bg-base-300 rounded-full inset-x-0"}),l.jsx("div",{className:`absolute h-2 rounded-full transition-colors ${c.includes("range-primary")?"bg-primary":c.includes("range-secondary")?"bg-secondary":"bg-primary"}`,style:{left:0,width:P}}),l.jsx("div",{className:`absolute w-5 h-5 rounded-full bg-base-100 border-2 shadow-md transition-transform ${m?"scale-110":""} ${c.includes("range-primary")?"border-primary":c.includes("range-secondary")?"border-secondary":"border-primary"}`,style:{left:P,transform:"translateX(-50%)"}})]})}function $a(){const e=v(b=>b.appLanguage),t=v(b=>b.portrait),a=v(b=>b.setPortrait),r=v(b=>b.setPortraitZoom),n=v(b=>b.setPortraitPan),c=v(b=>b.setPortraitRawImage),o=v(b=>b.setPortraitBgRemoved),s=v(b=>b.setPortraitBgOpacity),i=v(b=>b.setPortraitBgBlur),d=v(b=>b.setPortraitEngravingIntensity),{enhance:m,removeBg:g,isEnhancing:h,isRemovingBg:p,error:k,hasKey:E,setApiKey:w}=za(),f=oe(e),P=u.useRef(null),[y,I]=u.useState(!1),[S,T]=u.useState(!1),N=u.useRef(null),D=u.useRef(null),C=t.rawImage,B=t.bgRemovedImage,_=t.bgRemoved,G=t.bgOpacity,A=t.bgBlur,X=t.engravingIntensity;u.useEffect(()=>{t.original&&!t.rawImage&&c(t.original)},[t.original,t.rawImage,c]),u.useEffect(()=>()=>{N.current&&clearTimeout(N.current),D.current&&clearTimeout(D.current)},[]);const q=v(b=>b.voucherConfig.templateHue),ie=u.useRef(q),Q=u.useCallback(async b=>{if(!b.type.startsWith("image/"))return;const L=new FileReader;L.onload=async M=>{var W;const H=(W=M.target)==null?void 0:W.result,O=await wt(H);bt(),c(O),a(O),r(1),n(0,0),o(!1,null),s(0),i(0),d(0)},L.readAsDataURL(b)},[a,c,r,n,o,s,i,d]),be=u.useCallback(b=>{b.preventDefault(),I(!1);const L=b.dataTransfer.files[0];L&&Q(L)},[Q]),F=u.useCallback(b=>{b.preventDefault(),I(!0)},[]),ee=u.useCallback(b=>{b.preventDefault(),I(!1)},[]),Z=()=>{var b;(b=P.current)==null||b.click()},we=b=>{var M;const L=(M=b.target.files)==null?void 0:M[0];L&&Q(L)},te=u.useCallback(async(b,L,M)=>{try{return await m(b,L,M)}catch(H){return console.error("Enhancement failed:",H),b}},[m]),Pe=u.useCallback(async b=>{try{const L=await g(b);return o(!0,L),L}catch(L){return console.error("Background removal failed:",L),b}},[g,o]),K=u.useCallback(async()=>{const b=v.getState(),L=b.portrait,M=b.voucherConfig.templateHue;if(!L.rawImage)return;let H;L.bgRemoved&&L.bgRemovedImage?H=await ze(L.bgRemovedImage,L.rawImage,L.bgOpacity,L.bgBlur):H=L.rawImage,L.engravingIntensity>0&&(H=await te(H,L.engravingIntensity,M)),a(H)},[te,a]),xe=u.useRef(!1);u.useEffect(()=>{t.rawImage&&!t.original&&!xe.current&&(xe.current=!0,setTimeout(()=>{K()},0)),t.rawImage||(xe.current=!1)},[t.rawImage,t.original,K]),u.useEffect(()=>{if(ie.current===q)return;ie.current=q;const b=v.getState().portrait;b.engravingIntensity>0&&b.rawImage&&(N.current&&clearTimeout(N.current),N.current=setTimeout(K,150))},[q,K]);const ye=async()=>{if(!C)return;if(!_&&!E){T(!0);return}if(!_){const L=await Pe(C),M=v.getState(),H=M.portrait,O=M.voucherConfig.templateHue;let W=await ze(L,C,H.bgOpacity,H.bgBlur);H.engravingIntensity>0&&(W=await te(W,H.engravingIntensity,O)),a(W)}else{o(!1,null);const L=v.getState(),M=L.portrait.engravingIntensity,H=L.voucherConfig.templateHue;if(M>0){const O=await te(C,M,H);a(O)}else a(C)}},Ue=b=>{d(b),N.current&&clearTimeout(N.current),C&&(N.current=setTimeout(K,150))},Te=async b=>{if(w(b),!C)return;const L=await Pe(C),M=v.getState(),H=M.portrait,O=M.voucherConfig.templateHue;let W=await ze(L,C,H.bgOpacity,H.bgBlur);H.engravingIntensity>0&&(W=await te(W,H.engravingIntensity,O)),a(W)},Ce=b=>{s(b),D.current&&clearTimeout(D.current),!(!C||!B)&&(D.current=setTimeout(K,150))},ve=b=>{i(b),D.current&&clearTimeout(D.current),!(!C||!B)&&(D.current=setTimeout(K,150))};return l.jsxs("div",{className:"space-y-4",children:[l.jsx("style",{children:`
2
2
  @keyframes sparkle1 {
3
3
  0%, 33%, 100% { opacity: 0.3; }
4
4
  16% { opacity: 1; }
@@ -11,9 +11,14 @@
11
11
  0%, 66%, 100% { opacity: 0.3; }
12
12
  83% { opacity: 1; }
13
13
  }
14
- `}),!t.original&&!t.rawImage?c.jsxs("div",{className:`border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-colors ${g?"border-primary bg-primary/10 pointer-events-none":k?"border-primary bg-primary/10":"border-base-300 hover:border-primary hover:bg-base-200"}`,onDrop:be,onDragOver:G,onDragLeave:ee,onClick:K,children:[c.jsx("input",{ref:T,type:"file",accept:"image/*",className:"hidden",onChange:xe}),g?c.jsxs("div",{className:"flex flex-col items-center gap-2",children:[c.jsx("span",{className:"loading loading-spinner loading-lg text-primary"}),c.jsx("p",{className:"font-medium",children:e==="de"?"Hintergrund wird entfernt ...":"Removing background ..."})]}):c.jsxs("div",{className:"flex flex-col items-center gap-2",children:[c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-12 w-12 text-base-content/50",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"})}),c.jsx("p",{className:"font-medium",children:b.form.portrait.upload}),c.jsx("p",{className:"text-sm text-base-content/60",children:b.form.portrait.dragDrop})]})]}):c.jsxs("div",{className:"flex flex-col space-y-4",children:[c.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4 w-full",children:[c.jsxs("div",{className:"form-control w-full",children:[c.jsxs("label",{className:"label",children:[c.jsx("span",{className:"label-text",children:b.form.portrait.zoom}),c.jsxs("span",{className:"label-text-alt",children:[Math.round(t.zoom*100),"%"]})]}),c.jsx(Ie,{min:.5,max:2,step:.05,value:t.zoom,onChange:a,className:"range range-primary range-sm"})]}),c.jsxs("div",{className:"form-control w-full",children:[c.jsxs("label",{className:"label",children:[c.jsxs("span",{className:"label-text flex items-center gap-2",children:[e==="de"?"Farbanpassung":"Color adjustment",f&&c.jsx("span",{className:"loading loading-spinner loading-xs"})]}),c.jsxs("span",{className:"label-text-alt",children:[Math.round(O*100),"%"]})]}),c.jsx(Ie,{min:0,max:1,step:.05,value:O,onChange:Ue,className:"range range-secondary range-sm",disabled:f||!R})]})]}),Y?c.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4 w-full",children:[c.jsxs("div",{className:"form-control w-full",children:[c.jsxs("label",{className:"label",children:[c.jsx("span",{className:"label-text",children:e==="de"?"Hintergrund":"Background"}),c.jsxs("span",{className:"label-text-alt",children:[Math.round(Z*100),"%"]})]}),c.jsx(Ie,{min:0,max:1,step:.05,value:Z,onChange:Se,className:"range range-primary range-sm"})]}),c.jsxs("div",{className:"form-control w-full",children:[c.jsxs("label",{className:"label",children:[c.jsx("span",{className:"label-text",children:e==="de"?"Unschärfe":"Blur"}),c.jsxs("span",{className:"label-text-alt",children:[Math.round(H*100),"%"]})]}),c.jsx(Ie,{min:0,max:1,step:.05,value:H,onChange:ve,className:"range range-primary range-sm",disabled:Z===0})]})]}):c.jsx("div",{className:"flex justify-center",children:c.jsxs("button",{className:"btn btn-ghost btn gap-2 text-base-content/70",onClick:ye,disabled:g||!R,children:[c.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:[c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z",style:g?{animation:"sparkle1 2.4s ease-in-out infinite"}:void 0}),c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456z",style:g?{animation:"sparkle2 2.4s ease-in-out infinite"}:void 0}),c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z",style:g?{animation:"sparkle3 2.4s ease-in-out infinite"}:void 0})]}),g?e==="de"?"Hintergrund wird entfernt ...":"Removing background ...":e==="de"?"Hintergrund entfernen":"Remove background",!g&&!I&&c.jsx("span",{className:"badge badge-sm badge-outline",children:"API"})]})}),v&&c.jsxs("div",{className:"alert alert-warning text-sm py-2",children:[c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"stroke-current shrink-0 h-5 w-5",fill:"none",viewBox:"0 0 24 24",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"2",d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"})}),c.jsx("span",{children:v})]})]}),c.jsx(Yt,{isOpen:L,onClose:()=>S(!1),onSubmit:Pe})]})}function Xn(){const e=y(i=>i.appLanguage),t=y(i=>i.voucherConfig.language),n=y(i=>i.voucherConfig.hours);y(i=>i.voucherConfig.templateHue);const a=y(i=>i.setBillLanguage),r=y(i=>i.setHours);y(i=>i.setTemplateHue);const l=oe(e),o=[1,5,10];return c.jsxs("div",{className:"space-y-4",children:[c.jsx("div",{className:"form-control",children:c.jsxs("div",{className:"flex items-center justify-between gap-2",children:[c.jsx("span",{className:"label-text font-medium",children:l.form.voucher.billLanguage}),c.jsxs("div",{className:"join border border-base-300 rounded-lg shadow",children:[c.jsx("button",{className:`join-item btn btn-md ${t==="de"?"btn-primary":"btn-ghost"}`,onClick:()=>a("de"),children:l.form.voucher.billLanguageGerman}),c.jsx("button",{className:`join-item btn btn-md ${t==="en"?"btn-primary":"btn-ghost"}`,onClick:()=>a("en"),children:l.form.voucher.billLanguageEnglish})]})]})}),c.jsx("div",{className:"form-control",children:c.jsxs("div",{className:"flex items-center justify-between gap-2",children:[c.jsx("span",{className:"label-text font-medium",children:l.form.voucher.hours}),c.jsx("div",{className:"join border border-base-300 rounded-lg shadow",children:o.map(i=>c.jsxs("button",{className:`join-item btn btn-md ${n===i?"btn-primary":"btn-ghost"}`,onClick:()=>r(i),children:[i,c.jsxs("span",{className:"hidden sm:inline",children:[" ",i===1?l.form.voucher.hourLabel:l.form.voucher.hoursLabel]})]},i))})]})}),!1]})}function rt(e,t){return{front:"",back:"",width:ae,height:re}}const He={front:{portrait:{x:1810,y:918,radiusX:570,radiusY:605},namePlate:{x:1816,y:1765,fontSize:85,maxWidth:898,align:"center"}},back:{portrait:{x:0,y:0,radiusX:0,radiusY:0},namePlate:{x:1816,y:1770,fontSize:85,maxWidth:898,align:"center"},contactInfo:{x:898,y:939,fontSize:93,lineHeight:165,align:"center"},description:{x:2721,y:939,fontSize:85,maxWidth:1177,lineHeight:124,align:"center"},signature:{x:1820,y:1445,width:950,height:145,labelFontSize:85}}},de=He,ge=He;function ot(e){return He}const Qe=.75;function Vn(e){const t=ot(),n=Qe,a=r=>({portrait:{x:r.portrait.x*n,y:r.portrait.y*n,radiusX:r.portrait.radiusX*n,radiusY:r.portrait.radiusY*n},namePlate:{x:r.namePlate.x*n,y:r.namePlate.y*n,fontSize:r.namePlate.fontSize*n,maxWidth:r.namePlate.maxWidth?r.namePlate.maxWidth*n:void 0,lineHeight:r.namePlate.lineHeight?r.namePlate.lineHeight*n:void 0,align:r.namePlate.align},contactInfo:r.contactInfo?{x:r.contactInfo.x*n,y:r.contactInfo.y*n,fontSize:r.contactInfo.fontSize*n,maxWidth:r.contactInfo.maxWidth?r.contactInfo.maxWidth*n:void 0,lineHeight:r.contactInfo.lineHeight?r.contactInfo.lineHeight*n:void 0,align:r.contactInfo.align}:void 0,description:r.description?{x:r.description.x*n,y:r.description.y*n,fontSize:r.description.fontSize*n,maxWidth:r.description.maxWidth?r.description.maxWidth*n:void 0,lineHeight:r.description.lineHeight?r.description.lineHeight*n:void 0,align:r.description.align}:void 0,signature:r.signature?{x:r.signature.x*n,y:r.signature.y*n,width:r.signature.width*n,height:r.signature.height*n,labelFontSize:r.signature.labelFontSize*n}:void 0});return{front:a(t.front),back:a(t.back)}}function Gn(e,t){const n=rt();return{...n,width:Math.round(n.width*Qe),height:Math.round(n.height*Qe)}}function qn(e,t){const[n,a]=d.useState(e);return d.useEffect(()=>{const r=setTimeout(()=>a(e),t);return()=>clearTimeout(r)},[e,t]),n}function Kn({onPortraitClick:e,onFileDrop:t}={}){const n=y(w=>w.appLanguage),a=y(w=>w.voucherConfig.language),r=y(w=>w.voucherConfig.hours),l=y(w=>w.voucherConfig.description),o=y(w=>w.voucherConfig.templateHue),i=y(w=>w.personalInfo),s=y(w=>w.portrait),u=y(w=>w.currentSide),h=y(w=>w.flipSide),x=y(w=>w.setPortraitPan),f=qn(o,150),g=oe(n),v=d.useRef(null),I=d.useRef(null),m=d.useRef(null),[b,T]=d.useState(!1),[k,E]=d.useState(!1),[L,S]=d.useState(!1),[A,j]=d.useState(!1),R=d.useRef(null),B=d.useRef(null),Y=d.useRef(!1),Z=d.useRef(0),H=Gn(),O=Vn(),J=s.useEnhanced&&s.enhanced?s.enhanced:s.original||s.rawImage,ie=at(a,r,l),[Q,be]=d.useState(""),[G,ee]=d.useState(""),[K,xe]=d.useState(""),[te,Ee]=d.useState(""),[q,we]=d.useState(""),[ye,Ue]=d.useState(""),[Pe,Se]=d.useState(!0);d.useEffect(()=>{let w=!0;Se(!0);async function N(){const[U,$]=await Promise.all([Je(r,a,"front"),Je(r,a,"back")]);w&&(be(U.background),ee(U.badges),xe(U.frame),Ee($.background),we($.badges),Ue($.frame),Se(!1))}return N(),()=>{w=!1}},[r,a]),d.useEffect(()=>{!v.current||!Q||!G||!K||Dt(v.current,Q,G,K,J,i.name,O.front,H.width,H.height,s.zoom,s.panX,s.panY,f,r,a)},[H,Q,G,K,J,i.name,O,s.zoom,s.panX,s.panY,f,r,a]),d.useEffect(()=>{!I.current||!te||!q||!ye||At(I.current,te,q,ye,i.name,i.email,i.phone,ie,O.back,H.width,H.height,f,r,a)},[H,te,q,ye,i,ie,O,f,r,a]);const ve=()=>{T(!b),h()};d.useEffect(()=>{T(u==="back")},[u]);const p=d.useCallback((w,N)=>{if(!m.current||u!=="front")return!1;const U=m.current.getBoundingClientRect(),$=U.width/H.width,Oe=U.height/H.height,Le=(w-U.left)/$,Ye=(N-U.top)/Oe,{x:We,y:_e,radiusX:ze,radiusY:tn}=O.front.portrait,st=(Le-We)/ze,ct=(Ye-_e)/tn;return st*st+ct*ct<=1},[u,H.width,H.height,O.front.portrait]),P=5,M=d.useCallback((w,N)=>{s.original&&(E(!0),R.current={x:w,y:N,panX:s.panX,panY:s.panY})},[s.original,s.panX,s.panY]),D=d.useCallback((w,N)=>{if(!k||!R.current||!m.current)return;const U=performance.now();if(U-Z.current<33)return;Z.current=U;const $=m.current.getBoundingClientRect(),Le=4/Math.max($.width,$.height)*s.zoom,Ye=(w-R.current.x)*Le,We=(N-R.current.y)*Le,_e=Math.max(-1,Math.min(1,R.current.panX+Ye)),ze=Math.max(-1,Math.min(1,R.current.panY+We));x(_e,ze)},[k,x,s.zoom]),z=d.useCallback(()=>{E(!1),R.current=null,B.current=null},[]),W=d.useCallback(()=>{e&&e()},[e]),Vt=w=>{p(w.clientX,w.clientY)&&(w.preventDefault(),B.current={x:w.clientX,y:w.clientY},Y.current=!1)},Gt=w=>{if(S(p(w.clientX,w.clientY)),B.current&&s.original){const N=w.clientX-B.current.x,U=w.clientY-B.current.y;Math.sqrt(N*N+U*U)>P&&!k&&(Y.current=!0,M(B.current.x,B.current.y))}k&&D(w.clientX,w.clientY)},qt=w=>{B.current&&!Y.current&&p(w.clientX,w.clientY)&&W(),z()},Kt=()=>{z(),S(!1)},Ft=w=>{if(w.touches.length===1){const N=w.touches[0];p(N.clientX,N.clientY)&&(B.current={x:N.clientX,y:N.clientY},Y.current=!1)}},Zt=w=>{if(w.touches.length===1&&B.current&&s.original){const N=w.touches[0],U=N.clientX-B.current.x,$=N.clientY-B.current.y;Math.sqrt(U*U+$*$)>P&&!k&&(Y.current=!0,M(B.current.x,B.current.y)),k&&D(N.clientX,N.clientY)}},Jt=()=>{B.current&&!Y.current&&p(B.current.x,B.current.y)&&W(),z()},it=d.useRef(!1);d.useEffect(()=>{it.current=k},[k]),d.useEffect(()=>{const w=m.current;if(!w)return;const N=U=>{it.current&&U.preventDefault()};return w.addEventListener("touchmove",N,{passive:!1}),()=>{w.removeEventListener("touchmove",N)}},[]);const Qt=u==="front"&&s.original,en=H.width/H.height;return c.jsxs("div",{className:"space-y-2",children:[c.jsxs("div",{className:"flex justify-between items-center mb-6",children:[c.jsxs("div",{className:"join border border-base-300 rounded-lg",children:[c.jsx("button",{className:`join-item btn btn-md ${u==="front"?"btn-primary":"btn-ghost"}`,onClick:()=>u!=="front"&&ve(),children:g.preview.front}),c.jsx("button",{className:`join-item btn btn-md ${u==="back"?"btn-primary":"btn-ghost"}`,onClick:()=>u!=="back"&&ve(),children:g.preview.back})]}),c.jsxs("button",{className:"btn btn-ghost btn-md",onClick:ve,children:[c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"})}),c.jsx("span",{className:"hidden sm:inline",children:g.preview.flip})]})]}),c.jsxs("div",{className:"relative w-full overflow-visible",style:{aspectRatio:en,perspective:"1500px"},children:[Pe&&c.jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-base-300 rounded-lg z-10",children:c.jsx("span",{className:"loading loading-spinner loading-lg text-primary"})}),c.jsxs("div",{ref:m,className:`relative w-full h-full shadow-lg ${L&&Qt?k?"cursor-grabbing":"cursor-grab":""} ${Pe?"opacity-0":"opacity-100"} transition-opacity duration-300`,style:{transformStyle:"preserve-3d",transition:"transform 0.6s ease-in-out, opacity 0.3s ease-in-out",transform:b?"rotateY(180deg)":"rotateY(0deg)"},onMouseDown:Vt,onMouseMove:Gt,onMouseUp:qt,onMouseLeave:Kt,onTouchStart:Ft,onTouchMove:Zt,onTouchEnd:Jt,onDragOver:w=>{w.preventDefault(),u==="front"&&j(!0)},onDragLeave:w=>{w.preventDefault(),j(!1)},onDrop:w=>{if(w.preventDefault(),j(!1),u==="front"&&t){const N=w.dataTransfer.files[0];N&&N.type.startsWith("image/")&&t(N)}},children:[c.jsx("canvas",{ref:v,className:"absolute inset-0 w-full h-full",style:{backfaceVisibility:"hidden",WebkitBackfaceVisibility:"hidden"}}),c.jsx("canvas",{ref:I,className:"absolute inset-0 w-full h-full",style:{backfaceVisibility:"hidden",WebkitBackfaceVisibility:"hidden",transform:"rotateY(180deg)"}}),u==="front"&&!s.original&&c.jsx("div",{className:`absolute flex flex-col items-center justify-center transition-colors duration-300 ease-in-out pointer-events-none ${A?"bg-primary/20":"hover:bg-base-content/5"}`,style:{left:`${(O.front.portrait.x-O.front.portrait.radiusX)/H.width*100}%`,top:`${(O.front.portrait.y-O.front.portrait.radiusY)/H.height*100}%`,width:`${O.front.portrait.radiusX*2/H.width*100}%`,height:`${O.front.portrait.radiusY*2/H.height*100}%`,borderRadius:"50%",backfaceVisibility:"hidden",WebkitBackfaceVisibility:"hidden"},children:c.jsxs("button",{className:"btn btn-dash hover:btn-dash hover:border-base-content/60 flex flex-col items-center gap-0.5 sm:gap-1 h-auto py-1.5 px-2.5 sm:py-3 sm:px-4 bg-base-100/20 hover:bg-base-100/30",children:[c.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",className:"w-7 h-6 sm:w-10 sm:h-9 text-base-content/50",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",children:[c.jsx("circle",{cx:"12",cy:"8",r:"4"}),c.jsx("path",{d:"M4 21c0-4 4-6 8-6s8 2 8 6"})]}),c.jsx("span",{className:"text-[10px] sm:text-xs text-center leading-tight whitespace-pre-line",children:n==="de"?`Foto
14
+ `}),!t.original&&!t.rawImage?l.jsxs("div",{className:`border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-colors ${p?"border-primary bg-primary/10 pointer-events-none":y?"border-primary bg-primary/10":"border-base-300 hover:border-primary hover:bg-base-200"}`,onDrop:be,onDragOver:F,onDragLeave:ee,onClick:Z,children:[l.jsx("input",{ref:P,type:"file",accept:"image/*",className:"hidden",onChange:we}),p?l.jsxs("div",{className:"flex flex-col items-center gap-2",children:[l.jsx("span",{className:"loading loading-spinner loading-lg text-primary"}),l.jsx("p",{className:"font-medium",children:e==="de"?"Hintergrund wird entfernt ...":"Removing background ..."})]}):l.jsxs("div",{className:"flex flex-col items-center gap-2",children:[l.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-12 w-12 text-base-content/50",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"})}),l.jsx("p",{className:"font-medium",children:f.form.portrait.upload}),l.jsx("p",{className:"text-sm text-base-content/60",children:f.form.portrait.dragDrop})]})]}):l.jsxs("div",{className:"flex flex-col space-y-4",children:[l.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4 w-full",children:[l.jsxs("div",{className:"form-control w-full",children:[l.jsxs("label",{className:"label",children:[l.jsx("span",{className:"label-text",children:f.form.portrait.zoom}),l.jsxs("span",{className:"label-text-alt",children:[Math.round(t.zoom*100),"%"]})]}),l.jsx(Ie,{min:.5,max:2,step:.05,value:t.zoom,onChange:r,className:"range range-primary range-sm"})]}),l.jsxs("div",{className:"form-control w-full",children:[l.jsxs("label",{className:"label",children:[l.jsxs("span",{className:"label-text flex items-center gap-2",children:[e==="de"?"Farbanpassung":"Color adjustment",h&&l.jsx("span",{className:"loading loading-spinner loading-xs"})]}),l.jsxs("span",{className:"label-text-alt",children:[Math.round(X*100),"%"]})]}),l.jsx(Ie,{min:0,max:1,step:.05,value:X,onChange:Ue,className:"range range-secondary range-sm",disabled:h||!C})]})]}),_?l.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4 w-full",children:[l.jsxs("div",{className:"form-control w-full",children:[l.jsxs("label",{className:"label",children:[l.jsx("span",{className:"label-text",children:e==="de"?"Hintergrund":"Background"}),l.jsxs("span",{className:"label-text-alt",children:[Math.round(G*100),"%"]})]}),l.jsx(Ie,{min:0,max:1,step:.05,value:G,onChange:Ce,className:"range range-primary range-sm"})]}),l.jsxs("div",{className:"form-control w-full",children:[l.jsxs("label",{className:"label",children:[l.jsx("span",{className:"label-text",children:e==="de"?"Unschärfe":"Blur"}),l.jsxs("span",{className:"label-text-alt",children:[Math.round(A*100),"%"]})]}),l.jsx(Ie,{min:0,max:1,step:.05,value:A,onChange:ve,className:"range range-primary range-sm",disabled:G===0})]})]}):l.jsx("div",{className:"flex justify-center",children:l.jsxs("button",{className:"btn btn-ghost btn gap-2 text-base-content/70",onClick:ye,disabled:p||!C,children:[l.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,children:[l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09z",style:p?{animation:"sparkle1 2.4s ease-in-out infinite"}:void 0}),l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456z",style:p?{animation:"sparkle2 2.4s ease-in-out infinite"}:void 0}),l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z",style:p?{animation:"sparkle3 2.4s ease-in-out infinite"}:void 0})]}),p?e==="de"?"Hintergrund wird entfernt ...":"Removing background ...":e==="de"?"Hintergrund entfernen":"Remove background",!p&&!E&&l.jsx("span",{className:"badge badge-sm badge-outline",children:"API"})]})}),k&&l.jsxs("div",{className:"alert alert-warning text-sm py-2",children:[l.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"stroke-current shrink-0 h-5 w-5",fill:"none",viewBox:"0 0 24 24",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:"2",d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"})}),l.jsx("span",{children:k})]})]}),l.jsx(Yt,{isOpen:S,onClose:()=>T(!1),onSubmit:Te})]})}function Va(){const e=v(s=>s.appLanguage),t=v(s=>s.voucherConfig.language),a=v(s=>s.voucherConfig.hours);v(s=>s.voucherConfig.templateHue);const r=v(s=>s.setBillLanguage),n=v(s=>s.setHours);v(s=>s.setTemplateHue);const c=oe(e),o=[1,5,10];return l.jsxs("div",{className:"space-y-4",children:[l.jsx("div",{className:"form-control",children:l.jsxs("div",{className:"flex items-center justify-between gap-2",children:[l.jsx("span",{className:"label-text font-medium",children:c.form.voucher.billLanguage}),l.jsxs("div",{className:"join border border-base-300 rounded-lg shadow",children:[l.jsx("button",{className:`join-item btn btn-md ${t==="de"?"btn-primary":"btn-ghost"}`,onClick:()=>r("de"),children:c.form.voucher.billLanguageGerman}),l.jsx("button",{className:`join-item btn btn-md ${t==="en"?"btn-primary":"btn-ghost"}`,onClick:()=>r("en"),children:c.form.voucher.billLanguageEnglish})]})]})}),l.jsx("div",{className:"form-control",children:l.jsxs("div",{className:"flex items-center justify-between gap-2",children:[l.jsx("span",{className:"label-text font-medium",children:c.form.voucher.hours}),l.jsx("div",{className:"join border border-base-300 rounded-lg shadow",children:o.map(s=>l.jsxs("button",{className:`join-item btn btn-md ${a===s?"btn-primary":"btn-ghost"}`,onClick:()=>n(s),children:[s,l.jsxs("span",{className:"hidden sm:inline",children:[" ",s===1?c.form.voucher.hourLabel:c.form.voucher.hoursLabel]})]},s))})]})}),!1]})}function rt(e,t){return{front:"",back:"",width:ne,height:re}}const Ae={front:{portrait:{x:1810,y:918,radiusX:570,radiusY:605},namePlate:{x:1816,y:1765,fontSize:85,maxWidth:898,align:"center"}},back:{portrait:{x:0,y:0,radiusX:0,radiusY:0},namePlate:{x:1816,y:1770,fontSize:85,maxWidth:898,align:"center"},contactInfo:{x:898,y:939,fontSize:93,lineHeight:165,align:"center"},description:{x:2721,y:939,fontSize:85,maxWidth:1177,lineHeight:124,align:"center"},signature:{x:1820,y:1445,width:950,height:145,labelFontSize:85}}},ue=Ae,ge=Ae;function ot(e){return Ae}const Qe=.75;function Ga(e){const t=ot(),a=Qe,r=n=>({portrait:{x:n.portrait.x*a,y:n.portrait.y*a,radiusX:n.portrait.radiusX*a,radiusY:n.portrait.radiusY*a},namePlate:{x:n.namePlate.x*a,y:n.namePlate.y*a,fontSize:n.namePlate.fontSize*a,maxWidth:n.namePlate.maxWidth?n.namePlate.maxWidth*a:void 0,lineHeight:n.namePlate.lineHeight?n.namePlate.lineHeight*a:void 0,align:n.namePlate.align},contactInfo:n.contactInfo?{x:n.contactInfo.x*a,y:n.contactInfo.y*a,fontSize:n.contactInfo.fontSize*a,maxWidth:n.contactInfo.maxWidth?n.contactInfo.maxWidth*a:void 0,lineHeight:n.contactInfo.lineHeight?n.contactInfo.lineHeight*a:void 0,align:n.contactInfo.align}:void 0,description:n.description?{x:n.description.x*a,y:n.description.y*a,fontSize:n.description.fontSize*a,maxWidth:n.description.maxWidth?n.description.maxWidth*a:void 0,lineHeight:n.description.lineHeight?n.description.lineHeight*a:void 0,align:n.description.align}:void 0,signature:n.signature?{x:n.signature.x*a,y:n.signature.y*a,width:n.signature.width*a,height:n.signature.height*a,labelFontSize:n.signature.labelFontSize*a}:void 0});return{front:r(t.front),back:r(t.back)}}function qa(e,t){const a=rt();return{...a,width:Math.round(a.width*Qe),height:Math.round(a.height*Qe)}}function Fa(e,t){const[a,r]=u.useState(e);return u.useEffect(()=>{const n=setTimeout(()=>r(e),t);return()=>clearTimeout(n)},[e,t]),a}function Ka({onPortraitClick:e,onFileDrop:t}={}){const a=v(x=>x.appLanguage),r=v(x=>x.voucherConfig.language),n=v(x=>x.voucherConfig.hours),c=v(x=>x.voucherConfig.description),o=v(x=>x.voucherConfig.templateHue),s=v(x=>x.personalInfo),i=v(x=>x.portrait),d=v(x=>x.currentSide),m=v(x=>x.flipSide),g=v(x=>x.setPortraitPan),h=Fa(o,150),p=oe(a),k=u.useRef(null),E=u.useRef(null),w=u.useRef(null),[f,P]=u.useState(!1),[y,I]=u.useState(!1),[S,T]=u.useState(!1),[N,D]=u.useState(!1),C=u.useRef(null),B=u.useRef(null),_=u.useRef(!1),G=u.useRef(0),A=qa(),X=Ga(),q=i.useEnhanced&&i.enhanced?i.enhanced:i.original||i.rawImage,ie=nt(r,n,c),[Q,be]=u.useState(""),[F,ee]=u.useState(""),[Z,we]=u.useState(""),[te,Pe]=u.useState(""),[K,xe]=u.useState(""),[ye,Ue]=u.useState(""),[Te,Ce]=u.useState(!0);u.useEffect(()=>{let x=!0;Ce(!0);async function j(){const[U,z]=await Promise.all([Je(n,r,"front"),Je(n,r,"back")]);x&&(be(U.background),ee(U.badges),we(U.frame),Pe(z.background),xe(z.badges),Ue(z.frame),Ce(!1))}return j(),()=>{x=!1}},[n,r]),u.useEffect(()=>{!k.current||!Q||!F||!Z||At(k.current,Q,F,Z,q,s.name,X.front,A.width,A.height,i.zoom,i.panX,i.panY,h,n,r)},[A,Q,F,Z,q,s.name,X,i.zoom,i.panX,i.panY,h,n,r]),u.useEffect(()=>{!E.current||!te||!K||!ye||Mt(E.current,te,K,ye,q,s.name,s.email,s.phone,ie,X.back,A.width,A.height,i.zoom,i.panX,i.panY,h,n,r)},[A,te,K,ye,q,s,ie,X,i.zoom,i.panX,i.panY,h,n,r]);const ve=()=>{P(!f),m()};u.useEffect(()=>{P(d==="back")},[d]);const b=u.useCallback((x,j)=>{if(!w.current||d!=="front")return!1;const U=w.current.getBoundingClientRect(),z=U.width/A.width,_e=U.height/A.height,Le=(x-U.left)/z,Xe=(j-U.top)/_e,{x:We,y:Ye,radiusX:Oe,radiusY:na}=X.front.portrait,st=(Le-We)/Oe,ct=(Xe-Ye)/na;return st*st+ct*ct<=1},[d,A.width,A.height,X.front.portrait]),L=5,M=u.useCallback((x,j)=>{i.original&&(I(!0),C.current={x,y:j,panX:i.panX,panY:i.panY})},[i.original,i.panX,i.panY]),H=u.useCallback((x,j)=>{if(!y||!C.current||!w.current)return;const U=performance.now();if(U-G.current<33)return;G.current=U;const z=w.current.getBoundingClientRect(),Le=4/Math.max(z.width,z.height)*i.zoom,Xe=(x-C.current.x)*Le,We=(j-C.current.y)*Le,Ye=Math.max(-1,Math.min(1,C.current.panX+Xe)),Oe=Math.max(-1,Math.min(1,C.current.panY+We));g(Ye,Oe)},[y,g,i.zoom]),O=u.useCallback(()=>{I(!1),C.current=null,B.current=null},[]),W=u.useCallback(()=>{e&&e()},[e]),qt=x=>{b(x.clientX,x.clientY)&&(x.preventDefault(),B.current={x:x.clientX,y:x.clientY},_.current=!1)},Ft=x=>{if(T(b(x.clientX,x.clientY)),B.current&&i.original){const j=x.clientX-B.current.x,U=x.clientY-B.current.y;Math.sqrt(j*j+U*U)>L&&!y&&(_.current=!0,M(B.current.x,B.current.y))}y&&H(x.clientX,x.clientY)},Kt=x=>{B.current&&!_.current&&b(x.clientX,x.clientY)&&W(),O()},Zt=()=>{O(),T(!1)},Jt=x=>{if(x.touches.length===1){const j=x.touches[0];b(j.clientX,j.clientY)&&(B.current={x:j.clientX,y:j.clientY},_.current=!1)}},Qt=x=>{if(x.touches.length===1&&B.current&&i.original){const j=x.touches[0],U=j.clientX-B.current.x,z=j.clientY-B.current.y;Math.sqrt(U*U+z*z)>L&&!y&&(_.current=!0,M(B.current.x,B.current.y)),y&&H(j.clientX,j.clientY)}},ea=()=>{B.current&&!_.current&&b(B.current.x,B.current.y)&&W(),O()},it=u.useRef(!1);u.useEffect(()=>{it.current=y},[y]),u.useEffect(()=>{const x=w.current;if(!x)return;const j=U=>{it.current&&U.preventDefault()};return x.addEventListener("touchmove",j,{passive:!1}),()=>{x.removeEventListener("touchmove",j)}},[]);const ta=d==="front"&&i.original,aa=A.width/A.height;return l.jsxs("div",{className:"space-y-2",children:[l.jsxs("div",{className:"flex justify-between items-center mb-6",children:[l.jsxs("div",{className:"join border border-base-300 rounded-lg",children:[l.jsx("button",{className:`join-item btn btn-md ${d==="front"?"btn-primary":"btn-ghost"}`,onClick:()=>d!=="front"&&ve(),children:p.preview.front}),l.jsx("button",{className:`join-item btn btn-md ${d==="back"?"btn-primary":"btn-ghost"}`,onClick:()=>d!=="back"&&ve(),children:p.preview.back})]}),l.jsxs("button",{className:"btn btn-ghost btn-md",onClick:ve,children:[l.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"})}),l.jsx("span",{className:"hidden sm:inline",children:p.preview.flip})]})]}),l.jsxs("div",{className:"relative w-full overflow-visible",style:{aspectRatio:aa,perspective:"1500px"},children:[Te&&l.jsx("div",{className:"absolute inset-0 flex items-center justify-center bg-base-300 rounded-lg z-10",children:l.jsx("span",{className:"loading loading-spinner loading-lg text-primary"})}),l.jsxs("div",{ref:w,className:`relative w-full h-full shadow-lg ${S&&ta?y?"cursor-grabbing":"cursor-grab":""} ${Te?"opacity-0":"opacity-100"} transition-opacity duration-300`,style:{transformStyle:"preserve-3d",transition:"transform 0.6s ease-in-out, opacity 0.3s ease-in-out",transform:f?"rotateY(180deg)":"rotateY(0deg)"},onMouseDown:qt,onMouseMove:Ft,onMouseUp:Kt,onMouseLeave:Zt,onTouchStart:Jt,onTouchMove:Qt,onTouchEnd:ea,onDragOver:x=>{x.preventDefault(),d==="front"&&D(!0)},onDragLeave:x=>{x.preventDefault(),D(!1)},onDrop:x=>{if(x.preventDefault(),D(!1),d==="front"&&t){const j=x.dataTransfer.files[0];j&&j.type.startsWith("image/")&&t(j)}},children:[l.jsx("canvas",{ref:k,className:"absolute inset-0 w-full h-full",style:{backfaceVisibility:"hidden",WebkitBackfaceVisibility:"hidden"}}),l.jsx("canvas",{ref:E,className:"absolute inset-0 w-full h-full",style:{backfaceVisibility:"hidden",WebkitBackfaceVisibility:"hidden",transform:"rotateY(180deg)"}}),d==="front"&&!i.original&&l.jsx("div",{className:`absolute flex flex-col items-center justify-center transition-colors duration-300 ease-in-out pointer-events-none ${N?"bg-primary/20":"hover:bg-base-content/5"}`,style:{left:`${(X.front.portrait.x-X.front.portrait.radiusX)/A.width*100}%`,top:`${(X.front.portrait.y-X.front.portrait.radiusY)/A.height*100}%`,width:`${X.front.portrait.radiusX*2/A.width*100}%`,height:`${X.front.portrait.radiusY*2/A.height*100}%`,borderRadius:"50%",backfaceVisibility:"hidden",WebkitBackfaceVisibility:"hidden"},children:l.jsxs("button",{className:"btn btn-dash hover:btn-dash hover:border-base-content/60 flex flex-col items-center gap-0.5 sm:gap-1 h-auto py-1.5 px-2.5 sm:py-3 sm:px-4 bg-base-100/20 hover:bg-base-100/30",children:[l.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",className:"w-7 h-6 sm:w-10 sm:h-9 text-base-content/50",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:1.5,strokeLinecap:"round",strokeLinejoin:"round",children:[l.jsx("circle",{cx:"12",cy:"8",r:"4"}),l.jsx("path",{d:"M4 21c0-4 4-6 8-6s8 2 8 6"})]}),l.jsx("span",{className:"text-[10px] sm:text-xs text-center leading-tight whitespace-pre-line",children:a==="de"?`Foto
15
15
  hochladen`:`Upload
16
- photo`})]})})]})]})]})}function Fn(){const e=d.useRef(null),t=d.useRef(null);return{frontCanvasRef:e,backCanvasRef:t}}const Zn=`
16
+ photo`})]})})]})]})]})}function Za(){const e=u.useRef(null),t=u.useRef(null);return{frontCanvasRef:e,backCanvasRef:t}}const mt=3,Ja=`
17
+ // Bleed configuration (3mm at 600 DPI = 71 pixels per side)
18
+ const BLEED_MM = 3;
19
+ const DPI = 600;
20
+ const BLEED_PX = Math.round((BLEED_MM / 25.4) * DPI); // ~71 pixels
21
+
17
22
  // Translations for banner text
18
23
  const TRANSLATIONS = {
19
24
  de: {
@@ -133,6 +138,66 @@ async function loadImageBitmap(url) {
133
138
  return createImageBitmap(blob);
134
139
  }
135
140
 
141
+ // Draw portrait as faded watermark with radial fade effect
142
+ function drawWatermarkPortrait(ctx, portrait, centerX, centerY, size, zoom, panX, panY) {
143
+ ctx.save();
144
+
145
+ // Create offscreen canvas for the watermark effect
146
+ const watermarkCanvas = new OffscreenCanvas(size, size);
147
+ const wmCtx = watermarkCanvas.getContext('2d');
148
+ if (!wmCtx) {
149
+ ctx.restore();
150
+ return;
151
+ }
152
+
153
+ // Calculate image dimensions to cover the circle
154
+ const imgAspect = portrait.width / portrait.height;
155
+ let drawWidth, drawHeight;
156
+
157
+ if (imgAspect > 1) {
158
+ drawHeight = size;
159
+ drawWidth = size * imgAspect;
160
+ } else {
161
+ drawWidth = size;
162
+ drawHeight = size / imgAspect;
163
+ }
164
+
165
+ drawWidth *= zoom;
166
+ drawHeight *= zoom;
167
+
168
+ const maxPanX = Math.max(0, (drawWidth - size) / 2);
169
+ const maxPanY = Math.max(0, (drawHeight - size) / 2);
170
+
171
+ const drawX = (size - drawWidth) / 2 + panX * maxPanX;
172
+ const drawY = (size - drawHeight) / 2 + panY * maxPanY;
173
+
174
+ // Draw portrait with desaturation and brightness
175
+ wmCtx.filter = 'grayscale(70%) brightness(1.4) contrast(0.6)';
176
+ wmCtx.drawImage(portrait, drawX, drawY, drawWidth, drawHeight);
177
+ wmCtx.filter = 'none';
178
+
179
+ // Apply radial gradient mask (center visible, edges transparent)
180
+ wmCtx.globalCompositeOperation = 'destination-in';
181
+ const gradient = wmCtx.createRadialGradient(
182
+ size / 2, size / 2, 0,
183
+ size / 2, size / 2, size / 2
184
+ );
185
+ gradient.addColorStop(0, 'rgba(0,0,0,1)');
186
+ gradient.addColorStop(0.5, 'rgba(0,0,0,0.8)');
187
+ gradient.addColorStop(0.8, 'rgba(0,0,0,0.3)');
188
+ gradient.addColorStop(1, 'rgba(0,0,0,0)');
189
+
190
+ wmCtx.fillStyle = gradient;
191
+ wmCtx.fillRect(0, 0, size, size);
192
+
193
+ // Draw the watermark onto main canvas with low opacity
194
+ ctx.globalAlpha = 0.18;
195
+ ctx.drawImage(watermarkCanvas, centerX - size / 2, centerY - size / 2);
196
+ ctx.globalAlpha = 1;
197
+
198
+ ctx.restore();
199
+ }
200
+
136
201
  // Draw oval portrait with clipping
137
202
  function drawOvalPortrait(ctx, portrait, centerX, centerY, radiusX, radiusY, zoom, panX, panY) {
138
203
  ctx.save();
@@ -355,7 +420,24 @@ self.onmessage = async (e) => {
355
420
  frontCtx.putImageData(frontImageData, 0, 0);
356
421
  }
357
422
 
358
- // Draw portrait
423
+ // Draw watermark portrait on right side
424
+ if (portrait) {
425
+ const watermarkSize = templateHeight * 0.6;
426
+ const watermarkX = templateWidth * 0.78 + 70;
427
+ const watermarkY = templateHeight * 0.5;
428
+ drawWatermarkPortrait(
429
+ frontCtx,
430
+ portrait,
431
+ watermarkX,
432
+ watermarkY,
433
+ watermarkSize,
434
+ portraitZoom,
435
+ portraitPanX,
436
+ portraitPanY
437
+ );
438
+ }
439
+
440
+ // Draw main portrait
359
441
  if (portrait) {
360
442
  drawOvalPortrait(
361
443
  frontCtx,
@@ -396,6 +478,23 @@ self.onmessage = async (e) => {
396
478
  backCtx.putImageData(backImageData, 0, 0);
397
479
  }
398
480
 
481
+ // Draw watermark portrait in center of back side
482
+ if (portrait) {
483
+ const watermarkSize = templateHeight * 0.6;
484
+ const watermarkX = templateWidth * 0.5;
485
+ const watermarkY = templateHeight * 0.5;
486
+ drawWatermarkPortrait(
487
+ backCtx,
488
+ portrait,
489
+ watermarkX,
490
+ watermarkY,
491
+ watermarkSize,
492
+ portraitZoom,
493
+ portraitPanX,
494
+ portraitPanY
495
+ );
496
+ }
497
+
399
498
  // Draw contact info
400
499
  if (layout.back.contactInfo && (name || email || phone)) {
401
500
  drawContactInfo(
@@ -462,10 +561,50 @@ self.onmessage = async (e) => {
462
561
  // Draw banner text on back
463
562
  drawBannerText(backCtx, hours, language);
464
563
 
465
- // Convert canvases to blobs and then to ArrayBuffer for transfer
564
+ // Add bleed area by extending edge pixels
565
+ const bleedWidth = templateWidth + (BLEED_PX * 2);
566
+ const bleedHeight = templateHeight + (BLEED_PX * 2);
567
+
568
+ // Create bleed canvases
569
+ const frontBleedCanvas = new OffscreenCanvas(bleedWidth, bleedHeight);
570
+ const backBleedCanvas = new OffscreenCanvas(bleedWidth, bleedHeight);
571
+ const frontBleedCtx = frontBleedCanvas.getContext('2d');
572
+ const backBleedCtx = backBleedCanvas.getContext('2d');
573
+
574
+ // Function to add bleed to a canvas
575
+ function addBleedToCanvas(srcCanvas, dstCtx, width, height) {
576
+ // Draw the original image in the center
577
+ dstCtx.drawImage(srcCanvas, BLEED_PX, BLEED_PX);
578
+
579
+ // Extend edges by mirroring/repeating edge pixels
580
+ // Top edge - stretch top row
581
+ dstCtx.drawImage(srcCanvas, 0, 0, width, 1, BLEED_PX, 0, width, BLEED_PX);
582
+ // Bottom edge - stretch bottom row
583
+ dstCtx.drawImage(srcCanvas, 0, height - 1, width, 1, BLEED_PX, height + BLEED_PX, width, BLEED_PX);
584
+ // Left edge - stretch left column
585
+ dstCtx.drawImage(srcCanvas, 0, 0, 1, height, 0, BLEED_PX, BLEED_PX, height);
586
+ // Right edge - stretch right column
587
+ dstCtx.drawImage(srcCanvas, width - 1, 0, 1, height, width + BLEED_PX, BLEED_PX, BLEED_PX, height);
588
+
589
+ // Corners - fill with corner pixel colors
590
+ // Top-left corner
591
+ dstCtx.drawImage(srcCanvas, 0, 0, 1, 1, 0, 0, BLEED_PX, BLEED_PX);
592
+ // Top-right corner
593
+ dstCtx.drawImage(srcCanvas, width - 1, 0, 1, 1, width + BLEED_PX, 0, BLEED_PX, BLEED_PX);
594
+ // Bottom-left corner
595
+ dstCtx.drawImage(srcCanvas, 0, height - 1, 1, 1, 0, height + BLEED_PX, BLEED_PX, BLEED_PX);
596
+ // Bottom-right corner
597
+ dstCtx.drawImage(srcCanvas, width - 1, height - 1, 1, 1, width + BLEED_PX, height + BLEED_PX, BLEED_PX, BLEED_PX);
598
+ }
599
+
600
+ // Add bleed to both canvases
601
+ addBleedToCanvas(frontCanvas, frontBleedCtx, templateWidth, templateHeight);
602
+ addBleedToCanvas(backCanvas, backBleedCtx, templateWidth, templateHeight);
603
+
604
+ // Convert bleed canvases to blobs and then to ArrayBuffer for transfer
466
605
  const [frontBlob, backBlob] = await Promise.all([
467
- frontCanvas.convertToBlob({ type: 'image/jpeg', quality: 0.95 }),
468
- backCanvas.convertToBlob({ type: 'image/jpeg', quality: 0.95 }),
606
+ frontBleedCanvas.convertToBlob({ type: 'image/jpeg', quality: 0.95 }),
607
+ backBleedCanvas.convertToBlob({ type: 'image/jpeg', quality: 0.95 }),
469
608
  ]);
470
609
 
471
610
  const [frontBuffer, backBuffer] = await Promise.all([
@@ -474,12 +613,14 @@ self.onmessage = async (e) => {
474
613
  ]);
475
614
 
476
615
  // Transfer buffers back to main thread (zero-copy)
616
+ // Return the bleed dimensions so PDF knows the new size
477
617
  self.postMessage({
478
618
  type: 'success',
479
619
  frontImageData: frontBuffer,
480
620
  backImageData: backBuffer,
481
- width: templateWidth,
482
- height: templateHeight,
621
+ width: bleedWidth,
622
+ height: bleedHeight,
623
+ bleedPx: BLEED_PX,
483
624
  }, [frontBuffer, backBuffer]);
484
625
  } catch (error) {
485
626
  self.postMessage({
@@ -488,4 +629,4 @@ self.onmessage = async (e) => {
488
629
  });
489
630
  }
490
631
  };
491
- `;let Ve=null,mt=null;function Jn(){if(!Ve){const e=new Blob([Zn],{type:"application/javascript"});mt=URL.createObjectURL(e),Ve=new Worker(mt,{type:"module"})}return Ve}async function Ge(e){const n=await(await fetch(e)).blob();return URL.createObjectURL(n)}function ht(e,t){const n=new Uint8Array(e);let a="";for(let r=0;r<n.length;r++)a+=String.fromCharCode(n[r]);return`data:${t};base64,${btoa(a)}`}async function Wt(e){const{frontTemplateSrc:t,backTemplateSrc:n,templateWidth:a,templateHeight:r,layout:l,portrait:o,portraitZoom:i=1,portraitPanX:s=0,portraitPanY:u=0,templateHue:h=160,name:x,email:f,phone:g,description:v,language:I="de",hours:m=1}=e,[b,T]=await Promise.all([Ge(t),Ge(n)]);let k=null;return o&&(k=await Ge(o)),new Promise((E,L)=>{const S=Jn(),A=setTimeout(()=>{S.removeEventListener("message",j),S.removeEventListener("error",R),URL.revokeObjectURL(b),URL.revokeObjectURL(T),k&&URL.revokeObjectURL(k),L(new Error("PDF generation timed out. Please try again."))},6e4),j=B=>{if(clearTimeout(A),S.removeEventListener("message",j),S.removeEventListener("error",R),URL.revokeObjectURL(b),URL.revokeObjectURL(T),k&&URL.revokeObjectURL(k),B.data.type==="success")try{const{frontImageData:Y,backImageData:Z,width:H,height:O}=B.data;if(!Y||!Z||!H||!O){L(new Error("Invalid response from worker"));return}const J=ht(Y,"image/jpeg"),ie=ht(Z,"image/jpeg"),Q=138.6,be=72.9,G=Q,ee=be,K=new an.jsPDF({orientation:G>ee?"landscape":"portrait",unit:"mm",format:[G,ee]});K.addImage(J,"JPEG",0,0,G,ee),K.addPage([G,ee]),K.addImage(ie,"JPEG",0,0,G,ee);const xe=K.output("blob");E(xe)}catch(Y){L(Y)}else L(new Error(B.data.error))},R=B=>{S.removeEventListener("message",j),S.removeEventListener("error",R),URL.revokeObjectURL(b),URL.revokeObjectURL(T),k&&URL.revokeObjectURL(k),L(new Error(B.message))};S.addEventListener("message",j),S.addEventListener("error",R),S.postMessage({type:"generate",frontTemplateUrl:b,backTemplateUrl:T,portraitUrl:k,templateWidth:a,templateHeight:r,templateHue:h,portraitZoom:i,portraitPanX:s,portraitPanY:u,layout:{front:{portrait:l.front.portrait,namePlate:l.front.namePlate},back:{namePlate:l.back.namePlate,contactInfo:l.back.contactInfo,description:l.back.description,signature:l.back.signature}},name:x,email:f,phone:g,description:v,language:I,hours:m})})}function _t(e,t){const n=URL.createObjectURL(e),a=document.createElement("a");a.href=n,a.download=t,document.body.appendChild(a),a.click(),document.body.removeChild(a),URL.revokeObjectURL(n)}async function zt(e){const t=await Wt(e);_t(t,e.filename)}function Qn(){const e=y(b=>b.appLanguage),t=y(b=>b.voucherConfig.language),n=y(b=>b.voucherConfig.hours),a=y(b=>b.voucherConfig.description),r=y(b=>b.voucherConfig.templateHue),l=y(b=>b.personalInfo),o=y(b=>b.portrait),i=y(b=>b.isExporting),s=y(b=>b.setIsExporting),u=oe(e),h=rt(),x=ot(),f=o.useEnhanced&&o.enhanced?o.enhanced:o.original||o.rawImage,g=at(t,n,a),v=o.original!==null||o.rawImage!==null,I=l.name.trim().length>0&&l.email.trim().length>0&&l.phone.trim().length>0&&v,m=async()=>{if(!(!I||i)){s(!0);try{const[b,T]=await Promise.all([Ze(n,t,"front"),Ze(n,t,"back")]),k=`zeitgutschein-${n}h-${l.name.replace(/\s+/g,"-").toLowerCase()}.pdf`;await zt({frontTemplateSrc:b,backTemplateSrc:T,templateWidth:h.width,templateHeight:h.height,layout:x,portrait:f,portraitZoom:o.zoom,portraitPanX:o.panX,portraitPanY:o.panY,templateHue:r,name:l.name,email:l.email,phone:l.phone,description:g,filename:k,language:t,hours:n})}catch(b){console.error("PDF export failed:",b)}finally{s(!1)}}};return c.jsxs("button",{className:`btn btn-primary w-full btn-md ${I?"":"btn-disabled"}`,onClick:m,disabled:!I,"aria-busy":i,children:[i?c.jsx("span",{className:"loading loading-spinner loading-sm"}):c.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:c.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"})}),u.export.button]})}function $t(){const e=y(a=>a.appLanguage),t=y(a=>a.setAppLanguage),n=a=>{t(a)};return c.jsxs("div",{className:"join",children:[c.jsx("button",{className:`join-item btn btn-sm ${e==="de"?"btn-primary":"btn-ghost"}`,onClick:()=>n("de"),children:"DE"}),c.jsx("button",{className:`join-item btn btn-sm ${e==="en"?"btn-primary":"btn-ghost"}`,onClick:()=>n("en"),children:"EN"})]})}function ea(){const e=y(n=>n.appLanguage),t=oe(e);return c.jsxs("div",{className:"navbar bg-currency-green text-currency-cream shadow-lg shrink-0",children:[c.jsx("div",{className:"navbar-start",children:c.jsx("a",{className:"btn btn-ghost text-xl font-currency font-bold",children:t.header.title})}),c.jsx("div",{className:"navbar-center hidden sm:flex",children:c.jsx("span",{className:"text-sm opacity-80",children:t.header.subtitle})}),c.jsx("div",{className:"navbar-end",children:c.jsx($t,{})})]})}const je="/",ta={id:"time-voucher-classic-de",name:"Zeitgutschein Classic",type:"time-voucher",category:"classic",images:{front:`${je}templates/front_hdpi_de.jpg`,back:`${je}templates/back_hdpi_de.jpg`,width:6144,height:4096},fields:[{id:"name",type:"text",label:{de:"Name",en:"Name"},required:!0,validation:{minLength:1,maxLength:50}},{id:"hours",type:"select",label:{de:"Stunden",en:"Hours"},required:!0,options:["1","5","10"]},{id:"portrait",type:"image",label:{de:"Portrait",en:"Portrait"},required:!1},{id:"email",type:"text",label:{de:"E-Mail",en:"Email"},required:!1},{id:"phone",type:"text",label:{de:"Telefon",en:"Phone"},required:!1},{id:"description",type:"textarea",label:{de:"Beschreibung",en:"Description"},required:!1,validation:{maxLength:200}}],layout:{front:{portrait:de.front.portrait,name:de.front.namePlate},back:{name:de.back.namePlate,contactInfo:de.back.contactInfo,description:de.back.description}},languages:["de"]},na={id:"time-voucher-classic-en",name:"Time Voucher Classic",type:"time-voucher",category:"classic",images:{front:`${je}templates/front_ldpi_en.png`,back:`${je}templates/back_ldpi_en.png`,width:1536,height:1024},fields:[{id:"name",type:"text",label:{de:"Name",en:"Name"},required:!0,validation:{minLength:1,maxLength:50}},{id:"hours",type:"select",label:{de:"Stunden",en:"Hours"},required:!0,options:["1","5","10"]},{id:"portrait",type:"image",label:{de:"Portrait",en:"Portrait"},required:!1},{id:"email",type:"text",label:{de:"E-Mail",en:"Email"},required:!1},{id:"phone",type:"text",label:{de:"Telefon",en:"Phone"},required:!1},{id:"description",type:"textarea",label:{de:"Beschreibung",en:"Description"},required:!1,validation:{maxLength:200}}],layout:{front:{portrait:ge.front.portrait,name:ge.front.namePlate},back:{name:ge.back.namePlate,contactInfo:ge.back.contactInfo,description:ge.back.description}},languages:["en"]},ft=[ta,na],Xt={async listTemplates(e){let t=[...ft];return e!=null&&e.type&&(t=t.filter(n=>n.type===e.type)),e!=null&&e.category&&(t=t.filter(n=>n.category===e.category)),e!=null&&e.language&&(t=t.filter(n=>n.languages.includes(e.language))),t},async getTemplate(e){const t=ft.find(n=>n.id===e);if(!t)throw new Error(`Template not found: ${e}`);return t}};function aa(e){return e==="de"?"time-voucher-classic-de":"time-voucher-classic-en"}let Me=Xt;function ra(e){Me=e}function oa(){return Me}async function ia(e){return Me.listTemplates(e)}async function sa(e){return Me.getTemplate(e)}exports.ApiKeyModal=Yt;exports.BillPreview=Kn;exports.ExportButton=Qn;exports.Header=ea;exports.LAYOUT_HDPI=de;exports.LAYOUT_LDPI=ge;exports.LanguageToggle=$t;exports.PREVIEW_HEIGHT=un;exports.PREVIEW_WIDTH=ln;exports.PersonalInfoForm=jn;exports.PortraitUpload=$n;exports.TEMPLATE_HEIGHT=re;exports.TEMPLATE_LAYOUT=He;exports.TEMPLATE_WIDTH=ae;exports.TouchSlider=Ie;exports.VoucherConfig=Xn;exports.applyEngravingEffect=xt;exports.applyHueShift=yt;exports.clearCompositorCache=Lt;exports.clearHueShiftedCache=Rt;exports.composeTemplate=St;exports.composeTemplateFullRes=Ze;exports.downloadBlob=_t;exports.drawContactInfo=jt;exports.drawMultilineText=Nt;exports.drawOvalPortrait=Ct;exports.drawTemplate=le;exports.drawText=tt;exports.enhancePortrait=_n;exports.exportBillAsPDF=zt;exports.formatDescription=at;exports.generateBillPDF=Wt;exports.getApiKey=Ae;exports.getDefaultTemplateId=aa;exports.getLayout=ot;exports.getRemoveBackgroundEndpoint=Mn;exports.getTemplate=rt;exports.getTemplateById=sa;exports.getTemplateDimensions=hn;exports.getTemplateLayers=Je;exports.getTemplateProvider=oa;exports.hasApiKey=Ce;exports.hasCustomEndpoint=Un;exports.initializeBillStore=Sn;exports.listTemplates=ia;exports.loadImage=C;exports.preloadAllTemplates=fn;exports.preloadBaseImages=dn;exports.removeBackground=Ot;exports.renderBackSide=At;exports.renderFrontSide=Dt;exports.resizeImage=bt;exports.setApiKey=Ut;exports.setRemoveBackgroundEndpoint=Hn;exports.setTemplateProvider=ra;exports.staticTemplateProvider=Xt;exports.t=oe;exports.useBillCanvasRefs=Fn;exports.useBillStore=y;
632
+ `;let Ve=null,ht=null;function Qa(){if(!Ve){const e=new Blob([Ja],{type:"application/javascript"});ht=URL.createObjectURL(e),Ve=new Worker(ht,{type:"module"})}return Ve}async function Ge(e){const a=await(await fetch(e)).blob();return URL.createObjectURL(a)}function pt(e,t){const a=new Uint8Array(e);let r="";for(let n=0;n<a.length;n++)r+=String.fromCharCode(a[n]);return`data:${t};base64,${btoa(r)}`}async function Ot(e){const{frontTemplateSrc:t,backTemplateSrc:a,templateWidth:r,templateHeight:n,layout:c,portrait:o,portraitZoom:s=1,portraitPanX:i=0,portraitPanY:d=0,templateHue:m=160,name:g,email:h,phone:p,description:k,language:E="de",hours:w=1}=e,[f,P]=await Promise.all([Ge(t),Ge(a)]);let y=null;return o&&(y=await Ge(o)),new Promise((I,S)=>{const T=Qa(),N=setTimeout(()=>{T.removeEventListener("message",D),T.removeEventListener("error",C),URL.revokeObjectURL(f),URL.revokeObjectURL(P),y&&URL.revokeObjectURL(y),S(new Error("PDF generation timed out. Please try again."))},6e4),D=B=>{if(clearTimeout(N),T.removeEventListener("message",D),T.removeEventListener("error",C),URL.revokeObjectURL(f),URL.revokeObjectURL(P),y&&URL.revokeObjectURL(y),B.data.type==="success")try{const{frontImageData:_,backImageData:G,width:A,height:X}=B.data;if(!_||!G||!A||!X){S(new Error("Invalid response from worker"));return}const q=pt(_,"image/jpeg"),ie=pt(G,"image/jpeg"),Q=138.6,be=72.9,F=Q+mt*2,ee=be+mt*2,Z=new oa.jsPDF({orientation:F>ee?"landscape":"portrait",unit:"mm",format:[F,ee]});Z.addImage(q,"JPEG",0,0,F,ee),Z.addPage([F,ee]),Z.addImage(ie,"JPEG",0,0,F,ee);const we=Z.output("blob");I(we)}catch(_){S(_)}else S(new Error(B.data.error))},C=B=>{T.removeEventListener("message",D),T.removeEventListener("error",C),URL.revokeObjectURL(f),URL.revokeObjectURL(P),y&&URL.revokeObjectURL(y),S(new Error(B.message))};T.addEventListener("message",D),T.addEventListener("error",C),T.postMessage({type:"generate",frontTemplateUrl:f,backTemplateUrl:P,portraitUrl:y,templateWidth:r,templateHeight:n,templateHue:m,portraitZoom:s,portraitPanX:i,portraitPanY:d,layout:{front:{portrait:c.front.portrait,namePlate:c.front.namePlate},back:{namePlate:c.back.namePlate,contactInfo:c.back.contactInfo,description:c.back.description,signature:c.back.signature}},name:g,email:h,phone:p,description:k,language:E,hours:w})})}function zt(e,t){const a=URL.createObjectURL(e),r=document.createElement("a");r.href=a,r.download=t,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(a)}async function $t(e){const t=await Ot(e);zt(t,e.filename)}function en(){const e=v(f=>f.appLanguage),t=v(f=>f.voucherConfig.language),a=v(f=>f.voucherConfig.hours),r=v(f=>f.voucherConfig.description),n=v(f=>f.voucherConfig.templateHue),c=v(f=>f.personalInfo),o=v(f=>f.portrait),s=v(f=>f.isExporting),i=v(f=>f.setIsExporting),d=oe(e),m=rt(),g=ot(),h=o.useEnhanced&&o.enhanced?o.enhanced:o.original||o.rawImage,p=nt(t,a,r),k=o.original!==null||o.rawImage!==null,E=c.name.trim().length>0&&c.email.trim().length>0&&c.phone.trim().length>0&&k,w=async()=>{if(!(!E||s)){i(!0);try{const[f,P]=await Promise.all([Ze(a,t,"front"),Ze(a,t,"back")]),y=`zeitgutschein-${a}h-${c.name.replace(/\s+/g,"-").toLowerCase()}.pdf`;await $t({frontTemplateSrc:f,backTemplateSrc:P,templateWidth:m.width,templateHeight:m.height,layout:g,portrait:h,portraitZoom:o.zoom,portraitPanX:o.panX,portraitPanY:o.panY,templateHue:n,name:c.name,email:c.email,phone:c.phone,description:p,filename:y,language:t,hours:a})}catch(f){console.error("PDF export failed:",f)}finally{i(!1)}}};return l.jsxs("button",{className:`btn btn-primary w-full btn-md ${E?"":"btn-disabled"}`,onClick:w,disabled:!E,"aria-busy":s,children:[s?l.jsx("span",{className:"loading loading-spinner loading-sm"}):l.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:l.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"})}),d.export.button]})}function Vt(){const e=v(r=>r.appLanguage),t=v(r=>r.setAppLanguage),a=r=>{t(r)};return l.jsxs("div",{className:"join",children:[l.jsx("button",{className:`join-item btn btn-sm ${e==="de"?"btn-primary":"btn-ghost"}`,onClick:()=>a("de"),children:"DE"}),l.jsx("button",{className:`join-item btn btn-sm ${e==="en"?"btn-primary":"btn-ghost"}`,onClick:()=>a("en"),children:"EN"})]})}function tn(){const e=v(a=>a.appLanguage),t=oe(e);return l.jsxs("div",{className:"navbar bg-currency-green text-currency-cream shadow-lg shrink-0",children:[l.jsx("div",{className:"navbar-start",children:l.jsx("a",{className:"btn btn-ghost text-xl font-currency font-bold",children:t.header.title})}),l.jsx("div",{className:"navbar-center hidden sm:flex",children:l.jsx("span",{className:"text-sm opacity-80",children:t.header.subtitle})}),l.jsx("div",{className:"navbar-end",children:l.jsx(Vt,{})})]})}const Ne="/",an={id:"time-voucher-classic-de",name:"Zeitgutschein Classic",type:"time-voucher",category:"classic",images:{front:`${Ne}templates/front_hdpi_de.jpg`,back:`${Ne}templates/back_hdpi_de.jpg`,width:6144,height:4096},fields:[{id:"name",type:"text",label:{de:"Name",en:"Name"},required:!0,validation:{minLength:1,maxLength:50}},{id:"hours",type:"select",label:{de:"Stunden",en:"Hours"},required:!0,options:["1","5","10"]},{id:"portrait",type:"image",label:{de:"Portrait",en:"Portrait"},required:!1},{id:"email",type:"text",label:{de:"E-Mail",en:"Email"},required:!1},{id:"phone",type:"text",label:{de:"Telefon",en:"Phone"},required:!1},{id:"description",type:"textarea",label:{de:"Beschreibung",en:"Description"},required:!1,validation:{maxLength:200}}],layout:{front:{portrait:ue.front.portrait,name:ue.front.namePlate},back:{name:ue.back.namePlate,contactInfo:ue.back.contactInfo,description:ue.back.description}},languages:["de"]},nn={id:"time-voucher-classic-en",name:"Time Voucher Classic",type:"time-voucher",category:"classic",images:{front:`${Ne}templates/front_ldpi_en.png`,back:`${Ne}templates/back_ldpi_en.png`,width:1536,height:1024},fields:[{id:"name",type:"text",label:{de:"Name",en:"Name"},required:!0,validation:{minLength:1,maxLength:50}},{id:"hours",type:"select",label:{de:"Stunden",en:"Hours"},required:!0,options:["1","5","10"]},{id:"portrait",type:"image",label:{de:"Portrait",en:"Portrait"},required:!1},{id:"email",type:"text",label:{de:"E-Mail",en:"Email"},required:!1},{id:"phone",type:"text",label:{de:"Telefon",en:"Phone"},required:!1},{id:"description",type:"textarea",label:{de:"Beschreibung",en:"Description"},required:!1,validation:{maxLength:200}}],layout:{front:{portrait:ge.front.portrait,name:ge.front.namePlate},back:{name:ge.back.namePlate,contactInfo:ge.back.contactInfo,description:ge.back.description}},languages:["en"]},ft=[an,nn],Gt={async listTemplates(e){let t=[...ft];return e!=null&&e.type&&(t=t.filter(a=>a.type===e.type)),e!=null&&e.category&&(t=t.filter(a=>a.category===e.category)),e!=null&&e.language&&(t=t.filter(a=>a.languages.includes(e.language))),t},async getTemplate(e){const t=ft.find(a=>a.id===e);if(!t)throw new Error(`Template not found: ${e}`);return t}};function rn(e){return e==="de"?"time-voucher-classic-de":"time-voucher-classic-en"}let Me=Gt;function on(e){Me=e}function sn(){return Me}async function cn(e){return Me.listTemplates(e)}async function ln(e){return Me.getTemplate(e)}exports.ApiKeyModal=Yt;exports.BillPreview=Ka;exports.ExportButton=en;exports.Header=tn;exports.LAYOUT_HDPI=ue;exports.LAYOUT_LDPI=ge;exports.LanguageToggle=Vt;exports.PREVIEW_HEIGHT=ua;exports.PREVIEW_WIDTH=da;exports.PersonalInfoForm=ja;exports.PortraitUpload=$a;exports.TEMPLATE_HEIGHT=re;exports.TEMPLATE_LAYOUT=Ae;exports.TEMPLATE_WIDTH=ne;exports.TouchSlider=Ie;exports.VoucherConfig=Va;exports.applyEngravingEffect=xt;exports.applyHueShift=vt;exports.clearCompositorCache=St;exports.clearHueShiftedCache=Bt;exports.composeTemplate=Lt;exports.composeTemplateFullRes=Ze;exports.downloadBlob=zt;exports.drawContactInfo=Ht;exports.drawMultilineText=jt;exports.drawOvalPortrait=Nt;exports.drawTemplate=le;exports.drawText=tt;exports.enhancePortrait=Oa;exports.exportBillAsPDF=$t;exports.formatDescription=nt;exports.generateBillPDF=Ot;exports.getApiKey=He;exports.getDefaultTemplateId=rn;exports.getLayout=ot;exports.getRemoveBackgroundEndpoint=Ua;exports.getTemplate=rt;exports.getTemplateById=ln;exports.getTemplateDimensions=pa;exports.getTemplateLayers=Je;exports.getTemplateProvider=sn;exports.hasApiKey=Re;exports.hasCustomEndpoint=_a;exports.initializeBillStore=La;exports.listTemplates=cn;exports.loadImage=R;exports.preloadAllTemplates=fa;exports.preloadBaseImages=ga;exports.removeBackground=Wt;exports.renderBackSide=Mt;exports.renderFrontSide=At;exports.resizeImage=wt;exports.setApiKey=Xt;exports.setRemoveBackgroundEndpoint=Ma;exports.setTemplateProvider=on;exports.staticTemplateProvider=Gt;exports.t=oe;exports.useBillCanvasRefs=Za;exports.useBillStore=v;
package/dist/index.d.ts CHANGED
@@ -317,7 +317,7 @@ export declare const PREVIEW_WIDTH: number;
317
317
 
318
318
  export declare function removeBackground(imageDataUrl: string): Promise<string>;
319
319
 
320
- export declare function renderBackSide(canvas: HTMLCanvasElement, backgroundSrc: string, badgesSrc: string, frameSrc: string, name: string, email: string, phone: string, description: string, layout: TemplateLayout, width: number, height: number, templateHue?: number, hours?: HourValue, language?: Language): Promise<void>;
320
+ export declare function renderBackSide(canvas: HTMLCanvasElement, backgroundSrc: string, badgesSrc: string, frameSrc: string, portraitSrc: string | null, name: string, email: string, phone: string, description: string, layout: TemplateLayout, width: number, height: number, portraitZoom?: number, portraitPanX?: number, portraitPanY?: number, templateHue?: number, hours?: HourValue, language?: Language): Promise<void>;
321
321
 
322
322
  export declare function renderFrontSide(canvas: HTMLCanvasElement, backgroundSrc: string, badgesSrc: string, frameSrc: string, portraitSrc: string | null, name: string, layout: TemplateLayout, width: number, height: number, portraitZoom?: number, portraitPanX?: number, portraitPanY?: number, templateHue?: number, hours?: HourValue, language?: Language): Promise<void>;
323
323