@almadar/ui 2.1.2 → 2.1.4

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.
@@ -1,21 +1,21 @@
1
- import { useAuthContext } from '../chunk-BKC4XU44.js';
2
- export { ENTITY_EVENTS, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useEntities, useEntitiesByType, useEntity as useEntityById, useEntityMutations, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInput, useOrbitalHistory, useOrbitalMutations, usePhysics, usePlayer, usePreview, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useUIEvents, useUpdateEntity, useValidation } from '../chunk-BKC4XU44.js';
3
1
  import { DEFAULT_CONFIG, renderStateMachineToDomData, parseContentSegments } from '../chunk-N6DJVKZ6.js';
2
+ import { useAuthContext } from '../chunk-E3EXHX2Z.js';
3
+ export { ENTITY_EVENTS, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useEntities, useEntitiesByType, useEntity as useEntityById, useEntityMutations, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInput, useOrbitalHistory, useOrbitalMutations, usePhysics, usePlayer, usePreview, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useUIEvents, useUpdateEntity, useValidation } from '../chunk-E3EXHX2Z.js';
4
4
  import '../chunk-XSEDIUM6.js';
5
- import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, HealthBar, ScoreDisplay, StateIndicator, Container, EntityDisplayEvents } from '../chunk-LB3HXNAR.js';
6
- export { Accordion, Card2 as ActionCard, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, DataTable, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FloatingActionButton, Form, FormField, FormSectionHeader, Grid, HStack, Heading, HealthBar, Icon, Input, InputGroup, Label, LawReferenceTooltip, LoadingState, MarkdownContent, MasterDetail, Menu, Modal, Overlay, PageHeader, Pagination, Popover, ProgressBar, QuizBlock, Radio, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, Spacer, Spinner, Sprite, Stack, StatCard, StateIndicator, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite } from '../chunk-LB3HXNAR.js';
5
+ import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, HealthBar, ScoreDisplay, StateIndicator, Container, EntityDisplayEvents } from '../chunk-Y7AFNUT2.js';
6
+ export { Accordion, Card2 as ActionCard, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, DataTable, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FloatingActionButton, Form, FormField, FormSectionHeader, Grid, HStack, Heading, HealthBar, Icon, Input, InputGroup, Label, LawReferenceTooltip, LoadingState, MarkdownContent, MasterDetail, Menu, Modal, Overlay, PageHeader, Pagination, Popover, ProgressBar, QuizBlock, Radio, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, Spacer, Spinner, Sprite, Stack, StatCard, StateIndicator, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite } from '../chunk-Y7AFNUT2.js';
7
7
  import '../chunk-BTXQJGFB.js';
8
- import { useTranslate } from '../chunk-PE2H3NAW.js';
9
- export { EntityDataProvider, I18nProvider, createTranslate, entityDataKeys, parseQueryBinding, useEntity, useEntityDataAdapter, useEntityDetail, useEntityList, useEntityListSuspense, useEntitySuspense, useQuerySingleton, useTranslate } from '../chunk-PE2H3NAW.js';
8
+ import { cn, getNestedValue } from '../chunk-KKCVDUK7.js';
9
+ export { cn } from '../chunk-KKCVDUK7.js';
10
+ import { useTranslate } from '../chunk-JLEMVREZ.js';
11
+ export { EntityDataProvider, I18nProvider, createTranslate, entityDataKeys, parseQueryBinding, useEntity, useEntityDataAdapter, useEntityDetail, useEntityList, useEntityListSuspense, useEntitySuspense, useQuerySingleton, useTranslate } from '../chunk-JLEMVREZ.js';
10
12
  import { useEventBus, useEventListener } from '../chunk-YXZM3WCF.js';
11
13
  export { useEmitEvent, useEventBus, useEventListener } from '../chunk-YXZM3WCF.js';
12
14
  export { DEFAULT_SLOTS, useUISlotManager } from '../chunk-7NEWMNNU.js';
13
- import { cn, getNestedValue } from '../chunk-KKCVDUK7.js';
14
- export { cn } from '../chunk-KKCVDUK7.js';
15
15
  export { clearEntities, getAllEntities, getByType, getEntity, getSingleton, removeEntity, spawnEntity, updateEntity, updateSingleton } from '../chunk-N7MVUW4R.js';
16
16
  import { __publicField } from '../chunk-PKBMQBKP.js';
17
17
  import * as React42 from 'react';
18
- import React42__default, { createContext, useState, useMemo, useCallback, useEffect, useRef, useContext } from 'react';
18
+ import React42__default, { createContext, useState, useCallback, useMemo, useEffect, useRef, useContext } from 'react';
19
19
  import { ChevronDown, X, Menu, ChevronRight, ChevronLeft, ArrowUp, ArrowDown, MoreVertical, Package, Check, AlertTriangle, Trash2, List as List$1, Printer, CheckCircle, XCircle, Play, RotateCcw, Send, Wrench, Bug, ArrowRight, Pause, SkipForward, Zap, Sword, Move, Heart, Shield, AlertCircle, Circle, Clock, CheckCircle2, Image as Image$1, Upload, ZoomIn, Eraser, FileText, ZoomOut, Download, Code, WrapText, Copy, Settings, Search, Bell, LogOut, Calendar, Pencil, Eye, MoreHorizontal, Minus, Plus } from 'lucide-react';
20
20
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
21
21
  import { createPortal } from 'react-dom';
@@ -417,13 +417,13 @@ var SidebarNavItem = ({ item, collapsed }) => {
417
417
  "w-full flex items-center gap-3 px-3 py-2.5 transition-all duration-[var(--transition-fast)] group relative",
418
418
  "rounded-[var(--radius-sm)] border-[length:var(--border-width-thin)] border-transparent",
419
419
  isActive ? [
420
- "bg-[var(--color-foreground)] text-[var(--color-background)]",
420
+ "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
421
421
  "font-medium shadow-[var(--shadow-sm)]",
422
- "border-[var(--color-border)] translate-x-1 -translate-y-0.5"
422
+ "border-[var(--color-primary)] translate-x-1 -translate-y-0.5"
423
423
  ].join(" ") : [
424
424
  "text-[var(--color-foreground)]",
425
425
  "hover:bg-[var(--color-muted)] hover:border-[var(--color-border)]",
426
- "active:bg-[var(--color-foreground)] active:text-[var(--color-background)]"
426
+ "active:bg-[var(--color-primary)] active:text-[var(--color-primary-foreground)]"
427
427
  ].join(" ")
428
428
  ),
429
429
  title: collapsed ? item.label : void 0,
@@ -434,7 +434,7 @@ var SidebarNavItem = ({ item, collapsed }) => {
434
434
  size: 20,
435
435
  className: cn(
436
436
  "min-w-[20px] flex-shrink-0",
437
- isActive && "text-[var(--color-background)]"
437
+ isActive && "text-[var(--color-primary-foreground)]"
438
438
  )
439
439
  }
440
440
  ),
@@ -460,22 +460,36 @@ var Sidebar = ({
460
460
  footerContent,
461
461
  collapsed: controlledCollapsed,
462
462
  defaultCollapsed = false,
463
- onCollapseChange,
463
+ collapseChangeEvent,
464
464
  hideCollapseButton = false,
465
465
  showCloseButton = false,
466
- onClose,
467
- onLogoClick,
466
+ closeEvent,
467
+ logoClickEvent,
468
468
  className
469
469
  }) => {
470
+ const { emit } = useEventBus();
471
+ const { t } = useTranslate();
470
472
  const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed);
471
473
  const collapsed = controlledCollapsed !== void 0 ? controlledCollapsed : internalCollapsed;
