Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

## About

Mathnetic_Carter is a branch of Mathnetic. This branch is designed for students who have the motor skills for using a keyboard and touchpad rather than touchscreen. The main Mathnetic branch will have touchscreen support and will be used as a more generalist program used in classes such as Life Skills.

Mathnetic is an assistive learning tool designed to help a student with cerebral palsy in their math-related endeavours. Mathnetic is designed to be a block-based editor, allowing mathematical symbols and text to be dragged to a primary workspace and be *snapped* together, in a very similar fashion to the popular block-based coding editor, [Scratch](https://scratch.mit.edu/).

Made with Love by Team Sming!!!!!!!!!

Founded by Lord Sming's Class of 2025.
Mathnetic's legacy carried on by Lord Sming's Class of 2026.

## Requirements

Expand Down Expand Up @@ -43,5 +46,4 @@ Here's a list of software, libraries, and frameworks you should be familiar with
* React
* HTML5 & JSX
* CSS
* npm
* Figma
* npm
246 changes: 145 additions & 101 deletions src/App.jsx

Large diffs are not rendered by default.

19 changes: 18 additions & 1 deletion src/components/SideBar/index.jsx → src/Archived/oldIndex.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//note: this sidebar works very differently from the one in the main branch

//to change the size of the nodes in sidebar, go to src->components->context->index.css

//index.css:
//100vh = 100% of the viewport height
//100vw = 100% of the viewport width
//100px = 100 pixels (dont use this, use vh or vw)
//overflow: scroll (changes sidebar to be able to be scrolled)

import React from 'react';
// import { useDnD } from '../DnDContext';
import { useEffect, useRef } from 'react';
Expand All @@ -21,7 +31,15 @@ export default () => {
// Yes, I probably should have used a for loop. Shut up.
// "I"

//im so sorry

// Drag and drop nodes, nodes in sidebar that are converted to actual nodes in app.jsx

//classname should always be dndnode
//onDragStart(event, 'node type', 'symbol inside the node')
// ^ ^ ^
// dont touch numeric,exponent,etc can use latex symbols (notation is '{\\name_of_symbol}')

return (
<aside className="sidebar">
<div className="description">You can drag these nodes to the pane on the right.</div>
Expand Down Expand Up @@ -106,7 +124,6 @@ export default () => {
<div className="dndnode" onDragStart={(event) => onDragStart(event, 'fraction', 'F')} draggable>
<InlineMath>f</InlineMath>
</div>

<div className="dndnode" onDragStart={(event) => onDragStart(event, 'start', 'O')} draggable>
<InlineMath>o</InlineMath>
</div>
Expand Down
13 changes: 13 additions & 0 deletions src/components/DeleteButton/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.trashbutton {
width: 15vw;
height: 15vw;
border: 2px dashed #ff0000;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: 5vw;
right: 5vw;
z-index: 10;
cursor: pointer;
}
19 changes: 19 additions & 0 deletions src/components/DeleteButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { useCallback, useRef, useState } from 'react';
import { useDraggable } from '@neodrag/react';
import { useReactFlow, XYPosition } from '@xyflow/react';
import { InlineMath } from 'react-katex';
import './index.css';

//delete/trash button
export default function DeleteButton() {
//deleting = true. idk why it needs to start at true, but it does.
//setDeleting() is the function that changes the value of deleting. setDeleting(true) will make deleting true.
const [deleting, setDeleting] = useState(true);
function handleClick() {
setDeleting(!deleting); //changes deleting = true to false or vice versa
const ev = new Event('trashClicked')
document.dispatchEvent(ev); //sends an event to the document to tell app.jsx whether to delete nodes or not
}
return <div className="trashbutton" style={{ background: deleting ? '#ffcccc' : '#008000' }} onClick={handleClick}>Trash</div>
}
4 changes: 2 additions & 2 deletions src/components/OutputPane/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default (props) => {
const denominator = readEquation(getNode(currentNode.data.connectors.lower));

if (!(numerator && denominator))
return '';
return 'aaaa';
lineString += '\\frac{' + numerator + '}{'+denominator+'}';
}
//if (currentNode.type === 'connector')
Expand Down Expand Up @@ -75,7 +75,7 @@ export default (props) => {

return (
<aside className="output-pane print">
<div className="description">Output</div>
<div className="description"></div>
<InlineMath math={equationString}/>
</aside>
);
Expand Down
3 changes: 3 additions & 0 deletions src/components/SideBar/index.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
.sidebar {
height: 100vh;
width: 200px;
background-color: white;
overflow: scroll;
z-index: 0;
}

139 changes: 139 additions & 0 deletions src/components/SideBar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import React from 'react';
import { useCallback, useRef, useState } from 'react';
import { useDraggable } from '@neodrag/react';
import { useReactFlow, XYPosition } from '@xyflow/react';
import { InlineMath } from 'react-katex';


// This is a simple ID generator for the nodes.
// You can customize this to use your own ID generation logic.
let id = 0;
const getId = () => `dndnode_${id++}`;

const latexEqs = ['0','1','2','3','4','5','6','7','8','9', '\\pi', 'e', '+', '-', '\\times', '\\div', '=', '\\pm', '--', '^2', '^3', 'x', 'y'];

interface DraggableNodeProps {
className?: string;
children: React.ReactNode;
nodeType: string;
latexEq: string;
onDrop: (nodeType: string, latexEq: string, position: XYPosition) => void;
}

let dnid = 0;
function DraggableNode({ className, children, nodeType, latexEq, onDrop }: DraggableNodeProps) {
const draggableRef = useRef<HTMLDivElement>(null);
const dragStarted = useRef(false);
const [position, setPosition] = useState<XYPosition>({ x: 0, y: 0 });
dnid++;

useDraggable(draggableRef, {
position: position,
onDrag: ({ offsetX, offsetY }) => {
// Calculate position relative to the viewport
let draggedNode = document.getElementById(String(latexEq));
if (draggedNode.getAttribute("beingDragged") == "false")
{
let dndflow = document.getElementById('dndflow');
let mySidebar = document.getElementById('sidebar');
let fillerNode = document.getElementById('fillerNode');
let nextNode = document.getElementById(latexEqs[latexEqs.indexOf(latexEq) + 1]);
const absY = draggedNode.getBoundingClientRect().top;
draggedNode.classList.add('is-dragging');
dndflow.appendChild(draggedNode);
mySidebar.insertBefore(fillerNode, nextNode);
draggedNode.style.top = String(absY) + "px";
draggedNode.setAttribute("beingDragged", "true");
}
setPosition({
x: offsetX,
y: offsetY,
});
},
onDragEnd: ({ event }) => {
let draggedNode = document.getElementById(String(latexEq));
let mySidebar = document.getElementById('sidebar');
let fillerNode = document.getElementById('fillerNode');
let nextNode = document.getElementById(latexEqs[latexEqs.indexOf(latexEq) + 1]);
draggedNode.classList.remove('is-dragging');
if (latexEq == latexEqs[latexEqs.length - 1])
mySidebar.appendChild(draggedNode);
else
mySidebar.insertBefore(draggedNode, nextNode);
mySidebar.appendChild(fillerNode);
draggedNode.style.top = "0px";
draggedNode.setAttribute("beingDragged", "false");

setPosition({ x: 0, y:0 });
onDrop(nodeType, latexEq, {
x: event.clientX,
y: event.clientY,
});
},
});
return (
<div className='dndnode' id={String(latexEq)} ref={draggableRef} beingDragged="false" >
<InlineMath math={latexEq}/>
</div>
);
}

export default function Sidebar() {
const { setNodes, screenToFlowPosition } = useReactFlow();

const handleNodeDrop = useCallback(
(nodeType: string, latexEq: string, screenPosition: XYPosition) => {
const flow = document.querySelector('.react-flow');
const flowRect = flow?.getBoundingClientRect();
const isInFlow =
flowRect &&
screenPosition.x >= flowRect.left &&
screenPosition.x <= flowRect.right &&
screenPosition.y >= flowRect.top &&
screenPosition.y <= flowRect.bottom;

// Create a new node and add it to the flow
if (isInFlow) {
const nodePosition = screenToFlowPosition(screenPosition);
const dropEv = new CustomEvent("drop", { detail: {position: nodePosition, type: nodeType, latexEq: latexEq} })
document.dispatchEvent(dropEv);
}
},
[setNodes, screenToFlowPosition],
);

return (
<aside>
<div className="sidebar" id = 'sidebar'>
You can drag these nodes to the pane to create new nodes.

<DraggableNode children="c" nodeType="start" latexEq='->' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='0' onDrop={handleNodeDrop}/>
<DraggableNode children="c" nodeType="numeric" latexEq='1' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='2' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='3' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='4' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='5' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='6' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='7' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='8' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='9' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq={'\\pi'} onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="numeric" latexEq='e' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="arithmetic" latexEq='+' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="arithmetic" latexEq='-' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="arithmetic" latexEq={'\\times'} onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="arithmetic" latexEq={'\\div'} onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="arithmetic" latexEq='=' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="arithmetic" latexEq={'\\pm'} onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="fraction" latexEq='--' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="exponent" latexEq='^2' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="exponent" latexEq='^3' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="variable" latexEq='x' onDrop={handleNodeDrop} />
<DraggableNode children="c" nodeType="variable" latexEq='y' onDrop={handleNodeDrop} />

<div className='dndnode fillernode' id="fillerNode"/>
</div>
</aside>
);
}
21 changes: 18 additions & 3 deletions src/components/context/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ body {

.dndflow aside {
border-right: 1px solid #eee;
display: flex;
padding: 15px 10px;
font-size: 12px;
font-size: 50px;
background: #fcfcfc;
}

Expand All @@ -31,18 +32,32 @@ body {
}

.dndflow .dndnode {
height: 200px;
padding: 4px;
height: 5vw;
width: 5vw;
padding: 10px;
border: 1px solid #1a192b;
border-radius: 2px;
margin-bottom: 10px;
display: flex;
position: relative;
justify-content: center;
align-items: center;
cursor: grab;
font-size: 40px;
background-color: burlywood;
}

.dndflow .dndnode.is-dragging {
background-color: green;
display: fixed;
position: fixed;
}

.dndflow .fillernode
{
background-color: transparent;
border: hidden;
}
.dndflow .dndnode.input {
border-color: #0041d0;
}
Expand Down
19 changes: 17 additions & 2 deletions src/components/node_types/ArithmeticNode/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,30 @@ import CustomHandle from '../../CustomHandle';
import 'katex/dist/katex.min.css'
import { InlineMath } from 'react-katex';

//some nodes dont have all, or any, targets/sources (see outputnode or exponentnode)
// target1 is the left connection
// target2 is the top connection
// source1 is the right connection
// source2 is the bottom connection
// |_____
/* |
V
___
|__ \ 3
\ \
/ \
/ /\ \
/ / \ \.-.
/_/ \_.-'
*/

function ArithmeticNode(props) {

return (
<div className="arithmetic-node">
<CustomHandle id={props.id + "_target1"} type="target" position={Position.Left} connectionCount={1} />
<CustomHandle id={props.id + "_target2"} type="target" position={Position.Top} connectionCount={1} />
<InlineMath>{props.data.value}</InlineMath>
<CustomHandle id={props.id + "_source1"} type="source" position={Position.Right} connectionCount={1} />
<CustomHandle id={props.id + "_source2"} type="source" position={Position.Bottom} connectionCount={1} />
</div>
);
}
Expand Down
1 change: 0 additions & 1 deletion src/components/node_types/FractionNode/index.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.fraction-node {
border: 1px solid #eee;
width: 10px;
padding: 15px 25px;
border-radius: 5px;
background: white;
Expand Down
Loading