refactor: migrate frontend from shadcn/Tailwind to Mantine v9
Reescribe todos los componentes UI para usar Mantine v9 en lugar de shadcn/Tailwind. Elimina cn(), CVA, components.json, theme_provider custom y globals.css con Tailwind. Añade 25+ componentes nuevos (AppShell, AuthForm, DatePickerInput, Dropzone, etc.) y MantineProvider como wrapper estándar del sistema de temas. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,12 @@ export interface GraphTheme {
|
||||
selectionColor?: string
|
||||
}
|
||||
|
||||
export interface ContextMenuTarget {
|
||||
type: "node" | "edge" | "canvas"
|
||||
id?: string
|
||||
data?: GraphNode | GraphEdge
|
||||
}
|
||||
|
||||
export interface GraphContainerProps {
|
||||
data: GraphData
|
||||
layout?: "organic" | "random"
|
||||
@@ -58,6 +64,7 @@ export interface GraphContainerProps {
|
||||
nodeTypes?: NodeType[]
|
||||
onNodeClick?: (node: GraphNode) => void
|
||||
onNodeDoubleClick?: (node: GraphNode) => void
|
||||
onContextMenu?: (event: MouseEvent, target: ContextMenuTarget) => void
|
||||
enableSelection?: boolean
|
||||
selectionMode?: "single" | "multiple"
|
||||
theme?: GraphTheme
|
||||
@@ -84,6 +91,7 @@ function GraphContainer({
|
||||
nodeTypes = [],
|
||||
onNodeClick,
|
||||
onNodeDoubleClick,
|
||||
onContextMenu,
|
||||
theme: themeProp,
|
||||
height = "100%",
|
||||
className,
|
||||
@@ -96,10 +104,30 @@ function GraphContainer({
|
||||
[themeProp],
|
||||
)
|
||||
|
||||
// Build + render
|
||||
// Build + render — wait for container to have dimensions
|
||||
const [ready, setReady] = React.useState(false)
|
||||
React.useEffect(() => {
|
||||
const el = containerRef.current
|
||||
if (!el) return
|
||||
if (el.clientHeight > 0 && el.clientWidth > 0) {
|
||||
setReady(true)
|
||||
return
|
||||
}
|
||||
const ro = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.contentRect.height > 0 && entry.contentRect.width > 0) {
|
||||
setReady(true)
|
||||
ro.disconnect()
|
||||
}
|
||||
}
|
||||
})
|
||||
ro.observe(el)
|
||||
return () => ro.disconnect()
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
const el = containerRef.current
|
||||
if (!el || !ready) return
|
||||
|
||||
// Cleanup previous instance
|
||||
if (sigmaRef.current) {
|
||||
@@ -110,7 +138,7 @@ function GraphContainer({
|
||||
const g = new Graph({ multi: true, type: "directed" })
|
||||
graphRef.current = g
|
||||
|
||||
// Add nodes
|
||||
// Add nodes — store entity type as entityType to avoid sigma interpreting it as render program
|
||||
for (const n of data.nodes) {
|
||||
g.addNode(n.id, {
|
||||
label: n.label,
|
||||
@@ -118,7 +146,7 @@ function GraphContainer({
|
||||
y: n.y ?? (Math.random() - 0.5) * 10,
|
||||
size: n.size ?? theme.nodeSize,
|
||||
color: n.color ?? theme.nodeColor,
|
||||
type: n.type,
|
||||
entityType: n.type,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -152,6 +180,7 @@ function GraphContainer({
|
||||
|
||||
// Render
|
||||
const renderer = new Sigma(g, el, {
|
||||
allowInvalidContainer: true,
|
||||
renderEdgeLabels: false,
|
||||
defaultEdgeColor: theme.edgeColor,
|
||||
defaultNodeColor: theme.nodeColor,
|
||||
@@ -174,13 +203,30 @@ function GraphContainer({
|
||||
onNodeDoubleClick({ id: node, ...attrs } as unknown as GraphNode)
|
||||
})
|
||||
}
|
||||
if (onContextMenu) {
|
||||
renderer.on("rightClickNode", ({ node, event }) => {
|
||||
const mouseEvent = event.original as MouseEvent
|
||||
mouseEvent.preventDefault()
|
||||
const attrs = g.getNodeAttributes(node)
|
||||
onContextMenu(mouseEvent, {
|
||||
type: "node",
|
||||
id: node,
|
||||
data: { id: node, ...attrs } as unknown as GraphNode,
|
||||
})
|
||||
})
|
||||
renderer.on("rightClickStage", ({ event }) => {
|
||||
const mouseEvent = event.original as MouseEvent
|
||||
mouseEvent.preventDefault()
|
||||
onContextMenu(mouseEvent, { type: "canvas" })
|
||||
})
|
||||
}
|
||||
|
||||
return () => {
|
||||
renderer.kill()
|
||||
sigmaRef.current = null
|
||||
graphRef.current = null
|
||||
}
|
||||
}, [data, layout, theme, onNodeClick, onNodeDoubleClick])
|
||||
}, [data, layout, theme, onNodeClick, onNodeDoubleClick, onContextMenu, ready])
|
||||
|
||||
// Container background
|
||||
const containerStyle: React.CSSProperties = {
|
||||
|
||||
Reference in New Issue
Block a user