mirror of
https://github.com/The-Low-Code-Foundation/OpenNoodl.git
synced 2026-01-12 23:32:55 +01:00
307 lines
6.7 KiB
Markdown
307 lines
6.7 KiB
Markdown
# TASK-000I Working Notes
|
|
|
|
## Key Code Locations
|
|
|
|
### Node Rendering
|
|
|
|
```
|
|
packages/noodl-editor/src/editor/src/views/nodegrapheditor/NodeGraphEditorNode.ts
|
|
|
|
Key methods:
|
|
- paint() - Main render function (~line 200-400)
|
|
- drawPlugs() - Port indicator rendering
|
|
- measure() - Calculate node dimensions
|
|
- handleMouseEvent() - Click/hover handling
|
|
```
|
|
|
|
### Colors
|
|
|
|
```
|
|
packages/noodl-core-ui/src/styles/custom-properties/colors.css
|
|
|
|
Node colors section (~line 30-60):
|
|
- --theme-color-node-data-*
|
|
- --theme-color-node-visual-*
|
|
- --theme-color-node-logic-*
|
|
- --theme-color-node-custom-*
|
|
- --theme-color-node-component-*
|
|
```
|
|
|
|
### Node Model
|
|
|
|
```
|
|
packages/noodl-editor/src/editor/src/models/nodegraphmodel/NodeGraphNode.ts
|
|
|
|
- metadata object already exists
|
|
- Add comment storage here
|
|
```
|
|
|
|
### Node Type Definitions
|
|
|
|
```
|
|
packages/noodl-editor/src/editor/src/models/nodelibrary/
|
|
|
|
- Port groups would be defined in node type registration
|
|
```
|
|
|
|
---
|
|
|
|
## Canvas API Notes
|
|
|
|
### roundRect Support
|
|
|
|
- Native `ctx.roundRect()` available in modern browsers
|
|
- Fallback for older browsers:
|
|
|
|
```javascript
|
|
function roundRect(ctx, x, y, w, h, r) {
|
|
ctx.beginPath();
|
|
ctx.moveTo(x + r, y);
|
|
ctx.lineTo(x + w - r, y);
|
|
ctx.arcTo(x + w, y, x + w, y + r, r);
|
|
ctx.lineTo(x + w, y + h - r);
|
|
ctx.arcTo(x + w, y + h, x + w - r, y + h, r);
|
|
ctx.lineTo(x + r, y + h);
|
|
ctx.arcTo(x, y + h, x, y + h - r, r);
|
|
ctx.lineTo(x, y + r);
|
|
ctx.arcTo(x, y, x + r, y, r);
|
|
ctx.closePath();
|
|
}
|
|
```
|
|
|
|
### Text Measurement
|
|
|
|
```javascript
|
|
const width = ctx.measureText(text).width;
|
|
```
|
|
|
|
### Hit Testing
|
|
|
|
Currently done manually by checking bounds - no need to change pattern.
|
|
|
|
---
|
|
|
|
## Color Palette Ideas
|
|
|
|
### Current (approximate from inspection)
|
|
|
|
```css
|
|
/* Data nodes - current olive green */
|
|
--base-color-node-green-700: #4a5d23;
|
|
--base-color-node-green-600: #5c7029;
|
|
|
|
/* Visual nodes - current muted blue */
|
|
--base-color-node-blue-700: #2d4a6d;
|
|
--base-color-node-blue-600: #3a5f8a;
|
|
|
|
/* Logic nodes - current grey */
|
|
--base-color-node-grey-700: #3d3d3d;
|
|
--base-color-node-grey-600: #4a4a4a;
|
|
|
|
/* Custom nodes - current pink/magenta */
|
|
--base-color-node-pink-700: #7d3a5d;
|
|
--base-color-node-pink-600: #9a4872;
|
|
```
|
|
|
|
### Proposed Direction
|
|
|
|
```css
|
|
/* Data nodes - richer emerald */
|
|
--base-color-node-green-700: #166534;
|
|
--base-color-node-green-600: #15803d;
|
|
|
|
/* Visual nodes - cleaner slate */
|
|
--base-color-node-blue-700: #334155;
|
|
--base-color-node-blue-600: #475569;
|
|
|
|
/* Logic nodes - warmer charcoal */
|
|
--base-color-node-grey-700: #3f3f46;
|
|
--base-color-node-grey-600: #52525b;
|
|
|
|
/* Custom nodes - refined rose */
|
|
--base-color-node-pink-700: #9f1239;
|
|
--base-color-node-pink-600: #be123c;
|
|
```
|
|
|
|
_Need to test contrast ratios and get visual feedback_
|
|
|
|
---
|
|
|
|
## Port Type Icons
|
|
|
|
### Character-based approach (simpler)
|
|
|
|
```typescript
|
|
const PORT_TYPE_ICONS = {
|
|
signal: '⚡', // or custom glyph
|
|
string: 'T',
|
|
number: '#',
|
|
boolean: '◐',
|
|
object: '{}',
|
|
array: '[]',
|
|
color: '●',
|
|
any: '◇'
|
|
};
|
|
```
|
|
|
|
### SVG path approach (more control)
|
|
|
|
```typescript
|
|
const PORT_TYPE_PATHS = {
|
|
signal: 'M4 0 L8 4 L4 8 L0 4 Z' // lightning bolt
|
|
// ... etc
|
|
};
|
|
```
|
|
|
|
_Need to evaluate which looks better at 10-12px_
|
|
|
|
---
|
|
|
|
## Port Grouping Logic
|
|
|
|
### Auto-grouping heuristics
|
|
|
|
```typescript
|
|
function autoGroupPorts(ports: Port[]): PortGroup[] {
|
|
const signals = ports.filter((p) => isSignalType(p.type));
|
|
const dataInputs = ports.filter((p) => p.direction === 'input' && !isSignalType(p.type));
|
|
const dataOutputs = ports.filter((p) => p.direction === 'output' && !isSignalType(p.type));
|
|
|
|
const groups: PortGroup[] = [];
|
|
|
|
if (signals.length > 0) {
|
|
groups.push({ name: 'Events', ports: signals, expanded: true });
|
|
}
|
|
if (dataInputs.length > 0) {
|
|
groups.push({ name: 'Inputs', ports: dataInputs, expanded: true });
|
|
}
|
|
if (dataOutputs.length > 0) {
|
|
groups.push({ name: 'Outputs', ports: dataOutputs, expanded: true });
|
|
}
|
|
|
|
return groups;
|
|
}
|
|
|
|
function isSignalType(type: string): boolean {
|
|
return type === 'signal' || type === '*'; // Check actual type names
|
|
}
|
|
```
|
|
|
|
### Explicit group configuration example (HTTP node)
|
|
|
|
```typescript
|
|
{
|
|
portGroups: [
|
|
{
|
|
name: 'Request',
|
|
ports: ['url', 'method', 'body', 'headers-*'],
|
|
defaultExpanded: true
|
|
},
|
|
{
|
|
name: 'Response',
|
|
ports: ['status', 'response', 'responseHeaders'],
|
|
defaultExpanded: true
|
|
},
|
|
{
|
|
name: 'Control',
|
|
ports: ['send', 'success', 'failure', 'error'],
|
|
defaultExpanded: true
|
|
}
|
|
];
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Connection Compatibility
|
|
|
|
### Existing type checking
|
|
|
|
```typescript
|
|
// Check NodeLibrary for existing type compatibility logic
|
|
NodeLibrary.instance.canConnect(sourceType, targetType);
|
|
```
|
|
|
|
### Visual feedback states
|
|
|
|
1. **Source port** - Normal rendering (this is what user is hovering)
|
|
2. **Compatible** - Brighter, subtle glow, maybe pulse animation
|
|
3. **Incompatible** - Dimmed to 50% opacity, greyed connection point
|
|
|
|
---
|
|
|
|
## Comment Modal Positioning
|
|
|
|
### Algorithm
|
|
|
|
```typescript
|
|
function calculateModalPosition(node: NodeGraphEditorNode): { x: number; y: number } {
|
|
const nodeScreenPos = canvasToScreen(node.global.x, node.global.y);
|
|
const nodeWidth = node.nodeSize.width * currentScale;
|
|
const nodeHeight = node.nodeSize.height * currentScale;
|
|
|
|
// Position to the right of the node
|
|
let x = nodeScreenPos.x + nodeWidth + 20;
|
|
let y = nodeScreenPos.y;
|
|
|
|
// Check if off-screen right, move to left
|
|
if (x + MODAL_WIDTH > window.innerWidth) {
|
|
x = nodeScreenPos.x - MODAL_WIDTH - 20;
|
|
}
|
|
|
|
// Check if off-screen bottom
|
|
if (y + MODAL_HEIGHT > window.innerHeight) {
|
|
y = window.innerHeight - MODAL_HEIGHT - 20;
|
|
}
|
|
|
|
return { x, y };
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Learnings to Add to LEARNINGS.md
|
|
|
|
_Add these after implementation:_
|
|
|
|
- [ ] Canvas roundRect browser support findings
|
|
- [ ] Performance impact of rounded corners
|
|
- [ ] Comment storage in metadata - any gotchas
|
|
- [ ] Port grouping measurement calculations
|
|
- [ ] Connection preview performance considerations
|
|
|
|
---
|
|
|
|
## Questions to Resolve
|
|
|
|
1. ~~Should rounded corners apply to title bar only or whole node?~~
|
|
|
|
- Decision: Whole node with consistent radius
|
|
|
|
2. What happens to comments when node is copied to different project?
|
|
|
|
- Need to test metadata handling in import/export
|
|
|
|
3. Should port groups be user-customizable or only defined in node types?
|
|
|
|
- Start with node type definitions, user customization is future enhancement
|
|
|
|
4. How to handle groups for Component nodes (user-defined ports)?
|
|
- Auto-group based on port direction (input/output)
|
|
|
|
---
|
|
|
|
## Reference Screenshots
|
|
|
|
_Add reference screenshots here during implementation for comparison_
|
|
|
|
### Design References
|
|
|
|
- [ ] Modern node-based tools (Unreal Blueprints, Blender Geometry Nodes)
|
|
- [ ] Other low-code tools for comparison
|
|
|
|
### OpenNoodl Current State
|
|
|
|
- [ ] Capture before screenshots
|
|
- [ ] Note specific problem areas
|