472
- const handleToggle = () => {
474
+ const handleToggle = useCallback(() => {
473
475
  const newCollapsed = !collapsed;
474
476
  if (controlledCollapsed === void 0) {
475
477
  setInternalCollapsed(newCollapsed);
476
478
  }
477
- onCollapseChange?.(newCollapsed);
478
- };
479
+ if (collapseChangeEvent) {
480
+ emit(collapseChangeEvent, { collapsed: newCollapsed });
481
+ }
482
+ }, [collapsed, controlledCollapsed, collapseChangeEvent, emit]);
483
+ const handleClose = useCallback(() => {
484
+ if (closeEvent) {
485
+ emit(closeEvent, {});
486
+ }
487
+ }, [closeEvent, emit]);
488
+ const handleLogoClick = useCallback(() => {
489
+ if (logoClickEvent) {
490
+ emit(logoClickEvent, {});
491
+ }
492
+ }, [logoClickEvent, emit]);
479
493
  return /* @__PURE__ */ jsxs(
480
494
  Box,
481
495
  {
@@ -496,7 +510,7 @@ var Sidebar = ({
496
510
  "flex items-center gap-3 cursor-pointer",
497
511
  collapsed && "justify-center w-full"
498
512
  ),
499
- onClick: onLogoClick,
513
+ onClick: handleLogoClick,
500
514
  children: [
501
515
  logo ? typeof logo === "string" ? (
502
516
  // eslint-disable-next-line almadar/no-raw-dom-elements -- semantic img with src/alt
@@ -519,7 +533,7 @@ var Sidebar = ({
519
533
  "rounded-[var(--radius-sm)]",
520
534
  collapsed && "mx-auto"
521
535
  ),
522
- title: collapsed ? "Expand Sidebar" : "Collapse Sidebar",
536
+ title: collapsed ? t("sidebar.expand") : t("sidebar.collapse"),
523
537
  children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, { size: 18 }) : /* @__PURE__ */ jsx(ChevronLeft, { size: 18 })
524
538
  }
525
539
  ),
@@ -527,9 +541,9 @@ var Sidebar = ({
527
541
  Button,
528
542
  {
529
543
  variant: "ghost",
530
- onClick: onClose,
544
+ onClick: handleClose,
531
545
  className: "p-1.5 hover:bg-[var(--color-muted)] text-[var(--color-foreground)] lg:hidden rounded-[var(--radius-sm)]",
532
- "aria-label": "Close sidebar",
546
+ "aria-label": t("sidebar.close"),
533
547
  children: /* @__PURE__ */ jsx(X, { size: 18 })
534
548
  }
535
549
  )
@@ -635,7 +649,6 @@ var Table = ({
635
649
  columns,
636
650
  // EntityDisplayProps
637
651
  entity,
638
- data,
639
652
  className,
640
653
  isLoading,
641
654
  error,
@@ -664,7 +677,7 @@ var Table = ({
664
677
  const eventBus = useEventBus();
665
678
  const resolvedEmptyMessage = emptyMessage ?? t("empty.noData");
666
679
  const resolvedSearchPlaceholder = searchPlaceholder ?? t("common.search");
667
- const resolvedData = Array.isArray(data) ? data : Array.isArray(entity) ? entity : [];
680
+ const resolvedData = Array.isArray(entity) ? entity : [];
668
681
  const resolvedSortColumn = sortColumnProp ?? sortBy;
669
682
  const resolvedSortDirection = sortDirectionProp ?? entitySortDirection ?? void 0;
670
683
  const resolvedCurrentPage = currentPageProp ?? page ?? 1;
@@ -994,7 +1007,6 @@ var ProgressIndicator = ({ value }) => {
994
1007
  };
995
1008
  var List = ({
996
1009
  entity,
997
- data,
998
1010
  isLoading = false,
999
1011
  error,
1000
1012
  selectable = false,
@@ -1010,14 +1022,12 @@ var List = ({
1010
1022
  const eventBus = useEventBus();
1011
1023
  const { t } = useTranslate();
1012
1024
  const resolvedEmptyMessage = emptyMessage ?? t("empty.noData");
1013
- const entityName = typeof entity === "string" ? entity : void 0;
1014
1025
  const effectiveFieldNames = normalizeFields(fields).length > 0 ? normalizeFields(fields) : fieldNames;
1015
1026
  const rawItems = useMemo(() => {
1016
- const d = data ?? [];
1017
- if (Array.isArray(d)) return d;
1018
- if (d && typeof d === "object" && "id" in d) return [d];
1027
+ if (Array.isArray(entity)) return entity;
1028
+ if (entity && typeof entity === "object" && "id" in entity) return [entity];
1019
1029
  return [];
1020
- }, [data]);
1030
+ }, [entity]);
1021
1031
  const getItemActions = React42__default.useCallback(
1022
1032
  (item) => {
1023
1033
  if (!itemActions) return [];
@@ -1033,26 +1043,25 @@ var List = ({
1033
1043
  /\{\{(\w+)\}\}/g,
1034
1044
  (_, key) => String(item[key] || item.id || "")
1035
1045
  );
1036
- eventBus.emit("UI:NAVIGATE", { url, row: item, entity: entityName });
1046
+ eventBus.emit("UI:NAVIGATE", { url, row: item });
1037
1047
  return;
1038
1048
  }
1039
1049
  if (action.event) {
1040
1050
  eventBus.emit(`UI:${action.event}`, {
1041
- row: item,
1042
- entity: entityName
1051
+ row: item
1043
1052
  });
1044
1053
  }
1045
1054
  }
1046
1055
  }));
1047
1056
  },
1048
- [itemActions, eventBus, entityName]
1057
+ [itemActions, eventBus]
1049
1058
  );
1050
1059
  const normalizedItemActions = itemActions ? getItemActions : void 0;
1051
1060
  if (isLoading) {
1052
1061
  return /* @__PURE__ */ jsx(
1053
1062
  LoadingState,
1054
1063
  {
1055
- message: `Loading ${entityType || "items"}...`,
1064
+ message: "Loading items...",
1056
1065
  className
1057
1066
  }
1058
1067
  );
@@ -1062,7 +1071,7 @@ var List = ({
1062
1071
  EmptyState,
1063
1072
  {
1064
1073
  icon: Package,
1065
- title: `Error loading ${entityType || "items"}`,
1074
+ title: "Error loading items",
1066
1075
  description: error.message,
1067
1076
  className
1068
1077
  }
@@ -1109,7 +1118,7 @@ var List = ({
1109
1118
  }
1110
1119
  };
1111
1120
  const handleRowClick = (item) => {
1112
- eventBus.emit("UI:VIEW", { row: item, entity: entityName });
1121
+ eventBus.emit("UI:VIEW", { row: item });
1113
1122
  };
1114
1123
  const defaultRenderItem = (item, index, isLast) => {
1115
1124
  const isSelected = selectedIds.map(String).includes(item.id);
@@ -1325,7 +1334,7 @@ var List = ({
1325
1334
  EmptyState,
1326
1335
  {
1327
1336
  icon: Package,
1328
- title: `No ${entityType || "items"} found`,
1337
+ title: "No items found",
1329
1338
  description: resolvedEmptyMessage,
1330
1339
  className
1331
1340
  }
@@ -3376,7 +3385,7 @@ var PRINT_STYLES = `
3376
3385
  }
3377
3386
  `;
3378
3387
  var BookViewer = ({
3379
- data,
3388
+ entity,
3380
3389
  initialPage = 0,
3381
3390
  fieldMap,
3382
3391
  className
@@ -3386,10 +3395,11 @@ var BookViewer = ({
3386
3395
  const [currentPage, setCurrentPage] = useState(initialPage);
3387
3396
  const resolvedFieldMap = useMemo(() => resolveFieldMap(fieldMap), [fieldMap]);
3388
3397
  const book = useMemo(() => {
3389
- const raw = data?.[0];
3398
+ const entityArray = Array.isArray(entity) ? entity : entity ? [entity] : [];
3399
+ const raw = entityArray[0];
3390
3400
  if (!raw) return null;
3391
3401
  return mapBookData(raw, resolvedFieldMap);
3392
- }, [data, resolvedFieldMap]);
3402
+ }, [entity, resolvedFieldMap]);
3393
3403
  const direction = book?.direction ?? "ltr";
3394
3404
  const chapters = useMemo(() => book ? flattenChapters(book) : [], [book]);
3395
3405
  const totalPages = 2 + chapters.length;
@@ -7333,6 +7343,7 @@ function BattleBoard({
7333
7343
  const currentTurn = entity.turn;
7334
7344
  const gameResult = entity.gameResult;
7335
7345
  const eventBus = useEventBus();
7346
+ const { t } = useTranslate();
7336
7347
  const [hoveredTile, setHoveredTile] = useState(null);
7337
7348
  const [isShaking, setIsShaking] = useState(false);
7338
7349
  const selectedUnit = useMemo(
@@ -7386,11 +7397,11 @@ function BattleBoard({
7386
7397
  const anim2 = movementAnimRef.current;
7387
7398
  if (!anim2) return;
7388
7399
  anim2.elapsed += 16;
7389
- const t = Math.min(anim2.elapsed / anim2.duration, 1);
7390
- const eased = 1 - (1 - t) * (1 - t);
7400
+ const t2 = Math.min(anim2.elapsed / anim2.duration, 1);
7401
+ const eased = 1 - (1 - t2) * (1 - t2);
7391
7402
  const cx = anim2.from.x + (anim2.to.x - anim2.from.x) * eased;
7392
7403
  const cy = anim2.from.y + (anim2.to.y - anim2.from.y) * eased;
7393
- if (t >= 1) {
7404
+ if (t2 >= 1) {
7394
7405
  movementAnimRef.current = null;
7395
7406
  setMovingPositions((prev) => {
7396
7407
  const next = new Map(prev);
@@ -7421,16 +7432,16 @@ function BattleBoard({
7421
7432
  unitType: unit.unitType,
7422
7433
  heroId: unit.heroId,
7423
7434
  sprite: unit.sprite,
7424
- traits: unit.traits?.map((t) => ({
7425
- name: t.name,
7426
- currentState: t.currentState,
7427
- states: t.states,
7428
- cooldown: t.cooldown ?? 0
7435
+ traits: unit.traits?.map((t2) => ({
7436
+ name: t2.name,
7437
+ currentState: t2.currentState,
7438
+ states: t2.states,
7439
+ cooldown: t2.cooldown ?? 0
7429
7440
  }))
7430
7441
  };
7431
7442
  });
7432
7443
  }, [units, movingPositions]);
7433
- const maxY = Math.max(...tiles.map((t) => t.y), 0);
7444
+ const maxY = Math.max(...tiles.map((t2) => t2.y), 0);
7434
7445
  const baseOffsetX = (maxY + 1) * (TILE_WIDTH * scale / 2);
7435
7446
  const tileToScreen = useCallback(
7436
7447
  (tx, ty) => isoToScreen(tx, ty, scale, baseOffsetX),
@@ -7458,7 +7469,7 @@ function BattleBoard({
7458
7469
  eventBus.emit(`UI:${unitClickEvent}`, { unitId });
7459
7470
  }
7460
7471
  if (currentPhase === "action" && selectedUnit) {
7461
- if (unit.team === "enemy" && attackTargets.some((t) => t.x === unit.position.x && t.y === unit.position.y)) {
7472
+ if (unit.team === "enemy" && attackTargets.some((t2) => t2.x === unit.position.x && t2.y === unit.position.y)) {
7462
7473
  const damage = calculateDamage2 ? calculateDamage2(selectedUnit, unit) : Math.max(1, selectedUnit.attack - unit.defense);
7463
7474
  setIsShaking(true);
7464
7475
  setTimeout(() => setIsShaking(false), 300);
@@ -7535,7 +7546,7 @@ function BattleBoard({
7535
7546
  ]
7536
7547
  );
7537
7548
  const shakeStyle = isShaking ? { animation: "battle-shake 0.3s ease-in-out" } : {};
7538
- return /* @__PURE__ */ jsxs("div", { className: cn("battle-board relative flex flex-col min-h-[600px] bg-[var(--color-background)]", className), children: [
7549
+ return /* @__PURE__ */ jsxs(VStack, { className: cn("battle-board relative min-h-[600px] bg-[var(--color-background)]", className), gap: "none", children: [
7539
7550
  /* @__PURE__ */ jsx("style", { children: `
7540
7551
  @keyframes battle-shake {
7541
7552
  0%, 100% { transform: translate(0, 0); }
@@ -7550,9 +7561,9 @@ function BattleBoard({
7550
7561
  90% { transform: translate(-2px, 1px); }
7551
7562
  }
7552
7563
  ` }),
7553
- header && /* @__PURE__ */ jsx("div", { className: "p-4", children: header(ctx) }),
7554
- /* @__PURE__ */ jsxs("div", { className: "flex flex-1 gap-4 p-4 pt-0", children: [
7555
- /* @__PURE__ */ jsxs("div", { className: "relative flex-1", style: shakeStyle, children: [
7564
+ header && /* @__PURE__ */ jsx(Box, { className: "p-4", children: header(ctx) }),
7565
+ /* @__PURE__ */ jsxs(HStack, { className: "flex-1 gap-4 p-4 pt-0", gap: "none", children: [
7566
+ /* @__PURE__ */ jsxs(Box, { className: "relative flex-1", style: shakeStyle, children: [
7556
7567
  /* @__PURE__ */ jsx(
7557
7568
  IsometricCanvas_default,
7558
7569
  {
@@ -7580,47 +7591,52 @@ function BattleBoard({
7580
7591
  ),
7581
7592
  overlay && overlay(ctx)
7582
7593
  ] }),
7583
- sidebar && /* @__PURE__ */ jsx("div", { className: "w-80 shrink-0", children: sidebar(ctx) })
7594
+ sidebar && /* @__PURE__ */ jsx(Box, { className: "w-80 shrink-0", children: sidebar(ctx) })
7584
7595
  ] }),
7585
- actions ? actions(ctx) : currentPhase !== "game_over" && /* @__PURE__ */ jsxs("div", { className: "fixed bottom-6 right-6 z-50 flex gap-2", children: [
7596
+ actions ? actions(ctx) : currentPhase !== "game_over" && /* @__PURE__ */ jsxs(HStack, { className: "fixed bottom-6 right-6 z-50", gap: "sm", children: [
7586
7597
  (currentPhase === "movement" || currentPhase === "action") && /* @__PURE__ */ jsx(
7587
- "button",
7598
+ Button,
7588
7599
  {
7589
- className: "px-4 py-2 rounded-lg bg-[var(--color-surface)] text-[var(--color-foreground)] border border-[var(--color-border)] shadow-xl hover:opacity-90",
7600
+ variant: "secondary",
7601
+ className: "shadow-xl",
7590
7602
  onClick: handleCancel,
7591
- children: "Cancel"
7603
+ children: t("battle.cancel")
7592
7604
  }
7593
7605
  ),
7594
7606
  /* @__PURE__ */ jsx(
7595
- "button",
7607
+ Button,
7596
7608
  {
7597
- className: "px-4 py-2 rounded-lg bg-[var(--color-primary)] text-white shadow-xl hover:opacity-90",
7609
+ variant: "primary",
7610
+ className: "shadow-xl",
7598
7611
  onClick: handleEndTurn,
7599
- children: "End Turn"
7612
+ children: t("battle.endTurn")
7600
7613
  }
7601
7614
  )
7602
7615
  ] }),
7603
- gameResult && (gameOverOverlay ? gameOverOverlay(ctx) : /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm rounded-xl", children: /* @__PURE__ */ jsxs("div", { className: "text-center space-y-6 p-8", children: [
7616
+ gameResult && (gameOverOverlay ? gameOverOverlay(ctx) : /* @__PURE__ */ jsx(Box, { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-sm rounded-xl", children: /* @__PURE__ */ jsxs(VStack, { className: "text-center p-8", gap: "lg", children: [
7604
7617
  /* @__PURE__ */ jsx(
7605
- "h2",
7618
+ Typography,
7606
7619
  {
7620
+ variant: "h2",
7607
7621
  className: cn(
7608
7622
  "text-4xl font-black tracking-widest uppercase",
7609
7623
  gameResult === "victory" ? "text-yellow-400" : "text-red-500"
7610
7624
  ),
7611
- children: gameResult === "victory" ? "Victory!" : "Defeat"
7625
+ children: gameResult === "victory" ? t("battle.victory") : t("battle.defeat")
7612
7626
  }
7613
7627
  ),
7614
- /* @__PURE__ */ jsxs("p", { className: "text-gray-300", children: [
7615
- "Turns played: ",
7628
+ /* @__PURE__ */ jsxs(Typography, { variant: "body1", className: "text-gray-300", children: [
7629
+ t("battle.turnsPlayed"),
7630
+ ": ",
7616
7631
  currentTurn
7617
7632
  ] }),
7618
7633
  /* @__PURE__ */ jsx(
7619
- "button",
7634
+ Button,
7620
7635
  {
7621
- className: "px-8 py-3 rounded-lg bg-[var(--color-primary)] text-white font-semibold hover:opacity-90",
7636
+ variant: "primary",
7637
+ className: "px-8 py-3 font-semibold",
7622
7638
  onClick: handleReset,
7623
- children: "Play Again"
7639
+ children: t("battle.playAgain")
7624
7640
  }
7625
7641
  )
7626
7642
  ] }) }))
@@ -8716,6 +8732,7 @@ function ActionTile({
8716
8732
  categoryColors,
8717
8733
  className
8718
8734
  }) {
8735
+ useTranslate();
8719
8736
  const config = SIZE_CONFIG3[size];
8720
8737
  const catColor = categoryColors?.[action.category];
8721
8738
  const handleDragStart = useCallback((e) => {
@@ -8743,7 +8760,7 @@ function ActionTile({
8743
8760
  draggable: !disabled,
8744
8761
  onDragStart: handleDragStart,
8745
8762
  children: [
8746
- /* @__PURE__ */ jsx(Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8763
+ action.iconUrl ? /* @__PURE__ */ jsx("img", { src: action.iconUrl, alt: "", className: "w-8 h-8 object-contain" }) : /* @__PURE__ */ jsx(Typography, { variant: "body1", className: cn(config.icon, "leading-none"), children: action.iconEmoji || "\u2726" }),
8747
8764
  /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn(config.text, "text-foreground font-medium whitespace-nowrap"), children: action.name })
8748
8765
  ]
8749
8766
  }
@@ -8856,6 +8873,7 @@ function SequencerBoard({
8856
8873
  }) {
8857
8874
  const { emit } = useEventBus();
8858
8875
  const { t } = useTranslate();
8876
+ const [headerError, setHeaderError] = useState(false);
8859
8877
  const [slots, setSlots] = useState(
8860
8878
  () => Array.from({ length: entity.maxSlots }, () => void 0)
8861
8879
  );
@@ -8968,64 +8986,76 @@ function SequencerBoard({
8968
8986
  const hasFeedback = slotFeedback.some((f) => f !== null);
8969
8987
  const correctCount = slotFeedback.filter((f) => f === "correct").length;
8970
8988
  const encourageKey = ENCOURAGEMENT_KEYS[Math.min(attempts - 1, ENCOURAGEMENT_KEYS.length - 1)] ?? ENCOURAGEMENT_KEYS[0];
8971
- return /* @__PURE__ */ jsxs(VStack, { className: cn("p-4 gap-6", className), children: [
8972
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
8973
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: entity.title }),
8974
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: entity.description })
8975
- ] }),
8976
- showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
8977
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
8978
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: entity.hint })
8979
- ] }) }),
8980
- filledSlots.length > 0 && /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
8981
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
8982
- /* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
8983
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
8984
- hasFeedback && playState === "idle" && /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
8985
- `${correctCount}/${entity.maxSlots} `,
8986
- "\u2705"
8989
+ return /* @__PURE__ */ jsxs(
8990
+ VStack,
8991
+ {
8992
+ className: cn("p-4 gap-6", className),
8993
+ style: {
8994
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
8995
+ backgroundSize: "cover",
8996
+ backgroundPosition: "center"
8997
+ },
8998
+ children: [
8999
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
9000
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9001
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: entity.title }),
9002
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: entity.description })
9003
+ ] }),
9004
+ showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
9005
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
9006
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: entity.hint })
9007
+ ] }) }),
9008
+ filledSlots.length > 0 && /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "linear", size: "md" }),
9009
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9010
+ /* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
9011
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("sequencer.yourSequence") + ":" }),
9012
+ hasFeedback && playState === "idle" && /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-muted-foreground", children: [
9013
+ `${correctCount}/${entity.maxSlots} `,
9014
+ "\u2705"
9015
+ ] })
9016
+ ] }),
9017
+ /* @__PURE__ */ jsx(
9018
+ SequenceBar,
9019
+ {
9020
+ slots,
9021
+ maxSlots: entity.maxSlots,
9022
+ onSlotDrop: handleSlotDrop,
9023
+ onSlotRemove: handleSlotRemove,
9024
+ playing: playState === "playing",
9025
+ currentStep,
9026
+ categoryColors,
9027
+ slotFeedback,
9028
+ size: "lg"
9029
+ }
9030
+ )
9031
+ ] }),
9032
+ playState !== "playing" && /* @__PURE__ */ jsx(
9033
+ ActionPalette,
9034
+ {
9035
+ actions: entity.availableActions,
9036
+ usedActionIds: usedIds,
9037
+ allowDuplicates: entity.allowDuplicates !== false,
9038
+ categoryColors,
9039
+ label: t("sequencer.dragActions")
9040
+ }
9041
+ ),
9042
+ hasFeedback && playState === "idle" && attempts > 0 && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
9043
+ playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: entity.successMessage || t("sequencer.levelComplete") }) }),
9044
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
9045
+ /* @__PURE__ */ jsx(
9046
+ Button,
9047
+ {
9048
+ variant: "primary",
9049
+ onClick: handlePlay,
9050
+ disabled: !canPlay,
9051
+ children: "\u25B6 " + t("game.play")
9052
+ }
9053
+ ),
9054
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleReset, children: "\u21BA " + t("game.reset") })
8987
9055
  ] })
8988
- ] }),
8989
- /* @__PURE__ */ jsx(
8990
- SequenceBar,
8991
- {
8992
- slots,
8993
- maxSlots: entity.maxSlots,
8994
- onSlotDrop: handleSlotDrop,
8995
- onSlotRemove: handleSlotRemove,
8996
- playing: playState === "playing",
8997
- currentStep,
8998
- categoryColors,
8999
- slotFeedback,
9000
- size: "lg"
9001
- }
9002
- )
9003
- ] }),
9004
- playState !== "playing" && /* @__PURE__ */ jsx(
9005
- ActionPalette,
9006
- {
9007
- actions: entity.availableActions,
9008
- usedActionIds: usedIds,
9009
- allowDuplicates: entity.allowDuplicates !== false,
9010
- categoryColors,
9011
- label: t("sequencer.dragActions")
9012
- }
9013
- ),
9014
- hasFeedback && playState === "idle" && attempts > 0 && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: t(encourageKey) }) }),
9015
- playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: entity.successMessage || t("sequencer.levelComplete") }) }),
9016
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
9017
- /* @__PURE__ */ jsx(
9018
- Button,
9019
- {
9020
- variant: "primary",
9021
- onClick: handlePlay,
9022
- disabled: !canPlay,
9023
- children: "\u25B6 " + t("game.play")
9024
- }
9025
- ),
9026
- /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleReset, children: "\u21BA " + t("game.reset") })
9027
- ] })
9028
- ] });
9056
+ ]
9057
+ }
9058
+ );
9029
9059
  }
