@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.js
CHANGED
|
@@ -8,9 +8,6 @@ import { MarkerType, useReactFlow, Handle, Position, getBezierPath, EdgeLabelRen
|
|
|
8
8
|
import { useTranslate, useEventBus as useEventBus$1 } from '@almadar/ui/hooks';
|
|
9
9
|
import * as LucideIcons2 from 'lucide-react';
|
|
10
10
|
import { Loader2, X, Code, FileText, WrapText, Check, Copy, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, RotateCcw, Play, Terminal, XCircle, AlertTriangle, Trash2, Link2, ZoomOut, ZoomIn, Download, Menu as Menu$1, Package, Calendar, MoreHorizontal, Image as Image$1, Upload, ArrowLeft, HelpCircle, PauseCircle, Search, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, Minus, Eraser, TrendingUp, TrendingDown, AlertCircle, Circle, Clock, CheckCircle2, Pause, SkipForward, Bug, Send, ChevronUp, ChevronDown, Wrench, Tag, User, DollarSign, Zap, Sword, Move, Heart, Shield } from 'lucide-react';
|
|
11
|
-
import * as PhosphorIcons from '@phosphor-icons/react';
|
|
12
|
-
import * as TablerIcons from '@tabler/icons-react';
|
|
13
|
-
import * as FaIcons from 'react-icons/fa';
|
|
14
11
|
import { createPortal } from 'react-dom';
|
|
15
12
|
import { evaluate, createMinimalContext } from '@almadar/evaluator';
|
|
16
13
|
import { UISlotProvider, useUISlots } from '@almadar/ui/context';
|
|
@@ -4473,6 +4470,41 @@ function kebabToPascal(name) {
|
|
|
4473
4470
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
4474
4471
|
}).join("");
|
|
4475
4472
|
}
|
|
4473
|
+
function loadLib(key, importer) {
|
|
4474
|
+
let p2 = libPromises.get(key);
|
|
4475
|
+
if (!p2) {
|
|
4476
|
+
p2 = importer().then((m) => m);
|
|
4477
|
+
libPromises.set(key, p2);
|
|
4478
|
+
}
|
|
4479
|
+
return p2;
|
|
4480
|
+
}
|
|
4481
|
+
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
4482
|
+
const Lazy = React91__default.lazy(async () => {
|
|
4483
|
+
const lib = await loadLib(libKey, importer);
|
|
4484
|
+
const Comp = pick(lib);
|
|
4485
|
+
if (!Comp) {
|
|
4486
|
+
warnFallback(fallbackName, family);
|
|
4487
|
+
return { default: makeLucideAdapter(fallbackName, true) };
|
|
4488
|
+
}
|
|
4489
|
+
return { default: Comp };
|
|
4490
|
+
});
|
|
4491
|
+
const Wrapped = (props) => /* @__PURE__ */ jsx(
|
|
4492
|
+
React91__default.Suspense,
|
|
4493
|
+
{
|
|
4494
|
+
fallback: /* @__PURE__ */ jsx(
|
|
4495
|
+
"span",
|
|
4496
|
+
{
|
|
4497
|
+
"aria-hidden": true,
|
|
4498
|
+
className: props.className,
|
|
4499
|
+
style: { display: "inline-block", ...props.style }
|
|
4500
|
+
}
|
|
4501
|
+
),
|
|
4502
|
+
children: /* @__PURE__ */ jsx(Lazy, { ...props })
|
|
4503
|
+
}
|
|
4504
|
+
);
|
|
4505
|
+
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
4506
|
+
return Wrapped;
|
|
4507
|
+
}
|
|
4476
4508
|
function resolveLucide(name) {
|
|
4477
4509
|
if (lucideAliases[name]) return lucideAliases[name];
|
|
4478
4510
|
const pascal = kebabToPascal(name);
|
|
@@ -4483,60 +4515,81 @@ function resolveLucide(name) {
|
|
|
4483
4515
|
if (asIs && typeof asIs === "object") return asIs;
|
|
4484
4516
|
return LucideIcons2.HelpCircle;
|
|
4485
4517
|
}
|
|
4486
|
-
function resolvePhosphor(name, weight) {
|
|
4518
|
+
function resolvePhosphor(name, weight, family) {
|
|
4487
4519
|
const target = phosphorAliases[name] ?? kebabToPascal(name);
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4520
|
+
return lazyFamilyIcon(
|
|
4521
|
+
"phosphor",
|
|
4522
|
+
() => import('@phosphor-icons/react'),
|
|
4523
|
+
(lib) => {
|
|
4524
|
+
const PhosphorComp = lib[target];
|
|
4525
|
+
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
4526
|
+
const Component = PhosphorComp;
|
|
4527
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
4528
|
+
Component,
|
|
4529
|
+
{
|
|
4530
|
+
weight,
|
|
4531
|
+
className: props.className,
|
|
4532
|
+
style: props.style,
|
|
4533
|
+
size: props.size ?? "1em"
|
|
4534
|
+
}
|
|
4535
|
+
);
|
|
4536
|
+
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
4537
|
+
return Adapter;
|
|
4538
|
+
},
|
|
4539
|
+
name,
|
|
4540
|
+
family
|
|
4500
4541
|
);
|
|
4501
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
4502
|
-
return Adapter;
|
|
4503
4542
|
}
|
|
4504
|
-
function resolveTabler(name) {
|
|
4543
|
+
function resolveTabler(name, family) {
|
|
4505
4544
|
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
4506
4545
|
const target = `Icon${suffix}`;
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4546
|
+
return lazyFamilyIcon(
|
|
4547
|
+
"tabler",
|
|
4548
|
+
() => import('@tabler/icons-react'),
|
|
4549
|
+
(lib) => {
|
|
4550
|
+
const TablerComp = lib[target];
|
|
4551
|
+
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
4552
|
+
const Component = TablerComp;
|
|
4553
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
4554
|
+
Component,
|
|
4555
|
+
{
|
|
4556
|
+
stroke: props.strokeWidth ?? 1.5,
|
|
4557
|
+
className: props.className,
|
|
4558
|
+
style: props.style,
|
|
4559
|
+
size: props.size ?? 24
|
|
4560
|
+
}
|
|
4561
|
+
);
|
|
4562
|
+
Adapter.displayName = `Tabler.${target}`;
|
|
4563
|
+
return Adapter;
|
|
4564
|
+
},
|
|
4565
|
+
name,
|
|
4566
|
+
family
|
|
4519
4567
|
);
|
|
4520
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
4521
|
-
return Adapter;
|
|
4522
4568
|
}
|
|
4523
|
-
function resolveFa(name) {
|
|
4569
|
+
function resolveFa(name, family) {
|
|
4524
4570
|
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
4525
4571
|
const target = `Fa${suffix}`;
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4572
|
+
return lazyFamilyIcon(
|
|
4573
|
+
"fa",
|
|
4574
|
+
() => import('react-icons/fa'),
|
|
4575
|
+
(lib) => {
|
|
4576
|
+
const FaComp = lib[target];
|
|
4577
|
+
if (!FaComp || typeof FaComp !== "function") return null;
|
|
4578
|
+
const Component = FaComp;
|
|
4579
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
4580
|
+
Component,
|
|
4581
|
+
{
|
|
4582
|
+
className: props.className,
|
|
4583
|
+
style: props.style,
|
|
4584
|
+
size: props.size ?? "1em"
|
|
4585
|
+
}
|
|
4586
|
+
);
|
|
4587
|
+
Adapter.displayName = `Fa.${target}`;
|
|
4588
|
+
return Adapter;
|
|
4589
|
+
},
|
|
4590
|
+
name,
|
|
4591
|
+
family
|
|
4537
4592
|
);
|
|
4538
|
-
Adapter.displayName = `Fa.${target}`;
|
|
4539
|
-
return Adapter;
|
|
4540
4593
|
}
|
|
4541
4594
|
function warnFallback(name, family) {
|
|
4542
4595
|
const key = `${family}::${name}`;
|
|
@@ -4570,39 +4623,22 @@ function resolveIconForFamily(name, family) {
|
|
|
4570
4623
|
switch (family) {
|
|
4571
4624
|
case "lucide":
|
|
4572
4625
|
return makeLucideAdapter(name, false);
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
return
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
return
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
return makeLucideAdapter(name, true);
|
|
4590
|
-
}
|
|
4591
|
-
case "tabler": {
|
|
4592
|
-
const t = resolveTabler(name);
|
|
4593
|
-
if (t) return t;
|
|
4594
|
-
warnFallback(name, family);
|
|
4595
|
-
return makeLucideAdapter(name, true);
|
|
4596
|
-
}
|
|
4597
|
-
case "fa-solid": {
|
|
4598
|
-
const f3 = resolveFa(name);
|
|
4599
|
-
if (f3) return f3;
|
|
4600
|
-
warnFallback(name, family);
|
|
4601
|
-
return makeLucideAdapter(name, true);
|
|
4602
|
-
}
|
|
4603
|
-
}
|
|
4604
|
-
}
|
|
4605
|
-
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
4626
|
+
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
4627
|
+
// dynamic-imports the library on first render and falls back to lucide
|
|
4628
|
+
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
4629
|
+
case "phosphor-outline":
|
|
4630
|
+
return resolvePhosphor(name, "regular", family);
|
|
4631
|
+
case "phosphor-fill":
|
|
4632
|
+
return resolvePhosphor(name, "fill", family);
|
|
4633
|
+
case "phosphor-duotone":
|
|
4634
|
+
return resolvePhosphor(name, "duotone", family);
|
|
4635
|
+
case "tabler":
|
|
4636
|
+
return resolveTabler(name, family);
|
|
4637
|
+
case "fa-solid":
|
|
4638
|
+
return resolveFa(name, family);
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
4606
4642
|
var init_iconFamily = __esm({
|
|
4607
4643
|
"lib/iconFamily.tsx"() {
|
|
4608
4644
|
"use client";
|
|
@@ -4618,6 +4654,7 @@ var init_iconFamily = __esm({
|
|
|
4618
4654
|
cachedFamily = null;
|
|
4619
4655
|
listeners = /* @__PURE__ */ new Set();
|
|
4620
4656
|
observer = null;
|
|
4657
|
+
libPromises = /* @__PURE__ */ new Map();
|
|
4621
4658
|
lucideAliases = {
|
|
4622
4659
|
close: LucideIcons2.X,
|
|
4623
4660
|
trash: LucideIcons2.Trash2,
|
|
@@ -19849,61 +19886,53 @@ var init_Breadcrumb = __esm({
|
|
|
19849
19886
|
function BuilderBoard({
|
|
19850
19887
|
entity,
|
|
19851
19888
|
completeEvent = "PUZZLE_COMPLETE",
|
|
19889
|
+
placeEvent,
|
|
19890
|
+
checkEvent,
|
|
19891
|
+
playAgainEvent,
|
|
19852
19892
|
className
|
|
19853
19893
|
}) {
|
|
19854
19894
|
const { emit } = useEventBus();
|
|
19855
19895
|
const { t } = useTranslate();
|
|
19856
19896
|
const resolved = boardEntity(entity);
|
|
19857
|
-
const [placements, setPlacements] = useState({});
|
|
19858
19897
|
const [headerError, setHeaderError] = useState(false);
|
|
19859
|
-
const [
|
|
19860
|
-
const [attempts, setAttempts] = useState(0);
|
|
19861
|
-
const [showHint, setShowHint] = useState(false);
|
|
19898
|
+
const [selectedComponent, setSelectedComponent] = useState(null);
|
|
19862
19899
|
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
19863
19900
|
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
19901
|
+
const placements = {};
|
|
19902
|
+
for (const slot of slots) {
|
|
19903
|
+
if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
|
|
19904
|
+
}
|
|
19905
|
+
const attempts = num(resolved?.attempts);
|
|
19906
|
+
const result = str(resolved?.result) || "none";
|
|
19907
|
+
const submitted = result === "win";
|
|
19864
19908
|
const usedComponentIds = new Set(Object.values(placements));
|
|
19865
19909
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
19866
|
-
const
|
|
19867
|
-
const allPlaced = Object.keys(placements).length === slots.length;
|
|
19910
|
+
const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
|
|
19868
19911
|
const results = submitted ? slots.map((slot) => ({
|
|
19869
19912
|
slot,
|
|
19870
19913
|
placed: placements[slot.id],
|
|
19871
|
-
correct: placements[slot.id] === slot.
|
|
19914
|
+
correct: placements[slot.id] === slot.requiredComponentId
|
|
19872
19915
|
})) : [];
|
|
19873
|
-
const
|
|
19916
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
19874
19917
|
const handlePlaceComponent = (slotId) => {
|
|
19875
19918
|
if (submitted || !selectedComponent) return;
|
|
19876
|
-
|
|
19919
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
|
|
19877
19920
|
setSelectedComponent(null);
|
|
19878
19921
|
};
|
|
19879
19922
|
const handleRemoveFromSlot = (slotId) => {
|
|
19880
19923
|
if (submitted) return;
|
|
19881
|
-
|
|
19882
|
-
const next = { ...prev };
|
|
19883
|
-
delete next[slotId];
|
|
19884
|
-
return next;
|
|
19885
|
-
});
|
|
19924
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
|
|
19886
19925
|
};
|
|
19887
|
-
const handleSubmit =
|
|
19888
|
-
|
|
19889
|
-
|
|
19890
|
-
|
|
19891
|
-
if (correct) {
|
|
19926
|
+
const handleSubmit = () => {
|
|
19927
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
19928
|
+
const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
|
|
19929
|
+
if (solved && completeEvent) {
|
|
19892
19930
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
19893
19931
|
}
|
|
19894
|
-
}, [slots, placements, attempts, completeEvent, emit]);
|
|
19895
|
-
const handleReset = () => {
|
|
19896
|
-
setSubmitted(false);
|
|
19897
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
19898
|
-
setShowHint(true);
|
|
19899
|
-
}
|
|
19900
19932
|
};
|
|
19901
|
-
const
|
|
19902
|
-
setPlacements({});
|
|
19903
|
-
setSubmitted(false);
|
|
19933
|
+
const handlePlayAgain = () => {
|
|
19904
19934
|
setSelectedComponent(null);
|
|
19905
|
-
|
|
19906
|
-
setShowHint(false);
|
|
19935
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
19907
19936
|
};
|
|
19908
19937
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
19909
19938
|
if (!resolved) return null;
|
|
@@ -19953,13 +19982,13 @@ function BuilderBoard({
|
|
|
19953
19982
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
|
|
19954
19983
|
/* @__PURE__ */ jsx(VStack, { gap: "sm", children: slots.map((slot) => {
|
|
19955
19984
|
const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
|
|
19956
|
-
const
|
|
19985
|
+
const result2 = results.find((r2) => r2.slot.id === slot.id);
|
|
19957
19986
|
return /* @__PURE__ */ jsxs(
|
|
19958
19987
|
HStack,
|
|
19959
19988
|
{
|
|
19960
19989
|
gap: "sm",
|
|
19961
19990
|
align: "center",
|
|
19962
|
-
className: `p-3 border-2 rounded ${
|
|
19991
|
+
className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
|
|
19963
19992
|
onClick: () => handlePlaceComponent(slot.id),
|
|
19964
19993
|
children: [
|
|
19965
19994
|
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
|
|
@@ -19974,7 +20003,7 @@ function BuilderBoard({
|
|
|
19974
20003
|
] }) : null,
|
|
19975
20004
|
placedComp.label
|
|
19976
20005
|
] }),
|
|
19977
|
-
|
|
20006
|
+
result2 && /* @__PURE__ */ jsx(Icon, { icon: result2.correct ? CheckCircle : XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
|
|
19978
20007
|
] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
|
|
19979
20008
|
]
|
|
19980
20009
|
},
|
|
@@ -19983,16 +20012,16 @@ function BuilderBoard({
|
|
|
19983
20012
|
}) })
|
|
19984
20013
|
] }) }),
|
|
19985
20014
|
submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
19986
|
-
/* @__PURE__ */ jsx(Icon, { icon:
|
|
19987
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children:
|
|
20015
|
+
/* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: "text-success" }),
|
|
20016
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
|
|
19988
20017
|
] }) }),
|
|
19989
20018
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
19990
20019
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
19991
|
-
!submitted
|
|
20020
|
+
!submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
19992
20021
|
/* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
|
|
19993
20022
|
t("builder.build")
|
|
19994
|
-
] })
|
|
19995
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick:
|
|
20023
|
+
] }),
|
|
20024
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
19996
20025
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
19997
20026
|
t("builder.reset")
|
|
19998
20027
|
] })
|
|
@@ -23448,57 +23477,84 @@ var init_ChartLegend = __esm({
|
|
|
23448
23477
|
function ClassifierBoard({
|
|
23449
23478
|
entity,
|
|
23450
23479
|
completeEvent = "PUZZLE_COMPLETE",
|
|
23480
|
+
assignEvent,
|
|
23481
|
+
checkEvent,
|
|
23482
|
+
playAgainEvent,
|
|
23451
23483
|
className
|
|
23452
23484
|
}) {
|
|
23453
23485
|
const { emit } = useEventBus();
|
|
23454
23486
|
const { t } = useTranslate();
|
|
23455
23487
|
const resolved = boardEntity(entity);
|
|
23456
|
-
const [
|
|
23488
|
+
const [localAssignments, setLocalAssignments] = useState({});
|
|
23457
23489
|
const [headerError, setHeaderError] = useState(false);
|
|
23458
|
-
const [
|
|
23459
|
-
const [
|
|
23490
|
+
const [localSubmitted, setLocalSubmitted] = useState(false);
|
|
23491
|
+
const [localAttempts, setLocalAttempts] = useState(0);
|
|
23460
23492
|
const [showHint, setShowHint] = useState(false);
|
|
23461
23493
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
23462
23494
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
23495
|
+
const entityResult = str(resolved?.result);
|
|
23496
|
+
const entityDrivesResult = entityResult.length > 0;
|
|
23497
|
+
const entityHasAssignments = items.some((item) => item.assignedCategory != null);
|
|
23498
|
+
const assignments = entityHasAssignments ? items.reduce((acc, item) => {
|
|
23499
|
+
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
23500
|
+
return acc;
|
|
23501
|
+
}, {}) : localAssignments;
|
|
23502
|
+
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
23503
|
+
const submitted = entityDrivesResult || localSubmitted;
|
|
23463
23504
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
23464
|
-
const allAssigned = Object.keys(assignments).length === items.length;
|
|
23505
|
+
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
23465
23506
|
const results = submitted ? items.map((item) => ({
|
|
23466
23507
|
item,
|
|
23467
23508
|
assigned: assignments[item.id],
|
|
23468
23509
|
correct: assignments[item.id] === item.correctCategory
|
|
23469
23510
|
})) : [];
|
|
23470
|
-
const allCorrect = results.length > 0 && results.every((r2) => r2.correct);
|
|
23511
|
+
const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r2) => r2.correct);
|
|
23471
23512
|
const correctCount = results.filter((r2) => r2.correct).length;
|
|
23472
23513
|
const handleAssign = (itemId, categoryId) => {
|
|
23473
23514
|
if (submitted) return;
|
|
23474
|
-
|
|
23515
|
+
if (assignEvent) {
|
|
23516
|
+
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
23517
|
+
}
|
|
23518
|
+
if (!entityHasAssignments) {
|
|
23519
|
+
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
23520
|
+
}
|
|
23475
23521
|
};
|
|
23476
23522
|
const handleUnassign = (itemId) => {
|
|
23477
23523
|
if (submitted) return;
|
|
23478
|
-
|
|
23479
|
-
|
|
23480
|
-
|
|
23481
|
-
|
|
23482
|
-
|
|
23524
|
+
if (!entityHasAssignments) {
|
|
23525
|
+
setLocalAssignments((prev) => {
|
|
23526
|
+
const next = { ...prev };
|
|
23527
|
+
delete next[itemId];
|
|
23528
|
+
return next;
|
|
23529
|
+
});
|
|
23530
|
+
}
|
|
23483
23531
|
};
|
|
23484
23532
|
const handleSubmit = useCallback(() => {
|
|
23485
|
-
|
|
23486
|
-
|
|
23487
|
-
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
23488
|
-
if (correct) {
|
|
23489
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
23533
|
+
if (checkEvent) {
|
|
23534
|
+
emit(`UI:${checkEvent}`, {});
|
|
23490
23535
|
}
|
|
23491
|
-
|
|
23536
|
+
if (!entityDrivesResult) {
|
|
23537
|
+
setLocalSubmitted(true);
|
|
23538
|
+
setLocalAttempts((a) => a + 1);
|
|
23539
|
+
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
23540
|
+
if (correct) {
|
|
23541
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
23542
|
+
}
|
|
23543
|
+
}
|
|
23544
|
+
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
23492
23545
|
const handleReset = () => {
|
|
23493
|
-
|
|
23546
|
+
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
23494
23547
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
23495
23548
|
setShowHint(true);
|
|
23496
23549
|
}
|
|
23497
23550
|
};
|
|
23498
23551
|
const handleFullReset = () => {
|
|
23499
|
-
|
|
23500
|
-
|
|
23501
|
-
|
|
23552
|
+
if (playAgainEvent) {
|
|
23553
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
23554
|
+
}
|
|
23555
|
+
setLocalAssignments({});
|
|
23556
|
+
setLocalSubmitted(false);
|
|
23557
|
+
setLocalAttempts(0);
|
|
23502
23558
|
setShowHint(false);
|
|
23503
23559
|
};
|
|
23504
23560
|
if (!resolved) return null;
|
|
@@ -31381,13 +31437,13 @@ var init_MapView = __esm({
|
|
|
31381
31437
|
shadowSize: [41, 41]
|
|
31382
31438
|
});
|
|
31383
31439
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
31384
|
-
const { useEffect:
|
|
31440
|
+
const { useEffect: useEffect78, useRef: useRef70, useCallback: useCallback117, useState: useState115 } = React91__default;
|
|
31385
31441
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
31386
31442
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
31387
31443
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
31388
31444
|
const map = useMap();
|
|
31389
|
-
const prevRef =
|
|
31390
|
-
|
|
31445
|
+
const prevRef = useRef70({ centerLat, centerLng, zoom });
|
|
31446
|
+
useEffect78(() => {
|
|
31391
31447
|
const prev = prevRef.current;
|
|
31392
31448
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
31393
31449
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -31398,7 +31454,7 @@ var init_MapView = __esm({
|
|
|
31398
31454
|
}
|
|
31399
31455
|
function MapClickHandler({ onMapClick }) {
|
|
31400
31456
|
const map = useMap();
|
|
31401
|
-
|
|
31457
|
+
useEffect78(() => {
|
|
31402
31458
|
if (!onMapClick) return;
|
|
31403
31459
|
const handler = (e) => {
|
|
31404
31460
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -31427,7 +31483,7 @@ var init_MapView = __esm({
|
|
|
31427
31483
|
}) {
|
|
31428
31484
|
const eventBus = useEventBus3();
|
|
31429
31485
|
const [clickedPosition, setClickedPosition] = useState115(null);
|
|
31430
|
-
const handleMapClick =
|
|
31486
|
+
const handleMapClick = useCallback117((lat, lng) => {
|
|
31431
31487
|
if (showClickedPin) {
|
|
31432
31488
|
setClickedPosition({ lat, lng });
|
|
31433
31489
|
}
|
|
@@ -31436,7 +31492,7 @@ var init_MapView = __esm({
|
|
|
31436
31492
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
31437
31493
|
}
|
|
31438
31494
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
31439
|
-
const handleMarkerClick =
|
|
31495
|
+
const handleMarkerClick = useCallback117((marker) => {
|
|
31440
31496
|
onMarkerClick?.(marker);
|
|
31441
31497
|
if (markerClickEvent) {
|
|
31442
31498
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -40249,51 +40305,52 @@ var init_DataTable = __esm({
|
|
|
40249
40305
|
function DebuggerBoard({
|
|
40250
40306
|
entity,
|
|
40251
40307
|
completeEvent = "PUZZLE_COMPLETE",
|
|
40308
|
+
toggleFlagEvent,
|
|
40309
|
+
checkEvent,
|
|
40310
|
+
playAgainEvent,
|
|
40252
40311
|
className
|
|
40253
40312
|
}) {
|
|
40254
40313
|
const { emit } = useEventBus();
|
|
40255
40314
|
const { t } = useTranslate();
|
|
40256
40315
|
const resolved = boardEntity(entity);
|
|
40257
|
-
const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
|
|
40258
40316
|
const [headerError, setHeaderError] = useState(false);
|
|
40259
|
-
const [submitted, setSubmitted] = useState(false);
|
|
40260
|
-
const [attempts, setAttempts] = useState(0);
|
|
40261
40317
|
const [showHint, setShowHint] = useState(false);
|
|
40318
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
40319
|
+
const result = resolved?.result ?? null;
|
|
40320
|
+
const attempts = num(resolved?.attempts);
|
|
40321
|
+
const submitted = result != null;
|
|
40322
|
+
const bugLines = lines.filter((l) => l.isBug);
|
|
40323
|
+
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
40324
|
+
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
40325
|
+
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
40326
|
+
const allCorrect = result === "win";
|
|
40262
40327
|
const toggleLine = (lineId) => {
|
|
40263
40328
|
if (submitted) return;
|
|
40264
|
-
|
|
40265
|
-
|
|
40266
|
-
|
|
40267
|
-
next.delete(lineId);
|
|
40268
|
-
} else {
|
|
40269
|
-
next.add(lineId);
|
|
40270
|
-
}
|
|
40271
|
-
return next;
|
|
40272
|
-
});
|
|
40329
|
+
if (toggleFlagEvent) {
|
|
40330
|
+
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
40331
|
+
}
|
|
40273
40332
|
};
|
|
40274
|
-
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
40275
|
-
const bugLines = lines.filter((l) => l.isBug);
|
|
40276
|
-
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
40277
|
-
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
40278
|
-
const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
40279
40333
|
const handleSubmit = useCallback(() => {
|
|
40280
|
-
|
|
40281
|
-
|
|
40334
|
+
if (checkEvent) {
|
|
40335
|
+
emit(`UI:${checkEvent}`, {});
|
|
40336
|
+
}
|
|
40282
40337
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
40283
40338
|
if (correct) {
|
|
40284
40339
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
40285
40340
|
}
|
|
40286
|
-
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
40341
|
+
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
40287
40342
|
const handleReset = () => {
|
|
40288
|
-
|
|
40343
|
+
if (playAgainEvent) {
|
|
40344
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
40345
|
+
}
|
|
40289
40346
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
40290
40347
|
setShowHint(true);
|
|
40291
40348
|
}
|
|
40292
40349
|
};
|
|
40293
40350
|
const handleFullReset = () => {
|
|
40294
|
-
|
|
40295
|
-
|
|
40296
|
-
|
|
40351
|
+
if (playAgainEvent) {
|
|
40352
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
40353
|
+
}
|
|
40297
40354
|
setShowHint(false);
|
|
40298
40355
|
};
|
|
40299
40356
|
if (!resolved) return null;
|
|
@@ -40321,7 +40378,7 @@ function DebuggerBoard({
|
|
|
40321
40378
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
40322
40379
|
] }) }),
|
|
40323
40380
|
/* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
40324
|
-
const isFlagged =
|
|
40381
|
+
const isFlagged = !!line.isFlagged;
|
|
40325
40382
|
let lineStyle = "";
|
|
40326
40383
|
if (submitted) {
|
|
40327
40384
|
if (line.isBug && isFlagged) lineStyle = "bg-success/10";
|
|
@@ -40355,9 +40412,9 @@ function DebuggerBoard({
|
|
|
40355
40412
|
/* @__PURE__ */ jsx(
|
|
40356
40413
|
Icon,
|
|
40357
40414
|
{
|
|
40358
|
-
icon:
|
|
40415
|
+
icon: line.isFlagged ? CheckCircle : XCircle,
|
|
40359
40416
|
size: "xs",
|
|
40360
|
-
className:
|
|
40417
|
+
className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
|
|
40361
40418
|
}
|
|
40362
40419
|
),
|
|
40363
40420
|
/* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
|
|
@@ -40368,7 +40425,7 @@ function DebuggerBoard({
|
|
|
40368
40425
|
] }) }),
|
|
40369
40426
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
40370
40427
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
40371
|
-
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.
|
|
40428
|
+
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
40372
40429
|
/* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
|
|
40373
40430
|
t("debugger.submit")
|
|
40374
40431
|
] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
|
|
@@ -44132,6 +44189,9 @@ function getOpponentAction(strategy, actions, history) {
|
|
|
44132
44189
|
function NegotiatorBoard({
|
|
44133
44190
|
entity,
|
|
44134
44191
|
completeEvent = "PUZZLE_COMPLETE",
|
|
44192
|
+
playRoundEvent,
|
|
44193
|
+
finishEvent,
|
|
44194
|
+
playAgainEvent,
|
|
44135
44195
|
className
|
|
44136
44196
|
}) {
|
|
44137
44197
|
const { emit } = useEventBus();
|
|
@@ -44140,13 +44200,14 @@ function NegotiatorBoard({
|
|
|
44140
44200
|
const [history, setHistory] = useState([]);
|
|
44141
44201
|
const [headerError, setHeaderError] = useState(false);
|
|
44142
44202
|
const [showHint, setShowHint] = useState(false);
|
|
44143
|
-
const totalRounds = num(resolved?.
|
|
44203
|
+
const totalRounds = num(resolved?.maxRounds);
|
|
44144
44204
|
const targetScore = num(resolved?.targetScore);
|
|
44145
|
-
const currentRound =
|
|
44146
|
-
const
|
|
44147
|
-
const playerTotal =
|
|
44205
|
+
const currentRound = num(resolved?.round);
|
|
44206
|
+
const result = str(resolved?.result) || "none";
|
|
44207
|
+
const playerTotal = num(resolved?.score);
|
|
44208
|
+
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
44209
|
+
const won = result === "win";
|
|
44148
44210
|
const opponentTotal = history.reduce((s, r2) => s + r2.opponentPayoff, 0);
|
|
44149
|
-
const won = isComplete && playerTotal >= targetScore;
|
|
44150
44211
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
44151
44212
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
44152
44213
|
const handleAction = useCallback((actionId) => {
|
|
@@ -44155,29 +44216,45 @@ function NegotiatorBoard({
|
|
|
44155
44216
|
const payoff = payoffMatrix.find(
|
|
44156
44217
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
44157
44218
|
);
|
|
44158
|
-
const
|
|
44159
|
-
|
|
44160
|
-
|
|
44161
|
-
|
|
44162
|
-
|
|
44163
|
-
|
|
44164
|
-
|
|
44165
|
-
|
|
44166
|
-
|
|
44167
|
-
|
|
44168
|
-
|
|
44169
|
-
|
|
44170
|
-
|
|
44171
|
-
|
|
44172
|
-
|
|
44219
|
+
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
44220
|
+
setHistory((prev) => [
|
|
44221
|
+
...prev,
|
|
44222
|
+
{
|
|
44223
|
+
round: prev.length + 1,
|
|
44224
|
+
playerAction: actionId,
|
|
44225
|
+
opponentAction,
|
|
44226
|
+
playerPayoff,
|
|
44227
|
+
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
44228
|
+
}
|
|
44229
|
+
]);
|
|
44230
|
+
if (playRoundEvent) {
|
|
44231
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
|
|
44232
|
+
}
|
|
44233
|
+
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
44234
|
+
if (finishEvent) {
|
|
44235
|
+
emit(`UI:${finishEvent}`, {});
|
|
44236
|
+
}
|
|
44237
|
+
if (str(resolved?.hint)) {
|
|
44173
44238
|
setShowHint(true);
|
|
44174
44239
|
}
|
|
44175
44240
|
}
|
|
44176
|
-
}, [isComplete, resolved, totalRounds,
|
|
44177
|
-
const handleReset = () => {
|
|
44241
|
+
}, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
|
|
44242
|
+
const handleReset = useCallback(() => {
|
|
44178
44243
|
setHistory([]);
|
|
44179
44244
|
setShowHint(false);
|
|
44180
|
-
|
|
44245
|
+
if (playAgainEvent) {
|
|
44246
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
44247
|
+
}
|
|
44248
|
+
}, [playAgainEvent, emit]);
|
|
44249
|
+
const completedRef = useRef(false);
|
|
44250
|
+
useEffect(() => {
|
|
44251
|
+
if (result === "win" && !completedRef.current) {
|
|
44252
|
+
completedRef.current = true;
|
|
44253
|
+
emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
|
|
44254
|
+
} else if (result === "none") {
|
|
44255
|
+
completedRef.current = false;
|
|
44256
|
+
}
|
|
44257
|
+
}, [result, playerTotal, completeEvent, emit]);
|
|
44181
44258
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
44182
44259
|
if (!resolved) return null;
|
|
44183
44260
|
const theme = resolved.theme ?? void 0;
|
|
@@ -47143,67 +47220,47 @@ var init_SimulationGraph = __esm({
|
|
|
47143
47220
|
function SimulatorBoard({
|
|
47144
47221
|
entity,
|
|
47145
47222
|
completeEvent = "PUZZLE_COMPLETE",
|
|
47223
|
+
setAEvent,
|
|
47224
|
+
setBEvent,
|
|
47225
|
+
checkEvent,
|
|
47226
|
+
playAgainEvent,
|
|
47146
47227
|
className
|
|
47147
47228
|
}) {
|
|
47148
47229
|
const { emit } = useEventBus();
|
|
47149
47230
|
const { t } = useTranslate();
|
|
47150
47231
|
const resolved = boardEntity(entity);
|
|
47151
47232
|
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
47152
|
-
const [values, setValues] = useState(() => {
|
|
47153
|
-
const init = {};
|
|
47154
|
-
for (const p2 of parameters) {
|
|
47155
|
-
init[p2.id] = p2.initial;
|
|
47156
|
-
}
|
|
47157
|
-
return init;
|
|
47158
|
-
});
|
|
47159
47233
|
const [headerError, setHeaderError] = useState(false);
|
|
47160
|
-
|
|
47161
|
-
const
|
|
47162
|
-
const
|
|
47163
|
-
const
|
|
47164
|
-
|
|
47165
|
-
|
|
47166
|
-
|
|
47167
|
-
|
|
47168
|
-
|
|
47169
|
-
|
|
47170
|
-
|
|
47171
|
-
const
|
|
47172
|
-
const
|
|
47173
|
-
const
|
|
47174
|
-
const
|
|
47175
|
-
|
|
47176
|
-
|
|
47177
|
-
|
|
47178
|
-
};
|
|
47179
|
-
const handleSubmit = () => {
|
|
47180
|
-
setSubmitted(true);
|
|
47181
|
-
setAttempts((a) => a + 1);
|
|
47182
|
-
if (isCorrect) {
|
|
47183
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
47184
|
-
}
|
|
47234
|
+
if (!resolved) return null;
|
|
47235
|
+
const paramA = num(resolved.paramA);
|
|
47236
|
+
const paramB = num(resolved.paramB);
|
|
47237
|
+
const output = num(resolved.output);
|
|
47238
|
+
const targetValue = num(resolved.target);
|
|
47239
|
+
const targetTolerance = num(resolved.tolerance);
|
|
47240
|
+
const attempts = num(resolved.attempts);
|
|
47241
|
+
const result = str(resolved.result);
|
|
47242
|
+
const isWin = result === "win";
|
|
47243
|
+
const isComplete = result !== "none" && result !== "";
|
|
47244
|
+
const paramAValue = parameters[0];
|
|
47245
|
+
const paramBValue = parameters[1];
|
|
47246
|
+
const sliderValues = [paramA, paramB];
|
|
47247
|
+
const sliderEvents = [setAEvent, setBEvent];
|
|
47248
|
+
const handleParameterChange = (index, value) => {
|
|
47249
|
+
if (isComplete) return;
|
|
47250
|
+
const ev = sliderEvents[index];
|
|
47251
|
+
if (ev) emit(`UI:${ev}`, { value });
|
|
47185
47252
|
};
|
|
47186
|
-
const
|
|
47187
|
-
|
|
47188
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
47189
|
-
setShowHint(true);
|
|
47190
|
-
}
|
|
47253
|
+
const handleCheck = () => {
|
|
47254
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
47191
47255
|
};
|
|
47192
|
-
const
|
|
47193
|
-
|
|
47194
|
-
for (const p2 of parameters) {
|
|
47195
|
-
init[p2.id] = p2.initial;
|
|
47196
|
-
}
|
|
47197
|
-
setValues(init);
|
|
47198
|
-
setSubmitted(false);
|
|
47199
|
-
setAttempts(0);
|
|
47200
|
-
setShowHint(false);
|
|
47256
|
+
const handlePlayAgain = () => {
|
|
47257
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
47201
47258
|
};
|
|
47202
|
-
if (!resolved) return null;
|
|
47203
47259
|
const theme = resolved.theme ?? void 0;
|
|
47204
47260
|
const themeBackground = theme?.background;
|
|
47205
47261
|
const headerImage = str(resolved.headerImage);
|
|
47206
47262
|
const hint = str(resolved.hint);
|
|
47263
|
+
const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
|
|
47207
47264
|
const outputLabel = str(resolved.outputLabel);
|
|
47208
47265
|
const outputUnit = str(resolved.outputUnit);
|
|
47209
47266
|
return /* @__PURE__ */ jsx(
|
|
@@ -47223,41 +47280,43 @@ function SimulatorBoard({
|
|
|
47223
47280
|
] }) }),
|
|
47224
47281
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
|
|
47225
47282
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
47226
|
-
|
|
47227
|
-
/* @__PURE__ */ jsxs(
|
|
47228
|
-
/* @__PURE__ */
|
|
47229
|
-
|
|
47230
|
-
|
|
47231
|
-
|
|
47232
|
-
|
|
47233
|
-
|
|
47234
|
-
|
|
47235
|
-
/* @__PURE__ */ jsx(
|
|
47236
|
-
"input",
|
|
47237
|
-
{
|
|
47238
|
-
type: "range",
|
|
47239
|
-
min: param.min,
|
|
47240
|
-
max: param.max,
|
|
47241
|
-
step: param.step,
|
|
47242
|
-
value: values[param.id],
|
|
47243
|
-
onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
|
|
47244
|
-
disabled: submitted,
|
|
47245
|
-
className: "w-full accent-foreground"
|
|
47246
|
-
}
|
|
47247
|
-
),
|
|
47248
|
-
/* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
|
|
47249
|
-
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47250
|
-
param.min,
|
|
47251
|
-
" ",
|
|
47252
|
-
param.unit
|
|
47283
|
+
[paramAValue, paramBValue].map(
|
|
47284
|
+
(param, index) => param ? /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
47285
|
+
/* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
|
|
47286
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
|
|
47287
|
+
/* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
|
|
47288
|
+
sliderValues[index],
|
|
47289
|
+
" ",
|
|
47290
|
+
param.unit
|
|
47291
|
+
] })
|
|
47253
47292
|
] }),
|
|
47254
|
-
/* @__PURE__ */
|
|
47255
|
-
|
|
47256
|
-
|
|
47257
|
-
|
|
47293
|
+
/* @__PURE__ */ jsx(
|
|
47294
|
+
"input",
|
|
47295
|
+
{
|
|
47296
|
+
type: "range",
|
|
47297
|
+
min: param.min,
|
|
47298
|
+
max: param.max,
|
|
47299
|
+
step: param.step,
|
|
47300
|
+
value: sliderValues[index],
|
|
47301
|
+
onChange: (e) => handleParameterChange(index, Number(e.target.value)),
|
|
47302
|
+
disabled: isComplete,
|
|
47303
|
+
className: "w-full accent-foreground"
|
|
47304
|
+
}
|
|
47305
|
+
),
|
|
47306
|
+
/* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
|
|
47307
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47308
|
+
param.min,
|
|
47309
|
+
" ",
|
|
47310
|
+
param.unit
|
|
47311
|
+
] }),
|
|
47312
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47313
|
+
param.max,
|
|
47314
|
+
" ",
|
|
47315
|
+
param.unit
|
|
47316
|
+
] })
|
|
47258
47317
|
] })
|
|
47259
|
-
] })
|
|
47260
|
-
|
|
47318
|
+
] }, param.id ?? index) : null
|
|
47319
|
+
)
|
|
47261
47320
|
] }) }),
|
|
47262
47321
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
47263
47322
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
@@ -47266,9 +47325,9 @@ function SimulatorBoard({
|
|
|
47266
47325
|
" ",
|
|
47267
47326
|
outputUnit
|
|
47268
47327
|
] }),
|
|
47269
|
-
|
|
47270
|
-
/* @__PURE__ */ jsx(Icon, { icon:
|
|
47271
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", className:
|
|
47328
|
+
isComplete && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
47329
|
+
/* @__PURE__ */ jsx(Icon, { icon: isWin ? CheckCircle : XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
|
|
47330
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", className: isWin ? "text-success" : "text-error", children: isWin ? str(resolved.successMessage) || t("simulator.correct") : str(resolved.failMessage) || t("simulator.incorrect") })
|
|
47272
47331
|
] }),
|
|
47273
47332
|
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
47274
47333
|
t("simulator.target"),
|
|
@@ -47283,11 +47342,11 @@ function SimulatorBoard({
|
|
|
47283
47342
|
] }) }),
|
|
47284
47343
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
47285
47344
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
47286
|
-
!
|
|
47345
|
+
!isComplete ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
|
|
47287
47346
|
/* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
|
|
47288
47347
|
t("simulator.simulate")
|
|
47289
|
-
] }) :
|
|
47290
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick:
|
|
47348
|
+
] }) : null,
|
|
47349
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
47291
47350
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
47292
47351
|
t("simulator.reset")
|
|
47293
47352
|
] })
|