Sophia - A Study Dashboard
<!-- Main container -->
<div class="flex flex-1">
    <!-- Graph Explorer (Left Pane) -->
    <div id="graph-container" class="graph-container flex-1 bg-gray-900 relative">
        <div class="absolute top-4 left-4 z-10">
            <h1 class="text-2xl font-bold text-white tracking-wider">Sophia</h1>
            <p class="text-sm text-gray-400">An Interactive Study Dashboard</p>
        </div>
         <!-- Legend -->
        <div id="legend" class="absolute bottom-4 left-4 bg-gray-800 bg-opacity-80 p-3 rounded-lg text-xs z-10"></div>
    </div>

    <!-- Study Pane (Right Pane) -->
    <aside id="study-pane" class="w-full max-w-md bg-gray-800 border-l border-gray-700 flex flex-col h-full">
        <div id="study-pane-content" class="flex-1 overflow-y-auto p-6 study-pane-content">
            <!-- Initial Welcome Message -->
            <div id="welcome-message" class="text-center h-full flex flex-col justify-center">
                <svg class="w-16 h-16 mx-auto text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v11.494m-9-5.747h18"></path><path d="M12 3a9 9 0 100 18 9 9 0 000-18z"></path></svg>
                <h2 class="mt-4 text-xl font-semibold text-white">Welcome to Sophia</h2>
                <p class="mt-2 text-gray-400">Click on a node in the graph to begin your exploration. Each node represents a concept, theory, or thinker in the world of Philosophy.</p>
            </div>

            <!-- Dynamic Content will be injected here -->
            <div id="node-content" class="hidden">
                <div class="flex items-center justify-between mb-4">
                    <h2 id="node-title" class="text-2xl font-bold text-white"></h2>
                    <span id="node-type-badge" class="px-3 py-1 text-sm font-medium rounded-full"></span>
                </div>
                <div id="node-description" class="prose prose-invert prose-sm max-w-none text-gray-300"></div>

                <h3 class="mt-6 mb-3 text-lg font-semibold text-white border-b border-gray-700 pb-2">Connections</h3>
                <ul id="node-connections" class="space-y-2 list-none p-0"></ul>

                <h3 class="mt-6 mb-3 text-lg font-semibold text-white border-b border-gray-700 pb-2">Sources</h3>
                <ul id="node-sources" class="space-y-2 list-disc list-inside p-0"></ul>
            </div>
        </div>
    </aside>
</div>