9030
9060
  SequencerBoard.displayName = "SequencerBoard";
9031
9061
  function RuleEditor({
@@ -9203,6 +9233,7 @@ function EventHandlerBoard({
9203
9233
  const [selectedObjectId, setSelectedObjectId] = useState(
9204
9234
  entity.objects[0]?.id || null
9205
9235
  );
9236
+ const [headerError, setHeaderError] = useState(false);
9206
9237
  const [playState, setPlayState] = useState("editing");
9207
9238
  const [eventLog, setEventLog] = useState([]);
9208
9239
  const [attempts, setAttempts] = useState(0);
@@ -9307,64 +9338,76 @@ function EventHandlerBoard({
9307
9338
  });
9308
9339
  const showHint = attempts >= 3 && entity.hint;
9309
9340
  const encourageKey = ENCOURAGEMENT_KEYS2[Math.min(attempts - 1, ENCOURAGEMENT_KEYS2.length - 1)] ?? ENCOURAGEMENT_KEYS2[0];
9310
- return /* @__PURE__ */ jsxs(VStack, { className: cn("p-4 gap-6", className), children: [
9311
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9312
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: entity.title }),
9313
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: entity.description }),
9314
- /* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
9315
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
9316
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: entity.goalCondition })
9317
- ] })
9318
- ] }),
9319
- /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9320
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
9321
- /* @__PURE__ */ jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => /* @__PURE__ */ jsx(
9322
- Box,
9323
- {
9324
- className: cn(
9325
- "p-3 rounded-lg border-2 cursor-pointer transition-all hover:scale-105",
9326
- selectedObjectId === obj.id ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
9327
- ),
9328
- onClick: () => setSelectedObjectId(obj.id),
9329
- children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
9330
- /* @__PURE__ */ jsx(Typography, { variant: "h5", children: obj.icon }),
9331
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: obj.name }),
9332
- /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
9341
+ return /* @__PURE__ */ jsxs(
9342
+ VStack,
9343
+ {
9344
+ className: cn("p-4 gap-6", className),
9345
+ style: {
9346
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
9347
+ backgroundSize: "cover",
9348
+ backgroundPosition: "center"
9349
+ },
9350
+ children: [
9351
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
9352
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9353
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: entity.title }),
9354
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: entity.description }),
9355
+ /* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-primary/10 border border-primary/30", gap: "xs", children: [
9356
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-primary font-bold", children: t("game.goal") + ":" }),
9357
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: entity.goalCondition })
9333
9358
  ] })
9334
- },
9335
- obj.id
9336
- )) })
9337
- ] }),
9338
- selectedObject && /* @__PURE__ */ jsx(
9339
- ObjectRulePanel,
9340
- {
9341
- object: selectedObject,
9342
- onRulesChange: handleRulesChange,
9343
- disabled: playState !== "editing"
9344
- }
9345
- ),
9346
- eventLog.length > 0 && /* @__PURE__ */ jsx(EventLog, { entries: eventLog }),
9347
- playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: entity.successMessage || t("eventHandler.chainComplete") }) }),
9348
- playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9349
- /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
9350
- showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
9351
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
9352
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: entity.hint })
9353
- ] }) })
9354
- ] }),
9355
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
9356
- playState === "fail" ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsx(
9357
- Button,
9358
- {
9359
- variant: "primary",
9360
- onClick: handlePlay,
9361
- disabled: playState !== "editing",
9362
- children: "\u25B6 " + t("game.play")
9363
- }
9364
- ),
9365
- /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleReset, children: "\u21BA " + t("game.reset") })
9366
- ] })
9367
- ] });
9359
+ ] }),
9360
+ /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9361
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("eventHandler.clickObject") + ":" }),
9362
+ /* @__PURE__ */ jsx(HStack, { className: "flex-wrap", gap: "sm", children: objectViewers.map(({ obj, machine }) => /* @__PURE__ */ jsx(
9363
+ Box,
9364
+ {
9365
+ className: cn(
9366
+ "p-3 rounded-lg border-2 cursor-pointer transition-all hover:scale-105",
9367
+ selectedObjectId === obj.id ? "border-primary bg-primary/10" : "border-border bg-card hover:border-muted-foreground"
9368
+ ),
9369
+ onClick: () => setSelectedObjectId(obj.id),
9370
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "items-center min-w-[120px]", children: [
9371
+ /* @__PURE__ */ jsx(Typography, { variant: "h5", children: obj.icon }),
9372
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground font-medium", children: obj.name }),
9373
+ /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "compact", size: "sm" })
9374
+ ] })
9375
+ },
9376
+ obj.id
9377
+ )) })
9378
+ ] }),
9379
+ selectedObject && /* @__PURE__ */ jsx(
9380
+ ObjectRulePanel,
9381
+ {
9382
+ object: selectedObject,
9383
+ onRulesChange: handleRulesChange,
9384
+ disabled: playState !== "editing"
9385
+ }
9386
+ ),
9387
+ eventLog.length > 0 && /* @__PURE__ */ jsx(EventLog, { entries: eventLog }),
9388
+ playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: entity.successMessage || t("eventHandler.chainComplete") }) }),
9389
+ playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9390
+ /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(encourageKey) }) }),
9391
+ showHint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
9392
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
9393
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: entity.hint })
9394
+ ] }) })
9395
+ ] }),
9396
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
9397
+ playState === "fail" ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsx(
9398
+ Button,
9399
+ {
9400
+ variant: "primary",
9401
+ onClick: handlePlay,
9402
+ disabled: playState !== "editing",
9403
+ children: "\u25B6 " + t("game.play")
9404
+ }
9405
+ ),
9406
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleReset, children: "\u21BA " + t("game.reset") })
9407
+ ] })
9408
+ ]
9409
+ }
9410
+ );
9368
9411
  }
9369
9412
  EventHandlerBoard.displayName = "EventHandlerBoard";
9370
9413
  function StateNode2({
@@ -9574,6 +9617,7 @@ function StateArchitectBoard({
9574
9617
  const { emit } = useEventBus();
9575
9618
  const { t } = useTranslate();
9576
9619
  const [transitions, setTransitions] = useState(entity.transitions);
9620
+ const [headerError, setHeaderError] = useState(false);
9577
9621
  const [playState, setPlayState] = useState("editing");
9578
9622
  const [currentState, setCurrentState] = useState(entity.initialState);
9579
9623
  const [selectedState, setSelectedState] = useState(null);
@@ -9696,150 +9740,162 @@ function StateArchitectBoard({
9696
9740
  ...t2.guardHint ? { guard: t2.guardHint } : {}
9697
9741
  }))
9698
9742
  }), [entity, transitions]);
9699
- return /* @__PURE__ */ jsxs(VStack, { className: cn("p-4 gap-6", className), children: [
9700
- /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9701
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: entity.title }),
9702
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: entity.description }),
9703
- /* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
9704
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
9705
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: entity.hint })
9706
- ] })
9707
- ] }),
9708
- /* @__PURE__ */ jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
9709
- /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "flex-1 min-w-[300px]", children: [
9710
- /* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
9711
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.graph") }),
9712
- addingFrom && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-accent animate-pulse", children: t("stateArchitect.clickTarget", { state: addingFrom || "" }) })
9743
+ return /* @__PURE__ */ jsxs(
9744
+ VStack,
9745
+ {
9746
+ className: cn("p-4 gap-6", className),
9747
+ style: {
9748
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
9749
+ backgroundSize: "cover",
9750
+ backgroundPosition: "center"
9751
+ },
9752
+ children: [
9753
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
9754
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9755
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: "text-foreground", children: entity.title }),
9756
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground", children: entity.description }),
9757
+ /* @__PURE__ */ jsxs(HStack, { className: "items-center p-2 rounded bg-warning/10 border border-warning/30", gap: "xs", children: [
9758
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-warning font-bold", children: t("game.hint") + ":" }),
9759
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: entity.hint })
9760
+ ] })
9713
9761
  ] }),
