@almadar/ui 5.21.12 → 5.22.3
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 +2432 -3173
- package/dist/avl/index.js +1373 -2114
- package/dist/components/core/molecules/CalendarGrid.d.ts +3 -10
- package/dist/components/core/molecules/ContentRenderer.d.ts +2 -2
- package/dist/components/core/molecules/DataGrid.d.ts +11 -20
- package/dist/components/core/molecules/DataList.d.ts +9 -15
- package/dist/components/core/molecules/FormSection.d.ts +4 -4
- package/dist/components/core/molecules/PositionedCanvas.d.ts +4 -17
- package/dist/components/core/molecules/ReplyTree.d.ts +2 -13
- package/dist/components/core/molecules/RichBlockEditor.d.ts +3 -6
- package/dist/components/core/molecules/SortableList.d.ts +7 -5
- package/dist/components/core/molecules/TableView.d.ts +7 -7
- package/dist/components/core/molecules/index.d.ts +3 -3
- package/dist/components/core/molecules/useDataDnd.d.ts +5 -5
- package/dist/components/core/organisms/CardGrid.d.ts +5 -2
- package/dist/components/core/organisms/CaseStudyOrganism.d.ts +4 -3
- package/dist/components/core/organisms/DataTable.d.ts +4 -2
- package/dist/components/core/organisms/DetailPanel.d.ts +6 -6
- package/dist/components/core/organisms/FeatureGridOrganism.d.ts +4 -3
- package/dist/components/core/organisms/HeroOrganism.d.ts +4 -5
- package/dist/components/core/organisms/List.d.ts +5 -2
- package/dist/components/core/organisms/MasterDetail.d.ts +4 -2
- package/dist/components/core/organisms/MediaGallery.d.ts +4 -2
- package/dist/components/core/organisms/ShowcaseOrganism.d.ts +4 -3
- package/dist/components/core/organisms/StatCard.d.ts +5 -2
- package/dist/components/core/organisms/StepFlowOrganism.d.ts +4 -3
- package/dist/components/core/organisms/Timeline.d.ts +2 -2
- package/dist/components/core/organisms/book/index.d.ts +1 -1
- package/dist/components/core/organisms/book/types.d.ts +28 -48
- package/dist/components/core/organisms/index.d.ts +1 -2
- package/dist/components/core/organisms/layout/DashboardGrid.d.ts +2 -2
- package/dist/components/core/organisms/marketing-types.d.ts +5 -94
- package/dist/components/core/organisms/types.d.ts +9 -27
- package/dist/components/core/templates/index.d.ts +6 -6
- package/dist/components/game/organisms/BattleBoard.d.ts +14 -90
- package/dist/components/game/organisms/CastleBoard.d.ts +7 -21
- package/dist/components/game/organisms/UncontrolledBattleBoard.d.ts +2 -7
- package/dist/components/game/organisms/WorldMapBoard.d.ts +13 -59
- package/dist/components/game/organisms/boardEntity.d.ts +44 -0
- package/dist/components/game/organisms/hooks/useBattleState.d.ts +7 -7
- package/dist/components/game/organisms/index.d.ts +3 -3
- package/dist/components/game/organisms/puzzles/builder/BuilderBoard.d.ts +7 -20
- package/dist/components/game/organisms/puzzles/builder/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/classifier/ClassifierBoard.d.ts +7 -20
- package/dist/components/game/organisms/puzzles/classifier/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/debugger/DebuggerBoard.d.ts +6 -22
- package/dist/components/game/organisms/puzzles/debugger/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/event-handler/EventHandlerBoard.d.ts +6 -33
- package/dist/components/game/organisms/puzzles/event-handler/ObjectRulePanel.d.ts +3 -21
- package/dist/components/game/organisms/puzzles/event-handler/index.d.ts +2 -2
- package/dist/components/game/organisms/puzzles/event-handler/puzzleObject.d.ts +21 -0
- package/dist/components/game/organisms/puzzles/negotiator/NegotiatorBoard.d.ts +8 -24
- package/dist/components/game/organisms/puzzles/negotiator/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/sequencer/ActionTile.d.ts +2 -2
- package/dist/components/game/organisms/puzzles/sequencer/SequencerBoard.d.ts +7 -36
- package/dist/components/game/organisms/puzzles/sequencer/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/simulator/SimulatorBoard.d.ts +6 -25
- package/dist/components/game/organisms/puzzles/simulator/index.d.ts +1 -1
- package/dist/components/game/organisms/puzzles/state-architect/StateArchitectBoard.d.ts +7 -40
- package/dist/components/game/organisms/puzzles/state-architect/VariablePanel.d.ts +3 -9
- package/dist/components/game/organisms/puzzles/state-architect/index.d.ts +2 -2
- package/dist/components/game/organisms/three/index.cjs +35 -21
- package/dist/components/game/organisms/three/index.js +35 -21
- package/dist/components/game/templates/BattleTemplate.d.ts +2 -3
- package/dist/components/game/templates/CastleTemplate.d.ts +2 -3
- package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +1 -16
- package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +1 -18
- package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +1 -14
- package/dist/components/game/templates/GameTemplate.d.ts +1 -6
- package/dist/components/game/templates/WorldMapTemplate.d.ts +2 -3
- package/dist/components/index.cjs +2016 -1668
- package/dist/components/index.js +1128 -780
- package/dist/components/marketing/organisms/PricingOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/StatsOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/TeamOrganism.d.ts +4 -3
- package/dist/components/marketing/organisms/book/BookChapterView.d.ts +5 -2
- package/dist/components/marketing/organisms/book/BookTableOfContents.d.ts +3 -2
- package/dist/components/marketing/organisms/book/BookViewer.d.ts +4 -4
- package/dist/components/marketing/templates/AboutPageTemplate.d.ts +32 -6
- package/dist/components/marketing/templates/FeatureDetailPageTemplate.d.ts +14 -4
- package/dist/components/marketing/templates/LandingPageTemplate.d.ts +47 -9
- package/dist/components/marketing/templates/PricingPageTemplate.d.ts +23 -5
- package/dist/providers/index.cjs +912 -624
- package/dist/providers/index.js +912 -624
- package/dist/runtime/index.cjs +914 -626
- package/dist/runtime/index.js +914 -626
- package/package.json +2 -2
package/dist/providers/index.js
CHANGED
|
@@ -2718,7 +2718,7 @@ var init_SvgGrid = __esm({
|
|
|
2718
2718
|
x,
|
|
2719
2719
|
y,
|
|
2720
2720
|
cols = 4,
|
|
2721
|
-
rows = 3,
|
|
2721
|
+
rows: rows2 = 3,
|
|
2722
2722
|
spacing = 20,
|
|
2723
2723
|
nodeRadius = 3,
|
|
2724
2724
|
color = "var(--color-primary)",
|
|
@@ -2727,7 +2727,7 @@ var init_SvgGrid = __esm({
|
|
|
2727
2727
|
highlights = []
|
|
2728
2728
|
}) => {
|
|
2729
2729
|
const highlightSet = new Set(highlights);
|
|
2730
|
-
return /* @__PURE__ */ jsx("g", { className, opacity, children: Array.from({ length:
|
|
2730
|
+
return /* @__PURE__ */ jsx("g", { className, opacity, children: Array.from({ length: rows2 }).map(
|
|
2731
2731
|
(_, row) => Array.from({ length: cols }).map((_2, col) => {
|
|
2732
2732
|
const index = row * cols + col;
|
|
2733
2733
|
const isHighlighted = highlightSet.has(index);
|
|
@@ -3387,7 +3387,7 @@ var init_Input = __esm({
|
|
|
3387
3387
|
onClear,
|
|
3388
3388
|
value,
|
|
3389
3389
|
options,
|
|
3390
|
-
rows = 3,
|
|
3390
|
+
rows: rows2 = 3,
|
|
3391
3391
|
onChange,
|
|
3392
3392
|
...props
|
|
3393
3393
|
}, ref) => {
|
|
@@ -3437,7 +3437,7 @@ var init_Input = __esm({
|
|
|
3437
3437
|
ref,
|
|
3438
3438
|
value,
|
|
3439
3439
|
onChange,
|
|
3440
|
-
rows,
|
|
3440
|
+
rows: rows2,
|
|
3441
3441
|
className: baseClassName,
|
|
3442
3442
|
...props
|
|
3443
3443
|
}
|
|
@@ -5518,66 +5518,6 @@ var init_RangeSlider = __esm({
|
|
|
5518
5518
|
RangeSlider.displayName = "RangeSlider";
|
|
5519
5519
|
}
|
|
5520
5520
|
});
|
|
5521
|
-
function easeOut(t) {
|
|
5522
|
-
return t * (2 - t);
|
|
5523
|
-
}
|
|
5524
|
-
var AnimatedCounter;
|
|
5525
|
-
var init_AnimatedCounter = __esm({
|
|
5526
|
-
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
5527
|
-
"use client";
|
|
5528
|
-
init_cn();
|
|
5529
|
-
init_Typography();
|
|
5530
|
-
AnimatedCounter = ({
|
|
5531
|
-
value: rawValue,
|
|
5532
|
-
duration = 600,
|
|
5533
|
-
prefix,
|
|
5534
|
-
suffix,
|
|
5535
|
-
className
|
|
5536
|
-
}) => {
|
|
5537
|
-
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
5538
|
-
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
5539
|
-
const [displayValue, setDisplayValue] = useState(value);
|
|
5540
|
-
const previousValueRef = useRef(value);
|
|
5541
|
-
const animationFrameRef = useRef(null);
|
|
5542
|
-
useEffect(() => {
|
|
5543
|
-
const from = previousValueRef.current;
|
|
5544
|
-
const to = value;
|
|
5545
|
-
previousValueRef.current = value;
|
|
5546
|
-
if (from === to) {
|
|
5547
|
-
setDisplayValue(to);
|
|
5548
|
-
return;
|
|
5549
|
-
}
|
|
5550
|
-
const startTime = performance.now();
|
|
5551
|
-
const diff = to - from;
|
|
5552
|
-
function animate(currentTime) {
|
|
5553
|
-
const elapsed = currentTime - startTime;
|
|
5554
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
5555
|
-
const easedProgress = easeOut(progress);
|
|
5556
|
-
setDisplayValue(from + diff * easedProgress);
|
|
5557
|
-
if (progress < 1) {
|
|
5558
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5559
|
-
} else {
|
|
5560
|
-
setDisplayValue(to);
|
|
5561
|
-
}
|
|
5562
|
-
}
|
|
5563
|
-
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5564
|
-
return () => {
|
|
5565
|
-
if (animationFrameRef.current !== null) {
|
|
5566
|
-
cancelAnimationFrame(animationFrameRef.current);
|
|
5567
|
-
}
|
|
5568
|
-
};
|
|
5569
|
-
}, [value, duration]);
|
|
5570
|
-
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
5571
|
-
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
5572
|
-
return /* @__PURE__ */ jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
5573
|
-
prefix,
|
|
5574
|
-
formattedValue,
|
|
5575
|
-
suffix
|
|
5576
|
-
] });
|
|
5577
|
-
};
|
|
5578
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
5579
|
-
}
|
|
5580
|
-
});
|
|
5581
5521
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
5582
5522
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
5583
5523
|
const observerRef = useRef(null);
|
|
@@ -8059,15 +7999,15 @@ function HeaderSkeleton({ className }) {
|
|
|
8059
7999
|
] })
|
|
8060
8000
|
] });
|
|
8061
8001
|
}
|
|
8062
|
-
function TableSkeleton({ rows = 5, columns = 4, className }) {
|
|
8002
|
+
function TableSkeleton({ rows: rows2 = 5, columns = 4, className }) {
|
|
8063
8003
|
return /* @__PURE__ */ jsxs(VStack, { gap: "none", className: cn("border border-border rounded-lg overflow-hidden", className), children: [
|
|
8064
8004
|
/* @__PURE__ */ jsx(HStack, { className: "px-4 py-3 bg-muted/30 border-b border-border", children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsx(SkeletonBlock, { className: "h-4 flex-1 mx-2" }, i)) }),
|
|
8065
|
-
Array.from({ length:
|
|
8005
|
+
Array.from({ length: rows2 }).map((_, rowIdx) => /* @__PURE__ */ jsx(
|
|
8066
8006
|
HStack,
|
|
8067
8007
|
{
|
|
8068
8008
|
className: cn(
|
|
8069
8009
|
"px-4 py-3",
|
|
8070
|
-
rowIdx <
|
|
8010
|
+
rowIdx < rows2 - 1 && "border-b border-border"
|
|
8071
8011
|
),
|
|
8072
8012
|
children: Array.from({ length: columns }).map((_2, colIdx) => /* @__PURE__ */ jsx(SkeletonLine, { className: "flex-1 mx-2" }, colIdx))
|
|
8073
8013
|
},
|
|
@@ -8115,18 +8055,18 @@ function CardSkeleton({ className }) {
|
|
|
8115
8055
|
}
|
|
8116
8056
|
);
|
|
8117
8057
|
}
|
|
8118
|
-
function TextSkeleton({ rows = 3, className }) {
|
|
8119
|
-
return /* @__PURE__ */ jsx(VStack, { gap: "sm", className, children: Array.from({ length:
|
|
8058
|
+
function TextSkeleton({ rows: rows2 = 3, className }) {
|
|
8059
|
+
return /* @__PURE__ */ jsx(VStack, { gap: "sm", className, children: Array.from({ length: rows2 }).map((_, i) => /* @__PURE__ */ jsx(
|
|
8120
8060
|
SkeletonLine,
|
|
8121
8061
|
{
|
|
8122
|
-
className: i ===
|
|
8062
|
+
className: i === rows2 - 1 ? "w-2/3" : "w-full"
|
|
8123
8063
|
},
|
|
8124
8064
|
i
|
|
8125
8065
|
)) });
|
|
8126
8066
|
}
|
|
8127
8067
|
function Skeleton({
|
|
8128
8068
|
variant = "text",
|
|
8129
|
-
rows,
|
|
8069
|
+
rows: rows2,
|
|
8130
8070
|
columns,
|
|
8131
8071
|
fields,
|
|
8132
8072
|
className
|
|
@@ -8136,15 +8076,15 @@ function Skeleton({
|
|
|
8136
8076
|
case "header":
|
|
8137
8077
|
return /* @__PURE__ */ jsx(HeaderSkeleton, { className });
|
|
8138
8078
|
case "table":
|
|
8139
|
-
return /* @__PURE__ */ jsx(TableSkeleton, { rows, columns, className });
|
|
8079
|
+
return /* @__PURE__ */ jsx(TableSkeleton, { rows: rows2, columns, className });
|
|
8140
8080
|
case "form":
|
|
8141
8081
|
return /* @__PURE__ */ jsx(FormSkeleton, { fields, className });
|
|
8142
8082
|
case "card":
|
|
8143
8083
|
return /* @__PURE__ */ jsx(CardSkeleton, { className });
|
|
8144
8084
|
case "text":
|
|
8145
|
-
return /* @__PURE__ */ jsx(TextSkeleton, { rows, className });
|
|
8085
|
+
return /* @__PURE__ */ jsx(TextSkeleton, { rows: rows2, className });
|
|
8146
8086
|
default:
|
|
8147
|
-
return /* @__PURE__ */ jsx(TextSkeleton, { rows, className });
|
|
8087
|
+
return /* @__PURE__ */ jsx(TextSkeleton, { rows: rows2, className });
|
|
8148
8088
|
}
|
|
8149
8089
|
}
|
|
8150
8090
|
var pulseClass;
|
|
@@ -10128,7 +10068,7 @@ var init_MapView = __esm({
|
|
|
10128
10068
|
shadowSize: [41, 41]
|
|
10129
10069
|
});
|
|
10130
10070
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
10131
|
-
const { useEffect: useEffect70, useRef: useRef66, useCallback:
|
|
10071
|
+
const { useEffect: useEffect70, useRef: useRef66, useCallback: useCallback114, useState: useState100 } = React85__default;
|
|
10132
10072
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
10133
10073
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
10134
10074
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -10174,7 +10114,7 @@ var init_MapView = __esm({
|
|
|
10174
10114
|
}) {
|
|
10175
10115
|
const eventBus = useEventBus2();
|
|
10176
10116
|
const [clickedPosition, setClickedPosition] = useState100(null);
|
|
10177
|
-
const handleMapClick =
|
|
10117
|
+
const handleMapClick = useCallback114((lat, lng) => {
|
|
10178
10118
|
if (showClickedPin) {
|
|
10179
10119
|
setClickedPosition({ lat, lng });
|
|
10180
10120
|
}
|
|
@@ -10183,7 +10123,7 @@ var init_MapView = __esm({
|
|
|
10183
10123
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
10184
10124
|
}
|
|
10185
10125
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
10186
|
-
const handleMarkerClick =
|
|
10126
|
+
const handleMarkerClick = useCallback114((marker) => {
|
|
10187
10127
|
onMarkerClick?.(marker);
|
|
10188
10128
|
if (markerClickEvent) {
|
|
10189
10129
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -10404,7 +10344,7 @@ function InputPattern({
|
|
|
10404
10344
|
function TextareaPattern({
|
|
10405
10345
|
value = "",
|
|
10406
10346
|
placeholder,
|
|
10407
|
-
rows = 4,
|
|
10347
|
+
rows: rows2 = 4,
|
|
10408
10348
|
disabled = false,
|
|
10409
10349
|
fieldError,
|
|
10410
10350
|
onChange,
|
|
@@ -10424,7 +10364,7 @@ function TextareaPattern({
|
|
|
10424
10364
|
{
|
|
10425
10365
|
value: localValue,
|
|
10426
10366
|
placeholder,
|
|
10427
|
-
rows,
|
|
10367
|
+
rows: rows2,
|
|
10428
10368
|
disabled,
|
|
10429
10369
|
error: fieldError,
|
|
10430
10370
|
onChange: handleChange,
|
|
@@ -10909,6 +10849,91 @@ var init_ActionPalette = __esm({
|
|
|
10909
10849
|
ActionPalette.displayName = "ActionPalette";
|
|
10910
10850
|
}
|
|
10911
10851
|
});
|
|
10852
|
+
function parseValue(value) {
|
|
10853
|
+
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
10854
|
+
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
10855
|
+
if (!match) {
|
|
10856
|
+
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
10857
|
+
}
|
|
10858
|
+
const numStr = match[2];
|
|
10859
|
+
const decimalIdx = numStr.indexOf(".");
|
|
10860
|
+
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
10861
|
+
return {
|
|
10862
|
+
prefix: match[1],
|
|
10863
|
+
num: parseFloat(numStr),
|
|
10864
|
+
suffix: match[3],
|
|
10865
|
+
decimals
|
|
10866
|
+
};
|
|
10867
|
+
}
|
|
10868
|
+
var AnimatedCounter;
|
|
10869
|
+
var init_AnimatedCounter = __esm({
|
|
10870
|
+
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
10871
|
+
"use client";
|
|
10872
|
+
init_cn();
|
|
10873
|
+
init_Box();
|
|
10874
|
+
init_Typography();
|
|
10875
|
+
AnimatedCounter = ({
|
|
10876
|
+
value,
|
|
10877
|
+
label,
|
|
10878
|
+
duration = 1500,
|
|
10879
|
+
className
|
|
10880
|
+
}) => {
|
|
10881
|
+
const ref = useRef(null);
|
|
10882
|
+
const [displayValue, setDisplayValue] = useState("0");
|
|
10883
|
+
const [hasAnimated, setHasAnimated] = useState(false);
|
|
10884
|
+
const animate = useCallback(() => {
|
|
10885
|
+
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
10886
|
+
if (num2 === 0) {
|
|
10887
|
+
setDisplayValue(String(value));
|
|
10888
|
+
return;
|
|
10889
|
+
}
|
|
10890
|
+
const startTime = performance.now();
|
|
10891
|
+
const tick = (now) => {
|
|
10892
|
+
const elapsed = now - startTime;
|
|
10893
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
10894
|
+
const eased = 1 - Math.pow(1 - progress, 3);
|
|
10895
|
+
const current = eased * num2;
|
|
10896
|
+
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
10897
|
+
if (progress < 1) {
|
|
10898
|
+
requestAnimationFrame(tick);
|
|
10899
|
+
} else {
|
|
10900
|
+
setDisplayValue(String(value));
|
|
10901
|
+
}
|
|
10902
|
+
};
|
|
10903
|
+
requestAnimationFrame(tick);
|
|
10904
|
+
}, [value, duration]);
|
|
10905
|
+
useEffect(() => {
|
|
10906
|
+
if (hasAnimated) return;
|
|
10907
|
+
const el = ref.current;
|
|
10908
|
+
if (!el) return;
|
|
10909
|
+
const observer2 = new IntersectionObserver(
|
|
10910
|
+
(entries) => {
|
|
10911
|
+
if (entries[0].isIntersecting) {
|
|
10912
|
+
setHasAnimated(true);
|
|
10913
|
+
animate();
|
|
10914
|
+
observer2.disconnect();
|
|
10915
|
+
}
|
|
10916
|
+
},
|
|
10917
|
+
{ threshold: 0.3 }
|
|
10918
|
+
);
|
|
10919
|
+
observer2.observe(el);
|
|
10920
|
+
return () => observer2.disconnect();
|
|
10921
|
+
}, [hasAnimated, animate]);
|
|
10922
|
+
return /* @__PURE__ */ jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
10923
|
+
/* @__PURE__ */ jsx(
|
|
10924
|
+
Typography,
|
|
10925
|
+
{
|
|
10926
|
+
variant: "h2",
|
|
10927
|
+
className: "text-primary font-bold tabular-nums",
|
|
10928
|
+
children: hasAnimated ? displayValue : "0"
|
|
10929
|
+
}
|
|
10930
|
+
),
|
|
10931
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
10932
|
+
] });
|
|
10933
|
+
};
|
|
10934
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
10935
|
+
}
|
|
10936
|
+
});
|
|
10912
10937
|
var AuthLayout;
|
|
10913
10938
|
var init_AuthLayout = __esm({
|
|
10914
10939
|
"components/core/templates/AuthLayout.tsx"() {
|
|
@@ -12250,6 +12275,39 @@ var init_IsometricCanvas2 = __esm({
|
|
|
12250
12275
|
init_IsometricCanvas();
|
|
12251
12276
|
}
|
|
12252
12277
|
});
|
|
12278
|
+
|
|
12279
|
+
// components/game/organisms/boardEntity.ts
|
|
12280
|
+
function boardEntity(entity) {
|
|
12281
|
+
if (!entity) return void 0;
|
|
12282
|
+
return Array.isArray(entity) ? entity[0] : entity;
|
|
12283
|
+
}
|
|
12284
|
+
function str(v) {
|
|
12285
|
+
return v == null ? "" : String(v);
|
|
12286
|
+
}
|
|
12287
|
+
function num(v, fallback = 0) {
|
|
12288
|
+
const n = Number(v);
|
|
12289
|
+
return Number.isFinite(n) ? n : fallback;
|
|
12290
|
+
}
|
|
12291
|
+
function rows(v) {
|
|
12292
|
+
return Array.isArray(v) ? v : [];
|
|
12293
|
+
}
|
|
12294
|
+
function vec2(v) {
|
|
12295
|
+
const o = v ?? {};
|
|
12296
|
+
return { x: num(o.x), y: num(o.y) };
|
|
12297
|
+
}
|
|
12298
|
+
function unitPosition(u) {
|
|
12299
|
+
return vec2(u.position);
|
|
12300
|
+
}
|
|
12301
|
+
function unitTeam(u) {
|
|
12302
|
+
return str(u.team);
|
|
12303
|
+
}
|
|
12304
|
+
function unitHealth(u) {
|
|
12305
|
+
return num(u.health);
|
|
12306
|
+
}
|
|
12307
|
+
var init_boardEntity = __esm({
|
|
12308
|
+
"components/game/organisms/boardEntity.ts"() {
|
|
12309
|
+
}
|
|
12310
|
+
});
|
|
12253
12311
|
function BattleBoard({
|
|
12254
12312
|
entity,
|
|
12255
12313
|
scale = 0.45,
|
|
@@ -12276,43 +12334,49 @@ function BattleBoard({
|
|
|
12276
12334
|
attackEvent,
|
|
12277
12335
|
className
|
|
12278
12336
|
}) {
|
|
12279
|
-
const
|
|
12280
|
-
const
|
|
12281
|
-
const
|
|
12282
|
-
const
|
|
12283
|
-
const
|
|
12284
|
-
const
|
|
12285
|
-
const
|
|
12286
|
-
const
|
|
12287
|
-
const
|
|
12288
|
-
const
|
|
12289
|
-
const
|
|
12337
|
+
const board = boardEntity(entity) ?? {};
|
|
12338
|
+
const tiles = Array.isArray(board.tiles) ? board.tiles : [];
|
|
12339
|
+
const features = Array.isArray(board.features) ? board.features : [];
|
|
12340
|
+
const boardWidth = num(board.boardWidth, 8);
|
|
12341
|
+
const boardHeight = num(board.boardHeight, 6);
|
|
12342
|
+
const assetManifest = board.assetManifest;
|
|
12343
|
+
const backgroundImage = board.backgroundImage;
|
|
12344
|
+
const units = rows(board.units);
|
|
12345
|
+
const selectedUnitId = board.selectedUnitId ?? null;
|
|
12346
|
+
const currentPhase = str(board.phase) || "observation";
|
|
12347
|
+
const currentTurn = num(board.turn, 1);
|
|
12348
|
+
const gameResult = board.gameResult ?? null;
|
|
12290
12349
|
const eventBus = useEventBus();
|
|
12291
12350
|
const { t } = useTranslate();
|
|
12292
12351
|
const [hoveredTile, setHoveredTile] = useState(null);
|
|
12293
12352
|
const [isShaking, setIsShaking] = useState(false);
|
|
12294
12353
|
const selectedUnit = useMemo(
|
|
12295
|
-
() => units.find((u) => u.id === selectedUnitId) ?? null,
|
|
12354
|
+
() => units.find((u) => str(u.id) === selectedUnitId) ?? null,
|
|
12296
12355
|
[units, selectedUnitId]
|
|
12297
12356
|
);
|
|
12298
12357
|
const hoveredUnit = useMemo(() => {
|
|
12299
12358
|
if (!hoveredTile) return null;
|
|
12300
|
-
return units.find(
|
|
12301
|
-
|
|
12302
|
-
|
|
12359
|
+
return units.find((u) => {
|
|
12360
|
+
const p2 = unitPosition(u);
|
|
12361
|
+
return p2.x === hoveredTile.x && p2.y === hoveredTile.y && unitHealth(u) > 0;
|
|
12362
|
+
}) ?? null;
|
|
12303
12363
|
}, [hoveredTile, units]);
|
|
12304
|
-
const playerUnits = useMemo(() => units.filter((u) => u
|
|
12305
|
-
const enemyUnits = useMemo(() => units.filter((u) => u
|
|
12364
|
+
const playerUnits = useMemo(() => units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0), [units]);
|
|
12365
|
+
const enemyUnits = useMemo(() => units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0), [units]);
|
|
12306
12366
|
const validMoves = useMemo(() => {
|
|
12307
12367
|
if (!selectedUnit || currentPhase !== "movement") return [];
|
|
12308
12368
|
const moves = [];
|
|
12309
|
-
const range = selectedUnit.movement;
|
|
12369
|
+
const range = num(selectedUnit.movement);
|
|
12370
|
+
const origin = unitPosition(selectedUnit);
|
|
12310
12371
|
for (let dy = -range; dy <= range; dy++) {
|
|
12311
12372
|
for (let dx = -range; dx <= range; dx++) {
|
|
12312
|
-
const nx =
|
|
12313
|
-
const ny =
|
|
12373
|
+
const nx = origin.x + dx;
|
|
12374
|
+
const ny = origin.y + dy;
|
|
12314
12375
|
const dist = Math.abs(dx) + Math.abs(dy);
|
|
12315
|
-
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) =>
|
|
12376
|
+
if (dist > 0 && dist <= range && nx >= 0 && nx < boardWidth && ny >= 0 && ny < boardHeight && !units.some((u) => {
|
|
12377
|
+
const p2 = unitPosition(u);
|
|
12378
|
+
return p2.x === nx && p2.y === ny && unitHealth(u) > 0;
|
|
12379
|
+
})) {
|
|
12316
12380
|
moves.push({ x: nx, y: ny });
|
|
12317
12381
|
}
|
|
12318
12382
|
}
|
|
@@ -12321,11 +12385,14 @@ function BattleBoard({
|
|
|
12321
12385
|
}, [selectedUnit, currentPhase, units, boardWidth, boardHeight]);
|
|
12322
12386
|
const attackTargets = useMemo(() => {
|
|
12323
12387
|
if (!selectedUnit || currentPhase !== "action") return [];
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12388
|
+
const sp = unitPosition(selectedUnit);
|
|
12389
|
+
const sTeam = unitTeam(selectedUnit);
|
|
12390
|
+
return units.filter((u) => unitTeam(u) !== sTeam && unitHealth(u) > 0).filter((u) => {
|
|
12391
|
+
const p2 = unitPosition(u);
|
|
12392
|
+
const dx = Math.abs(p2.x - sp.x);
|
|
12393
|
+
const dy = Math.abs(p2.y - sp.y);
|
|
12327
12394
|
return dx <= 1 && dy <= 1 && dx + dy > 0;
|
|
12328
|
-
}).map((u) => u
|
|
12395
|
+
}).map((u) => unitPosition(u));
|
|
12329
12396
|
}, [selectedUnit, currentPhase, units]);
|
|
12330
12397
|
const MOVE_SPEED_MS_PER_TILE = 300;
|
|
12331
12398
|
const movementAnimRef = useRef(null);
|
|
@@ -12365,23 +12432,25 @@ function BattleBoard({
|
|
|
12365
12432
|
return () => clearInterval(interval);
|
|
12366
12433
|
}, []);
|
|
12367
12434
|
const isoUnits = useMemo(() => {
|
|
12368
|
-
return units.filter((u) => u
|
|
12369
|
-
const
|
|
12435
|
+
return units.filter((u) => unitHealth(u) > 0).map((unit) => {
|
|
12436
|
+
const id = str(unit.id);
|
|
12437
|
+
const pos = movingPositions.get(id) ?? unitPosition(unit);
|
|
12438
|
+
const unitTraits = Array.isArray(unit.traits) ? unit.traits : void 0;
|
|
12370
12439
|
return {
|
|
12371
|
-
id
|
|
12440
|
+
id,
|
|
12372
12441
|
position: pos,
|
|
12373
|
-
name: unit.name,
|
|
12374
|
-
team: unit
|
|
12375
|
-
health: unit
|
|
12376
|
-
maxHealth: unit.maxHealth,
|
|
12377
|
-
unitType: unit.unitType,
|
|
12378
|
-
heroId: unit.heroId,
|
|
12379
|
-
sprite: unit.sprite,
|
|
12380
|
-
traits:
|
|
12381
|
-
name:
|
|
12382
|
-
currentState:
|
|
12383
|
-
states:
|
|
12384
|
-
cooldown:
|
|
12442
|
+
name: str(unit.name),
|
|
12443
|
+
team: unitTeam(unit),
|
|
12444
|
+
health: unitHealth(unit),
|
|
12445
|
+
maxHealth: num(unit.maxHealth),
|
|
12446
|
+
unitType: unit.unitType == null ? void 0 : str(unit.unitType),
|
|
12447
|
+
heroId: unit.heroId == null ? void 0 : str(unit.heroId),
|
|
12448
|
+
sprite: unit.sprite == null ? void 0 : str(unit.sprite),
|
|
12449
|
+
traits: unitTraits?.map((tr) => ({
|
|
12450
|
+
name: tr.name,
|
|
12451
|
+
currentState: tr.currentState,
|
|
12452
|
+
states: tr.states,
|
|
12453
|
+
cooldown: tr.cooldown ?? 0
|
|
12385
12454
|
}))
|
|
12386
12455
|
};
|
|
12387
12456
|
});
|
|
@@ -12393,8 +12462,8 @@ function BattleBoard({
|
|
|
12393
12462
|
[scale, baseOffsetX]
|
|
12394
12463
|
);
|
|
12395
12464
|
const checkGameEnd = useCallback(() => {
|
|
12396
|
-
const pa = units.filter((u) => u
|
|
12397
|
-
const ea = units.filter((u) => u
|
|
12465
|
+
const pa = units.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
12466
|
+
const ea = units.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
12398
12467
|
if (pa.length === 0) {
|
|
12399
12468
|
onGameEnd?.("defeat");
|
|
12400
12469
|
if (gameEndEvent) {
|
|
@@ -12408,21 +12477,22 @@ function BattleBoard({
|
|
|
12408
12477
|
}
|
|
12409
12478
|
}, [units, onGameEnd, gameEndEvent, eventBus]);
|
|
12410
12479
|
const handleUnitClick = useCallback((unitId) => {
|
|
12411
|
-
const unit = units.find((u) => u.id === unitId);
|
|
12480
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
12412
12481
|
if (!unit) return;
|
|
12413
12482
|
if (unitClickEvent) {
|
|
12414
12483
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
12415
12484
|
}
|
|
12416
12485
|
if (currentPhase === "action" && selectedUnit) {
|
|
12417
|
-
|
|
12418
|
-
|
|
12486
|
+
const up = unitPosition(unit);
|
|
12487
|
+
if (unitTeam(unit) === "enemy" && attackTargets.some((t2) => t2.x === up.x && t2.y === up.y)) {
|
|
12488
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
12419
12489
|
setIsShaking(true);
|
|
12420
12490
|
setTimeout(() => setIsShaking(false), 300);
|
|
12421
12491
|
onAttack?.(selectedUnit, unit, damage);
|
|
12422
12492
|
if (attackEvent) {
|
|
12423
12493
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
12424
|
-
attackerId: selectedUnit.id,
|
|
12425
|
-
targetId: unit.id,
|
|
12494
|
+
attackerId: str(selectedUnit.id),
|
|
12495
|
+
targetId: str(unit.id),
|
|
12426
12496
|
damage
|
|
12427
12497
|
});
|
|
12428
12498
|
}
|
|
@@ -12437,9 +12507,9 @@ function BattleBoard({
|
|
|
12437
12507
|
if (currentPhase === "movement" && selectedUnit) {
|
|
12438
12508
|
if (movementAnimRef.current) return;
|
|
12439
12509
|
if (validMoves.some((m) => m.x === x && m.y === y)) {
|
|
12440
|
-
const from = { ...selectedUnit
|
|
12510
|
+
const from = { ...unitPosition(selectedUnit) };
|
|
12441
12511
|
const to = { x, y };
|
|
12442
|
-
startMoveAnimation(selectedUnit.id, from, to, () => {
|
|
12512
|
+
startMoveAnimation(str(selectedUnit.id), from, to, () => {
|
|
12443
12513
|
onUnitMove?.(selectedUnit, to);
|
|
12444
12514
|
});
|
|
12445
12515
|
}
|
|
@@ -12597,6 +12667,7 @@ var init_BattleBoard = __esm({
|
|
|
12597
12667
|
init_Typography();
|
|
12598
12668
|
init_Stack();
|
|
12599
12669
|
init_IsometricCanvas2();
|
|
12670
|
+
init_boardEntity();
|
|
12600
12671
|
init_isometric();
|
|
12601
12672
|
BattleBoard.displayName = "BattleBoard";
|
|
12602
12673
|
}
|
|
@@ -13819,24 +13890,24 @@ var init_CodeBlock = __esm({
|
|
|
13819
13890
|
return;
|
|
13820
13891
|
}
|
|
13821
13892
|
lineEls.forEach((el) => {
|
|
13822
|
-
const
|
|
13823
|
-
if (hiddenLines.has(
|
|
13893
|
+
const num2 = parseInt(el.getAttribute("data-line") ?? "-1", 10);
|
|
13894
|
+
if (hiddenLines.has(num2)) {
|
|
13824
13895
|
el.style.display = "none";
|
|
13825
13896
|
return;
|
|
13826
13897
|
}
|
|
13827
13898
|
el.style.display = "";
|
|
13828
13899
|
el.style.position = "relative";
|
|
13829
13900
|
el.style.paddingLeft = "1.2em";
|
|
13830
|
-
const region = foldStartMap.get(
|
|
13901
|
+
const region = foldStartMap.get(num2);
|
|
13831
13902
|
if (!region) return;
|
|
13832
|
-
const isCollapsed = collapsed.has(
|
|
13903
|
+
const isCollapsed = collapsed.has(num2);
|
|
13833
13904
|
const toggle = document.createElement("span");
|
|
13834
13905
|
toggle.className = "fold-toggle";
|
|
13835
13906
|
toggle.textContent = isCollapsed ? "\u25B6" : "\u25BC";
|
|
13836
13907
|
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%";
|
|
13837
13908
|
toggle.addEventListener("click", (e) => {
|
|
13838
13909
|
e.stopPropagation();
|
|
13839
|
-
toggleFoldRef.current(
|
|
13910
|
+
toggleFoldRef.current(num2);
|
|
13840
13911
|
});
|
|
13841
13912
|
el.insertBefore(toggle, el.firstChild);
|
|
13842
13913
|
if (isCollapsed) {
|
|
@@ -16089,10 +16160,13 @@ var init_BookChapterView = __esm({
|
|
|
16089
16160
|
init_cn();
|
|
16090
16161
|
BookChapterView = ({
|
|
16091
16162
|
chapter,
|
|
16163
|
+
orbitalSchema,
|
|
16092
16164
|
direction,
|
|
16093
16165
|
className
|
|
16094
16166
|
}) => {
|
|
16095
16167
|
const { t: _t } = useTranslate();
|
|
16168
|
+
const title = String(chapter.title ?? "");
|
|
16169
|
+
const content = String(chapter.content ?? "");
|
|
16096
16170
|
return /* @__PURE__ */ jsxs(
|
|
16097
16171
|
VStack,
|
|
16098
16172
|
{
|
|
@@ -16100,16 +16174,16 @@ var init_BookChapterView = __esm({
|
|
|
16100
16174
|
className: cn("px-6 py-8 max-w-4xl mx-auto w-full", className),
|
|
16101
16175
|
style: { direction },
|
|
16102
16176
|
children: [
|
|
16103
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children:
|
|
16177
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h1", className: "text-3xl font-bold", children: title }),
|
|
16104
16178
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
16105
|
-
!!
|
|
16179
|
+
!!orbitalSchema && /* @__PURE__ */ jsx(ScaledDiagram, { children: /* @__PURE__ */ jsx(
|
|
16106
16180
|
JazariStateMachine,
|
|
16107
16181
|
{
|
|
16108
|
-
schema:
|
|
16182
|
+
schema: orbitalSchema,
|
|
16109
16183
|
direction
|
|
16110
16184
|
}
|
|
16111
16185
|
) }),
|
|
16112
|
-
/* @__PURE__ */ jsx(ContentRenderer, { content
|
|
16186
|
+
/* @__PURE__ */ jsx(ContentRenderer, { content, direction })
|
|
16113
16187
|
]
|
|
16114
16188
|
}
|
|
16115
16189
|
);
|
|
@@ -16207,7 +16281,7 @@ var init_BookNavBar = __esm({
|
|
|
16207
16281
|
BookNavBar = ({
|
|
16208
16282
|
currentPage,
|
|
16209
16283
|
totalPages,
|
|
16210
|
-
chapterTitle,
|
|
16284
|
+
chapterTitle: chapterTitle2,
|
|
16211
16285
|
direction,
|
|
16212
16286
|
className
|
|
16213
16287
|
}) => {
|
|
@@ -16248,12 +16322,12 @@ var init_BookNavBar = __esm({
|
|
|
16248
16322
|
)
|
|
16249
16323
|
] }),
|
|
16250
16324
|
/* @__PURE__ */ jsxs(Box, { className: "flex-1 mx-4 max-w-md", children: [
|
|
16251
|
-
|
|
16325
|
+
chapterTitle2 && /* @__PURE__ */ jsx(
|
|
16252
16326
|
Typography,
|
|
16253
16327
|
{
|
|
16254
16328
|
variant: "caption",
|
|
16255
16329
|
className: "text-center block truncate text-muted-foreground",
|
|
16256
|
-
children:
|
|
16330
|
+
children: chapterTitle2
|
|
16257
16331
|
}
|
|
16258
16332
|
),
|
|
16259
16333
|
/* @__PURE__ */ jsx(ProgressBar, { value: progress, size: "sm", variant: "primary" })
|
|
@@ -16320,31 +16394,35 @@ var init_BookTableOfContents = __esm({
|
|
|
16320
16394
|
style: { direction },
|
|
16321
16395
|
children: [
|
|
16322
16396
|
/* @__PURE__ */ jsx(Typography, { variant: "h1", className: "text-3xl font-bold text-center mb-4", children: t("book.tableOfContents") }),
|
|
16323
|
-
parts.map((part, partIdx) =>
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
/* @__PURE__ */
|
|
16327
|
-
|
|
16328
|
-
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
|
|
16334
|
-
|
|
16335
|
-
|
|
16336
|
-
|
|
16337
|
-
|
|
16338
|
-
|
|
16339
|
-
|
|
16340
|
-
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16397
|
+
parts.map((part, partIdx) => {
|
|
16398
|
+
const chapters = Array.isArray(part.chapters) ? part.chapters : [];
|
|
16399
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
16400
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", children: [
|
|
16401
|
+
/* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: t("book.partNumber", { number: String(partIdx + 1) }) }),
|
|
16402
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h3", className: "font-semibold", children: String(part.title ?? "") })
|
|
16403
|
+
] }),
|
|
16404
|
+
/* @__PURE__ */ jsx(VStack, { gap: "xs", className: direction === "rtl" ? "pr-6" : "pl-6", children: chapters.map((chapter) => {
|
|
16405
|
+
const id = chapter.id == null ? "" : String(chapter.id);
|
|
16406
|
+
const isCurrent = id === currentChapterId;
|
|
16407
|
+
return /* @__PURE__ */ jsx(
|
|
16408
|
+
Button,
|
|
16409
|
+
{
|
|
16410
|
+
variant: "ghost",
|
|
16411
|
+
size: "sm",
|
|
16412
|
+
action: "BOOK_NAVIGATE",
|
|
16413
|
+
actionPayload: { chapterId: id },
|
|
16414
|
+
className: cn(
|
|
16415
|
+
"justify-start text-left w-full",
|
|
16416
|
+
direction === "rtl" && "text-right",
|
|
16417
|
+
isCurrent && "bg-blue-50 dark:bg-blue-950 text-blue-600 dark:text-blue-400"
|
|
16418
|
+
),
|
|
16419
|
+
children: /* @__PURE__ */ jsx(Box, { className: "truncate", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: String(chapter.title ?? "") }) })
|
|
16420
|
+
},
|
|
16421
|
+
id
|
|
16422
|
+
);
|
|
16423
|
+
}) })
|
|
16424
|
+
] }, partIdx);
|
|
16425
|
+
})
|
|
16348
16426
|
]
|
|
16349
16427
|
}
|
|
16350
16428
|
);
|
|
@@ -16466,27 +16544,41 @@ function resolveFieldMap(fieldMap) {
|
|
|
16466
16544
|
function get(obj, key) {
|
|
16467
16545
|
return obj[key];
|
|
16468
16546
|
}
|
|
16547
|
+
function asStr(v) {
|
|
16548
|
+
return v == null ? "" : String(v);
|
|
16549
|
+
}
|
|
16469
16550
|
function mapBookData(raw, fields = IDENTITY_BOOK_FIELDS) {
|
|
16470
16551
|
const rawParts = get(raw, fields.parts) ?? [];
|
|
16471
|
-
|
|
16472
|
-
|
|
16473
|
-
|
|
16474
|
-
|
|
16475
|
-
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16479
|
-
return {
|
|
16480
|
-
title: get(part, fields.partTitle) ?? "",
|
|
16481
|
-
chapters: rawChapters.map((ch) => ({
|
|
16482
|
-
id: get(ch, fields.chapterId) ?? "",
|
|
16483
|
-
title: get(ch, fields.chapterTitle) ?? "",
|
|
16484
|
-
content: get(ch, fields.chapterContent) ?? "",
|
|
16485
|
-
orbitalSchema: get(ch, fields.chapterOrbitalSchema)
|
|
16486
|
-
}))
|
|
16487
|
-
};
|
|
16488
|
-
})
|
|
16552
|
+
const direction = get(raw, fields.direction) ?? "ltr";
|
|
16553
|
+
const cover = {
|
|
16554
|
+
title: asStr(get(raw, fields.title)),
|
|
16555
|
+
subtitle: asStr(get(raw, fields.subtitle)),
|
|
16556
|
+
author: asStr(get(raw, fields.author)),
|
|
16557
|
+
coverImageUrl: asStr(get(raw, fields.coverImageUrl)),
|
|
16558
|
+
direction
|
|
16489
16559
|
};
|
|
16560
|
+
const schemaByChapterId = {};
|
|
16561
|
+
const chapters = [];
|
|
16562
|
+
const parts = rawParts.map((part) => {
|
|
16563
|
+
const rawChapters = get(part, fields.chapters) ?? [];
|
|
16564
|
+
const chapterRows = rawChapters.map((ch) => {
|
|
16565
|
+
const id = asStr(get(ch, fields.chapterId));
|
|
16566
|
+
const schema = get(ch, fields.chapterOrbitalSchema);
|
|
16567
|
+
if (schema) schemaByChapterId[id] = schema;
|
|
16568
|
+
const row = {
|
|
16569
|
+
id,
|
|
16570
|
+
title: asStr(get(ch, fields.chapterTitle)),
|
|
16571
|
+
content: asStr(get(ch, fields.chapterContent))
|
|
16572
|
+
};
|
|
16573
|
+
chapters.push(row);
|
|
16574
|
+
return row;
|
|
16575
|
+
});
|
|
16576
|
+
return {
|
|
16577
|
+
title: asStr(get(part, fields.partTitle)),
|
|
16578
|
+
chapters: chapterRows
|
|
16579
|
+
};
|
|
16580
|
+
});
|
|
16581
|
+
return { cover, direction, parts, chapters, schemaByChapterId };
|
|
16490
16582
|
}
|
|
16491
16583
|
var IDENTITY_BOOK_FIELDS, AR_BOOK_FIELDS, FIELD_MAP_REGISTRY;
|
|
16492
16584
|
var init_types2 = __esm({
|
|
@@ -16524,10 +16616,7 @@ var init_types2 = __esm({
|
|
|
16524
16616
|
};
|
|
16525
16617
|
}
|
|
16526
16618
|
});
|
|
16527
|
-
|
|
16528
|
-
return book.parts.flatMap((part) => part.chapters);
|
|
16529
|
-
}
|
|
16530
|
-
var PRINT_STYLES, BookViewer;
|
|
16619
|
+
var chapterId, chapterTitle, PRINT_STYLES, BookViewer;
|
|
16531
16620
|
var init_BookViewer = __esm({
|
|
16532
16621
|
"components/marketing/organisms/book/BookViewer.tsx"() {
|
|
16533
16622
|
init_Box();
|
|
@@ -16540,6 +16629,8 @@ var init_BookViewer = __esm({
|
|
|
16540
16629
|
init_BookNavBar();
|
|
16541
16630
|
init_EmptyState();
|
|
16542
16631
|
init_types2();
|
|
16632
|
+
chapterId = (ch) => ch?.id == null ? void 0 : String(ch.id);
|
|
16633
|
+
chapterTitle = (ch) => ch?.title == null ? void 0 : String(ch.title);
|
|
16543
16634
|
PRINT_STYLES = `
|
|
16544
16635
|
@media print {
|
|
16545
16636
|
.book-viewer-page {
|
|
@@ -16568,14 +16659,14 @@ var init_BookViewer = __esm({
|
|
|
16568
16659
|
return mapBookData(raw, resolvedFieldMap);
|
|
16569
16660
|
}, [entity, resolvedFieldMap]);
|
|
16570
16661
|
const direction = book?.direction ?? "ltr";
|
|
16571
|
-
const chapters = useMemo(() => book ?
|
|
16662
|
+
const chapters = useMemo(() => book ? book.chapters : [], [book]);
|
|
16572
16663
|
const totalPages = 2 + chapters.length;
|
|
16573
16664
|
const navigateTo = useCallback(
|
|
16574
16665
|
(page) => {
|
|
16575
16666
|
const clamped = Math.max(0, Math.min(page, totalPages - 1));
|
|
16576
16667
|
setCurrentPage(clamped);
|
|
16577
|
-
const
|
|
16578
|
-
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId });
|
|
16668
|
+
const id = clamped >= 2 ? chapterId(chapters[clamped - 2]) : void 0;
|
|
16669
|
+
eventBus.emit("UI:BOOK_PAGE_CHANGE", { pageIndex: clamped, chapterId: id });
|
|
16579
16670
|
},
|
|
16580
16671
|
[totalPages, chapters, eventBus]
|
|
16581
16672
|
);
|
|
@@ -16587,8 +16678,8 @@ var init_BookViewer = __esm({
|
|
|
16587
16678
|
eventBus.on("UI:BOOK_PAGE_NEXT", () => navigateTo(currentPage + 1)),
|
|
16588
16679
|
eventBus.on("UI:BOOK_PRINT", () => window.print()),
|
|
16589
16680
|
eventBus.on("UI:BOOK_NAVIGATE", (event) => {
|
|
16590
|
-
const
|
|
16591
|
-
const idx = chapters.findIndex((ch) => ch
|
|
16681
|
+
const targetId = event.payload?.chapterId;
|
|
16682
|
+
const idx = chapters.findIndex((ch) => chapterId(ch) === targetId);
|
|
16592
16683
|
if (idx >= 0) navigateTo(idx + 2);
|
|
16593
16684
|
})
|
|
16594
16685
|
];
|
|
@@ -16605,9 +16696,11 @@ var init_BookViewer = __esm({
|
|
|
16605
16696
|
style.remove();
|
|
16606
16697
|
};
|
|
16607
16698
|
}, []);
|
|
16608
|
-
const currentChapterId = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16609
|
-
const currentChapterTitle = currentPage >= 2 ? chapters[currentPage - 2]
|
|
16699
|
+
const currentChapterId = currentPage >= 2 ? chapterId(chapters[currentPage - 2]) : void 0;
|
|
16700
|
+
const currentChapterTitle = currentPage >= 2 ? chapterTitle(chapters[currentPage - 2]) : void 0;
|
|
16610
16701
|
if (!book) return /* @__PURE__ */ jsx(EmptyState, { message: t("book.noData") });
|
|
16702
|
+
const cover = book.cover;
|
|
16703
|
+
const coverTitle = String(cover.title ?? "");
|
|
16611
16704
|
return /* @__PURE__ */ jsxs(VStack, { className: cn("relative h-full overflow-hidden bg-background", className), children: [
|
|
16612
16705
|
/* @__PURE__ */ jsxs(
|
|
16613
16706
|
Box,
|
|
@@ -16619,10 +16712,10 @@ var init_BookViewer = __esm({
|
|
|
16619
16712
|
/* @__PURE__ */ jsx(
|
|
16620
16713
|
BookCoverPage,
|
|
16621
16714
|
{
|
|
16622
|
-
title:
|
|
16623
|
-
subtitle:
|
|
16624
|
-
author:
|
|
16625
|
-
coverImageUrl:
|
|
16715
|
+
title: coverTitle,
|
|
16716
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16717
|
+
author: String(cover.author ?? "") || void 0,
|
|
16718
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16626
16719
|
direction
|
|
16627
16720
|
}
|
|
16628
16721
|
),
|
|
@@ -16633,23 +16726,27 @@ var init_BookViewer = __esm({
|
|
|
16633
16726
|
direction
|
|
16634
16727
|
}
|
|
16635
16728
|
),
|
|
16636
|
-
chapters.map((chapter) =>
|
|
16637
|
-
|
|
16638
|
-
|
|
16639
|
-
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
|
|
16643
|
-
|
|
16729
|
+
chapters.map((chapter) => {
|
|
16730
|
+
const id = chapterId(chapter);
|
|
16731
|
+
return /* @__PURE__ */ jsx(
|
|
16732
|
+
BookChapterView,
|
|
16733
|
+
{
|
|
16734
|
+
chapter,
|
|
16735
|
+
orbitalSchema: id ? book.schemaByChapterId[id] : void 0,
|
|
16736
|
+
direction
|
|
16737
|
+
},
|
|
16738
|
+
id
|
|
16739
|
+
);
|
|
16740
|
+
})
|
|
16644
16741
|
] }),
|
|
16645
16742
|
/* @__PURE__ */ jsxs(Box, { className: "print:hidden", children: [
|
|
16646
16743
|
currentPage === 0 && /* @__PURE__ */ jsx(
|
|
16647
16744
|
BookCoverPage,
|
|
16648
16745
|
{
|
|
16649
|
-
title:
|
|
16650
|
-
subtitle:
|
|
16651
|
-
author:
|
|
16652
|
-
coverImageUrl:
|
|
16746
|
+
title: coverTitle,
|
|
16747
|
+
subtitle: String(cover.subtitle ?? "") || void 0,
|
|
16748
|
+
author: String(cover.author ?? "") || void 0,
|
|
16749
|
+
coverImageUrl: String(cover.coverImageUrl ?? "") || void 0,
|
|
16653
16750
|
direction
|
|
16654
16751
|
}
|
|
16655
16752
|
),
|
|
@@ -16665,6 +16762,7 @@ var init_BookViewer = __esm({
|
|
|
16665
16762
|
BookChapterView,
|
|
16666
16763
|
{
|
|
16667
16764
|
chapter: chapters[currentPage - 2],
|
|
16765
|
+
orbitalSchema: currentChapterId ? book.schemaByChapterId[currentChapterId] : void 0,
|
|
16668
16766
|
direction
|
|
16669
16767
|
}
|
|
16670
16768
|
)
|
|
@@ -16677,7 +16775,7 @@ var init_BookViewer = __esm({
|
|
|
16677
16775
|
{
|
|
16678
16776
|
currentPage,
|
|
16679
16777
|
totalPages,
|
|
16680
|
-
chapterTitle: currentPage === 0 ?
|
|
16778
|
+
chapterTitle: currentPage === 0 ? coverTitle : currentPage === 1 ? t("book.tableOfContents") : currentChapterTitle,
|
|
16681
16779
|
direction
|
|
16682
16780
|
}
|
|
16683
16781
|
)
|
|
@@ -16775,7 +16873,7 @@ var init_Grid = __esm({
|
|
|
16775
16873
|
};
|
|
16776
16874
|
Grid = ({
|
|
16777
16875
|
cols = 1,
|
|
16778
|
-
rows,
|
|
16876
|
+
rows: rows2,
|
|
16779
16877
|
gap = "md",
|
|
16780
16878
|
rowGap,
|
|
16781
16879
|
colGap,
|
|
@@ -16787,7 +16885,7 @@ var init_Grid = __esm({
|
|
|
16787
16885
|
children,
|
|
16788
16886
|
as: Component = "div"
|
|
16789
16887
|
}) => {
|
|
16790
|
-
const mergedStyle =
|
|
16888
|
+
const mergedStyle = rows2 ? { gridTemplateRows: `repeat(${rows2}, minmax(0, 1fr))`, ...style } : style;
|
|
16791
16889
|
return React85__default.createElement(
|
|
16792
16890
|
Component,
|
|
16793
16891
|
{
|
|
@@ -17503,14 +17601,14 @@ function BuilderBoard({
|
|
|
17503
17601
|
}) {
|
|
17504
17602
|
const { emit } = useEventBus();
|
|
17505
17603
|
const { t } = useTranslate();
|
|
17506
|
-
const resolved =
|
|
17604
|
+
const resolved = boardEntity(entity);
|
|
17507
17605
|
const [placements, setPlacements] = useState({});
|
|
17508
17606
|
const [headerError, setHeaderError] = useState(false);
|
|
17509
17607
|
const [submitted, setSubmitted] = useState(false);
|
|
17510
17608
|
const [attempts, setAttempts] = useState(0);
|
|
17511
17609
|
const [showHint, setShowHint] = useState(false);
|
|
17512
|
-
const components = resolved?.components
|
|
17513
|
-
const slots = resolved?.slots
|
|
17610
|
+
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
17611
|
+
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
17514
17612
|
const usedComponentIds = new Set(Object.values(placements));
|
|
17515
17613
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
17516
17614
|
const [selectedComponent, setSelectedComponent] = useState(null);
|
|
@@ -17544,7 +17642,7 @@ function BuilderBoard({
|
|
|
17544
17642
|
}, [slots, placements, attempts, completeEvent, emit]);
|
|
17545
17643
|
const handleReset = () => {
|
|
17546
17644
|
setSubmitted(false);
|
|
17547
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
17645
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
17548
17646
|
setShowHint(true);
|
|
17549
17647
|
}
|
|
17550
17648
|
};
|
|
@@ -17557,20 +17655,24 @@ function BuilderBoard({
|
|
|
17557
17655
|
};
|
|
17558
17656
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
17559
17657
|
if (!resolved) return null;
|
|
17658
|
+
const theme = resolved.theme ?? void 0;
|
|
17659
|
+
const themeBackground = theme?.background;
|
|
17660
|
+
const headerImage = str(resolved.headerImage);
|
|
17661
|
+
const hint = str(resolved.hint);
|
|
17560
17662
|
return /* @__PURE__ */ jsx(
|
|
17561
17663
|
Box,
|
|
17562
17664
|
{
|
|
17563
17665
|
className,
|
|
17564
17666
|
style: {
|
|
17565
|
-
backgroundImage:
|
|
17667
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
17566
17668
|
backgroundSize: "cover",
|
|
17567
17669
|
backgroundPosition: "center"
|
|
17568
17670
|
},
|
|
17569
17671
|
children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
17570
|
-
|
|
17672
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
17571
17673
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
17572
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
17573
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description })
|
|
17674
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
17675
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
17574
17676
|
] }) }),
|
|
17575
17677
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
17576
17678
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.components") }),
|
|
@@ -17630,9 +17732,9 @@ function BuilderBoard({
|
|
|
17630
17732
|
] }) }),
|
|
17631
17733
|
submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17632
17734
|
/* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
17633
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
17735
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("builder.success") : str(resolved.failMessage) || t("builder.incorrect") })
|
|
17634
17736
|
] }) }),
|
|
17635
|
-
showHint &&
|
|
17737
|
+
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
17636
17738
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17637
17739
|
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17638
17740
|
/* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
|
|
@@ -17651,6 +17753,7 @@ var init_BuilderBoard = __esm({
|
|
|
17651
17753
|
"components/game/organisms/puzzles/builder/BuilderBoard.tsx"() {
|
|
17652
17754
|
init_atoms2();
|
|
17653
17755
|
init_useEventBus();
|
|
17756
|
+
init_boardEntity();
|
|
17654
17757
|
BuilderBoard.displayName = "BuilderBoard";
|
|
17655
17758
|
}
|
|
17656
17759
|
});
|
|
@@ -17988,21 +18091,24 @@ function CalendarGrid({
|
|
|
17988
18091
|
eventBus.emit(`UI:${longPressEvent}`, { date: day.toISOString(), time, ...longPressPayload });
|
|
17989
18092
|
}, 500);
|
|
17990
18093
|
}, [longPressEvent, longPressPayload, eventBus]);
|
|
17991
|
-
const renderEvent = (event) =>
|
|
17992
|
-
|
|
17993
|
-
|
|
17994
|
-
|
|
17995
|
-
|
|
17996
|
-
|
|
17997
|
-
|
|
17998
|
-
|
|
17999
|
-
|
|
18000
|
-
|
|
18001
|
-
|
|
18002
|
-
|
|
18003
|
-
|
|
18004
|
-
|
|
18005
|
-
|
|
18094
|
+
const renderEvent = (event) => {
|
|
18095
|
+
const color = event.color;
|
|
18096
|
+
return /* @__PURE__ */ jsx(
|
|
18097
|
+
Box,
|
|
18098
|
+
{
|
|
18099
|
+
rounded: "md",
|
|
18100
|
+
padding: "xs",
|
|
18101
|
+
border: true,
|
|
18102
|
+
className: cn(
|
|
18103
|
+
"cursor-pointer hover:shadow-sm transition-shadow text-xs truncate",
|
|
18104
|
+
color ? color : "bg-blue-500/15 border-blue-500/30 text-blue-600"
|
|
18105
|
+
),
|
|
18106
|
+
onClick: (e) => handleEventClick(event, e),
|
|
18107
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "small", className: "truncate font-medium", children: event.title })
|
|
18108
|
+
},
|
|
18109
|
+
event.id
|
|
18110
|
+
);
|
|
18111
|
+
};
|
|
18006
18112
|
return /* @__PURE__ */ jsxs(
|
|
18007
18113
|
Box,
|
|
18008
18114
|
{
|
|
@@ -19666,7 +19772,6 @@ var init_CardGrid = __esm({
|
|
|
19666
19772
|
alignItems = "stretch",
|
|
19667
19773
|
className,
|
|
19668
19774
|
children,
|
|
19669
|
-
// EntityDisplayProps
|
|
19670
19775
|
entity,
|
|
19671
19776
|
isLoading = false,
|
|
19672
19777
|
error = null,
|
|
@@ -20138,14 +20243,14 @@ var init_CaseStudyOrganism = __esm({
|
|
|
20138
20243
|
/* @__PURE__ */ jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((study) => /* @__PURE__ */ jsx(
|
|
20139
20244
|
CaseStudyCard,
|
|
20140
20245
|
{
|
|
20141
|
-
title: study.title,
|
|
20142
|
-
description: study.description,
|
|
20143
|
-
category: study.category,
|
|
20144
|
-
categoryColor: study.categoryColor,
|
|
20145
|
-
href: study.href,
|
|
20146
|
-
linkLabel: study.linkLabel
|
|
20246
|
+
title: String(study.title ?? ""),
|
|
20247
|
+
description: String(study.description ?? ""),
|
|
20248
|
+
category: String(study.category ?? ""),
|
|
20249
|
+
categoryColor: study.categoryColor != null ? String(study.categoryColor) : void 0,
|
|
20250
|
+
href: String(study.href ?? ""),
|
|
20251
|
+
linkLabel: study.linkLabel != null ? String(study.linkLabel) : void 0
|
|
20147
20252
|
},
|
|
20148
|
-
study.id
|
|
20253
|
+
String(study.id ?? "")
|
|
20149
20254
|
)) })
|
|
20150
20255
|
] });
|
|
20151
20256
|
};
|
|
@@ -20168,10 +20273,10 @@ function CastleBoard({
|
|
|
20168
20273
|
className
|
|
20169
20274
|
}) {
|
|
20170
20275
|
const eventBus = useEventBus();
|
|
20171
|
-
const resolved =
|
|
20172
|
-
const tiles = resolved?.tiles
|
|
20173
|
-
const features = resolved?.features
|
|
20174
|
-
const units = resolved?.units
|
|
20276
|
+
const resolved = boardEntity(entity);
|
|
20277
|
+
const tiles = Array.isArray(resolved?.tiles) ? resolved.tiles : [];
|
|
20278
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
20279
|
+
const units = Array.isArray(resolved?.units) ? resolved.units : [];
|
|
20175
20280
|
const assetManifest = resolved?.assetManifest;
|
|
20176
20281
|
const backgroundImage = resolved?.backgroundImage;
|
|
20177
20282
|
const [hoveredTile, setHoveredTile] = useState(null);
|
|
@@ -20199,7 +20304,7 @@ function CastleBoard({
|
|
|
20199
20304
|
onFeatureClick?.(feature);
|
|
20200
20305
|
if (featureClickEvent) {
|
|
20201
20306
|
eventBus.emit(`UI:${featureClickEvent}`, {
|
|
20202
|
-
featureId: feature.id,
|
|
20307
|
+
featureId: feature.id ?? "",
|
|
20203
20308
|
featureType: feature.type,
|
|
20204
20309
|
x: feature.x,
|
|
20205
20310
|
y: feature.y
|
|
@@ -20267,6 +20372,7 @@ var init_CastleBoard = __esm({
|
|
|
20267
20372
|
init_cn();
|
|
20268
20373
|
init_useEventBus();
|
|
20269
20374
|
init_IsometricCanvas2();
|
|
20375
|
+
init_boardEntity();
|
|
20270
20376
|
init_isometric();
|
|
20271
20377
|
CastleBoard.displayName = "CastleBoard";
|
|
20272
20378
|
}
|
|
@@ -21077,14 +21183,14 @@ function ClassifierBoard({
|
|
|
21077
21183
|
}) {
|
|
21078
21184
|
const { emit } = useEventBus();
|
|
21079
21185
|
const { t } = useTranslate();
|
|
21080
|
-
const resolved =
|
|
21186
|
+
const resolved = boardEntity(entity);
|
|
21081
21187
|
const [assignments, setAssignments] = useState({});
|
|
21082
21188
|
const [headerError, setHeaderError] = useState(false);
|
|
21083
21189
|
const [submitted, setSubmitted] = useState(false);
|
|
21084
21190
|
const [attempts, setAttempts] = useState(0);
|
|
21085
21191
|
const [showHint, setShowHint] = useState(false);
|
|
21086
|
-
const items = resolved?.items
|
|
21087
|
-
const categories = resolved?.categories
|
|
21192
|
+
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
21193
|
+
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
21088
21194
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
21089
21195
|
const allAssigned = Object.keys(assignments).length === items.length;
|
|
21090
21196
|
const results = submitted ? items.map((item) => ({
|
|
@@ -21116,7 +21222,7 @@ function ClassifierBoard({
|
|
|
21116
21222
|
}, [items, assignments, attempts, completeEvent, emit]);
|
|
21117
21223
|
const handleReset = () => {
|
|
21118
21224
|
setSubmitted(false);
|
|
21119
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
21225
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
21120
21226
|
setShowHint(true);
|
|
21121
21227
|
}
|
|
21122
21228
|
};
|
|
@@ -21127,20 +21233,25 @@ function ClassifierBoard({
|
|
|
21127
21233
|
setShowHint(false);
|
|
21128
21234
|
};
|
|
21129
21235
|
if (!resolved) return null;
|
|
21236
|
+
const theme = resolved.theme ?? void 0;
|
|
21237
|
+
const themeBackground = theme?.background;
|
|
21238
|
+
const headerImage = str(resolved.headerImage);
|
|
21239
|
+
const hint = str(resolved.hint);
|
|
21240
|
+
const failMessage = str(resolved.failMessage);
|
|
21130
21241
|
return /* @__PURE__ */ jsx(
|
|
21131
21242
|
Box,
|
|
21132
21243
|
{
|
|
21133
21244
|
className,
|
|
21134
21245
|
style: {
|
|
21135
|
-
backgroundImage:
|
|
21246
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
21136
21247
|
backgroundSize: "cover",
|
|
21137
21248
|
backgroundPosition: "center"
|
|
21138
21249
|
},
|
|
21139
21250
|
children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
21140
|
-
|
|
21251
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
21141
21252
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
21142
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
21143
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description })
|
|
21253
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
21254
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
21144
21255
|
] }) }),
|
|
21145
21256
|
unassignedItems.length > 0 && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
21146
21257
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("classifier.itemsToSort") }),
|
|
@@ -21192,10 +21303,10 @@ function ClassifierBoard({
|
|
|
21192
21303
|
}) }),
|
|
21193
21304
|
submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
21194
21305
|
/* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-success" : "text-error" }),
|
|
21195
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
21196
|
-
!allCorrect &&
|
|
21306
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("classifier.allCorrect") : `${correctCount}/${items.length} ${t("classifier.correct")}` }),
|
|
21307
|
+
!allCorrect && failMessage && /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-muted-foreground", children: failMessage })
|
|
21197
21308
|
] }) }),
|
|
21198
|
-
showHint &&
|
|
21309
|
+
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
21199
21310
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
21200
21311
|
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
|
|
21201
21312
|
/* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
|
|
@@ -21214,6 +21325,7 @@ var init_ClassifierBoard = __esm({
|
|
|
21214
21325
|
"components/game/organisms/puzzles/classifier/ClassifierBoard.tsx"() {
|
|
21215
21326
|
init_atoms2();
|
|
21216
21327
|
init_useEventBus();
|
|
21328
|
+
init_boardEntity();
|
|
21217
21329
|
ClassifierBoard.displayName = "ClassifierBoard";
|
|
21218
21330
|
}
|
|
21219
21331
|
});
|
|
@@ -27584,7 +27696,7 @@ function InventoryPanel({
|
|
|
27584
27696
|
const slotArray = Array.from({ length: safeSlots }, (_, index) => {
|
|
27585
27697
|
return safeItems[index] ?? null;
|
|
27586
27698
|
});
|
|
27587
|
-
const
|
|
27699
|
+
const rows2 = Math.ceil(safeSlots / safeColumns);
|
|
27588
27700
|
const handleSlotClick = useCallback((index) => {
|
|
27589
27701
|
if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
|
|
27590
27702
|
onSelectSlot?.(index);
|
|
@@ -27653,7 +27765,7 @@ function InventoryPanel({
|
|
|
27653
27765
|
className: "grid gap-1 bg-[var(--color-card)] p-2 rounded-container border border-border",
|
|
27654
27766
|
style: {
|
|
27655
27767
|
gridTemplateColumns: `repeat(${safeColumns}, ${slotSize}px)`,
|
|
27656
|
-
gridTemplateRows: `repeat(${
|
|
27768
|
+
gridTemplateRows: `repeat(${rows2}, ${slotSize}px)`
|
|
27657
27769
|
},
|
|
27658
27770
|
children: slotArray.map((item, index) => /* @__PURE__ */ jsx(
|
|
27659
27771
|
"button",
|
|
@@ -31617,11 +31729,11 @@ function LatticeSVG({
|
|
|
31617
31729
|
}) {
|
|
31618
31730
|
const paths = [];
|
|
31619
31731
|
const cols = 5;
|
|
31620
|
-
const
|
|
31732
|
+
const rows2 = Math.ceil(h / (w / cols));
|
|
31621
31733
|
const cellW = w / cols;
|
|
31622
31734
|
const cellH = cellW;
|
|
31623
31735
|
const bulge = cellW * 0.3;
|
|
31624
|
-
for (let row = 0; row <
|
|
31736
|
+
for (let row = 0; row < rows2; row++) {
|
|
31625
31737
|
for (let col = 0; col < cols; col++) {
|
|
31626
31738
|
const cx = col * cellW + cellW / 2;
|
|
31627
31739
|
const cy = row * cellH + cellH / 2;
|
|
@@ -32033,7 +32145,7 @@ var init_MatrixQuestion = __esm({
|
|
|
32033
32145
|
};
|
|
32034
32146
|
MatrixQuestion = ({
|
|
32035
32147
|
title,
|
|
32036
|
-
rows,
|
|
32148
|
+
rows: rows2,
|
|
32037
32149
|
columns = DEFAULT_MATRIX_COLUMNS,
|
|
32038
32150
|
values,
|
|
32039
32151
|
onChange,
|
|
@@ -32043,7 +32155,7 @@ var init_MatrixQuestion = __esm({
|
|
|
32043
32155
|
className
|
|
32044
32156
|
}) => {
|
|
32045
32157
|
const styles = sizeStyles13[size];
|
|
32046
|
-
const safeRows =
|
|
32158
|
+
const safeRows = rows2 ?? [];
|
|
32047
32159
|
const safeValues = values ?? {};
|
|
32048
32160
|
const eventBus = useEventBus();
|
|
32049
32161
|
const handleChange = useCallback(
|
|
@@ -32671,7 +32783,8 @@ var init_PositionedCanvas = __esm({
|
|
|
32671
32783
|
dragRef.current = null;
|
|
32672
32784
|
setDraggingId(null);
|
|
32673
32785
|
if (!wasDrag) {
|
|
32674
|
-
const
|
|
32786
|
+
const itemId = item.id;
|
|
32787
|
+
const next = selectedId === itemId ? null : itemId;
|
|
32675
32788
|
onSelect?.(next);
|
|
32676
32789
|
if (selectEvent) {
|
|
32677
32790
|
eventBus.emit(`UI:${selectEvent}`, { id: next });
|
|
@@ -32706,15 +32819,22 @@ var init_PositionedCanvas = __esm({
|
|
|
32706
32819
|
style: { width, height },
|
|
32707
32820
|
onClick: handleContainerClick,
|
|
32708
32821
|
children: items.map((item) => {
|
|
32822
|
+
const itemId = item.id;
|
|
32823
|
+
const label = item.label;
|
|
32824
|
+
const x = item.x;
|
|
32825
|
+
const y = item.y;
|
|
32826
|
+
const capacity = item.capacity;
|
|
32827
|
+
const partySize = item.partySize;
|
|
32828
|
+
const serverName = item.serverName;
|
|
32709
32829
|
const status = item.status ?? "empty";
|
|
32710
32830
|
const shape = item.shape ?? "round";
|
|
32711
|
-
const isSelected = selectedId ===
|
|
32712
|
-
const isDragging = draggingId ===
|
|
32831
|
+
const isSelected = selectedId === itemId;
|
|
32832
|
+
const isDragging = draggingId === itemId;
|
|
32713
32833
|
const statusBadge = STATUS_BADGE[status];
|
|
32714
32834
|
return /* @__PURE__ */ jsxs(
|
|
32715
32835
|
Box,
|
|
32716
32836
|
{
|
|
32717
|
-
"data-testid": `item-node-${
|
|
32837
|
+
"data-testid": `item-node-${itemId}`,
|
|
32718
32838
|
"data-status": status,
|
|
32719
32839
|
className: cn(
|
|
32720
32840
|
"absolute flex flex-col items-center justify-center gap-1 border-2 select-none",
|
|
@@ -32725,7 +32845,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32725
32845
|
isSelected && "outline outline-2 outline-offset-2 outline-primary shadow-md",
|
|
32726
32846
|
isDragging && "shadow-lg z-10"
|
|
32727
32847
|
),
|
|
32728
|
-
style: { left:
|
|
32848
|
+
style: { left: x, top: y, touchAction: "none" },
|
|
32729
32849
|
onPointerDown: (e) => handlePointerDown(e, item),
|
|
32730
32850
|
onPointerMove: handlePointerMove,
|
|
32731
32851
|
onPointerUp: (e) => handlePointerUp(e, item),
|
|
@@ -32733,10 +32853,10 @@ var init_PositionedCanvas = __esm({
|
|
|
32733
32853
|
children: [
|
|
32734
32854
|
/* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-1", children: [
|
|
32735
32855
|
getStatusIcon(status),
|
|
32736
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "semibold", children:
|
|
32856
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", weight: "semibold", children: label })
|
|
32737
32857
|
] }),
|
|
32738
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
32739
|
-
status === "seated" &&
|
|
32858
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: partySize !== void 0 && status === "seated" ? `${partySize}/${capacity}` : `Cap ${capacity}` }),
|
|
32859
|
+
status === "seated" && serverName && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "truncate max-w-[80%]", children: serverName }),
|
|
32740
32860
|
isSelected && /* @__PURE__ */ jsx(
|
|
32741
32861
|
Badge,
|
|
32742
32862
|
{
|
|
@@ -32748,7 +32868,7 @@ var init_PositionedCanvas = __esm({
|
|
|
32748
32868
|
)
|
|
32749
32869
|
]
|
|
32750
32870
|
},
|
|
32751
|
-
|
|
32871
|
+
itemId
|
|
32752
32872
|
);
|
|
32753
32873
|
})
|
|
32754
32874
|
}
|
|
@@ -33520,9 +33640,10 @@ var init_RichBlockEditor = __esm({
|
|
|
33520
33640
|
});
|
|
33521
33641
|
function collectInitiallyCollapsed(nodes, acc) {
|
|
33522
33642
|
for (const n of nodes) {
|
|
33643
|
+
const replies = n.replies;
|
|
33523
33644
|
if (n.collapsed) acc.add(n.id);
|
|
33524
|
-
if (
|
|
33525
|
-
collectInitiallyCollapsed(
|
|
33645
|
+
if (replies && replies.length > 0) {
|
|
33646
|
+
collectInitiallyCollapsed(replies, acc);
|
|
33526
33647
|
}
|
|
33527
33648
|
}
|
|
33528
33649
|
}
|
|
@@ -33552,44 +33673,52 @@ var init_ReplyTree = __esm({
|
|
|
33552
33673
|
}) => {
|
|
33553
33674
|
const eventBus = useEventBus();
|
|
33554
33675
|
const { t } = useTranslate();
|
|
33555
|
-
const
|
|
33556
|
-
const
|
|
33676
|
+
const nodeId = node.id;
|
|
33677
|
+
const authorName = node.authorName;
|
|
33678
|
+
const authorAvatarUrl = node.authorAvatarUrl;
|
|
33679
|
+
const content = node.content;
|
|
33680
|
+
const postedAt = node.postedAt;
|
|
33681
|
+
const voteCount = node.voteCount;
|
|
33682
|
+
const userVote = node.userVote;
|
|
33683
|
+
const replies = node.replies;
|
|
33684
|
+
const hasReplies = !!replies && replies.length > 0;
|
|
33685
|
+
const isCollapsed = collapsedSet.has(nodeId);
|
|
33557
33686
|
const atMaxDepth = depth >= maxDepth;
|
|
33558
33687
|
const [replyOpen, setReplyOpen] = useState(false);
|
|
33559
33688
|
const [draft, setDraft] = useState("");
|
|
33560
33689
|
const handleVote = useCallback(
|
|
33561
33690
|
(next) => {
|
|
33562
|
-
onVote?.(
|
|
33563
|
-
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId
|
|
33691
|
+
onVote?.(nodeId, next);
|
|
33692
|
+
if (voteEvent) eventBus.emit(`UI:${voteEvent}`, { nodeId, vote: next });
|
|
33564
33693
|
},
|
|
33565
|
-
[
|
|
33694
|
+
[nodeId, onVote, voteEvent, eventBus]
|
|
33566
33695
|
);
|
|
33567
33696
|
const handleReply = useCallback(() => {
|
|
33568
|
-
onReply?.(
|
|
33697
|
+
onReply?.(nodeId);
|
|
33569
33698
|
setReplyOpen((open) => !open);
|
|
33570
|
-
}, [
|
|
33699
|
+
}, [nodeId, onReply]);
|
|
33571
33700
|
const handleSubmitReply = useCallback(() => {
|
|
33572
|
-
const
|
|
33573
|
-
if (!
|
|
33574
|
-
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId:
|
|
33701
|
+
const text = draft.trim();
|
|
33702
|
+
if (!text) return;
|
|
33703
|
+
if (replyEvent) eventBus.emit(`UI:${replyEvent}`, { parentNodeId: nodeId, content: text });
|
|
33575
33704
|
setDraft("");
|
|
33576
33705
|
setReplyOpen(false);
|
|
33577
|
-
}, [
|
|
33706
|
+
}, [nodeId, draft, replyEvent, eventBus]);
|
|
33578
33707
|
const handleCancelReply = useCallback(() => {
|
|
33579
33708
|
setDraft("");
|
|
33580
33709
|
setReplyOpen(false);
|
|
33581
33710
|
}, []);
|
|
33582
33711
|
const handleFlag = useCallback(() => {
|
|
33583
|
-
onFlag?.(
|
|
33584
|
-
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId
|
|
33585
|
-
}, [
|
|
33712
|
+
onFlag?.(nodeId);
|
|
33713
|
+
if (flagEvent) eventBus.emit(`UI:${flagEvent}`, { nodeId });
|
|
33714
|
+
}, [nodeId, onFlag, flagEvent, eventBus]);
|
|
33586
33715
|
const handleContinue = useCallback(() => {
|
|
33587
|
-
onContinueThread?.(
|
|
33588
|
-
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId
|
|
33589
|
-
}, [
|
|
33716
|
+
onContinueThread?.(nodeId);
|
|
33717
|
+
if (continueThreadEvent) eventBus.emit(`UI:${continueThreadEvent}`, { nodeId });
|
|
33718
|
+
}, [nodeId, onContinueThread, continueThreadEvent, eventBus]);
|
|
33590
33719
|
const handleToggle = useCallback(() => {
|
|
33591
|
-
toggleCollapse(
|
|
33592
|
-
}, [
|
|
33720
|
+
toggleCollapse(nodeId);
|
|
33721
|
+
}, [nodeId, toggleCollapse]);
|
|
33593
33722
|
return /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-stretch min-w-0", children: [
|
|
33594
33723
|
/* @__PURE__ */ jsxs(Box, { className: "flex flex-col items-center flex-shrink-0 w-6", children: [
|
|
33595
33724
|
hasReplies ? /* @__PURE__ */ jsx(
|
|
@@ -33621,25 +33750,25 @@ var init_ReplyTree = __esm({
|
|
|
33621
33750
|
/* @__PURE__ */ jsx(
|
|
33622
33751
|
Avatar,
|
|
33623
33752
|
{
|
|
33624
|
-
src:
|
|
33625
|
-
name:
|
|
33753
|
+
src: authorAvatarUrl,
|
|
33754
|
+
name: authorName,
|
|
33626
33755
|
size: "sm"
|
|
33627
33756
|
}
|
|
33628
33757
|
),
|
|
33629
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "semibold", children:
|
|
33630
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children:
|
|
33758
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "semibold", children: authorName }),
|
|
33759
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: postedAt })
|
|
33631
33760
|
] }),
|
|
33632
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children:
|
|
33761
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", className: "whitespace-pre-wrap break-words", children: content }),
|
|
33633
33762
|
showActions && /* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
33634
33763
|
/* @__PURE__ */ jsx(
|
|
33635
33764
|
VoteStack,
|
|
33636
33765
|
{
|
|
33637
|
-
count:
|
|
33638
|
-
userVote:
|
|
33766
|
+
count: voteCount ?? 0,
|
|
33767
|
+
userVote: userVote ?? null,
|
|
33639
33768
|
onVote: handleVote,
|
|
33640
33769
|
size: "sm",
|
|
33641
33770
|
variant: "horizontal",
|
|
33642
|
-
label: t("replyTree.voteOnReplyBy", { author:
|
|
33771
|
+
label: t("replyTree.voteOnReplyBy", { author: authorName })
|
|
33643
33772
|
}
|
|
33644
33773
|
),
|
|
33645
33774
|
/* @__PURE__ */ jsx(
|
|
@@ -33649,7 +33778,7 @@ var init_ReplyTree = __esm({
|
|
|
33649
33778
|
size: "sm",
|
|
33650
33779
|
leftIcon: "message-square",
|
|
33651
33780
|
onClick: handleReply,
|
|
33652
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33781
|
+
"aria-label": t("replyTree.replyTo", { author: authorName }),
|
|
33653
33782
|
children: t("replyTree.reply")
|
|
33654
33783
|
}
|
|
33655
33784
|
),
|
|
@@ -33660,7 +33789,7 @@ var init_ReplyTree = __esm({
|
|
|
33660
33789
|
size: "sm",
|
|
33661
33790
|
leftIcon: "flag",
|
|
33662
33791
|
onClick: handleFlag,
|
|
33663
|
-
"aria-label": t("replyTree.flagReplyBy", { author:
|
|
33792
|
+
"aria-label": t("replyTree.flagReplyBy", { author: authorName }),
|
|
33664
33793
|
children: t("replyTree.flag")
|
|
33665
33794
|
}
|
|
33666
33795
|
)
|
|
@@ -33672,9 +33801,9 @@ var init_ReplyTree = __esm({
|
|
|
33672
33801
|
inputType: "textarea",
|
|
33673
33802
|
rows: 2,
|
|
33674
33803
|
value: draft,
|
|
33675
|
-
placeholder: t("replyTree.replyToPlaceholder", { author:
|
|
33804
|
+
placeholder: t("replyTree.replyToPlaceholder", { author: authorName }),
|
|
33676
33805
|
onChange: (e) => setDraft(e.target.value),
|
|
33677
|
-
"aria-label": t("replyTree.replyTo", { author:
|
|
33806
|
+
"aria-label": t("replyTree.replyTo", { author: authorName })
|
|
33678
33807
|
}
|
|
33679
33808
|
),
|
|
33680
33809
|
/* @__PURE__ */ jsxs(Box, { className: "flex flex-row gap-2 items-center", children: [
|
|
@@ -33705,7 +33834,7 @@ var init_ReplyTree = __esm({
|
|
|
33705
33834
|
),
|
|
33706
33835
|
children: t("replyTree.continueThread")
|
|
33707
33836
|
}
|
|
33708
|
-
) : /* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-2 mt-1", children:
|
|
33837
|
+
) : /* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-2 mt-1", children: replies.map((child) => /* @__PURE__ */ jsx(
|
|
33709
33838
|
ReplyTreeNode,
|
|
33710
33839
|
{
|
|
33711
33840
|
node: child,
|
|
@@ -36025,8 +36154,8 @@ var init_WizardContainer = __esm({
|
|
|
36025
36154
|
return void 0;
|
|
36026
36155
|
if (typeof controlledStep === "number") return controlledStep;
|
|
36027
36156
|
if (typeof controlledStep === "string") return parseInt(controlledStep, 10);
|
|
36028
|
-
const
|
|
36029
|
-
return isNaN(
|
|
36157
|
+
const num2 = Number(controlledStep);
|
|
36158
|
+
return isNaN(num2) ? void 0 : num2;
|
|
36030
36159
|
})();
|
|
36031
36160
|
const currentStep = normalizedControlledStep !== void 0 ? normalizedControlledStep : internalStep;
|
|
36032
36161
|
const totalSteps = steps.length;
|
|
@@ -37731,7 +37860,7 @@ function DebuggerBoard({
|
|
|
37731
37860
|
}) {
|
|
37732
37861
|
const { emit } = useEventBus();
|
|
37733
37862
|
const { t } = useTranslate();
|
|
37734
|
-
const resolved =
|
|
37863
|
+
const resolved = boardEntity(entity);
|
|
37735
37864
|
const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
|
|
37736
37865
|
const [headerError, setHeaderError] = useState(false);
|
|
37737
37866
|
const [submitted, setSubmitted] = useState(false);
|
|
@@ -37749,7 +37878,7 @@ function DebuggerBoard({
|
|
|
37749
37878
|
return next;
|
|
37750
37879
|
});
|
|
37751
37880
|
};
|
|
37752
|
-
const lines = resolved?.lines
|
|
37881
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37753
37882
|
const bugLines = lines.filter((l) => l.isBug);
|
|
37754
37883
|
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
37755
37884
|
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
@@ -37764,7 +37893,7 @@ function DebuggerBoard({
|
|
|
37764
37893
|
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37765
37894
|
const handleReset = () => {
|
|
37766
37895
|
setSubmitted(false);
|
|
37767
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
37896
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
37768
37897
|
setShowHint(true);
|
|
37769
37898
|
}
|
|
37770
37899
|
};
|
|
@@ -37775,24 +37904,28 @@ function DebuggerBoard({
|
|
|
37775
37904
|
setShowHint(false);
|
|
37776
37905
|
};
|
|
37777
37906
|
if (!resolved) return null;
|
|
37907
|
+
const theme = resolved.theme ?? void 0;
|
|
37908
|
+
const themeBackground = theme?.background;
|
|
37909
|
+
const headerImage = str(resolved.headerImage);
|
|
37910
|
+
const hint = str(resolved.hint);
|
|
37778
37911
|
return /* @__PURE__ */ jsx(
|
|
37779
37912
|
Box,
|
|
37780
37913
|
{
|
|
37781
37914
|
className,
|
|
37782
37915
|
style: {
|
|
37783
|
-
backgroundImage:
|
|
37916
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
37784
37917
|
backgroundSize: "cover",
|
|
37785
37918
|
backgroundPosition: "center"
|
|
37786
37919
|
},
|
|
37787
37920
|
children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
37788
|
-
|
|
37921
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
37789
37922
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
37790
37923
|
/* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
37791
37924
|
/* @__PURE__ */ jsx(Icon, { icon: Bug, size: "sm" }),
|
|
37792
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title })
|
|
37925
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) })
|
|
37793
37926
|
] }),
|
|
37794
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description }),
|
|
37795
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(resolved.bugCount) }) })
|
|
37927
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
37928
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
37796
37929
|
] }) }),
|
|
37797
37930
|
/* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
37798
37931
|
const isFlagged = flaggedLines.has(line.id);
|
|
@@ -37824,7 +37957,7 @@ function DebuggerBoard({
|
|
|
37824
37957
|
);
|
|
37825
37958
|
}) }) }),
|
|
37826
37959
|
submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
37827
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? resolved.successMessage
|
|
37960
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? str(resolved.successMessage) || t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
|
|
37828
37961
|
bugLines.map((line) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "start", children: [
|
|
37829
37962
|
/* @__PURE__ */ jsx(
|
|
37830
37963
|
Icon,
|
|
@@ -37840,7 +37973,7 @@ function DebuggerBoard({
|
|
|
37840
37973
|
] })
|
|
37841
37974
|
] }, line.id))
|
|
37842
37975
|
] }) }),
|
|
37843
|
-
showHint &&
|
|
37976
|
+
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
37844
37977
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
37845
37978
|
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
|
|
37846
37979
|
/* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
|
|
@@ -37859,6 +37992,7 @@ var init_DebuggerBoard = __esm({
|
|
|
37859
37992
|
"components/game/organisms/puzzles/debugger/DebuggerBoard.tsx"() {
|
|
37860
37993
|
init_atoms2();
|
|
37861
37994
|
init_useEventBus();
|
|
37995
|
+
init_boardEntity();
|
|
37862
37996
|
DebuggerBoard.displayName = "DebuggerBoard";
|
|
37863
37997
|
}
|
|
37864
37998
|
});
|
|
@@ -37896,7 +38030,7 @@ function getBadgeVariant(fieldName, value) {
|
|
|
37896
38030
|
return "default";
|
|
37897
38031
|
}
|
|
37898
38032
|
function formatFieldLabel(fieldName) {
|
|
37899
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
38033
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase());
|
|
37900
38034
|
}
|
|
37901
38035
|
function formatFieldValue(value, fieldName) {
|
|
37902
38036
|
if (typeof value === "number") {
|
|
@@ -37915,26 +38049,26 @@ function formatFieldValue(value, fieldName) {
|
|
|
37915
38049
|
}
|
|
37916
38050
|
function renderRichFieldValue(value, fieldName, fieldType) {
|
|
37917
38051
|
if (value === void 0 || value === null) return "\u2014";
|
|
37918
|
-
const
|
|
38052
|
+
const str2 = String(value);
|
|
37919
38053
|
switch (fieldType) {
|
|
37920
38054
|
case "image":
|
|
37921
38055
|
case "url": {
|
|
37922
|
-
if (
|
|
38056
|
+
if (str2.match(/\.(png|jpe?g|gif|svg|webp|avif)(\?|$)/i) || str2.startsWith("data:image/")) {
|
|
37923
38057
|
return /* @__PURE__ */ jsx(Box, { className: "mt-1 max-w-full", children: /* @__PURE__ */ jsx(
|
|
37924
38058
|
"img",
|
|
37925
38059
|
{
|
|
37926
|
-
src:
|
|
38060
|
+
src: str2,
|
|
37927
38061
|
alt: formatFieldLabel(fieldName),
|
|
37928
38062
|
className: "max-w-full max-h-64 rounded-md object-contain",
|
|
37929
38063
|
loading: "lazy"
|
|
37930
38064
|
}
|
|
37931
38065
|
) });
|
|
37932
38066
|
}
|
|
37933
|
-
return
|
|
38067
|
+
return str2;
|
|
37934
38068
|
}
|
|
37935
38069
|
case "markdown":
|
|
37936
38070
|
case "richtext":
|
|
37937
|
-
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children:
|
|
38071
|
+
return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "break-words", children: str2 }), children: /* @__PURE__ */ jsx(
|
|
37938
38072
|
Box,
|
|
37939
38073
|
{
|
|
37940
38074
|
className: "prose prose-sm max-w-none",
|
|
@@ -37952,11 +38086,11 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
37952
38086
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
37953
38087
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
37954
38088
|
},
|
|
37955
|
-
children: /* @__PURE__ */ jsx(ReactMarkdown2, { children:
|
|
38089
|
+
children: /* @__PURE__ */ jsx(ReactMarkdown2, { children: str2 })
|
|
37956
38090
|
}
|
|
37957
38091
|
) });
|
|
37958
38092
|
case "code":
|
|
37959
|
-
return /* @__PURE__ */ jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsx("code", { children:
|
|
38093
|
+
return /* @__PURE__ */ jsx(Box, { className: "mt-1 rounded-md bg-muted p-3 overflow-x-auto", children: /* @__PURE__ */ jsx("pre", { className: "text-sm font-mono whitespace-pre-wrap break-words m-0", children: /* @__PURE__ */ jsx("code", { children: str2 }) }) });
|
|
37960
38094
|
case "html":
|
|
37961
38095
|
return /* @__PURE__ */ jsx(
|
|
37962
38096
|
Box,
|
|
@@ -37976,12 +38110,12 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
37976
38110
|
"--tw-prose-th-borders": "var(--color-border)",
|
|
37977
38111
|
"--tw-prose-td-borders": "var(--color-border)"
|
|
37978
38112
|
},
|
|
37979
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "body", children:
|
|
38113
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: str2 })
|
|
37980
38114
|
}
|
|
37981
38115
|
);
|
|
37982
38116
|
case "date":
|
|
37983
38117
|
case "datetime": {
|
|
37984
|
-
const d = new Date(
|
|
38118
|
+
const d = new Date(str2);
|
|
37985
38119
|
if (!isNaN(d.getTime())) {
|
|
37986
38120
|
return d.toLocaleDateString(void 0, {
|
|
37987
38121
|
year: "numeric",
|
|
@@ -37990,7 +38124,7 @@ function renderRichFieldValue(value, fieldName, fieldType) {
|
|
|
37990
38124
|
...fieldType === "datetime" ? { hour: "2-digit", minute: "2-digit" } : {}
|
|
37991
38125
|
});
|
|
37992
38126
|
}
|
|
37993
|
-
return
|
|
38127
|
+
return str2;
|
|
37994
38128
|
}
|
|
37995
38129
|
default:
|
|
37996
38130
|
return formatFieldValue(value, fieldName);
|
|
@@ -38668,6 +38802,40 @@ var init_RuleEditor = __esm({
|
|
|
38668
38802
|
RuleEditor.displayName = "RuleEditor";
|
|
38669
38803
|
}
|
|
38670
38804
|
});
|
|
38805
|
+
|
|
38806
|
+
// components/game/organisms/puzzles/event-handler/puzzleObject.ts
|
|
38807
|
+
function objId(o) {
|
|
38808
|
+
return o.id == null ? "" : String(o.id);
|
|
38809
|
+
}
|
|
38810
|
+
function objName(o) {
|
|
38811
|
+
return o.name == null ? "" : String(o.name);
|
|
38812
|
+
}
|
|
38813
|
+
function objIcon(o) {
|
|
38814
|
+
return o.icon == null ? "" : String(o.icon);
|
|
38815
|
+
}
|
|
38816
|
+
function objStates(o) {
|
|
38817
|
+
return Array.isArray(o.states) ? o.states : [];
|
|
38818
|
+
}
|
|
38819
|
+
function objCurrentState(o) {
|
|
38820
|
+
return o.currentState == null ? "" : String(o.currentState);
|
|
38821
|
+
}
|
|
38822
|
+
function objAvailableEvents(o) {
|
|
38823
|
+
return Array.isArray(o.availableEvents) ? o.availableEvents : [];
|
|
38824
|
+
}
|
|
38825
|
+
function objAvailableActions(o) {
|
|
38826
|
+
return Array.isArray(o.availableActions) ? o.availableActions : [];
|
|
38827
|
+
}
|
|
38828
|
+
function objRules(o) {
|
|
38829
|
+
return Array.isArray(o.rules) ? o.rules : [];
|
|
38830
|
+
}
|
|
38831
|
+
function objMaxRules(o) {
|
|
38832
|
+
const n = Number(o.maxRules);
|
|
38833
|
+
return Number.isFinite(n) && n > 0 ? n : 3;
|
|
38834
|
+
}
|
|
38835
|
+
var init_puzzleObject = __esm({
|
|
38836
|
+
"components/game/organisms/puzzles/event-handler/puzzleObject.ts"() {
|
|
38837
|
+
}
|
|
38838
|
+
});
|
|
38671
38839
|
function ObjectRulePanel({
|
|
38672
38840
|
object,
|
|
38673
38841
|
onRulesChange,
|
|
@@ -38675,55 +38843,63 @@ function ObjectRulePanel({
|
|
|
38675
38843
|
className
|
|
38676
38844
|
}) {
|
|
38677
38845
|
const { t } = useTranslate();
|
|
38678
|
-
const
|
|
38679
|
-
const
|
|
38846
|
+
const id = objId(object);
|
|
38847
|
+
const name = objName(object);
|
|
38848
|
+
const icon = objIcon(object);
|
|
38849
|
+
const states = objStates(object);
|
|
38850
|
+
const currentState = objCurrentState(object);
|
|
38851
|
+
const availableEvents = objAvailableEvents(object);
|
|
38852
|
+
const availableActions = objAvailableActions(object);
|
|
38853
|
+
const rules = objRules(object);
|
|
38854
|
+
const maxRules = objMaxRules(object);
|
|
38855
|
+
const canAdd = rules.length < maxRules;
|
|
38680
38856
|
const handleRuleChange = useCallback((index, updatedRule) => {
|
|
38681
|
-
const newRules = [...
|
|
38857
|
+
const newRules = [...rules];
|
|
38682
38858
|
newRules[index] = updatedRule;
|
|
38683
|
-
onRulesChange(
|
|
38684
|
-
}, [
|
|
38859
|
+
onRulesChange(id, newRules);
|
|
38860
|
+
}, [id, rules, onRulesChange]);
|
|
38685
38861
|
const handleRuleRemove = useCallback((index) => {
|
|
38686
|
-
const newRules =
|
|
38687
|
-
onRulesChange(
|
|
38688
|
-
}, [
|
|
38862
|
+
const newRules = rules.filter((_, i) => i !== index);
|
|
38863
|
+
onRulesChange(id, newRules);
|
|
38864
|
+
}, [id, rules, onRulesChange]);
|
|
38689
38865
|
const handleAddRule = useCallback(() => {
|
|
38690
38866
|
if (!canAdd || disabled) return;
|
|
38691
|
-
const firstEvent =
|
|
38692
|
-
const firstAction =
|
|
38867
|
+
const firstEvent = availableEvents[0]?.value || "";
|
|
38868
|
+
const firstAction = availableActions[0]?.value || "";
|
|
38693
38869
|
const newRule = {
|
|
38694
38870
|
id: `rule-${nextRuleId++}`,
|
|
38695
38871
|
whenEvent: firstEvent,
|
|
38696
38872
|
thenAction: firstAction
|
|
38697
38873
|
};
|
|
38698
|
-
onRulesChange(
|
|
38699
|
-
}, [canAdd, disabled,
|
|
38874
|
+
onRulesChange(id, [...rules, newRule]);
|
|
38875
|
+
}, [canAdd, disabled, id, rules, availableEvents, availableActions, onRulesChange]);
|
|
38700
38876
|
const machine = {
|
|
38701
|
-
name
|
|
38702
|
-
states
|
|
38703
|
-
currentState
|
|
38704
|
-
transitions:
|
|
38705
|
-
from:
|
|
38706
|
-
to:
|
|
38877
|
+
name,
|
|
38878
|
+
states,
|
|
38879
|
+
currentState,
|
|
38880
|
+
transitions: rules.map((r) => ({
|
|
38881
|
+
from: currentState,
|
|
38882
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38707
38883
|
event: r.whenEvent
|
|
38708
38884
|
}))
|
|
38709
38885
|
};
|
|
38710
38886
|
return /* @__PURE__ */ jsxs(VStack, { className: cn("p-4 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
38711
38887
|
/* @__PURE__ */ jsxs(HStack, { className: "items-center", gap: "sm", children: [
|
|
38712
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h5", children:
|
|
38888
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", children: icon }),
|
|
38713
38889
|
/* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
|
|
38714
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children:
|
|
38715
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " +
|
|
38890
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-bold", children: name }),
|
|
38891
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("eventHandler.state") + ": " + currentState })
|
|
38716
38892
|
] })
|
|
38717
38893
|
] }),
|
|
38718
38894
|
/* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" }),
|
|
38719
38895
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
38720
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count:
|
|
38721
|
-
|
|
38896
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.rules", { count: rules.length, max: maxRules }) + ":" }),
|
|
38897
|
+
rules.map((rule, i) => /* @__PURE__ */ jsx(
|
|
38722
38898
|
RuleEditor,
|
|
38723
38899
|
{
|
|
38724
38900
|
rule,
|
|
38725
|
-
availableEvents
|
|
38726
|
-
availableActions
|
|
38901
|
+
availableEvents,
|
|
38902
|
+
availableActions,
|
|
38727
38903
|
onChange: (r) => handleRuleChange(i, r),
|
|
38728
38904
|
onRemove: () => handleRuleRemove(i),
|
|
38729
38905
|
disabled
|
|
@@ -38741,6 +38917,7 @@ var init_ObjectRulePanel = __esm({
|
|
|
38741
38917
|
init_cn();
|
|
38742
38918
|
init_TraitStateViewer();
|
|
38743
38919
|
init_RuleEditor();
|
|
38920
|
+
init_puzzleObject();
|
|
38744
38921
|
nextRuleId = 1;
|
|
38745
38922
|
ObjectRulePanel.displayName = "ObjectRulePanel";
|
|
38746
38923
|
}
|
|
@@ -38807,11 +38984,11 @@ function EventHandlerBoard({
|
|
|
38807
38984
|
}) {
|
|
38808
38985
|
const { emit } = useEventBus();
|
|
38809
38986
|
const { t } = useTranslate();
|
|
38810
|
-
const resolved =
|
|
38811
|
-
const entityObjects = resolved?.objects
|
|
38812
|
-
const [objects, setObjects] = useState(entityObjects);
|
|
38987
|
+
const resolved = boardEntity(entity);
|
|
38988
|
+
const entityObjects = rows(resolved?.objects);
|
|
38989
|
+
const [objects, setObjects] = useState(() => [...entityObjects]);
|
|
38813
38990
|
const [selectedObjectId, setSelectedObjectId] = useState(
|
|
38814
|
-
entityObjects[0]
|
|
38991
|
+
entityObjects[0] ? objId(entityObjects[0]) : null
|
|
38815
38992
|
);
|
|
38816
38993
|
const [headerError, setHeaderError] = useState(false);
|
|
38817
38994
|
const [playState, setPlayState] = useState("editing");
|
|
@@ -38822,10 +38999,10 @@ function EventHandlerBoard({
|
|
|
38822
38999
|
useEffect(() => () => {
|
|
38823
39000
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38824
39001
|
}, []);
|
|
38825
|
-
const selectedObject = objects.find((o) => o
|
|
39002
|
+
const selectedObject = objects.find((o) => objId(o) === selectedObjectId) || null;
|
|
38826
39003
|
const handleRulesChange = useCallback((objectId, rules) => {
|
|
38827
39004
|
setObjects((prev) => prev.map(
|
|
38828
|
-
(o) => o
|
|
39005
|
+
(o) => objId(o) === objectId ? { ...o, rules } : o
|
|
38829
39006
|
));
|
|
38830
39007
|
}, []);
|
|
38831
39008
|
const addLogEntry = useCallback((icon, message, status = "done") => {
|
|
@@ -38839,11 +39016,12 @@ function EventHandlerBoard({
|
|
|
38839
39016
|
setEventLog([]);
|
|
38840
39017
|
const allRules = [];
|
|
38841
39018
|
objects.forEach((obj) => {
|
|
38842
|
-
obj.
|
|
39019
|
+
objRules(obj).forEach((rule) => {
|
|
38843
39020
|
allRules.push({ object: obj, rule });
|
|
38844
39021
|
});
|
|
38845
39022
|
});
|
|
38846
|
-
const triggers = resolved?.triggerEvents
|
|
39023
|
+
const triggers = Array.isArray(resolved?.triggerEvents) ? resolved.triggerEvents : [];
|
|
39024
|
+
const goalEvent = str(resolved?.goalEvent);
|
|
38847
39025
|
const eventQueue = [...triggers];
|
|
38848
39026
|
const firedEvents = /* @__PURE__ */ new Set();
|
|
38849
39027
|
let stepIdx = 0;
|
|
@@ -38872,14 +39050,14 @@ function EventHandlerBoard({
|
|
|
38872
39050
|
addLogEntry("\u26A1", t("eventHandler.noListeners", { event: currentEvent }), "done");
|
|
38873
39051
|
} else {
|
|
38874
39052
|
matching.forEach(({ object, rule }) => {
|
|
38875
|
-
addLogEntry(object
|
|
39053
|
+
addLogEntry(objIcon(object), t("eventHandler.heardEvent", { object: objName(object), event: currentEvent, action: rule.thenAction }), "done");
|
|
38876
39054
|
eventQueue.push(rule.thenAction);
|
|
38877
|
-
if (rule.thenAction ===
|
|
39055
|
+
if (rule.thenAction === goalEvent) {
|
|
38878
39056
|
goalReached = true;
|
|
38879
39057
|
}
|
|
38880
39058
|
});
|
|
38881
39059
|
}
|
|
38882
|
-
if (currentEvent ===
|
|
39060
|
+
if (currentEvent === goalEvent) {
|
|
38883
39061
|
goalReached = true;
|
|
38884
39062
|
}
|
|
38885
39063
|
stepIdx++;
|
|
@@ -38897,65 +39075,75 @@ function EventHandlerBoard({
|
|
|
38897
39075
|
}, []);
|
|
38898
39076
|
const handleReset = useCallback(() => {
|
|
38899
39077
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
38900
|
-
|
|
39078
|
+
const resetObjects = rows(resolved?.objects);
|
|
39079
|
+
setObjects([...resetObjects]);
|
|
38901
39080
|
setPlayState("editing");
|
|
38902
39081
|
setEventLog([]);
|
|
38903
|
-
setSelectedObjectId(
|
|
39082
|
+
setSelectedObjectId(resetObjects[0] ? objId(resetObjects[0]) : null);
|
|
38904
39083
|
setAttempts(0);
|
|
38905
39084
|
}, [resolved?.objects]);
|
|
38906
39085
|
if (!resolved) return null;
|
|
38907
39086
|
const objectViewers = objects.map((obj) => {
|
|
39087
|
+
const states = objStates(obj);
|
|
39088
|
+
const currentState = objCurrentState(obj);
|
|
38908
39089
|
const machine = {
|
|
38909
|
-
name: obj
|
|
38910
|
-
states
|
|
38911
|
-
currentState
|
|
38912
|
-
transitions: obj.
|
|
38913
|
-
from:
|
|
38914
|
-
to:
|
|
39090
|
+
name: objName(obj),
|
|
39091
|
+
states,
|
|
39092
|
+
currentState,
|
|
39093
|
+
transitions: objRules(obj).map((r) => ({
|
|
39094
|
+
from: currentState,
|
|
39095
|
+
to: states.find((s) => s !== currentState) || currentState,
|
|
38915
39096
|
event: r.whenEvent
|
|
38916
39097
|
}))
|
|
38917
39098
|
};
|
|
38918
39099
|
return { obj, machine };
|
|
38919
39100
|
});
|
|
38920
|
-
const
|
|
39101
|
+
const hint = str(resolved.hint);
|
|
39102
|
+
const showHint = attempts >= 3 && hint;
|
|
39103
|
+
const theme = resolved.theme ?? void 0;
|
|
39104
|
+
const themeBackground = theme?.background;
|
|
39105
|
+
const headerImage = str(resolved.headerImage);
|
|
38921
39106
|
const encourageKey = ENCOURAGEMENT_KEYS[Math.min(attempts - 1, ENCOURAGEMENT_KEYS.length - 1)] ?? ENCOURAGEMENT_KEYS[0];
|
|
38922
39107
|
return /* @__PURE__ */ jsxs(
|
|
38923
39108
|
VStack,
|
|
38924
39109
|
{
|
|
38925
39110
|
className: cn("p-4 gap-6", className),
|
|
38926
39111
|
style: {
|
|
38927
|
-
backgroundImage:
|
|
39112
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
38928
39113
|
backgroundSize: "cover",
|
|
38929
39114
|
backgroundPosition: "center"
|
|
38930
39115
|
},
|
|
38931
39116
|
children: [
|
|
38932
|
-
|
|
39117
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
38933
39118
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
38934
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
38935
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
39119
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
39120
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
38936
39121
|
/* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
|
|
38937
39122
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
|
|
38938
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: resolved.goalCondition })
|
|
39123
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: str(resolved.goalCondition) })
|
|
38939
39124
|
] })
|
|
38940
39125
|
] }),
|
|
38941
39126
|
/* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
38942
39127
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
|
|
38943
|
-
/* @__PURE__ */ jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) =>
|
|
38944
|
-
|
|
38945
|
-
|
|
38946
|
-
|
|
38947
|
-
|
|
38948
|
-
|
|
38949
|
-
|
|
38950
|
-
|
|
38951
|
-
|
|
38952
|
-
|
|
38953
|
-
/* @__PURE__ */
|
|
38954
|
-
|
|
38955
|
-
|
|
38956
|
-
|
|
38957
|
-
|
|
38958
|
-
|
|
39128
|
+
/* @__PURE__ */ jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => {
|
|
39129
|
+
const oid = objId(obj);
|
|
39130
|
+
return /* @__PURE__ */ jsx(
|
|
39131
|
+
Box,
|
|
39132
|
+
{
|
|
39133
|
+
className: cn(
|
|
39134
|
+
"p-3 rounded-container border-2 cursor-pointer transition-all hover:scale-105",
|
|
39135
|
+
selectedObjectId === oid ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
|
|
39136
|
+
),
|
|
39137
|
+
onClick: () => setSelectedObjectId(oid),
|
|
39138
|
+
children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
|
|
39139
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h5", children: objIcon(obj) }),
|
|
39140
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: objName(obj) }),
|
|
39141
|
+
/* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
|
|
39142
|
+
] })
|
|
39143
|
+
},
|
|
39144
|
+
oid
|
|
39145
|
+
);
|
|
39146
|
+
}) })
|
|
38959
39147
|
] }),
|
|
38960
39148
|
selectedObject && /* @__PURE__ */ jsx(
|
|
38961
39149
|
ObjectRulePanel,
|
|
@@ -38966,12 +39154,12 @@ function EventHandlerBoard({
|
|
|
38966
39154
|
}
|
|
38967
39155
|
),
|
|
38968
39156
|
eventLog.length > 0 && /* @__PURE__ */ jsx(EventLog, { entries: eventLog }),
|
|
38969
|
-
playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("eventHandler.chainComplete") }) }),
|
|
39157
|
+
playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("eventHandler.chainComplete") }) }),
|
|
38970
39158
|
playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
38971
39159
|
/* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
|
|
38972
39160
|
showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
38973
39161
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
38974
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
39162
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
38975
39163
|
] }) })
|
|
38976
39164
|
] }),
|
|
38977
39165
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
|
|
@@ -38999,6 +39187,8 @@ var init_EventHandlerBoard = __esm({
|
|
|
38999
39187
|
init_TraitStateViewer();
|
|
39000
39188
|
init_ObjectRulePanel();
|
|
39001
39189
|
init_EventLog();
|
|
39190
|
+
init_puzzleObject();
|
|
39191
|
+
init_boardEntity();
|
|
39002
39192
|
ENCOURAGEMENT_KEYS = [
|
|
39003
39193
|
"puzzle.tryAgain1",
|
|
39004
39194
|
"puzzle.tryAgain2",
|
|
@@ -39087,7 +39277,10 @@ var init_FeatureGridOrganism = __esm({
|
|
|
39087
39277
|
);
|
|
39088
39278
|
useCallback(
|
|
39089
39279
|
(feature) => {
|
|
39090
|
-
eventBus.emit("UI:FEATURE_CLICK", {
|
|
39280
|
+
eventBus.emit("UI:FEATURE_CLICK", {
|
|
39281
|
+
id: String(feature.id ?? ""),
|
|
39282
|
+
href: String(feature.href ?? "")
|
|
39283
|
+
});
|
|
39091
39284
|
},
|
|
39092
39285
|
[eventBus]
|
|
39093
39286
|
);
|
|
@@ -39097,14 +39290,17 @@ var init_FeatureGridOrganism = __esm({
|
|
|
39097
39290
|
if (error) {
|
|
39098
39291
|
return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
|
|
39099
39292
|
}
|
|
39100
|
-
const featureCards = items.map((feature) =>
|
|
39101
|
-
|
|
39102
|
-
|
|
39103
|
-
|
|
39104
|
-
|
|
39105
|
-
|
|
39106
|
-
|
|
39107
|
-
|
|
39293
|
+
const featureCards = items.map((feature) => {
|
|
39294
|
+
const href = feature.href != null ? String(feature.href) : void 0;
|
|
39295
|
+
return {
|
|
39296
|
+
icon: feature.icon != null ? String(feature.icon) : void 0,
|
|
39297
|
+
title: String(feature.title ?? ""),
|
|
39298
|
+
description: String(feature.description ?? ""),
|
|
39299
|
+
href,
|
|
39300
|
+
linkLabel: feature.linkLabel != null ? String(feature.linkLabel) : void 0,
|
|
39301
|
+
variant: href ? "interactive" : "bordered"
|
|
39302
|
+
};
|
|
39303
|
+
});
|
|
39108
39304
|
return /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
39109
39305
|
(heading || subtitle) && /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
39110
39306
|
heading && /* @__PURE__ */ jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
@@ -40422,22 +40618,24 @@ var init_HeroOrganism = __esm({
|
|
|
40422
40618
|
() => Array.isArray(entity) ? entity[0] : entity && typeof entity === "object" ? entity : void 0,
|
|
40423
40619
|
[entity]
|
|
40424
40620
|
);
|
|
40621
|
+
const primaryAction = resolved?.primaryAction;
|
|
40622
|
+
const secondaryAction = resolved?.secondaryAction;
|
|
40425
40623
|
const handlePrimaryClick = useCallback(() => {
|
|
40426
|
-
if (
|
|
40624
|
+
if (primaryAction) {
|
|
40427
40625
|
eventBus.emit("UI:CTA_PRIMARY", {
|
|
40428
|
-
label:
|
|
40429
|
-
href:
|
|
40626
|
+
label: String(primaryAction.label ?? ""),
|
|
40627
|
+
href: String(primaryAction.href ?? "")
|
|
40430
40628
|
});
|
|
40431
40629
|
}
|
|
40432
|
-
}, [eventBus,
|
|
40630
|
+
}, [eventBus, primaryAction]);
|
|
40433
40631
|
const handleSecondaryClick = useCallback(() => {
|
|
40434
|
-
if (
|
|
40632
|
+
if (secondaryAction) {
|
|
40435
40633
|
eventBus.emit("UI:CTA_SECONDARY", {
|
|
40436
|
-
label:
|
|
40437
|
-
href:
|
|
40634
|
+
label: String(secondaryAction.label ?? ""),
|
|
40635
|
+
href: String(secondaryAction.href ?? "")
|
|
40438
40636
|
});
|
|
40439
40637
|
}
|
|
40440
|
-
}, [eventBus,
|
|
40638
|
+
}, [eventBus, secondaryAction]);
|
|
40441
40639
|
if (isLoading) {
|
|
40442
40640
|
return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
|
|
40443
40641
|
}
|
|
@@ -40447,17 +40645,19 @@ var init_HeroOrganism = __esm({
|
|
|
40447
40645
|
if (!resolved) {
|
|
40448
40646
|
return null;
|
|
40449
40647
|
}
|
|
40648
|
+
const imageRaw = resolved.image;
|
|
40649
|
+
const image = imageRaw ? { src: String(imageRaw.src ?? ""), alt: String(imageRaw.alt ?? "") } : void 0;
|
|
40450
40650
|
return /* @__PURE__ */ jsxs(
|
|
40451
40651
|
HeroSection,
|
|
40452
40652
|
{
|
|
40453
|
-
tag: resolved.tag,
|
|
40454
|
-
title: resolved.title,
|
|
40455
|
-
titleAccent: resolved.titleAccent,
|
|
40456
|
-
subtitle: resolved.subtitle,
|
|
40457
|
-
primaryAction:
|
|
40458
|
-
secondaryAction:
|
|
40459
|
-
installCommand: resolved.installCommand,
|
|
40460
|
-
image
|
|
40653
|
+
tag: resolved.tag != null ? String(resolved.tag) : void 0,
|
|
40654
|
+
title: String(resolved.title ?? ""),
|
|
40655
|
+
titleAccent: resolved.titleAccent != null ? String(resolved.titleAccent) : void 0,
|
|
40656
|
+
subtitle: String(resolved.subtitle ?? ""),
|
|
40657
|
+
primaryAction: primaryAction ? { label: String(primaryAction.label ?? ""), href: String(primaryAction.href ?? "") } : void 0,
|
|
40658
|
+
secondaryAction: secondaryAction ? { label: String(secondaryAction.label ?? ""), href: String(secondaryAction.href ?? "") } : void 0,
|
|
40659
|
+
installCommand: resolved.installCommand != null ? String(resolved.installCommand) : void 0,
|
|
40660
|
+
image,
|
|
40461
40661
|
imagePosition: resolved.imagePosition,
|
|
40462
40662
|
background: resolved.background,
|
|
40463
40663
|
className: cn(className),
|
|
@@ -40466,8 +40666,8 @@ var init_HeroOrganism = __esm({
|
|
|
40466
40666
|
/* @__PURE__ */ jsx(
|
|
40467
40667
|
_HeroClickInterceptor,
|
|
40468
40668
|
{
|
|
40469
|
-
hasPrimary: !!
|
|
40470
|
-
hasSecondary: !!
|
|
40669
|
+
hasPrimary: !!primaryAction,
|
|
40670
|
+
hasSecondary: !!secondaryAction,
|
|
40471
40671
|
onPrimaryClick: handlePrimaryClick,
|
|
40472
40672
|
onSecondaryClick: handleSecondaryClick
|
|
40473
40673
|
}
|
|
@@ -40696,7 +40896,7 @@ function formatValue3(value, fieldName) {
|
|
|
40696
40896
|
return String(value);
|
|
40697
40897
|
}
|
|
40698
40898
|
function formatFieldLabel2(fieldName) {
|
|
40699
|
-
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (
|
|
40899
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str2) => str2.toUpperCase()).replace(/Id$/, "").trim();
|
|
40700
40900
|
}
|
|
40701
40901
|
var STATUS_STYLES2, StatusBadge, ProgressIndicator, List3;
|
|
40702
40902
|
var init_List = __esm({
|
|
@@ -41543,20 +41743,22 @@ function NegotiatorBoard({
|
|
|
41543
41743
|
}) {
|
|
41544
41744
|
const { emit } = useEventBus();
|
|
41545
41745
|
const { t } = useTranslate();
|
|
41546
|
-
const resolved =
|
|
41746
|
+
const resolved = boardEntity(entity);
|
|
41547
41747
|
const [history, setHistory] = useState([]);
|
|
41548
41748
|
const [headerError, setHeaderError] = useState(false);
|
|
41549
41749
|
const [showHint, setShowHint] = useState(false);
|
|
41750
|
+
const totalRounds = num(resolved?.totalRounds);
|
|
41751
|
+
const targetScore = num(resolved?.targetScore);
|
|
41550
41752
|
const currentRound = history.length;
|
|
41551
|
-
const isComplete = currentRound >=
|
|
41753
|
+
const isComplete = currentRound >= totalRounds;
|
|
41552
41754
|
const playerTotal = history.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41553
41755
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
41554
|
-
const won = isComplete && playerTotal >=
|
|
41555
|
-
const actions = resolved?.actions
|
|
41556
|
-
const payoffMatrix = resolved?.payoffMatrix
|
|
41756
|
+
const won = isComplete && playerTotal >= targetScore;
|
|
41757
|
+
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
41758
|
+
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
41557
41759
|
const handleAction = useCallback((actionId) => {
|
|
41558
41760
|
if (isComplete) return;
|
|
41559
|
-
const opponentAction = getOpponentAction(resolved?.opponentStrategy
|
|
41761
|
+
const opponentAction = getOpponentAction(str(resolved?.opponentStrategy) || "random", actions, history);
|
|
41560
41762
|
const payoff = payoffMatrix.find(
|
|
41561
41763
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
41562
41764
|
);
|
|
@@ -41569,42 +41771,46 @@ function NegotiatorBoard({
|
|
|
41569
41771
|
};
|
|
41570
41772
|
const newHistory = [...history, result];
|
|
41571
41773
|
setHistory(newHistory);
|
|
41572
|
-
if (newHistory.length >=
|
|
41774
|
+
if (newHistory.length >= totalRounds) {
|
|
41573
41775
|
const total = newHistory.reduce((s, r) => s + r.playerPayoff, 0);
|
|
41574
|
-
if (total >=
|
|
41776
|
+
if (total >= targetScore) {
|
|
41575
41777
|
emit(`UI:${completeEvent}`, { success: true, score: total });
|
|
41576
41778
|
}
|
|
41577
|
-
if (newHistory.length >= 3 && resolved?.hint) {
|
|
41779
|
+
if (newHistory.length >= 3 && str(resolved?.hint)) {
|
|
41578
41780
|
setShowHint(true);
|
|
41579
41781
|
}
|
|
41580
41782
|
}
|
|
41581
|
-
}, [isComplete, resolved, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41783
|
+
}, [isComplete, resolved, totalRounds, targetScore, actions, payoffMatrix, history, currentRound, completeEvent, emit]);
|
|
41582
41784
|
const handleReset = () => {
|
|
41583
41785
|
setHistory([]);
|
|
41584
41786
|
setShowHint(false);
|
|
41585
41787
|
};
|
|
41586
41788
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
41587
41789
|
if (!resolved) return null;
|
|
41790
|
+
const theme = resolved.theme ?? void 0;
|
|
41791
|
+
const themeBackground = theme?.background;
|
|
41792
|
+
const headerImage = str(resolved.headerImage);
|
|
41793
|
+
const hint = str(resolved.hint);
|
|
41588
41794
|
return /* @__PURE__ */ jsx(
|
|
41589
41795
|
Box,
|
|
41590
41796
|
{
|
|
41591
41797
|
className,
|
|
41592
41798
|
style: {
|
|
41593
|
-
backgroundImage:
|
|
41799
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
41594
41800
|
backgroundSize: "cover",
|
|
41595
41801
|
backgroundPosition: "center"
|
|
41596
41802
|
},
|
|
41597
41803
|
children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
41598
|
-
|
|
41804
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
41599
41805
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
41600
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
41601
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description }),
|
|
41806
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
41807
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) }),
|
|
41602
41808
|
/* @__PURE__ */ jsxs(HStack, { gap: "md", children: [
|
|
41603
|
-
/* @__PURE__ */ jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(
|
|
41809
|
+
/* @__PURE__ */ jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(totalRounds) }) }),
|
|
41604
41810
|
/* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
|
|
41605
41811
|
t("negotiator.target"),
|
|
41606
41812
|
": ",
|
|
41607
|
-
|
|
41813
|
+
targetScore
|
|
41608
41814
|
] })
|
|
41609
41815
|
] })
|
|
41610
41816
|
] }) }),
|
|
@@ -41653,16 +41859,16 @@ function NegotiatorBoard({
|
|
|
41653
41859
|
] }) }),
|
|
41654
41860
|
isComplete && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
41655
41861
|
/* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: won ? "text-success" : "text-error" }),
|
|
41656
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: won ? resolved.successMessage
|
|
41862
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: won ? str(resolved.successMessage) || t("negotiator.success") : str(resolved.failMessage) || t("negotiator.failed") }),
|
|
41657
41863
|
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
41658
41864
|
t("negotiator.finalScore"),
|
|
41659
41865
|
": ",
|
|
41660
41866
|
playerTotal,
|
|
41661
41867
|
"/",
|
|
41662
|
-
|
|
41868
|
+
targetScore
|
|
41663
41869
|
] })
|
|
41664
41870
|
] }) }),
|
|
41665
|
-
showHint &&
|
|
41871
|
+
showHint && hint && !won && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
41666
41872
|
isComplete && !won && /* @__PURE__ */ jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
|
|
41667
41873
|
] })
|
|
41668
41874
|
}
|
|
@@ -41672,6 +41878,7 @@ var init_NegotiatorBoard = __esm({
|
|
|
41672
41878
|
"components/game/organisms/puzzles/negotiator/NegotiatorBoard.tsx"() {
|
|
41673
41879
|
init_atoms2();
|
|
41674
41880
|
init_useEventBus();
|
|
41881
|
+
init_boardEntity();
|
|
41675
41882
|
NegotiatorBoard.displayName = "NegotiatorBoard";
|
|
41676
41883
|
}
|
|
41677
41884
|
});
|
|
@@ -41707,13 +41914,13 @@ var init_PricingOrganism = __esm({
|
|
|
41707
41914
|
return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
|
|
41708
41915
|
}
|
|
41709
41916
|
const plans = items.map((plan) => ({
|
|
41710
|
-
name: plan.name,
|
|
41711
|
-
price: plan.price,
|
|
41712
|
-
description: plan.description,
|
|
41713
|
-
features: plan.features,
|
|
41714
|
-
action: { label: plan.actionLabel, href: plan.actionHref },
|
|
41715
|
-
highlighted: plan.highlighted,
|
|
41716
|
-
badge: plan.badge
|
|
41917
|
+
name: String(plan.name ?? ""),
|
|
41918
|
+
price: String(plan.price ?? ""),
|
|
41919
|
+
description: plan.description != null ? String(plan.description) : void 0,
|
|
41920
|
+
features: (plan.features ?? []).map((f3) => String(f3)),
|
|
41921
|
+
action: { label: String(plan.actionLabel ?? ""), href: String(plan.actionHref ?? "") },
|
|
41922
|
+
highlighted: Boolean(plan.highlighted),
|
|
41923
|
+
badge: plan.badge != null ? String(plan.badge) : void 0
|
|
41717
41924
|
}));
|
|
41718
41925
|
return /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
41719
41926
|
(heading || subtitle) && /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -43784,16 +43991,20 @@ function SequencerBoard({
|
|
|
43784
43991
|
}) {
|
|
43785
43992
|
const { emit } = useEventBus();
|
|
43786
43993
|
const { t } = useTranslate();
|
|
43787
|
-
const resolved =
|
|
43994
|
+
const resolved = boardEntity(entity);
|
|
43995
|
+
const maxSlots = num(resolved?.maxSlots);
|
|
43996
|
+
const solutions = Array.isArray(resolved?.solutions) ? resolved.solutions : [];
|
|
43997
|
+
const availableActions = Array.isArray(resolved?.availableActions) ? resolved.availableActions : [];
|
|
43998
|
+
const allowDuplicates = resolved?.allowDuplicates !== false;
|
|
43788
43999
|
const [headerError, setHeaderError] = useState(false);
|
|
43789
44000
|
const [slots, setSlots] = useState(
|
|
43790
|
-
() => Array.from({ length:
|
|
44001
|
+
() => Array.from({ length: maxSlots }, () => void 0)
|
|
43791
44002
|
);
|
|
43792
44003
|
const [playState, setPlayState] = useState("idle");
|
|
43793
44004
|
const [currentStep, setCurrentStep] = useState(-1);
|
|
43794
44005
|
const [attempts, setAttempts] = useState(0);
|
|
43795
44006
|
const [slotFeedback, setSlotFeedback] = useState(
|
|
43796
|
-
() => Array.from({ length:
|
|
44007
|
+
() => Array.from({ length: maxSlots }, () => null)
|
|
43797
44008
|
);
|
|
43798
44009
|
const timerRef = useRef(null);
|
|
43799
44010
|
useEffect(() => () => {
|
|
@@ -43827,17 +44038,17 @@ function SequencerBoard({
|
|
|
43827
44038
|
}, [emit]);
|
|
43828
44039
|
const handleReset = useCallback(() => {
|
|
43829
44040
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
43830
|
-
setSlots(Array.from({ length:
|
|
44041
|
+
setSlots(Array.from({ length: maxSlots }, () => void 0));
|
|
43831
44042
|
setPlayState("idle");
|
|
43832
44043
|
setCurrentStep(-1);
|
|
43833
44044
|
setAttempts(0);
|
|
43834
|
-
setSlotFeedback(Array.from({ length:
|
|
43835
|
-
}, [
|
|
44045
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
44046
|
+
}, [maxSlots]);
|
|
43836
44047
|
const filledSlots = slots.filter((s) => !!s);
|
|
43837
44048
|
const canPlay = filledSlots.length > 0 && playState === "idle";
|
|
43838
44049
|
const handlePlay = useCallback(() => {
|
|
43839
44050
|
if (!canPlay) return;
|
|
43840
|
-
setSlotFeedback(Array.from({ length:
|
|
44051
|
+
setSlotFeedback(Array.from({ length: maxSlots }, () => null));
|
|
43841
44052
|
emit("UI:PLAY_SOUND", { key: "confirm" });
|
|
43842
44053
|
const sequence = slots.map((s) => s?.id || "");
|
|
43843
44054
|
if (playEvent) {
|
|
@@ -43848,10 +44059,10 @@ function SequencerBoard({
|
|
|
43848
44059
|
let step = 0;
|
|
43849
44060
|
const advance = () => {
|
|
43850
44061
|
step++;
|
|
43851
|
-
if (step >=
|
|
44062
|
+
if (step >= maxSlots) {
|
|
43852
44063
|
const playerSeq = slots.map((s) => s?.id);
|
|
43853
44064
|
const playerIds = slots.filter(Boolean).map((s) => s?.id || "");
|
|
43854
|
-
const success =
|
|
44065
|
+
const success = solutions.some(
|
|
43855
44066
|
(sol) => sol.length === playerIds.length && sol.every((id, i) => id === playerIds[i])
|
|
43856
44067
|
);
|
|
43857
44068
|
if (success) {
|
|
@@ -43863,7 +44074,7 @@ function SequencerBoard({
|
|
|
43863
44074
|
}
|
|
43864
44075
|
} else {
|
|
43865
44076
|
setAttempts((prev) => prev + 1);
|
|
43866
|
-
const feedback = computeSlotFeedback(playerSeq,
|
|
44077
|
+
const feedback = computeSlotFeedback(playerSeq, solutions);
|
|
43867
44078
|
setSlotFeedback(feedback);
|
|
43868
44079
|
setPlayState("idle");
|
|
43869
44080
|
setCurrentStep(-1);
|
|
@@ -43881,10 +44092,10 @@ function SequencerBoard({
|
|
|
43881
44092
|
}
|
|
43882
44093
|
};
|
|
43883
44094
|
timerRef.current = setTimeout(advance, stepDurationMs);
|
|
43884
|
-
}, [canPlay, slots,
|
|
44095
|
+
}, [canPlay, slots, maxSlots, solutions, stepDurationMs, playEvent, completeEvent, emit]);
|
|
43885
44096
|
const machine = {
|
|
43886
|
-
name: resolved?.title
|
|
43887
|
-
description: resolved?.description
|
|
44097
|
+
name: str(resolved?.title),
|
|
44098
|
+
description: str(resolved?.description),
|
|
43888
44099
|
states: slots.map((s, i) => stepLabel(s, i)),
|
|
43889
44100
|
currentState: currentStep >= 0 ? stepLabel(slots[currentStep], currentStep) : "__idle__",
|
|
43890
44101
|
transitions: slots.slice(0, -1).map((s, i) => ({
|
|
@@ -43893,37 +44104,41 @@ function SequencerBoard({
|
|
|
43893
44104
|
event: "NEXT"
|
|
43894
44105
|
}))
|
|
43895
44106
|
};
|
|
43896
|
-
const usedIds =
|
|
43897
|
-
const
|
|
44107
|
+
const usedIds = !allowDuplicates ? slots.filter(Boolean).map((s) => s?.id || "") : [];
|
|
44108
|
+
const hint = str(resolved?.hint);
|
|
44109
|
+
const showHint = attempts >= 3 && !!hint;
|
|
43898
44110
|
const hasFeedback = slotFeedback.some((f3) => f3 !== null);
|
|
43899
44111
|
const correctCount = slotFeedback.filter((f3) => f3 === "correct").length;
|
|
43900
44112
|
const encourageKey = ENCOURAGEMENT_KEYS2[Math.min(attempts - 1, ENCOURAGEMENT_KEYS2.length - 1)] ?? ENCOURAGEMENT_KEYS2[0];
|
|
43901
44113
|
if (!resolved) return null;
|
|
44114
|
+
const theme = resolved.theme ?? void 0;
|
|
44115
|
+
const themeBackground = theme?.background;
|
|
44116
|
+
const headerImage = str(resolved.headerImage);
|
|
43902
44117
|
return /* @__PURE__ */ jsxs(
|
|
43903
44118
|
VStack,
|
|
43904
44119
|
{
|
|
43905
44120
|
className: cn("p-4 gap-6", className),
|
|
43906
44121
|
style: {
|
|
43907
|
-
backgroundImage:
|
|
44122
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
43908
44123
|
backgroundSize: "cover",
|
|
43909
44124
|
backgroundPosition: "center"
|
|
43910
44125
|
},
|
|
43911
44126
|
children: [
|
|
43912
|
-
|
|
44127
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
43913
44128
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
43914
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
43915
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description })
|
|
44129
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
44130
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) })
|
|
43916
44131
|
] }),
|
|
43917
44132
|
showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
43918
44133
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
43919
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
44134
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
43920
44135
|
] }) }),
|
|
43921
44136
|
filledSlots.length > 0 && /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
|
|
43922
44137
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
43923
44138
|
/* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
|
|
43924
44139
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
|
|
43925
44140
|
hasFeedback && playState === "idle" && /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
43926
|
-
`${correctCount}/${
|
|
44141
|
+
`${correctCount}/${maxSlots} `,
|
|
43927
44142
|
"\u2705"
|
|
43928
44143
|
] })
|
|
43929
44144
|
] }),
|
|
@@ -43931,7 +44146,7 @@ function SequencerBoard({
|
|
|
43931
44146
|
SequenceBar,
|
|
43932
44147
|
{
|
|
43933
44148
|
slots,
|
|
43934
|
-
maxSlots
|
|
44149
|
+
maxSlots,
|
|
43935
44150
|
onSlotDrop: handleSlotDrop,
|
|
43936
44151
|
onSlotRemove: handleSlotRemove,
|
|
43937
44152
|
playing: playState === "playing",
|
|
@@ -43945,15 +44160,15 @@ function SequencerBoard({
|
|
|
43945
44160
|
playState !== "playing" && /* @__PURE__ */ jsx(
|
|
43946
44161
|
ActionPalette,
|
|
43947
44162
|
{
|
|
43948
|
-
actions:
|
|
44163
|
+
actions: availableActions,
|
|
43949
44164
|
usedActionIds: usedIds,
|
|
43950
|
-
allowDuplicates
|
|
44165
|
+
allowDuplicates,
|
|
43951
44166
|
categoryColors,
|
|
43952
44167
|
label: t("sequencer.dragActions")
|
|
43953
44168
|
}
|
|
43954
44169
|
),
|
|
43955
44170
|
hasFeedback && playState === "idle" && attempts > 0 && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
|
|
43956
|
-
playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("sequencer.levelComplete") }) }),
|
|
44171
|
+
playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("sequencer.levelComplete") }) }),
|
|
43957
44172
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
|
|
43958
44173
|
/* @__PURE__ */ jsx(
|
|
43959
44174
|
Button,
|
|
@@ -43977,6 +44192,7 @@ var init_SequencerBoard = __esm({
|
|
|
43977
44192
|
init_cn();
|
|
43978
44193
|
init_useEventBus();
|
|
43979
44194
|
init_TraitStateViewer();
|
|
44195
|
+
init_boardEntity();
|
|
43980
44196
|
init_SequenceBar();
|
|
43981
44197
|
init_ActionPalette();
|
|
43982
44198
|
ENCOURAGEMENT_KEYS2 = [
|
|
@@ -44026,18 +44242,21 @@ var init_ShowcaseOrganism = __esm({
|
|
|
44026
44242
|
heading && /* @__PURE__ */ jsx(Typography, { variant: "h2", align: "center", children: heading }),
|
|
44027
44243
|
subtitle && /* @__PURE__ */ jsx(Typography, { variant: "body1", color: "muted", align: "center", className: "max-w-2xl", children: subtitle })
|
|
44028
44244
|
] }),
|
|
44029
|
-
/* @__PURE__ */ jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) =>
|
|
44030
|
-
|
|
44031
|
-
|
|
44032
|
-
|
|
44033
|
-
|
|
44034
|
-
|
|
44035
|
-
|
|
44036
|
-
|
|
44037
|
-
|
|
44038
|
-
|
|
44039
|
-
|
|
44040
|
-
|
|
44245
|
+
/* @__PURE__ */ jsx(SimpleGrid, { cols: columns, gap: "lg", children: items.map((item) => {
|
|
44246
|
+
const imageRaw = item.image;
|
|
44247
|
+
return /* @__PURE__ */ jsx(
|
|
44248
|
+
ShowcaseCard,
|
|
44249
|
+
{
|
|
44250
|
+
title: String(item.title ?? ""),
|
|
44251
|
+
description: item.description != null ? String(item.description) : void 0,
|
|
44252
|
+
image: { src: String(imageRaw?.src ?? ""), alt: String(imageRaw?.alt ?? "") },
|
|
44253
|
+
href: item.href != null ? String(item.href) : void 0,
|
|
44254
|
+
badge: item.badge != null ? String(item.badge) : void 0,
|
|
44255
|
+
accentColor: item.accentColor != null ? String(item.accentColor) : void 0
|
|
44256
|
+
},
|
|
44257
|
+
String(item.id ?? "")
|
|
44258
|
+
);
|
|
44259
|
+
}) })
|
|
44041
44260
|
] });
|
|
44042
44261
|
};
|
|
44043
44262
|
ShowcaseOrganism.displayName = "ShowcaseOrganism";
|
|
@@ -44405,8 +44624,8 @@ function SimulatorBoard({
|
|
|
44405
44624
|
}) {
|
|
44406
44625
|
const { emit } = useEventBus();
|
|
44407
44626
|
const { t } = useTranslate();
|
|
44408
|
-
const resolved =
|
|
44409
|
-
const parameters = resolved?.parameters
|
|
44627
|
+
const resolved = boardEntity(entity);
|
|
44628
|
+
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
44410
44629
|
const [values, setValues] = useState(() => {
|
|
44411
44630
|
const init = {};
|
|
44412
44631
|
for (const p2 of parameters) {
|
|
@@ -44420,15 +44639,15 @@ function SimulatorBoard({
|
|
|
44420
44639
|
const [showHint, setShowHint] = useState(false);
|
|
44421
44640
|
const computeOutput = useCallback((params) => {
|
|
44422
44641
|
try {
|
|
44423
|
-
const fn = new Function("params", `return (${resolved?.computeExpression})`);
|
|
44642
|
+
const fn = new Function("params", `return (${str(resolved?.computeExpression)})`);
|
|
44424
44643
|
return fn(params);
|
|
44425
44644
|
} catch {
|
|
44426
44645
|
return 0;
|
|
44427
44646
|
}
|
|
44428
44647
|
}, [resolved?.computeExpression]);
|
|
44429
44648
|
const output = useMemo(() => computeOutput(values) ?? 0, [computeOutput, values]);
|
|
44430
|
-
const targetValue = resolved?.targetValue
|
|
44431
|
-
const targetTolerance = resolved?.targetTolerance
|
|
44649
|
+
const targetValue = num(resolved?.targetValue);
|
|
44650
|
+
const targetTolerance = num(resolved?.targetTolerance);
|
|
44432
44651
|
const isCorrect = Math.abs(output - targetValue) <= targetTolerance;
|
|
44433
44652
|
const handleParameterChange = (id, value) => {
|
|
44434
44653
|
if (submitted) return;
|
|
@@ -44443,7 +44662,7 @@ function SimulatorBoard({
|
|
|
44443
44662
|
};
|
|
44444
44663
|
const handleReset = () => {
|
|
44445
44664
|
setSubmitted(false);
|
|
44446
|
-
if (attempts >= 2 && resolved?.hint) {
|
|
44665
|
+
if (attempts >= 2 && str(resolved?.hint)) {
|
|
44447
44666
|
setShowHint(true);
|
|
44448
44667
|
}
|
|
44449
44668
|
};
|
|
@@ -44458,20 +44677,26 @@ function SimulatorBoard({
|
|
|
44458
44677
|
setShowHint(false);
|
|
44459
44678
|
};
|
|
44460
44679
|
if (!resolved) return null;
|
|
44680
|
+
const theme = resolved.theme ?? void 0;
|
|
44681
|
+
const themeBackground = theme?.background;
|
|
44682
|
+
const headerImage = str(resolved.headerImage);
|
|
44683
|
+
const hint = str(resolved.hint);
|
|
44684
|
+
const outputLabel = str(resolved.outputLabel);
|
|
44685
|
+
const outputUnit = str(resolved.outputUnit);
|
|
44461
44686
|
return /* @__PURE__ */ jsx(
|
|
44462
44687
|
Box,
|
|
44463
44688
|
{
|
|
44464
44689
|
className,
|
|
44465
44690
|
style: {
|
|
44466
|
-
backgroundImage:
|
|
44691
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
44467
44692
|
backgroundSize: "cover",
|
|
44468
44693
|
backgroundPosition: "center"
|
|
44469
44694
|
},
|
|
44470
44695
|
children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
|
|
44471
|
-
|
|
44696
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
44472
44697
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
44473
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: resolved.title }),
|
|
44474
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", children: resolved.description })
|
|
44698
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: str(resolved.title) }),
|
|
44699
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", children: str(resolved.description) })
|
|
44475
44700
|
] }) }),
|
|
44476
44701
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
|
|
44477
44702
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
@@ -44512,28 +44737,28 @@ function SimulatorBoard({
|
|
|
44512
44737
|
] }, param.id))
|
|
44513
44738
|
] }) }),
|
|
44514
44739
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
44515
|
-
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children:
|
|
44740
|
+
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
44516
44741
|
/* @__PURE__ */ jsxs(Typography, { variant: "h3", weight: "bold", children: [
|
|
44517
44742
|
output.toFixed(2),
|
|
44518
44743
|
" ",
|
|
44519
|
-
|
|
44744
|
+
outputUnit
|
|
44520
44745
|
] }),
|
|
44521
44746
|
submitted && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
44522
44747
|
/* @__PURE__ */ jsx(Icon, { icon: isCorrect ? CheckCircle : XCircle, size: "sm", className: isCorrect ? "text-success" : "text-error" }),
|
|
44523
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? resolved.successMessage
|
|
44748
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", className: isCorrect ? "text-success" : "text-error", children: isCorrect ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
|
|
44524
44749
|
] }),
|
|
44525
44750
|
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44526
44751
|
t("simulator.target"),
|
|
44527
44752
|
": ",
|
|
44528
44753
|
targetValue,
|
|
44529
44754
|
" ",
|
|
44530
|
-
|
|
44755
|
+
outputUnit,
|
|
44531
44756
|
" (\xB1",
|
|
44532
44757
|
targetTolerance,
|
|
44533
44758
|
")"
|
|
44534
44759
|
] })
|
|
44535
44760
|
] }) }),
|
|
44536
|
-
showHint &&
|
|
44761
|
+
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
44537
44762
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
44538
44763
|
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
|
|
44539
44764
|
/* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
|
|
@@ -44552,6 +44777,7 @@ var init_SimulatorBoard = __esm({
|
|
|
44552
44777
|
"components/game/organisms/puzzles/simulator/SimulatorBoard.tsx"() {
|
|
44553
44778
|
init_atoms2();
|
|
44554
44779
|
init_useEventBus();
|
|
44780
|
+
init_boardEntity();
|
|
44555
44781
|
SimulatorBoard.displayName = "SimulatorBoard";
|
|
44556
44782
|
}
|
|
44557
44783
|
});
|
|
@@ -44977,22 +45203,25 @@ function VariablePanel({
|
|
|
44977
45203
|
return /* @__PURE__ */ jsxs(VStack, { className: cn("p-3 rounded-lg bg-card border border-border", className), gap: "sm", children: [
|
|
44978
45204
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.variables", { name: entityName }) }),
|
|
44979
45205
|
variables.map((v) => {
|
|
44980
|
-
const
|
|
44981
|
-
const
|
|
44982
|
-
const
|
|
45206
|
+
const name = v.name == null ? "" : String(v.name);
|
|
45207
|
+
const value = numField(v.value);
|
|
45208
|
+
const max = numField(v.max, 100);
|
|
45209
|
+
const min = numField(v.min, 0);
|
|
45210
|
+
const unit = v.unit == null ? "" : String(v.unit);
|
|
45211
|
+
const pct = Math.round((value - min) / (max - min) * 100);
|
|
44983
45212
|
const isHigh = pct > 80;
|
|
44984
45213
|
const isLow = pct < 20;
|
|
44985
45214
|
return /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
|
|
44986
45215
|
/* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
|
|
44987
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children:
|
|
45216
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground font-medium", children: name }),
|
|
44988
45217
|
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: cn(
|
|
44989
45218
|
isHigh ? "text-error" : isLow ? "text-warning" : "text-foreground"
|
|
44990
45219
|
), children: [
|
|
44991
|
-
|
|
44992
|
-
|
|
45220
|
+
value,
|
|
45221
|
+
unit,
|
|
44993
45222
|
" / ",
|
|
44994
45223
|
max,
|
|
44995
|
-
|
|
45224
|
+
unit
|
|
44996
45225
|
] })
|
|
44997
45226
|
] }),
|
|
44998
45227
|
/* @__PURE__ */ jsx(
|
|
@@ -45003,14 +45232,19 @@ function VariablePanel({
|
|
|
45003
45232
|
size: "sm"
|
|
45004
45233
|
}
|
|
45005
45234
|
)
|
|
45006
|
-
] },
|
|
45235
|
+
] }, name);
|
|
45007
45236
|
})
|
|
45008
45237
|
] });
|
|
45009
45238
|
}
|
|
45239
|
+
var numField;
|
|
45010
45240
|
var init_VariablePanel = __esm({
|
|
45011
45241
|
"components/game/organisms/puzzles/state-architect/VariablePanel.tsx"() {
|
|
45012
45242
|
init_atoms2();
|
|
45013
45243
|
init_cn();
|
|
45244
|
+
numField = (v, fallback = 0) => {
|
|
45245
|
+
const n = Number(v);
|
|
45246
|
+
return Number.isFinite(n) ? n : fallback;
|
|
45247
|
+
};
|
|
45014
45248
|
VariablePanel.displayName = "VariablePanel";
|
|
45015
45249
|
}
|
|
45016
45250
|
});
|
|
@@ -45037,14 +45271,21 @@ function StateArchitectBoard({
|
|
|
45037
45271
|
}) {
|
|
45038
45272
|
const { emit } = useEventBus();
|
|
45039
45273
|
const { t } = useTranslate();
|
|
45040
|
-
const resolved =
|
|
45041
|
-
const
|
|
45274
|
+
const resolved = boardEntity(entity);
|
|
45275
|
+
const entityStates = Array.isArray(resolved?.states) ? resolved.states : [];
|
|
45276
|
+
const initialState = str(resolved?.initialState);
|
|
45277
|
+
const entityName = str(resolved?.entityName);
|
|
45278
|
+
const availableEvents = Array.isArray(resolved?.availableEvents) ? resolved.availableEvents : [];
|
|
45279
|
+
const testCases = Array.isArray(resolved?.testCases) ? resolved.testCases : [];
|
|
45280
|
+
const entityTransitions = Array.isArray(resolved?.transitions) ? resolved.transitions : [];
|
|
45281
|
+
const entityVariables = rows(resolved?.variables);
|
|
45282
|
+
const [transitions, setTransitions] = useState(entityTransitions);
|
|
45042
45283
|
const [headerError, setHeaderError] = useState(false);
|
|
45043
45284
|
const [playState, setPlayState] = useState("editing");
|
|
45044
|
-
const [currentState, setCurrentState] = useState(
|
|
45285
|
+
const [currentState, setCurrentState] = useState(initialState);
|
|
45045
45286
|
const [selectedState, setSelectedState] = useState(null);
|
|
45046
45287
|
const [testResults, setTestResults] = useState([]);
|
|
45047
|
-
const [variables, setVariables] = useState(
|
|
45288
|
+
const [variables, setVariables] = useState(() => [...entityVariables]);
|
|
45048
45289
|
const [attempts, setAttempts] = useState(0);
|
|
45049
45290
|
const timerRef = useRef(null);
|
|
45050
45291
|
const [addingFrom, setAddingFrom] = useState(null);
|
|
@@ -45053,12 +45294,12 @@ function StateArchitectBoard({
|
|
|
45053
45294
|
}, []);
|
|
45054
45295
|
const GRAPH_W = 500;
|
|
45055
45296
|
const GRAPH_H = 400;
|
|
45056
|
-
const positions = useMemo(() => layoutStates(
|
|
45297
|
+
const positions = useMemo(() => layoutStates(entityStates, GRAPH_W, GRAPH_H), [entityStates]);
|
|
45057
45298
|
const handleStateClick = useCallback((state) => {
|
|
45058
45299
|
if (playState !== "editing") return;
|
|
45059
45300
|
if (addingFrom) {
|
|
45060
45301
|
if (addingFrom !== state) {
|
|
45061
|
-
const event =
|
|
45302
|
+
const event = availableEvents[0] || "EVENT";
|
|
45062
45303
|
const newTrans = {
|
|
45063
45304
|
id: `t-${nextTransId++}`,
|
|
45064
45305
|
from: addingFrom,
|
|
@@ -45071,7 +45312,7 @@ function StateArchitectBoard({
|
|
|
45071
45312
|
} else {
|
|
45072
45313
|
setSelectedState(state);
|
|
45073
45314
|
}
|
|
45074
|
-
}, [playState, addingFrom,
|
|
45315
|
+
}, [playState, addingFrom, availableEvents]);
|
|
45075
45316
|
const handleStartAddTransition = useCallback(() => {
|
|
45076
45317
|
if (!selectedState) return;
|
|
45077
45318
|
setAddingFrom(selectedState);
|
|
@@ -45080,9 +45321,9 @@ function StateArchitectBoard({
|
|
|
45080
45321
|
setTransitions((prev) => prev.filter((t2) => t2.id !== transId));
|
|
45081
45322
|
}, []);
|
|
45082
45323
|
const machine = useMemo(() => ({
|
|
45083
|
-
name:
|
|
45084
|
-
description: resolved?.description
|
|
45085
|
-
states:
|
|
45324
|
+
name: entityName,
|
|
45325
|
+
description: str(resolved?.description),
|
|
45326
|
+
states: entityStates,
|
|
45086
45327
|
currentState,
|
|
45087
45328
|
transitions: transitions.map((t2) => ({
|
|
45088
45329
|
from: t2.from,
|
|
@@ -45090,7 +45331,7 @@ function StateArchitectBoard({
|
|
|
45090
45331
|
event: t2.event,
|
|
45091
45332
|
guardHint: t2.guardHint
|
|
45092
45333
|
}))
|
|
45093
|
-
}), [resolved, currentState, transitions]);
|
|
45334
|
+
}), [entityName, resolved, entityStates, currentState, transitions]);
|
|
45094
45335
|
const handleTest = useCallback(() => {
|
|
45095
45336
|
if (playState !== "editing") return;
|
|
45096
45337
|
if (testEvent) emit(`UI:${testEvent}`, {});
|
|
@@ -45099,7 +45340,7 @@ function StateArchitectBoard({
|
|
|
45099
45340
|
const results = [];
|
|
45100
45341
|
let testIdx = 0;
|
|
45101
45342
|
const runNextTest = () => {
|
|
45102
|
-
if (testIdx >=
|
|
45343
|
+
if (testIdx >= testCases.length) {
|
|
45103
45344
|
const allPassed = results.every((r) => r.passed);
|
|
45104
45345
|
setPlayState(allPassed ? "success" : "fail");
|
|
45105
45346
|
setTestResults(results);
|
|
@@ -45114,9 +45355,9 @@ function StateArchitectBoard({
|
|
|
45114
45355
|
}
|
|
45115
45356
|
return;
|
|
45116
45357
|
}
|
|
45117
|
-
const testCase =
|
|
45358
|
+
const testCase = testCases[testIdx];
|
|
45118
45359
|
if (!testCase) return;
|
|
45119
|
-
let state =
|
|
45360
|
+
let state = initialState;
|
|
45120
45361
|
for (const event of testCase.events) {
|
|
45121
45362
|
const trans = transitions.find((t2) => t2.from === state && t2.event === event);
|
|
45122
45363
|
if (trans) {
|
|
@@ -45134,53 +45375,57 @@ function StateArchitectBoard({
|
|
|
45134
45375
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
45135
45376
|
};
|
|
45136
45377
|
timerRef.current = setTimeout(runNextTest, stepDurationMs);
|
|
45137
|
-
}, [playState, transitions,
|
|
45378
|
+
}, [playState, transitions, testCases, initialState, stepDurationMs, testEvent, completeEvent, emit]);
|
|
45138
45379
|
const handleTryAgain = useCallback(() => {
|
|
45139
45380
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45140
45381
|
setPlayState("editing");
|
|
45141
|
-
setCurrentState(
|
|
45382
|
+
setCurrentState(initialState);
|
|
45142
45383
|
setTestResults([]);
|
|
45143
|
-
}, [
|
|
45384
|
+
}, [initialState]);
|
|
45144
45385
|
const handleReset = useCallback(() => {
|
|
45145
45386
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
45146
|
-
setTransitions(
|
|
45387
|
+
setTransitions(entityTransitions);
|
|
45147
45388
|
setPlayState("editing");
|
|
45148
|
-
setCurrentState(
|
|
45389
|
+
setCurrentState(initialState);
|
|
45149
45390
|
setTestResults([]);
|
|
45150
|
-
setVariables(
|
|
45391
|
+
setVariables([...entityVariables]);
|
|
45151
45392
|
setSelectedState(null);
|
|
45152
45393
|
setAddingFrom(null);
|
|
45153
45394
|
setAttempts(0);
|
|
45154
|
-
}, [
|
|
45395
|
+
}, [entityTransitions, initialState, entityVariables]);
|
|
45155
45396
|
const codeData = useMemo(() => ({
|
|
45156
|
-
name:
|
|
45157
|
-
states:
|
|
45158
|
-
initialState
|
|
45397
|
+
name: entityName,
|
|
45398
|
+
states: entityStates,
|
|
45399
|
+
initialState,
|
|
45159
45400
|
transitions: transitions.map((t2) => ({
|
|
45160
45401
|
from: t2.from,
|
|
45161
45402
|
to: t2.to,
|
|
45162
45403
|
event: t2.event,
|
|
45163
45404
|
...t2.guardHint ? { guard: t2.guardHint } : {}
|
|
45164
45405
|
}))
|
|
45165
|
-
}), [
|
|
45406
|
+
}), [entityName, entityStates, initialState, transitions]);
|
|
45166
45407
|
if (!resolved) return null;
|
|
45408
|
+
const theme = resolved.theme ?? void 0;
|
|
45409
|
+
const themeBackground = theme?.background;
|
|
45410
|
+
const headerImage = str(resolved.headerImage);
|
|
45411
|
+
const hint = str(resolved.hint);
|
|
45167
45412
|
return /* @__PURE__ */ jsxs(
|
|
45168
45413
|
VStack,
|
|
45169
45414
|
{
|
|
45170
45415
|
className: cn("p-4 gap-6", className),
|
|
45171
45416
|
style: {
|
|
45172
|
-
backgroundImage:
|
|
45417
|
+
backgroundImage: themeBackground ? `url(${themeBackground})` : void 0,
|
|
45173
45418
|
backgroundSize: "cover",
|
|
45174
45419
|
backgroundPosition: "center"
|
|
45175
45420
|
},
|
|
45176
45421
|
children: [
|
|
45177
|
-
|
|
45422
|
+
headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-container", children: /* @__PURE__ */ jsx("img", { src: headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-container bg-gradient-to-br from-muted to-accent opacity-60" }) : null,
|
|
45178
45423
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
45179
|
-
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: resolved.title }),
|
|
45180
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: resolved.description }),
|
|
45424
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: str(resolved.title) }),
|
|
45425
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: str(resolved.description) }),
|
|
45181
45426
|
/* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
|
|
45182
45427
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
|
|
45183
|
-
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children:
|
|
45428
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: hint })
|
|
45184
45429
|
] })
|
|
45185
45430
|
] }),
|
|
45186
45431
|
/* @__PURE__ */ jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
|
|
@@ -45228,14 +45473,14 @@ function StateArchitectBoard({
|
|
|
45228
45473
|
]
|
|
45229
45474
|
}
|
|
45230
45475
|
),
|
|
45231
|
-
|
|
45476
|
+
entityStates.map((state) => /* @__PURE__ */ jsx(
|
|
45232
45477
|
StateNode2,
|
|
45233
45478
|
{
|
|
45234
45479
|
name: state,
|
|
45235
45480
|
position: positions[state],
|
|
45236
45481
|
isCurrent: state === currentState,
|
|
45237
45482
|
isSelected: state === selectedState,
|
|
45238
|
-
isInitial: state ===
|
|
45483
|
+
isInitial: state === initialState,
|
|
45239
45484
|
onClick: () => handleStateClick(state)
|
|
45240
45485
|
},
|
|
45241
45486
|
state
|
|
@@ -45282,7 +45527,7 @@ function StateArchitectBoard({
|
|
|
45282
45527
|
/* @__PURE__ */ jsx(
|
|
45283
45528
|
VariablePanel,
|
|
45284
45529
|
{
|
|
45285
|
-
entityName
|
|
45530
|
+
entityName,
|
|
45286
45531
|
variables
|
|
45287
45532
|
}
|
|
45288
45533
|
),
|
|
@@ -45297,12 +45542,12 @@ function StateArchitectBoard({
|
|
|
45297
45542
|
resolved.showCodeView !== false && /* @__PURE__ */ jsx(CodeView, { data: codeData, label: "View Code" })
|
|
45298
45543
|
] })
|
|
45299
45544
|
] }),
|
|
45300
|
-
playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: resolved.successMessage || t("stateArchitect.allPassed") }) }),
|
|
45545
|
+
playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: str(resolved.successMessage) || t("stateArchitect.allPassed") }) }),
|
|
45301
45546
|
playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
45302
45547
|
/* @__PURE__ */ jsx(Box, { className: "p-4 rounded-container bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
|
|
45303
|
-
attempts >= 3 &&
|
|
45548
|
+
attempts >= 3 && hint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-container bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
|
|
45304
45549
|
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
|
|
45305
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children:
|
|
45550
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: hint })
|
|
45306
45551
|
] }) })
|
|
45307
45552
|
] }),
|
|
45308
45553
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
|
|
@@ -45332,6 +45577,7 @@ var init_StateArchitectBoard = __esm({
|
|
|
45332
45577
|
init_TransitionArrow();
|
|
45333
45578
|
init_VariablePanel();
|
|
45334
45579
|
init_CodeView();
|
|
45580
|
+
init_boardEntity();
|
|
45335
45581
|
ENCOURAGEMENT_KEYS3 = [
|
|
45336
45582
|
"puzzle.tryAgain1",
|
|
45337
45583
|
"puzzle.tryAgain2",
|
|
@@ -45368,8 +45614,8 @@ var init_StatsOrganism = __esm({
|
|
|
45368
45614
|
return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
|
|
45369
45615
|
}
|
|
45370
45616
|
const stats = items.map((item) => ({
|
|
45371
|
-
value: item.value,
|
|
45372
|
-
label: item.label
|
|
45617
|
+
value: String(item.value ?? ""),
|
|
45618
|
+
label: String(item.label ?? "")
|
|
45373
45619
|
}));
|
|
45374
45620
|
return /* @__PURE__ */ jsx(
|
|
45375
45621
|
StatsGrid,
|
|
@@ -45415,10 +45661,10 @@ var init_StepFlowOrganism = __esm({
|
|
|
45415
45661
|
return /* @__PURE__ */ jsx(ErrorState, { message: error.message, className });
|
|
45416
45662
|
}
|
|
45417
45663
|
const steps = items.map((item) => ({
|
|
45418
|
-
number: item.number,
|
|
45419
|
-
title: item.title,
|
|
45420
|
-
description: item.description,
|
|
45421
|
-
icon: item.icon
|
|
45664
|
+
number: item.number != null ? Number(item.number) : void 0,
|
|
45665
|
+
title: String(item.title ?? ""),
|
|
45666
|
+
description: String(item.description ?? ""),
|
|
45667
|
+
icon: item.icon != null ? String(item.icon) : void 0
|
|
45422
45668
|
}));
|
|
45423
45669
|
return /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: cn("w-full", className), children: [
|
|
45424
45670
|
(heading || subtitle) && /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", className: "w-full", children: [
|
|
@@ -45591,13 +45837,13 @@ var init_TeamOrganism = __esm({
|
|
|
45591
45837
|
/* @__PURE__ */ jsx(SimpleGrid, { cols: cols > 0 ? cols : 1, gap: "lg", children: items.map((member) => /* @__PURE__ */ jsx(
|
|
45592
45838
|
TeamCard,
|
|
45593
45839
|
{
|
|
45594
|
-
name: member.name,
|
|
45595
|
-
nameAr: member.nameAr,
|
|
45596
|
-
role: member.role,
|
|
45597
|
-
bio: member.bio,
|
|
45598
|
-
avatar: member.avatar
|
|
45840
|
+
name: String(member.name ?? ""),
|
|
45841
|
+
nameAr: member.nameAr != null ? String(member.nameAr) : void 0,
|
|
45842
|
+
role: String(member.role ?? ""),
|
|
45843
|
+
bio: String(member.bio ?? ""),
|
|
45844
|
+
avatar: member.avatar != null ? String(member.avatar) : void 0
|
|
45599
45845
|
},
|
|
45600
|
-
member.id
|
|
45846
|
+
String(member.id ?? "")
|
|
45601
45847
|
)) })
|
|
45602
45848
|
] });
|
|
45603
45849
|
};
|
|
@@ -45834,8 +46080,8 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45834
46080
|
const [turn, setTurn] = useState(1);
|
|
45835
46081
|
const [gameResult, setGameResult] = useState(null);
|
|
45836
46082
|
const checkGameEnd = useCallback((currentUnits) => {
|
|
45837
|
-
const pa = currentUnits.filter((u) => u
|
|
45838
|
-
const ea = currentUnits.filter((u) => u
|
|
46083
|
+
const pa = currentUnits.filter((u) => unitTeam(u) === "player" && unitHealth(u) > 0);
|
|
46084
|
+
const ea = currentUnits.filter((u) => unitTeam(u) === "enemy" && unitHealth(u) > 0);
|
|
45839
46085
|
if (pa.length === 0) {
|
|
45840
46086
|
setGameResult("defeat");
|
|
45841
46087
|
setPhase("game_over");
|
|
@@ -45853,34 +46099,36 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45853
46099
|
}
|
|
45854
46100
|
}, [onGameEnd, gameEndEvent, eventBus]);
|
|
45855
46101
|
const handleUnitClick = useCallback((unitId) => {
|
|
45856
|
-
const unit = units.find((u) => u.id === unitId);
|
|
46102
|
+
const unit = units.find((u) => str(u.id) === unitId);
|
|
45857
46103
|
if (!unit) return;
|
|
45858
46104
|
if (unitClickEvent) {
|
|
45859
46105
|
eventBus.emit(`UI:${unitClickEvent}`, { unitId });
|
|
45860
46106
|
}
|
|
45861
46107
|
if (phase === "observation" || phase === "selection") {
|
|
45862
|
-
if (unit
|
|
46108
|
+
if (unitTeam(unit) === "player") {
|
|
45863
46109
|
setSelectedUnitId(unitId);
|
|
45864
46110
|
setPhase("movement");
|
|
45865
46111
|
}
|
|
45866
46112
|
} else if (phase === "action") {
|
|
45867
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
46113
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45868
46114
|
if (!selectedUnit) return;
|
|
45869
|
-
if (unit
|
|
45870
|
-
const
|
|
45871
|
-
const
|
|
46115
|
+
if (unitTeam(unit) === "enemy") {
|
|
46116
|
+
const up = unitPosition(unit);
|
|
46117
|
+
const sp = unitPosition(selectedUnit);
|
|
46118
|
+
const dx = Math.abs(up.x - sp.x);
|
|
46119
|
+
const dy = Math.abs(up.y - sp.y);
|
|
45872
46120
|
if (dx <= 1 && dy <= 1 && dx + dy > 0) {
|
|
45873
|
-
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
|
|
45874
|
-
const newHealth = Math.max(0, unit
|
|
46121
|
+
const damage = calculateDamage ? calculateDamage(selectedUnit, unit) : Math.max(1, num(selectedUnit.attack) - num(unit.defense));
|
|
46122
|
+
const newHealth = Math.max(0, unitHealth(unit) - damage);
|
|
45875
46123
|
const updatedUnits = units.map(
|
|
45876
|
-
(u) => u.id === unit.id ? { ...u, health: newHealth } : u
|
|
46124
|
+
(u) => str(u.id) === str(unit.id) ? { ...u, health: newHealth } : u
|
|
45877
46125
|
);
|
|
45878
46126
|
setUnits(updatedUnits);
|
|
45879
46127
|
onAttack?.(selectedUnit, unit, damage);
|
|
45880
46128
|
if (attackEvent) {
|
|
45881
46129
|
eventBus.emit(`UI:${attackEvent}`, {
|
|
45882
|
-
attackerId: selectedUnit.id,
|
|
45883
|
-
targetId: unit.id,
|
|
46130
|
+
attackerId: str(selectedUnit.id),
|
|
46131
|
+
targetId: str(unit.id),
|
|
45884
46132
|
damage
|
|
45885
46133
|
});
|
|
45886
46134
|
}
|
|
@@ -45897,16 +46145,20 @@ function useBattleState(initialUnits, eventConfig = {}, callbacks = {}) {
|
|
|
45897
46145
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
45898
46146
|
}
|
|
45899
46147
|
if (phase === "movement" && selectedUnitId) {
|
|
45900
|
-
const selectedUnit = units.find((u) => u.id === selectedUnitId);
|
|
46148
|
+
const selectedUnit = units.find((u) => str(u.id) === selectedUnitId);
|
|
45901
46149
|
if (!selectedUnit) return;
|
|
45902
|
-
const
|
|
45903
|
-
const
|
|
46150
|
+
const sp = unitPosition(selectedUnit);
|
|
46151
|
+
const dx = Math.abs(x - sp.x);
|
|
46152
|
+
const dy = Math.abs(y - sp.y);
|
|
45904
46153
|
const dist = dx + dy;
|
|
45905
|
-
if (dist > 0 && dist <= selectedUnit.movement) {
|
|
45906
|
-
if (!units.some((u) =>
|
|
46154
|
+
if (dist > 0 && dist <= num(selectedUnit.movement)) {
|
|
46155
|
+
if (!units.some((u) => {
|
|
46156
|
+
const p2 = unitPosition(u);
|
|
46157
|
+
return p2.x === x && p2.y === y && unitHealth(u) > 0;
|
|
46158
|
+
})) {
|
|
45907
46159
|
setUnits(
|
|
45908
46160
|
(prev) => prev.map(
|
|
45909
|
-
(u) => u.id === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
46161
|
+
(u) => str(u.id) === selectedUnitId ? { ...u, position: { x, y } } : u
|
|
45910
46162
|
)
|
|
45911
46163
|
);
|
|
45912
46164
|
setPhase("action");
|
|
@@ -45949,12 +46201,13 @@ var init_useBattleState = __esm({
|
|
|
45949
46201
|
"components/game/organisms/hooks/useBattleState.ts"() {
|
|
45950
46202
|
"use client";
|
|
45951
46203
|
init_useEventBus();
|
|
46204
|
+
init_boardEntity();
|
|
45952
46205
|
}
|
|
45953
46206
|
});
|
|
45954
46207
|
function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
45955
|
-
const resolved =
|
|
46208
|
+
const resolved = boardEntity(entity);
|
|
45956
46209
|
const battleState = useBattleState(
|
|
45957
|
-
resolved?.initialUnits
|
|
46210
|
+
rows(resolved?.initialUnits),
|
|
45958
46211
|
{
|
|
45959
46212
|
tileClickEvent: rest.tileClickEvent,
|
|
45960
46213
|
unitClickEvent: rest.unitClickEvent,
|
|
@@ -45990,10 +46243,23 @@ function UncontrolledBattleBoard({ entity, ...rest }) {
|
|
|
45990
46243
|
var init_UncontrolledBattleBoard = __esm({
|
|
45991
46244
|
"components/game/organisms/UncontrolledBattleBoard.tsx"() {
|
|
45992
46245
|
init_BattleBoard();
|
|
46246
|
+
init_boardEntity();
|
|
45993
46247
|
init_useBattleState();
|
|
45994
46248
|
UncontrolledBattleBoard.displayName = "UncontrolledBattleBoard";
|
|
45995
46249
|
}
|
|
45996
46250
|
});
|
|
46251
|
+
function heroPosition(h) {
|
|
46252
|
+
return vec2(h.position);
|
|
46253
|
+
}
|
|
46254
|
+
function heroOwner(h) {
|
|
46255
|
+
return str(h.owner);
|
|
46256
|
+
}
|
|
46257
|
+
function heroMovement(h) {
|
|
46258
|
+
return num(h.movement);
|
|
46259
|
+
}
|
|
46260
|
+
function hexPassable(h) {
|
|
46261
|
+
return h.passable !== false;
|
|
46262
|
+
}
|
|
45997
46263
|
function defaultIsInRange(from, to, range) {
|
|
45998
46264
|
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) <= range;
|
|
45999
46265
|
}
|
|
@@ -46024,36 +46290,36 @@ function WorldMapBoard({
|
|
|
46024
46290
|
className
|
|
46025
46291
|
}) {
|
|
46026
46292
|
const eventBus = useEventBus();
|
|
46027
|
-
const resolved =
|
|
46028
|
-
const hexes = resolved?.hexes
|
|
46029
|
-
const heroes = resolved?.heroes
|
|
46030
|
-
const features = resolved?.features
|
|
46031
|
-
const selectedHeroId = resolved?.selectedHeroId;
|
|
46293
|
+
const resolved = boardEntity(entity);
|
|
46294
|
+
const hexes = rows(resolved?.hexes);
|
|
46295
|
+
const heroes = rows(resolved?.heroes);
|
|
46296
|
+
const features = Array.isArray(resolved?.features) ? resolved.features : [];
|
|
46297
|
+
const selectedHeroId = resolved?.selectedHeroId ?? null;
|
|
46032
46298
|
const assetManifest = resolved?.assetManifest;
|
|
46033
46299
|
const backgroundImage = resolved?.backgroundImage;
|
|
46034
46300
|
const [hoveredTile, setHoveredTile] = useState(null);
|
|
46035
46301
|
const selectedHero = useMemo(
|
|
46036
|
-
() => heroes.find((h) => h.id === selectedHeroId) ?? null,
|
|
46302
|
+
() => heroes.find((h) => str(h.id) === selectedHeroId) ?? null,
|
|
46037
46303
|
[heroes, selectedHeroId]
|
|
46038
46304
|
);
|
|
46039
46305
|
const tiles = useMemo(
|
|
46040
46306
|
() => hexes.map((hex) => ({
|
|
46041
|
-
x: hex.x,
|
|
46042
|
-
y: hex.y,
|
|
46043
|
-
terrain: hex.terrain,
|
|
46044
|
-
terrainSprite: hex.terrainSprite
|
|
46307
|
+
x: num(hex.x),
|
|
46308
|
+
y: num(hex.y),
|
|
46309
|
+
terrain: str(hex.terrain),
|
|
46310
|
+
terrainSprite: hex.terrainSprite == null ? void 0 : str(hex.terrainSprite)
|
|
46045
46311
|
})),
|
|
46046
46312
|
[hexes]
|
|
46047
46313
|
);
|
|
46048
46314
|
const baseUnits = useMemo(
|
|
46049
46315
|
() => heroes.map((hero) => ({
|
|
46050
|
-
id: hero.id,
|
|
46051
|
-
position: hero
|
|
46052
|
-
name: hero.name,
|
|
46053
|
-
team: hero
|
|
46316
|
+
id: str(hero.id),
|
|
46317
|
+
position: heroPosition(hero),
|
|
46318
|
+
name: str(hero.name),
|
|
46319
|
+
team: heroOwner(hero) === "enemy" ? "enemy" : "player",
|
|
46054
46320
|
health: 100,
|
|
46055
46321
|
maxHealth: 100,
|
|
46056
|
-
sprite: hero.sprite
|
|
46322
|
+
sprite: hero.sprite == null ? void 0 : str(hero.sprite)
|
|
46057
46323
|
})),
|
|
46058
46324
|
[heroes]
|
|
46059
46325
|
);
|
|
@@ -46094,73 +46360,94 @@ function WorldMapBoard({
|
|
|
46094
46360
|
const isoUnits = useMemo(() => {
|
|
46095
46361
|
if (movingPositions.size === 0) return baseUnits;
|
|
46096
46362
|
return baseUnits.map((u) => {
|
|
46097
|
-
const pos = movingPositions.get(u.id);
|
|
46363
|
+
const pos = u.id == null ? void 0 : movingPositions.get(u.id);
|
|
46098
46364
|
return pos ? { ...u, position: pos } : u;
|
|
46099
46365
|
});
|
|
46100
46366
|
}, [baseUnits, movingPositions]);
|
|
46101
46367
|
const validMoves = useMemo(() => {
|
|
46102
|
-
if (!selectedHero || selectedHero
|
|
46368
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46369
|
+
const sp = heroPosition(selectedHero);
|
|
46370
|
+
const sOwner = heroOwner(selectedHero);
|
|
46371
|
+
const range = heroMovement(selectedHero);
|
|
46103
46372
|
const moves = [];
|
|
46104
46373
|
hexes.forEach((hex) => {
|
|
46105
|
-
|
|
46106
|
-
|
|
46107
|
-
if (!
|
|
46108
|
-
if (
|
|
46109
|
-
|
|
46374
|
+
const hx = num(hex.x);
|
|
46375
|
+
const hy = num(hex.y);
|
|
46376
|
+
if (!hexPassable(hex)) return;
|
|
46377
|
+
if (hx === sp.x && hy === sp.y) return;
|
|
46378
|
+
if (!isInRange(sp, { x: hx, y: hy }, range)) return;
|
|
46379
|
+
if (heroes.some((h) => {
|
|
46380
|
+
const hp = heroPosition(h);
|
|
46381
|
+
return hp.x === hx && hp.y === hy && heroOwner(h) === sOwner;
|
|
46382
|
+
})) return;
|
|
46383
|
+
moves.push({ x: hx, y: hy });
|
|
46110
46384
|
});
|
|
46111
46385
|
return moves;
|
|
46112
46386
|
}, [selectedHero, hexes, heroes, isInRange]);
|
|
46113
46387
|
const attackTargets = useMemo(() => {
|
|
46114
|
-
if (!selectedHero || selectedHero
|
|
46115
|
-
|
|
46388
|
+
if (!selectedHero || heroMovement(selectedHero) <= 0) return [];
|
|
46389
|
+
const sp = heroPosition(selectedHero);
|
|
46390
|
+
const sOwner = heroOwner(selectedHero);
|
|
46391
|
+
const range = heroMovement(selectedHero);
|
|
46392
|
+
return heroes.filter((h) => heroOwner(h) !== sOwner).filter((h) => isInRange(sp, heroPosition(h), range)).map((h) => heroPosition(h));
|
|
46116
46393
|
}, [selectedHero, heroes, isInRange]);
|
|
46117
|
-
const maxY = Math.max(...hexes.map((h) => h.y), 0);
|
|
46394
|
+
const maxY = Math.max(...hexes.map((h) => num(h.y)), 0);
|
|
46118
46395
|
const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
|
|
46119
46396
|
const tileToScreen = useCallback(
|
|
46120
46397
|
(tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
|
|
46121
46398
|
[scale, baseOffsetX]
|
|
46122
46399
|
);
|
|
46123
46400
|
const hoveredHex = useMemo(
|
|
46124
|
-
() => hoveredTile ? hexes.find((h) => h.x === hoveredTile.x && h.y === hoveredTile.y) ?? null : null,
|
|
46401
|
+
() => hoveredTile ? hexes.find((h) => num(h.x) === hoveredTile.x && num(h.y) === hoveredTile.y) ?? null : null,
|
|
46125
46402
|
[hoveredTile, hexes]
|
|
46126
46403
|
);
|
|
46127
46404
|
const hoveredHero = useMemo(
|
|
46128
|
-
() => hoveredTile ? heroes.find((h) =>
|
|
46405
|
+
() => hoveredTile ? heroes.find((h) => {
|
|
46406
|
+
const hp = heroPosition(h);
|
|
46407
|
+
return hp.x === hoveredTile.x && hp.y === hoveredTile.y;
|
|
46408
|
+
}) ?? null : null,
|
|
46129
46409
|
[hoveredTile, heroes]
|
|
46130
46410
|
);
|
|
46131
46411
|
const handleTileClick = useCallback((x, y) => {
|
|
46132
46412
|
if (movementAnimRef.current) return;
|
|
46133
|
-
const hex = hexes.find((h) => h.x === x && h.y === y);
|
|
46413
|
+
const hex = hexes.find((h) => num(h.x) === x && num(h.y) === y);
|
|
46134
46414
|
if (!hex) return;
|
|
46135
46415
|
if (tileClickEvent) {
|
|
46136
46416
|
eventBus.emit(`UI:${tileClickEvent}`, { x, y });
|
|
46137
46417
|
}
|
|
46138
46418
|
if (selectedHero && validMoves.some((m) => m.x === x && m.y === y)) {
|
|
46139
|
-
|
|
46140
|
-
|
|
46419
|
+
const heroId = str(selectedHero.id);
|
|
46420
|
+
startMoveAnimation(heroId, { ...heroPosition(selectedHero) }, { x, y }, () => {
|
|
46421
|
+
onHeroMove?.(heroId, x, y);
|
|
46141
46422
|
if (heroMoveEvent) {
|
|
46142
|
-
eventBus.emit(`UI:${heroMoveEvent}`, { heroId
|
|
46423
|
+
eventBus.emit(`UI:${heroMoveEvent}`, { heroId, toX: x, toY: y });
|
|
46143
46424
|
}
|
|
46144
|
-
|
|
46145
|
-
|
|
46425
|
+
const feature = str(hex.feature);
|
|
46426
|
+
if (feature && feature !== "none") {
|
|
46427
|
+
onFeatureEnter?.(heroId, hex);
|
|
46146
46428
|
if (featureEnterEvent) {
|
|
46147
|
-
eventBus.emit(`UI:${featureEnterEvent}`, { heroId
|
|
46429
|
+
eventBus.emit(`UI:${featureEnterEvent}`, { heroId, feature, hex });
|
|
46148
46430
|
}
|
|
46149
46431
|
}
|
|
46150
46432
|
});
|
|
46151
46433
|
return;
|
|
46152
46434
|
}
|
|
46153
|
-
const enemy = heroes.find((h) =>
|
|
46435
|
+
const enemy = heroes.find((h) => {
|
|
46436
|
+
const hp = heroPosition(h);
|
|
46437
|
+
return hp.x === x && hp.y === y && heroOwner(h) === "enemy";
|
|
46438
|
+
});
|
|
46154
46439
|
if (selectedHero && enemy && attackTargets.some((t) => t.x === x && t.y === y)) {
|
|
46155
|
-
|
|
46440
|
+
const attackerId = str(selectedHero.id);
|
|
46441
|
+
const defenderId = str(enemy.id);
|
|
46442
|
+
onBattleEncounter?.(attackerId, defenderId);
|
|
46156
46443
|
if (battleEncounterEvent) {
|
|
46157
|
-
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId
|
|
46444
|
+
eventBus.emit(`UI:${battleEncounterEvent}`, { attackerId, defenderId });
|
|
46158
46445
|
}
|
|
46159
46446
|
}
|
|
46160
46447
|
}, [hexes, heroes, selectedHero, validMoves, attackTargets, startMoveAnimation, onHeroMove, onFeatureEnter, onBattleEncounter, eventBus, tileClickEvent, heroMoveEvent, featureEnterEvent, battleEncounterEvent]);
|
|
46161
46448
|
const handleUnitClick = useCallback((unitId) => {
|
|
46162
|
-
const hero = heroes.find((h) => h.id === unitId);
|
|
46163
|
-
if (hero && (hero
|
|
46449
|
+
const hero = heroes.find((h) => str(h.id) === unitId);
|
|
46450
|
+
if (hero && (heroOwner(hero) === "player" || allowMoveAllHeroes)) {
|
|
46164
46451
|
onHeroSelect?.(unitId);
|
|
46165
46452
|
if (heroSelectEvent) {
|
|
46166
46453
|
eventBus.emit(`UI:${heroSelectEvent}`, { heroId: unitId });
|
|
@@ -46233,6 +46520,7 @@ var init_WorldMapBoard = __esm({
|
|
|
46233
46520
|
init_Stack();
|
|
46234
46521
|
init_LoadingState();
|
|
46235
46522
|
init_IsometricCanvas2();
|
|
46523
|
+
init_boardEntity();
|
|
46236
46524
|
init_isometric();
|
|
46237
46525
|
WorldMapBoard.displayName = "WorldMapBoard";
|
|
46238
46526
|
}
|