@almadar/ui 5.77.0 → 5.79.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 +863 -98
- package/dist/avl/index.css +3 -3
- package/dist/avl/index.js +863 -98
- package/dist/components/core/atoms/FlipContainer.d.ts +1 -1
- package/dist/components/core/atoms/index.d.ts +2 -1
- package/dist/components/core/molecules/Card.d.ts +1 -1
- package/dist/components/core/molecules/DataGrid.d.ts +1 -1
- package/dist/components/core/molecules/DataList.d.ts +1 -1
- package/dist/components/core/molecules/DocPagination.d.ts +8 -1
- package/dist/components/core/molecules/DocSearch.d.ts +8 -1
- package/dist/components/core/molecules/FlipCard.d.ts +1 -1
- package/dist/components/core/molecules/MapView.d.ts +18 -1
- package/dist/components/core/molecules/PropertyInspector.d.ts +2 -0
- package/dist/components/core/molecules/SortableList.d.ts +1 -1
- package/dist/components/core/molecules/TableView.d.ts +1 -1
- package/dist/components/core/molecules/index.d.ts +4 -0
- package/dist/components/core/organisms/DataTable.d.ts +1 -1
- package/dist/components/core/organisms/debug/RuntimeDebugger.d.ts +10 -1
- package/dist/components/core/organisms/debug/tabs/EntitiesTab.d.ts +2 -1
- package/dist/components/core/organisms/debug/tabs/EventDispatcherTab.d.ts +2 -1
- package/dist/components/core/organisms/debug/tabs/EventFlowTab.d.ts +6 -1
- package/dist/components/core/organisms/debug/tabs/GuardsPanel.d.ts +6 -1
- package/dist/components/core/organisms/debug/tabs/ServerBridgeTab.d.ts +12 -1
- package/dist/components/core/organisms/debug/tabs/TicksTab.d.ts +2 -1
- package/dist/components/core/organisms/debug/tabs/TraitsTab.d.ts +2 -1
- package/dist/components/core/organisms/debug/tabs/TransitionTimeline.d.ts +11 -1
- package/dist/components/core/organisms/debug/tabs/VerificationTab.d.ts +8 -1
- package/dist/components/game/2d/atoms/ActionButton.d.ts +2 -1
- package/dist/components/game/2d/atoms/ChoiceButton.d.ts +2 -1
- package/dist/components/game/2d/atoms/ComboCounter.d.ts +2 -1
- package/dist/components/game/2d/atoms/ControlButton.d.ts +2 -1
- package/dist/components/game/2d/atoms/DamageNumber.d.ts +2 -1
- package/dist/components/game/2d/atoms/DialogueBubble.d.ts +2 -1
- package/dist/components/game/2d/atoms/GameIcon.d.ts +2 -1
- package/dist/components/game/2d/atoms/HealthBar.d.ts +2 -1
- package/dist/components/game/2d/atoms/ItemSlot.d.ts +2 -1
- package/dist/components/game/2d/atoms/MiniMap.d.ts +2 -1
- package/dist/components/game/2d/atoms/ResourceCounter.d.ts +2 -1
- package/dist/components/game/2d/atoms/ScoreDisplay.d.ts +2 -1
- package/dist/components/game/2d/atoms/StatusEffect.d.ts +2 -1
- package/dist/components/game/2d/atoms/TimerDisplay.d.ts +2 -1
- package/dist/components/game/2d/atoms/TurnIndicator.d.ts +2 -1
- package/dist/components/game/2d/atoms/WaypointMarker.d.ts +2 -1
- package/dist/components/game/2d/molecules/GameHud.d.ts +2 -1
- package/dist/components/game/2d/molecules/GameMenu.d.ts +2 -1
- package/dist/components/game/2d/molecules/InventoryGrid.d.ts +2 -1
- package/dist/components/game/2d/molecules/ResourceBar.d.ts +2 -1
- package/dist/components/game/2d/molecules/StatBadge.d.ts +2 -1
- package/dist/components/game/shared/lib/editorUtils.d.ts +8 -8
- package/dist/components/index.cjs +2212 -1525
- package/dist/components/index.css +3 -3
- package/dist/components/index.js +1002 -315
- 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/hooks/useGitHub.d.ts +7 -7
- package/dist/marketing/index.cjs +2 -2
- package/dist/marketing/index.js +2 -2
- package/dist/providers/EventBusProvider.d.ts +1 -1
- package/dist/providers/SelectionProvider.d.ts +1 -1
- package/dist/providers/ServerBridge.d.ts +1 -1
- package/dist/providers/index.cjs +859 -94
- package/dist/providers/index.css +3 -3
- package/dist/providers/index.js +859 -94
- package/dist/runtime/index.cjs +859 -94
- package/dist/runtime/index.css +3 -3
- package/dist/runtime/index.js +859 -94
- package/package.json +1 -1
package/dist/runtime/index.js
CHANGED
|
@@ -6180,6 +6180,66 @@ var init_RangeSlider = __esm({
|
|
|
6180
6180
|
RangeSlider.displayName = "RangeSlider";
|
|
6181
6181
|
}
|
|
6182
6182
|
});
|
|
6183
|
+
function easeOut(t) {
|
|
6184
|
+
return t * (2 - t);
|
|
6185
|
+
}
|
|
6186
|
+
var AnimatedCounter;
|
|
6187
|
+
var init_AnimatedCounter = __esm({
|
|
6188
|
+
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
6189
|
+
"use client";
|
|
6190
|
+
init_cn();
|
|
6191
|
+
init_Typography();
|
|
6192
|
+
AnimatedCounter = ({
|
|
6193
|
+
value: rawValue,
|
|
6194
|
+
duration = 600,
|
|
6195
|
+
prefix,
|
|
6196
|
+
suffix,
|
|
6197
|
+
className
|
|
6198
|
+
}) => {
|
|
6199
|
+
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
6200
|
+
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
6201
|
+
const [displayValue, setDisplayValue] = useState(value);
|
|
6202
|
+
const previousValueRef = useRef(value);
|
|
6203
|
+
const animationFrameRef = useRef(null);
|
|
6204
|
+
useEffect(() => {
|
|
6205
|
+
const from = previousValueRef.current;
|
|
6206
|
+
const to = value;
|
|
6207
|
+
previousValueRef.current = value;
|
|
6208
|
+
if (from === to) {
|
|
6209
|
+
setDisplayValue(to);
|
|
6210
|
+
return;
|
|
6211
|
+
}
|
|
6212
|
+
const startTime = performance.now();
|
|
6213
|
+
const diff = to - from;
|
|
6214
|
+
function animate(currentTime) {
|
|
6215
|
+
const elapsed = currentTime - startTime;
|
|
6216
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
6217
|
+
const easedProgress = easeOut(progress);
|
|
6218
|
+
setDisplayValue(from + diff * easedProgress);
|
|
6219
|
+
if (progress < 1) {
|
|
6220
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
6221
|
+
} else {
|
|
6222
|
+
setDisplayValue(to);
|
|
6223
|
+
}
|
|
6224
|
+
}
|
|
6225
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
6226
|
+
return () => {
|
|
6227
|
+
if (animationFrameRef.current !== null) {
|
|
6228
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
6229
|
+
}
|
|
6230
|
+
};
|
|
6231
|
+
}, [value, duration]);
|
|
6232
|
+
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
6233
|
+
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
6234
|
+
return /* @__PURE__ */ jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
6235
|
+
prefix,
|
|
6236
|
+
formattedValue,
|
|
6237
|
+
suffix
|
|
6238
|
+
] });
|
|
6239
|
+
};
|
|
6240
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
6241
|
+
}
|
|
6242
|
+
});
|
|
6183
6243
|
var InfiniteScrollSentinel;
|
|
6184
6244
|
var init_InfiniteScrollSentinel = __esm({
|
|
6185
6245
|
"components/core/atoms/InfiniteScrollSentinel.tsx"() {
|
|
@@ -6441,6 +6501,34 @@ var init_SectionHeader = __esm({
|
|
|
6441
6501
|
SectionHeader.displayName = "SectionHeader";
|
|
6442
6502
|
}
|
|
6443
6503
|
});
|
|
6504
|
+
var sizeClasses6, MarketingStatCard;
|
|
6505
|
+
var init_MarketingStatCard = __esm({
|
|
6506
|
+
"components/marketing/atoms/MarketingStatCard.tsx"() {
|
|
6507
|
+
init_cn();
|
|
6508
|
+
init_Stack();
|
|
6509
|
+
init_Typography();
|
|
6510
|
+
sizeClasses6 = {
|
|
6511
|
+
sm: "text-2xl",
|
|
6512
|
+
md: "text-4xl",
|
|
6513
|
+
lg: "text-5xl"
|
|
6514
|
+
};
|
|
6515
|
+
MarketingStatCard = ({ value, label, size = "md", className }) => {
|
|
6516
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", className: cn(className), children: [
|
|
6517
|
+
/* @__PURE__ */ jsx(
|
|
6518
|
+
Typography,
|
|
6519
|
+
{
|
|
6520
|
+
weight: "bold",
|
|
6521
|
+
color: "primary",
|
|
6522
|
+
className: cn(sizeClasses6[size]),
|
|
6523
|
+
children: value
|
|
6524
|
+
}
|
|
6525
|
+
),
|
|
6526
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
6527
|
+
] });
|
|
6528
|
+
};
|
|
6529
|
+
MarketingStatCard.displayName = "MarketingStatCard";
|
|
6530
|
+
}
|
|
6531
|
+
});
|
|
6444
6532
|
var backgroundClasses, paddingClasses, ContentSection;
|
|
6445
6533
|
var init_ContentSection = __esm({
|
|
6446
6534
|
"components/marketing/atoms/ContentSection.tsx"() {
|
|
@@ -20106,6 +20194,315 @@ var init_molecules = __esm({
|
|
|
20106
20194
|
init_puzzleObject();
|
|
20107
20195
|
}
|
|
20108
20196
|
});
|
|
20197
|
+
function resolveColor2(color, ctx, fallback) {
|
|
20198
|
+
if (!color) return fallback;
|
|
20199
|
+
if (color.startsWith("var(")) {
|
|
20200
|
+
ctx.canvas.style;
|
|
20201
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color);
|
|
20202
|
+
if (m) {
|
|
20203
|
+
const computed = getComputedStyle(ctx.canvas).getPropertyValue(m[1]).trim();
|
|
20204
|
+
return computed || m[2]?.trim() || fallback;
|
|
20205
|
+
}
|
|
20206
|
+
}
|
|
20207
|
+
return color;
|
|
20208
|
+
}
|
|
20209
|
+
function shapeBounds(shape) {
|
|
20210
|
+
switch (shape.type) {
|
|
20211
|
+
case "line":
|
|
20212
|
+
case "arrow":
|
|
20213
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) return null;
|
|
20214
|
+
return {
|
|
20215
|
+
x: Math.min(shape.x1, shape.x2) - 6,
|
|
20216
|
+
y: Math.min(shape.y1, shape.y2) - 6,
|
|
20217
|
+
w: Math.abs(shape.x2 - shape.x1) + 12,
|
|
20218
|
+
h: Math.abs(shape.y2 - shape.y1) + 12
|
|
20219
|
+
};
|
|
20220
|
+
case "circle":
|
|
20221
|
+
if (shape.x == null || shape.y == null || shape.radius == null) return null;
|
|
20222
|
+
return {
|
|
20223
|
+
x: shape.x - shape.radius - 4,
|
|
20224
|
+
y: shape.y - shape.radius - 4,
|
|
20225
|
+
w: shape.radius * 2 + 8,
|
|
20226
|
+
h: shape.radius * 2 + 8
|
|
20227
|
+
};
|
|
20228
|
+
case "rect":
|
|
20229
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) return null;
|
|
20230
|
+
return { x: shape.x - 4, y: shape.y - 4, w: shape.width + 8, h: shape.height + 8 };
|
|
20231
|
+
case "polygon":
|
|
20232
|
+
if (!shape.points || shape.points.length === 0) return null;
|
|
20233
|
+
{
|
|
20234
|
+
const xs = shape.points.map((p2) => p2.x);
|
|
20235
|
+
const ys = shape.points.map((p2) => p2.y);
|
|
20236
|
+
const minX = Math.min(...xs);
|
|
20237
|
+
const minY = Math.min(...ys);
|
|
20238
|
+
return {
|
|
20239
|
+
x: minX - 4,
|
|
20240
|
+
y: minY - 4,
|
|
20241
|
+
w: Math.max(...xs) - minX + 8,
|
|
20242
|
+
h: Math.max(...ys) - minY + 8
|
|
20243
|
+
};
|
|
20244
|
+
}
|
|
20245
|
+
case "text":
|
|
20246
|
+
if (shape.x == null || shape.y == null) return null;
|
|
20247
|
+
return { x: shape.x - 4, y: shape.y - (shape.fontSize ?? 14) - 4, w: 120, h: (shape.fontSize ?? 14) + 8 };
|
|
20248
|
+
default:
|
|
20249
|
+
return null;
|
|
20250
|
+
}
|
|
20251
|
+
}
|
|
20252
|
+
function drawArrowHead(ctx, x1, y1, x2, y2, size) {
|
|
20253
|
+
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
20254
|
+
ctx.beginPath();
|
|
20255
|
+
ctx.moveTo(x2, y2);
|
|
20256
|
+
ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
|
|
20257
|
+
ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
|
|
20258
|
+
ctx.closePath();
|
|
20259
|
+
ctx.fill();
|
|
20260
|
+
}
|
|
20261
|
+
function drawShape(ctx, shape, width, height) {
|
|
20262
|
+
ctx.save();
|
|
20263
|
+
const opacity = shape.opacity ?? 1;
|
|
20264
|
+
ctx.globalAlpha = opacity;
|
|
20265
|
+
const stroke = resolveColor2(shape.color, ctx, "#333333");
|
|
20266
|
+
const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
|
|
20267
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
20268
|
+
switch (shape.type) {
|
|
20269
|
+
case "grid": {
|
|
20270
|
+
const step = shape.step ?? 40;
|
|
20271
|
+
ctx.strokeStyle = stroke;
|
|
20272
|
+
ctx.globalAlpha = opacity * 0.25;
|
|
20273
|
+
ctx.lineWidth = 1;
|
|
20274
|
+
ctx.beginPath();
|
|
20275
|
+
for (let x = 0; x <= width; x += step) {
|
|
20276
|
+
ctx.moveTo(x, 0);
|
|
20277
|
+
ctx.lineTo(x, height);
|
|
20278
|
+
}
|
|
20279
|
+
for (let y = 0; y <= height; y += step) {
|
|
20280
|
+
ctx.moveTo(0, y);
|
|
20281
|
+
ctx.lineTo(width, y);
|
|
20282
|
+
}
|
|
20283
|
+
ctx.stroke();
|
|
20284
|
+
break;
|
|
20285
|
+
}
|
|
20286
|
+
case "axis": {
|
|
20287
|
+
const axis = shape.axis ?? "x";
|
|
20288
|
+
ctx.strokeStyle = stroke;
|
|
20289
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
20290
|
+
ctx.beginPath();
|
|
20291
|
+
if (axis === "x") {
|
|
20292
|
+
ctx.moveTo(0, height / 2);
|
|
20293
|
+
ctx.lineTo(width, height / 2);
|
|
20294
|
+
} else {
|
|
20295
|
+
ctx.moveTo(width / 2, 0);
|
|
20296
|
+
ctx.lineTo(width / 2, height);
|
|
20297
|
+
}
|
|
20298
|
+
ctx.stroke();
|
|
20299
|
+
break;
|
|
20300
|
+
}
|
|
20301
|
+
case "line": {
|
|
20302
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
20303
|
+
ctx.strokeStyle = stroke;
|
|
20304
|
+
ctx.beginPath();
|
|
20305
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
20306
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
20307
|
+
ctx.stroke();
|
|
20308
|
+
break;
|
|
20309
|
+
}
|
|
20310
|
+
case "arrow": {
|
|
20311
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
20312
|
+
ctx.strokeStyle = stroke;
|
|
20313
|
+
ctx.fillStyle = stroke;
|
|
20314
|
+
ctx.beginPath();
|
|
20315
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
20316
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
20317
|
+
ctx.stroke();
|
|
20318
|
+
drawArrowHead(ctx, shape.x1, shape.y1, shape.x2, shape.y2, 10);
|
|
20319
|
+
break;
|
|
20320
|
+
}
|
|
20321
|
+
case "circle": {
|
|
20322
|
+
if (shape.x == null || shape.y == null || shape.radius == null) break;
|
|
20323
|
+
ctx.beginPath();
|
|
20324
|
+
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
|
|
20325
|
+
if (fill) {
|
|
20326
|
+
ctx.fillStyle = fill;
|
|
20327
|
+
ctx.fill();
|
|
20328
|
+
}
|
|
20329
|
+
ctx.strokeStyle = stroke;
|
|
20330
|
+
ctx.stroke();
|
|
20331
|
+
break;
|
|
20332
|
+
}
|
|
20333
|
+
case "rect": {
|
|
20334
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) break;
|
|
20335
|
+
if (fill) {
|
|
20336
|
+
ctx.fillStyle = fill;
|
|
20337
|
+
ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
|
|
20338
|
+
}
|
|
20339
|
+
ctx.strokeStyle = stroke;
|
|
20340
|
+
ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
|
|
20341
|
+
break;
|
|
20342
|
+
}
|
|
20343
|
+
case "polygon": {
|
|
20344
|
+
if (!shape.points || shape.points.length < 2) break;
|
|
20345
|
+
ctx.beginPath();
|
|
20346
|
+
ctx.moveTo(shape.points[0].x, shape.points[0].y);
|
|
20347
|
+
for (let i = 1; i < shape.points.length; i++) {
|
|
20348
|
+
ctx.lineTo(shape.points[i].x, shape.points[i].y);
|
|
20349
|
+
}
|
|
20350
|
+
ctx.closePath();
|
|
20351
|
+
if (fill) {
|
|
20352
|
+
ctx.fillStyle = fill;
|
|
20353
|
+
ctx.fill();
|
|
20354
|
+
}
|
|
20355
|
+
ctx.strokeStyle = stroke;
|
|
20356
|
+
ctx.stroke();
|
|
20357
|
+
break;
|
|
20358
|
+
}
|
|
20359
|
+
case "path": {
|
|
20360
|
+
if (!shape.path) break;
|
|
20361
|
+
const p2 = new Path2D(shape.path);
|
|
20362
|
+
if (fill) {
|
|
20363
|
+
ctx.fillStyle = fill;
|
|
20364
|
+
ctx.fill(p2);
|
|
20365
|
+
}
|
|
20366
|
+
ctx.strokeStyle = stroke;
|
|
20367
|
+
ctx.stroke(p2);
|
|
20368
|
+
break;
|
|
20369
|
+
}
|
|
20370
|
+
case "text": {
|
|
20371
|
+
if (shape.x == null || shape.y == null || !shape.text) break;
|
|
20372
|
+
ctx.fillStyle = stroke;
|
|
20373
|
+
ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
|
|
20374
|
+
ctx.textAlign = shape.align ?? "left";
|
|
20375
|
+
ctx.textBaseline = "middle";
|
|
20376
|
+
ctx.fillText(shape.text, shape.x, shape.y);
|
|
20377
|
+
break;
|
|
20378
|
+
}
|
|
20379
|
+
}
|
|
20380
|
+
ctx.restore();
|
|
20381
|
+
}
|
|
20382
|
+
var LearningCanvas;
|
|
20383
|
+
var init_LearningCanvas = __esm({
|
|
20384
|
+
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
20385
|
+
"use client";
|
|
20386
|
+
init_cn();
|
|
20387
|
+
init_useEventBus();
|
|
20388
|
+
LearningCanvas = ({
|
|
20389
|
+
className,
|
|
20390
|
+
width = 600,
|
|
20391
|
+
height = 400,
|
|
20392
|
+
backgroundColor,
|
|
20393
|
+
shapes = [],
|
|
20394
|
+
interactive = false,
|
|
20395
|
+
animate = false,
|
|
20396
|
+
onShapeClick,
|
|
20397
|
+
onShapeHover,
|
|
20398
|
+
isLoading,
|
|
20399
|
+
error
|
|
20400
|
+
}) => {
|
|
20401
|
+
const canvasRef = useRef(null);
|
|
20402
|
+
const eventBus = useEventBus();
|
|
20403
|
+
const animRef = useRef(0);
|
|
20404
|
+
const hoverIndexRef = useRef(-1);
|
|
20405
|
+
const findShapeAt = useCallback((clientX, clientY) => {
|
|
20406
|
+
const canvas = canvasRef.current;
|
|
20407
|
+
if (!canvas) return -1;
|
|
20408
|
+
const rect = canvas.getBoundingClientRect();
|
|
20409
|
+
const x = clientX - rect.left;
|
|
20410
|
+
const y = clientY - rect.top;
|
|
20411
|
+
for (let i = shapes.length - 1; i >= 0; i--) {
|
|
20412
|
+
const b = shapeBounds(shapes[i]);
|
|
20413
|
+
if (b && x >= b.x && x <= b.x + b.w && y >= b.y && y <= b.y + b.h) {
|
|
20414
|
+
return i;
|
|
20415
|
+
}
|
|
20416
|
+
}
|
|
20417
|
+
return -1;
|
|
20418
|
+
}, [shapes]);
|
|
20419
|
+
const draw = useCallback(() => {
|
|
20420
|
+
const canvas = canvasRef.current;
|
|
20421
|
+
if (!canvas) return;
|
|
20422
|
+
const ctx = canvas.getContext("2d");
|
|
20423
|
+
if (!ctx) return;
|
|
20424
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
20425
|
+
canvas.width = Math.max(1, Math.floor(width * dpr));
|
|
20426
|
+
canvas.height = Math.max(1, Math.floor(height * dpr));
|
|
20427
|
+
canvas.style.width = `${width}px`;
|
|
20428
|
+
canvas.style.height = `${height}px`;
|
|
20429
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
20430
|
+
ctx.clearRect(0, 0, width, height);
|
|
20431
|
+
if (backgroundColor) {
|
|
20432
|
+
ctx.fillStyle = backgroundColor;
|
|
20433
|
+
ctx.fillRect(0, 0, width, height);
|
|
20434
|
+
}
|
|
20435
|
+
for (const shape of shapes) {
|
|
20436
|
+
drawShape(ctx, shape, width, height);
|
|
20437
|
+
}
|
|
20438
|
+
}, [width, height, backgroundColor, shapes]);
|
|
20439
|
+
useEffect(() => {
|
|
20440
|
+
draw();
|
|
20441
|
+
}, [draw]);
|
|
20442
|
+
useEffect(() => {
|
|
20443
|
+
if (!animate) return;
|
|
20444
|
+
const loop = () => {
|
|
20445
|
+
draw();
|
|
20446
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20447
|
+
};
|
|
20448
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20449
|
+
return () => cancelAnimationFrame(animRef.current);
|
|
20450
|
+
}, [animate, draw]);
|
|
20451
|
+
const handlePointerMove = useCallback(
|
|
20452
|
+
(e) => {
|
|
20453
|
+
if (!interactive) return;
|
|
20454
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20455
|
+
if (idx !== hoverIndexRef.current) {
|
|
20456
|
+
hoverIndexRef.current = idx;
|
|
20457
|
+
if (idx >= 0) {
|
|
20458
|
+
const shape = shapes[idx];
|
|
20459
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20460
|
+
if (onShapeHover) onShapeHover(payload);
|
|
20461
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_HOVER`, payload);
|
|
20462
|
+
}
|
|
20463
|
+
}
|
|
20464
|
+
},
|
|
20465
|
+
[interactive, onShapeHover, eventBus, findShapeAt, shapes]
|
|
20466
|
+
);
|
|
20467
|
+
const handleClick = useCallback(
|
|
20468
|
+
(e) => {
|
|
20469
|
+
if (!interactive) return;
|
|
20470
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20471
|
+
if (idx >= 0) {
|
|
20472
|
+
const shape = shapes[idx];
|
|
20473
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20474
|
+
if (onShapeClick) onShapeClick(payload);
|
|
20475
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_CLICK`, payload);
|
|
20476
|
+
}
|
|
20477
|
+
},
|
|
20478
|
+
[interactive, onShapeClick, eventBus, findShapeAt, shapes]
|
|
20479
|
+
);
|
|
20480
|
+
if (isLoading || error) {
|
|
20481
|
+
return /* @__PURE__ */ jsx(
|
|
20482
|
+
"div",
|
|
20483
|
+
{
|
|
20484
|
+
className: cn(
|
|
20485
|
+
"flex items-center justify-center rounded border border-border bg-surface",
|
|
20486
|
+
className
|
|
20487
|
+
),
|
|
20488
|
+
style: { width, height },
|
|
20489
|
+
children: error ? /* @__PURE__ */ jsx("span", { className: "text-sm text-destructive", children: error.message }) : /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading canvas\u2026" })
|
|
20490
|
+
}
|
|
20491
|
+
);
|
|
20492
|
+
}
|
|
20493
|
+
return /* @__PURE__ */ jsx(
|
|
20494
|
+
"canvas",
|
|
20495
|
+
{
|
|
20496
|
+
ref: canvasRef,
|
|
20497
|
+
className: cn("block touch-none rounded border border-border", className),
|
|
20498
|
+
style: { width, height },
|
|
20499
|
+
onClick: handleClick,
|
|
20500
|
+
onPointerMove: handlePointerMove
|
|
20501
|
+
}
|
|
20502
|
+
);
|
|
20503
|
+
};
|
|
20504
|
+
}
|
|
20505
|
+
});
|
|
20109
20506
|
|
|
20110
20507
|
// components/core/atoms/index.ts
|
|
20111
20508
|
var init_atoms = __esm({
|
|
@@ -21591,91 +21988,6 @@ var init_ComponentPatterns = __esm({
|
|
|
21591
21988
|
AlertPattern.displayName = "AlertPattern";
|
|
21592
21989
|
}
|
|
21593
21990
|
});
|
|
21594
|
-
function parseValue(value) {
|
|
21595
|
-
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
21596
|
-
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
21597
|
-
if (!match) {
|
|
21598
|
-
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
21599
|
-
}
|
|
21600
|
-
const numStr = match[2];
|
|
21601
|
-
const decimalIdx = numStr.indexOf(".");
|
|
21602
|
-
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
21603
|
-
return {
|
|
21604
|
-
prefix: match[1],
|
|
21605
|
-
num: parseFloat(numStr),
|
|
21606
|
-
suffix: match[3],
|
|
21607
|
-
decimals
|
|
21608
|
-
};
|
|
21609
|
-
}
|
|
21610
|
-
var AnimatedCounter;
|
|
21611
|
-
var init_AnimatedCounter = __esm({
|
|
21612
|
-
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
21613
|
-
"use client";
|
|
21614
|
-
init_cn();
|
|
21615
|
-
init_Box();
|
|
21616
|
-
init_Typography();
|
|
21617
|
-
AnimatedCounter = ({
|
|
21618
|
-
value,
|
|
21619
|
-
label,
|
|
21620
|
-
duration = 1500,
|
|
21621
|
-
className
|
|
21622
|
-
}) => {
|
|
21623
|
-
const ref = useRef(null);
|
|
21624
|
-
const [displayValue, setDisplayValue] = useState("0");
|
|
21625
|
-
const [hasAnimated, setHasAnimated] = useState(false);
|
|
21626
|
-
const animate = useCallback(() => {
|
|
21627
|
-
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
21628
|
-
if (num2 === 0) {
|
|
21629
|
-
setDisplayValue(String(value));
|
|
21630
|
-
return;
|
|
21631
|
-
}
|
|
21632
|
-
const startTime = performance.now();
|
|
21633
|
-
const tick = (now2) => {
|
|
21634
|
-
const elapsed = now2 - startTime;
|
|
21635
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
21636
|
-
const eased = 1 - Math.pow(1 - progress, 3);
|
|
21637
|
-
const current = eased * num2;
|
|
21638
|
-
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
21639
|
-
if (progress < 1) {
|
|
21640
|
-
requestAnimationFrame(tick);
|
|
21641
|
-
} else {
|
|
21642
|
-
setDisplayValue(String(value));
|
|
21643
|
-
}
|
|
21644
|
-
};
|
|
21645
|
-
requestAnimationFrame(tick);
|
|
21646
|
-
}, [value, duration]);
|
|
21647
|
-
useEffect(() => {
|
|
21648
|
-
if (hasAnimated) return;
|
|
21649
|
-
const el = ref.current;
|
|
21650
|
-
if (!el) return;
|
|
21651
|
-
const observer2 = new IntersectionObserver(
|
|
21652
|
-
(entries) => {
|
|
21653
|
-
if (entries[0].isIntersecting) {
|
|
21654
|
-
setHasAnimated(true);
|
|
21655
|
-
animate();
|
|
21656
|
-
observer2.disconnect();
|
|
21657
|
-
}
|
|
21658
|
-
},
|
|
21659
|
-
{ threshold: 0.3 }
|
|
21660
|
-
);
|
|
21661
|
-
observer2.observe(el);
|
|
21662
|
-
return () => observer2.disconnect();
|
|
21663
|
-
}, [hasAnimated, animate]);
|
|
21664
|
-
return /* @__PURE__ */ jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
21665
|
-
/* @__PURE__ */ jsx(
|
|
21666
|
-
Typography,
|
|
21667
|
-
{
|
|
21668
|
-
variant: "h2",
|
|
21669
|
-
className: "text-primary font-bold tabular-nums",
|
|
21670
|
-
children: hasAnimated ? displayValue : "0"
|
|
21671
|
-
}
|
|
21672
|
-
),
|
|
21673
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
21674
|
-
] });
|
|
21675
|
-
};
|
|
21676
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
21677
|
-
}
|
|
21678
|
-
});
|
|
21679
21991
|
var AuthLayout;
|
|
21680
21992
|
var init_AuthLayout = __esm({
|
|
21681
21993
|
"components/marketing/templates/AuthLayout.tsx"() {
|
|
@@ -22644,10 +22956,107 @@ var init_BehaviorView = __esm({
|
|
|
22644
22956
|
BehaviorView.displayName = "BehaviorView";
|
|
22645
22957
|
}
|
|
22646
22958
|
});
|
|
22959
|
+
var BiologyCanvas;
|
|
22960
|
+
var init_BiologyCanvas = __esm({
|
|
22961
|
+
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
22962
|
+
"use client";
|
|
22963
|
+
init_atoms();
|
|
22964
|
+
init_Stack();
|
|
22965
|
+
init_LearningCanvas();
|
|
22966
|
+
BiologyCanvas = ({
|
|
22967
|
+
className,
|
|
22968
|
+
width = 600,
|
|
22969
|
+
height = 400,
|
|
22970
|
+
title,
|
|
22971
|
+
backgroundColor,
|
|
22972
|
+
nodes = [],
|
|
22973
|
+
edges = [],
|
|
22974
|
+
shapes = [],
|
|
22975
|
+
interactive = false,
|
|
22976
|
+
animate = false,
|
|
22977
|
+
onShapeClick,
|
|
22978
|
+
isLoading,
|
|
22979
|
+
error
|
|
22980
|
+
}) => {
|
|
22981
|
+
const derivedShapes = useMemo(() => {
|
|
22982
|
+
const out = [];
|
|
22983
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
22984
|
+
for (const n of nodes) {
|
|
22985
|
+
if (n.id) nodeById.set(n.id, n);
|
|
22986
|
+
}
|
|
22987
|
+
for (const e of edges) {
|
|
22988
|
+
const a = nodeById.get(e.from);
|
|
22989
|
+
const b = nodeById.get(e.to);
|
|
22990
|
+
if (!a || !b) continue;
|
|
22991
|
+
out.push({
|
|
22992
|
+
type: "line",
|
|
22993
|
+
x1: a.x,
|
|
22994
|
+
y1: a.y,
|
|
22995
|
+
x2: b.x,
|
|
22996
|
+
y2: b.y,
|
|
22997
|
+
color: e.color ?? "#9ca3af",
|
|
22998
|
+
lineWidth: 2
|
|
22999
|
+
});
|
|
23000
|
+
if (e.label) {
|
|
23001
|
+
out.push({
|
|
23002
|
+
type: "text",
|
|
23003
|
+
x: (a.x + b.x) / 2 + 4,
|
|
23004
|
+
y: (a.y + b.y) / 2 - 4,
|
|
23005
|
+
text: e.label,
|
|
23006
|
+
color: "#374151",
|
|
23007
|
+
fontSize: 11
|
|
23008
|
+
});
|
|
23009
|
+
}
|
|
23010
|
+
}
|
|
23011
|
+
for (const n of nodes) {
|
|
23012
|
+
out.push({
|
|
23013
|
+
type: "circle",
|
|
23014
|
+
x: n.x,
|
|
23015
|
+
y: n.y,
|
|
23016
|
+
radius: n.radius ?? 16,
|
|
23017
|
+
color: n.color ?? "#16a34a",
|
|
23018
|
+
fill: `${n.color ?? "#16a34a"}33`,
|
|
23019
|
+
id: n.id
|
|
23020
|
+
});
|
|
23021
|
+
if (n.label) {
|
|
23022
|
+
out.push({
|
|
23023
|
+
type: "text",
|
|
23024
|
+
x: n.x,
|
|
23025
|
+
y: n.y + (n.radius ?? 16) + 14,
|
|
23026
|
+
text: n.label,
|
|
23027
|
+
color: "#111827",
|
|
23028
|
+
fontSize: 12,
|
|
23029
|
+
align: "center"
|
|
23030
|
+
});
|
|
23031
|
+
}
|
|
23032
|
+
}
|
|
23033
|
+
out.push(...shapes);
|
|
23034
|
+
return out;
|
|
23035
|
+
}, [nodes, edges, shapes]);
|
|
23036
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
23037
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
23038
|
+
/* @__PURE__ */ jsx(
|
|
23039
|
+
LearningCanvas,
|
|
23040
|
+
{
|
|
23041
|
+
width,
|
|
23042
|
+
height,
|
|
23043
|
+
backgroundColor,
|
|
23044
|
+
shapes: derivedShapes,
|
|
23045
|
+
interactive,
|
|
23046
|
+
animate,
|
|
23047
|
+
onShapeClick,
|
|
23048
|
+
isLoading,
|
|
23049
|
+
error
|
|
23050
|
+
}
|
|
23051
|
+
)
|
|
23052
|
+
] }) });
|
|
23053
|
+
};
|
|
23054
|
+
}
|
|
23055
|
+
});
|
|
22647
23056
|
|
|
22648
|
-
// node_modules/katex/dist/katex.min.css
|
|
23057
|
+
// node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
|
|
22649
23058
|
var init_katex_min = __esm({
|
|
22650
|
-
"node_modules/katex/dist/katex.min.css"() {
|
|
23059
|
+
"node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
|
|
22651
23060
|
}
|
|
22652
23061
|
});
|
|
22653
23062
|
var Tabs;
|
|
@@ -29016,6 +29425,122 @@ var init_ChatBar = __esm({
|
|
|
29016
29425
|
ChatBar.displayName = "ChatBar";
|
|
29017
29426
|
}
|
|
29018
29427
|
});
|
|
29428
|
+
var ChemistryCanvas;
|
|
29429
|
+
var init_ChemistryCanvas = __esm({
|
|
29430
|
+
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
29431
|
+
"use client";
|
|
29432
|
+
init_atoms();
|
|
29433
|
+
init_Stack();
|
|
29434
|
+
init_LearningCanvas();
|
|
29435
|
+
ChemistryCanvas = ({
|
|
29436
|
+
className,
|
|
29437
|
+
width = 600,
|
|
29438
|
+
height = 400,
|
|
29439
|
+
title,
|
|
29440
|
+
backgroundColor,
|
|
29441
|
+
atoms = [],
|
|
29442
|
+
bonds = [],
|
|
29443
|
+
arrows = [],
|
|
29444
|
+
shapes = [],
|
|
29445
|
+
interactive = false,
|
|
29446
|
+
animate = false,
|
|
29447
|
+
onShapeClick,
|
|
29448
|
+
isLoading,
|
|
29449
|
+
error
|
|
29450
|
+
}) => {
|
|
29451
|
+
const derivedShapes = useMemo(() => {
|
|
29452
|
+
const out = [];
|
|
29453
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
29454
|
+
for (const a of atoms) {
|
|
29455
|
+
if (a.id) atomById.set(a.id, a);
|
|
29456
|
+
}
|
|
29457
|
+
for (const b of bonds) {
|
|
29458
|
+
const a = atomById.get(b.from);
|
|
29459
|
+
const c = atomById.get(b.to);
|
|
29460
|
+
if (!a || !c) continue;
|
|
29461
|
+
const color = b.color ?? "#6b7280";
|
|
29462
|
+
const strokeWidth = b.type === "double" ? 4 : b.type === "triple" ? 6 : 2;
|
|
29463
|
+
out.push({
|
|
29464
|
+
type: "line",
|
|
29465
|
+
x1: a.x,
|
|
29466
|
+
y1: a.y,
|
|
29467
|
+
x2: c.x,
|
|
29468
|
+
y2: c.y,
|
|
29469
|
+
color,
|
|
29470
|
+
lineWidth: strokeWidth
|
|
29471
|
+
});
|
|
29472
|
+
}
|
|
29473
|
+
for (const a of arrows) {
|
|
29474
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
29475
|
+
const len = a.length ?? 60;
|
|
29476
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
29477
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
29478
|
+
out.push({
|
|
29479
|
+
type: "arrow",
|
|
29480
|
+
x1: a.x,
|
|
29481
|
+
y1: a.y,
|
|
29482
|
+
x2,
|
|
29483
|
+
y2,
|
|
29484
|
+
color: a.color ?? "#dc2626",
|
|
29485
|
+
lineWidth: 2
|
|
29486
|
+
});
|
|
29487
|
+
if (a.label) {
|
|
29488
|
+
out.push({
|
|
29489
|
+
type: "text",
|
|
29490
|
+
x: (a.x + x2) / 2,
|
|
29491
|
+
y: (a.y + y2) / 2 - 10,
|
|
29492
|
+
text: a.label,
|
|
29493
|
+
color: "#111827",
|
|
29494
|
+
fontSize: 12,
|
|
29495
|
+
align: "center"
|
|
29496
|
+
});
|
|
29497
|
+
}
|
|
29498
|
+
}
|
|
29499
|
+
for (const a of atoms) {
|
|
29500
|
+
out.push({
|
|
29501
|
+
type: "circle",
|
|
29502
|
+
x: a.x,
|
|
29503
|
+
y: a.y,
|
|
29504
|
+
radius: a.radius ?? 14,
|
|
29505
|
+
color: a.color ?? "#2563eb",
|
|
29506
|
+
fill: a.color ?? "#2563eb",
|
|
29507
|
+
id: a.id
|
|
29508
|
+
});
|
|
29509
|
+
if (a.element) {
|
|
29510
|
+
out.push({
|
|
29511
|
+
type: "text",
|
|
29512
|
+
x: a.x,
|
|
29513
|
+
y: a.y,
|
|
29514
|
+
text: a.element,
|
|
29515
|
+
color: "#ffffff",
|
|
29516
|
+
fontSize: 12,
|
|
29517
|
+
align: "center"
|
|
29518
|
+
});
|
|
29519
|
+
}
|
|
29520
|
+
}
|
|
29521
|
+
out.push(...shapes);
|
|
29522
|
+
return out;
|
|
29523
|
+
}, [atoms, bonds, arrows, shapes]);
|
|
29524
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
29525
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
29526
|
+
/* @__PURE__ */ jsx(
|
|
29527
|
+
LearningCanvas,
|
|
29528
|
+
{
|
|
29529
|
+
width,
|
|
29530
|
+
height,
|
|
29531
|
+
backgroundColor,
|
|
29532
|
+
shapes: derivedShapes,
|
|
29533
|
+
interactive,
|
|
29534
|
+
animate,
|
|
29535
|
+
onShapeClick,
|
|
29536
|
+
isLoading,
|
|
29537
|
+
error
|
|
29538
|
+
}
|
|
29539
|
+
)
|
|
29540
|
+
] }) });
|
|
29541
|
+
};
|
|
29542
|
+
}
|
|
29543
|
+
});
|
|
29019
29544
|
var CodeRunnerPanel;
|
|
29020
29545
|
var init_CodeRunnerPanel = __esm({
|
|
29021
29546
|
"components/core/organisms/CodeRunnerPanel.tsx"() {
|
|
@@ -34635,6 +35160,234 @@ var init_ProgressDots = __esm({
|
|
|
34635
35160
|
ProgressDots.displayName = "ProgressDots";
|
|
34636
35161
|
}
|
|
34637
35162
|
});
|
|
35163
|
+
var MathCanvas;
|
|
35164
|
+
var init_MathCanvas = __esm({
|
|
35165
|
+
"components/learning/molecules/MathCanvas.tsx"() {
|
|
35166
|
+
"use client";
|
|
35167
|
+
init_atoms();
|
|
35168
|
+
init_Stack();
|
|
35169
|
+
init_LearningCanvas();
|
|
35170
|
+
MathCanvas = ({
|
|
35171
|
+
className,
|
|
35172
|
+
width = 600,
|
|
35173
|
+
height = 400,
|
|
35174
|
+
title,
|
|
35175
|
+
xMin = -10,
|
|
35176
|
+
xMax = 10,
|
|
35177
|
+
yMin = -10,
|
|
35178
|
+
yMax = 10,
|
|
35179
|
+
showAxes = true,
|
|
35180
|
+
showGrid = true,
|
|
35181
|
+
gridStep = 1,
|
|
35182
|
+
curves = [],
|
|
35183
|
+
points = [],
|
|
35184
|
+
vectors = [],
|
|
35185
|
+
shapes = [],
|
|
35186
|
+
interactive = false,
|
|
35187
|
+
animate = false,
|
|
35188
|
+
onShapeClick,
|
|
35189
|
+
isLoading,
|
|
35190
|
+
error
|
|
35191
|
+
}) => {
|
|
35192
|
+
const derivedShapes = useMemo(() => {
|
|
35193
|
+
const out = [];
|
|
35194
|
+
const margin = 24;
|
|
35195
|
+
const plotW = width - margin * 2;
|
|
35196
|
+
const plotH = height - margin * 2;
|
|
35197
|
+
const mapX = (x) => margin + (x - xMin) / (xMax - xMin) * plotW;
|
|
35198
|
+
const mapY = (y) => height - (margin + (y - yMin) / (yMax - yMin) * plotH);
|
|
35199
|
+
if (showGrid) {
|
|
35200
|
+
for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
|
|
35201
|
+
const px = mapX(x);
|
|
35202
|
+
out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#e5e7eb", lineWidth: 1 });
|
|
35203
|
+
}
|
|
35204
|
+
for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
|
|
35205
|
+
const py = mapY(y);
|
|
35206
|
+
out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#e5e7eb", lineWidth: 1 });
|
|
35207
|
+
}
|
|
35208
|
+
}
|
|
35209
|
+
if (showAxes) {
|
|
35210
|
+
const xAxisY = Math.max(margin, Math.min(height - margin, mapY(0)));
|
|
35211
|
+
const yAxisX = Math.max(margin, Math.min(width - margin, mapX(0)));
|
|
35212
|
+
out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: "#374151", lineWidth: 2 });
|
|
35213
|
+
out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: "#374151", lineWidth: 2 });
|
|
35214
|
+
}
|
|
35215
|
+
for (const curve of curves) {
|
|
35216
|
+
if (!curve.samples || curve.samples.length < 2) continue;
|
|
35217
|
+
for (let i = 1; i < curve.samples.length; i++) {
|
|
35218
|
+
const a = curve.samples[i - 1];
|
|
35219
|
+
const b = curve.samples[i];
|
|
35220
|
+
if (a.x < xMin || a.x > xMax || b.x < xMin || b.x > xMax) continue;
|
|
35221
|
+
out.push({
|
|
35222
|
+
type: "line",
|
|
35223
|
+
x1: mapX(a.x),
|
|
35224
|
+
y1: mapY(a.y),
|
|
35225
|
+
x2: mapX(b.x),
|
|
35226
|
+
y2: mapY(b.y),
|
|
35227
|
+
color: curve.color ?? "#2563eb",
|
|
35228
|
+
lineWidth: 2
|
|
35229
|
+
});
|
|
35230
|
+
}
|
|
35231
|
+
}
|
|
35232
|
+
for (const p2 of points) {
|
|
35233
|
+
if (p2.x < xMin || p2.x > xMax || p2.y < yMin || p2.y > yMax) continue;
|
|
35234
|
+
out.push({
|
|
35235
|
+
type: "circle",
|
|
35236
|
+
x: mapX(p2.x),
|
|
35237
|
+
y: mapY(p2.y),
|
|
35238
|
+
radius: p2.radius ?? 4,
|
|
35239
|
+
color: p2.color ?? "#dc2626",
|
|
35240
|
+
fill: p2.color ?? "#dc2626"
|
|
35241
|
+
});
|
|
35242
|
+
if (p2.label) {
|
|
35243
|
+
out.push({ type: "text", x: mapX(p2.x) + 8, y: mapY(p2.y) - 8, text: p2.label, color: "#111827", fontSize: 12 });
|
|
35244
|
+
}
|
|
35245
|
+
}
|
|
35246
|
+
for (const v of vectors) {
|
|
35247
|
+
if (v.x < xMin || v.x > xMax || v.y < yMin || v.y > yMax) continue;
|
|
35248
|
+
const x1 = mapX(v.x);
|
|
35249
|
+
const y1 = mapY(v.y);
|
|
35250
|
+
const x2 = mapX(v.x + v.vx);
|
|
35251
|
+
const y2 = mapY(v.y + v.vy);
|
|
35252
|
+
out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
|
|
35253
|
+
if (v.label) {
|
|
35254
|
+
out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: "#111827", fontSize: 12 });
|
|
35255
|
+
}
|
|
35256
|
+
}
|
|
35257
|
+
out.push(...shapes);
|
|
35258
|
+
return out;
|
|
35259
|
+
}, [width, height, xMin, xMax, yMin, yMax, showAxes, showGrid, gridStep, curves, points, vectors, shapes]);
|
|
35260
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
35261
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35262
|
+
/* @__PURE__ */ jsx(
|
|
35263
|
+
LearningCanvas,
|
|
35264
|
+
{
|
|
35265
|
+
width,
|
|
35266
|
+
height,
|
|
35267
|
+
shapes: derivedShapes,
|
|
35268
|
+
interactive,
|
|
35269
|
+
animate,
|
|
35270
|
+
onShapeClick,
|
|
35271
|
+
isLoading,
|
|
35272
|
+
error
|
|
35273
|
+
}
|
|
35274
|
+
)
|
|
35275
|
+
] }) });
|
|
35276
|
+
};
|
|
35277
|
+
}
|
|
35278
|
+
});
|
|
35279
|
+
var PhysicsCanvas;
|
|
35280
|
+
var init_PhysicsCanvas = __esm({
|
|
35281
|
+
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
35282
|
+
"use client";
|
|
35283
|
+
init_atoms();
|
|
35284
|
+
init_Stack();
|
|
35285
|
+
init_LearningCanvas();
|
|
35286
|
+
PhysicsCanvas = ({
|
|
35287
|
+
className,
|
|
35288
|
+
width = 600,
|
|
35289
|
+
height = 400,
|
|
35290
|
+
title,
|
|
35291
|
+
backgroundColor,
|
|
35292
|
+
bodies = [],
|
|
35293
|
+
constraints = [],
|
|
35294
|
+
showVelocity = true,
|
|
35295
|
+
showForces = false,
|
|
35296
|
+
velocityScale = 20,
|
|
35297
|
+
forceScale = 20,
|
|
35298
|
+
shapes = [],
|
|
35299
|
+
interactive = false,
|
|
35300
|
+
animate = false,
|
|
35301
|
+
onShapeClick,
|
|
35302
|
+
isLoading,
|
|
35303
|
+
error
|
|
35304
|
+
}) => {
|
|
35305
|
+
const derivedShapes = useMemo(() => {
|
|
35306
|
+
const out = [];
|
|
35307
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
35308
|
+
for (const b of bodies) {
|
|
35309
|
+
if (b.id) bodyById.set(b.id, b);
|
|
35310
|
+
}
|
|
35311
|
+
for (const c of constraints) {
|
|
35312
|
+
const a = bodyById.get(c.from);
|
|
35313
|
+
const b = bodyById.get(c.to);
|
|
35314
|
+
if (!a || !b) continue;
|
|
35315
|
+
out.push({
|
|
35316
|
+
type: "line",
|
|
35317
|
+
x1: a.x,
|
|
35318
|
+
y1: a.y,
|
|
35319
|
+
x2: b.x,
|
|
35320
|
+
y2: b.y,
|
|
35321
|
+
color: c.color ?? "#9ca3af",
|
|
35322
|
+
lineWidth: 2
|
|
35323
|
+
});
|
|
35324
|
+
}
|
|
35325
|
+
for (const b of bodies) {
|
|
35326
|
+
out.push({
|
|
35327
|
+
type: "circle",
|
|
35328
|
+
x: b.x,
|
|
35329
|
+
y: b.y,
|
|
35330
|
+
radius: b.radius ?? 12,
|
|
35331
|
+
color: b.color ?? "#2563eb",
|
|
35332
|
+
fill: b.color ?? "#2563eb",
|
|
35333
|
+
id: b.id
|
|
35334
|
+
});
|
|
35335
|
+
if (b.label) {
|
|
35336
|
+
out.push({
|
|
35337
|
+
type: "text",
|
|
35338
|
+
x: b.x + (b.radius ?? 12) + 6,
|
|
35339
|
+
y: b.y - (b.radius ?? 12) - 6,
|
|
35340
|
+
text: b.label,
|
|
35341
|
+
color: "#111827",
|
|
35342
|
+
fontSize: 12
|
|
35343
|
+
});
|
|
35344
|
+
}
|
|
35345
|
+
if (showVelocity && b.vx != null && b.vy != null && (b.vx !== 0 || b.vy !== 0)) {
|
|
35346
|
+
out.push({
|
|
35347
|
+
type: "arrow",
|
|
35348
|
+
x1: b.x,
|
|
35349
|
+
y1: b.y,
|
|
35350
|
+
x2: b.x + b.vx * velocityScale,
|
|
35351
|
+
y2: b.y + b.vy * velocityScale,
|
|
35352
|
+
color: "#16a34a",
|
|
35353
|
+
lineWidth: 2
|
|
35354
|
+
});
|
|
35355
|
+
}
|
|
35356
|
+
if (showForces && b.fx != null && b.fy != null && (b.fx !== 0 || b.fy !== 0)) {
|
|
35357
|
+
out.push({
|
|
35358
|
+
type: "arrow",
|
|
35359
|
+
x1: b.x,
|
|
35360
|
+
y1: b.y,
|
|
35361
|
+
x2: b.x + b.fx * forceScale,
|
|
35362
|
+
y2: b.y + b.fy * forceScale,
|
|
35363
|
+
color: "#dc2626",
|
|
35364
|
+
lineWidth: 2
|
|
35365
|
+
});
|
|
35366
|
+
}
|
|
35367
|
+
}
|
|
35368
|
+
out.push(...shapes);
|
|
35369
|
+
return out;
|
|
35370
|
+
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
35371
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
35372
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35373
|
+
/* @__PURE__ */ jsx(
|
|
35374
|
+
LearningCanvas,
|
|
35375
|
+
{
|
|
35376
|
+
width,
|
|
35377
|
+
height,
|
|
35378
|
+
backgroundColor,
|
|
35379
|
+
shapes: derivedShapes,
|
|
35380
|
+
interactive,
|
|
35381
|
+
animate,
|
|
35382
|
+
onShapeClick,
|
|
35383
|
+
isLoading,
|
|
35384
|
+
error
|
|
35385
|
+
}
|
|
35386
|
+
)
|
|
35387
|
+
] }) });
|
|
35388
|
+
};
|
|
35389
|
+
}
|
|
35390
|
+
});
|
|
34638
35391
|
function resolveNodeColor(node, groups) {
|
|
34639
35392
|
if (node.color) return node.color;
|
|
34640
35393
|
if (node.group) {
|
|
@@ -35006,13 +35759,13 @@ var init_MapView = __esm({
|
|
|
35006
35759
|
shadowSize: [41, 41]
|
|
35007
35760
|
});
|
|
35008
35761
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
35009
|
-
const { useEffect:
|
|
35762
|
+
const { useEffect: useEffect75, useRef: useRef77, useCallback: useCallback112, useState: useState107 } = React105__default;
|
|
35010
35763
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
35011
35764
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
35012
35765
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
35013
35766
|
const map = useMap();
|
|
35014
|
-
const prevRef =
|
|
35015
|
-
|
|
35767
|
+
const prevRef = useRef77({ centerLat, centerLng, zoom });
|
|
35768
|
+
useEffect75(() => {
|
|
35016
35769
|
const prev = prevRef.current;
|
|
35017
35770
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
35018
35771
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -35023,7 +35776,7 @@ var init_MapView = __esm({
|
|
|
35023
35776
|
}
|
|
35024
35777
|
function MapClickHandler({ onMapClick }) {
|
|
35025
35778
|
const map = useMap();
|
|
35026
|
-
|
|
35779
|
+
useEffect75(() => {
|
|
35027
35780
|
if (!onMapClick) return;
|
|
35028
35781
|
const handler = (e) => {
|
|
35029
35782
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -43326,7 +44079,7 @@ function getGroupColor(group, groups) {
|
|
|
43326
44079
|
const idx = groups.indexOf(group);
|
|
43327
44080
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
43328
44081
|
}
|
|
43329
|
-
function
|
|
44082
|
+
function resolveColor3(color, el) {
|
|
43330
44083
|
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
43331
44084
|
if (!m) return color;
|
|
43332
44085
|
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
@@ -43587,7 +44340,7 @@ var init_GraphCanvas = __esm({
|
|
|
43587
44340
|
const w = logicalW;
|
|
43588
44341
|
const h = height;
|
|
43589
44342
|
const nodes = nodesRef.current;
|
|
43590
|
-
const accentColor =
|
|
44343
|
+
const accentColor = resolveColor3("var(--color-accent)", canvas);
|
|
43591
44344
|
const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
|
|
43592
44345
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
43593
44346
|
ctx.clearRect(0, 0, w, h);
|
|
@@ -43626,7 +44379,7 @@ var init_GraphCanvas = __esm({
|
|
|
43626
44379
|
ctx.globalAlpha = 1;
|
|
43627
44380
|
for (const node of nodes) {
|
|
43628
44381
|
const size = node.size || 8;
|
|
43629
|
-
const color =
|
|
44382
|
+
const color = resolveColor3(node.color || getGroupColor(node.group, groups), canvas);
|
|
43630
44383
|
const isHovered = hoveredNode === node.id;
|
|
43631
44384
|
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
43632
44385
|
ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
|
|
@@ -50524,6 +51277,7 @@ var init_component_registry_generated = __esm({
|
|
|
50524
51277
|
init_BattleBoard();
|
|
50525
51278
|
init_BattleTemplate();
|
|
50526
51279
|
init_BehaviorView();
|
|
51280
|
+
init_BiologyCanvas();
|
|
50527
51281
|
init_BloomQuizBlock();
|
|
50528
51282
|
init_BoardgameBoard();
|
|
50529
51283
|
init_BookChapterView();
|
|
@@ -50553,6 +51307,7 @@ var init_component_registry_generated = __esm({
|
|
|
50553
51307
|
init_ChartLegend();
|
|
50554
51308
|
init_ChatBar();
|
|
50555
51309
|
init_Checkbox();
|
|
51310
|
+
init_ChemistryCanvas();
|
|
50556
51311
|
init_ChoiceButton();
|
|
50557
51312
|
init_CityBuilderBoard();
|
|
50558
51313
|
init_CityBuilderTemplate();
|
|
@@ -50644,6 +51399,7 @@ var init_component_registry_generated = __esm({
|
|
|
50644
51399
|
init_JazariStateMachine();
|
|
50645
51400
|
init_LandingPageTemplate();
|
|
50646
51401
|
init_LawReferenceTooltip();
|
|
51402
|
+
init_LearningCanvas();
|
|
50647
51403
|
init_Lightbox();
|
|
50648
51404
|
init_LikertScale();
|
|
50649
51405
|
init_LineChart();
|
|
@@ -50652,9 +51408,11 @@ var init_component_registry_generated = __esm({
|
|
|
50652
51408
|
init_MapView();
|
|
50653
51409
|
init_MarkdownContent();
|
|
50654
51410
|
init_MarketingFooter();
|
|
51411
|
+
init_MarketingStatCard();
|
|
50655
51412
|
init_MasterDetail();
|
|
50656
51413
|
init_MasterDetailLayout();
|
|
50657
51414
|
init_MatchPuzzleBoard();
|
|
51415
|
+
init_MathCanvas();
|
|
50658
51416
|
init_MatrixQuestion();
|
|
50659
51417
|
init_MediaGallery();
|
|
50660
51418
|
init_Menu();
|
|
@@ -50673,6 +51431,7 @@ var init_component_registry_generated = __esm({
|
|
|
50673
51431
|
init_PageHeader();
|
|
50674
51432
|
init_Pagination();
|
|
50675
51433
|
init_PatternTile();
|
|
51434
|
+
init_PhysicsCanvas();
|
|
50676
51435
|
init_PinballBoard();
|
|
50677
51436
|
init_PirateBoard();
|
|
50678
51437
|
init_PlatformerBoard();
|
|
@@ -50849,6 +51608,7 @@ var init_component_registry_generated = __esm({
|
|
|
50849
51608
|
"BattleBoard": BattleBoard,
|
|
50850
51609
|
"BattleTemplate": BattleTemplate,
|
|
50851
51610
|
"BehaviorView": BehaviorView,
|
|
51611
|
+
"BiologyCanvas": BiologyCanvas,
|
|
50852
51612
|
"BloomQuizBlock": BloomQuizBlock,
|
|
50853
51613
|
"BoardgameBoard": BoardgameBoard,
|
|
50854
51614
|
"BookChapterView": BookChapterView,
|
|
@@ -50881,6 +51641,7 @@ var init_component_registry_generated = __esm({
|
|
|
50881
51641
|
"ChartLegend": ChartLegend,
|
|
50882
51642
|
"ChatBar": ChatBar,
|
|
50883
51643
|
"Checkbox": Checkbox,
|
|
51644
|
+
"ChemistryCanvas": ChemistryCanvas,
|
|
50884
51645
|
"ChoiceButton": ChoiceButton,
|
|
50885
51646
|
"CityBuilderBoard": CityBuilderBoard,
|
|
50886
51647
|
"CityBuilderTemplate": CityBuilderTemplate,
|
|
@@ -50982,6 +51743,7 @@ var init_component_registry_generated = __esm({
|
|
|
50982
51743
|
"LabelPattern": LabelPattern,
|
|
50983
51744
|
"LandingPageTemplate": LandingPageTemplate,
|
|
50984
51745
|
"LawReferenceTooltip": LawReferenceTooltip,
|
|
51746
|
+
"LearningCanvas": LearningCanvas,
|
|
50985
51747
|
"Lightbox": Lightbox,
|
|
50986
51748
|
"LikertScale": LikertScale,
|
|
50987
51749
|
"LineChart": LineChart2,
|
|
@@ -50990,9 +51752,11 @@ var init_component_registry_generated = __esm({
|
|
|
50990
51752
|
"MapView": MapView,
|
|
50991
51753
|
"MarkdownContent": MarkdownContent,
|
|
50992
51754
|
"MarketingFooter": MarketingFooter,
|
|
51755
|
+
"MarketingStatCard": MarketingStatCard,
|
|
50993
51756
|
"MasterDetail": MasterDetail,
|
|
50994
51757
|
"MasterDetailLayout": MasterDetailLayout,
|
|
50995
51758
|
"MatchPuzzleBoard": MatchPuzzleBoard,
|
|
51759
|
+
"MathCanvas": MathCanvas,
|
|
50996
51760
|
"MatrixQuestion": MatrixQuestion,
|
|
50997
51761
|
"MediaGallery": MediaGallery,
|
|
50998
51762
|
"Menu": Menu,
|
|
@@ -51011,6 +51775,7 @@ var init_component_registry_generated = __esm({
|
|
|
51011
51775
|
"PageHeader": PageHeader,
|
|
51012
51776
|
"Pagination": Pagination,
|
|
51013
51777
|
"PatternTile": PatternTile,
|
|
51778
|
+
"PhysicsCanvas": PhysicsCanvas,
|
|
51014
51779
|
"PinballBoard": PinballBoard,
|
|
51015
51780
|
"PirateBoard": PirateBoard,
|
|
51016
51781
|
"PlatformerBoard": PlatformerBoard,
|