9714
- /* @__PURE__ */ jsxs(
9715
- Box,
9716
- {
9717
- position: "relative",
9718
- className: "rounded-lg border border-border bg-background overflow-hidden",
9719
- style: { width: GRAPH_W, height: GRAPH_H },
9720
- children: [
9721
- /* @__PURE__ */ jsxs(
9722
- "svg",
9723
- {
9724
- width: GRAPH_W,
9725
- height: GRAPH_H,
9726
- className: "absolute inset-0",
9727
- style: { pointerEvents: "none" },
9728
- children: [
9729
- /* @__PURE__ */ jsxs("defs", { children: [
9730
- /* @__PURE__ */ jsx("marker", { id: "arrowhead", markerWidth: "10", markerHeight: "7", refX: "10", refY: "3.5", orient: "auto", children: /* @__PURE__ */ jsx("polygon", { points: "0 0, 10 3.5, 0 7", fill: "var(--color-border)" }) }),
9731
- /* @__PURE__ */ jsx("marker", { id: "arrowhead-active", markerWidth: "10", markerHeight: "7", refX: "10", refY: "3.5", orient: "auto", children: /* @__PURE__ */ jsx("polygon", { points: "0 0, 10 3.5, 0 7", fill: "var(--color-primary)" }) })
9732
- ] }),
9733
- transitions.map((t2) => {
9734
- const fromPos = positions[t2.from];
9735
- const toPos = positions[t2.to];
9736
- if (!fromPos || !toPos) return null;
9737
- const isActive = t2.from === currentState;
9738
- return /* @__PURE__ */ jsx(
9739
- TransitionArrow,
9740
- {
9741
- from: fromPos,
9742
- to: toPos,
9743
- eventLabel: t2.event,
9744
- guardHint: t2.guardHint,
9745
- isActive
9746
- },
9747
- t2.id
9748
- );
9749
- })
9750
- ]
9751
- }
9752
- ),
9753
- entity.states.map((state) => /* @__PURE__ */ jsx(
9754
- StateNode2,
9755
- {
9756
- name: state,
9757
- position: positions[state],
9758
- isCurrent: state === currentState,
9759
- isSelected: state === selectedState,
9760
- isInitial: state === entity.initialState,
9761
- onClick: () => handleStateClick(state)
9762
- },
9763
- state
9764
- ))
9765
- ]
9766
- }
9767
- ),
9768
- playState === "editing" && /* @__PURE__ */ jsx(HStack, { gap: "sm", children: /* @__PURE__ */ jsx(
9769
- Button,
9770
- {
9771
- variant: "ghost",
9772
- onClick: handleStartAddTransition,
9773
- disabled: !selectedState,
9774
- children: selectedState ? t("stateArchitect.addTransition", { state: selectedState }) : t("stateArchitect.addTransitionPrompt")
9775
- }
9776
- ) }),
9777
- transitions.length > 0 && /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "p-3 rounded-lg bg-muted/50 border border-border", children: [
9778
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground font-medium", children: t("stateArchitect.transitions", { count: transitions.length }) + ":" }),
9779
- transitions.map((t2) => /* @__PURE__ */ jsxs(HStack, { className: "items-center text-xs", gap: "xs", children: [
9780
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: t2.from }),
9781
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: "\u2014[" }),
9782
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-accent font-medium", children: t2.event }),
9783
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: "]\u2192" }),
9784
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-success", children: t2.to }),
9785
- t2.guardHint && /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-warning", children: [
9786
- "(",
9787
- t2.guardHint,
9788
- ")"
9762
+ /* @__PURE__ */ jsxs(HStack, { className: "flex-wrap items-start", gap: "lg", children: [
9763
+ /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "flex-1 min-w-[300px]", children: [
9764
+ /* @__PURE__ */ jsxs(HStack, { className: "items-center justify-between", children: [
9765
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.graph") }),
9766
+ addingFrom && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-accent animate-pulse", children: t("stateArchitect.clickTarget", { state: addingFrom || "" }) })
9789
9767
  ] }),
9790
- playState === "editing" && /* @__PURE__ */ jsx(
9768
+ /* @__PURE__ */ jsxs(
9769
+ Box,
9770
+ {
9771
+ position: "relative",
9772
+ className: "rounded-lg border border-border bg-background overflow-hidden",
9773
+ style: { width: GRAPH_W, height: GRAPH_H },
9774
+ children: [
9775
+ /* @__PURE__ */ jsxs(
9776
+ "svg",
9777
+ {
9778
+ width: GRAPH_W,
9779
+ height: GRAPH_H,
9780
+ className: "absolute inset-0",
9781
+ style: { pointerEvents: "none" },
9782
+ children: [
9783
+ /* @__PURE__ */ jsxs("defs", { children: [
9784
+ /* @__PURE__ */ jsx("marker", { id: "arrowhead", markerWidth: "10", markerHeight: "7", refX: "10", refY: "3.5", orient: "auto", children: /* @__PURE__ */ jsx("polygon", { points: "0 0, 10 3.5, 0 7", fill: "var(--color-border)" }) }),
9785
+ /* @__PURE__ */ jsx("marker", { id: "arrowhead-active", markerWidth: "10", markerHeight: "7", refX: "10", refY: "3.5", orient: "auto", children: /* @__PURE__ */ jsx("polygon", { points: "0 0, 10 3.5, 0 7", fill: "var(--color-primary)" }) })
9786
+ ] }),
9787
+ transitions.map((t2) => {
9788
+ const fromPos = positions[t2.from];
9789
+ const toPos = positions[t2.to];
9790
+ if (!fromPos || !toPos) return null;
9791
+ const isActive = t2.from === currentState;
9792
+ return /* @__PURE__ */ jsx(
9793
+ TransitionArrow,
9794
+ {
9795
+ from: fromPos,
9796
+ to: toPos,
9797
+ eventLabel: t2.event,
9798
+ guardHint: t2.guardHint,
9799
+ isActive
9800
+ },
9801
+ t2.id
9802
+ );
9803
+ })
9804
+ ]
9805
+ }
9806
+ ),
9807
+ entity.states.map((state) => /* @__PURE__ */ jsx(
9808
+ StateNode2,
9809
+ {
9810
+ name: state,
9811
+ position: positions[state],
9812
+ isCurrent: state === currentState,
9813
+ isSelected: state === selectedState,
9814
+ isInitial: state === entity.initialState,
9815
+ onClick: () => handleStateClick(state)
9816
+ },
9817
+ state
9818
+ ))
9819
+ ]
9820
+ }
9821
+ ),
9822
+ playState === "editing" && /* @__PURE__ */ jsx(HStack, { gap: "sm", children: /* @__PURE__ */ jsx(
9791
9823
  Button,
9792
9824
  {
9793
9825
  variant: "ghost",
9794
- onClick: () => handleRemoveTransition(t2.id),
9795
- className: "text-xs ml-auto",
9796
- children: "\xD7"
9826
+ onClick: handleStartAddTransition,
9827
+ disabled: !selectedState,
9828
+ children: selectedState ? t("stateArchitect.addTransition", { state: selectedState }) : t("stateArchitect.addTransitionPrompt")
9797
9829
  }
9798
- )
9799
- ] }, t2.id))
9800
- ] })
9801
- ] }),
9802
- /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "w-[280px] shrink-0", children: [
9803
- /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "full", size: "sm" }),
9804
- /* @__PURE__ */ jsx(
9805
- VariablePanel,
9806
- {
9807
- entityName: entity.entityName,
9808
- variables
9809
- }
9810
- ),
9811
- testResults.length > 0 && /* @__PURE__ */ jsxs(VStack, { className: "p-3 rounded-lg bg-card border border-border", gap: "xs", children: [
9812
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.testResults") + ":" }),
9813
- testResults.map((r, i) => /* @__PURE__ */ jsxs(HStack, { className: "items-center text-xs", gap: "xs", children: [
9814
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: r.passed ? "text-success" : "text-error", children: r.passed ? "\u2714" : "\u2717" }),
9815
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground flex-1", children: r.label }),
9816
- !r.passed && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-error", children: t("stateArchitect.gotState", { state: r.actualState }) })
9817
- ] }, i))
9830
+ ) }),
9831
+ transitions.length > 0 && /* @__PURE__ */ jsxs(VStack, { gap: "xs", className: "p-3 rounded-lg bg-muted/50 border border-border", children: [
9832
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground font-medium", children: t("stateArchitect.transitions", { count: transitions.length }) + ":" }),
9833
+ transitions.map((t2) => /* @__PURE__ */ jsxs(HStack, { className: "items-center text-xs", gap: "xs", children: [
9834
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground", children: t2.from }),
9835
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: "\u2014[" }),
9836
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-accent font-medium", children: t2.event }),
9837
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-muted-foreground", children: "]\u2192" }),
9838
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-success", children: t2.to }),
9839
+ t2.guardHint && /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-warning", children: [
9840
+ "(",
9841
+ t2.guardHint,
9842
+ ")"
9843
+ ] }),
9844
+ playState === "editing" && /* @__PURE__ */ jsx(
9845
+ Button,
9846
+ {
9847
+ variant: "ghost",
9848
+ onClick: () => handleRemoveTransition(t2.id),
9849
+ className: "text-xs ml-auto",
9850
+ children: "\xD7"
9851
+ }
9852
+ )
9853
+ ] }, t2.id))
9854
+ ] })
9855
+ ] }),
9856
+ /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: "w-[280px] shrink-0", children: [
9857
+ /* @__PURE__ */ jsx(TraitStateViewer, { trait: machine, variant: "full", size: "sm" }),
9858
+ /* @__PURE__ */ jsx(
9859
+ VariablePanel,
9860
+ {
9861
+ entityName: entity.entityName,
9862
+ variables
9863
+ }
9864
+ ),
9865
+ testResults.length > 0 && /* @__PURE__ */ jsxs(VStack, { className: "p-3 rounded-lg bg-card border border-border", gap: "xs", children: [
9866
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-muted-foreground font-medium", children: t("stateArchitect.testResults") + ":" }),
9867
+ testResults.map((r, i) => /* @__PURE__ */ jsxs(HStack, { className: "items-center text-xs", gap: "xs", children: [
9868
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: r.passed ? "text-success" : "text-error", children: r.passed ? "\u2714" : "\u2717" }),
9869
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-foreground flex-1", children: r.label }),
9870
+ !r.passed && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-error", children: t("stateArchitect.gotState", { state: r.actualState }) })
9871
+ ] }, i))
9872
+ ] }),
9873
+ entity.showCodeView !== false && /* @__PURE__ */ jsx(CodeView, { data: codeData, label: "View Code" })
9874
+ ] })
9818
9875
  ] }),
9819
- entity.showCodeView !== false && /* @__PURE__ */ jsx(CodeView, { data: codeData, label: "View Code" })
9820
- ] })
9821
- ] }),
9822
- playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: entity.successMessage || t("stateArchitect.allPassed") }) }),
9823
- playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9824
- /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
9825
- attempts >= 3 && entity.hint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
9826
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
9827
- /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: entity.hint })
9828
- ] }) })
9829
- ] }),
9830
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
9831
- playState === "fail" ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsx(
9832
- Button,
9833
- {
9834
- variant: "primary",
9835
- onClick: handleTest,
9836
- disabled: playState !== "editing",
9837
- children: "\u25B6 " + t("game.runTests")
9838
- }
9839
- ),
9840
- /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleReset, children: "\u21BA " + t("game.reset") })
9841
- ] })
9842
- ] });
9876
+ playState === "success" && /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-success/20 border border-success text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "h5", className: "text-success", children: entity.successMessage || t("stateArchitect.allPassed") }) }),
9877
+ playState === "fail" && /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9878
+ /* @__PURE__ */ jsx(Box, { className: "p-4 rounded-lg bg-warning/10 border border-warning/30 text-center", children: /* @__PURE__ */ jsx(Typography, { variant: "body1", className: "text-foreground font-medium", children: t(ENCOURAGEMENT_KEYS3[Math.min(attempts - 1, ENCOURAGEMENT_KEYS3.length - 1)] ?? ENCOURAGEMENT_KEYS3[0]) }) }),
9879
+ attempts >= 3 && entity.hint && /* @__PURE__ */ jsx(Box, { className: "p-3 rounded-lg bg-accent/10 border border-accent/30", children: /* @__PURE__ */ jsxs(HStack, { className: "items-start", gap: "xs", children: [
9880
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-accent font-bold shrink-0", children: "\u{1F4A1} " + t("game.hint") + ":" }),
9881
+ /* @__PURE__ */ jsx(Typography, { variant: "body2", className: "text-foreground", children: entity.hint })
9882
+ ] }) })
9883
+ ] }),
9884
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
9885
+ playState === "fail" ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleTryAgain, children: "\u{1F504} " + t("puzzle.tryAgainButton") }) : /* @__PURE__ */ jsx(
9886
+ Button,
9887
+ {
9888
+ variant: "primary",
9889
+ onClick: handleTest,
9890
+ disabled: playState !== "editing",
9891
+ children: "\u25B6 " + t("game.runTests")
9892
+ }
9893
+ ),
9894
+ /* @__PURE__ */ jsx(Button, { variant: "ghost", onClick: handleReset, children: "\u21BA " + t("game.reset") })
9895
+ ] })
9896
+ ]
9897
+ }
9898
+ );
9843
9899
  }
9844
9900
  StateArchitectBoard.displayName = "StateArchitectBoard";
