@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/avl/index.js
CHANGED
|
@@ -9373,6 +9373,66 @@ var init_RangeSlider = __esm({
|
|
|
9373
9373
|
RangeSlider.displayName = "RangeSlider";
|
|
9374
9374
|
}
|
|
9375
9375
|
});
|
|
9376
|
+
function easeOut(t) {
|
|
9377
|
+
return t * (2 - t);
|
|
9378
|
+
}
|
|
9379
|
+
var AnimatedCounter;
|
|
9380
|
+
var init_AnimatedCounter = __esm({
|
|
9381
|
+
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
9382
|
+
"use client";
|
|
9383
|
+
init_cn();
|
|
9384
|
+
init_Typography();
|
|
9385
|
+
AnimatedCounter = ({
|
|
9386
|
+
value: rawValue,
|
|
9387
|
+
duration = 600,
|
|
9388
|
+
prefix,
|
|
9389
|
+
suffix,
|
|
9390
|
+
className
|
|
9391
|
+
}) => {
|
|
9392
|
+
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
9393
|
+
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
9394
|
+
const [displayValue, setDisplayValue] = useState(value);
|
|
9395
|
+
const previousValueRef = useRef(value);
|
|
9396
|
+
const animationFrameRef = useRef(null);
|
|
9397
|
+
useEffect(() => {
|
|
9398
|
+
const from = previousValueRef.current;
|
|
9399
|
+
const to = value;
|
|
9400
|
+
previousValueRef.current = value;
|
|
9401
|
+
if (from === to) {
|
|
9402
|
+
setDisplayValue(to);
|
|
9403
|
+
return;
|
|
9404
|
+
}
|
|
9405
|
+
const startTime = performance.now();
|
|
9406
|
+
const diff = to - from;
|
|
9407
|
+
function animate(currentTime) {
|
|
9408
|
+
const elapsed = currentTime - startTime;
|
|
9409
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
9410
|
+
const easedProgress = easeOut(progress);
|
|
9411
|
+
setDisplayValue(from + diff * easedProgress);
|
|
9412
|
+
if (progress < 1) {
|
|
9413
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
9414
|
+
} else {
|
|
9415
|
+
setDisplayValue(to);
|
|
9416
|
+
}
|
|
9417
|
+
}
|
|
9418
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
9419
|
+
return () => {
|
|
9420
|
+
if (animationFrameRef.current !== null) {
|
|
9421
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
9422
|
+
}
|
|
9423
|
+
};
|
|
9424
|
+
}, [value, duration]);
|
|
9425
|
+
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
9426
|
+
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
9427
|
+
return /* @__PURE__ */ jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
9428
|
+
prefix,
|
|
9429
|
+
formattedValue,
|
|
9430
|
+
suffix
|
|
9431
|
+
] });
|
|
9432
|
+
};
|
|
9433
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
9434
|
+
}
|
|
9435
|
+
});
|
|
9376
9436
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
9377
9437
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
9378
9438
|
const observerRef = useRef(null);
|
|
@@ -9669,6 +9729,34 @@ var init_SectionHeader = __esm({
|
|
|
9669
9729
|
SectionHeader.displayName = "SectionHeader";
|
|
9670
9730
|
}
|
|
9671
9731
|
});
|
|
9732
|
+
var sizeClasses6, MarketingStatCard;
|
|
9733
|
+
var init_MarketingStatCard = __esm({
|
|
9734
|
+
"components/marketing/atoms/MarketingStatCard.tsx"() {
|
|
9735
|
+
init_cn();
|
|
9736
|
+
init_Stack();
|
|
9737
|
+
init_Typography();
|
|
9738
|
+
sizeClasses6 = {
|
|
9739
|
+
sm: "text-2xl",
|
|
9740
|
+
md: "text-4xl",
|
|
9741
|
+
lg: "text-5xl"
|
|
9742
|
+
};
|
|
9743
|
+
MarketingStatCard = ({ value, label, size = "md", className }) => {
|
|
9744
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", className: cn(className), children: [
|
|
9745
|
+
/* @__PURE__ */ jsx(
|
|
9746
|
+
Typography,
|
|
9747
|
+
{
|
|
9748
|
+
weight: "bold",
|
|
9749
|
+
color: "primary",
|
|
9750
|
+
className: cn(sizeClasses6[size]),
|
|
9751
|
+
children: value
|
|
9752
|
+
}
|
|
9753
|
+
),
|
|
9754
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
9755
|
+
] });
|
|
9756
|
+
};
|
|
9757
|
+
MarketingStatCard.displayName = "MarketingStatCard";
|
|
9758
|
+
}
|
|
9759
|
+
});
|
|
9672
9760
|
var backgroundClasses, paddingClasses, ContentSection;
|
|
9673
9761
|
var init_ContentSection = __esm({
|
|
9674
9762
|
"components/marketing/atoms/ContentSection.tsx"() {
|
|
@@ -23513,6 +23601,315 @@ var init_molecules = __esm({
|
|
|
23513
23601
|
init_puzzleObject();
|
|
23514
23602
|
}
|
|
23515
23603
|
});
|
|
23604
|
+
function resolveColor2(color, ctx, fallback) {
|
|
23605
|
+
if (!color) return fallback;
|
|
23606
|
+
if (color.startsWith("var(")) {
|
|
23607
|
+
ctx.canvas.style;
|
|
23608
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color);
|
|
23609
|
+
if (m) {
|
|
23610
|
+
const computed = getComputedStyle(ctx.canvas).getPropertyValue(m[1]).trim();
|
|
23611
|
+
return computed || m[2]?.trim() || fallback;
|
|
23612
|
+
}
|
|
23613
|
+
}
|
|
23614
|
+
return color;
|
|
23615
|
+
}
|
|
23616
|
+
function shapeBounds(shape) {
|
|
23617
|
+
switch (shape.type) {
|
|
23618
|
+
case "line":
|
|
23619
|
+
case "arrow":
|
|
23620
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) return null;
|
|
23621
|
+
return {
|
|
23622
|
+
x: Math.min(shape.x1, shape.x2) - 6,
|
|
23623
|
+
y: Math.min(shape.y1, shape.y2) - 6,
|
|
23624
|
+
w: Math.abs(shape.x2 - shape.x1) + 12,
|
|
23625
|
+
h: Math.abs(shape.y2 - shape.y1) + 12
|
|
23626
|
+
};
|
|
23627
|
+
case "circle":
|
|
23628
|
+
if (shape.x == null || shape.y == null || shape.radius == null) return null;
|
|
23629
|
+
return {
|
|
23630
|
+
x: shape.x - shape.radius - 4,
|
|
23631
|
+
y: shape.y - shape.radius - 4,
|
|
23632
|
+
w: shape.radius * 2 + 8,
|
|
23633
|
+
h: shape.radius * 2 + 8
|
|
23634
|
+
};
|
|
23635
|
+
case "rect":
|
|
23636
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) return null;
|
|
23637
|
+
return { x: shape.x - 4, y: shape.y - 4, w: shape.width + 8, h: shape.height + 8 };
|
|
23638
|
+
case "polygon":
|
|
23639
|
+
if (!shape.points || shape.points.length === 0) return null;
|
|
23640
|
+
{
|
|
23641
|
+
const xs = shape.points.map((p2) => p2.x);
|
|
23642
|
+
const ys = shape.points.map((p2) => p2.y);
|
|
23643
|
+
const minX = Math.min(...xs);
|
|
23644
|
+
const minY = Math.min(...ys);
|
|
23645
|
+
return {
|
|
23646
|
+
x: minX - 4,
|
|
23647
|
+
y: minY - 4,
|
|
23648
|
+
w: Math.max(...xs) - minX + 8,
|
|
23649
|
+
h: Math.max(...ys) - minY + 8
|
|
23650
|
+
};
|
|
23651
|
+
}
|
|
23652
|
+
case "text":
|
|
23653
|
+
if (shape.x == null || shape.y == null) return null;
|
|
23654
|
+
return { x: shape.x - 4, y: shape.y - (shape.fontSize ?? 14) - 4, w: 120, h: (shape.fontSize ?? 14) + 8 };
|
|
23655
|
+
default:
|
|
23656
|
+
return null;
|
|
23657
|
+
}
|
|
23658
|
+
}
|
|
23659
|
+
function drawArrowHead(ctx, x1, y1, x2, y2, size) {
|
|
23660
|
+
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
23661
|
+
ctx.beginPath();
|
|
23662
|
+
ctx.moveTo(x2, y2);
|
|
23663
|
+
ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
|
|
23664
|
+
ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
|
|
23665
|
+
ctx.closePath();
|
|
23666
|
+
ctx.fill();
|
|
23667
|
+
}
|
|
23668
|
+
function drawShape(ctx, shape, width, height) {
|
|
23669
|
+
ctx.save();
|
|
23670
|
+
const opacity = shape.opacity ?? 1;
|
|
23671
|
+
ctx.globalAlpha = opacity;
|
|
23672
|
+
const stroke = resolveColor2(shape.color, ctx, "#333333");
|
|
23673
|
+
const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
|
|
23674
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
23675
|
+
switch (shape.type) {
|
|
23676
|
+
case "grid": {
|
|
23677
|
+
const step = shape.step ?? 40;
|
|
23678
|
+
ctx.strokeStyle = stroke;
|
|
23679
|
+
ctx.globalAlpha = opacity * 0.25;
|
|
23680
|
+
ctx.lineWidth = 1;
|
|
23681
|
+
ctx.beginPath();
|
|
23682
|
+
for (let x = 0; x <= width; x += step) {
|
|
23683
|
+
ctx.moveTo(x, 0);
|
|
23684
|
+
ctx.lineTo(x, height);
|
|
23685
|
+
}
|
|
23686
|
+
for (let y = 0; y <= height; y += step) {
|
|
23687
|
+
ctx.moveTo(0, y);
|
|
23688
|
+
ctx.lineTo(width, y);
|
|
23689
|
+
}
|
|
23690
|
+
ctx.stroke();
|
|
23691
|
+
break;
|
|
23692
|
+
}
|
|
23693
|
+
case "axis": {
|
|
23694
|
+
const axis = shape.axis ?? "x";
|
|
23695
|
+
ctx.strokeStyle = stroke;
|
|
23696
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
23697
|
+
ctx.beginPath();
|
|
23698
|
+
if (axis === "x") {
|
|
23699
|
+
ctx.moveTo(0, height / 2);
|
|
23700
|
+
ctx.lineTo(width, height / 2);
|
|
23701
|
+
} else {
|
|
23702
|
+
ctx.moveTo(width / 2, 0);
|
|
23703
|
+
ctx.lineTo(width / 2, height);
|
|
23704
|
+
}
|
|
23705
|
+
ctx.stroke();
|
|
23706
|
+
break;
|
|
23707
|
+
}
|
|
23708
|
+
case "line": {
|
|
23709
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
23710
|
+
ctx.strokeStyle = stroke;
|
|
23711
|
+
ctx.beginPath();
|
|
23712
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
23713
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
23714
|
+
ctx.stroke();
|
|
23715
|
+
break;
|
|
23716
|
+
}
|
|
23717
|
+
case "arrow": {
|
|
23718
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
23719
|
+
ctx.strokeStyle = stroke;
|
|
23720
|
+
ctx.fillStyle = stroke;
|
|
23721
|
+
ctx.beginPath();
|
|
23722
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
23723
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
23724
|
+
ctx.stroke();
|
|
23725
|
+
drawArrowHead(ctx, shape.x1, shape.y1, shape.x2, shape.y2, 10);
|
|
23726
|
+
break;
|
|
23727
|
+
}
|
|
23728
|
+
case "circle": {
|
|
23729
|
+
if (shape.x == null || shape.y == null || shape.radius == null) break;
|
|
23730
|
+
ctx.beginPath();
|
|
23731
|
+
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
|
|
23732
|
+
if (fill) {
|
|
23733
|
+
ctx.fillStyle = fill;
|
|
23734
|
+
ctx.fill();
|
|
23735
|
+
}
|
|
23736
|
+
ctx.strokeStyle = stroke;
|
|
23737
|
+
ctx.stroke();
|
|
23738
|
+
break;
|
|
23739
|
+
}
|
|
23740
|
+
case "rect": {
|
|
23741
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) break;
|
|
23742
|
+
if (fill) {
|
|
23743
|
+
ctx.fillStyle = fill;
|
|
23744
|
+
ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
|
|
23745
|
+
}
|
|
23746
|
+
ctx.strokeStyle = stroke;
|
|
23747
|
+
ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
|
|
23748
|
+
break;
|
|
23749
|
+
}
|
|
23750
|
+
case "polygon": {
|
|
23751
|
+
if (!shape.points || shape.points.length < 2) break;
|
|
23752
|
+
ctx.beginPath();
|
|
23753
|
+
ctx.moveTo(shape.points[0].x, shape.points[0].y);
|
|
23754
|
+
for (let i = 1; i < shape.points.length; i++) {
|
|
23755
|
+
ctx.lineTo(shape.points[i].x, shape.points[i].y);
|
|
23756
|
+
}
|
|
23757
|
+
ctx.closePath();
|
|
23758
|
+
if (fill) {
|
|
23759
|
+
ctx.fillStyle = fill;
|
|
23760
|
+
ctx.fill();
|
|
23761
|
+
}
|
|
23762
|
+
ctx.strokeStyle = stroke;
|
|
23763
|
+
ctx.stroke();
|
|
23764
|
+
break;
|
|
23765
|
+
}
|
|
23766
|
+
case "path": {
|
|
23767
|
+
if (!shape.path) break;
|
|
23768
|
+
const p2 = new Path2D(shape.path);
|
|
23769
|
+
if (fill) {
|
|
23770
|
+
ctx.fillStyle = fill;
|
|
23771
|
+
ctx.fill(p2);
|
|
23772
|
+
}
|
|
23773
|
+
ctx.strokeStyle = stroke;
|
|
23774
|
+
ctx.stroke(p2);
|
|
23775
|
+
break;
|
|
23776
|
+
}
|
|
23777
|
+
case "text": {
|
|
23778
|
+
if (shape.x == null || shape.y == null || !shape.text) break;
|
|
23779
|
+
ctx.fillStyle = stroke;
|
|
23780
|
+
ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
|
|
23781
|
+
ctx.textAlign = shape.align ?? "left";
|
|
23782
|
+
ctx.textBaseline = "middle";
|
|
23783
|
+
ctx.fillText(shape.text, shape.x, shape.y);
|
|
23784
|
+
break;
|
|
23785
|
+
}
|
|
23786
|
+
}
|
|
23787
|
+
ctx.restore();
|
|
23788
|
+
}
|
|
23789
|
+
var LearningCanvas;
|
|
23790
|
+
var init_LearningCanvas = __esm({
|
|
23791
|
+
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
23792
|
+
"use client";
|
|
23793
|
+
init_cn();
|
|
23794
|
+
init_useEventBus();
|
|
23795
|
+
LearningCanvas = ({
|
|
23796
|
+
className,
|
|
23797
|
+
width = 600,
|
|
23798
|
+
height = 400,
|
|
23799
|
+
backgroundColor,
|
|
23800
|
+
shapes = [],
|
|
23801
|
+
interactive = false,
|
|
23802
|
+
animate = false,
|
|
23803
|
+
onShapeClick,
|
|
23804
|
+
onShapeHover,
|
|
23805
|
+
isLoading,
|
|
23806
|
+
error
|
|
23807
|
+
}) => {
|
|
23808
|
+
const canvasRef = useRef(null);
|
|
23809
|
+
const eventBus = useEventBus();
|
|
23810
|
+
const animRef = useRef(0);
|
|
23811
|
+
const hoverIndexRef = useRef(-1);
|
|
23812
|
+
const findShapeAt = useCallback((clientX, clientY) => {
|
|
23813
|
+
const canvas = canvasRef.current;
|
|
23814
|
+
if (!canvas) return -1;
|
|
23815
|
+
const rect = canvas.getBoundingClientRect();
|
|
23816
|
+
const x = clientX - rect.left;
|
|
23817
|
+
const y = clientY - rect.top;
|
|
23818
|
+
for (let i = shapes.length - 1; i >= 0; i--) {
|
|
23819
|
+
const b = shapeBounds(shapes[i]);
|
|
23820
|
+
if (b && x >= b.x && x <= b.x + b.w && y >= b.y && y <= b.y + b.h) {
|
|
23821
|
+
return i;
|
|
23822
|
+
}
|
|
23823
|
+
}
|
|
23824
|
+
return -1;
|
|
23825
|
+
}, [shapes]);
|
|
23826
|
+
const draw = useCallback(() => {
|
|
23827
|
+
const canvas = canvasRef.current;
|
|
23828
|
+
if (!canvas) return;
|
|
23829
|
+
const ctx = canvas.getContext("2d");
|
|
23830
|
+
if (!ctx) return;
|
|
23831
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
23832
|
+
canvas.width = Math.max(1, Math.floor(width * dpr));
|
|
23833
|
+
canvas.height = Math.max(1, Math.floor(height * dpr));
|
|
23834
|
+
canvas.style.width = `${width}px`;
|
|
23835
|
+
canvas.style.height = `${height}px`;
|
|
23836
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
23837
|
+
ctx.clearRect(0, 0, width, height);
|
|
23838
|
+
if (backgroundColor) {
|
|
23839
|
+
ctx.fillStyle = backgroundColor;
|
|
23840
|
+
ctx.fillRect(0, 0, width, height);
|
|
23841
|
+
}
|
|
23842
|
+
for (const shape of shapes) {
|
|
23843
|
+
drawShape(ctx, shape, width, height);
|
|
23844
|
+
}
|
|
23845
|
+
}, [width, height, backgroundColor, shapes]);
|
|
23846
|
+
useEffect(() => {
|
|
23847
|
+
draw();
|
|
23848
|
+
}, [draw]);
|
|
23849
|
+
useEffect(() => {
|
|
23850
|
+
if (!animate) return;
|
|
23851
|
+
const loop = () => {
|
|
23852
|
+
draw();
|
|
23853
|
+
animRef.current = requestAnimationFrame(loop);
|
|
23854
|
+
};
|
|
23855
|
+
animRef.current = requestAnimationFrame(loop);
|
|
23856
|
+
return () => cancelAnimationFrame(animRef.current);
|
|
23857
|
+
}, [animate, draw]);
|
|
23858
|
+
const handlePointerMove = useCallback(
|
|
23859
|
+
(e) => {
|
|
23860
|
+
if (!interactive) return;
|
|
23861
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
23862
|
+
if (idx !== hoverIndexRef.current) {
|
|
23863
|
+
hoverIndexRef.current = idx;
|
|
23864
|
+
if (idx >= 0) {
|
|
23865
|
+
const shape = shapes[idx];
|
|
23866
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
23867
|
+
if (onShapeHover) onShapeHover(payload);
|
|
23868
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_HOVER`, payload);
|
|
23869
|
+
}
|
|
23870
|
+
}
|
|
23871
|
+
},
|
|
23872
|
+
[interactive, onShapeHover, eventBus, findShapeAt, shapes]
|
|
23873
|
+
);
|
|
23874
|
+
const handleClick = useCallback(
|
|
23875
|
+
(e) => {
|
|
23876
|
+
if (!interactive) return;
|
|
23877
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
23878
|
+
if (idx >= 0) {
|
|
23879
|
+
const shape = shapes[idx];
|
|
23880
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
23881
|
+
if (onShapeClick) onShapeClick(payload);
|
|
23882
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_CLICK`, payload);
|
|
23883
|
+
}
|
|
23884
|
+
},
|
|
23885
|
+
[interactive, onShapeClick, eventBus, findShapeAt, shapes]
|
|
23886
|
+
);
|
|
23887
|
+
if (isLoading || error) {
|
|
23888
|
+
return /* @__PURE__ */ jsx(
|
|
23889
|
+
"div",
|
|
23890
|
+
{
|
|
23891
|
+
className: cn(
|
|
23892
|
+
"flex items-center justify-center rounded border border-border bg-surface",
|
|
23893
|
+
className
|
|
23894
|
+
),
|
|
23895
|
+
style: { width, height },
|
|
23896
|
+
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" })
|
|
23897
|
+
}
|
|
23898
|
+
);
|
|
23899
|
+
}
|
|
23900
|
+
return /* @__PURE__ */ jsx(
|
|
23901
|
+
"canvas",
|
|
23902
|
+
{
|
|
23903
|
+
ref: canvasRef,
|
|
23904
|
+
className: cn("block touch-none rounded border border-border", className),
|
|
23905
|
+
style: { width, height },
|
|
23906
|
+
onClick: handleClick,
|
|
23907
|
+
onPointerMove: handlePointerMove
|
|
23908
|
+
}
|
|
23909
|
+
);
|
|
23910
|
+
};
|
|
23911
|
+
}
|
|
23912
|
+
});
|
|
23516
23913
|
|
|
23517
23914
|
// components/core/atoms/index.ts
|
|
23518
23915
|
var init_atoms = __esm({
|
|
@@ -24998,91 +25395,6 @@ var init_ComponentPatterns = __esm({
|
|
|
24998
25395
|
AlertPattern.displayName = "AlertPattern";
|
|
24999
25396
|
}
|
|
25000
25397
|
});
|
|
25001
|
-
function parseValue(value) {
|
|
25002
|
-
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
25003
|
-
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
25004
|
-
if (!match) {
|
|
25005
|
-
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
25006
|
-
}
|
|
25007
|
-
const numStr = match[2];
|
|
25008
|
-
const decimalIdx = numStr.indexOf(".");
|
|
25009
|
-
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
25010
|
-
return {
|
|
25011
|
-
prefix: match[1],
|
|
25012
|
-
num: parseFloat(numStr),
|
|
25013
|
-
suffix: match[3],
|
|
25014
|
-
decimals
|
|
25015
|
-
};
|
|
25016
|
-
}
|
|
25017
|
-
var AnimatedCounter;
|
|
25018
|
-
var init_AnimatedCounter = __esm({
|
|
25019
|
-
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
25020
|
-
"use client";
|
|
25021
|
-
init_cn();
|
|
25022
|
-
init_Box();
|
|
25023
|
-
init_Typography();
|
|
25024
|
-
AnimatedCounter = ({
|
|
25025
|
-
value,
|
|
25026
|
-
label,
|
|
25027
|
-
duration = 1500,
|
|
25028
|
-
className
|
|
25029
|
-
}) => {
|
|
25030
|
-
const ref = useRef(null);
|
|
25031
|
-
const [displayValue, setDisplayValue] = useState("0");
|
|
25032
|
-
const [hasAnimated, setHasAnimated] = useState(false);
|
|
25033
|
-
const animate = useCallback(() => {
|
|
25034
|
-
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
25035
|
-
if (num2 === 0) {
|
|
25036
|
-
setDisplayValue(String(value));
|
|
25037
|
-
return;
|
|
25038
|
-
}
|
|
25039
|
-
const startTime = performance.now();
|
|
25040
|
-
const tick = (now2) => {
|
|
25041
|
-
const elapsed = now2 - startTime;
|
|
25042
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
25043
|
-
const eased = 1 - Math.pow(1 - progress, 3);
|
|
25044
|
-
const current = eased * num2;
|
|
25045
|
-
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
25046
|
-
if (progress < 1) {
|
|
25047
|
-
requestAnimationFrame(tick);
|
|
25048
|
-
} else {
|
|
25049
|
-
setDisplayValue(String(value));
|
|
25050
|
-
}
|
|
25051
|
-
};
|
|
25052
|
-
requestAnimationFrame(tick);
|
|
25053
|
-
}, [value, duration]);
|
|
25054
|
-
useEffect(() => {
|
|
25055
|
-
if (hasAnimated) return;
|
|
25056
|
-
const el = ref.current;
|
|
25057
|
-
if (!el) return;
|
|
25058
|
-
const observer2 = new IntersectionObserver(
|
|
25059
|
-
(entries) => {
|
|
25060
|
-
if (entries[0].isIntersecting) {
|
|
25061
|
-
setHasAnimated(true);
|
|
25062
|
-
animate();
|
|
25063
|
-
observer2.disconnect();
|
|
25064
|
-
}
|
|
25065
|
-
},
|
|
25066
|
-
{ threshold: 0.3 }
|
|
25067
|
-
);
|
|
25068
|
-
observer2.observe(el);
|
|
25069
|
-
return () => observer2.disconnect();
|
|
25070
|
-
}, [hasAnimated, animate]);
|
|
25071
|
-
return /* @__PURE__ */ jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
25072
|
-
/* @__PURE__ */ jsx(
|
|
25073
|
-
Typography,
|
|
25074
|
-
{
|
|
25075
|
-
variant: "h2",
|
|
25076
|
-
className: "text-primary font-bold tabular-nums",
|
|
25077
|
-
children: hasAnimated ? displayValue : "0"
|
|
25078
|
-
}
|
|
25079
|
-
),
|
|
25080
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
25081
|
-
] });
|
|
25082
|
-
};
|
|
25083
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
25084
|
-
}
|
|
25085
|
-
});
|
|
25086
25398
|
var AuthLayout;
|
|
25087
25399
|
var init_AuthLayout = __esm({
|
|
25088
25400
|
"components/marketing/templates/AuthLayout.tsx"() {
|
|
@@ -25224,6 +25536,103 @@ var init_AuthLayout = __esm({
|
|
|
25224
25536
|
AuthLayout.displayName = "AuthLayout";
|
|
25225
25537
|
}
|
|
25226
25538
|
});
|
|
25539
|
+
var BiologyCanvas;
|
|
25540
|
+
var init_BiologyCanvas = __esm({
|
|
25541
|
+
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
25542
|
+
"use client";
|
|
25543
|
+
init_atoms();
|
|
25544
|
+
init_Stack();
|
|
25545
|
+
init_LearningCanvas();
|
|
25546
|
+
BiologyCanvas = ({
|
|
25547
|
+
className,
|
|
25548
|
+
width = 600,
|
|
25549
|
+
height = 400,
|
|
25550
|
+
title,
|
|
25551
|
+
backgroundColor,
|
|
25552
|
+
nodes = [],
|
|
25553
|
+
edges = [],
|
|
25554
|
+
shapes = [],
|
|
25555
|
+
interactive = false,
|
|
25556
|
+
animate = false,
|
|
25557
|
+
onShapeClick,
|
|
25558
|
+
isLoading,
|
|
25559
|
+
error
|
|
25560
|
+
}) => {
|
|
25561
|
+
const derivedShapes = useMemo(() => {
|
|
25562
|
+
const out = [];
|
|
25563
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
25564
|
+
for (const n of nodes) {
|
|
25565
|
+
if (n.id) nodeById.set(n.id, n);
|
|
25566
|
+
}
|
|
25567
|
+
for (const e of edges) {
|
|
25568
|
+
const a = nodeById.get(e.from);
|
|
25569
|
+
const b = nodeById.get(e.to);
|
|
25570
|
+
if (!a || !b) continue;
|
|
25571
|
+
out.push({
|
|
25572
|
+
type: "line",
|
|
25573
|
+
x1: a.x,
|
|
25574
|
+
y1: a.y,
|
|
25575
|
+
x2: b.x,
|
|
25576
|
+
y2: b.y,
|
|
25577
|
+
color: e.color ?? "#9ca3af",
|
|
25578
|
+
lineWidth: 2
|
|
25579
|
+
});
|
|
25580
|
+
if (e.label) {
|
|
25581
|
+
out.push({
|
|
25582
|
+
type: "text",
|
|
25583
|
+
x: (a.x + b.x) / 2 + 4,
|
|
25584
|
+
y: (a.y + b.y) / 2 - 4,
|
|
25585
|
+
text: e.label,
|
|
25586
|
+
color: "#374151",
|
|
25587
|
+
fontSize: 11
|
|
25588
|
+
});
|
|
25589
|
+
}
|
|
25590
|
+
}
|
|
25591
|
+
for (const n of nodes) {
|
|
25592
|
+
out.push({
|
|
25593
|
+
type: "circle",
|
|
25594
|
+
x: n.x,
|
|
25595
|
+
y: n.y,
|
|
25596
|
+
radius: n.radius ?? 16,
|
|
25597
|
+
color: n.color ?? "#16a34a",
|
|
25598
|
+
fill: `${n.color ?? "#16a34a"}33`,
|
|
25599
|
+
id: n.id
|
|
25600
|
+
});
|
|
25601
|
+
if (n.label) {
|
|
25602
|
+
out.push({
|
|
25603
|
+
type: "text",
|
|
25604
|
+
x: n.x,
|
|
25605
|
+
y: n.y + (n.radius ?? 16) + 14,
|
|
25606
|
+
text: n.label,
|
|
25607
|
+
color: "#111827",
|
|
25608
|
+
fontSize: 12,
|
|
25609
|
+
align: "center"
|
|
25610
|
+
});
|
|
25611
|
+
}
|
|
25612
|
+
}
|
|
25613
|
+
out.push(...shapes);
|
|
25614
|
+
return out;
|
|
25615
|
+
}, [nodes, edges, shapes]);
|
|
25616
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
25617
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
25618
|
+
/* @__PURE__ */ jsx(
|
|
25619
|
+
LearningCanvas,
|
|
25620
|
+
{
|
|
25621
|
+
width,
|
|
25622
|
+
height,
|
|
25623
|
+
backgroundColor,
|
|
25624
|
+
shapes: derivedShapes,
|
|
25625
|
+
interactive,
|
|
25626
|
+
animate,
|
|
25627
|
+
onShapeClick,
|
|
25628
|
+
isLoading,
|
|
25629
|
+
error
|
|
25630
|
+
}
|
|
25631
|
+
)
|
|
25632
|
+
] }) });
|
|
25633
|
+
};
|
|
25634
|
+
}
|
|
25635
|
+
});
|
|
25227
25636
|
|
|
25228
25637
|
// node_modules/katex/dist/katex.min.css
|
|
25229
25638
|
var init_katex_min = __esm({
|
|
@@ -31713,6 +32122,122 @@ var init_ChatBar = __esm({
|
|
|
31713
32122
|
ChatBar.displayName = "ChatBar";
|
|
31714
32123
|
}
|
|
31715
32124
|
});
|
|
32125
|
+
var ChemistryCanvas;
|
|
32126
|
+
var init_ChemistryCanvas = __esm({
|
|
32127
|
+
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
32128
|
+
"use client";
|
|
32129
|
+
init_atoms();
|
|
32130
|
+
init_Stack();
|
|
32131
|
+
init_LearningCanvas();
|
|
32132
|
+
ChemistryCanvas = ({
|
|
32133
|
+
className,
|
|
32134
|
+
width = 600,
|
|
32135
|
+
height = 400,
|
|
32136
|
+
title,
|
|
32137
|
+
backgroundColor,
|
|
32138
|
+
atoms = [],
|
|
32139
|
+
bonds = [],
|
|
32140
|
+
arrows = [],
|
|
32141
|
+
shapes = [],
|
|
32142
|
+
interactive = false,
|
|
32143
|
+
animate = false,
|
|
32144
|
+
onShapeClick,
|
|
32145
|
+
isLoading,
|
|
32146
|
+
error
|
|
32147
|
+
}) => {
|
|
32148
|
+
const derivedShapes = useMemo(() => {
|
|
32149
|
+
const out = [];
|
|
32150
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
32151
|
+
for (const a of atoms) {
|
|
32152
|
+
if (a.id) atomById.set(a.id, a);
|
|
32153
|
+
}
|
|
32154
|
+
for (const b of bonds) {
|
|
32155
|
+
const a = atomById.get(b.from);
|
|
32156
|
+
const c = atomById.get(b.to);
|
|
32157
|
+
if (!a || !c) continue;
|
|
32158
|
+
const color = b.color ?? "#6b7280";
|
|
32159
|
+
const strokeWidth = b.type === "double" ? 4 : b.type === "triple" ? 6 : 2;
|
|
32160
|
+
out.push({
|
|
32161
|
+
type: "line",
|
|
32162
|
+
x1: a.x,
|
|
32163
|
+
y1: a.y,
|
|
32164
|
+
x2: c.x,
|
|
32165
|
+
y2: c.y,
|
|
32166
|
+
color,
|
|
32167
|
+
lineWidth: strokeWidth
|
|
32168
|
+
});
|
|
32169
|
+
}
|
|
32170
|
+
for (const a of arrows) {
|
|
32171
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
32172
|
+
const len = a.length ?? 60;
|
|
32173
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
32174
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
32175
|
+
out.push({
|
|
32176
|
+
type: "arrow",
|
|
32177
|
+
x1: a.x,
|
|
32178
|
+
y1: a.y,
|
|
32179
|
+
x2,
|
|
32180
|
+
y2,
|
|
32181
|
+
color: a.color ?? "#dc2626",
|
|
32182
|
+
lineWidth: 2
|
|
32183
|
+
});
|
|
32184
|
+
if (a.label) {
|
|
32185
|
+
out.push({
|
|
32186
|
+
type: "text",
|
|
32187
|
+
x: (a.x + x2) / 2,
|
|
32188
|
+
y: (a.y + y2) / 2 - 10,
|
|
32189
|
+
text: a.label,
|
|
32190
|
+
color: "#111827",
|
|
32191
|
+
fontSize: 12,
|
|
32192
|
+
align: "center"
|
|
32193
|
+
});
|
|
32194
|
+
}
|
|
32195
|
+
}
|
|
32196
|
+
for (const a of atoms) {
|
|
32197
|
+
out.push({
|
|
32198
|
+
type: "circle",
|
|
32199
|
+
x: a.x,
|
|
32200
|
+
y: a.y,
|
|
32201
|
+
radius: a.radius ?? 14,
|
|
32202
|
+
color: a.color ?? "#2563eb",
|
|
32203
|
+
fill: a.color ?? "#2563eb",
|
|
32204
|
+
id: a.id
|
|
32205
|
+
});
|
|
32206
|
+
if (a.element) {
|
|
32207
|
+
out.push({
|
|
32208
|
+
type: "text",
|
|
32209
|
+
x: a.x,
|
|
32210
|
+
y: a.y,
|
|
32211
|
+
text: a.element,
|
|
32212
|
+
color: "#ffffff",
|
|
32213
|
+
fontSize: 12,
|
|
32214
|
+
align: "center"
|
|
32215
|
+
});
|
|
32216
|
+
}
|
|
32217
|
+
}
|
|
32218
|
+
out.push(...shapes);
|
|
32219
|
+
return out;
|
|
32220
|
+
}, [atoms, bonds, arrows, shapes]);
|
|
32221
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
32222
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
32223
|
+
/* @__PURE__ */ jsx(
|
|
32224
|
+
LearningCanvas,
|
|
32225
|
+
{
|
|
32226
|
+
width,
|
|
32227
|
+
height,
|
|
32228
|
+
backgroundColor,
|
|
32229
|
+
shapes: derivedShapes,
|
|
32230
|
+
interactive,
|
|
32231
|
+
animate,
|
|
32232
|
+
onShapeClick,
|
|
32233
|
+
isLoading,
|
|
32234
|
+
error
|
|
32235
|
+
}
|
|
32236
|
+
)
|
|
32237
|
+
] }) });
|
|
32238
|
+
};
|
|
32239
|
+
}
|
|
32240
|
+
});
|
|
31716
32241
|
var CodeRunnerPanel;
|
|
31717
32242
|
var init_CodeRunnerPanel = __esm({
|
|
31718
32243
|
"components/core/organisms/CodeRunnerPanel.tsx"() {
|
|
@@ -37410,6 +37935,234 @@ var init_ProgressDots = __esm({
|
|
|
37410
37935
|
ProgressDots.displayName = "ProgressDots";
|
|
37411
37936
|
}
|
|
37412
37937
|
});
|
|
37938
|
+
var MathCanvas;
|
|
37939
|
+
var init_MathCanvas = __esm({
|
|
37940
|
+
"components/learning/molecules/MathCanvas.tsx"() {
|
|
37941
|
+
"use client";
|
|
37942
|
+
init_atoms();
|
|
37943
|
+
init_Stack();
|
|
37944
|
+
init_LearningCanvas();
|
|
37945
|
+
MathCanvas = ({
|
|
37946
|
+
className,
|
|
37947
|
+
width = 600,
|
|
37948
|
+
height = 400,
|
|
37949
|
+
title,
|
|
37950
|
+
xMin = -10,
|
|
37951
|
+
xMax = 10,
|
|
37952
|
+
yMin = -10,
|
|
37953
|
+
yMax = 10,
|
|
37954
|
+
showAxes = true,
|
|
37955
|
+
showGrid = true,
|
|
37956
|
+
gridStep = 1,
|
|
37957
|
+
curves = [],
|
|
37958
|
+
points = [],
|
|
37959
|
+
vectors = [],
|
|
37960
|
+
shapes = [],
|
|
37961
|
+
interactive = false,
|
|
37962
|
+
animate = false,
|
|
37963
|
+
onShapeClick,
|
|
37964
|
+
isLoading,
|
|
37965
|
+
error
|
|
37966
|
+
}) => {
|
|
37967
|
+
const derivedShapes = useMemo(() => {
|
|
37968
|
+
const out = [];
|
|
37969
|
+
const margin = 24;
|
|
37970
|
+
const plotW = width - margin * 2;
|
|
37971
|
+
const plotH = height - margin * 2;
|
|
37972
|
+
const mapX = (x) => margin + (x - xMin) / (xMax - xMin) * plotW;
|
|
37973
|
+
const mapY = (y) => height - (margin + (y - yMin) / (yMax - yMin) * plotH);
|
|
37974
|
+
if (showGrid) {
|
|
37975
|
+
for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
|
|
37976
|
+
const px = mapX(x);
|
|
37977
|
+
out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#e5e7eb", lineWidth: 1 });
|
|
37978
|
+
}
|
|
37979
|
+
for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
|
|
37980
|
+
const py = mapY(y);
|
|
37981
|
+
out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#e5e7eb", lineWidth: 1 });
|
|
37982
|
+
}
|
|
37983
|
+
}
|
|
37984
|
+
if (showAxes) {
|
|
37985
|
+
const xAxisY = Math.max(margin, Math.min(height - margin, mapY(0)));
|
|
37986
|
+
const yAxisX = Math.max(margin, Math.min(width - margin, mapX(0)));
|
|
37987
|
+
out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: "#374151", lineWidth: 2 });
|
|
37988
|
+
out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: "#374151", lineWidth: 2 });
|
|
37989
|
+
}
|
|
37990
|
+
for (const curve of curves) {
|
|
37991
|
+
if (!curve.samples || curve.samples.length < 2) continue;
|
|
37992
|
+
for (let i = 1; i < curve.samples.length; i++) {
|
|
37993
|
+
const a = curve.samples[i - 1];
|
|
37994
|
+
const b = curve.samples[i];
|
|
37995
|
+
if (a.x < xMin || a.x > xMax || b.x < xMin || b.x > xMax) continue;
|
|
37996
|
+
out.push({
|
|
37997
|
+
type: "line",
|
|
37998
|
+
x1: mapX(a.x),
|
|
37999
|
+
y1: mapY(a.y),
|
|
38000
|
+
x2: mapX(b.x),
|
|
38001
|
+
y2: mapY(b.y),
|
|
38002
|
+
color: curve.color ?? "#2563eb",
|
|
38003
|
+
lineWidth: 2
|
|
38004
|
+
});
|
|
38005
|
+
}
|
|
38006
|
+
}
|
|
38007
|
+
for (const p2 of points) {
|
|
38008
|
+
if (p2.x < xMin || p2.x > xMax || p2.y < yMin || p2.y > yMax) continue;
|
|
38009
|
+
out.push({
|
|
38010
|
+
type: "circle",
|
|
38011
|
+
x: mapX(p2.x),
|
|
38012
|
+
y: mapY(p2.y),
|
|
38013
|
+
radius: p2.radius ?? 4,
|
|
38014
|
+
color: p2.color ?? "#dc2626",
|
|
38015
|
+
fill: p2.color ?? "#dc2626"
|
|
38016
|
+
});
|
|
38017
|
+
if (p2.label) {
|
|
38018
|
+
out.push({ type: "text", x: mapX(p2.x) + 8, y: mapY(p2.y) - 8, text: p2.label, color: "#111827", fontSize: 12 });
|
|
38019
|
+
}
|
|
38020
|
+
}
|
|
38021
|
+
for (const v of vectors) {
|
|
38022
|
+
if (v.x < xMin || v.x > xMax || v.y < yMin || v.y > yMax) continue;
|
|
38023
|
+
const x1 = mapX(v.x);
|
|
38024
|
+
const y1 = mapY(v.y);
|
|
38025
|
+
const x2 = mapX(v.x + v.vx);
|
|
38026
|
+
const y2 = mapY(v.y + v.vy);
|
|
38027
|
+
out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
|
|
38028
|
+
if (v.label) {
|
|
38029
|
+
out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: "#111827", fontSize: 12 });
|
|
38030
|
+
}
|
|
38031
|
+
}
|
|
38032
|
+
out.push(...shapes);
|
|
38033
|
+
return out;
|
|
38034
|
+
}, [width, height, xMin, xMax, yMin, yMax, showAxes, showGrid, gridStep, curves, points, vectors, shapes]);
|
|
38035
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
38036
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
38037
|
+
/* @__PURE__ */ jsx(
|
|
38038
|
+
LearningCanvas,
|
|
38039
|
+
{
|
|
38040
|
+
width,
|
|
38041
|
+
height,
|
|
38042
|
+
shapes: derivedShapes,
|
|
38043
|
+
interactive,
|
|
38044
|
+
animate,
|
|
38045
|
+
onShapeClick,
|
|
38046
|
+
isLoading,
|
|
38047
|
+
error
|
|
38048
|
+
}
|
|
38049
|
+
)
|
|
38050
|
+
] }) });
|
|
38051
|
+
};
|
|
38052
|
+
}
|
|
38053
|
+
});
|
|
38054
|
+
var PhysicsCanvas;
|
|
38055
|
+
var init_PhysicsCanvas = __esm({
|
|
38056
|
+
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
38057
|
+
"use client";
|
|
38058
|
+
init_atoms();
|
|
38059
|
+
init_Stack();
|
|
38060
|
+
init_LearningCanvas();
|
|
38061
|
+
PhysicsCanvas = ({
|
|
38062
|
+
className,
|
|
38063
|
+
width = 600,
|
|
38064
|
+
height = 400,
|
|
38065
|
+
title,
|
|
38066
|
+
backgroundColor,
|
|
38067
|
+
bodies = [],
|
|
38068
|
+
constraints = [],
|
|
38069
|
+
showVelocity = true,
|
|
38070
|
+
showForces = false,
|
|
38071
|
+
velocityScale = 20,
|
|
38072
|
+
forceScale = 20,
|
|
38073
|
+
shapes = [],
|
|
38074
|
+
interactive = false,
|
|
38075
|
+
animate = false,
|
|
38076
|
+
onShapeClick,
|
|
38077
|
+
isLoading,
|
|
38078
|
+
error
|
|
38079
|
+
}) => {
|
|
38080
|
+
const derivedShapes = useMemo(() => {
|
|
38081
|
+
const out = [];
|
|
38082
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
38083
|
+
for (const b of bodies) {
|
|
38084
|
+
if (b.id) bodyById.set(b.id, b);
|
|
38085
|
+
}
|
|
38086
|
+
for (const c of constraints) {
|
|
38087
|
+
const a = bodyById.get(c.from);
|
|
38088
|
+
const b = bodyById.get(c.to);
|
|
38089
|
+
if (!a || !b) continue;
|
|
38090
|
+
out.push({
|
|
38091
|
+
type: "line",
|
|
38092
|
+
x1: a.x,
|
|
38093
|
+
y1: a.y,
|
|
38094
|
+
x2: b.x,
|
|
38095
|
+
y2: b.y,
|
|
38096
|
+
color: c.color ?? "#9ca3af",
|
|
38097
|
+
lineWidth: 2
|
|
38098
|
+
});
|
|
38099
|
+
}
|
|
38100
|
+
for (const b of bodies) {
|
|
38101
|
+
out.push({
|
|
38102
|
+
type: "circle",
|
|
38103
|
+
x: b.x,
|
|
38104
|
+
y: b.y,
|
|
38105
|
+
radius: b.radius ?? 12,
|
|
38106
|
+
color: b.color ?? "#2563eb",
|
|
38107
|
+
fill: b.color ?? "#2563eb",
|
|
38108
|
+
id: b.id
|
|
38109
|
+
});
|
|
38110
|
+
if (b.label) {
|
|
38111
|
+
out.push({
|
|
38112
|
+
type: "text",
|
|
38113
|
+
x: b.x + (b.radius ?? 12) + 6,
|
|
38114
|
+
y: b.y - (b.radius ?? 12) - 6,
|
|
38115
|
+
text: b.label,
|
|
38116
|
+
color: "#111827",
|
|
38117
|
+
fontSize: 12
|
|
38118
|
+
});
|
|
38119
|
+
}
|
|
38120
|
+
if (showVelocity && b.vx != null && b.vy != null && (b.vx !== 0 || b.vy !== 0)) {
|
|
38121
|
+
out.push({
|
|
38122
|
+
type: "arrow",
|
|
38123
|
+
x1: b.x,
|
|
38124
|
+
y1: b.y,
|
|
38125
|
+
x2: b.x + b.vx * velocityScale,
|
|
38126
|
+
y2: b.y + b.vy * velocityScale,
|
|
38127
|
+
color: "#16a34a",
|
|
38128
|
+
lineWidth: 2
|
|
38129
|
+
});
|
|
38130
|
+
}
|
|
38131
|
+
if (showForces && b.fx != null && b.fy != null && (b.fx !== 0 || b.fy !== 0)) {
|
|
38132
|
+
out.push({
|
|
38133
|
+
type: "arrow",
|
|
38134
|
+
x1: b.x,
|
|
38135
|
+
y1: b.y,
|
|
38136
|
+
x2: b.x + b.fx * forceScale,
|
|
38137
|
+
y2: b.y + b.fy * forceScale,
|
|
38138
|
+
color: "#dc2626",
|
|
38139
|
+
lineWidth: 2
|
|
38140
|
+
});
|
|
38141
|
+
}
|
|
38142
|
+
}
|
|
38143
|
+
out.push(...shapes);
|
|
38144
|
+
return out;
|
|
38145
|
+
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
38146
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
38147
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
38148
|
+
/* @__PURE__ */ jsx(
|
|
38149
|
+
LearningCanvas,
|
|
38150
|
+
{
|
|
38151
|
+
width,
|
|
38152
|
+
height,
|
|
38153
|
+
backgroundColor,
|
|
38154
|
+
shapes: derivedShapes,
|
|
38155
|
+
interactive,
|
|
38156
|
+
animate,
|
|
38157
|
+
onShapeClick,
|
|
38158
|
+
isLoading,
|
|
38159
|
+
error
|
|
38160
|
+
}
|
|
38161
|
+
)
|
|
38162
|
+
] }) });
|
|
38163
|
+
};
|
|
38164
|
+
}
|
|
38165
|
+
});
|
|
37413
38166
|
function resolveNodeColor(node, groups) {
|
|
37414
38167
|
if (node.color) return node.color;
|
|
37415
38168
|
if (node.group) {
|
|
@@ -37781,13 +38534,13 @@ var init_MapView = __esm({
|
|
|
37781
38534
|
shadowSize: [41, 41]
|
|
37782
38535
|
});
|
|
37783
38536
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
37784
|
-
const { useEffect:
|
|
38537
|
+
const { useEffect: useEffect79, useRef: useRef79, useCallback: useCallback118, useState: useState115 } = React114__default;
|
|
37785
38538
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
37786
38539
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
37787
38540
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
37788
38541
|
const map = useMap();
|
|
37789
|
-
const prevRef =
|
|
37790
|
-
|
|
38542
|
+
const prevRef = useRef79({ centerLat, centerLng, zoom });
|
|
38543
|
+
useEffect79(() => {
|
|
37791
38544
|
const prev = prevRef.current;
|
|
37792
38545
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
37793
38546
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -37798,7 +38551,7 @@ var init_MapView = __esm({
|
|
|
37798
38551
|
}
|
|
37799
38552
|
function MapClickHandler({ onMapClick }) {
|
|
37800
38553
|
const map = useMap();
|
|
37801
|
-
|
|
38554
|
+
useEffect79(() => {
|
|
37802
38555
|
if (!onMapClick) return;
|
|
37803
38556
|
const handler = (e) => {
|
|
37804
38557
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -45830,7 +46583,7 @@ function getGroupColor(group, groups) {
|
|
|
45830
46583
|
const idx = groups.indexOf(group);
|
|
45831
46584
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
45832
46585
|
}
|
|
45833
|
-
function
|
|
46586
|
+
function resolveColor3(color, el) {
|
|
45834
46587
|
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
45835
46588
|
if (!m) return color;
|
|
45836
46589
|
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
@@ -46091,7 +46844,7 @@ var init_GraphCanvas = __esm({
|
|
|
46091
46844
|
const w = logicalW;
|
|
46092
46845
|
const h = height;
|
|
46093
46846
|
const nodes = nodesRef.current;
|
|
46094
|
-
const accentColor =
|
|
46847
|
+
const accentColor = resolveColor3("var(--color-accent)", canvas);
|
|
46095
46848
|
const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
|
|
46096
46849
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
46097
46850
|
ctx.clearRect(0, 0, w, h);
|
|
@@ -46130,7 +46883,7 @@ var init_GraphCanvas = __esm({
|
|
|
46130
46883
|
ctx.globalAlpha = 1;
|
|
46131
46884
|
for (const node of nodes) {
|
|
46132
46885
|
const size = node.size || 8;
|
|
46133
|
-
const color =
|
|
46886
|
+
const color = resolveColor3(node.color || getGroupColor(node.group, groups), canvas);
|
|
46134
46887
|
const isHovered = hoveredNode === node.id;
|
|
46135
46888
|
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
46136
46889
|
ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
|
|
@@ -53028,6 +53781,7 @@ var init_component_registry_generated = __esm({
|
|
|
53028
53781
|
init_BattleBoard();
|
|
53029
53782
|
init_BattleTemplate();
|
|
53030
53783
|
init_BehaviorView();
|
|
53784
|
+
init_BiologyCanvas();
|
|
53031
53785
|
init_BloomQuizBlock();
|
|
53032
53786
|
init_BoardgameBoard();
|
|
53033
53787
|
init_BookChapterView();
|
|
@@ -53057,6 +53811,7 @@ var init_component_registry_generated = __esm({
|
|
|
53057
53811
|
init_ChartLegend();
|
|
53058
53812
|
init_ChatBar();
|
|
53059
53813
|
init_Checkbox();
|
|
53814
|
+
init_ChemistryCanvas();
|
|
53060
53815
|
init_ChoiceButton();
|
|
53061
53816
|
init_CityBuilderBoard();
|
|
53062
53817
|
init_CityBuilderTemplate();
|
|
@@ -53148,6 +53903,7 @@ var init_component_registry_generated = __esm({
|
|
|
53148
53903
|
init_JazariStateMachine();
|
|
53149
53904
|
init_LandingPageTemplate();
|
|
53150
53905
|
init_LawReferenceTooltip();
|
|
53906
|
+
init_LearningCanvas();
|
|
53151
53907
|
init_Lightbox();
|
|
53152
53908
|
init_LikertScale();
|
|
53153
53909
|
init_LineChart();
|
|
@@ -53156,9 +53912,11 @@ var init_component_registry_generated = __esm({
|
|
|
53156
53912
|
init_MapView();
|
|
53157
53913
|
init_MarkdownContent();
|
|
53158
53914
|
init_MarketingFooter();
|
|
53915
|
+
init_MarketingStatCard();
|
|
53159
53916
|
init_MasterDetail();
|
|
53160
53917
|
init_MasterDetailLayout();
|
|
53161
53918
|
init_MatchPuzzleBoard();
|
|
53919
|
+
init_MathCanvas();
|
|
53162
53920
|
init_MatrixQuestion();
|
|
53163
53921
|
init_MediaGallery();
|
|
53164
53922
|
init_Menu();
|
|
@@ -53177,6 +53935,7 @@ var init_component_registry_generated = __esm({
|
|
|
53177
53935
|
init_PageHeader();
|
|
53178
53936
|
init_Pagination();
|
|
53179
53937
|
init_PatternTile();
|
|
53938
|
+
init_PhysicsCanvas();
|
|
53180
53939
|
init_PinballBoard();
|
|
53181
53940
|
init_PirateBoard();
|
|
53182
53941
|
init_PlatformerBoard();
|
|
@@ -53353,6 +54112,7 @@ var init_component_registry_generated = __esm({
|
|
|
53353
54112
|
"BattleBoard": BattleBoard,
|
|
53354
54113
|
"BattleTemplate": BattleTemplate,
|
|
53355
54114
|
"BehaviorView": BehaviorView,
|
|
54115
|
+
"BiologyCanvas": BiologyCanvas,
|
|
53356
54116
|
"BloomQuizBlock": BloomQuizBlock,
|
|
53357
54117
|
"BoardgameBoard": BoardgameBoard,
|
|
53358
54118
|
"BookChapterView": BookChapterView,
|
|
@@ -53385,6 +54145,7 @@ var init_component_registry_generated = __esm({
|
|
|
53385
54145
|
"ChartLegend": ChartLegend,
|
|
53386
54146
|
"ChatBar": ChatBar,
|
|
53387
54147
|
"Checkbox": Checkbox,
|
|
54148
|
+
"ChemistryCanvas": ChemistryCanvas,
|
|
53388
54149
|
"ChoiceButton": ChoiceButton,
|
|
53389
54150
|
"CityBuilderBoard": CityBuilderBoard,
|
|
53390
54151
|
"CityBuilderTemplate": CityBuilderTemplate,
|
|
@@ -53486,6 +54247,7 @@ var init_component_registry_generated = __esm({
|
|
|
53486
54247
|
"LabelPattern": LabelPattern,
|
|
53487
54248
|
"LandingPageTemplate": LandingPageTemplate,
|
|
53488
54249
|
"LawReferenceTooltip": LawReferenceTooltip,
|
|
54250
|
+
"LearningCanvas": LearningCanvas,
|
|
53489
54251
|
"Lightbox": Lightbox,
|
|
53490
54252
|
"LikertScale": LikertScale,
|
|
53491
54253
|
"LineChart": LineChart2,
|
|
@@ -53494,9 +54256,11 @@ var init_component_registry_generated = __esm({
|
|
|
53494
54256
|
"MapView": MapView,
|
|
53495
54257
|
"MarkdownContent": MarkdownContent,
|
|
53496
54258
|
"MarketingFooter": MarketingFooter,
|
|
54259
|
+
"MarketingStatCard": MarketingStatCard,
|
|
53497
54260
|
"MasterDetail": MasterDetail,
|
|
53498
54261
|
"MasterDetailLayout": MasterDetailLayout,
|
|
53499
54262
|
"MatchPuzzleBoard": MatchPuzzleBoard,
|
|
54263
|
+
"MathCanvas": MathCanvas,
|
|
53500
54264
|
"MatrixQuestion": MatrixQuestion,
|
|
53501
54265
|
"MediaGallery": MediaGallery,
|
|
53502
54266
|
"Menu": Menu,
|
|
@@ -53515,6 +54279,7 @@ var init_component_registry_generated = __esm({
|
|
|
53515
54279
|
"PageHeader": PageHeader,
|
|
53516
54280
|
"Pagination": Pagination,
|
|
53517
54281
|
"PatternTile": PatternTile,
|
|
54282
|
+
"PhysicsCanvas": PhysicsCanvas,
|
|
53518
54283
|
"PinballBoard": PinballBoard,
|
|
53519
54284
|
"PirateBoard": PirateBoard,
|
|
53520
54285
|
"PlatformerBoard": PlatformerBoard,
|