@almadar/ui 5.145.0 → 5.146.1

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.
@@ -24234,6 +24234,7 @@ var init_CodeRunnerPanel = __esm({
24234
24234
  const [output, setOutput] = React94.useState(null);
24235
24235
  const [error, setError] = React94.useState(null);
24236
24236
  const [isRunning, setIsRunning] = React94.useState(false);
24237
+ const [copied, setCopied] = React94.useState(false);
24237
24238
  const handleRun = React94.useCallback(async () => {
24238
24239
  if (!onRun) return;
24239
24240
  setIsRunning(true);
@@ -24256,63 +24257,75 @@ var init_CodeRunnerPanel = __esm({
24256
24257
  setOutput(null);
24257
24258
  setError(null);
24258
24259
  }, [initialCode]);
24260
+ const handleCopy = React94.useCallback(async () => {
24261
+ try {
24262
+ await navigator.clipboard.writeText(code);
24263
+ setCopied(true);
24264
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
24265
+ setTimeout(() => setCopied(false), 2e3);
24266
+ } catch {
24267
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
24268
+ }
24269
+ }, [code, language, eventBus]);
24259
24270
  if (!runnable || !onRun) {
24260
24271
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { language, code }) });
24261
24272
  }
24262
24273
  const hasOutput = output !== null || error !== null;
24263
24274
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("space-y-3", className), children: [
24264
- /* @__PURE__ */ jsxRuntime.jsx(
24265
- CodeBlock,
24266
- {
24267
- language,
24268
- code,
24269
- editable: true,
24270
- onChange: setCode,
24271
- showLanguageBadge: true,
24272
- showCopyButton: true
24273
- }
24274
- ),
24275
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "between", children: [
24276
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
24277
- /* @__PURE__ */ jsxRuntime.jsx(
24278
- Button,
24279
- {
24280
- variant: "primary",
24281
- size: "sm",
24282
- onClick: handleRun,
24283
- disabled: isRunning,
24284
- className: "min-w-[5rem]",
24285
- children: isRunning ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
24286
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16, className: "animate-spin" }),
24287
- t("common.loading")
24288
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
24289
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Play, { size: 16 }),
24290
- "Run"
24291
- ] })
24292
- }
24293
- ),
24294
- /* @__PURE__ */ jsxRuntime.jsx(
24295
- Button,
24296
- {
24297
- variant: "secondary",
24298
- size: "sm",
24299
- onClick: handleReset,
24300
- disabled: isRunning,
24301
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
24302
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16 }),
24303
- "Reset"
24304
- ] })
24305
- }
24306
- )
24307
- ] }),
24308
- output && /* @__PURE__ */ jsxRuntime.jsxs(
24309
- Badge,
24275
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
24276
+ /* @__PURE__ */ jsxRuntime.jsx(
24277
+ CodeBlock,
24310
24278
  {
24311
- variant: output.exitCode === 0 ? "success" : "danger",
24312
- size: "sm",
24279
+ language,
24280
+ code,
24281
+ editable: true,
24282
+ onChange: setCode,
24283
+ showLanguageBadge: true,
24284
+ showCopyButton: false,
24285
+ maxHeight: "100%"
24286
+ }
24287
+ ),
24288
+ /* @__PURE__ */ jsxRuntime.jsxs(
24289
+ HStack,
24290
+ {
24291
+ gap: "xs",
24292
+ align: "center",
24293
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
24313
24294
  children: [
24314
- "Exit ",
24315
- output.exitCode
24295
+ /* @__PURE__ */ jsxRuntime.jsx(
24296
+ Button,
24297
+ {
24298
+ variant: "ghost",
24299
+ size: "sm",
24300
+ onClick: handleCopy,
24301
+ icon: copied ? LucideIcons2.Check : LucideIcons2.Copy,
24302
+ "aria-label": t("common.copy"),
24303
+ className: copied ? "text-success" : ""
24304
+ }
24305
+ ),
24306
+ /* @__PURE__ */ jsxRuntime.jsx(
24307
+ Button,
24308
+ {
24309
+ variant: "ghost",
24310
+ size: "sm",
24311
+ onClick: handleReset,
24312
+ disabled: isRunning,
24313
+ icon: LucideIcons2.RotateCcw,
24314
+ "aria-label": "Reset"
24315
+ }
24316
+ ),
24317
+ /* @__PURE__ */ jsxRuntime.jsx(
24318
+ Button,
24319
+ {
24320
+ variant: "primary",
24321
+ size: "sm",
24322
+ onClick: handleRun,
24323
+ disabled: isRunning,
24324
+ icon: isRunning ? LucideIcons2.RotateCcw : LucideIcons2.Play,
24325
+ className: isRunning ? "[&_svg]:animate-spin" : "",
24326
+ children: isRunning ? t("common.loading") : "Run"
24327
+ }
24328
+ )
24316
24329
  ]
24317
24330
  }
24318
24331
  )
@@ -24326,7 +24339,18 @@ var init_CodeRunnerPanel = __esm({
24326
24339
  className: "px-3 py-2 bg-card border-b border-border",
24327
24340
  children: [
24328
24341
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Terminal, { size: 16, className: "text-muted-foreground" }),
24329
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
24342
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
24343
+ output && /* @__PURE__ */ jsxRuntime.jsxs(
24344
+ Badge,
24345
+ {
24346
+ variant: output.exitCode === 0 ? "success" : "danger",
24347
+ size: "sm",
24348
+ children: [
24349
+ "Exit ",
24350
+ output.exitCode
24351
+ ]
24352
+ }
24353
+ )
24330
24354
  ]
24331
24355
  }
24332
24356
  ),
