import { useMemo } from "react"; import ReactMarkdown from "react-markdown"; import { useDashboardStore } from "../store"; import { useI18n } from "../contexts/I18nContext"; export default function LearnPanel() { const graph = useDashboardStore((s) => s.graph); const tourActive = useDashboardStore((s) => s.tourActive); const currentTourStep = useDashboardStore((s) => s.currentTourStep); const startTour = useDashboardStore((s) => s.startTour); const stopTour = useDashboardStore((s) => s.stopTour); const setTourStep = useDashboardStore((s) => s.setTourStep); const nextTourStep = useDashboardStore((s) => s.nextTourStep); const prevTourStep = useDashboardStore((s) => s.prevTourStep); const selectNode = useDashboardStore((s) => s.selectNode); const { t } = useI18n(); const tourSteps = useMemo( () => graph?.tour ? [...graph.tour].sort((a, b) => a.order - b.order) : [], [graph?.tour] ); const hasTour = tourSteps.length > 0; // State 1: No tour available if (!hasTour) { return (
🧭

{t.learnPanel.noTour}

{t.learnPanel.noTourHint}

); } // State 2: Tour available but not started if (!tourActive) { return (

{t.learnPanel.projectTour}

{tourSteps.length} {t.learnPanel.steps} · {t.learnPanel.guidedWalkthrough}

{t.learnPanel.steps}

{tourSteps.map((step, i) => (
{i + 1}. {step.title}
))}
); } // State 3: Tour active const step = tourSteps[currentTourStep]; if (!step) return null; const totalSteps = tourSteps.length; const progressPct = ((currentTourStep + 1) / totalSteps) * 100; const isFirst = currentTourStep === 0; const isLast = currentTourStep === totalSteps - 1; return (
{/* Header with progress counter and exit */}

{t.learnPanel.tour}

{currentTourStep + 1} / {totalSteps}
{/* Progress bar */}
{/* Scrollable content */}
{/* Step title */}

{step.title}

{/* Description via ReactMarkdown */}
(

{children}

), strong: ({ children }) => ( {children} ), code: ({ className, children }) => { const isBlock = className?.includes("language-"); return isBlock ? ( {children} ) : ( {children} ); }, ul: ({ children }) => (
    {children}
), ol: ({ children }) => (
    {children}
), }} > {step.description}
{/* Language lesson */} {step.languageLesson && (

Language Lesson

{step.languageLesson}

)} {/* Referenced component pills */} {step.nodeIds.length > 0 && (

Referenced Components

{step.nodeIds.map((nodeId) => { const node = graph?.nodes.find((n) => n.id === nodeId); return ( ); })}
)}
{/* Navigation: dots + prev/next */}
{/* Step dots */}
{tourSteps.map((_, i) => (
{/* Prev / Next buttons */}
); }