import React, { useState } from 'react';
// Folder-level data
const folders = [
{ id: 'pages', name: 'Pages', icon: '📄', count: 5, x: 80, y: 100, color: 'blue' },
{ id: 'swapcard', name: '#Swapcard', icon: '🔗', count: 8, x: 230, y: 50, color: 'orange' },
{ id: 'forms', name: '#Forms', icon: '📝', count: 15, x: 230, y: 170, color: 'purple' },
{ id: 'directus', name: '#Directus', icon: '🗄️', count: 45, x: 400, y: 50, color: 'green' },
{ id: 'ui', name: '#UI', icon: '🎨', count: 32, x: 400, y: 170, color: 'cyan' },
{ id: 'global', name: '#Global', icon: '⚙️', count: 18, x: 520, y: 280, color: 'gray' },
];
const folderConnections = [
{ from: 'pages', to: 'directus', count: 34 },
{ from: 'pages', to: 'ui', count: 28 },
{ from: 'pages', to: 'forms', count: 8 },
{ from: 'pages', to: 'swapcard', count: 15 },
{ from: 'pages', to: 'global', count: 12 },
{ from: 'forms', to: 'directus', count: 22 },
{ from: 'forms', to: 'ui', count: 18 },
{ from: 'swapcard', to: 'ui', count: 6 },
{ from: 'swapcard', to: 'global', count: 3 },
{ from: 'directus', to: 'global', count: 8 },
{ from: 'ui', to: 'global', count: 5 },
];
// Component-level data for #Directus folder
const directusComponents = [
{ id: 'auth', name: 'DirectusAuth', usedBy: 12, uses: ['global-logger'], x: 60, y: 60 },
{ id: 'query', name: 'DirectusQuery', usedBy: 28, uses: ['auth', 'error'], x: 180, y: 40 },
{ id: 'mutation', name: 'DirectusMutation', usedBy: 18, uses: ['auth', 'error'], x: 180, y: 110 },
{ id: 'upload', name: 'DirectusUpload', usedBy: 8, uses: ['auth'], x: 300, y: 60 },
{ id: 'list', name: 'DirectusList', usedBy: 15, uses: ['query'], x: 300, y: 130 },
{ id: 'item', name: 'DirectusItem', usedBy: 22, uses: ['query', 'mutation'], x: 420, y: 80 },
{ id: 'error', name: 'DirectusError', usedBy: 3, uses: [], x: 60, y: 130 },
{ id: 'file', name: 'DirectusFile', usedBy: 6, uses: ['upload'], x: 420, y: 150 },
];
const directusInternalConnections = [
{ from: 'query', to: 'auth' },
{ from: 'mutation', to: 'auth' },
{ from: 'upload', to: 'auth' },
{ from: 'query', to: 'error' },
{ from: 'mutation', to: 'error' },
{ from: 'list', to: 'query' },
{ from: 'item', to: 'query' },
{ from: 'item', to: 'mutation' },
{ from: 'file', to: 'upload' },
];
// External connections (from components in other folders TO directus components)
const directusExternalConnections = [
{ fromFolder: 'pages', toComponent: 'query', count: 18 },
{ fromFolder: 'pages', toComponent: 'mutation', count: 8 },
{ fromFolder: 'pages', toComponent: 'list', count: 5 },
{ fromFolder: 'pages', toComponent: 'auth', count: 3 },
{ fromFolder: 'forms', toComponent: 'query', count: 12 },
{ fromFolder: 'forms', toComponent: 'mutation', count: 10 },
];
const colorClasses = {
blue: { bg: 'bg-blue-900', border: 'border-blue-500', text: 'text-blue-200', light: 'bg-blue-800' },
orange: { bg: 'bg-orange-900', border: 'border-orange-500', text: 'text-orange-200', light: 'bg-orange-800' },
purple: { bg: 'bg-purple-900', border: 'border-purple-500', text: 'text-purple-200', light: 'bg-purple-800' },
green: { bg: 'bg-green-900', border: 'border-green-500', text: 'text-green-200', light: 'bg-green-800' },
cyan: { bg: 'bg-cyan-900', border: 'border-cyan-500', text: 'text-cyan-200', light: 'bg-cyan-800' },
gray: { bg: 'bg-gray-700', border: 'border-gray-500', text: 'text-gray-200', light: 'bg-gray-600' },
};
// State 1: Folder-level overview
function FolderOverview({ onExpandFolder, onSelectFolder, selectedFolder }) {
return (
);
}
// State 2: Expanded folder showing components
function ExpandedFolderView({ folderId, onBack, onSelectComponent, selectedComponent, onOpenXray }) {
const folder = folders.find(f => f.id === folderId);
const colors = colorClasses[folder.color];
// For this mockup, we only have detailed data for Directus
const components = folderId === 'directus' ? directusComponents : [];
const internalConns = folderId === 'directus' ? directusInternalConnections : [];
const externalConns = folderId === 'directus' ? directusExternalConnections : [];
return (
);
}
// Component detail panel (appears when component selected)
function ComponentDetailPanel({ component, onOpenXray, onClose }) {
if (!component) return null;
const comp = directusComponents.find(c => c.id === component);
if (!comp) return null;
return (
Used by
{comp.usedBy} components
Pages (18×), Forms (12×)...
Uses
{comp.uses.length > 0 ? comp.uses.map(u => (
{u}
)) : No dependencies}
);
}
// Folder detail panel
function FolderDetailPanel({ folder, onExpand, onClose }) {
if (!folder) return null;
const f = folders.find(fo => fo.id === folder);
if (!f) return null;
const incomingConns = folderConnections.filter(c => c.to === folder);
const outgoingConns = folderConnections.filter(c => c.from === folder);
return (
Components
{f.count}
Incoming ({incomingConns.reduce((a, c) => a + c.count, 0)})
{incomingConns.slice(0, 3).map(c => {
const fromFolder = folders.find(fo => fo.id === c.from);
return (
← {fromFolder.name}
{c.count}×
);
})}
Outgoing ({outgoingConns.reduce((a, c) => a + c.count, 0)})
{outgoingConns.slice(0, 3).map(c => {
const toFolder = folders.find(fo => fo.id === c.to);
return (
→ {toFolder.name}
{c.count}×
);
})}
);
}
// X-Ray modal preview (just to show the handoff)
function XrayPreviewModal({ component, onClose }) {
return (
X-Ray View
{component.name}
{/* Mock X-ray content */}
Inputs
collectionName
filter
limit
Outputs
data
loading
error
Internal Nodes
12 nodes (3 REST, 4 Logic, 5 Data)
This is a preview — full X-Ray would open in sidebar panel
);
}
// Main component with state management
export default function TopologyDrilldown() {
const [view, setView] = useState('folders'); // 'folders' | 'expanded'
const [expandedFolder, setExpandedFolder] = useState(null);
const [selectedFolder, setSelectedFolder] = useState(null);
const [selectedComponent, setSelectedComponent] = useState(null);
const [xrayComponent, setXrayComponent] = useState(null);
const handleExpandFolder = (folderId) => {
setExpandedFolder(folderId);
setView('expanded');
setSelectedFolder(null);
};
const handleBack = () => {
setView('folders');
setExpandedFolder(null);
setSelectedComponent(null);
};
const handleOpenXray = (component) => {
setXrayComponent(component);
};
return (
{/* Header */}
Project Topology
{view === 'expanded' && (
)}
{view === 'folders' ? '6 folders • 123 components' : `#Directus • 45 components`}
{/* Breadcrumb */}
App
{view === 'expanded' && (
<>
›
#Directus
>
)}
{selectedComponent && (
<>
›
{directusComponents.find(c => c.id === selectedComponent)?.name}
>
)}
{/* Main canvas area */}
{view === 'folders' ? (
) : (
)}
{/* Detail panels */}
{view === 'folders' && selectedFolder && (
handleExpandFolder(selectedFolder)}
onClose={() => setSelectedFolder(null)}
/>
)}
{view === 'expanded' && selectedComponent && (
setSelectedComponent(null)}
/>
)}
{/* X-Ray modal */}
{xrayComponent && (
setXrayComponent(null)}
/>
)}
{/* Footer status */}
{view === 'folders'
? 'Double-click folder to expand • Click for details • 68 orphan components not shown'
: 'Double-click component for X-Ray • External connections shown from Pages & Forms'
}
Pages
Forms
Internal
);
}