<script>
    // --- DATA ---
    // Hardcoded data for the Philosophy knowledge graph
    const philosophyData = {
        nodes: [
            { id: 1, name: "Philosophy", type: "Discipline", content: "The study of general and fundamental questions, such as those about reason, existence, knowledge, values, mind, and language. It is a rational and critical inquiry that reflects on its own methods and assumptions." },
            { id: 2, name: "Epistemology", type: "Branch", content: "The branch of philosophy concerned with knowledge. Epistemologists study the nature of knowledge, epistemic justification, the rationality of belief, and various related issues." },
            { id: 3, name: "Metaphysics", type: "Branch", content: "The branch of philosophy that examines the fundamental nature of reality, including the relationship between mind and matter, between substance and attribute, and between potentiality and actuality." },
            { id: 4, name: "Ethics", type: "Branch", content: "Also known as moral philosophy, this branch involves systematizing, defending, and recommending concepts of right and wrong conduct. It is often divided into meta-ethics, normative ethics, and applied ethics." },
            { id: 5, name: "A Priori Knowledge", type: "Concept", content: "Knowledge that is independent of all particular experiences, as opposed to a posteriori knowledge, which derives from experience. Mathematical truths (e.g., 2+2=4) are often cited as examples." },
            { id: 6, name: "A Posteriori Knowledge", type: "Concept", content: "Knowledge derived from experience or empirical evidence. The statement 'Water boils at 100°C at sea level' is an example, as it is known through observation." },
            { id: 7, name: "Rationalism", type: "Theory", content: "A theory in epistemology that views reason as the chief source and test of knowledge. Rationalists hold that reality itself has an inherently logical structure and that certain truths exist which the intellect can grasp directly." },
            { id: 8, name: "Empiricism", type: "Theory", content: "A theory that states that knowledge comes only or primarily from sensory experience. It emphasizes the role of empirical evidence in the formation of ideas, over the idea of innate ideas or tradition." },
            { id: 9, name: "Plato", type: "Philosopher", content: "An Athenian philosopher during the Classical period in Ancient Greece, founder of the Platonist school of thought, and the Academy, the first institution of higher learning in the Western world. He is a central figure in the history of Ancient Greek philosophy and the Western tradition." },
            { id: 10, name: "Aristotle", type: "Philosopher", content: "A Greek philosopher and polymath during the Classical period in Ancient Greece. Taught by Plato, he was the founder of the Lyceum, the Peripatetic school of philosophy, and the Aristotelian tradition." },
            { id: 11, name: "Theory of Forms", type: "Theory", content: "A philosophical theory, concept, or world-view, attributed to Plato, that the physical world is not as real or true as timeless, absolute, unchangeable ideas. According to this theory, ideas in this sense, often capitalized and translated as 'Ideas' or 'Forms', are the non-physical essences of all things, of which objects and matter in the physical world are merely imitations." },
            { id: 12, "name": "Socratic Method", "type": "Concept", "content": "A form of cooperative argumentative dialogue between individuals, based on asking and answering questions to stimulate critical thinking and to draw out ideas and underlying presuppositions. It is named after the Classical Greek philosopher Socrates." }
        ],
        links: [
            { source: 1, target: 2 }, { source: 1, target: 3 }, { source: 1, target: 4 },
            { source: 2, target: 5 }, { source: 2, target: 6 }, { source: 2, target: 7 }, { source: 2, target: 8 },
            { source: 7, target: 5 }, { source: 8, target: 6 },
            { source: 9, target: 2 }, { source: 9, target: 3 }, { source: 9, target: 11 }, { source: 9, target: 12 },
            { source: 10, target: 2 }, { source: 10, target: 3 }, { source: 10, target: 4 },
            { source: 9, target: 10 }, // Plato taught Aristotle
            { source: 7, target: 9 }, // Plato was a key rationalist
            { source: 8, target: 10 }, // Aristotle was a key empiricist
            { source: 11, target: 3 }
        ]
    };
    
    // --- CONFIGURATION ---
    const nodeColors = {
        'Discipline': '#3b82f6', // blue-500
        'Branch': '#8b5cf6', // violet-500
        'Concept': '#10b981', // emerald-500
        'Theory': '#ec4899', // pink-500
        'Philosopher': '#f97316', // orange-500
    };
    const nodeTypeBadgeClasses = {
        'Discipline': 'bg-blue-500 text-white',
        'Branch': 'bg-violet-500 text-white',
        'Concept': 'bg-emerald-500 text-white',
        'Theory': 'bg-pink-500 text-white',
        'Philosopher': 'bg-orange-500 text-white',
    }

    // --- DOM ELEMENTS ---
    const graphContainer = document.getElementById('graph-container');
    const studyPane = document.getElementById('study-pane');
    const welcomeMessage = document.getElementById('welcome-message');
    const nodeContent = document.getElementById('node-content');
    const nodeTitle = document.getElementById('node-title');
    const nodeTypeBadge = document.getElementById('node-type-badge');
    const nodeDescription = document.getElementById('node-description');
    const nodeConnections = document.getElementById('node-connections');
    const nodeSources = document.getElementById('node-sources');

    // --- D3 GRAPH VISUALIZATION ---
    const width = graphContainer.clientWidth;
    const height = graphContainer.clientHeight;

    const svg = d3.select("#graph-container").append("svg")
        .attr("width", 500)
        .attr("height", 2000)
        .call(d3.zoom().on("zoom", (event) => {
            g.attr("transform", event.transform);
        }))
        .append("g");
    
    const g = svg.append("g");
    
    const simulation = d3.forceSimulation(philosophyData.nodes)
        .force("link", d3.forceLink(philosophyData.links).id(d => d.id).distance(100))
        .force("charge", d3.forceManyBody().strength(-300))
        .force("center", d3.forceCenter(width / 2, height / 2))
        .force("collide", d3.forceCollide().radius(30));

    const link = g.append("g")
        .attr("class", "links")
        .selectAll("line")
        .data(philosophyData.links)
        .enter().append("line")
        .attr("class", "link");

    const node = g.append("g")
        .attr("class", "nodes")
        .selectAll("g")
        .data(philosophyData.nodes)
        .enter().append("g")
        .attr("class", "node")
        .on("click", onNodeClick)
        .call(d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended));

    node.append("circle")
        .attr("r", 20)
        .attr("fill", d => nodeColors[d.type] || '#737373');

    node.append("text")
        .text(d => d.name)
        .attr("y", 30);

    simulation.on("tick", () => {
        link
            .attr("x1", d => d.source.x)
            .attr("y1", d => d.source.y)
            .attr("x2", d => d.target.x)
            .attr("y2", d => d.target.y);

        node.attr("transform", d => `translate(${d.x},${d.y})`);
    });

    // --- EVENT HANDLERS & HELPERS ---
    let selectedNode = null;

    function onNodeClick(event, d) {
        // Update selected node state
        selectedNode = d;
        
        // Update graph visuals
        node.classed("selected", n => n.id === d.id);
        link.classed("highlighted", l => (l.source.id === d.id || l.target.id === d.id));
        
        // Update study pane content
        updateStudyPane(d);
        
        // Prevent event propagation
        event.stopPropagation();
    }

    // Reset selection when clicking on the background
    d3.select("#graph-container svg").on("click", () => {
         if (selectedNode) {
             selectedNode = null;
             node.classed("selected", false);
             link.classed("highlighted", false);
             welcomeMessage.classList.remove('hidden');
             nodeContent.classList.add('hidden');
         }
    });

    function updateStudyPane(d) {
        welcomeMessage.classList.add('hidden');
        nodeContent.classList.remove('hidden');

        nodeTitle.textContent = d.name;
        nodeTypeBadge.textContent = d.type;
        nodeTypeBadge.className = `px-3 py-1 text-sm font-medium rounded-full ${nodeTypeBadgeClasses[d.type] || 'bg-gray-500 text-white'}`;
        nodeDescription.innerHTML = `<p>${d.content.replace(/\n/g, '</p><p>')}</p>`;

        // Update connections
        nodeConnections.innerHTML = '';
        const connections = philosophyData.links.filter(l => l.source.id === d.id || l.target.id === d.id);
        if(connections.length > 0) {
            connections.forEach(l => {
                const otherNodeId = l.source.id === d.id ? l.target.id : l.source.id;
                const otherNode = philosophyData.nodes.find(n => n.id === otherNodeId);
                if (otherNode) {
                    const li = document.createElement('li');
                    li.className = 'bg-gray-700 p-2 rounded-md text-sm text-gray-300';
                    li.innerHTML = `Connected to: <span class="font-semibold text-white">${otherNode.name}</span>`;
                    nodeConnections.appendChild(li);
                }
            });
        } else {
             nodeConnections.innerHTML = '<li class="text-gray-400 text-sm">No direct connections in this view.</li>';
        }


        // Mock sources
        nodeSources.innerHTML = '';
        const sources = [
            { title: "Stanford Encyclopedia of Philosophy", url: "#" },
            { title: "Internet Encyclopedia of Philosophy", url: "#" }
        ];
        sources.forEach(source => {
             const li = document.createElement('li');
             li.className = 'text-sm';
             li.innerHTML = `<a href="${source.url}" target="_blank" rel="noopener noreferrer" class="text-violet-400 hover:underline">${source.title}</a>`;
             nodeSources.appendChild(li);
        });
    }
    
    // --- DRAG FUNCTIONS ---
    function dragstarted(event, d) {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
        d3.select(this).raise();
    }

    function dragged(event, d) {
        d.fx = event.x;
        d.fy = event.y;
    }

    function dragended(event, d) {
        if (!event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
    }

    // --- LEGEND ---
    const legendContainer = d3.select("#legend");
    const legendData = Object.entries(nodeColors);
    
    legendData.forEach(([type, color]) => {
        const legendItem = legendContainer.append("div")
            .attr("class", "flex items-center mb-1");

        legendItem.append("div")
            .style("background-color", color)
            .attr("class", "w-3 h-3 rounded-full mr-2");

        legendItem.append("span")
            .text(type)
            .attr("class", "text-gray-300");
    });

</script>