9845
9901
  function SimulatorBoard({
@@ -9856,6 +9912,7 @@ function SimulatorBoard({
9856
9912
  }
9857
9913
  return init;
9858
9914
  });
9915
+ const [headerError, setHeaderError] = useState(false);
9859
9916
  const [submitted, setSubmitted] = useState(false);
9860
9917
  const [attempts, setAttempts] = useState(0);
9861
9918
  const [showHint, setShowHint] = useState(false);
@@ -9896,83 +9953,95 @@ function SimulatorBoard({
9896
9953
  setAttempts(0);
9897
9954
  setShowHint(false);
9898
9955
  };
9899
- return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
9900
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9901
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
9902
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description })
9903
- ] }) }),
9904
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
9905
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("simulator.parameters") }),
9906
- entity.parameters.map((param) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9907
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
9908
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
9909
- /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
9910
- values[param.id],
9911
- " ",
9912
- param.unit
9913
- ] })
9914
- ] }),
9915
- /* @__PURE__ */ jsx(
9916
- "input",
9917
- {
9918
- type: "range",
9919
- min: param.min,
9920
- max: param.max,
9921
- step: param.step,
9922
- value: values[param.id],
9923
- onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
9924
- disabled: submitted,
9925
- className: "w-full accent-[var(--color-foreground)]"
9926
- }
9927
- ),
9928
- /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
9929
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
9930
- param.min,
9956
+ return /* @__PURE__ */ jsx(
9957
+ Box,
9958
+ {
9959
+ className,
9960
+ style: {
9961
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
9962
+ backgroundSize: "cover",
9963
+ backgroundPosition: "center"
9964
+ },
9965
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
9966
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
9967
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
9968
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
9969
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description })
9970
+ ] }) }),
9971
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
9972
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("simulator.parameters") }),
9973
+ entity.parameters.map((param) => /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
9974
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
9975
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: param.label }),
9976
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
9977
+ values[param.id],
9978
+ " ",
9979
+ param.unit
9980
+ ] })
9981
+ ] }),
9982
+ /* @__PURE__ */ jsx(
9983
+ "input",
9984
+ {
9985
+ type: "range",
9986
+ min: param.min,
9987
+ max: param.max,
9988
+ step: param.step,
9989
+ value: values[param.id],
9990
+ onChange: (e) => handleParameterChange(param.id, Number(e.target.value)),
9991
+ disabled: submitted,
9992
+ className: "w-full accent-[var(--color-foreground)]"
9993
+ }
9994
+ ),
9995
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", children: [
9996
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
9997
+ param.min,
9998
+ " ",
9999
+ param.unit
10000
+ ] }),
10001
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
10002
+ param.max,
10003
+ " ",
10004
+ param.unit
10005
+ ] })
10006
+ ] })
10007
+ ] }, param.id))
10008
+ ] }) }),
10009
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
10010
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: entity.outputLabel }),
10011
+ /* @__PURE__ */ jsxs(Typography, { variant: "h3", weight: "bold", children: [
10012
+ output.toFixed(2),
9931
10013
  " ",
9932
- param.unit
10014
+ entity.outputUnit
10015
+ ] }),
10016
+ submitted && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
10017
+ /* @__PURE__ */ jsx(Icon, { icon: isCorrect ? CheckCircle : XCircle, size: "sm", className: isCorrect ? "text-green-600" : "text-red-600" }),
10018
+ /* @__PURE__ */ jsx(Typography, { variant: "body", className: isCorrect ? "text-green-600" : "text-red-600", children: isCorrect ? entity.successMessage ?? t("simulator.correct") : entity.failMessage ?? t("simulator.incorrect") })
9933
10019
  ] }),
9934
10020
  /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
9935
- param.max,
10021
+ t("simulator.target"),
10022
+ ": ",
10023
+ entity.targetValue,
9936
10024
  " ",
9937
- param.unit
10025
+ entity.outputUnit,
10026
+ " (\xB1",
10027
+ entity.targetTolerance,
10028
+ ")"
10029
+ ] })
10030
+ ] }) }),
10031
+ showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10032
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
10033
+ !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
10034
+ /* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
10035
+ t("simulator.simulate")
10036
+ ] }) : !isCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("simulator.tryAgain") }) : null,
10037
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
10038
+ /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
10039
+ t("simulator.reset")
9938
10040
  ] })
9939
10041
  ] })
9940
- ] }, param.id))
9941
- ] }) }),
9942
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
9943
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: entity.outputLabel }),
9944
- /* @__PURE__ */ jsxs(Typography, { variant: "h3", weight: "bold", children: [
9945
- output.toFixed(2),
9946
- " ",
9947
- entity.outputUnit
9948
- ] }),
9949
- submitted && /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
9950
- /* @__PURE__ */ jsx(Icon, { icon: isCorrect ? CheckCircle : XCircle, size: "sm", className: isCorrect ? "text-green-600" : "text-red-600" }),
9951
- /* @__PURE__ */ jsx(Typography, { variant: "body", className: isCorrect ? "text-green-600" : "text-red-600", children: isCorrect ? entity.successMessage ?? t("simulator.correct") : entity.failMessage ?? t("simulator.incorrect") })
9952
- ] }),
9953
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
9954
- t("simulator.target"),
9955
- ": ",
9956
- entity.targetValue,
9957
- " ",
9958
- entity.outputUnit,
9959
- " (\xB1",
9960
- entity.targetTolerance,
9961
- ")"
9962
- ] })
9963
- ] }) }),
9964
- showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
9965
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
9966
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, children: [
9967
- /* @__PURE__ */ jsx(Icon, { icon: Play, size: "sm" }),
9968
- t("simulator.simulate")
9969
- ] }) : !isCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("simulator.tryAgain") }) : null,
9970
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
9971
- /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
9972
- t("simulator.reset")
9973
10042
  ] })
9974
- ] })
9975
- ] }) });
10043
+ }
10044
+ );
9976
10045
  }
9977
10046
  SimulatorBoard.displayName = "SimulatorBoard";
9978
10047
  function ClassifierBoard({
@@ -9983,6 +10052,7 @@ function ClassifierBoard({
9983
10052
  const { emit } = useEventBus();
9984
10053
  const { t } = useTranslate();
9985
10054
  const [assignments, setAssignments] = useState({});
10055
+ const [headerError, setHeaderError] = useState(false);
9986
10056
  const [submitted, setSubmitted] = useState(false);
9987
10057
  const [attempts, setAttempts] = useState(0);
9988
10058
  const [showHint, setShowHint] = useState(false);
@@ -10027,71 +10097,88 @@ function ClassifierBoard({
10027
10097
  setAttempts(0);
10028
10098
  setShowHint(false);
10029
10099
  };
10030
- return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10031
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10032
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
10033
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description })
10034
- ] }) }),
10035
- unassignedItems.length > 0 && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10036
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("classifier.itemsToSort") }),
10037
- /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "flex-wrap", children: unassignedItems.map((item) => /* @__PURE__ */ jsx(Badge, { size: "md", className: "cursor-pointer", children: item.label }, item.id)) })
10038
- ] }) }),
10039
- /* @__PURE__ */ jsx(VStack, { gap: "md", children: entity.categories.map((cat) => {
10040
- const catItems = entity.items.filter((item) => assignments[item.id] === cat.id);
10041
- return /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10042
- /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
10043
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: cat.label }),
10044
- /* @__PURE__ */ jsx(Badge, { size: "sm", children: catItems.length })
10045
- ] }),
10046
- /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap min-h-[2rem]", children: catItems.map((item) => {
10047
- const result = results.find((r) => r.item.id === item.id);
10048
- return /* @__PURE__ */ jsxs(
10049
- Badge,
10050
- {
10051
- size: "sm",
10052
- className: `cursor-pointer ${result ? result.correct ? "border-green-500 bg-green-50 dark:bg-green-950" : "border-red-500 bg-red-50 dark:bg-red-950" : ""}`,
10053
- onClick: () => handleUnassign(item.id),
10054
- children: [
10055
- item.label,
10056
- result && /* @__PURE__ */ jsx(Icon, { icon: result.correct ? CheckCircle : XCircle, size: "xs", className: result.correct ? "text-green-600" : "text-red-600" })
10057
- ]
10058
- },
10059
- item.id
10060
- );
10100
+ return /* @__PURE__ */ jsx(
10101
+ Box,
10102
+ {
10103
+ className,
10104
+ style: {
10105
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
10106
+ backgroundSize: "cover",
10107
+ backgroundPosition: "center"
10108
+ },
10109
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10110
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
10111
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10112
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
10113
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description })
10114
+ ] }) }),
10115
+ unassignedItems.length > 0 && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10116
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("classifier.itemsToSort") }),
10117
+ /* @__PURE__ */ jsx(HStack, { gap: "sm", className: "flex-wrap", children: unassignedItems.map((item) => /* @__PURE__ */ jsxs(Badge, { size: "md", className: "cursor-pointer", children: [
10118
+ item.iconUrl && /* @__PURE__ */ jsx("img", { src: item.iconUrl, alt: "", className: "w-4 h-4 object-contain inline-block" }),
10119
+ item.label
10120
+ ] }, item.id)) })
10121
+ ] }) }),
10122
+ /* @__PURE__ */ jsx(VStack, { gap: "md", children: entity.categories.map((cat) => {
10123
+ const catItems = entity.items.filter((item) => assignments[item.id] === cat.id);
10124
+ return /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10125
+ cat.imageUrl && /* @__PURE__ */ jsx(Box, { className: "w-full h-16 overflow-hidden rounded-md", children: /* @__PURE__ */ jsx("img", { src: cat.imageUrl, alt: "", className: "w-full h-full object-cover" }) }),
10126
+ /* @__PURE__ */ jsxs(HStack, { justify: "between", align: "center", children: [
10127
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: cat.label }),
10128
+ /* @__PURE__ */ jsx(Badge, { size: "sm", children: catItems.length })
10129
+ ] }),
10130
+ /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap min-h-[2rem]", children: catItems.map((item) => {
10131
+ const result = results.find((r) => r.item.id === item.id);
10132
+ return /* @__PURE__ */ jsxs(
10133
+ Badge,
10134
+ {
10135
+ size: "sm",
10136
+ className: `cursor-pointer ${result ? result.correct ? "border-green-500 bg-green-50 dark:bg-green-950" : "border-red-500 bg-red-50 dark:bg-red-950" : ""}`,
10137
+ onClick: () => handleUnassign(item.id),
10138
+ children: [
10139
+ item.iconUrl && /* @__PURE__ */ jsx("img", { src: item.iconUrl, alt: "", className: "w-3 h-3 object-contain inline-block" }),
10140
+ item.label,
10141
+ result && /* @__PURE__ */ jsx(Icon, { icon: result.correct ? CheckCircle : XCircle, size: "xs", className: result.correct ? "text-green-600" : "text-red-600" })
10142
+ ]
10143
+ },
10144
+ item.id
10145
+ );
10146
+ }) }),
10147
+ !submitted && unassignedItems.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: unassignedItems.map((item) => /* @__PURE__ */ jsxs(
10148
+ Button,
10149
+ {
10150
+ size: "sm",
10151
+ variant: "ghost",
10152
+ onClick: () => handleAssign(item.id, cat.id),
10153
+ className: "text-xs opacity-50 hover:opacity-100",
10154
+ children: [
10155
+ "+ ",
10156
+ item.label
10157
+ ]
10158
+ },
10159
+ item.id
10160
+ )) })
10161
+ ] }) }, cat.id);
10061
10162
  }) }),
10062
- !submitted && unassignedItems.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "flex-wrap", children: unassignedItems.map((item) => /* @__PURE__ */ jsxs(
10063
- Button,
10064
- {
10065
- size: "sm",
10066
- variant: "ghost",
10067
- onClick: () => handleAssign(item.id, cat.id),
10068
- className: "text-xs opacity-50 hover:opacity-100",
10069
- children: [
10070
- "+ ",
10071
- item.label
10072
- ]
10073
- },
10074
- item.id
10075
- )) })
10076
- ] }) }, cat.id);
10077
- }) }),
10078
- submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
10079
- /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-green-600" : "text-red-600" }),
10080
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? entity.successMessage ?? t("classifier.allCorrect") : `${correctCount}/${entity.items.length} ${t("classifier.correct")}` }),
10081
- !allCorrect && entity.failMessage && /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-[var(--color-muted-foreground)]", children: entity.failMessage })
10082
- ] }) }),
10083
- showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10084
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
10085
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
10086
- /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
10087
- t("classifier.check")
10088
- ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("classifier.tryAgain") }) : null,
10089
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
10090
- /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
10091
- t("classifier.reset")
10163
+ submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
10164
+ /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-green-600" : "text-red-600" }),
10165
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? entity.successMessage ?? t("classifier.allCorrect") : `${correctCount}/${entity.items.length} ${t("classifier.correct")}` }),
10166
+ !allCorrect && entity.failMessage && /* @__PURE__ */ jsx(Typography, { variant: "body", className: "text-[var(--color-muted-foreground)]", children: entity.failMessage })
10167
+ ] }) }),
10168
+ showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10169
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
10170
+ !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allAssigned, children: [
10171
+ /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
10172
+ t("classifier.check")
10173
+ ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("classifier.tryAgain") }) : null,
10174
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
10175
+ /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
10176
+ t("classifier.reset")
10177
+ ] })
10178
+ ] })
10092
10179
  ] })
10093
- ] })
10094
- ] }) });
10180
+ }
10181
+ );
10095
10182
  }
10096
10183
  ClassifierBoard.displayName = "ClassifierBoard";
