@almadar/ui 5.35.0 → 5.37.0
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 +341 -285
- package/dist/avl/index.js +341 -282
- package/dist/components/game/organisms/puzzles/builder/BuilderBoard.d.ts +18 -5
- package/dist/components/game/organisms/puzzles/classifier/ClassifierBoard.d.ts +21 -3
- package/dist/components/game/organisms/puzzles/debugger/DebuggerBoard.d.ts +12 -2
- package/dist/components/game/organisms/puzzles/negotiator/NegotiatorBoard.d.ts +13 -3
- package/dist/components/game/organisms/puzzles/simulator/SimulatorBoard.d.ts +22 -7
- package/dist/components/index.cjs +348 -288
- package/dist/components/index.js +348 -285
- package/dist/docs/index.cjs +115 -81
- package/dist/docs/index.js +115 -78
- package/dist/marketing/index.cjs +114 -80
- package/dist/marketing/index.js +114 -77
- package/dist/providers/index.cjs +341 -285
- package/dist/providers/index.js +341 -282
- package/dist/runtime/index.cjs +341 -285
- package/dist/runtime/index.js +341 -282
- package/package.json +1 -1
package/dist/providers/index.cjs
CHANGED
|
@@ -7,9 +7,6 @@ var providers = require('@almadar/ui/providers');
|
|
|
7
7
|
var clsx = require('clsx');
|
|
8
8
|
var tailwindMerge = require('tailwind-merge');
|
|
9
9
|
var LucideIcons2 = require('lucide-react');
|
|
10
|
-
var PhosphorIcons = require('@phosphor-icons/react');
|
|
11
|
-
var TablerIcons = require('@tabler/icons-react');
|
|
12
|
-
var FaIcons = require('react-icons/fa');
|
|
13
10
|
var reactDom = require('react-dom');
|
|
14
11
|
var hooks = require('@almadar/ui/hooks');
|
|
15
12
|
var evaluator = require('@almadar/evaluator');
|
|
@@ -68,9 +65,6 @@ function _interopNamespace(e) {
|
|
|
68
65
|
|
|
69
66
|
var React83__namespace = /*#__PURE__*/_interopNamespace(React83);
|
|
70
67
|
var LucideIcons2__namespace = /*#__PURE__*/_interopNamespace(LucideIcons2);
|
|
71
|
-
var PhosphorIcons__namespace = /*#__PURE__*/_interopNamespace(PhosphorIcons);
|
|
72
|
-
var TablerIcons__namespace = /*#__PURE__*/_interopNamespace(TablerIcons);
|
|
73
|
-
var FaIcons__namespace = /*#__PURE__*/_interopNamespace(FaIcons);
|
|
74
68
|
var ELK__default = /*#__PURE__*/_interopDefault(ELK);
|
|
75
69
|
var SyntaxHighlighter__default = /*#__PURE__*/_interopDefault(SyntaxHighlighter);
|
|
76
70
|
var dark__default = /*#__PURE__*/_interopDefault(dark);
|
|
@@ -842,6 +836,41 @@ function kebabToPascal(name) {
|
|
|
842
836
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
843
837
|
}).join("");
|
|
844
838
|
}
|
|
839
|
+
function loadLib(key, importer) {
|
|
840
|
+
let p2 = libPromises.get(key);
|
|
841
|
+
if (!p2) {
|
|
842
|
+
p2 = importer().then((m) => m);
|
|
843
|
+
libPromises.set(key, p2);
|
|
844
|
+
}
|
|
845
|
+
return p2;
|
|
846
|
+
}
|
|
847
|
+
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
848
|
+
const Lazy = React83__namespace.default.lazy(async () => {
|
|
849
|
+
const lib = await loadLib(libKey, importer);
|
|
850
|
+
const Comp = pick(lib);
|
|
851
|
+
if (!Comp) {
|
|
852
|
+
warnFallback(fallbackName, family);
|
|
853
|
+
return { default: makeLucideAdapter(fallbackName, true) };
|
|
854
|
+
}
|
|
855
|
+
return { default: Comp };
|
|
856
|
+
});
|
|
857
|
+
const Wrapped = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
858
|
+
React83__namespace.default.Suspense,
|
|
859
|
+
{
|
|
860
|
+
fallback: /* @__PURE__ */ jsxRuntime.jsx(
|
|
861
|
+
"span",
|
|
862
|
+
{
|
|
863
|
+
"aria-hidden": true,
|
|
864
|
+
className: props.className,
|
|
865
|
+
style: { display: "inline-block", ...props.style }
|
|
866
|
+
}
|
|
867
|
+
),
|
|
868
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Lazy, { ...props })
|
|
869
|
+
}
|
|
870
|
+
);
|
|
871
|
+
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
872
|
+
return Wrapped;
|
|
873
|
+
}
|
|
845
874
|
function resolveLucide(name) {
|
|
846
875
|
if (lucideAliases[name]) return lucideAliases[name];
|
|
847
876
|
const pascal = kebabToPascal(name);
|
|
@@ -852,60 +881,81 @@ function resolveLucide(name) {
|
|
|
852
881
|
if (asIs && typeof asIs === "object") return asIs;
|
|
853
882
|
return LucideIcons2__namespace.HelpCircle;
|
|
854
883
|
}
|
|
855
|
-
function resolvePhosphor(name, weight) {
|
|
884
|
+
function resolvePhosphor(name, weight, family) {
|
|
856
885
|
const target = phosphorAliases[name] ?? kebabToPascal(name);
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
886
|
+
return lazyFamilyIcon(
|
|
887
|
+
"phosphor",
|
|
888
|
+
() => import('@phosphor-icons/react'),
|
|
889
|
+
(lib) => {
|
|
890
|
+
const PhosphorComp = lib[target];
|
|
891
|
+
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
892
|
+
const Component = PhosphorComp;
|
|
893
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
894
|
+
Component,
|
|
895
|
+
{
|
|
896
|
+
weight,
|
|
897
|
+
className: props.className,
|
|
898
|
+
style: props.style,
|
|
899
|
+
size: props.size ?? "1em"
|
|
900
|
+
}
|
|
901
|
+
);
|
|
902
|
+
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
903
|
+
return Adapter;
|
|
904
|
+
},
|
|
905
|
+
name,
|
|
906
|
+
family
|
|
869
907
|
);
|
|
870
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
871
|
-
return Adapter;
|
|
872
908
|
}
|
|
873
|
-
function resolveTabler(name) {
|
|
909
|
+
function resolveTabler(name, family) {
|
|
874
910
|
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
875
911
|
const target = `Icon${suffix}`;
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
912
|
+
return lazyFamilyIcon(
|
|
913
|
+
"tabler",
|
|
914
|
+
() => import('@tabler/icons-react'),
|
|
915
|
+
(lib) => {
|
|
916
|
+
const TablerComp = lib[target];
|
|
917
|
+
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
918
|
+
const Component = TablerComp;
|
|
919
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
920
|
+
Component,
|
|
921
|
+
{
|
|
922
|
+
stroke: props.strokeWidth ?? 1.5,
|
|
923
|
+
className: props.className,
|
|
924
|
+
style: props.style,
|
|
925
|
+
size: props.size ?? 24
|
|
926
|
+
}
|
|
927
|
+
);
|
|
928
|
+
Adapter.displayName = `Tabler.${target}`;
|
|
929
|
+
return Adapter;
|
|
930
|
+
},
|
|
931
|
+
name,
|
|
932
|
+
family
|
|
888
933
|
);
|
|
889
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
890
|
-
return Adapter;
|
|
891
934
|
}
|
|
892
|
-
function resolveFa(name) {
|
|
935
|
+
function resolveFa(name, family) {
|
|
893
936
|
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
894
937
|
const target = `Fa${suffix}`;
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
938
|
+
return lazyFamilyIcon(
|
|
939
|
+
"fa",
|
|
940
|
+
() => import('react-icons/fa'),
|
|
941
|
+
(lib) => {
|
|
942
|
+
const FaComp = lib[target];
|
|
943
|
+
if (!FaComp || typeof FaComp !== "function") return null;
|
|
944
|
+
const Component = FaComp;
|
|
945
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
946
|
+
Component,
|
|
947
|
+
{
|
|
948
|
+
className: props.className,
|
|
949
|
+
style: props.style,
|
|
950
|
+
size: props.size ?? "1em"
|
|
951
|
+
}
|
|
952
|
+
);
|
|
953
|
+
Adapter.displayName = `Fa.${target}`;
|
|
954
|
+
return Adapter;
|
|
955
|
+
},
|
|
956
|
+
name,
|
|
957
|
+
family
|
|
906
958
|
);
|
|
907
|
-
Adapter.displayName = `Fa.${target}`;
|
|
908
|
-
return Adapter;
|
|
909
959
|
}
|
|
910
960
|
function warnFallback(name, family) {
|
|
911
961
|
const key = `${family}::${name}`;
|
|
@@ -939,39 +989,22 @@ function resolveIconForFamily(name, family) {
|
|
|
939
989
|
switch (family) {
|
|
940
990
|
case "lucide":
|
|
941
991
|
return makeLucideAdapter(name, false);
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
return
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
return
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
return makeLucideAdapter(name, true);
|
|
959
|
-
}
|
|
960
|
-
case "tabler": {
|
|
961
|
-
const t = resolveTabler(name);
|
|
962
|
-
if (t) return t;
|
|
963
|
-
warnFallback(name, family);
|
|
964
|
-
return makeLucideAdapter(name, true);
|
|
965
|
-
}
|
|
966
|
-
case "fa-solid": {
|
|
967
|
-
const f3 = resolveFa(name);
|
|
968
|
-
if (f3) return f3;
|
|
969
|
-
warnFallback(name, family);
|
|
970
|
-
return makeLucideAdapter(name, true);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
992
|
+
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
993
|
+
// dynamic-imports the library on first render and falls back to lucide
|
|
994
|
+
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
995
|
+
case "phosphor-outline":
|
|
996
|
+
return resolvePhosphor(name, "regular", family);
|
|
997
|
+
case "phosphor-fill":
|
|
998
|
+
return resolvePhosphor(name, "fill", family);
|
|
999
|
+
case "phosphor-duotone":
|
|
1000
|
+
return resolvePhosphor(name, "duotone", family);
|
|
1001
|
+
case "tabler":
|
|
1002
|
+
return resolveTabler(name, family);
|
|
1003
|
+
case "fa-solid":
|
|
1004
|
+
return resolveFa(name, family);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
975
1008
|
var init_iconFamily = __esm({
|
|
976
1009
|
"lib/iconFamily.tsx"() {
|
|
977
1010
|
"use client";
|
|
@@ -987,6 +1020,7 @@ var init_iconFamily = __esm({
|
|
|
987
1020
|
cachedFamily = null;
|
|
988
1021
|
listeners = /* @__PURE__ */ new Set();
|
|
989
1022
|
observer = null;
|
|
1023
|
+
libPromises = /* @__PURE__ */ new Map();
|
|
990
1024
|
lucideAliases = {
|
|
991
1025
|
close: LucideIcons2__namespace.X,
|
|
992
1026
|
trash: LucideIcons2__namespace.Trash2,
|
|
@@ -17421,61 +17455,53 @@ var init_Breadcrumb = __esm({
|
|
|
17421
17455
|
function BuilderBoard({
|
|
17422
17456
|
entity,
|
|
17423
17457
|
completeEvent = "PUZZLE_COMPLETE",
|
|
17458
|
+
placeEvent,
|
|
17459
|
+
checkEvent,
|
|
17460
|
+
playAgainEvent,
|
|
17424
17461
|
className
|
|
17425
17462
|
}) {
|
|
17426
17463
|
const { emit } = useEventBus();
|
|
17427
17464
|
const { t } = hooks.useTranslate();
|
|
17428
17465
|
const resolved = boardEntity(entity);
|
|
17429
|
-
const [placements, setPlacements] = React83.useState({});
|
|
17430
17466
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
17431
|
-
const [
|
|
17432
|
-
const [attempts, setAttempts] = React83.useState(0);
|
|
17433
|
-
const [showHint, setShowHint] = React83.useState(false);
|
|
17467
|
+
const [selectedComponent, setSelectedComponent] = React83.useState(null);
|
|
17434
17468
|
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
17435
17469
|
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
17470
|
+
const placements = {};
|
|
17471
|
+
for (const slot of slots) {
|
|
17472
|
+
if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
|
|
17473
|
+
}
|
|
17474
|
+
const attempts = num(resolved?.attempts);
|
|
17475
|
+
const result = str(resolved?.result) || "none";
|
|
17476
|
+
const submitted = result === "win";
|
|
17436
17477
|
const usedComponentIds = new Set(Object.values(placements));
|
|
17437
17478
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
17438
|
-
const
|
|
17439
|
-
const allPlaced = Object.keys(placements).length === slots.length;
|
|
17479
|
+
const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
|
|
17440
17480
|
const results = submitted ? slots.map((slot) => ({
|
|
17441
17481
|
slot,
|
|
17442
17482
|
placed: placements[slot.id],
|
|
17443
|
-
correct: placements[slot.id] === slot.
|
|
17483
|
+
correct: placements[slot.id] === slot.requiredComponentId
|
|
17444
17484
|
})) : [];
|
|
17445
|
-
const
|
|
17485
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
17446
17486
|
const handlePlaceComponent = (slotId) => {
|
|
17447
17487
|
if (submitted || !selectedComponent) return;
|
|
17448
|
-
|
|
17488
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
|
|
17449
17489
|
setSelectedComponent(null);
|
|
17450
17490
|
};
|
|
17451
17491
|
const handleRemoveFromSlot = (slotId) => {
|
|
17452
17492
|
if (submitted) return;
|
|
17453
|
-
|
|
17454
|
-
const next = { ...prev };
|
|
17455
|
-
delete next[slotId];
|
|
17456
|
-
return next;
|
|
17457
|
-
});
|
|
17493
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
|
|
17458
17494
|
};
|
|
17459
|
-
const handleSubmit =
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
|
|
17463
|
-
if (correct) {
|
|
17495
|
+
const handleSubmit = () => {
|
|
17496
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
17497
|
+
const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
|
|
17498
|
+
if (solved && completeEvent) {
|
|
17464
17499
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
17465
17500
|
}
|
|
17466
|
-
}, [slots, placements, attempts, completeEvent, emit]);
|
|
17467
|
-
const handleReset = () => {
|
|
17468
|
-
setSubmitted(false);
|
|
17469
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
17470
|
-
setShowHint(true);
|
|
17471
|
-
}
|
|
17472
17501
|
};
|
|
17473
|
-
const
|
|
17474
|
-
setPlacements({});
|
|
17475
|
-
setSubmitted(false);
|
|
17502
|
+
const handlePlayAgain = () => {
|
|
17476
17503
|
setSelectedComponent(null);
|
|
17477
|
-
|
|
17478
|
-
setShowHint(false);
|
|
17504
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
17479
17505
|
};
|
|
17480
17506
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
17481
17507
|
if (!resolved) return null;
|
|
@@ -17525,13 +17551,13 @@ function BuilderBoard({
|
|
|
17525
17551
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
|
|
17526
17552
|
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", children: slots.map((slot) => {
|
|
17527
17553
|
const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
|
|
17528
|
-
const
|
|
17554
|
+
const result2 = results.find((r) => r.slot.id === slot.id);
|
|
17529
17555
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17530
17556
|
HStack,
|
|
17531
17557
|
{
|
|
17532
17558
|
gap: "sm",
|
|
17533
17559
|
align: "center",
|
|
17534
|
-
className: `p-3 border-2 rounded ${
|
|
17560
|
+
className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
|
|
17535
17561
|
onClick: () => handlePlaceComponent(slot.id),
|
|
17536
17562
|
children: [
|
|
17537
17563
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "flex-1", children: [
|
|
@@ -17546,7 +17572,7 @@ function BuilderBoard({
|
|
|
17546
17572
|
] }) : null,
|
|
17547
17573
|
placedComp.label
|
|
17548
17574
|
] }),
|
|
17549
|
-
|
|
17575
|
+
result2 && /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: result2.correct ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
|
|
17550
17576
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
|
|
17551
17577
|
]
|
|
17552
17578
|
},
|
|
@@ -17555,16 +17581,16 @@ function BuilderBoard({
|
|
|
17555
17581
|
}) })
|
|
17556
17582
|
] }) }),
|
|
17557
17583
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17558
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon:
|
|
17559
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children:
|
|
17584
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: "text-success" }),
|
|
17585
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
|
|
17560
17586
|
] }) }),
|
|
17561
17587
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
17562
17588
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17563
|
-
!submitted
|
|
17589
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17564
17590
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
17565
17591
|
t("builder.build")
|
|
17566
|
-
] })
|
|
17567
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick:
|
|
17592
|
+
] }),
|
|
17593
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
17568
17594
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
17569
17595
|
t("builder.reset")
|
|
17570
17596
|
] })
|
|
@@ -21020,57 +21046,84 @@ var init_ChartLegend = __esm({
|
|
|
21020
21046
|
function ClassifierBoard({
|
|
21021
21047
|
entity,
|
|
21022
21048
|
completeEvent = "PUZZLE_COMPLETE",
|
|
21049
|
+
assignEvent,
|
|
21050
|
+
checkEvent,
|
|
21051
|
+
playAgainEvent,
|
|
21023
21052
|
className
|
|
21024
21053
|
}) {
|
|
21025
21054
|
const { emit } = useEventBus();
|
|
21026
21055
|
const { t } = hooks.useTranslate();
|
|
21027
21056
|
const resolved = boardEntity(entity);
|
|
21028
|
-
const [
|
|
21057
|
+
const [localAssignments, setLocalAssignments] = React83.useState({});
|
|
21029
21058
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
21030
|
-
const [
|
|
21031
|
-
const [
|
|
21059
|
+
const [localSubmitted, setLocalSubmitted] = React83.useState(false);
|
|
21060
|
+
const [localAttempts, setLocalAttempts] = React83.useState(0);
|
|
21032
21061
|
const [showHint, setShowHint] = React83.useState(false);
|
|
21033
21062
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
21034
21063
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
21064
|
+
const entityResult = str(resolved?.result);
|
|
21065
|
+
const entityDrivesResult = entityResult.length > 0;
|
|
21066
|
+
const entityHasAssignments = items.some((item) => item.assignedCategory != null);
|
|
21067
|
+
const assignments = entityHasAssignments ? items.reduce((acc, item) => {
|
|
21068
|
+
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
21069
|
+
return acc;
|
|
21070
|
+
}, {}) : localAssignments;
|
|
21071
|
+
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
21072
|
+
const submitted = entityDrivesResult || localSubmitted;
|
|
21035
21073
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
21036
|
-
const allAssigned = Object.keys(assignments).length === items.length;
|
|
21074
|
+
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
21037
21075
|
const results = submitted ? items.map((item) => ({
|
|
21038
21076
|
item,
|
|
21039
21077
|
assigned: assignments[item.id],
|
|
21040
21078
|
correct: assignments[item.id] === item.correctCategory
|
|
21041
21079
|
})) : [];
|
|
21042
|
-
const allCorrect = results.length > 0 && results.every((r) => r.correct);
|
|
21080
|
+
const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r) => r.correct);
|
|
21043
21081
|
const correctCount = results.filter((r) => r.correct).length;
|
|
21044
21082
|
const handleAssign = (itemId, categoryId) => {
|
|
21045
21083
|
if (submitted) return;
|
|
21046
|
-
|
|
21084
|
+
if (assignEvent) {
|
|
21085
|
+
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
21086
|
+
}
|
|
21087
|
+
if (!entityHasAssignments) {
|
|
21088
|
+
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
21089
|
+
}
|
|
21047
21090
|
};
|
|
21048
21091
|
const handleUnassign = (itemId) => {
|
|
21049
21092
|
if (submitted) return;
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
|
|
21054
|
-
|
|
21093
|
+
if (!entityHasAssignments) {
|
|
21094
|
+
setLocalAssignments((prev) => {
|
|
21095
|
+
const next = { ...prev };
|
|
21096
|
+
delete next[itemId];
|
|
21097
|
+
return next;
|
|
21098
|
+
});
|
|
21099
|
+
}
|
|
21055
21100
|
};
|
|
21056
21101
|
const handleSubmit = React83.useCallback(() => {
|
|
21057
|
-
|
|
21058
|
-
|
|
21059
|
-
|
|
21060
|
-
if (
|
|
21061
|
-
|
|
21102
|
+
if (checkEvent) {
|
|
21103
|
+
emit(`UI:${checkEvent}`, {});
|
|
21104
|
+
}
|
|
21105
|
+
if (!entityDrivesResult) {
|
|
21106
|
+
setLocalSubmitted(true);
|
|
21107
|
+
setLocalAttempts((a) => a + 1);
|
|
21108
|
+
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
21109
|
+
if (correct) {
|
|
21110
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
21111
|
+
}
|
|
21062
21112
|
}
|
|
21063
|
-
}, [items, assignments, attempts, completeEvent, emit]);
|
|
21113
|
+
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
21064
21114
|
const handleReset = () => {
|
|
21065
|
-
|
|
21115
|
+
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
21066
21116
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
21067
21117
|
setShowHint(true);
|
|
21068
21118
|
}
|
|
21069
21119
|
};
|
|
21070
21120
|
const handleFullReset = () => {
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21121
|
+
if (playAgainEvent) {
|
|
21122
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
21123
|
+
}
|
|
21124
|
+
setLocalAssignments({});
|
|
21125
|
+
setLocalSubmitted(false);
|
|
21126
|
+
setLocalAttempts(0);
|
|
21074
21127
|
setShowHint(false);
|
|
21075
21128
|
};
|
|
21076
21129
|
if (!resolved) return null;
|
|
@@ -28953,13 +29006,13 @@ var init_MapView = __esm({
|
|
|
28953
29006
|
shadowSize: [41, 41]
|
|
28954
29007
|
});
|
|
28955
29008
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28956
|
-
const { useEffect:
|
|
29009
|
+
const { useEffect: useEffect73, useRef: useRef68, useCallback: useCallback111, useState: useState104 } = React83__namespace.default;
|
|
28957
29010
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28958
29011
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28959
29012
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28960
29013
|
const map = useMap();
|
|
28961
|
-
const prevRef =
|
|
28962
|
-
|
|
29014
|
+
const prevRef = useRef68({ centerLat, centerLng, zoom });
|
|
29015
|
+
useEffect73(() => {
|
|
28963
29016
|
const prev = prevRef.current;
|
|
28964
29017
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
28965
29018
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -28970,7 +29023,7 @@ var init_MapView = __esm({
|
|
|
28970
29023
|
}
|
|
28971
29024
|
function MapClickHandler({ onMapClick }) {
|
|
28972
29025
|
const map = useMap();
|
|
28973
|
-
|
|
29026
|
+
useEffect73(() => {
|
|
28974
29027
|
if (!onMapClick) return;
|
|
28975
29028
|
const handler = (e) => {
|
|
28976
29029
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -28999,7 +29052,7 @@ var init_MapView = __esm({
|
|
|
28999
29052
|
}) {
|
|
29000
29053
|
const eventBus = useEventBus2();
|
|
29001
29054
|
const [clickedPosition, setClickedPosition] = useState104(null);
|
|
29002
|
-
const handleMapClick =
|
|
29055
|
+
const handleMapClick = useCallback111((lat, lng) => {
|
|
29003
29056
|
if (showClickedPin) {
|
|
29004
29057
|
setClickedPosition({ lat, lng });
|
|
29005
29058
|
}
|
|
@@ -29008,7 +29061,7 @@ var init_MapView = __esm({
|
|
|
29008
29061
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
29009
29062
|
}
|
|
29010
29063
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
29011
|
-
const handleMarkerClick =
|
|
29064
|
+
const handleMarkerClick = useCallback111((marker) => {
|
|
29012
29065
|
onMarkerClick?.(marker);
|
|
29013
29066
|
if (markerClickEvent) {
|
|
29014
29067
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -38230,51 +38283,52 @@ var init_DataTable = __esm({
|
|
|
38230
38283
|
function DebuggerBoard({
|
|
38231
38284
|
entity,
|
|
38232
38285
|
completeEvent = "PUZZLE_COMPLETE",
|
|
38286
|
+
toggleFlagEvent,
|
|
38287
|
+
checkEvent,
|
|
38288
|
+
playAgainEvent,
|
|
38233
38289
|
className
|
|
38234
38290
|
}) {
|
|
38235
38291
|
const { emit } = useEventBus();
|
|
38236
38292
|
const { t } = hooks.useTranslate();
|
|
38237
38293
|
const resolved = boardEntity(entity);
|
|
38238
|
-
const [flaggedLines, setFlaggedLines] = React83.useState(/* @__PURE__ */ new Set());
|
|
38239
38294
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
38240
|
-
const [submitted, setSubmitted] = React83.useState(false);
|
|
38241
|
-
const [attempts, setAttempts] = React83.useState(0);
|
|
38242
38295
|
const [showHint, setShowHint] = React83.useState(false);
|
|
38296
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
38297
|
+
const result = resolved?.result ?? null;
|
|
38298
|
+
const attempts = num(resolved?.attempts);
|
|
38299
|
+
const submitted = result != null;
|
|
38300
|
+
const bugLines = lines.filter((l) => l.isBug);
|
|
38301
|
+
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
38302
|
+
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
38303
|
+
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
38304
|
+
const allCorrect = result === "win";
|
|
38243
38305
|
const toggleLine = (lineId) => {
|
|
38244
38306
|
if (submitted) return;
|
|
38245
|
-
|
|
38246
|
-
|
|
38247
|
-
|
|
38248
|
-
next.delete(lineId);
|
|
38249
|
-
} else {
|
|
38250
|
-
next.add(lineId);
|
|
38251
|
-
}
|
|
38252
|
-
return next;
|
|
38253
|
-
});
|
|
38307
|
+
if (toggleFlagEvent) {
|
|
38308
|
+
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
38309
|
+
}
|
|
38254
38310
|
};
|
|
38255
|
-
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
38256
|
-
const bugLines = lines.filter((l) => l.isBug);
|
|
38257
|
-
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
38258
|
-
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
38259
|
-
const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
38260
38311
|
const handleSubmit = React83.useCallback(() => {
|
|
38261
|
-
|
|
38262
|
-
|
|
38312
|
+
if (checkEvent) {
|
|
38313
|
+
emit(`UI:${checkEvent}`, {});
|
|
38314
|
+
}
|
|
38263
38315
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
38264
38316
|
if (correct) {
|
|
38265
38317
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
38266
38318
|
}
|
|
38267
|
-
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
38319
|
+
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
38268
38320
|
const handleReset = () => {
|
|
38269
|
-
|
|
38321
|
+
if (playAgainEvent) {
|
|
38322
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
38323
|
+
}
|
|
38270
38324
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
38271
38325
|
setShowHint(true);
|
|
38272
38326
|
}
|
|
38273
38327
|
};
|
|
38274
38328
|
const handleFullReset = () => {
|
|
38275
|
-
|
|
38276
|
-
|
|
38277
|
-
|
|
38329
|
+
if (playAgainEvent) {
|
|
38330
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
38331
|
+
}
|
|
38278
38332
|
setShowHint(false);
|
|
38279
38333
|
};
|
|
38280
38334
|
if (!resolved) return null;
|
|
@@ -38302,7 +38356,7 @@ function DebuggerBoard({
|
|
|
38302
38356
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
38303
38357
|
] }) }),
|
|
38304
38358
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
38305
|
-
const isFlagged =
|
|
38359
|
+
const isFlagged = !!line.isFlagged;
|
|
38306
38360
|
let lineStyle = "";
|
|
38307
38361
|
if (submitted) {
|
|
38308
38362
|
if (line.isBug && isFlagged) lineStyle = "bg-success/10";
|
|
@@ -38336,9 +38390,9 @@ function DebuggerBoard({
|
|
|
38336
38390
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
38337
38391
|
Icon,
|
|
38338
38392
|
{
|
|
38339
|
-
icon:
|
|
38393
|
+
icon: line.isFlagged ? LucideIcons2.CheckCircle : LucideIcons2.XCircle,
|
|
38340
38394
|
size: "xs",
|
|
38341
|
-
className:
|
|
38395
|
+
className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
|
|
38342
38396
|
}
|
|
38343
38397
|
),
|
|
38344
38398
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
@@ -38349,7 +38403,7 @@ function DebuggerBoard({
|
|
|
38349
38403
|
] }) }),
|
|
38350
38404
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
38351
38405
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
38352
|
-
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.
|
|
38406
|
+
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
38353
38407
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
38354
38408
|
t("debugger.submit")
|
|
38355
38409
|
] }) : !allCorrect ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
|
|
@@ -42113,6 +42167,9 @@ function getOpponentAction(strategy, actions, history) {
|
|
|
42113
42167
|
function NegotiatorBoard({
|
|
42114
42168
|
entity,
|
|
42115
42169
|
completeEvent = "PUZZLE_COMPLETE",
|
|
42170
|
+
playRoundEvent,
|
|
42171
|
+
finishEvent,
|
|
42172
|
+
playAgainEvent,
|
|
42116
42173
|
className
|
|
42117
42174
|
}) {
|
|
42118
42175
|
const { emit } = useEventBus();
|
|
@@ -42121,13 +42178,14 @@ function NegotiatorBoard({
|
|
|
42121
42178
|
const [history, setHistory] = React83.useState([]);
|
|
42122
42179
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
42123
42180
|
const [showHint, setShowHint] = React83.useState(false);
|
|
42124
|
-
const totalRounds = num(resolved?.
|
|
42181
|
+
const totalRounds = num(resolved?.maxRounds);
|
|
42125
42182
|
const targetScore = num(resolved?.targetScore);
|
|
42126
|
-
const currentRound =
|
|
42127
|
-
const
|
|
42128
|
-
const playerTotal =
|
|
42183
|
+
const currentRound = num(resolved?.round);
|
|
42184
|
+
const result = str(resolved?.result) || "none";
|
|
42185
|
+
const playerTotal = num(resolved?.score);
|
|
42186
|
+
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
42187
|
+
const won = result === "win";
|
|
42129
42188
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
42130
|
-
const won = isComplete && playerTotal >= targetScore;
|
|
42131
42189
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
42132
42190
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
42133
42191
|
const handleAction = React83.useCallback((actionId) => {
|
|
@@ -42136,29 +42194,45 @@ function NegotiatorBoard({
|
|
|
42136
42194
|
const payoff = payoffMatrix.find(
|
|
42137
42195
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
42138
42196
|
);
|
|
42139
|
-
const
|
|
42140
|
-
|
|
42141
|
-
|
|
42142
|
-
|
|
42143
|
-
|
|
42144
|
-
|
|
42145
|
-
|
|
42146
|
-
|
|
42147
|
-
|
|
42148
|
-
|
|
42149
|
-
|
|
42150
|
-
|
|
42151
|
-
|
|
42152
|
-
|
|
42153
|
-
|
|
42197
|
+
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
42198
|
+
setHistory((prev) => [
|
|
42199
|
+
...prev,
|
|
42200
|
+
{
|
|
42201
|
+
round: prev.length + 1,
|
|
42202
|
+
playerAction: actionId,
|
|
42203
|
+
opponentAction,
|
|
42204
|
+
playerPayoff,
|
|
42205
|
+
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
42206
|
+
}
|
|
42207
|
+
]);
|
|
42208
|
+
if (playRoundEvent) {
|
|
42209
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
|
|
42210
|
+
}
|
|
42211
|
+
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
42212
|
+
if (finishEvent) {
|
|
42213
|
+
emit(`UI:${finishEvent}`, {});
|
|
42214
|
+
}
|
|
42215
|
+
if (str(resolved?.hint)) {
|
|
42154
42216
|
setShowHint(true);
|
|
42155
42217
|
}
|
|
42156
42218
|
}
|
|
42157
|
-
}, [isComplete, resolved, totalRounds,
|
|
42158
|
-
const handleReset = () => {
|
|
42219
|
+
}, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
|
|
42220
|
+
const handleReset = React83.useCallback(() => {
|
|
42159
42221
|
setHistory([]);
|
|
42160
42222
|
setShowHint(false);
|
|
42161
|
-
|
|
42223
|
+
if (playAgainEvent) {
|
|
42224
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
42225
|
+
}
|
|
42226
|
+
}, [playAgainEvent, emit]);
|
|
42227
|
+
const completedRef = React83.useRef(false);
|
|
42228
|
+
React83.useEffect(() => {
|
|
42229
|
+
if (result === "win" && !completedRef.current) {
|
|
42230
|
+
completedRef.current = true;
|
|
42231
|
+
emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
|
|
42232
|
+
} else if (result === "none") {
|
|
42233
|
+
completedRef.current = false;
|
|
42234
|
+
}
|
|
42235
|
+
}, [result, playerTotal, completeEvent, emit]);
|
|
42162
42236
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
42163
42237
|
if (!resolved) return null;
|
|
42164
42238
|
const theme = resolved.theme ?? void 0;
|
|
@@ -45105,67 +45179,47 @@ var init_SimulationGraph = __esm({
|
|
|
45105
45179
|
function SimulatorBoard({
|
|
45106
45180
|
entity,
|
|
45107
45181
|
completeEvent = "PUZZLE_COMPLETE",
|
|
45182
|
+
setAEvent,
|
|
45183
|
+
setBEvent,
|
|
45184
|
+
checkEvent,
|
|
45185
|
+
playAgainEvent,
|
|
45108
45186
|
className
|
|
45109
45187
|
}) {
|
|
45110
45188
|
const { emit } = useEventBus();
|
|
45111
45189
|
const { t } = hooks.useTranslate();
|
|
45112
45190
|
const resolved = boardEntity(entity);
|
|
45113
45191
|
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
45114
|
-
const [values, setValues] = React83.useState(() => {
|
|
45115
|
-
const init = {};
|
|
45116
|
-
for (const p2 of parameters) {
|
|
45117
|
-
init[p2.id] = p2.initial;
|
|
45118
|
-
}
|
|
45119
|
-
return init;
|
|
45120
|
-
});
|
|
45121
45192
|
const [headerError, setHeaderError] = React83.useState(false);
|
|
45122
|
-
|
|
45123
|
-
const
|
|
45124
|
-
const
|
|
45125
|
-
const
|
|
45126
|
-
|
|
45127
|
-
|
|
45128
|
-
|
|
45129
|
-
|
|
45130
|
-
|
|
45131
|
-
|
|
45132
|
-
|
|
45133
|
-
const
|
|
45134
|
-
const
|
|
45135
|
-
const
|
|
45136
|
-
const
|
|
45137
|
-
|
|
45138
|
-
|
|
45139
|
-
|
|
45140
|
-
};
|
|
45141
|
-
const handleSubmit = () => {
|
|
45142
|
-
setSubmitted(true);
|
|
45143
|
-
setAttempts((a) => a + 1);
|
|
45144
|
-
if (isCorrect) {
|
|
45145
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
45146
|
-
}
|
|
45193
|
+
if (!resolved) return null;
|
|
45194
|
+
const paramA = num(resolved.paramA);
|
|
45195
|
+
const paramB = num(resolved.paramB);
|
|
45196
|
+
const output = num(resolved.output);
|
|
45197
|
+
const targetValue = num(resolved.target);
|
|
45198
|
+
const targetTolerance = num(resolved.tolerance);
|
|
45199
|
+
const attempts = num(resolved.attempts);
|
|
45200
|
+
const result = str(resolved.result);
|
|
45201
|
+
const isWin = result === "win";
|
|
45202
|
+
const isComplete = result !== "none" && result !== "";
|
|
45203
|
+
const paramAValue = parameters[0];
|
|
45204
|
+
const paramBValue = parameters[1];
|
|
45205
|
+
const sliderValues = [paramA, paramB];
|
|
45206
|
+
const sliderEvents = [setAEvent, setBEvent];
|
|
45207
|
+
const handleParameterChange = (index, value) => {
|
|
45208
|
+
if (isComplete) return;
|
|
45209
|
+
const ev = sliderEvents[index];
|
|
45210
|
+
if (ev) emit(`UI:${ev}`, { value });
|
|
45147
45211
|
};
|
|
45148
|
-
const
|
|
45149
|
-
|
|
45150
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
45151
|
-
setShowHint(true);
|
|
45152
|
-
}
|
|
45212
|
+
const handleCheck = () => {
|
|
45213
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
45153
45214
|
};
|
|
45154
|
-
const
|
|
45155
|
-
|
|
45156
|
-
for (const p2 of parameters) {
|
|
45157
|
-
init[p2.id] = p2.initial;
|
|
45158
|
-
}
|
|
45159
|
-
setValues(init);
|
|
45160
|
-
setSubmitted(false);
|
|
45161
|
-
setAttempts(0);
|
|
45162
|
-
setShowHint(false);
|
|
45215
|
+
const handlePlayAgain = () => {
|
|
45216
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
45163
45217
|
};
|
|
45164
|
-
if (!resolved) return null;
|
|
45165
45218
|
const theme = resolved.theme ?? void 0;
|
|
45166
45219
|
const themeBackground = theme?.background;
|
|
45167
45220
|
const headerImage = str(resolved.headerImage);
|
|
45168
45221
|
const hint = str(resolved.hint);
|
|
45222
|
+
const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
|
|
45169
45223
|
const outputLabel = str(resolved.outputLabel);
|
|
45170
45224
|
const outputUnit = str(resolved.outputUnit);
|
|
45171
45225
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -45185,41 +45239,43 @@ function SimulatorBoard({
|
|
|
45185
45239
|
] }) }),
|
|
45186
45240
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
45187
45241
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
45188
|
-
|
|
45189
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
45190
|
-
/* @__PURE__ */ jsxRuntime.
|
|
45191
|
-
|
|
45192
|
-
|
|
45193
|
-
|
|
45194
|
-
|
|
45195
|
-
|
|
45196
|
-
|
|
45197
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45198
|
-
"input",
|
|
45199
|
-
{
|
|
45200
|
-
type: "range",
|
|
45201
|
-
min: param.min,
|
|
45202
|
-
max: param.max,
|
|
45203
|
-
step: param.step,
|
|
45204
|
-
value: values[param.id],
|
|
45205
|
-
onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
|
|
45206
|
-
disabled: submitted,
|
|
45207
|
-
className: "w-full accent-foreground"
|
|
45208
|
-
}
|
|
45209
|
-
),
|
|
45210
|
-
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", children: [
|
|
45211
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45212
|
-
param.min,
|
|
45213
|
-
" ",
|
|
45214
|
-
param.unit
|
|
45242
|
+
[paramAValue, paramBValue].map(
|
|
45243
|
+
(param, index) => param ? /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
45244
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "center", children: [
|
|
45245
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
|
|
45246
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", children: [
|
|
45247
|
+
sliderValues[index],
|
|
45248
|
+
" ",
|
|
45249
|
+
param.unit
|
|
45250
|
+
] })
|
|
45215
45251
|
] }),
|
|
45216
|
-
/* @__PURE__ */ jsxRuntime.
|
|
45217
|
-
|
|
45218
|
-
|
|
45219
|
-
|
|
45252
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
45253
|
+
"input",
|
|
45254
|
+
{
|
|
45255
|
+
type: "range",
|
|
45256
|
+
min: param.min,
|
|
45257
|
+
max: param.max,
|
|
45258
|
+
step: param.step,
|
|
45259
|
+
value: sliderValues[index],
|
|
45260
|
+
onChange: (e) => handleParameterChange(index, Number(e.target.value)),
|
|
45261
|
+
disabled: isComplete,
|
|
45262
|
+
className: "w-full accent-foreground"
|
|
45263
|
+
}
|
|
45264
|
+
),
|
|
45265
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", children: [
|
|
45266
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45267
|
+
param.min,
|
|
45268
|
+
" ",
|
|
45269
|
+
param.unit
|
|
45270
|
+
] }),
|
|
45271
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45272
|
+
param.max,
|
|
45273
|
+
" ",
|
|
45274
|
+
param.unit
|
|
45275
|
+
] })
|
|
45220
45276
|
] })
|
|
45221
|
-
] })
|
|
45222
|
-
|
|
45277
|
+
] }, param.id ?? index) : null
|
|
45278
|
+
)
|
|
45223
45279
|
] }) }),
|
|
45224
45280
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
45225
45281
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
@@ -45228,9 +45284,9 @@ function SimulatorBoard({
|
|
|
45228
45284
|
" ",
|
|
45229
45285
|
outputUnit
|
|
45230
45286
|
] }),
|
|
45231
|
-
|
|
45232
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon:
|
|
45233
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className:
|
|
45287
|
+
isComplete && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
45288
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: isWin ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
|
|
45289
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className: isWin ? "text-success" : "text-error", children: isWin ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
|
|
45234
45290
|
] }),
|
|
45235
45291
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45236
45292
|
t("simulator.target"),
|
|
@@ -45245,11 +45301,11 @@ function SimulatorBoard({
|
|
|
45245
45301
|
] }) }),
|
|
45246
45302
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
45247
45303
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
45248
|
-
!
|
|
45304
|
+
!isComplete ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
|
|
45249
45305
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
45250
45306
|
t("simulator.simulate")
|
|
45251
|
-
] }) :
|
|
45252
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick:
|
|
45307
|
+
] }) : null,
|
|
45308
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
45253
45309
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
45254
45310
|
t("simulator.reset")
|
|
45255
45311
|
] })
|