@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/runtime/index.cjs
CHANGED
|
@@ -7,9 +7,6 @@ var tailwindMerge = require('tailwind-merge');
|
|
|
7
7
|
var providers = require('@almadar/ui/providers');
|
|
8
8
|
var logger = require('@almadar/logger');
|
|
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');
|
|
@@ -70,9 +67,6 @@ function _interopNamespace(e) {
|
|
|
70
67
|
|
|
71
68
|
var React82__namespace = /*#__PURE__*/_interopNamespace(React82);
|
|
72
69
|
var LucideIcons2__namespace = /*#__PURE__*/_interopNamespace(LucideIcons2);
|
|
73
|
-
var PhosphorIcons__namespace = /*#__PURE__*/_interopNamespace(PhosphorIcons);
|
|
74
|
-
var TablerIcons__namespace = /*#__PURE__*/_interopNamespace(TablerIcons);
|
|
75
|
-
var FaIcons__namespace = /*#__PURE__*/_interopNamespace(FaIcons);
|
|
76
70
|
var ELK__default = /*#__PURE__*/_interopDefault(ELK);
|
|
77
71
|
var SyntaxHighlighter__default = /*#__PURE__*/_interopDefault(SyntaxHighlighter);
|
|
78
72
|
var dark__default = /*#__PURE__*/_interopDefault(dark);
|
|
@@ -578,6 +572,41 @@ function kebabToPascal(name) {
|
|
|
578
572
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
579
573
|
}).join("");
|
|
580
574
|
}
|
|
575
|
+
function loadLib(key, importer) {
|
|
576
|
+
let p2 = libPromises.get(key);
|
|
577
|
+
if (!p2) {
|
|
578
|
+
p2 = importer().then((m) => m);
|
|
579
|
+
libPromises.set(key, p2);
|
|
580
|
+
}
|
|
581
|
+
return p2;
|
|
582
|
+
}
|
|
583
|
+
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
584
|
+
const Lazy = React82__namespace.default.lazy(async () => {
|
|
585
|
+
const lib = await loadLib(libKey, importer);
|
|
586
|
+
const Comp = pick(lib);
|
|
587
|
+
if (!Comp) {
|
|
588
|
+
warnFallback(fallbackName, family);
|
|
589
|
+
return { default: makeLucideAdapter(fallbackName, true) };
|
|
590
|
+
}
|
|
591
|
+
return { default: Comp };
|
|
592
|
+
});
|
|
593
|
+
const Wrapped = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
594
|
+
React82__namespace.default.Suspense,
|
|
595
|
+
{
|
|
596
|
+
fallback: /* @__PURE__ */ jsxRuntime.jsx(
|
|
597
|
+
"span",
|
|
598
|
+
{
|
|
599
|
+
"aria-hidden": true,
|
|
600
|
+
className: props.className,
|
|
601
|
+
style: { display: "inline-block", ...props.style }
|
|
602
|
+
}
|
|
603
|
+
),
|
|
604
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Lazy, { ...props })
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
608
|
+
return Wrapped;
|
|
609
|
+
}
|
|
581
610
|
function resolveLucide(name) {
|
|
582
611
|
if (lucideAliases[name]) return lucideAliases[name];
|
|
583
612
|
const pascal = kebabToPascal(name);
|
|
@@ -588,60 +617,81 @@ function resolveLucide(name) {
|
|
|
588
617
|
if (asIs && typeof asIs === "object") return asIs;
|
|
589
618
|
return LucideIcons2__namespace.HelpCircle;
|
|
590
619
|
}
|
|
591
|
-
function resolvePhosphor(name, weight) {
|
|
620
|
+
function resolvePhosphor(name, weight, family) {
|
|
592
621
|
const target = phosphorAliases[name] ?? kebabToPascal(name);
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
622
|
+
return lazyFamilyIcon(
|
|
623
|
+
"phosphor",
|
|
624
|
+
() => import('@phosphor-icons/react'),
|
|
625
|
+
(lib) => {
|
|
626
|
+
const PhosphorComp = lib[target];
|
|
627
|
+
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
628
|
+
const Component = PhosphorComp;
|
|
629
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
630
|
+
Component,
|
|
631
|
+
{
|
|
632
|
+
weight,
|
|
633
|
+
className: props.className,
|
|
634
|
+
style: props.style,
|
|
635
|
+
size: props.size ?? "1em"
|
|
636
|
+
}
|
|
637
|
+
);
|
|
638
|
+
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
639
|
+
return Adapter;
|
|
640
|
+
},
|
|
641
|
+
name,
|
|
642
|
+
family
|
|
605
643
|
);
|
|
606
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
607
|
-
return Adapter;
|
|
608
644
|
}
|
|
609
|
-
function resolveTabler(name) {
|
|
645
|
+
function resolveTabler(name, family) {
|
|
610
646
|
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
611
647
|
const target = `Icon${suffix}`;
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
648
|
+
return lazyFamilyIcon(
|
|
649
|
+
"tabler",
|
|
650
|
+
() => import('@tabler/icons-react'),
|
|
651
|
+
(lib) => {
|
|
652
|
+
const TablerComp = lib[target];
|
|
653
|
+
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
654
|
+
const Component = TablerComp;
|
|
655
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
656
|
+
Component,
|
|
657
|
+
{
|
|
658
|
+
stroke: props.strokeWidth ?? 1.5,
|
|
659
|
+
className: props.className,
|
|
660
|
+
style: props.style,
|
|
661
|
+
size: props.size ?? 24
|
|
662
|
+
}
|
|
663
|
+
);
|
|
664
|
+
Adapter.displayName = `Tabler.${target}`;
|
|
665
|
+
return Adapter;
|
|
666
|
+
},
|
|
667
|
+
name,
|
|
668
|
+
family
|
|
624
669
|
);
|
|
625
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
626
|
-
return Adapter;
|
|
627
670
|
}
|
|
628
|
-
function resolveFa(name) {
|
|
671
|
+
function resolveFa(name, family) {
|
|
629
672
|
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
630
673
|
const target = `Fa${suffix}`;
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
674
|
+
return lazyFamilyIcon(
|
|
675
|
+
"fa",
|
|
676
|
+
() => import('react-icons/fa'),
|
|
677
|
+
(lib) => {
|
|
678
|
+
const FaComp = lib[target];
|
|
679
|
+
if (!FaComp || typeof FaComp !== "function") return null;
|
|
680
|
+
const Component = FaComp;
|
|
681
|
+
const Adapter = (props) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
682
|
+
Component,
|
|
683
|
+
{
|
|
684
|
+
className: props.className,
|
|
685
|
+
style: props.style,
|
|
686
|
+
size: props.size ?? "1em"
|
|
687
|
+
}
|
|
688
|
+
);
|
|
689
|
+
Adapter.displayName = `Fa.${target}`;
|
|
690
|
+
return Adapter;
|
|
691
|
+
},
|
|
692
|
+
name,
|
|
693
|
+
family
|
|
642
694
|
);
|
|
643
|
-
Adapter.displayName = `Fa.${target}`;
|
|
644
|
-
return Adapter;
|
|
645
695
|
}
|
|
646
696
|
function warnFallback(name, family) {
|
|
647
697
|
const key = `${family}::${name}`;
|
|
@@ -675,39 +725,22 @@ function resolveIconForFamily(name, family) {
|
|
|
675
725
|
switch (family) {
|
|
676
726
|
case "lucide":
|
|
677
727
|
return makeLucideAdapter(name, false);
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
return
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
return
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
return makeLucideAdapter(name, true);
|
|
695
|
-
}
|
|
696
|
-
case "tabler": {
|
|
697
|
-
const t = resolveTabler(name);
|
|
698
|
-
if (t) return t;
|
|
699
|
-
warnFallback(name, family);
|
|
700
|
-
return makeLucideAdapter(name, true);
|
|
701
|
-
}
|
|
702
|
-
case "fa-solid": {
|
|
703
|
-
const f3 = resolveFa(name);
|
|
704
|
-
if (f3) return f3;
|
|
705
|
-
warnFallback(name, family);
|
|
706
|
-
return makeLucideAdapter(name, true);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
728
|
+
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
729
|
+
// dynamic-imports the library on first render and falls back to lucide
|
|
730
|
+
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
731
|
+
case "phosphor-outline":
|
|
732
|
+
return resolvePhosphor(name, "regular", family);
|
|
733
|
+
case "phosphor-fill":
|
|
734
|
+
return resolvePhosphor(name, "fill", family);
|
|
735
|
+
case "phosphor-duotone":
|
|
736
|
+
return resolvePhosphor(name, "duotone", family);
|
|
737
|
+
case "tabler":
|
|
738
|
+
return resolveTabler(name, family);
|
|
739
|
+
case "fa-solid":
|
|
740
|
+
return resolveFa(name, family);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
711
744
|
var init_iconFamily = __esm({
|
|
712
745
|
"lib/iconFamily.tsx"() {
|
|
713
746
|
"use client";
|
|
@@ -723,6 +756,7 @@ var init_iconFamily = __esm({
|
|
|
723
756
|
cachedFamily = null;
|
|
724
757
|
listeners = /* @__PURE__ */ new Set();
|
|
725
758
|
observer = null;
|
|
759
|
+
libPromises = /* @__PURE__ */ new Map();
|
|
726
760
|
lucideAliases = {
|
|
727
761
|
close: LucideIcons2__namespace.X,
|
|
728
762
|
trash: LucideIcons2__namespace.Trash2,
|
|
@@ -16988,61 +17022,53 @@ var init_Breadcrumb = __esm({
|
|
|
16988
17022
|
function BuilderBoard({
|
|
16989
17023
|
entity,
|
|
16990
17024
|
completeEvent = "PUZZLE_COMPLETE",
|
|
17025
|
+
placeEvent,
|
|
17026
|
+
checkEvent,
|
|
17027
|
+
playAgainEvent,
|
|
16991
17028
|
className
|
|
16992
17029
|
}) {
|
|
16993
17030
|
const { emit } = useEventBus();
|
|
16994
17031
|
const { t } = hooks.useTranslate();
|
|
16995
17032
|
const resolved = boardEntity(entity);
|
|
16996
|
-
const [placements, setPlacements] = React82.useState({});
|
|
16997
17033
|
const [headerError, setHeaderError] = React82.useState(false);
|
|
16998
|
-
const [
|
|
16999
|
-
const [attempts, setAttempts] = React82.useState(0);
|
|
17000
|
-
const [showHint, setShowHint] = React82.useState(false);
|
|
17034
|
+
const [selectedComponent, setSelectedComponent] = React82.useState(null);
|
|
17001
17035
|
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
17002
17036
|
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
17037
|
+
const placements = {};
|
|
17038
|
+
for (const slot of slots) {
|
|
17039
|
+
if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
|
|
17040
|
+
}
|
|
17041
|
+
const attempts = num(resolved?.attempts);
|
|
17042
|
+
const result = str(resolved?.result) || "none";
|
|
17043
|
+
const submitted = result === "win";
|
|
17003
17044
|
const usedComponentIds = new Set(Object.values(placements));
|
|
17004
17045
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
17005
|
-
const
|
|
17006
|
-
const allPlaced = Object.keys(placements).length === slots.length;
|
|
17046
|
+
const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
|
|
17007
17047
|
const results = submitted ? slots.map((slot) => ({
|
|
17008
17048
|
slot,
|
|
17009
17049
|
placed: placements[slot.id],
|
|
17010
|
-
correct: placements[slot.id] === slot.
|
|
17050
|
+
correct: placements[slot.id] === slot.requiredComponentId
|
|
17011
17051
|
})) : [];
|
|
17012
|
-
const
|
|
17052
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
17013
17053
|
const handlePlaceComponent = (slotId) => {
|
|
17014
17054
|
if (submitted || !selectedComponent) return;
|
|
17015
|
-
|
|
17055
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
|
|
17016
17056
|
setSelectedComponent(null);
|
|
17017
17057
|
};
|
|
17018
17058
|
const handleRemoveFromSlot = (slotId) => {
|
|
17019
17059
|
if (submitted) return;
|
|
17020
|
-
|
|
17021
|
-
const next = { ...prev };
|
|
17022
|
-
delete next[slotId];
|
|
17023
|
-
return next;
|
|
17024
|
-
});
|
|
17060
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
|
|
17025
17061
|
};
|
|
17026
|
-
const handleSubmit =
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
if (correct) {
|
|
17062
|
+
const handleSubmit = () => {
|
|
17063
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
17064
|
+
const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
|
|
17065
|
+
if (solved && completeEvent) {
|
|
17031
17066
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
17032
17067
|
}
|
|
17033
|
-
}, [slots, placements, attempts, completeEvent, emit]);
|
|
17034
|
-
const handleReset = () => {
|
|
17035
|
-
setSubmitted(false);
|
|
17036
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
17037
|
-
setShowHint(true);
|
|
17038
|
-
}
|
|
17039
17068
|
};
|
|
17040
|
-
const
|
|
17041
|
-
setPlacements({});
|
|
17042
|
-
setSubmitted(false);
|
|
17069
|
+
const handlePlayAgain = () => {
|
|
17043
17070
|
setSelectedComponent(null);
|
|
17044
|
-
|
|
17045
|
-
setShowHint(false);
|
|
17071
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
17046
17072
|
};
|
|
17047
17073
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
17048
17074
|
if (!resolved) return null;
|
|
@@ -17092,13 +17118,13 @@ function BuilderBoard({
|
|
|
17092
17118
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
|
|
17093
17119
|
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "sm", children: slots.map((slot) => {
|
|
17094
17120
|
const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
|
|
17095
|
-
const
|
|
17121
|
+
const result2 = results.find((r) => r.slot.id === slot.id);
|
|
17096
17122
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17097
17123
|
HStack,
|
|
17098
17124
|
{
|
|
17099
17125
|
gap: "sm",
|
|
17100
17126
|
align: "center",
|
|
17101
|
-
className: `p-3 border-2 rounded ${
|
|
17127
|
+
className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
|
|
17102
17128
|
onClick: () => handlePlaceComponent(slot.id),
|
|
17103
17129
|
children: [
|
|
17104
17130
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "flex-1", children: [
|
|
@@ -17113,7 +17139,7 @@ function BuilderBoard({
|
|
|
17113
17139
|
] }) : null,
|
|
17114
17140
|
placedComp.label
|
|
17115
17141
|
] }),
|
|
17116
|
-
|
|
17142
|
+
result2 && /* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: result2.correct ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
|
|
17117
17143
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
|
|
17118
17144
|
]
|
|
17119
17145
|
},
|
|
@@ -17122,16 +17148,16 @@ function BuilderBoard({
|
|
|
17122
17148
|
}) })
|
|
17123
17149
|
] }) }),
|
|
17124
17150
|
submitted && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17125
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon:
|
|
17126
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children:
|
|
17151
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.CheckCircle, size: "lg", className: "text-success" }),
|
|
17152
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
|
|
17127
17153
|
] }) }),
|
|
17128
17154
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
17129
17155
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17130
|
-
!submitted
|
|
17156
|
+
!submitted && /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17131
17157
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Wrench, size: "sm" }),
|
|
17132
17158
|
t("builder.build")
|
|
17133
|
-
] })
|
|
17134
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick:
|
|
17159
|
+
] }),
|
|
17160
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
17135
17161
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
17136
17162
|
t("builder.reset")
|
|
17137
17163
|
] })
|
|
@@ -20587,57 +20613,84 @@ var init_ChartLegend = __esm({
|
|
|
20587
20613
|
function ClassifierBoard({
|
|
20588
20614
|
entity,
|
|
20589
20615
|
completeEvent = "PUZZLE_COMPLETE",
|
|
20616
|
+
assignEvent,
|
|
20617
|
+
checkEvent,
|
|
20618
|
+
playAgainEvent,
|
|
20590
20619
|
className
|
|
20591
20620
|
}) {
|
|
20592
20621
|
const { emit } = useEventBus();
|
|
20593
20622
|
const { t } = hooks.useTranslate();
|
|
20594
20623
|
const resolved = boardEntity(entity);
|
|
20595
|
-
const [
|
|
20624
|
+
const [localAssignments, setLocalAssignments] = React82.useState({});
|
|
20596
20625
|
const [headerError, setHeaderError] = React82.useState(false);
|
|
20597
|
-
const [
|
|
20598
|
-
const [
|
|
20626
|
+
const [localSubmitted, setLocalSubmitted] = React82.useState(false);
|
|
20627
|
+
const [localAttempts, setLocalAttempts] = React82.useState(0);
|
|
20599
20628
|
const [showHint, setShowHint] = React82.useState(false);
|
|
20600
20629
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
20601
20630
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
20631
|
+
const entityResult = str(resolved?.result);
|
|
20632
|
+
const entityDrivesResult = entityResult.length > 0;
|
|
20633
|
+
const entityHasAssignments = items.some((item) => item.assignedCategory != null);
|
|
20634
|
+
const assignments = entityHasAssignments ? items.reduce((acc, item) => {
|
|
20635
|
+
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
20636
|
+
return acc;
|
|
20637
|
+
}, {}) : localAssignments;
|
|
20638
|
+
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
20639
|
+
const submitted = entityDrivesResult || localSubmitted;
|
|
20602
20640
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
20603
|
-
const allAssigned = Object.keys(assignments).length === items.length;
|
|
20641
|
+
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
20604
20642
|
const results = submitted ? items.map((item) => ({
|
|
20605
20643
|
item,
|
|
20606
20644
|
assigned: assignments[item.id],
|
|
20607
20645
|
correct: assignments[item.id] === item.correctCategory
|
|
20608
20646
|
})) : [];
|
|
20609
|
-
const allCorrect = results.length > 0 && results.every((r) => r.correct);
|
|
20647
|
+
const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r) => r.correct);
|
|
20610
20648
|
const correctCount = results.filter((r) => r.correct).length;
|
|
20611
20649
|
const handleAssign = (itemId, categoryId) => {
|
|
20612
20650
|
if (submitted) return;
|
|
20613
|
-
|
|
20651
|
+
if (assignEvent) {
|
|
20652
|
+
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
20653
|
+
}
|
|
20654
|
+
if (!entityHasAssignments) {
|
|
20655
|
+
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
20656
|
+
}
|
|
20614
20657
|
};
|
|
20615
20658
|
const handleUnassign = (itemId) => {
|
|
20616
20659
|
if (submitted) return;
|
|
20617
|
-
|
|
20618
|
-
|
|
20619
|
-
|
|
20620
|
-
|
|
20621
|
-
|
|
20660
|
+
if (!entityHasAssignments) {
|
|
20661
|
+
setLocalAssignments((prev) => {
|
|
20662
|
+
const next = { ...prev };
|
|
20663
|
+
delete next[itemId];
|
|
20664
|
+
return next;
|
|
20665
|
+
});
|
|
20666
|
+
}
|
|
20622
20667
|
};
|
|
20623
20668
|
const handleSubmit = React82.useCallback(() => {
|
|
20624
|
-
|
|
20625
|
-
|
|
20626
|
-
|
|
20627
|
-
if (
|
|
20628
|
-
|
|
20669
|
+
if (checkEvent) {
|
|
20670
|
+
emit(`UI:${checkEvent}`, {});
|
|
20671
|
+
}
|
|
20672
|
+
if (!entityDrivesResult) {
|
|
20673
|
+
setLocalSubmitted(true);
|
|
20674
|
+
setLocalAttempts((a) => a + 1);
|
|
20675
|
+
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
20676
|
+
if (correct) {
|
|
20677
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
20678
|
+
}
|
|
20629
20679
|
}
|
|
20630
|
-
}, [items, assignments, attempts, completeEvent, emit]);
|
|
20680
|
+
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
20631
20681
|
const handleReset = () => {
|
|
20632
|
-
|
|
20682
|
+
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
20633
20683
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
20634
20684
|
setShowHint(true);
|
|
20635
20685
|
}
|
|
20636
20686
|
};
|
|
20637
20687
|
const handleFullReset = () => {
|
|
20638
|
-
|
|
20639
|
-
|
|
20640
|
-
|
|
20688
|
+
if (playAgainEvent) {
|
|
20689
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
20690
|
+
}
|
|
20691
|
+
setLocalAssignments({});
|
|
20692
|
+
setLocalSubmitted(false);
|
|
20693
|
+
setLocalAttempts(0);
|
|
20641
20694
|
setShowHint(false);
|
|
20642
20695
|
};
|
|
20643
20696
|
if (!resolved) return null;
|
|
@@ -28520,13 +28573,13 @@ var init_MapView = __esm({
|
|
|
28520
28573
|
shadowSize: [41, 41]
|
|
28521
28574
|
});
|
|
28522
28575
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28523
|
-
const { useEffect:
|
|
28576
|
+
const { useEffect: useEffect74, useRef: useRef68, useCallback: useCallback111, useState: useState107 } = React82__namespace.default;
|
|
28524
28577
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28525
28578
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28526
28579
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28527
28580
|
const map = useMap();
|
|
28528
|
-
const prevRef =
|
|
28529
|
-
|
|
28581
|
+
const prevRef = useRef68({ centerLat, centerLng, zoom });
|
|
28582
|
+
useEffect74(() => {
|
|
28530
28583
|
const prev = prevRef.current;
|
|
28531
28584
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
28532
28585
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -28537,7 +28590,7 @@ var init_MapView = __esm({
|
|
|
28537
28590
|
}
|
|
28538
28591
|
function MapClickHandler({ onMapClick }) {
|
|
28539
28592
|
const map = useMap();
|
|
28540
|
-
|
|
28593
|
+
useEffect74(() => {
|
|
28541
28594
|
if (!onMapClick) return;
|
|
28542
28595
|
const handler = (e) => {
|
|
28543
28596
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -28566,7 +28619,7 @@ var init_MapView = __esm({
|
|
|
28566
28619
|
}) {
|
|
28567
28620
|
const eventBus = useEventBus3();
|
|
28568
28621
|
const [clickedPosition, setClickedPosition] = useState107(null);
|
|
28569
|
-
const handleMapClick =
|
|
28622
|
+
const handleMapClick = useCallback111((lat, lng) => {
|
|
28570
28623
|
if (showClickedPin) {
|
|
28571
28624
|
setClickedPosition({ lat, lng });
|
|
28572
28625
|
}
|
|
@@ -28575,7 +28628,7 @@ var init_MapView = __esm({
|
|
|
28575
28628
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
28576
28629
|
}
|
|
28577
28630
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
28578
|
-
const handleMarkerClick =
|
|
28631
|
+
const handleMarkerClick = useCallback111((marker) => {
|
|
28579
28632
|
onMarkerClick?.(marker);
|
|
28580
28633
|
if (markerClickEvent) {
|
|
28581
28634
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -37797,51 +37850,52 @@ var init_DataTable = __esm({
|
|
|
37797
37850
|
function DebuggerBoard({
|
|
37798
37851
|
entity,
|
|
37799
37852
|
completeEvent = "PUZZLE_COMPLETE",
|
|
37853
|
+
toggleFlagEvent,
|
|
37854
|
+
checkEvent,
|
|
37855
|
+
playAgainEvent,
|
|
37800
37856
|
className
|
|
37801
37857
|
}) {
|
|
37802
37858
|
const { emit } = useEventBus();
|
|
37803
37859
|
const { t } = hooks.useTranslate();
|
|
37804
37860
|
const resolved = boardEntity(entity);
|
|
37805
|
-
const [flaggedLines, setFlaggedLines] = React82.useState(/* @__PURE__ */ new Set());
|
|
37806
37861
|
const [headerError, setHeaderError] = React82.useState(false);
|
|
37807
|
-
const [submitted, setSubmitted] = React82.useState(false);
|
|
37808
|
-
const [attempts, setAttempts] = React82.useState(0);
|
|
37809
37862
|
const [showHint, setShowHint] = React82.useState(false);
|
|
37863
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37864
|
+
const result = resolved?.result ?? null;
|
|
37865
|
+
const attempts = num(resolved?.attempts);
|
|
37866
|
+
const submitted = result != null;
|
|
37867
|
+
const bugLines = lines.filter((l) => l.isBug);
|
|
37868
|
+
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
37869
|
+
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
37870
|
+
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
37871
|
+
const allCorrect = result === "win";
|
|
37810
37872
|
const toggleLine = (lineId) => {
|
|
37811
37873
|
if (submitted) return;
|
|
37812
|
-
|
|
37813
|
-
|
|
37814
|
-
|
|
37815
|
-
next.delete(lineId);
|
|
37816
|
-
} else {
|
|
37817
|
-
next.add(lineId);
|
|
37818
|
-
}
|
|
37819
|
-
return next;
|
|
37820
|
-
});
|
|
37874
|
+
if (toggleFlagEvent) {
|
|
37875
|
+
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
37876
|
+
}
|
|
37821
37877
|
};
|
|
37822
|
-
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37823
|
-
const bugLines = lines.filter((l) => l.isBug);
|
|
37824
|
-
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
37825
|
-
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
37826
|
-
const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
37827
37878
|
const handleSubmit = React82.useCallback(() => {
|
|
37828
|
-
|
|
37829
|
-
|
|
37879
|
+
if (checkEvent) {
|
|
37880
|
+
emit(`UI:${checkEvent}`, {});
|
|
37881
|
+
}
|
|
37830
37882
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
37831
37883
|
if (correct) {
|
|
37832
37884
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
37833
37885
|
}
|
|
37834
|
-
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37886
|
+
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37835
37887
|
const handleReset = () => {
|
|
37836
|
-
|
|
37888
|
+
if (playAgainEvent) {
|
|
37889
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
37890
|
+
}
|
|
37837
37891
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
37838
37892
|
setShowHint(true);
|
|
37839
37893
|
}
|
|
37840
37894
|
};
|
|
37841
37895
|
const handleFullReset = () => {
|
|
37842
|
-
|
|
37843
|
-
|
|
37844
|
-
|
|
37896
|
+
if (playAgainEvent) {
|
|
37897
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
37898
|
+
}
|
|
37845
37899
|
setShowHint(false);
|
|
37846
37900
|
};
|
|
37847
37901
|
if (!resolved) return null;
|
|
@@ -37869,7 +37923,7 @@ function DebuggerBoard({
|
|
|
37869
37923
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
37870
37924
|
] }) }),
|
|
37871
37925
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
37872
|
-
const isFlagged =
|
|
37926
|
+
const isFlagged = !!line.isFlagged;
|
|
37873
37927
|
let lineStyle = "";
|
|
37874
37928
|
if (submitted) {
|
|
37875
37929
|
if (line.isBug && isFlagged) lineStyle = "bg-success/10";
|
|
@@ -37903,9 +37957,9 @@ function DebuggerBoard({
|
|
|
37903
37957
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
37904
37958
|
Icon,
|
|
37905
37959
|
{
|
|
37906
|
-
icon:
|
|
37960
|
+
icon: line.isFlagged ? LucideIcons2.CheckCircle : LucideIcons2.XCircle,
|
|
37907
37961
|
size: "xs",
|
|
37908
|
-
className:
|
|
37962
|
+
className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
|
|
37909
37963
|
}
|
|
37910
37964
|
),
|
|
37911
37965
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", children: [
|
|
@@ -37916,7 +37970,7 @@ function DebuggerBoard({
|
|
|
37916
37970
|
] }) }),
|
|
37917
37971
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
37918
37972
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
37919
|
-
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.
|
|
37973
|
+
!submitted ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
37920
37974
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Send, size: "sm" }),
|
|
37921
37975
|
t("debugger.submit")
|
|
37922
37976
|
] }) : !allCorrect ? /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
|
|
@@ -41680,6 +41734,9 @@ function getOpponentAction(strategy, actions, history) {
|
|
|
41680
41734
|
function NegotiatorBoard({
|
|
41681
41735
|
entity,
|
|
41682
41736
|
completeEvent = "PUZZLE_COMPLETE",
|
|
41737
|
+
playRoundEvent,
|
|
41738
|
+
finishEvent,
|
|
41739
|
+
playAgainEvent,
|
|
41683
41740
|
className
|
|
41684
41741
|
}) {
|
|
41685
41742
|
const { emit } = useEventBus();
|
|
@@ -41688,13 +41745,14 @@ function NegotiatorBoard({
|
|
|
41688
41745
|
const [history, setHistory] = React82.useState([]);
|
|
41689
41746
|
const [headerError, setHeaderError] = React82.useState(false);
|
|
41690
41747
|
const [showHint, setShowHint] = React82.useState(false);
|
|
41691
|
-
const totalRounds = num(resolved?.
|
|
41748
|
+
const totalRounds = num(resolved?.maxRounds);
|
|
41692
41749
|
const targetScore = num(resolved?.targetScore);
|
|
41693
|
-
const currentRound =
|
|
41694
|
-
const
|
|
41695
|
-
const playerTotal =
|
|
41750
|
+
const currentRound = num(resolved?.round);
|
|
41751
|
+
const result = str(resolved?.result) || "none";
|
|
41752
|
+
const playerTotal = num(resolved?.score);
|
|
41753
|
+
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
41754
|
+
const won = result === "win";
|
|
41696
41755
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
41697
|
-
const won = isComplete && playerTotal >= targetScore;
|
|
41698
41756
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
41699
41757
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
41700
41758
|
const handleAction = React82.useCallback((actionId) => {
|
|
@@ -41703,29 +41761,45 @@ function NegotiatorBoard({
|
|
|
41703
41761
|
const payoff = payoffMatrix.find(
|
|
41704
41762
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
41705
41763
|
);
|
|
41706
|
-
const
|
|
41707
|
-
|
|
41708
|
-
|
|
41709
|
-
|
|
41710
|
-
|
|
41711
|
-
|
|
41712
|
-
|
|
41713
|
-
|
|
41714
|
-
|
|
41715
|
-
|
|
41716
|
-
|
|
41717
|
-
|
|
41718
|
-
|
|
41719
|
-
|
|
41720
|
-
|
|
41764
|
+
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
41765
|
+
setHistory((prev) => [
|
|
41766
|
+
...prev,
|
|
41767
|
+
{
|
|
41768
|
+
round: prev.length + 1,
|
|
41769
|
+
playerAction: actionId,
|
|
41770
|
+
opponentAction,
|
|
41771
|
+
playerPayoff,
|
|
41772
|
+
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
41773
|
+
}
|
|
41774
|
+
]);
|
|
41775
|
+
if (playRoundEvent) {
|
|
41776
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
|
|
41777
|
+
}
|
|
41778
|
+
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
41779
|
+
if (finishEvent) {
|
|
41780
|
+
emit(`UI:${finishEvent}`, {});
|
|
41781
|
+
}
|
|
41782
|
+
if (str(resolved?.hint)) {
|
|
41721
41783
|
setShowHint(true);
|
|
41722
41784
|
}
|
|
41723
41785
|
}
|
|
41724
|
-
}, [isComplete, resolved, totalRounds,
|
|
41725
|
-
const handleReset = () => {
|
|
41786
|
+
}, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
|
|
41787
|
+
const handleReset = React82.useCallback(() => {
|
|
41726
41788
|
setHistory([]);
|
|
41727
41789
|
setShowHint(false);
|
|
41728
|
-
|
|
41790
|
+
if (playAgainEvent) {
|
|
41791
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
41792
|
+
}
|
|
41793
|
+
}, [playAgainEvent, emit]);
|
|
41794
|
+
const completedRef = React82.useRef(false);
|
|
41795
|
+
React82.useEffect(() => {
|
|
41796
|
+
if (result === "win" && !completedRef.current) {
|
|
41797
|
+
completedRef.current = true;
|
|
41798
|
+
emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
|
|
41799
|
+
} else if (result === "none") {
|
|
41800
|
+
completedRef.current = false;
|
|
41801
|
+
}
|
|
41802
|
+
}, [result, playerTotal, completeEvent, emit]);
|
|
41729
41803
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
41730
41804
|
if (!resolved) return null;
|
|
41731
41805
|
const theme = resolved.theme ?? void 0;
|
|
@@ -44691,67 +44765,47 @@ var init_SimulationGraph = __esm({
|
|
|
44691
44765
|
function SimulatorBoard({
|
|
44692
44766
|
entity,
|
|
44693
44767
|
completeEvent = "PUZZLE_COMPLETE",
|
|
44768
|
+
setAEvent,
|
|
44769
|
+
setBEvent,
|
|
44770
|
+
checkEvent,
|
|
44771
|
+
playAgainEvent,
|
|
44694
44772
|
className
|
|
44695
44773
|
}) {
|
|
44696
44774
|
const { emit } = useEventBus();
|
|
44697
44775
|
const { t } = hooks.useTranslate();
|
|
44698
44776
|
const resolved = boardEntity(entity);
|
|
44699
44777
|
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
44700
|
-
const [values, setValues] = React82.useState(() => {
|
|
44701
|
-
const init = {};
|
|
44702
|
-
for (const p2 of parameters) {
|
|
44703
|
-
init[p2.id] = p2.initial;
|
|
44704
|
-
}
|
|
44705
|
-
return init;
|
|
44706
|
-
});
|
|
44707
44778
|
const [headerError, setHeaderError] = React82.useState(false);
|
|
44708
|
-
|
|
44709
|
-
const
|
|
44710
|
-
const
|
|
44711
|
-
const
|
|
44712
|
-
|
|
44713
|
-
|
|
44714
|
-
|
|
44715
|
-
|
|
44716
|
-
|
|
44717
|
-
|
|
44718
|
-
|
|
44719
|
-
const
|
|
44720
|
-
const
|
|
44721
|
-
const
|
|
44722
|
-
const
|
|
44723
|
-
|
|
44724
|
-
|
|
44725
|
-
|
|
44726
|
-
};
|
|
44727
|
-
const handleSubmit = () => {
|
|
44728
|
-
setSubmitted(true);
|
|
44729
|
-
setAttempts((a) => a + 1);
|
|
44730
|
-
if (isCorrect) {
|
|
44731
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
44732
|
-
}
|
|
44779
|
+
if (!resolved) return null;
|
|
44780
|
+
const paramA = num(resolved.paramA);
|
|
44781
|
+
const paramB = num(resolved.paramB);
|
|
44782
|
+
const output = num(resolved.output);
|
|
44783
|
+
const targetValue = num(resolved.target);
|
|
44784
|
+
const targetTolerance = num(resolved.tolerance);
|
|
44785
|
+
const attempts = num(resolved.attempts);
|
|
44786
|
+
const result = str(resolved.result);
|
|
44787
|
+
const isWin = result === "win";
|
|
44788
|
+
const isComplete = result !== "none" && result !== "";
|
|
44789
|
+
const paramAValue = parameters[0];
|
|
44790
|
+
const paramBValue = parameters[1];
|
|
44791
|
+
const sliderValues = [paramA, paramB];
|
|
44792
|
+
const sliderEvents = [setAEvent, setBEvent];
|
|
44793
|
+
const handleParameterChange = (index, value) => {
|
|
44794
|
+
if (isComplete) return;
|
|
44795
|
+
const ev = sliderEvents[index];
|
|
44796
|
+
if (ev) emit(`UI:${ev}`, { value });
|
|
44733
44797
|
};
|
|
44734
|
-
const
|
|
44735
|
-
|
|
44736
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
44737
|
-
setShowHint(true);
|
|
44738
|
-
}
|
|
44798
|
+
const handleCheck = () => {
|
|
44799
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
44739
44800
|
};
|
|
44740
|
-
const
|
|
44741
|
-
|
|
44742
|
-
for (const p2 of parameters) {
|
|
44743
|
-
init[p2.id] = p2.initial;
|
|
44744
|
-
}
|
|
44745
|
-
setValues(init);
|
|
44746
|
-
setSubmitted(false);
|
|
44747
|
-
setAttempts(0);
|
|
44748
|
-
setShowHint(false);
|
|
44801
|
+
const handlePlayAgain = () => {
|
|
44802
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
44749
44803
|
};
|
|
44750
|
-
if (!resolved) return null;
|
|
44751
44804
|
const theme = resolved.theme ?? void 0;
|
|
44752
44805
|
const themeBackground = theme?.background;
|
|
44753
44806
|
const headerImage = str(resolved.headerImage);
|
|
44754
44807
|
const hint = str(resolved.hint);
|
|
44808
|
+
const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
|
|
44755
44809
|
const outputLabel = str(resolved.outputLabel);
|
|
44756
44810
|
const outputUnit = str(resolved.outputUnit);
|
|
44757
44811
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -44771,41 +44825,43 @@ function SimulatorBoard({
|
|
|
44771
44825
|
] }) }),
|
|
44772
44826
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
44773
44827
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
44774
|
-
|
|
44775
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
44776
|
-
/* @__PURE__ */ jsxRuntime.
|
|
44777
|
-
|
|
44778
|
-
|
|
44779
|
-
|
|
44780
|
-
|
|
44781
|
-
|
|
44782
|
-
|
|
44783
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44784
|
-
"input",
|
|
44785
|
-
{
|
|
44786
|
-
type: "range",
|
|
44787
|
-
min: param.min,
|
|
44788
|
-
max: param.max,
|
|
44789
|
-
step: param.step,
|
|
44790
|
-
value: values[param.id],
|
|
44791
|
-
onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
|
|
44792
|
-
disabled: submitted,
|
|
44793
|
-
className: "w-full accent-foreground"
|
|
44794
|
-
}
|
|
44795
|
-
),
|
|
44796
|
-
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", children: [
|
|
44797
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44798
|
-
param.min,
|
|
44799
|
-
" ",
|
|
44800
|
-
param.unit
|
|
44828
|
+
[paramAValue, paramBValue].map(
|
|
44829
|
+
(param, index) => param ? /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
44830
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", align: "center", children: [
|
|
44831
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
|
|
44832
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", children: [
|
|
44833
|
+
sliderValues[index],
|
|
44834
|
+
" ",
|
|
44835
|
+
param.unit
|
|
44836
|
+
] })
|
|
44801
44837
|
] }),
|
|
44802
|
-
/* @__PURE__ */ jsxRuntime.
|
|
44803
|
-
|
|
44804
|
-
|
|
44805
|
-
|
|
44838
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
44839
|
+
"input",
|
|
44840
|
+
{
|
|
44841
|
+
type: "range",
|
|
44842
|
+
min: param.min,
|
|
44843
|
+
max: param.max,
|
|
44844
|
+
step: param.step,
|
|
44845
|
+
value: sliderValues[index],
|
|
44846
|
+
onChange: (e) => handleParameterChange(index, Number(e.target.value)),
|
|
44847
|
+
disabled: isComplete,
|
|
44848
|
+
className: "w-full accent-foreground"
|
|
44849
|
+
}
|
|
44850
|
+
),
|
|
44851
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { justify: "between", children: [
|
|
44852
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44853
|
+
param.min,
|
|
44854
|
+
" ",
|
|
44855
|
+
param.unit
|
|
44856
|
+
] }),
|
|
44857
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44858
|
+
param.max,
|
|
44859
|
+
" ",
|
|
44860
|
+
param.unit
|
|
44861
|
+
] })
|
|
44806
44862
|
] })
|
|
44807
|
-
] })
|
|
44808
|
-
|
|
44863
|
+
] }, param.id ?? index) : null
|
|
44864
|
+
)
|
|
44809
44865
|
] }) }),
|
|
44810
44866
|
/* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
44811
44867
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
@@ -44814,9 +44870,9 @@ function SimulatorBoard({
|
|
|
44814
44870
|
" ",
|
|
44815
44871
|
outputUnit
|
|
44816
44872
|
] }),
|
|
44817
|
-
|
|
44818
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon:
|
|
44819
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", className:
|
|
44873
|
+
isComplete && /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
44874
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: isWin ? LucideIcons2.CheckCircle : LucideIcons2.XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
|
|
44875
|
+
/* @__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") })
|
|
44820
44876
|
] }),
|
|
44821
44877
|
/* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44822
44878
|
t("simulator.target"),
|
|
@@ -44831,11 +44887,11 @@ function SimulatorBoard({
|
|
|
44831
44887
|
] }) }),
|
|
44832
44888
|
showHint && hint && /* @__PURE__ */ jsxRuntime.jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body", children: hint }) }),
|
|
44833
44889
|
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
44834
|
-
!
|
|
44890
|
+
!isComplete ? /* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
|
|
44835
44891
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.Play, size: "sm" }),
|
|
44836
44892
|
t("simulator.simulate")
|
|
44837
|
-
] }) :
|
|
44838
|
-
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick:
|
|
44893
|
+
] }) : null,
|
|
44894
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
44839
44895
|
/* @__PURE__ */ jsxRuntime.jsx(Icon, { icon: LucideIcons2.RotateCcw, size: "sm" }),
|
|
44840
44896
|
t("simulator.reset")
|
|
44841
44897
|
] })
|