@almadar/ui 5.21.12 → 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 +919 -631
- package/dist/avl/index.js +919 -631
- 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 +2016 -1668
- package/dist/components/index.js +1128 -780
- 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 +912 -624
- package/dist/providers/index.js +912 -624
- package/dist/runtime/index.cjs +914 -626
- package/dist/runtime/index.js +914 -626
- package/package.json +2 -2
package/dist/providers/index.cjs
CHANGED
|
@@ -2767,7 +2767,7 @@ var init_SvgGrid = __esm({
|
|
|
2767
2767
|
x,
|
|
2768
2768
|
y,
|
|
2769
2769
|
cols = 4,
|
|
2770
|
-
rows = 3,
|
|
2770
|
+
rows: rows2 = 3,
|
|
2771
2771
|
spacing = 20,
|
|
2772
2772
|
nodeRadius = 3,
|
|
2773
2773
|
color = "var(--color-primary)",
|
|
@@ -2776,7 +2776,7 @@ var init_SvgGrid = __esm({
|
|
|
2776
2776
|
highlights = []
|
|
2777
2777
|
}) => {
|
|
2778
2778
|
const highlightSet = new Set(highlights);
|
|
2779
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length:
|
|
2779
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length: rows2 }).map(
|
|
2780
2780
|
(_, row) => Array.from({ length: cols }).map((_2, col) => {
|
|
2781
2781
|
const index = row * cols + col;
|
|
2782
2782
|
const isHighlighted = highlightSet.has(index);
|
|
@@ -3436,7 +3436,7 @@ var init_Input = __esm({
|
|
|
3436
3436
|
onClear,
|
|
3437
3437
|
value,
|
|
3438
3438
|
options,
|
|
3439
|
-
rows = 3,
|
|
3439
|
+
rows: rows2 = 3,
|
|
3440
3440
|
onChange,
|
|
3441
3441
|
...props
|
|
3442
3442
|
}, ref) => {
|
|
@@ -3486,7 +3486,7 @@ var init_Input = __esm({
|
|
|
3486
3486
|
ref,
|
|
3487
3487
|
value,
|
|
3488
3488
|
onChange,
|
|
3489
|
-
rows,
|
|
3489
|
+
rows: rows2,
|
|
3490
3490
|
className: baseClassName,
|
|
3491
3491
|
...props
|
|
3492
3492
|
}
|
|
@@ -5567,66 +5567,6 @@ var init_RangeSlider = __esm({
|
|
|
5567
5567
|
RangeSlider.displayName = "RangeSlider";
|
|
5568
5568
|
}
|
|
5569
5569
|
});
|
|
5570
|
-
function easeOut(t) {
|
|
5571
|
-
return t * (2 - t);
|
|
5572
|
-
}
|
|
5573
|
-
var AnimatedCounter;
|
|
5574
|
-
var init_AnimatedCounter = __esm({
|
|
5575
|
-
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
5576
|
-
"use client";
|
|
5577
|
-
init_cn();
|
|
5578
|
-
init_Typography();
|
|
5579
|
-
AnimatedCounter = ({
|
|
5580
|
-
value: rawValue,
|
|
5581
|
-
duration = 600,
|
|
5582
|
-
prefix,
|
|
5583
|
-
suffix,
|
|
5584
|
-
className
|
|
5585
|
-
}) => {
|
|
5586
|
-
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
5587
|
-
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
5588
|
-
const [displayValue, setDisplayValue] = React85.useState(value);
|
|
5589
|
-
const previousValueRef = React85.useRef(value);
|
|
5590
|
-
const animationFrameRef = React85.useRef(null);
|
|
5591
|
-
React85.useEffect(() => {
|
|
5592
|
-
const from = previousValueRef.current;
|
|
5593
|
-
const to = value;
|
|
5594
|
-
previousValueRef.current = value;
|
|
5595
|
-
if (from === to) {
|
|
5596
|
-
setDisplayValue(to);
|
|
5597
|
-
return;
|
|
5598
|
-
}
|
|
5599
|
-
const startTime = performance.now();
|
|
5600
|
-
const diff = to - from;
|
|
5601
|
-
function animate(currentTime) {
|
|
5602
|
-
const elapsed = currentTime - startTime;
|
|
5603
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
5604
|
-
const easedProgress = easeOut(progress);
|
|
5605
|
-
setDisplayValue(from + diff * easedProgress);
|
|
5606
|
-
if (progress < 1) {
|
|
5607
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5608
|
-
} else {
|
|
5609
|
-
setDisplayValue(to);
|
|
5610
|
-
}
|
|
5611
|
-
}
|
|
5612
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5613
|
-
return () => {
|
|
5614
|
-
if (animationFrameRef.current !== null) {
|
|
5615
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
5616
|
-
}
|
|
5617
|
-
};
|
|
5618
|
-
}, [value, duration]);
|
|
5619
|
-
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
5620
|
-
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
5621
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
5622
|
-
prefix,
|
|
5623
|
-
formattedValue,
|
|
5624
|
-
suffix
|
|
5625
|
-
] });
|
|
5626
|
-
};
|
|
5627
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
5628
|
-
}
|
|
5629
|
-
});
|
|
5630
5570
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
5631
5571
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
5632
5572
|
const observerRef = React85.useRef(null);
|
|
@@ -8108,15 +8048,15 @@ function HeaderSkeleton({ className }) {
|
|
|
8108
8048
|
] })
|
|
8109
8049
|
] });
|
|
8110
8050
|
}
|
|
8111
|
-
function TableSkeleton({ rows = 5, columns = 4, className }) {
|
|
8051
|
+
function TableSkeleton({ rows: rows2 = 5, columns = 4, className }) {
|
|
8112
8052
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: cn("border border-border rounded-lg overflow-hidden", className), children: [
|
|
8113
8053
|
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "px-4 py-3 bg-muted/30 border-b border-border", children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonBlock, { className: "h-4 flex-1 mx-2" }, i)) }),
|
|
8114
|
-
Array.from({ length:
|
|
8054
|
+
Array.from({ length: rows2 }).map((_, rowIdx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8115
8055
|
HStack,
|
|
8116
8056
|
{
|
|
8117
8057
|
className: cn(
|
|
8118
8058
|
"px-4 py-3",
|
|
8119
|
-
rowIdx <
|
|
8059
|
+
rowIdx < rows2 - 1 && "border-b border-border"
|
|
8120
8060
|
),
|
|
8121
8061
|
children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonLine, { className: "flex-1 mx-2" }, colIdx))
|
|
8122
8062
|
},
|
|
@@ -8164,18 +8104,18 @@ function CardSkeleton({ className }) {
|
|
|
8164
8104
|
}
|
|
8165
8105
|
);
|
|
8166
8106
|
}
|
|
8167
|
-
function TextSkeleton({ rows = 3, className }) {
|
|
8168
|
-
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length:
|
|
8107
|
+
function TextSkeleton({ rows: rows2 = 3, className }) {
|
|
8108
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length: rows2 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8169
8109
|
SkeletonLine,
|
|
8170
8110
|
{
|
|
8171
|
-
className: i ===
|
|
8111
|
+
className: i === rows2 - 1 ? "w-2/3" : "w-full"
|
|
8172
8112
|
},
|
|
8173
8113
|
i
|
|
8174
8114
|
)) });
|
|
8175
8115
|
}
|
|
8176
8116
|
function Skeleton({
|
|
8177
8117
|
variant = "text",
|
|
8178
|
-
rows,
|
|
8118
|
+
rows: rows2,
|
|
8179
8119
|
columns,
|
|
8180
8120
|
fields,
|
|
8181
8121
|
className
|
|
@@ -8185,15 +8125,15 @@ function Skeleton({
|
|
|
8185
8125
|
case "header":
|
|
8186
8126
|
return /* @__PURE__ */ jsxRuntime.jsx(HeaderSkeleton, { className });
|
|
8187
8127
|
case "table":
|
|
8188
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows, columns, className });
|
|
8128
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows: rows2, columns, className });
|
|
8189
8129
|
case "form":
|
|
8190
8130
|
return /* @__PURE__ */ jsxRuntime.jsx(FormSkeleton, { fields, className });
|
|
8191
8131
|
case "card":
|
|
8192
8132
|
return /* @__PURE__ */ jsxRuntime.jsx(CardSkeleton, { className });
|
|
8193
8133
|
case "text":
|
|
8194
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
8134
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
8195
8135
|
default:
|
|
8196
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
8136
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
8197
8137
|
}
|
|
8198
8138
|
}
|
|
8199
8139
|
var pulseClass;
|
|
@@ -10177,7 +10117,7 @@ var init_MapView = __esm({
|
|
|
10177
10117
|
shadowSize: [41, 41]
|
|
10178
10118
|
});
|
|
10179
10119
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
10180
|
-
const { useEffect: useEffect70, useRef: useRef66, useCallback:
|
|
10120
|
+
const { useEffect: useEffect70, useRef: useRef66, useCallback: useCallback114, useState: useState100 } = React85__namespace.default;
|
|
10181
10121
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
10182
10122
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
10183
10123
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -10223,7 +10163,7 @@ var init_MapView = __esm({
|
|
|
10223
10163
|
}) {
|
|
10224
10164
|
const eventBus = useEventBus2();
|
|
10225
10165
|
const [clickedPosition, setClickedPosition] = useState100(null);
|
|
10226
|
-
const handleMapClick =
|
|
10166
|
+
const handleMapClick = useCallback114((lat, lng) => {
|
|
10227
10167
|
if (showClickedPin) {
|
|
10228
10168
|
setClickedPosition({ lat, lng });
|
|
10229
10169
|
}
|
|
@@ -10232,7 +10172,7 @@ var init_MapView = __esm({
|
|
|
10232
10172
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
10233
10173
|
}
|
|
10234
10174
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
10235
|
-
const handleMarkerClick =
|
|
10175
|
+
const handleMarkerClick = useCallback114((marker) => {
|
|
10236
10176
|
onMarkerClick?.(marker);
|
|
10237
10177
|
if (markerClickEvent) {
|
|
10238
10178
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -10453,7 +10393,7 @@ function InputPattern({
|
|
|
10453
10393
|
function TextareaPattern({
|
|
10454
10394
|
value = "",
|
|
10455
10395
|
placeholder,
|
|
10456
|
-
rows = 4,
|
|
10396
|
+
rows: rows2 = 4,
|
|
10457
10397
|
disabled = false,
|
|
10458
10398
|
fieldError,
|
|
10459
10399
|
onChange,
|
|
@@ -10473,7 +10413,7 @@ function TextareaPattern({
|
|
|
10473
10413
|
{
|
|
10474
10414
|
value: localValue,
|
|
10475
10415
|
placeholder,
|
|
10476
|
-
rows,
|
|
10416
|
+
rows: rows2,
|
|
10477
10417
|
disabled,
|
|
10478
10418
|
error: fieldError,
|
|
10479
10419
|
onChange: handleChange,
|
|
@@ -10958,6 +10898,91 @@ var init_ActionPalette = __esm({
|
|
|
10958
10898
|
ActionPalette.displayName = "ActionPalette";
|
|
10959
10899
|
}
|
|
10960
10900
|
});
|
|
10901
|
+
function parseValue(value) {
|
|
10902
|
+
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
10903
|
+
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
10904
|
+
if (!match) {
|
|
10905
|
+
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
10906
|
+
}
|
|
10907
|
+
const numStr = match[2];
|
|
10908
|
+
const decimalIdx = numStr.indexOf(".");
|
|
10909
|
+
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
10910
|
+
return {
|
|
10911
|
+
prefix: match[1],
|
|
10912
|
+
num: parseFloat(numStr),
|
|
10913
|
+
suffix: match[3],
|
|
10914
|
+
decimals
|
|
10915
|
+
};
|
|
10916
|
+
}
|
|
10917
|
+
var AnimatedCounter;
|
|
10918
|
+
var init_AnimatedCounter = __esm({
|
|
10919
|
+
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
10920
|
+
"use client";
|
|
10921
|
+
init_cn();
|
|
10922
|
+
init_Box();
|
|
10923
|
+
init_Typography();
|
|
10924
|
+
AnimatedCounter = ({
|
|
10925
|
+
value,
|
|
10926
|
+
label,
|
|
10927
|
+
duration = 1500,
|
|
10928
|
+
className
|
|
10929
|
+
}) => {
|
|
10930
|
+
const ref = React85.useRef(null);
|
|
10931
|
+
const [displayValue, setDisplayValue] = React85.useState("0");
|
|
10932
|
+
const [hasAnimated, setHasAnimated] = React85.useState(false);
|
|
10933
|
+
const animate = React85.useCallback(() => {
|
|
10934
|
+
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
10935
|
+
if (num2 === 0) {
|
|
10936
|
+
setDisplayValue(String(value));
|
|
10937
|
+
return;
|
|
10938
|
+
}
|
|
10939
|
+
const startTime = performance.now();
|
|
10940
|
+
const tick = (now) => {
|
|
10941
|
+
const elapsed = now - startTime;
|
|
10942
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
10943
|
+
const eased = 1 - Math.pow(1 - progress, 3);
|
|
10944
|
+
const current = eased * num2;
|
|
10945
|
+
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
10946
|
+
if (progress < 1) {
|
|
10947
|
+
requestAnimationFrame(tick);
|
|
10948
|
+
} else {
|
|
10949
|
+
setDisplayValue(String(value));
|
|
10950
|
+
}
|
|
10951
|
+
};
|
|
10952
|
+
requestAnimationFrame(tick);
|
|
10953
|
+
}, [value, duration]);
|
|
10954
|
+
React85.useEffect(() => {
|
|
10955
|
+
if (hasAnimated) return;
|
|
10956
|
+
const el = ref.current;
|
|
10957
|
+
if (!el) return;
|
|
10958
|
+
const observer2 = new IntersectionObserver(
|
|
10959
|
+
(entries) => {
|
|
10960
|
+
if (entries[0].isIntersecting) {
|
|
10961
|
+
setHasAnimated(true);
|
|
10962
|
+
animate();
|
|
10963
|
+
observer2.disconnect();
|
|
10964
|
+
}
|
|
10965
|
+
},
|
|
10966
|
+
{ threshold: 0.3 }
|
|
10967
|
+
);
|
|
10968
|
+
observer2.observe(el);
|
|
10969
|
+
return () => observer2.disconnect();
|
|
10970
|
+
}, [hasAnimated, animate]);
|
|
10971
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
10972
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10973
|
+
Typography,
|
|
10974
|
+
{
|
|
10975
|
+
variant: "h2",
|
|
10976
|
+
className: "text-primary font-bold tabular-nums",
|
|
10977
|
+
children: hasAnimated ? displayValue : "0"
|
|
10978
|
+
}
|
|
10979
|
+
),
|
|
10980
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
10981
|
+
] });
|
|
10982
|
+
};
|
|
10983
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
10984
|
+
}
|
|
10985
|
+
});
|
|
10961
10986
|
var AuthLayout;
|
|
10962
10987
|
var init_AuthLayout = __esm({
|
|
10963
10988
|
"components/core/templates/AuthLayout.tsx"() {
|
|
@@ -12299,6 +12324,39 @@ var init_IsometricCanvas2 = __esm({
|
|
|
12299
12324
|
init_IsometricCanvas();
|
|
12300
12325
|
}
|
|
12301
12326
|
});
|
|
12327
|
+
|
|
12328
|
+
// components/game/organisms/boardEntity.ts
|
|
12329
|
+
function boardEntity(entity) {
|
|
12330
|
+
if (!entity) return void 0;
|
|
12331
|
+
return Array.isArray(entity) ? entity[0] : entity;
|
|
12332
|
+
}
|
|
12333
|
+
function str(v) {
|
|
12334
|
+
return v == null ? "" : String(v);
|
|
12335
|
+
}
|
|
12336
|
+
function num(v, fallback = 0) {
|
|
12337
|
+
const n = Number(v);
|
|
12338
|
+
return Number.isFinite(n) ? n : fallback;
|
|
12339
|
+
}
|
|
12340
|
+
function rows(v) {
|
|
12341
|
+
return Array.isArray(v) ? v : [];
|
|
12342
|
+
}
|
|
12343
|
+
function vec2(v) {
|
|
12344
|
+
const o = v ?? {};
|
|
12345
|
+
return { x: num(o.x), y: num(o.y) };
|
|
12346
|
+
}
|
|
12347
|
+
function unitPosition(u) {
|
|
12348
|
+
return vec2(u.position);
|
|
12349
|
+
}
|
|
12350
|
+
function unitTeam(u) {
|
|
12351
|
+
return str(u.team);
|
|
12352
|
+
}
|
|
12353
|
+
function unitHealth(u) {
|
|
12354
|
+
return num(u.health);
|
|
12355
|
+
}
|
|
12356
|
+
var init_boardEntity = __esm({
|
|
12357
|
+
"components/game/organisms/boardEntity.ts"() {
|
|
12358
|
+
}
|
|
12359
|
+
});
|
|
12302
12360
|
function BattleBoard({
|
|
12303
12361
|
entity,
|
|
12304
12362
|
scale = 0.45,
|
|
@@ -12325,43 +12383,49 @@ function BattleBoard({
|
|
|
12325
12383
|
attackEvent,
|
|
12326
12384
|
className
|
|
12327
12385
|
}) {
|
|
12328
|
-
const
|
|
12329
|
-
const
|
|
12330
|
-
const
|
|
12331
|
-
const
|
|
12332
|
-
const
|
|
12333
|
-
const
|
|
12334
|
-
const
|
|
12335
|
-
const
|
|
12336
|
-
const
|
|
12337
|
-
const
|
|
12338
|
-
const
|
|
12386
|
+
const board = boardEntity(entity) ?? {};
|
|
12387
|
+
const tiles = Array.isArray(board.tiles) ? board.tiles : [];
|
|
12388
|
+
const features = Array.isArray(board.features) ? board.features : [];
|
|
12389
|
+
const boardWidth = num(board.boardWidth, 8);
|
|
12390
|
+
const boardHeight = num(board.boardHeight, 6);
|
|
12391
|
+
const assetManifest = board.assetManifest;
|
|
12392
|
+
const backgroundImage = board.backgroundImage;
|
|
12393
|
+
const units = rows(board.units);
|
|
12394
|
+
const selectedUnitId = board.selectedUnitId ?? null;
|
|
12395
|
+
const currentPhase = str(board.phase) || "observation";
|
|
12396
|
+
const currentTurn = num(board.turn, 1);
|
|
12397
|
+
const gameResult = board.gameResult ?? null;
|
|
12339
12398
|
const eventBus = useEventBus();
|
|
12340
12399
|
const { t } = hooks.useTranslate();
|
|
12341
12400
|
const [hoveredTile, setHoveredTile] = React85.useState(null);
|
|
12342
12401
|
const [isShaking, setIsShaking] = React85.useState(false);
|
|
12343
12402
|
const selectedUnit = React85.useMemo(
|
|
12344
|
-
() => units.find((u) => u.id === selectedUnitId) ?? null,
|
|
12403
|
+
() => units.find((u) => str(u.id) === selectedUnitId) ?? null,
|
|
12345
12404
|
[units, selectedUnitId]
|
|
12346
12405
|
);
|
|
12347
12406
|
const hoveredUnit = React85.useMemo(() => {
|
|
12348
12407
|
if (!hoveredTile) return null;
|
|
12349
|
-
return units.find(
|
|
12350
|
-
|
|
12351
|
-
|
|
12408
|
+
return units.find((u) => {
|
|
12409
|
+
const p2 = unitPosition(u);
|
|
12410
|
+
return p2.x === hoveredTile.x && p2.y === hoveredTile.y && unitHealth(u) > 0;
|
|
12411
|
+
}) ?? null;
|
|
12352
12412
|
}, [hoveredTile, units]);
|
|
12353
|
-
const playerUnits = React85.useMemo(() => units.filter((u) => u
|
|
12354
|
-
const enemyUnits = React85.useMemo(() => units.filter((u) => u
|
|
12413
|
+
const playerUnits = React85.useMemo(() => units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0), [units]);
|
|
12414
|
+
const enemyUnits = React85.useMemo(() => units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0), [units]);
|
|
12355
12415
|
const validMoves = React85.useMemo(() => {
|
|
12356
12416
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
12357
12417
|
const moves = [];
|
|
12358
|
-
const range = selectedUnit.movement;
|
|
12418
|
+
const range = num(selectedUnit.movement);
|
|
12419
|
+
const origin = unitPosition(selectedUnit);
|
|
12359
12420
|
for (let dy = -range; dy <= range; dy++) {
|
|
12360
12421
|
for (let dx = -range; dx <= range; dx++) {
|
|
12361
|
-
const nx =
|
|
12362
|
-
const ny =
|
|
12422
|
+
const nx = origin.x + dx;
|
|
12423
|
+
const ny = origin.y + dy;
|
|
12363
12424
|
const dist = Math.abs(dx) + Math.abs(dy);
|
|
12364
|
-
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) =>
|
|
12425
|
+
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) => {
|
|
12426
|
+
const p2 = unitPosition(u);
|
|
12427
|
+
return p2.x === nx && p2.y === ny && unitHealth(u) > 0;
|
|
12428
|
+
})) {
|
|
12365
12429
|
moves.push({ x: nx, y: ny });
|
|
12366
12430
|
}
|
|
12367
12431
|
}
|
|
@@ -12370,11 +12434,14 @@ function BattleBoard({
|
|
|
12370
12434
|
}, [selectedUnit, currentPhase, units, boardWidth, boardHeight]);
|
|
12371
12435
|
const attackTargets = React85.useMemo(() => {
|
|
12372
12436
|
if (!selectedUnit || currentPhase !== "action") return [];
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12437
|
+
const sp = unitPosition(selectedUnit);
|
|
12438
|
+
const sTeam = unitTeam(selectedUnit);
|
|
12439
|
+
return units.filter((u) => unitTeam(u) !== sTeam && unitHealth(u) > 0).filter((u) => {
|
|
12440
|
+
const p2 = unitPosition(u);
|
|
12441
|
+
const dx = Math.abs(p2.x - sp.x);
|
|
12442
|
+
const dy = Math.abs(p2.y - sp.y);
|
|
12376
12443
|
return dx <= 1 && dy <= 1 && dx + dy > 0;
|
|
12377
|
-
}).map((u) => u
|
|
12444
|
+
}).map((u) => unitPosition(u));
|
|
12378
12445
|
}, [selectedUnit, currentPhase, units]);
|
|
12379
12446
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
12380
12447
|
const movementAnimRef = React85.useRef(null);
|
|
@@ -12414,23 +12481,25 @@ function BattleBoard({
|
|
|
12414
12481
|
return () => clearInterval(interval);
|
|
12415
12482
|
}, []);
|
|
12416
12483
|
const isoUnits = React85.useMemo(() => {
|
|
12417
|
-
return units.filter((u) => u
|
|
12418
|
-
const
|
|
12484
|
+
return units.filter((u) => unitHealth(u) > 0).map((unit) => {
|
|
12485
|
+
const id = str(unit.id);
|
|
12486
|
+
const pos = movingPositions.get(id) ?? unitPosition(unit);
|
|
12487
|
+
const unitTraits = Array.isArray(unit.traits) ? unit.traits : void 0;
|
|
12419
12488
|
return {
|
|
12420
|
-
id
|
|
12489
|
+
id,
|
|
12421
12490
|
position: pos,
|
|
12422
|
-
name: unit.name,
|
|
12423
|
-
team: unit
|
|
12424
|
-
health: unit
|
|
12425
|
-
maxHealth: unit.maxHealth,
|
|
12426
|
-
unitType: unit.unitType,
|
|
12427
|
-
heroId: unit.heroId,
|
|
12428
|
-
sprite: unit.sprite,
|
|
12429
|
-
traits:
|
|
12430
|
-
name:
|
|
12431
|
-
currentState:
|
|
12432
|
-
states:
|
|
12433
|
-
cooldown:
|
|
12491
|
+
name: str(unit.name),
|
|
12492
|
+
team: unitTeam(unit),
|
|
12493
|
+
health: unitHealth(unit),
|
|
12494
|
+
maxHealth: num(unit.maxHealth),
|
|
12495
|
+
unitType: unit.unitType == null ? void 0 : str(unit.unitType),
|
|
12496
|
+
heroId: unit.heroId == null ? void 0 : str(unit.heroId),
|
|
12497
|
+
sprite: unit.sprite == null ? void 0 : str(unit.sprite),
|
|
12498
|
+
traits: unitTraits?.map((tr) => ({
|
|
12499
|
+
name: tr.name,
|
|
12500
|
+
currentState: tr.currentState,
|
|
12501
|
+
states: tr.states,
|
|
12502
|
+
cooldown: tr.cooldown ?? 0
|
|
12434
12503
|
}))
|
|
12435
12504
|
};
|
|
12436
12505
|
});
|
|
@@ -12442,8 +12511,8 @@ function BattleBoard({
|
|
|
12442
12511
|
[scale, baseOffsetX]
|
|
12443
12512
|
);
|
|
12444
12513
|
const checkGameEnd = React85.useCallback(() => {
|
|
12445
|
-
const pa = units.filter((u) => u
|
|
12446
|
-
const ea = units.filter((u) => u
|
|
12514
|
+
const pa = units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
12515
|
+
const ea = units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
12447
12516
|
if (pa.length === 0) {
|
|
12448
12517
|
onGameEnd?.("defeat");
|
|
12449
12518
|
if (gameEndEvent) {
|
|
@@ -12457,21 +12526,22 @@ function BattleBoard({
|
|
|
12457
12526
|
}
|
|
12458
12527
|
}, [units, onGameEnd, gameEndEvent, eventBus]);
|
|
12459
12528
|
const handleUnitClick = React85.useCallback((unitId) => {
|
|
12460
|
-
const unit = units.find((u) => u.id === unitId);
|
|
12529
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
12461
12530
|
if (!unit) return;
|
|
12462
12531
|
if (unitClickEvent) {
|
|
12463
12532
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
12464
12533
|
}
|
|
12465
12534
|
if (currentPhase === "action" && selectedUnit) {
|
|
12466
|
-
|
|
12467
|
-
|
|
12535
|
+
const up = unitPosition(unit);
|
|
12536
|
+
if (unitTeam(unit) === "enemy" && attackTargets.some((t2) => t2.x === up.x && t2.y === up.y)) {
|
|
12537
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
12468
12538
|
setIsShaking(true);
|
|
12469
12539
|
setTimeout(() => setIsShaking(false), 300);
|
|
12470
12540
|
onAttack?.(selectedUnit, unit, damage);
|
|
12471
12541
|
if (attackEvent) {
|
|
12472
12542
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
12473
|
-
attackerId: selectedUnit.id,
|
|
12474
|
-
targetId: unit.id,
|
|
12543
|
+
attackerId: str(selectedUnit.id),
|
|
12544
|
+
targetId: str(unit.id),
|
|
12475
12545
|
damage
|
|
12476
12546
|
});
|
|
12477
12547
|
}
|
|
@@ -12486,9 +12556,9 @@ function BattleBoard({
|
|
|
12486
12556
|
if (currentPhase === "movement" && selectedUnit) {
|
|
12487
12557
|
if (movementAnimRef.current) return;
|
|
12488
12558
|
if (validMoves.some((m) => m.x === x && m.y === y)) {
|
|
12489
|
-
const from = { ...selectedUnit
|
|
12559
|
+
const from = { ...unitPosition(selectedUnit) };
|
|
12490
12560
|
const to = { x, y };
|
|
12491
|
-
startMoveAnimation(selectedUnit.id, from, to, () => {
|
|
12561
|
+
startMoveAnimation(str(selectedUnit.id), from, to, () => {
|
|
12492
12562
|
onUnitMove?.(selectedUnit, to);
|
|
12493
12563
|
});
|
|
12494
12564
|
}
|
|
@@ -12646,6 +12716,7 @@ var init_BattleBoard = __esm({
|
|
|
12646
12716
|
init_Typography();
|
|
12647
12717
|
init_Stack();
|
|
12648
12718
|
init_IsometricCanvas2();
|
|
12719
|
+
init_boardEntity();
|
|
12649
12720
|
init_isometric();
|
|
12650
12721
|
BattleBoard.displayName = "BattleBoard";
|
|
12651
12722
|
}
|
|
@@ -13868,24 +13939,24 @@ var init_CodeBlock = __esm({
|
|
|
13868
13939
|
return;
|
|
13869
13940
|
}
|
|
13870
13941
|
lineEls.forEach((el) => {
|
|
13871
|
-
const
|
|
13872
|
-
if (hiddenLines.has(
|
|
13942
|
+
const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
|
|
13943
|
+
if (hiddenLines.has(num2)) {
|
|
13873
13944
|
el.style.display = "none";
|
|
13874
13945
|
return;
|
|
13875
13946
|
}
|
|
13876
13947
|
el.style.display = "";
|
|
13877
13948
|
el.style.position = "relative";
|
|
13878
13949
|
el.style.paddingLeft = "1.2em";
|
|
13879
|
-
const region = foldStartMap.get(
|
|
13950
|
+
const region = foldStartMap.get(num2);
|
|
13880
13951
|
if (!region) return;
|
|
13881
|
-
const isCollapsed = collapsed.has(
|
|
13952
|
+
const isCollapsed = collapsed.has(num2);
|
|
13882
13953
|
const toggle = document.createElement("span");
|
|
13883
13954
|
toggle.className = "fold-toggle";
|
|
13884
13955
|
toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
|
|
13885
13956
|
toggle.style.cssText = "position:absolute;left:0;top:0;width:1.2em;text-align:center;cursor:pointer;color:#858585;font-size:10px;user-select:none;line-height:inherit;height:100%";
|
|
13886
13957
|
toggle.addEventListener("click", (e) => {
|
|
13887
13958
|
e.stopPropagation();
|
|
13888
|
-
toggleFoldRef.current(
|
|
13959
|
+
toggleFoldRef.current(num2);
|
|
13889
13960
|
});
|
|
13890
13961
|
el.insertBefore(toggle, el.firstChild);
|
|
13891
13962
|
if (isCollapsed) {
|
|
@@ -16138,10 +16209,13 @@ var init_BookChapterView = __esm({
|
|
|
16138
16209
|
init_cn();
|
|
16139
16210
|
BookChapterView = ({
|
|
16140
16211
|
chapter,
|
|
16212
|
+
orbitalSchema,
|
|
16141
16213
|
direction,
|
|
16142
16214
|
className
|
|
16143
16215
|
}) => {
|
|
16144
16216
|
const { t: _t } = hooks.useTranslate();
|
|
16217
|
+
const title = String(chapter.title ?? "");
|
|
16218
|
+
const content = String(chapter.content ?? "");
|
|
16145
16219
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
16146
16220
|
VStack,
|
|
16147
16221
|
{
|
|
@@ -16149,16 +16223,16 @@ var init_BookChapterView = __esm({
|
|
|
16149
16223
|
className: cn("px-6 py-8 max-w-4xl mx-auto w-full", className),
|
|
16150
16224
|
style: { direction },
|
|
16151
16225
|
children: [
|
|
16152
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children:
|
|
16226
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children: title }),
|
|
16153
16227
|
/* @__PURE__ */ jsxRuntime.jsx(Divider, {}),
|
|
16154
|
-
!!
|
|
16228
|
+
!!orbitalSchema && /* @__PURE__ */ jsxRuntime.jsx(ScaledDiagram, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
16155
16229
|
JazariStateMachine,
|
|
16156
16230
|
{
|
|
16157
|
-
schema:
|
|
16231
|
+
schema: orbitalSchema,
|
|
16158
16232
|
direction
|
|
16159
16233
|
}
|
|
16160
16234
|
) }),
|
|
16161
|
-
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content
|
|
16235
|
+
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content, direction })
|
|
16162
16236
|
]
|
|
16163
16237
|
}
|
|
16164
16238
|
);
|
|
@@ -16256,7 +16330,7 @@ var init_BookNavBar = __esm({
|
|
|
16256
16330
|
BookNavBar = ({
|
|
16257
16331
|
currentPage,
|
|
16258
16332
|
totalPages,
|
|
16259
|
-
chapterTitle,
|
|
16333
|
+
chapterTitle: chapterTitle2,
|
|
16260
16334
|
direction,
|
|
16261
16335
|
className
|
|
16262
16336
|
}) => {
|
|
@@ -16297,12 +16371,12 @@ var init_BookNavBar = __esm({
|
|
|
16297
16371
|
)
|
|
16298
16372
|
] }),
|
|
16299
16373
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex-1 mx-4 max-w-md", children: [
|
|
16300
|
-
|
|
16374
|
+
chapterTitle2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16301
16375
|
Typography,
|
|
16302
16376
|
{
|
|
16303
16377
|
variant: "caption",
|
|
16304
16378
|
className: "text-center block truncate text-muted-foreground",
|
|
16305
|
-
children:
|
|
16379
|
+
children: chapterTitle2
|
|
16306
16380
|
}
|
|
16307
16381
|
),
|
|
16308
16382
|
/* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { value: progress, size: "sm", variant: "primary" })
|
|
@@ -16369,31 +16443,35 @@ var init_BookTableOfContents = __esm({
|
|
|
16369
16443
|
style: { direction },
|
|
16370
16444
|
children: [
|
|
16371
16445
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold text-center mb-4", children: t("book.tableOfContents") }),
|
|
16372
|
-
parts.map((part, partIdx) =>
|
|
16373
|
-
|
|
16374
|
-
|
|
16375
|
-
/* @__PURE__ */ jsxRuntime.
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16446
|
+
parts.map((part, partIdx) => {
|
|
16447
|
+
const chapters = Array.isArray(part.chapters) ? part.chapters : [];
|
|
16448
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
16449
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", children: [
|
|
16450
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: t("book.partNumber", { number: String(partIdx + 1) }) }),
|
|
16451
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "font-semibold", children: String(part.title ?? "") })
|
|
16452
|
+
] }),
|
|
16453
|
+
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "xs", className: direction === "rtl" ? "pr-6" : "pl-6", children: chapters.map((chapter) => {
|
|
16454
|
+
const id = chapter.id == null ? "" : String(chapter.id);
|
|
16455
|
+
const isCurrent = id === currentChapterId;
|
|
16456
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16457
|
+
Button,
|
|
16458
|
+
{
|
|
16459
|
+
variant: "ghost",
|
|
16460
|
+
size: "sm",
|
|
16461
|
+
action: "BOOK_NAVIGATE",
|
|
16462
|
+
actionPayload: { chapterId: id },
|
|
16463
|
+
className: cn(
|
|
16464
|
+
"justify-start text-left w-full",
|
|
16465
|
+
direction === "rtl" && "text-right",
|
|
16466
|
+
isCurrent && "bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400"
|
|
16467
|
+
),
|
|
16468
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "truncate", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: String(chapter.title ?? "") }) })
|
|
16469
|
+
},
|
|
16470
|
+
id
|
|
16471
|
+
);
|
|
16472
|
+
}) })
|
|
16473
|
+
] }, partIdx);
|
|
16474
|
+
})
|
|
16397
16475
|
]
|
|
16398
16476
|
}
|
|
16399
16477
|
);
|
|
@@ -16515,27 +16593,41 @@ function resolveFieldMap(fieldMap) {
|
|
|
16515
16593
|
function get(obj, key) {
|
|
16516
16594
|
return obj[key];
|
|
16517
16595
|
}
|
|
16596
|
+
function asStr(v) {
|
|
16597
|
+
return v == null ? "" : String(v);
|
|
16598
|
+
}
|
|
16518
16599
|
function mapBookData(raw, fields = IDENTITY_BOOK_FIELDS) {
|
|
16519
16600
|
const rawParts = get(raw, fields.parts) ?? [];
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16528
|
-
return {
|
|
16529
|
-
title: get(part, fields.partTitle) ?? "",
|
|
16530
|
-
chapters: rawChapters.map((ch) => ({
|
|
16531
|
-
id: get(ch, fields.chapterId) ?? "",
|
|
16532
|
-
title: get(ch, fields.chapterTitle) ?? "",
|
|
16533
|
-
content: get(ch, fields.chapterContent) ?? "",
|
|
16534
|
-
orbitalSchema: get(ch, fields.chapterOrbitalSchema)
|
|
16535
|
-
}))
|
|
16536
|
-
};
|
|
16537
|
-
})
|
|
16601
|
+
const direction = get(raw, fields.direction) ?? "ltr";
|
|
16602
|
+
const cover = {
|
|
16603
|
+
title: asStr(get(raw, fields.title)),
|
|
16604
|
+
subtitle: asStr(get(raw, fields.subtitle)),
|
|
16605
|
+
author: asStr(get(raw, fields.author)),
|
|
16606
|
+
coverImageUrl: asStr(get(raw, fields.coverImageUrl)),
|
|
16607
|
+
direction
|
|
16538
16608
|
};
|
|
16609
|
+
const schemaByChapterId = {};
|
|
16610
|
+
const chapters = [];
|
|
16611
|
+
const parts = rawParts.map((part) => {
|
|
16612
|
+
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16613
|
+
const chapterRows = rawChapters.map((ch) => {
|
|
16614
|
+
const id = asStr(get(ch, fields.chapterId));
|
|
16615
|
+
const schema = get(ch, fields.chapterOrbitalSchema);
|
|
16616
|
+
if (schema) schemaByChapterId[id] = schema;
|
|
16617
|
+
const row = {
|
|
16618
|
+
id,
|
|
16619
|
+
title: asStr(get(ch, fields.chapterTitle)),
|
|
16620
|
+
content: asStr(get(ch, fields.chapterContent))
|
|
16621
|
+
};
|
|
16622
|
+
chapters.push(row);
|
|
16623
|
+
return row;
|
|
16624
|
+
});
|
|
16625
|
+
return {
|
|
16626
|
+
title: asStr(get(part, fields.partTitle)),
|
|
16627
|
+
chapters: chapterRows
|
|
16628
|
+
};
|
|
16629
|
+
});
|
|
16630
|
+
return { cover, direction, parts, chapters, schemaByChapterId };
|
|
16539
16631
|
}
|
|
16540
16632
|
var IDENTITY_BOOK_FIELDS, AR_BOOK_FIELDS, FIELD_MAP_REGISTRY;
|
|
16541
16633
|
var init_types2 = __esm({
|
|
@@ -16573,10 +16665,7 @@ var init_types2 = __esm({
|
|
|
16573
16665
|
};
|
|
16574
16666
|
}
|
|
16575
16667
|
});
|
|
16576
|
-
|
|
16577
|
-
return book.parts.flatMap((part) => part.chapters);
|
|
16578
|
-
}
|
|
16579
|
-
var PRINT_STYLES, BookViewer;
|
|
16668
|
+
var chapterId, chapterTitle, PRINT_STYLES, BookViewer;
|
|
16580
16669
|
var init_BookViewer = __esm({
|
|
16581
16670
|
"components/marketing/organisms/book/BookViewer.tsx"() {
|
|
16582
16671
|
init_Box();
|
|
@@ -16589,6 +16678,8 @@ var init_BookViewer = __esm({
|
|
|
16589
16678
|
init_BookNavBar();
|
|
16590
16679
|
init_EmptyState();
|
|
16591
16680
|
init_types2();
|
|
16681
|
+
chapterId = (ch) => ch?.id == null ? void 0 : String(ch.id);
|
|
16682
|
+
chapterTitle = (ch) => ch?.title == null ? void 0 : String(ch.title);
|
|
16592
16683
|
PRINT_STYLES = `
|
|
16593
16684
|
@media print {
|
|
16594
16685
|
.book-viewer-page {
|
|
@@ -16617,14 +16708,14 @@ var init_BookViewer = __esm({
|
|
|
16617
16708
|
return mapBookData(raw, resolvedFieldMap);
|
|
16618
16709
|
}, [entity, resolvedFieldMap]);
|
|
16619
16710
|
const direction = book?.direction ?? "ltr";
|
|
16620
|
-
const chapters = React85.useMemo(() => book ?
|
|
16711
|
+
const chapters = React85.useMemo(() => book ? book.chapters : [], [book]);
|
|
16621
16712
|
const totalPages = 2 + chapters.length;
|
|
16622
16713
|
const navigateTo = React85.useCallback(
|
|
16623
16714
|
(page) => {
|
|
16624
16715
|
const clamped = Math.max(0, Math.min(page, totalPages - 1));
|
|
16625
16716
|
setCurrentPage(clamped);
|
|
16626
|
-
const
|
|
16627
|
-
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId });
|
|
16717
|
+
const id = clamped >= 2 ? chapterId(chapters[clamped - 2]) : void 0;
|
|
16718
|
+
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId: id });
|
|
16628
16719
|
},
|
|
16629
16720
|
[totalPages, chapters, eventBus]
|
|
16630
16721
|
);
|
|
@@ -16636,8 +16727,8 @@ var init_BookViewer = __esm({
|
|
|
16636
16727
|
eventBus.on("UI:BOOK_PAGE_NEXT", () => navigateTo(currentPage + 1)),
|
|
16637
16728
|
eventBus.on("UI:BOOK_PRINT", () => window.print()),
|
|
16638
16729
|
eventBus.on("UI:BOOK_NAVIGATE", (event) => {
|
|
16639
|
-
const
|
|
16640
|
-
const idx = chapters.findIndex((ch) => ch
|
|
16730
|
+
const targetId = event.payload?.chapterId;
|
|
16731
|
+
const idx = chapters.findIndex((ch) => chapterId(ch) === targetId);
|
|
16641
16732
|
if (idx >= 0) navigateTo(idx + 2);
|
|
16642
16733
|
})
|
|
16643
16734
|
];
|
|
@@ -16654,9 +16745,11 @@ var init_BookViewer = __esm({
|
|
|
16654
16745
|
style.remove();
|
|
16655
16746
|
};
|
|
16656
16747
|
}, []);
|
|
16657
|
-
const currentChapterId = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16658
|
-
const currentChapterTitle = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16748
|
+
const currentChapterId = currentPage >= 2 ? chapterId(chapters[currentPage - 2]) : void 0;
|
|
16749
|
+
const currentChapterTitle = currentPage >= 2 ? chapterTitle(chapters[currentPage - 2]) : void 0;
|
|
16659
16750
|
if (!book) return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { message: t("book.noData") });
|
|
16751
|
+
const cover = book.cover;
|
|
16752
|
+
const coverTitle = String(cover.title ?? "");
|
|
16660
16753
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("relative h-full overflow-hidden bg-background", className), children: [
|
|
16661
16754
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
16662
16755
|
Box,
|
|
@@ -16668,10 +16761,10 @@ var init_BookViewer = __esm({
|
|
|
16668
16761
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16669
16762
|
BookCoverPage,
|
|
16670
16763
|
{
|
|
16671
|
-
title:
|
|
16672
|
-
subtitle:
|
|
16673
|
-
author:
|
|
16674
|
-
coverImageUrl:
|
|
16764
|
+
title: coverTitle,
|
|
16765
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16766
|
+
author: String(cover.author ?? "") || void 0,
|
|
16767
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16675
16768
|
direction
|
|
16676
16769
|
}
|
|
16677
16770
|
),
|
|
@@ -16682,23 +16775,27 @@ var init_BookViewer = __esm({
|
|
|
16682
16775
|
direction
|
|
16683
16776
|
}
|
|
16684
16777
|
),
|
|
16685
|
-
chapters.map((chapter) =>
|
|
16686
|
-
|
|
16687
|
-
|
|
16688
|
-
|
|
16689
|
-
|
|
16690
|
-
|
|
16691
|
-
|
|
16692
|
-
|
|
16778
|
+
chapters.map((chapter) => {
|
|
16779
|
+
const id = chapterId(chapter);
|
|
16780
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16781
|
+
BookChapterView,
|
|
16782
|
+
{
|
|
16783
|
+
chapter,
|
|
16784
|
+
orbitalSchema: id ? book.schemaByChapterId[id] : void 0,
|
|
16785
|
+
direction
|
|
16786
|
+
},
|
|
16787
|
+
id
|
|
16788
|
+
);
|
|
16789
|
+
})
|
|
16693
16790
|
] }),
|
|
16694
16791
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "print:hidden", children: [
|
|
16695
16792
|
currentPage === 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16696
16793
|
BookCoverPage,
|
|
16697
16794
|
{
|
|
16698
|
-
title:
|
|
16699
|
-
subtitle:
|
|
16700
|
-
author:
|
|
16701
|
-
coverImageUrl:
|
|
16795
|
+
title: coverTitle,
|
|
16796
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16797
|
+
author: String(cover.author ?? "") || void 0,
|
|
16798
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16702
16799
|
direction
|
|
16703
16800
|
}
|
|
16704
16801
|
),
|
|
@@ -16714,6 +16811,7 @@ var init_BookViewer = __esm({
|
|
|
16714
16811
|
BookChapterView,
|
|
16715
16812
|
{
|
|
16716
16813
|
chapter: chapters[currentPage - 2],
|
|
16814
|
+
orbitalSchema: currentChapterId ? book.schemaByChapterId[currentChapterId] : void 0,
|
|
16717
16815
|
direction
|
|
16718
16816
|
}
|
|
16719
16817
|
)
|
|
@@ -16726,7 +16824,7 @@ var init_BookViewer = __esm({
|
|
|
16726
16824
|
{
|
|
16727
16825
|
currentPage,
|
|
16728
16826
|
totalPages,
|
|
16729
|
-
chapterTitle: currentPage === 0 ?
|
|
16827
|
+
chapterTitle: currentPage === 0 ? coverTitle : currentPage === 1 ? t("book.tableOfContents") : currentChapterTitle,
|
|
16730
16828
|
direction
|
|
16731
16829
|
}
|
|
16732
16830
|
)
|
|
@@ -16824,7 +16922,7 @@ var init_Grid = __esm({
|
|
|
16824
16922
|
};
|
|
16825
16923
|
Grid = ({
|
|
16826
16924
|
cols = 1,
|
|
16827
|
-
rows,
|
|
16925
|
+
rows: rows2,
|
|
16828
16926
|
gap = "md",
|
|
16829
16927
|
rowGap,
|
|
16830
16928
|
colGap,
|
|
@@ -16836,7 +16934,7 @@ var init_Grid = __esm({
|
|
|
16836
16934
|
children,
|
|
16837
16935
|
as: Component = "div"
|
|
16838
16936
|
}) => {
|
|
16839
|
-
const mergedStyle =
|
|
16937
|
+
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
16840
16938
|
return React85__namespace.default.createElement(
|
|
16841
16939
|
Component,
|
|
16842
16940
|
{
|
|
@@ -17552,14 +17650,14 @@ function BuilderBoard({
|
|
|
17552
17650
|
}) {
|
|
17553
17651
|
const { emit } = useEventBus();
|
|
17554
17652
|
const { t } = hooks.useTranslate();
|
|
17555
|
-
const resolved =
|
|
17653
|
+
const resolved = boardEntity(entity);
|
|
17556
17654
|
const [placements, setPlacements] = React85.useState({});
|
|
17557
17655
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
17558
17656
|
const [submitted, setSubmitted] = React85.useState(false);
|
|
17559
17657
|
const [attempts, setAttempts] = React85.useState(0);
|
|
17560
17658
|
const [showHint, setShowHint] = React85.useState(false);
|
|
17561
|
-
const components = resolved?.components
|
|
17562
|
-
const slots = resolved?.slots
|
|
17659
|
+
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
17660
|
+
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
17563
17661
|
const usedComponentIds = new Set(Object.values(placements));
|
|
17564
17662
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
17565
17663
|
const [selectedComponent, setSelectedComponent] = React85.useState(null);
|
|
@@ -17593,7 +17691,7 @@ function BuilderBoard({
|
|
|
17593
17691
|
}, [slots, placements, attempts, completeEvent, emit]);
|
|
17594
17692
|
const handleReset = () => {
|
|
17595
17693
|
setSubmitted(false);
|
|
17596
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
17694
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
17597
17695
|
setShowHint(true);
|
|
17598
17696
|
}
|
|
17599
17697
|
};
|
|
@@ -17606,20 +17704,24 @@ function BuilderBoard({
|
|
|
17606
17704
|
};
|
|
17607
17705
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
17608
17706
|
if (!resolved) return null;
|
|
17707
|
+
const theme = resolved.theme ?? void 0;
|
|
17708
|
+
const themeBackground = theme?.background;
|
|
17709
|
+
const headerImage = str(resolved.headerImage);
|
|
17710
|
+
const hint = str(resolved.hint);
|
|
17609
17711
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17610
17712
|
Box,
|
|
17611
17713
|
{
|
|
17612
17714
|
className,
|
|
17613
17715
|
style: {
|
|
17614
|
-
backgroundImage:
|
|
17716
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
17615
17717
|
backgroundSize: "cover",
|
|
17616
17718
|
backgroundPosition: "center"
|
|
17617
17719
|
},
|
|
17618
17720
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
17619
|
-
|
|
17721
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
17620
17722
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17621
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
17622
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
17723
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
17724
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
17623
17725
|
] }) }),
|
|
17624
17726
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17625
17727
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.components") }),
|
|
@@ -17679,9 +17781,9 @@ function BuilderBoard({
|
|
|
17679
17781
|
] }) }),
|
|
17680
17782
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17681
17783
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
17682
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
17784
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
|
|
17683
17785
|
] }) }),
|
|
17684
|
-
showHint &&
|
|
17786
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
17685
17787
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17686
17788
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17687
17789
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
@@ -17700,6 +17802,7 @@ var init_BuilderBoard = __esm({
|
|
|
17700
17802
|
"components/game/organisms/puzzles/builder/BuilderBoard.tsx"() {
|
|
17701
17803
|
init_atoms2();
|
|
17702
17804
|
init_useEventBus();
|
|
17805
|
+
init_boardEntity();
|
|
17703
17806
|
BuilderBoard.displayName = "BuilderBoard";
|
|
17704
17807
|
}
|
|
17705
17808
|
});
|
|
@@ -18037,21 +18140,24 @@ function CalendarGrid({
|
|
|
18037
18140
|
eventBus.emit(`UI:${longPressEvent}`, { date: day.toISOString(), time, ...longPressPayload });
|
|
18038
18141
|
}, 500);
|
|
18039
18142
|
}, [longPressEvent, longPressPayload, eventBus]);
|
|
18040
|
-
const renderEvent = (event) =>
|
|
18041
|
-
|
|
18042
|
-
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
|
|
18046
|
-
|
|
18047
|
-
|
|
18048
|
-
|
|
18049
|
-
|
|
18050
|
-
|
|
18051
|
-
|
|
18052
|
-
|
|
18053
|
-
|
|
18054
|
-
|
|
18143
|
+
const renderEvent = (event) => {
|
|
18144
|
+
const color = event.color;
|
|
18145
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18146
|
+
Box,
|
|
18147
|
+
{
|
|
18148
|
+
rounded: "md",
|
|
18149
|
+
padding: "xs",
|
|
18150
|
+
border: true,
|
|
18151
|
+
className: cn(
|
|
18152
|
+
"cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
|
|
18153
|
+
color ? color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
|
|
18154
|
+
),
|
|
18155
|
+
onClick: (e) => handleEventClick(event, e),
|
|
18156
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
|
|
18157
|
+
},
|
|
18158
|
+
event.id
|
|
18159
|
+
);
|
|
18160
|
+
};
|
|
18055
18161
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18056
18162
|
Box,
|
|
18057
18163
|
{
|
|
@@ -19715,7 +19821,6 @@ var init_CardGrid = __esm({
|
|
|
19715
19821
|
alignItems = "stretch",
|
|
19716
19822
|
className,
|
|
19717
19823
|
children,
|
|
19718
|
-
// EntityDisplayProps
|
|
19719
19824
|
entity,
|
|
19720
19825
|
isLoading = false,
|
|
19721
19826
|
error = null,
|
|
@@ -20187,14 +20292,14 @@ var init_CaseStudyOrganism = __esm({
|
|
|
20187
20292
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((study) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
20188
20293
|
CaseStudyCard,
|
|
20189
20294
|
{
|
|
20190
|
-
title: study.title,
|
|
20191
|
-
description: study.description,
|
|
20192
|
-
category: study.category,
|
|
20193
|
-
categoryColor: study.categoryColor,
|
|
20194
|
-
href: study.href,
|
|
20195
|
-
linkLabel: study.linkLabel
|
|
20295
|
+
title: String(study.title ?? ""),
|
|
20296
|
+
description: String(study.description ?? ""),
|
|
20297
|
+
category: String(study.category ?? ""),
|
|
20298
|
+
categoryColor: study.categoryColor != null ? String(study.categoryColor) : void 0,
|
|
20299
|
+
href: String(study.href ?? ""),
|
|
20300
|
+
linkLabel: study.linkLabel != null ? String(study.linkLabel) : void 0
|
|
20196
20301
|
},
|
|
20197
|
-
study.id
|
|
20302
|
+
String(study.id ?? "")
|
|
20198
20303
|
)) })
|
|
20199
20304
|
] });
|
|
20200
20305
|
};
|
|
@@ -20217,10 +20322,10 @@ function CastleBoard({
|
|
|
20217
20322
|
className
|
|
20218
20323
|
}) {
|
|
20219
20324
|
const eventBus = useEventBus();
|
|
20220
|
-
const resolved =
|
|
20221
|
-
const tiles = resolved?.tiles
|
|
20222
|
-
const features = resolved?.features
|
|
20223
|
-
const units = resolved?.units
|
|
20325
|
+
const resolved = boardEntity(entity);
|
|
20326
|
+
const tiles = Array.isArray(resolved?.tiles) ? resolved.tiles : [];
|
|
20327
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
20328
|
+
const units = Array.isArray(resolved?.units) ? resolved.units : [];
|
|
20224
20329
|
const assetManifest = resolved?.assetManifest;
|
|
20225
20330
|
const backgroundImage = resolved?.backgroundImage;
|
|
20226
20331
|
const [hoveredTile, setHoveredTile] = React85.useState(null);
|
|
@@ -20248,7 +20353,7 @@ function CastleBoard({
|
|
|
20248
20353
|
onFeatureClick?.(feature);
|
|
20249
20354
|
if (featureClickEvent) {
|
|
20250
20355
|
eventBus.emit(`UI:${featureClickEvent}`, {
|
|
20251
|
-
featureId: feature.id,
|
|
20356
|
+
featureId: feature.id ?? "",
|
|
20252
20357
|
featureType: feature.type,
|
|
20253
20358
|
x: feature.x,
|
|
20254
20359
|
y: feature.y
|
|
@@ -20316,6 +20421,7 @@ var init_CastleBoard = __esm({
|
|
|
20316
20421
|
init_cn();
|
|
20317
20422
|
init_useEventBus();
|
|
20318
20423
|
init_IsometricCanvas2();
|
|
20424
|
+
init_boardEntity();
|
|
20319
20425
|
init_isometric();
|
|
20320
20426
|
CastleBoard.displayName = "CastleBoard";
|
|
20321
20427
|
}
|
|
@@ -21126,14 +21232,14 @@ function ClassifierBoard({
|
|
|
21126
21232
|
}) {
|
|
21127
21233
|
const { emit } = useEventBus();
|
|
21128
21234
|
const { t } = hooks.useTranslate();
|
|
21129
|
-
const resolved =
|
|
21235
|
+
const resolved = boardEntity(entity);
|
|
21130
21236
|
const [assignments, setAssignments] = React85.useState({});
|
|
21131
21237
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
21132
21238
|
const [submitted, setSubmitted] = React85.useState(false);
|
|
21133
21239
|
const [attempts, setAttempts] = React85.useState(0);
|
|
21134
21240
|
const [showHint, setShowHint] = React85.useState(false);
|
|
21135
|
-
const items = resolved?.items
|
|
21136
|
-
const categories = resolved?.categories
|
|
21241
|
+
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
21242
|
+
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
21137
21243
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
21138
21244
|
const allAssigned = Object.keys(assignments).length === items.length;
|
|
21139
21245
|
const results = submitted ? items.map((item) => ({
|
|
@@ -21165,7 +21271,7 @@ function ClassifierBoard({
|
|
|
21165
21271
|
}, [items, assignments, attempts, completeEvent, emit]);
|
|
21166
21272
|
const handleReset = () => {
|
|
21167
21273
|
setSubmitted(false);
|
|
21168
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
21274
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
21169
21275
|
setShowHint(true);
|
|
21170
21276
|
}
|
|
21171
21277
|
};
|
|
@@ -21176,20 +21282,25 @@ function ClassifierBoard({
|
|
|
21176
21282
|
setShowHint(false);
|
|
21177
21283
|
};
|
|
21178
21284
|
if (!resolved) return null;
|
|
21285
|
+
const theme = resolved.theme ?? void 0;
|
|
21286
|
+
const themeBackground = theme?.background;
|
|
21287
|
+
const headerImage = str(resolved.headerImage);
|
|
21288
|
+
const hint = str(resolved.hint);
|
|
21289
|
+
const failMessage = str(resolved.failMessage);
|
|
21179
21290
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
21180
21291
|
Box,
|
|
21181
21292
|
{
|
|
21182
21293
|
className,
|
|
21183
21294
|
style: {
|
|
21184
|
-
backgroundImage:
|
|
21295
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
21185
21296
|
backgroundSize: "cover",
|
|
21186
21297
|
backgroundPosition: "center"
|
|
21187
21298
|
},
|
|
21188
21299
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
21189
|
-
|
|
21300
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
21190
21301
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
21191
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
21192
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
21302
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
21303
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
21193
21304
|
] }) }),
|
|
21194
21305
|
unassignedItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
21195
21306
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("classifier.itemsToSort") }),
|
|
@@ -21241,10 +21352,10 @@ function ClassifierBoard({
|
|
|
21241
21352
|
}) }),
|
|
21242
21353
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
21243
21354
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
21244
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
21245
|
-
!allCorrect &&
|
|
21355
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("classifier.allCorrect") : `${correctCount}/${items.length} ${t("classifier.correct")}` }),
|
|
21356
|
+
!allCorrect && failMessage && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "text-muted-foreground", children: failMessage })
|
|
21246
21357
|
] }) }),
|
|
21247
|
-
showHint &&
|
|
21358
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
21248
21359
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
21249
21360
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
21250
21361
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -21263,6 +21374,7 @@ var init_ClassifierBoard = __esm({
|
|
|
21263
21374
|
"components/game/organisms/puzzles/classifier/ClassifierBoard.tsx"() {
|
|
21264
21375
|
init_atoms2();
|
|
21265
21376
|
init_useEventBus();
|
|
21377
|
+
init_boardEntity();
|
|
21266
21378
|
ClassifierBoard.displayName = "ClassifierBoard";
|
|
21267
21379
|
}
|
|
21268
21380
|
});
|
|
@@ -27633,7 +27745,7 @@ function InventoryPanel({
|
|
|
27633
27745
|
const slotArray = Array.from({ length: safeSlots }, (_, index) => {
|
|
27634
27746
|
return safeItems[index] ?? null;
|
|
27635
27747
|
});
|
|
27636
|
-
const
|
|
27748
|
+
const rows2 = Math.ceil(safeSlots / safeColumns);
|
|
27637
27749
|
const handleSlotClick = React85.useCallback((index) => {
|
|
27638
27750
|
if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
|
|
27639
27751
|
onSelectSlot?.(index);
|
|
@@ -27702,7 +27814,7 @@ function InventoryPanel({
|
|
|
27702
27814
|
className: "grid gap-1 bg-[var(--color-card)] p-2 rounded-container border border-border",
|
|
27703
27815
|
style: {
|
|
27704
27816
|
gridTemplateColumns: `repeat(${safeColumns}, ${slotSize}px)`,
|
|
27705
|
-
gridTemplateRows: `repeat(${
|
|
27817
|
+
gridTemplateRows: `repeat(${rows2}, ${slotSize}px)`
|
|
27706
27818
|
},
|
|
27707
27819
|
children: slotArray.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
27708
27820
|
"button",
|
|
@@ -31666,11 +31778,11 @@ function LatticeSVG({
|
|
|
31666
31778
|
}) {
|
|
31667
31779
|
const paths = [];
|
|
31668
31780
|
const cols = 5;
|
|
31669
|
-
const
|
|
31781
|
+
const rows2 = Math.ceil(h / (w / cols));
|
|
31670
31782
|
const cellW = w / cols;
|
|
31671
31783
|
const cellH = cellW;
|
|
31672
31784
|
const bulge = cellW * 0.3;
|
|
31673
|
-
for (let row = 0; row <
|
|
31785
|
+
for (let row = 0; row < rows2; row++) {
|
|
31674
31786
|
for (let col = 0; col < cols; col++) {
|
|
31675
31787
|
const cx = col * cellW + cellW / 2;
|
|
31676
31788
|
const cy = row * cellH + cellH / 2;
|
|
@@ -32082,7 +32194,7 @@ var init_MatrixQuestion = __esm({
|
|
|
32082
32194
|
};
|
|
32083
32195
|
MatrixQuestion = ({
|
|
32084
32196
|
title,
|
|
32085
|
-
rows,
|
|
32197
|
+
rows: rows2,
|
|
32086
32198
|
columns = DEFAULT_MATRIX_COLUMNS,
|
|
32087
32199
|
values,
|
|
32088
32200
|
onChange,
|
|
@@ -32092,7 +32204,7 @@ var init_MatrixQuestion = __esm({
|
|
|
32092
32204
|
className
|
|
32093
32205
|
}) => {
|
|
32094
32206
|
const styles = sizeStyles13[size];
|
|
32095
|
-
const safeRows =
|
|
32207
|
+
const safeRows = rows2 ?? [];
|
|
32096
32208
|
const safeValues = values ?? {};
|
|
32097
32209
|
const eventBus = useEventBus();
|
|
32098
32210
|
const handleChange = React85.useCallback(
|
|
@@ -32720,7 +32832,8 @@ var init_PositionedCanvas = __esm({
|
|
|
32720
32832
|
dragRef.current = null;
|
|
32721
32833
|
setDraggingId(null);
|
|
32722
32834
|
if (!wasDrag) {
|
|
32723
|
-
const
|
|
32835
|
+
const itemId = item.id;
|
|
32836
|
+
const next = selectedId === itemId ? null : itemId;
|
|
32724
32837
|
onSelect?.(next);
|
|
32725
32838
|
if (selectEvent) {
|
|
32726
32839
|
eventBus.emit(`UI:${selectEvent}`, { id: next });
|
|
@@ -32755,15 +32868,22 @@ var init_PositionedCanvas = __esm({
|
|
|
32755
32868
|
style: { width, height },
|
|
32756
32869
|
onClick: handleContainerClick,
|
|
32757
32870
|
children: items.map((item) => {
|
|
32871
|
+
const itemId = item.id;
|
|
32872
|
+
const label = item.label;
|
|
32873
|
+
const x = item.x;
|
|
32874
|
+
const y = item.y;
|
|
32875
|
+
const capacity = item.capacity;
|
|
32876
|
+
const partySize = item.partySize;
|
|
32877
|
+
const serverName = item.serverName;
|
|
32758
32878
|
const status = item.status ?? "empty";
|
|
32759
32879
|
const shape = item.shape ?? "round";
|
|
32760
|
-
const isSelected = selectedId ===
|
|
32761
|
-
const isDragging = draggingId ===
|
|
32880
|
+
const isSelected = selectedId === itemId;
|
|
32881
|
+
const isDragging = draggingId === itemId;
|
|
32762
32882
|
const statusBadge = STATUS_BADGE[status];
|
|
32763
32883
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32764
32884
|
Box,
|
|
32765
32885
|
{
|
|
32766
|
-
"data-testid": `item-node-${
|
|
32886
|
+
"data-testid": `item-node-${itemId}`,
|
|
32767
32887
|
"data-status": status,
|
|
32768
32888
|
className: cn(
|
|
32769
32889
|
"absolute flex flex-col items-center justify-center gap-1 border-2 select-none",
|
|
@@ -32774,7 +32894,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32774
32894
|
isSelected && "outline outline-2 outline-offset-2 outline-primary shadow-md",
|
|
32775
32895
|
isDragging && "shadow-lg z-10"
|
|
32776
32896
|
),
|
|
32777
|
-
style: { left:
|
|
32897
|
+
style: { left: x, top: y, touchAction: "none" },
|
|
32778
32898
|
onPointerDown: (e) => handlePointerDown(e, item),
|
|
32779
32899
|
onPointerMove: handlePointerMove,
|
|
32780
32900
|
onPointerUp: (e) => handlePointerUp(e, item),
|
|
@@ -32782,10 +32902,10 @@ var init_PositionedCanvas = __esm({
|
|
|
32782
32902
|
children: [
|
|
32783
32903
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", children: [
|
|
32784
32904
|
getStatusIcon(status),
|
|
32785
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children:
|
|
32905
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children: label })
|
|
32786
32906
|
] }),
|
|
32787
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
32788
|
-
status === "seated" &&
|
|
32907
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: partySize !== void 0 && status === "seated" ? `${partySize}/${capacity}` : `Cap ${capacity}` }),
|
|
32908
|
+
status === "seated" && serverName && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "truncate max-w-[80%]", children: serverName }),
|
|
32789
32909
|
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32790
32910
|
Badge,
|
|
32791
32911
|
{
|
|
@@ -32797,7 +32917,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32797
32917
|
)
|
|
32798
32918
|
]
|
|
32799
32919
|
},
|
|
32800
|
-
|
|
32920
|
+
itemId
|
|
32801
32921
|
);
|
|
32802
32922
|
})
|
|
32803
32923
|
}
|
|
@@ -33569,9 +33689,10 @@ var init_RichBlockEditor = __esm({
|
|
|
33569
33689
|
});
|
|
33570
33690
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
33571
33691
|
for (const n of nodes) {
|
|
33692
|
+
const replies = n.replies;
|
|
33572
33693
|
if (n.collapsed) acc.add(n.id);
|
|
33573
|
-
if (
|
|
33574
|
-
collectInitiallyCollapsed(
|
|
33694
|
+
if (replies && replies.length > 0) {
|
|
33695
|
+
collectInitiallyCollapsed(replies, acc);
|
|
33575
33696
|
}
|
|
33576
33697
|
}
|
|
33577
33698
|
}
|
|
@@ -33601,44 +33722,52 @@ var init_ReplyTree = __esm({
|
|
|
33601
33722
|
}) => {
|
|
33602
33723
|
const eventBus = useEventBus();
|
|
33603
33724
|
const { t } = hooks.useTranslate();
|
|
33604
|
-
const
|
|
33605
|
-
const
|
|
33725
|
+
const nodeId = node.id;
|
|
33726
|
+
const authorName = node.authorName;
|
|
33727
|
+
const authorAvatarUrl = node.authorAvatarUrl;
|
|
33728
|
+
const content = node.content;
|
|
33729
|
+
const postedAt = node.postedAt;
|
|
33730
|
+
const voteCount = node.voteCount;
|
|
33731
|
+
const userVote = node.userVote;
|
|
33732
|
+
const replies = node.replies;
|
|
33733
|
+
const hasReplies = !!replies && replies.length > 0;
|
|
33734
|
+
const isCollapsed = collapsedSet.has(nodeId);
|
|
33606
33735
|
const atMaxDepth = depth >= maxDepth;
|
|
33607
33736
|
const [replyOpen, setReplyOpen] = React85.useState(false);
|
|
33608
33737
|
const [draft, setDraft] = React85.useState("");
|
|
33609
33738
|
const handleVote = React85.useCallback(
|
|
33610
33739
|
(next) => {
|
|
33611
|
-
onVote?.(
|
|
33612
|
-
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId
|
|
33740
|
+
onVote?.(nodeId, next);
|
|
33741
|
+
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId, vote: next });
|
|
33613
33742
|
},
|
|
33614
|
-
[
|
|
33743
|
+
[nodeId, onVote, voteEvent, eventBus]
|
|
33615
33744
|
);
|
|
33616
33745
|
const handleReply = React85.useCallback(() => {
|
|
33617
|
-
onReply?.(
|
|
33746
|
+
onReply?.(nodeId);
|
|
33618
33747
|
setReplyOpen((open) => !open);
|
|
33619
|
-
}, [
|
|
33748
|
+
}, [nodeId, onReply]);
|
|
33620
33749
|
const handleSubmitReply = React85.useCallback(() => {
|
|
33621
|
-
const
|
|
33622
|
-
if (!
|
|
33623
|
-
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId:
|
|
33750
|
+
const text = draft.trim();
|
|
33751
|
+
if (!text) return;
|
|
33752
|
+
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: nodeId, content: text });
|
|
33624
33753
|
setDraft("");
|
|
33625
33754
|
setReplyOpen(false);
|
|
33626
|
-
}, [
|
|
33755
|
+
}, [nodeId, draft, replyEvent, eventBus]);
|
|
33627
33756
|
const handleCancelReply = React85.useCallback(() => {
|
|
33628
33757
|
setDraft("");
|
|
33629
33758
|
setReplyOpen(false);
|
|
33630
33759
|
}, []);
|
|
33631
33760
|
const handleFlag = React85.useCallback(() => {
|
|
33632
|
-
onFlag?.(
|
|
33633
|
-
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId
|
|
33634
|
-
}, [
|
|
33761
|
+
onFlag?.(nodeId);
|
|
33762
|
+
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId });
|
|
33763
|
+
}, [nodeId, onFlag, flagEvent, eventBus]);
|
|
33635
33764
|
const handleContinue = React85.useCallback(() => {
|
|
33636
|
-
onContinueThread?.(
|
|
33637
|
-
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId
|
|
33638
|
-
}, [
|
|
33765
|
+
onContinueThread?.(nodeId);
|
|
33766
|
+
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId });
|
|
33767
|
+
}, [nodeId, onContinueThread, continueThreadEvent, eventBus]);
|
|
33639
33768
|
const handleToggle = React85.useCallback(() => {
|
|
33640
|
-
toggleCollapse(
|
|
33641
|
-
}, [
|
|
33769
|
+
toggleCollapse(nodeId);
|
|
33770
|
+
}, [nodeId, toggleCollapse]);
|
|
33642
33771
|
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-stretch min-w-0", children: [
|
|
33643
33772
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col items-center flex-shrink-0 w-6", children: [
|
|
33644
33773
|
hasReplies ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -33670,25 +33799,25 @@ var init_ReplyTree = __esm({
|
|
|
33670
33799
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33671
33800
|
Avatar,
|
|
33672
33801
|
{
|
|
33673
|
-
src:
|
|
33674
|
-
name:
|
|
33802
|
+
src: authorAvatarUrl,
|
|
33803
|
+
name: authorName,
|
|
33675
33804
|
size: "sm"
|
|
33676
33805
|
}
|
|
33677
33806
|
),
|
|
33678
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children:
|
|
33679
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
33807
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children: authorName }),
|
|
33808
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: postedAt })
|
|
33680
33809
|
] }),
|
|
33681
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children:
|
|
33810
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: content }),
|
|
33682
33811
|
showActions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
33683
33812
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33684
33813
|
VoteStack,
|
|
33685
33814
|
{
|
|
33686
|
-
count:
|
|
33687
|
-
userVote:
|
|
33815
|
+
count: voteCount ?? 0,
|
|
33816
|
+
userVote: userVote ?? null,
|
|
33688
33817
|
onVote: handleVote,
|
|
33689
33818
|
size: "sm",
|
|
33690
33819
|
variant: "horizontal",
|
|
33691
|
-
label: t("replyTree.voteOnReplyBy", { author:
|
|
33820
|
+
label: t("replyTree.voteOnReplyBy", { author: authorName })
|
|
33692
33821
|
}
|
|
33693
33822
|
),
|
|
33694
33823
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -33698,7 +33827,7 @@ var init_ReplyTree = __esm({
|
|
|
33698
33827
|
size: "sm",
|
|
33699
33828
|
leftIcon: "message-square",
|
|
33700
33829
|
onClick: handleReply,
|
|
33701
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33830
|
+
"aria-label": t("replyTree.replyTo", { author: authorName }),
|
|
33702
33831
|
children: t("replyTree.reply")
|
|
33703
33832
|
}
|
|
33704
33833
|
),
|
|
@@ -33709,7 +33838,7 @@ var init_ReplyTree = __esm({
|
|
|
33709
33838
|
size: "sm",
|
|
33710
33839
|
leftIcon: "flag",
|
|
33711
33840
|
onClick: handleFlag,
|
|
33712
|
-
"aria-label": t("replyTree.flagReplyBy", { author:
|
|
33841
|
+
"aria-label": t("replyTree.flagReplyBy", { author: authorName }),
|
|
33713
33842
|
children: t("replyTree.flag")
|
|
33714
33843
|
}
|
|
33715
33844
|
)
|
|
@@ -33721,9 +33850,9 @@ var init_ReplyTree = __esm({
|
|
|
33721
33850
|
inputType: "textarea",
|
|
33722
33851
|
rows: 2,
|
|
33723
33852
|
value: draft,
|
|
33724
|
-
placeholder: t("replyTree.replyToPlaceholder", { author:
|
|
33853
|
+
placeholder: t("replyTree.replyToPlaceholder", { author: authorName }),
|
|
33725
33854
|
onChange: (e) => setDraft(e.target.value),
|
|
33726
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33855
|
+
"aria-label": t("replyTree.replyTo", { author: authorName })
|
|
33727
33856
|
}
|
|
33728
33857
|
),
|
|
33729
33858
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
@@ -33754,7 +33883,7 @@ var init_ReplyTree = __esm({
|
|
|
33754
33883
|
),
|
|
33755
33884
|
children: t("replyTree.continueThread")
|
|
33756
33885
|
}
|
|
33757
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children:
|
|
33886
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children: replies.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
33758
33887
|
ReplyTreeNode,
|
|
33759
33888
|
{
|
|
33760
33889
|
node: child,
|
|
@@ -36074,8 +36203,8 @@ var init_WizardContainer = __esm({
|
|
|
36074
36203
|
return void 0;
|
|
36075
36204
|
if (typeof controlledStep === "number") return controlledStep;
|
|
36076
36205
|
if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
|
|
36077
|
-
const
|
|
36078
|
-
return isNaN(
|
|
36206
|
+
const num2 = Number(controlledStep);
|
|
36207
|
+
return isNaN(num2) ? void 0 : num2;
|
|
36079
36208
|
})();
|
|
36080
36209
|
const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
|
|
36081
36210
|
const totalSteps = steps.length;
|
|
@@ -37780,7 +37909,7 @@ function DebuggerBoard({
|
|
|
37780
37909
|
}) {
|
|
37781
37910
|
const { emit } = useEventBus();
|
|
37782
37911
|
const { t } = hooks.useTranslate();
|
|
37783
|
-
const resolved =
|
|
37912
|
+
const resolved = boardEntity(entity);
|
|
37784
37913
|
const [flaggedLines, setFlaggedLines] = React85.useState(/* @__PURE__ */ new Set());
|
|
37785
37914
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
37786
37915
|
const [submitted, setSubmitted] = React85.useState(false);
|
|
@@ -37798,7 +37927,7 @@ function DebuggerBoard({
|
|
|
37798
37927
|
return next;
|
|
37799
37928
|
});
|
|
37800
37929
|
};
|
|
37801
|
-
const lines = resolved?.lines
|
|
37930
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37802
37931
|
const bugLines = lines.filter((l) => l.isBug);
|
|
37803
37932
|
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
37804
37933
|
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
@@ -37813,7 +37942,7 @@ function DebuggerBoard({
|
|
|
37813
37942
|
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37814
37943
|
const handleReset = () => {
|
|
37815
37944
|
setSubmitted(false);
|
|
37816
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
37945
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
37817
37946
|
setShowHint(true);
|
|
37818
37947
|
}
|
|
37819
37948
|
};
|
|
@@ -37824,24 +37953,28 @@ function DebuggerBoard({
|
|
|
37824
37953
|
setShowHint(false);
|
|
37825
37954
|
};
|
|
37826
37955
|
if (!resolved) return null;
|
|
37956
|
+
const theme = resolved.theme ?? void 0;
|
|
37957
|
+
const themeBackground = theme?.background;
|
|
37958
|
+
const headerImage = str(resolved.headerImage);
|
|
37959
|
+
const hint = str(resolved.hint);
|
|
37827
37960
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37828
37961
|
Box,
|
|
37829
37962
|
{
|
|
37830
37963
|
className,
|
|
37831
37964
|
style: {
|
|
37832
|
-
backgroundImage:
|
|
37965
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
37833
37966
|
backgroundSize: "cover",
|
|
37834
37967
|
backgroundPosition: "center"
|
|
37835
37968
|
},
|
|
37836
37969
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
37837
|
-
|
|
37970
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
37838
37971
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
37839
37972
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
37840
37973
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Bug, size: "sm" }),
|
|
37841
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title })
|
|
37974
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
37842
37975
|
] }),
|
|
37843
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
37844
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(resolved.bugCount) }) })
|
|
37976
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
37977
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
37845
37978
|
] }) }),
|
|
37846
37979
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
37847
37980
|
const isFlagged = flaggedLines.has(line.id);
|
|
@@ -37873,7 +38006,7 @@ function DebuggerBoard({
|
|
|
37873
38006
|
);
|
|
37874
38007
|
}) }) }),
|
|
37875
38008
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
37876
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
38009
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
|
|
37877
38010
|
bugLines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "start", children: [
|
|
37878
38011
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37879
38012
|
Icon,
|
|
@@ -37889,7 +38022,7 @@ function DebuggerBoard({
|
|
|
37889
38022
|
] })
|
|
37890
38023
|
] }, line.id))
|
|
37891
38024
|
] }) }),
|
|
37892
|
-
showHint &&
|
|
38025
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
37893
38026
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
37894
38027
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
|
|
37895
38028
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -37908,6 +38041,7 @@ var init_DebuggerBoard = __esm({
|
|
|
37908
38041
|
"components/game/organisms/puzzles/debugger/DebuggerBoard.tsx"() {
|
|
37909
38042
|
init_atoms2();
|
|
37910
38043
|
init_useEventBus();
|
|
38044
|
+
init_boardEntity();
|
|
37911
38045
|
DebuggerBoard.displayName = "DebuggerBoard";
|
|
37912
38046
|
}
|
|
37913
38047
|
});
|
|
@@ -37945,7 +38079,7 @@ function getBadgeVariant(fieldName, value) {
|
|
|
37945
38079
|
return "default";
|
|
37946
38080
|
}
|
|
37947
38081
|
function formatFieldLabel(fieldName) {
|
|
37948
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
38082
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
|
|
37949
38083
|
}
|
|
37950
38084
|
function formatFieldValue(value, fieldName) {
|
|
37951
38085
|
if (typeof value === "number") {
|
|
@@ -37964,26 +38098,26 @@ function formatFieldValue(value, fieldName) {
|
|
|
37964
38098
|
}
|
|
37965
38099
|
function renderRichFieldValue(value, fieldName, fieldType) {
|
|
37966
38100
|
if (value === void 0 || value === null) return "\u2014";
|
|
37967
|
-
const
|
|
38101
|
+
const str2 = String(value);
|
|
37968
38102
|
switch (fieldType) {
|
|
37969
38103
|
case "image":
|
|
37970
38104
|
case "url": {
|
|
37971
|
-
if (
|
|
38105
|
+
if (str2.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str2.startsWith("data:image/")) {
|
|
37972
38106
|
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
37973
38107
|
"img",
|
|
37974
38108
|
{
|
|
37975
|
-
src:
|
|
38109
|
+
src: str2,
|
|
37976
38110
|
alt: formatFieldLabel(fieldName),
|
|
37977
38111
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
37978
38112
|
loading: "lazy"
|
|
37979
38113
|
}
|
|
37980
38114
|
) });
|
|
37981
38115
|
}
|
|
37982
|
-
return
|
|
38116
|
+
return str2;
|
|
37983
38117
|
}
|
|
37984
38118
|
case "markdown":
|
|
37985
38119
|
case "richtext":
|
|
37986
|
-
return /* @__PURE__ */ jsxRuntime.jsx(React85.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children:
|
|
38120
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React85.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children: str2 }), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
37987
38121
|
Box,
|
|
37988
38122
|
{
|
|
37989
38123
|
className: "prose prose-sm max-w-none",
|
|
@@ -38001,11 +38135,11 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
38001
38135
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
38002
38136
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
38003
38137
|
},
|
|
38004
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children:
|
|
38138
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children: str2 })
|
|
38005
38139
|
}
|
|
38006
38140
|
) });
|
|
38007
38141
|
case "code":
|
|
38008
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children:
|
|
38142
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: str2 }) }) });
|
|
38009
38143
|
case "html":
|
|
38010
38144
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
38011
38145
|
Box,
|
|
@@ -38025,12 +38159,12 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
38025
38159
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
38026
38160
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
38027
38161
|
},
|
|
38028
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children:
|
|
38162
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str2 })
|
|
38029
38163
|
}
|
|
38030
38164
|
);
|
|
38031
38165
|
case "date":
|
|
38032
38166
|
case "datetime": {
|
|
38033
|
-
const d = new Date(
|
|
38167
|
+
const d = new Date(str2);
|
|
38034
38168
|
if (!isNaN(d.getTime())) {
|
|
38035
38169
|
return d.toLocaleDateString(void 0, {
|
|
38036
38170
|
year: "numeric",
|
|
@@ -38039,7 +38173,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
38039
38173
|
...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
|
|
38040
38174
|
});
|
|
38041
38175
|
}
|
|
38042
|
-
return
|
|
38176
|
+
return str2;
|
|
38043
38177
|
}
|
|
38044
38178
|
default:
|
|
38045
38179
|
return formatFieldValue(value, fieldName);
|
|
@@ -38717,6 +38851,40 @@ var init_RuleEditor = __esm({
|
|
|
38717
38851
|
RuleEditor.displayName = "RuleEditor";
|
|
38718
38852
|
}
|
|
38719
38853
|
});
|
|
38854
|
+
|
|
38855
|
+
// components/game/organisms/puzzles/event-handler/puzzleObject.ts
|
|
38856
|
+
function objId(o) {
|
|
38857
|
+
return o.id == null ? "" : String(o.id);
|
|
38858
|
+
}
|
|
38859
|
+
function objName(o) {
|
|
38860
|
+
return o.name == null ? "" : String(o.name);
|
|
38861
|
+
}
|
|
38862
|
+
function objIcon(o) {
|
|
38863
|
+
return o.icon == null ? "" : String(o.icon);
|
|
38864
|
+
}
|
|
38865
|
+
function objStates(o) {
|
|
38866
|
+
return Array.isArray(o.states) ? o.states : [];
|
|
38867
|
+
}
|
|
38868
|
+
function objCurrentState(o) {
|
|
38869
|
+
return o.currentState == null ? "" : String(o.currentState);
|
|
38870
|
+
}
|
|
38871
|
+
function objAvailableEvents(o) {
|
|
38872
|
+
return Array.isArray(o.availableEvents) ? o.availableEvents : [];
|
|
38873
|
+
}
|
|
38874
|
+
function objAvailableActions(o) {
|
|
38875
|
+
return Array.isArray(o.availableActions) ? o.availableActions : [];
|
|
38876
|
+
}
|
|
38877
|
+
function objRules(o) {
|
|
38878
|
+
return Array.isArray(o.rules) ? o.rules : [];
|
|
38879
|
+
}
|
|
38880
|
+
function objMaxRules(o) {
|
|
38881
|
+
const n = Number(o.maxRules);
|
|
38882
|
+
return Number.isFinite(n) && n > 0 ? n : 3;
|
|
38883
|
+
}
|
|
38884
|
+
var init_puzzleObject = __esm({
|
|
38885
|
+
"components/game/organisms/puzzles/event-handler/puzzleObject.ts"() {
|
|
38886
|
+
}
|
|
38887
|
+
});
|
|
38720
38888
|
function ObjectRulePanel({
|
|
38721
38889
|
object,
|
|
38722
38890
|
onRulesChange,
|
|
@@ -38724,55 +38892,63 @@ function ObjectRulePanel({
|
|
|
38724
38892
|
className
|
|
38725
38893
|
}) {
|
|
38726
38894
|
const { t } = hooks.useTranslate();
|
|
38727
|
-
const
|
|
38728
|
-
const
|
|
38895
|
+
const id = objId(object);
|
|
38896
|
+
const name = objName(object);
|
|
38897
|
+
const icon = objIcon(object);
|
|
38898
|
+
const states = objStates(object);
|
|
38899
|
+
const currentState = objCurrentState(object);
|
|
38900
|
+
const availableEvents = objAvailableEvents(object);
|
|
38901
|
+
const availableActions = objAvailableActions(object);
|
|
38902
|
+
const rules = objRules(object);
|
|
38903
|
+
const maxRules = objMaxRules(object);
|
|
38904
|
+
const canAdd = rules.length < maxRules;
|
|
38729
38905
|
const handleRuleChange = React85.useCallback((index, updatedRule) => {
|
|
38730
|
-
const newRules = [...
|
|
38906
|
+
const newRules = [...rules];
|
|
38731
38907
|
newRules[index] = updatedRule;
|
|
38732
|
-
onRulesChange(
|
|
38733
|
-
}, [
|
|
38908
|
+
onRulesChange(id, newRules);
|
|
38909
|
+
}, [id, rules, onRulesChange]);
|
|
38734
38910
|
const handleRuleRemove = React85.useCallback((index) => {
|
|
38735
|
-
const newRules =
|
|
38736
|
-
onRulesChange(
|
|
38737
|
-
}, [
|
|
38911
|
+
const newRules = rules.filter((_, i) => i !== index);
|
|
38912
|
+
onRulesChange(id, newRules);
|
|
38913
|
+
}, [id, rules, onRulesChange]);
|
|
38738
38914
|
const handleAddRule = React85.useCallback(() => {
|
|
38739
38915
|
if (!canAdd || disabled) return;
|
|
38740
|
-
const firstEvent =
|
|
38741
|
-
const firstAction =
|
|
38916
|
+
const firstEvent = availableEvents[0]?.value || "";
|
|
38917
|
+
const firstAction = availableActions[0]?.value || "";
|
|
38742
38918
|
const newRule = {
|
|
38743
38919
|
id: `rule-${nextRuleId++}`,
|
|
38744
38920
|
whenEvent: firstEvent,
|
|
38745
38921
|
thenAction: firstAction
|
|
38746
38922
|
};
|
|
38747
|
-
onRulesChange(
|
|
38748
|
-
}, [canAdd, disabled,
|
|
38923
|
+
onRulesChange(id, [...rules, newRule]);
|
|
38924
|
+
}, [canAdd, disabled, id, rules, availableEvents, availableActions, onRulesChange]);
|
|
38749
38925
|
const machine = {
|
|
38750
|
-
name
|
|
38751
|
-
states
|
|
38752
|
-
currentState
|
|
38753
|
-
transitions:
|
|
38754
|
-
from:
|
|
38755
|
-
to:
|
|
38926
|
+
name,
|
|
38927
|
+
states,
|
|
38928
|
+
currentState,
|
|
38929
|
+
transitions: rules.map((r) => ({
|
|
38930
|
+
from: currentState,
|
|
38931
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38756
38932
|
event: r.whenEvent
|
|
38757
38933
|
}))
|
|
38758
38934
|
};
|
|
38759
38935
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-4 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
38760
38936
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center", gap: "sm", children: [
|
|
38761
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children:
|
|
38937
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: icon }),
|
|
38762
38938
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
38763
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children:
|
|
38764
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " +
|
|
38939
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children: name }),
|
|
38940
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " + currentState })
|
|
38765
38941
|
] })
|
|
38766
38942
|
] }),
|
|
38767
38943
|
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" }),
|
|
38768
38944
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
38769
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count:
|
|
38770
|
-
|
|
38945
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count: rules.length, max: maxRules }) + ":" }),
|
|
38946
|
+
rules.map((rule, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
38771
38947
|
RuleEditor,
|
|
38772
38948
|
{
|
|
38773
38949
|
rule,
|
|
38774
|
-
availableEvents
|
|
38775
|
-
availableActions
|
|
38950
|
+
availableEvents,
|
|
38951
|
+
availableActions,
|
|
38776
38952
|
onChange: (r) => handleRuleChange(i, r),
|
|
38777
38953
|
onRemove: () => handleRuleRemove(i),
|
|
38778
38954
|
disabled
|
|
@@ -38790,6 +38966,7 @@ var init_ObjectRulePanel = __esm({
|
|
|
38790
38966
|
init_cn();
|
|
38791
38967
|
init_TraitStateViewer();
|
|
38792
38968
|
init_RuleEditor();
|
|
38969
|
+
init_puzzleObject();
|
|
38793
38970
|
nextRuleId = 1;
|
|
38794
38971
|
ObjectRulePanel.displayName = "ObjectRulePanel";
|
|
38795
38972
|
}
|
|
@@ -38856,11 +39033,11 @@ function EventHandlerBoard({
|
|
|
38856
39033
|
}) {
|
|
38857
39034
|
const { emit } = useEventBus();
|
|
38858
39035
|
const { t } = hooks.useTranslate();
|
|
38859
|
-
const resolved =
|
|
38860
|
-
const entityObjects = resolved?.objects
|
|
38861
|
-
const [objects, setObjects] = React85.useState(entityObjects);
|
|
39036
|
+
const resolved = boardEntity(entity);
|
|
39037
|
+
const entityObjects = rows(resolved?.objects);
|
|
39038
|
+
const [objects, setObjects] = React85.useState(() => [...entityObjects]);
|
|
38862
39039
|
const [selectedObjectId, setSelectedObjectId] = React85.useState(
|
|
38863
|
-
entityObjects[0]
|
|
39040
|
+
entityObjects[0] ? objId(entityObjects[0]) : null
|
|
38864
39041
|
);
|
|
38865
39042
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
38866
39043
|
const [playState, setPlayState] = React85.useState("editing");
|
|
@@ -38871,10 +39048,10 @@ function EventHandlerBoard({
|
|
|
38871
39048
|
React85.useEffect(() => () => {
|
|
38872
39049
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38873
39050
|
}, []);
|
|
38874
|
-
const selectedObject = objects.find((o) => o
|
|
39051
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) || null;
|
|
38875
39052
|
const handleRulesChange = React85.useCallback((objectId, rules) => {
|
|
38876
39053
|
setObjects((prev) => prev.map(
|
|
38877
|
-
(o) => o
|
|
39054
|
+
(o) => objId(o) === objectId ? { ...o, rules } : o
|
|
38878
39055
|
));
|
|
38879
39056
|
}, []);
|
|
38880
39057
|
const addLogEntry = React85.useCallback((icon, message, status = "done") => {
|
|
@@ -38888,11 +39065,12 @@ function EventHandlerBoard({
|
|
|
38888
39065
|
setEventLog([]);
|
|
38889
39066
|
const allRules = [];
|
|
38890
39067
|
objects.forEach((obj) => {
|
|
38891
|
-
obj.
|
|
39068
|
+
objRules(obj).forEach((rule) => {
|
|
38892
39069
|
allRules.push({ object: obj, rule });
|
|
38893
39070
|
});
|
|
38894
39071
|
});
|
|
38895
|
-
const triggers = resolved?.triggerEvents
|
|
39072
|
+
const triggers = Array.isArray(resolved?.triggerEvents) ? resolved.triggerEvents : [];
|
|
39073
|
+
const goalEvent = str(resolved?.goalEvent);
|
|
38896
39074
|
const eventQueue = [...triggers];
|
|
38897
39075
|
const firedEvents = /* @__PURE__ */ new Set();
|
|
38898
39076
|
let stepIdx = 0;
|
|
@@ -38921,14 +39099,14 @@ function EventHandlerBoard({
|
|
|
38921
39099
|
addLogEntry("\u26A1", t("eventHandler.noListeners", { event: currentEvent }), "done");
|
|
38922
39100
|
} else {
|
|
38923
39101
|
matching.forEach(({ object, rule }) => {
|
|
38924
|
-
addLogEntry(object
|
|
39102
|
+
addLogEntry(objIcon(object), t("eventHandler.heardEvent", { object: objName(object), event: currentEvent, action: rule.thenAction }), "done");
|
|
38925
39103
|
eventQueue.push(rule.thenAction);
|
|
38926
|
-
if (rule.thenAction ===
|
|
39104
|
+
if (rule.thenAction === goalEvent) {
|
|
38927
39105
|
goalReached = true;
|
|
38928
39106
|
}
|
|
38929
39107
|
});
|
|
38930
39108
|
}
|
|
38931
|
-
if (currentEvent ===
|
|
39109
|
+
if (currentEvent === goalEvent) {
|
|
38932
39110
|
goalReached = true;
|
|
38933
39111
|
}
|
|
38934
39112
|
stepIdx++;
|
|
@@ -38946,65 +39124,75 @@ function EventHandlerBoard({
|
|
|
38946
39124
|
}, []);
|
|
38947
39125
|
const handleReset = React85.useCallback(() => {
|
|
38948
39126
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38949
|
-
|
|
39127
|
+
const resetObjects = rows(resolved?.objects);
|
|
39128
|
+
setObjects([...resetObjects]);
|
|
38950
39129
|
setPlayState("editing");
|
|
38951
39130
|
setEventLog([]);
|
|
38952
|
-
setSelectedObjectId(
|
|
39131
|
+
setSelectedObjectId(resetObjects[0] ? objId(resetObjects[0]) : null);
|
|
38953
39132
|
setAttempts(0);
|
|
38954
39133
|
}, [resolved?.objects]);
|
|
38955
39134
|
if (!resolved) return null;
|
|
38956
39135
|
const objectViewers = objects.map((obj) => {
|
|
39136
|
+
const states = objStates(obj);
|
|
39137
|
+
const currentState = objCurrentState(obj);
|
|
38957
39138
|
const machine = {
|
|
38958
|
-
name: obj
|
|
38959
|
-
states
|
|
38960
|
-
currentState
|
|
38961
|
-
transitions: obj.
|
|
38962
|
-
from:
|
|
38963
|
-
to:
|
|
39139
|
+
name: objName(obj),
|
|
39140
|
+
states,
|
|
39141
|
+
currentState,
|
|
39142
|
+
transitions: objRules(obj).map((r) => ({
|
|
39143
|
+
from: currentState,
|
|
39144
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38964
39145
|
event: r.whenEvent
|
|
38965
39146
|
}))
|
|
38966
39147
|
};
|
|
38967
39148
|
return { obj, machine };
|
|
38968
39149
|
});
|
|
38969
|
-
const
|
|
39150
|
+
const hint = str(resolved.hint);
|
|
39151
|
+
const showHint = attempts >= 3 && hint;
|
|
39152
|
+
const theme = resolved.theme ?? void 0;
|
|
39153
|
+
const themeBackground = theme?.background;
|
|
39154
|
+
const headerImage = str(resolved.headerImage);
|
|
38970
39155
|
const encourageKey = ENCOURAGEMENT_KEYS[Math.min(attempts - 1, ENCOURAGEMENT_KEYS.length - 1)] ?? ENCOURAGEMENT_KEYS[0];
|
|
38971
39156
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
38972
39157
|
VStack,
|
|
38973
39158
|
{
|
|
38974
39159
|
className: cn("p-4 gap-6", className),
|
|
38975
39160
|
style: {
|
|
38976
|
-
backgroundImage:
|
|
39161
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
38977
39162
|
backgroundSize: "cover",
|
|
38978
39163
|
backgroundPosition: "center"
|
|
38979
39164
|
},
|
|
38980
39165
|
children: [
|
|
38981
|
-
|
|
39166
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
38982
39167
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
38983
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
38984
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
39168
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
39169
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
38985
39170
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
|
|
38986
39171
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
|
|
38987
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: resolved.goalCondition })
|
|
39172
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: str(resolved.goalCondition) })
|
|
38988
39173
|
] })
|
|
38989
39174
|
] }),
|
|
38990
39175
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
38991
39176
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
|
|
38992
|
-
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) =>
|
|
38993
|
-
|
|
38994
|
-
|
|
38995
|
-
|
|
38996
|
-
|
|
38997
|
-
|
|
38998
|
-
|
|
38999
|
-
|
|
39000
|
-
|
|
39001
|
-
|
|
39002
|
-
/* @__PURE__ */ jsxRuntime.
|
|
39003
|
-
|
|
39004
|
-
|
|
39005
|
-
|
|
39006
|
-
|
|
39007
|
-
|
|
39177
|
+
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => {
|
|
39178
|
+
const oid = objId(obj);
|
|
39179
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
39180
|
+
Box,
|
|
39181
|
+
{
|
|
39182
|
+
className: cn(
|
|
39183
|
+
"p-3 rounded-container border-2 cursor-pointer transition-all hover:scale-105",
|
|
39184
|
+
selectedObjectId === oid ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
|
|
39185
|
+
),
|
|
39186
|
+
onClick: () => setSelectedObjectId(oid),
|
|
39187
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
|
|
39188
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: objIcon(obj) }),
|
|
39189
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: objName(obj) }),
|
|
39190
|
+
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
|
|
39191
|
+
] })
|
|
39192
|
+
},
|
|
39193
|
+
oid
|
|
39194
|
+
);
|
|
39195
|
+
}) })
|
|
39008
39196
|
] }),
|
|
39009
39197
|
selectedObject && /* @__PURE__ */ jsxRuntime.jsx(
|
|
39010
39198
|
ObjectRulePanel,
|
|
@@ -39015,12 +39203,12 @@ function EventHandlerBoard({
|
|
|
39015
39203
|
}
|
|
39016
39204
|
),
|
|
39017
39205
|
eventLog.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(EventLog, { entries: eventLog }),
|
|
39018
|
-
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("eventHandler.chainComplete") }) }),
|
|
39206
|
+
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("eventHandler.chainComplete") }) }),
|
|
39019
39207
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
39020
39208
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
|
|
39021
39209
|
showHint && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
39022
39210
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
39023
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
39211
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
39024
39212
|
] }) })
|
|
39025
39213
|
] }),
|
|
39026
39214
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -39048,6 +39236,8 @@ var init_EventHandlerBoard = __esm({
|
|
|
39048
39236
|
init_TraitStateViewer();
|
|
39049
39237
|
init_ObjectRulePanel();
|
|
39050
39238
|
init_EventLog();
|
|
39239
|
+
init_puzzleObject();
|
|
39240
|
+
init_boardEntity();
|
|
39051
39241
|
ENCOURAGEMENT_KEYS = [
|
|
39052
39242
|
"puzzle.tryAgain1",
|
|
39053
39243
|
"puzzle.tryAgain2",
|
|
@@ -39136,7 +39326,10 @@ var init_FeatureGridOrganism = __esm({
|
|
|
39136
39326
|
);
|
|
39137
39327
|
React85.useCallback(
|
|
39138
39328
|
(feature) => {
|
|
39139
|
-
eventBus.emit("UI:FEATURE_CLICK", {
|
|
39329
|
+
eventBus.emit("UI:FEATURE_CLICK", {
|
|
39330
|
+
id: String(feature.id ?? ""),
|
|
39331
|
+
href: String(feature.href ?? "")
|
|
39332
|
+
});
|
|
39140
39333
|
},
|
|
39141
39334
|
[eventBus]
|
|
39142
39335
|
);
|
|
@@ -39146,14 +39339,17 @@ var init_FeatureGridOrganism = __esm({
|
|
|
39146
39339
|
if (error) {
|
|
39147
39340
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
39148
39341
|
}
|
|
39149
|
-
const featureCards = items.map((feature) =>
|
|
39150
|
-
|
|
39151
|
-
|
|
39152
|
-
|
|
39153
|
-
|
|
39154
|
-
|
|
39155
|
-
|
|
39156
|
-
|
|
39342
|
+
const featureCards = items.map((feature) => {
|
|
39343
|
+
const href = feature.href != null ? String(feature.href) : void 0;
|
|
39344
|
+
return {
|
|
39345
|
+
icon: feature.icon != null ? String(feature.icon) : void 0,
|
|
39346
|
+
title: String(feature.title ?? ""),
|
|
39347
|
+
description: String(feature.description ?? ""),
|
|
39348
|
+
href,
|
|
39349
|
+
linkLabel: feature.linkLabel != null ? String(feature.linkLabel) : void 0,
|
|
39350
|
+
variant: href ? "interactive" : "bordered"
|
|
39351
|
+
};
|
|
39352
|
+
});
|
|
39157
39353
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
39158
39354
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
39159
39355
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
@@ -40471,22 +40667,24 @@ var init_HeroOrganism = __esm({
|
|
|
40471
40667
|
() => Array.isArray(entity) ? entity[0] : entity && typeof entity === "object" ? entity : void 0,
|
|
40472
40668
|
[entity]
|
|
40473
40669
|
);
|
|
40670
|
+
const primaryAction = resolved?.primaryAction;
|
|
40671
|
+
const secondaryAction = resolved?.secondaryAction;
|
|
40474
40672
|
const handlePrimaryClick = React85.useCallback(() => {
|
|
40475
|
-
if (
|
|
40673
|
+
if (primaryAction) {
|
|
40476
40674
|
eventBus.emit("UI:CTA_PRIMARY", {
|
|
40477
|
-
label:
|
|
40478
|
-
href:
|
|
40675
|
+
label: String(primaryAction.label ?? ""),
|
|
40676
|
+
href: String(primaryAction.href ?? "")
|
|
40479
40677
|
});
|
|
40480
40678
|
}
|
|
40481
|
-
}, [eventBus,
|
|
40679
|
+
}, [eventBus, primaryAction]);
|
|
40482
40680
|
const handleSecondaryClick = React85.useCallback(() => {
|
|
40483
|
-
if (
|
|
40681
|
+
if (secondaryAction) {
|
|
40484
40682
|
eventBus.emit("UI:CTA_SECONDARY", {
|
|
40485
|
-
label:
|
|
40486
|
-
href:
|
|
40683
|
+
label: String(secondaryAction.label ?? ""),
|
|
40684
|
+
href: String(secondaryAction.href ?? "")
|
|
40487
40685
|
});
|
|
40488
40686
|
}
|
|
40489
|
-
}, [eventBus,
|
|
40687
|
+
}, [eventBus, secondaryAction]);
|
|
40490
40688
|
if (isLoading) {
|
|
40491
40689
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
40492
40690
|
}
|
|
@@ -40496,17 +40694,19 @@ var init_HeroOrganism = __esm({
|
|
|
40496
40694
|
if (!resolved) {
|
|
40497
40695
|
return null;
|
|
40498
40696
|
}
|
|
40697
|
+
const imageRaw = resolved.image;
|
|
40698
|
+
const image = imageRaw ? { src: String(imageRaw.src ?? ""), alt: String(imageRaw.alt ?? "") } : void 0;
|
|
40499
40699
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
40500
40700
|
HeroSection,
|
|
40501
40701
|
{
|
|
40502
|
-
tag: resolved.tag,
|
|
40503
|
-
title: resolved.title,
|
|
40504
|
-
titleAccent: resolved.titleAccent,
|
|
40505
|
-
subtitle: resolved.subtitle,
|
|
40506
|
-
primaryAction:
|
|
40507
|
-
secondaryAction:
|
|
40508
|
-
installCommand: resolved.installCommand,
|
|
40509
|
-
image
|
|
40702
|
+
tag: resolved.tag != null ? String(resolved.tag) : void 0,
|
|
40703
|
+
title: String(resolved.title ?? ""),
|
|
40704
|
+
titleAccent: resolved.titleAccent != null ? String(resolved.titleAccent) : void 0,
|
|
40705
|
+
subtitle: String(resolved.subtitle ?? ""),
|
|
40706
|
+
primaryAction: primaryAction ? { label: String(primaryAction.label ?? ""), href: String(primaryAction.href ?? "") } : void 0,
|
|
40707
|
+
secondaryAction: secondaryAction ? { label: String(secondaryAction.label ?? ""), href: String(secondaryAction.href ?? "") } : void 0,
|
|
40708
|
+
installCommand: resolved.installCommand != null ? String(resolved.installCommand) : void 0,
|
|
40709
|
+
image,
|
|
40510
40710
|
imagePosition: resolved.imagePosition,
|
|
40511
40711
|
background: resolved.background,
|
|
40512
40712
|
className: cn(className),
|
|
@@ -40515,8 +40715,8 @@ var init_HeroOrganism = __esm({
|
|
|
40515
40715
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
40516
40716
|
_HeroClickInterceptor,
|
|
40517
40717
|
{
|
|
40518
|
-
hasPrimary: !!
|
|
40519
|
-
hasSecondary: !!
|
|
40718
|
+
hasPrimary: !!primaryAction,
|
|
40719
|
+
hasSecondary: !!secondaryAction,
|
|
40520
40720
|
onPrimaryClick: handlePrimaryClick,
|
|
40521
40721
|
onSecondaryClick: handleSecondaryClick
|
|
40522
40722
|
}
|
|
@@ -40745,7 +40945,7 @@ function formatValue3(value, fieldName) {
|
|
|
40745
40945
|
return String(value);
|
|
40746
40946
|
}
|
|
40747
40947
|
function formatFieldLabel2(fieldName) {
|
|
40748
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
40948
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
|
|
40749
40949
|
}
|
|
40750
40950
|
var STATUS_STYLES2, StatusBadge, ProgressIndicator, List3;
|
|
40751
40951
|
var init_List = __esm({
|
|
@@ -41592,20 +41792,22 @@ function NegotiatorBoard({
|
|
|
41592
41792
|
}) {
|
|
41593
41793
|
const { emit } = useEventBus();
|
|
41594
41794
|
const { t } = hooks.useTranslate();
|
|
41595
|
-
const resolved =
|
|
41795
|
+
const resolved = boardEntity(entity);
|
|
41596
41796
|
const [history, setHistory] = React85.useState([]);
|
|
41597
41797
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
41598
41798
|
const [showHint, setShowHint] = React85.useState(false);
|
|
41799
|
+
const totalRounds = num(resolved?.totalRounds);
|
|
41800
|
+
const targetScore = num(resolved?.targetScore);
|
|
41599
41801
|
const currentRound = history.length;
|
|
41600
|
-
const isComplete = currentRound >=
|
|
41802
|
+
const isComplete = currentRound >= totalRounds;
|
|
41601
41803
|
const playerTotal = history.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41602
41804
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
41603
|
-
const won = isComplete && playerTotal >=
|
|
41604
|
-
const actions = resolved?.actions
|
|
41605
|
-
const payoffMatrix = resolved?.payoffMatrix
|
|
41805
|
+
const won = isComplete && playerTotal >= targetScore;
|
|
41806
|
+
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
41807
|
+
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
41606
41808
|
const handleAction = React85.useCallback((actionId) => {
|
|
41607
41809
|
if (isComplete) return;
|
|
41608
|
-
const opponentAction = getOpponentAction(resolved?.opponentStrategy
|
|
41810
|
+
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
41609
41811
|
const payoff = payoffMatrix.find(
|
|
41610
41812
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
41611
41813
|
);
|
|
@@ -41618,42 +41820,46 @@ function NegotiatorBoard({
|
|
|
41618
41820
|
};
|
|
41619
41821
|
const newHistory = [...history, result];
|
|
41620
41822
|
setHistory(newHistory);
|
|
41621
|
-
if (newHistory.length >=
|
|
41823
|
+
if (newHistory.length >= totalRounds) {
|
|
41622
41824
|
const total = newHistory.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41623
|
-
if (total >=
|
|
41825
|
+
if (total >= targetScore) {
|
|
41624
41826
|
emit(`UI:${completeEvent}`, { success: true, score: total });
|
|
41625
41827
|
}
|
|
41626
|
-
if (newHistory.length >= 3 && resolved?.hint) {
|
|
41828
|
+
if (newHistory.length >= 3 && str(resolved?.hint)) {
|
|
41627
41829
|
setShowHint(true);
|
|
41628
41830
|
}
|
|
41629
41831
|
}
|
|
41630
|
-
}, [isComplete, resolved, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41832
|
+
}, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41631
41833
|
const handleReset = () => {
|
|
41632
41834
|
setHistory([]);
|
|
41633
41835
|
setShowHint(false);
|
|
41634
41836
|
};
|
|
41635
41837
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
41636
41838
|
if (!resolved) return null;
|
|
41839
|
+
const theme = resolved.theme ?? void 0;
|
|
41840
|
+
const themeBackground = theme?.background;
|
|
41841
|
+
const headerImage = str(resolved.headerImage);
|
|
41842
|
+
const hint = str(resolved.hint);
|
|
41637
41843
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
41638
41844
|
Box,
|
|
41639
41845
|
{
|
|
41640
41846
|
className,
|
|
41641
41847
|
style: {
|
|
41642
|
-
backgroundImage:
|
|
41848
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
41643
41849
|
backgroundSize: "cover",
|
|
41644
41850
|
backgroundPosition: "center"
|
|
41645
41851
|
},
|
|
41646
41852
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
41647
|
-
|
|
41853
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
41648
41854
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
41649
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
41650
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
41855
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
41856
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
41651
41857
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", children: [
|
|
41652
|
-
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(
|
|
41858
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(totalRounds) }) }),
|
|
41653
41859
|
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", children: [
|
|
41654
41860
|
t("negotiator.target"),
|
|
41655
41861
|
": ",
|
|
41656
|
-
|
|
41862
|
+
targetScore
|
|
41657
41863
|
] })
|
|
41658
41864
|
] })
|
|
41659
41865
|
] }) }),
|
|
@@ -41702,16 +41908,16 @@ function NegotiatorBoard({
|
|
|
41702
41908
|
] }) }),
|
|
41703
41909
|
isComplete && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
41704
41910
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: won ? "text-success" : "text-error" }),
|
|
41705
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? resolved.successMessage
|
|
41911
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? str(resolved.successMessage) || t("negotiator.success") : str(resolved.failMessage) || t("negotiator.failed") }),
|
|
41706
41912
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
41707
41913
|
t("negotiator.finalScore"),
|
|
41708
41914
|
": ",
|
|
41709
41915
|
playerTotal,
|
|
41710
41916
|
"/",
|
|
41711
|
-
|
|
41917
|
+
targetScore
|
|
41712
41918
|
] })
|
|
41713
41919
|
] }) }),
|
|
41714
|
-
showHint &&
|
|
41920
|
+
showHint && hint && !won && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
41715
41921
|
isComplete && !won && /* @__PURE__ */ jsxRuntime.jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
|
|
41716
41922
|
] })
|
|
41717
41923
|
}
|
|
@@ -41721,6 +41927,7 @@ var init_NegotiatorBoard = __esm({
|
|
|
41721
41927
|
"components/game/organisms/puzzles/negotiator/NegotiatorBoard.tsx"() {
|
|
41722
41928
|
init_atoms2();
|
|
41723
41929
|
init_useEventBus();
|
|
41930
|
+
init_boardEntity();
|
|
41724
41931
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
41725
41932
|
}
|
|
41726
41933
|
});
|
|
@@ -41756,13 +41963,13 @@ var init_PricingOrganism = __esm({
|
|
|
41756
41963
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
41757
41964
|
}
|
|
41758
41965
|
const plans = items.map((plan) => ({
|
|
41759
|
-
name: plan.name,
|
|
41760
|
-
price: plan.price,
|
|
41761
|
-
description: plan.description,
|
|
41762
|
-
features: plan.features,
|
|
41763
|
-
action: { label: plan.actionLabel, href: plan.actionHref },
|
|
41764
|
-
highlighted: plan.highlighted,
|
|
41765
|
-
badge: plan.badge
|
|
41966
|
+
name: String(plan.name ?? ""),
|
|
41967
|
+
price: String(plan.price ?? ""),
|
|
41968
|
+
description: plan.description != null ? String(plan.description) : void 0,
|
|
41969
|
+
features: (plan.features ?? []).map((f3) => String(f3)),
|
|
41970
|
+
action: { label: String(plan.actionLabel ?? ""), href: String(plan.actionHref ?? "") },
|
|
41971
|
+
highlighted: Boolean(plan.highlighted),
|
|
41972
|
+
badge: plan.badge != null ? String(plan.badge) : void 0
|
|
41766
41973
|
}));
|
|
41767
41974
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
41768
41975
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -43833,16 +44040,20 @@ function SequencerBoard({
|
|
|
43833
44040
|
}) {
|
|
43834
44041
|
const { emit } = useEventBus();
|
|
43835
44042
|
const { t } = hooks.useTranslate();
|
|
43836
|
-
const resolved =
|
|
44043
|
+
const resolved = boardEntity(entity);
|
|
44044
|
+
const maxSlots = num(resolved?.maxSlots);
|
|
44045
|
+
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
44046
|
+
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
44047
|
+
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
43837
44048
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
43838
44049
|
const [slots, setSlots] = React85.useState(
|
|
43839
|
-
() => Array.from({ length:
|
|
44050
|
+
() => Array.from({ length: maxSlots }, () => void 0)
|
|
43840
44051
|
);
|
|
43841
44052
|
const [playState, setPlayState] = React85.useState("idle");
|
|
43842
44053
|
const [currentStep, setCurrentStep] = React85.useState(-1);
|
|
43843
44054
|
const [attempts, setAttempts] = React85.useState(0);
|
|
43844
44055
|
const [slotFeedback, setSlotFeedback] = React85.useState(
|
|
43845
|
-
() => Array.from({ length:
|
|
44056
|
+
() => Array.from({ length: maxSlots }, () => null)
|
|
43846
44057
|
);
|
|
43847
44058
|
const timerRef = React85.useRef(null);
|
|
43848
44059
|
React85.useEffect(() => () => {
|
|
@@ -43876,17 +44087,17 @@ function SequencerBoard({
|
|
|
43876
44087
|
}, [emit]);
|
|
43877
44088
|
const handleReset = React85.useCallback(() => {
|
|
43878
44089
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
43879
|
-
setSlots(Array.from({ length:
|
|
44090
|
+
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
43880
44091
|
setPlayState("idle");
|
|
43881
44092
|
setCurrentStep(-1);
|
|
43882
44093
|
setAttempts(0);
|
|
43883
|
-
setSlotFeedback(Array.from({ length:
|
|
43884
|
-
}, [
|
|
44094
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
44095
|
+
}, [maxSlots]);
|
|
43885
44096
|
const filledSlots = slots.filter((s) => !!s);
|
|
43886
44097
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
43887
44098
|
const handlePlay = React85.useCallback(() => {
|
|
43888
44099
|
if (!canPlay) return;
|
|
43889
|
-
setSlotFeedback(Array.from({ length:
|
|
44100
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
43890
44101
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
43891
44102
|
const sequence = slots.map((s) => s?.id || "");
|
|
43892
44103
|
if (playEvent) {
|
|
@@ -43897,10 +44108,10 @@ function SequencerBoard({
|
|
|
43897
44108
|
let step = 0;
|
|
43898
44109
|
const advance = () => {
|
|
43899
44110
|
step++;
|
|
43900
|
-
if (step >=
|
|
44111
|
+
if (step >= maxSlots) {
|
|
43901
44112
|
const playerSeq = slots.map((s) => s?.id);
|
|
43902
44113
|
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
43903
|
-
const success =
|
|
44114
|
+
const success = solutions.some(
|
|
43904
44115
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
43905
44116
|
);
|
|
43906
44117
|
if (success) {
|
|
@@ -43912,7 +44123,7 @@ function SequencerBoard({
|
|
|
43912
44123
|
}
|
|
43913
44124
|
} else {
|
|
43914
44125
|
setAttempts((prev) => prev + 1);
|
|
43915
|
-
const feedback = computeSlotFeedback(playerSeq,
|
|
44126
|
+
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
43916
44127
|
setSlotFeedback(feedback);
|
|
43917
44128
|
setPlayState("idle");
|
|
43918
44129
|
setCurrentStep(-1);
|
|
@@ -43930,10 +44141,10 @@ function SequencerBoard({
|
|
|
43930
44141
|
}
|
|
43931
44142
|
};
|
|
43932
44143
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
43933
|
-
}, [canPlay, slots,
|
|
44144
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
43934
44145
|
const machine = {
|
|
43935
|
-
name: resolved?.title
|
|
43936
|
-
description: resolved?.description
|
|
44146
|
+
name: str(resolved?.title),
|
|
44147
|
+
description: str(resolved?.description),
|
|
43937
44148
|
states: slots.map((s, i) => stepLabel(s, i)),
|
|
43938
44149
|
currentState: currentStep >= 0 ? stepLabel(slots[currentStep], currentStep) : "__idle__",
|
|
43939
44150
|
transitions: slots.slice(0, -1).map((s, i) => ({
|
|
@@ -43942,37 +44153,41 @@ function SequencerBoard({
|
|
|
43942
44153
|
event: "NEXT"
|
|
43943
44154
|
}))
|
|
43944
44155
|
};
|
|
43945
|
-
const usedIds =
|
|
43946
|
-
const
|
|
44156
|
+
const usedIds = !allowDuplicates ? slots.filter(Boolean).map((s) => s?.id || "") : [];
|
|
44157
|
+
const hint = str(resolved?.hint);
|
|
44158
|
+
const showHint = attempts >= 3 && !!hint;
|
|
43947
44159
|
const hasFeedback = slotFeedback.some((f3) => f3 !== null);
|
|
43948
44160
|
const correctCount = slotFeedback.filter((f3) => f3 === "correct").length;
|
|
43949
44161
|
const encourageKey = ENCOURAGEMENT_KEYS2[Math.min(attempts - 1, ENCOURAGEMENT_KEYS2.length - 1)] ?? ENCOURAGEMENT_KEYS2[0];
|
|
43950
44162
|
if (!resolved) return null;
|
|
44163
|
+
const theme = resolved.theme ?? void 0;
|
|
44164
|
+
const themeBackground = theme?.background;
|
|
44165
|
+
const headerImage = str(resolved.headerImage);
|
|
43951
44166
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
43952
44167
|
VStack,
|
|
43953
44168
|
{
|
|
43954
44169
|
className: cn("p-4 gap-6", className),
|
|
43955
44170
|
style: {
|
|
43956
|
-
backgroundImage:
|
|
44171
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
43957
44172
|
backgroundSize: "cover",
|
|
43958
44173
|
backgroundPosition: "center"
|
|
43959
44174
|
},
|
|
43960
44175
|
children: [
|
|
43961
|
-
|
|
44176
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
43962
44177
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
43963
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
43964
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description })
|
|
44178
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
44179
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) })
|
|
43965
44180
|
] }),
|
|
43966
44181
|
showHint && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
43967
44182
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
43968
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
44183
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
43969
44184
|
] }) }),
|
|
43970
44185
|
filledSlots.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
|
|
43971
44186
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
43972
44187
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
43973
44188
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
43974
44189
|
hasFeedback && playState === "idle" && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
43975
|
-
`${correctCount}/${
|
|
44190
|
+
`${correctCount}/${maxSlots} `,
|
|
43976
44191
|
"\u2705"
|
|
43977
44192
|
] })
|
|
43978
44193
|
] }),
|
|
@@ -43980,7 +44195,7 @@ function SequencerBoard({
|
|
|
43980
44195
|
SequenceBar,
|
|
43981
44196
|
{
|
|
43982
44197
|
slots,
|
|
43983
|
-
maxSlots
|
|
44198
|
+
maxSlots,
|
|
43984
44199
|
onSlotDrop: handleSlotDrop,
|
|
43985
44200
|
onSlotRemove: handleSlotRemove,
|
|
43986
44201
|
playing: playState === "playing",
|
|
@@ -43994,15 +44209,15 @@ function SequencerBoard({
|
|
|
43994
44209
|
playState !== "playing" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
43995
44210
|
ActionPalette,
|
|
43996
44211
|
{
|
|
43997
|
-
actions:
|
|
44212
|
+
actions: availableActions,
|
|
43998
44213
|
usedActionIds: usedIds,
|
|
43999
|
-
allowDuplicates
|
|
44214
|
+
allowDuplicates,
|
|
44000
44215
|
categoryColors,
|
|
44001
44216
|
label: t("sequencer.dragActions")
|
|
44002
44217
|
}
|
|
44003
44218
|
),
|
|
44004
44219
|
hasFeedback && playState === "idle" && attempts > 0 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
|
|
44005
|
-
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("sequencer.levelComplete") }) }),
|
|
44220
|
+
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("sequencer.levelComplete") }) }),
|
|
44006
44221
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
44007
44222
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44008
44223
|
Button,
|
|
@@ -44026,6 +44241,7 @@ var init_SequencerBoard = __esm({
|
|
|
44026
44241
|
init_cn();
|
|
44027
44242
|
init_useEventBus();
|
|
44028
44243
|
init_TraitStateViewer();
|
|
44244
|
+
init_boardEntity();
|
|
44029
44245
|
init_SequenceBar();
|
|
44030
44246
|
init_ActionPalette();
|
|
44031
44247
|
ENCOURAGEMENT_KEYS2 = [
|
|
@@ -44075,18 +44291,21 @@ var init_ShowcaseOrganism = __esm({
|
|
|
44075
44291
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
44076
44292
|
subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", color: "muted", align: "center", className: "max-w-2xl", children: subtitle })
|
|
44077
44293
|
] }),
|
|
44078
|
-
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) =>
|
|
44079
|
-
|
|
44080
|
-
|
|
44081
|
-
|
|
44082
|
-
|
|
44083
|
-
|
|
44084
|
-
|
|
44085
|
-
|
|
44086
|
-
|
|
44087
|
-
|
|
44088
|
-
|
|
44089
|
-
|
|
44294
|
+
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) => {
|
|
44295
|
+
const imageRaw = item.image;
|
|
44296
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44297
|
+
ShowcaseCard,
|
|
44298
|
+
{
|
|
44299
|
+
title: String(item.title ?? ""),
|
|
44300
|
+
description: item.description != null ? String(item.description) : void 0,
|
|
44301
|
+
image: { src: String(imageRaw?.src ?? ""), alt: String(imageRaw?.alt ?? "") },
|
|
44302
|
+
href: item.href != null ? String(item.href) : void 0,
|
|
44303
|
+
badge: item.badge != null ? String(item.badge) : void 0,
|
|
44304
|
+
accentColor: item.accentColor != null ? String(item.accentColor) : void 0
|
|
44305
|
+
},
|
|
44306
|
+
String(item.id ?? "")
|
|
44307
|
+
);
|
|
44308
|
+
}) })
|
|
44090
44309
|
] });
|
|
44091
44310
|
};
|
|
44092
44311
|
ShowcaseOrganism.displayName = "ShowcaseOrganism";
|
|
@@ -44454,8 +44673,8 @@ function SimulatorBoard({
|
|
|
44454
44673
|
}) {
|
|
44455
44674
|
const { emit } = useEventBus();
|
|
44456
44675
|
const { t } = hooks.useTranslate();
|
|
44457
|
-
const resolved =
|
|
44458
|
-
const parameters = resolved?.parameters
|
|
44676
|
+
const resolved = boardEntity(entity);
|
|
44677
|
+
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
44459
44678
|
const [values, setValues] = React85.useState(() => {
|
|
44460
44679
|
const init = {};
|
|
44461
44680
|
for (const p2 of parameters) {
|
|
@@ -44469,15 +44688,15 @@ function SimulatorBoard({
|
|
|
44469
44688
|
const [showHint, setShowHint] = React85.useState(false);
|
|
44470
44689
|
const computeOutput = React85.useCallback((params) => {
|
|
44471
44690
|
try {
|
|
44472
|
-
const fn = new Function("params", `return (${resolved?.computeExpression})`);
|
|
44691
|
+
const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
|
|
44473
44692
|
return fn(params);
|
|
44474
44693
|
} catch {
|
|
44475
44694
|
return 0;
|
|
44476
44695
|
}
|
|
44477
44696
|
}, [resolved?.computeExpression]);
|
|
44478
44697
|
const output = React85.useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
|
|
44479
|
-
const targetValue = resolved?.targetValue
|
|
44480
|
-
const targetTolerance = resolved?.targetTolerance
|
|
44698
|
+
const targetValue = num(resolved?.targetValue);
|
|
44699
|
+
const targetTolerance = num(resolved?.targetTolerance);
|
|
44481
44700
|
const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
|
|
44482
44701
|
const handleParameterChange = (id, value) => {
|
|
44483
44702
|
if (submitted) return;
|
|
@@ -44492,7 +44711,7 @@ function SimulatorBoard({
|
|
|
44492
44711
|
};
|
|
44493
44712
|
const handleReset = () => {
|
|
44494
44713
|
setSubmitted(false);
|
|
44495
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
44714
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
44496
44715
|
setShowHint(true);
|
|
44497
44716
|
}
|
|
44498
44717
|
};
|
|
@@ -44507,20 +44726,26 @@ function SimulatorBoard({
|
|
|
44507
44726
|
setShowHint(false);
|
|
44508
44727
|
};
|
|
44509
44728
|
if (!resolved) return null;
|
|
44729
|
+
const theme = resolved.theme ?? void 0;
|
|
44730
|
+
const themeBackground = theme?.background;
|
|
44731
|
+
const headerImage = str(resolved.headerImage);
|
|
44732
|
+
const hint = str(resolved.hint);
|
|
44733
|
+
const outputLabel = str(resolved.outputLabel);
|
|
44734
|
+
const outputUnit = str(resolved.outputUnit);
|
|
44510
44735
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44511
44736
|
Box,
|
|
44512
44737
|
{
|
|
44513
44738
|
className,
|
|
44514
44739
|
style: {
|
|
44515
|
-
backgroundImage:
|
|
44740
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
44516
44741
|
backgroundSize: "cover",
|
|
44517
44742
|
backgroundPosition: "center"
|
|
44518
44743
|
},
|
|
44519
44744
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
44520
|
-
|
|
44745
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
44521
44746
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
44522
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
44523
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
44747
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
44748
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
44524
44749
|
] }) }),
|
|
44525
44750
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
44526
44751
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
@@ -44561,28 +44786,28 @@ function SimulatorBoard({
|
|
|
44561
44786
|
] }, param.id))
|
|
44562
44787
|
] }) }),
|
|
44563
44788
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
44564
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children:
|
|
44789
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
44565
44790
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", weight: "bold", children: [
|
|
44566
44791
|
output.toFixed(2),
|
|
44567
44792
|
" ",
|
|
44568
|
-
|
|
44793
|
+
outputUnit
|
|
44569
44794
|
] }),
|
|
44570
44795
|
submitted && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
44571
44796
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: isCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
|
|
44572
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? resolved.successMessage
|
|
44797
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
|
|
44573
44798
|
] }),
|
|
44574
44799
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44575
44800
|
t("simulator.target"),
|
|
44576
44801
|
": ",
|
|
44577
44802
|
targetValue,
|
|
44578
44803
|
" ",
|
|
44579
|
-
|
|
44804
|
+
outputUnit,
|
|
44580
44805
|
" (\xB1",
|
|
44581
44806
|
targetTolerance,
|
|
44582
44807
|
")"
|
|
44583
44808
|
] })
|
|
44584
44809
|
] }) }),
|
|
44585
|
-
showHint &&
|
|
44810
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
44586
44811
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
44587
44812
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
|
|
44588
44813
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
@@ -44601,6 +44826,7 @@ var init_SimulatorBoard = __esm({
|
|
|
44601
44826
|
"components/game/organisms/puzzles/simulator/SimulatorBoard.tsx"() {
|
|
44602
44827
|
init_atoms2();
|
|
44603
44828
|
init_useEventBus();
|
|
44829
|
+
init_boardEntity();
|
|
44604
44830
|
SimulatorBoard.displayName = "SimulatorBoard";
|
|
44605
44831
|
}
|
|
44606
44832
|
});
|
|
@@ -45026,22 +45252,25 @@ function VariablePanel({
|
|
|
45026
45252
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-3 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
45027
45253
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
45028
45254
|
variables.map((v) => {
|
|
45029
|
-
const
|
|
45030
|
-
const
|
|
45031
|
-
const
|
|
45255
|
+
const name = v.name == null ? "" : String(v.name);
|
|
45256
|
+
const value = numField(v.value);
|
|
45257
|
+
const max = numField(v.max, 100);
|
|
45258
|
+
const min = numField(v.min, 0);
|
|
45259
|
+
const unit = v.unit == null ? "" : String(v.unit);
|
|
45260
|
+
const pct = Math.round((value - min) / (max - min) * 100);
|
|
45032
45261
|
const isHigh = pct > 80;
|
|
45033
45262
|
const isLow = pct < 20;
|
|
45034
45263
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
45035
45264
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
45036
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children:
|
|
45265
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children: name }),
|
|
45037
45266
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: cn(
|
|
45038
45267
|
isHigh ? "text-error" : isLow ? "text-warning" : "text-foreground"
|
|
45039
45268
|
), children: [
|
|
45040
|
-
|
|
45041
|
-
|
|
45269
|
+
value,
|
|
45270
|
+
unit,
|
|
45042
45271
|
" / ",
|
|
45043
45272
|
max,
|
|
45044
|
-
|
|
45273
|
+
unit
|
|
45045
45274
|
] })
|
|
45046
45275
|
] }),
|
|
45047
45276
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -45052,14 +45281,19 @@ function VariablePanel({
|
|
|
45052
45281
|
size: "sm"
|
|
45053
45282
|
}
|
|
45054
45283
|
)
|
|
45055
|
-
] },
|
|
45284
|
+
] }, name);
|
|
45056
45285
|
})
|
|
45057
45286
|
] });
|
|
45058
45287
|
}
|
|
45288
|
+
var numField;
|
|
45059
45289
|
var init_VariablePanel = __esm({
|
|
45060
45290
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
45061
45291
|
init_atoms2();
|
|
45062
45292
|
init_cn();
|
|
45293
|
+
numField = (v, fallback = 0) => {
|
|
45294
|
+
const n = Number(v);
|
|
45295
|
+
return Number.isFinite(n) ? n : fallback;
|
|
45296
|
+
};
|
|
45063
45297
|
VariablePanel.displayName = "VariablePanel";
|
|
45064
45298
|
}
|
|
45065
45299
|
});
|
|
@@ -45086,14 +45320,21 @@ function StateArchitectBoard({
|
|
|
45086
45320
|
}) {
|
|
45087
45321
|
const { emit } = useEventBus();
|
|
45088
45322
|
const { t } = hooks.useTranslate();
|
|
45089
|
-
const resolved =
|
|
45090
|
-
const
|
|
45323
|
+
const resolved = boardEntity(entity);
|
|
45324
|
+
const entityStates = Array.isArray(resolved?.states) ? resolved.states : [];
|
|
45325
|
+
const initialState = str(resolved?.initialState);
|
|
45326
|
+
const entityName = str(resolved?.entityName);
|
|
45327
|
+
const availableEvents = Array.isArray(resolved?.availableEvents) ? resolved.availableEvents : [];
|
|
45328
|
+
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
45329
|
+
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
45330
|
+
const entityVariables = rows(resolved?.variables);
|
|
45331
|
+
const [transitions, setTransitions] = React85.useState(entityTransitions);
|
|
45091
45332
|
const [headerError, setHeaderError] = React85.useState(false);
|
|
45092
45333
|
const [playState, setPlayState] = React85.useState("editing");
|
|
45093
|
-
const [currentState, setCurrentState] = React85.useState(
|
|
45334
|
+
const [currentState, setCurrentState] = React85.useState(initialState);
|
|
45094
45335
|
const [selectedState, setSelectedState] = React85.useState(null);
|
|
45095
45336
|
const [testResults, setTestResults] = React85.useState([]);
|
|
45096
|
-
const [variables, setVariables] = React85.useState(
|
|
45337
|
+
const [variables, setVariables] = React85.useState(() => [...entityVariables]);
|
|
45097
45338
|
const [attempts, setAttempts] = React85.useState(0);
|
|
45098
45339
|
const timerRef = React85.useRef(null);
|
|
45099
45340
|
const [addingFrom, setAddingFrom] = React85.useState(null);
|
|
@@ -45102,12 +45343,12 @@ function StateArchitectBoard({
|
|
|
45102
45343
|
}, []);
|
|
45103
45344
|
const GRAPH_W = 500;
|
|
45104
45345
|
const GRAPH_H = 400;
|
|
45105
|
-
const positions = React85.useMemo(() => layoutStates(
|
|
45346
|
+
const positions = React85.useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
45106
45347
|
const handleStateClick = React85.useCallback((state) => {
|
|
45107
45348
|
if (playState !== "editing") return;
|
|
45108
45349
|
if (addingFrom) {
|
|
45109
45350
|
if (addingFrom !== state) {
|
|
45110
|
-
const event =
|
|
45351
|
+
const event = availableEvents[0] || "EVENT";
|
|
45111
45352
|
const newTrans = {
|
|
45112
45353
|
id: `t-${nextTransId++}`,
|
|
45113
45354
|
from: addingFrom,
|
|
@@ -45120,7 +45361,7 @@ function StateArchitectBoard({
|
|
|
45120
45361
|
} else {
|
|
45121
45362
|
setSelectedState(state);
|
|
45122
45363
|
}
|
|
45123
|
-
}, [playState, addingFrom,
|
|
45364
|
+
}, [playState, addingFrom, availableEvents]);
|
|
45124
45365
|
const handleStartAddTransition = React85.useCallback(() => {
|
|
45125
45366
|
if (!selectedState) return;
|
|
45126
45367
|
setAddingFrom(selectedState);
|
|
@@ -45129,9 +45370,9 @@ function StateArchitectBoard({
|
|
|
45129
45370
|
setTransitions((prev) => prev.filter((t2) => t2.id !== transId));
|
|
45130
45371
|
}, []);
|
|
45131
45372
|
const machine = React85.useMemo(() => ({
|
|
45132
|
-
name:
|
|
45133
|
-
description: resolved?.description
|
|
45134
|
-
states:
|
|
45373
|
+
name: entityName,
|
|
45374
|
+
description: str(resolved?.description),
|
|
45375
|
+
states: entityStates,
|
|
45135
45376
|
currentState,
|
|
45136
45377
|
transitions: transitions.map((t2) => ({
|
|
45137
45378
|
from: t2.from,
|
|
@@ -45139,7 +45380,7 @@ function StateArchitectBoard({
|
|
|
45139
45380
|
event: t2.event,
|
|
45140
45381
|
guardHint: t2.guardHint
|
|
45141
45382
|
}))
|
|
45142
|
-
}), [resolved, currentState, transitions]);
|
|
45383
|
+
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
45143
45384
|
const handleTest = React85.useCallback(() => {
|
|
45144
45385
|
if (playState !== "editing") return;
|
|
45145
45386
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
@@ -45148,7 +45389,7 @@ function StateArchitectBoard({
|
|
|
45148
45389
|
const results = [];
|
|
45149
45390
|
let testIdx = 0;
|
|
45150
45391
|
const runNextTest = () => {
|
|
45151
|
-
if (testIdx >=
|
|
45392
|
+
if (testIdx >= testCases.length) {
|
|
45152
45393
|
const allPassed = results.every((r) => r.passed);
|
|
45153
45394
|
setPlayState(allPassed ? "success" : "fail");
|
|
45154
45395
|
setTestResults(results);
|
|
@@ -45163,9 +45404,9 @@ function StateArchitectBoard({
|
|
|
45163
45404
|
}
|
|
45164
45405
|
return;
|
|
45165
45406
|
}
|
|
45166
|
-
const testCase =
|
|
45407
|
+
const testCase = testCases[testIdx];
|
|
45167
45408
|
if (!testCase) return;
|
|
45168
|
-
let state =
|
|
45409
|
+
let state = initialState;
|
|
45169
45410
|
for (const event of testCase.events) {
|
|
45170
45411
|
const trans = transitions.find((t2) => t2.from === state && t2.event === event);
|
|
45171
45412
|
if (trans) {
|
|
@@ -45183,53 +45424,57 @@ function StateArchitectBoard({
|
|
|
45183
45424
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
45184
45425
|
};
|
|
45185
45426
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
45186
|
-
}, [playState, transitions,
|
|
45427
|
+
}, [playState, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
45187
45428
|
const handleTryAgain = React85.useCallback(() => {
|
|
45188
45429
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45189
45430
|
setPlayState("editing");
|
|
45190
|
-
setCurrentState(
|
|
45431
|
+
setCurrentState(initialState);
|
|
45191
45432
|
setTestResults([]);
|
|
45192
|
-
}, [
|
|
45433
|
+
}, [initialState]);
|
|
45193
45434
|
const handleReset = React85.useCallback(() => {
|
|
45194
45435
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45195
|
-
setTransitions(
|
|
45436
|
+
setTransitions(entityTransitions);
|
|
45196
45437
|
setPlayState("editing");
|
|
45197
|
-
setCurrentState(
|
|
45438
|
+
setCurrentState(initialState);
|
|
45198
45439
|
setTestResults([]);
|
|
45199
|
-
setVariables(
|
|
45440
|
+
setVariables([...entityVariables]);
|
|
45200
45441
|
setSelectedState(null);
|
|
45201
45442
|
setAddingFrom(null);
|
|
45202
45443
|
setAttempts(0);
|
|
45203
|
-
}, [
|
|
45444
|
+
}, [entityTransitions, initialState, entityVariables]);
|
|
45204
45445
|
const codeData = React85.useMemo(() => ({
|
|
45205
|
-
name:
|
|
45206
|
-
states:
|
|
45207
|
-
initialState
|
|
45446
|
+
name: entityName,
|
|
45447
|
+
states: entityStates,
|
|
45448
|
+
initialState,
|
|
45208
45449
|
transitions: transitions.map((t2) => ({
|
|
45209
45450
|
from: t2.from,
|
|
45210
45451
|
to: t2.to,
|
|
45211
45452
|
event: t2.event,
|
|
45212
45453
|
...t2.guardHint ? { guard: t2.guardHint } : {}
|
|
45213
45454
|
}))
|
|
45214
|
-
}), [
|
|
45455
|
+
}), [entityName, entityStates, initialState, transitions]);
|
|
45215
45456
|
if (!resolved) return null;
|
|
45457
|
+
const theme = resolved.theme ?? void 0;
|
|
45458
|
+
const themeBackground = theme?.background;
|
|
45459
|
+
const headerImage = str(resolved.headerImage);
|
|
45460
|
+
const hint = str(resolved.hint);
|
|
45216
45461
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
45217
45462
|
VStack,
|
|
45218
45463
|
{
|
|
45219
45464
|
className: cn("p-4 gap-6", className),
|
|
45220
45465
|
style: {
|
|
45221
|
-
backgroundImage:
|
|
45466
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
45222
45467
|
backgroundSize: "cover",
|
|
45223
45468
|
backgroundPosition: "center"
|
|
45224
45469
|
},
|
|
45225
45470
|
children: [
|
|
45226
|
-
|
|
45471
|
+
headerImage && !headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
45227
45472
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
45228
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
45229
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
45473
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
45474
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
45230
45475
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
|
|
45231
45476
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
|
|
45232
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children:
|
|
45477
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: hint })
|
|
45233
45478
|
] })
|
|
45234
45479
|
] }),
|
|
45235
45480
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
|
|
@@ -45277,14 +45522,14 @@ function StateArchitectBoard({
|
|
|
45277
45522
|
]
|
|
45278
45523
|
}
|
|
45279
45524
|
),
|
|
45280
|
-
|
|
45525
|
+
entityStates.map((state) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45281
45526
|
StateNode2,
|
|
45282
45527
|
{
|
|
45283
45528
|
name: state,
|
|
45284
45529
|
position: positions[state],
|
|
45285
45530
|
isCurrent: state === currentState,
|
|
45286
45531
|
isSelected: state === selectedState,
|
|
45287
|
-
isInitial: state ===
|
|
45532
|
+
isInitial: state === initialState,
|
|
45288
45533
|
onClick: () => handleStateClick(state)
|
|
45289
45534
|
},
|
|
45290
45535
|
state
|
|
@@ -45331,7 +45576,7 @@ function StateArchitectBoard({
|
|
|
45331
45576
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45332
45577
|
VariablePanel,
|
|
45333
45578
|
{
|
|
45334
|
-
entityName
|
|
45579
|
+
entityName,
|
|
45335
45580
|
variables
|
|
45336
45581
|
}
|
|
45337
45582
|
),
|
|
@@ -45346,12 +45591,12 @@ function StateArchitectBoard({
|
|
|
45346
45591
|
resolved.showCodeView !== false && /* @__PURE__ */ jsxRuntime.jsx(CodeView, { data: codeData, label: "View Code" })
|
|
45347
45592
|
] })
|
|
45348
45593
|
] }),
|
|
45349
|
-
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("stateArchitect.allPassed") }) }),
|
|
45594
|
+
playState === "success" && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("stateArchitect.allPassed") }) }),
|
|
45350
45595
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
45351
45596
|
/* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
|
|
45352
|
-
attempts >= 3 &&
|
|
45597
|
+
attempts >= 3 && hint && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
45353
45598
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
45354
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
45599
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
45355
45600
|
] }) })
|
|
45356
45601
|
] }),
|
|
45357
45602
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -45381,6 +45626,7 @@ var init_StateArchitectBoard = __esm({
|
|
|
45381
45626
|
init_TransitionArrow();
|
|
45382
45627
|
init_VariablePanel();
|
|
45383
45628
|
init_CodeView();
|
|
45629
|
+
init_boardEntity();
|
|
45384
45630
|
ENCOURAGEMENT_KEYS3 = [
|
|
45385
45631
|
"puzzle.tryAgain1",
|
|
45386
45632
|
"puzzle.tryAgain2",
|
|
@@ -45417,8 +45663,8 @@ var init_StatsOrganism = __esm({
|
|
|
45417
45663
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
45418
45664
|
}
|
|
45419
45665
|
const stats = items.map((item) => ({
|
|
45420
|
-
value: item.value,
|
|
45421
|
-
label: item.label
|
|
45666
|
+
value: String(item.value ?? ""),
|
|
45667
|
+
label: String(item.label ?? "")
|
|
45422
45668
|
}));
|
|
45423
45669
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
45424
45670
|
StatsGrid,
|
|
@@ -45464,10 +45710,10 @@ var init_StepFlowOrganism = __esm({
|
|
|
45464
45710
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
45465
45711
|
}
|
|
45466
45712
|
const steps = items.map((item) => ({
|
|
45467
|
-
number: item.number,
|
|
45468
|
-
title: item.title,
|
|
45469
|
-
description: item.description,
|
|
45470
|
-
icon: item.icon
|
|
45713
|
+
number: item.number != null ? Number(item.number) : void 0,
|
|
45714
|
+
title: String(item.title ?? ""),
|
|
45715
|
+
description: String(item.description ?? ""),
|
|
45716
|
+
icon: item.icon != null ? String(item.icon) : void 0
|
|
45471
45717
|
}));
|
|
45472
45718
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
45473
45719
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -45640,13 +45886,13 @@ var init_TeamOrganism = __esm({
|
|
|
45640
45886
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((member) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45641
45887
|
TeamCard,
|
|
45642
45888
|
{
|
|
45643
|
-
name: member.name,
|
|
45644
|
-
nameAr: member.nameAr,
|
|
45645
|
-
role: member.role,
|
|
45646
|
-
bio: member.bio,
|
|
45647
|
-
avatar: member.avatar
|
|
45889
|
+
name: String(member.name ?? ""),
|
|
45890
|
+
nameAr: member.nameAr != null ? String(member.nameAr) : void 0,
|
|
45891
|
+
role: String(member.role ?? ""),
|
|
45892
|
+
bio: String(member.bio ?? ""),
|
|
45893
|
+
avatar: member.avatar != null ? String(member.avatar) : void 0
|
|
45648
45894
|
},
|
|
45649
|
-
member.id
|
|
45895
|
+
String(member.id ?? "")
|
|
45650
45896
|
)) })
|
|
45651
45897
|
] });
|
|
45652
45898
|
};
|
|
@@ -45883,8 +46129,8 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45883
46129
|
const [turn, setTurn] = React85.useState(1);
|
|
45884
46130
|
const [gameResult, setGameResult] = React85.useState(null);
|
|
45885
46131
|
const checkGameEnd = React85.useCallback((currentUnits) => {
|
|
45886
|
-
const pa = currentUnits.filter((u) => u
|
|
45887
|
-
const ea = currentUnits.filter((u) => u
|
|
46132
|
+
const pa = currentUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
46133
|
+
const ea = currentUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
45888
46134
|
if (pa.length === 0) {
|
|
45889
46135
|
setGameResult("defeat");
|
|
45890
46136
|
setPhase("game_over");
|
|
@@ -45902,34 +46148,36 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45902
46148
|
}
|
|
45903
46149
|
}, [onGameEnd, gameEndEvent, eventBus]);
|
|
45904
46150
|
const handleUnitClick = React85.useCallback((unitId) => {
|
|
45905
|
-
const unit = units.find((u) => u.id === unitId);
|
|
46151
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
45906
46152
|
if (!unit) return;
|
|
45907
46153
|
if (unitClickEvent) {
|
|
45908
46154
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
45909
46155
|
}
|
|
45910
46156
|
if (phase === "observation" || phase === "selection") {
|
|
45911
|
-
if (unit
|
|
46157
|
+
if (unitTeam(unit) === "player") {
|
|
45912
46158
|
setSelectedUnitId(unitId);
|
|
45913
46159
|
setPhase("movement");
|
|
45914
46160
|
}
|
|
45915
46161
|
} else if (phase === "action") {
|
|
45916
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
46162
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45917
46163
|
if (!selectedUnit) return;
|
|
45918
|
-
if (unit
|
|
45919
|
-
const
|
|
45920
|
-
const
|
|
46164
|
+
if (unitTeam(unit) === "enemy") {
|
|
46165
|
+
const up = unitPosition(unit);
|
|
46166
|
+
const sp = unitPosition(selectedUnit);
|
|
46167
|
+
const dx = Math.abs(up.x - sp.x);
|
|
46168
|
+
const dy = Math.abs(up.y - sp.y);
|
|
45921
46169
|
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
45922
|
-
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
|
|
45923
|
-
const newHealth = Math.max(0, unit
|
|
46170
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
46171
|
+
const newHealth = Math.max(0, unitHealth(unit) - damage);
|
|
45924
46172
|
const updatedUnits = units.map(
|
|
45925
|
-
(u) => u.id === unit.id ? { ...u, health: newHealth } : u
|
|
46173
|
+
(u) => str(u.id) === str(unit.id) ? { ...u, health: newHealth } : u
|
|
45926
46174
|
);
|
|
45927
46175
|
setUnits(updatedUnits);
|
|
45928
46176
|
onAttack?.(selectedUnit, unit, damage);
|
|
45929
46177
|
if (attackEvent) {
|
|
45930
46178
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
45931
|
-
attackerId: selectedUnit.id,
|
|
45932
|
-
targetId: unit.id,
|
|
46179
|
+
attackerId: str(selectedUnit.id),
|
|
46180
|
+
targetId: str(unit.id),
|
|
45933
46181
|
damage
|
|
45934
46182
|
});
|
|
45935
46183
|
}
|
|
@@ -45946,16 +46194,20 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45946
46194
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
45947
46195
|
}
|
|
45948
46196
|
if (phase === "movement" && selectedUnitId) {
|
|
45949
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
46197
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45950
46198
|
if (!selectedUnit) return;
|
|
45951
|
-
const
|
|
45952
|
-
const
|
|
46199
|
+
const sp = unitPosition(selectedUnit);
|
|
46200
|
+
const dx = Math.abs(x - sp.x);
|
|
46201
|
+
const dy = Math.abs(y - sp.y);
|
|
45953
46202
|
const dist = dx + dy;
|
|
45954
|
-
if (dist > 0 && dist <= selectedUnit.movement) {
|
|
45955
|
-
if (!units.some((u) =>
|
|
46203
|
+
if (dist > 0 && dist <= num(selectedUnit.movement)) {
|
|
46204
|
+
if (!units.some((u) => {
|
|
46205
|
+
const p2 = unitPosition(u);
|
|
46206
|
+
return p2.x === x && p2.y === y && unitHealth(u) > 0;
|
|
46207
|
+
})) {
|
|
45956
46208
|
setUnits(
|
|
45957
46209
|
(prev) => prev.map(
|
|
45958
|
-
(u) => u.id === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
46210
|
+
(u) => str(u.id) === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
45959
46211
|
)
|
|
45960
46212
|
);
|
|
45961
46213
|
setPhase("action");
|
|
@@ -45998,12 +46250,13 @@ var init_useBattleState = __esm({
|
|
|
45998
46250
|
"components/game/organisms/hooks/useBattleState.ts"() {
|
|
45999
46251
|
"use client";
|
|
46000
46252
|
init_useEventBus();
|
|
46253
|
+
init_boardEntity();
|
|
46001
46254
|
}
|
|
46002
46255
|
});
|
|
46003
46256
|
function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
46004
|
-
const resolved =
|
|
46257
|
+
const resolved = boardEntity(entity);
|
|
46005
46258
|
const battleState = useBattleState(
|
|
46006
|
-
resolved?.initialUnits
|
|
46259
|
+
rows(resolved?.initialUnits),
|
|
46007
46260
|
{
|
|
46008
46261
|
tileClickEvent: rest.tileClickEvent,
|
|
46009
46262
|
unitClickEvent: rest.unitClickEvent,
|
|
@@ -46039,10 +46292,23 @@ function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
|
46039
46292
|
var init_UncontrolledBattleBoard = __esm({
|
|
46040
46293
|
"components/game/organisms/UncontrolledBattleBoard.tsx"() {
|
|
46041
46294
|
init_BattleBoard();
|
|
46295
|
+
init_boardEntity();
|
|
46042
46296
|
init_useBattleState();
|
|
46043
46297
|
UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
|
|
46044
46298
|
}
|
|
46045
46299
|
});
|
|
46300
|
+
function heroPosition(h) {
|
|
46301
|
+
return vec2(h.position);
|
|
46302
|
+
}
|
|
46303
|
+
function heroOwner(h) {
|
|
46304
|
+
return str(h.owner);
|
|
46305
|
+
}
|
|
46306
|
+
function heroMovement(h) {
|
|
46307
|
+
return num(h.movement);
|
|
46308
|
+
}
|
|
46309
|
+
function hexPassable(h) {
|
|
46310
|
+
return h.passable !== false;
|
|
46311
|
+
}
|
|
46046
46312
|
function defaultIsInRange(from, to, range) {
|
|
46047
46313
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
46048
46314
|
}
|
|
@@ -46073,36 +46339,36 @@ function WorldMapBoard({
|
|
|
46073
46339
|
className
|
|
46074
46340
|
}) {
|
|
46075
46341
|
const eventBus = useEventBus();
|
|
46076
|
-
const resolved =
|
|
46077
|
-
const hexes = resolved?.hexes
|
|
46078
|
-
const heroes = resolved?.heroes
|
|
46079
|
-
const features = resolved?.features
|
|
46080
|
-
const selectedHeroId = resolved?.selectedHeroId;
|
|
46342
|
+
const resolved = boardEntity(entity);
|
|
46343
|
+
const hexes = rows(resolved?.hexes);
|
|
46344
|
+
const heroes = rows(resolved?.heroes);
|
|
46345
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
46346
|
+
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
46081
46347
|
const assetManifest = resolved?.assetManifest;
|
|
46082
46348
|
const backgroundImage = resolved?.backgroundImage;
|
|
46083
46349
|
const [hoveredTile, setHoveredTile] = React85.useState(null);
|
|
46084
46350
|
const selectedHero = React85.useMemo(
|
|
46085
|
-
() => heroes.find((h) => h.id === selectedHeroId) ?? null,
|
|
46351
|
+
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
46086
46352
|
[heroes, selectedHeroId]
|
|
46087
46353
|
);
|
|
46088
46354
|
const tiles = React85.useMemo(
|
|
46089
46355
|
() => hexes.map((hex) => ({
|
|
46090
|
-
x: hex.x,
|
|
46091
|
-
y: hex.y,
|
|
46092
|
-
terrain: hex.terrain,
|
|
46093
|
-
terrainSprite: hex.terrainSprite
|
|
46356
|
+
x: num(hex.x),
|
|
46357
|
+
y: num(hex.y),
|
|
46358
|
+
terrain: str(hex.terrain),
|
|
46359
|
+
terrainSprite: hex.terrainSprite == null ? void 0 : str(hex.terrainSprite)
|
|
46094
46360
|
})),
|
|
46095
46361
|
[hexes]
|
|
46096
46362
|
);
|
|
46097
46363
|
const baseUnits = React85.useMemo(
|
|
46098
46364
|
() => heroes.map((hero) => ({
|
|
46099
|
-
id: hero.id,
|
|
46100
|
-
position: hero
|
|
46101
|
-
name: hero.name,
|
|
46102
|
-
team: hero
|
|
46365
|
+
id: str(hero.id),
|
|
46366
|
+
position: heroPosition(hero),
|
|
46367
|
+
name: str(hero.name),
|
|
46368
|
+
team: heroOwner(hero) === "enemy" ? "enemy" : "player",
|
|
46103
46369
|
health: 100,
|
|
46104
46370
|
maxHealth: 100,
|
|
46105
|
-
sprite: hero.sprite
|
|
46371
|
+
sprite: hero.sprite == null ? void 0 : str(hero.sprite)
|
|
46106
46372
|
})),
|
|
46107
46373
|
[heroes]
|
|
46108
46374
|
);
|
|
@@ -46143,73 +46409,94 @@ function WorldMapBoard({
|
|
|
46143
46409
|
const isoUnits = React85.useMemo(() => {
|
|
46144
46410
|
if (movingPositions.size === 0) return baseUnits;
|
|
46145
46411
|
return baseUnits.map((u) => {
|
|
46146
|
-
const pos = movingPositions.get(u.id);
|
|
46412
|
+
const pos = u.id == null ? void 0 : movingPositions.get(u.id);
|
|
46147
46413
|
return pos ? { ...u, position: pos } : u;
|
|
46148
46414
|
});
|
|
46149
46415
|
}, [baseUnits, movingPositions]);
|
|
46150
46416
|
const validMoves = React85.useMemo(() => {
|
|
46151
|
-
if (!selectedHero || selectedHero
|
|
46417
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46418
|
+
const sp = heroPosition(selectedHero);
|
|
46419
|
+
const sOwner = heroOwner(selectedHero);
|
|
46420
|
+
const range = heroMovement(selectedHero);
|
|
46152
46421
|
const moves = [];
|
|
46153
46422
|
hexes.forEach((hex) => {
|
|
46154
|
-
|
|
46155
|
-
|
|
46156
|
-
if (!
|
|
46157
|
-
if (
|
|
46158
|
-
|
|
46423
|
+
const hx = num(hex.x);
|
|
46424
|
+
const hy = num(hex.y);
|
|
46425
|
+
if (!hexPassable(hex)) return;
|
|
46426
|
+
if (hx === sp.x && hy === sp.y) return;
|
|
46427
|
+
if (!isInRange(sp, { x: hx, y: hy }, range)) return;
|
|
46428
|
+
if (heroes.some((h) => {
|
|
46429
|
+
const hp = heroPosition(h);
|
|
46430
|
+
return hp.x === hx && hp.y === hy && heroOwner(h) === sOwner;
|
|
46431
|
+
})) return;
|
|
46432
|
+
moves.push({ x: hx, y: hy });
|
|
46159
46433
|
});
|
|
46160
46434
|
return moves;
|
|
46161
46435
|
}, [selectedHero, hexes, heroes, isInRange]);
|
|
46162
46436
|
const attackTargets = React85.useMemo(() => {
|
|
46163
|
-
if (!selectedHero || selectedHero
|
|
46164
|
-
|
|
46437
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46438
|
+
const sp = heroPosition(selectedHero);
|
|
46439
|
+
const sOwner = heroOwner(selectedHero);
|
|
46440
|
+
const range = heroMovement(selectedHero);
|
|
46441
|
+
return heroes.filter((h) => heroOwner(h) !== sOwner).filter((h) => isInRange(sp, heroPosition(h), range)).map((h) => heroPosition(h));
|
|
46165
46442
|
}, [selectedHero, heroes, isInRange]);
|
|
46166
|
-
const maxY = Math.max(...hexes.map((h) => h.y), 0);
|
|
46443
|
+
const maxY = Math.max(...hexes.map((h) => num(h.y)), 0);
|
|
46167
46444
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
46168
46445
|
const tileToScreen = React85.useCallback(
|
|
46169
46446
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
46170
46447
|
[scale, baseOffsetX]
|
|
46171
46448
|
);
|
|
46172
46449
|
const hoveredHex = React85.useMemo(
|
|
46173
|
-
() => hoveredTile ? hexes.find((h) => h.x === hoveredTile.x && h.y === hoveredTile.y) ?? null : null,
|
|
46450
|
+
() => hoveredTile ? hexes.find((h) => num(h.x) === hoveredTile.x && num(h.y) === hoveredTile.y) ?? null : null,
|
|
46174
46451
|
[hoveredTile, hexes]
|
|
46175
46452
|
);
|
|
46176
46453
|
const hoveredHero = React85.useMemo(
|
|
46177
|
-
() => hoveredTile ? heroes.find((h) =>
|
|
46454
|
+
() => hoveredTile ? heroes.find((h) => {
|
|
46455
|
+
const hp = heroPosition(h);
|
|
46456
|
+
return hp.x === hoveredTile.x && hp.y === hoveredTile.y;
|
|
46457
|
+
}) ?? null : null,
|
|
46178
46458
|
[hoveredTile, heroes]
|
|
46179
46459
|
);
|
|
46180
46460
|
const handleTileClick = React85.useCallback((x, y) => {
|
|
46181
46461
|
if (movementAnimRef.current) return;
|
|
46182
|
-
const hex = hexes.find((h) => h.x === x && h.y === y);
|
|
46462
|
+
const hex = hexes.find((h) => num(h.x) === x && num(h.y) === y);
|
|
46183
46463
|
if (!hex) return;
|
|
46184
46464
|
if (tileClickEvent) {
|
|
46185
46465
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
46186
46466
|
}
|
|
46187
46467
|
if (selectedHero && validMoves.some((m) => m.x === x && m.y === y)) {
|
|
46188
|
-
|
|
46189
|
-
|
|
46468
|
+
const heroId = str(selectedHero.id);
|
|
46469
|
+
startMoveAnimation(heroId, { ...heroPosition(selectedHero) }, { x, y }, () => {
|
|
46470
|
+
onHeroMove?.(heroId, x, y);
|
|
46190
46471
|
if (heroMoveEvent) {
|
|
46191
|
-
eventBus.emit(`UI:${heroMoveEvent}`, { heroId
|
|
46472
|
+
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
46192
46473
|
}
|
|
46193
|
-
|
|
46194
|
-
|
|
46474
|
+
const feature = str(hex.feature);
|
|
46475
|
+
if (feature && feature !== "none") {
|
|
46476
|
+
onFeatureEnter?.(heroId, hex);
|
|
46195
46477
|
if (featureEnterEvent) {
|
|
46196
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId
|
|
46478
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
46197
46479
|
}
|
|
46198
46480
|
}
|
|
46199
46481
|
});
|
|
46200
46482
|
return;
|
|
46201
46483
|
}
|
|
46202
|
-
const enemy = heroes.find((h) =>
|
|
46484
|
+
const enemy = heroes.find((h) => {
|
|
46485
|
+
const hp = heroPosition(h);
|
|
46486
|
+
return hp.x === x && hp.y === y && heroOwner(h) === "enemy";
|
|
46487
|
+
});
|
|
46203
46488
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
46204
|
-
|
|
46489
|
+
const attackerId = str(selectedHero.id);
|
|
46490
|
+
const defenderId = str(enemy.id);
|
|
46491
|
+
onBattleEncounter?.(attackerId, defenderId);
|
|
46205
46492
|
if (battleEncounterEvent) {
|
|
46206
|
-
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId
|
|
46493
|
+
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
46207
46494
|
}
|
|
46208
46495
|
}
|
|
46209
46496
|
}, [hexes, heroes, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
46210
46497
|
const handleUnitClick = React85.useCallback((unitId) => {
|
|
46211
|
-
const hero = heroes.find((h) => h.id === unitId);
|
|
46212
|
-
if (hero && (hero
|
|
46498
|
+
const hero = heroes.find((h) => str(h.id) === unitId);
|
|
46499
|
+
if (hero && (heroOwner(hero) === "player" || allowMoveAllHeroes)) {
|
|
46213
46500
|
onHeroSelect?.(unitId);
|
|
46214
46501
|
if (heroSelectEvent) {
|
|
46215
46502
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
@@ -46282,6 +46569,7 @@ var init_WorldMapBoard = __esm({
|
|
|
46282
46569
|
init_Stack();
|
|
46283
46570
|
init_LoadingState();
|
|
46284
46571
|
init_IsometricCanvas2();
|
|
46572
|
+
init_boardEntity();
|
|
46285
46573
|
init_isometric();
|
|
46286
46574
|
WorldMapBoard.displayName = "WorldMapBoard";
|
|
46287
46575
|
}
|