@almadar/ui 5.21.11 → 5.22.2
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/avl/index.cjs +939 -638
- package/dist/avl/index.js +939 -638
- package/dist/components/core/molecules/CalendarGrid.d.ts +3 -10
- package/dist/components/core/molecules/ContentRenderer.d.ts +2 -2
- package/dist/components/core/molecules/DataGrid.d.ts +11 -20
- package/dist/components/core/molecules/DataList.d.ts +9 -15
- package/dist/components/core/molecules/FormSection.d.ts +4 -4
- package/dist/components/core/molecules/PositionedCanvas.d.ts +4 -17
- package/dist/components/core/molecules/ReplyTree.d.ts +2 -13
- package/dist/components/core/molecules/RichBlockEditor.d.ts +3 -6
- package/dist/components/core/molecules/SortableList.d.ts +7 -5
- package/dist/components/core/molecules/TableView.d.ts +7 -7
- package/dist/components/core/molecules/index.d.ts +3 -3
- package/dist/components/core/molecules/useDataDnd.d.ts +5 -5
- package/dist/components/core/organisms/CardGrid.d.ts +5 -2
- package/dist/components/core/organisms/CaseStudyOrganism.d.ts +4 -3
- package/dist/components/core/organisms/DataTable.d.ts +4 -2
- package/dist/components/core/organisms/DetailPanel.d.ts +6 -6
- package/dist/components/core/organisms/FeatureGridOrganism.d.ts +4 -3
- package/dist/components/core/organisms/HeroOrganism.d.ts +4 -5
- package/dist/components/core/organisms/List.d.ts +5 -2
- package/dist/components/core/organisms/MasterDetail.d.ts +4 -2
- package/dist/components/core/organisms/MediaGallery.d.ts +4 -2
- package/dist/components/core/organisms/ShowcaseOrganism.d.ts +4 -3
- package/dist/components/core/organisms/StatCard.d.ts +5 -2
- package/dist/components/core/organisms/StepFlowOrganism.d.ts +4 -3
- package/dist/components/core/organisms/Timeline.d.ts +2 -2
- package/dist/components/core/organisms/book/index.d.ts +1 -1
- package/dist/components/core/organisms/book/types.d.ts +28 -48
- package/dist/components/core/organisms/index.d.ts +1 -2
- package/dist/components/core/organisms/layout/DashboardGrid.d.ts +2 -2
- package/dist/components/core/organisms/marketing-types.d.ts +5 -94
- package/dist/components/core/organisms/types.d.ts +9 -27
- package/dist/components/core/templates/index.d.ts +6 -6
- package/dist/components/game/organisms/BattleBoard.d.ts +14 -90
- package/dist/components/game/organisms/CastleBoard.d.ts +7 -21
- package/dist/components/game/organisms/UncontrolledBattleBoard.d.ts +2 -7
- package/dist/components/game/organisms/WorldMapBoard.d.ts +13 -59
- package/dist/components/game/organisms/boardEntity.d.ts +44 -0
- package/dist/components/game/organisms/hooks/useBattleState.d.ts +7 -7
- package/dist/components/game/organisms/index.d.ts +3 -3
- package/dist/components/game/organisms/puzzles/builder/BuilderBoard.d.ts +7 -20
- package/dist/components/game/organisms/puzzles/builder/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/classifier/ClassifierBoard.d.ts +7 -20
- package/dist/components/game/organisms/puzzles/classifier/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/debugger/DebuggerBoard.d.ts +6 -22
- package/dist/components/game/organisms/puzzles/debugger/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/event-handler/EventHandlerBoard.d.ts +6 -33
- package/dist/components/game/organisms/puzzles/event-handler/ObjectRulePanel.d.ts +3 -21
- package/dist/components/game/organisms/puzzles/event-handler/index.d.ts +2 -2
- package/dist/components/game/organisms/puzzles/event-handler/puzzleObject.d.ts +21 -0
- package/dist/components/game/organisms/puzzles/negotiator/NegotiatorBoard.d.ts +8 -24
- package/dist/components/game/organisms/puzzles/negotiator/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/sequencer/ActionTile.d.ts +2 -2
- package/dist/components/game/organisms/puzzles/sequencer/SequencerBoard.d.ts +7 -36
- package/dist/components/game/organisms/puzzles/sequencer/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/simulator/SimulatorBoard.d.ts +6 -25
- package/dist/components/game/organisms/puzzles/simulator/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/state-architect/StateArchitectBoard.d.ts +7 -40
- package/dist/components/game/organisms/puzzles/state-architect/VariablePanel.d.ts +3 -9
- package/dist/components/game/organisms/puzzles/state-architect/index.d.ts +2 -2
- package/dist/components/game/organisms/three/index.cjs +35 -21
- package/dist/components/game/organisms/three/index.js +35 -21
- package/dist/components/game/templates/BattleTemplate.d.ts +2 -3
- package/dist/components/game/templates/CastleTemplate.d.ts +2 -3
- package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +1 -16
- package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +1 -18
- package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +1 -14
- package/dist/components/game/templates/GameTemplate.d.ts +1 -6
- package/dist/components/game/templates/WorldMapTemplate.d.ts +2 -3
- package/dist/components/index.cjs +2036 -1675
- package/dist/components/index.js +1148 -787
- package/dist/components/marketing/organisms/PricingOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/StatsOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/TeamOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/book/BookChapterView.d.ts +5 -2
- package/dist/components/marketing/organisms/book/BookTableOfContents.d.ts +3 -2
- package/dist/components/marketing/organisms/book/BookViewer.d.ts +4 -4
- package/dist/components/marketing/templates/AboutPageTemplate.d.ts +32 -6
- package/dist/components/marketing/templates/FeatureDetailPageTemplate.d.ts +14 -4
- package/dist/components/marketing/templates/LandingPageTemplate.d.ts +47 -9
- package/dist/components/marketing/templates/PricingPageTemplate.d.ts +23 -5
- package/dist/providers/index.cjs +932 -631
- package/dist/providers/index.js +932 -631
- package/dist/runtime/index.cjs +934 -633
- package/dist/runtime/index.js +934 -633
- package/package.json +2 -2
package/dist/providers/index.cjs
CHANGED
|
@@ -2767,7 +2767,7 @@ var init_SvgGrid = __esm({
|
|
|
2767
2767
|
x,
|
|
2768
2768
|
y,
|
|
2769
2769
|
cols = 4,
|
|
2770
|
-
rows = 3,
|
|
2770
|
+
rows: rows2 = 3,
|
|
2771
2771
|
spacing = 20,
|
|
2772
2772
|
nodeRadius = 3,
|
|
2773
2773
|
color = "var(--color-primary)",
|
|
@@ -2776,7 +2776,7 @@ var init_SvgGrid = __esm({
|
|
|
2776
2776
|
highlights = []
|
|
2777
2777
|
}) => {
|
|
2778
2778
|
const highlightSet = new Set(highlights);
|
|
2779
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length:
|
|
2779
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length: rows2 }).map(
|
|
2780
2780
|
(_, row) => Array.from({ length: cols }).map((_2, col) => {
|
|
2781
2781
|
const index = row * cols + col;
|
|
2782
2782
|
const isHighlighted = highlightSet.has(index);
|
|
@@ -3436,7 +3436,7 @@ var init_Input = __esm({
|
|
|
3436
3436
|
onClear,
|
|
3437
3437
|
value,
|
|
3438
3438
|
options,
|
|
3439
|
-
rows = 3,
|
|
3439
|
+
rows: rows2 = 3,
|
|
3440
3440
|
onChange,
|
|
3441
3441
|
...props
|
|
3442
3442
|
}, ref) => {
|
|
@@ -3486,7 +3486,7 @@ var init_Input = __esm({
|
|
|
3486
3486
|
ref,
|
|
3487
3487
|
value,
|
|
3488
3488
|
onChange,
|
|
3489
|
-
rows,
|
|
3489
|
+
rows: rows2,
|
|
3490
3490
|
className: baseClassName,
|
|
3491
3491
|
...props
|
|
3492
3492
|
}
|
|
@@ -5567,66 +5567,6 @@ var init_RangeSlider = __esm({
|
|
|
5567
5567
|
RangeSlider.displayName = "RangeSlider";
|
|
5568
5568
|
}
|
|
5569
5569
|
});
|
|
5570
|
-
function easeOut(t) {
|
|
5571
|
-
return t * (2 - t);
|
|
5572
|
-
}
|
|
5573
|
-
var AnimatedCounter;
|
|
5574
|
-
var init_AnimatedCounter = __esm({
|
|
5575
|
-
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
5576
|
-
"use client";
|
|
5577
|
-
init_cn();
|
|
5578
|
-
init_Typography();
|
|
5579
|
-
AnimatedCounter = ({
|
|
5580
|
-
value: rawValue,
|
|
5581
|
-
duration = 600,
|
|
5582
|
-
prefix,
|
|
5583
|
-
suffix,
|
|
5584
|
-
className
|
|
5585
|
-
}) => {
|
|
5586
|
-
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
5587
|
-
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
5588
|
-
const [displayValue, setDisplayValue] = React85.useState(value);
|
|
5589
|
-
const previousValueRef = React85.useRef(value);
|
|
5590
|
-
const animationFrameRef = React85.useRef(null);
|
|
5591
|
-
React85.useEffect(() => {
|
|
5592
|
-
const from = previousValueRef.current;
|
|
5593
|
-
const to = value;
|
|
5594
|
-
previousValueRef.current = value;
|
|
5595
|
-
if (from === to) {
|
|
5596
|
-
setDisplayValue(to);
|
|
5597
|
-
return;
|
|
5598
|
-
}
|
|
5599
|
-
const startTime = performance.now();
|
|
5600
|
-
const diff = to - from;
|
|
5601
|
-
function animate(currentTime) {
|
|
5602
|
-
const elapsed = currentTime - startTime;
|
|
5603
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
5604
|
-
const easedProgress = easeOut(progress);
|
|
5605
|
-
setDisplayValue(from + diff * easedProgress);
|
|
5606
|
-
if (progress < 1) {
|
|
5607
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5608
|
-
} else {
|
|
5609
|
-
setDisplayValue(to);
|
|
5610
|
-
}
|
|
5611
|
-
}
|
|
5612
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5613
|
-
return () => {
|
|
5614
|
-
if (animationFrameRef.current !== null) {
|
|
5615
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
5616
|
-
}
|
|
5617
|
-
};
|
|
5618
|
-
}, [value, duration]);
|
|
5619
|
-
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
5620
|
-
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
5621
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
5622
|
-
prefix,
|
|
5623
|
-
formattedValue,
|
|
5624
|
-
suffix
|
|
5625
|
-
] });
|
|
5626
|
-
};
|
|
5627
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
5628
|
-
}
|
|
5629
|
-
});
|
|
5630
5570
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
5631
5571
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
5632
5572
|
const observerRef = React85.useRef(null);
|
|
@@ -8108,15 +8048,15 @@ function HeaderSkeleton({ className }) {
|
|
|
8108
8048
|
] })
|
|
8109
8049
|
] });
|
|
8110
8050
|
}
|
|
8111
|
-
function TableSkeleton({ rows = 5, columns = 4, className }) {
|
|
8051
|
+
function TableSkeleton({ rows: rows2 = 5, columns = 4, className }) {
|
|
8112
8052
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: cn("border border-border rounded-lg overflow-hidden", className), children: [
|
|
8113
8053
|
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "px-4 py-3 bg-muted/30 border-b border-border", children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonBlock, { className: "h-4 flex-1 mx-2" }, i)) }),
|
|
8114
|
-
Array.from({ length:
|
|
8054
|
+
Array.from({ length: rows2 }).map((_, rowIdx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8115
8055
|
HStack,
|
|
8116
8056
|
{
|
|
8117
8057
|
className: cn(
|
|
8118
8058
|
"px-4 py-3",
|
|
8119
|
-
rowIdx <
|
|
8059
|
+
rowIdx < rows2 - 1 && "border-b border-border"
|
|
8120
8060
|
),
|
|
8121
8061
|
children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonLine, { className: "flex-1 mx-2" }, colIdx))
|
|
8122
8062
|
},
|
|
@@ -8164,18 +8104,18 @@ function CardSkeleton({ className }) {
|
|
|
8164
8104
|
}
|
|
8165
8105
|
);
|
|
8166
8106
|
}
|
|
8167
|
-
function TextSkeleton({ rows = 3, className }) {
|
|
8168
|
-
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length:
|
|
8107
|
+
function TextSkeleton({ rows: rows2 = 3, className }) {
|
|
8108
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length: rows2 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8169
8109
|
SkeletonLine,
|
|
8170
8110
|
{
|
|
8171
|
-
className: i ===
|
|
8111
|
+
className: i === rows2 - 1 ? "w-2/3" : "w-full"
|
|
8172
8112
|
},
|
|
8173
8113
|
i
|
|
8174
8114
|
)) });
|
|
8175
8115
|
}
|
|
8176
8116
|
function Skeleton({
|
|
8177
8117
|
variant = "text",
|
|
8178
|
-
rows,
|
|
8118
|
+
rows: rows2,
|
|
8179
8119
|
columns,
|
|
8180
8120
|
fields,
|
|
8181
8121
|
className
|
|
@@ -8185,15 +8125,15 @@ function Skeleton({
|
|
|
8185
8125
|
case "header":
|
|
8186
8126
|
return /* @__PURE__ */ jsxRuntime.jsx(HeaderSkeleton, { className });
|
|
8187
8127
|
case "table":
|
|
8188
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows, columns, className });
|
|
8128
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows: rows2, columns, className });
|
|
8189
8129
|
case "form":
|
|
8190
8130
|
return /* @__PURE__ */ jsxRuntime.jsx(FormSkeleton, { fields, className });
|
|
8191
8131
|
case "card":
|
|
8192
8132
|
return /* @__PURE__ */ jsxRuntime.jsx(CardSkeleton, { className });
|
|
8193
8133
|
case "text":
|
|
8194
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
8134
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
8195
8135
|
default:
|
|
8196
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
8136
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
8197
8137
|
}
|
|
8198
8138
|
}
|
|
8199
8139
|
var pulseClass;
|
|
@@ -9703,7 +9643,7 @@ var init_Menu = __esm({
|
|
|
9703
9643
|
className
|
|
9704
9644
|
}) => {
|
|
9705
9645
|
const eventBus = useEventBus();
|
|
9706
|
-
const { t } = hooks.useTranslate();
|
|
9646
|
+
const { t, direction } = hooks.useTranslate();
|
|
9707
9647
|
const [isOpen, setIsOpen] = React85.useState(false);
|
|
9708
9648
|
const [activeSubMenu, setActiveSubMenu] = React85.useState(null);
|
|
9709
9649
|
const [triggerRect, setTriggerRect] = React85.useState(null);
|
|
@@ -9757,6 +9697,18 @@ var init_Menu = __esm({
|
|
|
9757
9697
|
"bottom-start": "top-full left-0 mt-2",
|
|
9758
9698
|
"bottom-end": "top-full right-0 mt-2"
|
|
9759
9699
|
};
|
|
9700
|
+
const rtlMirror = {
|
|
9701
|
+
"top-left": "top-right",
|
|
9702
|
+
"top-right": "top-left",
|
|
9703
|
+
"bottom-left": "bottom-right",
|
|
9704
|
+
"bottom-right": "bottom-left",
|
|
9705
|
+
"top-start": "top-end",
|
|
9706
|
+
"top-end": "top-start",
|
|
9707
|
+
"bottom-start": "bottom-end",
|
|
9708
|
+
"bottom-end": "bottom-start"
|
|
9709
|
+
};
|
|
9710
|
+
const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
|
|
9711
|
+
const subMenuSideClass = direction === "rtl" ? "right-full mr-2" : "left-full ml-2";
|
|
9760
9712
|
const triggerChild = React85__namespace.default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", as: "span", children: trigger });
|
|
9761
9713
|
const triggerElement = React85__namespace.default.cloneElement(
|
|
9762
9714
|
triggerChild,
|
|
@@ -9784,7 +9736,7 @@ var init_Menu = __esm({
|
|
|
9784
9736
|
onMouseEnter: () => hasSubMenu && setActiveSubMenu(itemId),
|
|
9785
9737
|
"data-testid": item.event ? `action-${item.event}` : void 0,
|
|
9786
9738
|
className: cn(
|
|
9787
|
-
"w-full flex items-center justify-between gap-3 px-4 py-2 text-
|
|
9739
|
+
"w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
|
|
9788
9740
|
"text-sm transition-colors",
|
|
9789
9741
|
"hover:bg-muted",
|
|
9790
9742
|
"focus:outline-none focus:bg-muted",
|
|
@@ -9803,7 +9755,7 @@ var init_Menu = __esm({
|
|
|
9803
9755
|
}
|
|
9804
9756
|
),
|
|
9805
9757
|
item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
|
|
9806
|
-
hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "chevron-right", size: "sm", className: "flex-shrink-0" })
|
|
9758
|
+
hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: direction === "rtl" ? "chevron-left" : "chevron-right", size: "sm", className: "flex-shrink-0" })
|
|
9807
9759
|
] })
|
|
9808
9760
|
},
|
|
9809
9761
|
itemId
|
|
@@ -9823,7 +9775,8 @@ var init_Menu = __esm({
|
|
|
9823
9775
|
Box,
|
|
9824
9776
|
{
|
|
9825
9777
|
className: cn(
|
|
9826
|
-
"absolute
|
|
9778
|
+
"absolute top-0 z-50",
|
|
9779
|
+
subMenuSideClass,
|
|
9827
9780
|
menuContainerStyles
|
|
9828
9781
|
),
|
|
9829
9782
|
children: renderMenuItems(item.subMenu)
|
|
@@ -9841,12 +9794,12 @@ var init_Menu = __esm({
|
|
|
9841
9794
|
className: cn(
|
|
9842
9795
|
"absolute z-50",
|
|
9843
9796
|
menuContainerStyles,
|
|
9844
|
-
positionClasses3[
|
|
9797
|
+
positionClasses3[effectivePosition],
|
|
9845
9798
|
className
|
|
9846
9799
|
),
|
|
9847
9800
|
style: {
|
|
9848
|
-
left:
|
|
9849
|
-
right:
|
|
9801
|
+
left: effectivePosition.includes("left") ? 0 : "auto",
|
|
9802
|
+
right: effectivePosition.includes("right") ? 0 : "auto"
|
|
9850
9803
|
},
|
|
9851
9804
|
role: "menu",
|
|
9852
9805
|
children: renderMenuItems(items)
|
|
@@ -10164,7 +10117,7 @@ var init_MapView = __esm({
|
|
|
10164
10117
|
shadowSize: [41, 41]
|
|
10165
10118
|
});
|
|
10166
10119
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
10167
|
-
const { useEffect: useEffect70, useRef: useRef66, useCallback:
|
|
10120
|
+
const { useEffect: useEffect70, useRef: useRef66, useCallback: useCallback114, useState: useState100 } = React85__namespace.default;
|
|
10168
10121
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
10169
10122
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
10170
10123
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -10210,7 +10163,7 @@ var init_MapView = __esm({
|
|
|
10210
10163
|
}) {
|
|
10211
10164
|
const eventBus = useEventBus2();
|
|
10212
10165
|
const [clickedPosition, setClickedPosition] = useState100(null);
|
|
10213
|
-
const handleMapClick =
|
|
10166
|
+
const handleMapClick = useCallback114((lat, lng) => {
|
|
10214
10167
|
if (showClickedPin) {
|
|
10215
10168
|
setClickedPosition({ lat, lng });
|
|
10216
10169
|
}
|
|
@@ -10219,7 +10172,7 @@ var init_MapView = __esm({
|
|
|
10219
10172
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
10220
10173
|
}
|
|
10221
10174
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
10222
|
-
const handleMarkerClick =
|
|
10175
|
+
const handleMarkerClick = useCallback114((marker) => {
|
|
10223
10176
|
onMarkerClick?.(marker);
|
|
10224
10177
|
if (markerClickEvent) {
|
|
10225
10178
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -10440,7 +10393,7 @@ function InputPattern({
|
|
|
10440
10393
|
function TextareaPattern({
|
|
10441
10394
|
value = "",
|
|
10442
10395
|
placeholder,
|
|
10443
|
-
rows = 4,
|
|
10396
|
+
rows: rows2 = 4,
|
|
10444
10397
|
disabled = false,
|
|
10445
10398
|
fieldError,
|
|
10446
10399
|
onChange,
|
|
@@ -10460,7 +10413,7 @@ function TextareaPattern({
|
|
|
10460
10413
|
{
|
|
10461
10414
|
value: localValue,
|
|
10462
10415
|
placeholder,
|
|
10463
|
-
rows,
|
|
10416
|
+
rows: rows2,
|
|
10464
10417
|
disabled,
|
|
10465
10418
|
error: fieldError,
|
|
10466
10419
|
onChange: handleChange,
|
|
@@ -10945,6 +10898,91 @@ var init_ActionPalette = __esm({
|
|
|
10945
10898
|
ActionPalette.displayName = "ActionPalette";
|
|
10946
10899
|
}
|
|
10947
10900
|
});
|
|
10901
|
+
function parseValue(value) {
|
|
10902
|
+
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
10903
|
+
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
10904
|
+
if (!match) {
|
|
10905
|
+
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
10906
|
+
}
|
|
10907
|
+
const numStr = match[2];
|
|
10908
|
+
const decimalIdx = numStr.indexOf(".");
|
|
10909
|
+
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
10910
|
+
return {
|
|
10911
|
+
prefix: match[1],
|
|
10912
|
+
num: parseFloat(numStr),
|
|
10913
|
+
suffix: match[3],
|
|
10914
|
+
decimals
|
|
10915
|
+
};
|
|
10916
|
+
}
|
|
10917
|
+
var AnimatedCounter;
|
|
10918
|
+
var init_AnimatedCounter = __esm({
|
|
10919
|
+
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
10920
|
+
"use client";
|
|
10921
|
+
init_cn();
|
|
10922
|
+
init_Box();
|
|
10923
|
+
init_Typography();
|
|
10924
|
+
AnimatedCounter = ({
|
|
10925
|
+
value,
|
|
10926
|
+
label,
|
|
10927
|
+
duration = 1500,
|
|
10928
|
+
className
|
|
10929
|
+
}) => {
|
|
10930
|
+
const ref = React85.useRef(null);
|
|
10931
|
+
const [displayValue, setDisplayValue] = React85.useState("0");
|
|
10932
|
+
const [hasAnimated, setHasAnimated] = React85.useState(false);
|
|
10933
|
+
const animate = React85.useCallback(() => {
|
|
10934
|
+
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
10935
|
+
if (num2 === 0) {
|
|
10936
|
+
setDisplayValue(String(value));
|
|
10937
|
+
return;
|
|
10938
|
+
}
|
|
10939
|
+
const startTime = performance.now();
|
|
10940
|
+
const tick = (now) => {
|
|
10941
|
+
const elapsed = now - startTime;
|
|
10942
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
10943
|
+
const eased = 1 - Math.pow(1 - progress, 3);
|
|
10944
|
+
const current = eased * num2;
|
|
10945
|
+
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
10946
|
+
if (progress < 1) {
|
|
10947
|
+
requestAnimationFrame(tick);
|
|
10948
|
+
} else {
|
|
10949
|
+
setDisplayValue(String(value));
|
|
10950
|
+
}
|
|
10951
|
+
};
|
|
10952
|
+
requestAnimationFrame(tick);
|
|
10953
|
+
}, [value, duration]);
|
|
10954
|
+
React85.useEffect(() => {
|
|
10955
|
+
if (hasAnimated) return;
|
|
10956
|
+
const el = ref.current;
|
|
10957
|
+
if (!el) return;
|
|
10958
|
+
const observer2 = new IntersectionObserver(
|
|
10959
|
+
(entries) => {
|
|
10960
|
+
if (entries[0].isIntersecting) {
|
|
10961
|
+
setHasAnimated(true);
|
|
10962
|
+
animate();
|
|
10963
|
+
observer2.disconnect();
|
|
10964
|
+
}
|
|
10965
|
+
},
|
|
10966
|
+
{ threshold: 0.3 }
|
|
10967
|
+
);
|
|
10968
|
+
observer2.observe(el);
|
|
10969
|
+
return () => observer2.disconnect();
|
|
10970
|
+
}, [hasAnimated, animate]);
|
|
10971
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
10972
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10973
|
+
Typography,
|
|
10974
|
+
{
|
|
10975
|
+
variant: "h2",
|
|
10976
|
+
className: "text-primary font-bold tabular-nums",
|
|
10977
|
+
children: hasAnimated ? displayValue : "0"
|
|
10978
|
+
}
|
|
10979
|
+
),
|
|
10980
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
10981
|
+
] });
|
|
10982
|
+
};
|
|
10983
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
10984
|
+
}
|
|
10985
|
+
});
|
|
10948
10986
|
var AuthLayout;
|
|
10949
10987
|
var init_AuthLayout = __esm({
|
|
10950
10988
|
"components/core/templates/AuthLayout.tsx"() {
|
|
@@ -12286,6 +12324,39 @@ var init_IsometricCanvas2 = __esm({
|
|
|
12286
12324
|
init_IsometricCanvas();
|
|
12287
12325
|
}
|
|
12288
12326
|
});
|
|
12327
|
+
|
|
12328
|
+
// components/game/organisms/boardEntity.ts
|
|
12329
|
+
function boardEntity(entity) {
|
|
12330
|
+
if (!entity) return void 0;
|
|
12331
|
+
return Array.isArray(entity) ? entity[0] : entity;
|
|
12332
|
+
}
|
|
12333
|
+
function str(v) {
|
|
12334
|
+
return v == null ? "" : String(v);
|
|
12335
|
+
}
|
|
12336
|
+
function num(v, fallback = 0) {
|
|
12337
|
+
const n = Number(v);
|
|
12338
|
+
return Number.isFinite(n) ? n : fallback;
|
|
12339
|
+
}
|
|
12340
|
+
function rows(v) {
|
|
12341
|
+
return Array.isArray(v) ? v : [];
|
|
12342
|
+
}
|
|
12343
|
+
function vec2(v) {
|
|
12344
|
+
const o = v ?? {};
|
|
12345
|
+
return { x: num(o.x), y: num(o.y) };
|
|
12346
|
+
}
|
|
12347
|
+
function unitPosition(u) {
|
|
12348
|
+
return vec2(u.position);
|
|
12349
|
+
}
|
|
12350
|
+
function unitTeam(u) {
|
|
12351
|
+
return str(u.team);
|
|
12352
|
+
}
|
|
12353
|
+
function unitHealth(u) {
|
|
12354
|
+
return num(u.health);
|
|
12355
|
+
}
|
|
12356
|
+
var init_boardEntity = __esm({
|
|
12357
|
+
"components/game/organisms/boardEntity.ts"() {
|
|
12358
|
+
}
|
|
12359
|
+
});
|
|
12289
12360
|
function BattleBoard({
|
|
12290
12361
|
entity,
|
|
12291
12362
|
scale = 0.45,
|
|
@@ -12312,43 +12383,49 @@ function BattleBoard({
|
|
|
12312
12383
|
attackEvent,
|
|
12313
12384
|
className
|
|
12314
12385
|
}) {
|
|
12315
|
-
const
|
|
12316
|
-
const
|
|
12317
|
-
const
|
|
12318
|
-
const
|
|
12319
|
-
const
|
|
12320
|
-
const
|
|
12321
|
-
const
|
|
12322
|
-
const
|
|
12323
|
-
const
|
|
12324
|
-
const
|
|
12325
|
-
const
|
|
12386
|
+
const board = boardEntity(entity) ?? {};
|
|
12387
|
+
const tiles = Array.isArray(board.tiles) ? board.tiles : [];
|
|
12388
|
+
const features = Array.isArray(board.features) ? board.features : [];
|
|
12389
|
+
const boardWidth = num(board.boardWidth, 8);
|
|
12390
|
+
const boardHeight = num(board.boardHeight, 6);
|
|
12391
|
+
const assetManifest = board.assetManifest;
|
|
12392
|
+
const backgroundImage = board.backgroundImage;
|
|
12393
|
+
const units = rows(board.units);
|
|
12394
|
+
const selectedUnitId = board.selectedUnitId ?? null;
|
|
12395
|
+
const currentPhase = str(board.phase) || "observation";
|
|
12396
|
+
const currentTurn = num(board.turn, 1);
|
|
12397
|
+
const gameResult = board.gameResult ?? null;
|
|
12326
12398
|
const eventBus = useEventBus();
|
|
12327
12399
|
const { t } = hooks.useTranslate();
|
|
12328
12400
|
const [hoveredTile, setHoveredTile] = React85.useState(null);
|
|
12329
12401
|
const [isShaking, setIsShaking] = React85.useState(false);
|
|
12330
12402
|
const selectedUnit = React85.useMemo(
|
|
12331
|
-
() => units.find((u) => u.id === selectedUnitId) ?? null,
|
|
12403
|
+
() => units.find((u) => str(u.id) === selectedUnitId) ?? null,
|
|
12332
12404
|
[units, selectedUnitId]
|
|
12333
12405
|
);
|
|
12334
12406
|
const hoveredUnit = React85.useMemo(() => {
|
|
12335
12407
|
if (!hoveredTile) return null;
|
|
12336
|
-
return units.find(
|
|
12337
|
-
|
|
12338
|
-
|
|
12408
|
+
return units.find((u) => {
|
|
12409
|
+
const p2 = unitPosition(u);
|
|
12410
|
+
return p2.x === hoveredTile.x && p2.y === hoveredTile.y && unitHealth(u) > 0;
|
|
12411
|
+
}) ?? null;
|
|
12339
12412
|
}, [hoveredTile, units]);
|
|
12340
|
-
const playerUnits = React85.useMemo(() => units.filter((u) => u
|
|
12341
|
-
const enemyUnits = React85.useMemo(() => units.filter((u) => u
|
|
12413
|
+
const playerUnits = React85.useMemo(() => units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0), [units]);
|
|
12414
|
+
const enemyUnits = React85.useMemo(() => units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0), [units]);
|
|
12342
12415
|
const validMoves = React85.useMemo(() => {
|
|
12343
12416
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
12344
12417
|
const moves = [];
|
|
12345
|
-
const range = selectedUnit.movement;
|
|
12418
|
+
const range = num(selectedUnit.movement);
|
|
12419
|
+
const origin = unitPosition(selectedUnit);
|
|
12346
12420
|
for (let dy = -range; dy <= range; dy++) {
|
|
12347
12421
|
for (let dx = -range; dx <= range; dx++) {
|
|
12348
|
-
const nx =
|
|
12349
|
-
const ny =
|
|
12422
|
+
const nx = origin.x + dx;
|
|
12423
|
+
const ny = origin.y + dy;
|
|
12350
12424
|
const dist = Math.abs(dx) + Math.abs(dy);
|
|
12351
|
-
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) =>
|
|
12425
|
+
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) => {
|
|
12426
|
+
const p2 = unitPosition(u);
|
|
12427
|
+
return p2.x === nx && p2.y === ny && unitHealth(u) > 0;
|
|
12428
|
+
})) {
|
|
12352
12429
|
moves.push({ x: nx, y: ny });
|
|
12353
12430
|
}
|
|
12354
12431
|
}
|
|
@@ -12357,11 +12434,14 @@ function BattleBoard({
|
|
|
12357
12434
|
}, [selectedUnit, currentPhase, units, boardWidth, boardHeight]);
|
|
12358
12435
|
const attackTargets = React85.useMemo(() => {
|
|
12359
12436
|
if (!selectedUnit || currentPhase !== "action") return [];
|
|
12360
|
-
|
|
12361
|
-
|
|
12362
|
-
|
|
12437
|
+
const sp = unitPosition(selectedUnit);
|
|
12438
|
+
const sTeam = unitTeam(selectedUnit);
|
|
12439
|
+
return units.filter((u) => unitTeam(u) !== sTeam && unitHealth(u) > 0).filter((u) => {
|
|
12440
|
+
const p2 = unitPosition(u);
|
|
12441
|
+
const dx = Math.abs(p2.x - sp.x);
|
|
12442
|
+
const dy = Math.abs(p2.y - sp.y);
|
|
12363
12443
|
return dx <= 1 && dy <= 1 && dx + dy > 0;
|
|
12364
|
-
}).map((u) => u
|
|
12444
|
+
}).map((u) => unitPosition(u));
|
|
12365
12445
|
}, [selectedUnit, currentPhase, units]);
|
|
12366
12446
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
12367
12447
|
const movementAnimRef = React85.useRef(null);
|
|
@@ -12401,23 +12481,25 @@ function BattleBoard({
|
|
|
12401
12481
|
return () => clearInterval(interval);
|
|
12402
12482
|
}, []);
|
|
12403
12483
|
const isoUnits = React85.useMemo(() => {
|
|
12404
|
-
return units.filter((u) => u
|
|
12405
|
-
const
|
|
12484
|
+
return units.filter((u) => unitHealth(u) > 0).map((unit) => {
|
|
12485
|
+
const id = str(unit.id);
|
|
12486
|
+
const pos = movingPositions.get(id) ?? unitPosition(unit);
|
|
12487
|
+
const unitTraits = Array.isArray(unit.traits) ? unit.traits : void 0;
|
|
12406
12488
|
return {
|
|
12407
|
-
id
|
|
12489
|
+
id,
|
|
12408
12490
|
position: pos,
|
|
12409
|
-
name: unit.name,
|
|
12410
|
-
team: unit
|
|
12411
|
-
health: unit
|
|
12412
|
-
maxHealth: unit.maxHealth,
|
|
12413
|
-
unitType: unit.unitType,
|
|
12414
|
-
heroId: unit.heroId,
|
|
12415
|
-
sprite: unit.sprite,
|
|
12416
|
-
traits:
|
|
12417
|
-
name:
|
|
12418
|
-
currentState:
|
|
12419
|
-
states:
|
|
12420
|
-
cooldown:
|
|
12491
|
+
name: str(unit.name),
|
|
12492
|
+
team: unitTeam(unit),
|
|
12493
|
+
health: unitHealth(unit),
|
|
12494
|
+
maxHealth: num(unit.maxHealth),
|
|
12495
|
+
unitType: unit.unitType == null ? void 0 : str(unit.unitType),
|
|
12496
|
+
heroId: unit.heroId == null ? void 0 : str(unit.heroId),
|
|
12497
|
+
sprite: unit.sprite == null ? void 0 : str(unit.sprite),
|
|
12498
|
+
traits: unitTraits?.map((tr) => ({
|
|
12499
|
+
name: tr.name,
|
|
12500
|
+
currentState: tr.currentState,
|
|
12501
|
+
states: tr.states,
|
|
12502
|
+
cooldown: tr.cooldown ?? 0
|
|
12421
12503
|
}))
|
|
12422
12504
|
};
|
|
12423
12505
|
});
|
|
@@ -12429,8 +12511,8 @@ function BattleBoard({
|
|
|
12429
12511
|
[scale, baseOffsetX]
|
|
12430
12512
|
);
|
|
12431
12513
|
const checkGameEnd = React85.useCallback(() => {
|
|
12432
|
-
const pa = units.filter((u) => u
|
|
12433
|
-
const ea = units.filter((u) => u
|
|
12514
|
+
const pa = units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
12515
|
+
const ea = units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
12434
12516
|
if (pa.length === 0) {
|
|
12435
12517
|
onGameEnd?.("defeat");
|
|
12436
12518
|
if (gameEndEvent) {
|
|
@@ -12444,21 +12526,22 @@ function BattleBoard({
|
|
|
12444
12526
|
}
|
|
12445
12527
|
}, [units, onGameEnd, gameEndEvent, eventBus]);
|
|
12446
12528
|
const handleUnitClick = React85.useCallback((unitId) => {
|
|
12447
|
-
const unit = units.find((u) => u.id === unitId);
|
|
12529
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
12448
12530
|
if (!unit) return;
|
|
12449
12531
|
if (unitClickEvent) {
|
|
12450
12532
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
12451
12533
|
}
|
|
12452
12534
|
if (currentPhase === "action" && selectedUnit) {
|
|
12453
|
-
|
|
12454
|
-
|
|
12535
|
+
const up = unitPosition(unit);
|
|
12536
|
+
if (unitTeam(unit) === "enemy" && attackTargets.some((t2) => t2.x === up.x && t2.y === up.y)) {
|
|
12537
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
12455
12538
|
setIsShaking(true);
|
|
12456
12539
|
setTimeout(() => setIsShaking(false), 300);
|
|
12457
12540
|
onAttack?.(selectedUnit, unit, damage);
|
|
12458
12541
|
if (attackEvent) {
|
|
12459
12542
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
12460
|
-
attackerId: selectedUnit.id,
|
|
12461
|
-
targetId: unit.id,
|
|
12543
|
+
attackerId: str(selectedUnit.id),
|
|
12544
|
+
targetId: str(unit.id),
|
|
12462
12545
|
damage
|
|
12463
12546
|
});
|
|
12464
12547
|
}
|
|
@@ -12473,9 +12556,9 @@ function BattleBoard({
|
|
|
12473
12556
|
if (currentPhase === "movement" && selectedUnit) {
|
|
12474
12557
|
if (movementAnimRef.current) return;
|
|
12475
12558
|
if (validMoves.some((m) => m.x === x && m.y === y)) {
|
|
12476
|
-
const from = { ...selectedUnit
|
|
12559
|
+
const from = { ...unitPosition(selectedUnit) };
|
|
12477
12560
|
const to = { x, y };
|
|
12478
|
-
startMoveAnimation(selectedUnit.id, from, to, () => {
|
|
12561
|
+
startMoveAnimation(str(selectedUnit.id), from, to, () => {
|
|
12479
12562
|
onUnitMove?.(selectedUnit, to);
|
|
12480
12563
|
});
|
|
12481
12564
|
}
|
|
@@ -12633,6 +12716,7 @@ var init_BattleBoard = __esm({
|
|
|
12633
12716
|
init_Typography();
|
|
12634
12717
|
init_Stack();
|
|
12635
12718
|
init_IsometricCanvas2();
|
|
12719
|
+
init_boardEntity();
|
|
12636
12720
|
init_isometric();
|
|
12637
12721
|
BattleBoard.displayName = "BattleBoard";
|
|
12638
12722
|
}
|
|
@@ -13855,24 +13939,24 @@ var init_CodeBlock = __esm({
|
|
|
13855
13939
|
return;
|
|
13856
13940
|
}
|
|
13857
13941
|
lineEls.forEach((el) => {
|
|
13858
|
-
const
|
|
13859
|
-
if (hiddenLines.has(
|
|
13942
|
+
const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
|
|
13943
|
+
if (hiddenLines.has(num2)) {
|
|
13860
13944
|
el.style.display = "none";
|
|
13861
13945
|
return;
|
|
13862
13946
|
}
|
|
13863
13947
|
el.style.display = "";
|
|
13864
13948
|
el.style.position = "relative";
|
|
13865
13949
|
el.style.paddingLeft = "1.2em";
|
|
13866
|
-
const region = foldStartMap.get(
|
|
13950
|
+
const region = foldStartMap.get(num2);
|
|
13867
13951
|
if (!region) return;
|
|
13868
|
-
const isCollapsed = collapsed.has(
|
|
13952
|
+
const isCollapsed = collapsed.has(num2);
|
|
13869
13953
|
const toggle = document.createElement("span");
|
|
13870
13954
|
toggle.className = "fold-toggle";
|
|
13871
13955
|
toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
|
|
13872
13956
|
toggle.style.cssText = "position:absolute;left:0;top:0;width:1.2em;text-align:center;cursor:pointer;color:#858585;font-size:10px;user-select:none;line-height:inherit;height:100%";
|
|
13873
13957
|
toggle.addEventListener("click", (e) => {
|
|
13874
13958
|
e.stopPropagation();
|
|
13875
|
-
toggleFoldRef.current(
|
|
13959
|
+
toggleFoldRef.current(num2);
|
|
13876
13960
|
});
|
|
13877
13961
|
el.insertBefore(toggle, el.firstChild);
|
|
13878
13962
|
if (isCollapsed) {
|
|
@@ -16125,10 +16209,13 @@ var init_BookChapterView = __esm({
|
|
|
16125
16209
|
init_cn();
|
|
16126
16210
|
BookChapterView = ({
|
|
16127
16211
|
chapter,
|
|
16212
|
+
orbitalSchema,
|
|
16128
16213
|
direction,
|
|
16129
16214
|
className
|
|
16130
16215
|
}) => {
|
|
16131
16216
|
const { t: _t } = hooks.useTranslate();
|
|
16217
|
+
const title = String(chapter.title ?? "");
|
|
16218
|
+
const content = String(chapter.content ?? "");
|
|
16132
16219
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
16133
16220
|
VStack,
|
|
16134
16221
|
{
|
|
@@ -16136,16 +16223,16 @@ var init_BookChapterView = __esm({
|
|
|
16136
16223
|
className: cn("px-6 py-8 max-w-4xl mx-auto w-full", className),
|
|
16137
16224
|
style: { direction },
|
|
16138
16225
|
children: [
|
|
16139
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children:
|
|
16226
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children: title }),
|
|
16140
16227
|
/* @__PURE__ */ jsxRuntime.jsx(Divider, {}),
|
|
16141
|
-
!!
|
|
16228
|
+
!!orbitalSchema && /* @__PURE__ */ jsxRuntime.jsx(ScaledDiagram, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16142
16229
|
JazariStateMachine,
|
|
16143
16230
|
{
|
|
16144
|
-
schema:
|
|
16231
|
+
schema: orbitalSchema,
|
|
16145
16232
|
direction
|
|
16146
16233
|
}
|
|
16147
16234
|
) }),
|
|
16148
|
-
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content
|
|
16235
|
+
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content, direction })
|
|
16149
16236
|
]
|
|
16150
16237
|
}
|
|
16151
16238
|
);
|
|
@@ -16243,7 +16330,7 @@ var init_BookNavBar = __esm({
|
|
|
16243
16330
|
BookNavBar = ({
|
|
16244
16331
|
currentPage,
|
|
16245
16332
|
totalPages,
|
|
16246
|
-
chapterTitle,
|
|
16333
|
+
chapterTitle: chapterTitle2,
|
|
16247
16334
|
direction,
|
|
16248
16335
|
className
|
|
16249
16336
|
}) => {
|
|
@@ -16284,12 +16371,12 @@ var init_BookNavBar = __esm({
|
|
|
16284
16371
|
)
|
|
16285
16372
|
] }),
|
|
16286
16373
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex-1 mx-4 max-w-md", children: [
|
|
16287
|
-
|
|
16374
|
+
chapterTitle2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16288
16375
|
Typography,
|
|
16289
16376
|
{
|
|
16290
16377
|
variant: "caption",
|
|
16291
16378
|
className: "text-center block truncate text-muted-foreground",
|
|
16292
|
-
children:
|
|
16379
|
+
children: chapterTitle2
|
|
16293
16380
|
}
|
|
16294
16381
|
),
|
|
16295
16382
|
/* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { value: progress, size: "sm", variant: "primary" })
|
|
@@ -16356,31 +16443,35 @@ var init_BookTableOfContents = __esm({
|
|
|
16356
16443
|
style: { direction },
|
|
16357
16444
|
children: [
|
|
16358
16445
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold text-center mb-4", children: t("book.tableOfContents") }),
|
|
16359
|
-
parts.map((part, partIdx) =>
|
|
16360
|
-
|
|
16361
|
-
|
|
16362
|
-
/* @__PURE__ */ jsxRuntime.
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
|
|
16367
|
-
|
|
16368
|
-
|
|
16369
|
-
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16446
|
+
parts.map((part, partIdx) => {
|
|
16447
|
+
const chapters = Array.isArray(part.chapters) ? part.chapters : [];
|
|
16448
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
16449
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", children: [
|
|
16450
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: t("book.partNumber", { number: String(partIdx + 1) }) }),
|
|
16451
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "font-semibold", children: String(part.title ?? "") })
|
|
16452
|
+
] }),
|
|
16453
|
+
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "xs", className: direction === "rtl" ? "pr-6" : "pl-6", children: chapters.map((chapter) => {
|
|
16454
|
+
const id = chapter.id == null ? "" : String(chapter.id);
|
|
16455
|
+
const isCurrent = id === currentChapterId;
|
|
16456
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16457
|
+
Button,
|
|
16458
|
+
{
|
|
16459
|
+
variant: "ghost",
|
|
16460
|
+
size: "sm",
|
|
16461
|
+
action: "BOOK_NAVIGATE",
|
|
16462
|
+
actionPayload: { chapterId: id },
|
|
16463
|
+
className: cn(
|
|
16464
|
+
"justify-start text-left w-full",
|
|
16465
|
+
direction === "rtl" && "text-right",
|
|
16466
|
+
isCurrent && "bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400"
|
|
16467
|
+
),
|
|
16468
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "truncate", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: String(chapter.title ?? "") }) })
|
|
16469
|
+
},
|
|
16470
|
+
id
|
|
16471
|
+
);
|
|
16472
|
+
}) })
|
|
16473
|
+
] }, partIdx);
|
|
16474
|
+
})
|
|
16384
16475
|
]
|
|
16385
16476
|
}
|
|
16386
16477
|
);
|
|
@@ -16502,27 +16593,41 @@ function resolveFieldMap(fieldMap) {
|
|
|
16502
16593
|
function get(obj, key) {
|
|
16503
16594
|
return obj[key];
|
|
16504
16595
|
}
|
|
16596
|
+
function asStr(v) {
|
|
16597
|
+
return v == null ? "" : String(v);
|
|
16598
|
+
}
|
|
16505
16599
|
function mapBookData(raw, fields = IDENTITY_BOOK_FIELDS) {
|
|
16506
16600
|
const rawParts = get(raw, fields.parts) ?? [];
|
|
16507
|
-
|
|
16508
|
-
|
|
16509
|
-
|
|
16510
|
-
|
|
16511
|
-
|
|
16512
|
-
|
|
16513
|
-
|
|
16514
|
-
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16515
|
-
return {
|
|
16516
|
-
title: get(part, fields.partTitle) ?? "",
|
|
16517
|
-
chapters: rawChapters.map((ch) => ({
|
|
16518
|
-
id: get(ch, fields.chapterId) ?? "",
|
|
16519
|
-
title: get(ch, fields.chapterTitle) ?? "",
|
|
16520
|
-
content: get(ch, fields.chapterContent) ?? "",
|
|
16521
|
-
orbitalSchema: get(ch, fields.chapterOrbitalSchema)
|
|
16522
|
-
}))
|
|
16523
|
-
};
|
|
16524
|
-
})
|
|
16601
|
+
const direction = get(raw, fields.direction) ?? "ltr";
|
|
16602
|
+
const cover = {
|
|
16603
|
+
title: asStr(get(raw, fields.title)),
|
|
16604
|
+
subtitle: asStr(get(raw, fields.subtitle)),
|
|
16605
|
+
author: asStr(get(raw, fields.author)),
|
|
16606
|
+
coverImageUrl: asStr(get(raw, fields.coverImageUrl)),
|
|
16607
|
+
direction
|
|
16525
16608
|
};
|
|
16609
|
+
const schemaByChapterId = {};
|
|
16610
|
+
const chapters = [];
|
|
16611
|
+
const parts = rawParts.map((part) => {
|
|
16612
|
+
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16613
|
+
const chapterRows = rawChapters.map((ch) => {
|
|
16614
|
+
const id = asStr(get(ch, fields.chapterId));
|
|
16615
|
+
const schema = get(ch, fields.chapterOrbitalSchema);
|
|
16616
|
+
if (schema) schemaByChapterId[id] = schema;
|
|
16617
|
+
const row = {
|
|
16618
|
+
id,
|
|
16619
|
+
title: asStr(get(ch, fields.chapterTitle)),
|
|
16620
|
+
content: asStr(get(ch, fields.chapterContent))
|
|
16621
|
+
};
|
|
16622
|
+
chapters.push(row);
|
|
16623
|
+
return row;
|
|
16624
|
+
});
|
|
16625
|
+
return {
|
|
16626
|
+
title: asStr(get(part, fields.partTitle)),
|
|
16627
|
+
chapters: chapterRows
|
|
16628
|
+
};
|
|
16629
|
+
});
|
|
16630
|
+
return { cover, direction, parts, chapters, schemaByChapterId };
|
|
16526
16631
|
}
|
|
16527
16632
|
var IDENTITY_BOOK_FIELDS, AR_BOOK_FIELDS, FIELD_MAP_REGISTRY;
|
|
16528
16633
|
var init_types2 = __esm({
|
|
@@ -16560,10 +16665,7 @@ var init_types2 = __esm({
|
|
|
16560
16665
|
};
|
|
16561
16666
|
}
|
|
16562
16667
|
});
|
|
16563
|
-
|
|
16564
|
-
return book.parts.flatMap((part) => part.chapters);
|
|
16565
|
-
}
|
|
16566
|
-
var PRINT_STYLES, BookViewer;
|
|
16668
|
+
var chapterId, chapterTitle, PRINT_STYLES, BookViewer;
|
|
16567
16669
|
var init_BookViewer = __esm({
|
|
16568
16670
|
"components/marketing/organisms/book/BookViewer.tsx"() {
|
|
16569
16671
|
init_Box();
|
|
@@ -16576,6 +16678,8 @@ var init_BookViewer = __esm({
|
|
|
16576
16678
|
init_BookNavBar();
|
|
16577
16679
|
init_EmptyState();
|
|
16578
16680
|
init_types2();
|
|
16681
|
+
chapterId = (ch) => ch?.id == null ? void 0 : String(ch.id);
|
|
16682
|
+
chapterTitle = (ch) => ch?.title == null ? void 0 : String(ch.title);
|
|
16579
16683
|
PRINT_STYLES = `
|
|
16580
16684
|
@media print {
|
|
16581
16685
|
.book-viewer-page {
|
|
@@ -16604,14 +16708,14 @@ var init_BookViewer = __esm({
|
|
|
16604
16708
|
return mapBookData(raw, resolvedFieldMap);
|
|
16605
16709
|
}, [entity, resolvedFieldMap]);
|
|
16606
16710
|
const direction = book?.direction ?? "ltr";
|
|
16607
|
-
const chapters = React85.useMemo(() => book ?
|
|
16711
|
+
const chapters = React85.useMemo(() => book ? book.chapters : [], [book]);
|
|
16608
16712
|
const totalPages = 2 + chapters.length;
|
|
16609
16713
|
const navigateTo = React85.useCallback(
|
|
16610
16714
|
(page) => {
|
|
16611
16715
|
const clamped = Math.max(0, Math.min(page, totalPages - 1));
|
|
16612
16716
|
setCurrentPage(clamped);
|
|
16613
|
-
const
|
|
16614
|
-
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId });
|
|
16717
|
+
const id = clamped >= 2 ? chapterId(chapters[clamped - 2]) : void 0;
|
|
16718
|
+
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId: id });
|
|
16615
16719
|
},
|
|
16616
16720
|
[totalPages, chapters, eventBus]
|
|
16617
16721
|
);
|
|
@@ -16623,8 +16727,8 @@ var init_BookViewer = __esm({
|
|
|
16623
16727
|
eventBus.on("UI:BOOK_PAGE_NEXT", () => navigateTo(currentPage + 1)),
|
|
16624
16728
|
eventBus.on("UI:BOOK_PRINT", () => window.print()),
|
|
16625
16729
|
eventBus.on("UI:BOOK_NAVIGATE", (event) => {
|
|
16626
|
-
const
|
|
16627
|
-
const idx = chapters.findIndex((ch) => ch
|
|
16730
|
+
const targetId = event.payload?.chapterId;
|
|
16731
|
+
const idx = chapters.findIndex((ch) => chapterId(ch) === targetId);
|
|
16628
16732
|
if (idx >= 0) navigateTo(idx + 2);
|
|
16629
16733
|
})
|
|
16630
16734
|
];
|
|
@@ -16641,9 +16745,11 @@ var init_BookViewer = __esm({
|
|
|
16641
16745
|
style.remove();
|
|
16642
16746
|
};
|
|
16643
16747
|
}, []);
|
|
16644
|
-
const currentChapterId = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16645
|
-
const currentChapterTitle = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16748
|
+
const currentChapterId = currentPage >= 2 ? chapterId(chapters[currentPage - 2]) : void 0;
|
|
16749
|
+
const currentChapterTitle = currentPage >= 2 ? chapterTitle(chapters[currentPage - 2]) : void 0;
|
|
16646
16750
|
if (!book) return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { message: t("book.noData") });
|
|
16751
|
+
const cover = book.cover;
|
|
16752
|
+
const coverTitle = String(cover.title ?? "");
|
|
16647
16753
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("relative h-full overflow-hidden bg-background", className), children: [
|
|
16648
16754
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
16649
16755
|
Box,
|
|
@@ -16655,10 +16761,10 @@ var init_BookViewer = __esm({
|
|
|
16655
16761
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16656
16762
|
BookCoverPage,
|
|
16657
16763
|
{
|
|
16658
|
-
title:
|
|
16659
|
-
subtitle:
|
|
16660
|
-
author:
|
|
16661
|
-
coverImageUrl:
|
|
16764
|
+
title: coverTitle,
|
|
16765
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16766
|
+
author: String(cover.author ?? "") || void 0,
|
|
16767
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16662
16768
|
direction
|
|
16663
16769
|
}
|
|
16664
16770
|
),
|
|
@@ -16669,23 +16775,27 @@ var init_BookViewer = __esm({
|
|
|
16669
16775
|
direction
|
|
16670
16776
|
}
|
|
16671
16777
|
),
|
|
16672
|
-
chapters.map((chapter) =>
|
|
16673
|
-
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
-
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16778
|
+
chapters.map((chapter) => {
|
|
16779
|
+
const id = chapterId(chapter);
|
|
16780
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16781
|
+
BookChapterView,
|
|
16782
|
+
{
|
|
16783
|
+
chapter,
|
|
16784
|
+
orbitalSchema: id ? book.schemaByChapterId[id] : void 0,
|
|
16785
|
+
direction
|
|
16786
|
+
},
|
|
16787
|
+
id
|
|
16788
|
+
);
|
|
16789
|
+
})
|
|
16680
16790
|
] }),
|
|
16681
16791
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "print:hidden", children: [
|
|
16682
16792
|
currentPage === 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16683
16793
|
BookCoverPage,
|
|
16684
16794
|
{
|
|
16685
|
-
title:
|
|
16686
|
-
subtitle:
|
|
16687
|
-
author:
|
|
16688
|
-
coverImageUrl:
|
|
16795
|
+
title: coverTitle,
|
|
16796
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16797
|
+
author: String(cover.author ?? "") || void 0,
|
|
16798
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16689
16799
|
direction
|
|
16690
16800
|
}
|
|
16691
16801
|
),
|
|
@@ -16701,6 +16811,7 @@ var init_BookViewer = __esm({
|
|
|
16701
16811
|
BookChapterView,
|
|
16702
16812
|
{
|
|
16703
16813
|
chapter: chapters[currentPage - 2],
|
|
16814
|
+
orbitalSchema: currentChapterId ? book.schemaByChapterId[currentChapterId] : void 0,
|
|
16704
16815
|
direction
|
|
16705
16816
|
}
|
|
16706
16817
|
)
|
|
@@ -16713,7 +16824,7 @@ var init_BookViewer = __esm({
|
|
|
16713
16824
|
{
|
|
16714
16825
|
currentPage,
|
|
16715
16826
|
totalPages,
|
|
16716
|
-
chapterTitle: currentPage === 0 ?
|
|
16827
|
+
chapterTitle: currentPage === 0 ? coverTitle : currentPage === 1 ? t("book.tableOfContents") : currentChapterTitle,
|
|
16717
16828
|
direction
|
|
16718
16829
|
}
|
|
16719
16830
|
)
|
|
@@ -16811,7 +16922,7 @@ var init_Grid = __esm({
|
|
|
16811
16922
|
};
|
|
16812
16923
|
Grid = ({
|
|
16813
16924
|
cols = 1,
|
|
16814
|
-
rows,
|
|
16925
|
+
rows: rows2,
|
|
16815
16926
|
gap = "md",
|
|
16816
16927
|
rowGap,
|
|
16817
16928
|
colGap,
|
|
@@ -16823,7 +16934,7 @@ var init_Grid = __esm({
|
|
|
16823
16934
|
children,
|
|
16824
16935
|
as: Component = "div"
|
|
16825
16936
|
}) => {
|
|
16826
|
-
const mergedStyle =
|
|
16937
|
+
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
16827
16938
|
return React85__namespace.default.createElement(
|
|
16828
16939
|
Component,
|
|
16829
16940
|
{
|
|
@@ -17539,14 +17650,14 @@ function BuilderBoard({
|
|
|
17539
17650
|
}) {
|
|
17540
17651
|
const { emit } = useEventBus();
|
|
17541
17652
|
const { t } = hooks.useTranslate();
|
|
17542
|
-
const resolved =
|
|
17653
|
+
const resolved = boardEntity(entity);
|
|
17543
17654
|
const [placements, setPlacements] = React85.useState({});
|
|
17544
17655
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
17545
17656
|
const [submitted, setSubmitted] = React85.useState(false);
|
|
17546
17657
|
const [attempts, setAttempts] = React85.useState(0);
|
|
17547
17658
|
const [showHint, setShowHint] = React85.useState(false);
|
|
17548
|
-
const components = resolved?.components
|
|
17549
|
-
const slots = resolved?.slots
|
|
17659
|
+
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
17660
|
+
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
17550
17661
|
const usedComponentIds = new Set(Object.values(placements));
|
|
17551
17662
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
17552
17663
|
const [selectedComponent, setSelectedComponent] = React85.useState(null);
|
|
@@ -17580,7 +17691,7 @@ function BuilderBoard({
|
|
|
17580
17691
|
}, [slots, placements, attempts, completeEvent, emit]);
|
|
17581
17692
|
const handleReset = () => {
|
|
17582
17693
|
setSubmitted(false);
|
|
17583
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
17694
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
17584
17695
|
setShowHint(true);
|
|
17585
17696
|
}
|
|
17586
17697
|
};
|
|
@@ -17593,20 +17704,24 @@ function BuilderBoard({
|
|
|
17593
17704
|
};
|
|
17594
17705
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
17595
17706
|
if (!resolved) return null;
|
|
17707
|
+
const theme = resolved.theme ?? void 0;
|
|
17708
|
+
const themeBackground = theme?.background;
|
|
17709
|
+
const headerImage = str(resolved.headerImage);
|
|
17710
|
+
const hint = str(resolved.hint);
|
|
17596
17711
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17597
17712
|
Box,
|
|
17598
17713
|
{
|
|
17599
17714
|
className,
|
|
17600
17715
|
style: {
|
|
17601
|
-
backgroundImage:
|
|
17716
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
17602
17717
|
backgroundSize: "cover",
|
|
17603
17718
|
backgroundPosition: "center"
|
|
17604
17719
|
},
|
|
17605
17720
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
17606
|
-
|
|
17721
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
17607
17722
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17608
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
17609
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
17723
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
17724
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
17610
17725
|
] }) }),
|
|
17611
17726
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17612
17727
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.components") }),
|
|
@@ -17666,9 +17781,9 @@ function BuilderBoard({
|
|
|
17666
17781
|
] }) }),
|
|
17667
17782
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17668
17783
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
17669
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
17784
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
|
|
17670
17785
|
] }) }),
|
|
17671
|
-
showHint &&
|
|
17786
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
17672
17787
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17673
17788
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17674
17789
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
@@ -17687,6 +17802,7 @@ var init_BuilderBoard = __esm({
|
|
|
17687
17802
|
"components/game/organisms/puzzles/builder/BuilderBoard.tsx"() {
|
|
17688
17803
|
init_atoms2();
|
|
17689
17804
|
init_useEventBus();
|
|
17805
|
+
init_boardEntity();
|
|
17690
17806
|
BuilderBoard.displayName = "BuilderBoard";
|
|
17691
17807
|
}
|
|
17692
17808
|
});
|
|
@@ -18024,21 +18140,24 @@ function CalendarGrid({
|
|
|
18024
18140
|
eventBus.emit(`UI:${longPressEvent}`, { date: day.toISOString(), time, ...longPressPayload });
|
|
18025
18141
|
}, 500);
|
|
18026
18142
|
}, [longPressEvent, longPressPayload, eventBus]);
|
|
18027
|
-
const renderEvent = (event) =>
|
|
18028
|
-
|
|
18029
|
-
|
|
18030
|
-
|
|
18031
|
-
|
|
18032
|
-
|
|
18033
|
-
|
|
18034
|
-
|
|
18035
|
-
|
|
18036
|
-
|
|
18037
|
-
|
|
18038
|
-
|
|
18039
|
-
|
|
18040
|
-
|
|
18041
|
-
|
|
18143
|
+
const renderEvent = (event) => {
|
|
18144
|
+
const color = event.color;
|
|
18145
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18146
|
+
Box,
|
|
18147
|
+
{
|
|
18148
|
+
rounded: "md",
|
|
18149
|
+
padding: "xs",
|
|
18150
|
+
border: true,
|
|
18151
|
+
className: cn(
|
|
18152
|
+
"cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
|
|
18153
|
+
color ? color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
|
|
18154
|
+
),
|
|
18155
|
+
onClick: (e) => handleEventClick(event, e),
|
|
18156
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
|
|
18157
|
+
},
|
|
18158
|
+
event.id
|
|
18159
|
+
);
|
|
18160
|
+
};
|
|
18042
18161
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18043
18162
|
Box,
|
|
18044
18163
|
{
|
|
@@ -19702,7 +19821,6 @@ var init_CardGrid = __esm({
|
|
|
19702
19821
|
alignItems = "stretch",
|
|
19703
19822
|
className,
|
|
19704
19823
|
children,
|
|
19705
|
-
// EntityDisplayProps
|
|
19706
19824
|
entity,
|
|
19707
19825
|
isLoading = false,
|
|
19708
19826
|
error = null,
|
|
@@ -20174,14 +20292,14 @@ var init_CaseStudyOrganism = __esm({
|
|
|
20174
20292
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((study) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
20175
20293
|
CaseStudyCard,
|
|
20176
20294
|
{
|
|
20177
|
-
title: study.title,
|
|
20178
|
-
description: study.description,
|
|
20179
|
-
category: study.category,
|
|
20180
|
-
categoryColor: study.categoryColor,
|
|
20181
|
-
href: study.href,
|
|
20182
|
-
linkLabel: study.linkLabel
|
|
20295
|
+
title: String(study.title ?? ""),
|
|
20296
|
+
description: String(study.description ?? ""),
|
|
20297
|
+
category: String(study.category ?? ""),
|
|
20298
|
+
categoryColor: study.categoryColor != null ? String(study.categoryColor) : void 0,
|
|
20299
|
+
href: String(study.href ?? ""),
|
|
20300
|
+
linkLabel: study.linkLabel != null ? String(study.linkLabel) : void 0
|
|
20183
20301
|
},
|
|
20184
|
-
study.id
|
|
20302
|
+
String(study.id ?? "")
|
|
20185
20303
|
)) })
|
|
20186
20304
|
] });
|
|
20187
20305
|
};
|
|
@@ -20204,10 +20322,10 @@ function CastleBoard({
|
|
|
20204
20322
|
className
|
|
20205
20323
|
}) {
|
|
20206
20324
|
const eventBus = useEventBus();
|
|
20207
|
-
const resolved =
|
|
20208
|
-
const tiles = resolved?.tiles
|
|
20209
|
-
const features = resolved?.features
|
|
20210
|
-
const units = resolved?.units
|
|
20325
|
+
const resolved = boardEntity(entity);
|
|
20326
|
+
const tiles = Array.isArray(resolved?.tiles) ? resolved.tiles : [];
|
|
20327
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
20328
|
+
const units = Array.isArray(resolved?.units) ? resolved.units : [];
|
|
20211
20329
|
const assetManifest = resolved?.assetManifest;
|
|
20212
20330
|
const backgroundImage = resolved?.backgroundImage;
|
|
20213
20331
|
const [hoveredTile, setHoveredTile] = React85.useState(null);
|
|
@@ -20235,7 +20353,7 @@ function CastleBoard({
|
|
|
20235
20353
|
onFeatureClick?.(feature);
|
|
20236
20354
|
if (featureClickEvent) {
|
|
20237
20355
|
eventBus.emit(`UI:${featureClickEvent}`, {
|
|
20238
|
-
featureId: feature.id,
|
|
20356
|
+
featureId: feature.id ?? "",
|
|
20239
20357
|
featureType: feature.type,
|
|
20240
20358
|
x: feature.x,
|
|
20241
20359
|
y: feature.y
|
|
@@ -20303,6 +20421,7 @@ var init_CastleBoard = __esm({
|
|
|
20303
20421
|
init_cn();
|
|
20304
20422
|
init_useEventBus();
|
|
20305
20423
|
init_IsometricCanvas2();
|
|
20424
|
+
init_boardEntity();
|
|
20306
20425
|
init_isometric();
|
|
20307
20426
|
CastleBoard.displayName = "CastleBoard";
|
|
20308
20427
|
}
|
|
@@ -21113,14 +21232,14 @@ function ClassifierBoard({
|
|
|
21113
21232
|
}) {
|
|
21114
21233
|
const { emit } = useEventBus();
|
|
21115
21234
|
const { t } = hooks.useTranslate();
|
|
21116
|
-
const resolved =
|
|
21235
|
+
const resolved = boardEntity(entity);
|
|
21117
21236
|
const [assignments, setAssignments] = React85.useState({});
|
|
21118
21237
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
21119
21238
|
const [submitted, setSubmitted] = React85.useState(false);
|
|
21120
21239
|
const [attempts, setAttempts] = React85.useState(0);
|
|
21121
21240
|
const [showHint, setShowHint] = React85.useState(false);
|
|
21122
|
-
const items = resolved?.items
|
|
21123
|
-
const categories = resolved?.categories
|
|
21241
|
+
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
21242
|
+
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
21124
21243
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
21125
21244
|
const allAssigned = Object.keys(assignments).length === items.length;
|
|
21126
21245
|
const results = submitted ? items.map((item) => ({
|
|
@@ -21152,7 +21271,7 @@ function ClassifierBoard({
|
|
|
21152
21271
|
}, [items, assignments, attempts, completeEvent, emit]);
|
|
21153
21272
|
const handleReset = () => {
|
|
21154
21273
|
setSubmitted(false);
|
|
21155
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
21274
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
21156
21275
|
setShowHint(true);
|
|
21157
21276
|
}
|
|
21158
21277
|
};
|
|
@@ -21163,20 +21282,25 @@ function ClassifierBoard({
|
|
|
21163
21282
|
setShowHint(false);
|
|
21164
21283
|
};
|
|
21165
21284
|
if (!resolved) return null;
|
|
21285
|
+
const theme = resolved.theme ?? void 0;
|
|
21286
|
+
const themeBackground = theme?.background;
|
|
21287
|
+
const headerImage = str(resolved.headerImage);
|
|
21288
|
+
const hint = str(resolved.hint);
|
|
21289
|
+
const failMessage = str(resolved.failMessage);
|
|
21166
21290
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21167
21291
|
Box,
|
|
21168
21292
|
{
|
|
21169
21293
|
className,
|
|
21170
21294
|
style: {
|
|
21171
|
-
backgroundImage:
|
|
21295
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
21172
21296
|
backgroundSize: "cover",
|
|
21173
21297
|
backgroundPosition: "center"
|
|
21174
21298
|
},
|
|
21175
21299
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
21176
|
-
|
|
21300
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
21177
21301
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
21178
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
21179
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
21302
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
21303
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
21180
21304
|
] }) }),
|
|
21181
21305
|
unassignedItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
21182
21306
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("classifier.itemsToSort") }),
|
|
@@ -21228,10 +21352,10 @@ function ClassifierBoard({
|
|
|
21228
21352
|
}) }),
|
|
21229
21353
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
21230
21354
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
21231
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
21232
|
-
!allCorrect &&
|
|
21355
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("classifier.allCorrect") : `${correctCount}/${items.length} ${t("classifier.correct")}` }),
|
|
21356
|
+
!allCorrect && failMessage && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "text-muted-foreground", children: failMessage })
|
|
21233
21357
|
] }) }),
|
|
21234
|
-
showHint &&
|
|
21358
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
21235
21359
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
21236
21360
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
21237
21361
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -21250,6 +21374,7 @@ var init_ClassifierBoard = __esm({
|
|
|
21250
21374
|
"components/game/organisms/puzzles/classifier/ClassifierBoard.tsx"() {
|
|
21251
21375
|
init_atoms2();
|
|
21252
21376
|
init_useEventBus();
|
|
21377
|
+
init_boardEntity();
|
|
21253
21378
|
ClassifierBoard.displayName = "ClassifierBoard";
|
|
21254
21379
|
}
|
|
21255
21380
|
});
|
|
@@ -27620,7 +27745,7 @@ function InventoryPanel({
|
|
|
27620
27745
|
const slotArray = Array.from({ length: safeSlots }, (_, index) => {
|
|
27621
27746
|
return safeItems[index] ?? null;
|
|
27622
27747
|
});
|
|
27623
|
-
const
|
|
27748
|
+
const rows2 = Math.ceil(safeSlots / safeColumns);
|
|
27624
27749
|
const handleSlotClick = React85.useCallback((index) => {
|
|
27625
27750
|
if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
|
|
27626
27751
|
onSelectSlot?.(index);
|
|
@@ -27689,7 +27814,7 @@ function InventoryPanel({
|
|
|
27689
27814
|
className: "grid gap-1 bg-[var(--color-card)] p-2 rounded-container border border-border",
|
|
27690
27815
|
style: {
|
|
27691
27816
|
gridTemplateColumns: `repeat(${safeColumns}, ${slotSize}px)`,
|
|
27692
|
-
gridTemplateRows: `repeat(${
|
|
27817
|
+
gridTemplateRows: `repeat(${rows2}, ${slotSize}px)`
|
|
27693
27818
|
},
|
|
27694
27819
|
children: slotArray.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
27695
27820
|
"button",
|
|
@@ -31653,11 +31778,11 @@ function LatticeSVG({
|
|
|
31653
31778
|
}) {
|
|
31654
31779
|
const paths = [];
|
|
31655
31780
|
const cols = 5;
|
|
31656
|
-
const
|
|
31781
|
+
const rows2 = Math.ceil(h / (w / cols));
|
|
31657
31782
|
const cellW = w / cols;
|
|
31658
31783
|
const cellH = cellW;
|
|
31659
31784
|
const bulge = cellW * 0.3;
|
|
31660
|
-
for (let row = 0; row <
|
|
31785
|
+
for (let row = 0; row < rows2; row++) {
|
|
31661
31786
|
for (let col = 0; col < cols; col++) {
|
|
31662
31787
|
const cx = col * cellW + cellW / 2;
|
|
31663
31788
|
const cy = row * cellH + cellH / 2;
|
|
@@ -32069,7 +32194,7 @@ var init_MatrixQuestion = __esm({
|
|
|
32069
32194
|
};
|
|
32070
32195
|
MatrixQuestion = ({
|
|
32071
32196
|
title,
|
|
32072
|
-
rows,
|
|
32197
|
+
rows: rows2,
|
|
32073
32198
|
columns = DEFAULT_MATRIX_COLUMNS,
|
|
32074
32199
|
values,
|
|
32075
32200
|
onChange,
|
|
@@ -32079,7 +32204,7 @@ var init_MatrixQuestion = __esm({
|
|
|
32079
32204
|
className
|
|
32080
32205
|
}) => {
|
|
32081
32206
|
const styles = sizeStyles13[size];
|
|
32082
|
-
const safeRows =
|
|
32207
|
+
const safeRows = rows2 ?? [];
|
|
32083
32208
|
const safeValues = values ?? {};
|
|
32084
32209
|
const eventBus = useEventBus();
|
|
32085
32210
|
const handleChange = React85.useCallback(
|
|
@@ -32707,7 +32832,8 @@ var init_PositionedCanvas = __esm({
|
|
|
32707
32832
|
dragRef.current = null;
|
|
32708
32833
|
setDraggingId(null);
|
|
32709
32834
|
if (!wasDrag) {
|
|
32710
|
-
const
|
|
32835
|
+
const itemId = item.id;
|
|
32836
|
+
const next = selectedId === itemId ? null : itemId;
|
|
32711
32837
|
onSelect?.(next);
|
|
32712
32838
|
if (selectEvent) {
|
|
32713
32839
|
eventBus.emit(`UI:${selectEvent}`, { id: next });
|
|
@@ -32742,15 +32868,22 @@ var init_PositionedCanvas = __esm({
|
|
|
32742
32868
|
style: { width, height },
|
|
32743
32869
|
onClick: handleContainerClick,
|
|
32744
32870
|
children: items.map((item) => {
|
|
32871
|
+
const itemId = item.id;
|
|
32872
|
+
const label = item.label;
|
|
32873
|
+
const x = item.x;
|
|
32874
|
+
const y = item.y;
|
|
32875
|
+
const capacity = item.capacity;
|
|
32876
|
+
const partySize = item.partySize;
|
|
32877
|
+
const serverName = item.serverName;
|
|
32745
32878
|
const status = item.status ?? "empty";
|
|
32746
32879
|
const shape = item.shape ?? "round";
|
|
32747
|
-
const isSelected = selectedId ===
|
|
32748
|
-
const isDragging = draggingId ===
|
|
32880
|
+
const isSelected = selectedId === itemId;
|
|
32881
|
+
const isDragging = draggingId === itemId;
|
|
32749
32882
|
const statusBadge = STATUS_BADGE[status];
|
|
32750
32883
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32751
32884
|
Box,
|
|
32752
32885
|
{
|
|
32753
|
-
"data-testid": `item-node-${
|
|
32886
|
+
"data-testid": `item-node-${itemId}`,
|
|
32754
32887
|
"data-status": status,
|
|
32755
32888
|
className: cn(
|
|
32756
32889
|
"absolute flex flex-col items-center justify-center gap-1 border-2 select-none",
|
|
@@ -32761,7 +32894,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32761
32894
|
isSelected && "outline outline-2 outline-offset-2 outline-primary shadow-md",
|
|
32762
32895
|
isDragging && "shadow-lg z-10"
|
|
32763
32896
|
),
|
|
32764
|
-
style: { left:
|
|
32897
|
+
style: { left: x, top: y, touchAction: "none" },
|
|
32765
32898
|
onPointerDown: (e) => handlePointerDown(e, item),
|
|
32766
32899
|
onPointerMove: handlePointerMove,
|
|
32767
32900
|
onPointerUp: (e) => handlePointerUp(e, item),
|
|
@@ -32769,10 +32902,10 @@ var init_PositionedCanvas = __esm({
|
|
|
32769
32902
|
children: [
|
|
32770
32903
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", children: [
|
|
32771
32904
|
getStatusIcon(status),
|
|
32772
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children:
|
|
32905
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children: label })
|
|
32773
32906
|
] }),
|
|
32774
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
32775
|
-
status === "seated" &&
|
|
32907
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: partySize !== void 0 && status === "seated" ? `${partySize}/${capacity}` : `Cap ${capacity}` }),
|
|
32908
|
+
status === "seated" && serverName && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "truncate max-w-[80%]", children: serverName }),
|
|
32776
32909
|
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32777
32910
|
Badge,
|
|
32778
32911
|
{
|
|
@@ -32784,7 +32917,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32784
32917
|
)
|
|
32785
32918
|
]
|
|
32786
32919
|
},
|
|
32787
|
-
|
|
32920
|
+
itemId
|
|
32788
32921
|
);
|
|
32789
32922
|
})
|
|
32790
32923
|
}
|
|
@@ -33556,9 +33689,10 @@ var init_RichBlockEditor = __esm({
|
|
|
33556
33689
|
});
|
|
33557
33690
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
33558
33691
|
for (const n of nodes) {
|
|
33692
|
+
const replies = n.replies;
|
|
33559
33693
|
if (n.collapsed) acc.add(n.id);
|
|
33560
|
-
if (
|
|
33561
|
-
collectInitiallyCollapsed(
|
|
33694
|
+
if (replies && replies.length > 0) {
|
|
33695
|
+
collectInitiallyCollapsed(replies, acc);
|
|
33562
33696
|
}
|
|
33563
33697
|
}
|
|
33564
33698
|
}
|
|
@@ -33588,44 +33722,52 @@ var init_ReplyTree = __esm({
|
|
|
33588
33722
|
}) => {
|
|
33589
33723
|
const eventBus = useEventBus();
|
|
33590
33724
|
const { t } = hooks.useTranslate();
|
|
33591
|
-
const
|
|
33592
|
-
const
|
|
33725
|
+
const nodeId = node.id;
|
|
33726
|
+
const authorName = node.authorName;
|
|
33727
|
+
const authorAvatarUrl = node.authorAvatarUrl;
|
|
33728
|
+
const content = node.content;
|
|
33729
|
+
const postedAt = node.postedAt;
|
|
33730
|
+
const voteCount = node.voteCount;
|
|
33731
|
+
const userVote = node.userVote;
|
|
33732
|
+
const replies = node.replies;
|
|
33733
|
+
const hasReplies = !!replies && replies.length > 0;
|
|
33734
|
+
const isCollapsed = collapsedSet.has(nodeId);
|
|
33593
33735
|
const atMaxDepth = depth >= maxDepth;
|
|
33594
33736
|
const [replyOpen, setReplyOpen] = React85.useState(false);
|
|
33595
33737
|
const [draft, setDraft] = React85.useState("");
|
|
33596
33738
|
const handleVote = React85.useCallback(
|
|
33597
33739
|
(next) => {
|
|
33598
|
-
onVote?.(
|
|
33599
|
-
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId
|
|
33740
|
+
onVote?.(nodeId, next);
|
|
33741
|
+
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId, vote: next });
|
|
33600
33742
|
},
|
|
33601
|
-
[
|
|
33743
|
+
[nodeId, onVote, voteEvent, eventBus]
|
|
33602
33744
|
);
|
|
33603
33745
|
const handleReply = React85.useCallback(() => {
|
|
33604
|
-
onReply?.(
|
|
33746
|
+
onReply?.(nodeId);
|
|
33605
33747
|
setReplyOpen((open) => !open);
|
|
33606
|
-
}, [
|
|
33748
|
+
}, [nodeId, onReply]);
|
|
33607
33749
|
const handleSubmitReply = React85.useCallback(() => {
|
|
33608
|
-
const
|
|
33609
|
-
if (!
|
|
33610
|
-
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId:
|
|
33750
|
+
const text = draft.trim();
|
|
33751
|
+
if (!text) return;
|
|
33752
|
+
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: nodeId, content: text });
|
|
33611
33753
|
setDraft("");
|
|
33612
33754
|
setReplyOpen(false);
|
|
33613
|
-
}, [
|
|
33755
|
+
}, [nodeId, draft, replyEvent, eventBus]);
|
|
33614
33756
|
const handleCancelReply = React85.useCallback(() => {
|
|
33615
33757
|
setDraft("");
|
|
33616
33758
|
setReplyOpen(false);
|
|
33617
33759
|
}, []);
|
|
33618
33760
|
const handleFlag = React85.useCallback(() => {
|
|
33619
|
-
onFlag?.(
|
|
33620
|
-
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId
|
|
33621
|
-
}, [
|
|
33761
|
+
onFlag?.(nodeId);
|
|
33762
|
+
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId });
|
|
33763
|
+
}, [nodeId, onFlag, flagEvent, eventBus]);
|
|
33622
33764
|
const handleContinue = React85.useCallback(() => {
|
|
33623
|
-
onContinueThread?.(
|
|
33624
|
-
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId
|
|
33625
|
-
}, [
|
|
33765
|
+
onContinueThread?.(nodeId);
|
|
33766
|
+
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId });
|
|
33767
|
+
}, [nodeId, onContinueThread, continueThreadEvent, eventBus]);
|
|
33626
33768
|
const handleToggle = React85.useCallback(() => {
|
|
33627
|
-
toggleCollapse(
|
|
33628
|
-
}, [
|
|
33769
|
+
toggleCollapse(nodeId);
|
|
33770
|
+
}, [nodeId, toggleCollapse]);
|
|
33629
33771
|
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-stretch min-w-0", children: [
|
|
33630
33772
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col items-center flex-shrink-0 w-6", children: [
|
|
33631
33773
|
hasReplies ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -33657,25 +33799,25 @@ var init_ReplyTree = __esm({
|
|
|
33657
33799
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33658
33800
|
Avatar,
|
|
33659
33801
|
{
|
|
33660
|
-
src:
|
|
33661
|
-
name:
|
|
33802
|
+
src: authorAvatarUrl,
|
|
33803
|
+
name: authorName,
|
|
33662
33804
|
size: "sm"
|
|
33663
33805
|
}
|
|
33664
33806
|
),
|
|
33665
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children:
|
|
33666
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
33807
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children: authorName }),
|
|
33808
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: postedAt })
|
|
33667
33809
|
] }),
|
|
33668
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children:
|
|
33810
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: content }),
|
|
33669
33811
|
showActions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
33670
33812
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33671
33813
|
VoteStack,
|
|
33672
33814
|
{
|
|
33673
|
-
count:
|
|
33674
|
-
userVote:
|
|
33815
|
+
count: voteCount ?? 0,
|
|
33816
|
+
userVote: userVote ?? null,
|
|
33675
33817
|
onVote: handleVote,
|
|
33676
33818
|
size: "sm",
|
|
33677
33819
|
variant: "horizontal",
|
|
33678
|
-
label: t("replyTree.voteOnReplyBy", { author:
|
|
33820
|
+
label: t("replyTree.voteOnReplyBy", { author: authorName })
|
|
33679
33821
|
}
|
|
33680
33822
|
),
|
|
33681
33823
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -33685,7 +33827,7 @@ var init_ReplyTree = __esm({
|
|
|
33685
33827
|
size: "sm",
|
|
33686
33828
|
leftIcon: "message-square",
|
|
33687
33829
|
onClick: handleReply,
|
|
33688
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33830
|
+
"aria-label": t("replyTree.replyTo", { author: authorName }),
|
|
33689
33831
|
children: t("replyTree.reply")
|
|
33690
33832
|
}
|
|
33691
33833
|
),
|
|
@@ -33696,7 +33838,7 @@ var init_ReplyTree = __esm({
|
|
|
33696
33838
|
size: "sm",
|
|
33697
33839
|
leftIcon: "flag",
|
|
33698
33840
|
onClick: handleFlag,
|
|
33699
|
-
"aria-label": t("replyTree.flagReplyBy", { author:
|
|
33841
|
+
"aria-label": t("replyTree.flagReplyBy", { author: authorName }),
|
|
33700
33842
|
children: t("replyTree.flag")
|
|
33701
33843
|
}
|
|
33702
33844
|
)
|
|
@@ -33708,9 +33850,9 @@ var init_ReplyTree = __esm({
|
|
|
33708
33850
|
inputType: "textarea",
|
|
33709
33851
|
rows: 2,
|
|
33710
33852
|
value: draft,
|
|
33711
|
-
placeholder: t("replyTree.replyToPlaceholder", { author:
|
|
33853
|
+
placeholder: t("replyTree.replyToPlaceholder", { author: authorName }),
|
|
33712
33854
|
onChange: (e) => setDraft(e.target.value),
|
|
33713
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33855
|
+
"aria-label": t("replyTree.replyTo", { author: authorName })
|
|
33714
33856
|
}
|
|
33715
33857
|
),
|
|
33716
33858
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
@@ -33741,7 +33883,7 @@ var init_ReplyTree = __esm({
|
|
|
33741
33883
|
),
|
|
33742
33884
|
children: t("replyTree.continueThread")
|
|
33743
33885
|
}
|
|
33744
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children:
|
|
33886
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children: replies.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
33745
33887
|
ReplyTreeNode,
|
|
33746
33888
|
{
|
|
33747
33889
|
node: child,
|
|
@@ -36061,8 +36203,8 @@ var init_WizardContainer = __esm({
|
|
|
36061
36203
|
return void 0;
|
|
36062
36204
|
if (typeof controlledStep === "number") return controlledStep;
|
|
36063
36205
|
if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
|
|
36064
|
-
const
|
|
36065
|
-
return isNaN(
|
|
36206
|
+
const num2 = Number(controlledStep);
|
|
36207
|
+
return isNaN(num2) ? void 0 : num2;
|
|
36066
36208
|
})();
|
|
36067
36209
|
const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
|
|
36068
36210
|
const totalSteps = steps.length;
|
|
@@ -37767,7 +37909,7 @@ function DebuggerBoard({
|
|
|
37767
37909
|
}) {
|
|
37768
37910
|
const { emit } = useEventBus();
|
|
37769
37911
|
const { t } = hooks.useTranslate();
|
|
37770
|
-
const resolved =
|
|
37912
|
+
const resolved = boardEntity(entity);
|
|
37771
37913
|
const [flaggedLines, setFlaggedLines] = React85.useState(/* @__PURE__ */ new Set());
|
|
37772
37914
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
37773
37915
|
const [submitted, setSubmitted] = React85.useState(false);
|
|
@@ -37785,7 +37927,7 @@ function DebuggerBoard({
|
|
|
37785
37927
|
return next;
|
|
37786
37928
|
});
|
|
37787
37929
|
};
|
|
37788
|
-
const lines = resolved?.lines
|
|
37930
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37789
37931
|
const bugLines = lines.filter((l) => l.isBug);
|
|
37790
37932
|
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
37791
37933
|
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
@@ -37800,7 +37942,7 @@ function DebuggerBoard({
|
|
|
37800
37942
|
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37801
37943
|
const handleReset = () => {
|
|
37802
37944
|
setSubmitted(false);
|
|
37803
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
37945
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
37804
37946
|
setShowHint(true);
|
|
37805
37947
|
}
|
|
37806
37948
|
};
|
|
@@ -37811,24 +37953,28 @@ function DebuggerBoard({
|
|
|
37811
37953
|
setShowHint(false);
|
|
37812
37954
|
};
|
|
37813
37955
|
if (!resolved) return null;
|
|
37956
|
+
const theme = resolved.theme ?? void 0;
|
|
37957
|
+
const themeBackground = theme?.background;
|
|
37958
|
+
const headerImage = str(resolved.headerImage);
|
|
37959
|
+
const hint = str(resolved.hint);
|
|
37814
37960
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37815
37961
|
Box,
|
|
37816
37962
|
{
|
|
37817
37963
|
className,
|
|
37818
37964
|
style: {
|
|
37819
|
-
backgroundImage:
|
|
37965
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
37820
37966
|
backgroundSize: "cover",
|
|
37821
37967
|
backgroundPosition: "center"
|
|
37822
37968
|
},
|
|
37823
37969
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
37824
|
-
|
|
37970
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
37825
37971
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
37826
37972
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
37827
37973
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Bug, size: "sm" }),
|
|
37828
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title })
|
|
37974
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
37829
37975
|
] }),
|
|
37830
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
37831
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(resolved.bugCount) }) })
|
|
37976
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
37977
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
37832
37978
|
] }) }),
|
|
37833
37979
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
37834
37980
|
const isFlagged = flaggedLines.has(line.id);
|
|
@@ -37860,7 +38006,7 @@ function DebuggerBoard({
|
|
|
37860
38006
|
);
|
|
37861
38007
|
}) }) }),
|
|
37862
38008
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
37863
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
38009
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
|
|
37864
38010
|
bugLines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "start", children: [
|
|
37865
38011
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37866
38012
|
Icon,
|
|
@@ -37876,7 +38022,7 @@ function DebuggerBoard({
|
|
|
37876
38022
|
] })
|
|
37877
38023
|
] }, line.id))
|
|
37878
38024
|
] }) }),
|
|
37879
|
-
showHint &&
|
|
38025
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
37880
38026
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
37881
38027
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
|
|
37882
38028
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -37895,6 +38041,7 @@ var init_DebuggerBoard = __esm({
|
|
|
37895
38041
|
"components/game/organisms/puzzles/debugger/DebuggerBoard.tsx"() {
|
|
37896
38042
|
init_atoms2();
|
|
37897
38043
|
init_useEventBus();
|
|
38044
|
+
init_boardEntity();
|
|
37898
38045
|
DebuggerBoard.displayName = "DebuggerBoard";
|
|
37899
38046
|
}
|
|
37900
38047
|
});
|
|
@@ -37932,7 +38079,7 @@ function getBadgeVariant(fieldName, value) {
|
|
|
37932
38079
|
return "default";
|
|
37933
38080
|
}
|
|
37934
38081
|
function formatFieldLabel(fieldName) {
|
|
37935
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
38082
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
|
|
37936
38083
|
}
|
|
37937
38084
|
function formatFieldValue(value, fieldName) {
|
|
37938
38085
|
if (typeof value === "number") {
|
|
@@ -37951,26 +38098,26 @@ function formatFieldValue(value, fieldName) {
|
|
|
37951
38098
|
}
|
|
37952
38099
|
function renderRichFieldValue(value, fieldName, fieldType) {
|
|
37953
38100
|
if (value === void 0 || value === null) return "\u2014";
|
|
37954
|
-
const
|
|
38101
|
+
const str2 = String(value);
|
|
37955
38102
|
switch (fieldType) {
|
|
37956
38103
|
case "image":
|
|
37957
38104
|
case "url": {
|
|
37958
|
-
if (
|
|
38105
|
+
if (str2.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str2.startsWith("data:image/")) {
|
|
37959
38106
|
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
37960
38107
|
"img",
|
|
37961
38108
|
{
|
|
37962
|
-
src:
|
|
38109
|
+
src: str2,
|
|
37963
38110
|
alt: formatFieldLabel(fieldName),
|
|
37964
38111
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
37965
38112
|
loading: "lazy"
|
|
37966
38113
|
}
|
|
37967
38114
|
) });
|
|
37968
38115
|
}
|
|
37969
|
-
return
|
|
38116
|
+
return str2;
|
|
37970
38117
|
}
|
|
37971
38118
|
case "markdown":
|
|
37972
38119
|
case "richtext":
|
|
37973
|
-
return /* @__PURE__ */ jsxRuntime.jsx(React85.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children:
|
|
38120
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React85.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children: str2 }), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
37974
38121
|
Box,
|
|
37975
38122
|
{
|
|
37976
38123
|
className: "prose prose-sm max-w-none",
|
|
@@ -37988,11 +38135,11 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
37988
38135
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
37989
38136
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
37990
38137
|
},
|
|
37991
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children:
|
|
38138
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children: str2 })
|
|
37992
38139
|
}
|
|
37993
38140
|
) });
|
|
37994
38141
|
case "code":
|
|
37995
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children:
|
|
38142
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: str2 }) }) });
|
|
37996
38143
|
case "html":
|
|
37997
38144
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37998
38145
|
Box,
|
|
@@ -38012,12 +38159,12 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
38012
38159
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
38013
38160
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
38014
38161
|
},
|
|
38015
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children:
|
|
38162
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str2 })
|
|
38016
38163
|
}
|
|
38017
38164
|
);
|
|
38018
38165
|
case "date":
|
|
38019
38166
|
case "datetime": {
|
|
38020
|
-
const d = new Date(
|
|
38167
|
+
const d = new Date(str2);
|
|
38021
38168
|
if (!isNaN(d.getTime())) {
|
|
38022
38169
|
return d.toLocaleDateString(void 0, {
|
|
38023
38170
|
year: "numeric",
|
|
@@ -38026,7 +38173,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
38026
38173
|
...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
|
|
38027
38174
|
});
|
|
38028
38175
|
}
|
|
38029
|
-
return
|
|
38176
|
+
return str2;
|
|
38030
38177
|
}
|
|
38031
38178
|
default:
|
|
38032
38179
|
return formatFieldValue(value, fieldName);
|
|
@@ -38704,6 +38851,40 @@ var init_RuleEditor = __esm({
|
|
|
38704
38851
|
RuleEditor.displayName = "RuleEditor";
|
|
38705
38852
|
}
|
|
38706
38853
|
});
|
|
38854
|
+
|
|
38855
|
+
// components/game/organisms/puzzles/event-handler/puzzleObject.ts
|
|
38856
|
+
function objId(o) {
|
|
38857
|
+
return o.id == null ? "" : String(o.id);
|
|
38858
|
+
}
|
|
38859
|
+
function objName(o) {
|
|
38860
|
+
return o.name == null ? "" : String(o.name);
|
|
38861
|
+
}
|
|
38862
|
+
function objIcon(o) {
|
|
38863
|
+
return o.icon == null ? "" : String(o.icon);
|
|
38864
|
+
}
|
|
38865
|
+
function objStates(o) {
|
|
38866
|
+
return Array.isArray(o.states) ? o.states : [];
|
|
38867
|
+
}
|
|
38868
|
+
function objCurrentState(o) {
|
|
38869
|
+
return o.currentState == null ? "" : String(o.currentState);
|
|
38870
|
+
}
|
|
38871
|
+
function objAvailableEvents(o) {
|
|
38872
|
+
return Array.isArray(o.availableEvents) ? o.availableEvents : [];
|
|
38873
|
+
}
|
|
38874
|
+
function objAvailableActions(o) {
|
|
38875
|
+
return Array.isArray(o.availableActions) ? o.availableActions : [];
|
|
38876
|
+
}
|
|
38877
|
+
function objRules(o) {
|
|
38878
|
+
return Array.isArray(o.rules) ? o.rules : [];
|
|
38879
|
+
}
|
|
38880
|
+
function objMaxRules(o) {
|
|
38881
|
+
const n = Number(o.maxRules);
|
|
38882
|
+
return Number.isFinite(n) && n > 0 ? n : 3;
|
|
38883
|
+
}
|
|
38884
|
+
var init_puzzleObject = __esm({
|
|
38885
|
+
"components/game/organisms/puzzles/event-handler/puzzleObject.ts"() {
|
|
38886
|
+
}
|
|
38887
|
+
});
|
|
38707
38888
|
function ObjectRulePanel({
|
|
38708
38889
|
object,
|
|
38709
38890
|
onRulesChange,
|
|
@@ -38711,55 +38892,63 @@ function ObjectRulePanel({
|
|
|
38711
38892
|
className
|
|
38712
38893
|
}) {
|
|
38713
38894
|
const { t } = hooks.useTranslate();
|
|
38714
|
-
const
|
|
38715
|
-
const
|
|
38895
|
+
const id = objId(object);
|
|
38896
|
+
const name = objName(object);
|
|
38897
|
+
const icon = objIcon(object);
|
|
38898
|
+
const states = objStates(object);
|
|
38899
|
+
const currentState = objCurrentState(object);
|
|
38900
|
+
const availableEvents = objAvailableEvents(object);
|
|
38901
|
+
const availableActions = objAvailableActions(object);
|
|
38902
|
+
const rules = objRules(object);
|
|
38903
|
+
const maxRules = objMaxRules(object);
|
|
38904
|
+
const canAdd = rules.length < maxRules;
|
|
38716
38905
|
const handleRuleChange = React85.useCallback((index, updatedRule) => {
|
|
38717
|
-
const newRules = [...
|
|
38906
|
+
const newRules = [...rules];
|
|
38718
38907
|
newRules[index] = updatedRule;
|
|
38719
|
-
onRulesChange(
|
|
38720
|
-
}, [
|
|
38908
|
+
onRulesChange(id, newRules);
|
|
38909
|
+
}, [id, rules, onRulesChange]);
|
|
38721
38910
|
const handleRuleRemove = React85.useCallback((index) => {
|
|
38722
|
-
const newRules =
|
|
38723
|
-
onRulesChange(
|
|
38724
|
-
}, [
|
|
38911
|
+
const newRules = rules.filter((_, i) => i !== index);
|
|
38912
|
+
onRulesChange(id, newRules);
|
|
38913
|
+
}, [id, rules, onRulesChange]);
|
|
38725
38914
|
const handleAddRule = React85.useCallback(() => {
|
|
38726
38915
|
if (!canAdd || disabled) return;
|
|
38727
|
-
const firstEvent =
|
|
38728
|
-
const firstAction =
|
|
38916
|
+
const firstEvent = availableEvents[0]?.value || "";
|
|
38917
|
+
const firstAction = availableActions[0]?.value || "";
|
|
38729
38918
|
const newRule = {
|
|
38730
38919
|
id: `rule-${nextRuleId++}`,
|
|
38731
38920
|
whenEvent: firstEvent,
|
|
38732
38921
|
thenAction: firstAction
|
|
38733
38922
|
};
|
|
38734
|
-
onRulesChange(
|
|
38735
|
-
}, [canAdd, disabled,
|
|
38923
|
+
onRulesChange(id, [...rules, newRule]);
|
|
38924
|
+
}, [canAdd, disabled, id, rules, availableEvents, availableActions, onRulesChange]);
|
|
38736
38925
|
const machine = {
|
|
38737
|
-
name
|
|
38738
|
-
states
|
|
38739
|
-
currentState
|
|
38740
|
-
transitions:
|
|
38741
|
-
from:
|
|
38742
|
-
to:
|
|
38926
|
+
name,
|
|
38927
|
+
states,
|
|
38928
|
+
currentState,
|
|
38929
|
+
transitions: rules.map((r) => ({
|
|
38930
|
+
from: currentState,
|
|
38931
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38743
38932
|
event: r.whenEvent
|
|
38744
38933
|
}))
|
|
38745
38934
|
};
|
|
38746
38935
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-4 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
38747
38936
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center", gap: "sm", children: [
|
|
38748
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children:
|
|
38937
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: icon }),
|
|
38749
38938
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
38750
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children:
|
|
38751
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " +
|
|
38939
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children: name }),
|
|
38940
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " + currentState })
|
|
38752
38941
|
] })
|
|
38753
38942
|
] }),
|
|
38754
38943
|
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" }),
|
|
38755
38944
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
38756
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count:
|
|
38757
|
-
|
|
38945
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count: rules.length, max: maxRules }) + ":" }),
|
|
38946
|
+
rules.map((rule, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
38758
38947
|
RuleEditor,
|
|
38759
38948
|
{
|
|
38760
38949
|
rule,
|
|
38761
|
-
availableEvents
|
|
38762
|
-
availableActions
|
|
38950
|
+
availableEvents,
|
|
38951
|
+
availableActions,
|
|
38763
38952
|
onChange: (r) => handleRuleChange(i, r),
|
|
38764
38953
|
onRemove: () => handleRuleRemove(i),
|
|
38765
38954
|
disabled
|
|
@@ -38777,6 +38966,7 @@ var init_ObjectRulePanel = __esm({
|
|
|
38777
38966
|
init_cn();
|
|
38778
38967
|
init_TraitStateViewer();
|
|
38779
38968
|
init_RuleEditor();
|
|
38969
|
+
init_puzzleObject();
|
|
38780
38970
|
nextRuleId = 1;
|
|
38781
38971
|
ObjectRulePanel.displayName = "ObjectRulePanel";
|
|
38782
38972
|
}
|
|
@@ -38843,11 +39033,11 @@ function EventHandlerBoard({
|
|
|
38843
39033
|
}) {
|
|
38844
39034
|
const { emit } = useEventBus();
|
|
38845
39035
|
const { t } = hooks.useTranslate();
|
|
38846
|
-
const resolved =
|
|
38847
|
-
const entityObjects = resolved?.objects
|
|
38848
|
-
const [objects, setObjects] = React85.useState(entityObjects);
|
|
39036
|
+
const resolved = boardEntity(entity);
|
|
39037
|
+
const entityObjects = rows(resolved?.objects);
|
|
39038
|
+
const [objects, setObjects] = React85.useState(() => [...entityObjects]);
|
|
38849
39039
|
const [selectedObjectId, setSelectedObjectId] = React85.useState(
|
|
38850
|
-
entityObjects[0]
|
|
39040
|
+
entityObjects[0] ? objId(entityObjects[0]) : null
|
|
38851
39041
|
);
|
|
38852
39042
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
38853
39043
|
const [playState, setPlayState] = React85.useState("editing");
|
|
@@ -38858,10 +39048,10 @@ function EventHandlerBoard({
|
|
|
38858
39048
|
React85.useEffect(() => () => {
|
|
38859
39049
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38860
39050
|
}, []);
|
|
38861
|
-
const selectedObject = objects.find((o) => o
|
|
39051
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) || null;
|
|
38862
39052
|
const handleRulesChange = React85.useCallback((objectId, rules) => {
|
|
38863
39053
|
setObjects((prev) => prev.map(
|
|
38864
|
-
(o) => o
|
|
39054
|
+
(o) => objId(o) === objectId ? { ...o, rules } : o
|
|
38865
39055
|
));
|
|
38866
39056
|
}, []);
|
|
38867
39057
|
const addLogEntry = React85.useCallback((icon, message, status = "done") => {
|
|
@@ -38875,11 +39065,12 @@ function EventHandlerBoard({
|
|
|
38875
39065
|
setEventLog([]);
|
|
38876
39066
|
const allRules = [];
|
|
38877
39067
|
objects.forEach((obj) => {
|
|
38878
|
-
obj.
|
|
39068
|
+
objRules(obj).forEach((rule) => {
|
|
38879
39069
|
allRules.push({ object: obj, rule });
|
|
38880
39070
|
});
|
|
38881
39071
|
});
|
|
38882
|
-
const triggers = resolved?.triggerEvents
|
|
39072
|
+
const triggers = Array.isArray(resolved?.triggerEvents) ? resolved.triggerEvents : [];
|
|
39073
|
+
const goalEvent = str(resolved?.goalEvent);
|
|
38883
39074
|
const eventQueue = [...triggers];
|
|
38884
39075
|
const firedEvents = /* @__PURE__ */ new Set();
|
|
38885
39076
|
let stepIdx = 0;
|
|
@@ -38908,14 +39099,14 @@ function EventHandlerBoard({
|
|
|
38908
39099
|
addLogEntry("\u26A1", t("eventHandler.noListeners", { event: currentEvent }), "done");
|
|
38909
39100
|
} else {
|
|
38910
39101
|
matching.forEach(({ object, rule }) => {
|
|
38911
|
-
addLogEntry(object
|
|
39102
|
+
addLogEntry(objIcon(object), t("eventHandler.heardEvent", { object: objName(object), event: currentEvent, action: rule.thenAction }), "done");
|
|
38912
39103
|
eventQueue.push(rule.thenAction);
|
|
38913
|
-
if (rule.thenAction ===
|
|
39104
|
+
if (rule.thenAction === goalEvent) {
|
|
38914
39105
|
goalReached = true;
|
|
38915
39106
|
}
|
|
38916
39107
|
});
|
|
38917
39108
|
}
|
|
38918
|
-
if (currentEvent ===
|
|
39109
|
+
if (currentEvent === goalEvent) {
|
|
38919
39110
|
goalReached = true;
|
|
38920
39111
|
}
|
|
38921
39112
|
stepIdx++;
|
|
@@ -38933,65 +39124,75 @@ function EventHandlerBoard({
|
|
|
38933
39124
|
}, []);
|
|
38934
39125
|
const handleReset = React85.useCallback(() => {
|
|
38935
39126
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38936
|
-
|
|
39127
|
+
const resetObjects = rows(resolved?.objects);
|
|
39128
|
+
setObjects([...resetObjects]);
|
|
38937
39129
|
setPlayState("editing");
|
|
38938
39130
|
setEventLog([]);
|
|
38939
|
-
setSelectedObjectId(
|
|
39131
|
+
setSelectedObjectId(resetObjects[0] ? objId(resetObjects[0]) : null);
|
|
38940
39132
|
setAttempts(0);
|
|
38941
39133
|
}, [resolved?.objects]);
|
|
38942
39134
|
if (!resolved) return null;
|
|
38943
39135
|
const objectViewers = objects.map((obj) => {
|
|
39136
|
+
const states = objStates(obj);
|
|
39137
|
+
const currentState = objCurrentState(obj);
|
|
38944
39138
|
const machine = {
|
|
38945
|
-
name: obj
|
|
38946
|
-
states
|
|
38947
|
-
currentState
|
|
38948
|
-
transitions: obj.
|
|
38949
|
-
from:
|
|
38950
|
-
to:
|
|
39139
|
+
name: objName(obj),
|
|
39140
|
+
states,
|
|
39141
|
+
currentState,
|
|
39142
|
+
transitions: objRules(obj).map((r) => ({
|
|
39143
|
+
from: currentState,
|
|
39144
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38951
39145
|
event: r.whenEvent
|
|
38952
39146
|
}))
|
|
38953
39147
|
};
|
|
38954
39148
|
return { obj, machine };
|
|
38955
39149
|
});
|
|
38956
|
-
const
|
|
39150
|
+
const hint = str(resolved.hint);
|
|
39151
|
+
const showHint = attempts >= 3 && hint;
|
|
39152
|
+
const theme = resolved.theme ?? void 0;
|
|
39153
|
+
const themeBackground = theme?.background;
|
|
39154
|
+
const headerImage = str(resolved.headerImage);
|
|
38957
39155
|
const encourageKey = ENCOURAGEMENT_KEYS[Math.min(attempts - 1, ENCOURAGEMENT_KEYS.length - 1)] ?? ENCOURAGEMENT_KEYS[0];
|
|
38958
39156
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
38959
39157
|
VStack,
|
|
38960
39158
|
{
|
|
38961
39159
|
className: cn("p-4 gap-6", className),
|
|
38962
39160
|
style: {
|
|
38963
|
-
backgroundImage:
|
|
39161
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
38964
39162
|
backgroundSize: "cover",
|
|
38965
39163
|
backgroundPosition: "center"
|
|
38966
39164
|
},
|
|
38967
39165
|
children: [
|
|
38968
|
-
|
|
39166
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
38969
39167
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
38970
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
38971
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
39168
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
39169
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
38972
39170
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
|
|
38973
39171
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
|
|
38974
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: resolved.goalCondition })
|
|
39172
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: str(resolved.goalCondition) })
|
|
38975
39173
|
] })
|
|
38976
39174
|
] }),
|
|
38977
39175
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
38978
39176
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
|
|
38979
|
-
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) =>
|
|
38980
|
-
|
|
38981
|
-
|
|
38982
|
-
|
|
38983
|
-
|
|
38984
|
-
|
|
38985
|
-
|
|
38986
|
-
|
|
38987
|
-
|
|
38988
|
-
|
|
38989
|
-
/* @__PURE__ */ jsxRuntime.
|
|
38990
|
-
|
|
38991
|
-
|
|
38992
|
-
|
|
38993
|
-
|
|
38994
|
-
|
|
39177
|
+
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => {
|
|
39178
|
+
const oid = objId(obj);
|
|
39179
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
39180
|
+
Box,
|
|
39181
|
+
{
|
|
39182
|
+
className: cn(
|
|
39183
|
+
"p-3 rounded-container border-2 cursor-pointer transition-all hover:scale-105",
|
|
39184
|
+
selectedObjectId === oid ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
|
|
39185
|
+
),
|
|
39186
|
+
onClick: () => setSelectedObjectId(oid),
|
|
39187
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
|
|
39188
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: objIcon(obj) }),
|
|
39189
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: objName(obj) }),
|
|
39190
|
+
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
|
|
39191
|
+
] })
|
|
39192
|
+
},
|
|
39193
|
+
oid
|
|
39194
|
+
);
|
|
39195
|
+
}) })
|
|
38995
39196
|
] }),
|
|
38996
39197
|
selectedObject && /* @__PURE__ */ jsxRuntime.jsx(
|
|
38997
39198
|
ObjectRulePanel,
|
|
@@ -39002,12 +39203,12 @@ function EventHandlerBoard({
|
|
|
39002
39203
|
}
|
|
39003
39204
|
),
|
|
39004
39205
|
eventLog.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(EventLog, { entries: eventLog }),
|
|
39005
|
-
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("eventHandler.chainComplete") }) }),
|
|
39206
|
+
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("eventHandler.chainComplete") }) }),
|
|
39006
39207
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
39007
39208
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
|
|
39008
39209
|
showHint && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
39009
39210
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
39010
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
39211
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
39011
39212
|
] }) })
|
|
39012
39213
|
] }),
|
|
39013
39214
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -39035,6 +39236,8 @@ var init_EventHandlerBoard = __esm({
|
|
|
39035
39236
|
init_TraitStateViewer();
|
|
39036
39237
|
init_ObjectRulePanel();
|
|
39037
39238
|
init_EventLog();
|
|
39239
|
+
init_puzzleObject();
|
|
39240
|
+
init_boardEntity();
|
|
39038
39241
|
ENCOURAGEMENT_KEYS = [
|
|
39039
39242
|
"puzzle.tryAgain1",
|
|
39040
39243
|
"puzzle.tryAgain2",
|
|
@@ -39123,7 +39326,10 @@ var init_FeatureGridOrganism = __esm({
|
|
|
39123
39326
|
);
|
|
39124
39327
|
React85.useCallback(
|
|
39125
39328
|
(feature) => {
|
|
39126
|
-
eventBus.emit("UI:FEATURE_CLICK", {
|
|
39329
|
+
eventBus.emit("UI:FEATURE_CLICK", {
|
|
39330
|
+
id: String(feature.id ?? ""),
|
|
39331
|
+
href: String(feature.href ?? "")
|
|
39332
|
+
});
|
|
39127
39333
|
},
|
|
39128
39334
|
[eventBus]
|
|
39129
39335
|
);
|
|
@@ -39133,14 +39339,17 @@ var init_FeatureGridOrganism = __esm({
|
|
|
39133
39339
|
if (error) {
|
|
39134
39340
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
39135
39341
|
}
|
|
39136
|
-
const featureCards = items.map((feature) =>
|
|
39137
|
-
|
|
39138
|
-
|
|
39139
|
-
|
|
39140
|
-
|
|
39141
|
-
|
|
39142
|
-
|
|
39143
|
-
|
|
39342
|
+
const featureCards = items.map((feature) => {
|
|
39343
|
+
const href = feature.href != null ? String(feature.href) : void 0;
|
|
39344
|
+
return {
|
|
39345
|
+
icon: feature.icon != null ? String(feature.icon) : void 0,
|
|
39346
|
+
title: String(feature.title ?? ""),
|
|
39347
|
+
description: String(feature.description ?? ""),
|
|
39348
|
+
href,
|
|
39349
|
+
linkLabel: feature.linkLabel != null ? String(feature.linkLabel) : void 0,
|
|
39350
|
+
variant: href ? "interactive" : "bordered"
|
|
39351
|
+
};
|
|
39352
|
+
});
|
|
39144
39353
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
39145
39354
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
39146
39355
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
@@ -40458,22 +40667,24 @@ var init_HeroOrganism = __esm({
|
|
|
40458
40667
|
() => Array.isArray(entity) ? entity[0] : entity && typeof entity === "object" ? entity : void 0,
|
|
40459
40668
|
[entity]
|
|
40460
40669
|
);
|
|
40670
|
+
const primaryAction = resolved?.primaryAction;
|
|
40671
|
+
const secondaryAction = resolved?.secondaryAction;
|
|
40461
40672
|
const handlePrimaryClick = React85.useCallback(() => {
|
|
40462
|
-
if (
|
|
40673
|
+
if (primaryAction) {
|
|
40463
40674
|
eventBus.emit("UI:CTA_PRIMARY", {
|
|
40464
|
-
label:
|
|
40465
|
-
href:
|
|
40675
|
+
label: String(primaryAction.label ?? ""),
|
|
40676
|
+
href: String(primaryAction.href ?? "")
|
|
40466
40677
|
});
|
|
40467
40678
|
}
|
|
40468
|
-
}, [eventBus,
|
|
40679
|
+
}, [eventBus, primaryAction]);
|
|
40469
40680
|
const handleSecondaryClick = React85.useCallback(() => {
|
|
40470
|
-
if (
|
|
40681
|
+
if (secondaryAction) {
|
|
40471
40682
|
eventBus.emit("UI:CTA_SECONDARY", {
|
|
40472
|
-
label:
|
|
40473
|
-
href:
|
|
40683
|
+
label: String(secondaryAction.label ?? ""),
|
|
40684
|
+
href: String(secondaryAction.href ?? "")
|
|
40474
40685
|
});
|
|
40475
40686
|
}
|
|
40476
|
-
}, [eventBus,
|
|
40687
|
+
}, [eventBus, secondaryAction]);
|
|
40477
40688
|
if (isLoading) {
|
|
40478
40689
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
40479
40690
|
}
|
|
@@ -40483,17 +40694,19 @@ var init_HeroOrganism = __esm({
|
|
|
40483
40694
|
if (!resolved) {
|
|
40484
40695
|
return null;
|
|
40485
40696
|
}
|
|
40697
|
+
const imageRaw = resolved.image;
|
|
40698
|
+
const image = imageRaw ? { src: String(imageRaw.src ?? ""), alt: String(imageRaw.alt ?? "") } : void 0;
|
|
40486
40699
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
40487
40700
|
HeroSection,
|
|
40488
40701
|
{
|
|
40489
|
-
tag: resolved.tag,
|
|
40490
|
-
title: resolved.title,
|
|
40491
|
-
titleAccent: resolved.titleAccent,
|
|
40492
|
-
subtitle: resolved.subtitle,
|
|
40493
|
-
primaryAction:
|
|
40494
|
-
secondaryAction:
|
|
40495
|
-
installCommand: resolved.installCommand,
|
|
40496
|
-
image
|
|
40702
|
+
tag: resolved.tag != null ? String(resolved.tag) : void 0,
|
|
40703
|
+
title: String(resolved.title ?? ""),
|
|
40704
|
+
titleAccent: resolved.titleAccent != null ? String(resolved.titleAccent) : void 0,
|
|
40705
|
+
subtitle: String(resolved.subtitle ?? ""),
|
|
40706
|
+
primaryAction: primaryAction ? { label: String(primaryAction.label ?? ""), href: String(primaryAction.href ?? "") } : void 0,
|
|
40707
|
+
secondaryAction: secondaryAction ? { label: String(secondaryAction.label ?? ""), href: String(secondaryAction.href ?? "") } : void 0,
|
|
40708
|
+
installCommand: resolved.installCommand != null ? String(resolved.installCommand) : void 0,
|
|
40709
|
+
image,
|
|
40497
40710
|
imagePosition: resolved.imagePosition,
|
|
40498
40711
|
background: resolved.background,
|
|
40499
40712
|
className: cn(className),
|
|
@@ -40502,8 +40715,8 @@ var init_HeroOrganism = __esm({
|
|
|
40502
40715
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
40503
40716
|
_HeroClickInterceptor,
|
|
40504
40717
|
{
|
|
40505
|
-
hasPrimary: !!
|
|
40506
|
-
hasSecondary: !!
|
|
40718
|
+
hasPrimary: !!primaryAction,
|
|
40719
|
+
hasSecondary: !!secondaryAction,
|
|
40507
40720
|
onPrimaryClick: handlePrimaryClick,
|
|
40508
40721
|
onSecondaryClick: handleSecondaryClick
|
|
40509
40722
|
}
|
|
@@ -40732,7 +40945,7 @@ function formatValue3(value, fieldName) {
|
|
|
40732
40945
|
return String(value);
|
|
40733
40946
|
}
|
|
40734
40947
|
function formatFieldLabel2(fieldName) {
|
|
40735
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
40948
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
|
|
40736
40949
|
}
|
|
40737
40950
|
var STATUS_STYLES2, StatusBadge, ProgressIndicator, List3;
|
|
40738
40951
|
var init_List = __esm({
|
|
@@ -41579,20 +41792,22 @@ function NegotiatorBoard({
|
|
|
41579
41792
|
}) {
|
|
41580
41793
|
const { emit } = useEventBus();
|
|
41581
41794
|
const { t } = hooks.useTranslate();
|
|
41582
|
-
const resolved =
|
|
41795
|
+
const resolved = boardEntity(entity);
|
|
41583
41796
|
const [history, setHistory] = React85.useState([]);
|
|
41584
41797
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
41585
41798
|
const [showHint, setShowHint] = React85.useState(false);
|
|
41799
|
+
const totalRounds = num(resolved?.totalRounds);
|
|
41800
|
+
const targetScore = num(resolved?.targetScore);
|
|
41586
41801
|
const currentRound = history.length;
|
|
41587
|
-
const isComplete = currentRound >=
|
|
41802
|
+
const isComplete = currentRound >= totalRounds;
|
|
41588
41803
|
const playerTotal = history.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41589
41804
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
41590
|
-
const won = isComplete && playerTotal >=
|
|
41591
|
-
const actions = resolved?.actions
|
|
41592
|
-
const payoffMatrix = resolved?.payoffMatrix
|
|
41805
|
+
const won = isComplete && playerTotal >= targetScore;
|
|
41806
|
+
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
41807
|
+
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
41593
41808
|
const handleAction = React85.useCallback((actionId) => {
|
|
41594
41809
|
if (isComplete) return;
|
|
41595
|
-
const opponentAction = getOpponentAction(resolved?.opponentStrategy
|
|
41810
|
+
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
41596
41811
|
const payoff = payoffMatrix.find(
|
|
41597
41812
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
41598
41813
|
);
|
|
@@ -41605,42 +41820,46 @@ function NegotiatorBoard({
|
|
|
41605
41820
|
};
|
|
41606
41821
|
const newHistory = [...history, result];
|
|
41607
41822
|
setHistory(newHistory);
|
|
41608
|
-
if (newHistory.length >=
|
|
41823
|
+
if (newHistory.length >= totalRounds) {
|
|
41609
41824
|
const total = newHistory.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41610
|
-
if (total >=
|
|
41825
|
+
if (total >= targetScore) {
|
|
41611
41826
|
emit(`UI:${completeEvent}`, { success: true, score: total });
|
|
41612
41827
|
}
|
|
41613
|
-
if (newHistory.length >= 3 && resolved?.hint) {
|
|
41828
|
+
if (newHistory.length >= 3 && str(resolved?.hint)) {
|
|
41614
41829
|
setShowHint(true);
|
|
41615
41830
|
}
|
|
41616
41831
|
}
|
|
41617
|
-
}, [isComplete, resolved, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41832
|
+
}, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41618
41833
|
const handleReset = () => {
|
|
41619
41834
|
setHistory([]);
|
|
41620
41835
|
setShowHint(false);
|
|
41621
41836
|
};
|
|
41622
41837
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
41623
41838
|
if (!resolved) return null;
|
|
41839
|
+
const theme = resolved.theme ?? void 0;
|
|
41840
|
+
const themeBackground = theme?.background;
|
|
41841
|
+
const headerImage = str(resolved.headerImage);
|
|
41842
|
+
const hint = str(resolved.hint);
|
|
41624
41843
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
41625
41844
|
Box,
|
|
41626
41845
|
{
|
|
41627
41846
|
className,
|
|
41628
41847
|
style: {
|
|
41629
|
-
backgroundImage:
|
|
41848
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
41630
41849
|
backgroundSize: "cover",
|
|
41631
41850
|
backgroundPosition: "center"
|
|
41632
41851
|
},
|
|
41633
41852
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
41634
|
-
|
|
41853
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
41635
41854
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
41636
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
41637
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
41855
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
41856
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
41638
41857
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", children: [
|
|
41639
|
-
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(
|
|
41858
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(totalRounds) }) }),
|
|
41640
41859
|
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", children: [
|
|
41641
41860
|
t("negotiator.target"),
|
|
41642
41861
|
": ",
|
|
41643
|
-
|
|
41862
|
+
targetScore
|
|
41644
41863
|
] })
|
|
41645
41864
|
] })
|
|
41646
41865
|
] }) }),
|
|
@@ -41689,16 +41908,16 @@ function NegotiatorBoard({
|
|
|
41689
41908
|
] }) }),
|
|
41690
41909
|
isComplete && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
41691
41910
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: won ? "text-success" : "text-error" }),
|
|
41692
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? resolved.successMessage
|
|
41911
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? str(resolved.successMessage) || t("negotiator.success") : str(resolved.failMessage) || t("negotiator.failed") }),
|
|
41693
41912
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
41694
41913
|
t("negotiator.finalScore"),
|
|
41695
41914
|
": ",
|
|
41696
41915
|
playerTotal,
|
|
41697
41916
|
"/",
|
|
41698
|
-
|
|
41917
|
+
targetScore
|
|
41699
41918
|
] })
|
|
41700
41919
|
] }) }),
|
|
41701
|
-
showHint &&
|
|
41920
|
+
showHint && hint && !won && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
41702
41921
|
isComplete && !won && /* @__PURE__ */ jsxRuntime.jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
|
|
41703
41922
|
] })
|
|
41704
41923
|
}
|
|
@@ -41708,6 +41927,7 @@ var init_NegotiatorBoard = __esm({
|
|
|
41708
41927
|
"components/game/organisms/puzzles/negotiator/NegotiatorBoard.tsx"() {
|
|
41709
41928
|
init_atoms2();
|
|
41710
41929
|
init_useEventBus();
|
|
41930
|
+
init_boardEntity();
|
|
41711
41931
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
41712
41932
|
}
|
|
41713
41933
|
});
|
|
@@ -41743,13 +41963,13 @@ var init_PricingOrganism = __esm({
|
|
|
41743
41963
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
41744
41964
|
}
|
|
41745
41965
|
const plans = items.map((plan) => ({
|
|
41746
|
-
name: plan.name,
|
|
41747
|
-
price: plan.price,
|
|
41748
|
-
description: plan.description,
|
|
41749
|
-
features: plan.features,
|
|
41750
|
-
action: { label: plan.actionLabel, href: plan.actionHref },
|
|
41751
|
-
highlighted: plan.highlighted,
|
|
41752
|
-
badge: plan.badge
|
|
41966
|
+
name: String(plan.name ?? ""),
|
|
41967
|
+
price: String(plan.price ?? ""),
|
|
41968
|
+
description: plan.description != null ? String(plan.description) : void 0,
|
|
41969
|
+
features: (plan.features ?? []).map((f3) => String(f3)),
|
|
41970
|
+
action: { label: String(plan.actionLabel ?? ""), href: String(plan.actionHref ?? "") },
|
|
41971
|
+
highlighted: Boolean(plan.highlighted),
|
|
41972
|
+
badge: plan.badge != null ? String(plan.badge) : void 0
|
|
41753
41973
|
}));
|
|
41754
41974
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
41755
41975
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -43820,16 +44040,20 @@ function SequencerBoard({
|
|
|
43820
44040
|
}) {
|
|
43821
44041
|
const { emit } = useEventBus();
|
|
43822
44042
|
const { t } = hooks.useTranslate();
|
|
43823
|
-
const resolved =
|
|
44043
|
+
const resolved = boardEntity(entity);
|
|
44044
|
+
const maxSlots = num(resolved?.maxSlots);
|
|
44045
|
+
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
44046
|
+
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
44047
|
+
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
43824
44048
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
43825
44049
|
const [slots, setSlots] = React85.useState(
|
|
43826
|
-
() => Array.from({ length:
|
|
44050
|
+
() => Array.from({ length: maxSlots }, () => void 0)
|
|
43827
44051
|
);
|
|
43828
44052
|
const [playState, setPlayState] = React85.useState("idle");
|
|
43829
44053
|
const [currentStep, setCurrentStep] = React85.useState(-1);
|
|
43830
44054
|
const [attempts, setAttempts] = React85.useState(0);
|
|
43831
44055
|
const [slotFeedback, setSlotFeedback] = React85.useState(
|
|
43832
|
-
() => Array.from({ length:
|
|
44056
|
+
() => Array.from({ length: maxSlots }, () => null)
|
|
43833
44057
|
);
|
|
43834
44058
|
const timerRef = React85.useRef(null);
|
|
43835
44059
|
React85.useEffect(() => () => {
|
|
@@ -43863,17 +44087,17 @@ function SequencerBoard({
|
|
|
43863
44087
|
}, [emit]);
|
|
43864
44088
|
const handleReset = React85.useCallback(() => {
|
|
43865
44089
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
43866
|
-
setSlots(Array.from({ length:
|
|
44090
|
+
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
43867
44091
|
setPlayState("idle");
|
|
43868
44092
|
setCurrentStep(-1);
|
|
43869
44093
|
setAttempts(0);
|
|
43870
|
-
setSlotFeedback(Array.from({ length:
|
|
43871
|
-
}, [
|
|
44094
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
44095
|
+
}, [maxSlots]);
|
|
43872
44096
|
const filledSlots = slots.filter((s) => !!s);
|
|
43873
44097
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
43874
44098
|
const handlePlay = React85.useCallback(() => {
|
|
43875
44099
|
if (!canPlay) return;
|
|
43876
|
-
setSlotFeedback(Array.from({ length:
|
|
44100
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
43877
44101
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
43878
44102
|
const sequence = slots.map((s) => s?.id || "");
|
|
43879
44103
|
if (playEvent) {
|
|
@@ -43884,10 +44108,10 @@ function SequencerBoard({
|
|
|
43884
44108
|
let step = 0;
|
|
43885
44109
|
const advance = () => {
|
|
43886
44110
|
step++;
|
|
43887
|
-
if (step >=
|
|
44111
|
+
if (step >= maxSlots) {
|
|
43888
44112
|
const playerSeq = slots.map((s) => s?.id);
|
|
43889
44113
|
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
43890
|
-
const success =
|
|
44114
|
+
const success = solutions.some(
|
|
43891
44115
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
43892
44116
|
);
|
|
43893
44117
|
if (success) {
|
|
@@ -43899,7 +44123,7 @@ function SequencerBoard({
|
|
|
43899
44123
|
}
|
|
43900
44124
|
} else {
|
|
43901
44125
|
setAttempts((prev) => prev + 1);
|
|
43902
|
-
const feedback = computeSlotFeedback(playerSeq,
|
|
44126
|
+
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
43903
44127
|
setSlotFeedback(feedback);
|
|
43904
44128
|
setPlayState("idle");
|
|
43905
44129
|
setCurrentStep(-1);
|
|
@@ -43917,10 +44141,10 @@ function SequencerBoard({
|
|
|
43917
44141
|
}
|
|
43918
44142
|
};
|
|
43919
44143
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
43920
|
-
}, [canPlay, slots,
|
|
44144
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
43921
44145
|
const machine = {
|
|
43922
|
-
name: resolved?.title
|
|
43923
|
-
description: resolved?.description
|
|
44146
|
+
name: str(resolved?.title),
|
|
44147
|
+
description: str(resolved?.description),
|
|
43924
44148
|
states: slots.map((s, i) => stepLabel(s, i)),
|
|
43925
44149
|
currentState: currentStep >= 0 ? stepLabel(slots[currentStep], currentStep) : "__idle__",
|
|
43926
44150
|
transitions: slots.slice(0, -1).map((s, i) => ({
|
|
@@ -43929,37 +44153,41 @@ function SequencerBoard({
|
|
|
43929
44153
|
event: "NEXT"
|
|
43930
44154
|
}))
|
|
43931
44155
|
};
|
|
43932
|
-
const usedIds =
|
|
43933
|
-
const
|
|
44156
|
+
const usedIds = !allowDuplicates ? slots.filter(Boolean).map((s) => s?.id || "") : [];
|
|
44157
|
+
const hint = str(resolved?.hint);
|
|
44158
|
+
const showHint = attempts >= 3 && !!hint;
|
|
43934
44159
|
const hasFeedback = slotFeedback.some((f3) => f3 !== null);
|
|
43935
44160
|
const correctCount = slotFeedback.filter((f3) => f3 === "correct").length;
|
|
43936
44161
|
const encourageKey = ENCOURAGEMENT_KEYS2[Math.min(attempts - 1, ENCOURAGEMENT_KEYS2.length - 1)] ?? ENCOURAGEMENT_KEYS2[0];
|
|
43937
44162
|
if (!resolved) return null;
|
|
44163
|
+
const theme = resolved.theme ?? void 0;
|
|
44164
|
+
const themeBackground = theme?.background;
|
|
44165
|
+
const headerImage = str(resolved.headerImage);
|
|
43938
44166
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
43939
44167
|
VStack,
|
|
43940
44168
|
{
|
|
43941
44169
|
className: cn("p-4 gap-6", className),
|
|
43942
44170
|
style: {
|
|
43943
|
-
backgroundImage:
|
|
44171
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
43944
44172
|
backgroundSize: "cover",
|
|
43945
44173
|
backgroundPosition: "center"
|
|
43946
44174
|
},
|
|
43947
44175
|
children: [
|
|
43948
|
-
|
|
44176
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
43949
44177
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
43950
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
43951
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description })
|
|
44178
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
44179
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) })
|
|
43952
44180
|
] }),
|
|
43953
44181
|
showHint && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
43954
44182
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
43955
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
44183
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
43956
44184
|
] }) }),
|
|
43957
44185
|
filledSlots.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
|
|
43958
44186
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
43959
44187
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
43960
44188
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
43961
44189
|
hasFeedback && playState === "idle" && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
43962
|
-
`${correctCount}/${
|
|
44190
|
+
`${correctCount}/${maxSlots} `,
|
|
43963
44191
|
"\u2705"
|
|
43964
44192
|
] })
|
|
43965
44193
|
] }),
|
|
@@ -43967,7 +44195,7 @@ function SequencerBoard({
|
|
|
43967
44195
|
SequenceBar,
|
|
43968
44196
|
{
|
|
43969
44197
|
slots,
|
|
43970
|
-
maxSlots
|
|
44198
|
+
maxSlots,
|
|
43971
44199
|
onSlotDrop: handleSlotDrop,
|
|
43972
44200
|
onSlotRemove: handleSlotRemove,
|
|
43973
44201
|
playing: playState === "playing",
|
|
@@ -43981,15 +44209,15 @@ function SequencerBoard({
|
|
|
43981
44209
|
playState !== "playing" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
43982
44210
|
ActionPalette,
|
|
43983
44211
|
{
|
|
43984
|
-
actions:
|
|
44212
|
+
actions: availableActions,
|
|
43985
44213
|
usedActionIds: usedIds,
|
|
43986
|
-
allowDuplicates
|
|
44214
|
+
allowDuplicates,
|
|
43987
44215
|
categoryColors,
|
|
43988
44216
|
label: t("sequencer.dragActions")
|
|
43989
44217
|
}
|
|
43990
44218
|
),
|
|
43991
44219
|
hasFeedback && playState === "idle" && attempts > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
|
|
43992
|
-
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("sequencer.levelComplete") }) }),
|
|
44220
|
+
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("sequencer.levelComplete") }) }),
|
|
43993
44221
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
43994
44222
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43995
44223
|
Button,
|
|
@@ -44013,6 +44241,7 @@ var init_SequencerBoard = __esm({
|
|
|
44013
44241
|
init_cn();
|
|
44014
44242
|
init_useEventBus();
|
|
44015
44243
|
init_TraitStateViewer();
|
|
44244
|
+
init_boardEntity();
|
|
44016
44245
|
init_SequenceBar();
|
|
44017
44246
|
init_ActionPalette();
|
|
44018
44247
|
ENCOURAGEMENT_KEYS2 = [
|
|
@@ -44062,18 +44291,21 @@ var init_ShowcaseOrganism = __esm({
|
|
|
44062
44291
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
44063
44292
|
subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", color: "muted", align: "center", className: "max-w-2xl", children: subtitle })
|
|
44064
44293
|
] }),
|
|
44065
|
-
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) =>
|
|
44066
|
-
|
|
44067
|
-
|
|
44068
|
-
|
|
44069
|
-
|
|
44070
|
-
|
|
44071
|
-
|
|
44072
|
-
|
|
44073
|
-
|
|
44074
|
-
|
|
44075
|
-
|
|
44076
|
-
|
|
44294
|
+
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) => {
|
|
44295
|
+
const imageRaw = item.image;
|
|
44296
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44297
|
+
ShowcaseCard,
|
|
44298
|
+
{
|
|
44299
|
+
title: String(item.title ?? ""),
|
|
44300
|
+
description: item.description != null ? String(item.description) : void 0,
|
|
44301
|
+
image: { src: String(imageRaw?.src ?? ""), alt: String(imageRaw?.alt ?? "") },
|
|
44302
|
+
href: item.href != null ? String(item.href) : void 0,
|
|
44303
|
+
badge: item.badge != null ? String(item.badge) : void 0,
|
|
44304
|
+
accentColor: item.accentColor != null ? String(item.accentColor) : void 0
|
|
44305
|
+
},
|
|
44306
|
+
String(item.id ?? "")
|
|
44307
|
+
);
|
|
44308
|
+
}) })
|
|
44077
44309
|
] });
|
|
44078
44310
|
};
|
|
44079
44311
|
ShowcaseOrganism.displayName = "ShowcaseOrganism";
|
|
@@ -44441,8 +44673,8 @@ function SimulatorBoard({
|
|
|
44441
44673
|
}) {
|
|
44442
44674
|
const { emit } = useEventBus();
|
|
44443
44675
|
const { t } = hooks.useTranslate();
|
|
44444
|
-
const resolved =
|
|
44445
|
-
const parameters = resolved?.parameters
|
|
44676
|
+
const resolved = boardEntity(entity);
|
|
44677
|
+
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
44446
44678
|
const [values, setValues] = React85.useState(() => {
|
|
44447
44679
|
const init = {};
|
|
44448
44680
|
for (const p2 of parameters) {
|
|
@@ -44456,15 +44688,15 @@ function SimulatorBoard({
|
|
|
44456
44688
|
const [showHint, setShowHint] = React85.useState(false);
|
|
44457
44689
|
const computeOutput = React85.useCallback((params) => {
|
|
44458
44690
|
try {
|
|
44459
|
-
const fn = new Function("params", `return (${resolved?.computeExpression})`);
|
|
44691
|
+
const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
|
|
44460
44692
|
return fn(params);
|
|
44461
44693
|
} catch {
|
|
44462
44694
|
return 0;
|
|
44463
44695
|
}
|
|
44464
44696
|
}, [resolved?.computeExpression]);
|
|
44465
44697
|
const output = React85.useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
|
|
44466
|
-
const targetValue = resolved?.targetValue
|
|
44467
|
-
const targetTolerance = resolved?.targetTolerance
|
|
44698
|
+
const targetValue = num(resolved?.targetValue);
|
|
44699
|
+
const targetTolerance = num(resolved?.targetTolerance);
|
|
44468
44700
|
const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
|
|
44469
44701
|
const handleParameterChange = (id, value) => {
|
|
44470
44702
|
if (submitted) return;
|
|
@@ -44479,7 +44711,7 @@ function SimulatorBoard({
|
|
|
44479
44711
|
};
|
|
44480
44712
|
const handleReset = () => {
|
|
44481
44713
|
setSubmitted(false);
|
|
44482
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
44714
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
44483
44715
|
setShowHint(true);
|
|
44484
44716
|
}
|
|
44485
44717
|
};
|
|
@@ -44494,20 +44726,26 @@ function SimulatorBoard({
|
|
|
44494
44726
|
setShowHint(false);
|
|
44495
44727
|
};
|
|
44496
44728
|
if (!resolved) return null;
|
|
44729
|
+
const theme = resolved.theme ?? void 0;
|
|
44730
|
+
const themeBackground = theme?.background;
|
|
44731
|
+
const headerImage = str(resolved.headerImage);
|
|
44732
|
+
const hint = str(resolved.hint);
|
|
44733
|
+
const outputLabel = str(resolved.outputLabel);
|
|
44734
|
+
const outputUnit = str(resolved.outputUnit);
|
|
44497
44735
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44498
44736
|
Box,
|
|
44499
44737
|
{
|
|
44500
44738
|
className,
|
|
44501
44739
|
style: {
|
|
44502
|
-
backgroundImage:
|
|
44740
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
44503
44741
|
backgroundSize: "cover",
|
|
44504
44742
|
backgroundPosition: "center"
|
|
44505
44743
|
},
|
|
44506
44744
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
44507
|
-
|
|
44745
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
44508
44746
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
44509
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
44510
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
44747
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
44748
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
44511
44749
|
] }) }),
|
|
44512
44750
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
44513
44751
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
@@ -44548,28 +44786,28 @@ function SimulatorBoard({
|
|
|
44548
44786
|
] }, param.id))
|
|
44549
44787
|
] }) }),
|
|
44550
44788
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
44551
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children:
|
|
44789
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
44552
44790
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", weight: "bold", children: [
|
|
44553
44791
|
output.toFixed(2),
|
|
44554
44792
|
" ",
|
|
44555
|
-
|
|
44793
|
+
outputUnit
|
|
44556
44794
|
] }),
|
|
44557
44795
|
submitted && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
44558
44796
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: isCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
|
|
44559
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? resolved.successMessage
|
|
44797
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
|
|
44560
44798
|
] }),
|
|
44561
44799
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44562
44800
|
t("simulator.target"),
|
|
44563
44801
|
": ",
|
|
44564
44802
|
targetValue,
|
|
44565
44803
|
" ",
|
|
44566
|
-
|
|
44804
|
+
outputUnit,
|
|
44567
44805
|
" (\xB1",
|
|
44568
44806
|
targetTolerance,
|
|
44569
44807
|
")"
|
|
44570
44808
|
] })
|
|
44571
44809
|
] }) }),
|
|
44572
|
-
showHint &&
|
|
44810
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
44573
44811
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
44574
44812
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
|
|
44575
44813
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
@@ -44588,6 +44826,7 @@ var init_SimulatorBoard = __esm({
|
|
|
44588
44826
|
"components/game/organisms/puzzles/simulator/SimulatorBoard.tsx"() {
|
|
44589
44827
|
init_atoms2();
|
|
44590
44828
|
init_useEventBus();
|
|
44829
|
+
init_boardEntity();
|
|
44591
44830
|
SimulatorBoard.displayName = "SimulatorBoard";
|
|
44592
44831
|
}
|
|
44593
44832
|
});
|
|
@@ -45013,22 +45252,25 @@ function VariablePanel({
|
|
|
45013
45252
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-3 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
45014
45253
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
45015
45254
|
variables.map((v) => {
|
|
45016
|
-
const
|
|
45017
|
-
const
|
|
45018
|
-
const
|
|
45255
|
+
const name = v.name == null ? "" : String(v.name);
|
|
45256
|
+
const value = numField(v.value);
|
|
45257
|
+
const max = numField(v.max, 100);
|
|
45258
|
+
const min = numField(v.min, 0);
|
|
45259
|
+
const unit = v.unit == null ? "" : String(v.unit);
|
|
45260
|
+
const pct = Math.round((value - min) / (max - min) * 100);
|
|
45019
45261
|
const isHigh = pct > 80;
|
|
45020
45262
|
const isLow = pct < 20;
|
|
45021
45263
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
45022
45264
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
45023
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children:
|
|
45265
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children: name }),
|
|
45024
45266
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: cn(
|
|
45025
45267
|
isHigh ? "text-error" : isLow ? "text-warning" : "text-foreground"
|
|
45026
45268
|
), children: [
|
|
45027
|
-
|
|
45028
|
-
|
|
45269
|
+
value,
|
|
45270
|
+
unit,
|
|
45029
45271
|
" / ",
|
|
45030
45272
|
max,
|
|
45031
|
-
|
|
45273
|
+
unit
|
|
45032
45274
|
] })
|
|
45033
45275
|
] }),
|
|
45034
45276
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -45039,14 +45281,19 @@ function VariablePanel({
|
|
|
45039
45281
|
size: "sm"
|
|
45040
45282
|
}
|
|
45041
45283
|
)
|
|
45042
|
-
] },
|
|
45284
|
+
] }, name);
|
|
45043
45285
|
})
|
|
45044
45286
|
] });
|
|
45045
45287
|
}
|
|
45288
|
+
var numField;
|
|
45046
45289
|
var init_VariablePanel = __esm({
|
|
45047
45290
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
45048
45291
|
init_atoms2();
|
|
45049
45292
|
init_cn();
|
|
45293
|
+
numField = (v, fallback = 0) => {
|
|
45294
|
+
const n = Number(v);
|
|
45295
|
+
return Number.isFinite(n) ? n : fallback;
|
|
45296
|
+
};
|
|
45050
45297
|
VariablePanel.displayName = "VariablePanel";
|
|
45051
45298
|
}
|
|
45052
45299
|
});
|
|
@@ -45073,14 +45320,21 @@ function StateArchitectBoard({
|
|
|
45073
45320
|
}) {
|
|
45074
45321
|
const { emit } = useEventBus();
|
|
45075
45322
|
const { t } = hooks.useTranslate();
|
|
45076
|
-
const resolved =
|
|
45077
|
-
const
|
|
45323
|
+
const resolved = boardEntity(entity);
|
|
45324
|
+
const entityStates = Array.isArray(resolved?.states) ? resolved.states : [];
|
|
45325
|
+
const initialState = str(resolved?.initialState);
|
|
45326
|
+
const entityName = str(resolved?.entityName);
|
|
45327
|
+
const availableEvents = Array.isArray(resolved?.availableEvents) ? resolved.availableEvents : [];
|
|
45328
|
+
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
45329
|
+
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
45330
|
+
const entityVariables = rows(resolved?.variables);
|
|
45331
|
+
const [transitions, setTransitions] = React85.useState(entityTransitions);
|
|
45078
45332
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
45079
45333
|
const [playState, setPlayState] = React85.useState("editing");
|
|
45080
|
-
const [currentState, setCurrentState] = React85.useState(
|
|
45334
|
+
const [currentState, setCurrentState] = React85.useState(initialState);
|
|
45081
45335
|
const [selectedState, setSelectedState] = React85.useState(null);
|
|
45082
45336
|
const [testResults, setTestResults] = React85.useState([]);
|
|
45083
|
-
const [variables, setVariables] = React85.useState(
|
|
45337
|
+
const [variables, setVariables] = React85.useState(() => [...entityVariables]);
|
|
45084
45338
|
const [attempts, setAttempts] = React85.useState(0);
|
|
45085
45339
|
const timerRef = React85.useRef(null);
|
|
45086
45340
|
const [addingFrom, setAddingFrom] = React85.useState(null);
|
|
@@ -45089,12 +45343,12 @@ function StateArchitectBoard({
|
|
|
45089
45343
|
}, []);
|
|
45090
45344
|
const GRAPH_W = 500;
|
|
45091
45345
|
const GRAPH_H = 400;
|
|
45092
|
-
const positions = React85.useMemo(() => layoutStates(
|
|
45346
|
+
const positions = React85.useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
45093
45347
|
const handleStateClick = React85.useCallback((state) => {
|
|
45094
45348
|
if (playState !== "editing") return;
|
|
45095
45349
|
if (addingFrom) {
|
|
45096
45350
|
if (addingFrom !== state) {
|
|
45097
|
-
const event =
|
|
45351
|
+
const event = availableEvents[0] || "EVENT";
|
|
45098
45352
|
const newTrans = {
|
|
45099
45353
|
id: `t-${nextTransId++}`,
|
|
45100
45354
|
from: addingFrom,
|
|
@@ -45107,7 +45361,7 @@ function StateArchitectBoard({
|
|
|
45107
45361
|
} else {
|
|
45108
45362
|
setSelectedState(state);
|
|
45109
45363
|
}
|
|
45110
|
-
}, [playState, addingFrom,
|
|
45364
|
+
}, [playState, addingFrom, availableEvents]);
|
|
45111
45365
|
const handleStartAddTransition = React85.useCallback(() => {
|
|
45112
45366
|
if (!selectedState) return;
|
|
45113
45367
|
setAddingFrom(selectedState);
|
|
@@ -45116,9 +45370,9 @@ function StateArchitectBoard({
|
|
|
45116
45370
|
setTransitions((prev) => prev.filter((t2) => t2.id !== transId));
|
|
45117
45371
|
}, []);
|
|
45118
45372
|
const machine = React85.useMemo(() => ({
|
|
45119
|
-
name:
|
|
45120
|
-
description: resolved?.description
|
|
45121
|
-
states:
|
|
45373
|
+
name: entityName,
|
|
45374
|
+
description: str(resolved?.description),
|
|
45375
|
+
states: entityStates,
|
|
45122
45376
|
currentState,
|
|
45123
45377
|
transitions: transitions.map((t2) => ({
|
|
45124
45378
|
from: t2.from,
|
|
@@ -45126,7 +45380,7 @@ function StateArchitectBoard({
|
|
|
45126
45380
|
event: t2.event,
|
|
45127
45381
|
guardHint: t2.guardHint
|
|
45128
45382
|
}))
|
|
45129
|
-
}), [resolved, currentState, transitions]);
|
|
45383
|
+
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
45130
45384
|
const handleTest = React85.useCallback(() => {
|
|
45131
45385
|
if (playState !== "editing") return;
|
|
45132
45386
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
@@ -45135,7 +45389,7 @@ function StateArchitectBoard({
|
|
|
45135
45389
|
const results = [];
|
|
45136
45390
|
let testIdx = 0;
|
|
45137
45391
|
const runNextTest = () => {
|
|
45138
|
-
if (testIdx >=
|
|
45392
|
+
if (testIdx >= testCases.length) {
|
|
45139
45393
|
const allPassed = results.every((r) => r.passed);
|
|
45140
45394
|
setPlayState(allPassed ? "success" : "fail");
|
|
45141
45395
|
setTestResults(results);
|
|
@@ -45150,9 +45404,9 @@ function StateArchitectBoard({
|
|
|
45150
45404
|
}
|
|
45151
45405
|
return;
|
|
45152
45406
|
}
|
|
45153
|
-
const testCase =
|
|
45407
|
+
const testCase = testCases[testIdx];
|
|
45154
45408
|
if (!testCase) return;
|
|
45155
|
-
let state =
|
|
45409
|
+
let state = initialState;
|
|
45156
45410
|
for (const event of testCase.events) {
|
|
45157
45411
|
const trans = transitions.find((t2) => t2.from === state && t2.event === event);
|
|
45158
45412
|
if (trans) {
|
|
@@ -45170,53 +45424,57 @@ function StateArchitectBoard({
|
|
|
45170
45424
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
45171
45425
|
};
|
|
45172
45426
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
45173
|
-
}, [playState, transitions,
|
|
45427
|
+
}, [playState, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
45174
45428
|
const handleTryAgain = React85.useCallback(() => {
|
|
45175
45429
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45176
45430
|
setPlayState("editing");
|
|
45177
|
-
setCurrentState(
|
|
45431
|
+
setCurrentState(initialState);
|
|
45178
45432
|
setTestResults([]);
|
|
45179
|
-
}, [
|
|
45433
|
+
}, [initialState]);
|
|
45180
45434
|
const handleReset = React85.useCallback(() => {
|
|
45181
45435
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45182
|
-
setTransitions(
|
|
45436
|
+
setTransitions(entityTransitions);
|
|
45183
45437
|
setPlayState("editing");
|
|
45184
|
-
setCurrentState(
|
|
45438
|
+
setCurrentState(initialState);
|
|
45185
45439
|
setTestResults([]);
|
|
45186
|
-
setVariables(
|
|
45440
|
+
setVariables([...entityVariables]);
|
|
45187
45441
|
setSelectedState(null);
|
|
45188
45442
|
setAddingFrom(null);
|
|
45189
45443
|
setAttempts(0);
|
|
45190
|
-
}, [
|
|
45444
|
+
}, [entityTransitions, initialState, entityVariables]);
|
|
45191
45445
|
const codeData = React85.useMemo(() => ({
|
|
45192
|
-
name:
|
|
45193
|
-
states:
|
|
45194
|
-
initialState
|
|
45446
|
+
name: entityName,
|
|
45447
|
+
states: entityStates,
|
|
45448
|
+
initialState,
|
|
45195
45449
|
transitions: transitions.map((t2) => ({
|
|
45196
45450
|
from: t2.from,
|
|
45197
45451
|
to: t2.to,
|
|
45198
45452
|
event: t2.event,
|
|
45199
45453
|
...t2.guardHint ? { guard: t2.guardHint } : {}
|
|
45200
45454
|
}))
|
|
45201
|
-
}), [
|
|
45455
|
+
}), [entityName, entityStates, initialState, transitions]);
|
|
45202
45456
|
if (!resolved) return null;
|
|
45457
|
+
const theme = resolved.theme ?? void 0;
|
|
45458
|
+
const themeBackground = theme?.background;
|
|
45459
|
+
const headerImage = str(resolved.headerImage);
|
|
45460
|
+
const hint = str(resolved.hint);
|
|
45203
45461
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
45204
45462
|
VStack,
|
|
45205
45463
|
{
|
|
45206
45464
|
className: cn("p-4 gap-6", className),
|
|
45207
45465
|
style: {
|
|
45208
|
-
backgroundImage:
|
|
45466
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
45209
45467
|
backgroundSize: "cover",
|
|
45210
45468
|
backgroundPosition: "center"
|
|
45211
45469
|
},
|
|
45212
45470
|
children: [
|
|
45213
|
-
|
|
45471
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
45214
45472
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
45215
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
45216
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
45473
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
45474
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
45217
45475
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
|
|
45218
45476
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
|
|
45219
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children:
|
|
45477
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: hint })
|
|
45220
45478
|
] })
|
|
45221
45479
|
] }),
|
|
45222
45480
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
|
|
@@ -45264,14 +45522,14 @@ function StateArchitectBoard({
|
|
|
45264
45522
|
]
|
|
45265
45523
|
}
|
|
45266
45524
|
),
|
|
45267
|
-
|
|
45525
|
+
entityStates.map((state) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45268
45526
|
StateNode2,
|
|
45269
45527
|
{
|
|
45270
45528
|
name: state,
|
|
45271
45529
|
position: positions[state],
|
|
45272
45530
|
isCurrent: state === currentState,
|
|
45273
45531
|
isSelected: state === selectedState,
|
|
45274
|
-
isInitial: state ===
|
|
45532
|
+
isInitial: state === initialState,
|
|
45275
45533
|
onClick: () => handleStateClick(state)
|
|
45276
45534
|
},
|
|
45277
45535
|
state
|
|
@@ -45318,7 +45576,7 @@ function StateArchitectBoard({
|
|
|
45318
45576
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45319
45577
|
VariablePanel,
|
|
45320
45578
|
{
|
|
45321
|
-
entityName
|
|
45579
|
+
entityName,
|
|
45322
45580
|
variables
|
|
45323
45581
|
}
|
|
45324
45582
|
),
|
|
@@ -45333,12 +45591,12 @@ function StateArchitectBoard({
|
|
|
45333
45591
|
resolved.showCodeView !== false && /* @__PURE__ */ jsxRuntime.jsx(CodeView, { data: codeData, label: "View Code" })
|
|
45334
45592
|
] })
|
|
45335
45593
|
] }),
|
|
45336
|
-
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("stateArchitect.allPassed") }) }),
|
|
45594
|
+
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("stateArchitect.allPassed") }) }),
|
|
45337
45595
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
45338
45596
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
|
|
45339
|
-
attempts >= 3 &&
|
|
45597
|
+
attempts >= 3 && hint && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
45340
45598
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
45341
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
45599
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
45342
45600
|
] }) })
|
|
45343
45601
|
] }),
|
|
45344
45602
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -45368,6 +45626,7 @@ var init_StateArchitectBoard = __esm({
|
|
|
45368
45626
|
init_TransitionArrow();
|
|
45369
45627
|
init_VariablePanel();
|
|
45370
45628
|
init_CodeView();
|
|
45629
|
+
init_boardEntity();
|
|
45371
45630
|
ENCOURAGEMENT_KEYS3 = [
|
|
45372
45631
|
"puzzle.tryAgain1",
|
|
45373
45632
|
"puzzle.tryAgain2",
|
|
@@ -45404,8 +45663,8 @@ var init_StatsOrganism = __esm({
|
|
|
45404
45663
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
45405
45664
|
}
|
|
45406
45665
|
const stats = items.map((item) => ({
|
|
45407
|
-
value: item.value,
|
|
45408
|
-
label: item.label
|
|
45666
|
+
value: String(item.value ?? ""),
|
|
45667
|
+
label: String(item.label ?? "")
|
|
45409
45668
|
}));
|
|
45410
45669
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45411
45670
|
StatsGrid,
|
|
@@ -45451,10 +45710,10 @@ var init_StepFlowOrganism = __esm({
|
|
|
45451
45710
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
45452
45711
|
}
|
|
45453
45712
|
const steps = items.map((item) => ({
|
|
45454
|
-
number: item.number,
|
|
45455
|
-
title: item.title,
|
|
45456
|
-
description: item.description,
|
|
45457
|
-
icon: item.icon
|
|
45713
|
+
number: item.number != null ? Number(item.number) : void 0,
|
|
45714
|
+
title: String(item.title ?? ""),
|
|
45715
|
+
description: String(item.description ?? ""),
|
|
45716
|
+
icon: item.icon != null ? String(item.icon) : void 0
|
|
45458
45717
|
}));
|
|
45459
45718
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
45460
45719
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -45627,13 +45886,13 @@ var init_TeamOrganism = __esm({
|
|
|
45627
45886
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((member) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45628
45887
|
TeamCard,
|
|
45629
45888
|
{
|
|
45630
|
-
name: member.name,
|
|
45631
|
-
nameAr: member.nameAr,
|
|
45632
|
-
role: member.role,
|
|
45633
|
-
bio: member.bio,
|
|
45634
|
-
avatar: member.avatar
|
|
45889
|
+
name: String(member.name ?? ""),
|
|
45890
|
+
nameAr: member.nameAr != null ? String(member.nameAr) : void 0,
|
|
45891
|
+
role: String(member.role ?? ""),
|
|
45892
|
+
bio: String(member.bio ?? ""),
|
|
45893
|
+
avatar: member.avatar != null ? String(member.avatar) : void 0
|
|
45635
45894
|
},
|
|
45636
|
-
member.id
|
|
45895
|
+
String(member.id ?? "")
|
|
45637
45896
|
)) })
|
|
45638
45897
|
] });
|
|
45639
45898
|
};
|
|
@@ -45870,8 +46129,8 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45870
46129
|
const [turn, setTurn] = React85.useState(1);
|
|
45871
46130
|
const [gameResult, setGameResult] = React85.useState(null);
|
|
45872
46131
|
const checkGameEnd = React85.useCallback((currentUnits) => {
|
|
45873
|
-
const pa = currentUnits.filter((u) => u
|
|
45874
|
-
const ea = currentUnits.filter((u) => u
|
|
46132
|
+
const pa = currentUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
46133
|
+
const ea = currentUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
45875
46134
|
if (pa.length === 0) {
|
|
45876
46135
|
setGameResult("defeat");
|
|
45877
46136
|
setPhase("game_over");
|
|
@@ -45889,34 +46148,36 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45889
46148
|
}
|
|
45890
46149
|
}, [onGameEnd, gameEndEvent, eventBus]);
|
|
45891
46150
|
const handleUnitClick = React85.useCallback((unitId) => {
|
|
45892
|
-
const unit = units.find((u) => u.id === unitId);
|
|
46151
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
45893
46152
|
if (!unit) return;
|
|
45894
46153
|
if (unitClickEvent) {
|
|
45895
46154
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
45896
46155
|
}
|
|
45897
46156
|
if (phase === "observation" || phase === "selection") {
|
|
45898
|
-
if (unit
|
|
46157
|
+
if (unitTeam(unit) === "player") {
|
|
45899
46158
|
setSelectedUnitId(unitId);
|
|
45900
46159
|
setPhase("movement");
|
|
45901
46160
|
}
|
|
45902
46161
|
} else if (phase === "action") {
|
|
45903
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
46162
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45904
46163
|
if (!selectedUnit) return;
|
|
45905
|
-
if (unit
|
|
45906
|
-
const
|
|
45907
|
-
const
|
|
46164
|
+
if (unitTeam(unit) === "enemy") {
|
|
46165
|
+
const up = unitPosition(unit);
|
|
46166
|
+
const sp = unitPosition(selectedUnit);
|
|
46167
|
+
const dx = Math.abs(up.x - sp.x);
|
|
46168
|
+
const dy = Math.abs(up.y - sp.y);
|
|
45908
46169
|
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
45909
|
-
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
|
|
45910
|
-
const newHealth = Math.max(0, unit
|
|
46170
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
46171
|
+
const newHealth = Math.max(0, unitHealth(unit) - damage);
|
|
45911
46172
|
const updatedUnits = units.map(
|
|
45912
|
-
(u) => u.id === unit.id ? { ...u, health: newHealth } : u
|
|
46173
|
+
(u) => str(u.id) === str(unit.id) ? { ...u, health: newHealth } : u
|
|
45913
46174
|
);
|
|
45914
46175
|
setUnits(updatedUnits);
|
|
45915
46176
|
onAttack?.(selectedUnit, unit, damage);
|
|
45916
46177
|
if (attackEvent) {
|
|
45917
46178
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
45918
|
-
attackerId: selectedUnit.id,
|
|
45919
|
-
targetId: unit.id,
|
|
46179
|
+
attackerId: str(selectedUnit.id),
|
|
46180
|
+
targetId: str(unit.id),
|
|
45920
46181
|
damage
|
|
45921
46182
|
});
|
|
45922
46183
|
}
|
|
@@ -45933,16 +46194,20 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45933
46194
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
45934
46195
|
}
|
|
45935
46196
|
if (phase === "movement" && selectedUnitId) {
|
|
45936
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
46197
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45937
46198
|
if (!selectedUnit) return;
|
|
45938
|
-
const
|
|
45939
|
-
const
|
|
46199
|
+
const sp = unitPosition(selectedUnit);
|
|
46200
|
+
const dx = Math.abs(x - sp.x);
|
|
46201
|
+
const dy = Math.abs(y - sp.y);
|
|
45940
46202
|
const dist = dx + dy;
|
|
45941
|
-
if (dist > 0 && dist <= selectedUnit.movement) {
|
|
45942
|
-
if (!units.some((u) =>
|
|
46203
|
+
if (dist > 0 && dist <= num(selectedUnit.movement)) {
|
|
46204
|
+
if (!units.some((u) => {
|
|
46205
|
+
const p2 = unitPosition(u);
|
|
46206
|
+
return p2.x === x && p2.y === y && unitHealth(u) > 0;
|
|
46207
|
+
})) {
|
|
45943
46208
|
setUnits(
|
|
45944
46209
|
(prev) => prev.map(
|
|
45945
|
-
(u) => u.id === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
46210
|
+
(u) => str(u.id) === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
45946
46211
|
)
|
|
45947
46212
|
);
|
|
45948
46213
|
setPhase("action");
|
|
@@ -45985,12 +46250,13 @@ var init_useBattleState = __esm({
|
|
|
45985
46250
|
"components/game/organisms/hooks/useBattleState.ts"() {
|
|
45986
46251
|
"use client";
|
|
45987
46252
|
init_useEventBus();
|
|
46253
|
+
init_boardEntity();
|
|
45988
46254
|
}
|
|
45989
46255
|
});
|
|
45990
46256
|
function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
45991
|
-
const resolved =
|
|
46257
|
+
const resolved = boardEntity(entity);
|
|
45992
46258
|
const battleState = useBattleState(
|
|
45993
|
-
resolved?.initialUnits
|
|
46259
|
+
rows(resolved?.initialUnits),
|
|
45994
46260
|
{
|
|
45995
46261
|
tileClickEvent: rest.tileClickEvent,
|
|
45996
46262
|
unitClickEvent: rest.unitClickEvent,
|
|
@@ -46026,10 +46292,23 @@ function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
|
46026
46292
|
var init_UncontrolledBattleBoard = __esm({
|
|
46027
46293
|
"components/game/organisms/UncontrolledBattleBoard.tsx"() {
|
|
46028
46294
|
init_BattleBoard();
|
|
46295
|
+
init_boardEntity();
|
|
46029
46296
|
init_useBattleState();
|
|
46030
46297
|
UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
|
|
46031
46298
|
}
|
|
46032
46299
|
});
|
|
46300
|
+
function heroPosition(h) {
|
|
46301
|
+
return vec2(h.position);
|
|
46302
|
+
}
|
|
46303
|
+
function heroOwner(h) {
|
|
46304
|
+
return str(h.owner);
|
|
46305
|
+
}
|
|
46306
|
+
function heroMovement(h) {
|
|
46307
|
+
return num(h.movement);
|
|
46308
|
+
}
|
|
46309
|
+
function hexPassable(h) {
|
|
46310
|
+
return h.passable !== false;
|
|
46311
|
+
}
|
|
46033
46312
|
function defaultIsInRange(from, to, range) {
|
|
46034
46313
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
46035
46314
|
}
|
|
@@ -46060,36 +46339,36 @@ function WorldMapBoard({
|
|
|
46060
46339
|
className
|
|
46061
46340
|
}) {
|
|
46062
46341
|
const eventBus = useEventBus();
|
|
46063
|
-
const resolved =
|
|
46064
|
-
const hexes = resolved?.hexes
|
|
46065
|
-
const heroes = resolved?.heroes
|
|
46066
|
-
const features = resolved?.features
|
|
46067
|
-
const selectedHeroId = resolved?.selectedHeroId;
|
|
46342
|
+
const resolved = boardEntity(entity);
|
|
46343
|
+
const hexes = rows(resolved?.hexes);
|
|
46344
|
+
const heroes = rows(resolved?.heroes);
|
|
46345
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
46346
|
+
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
46068
46347
|
const assetManifest = resolved?.assetManifest;
|
|
46069
46348
|
const backgroundImage = resolved?.backgroundImage;
|
|
46070
46349
|
const [hoveredTile, setHoveredTile] = React85.useState(null);
|
|
46071
46350
|
const selectedHero = React85.useMemo(
|
|
46072
|
-
() => heroes.find((h) => h.id === selectedHeroId) ?? null,
|
|
46351
|
+
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
46073
46352
|
[heroes, selectedHeroId]
|
|
46074
46353
|
);
|
|
46075
46354
|
const tiles = React85.useMemo(
|
|
46076
46355
|
() => hexes.map((hex) => ({
|
|
46077
|
-
x: hex.x,
|
|
46078
|
-
y: hex.y,
|
|
46079
|
-
terrain: hex.terrain,
|
|
46080
|
-
terrainSprite: hex.terrainSprite
|
|
46356
|
+
x: num(hex.x),
|
|
46357
|
+
y: num(hex.y),
|
|
46358
|
+
terrain: str(hex.terrain),
|
|
46359
|
+
terrainSprite: hex.terrainSprite == null ? void 0 : str(hex.terrainSprite)
|
|
46081
46360
|
})),
|
|
46082
46361
|
[hexes]
|
|
46083
46362
|
);
|
|
46084
46363
|
const baseUnits = React85.useMemo(
|
|
46085
46364
|
() => heroes.map((hero) => ({
|
|
46086
|
-
id: hero.id,
|
|
46087
|
-
position: hero
|
|
46088
|
-
name: hero.name,
|
|
46089
|
-
team: hero
|
|
46365
|
+
id: str(hero.id),
|
|
46366
|
+
position: heroPosition(hero),
|
|
46367
|
+
name: str(hero.name),
|
|
46368
|
+
team: heroOwner(hero) === "enemy" ? "enemy" : "player",
|
|
46090
46369
|
health: 100,
|
|
46091
46370
|
maxHealth: 100,
|
|
46092
|
-
sprite: hero.sprite
|
|
46371
|
+
sprite: hero.sprite == null ? void 0 : str(hero.sprite)
|
|
46093
46372
|
})),
|
|
46094
46373
|
[heroes]
|
|
46095
46374
|
);
|
|
@@ -46130,73 +46409,94 @@ function WorldMapBoard({
|
|
|
46130
46409
|
const isoUnits = React85.useMemo(() => {
|
|
46131
46410
|
if (movingPositions.size === 0) return baseUnits;
|
|
46132
46411
|
return baseUnits.map((u) => {
|
|
46133
|
-
const pos = movingPositions.get(u.id);
|
|
46412
|
+
const pos = u.id == null ? void 0 : movingPositions.get(u.id);
|
|
46134
46413
|
return pos ? { ...u, position: pos } : u;
|
|
46135
46414
|
});
|
|
46136
46415
|
}, [baseUnits, movingPositions]);
|
|
46137
46416
|
const validMoves = React85.useMemo(() => {
|
|
46138
|
-
if (!selectedHero || selectedHero
|
|
46417
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46418
|
+
const sp = heroPosition(selectedHero);
|
|
46419
|
+
const sOwner = heroOwner(selectedHero);
|
|
46420
|
+
const range = heroMovement(selectedHero);
|
|
46139
46421
|
const moves = [];
|
|
46140
46422
|
hexes.forEach((hex) => {
|
|
46141
|
-
|
|
46142
|
-
|
|
46143
|
-
if (!
|
|
46144
|
-
if (
|
|
46145
|
-
|
|
46423
|
+
const hx = num(hex.x);
|
|
46424
|
+
const hy = num(hex.y);
|
|
46425
|
+
if (!hexPassable(hex)) return;
|
|
46426
|
+
if (hx === sp.x && hy === sp.y) return;
|
|
46427
|
+
if (!isInRange(sp, { x: hx, y: hy }, range)) return;
|
|
46428
|
+
if (heroes.some((h) => {
|
|
46429
|
+
const hp = heroPosition(h);
|
|
46430
|
+
return hp.x === hx && hp.y === hy && heroOwner(h) === sOwner;
|
|
46431
|
+
})) return;
|
|
46432
|
+
moves.push({ x: hx, y: hy });
|
|
46146
46433
|
});
|
|
46147
46434
|
return moves;
|
|
46148
46435
|
}, [selectedHero, hexes, heroes, isInRange]);
|
|
46149
46436
|
const attackTargets = React85.useMemo(() => {
|
|
46150
|
-
if (!selectedHero || selectedHero
|
|
46151
|
-
|
|
46437
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46438
|
+
const sp = heroPosition(selectedHero);
|
|
46439
|
+
const sOwner = heroOwner(selectedHero);
|
|
46440
|
+
const range = heroMovement(selectedHero);
|
|
46441
|
+
return heroes.filter((h) => heroOwner(h) !== sOwner).filter((h) => isInRange(sp, heroPosition(h), range)).map((h) => heroPosition(h));
|
|
46152
46442
|
}, [selectedHero, heroes, isInRange]);
|
|
46153
|
-
const maxY = Math.max(...hexes.map((h) => h.y), 0);
|
|
46443
|
+
const maxY = Math.max(...hexes.map((h) => num(h.y)), 0);
|
|
46154
46444
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
46155
46445
|
const tileToScreen = React85.useCallback(
|
|
46156
46446
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
46157
46447
|
[scale, baseOffsetX]
|
|
46158
46448
|
);
|
|
46159
46449
|
const hoveredHex = React85.useMemo(
|
|
46160
|
-
() => hoveredTile ? hexes.find((h) => h.x === hoveredTile.x && h.y === hoveredTile.y) ?? null : null,
|
|
46450
|
+
() => hoveredTile ? hexes.find((h) => num(h.x) === hoveredTile.x && num(h.y) === hoveredTile.y) ?? null : null,
|
|
46161
46451
|
[hoveredTile, hexes]
|
|
46162
46452
|
);
|
|
46163
46453
|
const hoveredHero = React85.useMemo(
|
|
46164
|
-
() => hoveredTile ? heroes.find((h) =>
|
|
46454
|
+
() => hoveredTile ? heroes.find((h) => {
|
|
46455
|
+
const hp = heroPosition(h);
|
|
46456
|
+
return hp.x === hoveredTile.x && hp.y === hoveredTile.y;
|
|
46457
|
+
}) ?? null : null,
|
|
46165
46458
|
[hoveredTile, heroes]
|
|
46166
46459
|
);
|
|
46167
46460
|
const handleTileClick = React85.useCallback((x, y) => {
|
|
46168
46461
|
if (movementAnimRef.current) return;
|
|
46169
|
-
const hex = hexes.find((h) => h.x === x && h.y === y);
|
|
46462
|
+
const hex = hexes.find((h) => num(h.x) === x && num(h.y) === y);
|
|
46170
46463
|
if (!hex) return;
|
|
46171
46464
|
if (tileClickEvent) {
|
|
46172
46465
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
46173
46466
|
}
|
|
46174
46467
|
if (selectedHero && validMoves.some((m) => m.x === x && m.y === y)) {
|
|
46175
|
-
|
|
46176
|
-
|
|
46468
|
+
const heroId = str(selectedHero.id);
|
|
46469
|
+
startMoveAnimation(heroId, { ...heroPosition(selectedHero) }, { x, y }, () => {
|
|
46470
|
+
onHeroMove?.(heroId, x, y);
|
|
46177
46471
|
if (heroMoveEvent) {
|
|
46178
|
-
eventBus.emit(`UI:${heroMoveEvent}`, { heroId
|
|
46472
|
+
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
46179
46473
|
}
|
|
46180
|
-
|
|
46181
|
-
|
|
46474
|
+
const feature = str(hex.feature);
|
|
46475
|
+
if (feature && feature !== "none") {
|
|
46476
|
+
onFeatureEnter?.(heroId, hex);
|
|
46182
46477
|
if (featureEnterEvent) {
|
|
46183
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId
|
|
46478
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
46184
46479
|
}
|
|
46185
46480
|
}
|
|
46186
46481
|
});
|
|
46187
46482
|
return;
|
|
46188
46483
|
}
|
|
46189
|
-
const enemy = heroes.find((h) =>
|
|
46484
|
+
const enemy = heroes.find((h) => {
|
|
46485
|
+
const hp = heroPosition(h);
|
|
46486
|
+
return hp.x === x && hp.y === y && heroOwner(h) === "enemy";
|
|
46487
|
+
});
|
|
46190
46488
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
46191
|
-
|
|
46489
|
+
const attackerId = str(selectedHero.id);
|
|
46490
|
+
const defenderId = str(enemy.id);
|
|
46491
|
+
onBattleEncounter?.(attackerId, defenderId);
|
|
46192
46492
|
if (battleEncounterEvent) {
|
|
46193
|
-
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId
|
|
46493
|
+
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
46194
46494
|
}
|
|
46195
46495
|
}
|
|
46196
46496
|
}, [hexes, heroes, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
46197
46497
|
const handleUnitClick = React85.useCallback((unitId) => {
|
|
46198
|
-
const hero = heroes.find((h) => h.id === unitId);
|
|
46199
|
-
if (hero && (hero
|
|
46498
|
+
const hero = heroes.find((h) => str(h.id) === unitId);
|
|
46499
|
+
if (hero && (heroOwner(hero) === "player" || allowMoveAllHeroes)) {
|
|
46200
46500
|
onHeroSelect?.(unitId);
|
|
46201
46501
|
if (heroSelectEvent) {
|
|
46202
46502
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
@@ -46269,6 +46569,7 @@ var init_WorldMapBoard = __esm({
|
|
|
46269
46569
|
init_Stack();
|
|
46270
46570
|
init_LoadingState();
|
|
46271
46571
|
init_IsometricCanvas2();
|
|
46572
|
+
init_boardEntity();
|
|
46272
46573
|
init_isometric();
|
|
46273
46574
|
WorldMapBoard.displayName = "WorldMapBoard";
|
|
46274
46575
|
}
|