sa2kit 1.6.67 → 1.6.69

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.
Files changed (41) hide show
  1. package/dist/festivalCard/core/index.d.mts +8 -0
  2. package/dist/festivalCard/core/index.d.ts +8 -0
  3. package/dist/festivalCard/core/index.js +181 -0
  4. package/dist/festivalCard/core/index.js.map +1 -0
  5. package/dist/festivalCard/core/index.mjs +177 -0
  6. package/dist/festivalCard/core/index.mjs.map +1 -0
  7. package/dist/festivalCard/index.d.mts +5 -10
  8. package/dist/festivalCard/index.d.ts +5 -10
  9. package/dist/festivalCard/index.js +549 -173
  10. package/dist/festivalCard/index.js.map +1 -1
  11. package/dist/festivalCard/index.mjs +539 -153
  12. package/dist/festivalCard/index.mjs.map +1 -1
  13. package/dist/festivalCard/miniapp/index.d.mts +12 -0
  14. package/dist/festivalCard/miniapp/index.d.ts +12 -0
  15. package/dist/festivalCard/miniapp/index.js +341 -0
  16. package/dist/festivalCard/miniapp/index.js.map +1 -0
  17. package/dist/festivalCard/miniapp/index.mjs +329 -0
  18. package/dist/festivalCard/miniapp/index.mjs.map +1 -0
  19. package/dist/festivalCard/server/index.d.mts +6 -0
  20. package/dist/festivalCard/server/index.d.ts +6 -0
  21. package/dist/festivalCard/server/index.js +13 -0
  22. package/dist/festivalCard/server/index.js.map +1 -0
  23. package/dist/festivalCard/server/index.mjs +10 -0
  24. package/dist/festivalCard/server/index.mjs.map +1 -0
  25. package/dist/festivalCard/web/index.d.mts +31 -0
  26. package/dist/festivalCard/web/index.d.ts +31 -0
  27. package/dist/festivalCard/web/index.js +582 -0
  28. package/dist/festivalCard/web/index.js.map +1 -0
  29. package/dist/festivalCard/web/index.mjs +567 -0
  30. package/dist/festivalCard/web/index.mjs.map +1 -0
  31. package/dist/festivalCardService-C0fhTezx.d.ts +25 -0
  32. package/dist/festivalCardService-uSg0oNuD.d.mts +25 -0
  33. package/dist/index.d.mts +4 -1
  34. package/dist/index.d.ts +4 -1
  35. package/dist/index.js +562 -164
  36. package/dist/index.js.map +1 -1
  37. package/dist/index.mjs +552 -163
  38. package/dist/index.mjs.map +1 -1
  39. package/dist/types-B-tjQTGi.d.mts +62 -0
  40. package/dist/types-B-tjQTGi.d.ts +62 -0
  41. package/package.json +21 -1
@@ -1,206 +1,582 @@
1
1
  'use strict';
2
2
 
3
- var React = require('react');
4
- var THREE = require('three');
3
+ var React3 = require('react');
5
4
 
6
5
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
6
 
8
- function _interopNamespace(e) {
9
- if (e && e.__esModule) return e;
10
- var n = Object.create(null);
11
- if (e) {
12
- Object.keys(e).forEach(function (k) {
13
- if (k !== 'default') {
14
- var d = Object.getOwnPropertyDescriptor(e, k);
15
- Object.defineProperty(n, k, d.get ? d : {
16
- enumerable: true,
17
- get: function () { return e[k]; }
18
- });
19
- }
20
- });
21
- }
22
- n.default = e;
23
- return Object.freeze(n);
24
- }
7
+ var React3__default = /*#__PURE__*/_interopDefault(React3);
25
8
 
