@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/providers/index.cjs
CHANGED
|
@@ -5676,6 +5676,66 @@ var init_RangeSlider = __esm({
|
|
|
5676
5676
|
RangeSlider.displayName = "RangeSlider";
|
|
5677
5677
|
}
|
|
5678
5678
|
});
|
|
5679
|
+
function easeOut(t) {
|
|
5680
|
+
return t * (2 - t);
|
|
5681
|
+
}
|
|
5682
|
+
var AnimatedCounter;
|
|
5683
|
+
var init_AnimatedCounter = __esm({
|
|
5684
|
+
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
5685
|
+
"use client";
|
|
5686
|
+
init_cn();
|
|
5687
|
+
init_Typography();
|
|
5688
|
+
AnimatedCounter = ({
|
|
5689
|
+
value: rawValue,
|
|
5690
|
+
duration = 600,
|
|
5691
|
+
prefix,
|
|
5692
|
+
suffix,
|
|
5693
|
+
className
|
|
5694
|
+
}) => {
|
|
5695
|
+
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
5696
|
+
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
5697
|
+
const [displayValue, setDisplayValue] = React107.useState(value);
|
|
5698
|
+
const previousValueRef = React107.useRef(value);
|
|
5699
|
+
const animationFrameRef = React107.useRef(null);
|
|
5700
|
+
React107.useEffect(() => {
|
|
5701
|
+
const from = previousValueRef.current;
|
|
5702
|
+
const to = value;
|
|
5703
|
+
previousValueRef.current = value;
|
|
5704
|
+
if (from === to) {
|
|
5705
|
+
setDisplayValue(to);
|
|
5706
|
+
return;
|
|
5707
|
+
}
|
|
5708
|
+
const startTime = performance.now();
|
|
5709
|
+
const diff = to - from;
|
|
5710
|
+
function animate(currentTime) {
|
|
5711
|
+
const elapsed = currentTime - startTime;
|
|
5712
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
5713
|
+
const easedProgress = easeOut(progress);
|
|
5714
|
+
setDisplayValue(from + diff * easedProgress);
|
|
5715
|
+
if (progress < 1) {
|
|
5716
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5717
|
+
} else {
|
|
5718
|
+
setDisplayValue(to);
|
|
5719
|
+
}
|
|
5720
|
+
}
|
|
5721
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5722
|
+
return () => {
|
|
5723
|
+
if (animationFrameRef.current !== null) {
|
|
5724
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
5725
|
+
}
|
|
5726
|
+
};
|
|
5727
|
+
}, [value, duration]);
|
|
5728
|
+
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
5729
|
+
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
5730
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
5731
|
+
prefix,
|
|
5732
|
+
formattedValue,
|
|
5733
|
+
suffix
|
|
5734
|
+
] });
|
|
5735
|
+
};
|
|
5736
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
5737
|
+
}
|
|
5738
|
+
});
|
|
5679
5739
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
5680
5740
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
5681
5741
|
const observerRef = React107.useRef(null);
|
|
@@ -5972,6 +6032,34 @@ var init_SectionHeader = __esm({
|
|
|
5972
6032
|
SectionHeader.displayName = "SectionHeader";
|
|
5973
6033
|
}
|
|
5974
6034
|
});
|
|
6035
|
+
var sizeClasses6, MarketingStatCard;
|
|
6036
|
+
var init_MarketingStatCard = __esm({
|
|
6037
|
+
"components/marketing/atoms/MarketingStatCard.tsx"() {
|
|
6038
|
+
init_cn();
|
|
6039
|
+
init_Stack();
|
|
6040
|
+
init_Typography();
|
|
6041
|
+
sizeClasses6 = {
|
|
6042
|
+
sm: "text-2xl",
|
|
6043
|
+
md: "text-4xl",
|
|
6044
|
+
lg: "text-5xl"
|
|
6045
|
+
};
|
|
6046
|
+
MarketingStatCard = ({ value, label, size = "md", className }) => {
|
|
6047
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "center", className: cn(className), children: [
|
|
6048
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6049
|
+
Typography,
|
|
6050
|
+
{
|
|
6051
|
+
weight: "bold",
|
|
6052
|
+
color: "primary",
|
|
6053
|
+
className: cn(sizeClasses6[size]),
|
|
6054
|
+
children: value
|
|
6055
|
+
}
|
|
6056
|
+
),
|
|
6057
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
6058
|
+
] });
|
|
6059
|
+
};
|
|
6060
|
+
MarketingStatCard.displayName = "MarketingStatCard";
|
|
6061
|
+
}
|
|
6062
|
+
});
|
|
5975
6063
|
var backgroundClasses, paddingClasses, ContentSection;
|
|
5976
6064
|
var init_ContentSection = __esm({
|
|
5977
6065
|
"components/marketing/atoms/ContentSection.tsx"() {
|
|
@@ -19804,6 +19892,315 @@ var init_molecules = __esm({
|
|
|
19804
19892
|
init_puzzleObject();
|
|
19805
19893
|
}
|
|
19806
19894
|
});
|
|
19895
|
+
function resolveColor2(color, ctx, fallback) {
|
|
19896
|
+
if (!color) return fallback;
|
|
19897
|
+
if (color.startsWith("var(")) {
|
|
19898
|
+
ctx.canvas.style;
|
|
19899
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color);
|
|
19900
|
+
if (m) {
|
|
19901
|
+
const computed = getComputedStyle(ctx.canvas).getPropertyValue(m[1]).trim();
|
|
19902
|
+
return computed || m[2]?.trim() || fallback;
|
|
19903
|
+
}
|
|
19904
|
+
}
|
|
19905
|
+
return color;
|
|
19906
|
+
}
|
|
19907
|
+
function shapeBounds(shape) {
|
|
19908
|
+
switch (shape.type) {
|
|
19909
|
+
case "line":
|
|
19910
|
+
case "arrow":
|
|
19911
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) return null;
|
|
19912
|
+
return {
|
|
19913
|
+
x: Math.min(shape.x1, shape.x2) - 6,
|
|
19914
|
+
y: Math.min(shape.y1, shape.y2) - 6,
|
|
19915
|
+
w: Math.abs(shape.x2 - shape.x1) + 12,
|
|
19916
|
+
h: Math.abs(shape.y2 - shape.y1) + 12
|
|
19917
|
+
};
|
|
19918
|
+
case "circle":
|
|
19919
|
+
if (shape.x == null || shape.y == null || shape.radius == null) return null;
|
|
19920
|
+
return {
|
|
19921
|
+
x: shape.x - shape.radius - 4,
|
|
19922
|
+
y: shape.y - shape.radius - 4,
|
|
19923
|
+
w: shape.radius * 2 + 8,
|
|
19924
|
+
h: shape.radius * 2 + 8
|
|
19925
|
+
};
|
|
19926
|
+
case "rect":
|
|
19927
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) return null;
|
|
19928
|
+
return { x: shape.x - 4, y: shape.y - 4, w: shape.width + 8, h: shape.height + 8 };
|
|
19929
|
+
case "polygon":
|
|
19930
|
+
if (!shape.points || shape.points.length === 0) return null;
|
|
19931
|
+
{
|
|
19932
|
+
const xs = shape.points.map((p2) => p2.x);
|
|
19933
|
+
const ys = shape.points.map((p2) => p2.y);
|
|
19934
|
+
const minX = Math.min(...xs);
|
|
19935
|
+
const minY = Math.min(...ys);
|
|
19936
|
+
return {
|
|
19937
|
+
x: minX - 4,
|
|
19938
|
+
y: minY - 4,
|
|
19939
|
+
w: Math.max(...xs) - minX + 8,
|
|
19940
|
+
h: Math.max(...ys) - minY + 8
|
|
19941
|
+
};
|
|
19942
|
+
}
|
|
19943
|
+
case "text":
|
|
19944
|
+
if (shape.x == null || shape.y == null) return null;
|
|
19945
|
+
return { x: shape.x - 4, y: shape.y - (shape.fontSize ?? 14) - 4, w: 120, h: (shape.fontSize ?? 14) + 8 };
|
|
19946
|
+
default:
|
|
19947
|
+
return null;
|
|
19948
|
+
}
|
|
19949
|
+
}
|
|
19950
|
+
function drawArrowHead(ctx, x1, y1, x2, y2, size) {
|
|
19951
|
+
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
19952
|
+
ctx.beginPath();
|
|
19953
|
+
ctx.moveTo(x2, y2);
|
|
19954
|
+
ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
|
|
19955
|
+
ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
|
|
19956
|
+
ctx.closePath();
|
|
19957
|
+
ctx.fill();
|
|
19958
|
+
}
|
|
19959
|
+
function drawShape(ctx, shape, width, height) {
|
|
19960
|
+
ctx.save();
|
|
19961
|
+
const opacity = shape.opacity ?? 1;
|
|
19962
|
+
ctx.globalAlpha = opacity;
|
|
19963
|
+
const stroke = resolveColor2(shape.color, ctx, "#333333");
|
|
19964
|
+
const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
|
|
19965
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
19966
|
+
switch (shape.type) {
|
|
19967
|
+
case "grid": {
|
|
19968
|
+
const step = shape.step ?? 40;
|
|
19969
|
+
ctx.strokeStyle = stroke;
|
|
19970
|
+
ctx.globalAlpha = opacity * 0.25;
|
|
19971
|
+
ctx.lineWidth = 1;
|
|
19972
|
+
ctx.beginPath();
|
|
19973
|
+
for (let x = 0; x <= width; x += step) {
|
|
19974
|
+
ctx.moveTo(x, 0);
|
|
19975
|
+
ctx.lineTo(x, height);
|
|
19976
|
+
}
|
|
19977
|
+
for (let y = 0; y <= height; y += step) {
|
|
19978
|
+
ctx.moveTo(0, y);
|
|
19979
|
+
ctx.lineTo(width, y);
|
|
19980
|
+
}
|
|
19981
|
+
ctx.stroke();
|
|
19982
|
+
break;
|
|
19983
|
+
}
|
|
19984
|
+
case "axis": {
|
|
19985
|
+
const axis = shape.axis ?? "x";
|
|
19986
|
+
ctx.strokeStyle = stroke;
|
|
19987
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
19988
|
+
ctx.beginPath();
|
|
19989
|
+
if (axis === "x") {
|
|
19990
|
+
ctx.moveTo(0, height / 2);
|
|
19991
|
+
ctx.lineTo(width, height / 2);
|
|
19992
|
+
} else {
|
|
19993
|
+
ctx.moveTo(width / 2, 0);
|
|
19994
|
+
ctx.lineTo(width / 2, height);
|
|
19995
|
+
}
|
|
19996
|
+
ctx.stroke();
|
|
19997
|
+
break;
|
|
19998
|
+
}
|
|
19999
|
+
case "line": {
|
|
20000
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
20001
|
+
ctx.strokeStyle = stroke;
|
|
20002
|
+
ctx.beginPath();
|
|
20003
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
20004
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
20005
|
+
ctx.stroke();
|
|
20006
|
+
break;
|
|
20007
|
+
}
|
|
20008
|
+
case "arrow": {
|
|
20009
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
20010
|
+
ctx.strokeStyle = stroke;
|
|
20011
|
+
ctx.fillStyle = stroke;
|
|
20012
|
+
ctx.beginPath();
|
|
20013
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
20014
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
20015
|
+
ctx.stroke();
|
|
20016
|
+
drawArrowHead(ctx, shape.x1, shape.y1, shape.x2, shape.y2, 10);
|
|
20017
|
+
break;
|
|
20018
|
+
}
|
|
20019
|
+
case "circle": {
|
|
20020
|
+
if (shape.x == null || shape.y == null || shape.radius == null) break;
|
|
20021
|
+
ctx.beginPath();
|
|
20022
|
+
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
|
|
20023
|
+
if (fill) {
|
|
20024
|
+
ctx.fillStyle = fill;
|
|
20025
|
+
ctx.fill();
|
|
20026
|
+
}
|
|
20027
|
+
ctx.strokeStyle = stroke;
|
|
20028
|
+
ctx.stroke();
|
|
20029
|
+
break;
|
|
20030
|
+
}
|
|
20031
|
+
case "rect": {
|
|
20032
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) break;
|
|
20033
|
+
if (fill) {
|
|
20034
|
+
ctx.fillStyle = fill;
|
|
20035
|
+
ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
|
|
20036
|
+
}
|
|
20037
|
+
ctx.strokeStyle = stroke;
|
|
20038
|
+
ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
|
|
20039
|
+
break;
|
|
20040
|
+
}
|
|
20041
|
+
case "polygon": {
|
|
20042
|
+
if (!shape.points || shape.points.length < 2) break;
|
|
20043
|
+
ctx.beginPath();
|
|
20044
|
+
ctx.moveTo(shape.points[0].x, shape.points[0].y);
|
|
20045
|
+
for (let i = 1; i < shape.points.length; i++) {
|
|
20046
|
+
ctx.lineTo(shape.points[i].x, shape.points[i].y);
|
|
20047
|
+
}
|
|
20048
|
+
ctx.closePath();
|
|
20049
|
+
if (fill) {
|
|
20050
|
+
ctx.fillStyle = fill;
|
|
20051
|
+
ctx.fill();
|
|
20052
|
+
}
|
|
20053
|
+
ctx.strokeStyle = stroke;
|
|
20054
|
+
ctx.stroke();
|
|
20055
|
+
break;
|
|
20056
|
+
}
|
|
20057
|
+
case "path": {
|
|
20058
|
+
if (!shape.path) break;
|
|
20059
|
+
const p2 = new Path2D(shape.path);
|
|
20060
|
+
if (fill) {
|
|
20061
|
+
ctx.fillStyle = fill;
|
|
20062
|
+
ctx.fill(p2);
|
|
20063
|
+
}
|
|
20064
|
+
ctx.strokeStyle = stroke;
|
|
20065
|
+
ctx.stroke(p2);
|
|
20066
|
+
break;
|
|
20067
|
+
}
|
|
20068
|
+
case "text": {
|
|
20069
|
+
if (shape.x == null || shape.y == null || !shape.text) break;
|
|
20070
|
+
ctx.fillStyle = stroke;
|
|
20071
|
+
ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
|
|
20072
|
+
ctx.textAlign = shape.align ?? "left";
|
|
20073
|
+
ctx.textBaseline = "middle";
|
|
20074
|
+
ctx.fillText(shape.text, shape.x, shape.y);
|
|
20075
|
+
break;
|
|
20076
|
+
}
|
|
20077
|
+
}
|
|
20078
|
+
ctx.restore();
|
|
20079
|
+
}
|
|
20080
|
+
var LearningCanvas;
|
|
20081
|
+
var init_LearningCanvas = __esm({
|
|
20082
|
+
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
20083
|
+
"use client";
|
|
20084
|
+
init_cn();
|
|
20085
|
+
init_useEventBus();
|
|
20086
|
+
LearningCanvas = ({
|
|
20087
|
+
className,
|
|
20088
|
+
width = 600,
|
|
20089
|
+
height = 400,
|
|
20090
|
+
backgroundColor,
|
|
20091
|
+
shapes = [],
|
|
20092
|
+
interactive = false,
|
|
20093
|
+
animate = false,
|
|
20094
|
+
onShapeClick,
|
|
20095
|
+
onShapeHover,
|
|
20096
|
+
isLoading,
|
|
20097
|
+
error
|
|
20098
|
+
}) => {
|
|
20099
|
+
const canvasRef = React107.useRef(null);
|
|
20100
|
+
const eventBus = useEventBus();
|
|
20101
|
+
const animRef = React107.useRef(0);
|
|
20102
|
+
const hoverIndexRef = React107.useRef(-1);
|
|
20103
|
+
const findShapeAt = React107.useCallback((clientX, clientY) => {
|
|
20104
|
+
const canvas = canvasRef.current;
|
|
20105
|
+
if (!canvas) return -1;
|
|
20106
|
+
const rect = canvas.getBoundingClientRect();
|
|
20107
|
+
const x = clientX - rect.left;
|
|
20108
|
+
const y = clientY - rect.top;
|
|
20109
|
+
for (let i = shapes.length - 1; i >= 0; i--) {
|
|
20110
|
+
const b = shapeBounds(shapes[i]);
|
|
20111
|
+
if (b && x >= b.x && x <= b.x + b.w && y >= b.y && y <= b.y + b.h) {
|
|
20112
|
+
return i;
|
|
20113
|
+
}
|
|
20114
|
+
}
|
|
20115
|
+
return -1;
|
|
20116
|
+
}, [shapes]);
|
|
20117
|
+
const draw = React107.useCallback(() => {
|
|
20118
|
+
const canvas = canvasRef.current;
|
|
20119
|
+
if (!canvas) return;
|
|
20120
|
+
const ctx = canvas.getContext("2d");
|
|
20121
|
+
if (!ctx) return;
|
|
20122
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
20123
|
+
canvas.width = Math.max(1, Math.floor(width * dpr));
|
|
20124
|
+
canvas.height = Math.max(1, Math.floor(height * dpr));
|
|
20125
|
+
canvas.style.width = `${width}px`;
|
|
20126
|
+
canvas.style.height = `${height}px`;
|
|
20127
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
20128
|
+
ctx.clearRect(0, 0, width, height);
|
|
20129
|
+
if (backgroundColor) {
|
|
20130
|
+
ctx.fillStyle = backgroundColor;
|
|
20131
|
+
ctx.fillRect(0, 0, width, height);
|
|
20132
|
+
}
|
|
20133
|
+
for (const shape of shapes) {
|
|
20134
|
+
drawShape(ctx, shape, width, height);
|
|
20135
|
+
}
|
|
20136
|
+
}, [width, height, backgroundColor, shapes]);
|
|
20137
|
+
React107.useEffect(() => {
|
|
20138
|
+
draw();
|
|
20139
|
+
}, [draw]);
|
|
20140
|
+
React107.useEffect(() => {
|
|
20141
|
+
if (!animate) return;
|
|
20142
|
+
const loop = () => {
|
|
20143
|
+
draw();
|
|
20144
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20145
|
+
};
|
|
20146
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20147
|
+
return () => cancelAnimationFrame(animRef.current);
|
|
20148
|
+
}, [animate, draw]);
|
|
20149
|
+
const handlePointerMove = React107.useCallback(
|
|
20150
|
+
(e) => {
|
|
20151
|
+
if (!interactive) return;
|
|
20152
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20153
|
+
if (idx !== hoverIndexRef.current) {
|
|
20154
|
+
hoverIndexRef.current = idx;
|
|
20155
|
+
if (idx >= 0) {
|
|
20156
|
+
const shape = shapes[idx];
|
|
20157
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20158
|
+
if (onShapeHover) onShapeHover(payload);
|
|
20159
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_HOVER`, payload);
|
|
20160
|
+
}
|
|
20161
|
+
}
|
|
20162
|
+
},
|
|
20163
|
+
[interactive, onShapeHover, eventBus, findShapeAt, shapes]
|
|
20164
|
+
);
|
|
20165
|
+
const handleClick = React107.useCallback(
|
|
20166
|
+
(e) => {
|
|
20167
|
+
if (!interactive) return;
|
|
20168
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20169
|
+
if (idx >= 0) {
|
|
20170
|
+
const shape = shapes[idx];
|
|
20171
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20172
|
+
if (onShapeClick) onShapeClick(payload);
|
|
20173
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_CLICK`, payload);
|
|
20174
|
+
}
|
|
20175
|
+
},
|
|
20176
|
+
[interactive, onShapeClick, eventBus, findShapeAt, shapes]
|
|
20177
|
+
);
|
|
20178
|
+
if (isLoading || error) {
|
|
20179
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20180
|
+
"div",
|
|
20181
|
+
{
|
|
20182
|
+
className: cn(
|
|
20183
|
+
"flex items-center justify-center rounded border border-border bg-surface",
|
|
20184
|
+
className
|
|
20185
|
+
),
|
|
20186
|
+
style: { width, height },
|
|
20187
|
+
children: error ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-destructive", children: error.message }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: "Loading canvas\u2026" })
|
|
20188
|
+
}
|
|
20189
|
+
);
|
|
20190
|
+
}
|
|
20191
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
20192
|
+
"canvas",
|
|
20193
|
+
{
|
|
20194
|
+
ref: canvasRef,
|
|
20195
|
+
className: cn("block touch-none rounded border border-border", className),
|
|
20196
|
+
style: { width, height },
|
|
20197
|
+
onClick: handleClick,
|
|
20198
|
+
onPointerMove: handlePointerMove
|
|
20199
|
+
}
|
|
20200
|
+
);
|
|
20201
|
+
};
|
|
20202
|
+
}
|
|
20203
|
+
});
|
|
19807
20204
|
|
|
19808
20205
|
// components/core/atoms/index.ts
|
|
19809
20206
|
var init_atoms = __esm({
|
|
@@ -21672,91 +22069,6 @@ var init_ComponentPatterns = __esm({
|
|
|
21672
22069
|
AlertPattern.displayName = "AlertPattern";
|
|
21673
22070
|
}
|
|
21674
22071
|
});
|
|
21675
|
-
function parseValue(value) {
|
|
21676
|
-
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
21677
|
-
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
21678
|
-
if (!match) {
|
|
21679
|
-
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
21680
|
-
}
|
|
21681
|
-
const numStr = match[2];
|
|
21682
|
-
const decimalIdx = numStr.indexOf(".");
|
|
21683
|
-
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
21684
|
-
return {
|
|
21685
|
-
prefix: match[1],
|
|
21686
|
-
num: parseFloat(numStr),
|
|
21687
|
-
suffix: match[3],
|
|
21688
|
-
decimals
|
|
21689
|
-
};
|
|
21690
|
-
}
|
|
21691
|
-
var AnimatedCounter;
|
|
21692
|
-
var init_AnimatedCounter = __esm({
|
|
21693
|
-
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
21694
|
-
"use client";
|
|
21695
|
-
init_cn();
|
|
21696
|
-
init_Box();
|
|
21697
|
-
init_Typography();
|
|
21698
|
-
AnimatedCounter = ({
|
|
21699
|
-
value,
|
|
21700
|
-
label,
|
|
21701
|
-
duration = 1500,
|
|
21702
|
-
className
|
|
21703
|
-
}) => {
|
|
21704
|
-
const ref = React107.useRef(null);
|
|
21705
|
-
const [displayValue, setDisplayValue] = React107.useState("0");
|
|
21706
|
-
const [hasAnimated, setHasAnimated] = React107.useState(false);
|
|
21707
|
-
const animate = React107.useCallback(() => {
|
|
21708
|
-
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
21709
|
-
if (num2 === 0) {
|
|
21710
|
-
setDisplayValue(String(value));
|
|
21711
|
-
return;
|
|
21712
|
-
}
|
|
21713
|
-
const startTime = performance.now();
|
|
21714
|
-
const tick = (now) => {
|
|
21715
|
-
const elapsed = now - startTime;
|
|
21716
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
21717
|
-
const eased = 1 - Math.pow(1 - progress, 3);
|
|
21718
|
-
const current = eased * num2;
|
|
21719
|
-
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
21720
|
-
if (progress < 1) {
|
|
21721
|
-
requestAnimationFrame(tick);
|
|
21722
|
-
} else {
|
|
21723
|
-
setDisplayValue(String(value));
|
|
21724
|
-
}
|
|
21725
|
-
};
|
|
21726
|
-
requestAnimationFrame(tick);
|
|
21727
|
-
}, [value, duration]);
|
|
21728
|
-
React107.useEffect(() => {
|
|
21729
|
-
if (hasAnimated) return;
|
|
21730
|
-
const el = ref.current;
|
|
21731
|
-
if (!el) return;
|
|
21732
|
-
const observer2 = new IntersectionObserver(
|
|
21733
|
-
(entries) => {
|
|
21734
|
-
if (entries[0].isIntersecting) {
|
|
21735
|
-
setHasAnimated(true);
|
|
21736
|
-
animate();
|
|
21737
|
-
observer2.disconnect();
|
|
21738
|
-
}
|
|
21739
|
-
},
|
|
21740
|
-
{ threshold: 0.3 }
|
|
21741
|
-
);
|
|
21742
|
-
observer2.observe(el);
|
|
21743
|
-
return () => observer2.disconnect();
|
|
21744
|
-
}, [hasAnimated, animate]);
|
|
21745
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
21746
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
21747
|
-
Typography,
|
|
21748
|
-
{
|
|
21749
|
-
variant: "h2",
|
|
21750
|
-
className: "text-primary font-bold tabular-nums",
|
|
21751
|
-
children: hasAnimated ? displayValue : "0"
|
|
21752
|
-
}
|
|
21753
|
-
),
|
|
21754
|
-
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
21755
|
-
] });
|
|
21756
|
-
};
|
|
21757
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
21758
|
-
}
|
|
21759
|
-
});
|
|
21760
22072
|
var AuthLayout;
|
|
21761
22073
|
var init_AuthLayout = __esm({
|
|
21762
22074
|
"components/marketing/templates/AuthLayout.tsx"() {
|
|
@@ -22725,6 +23037,103 @@ var init_BehaviorView = __esm({
|
|
|
22725
23037
|
BehaviorView.displayName = "BehaviorView";
|
|
22726
23038
|
}
|
|
22727
23039
|
});
|
|
23040
|
+
var BiologyCanvas;
|
|
23041
|
+
var init_BiologyCanvas = __esm({
|
|
23042
|
+
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
23043
|
+
"use client";
|
|
23044
|
+
init_atoms();
|
|
23045
|
+
init_Stack();
|
|
23046
|
+
init_LearningCanvas();
|
|
23047
|
+
BiologyCanvas = ({
|
|
23048
|
+
className,
|
|
23049
|
+
width = 600,
|
|
23050
|
+
height = 400,
|
|
23051
|
+
title,
|
|
23052
|
+
backgroundColor,
|
|
23053
|
+
nodes = [],
|
|
23054
|
+
edges = [],
|
|
23055
|
+
shapes = [],
|
|
23056
|
+
interactive = false,
|
|
23057
|
+
animate = false,
|
|
23058
|
+
onShapeClick,
|
|
23059
|
+
isLoading,
|
|
23060
|
+
error
|
|
23061
|
+
}) => {
|
|
23062
|
+
const derivedShapes = React107.useMemo(() => {
|
|
23063
|
+
const out = [];
|
|
23064
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
23065
|
+
for (const n of nodes) {
|
|
23066
|
+
if (n.id) nodeById.set(n.id, n);
|
|
23067
|
+
}
|
|
23068
|
+
for (const e of edges) {
|
|
23069
|
+
const a = nodeById.get(e.from);
|
|
23070
|
+
const b = nodeById.get(e.to);
|
|
23071
|
+
if (!a || !b) continue;
|
|
23072
|
+
out.push({
|
|
23073
|
+
type: "line",
|
|
23074
|
+
x1: a.x,
|
|
23075
|
+
y1: a.y,
|
|
23076
|
+
x2: b.x,
|
|
23077
|
+
y2: b.y,
|
|
23078
|
+
color: e.color ?? "#9ca3af",
|
|
23079
|
+
lineWidth: 2
|
|
23080
|
+
});
|
|
23081
|
+
if (e.label) {
|
|
23082
|
+
out.push({
|
|
23083
|
+
type: "text",
|
|
23084
|
+
x: (a.x + b.x) / 2 + 4,
|
|
23085
|
+
y: (a.y + b.y) / 2 - 4,
|
|
23086
|
+
text: e.label,
|
|
23087
|
+
color: "#374151",
|
|
23088
|
+
fontSize: 11
|
|
23089
|
+
});
|
|
23090
|
+
}
|
|
23091
|
+
}
|
|
23092
|
+
for (const n of nodes) {
|
|
23093
|
+
out.push({
|
|
23094
|
+
type: "circle",
|
|
23095
|
+
x: n.x,
|
|
23096
|
+
y: n.y,
|
|
23097
|
+
radius: n.radius ?? 16,
|
|
23098
|
+
color: n.color ?? "#16a34a",
|
|
23099
|
+
fill: `${n.color ?? "#16a34a"}33`,
|
|
23100
|
+
id: n.id
|
|
23101
|
+
});
|
|
23102
|
+
if (n.label) {
|
|
23103
|
+
out.push({
|
|
23104
|
+
type: "text",
|
|
23105
|
+
x: n.x,
|
|
23106
|
+
y: n.y + (n.radius ?? 16) + 14,
|
|
23107
|
+
text: n.label,
|
|
23108
|
+
color: "#111827",
|
|
23109
|
+
fontSize: 12,
|
|
23110
|
+
align: "center"
|
|
23111
|
+
});
|
|
23112
|
+
}
|
|
23113
|
+
}
|
|
23114
|
+
out.push(...shapes);
|
|
23115
|
+
return out;
|
|
23116
|
+
}, [nodes, edges, shapes]);
|
|
23117
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
23118
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
23119
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23120
|
+
LearningCanvas,
|
|
23121
|
+
{
|
|
23122
|
+
width,
|
|
23123
|
+
height,
|
|
23124
|
+
backgroundColor,
|
|
23125
|
+
shapes: derivedShapes,
|
|
23126
|
+
interactive,
|
|
23127
|
+
animate,
|
|
23128
|
+
onShapeClick,
|
|
23129
|
+
isLoading,
|
|
23130
|
+
error
|
|
23131
|
+
}
|
|
23132
|
+
)
|
|
23133
|
+
] }) });
|
|
23134
|
+
};
|
|
23135
|
+
}
|
|
23136
|
+
});
|
|
22728
23137
|
|
|
22729
23138
|
// node_modules/katex/dist/katex.min.css
|
|
22730
23139
|
var init_katex_min = __esm({
|
|
@@ -29214,6 +29623,122 @@ var init_ChatBar = __esm({
|
|
|
29214
29623
|
ChatBar.displayName = "ChatBar";
|
|
29215
29624
|
}
|
|
29216
29625
|
});
|
|
29626
|
+
var ChemistryCanvas;
|
|
29627
|
+
var init_ChemistryCanvas = __esm({
|
|
29628
|
+
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
29629
|
+
"use client";
|
|
29630
|
+
init_atoms();
|
|
29631
|
+
init_Stack();
|
|
29632
|
+
init_LearningCanvas();
|
|
29633
|
+
ChemistryCanvas = ({
|
|
29634
|
+
className,
|
|
29635
|
+
width = 600,
|
|
29636
|
+
height = 400,
|
|
29637
|
+
title,
|
|
29638
|
+
backgroundColor,
|
|
29639
|
+
atoms = [],
|
|
29640
|
+
bonds = [],
|
|
29641
|
+
arrows = [],
|
|
29642
|
+
shapes = [],
|
|
29643
|
+
interactive = false,
|
|
29644
|
+
animate = false,
|
|
29645
|
+
onShapeClick,
|
|
29646
|
+
isLoading,
|
|
29647
|
+
error
|
|
29648
|
+
}) => {
|
|
29649
|
+
const derivedShapes = React107.useMemo(() => {
|
|
29650
|
+
const out = [];
|
|
29651
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
29652
|
+
for (const a of atoms) {
|
|
29653
|
+
if (a.id) atomById.set(a.id, a);
|
|
29654
|
+
}
|
|
29655
|
+
for (const b of bonds) {
|
|
29656
|
+
const a = atomById.get(b.from);
|
|
29657
|
+
const c = atomById.get(b.to);
|
|
29658
|
+
if (!a || !c) continue;
|
|
29659
|
+
const color = b.color ?? "#6b7280";
|
|
29660
|
+
const strokeWidth = b.type === "double" ? 4 : b.type === "triple" ? 6 : 2;
|
|
29661
|
+
out.push({
|
|
29662
|
+
type: "line",
|
|
29663
|
+
x1: a.x,
|
|
29664
|
+
y1: a.y,
|
|
29665
|
+
x2: c.x,
|
|
29666
|
+
y2: c.y,
|
|
29667
|
+
color,
|
|
29668
|
+
lineWidth: strokeWidth
|
|
29669
|
+
});
|
|
29670
|
+
}
|
|
29671
|
+
for (const a of arrows) {
|
|
29672
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
29673
|
+
const len = a.length ?? 60;
|
|
29674
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
29675
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
29676
|
+
out.push({
|
|
29677
|
+
type: "arrow",
|
|
29678
|
+
x1: a.x,
|
|
29679
|
+
y1: a.y,
|
|
29680
|
+
x2,
|
|
29681
|
+
y2,
|
|
29682
|
+
color: a.color ?? "#dc2626",
|
|
29683
|
+
lineWidth: 2
|
|
29684
|
+
});
|
|
29685
|
+
if (a.label) {
|
|
29686
|
+
out.push({
|
|
29687
|
+
type: "text",
|
|
29688
|
+
x: (a.x + x2) / 2,
|
|
29689
|
+
y: (a.y + y2) / 2 - 10,
|
|
29690
|
+
text: a.label,
|
|
29691
|
+
color: "#111827",
|
|
29692
|
+
fontSize: 12,
|
|
29693
|
+
align: "center"
|
|
29694
|
+
});
|
|
29695
|
+
}
|
|
29696
|
+
}
|
|
29697
|
+
for (const a of atoms) {
|
|
29698
|
+
out.push({
|
|
29699
|
+
type: "circle",
|
|
29700
|
+
x: a.x,
|
|
29701
|
+
y: a.y,
|
|
29702
|
+
radius: a.radius ?? 14,
|
|
29703
|
+
color: a.color ?? "#2563eb",
|
|
29704
|
+
fill: a.color ?? "#2563eb",
|
|
29705
|
+
id: a.id
|
|
29706
|
+
});
|
|
29707
|
+
if (a.element) {
|
|
29708
|
+
out.push({
|
|
29709
|
+
type: "text",
|
|
29710
|
+
x: a.x,
|
|
29711
|
+
y: a.y,
|
|
29712
|
+
text: a.element,
|
|
29713
|
+
color: "#ffffff",
|
|
29714
|
+
fontSize: 12,
|
|
29715
|
+
align: "center"
|
|
29716
|
+
});
|
|
29717
|
+
}
|
|
29718
|
+
}
|
|
29719
|
+
out.push(...shapes);
|
|
29720
|
+
return out;
|
|
29721
|
+
}, [atoms, bonds, arrows, shapes]);
|
|
29722
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
29723
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
29724
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29725
|
+
LearningCanvas,
|
|
29726
|
+
{
|
|
29727
|
+
width,
|
|
29728
|
+
height,
|
|
29729
|
+
backgroundColor,
|
|
29730
|
+
shapes: derivedShapes,
|
|
29731
|
+
interactive,
|
|
29732
|
+
animate,
|
|
29733
|
+
onShapeClick,
|
|
29734
|
+
isLoading,
|
|
29735
|
+
error
|
|
29736
|
+
}
|
|
29737
|
+
)
|
|
29738
|
+
] }) });
|
|
29739
|
+
};
|
|
29740
|
+
}
|
|
29741
|
+
});
|
|
29217
29742
|
var CodeRunnerPanel;
|
|
29218
29743
|
var init_CodeRunnerPanel = __esm({
|
|
29219
29744
|
"components/core/organisms/CodeRunnerPanel.tsx"() {
|
|
@@ -34911,6 +35436,234 @@ var init_ProgressDots = __esm({
|
|
|
34911
35436
|
ProgressDots.displayName = "ProgressDots";
|
|
34912
35437
|
}
|
|
34913
35438
|
});
|
|
35439
|
+
var MathCanvas;
|
|
35440
|
+
var init_MathCanvas = __esm({
|
|
35441
|
+
"components/learning/molecules/MathCanvas.tsx"() {
|
|
35442
|
+
"use client";
|
|
35443
|
+
init_atoms();
|
|
35444
|
+
init_Stack();
|
|
35445
|
+
init_LearningCanvas();
|
|
35446
|
+
MathCanvas = ({
|
|
35447
|
+
className,
|
|
35448
|
+
width = 600,
|
|
35449
|
+
height = 400,
|
|
35450
|
+
title,
|
|
35451
|
+
xMin = -10,
|
|
35452
|
+
xMax = 10,
|
|
35453
|
+
yMin = -10,
|
|
35454
|
+
yMax = 10,
|
|
35455
|
+
showAxes = true,
|
|
35456
|
+
showGrid = true,
|
|
35457
|
+
gridStep = 1,
|
|
35458
|
+
curves = [],
|
|
35459
|
+
points = [],
|
|
35460
|
+
vectors = [],
|
|
35461
|
+
shapes = [],
|
|
35462
|
+
interactive = false,
|
|
35463
|
+
animate = false,
|
|
35464
|
+
onShapeClick,
|
|
35465
|
+
isLoading,
|
|
35466
|
+
error
|
|
35467
|
+
}) => {
|
|
35468
|
+
const derivedShapes = React107.useMemo(() => {
|
|
35469
|
+
const out = [];
|
|
35470
|
+
const margin = 24;
|
|
35471
|
+
const plotW = width - margin * 2;
|
|
35472
|
+
const plotH = height - margin * 2;
|
|
35473
|
+
const mapX = (x) => margin + (x - xMin) / (xMax - xMin) * plotW;
|
|
35474
|
+
const mapY = (y) => height - (margin + (y - yMin) / (yMax - yMin) * plotH);
|
|
35475
|
+
if (showGrid) {
|
|
35476
|
+
for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
|
|
35477
|
+
const px = mapX(x);
|
|
35478
|
+
out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#e5e7eb", lineWidth: 1 });
|
|
35479
|
+
}
|
|
35480
|
+
for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
|
|
35481
|
+
const py = mapY(y);
|
|
35482
|
+
out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#e5e7eb", lineWidth: 1 });
|
|
35483
|
+
}
|
|
35484
|
+
}
|
|
35485
|
+
if (showAxes) {
|
|
35486
|
+
const xAxisY = Math.max(margin, Math.min(height - margin, mapY(0)));
|
|
35487
|
+
const yAxisX = Math.max(margin, Math.min(width - margin, mapX(0)));
|
|
35488
|
+
out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: "#374151", lineWidth: 2 });
|
|
35489
|
+
out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: "#374151", lineWidth: 2 });
|
|
35490
|
+
}
|
|
35491
|
+
for (const curve of curves) {
|
|
35492
|
+
if (!curve.samples || curve.samples.length < 2) continue;
|
|
35493
|
+
for (let i = 1; i < curve.samples.length; i++) {
|
|
35494
|
+
const a = curve.samples[i - 1];
|
|
35495
|
+
const b = curve.samples[i];
|
|
35496
|
+
if (a.x < xMin || a.x > xMax || b.x < xMin || b.x > xMax) continue;
|
|
35497
|
+
out.push({
|
|
35498
|
+
type: "line",
|
|
35499
|
+
x1: mapX(a.x),
|
|
35500
|
+
y1: mapY(a.y),
|
|
35501
|
+
x2: mapX(b.x),
|
|
35502
|
+
y2: mapY(b.y),
|
|
35503
|
+
color: curve.color ?? "#2563eb",
|
|
35504
|
+
lineWidth: 2
|
|
35505
|
+
});
|
|
35506
|
+
}
|
|
35507
|
+
}
|
|
35508
|
+
for (const p2 of points) {
|
|
35509
|
+
if (p2.x < xMin || p2.x > xMax || p2.y < yMin || p2.y > yMax) continue;
|
|
35510
|
+
out.push({
|
|
35511
|
+
type: "circle",
|
|
35512
|
+
x: mapX(p2.x),
|
|
35513
|
+
y: mapY(p2.y),
|
|
35514
|
+
radius: p2.radius ?? 4,
|
|
35515
|
+
color: p2.color ?? "#dc2626",
|
|
35516
|
+
fill: p2.color ?? "#dc2626"
|
|
35517
|
+
});
|
|
35518
|
+
if (p2.label) {
|
|
35519
|
+
out.push({ type: "text", x: mapX(p2.x) + 8, y: mapY(p2.y) - 8, text: p2.label, color: "#111827", fontSize: 12 });
|
|
35520
|
+
}
|
|
35521
|
+
}
|
|
35522
|
+
for (const v of vectors) {
|
|
35523
|
+
if (v.x < xMin || v.x > xMax || v.y < yMin || v.y > yMax) continue;
|
|
35524
|
+
const x1 = mapX(v.x);
|
|
35525
|
+
const y1 = mapY(v.y);
|
|
35526
|
+
const x2 = mapX(v.x + v.vx);
|
|
35527
|
+
const y2 = mapY(v.y + v.vy);
|
|
35528
|
+
out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
|
|
35529
|
+
if (v.label) {
|
|
35530
|
+
out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: "#111827", fontSize: 12 });
|
|
35531
|
+
}
|
|
35532
|
+
}
|
|
35533
|
+
out.push(...shapes);
|
|
35534
|
+
return out;
|
|
35535
|
+
}, [width, height, xMin, xMax, yMin, yMax, showAxes, showGrid, gridStep, curves, points, vectors, shapes]);
|
|
35536
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
35537
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35538
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35539
|
+
LearningCanvas,
|
|
35540
|
+
{
|
|
35541
|
+
width,
|
|
35542
|
+
height,
|
|
35543
|
+
shapes: derivedShapes,
|
|
35544
|
+
interactive,
|
|
35545
|
+
animate,
|
|
35546
|
+
onShapeClick,
|
|
35547
|
+
isLoading,
|
|
35548
|
+
error
|
|
35549
|
+
}
|
|
35550
|
+
)
|
|
35551
|
+
] }) });
|
|
35552
|
+
};
|
|
35553
|
+
}
|
|
35554
|
+
});
|
|
35555
|
+
var PhysicsCanvas;
|
|
35556
|
+
var init_PhysicsCanvas = __esm({
|
|
35557
|
+
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
35558
|
+
"use client";
|
|
35559
|
+
init_atoms();
|
|
35560
|
+
init_Stack();
|
|
35561
|
+
init_LearningCanvas();
|
|
35562
|
+
PhysicsCanvas = ({
|
|
35563
|
+
className,
|
|
35564
|
+
width = 600,
|
|
35565
|
+
height = 400,
|
|
35566
|
+
title,
|
|
35567
|
+
backgroundColor,
|
|
35568
|
+
bodies = [],
|
|
35569
|
+
constraints = [],
|
|
35570
|
+
showVelocity = true,
|
|
35571
|
+
showForces = false,
|
|
35572
|
+
velocityScale = 20,
|
|
35573
|
+
forceScale = 20,
|
|
35574
|
+
shapes = [],
|
|
35575
|
+
interactive = false,
|
|
35576
|
+
animate = false,
|
|
35577
|
+
onShapeClick,
|
|
35578
|
+
isLoading,
|
|
35579
|
+
error
|
|
35580
|
+
}) => {
|
|
35581
|
+
const derivedShapes = React107.useMemo(() => {
|
|
35582
|
+
const out = [];
|
|
35583
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
35584
|
+
for (const b of bodies) {
|
|
35585
|
+
if (b.id) bodyById.set(b.id, b);
|
|
35586
|
+
}
|
|
35587
|
+
for (const c of constraints) {
|
|
35588
|
+
const a = bodyById.get(c.from);
|
|
35589
|
+
const b = bodyById.get(c.to);
|
|
35590
|
+
if (!a || !b) continue;
|
|
35591
|
+
out.push({
|
|
35592
|
+
type: "line",
|
|
35593
|
+
x1: a.x,
|
|
35594
|
+
y1: a.y,
|
|
35595
|
+
x2: b.x,
|
|
35596
|
+
y2: b.y,
|
|
35597
|
+
color: c.color ?? "#9ca3af",
|
|
35598
|
+
lineWidth: 2
|
|
35599
|
+
});
|
|
35600
|
+
}
|
|
35601
|
+
for (const b of bodies) {
|
|
35602
|
+
out.push({
|
|
35603
|
+
type: "circle",
|
|
35604
|
+
x: b.x,
|
|
35605
|
+
y: b.y,
|
|
35606
|
+
radius: b.radius ?? 12,
|
|
35607
|
+
color: b.color ?? "#2563eb",
|
|
35608
|
+
fill: b.color ?? "#2563eb",
|
|
35609
|
+
id: b.id
|
|
35610
|
+
});
|
|
35611
|
+
if (b.label) {
|
|
35612
|
+
out.push({
|
|
35613
|
+
type: "text",
|
|
35614
|
+
x: b.x + (b.radius ?? 12) + 6,
|
|
35615
|
+
y: b.y - (b.radius ?? 12) - 6,
|
|
35616
|
+
text: b.label,
|
|
35617
|
+
color: "#111827",
|
|
35618
|
+
fontSize: 12
|
|
35619
|
+
});
|
|
35620
|
+
}
|
|
35621
|
+
if (showVelocity && b.vx != null && b.vy != null && (b.vx !== 0 || b.vy !== 0)) {
|
|
35622
|
+
out.push({
|
|
35623
|
+
type: "arrow",
|
|
35624
|
+
x1: b.x,
|
|
35625
|
+
y1: b.y,
|
|
35626
|
+
x2: b.x + b.vx * velocityScale,
|
|
35627
|
+
y2: b.y + b.vy * velocityScale,
|
|
35628
|
+
color: "#16a34a",
|
|
35629
|
+
lineWidth: 2
|
|
35630
|
+
});
|
|
35631
|
+
}
|
|
35632
|
+
if (showForces && b.fx != null && b.fy != null && (b.fx !== 0 || b.fy !== 0)) {
|
|
35633
|
+
out.push({
|
|
35634
|
+
type: "arrow",
|
|
35635
|
+
x1: b.x,
|
|
35636
|
+
y1: b.y,
|
|
35637
|
+
x2: b.x + b.fx * forceScale,
|
|
35638
|
+
y2: b.y + b.fy * forceScale,
|
|
35639
|
+
color: "#dc2626",
|
|
35640
|
+
lineWidth: 2
|
|
35641
|
+
});
|
|
35642
|
+
}
|
|
35643
|
+
}
|
|
35644
|
+
out.push(...shapes);
|
|
35645
|
+
return out;
|
|
35646
|
+
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
35647
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className, children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", children: [
|
|
35648
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35649
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
35650
|
+
LearningCanvas,
|
|
35651
|
+
{
|
|
35652
|
+
width,
|
|
35653
|
+
height,
|
|
35654
|
+
backgroundColor,
|
|
35655
|
+
shapes: derivedShapes,
|
|
35656
|
+
interactive,
|
|
35657
|
+
animate,
|
|
35658
|
+
onShapeClick,
|
|
35659
|
+
isLoading,
|
|
35660
|
+
error
|
|
35661
|
+
}
|
|
35662
|
+
)
|
|
35663
|
+
] }) });
|
|
35664
|
+
};
|
|
35665
|
+
}
|
|
35666
|
+
});
|
|
34914
35667
|
function resolveNodeColor(node, groups) {
|
|
34915
35668
|
if (node.color) return node.color;
|
|
34916
35669
|
if (node.group) {
|
|
@@ -35282,13 +36035,13 @@ var init_MapView = __esm({
|
|
|
35282
36035
|
shadowSize: [41, 41]
|
|
35283
36036
|
});
|
|
35284
36037
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
35285
|
-
const { useEffect:
|
|
36038
|
+
const { useEffect: useEffect76, useRef: useRef77, useCallback: useCallback117, useState: useState108 } = React107__namespace.default;
|
|
35286
36039
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
35287
36040
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
35288
36041
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
35289
36042
|
const map = useMap();
|
|
35290
|
-
const prevRef =
|
|
35291
|
-
|
|
36043
|
+
const prevRef = useRef77({ centerLat, centerLng, zoom });
|
|
36044
|
+
useEffect76(() => {
|
|
35292
36045
|
const prev = prevRef.current;
|
|
35293
36046
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
35294
36047
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -35299,7 +36052,7 @@ var init_MapView = __esm({
|
|
|
35299
36052
|
}
|
|
35300
36053
|
function MapClickHandler({ onMapClick }) {
|
|
35301
36054
|
const map = useMap();
|
|
35302
|
-
|
|
36055
|
+
useEffect76(() => {
|
|
35303
36056
|
if (!onMapClick) return;
|
|
35304
36057
|
const handler = (e) => {
|
|
35305
36058
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -43740,7 +44493,7 @@ function getGroupColor(group, groups) {
|
|
|
43740
44493
|
const idx = groups.indexOf(group);
|
|
43741
44494
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
43742
44495
|
}
|
|
43743
|
-
function
|
|
44496
|
+
function resolveColor3(color, el) {
|
|
43744
44497
|
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
43745
44498
|
if (!m) return color;
|
|
43746
44499
|
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
@@ -44001,7 +44754,7 @@ var init_GraphCanvas = __esm({
|
|
|
44001
44754
|
const w = logicalW;
|
|
44002
44755
|
const h = height;
|
|
44003
44756
|
const nodes = nodesRef.current;
|
|
44004
|
-
const accentColor =
|
|
44757
|
+
const accentColor = resolveColor3("var(--color-accent)", canvas);
|
|
44005
44758
|
const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
|
|
44006
44759
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
44007
44760
|
ctx.clearRect(0, 0, w, h);
|
|
@@ -44040,7 +44793,7 @@ var init_GraphCanvas = __esm({
|
|
|
44040
44793
|
ctx.globalAlpha = 1;
|
|
44041
44794
|
for (const node of nodes) {
|
|
44042
44795
|
const size = node.size || 8;
|
|
44043
|
-
const color =
|
|
44796
|
+
const color = resolveColor3(node.color || getGroupColor(node.group, groups), canvas);
|
|
44044
44797
|
const isHovered = hoveredNode === node.id;
|
|
44045
44798
|
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
44046
44799
|
ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
|
|
@@ -50919,6 +51672,7 @@ var init_component_registry_generated = __esm({
|
|
|
50919
51672
|
init_BattleBoard();
|
|
50920
51673
|
init_BattleTemplate();
|
|
50921
51674
|
init_BehaviorView();
|
|
51675
|
+
init_BiologyCanvas();
|
|
50922
51676
|
init_BloomQuizBlock();
|
|
50923
51677
|
init_BoardgameBoard();
|
|
50924
51678
|
init_BookChapterView();
|
|
@@ -50948,6 +51702,7 @@ var init_component_registry_generated = __esm({
|
|
|
50948
51702
|
init_ChartLegend();
|
|
50949
51703
|
init_ChatBar();
|
|
50950
51704
|
init_Checkbox();
|
|
51705
|
+
init_ChemistryCanvas();
|
|
50951
51706
|
init_ChoiceButton();
|
|
50952
51707
|
init_CityBuilderBoard();
|
|
50953
51708
|
init_CityBuilderTemplate();
|
|
@@ -51039,6 +51794,7 @@ var init_component_registry_generated = __esm({
|
|
|
51039
51794
|
init_JazariStateMachine();
|
|
51040
51795
|
init_LandingPageTemplate();
|
|
51041
51796
|
init_LawReferenceTooltip();
|
|
51797
|
+
init_LearningCanvas();
|
|
51042
51798
|
init_Lightbox();
|
|
51043
51799
|
init_LikertScale();
|
|
51044
51800
|
init_LineChart();
|
|
@@ -51047,9 +51803,11 @@ var init_component_registry_generated = __esm({
|
|
|
51047
51803
|
init_MapView();
|
|
51048
51804
|
init_MarkdownContent();
|
|
51049
51805
|
init_MarketingFooter();
|
|
51806
|
+
init_MarketingStatCard();
|
|
51050
51807
|
init_MasterDetail();
|
|
51051
51808
|
init_MasterDetailLayout();
|
|
51052
51809
|
init_MatchPuzzleBoard();
|
|
51810
|
+
init_MathCanvas();
|
|
51053
51811
|
init_MatrixQuestion();
|
|
51054
51812
|
init_MediaGallery();
|
|
51055
51813
|
init_Menu();
|
|
@@ -51068,6 +51826,7 @@ var init_component_registry_generated = __esm({
|
|
|
51068
51826
|
init_PageHeader();
|
|
51069
51827
|
init_Pagination();
|
|
51070
51828
|
init_PatternTile();
|
|
51829
|
+
init_PhysicsCanvas();
|
|
51071
51830
|
init_PinballBoard();
|
|
51072
51831
|
init_PirateBoard();
|
|
51073
51832
|
init_PlatformerBoard();
|
|
@@ -51244,6 +52003,7 @@ var init_component_registry_generated = __esm({
|
|
|
51244
52003
|
"BattleBoard": BattleBoard,
|
|
51245
52004
|
"BattleTemplate": BattleTemplate,
|
|
51246
52005
|
"BehaviorView": BehaviorView,
|
|
52006
|
+
"BiologyCanvas": BiologyCanvas,
|
|
51247
52007
|
"BloomQuizBlock": BloomQuizBlock,
|
|
51248
52008
|
"BoardgameBoard": BoardgameBoard,
|
|
51249
52009
|
"BookChapterView": BookChapterView,
|
|
@@ -51276,6 +52036,7 @@ var init_component_registry_generated = __esm({
|
|
|
51276
52036
|
"ChartLegend": ChartLegend,
|
|
51277
52037
|
"ChatBar": ChatBar,
|
|
51278
52038
|
"Checkbox": Checkbox,
|
|
52039
|
+
"ChemistryCanvas": ChemistryCanvas,
|
|
51279
52040
|
"ChoiceButton": ChoiceButton,
|
|
51280
52041
|
"CityBuilderBoard": CityBuilderBoard,
|
|
51281
52042
|
"CityBuilderTemplate": CityBuilderTemplate,
|
|
@@ -51377,6 +52138,7 @@ var init_component_registry_generated = __esm({
|
|
|
51377
52138
|
"LabelPattern": LabelPattern,
|
|
51378
52139
|
"LandingPageTemplate": LandingPageTemplate,
|
|
51379
52140
|
"LawReferenceTooltip": LawReferenceTooltip,
|
|
52141
|
+
"LearningCanvas": LearningCanvas,
|
|
51380
52142
|
"Lightbox": Lightbox,
|
|
51381
52143
|
"LikertScale": LikertScale,
|
|
51382
52144
|
"LineChart": LineChart2,
|
|
@@ -51385,9 +52147,11 @@ var init_component_registry_generated = __esm({
|
|
|
51385
52147
|
"MapView": MapView,
|
|
51386
52148
|
"MarkdownContent": MarkdownContent,
|
|
51387
52149
|
"MarketingFooter": MarketingFooter,
|
|
52150
|
+
"MarketingStatCard": MarketingStatCard,
|
|
51388
52151
|
"MasterDetail": MasterDetail,
|
|
51389
52152
|
"MasterDetailLayout": MasterDetailLayout,
|
|
51390
52153
|
"MatchPuzzleBoard": MatchPuzzleBoard,
|
|
52154
|
+
"MathCanvas": MathCanvas,
|
|
51391
52155
|
"MatrixQuestion": MatrixQuestion,
|
|
51392
52156
|
"MediaGallery": MediaGallery,
|
|
51393
52157
|
"Menu": Menu,
|
|
@@ -51406,6 +52170,7 @@ var init_component_registry_generated = __esm({
|
|
|
51406
52170
|
"PageHeader": PageHeader,
|
|
51407
52171
|
"Pagination": Pagination,
|
|
51408
52172
|
"PatternTile": PatternTile,
|
|
52173
|
+
"PhysicsCanvas": PhysicsCanvas,
|
|
51409
52174
|
"PinballBoard": PinballBoard,
|
|
51410
52175
|
"PirateBoard": PirateBoard,
|
|
51411
52176
|
"PlatformerBoard": PlatformerBoard,
|