package/dist/avl/index.js CHANGED
@@ -24158,6 +24158,7 @@ var init_CodeRunnerPanel = __esm({
24158
24158
  const [output, setOutput] = useState(null);
24159
24159
  const [error, setError] = useState(null);
24160
24160
  const [isRunning, setIsRunning] = useState(false);
24161
+ const [copied, setCopied] = useState(false);
24161
24162
  const handleRun = useCallback(async () => {
24162
24163
  if (!onRun) return;
24163
24164
  setIsRunning(true);
@@ -24180,63 +24181,75 @@ var init_CodeRunnerPanel = __esm({
24180
24181
  setOutput(null);
24181
24182
  setError(null);
24182
24183
  }, [initialCode]);
24184
+ const handleCopy = useCallback(async () => {
24185
+ try {
24186
+ await navigator.clipboard.writeText(code);
24187
+ setCopied(true);
24188
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
24189
+ setTimeout(() => setCopied(false), 2e3);
24190
+ } catch {
24191
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
24192
+ }
24193
+ }, [code, language, eventBus]);
24183
24194
  if (!runnable || !onRun) {
24184
24195
  return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsx(CodeBlock, { language, code }) });
24185
24196
  }
24186
24197
  const hasOutput = output !== null || error !== null;
24187
24198
  return /* @__PURE__ */ jsxs(Box, { className: cn("space-y-3", className), children: [
24188
- /* @__PURE__ */ jsx(
24189
- CodeBlock,
24190
- {
24191
- language,
24192
- code,
24193
- editable: true,
24194
- onChange: setCode,
24195
- showLanguageBadge: true,
24196
- showCopyButton: true
24197
- }
24198
- ),
24199
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "between", children: [
24200
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
24201
- /* @__PURE__ */ jsx(
24202
- Button,
24203
- {
24204
- variant: "primary",
24205
- size: "sm",
24206
- onClick: handleRun,
24207
- disabled: isRunning,
24208
- className: "min-w-[5rem]",
24209
- children: isRunning ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
24210
- /* @__PURE__ */ jsx(RotateCcw, { size: 16, className: "animate-spin" }),
24211
- t("common.loading")
24212
- ] }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
24213
- /* @__PURE__ */ jsx(Play, { size: 16 }),
24214
- "Run"
24215
- ] })
24216
- }
24217
- ),
24218
- /* @__PURE__ */ jsx(
24219
- Button,
24220
- {
24221
- variant: "secondary",
24222
- size: "sm",
24223
- onClick: handleReset,
24224
- disabled: isRunning,
24225
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
24226
- /* @__PURE__ */ jsx(RotateCcw, { size: 16 }),
24227
- "Reset"
24228
- ] })
24229
- }
24230
- )
24231
- ] }),
24232
- output && /* @__PURE__ */ jsxs(
24233
- Badge,
24199
+ /* @__PURE__ */ jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
24200
+ /* @__PURE__ */ jsx(
24201
+ CodeBlock,
24234
24202
  {
24235
- variant: output.exitCode === 0 ? "success" : "danger",
24236
- size: "sm",
24203
+ language,
24204
+ code,
24205
+ editable: true,
24206
+ onChange: setCode,
24207
+ showLanguageBadge: true,
24208
+ showCopyButton: false,
24209
+ maxHeight: "100%"
24210
+ }
24211
+ ),
24212
+ /* @__PURE__ */ jsxs(
24213
+ HStack,
24214
+ {
24215
+ gap: "xs",
24216
+ align: "center",
24217
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
24237
24218
  children: [
24238
- "Exit ",
24239
- output.exitCode
24219
+ /* @__PURE__ */ jsx(
24220
+ Button,
24221
+ {
24222
+ variant: "ghost",
24223
+ size: "sm",
24224
+ onClick: handleCopy,
24225
+ icon: copied ? Check : Copy,
24226
+ "aria-label": t("common.copy"),
24227
+ className: copied ? "text-success" : ""
24228
+ }
24229
+ ),
24230
+ /* @__PURE__ */ jsx(
24231
+ Button,
24232
+ {
24233
+ variant: "ghost",
24234
+ size: "sm",
24235
+ onClick: handleReset,
24236
+ disabled: isRunning,
24237
+ icon: RotateCcw,
24238
+ "aria-label": "Reset"
24239
+ }
24240
+ ),
24241
+ /* @__PURE__ */ jsx(
24242
+ Button,
24243
+ {
24244
+ variant: "primary",
24245
+ size: "sm",
24246
+ onClick: handleRun,
24247
+ disabled: isRunning,
24248
+ icon: isRunning ? RotateCcw : Play,
24249
+ className: isRunning ? "[&_svg]:animate-spin" : "",
24250
+ children: isRunning ? t("common.loading") : "Run"
24251
+ }
24252
+ )
24240
24253
  ]
24241
24254
  }
24242
24255
  )
@@ -24250,7 +24263,18 @@ var init_CodeRunnerPanel = __esm({
24250
24263
  className: "px-3 py-2 bg-card border-b border-border",
24251
24264
  children: [
24252
24265
  /* @__PURE__ */ jsx(Terminal, { size: 16, className: "text-muted-foreground" }),
24253
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
24266
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
24267
+ output && /* @__PURE__ */ jsxs(
24268
+ Badge,
24269
+ {
24270
+ variant: output.exitCode === 0 ? "success" : "danger",
24271
+ size: "sm",
24272
+ children: [
24273
+ "Exit ",
24274
+ output.exitCode
24275
+ ]
24276
+ }
24277
+ )
24254
24278
  ]
24255
24279
  }
24256
24280
  ),
@@ -19346,6 +19346,7 @@ var init_CodeRunnerPanel = __esm({
19346
19346
  const [output, setOutput] = React77.useState(null);
19347
19347
  const [error, setError] = React77.useState(null);
19348
19348
  const [isRunning, setIsRunning] = React77.useState(false);
19349
+ const [copied, setCopied] = React77.useState(false);
19349
19350
  const handleRun = React77.useCallback(async () => {
19350
19351
  if (!onRun) return;
19351
19352
  setIsRunning(true);
@@ -19368,63 +19369,75 @@ var init_CodeRunnerPanel = __esm({
19368
19369
  setOutput(null);
19369
19370
  setError(null);
19370
19371
  }, [initialCode]);
19372
+ const handleCopy = React77.useCallback(async () => {
19373
+ try {
19374
+ await navigator.clipboard.writeText(code);
19375
+ setCopied(true);
19376
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
19377
+ setTimeout(() => setCopied(false), 2e3);
19378
+ } catch {
19379
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
19380
+ }
19381
+ }, [code, language, eventBus]);
19371
19382
  if (!runnable || !onRun) {
19372
19383
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className, children: /* @__PURE__ */ jsxRuntime.jsx(exports.CodeBlock, { language, code }) });
19373
19384
  }
19374
19385
  const hasOutput = output !== null || error !== null;
19375
19386
  return /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: cn("space-y-3", className), children: [
19376
- /* @__PURE__ */ jsxRuntime.jsx(
19377
- exports.CodeBlock,
19378
- {
19379
- language,
19380
- code,
19381
- editable: true,
19382
- onChange: setCode,
19383
- showLanguageBadge: true,
19384
- showCopyButton: true
19385
- }
19386
- ),
19387
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", justify: "between", children: [
19388
- /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", children: [
19389
- /* @__PURE__ */ jsxRuntime.jsx(
19390
- exports.Button,
19391
- {
19392
- variant: "primary",
19393
- size: "sm",
19394
- onClick: handleRun,
19395
- disabled: isRunning,
19396
- className: "min-w-[5rem]",
19397
- children: isRunning ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
19398
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16, className: "animate-spin" }),
19399
- t("common.loading")
19400
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
19401
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Play, { size: 16 }),
19402
- "Run"
19403
- ] })
19404
- }
19405
- ),
19406
- /* @__PURE__ */ jsxRuntime.jsx(
19407
- exports.Button,
19408
- {
19409
- variant: "secondary",
19410
- size: "sm",
19411
- onClick: handleReset,
19412
- disabled: isRunning,
19413
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
19414
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16 }),
19415
- "Reset"
19416
- ] })
19417
- }
19418
- )
19419
- ] }),
19420
- output && /* @__PURE__ */ jsxRuntime.jsxs(
19421
- exports.Badge,
19387
+ /* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "group relative", style: { height: 360 }, children: [
19388
+ /* @__PURE__ */ jsxRuntime.jsx(
19389
+ exports.CodeBlock,
19422
19390
  {
19423
- variant: output.exitCode === 0 ? "success" : "danger",
19424
- size: "sm",
19391
+ language,
19392
+ code,
19393
+ editable: true,
19394
+ onChange: setCode,
19395
+ showLanguageBadge: true,
19396
+ showCopyButton: false,
19397
+ maxHeight: "100%"
19398
+ }
19399
+ ),
19400
+ /* @__PURE__ */ jsxRuntime.jsxs(
19401
+ exports.HStack,
19402
+ {
19403
+ gap: "xs",
19404
+ align: "center",
19405
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
19425
19406
  children: [
19426
- "Exit ",
19427
- output.exitCode
19407
+ /* @__PURE__ */ jsxRuntime.jsx(
19408
+ exports.Button,
19409
+ {
19410
+ variant: "ghost",
19411
+ size: "sm",
19412
+ onClick: handleCopy,
19413
+ icon: copied ? LucideIcons2.Check : LucideIcons2.Copy,
19414
+ "aria-label": t("common.copy"),
19415
+ className: copied ? "text-success" : ""
19416
+ }
19417
+ ),
19418
+ /* @__PURE__ */ jsxRuntime.jsx(
19419
+ exports.Button,
19420
+ {
19421
+ variant: "ghost",
19422
+ size: "sm",
19423
+ onClick: handleReset,
19424
+ disabled: isRunning,
19425
+ icon: LucideIcons2.RotateCcw,
19426
+ "aria-label": "Reset"
19427
+ }
19428
+ ),
19429
+ /* @__PURE__ */ jsxRuntime.jsx(
19430
+ exports.Button,
19431
+ {
19432
+ variant: "primary",
19433
+ size: "sm",
19434
+ onClick: handleRun,
19435
+ disabled: isRunning,
19436
+ icon: isRunning ? LucideIcons2.RotateCcw : LucideIcons2.Play,
19437
+ className: isRunning ? "[&_svg]:animate-spin" : "",
19438
+ children: isRunning ? t("common.loading") : "Run"
19439
+ }
19440
+ )
19428
19441
  ]
19429
19442
  }
19430
19443
  )
@@ -19438,7 +19451,18 @@ var init_CodeRunnerPanel = __esm({
19438
19451
  className: "px-3 py-2 bg-card border-b border-border",
19439
19452
  children: [
19440
19453
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Terminal, { size: 16, className: "text-muted-foreground" }),
19441
- /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
19454
+ /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
19455
+ output && /* @__PURE__ */ jsxRuntime.jsxs(
19456
+ exports.Badge,
19457
+ {
19458
+ variant: output.exitCode === 0 ? "success" : "danger",
19459
+ size: "sm",
19460
+ children: [
19461
+ "Exit ",
19462
+ output.exitCode
19463
+ ]
19464
+ }
19465
+ )
19442
19466
  ]
19443
19467
  }
19444
19468
  ),
