@antontranelis/money-printer 1.0.0

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.js ADDED
@@ -0,0 +1,1290 @@
1
+ import { jsxs as h, jsx as o, Fragment as z } from "react/jsx-runtime";
2
+ import { create as le } from "zustand";
3
+ import { persist as se } from "zustand/middleware";
4
+ import { useState as C, useCallback as E, useRef as _, useEffect as O } from "react";
5
+ import ce from "jspdf";
6
+ const V = {
7
+ personalInfo: {
8
+ name: "",
9
+ email: "",
10
+ phone: ""
11
+ },
12
+ voucherConfig: {
13
+ hours: 1,
14
+ description: "",
15
+ language: "de"
16
+ },
17
+ portrait: {
18
+ original: null,
19
+ enhanced: null,
20
+ useEnhanced: !1,
21
+ zoom: 1
22
+ },
23
+ currentSide: "front",
24
+ isEnhancing: !1,
25
+ isExporting: !1
26
+ }, g = le()(
27
+ se(
28
+ (e) => ({
29
+ ...V,
30
+ setPersonalInfo: (t) => e((n) => ({
31
+ personalInfo: { ...n.personalInfo, ...t }
32
+ })),
33
+ setVoucherConfig: (t) => e((n) => ({
34
+ voucherConfig: { ...n.voucherConfig, ...t }
35
+ })),
36
+ setPortrait: (t, n = null) => e({
37
+ portrait: {
38
+ original: t,
39
+ enhanced: n,
40
+ useEnhanced: !1,
41
+ zoom: 1
42
+ }
43
+ }),
44
+ setEnhancedPortrait: (t) => e((n) => ({
45
+ portrait: {
46
+ ...n.portrait,
47
+ enhanced: t,
48
+ useEnhanced: t !== null
49
+ }
50
+ })),
51
+ toggleUseEnhanced: () => e((t) => ({
52
+ portrait: {
53
+ ...t.portrait,
54
+ useEnhanced: t.portrait.enhanced ? !t.portrait.useEnhanced : !1
55
+ }
56
+ })),
57
+ setPortraitZoom: (t) => e((n) => ({
58
+ portrait: {
59
+ ...n.portrait,
60
+ zoom: t
61
+ }
62
+ })),
63
+ setCurrentSide: (t) => e({ currentSide: t }),
64
+ flipSide: () => e((t) => ({
65
+ currentSide: t.currentSide === "front" ? "back" : "front"
66
+ })),
67
+ setIsEnhancing: (t) => e({ isEnhancing: t }),
68
+ setIsExporting: (t) => e({ isExporting: t }),
69
+ setLanguage: (t) => e((n) => ({
70
+ voucherConfig: { ...n.voucherConfig, language: t }
71
+ })),
72
+ setHours: (t) => e((n) => ({
73
+ voucherConfig: { ...n.voucherConfig, hours: t }
74
+ })),
75
+ reset: () => e(V)
76
+ }),
77
+ {
78
+ name: "money-generator-storage",
79
+ partialize: (e) => ({
80
+ personalInfo: e.personalInfo,
81
+ voucherConfig: e.voucherConfig
82
+ })
83
+ }
84
+ )
85
+ ), de = {
86
+ header: {
87
+ title: "Money Generator",
88
+ subtitle: "Erstelle deinen persönlichen Zeitgutschein"
89
+ },
90
+ form: {
91
+ personalInfo: {
92
+ title: "Persönliche Daten",
93
+ name: "Name",
94
+ namePlaceholder: "Dein Name",
95
+ email: "E-Mail",
96
+ emailPlaceholder: "deine@email.de",
97
+ phone: "Telefon",
98
+ phonePlaceholder: "+49 123 456789"
99
+ },
100
+ portrait: {
101
+ title: "Portrait",
102
+ upload: "Bild hochladen",
103
+ dragDrop: "oder hierher ziehen",
104
+ enhance: "Mit AI verbessern",
105
+ enhancing: "Wird verbessert...",
106
+ useOriginal: "Original verwenden",
107
+ useEnhanced: "Verbessertes verwenden",
108
+ zoom: "Zoom"
109
+ },
110
+ voucher: {
111
+ title: "Gutschein",
112
+ hours: "Stunden",
113
+ hourLabel: "Stunde",
114
+ hoursLabel: "Stunden",
115
+ description: "Beschreibung",
116
+ descriptionPlaceholder: "Was kann mit diesem Gutschein eingelöst werden?"
117
+ }
118
+ },
119
+ preview: {
120
+ front: "Vorderseite",
121
+ back: "Rückseite",
122
+ flip: "Umdrehen"
123
+ },
124
+ export: {
125
+ button: "Als PDF herunterladen",
126
+ exporting: "PDF wird erstellt...",
127
+ success: "Download gestartet!"
128
+ },
129
+ bill: {
130
+ descriptionText: "Für diesen Schein erhältst du {hours} {hourLabel} meiner Zeit oder ein gleichwertiges Dankeschön"
131
+ }
132
+ }, he = {
133
+ header: {
134
+ title: "Money Generator",
135
+ subtitle: "Create your personal time voucher"
136
+ },
137
+ form: {
138
+ personalInfo: {
139
+ title: "Personal Information",
140
+ name: "Name",
141
+ namePlaceholder: "Your name",
142
+ email: "Email",
143
+ emailPlaceholder: "your@email.com",
144
+ phone: "Phone",
145
+ phonePlaceholder: "+1 234 567890"
146
+ },
147
+ portrait: {
148
+ title: "Portrait",
149
+ upload: "Upload image",
150
+ dragDrop: "or drag and drop",
151
+ enhance: "Enhance with AI",
152
+ enhancing: "Enhancing...",
153
+ useOriginal: "Use original",
154
+ useEnhanced: "Use enhanced",
155
+ zoom: "Zoom"
156
+ },
157
+ voucher: {
158
+ title: "Voucher",
159
+ hours: "Hours",
160
+ hourLabel: "hour",
161
+ hoursLabel: "hours",
162
+ description: "Description",
163
+ descriptionPlaceholder: "What can be redeemed with this voucher?"
164
+ }
165
+ },
166
+ preview: {
167
+ front: "Front",
168
+ back: "Back",
169
+ flip: "Flip"
170
+ },
171
+ export: {
172
+ button: "Download as PDF",
173
+ exporting: "Creating PDF...",
174
+ success: "Download started!"
175
+ },
176
+ bill: {
177
+ descriptionText: "This voucher entitles you to {hours} {hourLabel} of my time or an equivalent thank you"
178
+ }
179
+ }, pe = { de, en: he };
180
+ function S(e) {
181
+ return pe[e];
182
+ }
183
+ function G(e, t, n) {
184
+ if (n && n.trim())
185
+ return n;
186
+ const a = S(e), r = t === 1 ? a.form.voucher.hourLabel : a.form.voucher.hoursLabel;
187
+ return a.bill.descriptionText.replace("{hours}", t.toString()).replace("{hourLabel}", r);
188
+ }
189
+ function Be() {
190
+ const e = g((r) => r.voucherConfig.language), t = g((r) => r.personalInfo), n = g((r) => r.setPersonalInfo), a = S(e);
191
+ return /* @__PURE__ */ h("div", { className: "space-y-4", children: [
192
+ /* @__PURE__ */ h("div", { className: "form-control", children: [
193
+ /* @__PURE__ */ o("label", { className: "label", children: /* @__PURE__ */ o("span", { className: "label-text font-medium", children: a.form.personalInfo.name }) }),
194
+ /* @__PURE__ */ o(
195
+ "input",
196
+ {
197
+ type: "text",
198
+ placeholder: a.form.personalInfo.namePlaceholder,
199
+ className: "input input-bordered w-full",
200
+ value: t.name,
201
+ onChange: (r) => n({ name: r.target.value })
202
+ }
203
+ )
204
+ ] }),
205
+ /* @__PURE__ */ h("div", { className: "form-control", children: [
206
+ /* @__PURE__ */ o("label", { className: "label", children: /* @__PURE__ */ o("span", { className: "label-text font-medium", children: a.form.personalInfo.email }) }),
207
+ /* @__PURE__ */ o(
208
+ "input",
209
+ {
210
+ type: "email",
211
+ placeholder: a.form.personalInfo.emailPlaceholder,
212
+ className: "input input-bordered w-full",
213
+ value: t.email,
214
+ onChange: (r) => n({ email: r.target.value })
215
+ }
216
+ )
217
+ ] }),
218
+ /* @__PURE__ */ h("div", { className: "form-control", children: [
219
+ /* @__PURE__ */ o("label", { className: "label", children: /* @__PURE__ */ o("span", { className: "label-text font-medium", children: a.form.personalInfo.phone }) }),
220
+ /* @__PURE__ */ o(
221
+ "input",
222
+ {
223
+ type: "tel",
224
+ placeholder: a.form.personalInfo.phonePlaceholder,
225
+ className: "input input-bordered w-full",
226
+ value: t.phone,
227
+ onChange: (r) => n({ phone: r.target.value })
228
+ }
229
+ )
230
+ ] })
231
+ ] });
232
+ }
233
+ const F = {}, me = "https://api.stability.ai/v1/generation", ue = {
234
+ vintage: "portrait in the style of vintage currency engraving, fine line work, crosshatching, sepia tones, detailed stippling, classic bank note portrait style",
235
+ engraved: "portrait as detailed intaglio engraving, currency bill style, fine parallel lines, high contrast, official government portrait",
236
+ currency: "portrait rendered as US dollar bill engraving, official currency portrait style, green tint, fine line engraving technique"
237
+ };
238
+ function ge(e) {
239
+ var i;
240
+ const t = e.split(","), n = ((i = t[0].match(/:(.*?);/)) == null ? void 0 : i[1]) || "image/png", a = atob(t[1]), r = a.length, s = new Uint8Array(r);
241
+ for (let d = 0; d < r; d++)
242
+ s[d] = a.charCodeAt(d);
243
+ return new Blob([s], { type: n });
244
+ }
245
+ function X() {
246
+ var t;
247
+ const e = typeof import.meta < "u" && (F == null ? void 0 : F.VITE_STABILITY_API_KEY) || typeof process < "u" && ((t = process.env) == null ? void 0 : t.NEXT_PUBLIC_STABILITY_API_KEY);
248
+ return e && e !== "your-api-key-here" ? e : typeof localStorage < "u" ? localStorage.getItem("stability_api_key") : null;
249
+ }
250
+ function fe(e) {
251
+ localStorage.setItem("stability_api_key", e);
252
+ }
253
+ function Y() {
254
+ return X() !== null;
255
+ }
256
+ async function be(e) {
257
+ const t = X();
258
+ if (!t)
259
+ throw new Error("No Stability AI API key configured");
260
+ const { imageDataUrl: n, style: a, strength: r = 0.35 } = e, s = ge(n), i = new FormData();
261
+ i.append("init_image", s, "portrait.png"), i.append("init_image_mode", "IMAGE_STRENGTH"), i.append("image_strength", String(1 - r)), i.append("text_prompts[0][text]", ue[a]), i.append("text_prompts[0][weight]", "1"), i.append("cfg_scale", "7"), i.append("samples", "1"), i.append("steps", "30");
262
+ const l = await fetch(`${me}/stable-diffusion-xl-1024-v1-0/image-to-image`, {
263
+ method: "POST",
264
+ headers: {
265
+ Authorization: `Bearer ${t}`,
266
+ Accept: "application/json"
267
+ },
268
+ body: i
269
+ });
270
+ if (!l.ok) {
271
+ const f = await l.text();
272
+ throw console.error("Stability AI error:", f), l.status === 401 ? new Error("Invalid API key") : l.status === 402 ? new Error("Insufficient credits") : l.status === 429 ? new Error("Rate limit exceeded. Please try again later.") : new Error(`API error: ${l.status}`);
273
+ }
274
+ const c = await l.json();
275
+ if (!c.artifacts || c.artifacts.length === 0)
276
+ throw new Error("No image generated");
277
+ return `data:image/png;base64,${c.artifacts[0].base64}`;
278
+ }
279
+ async function q(e) {
280
+ return new Promise((t, n) => {
281
+ const a = new Image();
282
+ a.onload = () => {
283
+ const r = document.createElement("canvas"), s = r.getContext("2d");
284
+ if (!s) {
285
+ n(new Error("Failed to get canvas context"));
286
+ return;
287
+ }
288
+ r.width = a.width, r.height = a.height, s.filter = "sepia(0.3) contrast(1.1) saturate(0.9)", s.drawImage(a, 0, 0), t(r.toDataURL("image/png"));
289
+ }, a.onerror = () => n(new Error("Failed to load image")), a.src = e;
290
+ });
291
+ }
292
+ function ve() {
293
+ const [e, t] = C(!1), [n, a] = C(null), [r, s] = C(Y()), i = E(() => a(null), []), d = E((c) => {
294
+ fe(c), s(!0), a(null);
295
+ }, []);
296
+ return {
297
+ enhance: E(
298
+ async (c, f = "vintage") => {
299
+ t(!0), a(null);
300
+ try {
301
+ return Y() ? await be({
302
+ imageDataUrl: c,
303
+ style: f,
304
+ strength: 0.35
305
+ }) : await q(c);
306
+ } catch (m) {
307
+ const b = m instanceof Error ? m.message : "Enhancement failed";
308
+ if (a(b), b.includes("API") || b.includes("key"))
309
+ try {
310
+ return await q(c);
311
+ } catch {
312
+ throw m;
313
+ }
314
+ throw m;
315
+ } finally {
316
+ t(!1);
317
+ }
318
+ },
319
+ []
320
+ ),
321
+ isEnhancing: e,
322
+ error: n,
323
+ hasKey: r,
324
+ setApiKey: d,
325
+ clearError: i
326
+ };
327
+ }
328
+ function ye({ isOpen: e, onClose: t, onSubmit: n }) {
329
+ const a = g((c) => c.voucherConfig.language), [r, s] = C("");
330
+ if (!e) return null;
331
+ const i = (c) => {
332
+ c.preventDefault(), r.trim() && (n(r.trim()), s(""), t());
333
+ }, l = {
334
+ de: {
335
+ title: "Stability AI API Key",
336
+ description: "Um die AI-Bildverbesserung zu nutzen, benötigst du einen Stability AI API Key. Du kannst ihn auf platform.stability.ai erhalten.",
337
+ placeholder: "sk-...",
338
+ submit: "Speichern",
339
+ cancel: "Abbrechen",
340
+ hint: "Der Key wird lokal in deinem Browser gespeichert."
341
+ },
342
+ en: {
343
+ title: "Stability AI API Key",
344
+ description: "To use AI image enhancement, you need a Stability AI API key. You can get one at platform.stability.ai.",
345
+ placeholder: "sk-...",
346
+ submit: "Save",
347
+ cancel: "Cancel",
348
+ hint: "The key is stored locally in your browser."
349
+ }
350
+ }[a];
351
+ return /* @__PURE__ */ h("dialog", { className: "modal modal-open", children: [
352
+ /* @__PURE__ */ h("div", { className: "modal-box", children: [
353
+ /* @__PURE__ */ o("h3", { className: "font-bold text-lg", children: l.title }),
354
+ /* @__PURE__ */ o("p", { className: "py-4 text-sm opacity-80", children: l.description }),
355
+ /* @__PURE__ */ h("form", { onSubmit: i, children: [
356
+ /* @__PURE__ */ h("div", { className: "form-control", children: [
357
+ /* @__PURE__ */ o(
358
+ "input",
359
+ {
360
+ type: "password",
361
+ placeholder: l.placeholder,
362
+ className: "input input-bordered w-full",
363
+ value: r,
364
+ onChange: (c) => s(c.target.value),
365
+ autoFocus: !0
366
+ }
367
+ ),
368
+ /* @__PURE__ */ o("label", { className: "label", children: /* @__PURE__ */ o("span", { className: "label-text-alt", children: l.hint }) })
369
+ ] }),
370
+ /* @__PURE__ */ h("div", { className: "modal-action", children: [
371
+ /* @__PURE__ */ o("button", { type: "button", className: "btn btn-ghost", onClick: t, children: l.cancel }),
372
+ /* @__PURE__ */ o("button", { type: "submit", className: "btn btn-primary", disabled: !r.trim(), children: l.submit })
373
+ ] })
374
+ ] })
375
+ ] }),
376
+ /* @__PURE__ */ o("form", { method: "dialog", className: "modal-backdrop", children: /* @__PURE__ */ o("button", { onClick: t, children: "close" }) })
377
+ ] });
378
+ }
379
+ function Re() {
380
+ const e = g((p) => p.voucherConfig.language), t = g((p) => p.portrait), n = g((p) => p.setPortrait), a = g((p) => p.setEnhancedPortrait), r = g((p) => p.toggleUseEnhanced), s = g((p) => p.setPortraitZoom), { enhance: i, isEnhancing: d, error: l, hasKey: c, setApiKey: f } = ve(), m = S(e), b = _(null), [y, u] = C(!1), [P, N] = C(!1), k = E(
381
+ (p) => {
382
+ if (!p.type.startsWith("image/"))
383
+ return;
384
+ const w = new FileReader();
385
+ w.onload = (H) => {
386
+ var K;
387
+ const ie = (K = H.target) == null ? void 0 : K.result;
388
+ n(ie);
389
+ }, w.readAsDataURL(p);
390
+ },
391
+ [n]
392
+ ), L = E(
393
+ (p) => {
394
+ p.preventDefault(), u(!1);
395
+ const w = p.dataTransfer.files[0];
396
+ w && k(w);
397
+ },
398
+ [k]
399
+ ), v = E((p) => {
400
+ p.preventDefault(), u(!0);
401
+ }, []), I = E((p) => {
402
+ p.preventDefault(), u(!1);
403
+ }, []), D = () => {
404
+ var p;
405
+ (p = b.current) == null || p.click();
406
+ }, $ = (p) => {
407
+ var H;
408
+ const w = (H = p.target.files) == null ? void 0 : H[0];
409
+ w && k(w);
410
+ }, M = async () => {
411
+ if (t.original) {
412
+ if (!c) {
413
+ N(!0);
414
+ return;
415
+ }
416
+ try {
417
+ const p = await i(t.original, "vintage");
418
+ a(p);
419
+ } catch (p) {
420
+ console.error("Enhancement failed:", p);
421
+ }
422
+ }
423
+ }, U = async (p) => {
424
+ if (f(p), t.original)
425
+ try {
426
+ const w = await i(t.original, "vintage");
427
+ a(w);
428
+ } catch (w) {
429
+ console.error("Enhancement failed:", w);
430
+ }
431
+ }, re = () => {
432
+ n(null);
433
+ }, oe = t.useEnhanced && t.enhanced ? t.enhanced : t.original;
434
+ return /* @__PURE__ */ h("div", { className: "space-y-4", children: [
435
+ t.original ? /* @__PURE__ */ h("div", { className: "space-y-4", children: [
436
+ /* @__PURE__ */ o("div", { className: "flex justify-center", children: /* @__PURE__ */ h("div", { className: "relative", children: [
437
+ /* @__PURE__ */ o("div", { className: "w-32 h-32 rounded-full overflow-hidden border-4 border-currency-gold shadow-lg", children: /* @__PURE__ */ o(
438
+ "img",
439
+ {
440
+ src: oe || "",
441
+ alt: "Portrait",
442
+ className: "w-full h-full object-cover",
443
+ style: { transform: `scale(${t.zoom})` }
444
+ }
445
+ ) }),
446
+ /* @__PURE__ */ o(
447
+ "button",
448
+ {
449
+ className: "btn btn-circle btn-xs btn-error absolute -top-1 -right-1",
450
+ onClick: re,
451
+ children: /* @__PURE__ */ o(
452
+ "svg",
453
+ {
454
+ xmlns: "http://www.w3.org/2000/svg",
455
+ className: "h-4 w-4",
456
+ fill: "none",
457
+ viewBox: "0 0 24 24",
458
+ stroke: "currentColor",
459
+ children: /* @__PURE__ */ o(
460
+ "path",
461
+ {
462
+ strokeLinecap: "round",
463
+ strokeLinejoin: "round",
464
+ strokeWidth: 2,
465
+ d: "M6 18L18 6M6 6l12 12"
466
+ }
467
+ )
468
+ }
469
+ )
470
+ }
471
+ )
472
+ ] }) }),
473
+ /* @__PURE__ */ h("div", { className: "form-control", children: [
474
+ /* @__PURE__ */ h("label", { className: "label", children: [
475
+ /* @__PURE__ */ o("span", { className: "label-text", children: m.form.portrait.zoom }),
476
+ /* @__PURE__ */ h("span", { className: "label-text-alt", children: [
477
+ Math.round(t.zoom * 100),
478
+ "%"
479
+ ] })
480
+ ] }),
481
+ /* @__PURE__ */ o(
482
+ "input",
483
+ {
484
+ type: "range",
485
+ min: "0.5",
486
+ max: "2",
487
+ step: "0.05",
488
+ value: t.zoom,
489
+ onChange: (p) => s(parseFloat(p.target.value)),
490
+ className: "range range-primary range-sm"
491
+ }
492
+ )
493
+ ] }),
494
+ c && /* @__PURE__ */ h("div", { className: "flex flex-col gap-2", children: [
495
+ /* @__PURE__ */ o(
496
+ "button",
497
+ {
498
+ className: `btn btn-secondary ${d ? "loading" : ""}`,
499
+ onClick: M,
500
+ disabled: d,
501
+ children: d ? /* @__PURE__ */ h(z, { children: [
502
+ /* @__PURE__ */ o("span", { className: "loading loading-spinner loading-sm" }),
503
+ m.form.portrait.enhancing
504
+ ] }) : /* @__PURE__ */ h(z, { children: [
505
+ /* @__PURE__ */ o(
506
+ "svg",
507
+ {
508
+ xmlns: "http://www.w3.org/2000/svg",
509
+ className: "h-5 w-5 mr-1",
510
+ fill: "none",
511
+ viewBox: "0 0 24 24",
512
+ stroke: "currentColor",
513
+ children: /* @__PURE__ */ o(
514
+ "path",
515
+ {
516
+ strokeLinecap: "round",
517
+ strokeLinejoin: "round",
518
+ strokeWidth: 2,
519
+ d: "M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"
520
+ }
521
+ )
522
+ }
523
+ ),
524
+ m.form.portrait.enhance
525
+ ] })
526
+ }
527
+ ),
528
+ l && /* @__PURE__ */ h("div", { className: "alert alert-warning text-sm py-2", children: [
529
+ /* @__PURE__ */ o("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: /* @__PURE__ */ o("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" }) }),
530
+ /* @__PURE__ */ o("span", { children: l })
531
+ ] }),
532
+ t.enhanced && /* @__PURE__ */ o("div", { className: "form-control", children: /* @__PURE__ */ h("label", { className: "label cursor-pointer justify-start gap-3", children: [
533
+ /* @__PURE__ */ o(
534
+ "input",
535
+ {
536
+ type: "checkbox",
537
+ className: "toggle toggle-primary",
538
+ checked: t.useEnhanced,
539
+ onChange: r
540
+ }
541
+ ),
542
+ /* @__PURE__ */ o("span", { className: "label-text", children: t.useEnhanced ? m.form.portrait.useEnhanced : m.form.portrait.useOriginal })
543
+ ] }) })
544
+ ] })
545
+ ] }) : /* @__PURE__ */ h(
546
+ "div",
547
+ {
548
+ className: `border-2 border-dashed rounded-lg p-8 text-center cursor-pointer transition-colors ${y ? "border-primary bg-primary/10" : "border-base-300 hover:border-primary hover:bg-base-200"}`,
549
+ onDrop: L,
550
+ onDragOver: v,
551
+ onDragLeave: I,
552
+ onClick: D,
553
+ children: [
554
+ /* @__PURE__ */ o(
555
+ "input",
556
+ {
557
+ ref: b,
558
+ type: "file",
559
+ accept: "image/*",
560
+ className: "hidden",
561
+ onChange: $
562
+ }
563
+ ),
564
+ /* @__PURE__ */ h("div", { className: "flex flex-col items-center gap-2", children: [
565
+ /* @__PURE__ */ o(
566
+ "svg",
567
+ {
568
+ xmlns: "http://www.w3.org/2000/svg",
569
+ className: "h-12 w-12 text-base-content/50",
570
+ fill: "none",
571
+ viewBox: "0 0 24 24",
572
+ stroke: "currentColor",
573
+ children: /* @__PURE__ */ o(
574
+ "path",
575
+ {
576
+ strokeLinecap: "round",
577
+ strokeLinejoin: "round",
578
+ strokeWidth: 2,
579
+ 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"
580
+ }
581
+ )
582
+ }
583
+ ),
584
+ /* @__PURE__ */ o("p", { className: "font-medium", children: m.form.portrait.upload }),
585
+ /* @__PURE__ */ o("p", { className: "text-sm text-base-content/60", children: m.form.portrait.dragDrop })
586
+ ] })
587
+ ]
588
+ }
589
+ ),
590
+ /* @__PURE__ */ o(
591
+ ye,
592
+ {
593
+ isOpen: P,
594
+ onClose: () => N(!1),
595
+ onSubmit: U
596
+ }
597
+ )
598
+ ] });
599
+ }
600
+ const we = [1, 5, 10];
601
+ function Me() {
602
+ const e = g((i) => i.voucherConfig.language), t = g((i) => i.voucherConfig), n = g((i) => i.setHours), a = g((i) => i.setVoucherConfig), r = S(e), s = (i) => i === 1 ? r.form.voucher.hourLabel : r.form.voucher.hoursLabel;
603
+ return /* @__PURE__ */ h("div", { className: "space-y-4", children: [
604
+ /* @__PURE__ */ h("div", { className: "form-control", children: [
605
+ /* @__PURE__ */ o("label", { className: "label", children: /* @__PURE__ */ o("span", { className: "label-text font-medium", children: r.form.voucher.hours }) }),
606
+ /* @__PURE__ */ o("div", { className: "join w-full", children: we.map((i) => /* @__PURE__ */ h(
607
+ "button",
608
+ {
609
+ className: `join-item btn flex-1 ${t.hours === i ? "btn-primary" : "btn-outline"}`,
610
+ onClick: () => n(i),
611
+ children: [
612
+ i,
613
+ " ",
614
+ s(i)
615
+ ]
616
+ },
617
+ i
618
+ )) })
619
+ ] }),
620
+ /* @__PURE__ */ h("div", { className: "form-control", children: [
621
+ /* @__PURE__ */ o("label", { className: "label", children: /* @__PURE__ */ o("span", { className: "label-text font-medium", children: r.form.voucher.description }) }),
622
+ /* @__PURE__ */ o(
623
+ "textarea",
624
+ {
625
+ className: "textarea textarea-bordered h-24 resize-none w-full",
626
+ placeholder: r.form.voucher.descriptionPlaceholder,
627
+ value: t.description,
628
+ onChange: (i) => a({ description: i.target.value }),
629
+ maxLength: 200
630
+ }
631
+ ),
632
+ /* @__PURE__ */ h("label", { className: "label", children: [
633
+ /* @__PURE__ */ o("span", { className: "label-text-alt" }),
634
+ /* @__PURE__ */ h("span", { className: "label-text-alt", children: [
635
+ t.description.length,
636
+ "/200"
637
+ ] })
638
+ ] })
639
+ ] })
640
+ ] });
641
+ }
642
+ const x = typeof import.meta < "u" && "/" || "/", xe = {
643
+ en: {
644
+ 1: {
645
+ front: `${x}templates/front_ldpi_en.png`,
646
+ back: `${x}templates/back_ldpi_en.png`,
647
+ width: 1536,
648
+ height: 1024
649
+ },
650
+ 5: {
651
+ front: `${x}templates/front_ldpi_en.png`,
652
+ back: `${x}templates/back_ldpi_en.png`,
653
+ width: 1536,
654
+ height: 1024
655
+ },
656
+ 10: {
657
+ front: `${x}templates/front_ldpi_en.png`,
658
+ back: `${x}templates/back_ldpi_en.png`,
659
+ width: 1536,
660
+ height: 1024
661
+ }
662
+ },
663
+ de: {
664
+ 1: {
665
+ front: `${x}templates/front_hdpi_de.webp`,
666
+ back: `${x}templates/back_hdpi_de.webp`,
667
+ width: 6144,
668
+ height: 3200
669
+ },
670
+ 5: {
671
+ front: `${x}templates/front_hdpi_de.webp`,
672
+ back: `${x}templates/back_hdpi_de.webp`,
673
+ width: 6144,
674
+ height: 3200
675
+ },
676
+ 10: {
677
+ front: `${x}templates/front_hdpi_de.webp`,
678
+ back: `${x}templates/back_hdpi_de.webp`,
679
+ width: 6144,
680
+ height: 3200
681
+ }
682
+ }
683
+ }, T = {
684
+ front: {
685
+ portrait: {
686
+ x: 768,
687
+ y: 490,
688
+ radiusX: 236,
689
+ radiusY: 258
690
+ },
691
+ namePlate: {
692
+ x: 768,
693
+ y: 848,
694
+ fontSize: 36,
695
+ maxWidth: 380,
696
+ align: "center"
697
+ }
698
+ },
699
+ back: {
700
+ portrait: {
701
+ x: 0,
702
+ y: 0,
703
+ radiusX: 0,
704
+ radiusY: 0
705
+ },
706
+ namePlate: {
707
+ x: 768,
708
+ y: 832,
709
+ fontSize: 36,
710
+ maxWidth: 380,
711
+ align: "center"
712
+ },
713
+ contactInfo: {
714
+ x: 380,
715
+ y: 500,
716
+ fontSize: 38,
717
+ lineHeight: 55,
718
+ align: "center"
719
+ },
720
+ description: {
721
+ x: 1150,
722
+ y: 500,
723
+ fontSize: 38,
724
+ maxWidth: 480,
725
+ lineHeight: 42,
726
+ align: "center"
727
+ }
728
+ }
729
+ }, A = {
730
+ front: {
731
+ portrait: {
732
+ x: 3074,
733
+ y: 1530,
734
+ radiusX: 942,
735
+ radiusY: 1020
736
+ },
737
+ namePlate: {
738
+ x: 3072,
739
+ y: 2950,
740
+ fontSize: 144,
741
+ maxWidth: 1520,
742
+ align: "center"
743
+ }
744
+ },
745
+ back: {
746
+ portrait: {
747
+ x: 0,
748
+ y: 0,
749
+ radiusX: 0,
750
+ radiusY: 0
751
+ },
752
+ namePlate: {
753
+ x: 3072,
754
+ y: 2930,
755
+ fontSize: 144,
756
+ maxWidth: 1520,
757
+ align: "center"
758
+ },
759
+ contactInfo: {
760
+ x: 1520,
761
+ y: 1680,
762
+ fontSize: 160,
763
+ lineHeight: 280,
764
+ align: "center"
765
+ },
766
+ description: {
767
+ x: 4600,
768
+ y: 1680,
769
+ fontSize: 145,
770
+ maxWidth: 2e3,
771
+ lineHeight: 210,
772
+ align: "center"
773
+ }
774
+ }
775
+ };
776
+ function J(e) {
777
+ return e === "de" ? A : T;
778
+ }
779
+ function Q(e, t) {
780
+ return xe[e][t];
781
+ }
782
+ const W = /* @__PURE__ */ new Map();
783
+ async function j(e) {
784
+ return W.has(e) ? W.get(e) : new Promise((t, n) => {
785
+ const a = new Image();
786
+ a.crossOrigin = "anonymous", a.onload = () => {
787
+ W.set(e, a), t(a);
788
+ }, a.onerror = n, a.src = e;
789
+ });
790
+ }
791
+ function ee(e, t, n, a) {
792
+ e.drawImage(t, 0, 0, n, a);
793
+ }
794
+ function ke(e, t, n, a, r, s, i = 1) {
795
+ e.save(), e.beginPath(), e.ellipse(n, a, r, s, 0, 0, Math.PI * 2), e.closePath(), e.clip();
796
+ const d = t.width / t.height, l = r / s, c = r * 2, f = s * 2;
797
+ let m, b;
798
+ d > l ? (b = f, m = f * d) : (m = c, b = c / d), m *= i, b *= i;
799
+ const y = n - m / 2, u = a - b / 2;
800
+ e.drawImage(t, y, u, m, b), e.restore();
801
+ }
802
+ function te(e, t, n, a = "#2a3a2a") {
803
+ 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();
804
+ }
805
+ function Ne(e, t, n, a = "#2a3a2a") {
806
+ e.save(), e.font = `${n.fontSize}px "Times New Roman", serif`, e.textAlign = n.align || "center", e.textBaseline = "top", e.fillStyle = a;
807
+ const r = n.maxWidth || 400, s = n.lineHeight || n.fontSize * 1.4, i = t.split(" "), d = [];
808
+ let l = "";
809
+ for (const m of i) {
810
+ const b = l ? `${l} ${m}` : m;
811
+ e.measureText(b).width > r && l ? (d.push(l), l = m) : l = b;
812
+ }
813
+ l && d.push(l);
814
+ const c = d.length * s;
815
+ let f = n.y - c / 2;
816
+ for (const m of d)
817
+ e.fillText(m, n.x, f), f += s;
818
+ e.restore();
819
+ }
820
+ function Ie(e, t, n, a, r, s = "#2a3a2a") {
821
+ e.save(), e.font = `${r.fontSize}px "Times New Roman", serif`, e.textAlign = r.align || "center", e.textBaseline = "middle", e.fillStyle = s;
822
+ const i = r.lineHeight || r.fontSize * 1.8, d = [t, n, a].filter(Boolean), l = (d.length - 1) * i;
823
+ let c = r.y - l / 2;
824
+ for (const f of d)
825
+ f && (e.fillText(f, r.x, c), c += i);
826
+ e.restore();
827
+ }
828
+ async function ne(e, t, n, a, r, s, i, d = 1) {
829
+ const l = e.getContext("2d");
830
+ if (!l) return;
831
+ e.width = s, e.height = i, l.clearRect(0, 0, s, i);
832
+ const c = await j(t);
833
+ if (ee(l, c, s, i), n)
834
+ try {
835
+ const f = await j(n);
836
+ ke(
837
+ l,
838
+ f,
839
+ r.portrait.x,
840
+ r.portrait.y,
841
+ r.portrait.radiusX,
842
+ r.portrait.radiusY,
843
+ d
844
+ );
845
+ } catch (f) {
846
+ console.error("Failed to load portrait:", f);
847
+ }
848
+ a && te(l, a, r.namePlate);
849
+ }
850
+ async function ae(e, t, n, a, r, s, i, d, l) {
851
+ const c = e.getContext("2d");
852
+ if (!c) return;
853
+ e.width = d, e.height = l, c.clearRect(0, 0, d, l);
854
+ const f = await j(t);
855
+ ee(c, f, d, l), i.contactInfo && (n || a || r) && Ie(c, n, a, r, i.contactInfo), i.description && s && Ne(c, s, i.description), n && te(c, n, i.namePlate);
856
+ }
857
+ function Ue() {
858
+ const e = g((v) => v.voucherConfig.language), t = g((v) => v.voucherConfig.hours), n = g((v) => v.voucherConfig.description), a = g((v) => v.personalInfo), r = g((v) => v.portrait), s = g((v) => v.currentSide), i = g((v) => v.flipSide), d = S(e), l = _(null), c = _(null), f = _(null), [m, b] = C(!1), y = Q(e, t), u = J(e), P = r.useEnhanced && r.enhanced ? r.enhanced : r.original, N = G(e, t, n);
859
+ O(() => {
860
+ l.current && ne(
861
+ l.current,
862
+ y.front,
863
+ P,
864
+ a.name,
865
+ u.front,
866
+ y.width,
867
+ y.height,
868
+ r.zoom
869
+ );
870
+ }, [y, P, a.name, u, r.zoom]), O(() => {
871
+ c.current && ae(
872
+ c.current,
873
+ y.back,
874
+ a.name,
875
+ a.email,
876
+ a.phone,
877
+ N,
878
+ u.back,
879
+ y.width,
880
+ y.height
881
+ );
882
+ }, [y, a, N, u]);
883
+ const k = () => {
884
+ b(!0), setTimeout(() => {
885
+ i(), b(!1);
886
+ }, 150);
887
+ }, L = y.width / y.height;
888
+ return /* @__PURE__ */ h("div", { className: "space-y-4", children: [
889
+ /* @__PURE__ */ h("div", { className: "flex justify-between items-center", children: [
890
+ /* @__PURE__ */ h("div", { className: "tabs tabs-boxed bg-base-200", children: [
891
+ /* @__PURE__ */ o(
892
+ "button",
893
+ {
894
+ className: `tab ${s === "front" ? "tab-active bg-primary text-primary-content font-semibold" : ""}`,
895
+ onClick: () => s !== "front" && k(),
896
+ children: d.preview.front
897
+ }
898
+ ),
899
+ /* @__PURE__ */ o(
900
+ "button",
901
+ {
902
+ className: `tab ${s === "back" ? "tab-active bg-primary text-primary-content font-semibold" : ""}`,
903
+ onClick: () => s !== "back" && k(),
904
+ children: d.preview.back
905
+ }
906
+ )
907
+ ] }),
908
+ /* @__PURE__ */ h("button", { className: "btn btn-ghost btn-sm", onClick: k, children: [
909
+ /* @__PURE__ */ o(
910
+ "svg",
911
+ {
912
+ xmlns: "http://www.w3.org/2000/svg",
913
+ className: "h-5 w-5",
914
+ fill: "none",
915
+ viewBox: "0 0 24 24",
916
+ stroke: "currentColor",
917
+ children: /* @__PURE__ */ o(
918
+ "path",
919
+ {
920
+ strokeLinecap: "round",
921
+ strokeLinejoin: "round",
922
+ strokeWidth: 2,
923
+ 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"
924
+ }
925
+ )
926
+ }
927
+ ),
928
+ d.preview.flip
929
+ ] })
930
+ ] }),
931
+ /* @__PURE__ */ h(
932
+ "div",
933
+ {
934
+ ref: f,
935
+ className: "relative w-full overflow-hidden shadow-lg",
936
+ style: { aspectRatio: L },
937
+ children: [
938
+ /* @__PURE__ */ o(
939
+ "canvas",
940
+ {
941
+ ref: l,
942
+ className: `absolute inset-0 w-full h-full transition-all duration-300 ${s === "front" ? m ? "opacity-0 scale-95" : "opacity-100 scale-100" : "opacity-0 scale-95 pointer-events-none"}`
943
+ }
944
+ ),
945
+ /* @__PURE__ */ o(
946
+ "canvas",
947
+ {
948
+ ref: c,
949
+ className: `absolute inset-0 w-full h-full transition-all duration-300 ${s === "back" ? m ? "opacity-0 scale-95" : "opacity-100 scale-100" : "opacity-0 scale-95 pointer-events-none"}`
950
+ }
951
+ )
952
+ ]
953
+ }
954
+ )
955
+ ] });
956
+ }
957
+ function Fe() {
958
+ const e = _(null), t = _(null);
959
+ return { frontCanvasRef: e, backCanvasRef: t };
960
+ }
961
+ async function Pe(e) {
962
+ const {
963
+ frontTemplateSrc: t,
964
+ backTemplateSrc: n,
965
+ templateWidth: a,
966
+ templateHeight: r,
967
+ layout: s,
968
+ portrait: i,
969
+ portraitZoom: d = 1,
970
+ name: l,
971
+ email: c,
972
+ phone: f,
973
+ description: m
974
+ } = e, b = document.createElement("canvas"), y = document.createElement("canvas");
975
+ await Promise.all([
976
+ ne(b, t, i, l, s.front, a, r, d),
977
+ ae(y, n, l, c, f, m, s.back, a, r)
978
+ ]);
979
+ const u = new ce({
980
+ orientation: "landscape",
981
+ unit: "mm",
982
+ format: "a4"
983
+ }), P = 297, N = 210, k = 10, L = a / r;
984
+ let v = P - k * 2, I = v / L;
985
+ I > N - k * 2 && (I = N - k * 2, v = I * L);
986
+ const D = (P - v) / 2, $ = (N - I) / 2, M = b.toDataURL("image/jpeg", 0.95);
987
+ u.addImage(M, "JPEG", D, $, v, I), u.addPage();
988
+ const U = y.toDataURL("image/jpeg", 0.95);
989
+ return u.addImage(U, "JPEG", D, $, v, I), u.output("blob");
990
+ }
991
+ function Ee(e, t) {
992
+ const n = URL.createObjectURL(e), a = document.createElement("a");
993
+ a.href = n, a.download = t, document.body.appendChild(a), a.click(), document.body.removeChild(a), URL.revokeObjectURL(n);
994
+ }
995
+ async function Ce(e) {
996
+ const t = await Pe(e);
997
+ Ee(t, e.filename);
998
+ }
999
+ function We() {
1000
+ const e = g((u) => u.voucherConfig.language), t = g((u) => u.voucherConfig.hours), n = g((u) => u.voucherConfig.description), a = g((u) => u.personalInfo), r = g((u) => u.portrait), s = g((u) => u.isExporting), i = g((u) => u.setIsExporting), d = S(e), l = Q(e, t), c = J(e), f = r.useEnhanced && r.enhanced ? r.enhanced : r.original, m = G(e, t, n), b = a.name.trim().length > 0;
1001
+ return /* @__PURE__ */ o(
1002
+ "button",
1003
+ {
1004
+ className: `btn btn-primary flex-1 ${s ? "loading" : ""}`,
1005
+ onClick: async () => {
1006
+ if (!(!b || s)) {
1007
+ i(!0);
1008
+ try {
1009
+ const u = `zeitgutschein-${t}h-${a.name.replace(/\s+/g, "-").toLowerCase()}.pdf`;
1010
+ await Ce({
1011
+ frontTemplateSrc: l.front,
1012
+ backTemplateSrc: l.back,
1013
+ templateWidth: l.width,
1014
+ templateHeight: l.height,
1015
+ layout: c,
1016
+ portrait: f,
1017
+ portraitZoom: r.zoom,
1018
+ name: a.name,
1019
+ email: a.email,
1020
+ phone: a.phone,
1021
+ description: m,
1022
+ filename: u
1023
+ });
1024
+ } catch (u) {
1025
+ console.error("PDF export failed:", u);
1026
+ } finally {
1027
+ i(!1);
1028
+ }
1029
+ }
1030
+ },
1031
+ disabled: !b || s,
1032
+ children: s ? /* @__PURE__ */ h(z, { children: [
1033
+ /* @__PURE__ */ o("span", { className: "loading loading-spinner loading-sm" }),
1034
+ d.export.exporting
1035
+ ] }) : /* @__PURE__ */ h(z, { children: [
1036
+ /* @__PURE__ */ o(
1037
+ "svg",
1038
+ {
1039
+ xmlns: "http://www.w3.org/2000/svg",
1040
+ className: "h-5 w-5",
1041
+ fill: "none",
1042
+ viewBox: "0 0 24 24",
1043
+ stroke: "currentColor",
1044
+ children: /* @__PURE__ */ o(
1045
+ "path",
1046
+ {
1047
+ strokeLinecap: "round",
1048
+ strokeLinejoin: "round",
1049
+ strokeWidth: 2,
1050
+ 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"
1051
+ }
1052
+ )
1053
+ }
1054
+ ),
1055
+ d.export.button
1056
+ ] })
1057
+ }
1058
+ );
1059
+ }
1060
+ function Se() {
1061
+ const e = g((a) => a.voucherConfig.language), t = g((a) => a.setLanguage), n = (a) => {
1062
+ t(a);
1063
+ };
1064
+ return /* @__PURE__ */ h("div", { className: "join", children: [
1065
+ /* @__PURE__ */ o(
1066
+ "button",
1067
+ {
1068
+ className: `join-item btn btn-sm ${e === "de" ? "btn-active btn-primary" : "btn-ghost"}`,
1069
+ onClick: () => n("de"),
1070
+ children: "DE"
1071
+ }
1072
+ ),
1073
+ /* @__PURE__ */ o(
1074
+ "button",
1075
+ {
1076
+ className: `join-item btn btn-sm ${e === "en" ? "btn-active btn-primary" : "btn-ghost"}`,
1077
+ onClick: () => n("en"),
1078
+ children: "EN"
1079
+ }
1080
+ )
1081
+ ] });
1082
+ }
1083
+ function je() {
1084
+ const e = g((n) => n.voucherConfig.language), t = S(e);
1085
+ return /* @__PURE__ */ h("div", { className: "navbar bg-currency-green text-currency-cream shadow-lg", children: [
1086
+ /* @__PURE__ */ o("div", { className: "navbar-start", children: /* @__PURE__ */ o("a", { className: "btn btn-ghost text-xl font-currency font-bold", children: t.header.title }) }),
1087
+ /* @__PURE__ */ o("div", { className: "navbar-center hidden sm:flex", children: /* @__PURE__ */ o("span", { className: "text-sm opacity-80", children: t.header.subtitle }) }),
1088
+ /* @__PURE__ */ o("div", { className: "navbar-end", children: /* @__PURE__ */ o(Se, {}) })
1089
+ ] });
1090
+ }
1091
+ const B = "/", Le = {
1092
+ id: "time-voucher-classic-de",
1093
+ name: "Zeitgutschein Classic",
1094
+ type: "time-voucher",
1095
+ category: "classic",
1096
+ images: {
1097
+ front: `${B}templates/front_hdpi_de.jpg`,
1098
+ back: `${B}templates/back_hdpi_de.jpg`,
1099
+ width: 6144,
1100
+ height: 4096
1101
+ },
1102
+ fields: [
1103
+ {
1104
+ id: "name",
1105
+ type: "text",
1106
+ label: { de: "Name", en: "Name" },
1107
+ required: !0,
1108
+ validation: { minLength: 1, maxLength: 50 }
1109
+ },
1110
+ {
1111
+ id: "hours",
1112
+ type: "select",
1113
+ label: { de: "Stunden", en: "Hours" },
1114
+ required: !0,
1115
+ options: ["1", "5", "10"]
1116
+ },
1117
+ {
1118
+ id: "portrait",
1119
+ type: "image",
1120
+ label: { de: "Portrait", en: "Portrait" },
1121
+ required: !1
1122
+ },
1123
+ {
1124
+ id: "email",
1125
+ type: "text",
1126
+ label: { de: "E-Mail", en: "Email" },
1127
+ required: !1
1128
+ },
1129
+ {
1130
+ id: "phone",
1131
+ type: "text",
1132
+ label: { de: "Telefon", en: "Phone" },
1133
+ required: !1
1134
+ },
1135
+ {
1136
+ id: "description",
1137
+ type: "textarea",
1138
+ label: { de: "Beschreibung", en: "Description" },
1139
+ required: !1,
1140
+ validation: { maxLength: 200 }
1141
+ }
1142
+ ],
1143
+ layout: {
1144
+ front: {
1145
+ portrait: A.front.portrait,
1146
+ name: A.front.namePlate
1147
+ },
1148
+ back: {
1149
+ name: A.back.namePlate,
1150
+ contactInfo: A.back.contactInfo,
1151
+ description: A.back.description
1152
+ }
1153
+ },
1154
+ languages: ["de"]
1155
+ }, Te = {
1156
+ id: "time-voucher-classic-en",
1157
+ name: "Time Voucher Classic",
1158
+ type: "time-voucher",
1159
+ category: "classic",
1160
+ images: {
1161
+ front: `${B}templates/front_ldpi_en.png`,
1162
+ back: `${B}templates/back_ldpi_en.png`,
1163
+ width: 1536,
1164
+ height: 1024
1165
+ },
1166
+ fields: [
1167
+ {
1168
+ id: "name",
1169
+ type: "text",
1170
+ label: { de: "Name", en: "Name" },
1171
+ required: !0,
1172
+ validation: { minLength: 1, maxLength: 50 }
1173
+ },
1174
+ {
1175
+ id: "hours",
1176
+ type: "select",
1177
+ label: { de: "Stunden", en: "Hours" },
1178
+ required: !0,
1179
+ options: ["1", "5", "10"]
1180
+ },
1181
+ {
1182
+ id: "portrait",
1183
+ type: "image",
1184
+ label: { de: "Portrait", en: "Portrait" },
1185
+ required: !1
1186
+ },
1187
+ {
1188
+ id: "email",
1189
+ type: "text",
1190
+ label: { de: "E-Mail", en: "Email" },
1191
+ required: !1
1192
+ },
1193
+ {
1194
+ id: "phone",
1195
+ type: "text",
1196
+ label: { de: "Telefon", en: "Phone" },
1197
+ required: !1
1198
+ },
1199
+ {
1200
+ id: "description",
1201
+ type: "textarea",
1202
+ label: { de: "Beschreibung", en: "Description" },
1203
+ required: !1,
1204
+ validation: { maxLength: 200 }
1205
+ }
1206
+ ],
1207
+ layout: {
1208
+ front: {
1209
+ portrait: T.front.portrait,
1210
+ name: T.front.namePlate
1211
+ },
1212
+ back: {
1213
+ name: T.back.namePlate,
1214
+ contactInfo: T.back.contactInfo,
1215
+ description: T.back.description
1216
+ }
1217
+ },
1218
+ languages: ["en"]
1219
+ }, Z = [
1220
+ Le,
1221
+ Te
1222
+ ], Ae = {
1223
+ async listTemplates(e) {
1224
+ let t = [...Z];
1225
+ 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;
1226
+ },
1227
+ async getTemplate(e) {
1228
+ const t = Z.find((n) => n.id === e);
1229
+ if (!t)
1230
+ throw new Error(`Template not found: ${e}`);
1231
+ return t;
1232
+ }
1233
+ };
1234
+ function Ke(e) {
1235
+ return e === "de" ? "time-voucher-classic-de" : "time-voucher-classic-en";
1236
+ }
1237
+ let R = Ae;
1238
+ function Oe(e) {
1239
+ R = e;
1240
+ }
1241
+ function Ve() {
1242
+ return R;
1243
+ }
1244
+ async function Ye(e) {
1245
+ return R.listTemplates(e);
1246
+ }
1247
+ async function qe(e) {
1248
+ return R.getTemplate(e);
1249
+ }
1250
+ export {
1251
+ ye as ApiKeyModal,
1252
+ Ue as BillPreview,
1253
+ We as ExportButton,
1254
+ je as Header,
1255
+ A as LAYOUT_HDPI,
1256
+ T as LAYOUT_LDPI,
1257
+ Se as LanguageToggle,
1258
+ Be as PersonalInfoForm,
1259
+ Re as PortraitUpload,
1260
+ xe as TEMPLATES,
1261
+ Me as VoucherConfig,
1262
+ Ee as downloadBlob,
1263
+ Ie as drawContactInfo,
1264
+ Ne as drawMultilineText,
1265
+ ke as drawOvalPortrait,
1266
+ ee as drawTemplate,
1267
+ te as drawText,
1268
+ be as enhancePortrait,
1269
+ q as enhancePortraitFallback,
1270
+ Ce as exportBillAsPDF,
1271
+ G as formatDescription,
1272
+ Pe as generateBillPDF,
1273
+ X as getApiKey,
1274
+ Ke as getDefaultTemplateId,
1275
+ J as getLayout,
1276
+ Q as getTemplate,
1277
+ qe as getTemplateById,
1278
+ Ve as getTemplateProvider,
1279
+ Y as hasApiKey,
1280
+ Ye as listTemplates,
1281
+ j as loadImage,
1282
+ ae as renderBackSide,
1283
+ ne as renderFrontSide,
1284
+ fe as setApiKey,
1285
+ Oe as setTemplateProvider,
1286
+ Ae as staticTemplateProvider,
1287
+ S as t,
1288
+ Fe as useBillCanvasRefs,
1289
+ g as useBillStore
1290
+ };