@almadar/ui 5.21.11 → 5.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +939 -638
- package/dist/avl/index.js +939 -638
- package/dist/components/core/molecules/CalendarGrid.d.ts +3 -10
- package/dist/components/core/molecules/ContentRenderer.d.ts +2 -2
- package/dist/components/core/molecules/DataGrid.d.ts +11 -20
- package/dist/components/core/molecules/DataList.d.ts +9 -15
- package/dist/components/core/molecules/FormSection.d.ts +4 -4
- package/dist/components/core/molecules/PositionedCanvas.d.ts +4 -17
- package/dist/components/core/molecules/ReplyTree.d.ts +2 -13
- package/dist/components/core/molecules/RichBlockEditor.d.ts +3 -6
- package/dist/components/core/molecules/SortableList.d.ts +7 -5
- package/dist/components/core/molecules/TableView.d.ts +7 -7
- package/dist/components/core/molecules/index.d.ts +3 -3
- package/dist/components/core/molecules/useDataDnd.d.ts +5 -5
- package/dist/components/core/organisms/CardGrid.d.ts +5 -2
- package/dist/components/core/organisms/CaseStudyOrganism.d.ts +4 -3
- package/dist/components/core/organisms/DataTable.d.ts +4 -2
- package/dist/components/core/organisms/DetailPanel.d.ts +6 -6
- package/dist/components/core/organisms/FeatureGridOrganism.d.ts +4 -3
- package/dist/components/core/organisms/HeroOrganism.d.ts +4 -5
- package/dist/components/core/organisms/List.d.ts +5 -2
- package/dist/components/core/organisms/MasterDetail.d.ts +4 -2
- package/dist/components/core/organisms/MediaGallery.d.ts +4 -2
- package/dist/components/core/organisms/ShowcaseOrganism.d.ts +4 -3
- package/dist/components/core/organisms/StatCard.d.ts +5 -2
- package/dist/components/core/organisms/StepFlowOrganism.d.ts +4 -3
- package/dist/components/core/organisms/Timeline.d.ts +2 -2
- package/dist/components/core/organisms/book/index.d.ts +1 -1
- package/dist/components/core/organisms/book/types.d.ts +28 -48
- package/dist/components/core/organisms/index.d.ts +1 -2
- package/dist/components/core/organisms/layout/DashboardGrid.d.ts +2 -2
- package/dist/components/core/organisms/marketing-types.d.ts +5 -94
- package/dist/components/core/organisms/types.d.ts +9 -27
- package/dist/components/core/templates/index.d.ts +6 -6
- package/dist/components/game/organisms/BattleBoard.d.ts +14 -90
- package/dist/components/game/organisms/CastleBoard.d.ts +7 -21
- package/dist/components/game/organisms/UncontrolledBattleBoard.d.ts +2 -7
- package/dist/components/game/organisms/WorldMapBoard.d.ts +13 -59
- package/dist/components/game/organisms/boardEntity.d.ts +44 -0
- package/dist/components/game/organisms/hooks/useBattleState.d.ts +7 -7
- package/dist/components/game/organisms/index.d.ts +3 -3
- package/dist/components/game/organisms/puzzles/builder/BuilderBoard.d.ts +7 -20
- package/dist/components/game/organisms/puzzles/builder/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/classifier/ClassifierBoard.d.ts +7 -20
- package/dist/components/game/organisms/puzzles/classifier/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/debugger/DebuggerBoard.d.ts +6 -22
- package/dist/components/game/organisms/puzzles/debugger/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/event-handler/EventHandlerBoard.d.ts +6 -33
- package/dist/components/game/organisms/puzzles/event-handler/ObjectRulePanel.d.ts +3 -21
- package/dist/components/game/organisms/puzzles/event-handler/index.d.ts +2 -2
- package/dist/components/game/organisms/puzzles/event-handler/puzzleObject.d.ts +21 -0
- package/dist/components/game/organisms/puzzles/negotiator/NegotiatorBoard.d.ts +8 -24
- package/dist/components/game/organisms/puzzles/negotiator/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/sequencer/ActionTile.d.ts +2 -2
- package/dist/components/game/organisms/puzzles/sequencer/SequencerBoard.d.ts +7 -36
- package/dist/components/game/organisms/puzzles/sequencer/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/simulator/SimulatorBoard.d.ts +6 -25
- package/dist/components/game/organisms/puzzles/simulator/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/state-architect/StateArchitectBoard.d.ts +7 -40
- package/dist/components/game/organisms/puzzles/state-architect/VariablePanel.d.ts +3 -9
- package/dist/components/game/organisms/puzzles/state-architect/index.d.ts +2 -2
- package/dist/components/game/organisms/three/index.cjs +35 -21
- package/dist/components/game/organisms/three/index.js +35 -21
- package/dist/components/game/templates/BattleTemplate.d.ts +2 -3
- package/dist/components/game/templates/CastleTemplate.d.ts +2 -3
- package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +1 -16
- package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +1 -18
- package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +1 -14
- package/dist/components/game/templates/GameTemplate.d.ts +1 -6
- package/dist/components/game/templates/WorldMapTemplate.d.ts +2 -3
- package/dist/components/index.cjs +2036 -1675
- package/dist/components/index.js +1148 -787
- package/dist/components/marketing/organisms/PricingOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/StatsOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/TeamOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/book/BookChapterView.d.ts +5 -2
- package/dist/components/marketing/organisms/book/BookTableOfContents.d.ts +3 -2
- package/dist/components/marketing/organisms/book/BookViewer.d.ts +4 -4
- package/dist/components/marketing/templates/AboutPageTemplate.d.ts +32 -6
- package/dist/components/marketing/templates/FeatureDetailPageTemplate.d.ts +14 -4
- package/dist/components/marketing/templates/LandingPageTemplate.d.ts +47 -9
- package/dist/components/marketing/templates/PricingPageTemplate.d.ts +23 -5
- package/dist/providers/index.cjs +932 -631
- package/dist/providers/index.js +932 -631
- package/dist/runtime/index.cjs +934 -633
- package/dist/runtime/index.js +934 -633
- package/package.json +2 -2
package/dist/runtime/index.cjs
CHANGED
|
@@ -2503,7 +2503,7 @@ var init_SvgGrid = __esm({
|
|
|
2503
2503
|
x,
|
|
2504
2504
|
y,
|
|
2505
2505
|
cols = 4,
|
|
2506
|
-
rows = 3,
|
|
2506
|
+
rows: rows2 = 3,
|
|
2507
2507
|
spacing = 20,
|
|
2508
2508
|
nodeRadius = 3,
|
|
2509
2509
|
color = "var(--color-primary)",
|
|
@@ -2512,7 +2512,7 @@ var init_SvgGrid = __esm({
|
|
|
2512
2512
|
highlights = []
|
|
2513
2513
|
}) => {
|
|
2514
2514
|
const highlightSet = new Set(highlights);
|
|
2515
|
-
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length:
|
|
2515
|
+
return /* @__PURE__ */ jsxRuntime.jsx("g", { className, opacity, children: Array.from({ length: rows2 }).map(
|
|
2516
2516
|
(_, row) => Array.from({ length: cols }).map((_2, col) => {
|
|
2517
2517
|
const index = row * cols + col;
|
|
2518
2518
|
const isHighlighted = highlightSet.has(index);
|
|
@@ -3172,7 +3172,7 @@ var init_Input = __esm({
|
|
|
3172
3172
|
onClear,
|
|
3173
3173
|
value,
|
|
3174
3174
|
options,
|
|
3175
|
-
rows = 3,
|
|
3175
|
+
rows: rows2 = 3,
|
|
3176
3176
|
onChange,
|
|
3177
3177
|
...props
|
|
3178
3178
|
}, ref) => {
|
|
@@ -3222,7 +3222,7 @@ var init_Input = __esm({
|
|
|
3222
3222
|
ref,
|
|
3223
3223
|
value,
|
|
3224
3224
|
onChange,
|
|
3225
|
-
rows,
|
|
3225
|
+
rows: rows2,
|
|
3226
3226
|
className: baseClassName,
|
|
3227
3227
|
...props
|
|
3228
3228
|
}
|
|
@@ -5478,66 +5478,6 @@ var init_RangeSlider = __esm({
|
|
|
5478
5478
|
RangeSlider.displayName = "RangeSlider";
|
|
5479
5479
|
}
|
|
5480
5480
|
});
|
|
5481
|
-
function easeOut(t) {
|
|
5482
|
-
return t * (2 - t);
|
|
5483
|
-
}
|
|
5484
|
-
var AnimatedCounter;
|
|
5485
|
-
var init_AnimatedCounter = __esm({
|
|
5486
|
-
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
5487
|
-
"use client";
|
|
5488
|
-
init_cn();
|
|
5489
|
-
init_Typography();
|
|
5490
|
-
AnimatedCounter = ({
|
|
5491
|
-
value: rawValue,
|
|
5492
|
-
duration = 600,
|
|
5493
|
-
prefix,
|
|
5494
|
-
suffix,
|
|
5495
|
-
className
|
|
5496
|
-
}) => {
|
|
5497
|
-
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
5498
|
-
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
5499
|
-
const [displayValue, setDisplayValue] = React84.useState(value);
|
|
5500
|
-
const previousValueRef = React84.useRef(value);
|
|
5501
|
-
const animationFrameRef = React84.useRef(null);
|
|
5502
|
-
React84.useEffect(() => {
|
|
5503
|
-
const from = previousValueRef.current;
|
|
5504
|
-
const to = value;
|
|
5505
|
-
previousValueRef.current = value;
|
|
5506
|
-
if (from === to) {
|
|
5507
|
-
setDisplayValue(to);
|
|
5508
|
-
return;
|
|
5509
|
-
}
|
|
5510
|
-
const startTime = performance.now();
|
|
5511
|
-
const diff = to - from;
|
|
5512
|
-
function animate(currentTime) {
|
|
5513
|
-
const elapsed = currentTime - startTime;
|
|
5514
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
5515
|
-
const easedProgress = easeOut(progress);
|
|
5516
|
-
setDisplayValue(from + diff * easedProgress);
|
|
5517
|
-
if (progress < 1) {
|
|
5518
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5519
|
-
} else {
|
|
5520
|
-
setDisplayValue(to);
|
|
5521
|
-
}
|
|
5522
|
-
}
|
|
5523
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5524
|
-
return () => {
|
|
5525
|
-
if (animationFrameRef.current !== null) {
|
|
5526
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
5527
|
-
}
|
|
5528
|
-
};
|
|
5529
|
-
}, [value, duration]);
|
|
5530
|
-
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
5531
|
-
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
5532
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
5533
|
-
prefix,
|
|
5534
|
-
formattedValue,
|
|
5535
|
-
suffix
|
|
5536
|
-
] });
|
|
5537
|
-
};
|
|
5538
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
5539
|
-
}
|
|
5540
|
-
});
|
|
5541
5481
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
5542
5482
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
5543
5483
|
const observerRef = React84.useRef(null);
|
|
@@ -8019,15 +7959,15 @@ function HeaderSkeleton({ className }) {
|
|
|
8019
7959
|
] })
|
|
8020
7960
|
] });
|
|
8021
7961
|
}
|
|
8022
|
-
function TableSkeleton({ rows = 5, columns = 4, className }) {
|
|
7962
|
+
function TableSkeleton({ rows: rows2 = 5, columns = 4, className }) {
|
|
8023
7963
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: cn("border border-border rounded-lg overflow-hidden", className), children: [
|
|
8024
7964
|
/* @__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)) }),
|
|
8025
|
-
Array.from({ length:
|
|
7965
|
+
Array.from({ length: rows2 }).map((_, rowIdx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8026
7966
|
HStack,
|
|
8027
7967
|
{
|
|
8028
7968
|
className: cn(
|
|
8029
7969
|
"px-4 py-3",
|
|
8030
|
-
rowIdx <
|
|
7970
|
+
rowIdx < rows2 - 1 && "border-b border-border"
|
|
8031
7971
|
),
|
|
8032
7972
|
children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonLine, { className: "flex-1 mx-2" }, colIdx))
|
|
8033
7973
|
},
|
|
@@ -8075,18 +8015,18 @@ function CardSkeleton({ className }) {
|
|
|
8075
8015
|
}
|
|
8076
8016
|
);
|
|
8077
8017
|
}
|
|
8078
|
-
function TextSkeleton({ rows = 3, className }) {
|
|
8079
|
-
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length:
|
|
8018
|
+
function TextSkeleton({ rows: rows2 = 3, className }) {
|
|
8019
|
+
return /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", className, children: Array.from({ length: rows2 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
8080
8020
|
SkeletonLine,
|
|
8081
8021
|
{
|
|
8082
|
-
className: i ===
|
|
8022
|
+
className: i === rows2 - 1 ? "w-2/3" : "w-full"
|
|
8083
8023
|
},
|
|
8084
8024
|
i
|
|
8085
8025
|
)) });
|
|
8086
8026
|
}
|
|
8087
8027
|
function Skeleton({
|
|
8088
8028
|
variant = "text",
|
|
8089
|
-
rows,
|
|
8029
|
+
rows: rows2,
|
|
8090
8030
|
columns,
|
|
8091
8031
|
fields,
|
|
8092
8032
|
className
|
|
@@ -8096,15 +8036,15 @@ function Skeleton({
|
|
|
8096
8036
|
case "header":
|
|
8097
8037
|
return /* @__PURE__ */ jsxRuntime.jsx(HeaderSkeleton, { className });
|
|
8098
8038
|
case "table":
|
|
8099
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows, columns, className });
|
|
8039
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TableSkeleton, { rows: rows2, columns, className });
|
|
8100
8040
|
case "form":
|
|
8101
8041
|
return /* @__PURE__ */ jsxRuntime.jsx(FormSkeleton, { fields, className });
|
|
8102
8042
|
case "card":
|
|
8103
8043
|
return /* @__PURE__ */ jsxRuntime.jsx(CardSkeleton, { className });
|
|
8104
8044
|
case "text":
|
|
8105
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
8045
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
8106
8046
|
default:
|
|
8107
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows, className });
|
|
8047
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TextSkeleton, { rows: rows2, className });
|
|
8108
8048
|
}
|
|
8109
8049
|
}
|
|
8110
8050
|
var pulseClass;
|
|
@@ -9258,7 +9198,7 @@ var init_Menu = __esm({
|
|
|
9258
9198
|
className
|
|
9259
9199
|
}) => {
|
|
9260
9200
|
const eventBus = useEventBus();
|
|
9261
|
-
const { t } = hooks.useTranslate();
|
|
9201
|
+
const { t, direction } = hooks.useTranslate();
|
|
9262
9202
|
const [isOpen, setIsOpen] = React84.useState(false);
|
|
9263
9203
|
const [activeSubMenu, setActiveSubMenu] = React84.useState(null);
|
|
9264
9204
|
const [triggerRect, setTriggerRect] = React84.useState(null);
|
|
@@ -9312,6 +9252,18 @@ var init_Menu = __esm({
|
|
|
9312
9252
|
"bottom-start": "top-full left-0 mt-2",
|
|
9313
9253
|
"bottom-end": "top-full right-0 mt-2"
|
|
9314
9254
|
};
|
|
9255
|
+
const rtlMirror = {
|
|
9256
|
+
"top-left": "top-right",
|
|
9257
|
+
"top-right": "top-left",
|
|
9258
|
+
"bottom-left": "bottom-right",
|
|
9259
|
+
"bottom-right": "bottom-left",
|
|
9260
|
+
"top-start": "top-end",
|
|
9261
|
+
"top-end": "top-start",
|
|
9262
|
+
"bottom-start": "bottom-end",
|
|
9263
|
+
"bottom-end": "bottom-start"
|
|
9264
|
+
};
|
|
9265
|
+
const effectivePosition = direction === "rtl" ? rtlMirror[position] ?? position : position;
|
|
9266
|
+
const subMenuSideClass = direction === "rtl" ? "right-full mr-2" : "left-full ml-2";
|
|
9315
9267
|
const triggerChild = React84__namespace.default.isValidElement(trigger) ? trigger : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", as: "span", children: trigger });
|
|
9316
9268
|
const triggerElement = React84__namespace.default.cloneElement(
|
|
9317
9269
|
triggerChild,
|
|
@@ -9339,7 +9291,7 @@ var init_Menu = __esm({
|
|
|
9339
9291
|
onMouseEnter: () => hasSubMenu && setActiveSubMenu(itemId),
|
|
9340
9292
|
"data-testid": item.event ? `action-${item.event}` : void 0,
|
|
9341
9293
|
className: cn(
|
|
9342
|
-
"w-full flex items-center justify-between gap-3 px-4 py-2 text-
|
|
9294
|
+
"w-full flex items-center justify-between gap-3 px-4 py-2 text-start",
|
|
9343
9295
|
"text-sm transition-colors",
|
|
9344
9296
|
"hover:bg-muted",
|
|
9345
9297
|
"focus:outline-none focus:bg-muted",
|
|
@@ -9358,7 +9310,7 @@ var init_Menu = __esm({
|
|
|
9358
9310
|
}
|
|
9359
9311
|
),
|
|
9360
9312
|
item.badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: item.badge }),
|
|
9361
|
-
hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: "chevron-right", size: "sm", className: "flex-shrink-0" })
|
|
9313
|
+
hasSubMenu && /* @__PURE__ */ jsxRuntime.jsx(Icon, { name: direction === "rtl" ? "chevron-left" : "chevron-right", size: "sm", className: "flex-shrink-0" })
|
|
9362
9314
|
] })
|
|
9363
9315
|
},
|
|
9364
9316
|
itemId
|
|
@@ -9378,7 +9330,8 @@ var init_Menu = __esm({
|
|
|
9378
9330
|
Box,
|
|
9379
9331
|
{
|
|
9380
9332
|
className: cn(
|
|
9381
|
-
"absolute
|
|
9333
|
+
"absolute top-0 z-50",
|
|
9334
|
+
subMenuSideClass,
|
|
9382
9335
|
menuContainerStyles
|
|
9383
9336
|
),
|
|
9384
9337
|
children: renderMenuItems(item.subMenu)
|
|
@@ -9396,12 +9349,12 @@ var init_Menu = __esm({
|
|
|
9396
9349
|
className: cn(
|
|
9397
9350
|
"absolute z-50",
|
|
9398
9351
|
menuContainerStyles,
|
|
9399
|
-
positionClasses3[
|
|
9352
|
+
positionClasses3[effectivePosition],
|
|
9400
9353
|
className
|
|
9401
9354
|
),
|
|
9402
9355
|
style: {
|
|
9403
|
-
left:
|
|
9404
|
-
right:
|
|
9356
|
+
left: effectivePosition.includes("left") ? 0 : "auto",
|
|
9357
|
+
right: effectivePosition.includes("right") ? 0 : "auto"
|
|
9405
9358
|
},
|
|
9406
9359
|
role: "menu",
|
|
9407
9360
|
children: renderMenuItems(items)
|
|
@@ -9719,7 +9672,7 @@ var init_MapView = __esm({
|
|
|
9719
9672
|
shadowSize: [41, 41]
|
|
9720
9673
|
});
|
|
9721
9674
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
9722
|
-
const { useEffect: useEffect71, useRef: useRef66, useCallback:
|
|
9675
|
+
const { useEffect: useEffect71, useRef: useRef66, useCallback: useCallback114, useState: useState103 } = React84__namespace.default;
|
|
9723
9676
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
9724
9677
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
9725
9678
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -9765,7 +9718,7 @@ var init_MapView = __esm({
|
|
|
9765
9718
|
}) {
|
|
9766
9719
|
const eventBus = useEventBus3();
|
|
9767
9720
|
const [clickedPosition, setClickedPosition] = useState103(null);
|
|
9768
|
-
const handleMapClick =
|
|
9721
|
+
const handleMapClick = useCallback114((lat, lng) => {
|
|
9769
9722
|
if (showClickedPin) {
|
|
9770
9723
|
setClickedPosition({ lat, lng });
|
|
9771
9724
|
}
|
|
@@ -9774,7 +9727,7 @@ var init_MapView = __esm({
|
|
|
9774
9727
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
9775
9728
|
}
|
|
9776
9729
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
9777
|
-
const handleMarkerClick =
|
|
9730
|
+
const handleMarkerClick = useCallback114((marker) => {
|
|
9778
9731
|
onMarkerClick?.(marker);
|
|
9779
9732
|
if (markerClickEvent) {
|
|
9780
9733
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -9995,7 +9948,7 @@ function InputPattern({
|
|
|
9995
9948
|
function TextareaPattern({
|
|
9996
9949
|
value = "",
|
|
9997
9950
|
placeholder,
|
|
9998
|
-
rows = 4,
|
|
9951
|
+
rows: rows2 = 4,
|
|
9999
9952
|
disabled = false,
|
|
10000
9953
|
fieldError,
|
|
10001
9954
|
onChange,
|
|
@@ -10015,7 +9968,7 @@ function TextareaPattern({
|
|
|
10015
9968
|
{
|
|
10016
9969
|
value: localValue,
|
|
10017
9970
|
placeholder,
|
|
10018
|
-
rows,
|
|
9971
|
+
rows: rows2,
|
|
10019
9972
|
disabled,
|
|
10020
9973
|
error: fieldError,
|
|
10021
9974
|
onChange: handleChange,
|
|
@@ -10500,6 +10453,91 @@ var init_ActionPalette = __esm({
|
|
|
10500
10453
|
ActionPalette.displayName = "ActionPalette";
|
|
10501
10454
|
}
|
|
10502
10455
|
});
|
|
10456
|
+
function parseValue(value) {
|
|
10457
|
+
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
10458
|
+
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
10459
|
+
if (!match) {
|
|
10460
|
+
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
10461
|
+
}
|
|
10462
|
+
const numStr = match[2];
|
|
10463
|
+
const decimalIdx = numStr.indexOf(".");
|
|
10464
|
+
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
10465
|
+
return {
|
|
10466
|
+
prefix: match[1],
|
|
10467
|
+
num: parseFloat(numStr),
|
|
10468
|
+
suffix: match[3],
|
|
10469
|
+
decimals
|
|
10470
|
+
};
|
|
10471
|
+
}
|
|
10472
|
+
var AnimatedCounter;
|
|
10473
|
+
var init_AnimatedCounter = __esm({
|
|
10474
|
+
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
10475
|
+
"use client";
|
|
10476
|
+
init_cn();
|
|
10477
|
+
init_Box();
|
|
10478
|
+
init_Typography();
|
|
10479
|
+
AnimatedCounter = ({
|
|
10480
|
+
value,
|
|
10481
|
+
label,
|
|
10482
|
+
duration = 1500,
|
|
10483
|
+
className
|
|
10484
|
+
}) => {
|
|
10485
|
+
const ref = React84.useRef(null);
|
|
10486
|
+
const [displayValue, setDisplayValue] = React84.useState("0");
|
|
10487
|
+
const [hasAnimated, setHasAnimated] = React84.useState(false);
|
|
10488
|
+
const animate = React84.useCallback(() => {
|
|
10489
|
+
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
10490
|
+
if (num2 === 0) {
|
|
10491
|
+
setDisplayValue(String(value));
|
|
10492
|
+
return;
|
|
10493
|
+
}
|
|
10494
|
+
const startTime = performance.now();
|
|
10495
|
+
const tick = (now2) => {
|
|
10496
|
+
const elapsed = now2 - startTime;
|
|
10497
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
10498
|
+
const eased = 1 - Math.pow(1 - progress, 3);
|
|
10499
|
+
const current = eased * num2;
|
|
10500
|
+
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
10501
|
+
if (progress < 1) {
|
|
10502
|
+
requestAnimationFrame(tick);
|
|
10503
|
+
} else {
|
|
10504
|
+
setDisplayValue(String(value));
|
|
10505
|
+
}
|
|
10506
|
+
};
|
|
10507
|
+
requestAnimationFrame(tick);
|
|
10508
|
+
}, [value, duration]);
|
|
10509
|
+
React84.useEffect(() => {
|
|
10510
|
+
if (hasAnimated) return;
|
|
10511
|
+
const el = ref.current;
|
|
10512
|
+
if (!el) return;
|
|
10513
|
+
const observer2 = new IntersectionObserver(
|
|
10514
|
+
(entries) => {
|
|
10515
|
+
if (entries[0].isIntersecting) {
|
|
10516
|
+
setHasAnimated(true);
|
|
10517
|
+
animate();
|
|
10518
|
+
observer2.disconnect();
|
|
10519
|
+
}
|
|
10520
|
+
},
|
|
10521
|
+
{ threshold: 0.3 }
|
|
10522
|
+
);
|
|
10523
|
+
observer2.observe(el);
|
|
10524
|
+
return () => observer2.disconnect();
|
|
10525
|
+
}, [hasAnimated, animate]);
|
|
10526
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
10527
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10528
|
+
Typography,
|
|
10529
|
+
{
|
|
10530
|
+
variant: "h2",
|
|
10531
|
+
className: "text-primary font-bold tabular-nums",
|
|
10532
|
+
children: hasAnimated ? displayValue : "0"
|
|
10533
|
+
}
|
|
10534
|
+
),
|
|
10535
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
10536
|
+
] });
|
|
10537
|
+
};
|
|
10538
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
10539
|
+
}
|
|
10540
|
+
});
|
|
10503
10541
|
var AuthLayout;
|
|
10504
10542
|
var init_AuthLayout = __esm({
|
|
10505
10543
|
"components/core/templates/AuthLayout.tsx"() {
|
|
@@ -11853,6 +11891,39 @@ var init_IsometricCanvas2 = __esm({
|
|
|
11853
11891
|
init_IsometricCanvas();
|
|
11854
11892
|
}
|
|
11855
11893
|
});
|
|
11894
|
+
|
|
11895
|
+
// components/game/organisms/boardEntity.ts
|
|
11896
|
+
function boardEntity(entity) {
|
|
11897
|
+
if (!entity) return void 0;
|
|
11898
|
+
return Array.isArray(entity) ? entity[0] : entity;
|
|
11899
|
+
}
|
|
11900
|
+
function str(v) {
|
|
11901
|
+
return v == null ? "" : String(v);
|
|
11902
|
+
}
|
|
11903
|
+
function num(v, fallback = 0) {
|
|
11904
|
+
const n = Number(v);
|
|
11905
|
+
return Number.isFinite(n) ? n : fallback;
|
|
11906
|
+
}
|
|
11907
|
+
function rows(v) {
|
|
11908
|
+
return Array.isArray(v) ? v : [];
|
|
11909
|
+
}
|
|
11910
|
+
function vec2(v) {
|
|
11911
|
+
const o = v ?? {};
|
|
11912
|
+
return { x: num(o.x), y: num(o.y) };
|
|
11913
|
+
}
|
|
11914
|
+
function unitPosition(u) {
|
|
11915
|
+
return vec2(u.position);
|
|
11916
|
+
}
|
|
11917
|
+
function unitTeam(u) {
|
|
11918
|
+
return str(u.team);
|
|
11919
|
+
}
|
|
11920
|
+
function unitHealth(u) {
|
|
11921
|
+
return num(u.health);
|
|
11922
|
+
}
|
|
11923
|
+
var init_boardEntity = __esm({
|
|
11924
|
+
"components/game/organisms/boardEntity.ts"() {
|
|
11925
|
+
}
|
|
11926
|
+
});
|
|
11856
11927
|
function BattleBoard({
|
|
11857
11928
|
entity,
|
|
11858
11929
|
scale = 0.45,
|
|
@@ -11879,43 +11950,49 @@ function BattleBoard({
|
|
|
11879
11950
|
attackEvent,
|
|
11880
11951
|
className
|
|
11881
11952
|
}) {
|
|
11882
|
-
const
|
|
11883
|
-
const
|
|
11884
|
-
const
|
|
11885
|
-
const
|
|
11886
|
-
const
|
|
11887
|
-
const
|
|
11888
|
-
const
|
|
11889
|
-
const
|
|
11890
|
-
const
|
|
11891
|
-
const
|
|
11892
|
-
const
|
|
11953
|
+
const board = boardEntity(entity) ?? {};
|
|
11954
|
+
const tiles = Array.isArray(board.tiles) ? board.tiles : [];
|
|
11955
|
+
const features = Array.isArray(board.features) ? board.features : [];
|
|
11956
|
+
const boardWidth = num(board.boardWidth, 8);
|
|
11957
|
+
const boardHeight = num(board.boardHeight, 6);
|
|
11958
|
+
const assetManifest = board.assetManifest;
|
|
11959
|
+
const backgroundImage = board.backgroundImage;
|
|
11960
|
+
const units = rows(board.units);
|
|
11961
|
+
const selectedUnitId = board.selectedUnitId ?? null;
|
|
11962
|
+
const currentPhase = str(board.phase) || "observation";
|
|
11963
|
+
const currentTurn = num(board.turn, 1);
|
|
11964
|
+
const gameResult = board.gameResult ?? null;
|
|
11893
11965
|
const eventBus = useEventBus();
|
|
11894
11966
|
const { t } = hooks.useTranslate();
|
|
11895
11967
|
const [hoveredTile, setHoveredTile] = React84.useState(null);
|
|
11896
11968
|
const [isShaking, setIsShaking] = React84.useState(false);
|
|
11897
11969
|
const selectedUnit = React84.useMemo(
|
|
11898
|
-
() => units.find((u) => u.id === selectedUnitId) ?? null,
|
|
11970
|
+
() => units.find((u) => str(u.id) === selectedUnitId) ?? null,
|
|
11899
11971
|
[units, selectedUnitId]
|
|
11900
11972
|
);
|
|
11901
11973
|
const hoveredUnit = React84.useMemo(() => {
|
|
11902
11974
|
if (!hoveredTile) return null;
|
|
11903
|
-
return units.find(
|
|
11904
|
-
|
|
11905
|
-
|
|
11975
|
+
return units.find((u) => {
|
|
11976
|
+
const p2 = unitPosition(u);
|
|
11977
|
+
return p2.x === hoveredTile.x && p2.y === hoveredTile.y && unitHealth(u) > 0;
|
|
11978
|
+
}) ?? null;
|
|
11906
11979
|
}, [hoveredTile, units]);
|
|
11907
|
-
const playerUnits = React84.useMemo(() => units.filter((u) => u
|
|
11908
|
-
const enemyUnits = React84.useMemo(() => units.filter((u) => u
|
|
11980
|
+
const playerUnits = React84.useMemo(() => units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0), [units]);
|
|
11981
|
+
const enemyUnits = React84.useMemo(() => units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0), [units]);
|
|
11909
11982
|
const validMoves = React84.useMemo(() => {
|
|
11910
11983
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
11911
11984
|
const moves = [];
|
|
11912
|
-
const range = selectedUnit.movement;
|
|
11985
|
+
const range = num(selectedUnit.movement);
|
|
11986
|
+
const origin = unitPosition(selectedUnit);
|
|
11913
11987
|
for (let dy = -range; dy <= range; dy++) {
|
|
11914
11988
|
for (let dx = -range; dx <= range; dx++) {
|
|
11915
|
-
const nx =
|
|
11916
|
-
const ny =
|
|
11989
|
+
const nx = origin.x + dx;
|
|
11990
|
+
const ny = origin.y + dy;
|
|
11917
11991
|
const dist = Math.abs(dx) + Math.abs(dy);
|
|
11918
|
-
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) =>
|
|
11992
|
+
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) => {
|
|
11993
|
+
const p2 = unitPosition(u);
|
|
11994
|
+
return p2.x === nx && p2.y === ny && unitHealth(u) > 0;
|
|
11995
|
+
})) {
|
|
11919
11996
|
moves.push({ x: nx, y: ny });
|
|
11920
11997
|
}
|
|
11921
11998
|
}
|
|
@@ -11924,11 +12001,14 @@ function BattleBoard({
|
|
|
11924
12001
|
}, [selectedUnit, currentPhase, units, boardWidth, boardHeight]);
|
|
11925
12002
|
const attackTargets = React84.useMemo(() => {
|
|
11926
12003
|
if (!selectedUnit || currentPhase !== "action") return [];
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
12004
|
+
const sp = unitPosition(selectedUnit);
|
|
12005
|
+
const sTeam = unitTeam(selectedUnit);
|
|
12006
|
+
return units.filter((u) => unitTeam(u) !== sTeam && unitHealth(u) > 0).filter((u) => {
|
|
12007
|
+
const p2 = unitPosition(u);
|
|
12008
|
+
const dx = Math.abs(p2.x - sp.x);
|
|
12009
|
+
const dy = Math.abs(p2.y - sp.y);
|
|
11930
12010
|
return dx <= 1 && dy <= 1 && dx + dy > 0;
|
|
11931
|
-
}).map((u) => u
|
|
12011
|
+
}).map((u) => unitPosition(u));
|
|
11932
12012
|
}, [selectedUnit, currentPhase, units]);
|
|
11933
12013
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
11934
12014
|
const movementAnimRef = React84.useRef(null);
|
|
@@ -11968,23 +12048,25 @@ function BattleBoard({
|
|
|
11968
12048
|
return () => clearInterval(interval);
|
|
11969
12049
|
}, []);
|
|
11970
12050
|
const isoUnits = React84.useMemo(() => {
|
|
11971
|
-
return units.filter((u) => u
|
|
11972
|
-
const
|
|
12051
|
+
return units.filter((u) => unitHealth(u) > 0).map((unit) => {
|
|
12052
|
+
const id = str(unit.id);
|
|
12053
|
+
const pos = movingPositions.get(id) ?? unitPosition(unit);
|
|
12054
|
+
const unitTraits = Array.isArray(unit.traits) ? unit.traits : void 0;
|
|
11973
12055
|
return {
|
|
11974
|
-
id
|
|
12056
|
+
id,
|
|
11975
12057
|
position: pos,
|
|
11976
|
-
name: unit.name,
|
|
11977
|
-
team: unit
|
|
11978
|
-
health: unit
|
|
11979
|
-
maxHealth: unit.maxHealth,
|
|
11980
|
-
unitType: unit.unitType,
|
|
11981
|
-
heroId: unit.heroId,
|
|
11982
|
-
sprite: unit.sprite,
|
|
11983
|
-
traits:
|
|
11984
|
-
name:
|
|
11985
|
-
currentState:
|
|
11986
|
-
states:
|
|
11987
|
-
cooldown:
|
|
12058
|
+
name: str(unit.name),
|
|
12059
|
+
team: unitTeam(unit),
|
|
12060
|
+
health: unitHealth(unit),
|
|
12061
|
+
maxHealth: num(unit.maxHealth),
|
|
12062
|
+
unitType: unit.unitType == null ? void 0 : str(unit.unitType),
|
|
12063
|
+
heroId: unit.heroId == null ? void 0 : str(unit.heroId),
|
|
12064
|
+
sprite: unit.sprite == null ? void 0 : str(unit.sprite),
|
|
12065
|
+
traits: unitTraits?.map((tr) => ({
|
|
12066
|
+
name: tr.name,
|
|
12067
|
+
currentState: tr.currentState,
|
|
12068
|
+
states: tr.states,
|
|
12069
|
+
cooldown: tr.cooldown ?? 0
|
|
11988
12070
|
}))
|
|
11989
12071
|
};
|
|
11990
12072
|
});
|
|
@@ -11996,8 +12078,8 @@ function BattleBoard({
|
|
|
11996
12078
|
[scale, baseOffsetX]
|
|
11997
12079
|
);
|
|
11998
12080
|
const checkGameEnd = React84.useCallback(() => {
|
|
11999
|
-
const pa = units.filter((u) => u
|
|
12000
|
-
const ea = units.filter((u) => u
|
|
12081
|
+
const pa = units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
12082
|
+
const ea = units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
12001
12083
|
if (pa.length === 0) {
|
|
12002
12084
|
onGameEnd?.("defeat");
|
|
12003
12085
|
if (gameEndEvent) {
|
|
@@ -12011,21 +12093,22 @@ function BattleBoard({
|
|
|
12011
12093
|
}
|
|
12012
12094
|
}, [units, onGameEnd, gameEndEvent, eventBus]);
|
|
12013
12095
|
const handleUnitClick = React84.useCallback((unitId) => {
|
|
12014
|
-
const unit = units.find((u) => u.id === unitId);
|
|
12096
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
12015
12097
|
if (!unit) return;
|
|
12016
12098
|
if (unitClickEvent) {
|
|
12017
12099
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
12018
12100
|
}
|
|
12019
12101
|
if (currentPhase === "action" && selectedUnit) {
|
|
12020
|
-
|
|
12021
|
-
|
|
12102
|
+
const up = unitPosition(unit);
|
|
12103
|
+
if (unitTeam(unit) === "enemy" && attackTargets.some((t2) => t2.x === up.x && t2.y === up.y)) {
|
|
12104
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
12022
12105
|
setIsShaking(true);
|
|
12023
12106
|
setTimeout(() => setIsShaking(false), 300);
|
|
12024
12107
|
onAttack?.(selectedUnit, unit, damage);
|
|
12025
12108
|
if (attackEvent) {
|
|
12026
12109
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
12027
|
-
attackerId: selectedUnit.id,
|
|
12028
|
-
targetId: unit.id,
|
|
12110
|
+
attackerId: str(selectedUnit.id),
|
|
12111
|
+
targetId: str(unit.id),
|
|
12029
12112
|
damage
|
|
12030
12113
|
});
|
|
12031
12114
|
}
|
|
@@ -12040,9 +12123,9 @@ function BattleBoard({
|
|
|
12040
12123
|
if (currentPhase === "movement" && selectedUnit) {
|
|
12041
12124
|
if (movementAnimRef.current) return;
|
|
12042
12125
|
if (validMoves.some((m) => m.x === x && m.y === y)) {
|
|
12043
|
-
const from = { ...selectedUnit
|
|
12126
|
+
const from = { ...unitPosition(selectedUnit) };
|
|
12044
12127
|
const to = { x, y };
|
|
12045
|
-
startMoveAnimation(selectedUnit.id, from, to, () => {
|
|
12128
|
+
startMoveAnimation(str(selectedUnit.id), from, to, () => {
|
|
12046
12129
|
onUnitMove?.(selectedUnit, to);
|
|
12047
12130
|
});
|
|
12048
12131
|
}
|
|
@@ -12200,6 +12283,7 @@ var init_BattleBoard = __esm({
|
|
|
12200
12283
|
init_Typography();
|
|
12201
12284
|
init_Stack();
|
|
12202
12285
|
init_IsometricCanvas2();
|
|
12286
|
+
init_boardEntity();
|
|
12203
12287
|
init_isometric();
|
|
12204
12288
|
BattleBoard.displayName = "BattleBoard";
|
|
12205
12289
|
}
|
|
@@ -13422,24 +13506,24 @@ var init_CodeBlock = __esm({
|
|
|
13422
13506
|
return;
|
|
13423
13507
|
}
|
|
13424
13508
|
lineEls.forEach((el) => {
|
|
13425
|
-
const
|
|
13426
|
-
if (hiddenLines.has(
|
|
13509
|
+
const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
|
|
13510
|
+
if (hiddenLines.has(num2)) {
|
|
13427
13511
|
el.style.display = "none";
|
|
13428
13512
|
return;
|
|
13429
13513
|
}
|
|
13430
13514
|
el.style.display = "";
|
|
13431
13515
|
el.style.position = "relative";
|
|
13432
13516
|
el.style.paddingLeft = "1.2em";
|
|
13433
|
-
const region = foldStartMap.get(
|
|
13517
|
+
const region = foldStartMap.get(num2);
|
|
13434
13518
|
if (!region) return;
|
|
13435
|
-
const isCollapsed = collapsed.has(
|
|
13519
|
+
const isCollapsed = collapsed.has(num2);
|
|
13436
13520
|
const toggle = document.createElement("span");
|
|
13437
13521
|
toggle.className = "fold-toggle";
|
|
13438
13522
|
toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
|
|
13439
13523
|
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%";
|
|
13440
13524
|
toggle.addEventListener("click", (e) => {
|
|
13441
13525
|
e.stopPropagation();
|
|
13442
|
-
toggleFoldRef.current(
|
|
13526
|
+
toggleFoldRef.current(num2);
|
|
13443
13527
|
});
|
|
13444
13528
|
el.insertBefore(toggle, el.firstChild);
|
|
13445
13529
|
if (isCollapsed) {
|
|
@@ -15692,10 +15776,13 @@ var init_BookChapterView = __esm({
|
|
|
15692
15776
|
init_cn();
|
|
15693
15777
|
BookChapterView = ({
|
|
15694
15778
|
chapter,
|
|
15779
|
+
orbitalSchema,
|
|
15695
15780
|
direction,
|
|
15696
15781
|
className
|
|
15697
15782
|
}) => {
|
|
15698
15783
|
const { t: _t } = hooks.useTranslate();
|
|
15784
|
+
const title = String(chapter.title ?? "");
|
|
15785
|
+
const content = String(chapter.content ?? "");
|
|
15699
15786
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15700
15787
|
VStack,
|
|
15701
15788
|
{
|
|
@@ -15703,16 +15790,16 @@ var init_BookChapterView = __esm({
|
|
|
15703
15790
|
className: cn("px-6 py-8 max-w-4xl mx-auto w-full", className),
|
|
15704
15791
|
style: { direction },
|
|
15705
15792
|
children: [
|
|
15706
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children:
|
|
15793
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children: title }),
|
|
15707
15794
|
/* @__PURE__ */ jsxRuntime.jsx(Divider, {}),
|
|
15708
|
-
!!
|
|
15795
|
+
!!orbitalSchema && /* @__PURE__ */ jsxRuntime.jsx(ScaledDiagram, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
15709
15796
|
JazariStateMachine,
|
|
15710
15797
|
{
|
|
15711
|
-
schema:
|
|
15798
|
+
schema: orbitalSchema,
|
|
15712
15799
|
direction
|
|
15713
15800
|
}
|
|
15714
15801
|
) }),
|
|
15715
|
-
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content
|
|
15802
|
+
/* @__PURE__ */ jsxRuntime.jsx(ContentRenderer, { content, direction })
|
|
15716
15803
|
]
|
|
15717
15804
|
}
|
|
15718
15805
|
);
|
|
@@ -15810,7 +15897,7 @@ var init_BookNavBar = __esm({
|
|
|
15810
15897
|
BookNavBar = ({
|
|
15811
15898
|
currentPage,
|
|
15812
15899
|
totalPages,
|
|
15813
|
-
chapterTitle,
|
|
15900
|
+
chapterTitle: chapterTitle2,
|
|
15814
15901
|
direction,
|
|
15815
15902
|
className
|
|
15816
15903
|
}) => {
|
|
@@ -15851,12 +15938,12 @@ var init_BookNavBar = __esm({
|
|
|
15851
15938
|
)
|
|
15852
15939
|
] }),
|
|
15853
15940
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex-1 mx-4 max-w-md", children: [
|
|
15854
|
-
|
|
15941
|
+
chapterTitle2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
15855
15942
|
Typography,
|
|
15856
15943
|
{
|
|
15857
15944
|
variant: "caption",
|
|
15858
15945
|
className: "text-center block truncate text-muted-foreground",
|
|
15859
|
-
children:
|
|
15946
|
+
children: chapterTitle2
|
|
15860
15947
|
}
|
|
15861
15948
|
),
|
|
15862
15949
|
/* @__PURE__ */ jsxRuntime.jsx(ProgressBar, { value: progress, size: "sm", variant: "primary" })
|
|
@@ -15923,31 +16010,35 @@ var init_BookTableOfContents = __esm({
|
|
|
15923
16010
|
style: { direction },
|
|
15924
16011
|
children: [
|
|
15925
16012
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h1", className: "text-3xl font-bold text-center mb-4", children: t("book.tableOfContents") }),
|
|
15926
|
-
parts.map((part, partIdx) =>
|
|
15927
|
-
|
|
15928
|
-
|
|
15929
|
-
/* @__PURE__ */ jsxRuntime.
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
|
|
15947
|
-
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
16013
|
+
parts.map((part, partIdx) => {
|
|
16014
|
+
const chapters = Array.isArray(part.chapters) ? part.chapters : [];
|
|
16015
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
16016
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "center", children: [
|
|
16017
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: t("book.partNumber", { number: String(partIdx + 1) }) }),
|
|
16018
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "font-semibold", children: String(part.title ?? "") })
|
|
16019
|
+
] }),
|
|
16020
|
+
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "xs", className: direction === "rtl" ? "pr-6" : "pl-6", children: chapters.map((chapter) => {
|
|
16021
|
+
const id = chapter.id == null ? "" : String(chapter.id);
|
|
16022
|
+
const isCurrent = id === currentChapterId;
|
|
16023
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16024
|
+
Button,
|
|
16025
|
+
{
|
|
16026
|
+
variant: "ghost",
|
|
16027
|
+
size: "sm",
|
|
16028
|
+
action: "BOOK_NAVIGATE",
|
|
16029
|
+
actionPayload: { chapterId: id },
|
|
16030
|
+
className: cn(
|
|
16031
|
+
"justify-start text-left w-full",
|
|
16032
|
+
direction === "rtl" && "text-right",
|
|
16033
|
+
isCurrent && "bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400"
|
|
16034
|
+
),
|
|
16035
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "truncate", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: String(chapter.title ?? "") }) })
|
|
16036
|
+
},
|
|
16037
|
+
id
|
|
16038
|
+
);
|
|
16039
|
+
}) })
|
|
16040
|
+
] }, partIdx);
|
|
16041
|
+
})
|
|
15951
16042
|
]
|
|
15952
16043
|
}
|
|
15953
16044
|
);
|
|
@@ -16069,27 +16160,41 @@ function resolveFieldMap(fieldMap) {
|
|
|
16069
16160
|
function get(obj, key) {
|
|
16070
16161
|
return obj[key];
|
|
16071
16162
|
}
|
|
16163
|
+
function asStr(v) {
|
|
16164
|
+
return v == null ? "" : String(v);
|
|
16165
|
+
}
|
|
16072
16166
|
function mapBookData(raw, fields = IDENTITY_BOOK_FIELDS) {
|
|
16073
16167
|
const rawParts = get(raw, fields.parts) ?? [];
|
|
16074
|
-
|
|
16075
|
-
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16082
|
-
return {
|
|
16083
|
-
title: get(part, fields.partTitle) ?? "",
|
|
16084
|
-
chapters: rawChapters.map((ch) => ({
|
|
16085
|
-
id: get(ch, fields.chapterId) ?? "",
|
|
16086
|
-
title: get(ch, fields.chapterTitle) ?? "",
|
|
16087
|
-
content: get(ch, fields.chapterContent) ?? "",
|
|
16088
|
-
orbitalSchema: get(ch, fields.chapterOrbitalSchema)
|
|
16089
|
-
}))
|
|
16090
|
-
};
|
|
16091
|
-
})
|
|
16168
|
+
const direction = get(raw, fields.direction) ?? "ltr";
|
|
16169
|
+
const cover = {
|
|
16170
|
+
title: asStr(get(raw, fields.title)),
|
|
16171
|
+
subtitle: asStr(get(raw, fields.subtitle)),
|
|
16172
|
+
author: asStr(get(raw, fields.author)),
|
|
16173
|
+
coverImageUrl: asStr(get(raw, fields.coverImageUrl)),
|
|
16174
|
+
direction
|
|
16092
16175
|
};
|
|
16176
|
+
const schemaByChapterId = {};
|
|
16177
|
+
const chapters = [];
|
|
16178
|
+
const parts = rawParts.map((part) => {
|
|
16179
|
+
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16180
|
+
const chapterRows = rawChapters.map((ch) => {
|
|
16181
|
+
const id = asStr(get(ch, fields.chapterId));
|
|
16182
|
+
const schema = get(ch, fields.chapterOrbitalSchema);
|
|
16183
|
+
if (schema) schemaByChapterId[id] = schema;
|
|
16184
|
+
const row = {
|
|
16185
|
+
id,
|
|
16186
|
+
title: asStr(get(ch, fields.chapterTitle)),
|
|
16187
|
+
content: asStr(get(ch, fields.chapterContent))
|
|
16188
|
+
};
|
|
16189
|
+
chapters.push(row);
|
|
16190
|
+
return row;
|
|
16191
|
+
});
|
|
16192
|
+
return {
|
|
16193
|
+
title: asStr(get(part, fields.partTitle)),
|
|
16194
|
+
chapters: chapterRows
|
|
16195
|
+
};
|
|
16196
|
+
});
|
|
16197
|
+
return { cover, direction, parts, chapters, schemaByChapterId };
|
|
16093
16198
|
}
|
|
16094
16199
|
var IDENTITY_BOOK_FIELDS, AR_BOOK_FIELDS, FIELD_MAP_REGISTRY;
|
|
16095
16200
|
var init_types2 = __esm({
|
|
@@ -16127,10 +16232,7 @@ var init_types2 = __esm({
|
|
|
16127
16232
|
};
|
|
16128
16233
|
}
|
|
16129
16234
|
});
|
|
16130
|
-
|
|
16131
|
-
return book.parts.flatMap((part) => part.chapters);
|
|
16132
|
-
}
|
|
16133
|
-
var PRINT_STYLES, BookViewer;
|
|
16235
|
+
var chapterId, chapterTitle, PRINT_STYLES, BookViewer;
|
|
16134
16236
|
var init_BookViewer = __esm({
|
|
16135
16237
|
"components/marketing/organisms/book/BookViewer.tsx"() {
|
|
16136
16238
|
init_Box();
|
|
@@ -16143,6 +16245,8 @@ var init_BookViewer = __esm({
|
|
|
16143
16245
|
init_BookNavBar();
|
|
16144
16246
|
init_EmptyState();
|
|
16145
16247
|
init_types2();
|
|
16248
|
+
chapterId = (ch) => ch?.id == null ? void 0 : String(ch.id);
|
|
16249
|
+
chapterTitle = (ch) => ch?.title == null ? void 0 : String(ch.title);
|
|
16146
16250
|
PRINT_STYLES = `
|
|
16147
16251
|
@media print {
|
|
16148
16252
|
.book-viewer-page {
|
|
@@ -16171,14 +16275,14 @@ var init_BookViewer = __esm({
|
|
|
16171
16275
|
return mapBookData(raw, resolvedFieldMap);
|
|
16172
16276
|
}, [entity, resolvedFieldMap]);
|
|
16173
16277
|
const direction = book?.direction ?? "ltr";
|
|
16174
|
-
const chapters = React84.useMemo(() => book ?
|
|
16278
|
+
const chapters = React84.useMemo(() => book ? book.chapters : [], [book]);
|
|
16175
16279
|
const totalPages = 2 + chapters.length;
|
|
16176
16280
|
const navigateTo = React84.useCallback(
|
|
16177
16281
|
(page) => {
|
|
16178
16282
|
const clamped = Math.max(0, Math.min(page, totalPages - 1));
|
|
16179
16283
|
setCurrentPage(clamped);
|
|
16180
|
-
const
|
|
16181
|
-
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId });
|
|
16284
|
+
const id = clamped >= 2 ? chapterId(chapters[clamped - 2]) : void 0;
|
|
16285
|
+
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId: id });
|
|
16182
16286
|
},
|
|
16183
16287
|
[totalPages, chapters, eventBus]
|
|
16184
16288
|
);
|
|
@@ -16190,8 +16294,8 @@ var init_BookViewer = __esm({
|
|
|
16190
16294
|
eventBus.on("UI:BOOK_PAGE_NEXT", () => navigateTo(currentPage + 1)),
|
|
16191
16295
|
eventBus.on("UI:BOOK_PRINT", () => window.print()),
|
|
16192
16296
|
eventBus.on("UI:BOOK_NAVIGATE", (event) => {
|
|
16193
|
-
const
|
|
16194
|
-
const idx = chapters.findIndex((ch) => ch
|
|
16297
|
+
const targetId = event.payload?.chapterId;
|
|
16298
|
+
const idx = chapters.findIndex((ch) => chapterId(ch) === targetId);
|
|
16195
16299
|
if (idx >= 0) navigateTo(idx + 2);
|
|
16196
16300
|
})
|
|
16197
16301
|
];
|
|
@@ -16208,9 +16312,11 @@ var init_BookViewer = __esm({
|
|
|
16208
16312
|
style.remove();
|
|
16209
16313
|
};
|
|
16210
16314
|
}, []);
|
|
16211
|
-
const currentChapterId = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16212
|
-
const currentChapterTitle = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16315
|
+
const currentChapterId = currentPage >= 2 ? chapterId(chapters[currentPage - 2]) : void 0;
|
|
16316
|
+
const currentChapterTitle = currentPage >= 2 ? chapterTitle(chapters[currentPage - 2]) : void 0;
|
|
16213
16317
|
if (!book) return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { message: t("book.noData") });
|
|
16318
|
+
const cover = book.cover;
|
|
16319
|
+
const coverTitle = String(cover.title ?? "");
|
|
16214
16320
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("relative h-full overflow-hidden bg-background", className), children: [
|
|
16215
16321
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
16216
16322
|
Box,
|
|
@@ -16222,10 +16328,10 @@ var init_BookViewer = __esm({
|
|
|
16222
16328
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
16223
16329
|
BookCoverPage,
|
|
16224
16330
|
{
|
|
16225
|
-
title:
|
|
16226
|
-
subtitle:
|
|
16227
|
-
author:
|
|
16228
|
-
coverImageUrl:
|
|
16331
|
+
title: coverTitle,
|
|
16332
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16333
|
+
author: String(cover.author ?? "") || void 0,
|
|
16334
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16229
16335
|
direction
|
|
16230
16336
|
}
|
|
16231
16337
|
),
|
|
@@ -16236,23 +16342,27 @@ var init_BookViewer = __esm({
|
|
|
16236
16342
|
direction
|
|
16237
16343
|
}
|
|
16238
16344
|
),
|
|
16239
|
-
chapters.map((chapter) =>
|
|
16240
|
-
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
16245
|
-
|
|
16246
|
-
|
|
16345
|
+
chapters.map((chapter) => {
|
|
16346
|
+
const id = chapterId(chapter);
|
|
16347
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
16348
|
+
BookChapterView,
|
|
16349
|
+
{
|
|
16350
|
+
chapter,
|
|
16351
|
+
orbitalSchema: id ? book.schemaByChapterId[id] : void 0,
|
|
16352
|
+
direction
|
|
16353
|
+
},
|
|
16354
|
+
id
|
|
16355
|
+
);
|
|
16356
|
+
})
|
|
16247
16357
|
] }),
|
|
16248
16358
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "print:hidden", children: [
|
|
16249
16359
|
currentPage === 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16250
16360
|
BookCoverPage,
|
|
16251
16361
|
{
|
|
16252
|
-
title:
|
|
16253
|
-
subtitle:
|
|
16254
|
-
author:
|
|
16255
|
-
coverImageUrl:
|
|
16362
|
+
title: coverTitle,
|
|
16363
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16364
|
+
author: String(cover.author ?? "") || void 0,
|
|
16365
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16256
16366
|
direction
|
|
16257
16367
|
}
|
|
16258
16368
|
),
|
|
@@ -16268,6 +16378,7 @@ var init_BookViewer = __esm({
|
|
|
16268
16378
|
BookChapterView,
|
|
16269
16379
|
{
|
|
16270
16380
|
chapter: chapters[currentPage - 2],
|
|
16381
|
+
orbitalSchema: currentChapterId ? book.schemaByChapterId[currentChapterId] : void 0,
|
|
16271
16382
|
direction
|
|
16272
16383
|
}
|
|
16273
16384
|
)
|
|
@@ -16280,7 +16391,7 @@ var init_BookViewer = __esm({
|
|
|
16280
16391
|
{
|
|
16281
16392
|
currentPage,
|
|
16282
16393
|
totalPages,
|
|
16283
|
-
chapterTitle: currentPage === 0 ?
|
|
16394
|
+
chapterTitle: currentPage === 0 ? coverTitle : currentPage === 1 ? t("book.tableOfContents") : currentChapterTitle,
|
|
16284
16395
|
direction
|
|
16285
16396
|
}
|
|
16286
16397
|
)
|
|
@@ -16378,7 +16489,7 @@ var init_Grid = __esm({
|
|
|
16378
16489
|
};
|
|
16379
16490
|
Grid = ({
|
|
16380
16491
|
cols = 1,
|
|
16381
|
-
rows,
|
|
16492
|
+
rows: rows2,
|
|
16382
16493
|
gap = "md",
|
|
16383
16494
|
rowGap,
|
|
16384
16495
|
colGap,
|
|
@@ -16390,7 +16501,7 @@ var init_Grid = __esm({
|
|
|
16390
16501
|
children,
|
|
16391
16502
|
as: Component = "div"
|
|
16392
16503
|
}) => {
|
|
16393
|
-
const mergedStyle =
|
|
16504
|
+
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
16394
16505
|
return React84__namespace.default.createElement(
|
|
16395
16506
|
Component,
|
|
16396
16507
|
{
|
|
@@ -17106,14 +17217,14 @@ function BuilderBoard({
|
|
|
17106
17217
|
}) {
|
|
17107
17218
|
const { emit } = useEventBus();
|
|
17108
17219
|
const { t } = hooks.useTranslate();
|
|
17109
|
-
const resolved =
|
|
17220
|
+
const resolved = boardEntity(entity);
|
|
17110
17221
|
const [placements, setPlacements] = React84.useState({});
|
|
17111
17222
|
const [headerError, setHeaderError] = React84.useState(false);
|
|
17112
17223
|
const [submitted, setSubmitted] = React84.useState(false);
|
|
17113
17224
|
const [attempts, setAttempts] = React84.useState(0);
|
|
17114
17225
|
const [showHint, setShowHint] = React84.useState(false);
|
|
17115
|
-
const components = resolved?.components
|
|
17116
|
-
const slots = resolved?.slots
|
|
17226
|
+
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
17227
|
+
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
17117
17228
|
const usedComponentIds = new Set(Object.values(placements));
|
|
17118
17229
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
17119
17230
|
const [selectedComponent, setSelectedComponent] = React84.useState(null);
|
|
@@ -17147,7 +17258,7 @@ function BuilderBoard({
|
|
|
17147
17258
|
}, [slots, placements, attempts, completeEvent, emit]);
|
|
17148
17259
|
const handleReset = () => {
|
|
17149
17260
|
setSubmitted(false);
|
|
17150
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
17261
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
17151
17262
|
setShowHint(true);
|
|
17152
17263
|
}
|
|
17153
17264
|
};
|
|
@@ -17160,20 +17271,24 @@ function BuilderBoard({
|
|
|
17160
17271
|
};
|
|
17161
17272
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
17162
17273
|
if (!resolved) return null;
|
|
17274
|
+
const theme = resolved.theme ?? void 0;
|
|
17275
|
+
const themeBackground = theme?.background;
|
|
17276
|
+
const headerImage = str(resolved.headerImage);
|
|
17277
|
+
const hint = str(resolved.hint);
|
|
17163
17278
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17164
17279
|
Box,
|
|
17165
17280
|
{
|
|
17166
17281
|
className,
|
|
17167
17282
|
style: {
|
|
17168
|
-
backgroundImage:
|
|
17283
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
17169
17284
|
backgroundSize: "cover",
|
|
17170
17285
|
backgroundPosition: "center"
|
|
17171
17286
|
},
|
|
17172
17287
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
17173
|
-
|
|
17288
|
+
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,
|
|
17174
17289
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17175
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
17176
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
17290
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
17291
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
17177
17292
|
] }) }),
|
|
17178
17293
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
17179
17294
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.components") }),
|
|
@@ -17233,9 +17348,9 @@ function BuilderBoard({
|
|
|
17233
17348
|
] }) }),
|
|
17234
17349
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17235
17350
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
17236
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
17351
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
|
|
17237
17352
|
] }) }),
|
|
17238
|
-
showHint &&
|
|
17353
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
17239
17354
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17240
17355
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17241
17356
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
@@ -17254,6 +17369,7 @@ var init_BuilderBoard = __esm({
|
|
|
17254
17369
|
"components/game/organisms/puzzles/builder/BuilderBoard.tsx"() {
|
|
17255
17370
|
init_atoms2();
|
|
17256
17371
|
init_useEventBus();
|
|
17372
|
+
init_boardEntity();
|
|
17257
17373
|
BuilderBoard.displayName = "BuilderBoard";
|
|
17258
17374
|
}
|
|
17259
17375
|
});
|
|
@@ -17591,21 +17707,24 @@ function CalendarGrid({
|
|
|
17591
17707
|
eventBus.emit(`UI:${longPressEvent}`, { date: day.toISOString(), time, ...longPressPayload });
|
|
17592
17708
|
}, 500);
|
|
17593
17709
|
}, [longPressEvent, longPressPayload, eventBus]);
|
|
17594
|
-
const renderEvent = (event) =>
|
|
17595
|
-
|
|
17596
|
-
|
|
17597
|
-
|
|
17598
|
-
|
|
17599
|
-
|
|
17600
|
-
|
|
17601
|
-
|
|
17602
|
-
|
|
17603
|
-
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
|
|
17607
|
-
|
|
17608
|
-
|
|
17710
|
+
const renderEvent = (event) => {
|
|
17711
|
+
const color = event.color;
|
|
17712
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17713
|
+
Box,
|
|
17714
|
+
{
|
|
17715
|
+
rounded: "md",
|
|
17716
|
+
padding: "xs",
|
|
17717
|
+
border: true,
|
|
17718
|
+
className: cn(
|
|
17719
|
+
"cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
|
|
17720
|
+
color ? color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
|
|
17721
|
+
),
|
|
17722
|
+
onClick: (e) => handleEventClick(event, e),
|
|
17723
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
|
|
17724
|
+
},
|
|
17725
|
+
event.id
|
|
17726
|
+
);
|
|
17727
|
+
};
|
|
17609
17728
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17610
17729
|
Box,
|
|
17611
17730
|
{
|
|
@@ -19269,7 +19388,6 @@ var init_CardGrid = __esm({
|
|
|
19269
19388
|
alignItems = "stretch",
|
|
19270
19389
|
className,
|
|
19271
19390
|
children,
|
|
19272
|
-
// EntityDisplayProps
|
|
19273
19391
|
entity,
|
|
19274
19392
|
isLoading = false,
|
|
19275
19393
|
error = null,
|
|
@@ -19741,14 +19859,14 @@ var init_CaseStudyOrganism = __esm({
|
|
|
19741
19859
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((study) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
19742
19860
|
CaseStudyCard,
|
|
19743
19861
|
{
|
|
19744
|
-
title: study.title,
|
|
19745
|
-
description: study.description,
|
|
19746
|
-
category: study.category,
|
|
19747
|
-
categoryColor: study.categoryColor,
|
|
19748
|
-
href: study.href,
|
|
19749
|
-
linkLabel: study.linkLabel
|
|
19862
|
+
title: String(study.title ?? ""),
|
|
19863
|
+
description: String(study.description ?? ""),
|
|
19864
|
+
category: String(study.category ?? ""),
|
|
19865
|
+
categoryColor: study.categoryColor != null ? String(study.categoryColor) : void 0,
|
|
19866
|
+
href: String(study.href ?? ""),
|
|
19867
|
+
linkLabel: study.linkLabel != null ? String(study.linkLabel) : void 0
|
|
19750
19868
|
},
|
|
19751
|
-
study.id
|
|
19869
|
+
String(study.id ?? "")
|
|
19752
19870
|
)) })
|
|
19753
19871
|
] });
|
|
19754
19872
|
};
|
|
@@ -19771,10 +19889,10 @@ function CastleBoard({
|
|
|
19771
19889
|
className
|
|
19772
19890
|
}) {
|
|
19773
19891
|
const eventBus = useEventBus();
|
|
19774
|
-
const resolved =
|
|
19775
|
-
const tiles = resolved?.tiles
|
|
19776
|
-
const features = resolved?.features
|
|
19777
|
-
const units = resolved?.units
|
|
19892
|
+
const resolved = boardEntity(entity);
|
|
19893
|
+
const tiles = Array.isArray(resolved?.tiles) ? resolved.tiles : [];
|
|
19894
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
19895
|
+
const units = Array.isArray(resolved?.units) ? resolved.units : [];
|
|
19778
19896
|
const assetManifest = resolved?.assetManifest;
|
|
19779
19897
|
const backgroundImage = resolved?.backgroundImage;
|
|
19780
19898
|
const [hoveredTile, setHoveredTile] = React84.useState(null);
|
|
@@ -19802,7 +19920,7 @@ function CastleBoard({
|
|
|
19802
19920
|
onFeatureClick?.(feature);
|
|
19803
19921
|
if (featureClickEvent) {
|
|
19804
19922
|
eventBus.emit(`UI:${featureClickEvent}`, {
|
|
19805
|
-
featureId: feature.id,
|
|
19923
|
+
featureId: feature.id ?? "",
|
|
19806
19924
|
featureType: feature.type,
|
|
19807
19925
|
x: feature.x,
|
|
19808
19926
|
y: feature.y
|
|
@@ -19870,6 +19988,7 @@ var init_CastleBoard = __esm({
|
|
|
19870
19988
|
init_cn();
|
|
19871
19989
|
init_useEventBus();
|
|
19872
19990
|
init_IsometricCanvas2();
|
|
19991
|
+
init_boardEntity();
|
|
19873
19992
|
init_isometric();
|
|
19874
19993
|
CastleBoard.displayName = "CastleBoard";
|
|
19875
19994
|
}
|
|
@@ -20680,14 +20799,14 @@ function ClassifierBoard({
|
|
|
20680
20799
|
}) {
|
|
20681
20800
|
const { emit } = useEventBus();
|
|
20682
20801
|
const { t } = hooks.useTranslate();
|
|
20683
|
-
const resolved =
|
|
20802
|
+
const resolved = boardEntity(entity);
|
|
20684
20803
|
const [assignments, setAssignments] = React84.useState({});
|
|
20685
20804
|
const [headerError, setHeaderError] = React84.useState(false);
|
|
20686
20805
|
const [submitted, setSubmitted] = React84.useState(false);
|
|
20687
20806
|
const [attempts, setAttempts] = React84.useState(0);
|
|
20688
20807
|
const [showHint, setShowHint] = React84.useState(false);
|
|
20689
|
-
const items = resolved?.items
|
|
20690
|
-
const categories = resolved?.categories
|
|
20808
|
+
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
20809
|
+
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
20691
20810
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
20692
20811
|
const allAssigned = Object.keys(assignments).length === items.length;
|
|
20693
20812
|
const results = submitted ? items.map((item) => ({
|
|
@@ -20719,7 +20838,7 @@ function ClassifierBoard({
|
|
|
20719
20838
|
}, [items, assignments, attempts, completeEvent, emit]);
|
|
20720
20839
|
const handleReset = () => {
|
|
20721
20840
|
setSubmitted(false);
|
|
20722
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
20841
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
20723
20842
|
setShowHint(true);
|
|
20724
20843
|
}
|
|
20725
20844
|
};
|
|
@@ -20730,20 +20849,25 @@ function ClassifierBoard({
|
|
|
20730
20849
|
setShowHint(false);
|
|
20731
20850
|
};
|
|
20732
20851
|
if (!resolved) return null;
|
|
20852
|
+
const theme = resolved.theme ?? void 0;
|
|
20853
|
+
const themeBackground = theme?.background;
|
|
20854
|
+
const headerImage = str(resolved.headerImage);
|
|
20855
|
+
const hint = str(resolved.hint);
|
|
20856
|
+
const failMessage = str(resolved.failMessage);
|
|
20733
20857
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20734
20858
|
Box,
|
|
20735
20859
|
{
|
|
20736
20860
|
className,
|
|
20737
20861
|
style: {
|
|
20738
|
-
backgroundImage:
|
|
20862
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
20739
20863
|
backgroundSize: "cover",
|
|
20740
20864
|
backgroundPosition: "center"
|
|
20741
20865
|
},
|
|
20742
20866
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
20743
|
-
|
|
20867
|
+
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,
|
|
20744
20868
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
20745
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
20746
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
20869
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
20870
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
20747
20871
|
] }) }),
|
|
20748
20872
|
unassignedItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
20749
20873
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("classifier.itemsToSort") }),
|
|
@@ -20795,10 +20919,10 @@ function ClassifierBoard({
|
|
|
20795
20919
|
}) }),
|
|
20796
20920
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
20797
20921
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: allCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
20798
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
20799
|
-
!allCorrect &&
|
|
20922
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("classifier.allCorrect") : `${correctCount}/${items.length} ${t("classifier.correct")}` }),
|
|
20923
|
+
!allCorrect && failMessage && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "text-muted-foreground", children: failMessage })
|
|
20800
20924
|
] }) }),
|
|
20801
|
-
showHint &&
|
|
20925
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
20802
20926
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
20803
20927
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
20804
20928
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -20817,6 +20941,7 @@ var init_ClassifierBoard = __esm({
|
|
|
20817
20941
|
"components/game/organisms/puzzles/classifier/ClassifierBoard.tsx"() {
|
|
20818
20942
|
init_atoms2();
|
|
20819
20943
|
init_useEventBus();
|
|
20944
|
+
init_boardEntity();
|
|
20820
20945
|
ClassifierBoard.displayName = "ClassifierBoard";
|
|
20821
20946
|
}
|
|
20822
20947
|
});
|
|
@@ -27187,7 +27312,7 @@ function InventoryPanel({
|
|
|
27187
27312
|
const slotArray = Array.from({ length: safeSlots }, (_, index) => {
|
|
27188
27313
|
return safeItems[index] ?? null;
|
|
27189
27314
|
});
|
|
27190
|
-
const
|
|
27315
|
+
const rows2 = Math.ceil(safeSlots / safeColumns);
|
|
27191
27316
|
const handleSlotClick = React84.useCallback((index) => {
|
|
27192
27317
|
if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
|
|
27193
27318
|
onSelectSlot?.(index);
|
|
@@ -27256,7 +27381,7 @@ function InventoryPanel({
|
|
|
27256
27381
|
className: "grid gap-1 bg-[var(--color-card)] p-2 rounded-container border border-border",
|
|
27257
27382
|
style: {
|
|
27258
27383
|
gridTemplateColumns: `repeat(${safeColumns}, ${slotSize}px)`,
|
|
27259
|
-
gridTemplateRows: `repeat(${
|
|
27384
|
+
gridTemplateRows: `repeat(${rows2}, ${slotSize}px)`
|
|
27260
27385
|
},
|
|
27261
27386
|
children: slotArray.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
27262
27387
|
"button",
|
|
@@ -31220,11 +31345,11 @@ function LatticeSVG({
|
|
|
31220
31345
|
}) {
|
|
31221
31346
|
const paths = [];
|
|
31222
31347
|
const cols = 5;
|
|
31223
|
-
const
|
|
31348
|
+
const rows2 = Math.ceil(h / (w / cols));
|
|
31224
31349
|
const cellW = w / cols;
|
|
31225
31350
|
const cellH = cellW;
|
|
31226
31351
|
const bulge = cellW * 0.3;
|
|
31227
|
-
for (let row = 0; row <
|
|
31352
|
+
for (let row = 0; row < rows2; row++) {
|
|
31228
31353
|
for (let col = 0; col < cols; col++) {
|
|
31229
31354
|
const cx = col * cellW + cellW / 2;
|
|
31230
31355
|
const cy = row * cellH + cellH / 2;
|
|
@@ -31636,7 +31761,7 @@ var init_MatrixQuestion = __esm({
|
|
|
31636
31761
|
};
|
|
31637
31762
|
MatrixQuestion = ({
|
|
31638
31763
|
title,
|
|
31639
|
-
rows,
|
|
31764
|
+
rows: rows2,
|
|
31640
31765
|
columns = DEFAULT_MATRIX_COLUMNS,
|
|
31641
31766
|
values,
|
|
31642
31767
|
onChange,
|
|
@@ -31646,7 +31771,7 @@ var init_MatrixQuestion = __esm({
|
|
|
31646
31771
|
className
|
|
31647
31772
|
}) => {
|
|
31648
31773
|
const styles = sizeStyles13[size];
|
|
31649
|
-
const safeRows =
|
|
31774
|
+
const safeRows = rows2 ?? [];
|
|
31650
31775
|
const safeValues = values ?? {};
|
|
31651
31776
|
const eventBus = useEventBus();
|
|
31652
31777
|
const handleChange = React84.useCallback(
|
|
@@ -32274,7 +32399,8 @@ var init_PositionedCanvas = __esm({
|
|
|
32274
32399
|
dragRef.current = null;
|
|
32275
32400
|
setDraggingId(null);
|
|
32276
32401
|
if (!wasDrag) {
|
|
32277
|
-
const
|
|
32402
|
+
const itemId = item.id;
|
|
32403
|
+
const next = selectedId === itemId ? null : itemId;
|
|
32278
32404
|
onSelect?.(next);
|
|
32279
32405
|
if (selectEvent) {
|
|
32280
32406
|
eventBus.emit(`UI:${selectEvent}`, { id: next });
|
|
@@ -32309,15 +32435,22 @@ var init_PositionedCanvas = __esm({
|
|
|
32309
32435
|
style: { width, height },
|
|
32310
32436
|
onClick: handleContainerClick,
|
|
32311
32437
|
children: items.map((item) => {
|
|
32438
|
+
const itemId = item.id;
|
|
32439
|
+
const label = item.label;
|
|
32440
|
+
const x = item.x;
|
|
32441
|
+
const y = item.y;
|
|
32442
|
+
const capacity = item.capacity;
|
|
32443
|
+
const partySize = item.partySize;
|
|
32444
|
+
const serverName = item.serverName;
|
|
32312
32445
|
const status = item.status ?? "empty";
|
|
32313
32446
|
const shape = item.shape ?? "round";
|
|
32314
|
-
const isSelected = selectedId ===
|
|
32315
|
-
const isDragging = draggingId ===
|
|
32447
|
+
const isSelected = selectedId === itemId;
|
|
32448
|
+
const isDragging = draggingId === itemId;
|
|
32316
32449
|
const statusBadge = STATUS_BADGE[status];
|
|
32317
32450
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
32318
32451
|
Box,
|
|
32319
32452
|
{
|
|
32320
|
-
"data-testid": `item-node-${
|
|
32453
|
+
"data-testid": `item-node-${itemId}`,
|
|
32321
32454
|
"data-status": status,
|
|
32322
32455
|
className: cn(
|
|
32323
32456
|
"absolute flex flex-col items-center justify-center gap-1 border-2 select-none",
|
|
@@ -32328,7 +32461,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32328
32461
|
isSelected && "outline outline-2 outline-offset-2 outline-primary shadow-md",
|
|
32329
32462
|
isDragging && "shadow-lg z-10"
|
|
32330
32463
|
),
|
|
32331
|
-
style: { left:
|
|
32464
|
+
style: { left: x, top: y, touchAction: "none" },
|
|
32332
32465
|
onPointerDown: (e) => handlePointerDown(e, item),
|
|
32333
32466
|
onPointerMove: handlePointerMove,
|
|
32334
32467
|
onPointerUp: (e) => handlePointerUp(e, item),
|
|
@@ -32336,10 +32469,10 @@ var init_PositionedCanvas = __esm({
|
|
|
32336
32469
|
children: [
|
|
32337
32470
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-1", children: [
|
|
32338
32471
|
getStatusIcon(status),
|
|
32339
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children:
|
|
32472
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", weight: "semibold", children: label })
|
|
32340
32473
|
] }),
|
|
32341
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
32342
|
-
status === "seated" &&
|
|
32474
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: partySize !== void 0 && status === "seated" ? `${partySize}/${capacity}` : `Cap ${capacity}` }),
|
|
32475
|
+
status === "seated" && serverName && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "truncate max-w-[80%]", children: serverName }),
|
|
32343
32476
|
isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
32344
32477
|
Badge,
|
|
32345
32478
|
{
|
|
@@ -32351,7 +32484,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32351
32484
|
)
|
|
32352
32485
|
]
|
|
32353
32486
|
},
|
|
32354
|
-
|
|
32487
|
+
itemId
|
|
32355
32488
|
);
|
|
32356
32489
|
})
|
|
32357
32490
|
}
|
|
@@ -33123,9 +33256,10 @@ var init_RichBlockEditor = __esm({
|
|
|
33123
33256
|
});
|
|
33124
33257
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
33125
33258
|
for (const n of nodes) {
|
|
33259
|
+
const replies = n.replies;
|
|
33126
33260
|
if (n.collapsed) acc.add(n.id);
|
|
33127
|
-
if (
|
|
33128
|
-
collectInitiallyCollapsed(
|
|
33261
|
+
if (replies && replies.length > 0) {
|
|
33262
|
+
collectInitiallyCollapsed(replies, acc);
|
|
33129
33263
|
}
|
|
33130
33264
|
}
|
|
33131
33265
|
}
|
|
@@ -33155,44 +33289,52 @@ var init_ReplyTree = __esm({
|
|
|
33155
33289
|
}) => {
|
|
33156
33290
|
const eventBus = useEventBus();
|
|
33157
33291
|
const { t } = hooks.useTranslate();
|
|
33158
|
-
const
|
|
33159
|
-
const
|
|
33292
|
+
const nodeId = node.id;
|
|
33293
|
+
const authorName = node.authorName;
|
|
33294
|
+
const authorAvatarUrl = node.authorAvatarUrl;
|
|
33295
|
+
const content = node.content;
|
|
33296
|
+
const postedAt = node.postedAt;
|
|
33297
|
+
const voteCount = node.voteCount;
|
|
33298
|
+
const userVote = node.userVote;
|
|
33299
|
+
const replies = node.replies;
|
|
33300
|
+
const hasReplies = !!replies && replies.length > 0;
|
|
33301
|
+
const isCollapsed = collapsedSet.has(nodeId);
|
|
33160
33302
|
const atMaxDepth = depth >= maxDepth;
|
|
33161
33303
|
const [replyOpen, setReplyOpen] = React84.useState(false);
|
|
33162
33304
|
const [draft, setDraft] = React84.useState("");
|
|
33163
33305
|
const handleVote = React84.useCallback(
|
|
33164
33306
|
(next) => {
|
|
33165
|
-
onVote?.(
|
|
33166
|
-
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId
|
|
33307
|
+
onVote?.(nodeId, next);
|
|
33308
|
+
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId, vote: next });
|
|
33167
33309
|
},
|
|
33168
|
-
[
|
|
33310
|
+
[nodeId, onVote, voteEvent, eventBus]
|
|
33169
33311
|
);
|
|
33170
33312
|
const handleReply = React84.useCallback(() => {
|
|
33171
|
-
onReply?.(
|
|
33313
|
+
onReply?.(nodeId);
|
|
33172
33314
|
setReplyOpen((open) => !open);
|
|
33173
|
-
}, [
|
|
33315
|
+
}, [nodeId, onReply]);
|
|
33174
33316
|
const handleSubmitReply = React84.useCallback(() => {
|
|
33175
|
-
const
|
|
33176
|
-
if (!
|
|
33177
|
-
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId:
|
|
33317
|
+
const text = draft.trim();
|
|
33318
|
+
if (!text) return;
|
|
33319
|
+
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: nodeId, content: text });
|
|
33178
33320
|
setDraft("");
|
|
33179
33321
|
setReplyOpen(false);
|
|
33180
|
-
}, [
|
|
33322
|
+
}, [nodeId, draft, replyEvent, eventBus]);
|
|
33181
33323
|
const handleCancelReply = React84.useCallback(() => {
|
|
33182
33324
|
setDraft("");
|
|
33183
33325
|
setReplyOpen(false);
|
|
33184
33326
|
}, []);
|
|
33185
33327
|
const handleFlag = React84.useCallback(() => {
|
|
33186
|
-
onFlag?.(
|
|
33187
|
-
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId
|
|
33188
|
-
}, [
|
|
33328
|
+
onFlag?.(nodeId);
|
|
33329
|
+
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId });
|
|
33330
|
+
}, [nodeId, onFlag, flagEvent, eventBus]);
|
|
33189
33331
|
const handleContinue = React84.useCallback(() => {
|
|
33190
|
-
onContinueThread?.(
|
|
33191
|
-
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId
|
|
33192
|
-
}, [
|
|
33332
|
+
onContinueThread?.(nodeId);
|
|
33333
|
+
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId });
|
|
33334
|
+
}, [nodeId, onContinueThread, continueThreadEvent, eventBus]);
|
|
33193
33335
|
const handleToggle = React84.useCallback(() => {
|
|
33194
|
-
toggleCollapse(
|
|
33195
|
-
}, [
|
|
33336
|
+
toggleCollapse(nodeId);
|
|
33337
|
+
}, [nodeId, toggleCollapse]);
|
|
33196
33338
|
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-stretch min-w-0", children: [
|
|
33197
33339
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-col items-center flex-shrink-0 w-6", children: [
|
|
33198
33340
|
hasReplies ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -33224,25 +33366,25 @@ var init_ReplyTree = __esm({
|
|
|
33224
33366
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33225
33367
|
Avatar,
|
|
33226
33368
|
{
|
|
33227
|
-
src:
|
|
33228
|
-
name:
|
|
33369
|
+
src: authorAvatarUrl,
|
|
33370
|
+
name: authorName,
|
|
33229
33371
|
size: "sm"
|
|
33230
33372
|
}
|
|
33231
33373
|
),
|
|
33232
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children:
|
|
33233
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
33374
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "semibold", children: authorName }),
|
|
33375
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: postedAt })
|
|
33234
33376
|
] }),
|
|
33235
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children:
|
|
33377
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: content }),
|
|
33236
33378
|
showActions && /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
33237
33379
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
33238
33380
|
VoteStack,
|
|
33239
33381
|
{
|
|
33240
|
-
count:
|
|
33241
|
-
userVote:
|
|
33382
|
+
count: voteCount ?? 0,
|
|
33383
|
+
userVote: userVote ?? null,
|
|
33242
33384
|
onVote: handleVote,
|
|
33243
33385
|
size: "sm",
|
|
33244
33386
|
variant: "horizontal",
|
|
33245
|
-
label: t("replyTree.voteOnReplyBy", { author:
|
|
33387
|
+
label: t("replyTree.voteOnReplyBy", { author: authorName })
|
|
33246
33388
|
}
|
|
33247
33389
|
),
|
|
33248
33390
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -33252,7 +33394,7 @@ var init_ReplyTree = __esm({
|
|
|
33252
33394
|
size: "sm",
|
|
33253
33395
|
leftIcon: "message-square",
|
|
33254
33396
|
onClick: handleReply,
|
|
33255
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33397
|
+
"aria-label": t("replyTree.replyTo", { author: authorName }),
|
|
33256
33398
|
children: t("replyTree.reply")
|
|
33257
33399
|
}
|
|
33258
33400
|
),
|
|
@@ -33263,7 +33405,7 @@ var init_ReplyTree = __esm({
|
|
|
33263
33405
|
size: "sm",
|
|
33264
33406
|
leftIcon: "flag",
|
|
33265
33407
|
onClick: handleFlag,
|
|
33266
|
-
"aria-label": t("replyTree.flagReplyBy", { author:
|
|
33408
|
+
"aria-label": t("replyTree.flagReplyBy", { author: authorName }),
|
|
33267
33409
|
children: t("replyTree.flag")
|
|
33268
33410
|
}
|
|
33269
33411
|
)
|
|
@@ -33275,9 +33417,9 @@ var init_ReplyTree = __esm({
|
|
|
33275
33417
|
inputType: "textarea",
|
|
33276
33418
|
rows: 2,
|
|
33277
33419
|
value: draft,
|
|
33278
|
-
placeholder: t("replyTree.replyToPlaceholder", { author:
|
|
33420
|
+
placeholder: t("replyTree.replyToPlaceholder", { author: authorName }),
|
|
33279
33421
|
onChange: (e) => setDraft(e.target.value),
|
|
33280
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33422
|
+
"aria-label": t("replyTree.replyTo", { author: authorName })
|
|
33281
33423
|
}
|
|
33282
33424
|
),
|
|
33283
33425
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
@@ -33308,7 +33450,7 @@ var init_ReplyTree = __esm({
|
|
|
33308
33450
|
),
|
|
33309
33451
|
children: t("replyTree.continueThread")
|
|
33310
33452
|
}
|
|
33311
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children:
|
|
33453
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-2 mt-1", children: replies.map((child) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
33312
33454
|
ReplyTreeNode,
|
|
33313
33455
|
{
|
|
33314
33456
|
node: child,
|
|
@@ -35628,8 +35770,8 @@ var init_WizardContainer = __esm({
|
|
|
35628
35770
|
return void 0;
|
|
35629
35771
|
if (typeof controlledStep === "number") return controlledStep;
|
|
35630
35772
|
if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
|
|
35631
|
-
const
|
|
35632
|
-
return isNaN(
|
|
35773
|
+
const num2 = Number(controlledStep);
|
|
35774
|
+
return isNaN(num2) ? void 0 : num2;
|
|
35633
35775
|
})();
|
|
35634
35776
|
const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
|
|
35635
35777
|
const totalSteps = steps.length;
|
|
@@ -37334,7 +37476,7 @@ function DebuggerBoard({
|
|
|
37334
37476
|
}) {
|
|
37335
37477
|
const { emit } = useEventBus();
|
|
37336
37478
|
const { t } = hooks.useTranslate();
|
|
37337
|
-
const resolved =
|
|
37479
|
+
const resolved = boardEntity(entity);
|
|
37338
37480
|
const [flaggedLines, setFlaggedLines] = React84.useState(/* @__PURE__ */ new Set());
|
|
37339
37481
|
const [headerError, setHeaderError] = React84.useState(false);
|
|
37340
37482
|
const [submitted, setSubmitted] = React84.useState(false);
|
|
@@ -37352,7 +37494,7 @@ function DebuggerBoard({
|
|
|
37352
37494
|
return next;
|
|
37353
37495
|
});
|
|
37354
37496
|
};
|
|
37355
|
-
const lines = resolved?.lines
|
|
37497
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37356
37498
|
const bugLines = lines.filter((l) => l.isBug);
|
|
37357
37499
|
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
37358
37500
|
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
@@ -37367,7 +37509,7 @@ function DebuggerBoard({
|
|
|
37367
37509
|
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37368
37510
|
const handleReset = () => {
|
|
37369
37511
|
setSubmitted(false);
|
|
37370
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
37512
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
37371
37513
|
setShowHint(true);
|
|
37372
37514
|
}
|
|
37373
37515
|
};
|
|
@@ -37378,24 +37520,28 @@ function DebuggerBoard({
|
|
|
37378
37520
|
setShowHint(false);
|
|
37379
37521
|
};
|
|
37380
37522
|
if (!resolved) return null;
|
|
37523
|
+
const theme = resolved.theme ?? void 0;
|
|
37524
|
+
const themeBackground = theme?.background;
|
|
37525
|
+
const headerImage = str(resolved.headerImage);
|
|
37526
|
+
const hint = str(resolved.hint);
|
|
37381
37527
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37382
37528
|
Box,
|
|
37383
37529
|
{
|
|
37384
37530
|
className,
|
|
37385
37531
|
style: {
|
|
37386
|
-
backgroundImage:
|
|
37532
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
37387
37533
|
backgroundSize: "cover",
|
|
37388
37534
|
backgroundPosition: "center"
|
|
37389
37535
|
},
|
|
37390
37536
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
37391
|
-
|
|
37537
|
+
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,
|
|
37392
37538
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
37393
37539
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
37394
37540
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Bug, size: "sm" }),
|
|
37395
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title })
|
|
37541
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
37396
37542
|
] }),
|
|
37397
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
37398
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(resolved.bugCount) }) })
|
|
37543
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
37544
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
37399
37545
|
] }) }),
|
|
37400
37546
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
37401
37547
|
const isFlagged = flaggedLines.has(line.id);
|
|
@@ -37427,7 +37573,7 @@ function DebuggerBoard({
|
|
|
37427
37573
|
);
|
|
37428
37574
|
}) }) }),
|
|
37429
37575
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
37430
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
37576
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
|
|
37431
37577
|
bugLines.map((line) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "start", children: [
|
|
37432
37578
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37433
37579
|
Icon,
|
|
@@ -37443,7 +37589,7 @@ function DebuggerBoard({
|
|
|
37443
37589
|
] })
|
|
37444
37590
|
] }, line.id))
|
|
37445
37591
|
] }) }),
|
|
37446
|
-
showHint &&
|
|
37592
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
37447
37593
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
37448
37594
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
|
|
37449
37595
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
@@ -37462,6 +37608,7 @@ var init_DebuggerBoard = __esm({
|
|
|
37462
37608
|
"components/game/organisms/puzzles/debugger/DebuggerBoard.tsx"() {
|
|
37463
37609
|
init_atoms2();
|
|
37464
37610
|
init_useEventBus();
|
|
37611
|
+
init_boardEntity();
|
|
37465
37612
|
DebuggerBoard.displayName = "DebuggerBoard";
|
|
37466
37613
|
}
|
|
37467
37614
|
});
|
|
@@ -37499,7 +37646,7 @@ function getBadgeVariant(fieldName, value) {
|
|
|
37499
37646
|
return "default";
|
|
37500
37647
|
}
|
|
37501
37648
|
function formatFieldLabel(fieldName) {
|
|
37502
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
37649
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
|
|
37503
37650
|
}
|
|
37504
37651
|
function formatFieldValue(value, fieldName) {
|
|
37505
37652
|
if (typeof value === "number") {
|
|
@@ -37518,26 +37665,26 @@ function formatFieldValue(value, fieldName) {
|
|
|
37518
37665
|
}
|
|
37519
37666
|
function renderRichFieldValue(value, fieldName, fieldType) {
|
|
37520
37667
|
if (value === void 0 || value === null) return "\u2014";
|
|
37521
|
-
const
|
|
37668
|
+
const str2 = String(value);
|
|
37522
37669
|
switch (fieldType) {
|
|
37523
37670
|
case "image":
|
|
37524
37671
|
case "url": {
|
|
37525
|
-
if (
|
|
37672
|
+
if (str2.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str2.startsWith("data:image/")) {
|
|
37526
37673
|
return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
37527
37674
|
"img",
|
|
37528
37675
|
{
|
|
37529
|
-
src:
|
|
37676
|
+
src: str2,
|
|
37530
37677
|
alt: formatFieldLabel(fieldName),
|
|
37531
37678
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
37532
37679
|
loading: "lazy"
|
|
37533
37680
|
}
|
|
37534
37681
|
) });
|
|
37535
37682
|
}
|
|
37536
|
-
return
|
|
37683
|
+
return str2;
|
|
37537
37684
|
}
|
|
37538
37685
|
case "markdown":
|
|
37539
37686
|
case "richtext":
|
|
37540
|
-
return /* @__PURE__ */ jsxRuntime.jsx(React84.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children:
|
|
37687
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React84.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: "break-words", children: str2 }), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
37541
37688
|
Box,
|
|
37542
37689
|
{
|
|
37543
37690
|
className: "prose prose-sm max-w-none",
|
|
@@ -37555,11 +37702,11 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
37555
37702
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
37556
37703
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
37557
37704
|
},
|
|
37558
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children:
|
|
37705
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ReactMarkdown2, { children: str2 })
|
|
37559
37706
|
}
|
|
37560
37707
|
) });
|
|
37561
37708
|
case "code":
|
|
37562
|
-
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:
|
|
37709
|
+
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 }) }) });
|
|
37563
37710
|
case "html":
|
|
37564
37711
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
37565
37712
|
Box,
|
|
@@ -37579,12 +37726,12 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
37579
37726
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
37580
37727
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
37581
37728
|
},
|
|
37582
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children:
|
|
37729
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str2 })
|
|
37583
37730
|
}
|
|
37584
37731
|
);
|
|
37585
37732
|
case "date":
|
|
37586
37733
|
case "datetime": {
|
|
37587
|
-
const d = new Date(
|
|
37734
|
+
const d = new Date(str2);
|
|
37588
37735
|
if (!isNaN(d.getTime())) {
|
|
37589
37736
|
return d.toLocaleDateString(void 0, {
|
|
37590
37737
|
year: "numeric",
|
|
@@ -37593,7 +37740,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
37593
37740
|
...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
|
|
37594
37741
|
});
|
|
37595
37742
|
}
|
|
37596
|
-
return
|
|
37743
|
+
return str2;
|
|
37597
37744
|
}
|
|
37598
37745
|
default:
|
|
37599
37746
|
return formatFieldValue(value, fieldName);
|
|
@@ -38271,6 +38418,40 @@ var init_RuleEditor = __esm({
|
|
|
38271
38418
|
RuleEditor.displayName = "RuleEditor";
|
|
38272
38419
|
}
|
|
38273
38420
|
});
|
|
38421
|
+
|
|
38422
|
+
// components/game/organisms/puzzles/event-handler/puzzleObject.ts
|
|
38423
|
+
function objId(o) {
|
|
38424
|
+
return o.id == null ? "" : String(o.id);
|
|
38425
|
+
}
|
|
38426
|
+
function objName(o) {
|
|
38427
|
+
return o.name == null ? "" : String(o.name);
|
|
38428
|
+
}
|
|
38429
|
+
function objIcon(o) {
|
|
38430
|
+
return o.icon == null ? "" : String(o.icon);
|
|
38431
|
+
}
|
|
38432
|
+
function objStates(o) {
|
|
38433
|
+
return Array.isArray(o.states) ? o.states : [];
|
|
38434
|
+
}
|
|
38435
|
+
function objCurrentState(o) {
|
|
38436
|
+
return o.currentState == null ? "" : String(o.currentState);
|
|
38437
|
+
}
|
|
38438
|
+
function objAvailableEvents(o) {
|
|
38439
|
+
return Array.isArray(o.availableEvents) ? o.availableEvents : [];
|
|
38440
|
+
}
|
|
38441
|
+
function objAvailableActions(o) {
|
|
38442
|
+
return Array.isArray(o.availableActions) ? o.availableActions : [];
|
|
38443
|
+
}
|
|
38444
|
+
function objRules(o) {
|
|
38445
|
+
return Array.isArray(o.rules) ? o.rules : [];
|
|
38446
|
+
}
|
|
38447
|
+
function objMaxRules(o) {
|
|
38448
|
+
const n = Number(o.maxRules);
|
|
38449
|
+
return Number.isFinite(n) && n > 0 ? n : 3;
|
|
38450
|
+
}
|
|
38451
|
+
var init_puzzleObject = __esm({
|
|
38452
|
+
"components/game/organisms/puzzles/event-handler/puzzleObject.ts"() {
|
|
38453
|
+
}
|
|
38454
|
+
});
|
|
38274
38455
|
function ObjectRulePanel({
|
|
38275
38456
|
object,
|
|
38276
38457
|
onRulesChange,
|
|
@@ -38278,55 +38459,63 @@ function ObjectRulePanel({
|
|
|
38278
38459
|
className
|
|
38279
38460
|
}) {
|
|
38280
38461
|
const { t } = hooks.useTranslate();
|
|
38281
|
-
const
|
|
38282
|
-
const
|
|
38462
|
+
const id = objId(object);
|
|
38463
|
+
const name = objName(object);
|
|
38464
|
+
const icon = objIcon(object);
|
|
38465
|
+
const states = objStates(object);
|
|
38466
|
+
const currentState = objCurrentState(object);
|
|
38467
|
+
const availableEvents = objAvailableEvents(object);
|
|
38468
|
+
const availableActions = objAvailableActions(object);
|
|
38469
|
+
const rules = objRules(object);
|
|
38470
|
+
const maxRules = objMaxRules(object);
|
|
38471
|
+
const canAdd = rules.length < maxRules;
|
|
38283
38472
|
const handleRuleChange = React84.useCallback((index, updatedRule) => {
|
|
38284
|
-
const newRules = [...
|
|
38473
|
+
const newRules = [...rules];
|
|
38285
38474
|
newRules[index] = updatedRule;
|
|
38286
|
-
onRulesChange(
|
|
38287
|
-
}, [
|
|
38475
|
+
onRulesChange(id, newRules);
|
|
38476
|
+
}, [id, rules, onRulesChange]);
|
|
38288
38477
|
const handleRuleRemove = React84.useCallback((index) => {
|
|
38289
|
-
const newRules =
|
|
38290
|
-
onRulesChange(
|
|
38291
|
-
}, [
|
|
38478
|
+
const newRules = rules.filter((_, i) => i !== index);
|
|
38479
|
+
onRulesChange(id, newRules);
|
|
38480
|
+
}, [id, rules, onRulesChange]);
|
|
38292
38481
|
const handleAddRule = React84.useCallback(() => {
|
|
38293
38482
|
if (!canAdd || disabled) return;
|
|
38294
|
-
const firstEvent =
|
|
38295
|
-
const firstAction =
|
|
38483
|
+
const firstEvent = availableEvents[0]?.value || "";
|
|
38484
|
+
const firstAction = availableActions[0]?.value || "";
|
|
38296
38485
|
const newRule = {
|
|
38297
38486
|
id: `rule-${nextRuleId++}`,
|
|
38298
38487
|
whenEvent: firstEvent,
|
|
38299
38488
|
thenAction: firstAction
|
|
38300
38489
|
};
|
|
38301
|
-
onRulesChange(
|
|
38302
|
-
}, [canAdd, disabled,
|
|
38490
|
+
onRulesChange(id, [...rules, newRule]);
|
|
38491
|
+
}, [canAdd, disabled, id, rules, availableEvents, availableActions, onRulesChange]);
|
|
38303
38492
|
const machine = {
|
|
38304
|
-
name
|
|
38305
|
-
states
|
|
38306
|
-
currentState
|
|
38307
|
-
transitions:
|
|
38308
|
-
from:
|
|
38309
|
-
to:
|
|
38493
|
+
name,
|
|
38494
|
+
states,
|
|
38495
|
+
currentState,
|
|
38496
|
+
transitions: rules.map((r) => ({
|
|
38497
|
+
from: currentState,
|
|
38498
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38310
38499
|
event: r.whenEvent
|
|
38311
38500
|
}))
|
|
38312
38501
|
};
|
|
38313
38502
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-4 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
38314
38503
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center", gap: "sm", children: [
|
|
38315
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children:
|
|
38504
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: icon }),
|
|
38316
38505
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
38317
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children:
|
|
38318
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " +
|
|
38506
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children: name }),
|
|
38507
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " + currentState })
|
|
38319
38508
|
] })
|
|
38320
38509
|
] }),
|
|
38321
38510
|
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" }),
|
|
38322
38511
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
38323
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count:
|
|
38324
|
-
|
|
38512
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count: rules.length, max: maxRules }) + ":" }),
|
|
38513
|
+
rules.map((rule, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
38325
38514
|
RuleEditor,
|
|
38326
38515
|
{
|
|
38327
38516
|
rule,
|
|
38328
|
-
availableEvents
|
|
38329
|
-
availableActions
|
|
38517
|
+
availableEvents,
|
|
38518
|
+
availableActions,
|
|
38330
38519
|
onChange: (r) => handleRuleChange(i, r),
|
|
38331
38520
|
onRemove: () => handleRuleRemove(i),
|
|
38332
38521
|
disabled
|
|
@@ -38344,6 +38533,7 @@ var init_ObjectRulePanel = __esm({
|
|
|
38344
38533
|
init_cn();
|
|
38345
38534
|
init_TraitStateViewer();
|
|
38346
38535
|
init_RuleEditor();
|
|
38536
|
+
init_puzzleObject();
|
|
38347
38537
|
nextRuleId = 1;
|
|
38348
38538
|
ObjectRulePanel.displayName = "ObjectRulePanel";
|
|
38349
38539
|
}
|
|
@@ -38410,11 +38600,11 @@ function EventHandlerBoard({
|
|
|
38410
38600
|
}) {
|
|
38411
38601
|
const { emit } = useEventBus();
|
|
38412
38602
|
const { t } = hooks.useTranslate();
|
|
38413
|
-
const resolved =
|
|
38414
|
-
const entityObjects = resolved?.objects
|
|
38415
|
-
const [objects, setObjects] = React84.useState(entityObjects);
|
|
38603
|
+
const resolved = boardEntity(entity);
|
|
38604
|
+
const entityObjects = rows(resolved?.objects);
|
|
38605
|
+
const [objects, setObjects] = React84.useState(() => [...entityObjects]);
|
|
38416
38606
|
const [selectedObjectId, setSelectedObjectId] = React84.useState(
|
|
38417
|
-
entityObjects[0]
|
|
38607
|
+
entityObjects[0] ? objId(entityObjects[0]) : null
|
|
38418
38608
|
);
|
|
38419
38609
|
const [headerError, setHeaderError] = React84.useState(false);
|
|
38420
38610
|
const [playState, setPlayState] = React84.useState("editing");
|
|
@@ -38425,10 +38615,10 @@ function EventHandlerBoard({
|
|
|
38425
38615
|
React84.useEffect(() => () => {
|
|
38426
38616
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38427
38617
|
}, []);
|
|
38428
|
-
const selectedObject = objects.find((o) => o
|
|
38618
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) || null;
|
|
38429
38619
|
const handleRulesChange = React84.useCallback((objectId, rules) => {
|
|
38430
38620
|
setObjects((prev) => prev.map(
|
|
38431
|
-
(o) => o
|
|
38621
|
+
(o) => objId(o) === objectId ? { ...o, rules } : o
|
|
38432
38622
|
));
|
|
38433
38623
|
}, []);
|
|
38434
38624
|
const addLogEntry = React84.useCallback((icon, message, status = "done") => {
|
|
@@ -38442,11 +38632,12 @@ function EventHandlerBoard({
|
|
|
38442
38632
|
setEventLog([]);
|
|
38443
38633
|
const allRules = [];
|
|
38444
38634
|
objects.forEach((obj) => {
|
|
38445
|
-
obj.
|
|
38635
|
+
objRules(obj).forEach((rule) => {
|
|
38446
38636
|
allRules.push({ object: obj, rule });
|
|
38447
38637
|
});
|
|
38448
38638
|
});
|
|
38449
|
-
const triggers = resolved?.triggerEvents
|
|
38639
|
+
const triggers = Array.isArray(resolved?.triggerEvents) ? resolved.triggerEvents : [];
|
|
38640
|
+
const goalEvent = str(resolved?.goalEvent);
|
|
38450
38641
|
const eventQueue = [...triggers];
|
|
38451
38642
|
const firedEvents = /* @__PURE__ */ new Set();
|
|
38452
38643
|
let stepIdx = 0;
|
|
@@ -38475,14 +38666,14 @@ function EventHandlerBoard({
|
|
|
38475
38666
|
addLogEntry("\u26A1", t("eventHandler.noListeners", { event: currentEvent }), "done");
|
|
38476
38667
|
} else {
|
|
38477
38668
|
matching.forEach(({ object, rule }) => {
|
|
38478
|
-
addLogEntry(object
|
|
38669
|
+
addLogEntry(objIcon(object), t("eventHandler.heardEvent", { object: objName(object), event: currentEvent, action: rule.thenAction }), "done");
|
|
38479
38670
|
eventQueue.push(rule.thenAction);
|
|
38480
|
-
if (rule.thenAction ===
|
|
38671
|
+
if (rule.thenAction === goalEvent) {
|
|
38481
38672
|
goalReached = true;
|
|
38482
38673
|
}
|
|
38483
38674
|
});
|
|
38484
38675
|
}
|
|
38485
|
-
if (currentEvent ===
|
|
38676
|
+
if (currentEvent === goalEvent) {
|
|
38486
38677
|
goalReached = true;
|
|
38487
38678
|
}
|
|
38488
38679
|
stepIdx++;
|
|
@@ -38500,65 +38691,75 @@ function EventHandlerBoard({
|
|
|
38500
38691
|
}, []);
|
|
38501
38692
|
const handleReset = React84.useCallback(() => {
|
|
38502
38693
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38503
|
-
|
|
38694
|
+
const resetObjects = rows(resolved?.objects);
|
|
38695
|
+
setObjects([...resetObjects]);
|
|
38504
38696
|
setPlayState("editing");
|
|
38505
38697
|
setEventLog([]);
|
|
38506
|
-
setSelectedObjectId(
|
|
38698
|
+
setSelectedObjectId(resetObjects[0] ? objId(resetObjects[0]) : null);
|
|
38507
38699
|
setAttempts(0);
|
|
38508
38700
|
}, [resolved?.objects]);
|
|
38509
38701
|
if (!resolved) return null;
|
|
38510
38702
|
const objectViewers = objects.map((obj) => {
|
|
38703
|
+
const states = objStates(obj);
|
|
38704
|
+
const currentState = objCurrentState(obj);
|
|
38511
38705
|
const machine = {
|
|
38512
|
-
name: obj
|
|
38513
|
-
states
|
|
38514
|
-
currentState
|
|
38515
|
-
transitions: obj.
|
|
38516
|
-
from:
|
|
38517
|
-
to:
|
|
38706
|
+
name: objName(obj),
|
|
38707
|
+
states,
|
|
38708
|
+
currentState,
|
|
38709
|
+
transitions: objRules(obj).map((r) => ({
|
|
38710
|
+
from: currentState,
|
|
38711
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38518
38712
|
event: r.whenEvent
|
|
38519
38713
|
}))
|
|
38520
38714
|
};
|
|
38521
38715
|
return { obj, machine };
|
|
38522
38716
|
});
|
|
38523
|
-
const
|
|
38717
|
+
const hint = str(resolved.hint);
|
|
38718
|
+
const showHint = attempts >= 3 && hint;
|
|
38719
|
+
const theme = resolved.theme ?? void 0;
|
|
38720
|
+
const themeBackground = theme?.background;
|
|
38721
|
+
const headerImage = str(resolved.headerImage);
|
|
38524
38722
|
const encourageKey = ENCOURAGEMENT_KEYS[Math.min(attempts - 1, ENCOURAGEMENT_KEYS.length - 1)] ?? ENCOURAGEMENT_KEYS[0];
|
|
38525
38723
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
38526
38724
|
VStack,
|
|
38527
38725
|
{
|
|
38528
38726
|
className: cn("p-4 gap-6", className),
|
|
38529
38727
|
style: {
|
|
38530
|
-
backgroundImage:
|
|
38728
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
38531
38729
|
backgroundSize: "cover",
|
|
38532
38730
|
backgroundPosition: "center"
|
|
38533
38731
|
},
|
|
38534
38732
|
children: [
|
|
38535
|
-
|
|
38733
|
+
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,
|
|
38536
38734
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
38537
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
38538
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
38735
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
38736
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
38539
38737
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
|
|
38540
38738
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
|
|
38541
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: resolved.goalCondition })
|
|
38739
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: str(resolved.goalCondition) })
|
|
38542
38740
|
] })
|
|
38543
38741
|
] }),
|
|
38544
38742
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
38545
38743
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
|
|
38546
|
-
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) =>
|
|
38547
|
-
|
|
38548
|
-
|
|
38549
|
-
|
|
38550
|
-
|
|
38551
|
-
|
|
38552
|
-
|
|
38553
|
-
|
|
38554
|
-
|
|
38555
|
-
|
|
38556
|
-
/* @__PURE__ */ jsxRuntime.
|
|
38557
|
-
|
|
38558
|
-
|
|
38559
|
-
|
|
38560
|
-
|
|
38561
|
-
|
|
38744
|
+
/* @__PURE__ */ jsxRuntime.jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => {
|
|
38745
|
+
const oid = objId(obj);
|
|
38746
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
38747
|
+
Box,
|
|
38748
|
+
{
|
|
38749
|
+
className: cn(
|
|
38750
|
+
"p-3 rounded-container border-2 cursor-pointer transition-all hover:scale-105",
|
|
38751
|
+
selectedObjectId === oid ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
|
|
38752
|
+
),
|
|
38753
|
+
onClick: () => setSelectedObjectId(oid),
|
|
38754
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
|
|
38755
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h5", children: objIcon(obj) }),
|
|
38756
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: objName(obj) }),
|
|
38757
|
+
/* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
|
|
38758
|
+
] })
|
|
38759
|
+
},
|
|
38760
|
+
oid
|
|
38761
|
+
);
|
|
38762
|
+
}) })
|
|
38562
38763
|
] }),
|
|
38563
38764
|
selectedObject && /* @__PURE__ */ jsxRuntime.jsx(
|
|
38564
38765
|
ObjectRulePanel,
|
|
@@ -38569,12 +38770,12 @@ function EventHandlerBoard({
|
|
|
38569
38770
|
}
|
|
38570
38771
|
),
|
|
38571
38772
|
eventLog.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(EventLog, { entries: eventLog }),
|
|
38572
|
-
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") }) }),
|
|
38773
|
+
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") }) }),
|
|
38573
38774
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
38574
38775
|
/* @__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) }) }),
|
|
38575
38776
|
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: [
|
|
38576
38777
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
38577
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
38778
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
38578
38779
|
] }) })
|
|
38579
38780
|
] }),
|
|
38580
38781
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -38602,6 +38803,8 @@ var init_EventHandlerBoard = __esm({
|
|
|
38602
38803
|
init_TraitStateViewer();
|
|
38603
38804
|
init_ObjectRulePanel();
|
|
38604
38805
|
init_EventLog();
|
|
38806
|
+
init_puzzleObject();
|
|
38807
|
+
init_boardEntity();
|
|
38605
38808
|
ENCOURAGEMENT_KEYS = [
|
|
38606
38809
|
"puzzle.tryAgain1",
|
|
38607
38810
|
"puzzle.tryAgain2",
|
|
@@ -38690,7 +38893,10 @@ var init_FeatureGridOrganism = __esm({
|
|
|
38690
38893
|
);
|
|
38691
38894
|
React84.useCallback(
|
|
38692
38895
|
(feature) => {
|
|
38693
|
-
eventBus.emit("UI:FEATURE_CLICK", {
|
|
38896
|
+
eventBus.emit("UI:FEATURE_CLICK", {
|
|
38897
|
+
id: String(feature.id ?? ""),
|
|
38898
|
+
href: String(feature.href ?? "")
|
|
38899
|
+
});
|
|
38694
38900
|
},
|
|
38695
38901
|
[eventBus]
|
|
38696
38902
|
);
|
|
@@ -38700,14 +38906,17 @@ var init_FeatureGridOrganism = __esm({
|
|
|
38700
38906
|
if (error) {
|
|
38701
38907
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
38702
38908
|
}
|
|
38703
|
-
const featureCards = items.map((feature) =>
|
|
38704
|
-
|
|
38705
|
-
|
|
38706
|
-
|
|
38707
|
-
|
|
38708
|
-
|
|
38709
|
-
|
|
38710
|
-
|
|
38909
|
+
const featureCards = items.map((feature) => {
|
|
38910
|
+
const href = feature.href != null ? String(feature.href) : void 0;
|
|
38911
|
+
return {
|
|
38912
|
+
icon: feature.icon != null ? String(feature.icon) : void 0,
|
|
38913
|
+
title: String(feature.title ?? ""),
|
|
38914
|
+
description: String(feature.description ?? ""),
|
|
38915
|
+
href,
|
|
38916
|
+
linkLabel: feature.linkLabel != null ? String(feature.linkLabel) : void 0,
|
|
38917
|
+
variant: href ? "interactive" : "bordered"
|
|
38918
|
+
};
|
|
38919
|
+
});
|
|
38711
38920
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
38712
38921
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
38713
38922
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
@@ -40025,22 +40234,24 @@ var init_HeroOrganism = __esm({
|
|
|
40025
40234
|
() => Array.isArray(entity) ? entity[0] : entity && typeof entity === "object" ? entity : void 0,
|
|
40026
40235
|
[entity]
|
|
40027
40236
|
);
|
|
40237
|
+
const primaryAction = resolved?.primaryAction;
|
|
40238
|
+
const secondaryAction = resolved?.secondaryAction;
|
|
40028
40239
|
const handlePrimaryClick = React84.useCallback(() => {
|
|
40029
|
-
if (
|
|
40240
|
+
if (primaryAction) {
|
|
40030
40241
|
eventBus.emit("UI:CTA_PRIMARY", {
|
|
40031
|
-
label:
|
|
40032
|
-
href:
|
|
40242
|
+
label: String(primaryAction.label ?? ""),
|
|
40243
|
+
href: String(primaryAction.href ?? "")
|
|
40033
40244
|
});
|
|
40034
40245
|
}
|
|
40035
|
-
}, [eventBus,
|
|
40246
|
+
}, [eventBus, primaryAction]);
|
|
40036
40247
|
const handleSecondaryClick = React84.useCallback(() => {
|
|
40037
|
-
if (
|
|
40248
|
+
if (secondaryAction) {
|
|
40038
40249
|
eventBus.emit("UI:CTA_SECONDARY", {
|
|
40039
|
-
label:
|
|
40040
|
-
href:
|
|
40250
|
+
label: String(secondaryAction.label ?? ""),
|
|
40251
|
+
href: String(secondaryAction.href ?? "")
|
|
40041
40252
|
});
|
|
40042
40253
|
}
|
|
40043
|
-
}, [eventBus,
|
|
40254
|
+
}, [eventBus, secondaryAction]);
|
|
40044
40255
|
if (isLoading) {
|
|
40045
40256
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
40046
40257
|
}
|
|
@@ -40050,17 +40261,19 @@ var init_HeroOrganism = __esm({
|
|
|
40050
40261
|
if (!resolved) {
|
|
40051
40262
|
return null;
|
|
40052
40263
|
}
|
|
40264
|
+
const imageRaw = resolved.image;
|
|
40265
|
+
const image = imageRaw ? { src: String(imageRaw.src ?? ""), alt: String(imageRaw.alt ?? "") } : void 0;
|
|
40053
40266
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
40054
40267
|
HeroSection,
|
|
40055
40268
|
{
|
|
40056
|
-
tag: resolved.tag,
|
|
40057
|
-
title: resolved.title,
|
|
40058
|
-
titleAccent: resolved.titleAccent,
|
|
40059
|
-
subtitle: resolved.subtitle,
|
|
40060
|
-
primaryAction:
|
|
40061
|
-
secondaryAction:
|
|
40062
|
-
installCommand: resolved.installCommand,
|
|
40063
|
-
image
|
|
40269
|
+
tag: resolved.tag != null ? String(resolved.tag) : void 0,
|
|
40270
|
+
title: String(resolved.title ?? ""),
|
|
40271
|
+
titleAccent: resolved.titleAccent != null ? String(resolved.titleAccent) : void 0,
|
|
40272
|
+
subtitle: String(resolved.subtitle ?? ""),
|
|
40273
|
+
primaryAction: primaryAction ? { label: String(primaryAction.label ?? ""), href: String(primaryAction.href ?? "") } : void 0,
|
|
40274
|
+
secondaryAction: secondaryAction ? { label: String(secondaryAction.label ?? ""), href: String(secondaryAction.href ?? "") } : void 0,
|
|
40275
|
+
installCommand: resolved.installCommand != null ? String(resolved.installCommand) : void 0,
|
|
40276
|
+
image,
|
|
40064
40277
|
imagePosition: resolved.imagePosition,
|
|
40065
40278
|
background: resolved.background,
|
|
40066
40279
|
className: cn(className),
|
|
@@ -40069,8 +40282,8 @@ var init_HeroOrganism = __esm({
|
|
|
40069
40282
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
40070
40283
|
_HeroClickInterceptor,
|
|
40071
40284
|
{
|
|
40072
|
-
hasPrimary: !!
|
|
40073
|
-
hasSecondary: !!
|
|
40285
|
+
hasPrimary: !!primaryAction,
|
|
40286
|
+
hasSecondary: !!secondaryAction,
|
|
40074
40287
|
onPrimaryClick: handlePrimaryClick,
|
|
40075
40288
|
onSecondaryClick: handleSecondaryClick
|
|
40076
40289
|
}
|
|
@@ -40299,7 +40512,7 @@ function formatValue3(value, fieldName) {
|
|
|
40299
40512
|
return String(value);
|
|
40300
40513
|
}
|
|
40301
40514
|
function formatFieldLabel2(fieldName) {
|
|
40302
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
40515
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
|
|
40303
40516
|
}
|
|
40304
40517
|
var STATUS_STYLES2, StatusBadge, ProgressIndicator, List3;
|
|
40305
40518
|
var init_List = __esm({
|
|
@@ -41146,20 +41359,22 @@ function NegotiatorBoard({
|
|
|
41146
41359
|
}) {
|
|
41147
41360
|
const { emit } = useEventBus();
|
|
41148
41361
|
const { t } = hooks.useTranslate();
|
|
41149
|
-
const resolved =
|
|
41362
|
+
const resolved = boardEntity(entity);
|
|
41150
41363
|
const [history, setHistory] = React84.useState([]);
|
|
41151
41364
|
const [headerError, setHeaderError] = React84.useState(false);
|
|
41152
41365
|
const [showHint, setShowHint] = React84.useState(false);
|
|
41366
|
+
const totalRounds = num(resolved?.totalRounds);
|
|
41367
|
+
const targetScore = num(resolved?.targetScore);
|
|
41153
41368
|
const currentRound = history.length;
|
|
41154
|
-
const isComplete = currentRound >=
|
|
41369
|
+
const isComplete = currentRound >= totalRounds;
|
|
41155
41370
|
const playerTotal = history.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41156
41371
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
41157
|
-
const won = isComplete && playerTotal >=
|
|
41158
|
-
const actions = resolved?.actions
|
|
41159
|
-
const payoffMatrix = resolved?.payoffMatrix
|
|
41372
|
+
const won = isComplete && playerTotal >= targetScore;
|
|
41373
|
+
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
41374
|
+
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
41160
41375
|
const handleAction = React84.useCallback((actionId) => {
|
|
41161
41376
|
if (isComplete) return;
|
|
41162
|
-
const opponentAction = getOpponentAction(resolved?.opponentStrategy
|
|
41377
|
+
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
41163
41378
|
const payoff = payoffMatrix.find(
|
|
41164
41379
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
41165
41380
|
);
|
|
@@ -41172,42 +41387,46 @@ function NegotiatorBoard({
|
|
|
41172
41387
|
};
|
|
41173
41388
|
const newHistory = [...history, result];
|
|
41174
41389
|
setHistory(newHistory);
|
|
41175
|
-
if (newHistory.length >=
|
|
41390
|
+
if (newHistory.length >= totalRounds) {
|
|
41176
41391
|
const total = newHistory.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41177
|
-
if (total >=
|
|
41392
|
+
if (total >= targetScore) {
|
|
41178
41393
|
emit(`UI:${completeEvent}`, { success: true, score: total });
|
|
41179
41394
|
}
|
|
41180
|
-
if (newHistory.length >= 3 && resolved?.hint) {
|
|
41395
|
+
if (newHistory.length >= 3 && str(resolved?.hint)) {
|
|
41181
41396
|
setShowHint(true);
|
|
41182
41397
|
}
|
|
41183
41398
|
}
|
|
41184
|
-
}, [isComplete, resolved, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41399
|
+
}, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41185
41400
|
const handleReset = () => {
|
|
41186
41401
|
setHistory([]);
|
|
41187
41402
|
setShowHint(false);
|
|
41188
41403
|
};
|
|
41189
41404
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
41190
41405
|
if (!resolved) return null;
|
|
41406
|
+
const theme = resolved.theme ?? void 0;
|
|
41407
|
+
const themeBackground = theme?.background;
|
|
41408
|
+
const headerImage = str(resolved.headerImage);
|
|
41409
|
+
const hint = str(resolved.hint);
|
|
41191
41410
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
41192
41411
|
Box,
|
|
41193
41412
|
{
|
|
41194
41413
|
className,
|
|
41195
41414
|
style: {
|
|
41196
|
-
backgroundImage:
|
|
41415
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
41197
41416
|
backgroundSize: "cover",
|
|
41198
41417
|
backgroundPosition: "center"
|
|
41199
41418
|
},
|
|
41200
41419
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
41201
|
-
|
|
41420
|
+
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,
|
|
41202
41421
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
41203
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
41204
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description }),
|
|
41422
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
41423
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
41205
41424
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", children: [
|
|
41206
|
-
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(
|
|
41425
|
+
/* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(totalRounds) }) }),
|
|
41207
41426
|
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", children: [
|
|
41208
41427
|
t("negotiator.target"),
|
|
41209
41428
|
": ",
|
|
41210
|
-
|
|
41429
|
+
targetScore
|
|
41211
41430
|
] })
|
|
41212
41431
|
] })
|
|
41213
41432
|
] }) }),
|
|
@@ -41256,16 +41475,16 @@ function NegotiatorBoard({
|
|
|
41256
41475
|
] }) }),
|
|
41257
41476
|
isComplete && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
41258
41477
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: won ? "text-success" : "text-error" }),
|
|
41259
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? resolved.successMessage
|
|
41478
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: won ? str(resolved.successMessage) || t("negotiator.success") : str(resolved.failMessage) || t("negotiator.failed") }),
|
|
41260
41479
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
41261
41480
|
t("negotiator.finalScore"),
|
|
41262
41481
|
": ",
|
|
41263
41482
|
playerTotal,
|
|
41264
41483
|
"/",
|
|
41265
|
-
|
|
41484
|
+
targetScore
|
|
41266
41485
|
] })
|
|
41267
41486
|
] }) }),
|
|
41268
|
-
showHint &&
|
|
41487
|
+
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 }) }),
|
|
41269
41488
|
isComplete && !won && /* @__PURE__ */ jsxRuntime.jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
|
|
41270
41489
|
] })
|
|
41271
41490
|
}
|
|
@@ -41275,6 +41494,7 @@ var init_NegotiatorBoard = __esm({
|
|
|
41275
41494
|
"components/game/organisms/puzzles/negotiator/NegotiatorBoard.tsx"() {
|
|
41276
41495
|
init_atoms2();
|
|
41277
41496
|
init_useEventBus();
|
|
41497
|
+
init_boardEntity();
|
|
41278
41498
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
41279
41499
|
}
|
|
41280
41500
|
});
|
|
@@ -41310,13 +41530,13 @@ var init_PricingOrganism = __esm({
|
|
|
41310
41530
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
41311
41531
|
}
|
|
41312
41532
|
const plans = items.map((plan) => ({
|
|
41313
|
-
name: plan.name,
|
|
41314
|
-
price: plan.price,
|
|
41315
|
-
description: plan.description,
|
|
41316
|
-
features: plan.features,
|
|
41317
|
-
action: { label: plan.actionLabel, href: plan.actionHref },
|
|
41318
|
-
highlighted: plan.highlighted,
|
|
41319
|
-
badge: plan.badge
|
|
41533
|
+
name: String(plan.name ?? ""),
|
|
41534
|
+
price: String(plan.price ?? ""),
|
|
41535
|
+
description: plan.description != null ? String(plan.description) : void 0,
|
|
41536
|
+
features: (plan.features ?? []).map((f3) => String(f3)),
|
|
41537
|
+
action: { label: String(plan.actionLabel ?? ""), href: String(plan.actionHref ?? "") },
|
|
41538
|
+
highlighted: Boolean(plan.highlighted),
|
|
41539
|
+
badge: plan.badge != null ? String(plan.badge) : void 0
|
|
41320
41540
|
}));
|
|
41321
41541
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
41322
41542
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -43406,16 +43626,20 @@ function SequencerBoard({
|
|
|
43406
43626
|
}) {
|
|
43407
43627
|
const { emit } = useEventBus();
|
|
43408
43628
|
const { t } = hooks.useTranslate();
|
|
43409
|
-
const resolved =
|
|
43629
|
+
const resolved = boardEntity(entity);
|
|
43630
|
+
const maxSlots = num(resolved?.maxSlots);
|
|
43631
|
+
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
43632
|
+
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
43633
|
+
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
43410
43634
|
const [headerError, setHeaderError] = React84.useState(false);
|
|
43411
43635
|
const [slots, setSlots] = React84.useState(
|
|
43412
|
-
() => Array.from({ length:
|
|
43636
|
+
() => Array.from({ length: maxSlots }, () => void 0)
|
|
43413
43637
|
);
|
|
43414
43638
|
const [playState, setPlayState] = React84.useState("idle");
|
|
43415
43639
|
const [currentStep, setCurrentStep] = React84.useState(-1);
|
|
43416
43640
|
const [attempts, setAttempts] = React84.useState(0);
|
|
43417
43641
|
const [slotFeedback, setSlotFeedback] = React84.useState(
|
|
43418
|
-
() => Array.from({ length:
|
|
43642
|
+
() => Array.from({ length: maxSlots }, () => null)
|
|
43419
43643
|
);
|
|
43420
43644
|
const timerRef = React84.useRef(null);
|
|
43421
43645
|
React84.useEffect(() => () => {
|
|
@@ -43449,17 +43673,17 @@ function SequencerBoard({
|
|
|
43449
43673
|
}, [emit]);
|
|
43450
43674
|
const handleReset = React84.useCallback(() => {
|
|
43451
43675
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
43452
|
-
setSlots(Array.from({ length:
|
|
43676
|
+
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
43453
43677
|
setPlayState("idle");
|
|
43454
43678
|
setCurrentStep(-1);
|
|
43455
43679
|
setAttempts(0);
|
|
43456
|
-
setSlotFeedback(Array.from({ length:
|
|
43457
|
-
}, [
|
|
43680
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
43681
|
+
}, [maxSlots]);
|
|
43458
43682
|
const filledSlots = slots.filter((s) => !!s);
|
|
43459
43683
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
43460
43684
|
const handlePlay = React84.useCallback(() => {
|
|
43461
43685
|
if (!canPlay) return;
|
|
43462
|
-
setSlotFeedback(Array.from({ length:
|
|
43686
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
43463
43687
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
43464
43688
|
const sequence = slots.map((s) => s?.id || "");
|
|
43465
43689
|
if (playEvent) {
|
|
@@ -43470,10 +43694,10 @@ function SequencerBoard({
|
|
|
43470
43694
|
let step = 0;
|
|
43471
43695
|
const advance = () => {
|
|
43472
43696
|
step++;
|
|
43473
|
-
if (step >=
|
|
43697
|
+
if (step >= maxSlots) {
|
|
43474
43698
|
const playerSeq = slots.map((s) => s?.id);
|
|
43475
43699
|
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
43476
|
-
const success =
|
|
43700
|
+
const success = solutions.some(
|
|
43477
43701
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
43478
43702
|
);
|
|
43479
43703
|
if (success) {
|
|
@@ -43485,7 +43709,7 @@ function SequencerBoard({
|
|
|
43485
43709
|
}
|
|
43486
43710
|
} else {
|
|
43487
43711
|
setAttempts((prev) => prev + 1);
|
|
43488
|
-
const feedback = computeSlotFeedback(playerSeq,
|
|
43712
|
+
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
43489
43713
|
setSlotFeedback(feedback);
|
|
43490
43714
|
setPlayState("idle");
|
|
43491
43715
|
setCurrentStep(-1);
|
|
@@ -43503,10 +43727,10 @@ function SequencerBoard({
|
|
|
43503
43727
|
}
|
|
43504
43728
|
};
|
|
43505
43729
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
43506
|
-
}, [canPlay, slots,
|
|
43730
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
43507
43731
|
const machine = {
|
|
43508
|
-
name: resolved?.title
|
|
43509
|
-
description: resolved?.description
|
|
43732
|
+
name: str(resolved?.title),
|
|
43733
|
+
description: str(resolved?.description),
|
|
43510
43734
|
states: slots.map((s, i) => stepLabel(s, i)),
|
|
43511
43735
|
currentState: currentStep >= 0 ? stepLabel(slots[currentStep], currentStep) : "__idle__",
|
|
43512
43736
|
transitions: slots.slice(0, -1).map((s, i) => ({
|
|
@@ -43515,37 +43739,41 @@ function SequencerBoard({
|
|
|
43515
43739
|
event: "NEXT"
|
|
43516
43740
|
}))
|
|
43517
43741
|
};
|
|
43518
|
-
const usedIds =
|
|
43519
|
-
const
|
|
43742
|
+
const usedIds = !allowDuplicates ? slots.filter(Boolean).map((s) => s?.id || "") : [];
|
|
43743
|
+
const hint = str(resolved?.hint);
|
|
43744
|
+
const showHint = attempts >= 3 && !!hint;
|
|
43520
43745
|
const hasFeedback = slotFeedback.some((f3) => f3 !== null);
|
|
43521
43746
|
const correctCount = slotFeedback.filter((f3) => f3 === "correct").length;
|
|
43522
43747
|
const encourageKey = ENCOURAGEMENT_KEYS2[Math.min(attempts - 1, ENCOURAGEMENT_KEYS2.length - 1)] ?? ENCOURAGEMENT_KEYS2[0];
|
|
43523
43748
|
if (!resolved) return null;
|
|
43749
|
+
const theme = resolved.theme ?? void 0;
|
|
43750
|
+
const themeBackground = theme?.background;
|
|
43751
|
+
const headerImage = str(resolved.headerImage);
|
|
43524
43752
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
43525
43753
|
VStack,
|
|
43526
43754
|
{
|
|
43527
43755
|
className: cn("p-4 gap-6", className),
|
|
43528
43756
|
style: {
|
|
43529
|
-
backgroundImage:
|
|
43757
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
43530
43758
|
backgroundSize: "cover",
|
|
43531
43759
|
backgroundPosition: "center"
|
|
43532
43760
|
},
|
|
43533
43761
|
children: [
|
|
43534
|
-
|
|
43762
|
+
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,
|
|
43535
43763
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
43536
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
43537
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description })
|
|
43764
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
43765
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) })
|
|
43538
43766
|
] }),
|
|
43539
43767
|
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: [
|
|
43540
43768
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
43541
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
43769
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
43542
43770
|
] }) }),
|
|
43543
43771
|
filledSlots.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
|
|
43544
43772
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
43545
43773
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
43546
43774
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
43547
43775
|
hasFeedback && playState === "idle" && /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
43548
|
-
`${correctCount}/${
|
|
43776
|
+
`${correctCount}/${maxSlots} `,
|
|
43549
43777
|
"\u2705"
|
|
43550
43778
|
] })
|
|
43551
43779
|
] }),
|
|
@@ -43553,7 +43781,7 @@ function SequencerBoard({
|
|
|
43553
43781
|
SequenceBar,
|
|
43554
43782
|
{
|
|
43555
43783
|
slots,
|
|
43556
|
-
maxSlots
|
|
43784
|
+
maxSlots,
|
|
43557
43785
|
onSlotDrop: handleSlotDrop,
|
|
43558
43786
|
onSlotRemove: handleSlotRemove,
|
|
43559
43787
|
playing: playState === "playing",
|
|
@@ -43567,15 +43795,15 @@ function SequencerBoard({
|
|
|
43567
43795
|
playState !== "playing" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
43568
43796
|
ActionPalette,
|
|
43569
43797
|
{
|
|
43570
|
-
actions:
|
|
43798
|
+
actions: availableActions,
|
|
43571
43799
|
usedActionIds: usedIds,
|
|
43572
|
-
allowDuplicates
|
|
43800
|
+
allowDuplicates,
|
|
43573
43801
|
categoryColors,
|
|
43574
43802
|
label: t("sequencer.dragActions")
|
|
43575
43803
|
}
|
|
43576
43804
|
),
|
|
43577
43805
|
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) }) }),
|
|
43578
|
-
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") }) }),
|
|
43806
|
+
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") }) }),
|
|
43579
43807
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
43580
43808
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
43581
43809
|
Button,
|
|
@@ -43599,6 +43827,7 @@ var init_SequencerBoard = __esm({
|
|
|
43599
43827
|
init_cn();
|
|
43600
43828
|
init_useEventBus();
|
|
43601
43829
|
init_TraitStateViewer();
|
|
43830
|
+
init_boardEntity();
|
|
43602
43831
|
init_SequenceBar();
|
|
43603
43832
|
init_ActionPalette();
|
|
43604
43833
|
ENCOURAGEMENT_KEYS2 = [
|
|
@@ -43648,18 +43877,21 @@ var init_ShowcaseOrganism = __esm({
|
|
|
43648
43877
|
heading && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
43649
43878
|
subtitle && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body1", color: "muted", align: "center", className: "max-w-2xl", children: subtitle })
|
|
43650
43879
|
] }),
|
|
43651
|
-
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) =>
|
|
43652
|
-
|
|
43653
|
-
|
|
43654
|
-
|
|
43655
|
-
|
|
43656
|
-
|
|
43657
|
-
|
|
43658
|
-
|
|
43659
|
-
|
|
43660
|
-
|
|
43661
|
-
|
|
43662
|
-
|
|
43880
|
+
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) => {
|
|
43881
|
+
const imageRaw = item.image;
|
|
43882
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
43883
|
+
ShowcaseCard,
|
|
43884
|
+
{
|
|
43885
|
+
title: String(item.title ?? ""),
|
|
43886
|
+
description: item.description != null ? String(item.description) : void 0,
|
|
43887
|
+
image: { src: String(imageRaw?.src ?? ""), alt: String(imageRaw?.alt ?? "") },
|
|
43888
|
+
href: item.href != null ? String(item.href) : void 0,
|
|
43889
|
+
badge: item.badge != null ? String(item.badge) : void 0,
|
|
43890
|
+
accentColor: item.accentColor != null ? String(item.accentColor) : void 0
|
|
43891
|
+
},
|
|
43892
|
+
String(item.id ?? "")
|
|
43893
|
+
);
|
|
43894
|
+
}) })
|
|
43663
43895
|
] });
|
|
43664
43896
|
};
|
|
43665
43897
|
ShowcaseOrganism.displayName = "ShowcaseOrganism";
|
|
@@ -44027,8 +44259,8 @@ function SimulatorBoard({
|
|
|
44027
44259
|
}) {
|
|
44028
44260
|
const { emit } = useEventBus();
|
|
44029
44261
|
const { t } = hooks.useTranslate();
|
|
44030
|
-
const resolved =
|
|
44031
|
-
const parameters = resolved?.parameters
|
|
44262
|
+
const resolved = boardEntity(entity);
|
|
44263
|
+
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
44032
44264
|
const [values, setValues] = React84.useState(() => {
|
|
44033
44265
|
const init = {};
|
|
44034
44266
|
for (const p2 of parameters) {
|
|
@@ -44042,15 +44274,15 @@ function SimulatorBoard({
|
|
|
44042
44274
|
const [showHint, setShowHint] = React84.useState(false);
|
|
44043
44275
|
const computeOutput = React84.useCallback((params) => {
|
|
44044
44276
|
try {
|
|
44045
|
-
const fn = new Function("params", `return (${resolved?.computeExpression})`);
|
|
44277
|
+
const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
|
|
44046
44278
|
return fn(params);
|
|
44047
44279
|
} catch {
|
|
44048
44280
|
return 0;
|
|
44049
44281
|
}
|
|
44050
44282
|
}, [resolved?.computeExpression]);
|
|
44051
44283
|
const output = React84.useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
|
|
44052
|
-
const targetValue = resolved?.targetValue
|
|
44053
|
-
const targetTolerance = resolved?.targetTolerance
|
|
44284
|
+
const targetValue = num(resolved?.targetValue);
|
|
44285
|
+
const targetTolerance = num(resolved?.targetTolerance);
|
|
44054
44286
|
const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
|
|
44055
44287
|
const handleParameterChange = (id, value) => {
|
|
44056
44288
|
if (submitted) return;
|
|
@@ -44065,7 +44297,7 @@ function SimulatorBoard({
|
|
|
44065
44297
|
};
|
|
44066
44298
|
const handleReset = () => {
|
|
44067
44299
|
setSubmitted(false);
|
|
44068
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
44300
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
44069
44301
|
setShowHint(true);
|
|
44070
44302
|
}
|
|
44071
44303
|
};
|
|
@@ -44080,20 +44312,26 @@ function SimulatorBoard({
|
|
|
44080
44312
|
setShowHint(false);
|
|
44081
44313
|
};
|
|
44082
44314
|
if (!resolved) return null;
|
|
44315
|
+
const theme = resolved.theme ?? void 0;
|
|
44316
|
+
const themeBackground = theme?.background;
|
|
44317
|
+
const headerImage = str(resolved.headerImage);
|
|
44318
|
+
const hint = str(resolved.hint);
|
|
44319
|
+
const outputLabel = str(resolved.outputLabel);
|
|
44320
|
+
const outputUnit = str(resolved.outputUnit);
|
|
44083
44321
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44084
44322
|
Box,
|
|
44085
44323
|
{
|
|
44086
44324
|
className,
|
|
44087
44325
|
style: {
|
|
44088
|
-
backgroundImage:
|
|
44326
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
44089
44327
|
backgroundSize: "cover",
|
|
44090
44328
|
backgroundPosition: "center"
|
|
44091
44329
|
},
|
|
44092
44330
|
children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
44093
|
-
|
|
44331
|
+
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,
|
|
44094
44332
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
44095
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
44096
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: resolved.description })
|
|
44333
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
44334
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
44097
44335
|
] }) }),
|
|
44098
44336
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
44099
44337
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
@@ -44134,28 +44372,28 @@ function SimulatorBoard({
|
|
|
44134
44372
|
] }, param.id))
|
|
44135
44373
|
] }) }),
|
|
44136
44374
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
44137
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children:
|
|
44375
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
44138
44376
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", weight: "bold", children: [
|
|
44139
44377
|
output.toFixed(2),
|
|
44140
44378
|
" ",
|
|
44141
|
-
|
|
44379
|
+
outputUnit
|
|
44142
44380
|
] }),
|
|
44143
44381
|
submitted && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
44144
44382
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: isCorrect ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
|
|
44145
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? resolved.successMessage
|
|
44383
|
+
/* @__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") })
|
|
44146
44384
|
] }),
|
|
44147
44385
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44148
44386
|
t("simulator.target"),
|
|
44149
44387
|
": ",
|
|
44150
44388
|
targetValue,
|
|
44151
44389
|
" ",
|
|
44152
|
-
|
|
44390
|
+
outputUnit,
|
|
44153
44391
|
" (\xB1",
|
|
44154
44392
|
targetTolerance,
|
|
44155
44393
|
")"
|
|
44156
44394
|
] })
|
|
44157
44395
|
] }) }),
|
|
44158
|
-
showHint &&
|
|
44396
|
+
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
44159
44397
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
44160
44398
|
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
|
|
44161
44399
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
@@ -44174,6 +44412,7 @@ var init_SimulatorBoard = __esm({
|
|
|
44174
44412
|
"components/game/organisms/puzzles/simulator/SimulatorBoard.tsx"() {
|
|
44175
44413
|
init_atoms2();
|
|
44176
44414
|
init_useEventBus();
|
|
44415
|
+
init_boardEntity();
|
|
44177
44416
|
SimulatorBoard.displayName = "SimulatorBoard";
|
|
44178
44417
|
}
|
|
44179
44418
|
});
|
|
@@ -44599,22 +44838,25 @@ function VariablePanel({
|
|
|
44599
44838
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { className: cn("p-3 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
44600
44839
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
44601
44840
|
variables.map((v) => {
|
|
44602
|
-
const
|
|
44603
|
-
const
|
|
44604
|
-
const
|
|
44841
|
+
const name = v.name == null ? "" : String(v.name);
|
|
44842
|
+
const value = numField(v.value);
|
|
44843
|
+
const max = numField(v.max, 100);
|
|
44844
|
+
const min = numField(v.min, 0);
|
|
44845
|
+
const unit = v.unit == null ? "" : String(v.unit);
|
|
44846
|
+
const pct = Math.round((value - min) / (max - min) * 100);
|
|
44605
44847
|
const isHigh = pct > 80;
|
|
44606
44848
|
const isLow = pct < 20;
|
|
44607
44849
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
44608
44850
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center justify-between", children: [
|
|
44609
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children:
|
|
44851
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children: name }),
|
|
44610
44852
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: cn(
|
|
44611
44853
|
isHigh ? "text-error" : isLow ? "text-warning" : "text-foreground"
|
|
44612
44854
|
), children: [
|
|
44613
|
-
|
|
44614
|
-
|
|
44855
|
+
value,
|
|
44856
|
+
unit,
|
|
44615
44857
|
" / ",
|
|
44616
44858
|
max,
|
|
44617
|
-
|
|
44859
|
+
unit
|
|
44618
44860
|
] })
|
|
44619
44861
|
] }),
|
|
44620
44862
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -44625,14 +44867,19 @@ function VariablePanel({
|
|
|
44625
44867
|
size: "sm"
|
|
44626
44868
|
}
|
|
44627
44869
|
)
|
|
44628
|
-
] },
|
|
44870
|
+
] }, name);
|
|
44629
44871
|
})
|
|
44630
44872
|
] });
|
|
44631
44873
|
}
|
|
44874
|
+
var numField;
|
|
44632
44875
|
var init_VariablePanel = __esm({
|
|
44633
44876
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
44634
44877
|
init_atoms2();
|
|
44635
44878
|
init_cn();
|
|
44879
|
+
numField = (v, fallback = 0) => {
|
|
44880
|
+
const n = Number(v);
|
|
44881
|
+
return Number.isFinite(n) ? n : fallback;
|
|
44882
|
+
};
|
|
44636
44883
|
VariablePanel.displayName = "VariablePanel";
|
|
44637
44884
|
}
|
|
44638
44885
|
});
|
|
@@ -44659,14 +44906,21 @@ function StateArchitectBoard({
|
|
|
44659
44906
|
}) {
|
|
44660
44907
|
const { emit } = useEventBus();
|
|
44661
44908
|
const { t } = hooks.useTranslate();
|
|
44662
|
-
const resolved =
|
|
44663
|
-
const
|
|
44909
|
+
const resolved = boardEntity(entity);
|
|
44910
|
+
const entityStates = Array.isArray(resolved?.states) ? resolved.states : [];
|
|
44911
|
+
const initialState = str(resolved?.initialState);
|
|
44912
|
+
const entityName = str(resolved?.entityName);
|
|
44913
|
+
const availableEvents = Array.isArray(resolved?.availableEvents) ? resolved.availableEvents : [];
|
|
44914
|
+
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
44915
|
+
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
44916
|
+
const entityVariables = rows(resolved?.variables);
|
|
44917
|
+
const [transitions, setTransitions] = React84.useState(entityTransitions);
|
|
44664
44918
|
const [headerError, setHeaderError] = React84.useState(false);
|
|
44665
44919
|
const [playState, setPlayState] = React84.useState("editing");
|
|
44666
|
-
const [currentState, setCurrentState] = React84.useState(
|
|
44920
|
+
const [currentState, setCurrentState] = React84.useState(initialState);
|
|
44667
44921
|
const [selectedState, setSelectedState] = React84.useState(null);
|
|
44668
44922
|
const [testResults, setTestResults] = React84.useState([]);
|
|
44669
|
-
const [variables, setVariables] = React84.useState(
|
|
44923
|
+
const [variables, setVariables] = React84.useState(() => [...entityVariables]);
|
|
44670
44924
|
const [attempts, setAttempts] = React84.useState(0);
|
|
44671
44925
|
const timerRef = React84.useRef(null);
|
|
44672
44926
|
const [addingFrom, setAddingFrom] = React84.useState(null);
|
|
@@ -44675,12 +44929,12 @@ function StateArchitectBoard({
|
|
|
44675
44929
|
}, []);
|
|
44676
44930
|
const GRAPH_W = 500;
|
|
44677
44931
|
const GRAPH_H = 400;
|
|
44678
|
-
const positions = React84.useMemo(() => layoutStates(
|
|
44932
|
+
const positions = React84.useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
44679
44933
|
const handleStateClick = React84.useCallback((state) => {
|
|
44680
44934
|
if (playState !== "editing") return;
|
|
44681
44935
|
if (addingFrom) {
|
|
44682
44936
|
if (addingFrom !== state) {
|
|
44683
|
-
const event =
|
|
44937
|
+
const event = availableEvents[0] || "EVENT";
|
|
44684
44938
|
const newTrans = {
|
|
44685
44939
|
id: `t-${nextTransId++}`,
|
|
44686
44940
|
from: addingFrom,
|
|
@@ -44693,7 +44947,7 @@ function StateArchitectBoard({
|
|
|
44693
44947
|
} else {
|
|
44694
44948
|
setSelectedState(state);
|
|
44695
44949
|
}
|
|
44696
|
-
}, [playState, addingFrom,
|
|
44950
|
+
}, [playState, addingFrom, availableEvents]);
|
|
44697
44951
|
const handleStartAddTransition = React84.useCallback(() => {
|
|
44698
44952
|
if (!selectedState) return;
|
|
44699
44953
|
setAddingFrom(selectedState);
|
|
@@ -44702,9 +44956,9 @@ function StateArchitectBoard({
|
|
|
44702
44956
|
setTransitions((prev) => prev.filter((t2) => t2.id !== transId));
|
|
44703
44957
|
}, []);
|
|
44704
44958
|
const machine = React84.useMemo(() => ({
|
|
44705
|
-
name:
|
|
44706
|
-
description: resolved?.description
|
|
44707
|
-
states:
|
|
44959
|
+
name: entityName,
|
|
44960
|
+
description: str(resolved?.description),
|
|
44961
|
+
states: entityStates,
|
|
44708
44962
|
currentState,
|
|
44709
44963
|
transitions: transitions.map((t2) => ({
|
|
44710
44964
|
from: t2.from,
|
|
@@ -44712,7 +44966,7 @@ function StateArchitectBoard({
|
|
|
44712
44966
|
event: t2.event,
|
|
44713
44967
|
guardHint: t2.guardHint
|
|
44714
44968
|
}))
|
|
44715
|
-
}), [resolved, currentState, transitions]);
|
|
44969
|
+
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
44716
44970
|
const handleTest = React84.useCallback(() => {
|
|
44717
44971
|
if (playState !== "editing") return;
|
|
44718
44972
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
@@ -44721,7 +44975,7 @@ function StateArchitectBoard({
|
|
|
44721
44975
|
const results = [];
|
|
44722
44976
|
let testIdx = 0;
|
|
44723
44977
|
const runNextTest = () => {
|
|
44724
|
-
if (testIdx >=
|
|
44978
|
+
if (testIdx >= testCases.length) {
|
|
44725
44979
|
const allPassed = results.every((r) => r.passed);
|
|
44726
44980
|
setPlayState(allPassed ? "success" : "fail");
|
|
44727
44981
|
setTestResults(results);
|
|
@@ -44736,9 +44990,9 @@ function StateArchitectBoard({
|
|
|
44736
44990
|
}
|
|
44737
44991
|
return;
|
|
44738
44992
|
}
|
|
44739
|
-
const testCase =
|
|
44993
|
+
const testCase = testCases[testIdx];
|
|
44740
44994
|
if (!testCase) return;
|
|
44741
|
-
let state =
|
|
44995
|
+
let state = initialState;
|
|
44742
44996
|
for (const event of testCase.events) {
|
|
44743
44997
|
const trans = transitions.find((t2) => t2.from === state && t2.event === event);
|
|
44744
44998
|
if (trans) {
|
|
@@ -44756,53 +45010,57 @@ function StateArchitectBoard({
|
|
|
44756
45010
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
44757
45011
|
};
|
|
44758
45012
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
44759
|
-
}, [playState, transitions,
|
|
45013
|
+
}, [playState, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
44760
45014
|
const handleTryAgain = React84.useCallback(() => {
|
|
44761
45015
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
44762
45016
|
setPlayState("editing");
|
|
44763
|
-
setCurrentState(
|
|
45017
|
+
setCurrentState(initialState);
|
|
44764
45018
|
setTestResults([]);
|
|
44765
|
-
}, [
|
|
45019
|
+
}, [initialState]);
|
|
44766
45020
|
const handleReset = React84.useCallback(() => {
|
|
44767
45021
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
44768
|
-
setTransitions(
|
|
45022
|
+
setTransitions(entityTransitions);
|
|
44769
45023
|
setPlayState("editing");
|
|
44770
|
-
setCurrentState(
|
|
45024
|
+
setCurrentState(initialState);
|
|
44771
45025
|
setTestResults([]);
|
|
44772
|
-
setVariables(
|
|
45026
|
+
setVariables([...entityVariables]);
|
|
44773
45027
|
setSelectedState(null);
|
|
44774
45028
|
setAddingFrom(null);
|
|
44775
45029
|
setAttempts(0);
|
|
44776
|
-
}, [
|
|
45030
|
+
}, [entityTransitions, initialState, entityVariables]);
|
|
44777
45031
|
const codeData = React84.useMemo(() => ({
|
|
44778
|
-
name:
|
|
44779
|
-
states:
|
|
44780
|
-
initialState
|
|
45032
|
+
name: entityName,
|
|
45033
|
+
states: entityStates,
|
|
45034
|
+
initialState,
|
|
44781
45035
|
transitions: transitions.map((t2) => ({
|
|
44782
45036
|
from: t2.from,
|
|
44783
45037
|
to: t2.to,
|
|
44784
45038
|
event: t2.event,
|
|
44785
45039
|
...t2.guardHint ? { guard: t2.guardHint } : {}
|
|
44786
45040
|
}))
|
|
44787
|
-
}), [
|
|
45041
|
+
}), [entityName, entityStates, initialState, transitions]);
|
|
44788
45042
|
if (!resolved) return null;
|
|
45043
|
+
const theme = resolved.theme ?? void 0;
|
|
45044
|
+
const themeBackground = theme?.background;
|
|
45045
|
+
const headerImage = str(resolved.headerImage);
|
|
45046
|
+
const hint = str(resolved.hint);
|
|
44789
45047
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
44790
45048
|
VStack,
|
|
44791
45049
|
{
|
|
44792
45050
|
className: cn("p-4 gap-6", className),
|
|
44793
45051
|
style: {
|
|
44794
|
-
backgroundImage:
|
|
45052
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
44795
45053
|
backgroundSize: "cover",
|
|
44796
45054
|
backgroundPosition: "center"
|
|
44797
45055
|
},
|
|
44798
45056
|
children: [
|
|
44799
|
-
|
|
45057
|
+
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,
|
|
44800
45058
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
44801
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
44802
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
45059
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
45060
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
44803
45061
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
|
|
44804
45062
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
|
|
44805
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children:
|
|
45063
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-foreground", children: hint })
|
|
44806
45064
|
] })
|
|
44807
45065
|
] }),
|
|
44808
45066
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
|
|
@@ -44850,14 +45108,14 @@ function StateArchitectBoard({
|
|
|
44850
45108
|
]
|
|
44851
45109
|
}
|
|
44852
45110
|
),
|
|
44853
|
-
|
|
45111
|
+
entityStates.map((state) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
44854
45112
|
StateNode2,
|
|
44855
45113
|
{
|
|
44856
45114
|
name: state,
|
|
44857
45115
|
position: positions[state],
|
|
44858
45116
|
isCurrent: state === currentState,
|
|
44859
45117
|
isSelected: state === selectedState,
|
|
44860
|
-
isInitial: state ===
|
|
45118
|
+
isInitial: state === initialState,
|
|
44861
45119
|
onClick: () => handleStateClick(state)
|
|
44862
45120
|
},
|
|
44863
45121
|
state
|
|
@@ -44904,7 +45162,7 @@ function StateArchitectBoard({
|
|
|
44904
45162
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44905
45163
|
VariablePanel,
|
|
44906
45164
|
{
|
|
44907
|
-
entityName
|
|
45165
|
+
entityName,
|
|
44908
45166
|
variables
|
|
44909
45167
|
}
|
|
44910
45168
|
),
|
|
@@ -44919,12 +45177,12 @@ function StateArchitectBoard({
|
|
|
44919
45177
|
resolved.showCodeView !== false && /* @__PURE__ */ jsxRuntime.jsx(CodeView, { data: codeData, label: "View Code" })
|
|
44920
45178
|
] })
|
|
44921
45179
|
] }),
|
|
44922
|
-
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") }) }),
|
|
45180
|
+
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") }) }),
|
|
44923
45181
|
playState === "fail" && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
44924
45182
|
/* @__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]) }) }),
|
|
44925
|
-
attempts >= 3 &&
|
|
45183
|
+
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: [
|
|
44926
45184
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
44927
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
45185
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
44928
45186
|
] }) })
|
|
44929
45187
|
] }),
|
|
44930
45188
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
|
|
@@ -44954,6 +45212,7 @@ var init_StateArchitectBoard = __esm({
|
|
|
44954
45212
|
init_TransitionArrow();
|
|
44955
45213
|
init_VariablePanel();
|
|
44956
45214
|
init_CodeView();
|
|
45215
|
+
init_boardEntity();
|
|
44957
45216
|
ENCOURAGEMENT_KEYS3 = [
|
|
44958
45217
|
"puzzle.tryAgain1",
|
|
44959
45218
|
"puzzle.tryAgain2",
|
|
@@ -44990,8 +45249,8 @@ var init_StatsOrganism = __esm({
|
|
|
44990
45249
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
44991
45250
|
}
|
|
44992
45251
|
const stats = items.map((item) => ({
|
|
44993
|
-
value: item.value,
|
|
44994
|
-
label: item.label
|
|
45252
|
+
value: String(item.value ?? ""),
|
|
45253
|
+
label: String(item.label ?? "")
|
|
44995
45254
|
}));
|
|
44996
45255
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
44997
45256
|
StatsGrid,
|
|
@@ -45037,10 +45296,10 @@ var init_StepFlowOrganism = __esm({
|
|
|
45037
45296
|
return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { message: error.message, className });
|
|
45038
45297
|
}
|
|
45039
45298
|
const steps = items.map((item) => ({
|
|
45040
|
-
number: item.number,
|
|
45041
|
-
title: item.title,
|
|
45042
|
-
description: item.description,
|
|
45043
|
-
icon: item.icon
|
|
45299
|
+
number: item.number != null ? Number(item.number) : void 0,
|
|
45300
|
+
title: String(item.title ?? ""),
|
|
45301
|
+
description: String(item.description ?? ""),
|
|
45302
|
+
icon: item.icon != null ? String(item.icon) : void 0
|
|
45044
45303
|
}));
|
|
45045
45304
|
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
45046
45305
|
(heading || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -45213,13 +45472,13 @@ var init_TeamOrganism = __esm({
|
|
|
45213
45472
|
/* @__PURE__ */ jsxRuntime.jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((member) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
45214
45473
|
TeamCard,
|
|
45215
45474
|
{
|
|
45216
|
-
name: member.name,
|
|
45217
|
-
nameAr: member.nameAr,
|
|
45218
|
-
role: member.role,
|
|
45219
|
-
bio: member.bio,
|
|
45220
|
-
avatar: member.avatar
|
|
45475
|
+
name: String(member.name ?? ""),
|
|
45476
|
+
nameAr: member.nameAr != null ? String(member.nameAr) : void 0,
|
|
45477
|
+
role: String(member.role ?? ""),
|
|
45478
|
+
bio: String(member.bio ?? ""),
|
|
45479
|
+
avatar: member.avatar != null ? String(member.avatar) : void 0
|
|
45221
45480
|
},
|
|
45222
|
-
member.id
|
|
45481
|
+
String(member.id ?? "")
|
|
45223
45482
|
)) })
|
|
45224
45483
|
] });
|
|
45225
45484
|
};
|
|
@@ -45456,8 +45715,8 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45456
45715
|
const [turn, setTurn] = React84.useState(1);
|
|
45457
45716
|
const [gameResult, setGameResult] = React84.useState(null);
|
|
45458
45717
|
const checkGameEnd = React84.useCallback((currentUnits) => {
|
|
45459
|
-
const pa = currentUnits.filter((u) => u
|
|
45460
|
-
const ea = currentUnits.filter((u) => u
|
|
45718
|
+
const pa = currentUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
45719
|
+
const ea = currentUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
45461
45720
|
if (pa.length === 0) {
|
|
45462
45721
|
setGameResult("defeat");
|
|
45463
45722
|
setPhase("game_over");
|
|
@@ -45475,34 +45734,36 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45475
45734
|
}
|
|
45476
45735
|
}, [onGameEnd, gameEndEvent, eventBus]);
|
|
45477
45736
|
const handleUnitClick = React84.useCallback((unitId) => {
|
|
45478
|
-
const unit = units.find((u) => u.id === unitId);
|
|
45737
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
45479
45738
|
if (!unit) return;
|
|
45480
45739
|
if (unitClickEvent) {
|
|
45481
45740
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
45482
45741
|
}
|
|
45483
45742
|
if (phase === "observation" || phase === "selection") {
|
|
45484
|
-
if (unit
|
|
45743
|
+
if (unitTeam(unit) === "player") {
|
|
45485
45744
|
setSelectedUnitId(unitId);
|
|
45486
45745
|
setPhase("movement");
|
|
45487
45746
|
}
|
|
45488
45747
|
} else if (phase === "action") {
|
|
45489
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
45748
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45490
45749
|
if (!selectedUnit) return;
|
|
45491
|
-
if (unit
|
|
45492
|
-
const
|
|
45493
|
-
const
|
|
45750
|
+
if (unitTeam(unit) === "enemy") {
|
|
45751
|
+
const up = unitPosition(unit);
|
|
45752
|
+
const sp = unitPosition(selectedUnit);
|
|
45753
|
+
const dx = Math.abs(up.x - sp.x);
|
|
45754
|
+
const dy = Math.abs(up.y - sp.y);
|
|
45494
45755
|
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
45495
|
-
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
|
|
45496
|
-
const newHealth = Math.max(0, unit
|
|
45756
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
45757
|
+
const newHealth = Math.max(0, unitHealth(unit) - damage);
|
|
45497
45758
|
const updatedUnits = units.map(
|
|
45498
|
-
(u) => u.id === unit.id ? { ...u, health: newHealth } : u
|
|
45759
|
+
(u) => str(u.id) === str(unit.id) ? { ...u, health: newHealth } : u
|
|
45499
45760
|
);
|
|
45500
45761
|
setUnits(updatedUnits);
|
|
45501
45762
|
onAttack?.(selectedUnit, unit, damage);
|
|
45502
45763
|
if (attackEvent) {
|
|
45503
45764
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
45504
|
-
attackerId: selectedUnit.id,
|
|
45505
|
-
targetId: unit.id,
|
|
45765
|
+
attackerId: str(selectedUnit.id),
|
|
45766
|
+
targetId: str(unit.id),
|
|
45506
45767
|
damage
|
|
45507
45768
|
});
|
|
45508
45769
|
}
|
|
@@ -45519,16 +45780,20 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45519
45780
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
45520
45781
|
}
|
|
45521
45782
|
if (phase === "movement" && selectedUnitId) {
|
|
45522
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
45783
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45523
45784
|
if (!selectedUnit) return;
|
|
45524
|
-
const
|
|
45525
|
-
const
|
|
45785
|
+
const sp = unitPosition(selectedUnit);
|
|
45786
|
+
const dx = Math.abs(x - sp.x);
|
|
45787
|
+
const dy = Math.abs(y - sp.y);
|
|
45526
45788
|
const dist = dx + dy;
|
|
45527
|
-
if (dist > 0 && dist <= selectedUnit.movement) {
|
|
45528
|
-
if (!units.some((u) =>
|
|
45789
|
+
if (dist > 0 && dist <= num(selectedUnit.movement)) {
|
|
45790
|
+
if (!units.some((u) => {
|
|
45791
|
+
const p2 = unitPosition(u);
|
|
45792
|
+
return p2.x === x && p2.y === y && unitHealth(u) > 0;
|
|
45793
|
+
})) {
|
|
45529
45794
|
setUnits(
|
|
45530
45795
|
(prev) => prev.map(
|
|
45531
|
-
(u) => u.id === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
45796
|
+
(u) => str(u.id) === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
45532
45797
|
)
|
|
45533
45798
|
);
|
|
45534
45799
|
setPhase("action");
|
|
@@ -45571,12 +45836,13 @@ var init_useBattleState = __esm({
|
|
|
45571
45836
|
"components/game/organisms/hooks/useBattleState.ts"() {
|
|
45572
45837
|
"use client";
|
|
45573
45838
|
init_useEventBus();
|
|
45839
|
+
init_boardEntity();
|
|
45574
45840
|
}
|
|
45575
45841
|
});
|
|
45576
45842
|
function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
45577
|
-
const resolved =
|
|
45843
|
+
const resolved = boardEntity(entity);
|
|
45578
45844
|
const battleState = useBattleState(
|
|
45579
|
-
resolved?.initialUnits
|
|
45845
|
+
rows(resolved?.initialUnits),
|
|
45580
45846
|
{
|
|
45581
45847
|
tileClickEvent: rest.tileClickEvent,
|
|
45582
45848
|
unitClickEvent: rest.unitClickEvent,
|
|
@@ -45612,10 +45878,23 @@ function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
|
45612
45878
|
var init_UncontrolledBattleBoard = __esm({
|
|
45613
45879
|
"components/game/organisms/UncontrolledBattleBoard.tsx"() {
|
|
45614
45880
|
init_BattleBoard();
|
|
45881
|
+
init_boardEntity();
|
|
45615
45882
|
init_useBattleState();
|
|
45616
45883
|
UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
|
|
45617
45884
|
}
|
|
45618
45885
|
});
|
|
45886
|
+
function heroPosition(h) {
|
|
45887
|
+
return vec2(h.position);
|
|
45888
|
+
}
|
|
45889
|
+
function heroOwner(h) {
|
|
45890
|
+
return str(h.owner);
|
|
45891
|
+
}
|
|
45892
|
+
function heroMovement(h) {
|
|
45893
|
+
return num(h.movement);
|
|
45894
|
+
}
|
|
45895
|
+
function hexPassable(h) {
|
|
45896
|
+
return h.passable !== false;
|
|
45897
|
+
}
|
|
45619
45898
|
function defaultIsInRange(from, to, range) {
|
|
45620
45899
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
45621
45900
|
}
|
|
@@ -45646,36 +45925,36 @@ function WorldMapBoard({
|
|
|
45646
45925
|
className
|
|
45647
45926
|
}) {
|
|
45648
45927
|
const eventBus = useEventBus();
|
|
45649
|
-
const resolved =
|
|
45650
|
-
const hexes = resolved?.hexes
|
|
45651
|
-
const heroes = resolved?.heroes
|
|
45652
|
-
const features = resolved?.features
|
|
45653
|
-
const selectedHeroId = resolved?.selectedHeroId;
|
|
45928
|
+
const resolved = boardEntity(entity);
|
|
45929
|
+
const hexes = rows(resolved?.hexes);
|
|
45930
|
+
const heroes = rows(resolved?.heroes);
|
|
45931
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
45932
|
+
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
45654
45933
|
const assetManifest = resolved?.assetManifest;
|
|
45655
45934
|
const backgroundImage = resolved?.backgroundImage;
|
|
45656
45935
|
const [hoveredTile, setHoveredTile] = React84.useState(null);
|
|
45657
45936
|
const selectedHero = React84.useMemo(
|
|
45658
|
-
() => heroes.find((h) => h.id === selectedHeroId) ?? null,
|
|
45937
|
+
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
45659
45938
|
[heroes, selectedHeroId]
|
|
45660
45939
|
);
|
|
45661
45940
|
const tiles = React84.useMemo(
|
|
45662
45941
|
() => hexes.map((hex) => ({
|
|
45663
|
-
x: hex.x,
|
|
45664
|
-
y: hex.y,
|
|
45665
|
-
terrain: hex.terrain,
|
|
45666
|
-
terrainSprite: hex.terrainSprite
|
|
45942
|
+
x: num(hex.x),
|
|
45943
|
+
y: num(hex.y),
|
|
45944
|
+
terrain: str(hex.terrain),
|
|
45945
|
+
terrainSprite: hex.terrainSprite == null ? void 0 : str(hex.terrainSprite)
|
|
45667
45946
|
})),
|
|
45668
45947
|
[hexes]
|
|
45669
45948
|
);
|
|
45670
45949
|
const baseUnits = React84.useMemo(
|
|
45671
45950
|
() => heroes.map((hero) => ({
|
|
45672
|
-
id: hero.id,
|
|
45673
|
-
position: hero
|
|
45674
|
-
name: hero.name,
|
|
45675
|
-
team: hero
|
|
45951
|
+
id: str(hero.id),
|
|
45952
|
+
position: heroPosition(hero),
|
|
45953
|
+
name: str(hero.name),
|
|
45954
|
+
team: heroOwner(hero) === "enemy" ? "enemy" : "player",
|
|
45676
45955
|
health: 100,
|
|
45677
45956
|
maxHealth: 100,
|
|
45678
|
-
sprite: hero.sprite
|
|
45957
|
+
sprite: hero.sprite == null ? void 0 : str(hero.sprite)
|
|
45679
45958
|
})),
|
|
45680
45959
|
[heroes]
|
|
45681
45960
|
);
|
|
@@ -45716,73 +45995,94 @@ function WorldMapBoard({
|
|
|
45716
45995
|
const isoUnits = React84.useMemo(() => {
|
|
45717
45996
|
if (movingPositions.size === 0) return baseUnits;
|
|
45718
45997
|
return baseUnits.map((u) => {
|
|
45719
|
-
const pos = movingPositions.get(u.id);
|
|
45998
|
+
const pos = u.id == null ? void 0 : movingPositions.get(u.id);
|
|
45720
45999
|
return pos ? { ...u, position: pos } : u;
|
|
45721
46000
|
});
|
|
45722
46001
|
}, [baseUnits, movingPositions]);
|
|
45723
46002
|
const validMoves = React84.useMemo(() => {
|
|
45724
|
-
if (!selectedHero || selectedHero
|
|
46003
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46004
|
+
const sp = heroPosition(selectedHero);
|
|
46005
|
+
const sOwner = heroOwner(selectedHero);
|
|
46006
|
+
const range = heroMovement(selectedHero);
|
|
45725
46007
|
const moves = [];
|
|
45726
46008
|
hexes.forEach((hex) => {
|
|
45727
|
-
|
|
45728
|
-
|
|
45729
|
-
if (!
|
|
45730
|
-
if (
|
|
45731
|
-
|
|
46009
|
+
const hx = num(hex.x);
|
|
46010
|
+
const hy = num(hex.y);
|
|
46011
|
+
if (!hexPassable(hex)) return;
|
|
46012
|
+
if (hx === sp.x && hy === sp.y) return;
|
|
46013
|
+
if (!isInRange(sp, { x: hx, y: hy }, range)) return;
|
|
46014
|
+
if (heroes.some((h) => {
|
|
46015
|
+
const hp = heroPosition(h);
|
|
46016
|
+
return hp.x === hx && hp.y === hy && heroOwner(h) === sOwner;
|
|
46017
|
+
})) return;
|
|
46018
|
+
moves.push({ x: hx, y: hy });
|
|
45732
46019
|
});
|
|
45733
46020
|
return moves;
|
|
45734
46021
|
}, [selectedHero, hexes, heroes, isInRange]);
|
|
45735
46022
|
const attackTargets = React84.useMemo(() => {
|
|
45736
|
-
if (!selectedHero || selectedHero
|
|
45737
|
-
|
|
46023
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46024
|
+
const sp = heroPosition(selectedHero);
|
|
46025
|
+
const sOwner = heroOwner(selectedHero);
|
|
46026
|
+
const range = heroMovement(selectedHero);
|
|
46027
|
+
return heroes.filter((h) => heroOwner(h) !== sOwner).filter((h) => isInRange(sp, heroPosition(h), range)).map((h) => heroPosition(h));
|
|
45738
46028
|
}, [selectedHero, heroes, isInRange]);
|
|
45739
|
-
const maxY = Math.max(...hexes.map((h) => h.y), 0);
|
|
46029
|
+
const maxY = Math.max(...hexes.map((h) => num(h.y)), 0);
|
|
45740
46030
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
45741
46031
|
const tileToScreen = React84.useCallback(
|
|
45742
46032
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
45743
46033
|
[scale, baseOffsetX]
|
|
45744
46034
|
);
|
|
45745
46035
|
const hoveredHex = React84.useMemo(
|
|
45746
|
-
() => hoveredTile ? hexes.find((h) => h.x === hoveredTile.x && h.y === hoveredTile.y) ?? null : null,
|
|
46036
|
+
() => hoveredTile ? hexes.find((h) => num(h.x) === hoveredTile.x && num(h.y) === hoveredTile.y) ?? null : null,
|
|
45747
46037
|
[hoveredTile, hexes]
|
|
45748
46038
|
);
|
|
45749
46039
|
const hoveredHero = React84.useMemo(
|
|
45750
|
-
() => hoveredTile ? heroes.find((h) =>
|
|
46040
|
+
() => hoveredTile ? heroes.find((h) => {
|
|
46041
|
+
const hp = heroPosition(h);
|
|
46042
|
+
return hp.x === hoveredTile.x && hp.y === hoveredTile.y;
|
|
46043
|
+
}) ?? null : null,
|
|
45751
46044
|
[hoveredTile, heroes]
|
|
45752
46045
|
);
|
|
45753
46046
|
const handleTileClick = React84.useCallback((x, y) => {
|
|
45754
46047
|
if (movementAnimRef.current) return;
|
|
45755
|
-
const hex = hexes.find((h) => h.x === x && h.y === y);
|
|
46048
|
+
const hex = hexes.find((h) => num(h.x) === x && num(h.y) === y);
|
|
45756
46049
|
if (!hex) return;
|
|
45757
46050
|
if (tileClickEvent) {
|
|
45758
46051
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
45759
46052
|
}
|
|
45760
46053
|
if (selectedHero && validMoves.some((m) => m.x === x && m.y === y)) {
|
|
45761
|
-
|
|
45762
|
-
|
|
46054
|
+
const heroId = str(selectedHero.id);
|
|
46055
|
+
startMoveAnimation(heroId, { ...heroPosition(selectedHero) }, { x, y }, () => {
|
|
46056
|
+
onHeroMove?.(heroId, x, y);
|
|
45763
46057
|
if (heroMoveEvent) {
|
|
45764
|
-
eventBus.emit(`UI:${heroMoveEvent}`, { heroId
|
|
46058
|
+
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
45765
46059
|
}
|
|
45766
|
-
|
|
45767
|
-
|
|
46060
|
+
const feature = str(hex.feature);
|
|
46061
|
+
if (feature && feature !== "none") {
|
|
46062
|
+
onFeatureEnter?.(heroId, hex);
|
|
45768
46063
|
if (featureEnterEvent) {
|
|
45769
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId
|
|
46064
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
45770
46065
|
}
|
|
45771
46066
|
}
|
|
45772
46067
|
});
|
|
45773
46068
|
return;
|
|
45774
46069
|
}
|
|
45775
|
-
const enemy = heroes.find((h) =>
|
|
46070
|
+
const enemy = heroes.find((h) => {
|
|
46071
|
+
const hp = heroPosition(h);
|
|
46072
|
+
return hp.x === x && hp.y === y && heroOwner(h) === "enemy";
|
|
46073
|
+
});
|
|
45776
46074
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
45777
|
-
|
|
46075
|
+
const attackerId = str(selectedHero.id);
|
|
46076
|
+
const defenderId = str(enemy.id);
|
|
46077
|
+
onBattleEncounter?.(attackerId, defenderId);
|
|
45778
46078
|
if (battleEncounterEvent) {
|
|
45779
|
-
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId
|
|
46079
|
+
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
45780
46080
|
}
|
|
45781
46081
|
}
|
|
45782
46082
|
}, [hexes, heroes, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
45783
46083
|
const handleUnitClick = React84.useCallback((unitId) => {
|
|
45784
|
-
const hero = heroes.find((h) => h.id === unitId);
|
|
45785
|
-
if (hero && (hero
|
|
46084
|
+
const hero = heroes.find((h) => str(h.id) === unitId);
|
|
46085
|
+
if (hero && (heroOwner(hero) === "player" || allowMoveAllHeroes)) {
|
|
45786
46086
|
onHeroSelect?.(unitId);
|
|
45787
46087
|
if (heroSelectEvent) {
|
|
45788
46088
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
@@ -45855,6 +46155,7 @@ var init_WorldMapBoard = __esm({
|
|
|
45855
46155
|
init_Stack();
|
|
45856
46156
|
init_LoadingState();
|
|
45857
46157
|
init_IsometricCanvas2();
|
|
46158
|
+
init_boardEntity();
|
|
45858
46159
|
init_isometric();
|
|
45859
46160
|
WorldMapBoard.displayName = "WorldMapBoard";
|
|
45860
46161
|
}
|
|
@@ -49083,11 +49384,11 @@ function buildMockData(schema) {
|
|
|
49083
49384
|
result[entityName] = entity.instances;
|
|
49084
49385
|
continue;
|
|
49085
49386
|
}
|
|
49086
|
-
const
|
|
49387
|
+
const rows2 = Array.from(
|
|
49087
49388
|
{ length: 10 },
|
|
49088
49389
|
(_, i) => generateEntityRow(entity, i + 1)
|
|
49089
49390
|
);
|
|
49090
|
-
result[entityName] =
|
|
49391
|
+
result[entityName] = rows2;
|
|
49091
49392
|
}
|
|
49092
49393
|
for (const orbital of schema.orbitals) {
|
|
49093
49394
|
for (const traitRef of orbital.traits ?? []) {
|