@almadar/ui 5.77.0 → 5.78.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +857 -92
- package/dist/avl/index.js +857 -92
- package/dist/components/core/atoms/index.d.ts +2 -1
- package/dist/components/core/molecules/index.d.ts +4 -0
- package/dist/components/index.cjs +2201 -1519
- package/dist/components/index.js +991 -309
- package/dist/components/learning/atoms/LearningCanvas.d.ts +80 -0
- package/dist/components/learning/molecules/BiologyCanvas.d.ts +47 -0
- package/dist/components/learning/molecules/ChemistryCanvas.d.ts +55 -0
- package/dist/components/learning/molecules/MathCanvas.d.ts +61 -0
- package/dist/components/learning/molecules/PhysicsCanvas.d.ts +54 -0
- package/dist/components/marketing/atoms/MarketingStatCard.d.ts +2 -2
- package/dist/providers/index.cjs +857 -92
- package/dist/providers/index.js +857 -92
- package/dist/runtime/index.cjs +857 -92
- package/dist/runtime/index.js +857 -92
- package/package.json +1 -1
package/dist/runtime/index.cjs
CHANGED
|
@@ -6225,6 +6225,66 @@ var init_RangeSlider = __esm({
|
|
|
6225
6225
|
RangeSlider.displayName = "RangeSlider";
|
|
6226
6226
|
}
|
|
6227
6227
|
});
|
|
6228
|
+
function easeOut(t) {
|
|
6229
|
+
return t * (2 - t);
|
|
6230
|
+
}
|
|
6231
|
+
var AnimatedCounter;
|
|
6232
|
+
var init_AnimatedCounter = __esm({
|
|
6233
|
+
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
6234
|
+
"use client";
|
|
6235
|
+
init_cn();
|
|
6236
|
+
init_Typography();
|
|
6237
|
+
AnimatedCounter = ({
|
|
6238
|
+
value: rawValue,
|
|
6239
|
+
duration = 600,
|
|
6240
|
+
prefix,
|
|
6241
|
+
suffix,
|
|
6242
|
+
className
|
|
6243
|
+
}) => {
|
|
6244
|
+
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
6245
|
+
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
6246
|
+
const [displayValue, setDisplayValue] = React105.useState(value);
|
|
6247
|
+
const previousValueRef = React105.useRef(value);
|
|
6248
|
+
const animationFrameRef = React105.useRef(null);
|
|
6249
|
+
React105.useEffect(() => {
|
|
6250
|
+
const from = previousValueRef.current;
|
|
6251
|
+
const to = value;
|
|
6252
|
+
previousValueRef.current = value;
|
|
6253
|
+
if (from === to) {
|
|
6254
|
+
setDisplayValue(to);
|
|
6255
|
+
return;
|
|
6256
|
+
}
|
|
6257
|
+
const startTime = performance.now();
|
|
6258
|
+
const diff = to - from;
|
|
6259
|
+
function animate(currentTime) {
|
|
6260
|
+
const elapsed = currentTime - startTime;
|
|
6261
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
6262
|
+
const easedProgress = easeOut(progress);
|
|
6263
|
+
setDisplayValue(from + diff * easedProgress);
|
|
6264
|
+
if (progress < 1) {
|
|
6265
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
6266
|
+
} else {
|
|
6267
|
+
setDisplayValue(to);
|
|
6268
|
+
}
|
|
6269
|
+
}
|
|
6270
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
6271
|
+
return () => {
|
|
6272
|
+
if (animationFrameRef.current !== null) {
|
|
6273
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
6274
|
+
}
|
|
6275
|
+
};
|
|
6276
|
+
}, [value, duration]);
|
|
6277
|
+
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
6278
|
+
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
6279
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
6280
|
+
prefix,
|
|
6281
|
+
formattedValue,
|
|
6282
|
+
suffix
|
|
6283
|
+
] });
|
|
6284
|
+
};
|
|
6285
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
6286
|
+
}
|
|
6287
|
+
});
|
|
6228
6288
|
var InfiniteScrollSentinel;
|
|
6229
6289
|
var init_InfiniteScrollSentinel = __esm({
|
|
6230
6290
|
"components/core/atoms/InfiniteScrollSentinel.tsx"() {
|
|
@@ -6486,6 +6546,34 @@ var init_SectionHeader = __esm({
|
|
|
6486
6546
|
SectionHeader.displayName = "SectionHeader";
|
|
6487
6547
|
}
|
|
6488
6548
|
});
|
|
6549
|
+
var sizeClasses6, MarketingStatCard;
|
|
6550
|
+
var init_MarketingStatCard = __esm({
|
|
6551
|
+
"components/marketing/atoms/MarketingStatCard.tsx"() {
|
|
6552
|
+
init_cn();
|
|
6553
|
+
init_Stack();
|
|
6554
|
+
init_Typography();
|
|
6555
|
+
sizeClasses6 = {
|
|
6556
|
+
sm: "text-2xl",
|
|
6557
|
+
md: "text-4xl",
|
|
6558
|
+
lg: "text-5xl"
|
|
6559
|
+
};
|
|
6560
|
+
MarketingStatCard = ({ value, label, size = "md", className }) => {
|
|
6561
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "center", className: cn(className), children: [
|
|
6562
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6563
|
+
Typography,
|
|
6564
|
+
{
|
|
6565
|
+
weight: "bold",
|
|
6566
|
+
color: "primary",
|
|
6567
|
+
className: cn(sizeClasses6[size]),
|
|
6568
|
+
children: value
|
|
6569
|
+
}
|
|
6570
|
+
),
|
|
6571
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
6572
|
+
] });
|
|
6573
|
+
};
|
|
6574
|
+
MarketingStatCard.displayName = "MarketingStatCard";
|
|
6575
|
+
}
|
|
6576
|
+
});
|
|
6489
6577
|
var backgroundClasses, paddingClasses, ContentSection;
|
|
6490
6578
|
var init_ContentSection = __esm({
|
|
6491
6579
|
"components/marketing/atoms/ContentSection.tsx"() {
|
|
@@ -20151,6 +20239,315 @@ var init_molecules = __esm({
|
|
|
20151
20239
|
init_puzzleObject();
|
|
20152
20240
|
}
|
|
20153
20241
|
});
|
|
20242
|
+
function resolveColor2(color, ctx, fallback) {
|
|
20243
|
+
if (!color) return fallback;
|
|
20244
|
+
if (color.startsWith("var(")) {
|
|
20245
|
+
ctx.canvas.style;
|
|
20246
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color);
|
|
20247
|
+
if (m) {
|
|
20248
|
+
const computed = getComputedStyle(ctx.canvas).getPropertyValue(m[1]).trim();
|
|
20249
|
+
return computed || m[2]?.trim() || fallback;
|
|
20250
|
+
}
|
|
20251
|
+
}
|
|
20252
|
+
return color;
|
|
20253
|
+
}
|
|
20254
|
+
function shapeBounds(shape) {
|
|
20255
|
+
switch (shape.type) {
|
|
20256
|
+
case "line":
|
|
20257
|
+
case "arrow":
|
|
20258
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) return null;
|
|
20259
|
+
return {
|
|
20260
|
+
x: Math.min(shape.x1, shape.x2) - 6,
|
|
20261
|
+
y: Math.min(shape.y1, shape.y2) - 6,
|
|
20262
|
+
w: Math.abs(shape.x2 - shape.x1) + 12,
|
|
20263
|
+
h: Math.abs(shape.y2 - shape.y1) + 12
|
|
20264
|
+
};
|
|
20265
|
+
case "circle":
|
|
20266
|
+
if (shape.x == null || shape.y == null || shape.radius == null) return null;
|
|
20267
|
+
return {
|
|
20268
|
+
x: shape.x - shape.radius - 4,
|
|
20269
|
+
y: shape.y - shape.radius - 4,
|
|
20270
|
+
w: shape.radius * 2 + 8,
|
|
20271
|
+
h: shape.radius * 2 + 8
|
|
20272
|
+
};
|
|
20273
|
+
case "rect":
|
|
20274
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) return null;
|
|
20275
|
+
return { x: shape.x - 4, y: shape.y - 4, w: shape.width + 8, h: shape.height + 8 };
|
|
20276
|
+
case "polygon":
|
|
20277
|
+
if (!shape.points || shape.points.length === 0) return null;
|
|
20278
|
+
{
|
|
20279
|
+
const xs = shape.points.map((p2) => p2.x);
|
|
20280
|
+
const ys = shape.points.map((p2) => p2.y);
|
|
20281
|
+
const minX = Math.min(...xs);
|
|
20282
|
+
const minY = Math.min(...ys);
|
|
20283
|
+
return {
|
|
20284
|
+
x: minX - 4,
|
|
20285
|
+
y: minY - 4,
|
|
20286
|
+
w: Math.max(...xs) - minX + 8,
|
|
20287
|
+
h: Math.max(...ys) - minY + 8
|
|
20288
|
+
};
|
|
20289
|
+
}
|
|
20290
|
+
case "text":
|
|
20291
|
+
if (shape.x == null || shape.y == null) return null;
|
|
20292
|
+
return { x: shape.x - 4, y: shape.y - (shape.fontSize ?? 14) - 4, w: 120, h: (shape.fontSize ?? 14) + 8 };
|
|
20293
|
+
default:
|
|
20294
|
+
return null;
|
|
20295
|
+
}
|
|
20296
|
+
}
|
|
20297
|
+
function drawArrowHead(ctx, x1, y1, x2, y2, size) {
|
|
20298
|
+
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
20299
|
+
ctx.beginPath();
|
|
20300
|
+
ctx.moveTo(x2, y2);
|
|
20301
|
+
ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
|
|
20302
|
+
ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
|
|
20303
|
+
ctx.closePath();
|
|
20304
|
+
ctx.fill();
|
|
20305
|
+
}
|
|
20306
|
+
function drawShape(ctx, shape, width, height) {
|
|
20307
|
+
ctx.save();
|
|
20308
|
+
const opacity = shape.opacity ?? 1;
|
|
20309
|
+
ctx.globalAlpha = opacity;
|
|
20310
|
+
const stroke = resolveColor2(shape.color, ctx, "#333333");
|
|
20311
|
+
const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
|
|
20312
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
20313
|
+
switch (shape.type) {
|
|
20314
|
+
case "grid": {
|
|
20315
|
+
const step = shape.step ?? 40;
|
|
20316
|
+
ctx.strokeStyle = stroke;
|
|
20317
|
+
ctx.globalAlpha = opacity * 0.25;
|
|
20318
|
+
ctx.lineWidth = 1;
|
|
20319
|
+
ctx.beginPath();
|
|
20320
|
+
for (let x = 0; x <= width; x += step) {
|
|
20321
|
+
ctx.moveTo(x, 0);
|
|
20322
|
+
ctx.lineTo(x, height);
|
|
20323
|
+
}
|
|
20324
|
+
for (let y = 0; y <= height; y += step) {
|
|
20325
|
+
ctx.moveTo(0, y);
|
|
20326
|
+
ctx.lineTo(width, y);
|
|
20327
|
+
}
|
|
20328
|
+
ctx.stroke();
|
|
20329
|
+
break;
|
|
20330
|
+
}
|
|
20331
|
+
case "axis": {
|
|
20332
|
+
const axis = shape.axis ?? "x";
|
|
20333
|
+
ctx.strokeStyle = stroke;
|
|
20334
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
20335
|
+
ctx.beginPath();
|
|
20336
|
+
if (axis === "x") {
|
|
20337
|
+
ctx.moveTo(0, height / 2);
|
|
20338
|
+
ctx.lineTo(width, height / 2);
|
|
20339
|
+
} else {
|
|
20340
|
+
ctx.moveTo(width / 2, 0);
|
|
20341
|
+
ctx.lineTo(width / 2, height);
|
|
20342
|
+
}
|
|
20343
|
+
ctx.stroke();
|
|
20344
|
+
break;
|
|
20345
|
+
}
|
|
20346
|
+
case "line": {
|
|
20347
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
20348
|
+
ctx.strokeStyle = stroke;
|
|
20349
|
+
ctx.beginPath();
|
|
20350
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
20351
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
20352
|
+
ctx.stroke();
|
|
20353
|
+
break;
|
|
20354
|
+
}
|
|
20355
|
+
case "arrow": {
|
|
20356
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
20357
|
+
ctx.strokeStyle = stroke;
|
|
20358
|
+
ctx.fillStyle = stroke;
|
|
20359
|
+
ctx.beginPath();
|
|
20360
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
20361
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
20362
|
+
ctx.stroke();
|
|
20363
|
+
drawArrowHead(ctx, shape.x1, shape.y1, shape.x2, shape.y2, 10);
|
|
20364
|
+
break;
|
|
20365
|
+
}
|
|
20366
|
+
case "circle": {
|
|
20367
|
+
if (shape.x == null || shape.y == null || shape.radius == null) break;
|
|
20368
|
+
ctx.beginPath();
|
|
20369
|
+
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
|
|
20370
|
+
if (fill) {
|
|
20371
|
+
ctx.fillStyle = fill;
|
|
20372
|
+
ctx.fill();
|
|
20373
|
+
}
|
|
20374
|
+
ctx.strokeStyle = stroke;
|
|
20375
|
+
ctx.stroke();
|
|
20376
|
+
break;
|
|
20377
|
+
}
|
|
20378
|
+
case "rect": {
|
|
20379
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) break;
|
|
20380
|
+
if (fill) {
|
|
20381
|
+
ctx.fillStyle = fill;
|
|
20382
|
+
ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
|
|
20383
|
+
}
|
|
20384
|
+
ctx.strokeStyle = stroke;
|
|
20385
|
+
ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
|
|
20386
|
+
break;
|
|
20387
|
+
}
|
|
20388
|
+
case "polygon": {
|
|
20389
|
+
if (!shape.points || shape.points.length < 2) break;
|
|
20390
|
+
ctx.beginPath();
|
|
20391
|
+
ctx.moveTo(shape.points[0].x, shape.points[0].y);
|
|
20392
|
+
for (let i = 1; i < shape.points.length; i++) {
|
|
20393
|
+
ctx.lineTo(shape.points[i].x, shape.points[i].y);
|
|
20394
|
+
}
|
|
20395
|
+
ctx.closePath();
|
|
20396
|
+
if (fill) {
|
|
20397
|
+
ctx.fillStyle = fill;
|
|
20398
|
+
ctx.fill();
|
|
20399
|
+
}
|
|
20400
|
+
ctx.strokeStyle = stroke;
|
|
20401
|
+
ctx.stroke();
|
|
20402
|
+
break;
|
|
20403
|
+
}
|
|
20404
|
+
case "path": {
|
|
20405
|
+
if (!shape.path) break;
|
|
20406
|
+
const p2 = new Path2D(shape.path);
|
|
20407
|
+
if (fill) {
|
|
20408
|
+
ctx.fillStyle = fill;
|
|
20409
|
+
ctx.fill(p2);
|
|
20410
|
+
}
|
|
20411
|
+
ctx.strokeStyle = stroke;
|
|
20412
|
+
ctx.stroke(p2);
|
|
20413
|
+
break;
|
|
20414
|
+
}
|
|
20415
|
+
case "text": {
|
|
20416
|
+
if (shape.x == null || shape.y == null || !shape.text) break;
|
|
20417
|
+
ctx.fillStyle = stroke;
|
|
20418
|
+
ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
|
|
20419
|
+
ctx.textAlign = shape.align ?? "left";
|
|
20420
|
+
ctx.textBaseline = "middle";
|
|
20421
|
+
ctx.fillText(shape.text, shape.x, shape.y);
|
|
20422
|
+
break;
|
|
20423
|
+
}
|
|
20424
|
+
}
|
|
20425
|
+
ctx.restore();
|
|
20426
|
+
}
|
|
20427
|
+
var LearningCanvas;
|
|
20428
|
+
var init_LearningCanvas = __esm({
|
|
20429
|
+
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
20430
|
+
"use client";
|
|
20431
|
+
init_cn();
|
|
20432
|
+
init_useEventBus();
|
|
20433
|
+
LearningCanvas = ({
|
|
20434
|
+
className,
|
|
20435
|
+
width = 600,
|
|
20436
|
+
height = 400,
|
|
20437
|
+
backgroundColor,
|
|
20438
|
+
shapes = [],
|
|
20439
|
+
interactive = false,
|
|
20440
|
+
animate = false,
|
|
20441
|
+
onShapeClick,
|
|
20442
|
+
onShapeHover,
|
|
20443
|
+
isLoading,
|
|
20444
|
+
error
|
|
20445
|
+
}) => {
|
|
20446
|
+
const canvasRef = React105.useRef(null);
|
|
20447
|
+
const eventBus = useEventBus();
|
|
20448
|
+
const animRef = React105.useRef(0);
|
|
20449
|
+
const hoverIndexRef = React105.useRef(-1);
|
|
20450
|
+
const findShapeAt = React105.useCallback((clientX, clientY) => {
|
|
20451
|
+
const canvas = canvasRef.current;
|
|
20452
|
+
if (!canvas) return -1;
|
|
20453
|
+
const rect = canvas.getBoundingClientRect();
|
|
20454
|
+
const x = clientX - rect.left;
|
|
20455
|
+
const y = clientY - rect.top;
|
|
20456
|
+
for (let i = shapes.length - 1; i >= 0; i--) {
|
|
20457
|
+
const b = shapeBounds(shapes[i]);
|
|
20458
|
+
if (b && x >= b.x && x <= b.x + b.w && y >= b.y && y <= b.y + b.h) {
|
|
20459
|
+
return i;
|
|
20460
|
+
}
|
|
20461
|
+
}
|
|
20462
|
+
return -1;
|
|
20463
|
+
}, [shapes]);
|
|
20464
|
+
const draw = React105.useCallback(() => {
|
|
20465
|
+
const canvas = canvasRef.current;
|
|
20466
|
+
if (!canvas) return;
|
|
20467
|
+
const ctx = canvas.getContext("2d");
|
|
20468
|
+
if (!ctx) return;
|
|
20469
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
20470
|
+
canvas.width = Math.max(1, Math.floor(width * dpr));
|
|
20471
|
+
canvas.height = Math.max(1, Math.floor(height * dpr));
|
|
20472
|
+
canvas.style.width = `${width}px`;
|
|
20473
|
+
canvas.style.height = `${height}px`;
|
|
20474
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
20475
|
+
ctx.clearRect(0, 0, width, height);
|
|
20476
|
+
if (backgroundColor) {
|
|
20477
|
+
ctx.fillStyle = backgroundColor;
|
|
20478
|
+
ctx.fillRect(0, 0, width, height);
|
|
20479
|
+
}
|
|
20480
|
+
for (const shape of shapes) {
|
|
20481
|
+
drawShape(ctx, shape, width, height);
|
|
20482
|
+
}
|
|
20483
|
+
}, [width, height, backgroundColor, shapes]);
|
|
20484
|
+
React105.useEffect(() => {
|
|
20485
|
+
draw();
|
|
20486
|
+
}, [draw]);
|
|
20487
|
+
React105.useEffect(() => {
|
|
20488
|
+
if (!animate) return;
|
|
20489
|
+
const loop = () => {
|
|
20490
|
+
draw();
|
|
20491
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20492
|
+
};
|
|
20493
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20494
|
+
return () => cancelAnimationFrame(animRef.current);
|
|
20495
|
+
}, [animate, draw]);
|
|
20496
|
+
const handlePointerMove = React105.useCallback(
|
|
20497
|
+
(e) => {
|
|
20498
|
+
if (!interactive) return;
|
|
20499
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20500
|
+
if (idx !== hoverIndexRef.current) {
|
|
20501
|
+
hoverIndexRef.current = idx;
|
|
20502
|
+
if (idx >= 0) {
|
|
20503
|
+
const shape = shapes[idx];
|
|
20504
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20505
|
+
if (onShapeHover) onShapeHover(payload);
|
|
20506
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_HOVER`, payload);
|
|
20507
|
+
}
|
|
20508
|
+
}
|
|
20509
|
+
},
|
|
20510
|
+
[interactive, onShapeHover, eventBus, findShapeAt, shapes]
|
|
20511
|
+
);
|
|
20512
|
+
const handleClick = React105.useCallback(
|
|
20513
|
+
(e) => {
|
|
20514
|
+
if (!interactive) return;
|
|
20515
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20516
|
+
if (idx >= 0) {
|
|
20517
|
+
const shape = shapes[idx];
|
|
20518
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20519
|
+
if (onShapeClick) onShapeClick(payload);
|
|
20520
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_CLICK`, payload);
|
|
20521
|
+
}
|
|
20522
|
+
},
|
|
20523
|
+
[interactive, onShapeClick, eventBus, findShapeAt, shapes]
|
|
20524
|
+
);
|
|
20525
|
+
if (isLoading || error) {
|
|
20526
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20527
|
+
"div",
|
|
20528
|
+
{
|
|
20529
|
+
className: cn(
|
|
20530
|
+
"flex items-center justify-center rounded border border-border bg-surface",
|
|
20531
|
+
className
|
|
20532
|
+
),
|
|
20533
|
+
style: { width, height },
|
|
20534
|
+
children: error ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: error.message }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Loading canvas\u2026" })
|
|
20535
|
+
}
|
|
20536
|
+
);
|
|
20537
|
+
}
|
|
20538
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20539
|
+
"canvas",
|
|
20540
|
+
{
|
|
20541
|
+
ref: canvasRef,
|
|
20542
|
+
className: cn("block touch-none rounded border border-border", className),
|
|
20543
|
+
style: { width, height },
|
|
20544
|
+
onClick: handleClick,
|
|
20545
|
+
onPointerMove: handlePointerMove
|
|
20546
|
+
}
|
|
20547
|
+
);
|
|
20548
|
+
};
|
|
20549
|
+
}
|
|
20550
|
+
});
|
|
20154
20551
|
|
|
20155
20552
|
// components/core/atoms/index.ts
|
|
20156
20553
|
var init_atoms = __esm({
|
|
@@ -21636,91 +22033,6 @@ var init_ComponentPatterns = __esm({
|
|
|
21636
22033
|
AlertPattern.displayName = "AlertPattern";
|
|
21637
22034
|
}
|
|
21638
22035
|
});
|
|
21639
|
-
function parseValue(value) {
|
|
21640
|
-
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
21641
|
-
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
21642
|
-
if (!match) {
|
|
21643
|
-
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
21644
|
-
}
|
|
21645
|
-
const numStr = match[2];
|
|
21646
|
-
const decimalIdx = numStr.indexOf(".");
|
|
21647
|
-
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
21648
|
-
return {
|
|
21649
|
-
prefix: match[1],
|
|
21650
|
-
num: parseFloat(numStr),
|
|
21651
|
-
suffix: match[3],
|
|
21652
|
-
decimals
|
|
21653
|
-
};
|
|
21654
|
-
}
|
|
21655
|
-
var AnimatedCounter;
|
|
21656
|
-
var init_AnimatedCounter = __esm({
|
|
21657
|
-
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
21658
|
-
"use client";
|
|
21659
|
-
init_cn();
|
|
21660
|
-
init_Box();
|
|
21661
|
-
init_Typography();
|
|
21662
|
-
AnimatedCounter = ({
|
|
21663
|
-
value,
|
|
21664
|
-
label,
|
|
21665
|
-
duration = 1500,
|
|
21666
|
-
className
|
|
21667
|
-
}) => {
|
|
21668
|
-
const ref = React105.useRef(null);
|
|
21669
|
-
const [displayValue, setDisplayValue] = React105.useState("0");
|
|
21670
|
-
const [hasAnimated, setHasAnimated] = React105.useState(false);
|
|
21671
|
-
const animate = React105.useCallback(() => {
|
|
21672
|
-
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
21673
|
-
if (num2 === 0) {
|
|
21674
|
-
setDisplayValue(String(value));
|
|
21675
|
-
return;
|
|
21676
|
-
}
|
|
21677
|
-
const startTime = performance.now();
|
|
21678
|
-
const tick = (now2) => {
|
|
21679
|
-
const elapsed = now2 - startTime;
|
|
21680
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
21681
|
-
const eased = 1 - Math.pow(1 - progress, 3);
|
|
21682
|
-
const current = eased * num2;
|
|
21683
|
-
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
21684
|
-
if (progress < 1) {
|
|
21685
|
-
requestAnimationFrame(tick);
|
|
21686
|
-
} else {
|
|
21687
|
-
setDisplayValue(String(value));
|
|
21688
|
-
}
|
|
21689
|
-
};
|
|
21690
|
-
requestAnimationFrame(tick);
|
|
21691
|
-
}, [value, duration]);
|
|
21692
|
-
React105.useEffect(() => {
|
|
21693
|
-
if (hasAnimated) return;
|
|
21694
|
-
const el = ref.current;
|
|
21695
|
-
if (!el) return;
|
|
21696
|
-
const observer2 = new IntersectionObserver(
|
|
21697
|
-
(entries) => {
|
|
21698
|
-
if (entries[0].isIntersecting) {
|
|
21699
|
-
setHasAnimated(true);
|
|
21700
|
-
animate();
|
|
21701
|
-
observer2.disconnect();
|
|
21702
|
-
}
|
|
21703
|
-
},
|
|
21704
|
-
{ threshold: 0.3 }
|
|
21705
|
-
);
|
|
21706
|
-
observer2.observe(el);
|
|
21707
|
-
return () => observer2.disconnect();
|
|
21708
|
-
}, [hasAnimated, animate]);
|
|
21709
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
21710
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21711
|
-
Typography,
|
|
21712
|
-
{
|
|
21713
|
-
variant: "h2",
|
|
21714
|
-
className: "text-primary font-bold tabular-nums",
|
|
21715
|
-
children: hasAnimated ? displayValue : "0"
|
|
21716
|
-
}
|
|
21717
|
-
),
|
|
21718
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
21719
|
-
] });
|
|
21720
|
-
};
|
|
21721
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
21722
|
-
}
|
|
21723
|
-
});
|
|
21724
22036
|
var AuthLayout;
|
|
21725
22037
|
var init_AuthLayout = __esm({
|
|
21726
22038
|
"components/marketing/templates/AuthLayout.tsx"() {
|
|
@@ -22689,6 +23001,103 @@ var init_BehaviorView = __esm({
|
|
|
22689
23001
|
BehaviorView.displayName = "BehaviorView";
|
|
22690
23002
|
}
|
|
22691
23003
|
});
|
|
23004
|
+
var BiologyCanvas;
|
|
23005
|
+
var init_BiologyCanvas = __esm({
|
|
23006
|
+
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
23007
|
+
"use client";
|
|
23008
|
+
init_atoms();
|
|
23009
|
+
init_Stack();
|
|
23010
|
+
init_LearningCanvas();
|
|
23011
|
+
BiologyCanvas = ({
|
|
23012
|
+
className,
|
|
23013
|
+
width = 600,
|
|
23014
|
+
height = 400,
|
|
23015
|
+
title,
|
|
23016
|
+
backgroundColor,
|
|
23017
|
+
nodes = [],
|
|
23018
|
+
edges = [],
|
|
23019
|
+
shapes = [],
|
|
23020
|
+
interactive = false,
|
|
23021
|
+
animate = false,
|
|
23022
|
+
onShapeClick,
|
|
23023
|
+
isLoading,
|
|
23024
|
+
error
|
|
23025
|
+
}) => {
|
|
23026
|
+
const derivedShapes = React105.useMemo(() => {
|
|
23027
|
+
const out = [];
|
|
23028
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
23029
|
+
for (const n of nodes) {
|
|
23030
|
+
if (n.id) nodeById.set(n.id, n);
|
|
23031
|
+
}
|
|
23032
|
+
for (const e of edges) {
|
|
23033
|
+
const a = nodeById.get(e.from);
|
|
23034
|
+
const b = nodeById.get(e.to);
|
|
23035
|
+
if (!a || !b) continue;
|
|
23036
|
+
out.push({
|
|
23037
|
+
type: "line",
|
|
23038
|
+
x1: a.x,
|
|
23039
|
+
y1: a.y,
|
|
23040
|
+
x2: b.x,
|
|
23041
|
+
y2: b.y,
|
|
23042
|
+
color: e.color ?? "#9ca3af",
|
|
23043
|
+
lineWidth: 2
|
|
23044
|
+
});
|
|
23045
|
+
if (e.label) {
|
|
23046
|
+
out.push({
|
|
23047
|
+
type: "text",
|
|
23048
|
+
x: (a.x + b.x) / 2 + 4,
|
|
23049
|
+
y: (a.y + b.y) / 2 - 4,
|
|
23050
|
+
text: e.label,
|
|
23051
|
+
color: "#374151",
|
|
23052
|
+
fontSize: 11
|
|
23053
|
+
});
|
|
23054
|
+
}
|
|
23055
|
+
}
|
|
23056
|
+
for (const n of nodes) {
|
|
23057
|
+
out.push({
|
|
23058
|
+
type: "circle",
|
|
23059
|
+
x: n.x,
|
|
23060
|
+
y: n.y,
|
|
23061
|
+
radius: n.radius ?? 16,
|
|
23062
|
+
color: n.color ?? "#16a34a",
|
|
23063
|
+
fill: `${n.color ?? "#16a34a"}33`,
|
|
23064
|
+
id: n.id
|
|
23065
|
+
});
|
|
23066
|
+
if (n.label) {
|
|
23067
|
+
out.push({
|
|
23068
|
+
type: "text",
|
|
23069
|
+
x: n.x,
|
|
23070
|
+
y: n.y + (n.radius ?? 16) + 14,
|
|
23071
|
+
text: n.label,
|
|
23072
|
+
color: "#111827",
|
|
23073
|
+
fontSize: 12,
|
|
23074
|
+
align: "center"
|
|
23075
|
+
});
|
|
23076
|
+
}
|
|
23077
|
+
}
|
|
23078
|
+
out.push(...shapes);
|
|
23079
|
+
return out;
|
|
23080
|
+
}, [nodes, edges, shapes]);
|
|
23081
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
23082
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
23083
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23084
|
+
LearningCanvas,
|
|
23085
|
+
{
|
|
23086
|
+
width,
|
|
23087
|
+
height,
|
|
23088
|
+
backgroundColor,
|
|
23089
|
+
shapes: derivedShapes,
|
|
23090
|
+
interactive,
|
|
23091
|
+
animate,
|
|
23092
|
+
onShapeClick,
|
|
23093
|
+
isLoading,
|
|
23094
|
+
error
|
|
23095
|
+
}
|
|
23096
|
+
)
|
|
23097
|
+
] }) });
|
|
23098
|
+
};
|
|
23099
|
+
}
|
|
23100
|
+
});
|
|
22692
23101
|
|
|
22693
23102
|
// node_modules/katex/dist/katex.min.css
|
|
22694
23103
|
var init_katex_min = __esm({
|
|
@@ -29061,6 +29470,122 @@ var init_ChatBar = __esm({
|
|
|
29061
29470
|
ChatBar.displayName = "ChatBar";
|
|
29062
29471
|
}
|
|
29063
29472
|
});
|
|
29473
|
+
var ChemistryCanvas;
|
|
29474
|
+
var init_ChemistryCanvas = __esm({
|
|
29475
|
+
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
29476
|
+
"use client";
|
|
29477
|
+
init_atoms();
|
|
29478
|
+
init_Stack();
|
|
29479
|
+
init_LearningCanvas();
|
|
29480
|
+
ChemistryCanvas = ({
|
|
29481
|
+
className,
|
|
29482
|
+
width = 600,
|
|
29483
|
+
height = 400,
|
|
29484
|
+
title,
|
|
29485
|
+
backgroundColor,
|
|
29486
|
+
atoms = [],
|
|
29487
|
+
bonds = [],
|
|
29488
|
+
arrows = [],
|
|
29489
|
+
shapes = [],
|
|
29490
|
+
interactive = false,
|
|
29491
|
+
animate = false,
|
|
29492
|
+
onShapeClick,
|
|
29493
|
+
isLoading,
|
|
29494
|
+
error
|
|
29495
|
+
}) => {
|
|
29496
|
+
const derivedShapes = React105.useMemo(() => {
|
|
29497
|
+
const out = [];
|
|
29498
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
29499
|
+
for (const a of atoms) {
|
|
29500
|
+
if (a.id) atomById.set(a.id, a);
|
|
29501
|
+
}
|
|
29502
|
+
for (const b of bonds) {
|
|
29503
|
+
const a = atomById.get(b.from);
|
|
29504
|
+
const c = atomById.get(b.to);
|
|
29505
|
+
if (!a || !c) continue;
|
|
29506
|
+
const color = b.color ?? "#6b7280";
|
|
29507
|
+
const strokeWidth = b.type === "double" ? 4 : b.type === "triple" ? 6 : 2;
|
|
29508
|
+
out.push({
|
|
29509
|
+
type: "line",
|
|
29510
|
+
x1: a.x,
|
|
29511
|
+
y1: a.y,
|
|
29512
|
+
x2: c.x,
|
|
29513
|
+
y2: c.y,
|
|
29514
|
+
color,
|
|
29515
|
+
lineWidth: strokeWidth
|
|
29516
|
+
});
|
|
29517
|
+
}
|
|
29518
|
+
for (const a of arrows) {
|
|
29519
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
29520
|
+
const len = a.length ?? 60;
|
|
29521
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
29522
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
29523
|
+
out.push({
|
|
29524
|
+
type: "arrow",
|
|
29525
|
+
x1: a.x,
|
|
29526
|
+
y1: a.y,
|
|
29527
|
+
x2,
|
|
29528
|
+
y2,
|
|
29529
|
+
color: a.color ?? "#dc2626",
|
|
29530
|
+
lineWidth: 2
|
|
29531
|
+
});
|
|
29532
|
+
if (a.label) {
|
|
29533
|
+
out.push({
|
|
29534
|
+
type: "text",
|
|
29535
|
+
x: (a.x + x2) / 2,
|
|
29536
|
+
y: (a.y + y2) / 2 - 10,
|
|
29537
|
+
text: a.label,
|
|
29538
|
+
color: "#111827",
|
|
29539
|
+
fontSize: 12,
|
|
29540
|
+
align: "center"
|
|
29541
|
+
});
|
|
29542
|
+
}
|
|
29543
|
+
}
|
|
29544
|
+
for (const a of atoms) {
|
|
29545
|
+
out.push({
|
|
29546
|
+
type: "circle",
|
|
29547
|
+
x: a.x,
|
|
29548
|
+
y: a.y,
|
|
29549
|
+
radius: a.radius ?? 14,
|
|
29550
|
+
color: a.color ?? "#2563eb",
|
|
29551
|
+
fill: a.color ?? "#2563eb",
|
|
29552
|
+
id: a.id
|
|
29553
|
+
});
|
|
29554
|
+
if (a.element) {
|
|
29555
|
+
out.push({
|
|
29556
|
+
type: "text",
|
|
29557
|
+
x: a.x,
|
|
29558
|
+
y: a.y,
|
|
29559
|
+
text: a.element,
|
|
29560
|
+
color: "#ffffff",
|
|
29561
|
+
fontSize: 12,
|
|
29562
|
+
align: "center"
|
|
29563
|
+
});
|
|
29564
|
+
}
|
|
29565
|
+
}
|
|
29566
|
+
out.push(...shapes);
|
|
29567
|
+
return out;
|
|
29568
|
+
}, [atoms, bonds, arrows, shapes]);
|
|
29569
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
29570
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
29571
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29572
|
+
LearningCanvas,
|
|
29573
|
+
{
|
|
29574
|
+
width,
|
|
29575
|
+
height,
|
|
29576
|
+
backgroundColor,
|
|
29577
|
+
shapes: derivedShapes,
|
|
29578
|
+
interactive,
|
|
29579
|
+
animate,
|
|
29580
|
+
onShapeClick,
|
|
29581
|
+
isLoading,
|
|
29582
|
+
error
|
|
29583
|
+
}
|
|
29584
|
+
)
|
|
29585
|
+
] }) });
|
|
29586
|
+
};
|
|
29587
|
+
}
|
|
29588
|
+
});
|
|
29064
29589
|
var CodeRunnerPanel;
|
|
29065
29590
|
var init_CodeRunnerPanel = __esm({
|
|
29066
29591
|
"components/core/organisms/CodeRunnerPanel.tsx"() {
|
|
@@ -34680,6 +35205,234 @@ var init_ProgressDots = __esm({
|
|
|
34680
35205
|
ProgressDots.displayName = "ProgressDots";
|
|
34681
35206
|
}
|
|
34682
35207
|
});
|
|
35208
|
+
var MathCanvas;
|
|
35209
|
+
var init_MathCanvas = __esm({
|
|
35210
|
+
"components/learning/molecules/MathCanvas.tsx"() {
|
|
35211
|
+
"use client";
|
|
35212
|
+
init_atoms();
|
|
35213
|
+
init_Stack();
|
|
35214
|
+
init_LearningCanvas();
|
|
35215
|
+
MathCanvas = ({
|
|
35216
|
+
className,
|
|
35217
|
+
width = 600,
|
|
35218
|
+
height = 400,
|
|
35219
|
+
title,
|
|
35220
|
+
xMin = -10,
|
|
35221
|
+
xMax = 10,
|
|
35222
|
+
yMin = -10,
|
|
35223
|
+
yMax = 10,
|
|
35224
|
+
showAxes = true,
|
|
35225
|
+
showGrid = true,
|
|
35226
|
+
gridStep = 1,
|
|
35227
|
+
curves = [],
|
|
35228
|
+
points = [],
|
|
35229
|
+
vectors = [],
|
|
35230
|
+
shapes = [],
|
|
35231
|
+
interactive = false,
|
|
35232
|
+
animate = false,
|
|
35233
|
+
onShapeClick,
|
|
35234
|
+
isLoading,
|
|
35235
|
+
error
|
|
35236
|
+
}) => {
|
|
35237
|
+
const derivedShapes = React105.useMemo(() => {
|
|
35238
|
+
const out = [];
|
|
35239
|
+
const margin = 24;
|
|
35240
|
+
const plotW = width - margin * 2;
|
|
35241
|
+
const plotH = height - margin * 2;
|
|
35242
|
+
const mapX = (x) => margin + (x - xMin) / (xMax - xMin) * plotW;
|
|
35243
|
+
const mapY = (y) => height - (margin + (y - yMin) / (yMax - yMin) * plotH);
|
|
35244
|
+
if (showGrid) {
|
|
35245
|
+
for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
|
|
35246
|
+
const px = mapX(x);
|
|
35247
|
+
out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#e5e7eb", lineWidth: 1 });
|
|
35248
|
+
}
|
|
35249
|
+
for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
|
|
35250
|
+
const py = mapY(y);
|
|
35251
|
+
out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#e5e7eb", lineWidth: 1 });
|
|
35252
|
+
}
|
|
35253
|
+
}
|
|
35254
|
+
if (showAxes) {
|
|
35255
|
+
const xAxisY = Math.max(margin, Math.min(height - margin, mapY(0)));
|
|
35256
|
+
const yAxisX = Math.max(margin, Math.min(width - margin, mapX(0)));
|
|
35257
|
+
out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: "#374151", lineWidth: 2 });
|
|
35258
|
+
out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: "#374151", lineWidth: 2 });
|
|
35259
|
+
}
|
|
35260
|
+
for (const curve of curves) {
|
|
35261
|
+
if (!curve.samples || curve.samples.length < 2) continue;
|
|
35262
|
+
for (let i = 1; i < curve.samples.length; i++) {
|
|
35263
|
+
const a = curve.samples[i - 1];
|
|
35264
|
+
const b = curve.samples[i];
|
|
35265
|
+
if (a.x < xMin || a.x > xMax || b.x < xMin || b.x > xMax) continue;
|
|
35266
|
+
out.push({
|
|
35267
|
+
type: "line",
|
|
35268
|
+
x1: mapX(a.x),
|
|
35269
|
+
y1: mapY(a.y),
|
|
35270
|
+
x2: mapX(b.x),
|
|
35271
|
+
y2: mapY(b.y),
|
|
35272
|
+
color: curve.color ?? "#2563eb",
|
|
35273
|
+
lineWidth: 2
|
|
35274
|
+
});
|
|
35275
|
+
}
|
|
35276
|
+
}
|
|
35277
|
+
for (const p2 of points) {
|
|
35278
|
+
if (p2.x < xMin || p2.x > xMax || p2.y < yMin || p2.y > yMax) continue;
|
|
35279
|
+
out.push({
|
|
35280
|
+
type: "circle",
|
|
35281
|
+
x: mapX(p2.x),
|
|
35282
|
+
y: mapY(p2.y),
|
|
35283
|
+
radius: p2.radius ?? 4,
|
|
35284
|
+
color: p2.color ?? "#dc2626",
|
|
35285
|
+
fill: p2.color ?? "#dc2626"
|
|
35286
|
+
});
|
|
35287
|
+
if (p2.label) {
|
|
35288
|
+
out.push({ type: "text", x: mapX(p2.x) + 8, y: mapY(p2.y) - 8, text: p2.label, color: "#111827", fontSize: 12 });
|
|
35289
|
+
}
|
|
35290
|
+
}
|
|
35291
|
+
for (const v of vectors) {
|
|
35292
|
+
if (v.x < xMin || v.x > xMax || v.y < yMin || v.y > yMax) continue;
|
|
35293
|
+
const x1 = mapX(v.x);
|
|
35294
|
+
const y1 = mapY(v.y);
|
|
35295
|
+
const x2 = mapX(v.x + v.vx);
|
|
35296
|
+
const y2 = mapY(v.y + v.vy);
|
|
35297
|
+
out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
|
|
35298
|
+
if (v.label) {
|
|
35299
|
+
out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: "#111827", fontSize: 12 });
|
|
35300
|
+
}
|
|
35301
|
+
}
|
|
35302
|
+
out.push(...shapes);
|
|
35303
|
+
return out;
|
|
35304
|
+
}, [width, height, xMin, xMax, yMin, yMax, showAxes, showGrid, gridStep, curves, points, vectors, shapes]);
|
|
35305
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
35306
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35307
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35308
|
+
LearningCanvas,
|
|
35309
|
+
{
|
|
35310
|
+
width,
|
|
35311
|
+
height,
|
|
35312
|
+
shapes: derivedShapes,
|
|
35313
|
+
interactive,
|
|
35314
|
+
animate,
|
|
35315
|
+
onShapeClick,
|
|
35316
|
+
isLoading,
|
|
35317
|
+
error
|
|
35318
|
+
}
|
|
35319
|
+
)
|
|
35320
|
+
] }) });
|
|
35321
|
+
};
|
|
35322
|
+
}
|
|
35323
|
+
});
|
|
35324
|
+
var PhysicsCanvas;
|
|
35325
|
+
var init_PhysicsCanvas = __esm({
|
|
35326
|
+
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
35327
|
+
"use client";
|
|
35328
|
+
init_atoms();
|
|
35329
|
+
init_Stack();
|
|
35330
|
+
init_LearningCanvas();
|
|
35331
|
+
PhysicsCanvas = ({
|
|
35332
|
+
className,
|
|
35333
|
+
width = 600,
|
|
35334
|
+
height = 400,
|
|
35335
|
+
title,
|
|
35336
|
+
backgroundColor,
|
|
35337
|
+
bodies = [],
|
|
35338
|
+
constraints = [],
|
|
35339
|
+
showVelocity = true,
|
|
35340
|
+
showForces = false,
|
|
35341
|
+
velocityScale = 20,
|
|
35342
|
+
forceScale = 20,
|
|
35343
|
+
shapes = [],
|
|
35344
|
+
interactive = false,
|
|
35345
|
+
animate = false,
|
|
35346
|
+
onShapeClick,
|
|
35347
|
+
isLoading,
|
|
35348
|
+
error
|
|
35349
|
+
}) => {
|
|
35350
|
+
const derivedShapes = React105.useMemo(() => {
|
|
35351
|
+
const out = [];
|
|
35352
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
35353
|
+
for (const b of bodies) {
|
|
35354
|
+
if (b.id) bodyById.set(b.id, b);
|
|
35355
|
+
}
|
|
35356
|
+
for (const c of constraints) {
|
|
35357
|
+
const a = bodyById.get(c.from);
|
|
35358
|
+
const b = bodyById.get(c.to);
|
|
35359
|
+
if (!a || !b) continue;
|
|
35360
|
+
out.push({
|
|
35361
|
+
type: "line",
|
|
35362
|
+
x1: a.x,
|
|
35363
|
+
y1: a.y,
|
|
35364
|
+
x2: b.x,
|
|
35365
|
+
y2: b.y,
|
|
35366
|
+
color: c.color ?? "#9ca3af",
|
|
35367
|
+
lineWidth: 2
|
|
35368
|
+
});
|
|
35369
|
+
}
|
|
35370
|
+
for (const b of bodies) {
|
|
35371
|
+
out.push({
|
|
35372
|
+
type: "circle",
|
|
35373
|
+
x: b.x,
|
|
35374
|
+
y: b.y,
|
|
35375
|
+
radius: b.radius ?? 12,
|
|
35376
|
+
color: b.color ?? "#2563eb",
|
|
35377
|
+
fill: b.color ?? "#2563eb",
|
|
35378
|
+
id: b.id
|
|
35379
|
+
});
|
|
35380
|
+
if (b.label) {
|
|
35381
|
+
out.push({
|
|
35382
|
+
type: "text",
|
|
35383
|
+
x: b.x + (b.radius ?? 12) + 6,
|
|
35384
|
+
y: b.y - (b.radius ?? 12) - 6,
|
|
35385
|
+
text: b.label,
|
|
35386
|
+
color: "#111827",
|
|
35387
|
+
fontSize: 12
|
|
35388
|
+
});
|
|
35389
|
+
}
|
|
35390
|
+
if (showVelocity && b.vx != null && b.vy != null && (b.vx !== 0 || b.vy !== 0)) {
|
|
35391
|
+
out.push({
|
|
35392
|
+
type: "arrow",
|
|
35393
|
+
x1: b.x,
|
|
35394
|
+
y1: b.y,
|
|
35395
|
+
x2: b.x + b.vx * velocityScale,
|
|
35396
|
+
y2: b.y + b.vy * velocityScale,
|
|
35397
|
+
color: "#16a34a",
|
|
35398
|
+
lineWidth: 2
|
|
35399
|
+
});
|
|
35400
|
+
}
|
|
35401
|
+
if (showForces && b.fx != null && b.fy != null && (b.fx !== 0 || b.fy !== 0)) {
|
|
35402
|
+
out.push({
|
|
35403
|
+
type: "arrow",
|
|
35404
|
+
x1: b.x,
|
|
35405
|
+
y1: b.y,
|
|
35406
|
+
x2: b.x + b.fx * forceScale,
|
|
35407
|
+
y2: b.y + b.fy * forceScale,
|
|
35408
|
+
color: "#dc2626",
|
|
35409
|
+
lineWidth: 2
|
|
35410
|
+
});
|
|
35411
|
+
}
|
|
35412
|
+
}
|
|
35413
|
+
out.push(...shapes);
|
|
35414
|
+
return out;
|
|
35415
|
+
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
35416
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
35417
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35418
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35419
|
+
LearningCanvas,
|
|
35420
|
+
{
|
|
35421
|
+
width,
|
|
35422
|
+
height,
|
|
35423
|
+
backgroundColor,
|
|
35424
|
+
shapes: derivedShapes,
|
|
35425
|
+
interactive,
|
|
35426
|
+
animate,
|
|
35427
|
+
onShapeClick,
|
|
35428
|
+
isLoading,
|
|
35429
|
+
error
|
|
35430
|
+
}
|
|
35431
|
+
)
|
|
35432
|
+
] }) });
|
|
35433
|
+
};
|
|
35434
|
+
}
|
|
35435
|
+
});
|
|
34683
35436
|
function resolveNodeColor(node, groups) {
|
|
34684
35437
|
if (node.color) return node.color;
|
|
34685
35438
|
if (node.group) {
|
|
@@ -35051,13 +35804,13 @@ var init_MapView = __esm({
|
|
|
35051
35804
|
shadowSize: [41, 41]
|
|
35052
35805
|
});
|
|
35053
35806
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
35054
|
-
const { useEffect:
|
|
35807
|
+
const { useEffect: useEffect75, useRef: useRef77, useCallback: useCallback112, useState: useState107 } = React105__namespace.default;
|
|
35055
35808
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
35056
35809
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
35057
35810
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
35058
35811
|
const map = useMap();
|
|
35059
|
-
const prevRef =
|
|
35060
|
-
|
|
35812
|
+
const prevRef = useRef77({ centerLat, centerLng, zoom });
|
|
35813
|
+
useEffect75(() => {
|
|
35061
35814
|
const prev = prevRef.current;
|
|
35062
35815
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
35063
35816
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -35068,7 +35821,7 @@ var init_MapView = __esm({
|
|
|
35068
35821
|
}
|
|
35069
35822
|
function MapClickHandler({ onMapClick }) {
|
|
35070
35823
|
const map = useMap();
|
|
35071
|
-
|
|
35824
|
+
useEffect75(() => {
|
|
35072
35825
|
if (!onMapClick) return;
|
|
35073
35826
|
const handler = (e) => {
|
|
35074
35827
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -43371,7 +44124,7 @@ function getGroupColor(group, groups) {
|
|
|
43371
44124
|
const idx = groups.indexOf(group);
|
|
43372
44125
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
43373
44126
|
}
|
|
43374
|
-
function
|
|
44127
|
+
function resolveColor3(color, el) {
|
|
43375
44128
|
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
43376
44129
|
if (!m) return color;
|
|
43377
44130
|
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
@@ -43632,7 +44385,7 @@ var init_GraphCanvas = __esm({
|
|
|
43632
44385
|
const w = logicalW;
|
|
43633
44386
|
const h = height;
|
|
43634
44387
|
const nodes = nodesRef.current;
|
|
43635
|
-
const accentColor =
|
|
44388
|
+
const accentColor = resolveColor3("var(--color-accent)", canvas);
|
|
43636
44389
|
const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
|
|
43637
44390
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
43638
44391
|
ctx.clearRect(0, 0, w, h);
|
|
@@ -43671,7 +44424,7 @@ var init_GraphCanvas = __esm({
|
|
|
43671
44424
|
ctx.globalAlpha = 1;
|
|
43672
44425
|
for (const node of nodes) {
|
|
43673
44426
|
const size = node.size || 8;
|
|
43674
|
-
const color =
|
|
44427
|
+
const color = resolveColor3(node.color || getGroupColor(node.group, groups), canvas);
|
|
43675
44428
|
const isHovered = hoveredNode === node.id;
|
|
43676
44429
|
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
43677
44430
|
ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
|
|
@@ -50569,6 +51322,7 @@ var init_component_registry_generated = __esm({
|
|
|
50569
51322
|
init_BattleBoard();
|
|
50570
51323
|
init_BattleTemplate();
|
|
50571
51324
|
init_BehaviorView();
|
|
51325
|
+
init_BiologyCanvas();
|
|
50572
51326
|
init_BloomQuizBlock();
|
|
50573
51327
|
init_BoardgameBoard();
|
|
50574
51328
|
init_BookChapterView();
|
|
@@ -50598,6 +51352,7 @@ var init_component_registry_generated = __esm({
|
|
|
50598
51352
|
init_ChartLegend();
|
|
50599
51353
|
init_ChatBar();
|
|
50600
51354
|
init_Checkbox();
|
|
51355
|
+
init_ChemistryCanvas();
|
|
50601
51356
|
init_ChoiceButton();
|
|
50602
51357
|
init_CityBuilderBoard();
|
|
50603
51358
|
init_CityBuilderTemplate();
|
|
@@ -50689,6 +51444,7 @@ var init_component_registry_generated = __esm({
|
|
|
50689
51444
|
init_JazariStateMachine();
|
|
50690
51445
|
init_LandingPageTemplate();
|
|
50691
51446
|
init_LawReferenceTooltip();
|
|
51447
|
+
init_LearningCanvas();
|
|
50692
51448
|
init_Lightbox();
|
|
50693
51449
|
init_LikertScale();
|
|
50694
51450
|
init_LineChart();
|
|
@@ -50697,9 +51453,11 @@ var init_component_registry_generated = __esm({
|
|
|
50697
51453
|
init_MapView();
|
|
50698
51454
|
init_MarkdownContent();
|
|
50699
51455
|
init_MarketingFooter();
|
|
51456
|
+
init_MarketingStatCard();
|
|
50700
51457
|
init_MasterDetail();
|
|
50701
51458
|
init_MasterDetailLayout();
|
|
50702
51459
|
init_MatchPuzzleBoard();
|
|
51460
|
+
init_MathCanvas();
|
|
50703
51461
|
init_MatrixQuestion();
|
|
50704
51462
|
init_MediaGallery();
|
|
50705
51463
|
init_Menu();
|
|
@@ -50718,6 +51476,7 @@ var init_component_registry_generated = __esm({
|
|
|
50718
51476
|
init_PageHeader();
|
|
50719
51477
|
init_Pagination();
|
|
50720
51478
|
init_PatternTile();
|
|
51479
|
+
init_PhysicsCanvas();
|
|
50721
51480
|
init_PinballBoard();
|
|
50722
51481
|
init_PirateBoard();
|
|
50723
51482
|
init_PlatformerBoard();
|
|
@@ -50894,6 +51653,7 @@ var init_component_registry_generated = __esm({
|
|
|
50894
51653
|
"BattleBoard": BattleBoard,
|
|
50895
51654
|
"BattleTemplate": BattleTemplate,
|
|
50896
51655
|
"BehaviorView": BehaviorView,
|
|
51656
|
+
"BiologyCanvas": BiologyCanvas,
|
|
50897
51657
|
"BloomQuizBlock": BloomQuizBlock,
|
|
50898
51658
|
"BoardgameBoard": BoardgameBoard,
|
|
50899
51659
|
"BookChapterView": BookChapterView,
|
|
@@ -50926,6 +51686,7 @@ var init_component_registry_generated = __esm({
|
|
|
50926
51686
|
"ChartLegend": ChartLegend,
|
|
50927
51687
|
"ChatBar": ChatBar,
|
|
50928
51688
|
"Checkbox": Checkbox,
|
|
51689
|
+
"ChemistryCanvas": ChemistryCanvas,
|
|
50929
51690
|
"ChoiceButton": ChoiceButton,
|
|
50930
51691
|
"CityBuilderBoard": CityBuilderBoard,
|
|
50931
51692
|
"CityBuilderTemplate": CityBuilderTemplate,
|
|
@@ -51027,6 +51788,7 @@ var init_component_registry_generated = __esm({
|
|
|
51027
51788
|
"LabelPattern": LabelPattern,
|
|
51028
51789
|
"LandingPageTemplate": LandingPageTemplate,
|
|
51029
51790
|
"LawReferenceTooltip": LawReferenceTooltip,
|
|
51791
|
+
"LearningCanvas": LearningCanvas,
|
|
51030
51792
|
"Lightbox": Lightbox,
|
|
51031
51793
|
"LikertScale": LikertScale,
|
|
51032
51794
|
"LineChart": LineChart2,
|
|
@@ -51035,9 +51797,11 @@ var init_component_registry_generated = __esm({
|
|
|
51035
51797
|
"MapView": MapView,
|
|
51036
51798
|
"MarkdownContent": MarkdownContent,
|
|
51037
51799
|
"MarketingFooter": MarketingFooter,
|
|
51800
|
+
"MarketingStatCard": MarketingStatCard,
|
|
51038
51801
|
"MasterDetail": MasterDetail,
|
|
51039
51802
|
"MasterDetailLayout": MasterDetailLayout,
|
|
51040
51803
|
"MatchPuzzleBoard": MatchPuzzleBoard,
|
|
51804
|
+
"MathCanvas": MathCanvas,
|
|
51041
51805
|
"MatrixQuestion": MatrixQuestion,
|
|
51042
51806
|
"MediaGallery": MediaGallery,
|
|
51043
51807
|
"Menu": Menu,
|
|
@@ -51056,6 +51820,7 @@ var init_component_registry_generated = __esm({
|
|
|
51056
51820
|
"PageHeader": PageHeader,
|
|
51057
51821
|
"Pagination": Pagination,
|
|
51058
51822
|
"PatternTile": PatternTile,
|
|
51823
|
+
"PhysicsCanvas": PhysicsCanvas,
|
|
51059
51824
|
"PinballBoard": PinballBoard,
|
|
51060
51825
|
"PirateBoard": PirateBoard,
|
|
51061
51826
|
"PlatformerBoard": PlatformerBoard,
|