10097
10184
  function BuilderBoard({
@@ -10102,6 +10189,7 @@ function BuilderBoard({
10102
10189
  const { emit } = useEventBus();
10103
10190
  const { t } = useTranslate();
10104
10191
  const [placements, setPlacements] = useState({});
10192
+ const [headerError, setHeaderError] = useState(false);
10105
10193
  const [submitted, setSubmitted] = useState(false);
10106
10194
  const [attempts, setAttempts] = useState(0);
10107
10195
  const [showHint, setShowHint] = useState(false);
@@ -10150,77 +10238,95 @@ function BuilderBoard({
10150
10238
  setShowHint(false);
10151
10239
  };
10152
10240
  const getComponentById = (id) => entity.components.find((c) => c.id === id);
10153
- return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10154
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10155
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
10156
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description })
10157
- ] }) }),
10158
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10159
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("builder.components") }),
10160
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "flex-wrap", children: [
10161
- availableComponents.map((comp) => /* @__PURE__ */ jsxs(
10162
- Button,
10163
- {
10164
- size: "sm",
10165
- variant: selectedComponent === comp.id ? "primary" : "secondary",
10166
- onClick: () => setSelectedComponent(selectedComponent === comp.id ? null : comp.id),
10167
- disabled: submitted,
10168
- children: [
10169
- comp.iconEmoji && `${comp.iconEmoji} `,
10170
- comp.label
10171
- ]
10172
- },
10173
- comp.id
10174
- )),
10175
- availableComponents.length === 0 && !submitted && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("builder.allPlaced") })
10176
- ] })
10177
- ] }) }),
10178
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10179
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("builder.blueprint") }),
10180
- /* @__PURE__ */ jsx(VStack, { gap: "sm", children: entity.slots.map((slot) => {
10181
- const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
10182
- const result = results.find((r) => r.slot.id === slot.id);
10183
- return /* @__PURE__ */ jsxs(
10184
- HStack,
10185
- {
10186
- gap: "sm",
10187
- align: "center",
10188
- className: `p-3 border-2 rounded ${result ? result.correct ? "border-green-500" : "border-red-500" : selectedComponent ? "border-dashed border-[var(--color-foreground)] cursor-pointer" : "border-[var(--color-border)]"}`,
10189
- onClick: () => handlePlaceComponent(slot.id),
10190
- children: [
10191
- /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
10192
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: slot.label }),
10193
- slot.description && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: slot.description })
10194
- ] }),
10195
- placedComp ? /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
10196
- /* @__PURE__ */ jsxs(Badge, { size: "sm", onClick: () => handleRemoveFromSlot(slot.id), children: [
10197
- placedComp.iconEmoji && `${placedComp.iconEmoji} `,
10198
- placedComp.label
10199
- ] }),
10200
- result && /* @__PURE__ */ jsx(Icon, { icon: result.correct ? CheckCircle : XCircle, size: "sm", className: result.correct ? "text-green-600" : "text-red-600" })
10201
- ] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("builder.empty") })
10202
- ]
10203
- },
10204
- slot.id
10205
- );
10206
- }) })
10207
- ] }) }),
10208
- submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
10209
- /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-green-600" : "text-red-600" }),
10210
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? entity.successMessage ?? t("builder.success") : entity.failMessage ?? t("builder.incorrect") })
10211
- ] }) }),
10212
- showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10213
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
10214
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
10215
- /* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
10216
- t("builder.build")
10217
- ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("builder.tryAgain") }) : null,
10218
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
10219
- /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
10220
- t("builder.reset")
10241
+ return /* @__PURE__ */ jsx(
10242
+ Box,
10243
+ {
10244
+ className,
10245
+ style: {
10246
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
10247
+ backgroundSize: "cover",
10248
+ backgroundPosition: "center"
10249
+ },
10250
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10251
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
10252
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10253
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
10254
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description })
10255
+ ] }) }),
10256
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10257
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("builder.components") }),
10258
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: "flex-wrap", children: [
10259
+ availableComponents.map((comp) => /* @__PURE__ */ jsxs(
10260
+ Button,
10261
+ {
10262
+ size: "sm",
10263
+ variant: selectedComponent === comp.id ? "primary" : "secondary",
10264
+ onClick: () => setSelectedComponent(selectedComponent === comp.id ? null : comp.id),
10265
+ disabled: submitted,
10266
+ children: [
10267
+ comp.iconUrl ? /* @__PURE__ */ jsx("img", { src: comp.iconUrl, alt: "", className: "w-5 h-5 object-contain inline-block mr-1" }) : comp.iconEmoji ? /* @__PURE__ */ jsxs(Fragment, { children: [
10268
+ comp.iconEmoji,
10269
+ " "
10270
+ ] }) : null,
10271
+ comp.label
10272
+ ]
10273
+ },
10274
+ comp.id
10275
+ )),
10276
+ availableComponents.length === 0 && !submitted && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("builder.allPlaced") })
10277
+ ] })
10278
+ ] }) }),
10279
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10280
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("builder.blueprint") }),
10281
+ /* @__PURE__ */ jsx(VStack, { gap: "sm", children: entity.slots.map((slot) => {
10282
+ const placedComp = placements[slot.id] ? getComponentById(placements[slot.id]) : null;
10283
+ const result = results.find((r) => r.slot.id === slot.id);
10284
+ return /* @__PURE__ */ jsxs(
10285
+ HStack,
10286
+ {
10287
+ gap: "sm",
10288
+ align: "center",
10289
+ className: `p-3 border-2 rounded ${result ? result.correct ? "border-green-500" : "border-red-500" : selectedComponent ? "border-dashed border-[var(--color-foreground)] cursor-pointer" : "border-[var(--color-border)]"}`,
10290
+ onClick: () => handlePlaceComponent(slot.id),
10291
+ children: [
10292
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "flex-1", children: [
10293
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "medium", children: slot.label }),
10294
+ slot.description && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: slot.description })
10295
+ ] }),
10296
+ placedComp ? /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
10297
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", onClick: () => handleRemoveFromSlot(slot.id), children: [
10298
+ placedComp.iconUrl ? /* @__PURE__ */ jsx("img", { src: placedComp.iconUrl, alt: "", className: "w-4 h-4 object-contain inline-block mr-1" }) : placedComp.iconEmoji ? /* @__PURE__ */ jsxs(Fragment, { children: [
10299
+ placedComp.iconEmoji,
10300
+ " "
10301
+ ] }) : null,
10302
+ placedComp.label
10303
+ ] }),
10304
+ result && /* @__PURE__ */ jsx(Icon, { icon: result.correct ? CheckCircle : XCircle, size: "sm", className: result.correct ? "text-green-600" : "text-red-600" })
10305
+ ] }) : /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("builder.empty") })
10306
+ ]
10307
+ },
10308
+ slot.id
10309
+ );
10310
+ }) })
10311
+ ] }) }),
10312
+ submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
10313
+ /* @__PURE__ */ jsx(Icon, { icon: allCorrect ? CheckCircle : XCircle, size: "lg", className: allCorrect ? "text-green-600" : "text-red-600" }),
10314
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? entity.successMessage ?? t("builder.success") : entity.failMessage ?? t("builder.incorrect") })
10315
+ ] }) }),
10316
+ showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10317
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
10318
+ !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: !allPlaced, children: [
10319
+ /* @__PURE__ */ jsx(Icon, { icon: Wrench, size: "sm" }),
10320
+ t("builder.build")
10321
+ ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("builder.tryAgain") }) : null,
10322
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
10323
+ /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
10324
+ t("builder.reset")
10325
+ ] })
10326
+ ] })
10221
10327
  ] })
10222
- ] })
10223
- ] }) });
10328
+ }
10329
+ );
10224
10330
  }
10225
10331
  BuilderBoard.displayName = "BuilderBoard";
10226
10332
  function DebuggerBoard({
@@ -10231,6 +10337,7 @@ function DebuggerBoard({
10231
10337
  const { emit } = useEventBus();
10232
10338
  const { t } = useTranslate();
10233
10339
  const [flaggedLines, setFlaggedLines] = useState(/* @__PURE__ */ new Set());
10340
+ const [headerError, setHeaderError] = useState(false);
10234
10341
  const [submitted, setSubmitted] = useState(false);
10235
10342
  const [attempts, setAttempts] = useState(0);
10236
10343
  const [showHint, setShowHint] = useState(false);
@@ -10270,73 +10377,85 @@ function DebuggerBoard({
10270
10377
  setAttempts(0);
10271
10378
  setShowHint(false);
10272
10379
  };
10273
- return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10274
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10275
- /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
10276
- /* @__PURE__ */ jsx(Icon, { icon: Bug, size: "sm" }),
10277
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title })
10278
- ] }),
10279
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description }),
10280
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("debugger.findBugs", { count: String(entity.bugCount) }) })
10281
- ] }) }),
10282
- /* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: entity.lines.map((line, i) => {
10283
- const isFlagged = flaggedLines.has(line.id);
10284
- let lineStyle = "";
10285
- if (submitted) {
10286
- if (line.isBug && isFlagged) lineStyle = "bg-green-50 dark:bg-green-950";
10287
- else if (line.isBug && !isFlagged) lineStyle = "bg-yellow-50 dark:bg-yellow-950";
10288
- else if (!line.isBug && isFlagged) lineStyle = "bg-red-50 dark:bg-red-950";
10289
- } else if (isFlagged) {
10290
- lineStyle = "bg-red-50 dark:bg-red-950";
10291
- }
10292
- return /* @__PURE__ */ jsxs(
10293
- HStack,
10294
- {
10295
- gap: "none",
10296
- align: "stretch",
10297
- className: `border-b border-[var(--color-border)] cursor-pointer hover:bg-[var(--color-muted)] ${lineStyle}`,
10298
- onClick: () => toggleLine(line.id),
10299
- children: [
10300
- /* @__PURE__ */ jsx(Box, { className: "w-10 flex-shrink-0 flex items-center justify-center border-r border-[var(--color-border)] text-[var(--color-muted-foreground)]", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", children: i + 1 }) }),
10301
- /* @__PURE__ */ jsx(Box, { className: "flex-1 px-3 py-1.5 font-mono text-sm whitespace-pre", children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-mono text-sm", children: line.content }) }),
10302
- /* @__PURE__ */ jsxs(Box, { className: "w-8 flex-shrink-0 flex items-center justify-center", children: [
10303
- isFlagged && /* @__PURE__ */ jsx(Icon, { icon: Bug, size: "xs", className: "text-red-600" }),
10304
- submitted && line.isBug && !isFlagged && /* @__PURE__ */ jsx(Icon, { icon: Bug, size: "xs", className: "text-yellow-600" })
10305
- ] })
10306
- ]
10307
- },
10308
- line.id
10309
- );
10310
- }) }) }),
10311
- submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10312
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? entity.successMessage ?? t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
10313
- bugLines.map((line) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "start", children: [
10314
- /* @__PURE__ */ jsx(
10315
- Icon,
10316
- {
10317
- icon: flaggedLines.has(line.id) ? CheckCircle : XCircle,
10318
- size: "xs",
10319
- className: flaggedLines.has(line.id) ? "text-green-600 mt-0.5" : "text-yellow-600 mt-0.5"
10380
+ return /* @__PURE__ */ jsx(
10381
+ Box,
10382
+ {
10383
+ className,
10384
+ style: {
10385
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
10386
+ backgroundSize: "cover",
10387
+ backgroundPosition: "center"
10388
+ },
10389
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10390
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
10391
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10392
+ /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
10393
+ /* @__PURE__ */ jsx(Icon, { icon: Bug, size: "sm" }),
10394
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title })
10395
+ ] }),
10396
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description }),
10397
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("debugger.findBugs", { count: String(entity.bugCount) }) })
10398
+ ] }) }),
10399
+ /* @__PURE__ */ jsx(Card, { className: "p-0 overflow-hidden", children: /* @__PURE__ */ jsx(VStack, { gap: "none", children: entity.lines.map((line, i) => {
10400
+ const isFlagged = flaggedLines.has(line.id);
10401
+ let lineStyle = "";
10402
+ if (submitted) {
10403
+ if (line.isBug && isFlagged) lineStyle = "bg-green-50 dark:bg-green-950";
10404
+ else if (line.isBug && !isFlagged) lineStyle = "bg-yellow-50 dark:bg-yellow-950";
10405
+ else if (!line.isBug && isFlagged) lineStyle = "bg-red-50 dark:bg-red-950";
10406
+ } else if (isFlagged) {
10407
+ lineStyle = "bg-red-50 dark:bg-red-950";
10320
10408
  }
10321
- ),
10322
- /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
10323
- /* @__PURE__ */ jsx(Typography, { variant: "caption", weight: "bold", className: "font-mono", children: line.content.trim() }),
10324
- line.explanation && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: line.explanation })
10409
+ return /* @__PURE__ */ jsxs(
10410
+ HStack,
10411
+ {
10412
+ gap: "none",
10413
+ align: "stretch",
10414
+ className: `border-b border-[var(--color-border)] cursor-pointer hover:bg-[var(--color-muted)] ${lineStyle}`,
10415
+ onClick: () => toggleLine(line.id),
10416
+ children: [
10417
+ /* @__PURE__ */ jsx(Box, { className: "w-10 flex-shrink-0 flex items-center justify-center border-r border-[var(--color-border)] text-[var(--color-muted-foreground)]", children: /* @__PURE__ */ jsx(Typography, { variant: "caption", children: i + 1 }) }),
10418
+ /* @__PURE__ */ jsx(Box, { className: "flex-1 px-3 py-1.5 font-mono text-sm whitespace-pre", children: /* @__PURE__ */ jsx(Typography, { variant: "body", className: "font-mono text-sm", children: line.content }) }),
10419
+ /* @__PURE__ */ jsxs(Box, { className: "w-8 flex-shrink-0 flex items-center justify-center", children: [
10420
+ isFlagged && /* @__PURE__ */ jsx(Icon, { icon: Bug, size: "xs", className: "text-red-600" }),
10421
+ submitted && line.isBug && !isFlagged && /* @__PURE__ */ jsx(Icon, { icon: Bug, size: "xs", className: "text-yellow-600" })
10422
+ ] })
10423
+ ]
10424
+ },
10425
+ line.id
10426
+ );
10427
+ }) }) }),
10428
+ submitted && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10429
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: allCorrect ? entity.successMessage ?? t("debugger.allFound") : `${correctFlags.length}/${bugLines.length} ${t("debugger.bugsFound")}` }),
10430
+ bugLines.map((line) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "start", children: [
10431
+ /* @__PURE__ */ jsx(
10432
+ Icon,
10433
+ {
10434
+ icon: flaggedLines.has(line.id) ? CheckCircle : XCircle,
10435
+ size: "xs",
10436
+ className: flaggedLines.has(line.id) ? "text-green-600 mt-0.5" : "text-yellow-600 mt-0.5"
10437
+ }
10438
+ ),
10439
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", children: [
10440
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", weight: "bold", className: "font-mono", children: line.content.trim() }),
10441
+ line.explanation && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: line.explanation })
10442
+ ] })
10443
+ ] }, line.id))
10444
+ ] }) }),
10445
+ showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10446
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
10447
+ !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
10448
+ /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
10449
+ t("debugger.submit")
10450
+ ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
10451
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
10452
+ /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
10453
+ t("debugger.reset")
10454
+ ] })
10325
10455
  ] })
