@almadar/ui 5.35.0 → 5.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +341 -285
- package/dist/avl/index.js +341 -282
- package/dist/components/game/organisms/puzzles/builder/BuilderBoard.d.ts +18 -5
- package/dist/components/game/organisms/puzzles/classifier/ClassifierBoard.d.ts +21 -3
- package/dist/components/game/organisms/puzzles/debugger/DebuggerBoard.d.ts +12 -2
- package/dist/components/game/organisms/puzzles/negotiator/NegotiatorBoard.d.ts +13 -3
- package/dist/components/game/organisms/puzzles/simulator/SimulatorBoard.d.ts +22 -7
- package/dist/components/index.cjs +348 -288
- package/dist/components/index.js +348 -285
- package/dist/docs/index.cjs +115 -81
- package/dist/docs/index.js +115 -78
- package/dist/marketing/index.cjs +114 -80
- package/dist/marketing/index.js +114 -77
- package/dist/providers/index.cjs +341 -285
- package/dist/providers/index.js +341 -282
- package/dist/runtime/index.cjs +341 -285
- package/dist/runtime/index.js +341 -282
- package/package.json +1 -1
package/dist/providers/index.js
CHANGED
|
@@ -7,9 +7,6 @@ import { clsx } from 'clsx';
|
|
|
7
7
|
import { twMerge } from 'tailwind-merge';
|
|
8
8
|
import * as LucideIcons2 from 'lucide-react';
|
|
9
9
|
import { Loader2, X, Lightbulb, CheckCircle, List, Printer, ChevronRight, ChevronLeft, GitBranch, Pencil, Eye, Plus, ArrowRight, Trash, Code, FileText, WrapText, Check, Copy, 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';
|
|
10
|
-
import * as PhosphorIcons from '@phosphor-icons/react';
|
|
11
|
-
import * as TablerIcons from '@tabler/icons-react';
|
|
12
|
-
import * as FaIcons from 'react-icons/fa';
|
|
13
10
|
import { createPortal } from 'react-dom';
|
|
14
11
|
import { useTranslate } from '@almadar/ui/hooks';
|
|
15
12
|
import { evaluate, createMinimalContext } from '@almadar/evaluator';
|
|
@@ -793,6 +790,41 @@ function kebabToPascal(name) {
|
|
|
793
790
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
794
791
|
}).join("");
|
|
795
792
|
}
|
|
793
|
+
function loadLib(key, importer) {
|
|
794
|
+
let p2 = libPromises.get(key);
|
|
795
|
+
if (!p2) {
|
|
796
|
+
p2 = importer().then((m) => m);
|
|
797
|
+
libPromises.set(key, p2);
|
|
798
|
+
}
|
|
799
|
+
return p2;
|
|
800
|
+
}
|
|
801
|
+
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
802
|
+
const Lazy = React83__default.lazy(async () => {
|
|
803
|
+
const lib = await loadLib(libKey, importer);
|
|
804
|
+
const Comp = pick(lib);
|
|
805
|
+
if (!Comp) {
|
|
806
|
+
warnFallback(fallbackName, family);
|
|
807
|
+
return { default: makeLucideAdapter(fallbackName, true) };
|
|
808
|
+
}
|
|
809
|
+
return { default: Comp };
|
|
810
|
+
});
|
|
811
|
+
const Wrapped = (props) => /* @__PURE__ */ jsx(
|
|
812
|
+
React83__default.Suspense,
|
|
813
|
+
{
|
|
814
|
+
fallback: /* @__PURE__ */ jsx(
|
|
815
|
+
"span",
|
|
816
|
+
{
|
|
817
|
+
"aria-hidden": true,
|
|
818
|
+
className: props.className,
|
|
819
|
+
style: { display: "inline-block", ...props.style }
|
|
820
|
+
}
|
|
821
|
+
),
|
|
822
|
+
children: /* @__PURE__ */ jsx(Lazy, { ...props })
|
|
823
|
+
}
|
|
824
|
+
);
|
|
825
|
+
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
826
|
+
return Wrapped;
|
|
827
|
+
}
|
|
796
828
|
function resolveLucide(name) {
|
|
797
829
|
if (lucideAliases[name]) return lucideAliases[name];
|
|
798
830
|
const pascal = kebabToPascal(name);
|
|
@@ -803,60 +835,81 @@ function resolveLucide(name) {
|
|
|
803
835
|
if (asIs && typeof asIs === "object") return asIs;
|
|
804
836
|
return LucideIcons2.HelpCircle;
|
|
805
837
|
}
|
|
806
|
-
function resolvePhosphor(name, weight) {
|
|
838
|
+
function resolvePhosphor(name, weight, family) {
|
|
807
839
|
const target = phosphorAliases[name] ?? kebabToPascal(name);
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
840
|
+
return lazyFamilyIcon(
|
|
841
|
+
"phosphor",
|
|
842
|
+
() => import('@phosphor-icons/react'),
|
|
843
|
+
(lib) => {
|
|
844
|
+
const PhosphorComp = lib[target];
|
|
845
|
+
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
846
|
+
const Component = PhosphorComp;
|
|
847
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
848
|
+
Component,
|
|
849
|
+
{
|
|
850
|
+
weight,
|
|
851
|
+
className: props.className,
|
|
852
|
+
style: props.style,
|
|
853
|
+
size: props.size ?? "1em"
|
|
854
|
+
}
|
|
855
|
+
);
|
|
856
|
+
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
857
|
+
return Adapter;
|
|
858
|
+
},
|
|
859
|
+
name,
|
|
860
|
+
family
|
|
820
861
|
);
|
|
821
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
822
|
-
return Adapter;
|
|
823
862
|
}
|
|
824
|
-
function resolveTabler(name) {
|
|
863
|
+
function resolveTabler(name, family) {
|
|
825
864
|
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
826
865
|
const target = `Icon${suffix}`;
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
866
|
+
return lazyFamilyIcon(
|
|
867
|
+
"tabler",
|
|
868
|
+
() => import('@tabler/icons-react'),
|
|
869
|
+
(lib) => {
|
|
870
|
+
const TablerComp = lib[target];
|
|
871
|
+
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
872
|
+
const Component = TablerComp;
|
|
873
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
874
|
+
Component,
|
|
875
|
+
{
|
|
876
|
+
stroke: props.strokeWidth ?? 1.5,
|
|
877
|
+
className: props.className,
|
|
878
|
+
style: props.style,
|
|
879
|
+
size: props.size ?? 24
|
|
880
|
+
}
|
|
881
|
+
);
|
|
882
|
+
Adapter.displayName = `Tabler.${target}`;
|
|
883
|
+
return Adapter;
|
|
884
|
+
},
|
|
885
|
+
name,
|
|
886
|
+
family
|
|
839
887
|
);
|
|
840
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
841
|
-
return Adapter;
|
|
842
888
|
}
|
|
843
|
-
function resolveFa(name) {
|
|
889
|
+
function resolveFa(name, family) {
|
|
844
890
|
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
845
891
|
const target = `Fa${suffix}`;
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
892
|
+
return lazyFamilyIcon(
|
|
893
|
+
"fa",
|
|
894
|
+
() => import('react-icons/fa'),
|
|
895
|
+
(lib) => {
|
|
896
|
+
const FaComp = lib[target];
|
|
897
|
+
if (!FaComp || typeof FaComp !== "function") return null;
|
|
898
|
+
const Component = FaComp;
|
|
899
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
900
|
+
Component,
|
|
901
|
+
{
|
|
902
|
+
className: props.className,
|
|
903
|
+
style: props.style,
|
|
904
|
+
size: props.size ?? "1em"
|
|
905
|
+
}
|
|
906
|
+
);
|
|
907
|
+
Adapter.displayName = `Fa.${target}`;
|
|
908
|
+
return Adapter;
|
|
909
|
+
},
|
|
910
|
+
name,
|
|
911
|
+
family
|
|
857
912
|
);
|
|
858
|
-
Adapter.displayName = `Fa.${target}`;
|
|
859
|
-
return Adapter;
|
|
860
913
|
}
|
|
861
914
|
function warnFallback(name, family) {
|
|
862
915
|
const key = `${family}::${name}`;
|
|
@@ -890,39 +943,22 @@ function resolveIconForFamily(name, family) {
|
|
|
890
943
|
switch (family) {
|
|
891
944
|
case "lucide":
|
|
892
945
|
return makeLucideAdapter(name, false);
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
return
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
return makeLucideAdapter(name, true);
|
|
910
|
-
}
|
|
911
|
-
case "tabler": {
|
|
912
|
-
const t = resolveTabler(name);
|
|
913
|
-
if (t) return t;
|
|
914
|
-
warnFallback(name, family);
|
|
915
|
-
return makeLucideAdapter(name, true);
|
|
916
|
-
}
|
|
917
|
-
case "fa-solid": {
|
|
918
|
-
const f3 = resolveFa(name);
|
|
919
|
-
if (f3) return f3;
|
|
920
|
-
warnFallback(name, family);
|
|
921
|
-
return makeLucideAdapter(name, true);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
946
|
+
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
947
|
+
// dynamic-imports the library on first render and falls back to lucide
|
|
948
|
+
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
949
|
+
case "phosphor-outline":
|
|
950
|
+
return resolvePhosphor(name, "regular", family);
|
|
951
|
+
case "phosphor-fill":
|
|
952
|
+
return resolvePhosphor(name, "fill", family);
|
|
953
|
+
case "phosphor-duotone":
|
|
954
|
+
return resolvePhosphor(name, "duotone", family);
|
|
955
|
+
case "tabler":
|
|
956
|
+
return resolveTabler(name, family);
|
|
957
|
+
case "fa-solid":
|
|
958
|
+
return resolveFa(name, family);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
926
962
|
var init_iconFamily = __esm({
|
|
927
963
|
"lib/iconFamily.tsx"() {
|
|
928
964
|
"use client";
|
|
@@ -938,6 +974,7 @@ var init_iconFamily = __esm({
|
|
|
938
974
|
cachedFamily = null;
|
|
939
975
|
listeners = /* @__PURE__ */ new Set();
|
|
940
976
|
observer = null;
|
|
977
|
+
libPromises = /* @__PURE__ */ new Map();
|
|
941
978
|
lucideAliases = {
|
|
942
979
|
close: LucideIcons2.X,
|
|
943
980
|
trash: LucideIcons2.Trash2,
|
|
@@ -17372,61 +17409,53 @@ var init_Breadcrumb = __esm({
|
|
|
17372
17409
|
function BuilderBoard({
|
|
17373
17410
|
entity,
|
|
17374
17411
|
completeEvent = "PUZZLE_COMPLETE",
|
|
17412
|
+
placeEvent,
|
|
17413
|
+
checkEvent,
|
|
17414
|
+
playAgainEvent,
|
|
17375
17415
|
className
|
|
17376
17416
|
}) {
|
|
17377
17417
|
const { emit } = useEventBus();
|
|
17378
17418
|
const { t } = useTranslate();
|
|
17379
17419
|
const resolved = boardEntity(entity);
|
|
17380
|
-
const [placements, setPlacements] = useState({});
|
|
17381
17420
|
const [headerError, setHeaderError] = useState(false);
|
|
17382
|
-
const [
|
|
17383
|
-
const [attempts, setAttempts] = useState(0);
|
|
17384
|
-
const [showHint, setShowHint] = useState(false);
|
|
17421
|
+
const [selectedComponent, setSelectedComponent] = useState(null);
|
|
17385
17422
|
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
17386
17423
|
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
17424
|
+
const placements = {};
|
|
17425
|
+
for (const slot of slots) {
|
|
17426
|
+
if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
|
|
17427
|
+
}
|
|
17428
|
+
const attempts = num(resolved?.attempts);
|
|
17429
|
+
const result = str(resolved?.result) || "none";
|
|
17430
|
+
const submitted = result === "win";
|
|
17387
17431
|
const usedComponentIds = new Set(Object.values(placements));
|
|
17388
17432
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
17389
|
-
const
|
|
17390
|
-
const allPlaced = Object.keys(placements).length === slots.length;
|
|
17433
|
+
const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
|
|
17391
17434
|
const results = submitted ? slots.map((slot) => ({
|
|
17392
17435
|
slot,
|
|
17393
17436
|
placed: placements[slot.id],
|
|
17394
|
-
correct: placements[slot.id] === slot.
|
|
17437
|
+
correct: placements[slot.id] === slot.requiredComponentId
|
|
17395
17438
|
})) : [];
|
|
17396
|
-
const
|
|
17439
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
17397
17440
|
const handlePlaceComponent = (slotId) => {
|
|
17398
17441
|
if (submitted || !selectedComponent) return;
|
|
17399
|
-
|
|
17442
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
|
|
17400
17443
|
setSelectedComponent(null);
|
|
17401
17444
|
};
|
|
17402
17445
|
const handleRemoveFromSlot = (slotId) => {
|
|
17403
17446
|
if (submitted) return;
|
|
17404
|
-
|
|
17405
|
-
const next = { ...prev };
|
|
17406
|
-
delete next[slotId];
|
|
17407
|
-
return next;
|
|
17408
|
-
});
|
|
17447
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
|
|
17409
17448
|
};
|
|
17410
|
-
const handleSubmit =
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
if (correct) {
|
|
17449
|
+
const handleSubmit = () => {
|
|
17450
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
17451
|
+
const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
|
|
17452
|
+
if (solved && completeEvent) {
|
|
17415
17453
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
17416
17454
|
}
|
|
17417
|
-
}, [slots, placements, attempts, completeEvent, emit]);
|
|
17418
|
-
const handleReset = () => {
|
|
17419
|
-
setSubmitted(false);
|
|
17420
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
17421
|
-
setShowHint(true);
|
|
17422
|
-
}
|
|
17423
17455
|
};
|
|
17424
|
-
const
|
|
17425
|
-
setPlacements({});
|
|
17426
|
-
setSubmitted(false);
|
|
17456
|
+
const handlePlayAgain = () => {
|
|
17427
17457
|
setSelectedComponent(null);
|
|
17428
|
-
|
|
17429
|
-
setShowHint(false);
|
|
17458
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
17430
17459
|
};
|
|
17431
17460
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
17432
17461
|
if (!resolved) return null;
|
|
@@ -17476,13 +17505,13 @@ function BuilderBoard({
|
|
|
17476
17505
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
|
|
17477
17506
|
/* @__PURE__ */ jsx(VStack, { gap: "sm", children: slots.map((slot) => {
|
|
17478
17507
|
const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
|
|
17479
|
-
const
|
|
17508
|
+
const result2 = results.find((r) => r.slot.id === slot.id);
|
|
17480
17509
|
return /* @__PURE__ */ jsxs(
|
|
17481
17510
|
HStack,
|
|
17482
17511
|
{
|
|
17483
17512
|
gap: "sm",
|
|
17484
17513
|
align: "center",
|
|
17485
|
-
className: `p-3 border-2 rounded ${
|
|
17514
|
+
className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
|
|
17486
17515
|
onClick: () => handlePlaceComponent(slot.id),
|
|
17487
17516
|
children: [
|
|
17488
17517
|
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
|
|
@@ -17497,7 +17526,7 @@ function BuilderBoard({
|
|
|
17497
17526
|
] }) : null,
|
|
17498
17527
|
placedComp.label
|
|
17499
17528
|
] }),
|
|
17500
|
-
|
|
17529
|
+
result2 && /* @__PURE__ */ jsx(Icon, { icon: result2.correct ? CheckCircle : XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
|
|
17501
17530
|
] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
|
|
17502
17531
|
]
|
|
17503
17532
|
},
|
|
@@ -17506,16 +17535,16 @@ function BuilderBoard({
|
|
|
17506
17535
|
}) })
|
|
17507
17536
|
] }) }),
|
|
17508
17537
|
submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17509
|
-
/* @__PURE__ */ jsx(Icon, { icon:
|
|
17510
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children:
|
|
17538
|
+
/* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: "text-success" }),
|
|
17539
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
|
|
17511
17540
|
] }) }),
|
|
17512
17541
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
17513
17542
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17514
|
-
!submitted
|
|
17543
|
+
!submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17515
17544
|
/* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
|
|
17516
17545
|
t("builder.build")
|
|
17517
|
-
] })
|
|
17518
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick:
|
|
17546
|
+
] }),
|
|
17547
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
17519
17548
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
17520
17549
|
t("builder.reset")
|
|
17521
17550
|
] })
|
|
@@ -20971,57 +21000,84 @@ var init_ChartLegend = __esm({
|
|
|
20971
21000
|
function ClassifierBoard({
|
|
20972
21001
|
entity,
|
|
20973
21002
|
completeEvent = "PUZZLE_COMPLETE",
|
|
21003
|
+
assignEvent,
|
|
21004
|
+
checkEvent,
|
|
21005
|
+
playAgainEvent,
|
|
20974
21006
|
className
|
|
20975
21007
|
}) {
|
|
20976
21008
|
const { emit } = useEventBus();
|
|
20977
21009
|
const { t } = useTranslate();
|
|
20978
21010
|
const resolved = boardEntity(entity);
|
|
20979
|
-
const [
|
|
21011
|
+
const [localAssignments, setLocalAssignments] = useState({});
|
|
20980
21012
|
const [headerError, setHeaderError] = useState(false);
|
|
20981
|
-
const [
|
|
20982
|
-
const [
|
|
21013
|
+
const [localSubmitted, setLocalSubmitted] = useState(false);
|
|
21014
|
+
const [localAttempts, setLocalAttempts] = useState(0);
|
|
20983
21015
|
const [showHint, setShowHint] = useState(false);
|
|
20984
21016
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
20985
21017
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
21018
|
+
const entityResult = str(resolved?.result);
|
|
21019
|
+
const entityDrivesResult = entityResult.length > 0;
|
|
21020
|
+
const entityHasAssignments = items.some((item) => item.assignedCategory != null);
|
|
21021
|
+
const assignments = entityHasAssignments ? items.reduce((acc, item) => {
|
|
21022
|
+
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
21023
|
+
return acc;
|
|
21024
|
+
}, {}) : localAssignments;
|
|
21025
|
+
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
21026
|
+
const submitted = entityDrivesResult || localSubmitted;
|
|
20986
21027
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
20987
|
-
const allAssigned = Object.keys(assignments).length === items.length;
|
|
21028
|
+
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
20988
21029
|
const results = submitted ? items.map((item) => ({
|
|
20989
21030
|
item,
|
|
20990
21031
|
assigned: assignments[item.id],
|
|
20991
21032
|
correct: assignments[item.id] === item.correctCategory
|
|
20992
21033
|
})) : [];
|
|
20993
|
-
const allCorrect = results.length > 0 && results.every((r) => r.correct);
|
|
21034
|
+
const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r) => r.correct);
|
|
20994
21035
|
const correctCount = results.filter((r) => r.correct).length;
|
|
20995
21036
|
const handleAssign = (itemId, categoryId) => {
|
|
20996
21037
|
if (submitted) return;
|
|
20997
|
-
|
|
21038
|
+
if (assignEvent) {
|
|
21039
|
+
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
21040
|
+
}
|
|
21041
|
+
if (!entityHasAssignments) {
|
|
21042
|
+
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
21043
|
+
}
|
|
20998
21044
|
};
|
|
20999
21045
|
const handleUnassign = (itemId) => {
|
|
21000
21046
|
if (submitted) return;
|
|
21001
|
-
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
|
|
21005
|
-
|
|
21047
|
+
if (!entityHasAssignments) {
|
|
21048
|
+
setLocalAssignments((prev) => {
|
|
21049
|
+
const next = { ...prev };
|
|
21050
|
+
delete next[itemId];
|
|
21051
|
+
return next;
|
|
21052
|
+
});
|
|
21053
|
+
}
|
|
21006
21054
|
};
|
|
21007
21055
|
const handleSubmit = useCallback(() => {
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
if (
|
|
21012
|
-
|
|
21056
|
+
if (checkEvent) {
|
|
21057
|
+
emit(`UI:${checkEvent}`, {});
|
|
21058
|
+
}
|
|
21059
|
+
if (!entityDrivesResult) {
|
|
21060
|
+
setLocalSubmitted(true);
|
|
21061
|
+
setLocalAttempts((a) => a + 1);
|
|
21062
|
+
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
21063
|
+
if (correct) {
|
|
21064
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
21065
|
+
}
|
|
21013
21066
|
}
|
|
21014
|
-
}, [items, assignments, attempts, completeEvent, emit]);
|
|
21067
|
+
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
21015
21068
|
const handleReset = () => {
|
|
21016
|
-
|
|
21069
|
+
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
21017
21070
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
21018
21071
|
setShowHint(true);
|
|
21019
21072
|
}
|
|
21020
21073
|
};
|
|
21021
21074
|
const handleFullReset = () => {
|
|
21022
|
-
|
|
21023
|
-
|
|
21024
|
-
|
|
21075
|
+
if (playAgainEvent) {
|
|
21076
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
21077
|
+
}
|
|
21078
|
+
setLocalAssignments({});
|
|
21079
|
+
setLocalSubmitted(false);
|
|
21080
|
+
setLocalAttempts(0);
|
|
21025
21081
|
setShowHint(false);
|
|
21026
21082
|
};
|
|
21027
21083
|
if (!resolved) return null;
|
|
@@ -28904,13 +28960,13 @@ var init_MapView = __esm({
|
|
|
28904
28960
|
shadowSize: [41, 41]
|
|
28905
28961
|
});
|
|
28906
28962
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28907
|
-
const { useEffect:
|
|
28963
|
+
const { useEffect: useEffect73, useRef: useRef68, useCallback: useCallback111, useState: useState104 } = React83__default;
|
|
28908
28964
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28909
28965
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28910
28966
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28911
28967
|
const map = useMap();
|
|
28912
|
-
const prevRef =
|
|
28913
|
-
|
|
28968
|
+
const prevRef = useRef68({ centerLat, centerLng, zoom });
|
|
28969
|
+
useEffect73(() => {
|
|
28914
28970
|
const prev = prevRef.current;
|
|
28915
28971
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
28916
28972
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -28921,7 +28977,7 @@ var init_MapView = __esm({
|
|
|
28921
28977
|
}
|
|
28922
28978
|
function MapClickHandler({ onMapClick }) {
|
|
28923
28979
|
const map = useMap();
|
|
28924
|
-
|
|
28980
|
+
useEffect73(() => {
|
|
28925
28981
|
if (!onMapClick) return;
|
|
28926
28982
|
const handler = (e) => {
|
|
28927
28983
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -28950,7 +29006,7 @@ var init_MapView = __esm({
|
|
|
28950
29006
|
}) {
|
|
28951
29007
|
const eventBus = useEventBus2();
|
|
28952
29008
|
const [clickedPosition, setClickedPosition] = useState104(null);
|
|
28953
|
-
const handleMapClick =
|
|
29009
|
+
const handleMapClick = useCallback111((lat, lng) => {
|
|
28954
29010
|
if (showClickedPin) {
|
|
28955
29011
|
setClickedPosition({ lat, lng });
|
|
28956
29012
|
}
|
|
@@ -28959,7 +29015,7 @@ var init_MapView = __esm({
|
|
|
28959
29015
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
28960
29016
|
}
|
|
28961
29017
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
28962
|
-
const handleMarkerClick =
|
|
29018
|
+
const handleMarkerClick = useCallback111((marker) => {
|
|
28963
29019
|
onMarkerClick?.(marker);
|
|
28964
29020
|
if (markerClickEvent) {
|
|
28965
29021
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -38181,51 +38237,52 @@ var init_DataTable = __esm({
|
|
|
38181
38237
|
function DebuggerBoard({
|
|
38182
38238
|
entity,
|
|
38183
38239
|
completeEvent = "PUZZLE_COMPLETE",
|
|
38240
|
+
toggleFlagEvent,
|
|
38241
|
+
checkEvent,
|
|
38242
|
+
playAgainEvent,
|
|
38184
38243
|
className
|
|
38185
38244
|
}) {
|
|
38186
38245
|
const { emit } = useEventBus();
|
|
38187
38246
|
const { t } = useTranslate();
|
|
38188
38247
|
const resolved = boardEntity(entity);
|
|
38189
|
-
const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
|
|
38190
38248
|
const [headerError, setHeaderError] = useState(false);
|
|
38191
|
-
const [submitted, setSubmitted] = useState(false);
|
|
38192
|
-
const [attempts, setAttempts] = useState(0);
|
|
38193
38249
|
const [showHint, setShowHint] = useState(false);
|
|
38250
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
38251
|
+
const result = resolved?.result ?? null;
|
|
38252
|
+
const attempts = num(resolved?.attempts);
|
|
38253
|
+
const submitted = result != null;
|
|
38254
|
+
const bugLines = lines.filter((l) => l.isBug);
|
|
38255
|
+
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
38256
|
+
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
38257
|
+
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
38258
|
+
const allCorrect = result === "win";
|
|
38194
38259
|
const toggleLine = (lineId) => {
|
|
38195
38260
|
if (submitted) return;
|
|
38196
|
-
|
|
38197
|
-
|
|
38198
|
-
|
|
38199
|
-
next.delete(lineId);
|
|
38200
|
-
} else {
|
|
38201
|
-
next.add(lineId);
|
|
38202
|
-
}
|
|
38203
|
-
return next;
|
|
38204
|
-
});
|
|
38261
|
+
if (toggleFlagEvent) {
|
|
38262
|
+
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
38263
|
+
}
|
|
38205
38264
|
};
|
|
38206
|
-
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
38207
|
-
const bugLines = lines.filter((l) => l.isBug);
|
|
38208
|
-
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
38209
|
-
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
38210
|
-
const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
38211
38265
|
const handleSubmit = useCallback(() => {
|
|
38212
|
-
|
|
38213
|
-
|
|
38266
|
+
if (checkEvent) {
|
|
38267
|
+
emit(`UI:${checkEvent}`, {});
|
|
38268
|
+
}
|
|
38214
38269
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
38215
38270
|
if (correct) {
|
|
38216
38271
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
38217
38272
|
}
|
|
38218
|
-
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
38273
|
+
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
38219
38274
|
const handleReset = () => {
|
|
38220
|
-
|
|
38275
|
+
if (playAgainEvent) {
|
|
38276
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
38277
|
+
}
|
|
38221
38278
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
38222
38279
|
setShowHint(true);
|
|
38223
38280
|
}
|
|
38224
38281
|
};
|
|
38225
38282
|
const handleFullReset = () => {
|
|
38226
|
-
|
|
38227
|
-
|
|
38228
|
-
|
|
38283
|
+
if (playAgainEvent) {
|
|
38284
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
38285
|
+
}
|
|
38229
38286
|
setShowHint(false);
|
|
38230
38287
|
};
|
|
38231
38288
|
if (!resolved) return null;
|
|
@@ -38253,7 +38310,7 @@ function DebuggerBoard({
|
|
|
38253
38310
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
38254
38311
|
] }) }),
|
|
38255
38312
|
/* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
38256
|
-
const isFlagged =
|
|
38313
|
+
const isFlagged = !!line.isFlagged;
|
|
38257
38314
|
let lineStyle = "";
|
|
38258
38315
|
if (submitted) {
|
|
38259
38316
|
if (line.isBug && isFlagged) lineStyle = "bg-success/10";
|
|
@@ -38287,9 +38344,9 @@ function DebuggerBoard({
|
|
|
38287
38344
|
/* @__PURE__ */ jsx(
|
|
38288
38345
|
Icon,
|
|
38289
38346
|
{
|
|
38290
|
-
icon:
|
|
38347
|
+
icon: line.isFlagged ? CheckCircle : XCircle,
|
|
38291
38348
|
size: "xs",
|
|
38292
|
-
className:
|
|
38349
|
+
className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
|
|
38293
38350
|
}
|
|
38294
38351
|
),
|
|
38295
38352
|
/* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
|
|
@@ -38300,7 +38357,7 @@ function DebuggerBoard({
|
|
|
38300
38357
|
] }) }),
|
|
38301
38358
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
38302
38359
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
38303
|
-
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.
|
|
38360
|
+
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
38304
38361
|
/* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
|
|
38305
38362
|
t("debugger.submit")
|
|
38306
38363
|
] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
|
|
@@ -42064,6 +42121,9 @@ function getOpponentAction(strategy, actions, history) {
|
|
|
42064
42121
|
function NegotiatorBoard({
|
|
42065
42122
|
entity,
|
|
42066
42123
|
completeEvent = "PUZZLE_COMPLETE",
|
|
42124
|
+
playRoundEvent,
|
|
42125
|
+
finishEvent,
|
|
42126
|
+
playAgainEvent,
|
|
42067
42127
|
className
|
|
42068
42128
|
}) {
|
|
42069
42129
|
const { emit } = useEventBus();
|
|
@@ -42072,13 +42132,14 @@ function NegotiatorBoard({
|
|
|
42072
42132
|
const [history, setHistory] = useState([]);
|
|
42073
42133
|
const [headerError, setHeaderError] = useState(false);
|
|
42074
42134
|
const [showHint, setShowHint] = useState(false);
|
|
42075
|
-
const totalRounds = num(resolved?.
|
|
42135
|
+
const totalRounds = num(resolved?.maxRounds);
|
|
42076
42136
|
const targetScore = num(resolved?.targetScore);
|
|
42077
|
-
const currentRound =
|
|
42078
|
-
const
|
|
42079
|
-
const playerTotal =
|
|
42137
|
+
const currentRound = num(resolved?.round);
|
|
42138
|
+
const result = str(resolved?.result) || "none";
|
|
42139
|
+
const playerTotal = num(resolved?.score);
|
|
42140
|
+
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
42141
|
+
const won = result === "win";
|
|
42080
42142
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
42081
|
-
const won = isComplete && playerTotal >= targetScore;
|
|
42082
42143
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
42083
42144
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
42084
42145
|
const handleAction = useCallback((actionId) => {
|
|
@@ -42087,29 +42148,45 @@ function NegotiatorBoard({
|
|
|
42087
42148
|
const payoff = payoffMatrix.find(
|
|
42088
42149
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
42089
42150
|
);
|
|
42090
|
-
const
|
|
42091
|
-
|
|
42092
|
-
|
|
42093
|
-
|
|
42094
|
-
|
|
42095
|
-
|
|
42096
|
-
|
|
42097
|
-
|
|
42098
|
-
|
|
42099
|
-
|
|
42100
|
-
|
|
42101
|
-
|
|
42102
|
-
|
|
42103
|
-
|
|
42104
|
-
|
|
42151
|
+
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
42152
|
+
setHistory((prev) => [
|
|
42153
|
+
...prev,
|
|
42154
|
+
{
|
|
42155
|
+
round: prev.length + 1,
|
|
42156
|
+
playerAction: actionId,
|
|
42157
|
+
opponentAction,
|
|
42158
|
+
playerPayoff,
|
|
42159
|
+
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
42160
|
+
}
|
|
42161
|
+
]);
|
|
42162
|
+
if (playRoundEvent) {
|
|
42163
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
|
|
42164
|
+
}
|
|
42165
|
+
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
42166
|
+
if (finishEvent) {
|
|
42167
|
+
emit(`UI:${finishEvent}`, {});
|
|
42168
|
+
}
|
|
42169
|
+
if (str(resolved?.hint)) {
|
|
42105
42170
|
setShowHint(true);
|
|
42106
42171
|
}
|
|
42107
42172
|
}
|
|
42108
|
-
}, [isComplete, resolved, totalRounds,
|
|
42109
|
-
const handleReset = () => {
|
|
42173
|
+
}, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
|
|
42174
|
+
const handleReset = useCallback(() => {
|
|
42110
42175
|
setHistory([]);
|
|
42111
42176
|
setShowHint(false);
|
|
42112
|
-
|
|
42177
|
+
if (playAgainEvent) {
|
|
42178
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
42179
|
+
}
|
|
42180
|
+
}, [playAgainEvent, emit]);
|
|
42181
|
+
const completedRef = useRef(false);
|
|
42182
|
+
useEffect(() => {
|
|
42183
|
+
if (result === "win" && !completedRef.current) {
|
|
42184
|
+
completedRef.current = true;
|
|
42185
|
+
emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
|
|
42186
|
+
} else if (result === "none") {
|
|
42187
|
+
completedRef.current = false;
|
|
42188
|
+
}
|
|
42189
|
+
}, [result, playerTotal, completeEvent, emit]);
|
|
42113
42190
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
42114
42191
|
if (!resolved) return null;
|
|
42115
42192
|
const theme = resolved.theme ?? void 0;
|
|
@@ -45056,67 +45133,47 @@ var init_SimulationGraph = __esm({
|
|
|
45056
45133
|
function SimulatorBoard({
|
|
45057
45134
|
entity,
|
|
45058
45135
|
completeEvent = "PUZZLE_COMPLETE",
|
|
45136
|
+
setAEvent,
|
|
45137
|
+
setBEvent,
|
|
45138
|
+
checkEvent,
|
|
45139
|
+
playAgainEvent,
|
|
45059
45140
|
className
|
|
45060
45141
|
}) {
|
|
45061
45142
|
const { emit } = useEventBus();
|
|
45062
45143
|
const { t } = useTranslate();
|
|
45063
45144
|
const resolved = boardEntity(entity);
|
|
45064
45145
|
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
45065
|
-
const [values, setValues] = useState(() => {
|
|
45066
|
-
const init = {};
|
|
45067
|
-
for (const p2 of parameters) {
|
|
45068
|
-
init[p2.id] = p2.initial;
|
|
45069
|
-
}
|
|
45070
|
-
return init;
|
|
45071
|
-
});
|
|
45072
45146
|
const [headerError, setHeaderError] = useState(false);
|
|
45073
|
-
|
|
45074
|
-
const
|
|
45075
|
-
const
|
|
45076
|
-
const
|
|
45077
|
-
|
|
45078
|
-
|
|
45079
|
-
|
|
45080
|
-
|
|
45081
|
-
|
|
45082
|
-
|
|
45083
|
-
|
|
45084
|
-
const
|
|
45085
|
-
const
|
|
45086
|
-
const
|
|
45087
|
-
const
|
|
45088
|
-
|
|
45089
|
-
|
|
45090
|
-
|
|
45091
|
-
};
|
|
45092
|
-
const handleSubmit = () => {
|
|
45093
|
-
setSubmitted(true);
|
|
45094
|
-
setAttempts((a) => a + 1);
|
|
45095
|
-
if (isCorrect) {
|
|
45096
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
45097
|
-
}
|
|
45147
|
+
if (!resolved) return null;
|
|
45148
|
+
const paramA = num(resolved.paramA);
|
|
45149
|
+
const paramB = num(resolved.paramB);
|
|
45150
|
+
const output = num(resolved.output);
|
|
45151
|
+
const targetValue = num(resolved.target);
|
|
45152
|
+
const targetTolerance = num(resolved.tolerance);
|
|
45153
|
+
const attempts = num(resolved.attempts);
|
|
45154
|
+
const result = str(resolved.result);
|
|
45155
|
+
const isWin = result === "win";
|
|
45156
|
+
const isComplete = result !== "none" && result !== "";
|
|
45157
|
+
const paramAValue = parameters[0];
|
|
45158
|
+
const paramBValue = parameters[1];
|
|
45159
|
+
const sliderValues = [paramA, paramB];
|
|
45160
|
+
const sliderEvents = [setAEvent, setBEvent];
|
|
45161
|
+
const handleParameterChange = (index, value) => {
|
|
45162
|
+
if (isComplete) return;
|
|
45163
|
+
const ev = sliderEvents[index];
|
|
45164
|
+
if (ev) emit(`UI:${ev}`, { value });
|
|
45098
45165
|
};
|
|
45099
|
-
const
|
|
45100
|
-
|
|
45101
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
45102
|
-
setShowHint(true);
|
|
45103
|
-
}
|
|
45166
|
+
const handleCheck = () => {
|
|
45167
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
45104
45168
|
};
|
|
45105
|
-
const
|
|
45106
|
-
|
|
45107
|
-
for (const p2 of parameters) {
|
|
45108
|
-
init[p2.id] = p2.initial;
|
|
45109
|
-
}
|
|
45110
|
-
setValues(init);
|
|
45111
|
-
setSubmitted(false);
|
|
45112
|
-
setAttempts(0);
|
|
45113
|
-
setShowHint(false);
|
|
45169
|
+
const handlePlayAgain = () => {
|
|
45170
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
45114
45171
|
};
|
|
45115
|
-
if (!resolved) return null;
|
|
45116
45172
|
const theme = resolved.theme ?? void 0;
|
|
45117
45173
|
const themeBackground = theme?.background;
|
|
45118
45174
|
const headerImage = str(resolved.headerImage);
|
|
45119
45175
|
const hint = str(resolved.hint);
|
|
45176
|
+
const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
|
|
45120
45177
|
const outputLabel = str(resolved.outputLabel);
|
|
45121
45178
|
const outputUnit = str(resolved.outputUnit);
|
|
45122
45179
|
return /* @__PURE__ */ jsx(
|
|
@@ -45136,41 +45193,43 @@ function SimulatorBoard({
|
|
|
45136
45193
|
] }) }),
|
|
45137
45194
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
|
|
45138
45195
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
45139
|
-
|
|
45140
|
-
/* @__PURE__ */ jsxs(
|
|
45141
|
-
/* @__PURE__ */
|
|
45142
|
-
|
|
45143
|
-
|
|
45144
|
-
|
|
45145
|
-
|
|
45146
|
-
|
|
45147
|
-
|
|
45148
|
-
/* @__PURE__ */ jsx(
|
|
45149
|
-
"input",
|
|
45150
|
-
{
|
|
45151
|
-
type: "range",
|
|
45152
|
-
min: param.min,
|
|
45153
|
-
max: param.max,
|
|
45154
|
-
step: param.step,
|
|
45155
|
-
value: values[param.id],
|
|
45156
|
-
onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
|
|
45157
|
-
disabled: submitted,
|
|
45158
|
-
className: "w-full accent-foreground"
|
|
45159
|
-
}
|
|
45160
|
-
),
|
|
45161
|
-
/* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
|
|
45162
|
-
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45163
|
-
param.min,
|
|
45164
|
-
" ",
|
|
45165
|
-
param.unit
|
|
45196
|
+
[paramAValue, paramBValue].map(
|
|
45197
|
+
(param, index) => param ? /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
45198
|
+
/* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
|
|
45199
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
|
|
45200
|
+
/* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
|
|
45201
|
+
sliderValues[index],
|
|
45202
|
+
" ",
|
|
45203
|
+
param.unit
|
|
45204
|
+
] })
|
|
45166
45205
|
] }),
|
|
45167
|
-
/* @__PURE__ */
|
|
45168
|
-
|
|
45169
|
-
|
|
45170
|
-
|
|
45206
|
+
/* @__PURE__ */ jsx(
|
|
45207
|
+
"input",
|
|
45208
|
+
{
|
|
45209
|
+
type: "range",
|
|
45210
|
+
min: param.min,
|
|
45211
|
+
max: param.max,
|
|
45212
|
+
step: param.step,
|
|
45213
|
+
value: sliderValues[index],
|
|
45214
|
+
onChange: (e) => handleParameterChange(index, Number(e.target.value)),
|
|
45215
|
+
disabled: isComplete,
|
|
45216
|
+
className: "w-full accent-foreground"
|
|
45217
|
+
}
|
|
45218
|
+
),
|
|
45219
|
+
/* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
|
|
45220
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45221
|
+
param.min,
|
|
45222
|
+
" ",
|
|
45223
|
+
param.unit
|
|
45224
|
+
] }),
|
|
45225
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45226
|
+
param.max,
|
|
45227
|
+
" ",
|
|
45228
|
+
param.unit
|
|
45229
|
+
] })
|
|
45171
45230
|
] })
|
|
45172
|
-
] })
|
|
45173
|
-
|
|
45231
|
+
] }, param.id ?? index) : null
|
|
45232
|
+
)
|
|
45174
45233
|
] }) }),
|
|
45175
45234
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
45176
45235
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
@@ -45179,9 +45238,9 @@ function SimulatorBoard({
|
|
|
45179
45238
|
" ",
|
|
45180
45239
|
outputUnit
|
|
45181
45240
|
] }),
|
|
45182
|
-
|
|
45183
|
-
/* @__PURE__ */ jsx(Icon, { icon:
|
|
45184
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", className:
|
|
45241
|
+
isComplete && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
45242
|
+
/* @__PURE__ */ jsx(Icon, { icon: isWin ? CheckCircle : XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
|
|
45243
|
+
/* @__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") })
|
|
45185
45244
|
] }),
|
|
45186
45245
|
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
45187
45246
|
t("simulator.target"),
|
|
@@ -45196,11 +45255,11 @@ function SimulatorBoard({
|
|
|
45196
45255
|
] }) }),
|
|
45197
45256
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
45198
45257
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
45199
|
-
!
|
|
45258
|
+
!isComplete ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
|
|
45200
45259
|
/* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
|
|
45201
45260
|
t("simulator.simulate")
|
|
45202
|
-
] }) :
|
|
45203
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick:
|
|
45261
|
+
] }) : null,
|
|
45262
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
45204
45263
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
45205
45264
|
t("simulator.reset")
|
|
45206
45265
|
] })
|