@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/avl/index.cjs
CHANGED
|
@@ -7179,7 +7179,7 @@ var init_SvgGrid = __esm({
|
|
|
7179
7179
|
x,
|
|
7180
7180
|
y,
|
|
7181
7181
|
cols = 4,
|
|
7182
|
-
rows = 3,
|
|
7182
|
+
rows: rows2 = 3,
|
|
7183
7183
|
spacing = 20,
|
|
7184
7184
|
nodeRadius = 3,
|
|
7185
7185
|
color = "var(--color-primary)",
|
|
@@ -7188,7 +7188,7 @@ var init_SvgGrid = __esm({
|
|
|
7188
7188
|
highlights = []
|
|
7189
7189
|
}) => {
|
|
7190
7190
|
const highlightSet = new Set(highlights);
|
|
7191
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length:
|
|
7191
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length: rows2 }).map(
|
|
7192
7192
|
(_, row) => Array.from({ length: cols }).map((_2, col) => {
|
|
7193
7193
|
const index = row * cols + col;
|
|
7194
7194
|
const isHighlighted = highlightSet.has(index);
|
|
@@ -7848,7 +7848,7 @@ var init_Input = __esm({
|
|
|
7848
7848
|
onClear,
|
|
7849
7849
|
value,
|
|
7850
7850
|
options,
|
|
7851
|
-
rows = 3,
|
|
7851
|
+
rows: rows2 = 3,
|
|
7852
7852
|
onChange,
|
|
7853
7853
|
...props
|
|
7854
7854
|
}, ref) => {
|
|
@@ -7898,7 +7898,7 @@ var init_Input = __esm({
|
|
|
7898
7898
|
ref,
|
|
7899
7899
|
value,
|
|
7900
7900
|
onChange,
|
|
7901
|
-
rows,
|
|
7901
|
+
rows: rows2,
|
|
7902
7902
|
className: baseClassName,
|
|
7903
7903
|
...props
|
|
7904
7904
|
}
|
|
@@ -9893,66 +9893,6 @@ var init_RangeSlider = __esm({
|
|
|
9893
9893
|
RangeSlider.displayName = "RangeSlider";
|
|
9894
9894
|
}
|
|
9895
9895
|
});
|
|
9896
|
-
function easeOut(t) {
|
|
9897
|
-
return t * (2 - t);
|
|
9898
|
-
}
|
|
9899
|
-
var AnimatedCounter;
|
|
9900
|
-
var init_AnimatedCounter = __esm({
|
|
9901
|
-
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
9902
|
-
"use client";
|
|
9903
|
-
init_cn();
|
|
9904
|
-
init_Typography();
|
|
9905
|
-
AnimatedCounter = ({
|
|
9906
|
-
value: rawValue,
|
|
9907
|
-
duration = 600,
|
|
9908
|
-
prefix,
|
|
9909
|
-
suffix,
|
|
9910
|
-
className
|
|
9911
|
-
}) => {
|
|
9912
|
-
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
9913
|
-
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
9914
|
-
const [displayValue, setDisplayValue] = React97.useState(value);
|
|
9915
|
-
const previousValueRef = React97.useRef(value);
|
|
9916
|
-
const animationFrameRef = React97.useRef(null);
|
|
9917
|
-
React97.useEffect(() => {
|
|
9918
|
-
const from = previousValueRef.current;
|
|
9919
|
-
const to = value;
|
|
9920
|
-
previousValueRef.current = value;
|
|
9921
|
-
if (from === to) {
|
|
9922
|
-
setDisplayValue(to);
|
|
9923
|
-
return;
|
|
9924
|
-
}
|
|
9925
|
-
const startTime = performance.now();
|
|
9926
|
-
const diff = to - from;
|
|
9927
|
-
function animate(currentTime) {
|
|
9928
|
-
const elapsed = currentTime - startTime;
|
|
9929
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
9930
|
-
const easedProgress = easeOut(progress);
|
|
9931
|
-
setDisplayValue(from + diff * easedProgress);
|
|
9932
|
-
if (progress < 1) {
|
|
9933
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
9934
|
-
} else {
|
|
9935
|
-
setDisplayValue(to);
|
|
9936
|
-
}
|
|
9937
|
-
}
|
|
9938
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
9939
|
-
return () => {
|
|
9940
|
-
if (animationFrameRef.current !== null) {
|
|
9941
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
9942
|
-
}
|
|
9943
|
-
};
|
|
9944
|
-
}, [value, duration]);
|
|
9945
|
-
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
9946
|
-
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
9947
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
9948
|
-
prefix,
|
|
9949
|
-
formattedValue,
|
|
9950
|
-
suffix
|
|
9951
|
-
] });
|
|
9952
|
-
};
|
|
9953
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
9954
|
-
}
|
|
9955
|
-
});
|
|
9956
9896
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
9957
9897
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
9958
9898
|
const observerRef = React97.useRef(null);
|
|
@@ -12436,15 +12376,15 @@ function HeaderSkeleton({ className }) {
|
|
|
12436
12376
|
] })
|
|
12437
12377
|
] });
|
|
12438
12378
|
}
|
|
12439
|
-
function TableSkeleton({ rows = 5, columns = 4, className }) {
|
|
12379
|
+
function TableSkeleton({ rows: rows2 = 5, columns = 4, className }) {
|
|
12440
12380
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: cn("border border-border rounded-lg overflow-hidden", className), children: [
|
|
12441
12381
|
/* @__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)) }),
|
|
12442
|
-
Array.from({ length:
|
|
12382
|
+
Array.from({ length: rows2 }).map((_, rowIdx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12443
12383
|
HStack,
|
|
12444
12384
|
{
|
|
12445
12385
|
className: cn(
|
|
12446
12386
|
"px-4 py-3",
|
|
12447
|
-
rowIdx <
|
|
12387
|
+
rowIdx < rows2 - 1 && "border-b border-border"
|
|
12448
12388
|
),
|
|
12449
12389
|
children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonLine, { className: "flex-1 mx-2" }, colIdx))
|
|
12450
12390
|
},
|
|
@@ -12492,18 +12432,18 @@ function CardSkeleton({ className }) {
|
|
|
12492
12432
|
}
|
|
12493
12433
|
);
|
|
12494
12434
|
}
|
|
12495
|
-
function TextSkeleton({ rows = 3, className }) {
|
|
12496
|
-
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length:
|
|
12435
|
+
function TextSkeleton({ rows: rows2 = 3, className }) {
|
|
12436
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length: rows2 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12497
12437
|
SkeletonLine,
|
|
12498
12438
|
{
|
|
12499
|
-
className: i ===
|
|
12439
|
+
className: i === rows2 - 1 ? "w-2/3" : "w-full"
|
|
12500
12440
|
},
|
|
12501
12441
|
i
|
|
12502
12442
|
)) });
|
|
12503
12443
|
}
|
|
12504
12444
|
function Skeleton({
|
|
12505
12445
|
variant = "text",
|
|
12506
|
-
rows,
|
|
12446
|
+
rows: rows2,
|
|
12507
12447
|
columns,
|
|
12508
12448
|
fields,
|
|
12509
12449
|
className
|
|
@@ -12513,15 +12453,15 @@ function Skeleton({
|
|
|
12513
12453
|
case "header":
|
|
12514
12454
|
return /* @__PURE__ */ jsxRuntime.jsx(HeaderSkeleton, { className });
|
|
12515
12455
|
case "table":
|
|
12516
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows, columns, className });
|
|
12456
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows: rows2, columns, className });
|
|
12517
12457
|
case "form":
|
|
12518
12458
|
return /* @__PURE__ */ jsxRuntime.jsx(FormSkeleton, { fields, className });
|
|
12519
12459
|
case "card":
|
|
12520
12460
|
return /* @__PURE__ */ jsxRuntime.jsx(CardSkeleton, { className });
|
|
12521
12461
|
case "text":
|
|
12522
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
12462
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
12523
12463
|
default:
|
|
12524
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
12464
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
12525
12465
|
}
|
|
12526
12466
|
}
|
|
12527
12467
|
var pulseClass;
|
|
@@ -13675,7 +13615,7 @@ var init_Menu = __esm({
|
|
|
13675
13615
|
className
|
|
13676
13616
|
}) => {
|
|
13677
13617
|
const eventBus = useEventBus();
|
|
13678
|
-
const { t } = hooks.useTranslate();
|
|
13618
|
+
const { t, direction } = hooks.useTranslate();
|
|
13679
13619
|
const [isOpen, setIsOpen] = React97.useState(false);
|
|
13680
13620
|
const [activeSubMenu, setActiveSubMenu] = React97.useState(null);
|
|
13681
13621
|
const [triggerRect, setTriggerRect] = React97.useState(null);
|
|
@@ -13729,6 +13669,18 @@ var init_Menu = __esm({
|
|
|
13729
13669
|
"bottom-start": "top-full left-0 mt-2",
|
|
13730
13670
|
"bottom-end": "top-full right-0 mt-2"
|
|
13731
13671
|
};
|
|
13672
|
+
const rtlMirror = {
|
|
13673
|
+
"top-left": "top-right",
|
|
13674
|
+
"top-right": "top-left",
|
|
13675
|
+
"bottom-left": "bottom-right",
|
|
13676
|
+
"bottom-right": "bottom-left",
|
|
13677
|
+
"top-start": "top-end",
|
|
13678
|
+
"top-end": "top-start",
|
|
13679
|
+
"bottom-start": "bottom-end",
|
|
13680
|
+
"bottom-end": "bottom-start"
|
|
13681
|
+
};
|
|
13682
|
+
const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
|
|
13683
|
+
const subMenuSideClass = direction === "rtl" ? "right-full mr-2" : "left-full ml-2";
|
|
13732
13684
|
const triggerChild = React97__namespace.default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", as: "span", children: trigger });
|
|
13733
13685
|
const triggerElement = React97__namespace.default.cloneElement(
|
|
13734
13686
|
triggerChild,
|
|
@@ -13756,7 +13708,7 @@ var init_Menu = __esm({
|
|
|
13756
13708
|
onMouseEnter: () => hasSubMenu && setActiveSubMenu(itemId),
|
|
13757
13709
|
"data-testid": item.event ? `action-${item.event}` : void 0,
|
|
13758
13710
|
className: cn(
|
|
13759
|
-
"w-full flex items-center justify-between gap-3 px-4 py-2 text-
|
|
13711
|
+
"w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
|
|
13760
13712
|
"text-sm transition-colors",
|
|
13761
13713
|
"hover:bg-muted",
|
|
13762
13714
|
"focus:outline-none focus:bg-muted",
|
|
@@ -13775,7 +13727,7 @@ var init_Menu = __esm({
|
|
|
13775
13727
|
}
|
|
13776
13728
|
),
|
|
13777
13729
|
item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
|
|
13778
|
-
hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "chevron-right", size: "sm", className: "flex-shrink-0" })
|
|
13730
|
+
hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: direction === "rtl" ? "chevron-left" : "chevron-right", size: "sm", className: "flex-shrink-0" })
|
|
13779
13731
|
] })
|
|
13780
13732
|
},
|
|
13781
13733
|
itemId
|
|
@@ -13795,7 +13747,8 @@ var init_Menu = __esm({
|
|
|
13795
13747
|
Box,
|
|
13796
13748
|
{
|
|
13797
13749
|
className: cn(
|
|
13798
|
-
"absolute
|
|
13750
|
+
"absolute top-0 z-50",
|
|
13751
|
+
subMenuSideClass,
|
|
13799
13752
|
menuContainerStyles
|
|
13800
13753
|
),
|
|
13801
13754
|
children: renderMenuItems(item.subMenu)
|
|
@@ -13813,12 +13766,12 @@ var init_Menu = __esm({
|
|
|
13813
13766
|
className: cn(
|
|
13814
13767
|
"absolute z-50",
|
|
13815
13768
|
menuContainerStyles,
|
|
13816
|
-
positionClasses3[
|
|
13769
|
+
positionClasses3[effectivePosition],
|
|
13817
13770
|
className
|
|
13818
13771
|
),
|
|
13819
13772
|
style: {
|
|
13820
|
-
left:
|
|
13821
|
-
right:
|
|
13773
|
+
left: effectivePosition.includes("left") ? 0 : "auto",
|
|
13774
|
+
right: effectivePosition.includes("right") ? 0 : "auto"
|
|
13822
13775
|
},
|
|
13823
13776
|
role: "menu",
|
|
13824
13777
|
children: renderMenuItems(items)
|
|
@@ -14136,7 +14089,7 @@ var init_MapView = __esm({
|
|
|
14136
14089
|
shadowSize: [41, 41]
|
|
14137
14090
|
});
|
|
14138
14091
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
14139
|
-
const { useEffect: useEffect79, useRef: useRef71, useCallback:
|
|
14092
|
+
const { useEffect: useEffect79, useRef: useRef71, useCallback: useCallback123, useState: useState113 } = React97__namespace.default;
|
|
14140
14093
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
14141
14094
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
14142
14095
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -14182,7 +14135,7 @@ var init_MapView = __esm({
|
|
|
14182
14135
|
}) {
|
|
14183
14136
|
const eventBus = useEventBus3();
|
|
14184
14137
|
const [clickedPosition, setClickedPosition] = useState113(null);
|
|
14185
|
-
const handleMapClick =
|
|
14138
|
+
const handleMapClick = useCallback123((lat, lng) => {
|
|
14186
14139
|
if (showClickedPin) {
|
|
14187
14140
|
setClickedPosition({ lat, lng });
|
|
14188
14141
|
}
|
|
@@ -14191,7 +14144,7 @@ var init_MapView = __esm({
|
|
|
14191
14144
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
14192
14145
|
}
|
|
14193
14146
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
14194
|
-
const handleMarkerClick =
|
|
14147
|
+
const handleMarkerClick = useCallback123((marker) => {
|
|
14195
14148
|
onMarkerClick?.(marker);
|
|
14196
14149
|
if (markerClickEvent) {
|
|
14197
14150
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -14412,7 +14365,7 @@ function InputPattern({
|
|
|
14412
14365
|
function TextareaPattern({
|
|
14413
14366
|
value = "",
|
|
14414
14367
|
placeholder,
|
|
14415
|
-
rows = 4,
|
|
14368
|
+
rows: rows2 = 4,
|
|
14416
14369
|
disabled = false,
|
|
14417
14370
|
fieldError,
|
|
14418
14371
|
onChange,
|
|
@@ -14432,7 +14385,7 @@ function TextareaPattern({
|
|
|
14432
14385
|
{
|
|
14433
14386
|
value: localValue,
|
|
14434
14387
|
placeholder,
|
|
14435
|
-
rows,
|
|
14388
|
+
rows: rows2,
|
|
14436
14389
|
disabled,
|
|
14437
14390
|
error: fieldError,
|
|
14438
14391
|
onChange: handleChange,
|
|
@@ -14917,6 +14870,91 @@ var init_ActionPalette = __esm({
|
|
|
14917
14870
|
ActionPalette.displayName = "ActionPalette";
|
|
14918
14871
|
}
|
|
14919
14872
|
});
|
|
14873
|
+
function parseValue(value) {
|
|
14874
|
+
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
14875
|
+
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
14876
|
+
if (!match) {
|
|
14877
|
+
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
14878
|
+
}
|
|
14879
|
+
const numStr = match[2];
|
|
14880
|
+
const decimalIdx = numStr.indexOf(".");
|
|
14881
|
+
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
14882
|
+
return {
|
|
14883
|
+
prefix: match[1],
|
|
14884
|
+
num: parseFloat(numStr),
|
|
14885
|
+
suffix: match[3],
|
|
14886
|
+
decimals
|
|
14887
|
+
};
|
|
14888
|
+
}
|
|
14889
|
+
var AnimatedCounter;
|
|
14890
|
+
var init_AnimatedCounter = __esm({
|
|
14891
|
+
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
14892
|
+
"use client";
|
|
14893
|
+
init_cn();
|
|
14894
|
+
init_Box();
|
|
14895
|
+
init_Typography();
|
|
14896
|
+
AnimatedCounter = ({
|
|
14897
|
+
value,
|
|
14898
|
+
label,
|
|
14899
|
+
duration = 1500,
|
|
14900
|
+
className
|
|
14901
|
+
}) => {
|
|
14902
|
+
const ref = React97.useRef(null);
|
|
14903
|
+
const [displayValue, setDisplayValue] = React97.useState("0");
|
|
14904
|
+
const [hasAnimated, setHasAnimated] = React97.useState(false);
|
|
14905
|
+
const animate = React97.useCallback(() => {
|
|
14906
|
+
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
14907
|
+
if (num2 === 0) {
|
|
14908
|
+
setDisplayValue(String(value));
|
|
14909
|
+
return;
|
|
14910
|
+
}
|
|
14911
|
+
const startTime = performance.now();
|
|
14912
|
+
const tick = (now2) => {
|
|
14913
|
+
const elapsed = now2 - startTime;
|
|
14914
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
14915
|
+
const eased = 1 - Math.pow(1 - progress, 3);
|
|
14916
|
+
const current = eased * num2;
|
|
14917
|
+
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
14918
|
+
if (progress < 1) {
|
|
14919
|
+
requestAnimationFrame(tick);
|
|
14920
|
+
} else {
|
|
14921
|
+
setDisplayValue(String(value));
|
|
14922
|
+
}
|
|
14923
|
+
};
|
|
14924
|
+
requestAnimationFrame(tick);
|
|
14925
|
+
}, [value, duration]);
|
|
14926
|
+
React97.useEffect(() => {
|
|
14927
|
+
if (hasAnimated) return;
|
|
14928
|
+
const el = ref.current;
|
|
14929
|
+
if (!el) return;
|
|
14930
|
+
const observer2 = new IntersectionObserver(
|
|
14931
|
+
(entries) => {
|
|
14932
|
+
if (entries[0].isIntersecting) {
|
|
14933
|
+
setHasAnimated(true);
|
|
14934
|
+
animate();
|
|
14935
|
+
observer2.disconnect();
|
|
14936
|
+
}
|
|
14937
|
+
},
|
|
14938
|
+
{ threshold: 0.3 }
|
|
14939
|
+
);
|
|
14940
|
+
observer2.observe(el);
|
|
14941
|
+
return () => observer2.disconnect();
|
|
14942
|
+
}, [hasAnimated, animate]);
|
|
14943
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
14944
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14945
|
+
Typography,
|
|
14946
|
+
{
|
|
14947
|
+
variant: "h2",
|
|
14948
|
+
className: "text-primary font-bold tabular-nums",
|
|
14949
|
+
children: hasAnimated ? displayValue : "0"
|
|
14950
|
+
}
|
|
14951
|
+
),
|
|
14952
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
14953
|
+
] });
|
|
14954
|
+
};
|
|
14955
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
14956
|
+
}
|
|
14957
|
+
});
|
|
14920
14958
|
var AuthLayout;
|
|
14921
14959
|
var init_AuthLayout = __esm({
|
|
14922
14960
|
"components/core/templates/AuthLayout.tsx"() {
|
|
@@ -16302,6 +16340,39 @@ var init_IsometricCanvas2 = __esm({
|
|
|
16302
16340
|
init_IsometricCanvas();
|
|
16303
16341
|
}
|
|
16304
16342
|
});
|
|
16343
|
+
|
|
16344
|
+
// components/game/organisms/boardEntity.ts
|
|
16345
|
+
function boardEntity(entity) {
|
|
16346
|
+
if (!entity) return void 0;
|
|
16347
|
+
return Array.isArray(entity) ? entity[0] : entity;
|
|
16348
|
+
}
|
|
16349
|
+
function str(v) {
|
|
16350
|
+
return v == null ? "" : String(v);
|
|
16351
|
+
}
|
|
16352
|
+
function num(v, fallback = 0) {
|
|
16353
|
+
const n = Number(v);
|
|
16354
|
+
return Number.isFinite(n) ? n : fallback;
|
|
16355
|
+
}
|
|
16356
|
+
function rows(v) {
|
|
16357
|
+
return Array.isArray(v) ? v : [];
|
|
16358
|
+
}
|
|
16359
|
+
function vec2(v) {
|
|
16360
|
+
const o = v ?? {};
|
|
16361
|
+
return { x: num(o.x), y: num(o.y) };
|
|
16362
|
+
}
|
|
16363
|
+
function unitPosition(u) {
|
|
16364
|
+
return vec2(u.position);
|
|
16365
|
+
}
|
|
16366
|
+
function unitTeam(u) {
|
|
16367
|
+
return str(u.team);
|
|
16368
|
+
}
|
|
16369
|
+
function unitHealth(u) {
|
|
16370
|
+
return num(u.health);
|
|
16371
|
+
}
|
|
16372
|
+
var init_boardEntity = __esm({
|
|
16373
|
+
"components/game/organisms/boardEntity.ts"() {
|
|
16374
|
+
}
|
|
16375
|
+
});
|
|
16305
16376
|
function BattleBoard({
|
|
16306
16377
|
entity,
|
|
16307
16378
|
scale = 0.45,
|
|
@@ -16328,43 +16399,49 @@ function BattleBoard({
|
|
|
16328
16399
|
attackEvent,
|
|
16329
16400
|
className
|
|
16330
16401
|
}) {
|
|
16331
|
-
const
|
|
16332
|
-
const
|
|
16333
|
-
const
|
|
16334
|
-
const
|
|
16335
|
-
const
|
|
16336
|
-
const
|
|
16337
|
-
const
|
|
16338
|
-
const
|
|
16339
|
-
const
|
|
16340
|
-
const
|
|
16341
|
-
const
|
|
16402
|
+
const board = boardEntity(entity) ?? {};
|
|
16403
|
+
const tiles = Array.isArray(board.tiles) ? board.tiles : [];
|
|
16404
|
+
const features = Array.isArray(board.features) ? board.features : [];
|
|
16405
|
+
const boardWidth = num(board.boardWidth, 8);
|
|
16406
|
+
const boardHeight = num(board.boardHeight, 6);
|
|
16407
|
+
const assetManifest = board.assetManifest;
|
|
16408
|
+
const backgroundImage = board.backgroundImage;
|
|
16409
|
+
const units = rows(board.units);
|
|
16410
|
+
const selectedUnitId = board.selectedUnitId ?? null;
|
|
16411
|
+
const currentPhase = str(board.phase) || "observation";
|
|
16412
|
+
const currentTurn = num(board.turn, 1);
|
|
16413
|
+
const gameResult = board.gameResult ?? null;
|
|
16342
16414
|
const eventBus = useEventBus();
|
|
16343
16415
|
const { t } = hooks.useTranslate();
|
|
16344
16416
|
const [hoveredTile, setHoveredTile] = React97.useState(null);
|
|
16345
16417
|
const [isShaking, setIsShaking] = React97.useState(false);
|
|
16346
16418
|
const selectedUnit = React97.useMemo(
|
|
16347
|
-
() => units.find((u) => u.id === selectedUnitId) ?? null,
|
|
16419
|
+
() => units.find((u) => str(u.id) === selectedUnitId) ?? null,
|
|
16348
16420
|
[units, selectedUnitId]
|
|
16349
16421
|
);
|
|
16350
16422
|
const hoveredUnit = React97.useMemo(() => {
|
|
16351
16423
|
if (!hoveredTile) return null;
|
|
16352
|
-
return units.find(
|
|
16353
|
-
|
|
16354
|
-
|
|
16424
|
+
return units.find((u) => {
|
|
16425
|
+
const p2 = unitPosition(u);
|
|
16426
|
+
return p2.x === hoveredTile.x && p2.y === hoveredTile.y && unitHealth(u) > 0;
|
|
16427
|
+
}) ?? null;
|
|
16355
16428
|
}, [hoveredTile, units]);
|
|
16356
|
-
const playerUnits = React97.useMemo(() => units.filter((u) => u
|
|
16357
|
-
const enemyUnits = React97.useMemo(() => units.filter((u) => u
|
|
16429
|
+
const playerUnits = React97.useMemo(() => units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0), [units]);
|
|
16430
|
+
const enemyUnits = React97.useMemo(() => units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0), [units]);
|
|
16358
16431
|
const validMoves = React97.useMemo(() => {
|
|
16359
16432
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
16360
16433
|
const moves = [];
|
|
16361
|
-
const range = selectedUnit.movement;
|
|
16434
|
+
const range = num(selectedUnit.movement);
|
|
16435
|
+
const origin = unitPosition(selectedUnit);
|
|
16362
16436
|
for (let dy = -range; dy <= range; dy++) {
|
|
16363
16437
|
for (let dx = -range; dx <= range; dx++) {
|
|
16364
|
-
const nx =
|
|
16365
|
-
const ny =
|
|
16438
|
+
const nx = origin.x + dx;
|
|
16439
|
+
const ny = origin.y + dy;
|
|
16366
16440
|
const dist = Math.abs(dx) + Math.abs(dy);
|
|
16367
|
-
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) =>
|
|
16441
|
+
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) => {
|
|
16442
|
+
const p2 = unitPosition(u);
|
|
16443
|
+
return p2.x === nx && p2.y === ny && unitHealth(u) > 0;
|
|
16444
|
+
})) {
|
|
16368
16445
|
moves.push({ x: nx, y: ny });
|
|
16369
16446
|
}
|
|
16370
16447
|
}
|
|
@@ -16373,11 +16450,14 @@ function BattleBoard({
|
|
|
16373
16450
|
}, [selectedUnit, currentPhase, units, boardWidth, boardHeight]);
|
|
16374
16451
|
const attackTargets = React97.useMemo(() => {
|
|
16375
16452
|
if (!selectedUnit || currentPhase !== "action") return [];
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16453
|
+
const sp = unitPosition(selectedUnit);
|
|
16454
|
+
const sTeam = unitTeam(selectedUnit);
|
|
16455
|
+
return units.filter((u) => unitTeam(u) !== sTeam && unitHealth(u) > 0).filter((u) => {
|
|
16456
|
+
const p2 = unitPosition(u);
|
|
16457
|
+
const dx = Math.abs(p2.x - sp.x);
|
|
16458
|
+
const dy = Math.abs(p2.y - sp.y);
|
|
16379
16459
|
return dx <= 1 && dy <= 1 && dx + dy > 0;
|
|
16380
|
-
}).map((u) => u
|
|
16460
|
+
}).map((u) => unitPosition(u));
|
|
16381
16461
|
}, [selectedUnit, currentPhase, units]);
|
|
16382
16462
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
16383
16463
|
const movementAnimRef = React97.useRef(null);
|
|
@@ -16417,23 +16497,25 @@ function BattleBoard({
|
|
|
16417
16497
|
return () => clearInterval(interval);
|
|
16418
16498
|
}, []);
|
|
16419
16499
|
const isoUnits = React97.useMemo(() => {
|
|
16420
|
-
return units.filter((u) => u
|
|
16421
|
-
const
|
|
16500
|
+
return units.filter((u) => unitHealth(u) > 0).map((unit) => {
|
|
16501
|
+
const id = str(unit.id);
|
|
16502
|
+
const pos = movingPositions.get(id) ?? unitPosition(unit);
|
|
16503
|
+
const unitTraits = Array.isArray(unit.traits) ? unit.traits : void 0;
|
|
16422
16504
|
return {
|
|
16423
|
-
id
|
|
16505
|
+
id,
|
|
16424
16506
|
position: pos,
|
|
16425
|
-
name: unit.name,
|
|
16426
|
-
team: unit
|
|
16427
|
-
health: unit
|
|
16428
|
-
maxHealth: unit.maxHealth,
|
|
16429
|
-
unitType: unit.unitType,
|
|
16430
|
-
heroId: unit.heroId,
|
|
16431
|
-
sprite: unit.sprite,
|
|
16432
|
-
traits:
|
|
16433
|
-
name:
|
|
16434
|
-
currentState:
|
|
16435
|
-
states:
|
|
16436
|
-
cooldown:
|
|
16507
|
+
name: str(unit.name),
|
|
16508
|
+
team: unitTeam(unit),
|
|
16509
|
+
health: unitHealth(unit),
|
|
16510
|
+
maxHealth: num(unit.maxHealth),
|
|
16511
|
+
unitType: unit.unitType == null ? void 0 : str(unit.unitType),
|
|
16512
|
+
heroId: unit.heroId == null ? void 0 : str(unit.heroId),
|
|
16513
|
+
sprite: unit.sprite == null ? void 0 : str(unit.sprite),
|
|
16514
|
+
traits: unitTraits?.map((tr) => ({
|
|
16515
|
+
name: tr.name,
|
|
16516
|
+
currentState: tr.currentState,
|
|
16517
|
+
states: tr.states,
|
|
16518
|
+
cooldown: tr.cooldown ?? 0
|
|
16437
16519
|
}))
|
|
16438
16520
|
};
|
|
16439
16521
|
});
|
|
@@ -16445,8 +16527,8 @@ function BattleBoard({
|
|
|
16445
16527
|
[scale, baseOffsetX]
|
|
16446
16528
|
);
|
|
16447
16529
|
const checkGameEnd = React97.useCallback(() => {
|
|
16448
|
-
const pa = units.filter((u) => u
|
|
16449
|
-
const ea = units.filter((u) => u
|
|
16530
|
+
const pa = units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
16531
|
+
const ea = units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
16450
16532
|
if (pa.length === 0) {
|
|
16451
16533
|
onGameEnd?.("defeat");
|
|
16452
16534
|
if (gameEndEvent) {
|
|
@@ -16460,21 +16542,22 @@ function BattleBoard({
|
|
|
16460
16542
|
}
|
|
16461
16543
|
}, [units, onGameEnd, gameEndEvent, eventBus]);
|
|
16462
16544
|
const handleUnitClick = React97.useCallback((unitId) => {
|
|
16463
|
-
const unit = units.find((u) => u.id === unitId);
|
|
16545
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
16464
16546
|
if (!unit) return;
|
|
16465
16547
|
if (unitClickEvent) {
|
|
16466
16548
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
16467
16549
|
}
|
|
16468
16550
|
if (currentPhase === "action" && selectedUnit) {
|
|
16469
|
-
|
|
16470
|
-
|
|
16551
|
+
const up = unitPosition(unit);
|
|
16552
|
+
if (unitTeam(unit) === "enemy" && attackTargets.some((t2) => t2.x === up.x && t2.y === up.y)) {
|
|
16553
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
16471
16554
|
setIsShaking(true);
|
|
16472
16555
|
setTimeout(() => setIsShaking(false), 300);
|
|
16473
16556
|
onAttack?.(selectedUnit, unit, damage);
|
|
16474
16557
|
if (attackEvent) {
|
|
16475
16558
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
16476
|
-
attackerId: selectedUnit.id,
|
|
16477
|
-
targetId: unit.id,
|
|
16559
|
+
attackerId: str(selectedUnit.id),
|
|
16560
|
+
targetId: str(unit.id),
|
|
16478
16561
|
damage
|
|
16479
16562
|
});
|
|
16480
16563
|
}
|
|
@@ -16489,9 +16572,9 @@ function BattleBoard({
|
|
|
16489
16572
|
if (currentPhase === "movement" && selectedUnit) {
|
|
16490
16573
|
if (movementAnimRef.current) return;
|
|
16491
16574
|
if (validMoves.some((m) => m.x === x && m.y === y)) {
|
|
16492
|
-
const from = { ...selectedUnit
|
|
16575
|
+
const from = { ...unitPosition(selectedUnit) };
|
|
16493
16576
|
const to = { x, y };
|
|
16494
|
-
startMoveAnimation(selectedUnit.id, from, to, () => {
|
|
16577
|
+
startMoveAnimation(str(selectedUnit.id), from, to, () => {
|
|
16495
16578
|
onUnitMove?.(selectedUnit, to);
|
|
16496
16579
|
});
|
|
16497
16580
|
}
|
|
@@ -16649,6 +16732,7 @@ var init_BattleBoard = __esm({
|
|
|
16649
16732
|
init_Typography();
|
|
16650
16733
|
init_Stack();
|
|
16651
16734
|
init_IsometricCanvas2();
|
|
16735
|
+
init_boardEntity();
|
|
16652
16736
|
init_isometric();
|
|
16653
16737
|
BattleBoard.displayName = "BattleBoard";
|
|
16654
16738
|
}
|
|
@@ -17042,24 +17126,24 @@ var init_CodeBlock = __esm({
|
|
|
17042
17126
|
return;
|
|
17043
17127
|
}
|
|
17044
17128
|
lineEls.forEach((el) => {
|
|
17045
|
-
const
|
|
17046
|
-
if (hiddenLines.has(
|
|
17129
|
+
const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
|
|
17130
|
+
if (hiddenLines.has(num2)) {
|
|
17047
17131
|
el.style.display = "none";
|
|
17048
17132
|
return;
|
|
17049
17133
|
}
|
|
17050
17134
|
el.style.display = "";
|
|
17051
17135
|
el.style.position = "relative";
|
|
17052
17136
|
el.style.paddingLeft = "1.2em";
|
|
17053
|
-
const region = foldStartMap.get(
|
|
17137
|
+
const region = foldStartMap.get(num2);
|
|
17054
17138
|
if (!region) return;
|
|
17055
|
-
const isCollapsed = collapsed.has(
|
|
17139
|
+
const isCollapsed = collapsed.has(num2);
|
|
17056
17140
|
const toggle = document.createElement("span");
|
|
17057
17141
|
toggle.className = "fold-toggle";
|
|
17058
17142
|
toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
|
|
17059
17143
|
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%";
|
|
17060
17144
|
toggle.addEventListener("click", (e) => {
|
|
17061
17145
|
e.stopPropagation();
|
|
17062
|
-
toggleFoldRef.current(
|
|
17146
|
+
toggleFoldRef.current(num2);
|
|
17063
17147
|
});
|
|
17064
17148
|
el.insertBefore(toggle, el.firstChild);
|
|
17065
17149
|
if (isCollapsed) {
|
|
@@ -19312,10 +19396,13 @@ var init_BookChapterView = __esm({
|
|
|
19312
19396
|
init_cn();
|
|
19313
19397
|
BookChapterView = ({
|
|
19314
19398
|
chapter,
|
|
19399
|
+
orbitalSchema,
|
|
19315
19400
|
direction,
|
|
19316
19401
|
className
|
|
19317
19402
|
}) => {
|
|
19318
19403
|
const { t: _t } = hooks.useTranslate();
|
|
19404
|
+
const title = String(chapter.title ?? "");
|
|
19405
|
+
const content = String(chapter.content ?? "");
|
|
19319
19406
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19320
19407
|
VStack,
|
|
19321
19408
|
{
|
|
@@ -19323,16 +19410,16 @@ var init_BookChapterView = __esm({
|
|
|
19323
19410
|
className: cn("px-6 py-8 max-w-4xl mx-auto w-full", className),
|
|
19324
19411
|
style: { direction },
|
|
19325
19412
|
children: [
|
|
19326
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children:
|
|
19413
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children: title }),
|
|
19327
19414
|
/* @__PURE__ */ jsxRuntime.jsx(Divider, {}),
|
|
19328
|
-
!!
|
|
19415
|
+
!!orbitalSchema && /* @__PURE__ */ jsxRuntime.jsx(ScaledDiagram, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
19329
19416
|
JazariStateMachine,
|
|
19330
19417
|
{
|
|
19331
|
-
schema:
|
|
19418
|
+
schema: orbitalSchema,
|
|
19332
19419
|
direction
|
|
19333
19420
|
}
|
|
19334
19421
|
) }),
|
|
19335
|
-
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content
|
|
19422
|
+
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content, direction })
|
|
19336
19423
|
]
|
|
19337
19424
|
}
|
|
19338
19425
|
);
|
|
@@ -19430,7 +19517,7 @@ var init_BookNavBar = __esm({
|
|
|
19430
19517
|
BookNavBar = ({
|
|
19431
19518
|
currentPage,
|
|
19432
19519
|
totalPages,
|
|
19433
|
-
chapterTitle,
|
|
19520
|
+
chapterTitle: chapterTitle2,
|
|
19434
19521
|
direction,
|
|
19435
19522
|
className
|
|
19436
19523
|
}) => {
|
|
@@ -19471,12 +19558,12 @@ var init_BookNavBar = __esm({
|
|
|
19471
19558
|
)
|
|
19472
19559
|
] }),
|
|
19473
19560
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex-1 mx-4 max-w-md", children: [
|
|
19474
|
-
|
|
19561
|
+
chapterTitle2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19475
19562
|
Typography,
|
|
19476
19563
|
{
|
|
19477
19564
|
variant: "caption",
|
|
19478
19565
|
className: "text-center block truncate text-muted-foreground",
|
|
19479
|
-
children:
|
|
19566
|
+
children: chapterTitle2
|
|
19480
19567
|
}
|
|
19481
19568
|
),
|
|
19482
19569
|
/* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { value: progress, size: "sm", variant: "primary" })
|
|
@@ -19543,31 +19630,35 @@ var init_BookTableOfContents = __esm({
|
|
|
19543
19630
|
style: { direction },
|
|
19544
19631
|
children: [
|
|
19545
19632
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold text-center mb-4", children: t("book.tableOfContents") }),
|
|
19546
|
-
parts.map((part, partIdx) =>
|
|
19547
|
-
|
|
19548
|
-
|
|
19549
|
-
/* @__PURE__ */ jsxRuntime.
|
|
19550
|
-
|
|
19551
|
-
|
|
19552
|
-
|
|
19553
|
-
|
|
19554
|
-
|
|
19555
|
-
|
|
19556
|
-
|
|
19557
|
-
|
|
19558
|
-
|
|
19559
|
-
|
|
19560
|
-
|
|
19561
|
-
|
|
19562
|
-
|
|
19563
|
-
|
|
19564
|
-
|
|
19565
|
-
|
|
19566
|
-
|
|
19567
|
-
|
|
19568
|
-
|
|
19569
|
-
|
|
19570
|
-
|
|
19633
|
+
parts.map((part, partIdx) => {
|
|
19634
|
+
const chapters = Array.isArray(part.chapters) ? part.chapters : [];
|
|
19635
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
19636
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", children: [
|
|
19637
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: t("book.partNumber", { number: String(partIdx + 1) }) }),
|
|
19638
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "font-semibold", children: String(part.title ?? "") })
|
|
19639
|
+
] }),
|
|
19640
|
+
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "xs", className: direction === "rtl" ? "pr-6" : "pl-6", children: chapters.map((chapter) => {
|
|
19641
|
+
const id = chapter.id == null ? "" : String(chapter.id);
|
|
19642
|
+
const isCurrent = id === currentChapterId;
|
|
19643
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19644
|
+
Button,
|
|
19645
|
+
{
|
|
19646
|
+
variant: "ghost",
|
|
19647
|
+
size: "sm",
|
|
19648
|
+
action: "BOOK_NAVIGATE",
|
|
19649
|
+
actionPayload: { chapterId: id },
|
|
19650
|
+
className: cn(
|
|
19651
|
+
"justify-start text-left w-full",
|
|
19652
|
+
direction === "rtl" && "text-right",
|
|
19653
|
+
isCurrent && "bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400"
|
|
19654
|
+
),
|
|
19655
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "truncate", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: String(chapter.title ?? "") }) })
|
|
19656
|
+
},
|
|
19657
|
+
id
|
|
19658
|
+
);
|
|
19659
|
+
}) })
|
|
19660
|
+
] }, partIdx);
|
|
19661
|
+
})
|
|
19571
19662
|
]
|
|
19572
19663
|
}
|
|
19573
19664
|
);
|
|
@@ -19689,27 +19780,41 @@ function resolveFieldMap(fieldMap) {
|
|
|
19689
19780
|
function get(obj, key) {
|
|
19690
19781
|
return obj[key];
|
|
19691
19782
|
}
|
|
19783
|
+
function asStr(v) {
|
|
19784
|
+
return v == null ? "" : String(v);
|
|
19785
|
+
}
|
|
19692
19786
|
function mapBookData(raw, fields = IDENTITY_BOOK_FIELDS) {
|
|
19693
19787
|
const rawParts = get(raw, fields.parts) ?? [];
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
19697
|
-
|
|
19698
|
-
|
|
19699
|
-
|
|
19700
|
-
|
|
19701
|
-
const rawChapters = get(part, fields.chapters) ?? [];
|
|
19702
|
-
return {
|
|
19703
|
-
title: get(part, fields.partTitle) ?? "",
|
|
19704
|
-
chapters: rawChapters.map((ch) => ({
|
|
19705
|
-
id: get(ch, fields.chapterId) ?? "",
|
|
19706
|
-
title: get(ch, fields.chapterTitle) ?? "",
|
|
19707
|
-
content: get(ch, fields.chapterContent) ?? "",
|
|
19708
|
-
orbitalSchema: get(ch, fields.chapterOrbitalSchema)
|
|
19709
|
-
}))
|
|
19710
|
-
};
|
|
19711
|
-
})
|
|
19788
|
+
const direction = get(raw, fields.direction) ?? "ltr";
|
|
19789
|
+
const cover = {
|
|
19790
|
+
title: asStr(get(raw, fields.title)),
|
|
19791
|
+
subtitle: asStr(get(raw, fields.subtitle)),
|
|
19792
|
+
author: asStr(get(raw, fields.author)),
|
|
19793
|
+
coverImageUrl: asStr(get(raw, fields.coverImageUrl)),
|
|
19794
|
+
direction
|
|
19712
19795
|
};
|
|
19796
|
+
const schemaByChapterId = {};
|
|
19797
|
+
const chapters = [];
|
|
19798
|
+
const parts = rawParts.map((part) => {
|
|
19799
|
+
const rawChapters = get(part, fields.chapters) ?? [];
|
|
19800
|
+
const chapterRows = rawChapters.map((ch) => {
|
|
19801
|
+
const id = asStr(get(ch, fields.chapterId));
|
|
19802
|
+
const schema = get(ch, fields.chapterOrbitalSchema);
|
|
19803
|
+
if (schema) schemaByChapterId[id] = schema;
|
|
19804
|
+
const row = {
|
|
19805
|
+
id,
|
|
19806
|
+
title: asStr(get(ch, fields.chapterTitle)),
|
|
19807
|
+
content: asStr(get(ch, fields.chapterContent))
|
|
19808
|
+
};
|
|
19809
|
+
chapters.push(row);
|
|
19810
|
+
return row;
|
|
19811
|
+
});
|
|
19812
|
+
return {
|
|
19813
|
+
title: asStr(get(part, fields.partTitle)),
|
|
19814
|
+
chapters: chapterRows
|
|
19815
|
+
};
|
|
19816
|
+
});
|
|
19817
|
+
return { cover, direction, parts, chapters, schemaByChapterId };
|
|
19713
19818
|
}
|
|
19714
19819
|
var IDENTITY_BOOK_FIELDS, AR_BOOK_FIELDS, FIELD_MAP_REGISTRY;
|
|
19715
19820
|
var init_types2 = __esm({
|
|
@@ -19747,10 +19852,7 @@ var init_types2 = __esm({
|
|
|
19747
19852
|
};
|
|
19748
19853
|
}
|
|
19749
19854
|
});
|
|
19750
|
-
|
|
19751
|
-
return book.parts.flatMap((part) => part.chapters);
|
|
19752
|
-
}
|
|
19753
|
-
var PRINT_STYLES, BookViewer;
|
|
19855
|
+
var chapterId, chapterTitle, PRINT_STYLES, BookViewer;
|
|
19754
19856
|
var init_BookViewer = __esm({
|
|
19755
19857
|
"components/marketing/organisms/book/BookViewer.tsx"() {
|
|
19756
19858
|
init_Box();
|
|
@@ -19763,6 +19865,8 @@ var init_BookViewer = __esm({
|
|
|
19763
19865
|
init_BookNavBar();
|
|
19764
19866
|
init_EmptyState();
|
|
19765
19867
|
init_types2();
|
|
19868
|
+
chapterId = (ch) => ch?.id == null ? void 0 : String(ch.id);
|
|
19869
|
+
chapterTitle = (ch) => ch?.title == null ? void 0 : String(ch.title);
|
|
19766
19870
|
PRINT_STYLES = `
|
|
19767
19871
|
@media print {
|
|
19768
19872
|
.book-viewer-page {
|
|
@@ -19791,14 +19895,14 @@ var init_BookViewer = __esm({
|
|
|
19791
19895
|
return mapBookData(raw, resolvedFieldMap);
|
|
19792
19896
|
}, [entity, resolvedFieldMap]);
|
|
19793
19897
|
const direction = book?.direction ?? "ltr";
|
|
19794
|
-
const chapters = React97.useMemo(() => book ?
|
|
19898
|
+
const chapters = React97.useMemo(() => book ? book.chapters : [], [book]);
|
|
19795
19899
|
const totalPages = 2 + chapters.length;
|
|
19796
19900
|
const navigateTo = React97.useCallback(
|
|
19797
19901
|
(page) => {
|
|
19798
19902
|
const clamped = Math.max(0, Math.min(page, totalPages - 1));
|
|
19799
19903
|
setCurrentPage(clamped);
|
|
19800
|
-
const
|
|
19801
|
-
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId });
|
|
19904
|
+
const id = clamped >= 2 ? chapterId(chapters[clamped - 2]) : void 0;
|
|
19905
|
+
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId: id });
|
|
19802
19906
|
},
|
|
19803
19907
|
[totalPages, chapters, eventBus]
|
|
19804
19908
|
);
|
|
@@ -19810,8 +19914,8 @@ var init_BookViewer = __esm({
|
|
|
19810
19914
|
eventBus.on("UI:BOOK_PAGE_NEXT", () => navigateTo(currentPage + 1)),
|
|
19811
19915
|
eventBus.on("UI:BOOK_PRINT", () => window.print()),
|
|
19812
19916
|
eventBus.on("UI:BOOK_NAVIGATE", (event) => {
|
|
19813
|
-
const
|
|
19814
|
-
const idx = chapters.findIndex((ch) => ch
|
|
19917
|
+
const targetId = event.payload?.chapterId;
|
|
19918
|
+
const idx = chapters.findIndex((ch) => chapterId(ch) === targetId);
|
|
19815
19919
|
if (idx >= 0) navigateTo(idx + 2);
|
|
19816
19920
|
})
|
|
19817
19921
|
];
|
|
@@ -19828,9 +19932,11 @@ var init_BookViewer = __esm({
|
|
|
19828
19932
|
style.remove();
|
|
19829
19933
|
};
|
|
19830
19934
|
}, []);
|
|
19831
|
-
const currentChapterId = currentPage >= 2 ? chapters[currentPage - 2]
|
|
19832
|
-
const currentChapterTitle = currentPage >= 2 ? chapters[currentPage - 2]
|
|
19935
|
+
const currentChapterId = currentPage >= 2 ? chapterId(chapters[currentPage - 2]) : void 0;
|
|
19936
|
+
const currentChapterTitle = currentPage >= 2 ? chapterTitle(chapters[currentPage - 2]) : void 0;
|
|
19833
19937
|
if (!book) return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { message: t("book.noData") });
|
|
19938
|
+
const cover = book.cover;
|
|
19939
|
+
const coverTitle = String(cover.title ?? "");
|
|
19834
19940
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("relative h-full overflow-hidden bg-background", className), children: [
|
|
19835
19941
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
19836
19942
|
Box,
|
|
@@ -19842,10 +19948,10 @@ var init_BookViewer = __esm({
|
|
|
19842
19948
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19843
19949
|
BookCoverPage,
|
|
19844
19950
|
{
|
|
19845
|
-
title:
|
|
19846
|
-
subtitle:
|
|
19847
|
-
author:
|
|
19848
|
-
coverImageUrl:
|
|
19951
|
+
title: coverTitle,
|
|
19952
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
19953
|
+
author: String(cover.author ?? "") || void 0,
|
|
19954
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
19849
19955
|
direction
|
|
19850
19956
|
}
|
|
19851
19957
|
),
|
|
@@ -19856,23 +19962,27 @@ var init_BookViewer = __esm({
|
|
|
19856
19962
|
direction
|
|
19857
19963
|
}
|
|
19858
19964
|
),
|
|
19859
|
-
chapters.map((chapter) =>
|
|
19860
|
-
|
|
19861
|
-
|
|
19862
|
-
|
|
19863
|
-
|
|
19864
|
-
|
|
19865
|
-
|
|
19866
|
-
|
|
19965
|
+
chapters.map((chapter) => {
|
|
19966
|
+
const id = chapterId(chapter);
|
|
19967
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19968
|
+
BookChapterView,
|
|
19969
|
+
{
|
|
19970
|
+
chapter,
|
|
19971
|
+
orbitalSchema: id ? book.schemaByChapterId[id] : void 0,
|
|
19972
|
+
direction
|
|
19973
|
+
},
|
|
19974
|
+
id
|
|
19975
|
+
);
|
|
19976
|
+
})
|
|
19867
19977
|
] }),
|
|
19868
19978
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "print:hidden", children: [
|
|
19869
19979
|
currentPage === 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19870
19980
|
BookCoverPage,
|
|
19871
19981
|
{
|
|
19872
|
-
title:
|
|
19873
|
-
subtitle:
|
|
19874
|
-
author:
|
|
19875
|
-
coverImageUrl:
|
|
19982
|
+
title: coverTitle,
|
|
19983
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
19984
|
+
author: String(cover.author ?? "") || void 0,
|
|
19985
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
19876
19986
|
direction
|
|
19877
19987
|
}
|
|
19878
19988
|
),
|
|
@@ -19888,6 +19998,7 @@ var init_BookViewer = __esm({
|
|
|
19888
19998
|
BookChapterView,
|
|
19889
19999
|
{
|
|
19890
20000
|
chapter: chapters[currentPage - 2],
|
|
20001
|
+
orbitalSchema: currentChapterId ? book.schemaByChapterId[currentChapterId] : void 0,
|
|
19891
20002
|
direction
|
|
19892
20003
|
}
|
|
19893
20004
|
)
|
|
@@ -19900,7 +20011,7 @@ var init_BookViewer = __esm({
|
|
|
19900
20011
|
{
|
|
19901
20012
|
currentPage,
|
|
19902
20013
|
totalPages,
|
|
19903
|
-
chapterTitle: currentPage === 0 ?
|
|
20014
|
+
chapterTitle: currentPage === 0 ? coverTitle : currentPage === 1 ? t("book.tableOfContents") : currentChapterTitle,
|
|
19904
20015
|
direction
|
|
19905
20016
|
}
|
|
19906
20017
|
)
|
|
@@ -19998,7 +20109,7 @@ var init_Grid = __esm({
|
|
|
19998
20109
|
};
|
|
19999
20110
|
Grid = ({
|
|
20000
20111
|
cols = 1,
|
|
20001
|
-
rows,
|
|
20112
|
+
rows: rows2,
|
|
20002
20113
|
gap = "md",
|
|
20003
20114
|
rowGap,
|
|
20004
20115
|
colGap,
|
|
@@ -20010,7 +20121,7 @@ var init_Grid = __esm({
|
|
|
20010
20121
|
children,
|
|
20011
20122
|
as: Component = "div"
|
|
20012
20123
|
}) => {
|
|
20013
|
-
const mergedStyle =
|
|
20124
|
+
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
20014
20125
|
return React97__namespace.default.createElement(
|
|
20015
20126
|
Component,
|
|
20016
20127
|
{
|
|
@@ -20726,14 +20837,14 @@ function BuilderBoard({
|
|
|
20726
20837
|
}) {
|
|
20727
20838
|
const { emit } = useEventBus();
|
|
20728
20839
|
const { t } = hooks.useTranslate();
|
|
20729
|
-
const resolved =
|
|
20840
|
+
const resolved = boardEntity(entity);
|
|
20730
20841
|
const [placements, setPlacements] = React97.useState({});
|
|
20731
20842
|
const [headerError, setHeaderError] = React97.useState(false);
|
|
20732
20843
|
const [submitted, setSubmitted] = React97.useState(false);
|
|
20733
20844
|
const [attempts, setAttempts] = React97.useState(0);
|
|
20734
20845
|
const [showHint, setShowHint] = React97.useState(false);
|
|
20735
|
-
const components = resolved?.components
|
|
20736
|
-
const slots = resolved?.slots
|
|
20846
|
+
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
20847
|
+
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
20737
20848
|
const usedComponentIds = new Set(Object.values(placements));
|
|
20738
20849
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
20739
20850
|
const [selectedComponent, setSelectedComponent] = React97.useState(null);
|
|
@@ -20767,7 +20878,7 @@ function BuilderBoard({
|
|
|
20767
20878
|
}, [slots, placements, attempts, completeEvent, emit]);
|
|
20768
20879
|
const handleReset = () => {
|
|
20769
20880
|
setSubmitted(false);
|
|
20770
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
20881
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
20771
20882
|
setShowHint(true);
|
|
20772
20883
|
}
|
|
20773
20884
|
};
|
|
@@ -20780,20 +20891,24 @@ function BuilderBoard({
|
|
|
20780
20891
|
};
|
|
20781
20892
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
20782
20893
|
if (!resolved) return null;
|
|
20894
|
+
const theme = resolved.theme ?? void 0;
|
|
20895
|
+
const themeBackground = theme?.background;
|
|
20896
|
+
const headerImage = str(resolved.headerImage);
|
|
20897
|
+
const hint = str(resolved.hint);
|
|
20783
20898
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20784
20899
|
Box,
|
|
20785
20900
|
{
|
|
20786
20901
|
className,
|
|
20787
20902
|
style: {
|
|
20788
|
-
backgroundImage:
|
|
20903
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
20789
20904
|
backgroundSize: "cover",
|
|
20790
20905
|
backgroundPosition: "center"
|
|
20791
20906
|
},
|
|
20792
20907
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
20793
|
-
|
|
20908
|
+
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,
|
|
20794
20909
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
20795
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
20796
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
20910
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
20911
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
20797
20912
|
] }) }),
|
|
20798
20913
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
20799
20914
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.components") }),
|
|
@@ -20853,9 +20968,9 @@ function BuilderBoard({
|
|
|
20853
20968
|
] }) }),
|
|
20854
20969
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
20855
20970
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
20856
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
20971
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
|
|
20857
20972
|
] }) }),
|
|
20858
|
-
showHint &&
|
|
20973
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
20859
20974
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
20860
20975
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
20861
20976
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
@@ -20874,6 +20989,7 @@ var init_BuilderBoard = __esm({
|
|
|
20874
20989
|
"components/game/organisms/puzzles/builder/BuilderBoard.tsx"() {
|
|
20875
20990
|
init_atoms2();
|
|
20876
20991
|
init_useEventBus();
|
|
20992
|
+
init_boardEntity();
|
|
20877
20993
|
BuilderBoard.displayName = "BuilderBoard";
|
|
20878
20994
|
}
|
|
20879
20995
|
});
|
|
@@ -21211,21 +21327,24 @@ function CalendarGrid({
|
|
|
21211
21327
|
eventBus.emit(`UI:${longPressEvent}`, { date: day.toISOString(), time, ...longPressPayload });
|
|
21212
21328
|
}, 500);
|
|
21213
21329
|
}, [longPressEvent, longPressPayload, eventBus]);
|
|
21214
|
-
const renderEvent = (event) =>
|
|
21215
|
-
|
|
21216
|
-
|
|
21217
|
-
|
|
21218
|
-
|
|
21219
|
-
|
|
21220
|
-
|
|
21221
|
-
|
|
21222
|
-
|
|
21223
|
-
|
|
21224
|
-
|
|
21225
|
-
|
|
21226
|
-
|
|
21227
|
-
|
|
21228
|
-
|
|
21330
|
+
const renderEvent = (event) => {
|
|
21331
|
+
const color = event.color;
|
|
21332
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21333
|
+
Box,
|
|
21334
|
+
{
|
|
21335
|
+
rounded: "md",
|
|
21336
|
+
padding: "xs",
|
|
21337
|
+
border: true,
|
|
21338
|
+
className: cn(
|
|
21339
|
+
"cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
|
|
21340
|
+
color ? color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
|
|
21341
|
+
),
|
|
21342
|
+
onClick: (e) => handleEventClick(event, e),
|
|
21343
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
|
|
21344
|
+
},
|
|
21345
|
+
event.id
|
|
21346
|
+
);
|
|
21347
|
+
};
|
|
21229
21348
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
21230
21349
|
Box,
|
|
21231
21350
|
{
|
|
@@ -22889,7 +23008,6 @@ var init_CardGrid = __esm({
|
|
|
22889
23008
|
alignItems = "stretch",
|
|
22890
23009
|
className,
|
|
22891
23010
|
children,
|
|
22892
|
-
// EntityDisplayProps
|
|
22893
23011
|
entity,
|
|
22894
23012
|
isLoading = false,
|
|
22895
23013
|
error = null,
|
|
@@ -23361,14 +23479,14 @@ var init_CaseStudyOrganism = __esm({
|
|
|
23361
23479
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((study) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
23362
23480
|
CaseStudyCard,
|
|
23363
23481
|
{
|
|
23364
|
-
title: study.title,
|
|
23365
|
-
description: study.description,
|
|
23366
|
-
category: study.category,
|
|
23367
|
-
categoryColor: study.categoryColor,
|
|
23368
|
-
href: study.href,
|
|
23369
|
-
linkLabel: study.linkLabel
|
|
23482
|
+
title: String(study.title ?? ""),
|
|
23483
|
+
description: String(study.description ?? ""),
|
|
23484
|
+
category: String(study.category ?? ""),
|
|
23485
|
+
categoryColor: study.categoryColor != null ? String(study.categoryColor) : void 0,
|
|
23486
|
+
href: String(study.href ?? ""),
|
|
23487
|
+
linkLabel: study.linkLabel != null ? String(study.linkLabel) : void 0
|
|
23370
23488
|
},
|
|
23371
|
-
study.id
|
|
23489
|
+
String(study.id ?? "")
|
|
23372
23490
|
)) })
|
|
23373
23491
|
] });
|
|
23374
23492
|
};
|
|
@@ -23391,10 +23509,10 @@ function CastleBoard({
|
|
|
23391
23509
|
className
|
|
23392
23510
|
}) {
|
|
23393
23511
|
const eventBus = useEventBus();
|
|
23394
|
-
const resolved =
|
|
23395
|
-
const tiles = resolved?.tiles
|
|
23396
|
-
const features = resolved?.features
|
|
23397
|
-
const units = resolved?.units
|
|
23512
|
+
const resolved = boardEntity(entity);
|
|
23513
|
+
const tiles = Array.isArray(resolved?.tiles) ? resolved.tiles : [];
|
|
23514
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
23515
|
+
const units = Array.isArray(resolved?.units) ? resolved.units : [];
|
|
23398
23516
|
const assetManifest = resolved?.assetManifest;
|
|
23399
23517
|
const backgroundImage = resolved?.backgroundImage;
|
|
23400
23518
|
const [hoveredTile, setHoveredTile] = React97.useState(null);
|
|
@@ -23422,7 +23540,7 @@ function CastleBoard({
|
|
|
23422
23540
|
onFeatureClick?.(feature);
|
|
23423
23541
|
if (featureClickEvent) {
|
|
23424
23542
|
eventBus.emit(`UI:${featureClickEvent}`, {
|
|
23425
|
-
featureId: feature.id,
|
|
23543
|
+
featureId: feature.id ?? "",
|
|
23426
23544
|
featureType: feature.type,
|
|
23427
23545
|
x: feature.x,
|
|
23428
23546
|
y: feature.y
|
|
@@ -23490,6 +23608,7 @@ var init_CastleBoard = __esm({
|
|
|
23490
23608
|
init_cn();
|
|
23491
23609
|
init_useEventBus();
|
|
23492
23610
|
init_IsometricCanvas2();
|
|
23611
|
+
init_boardEntity();
|
|
23493
23612
|
init_isometric();
|
|
23494
23613
|
CastleBoard.displayName = "CastleBoard";
|
|
23495
23614
|
}
|
|
@@ -24300,14 +24419,14 @@ function ClassifierBoard({
|
|
|
24300
24419
|
}) {
|
|
24301
24420
|
const { emit } = useEventBus();
|
|
24302
24421
|
const { t } = hooks.useTranslate();
|
|
24303
|
-
const resolved =
|
|
24422
|
+
const resolved = boardEntity(entity);
|
|
24304
24423
|
const [assignments, setAssignments] = React97.useState({});
|
|
24305
24424
|
const [headerError, setHeaderError] = React97.useState(false);
|
|
24306
24425
|
const [submitted, setSubmitted] = React97.useState(false);
|
|
24307
24426
|
const [attempts, setAttempts] = React97.useState(0);
|
|
24308
24427
|
const [showHint, setShowHint] = React97.useState(false);
|
|
24309
|
-
const items = resolved?.items
|
|
24310
|
-
const categories = resolved?.categories
|
|
24428
|
+
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
24429
|
+
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
24311
24430
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
24312
24431
|
const allAssigned = Object.keys(assignments).length === items.length;
|
|
24313
24432
|
const results = submitted ? items.map((item) => ({
|
|
@@ -24339,7 +24458,7 @@ function ClassifierBoard({
|
|
|
24339
24458
|
}, [items, assignments, attempts, completeEvent, emit]);
|
|
24340
24459
|
const handleReset = () => {
|
|
24341
24460
|
setSubmitted(false);
|
|
24342
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
24461
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
24343
24462
|
setShowHint(true);
|
|
24344
24463
|
}
|
|
24345
24464
|
};
|
|
@@ -24350,20 +24469,25 @@ function ClassifierBoard({
|
|
|
24350
24469
|
setShowHint(false);
|
|
24351
24470
|
};
|
|
24352
24471
|
if (!resolved) return null;
|
|
24472
|
+
const theme = resolved.theme ?? void 0;
|
|
24473
|
+
const themeBackground = theme?.background;
|
|
24474
|
+
const headerImage = str(resolved.headerImage);
|
|
24475
|
+
const hint = str(resolved.hint);
|
|
24476
|
+
const failMessage = str(resolved.failMessage);
|
|
24353
24477
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
24354
24478
|
Box,
|
|
24355
24479
|
{
|
|
24356
24480
|
className,
|
|
24357
24481
|
style: {
|
|
24358
|
-
backgroundImage:
|
|
24482
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
24359
24483
|
backgroundSize: "cover",
|
|
24360
24484
|
backgroundPosition: "center"
|
|
24361
24485
|
},
|
|
24362
24486
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
24363
|
-
|
|
24487
|
+
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,
|
|
24364
24488
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
24365
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
24366
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
24489
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
24490
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
24367
24491
|
] }) }),
|
|
24368
24492
|
unassignedItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
24369
24493
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("classifier.itemsToSort") }),
|
|
@@ -24415,10 +24539,10 @@ function ClassifierBoard({
|
|
|
24415
24539
|
}) }),
|
|
24416
24540
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
24417
24541
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
24418
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
24419
|
-
!allCorrect &&
|
|
24542
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("classifier.allCorrect") : `${correctCount}/${items.length} ${t("classifier.correct")}` }),
|
|
24543
|
+
!allCorrect && failMessage && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "text-muted-foreground", children: failMessage })
|
|
24420
24544
|
] }) }),
|
|
24421
|
-
showHint &&
|
|
24545
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
24422
24546
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
24423
24547
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
24424
24548
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -24437,6 +24561,7 @@ var init_ClassifierBoard = __esm({
|
|
|
24437
24561
|
"components/game/organisms/puzzles/classifier/ClassifierBoard.tsx"() {
|
|
24438
24562
|
init_atoms2();
|
|
24439
24563
|
init_useEventBus();
|
|
24564
|
+
init_boardEntity();
|
|
24440
24565
|
ClassifierBoard.displayName = "ClassifierBoard";
|
|
24441
24566
|
}
|
|
24442
24567
|
});
|
|
@@ -30807,7 +30932,7 @@ function InventoryPanel({
|
|
|
30807
30932
|
const slotArray = Array.from({ length: safeSlots }, (_, index) => {
|
|
30808
30933
|
return safeItems[index] ?? null;
|
|
30809
30934
|
});
|
|
30810
|
-
const
|
|
30935
|
+
const rows2 = Math.ceil(safeSlots / safeColumns);
|
|
30811
30936
|
const handleSlotClick = React97.useCallback((index) => {
|
|
30812
30937
|
if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
|
|
30813
30938
|
onSelectSlot?.(index);
|
|
@@ -30876,7 +31001,7 @@ function InventoryPanel({
|
|
|
30876
31001
|
className: "grid gap-1 bg-[var(--color-card)] p-2 rounded-container border border-border",
|
|
30877
31002
|
style: {
|
|
30878
31003
|
gridTemplateColumns: `repeat(${safeColumns}, ${slotSize}px)`,
|
|
30879
|
-
gridTemplateRows: `repeat(${
|
|
31004
|
+
gridTemplateRows: `repeat(${rows2}, ${slotSize}px)`
|
|
30880
31005
|
},
|
|
30881
31006
|
children: slotArray.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
30882
31007
|
"button",
|
|
@@ -34840,11 +34965,11 @@ function LatticeSVG({
|
|
|
34840
34965
|
}) {
|
|
34841
34966
|
const paths = [];
|
|
34842
34967
|
const cols = 5;
|
|
34843
|
-
const
|
|
34968
|
+
const rows2 = Math.ceil(h / (w / cols));
|
|
34844
34969
|
const cellW = w / cols;
|
|
34845
34970
|
const cellH = cellW;
|
|
34846
34971
|
const bulge = cellW * 0.3;
|
|
34847
|
-
for (let row = 0; row <
|
|
34972
|
+
for (let row = 0; row < rows2; row++) {
|
|
34848
34973
|
for (let col = 0; col < cols; col++) {
|
|
34849
34974
|
const cx = col * cellW + cellW / 2;
|
|
34850
34975
|
const cy = row * cellH + cellH / 2;
|
|
@@ -35256,7 +35381,7 @@ var init_MatrixQuestion = __esm({
|
|
|
35256
35381
|
};
|
|
35257
35382
|
MatrixQuestion = ({
|
|
35258
35383
|
title,
|
|
35259
|
-
rows,
|
|
35384
|
+
rows: rows2,
|
|
35260
35385
|
columns = DEFAULT_MATRIX_COLUMNS,
|
|
35261
35386
|
values,
|
|
35262
35387
|
onChange,
|
|
@@ -35266,7 +35391,7 @@ var init_MatrixQuestion = __esm({
|
|
|
35266
35391
|
className
|
|
35267
35392
|
}) => {
|
|
35268
35393
|
const styles = sizeStyles13[size];
|
|
35269
|
-
const safeRows =
|
|
35394
|
+
const safeRows = rows2 ?? [];
|
|
35270
35395
|
const safeValues = values ?? {};
|
|
35271
35396
|
const eventBus = useEventBus();
|
|
35272
35397
|
const handleChange = React97.useCallback(
|
|
@@ -35894,7 +36019,8 @@ var init_PositionedCanvas = __esm({
|
|
|
35894
36019
|
dragRef.current = null;
|
|
35895
36020
|
setDraggingId(null);
|
|
35896
36021
|
if (!wasDrag) {
|
|
35897
|
-
const
|
|
36022
|
+
const itemId = item.id;
|
|
36023
|
+
const next = selectedId === itemId ? null : itemId;
|
|
35898
36024
|
onSelect?.(next);
|
|
35899
36025
|
if (selectEvent) {
|
|
35900
36026
|
eventBus.emit(`UI:${selectEvent}`, { id: next });
|
|
@@ -35929,15 +36055,22 @@ var init_PositionedCanvas = __esm({
|
|
|
35929
36055
|
style: { width, height },
|
|
35930
36056
|
onClick: handleContainerClick,
|
|
35931
36057
|
children: items.map((item) => {
|
|
36058
|
+
const itemId = item.id;
|
|
36059
|
+
const label = item.label;
|
|
36060
|
+
const x = item.x;
|
|
36061
|
+
const y = item.y;
|
|
36062
|
+
const capacity = item.capacity;
|
|
36063
|
+
const partySize = item.partySize;
|
|
36064
|
+
const serverName = item.serverName;
|
|
35932
36065
|
const status = item.status ?? "empty";
|
|
35933
36066
|
const shape = item.shape ?? "round";
|
|
35934
|
-
const isSelected = selectedId ===
|
|
35935
|
-
const isDragging = draggingId ===
|
|
36067
|
+
const isSelected = selectedId === itemId;
|
|
36068
|
+
const isDragging = draggingId === itemId;
|
|
35936
36069
|
const statusBadge = STATUS_BADGE[status];
|
|
35937
36070
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
35938
36071
|
Box,
|
|
35939
36072
|
{
|
|
35940
|
-
"data-testid": `item-node-${
|
|
36073
|
+
"data-testid": `item-node-${itemId}`,
|
|
35941
36074
|
"data-status": status,
|
|
35942
36075
|
className: cn(
|
|
35943
36076
|
"absolute flex flex-col items-center justify-center gap-1 border-2 select-none",
|
|
@@ -35948,7 +36081,7 @@ var init_PositionedCanvas = __esm({
|
|
|
35948
36081
|
isSelected && "outline outline-2 outline-offset-2 outline-primary shadow-md",
|
|
35949
36082
|
isDragging && "shadow-lg z-10"
|
|
35950
36083
|
),
|
|
35951
|
-
style: { left:
|
|
36084
|
+
style: { left: x, top: y, touchAction: "none" },
|
|
35952
36085
|
onPointerDown: (e) => handlePointerDown(e, item),
|
|
35953
36086
|
onPointerMove: handlePointerMove,
|
|
35954
36087
|
onPointerUp: (e) => handlePointerUp(e, item),
|
|
@@ -35956,10 +36089,10 @@ var init_PositionedCanvas = __esm({
|
|
|
35956
36089
|
children: [
|
|
35957
36090
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", children: [
|
|
35958
36091
|
getStatusIcon(status),
|
|
35959
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children:
|
|
36092
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children: label })
|
|
35960
36093
|
] }),
|
|
35961
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
35962
|
-
status === "seated" &&
|
|
36094
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: partySize !== void 0 && status === "seated" ? `${partySize}/${capacity}` : `Cap ${capacity}` }),
|
|
36095
|
+
status === "seated" && serverName && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "truncate max-w-[80%]", children: serverName }),
|
|
35963
36096
|
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
35964
36097
|
Badge,
|
|
35965
36098
|
{
|
|
@@ -35971,7 +36104,7 @@ var init_PositionedCanvas = __esm({
|
|
|
35971
36104
|
)
|
|
35972
36105
|
]
|
|
35973
36106
|
},
|
|
35974
|
-
|
|
36107
|
+
itemId
|
|
35975
36108
|
);
|
|
35976
36109
|
})
|
|
35977
36110
|
}
|
|
@@ -36743,9 +36876,10 @@ var init_RichBlockEditor = __esm({
|
|
|
36743
36876
|
});
|
|
36744
36877
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
36745
36878
|
for (const n of nodes) {
|
|
36879
|
+
const replies = n.replies;
|
|
36746
36880
|
if (n.collapsed) acc.add(n.id);
|
|
36747
|
-
if (
|
|
36748
|
-
collectInitiallyCollapsed(
|
|
36881
|
+
if (replies && replies.length > 0) {
|
|
36882
|
+
collectInitiallyCollapsed(replies, acc);
|
|
36749
36883
|
}
|
|
36750
36884
|
}
|
|
36751
36885
|
}
|
|
@@ -36775,44 +36909,52 @@ var init_ReplyTree = __esm({
|
|
|
36775
36909
|
}) => {
|
|
36776
36910
|
const eventBus = useEventBus();
|
|
36777
36911
|
const { t } = hooks.useTranslate();
|
|
36778
|
-
const
|
|
36779
|
-
const
|
|
36912
|
+
const nodeId = node.id;
|
|
36913
|
+
const authorName = node.authorName;
|
|
36914
|
+
const authorAvatarUrl = node.authorAvatarUrl;
|
|
36915
|
+
const content = node.content;
|
|
36916
|
+
const postedAt = node.postedAt;
|
|
36917
|
+
const voteCount = node.voteCount;
|
|
36918
|
+
const userVote = node.userVote;
|
|
36919
|
+
const replies = node.replies;
|
|
36920
|
+
const hasReplies = !!replies && replies.length > 0;
|
|
36921
|
+
const isCollapsed = collapsedSet.has(nodeId);
|
|
36780
36922
|
const atMaxDepth = depth >= maxDepth;
|
|
36781
36923
|
const [replyOpen, setReplyOpen] = React97.useState(false);
|
|
36782
36924
|
const [draft, setDraft] = React97.useState("");
|
|
36783
36925
|
const handleVote = React97.useCallback(
|
|
36784
36926
|
(next) => {
|
|
36785
|
-
onVote?.(
|
|
36786
|
-
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId
|
|
36927
|
+
onVote?.(nodeId, next);
|
|
36928
|
+
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId, vote: next });
|
|
36787
36929
|
},
|
|
36788
|
-
[
|
|
36930
|
+
[nodeId, onVote, voteEvent, eventBus]
|
|
36789
36931
|
);
|
|
36790
36932
|
const handleReply = React97.useCallback(() => {
|
|
36791
|
-
onReply?.(
|
|
36933
|
+
onReply?.(nodeId);
|
|
36792
36934
|
setReplyOpen((open) => !open);
|
|
36793
|
-
}, [
|
|
36935
|
+
}, [nodeId, onReply]);
|
|
36794
36936
|
const handleSubmitReply = React97.useCallback(() => {
|
|
36795
|
-
const
|
|
36796
|
-
if (!
|
|
36797
|
-
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId:
|
|
36937
|
+
const text = draft.trim();
|
|
36938
|
+
if (!text) return;
|
|
36939
|
+
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: nodeId, content: text });
|
|
36798
36940
|
setDraft("");
|
|
36799
36941
|
setReplyOpen(false);
|
|
36800
|
-
}, [
|
|
36942
|
+
}, [nodeId, draft, replyEvent, eventBus]);
|
|
36801
36943
|
const handleCancelReply = React97.useCallback(() => {
|
|
36802
36944
|
setDraft("");
|
|
36803
36945
|
setReplyOpen(false);
|
|
36804
36946
|
}, []);
|
|
36805
36947
|
const handleFlag = React97.useCallback(() => {
|
|
36806
|
-
onFlag?.(
|
|
36807
|
-
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId
|
|
36808
|
-
}, [
|
|
36948
|
+
onFlag?.(nodeId);
|
|
36949
|
+
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId });
|
|
36950
|
+
}, [nodeId, onFlag, flagEvent, eventBus]);
|
|
36809
36951
|
const handleContinue = React97.useCallback(() => {
|
|
36810
|
-
onContinueThread?.(
|
|
36811
|
-
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId
|
|
36812
|
-
}, [
|
|
36952
|
+
onContinueThread?.(nodeId);
|
|
36953
|
+
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId });
|
|
36954
|
+
}, [nodeId, onContinueThread, continueThreadEvent, eventBus]);
|
|
36813
36955
|
const handleToggle = React97.useCallback(() => {
|
|
36814
|
-
toggleCollapse(
|
|
36815
|
-
}, [
|
|
36956
|
+
toggleCollapse(nodeId);
|
|
36957
|
+
}, [nodeId, toggleCollapse]);
|
|
36816
36958
|
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-stretch min-w-0", children: [
|
|
36817
36959
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col items-center flex-shrink-0 w-6", children: [
|
|
36818
36960
|
hasReplies ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -36844,25 +36986,25 @@ var init_ReplyTree = __esm({
|
|
|
36844
36986
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36845
36987
|
Avatar,
|
|
36846
36988
|
{
|
|
36847
|
-
src:
|
|
36848
|
-
name:
|
|
36989
|
+
src: authorAvatarUrl,
|
|
36990
|
+
name: authorName,
|
|
36849
36991
|
size: "sm"
|
|
36850
36992
|
}
|
|
36851
36993
|
),
|
|
36852
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children:
|
|
36853
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
36994
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children: authorName }),
|
|
36995
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: postedAt })
|
|
36854
36996
|
] }),
|
|
36855
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children:
|
|
36997
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: content }),
|
|
36856
36998
|
showActions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
36857
36999
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36858
37000
|
VoteStack,
|
|
36859
37001
|
{
|
|
36860
|
-
count:
|
|
36861
|
-
userVote:
|
|
37002
|
+
count: voteCount ?? 0,
|
|
37003
|
+
userVote: userVote ?? null,
|
|
36862
37004
|
onVote: handleVote,
|
|
36863
37005
|
size: "sm",
|
|
36864
37006
|
variant: "horizontal",
|
|
36865
|
-
label: t("replyTree.voteOnReplyBy", { author:
|
|
37007
|
+
label: t("replyTree.voteOnReplyBy", { author: authorName })
|
|
36866
37008
|
}
|
|
36867
37009
|
),
|
|
36868
37010
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -36872,7 +37014,7 @@ var init_ReplyTree = __esm({
|
|
|
36872
37014
|
size: "sm",
|
|
36873
37015
|
leftIcon: "message-square",
|
|
36874
37016
|
onClick: handleReply,
|
|
36875
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
37017
|
+
"aria-label": t("replyTree.replyTo", { author: authorName }),
|
|
36876
37018
|
children: t("replyTree.reply")
|
|
36877
37019
|
}
|
|
36878
37020
|
),
|
|
@@ -36883,7 +37025,7 @@ var init_ReplyTree = __esm({
|
|
|
36883
37025
|
size: "sm",
|
|
36884
37026
|
leftIcon: "flag",
|
|
36885
37027
|
onClick: handleFlag,
|
|
36886
|
-
"aria-label": t("replyTree.flagReplyBy", { author:
|
|
37028
|
+
"aria-label": t("replyTree.flagReplyBy", { author: authorName }),
|
|
36887
37029
|
children: t("replyTree.flag")
|
|
36888
37030
|
}
|
|
36889
37031
|
)
|
|
@@ -36895,9 +37037,9 @@ var init_ReplyTree = __esm({
|
|
|
36895
37037
|
inputType: "textarea",
|
|
36896
37038
|
rows: 2,
|
|
36897
37039
|
value: draft,
|
|
36898
|
-
placeholder: t("replyTree.replyToPlaceholder", { author:
|
|
37040
|
+
placeholder: t("replyTree.replyToPlaceholder", { author: authorName }),
|
|
36899
37041
|
onChange: (e) => setDraft(e.target.value),
|
|
36900
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
37042
|
+
"aria-label": t("replyTree.replyTo", { author: authorName })
|
|
36901
37043
|
}
|
|
36902
37044
|
),
|
|
36903
37045
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
@@ -36928,7 +37070,7 @@ var init_ReplyTree = __esm({
|
|
|
36928
37070
|
),
|
|
36929
37071
|
children: t("replyTree.continueThread")
|
|
36930
37072
|
}
|
|
36931
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children:
|
|
37073
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children: replies.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
36932
37074
|
ReplyTreeNode,
|
|
36933
37075
|
{
|
|
36934
37076
|
node: child,
|
|
@@ -38839,8 +38981,8 @@ var init_WizardContainer = __esm({
|
|
|
38839
38981
|
return void 0;
|
|
38840
38982
|
if (typeof controlledStep === "number") return controlledStep;
|
|
38841
38983
|
if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
|
|
38842
|
-
const
|
|
38843
|
-
return isNaN(
|
|
38984
|
+
const num2 = Number(controlledStep);
|
|
38985
|
+
return isNaN(num2) ? void 0 : num2;
|
|
38844
38986
|
})();
|
|
38845
38987
|
const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
|
|
38846
38988
|
const totalSteps = steps.length;
|
|
@@ -40545,7 +40687,7 @@ function DebuggerBoard({
|
|
|
40545
40687
|
}) {
|
|
40546
40688
|
const { emit } = useEventBus();
|
|
40547
40689
|
const { t } = hooks.useTranslate();
|
|
40548
|
-
const resolved =
|
|
40690
|
+
const resolved = boardEntity(entity);
|
|
40549
40691
|
const [flaggedLines, setFlaggedLines] = React97.useState(/* @__PURE__ */ new Set());
|
|
40550
40692
|
const [headerError, setHeaderError] = React97.useState(false);
|
|
40551
40693
|
const [submitted, setSubmitted] = React97.useState(false);
|
|
@@ -40563,7 +40705,7 @@ function DebuggerBoard({
|
|
|
40563
40705
|
return next;
|
|
40564
40706
|
});
|
|
40565
40707
|
};
|
|
40566
|
-
const lines = resolved?.lines
|
|
40708
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
40567
40709
|
const bugLines = lines.filter((l) => l.isBug);
|
|
40568
40710
|
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
40569
40711
|
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
@@ -40578,7 +40720,7 @@ function DebuggerBoard({
|
|
|
40578
40720
|
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
40579
40721
|
const handleReset = () => {
|
|
40580
40722
|
setSubmitted(false);
|
|
40581
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
40723
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
40582
40724
|
setShowHint(true);
|
|
40583
40725
|
}
|
|
40584
40726
|
};
|
|
@@ -40589,24 +40731,28 @@ function DebuggerBoard({
|
|
|
40589
40731
|
setShowHint(false);
|
|
40590
40732
|
};
|
|
40591
40733
|
if (!resolved) return null;
|
|
40734
|
+
const theme = resolved.theme ?? void 0;
|
|
40735
|
+
const themeBackground = theme?.background;
|
|
40736
|
+
const headerImage = str(resolved.headerImage);
|
|
40737
|
+
const hint = str(resolved.hint);
|
|
40592
40738
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
40593
40739
|
Box,
|
|
40594
40740
|
{
|
|
40595
40741
|
className,
|
|
40596
40742
|
style: {
|
|
40597
|
-
backgroundImage:
|
|
40743
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
40598
40744
|
backgroundSize: "cover",
|
|
40599
40745
|
backgroundPosition: "center"
|
|
40600
40746
|
},
|
|
40601
40747
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
40602
|
-
|
|
40748
|
+
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,
|
|
40603
40749
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
40604
40750
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
40605
40751
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Bug, size: "sm" }),
|
|
40606
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title })
|
|
40752
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
40607
40753
|
] }),
|
|
40608
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
40609
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(resolved.bugCount) }) })
|
|
40754
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
40755
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
40610
40756
|
] }) }),
|
|
40611
40757
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
40612
40758
|
const isFlagged = flaggedLines.has(line.id);
|
|
@@ -40638,7 +40784,7 @@ function DebuggerBoard({
|
|
|
40638
40784
|
);
|
|
40639
40785
|
}) }) }),
|
|
40640
40786
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
40641
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
40787
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
|
|
40642
40788
|
bugLines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "start", children: [
|
|
40643
40789
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
40644
40790
|
Icon,
|
|
@@ -40654,7 +40800,7 @@ function DebuggerBoard({
|
|
|
40654
40800
|
] })
|
|
40655
40801
|
] }, line.id))
|
|
40656
40802
|
] }) }),
|
|
40657
|
-
showHint &&
|
|
40803
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
40658
40804
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
40659
40805
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
|
|
40660
40806
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -40673,6 +40819,7 @@ var init_DebuggerBoard = __esm({
|
|
|
40673
40819
|
"components/game/organisms/puzzles/debugger/DebuggerBoard.tsx"() {
|
|
40674
40820
|
init_atoms2();
|
|
40675
40821
|
init_useEventBus();
|
|
40822
|
+
init_boardEntity();
|
|
40676
40823
|
DebuggerBoard.displayName = "DebuggerBoard";
|
|
40677
40824
|
}
|
|
40678
40825
|
});
|
|
@@ -40710,7 +40857,7 @@ function getBadgeVariant(fieldName, value) {
|
|
|
40710
40857
|
return "default";
|
|
40711
40858
|
}
|
|
40712
40859
|
function formatFieldLabel(fieldName) {
|
|
40713
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
40860
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
|
|
40714
40861
|
}
|
|
40715
40862
|
function formatFieldValue(value, fieldName) {
|
|
40716
40863
|
if (typeof value === "number") {
|
|
@@ -40729,26 +40876,26 @@ function formatFieldValue(value, fieldName) {
|
|
|
40729
40876
|
}
|
|
40730
40877
|
function renderRichFieldValue(value, fieldName, fieldType) {
|
|
40731
40878
|
if (value === void 0 || value === null) return "\u2014";
|
|
40732
|
-
const
|
|
40879
|
+
const str2 = String(value);
|
|
40733
40880
|
switch (fieldType) {
|
|
40734
40881
|
case "image":
|
|
40735
40882
|
case "url": {
|
|
40736
|
-
if (
|
|
40883
|
+
if (str2.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str2.startsWith("data:image/")) {
|
|
40737
40884
|
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
40738
40885
|
"img",
|
|
40739
40886
|
{
|
|
40740
|
-
src:
|
|
40887
|
+
src: str2,
|
|
40741
40888
|
alt: formatFieldLabel(fieldName),
|
|
40742
40889
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
40743
40890
|
loading: "lazy"
|
|
40744
40891
|
}
|
|
40745
40892
|
) });
|
|
40746
40893
|
}
|
|
40747
|
-
return
|
|
40894
|
+
return str2;
|
|
40748
40895
|
}
|
|
40749
40896
|
case "markdown":
|
|
40750
40897
|
case "richtext":
|
|
40751
|
-
return /* @__PURE__ */ jsxRuntime.jsx(React97.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children:
|
|
40898
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React97.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children: str2 }), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
40752
40899
|
Box,
|
|
40753
40900
|
{
|
|
40754
40901
|
className: "prose prose-sm max-w-none",
|
|
@@ -40766,11 +40913,11 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
40766
40913
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
40767
40914
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
40768
40915
|
},
|
|
40769
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children:
|
|
40916
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children: str2 })
|
|
40770
40917
|
}
|
|
40771
40918
|
) });
|
|
40772
40919
|
case "code":
|
|
40773
|
-
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:
|
|
40920
|
+
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 }) }) });
|
|
40774
40921
|
case "html":
|
|
40775
40922
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
40776
40923
|
Box,
|
|
@@ -40790,12 +40937,12 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
40790
40937
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
40791
40938
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
40792
40939
|
},
|
|
40793
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children:
|
|
40940
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str2 })
|
|
40794
40941
|
}
|
|
40795
40942
|
);
|
|
40796
40943
|
case "date":
|
|
40797
40944
|
case "datetime": {
|
|
40798
|
-
const d = new Date(
|
|
40945
|
+
const d = new Date(str2);
|
|
40799
40946
|
if (!isNaN(d.getTime())) {
|
|
40800
40947
|
return d.toLocaleDateString(void 0, {
|
|
40801
40948
|
year: "numeric",
|
|
@@ -40804,7 +40951,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
40804
40951
|
...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
|
|
40805
40952
|
});
|
|
40806
40953
|
}
|
|
40807
|
-
return
|
|
40954
|
+
return str2;
|
|
40808
40955
|
}
|
|
40809
40956
|
default:
|
|
40810
40957
|
return formatFieldValue(value, fieldName);
|
|
@@ -41482,6 +41629,40 @@ var init_RuleEditor = __esm({
|
|
|
41482
41629
|
RuleEditor.displayName = "RuleEditor";
|
|
41483
41630
|
}
|
|
41484
41631
|
});
|
|
41632
|
+
|
|
41633
|
+
// components/game/organisms/puzzles/event-handler/puzzleObject.ts
|
|
41634
|
+
function objId(o) {
|
|
41635
|
+
return o.id == null ? "" : String(o.id);
|
|
41636
|
+
}
|
|
41637
|
+
function objName(o) {
|
|
41638
|
+
return o.name == null ? "" : String(o.name);
|
|
41639
|
+
}
|
|
41640
|
+
function objIcon(o) {
|
|
41641
|
+
return o.icon == null ? "" : String(o.icon);
|
|
41642
|
+
}
|
|
41643
|
+
function objStates(o) {
|
|
41644
|
+
return Array.isArray(o.states) ? o.states : [];
|
|
41645
|
+
}
|
|
41646
|
+
function objCurrentState(o) {
|
|
41647
|
+
return o.currentState == null ? "" : String(o.currentState);
|
|
41648
|
+
}
|
|
41649
|
+
function objAvailableEvents(o) {
|
|
41650
|
+
return Array.isArray(o.availableEvents) ? o.availableEvents : [];
|
|
41651
|
+
}
|
|
41652
|
+
function objAvailableActions(o) {
|
|
41653
|
+
return Array.isArray(o.availableActions) ? o.availableActions : [];
|
|
41654
|
+
}
|
|
41655
|
+
function objRules(o) {
|
|
41656
|
+
return Array.isArray(o.rules) ? o.rules : [];
|
|
41657
|
+
}
|
|
41658
|
+
function objMaxRules(o) {
|
|
41659
|
+
const n = Number(o.maxRules);
|
|
41660
|
+
return Number.isFinite(n) && n > 0 ? n : 3;
|
|
41661
|
+
}
|
|
41662
|
+
var init_puzzleObject = __esm({
|
|
41663
|
+
"components/game/organisms/puzzles/event-handler/puzzleObject.ts"() {
|
|
41664
|
+
}
|
|
41665
|
+
});
|
|
41485
41666
|
function ObjectRulePanel({
|
|
41486
41667
|
object,
|
|
41487
41668
|
onRulesChange,
|
|
@@ -41489,55 +41670,63 @@ function ObjectRulePanel({
|
|
|
41489
41670
|
className
|
|
41490
41671
|
}) {
|
|
41491
41672
|
const { t } = hooks.useTranslate();
|
|
41492
|
-
const
|
|
41493
|
-
const
|
|
41673
|
+
const id = objId(object);
|
|
41674
|
+
const name = objName(object);
|
|
41675
|
+
const icon = objIcon(object);
|
|
41676
|
+
const states = objStates(object);
|
|
41677
|
+
const currentState = objCurrentState(object);
|
|
41678
|
+
const availableEvents = objAvailableEvents(object);
|
|
41679
|
+
const availableActions = objAvailableActions(object);
|
|
41680
|
+
const rules = objRules(object);
|
|
41681
|
+
const maxRules = objMaxRules(object);
|
|
41682
|
+
const canAdd = rules.length < maxRules;
|
|
41494
41683
|
const handleRuleChange = React97.useCallback((index, updatedRule) => {
|
|
41495
|
-
const newRules = [...
|
|
41684
|
+
const newRules = [...rules];
|
|
41496
41685
|
newRules[index] = updatedRule;
|
|
41497
|
-
onRulesChange(
|
|
41498
|
-
}, [
|
|
41686
|
+
onRulesChange(id, newRules);
|
|
41687
|
+
}, [id, rules, onRulesChange]);
|
|
41499
41688
|
const handleRuleRemove = React97.useCallback((index) => {
|
|
41500
|
-
const newRules =
|
|
41501
|
-
onRulesChange(
|
|
41502
|
-
}, [
|
|
41689
|
+
const newRules = rules.filter((_, i) => i !== index);
|
|
41690
|
+
onRulesChange(id, newRules);
|
|
41691
|
+
}, [id, rules, onRulesChange]);
|
|
41503
41692
|
const handleAddRule = React97.useCallback(() => {
|
|
41504
41693
|
if (!canAdd || disabled) return;
|
|
41505
|
-
const firstEvent =
|
|
41506
|
-
const firstAction =
|
|
41694
|
+
const firstEvent = availableEvents[0]?.value || "";
|
|
41695
|
+
const firstAction = availableActions[0]?.value || "";
|
|
41507
41696
|
const newRule = {
|
|
41508
41697
|
id: `rule-${nextRuleId++}`,
|
|
41509
41698
|
whenEvent: firstEvent,
|
|
41510
41699
|
thenAction: firstAction
|
|
41511
41700
|
};
|
|
41512
|
-
onRulesChange(
|
|
41513
|
-
}, [canAdd, disabled,
|
|
41701
|
+
onRulesChange(id, [...rules, newRule]);
|
|
41702
|
+
}, [canAdd, disabled, id, rules, availableEvents, availableActions, onRulesChange]);
|
|
41514
41703
|
const machine = {
|
|
41515
|
-
name
|
|
41516
|
-
states
|
|
41517
|
-
currentState
|
|
41518
|
-
transitions:
|
|
41519
|
-
from:
|
|
41520
|
-
to:
|
|
41704
|
+
name,
|
|
41705
|
+
states,
|
|
41706
|
+
currentState,
|
|
41707
|
+
transitions: rules.map((r2) => ({
|
|
41708
|
+
from: currentState,
|
|
41709
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
41521
41710
|
event: r2.whenEvent
|
|
41522
41711
|
}))
|
|
41523
41712
|
};
|
|
41524
41713
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-4 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
41525
41714
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center", gap: "sm", children: [
|
|
41526
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children:
|
|
41715
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: icon }),
|
|
41527
41716
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
41528
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children:
|
|
41529
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " +
|
|
41717
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children: name }),
|
|
41718
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " + currentState })
|
|
41530
41719
|
] })
|
|
41531
41720
|
] }),
|
|
41532
41721
|
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" }),
|
|
41533
41722
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
41534
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count:
|
|
41535
|
-
|
|
41723
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count: rules.length, max: maxRules }) + ":" }),
|
|
41724
|
+
rules.map((rule, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
41536
41725
|
RuleEditor,
|
|
41537
41726
|
{
|
|
41538
41727
|
rule,
|
|
41539
|
-
availableEvents
|
|
41540
|
-
availableActions
|
|
41728
|
+
availableEvents,
|
|
41729
|
+
availableActions,
|
|
41541
41730
|
onChange: (r2) => handleRuleChange(i, r2),
|
|
41542
41731
|
onRemove: () => handleRuleRemove(i),
|
|
41543
41732
|
disabled
|
|
@@ -41555,6 +41744,7 @@ var init_ObjectRulePanel = __esm({
|
|
|
41555
41744
|
init_cn();
|
|
41556
41745
|
init_TraitStateViewer();
|
|
41557
41746
|
init_RuleEditor();
|
|
41747
|
+
init_puzzleObject();
|
|
41558
41748
|
nextRuleId = 1;
|
|
41559
41749
|
ObjectRulePanel.displayName = "ObjectRulePanel";
|
|
41560
41750
|
}
|
|
@@ -41621,11 +41811,11 @@ function EventHandlerBoard({
|
|
|
41621
41811
|
}) {
|
|
41622
41812
|
const { emit } = useEventBus();
|
|
41623
41813
|
const { t } = hooks.useTranslate();
|
|
41624
|
-
const resolved =
|
|
41625
|
-
const entityObjects = resolved?.objects
|
|
41626
|
-
const [objects, setObjects] = React97.useState(entityObjects);
|
|
41814
|
+
const resolved = boardEntity(entity);
|
|
41815
|
+
const entityObjects = rows(resolved?.objects);
|
|
41816
|
+
const [objects, setObjects] = React97.useState(() => [...entityObjects]);
|
|
41627
41817
|
const [selectedObjectId, setSelectedObjectId] = React97.useState(
|
|
41628
|
-
entityObjects[0]
|
|
41818
|
+
entityObjects[0] ? objId(entityObjects[0]) : null
|
|
41629
41819
|
);
|
|
41630
41820
|
const [headerError, setHeaderError] = React97.useState(false);
|
|
41631
41821
|
const [playState, setPlayState] = React97.useState("editing");
|
|
@@ -41636,10 +41826,10 @@ function EventHandlerBoard({
|
|
|
41636
41826
|
React97.useEffect(() => () => {
|
|
41637
41827
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
41638
41828
|
}, []);
|
|
41639
|
-
const selectedObject = objects.find((o) => o
|
|
41829
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) || null;
|
|
41640
41830
|
const handleRulesChange = React97.useCallback((objectId, rules) => {
|
|
41641
41831
|
setObjects((prev) => prev.map(
|
|
41642
|
-
(o) => o
|
|
41832
|
+
(o) => objId(o) === objectId ? { ...o, rules } : o
|
|
41643
41833
|
));
|
|
41644
41834
|
}, []);
|
|
41645
41835
|
const addLogEntry = React97.useCallback((icon, message, status = "done") => {
|
|
@@ -41653,11 +41843,12 @@ function EventHandlerBoard({
|
|
|
41653
41843
|
setEventLog([]);
|
|
41654
41844
|
const allRules = [];
|
|
41655
41845
|
objects.forEach((obj) => {
|
|
41656
|
-
obj.
|
|
41846
|
+
objRules(obj).forEach((rule) => {
|
|
41657
41847
|
allRules.push({ object: obj, rule });
|
|
41658
41848
|
});
|
|
41659
41849
|
});
|
|
41660
|
-
const triggers = resolved?.triggerEvents
|
|
41850
|
+
const triggers = Array.isArray(resolved?.triggerEvents) ? resolved.triggerEvents : [];
|
|
41851
|
+
const goalEvent = str(resolved?.goalEvent);
|
|
41661
41852
|
const eventQueue = [...triggers];
|
|
41662
41853
|
const firedEvents = /* @__PURE__ */ new Set();
|
|
41663
41854
|
let stepIdx = 0;
|
|
@@ -41686,14 +41877,14 @@ function EventHandlerBoard({
|
|
|
41686
41877
|
addLogEntry("\u26A1", t("eventHandler.noListeners", { event: currentEvent }), "done");
|
|
41687
41878
|
} else {
|
|
41688
41879
|
matching.forEach(({ object, rule }) => {
|
|
41689
|
-
addLogEntry(object
|
|
41880
|
+
addLogEntry(objIcon(object), t("eventHandler.heardEvent", { object: objName(object), event: currentEvent, action: rule.thenAction }), "done");
|
|
41690
41881
|
eventQueue.push(rule.thenAction);
|
|
41691
|
-
if (rule.thenAction ===
|
|
41882
|
+
if (rule.thenAction === goalEvent) {
|
|
41692
41883
|
goalReached = true;
|
|
41693
41884
|
}
|
|
41694
41885
|
});
|
|
41695
41886
|
}
|
|
41696
|
-
if (currentEvent ===
|
|
41887
|
+
if (currentEvent === goalEvent) {
|
|
41697
41888
|
goalReached = true;
|
|
41698
41889
|
}
|
|
41699
41890
|
stepIdx++;
|
|
@@ -41711,65 +41902,75 @@ function EventHandlerBoard({
|
|
|
41711
41902
|
}, []);
|
|
41712
41903
|
const handleReset = React97.useCallback(() => {
|
|
41713
41904
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
41714
|
-
|
|
41905
|
+
const resetObjects = rows(resolved?.objects);
|
|
41906
|
+
setObjects([...resetObjects]);
|
|
41715
41907
|
setPlayState("editing");
|
|
41716
41908
|
setEventLog([]);
|
|
41717
|
-
setSelectedObjectId(
|
|
41909
|
+
setSelectedObjectId(resetObjects[0] ? objId(resetObjects[0]) : null);
|
|
41718
41910
|
setAttempts(0);
|
|
41719
41911
|
}, [resolved?.objects]);
|
|
41720
41912
|
if (!resolved) return null;
|
|
41721
41913
|
const objectViewers = objects.map((obj) => {
|
|
41914
|
+
const states = objStates(obj);
|
|
41915
|
+
const currentState = objCurrentState(obj);
|
|
41722
41916
|
const machine = {
|
|
41723
|
-
name: obj
|
|
41724
|
-
states
|
|
41725
|
-
currentState
|
|
41726
|
-
transitions: obj.
|
|
41727
|
-
from:
|
|
41728
|
-
to:
|
|
41917
|
+
name: objName(obj),
|
|
41918
|
+
states,
|
|
41919
|
+
currentState,
|
|
41920
|
+
transitions: objRules(obj).map((r2) => ({
|
|
41921
|
+
from: currentState,
|
|
41922
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
41729
41923
|
event: r2.whenEvent
|
|
41730
41924
|
}))
|
|
41731
41925
|
};
|
|
41732
41926
|
return { obj, machine };
|
|
41733
41927
|
});
|
|
41734
|
-
const
|
|
41928
|
+
const hint = str(resolved.hint);
|
|
41929
|
+
const showHint = attempts >= 3 && hint;
|
|
41930
|
+
const theme = resolved.theme ?? void 0;
|
|
41931
|
+
const themeBackground = theme?.background;
|
|
41932
|
+
const headerImage = str(resolved.headerImage);
|
|
41735
41933
|
const encourageKey = ENCOURAGEMENT_KEYS[Math.min(attempts - 1, ENCOURAGEMENT_KEYS.length - 1)] ?? ENCOURAGEMENT_KEYS[0];
|
|
41736
41934
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
41737
41935
|
VStack,
|
|
41738
41936
|
{
|
|
41739
41937
|
className: cn("p-4 gap-6", className),
|
|
41740
41938
|
style: {
|
|
41741
|
-
backgroundImage:
|
|
41939
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
41742
41940
|
backgroundSize: "cover",
|
|
41743
41941
|
backgroundPosition: "center"
|
|
41744
41942
|
},
|
|
41745
41943
|
children: [
|
|
41746
|
-
|
|
41944
|
+
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,
|
|
41747
41945
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
41748
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
41749
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
41946
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
41947
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
41750
41948
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
|
|
41751
41949
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
|
|
41752
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: resolved.goalCondition })
|
|
41950
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: str(resolved.goalCondition) })
|
|
41753
41951
|
] })
|
|
41754
41952
|
] }),
|
|
41755
41953
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
41756
41954
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
|
|
41757
|
-
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) =>
|
|
41758
|
-
|
|
41759
|
-
|
|
41760
|
-
|
|
41761
|
-
|
|
41762
|
-
|
|
41763
|
-
|
|
41764
|
-
|
|
41765
|
-
|
|
41766
|
-
|
|
41767
|
-
/* @__PURE__ */ jsxRuntime.
|
|
41768
|
-
|
|
41769
|
-
|
|
41770
|
-
|
|
41771
|
-
|
|
41772
|
-
|
|
41955
|
+
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => {
|
|
41956
|
+
const oid = objId(obj);
|
|
41957
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
41958
|
+
Box,
|
|
41959
|
+
{
|
|
41960
|
+
className: cn(
|
|
41961
|
+
"p-3 rounded-container border-2 cursor-pointer transition-all hover:scale-105",
|
|
41962
|
+
selectedObjectId === oid ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
|
|
41963
|
+
),
|
|
41964
|
+
onClick: () => setSelectedObjectId(oid),
|
|
41965
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
|
|
41966
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: objIcon(obj) }),
|
|
41967
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: objName(obj) }),
|
|
41968
|
+
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
|
|
41969
|
+
] })
|
|
41970
|
+
},
|
|
41971
|
+
oid
|
|
41972
|
+
);
|
|
41973
|
+
}) })
|
|
41773
41974
|
] }),
|
|
41774
41975
|
selectedObject && /* @__PURE__ */ jsxRuntime.jsx(
|
|
41775
41976
|
ObjectRulePanel,
|
|
@@ -41780,12 +41981,12 @@ function EventHandlerBoard({
|
|
|
41780
41981
|
}
|
|
41781
41982
|
),
|
|
41782
41983
|
eventLog.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(EventLog, { entries: eventLog }),
|
|
41783
|
-
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") }) }),
|
|
41984
|
+
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") }) }),
|
|
41784
41985
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
41785
41986
|
/* @__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) }) }),
|
|
41786
41987
|
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: [
|
|
41787
41988
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
41788
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
41989
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
41789
41990
|
] }) })
|
|
41790
41991
|
] }),
|
|
41791
41992
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -41813,6 +42014,8 @@ var init_EventHandlerBoard = __esm({
|
|
|
41813
42014
|
init_TraitStateViewer();
|
|
41814
42015
|
init_ObjectRulePanel();
|
|
41815
42016
|
init_EventLog();
|
|
42017
|
+
init_puzzleObject();
|
|
42018
|
+
init_boardEntity();
|
|
41816
42019
|
ENCOURAGEMENT_KEYS = [
|
|
41817
42020
|
"puzzle.tryAgain1",
|
|
41818
42021
|
"puzzle.tryAgain2",
|
|
@@ -41901,7 +42104,10 @@ var init_FeatureGridOrganism = __esm({
|
|
|
41901
42104
|
);
|
|
41902
42105
|
React97.useCallback(
|
|
41903
42106
|
(feature) => {
|
|
41904
|
-
eventBus.emit("UI:FEATURE_CLICK", {
|
|
42107
|
+
eventBus.emit("UI:FEATURE_CLICK", {
|
|
42108
|
+
id: String(feature.id ?? ""),
|
|
42109
|
+
href: String(feature.href ?? "")
|
|
42110
|
+
});
|
|
41905
42111
|
},
|
|
41906
42112
|
[eventBus]
|
|
41907
42113
|
);
|
|
@@ -41911,14 +42117,17 @@ var init_FeatureGridOrganism = __esm({
|
|
|
41911
42117
|
if (error) {
|
|
41912
42118
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
41913
42119
|
}
|
|
41914
|
-
const featureCards = items.map((feature) =>
|
|
41915
|
-
|
|
41916
|
-
|
|
41917
|
-
|
|
41918
|
-
|
|
41919
|
-
|
|
41920
|
-
|
|
41921
|
-
|
|
42120
|
+
const featureCards = items.map((feature) => {
|
|
42121
|
+
const href = feature.href != null ? String(feature.href) : void 0;
|
|
42122
|
+
return {
|
|
42123
|
+
icon: feature.icon != null ? String(feature.icon) : void 0,
|
|
42124
|
+
title: String(feature.title ?? ""),
|
|
42125
|
+
description: String(feature.description ?? ""),
|
|
42126
|
+
href,
|
|
42127
|
+
linkLabel: feature.linkLabel != null ? String(feature.linkLabel) : void 0,
|
|
42128
|
+
variant: href ? "interactive" : "bordered"
|
|
42129
|
+
};
|
|
42130
|
+
});
|
|
41922
42131
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
41923
42132
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
41924
42133
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
@@ -43236,22 +43445,24 @@ var init_HeroOrganism = __esm({
|
|
|
43236
43445
|
() => Array.isArray(entity) ? entity[0] : entity && typeof entity === "object" ? entity : void 0,
|
|
43237
43446
|
[entity]
|
|
43238
43447
|
);
|
|
43448
|
+
const primaryAction = resolved?.primaryAction;
|
|
43449
|
+
const secondaryAction = resolved?.secondaryAction;
|
|
43239
43450
|
const handlePrimaryClick = React97.useCallback(() => {
|
|
43240
|
-
if (
|
|
43451
|
+
if (primaryAction) {
|
|
43241
43452
|
eventBus.emit("UI:CTA_PRIMARY", {
|
|
43242
|
-
label:
|
|
43243
|
-
href:
|
|
43453
|
+
label: String(primaryAction.label ?? ""),
|
|
43454
|
+
href: String(primaryAction.href ?? "")
|
|
43244
43455
|
});
|
|
43245
43456
|
}
|
|
43246
|
-
}, [eventBus,
|
|
43457
|
+
}, [eventBus, primaryAction]);
|
|
43247
43458
|
const handleSecondaryClick = React97.useCallback(() => {
|
|
43248
|
-
if (
|
|
43459
|
+
if (secondaryAction) {
|
|
43249
43460
|
eventBus.emit("UI:CTA_SECONDARY", {
|
|
43250
|
-
label:
|
|
43251
|
-
href:
|
|
43461
|
+
label: String(secondaryAction.label ?? ""),
|
|
43462
|
+
href: String(secondaryAction.href ?? "")
|
|
43252
43463
|
});
|
|
43253
43464
|
}
|
|
43254
|
-
}, [eventBus,
|
|
43465
|
+
}, [eventBus, secondaryAction]);
|
|
43255
43466
|
if (isLoading) {
|
|
43256
43467
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
43257
43468
|
}
|
|
@@ -43261,17 +43472,19 @@ var init_HeroOrganism = __esm({
|
|
|
43261
43472
|
if (!resolved) {
|
|
43262
43473
|
return null;
|
|
43263
43474
|
}
|
|
43475
|
+
const imageRaw = resolved.image;
|
|
43476
|
+
const image = imageRaw ? { src: String(imageRaw.src ?? ""), alt: String(imageRaw.alt ?? "") } : void 0;
|
|
43264
43477
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
43265
43478
|
HeroSection,
|
|
43266
43479
|
{
|
|
43267
|
-
tag: resolved.tag,
|
|
43268
|
-
title: resolved.title,
|
|
43269
|
-
titleAccent: resolved.titleAccent,
|
|
43270
|
-
subtitle: resolved.subtitle,
|
|
43271
|
-
primaryAction:
|
|
43272
|
-
secondaryAction:
|
|
43273
|
-
installCommand: resolved.installCommand,
|
|
43274
|
-
image
|
|
43480
|
+
tag: resolved.tag != null ? String(resolved.tag) : void 0,
|
|
43481
|
+
title: String(resolved.title ?? ""),
|
|
43482
|
+
titleAccent: resolved.titleAccent != null ? String(resolved.titleAccent) : void 0,
|
|
43483
|
+
subtitle: String(resolved.subtitle ?? ""),
|
|
43484
|
+
primaryAction: primaryAction ? { label: String(primaryAction.label ?? ""), href: String(primaryAction.href ?? "") } : void 0,
|
|
43485
|
+
secondaryAction: secondaryAction ? { label: String(secondaryAction.label ?? ""), href: String(secondaryAction.href ?? "") } : void 0,
|
|
43486
|
+
installCommand: resolved.installCommand != null ? String(resolved.installCommand) : void 0,
|
|
43487
|
+
image,
|
|
43275
43488
|
imagePosition: resolved.imagePosition,
|
|
43276
43489
|
background: resolved.background,
|
|
43277
43490
|
className: cn(className),
|
|
@@ -43280,8 +43493,8 @@ var init_HeroOrganism = __esm({
|
|
|
43280
43493
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43281
43494
|
_HeroClickInterceptor,
|
|
43282
43495
|
{
|
|
43283
|
-
hasPrimary: !!
|
|
43284
|
-
hasSecondary: !!
|
|
43496
|
+
hasPrimary: !!primaryAction,
|
|
43497
|
+
hasSecondary: !!secondaryAction,
|
|
43285
43498
|
onPrimaryClick: handlePrimaryClick,
|
|
43286
43499
|
onSecondaryClick: handleSecondaryClick
|
|
43287
43500
|
}
|
|
@@ -43510,7 +43723,7 @@ function formatValue3(value, fieldName) {
|
|
|
43510
43723
|
return String(value);
|
|
43511
43724
|
}
|
|
43512
43725
|
function formatFieldLabel2(fieldName) {
|
|
43513
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
43726
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
|
|
43514
43727
|
}
|
|
43515
43728
|
var STATUS_STYLES2, StatusBadge, ProgressIndicator, List3;
|
|
43516
43729
|
var init_List = __esm({
|
|
@@ -44357,20 +44570,22 @@ function NegotiatorBoard({
|
|
|
44357
44570
|
}) {
|
|
44358
44571
|
const { emit } = useEventBus();
|
|
44359
44572
|
const { t } = hooks.useTranslate();
|
|
44360
|
-
const resolved =
|
|
44573
|
+
const resolved = boardEntity(entity);
|
|
44361
44574
|
const [history, setHistory] = React97.useState([]);
|
|
44362
44575
|
const [headerError, setHeaderError] = React97.useState(false);
|
|
44363
44576
|
const [showHint, setShowHint] = React97.useState(false);
|
|
44577
|
+
const totalRounds = num(resolved?.totalRounds);
|
|
44578
|
+
const targetScore = num(resolved?.targetScore);
|
|
44364
44579
|
const currentRound = history.length;
|
|
44365
|
-
const isComplete = currentRound >=
|
|
44580
|
+
const isComplete = currentRound >= totalRounds;
|
|
44366
44581
|
const playerTotal = history.reduce((s, r2) => s + r2.playerPayoff, 0);
|
|
44367
44582
|
const opponentTotal = history.reduce((s, r2) => s + r2.opponentPayoff, 0);
|
|
44368
|
-
const won = isComplete && playerTotal >=
|
|
44369
|
-
const actions = resolved?.actions
|
|
44370
|
-
const payoffMatrix = resolved?.payoffMatrix
|
|
44583
|
+
const won = isComplete && playerTotal >= targetScore;
|
|
44584
|
+
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
44585
|
+
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
44371
44586
|
const handleAction = React97.useCallback((actionId) => {
|
|
44372
44587
|
if (isComplete) return;
|
|
44373
|
-
const opponentAction = getOpponentAction(resolved?.opponentStrategy
|
|
44588
|
+
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
44374
44589
|
const payoff = payoffMatrix.find(
|
|
44375
44590
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
44376
44591
|
);
|
|
@@ -44383,42 +44598,46 @@ function NegotiatorBoard({
|
|
|
44383
44598
|
};
|
|
44384
44599
|
const newHistory = [...history, result];
|
|
44385
44600
|
setHistory(newHistory);
|
|
44386
|
-
if (newHistory.length >=
|
|
44601
|
+
if (newHistory.length >= totalRounds) {
|
|
44387
44602
|
const total = newHistory.reduce((s, r2) => s + r2.playerPayoff, 0);
|
|
44388
|
-
if (total >=
|
|
44603
|
+
if (total >= targetScore) {
|
|
44389
44604
|
emit(`UI:${completeEvent}`, { success: true, score: total });
|
|
44390
44605
|
}
|
|
44391
|
-
if (newHistory.length >= 3 && resolved?.hint) {
|
|
44606
|
+
if (newHistory.length >= 3 && str(resolved?.hint)) {
|
|
44392
44607
|
setShowHint(true);
|
|
44393
44608
|
}
|
|
44394
44609
|
}
|
|
44395
|
-
}, [isComplete, resolved, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
44610
|
+
}, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
44396
44611
|
const handleReset = () => {
|
|
44397
44612
|
setHistory([]);
|
|
44398
44613
|
setShowHint(false);
|
|
44399
44614
|
};
|
|
44400
44615
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
44401
44616
|
if (!resolved) return null;
|
|
44617
|
+
const theme = resolved.theme ?? void 0;
|
|
44618
|
+
const themeBackground = theme?.background;
|
|
44619
|
+
const headerImage = str(resolved.headerImage);
|
|
44620
|
+
const hint = str(resolved.hint);
|
|
44402
44621
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44403
44622
|
Box,
|
|
44404
44623
|
{
|
|
44405
44624
|
className,
|
|
44406
44625
|
style: {
|
|
44407
|
-
backgroundImage:
|
|
44626
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
44408
44627
|
backgroundSize: "cover",
|
|
44409
44628
|
backgroundPosition: "center"
|
|
44410
44629
|
},
|
|
44411
44630
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
44412
|
-
|
|
44631
|
+
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,
|
|
44413
44632
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
44414
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
44415
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
44633
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
44634
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
44416
44635
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", children: [
|
|
44417
|
-
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(
|
|
44636
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(totalRounds) }) }),
|
|
44418
44637
|
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", children: [
|
|
44419
44638
|
t("negotiator.target"),
|
|
44420
44639
|
": ",
|
|
44421
|
-
|
|
44640
|
+
targetScore
|
|
44422
44641
|
] })
|
|
44423
44642
|
] })
|
|
44424
44643
|
] }) }),
|
|
@@ -44467,16 +44686,16 @@ function NegotiatorBoard({
|
|
|
44467
44686
|
] }) }),
|
|
44468
44687
|
isComplete && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
44469
44688
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: won ? "text-success" : "text-error" }),
|
|
44470
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? resolved.successMessage
|
|
44689
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? str(resolved.successMessage) || t("negotiator.success") : str(resolved.failMessage) || t("negotiator.failed") }),
|
|
44471
44690
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44472
44691
|
t("negotiator.finalScore"),
|
|
44473
44692
|
": ",
|
|
44474
44693
|
playerTotal,
|
|
44475
44694
|
"/",
|
|
44476
|
-
|
|
44695
|
+
targetScore
|
|
44477
44696
|
] })
|
|
44478
44697
|
] }) }),
|
|
44479
|
-
showHint &&
|
|
44698
|
+
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 }) }),
|
|
44480
44699
|
isComplete && !won && /* @__PURE__ */ jsxRuntime.jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
|
|
44481
44700
|
] })
|
|
44482
44701
|
}
|
|
@@ -44486,6 +44705,7 @@ var init_NegotiatorBoard = __esm({
|
|
|
44486
44705
|
"components/game/organisms/puzzles/negotiator/NegotiatorBoard.tsx"() {
|
|
44487
44706
|
init_atoms2();
|
|
44488
44707
|
init_useEventBus();
|
|
44708
|
+
init_boardEntity();
|
|
44489
44709
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
44490
44710
|
}
|
|
44491
44711
|
});
|
|
@@ -44521,13 +44741,13 @@ var init_PricingOrganism = __esm({
|
|
|
44521
44741
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
44522
44742
|
}
|
|
44523
44743
|
const plans = items.map((plan) => ({
|
|
44524
|
-
name: plan.name,
|
|
44525
|
-
price: plan.price,
|
|
44526
|
-
description: plan.description,
|
|
44527
|
-
features: plan.features,
|
|
44528
|
-
action: { label: plan.actionLabel, href: plan.actionHref },
|
|
44529
|
-
highlighted: plan.highlighted,
|
|
44530
|
-
badge: plan.badge
|
|
44744
|
+
name: String(plan.name ?? ""),
|
|
44745
|
+
price: String(plan.price ?? ""),
|
|
44746
|
+
description: plan.description != null ? String(plan.description) : void 0,
|
|
44747
|
+
features: (plan.features ?? []).map((f3) => String(f3)),
|
|
44748
|
+
action: { label: String(plan.actionLabel ?? ""), href: String(plan.actionHref ?? "") },
|
|
44749
|
+
highlighted: Boolean(plan.highlighted),
|
|
44750
|
+
badge: plan.badge != null ? String(plan.badge) : void 0
|
|
44531
44751
|
}));
|
|
44532
44752
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
44533
44753
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -46617,16 +46837,20 @@ function SequencerBoard({
|
|
|
46617
46837
|
}) {
|
|
46618
46838
|
const { emit } = useEventBus();
|
|
46619
46839
|
const { t } = hooks.useTranslate();
|
|
46620
|
-
const resolved =
|
|
46840
|
+
const resolved = boardEntity(entity);
|
|
46841
|
+
const maxSlots = num(resolved?.maxSlots);
|
|
46842
|
+
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
46843
|
+
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
46844
|
+
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
46621
46845
|
const [headerError, setHeaderError] = React97.useState(false);
|
|
46622
46846
|
const [slots, setSlots] = React97.useState(
|
|
46623
|
-
() => Array.from({ length:
|
|
46847
|
+
() => Array.from({ length: maxSlots }, () => void 0)
|
|
46624
46848
|
);
|
|
46625
46849
|
const [playState, setPlayState] = React97.useState("idle");
|
|
46626
46850
|
const [currentStep, setCurrentStep] = React97.useState(-1);
|
|
46627
46851
|
const [attempts, setAttempts] = React97.useState(0);
|
|
46628
46852
|
const [slotFeedback, setSlotFeedback] = React97.useState(
|
|
46629
|
-
() => Array.from({ length:
|
|
46853
|
+
() => Array.from({ length: maxSlots }, () => null)
|
|
46630
46854
|
);
|
|
46631
46855
|
const timerRef = React97.useRef(null);
|
|
46632
46856
|
React97.useEffect(() => () => {
|
|
@@ -46660,17 +46884,17 @@ function SequencerBoard({
|
|
|
46660
46884
|
}, [emit]);
|
|
46661
46885
|
const handleReset = React97.useCallback(() => {
|
|
46662
46886
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
46663
|
-
setSlots(Array.from({ length:
|
|
46887
|
+
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
46664
46888
|
setPlayState("idle");
|
|
46665
46889
|
setCurrentStep(-1);
|
|
46666
46890
|
setAttempts(0);
|
|
46667
|
-
setSlotFeedback(Array.from({ length:
|
|
46668
|
-
}, [
|
|
46891
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
46892
|
+
}, [maxSlots]);
|
|
46669
46893
|
const filledSlots = slots.filter((s) => !!s);
|
|
46670
46894
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
46671
46895
|
const handlePlay = React97.useCallback(() => {
|
|
46672
46896
|
if (!canPlay) return;
|
|
46673
|
-
setSlotFeedback(Array.from({ length:
|
|
46897
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
46674
46898
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
46675
46899
|
const sequence = slots.map((s) => s?.id || "");
|
|
46676
46900
|
if (playEvent) {
|
|
@@ -46681,10 +46905,10 @@ function SequencerBoard({
|
|
|
46681
46905
|
let step = 0;
|
|
46682
46906
|
const advance = () => {
|
|
46683
46907
|
step++;
|
|
46684
|
-
if (step >=
|
|
46908
|
+
if (step >= maxSlots) {
|
|
46685
46909
|
const playerSeq = slots.map((s) => s?.id);
|
|
46686
46910
|
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
46687
|
-
const success =
|
|
46911
|
+
const success = solutions.some(
|
|
46688
46912
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
46689
46913
|
);
|
|
46690
46914
|
if (success) {
|
|
@@ -46696,7 +46920,7 @@ function SequencerBoard({
|
|
|
46696
46920
|
}
|
|
46697
46921
|
} else {
|
|
46698
46922
|
setAttempts((prev) => prev + 1);
|
|
46699
|
-
const feedback = computeSlotFeedback(playerSeq,
|
|
46923
|
+
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
46700
46924
|
setSlotFeedback(feedback);
|
|
46701
46925
|
setPlayState("idle");
|
|
46702
46926
|
setCurrentStep(-1);
|
|
@@ -46714,10 +46938,10 @@ function SequencerBoard({
|
|
|
46714
46938
|
}
|
|
46715
46939
|
};
|
|
46716
46940
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
46717
|
-
}, [canPlay, slots,
|
|
46941
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
46718
46942
|
const machine = {
|
|
46719
|
-
name: resolved?.title
|
|
46720
|
-
description: resolved?.description
|
|
46943
|
+
name: str(resolved?.title),
|
|
46944
|
+
description: str(resolved?.description),
|
|
46721
46945
|
states: slots.map((s, i) => stepLabel(s, i)),
|
|
46722
46946
|
currentState: currentStep >= 0 ? stepLabel(slots[currentStep], currentStep) : "__idle__",
|
|
46723
46947
|
transitions: slots.slice(0, -1).map((s, i) => ({
|
|
@@ -46726,37 +46950,41 @@ function SequencerBoard({
|
|
|
46726
46950
|
event: "NEXT"
|
|
46727
46951
|
}))
|
|
46728
46952
|
};
|
|
46729
|
-
const usedIds =
|
|
46730
|
-
const
|
|
46953
|
+
const usedIds = !allowDuplicates ? slots.filter(Boolean).map((s) => s?.id || "") : [];
|
|
46954
|
+
const hint = str(resolved?.hint);
|
|
46955
|
+
const showHint = attempts >= 3 && !!hint;
|
|
46731
46956
|
const hasFeedback = slotFeedback.some((f3) => f3 !== null);
|
|
46732
46957
|
const correctCount = slotFeedback.filter((f3) => f3 === "correct").length;
|
|
46733
46958
|
const encourageKey = ENCOURAGEMENT_KEYS2[Math.min(attempts - 1, ENCOURAGEMENT_KEYS2.length - 1)] ?? ENCOURAGEMENT_KEYS2[0];
|
|
46734
46959
|
if (!resolved) return null;
|
|
46960
|
+
const theme = resolved.theme ?? void 0;
|
|
46961
|
+
const themeBackground = theme?.background;
|
|
46962
|
+
const headerImage = str(resolved.headerImage);
|
|
46735
46963
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
46736
46964
|
VStack,
|
|
46737
46965
|
{
|
|
46738
46966
|
className: cn("p-4 gap-6", className),
|
|
46739
46967
|
style: {
|
|
46740
|
-
backgroundImage:
|
|
46968
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
46741
46969
|
backgroundSize: "cover",
|
|
46742
46970
|
backgroundPosition: "center"
|
|
46743
46971
|
},
|
|
46744
46972
|
children: [
|
|
46745
|
-
|
|
46973
|
+
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,
|
|
46746
46974
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
46747
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
46748
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description })
|
|
46975
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
46976
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) })
|
|
46749
46977
|
] }),
|
|
46750
46978
|
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: [
|
|
46751
46979
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
46752
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
46980
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
46753
46981
|
] }) }),
|
|
46754
46982
|
filledSlots.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
|
|
46755
46983
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
46756
46984
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
46757
46985
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
46758
46986
|
hasFeedback && playState === "idle" && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
46759
|
-
`${correctCount}/${
|
|
46987
|
+
`${correctCount}/${maxSlots} `,
|
|
46760
46988
|
"\u2705"
|
|
46761
46989
|
] })
|
|
46762
46990
|
] }),
|
|
@@ -46764,7 +46992,7 @@ function SequencerBoard({
|
|
|
46764
46992
|
SequenceBar,
|
|
46765
46993
|
{
|
|
46766
46994
|
slots,
|
|
46767
|
-
maxSlots
|
|
46995
|
+
maxSlots,
|
|
46768
46996
|
onSlotDrop: handleSlotDrop,
|
|
46769
46997
|
onSlotRemove: handleSlotRemove,
|
|
46770
46998
|
playing: playState === "playing",
|
|
@@ -46778,15 +47006,15 @@ function SequencerBoard({
|
|
|
46778
47006
|
playState !== "playing" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
46779
47007
|
ActionPalette,
|
|
46780
47008
|
{
|
|
46781
|
-
actions:
|
|
47009
|
+
actions: availableActions,
|
|
46782
47010
|
usedActionIds: usedIds,
|
|
46783
|
-
allowDuplicates
|
|
47011
|
+
allowDuplicates,
|
|
46784
47012
|
categoryColors,
|
|
46785
47013
|
label: t("sequencer.dragActions")
|
|
46786
47014
|
}
|
|
46787
47015
|
),
|
|
46788
47016
|
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) }) }),
|
|
46789
|
-
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") }) }),
|
|
47017
|
+
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") }) }),
|
|
46790
47018
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
46791
47019
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
46792
47020
|
Button,
|
|
@@ -46810,6 +47038,7 @@ var init_SequencerBoard = __esm({
|
|
|
46810
47038
|
init_cn();
|
|
46811
47039
|
init_useEventBus();
|
|
46812
47040
|
init_TraitStateViewer();
|
|
47041
|
+
init_boardEntity();
|
|
46813
47042
|
init_SequenceBar();
|
|
46814
47043
|
init_ActionPalette();
|
|
46815
47044
|
ENCOURAGEMENT_KEYS2 = [
|
|
@@ -46859,18 +47088,21 @@ var init_ShowcaseOrganism = __esm({
|
|
|
46859
47088
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
46860
47089
|
subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", color: "muted", align: "center", className: "max-w-2xl", children: subtitle })
|
|
46861
47090
|
] }),
|
|
46862
|
-
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) =>
|
|
46863
|
-
|
|
46864
|
-
|
|
46865
|
-
|
|
46866
|
-
|
|
46867
|
-
|
|
46868
|
-
|
|
46869
|
-
|
|
46870
|
-
|
|
46871
|
-
|
|
46872
|
-
|
|
46873
|
-
|
|
47091
|
+
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) => {
|
|
47092
|
+
const imageRaw = item.image;
|
|
47093
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
47094
|
+
ShowcaseCard,
|
|
47095
|
+
{
|
|
47096
|
+
title: String(item.title ?? ""),
|
|
47097
|
+
description: item.description != null ? String(item.description) : void 0,
|
|
47098
|
+
image: { src: String(imageRaw?.src ?? ""), alt: String(imageRaw?.alt ?? "") },
|
|
47099
|
+
href: item.href != null ? String(item.href) : void 0,
|
|
47100
|
+
badge: item.badge != null ? String(item.badge) : void 0,
|
|
47101
|
+
accentColor: item.accentColor != null ? String(item.accentColor) : void 0
|
|
47102
|
+
},
|
|
47103
|
+
String(item.id ?? "")
|
|
47104
|
+
);
|
|
47105
|
+
}) })
|
|
46874
47106
|
] });
|
|
46875
47107
|
};
|
|
46876
47108
|
ShowcaseOrganism.displayName = "ShowcaseOrganism";
|
|
@@ -47238,8 +47470,8 @@ function SimulatorBoard({
|
|
|
47238
47470
|
}) {
|
|
47239
47471
|
const { emit } = useEventBus();
|
|
47240
47472
|
const { t } = hooks.useTranslate();
|
|
47241
|
-
const resolved =
|
|
47242
|
-
const parameters = resolved?.parameters
|
|
47473
|
+
const resolved = boardEntity(entity);
|
|
47474
|
+
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
47243
47475
|
const [values, setValues] = React97.useState(() => {
|
|
47244
47476
|
const init = {};
|
|
47245
47477
|
for (const p2 of parameters) {
|
|
@@ -47253,15 +47485,15 @@ function SimulatorBoard({
|
|
|
47253
47485
|
const [showHint, setShowHint] = React97.useState(false);
|
|
47254
47486
|
const computeOutput = React97.useCallback((params) => {
|
|
47255
47487
|
try {
|
|
47256
|
-
const fn = new Function("params", `return (${resolved?.computeExpression})`);
|
|
47488
|
+
const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
|
|
47257
47489
|
return fn(params);
|
|
47258
47490
|
} catch {
|
|
47259
47491
|
return 0;
|
|
47260
47492
|
}
|
|
47261
47493
|
}, [resolved?.computeExpression]);
|
|
47262
47494
|
const output = React97.useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
|
|
47263
|
-
const targetValue = resolved?.targetValue
|
|
47264
|
-
const targetTolerance = resolved?.targetTolerance
|
|
47495
|
+
const targetValue = num(resolved?.targetValue);
|
|
47496
|
+
const targetTolerance = num(resolved?.targetTolerance);
|
|
47265
47497
|
const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
|
|
47266
47498
|
const handleParameterChange = (id, value) => {
|
|
47267
47499
|
if (submitted) return;
|
|
@@ -47276,7 +47508,7 @@ function SimulatorBoard({
|
|
|
47276
47508
|
};
|
|
47277
47509
|
const handleReset = () => {
|
|
47278
47510
|
setSubmitted(false);
|
|
47279
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
47511
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
47280
47512
|
setShowHint(true);
|
|
47281
47513
|
}
|
|
47282
47514
|
};
|
|
@@ -47291,20 +47523,26 @@ function SimulatorBoard({
|
|
|
47291
47523
|
setShowHint(false);
|
|
47292
47524
|
};
|
|
47293
47525
|
if (!resolved) return null;
|
|
47526
|
+
const theme = resolved.theme ?? void 0;
|
|
47527
|
+
const themeBackground = theme?.background;
|
|
47528
|
+
const headerImage = str(resolved.headerImage);
|
|
47529
|
+
const hint = str(resolved.hint);
|
|
47530
|
+
const outputLabel = str(resolved.outputLabel);
|
|
47531
|
+
const outputUnit = str(resolved.outputUnit);
|
|
47294
47532
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
47295
47533
|
Box,
|
|
47296
47534
|
{
|
|
47297
47535
|
className,
|
|
47298
47536
|
style: {
|
|
47299
|
-
backgroundImage:
|
|
47537
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
47300
47538
|
backgroundSize: "cover",
|
|
47301
47539
|
backgroundPosition: "center"
|
|
47302
47540
|
},
|
|
47303
47541
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
47304
|
-
|
|
47542
|
+
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,
|
|
47305
47543
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
47306
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
47307
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
47544
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
47545
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
47308
47546
|
] }) }),
|
|
47309
47547
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
47310
47548
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
@@ -47345,28 +47583,28 @@ function SimulatorBoard({
|
|
|
47345
47583
|
] }, param.id))
|
|
47346
47584
|
] }) }),
|
|
47347
47585
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
47348
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children:
|
|
47586
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
47349
47587
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", weight: "bold", children: [
|
|
47350
47588
|
output.toFixed(2),
|
|
47351
47589
|
" ",
|
|
47352
|
-
|
|
47590
|
+
outputUnit
|
|
47353
47591
|
] }),
|
|
47354
47592
|
submitted && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
47355
47593
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: isCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
|
|
47356
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? resolved.successMessage
|
|
47594
|
+
/* @__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") })
|
|
47357
47595
|
] }),
|
|
47358
47596
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47359
47597
|
t("simulator.target"),
|
|
47360
47598
|
": ",
|
|
47361
47599
|
targetValue,
|
|
47362
47600
|
" ",
|
|
47363
|
-
|
|
47601
|
+
outputUnit,
|
|
47364
47602
|
" (\xB1",
|
|
47365
47603
|
targetTolerance,
|
|
47366
47604
|
")"
|
|
47367
47605
|
] })
|
|
47368
47606
|
] }) }),
|
|
47369
|
-
showHint &&
|
|
47607
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
47370
47608
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
47371
47609
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
|
|
47372
47610
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
@@ -47385,6 +47623,7 @@ var init_SimulatorBoard = __esm({
|
|
|
47385
47623
|
"components/game/organisms/puzzles/simulator/SimulatorBoard.tsx"() {
|
|
47386
47624
|
init_atoms2();
|
|
47387
47625
|
init_useEventBus();
|
|
47626
|
+
init_boardEntity();
|
|
47388
47627
|
SimulatorBoard.displayName = "SimulatorBoard";
|
|
47389
47628
|
}
|
|
47390
47629
|
});
|
|
@@ -47810,22 +48049,25 @@ function VariablePanel({
|
|
|
47810
48049
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-3 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
47811
48050
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
47812
48051
|
variables.map((v) => {
|
|
47813
|
-
const
|
|
47814
|
-
const
|
|
47815
|
-
const
|
|
48052
|
+
const name = v.name == null ? "" : String(v.name);
|
|
48053
|
+
const value = numField(v.value);
|
|
48054
|
+
const max = numField(v.max, 100);
|
|
48055
|
+
const min = numField(v.min, 0);
|
|
48056
|
+
const unit = v.unit == null ? "" : String(v.unit);
|
|
48057
|
+
const pct = Math.round((value - min) / (max - min) * 100);
|
|
47816
48058
|
const isHigh = pct > 80;
|
|
47817
48059
|
const isLow = pct < 20;
|
|
47818
48060
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
47819
48061
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
47820
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children:
|
|
48062
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children: name }),
|
|
47821
48063
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: cn(
|
|
47822
48064
|
isHigh ? "text-error" : isLow ? "text-warning" : "text-foreground"
|
|
47823
48065
|
), children: [
|
|
47824
|
-
|
|
47825
|
-
|
|
48066
|
+
value,
|
|
48067
|
+
unit,
|
|
47826
48068
|
" / ",
|
|
47827
48069
|
max,
|
|
47828
|
-
|
|
48070
|
+
unit
|
|
47829
48071
|
] })
|
|
47830
48072
|
] }),
|
|
47831
48073
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -47836,14 +48078,19 @@ function VariablePanel({
|
|
|
47836
48078
|
size: "sm"
|
|
47837
48079
|
}
|
|
47838
48080
|
)
|
|
47839
|
-
] },
|
|
48081
|
+
] }, name);
|
|
47840
48082
|
})
|
|
47841
48083
|
] });
|
|
47842
48084
|
}
|
|
48085
|
+
var numField;
|
|
47843
48086
|
var init_VariablePanel = __esm({
|
|
47844
48087
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
47845
48088
|
init_atoms2();
|
|
47846
48089
|
init_cn();
|
|
48090
|
+
numField = (v, fallback = 0) => {
|
|
48091
|
+
const n = Number(v);
|
|
48092
|
+
return Number.isFinite(n) ? n : fallback;
|
|
48093
|
+
};
|
|
47847
48094
|
VariablePanel.displayName = "VariablePanel";
|
|
47848
48095
|
}
|
|
47849
48096
|
});
|
|
@@ -47870,14 +48117,21 @@ function StateArchitectBoard({
|
|
|
47870
48117
|
}) {
|
|
47871
48118
|
const { emit } = useEventBus();
|
|
47872
48119
|
const { t } = hooks.useTranslate();
|
|
47873
|
-
const resolved =
|
|
47874
|
-
const
|
|
48120
|
+
const resolved = boardEntity(entity);
|
|
48121
|
+
const entityStates = Array.isArray(resolved?.states) ? resolved.states : [];
|
|
48122
|
+
const initialState = str(resolved?.initialState);
|
|
48123
|
+
const entityName = str(resolved?.entityName);
|
|
48124
|
+
const availableEvents = Array.isArray(resolved?.availableEvents) ? resolved.availableEvents : [];
|
|
48125
|
+
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
48126
|
+
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
48127
|
+
const entityVariables = rows(resolved?.variables);
|
|
48128
|
+
const [transitions, setTransitions] = React97.useState(entityTransitions);
|
|
47875
48129
|
const [headerError, setHeaderError] = React97.useState(false);
|
|
47876
48130
|
const [playState, setPlayState] = React97.useState("editing");
|
|
47877
|
-
const [currentState, setCurrentState] = React97.useState(
|
|
48131
|
+
const [currentState, setCurrentState] = React97.useState(initialState);
|
|
47878
48132
|
const [selectedState, setSelectedState] = React97.useState(null);
|
|
47879
48133
|
const [testResults, setTestResults] = React97.useState([]);
|
|
47880
|
-
const [variables, setVariables] = React97.useState(
|
|
48134
|
+
const [variables, setVariables] = React97.useState(() => [...entityVariables]);
|
|
47881
48135
|
const [attempts, setAttempts] = React97.useState(0);
|
|
47882
48136
|
const timerRef = React97.useRef(null);
|
|
47883
48137
|
const [addingFrom, setAddingFrom] = React97.useState(null);
|
|
@@ -47886,12 +48140,12 @@ function StateArchitectBoard({
|
|
|
47886
48140
|
}, []);
|
|
47887
48141
|
const GRAPH_W = 500;
|
|
47888
48142
|
const GRAPH_H = 400;
|
|
47889
|
-
const positions = React97.useMemo(() => layoutStates(
|
|
48143
|
+
const positions = React97.useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
47890
48144
|
const handleStateClick = React97.useCallback((state) => {
|
|
47891
48145
|
if (playState !== "editing") return;
|
|
47892
48146
|
if (addingFrom) {
|
|
47893
48147
|
if (addingFrom !== state) {
|
|
47894
|
-
const event =
|
|
48148
|
+
const event = availableEvents[0] || "EVENT";
|
|
47895
48149
|
const newTrans = {
|
|
47896
48150
|
id: `t-${nextTransId++}`,
|
|
47897
48151
|
from: addingFrom,
|
|
@@ -47904,7 +48158,7 @@ function StateArchitectBoard({
|
|
|
47904
48158
|
} else {
|
|
47905
48159
|
setSelectedState(state);
|
|
47906
48160
|
}
|
|
47907
|
-
}, [playState, addingFrom,
|
|
48161
|
+
}, [playState, addingFrom, availableEvents]);
|
|
47908
48162
|
const handleStartAddTransition = React97.useCallback(() => {
|
|
47909
48163
|
if (!selectedState) return;
|
|
47910
48164
|
setAddingFrom(selectedState);
|
|
@@ -47913,9 +48167,9 @@ function StateArchitectBoard({
|
|
|
47913
48167
|
setTransitions((prev) => prev.filter((t2) => t2.id !== transId));
|
|
47914
48168
|
}, []);
|
|
47915
48169
|
const machine = React97.useMemo(() => ({
|
|
47916
|
-
name:
|
|
47917
|
-
description: resolved?.description
|
|
47918
|
-
states:
|
|
48170
|
+
name: entityName,
|
|
48171
|
+
description: str(resolved?.description),
|
|
48172
|
+
states: entityStates,
|
|
47919
48173
|
currentState,
|
|
47920
48174
|
transitions: transitions.map((t2) => ({
|
|
47921
48175
|
from: t2.from,
|
|
@@ -47923,7 +48177,7 @@ function StateArchitectBoard({
|
|
|
47923
48177
|
event: t2.event,
|
|
47924
48178
|
guardHint: t2.guardHint
|
|
47925
48179
|
}))
|
|
47926
|
-
}), [resolved, currentState, transitions]);
|
|
48180
|
+
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
47927
48181
|
const handleTest = React97.useCallback(() => {
|
|
47928
48182
|
if (playState !== "editing") return;
|
|
47929
48183
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
@@ -47932,7 +48186,7 @@ function StateArchitectBoard({
|
|
|
47932
48186
|
const results = [];
|
|
47933
48187
|
let testIdx = 0;
|
|
47934
48188
|
const runNextTest = () => {
|
|
47935
|
-
if (testIdx >=
|
|
48189
|
+
if (testIdx >= testCases.length) {
|
|
47936
48190
|
const allPassed = results.every((r2) => r2.passed);
|
|
47937
48191
|
setPlayState(allPassed ? "success" : "fail");
|
|
47938
48192
|
setTestResults(results);
|
|
@@ -47947,9 +48201,9 @@ function StateArchitectBoard({
|
|
|
47947
48201
|
}
|
|
47948
48202
|
return;
|
|
47949
48203
|
}
|
|
47950
|
-
const testCase =
|
|
48204
|
+
const testCase = testCases[testIdx];
|
|
47951
48205
|
if (!testCase) return;
|
|
47952
|
-
let state =
|
|
48206
|
+
let state = initialState;
|
|
47953
48207
|
for (const event of testCase.events) {
|
|
47954
48208
|
const trans = transitions.find((t2) => t2.from === state && t2.event === event);
|
|
47955
48209
|
if (trans) {
|
|
@@ -47967,53 +48221,57 @@ function StateArchitectBoard({
|
|
|
47967
48221
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
47968
48222
|
};
|
|
47969
48223
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
47970
|
-
}, [playState, transitions,
|
|
48224
|
+
}, [playState, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
47971
48225
|
const handleTryAgain = React97.useCallback(() => {
|
|
47972
48226
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
47973
48227
|
setPlayState("editing");
|
|
47974
|
-
setCurrentState(
|
|
48228
|
+
setCurrentState(initialState);
|
|
47975
48229
|
setTestResults([]);
|
|
47976
|
-
}, [
|
|
48230
|
+
}, [initialState]);
|
|
47977
48231
|
const handleReset = React97.useCallback(() => {
|
|
47978
48232
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
47979
|
-
setTransitions(
|
|
48233
|
+
setTransitions(entityTransitions);
|
|
47980
48234
|
setPlayState("editing");
|
|
47981
|
-
setCurrentState(
|
|
48235
|
+
setCurrentState(initialState);
|
|
47982
48236
|
setTestResults([]);
|
|
47983
|
-
setVariables(
|
|
48237
|
+
setVariables([...entityVariables]);
|
|
47984
48238
|
setSelectedState(null);
|
|
47985
48239
|
setAddingFrom(null);
|
|
47986
48240
|
setAttempts(0);
|
|
47987
|
-
}, [
|
|
48241
|
+
}, [entityTransitions, initialState, entityVariables]);
|
|
47988
48242
|
const codeData = React97.useMemo(() => ({
|
|
47989
|
-
name:
|
|
47990
|
-
states:
|
|
47991
|
-
initialState
|
|
48243
|
+
name: entityName,
|
|
48244
|
+
states: entityStates,
|
|
48245
|
+
initialState,
|
|
47992
48246
|
transitions: transitions.map((t2) => ({
|
|
47993
48247
|
from: t2.from,
|
|
47994
48248
|
to: t2.to,
|
|
47995
48249
|
event: t2.event,
|
|
47996
48250
|
...t2.guardHint ? { guard: t2.guardHint } : {}
|
|
47997
48251
|
}))
|
|
47998
|
-
}), [
|
|
48252
|
+
}), [entityName, entityStates, initialState, transitions]);
|
|
47999
48253
|
if (!resolved) return null;
|
|
48254
|
+
const theme = resolved.theme ?? void 0;
|
|
48255
|
+
const themeBackground = theme?.background;
|
|
48256
|
+
const headerImage = str(resolved.headerImage);
|
|
48257
|
+
const hint = str(resolved.hint);
|
|
48000
48258
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
48001
48259
|
VStack,
|
|
48002
48260
|
{
|
|
48003
48261
|
className: cn("p-4 gap-6", className),
|
|
48004
48262
|
style: {
|
|
48005
|
-
backgroundImage:
|
|
48263
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
48006
48264
|
backgroundSize: "cover",
|
|
48007
48265
|
backgroundPosition: "center"
|
|
48008
48266
|
},
|
|
48009
48267
|
children: [
|
|
48010
|
-
|
|
48268
|
+
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,
|
|
48011
48269
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
48012
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
48013
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
48270
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
48271
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
48014
48272
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
|
|
48015
48273
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
|
|
48016
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children:
|
|
48274
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: hint })
|
|
48017
48275
|
] })
|
|
48018
48276
|
] }),
|
|
48019
48277
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
|
|
@@ -48061,14 +48319,14 @@ function StateArchitectBoard({
|
|
|
48061
48319
|
]
|
|
48062
48320
|
}
|
|
48063
48321
|
),
|
|
48064
|
-
|
|
48322
|
+
entityStates.map((state) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
48065
48323
|
StateNode2,
|
|
48066
48324
|
{
|
|
48067
48325
|
name: state,
|
|
48068
48326
|
position: positions[state],
|
|
48069
48327
|
isCurrent: state === currentState,
|
|
48070
48328
|
isSelected: state === selectedState,
|
|
48071
|
-
isInitial: state ===
|
|
48329
|
+
isInitial: state === initialState,
|
|
48072
48330
|
onClick: () => handleStateClick(state)
|
|
48073
48331
|
},
|
|
48074
48332
|
state
|
|
@@ -48115,7 +48373,7 @@ function StateArchitectBoard({
|
|
|
48115
48373
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
48116
48374
|
VariablePanel,
|
|
48117
48375
|
{
|
|
48118
|
-
entityName
|
|
48376
|
+
entityName,
|
|
48119
48377
|
variables
|
|
48120
48378
|
}
|
|
48121
48379
|
),
|
|
@@ -48130,12 +48388,12 @@ function StateArchitectBoard({
|
|
|
48130
48388
|
resolved.showCodeView !== false && /* @__PURE__ */ jsxRuntime.jsx(CodeView, { data: codeData, label: "View Code" })
|
|
48131
48389
|
] })
|
|
48132
48390
|
] }),
|
|
48133
|
-
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") }) }),
|
|
48391
|
+
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") }) }),
|
|
48134
48392
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
48135
48393
|
/* @__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]) }) }),
|
|
48136
|
-
attempts >= 3 &&
|
|
48394
|
+
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: [
|
|
48137
48395
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
48138
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
48396
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
48139
48397
|
] }) })
|
|
48140
48398
|
] }),
|
|
48141
48399
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -48165,6 +48423,7 @@ var init_StateArchitectBoard = __esm({
|
|
|
48165
48423
|
init_TransitionArrow();
|
|
48166
48424
|
init_VariablePanel();
|
|
48167
48425
|
init_CodeView();
|
|
48426
|
+
init_boardEntity();
|
|
48168
48427
|
ENCOURAGEMENT_KEYS3 = [
|
|
48169
48428
|
"puzzle.tryAgain1",
|
|
48170
48429
|
"puzzle.tryAgain2",
|
|
@@ -48201,8 +48460,8 @@ var init_StatsOrganism = __esm({
|
|
|
48201
48460
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
48202
48461
|
}
|
|
48203
48462
|
const stats = items.map((item) => ({
|
|
48204
|
-
value: item.value,
|
|
48205
|
-
label: item.label
|
|
48463
|
+
value: String(item.value ?? ""),
|
|
48464
|
+
label: String(item.label ?? "")
|
|
48206
48465
|
}));
|
|
48207
48466
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
48208
48467
|
StatsGrid,
|
|
@@ -48248,10 +48507,10 @@ var init_StepFlowOrganism = __esm({
|
|
|
48248
48507
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
48249
48508
|
}
|
|
48250
48509
|
const steps = items.map((item) => ({
|
|
48251
|
-
number: item.number,
|
|
48252
|
-
title: item.title,
|
|
48253
|
-
description: item.description,
|
|
48254
|
-
icon: item.icon
|
|
48510
|
+
number: item.number != null ? Number(item.number) : void 0,
|
|
48511
|
+
title: String(item.title ?? ""),
|
|
48512
|
+
description: String(item.description ?? ""),
|
|
48513
|
+
icon: item.icon != null ? String(item.icon) : void 0
|
|
48255
48514
|
}));
|
|
48256
48515
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
48257
48516
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -48424,13 +48683,13 @@ var init_TeamOrganism = __esm({
|
|
|
48424
48683
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((member) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
48425
48684
|
TeamCard,
|
|
48426
48685
|
{
|
|
48427
|
-
name: member.name,
|
|
48428
|
-
nameAr: member.nameAr,
|
|
48429
|
-
role: member.role,
|
|
48430
|
-
bio: member.bio,
|
|
48431
|
-
avatar: member.avatar
|
|
48686
|
+
name: String(member.name ?? ""),
|
|
48687
|
+
nameAr: member.nameAr != null ? String(member.nameAr) : void 0,
|
|
48688
|
+
role: String(member.role ?? ""),
|
|
48689
|
+
bio: String(member.bio ?? ""),
|
|
48690
|
+
avatar: member.avatar != null ? String(member.avatar) : void 0
|
|
48432
48691
|
},
|
|
48433
|
-
member.id
|
|
48692
|
+
String(member.id ?? "")
|
|
48434
48693
|
)) })
|
|
48435
48694
|
] });
|
|
48436
48695
|
};
|
|
@@ -48667,8 +48926,8 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
48667
48926
|
const [turn, setTurn] = React97.useState(1);
|
|
48668
48927
|
const [gameResult, setGameResult] = React97.useState(null);
|
|
48669
48928
|
const checkGameEnd = React97.useCallback((currentUnits) => {
|
|
48670
|
-
const pa = currentUnits.filter((u) => u
|
|
48671
|
-
const ea = currentUnits.filter((u) => u
|
|
48929
|
+
const pa = currentUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
48930
|
+
const ea = currentUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
48672
48931
|
if (pa.length === 0) {
|
|
48673
48932
|
setGameResult("defeat");
|
|
48674
48933
|
setPhase("game_over");
|
|
@@ -48686,34 +48945,36 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
48686
48945
|
}
|
|
48687
48946
|
}, [onGameEnd, gameEndEvent, eventBus]);
|
|
48688
48947
|
const handleUnitClick = React97.useCallback((unitId) => {
|
|
48689
|
-
const unit = units.find((u) => u.id === unitId);
|
|
48948
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
48690
48949
|
if (!unit) return;
|
|
48691
48950
|
if (unitClickEvent) {
|
|
48692
48951
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
48693
48952
|
}
|
|
48694
48953
|
if (phase === "observation" || phase === "selection") {
|
|
48695
|
-
if (unit
|
|
48954
|
+
if (unitTeam(unit) === "player") {
|
|
48696
48955
|
setSelectedUnitId(unitId);
|
|
48697
48956
|
setPhase("movement");
|
|
48698
48957
|
}
|
|
48699
48958
|
} else if (phase === "action") {
|
|
48700
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
48959
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
48701
48960
|
if (!selectedUnit) return;
|
|
48702
|
-
if (unit
|
|
48703
|
-
const
|
|
48704
|
-
const
|
|
48961
|
+
if (unitTeam(unit) === "enemy") {
|
|
48962
|
+
const up = unitPosition(unit);
|
|
48963
|
+
const sp = unitPosition(selectedUnit);
|
|
48964
|
+
const dx = Math.abs(up.x - sp.x);
|
|
48965
|
+
const dy = Math.abs(up.y - sp.y);
|
|
48705
48966
|
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
48706
|
-
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
|
|
48707
|
-
const newHealth = Math.max(0, unit
|
|
48967
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
48968
|
+
const newHealth = Math.max(0, unitHealth(unit) - damage);
|
|
48708
48969
|
const updatedUnits = units.map(
|
|
48709
|
-
(u) => u.id === unit.id ? { ...u, health: newHealth } : u
|
|
48970
|
+
(u) => str(u.id) === str(unit.id) ? { ...u, health: newHealth } : u
|
|
48710
48971
|
);
|
|
48711
48972
|
setUnits(updatedUnits);
|
|
48712
48973
|
onAttack?.(selectedUnit, unit, damage);
|
|
48713
48974
|
if (attackEvent) {
|
|
48714
48975
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
48715
|
-
attackerId: selectedUnit.id,
|
|
48716
|
-
targetId: unit.id,
|
|
48976
|
+
attackerId: str(selectedUnit.id),
|
|
48977
|
+
targetId: str(unit.id),
|
|
48717
48978
|
damage
|
|
48718
48979
|
});
|
|
48719
48980
|
}
|
|
@@ -48730,16 +48991,20 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
48730
48991
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
48731
48992
|
}
|
|
48732
48993
|
if (phase === "movement" && selectedUnitId) {
|
|
48733
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
48994
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
48734
48995
|
if (!selectedUnit) return;
|
|
48735
|
-
const
|
|
48736
|
-
const
|
|
48996
|
+
const sp = unitPosition(selectedUnit);
|
|
48997
|
+
const dx = Math.abs(x - sp.x);
|
|
48998
|
+
const dy = Math.abs(y - sp.y);
|
|
48737
48999
|
const dist = dx + dy;
|
|
48738
|
-
if (dist > 0 && dist <= selectedUnit.movement) {
|
|
48739
|
-
if (!units.some((u) =>
|
|
49000
|
+
if (dist > 0 && dist <= num(selectedUnit.movement)) {
|
|
49001
|
+
if (!units.some((u) => {
|
|
49002
|
+
const p2 = unitPosition(u);
|
|
49003
|
+
return p2.x === x && p2.y === y && unitHealth(u) > 0;
|
|
49004
|
+
})) {
|
|
48740
49005
|
setUnits(
|
|
48741
49006
|
(prev) => prev.map(
|
|
48742
|
-
(u) => u.id === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
49007
|
+
(u) => str(u.id) === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
48743
49008
|
)
|
|
48744
49009
|
);
|
|
48745
49010
|
setPhase("action");
|
|
@@ -48782,12 +49047,13 @@ var init_useBattleState = __esm({
|
|
|
48782
49047
|
"components/game/organisms/hooks/useBattleState.ts"() {
|
|
48783
49048
|
"use client";
|
|
48784
49049
|
init_useEventBus();
|
|
49050
|
+
init_boardEntity();
|
|
48785
49051
|
}
|
|
48786
49052
|
});
|
|
48787
49053
|
function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
48788
|
-
const resolved =
|
|
49054
|
+
const resolved = boardEntity(entity);
|
|
48789
49055
|
const battleState = useBattleState(
|
|
48790
|
-
resolved?.initialUnits
|
|
49056
|
+
rows(resolved?.initialUnits),
|
|
48791
49057
|
{
|
|
48792
49058
|
tileClickEvent: rest.tileClickEvent,
|
|
48793
49059
|
unitClickEvent: rest.unitClickEvent,
|
|
@@ -48823,10 +49089,23 @@ function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
|
48823
49089
|
var init_UncontrolledBattleBoard = __esm({
|
|
48824
49090
|
"components/game/organisms/UncontrolledBattleBoard.tsx"() {
|
|
48825
49091
|
init_BattleBoard();
|
|
49092
|
+
init_boardEntity();
|
|
48826
49093
|
init_useBattleState();
|
|
48827
49094
|
UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
|
|
48828
49095
|
}
|
|
48829
49096
|
});
|
|
49097
|
+
function heroPosition(h) {
|
|
49098
|
+
return vec2(h.position);
|
|
49099
|
+
}
|
|
49100
|
+
function heroOwner(h) {
|
|
49101
|
+
return str(h.owner);
|
|
49102
|
+
}
|
|
49103
|
+
function heroMovement(h) {
|
|
49104
|
+
return num(h.movement);
|
|
49105
|
+
}
|
|
49106
|
+
function hexPassable(h) {
|
|
49107
|
+
return h.passable !== false;
|
|
49108
|
+
}
|
|
48830
49109
|
function defaultIsInRange(from, to, range) {
|
|
48831
49110
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
48832
49111
|
}
|
|
@@ -48857,36 +49136,36 @@ function WorldMapBoard({
|
|
|
48857
49136
|
className
|
|
48858
49137
|
}) {
|
|
48859
49138
|
const eventBus = useEventBus();
|
|
48860
|
-
const resolved =
|
|
48861
|
-
const hexes = resolved?.hexes
|
|
48862
|
-
const heroes = resolved?.heroes
|
|
48863
|
-
const features = resolved?.features
|
|
48864
|
-
const selectedHeroId = resolved?.selectedHeroId;
|
|
49139
|
+
const resolved = boardEntity(entity);
|
|
49140
|
+
const hexes = rows(resolved?.hexes);
|
|
49141
|
+
const heroes = rows(resolved?.heroes);
|
|
49142
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
49143
|
+
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
48865
49144
|
const assetManifest = resolved?.assetManifest;
|
|
48866
49145
|
const backgroundImage = resolved?.backgroundImage;
|
|
48867
49146
|
const [hoveredTile, setHoveredTile] = React97.useState(null);
|
|
48868
49147
|
const selectedHero = React97.useMemo(
|
|
48869
|
-
() => heroes.find((h) => h.id === selectedHeroId) ?? null,
|
|
49148
|
+
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
48870
49149
|
[heroes, selectedHeroId]
|
|
48871
49150
|
);
|
|
48872
49151
|
const tiles = React97.useMemo(
|
|
48873
49152
|
() => hexes.map((hex) => ({
|
|
48874
|
-
x: hex.x,
|
|
48875
|
-
y: hex.y,
|
|
48876
|
-
terrain: hex.terrain,
|
|
48877
|
-
terrainSprite: hex.terrainSprite
|
|
49153
|
+
x: num(hex.x),
|
|
49154
|
+
y: num(hex.y),
|
|
49155
|
+
terrain: str(hex.terrain),
|
|
49156
|
+
terrainSprite: hex.terrainSprite == null ? void 0 : str(hex.terrainSprite)
|
|
48878
49157
|
})),
|
|
48879
49158
|
[hexes]
|
|
48880
49159
|
);
|
|
48881
49160
|
const baseUnits = React97.useMemo(
|
|
48882
49161
|
() => heroes.map((hero) => ({
|
|
48883
|
-
id: hero.id,
|
|
48884
|
-
position: hero
|
|
48885
|
-
name: hero.name,
|
|
48886
|
-
team: hero
|
|
49162
|
+
id: str(hero.id),
|
|
49163
|
+
position: heroPosition(hero),
|
|
49164
|
+
name: str(hero.name),
|
|
49165
|
+
team: heroOwner(hero) === "enemy" ? "enemy" : "player",
|
|
48887
49166
|
health: 100,
|
|
48888
49167
|
maxHealth: 100,
|
|
48889
|
-
sprite: hero.sprite
|
|
49168
|
+
sprite: hero.sprite == null ? void 0 : str(hero.sprite)
|
|
48890
49169
|
})),
|
|
48891
49170
|
[heroes]
|
|
48892
49171
|
);
|
|
@@ -48927,73 +49206,94 @@ function WorldMapBoard({
|
|
|
48927
49206
|
const isoUnits = React97.useMemo(() => {
|
|
48928
49207
|
if (movingPositions.size === 0) return baseUnits;
|
|
48929
49208
|
return baseUnits.map((u) => {
|
|
48930
|
-
const pos = movingPositions.get(u.id);
|
|
49209
|
+
const pos = u.id == null ? void 0 : movingPositions.get(u.id);
|
|
48931
49210
|
return pos ? { ...u, position: pos } : u;
|
|
48932
49211
|
});
|
|
48933
49212
|
}, [baseUnits, movingPositions]);
|
|
48934
49213
|
const validMoves = React97.useMemo(() => {
|
|
48935
|
-
if (!selectedHero || selectedHero
|
|
49214
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
49215
|
+
const sp = heroPosition(selectedHero);
|
|
49216
|
+
const sOwner = heroOwner(selectedHero);
|
|
49217
|
+
const range = heroMovement(selectedHero);
|
|
48936
49218
|
const moves = [];
|
|
48937
49219
|
hexes.forEach((hex) => {
|
|
48938
|
-
|
|
48939
|
-
|
|
48940
|
-
if (!
|
|
48941
|
-
if (
|
|
48942
|
-
|
|
49220
|
+
const hx = num(hex.x);
|
|
49221
|
+
const hy = num(hex.y);
|
|
49222
|
+
if (!hexPassable(hex)) return;
|
|
49223
|
+
if (hx === sp.x && hy === sp.y) return;
|
|
49224
|
+
if (!isInRange(sp, { x: hx, y: hy }, range)) return;
|
|
49225
|
+
if (heroes.some((h) => {
|
|
49226
|
+
const hp = heroPosition(h);
|
|
49227
|
+
return hp.x === hx && hp.y === hy && heroOwner(h) === sOwner;
|
|
49228
|
+
})) return;
|
|
49229
|
+
moves.push({ x: hx, y: hy });
|
|
48943
49230
|
});
|
|
48944
49231
|
return moves;
|
|
48945
49232
|
}, [selectedHero, hexes, heroes, isInRange]);
|
|
48946
49233
|
const attackTargets = React97.useMemo(() => {
|
|
48947
|
-
if (!selectedHero || selectedHero
|
|
48948
|
-
|
|
49234
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
49235
|
+
const sp = heroPosition(selectedHero);
|
|
49236
|
+
const sOwner = heroOwner(selectedHero);
|
|
49237
|
+
const range = heroMovement(selectedHero);
|
|
49238
|
+
return heroes.filter((h) => heroOwner(h) !== sOwner).filter((h) => isInRange(sp, heroPosition(h), range)).map((h) => heroPosition(h));
|
|
48949
49239
|
}, [selectedHero, heroes, isInRange]);
|
|
48950
|
-
const maxY = Math.max(...hexes.map((h) => h.y), 0);
|
|
49240
|
+
const maxY = Math.max(...hexes.map((h) => num(h.y)), 0);
|
|
48951
49241
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
48952
49242
|
const tileToScreen = React97.useCallback(
|
|
48953
49243
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
48954
49244
|
[scale, baseOffsetX]
|
|
48955
49245
|
);
|
|
48956
49246
|
const hoveredHex = React97.useMemo(
|
|
48957
|
-
() => hoveredTile ? hexes.find((h) => h.x === hoveredTile.x && h.y === hoveredTile.y) ?? null : null,
|
|
49247
|
+
() => hoveredTile ? hexes.find((h) => num(h.x) === hoveredTile.x && num(h.y) === hoveredTile.y) ?? null : null,
|
|
48958
49248
|
[hoveredTile, hexes]
|
|
48959
49249
|
);
|
|
48960
49250
|
const hoveredHero = React97.useMemo(
|
|
48961
|
-
() => hoveredTile ? heroes.find((h) =>
|
|
49251
|
+
() => hoveredTile ? heroes.find((h) => {
|
|
49252
|
+
const hp = heroPosition(h);
|
|
49253
|
+
return hp.x === hoveredTile.x && hp.y === hoveredTile.y;
|
|
49254
|
+
}) ?? null : null,
|
|
48962
49255
|
[hoveredTile, heroes]
|
|
48963
49256
|
);
|
|
48964
49257
|
const handleTileClick = React97.useCallback((x, y) => {
|
|
48965
49258
|
if (movementAnimRef.current) return;
|
|
48966
|
-
const hex = hexes.find((h) => h.x === x && h.y === y);
|
|
49259
|
+
const hex = hexes.find((h) => num(h.x) === x && num(h.y) === y);
|
|
48967
49260
|
if (!hex) return;
|
|
48968
49261
|
if (tileClickEvent) {
|
|
48969
49262
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
48970
49263
|
}
|
|
48971
49264
|
if (selectedHero && validMoves.some((m) => m.x === x && m.y === y)) {
|
|
48972
|
-
|
|
48973
|
-
|
|
49265
|
+
const heroId = str(selectedHero.id);
|
|
49266
|
+
startMoveAnimation(heroId, { ...heroPosition(selectedHero) }, { x, y }, () => {
|
|
49267
|
+
onHeroMove?.(heroId, x, y);
|
|
48974
49268
|
if (heroMoveEvent) {
|
|
48975
|
-
eventBus.emit(`UI:${heroMoveEvent}`, { heroId
|
|
49269
|
+
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
48976
49270
|
}
|
|
48977
|
-
|
|
48978
|
-
|
|
49271
|
+
const feature = str(hex.feature);
|
|
49272
|
+
if (feature && feature !== "none") {
|
|
49273
|
+
onFeatureEnter?.(heroId, hex);
|
|
48979
49274
|
if (featureEnterEvent) {
|
|
48980
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId
|
|
49275
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
48981
49276
|
}
|
|
48982
49277
|
}
|
|
48983
49278
|
});
|
|
48984
49279
|
return;
|
|
48985
49280
|
}
|
|
48986
|
-
const enemy = heroes.find((h) =>
|
|
49281
|
+
const enemy = heroes.find((h) => {
|
|
49282
|
+
const hp = heroPosition(h);
|
|
49283
|
+
return hp.x === x && hp.y === y && heroOwner(h) === "enemy";
|
|
49284
|
+
});
|
|
48987
49285
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
48988
|
-
|
|
49286
|
+
const attackerId = str(selectedHero.id);
|
|
49287
|
+
const defenderId = str(enemy.id);
|
|
49288
|
+
onBattleEncounter?.(attackerId, defenderId);
|
|
48989
49289
|
if (battleEncounterEvent) {
|
|
48990
|
-
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId
|
|
49290
|
+
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
48991
49291
|
}
|
|
48992
49292
|
}
|
|
48993
49293
|
}, [hexes, heroes, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
48994
49294
|
const handleUnitClick = React97.useCallback((unitId) => {
|
|
48995
|
-
const hero = heroes.find((h) => h.id === unitId);
|
|
48996
|
-
if (hero && (hero
|
|
49295
|
+
const hero = heroes.find((h) => str(h.id) === unitId);
|
|
49296
|
+
if (hero && (heroOwner(hero) === "player" || allowMoveAllHeroes)) {
|
|
48997
49297
|
onHeroSelect?.(unitId);
|
|
48998
49298
|
if (heroSelectEvent) {
|
|
48999
49299
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
@@ -49066,6 +49366,7 @@ var init_WorldMapBoard = __esm({
|
|
|
49066
49366
|
init_Stack();
|
|
49067
49367
|
init_LoadingState();
|
|
49068
49368
|
init_IsometricCanvas2();
|
|
49369
|
+
init_boardEntity();
|
|
49069
49370
|
init_isometric();
|
|
49070
49371
|
WorldMapBoard.displayName = "WorldMapBoard";
|
|
49071
49372
|
}
|
|
@@ -52629,10 +52930,10 @@ function parseApplicationLevel(schema) {
|
|
|
52629
52930
|
}
|
|
52630
52931
|
const count = schema.orbitals.length;
|
|
52631
52932
|
const cols = Math.ceil(Math.sqrt(count));
|
|
52632
|
-
const
|
|
52933
|
+
const rows2 = Math.ceil(count / cols);
|
|
52633
52934
|
const spacing = 200;
|
|
52634
52935
|
const gridW = cols * spacing;
|
|
52635
|
-
const gridH =
|
|
52936
|
+
const gridH = rows2 * spacing;
|
|
52636
52937
|
const originX = (600 - gridW) / 2 + spacing / 2;
|
|
52637
52938
|
const originY = (400 - gridH) / 2 + spacing / 2;
|
|
52638
52939
|
schema.orbitals.forEach((orbital, i) => {
|
|
@@ -55774,11 +56075,11 @@ function buildMockData(schema) {
|
|
|
55774
56075
|
result[entityName] = entity.instances;
|
|
55775
56076
|
continue;
|
|
55776
56077
|
}
|
|
55777
|
-
const
|
|
56078
|
+
const rows2 = Array.from(
|
|
55778
56079
|
{ length: 10 },
|
|
55779
56080
|
(_, i) => generateEntityRow(entity, i + 1)
|
|
55780
56081
|
);
|
|
55781
|
-
result[entityName] =
|
|
56082
|
+
result[entityName] = rows2;
|
|
55782
56083
|
}
|
|
55783
56084
|
for (const orbital of schema.orbitals) {
|
|
55784
56085
|
for (const traitRef of orbital.traits ?? []) {
|
|
@@ -59277,18 +59578,18 @@ function layoutOrbitals(count, containerW, containerH) {
|
|
|
59277
59578
|
if (count === 0) return [];
|
|
59278
59579
|
if (count === 1) return [{ cx: containerW / 2, cy: containerH / 2 }];
|
|
59279
59580
|
const cols = Math.min(count, Math.ceil(Math.sqrt(count)));
|
|
59280
|
-
const
|
|
59581
|
+
const rows2 = Math.ceil(count / cols);
|
|
59281
59582
|
const edgePad = 24;
|
|
59282
59583
|
const fitMinCx = UNIT_DISPLAY_W / 2 + edgePad;
|
|
59283
59584
|
const fitMinCy = UNIT_DISPLAY_H / 2 + edgePad;
|
|
59284
59585
|
const fitMaxCx = Math.max(fitMinCx, containerW - UNIT_DISPLAY_W / 2 - edgePad);
|
|
59285
59586
|
const fitMaxCy = Math.max(fitMinCy, containerH - UNIT_DISPLAY_H / 2 - edgePad);
|
|
59286
59587
|
const fitStepX = cols > 1 ? (fitMaxCx - fitMinCx) / (cols - 1) : 0;
|
|
59287
|
-
const fitStepY =
|
|
59588
|
+
const fitStepY = rows2 > 1 ? (fitMaxCy - fitMinCy) / (rows2 - 1) : 0;
|
|
59288
59589
|
const stepX = Math.min(fitStepX, UNIT_DISPLAY_W * 3.5);
|
|
59289
59590
|
const stepY = Math.min(fitStepY, UNIT_DISPLAY_H * 3.5);
|
|
59290
59591
|
const gridW = (cols - 1) * stepX;
|
|
59291
|
-
const gridH = (
|
|
59592
|
+
const gridH = (rows2 - 1) * stepY;
|
|
59292
59593
|
const originX = (containerW - gridW) / 2;
|
|
59293
59594
|
const originY = (containerH - gridH) / 2;
|
|
59294
59595
|
return Array.from({ length: count }, (_, i) => ({
|