26
- var React__default = /*#__PURE__*/_interopDefault(React);
27
- var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
9
+ // src/festivalCard/core/defaults.ts
10
+ var DEFAULT_FESTIVAL_CARD_CONFIG = {
11
+ id: "default-festival-card",
12
+ name: "Holiday Card",
13
+ theme: "winter",
14
+ coverTitle: "Happy Holidays",
15
+ coverSubtitle: "Warm wishes for you",
16
+ background: {
17
+ colorA: "#0c1a34",
18
+ colorB: "#1f4f8a"
19
+ },
20
+ backgroundMusic: {
21
+ src: "",
22
+ loop: true,
23
+ autoPlay: false,
24
+ volume: 0.5
25
+ },
26
+ pages: [
27
+ {
28
+ id: "page-1",
29
+ title: "\u5C01\u9762",
30
+ background: { color: "#11284d" },
31
+ elements: [
32
+ {
33
+ id: "p1-text-1",
34
+ type: "text",
35
+ x: 50,
36
+ y: 20,
37
+ content: "\u65B0\u5E74\u5FEB\u4E50",
38
+ fontSize: 34,
39
+ fontWeight: 700,
40
+ align: "center",
41
+ color: "#f8fafc"
42
+ },
43
+ {
44
+ id: "p1-text-2",
45
+ type: "text",
46
+ x: 50,
47
+ y: 36,
48
+ content: "\u613F\u8FD9\u4E00\u5E74\u5E73\u5B89\u559C\u4E50",
49
+ fontSize: 18,
50
+ fontWeight: 500,
51
+ align: "center",
52
+ color: "#dbeafe"
53
+ },
54
+ {
55
+ id: "p1-image-1",
56
+ type: "image",
57
+ x: 50,
58
+ y: 68,
59
+ width: 72,
60
+ height: 42,
61
+ src: "https://images.unsplash.com/photo-1512389142860-9c449e58a543?auto=format&fit=crop&w=1200&q=80",
62
+ fit: "cover",
63
+ borderRadius: 16,
64
+ alt: "holiday"
65
+ }
66
+ ]
67
+ },
68
+ {
69
+ id: "page-2",
70
+ title: "\u795D\u798F",
71
+ background: { color: "#1a3766" },
72
+ elements: [
73
+ {
74
+ id: "p2-text-1",
75
+ type: "text",
76
+ x: 50,
77
+ y: 28,
78
+ content: "\u613F\u4F60\u65B0\u5C81\uFF1A",
79
+ fontSize: 28,
80
+ fontWeight: 700,
81
+ align: "center",
82
+ color: "#fef3c7"
83
+ },
84
+ {
85
+ id: "p2-text-2",
86
+ type: "text",
87
+ x: 50,
88
+ y: 42,
89
+ content: "\u6240\u5F97\u7686\u6240\u671F\uFF0C\u6240\u5931\u4EA6\u65E0\u788D",
90
+ fontSize: 18,
91
+ fontWeight: 500,
92
+ align: "center",
93
+ color: "#f8fafc"
94
+ },
95
+ {
96
+ id: "p2-text-3",
97
+ type: "text",
98
+ x: 50,
99
+ y: 55,
100
+ content: "\u613F\u4F60\u7684\u6BCF\u4E00\u6B65\u90FD\u8D70\u5411\u5149\u4EAE",
101
+ fontSize: 16,
102
+ fontWeight: 400,
103
+ align: "center",
104
+ color: "#dbeafe"
105
+ }
106
+ ]
107
+ },
108
+ {
109
+ id: "page-3",
110
+ title: "\u843D\u6B3E",
111
+ background: { color: "#11284d" },
112
+ elements: [
113
+ {
114
+ id: "p3-image-1",
115
+ type: "image",
116
+ x: 50,
117
+ y: 34,
118
+ width: 60,
119
+ height: 42,
120
+ src: "https://images.unsplash.com/photo-1456324504439-367cee3b3c32?auto=format&fit=crop&w=1200&q=80",
121
+ fit: "cover",
122
+ borderRadius: 14,
123
+ alt: "gift"
124
+ },
125
+ {
126
+ id: "p3-text-1",
127
+ type: "text",
128
+ x: 50,
129
+ y: 72,
130
+ content: "Best wishes, from SA2Kit",
131
+ fontSize: 18,
132
+ fontWeight: 600,
133
+ align: "center",
134
+ color: "#f8fafc"
135
+ }
136
+ ]
137
+ }
138
+ ]
139
+ };
28
140
 
