@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.js
CHANGED
|
@@ -7,9 +7,6 @@ import { EventBusContext, useTraitScope, OrbitalProvider, TraitScopeProvider, Ve
|
|
|
7
7
|
import { createLogger, isLogLevelEnabled } from '@almadar/logger';
|
|
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, useEventBus as useEventBus$1 } from '@almadar/ui/hooks';
|
|
15
12
|
import { evaluate, createMinimalContext } from '@almadar/evaluator';
|
|
@@ -529,6 +526,41 @@ function kebabToPascal(name) {
|
|
|
529
526
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
530
527
|
}).join("");
|
|
531
528
|
}
|
|
529
|
+
function loadLib(key, importer) {
|
|
530
|
+
let p2 = libPromises.get(key);
|
|
531
|
+
if (!p2) {
|
|
532
|
+
p2 = importer().then((m) => m);
|
|
533
|
+
libPromises.set(key, p2);
|
|
534
|
+
}
|
|
535
|
+
return p2;
|
|
536
|
+
}
|
|
537
|
+
function lazyFamilyIcon(libKey, importer, pick, fallbackName, family) {
|
|
538
|
+
const Lazy = React82__default.lazy(async () => {
|
|
539
|
+
const lib = await loadLib(libKey, importer);
|
|
540
|
+
const Comp = pick(lib);
|
|
541
|
+
if (!Comp) {
|
|
542
|
+
warnFallback(fallbackName, family);
|
|
543
|
+
return { default: makeLucideAdapter(fallbackName, true) };
|
|
544
|
+
}
|
|
545
|
+
return { default: Comp };
|
|
546
|
+
});
|
|
547
|
+
const Wrapped = (props) => /* @__PURE__ */ jsx(
|
|
548
|
+
React82__default.Suspense,
|
|
549
|
+
{
|
|
550
|
+
fallback: /* @__PURE__ */ jsx(
|
|
551
|
+
"span",
|
|
552
|
+
{
|
|
553
|
+
"aria-hidden": true,
|
|
554
|
+
className: props.className,
|
|
555
|
+
style: { display: "inline-block", ...props.style }
|
|
556
|
+
}
|
|
557
|
+
),
|
|
558
|
+
children: /* @__PURE__ */ jsx(Lazy, { ...props })
|
|
559
|
+
}
|
|
560
|
+
);
|
|
561
|
+
Wrapped.displayName = `Lazy.${libKey}.${fallbackName}`;
|
|
562
|
+
return Wrapped;
|
|
563
|
+
}
|
|
532
564
|
function resolveLucide(name) {
|
|
533
565
|
if (lucideAliases[name]) return lucideAliases[name];
|
|
534
566
|
const pascal = kebabToPascal(name);
|
|
@@ -539,60 +571,81 @@ function resolveLucide(name) {
|
|
|
539
571
|
if (asIs && typeof asIs === "object") return asIs;
|
|
540
572
|
return LucideIcons2.HelpCircle;
|
|
541
573
|
}
|
|
542
|
-
function resolvePhosphor(name, weight) {
|
|
574
|
+
function resolvePhosphor(name, weight, family) {
|
|
543
575
|
const target = phosphorAliases[name] ?? kebabToPascal(name);
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
576
|
+
return lazyFamilyIcon(
|
|
577
|
+
"phosphor",
|
|
578
|
+
() => import('@phosphor-icons/react'),
|
|
579
|
+
(lib) => {
|
|
580
|
+
const PhosphorComp = lib[target];
|
|
581
|
+
if (!PhosphorComp || typeof PhosphorComp !== "object") return null;
|
|
582
|
+
const Component = PhosphorComp;
|
|
583
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
584
|
+
Component,
|
|
585
|
+
{
|
|
586
|
+
weight,
|
|
587
|
+
className: props.className,
|
|
588
|
+
style: props.style,
|
|
589
|
+
size: props.size ?? "1em"
|
|
590
|
+
}
|
|
591
|
+
);
|
|
592
|
+
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
593
|
+
return Adapter;
|
|
594
|
+
},
|
|
595
|
+
name,
|
|
596
|
+
family
|
|
556
597
|
);
|
|
557
|
-
Adapter.displayName = `Phosphor.${target}.${weight}`;
|
|
558
|
-
return Adapter;
|
|
559
598
|
}
|
|
560
|
-
function resolveTabler(name) {
|
|
599
|
+
function resolveTabler(name, family) {
|
|
561
600
|
const suffix = tablerAliases[name] ?? kebabToPascal(name);
|
|
562
601
|
const target = `Icon${suffix}`;
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
602
|
+
return lazyFamilyIcon(
|
|
603
|
+
"tabler",
|
|
604
|
+
() => import('@tabler/icons-react'),
|
|
605
|
+
(lib) => {
|
|
606
|
+
const TablerComp = lib[target];
|
|
607
|
+
if (!TablerComp || typeof TablerComp !== "object") return null;
|
|
608
|
+
const Component = TablerComp;
|
|
609
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
610
|
+
Component,
|
|
611
|
+
{
|
|
612
|
+
stroke: props.strokeWidth ?? 1.5,
|
|
613
|
+
className: props.className,
|
|
614
|
+
style: props.style,
|
|
615
|
+
size: props.size ?? 24
|
|
616
|
+
}
|
|
617
|
+
);
|
|
618
|
+
Adapter.displayName = `Tabler.${target}`;
|
|
619
|
+
return Adapter;
|
|
620
|
+
},
|
|
621
|
+
name,
|
|
622
|
+
family
|
|
575
623
|
);
|
|
576
|
-
Adapter.displayName = `Tabler.${target}`;
|
|
577
|
-
return Adapter;
|
|
578
624
|
}
|
|
579
|
-
function resolveFa(name) {
|
|
625
|
+
function resolveFa(name, family) {
|
|
580
626
|
const suffix = faAliases[name] ?? kebabToPascal(name);
|
|
581
627
|
const target = `Fa${suffix}`;
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
628
|
+
return lazyFamilyIcon(
|
|
629
|
+
"fa",
|
|
630
|
+
() => import('react-icons/fa'),
|
|
631
|
+
(lib) => {
|
|
632
|
+
const FaComp = lib[target];
|
|
633
|
+
if (!FaComp || typeof FaComp !== "function") return null;
|
|
634
|
+
const Component = FaComp;
|
|
635
|
+
const Adapter = (props) => /* @__PURE__ */ jsx(
|
|
636
|
+
Component,
|
|
637
|
+
{
|
|
638
|
+
className: props.className,
|
|
639
|
+
style: props.style,
|
|
640
|
+
size: props.size ?? "1em"
|
|
641
|
+
}
|
|
642
|
+
);
|
|
643
|
+
Adapter.displayName = `Fa.${target}`;
|
|
644
|
+
return Adapter;
|
|
645
|
+
},
|
|
646
|
+
name,
|
|
647
|
+
family
|
|
593
648
|
);
|
|
594
|
-
Adapter.displayName = `Fa.${target}`;
|
|
595
|
-
return Adapter;
|
|
596
649
|
}
|
|
597
650
|
function warnFallback(name, family) {
|
|
598
651
|
const key = `${family}::${name}`;
|
|
@@ -626,39 +679,22 @@ function resolveIconForFamily(name, family) {
|
|
|
626
679
|
switch (family) {
|
|
627
680
|
case "lucide":
|
|
628
681
|
return makeLucideAdapter(name, false);
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
return
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
return
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
return makeLucideAdapter(name, true);
|
|
646
|
-
}
|
|
647
|
-
case "tabler": {
|
|
648
|
-
const t = resolveTabler(name);
|
|
649
|
-
if (t) return t;
|
|
650
|
-
warnFallback(name, family);
|
|
651
|
-
return makeLucideAdapter(name, true);
|
|
652
|
-
}
|
|
653
|
-
case "fa-solid": {
|
|
654
|
-
const f3 = resolveFa(name);
|
|
655
|
-
if (f3) return f3;
|
|
656
|
-
warnFallback(name, family);
|
|
657
|
-
return makeLucideAdapter(name, true);
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
682
|
+
// Non-lucide families resolve to a lazy, Suspense-wrapped component that
|
|
683
|
+
// dynamic-imports the library on first render and falls back to lucide
|
|
684
|
+
// internally when the family lacks the icon (see lazyFamilyIcon).
|
|
685
|
+
case "phosphor-outline":
|
|
686
|
+
return resolvePhosphor(name, "regular", family);
|
|
687
|
+
case "phosphor-fill":
|
|
688
|
+
return resolvePhosphor(name, "fill", family);
|
|
689
|
+
case "phosphor-duotone":
|
|
690
|
+
return resolvePhosphor(name, "duotone", family);
|
|
691
|
+
case "tabler":
|
|
692
|
+
return resolveTabler(name, family);
|
|
693
|
+
case "fa-solid":
|
|
694
|
+
return resolveFa(name, family);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
var DEFAULT_FAMILY, VALID_FAMILIES, cachedFamily, listeners, observer, libPromises, lucideAliases, phosphorAliases, tablerAliases, faAliases, warned;
|
|
662
698
|
var init_iconFamily = __esm({
|
|
663
699
|
"lib/iconFamily.tsx"() {
|
|
664
700
|
"use client";
|
|
@@ -674,6 +710,7 @@ var init_iconFamily = __esm({
|
|
|
674
710
|
cachedFamily = null;
|
|
675
711
|
listeners = /* @__PURE__ */ new Set();
|
|
676
712
|
observer = null;
|
|
713
|
+
libPromises = /* @__PURE__ */ new Map();
|
|
677
714
|
lucideAliases = {
|
|
678
715
|
close: LucideIcons2.X,
|
|
679
716
|
trash: LucideIcons2.Trash2,
|
|
@@ -16939,61 +16976,53 @@ var init_Breadcrumb = __esm({
|
|
|
16939
16976
|
function BuilderBoard({
|
|
16940
16977
|
entity,
|
|
16941
16978
|
completeEvent = "PUZZLE_COMPLETE",
|
|
16979
|
+
placeEvent,
|
|
16980
|
+
checkEvent,
|
|
16981
|
+
playAgainEvent,
|
|
16942
16982
|
className
|
|
16943
16983
|
}) {
|
|
16944
16984
|
const { emit } = useEventBus();
|
|
16945
16985
|
const { t } = useTranslate();
|
|
16946
16986
|
const resolved = boardEntity(entity);
|
|
16947
|
-
const [placements, setPlacements] = useState({});
|
|
16948
16987
|
const [headerError, setHeaderError] = useState(false);
|
|
16949
|
-
const [
|
|
16950
|
-
const [attempts, setAttempts] = useState(0);
|
|
16951
|
-
const [showHint, setShowHint] = useState(false);
|
|
16988
|
+
const [selectedComponent, setSelectedComponent] = useState(null);
|
|
16952
16989
|
const components = Array.isArray(resolved?.components) ? resolved.components : [];
|
|
16953
16990
|
const slots = Array.isArray(resolved?.slots) ? resolved.slots : [];
|
|
16991
|
+
const placements = {};
|
|
16992
|
+
for (const slot of slots) {
|
|
16993
|
+
if (slot.placedComponentId) placements[slot.id] = slot.placedComponentId;
|
|
16994
|
+
}
|
|
16995
|
+
const attempts = num(resolved?.attempts);
|
|
16996
|
+
const result = str(resolved?.result) || "none";
|
|
16997
|
+
const submitted = result === "win";
|
|
16954
16998
|
const usedComponentIds = new Set(Object.values(placements));
|
|
16955
16999
|
const availableComponents = components.filter((c) => !usedComponentIds.has(c.id));
|
|
16956
|
-
const
|
|
16957
|
-
const allPlaced = Object.keys(placements).length === slots.length;
|
|
17000
|
+
const allPlaced = slots.length > 0 && slots.every((s) => Boolean(placements[s.id]));
|
|
16958
17001
|
const results = submitted ? slots.map((slot) => ({
|
|
16959
17002
|
slot,
|
|
16960
17003
|
placed: placements[slot.id],
|
|
16961
|
-
correct: placements[slot.id] === slot.
|
|
17004
|
+
correct: placements[slot.id] === slot.requiredComponentId
|
|
16962
17005
|
})) : [];
|
|
16963
|
-
const
|
|
17006
|
+
const showHint = attempts >= 2 && Boolean(str(resolved?.hint));
|
|
16964
17007
|
const handlePlaceComponent = (slotId) => {
|
|
16965
17008
|
if (submitted || !selectedComponent) return;
|
|
16966
|
-
|
|
17009
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: selectedComponent });
|
|
16967
17010
|
setSelectedComponent(null);
|
|
16968
17011
|
};
|
|
16969
17012
|
const handleRemoveFromSlot = (slotId) => {
|
|
16970
17013
|
if (submitted) return;
|
|
16971
|
-
|
|
16972
|
-
const next = { ...prev };
|
|
16973
|
-
delete next[slotId];
|
|
16974
|
-
return next;
|
|
16975
|
-
});
|
|
17014
|
+
if (placeEvent) emit(`UI:${placeEvent}`, { slotId, componentId: "" });
|
|
16976
17015
|
};
|
|
16977
|
-
const handleSubmit =
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
if (correct) {
|
|
17016
|
+
const handleSubmit = () => {
|
|
17017
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
17018
|
+
const solved = slots.length > 0 && slots.every((s) => placements[s.id] === s.requiredComponentId);
|
|
17019
|
+
if (solved && completeEvent) {
|
|
16982
17020
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
16983
17021
|
}
|
|
16984
|
-
}, [slots, placements, attempts, completeEvent, emit]);
|
|
16985
|
-
const handleReset = () => {
|
|
16986
|
-
setSubmitted(false);
|
|
16987
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
16988
|
-
setShowHint(true);
|
|
16989
|
-
}
|
|
16990
17022
|
};
|
|
16991
|
-
const
|
|
16992
|
-
setPlacements({});
|
|
16993
|
-
setSubmitted(false);
|
|
17023
|
+
const handlePlayAgain = () => {
|
|
16994
17024
|
setSelectedComponent(null);
|
|
16995
|
-
|
|
16996
|
-
setShowHint(false);
|
|
17025
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
16997
17026
|
};
|
|
16998
17027
|
const getComponentById = (id) => components.find((c) => c.id === id);
|
|
16999
17028
|
if (!resolved) return null;
|
|
@@ -17043,13 +17072,13 @@ function BuilderBoard({
|
|
|
17043
17072
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("builder.blueprint") }),
|
|
17044
17073
|
/* @__PURE__ */ jsx(VStack, { gap: "sm", children: slots.map((slot) => {
|
|
17045
17074
|
const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
|
|
17046
|
-
const
|
|
17075
|
+
const result2 = results.find((r) => r.slot.id === slot.id);
|
|
17047
17076
|
return /* @__PURE__ */ jsxs(
|
|
17048
17077
|
HStack,
|
|
17049
17078
|
{
|
|
17050
17079
|
gap: "sm",
|
|
17051
17080
|
align: "center",
|
|
17052
|
-
className: `p-3 border-2 rounded ${
|
|
17081
|
+
className: `p-3 border-2 rounded ${result2 ? result2.correct ? "border-success" : "border-error" : selectedComponent ? "border-dashed border-foreground cursor-pointer" : "border-border"}`,
|
|
17053
17082
|
onClick: () => handlePlaceComponent(slot.id),
|
|
17054
17083
|
children: [
|
|
17055
17084
|
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
|
|
@@ -17064,7 +17093,7 @@ function BuilderBoard({
|
|
|
17064
17093
|
] }) : null,
|
|
17065
17094
|
placedComp.label
|
|
17066
17095
|
] }),
|
|
17067
|
-
|
|
17096
|
+
result2 && /* @__PURE__ */ jsx(Icon, { icon: result2.correct ? CheckCircle : XCircle, size: "sm", className: result2.correct ? "text-success" : "text-error" })
|
|
17068
17097
|
] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("builder.empty") })
|
|
17069
17098
|
]
|
|
17070
17099
|
},
|
|
@@ -17073,16 +17102,16 @@ function BuilderBoard({
|
|
|
17073
17102
|
}) })
|
|
17074
17103
|
] }) }),
|
|
17075
17104
|
submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
17076
|
-
/* @__PURE__ */ jsx(Icon, { icon:
|
|
17077
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children:
|
|
17105
|
+
/* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: "text-success" }),
|
|
17106
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: str(resolved.successMessage) || t("builder.success") })
|
|
17078
17107
|
] }) }),
|
|
17079
17108
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
17080
17109
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
17081
|
-
!submitted
|
|
17110
|
+
!submitted && /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
|
|
17082
17111
|
/* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
|
|
17083
17112
|
t("builder.build")
|
|
17084
|
-
] })
|
|
17085
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick:
|
|
17113
|
+
] }),
|
|
17114
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
17086
17115
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
17087
17116
|
t("builder.reset")
|
|
17088
17117
|
] })
|
|
@@ -20538,57 +20567,84 @@ var init_ChartLegend = __esm({
|
|
|
20538
20567
|
function ClassifierBoard({
|
|
20539
20568
|
entity,
|
|
20540
20569
|
completeEvent = "PUZZLE_COMPLETE",
|
|
20570
|
+
assignEvent,
|
|
20571
|
+
checkEvent,
|
|
20572
|
+
playAgainEvent,
|
|
20541
20573
|
className
|
|
20542
20574
|
}) {
|
|
20543
20575
|
const { emit } = useEventBus();
|
|
20544
20576
|
const { t } = useTranslate();
|
|
20545
20577
|
const resolved = boardEntity(entity);
|
|
20546
|
-
const [
|
|
20578
|
+
const [localAssignments, setLocalAssignments] = useState({});
|
|
20547
20579
|
const [headerError, setHeaderError] = useState(false);
|
|
20548
|
-
const [
|
|
20549
|
-
const [
|
|
20580
|
+
const [localSubmitted, setLocalSubmitted] = useState(false);
|
|
20581
|
+
const [localAttempts, setLocalAttempts] = useState(0);
|
|
20550
20582
|
const [showHint, setShowHint] = useState(false);
|
|
20551
20583
|
const items = Array.isArray(resolved?.items) ? resolved.items : [];
|
|
20552
20584
|
const categories = Array.isArray(resolved?.categories) ? resolved.categories : [];
|
|
20585
|
+
const entityResult = str(resolved?.result);
|
|
20586
|
+
const entityDrivesResult = entityResult.length > 0;
|
|
20587
|
+
const entityHasAssignments = items.some((item) => item.assignedCategory != null);
|
|
20588
|
+
const assignments = entityHasAssignments ? items.reduce((acc, item) => {
|
|
20589
|
+
if (item.assignedCategory != null) acc[item.id] = item.assignedCategory;
|
|
20590
|
+
return acc;
|
|
20591
|
+
}, {}) : localAssignments;
|
|
20592
|
+
const attempts = entityDrivesResult ? num(resolved?.attempts) : localAttempts;
|
|
20593
|
+
const submitted = entityDrivesResult || localSubmitted;
|
|
20553
20594
|
const unassignedItems = items.filter((item) => !assignments[item.id]);
|
|
20554
|
-
const allAssigned = Object.keys(assignments).length === items.length;
|
|
20595
|
+
const allAssigned = items.length > 0 && Object.keys(assignments).length === items.length;
|
|
20555
20596
|
const results = submitted ? items.map((item) => ({
|
|
20556
20597
|
item,
|
|
20557
20598
|
assigned: assignments[item.id],
|
|
20558
20599
|
correct: assignments[item.id] === item.correctCategory
|
|
20559
20600
|
})) : [];
|
|
20560
|
-
const allCorrect = results.length > 0 && results.every((r) => r.correct);
|
|
20601
|
+
const allCorrect = entityDrivesResult ? entityResult === "success" : results.length > 0 && results.every((r) => r.correct);
|
|
20561
20602
|
const correctCount = results.filter((r) => r.correct).length;
|
|
20562
20603
|
const handleAssign = (itemId, categoryId) => {
|
|
20563
20604
|
if (submitted) return;
|
|
20564
|
-
|
|
20605
|
+
if (assignEvent) {
|
|
20606
|
+
emit(`UI:${assignEvent}`, { itemId, categoryId });
|
|
20607
|
+
}
|
|
20608
|
+
if (!entityHasAssignments) {
|
|
20609
|
+
setLocalAssignments((prev) => ({ ...prev, [itemId]: categoryId }));
|
|
20610
|
+
}
|
|
20565
20611
|
};
|
|
20566
20612
|
const handleUnassign = (itemId) => {
|
|
20567
20613
|
if (submitted) return;
|
|
20568
|
-
|
|
20569
|
-
|
|
20570
|
-
|
|
20571
|
-
|
|
20572
|
-
|
|
20614
|
+
if (!entityHasAssignments) {
|
|
20615
|
+
setLocalAssignments((prev) => {
|
|
20616
|
+
const next = { ...prev };
|
|
20617
|
+
delete next[itemId];
|
|
20618
|
+
return next;
|
|
20619
|
+
});
|
|
20620
|
+
}
|
|
20573
20621
|
};
|
|
20574
20622
|
const handleSubmit = useCallback(() => {
|
|
20575
|
-
|
|
20576
|
-
|
|
20577
|
-
|
|
20578
|
-
if (
|
|
20579
|
-
|
|
20623
|
+
if (checkEvent) {
|
|
20624
|
+
emit(`UI:${checkEvent}`, {});
|
|
20625
|
+
}
|
|
20626
|
+
if (!entityDrivesResult) {
|
|
20627
|
+
setLocalSubmitted(true);
|
|
20628
|
+
setLocalAttempts((a) => a + 1);
|
|
20629
|
+
const correct = items.every((item) => assignments[item.id] === item.correctCategory);
|
|
20630
|
+
if (correct) {
|
|
20631
|
+
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
20632
|
+
}
|
|
20580
20633
|
}
|
|
20581
|
-
}, [items, assignments, attempts, completeEvent, emit]);
|
|
20634
|
+
}, [checkEvent, entityDrivesResult, items, assignments, attempts, completeEvent, emit]);
|
|
20582
20635
|
const handleReset = () => {
|
|
20583
|
-
|
|
20636
|
+
if (!entityDrivesResult) setLocalSubmitted(false);
|
|
20584
20637
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
20585
20638
|
setShowHint(true);
|
|
20586
20639
|
}
|
|
20587
20640
|
};
|
|
20588
20641
|
const handleFullReset = () => {
|
|
20589
|
-
|
|
20590
|
-
|
|
20591
|
-
|
|
20642
|
+
if (playAgainEvent) {
|
|
20643
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
20644
|
+
}
|
|
20645
|
+
setLocalAssignments({});
|
|
20646
|
+
setLocalSubmitted(false);
|
|
20647
|
+
setLocalAttempts(0);
|
|
20592
20648
|
setShowHint(false);
|
|
20593
20649
|
};
|
|
20594
20650
|
if (!resolved) return null;
|
|
@@ -28471,13 +28527,13 @@ var init_MapView = __esm({
|
|
|
28471
28527
|
shadowSize: [41, 41]
|
|
28472
28528
|
});
|
|
28473
28529
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
28474
|
-
const { useEffect:
|
|
28530
|
+
const { useEffect: useEffect74, useRef: useRef68, useCallback: useCallback111, useState: useState107 } = React82__default;
|
|
28475
28531
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
28476
28532
|
const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
28477
28533
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
28478
28534
|
const map = useMap();
|
|
28479
|
-
const prevRef =
|
|
28480
|
-
|
|
28535
|
+
const prevRef = useRef68({ centerLat, centerLng, zoom });
|
|
28536
|
+
useEffect74(() => {
|
|
28481
28537
|
const prev = prevRef.current;
|
|
28482
28538
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
28483
28539
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -28488,7 +28544,7 @@ var init_MapView = __esm({
|
|
|
28488
28544
|
}
|
|
28489
28545
|
function MapClickHandler({ onMapClick }) {
|
|
28490
28546
|
const map = useMap();
|
|
28491
|
-
|
|
28547
|
+
useEffect74(() => {
|
|
28492
28548
|
if (!onMapClick) return;
|
|
28493
28549
|
const handler = (e) => {
|
|
28494
28550
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -28517,7 +28573,7 @@ var init_MapView = __esm({
|
|
|
28517
28573
|
}) {
|
|
28518
28574
|
const eventBus = useEventBus3();
|
|
28519
28575
|
const [clickedPosition, setClickedPosition] = useState107(null);
|
|
28520
|
-
const handleMapClick =
|
|
28576
|
+
const handleMapClick = useCallback111((lat, lng) => {
|
|
28521
28577
|
if (showClickedPin) {
|
|
28522
28578
|
setClickedPosition({ lat, lng });
|
|
28523
28579
|
}
|
|
@@ -28526,7 +28582,7 @@ var init_MapView = __esm({
|
|
|
28526
28582
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
28527
28583
|
}
|
|
28528
28584
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
28529
|
-
const handleMarkerClick =
|
|
28585
|
+
const handleMarkerClick = useCallback111((marker) => {
|
|
28530
28586
|
onMarkerClick?.(marker);
|
|
28531
28587
|
if (markerClickEvent) {
|
|
28532
28588
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -37748,51 +37804,52 @@ var init_DataTable = __esm({
|
|
|
37748
37804
|
function DebuggerBoard({
|
|
37749
37805
|
entity,
|
|
37750
37806
|
completeEvent = "PUZZLE_COMPLETE",
|
|
37807
|
+
toggleFlagEvent,
|
|
37808
|
+
checkEvent,
|
|
37809
|
+
playAgainEvent,
|
|
37751
37810
|
className
|
|
37752
37811
|
}) {
|
|
37753
37812
|
const { emit } = useEventBus();
|
|
37754
37813
|
const { t } = useTranslate();
|
|
37755
37814
|
const resolved = boardEntity(entity);
|
|
37756
|
-
const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
|
|
37757
37815
|
const [headerError, setHeaderError] = useState(false);
|
|
37758
|
-
const [submitted, setSubmitted] = useState(false);
|
|
37759
|
-
const [attempts, setAttempts] = useState(0);
|
|
37760
37816
|
const [showHint, setShowHint] = useState(false);
|
|
37817
|
+
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37818
|
+
const result = resolved?.result ?? null;
|
|
37819
|
+
const attempts = num(resolved?.attempts);
|
|
37820
|
+
const submitted = result != null;
|
|
37821
|
+
const bugLines = lines.filter((l) => l.isBug);
|
|
37822
|
+
const flaggedLines = lines.filter((l) => l.isFlagged);
|
|
37823
|
+
const correctFlags = lines.filter((l) => l.isBug && l.isFlagged);
|
|
37824
|
+
const falseFlags = lines.filter((l) => !l.isBug && l.isFlagged);
|
|
37825
|
+
const allCorrect = result === "win";
|
|
37761
37826
|
const toggleLine = (lineId) => {
|
|
37762
37827
|
if (submitted) return;
|
|
37763
|
-
|
|
37764
|
-
|
|
37765
|
-
|
|
37766
|
-
next.delete(lineId);
|
|
37767
|
-
} else {
|
|
37768
|
-
next.add(lineId);
|
|
37769
|
-
}
|
|
37770
|
-
return next;
|
|
37771
|
-
});
|
|
37828
|
+
if (toggleFlagEvent) {
|
|
37829
|
+
emit(`UI:${toggleFlagEvent}`, { lineId });
|
|
37830
|
+
}
|
|
37772
37831
|
};
|
|
37773
|
-
const lines = Array.isArray(resolved?.lines) ? resolved.lines : [];
|
|
37774
|
-
const bugLines = lines.filter((l) => l.isBug);
|
|
37775
|
-
const correctFlags = lines.filter((l) => l.isBug && flaggedLines.has(l.id));
|
|
37776
|
-
const falseFlags = lines.filter((l) => !l.isBug && flaggedLines.has(l.id));
|
|
37777
|
-
const allCorrect = submitted && correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
37778
37832
|
const handleSubmit = useCallback(() => {
|
|
37779
|
-
|
|
37780
|
-
|
|
37833
|
+
if (checkEvent) {
|
|
37834
|
+
emit(`UI:${checkEvent}`, {});
|
|
37835
|
+
}
|
|
37781
37836
|
const correct = correctFlags.length === bugLines.length && falseFlags.length === 0;
|
|
37782
37837
|
if (correct) {
|
|
37783
37838
|
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
37784
37839
|
}
|
|
37785
|
-
}, [correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37840
|
+
}, [checkEvent, correctFlags.length, bugLines.length, falseFlags.length, attempts, completeEvent, emit]);
|
|
37786
37841
|
const handleReset = () => {
|
|
37787
|
-
|
|
37842
|
+
if (playAgainEvent) {
|
|
37843
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
37844
|
+
}
|
|
37788
37845
|
if (attempts >= 2 && str(resolved?.hint)) {
|
|
37789
37846
|
setShowHint(true);
|
|
37790
37847
|
}
|
|
37791
37848
|
};
|
|
37792
37849
|
const handleFullReset = () => {
|
|
37793
|
-
|
|
37794
|
-
|
|
37795
|
-
|
|
37850
|
+
if (playAgainEvent) {
|
|
37851
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
37852
|
+
}
|
|
37796
37853
|
setShowHint(false);
|
|
37797
37854
|
};
|
|
37798
37855
|
if (!resolved) return null;
|
|
@@ -37820,7 +37877,7 @@ function DebuggerBoard({
|
|
|
37820
37877
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: t("debugger.findBugs", { count: String(num(resolved.bugCount)) }) })
|
|
37821
37878
|
] }) }),
|
|
37822
37879
|
/* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: lines.map((line, i) => {
|
|
37823
|
-
const isFlagged =
|
|
37880
|
+
const isFlagged = !!line.isFlagged;
|
|
37824
37881
|
let lineStyle = "";
|
|
37825
37882
|
if (submitted) {
|
|
37826
37883
|
if (line.isBug && isFlagged) lineStyle = "bg-success/10";
|
|
@@ -37854,9 +37911,9 @@ function DebuggerBoard({
|
|
|
37854
37911
|
/* @__PURE__ */ jsx(
|
|
37855
37912
|
Icon,
|
|
37856
37913
|
{
|
|
37857
|
-
icon:
|
|
37914
|
+
icon: line.isFlagged ? CheckCircle : XCircle,
|
|
37858
37915
|
size: "xs",
|
|
37859
|
-
className:
|
|
37916
|
+
className: line.isFlagged ? "text-success mt-0.5" : "text-warning mt-0.5"
|
|
37860
37917
|
}
|
|
37861
37918
|
),
|
|
37862
37919
|
/* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
|
|
@@ -37867,7 +37924,7 @@ function DebuggerBoard({
|
|
|
37867
37924
|
] }) }),
|
|
37868
37925
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
37869
37926
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
37870
|
-
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.
|
|
37927
|
+
!submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.length === 0, children: [
|
|
37871
37928
|
/* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
|
|
37872
37929
|
t("debugger.submit")
|
|
37873
37930
|
] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
|
|
@@ -41631,6 +41688,9 @@ function getOpponentAction(strategy, actions, history) {
|
|
|
41631
41688
|
function NegotiatorBoard({
|
|
41632
41689
|
entity,
|
|
41633
41690
|
completeEvent = "PUZZLE_COMPLETE",
|
|
41691
|
+
playRoundEvent,
|
|
41692
|
+
finishEvent,
|
|
41693
|
+
playAgainEvent,
|
|
41634
41694
|
className
|
|
41635
41695
|
}) {
|
|
41636
41696
|
const { emit } = useEventBus();
|
|
@@ -41639,13 +41699,14 @@ function NegotiatorBoard({
|
|
|
41639
41699
|
const [history, setHistory] = useState([]);
|
|
41640
41700
|
const [headerError, setHeaderError] = useState(false);
|
|
41641
41701
|
const [showHint, setShowHint] = useState(false);
|
|
41642
|
-
const totalRounds = num(resolved?.
|
|
41702
|
+
const totalRounds = num(resolved?.maxRounds);
|
|
41643
41703
|
const targetScore = num(resolved?.targetScore);
|
|
41644
|
-
const currentRound =
|
|
41645
|
-
const
|
|
41646
|
-
const playerTotal =
|
|
41704
|
+
const currentRound = num(resolved?.round);
|
|
41705
|
+
const result = str(resolved?.result) || "none";
|
|
41706
|
+
const playerTotal = num(resolved?.score);
|
|
41707
|
+
const isComplete = result !== "none" || totalRounds > 0 && currentRound >= totalRounds;
|
|
41708
|
+
const won = result === "win";
|
|
41647
41709
|
const opponentTotal = history.reduce((s, r) => s + r.opponentPayoff, 0);
|
|
41648
|
-
const won = isComplete && playerTotal >= targetScore;
|
|
41649
41710
|
const actions = Array.isArray(resolved?.actions) ? resolved.actions : [];
|
|
41650
41711
|
const payoffMatrix = Array.isArray(resolved?.payoffMatrix) ? resolved.payoffMatrix : [];
|
|
41651
41712
|
const handleAction = useCallback((actionId) => {
|
|
@@ -41654,29 +41715,45 @@ function NegotiatorBoard({
|
|
|
41654
41715
|
const payoff = payoffMatrix.find(
|
|
41655
41716
|
(p2) => p2.playerAction === actionId && p2.opponentAction === opponentAction
|
|
41656
41717
|
);
|
|
41657
|
-
const
|
|
41658
|
-
|
|
41659
|
-
|
|
41660
|
-
|
|
41661
|
-
|
|
41662
|
-
|
|
41663
|
-
|
|
41664
|
-
|
|
41665
|
-
|
|
41666
|
-
|
|
41667
|
-
|
|
41668
|
-
|
|
41669
|
-
|
|
41670
|
-
|
|
41671
|
-
|
|
41718
|
+
const playerPayoff = payoff?.playerPayoff ?? 0;
|
|
41719
|
+
setHistory((prev) => [
|
|
41720
|
+
...prev,
|
|
41721
|
+
{
|
|
41722
|
+
round: prev.length + 1,
|
|
41723
|
+
playerAction: actionId,
|
|
41724
|
+
opponentAction,
|
|
41725
|
+
playerPayoff,
|
|
41726
|
+
opponentPayoff: payoff?.opponentPayoff ?? 0
|
|
41727
|
+
}
|
|
41728
|
+
]);
|
|
41729
|
+
if (playRoundEvent) {
|
|
41730
|
+
emit(`UI:${playRoundEvent}`, { playerAction: actionId, payoff: playerPayoff });
|
|
41731
|
+
}
|
|
41732
|
+
if (totalRounds > 0 && currentRound + 1 >= totalRounds) {
|
|
41733
|
+
if (finishEvent) {
|
|
41734
|
+
emit(`UI:${finishEvent}`, {});
|
|
41735
|
+
}
|
|
41736
|
+
if (str(resolved?.hint)) {
|
|
41672
41737
|
setShowHint(true);
|
|
41673
41738
|
}
|
|
41674
41739
|
}
|
|
41675
|
-
}, [isComplete, resolved, totalRounds,
|
|
41676
|
-
const handleReset = () => {
|
|
41740
|
+
}, [isComplete, resolved, totalRounds, currentRound, actions, payoffMatrix, history, playRoundEvent, finishEvent, emit]);
|
|
41741
|
+
const handleReset = useCallback(() => {
|
|
41677
41742
|
setHistory([]);
|
|
41678
41743
|
setShowHint(false);
|
|
41679
|
-
|
|
41744
|
+
if (playAgainEvent) {
|
|
41745
|
+
emit(`UI:${playAgainEvent}`, {});
|
|
41746
|
+
}
|
|
41747
|
+
}, [playAgainEvent, emit]);
|
|
41748
|
+
const completedRef = useRef(false);
|
|
41749
|
+
useEffect(() => {
|
|
41750
|
+
if (result === "win" && !completedRef.current) {
|
|
41751
|
+
completedRef.current = true;
|
|
41752
|
+
emit(`UI:${completeEvent}`, { success: true, score: playerTotal });
|
|
41753
|
+
} else if (result === "none") {
|
|
41754
|
+
completedRef.current = false;
|
|
41755
|
+
}
|
|
41756
|
+
}, [result, playerTotal, completeEvent, emit]);
|
|
41680
41757
|
const getActionLabel = (id) => actions.find((a) => a.id === id)?.label ?? id;
|
|
41681
41758
|
if (!resolved) return null;
|
|
41682
41759
|
const theme = resolved.theme ?? void 0;
|
|
@@ -44642,67 +44719,47 @@ var init_SimulationGraph = __esm({
|
|
|
44642
44719
|
function SimulatorBoard({
|
|
44643
44720
|
entity,
|
|
44644
44721
|
completeEvent = "PUZZLE_COMPLETE",
|
|
44722
|
+
setAEvent,
|
|
44723
|
+
setBEvent,
|
|
44724
|
+
checkEvent,
|
|
44725
|
+
playAgainEvent,
|
|
44645
44726
|
className
|
|
44646
44727
|
}) {
|
|
44647
44728
|
const { emit } = useEventBus();
|
|
44648
44729
|
const { t } = useTranslate();
|
|
44649
44730
|
const resolved = boardEntity(entity);
|
|
44650
44731
|
const parameters = Array.isArray(resolved?.parameters) ? resolved.parameters : [];
|
|
44651
|
-
const [values, setValues] = useState(() => {
|
|
44652
|
-
const init = {};
|
|
44653
|
-
for (const p2 of parameters) {
|
|
44654
|
-
init[p2.id] = p2.initial;
|
|
44655
|
-
}
|
|
44656
|
-
return init;
|
|
44657
|
-
});
|
|
44658
44732
|
const [headerError, setHeaderError] = useState(false);
|
|
44659
|
-
|
|
44660
|
-
const
|
|
44661
|
-
const
|
|
44662
|
-
const
|
|
44663
|
-
|
|
44664
|
-
|
|
44665
|
-
|
|
44666
|
-
|
|
44667
|
-
|
|
44668
|
-
|
|
44669
|
-
|
|
44670
|
-
const
|
|
44671
|
-
const
|
|
44672
|
-
const
|
|
44673
|
-
const
|
|
44674
|
-
|
|
44675
|
-
|
|
44676
|
-
|
|
44677
|
-
};
|
|
44678
|
-
const handleSubmit = () => {
|
|
44679
|
-
setSubmitted(true);
|
|
44680
|
-
setAttempts((a) => a + 1);
|
|
44681
|
-
if (isCorrect) {
|
|
44682
|
-
emit(`UI:${completeEvent}`, { success: true, attempts: attempts + 1 });
|
|
44683
|
-
}
|
|
44733
|
+
if (!resolved) return null;
|
|
44734
|
+
const paramA = num(resolved.paramA);
|
|
44735
|
+
const paramB = num(resolved.paramB);
|
|
44736
|
+
const output = num(resolved.output);
|
|
44737
|
+
const targetValue = num(resolved.target);
|
|
44738
|
+
const targetTolerance = num(resolved.tolerance);
|
|
44739
|
+
const attempts = num(resolved.attempts);
|
|
44740
|
+
const result = str(resolved.result);
|
|
44741
|
+
const isWin = result === "win";
|
|
44742
|
+
const isComplete = result !== "none" && result !== "";
|
|
44743
|
+
const paramAValue = parameters[0];
|
|
44744
|
+
const paramBValue = parameters[1];
|
|
44745
|
+
const sliderValues = [paramA, paramB];
|
|
44746
|
+
const sliderEvents = [setAEvent, setBEvent];
|
|
44747
|
+
const handleParameterChange = (index, value) => {
|
|
44748
|
+
if (isComplete) return;
|
|
44749
|
+
const ev = sliderEvents[index];
|
|
44750
|
+
if (ev) emit(`UI:${ev}`, { value });
|
|
44684
44751
|
};
|
|
44685
|
-
const
|
|
44686
|
-
|
|
44687
|
-
if (attempts >= 2 && str(resolved?.hint)) {
|
|
44688
|
-
setShowHint(true);
|
|
44689
|
-
}
|
|
44752
|
+
const handleCheck = () => {
|
|
44753
|
+
if (checkEvent) emit(`UI:${checkEvent}`, {});
|
|
44690
44754
|
};
|
|
44691
|
-
const
|
|
44692
|
-
|
|
44693
|
-
for (const p2 of parameters) {
|
|
44694
|
-
init[p2.id] = p2.initial;
|
|
44695
|
-
}
|
|
44696
|
-
setValues(init);
|
|
44697
|
-
setSubmitted(false);
|
|
44698
|
-
setAttempts(0);
|
|
44699
|
-
setShowHint(false);
|
|
44755
|
+
const handlePlayAgain = () => {
|
|
44756
|
+
if (playAgainEvent) emit(`UI:${playAgainEvent}`, {});
|
|
44700
44757
|
};
|
|
44701
|
-
if (!resolved) return null;
|
|
44702
44758
|
const theme = resolved.theme ?? void 0;
|
|
44703
44759
|
const themeBackground = theme?.background;
|
|
44704
44760
|
const headerImage = str(resolved.headerImage);
|
|
44705
44761
|
const hint = str(resolved.hint);
|
|
44762
|
+
const showHint = isComplete && !isWin && attempts >= 2 && Boolean(hint);
|
|
44706
44763
|
const outputLabel = str(resolved.outputLabel);
|
|
44707
44764
|
const outputUnit = str(resolved.outputUnit);
|
|
44708
44765
|
return /* @__PURE__ */ jsx(
|
|
@@ -44722,41 +44779,43 @@ function SimulatorBoard({
|
|
|
44722
44779
|
] }) }),
|
|
44723
44780
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
|
|
44724
44781
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: t("simulator.parameters") }),
|
|
44725
|
-
|
|
44726
|
-
/* @__PURE__ */ jsxs(
|
|
44727
|
-
/* @__PURE__ */
|
|
44728
|
-
|
|
44729
|
-
|
|
44730
|
-
|
|
44731
|
-
|
|
44732
|
-
|
|
44733
|
-
|
|
44734
|
-
/* @__PURE__ */ jsx(
|
|
44735
|
-
"input",
|
|
44736
|
-
{
|
|
44737
|
-
type: "range",
|
|
44738
|
-
min: param.min,
|
|
44739
|
-
max: param.max,
|
|
44740
|
-
step: param.step,
|
|
44741
|
-
value: values[param.id],
|
|
44742
|
-
onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
|
|
44743
|
-
disabled: submitted,
|
|
44744
|
-
className: "w-full accent-foreground"
|
|
44745
|
-
}
|
|
44746
|
-
),
|
|
44747
|
-
/* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
|
|
44748
|
-
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44749
|
-
param.min,
|
|
44750
|
-
" ",
|
|
44751
|
-
param.unit
|
|
44782
|
+
[paramAValue, paramBValue].map(
|
|
44783
|
+
(param, index) => param ? /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
44784
|
+
/* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
|
|
44785
|
+
/* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
|
|
44786
|
+
/* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
|
|
44787
|
+
sliderValues[index],
|
|
44788
|
+
" ",
|
|
44789
|
+
param.unit
|
|
44790
|
+
] })
|
|
44752
44791
|
] }),
|
|
44753
|
-
/* @__PURE__ */
|
|
44754
|
-
|
|
44755
|
-
|
|
44756
|
-
|
|
44792
|
+
/* @__PURE__ */ jsx(
|
|
44793
|
+
"input",
|
|
44794
|
+
{
|
|
44795
|
+
type: "range",
|
|
44796
|
+
min: param.min,
|
|
44797
|
+
max: param.max,
|
|
44798
|
+
step: param.step,
|
|
44799
|
+
value: sliderValues[index],
|
|
44800
|
+
onChange: (e) => handleParameterChange(index, Number(e.target.value)),
|
|
44801
|
+
disabled: isComplete,
|
|
44802
|
+
className: "w-full accent-foreground"
|
|
44803
|
+
}
|
|
44804
|
+
),
|
|
44805
|
+
/* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
|
|
44806
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44807
|
+
param.min,
|
|
44808
|
+
" ",
|
|
44809
|
+
param.unit
|
|
44810
|
+
] }),
|
|
44811
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44812
|
+
param.max,
|
|
44813
|
+
" ",
|
|
44814
|
+
param.unit
|
|
44815
|
+
] })
|
|
44757
44816
|
] })
|
|
44758
|
-
] })
|
|
44759
|
-
|
|
44817
|
+
] }, param.id ?? index) : null
|
|
44818
|
+
)
|
|
44760
44819
|
] }) }),
|
|
44761
44820
|
/* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
|
|
44762
44821
|
/* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-muted-foreground", children: outputLabel }),
|
|
@@ -44765,9 +44824,9 @@ function SimulatorBoard({
|
|
|
44765
44824
|
" ",
|
|
44766
44825
|
outputUnit
|
|
44767
44826
|
] }),
|
|
44768
|
-
|
|
44769
|
-
/* @__PURE__ */ jsx(Icon, { icon:
|
|
44770
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body", className:
|
|
44827
|
+
isComplete && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
44828
|
+
/* @__PURE__ */ jsx(Icon, { icon: isWin ? CheckCircle : XCircle, size: "sm", className: isWin ? "text-success" : "text-error" }),
|
|
44829
|
+
/* @__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") })
|
|
44771
44830
|
] }),
|
|
44772
44831
|
/* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
|
|
44773
44832
|
t("simulator.target"),
|
|
@@ -44782,11 +44841,11 @@ function SimulatorBoard({
|
|
|
44782
44841
|
] }) }),
|
|
44783
44842
|
showHint && hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-warning", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: hint }) }),
|
|
44784
44843
|
/* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
|
|
44785
|
-
!
|
|
44844
|
+
!isComplete ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleCheck, children: [
|
|
44786
44845
|
/* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
|
|
44787
44846
|
t("simulator.simulate")
|
|
44788
|
-
] }) :
|
|
44789
|
-
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick:
|
|
44847
|
+
] }) : null,
|
|
44848
|
+
/* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handlePlayAgain, children: [
|
|
44790
44849
|
/* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
|
|
44791
44850
|
t("simulator.reset")
|
|
44792
44851
|
] })
|