10326
- ] }, line.id))
10327
- ] }) }),
10328
- showHint && entity.hint && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10329
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "center", children: [
10330
- !submitted ? /* @__PURE__ */ jsxs(Button, { variant: "primary", onClick: handleSubmit, disabled: flaggedLines.size === 0, children: [
10331
- /* @__PURE__ */ jsx(Icon, { icon: Send, size: "sm" }),
10332
- t("debugger.submit")
10333
- ] }) : !allCorrect ? /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("debugger.tryAgain") }) : null,
10334
- /* @__PURE__ */ jsxs(Button, { variant: "secondary", onClick: handleFullReset, children: [
10335
- /* @__PURE__ */ jsx(Icon, { icon: RotateCcw, size: "sm" }),
10336
- t("debugger.reset")
10337
10456
  ] })
10338
- ] })
10339
- ] }) });
10457
+ }
10458
+ );
10340
10459
  }
10341
10460
  DebuggerBoard.displayName = "DebuggerBoard";
10342
10461
  function getOpponentAction(strategy, actions, history) {
@@ -10362,6 +10481,7 @@ function NegotiatorBoard({
10362
10481
  const { emit } = useEventBus();
10363
10482
  const { t } = useTranslate();
10364
10483
  const [history, setHistory] = useState([]);
10484
+ const [headerError, setHeaderError] = useState(false);
10365
10485
  const [showHint, setShowHint] = useState(false);
10366
10486
  const currentRound = history.length;
10367
10487
  const isComplete = currentRound >= entity.totalRounds;
@@ -10398,76 +10518,88 @@ function NegotiatorBoard({
10398
10518
  setShowHint(false);
10399
10519
  };
10400
10520
  const getActionLabel = (id) => entity.actions.find((a) => a.id === id)?.label ?? id;
10401
- return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10402
- /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10403
- /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
10404
- /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description }),
10405
- /* @__PURE__ */ jsxs(HStack, { gap: "md", children: [
10406
- /* @__PURE__ */ jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(entity.totalRounds) }) }),
10407
- /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
10408
- t("negotiator.target"),
10409
- ": ",
10410
- entity.targetScore
10411
- ] })
10412
- ] })
10413
- ] }) }),
10414
- /* @__PURE__ */ jsxs(HStack, { gap: "md", justify: "center", children: [
10415
- /* @__PURE__ */ jsx(Card, { className: "p-4 flex-1 text-center", children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", children: [
10416
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("negotiator.you") }),
10417
- /* @__PURE__ */ jsx(Typography, { variant: "h3", weight: "bold", children: playerTotal })
10418
- ] }) }),
10419
- /* @__PURE__ */ jsx(Card, { className: "p-4 flex-1 text-center", children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", children: [
10420
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("negotiator.opponent") }),
10421
- /* @__PURE__ */ jsx(Typography, { variant: "h3", weight: "bold", children: opponentTotal })
10422
- ] }) })
10423
- ] }),
10424
- !isComplete && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10425
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("negotiator.chooseAction") }),
10426
- /* @__PURE__ */ jsx(HStack, { gap: "sm", justify: "center", className: "flex-wrap", children: entity.actions.map((action) => /* @__PURE__ */ jsx(
10427
- Button,
10428
- {
10429
- variant: "primary",
10430
- onClick: () => handleAction(action.id),
10431
- children: action.label
10432
- },
10433
- action.id
10434
- )) })
10435
- ] }) }),
10436
- history.length > 0 && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10437
- /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("negotiator.history") }),
10438
- history.map((round) => /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", className: "text-sm", children: [
10439
- /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
10440
- "R",
10441
- round.round
10442
- ] }),
10443
- /* @__PURE__ */ jsx(Typography, { variant: "caption", children: getActionLabel(round.playerAction) }),
10444
- /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: "vs" }),
10445
- /* @__PURE__ */ jsx(Typography, { variant: "caption", children: getActionLabel(round.opponentAction) }),
10446
- /* @__PURE__ */ jsx(Icon, { icon: ArrowRight, size: "xs" }),
10447
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", weight: "bold", className: "text-green-600", children: [
10448
- "+",
10449
- round.playerPayoff
10521
+ return /* @__PURE__ */ jsx(
10522
+ Box,
10523
+ {
10524
+ className,
10525
+ style: {
10526
+ backgroundImage: entity.theme?.background ? `url(${entity.theme.background})` : void 0,
10527
+ backgroundSize: "cover",
10528
+ backgroundPosition: "center"
10529
+ },
10530
+ children: /* @__PURE__ */ jsxs(VStack, { gap: "lg", className: "p-4", children: [
10531
+ entity.headerImage && !headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 overflow-hidden rounded-lg", children: /* @__PURE__ */ jsx("img", { src: entity.headerImage, alt: "", onError: () => setHeaderError(true), className: "w-full h-full object-cover" }) }) : entity.headerImage && headerError ? /* @__PURE__ */ jsx(Box, { className: "w-full h-32 rounded-lg bg-gradient-to-br from-[var(--color-muted)] to-[var(--color-accent)] opacity-60" }) : null,
10532
+ /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10533
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", weight: "bold", children: entity.title }),
10534
+ /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.description }),
10535
+ /* @__PURE__ */ jsxs(HStack, { gap: "md", children: [
10536
+ /* @__PURE__ */ jsx(Badge, { size: "sm", children: t("negotiator.round", { current: String(currentRound), total: String(entity.totalRounds) }) }),
10537
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
10538
+ t("negotiator.target"),
10539
+ ": ",
10540
+ entity.targetScore
10541
+ ] })
10542
+ ] })
10543
+ ] }) }),
10544
+ /* @__PURE__ */ jsxs(HStack, { gap: "md", justify: "center", children: [
10545
+ /* @__PURE__ */ jsx(Card, { className: "p-4 flex-1 text-center", children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", children: [
10546
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("negotiator.you") }),
10547
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", weight: "bold", children: playerTotal })
10548
+ ] }) }),
10549
+ /* @__PURE__ */ jsx(Card, { className: "p-4 flex-1 text-center", children: /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", children: [
10550
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: t("negotiator.opponent") }),
10551
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", weight: "bold", children: opponentTotal })
10552
+ ] }) })
10450
10553
  ] }),
10451
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
10452
- "/ +",
10453
- round.opponentPayoff
10454
- ] })
10455
- ] }, round.round))
10456
- ] }) }),
10457
- isComplete && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
10458
- /* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: won ? "text-green-600" : "text-red-600" }),
10459
- /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: won ? entity.successMessage ?? t("negotiator.success") : entity.failMessage ?? t("negotiator.failed") }),
10460
- /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
10461
- t("negotiator.finalScore"),
10462
- ": ",
10463
- playerTotal,
10464
- "/",
10465
- entity.targetScore
10554
+ !isComplete && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10555
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("negotiator.chooseAction") }),
10556
+ /* @__PURE__ */ jsx(HStack, { gap: "sm", justify: "center", className: "flex-wrap", children: entity.actions.map((action) => /* @__PURE__ */ jsx(
10557
+ Button,
10558
+ {
10559
+ variant: "primary",
10560
+ onClick: () => handleAction(action.id),
10561
+ children: action.label
10562
+ },
10563
+ action.id
10564
+ )) })
10565
+ ] }) }),
10566
+ history.length > 0 && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
10567
+ /* @__PURE__ */ jsx(Typography, { variant: "small", weight: "bold", className: "uppercase tracking-wider text-[var(--color-muted-foreground)]", children: t("negotiator.history") }),
10568
+ history.map((round) => /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "center", className: "text-sm", children: [
10569
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", children: [
10570
+ "R",
10571
+ round.round
10572
+ ] }),
10573
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", children: getActionLabel(round.playerAction) }),
10574
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: "vs" }),
10575
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", children: getActionLabel(round.opponentAction) }),
10576
+ /* @__PURE__ */ jsx(Icon, { icon: ArrowRight, size: "xs" }),
10577
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", weight: "bold", className: "text-green-600", children: [
10578
+ "+",
10579
+ round.playerPayoff
10580
+ ] }),
10581
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
10582
+ "/ +",
10583
+ round.opponentPayoff
10584
+ ] })
10585
+ ] }, round.round))
10586
+ ] }) }),
10587
+ isComplete && /* @__PURE__ */ jsx(Card, { className: "p-4", children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", align: "center", children: [
10588
+ /* @__PURE__ */ jsx(Icon, { icon: CheckCircle, size: "lg", className: won ? "text-green-600" : "text-red-600" }),
10589
+ /* @__PURE__ */ jsx(Typography, { variant: "body", weight: "bold", children: won ? entity.successMessage ?? t("negotiator.success") : entity.failMessage ?? t("negotiator.failed") }),
10590
+ /* @__PURE__ */ jsxs(Typography, { variant: "caption", className: "text-[var(--color-muted-foreground)]", children: [
10591
+ t("negotiator.finalScore"),
10592
+ ": ",
10593
+ playerTotal,
10594
+ "/",
10595
+ entity.targetScore
10596
+ ] })
10597
+ ] }) }),
10598
+ showHint && entity.hint && !won && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10599
+ isComplete && !won && /* @__PURE__ */ jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
10466
10600
  ] })
10467
- ] }) }),
10468
- showHint && entity.hint && !won && /* @__PURE__ */ jsx(Card, { className: "p-4 border-l-4 border-l-yellow-500", children: /* @__PURE__ */ jsx(Typography, { variant: "body", children: entity.hint }) }),
10469
- isComplete && !won && /* @__PURE__ */ jsx(HStack, { justify: "center", children: /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleReset, children: t("negotiator.playAgain") }) })
10470
- ] }) });
10601
+ }
10602
+ );
10471
10603
  }
10472
10604
  NegotiatorBoard.displayName = "NegotiatorBoard";
