@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/providers/index.js
CHANGED
|
@@ -5631,6 +5631,66 @@ var init_RangeSlider = __esm({
|
|
|
5631
5631
|
RangeSlider.displayName = "RangeSlider";
|
|
5632
5632
|
}
|
|
5633
5633
|
});
|
|
5634
|
+
function easeOut(t) {
|
|
5635
|
+
return t * (2 - t);
|
|
5636
|
+
}
|
|
5637
|
+
var AnimatedCounter;
|
|
5638
|
+
var init_AnimatedCounter = __esm({
|
|
5639
|
+
"components/marketing/atoms/AnimatedCounter.tsx"() {
|
|
5640
|
+
"use client";
|
|
5641
|
+
init_cn();
|
|
5642
|
+
init_Typography();
|
|
5643
|
+
AnimatedCounter = ({
|
|
5644
|
+
value: rawValue,
|
|
5645
|
+
duration = 600,
|
|
5646
|
+
prefix,
|
|
5647
|
+
suffix,
|
|
5648
|
+
className
|
|
5649
|
+
}) => {
|
|
5650
|
+
const numericRaw = typeof rawValue === "number" ? rawValue : Number.parseFloat(String(rawValue ?? ""));
|
|
5651
|
+
const value = !Number.isNaN(numericRaw) ? numericRaw : 0;
|
|
5652
|
+
const [displayValue, setDisplayValue] = useState(value);
|
|
5653
|
+
const previousValueRef = useRef(value);
|
|
5654
|
+
const animationFrameRef = useRef(null);
|
|
5655
|
+
useEffect(() => {
|
|
5656
|
+
const from = previousValueRef.current;
|
|
5657
|
+
const to = value;
|
|
5658
|
+
previousValueRef.current = value;
|
|
5659
|
+
if (from === to) {
|
|
5660
|
+
setDisplayValue(to);
|
|
5661
|
+
return;
|
|
5662
|
+
}
|
|
5663
|
+
const startTime = performance.now();
|
|
5664
|
+
const diff = to - from;
|
|
5665
|
+
function animate(currentTime) {
|
|
5666
|
+
const elapsed = currentTime - startTime;
|
|
5667
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
5668
|
+
const easedProgress = easeOut(progress);
|
|
5669
|
+
setDisplayValue(from + diff * easedProgress);
|
|
5670
|
+
if (progress < 1) {
|
|
5671
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5672
|
+
} else {
|
|
5673
|
+
setDisplayValue(to);
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
animationFrameRef.current = requestAnimationFrame(animate);
|
|
5677
|
+
return () => {
|
|
5678
|
+
if (animationFrameRef.current !== null) {
|
|
5679
|
+
cancelAnimationFrame(animationFrameRef.current);
|
|
5680
|
+
}
|
|
5681
|
+
};
|
|
5682
|
+
}, [value, duration]);
|
|
5683
|
+
const decimalPlaces = Number.isInteger(value) ? 0 : String(value).split(".")[1]?.length ?? 0;
|
|
5684
|
+
const formattedValue = displayValue.toFixed(decimalPlaces);
|
|
5685
|
+
return /* @__PURE__ */ jsxs(Typography, { variant: "h3", className: cn("tabular-nums", className), children: [
|
|
5686
|
+
prefix,
|
|
5687
|
+
formattedValue,
|
|
5688
|
+
suffix
|
|
5689
|
+
] });
|
|
5690
|
+
};
|
|
5691
|
+
AnimatedCounter.displayName = "AnimatedCounter";
|
|
5692
|
+
}
|
|
5693
|
+
});
|
|
5634
5694
|
function useInfiniteScroll(onLoadMore, options = {}) {
|
|
5635
5695
|
const { rootMargin = "200px", hasMore = true, isLoading = false } = options;
|
|
5636
5696
|
const observerRef = useRef(null);
|
|
@@ -5927,6 +5987,34 @@ var init_SectionHeader = __esm({
|
|
|
5927
5987
|
SectionHeader.displayName = "SectionHeader";
|
|
5928
5988
|
}
|
|
5929
5989
|
});
|
|
5990
|
+
var sizeClasses6, MarketingStatCard;
|
|
5991
|
+
var init_MarketingStatCard = __esm({
|
|
5992
|
+
"components/marketing/atoms/MarketingStatCard.tsx"() {
|
|
5993
|
+
init_cn();
|
|
5994
|
+
init_Stack();
|
|
5995
|
+
init_Typography();
|
|
5996
|
+
sizeClasses6 = {
|
|
5997
|
+
sm: "text-2xl",
|
|
5998
|
+
md: "text-4xl",
|
|
5999
|
+
lg: "text-5xl"
|
|
6000
|
+
};
|
|
6001
|
+
MarketingStatCard = ({ value, label, size = "md", className }) => {
|
|
6002
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", className: cn(className), children: [
|
|
6003
|
+
/* @__PURE__ */ jsx(
|
|
6004
|
+
Typography,
|
|
6005
|
+
{
|
|
6006
|
+
weight: "bold",
|
|
6007
|
+
color: "primary",
|
|
6008
|
+
className: cn(sizeClasses6[size]),
|
|
6009
|
+
children: value
|
|
6010
|
+
}
|
|
6011
|
+
),
|
|
6012
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "muted", children: label })
|
|
6013
|
+
] });
|
|
6014
|
+
};
|
|
6015
|
+
MarketingStatCard.displayName = "MarketingStatCard";
|
|
6016
|
+
}
|
|
6017
|
+
});
|
|
5930
6018
|
var backgroundClasses, paddingClasses, ContentSection;
|
|
5931
6019
|
var init_ContentSection = __esm({
|
|
5932
6020
|
"components/marketing/atoms/ContentSection.tsx"() {
|
|
@@ -19759,6 +19847,315 @@ var init_molecules = __esm({
|
|
|
19759
19847
|
init_puzzleObject();
|
|
19760
19848
|
}
|
|
19761
19849
|
});
|
|
19850
|
+
function resolveColor2(color, ctx, fallback) {
|
|
19851
|
+
if (!color) return fallback;
|
|
19852
|
+
if (color.startsWith("var(")) {
|
|
19853
|
+
ctx.canvas.style;
|
|
19854
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color);
|
|
19855
|
+
if (m) {
|
|
19856
|
+
const computed = getComputedStyle(ctx.canvas).getPropertyValue(m[1]).trim();
|
|
19857
|
+
return computed || m[2]?.trim() || fallback;
|
|
19858
|
+
}
|
|
19859
|
+
}
|
|
19860
|
+
return color;
|
|
19861
|
+
}
|
|
19862
|
+
function shapeBounds(shape) {
|
|
19863
|
+
switch (shape.type) {
|
|
19864
|
+
case "line":
|
|
19865
|
+
case "arrow":
|
|
19866
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) return null;
|
|
19867
|
+
return {
|
|
19868
|
+
x: Math.min(shape.x1, shape.x2) - 6,
|
|
19869
|
+
y: Math.min(shape.y1, shape.y2) - 6,
|
|
19870
|
+
w: Math.abs(shape.x2 - shape.x1) + 12,
|
|
19871
|
+
h: Math.abs(shape.y2 - shape.y1) + 12
|
|
19872
|
+
};
|
|
19873
|
+
case "circle":
|
|
19874
|
+
if (shape.x == null || shape.y == null || shape.radius == null) return null;
|
|
19875
|
+
return {
|
|
19876
|
+
x: shape.x - shape.radius - 4,
|
|
19877
|
+
y: shape.y - shape.radius - 4,
|
|
19878
|
+
w: shape.radius * 2 + 8,
|
|
19879
|
+
h: shape.radius * 2 + 8
|
|
19880
|
+
};
|
|
19881
|
+
case "rect":
|
|
19882
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) return null;
|
|
19883
|
+
return { x: shape.x - 4, y: shape.y - 4, w: shape.width + 8, h: shape.height + 8 };
|
|
19884
|
+
case "polygon":
|
|
19885
|
+
if (!shape.points || shape.points.length === 0) return null;
|
|
19886
|
+
{
|
|
19887
|
+
const xs = shape.points.map((p2) => p2.x);
|
|
19888
|
+
const ys = shape.points.map((p2) => p2.y);
|
|
19889
|
+
const minX = Math.min(...xs);
|
|
19890
|
+
const minY = Math.min(...ys);
|
|
19891
|
+
return {
|
|
19892
|
+
x: minX - 4,
|
|
19893
|
+
y: minY - 4,
|
|
19894
|
+
w: Math.max(...xs) - minX + 8,
|
|
19895
|
+
h: Math.max(...ys) - minY + 8
|
|
19896
|
+
};
|
|
19897
|
+
}
|
|
19898
|
+
case "text":
|
|
19899
|
+
if (shape.x == null || shape.y == null) return null;
|
|
19900
|
+
return { x: shape.x - 4, y: shape.y - (shape.fontSize ?? 14) - 4, w: 120, h: (shape.fontSize ?? 14) + 8 };
|
|
19901
|
+
default:
|
|
19902
|
+
return null;
|
|
19903
|
+
}
|
|
19904
|
+
}
|
|
19905
|
+
function drawArrowHead(ctx, x1, y1, x2, y2, size) {
|
|
19906
|
+
const angle = Math.atan2(y2 - y1, x2 - x1);
|
|
19907
|
+
ctx.beginPath();
|
|
19908
|
+
ctx.moveTo(x2, y2);
|
|
19909
|
+
ctx.lineTo(x2 - size * Math.cos(angle - Math.PI / 6), y2 - size * Math.sin(angle - Math.PI / 6));
|
|
19910
|
+
ctx.lineTo(x2 - size * Math.cos(angle + Math.PI / 6), y2 - size * Math.sin(angle + Math.PI / 6));
|
|
19911
|
+
ctx.closePath();
|
|
19912
|
+
ctx.fill();
|
|
19913
|
+
}
|
|
19914
|
+
function drawShape(ctx, shape, width, height) {
|
|
19915
|
+
ctx.save();
|
|
19916
|
+
const opacity = shape.opacity ?? 1;
|
|
19917
|
+
ctx.globalAlpha = opacity;
|
|
19918
|
+
const stroke = resolveColor2(shape.color, ctx, "#333333");
|
|
19919
|
+
const fill = shape.fill ? resolveColor2(shape.fill, ctx, "#cccccc") : void 0;
|
|
19920
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
19921
|
+
switch (shape.type) {
|
|
19922
|
+
case "grid": {
|
|
19923
|
+
const step = shape.step ?? 40;
|
|
19924
|
+
ctx.strokeStyle = stroke;
|
|
19925
|
+
ctx.globalAlpha = opacity * 0.25;
|
|
19926
|
+
ctx.lineWidth = 1;
|
|
19927
|
+
ctx.beginPath();
|
|
19928
|
+
for (let x = 0; x <= width; x += step) {
|
|
19929
|
+
ctx.moveTo(x, 0);
|
|
19930
|
+
ctx.lineTo(x, height);
|
|
19931
|
+
}
|
|
19932
|
+
for (let y = 0; y <= height; y += step) {
|
|
19933
|
+
ctx.moveTo(0, y);
|
|
19934
|
+
ctx.lineTo(width, y);
|
|
19935
|
+
}
|
|
19936
|
+
ctx.stroke();
|
|
19937
|
+
break;
|
|
19938
|
+
}
|
|
19939
|
+
case "axis": {
|
|
19940
|
+
const axis = shape.axis ?? "x";
|
|
19941
|
+
ctx.strokeStyle = stroke;
|
|
19942
|
+
ctx.lineWidth = shape.lineWidth ?? 2;
|
|
19943
|
+
ctx.beginPath();
|
|
19944
|
+
if (axis === "x") {
|
|
19945
|
+
ctx.moveTo(0, height / 2);
|
|
19946
|
+
ctx.lineTo(width, height / 2);
|
|
19947
|
+
} else {
|
|
19948
|
+
ctx.moveTo(width / 2, 0);
|
|
19949
|
+
ctx.lineTo(width / 2, height);
|
|
19950
|
+
}
|
|
19951
|
+
ctx.stroke();
|
|
19952
|
+
break;
|
|
19953
|
+
}
|
|
19954
|
+
case "line": {
|
|
19955
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
19956
|
+
ctx.strokeStyle = stroke;
|
|
19957
|
+
ctx.beginPath();
|
|
19958
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
19959
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
19960
|
+
ctx.stroke();
|
|
19961
|
+
break;
|
|
19962
|
+
}
|
|
19963
|
+
case "arrow": {
|
|
19964
|
+
if (shape.x1 == null || shape.y1 == null || shape.x2 == null || shape.y2 == null) break;
|
|
19965
|
+
ctx.strokeStyle = stroke;
|
|
19966
|
+
ctx.fillStyle = stroke;
|
|
19967
|
+
ctx.beginPath();
|
|
19968
|
+
ctx.moveTo(shape.x1, shape.y1);
|
|
19969
|
+
ctx.lineTo(shape.x2, shape.y2);
|
|
19970
|
+
ctx.stroke();
|
|
19971
|
+
drawArrowHead(ctx, shape.x1, shape.y1, shape.x2, shape.y2, 10);
|
|
19972
|
+
break;
|
|
19973
|
+
}
|
|
19974
|
+
case "circle": {
|
|
19975
|
+
if (shape.x == null || shape.y == null || shape.radius == null) break;
|
|
19976
|
+
ctx.beginPath();
|
|
19977
|
+
ctx.arc(shape.x, shape.y, shape.radius, 0, Math.PI * 2);
|
|
19978
|
+
if (fill) {
|
|
19979
|
+
ctx.fillStyle = fill;
|
|
19980
|
+
ctx.fill();
|
|
19981
|
+
}
|
|
19982
|
+
ctx.strokeStyle = stroke;
|
|
19983
|
+
ctx.stroke();
|
|
19984
|
+
break;
|
|
19985
|
+
}
|
|
19986
|
+
case "rect": {
|
|
19987
|
+
if (shape.x == null || shape.y == null || shape.width == null || shape.height == null) break;
|
|
19988
|
+
if (fill) {
|
|
19989
|
+
ctx.fillStyle = fill;
|
|
19990
|
+
ctx.fillRect(shape.x, shape.y, shape.width, shape.height);
|
|
19991
|
+
}
|
|
19992
|
+
ctx.strokeStyle = stroke;
|
|
19993
|
+
ctx.strokeRect(shape.x, shape.y, shape.width, shape.height);
|
|
19994
|
+
break;
|
|
19995
|
+
}
|
|
19996
|
+
case "polygon": {
|
|
19997
|
+
if (!shape.points || shape.points.length < 2) break;
|
|
19998
|
+
ctx.beginPath();
|
|
19999
|
+
ctx.moveTo(shape.points[0].x, shape.points[0].y);
|
|
20000
|
+
for (let i = 1; i < shape.points.length; i++) {
|
|
20001
|
+
ctx.lineTo(shape.points[i].x, shape.points[i].y);
|
|
20002
|
+
}
|
|
20003
|
+
ctx.closePath();
|
|
20004
|
+
if (fill) {
|
|
20005
|
+
ctx.fillStyle = fill;
|
|
20006
|
+
ctx.fill();
|
|
20007
|
+
}
|
|
20008
|
+
ctx.strokeStyle = stroke;
|
|
20009
|
+
ctx.stroke();
|
|
20010
|
+
break;
|
|
20011
|
+
}
|
|
20012
|
+
case "path": {
|
|
20013
|
+
if (!shape.path) break;
|
|
20014
|
+
const p2 = new Path2D(shape.path);
|
|
20015
|
+
if (fill) {
|
|
20016
|
+
ctx.fillStyle = fill;
|
|
20017
|
+
ctx.fill(p2);
|
|
20018
|
+
}
|
|
20019
|
+
ctx.strokeStyle = stroke;
|
|
20020
|
+
ctx.stroke(p2);
|
|
20021
|
+
break;
|
|
20022
|
+
}
|
|
20023
|
+
case "text": {
|
|
20024
|
+
if (shape.x == null || shape.y == null || !shape.text) break;
|
|
20025
|
+
ctx.fillStyle = stroke;
|
|
20026
|
+
ctx.font = `${shape.fontSize ?? 14}px system-ui, sans-serif`;
|
|
20027
|
+
ctx.textAlign = shape.align ?? "left";
|
|
20028
|
+
ctx.textBaseline = "middle";
|
|
20029
|
+
ctx.fillText(shape.text, shape.x, shape.y);
|
|
20030
|
+
break;
|
|
20031
|
+
}
|
|
20032
|
+
}
|
|
20033
|
+
ctx.restore();
|
|
20034
|
+
}
|
|
20035
|
+
var LearningCanvas;
|
|
20036
|
+
var init_LearningCanvas = __esm({
|
|
20037
|
+
"components/learning/atoms/LearningCanvas.tsx"() {
|
|
20038
|
+
"use client";
|
|
20039
|
+
init_cn();
|
|
20040
|
+
init_useEventBus();
|
|
20041
|
+
LearningCanvas = ({
|
|
20042
|
+
className,
|
|
20043
|
+
width = 600,
|
|
20044
|
+
height = 400,
|
|
20045
|
+
backgroundColor,
|
|
20046
|
+
shapes = [],
|
|
20047
|
+
interactive = false,
|
|
20048
|
+
animate = false,
|
|
20049
|
+
onShapeClick,
|
|
20050
|
+
onShapeHover,
|
|
20051
|
+
isLoading,
|
|
20052
|
+
error
|
|
20053
|
+
}) => {
|
|
20054
|
+
const canvasRef = useRef(null);
|
|
20055
|
+
const eventBus = useEventBus();
|
|
20056
|
+
const animRef = useRef(0);
|
|
20057
|
+
const hoverIndexRef = useRef(-1);
|
|
20058
|
+
const findShapeAt = useCallback((clientX, clientY) => {
|
|
20059
|
+
const canvas = canvasRef.current;
|
|
20060
|
+
if (!canvas) return -1;
|
|
20061
|
+
const rect = canvas.getBoundingClientRect();
|
|
20062
|
+
const x = clientX - rect.left;
|
|
20063
|
+
const y = clientY - rect.top;
|
|
20064
|
+
for (let i = shapes.length - 1; i >= 0; i--) {
|
|
20065
|
+
const b = shapeBounds(shapes[i]);
|
|
20066
|
+
if (b && x >= b.x && x <= b.x + b.w && y >= b.y && y <= b.y + b.h) {
|
|
20067
|
+
return i;
|
|
20068
|
+
}
|
|
20069
|
+
}
|
|
20070
|
+
return -1;
|
|
20071
|
+
}, [shapes]);
|
|
20072
|
+
const draw = useCallback(() => {
|
|
20073
|
+
const canvas = canvasRef.current;
|
|
20074
|
+
if (!canvas) return;
|
|
20075
|
+
const ctx = canvas.getContext("2d");
|
|
20076
|
+
if (!ctx) return;
|
|
20077
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
20078
|
+
canvas.width = Math.max(1, Math.floor(width * dpr));
|
|
20079
|
+
canvas.height = Math.max(1, Math.floor(height * dpr));
|
|
20080
|
+
canvas.style.width = `${width}px`;
|
|
20081
|
+
canvas.style.height = `${height}px`;
|
|
20082
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
20083
|
+
ctx.clearRect(0, 0, width, height);
|
|
20084
|
+
if (backgroundColor) {
|
|
20085
|
+
ctx.fillStyle = backgroundColor;
|
|
20086
|
+
ctx.fillRect(0, 0, width, height);
|
|
20087
|
+
}
|
|
20088
|
+
for (const shape of shapes) {
|
|
20089
|
+
drawShape(ctx, shape, width, height);
|
|
20090
|
+
}
|
|
20091
|
+
}, [width, height, backgroundColor, shapes]);
|
|
20092
|
+
useEffect(() => {
|
|
20093
|
+
draw();
|
|
20094
|
+
}, [draw]);
|
|
20095
|
+
useEffect(() => {
|
|
20096
|
+
if (!animate) return;
|
|
20097
|
+
const loop = () => {
|
|
20098
|
+
draw();
|
|
20099
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20100
|
+
};
|
|
20101
|
+
animRef.current = requestAnimationFrame(loop);
|
|
20102
|
+
return () => cancelAnimationFrame(animRef.current);
|
|
20103
|
+
}, [animate, draw]);
|
|
20104
|
+
const handlePointerMove = useCallback(
|
|
20105
|
+
(e) => {
|
|
20106
|
+
if (!interactive) return;
|
|
20107
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20108
|
+
if (idx !== hoverIndexRef.current) {
|
|
20109
|
+
hoverIndexRef.current = idx;
|
|
20110
|
+
if (idx >= 0) {
|
|
20111
|
+
const shape = shapes[idx];
|
|
20112
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20113
|
+
if (onShapeHover) onShapeHover(payload);
|
|
20114
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_HOVER`, payload);
|
|
20115
|
+
}
|
|
20116
|
+
}
|
|
20117
|
+
},
|
|
20118
|
+
[interactive, onShapeHover, eventBus, findShapeAt, shapes]
|
|
20119
|
+
);
|
|
20120
|
+
const handleClick = useCallback(
|
|
20121
|
+
(e) => {
|
|
20122
|
+
if (!interactive) return;
|
|
20123
|
+
const idx = findShapeAt(e.clientX, e.clientY);
|
|
20124
|
+
if (idx >= 0) {
|
|
20125
|
+
const shape = shapes[idx];
|
|
20126
|
+
const payload = { id: shape.id, type: shape.type, index: idx };
|
|
20127
|
+
if (onShapeClick) onShapeClick(payload);
|
|
20128
|
+
else if (eventBus) eventBus.emit(`UI:SHAPE_CLICK`, payload);
|
|
20129
|
+
}
|
|
20130
|
+
},
|
|
20131
|
+
[interactive, onShapeClick, eventBus, findShapeAt, shapes]
|
|
20132
|
+
);
|
|
20133
|
+
if (isLoading || error) {
|
|
20134
|
+
return /* @__PURE__ */ jsx(
|
|
20135
|
+
"div",
|
|
20136
|
+
{
|
|
20137
|
+
className: cn(
|
|
20138
|
+
"flex items-center justify-center rounded border border-border bg-surface",
|
|
20139
|
+
className
|
|
20140
|
+
),
|
|
20141
|
+
style: { width, height },
|
|
20142
|
+
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" })
|
|
20143
|
+
}
|
|
20144
|
+
);
|
|
20145
|
+
}
|
|
20146
|
+
return /* @__PURE__ */ jsx(
|
|
20147
|
+
"canvas",
|
|
20148
|
+
{
|
|
20149
|
+
ref: canvasRef,
|
|
20150
|
+
className: cn("block touch-none rounded border border-border", className),
|
|
20151
|
+
style: { width, height },
|
|
20152
|
+
onClick: handleClick,
|
|
20153
|
+
onPointerMove: handlePointerMove
|
|
20154
|
+
}
|
|
20155
|
+
);
|
|
20156
|
+
};
|
|
20157
|
+
}
|
|
20158
|
+
});
|
|
19762
20159
|
|
|
19763
20160
|
// components/core/atoms/index.ts
|
|
19764
20161
|
var init_atoms = __esm({
|
|
@@ -21627,91 +22024,6 @@ var init_ComponentPatterns = __esm({
|
|
|
21627
22024
|
AlertPattern.displayName = "AlertPattern";
|
|
21628
22025
|
}
|
|
21629
22026
|
});
|
|
21630
|
-
function parseValue(value) {
|
|
21631
|
-
if (value === "" || value == null) return { num: 0, prefix: "", suffix: "", decimals: 0 };
|
|
21632
|
-
const match = String(value).match(/^([^0-9]*)([0-9]+(?:\.[0-9]+)?)(.*)$/);
|
|
21633
|
-
if (!match) {
|
|
21634
|
-
return { num: 0, prefix: "", suffix: String(value), decimals: 0 };
|
|
21635
|
-
}
|
|
21636
|
-
const numStr = match[2];
|
|
21637
|
-
const decimalIdx = numStr.indexOf(".");
|
|
21638
|
-
const decimals = decimalIdx >= 0 ? numStr.length - decimalIdx - 1 : 0;
|
|
21639
|
-
return {
|
|
21640
|
-
prefix: match[1],
|
|
21641
|
-
num: parseFloat(numStr),
|
|
21642
|
-
suffix: match[3],
|
|
21643
|
-
decimals
|
|
21644
|
-
};
|
|
21645
|
-
}
|
|
21646
|
-
var AnimatedCounter;
|
|
21647
|
-
var init_AnimatedCounter = __esm({
|
|
21648
|
-
"components/core/molecules/AnimatedCounter.tsx"() {
|
|
21649
|
-
"use client";
|
|
21650
|
-
init_cn();
|
|
21651
|
-
init_Box();
|
|
21652
|
-
init_Typography();
|
|
21653
|
-
AnimatedCounter = ({
|
|
21654
|
-
value,
|
|
21655
|
-
label,
|
|
21656
|
-
duration = 1500,
|
|
21657
|
-
className
|
|
21658
|
-
}) => {
|
|
21659
|
-
const ref = useRef(null);
|
|
21660
|
-
const [displayValue, setDisplayValue] = useState("0");
|
|
21661
|
-
const [hasAnimated, setHasAnimated] = useState(false);
|
|
21662
|
-
const animate = useCallback(() => {
|
|
21663
|
-
const { num: num2, prefix, suffix, decimals } = parseValue(value);
|
|
21664
|
-
if (num2 === 0) {
|
|
21665
|
-
setDisplayValue(String(value));
|
|
21666
|
-
return;
|
|
21667
|
-
}
|
|
21668
|
-
const startTime = performance.now();
|
|
21669
|
-
const tick = (now) => {
|
|
21670
|
-
const elapsed = now - startTime;
|
|
21671
|
-
const progress = Math.min(elapsed / duration, 1);
|
|
21672
|
-
const eased = 1 - Math.pow(1 - progress, 3);
|
|
21673
|
-
const current = eased * num2;
|
|
21674
|
-
setDisplayValue(`${prefix}${current.toFixed(decimals)}${suffix}`);
|
|
21675
|
-
if (progress < 1) {
|
|
21676
|
-
requestAnimationFrame(tick);
|
|
21677
|
-
} else {
|
|
21678
|
-
setDisplayValue(String(value));
|
|
21679
|
-
}
|
|
21680
|
-
};
|
|
21681
|
-
requestAnimationFrame(tick);
|
|
21682
|
-
}, [value, duration]);
|
|
21683
|
-
useEffect(() => {
|
|
21684
|
-
if (hasAnimated) return;
|
|
21685
|
-
const el = ref.current;
|
|
21686
|
-
if (!el) return;
|
|
21687
|
-
const observer2 = new IntersectionObserver(
|
|
21688
|
-
(entries) => {
|
|
21689
|
-
if (entries[0].isIntersecting) {
|
|
21690
|
-
setHasAnimated(true);
|
|
21691
|
-
animate();
|
|
21692
|
-
observer2.disconnect();
|
|
21693
|
-
}
|
|
21694
|
-
},
|
|
21695
|
-
{ threshold: 0.3 }
|
|
21696
|
-
);
|
|
21697
|
-
observer2.observe(el);
|
|
21698
|
-
return () => observer2.disconnect();
|
|
21699
|
-
}, [hasAnimated, animate]);
|
|
21700
|
-
return /* @__PURE__ */ jsxs(Box, { ref, className: cn("flex flex-col items-center gap-1 p-4", className), children: [
|
|
21701
|
-
/* @__PURE__ */ jsx(
|
|
21702
|
-
Typography,
|
|
21703
|
-
{
|
|
21704
|
-
variant: "h2",
|
|
21705
|
-
className: "text-primary font-bold tabular-nums",
|
|
21706
|
-
children: hasAnimated ? displayValue : "0"
|
|
21707
|
-
}
|
|
21708
|
-
),
|
|
21709
|
-
/* @__PURE__ */ jsx(Typography, { variant: "body2", color: "muted", className: "text-center", children: label })
|
|
21710
|
-
] });
|
|
21711
|
-
};
|
|
21712
|
-
AnimatedCounter.displayName = "AnimatedCounter";
|
|
21713
|
-
}
|
|
21714
|
-
});
|
|
21715
22027
|
var AuthLayout;
|
|
21716
22028
|
var init_AuthLayout = __esm({
|
|
21717
22029
|
"components/marketing/templates/AuthLayout.tsx"() {
|
|
@@ -22680,10 +22992,107 @@ var init_BehaviorView = __esm({
|
|
|
22680
22992
|
BehaviorView.displayName = "BehaviorView";
|
|
22681
22993
|
}
|
|
22682
22994
|
});
|
|
22995
|
+
var BiologyCanvas;
|
|
22996
|
+
var init_BiologyCanvas = __esm({
|
|
22997
|
+
"components/learning/molecules/BiologyCanvas.tsx"() {
|
|
22998
|
+
"use client";
|
|
22999
|
+
init_atoms();
|
|
23000
|
+
init_Stack();
|
|
23001
|
+
init_LearningCanvas();
|
|
23002
|
+
BiologyCanvas = ({
|
|
23003
|
+
className,
|
|
23004
|
+
width = 600,
|
|
23005
|
+
height = 400,
|
|
23006
|
+
title,
|
|
23007
|
+
backgroundColor,
|
|
23008
|
+
nodes = [],
|
|
23009
|
+
edges = [],
|
|
23010
|
+
shapes = [],
|
|
23011
|
+
interactive = false,
|
|
23012
|
+
animate = false,
|
|
23013
|
+
onShapeClick,
|
|
23014
|
+
isLoading,
|
|
23015
|
+
error
|
|
23016
|
+
}) => {
|
|
23017
|
+
const derivedShapes = useMemo(() => {
|
|
23018
|
+
const out = [];
|
|
23019
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
23020
|
+
for (const n of nodes) {
|
|
23021
|
+
if (n.id) nodeById.set(n.id, n);
|
|
23022
|
+
}
|
|
23023
|
+
for (const e of edges) {
|
|
23024
|
+
const a = nodeById.get(e.from);
|
|
23025
|
+
const b = nodeById.get(e.to);
|
|
23026
|
+
if (!a || !b) continue;
|
|
23027
|
+
out.push({
|
|
23028
|
+
type: "line",
|
|
23029
|
+
x1: a.x,
|
|
23030
|
+
y1: a.y,
|
|
23031
|
+
x2: b.x,
|
|
23032
|
+
y2: b.y,
|
|
23033
|
+
color: e.color ?? "#9ca3af",
|
|
23034
|
+
lineWidth: 2
|
|
23035
|
+
});
|
|
23036
|
+
if (e.label) {
|
|
23037
|
+
out.push({
|
|
23038
|
+
type: "text",
|
|
23039
|
+
x: (a.x + b.x) / 2 + 4,
|
|
23040
|
+
y: (a.y + b.y) / 2 - 4,
|
|
23041
|
+
text: e.label,
|
|
23042
|
+
color: "#374151",
|
|
23043
|
+
fontSize: 11
|
|
23044
|
+
});
|
|
23045
|
+
}
|
|
23046
|
+
}
|
|
23047
|
+
for (const n of nodes) {
|
|
23048
|
+
out.push({
|
|
23049
|
+
type: "circle",
|
|
23050
|
+
x: n.x,
|
|
23051
|
+
y: n.y,
|
|
23052
|
+
radius: n.radius ?? 16,
|
|
23053
|
+
color: n.color ?? "#16a34a",
|
|
23054
|
+
fill: `${n.color ?? "#16a34a"}33`,
|
|
23055
|
+
id: n.id
|
|
23056
|
+
});
|
|
23057
|
+
if (n.label) {
|
|
23058
|
+
out.push({
|
|
23059
|
+
type: "text",
|
|
23060
|
+
x: n.x,
|
|
23061
|
+
y: n.y + (n.radius ?? 16) + 14,
|
|
23062
|
+
text: n.label,
|
|
23063
|
+
color: "#111827",
|
|
23064
|
+
fontSize: 12,
|
|
23065
|
+
align: "center"
|
|
23066
|
+
});
|
|
23067
|
+
}
|
|
23068
|
+
}
|
|
23069
|
+
out.push(...shapes);
|
|
23070
|
+
return out;
|
|
23071
|
+
}, [nodes, edges, shapes]);
|
|
23072
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
23073
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
23074
|
+
/* @__PURE__ */ jsx(
|
|
23075
|
+
LearningCanvas,
|
|
23076
|
+
{
|
|
23077
|
+
width,
|
|
23078
|
+
height,
|
|
23079
|
+
backgroundColor,
|
|
23080
|
+
shapes: derivedShapes,
|
|
23081
|
+
interactive,
|
|
23082
|
+
animate,
|
|
23083
|
+
onShapeClick,
|
|
23084
|
+
isLoading,
|
|
23085
|
+
error
|
|
23086
|
+
}
|
|
23087
|
+
)
|
|
23088
|
+
] }) });
|
|
23089
|
+
};
|
|
23090
|
+
}
|
|
23091
|
+
});
|
|
22683
23092
|
|
|
22684
|
-
// node_modules/katex/dist/katex.min.css
|
|
23093
|
+
// node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css
|
|
22685
23094
|
var init_katex_min = __esm({
|
|
22686
|
-
"node_modules/katex/dist/katex.min.css"() {
|
|
23095
|
+
"node_modules/.pnpm/katex@0.16.47/node_modules/katex/dist/katex.min.css"() {
|
|
22687
23096
|
}
|
|
22688
23097
|
});
|
|
22689
23098
|
var Tabs;
|
|
@@ -29169,6 +29578,122 @@ var init_ChatBar = __esm({
|
|
|
29169
29578
|
ChatBar.displayName = "ChatBar";
|
|
29170
29579
|
}
|
|
29171
29580
|
});
|
|
29581
|
+
var ChemistryCanvas;
|
|
29582
|
+
var init_ChemistryCanvas = __esm({
|
|
29583
|
+
"components/learning/molecules/ChemistryCanvas.tsx"() {
|
|
29584
|
+
"use client";
|
|
29585
|
+
init_atoms();
|
|
29586
|
+
init_Stack();
|
|
29587
|
+
init_LearningCanvas();
|
|
29588
|
+
ChemistryCanvas = ({
|
|
29589
|
+
className,
|
|
29590
|
+
width = 600,
|
|
29591
|
+
height = 400,
|
|
29592
|
+
title,
|
|
29593
|
+
backgroundColor,
|
|
29594
|
+
atoms = [],
|
|
29595
|
+
bonds = [],
|
|
29596
|
+
arrows = [],
|
|
29597
|
+
shapes = [],
|
|
29598
|
+
interactive = false,
|
|
29599
|
+
animate = false,
|
|
29600
|
+
onShapeClick,
|
|
29601
|
+
isLoading,
|
|
29602
|
+
error
|
|
29603
|
+
}) => {
|
|
29604
|
+
const derivedShapes = useMemo(() => {
|
|
29605
|
+
const out = [];
|
|
29606
|
+
const atomById = /* @__PURE__ */ new Map();
|
|
29607
|
+
for (const a of atoms) {
|
|
29608
|
+
if (a.id) atomById.set(a.id, a);
|
|
29609
|
+
}
|
|
29610
|
+
for (const b of bonds) {
|
|
29611
|
+
const a = atomById.get(b.from);
|
|
29612
|
+
const c = atomById.get(b.to);
|
|
29613
|
+
if (!a || !c) continue;
|
|
29614
|
+
const color = b.color ?? "#6b7280";
|
|
29615
|
+
const strokeWidth = b.type === "double" ? 4 : b.type === "triple" ? 6 : 2;
|
|
29616
|
+
out.push({
|
|
29617
|
+
type: "line",
|
|
29618
|
+
x1: a.x,
|
|
29619
|
+
y1: a.y,
|
|
29620
|
+
x2: c.x,
|
|
29621
|
+
y2: c.y,
|
|
29622
|
+
color,
|
|
29623
|
+
lineWidth: strokeWidth
|
|
29624
|
+
});
|
|
29625
|
+
}
|
|
29626
|
+
for (const a of arrows) {
|
|
29627
|
+
const angle = (a.angle ?? 0) * (Math.PI / 180);
|
|
29628
|
+
const len = a.length ?? 60;
|
|
29629
|
+
const x2 = a.x + Math.cos(angle) * len;
|
|
29630
|
+
const y2 = a.y + Math.sin(angle) * len;
|
|
29631
|
+
out.push({
|
|
29632
|
+
type: "arrow",
|
|
29633
|
+
x1: a.x,
|
|
29634
|
+
y1: a.y,
|
|
29635
|
+
x2,
|
|
29636
|
+
y2,
|
|
29637
|
+
color: a.color ?? "#dc2626",
|
|
29638
|
+
lineWidth: 2
|
|
29639
|
+
});
|
|
29640
|
+
if (a.label) {
|
|
29641
|
+
out.push({
|
|
29642
|
+
type: "text",
|
|
29643
|
+
x: (a.x + x2) / 2,
|
|
29644
|
+
y: (a.y + y2) / 2 - 10,
|
|
29645
|
+
text: a.label,
|
|
29646
|
+
color: "#111827",
|
|
29647
|
+
fontSize: 12,
|
|
29648
|
+
align: "center"
|
|
29649
|
+
});
|
|
29650
|
+
}
|
|
29651
|
+
}
|
|
29652
|
+
for (const a of atoms) {
|
|
29653
|
+
out.push({
|
|
29654
|
+
type: "circle",
|
|
29655
|
+
x: a.x,
|
|
29656
|
+
y: a.y,
|
|
29657
|
+
radius: a.radius ?? 14,
|
|
29658
|
+
color: a.color ?? "#2563eb",
|
|
29659
|
+
fill: a.color ?? "#2563eb",
|
|
29660
|
+
id: a.id
|
|
29661
|
+
});
|
|
29662
|
+
if (a.element) {
|
|
29663
|
+
out.push({
|
|
29664
|
+
type: "text",
|
|
29665
|
+
x: a.x,
|
|
29666
|
+
y: a.y,
|
|
29667
|
+
text: a.element,
|
|
29668
|
+
color: "#ffffff",
|
|
29669
|
+
fontSize: 12,
|
|
29670
|
+
align: "center"
|
|
29671
|
+
});
|
|
29672
|
+
}
|
|
29673
|
+
}
|
|
29674
|
+
out.push(...shapes);
|
|
29675
|
+
return out;
|
|
29676
|
+
}, [atoms, bonds, arrows, shapes]);
|
|
29677
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
29678
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
29679
|
+
/* @__PURE__ */ jsx(
|
|
29680
|
+
LearningCanvas,
|
|
29681
|
+
{
|
|
29682
|
+
width,
|
|
29683
|
+
height,
|
|
29684
|
+
backgroundColor,
|
|
29685
|
+
shapes: derivedShapes,
|
|
29686
|
+
interactive,
|
|
29687
|
+
animate,
|
|
29688
|
+
onShapeClick,
|
|
29689
|
+
isLoading,
|
|
29690
|
+
error
|
|
29691
|
+
}
|
|
29692
|
+
)
|
|
29693
|
+
] }) });
|
|
29694
|
+
};
|
|
29695
|
+
}
|
|
29696
|
+
});
|
|
29172
29697
|
var CodeRunnerPanel;
|
|
29173
29698
|
var init_CodeRunnerPanel = __esm({
|
|
29174
29699
|
"components/core/organisms/CodeRunnerPanel.tsx"() {
|
|
@@ -34866,6 +35391,234 @@ var init_ProgressDots = __esm({
|
|
|
34866
35391
|
ProgressDots.displayName = "ProgressDots";
|
|
34867
35392
|
}
|
|
34868
35393
|
});
|
|
35394
|
+
var MathCanvas;
|
|
35395
|
+
var init_MathCanvas = __esm({
|
|
35396
|
+
"components/learning/molecules/MathCanvas.tsx"() {
|
|
35397
|
+
"use client";
|
|
35398
|
+
init_atoms();
|
|
35399
|
+
init_Stack();
|
|
35400
|
+
init_LearningCanvas();
|
|
35401
|
+
MathCanvas = ({
|
|
35402
|
+
className,
|
|
35403
|
+
width = 600,
|
|
35404
|
+
height = 400,
|
|
35405
|
+
title,
|
|
35406
|
+
xMin = -10,
|
|
35407
|
+
xMax = 10,
|
|
35408
|
+
yMin = -10,
|
|
35409
|
+
yMax = 10,
|
|
35410
|
+
showAxes = true,
|
|
35411
|
+
showGrid = true,
|
|
35412
|
+
gridStep = 1,
|
|
35413
|
+
curves = [],
|
|
35414
|
+
points = [],
|
|
35415
|
+
vectors = [],
|
|
35416
|
+
shapes = [],
|
|
35417
|
+
interactive = false,
|
|
35418
|
+
animate = false,
|
|
35419
|
+
onShapeClick,
|
|
35420
|
+
isLoading,
|
|
35421
|
+
error
|
|
35422
|
+
}) => {
|
|
35423
|
+
const derivedShapes = useMemo(() => {
|
|
35424
|
+
const out = [];
|
|
35425
|
+
const margin = 24;
|
|
35426
|
+
const plotW = width - margin * 2;
|
|
35427
|
+
const plotH = height - margin * 2;
|
|
35428
|
+
const mapX = (x) => margin + (x - xMin) / (xMax - xMin) * plotW;
|
|
35429
|
+
const mapY = (y) => height - (margin + (y - yMin) / (yMax - yMin) * plotH);
|
|
35430
|
+
if (showGrid) {
|
|
35431
|
+
for (let x = Math.ceil(xMin / gridStep) * gridStep; x <= xMax; x += gridStep) {
|
|
35432
|
+
const px = mapX(x);
|
|
35433
|
+
out.push({ type: "line", x1: px, y1: margin, x2: px, y2: height - margin, color: "#e5e7eb", lineWidth: 1 });
|
|
35434
|
+
}
|
|
35435
|
+
for (let y = Math.ceil(yMin / gridStep) * gridStep; y <= yMax; y += gridStep) {
|
|
35436
|
+
const py = mapY(y);
|
|
35437
|
+
out.push({ type: "line", x1: margin, y1: py, x2: width - margin, y2: py, color: "#e5e7eb", lineWidth: 1 });
|
|
35438
|
+
}
|
|
35439
|
+
}
|
|
35440
|
+
if (showAxes) {
|
|
35441
|
+
const xAxisY = Math.max(margin, Math.min(height - margin, mapY(0)));
|
|
35442
|
+
const yAxisX = Math.max(margin, Math.min(width - margin, mapX(0)));
|
|
35443
|
+
out.push({ type: "line", x1: margin, y1: xAxisY, x2: width - margin, y2: xAxisY, color: "#374151", lineWidth: 2 });
|
|
35444
|
+
out.push({ type: "line", x1: yAxisX, y1: margin, x2: yAxisX, y2: height - margin, color: "#374151", lineWidth: 2 });
|
|
35445
|
+
}
|
|
35446
|
+
for (const curve of curves) {
|
|
35447
|
+
if (!curve.samples || curve.samples.length < 2) continue;
|
|
35448
|
+
for (let i = 1; i < curve.samples.length; i++) {
|
|
35449
|
+
const a = curve.samples[i - 1];
|
|
35450
|
+
const b = curve.samples[i];
|
|
35451
|
+
if (a.x < xMin || a.x > xMax || b.x < xMin || b.x > xMax) continue;
|
|
35452
|
+
out.push({
|
|
35453
|
+
type: "line",
|
|
35454
|
+
x1: mapX(a.x),
|
|
35455
|
+
y1: mapY(a.y),
|
|
35456
|
+
x2: mapX(b.x),
|
|
35457
|
+
y2: mapY(b.y),
|
|
35458
|
+
color: curve.color ?? "#2563eb",
|
|
35459
|
+
lineWidth: 2
|
|
35460
|
+
});
|
|
35461
|
+
}
|
|
35462
|
+
}
|
|
35463
|
+
for (const p2 of points) {
|
|
35464
|
+
if (p2.x < xMin || p2.x > xMax || p2.y < yMin || p2.y > yMax) continue;
|
|
35465
|
+
out.push({
|
|
35466
|
+
type: "circle",
|
|
35467
|
+
x: mapX(p2.x),
|
|
35468
|
+
y: mapY(p2.y),
|
|
35469
|
+
radius: p2.radius ?? 4,
|
|
35470
|
+
color: p2.color ?? "#dc2626",
|
|
35471
|
+
fill: p2.color ?? "#dc2626"
|
|
35472
|
+
});
|
|
35473
|
+
if (p2.label) {
|
|
35474
|
+
out.push({ type: "text", x: mapX(p2.x) + 8, y: mapY(p2.y) - 8, text: p2.label, color: "#111827", fontSize: 12 });
|
|
35475
|
+
}
|
|
35476
|
+
}
|
|
35477
|
+
for (const v of vectors) {
|
|
35478
|
+
if (v.x < xMin || v.x > xMax || v.y < yMin || v.y > yMax) continue;
|
|
35479
|
+
const x1 = mapX(v.x);
|
|
35480
|
+
const y1 = mapY(v.y);
|
|
35481
|
+
const x2 = mapX(v.x + v.vx);
|
|
35482
|
+
const y2 = mapY(v.y + v.vy);
|
|
35483
|
+
out.push({ type: "arrow", x1, y1, x2, y2, color: v.color ?? "#7c3aed", lineWidth: 2 });
|
|
35484
|
+
if (v.label) {
|
|
35485
|
+
out.push({ type: "text", x: x2 + 6, y: y2 - 6, text: v.label, color: "#111827", fontSize: 12 });
|
|
35486
|
+
}
|
|
35487
|
+
}
|
|
35488
|
+
out.push(...shapes);
|
|
35489
|
+
return out;
|
|
35490
|
+
}, [width, height, xMin, xMax, yMin, yMax, showAxes, showGrid, gridStep, curves, points, vectors, shapes]);
|
|
35491
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
35492
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35493
|
+
/* @__PURE__ */ jsx(
|
|
35494
|
+
LearningCanvas,
|
|
35495
|
+
{
|
|
35496
|
+
width,
|
|
35497
|
+
height,
|
|
35498
|
+
shapes: derivedShapes,
|
|
35499
|
+
interactive,
|
|
35500
|
+
animate,
|
|
35501
|
+
onShapeClick,
|
|
35502
|
+
isLoading,
|
|
35503
|
+
error
|
|
35504
|
+
}
|
|
35505
|
+
)
|
|
35506
|
+
] }) });
|
|
35507
|
+
};
|
|
35508
|
+
}
|
|
35509
|
+
});
|
|
35510
|
+
var PhysicsCanvas;
|
|
35511
|
+
var init_PhysicsCanvas = __esm({
|
|
35512
|
+
"components/learning/molecules/PhysicsCanvas.tsx"() {
|
|
35513
|
+
"use client";
|
|
35514
|
+
init_atoms();
|
|
35515
|
+
init_Stack();
|
|
35516
|
+
init_LearningCanvas();
|
|
35517
|
+
PhysicsCanvas = ({
|
|
35518
|
+
className,
|
|
35519
|
+
width = 600,
|
|
35520
|
+
height = 400,
|
|
35521
|
+
title,
|
|
35522
|
+
backgroundColor,
|
|
35523
|
+
bodies = [],
|
|
35524
|
+
constraints = [],
|
|
35525
|
+
showVelocity = true,
|
|
35526
|
+
showForces = false,
|
|
35527
|
+
velocityScale = 20,
|
|
35528
|
+
forceScale = 20,
|
|
35529
|
+
shapes = [],
|
|
35530
|
+
interactive = false,
|
|
35531
|
+
animate = false,
|
|
35532
|
+
onShapeClick,
|
|
35533
|
+
isLoading,
|
|
35534
|
+
error
|
|
35535
|
+
}) => {
|
|
35536
|
+
const derivedShapes = useMemo(() => {
|
|
35537
|
+
const out = [];
|
|
35538
|
+
const bodyById = /* @__PURE__ */ new Map();
|
|
35539
|
+
for (const b of bodies) {
|
|
35540
|
+
if (b.id) bodyById.set(b.id, b);
|
|
35541
|
+
}
|
|
35542
|
+
for (const c of constraints) {
|
|
35543
|
+
const a = bodyById.get(c.from);
|
|
35544
|
+
const b = bodyById.get(c.to);
|
|
35545
|
+
if (!a || !b) continue;
|
|
35546
|
+
out.push({
|
|
35547
|
+
type: "line",
|
|
35548
|
+
x1: a.x,
|
|
35549
|
+
y1: a.y,
|
|
35550
|
+
x2: b.x,
|
|
35551
|
+
y2: b.y,
|
|
35552
|
+
color: c.color ?? "#9ca3af",
|
|
35553
|
+
lineWidth: 2
|
|
35554
|
+
});
|
|
35555
|
+
}
|
|
35556
|
+
for (const b of bodies) {
|
|
35557
|
+
out.push({
|
|
35558
|
+
type: "circle",
|
|
35559
|
+
x: b.x,
|
|
35560
|
+
y: b.y,
|
|
35561
|
+
radius: b.radius ?? 12,
|
|
35562
|
+
color: b.color ?? "#2563eb",
|
|
35563
|
+
fill: b.color ?? "#2563eb",
|
|
35564
|
+
id: b.id
|
|
35565
|
+
});
|
|
35566
|
+
if (b.label) {
|
|
35567
|
+
out.push({
|
|
35568
|
+
type: "text",
|
|
35569
|
+
x: b.x + (b.radius ?? 12) + 6,
|
|
35570
|
+
y: b.y - (b.radius ?? 12) - 6,
|
|
35571
|
+
text: b.label,
|
|
35572
|
+
color: "#111827",
|
|
35573
|
+
fontSize: 12
|
|
35574
|
+
});
|
|
35575
|
+
}
|
|
35576
|
+
if (showVelocity && b.vx != null && b.vy != null && (b.vx !== 0 || b.vy !== 0)) {
|
|
35577
|
+
out.push({
|
|
35578
|
+
type: "arrow",
|
|
35579
|
+
x1: b.x,
|
|
35580
|
+
y1: b.y,
|
|
35581
|
+
x2: b.x + b.vx * velocityScale,
|
|
35582
|
+
y2: b.y + b.vy * velocityScale,
|
|
35583
|
+
color: "#16a34a",
|
|
35584
|
+
lineWidth: 2
|
|
35585
|
+
});
|
|
35586
|
+
}
|
|
35587
|
+
if (showForces && b.fx != null && b.fy != null && (b.fx !== 0 || b.fy !== 0)) {
|
|
35588
|
+
out.push({
|
|
35589
|
+
type: "arrow",
|
|
35590
|
+
x1: b.x,
|
|
35591
|
+
y1: b.y,
|
|
35592
|
+
x2: b.x + b.fx * forceScale,
|
|
35593
|
+
y2: b.y + b.fy * forceScale,
|
|
35594
|
+
color: "#dc2626",
|
|
35595
|
+
lineWidth: 2
|
|
35596
|
+
});
|
|
35597
|
+
}
|
|
35598
|
+
}
|
|
35599
|
+
out.push(...shapes);
|
|
35600
|
+
return out;
|
|
35601
|
+
}, [bodies, constraints, showVelocity, showForces, velocityScale, forceScale, shapes]);
|
|
35602
|
+
return /* @__PURE__ */ jsx(Card, { className, children: /* @__PURE__ */ jsxs(VStack, { gap: "sm", children: [
|
|
35603
|
+
title ? /* @__PURE__ */ jsx(Typography, { variant: "h4", children: title }) : null,
|
|
35604
|
+
/* @__PURE__ */ jsx(
|
|
35605
|
+
LearningCanvas,
|
|
35606
|
+
{
|
|
35607
|
+
width,
|
|
35608
|
+
height,
|
|
35609
|
+
backgroundColor,
|
|
35610
|
+
shapes: derivedShapes,
|
|
35611
|
+
interactive,
|
|
35612
|
+
animate,
|
|
35613
|
+
onShapeClick,
|
|
35614
|
+
isLoading,
|
|
35615
|
+
error
|
|
35616
|
+
}
|
|
35617
|
+
)
|
|
35618
|
+
] }) });
|
|
35619
|
+
};
|
|
35620
|
+
}
|
|
35621
|
+
});
|
|
34869
35622
|
function resolveNodeColor(node, groups) {
|
|
34870
35623
|
if (node.color) return node.color;
|
|
34871
35624
|
if (node.group) {
|
|
@@ -35237,13 +35990,13 @@ var init_MapView = __esm({
|
|
|
35237
35990
|
shadowSize: [41, 41]
|
|
35238
35991
|
});
|
|
35239
35992
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
35240
|
-
const { useEffect:
|
|
35993
|
+
const { useEffect: useEffect76, useRef: useRef77, useCallback: useCallback117, useState: useState108 } = React107__default;
|
|
35241
35994
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
35242
35995
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
35243
35996
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
35244
35997
|
const map = useMap();
|
|
35245
|
-
const prevRef =
|
|
35246
|
-
|
|
35998
|
+
const prevRef = useRef77({ centerLat, centerLng, zoom });
|
|
35999
|
+
useEffect76(() => {
|
|
35247
36000
|
const prev = prevRef.current;
|
|
35248
36001
|
if (prev.centerLat !== centerLat || prev.centerLng !== centerLng || prev.zoom !== zoom) {
|
|
35249
36002
|
map.setView([centerLat, centerLng], zoom);
|
|
@@ -35254,7 +36007,7 @@ var init_MapView = __esm({
|
|
|
35254
36007
|
}
|
|
35255
36008
|
function MapClickHandler({ onMapClick }) {
|
|
35256
36009
|
const map = useMap();
|
|
35257
|
-
|
|
36010
|
+
useEffect76(() => {
|
|
35258
36011
|
if (!onMapClick) return;
|
|
35259
36012
|
const handler = (e) => {
|
|
35260
36013
|
onMapClick(e.latlng.lat, e.latlng.lng);
|
|
@@ -43695,7 +44448,7 @@ function getGroupColor(group, groups) {
|
|
|
43695
44448
|
const idx = groups.indexOf(group);
|
|
43696
44449
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
43697
44450
|
}
|
|
43698
|
-
function
|
|
44451
|
+
function resolveColor3(color, el) {
|
|
43699
44452
|
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
43700
44453
|
if (!m) return color;
|
|
43701
44454
|
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
@@ -43956,7 +44709,7 @@ var init_GraphCanvas = __esm({
|
|
|
43956
44709
|
const w = logicalW;
|
|
43957
44710
|
const h = height;
|
|
43958
44711
|
const nodes = nodesRef.current;
|
|
43959
|
-
const accentColor =
|
|
44712
|
+
const accentColor = resolveColor3("var(--color-accent)", canvas);
|
|
43960
44713
|
const dpr = typeof window !== "undefined" && window.devicePixelRatio || 1;
|
|
43961
44714
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
43962
44715
|
ctx.clearRect(0, 0, w, h);
|
|
@@ -43995,7 +44748,7 @@ var init_GraphCanvas = __esm({
|
|
|
43995
44748
|
ctx.globalAlpha = 1;
|
|
43996
44749
|
for (const node of nodes) {
|
|
43997
44750
|
const size = node.size || 8;
|
|
43998
|
-
const color =
|
|
44751
|
+
const color = resolveColor3(node.color || getGroupColor(node.group, groups), canvas);
|
|
43999
44752
|
const isHovered = hoveredNode === node.id;
|
|
44000
44753
|
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
44001
44754
|
ctx.globalAlpha = hoveredNode && !neighbors.has(node.id) ? 0.2 : 1;
|
|
@@ -50874,6 +51627,7 @@ var init_component_registry_generated = __esm({
|
|
|
50874
51627
|
init_BattleBoard();
|
|
50875
51628
|
init_BattleTemplate();
|
|
50876
51629
|
init_BehaviorView();
|
|
51630
|
+
init_BiologyCanvas();
|
|
50877
51631
|
init_BloomQuizBlock();
|
|
50878
51632
|
init_BoardgameBoard();
|
|
50879
51633
|
init_BookChapterView();
|
|
@@ -50903,6 +51657,7 @@ var init_component_registry_generated = __esm({
|
|
|
50903
51657
|
init_ChartLegend();
|
|
50904
51658
|
init_ChatBar();
|
|
50905
51659
|
init_Checkbox();
|
|
51660
|
+
init_ChemistryCanvas();
|
|
50906
51661
|
init_ChoiceButton();
|
|
50907
51662
|
init_CityBuilderBoard();
|
|
50908
51663
|
init_CityBuilderTemplate();
|
|
@@ -50994,6 +51749,7 @@ var init_component_registry_generated = __esm({
|
|
|
50994
51749
|
init_JazariStateMachine();
|
|
50995
51750
|
init_LandingPageTemplate();
|
|
50996
51751
|
init_LawReferenceTooltip();
|
|
51752
|
+
init_LearningCanvas();
|
|
50997
51753
|
init_Lightbox();
|
|
50998
51754
|
init_LikertScale();
|
|
50999
51755
|
init_LineChart();
|
|
@@ -51002,9 +51758,11 @@ var init_component_registry_generated = __esm({
|
|
|
51002
51758
|
init_MapView();
|
|
51003
51759
|
init_MarkdownContent();
|
|
51004
51760
|
init_MarketingFooter();
|
|
51761
|
+
init_MarketingStatCard();
|
|
51005
51762
|
init_MasterDetail();
|
|
51006
51763
|
init_MasterDetailLayout();
|
|
51007
51764
|
init_MatchPuzzleBoard();
|
|
51765
|
+
init_MathCanvas();
|
|
51008
51766
|
init_MatrixQuestion();
|
|
51009
51767
|
init_MediaGallery();
|
|
51010
51768
|
init_Menu();
|
|
@@ -51023,6 +51781,7 @@ var init_component_registry_generated = __esm({
|
|
|
51023
51781
|
init_PageHeader();
|
|
51024
51782
|
init_Pagination();
|
|
51025
51783
|
init_PatternTile();
|
|
51784
|
+
init_PhysicsCanvas();
|
|
51026
51785
|
init_PinballBoard();
|
|
51027
51786
|
init_PirateBoard();
|
|
51028
51787
|
init_PlatformerBoard();
|
|
@@ -51199,6 +51958,7 @@ var init_component_registry_generated = __esm({
|
|
|
51199
51958
|
"BattleBoard": BattleBoard,
|
|
51200
51959
|
"BattleTemplate": BattleTemplate,
|
|
51201
51960
|
"BehaviorView": BehaviorView,
|
|
51961
|
+
"BiologyCanvas": BiologyCanvas,
|
|
51202
51962
|
"BloomQuizBlock": BloomQuizBlock,
|
|
51203
51963
|
"BoardgameBoard": BoardgameBoard,
|
|
51204
51964
|
"BookChapterView": BookChapterView,
|
|
@@ -51231,6 +51991,7 @@ var init_component_registry_generated = __esm({
|
|
|
51231
51991
|
"ChartLegend": ChartLegend,
|
|
51232
51992
|
"ChatBar": ChatBar,
|
|
51233
51993
|
"Checkbox": Checkbox,
|
|
51994
|
+
"ChemistryCanvas": ChemistryCanvas,
|
|
51234
51995
|
"ChoiceButton": ChoiceButton,
|
|
51235
51996
|
"CityBuilderBoard": CityBuilderBoard,
|
|
51236
51997
|
"CityBuilderTemplate": CityBuilderTemplate,
|
|
@@ -51332,6 +52093,7 @@ var init_component_registry_generated = __esm({
|
|
|
51332
52093
|
"LabelPattern": LabelPattern,
|
|
51333
52094
|
"LandingPageTemplate": LandingPageTemplate,
|
|
51334
52095
|
"LawReferenceTooltip": LawReferenceTooltip,
|
|
52096
|
+
"LearningCanvas": LearningCanvas,
|
|
51335
52097
|
"Lightbox": Lightbox,
|
|
51336
52098
|
"LikertScale": LikertScale,
|
|
51337
52099
|
"LineChart": LineChart2,
|
|
@@ -51340,9 +52102,11 @@ var init_component_registry_generated = __esm({
|
|
|
51340
52102
|
"MapView": MapView,
|
|
51341
52103
|
"MarkdownContent": MarkdownContent,
|
|
51342
52104
|
"MarketingFooter": MarketingFooter,
|
|
52105
|
+
"MarketingStatCard": MarketingStatCard,
|
|
51343
52106
|
"MasterDetail": MasterDetail,
|
|
51344
52107
|
"MasterDetailLayout": MasterDetailLayout,
|
|
51345
52108
|
"MatchPuzzleBoard": MatchPuzzleBoard,
|
|
52109
|
+
"MathCanvas": MathCanvas,
|
|
51346
52110
|
"MatrixQuestion": MatrixQuestion,
|
|
51347
52111
|
"MediaGallery": MediaGallery,
|
|
51348
52112
|
"Menu": Menu,
|
|
@@ -51361,6 +52125,7 @@ var init_component_registry_generated = __esm({
|
|
|
51361
52125
|
"PageHeader": PageHeader,
|
|
51362
52126
|
"Pagination": Pagination,
|
|
51363
52127
|
"PatternTile": PatternTile,
|
|
52128
|
+
"PhysicsCanvas": PhysicsCanvas,
|
|
51364
52129
|
"PinballBoard": PinballBoard,
|
|
51365
52130
|
"PirateBoard": PirateBoard,
|
|
51366
52131
|
"PlatformerBoard": PlatformerBoard,
|