@@ -39325,7 +39349,7 @@ function parseLessonSegments(lesson) {
39325
39349
  content = content.replace(connectResult.fullMatch, "").trim();
39326
39350
  }
39327
39351
  const tagRegex = new RegExp(
39328
- '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>chart|simulation|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
39352
+ '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability|freeform)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
39329
39353
  "gi"
39330
39354
  );
39331
39355
  let lastIndex = 0;
@@ -9506,7 +9506,7 @@ declare function parseMarkdownWithCodeBlocks(content: string): MixedSegment[];
9506
9506
  * until the next recognised tag, a section heading (`\n\n#`), or end-of-input.
9507
9507
  */
9508
9508
 
9509
- type InteractiveOrbitalType = 'chart' | 'simulation' | 'math' | 'physics' | 'biology' | 'chemistry' | 'probability';
9509
+ type InteractiveOrbitalType = 'algorithms' | 'math' | 'physics' | 'biology' | 'chemistry' | 'probability' | 'freeform';
9510
9510
  type LessonSegment = MixedSegment | {
9511
9511
  type: 'quiz';
9512
9512
  question: string;
@@ -9506,7 +9506,7 @@ declare function parseMarkdownWithCodeBlocks(content: string): MixedSegment[];
9506
9506
  * until the next recognised tag, a section heading (`\n\n#`), or end-of-input.
9507
9507
  */
9508
9508
 
9509
- type InteractiveOrbitalType = 'chart' | 'simulation' | 'math' | 'physics' | 'biology' | 'chemistry' | 'probability';
9509
+ type InteractiveOrbitalType = 'algorithms' | 'math' | 'physics' | 'biology' | 'chemistry' | 'probability' | 'freeform';
9510
9510
  type LessonSegment = MixedSegment | {
9511
9511
  type: 'quiz';
9512
9512
  question: string;
@@ -7,7 +7,7 @@ import { EventBusContext, useTraitScopeChain, useCurrentPagePath, useGameAudioCo
7
7
  export { GameAudioContext, GameAudioProvider, useGameAudioContext } from '@almadar/ui/providers';
8
8
  import { createLogger, isLogLevelEnabled } from '@almadar/logger';
9
9
  import * as LucideIcons2 from 'lucide-react';
10
- import { X, List, Printer, ChevronRight, ChevronLeft, RotateCcw, Play, Terminal, CheckCircle, XCircle, ChevronDown, Search, ChevronUp, MoreHorizontal, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, Check, Copy, HelpCircle, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, GitBranch, Plus, ArrowRight, Trash, ArrowLeft, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2, Tag, User, DollarSign } from 'lucide-react';
10
+ import { X, List, Printer, ChevronRight, ChevronLeft, Check, Copy, RotateCcw, Play, Terminal, CheckCircle, XCircle, ChevronDown, Search, ChevronUp, MoreHorizontal, Package, Calendar, Pencil, Eye, Image as Image$1, Upload, ZoomIn, TrendingUp, TrendingDown, Minus, AlertCircle, Circle, Clock, CheckCircle2, Loader2, Code, FileText, WrapText, HelpCircle, Type, Heading1, Heading2, Heading3, ListOrdered, Quote, GitBranch, Plus, ArrowRight, Trash, ArrowLeft, Menu as Menu$1, AlertTriangle, Trash2, Eraser, ZoomOut, Download, Lightbulb, PauseCircle, Link2, Tag, User, DollarSign } from 'lucide-react';
11
11
  import { useTranslate } from '@almadar/ui/hooks';
12
12
  import { useUISlots, useTheme } from '@almadar/ui/context';
13
13
  import { evaluate, createMinimalContext } from '@almadar/evaluator';
@@ -19271,6 +19271,7 @@ var init_CodeRunnerPanel = __esm({
19271
19271
  const [output, setOutput] = useState(null);
19272
19272
  const [error, setError] = useState(null);
19273
19273
  const [isRunning, setIsRunning] = useState(false);
19274
+ const [copied, setCopied] = useState(false);
19274
19275
  const handleRun = useCallback(async () => {
19275
19276
  if (!onRun) return;
19276
19277
  setIsRunning(true);
@@ -19293,63 +19294,75 @@ var init_CodeRunnerPanel = __esm({
19293
19294
  setOutput(null);
19294
19295
  setError(null);
19295
19296
  }, [initialCode]);
19297
+ const handleCopy = useCallback(async () => {
19298
+ try {
19299
+ await navigator.clipboard.writeText(code);
19300
+ setCopied(true);
19301
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
19302
+ setTimeout(() => setCopied(false), 2e3);
19303
+ } catch {
19304
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
19305
+ }
19306
+ }, [code, language, eventBus]);
19296
19307
  if (!runnable || !onRun) {
19297
19308
  return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsx(CodeBlock, { language, code }) });
19298
19309
  }
19299
19310
  const hasOutput = output !== null || error !== null;
19300
19311
  return /* @__PURE__ */ jsxs(Box, { className: cn("space-y-3", className), children: [
19301
- /* @__PURE__ */ jsx(
19302
- CodeBlock,
19303
- {
19304
- language,
19305
- code,
19306
- editable: true,
19307
- onChange: setCode,
19308
- showLanguageBadge: true,
19309
- showCopyButton: true
19310
- }
19311
- ),
19312
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "between", children: [
19313
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
19314
- /* @__PURE__ */ jsx(
19315
- Button,
19316
- {
19317
- variant: "primary",
19318
- size: "sm",
19319
- onClick: handleRun,
19320
- disabled: isRunning,
19321
- className: "min-w-[5rem]",
19322
- children: isRunning ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
19323
- /* @__PURE__ */ jsx(RotateCcw, { size: 16, className: "animate-spin" }),
19324
- t("common.loading")
19325
- ] }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
19326
- /* @__PURE__ */ jsx(Play, { size: 16 }),
19327
- "Run"
19328
- ] })
19329
- }
19330
- ),
19331
- /* @__PURE__ */ jsx(
19332
- Button,
19333
- {
19334
- variant: "secondary",
19335
- size: "sm",
19336
- onClick: handleReset,
19337
- disabled: isRunning,
19338
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
19339
- /* @__PURE__ */ jsx(RotateCcw, { size: 16 }),
19340
- "Reset"
19341
- ] })
19342
- }
19343
- )
19344
- ] }),
19345
- output && /* @__PURE__ */ jsxs(
19346
- Badge,
19312
+ /* @__PURE__ */ jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
19313
+ /* @__PURE__ */ jsx(
19314
+ CodeBlock,
19347
19315
  {
19348
- variant: output.exitCode === 0 ? "success" : "danger",
19349
- size: "sm",
19316
+ language,
19317
+ code,
19318
+ editable: true,
19319
+ onChange: setCode,
19320
+ showLanguageBadge: true,
19321
+ showCopyButton: false,
19322
+ maxHeight: "100%"
19323
+ }
19324
+ ),
19325
+ /* @__PURE__ */ jsxs(
19326
+ HStack,
19327
+ {
19328
+ gap: "xs",
19329
+ align: "center",
19330
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
19350
19331
  children: [
19351
- "Exit ",
19352
- output.exitCode
19332
+ /* @__PURE__ */ jsx(
19333
+ Button,
19334
+ {
19335
+ variant: "ghost",
19336
+ size: "sm",
19337
+ onClick: handleCopy,
19338
+ icon: copied ? Check : Copy,
19339
+ "aria-label": t("common.copy"),
19340
+ className: copied ? "text-success" : ""
19341
+ }
19342
+ ),
19343
+ /* @__PURE__ */ jsx(
19344
+ Button,
19345
+ {
19346
+ variant: "ghost",
19347
+ size: "sm",
19348
+ onClick: handleReset,
19349
+ disabled: isRunning,
19350
+ icon: RotateCcw,
19351
+ "aria-label": "Reset"
19352
+ }
19353
+ ),
19354
+ /* @__PURE__ */ jsx(
19355
+ Button,
19356
+ {
19357
+ variant: "primary",
19358
+ size: "sm",
19359
+ onClick: handleRun,
19360
+ disabled: isRunning,
19361
+ icon: isRunning ? RotateCcw : Play,
19362
+ className: isRunning ? "[&_svg]:animate-spin" : "",
19363
+ children: isRunning ? t("common.loading") : "Run"
19364
+ }
19365
+ )
19353
19366
  ]
19354
19367
  }
19355
19368
  )
@@ -19363,7 +19376,18 @@ var init_CodeRunnerPanel = __esm({
19363
19376
  className: "px-3 py-2 bg-card border-b border-border",
19364
19377
  children: [
19365
19378
  /* @__PURE__ */ jsx(Terminal, { size: 16, className: "text-muted-foreground" }),
19366
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
19379
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
19380
+ output && /* @__PURE__ */ jsxs(
19381
+ Badge,
19382
+ {
19383
+ variant: output.exitCode === 0 ? "success" : "danger",
19384
+ size: "sm",
19385
+ children: [
19386
+ "Exit ",
19387
+ output.exitCode
19388
+ ]
19389
+ }
19390
+ )
19367
19391
  ]
19368
19392
  }
19369
19393
  ),
@@ -39250,7 +39274,7 @@ function parseLessonSegments(lesson) {
39250
39274
  content = content.replace(connectResult.fullMatch, "").trim();
39251
39275
  }
39252
39276
  const tagRegex = new RegExp(
39253
- '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>chart|simulation|math|physics|biology|chemistry|probability)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
39277
+ '(?<reflect><reflect>(?<reflectClosed>[\\s\\S]*?)<\\/reflect>)|(?<reflectUnclosed><reflect>(?<reflectOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<bloom><bloom\\s+level="(?<bloomLevel>remember|understand|apply|analyze|evaluate|create)">(?<bloomClosed>[\\s\\S]*?)<\\/bloom>)|(?<bloomUnclosed><bloom\\s+level="(?<bloomLevelUn>remember|understand|apply|analyze|evaluate|create)">(?<bloomOpen>[\\s\\S]*?)(?=<(?:activate|connect|reflect|bloom|prq|question|answer|visualize)|\\n\\n#|$))|(?<quiz><question>(?<quizQuestion>[\\s\\S]*?)<\\/question>\\s*<answer>(?<quizAnswer>[\\s\\S]*?)<\\/answer>)|(?<visualize><visualize\\s+type="(?<vizType>algorithms|math|physics|biology|chemistry|probability|freeform)"\\s+description="(?<vizDesc>[^"]*?)"\\s*\\/?>)',
39254
39278
  "gi"
39255
39279
  );
39256
39280
  let lastIndex = 0;
@@ -21969,6 +21969,7 @@ var init_CodeRunnerPanel = __esm({
21969
21969
  const [output, setOutput] = React87.useState(null);
21970
21970
  const [error, setError] = React87.useState(null);
21971
21971
  const [isRunning, setIsRunning] = React87.useState(false);
21972
+ const [copied, setCopied] = React87.useState(false);
21972
21973
  const handleRun = React87.useCallback(async () => {
21973
21974
  if (!onRun) return;
21974
21975
  setIsRunning(true);
@@ -21991,63 +21992,75 @@ var init_CodeRunnerPanel = __esm({
21991
21992
  setOutput(null);
21992
21993
  setError(null);
21993
21994
  }, [initialCode]);
21995
+ const handleCopy = React87.useCallback(async () => {
21996
+ try {
21997
+ await navigator.clipboard.writeText(code);
21998
+ setCopied(true);
21999
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
22000
+ setTimeout(() => setCopied(false), 2e3);
22001
+ } catch {
22002
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
22003
+ }
22004
+ }, [code, language, eventBus]);
21994
22005
  if (!runnable || !onRun) {
21995
22006
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { language, code }) });
21996
22007
  }
21997
22008
  const hasOutput = output !== null || error !== null;
21998
22009
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("space-y-3", className), children: [
21999
- /* @__PURE__ */ jsxRuntime.jsx(
22000
- CodeBlock,
22001
- {
22002
- language,
22003
- code,
22004
- editable: true,
22005
- onChange: setCode,
22006
- showLanguageBadge: true,
22007
- showCopyButton: true
22008
- }
22009
- ),
22010
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "between", children: [
22011
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
22012
- /* @__PURE__ */ jsxRuntime.jsx(
22013
- Button,
22014
- {
22015
- variant: "primary",
22016
- size: "sm",
22017
- onClick: handleRun,
22018
- disabled: isRunning,
22019
- className: "min-w-[5rem]",
22020
- children: isRunning ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
22021
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16, className: "animate-spin" }),
22022
- t("common.loading")
22023
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
22024
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Play, { size: 16 }),
22025
- "Run"
22026
- ] })
22027
- }
22028
- ),
22029
- /* @__PURE__ */ jsxRuntime.jsx(
22030
- Button,
22031
- {
22032
- variant: "secondary",
22033
- size: "sm",
22034
- onClick: handleReset,
22035
- disabled: isRunning,
22036
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
22037
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16 }),
22038
- "Reset"
22039
- ] })
22040
- }
22041
- )
22042
- ] }),
22043
- output && /* @__PURE__ */ jsxRuntime.jsxs(
22044
- Badge,
22010
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
22011
+ /* @__PURE__ */ jsxRuntime.jsx(
22012
+ CodeBlock,
22045
22013
  {
22046
- variant: output.exitCode === 0 ? "success" : "danger",
22047
- size: "sm",
22014
+ language,
22015
+ code,
22016
+ editable: true,
22017
+ onChange: setCode,
22018
+ showLanguageBadge: true,
22019
+ showCopyButton: false,
22020
+ maxHeight: "100%"
22021
+ }
22022
+ ),
22023
+ /* @__PURE__ */ jsxRuntime.jsxs(
22024
+ HStack,
22025
+ {
22026
+ gap: "xs",
22027
+ align: "center",
22028
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
22048
22029
  children: [
22049
- "Exit ",
22050
- output.exitCode
22030
+ /* @__PURE__ */ jsxRuntime.jsx(
22031
+ Button,
22032
+ {
22033
+ variant: "ghost",
22034
+ size: "sm",
22035
+ onClick: handleCopy,
22036
+ icon: copied ? LucideIcons2.Check : LucideIcons2.Copy,
22037
+ "aria-label": t("common.copy"),
22038
+ className: copied ? "text-success" : ""
22039
+ }
22040
+ ),
22041
+ /* @__PURE__ */ jsxRuntime.jsx(
22042
+ Button,
22043
+ {
22044
+ variant: "ghost",
22045
+ size: "sm",
22046
+ onClick: handleReset,
22047
+ disabled: isRunning,
22048
+ icon: LucideIcons2.RotateCcw,
22049
+ "aria-label": "Reset"
22050
+ }
22051
+ ),
22052
+ /* @__PURE__ */ jsxRuntime.jsx(
22053
+ Button,
22054
+ {
22055
+ variant: "primary",
22056
+ size: "sm",
22057
+ onClick: handleRun,
22058
+ disabled: isRunning,
22059
+ icon: isRunning ? LucideIcons2.RotateCcw : LucideIcons2.Play,
22060
+ className: isRunning ? "[&_svg]:animate-spin" : "",
22061
+ children: isRunning ? t("common.loading") : "Run"
22062
+ }
22063
+ )
22051
22064
  ]
22052
22065
  }
22053
22066
  )
@@ -22061,7 +22074,18 @@ var init_CodeRunnerPanel = __esm({
22061
22074
  className: "px-3 py-2 bg-card border-b border-border",
22062
22075
  children: [
22063
22076
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Terminal, { size: 16, className: "text-muted-foreground" }),
22064
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
22077
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
22078
+ output && /* @__PURE__ */ jsxRuntime.jsxs(
22079
+ Badge,
22080
+ {
22081
+ variant: output.exitCode === 0 ? "success" : "danger",
22082
+ size: "sm",
22083
+ children: [
22084
+ "Exit ",
22085
+ output.exitCode
22086
+ ]
22087
+ }
22088
+ )
22065
22089
  ]
22066
22090
  }
22067
22091
  ),