10473
10605
  function SimulationCanvas({
@@ -11289,10 +11421,10 @@ var Chart = ({
11289
11421
  const handleAction = useCallback(
11290
11422
  (action) => {
11291
11423
  if (action.event) {
11292
- eventBus.emit(`UI:${action.event}`, { entity });
11424
+ eventBus.emit(`UI:${action.event}`, {});
11293
11425
  }
11294
11426
  },
11295
- [eventBus, entity]
11427
+ [eventBus]
11296
11428
  );
11297
11429
  const normalizedData = useMemo(() => {
11298
11430
  if (simpleData) return simpleData;
@@ -11392,10 +11524,10 @@ var Meter = ({
11392
11524
  const handleAction = useCallback(
11393
11525
  (action) => {
11394
11526
  if (action.event) {
11395
- eventBus.emit(`UI:${action.event}`, { entity, value });
11527
+ eventBus.emit(`UI:${action.event}`, { value });
11396
11528
  }
11397
11529
  },
11398
- [eventBus, entity, value]
11530
+ [eventBus, value]
11399
11531
  );
11400
11532
  const percentage = useMemo(() => {
11401
11533
  const range = max - min;
@@ -11580,7 +11712,6 @@ var STATUS_STYLES3 = {
11580
11712
  var Timeline = ({
11581
11713
  title,
11582
11714
  items: propItems,
11583
- data,
11584
11715
  fields,
11585
11716
  itemActions,
11586
11717
  entity,
@@ -11588,19 +11719,12 @@ var Timeline = ({
11588
11719
  error,
11589
11720
  className
11590
11721
  }) => {
11591
- const eventBus = useEventBus();
11592
- const handleAction = useCallback(
11593
- (action, item) => {
11594
- if (action.event) {
11595
- eventBus.emit(`UI:${action.event}`, { entity, row: item });
11596
- }
11597
- },
11598
- [eventBus, entity]
11599
- );
11722
+ const { t } = useTranslate();
11723
+ const entityData = Array.isArray(entity) ? entity : [];
11600
11724
  const items = React42__default.useMemo(() => {
11601
11725
  if (propItems) return propItems;
11602
- if (!data) return [];
11603
- return data.map((record, idx) => {
11726
+ if (entityData.length === 0) return [];
11727
+ return entityData.map((record, idx) => {
11604
11728
  const titleField = fields?.[0] || "title";
11605
11729
  const descField = fields?.[1] || "description";
11606
11730
  const dateField = fields?.find(
@@ -11617,7 +11741,7 @@ var Timeline = ({
11617
11741
  status: record[statusField] || "pending"
11618
11742
  };
11619
11743
  });
11620
- }, [propItems, data, fields]);
11744
+ }, [propItems, entityData, fields]);
11621
11745
  if (isLoading) {
11622
11746
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading timeline...", className });
11623
11747
  }
@@ -11677,12 +11801,12 @@ var Timeline = ({
11677
11801
  item.description && /* @__PURE__ */ jsx(Typography, { variant: "small", color: "secondary", children: item.description }),
11678
11802
  item.tags && item.tags.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: item.tags.map((tag, tagIdx) => /* @__PURE__ */ jsx(Badge, { variant: "default", children: tag }, tagIdx)) }),
11679
11803
  itemActions && itemActions.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", className: "mt-1", children: itemActions.map((action, actionIdx) => /* @__PURE__ */ jsx(
11680
- Badge,
11804
+ Box,
11681
11805
  {
11682
- variant: "default",
11806
+ action: action.event,
11807
+ actionPayload: { row: item },
11683
11808
  className: "cursor-pointer hover:opacity-80 transition-opacity",
11684
- onClick: () => handleAction(action, item),
11685
- children: action.label
11809
+ children: /* @__PURE__ */ jsx(Badge, { variant: "default", children: action.label })
11686
11810
  },
11687
11811
  actionIdx
11688
11812
  )) })
@@ -11707,11 +11831,10 @@ var ASPECT_CLASSES = {
11707
11831
  var MediaGallery = ({
11708
11832
  title,
11709
11833
  items: propItems,
11710
- data,
11711
11834
  columns = 3,
11712
11835
  selectable = false,
11713
11836
  selectedItems = [],
11714
- onSelectionChange,
11837
+ selectionEvent = "SELECTION_CHANGE",
11715
11838
  showUpload = false,
11716
11839
  actions,
11717
11840
  aspectRatio = "square",
@@ -11721,42 +11844,35 @@ var MediaGallery = ({
11721
11844
  className
11722
11845
  }) => {
11723
11846
  const eventBus = useEventBus();
11847
+ const { t } = useTranslate();
11724
11848
  const [lightboxItem, setLightboxItem] = useState(null);
11725
- const handleAction = useCallback(
11726
- (action) => {
11727
- if (action.event) {
11728
- eventBus.emit(`UI:${action.event}`, { entity });
11729
- }
11730
- },
11731
- [eventBus, entity]
11732
- );
11849
+ const closeLightbox = useCallback(() => setLightboxItem(null), []);
11850
+ useEventListener("UI:LIGHTBOX_CLOSE", closeLightbox);
11733
11851
  const handleItemClick = useCallback(
11734
11852
  (item) => {
11735
11853
  if (selectable) {
11736
11854
  const isSelected = selectedItems.includes(item.id);
11737
11855
  const newSelection = isSelected ? selectedItems.filter((id) => id !== item.id) : [...selectedItems, item.id];
11738
- onSelectionChange?.(newSelection);
11856
+ eventBus.emit(`UI:${selectionEvent}`, { selection: newSelection });
11739
11857
  } else {
11740
11858
  setLightboxItem(item);
11741
11859
  }
11742
- eventBus.emit("UI:MEDIA_SELECT", { entity, row: item });
11860
+ eventBus.emit("UI:MEDIA_SELECT", { row: item });
11743
11861
  },
11744
- [selectable, selectedItems, onSelectionChange, eventBus, entity]
11862
+ [selectable, selectedItems, selectionEvent, eventBus]
11745
11863
  );
11746
- const handleUpload = useCallback(() => {
11747
- eventBus.emit("UI:MEDIA_UPLOAD", { entity });
11748
- }, [eventBus, entity]);
11864
+ const entityData = Array.isArray(entity) ? entity : [];
11749
11865
  const items = React42__default.useMemo(() => {
11750
11866
  if (propItems) return propItems;
11751
- if (!data) return [];
11752
- return data.map((record, idx) => ({
11867
+ if (entityData.length === 0) return [];
11868
+ return entityData.map((record, idx) => ({
11753
11869
  id: String(record.id ?? idx),
11754
11870
  src: String(record.src ?? record.url ?? record.image ?? ""),
11755
11871
  alt: record.alt ? String(record.alt) : void 0,
11756
11872
  thumbnail: record.thumbnail ? String(record.thumbnail) : void 0,
11757
11873
  caption: record.caption ? String(record.caption) : record.title ? String(record.title) : void 0
11758
11874
  }));
11759
- }, [propItems, data]);
11875
+ }, [propItems, entityData]);
11760
11876
  if (isLoading) {
11761
11877
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading media...", className });
11762
11878
  }
@@ -11792,17 +11908,16 @@ var MediaGallery = ({
11792
11908
  variant: "secondary",
11793
11909
  size: "sm",
11794
11910
  icon: Upload,
11795
- onClick: handleUpload,
11911
+ action: "MEDIA_UPLOAD",
11796
11912
  children: "Upload"
11797
11913
  }
11798
11914
  ),
11799
11915
  actions?.map((action, idx) => /* @__PURE__ */ jsx(
11800
- Badge,
11916
+ Box,
11801
11917
  {
11802
- variant: "default",
11918
+ action: action.event,
11803
11919
  className: "cursor-pointer hover:opacity-80 transition-opacity",
11804
- onClick: () => handleAction(action),
11805
- children: action.label
11920
+ children: /* @__PURE__ */ jsx(Badge, { variant: "default", children: action.label })
11806
11921
  },
11807
11922
  idx
11808
11923
  ))
@@ -11872,7 +11987,7 @@ var MediaGallery = ({
11872
11987
  Box,
11873
11988
  {
11874
11989
  className: "fixed inset-0 z-50 bg-[var(--color-background)]/80 backdrop-blur-sm flex items-center justify-center",
11875
- onClick: () => setLightboxItem(null),
11990
+ action: "LIGHTBOX_CLOSE",
11876
11991
  children: /* @__PURE__ */ jsxs(
11877
11992
  VStack,
11878
11993
  {
@@ -11887,7 +12002,7 @@ var MediaGallery = ({
11887
12002
  variant: "ghost",
11888
12003
  size: "sm",
11889
12004
  icon: X,
11890
- onClick: () => setLightboxItem(null),
12005
+ action: "LIGHTBOX_CLOSE",
11891
12006
  className: "text-white hover:bg-white/20"
11892
12007
  }
11893
12008
  ) }),
@@ -12004,15 +12119,15 @@ var SignaturePad = ({
12004
12119
  setHasSignature(false);
12005
12120
  onChange?.(null);
12006
12121
  if (clearEvent) {
12007
- eventBus.emit(`UI:${clearEvent}`, { entity });
12122
+ eventBus.emit(`UI:${clearEvent}`, {});
12008
12123
  }
12009
- }, [onChange, clearEvent, eventBus, entity]);
12124
+ }, [onChange, clearEvent, eventBus]);
12010
12125
  const confirmSignature = useCallback(() => {
12011
12126
  const dataUrl = canvasRef.current?.toDataURL("image/png") ?? null;
12012
12127
  if (signEvent) {
12013
- eventBus.emit(`UI:${signEvent}`, { entity, signature: dataUrl });
12128
+ eventBus.emit(`UI:${signEvent}`, { signature: dataUrl });
12014
12129
  }
12015
- }, [signEvent, eventBus, entity]);
12130
+ }, [signEvent, eventBus]);
12016
12131
  if (isLoading) {
12017
12132
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading signature pad...", className });
12018
12133
  }
@@ -12109,34 +12224,34 @@ var DocumentViewer = ({
12109
12224
  const handleAction = useCallback(
12110
12225
  (action) => {
12111
12226
  if (action.event) {
12112
- eventBus.emit(`UI:${action.event}`, { entity, page: currentPage });
12227
+ eventBus.emit(`UI:${action.event}`, { page: currentPage });
12113
12228
  }
12114
12229
  },
12115
- [eventBus, entity, currentPage]
12230
+ [eventBus, currentPage]
12116
12231
  );
12117
12232
  const handleDownload = useCallback(() => {
12118
12233
  const downloadSrc = documents?.[activeDocIndex]?.src ?? src;
12119
12234
  if (downloadSrc) {
12120
- eventBus.emit("UI:DOCUMENT_DOWNLOAD", { entity, src: downloadSrc });
12235
+ eventBus.emit("UI:DOCUMENT_DOWNLOAD", { src: downloadSrc });
12121
12236
  window.open(downloadSrc, "_blank");
12122
12237
  }
12123
- }, [documents, activeDocIndex, src, eventBus, entity]);
12238
+ }, [documents, activeDocIndex, src, eventBus]);
12124
12239
  const handlePrint = useCallback(() => {
12125
- eventBus.emit("UI:DOCUMENT_PRINT", { entity });
12240
+ eventBus.emit("UI:DOCUMENT_PRINT", {});
12126
12241
  window.print();
12127
- }, [eventBus, entity]);
12242
+ }, [eventBus]);
12128
12243
  const handleZoomIn = useCallback(() => setZoom((z) => Math.min(z + 25, 200)), []);
12129
12244
  const handleZoomOut = useCallback(() => setZoom((z) => Math.max(z - 25, 50)), []);
12130
12245
  const handlePagePrev = useCallback(() => {
12131
12246
  setCurrentPage((p2) => Math.max(p2 - 1, 1));
12132
- eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { entity, page: currentPage - 1 });
12133
- }, [eventBus, entity, currentPage]);
12247
+ eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { page: currentPage - 1 });
12248
+ }, [eventBus, currentPage]);
12134
12249
  const handlePageNext = useCallback(() => {
12135
12250
  if (totalPages) {
12136
12251
  setCurrentPage((p2) => Math.min(p2 + 1, totalPages));
12137
- eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { entity, page: currentPage + 1 });
12252
+ eventBus.emit("UI:DOCUMENT_PAGE_CHANGE", { page: currentPage + 1 });
12138
12253
  }
12139
- }, [totalPages, eventBus, entity, currentPage]);
12254
+ }, [totalPages, eventBus, currentPage]);
12140
12255
  if (isLoading) {
12141
12256
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading document...", className });
12142
12257
  }
@@ -12310,19 +12425,19 @@ var GraphCanvas = ({
12310
12425
  const handleAction = useCallback(
12311
12426
  (action) => {
12312
12427
  if (action.event) {
12313
- eventBus.emit(`UI:${action.event}`, { entity });
12428
+ eventBus.emit(`UI:${action.event}`, {});
12314
12429
  }
12315
12430
  },
12316
- [eventBus, entity]
12431
+ [eventBus]
12317
12432
  );
12318
12433
  const handleNodeClick = useCallback(
12319
12434
  (node) => {
12320
12435
  if (nodeClickEvent) {
12321
- eventBus.emit(`UI:${nodeClickEvent}`, { entity, row: node });
12436
+ eventBus.emit(`UI:${nodeClickEvent}`, { row: node });
12322
12437
  }
12323
12438
  onNodeClick?.(node);
12324
12439
  },
12325
- [nodeClickEvent, eventBus, entity, onNodeClick]
12440
+ [nodeClickEvent, eventBus, onNodeClick]
12326
12441
  );
12327
12442
  const groups = useMemo(
12328
12443
  () => [...new Set(propNodes.map((n) => n.group).filter(Boolean))],
@@ -12634,10 +12749,10 @@ var CodeViewer = ({
12634
12749
  const handleAction = useCallback(
12635
12750
  (action) => {
12636
12751
  if (action.event) {
12637
- eventBus.emit(`UI:${action.event}`, { entity });
12752
+ eventBus.emit(`UI:${action.event}`, {});
12638
12753
  }
12639
12754
  },
12640
- [eventBus, entity]
12755
+ [eventBus]
12641
12756
  );
12642
12757
  const activeFile = files?.[activeFileIndex];
12643
12758
  const activeCode = activeFile?.code ?? code ?? "";
@@ -12654,11 +12769,11 @@ var CodeViewer = ({
12654
12769
  try {
12655
12770
  await navigator.clipboard.writeText(activeCode);
12656
12771
  setCopied(true);
12657
- eventBus.emit("UI:CODE_COPY", { entity, language: activeLanguage });
12772
+ eventBus.emit("UI:CODE_COPY", { language: activeLanguage });
12658
12773
  setTimeout(() => setCopied(false), 2e3);
12659
12774
  } catch {
12660
12775
  }
12661
- }, [activeCode, eventBus, entity, activeLanguage]);
12776
+ }, [activeCode, eventBus, activeLanguage]);
12662
12777
  const tabItems = files?.map((file, idx) => ({
12663
12778
  id: `file-${idx}`,
12664
12779
  label: file.label,