Spaces:
Running
Running
File size: 4,939 Bytes
8e723d7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | "use client";
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import {
Network,
Target,
Rocket,
Shield,
Users,
Zap,
Heart,
Briefcase
} from "lucide-react";
const mindMapData = [
{ id: "root", label: "Corporación ERP", icon: Network, color: "text-blue-400", sub: ["mision", "vision", "valores"] },
{ id: "mision", label: "Misión", icon: Target, color: "text-purple-400", sub: ["digitalizar", "automatizar"] },
{ id: "vision", label: "Visión 2030", icon: Rocket, color: "text-orange-400", sub: ["global", "ia"] },
{ id: "valores", label: "Valores", icon: Shield, color: "text-emerald-400", sub: ["etica", "calidad"] },
{ id: "digitalizar", label: "Digitalización", icon: Zap, color: "text-yellow-400", parent: "mision" },
{ id: "automatizar", label: "Automatización", icon: Heart, color: "text-pink-400", parent: "mision" },
{ id: "global", label: "Expansión Global", icon: Briefcase, color: "text-blue-500", parent: "vision" },
{ id: "ia", label: "IA Avanzada", icon: Rocket, color: "text-indigo-400", parent: "vision" },
];
export default function MindMapPage() {
const [activeNode, setActiveNode] = useState("root");
const currentNode = mindMapData.find(n => n.id === activeNode) || mindMapData[0];
const children = mindMapData.filter(n => currentNode.sub?.includes(n.id));
const parent = mindMapData.find(n => n.id === currentNode.parent);
return (
<div className="p-10 min-h-screen relative flex items-center justify-center overflow-hidden">
<div className="absolute top-10 left-10">
<h1 className="text-4xl font-black italic mb-2 tracking-tighter">MIND / MAP</h1>
<p className="text-gray-500 font-bold uppercase text-[10px] tracking-widest">ADN de la Organización</p>
</div>
<AnimatePresence mode="wait">
<motion.div
key={activeNode}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 1.2 }}
className="relative flex flex-col items-center"
>
{/* Main Node */}
<div className="relative z-20">
<NodeUI node={currentNode} size="large" />
{/* Parent Link */}
{parent && (
<button
onClick={() => setActiveNode(parent.id)}
className="absolute -top-32 left-1/2 -translate-x-1/2 px-4 py-2 bg-white/5 border border-white/10 rounded-full text-[10px] font-black uppercase text-gray-500 hover:text-white hover:bg-white/10 transition-all border-dashed"
>
↑ Subir a {parent.label}
</button>
)}
</div>
{/* Children Nodes */}
{children.length > 0 && (
<div className="mt-40 flex gap-20 relative">
{children.map((child, i) => (
<div key={child.id} className="relative group">
<motion.div
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ delay: i * 0.1 }}
onClick={() => setActiveNode(child.id)}
className="cursor-pointer"
>
<NodeUI node={child} size="medium" />
</motion.div>
{/* Line */}
<div className="absolute -top-24 left-1/2 -translate-x-1/2 w-px h-24 bg-gradient-to-t from-white/20 to-transparent"></div>
</div>
))}
</div>
)}
</motion.div>
</AnimatePresence>
<div className="absolute bottom-10 right-10 text-right text-[10px] text-gray-700 font-bold uppercase tracking-widest leading-loose">
Navegación Interactiva<br/>
Selecciona un nodo para profundizar<br/>
Basado en Core-Business Pillars
</div>
</div>
);
}
function NodeUI({ node, size }: { node: any, size: "large" | "medium" }) {
const Icon = node.icon;
return (
<div className={`
flex flex-col items-center justify-center rounded-[3rem] border backdrop-blur-3xl shadow-2xl group transition-all
${size === 'large' ? 'w-64 h-64 bg-blue-600/10 border-blue-500/40' : 'w-48 h-48 bg-white/5 border-white/10 hover:border-white/30 hover:bg-white/10'}
`}>
<Icon size={size === 'large' ? 64 : 40} className={`${node.color} mb-6 group-hover:scale-110 transition-transform`} />
<span className={`font-black uppercase tracking-tighter text-center px-4 ${size === 'large' ? 'text-2xl' : 'text-sm text-gray-400 group-hover:text-white transition-colors'}`}>
{node.label}
</span>
{node.sub && (
<span className="mt-4 text-[8px] font-black text-blue-500/60 uppercase group-hover:text-blue-400 transition-colors">
Expandible +
</span>
)}
</div>
);
}
|