78 lines
2.5 KiB
TypeScript
78 lines
2.5 KiB
TypeScript
'use client';
|
|
|
|
import { useRef, useCallback } from 'react';
|
|
|
|
interface TableNodeProps {
|
|
tableName: string;
|
|
label: string;
|
|
icon: string;
|
|
columns: Record<string, any>[];
|
|
x: number;
|
|
y: number;
|
|
style?: React.CSSProperties;
|
|
onMove?: (name: string, x: number, y: number) => void;
|
|
}
|
|
|
|
export function TableNode({ tableName, label, icon, columns, x, y, style, onMove }: TableNodeProps) {
|
|
const nodeRef = useRef<HTMLDivElement>(null);
|
|
|
|
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
|
if (!onMove) return;
|
|
e.preventDefault();
|
|
const sx = e.clientX, sy = e.clientY;
|
|
const sl = x, st = y;
|
|
const el = nodeRef.current;
|
|
if (el) el.style.zIndex = '30';
|
|
|
|
const move = (ev: MouseEvent) => {
|
|
onMove(tableName, sl + ev.clientX - sx, st + ev.clientY - sy);
|
|
};
|
|
const up = () => {
|
|
if (el) el.style.zIndex = '20';
|
|
document.removeEventListener('mousemove', move);
|
|
document.removeEventListener('mouseup', up);
|
|
};
|
|
document.addEventListener('mousemove', move);
|
|
document.addEventListener('mouseup', up);
|
|
}, [onMove, tableName, x, y]);
|
|
|
|
const dtypeIcons: Record<string, string> = {
|
|
text: 'Aa', number: '#', date: '📅', select: '▼', checkbox: '☑', file: '📎', code: '⚡',
|
|
textarea: 'Aa', datetime: '📅', entity: '🔗',
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={nodeRef}
|
|
className="tbl-node"
|
|
data-table={tableName}
|
|
style={{ left: x, top: y, ...style }}
|
|
>
|
|
<div className="tbl-node-head" onMouseDown={handleMouseDown}>
|
|
<div className="tbl-icon">{icon}</div>
|
|
<span className="tbl-name">{tableName}</span>
|
|
<span className="tbl-badge">{label}</span>
|
|
</div>
|
|
<div className="tbl-node-cols">
|
|
{columns.map((col) => {
|
|
const name = col.column ?? col.name ?? col.COLUMN_NAME ?? '';
|
|
const type = col.type ?? col.dtype ?? 'text';
|
|
const mark = col.pk ? 'PK' : col.mark === 'FK' ? 'FK' : '';
|
|
const portCls = mark === 'PK' ? 'pk' : mark === 'FK' ? 'fk' : '';
|
|
const displayName = col.label ?? col.dname ?? name;
|
|
const dtIcon = dtypeIcons[type] || 'Aa';
|
|
|
|
return (
|
|
<div key={name} className="tbl-col" data-col={name}>
|
|
<div className={`tbl-port ${portCls}`} />
|
|
<span className="tbl-col-name">{displayName}</span>
|
|
<span className="tbl-col-type">{dtIcon} {type}</span>
|
|
{mark && <span className={`tbl-col-mark ${mark.toLowerCase()}`}>{mark}</span>}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|