29
- // src/festivalCard/components/FestivalCard3D.tsx
30
- var createSnow = (count) => {
31
- const positions = new Float32Array(count * 3);
32
- const speeds = new Float32Array(count);
33
- for (let i = 0; i < count; i++) {
34
- const i3 = i * 3;
35
- positions[i3] = (Math.random() - 0.5) * 16;
36
- positions[i3 + 1] = Math.random() * 10 + 1;
37
- positions[i3 + 2] = (Math.random() - 0.5) * 16;
38
- speeds[i] = 4e-3 + Math.random() * 0.01;
141
+ // src/festivalCard/core/normalize.ts
142
+ var ensurePage = (page, index) => ({
143
+ id: page.id || `page-${index + 1}`,
144
+ title: page.title || `\u7B2C ${index + 1} \u9875`,
145
+ elements: Array.isArray(page.elements) ? page.elements : [],
146
+ background: page.background || {}
147
+ });
148
+ var normalizeFestivalCardConfig = (config) => {
149
+ const pages = config?.pages && config.pages.length > 0 ? config.pages : DEFAULT_FESTIVAL_CARD_CONFIG.pages;
150
+ return {
151
+ ...DEFAULT_FESTIVAL_CARD_CONFIG,
152
+ ...config,
153
+ background: {
154
+ ...DEFAULT_FESTIVAL_CARD_CONFIG.background,
155
+ ...config?.background || {}
156
+ },
157
+ backgroundMusic: {
158
+ ...DEFAULT_FESTIVAL_CARD_CONFIG.backgroundMusic,
159
+ ...config?.backgroundMusic || {},
160
+ src: config?.backgroundMusic?.src ?? DEFAULT_FESTIVAL_CARD_CONFIG.backgroundMusic?.src ?? ""
161
+ },
162
+ pages: pages.map(ensurePage)
163
+ };
164
+ };
165
+ var resizeFestivalCardPages = (config, pageCount) => {
166
+ const safeCount = Math.max(1, Math.min(12, Math.floor(pageCount || 1)));
167
+ const nextPages = [...config.pages];
168
+ while (nextPages.length < safeCount) {
169
+ const idx = nextPages.length;
170
+ nextPages.push({
171
+ id: `page-${idx + 1}`,
172
+ title: `\u7B2C ${idx + 1} \u9875`,
173
+ elements: [],
174
+ background: {}
175
+ });
39
176
  }
40
- return { positions, speeds };
177
+ return {
178
+ ...config,
179
+ pages: nextPages.slice(0, safeCount)
180
+ };
41
181
  };
42
- var FestivalCard3D = ({
43
- title = "Happy Holidays",
44
- subtitle = "Wishing you joy and peace",
45
- className
46
- }) => {
47
- const mountRef = React.useRef(null);
48
- React.useEffect(() => {
49
- const mount = mountRef.current;
50
- if (!mount) return;
51
- const scene = new THREE__namespace.Scene();
52
- scene.fog = new THREE__namespace.Fog(528934, 12, 28);
53
- const camera = new THREE__namespace.PerspectiveCamera(50, mount.clientWidth / mount.clientHeight, 0.1, 100);
54
- camera.position.set(0, 2.6, 7.5);
55
- const renderer = new THREE__namespace.WebGLRenderer({ antialias: true, alpha: true });
56
- renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
57
- renderer.setSize(mount.clientWidth, mount.clientHeight);
58
- renderer.outputColorSpace = THREE__namespace.SRGBColorSpace;
59
- mount.appendChild(renderer.domElement);
60
- const ambientLight = new THREE__namespace.AmbientLight(9090303, 0.8);
61
- scene.add(ambientLight);
62
- const keyLight = new THREE__namespace.DirectionalLight(16777215, 1.25);
63
- keyLight.position.set(2, 5, 4);
64
- scene.add(keyLight);
65
- const fillLight = new THREE__namespace.PointLight(8050687, 0.9, 24);
66
- fillLight.position.set(-4, 3, -2);
67
- scene.add(fillLight);
68
- const floor = new THREE__namespace.Mesh(
69
- new THREE__namespace.CircleGeometry(12, 48),
70
- new THREE__namespace.MeshStandardMaterial({ color: 1056826, roughness: 0.95, metalness: 0.05 })
71
- );
72
- floor.rotation.x = -Math.PI / 2;
73
- floor.position.y = -1.2;
74
- scene.add(floor);
75
- const giftGroup = new THREE__namespace.Group();
76
- scene.add(giftGroup);
77
- const box = new THREE__namespace.Mesh(
78
- new THREE__namespace.BoxGeometry(2, 1.6, 2),
79
- new THREE__namespace.MeshStandardMaterial({ color: 14238053, roughness: 0.55, metalness: 0.2 })
80
- );
81
- giftGroup.add(box);
82
- const ribbonMaterial = new THREE__namespace.MeshStandardMaterial({ color: 16767354, roughness: 0.3, metalness: 0.5 });
83
- const verticalRibbon = new THREE__namespace.Mesh(new THREE__namespace.BoxGeometry(0.24, 1.7, 2.02), ribbonMaterial);
84
- const horizontalRibbon = new THREE__namespace.Mesh(new THREE__namespace.BoxGeometry(2.02, 1.7, 0.24), ribbonMaterial);
85
- giftGroup.add(verticalRibbon);
86
- giftGroup.add(horizontalRibbon);
87
- const lid = new THREE__namespace.Mesh(
88
- new THREE__namespace.BoxGeometry(2.15, 0.34, 2.15),
89
- new THREE__namespace.MeshStandardMaterial({ color: 13448278, roughness: 0.52, metalness: 0.2 })
90
- );
91
- lid.position.y = 0.98;
92
- giftGroup.add(lid);
93
- const bowLeft = new THREE__namespace.Mesh(new THREE__namespace.TorusGeometry(0.26, 0.08, 12, 32), ribbonMaterial);
94
- bowLeft.rotation.set(Math.PI / 2, Math.PI / 6, 0);
95
- bowLeft.position.set(-0.22, 1.14, 0);
96
- const bowRight = bowLeft.clone();
97
- bowRight.rotation.y = -Math.PI / 6;
98
- bowRight.position.x = 0.22;
99
- giftGroup.add(bowLeft, bowRight);
100
- giftGroup.position.y = -0.15;
101
- const { positions, speeds } = createSnow(260);
102
- const snowGeometry = new THREE__namespace.BufferGeometry();
103
- snowGeometry.setAttribute("position", new THREE__namespace.BufferAttribute(positions, 3));
104
- const snow = new THREE__namespace.Points(
105
- snowGeometry,
106
- new THREE__namespace.PointsMaterial({
107
- color: 15267071,
108
- size: 0.08,
109
- transparent: true,
110
- opacity: 0.92,
111
- depthWrite: false
112
- })
113
- );
114
- scene.add(snow);
115
- let rafId = 0;
116
- const clock = new THREE__namespace.Clock();
117
- const animate = () => {
118
- const elapsed = clock.getElapsedTime();
119
- const pos = snowGeometry.attributes.position;
120
- for (let i = 0; i < pos.count; i++) {
121
- const speed = speeds[i] ?? 0.01;
122
- const y = pos.getY(i) - speed;
123
- pos.setY(i, y < -1.1 ? 10 + Math.random() * 2 : y);
124
- pos.setX(i, pos.getX(i) + Math.sin(elapsed + i * 0.04) * 16e-4);
125
- }
126
- pos.needsUpdate = true;
127
- giftGroup.rotation.y = elapsed * 0.35;
128
- giftGroup.position.y = -0.15 + Math.sin(elapsed * 1.4) * 0.08;
129
- lid.position.y = 0.98 + Math.sin(elapsed * 2.2) * 0.08;
130
- renderer.render(scene, camera);
131
- rafId = window.requestAnimationFrame(animate);
132
- };
133
- const handleResize = () => {
134
- if (!mount) return;
135
- const width = mount.clientWidth;
136
- const height = mount.clientHeight;
137
- camera.aspect = width / height;
138
- camera.updateProjectionMatrix();
139
- renderer.setSize(width, height);
140
- };
141
- window.addEventListener("resize", handleResize);
142
- animate();
182
+ var useFestivalCardConfig = (options) => {
183
+ const [config, setConfig] = React3.useState(
184
+ () => normalizeFestivalCardConfig(options?.initialConfig || DEFAULT_FESTIVAL_CARD_CONFIG)
185
+ );
186
+ const [loading, setLoading] = React3.useState(Boolean(options?.fetchConfig));
187
+ const [saving, setSaving] = React3.useState(false);
188
+ React3.useEffect(() => {
189
+ if (!options?.fetchConfig) return;
190
+ let active = true;
191
+ void options.fetchConfig().then((value) => {
192
+ if (!active) return;
193
+ setConfig(normalizeFestivalCardConfig(value));
194
+ }).finally(() => {
195
+ if (active) setLoading(false);
196
+ });
143
197
  return () => {
144
- window.cancelAnimationFrame(rafId);
145
- window.removeEventListener("resize", handleResize);
146
- scene.traverse((obj) => {
147
- const mesh = obj;
148
- if (mesh.geometry) mesh.geometry.dispose();
149
- const material = mesh.material;
150
- if (Array.isArray(material)) material.forEach((m) => m.dispose());
151
- else material?.dispose();
152
- });
153
- renderer.dispose();
154
- mount.removeChild(renderer.domElement);
198
+ active = false;
155
199
  };
156
- }, []);
157
- return /* @__PURE__ */ React__default.default.createElement(
200
+ }, [options]);
201
+ const save = React3.useCallback(async () => {
202
+ if (!options?.onSave) return;
203
+ setSaving(true);
204
+ try {
205
+ await options.onSave(config);
206
+ } finally {
207
+ setSaving(false);
208
+ }
209
+ }, [config, options]);
210
+ return React3.useMemo(
211
+ () => ({
212
+ config,
213
+ setConfig,
214
+ loading,
215
+ saving,
216
+ save
217
+ }),
218
+ [config, loading, save, saving]
219
+ );
220
+ };
221
+ var elementStyle = (element) => ({
222
+ position: "absolute",
223
+ left: `${element.x}%`,
224
+ top: `${element.y}%`,
225
+ width: `${element.width ?? 70}%`,
226
+ height: element.height ? `${element.height}%` : void 0,
227
+ transform: "translate(-50%, -50%)"
228
+ });
229
+ var renderElement = (element) => {
230
+ if (element.type === "text") {
231
+ return /* @__PURE__ */ React3__default.default.createElement(
232
+ "div",
233
+ {
234
+ key: element.id,
235
+ style: {
236
+ ...elementStyle(element),
237
+ color: element.color || "#f8fafc",
238
+ fontSize: element.fontSize || 18,
239
+ fontWeight: element.fontWeight || 500,
240
+ textAlign: element.align || "left",
241
+ lineHeight: 1.45,
242
+ whiteSpace: "pre-wrap"
243
+ }
244
+ },
245
+ element.content
246
+ );
247
+ }
248
+ return /* @__PURE__ */ React3__default.default.createElement(
249
+ "img",
250
+ {
251
+ key: element.id,
252
+ src: element.src,
253
+ alt: element.alt || "festival-card-image",
254
+ style: {
255
+ ...elementStyle(element),
256
+ objectFit: element.fit || "cover",
257
+ borderRadius: element.borderRadius || 0,
258
+ overflow: "hidden",
259
+ boxShadow: "0 12px 30px rgba(2, 6, 23, 0.32)"
260
+ }
261
+ }
262
+ );
263
+ };
264
+ var FestivalCardPageRenderer = ({ page }) => {
265
+ return /* @__PURE__ */ React3__default.default.createElement(
158
266
  "div",
159
267
  {
160
- className,
161
268
  style: {
162
269
  position: "relative",
163
270
  width: "100%",
164
- minHeight: 420,
165
- borderRadius: 20,
271
+ height: "100%",
166
272
  overflow: "hidden",
167
- background: "radial-gradient(circle at 20% 20%, #244d8c 0%, #0c1a34 45%, #060d1f 100%)"
273
+ borderRadius: 16,
274
+ backgroundColor: page.background?.color || "#0f172a",
275
+ backgroundImage: page.background?.image ? `url(${page.background.image})` : void 0,
276
+ backgroundSize: "cover",
277
+ backgroundPosition: "center"
168
278
  }
169
279
  },
170
- /* @__PURE__ */ React__default.default.createElement("div", { ref: mountRef, style: { position: "absolute", inset: 0 } }),
171
- /* @__PURE__ */ React__default.default.createElement(
280
+ page.elements.map(renderElement)
281
+ );
282
+ };
283
+
284
+ // src/festivalCard/components/FestivalCardBook3D.tsx
285
+ var FestivalCardBook3D = ({ config, className }) => {
286
+ const [currentPage, setCurrentPage] = React3.useState(0);
287
+ const normalized = React3.useMemo(() => normalizeFestivalCardConfig(config), [config]);
288
+ const pages = normalized.pages;
289
+ const canPrev = currentPage > 0;
290
+ const canNext = currentPage < pages.length - 1;
291
+ return /* @__PURE__ */ React3__default.default.createElement("div", { className }, /* @__PURE__ */ React3__default.default.createElement(
292
+ "div",
293
+ {
294
+ style: {
295
+ width: "100%",
296
+ minHeight: 560,
297
+ borderRadius: 24,
298
+ padding: 24,
299
+ background: `linear-gradient(145deg, ${normalized.background?.colorA || "#0c1a34"} 0%, ${normalized.background?.colorB || "#1f4f8a"} 100%)`,
300
+ boxShadow: "0 26px 70px rgba(2, 6, 23, 0.45)"
301
+ }
302
+ },
303
+ /* @__PURE__ */ React3__default.default.createElement(
172
304
  "div",
173
305
  {
174
306
  style: {
175
- position: "absolute",
176
- inset: 0,
177
- pointerEvents: "none",
178
- background: "linear-gradient(180deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0.04) 35%, rgba(4,8,20,0.36) 100%)"
307
+ marginBottom: 14,
308
+ color: "#f8fafc",
309
+ fontSize: 14,
310
+ opacity: 0.9,
311
+ textAlign: "center"
179
312
  }
180
- }
313
+ },
314
+ normalized.coverTitle || "Festival Card",
315
+ " \xB7 \u7B2C ",
316
+ currentPage + 1,
317
+ " / ",
318
+ pages.length,
319
+ " \u9875"
181
320
  ),
182
- /* @__PURE__ */ React__default.default.createElement(
321
+ /* @__PURE__ */ React3__default.default.createElement("div", { style: { perspective: 1400, width: "100%", maxWidth: 920, margin: "0 auto" } }, /* @__PURE__ */ React3__default.default.createElement(
183
322
  "div",
184
323
  {
185
324
  style: {
186
- position: "absolute",
187
- left: 20,
188
- right: 20,
189
- bottom: 20,
190
- zIndex: 2,
191
- padding: "16px 18px",
192
- borderRadius: 14,
193
- backgroundColor: "rgba(8, 16, 35, 0.66)",
194
- border: "1px solid rgba(255, 255, 255, 0.16)",
195
- color: "#f8fafc"
325
+ position: "relative",
326
+ height: 460,
327
+ transformStyle: "preserve-3d"
196
328
  }
197
329
  },
198
- /* @__PURE__ */ React__default.default.createElement("div", { style: { fontSize: 26, fontWeight: 700, lineHeight: 1.2 } }, title),
199
- /* @__PURE__ */ React__default.default.createElement("div", { style: { marginTop: 6, fontSize: 15, opacity: 0.92 } }, subtitle)
200
- )
201
- );
330
+ pages.map((page, index) => {
331
+ const isFlipped = index < currentPage;
332
+ const zIndex = pages.length - index;
333
+ return /* @__PURE__ */ React3__default.default.createElement(
334
+ "div",
335
+ {
336
+ key: page.id,
337
+ style: {
338
+ position: "absolute",
339
+ inset: 0,
340
+ transformStyle: "preserve-3d",
341
+ transformOrigin: "left center",
342
+ transform: `rotateY(${isFlipped ? -170 : 0}deg)`,
343
+ transition: "transform 600ms cubic-bezier(0.2, 0.8, 0.2, 1)",
344
+ zIndex
345
+ }
346
+ },
347
+ /* @__PURE__ */ React3__default.default.createElement(
348
+ "div",
349
+ {
350
+ style: {
351
+ position: "absolute",
352
+ inset: 0,
353
+ backfaceVisibility: "hidden"
354
+ }
355
+ },
356
+ /* @__PURE__ */ React3__default.default.createElement(FestivalCardPageRenderer, { page })
357
+ ),
358
+ /* @__PURE__ */ React3__default.default.createElement(
359
+ "div",
360
+ {
361
+ style: {
362
+ position: "absolute",
363
+ inset: 0,
364
+ transform: "rotateY(180deg)",
365
+ backfaceVisibility: "hidden",
366
+ borderRadius: 16,
367
+ background: "#0f172a"
368
+ }
369
+ }
370
+ )
371
+ );
372
+ })
373
+ )),
374
+ /* @__PURE__ */ React3__default.default.createElement("div", { style: { display: "flex", justifyContent: "center", gap: 12, marginTop: 18 } }, /* @__PURE__ */ React3__default.default.createElement(
375
+ "button",
376
+ {
377
+ type: "button",
378
+ disabled: !canPrev,
379
+ onClick: () => setCurrentPage((p) => Math.max(0, p - 1)),
380
+ style: {
381
+ border: "none",
382
+ borderRadius: 999,
383
+ padding: "9px 16px",
384
+ fontSize: 14,
385
+ cursor: canPrev ? "pointer" : "not-allowed",
386
+ opacity: canPrev ? 1 : 0.4
387
+ }
388
+ },
389
+ "\u4E0A\u4E00\u9875"
390
+ ), /* @__PURE__ */ React3__default.default.createElement(
391
+ "button",
392
+ {
393
+ type: "button",
394
+ disabled: !canNext,
395
+ onClick: () => setCurrentPage((p) => Math.min(pages.length - 1, p + 1)),
396
+ style: {
397
+ border: "none",
398
+ borderRadius: 999,
399
+ padding: "9px 16px",
400
+ fontSize: 14,
401
+ cursor: canNext ? "pointer" : "not-allowed",
402
+ opacity: canNext ? 1 : 0.4
403
+ }
404
+ },
405
+ "\u4E0B\u4E00\u9875"
406
+ ))
407
+ ), normalized.backgroundMusic?.src ? /* @__PURE__ */ React3__default.default.createElement(
408
+ "audio",
409
+ {
410
+ src: normalized.backgroundMusic.src,
411
+ autoPlay: normalized.backgroundMusic.autoPlay,
412
+ loop: normalized.backgroundMusic.loop,
413
+ controls: true,
414
+ style: { width: "100%", marginTop: 10 }
415
+ }
416
+ ) : null);
417
+ };
418
+ var createTextElement = (pageIndex) => ({
419
+ id: `text-${Date.now()}-${pageIndex}`,
420
+ type: "text",
421
+ x: 50,
422
+ y: 50,
423
+ content: "\u8BF7\u8F93\u5165\u6587\u5B57",
424
+ fontSize: 18,
425
+ fontWeight: 500,
426
+ align: "center",
427
+ color: "#ffffff"
428
+ });
429
+ var createImageElement = (pageIndex) => ({
430
+ id: `image-${Date.now()}-${pageIndex}`,
431
+ type: "image",
432
+ x: 50,
433
+ y: 50,
434
+ width: 60,
435
+ height: 40,
436
+ src: "https://images.unsplash.com/photo-1482517967863-00e15c9b44be?auto=format&fit=crop&w=1200&q=80",
437
+ fit: "cover",
438
+ borderRadius: 12
439
+ });
440
+ var FestivalCardConfigEditor = ({ value, onChange }) => {
441
+ const [activePageIndex, setActivePageIndex] = React3.useState(0);
442
+ const page = value.pages[activePageIndex];
443
+ const canEditPage = Boolean(page);
444
+ const pageOptions = React3.useMemo(() => value.pages.map((_, index) => index), [value.pages]);
445
+ const updateElement = (elementId, patch) => {
446
+ onChange({
447
+ ...value,
448
+ pages: value.pages.map(
449
+ (p, pIndex) => pIndex === activePageIndex ? {
450
+ ...p,
451
+ elements: p.elements.map((el) => el.id === elementId ? { ...el, ...patch } : el)
452
+ } : p
453
+ )
454
+ });
455
+ };
456
+ return /* @__PURE__ */ React3__default.default.createElement("div", { style: { borderRadius: 16, background: "#0f172a", color: "#e2e8f0", padding: 16 } }, /* @__PURE__ */ React3__default.default.createElement("div", { style: { display: "grid", gap: 12 } }, /* @__PURE__ */ React3__default.default.createElement("label", { style: { display: "grid", gap: 6 } }, /* @__PURE__ */ React3__default.default.createElement("span", null, "\u9875\u9762\u6570\u91CF"), /* @__PURE__ */ React3__default.default.createElement(
457
+ "input",
458
+ {
459
+ type: "number",
460
+ min: 1,
461
+ max: 12,
462
+ value: value.pages.length,
463
+ onChange: (event) => onChange(resizeFestivalCardPages(value, Number(event.target.value)))
464
+ }
465
+ )), /* @__PURE__ */ React3__default.default.createElement("label", { style: { display: "grid", gap: 6 } }, /* @__PURE__ */ React3__default.default.createElement("span", null, "\u80CC\u666F\u97F3\u4E50 URL"), /* @__PURE__ */ React3__default.default.createElement(
466
+ "input",
467
+ {
468
+ type: "url",
469
+ value: value.backgroundMusic?.src || "",
470
+ onChange: (event) => onChange({
471
+ ...value,
472
+ backgroundMusic: {
473
+ ...value.backgroundMusic,
474
+ src: event.target.value
475
+ }
476
+ })
477
+ }
478
+ )), /* @__PURE__ */ React3__default.default.createElement("label", { style: { display: "grid", gap: 6 } }, /* @__PURE__ */ React3__default.default.createElement("span", null, "\u7F16\u8F91\u9875\u9762"), /* @__PURE__ */ React3__default.default.createElement("select", { value: activePageIndex, onChange: (event) => setActivePageIndex(Number(event.target.value)) }, pageOptions.map((index) => /* @__PURE__ */ React3__default.default.createElement("option", { key: index, value: index }, "\u7B2C ", index + 1, " \u9875"))))), canEditPage ? /* @__PURE__ */ React3__default.default.createElement("div", { style: { marginTop: 16 } }, /* @__PURE__ */ React3__default.default.createElement("div", { style: { display: "flex", gap: 8, marginBottom: 12 } }, /* @__PURE__ */ React3__default.default.createElement(
479
+ "button",
480
+ {
481
+ type: "button",
482
+ onClick: () => onChange({
483
+ ...value,
484
+ pages: value.pages.map(
485
+ (p, index) => index === activePageIndex ? { ...p, elements: [...p.elements, createTextElement(index)] } : p
486
+ )
487
+ })
488
+ },
489
+ "+ \u6587\u5B57"
490
+ ), /* @__PURE__ */ React3__default.default.createElement(
491
+ "button",
492
+ {
493
+ type: "button",
494
+ onClick: () => onChange({
495
+ ...value,
496
+ pages: value.pages.map(
497
+ (p, index) => index === activePageIndex ? { ...p, elements: [...p.elements, createImageElement(index)] } : p
498
+ )
499
+ })
500
+ },
501
+ "+ \u56FE\u7247"
502
+ )), /* @__PURE__ */ React3__default.default.createElement("div", { style: { display: "grid", gap: 10, maxHeight: 340, overflow: "auto" } }, (page?.elements ?? []).map((element) => /* @__PURE__ */ React3__default.default.createElement("div", { key: element.id, style: { border: "1px solid #334155", borderRadius: 10, padding: 10 } }, /* @__PURE__ */ React3__default.default.createElement("div", { style: { marginBottom: 8 } }, element.type.toUpperCase()), element.type === "text" ? /* @__PURE__ */ React3__default.default.createElement(
503
+ "textarea",
504
+ {
505
+ value: element.content,
506
+ onChange: (event) => updateElement(element.id, { content: event.target.value }),
507
+ rows: 3,
508
+ style: { width: "100%" }
509
+ }
510
+ ) : /* @__PURE__ */ React3__default.default.createElement(
511
+ "input",
512
+ {
513
+ type: "url",
514
+ value: element.src,
515
+ onChange: (event) => updateElement(element.id, { src: event.target.value }),
516
+ style: { width: "100%" }
517
+ }
518
+ ))))) : null);
519
+ };
520
+ var FestivalCardStudio = ({ initialConfig, fetchConfig, onSave }) => {
521
+ const { config, setConfig, loading, save, saving } = useFestivalCardConfig({
522
+ initialConfig: normalizeFestivalCardConfig(initialConfig),
523
+ fetchConfig,
524
+ onSave
525
+ });
526
+ if (loading) return /* @__PURE__ */ React3__default.default.createElement("div", null, "\u52A0\u8F7D\u4E2D...");
527
+ return /* @__PURE__ */ React3__default.default.createElement("div", { style: { display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 16 } }, /* @__PURE__ */ React3__default.default.createElement(FestivalCardBook3D, { config }), /* @__PURE__ */ React3__default.default.createElement("div", null, /* @__PURE__ */ React3__default.default.createElement(FestivalCardConfigEditor, { value: config, onChange: setConfig }), onSave ? /* @__PURE__ */ React3__default.default.createElement(
528
+ "button",
529
+ {
530
+ type: "button",
531
+ onClick: () => void save(),
532
+ disabled: saving,
533
+ style: { marginTop: 12, width: "100%", padding: "10px 16px" }
534
+ },
535
+ saving ? "\u4FDD\u5B58\u4E2D..." : "\u4FDD\u5B58\u914D\u7F6E"
536
+ ) : null));
202
537
  };
203
538
 
204
- exports.FestivalCard3D = FestivalCard3D;
539
+ // src/festivalCard/server/db.ts
540
+ var dbAdapter = null;
541
+ var getFestivalCardDb = () => dbAdapter;
542
+
543
+ // src/festivalCard/services/festivalCardService.ts
544
+ var FestivalCardService = class {
545
+ constructor(options) {
546
+ this.db = options?.db || getFestivalCardDb();
547
+ }
548
+ async getConfig(cardId = "default-festival-card") {
549
+ if (!this.db) return DEFAULT_FESTIVAL_CARD_CONFIG;
550
+ const config = await this.db.getConfig(cardId);
551
+ return normalizeFestivalCardConfig(config);
552
+ }
553
+ async saveConfig(cardId, config) {
554
+ const normalized = normalizeFestivalCardConfig(config);
555
+ if (!this.db) return normalized;
556
+ await this.db.saveConfig(cardId, normalized);
557
+ return normalized;
558
+ }
559
+ };
560
+ var memoryStore = /* @__PURE__ */ new Map();
561
+ var createInMemoryFestivalCardDb = () => ({
562
+ getConfig(id) {
563
+ return Promise.resolve(memoryStore.get(id) || null);
564
+ },
565
+ saveConfig(id, config) {
566
+ memoryStore.set(id, config);
567
+ return Promise.resolve();
568
+ }
569
+ });
570
+
571
+ exports.DEFAULT_FESTIVAL_CARD_CONFIG = DEFAULT_FESTIVAL_CARD_CONFIG;
572
+ exports.FestivalCardBook3D = FestivalCardBook3D;
573
+ exports.FestivalCardConfigEditor = FestivalCardConfigEditor;
574
+ exports.FestivalCardPageRenderer = FestivalCardPageRenderer;
575
+ exports.FestivalCardService = FestivalCardService;
576
+ exports.FestivalCardStudio = FestivalCardStudio;
577
+ exports.createInMemoryFestivalCardDb = createInMemoryFestivalCardDb;
578
+ exports.normalizeFestivalCardConfig = normalizeFestivalCardConfig;
579
+ exports.resizeFestivalCardPages = resizeFestivalCardPages;
580
+ exports.useFestivalCardConfig = useFestivalCardConfig;
205
581
  //# sourceMappingURL=index.js.map
206
582
  //# sourceMappingURL=index.js.map