sa2kit 1.6.89 → 1.6.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/{booking-473Db8Bo.d.mts → booking-BH7HM0D0.d.mts} +1 -0
- package/dist/{booking-473Db8Bo.d.ts → booking-BH7HM0D0.d.ts} +1 -0
- package/dist/{bookingAdminService-DqQ7hEGw.d.ts → bookingAdminService-nr1vOp6I.d.ts} +1 -1
- package/dist/{bookingAdminService-SBX4JA_U.d.mts → bookingAdminService-pvk2MY1r.d.mts} +1 -1
- package/dist/{client-Bkn6mRI7.d.ts → client-UDQ7uMFA.d.ts} +1 -1
- package/dist/{client-exYn2Qla.d.mts → client-jOToHJEx.d.mts} +1 -1
- package/dist/festivalCard/index.js +803 -212
- package/dist/festivalCard/index.js.map +1 -1
- package/dist/festivalCard/index.mjs +784 -193
- package/dist/festivalCard/index.mjs.map +1 -1
- package/dist/festivalCard/miniapp/index.js +162 -21
- package/dist/festivalCard/miniapp/index.js.map +1 -1
- package/dist/festivalCard/miniapp/index.mjs +153 -12
- package/dist/festivalCard/miniapp/index.mjs.map +1 -1
- package/dist/festivalCard/web/index.d.mts +17 -3
- package/dist/festivalCard/web/index.d.ts +17 -3
- package/dist/festivalCard/web/index.js +803 -212
- package/dist/festivalCard/web/index.js.map +1 -1
- package/dist/festivalCard/web/index.mjs +784 -193
- package/dist/festivalCard/web/index.mjs.map +1 -1
- package/dist/{index-z15F7afa.d.mts → index-Bs06cHTn.d.mts} +2 -2
- package/dist/{index-BJpxvH7X.d.ts → index-C-oNM7Gv.d.ts} +1 -1
- package/dist/{index-XTV6IU-M.d.ts → index-CUab5EBV.d.ts} +2 -2
- package/dist/{index-Cum2EknK.d.mts → index-CYDb3AKs.d.mts} +1 -1
- package/dist/{index-DyxLpkmm.d.mts → index-DBB4ad0S.d.mts} +2 -2
- package/dist/{index-CdTIsNsy.d.ts → index-DBHwbXrv.d.ts} +2 -2
- package/dist/index.js +575 -170
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +575 -170
- package/dist/index.mjs.map +1 -1
- package/dist/showmasterpiece/core.d.mts +3 -3
- package/dist/showmasterpiece/core.d.ts +3 -3
- package/dist/showmasterpiece/db.d.mts +2 -0
- package/dist/showmasterpiece/db.d.ts +2 -0
- package/dist/showmasterpiece/db.js +4 -2
- package/dist/showmasterpiece/db.js.map +1 -1
- package/dist/showmasterpiece/db.mjs +4 -2
- package/dist/showmasterpiece/db.mjs.map +1 -1
- package/dist/showmasterpiece/index.js +18 -2
- package/dist/showmasterpiece/index.js.map +1 -1
- package/dist/showmasterpiece/index.mjs +18 -2
- package/dist/showmasterpiece/index.mjs.map +1 -1
- package/dist/showmasterpiece/logic/index.d.mts +2 -2
- package/dist/showmasterpiece/logic/index.d.ts +2 -2
- package/dist/showmasterpiece/server/index.js +4 -2
- package/dist/showmasterpiece/server/index.js.map +1 -1
- package/dist/showmasterpiece/server/index.mjs +4 -2
- package/dist/showmasterpiece/server/index.mjs.map +1 -1
- package/dist/showmasterpiece/service/api/index.d.mts +1 -1
- package/dist/showmasterpiece/service/api/index.d.ts +1 -1
- package/dist/showmasterpiece/service/client-business/index.d.mts +3 -3
- package/dist/showmasterpiece/service/client-business/index.d.ts +3 -3
- package/dist/showmasterpiece/service/index.d.mts +6 -6
- package/dist/showmasterpiece/service/index.d.ts +6 -6
- package/dist/showmasterpiece/service/miniapp/index.d.mts +2 -2
- package/dist/showmasterpiece/service/miniapp/index.d.ts +2 -2
- package/dist/showmasterpiece/service/web/index.d.mts +4 -4
- package/dist/showmasterpiece/service/web/index.d.ts +4 -4
- package/dist/showmasterpiece/ui/miniapp/index.d.mts +2 -2
- package/dist/showmasterpiece/ui/miniapp/index.d.ts +2 -2
- package/dist/showmasterpiece/ui/miniapp/index.js +4 -3
- package/dist/showmasterpiece/ui/miniapp/index.js.map +1 -1
- package/dist/showmasterpiece/ui/miniapp/index.mjs +4 -3
- package/dist/showmasterpiece/ui/miniapp/index.mjs.map +1 -1
- package/dist/showmasterpiece/ui/web/index.js +18 -2
- package/dist/showmasterpiece/ui/web/index.js.map +1 -1
- package/dist/showmasterpiece/ui/web/index.mjs +18 -2
- package/dist/showmasterpiece/ui/web/index.mjs.map +1 -1
- package/dist/showmasterpiece/web/index.js +18 -2
- package/dist/showmasterpiece/web/index.js.map +1 -1
- package/dist/showmasterpiece/web/index.mjs +18 -2
- package/dist/showmasterpiece/web/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7420,15 +7420,92 @@ var renderElement = (element) => {
|
|
|
7420
7420
|
}
|
|
7421
7421
|
);
|
|
7422
7422
|
};
|
|
7423
|
-
var
|
|
7424
|
-
|
|
7425
|
-
|
|
7423
|
+
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
7424
|
+
var FestivalCardPageRenderer = ({
|
|
7425
|
+
page,
|
|
7426
|
+
editable = false,
|
|
7427
|
+
selectedElementId = null,
|
|
7428
|
+
onElementSelect,
|
|
7429
|
+
onElementChange
|
|
7430
|
+
}) => {
|
|
7431
|
+
const [draggingElementId, setDraggingElementId] = React69.useState(null);
|
|
7432
|
+
const [resizingElementId, setResizingElementId] = React69.useState(null);
|
|
7433
|
+
const stageRef = React69.useRef(null);
|
|
7434
|
+
const interactionRef = React69.useRef(null);
|
|
7435
|
+
const backgroundElement = React69.useMemo(
|
|
7436
|
+
() => page.elements.find(
|
|
7437
|
+
(element) => element.type === "image" && Boolean(element.isBackground)
|
|
7438
|
+
),
|
|
7439
|
+
[page]
|
|
7426
7440
|
);
|
|
7427
|
-
const foregroundElements =
|
|
7441
|
+
const foregroundElements = React69.useMemo(
|
|
7442
|
+
() => page.elements.filter((element) => !(element.type === "image" && element.isBackground)),
|
|
7443
|
+
[page]
|
|
7444
|
+
);
|
|
7445
|
+
const updateElementByPointer = (element, interaction, clientX, clientY) => {
|
|
7446
|
+
if (!onElementChange || interaction.rect.width <= 0 || interaction.rect.height <= 0) return;
|
|
7447
|
+
const xPercent = clamp((clientX - interaction.rect.left) / interaction.rect.width * 100, 0, 100);
|
|
7448
|
+
const yPercent = clamp((clientY - interaction.rect.top) / interaction.rect.height * 100, 0, 100);
|
|
7449
|
+
if (interaction.mode === "move") {
|
|
7450
|
+
onElementChange(element.id, { x: xPercent, y: yPercent });
|
|
7451
|
+
return;
|
|
7452
|
+
}
|
|
7453
|
+
const nextWidth = clamp(Math.abs(xPercent - element.x) * 2, 4, 100);
|
|
7454
|
+
if (element.type === "image") {
|
|
7455
|
+
const nextHeight = clamp(Math.abs(yPercent - element.y) * 2, 4, 100);
|
|
7456
|
+
onElementChange(element.id, { width: nextWidth, height: nextHeight });
|
|
7457
|
+
return;
|
|
7458
|
+
}
|
|
7459
|
+
onElementChange(element.id, { width: nextWidth });
|
|
7460
|
+
};
|
|
7461
|
+
const beginInteraction = (event, elementId, mode) => {
|
|
7462
|
+
if (!editable || !stageRef.current) return;
|
|
7463
|
+
event.preventDefault();
|
|
7464
|
+
event.stopPropagation();
|
|
7465
|
+
const rect = stageRef.current.getBoundingClientRect();
|
|
7466
|
+
interactionRef.current = {
|
|
7467
|
+
pointerId: event.pointerId,
|
|
7468
|
+
elementId,
|
|
7469
|
+
mode,
|
|
7470
|
+
rect
|
|
7471
|
+
};
|
|
7472
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
7473
|
+
onElementSelect?.(elementId);
|
|
7474
|
+
if (mode === "move") {
|
|
7475
|
+
setDraggingElementId(elementId);
|
|
7476
|
+
setResizingElementId(null);
|
|
7477
|
+
} else {
|
|
7478
|
+
setResizingElementId(elementId);
|
|
7479
|
+
setDraggingElementId(null);
|
|
7480
|
+
}
|
|
7481
|
+
const element = foregroundElements.find((item) => item.id === elementId);
|
|
7482
|
+
if (element) {
|
|
7483
|
+
updateElementByPointer(element, interactionRef.current, event.clientX, event.clientY);
|
|
7484
|
+
}
|
|
7485
|
+
};
|
|
7486
|
+
const handlePointerMove = (event) => {
|
|
7487
|
+
const interaction = interactionRef.current;
|
|
7488
|
+
if (!interaction || interaction.pointerId !== event.pointerId) return;
|
|
7489
|
+
const element = foregroundElements.find((item) => item.id === interaction.elementId);
|
|
7490
|
+
if (!element) return;
|
|
7491
|
+
updateElementByPointer(element, interaction, event.clientX, event.clientY);
|
|
7492
|
+
};
|
|
7493
|
+
const endInteraction = (event) => {
|
|
7494
|
+
const interaction = interactionRef.current;
|
|
7495
|
+
if (!interaction || interaction.pointerId !== event.pointerId) return;
|
|
7496
|
+
interactionRef.current = null;
|
|
7497
|
+
setDraggingElementId(null);
|
|
7498
|
+
setResizingElementId(null);
|
|
7499
|
+
};
|
|
7428
7500
|
return /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7429
7501
|
"div",
|
|
7430
7502
|
{
|
|
7431
|
-
|
|
7503
|
+
ref: stageRef,
|
|
7504
|
+
onPointerMove: editable ? handlePointerMove : void 0,
|
|
7505
|
+
onPointerUp: editable ? endInteraction : void 0,
|
|
7506
|
+
onPointerCancel: editable ? endInteraction : void 0,
|
|
7507
|
+
onClick: editable ? () => onElementSelect?.(null) : void 0,
|
|
7508
|
+
className: `relative h-full w-full overflow-hidden rounded-2xl ${editable ? "touch-none" : ""}`,
|
|
7432
7509
|
style: {
|
|
7433
7510
|
backgroundColor: page.background?.color || "#0f172a",
|
|
7434
7511
|
backgroundImage: backgroundElement ? `url(${backgroundElement.src})` : page.background?.image ? `url(${page.background.image})` : void 0,
|
|
@@ -7437,17 +7514,249 @@ var FestivalCardPageRenderer = ({ page }) => {
|
|
|
7437
7514
|
}
|
|
7438
7515
|
},
|
|
7439
7516
|
/* @__PURE__ */ React69__namespace.default.createElement("div", { className: "absolute inset-0 bg-slate-950/20" }),
|
|
7440
|
-
foregroundElements.map(
|
|
7517
|
+
foregroundElements.map((element) => {
|
|
7518
|
+
if (!editable) {
|
|
7519
|
+
return renderElement(element);
|
|
7520
|
+
}
|
|
7521
|
+
const isSelected = selectedElementId === element.id;
|
|
7522
|
+
const isDragging = draggingElementId === element.id;
|
|
7523
|
+
const isResizing = resizingElementId === element.id;
|
|
7524
|
+
return /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7525
|
+
"div",
|
|
7526
|
+
{
|
|
7527
|
+
key: element.id,
|
|
7528
|
+
role: "button",
|
|
7529
|
+
tabIndex: 0,
|
|
7530
|
+
onClick: (event) => {
|
|
7531
|
+
event.stopPropagation();
|
|
7532
|
+
onElementSelect?.(element.id);
|
|
7533
|
+
},
|
|
7534
|
+
onPointerDown: (event) => beginInteraction(event, element.id, "move"),
|
|
7535
|
+
className: `absolute select-none touch-none rounded-md ${isDragging ? "cursor-grabbing" : isResizing ? "cursor-se-resize" : "cursor-grab"} ${isSelected ? "ring-2 ring-sky-300" : "ring-1 ring-white/40"}`,
|
|
7536
|
+
style: {
|
|
7537
|
+
...elementStyle(element),
|
|
7538
|
+
zIndex: isSelected ? 4 : 2
|
|
7539
|
+
}
|
|
7540
|
+
},
|
|
7541
|
+
element.type === "text" ? /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7542
|
+
"div",
|
|
7543
|
+
{
|
|
7544
|
+
className: "rounded-md bg-black/20 px-2 py-1",
|
|
7545
|
+
style: {
|
|
7546
|
+
color: element.color || "#f8fafc",
|
|
7547
|
+
fontSize: element.fontSize || 18,
|
|
7548
|
+
fontWeight: element.fontWeight || 500,
|
|
7549
|
+
fontFamily: element.fontFamily || "inherit",
|
|
7550
|
+
textAlign: element.align || "left",
|
|
7551
|
+
lineHeight: 1.45,
|
|
7552
|
+
whiteSpace: "pre-wrap"
|
|
7553
|
+
}
|
|
7554
|
+
},
|
|
7555
|
+
element.content
|
|
7556
|
+
) : /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7557
|
+
"img",
|
|
7558
|
+
{
|
|
7559
|
+
src: element.src,
|
|
7560
|
+
alt: element.alt || "festival-card-image",
|
|
7561
|
+
draggable: false,
|
|
7562
|
+
className: "pointer-events-none h-full w-full",
|
|
7563
|
+
style: {
|
|
7564
|
+
objectFit: element.fit || "cover",
|
|
7565
|
+
borderRadius: element.borderRadius || 0,
|
|
7566
|
+
overflow: "hidden",
|
|
7567
|
+
boxShadow: "0 12px 30px rgba(2, 6, 23, 0.32)"
|
|
7568
|
+
}
|
|
7569
|
+
}
|
|
7570
|
+
),
|
|
7571
|
+
/* @__PURE__ */ React69__namespace.default.createElement(
|
|
7572
|
+
"button",
|
|
7573
|
+
{
|
|
7574
|
+
type: "button",
|
|
7575
|
+
"aria-label": "resize",
|
|
7576
|
+
onPointerDown: (event) => beginInteraction(event, element.id, "resize"),
|
|
7577
|
+
className: "absolute -bottom-2 -right-2 h-4 w-4 rounded-full border border-white bg-sky-500 shadow"
|
|
7578
|
+
}
|
|
7579
|
+
)
|
|
7580
|
+
);
|
|
7581
|
+
})
|
|
7441
7582
|
);
|
|
7442
7583
|
};
|
|
7443
7584
|
|
|
7444
7585
|
// src/festivalCard/components/FestivalCardBook3D.tsx
|
|
7445
|
-
var
|
|
7446
|
-
const
|
|
7586
|
+
var loadImage2 = (src) => new Promise((resolve, reject) => {
|
|
7587
|
+
const image = new window.Image();
|
|
7588
|
+
image.crossOrigin = "anonymous";
|
|
7589
|
+
image.decoding = "async";
|
|
7590
|
+
image.onload = () => resolve(image);
|
|
7591
|
+
image.onerror = () => reject(new Error(`\u56FE\u7247\u52A0\u8F7D\u5931\u8D25: ${src}`));
|
|
7592
|
+
image.src = src;
|
|
7593
|
+
});
|
|
7594
|
+
var drawImageWithFit = (ctx, image, left, top, width, height, fit) => {
|
|
7595
|
+
const imageRatio = image.width / image.height;
|
|
7596
|
+
const boxRatio = width / height;
|
|
7597
|
+
let drawWidth = width;
|
|
7598
|
+
let drawHeight = height;
|
|
7599
|
+
let offsetX = left;
|
|
7600
|
+
let offsetY = top;
|
|
7601
|
+
if (fit === "cover") {
|
|
7602
|
+
if (imageRatio > boxRatio) {
|
|
7603
|
+
drawHeight = height;
|
|
7604
|
+
drawWidth = height * imageRatio;
|
|
7605
|
+
offsetX = left - (drawWidth - width) / 2;
|
|
7606
|
+
} else {
|
|
7607
|
+
drawWidth = width;
|
|
7608
|
+
drawHeight = width / imageRatio;
|
|
7609
|
+
offsetY = top - (drawHeight - height) / 2;
|
|
7610
|
+
}
|
|
7611
|
+
} else if (imageRatio > boxRatio) {
|
|
7612
|
+
drawWidth = width;
|
|
7613
|
+
drawHeight = width / imageRatio;
|
|
7614
|
+
offsetY = top + (height - drawHeight) / 2;
|
|
7615
|
+
} else {
|
|
7616
|
+
drawHeight = height;
|
|
7617
|
+
drawWidth = height * imageRatio;
|
|
7618
|
+
offsetX = left + (width - drawWidth) / 2;
|
|
7619
|
+
}
|
|
7620
|
+
ctx.drawImage(image, offsetX, offsetY, drawWidth, drawHeight);
|
|
7621
|
+
};
|
|
7622
|
+
var withRoundedClip = (ctx, left, top, width, height, radius, draw) => {
|
|
7623
|
+
const safeRadius = Math.max(0, Math.min(radius, Math.min(width, height) / 2));
|
|
7624
|
+
if (safeRadius <= 0) {
|
|
7625
|
+
draw();
|
|
7626
|
+
return;
|
|
7627
|
+
}
|
|
7628
|
+
ctx.save();
|
|
7629
|
+
ctx.beginPath();
|
|
7630
|
+
ctx.moveTo(left + safeRadius, top);
|
|
7631
|
+
ctx.lineTo(left + width - safeRadius, top);
|
|
7632
|
+
ctx.quadraticCurveTo(left + width, top, left + width, top + safeRadius);
|
|
7633
|
+
ctx.lineTo(left + width, top + height - safeRadius);
|
|
7634
|
+
ctx.quadraticCurveTo(left + width, top + height, left + width - safeRadius, top + height);
|
|
7635
|
+
ctx.lineTo(left + safeRadius, top + height);
|
|
7636
|
+
ctx.quadraticCurveTo(left, top + height, left, top + height - safeRadius);
|
|
7637
|
+
ctx.lineTo(left, top + safeRadius);
|
|
7638
|
+
ctx.quadraticCurveTo(left, top, left + safeRadius, top);
|
|
7639
|
+
ctx.closePath();
|
|
7640
|
+
ctx.clip();
|
|
7641
|
+
draw();
|
|
7642
|
+
ctx.restore();
|
|
7643
|
+
};
|
|
7644
|
+
var drawMultilineText = (ctx, text5, left, top, maxWidth, lineHeight) => {
|
|
7645
|
+
const paragraphs = text5.split("\n");
|
|
7646
|
+
let currentY = top;
|
|
7647
|
+
paragraphs.forEach((paragraph, index) => {
|
|
7648
|
+
const words = paragraph.split("");
|
|
7649
|
+
let line = "";
|
|
7650
|
+
for (const word of words) {
|
|
7651
|
+
const testLine = line + word;
|
|
7652
|
+
if (ctx.measureText(testLine).width > maxWidth && line) {
|
|
7653
|
+
ctx.fillText(line, left, currentY);
|
|
7654
|
+
line = word;
|
|
7655
|
+
currentY += lineHeight;
|
|
7656
|
+
} else {
|
|
7657
|
+
line = testLine;
|
|
7658
|
+
}
|
|
7659
|
+
}
|
|
7660
|
+
ctx.fillText(line, left, currentY);
|
|
7661
|
+
currentY += lineHeight;
|
|
7662
|
+
if (index < paragraphs.length - 1) {
|
|
7663
|
+
currentY += lineHeight * 0.2;
|
|
7664
|
+
}
|
|
7665
|
+
});
|
|
7666
|
+
};
|
|
7667
|
+
var exportPageToPng = async (page, fileName) => {
|
|
7668
|
+
const width = 1080;
|
|
7669
|
+
const height = 1440;
|
|
7670
|
+
const canvas = document.createElement("canvas");
|
|
7671
|
+
canvas.width = width;
|
|
7672
|
+
canvas.height = height;
|
|
7673
|
+
const ctx = canvas.getContext("2d");
|
|
7674
|
+
if (!ctx) throw new Error("\u65E0\u6CD5\u521B\u5EFA Canvas \u4E0A\u4E0B\u6587");
|
|
7675
|
+
ctx.fillStyle = page.background?.color || "#0f172a";
|
|
7676
|
+
ctx.fillRect(0, 0, width, height);
|
|
7677
|
+
const backgroundElement = page.elements.find(
|
|
7678
|
+
(element) => element.type === "image" && Boolean(element.isBackground)
|
|
7679
|
+
);
|
|
7680
|
+
const backgroundImageSrc = backgroundElement?.src || page.background?.image;
|
|
7681
|
+
if (backgroundImageSrc) {
|
|
7682
|
+
const image = await loadImage2(backgroundImageSrc);
|
|
7683
|
+
drawImageWithFit(ctx, image, 0, 0, width, height, "cover");
|
|
7684
|
+
}
|
|
7685
|
+
const foregroundElements = page.elements.filter((element) => !(element.type === "image" && element.isBackground));
|
|
7686
|
+
for (const element of foregroundElements) {
|
|
7687
|
+
const elementWidth = width * (element.width ?? 70) / 100;
|
|
7688
|
+
const elementHeight = element.height ? height * element.height / 100 : void 0;
|
|
7689
|
+
const centerX = width * element.x / 100;
|
|
7690
|
+
const centerY = height * element.y / 100;
|
|
7691
|
+
const left = centerX - elementWidth / 2;
|
|
7692
|
+
if (element.type === "image") {
|
|
7693
|
+
const image = await loadImage2(element.src);
|
|
7694
|
+
const drawHeight = elementHeight ?? elementWidth;
|
|
7695
|
+
const boxTop = centerY - drawHeight / 2;
|
|
7696
|
+
withRoundedClip(ctx, left, boxTop, elementWidth, drawHeight, element.borderRadius ?? 0, () => {
|
|
7697
|
+
drawImageWithFit(ctx, image, left, boxTop, elementWidth, drawHeight, element.fit || "cover");
|
|
7698
|
+
});
|
|
7699
|
+
continue;
|
|
7700
|
+
}
|
|
7701
|
+
const fontSize = (element.fontSize || 18) * 1.5;
|
|
7702
|
+
ctx.fillStyle = element.color || "#f8fafc";
|
|
7703
|
+
ctx.font = `${element.fontWeight || 500} ${fontSize}px ${element.fontFamily || "sans-serif"}`;
|
|
7704
|
+
ctx.textBaseline = "top";
|
|
7705
|
+
ctx.textAlign = element.align || "left";
|
|
7706
|
+
const textX = element.align === "center" ? centerX : element.align === "right" ? left + elementWidth : left;
|
|
7707
|
+
drawMultilineText(ctx, element.content || "", textX, centerY - fontSize * 0.72, elementWidth, fontSize * 1.45);
|
|
7708
|
+
}
|
|
7709
|
+
const blob = await new Promise((resolve) => canvas.toBlob(resolve, "image/png"));
|
|
7710
|
+
if (!blob) throw new Error("\u5BFC\u51FA\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
|
|
7711
|
+
const url = URL.createObjectURL(blob);
|
|
7712
|
+
const anchor = document.createElement("a");
|
|
7713
|
+
anchor.href = url;
|
|
7714
|
+
anchor.download = fileName;
|
|
7715
|
+
anchor.click();
|
|
7716
|
+
URL.revokeObjectURL(url);
|
|
7717
|
+
};
|
|
7718
|
+
var FestivalCardBook3D = ({
|
|
7719
|
+
config,
|
|
7720
|
+
className,
|
|
7721
|
+
editable = false,
|
|
7722
|
+
enableExportImage = !editable,
|
|
7723
|
+
currentPage: currentPageProp,
|
|
7724
|
+
onCurrentPageChange,
|
|
7725
|
+
selectedElementId = null,
|
|
7726
|
+
onSelectedElementChange,
|
|
7727
|
+
onElementChange
|
|
7728
|
+
}) => {
|
|
7729
|
+
const [internalCurrentPage, setInternalCurrentPage] = React69.useState(0);
|
|
7730
|
+
const [exporting, setExporting] = React69.useState(false);
|
|
7447
7731
|
const normalized = React69.useMemo(() => normalizeFestivalCardConfig(config), [config]);
|
|
7448
7732
|
const pages = normalized.pages;
|
|
7733
|
+
const currentPage = typeof currentPageProp === "number" ? currentPageProp : internalCurrentPage;
|
|
7734
|
+
const setCurrentPage = (updater) => {
|
|
7735
|
+
const prev = currentPage;
|
|
7736
|
+
const nextValue = typeof updater === "function" ? updater(prev) : updater;
|
|
7737
|
+
if (typeof currentPageProp === "number") {
|
|
7738
|
+
onCurrentPageChange?.(nextValue);
|
|
7739
|
+
return;
|
|
7740
|
+
}
|
|
7741
|
+
setInternalCurrentPage(nextValue);
|
|
7742
|
+
onCurrentPageChange?.(nextValue);
|
|
7743
|
+
};
|
|
7449
7744
|
const canPrev = currentPage > 0;
|
|
7450
7745
|
const canNext = currentPage < pages.length - 1;
|
|
7746
|
+
const currentPageData = pages[currentPage];
|
|
7747
|
+
const handleExportCurrentPage = async () => {
|
|
7748
|
+
if (!currentPageData || exporting) return;
|
|
7749
|
+
setExporting(true);
|
|
7750
|
+
try {
|
|
7751
|
+
const base = normalized.id || "festival-card";
|
|
7752
|
+
const fileName = `${base}-page-${currentPage + 1}.png`;
|
|
7753
|
+
await exportPageToPng(currentPageData, fileName);
|
|
7754
|
+
} catch (error) {
|
|
7755
|
+
window.alert(error.message || "\u5BFC\u51FA\u56FE\u7247\u5931\u8D25");
|
|
7756
|
+
} finally {
|
|
7757
|
+
setExporting(false);
|
|
7758
|
+
}
|
|
7759
|
+
};
|
|
7451
7760
|
return /* @__PURE__ */ React69__namespace.default.createElement("div", { className }, /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "w-full min-h-screen px-0 py-4" }, /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "mx-auto w-full text-center text-slate-100" }, /* @__PURE__ */ React69__namespace.default.createElement("h3", { className: "mb-3 text-lg font-semibold" }, normalized.coverTitle || "Festival Card")), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "mx-auto w-full" }, /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "relative h-[calc(100vh-170px)] min-h-[460px]" }, pages.map((page, index) => /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7452
7761
|
"div",
|
|
7453
7762
|
{
|
|
@@ -7458,7 +7767,16 @@ var FestivalCardBook3D = ({ config, className }) => {
|
|
|
7458
7767
|
pointerEvents: index === currentPage ? "auto" : "none"
|
|
7459
7768
|
}
|
|
7460
7769
|
},
|
|
7461
|
-
/* @__PURE__ */ React69__namespace.default.createElement(
|
|
7770
|
+
/* @__PURE__ */ React69__namespace.default.createElement(
|
|
7771
|
+
FestivalCardPageRenderer,
|
|
7772
|
+
{
|
|
7773
|
+
page,
|
|
7774
|
+
editable: editable && index === currentPage,
|
|
7775
|
+
selectedElementId,
|
|
7776
|
+
onElementSelect: onSelectedElementChange,
|
|
7777
|
+
onElementChange: (elementId, patch) => onElementChange?.(index, elementId, patch)
|
|
7778
|
+
}
|
|
7779
|
+
)
|
|
7462
7780
|
)))), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "mt-4 flex justify-center gap-3" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7463
7781
|
"button",
|
|
7464
7782
|
{
|
|
@@ -7486,6 +7804,24 @@ var FestivalCardBook3D = ({ config, className }) => {
|
|
|
7486
7804
|
controls: true,
|
|
7487
7805
|
className: "mt-3 w-full"
|
|
7488
7806
|
}
|
|
7807
|
+
) : null, enableExportImage ? /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7808
|
+
FloatingMenu_default,
|
|
7809
|
+
{
|
|
7810
|
+
initialPosition: { x: 24, y: 120 },
|
|
7811
|
+
trigger: /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "text-lg leading-none text-slate-700", "aria-hidden": true }, "\u2301"),
|
|
7812
|
+
menu: /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "text-xs font-semibold tracking-wide text-slate-500" }, "\u8D3A\u5361\u5DE5\u5177"), /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7813
|
+
"button",
|
|
7814
|
+
{
|
|
7815
|
+
type: "button",
|
|
7816
|
+
onClick: () => void handleExportCurrentPage(),
|
|
7817
|
+
disabled: exporting,
|
|
7818
|
+
className: "rounded-lg bg-sky-600 px-3 py-2 text-left text-sm font-medium text-white disabled:opacity-60"
|
|
7819
|
+
},
|
|
7820
|
+
exporting ? "\u5BFC\u51FA\u4E2D..." : `\u5BFC\u51FA\u7B2C ${currentPage + 1} \u9875 PNG`
|
|
7821
|
+
)),
|
|
7822
|
+
triggerClassName: "bg-white/95 backdrop-blur",
|
|
7823
|
+
menuClassName: "bg-white/95 backdrop-blur"
|
|
7824
|
+
}
|
|
7489
7825
|
) : null);
|
|
7490
7826
|
};
|
|
7491
7827
|
var createTextElement = (pageIndex) => ({
|
|
@@ -7512,8 +7848,22 @@ var createImageElement = (pageIndex) => ({
|
|
|
7512
7848
|
fit: "cover",
|
|
7513
7849
|
borderRadius: 12
|
|
7514
7850
|
});
|
|
7515
|
-
var FestivalCardConfigEditor = ({
|
|
7516
|
-
|
|
7851
|
+
var FestivalCardConfigEditor = ({
|
|
7852
|
+
value,
|
|
7853
|
+
onChange,
|
|
7854
|
+
activePageIndex: activePageIndexProp,
|
|
7855
|
+
onActivePageIndexChange,
|
|
7856
|
+
selectedElementId
|
|
7857
|
+
}) => {
|
|
7858
|
+
const [internalActivePageIndex, setInternalActivePageIndex] = React69.useState(0);
|
|
7859
|
+
const activePageIndex = activePageIndexProp ?? internalActivePageIndex;
|
|
7860
|
+
const setActivePageIndex = (index) => {
|
|
7861
|
+
if (typeof activePageIndexProp === "number") {
|
|
7862
|
+
onActivePageIndexChange?.(index);
|
|
7863
|
+
return;
|
|
7864
|
+
}
|
|
7865
|
+
setInternalActivePageIndex(index);
|
|
7866
|
+
};
|
|
7517
7867
|
const page = value.pages[activePageIndex];
|
|
7518
7868
|
const canEditPage = Boolean(page);
|
|
7519
7869
|
const pageOptions = React69.useMemo(() => value.pages.map((_, index) => index), [value.pages]);
|
|
@@ -7646,166 +7996,174 @@ var FestivalCardConfigEditor = ({ value, onChange }) => {
|
|
|
7646
7996
|
className: "rounded-lg bg-sky-600 px-3 py-2 text-sm font-medium text-white"
|
|
7647
7997
|
},
|
|
7648
7998
|
"+ \u56FE\u7247"
|
|
7649
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid max-h-[340px] gap-2.5 overflow-auto pr-1" }, (page?.elements ?? []).map((element) => /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7650
|
-
"
|
|
7651
|
-
{
|
|
7652
|
-
type: "button",
|
|
7653
|
-
onClick: () => removeElement(element.id),
|
|
7654
|
-
className: "rounded-md border border-rose-300 bg-rose-50 px-2 py-1 text-xs font-medium text-rose-700"
|
|
7655
|
-
},
|
|
7656
|
-
"\u5220\u9664"
|
|
7657
|
-
)), element.type === "text" ? /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7658
|
-
"textarea",
|
|
7659
|
-
{
|
|
7660
|
-
value: element.content,
|
|
7661
|
-
onChange: (event) => updateElement(element.id, { content: event.target.value }),
|
|
7662
|
-
rows: 3,
|
|
7663
|
-
className: "w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
|
|
7664
|
-
}
|
|
7665
|
-
), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2 sm:grid-cols-2" }, /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "X(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7666
|
-
"input",
|
|
7667
|
-
{
|
|
7668
|
-
type: "number",
|
|
7669
|
-
value: element.x,
|
|
7670
|
-
onChange: (event) => updateElement(element.id, { x: Number(event.target.value) }),
|
|
7671
|
-
className: numberFieldClassName
|
|
7672
|
-
}
|
|
7673
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "Y(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7674
|
-
"input",
|
|
7675
|
-
{
|
|
7676
|
-
type: "number",
|
|
7677
|
-
value: element.y,
|
|
7678
|
-
onChange: (event) => updateElement(element.id, { y: Number(event.target.value) }),
|
|
7679
|
-
className: numberFieldClassName
|
|
7680
|
-
}
|
|
7681
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5BBD\u5EA6(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7682
|
-
"input",
|
|
7683
|
-
{
|
|
7684
|
-
type: "number",
|
|
7685
|
-
value: element.width ?? 70,
|
|
7686
|
-
onChange: (event) => updateElement(element.id, { width: Number(event.target.value) }),
|
|
7687
|
-
className: numberFieldClassName
|
|
7688
|
-
}
|
|
7689
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5B57\u53F7(px)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7690
|
-
"input",
|
|
7691
|
-
{
|
|
7692
|
-
type: "number",
|
|
7693
|
-
value: element.fontSize ?? 18,
|
|
7694
|
-
onChange: (event) => updateElement(element.id, { fontSize: Number(event.target.value) }),
|
|
7695
|
-
className: numberFieldClassName
|
|
7696
|
-
}
|
|
7697
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5B57\u91CD", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7698
|
-
"input",
|
|
7699
|
-
{
|
|
7700
|
-
type: "number",
|
|
7701
|
-
min: 100,
|
|
7702
|
-
max: 900,
|
|
7703
|
-
step: 100,
|
|
7704
|
-
value: element.fontWeight ?? 500,
|
|
7705
|
-
onChange: (event) => updateElement(element.id, { fontWeight: Number(event.target.value) }),
|
|
7706
|
-
className: numberFieldClassName
|
|
7707
|
-
}
|
|
7708
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5BF9\u9F50", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7709
|
-
"select",
|
|
7710
|
-
{
|
|
7711
|
-
value: element.align || "left",
|
|
7712
|
-
onChange: (event) => updateElement(element.id, { align: event.target.value }),
|
|
7713
|
-
className: numberFieldClassName
|
|
7714
|
-
},
|
|
7715
|
-
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "left" }, "left"),
|
|
7716
|
-
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "center" }, "center"),
|
|
7717
|
-
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "right" }, "right")
|
|
7718
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600 sm:col-span-2" }, "\u5B57\u4F53", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7719
|
-
"input",
|
|
7720
|
-
{
|
|
7721
|
-
type: "text",
|
|
7722
|
-
value: element.fontFamily || "",
|
|
7723
|
-
onChange: (event) => updateElement(element.id, { fontFamily: event.target.value }),
|
|
7724
|
-
placeholder: "inherit / serif / sans-serif / PingFang SC",
|
|
7725
|
-
className: numberFieldClassName
|
|
7726
|
-
}
|
|
7727
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600 sm:col-span-2" }, "\u6587\u5B57\u989C\u8272", /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid grid-cols-[64px_1fr] gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7728
|
-
"input",
|
|
7729
|
-
{
|
|
7730
|
-
type: "color",
|
|
7731
|
-
value: element.color || "#ffffff",
|
|
7732
|
-
onChange: (event) => updateElement(element.id, { color: event.target.value }),
|
|
7733
|
-
className: "h-10 rounded-lg border border-slate-300 bg-white p-1"
|
|
7734
|
-
}
|
|
7735
|
-
), /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7736
|
-
"input",
|
|
7737
|
-
{
|
|
7738
|
-
type: "text",
|
|
7739
|
-
value: element.color || "#ffffff",
|
|
7740
|
-
onChange: (event) => updateElement(element.id, { color: event.target.value }),
|
|
7741
|
-
className: numberFieldClassName
|
|
7742
|
-
}
|
|
7743
|
-
))))) : /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7744
|
-
"input",
|
|
7745
|
-
{
|
|
7746
|
-
type: "url",
|
|
7747
|
-
value: element.src,
|
|
7748
|
-
onChange: (event) => updateElement(element.id, { src: event.target.value }),
|
|
7749
|
-
className: "w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
|
|
7750
|
-
}
|
|
7751
|
-
), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2 sm:grid-cols-2" }, /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "X(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7752
|
-
"input",
|
|
7753
|
-
{
|
|
7754
|
-
type: "number",
|
|
7755
|
-
value: element.x,
|
|
7756
|
-
onChange: (event) => updateElement(element.id, { x: Number(event.target.value) }),
|
|
7757
|
-
className: numberFieldClassName
|
|
7758
|
-
}
|
|
7759
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "Y(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7760
|
-
"input",
|
|
7761
|
-
{
|
|
7762
|
-
type: "number",
|
|
7763
|
-
value: element.y,
|
|
7764
|
-
onChange: (event) => updateElement(element.id, { y: Number(event.target.value) }),
|
|
7765
|
-
className: numberFieldClassName
|
|
7766
|
-
}
|
|
7767
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5BBD\u5EA6(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7768
|
-
"input",
|
|
7769
|
-
{
|
|
7770
|
-
type: "number",
|
|
7771
|
-
value: element.width ?? 60,
|
|
7772
|
-
onChange: (event) => updateElement(element.id, { width: Number(event.target.value) }),
|
|
7773
|
-
className: numberFieldClassName
|
|
7774
|
-
}
|
|
7775
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u9AD8\u5EA6(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7776
|
-
"input",
|
|
7777
|
-
{
|
|
7778
|
-
type: "number",
|
|
7779
|
-
value: element.height ?? 40,
|
|
7780
|
-
onChange: (event) => updateElement(element.id, { height: Number(event.target.value) }),
|
|
7781
|
-
className: numberFieldClassName
|
|
7782
|
-
}
|
|
7783
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5706\u89D2(px)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7784
|
-
"input",
|
|
7785
|
-
{
|
|
7786
|
-
type: "number",
|
|
7787
|
-
value: element.borderRadius ?? 0,
|
|
7788
|
-
onChange: (event) => updateElement(element.id, { borderRadius: Number(event.target.value) }),
|
|
7789
|
-
className: numberFieldClassName
|
|
7790
|
-
}
|
|
7791
|
-
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u586B\u5145", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7792
|
-
"select",
|
|
7999
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid max-h-[340px] gap-2.5 overflow-auto pr-1" }, (page?.elements ?? []).map((element) => /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8000
|
+
"div",
|
|
7793
8001
|
{
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
className: numberFieldClassName
|
|
8002
|
+
key: element.id,
|
|
8003
|
+
className: `rounded-xl border bg-slate-50 p-3 ${selectedElementId === element.id ? "border-sky-400 ring-2 ring-sky-100" : "border-slate-200"}`
|
|
7797
8004
|
},
|
|
7798
|
-
/* @__PURE__ */ React69__namespace.default.createElement("
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
}
|
|
7808
|
-
|
|
8005
|
+
/* @__PURE__ */ React69__namespace.default.createElement("div", { className: "mb-2 flex items-center justify-between" }, /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "text-xs font-semibold tracking-wide text-slate-500" }, element.type.toUpperCase()), /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8006
|
+
"button",
|
|
8007
|
+
{
|
|
8008
|
+
type: "button",
|
|
8009
|
+
onClick: () => removeElement(element.id),
|
|
8010
|
+
className: "rounded-md border border-rose-300 bg-rose-50 px-2 py-1 text-xs font-medium text-rose-700"
|
|
8011
|
+
},
|
|
8012
|
+
"\u5220\u9664"
|
|
8013
|
+
)),
|
|
8014
|
+
element.type === "text" ? /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8015
|
+
"textarea",
|
|
8016
|
+
{
|
|
8017
|
+
value: element.content,
|
|
8018
|
+
onChange: (event) => updateElement(element.id, { content: event.target.value }),
|
|
8019
|
+
rows: 3,
|
|
8020
|
+
className: "w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
|
|
8021
|
+
}
|
|
8022
|
+
), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2 sm:grid-cols-2" }, /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "X(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8023
|
+
"input",
|
|
8024
|
+
{
|
|
8025
|
+
type: "number",
|
|
8026
|
+
value: element.x,
|
|
8027
|
+
onChange: (event) => updateElement(element.id, { x: Number(event.target.value) }),
|
|
8028
|
+
className: numberFieldClassName
|
|
8029
|
+
}
|
|
8030
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "Y(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8031
|
+
"input",
|
|
8032
|
+
{
|
|
8033
|
+
type: "number",
|
|
8034
|
+
value: element.y,
|
|
8035
|
+
onChange: (event) => updateElement(element.id, { y: Number(event.target.value) }),
|
|
8036
|
+
className: numberFieldClassName
|
|
8037
|
+
}
|
|
8038
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5BBD\u5EA6(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8039
|
+
"input",
|
|
8040
|
+
{
|
|
8041
|
+
type: "number",
|
|
8042
|
+
value: element.width ?? 70,
|
|
8043
|
+
onChange: (event) => updateElement(element.id, { width: Number(event.target.value) }),
|
|
8044
|
+
className: numberFieldClassName
|
|
8045
|
+
}
|
|
8046
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5B57\u53F7(px)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8047
|
+
"input",
|
|
8048
|
+
{
|
|
8049
|
+
type: "number",
|
|
8050
|
+
value: element.fontSize ?? 18,
|
|
8051
|
+
onChange: (event) => updateElement(element.id, { fontSize: Number(event.target.value) }),
|
|
8052
|
+
className: numberFieldClassName
|
|
8053
|
+
}
|
|
8054
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5B57\u91CD", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8055
|
+
"input",
|
|
8056
|
+
{
|
|
8057
|
+
type: "number",
|
|
8058
|
+
min: 100,
|
|
8059
|
+
max: 900,
|
|
8060
|
+
step: 100,
|
|
8061
|
+
value: element.fontWeight ?? 500,
|
|
8062
|
+
onChange: (event) => updateElement(element.id, { fontWeight: Number(event.target.value) }),
|
|
8063
|
+
className: numberFieldClassName
|
|
8064
|
+
}
|
|
8065
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5BF9\u9F50", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8066
|
+
"select",
|
|
8067
|
+
{
|
|
8068
|
+
value: element.align || "left",
|
|
8069
|
+
onChange: (event) => updateElement(element.id, { align: event.target.value }),
|
|
8070
|
+
className: numberFieldClassName
|
|
8071
|
+
},
|
|
8072
|
+
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "left" }, "left"),
|
|
8073
|
+
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "center" }, "center"),
|
|
8074
|
+
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "right" }, "right")
|
|
8075
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600 sm:col-span-2" }, "\u5B57\u4F53", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8076
|
+
"input",
|
|
8077
|
+
{
|
|
8078
|
+
type: "text",
|
|
8079
|
+
value: element.fontFamily || "",
|
|
8080
|
+
onChange: (event) => updateElement(element.id, { fontFamily: event.target.value }),
|
|
8081
|
+
placeholder: "inherit / serif / sans-serif / PingFang SC",
|
|
8082
|
+
className: numberFieldClassName
|
|
8083
|
+
}
|
|
8084
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600 sm:col-span-2" }, "\u6587\u5B57\u989C\u8272", /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid grid-cols-[64px_1fr] gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8085
|
+
"input",
|
|
8086
|
+
{
|
|
8087
|
+
type: "color",
|
|
8088
|
+
value: element.color || "#ffffff",
|
|
8089
|
+
onChange: (event) => updateElement(element.id, { color: event.target.value }),
|
|
8090
|
+
className: "h-10 rounded-lg border border-slate-300 bg-white p-1"
|
|
8091
|
+
}
|
|
8092
|
+
), /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8093
|
+
"input",
|
|
8094
|
+
{
|
|
8095
|
+
type: "text",
|
|
8096
|
+
value: element.color || "#ffffff",
|
|
8097
|
+
onChange: (event) => updateElement(element.id, { color: event.target.value }),
|
|
8098
|
+
className: numberFieldClassName
|
|
8099
|
+
}
|
|
8100
|
+
))))) : /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8101
|
+
"input",
|
|
8102
|
+
{
|
|
8103
|
+
type: "url",
|
|
8104
|
+
value: element.src,
|
|
8105
|
+
onChange: (event) => updateElement(element.id, { src: event.target.value }),
|
|
8106
|
+
className: "w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
|
|
8107
|
+
}
|
|
8108
|
+
), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid gap-2 sm:grid-cols-2" }, /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "X(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8109
|
+
"input",
|
|
8110
|
+
{
|
|
8111
|
+
type: "number",
|
|
8112
|
+
value: element.x,
|
|
8113
|
+
onChange: (event) => updateElement(element.id, { x: Number(event.target.value) }),
|
|
8114
|
+
className: numberFieldClassName
|
|
8115
|
+
}
|
|
8116
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "Y(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8117
|
+
"input",
|
|
8118
|
+
{
|
|
8119
|
+
type: "number",
|
|
8120
|
+
value: element.y,
|
|
8121
|
+
onChange: (event) => updateElement(element.id, { y: Number(event.target.value) }),
|
|
8122
|
+
className: numberFieldClassName
|
|
8123
|
+
}
|
|
8124
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5BBD\u5EA6(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8125
|
+
"input",
|
|
8126
|
+
{
|
|
8127
|
+
type: "number",
|
|
8128
|
+
value: element.width ?? 60,
|
|
8129
|
+
onChange: (event) => updateElement(element.id, { width: Number(event.target.value) }),
|
|
8130
|
+
className: numberFieldClassName
|
|
8131
|
+
}
|
|
8132
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u9AD8\u5EA6(%)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8133
|
+
"input",
|
|
8134
|
+
{
|
|
8135
|
+
type: "number",
|
|
8136
|
+
value: element.height ?? 40,
|
|
8137
|
+
onChange: (event) => updateElement(element.id, { height: Number(event.target.value) }),
|
|
8138
|
+
className: numberFieldClassName
|
|
8139
|
+
}
|
|
8140
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u5706\u89D2(px)", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8141
|
+
"input",
|
|
8142
|
+
{
|
|
8143
|
+
type: "number",
|
|
8144
|
+
value: element.borderRadius ?? 0,
|
|
8145
|
+
onChange: (event) => updateElement(element.id, { borderRadius: Number(event.target.value) }),
|
|
8146
|
+
className: numberFieldClassName
|
|
8147
|
+
}
|
|
8148
|
+
)), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "grid gap-1 text-xs text-slate-600" }, "\u586B\u5145", /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8149
|
+
"select",
|
|
8150
|
+
{
|
|
8151
|
+
value: element.fit || "cover",
|
|
8152
|
+
onChange: (event) => updateElement(element.id, { fit: event.target.value }),
|
|
8153
|
+
className: numberFieldClassName
|
|
8154
|
+
},
|
|
8155
|
+
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "cover" }, "cover"),
|
|
8156
|
+
/* @__PURE__ */ React69__namespace.default.createElement("option", { value: "contain" }, "contain")
|
|
8157
|
+
))), /* @__PURE__ */ React69__namespace.default.createElement("label", { className: "inline-flex items-center gap-2 text-sm text-slate-700" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8158
|
+
"input",
|
|
8159
|
+
{
|
|
8160
|
+
type: "checkbox",
|
|
8161
|
+
checked: Boolean(element.isBackground),
|
|
8162
|
+
onChange: (event) => updateElement(element.id, { isBackground: event.target.checked }),
|
|
8163
|
+
className: "h-4 w-4 rounded border-slate-300 text-sky-600"
|
|
8164
|
+
}
|
|
8165
|
+
), "\u4F5C\u4E3A\u672C\u9875\u80CC\u666F\u56FE"))
|
|
8166
|
+
)))) : null);
|
|
7809
8167
|
};
|
|
7810
8168
|
|
|
7811
8169
|
// src/festivalCard/components/FestivalCardStudio.tsx
|
|
@@ -7815,8 +8173,55 @@ var FestivalCardStudio = ({ initialConfig, fetchConfig, onSave }) => {
|
|
|
7815
8173
|
fetchConfig,
|
|
7816
8174
|
onSave
|
|
7817
8175
|
});
|
|
8176
|
+
const [activePageIndex, setActivePageIndex] = React69.useState(0);
|
|
8177
|
+
const [selectedElementId, setSelectedElementId] = React69.useState(null);
|
|
8178
|
+
React69.useEffect(() => {
|
|
8179
|
+
if (config.pages.length === 0) return;
|
|
8180
|
+
if (activePageIndex <= config.pages.length - 1) return;
|
|
8181
|
+
setActivePageIndex(config.pages.length - 1);
|
|
8182
|
+
}, [activePageIndex, config.pages.length]);
|
|
8183
|
+
const updateElementByPreview = (pageIndex, elementId, patch) => {
|
|
8184
|
+
setConfig((prev) => ({
|
|
8185
|
+
...prev,
|
|
8186
|
+
pages: prev.pages.map(
|
|
8187
|
+
(page, index) => index === pageIndex ? {
|
|
8188
|
+
...page,
|
|
8189
|
+
elements: page.elements.map(
|
|
8190
|
+
(element) => element.id === elementId ? { ...element, ...patch } : element
|
|
8191
|
+
)
|
|
8192
|
+
} : page
|
|
8193
|
+
)
|
|
8194
|
+
}));
|
|
8195
|
+
};
|
|
7818
8196
|
if (loading) return /* @__PURE__ */ React69__namespace.default.createElement("div", null, "\u52A0\u8F7D\u4E2D...");
|
|
7819
|
-
return /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid items-start gap-4 lg:grid-cols-[1.45fr_1fr]" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8197
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "grid items-start gap-4 lg:grid-cols-[1.45fr_1fr]" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8198
|
+
FestivalCardBook3D,
|
|
8199
|
+
{
|
|
8200
|
+
config,
|
|
8201
|
+
className: "h-full",
|
|
8202
|
+
editable: true,
|
|
8203
|
+
currentPage: activePageIndex,
|
|
8204
|
+
onCurrentPageChange: (index) => {
|
|
8205
|
+
setActivePageIndex(index);
|
|
8206
|
+
setSelectedElementId(null);
|
|
8207
|
+
},
|
|
8208
|
+
selectedElementId,
|
|
8209
|
+
onSelectedElementChange: setSelectedElementId,
|
|
8210
|
+
onElementChange: updateElementByPreview
|
|
8211
|
+
}
|
|
8212
|
+
), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "lg:sticky lg:top-4" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
8213
|
+
FestivalCardConfigEditor,
|
|
8214
|
+
{
|
|
8215
|
+
value: config,
|
|
8216
|
+
onChange: setConfig,
|
|
8217
|
+
activePageIndex,
|
|
8218
|
+
onActivePageIndexChange: (index) => {
|
|
8219
|
+
setActivePageIndex(index);
|
|
8220
|
+
setSelectedElementId(null);
|
|
8221
|
+
},
|
|
8222
|
+
selectedElementId
|
|
8223
|
+
}
|
|
8224
|
+
), onSave ? /* @__PURE__ */ React69__namespace.default.createElement(
|
|
7820
8225
|
"button",
|
|
7821
8226
|
{
|
|
7822
8227
|
type: "button",
|