@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/avl/index.cjs
CHANGED
|
@@ -8,9 +8,6 @@ var ELK = require('elkjs/lib/elk.bundled.js');
|
|
|
8
8
|
var react = require('@xyflow/react');
|
|
9
9
|
var hooks = require('@almadar/ui/hooks');
|
|
10
10
|
var LucideIcons2 = require('lucide-react');
|
|
11
|
-
var PhosphorIcons = require('@phosphor-icons/react');
|
|
12
|
-
var TablerIcons = require('@tabler/icons-react');
|
|
13
|
-
var FaIcons = require('react-icons/fa');
|
|
14
11
|
var reactDom = require('react-dom');
|
|
15
12
|
var evaluator = require('@almadar/evaluator');
|
|
16
13
|
var context = require('@almadar/ui/context');
|
|
@@ -69,9 +66,6 @@ function _interopNamespace(e) {
|
|
|
69
66
|
var React91__namespace = /*#__PURE__*/_interopNamespace(React91);
|
|
70
67
|
var ELK__default = /*#__PURE__*/_interopDefault(ELK);
|
|
71
68
|
var LucideIcons2__namespace = /*#__PURE__*/_interopNamespace(LucideIcons2);
|
|
72
|
-
var PhosphorIcons__namespace = /*#__PURE__*/_interopNamespace(PhosphorIcons);
|
|
73
|
-
var TablerIcons__namespace = /*#__PURE__*/_interopNamespace(TablerIcons);
|
|
74
|
-
var FaIcons__namespace = /*#__PURE__*/_interopNamespace(FaIcons);
|
|
75
69
|
var SyntaxHighlighter__default = /*#__PURE__*/_interopDefault(SyntaxHighlighter);
|
|
76
70
|
var dark__default = /*#__PURE__*/_interopDefault(dark);
|
|
77
71
|
var langJson__default = /*#__PURE__*/_interopDefault(langJson);
|
|
@@ -4522,6 +4516,41 @@ function kebabToPascal(name) {
|
|
|
4522
4516
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
4523
4517
|
}).join("");
|
|
4524
4518
|
}
|
|
4519
|
+
function loadLib(key, importer) {
|
|
4520
|
+
let p2 = libPromises.get(key);
|
|
4521
|
+
if (!p2) {
|
|
4522
|
+
p2 = importer().then((m) => m);
|
|
4523
|
+
libPromises.set(key, p2);
|
|
4524
|
+
}
|
|
4525
|
+
return p2;
|
|
4526
|
+
}
|
|
4527
|
+
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
4528
|
+
const Lazy = React91__namespace.default.lazy(async () => {
|
|
4529
|
+
const lib = await loadLib(libKey, importer);
|
|
4530
|
+
const Comp = pick(lib);
|
|
4531
|
+
if (!Comp) {
|
|
4532
|
+
warnFallback(fallbackName, family);
|
|
4533
|
+
return { default: makeLucideAdapter(fallbackName, true) };
|
|
4534
|
+
}
|
|
4535
|
+
return { default: Comp };
|
|
4536
|
+
});
|
|
4537
|
+
const Wrapped = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4538
|
+
React91__namespace.default.Suspense,
|
|
4539
|
+
{
|
|
4540
|
+
fallback: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4541
|
+
"span",
|
|
4542
|
+
{
|
|
4543
|
+
"aria-hidden": true,
|
|
4544
|
+
className: props.className,
|
|
4545
|
+
style: { display: "inline-block", ...props.style }
|
|
4546
|
+
}
|
|
4547
|
+
),
|
|
4548
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Lazy, { ...props })
|
|
4549
|
+
}
|
|
4550
|
+
);
|
|
4551
|
+
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
4552
|
+
return Wrapped;
|
|
4553
|
+
}
|
|
4525
4554
|
function resolveLucide(name) {
|
|
4526
4555
|
if (lucideAliases[name]) return lucideAliases[name];
|
|
4527
4556
|
const pascal = kebabToPascal(name);
|
|
@@ -4532,60 +4561,81 @@ function resolveLucide(name) {
|
|
|
4532
4561
|
if (asIs && typeof asIs === "object") return asIs;
|
|
4533
4562
|
return LucideIcons2__namespace.HelpCircle;
|
|
4534
4563
|
}
|
|
4535
|
-
function resolvePhosphor(name, weight) {
|
|
4564
|
+
function resolvePhosphor(name, weight, family) {
|
|
4536
4565
|
const target = phosphorAliases[name] ?? kebabToPascal(name);
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4566
|
+
return lazyFamilyIcon(
|
|
4567
|
+
"phosphor",
|
|
4568
|
+
() => import('@phosphor-icons/react'),
|
|
4569
|
+
(lib) => {
|
|
4570
|
+
const PhosphorComp = lib[target];
|
|
4571
|
+
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
4572
|
+
const Component = PhosphorComp;
|
|
4573
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4574
|
+
Component,
|
|
4575
|
+
{
|
|
4576
|
+
weight,
|
|
4577
|
+
className: props.className,
|
|
4578
|
+
style: props.style,
|
|
4579
|
+
size: props.size ?? "1em"
|
|
4580
|
+
}
|
|
4581
|
+
);
|
|
4582
|
+
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
4583
|
+
return Adapter;
|
|
4584
|
+
},
|
|
4585
|
+
name,
|
|
4586
|
+
family
|
|
4549
4587
|
);
|
|
4550
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
4551
|
-
return Adapter;
|
|
4552
4588
|
}
|
|
4553
|
-
function resolveTabler(name) {
|
|
4589
|
+
function resolveTabler(name, family) {
|
|
4554
4590
|
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
4555
4591
|
const target = `Icon${suffix}`;
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4592
|
+
return lazyFamilyIcon(
|
|
4593
|
+
"tabler",
|
|
4594
|
+
() => import('@tabler/icons-react'),
|
|
4595
|
+
(lib) => {
|
|
4596
|
+
const TablerComp = lib[target];
|
|
4597
|
+
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
4598
|
+
const Component = TablerComp;
|
|
4599
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4600
|
+
Component,
|
|
4601
|
+
{
|
|
4602
|
+
stroke: props.strokeWidth ?? 1.5,
|
|
4603
|
+
className: props.className,
|
|
4604
|
+
style: props.style,
|
|
4605
|
+
size: props.size ?? 24
|
|
4606
|
+
}
|
|
4607
|
+
);
|
|
4608
|
+
Adapter.displayName = `Tabler.${target}`;
|
|
4609
|
+
return Adapter;
|
|
4610
|
+
},
|
|
4611
|
+
name,
|
|
4612
|
+
family
|
|
4568
4613
|
);
|
|
4569
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
4570
|
-
return Adapter;
|
|
4571
4614
|
}
|
|
4572
|
-
function resolveFa(name) {
|
|
4615
|
+
function resolveFa(name, family) {
|
|
4573
4616
|
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
4574
4617
|
const target = `Fa${suffix}`;
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4618
|
+
return lazyFamilyIcon(
|
|
4619
|
+
"fa",
|
|
4620
|
+
() => import('react-icons/fa'),
|
|
4621
|
+
(lib) => {
|
|
4622
|
+
const FaComp = lib[target];
|
|
4623
|
+
if (!FaComp || typeof FaComp !== "function") return null;
|
|
4624
|
+
const Component = FaComp;
|
|
4625
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4626
|
+
Component,
|
|
4627
|
+
{
|
|
4628
|
+
className: props.className,
|
|
4629
|
+
style: props.style,
|
|
4630
|
+
size: props.size ?? "1em"
|
|
4631
|
+
}
|
|
4632
|
+
);
|
|
4633
|
+
Adapter.displayName = `Fa.${target}`;
|
|
4634
|
+
return Adapter;
|
|
4635
|
+
},
|
|
4636
|
+
name,
|
|
4637
|
+
family
|
|
4586
4638
|
);
|
|
4587
|
-
Adapter.displayName = `Fa.${target}`;
|
|
4588
|
-
return Adapter;
|
|
4589
4639
|
}
|
|
4590
4640
|
function warnFallback(name, family) {
|
|
4591
4641
|
const key = `${family}::${name}`;
|
|
@@ -4619,39 +4669,22 @@ function resolveIconForFamily(name, family) {
|
|
|
4619
4669
|
switch (family) {
|
|
4620
4670
|
case "lucide":
|
|
4621
4671
|
return makeLucideAdapter(name, false);
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
return
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
return
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
return makeLucideAdapter(name, true);
|
|
4639
|
-
}
|
|
4640
|
-
case "tabler": {
|
|
4641
|
-
const t = resolveTabler(name);
|
|
4642
|
-
if (t) return t;
|
|
4643
|
-
warnFallback(name, family);
|
|
4644
|
-
return makeLucideAdapter(name, true);
|
|
4645
|
-
}
|
|
4646
|
-
case "fa-solid": {
|
|
4647
|
-
const f3 = resolveFa(name);
|
|
4648
|
-
if (f3) return f3;
|
|
4649
|
-
warnFallback(name, family);
|
|
4650
|
-
return makeLucideAdapter(name, true);
|
|
4651
|
-
}
|
|
4652
|
-
}
|
|
4653
|
-
}
|
|
4654
|
-
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
4672
|
+
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
4673
|
+
// dynamic-imports the library on first render and falls back to lucide
|
|
4674
|
+
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
4675
|
+
case "phosphor-outline":
|
|
4676
|
+
return resolvePhosphor(name, "regular", family);
|
|
4677
|
+
case "phosphor-fill":
|
|
4678
|
+
return resolvePhosphor(name, "fill", family);
|
|
4679
|
+
case "phosphor-duotone":
|
|
4680
|
+
return resolvePhosphor(name, "duotone", family);
|
|
4681
|
+
case "tabler":
|
|
4682
|
+
return resolveTabler(name, family);
|
|
4683
|
+
case "fa-solid":
|
|
4684
|
+
return resolveFa(name, family);
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
4655
4688
|
var init_iconFamily = __esm({
|
|
4656
4689
|
"lib/iconFamily.tsx"() {
|
|
4657
4690
|
"use client";
|
|
@@ -4667,6 +4700,7 @@ var init_iconFamily = __esm({
|
|
|
4667
4700
|
cachedFamily = null;
|
|
4668
4701
|
listeners = /* @__PURE__ */ new Set();
|
|
4669
4702
|
observer = null;
|
|
4703
|
+
libPromises = /* @__PURE__ */ new Map();
|
|
4670
4704
|
lucideAliases = {
|
|
4671
4705
|
close: LucideIcons2__namespace.X,
|
|
4672
4706
|
trash: LucideIcons2__namespace.Trash2,
|
|
@@ -19898,61 +19932,53 @@ var init_Breadcrumb = __esm({
|
|
|
19898
19932
|
function BuilderBoard({
|
|
19899
19933
|
entity,
|
|
19900
19934
|
completeEvent = "PUZZLE_COMPLETE",
|
|
19935
|
+
placeEvent,
|
|
19936
|
+
checkEvent,
|
|
19937
|
+
playAgainEvent,
|
|
19901
19938
|
className
|
|
19902
19939
|
}) {
|
|
19903
19940
|
const { emit } = useEventBus();
|
|
19904
19941
|
const { t } = hooks.useTranslate();
|
|
19905
19942
|
const resolved = boardEntity(entity);
|
|
19906
|
-
const [placements, setPlacements] = React91.useState({});
|
|
19907
19943
|
const [headerError, setHeaderError] = React91.useState(false);
|
|
19908
|
-
const [
|
|
19909
|
-
const [attempts, setAttempts] = React91.useState(0);
|
|
19910
|
-
const [showHint, setShowHint] = React91.useState(false);
|
|
19944
|
+
const [selectedComponent, setSelectedComponent] = React91.useState(null);
|
|
19911
19945
|
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
19912
19946
|
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
19947
|
+
const placements = {};
|
|
19948
|
+
for (const slot of slots) {
|
|
19949
|
+
if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
|
|
19950
|
+
}
|
|
19951
|
+
const attempts = num(resolved?.attempts);
|
|
19952
|
+
const result = str(resolved?.result) || "none";
|
|
19953
|
+
const submitted = result === "win";
|
|
19913
19954
|
const usedComponentIds = new Set(Object.values(placements));
|
|
19914
19955
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
19915
|
-
const
|
|
19916
|
-
const allPlaced = Object.keys(placements).length === slots.length;
|
|
19956
|
+
const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
|
|
19917
19957
|
const results = submitted ? slots.map((slot) => ({
|
|
19918
19958
|
slot,
|
|
19919
19959
|
placed: placements[slot.id],
|
|
19920
|
-
correct: placements[slot.id] === slot.
|
|
19960
|
+
correct: placements[slot.id] === slot.requiredComponentId
|
|
19921
19961
|
})) : [];
|
|
19922
|
-
const
|
|
19962
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
19923
19963
|
const handlePlaceComponent = (slotId) => {
|
|
19924
19964
|
if (submitted || !selectedComponent) return;
|
|
19925
|
-
|
|
19965
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
|
|
19926
19966
|
setSelectedComponent(null);
|
|
19927
19967
|
};
|
|
19928
19968
|
const handleRemoveFromSlot = (slotId) => {
|
|
19929
19969
|
if (submitted) return;
|
|
19930
|
-
|
|
19931
|
-
const next = { ...prev };
|
|
19932
|
-
delete next[slotId];
|
|
19933
|
-
return next;
|
|
19934
|
-
});
|
|
19970
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
|
|
19935
19971
|
};
|
|
19936
|
-
const handleSubmit =
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
|
|
19940
|
-
if (correct) {
|
|
19972
|
+
const handleSubmit = () => {
|
|
19973
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
19974
|
+
const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
|
|
19975
|
+
if (solved && completeEvent) {
|
|
19941
19976
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
19942
19977
|
}
|
|
19943
|
-
}, [slots, placements, attempts, completeEvent, emit]);
|
|
19944
|
-
const handleReset = () => {
|
|
19945
|
-
setSubmitted(false);
|
|
19946
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
19947
|
-
setShowHint(true);
|
|
19948
|
-
}
|
|
19949
19978
|
};
|
|
19950
|
-
const
|
|
19951
|
-
setPlacements({});
|
|
19952
|
-
setSubmitted(false);
|
|
19979
|
+
const handlePlayAgain = () => {
|
|
19953
19980
|
setSelectedComponent(null);
|
|
19954
|
-
|
|
19955
|
-
setShowHint(false);
|
|
19981
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
19956
19982
|
};
|
|
19957
19983
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
19958
19984
|
if (!resolved) return null;
|
|
@@ -20002,13 +20028,13 @@ function BuilderBoard({
|
|
|
20002
20028
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
|
|
20003
20029
|
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", children: slots.map((slot) => {
|
|
20004
20030
|
const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
|
|
20005
|
-
const
|
|
20031
|
+
const result2 = results.find((r2) => r2.slot.id === slot.id);
|
|
20006
20032
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
20007
20033
|
HStack,
|
|
20008
20034
|
{
|
|
20009
20035
|
gap: "sm",
|
|
20010
20036
|
align: "center",
|
|
20011
|
-
className: `p-3 border-2 rounded ${
|
|
20037
|
+
className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
|
|
20012
20038
|
onClick: () => handlePlaceComponent(slot.id),
|
|
20013
20039
|
children: [
|
|
20014
20040
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "flex-1", children: [
|
|
@@ -20023,7 +20049,7 @@ function BuilderBoard({
|
|
|
20023
20049
|
] }) : null,
|
|
20024
20050
|
placedComp.label
|
|
20025
20051
|
] }),
|
|
20026
|
-
|
|
20052
|
+
result2 && /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: result2.correct ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
|
|
20027
20053
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
|
|
20028
20054
|
]
|
|
20029
20055
|
},
|
|
@@ -20032,16 +20058,16 @@ function BuilderBoard({
|
|
|
20032
20058
|
}) })
|
|
20033
20059
|
] }) }),
|
|
20034
20060
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
20035
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon:
|
|
20036
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children:
|
|
20061
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: "text-success" }),
|
|
20062
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
|
|
20037
20063
|
] }) }),
|
|
20038
20064
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
20039
20065
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
20040
|
-
!submitted
|
|
20066
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
20041
20067
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
20042
20068
|
t("builder.build")
|
|
20043
|
-
] })
|
|
20044
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick:
|
|
20069
|
+
] }),
|
|
20070
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
20045
20071
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
20046
20072
|
t("builder.reset")
|
|
20047
20073
|
] })
|
|
@@ -23497,57 +23523,84 @@ var init_ChartLegend = __esm({
|
|
|
23497
23523
|
function ClassifierBoard({
|
|
23498
23524
|
entity,
|
|
23499
23525
|
completeEvent = "PUZZLE_COMPLETE",
|
|
23526
|
+
assignEvent,
|
|
23527
|
+
checkEvent,
|
|
23528
|
+
playAgainEvent,
|
|
23500
23529
|
className
|
|
23501
23530
|
}) {
|
|
23502
23531
|
const { emit } = useEventBus();
|
|
23503
23532
|
const { t } = hooks.useTranslate();
|
|
23504
23533
|
const resolved = boardEntity(entity);
|
|
23505
|
-
const [
|
|
23534
|
+
const [localAssignments, setLocalAssignments] = React91.useState({});
|
|
23506
23535
|
const [headerError, setHeaderError] = React91.useState(false);
|
|
23507
|
-
const [
|
|
23508
|
-
const [
|
|
23536
|
+
const [localSubmitted, setLocalSubmitted] = React91.useState(false);
|
|
23537
|
+
const [localAttempts, setLocalAttempts] = React91.useState(0);
|
|
23509
23538
|
const [showHint, setShowHint] = React91.useState(false);
|
|
23510
23539
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
23511
23540
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
23541
|
+
const entityResult = str(resolved?.result);
|
|
23542
|
+
const entityDrivesResult = entityResult.length > 0;
|
|
23543
|
+
const entityHasAssignments = items.some((item) => item.assignedCategory != null);
|
|
23544
|
+
const assignments = entityHasAssignments ? items.reduce((acc, item) => {
|
|
23545
|
+
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
23546
|
+
return acc;
|
|
23547
|
+
}, {}) : localAssignments;
|
|
23548
|
+
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
23549
|
+
const submitted = entityDrivesResult || localSubmitted;
|
|
23512
23550
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
23513
|
-
const allAssigned = Object.keys(assignments).length === items.length;
|
|
23551
|
+
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
23514
23552
|
const results = submitted ? items.map((item) => ({
|
|
23515
23553
|
item,
|
|
23516
23554
|
assigned: assignments[item.id],
|
|
23517
23555
|
correct: assignments[item.id] === item.correctCategory
|
|
23518
23556
|
})) : [];
|
|
23519
|
-
const allCorrect = results.length > 0 && results.every((r2) => r2.correct);
|
|
23557
|
+
const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r2) => r2.correct);
|
|
23520
23558
|
const correctCount = results.filter((r2) => r2.correct).length;
|
|
23521
23559
|
const handleAssign = (itemId, categoryId) => {
|
|
23522
23560
|
if (submitted) return;
|
|
23523
|
-
|
|
23561
|
+
if (assignEvent) {
|
|
23562
|
+
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
23563
|
+
}
|
|
23564
|
+
if (!entityHasAssignments) {
|
|
23565
|
+
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
23566
|
+
}
|
|
23524
23567
|
};
|
|
23525
23568
|
const handleUnassign = (itemId) => {
|
|
23526
23569
|
if (submitted) return;
|
|
23527
|
-
|
|
23528
|
-
|
|
23529
|
-
|
|
23530
|
-
|
|
23531
|
-
|
|
23570
|
+
if (!entityHasAssignments) {
|
|
23571
|
+
setLocalAssignments((prev) => {
|
|
23572
|
+
const next = { ...prev };
|
|
23573
|
+
delete next[itemId];
|
|
23574
|
+
return next;
|
|
23575
|
+
});
|
|
23576
|
+
}
|
|
23532
23577
|
};
|
|
23533
23578
|
const handleSubmit = React91.useCallback(() => {
|
|
23534
|
-
|
|
23535
|
-
|
|
23536
|
-
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
23537
|
-
if (correct) {
|
|
23538
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
23579
|
+
if (checkEvent) {
|
|
23580
|
+
emit(`UI:${checkEvent}`, {});
|
|
23539
23581
|
}
|
|
23540
|
-
|
|
23582
|
+
if (!entityDrivesResult) {
|
|
23583
|
+
setLocalSubmitted(true);
|
|
23584
|
+
setLocalAttempts((a) => a + 1);
|
|
23585
|
+
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
23586
|
+
if (correct) {
|
|
23587
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
23588
|
+
}
|
|
23589
|
+
}
|
|
23590
|
+
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
23541
23591
|
const handleReset = () => {
|
|
23542
|
-
|
|
23592
|
+
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
23543
23593
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
23544
23594
|
setShowHint(true);
|
|
23545
23595
|
}
|
|
23546
23596
|
};
|
|
23547
23597
|
const handleFullReset = () => {
|
|
23548
|
-
|
|
23549
|
-
|
|
23550
|
-
|
|
23598
|
+
if (playAgainEvent) {
|
|
23599
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
23600
|
+
}
|
|
23601
|
+
setLocalAssignments({});
|
|
23602
|
+
setLocalSubmitted(false);
|
|
23603
|
+
setLocalAttempts(0);
|
|
23551
23604
|
setShowHint(false);
|
|
23552
23605
|
};
|
|
23553
23606
|
if (!resolved) return null;
|
|
@@ -31430,13 +31483,13 @@ var init_MapView = __esm({
|
|
|
31430
31483
|
shadowSize: [41, 41]
|
|
31431
31484
|
});
|
|
31432
31485
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
31433
|
-
const { useEffect:
|
|
31486
|
+
const { useEffect: useEffect78, useRef: useRef70, useCallback: useCallback117, useState: useState115 } = React91__namespace.default;
|
|
31434
31487
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
31435
31488
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
31436
31489
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
31437
31490
|
const map = useMap();
|
|
31438
|
-
const prevRef =
|
|
31439
|
-
|
|
31491
|
+
const prevRef = useRef70({ centerLat, centerLng, zoom });
|
|
31492
|
+
useEffect78(() => {
|
|
31440
31493
|
const prev = prevRef.current;
|
|
31441
31494
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
31442
31495
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -31447,7 +31500,7 @@ var init_MapView = __esm({
|
|
|
31447
31500
|
}
|
|
31448
31501
|
function MapClickHandler({ onMapClick }) {
|
|
31449
31502
|
const map = useMap();
|
|
31450
|
-
|
|
31503
|
+
useEffect78(() => {
|
|
31451
31504
|
if (!onMapClick) return;
|
|
31452
31505
|
const handler = (e) => {
|
|
31453
31506
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -31476,7 +31529,7 @@ var init_MapView = __esm({
|
|
|
31476
31529
|
}) {
|
|
31477
31530
|
const eventBus = useEventBus3();
|
|
31478
31531
|
const [clickedPosition, setClickedPosition] = useState115(null);
|
|
31479
|
-
const handleMapClick =
|
|
31532
|
+
const handleMapClick = useCallback117((lat, lng) => {
|
|
31480
31533
|
if (showClickedPin) {
|
|
31481
31534
|
setClickedPosition({ lat, lng });
|
|
31482
31535
|
}
|
|
@@ -31485,7 +31538,7 @@ var init_MapView = __esm({
|
|
|
31485
31538
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
31486
31539
|
}
|
|
31487
31540
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
31488
|
-
const handleMarkerClick =
|
|
31541
|
+
const handleMarkerClick = useCallback117((marker) => {
|
|
31489
31542
|
onMarkerClick?.(marker);
|
|
31490
31543
|
if (markerClickEvent) {
|
|
31491
31544
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -40298,51 +40351,52 @@ var init_DataTable = __esm({
|
|
|
40298
40351
|
function DebuggerBoard({
|
|
40299
40352
|
entity,
|
|
40300
40353
|
completeEvent = "PUZZLE_COMPLETE",
|
|
40354
|
+
toggleFlagEvent,
|
|
40355
|
+
checkEvent,
|
|
40356
|
+
playAgainEvent,
|
|
40301
40357
|
className
|
|
40302
40358
|
}) {
|
|
40303
40359
|
const { emit } = useEventBus();
|
|
40304
40360
|
const { t } = hooks.useTranslate();
|
|
40305
40361
|
const resolved = boardEntity(entity);
|
|
40306
|
-
const [flaggedLines, setFlaggedLines] = React91.useState(/* @__PURE__ */ new Set());
|
|
40307
40362
|
const [headerError, setHeaderError] = React91.useState(false);
|
|
40308
|
-
const [submitted, setSubmitted] = React91.useState(false);
|
|
40309
|
-
const [attempts, setAttempts] = React91.useState(0);
|
|
40310
40363
|
const [showHint, setShowHint] = React91.useState(false);
|
|
40364
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
40365
|
+
const result = resolved?.result ?? null;
|
|
40366
|
+
const attempts = num(resolved?.attempts);
|
|
40367
|
+
const submitted = result != null;
|
|
40368
|
+
const bugLines = lines.filter((l) => l.isBug);
|
|
40369
|
+
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
40370
|
+
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
40371
|
+
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
40372
|
+
const allCorrect = result === "win";
|
|
40311
40373
|
const toggleLine = (lineId) => {
|
|
40312
40374
|
if (submitted) return;
|
|
40313
|
-
|
|
40314
|
-
|
|
40315
|
-
|
|
40316
|
-
next.delete(lineId);
|
|
40317
|
-
} else {
|
|
40318
|
-
next.add(lineId);
|
|
40319
|
-
}
|
|
40320
|
-
return next;
|
|
40321
|
-
});
|
|
40375
|
+
if (toggleFlagEvent) {
|
|
40376
|
+
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
40377
|
+
}
|
|
40322
40378
|
};
|
|
40323
|
-
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
40324
|
-
const bugLines = lines.filter((l) => l.isBug);
|
|
40325
|
-
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
40326
|
-
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
40327
|
-
const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
40328
40379
|
const handleSubmit = React91.useCallback(() => {
|
|
40329
|
-
|
|
40330
|
-
|
|
40380
|
+
if (checkEvent) {
|
|
40381
|
+
emit(`UI:${checkEvent}`, {});
|
|
40382
|
+
}
|
|
40331
40383
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
40332
40384
|
if (correct) {
|
|
40333
40385
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
40334
40386
|
}
|
|
40335
|
-
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
40387
|
+
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
40336
40388
|
const handleReset = () => {
|
|
40337
|
-
|
|
40389
|
+
if (playAgainEvent) {
|
|
40390
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
40391
|
+
}
|
|
40338
40392
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
40339
40393
|
setShowHint(true);
|
|
40340
40394
|
}
|
|
40341
40395
|
};
|
|
40342
40396
|
const handleFullReset = () => {
|
|
40343
|
-
|
|
40344
|
-
|
|
40345
|
-
|
|
40397
|
+
if (playAgainEvent) {
|
|
40398
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
40399
|
+
}
|
|
40346
40400
|
setShowHint(false);
|
|
40347
40401
|
};
|
|
40348
40402
|
if (!resolved) return null;
|
|
@@ -40370,7 +40424,7 @@ function DebuggerBoard({
|
|
|
40370
40424
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
40371
40425
|
] }) }),
|
|
40372
40426
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
40373
|
-
const isFlagged =
|
|
40427
|
+
const isFlagged = !!line.isFlagged;
|
|
40374
40428
|
let lineStyle = "";
|
|
40375
40429
|
if (submitted) {
|
|
40376
40430
|
if (line.isBug && isFlagged) lineStyle = "bg-success/10";
|
|
@@ -40404,9 +40458,9 @@ function DebuggerBoard({
|
|
|
40404
40458
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
40405
40459
|
Icon,
|
|
40406
40460
|
{
|
|
40407
|
-
icon:
|
|
40461
|
+
icon: line.isFlagged ? LucideIcons2.CheckCircle : LucideIcons2.XCircle,
|
|
40408
40462
|
size: "xs",
|
|
40409
|
-
className:
|
|
40463
|
+
className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
|
|
40410
40464
|
}
|
|
40411
40465
|
),
|
|
40412
40466
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
@@ -40417,7 +40471,7 @@ function DebuggerBoard({
|
|
|
40417
40471
|
] }) }),
|
|
40418
40472
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
40419
40473
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
40420
|
-
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.
|
|
40474
|
+
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
40421
40475
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
40422
40476
|
t("debugger.submit")
|
|
40423
40477
|
] }) : !allCorrect ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
|
|
@@ -44181,6 +44235,9 @@ function getOpponentAction(strategy, actions, history) {
|
|
|
44181
44235
|
function NegotiatorBoard({
|
|
44182
44236
|
entity,
|
|
44183
44237
|
completeEvent = "PUZZLE_COMPLETE",
|
|
44238
|
+
playRoundEvent,
|
|
44239
|
+
finishEvent,
|
|
44240
|
+
playAgainEvent,
|
|
44184
44241
|
className
|
|
44185
44242
|
}) {
|
|
44186
44243
|
const { emit } = useEventBus();
|
|
@@ -44189,13 +44246,14 @@ function NegotiatorBoard({
|
|
|
44189
44246
|
const [history, setHistory] = React91.useState([]);
|
|
44190
44247
|
const [headerError, setHeaderError] = React91.useState(false);
|
|
44191
44248
|
const [showHint, setShowHint] = React91.useState(false);
|
|
44192
|
-
const totalRounds = num(resolved?.
|
|
44249
|
+
const totalRounds = num(resolved?.maxRounds);
|
|
44193
44250
|
const targetScore = num(resolved?.targetScore);
|
|
44194
|
-
const currentRound =
|
|
44195
|
-
const
|
|
44196
|
-
const playerTotal =
|
|
44251
|
+
const currentRound = num(resolved?.round);
|
|
44252
|
+
const result = str(resolved?.result) || "none";
|
|
44253
|
+
const playerTotal = num(resolved?.score);
|
|
44254
|
+
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
44255
|
+
const won = result === "win";
|
|
44197
44256
|
const opponentTotal = history.reduce((s, r2) => s + r2.opponentPayoff, 0);
|
|
44198
|
-
const won = isComplete && playerTotal >= targetScore;
|
|
44199
44257
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
44200
44258
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
44201
44259
|
const handleAction = React91.useCallback((actionId) => {
|
|
@@ -44204,29 +44262,45 @@ function NegotiatorBoard({
|
|
|
44204
44262
|
const payoff = payoffMatrix.find(
|
|
44205
44263
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
44206
44264
|
);
|
|
44207
|
-
const
|
|
44208
|
-
|
|
44209
|
-
|
|
44210
|
-
|
|
44211
|
-
|
|
44212
|
-
|
|
44213
|
-
|
|
44214
|
-
|
|
44215
|
-
|
|
44216
|
-
|
|
44217
|
-
|
|
44218
|
-
|
|
44219
|
-
|
|
44220
|
-
|
|
44221
|
-
|
|
44265
|
+
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
44266
|
+
setHistory((prev) => [
|
|
44267
|
+
...prev,
|
|
44268
|
+
{
|
|
44269
|
+
round: prev.length + 1,
|
|
44270
|
+
playerAction: actionId,
|
|
44271
|
+
opponentAction,
|
|
44272
|
+
playerPayoff,
|
|
44273
|
+
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
44274
|
+
}
|
|
44275
|
+
]);
|
|
44276
|
+
if (playRoundEvent) {
|
|
44277
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
|
|
44278
|
+
}
|
|
44279
|
+
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
44280
|
+
if (finishEvent) {
|
|
44281
|
+
emit(`UI:${finishEvent}`, {});
|
|
44282
|
+
}
|
|
44283
|
+
if (str(resolved?.hint)) {
|
|
44222
44284
|
setShowHint(true);
|
|
44223
44285
|
}
|
|
44224
44286
|
}
|
|
44225
|
-
}, [isComplete, resolved, totalRounds,
|
|
44226
|
-
const handleReset = () => {
|
|
44287
|
+
}, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
|
|
44288
|
+
const handleReset = React91.useCallback(() => {
|
|
44227
44289
|
setHistory([]);
|
|
44228
44290
|
setShowHint(false);
|
|
44229
|
-
|
|
44291
|
+
if (playAgainEvent) {
|
|
44292
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
44293
|
+
}
|
|
44294
|
+
}, [playAgainEvent, emit]);
|
|
44295
|
+
const completedRef = React91.useRef(false);
|
|
44296
|
+
React91.useEffect(() => {
|
|
44297
|
+
if (result === "win" && !completedRef.current) {
|
|
44298
|
+
completedRef.current = true;
|
|
44299
|
+
emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
|
|
44300
|
+
} else if (result === "none") {
|
|
44301
|
+
completedRef.current = false;
|
|
44302
|
+
}
|
|
44303
|
+
}, [result, playerTotal, completeEvent, emit]);
|
|
44230
44304
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
44231
44305
|
if (!resolved) return null;
|
|
44232
44306
|
const theme = resolved.theme ?? void 0;
|
|
@@ -47192,67 +47266,47 @@ var init_SimulationGraph = __esm({
|
|
|
47192
47266
|
function SimulatorBoard({
|
|
47193
47267
|
entity,
|
|
47194
47268
|
completeEvent = "PUZZLE_COMPLETE",
|
|
47269
|
+
setAEvent,
|
|
47270
|
+
setBEvent,
|
|
47271
|
+
checkEvent,
|
|
47272
|
+
playAgainEvent,
|
|
47195
47273
|
className
|
|
47196
47274
|
}) {
|
|
47197
47275
|
const { emit } = useEventBus();
|
|
47198
47276
|
const { t } = hooks.useTranslate();
|
|
47199
47277
|
const resolved = boardEntity(entity);
|
|
47200
47278
|
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
47201
|
-
const [values, setValues] = React91.useState(() => {
|
|
47202
|
-
const init = {};
|
|
47203
|
-
for (const p2 of parameters) {
|
|
47204
|
-
init[p2.id] = p2.initial;
|
|
47205
|
-
}
|
|
47206
|
-
return init;
|
|
47207
|
-
});
|
|
47208
47279
|
const [headerError, setHeaderError] = React91.useState(false);
|
|
47209
|
-
|
|
47210
|
-
const
|
|
47211
|
-
const
|
|
47212
|
-
const
|
|
47213
|
-
|
|
47214
|
-
|
|
47215
|
-
|
|
47216
|
-
|
|
47217
|
-
|
|
47218
|
-
|
|
47219
|
-
|
|
47220
|
-
const
|
|
47221
|
-
const
|
|
47222
|
-
const
|
|
47223
|
-
const
|
|
47224
|
-
|
|
47225
|
-
|
|
47226
|
-
|
|
47227
|
-
};
|
|
47228
|
-
const handleSubmit = () => {
|
|
47229
|
-
setSubmitted(true);
|
|
47230
|
-
setAttempts((a) => a + 1);
|
|
47231
|
-
if (isCorrect) {
|
|
47232
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
47233
|
-
}
|
|
47280
|
+
if (!resolved) return null;
|
|
47281
|
+
const paramA = num(resolved.paramA);
|
|
47282
|
+
const paramB = num(resolved.paramB);
|
|
47283
|
+
const output = num(resolved.output);
|
|
47284
|
+
const targetValue = num(resolved.target);
|
|
47285
|
+
const targetTolerance = num(resolved.tolerance);
|
|
47286
|
+
const attempts = num(resolved.attempts);
|
|
47287
|
+
const result = str(resolved.result);
|
|
47288
|
+
const isWin = result === "win";
|
|
47289
|
+
const isComplete = result !== "none" && result !== "";
|
|
47290
|
+
const paramAValue = parameters[0];
|
|
47291
|
+
const paramBValue = parameters[1];
|
|
47292
|
+
const sliderValues = [paramA, paramB];
|
|
47293
|
+
const sliderEvents = [setAEvent, setBEvent];
|
|
47294
|
+
const handleParameterChange = (index, value) => {
|
|
47295
|
+
if (isComplete) return;
|
|
47296
|
+
const ev = sliderEvents[index];
|
|
47297
|
+
if (ev) emit(`UI:${ev}`, { value });
|
|
47234
47298
|
};
|
|
47235
|
-
const
|
|
47236
|
-
|
|
47237
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
47238
|
-
setShowHint(true);
|
|
47239
|
-
}
|
|
47299
|
+
const handleCheck = () => {
|
|
47300
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
47240
47301
|
};
|
|
47241
|
-
const
|
|
47242
|
-
|
|
47243
|
-
for (const p2 of parameters) {
|
|
47244
|
-
init[p2.id] = p2.initial;
|
|
47245
|
-
}
|
|
47246
|
-
setValues(init);
|
|
47247
|
-
setSubmitted(false);
|
|
47248
|
-
setAttempts(0);
|
|
47249
|
-
setShowHint(false);
|
|
47302
|
+
const handlePlayAgain = () => {
|
|
47303
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
47250
47304
|
};
|
|
47251
|
-
if (!resolved) return null;
|
|
47252
47305
|
const theme = resolved.theme ?? void 0;
|
|
47253
47306
|
const themeBackground = theme?.background;
|
|
47254
47307
|
const headerImage = str(resolved.headerImage);
|
|
47255
47308
|
const hint = str(resolved.hint);
|
|
47309
|
+
const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
|
|
47256
47310
|
const outputLabel = str(resolved.outputLabel);
|
|
47257
47311
|
const outputUnit = str(resolved.outputUnit);
|
|
47258
47312
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -47272,41 +47326,43 @@ function SimulatorBoard({
|
|
|
47272
47326
|
] }) }),
|
|
47273
47327
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
47274
47328
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
47275
|
-
|
|
47276
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
47277
|
-
/* @__PURE__ */ jsxRuntime.
|
|
47278
|
-
|
|
47279
|
-
|
|
47280
|
-
|
|
47281
|
-
|
|
47282
|
-
|
|
47283
|
-
|
|
47284
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
47285
|
-
"input",
|
|
47286
|
-
{
|
|
47287
|
-
type: "range",
|
|
47288
|
-
min: param.min,
|
|
47289
|
-
max: param.max,
|
|
47290
|
-
step: param.step,
|
|
47291
|
-
value: values[param.id],
|
|
47292
|
-
onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
|
|
47293
|
-
disabled: submitted,
|
|
47294
|
-
className: "w-full accent-foreground"
|
|
47295
|
-
}
|
|
47296
|
-
),
|
|
47297
|
-
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", children: [
|
|
47298
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47299
|
-
param.min,
|
|
47300
|
-
" ",
|
|
47301
|
-
param.unit
|
|
47329
|
+
[paramAValue, paramBValue].map(
|
|
47330
|
+
(param, index) => param ? /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
47331
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "center", children: [
|
|
47332
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
|
|
47333
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", children: [
|
|
47334
|
+
sliderValues[index],
|
|
47335
|
+
" ",
|
|
47336
|
+
param.unit
|
|
47337
|
+
] })
|
|
47302
47338
|
] }),
|
|
47303
|
-
/* @__PURE__ */ jsxRuntime.
|
|
47304
|
-
|
|
47305
|
-
|
|
47306
|
-
|
|
47339
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
47340
|
+
"input",
|
|
47341
|
+
{
|
|
47342
|
+
type: "range",
|
|
47343
|
+
min: param.min,
|
|
47344
|
+
max: param.max,
|
|
47345
|
+
step: param.step,
|
|
47346
|
+
value: sliderValues[index],
|
|
47347
|
+
onChange: (e) => handleParameterChange(index, Number(e.target.value)),
|
|
47348
|
+
disabled: isComplete,
|
|
47349
|
+
className: "w-full accent-foreground"
|
|
47350
|
+
}
|
|
47351
|
+
),
|
|
47352
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", children: [
|
|
47353
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47354
|
+
param.min,
|
|
47355
|
+
" ",
|
|
47356
|
+
param.unit
|
|
47357
|
+
] }),
|
|
47358
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47359
|
+
param.max,
|
|
47360
|
+
" ",
|
|
47361
|
+
param.unit
|
|
47362
|
+
] })
|
|
47307
47363
|
] })
|
|
47308
|
-
] })
|
|
47309
|
-
|
|
47364
|
+
] }, param.id ?? index) : null
|
|
47365
|
+
)
|
|
47310
47366
|
] }) }),
|
|
47311
47367
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
47312
47368
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
@@ -47315,9 +47371,9 @@ function SimulatorBoard({
|
|
|
47315
47371
|
" ",
|
|
47316
47372
|
outputUnit
|
|
47317
47373
|
] }),
|
|
47318
|
-
|
|
47319
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon:
|
|
47320
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className:
|
|
47374
|
+
isComplete && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
47375
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: isWin ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
|
|
47376
|
+
/* @__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") })
|
|
47321
47377
|
] }),
|
|
47322
47378
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47323
47379
|
t("simulator.target"),
|
|
@@ -47332,11 +47388,11 @@ function SimulatorBoard({
|
|
|
47332
47388
|
] }) }),
|
|
47333
47389
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
47334
47390
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
47335
|
-
!
|
|
47391
|
+
!isComplete ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
|
|
47336
47392
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
47337
47393
|
t("simulator.simulate")
|
|
47338
|
-
] }) :
|
|
47339
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick:
|
|
47394
|
+
] }) : null,
|
|
47395
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
47340
47396
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
47341
47397
|
t("simulator.reset")
|
|
47342
47398
|
] })
|