@@ -21895,6 +21895,7 @@ var init_CodeRunnerPanel = __esm({
21895
21895
  const [output, setOutput] = useState(null);
21896
21896
  const [error, setError] = useState(null);
21897
21897
  const [isRunning, setIsRunning] = useState(false);
21898
+ const [copied, setCopied] = useState(false);
21898
21899
  const handleRun = useCallback(async () => {
21899
21900
  if (!onRun) return;
21900
21901
  setIsRunning(true);
@@ -21917,63 +21918,75 @@ var init_CodeRunnerPanel = __esm({
21917
21918
  setOutput(null);
21918
21919
  setError(null);
21919
21920
  }, [initialCode]);
21921
+ const handleCopy = useCallback(async () => {
21922
+ try {
21923
+ await navigator.clipboard.writeText(code);
21924
+ setCopied(true);
21925
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
21926
+ setTimeout(() => setCopied(false), 2e3);
21927
+ } catch {
21928
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
21929
+ }
21930
+ }, [code, language, eventBus]);
21920
21931
  if (!runnable || !onRun) {
21921
21932
  return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsx(CodeBlock, { language, code }) });
21922
21933
  }
21923
21934
  const hasOutput = output !== null || error !== null;
21924
21935
  return /* @__PURE__ */ jsxs(Box, { className: cn("space-y-3", className), children: [
21925
- /* @__PURE__ */ jsx(
21926
- CodeBlock,
21927
- {
21928
- language,
21929
- code,
21930
- editable: true,
21931
- onChange: setCode,
21932
- showLanguageBadge: true,
21933
- showCopyButton: true
21934
- }
21935
- ),
21936
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "between", children: [
21937
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
21938
- /* @__PURE__ */ jsx(
21939
- Button,
21940
- {
21941
- variant: "primary",
21942
- size: "sm",
21943
- onClick: handleRun,
21944
- disabled: isRunning,
21945
- className: "min-w-[5rem]",
21946
- children: isRunning ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
21947
- /* @__PURE__ */ jsx(RotateCcw, { size: 16, className: "animate-spin" }),
21948
- t("common.loading")
21949
- ] }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
21950
- /* @__PURE__ */ jsx(Play, { size: 16 }),
21951
- "Run"
21952
- ] })
21953
- }
21954
- ),
21955
- /* @__PURE__ */ jsx(
21956
- Button,
21957
- {
21958
- variant: "secondary",
21959
- size: "sm",
21960
- onClick: handleReset,
21961
- disabled: isRunning,
21962
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
21963
- /* @__PURE__ */ jsx(RotateCcw, { size: 16 }),
21964
- "Reset"
21965
- ] })
21966
- }
21967
- )
21968
- ] }),
21969
- output && /* @__PURE__ */ jsxs(
21970
- Badge,
21936
+ /* @__PURE__ */ jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
21937
+ /* @__PURE__ */ jsx(
21938
+ CodeBlock,
21971
21939
  {
21972
- variant: output.exitCode === 0 ? "success" : "danger",
21973
- size: "sm",
21940
+ language,
21941
+ code,
21942
+ editable: true,
21943
+ onChange: setCode,
21944
+ showLanguageBadge: true,
21945
+ showCopyButton: false,
21946
+ maxHeight: "100%"
21947
+ }
21948
+ ),
21949
+ /* @__PURE__ */ jsxs(
21950
+ HStack,
21951
+ {
21952
+ gap: "xs",
21953
+ align: "center",
21954
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
21974
21955
  children: [
21975
- "Exit ",
21976
- output.exitCode
21956
+ /* @__PURE__ */ jsx(
21957
+ Button,
21958
+ {
21959
+ variant: "ghost",
21960
+ size: "sm",
21961
+ onClick: handleCopy,
21962
+ icon: copied ? Check : Copy,
21963
+ "aria-label": t("common.copy"),
21964
+ className: copied ? "text-success" : ""
21965
+ }
21966
+ ),
21967
+ /* @__PURE__ */ jsx(
21968
+ Button,
21969
+ {
21970
+ variant: "ghost",
21971
+ size: "sm",
21972
+ onClick: handleReset,
21973
+ disabled: isRunning,
21974
+ icon: RotateCcw,
21975
+ "aria-label": "Reset"
21976
+ }
21977
+ ),
21978
+ /* @__PURE__ */ jsx(
21979
+ Button,
21980
+ {
21981
+ variant: "primary",
21982
+ size: "sm",
21983
+ onClick: handleRun,
21984
+ disabled: isRunning,
21985
+ icon: isRunning ? RotateCcw : Play,
21986
+ className: isRunning ? "[&_svg]:animate-spin" : "",
21987
+ children: isRunning ? t("common.loading") : "Run"
21988
+ }
21989
+ )
21977
21990
  ]
21978
21991
  }
21979
21992
  )
@@ -21987,7 +22000,18 @@ var init_CodeRunnerPanel = __esm({
21987
22000
  className: "px-3 py-2 bg-card border-b border-border",
21988
22001
  children: [
21989
22002
  /* @__PURE__ */ jsx(Terminal, { size: 16, className: "text-muted-foreground" }),
21990
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
22003
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
22004
+ output && /* @__PURE__ */ jsxs(
22005
+ Badge,
22006
+ {
22007
+ variant: output.exitCode === 0 ? "success" : "danger",
22008
+ size: "sm",
22009
+ children: [
22010
+ "Exit ",
22011
+ output.exitCode
22012
+ ]
22013
+ }
22014
+ )
21991
22015
  ]
21992
22016
  }
21993
22017
  ),
@@ -21556,6 +21556,7 @@ var init_CodeRunnerPanel = __esm({
21556
21556
  const [output, setOutput] = React85.useState(null);
21557
21557
  const [error, setError] = React85.useState(null);
21558
21558
  const [isRunning, setIsRunning] = React85.useState(false);
21559
+ const [copied, setCopied] = React85.useState(false);
21559
21560
  const handleRun = React85.useCallback(async () => {
21560
21561
  if (!onRun) return;
21561
21562
  setIsRunning(true);
@@ -21578,63 +21579,75 @@ var init_CodeRunnerPanel = __esm({
21578
21579
  setOutput(null);
21579
21580
  setError(null);
21580
21581
  }, [initialCode]);
21582
+ const handleCopy = React85.useCallback(async () => {
21583
+ try {
21584
+ await navigator.clipboard.writeText(code);
21585
+ setCopied(true);
21586
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
21587
+ setTimeout(() => setCopied(false), 2e3);
21588
+ } catch {
21589
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
21590
+ }
21591
+ }, [code, language, eventBus]);
21581
21592
  if (!runnable || !onRun) {
21582
21593
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className, children: /* @__PURE__ */ jsxRuntime.jsx(CodeBlock, { language, code }) });
21583
21594
  }
21584
21595
  const hasOutput = output !== null || error !== null;
21585
21596
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: cn("space-y-3", className), children: [
21586
- /* @__PURE__ */ jsxRuntime.jsx(
21587
- CodeBlock,
21588
- {
21589
- language,
21590
- code,
21591
- editable: true,
21592
- onChange: setCode,
21593
- showLanguageBadge: true,
21594
- showCopyButton: true
21595
- }
21596
- ),
21597
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", justify: "between", children: [
21598
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", children: [
21599
- /* @__PURE__ */ jsxRuntime.jsx(
21600
- Button,
21601
- {
21602
- variant: "primary",
21603
- size: "sm",
21604
- onClick: handleRun,
21605
- disabled: isRunning,
21606
- className: "min-w-[5rem]",
21607
- children: isRunning ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
21608
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16, className: "animate-spin" }),
21609
- t("common.loading")
21610
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
21611
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Play, { size: 16 }),
21612
- "Run"
21613
- ] })
21614
- }
21615
- ),
21616
- /* @__PURE__ */ jsxRuntime.jsx(
21617
- Button,
21618
- {
21619
- variant: "secondary",
21620
- size: "sm",
21621
- onClick: handleReset,
21622
- disabled: isRunning,
21623
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-2", children: [
21624
- /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.RotateCcw, { size: 16 }),
21625
- "Reset"
21626
- ] })
21627
- }
21628
- )
21629
- ] }),
21630
- output && /* @__PURE__ */ jsxRuntime.jsxs(
21631
- Badge,
21597
+ /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
21598
+ /* @__PURE__ */ jsxRuntime.jsx(
21599
+ CodeBlock,
21632
21600
  {
21633
- variant: output.exitCode === 0 ? "success" : "danger",
21634
- size: "sm",
21601
+ language,
21602
+ code,
21603
+ editable: true,
21604
+ onChange: setCode,
21605
+ showLanguageBadge: true,
21606
+ showCopyButton: false,
21607
+ maxHeight: "100%"
21608
+ }
21609
+ ),
21610
+ /* @__PURE__ */ jsxRuntime.jsxs(
21611
+ HStack,
21612
+ {
21613
+ gap: "xs",
21614
+ align: "center",
21615
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
21635
21616
  children: [
21636
- "Exit ",
21637
- output.exitCode
21617
+ /* @__PURE__ */ jsxRuntime.jsx(
21618
+ Button,
21619
+ {
21620
+ variant: "ghost",
21621
+ size: "sm",
21622
+ onClick: handleCopy,
21623
+ icon: copied ? LucideIcons2.Check : LucideIcons2.Copy,
21624
+ "aria-label": t("common.copy"),
21625
+ className: copied ? "text-success" : ""
21626
+ }
21627
+ ),
21628
+ /* @__PURE__ */ jsxRuntime.jsx(
21629
+ Button,
21630
+ {
21631
+ variant: "ghost",
21632
+ size: "sm",
21633
+ onClick: handleReset,
21634
+ disabled: isRunning,
21635
+ icon: LucideIcons2.RotateCcw,
21636
+ "aria-label": "Reset"
21637
+ }
21638
+ ),
21639
+ /* @__PURE__ */ jsxRuntime.jsx(
21640
+ Button,
21641
+ {
21642
+ variant: "primary",
21643
+ size: "sm",
21644
+ onClick: handleRun,
21645
+ disabled: isRunning,
21646
+ icon: isRunning ? LucideIcons2.RotateCcw : LucideIcons2.Play,
21647
+ className: isRunning ? "[&_svg]:animate-spin" : "",
21648
+ children: isRunning ? t("common.loading") : "Run"
21649
+ }
21650
+ )
21638
21651
  ]
21639
21652
  }
21640
21653
  )
@@ -21648,7 +21661,18 @@ var init_CodeRunnerPanel = __esm({
21648
21661
  className: "px-3 py-2 bg-card border-b border-border",
21649
21662
  children: [
21650
21663
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons2.Terminal, { size: 16, className: "text-muted-foreground" }),
21651
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
21664
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
21665
+ output && /* @__PURE__ */ jsxRuntime.jsxs(
21666
+ Badge,
21667
+ {
21668
+ variant: output.exitCode === 0 ? "success" : "danger",
21669
+ size: "sm",
21670
+ children: [
21671
+ "Exit ",
21672
+ output.exitCode
21673
+ ]
21674
+ }
21675
+ )
21652
21676
  ]
21653
21677
  }
21654
21678
  ),
