feat(appliance): initial release of MERICA standalone appliance v1.0.0

This commit is contained in:
2026-10-21 17:16:46 +07:00
commit 851be0cda7
144 changed files with 31135 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
import React, { useState } from 'react';
import { EdgeLabelRenderer, BaseEdge } from 'reactflow';
import { X } from 'lucide-react';
export default function RemovableEdge({
id,
sourceX,
sourceY,
targetX,
targetY,
style = {},
markerEnd,
data,
}) {
const [isHovered, setIsHovered] = useState(false);
// Cubic Bezier with horizontal control points max(50, |dx|/2)
const dx = Math.max(50, Math.abs(targetX - sourceX) / 2);
const edgePath = `M${sourceX},${sourceY} C${sourceX + dx},${sourceY} ${targetX - dx},${targetY} ${targetX},${targetY}`;
const midX = (sourceX + targetX) / 2;
const midY = (sourceY + targetY) / 2;
const handleDelete = (evt) => {
if (evt) evt.stopPropagation();
if (data && data.onDeleteEdge) {
data.onDeleteEdge(id);
}
};
const handleDoubleClick = (evt) => {
evt.stopPropagation();
handleDelete(evt);
};
return (
<>
{/* VISIBLE BEZIER EDGE */}
<BaseEdge
path={edgePath}
markerEnd={markerEnd}
style={{
...style,
stroke: isHovered ? 'var(--acc)' : style.stroke || 'var(--muted)',
strokeWidth: isHovered ? 2.5 : style.strokeWidth || 2,
transition: 'stroke 0.15s ease, stroke-width 0.15s ease',
}}
/>
{/* INVISIBLE WIDE HIT AREA FOR HOVER AND DOUBLE CLICK TO DELETE */}
<path
d={edgePath}
fill="none"
stroke="transparent"
strokeWidth={22}
style={{ cursor: 'pointer' }}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
onDoubleClick={handleDoubleClick}
/>
{/* OPTIONAL HOVER DELETE BUTTON IN CENTER */}
{isHovered && (
<EdgeLabelRenderer>
<div
style={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${midX}px,${midY}px)`,
fontSize: 12,
pointerEvents: 'all',
zIndex: 10,
}}
className="nodrag nopan"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<button
onClick={handleDelete}
title="Click or double-click line to delete connection"
aria-label="Delete connection"
style={{
width: '18px',
height: '18px',
borderRadius: '50%',
background: 'var(--surface)',
color: 'var(--muted)',
border: '1px solid var(--line)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
boxShadow: 'var(--shadow)',
padding: 0,
}}
onMouseEnter={(e) => {
e.currentTarget.style.color = '#ffffff';
e.currentTarget.style.background = 'var(--err)';
e.currentTarget.style.borderColor = 'var(--err)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.color = 'var(--muted)';
e.currentTarget.style.background = 'var(--surface)';
e.currentTarget.style.borderColor = 'var(--line)';
}}
>
<X size={10} strokeWidth={2.5} />
</button>
</div>
</EdgeLabelRenderer>
)}
</>
);
}