feat: preact-router and GraphInput node balance modifier

backup-1
Antonio De Lucreziis 2 years ago
parent 35759b6d1d
commit 160007eb0d

Binary file not shown.

@ -22,6 +22,7 @@
"@ruby/wasm-wasi": "^2.6.2",
"katex": "^0.16.11",
"lodash": "^4.17.21",
"preact-router": "^4.1.2",
"vite-plugin-wasm": "^3.3.0"
}
}

@ -20,18 +20,21 @@ export const View = ({}) => {
{
id: id1,
label: '1',
balance: 0,
x: 100 + Math.random() * 500,
y: 100 + Math.random() * 300,
},
{
id: id2,
label: '2',
balance: 0,
x: 100 + Math.random() * 500,
y: 100 + Math.random() * 300,
},
{
id: id3,
label: '3',
balance: 0,
x: 100 + Math.random() * 500,
y: 100 + Math.random() * 300,
},

@ -56,6 +56,7 @@ export const GraphInput = ({ graph, setGraph }) => {
{
id: crypto.randomUUID(9).split('-')[0],
label: '?',
balance: 0,
x,
y,
},
@ -193,7 +194,7 @@ export const GraphInput = ({ graph, setGraph }) => {
))}
</div>
<div class="nodes">
{graph.nodes.map(({ id, label, x, y }, index) => (
{graph.nodes.map(({ id, label, balance, x, y }, index) => (
<div
class={[
'node',
@ -204,44 +205,6 @@ export const GraphInput = ({ graph, setGraph }) => {
.filter(Boolean)
.join(' ')}
style={{ '--x': x, '--y': y }}
onMouseDown={e => {
if (interacting) return
if (e.ctrlKey) {
setInteracting({
type: 'arrow',
index,
initialPos: { x, y },
initialDragPos: { x: e.x, y: e.y },
x: x,
y: y,
target: null,
})
} else {
setInteracting({
type: 'drag',
index,
initialPos: { x, y },
initialDragPos: { x: e.x, y: e.y },
})
}
}}
onMouseMove={e => {
if (interacting?.type === 'arrow' && interacting.index !== index) {
setInteracting(i => ({ ...i, target: index }))
}
}}
onMouseLeave={e => {
if (interacting && interacting.type === 'arrow') {
setInteracting(i => ({ ...i, target: null }))
}
}}
onDblclick={e => {
setInteracting({
type: 'edit-node',
index,
})
}}
onKeyDown={e => {
if (
(e.key === 'Enter' || e.key === 'Escape') &&
@ -251,27 +214,110 @@ export const GraphInput = ({ graph, setGraph }) => {
}
}}
>
{interacting?.type === 'edit-node' && interacting.index === index ? (
<input
type="text"
value={label}
onInput={e =>
<div class="popup">
<button
onClick={() => {
setGraph(g => {
const newNodes = [...g.nodes]
newNodes[interacting.index] = {
...g.nodes[interacting.index],
label: e.target.value,
newNodes[index] = {
...g.nodes[index],
balance: g.nodes[index].balance + 1,
}
return {
...g,
nodes: newNodes,
return { ...g, nodes: newNodes }
})
}}
>
+
</button>
<button
onClick={() => {
setGraph(g => {
const newNodes = [...g.nodes]
newNodes[index] = {
...g.nodes[index],
balance: g.nodes[index].balance - 1,
}
return { ...g, nodes: newNodes }
})
}}
>
-
</button>
</div>
<div
class="node-ball"
onMouseDown={e => {
if (interacting) return
if (e.ctrlKey) {
setInteracting({
type: 'arrow',
index,
initialPos: { x, y },
initialDragPos: { x: e.x, y: e.y },
x: x,
y: y,
target: null,
})
} else {
setInteracting({
type: 'drag',
index,
initialPos: { x, y },
initialDragPos: { x: e.x, y: e.y },
})
}
/>
) : (
label
}}
onMouseMove={e => {
if (interacting?.type === 'arrow' && interacting.index !== index) {
setInteracting(i => ({ ...i, target: index }))
}
}}
onMouseLeave={e => {
if (interacting && interacting.type === 'arrow') {
setInteracting(i => ({ ...i, target: null }))
}
}}
onDblclick={e => {
setInteracting({
type: 'edit-node',
index,
})
}}
>
{interacting?.type === 'edit-node' && interacting.index === index ? (
<input
type="text"
value={label}
onInput={e =>
setGraph(g => {
const newNodes = [...g.nodes]
newNodes[interacting.index] = {
...g.nodes[interacting.index],
label: e.target.value,
}
return {
...g,
nodes: newNodes,
}
})
}
/>
) : (
label
)}
</div>
{balance !== 0 && (
<div class="balance">
{balance < 0 ? (
<>&minus;{Math.abs(balance)}</>
) : (
<>+{Math.abs(balance)}</>
)}
</div>
)}
</div>
))}

@ -4,6 +4,7 @@ import '@fontsource/inter/latin.css'
import _ from 'lodash'
import { render } from 'preact'
import Router, { route } from 'preact-router'
import { useState } from 'preact/hooks'
const ViewRegistry = Object.fromEntries(
@ -25,7 +26,7 @@ const NewAlgorithmBox = ({ title, description, onClick }) => (
</div>
)
const AlgorithmChooserView = ({ setCurrentView }) => {
const AlgorithmChooserView = ({}) => {
const sections = _.groupBy(ViewRegistry, 'metadata.group')
return (
@ -41,7 +42,7 @@ const AlgorithmChooserView = ({ setCurrentView }) => {
<NewAlgorithmBox
title={metadata.title}
description={metadata.description}
onClick={() => setCurrentView(id)}
onClick={() => route(id)}
/>
))}
</div>
@ -98,7 +99,12 @@ const App = ({}) => {
<h2>History</h2>
</aside>
<main>
<Main />
<Router>
<AlgorithmChooserView path="/" />
{Object.entries(ViewRegistry).map(([id, { View }]) => (
<View path={id} />
))}
</Router>
</main>
</>
)

@ -51,6 +51,22 @@ h6 {
/* Components */
button {
outline: none;
border: none;
background: #555;
color: #fff;
border-radius: 0.25rem;
cursor: pointer;
&:hover {
background: #777;
}
}
.boxes {
display: flex;
flex-direction: row;
@ -174,24 +190,71 @@ h6 {
transform: translate(-50%, -50%);
display: grid;
place-content: center;
pointer-events: all;
width: 2.5rem;
height: 2.5rem;
> .balance {
position: absolute;
top: 100%;
left: 50%;
background: #f0f0f0;
border: 2px solid #333;
border-radius: 1.25rem;
font-size: 18px;
pointer-events: all;
transform: translateX(-50%);
}
cursor: move;
> .node-ball {
display: grid;
place-content: center;
&.targeted {
width: 2.5rem;
height: 2.5rem;
background: #f0f0f0;
border: 2px solid #333;
border-radius: 1.25rem;
cursor: move;
}
> .popup {
position: absolute;
z-index: -1;
inset: -0.25rem;
height: 4rem;
/* background: #e0e0e0dd;
border: 2px solid #333; */
/* border-radius: 0.5rem; */
display: flex;
flex-direction: column;
gap: 0.25rem;
right: -2.25rem;
top: 50%;
transform: translateY(-50%);
padding: 0.25rem;
padding-left: 3rem;
opacity: 0;
> * {
flex-grow: 1;
}
}
&.targeted > .node-ball {
color: #fff;
background: green;
}
&:hover > .popup {
opacity: 1;
}
}
}
}

Loading…
Cancel
Save