@@ -21482,6 +21482,7 @@ var init_CodeRunnerPanel = __esm({
21482
21482
  const [output, setOutput] = useState(null);
21483
21483
  const [error, setError] = useState(null);
21484
21484
  const [isRunning, setIsRunning] = useState(false);
21485
+ const [copied, setCopied] = useState(false);
21485
21486
  const handleRun = useCallback(async () => {
21486
21487
  if (!onRun) return;
21487
21488
  setIsRunning(true);
@@ -21504,63 +21505,75 @@ var init_CodeRunnerPanel = __esm({
21504
21505
  setOutput(null);
21505
21506
  setError(null);
21506
21507
  }, [initialCode]);
21508
+ const handleCopy = useCallback(async () => {
21509
+ try {
21510
+ await navigator.clipboard.writeText(code);
21511
+ setCopied(true);
21512
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
21513
+ setTimeout(() => setCopied(false), 2e3);
21514
+ } catch {
21515
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
21516
+ }
21517
+ }, [code, language, eventBus]);
21507
21518
  if (!runnable || !onRun) {
21508
21519
  return /* @__PURE__ */ jsx(Box, { className, children: /* @__PURE__ */ jsx(CodeBlock, { language, code }) });
21509
21520
  }
21510
21521
  const hasOutput = output !== null || error !== null;
21511
21522
  return /* @__PURE__ */ jsxs(Box, { className: cn("space-y-3", className), children: [
21512
- /* @__PURE__ */ jsx(
21513
- CodeBlock,
21514
- {
21515
- language,
21516
- code,
21517
- editable: true,
21518
- onChange: setCode,
21519
- showLanguageBadge: true,
21520
- showCopyButton: true
21521
- }
21522
- ),
21523
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", justify: "between", children: [
21524
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", children: [
21525
- /* @__PURE__ */ jsx(
21526
- Button,
21527
- {
21528
- variant: "primary",
21529
- size: "sm",
21530
- onClick: handleRun,
21531
- disabled: isRunning,
21532
- className: "min-w-[5rem]",
21533
- children: isRunning ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
21534
- /* @__PURE__ */ jsx(RotateCcw, { size: 16, className: "animate-spin" }),
21535
- t("common.loading")
21536
- ] }) : /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
21537
- /* @__PURE__ */ jsx(Play, { size: 16 }),
21538
- "Run"
21539
- ] })
21540
- }
21541
- ),
21542
- /* @__PURE__ */ jsx(
21543
- Button,
21544
- {
21545
- variant: "secondary",
21546
- size: "sm",
21547
- onClick: handleReset,
21548
- disabled: isRunning,
21549
- children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-2", children: [
21550
- /* @__PURE__ */ jsx(RotateCcw, { size: 16 }),
21551
- "Reset"
21552
- ] })
21553
- }
21554
- )
21555
- ] }),
21556
- output && /* @__PURE__ */ jsxs(
21557
- Badge,
21523
+ /* @__PURE__ */ jsxs(Box, { className: "group relative", style: { height: 360 }, children: [
21524
+ /* @__PURE__ */ jsx(
21525
+ CodeBlock,
21558
21526
  {
21559
- variant: output.exitCode === 0 ? "success" : "danger",
21560
- size: "sm",
21527
+ language,
21528
+ code,
21529
+ editable: true,
21530
+ onChange: setCode,
21531
+ showLanguageBadge: true,
21532
+ showCopyButton: false,
21533
+ maxHeight: "100%"
21534
+ }
21535
+ ),
21536
+ /* @__PURE__ */ jsxs(
21537
+ HStack,
21538
+ {
21539
+ gap: "xs",
21540
+ align: "center",
21541
+ className: "absolute top-2 right-2 z-10 opacity-0 pointer-events-none group-hover:opacity-100 group-hover:pointer-events-auto focus-within:opacity-100 focus-within:pointer-events-auto transition-opacity bg-[var(--color-card)]/90 backdrop-blur-sm rounded-md p-1 shadow-sm border border-border",
21561
21542
  children: [
21562
- "Exit ",
21563
- output.exitCode
21543
+ /* @__PURE__ */ jsx(
21544
+ Button,
21545
+ {
21546
+ variant: "ghost",
21547
+ size: "sm",
21548
+ onClick: handleCopy,
21549
+ icon: copied ? Check : Copy,
21550
+ "aria-label": t("common.copy"),
21551
+ className: copied ? "text-success" : ""
21552
+ }
21553
+ ),
21554
+ /* @__PURE__ */ jsx(
21555
+ Button,
21556
+ {
21557
+ variant: "ghost",
21558
+ size: "sm",
21559
+ onClick: handleReset,
21560
+ disabled: isRunning,
21561
+ icon: RotateCcw,
21562
+ "aria-label": "Reset"
21563
+ }
21564
+ ),
21565
+ /* @__PURE__ */ jsx(
21566
+ Button,
21567
+ {
21568
+ variant: "primary",
21569
+ size: "sm",
21570
+ onClick: handleRun,
21571
+ disabled: isRunning,
21572
+ icon: isRunning ? RotateCcw : Play,
21573
+ className: isRunning ? "[&_svg]:animate-spin" : "",
21574
+ children: isRunning ? t("common.loading") : "Run"
21575
+ }
21576
+ )
21564
21577
  ]
21565
21578
  }
21566
21579
  )
@@ -21574,7 +21587,18 @@ var init_CodeRunnerPanel = __esm({
21574
21587
  className: "px-3 py-2 bg-card border-b border-border",
21575
21588
  children: [
21576
21589
  /* @__PURE__ */ jsx(Terminal, { size: 16, className: "text-muted-foreground" }),
21577
- /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" })
21590
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-foreground font-medium", children: "Output" }),
21591
+ output && /* @__PURE__ */ jsxs(
21592
+ Badge,
21593
+ {
21594
+ variant: output.exitCode === 0 ? "success" : "danger",
21595
+ size: "sm",
21596
+ children: [
21597
+ "Exit ",
21598
+ output.exitCode
21599
+ ]
21600
+ }
21601
+ )
21578
21602
  ]
21579
21603
  }
21580
21604
  ),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.145.0",
3
+ "version": "5.146.1",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [