From 6fd278d355f9911298867e6ee856fd4b42787b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Fri, 27 Jun 2025 17:18:56 -0700 Subject: [PATCH 1/7] initial commit --- website/docs/test-lidia.mdx | 16 +++++ website/sidebars.js | 12 ++++ website/src/components/Lidia/LidiaDiagram.tsx | 72 +++++++++++++++++++ .../components/Lidia/hooks/useLidiaState.ts | 39 ++++++++++ website/src/components/Lidia/index.tsx | 2 + website/src/components/Lidia/types.ts | 24 +++++++ website/src/css/custom.css | 3 + website/src/css/lidia.css | 64 +++++++++++++++++ website/static/diagrams/example/config.json | 47 ++++++++++++ .../static/diagrams/example/deep-dive-1.svg | 30 ++++++++ website/static/diagrams/example/detail-a.svg | 30 ++++++++ website/static/diagrams/example/detail-b.svg | 30 ++++++++ website/static/diagrams/example/overview.svg | 20 ++++++ 13 files changed, 389 insertions(+) create mode 100644 website/docs/test-lidia.mdx create mode 100644 website/src/components/Lidia/LidiaDiagram.tsx create mode 100644 website/src/components/Lidia/hooks/useLidiaState.ts create mode 100644 website/src/components/Lidia/index.tsx create mode 100644 website/src/components/Lidia/types.ts create mode 100644 website/src/css/lidia.css create mode 100644 website/static/diagrams/example/config.json create mode 100644 website/static/diagrams/example/deep-dive-1.svg create mode 100644 website/static/diagrams/example/detail-a.svg create mode 100644 website/static/diagrams/example/detail-b.svg create mode 100644 website/static/diagrams/example/overview.svg diff --git a/website/docs/test-lidia.mdx b/website/docs/test-lidia.mdx new file mode 100644 index 0000000000..b324d37dc1 --- /dev/null +++ b/website/docs/test-lidia.mdx @@ -0,0 +1,16 @@ +--- +title: Lidia Test Page +--- + +import LidiaDiagram from '@site/src/components/Lidia'; +import exampleConfig from '@site/static/diagrams/example/config.json'; + +# Testing Lidia Interactive Diagrams + +This page demonstrates the Lidia interactive diagram component. + + + +## How it works + +Click on different parts of the diagram to explore more details. Use the back button to return to previous states. \ No newline at end of file diff --git a/website/sidebars.js b/website/sidebars.js index d7d4957b76..b7f6a40b58 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -1208,6 +1208,18 @@ const sidebars = { label: 'Audit reports', id: 'audit-reports', }, + { + type: 'category', + label: 'Development Tools', + collapsed: true, + items: [ + { + type: 'doc', + id: 'test-lidia', + label: 'Lidia Interactive Diagrams', + }, + ], + }, { type: 'link', label: 'DAO docs', diff --git a/website/src/components/Lidia/LidiaDiagram.tsx b/website/src/components/Lidia/LidiaDiagram.tsx new file mode 100644 index 0000000000..fd91255ab5 --- /dev/null +++ b/website/src/components/Lidia/LidiaDiagram.tsx @@ -0,0 +1,72 @@ +import React, { useEffect, useRef } from 'react'; +import type { LidiaDiagramConfig } from './types'; +import { useLidiaState } from './hooks/useLidiaState'; + +interface LidiaDiagramProps { + config: LidiaDiagramConfig; +} + +export default function LidiaDiagram({ config }: LidiaDiagramProps) { + const { currentState, navigateToState, goBack, canGoBack } = useLidiaState(config); + const svgContainerRef = useRef(null); + + useEffect(() => { + if (!currentState || !svgContainerRef.current) return; + + const loadAndSetupSvg = async () => { + try { + const response = await fetch(currentState.svgPath); + const svgText = await response.text(); + + svgContainerRef.current!.innerHTML = svgText; + + const svg = svgContainerRef.current!.querySelector('svg'); + if (!svg) return; + + currentState.clickableAreas.forEach(area => { + const element = svg.querySelector(area.selector); + if (!element) return; + + element.classList.add('lidia-clickable'); + + if (area.tooltip) { + element.setAttribute('title', area.tooltip); + } + + element.addEventListener('click', () => { + navigateToState(area.nextStateId); + }); + }); + } catch (error) { + console.error('Error loading SVG:', error); + } + }; + + loadAndSetupSvg(); + }, [currentState, navigateToState]); + + if (!currentState) { + return
Error: Invalid diagram state
; + } + + return ( +
+
+

{config.title}

+ {canGoBack && ( + + )} +
+
+
+ ); +} \ No newline at end of file diff --git a/website/src/components/Lidia/hooks/useLidiaState.ts b/website/src/components/Lidia/hooks/useLidiaState.ts new file mode 100644 index 0000000000..ed98c6794b --- /dev/null +++ b/website/src/components/Lidia/hooks/useLidiaState.ts @@ -0,0 +1,39 @@ +import { useState, useCallback } from 'react'; +import type { LidiaDiagramConfig, LidiaState } from '../types'; + +export function useLidiaState(config: LidiaDiagramConfig) { + const [state, setState] = useState({ + currentStateId: config.initialStateId, + history: [config.initialStateId], + }); + + const navigateToState = useCallback((stateId: string) => { + setState(prev => ({ + currentStateId: stateId, + history: [...prev.history, stateId], + })); + }, []); + + const goBack = useCallback(() => { + setState(prev => { + if (prev.history.length <= 1) return prev; + + const newHistory = prev.history.slice(0, -1); + return { + currentStateId: newHistory[newHistory.length - 1], + history: newHistory, + }; + }); + }, []); + + const canGoBack = state.history.length > 1; + + const currentState = config.states.find(s => s.id === state.currentStateId); + + return { + currentState, + navigateToState, + goBack, + canGoBack, + }; +} \ No newline at end of file diff --git a/website/src/components/Lidia/index.tsx b/website/src/components/Lidia/index.tsx new file mode 100644 index 0000000000..fe6fc86583 --- /dev/null +++ b/website/src/components/Lidia/index.tsx @@ -0,0 +1,2 @@ +export { default } from './LidiaDiagram'; +export type { LidiaDiagramConfig, DiagramState, ClickableArea } from './types'; \ No newline at end of file diff --git a/website/src/components/Lidia/types.ts b/website/src/components/Lidia/types.ts new file mode 100644 index 0000000000..7a84e82c77 --- /dev/null +++ b/website/src/components/Lidia/types.ts @@ -0,0 +1,24 @@ +export interface ClickableArea { + id: string; + selector: string; + nextStateId: string; + tooltip?: string; +} + +export interface DiagramState { + id: string; + svgPath: string; + clickableAreas: ClickableArea[]; +} + +export interface LidiaDiagramConfig { + id: string; + title: string; + states: DiagramState[]; + initialStateId: string; +} + +export interface LidiaState { + currentStateId: string; + history: string[]; +} \ No newline at end of file diff --git a/website/src/css/custom.css b/website/src/css/custom.css index dbe0b5f53f..e959e8ee4d 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -98,3 +98,6 @@ .wrapcode code { white-space: pre-wrap; } + +/* Import Lidia component styles */ +@import './lidia.css'; diff --git a/website/src/css/lidia.css b/website/src/css/lidia.css new file mode 100644 index 0000000000..37e13def67 --- /dev/null +++ b/website/src/css/lidia.css @@ -0,0 +1,64 @@ +.lidia-container { + margin: 2rem 0; + border: 1px solid var(--ifm-color-emphasis-300); + border-radius: var(--ifm-border-radius); + padding: 1.5rem; + background: var(--ifm-background-surface-color); +} + +.lidia-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.lidia-title { + margin: 0; + font-size: 1.25rem; +} + +.lidia-back-button { + padding: 0.5rem 1rem; + background: var(--ifm-color-primary); + color: white; + border: none; + border-radius: var(--ifm-border-radius); + cursor: pointer; + font-size: 0.875rem; + transition: opacity 0.2s; +} + +.lidia-back-button:hover { + opacity: 0.8; +} + +.lidia-svg-container { + overflow: auto; + display: flex; + justify-content: center; + align-items: center; + min-height: 400px; +} + +.lidia-svg-container svg { + max-width: 100%; + height: auto; +} + +.lidia-clickable { + cursor: pointer; + transition: opacity 0.2s; +} + +.lidia-clickable:hover { + opacity: 0.7; +} + +.lidia-error { + padding: 1rem; + background: var(--ifm-color-danger-lightest); + color: var(--ifm-color-danger-dark); + border-radius: var(--ifm-border-radius); + margin: 1rem 0; +} \ No newline at end of file diff --git a/website/static/diagrams/example/config.json b/website/static/diagrams/example/config.json new file mode 100644 index 0000000000..c2a0719b40 --- /dev/null +++ b/website/static/diagrams/example/config.json @@ -0,0 +1,47 @@ +{ + "id": "example-diagram", + "title": "Example Interactive Diagram", + "initialStateId": "overview", + "states": [ + { + "id": "overview", + "svgPath": "/diagrams/example/overview.svg", + "clickableAreas": [ + { + "id": "component-a", + "selector": "#component-a", + "nextStateId": "detail-a", + "tooltip": "Click to explore Component A" + }, + { + "id": "component-b", + "selector": "#component-b", + "nextStateId": "detail-b", + "tooltip": "Click to explore Component B" + } + ] + }, + { + "id": "detail-a", + "svgPath": "/diagrams/example/detail-a.svg", + "clickableAreas": [ + { + "id": "sub-component-1", + "selector": "#sub-1", + "nextStateId": "deep-dive-1", + "tooltip": "Dive deeper into Sub-component 1" + } + ] + }, + { + "id": "detail-b", + "svgPath": "/diagrams/example/detail-b.svg", + "clickableAreas": [] + }, + { + "id": "deep-dive-1", + "svgPath": "/diagrams/example/deep-dive-1.svg", + "clickableAreas": [] + } + ] +} \ No newline at end of file diff --git a/website/static/diagrams/example/deep-dive-1.svg b/website/static/diagrams/example/deep-dive-1.svg new file mode 100644 index 0000000000..adeed26f69 --- /dev/null +++ b/website/static/diagrams/example/deep-dive-1.svg @@ -0,0 +1,30 @@ + + + + Sub-component 1 Deep Dive + + + + Input + + + Process + + + Output + + + + + + + + Implementation Details + + • Uses advanced algorithms + • Optimized for performance + • Handles edge cases gracefully + • Fully tested and documented + + This is the deepest level of detail + \ No newline at end of file diff --git a/website/static/diagrams/example/detail-a.svg b/website/static/diagrams/example/detail-a.svg new file mode 100644 index 0000000000..e34cbfca84 --- /dev/null +++ b/website/static/diagrams/example/detail-a.svg @@ -0,0 +1,30 @@ + + + + Component A Details + + + + Component A + + + + + Sub-component 1 + + + + + Sub-component 2 + + + + Sub-component 3 + + + + + + + Click Sub-component 1 to dive deeper + \ No newline at end of file diff --git a/website/static/diagrams/example/detail-b.svg b/website/static/diagrams/example/detail-b.svg new file mode 100644 index 0000000000..6cbd81be38 --- /dev/null +++ b/website/static/diagrams/example/detail-b.svg @@ -0,0 +1,30 @@ + + + + Component B Details + + + + Component B + + + + Module 1 + + + Module 2 + + + Module 3 + + + Module 4 + + + + + + + + Component B has no further drill-down + \ No newline at end of file diff --git a/website/static/diagrams/example/overview.svg b/website/static/diagrams/example/overview.svg new file mode 100644 index 0000000000..c0c959ee9d --- /dev/null +++ b/website/static/diagrams/example/overview.svg @@ -0,0 +1,20 @@ + + + + + + + Component A + + + + + + Component B + + + + + + Click on components to explore details + \ No newline at end of file From 2358067297f75e9fe94038aa2f5b6a2478075d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Fri, 27 Jun 2025 17:19:28 -0700 Subject: [PATCH 2/7] add additional Lidia diagram features --- website/src/components/Lidia/LidiaDiagram.tsx | 19 ++++++++----------- .../components/Lidia/hooks/useLidiaState.ts | 10 +++++----- website/src/components/Lidia/index.tsx | 2 +- website/src/components/Lidia/types.ts | 2 +- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/website/src/components/Lidia/LidiaDiagram.tsx b/website/src/components/Lidia/LidiaDiagram.tsx index fd91255ab5..2218fdff08 100644 --- a/website/src/components/Lidia/LidiaDiagram.tsx +++ b/website/src/components/Lidia/LidiaDiagram.tsx @@ -17,18 +17,18 @@ export default function LidiaDiagram({ config }: LidiaDiagramProps) { try { const response = await fetch(currentState.svgPath); const svgText = await response.text(); - + svgContainerRef.current!.innerHTML = svgText; - + const svg = svgContainerRef.current!.querySelector('svg'); if (!svg) return; - currentState.clickableAreas.forEach(area => { + currentState.clickableAreas.forEach((area) => { const element = svg.querySelector(area.selector); if (!element) return; element.classList.add('lidia-clickable'); - + if (area.tooltip) { element.setAttribute('title', area.tooltip); } @@ -54,8 +54,8 @@ export default function LidiaDiagram({ config }: LidiaDiagramProps) {

{config.title}

{canGoBack && ( - )}
-
+
); -} \ No newline at end of file +} diff --git a/website/src/components/Lidia/hooks/useLidiaState.ts b/website/src/components/Lidia/hooks/useLidiaState.ts index ed98c6794b..6e237b42f4 100644 --- a/website/src/components/Lidia/hooks/useLidiaState.ts +++ b/website/src/components/Lidia/hooks/useLidiaState.ts @@ -8,16 +8,16 @@ export function useLidiaState(config: LidiaDiagramConfig) { }); const navigateToState = useCallback((stateId: string) => { - setState(prev => ({ + setState((prev) => ({ currentStateId: stateId, history: [...prev.history, stateId], })); }, []); const goBack = useCallback(() => { - setState(prev => { + setState((prev) => { if (prev.history.length <= 1) return prev; - + const newHistory = prev.history.slice(0, -1); return { currentStateId: newHistory[newHistory.length - 1], @@ -28,7 +28,7 @@ export function useLidiaState(config: LidiaDiagramConfig) { const canGoBack = state.history.length > 1; - const currentState = config.states.find(s => s.id === state.currentStateId); + const currentState = config.states.find((s) => s.id === state.currentStateId); return { currentState, @@ -36,4 +36,4 @@ export function useLidiaState(config: LidiaDiagramConfig) { goBack, canGoBack, }; -} \ No newline at end of file +} diff --git a/website/src/components/Lidia/index.tsx b/website/src/components/Lidia/index.tsx index fe6fc86583..de9490e319 100644 --- a/website/src/components/Lidia/index.tsx +++ b/website/src/components/Lidia/index.tsx @@ -1,2 +1,2 @@ export { default } from './LidiaDiagram'; -export type { LidiaDiagramConfig, DiagramState, ClickableArea } from './types'; \ No newline at end of file +export type { LidiaDiagramConfig, DiagramState, ClickableArea } from './types'; diff --git a/website/src/components/Lidia/types.ts b/website/src/components/Lidia/types.ts index 7a84e82c77..46986e9c0b 100644 --- a/website/src/components/Lidia/types.ts +++ b/website/src/components/Lidia/types.ts @@ -21,4 +21,4 @@ export interface LidiaDiagramConfig { export interface LidiaState { currentStateId: string; history: string[]; -} \ No newline at end of file +} From 6c54699353e76f557af3b090da9314136be658c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Fri, 27 Jun 2025 17:37:03 -0700 Subject: [PATCH 3/7] relocate lidia to /arbitrum-docs/for-devs/lidia-interactive-diagrams.mdx --- .../for-devs/lidia-interactive-diagrams.mdx | 69 +++++++++++++++++++ website/docs/test-lidia.mdx | 16 ----- website/sidebars.js | 17 ++--- 3 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 arbitrum-docs/for-devs/lidia-interactive-diagrams.mdx delete mode 100644 website/docs/test-lidia.mdx diff --git a/arbitrum-docs/for-devs/lidia-interactive-diagrams.mdx b/arbitrum-docs/for-devs/lidia-interactive-diagrams.mdx new file mode 100644 index 0000000000..45c7d75c74 --- /dev/null +++ b/arbitrum-docs/for-devs/lidia-interactive-diagrams.mdx @@ -0,0 +1,69 @@ +--- +title: Lidia Interactive Diagrams +description: Learn how to use Lidia, a React component for creating interactive, click-to-morph diagrams in your Arbitrum documentation +--- + +import LidiaDiagram from '@site/src/components/Lidia'; +import exampleConfig from '@site/static/diagrams/example/config.json'; + +# Lidia Interactive Diagrams + +Lidia is a React component that enables interactive, click-to-morph diagrams for exploring complex technical concepts. It's particularly useful for visualizing multi-layered architectures, workflows, and system components. + +## Example + + + +## How it works + +- **Click** on highlighted areas to explore deeper levels of detail +- **Navigate back** using the back button to return to previous states +- **Tooltips** appear on hover to guide your exploration + +## Using Lidia in your documentation + +To add interactive diagrams to your documentation: + +1. Create SVG diagrams with clickable areas (elements with unique IDs) +2. Define a configuration file mapping the navigation flow +3. Import and use the `LidiaDiagram` component in your MDX files + +### Example usage + +```mdx +import LidiaDiagram from '@site/src/components/Lidia'; +import myDiagramConfig from '@site/static/diagrams/my-diagram/config.json'; + + +``` + +### Configuration structure + +```json +{ + "id": "diagram-id", + "title": "Diagram Title", + "initialStateId": "overview", + "states": [ + { + "id": "overview", + "svgPath": "/diagrams/my-diagram/overview.svg", + "clickableAreas": [ + { + "id": "area-1", + "selector": "#svg-element-id", + "nextStateId": "detail-view", + "tooltip": "Click to explore" + } + ] + } + ] +} +``` + +## Best practices + +- Keep diagrams simple and focused on one concept per state +- Use clear, descriptive IDs for clickable areas +- Provide helpful tooltips to guide users +- Limit navigation depth to 3-5 levels for optimal user experience diff --git a/website/docs/test-lidia.mdx b/website/docs/test-lidia.mdx deleted file mode 100644 index b324d37dc1..0000000000 --- a/website/docs/test-lidia.mdx +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Lidia Test Page ---- - -import LidiaDiagram from '@site/src/components/Lidia'; -import exampleConfig from '@site/static/diagrams/example/config.json'; - -# Testing Lidia Interactive Diagrams - -This page demonstrates the Lidia interactive diagram component. - - - -## How it works - -Click on different parts of the diagram to explore more details. Use the back button to return to previous states. \ No newline at end of file diff --git a/website/sidebars.js b/website/sidebars.js index b7f6a40b58..c10d44eaff 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -27,6 +27,11 @@ const sidebars = { id: 'for-devs/dev-tools-and-resources/chain-info', label: 'Chain info', }, + { + type: 'doc', + label: 'Lidia Interactive Diagrams', + id: 'for-devs/lidia-interactive-diagrams', + }, ], }, { @@ -1208,18 +1213,6 @@ const sidebars = { label: 'Audit reports', id: 'audit-reports', }, - { - type: 'category', - label: 'Development Tools', - collapsed: true, - items: [ - { - type: 'doc', - id: 'test-lidia', - label: 'Lidia Interactive Diagrams', - }, - ], - }, { type: 'link', label: 'DAO docs', From 1cdd17941103922e63d7bd435684e9db7be31781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Fri, 27 Jun 2025 17:55:02 -0700 Subject: [PATCH 4/7] add smooth crossfade transition to Lidia diagram --- website/src/components/Lidia/LidiaDiagram.tsx | 85 +++++++++++++++++-- website/src/css/lidia.css | 34 +++++++- 2 files changed, 109 insertions(+), 10 deletions(-) diff --git a/website/src/components/Lidia/LidiaDiagram.tsx b/website/src/components/Lidia/LidiaDiagram.tsx index 2218fdff08..4dc1bef57f 100644 --- a/website/src/components/Lidia/LidiaDiagram.tsx +++ b/website/src/components/Lidia/LidiaDiagram.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState, useCallback } from 'react'; import type { LidiaDiagramConfig } from './types'; import { useLidiaState } from './hooks/useLidiaState'; @@ -8,21 +8,50 @@ interface LidiaDiagramProps { export default function LidiaDiagram({ config }: LidiaDiagramProps) { const { currentState, navigateToState, goBack, canGoBack } = useLidiaState(config); - const svgContainerRef = useRef(null); + const containerRef = useRef(null); + const [isTransitioning, setIsTransitioning] = useState(false); + const prevStateIdRef = useRef(null); + const transitioningRef = useRef(false); + + const handleNavigation = useCallback( + (nextStateId: string) => { + if (!transitioningRef.current) { + transitioningRef.current = true; + setIsTransitioning(true); + navigateToState(nextStateId); + } + }, + [navigateToState], + ); + + const handleBackClick = useCallback(() => { + if (!transitioningRef.current) { + transitioningRef.current = true; + setIsTransitioning(true); + goBack(); + } + }, [goBack]); useEffect(() => { - if (!currentState || !svgContainerRef.current) return; + if (!currentState || !containerRef.current) return; + + // Skip if we're still showing the same state + if (prevStateIdRef.current === currentState.id) return; const loadAndSetupSvg = async () => { try { const response = await fetch(currentState.svgPath); const svgText = await response.text(); - svgContainerRef.current!.innerHTML = svgText; + // Create a new div for the incoming SVG + const newSvgDiv = document.createElement('div'); + newSvgDiv.className = 'lidia-svg-wrapper'; + newSvgDiv.innerHTML = svgText; - const svg = svgContainerRef.current!.querySelector('svg'); + const svg = newSvgDiv.querySelector('svg'); if (!svg) return; + // Set up clickable areas currentState.clickableAreas.forEach((area) => { const element = svg.querySelector(area.selector); if (!element) return; @@ -34,16 +63,53 @@ export default function LidiaDiagram({ config }: LidiaDiagramProps) { } element.addEventListener('click', () => { - navigateToState(area.nextStateId); + handleNavigation(area.nextStateId); }); }); + + // Handle transition + const existingWrapper = containerRef.current.querySelector('.lidia-svg-wrapper'); + + if (existingWrapper && prevStateIdRef.current !== null) { + // Crossfade effect + newSvgDiv.classList.add('lidia-svg-wrapper-entering'); + containerRef.current.appendChild(newSvgDiv); + + // Force reflow + void newSvgDiv.offsetHeight; + + // Start transition + requestAnimationFrame(() => { + existingWrapper.classList.add('lidia-fade-out'); + newSvgDiv.classList.remove('lidia-svg-wrapper-entering'); + newSvgDiv.classList.add('lidia-fade-in'); + + // Clean up after transition + setTimeout(() => { + existingWrapper.remove(); + transitioningRef.current = false; + setIsTransitioning(false); + }, 600); + }); + } else { + // Initial load + if (existingWrapper) existingWrapper.remove(); + containerRef.current.appendChild(newSvgDiv); + transitioningRef.current = false; + setIsTransitioning(false); + } + + // Update the previous state reference + prevStateIdRef.current = currentState.id; } catch (error) { console.error('Error loading SVG:', error); + transitioningRef.current = false; + setIsTransitioning(false); } }; loadAndSetupSvg(); - }, [currentState, navigateToState]); + }, [currentState, handleNavigation]); if (!currentState) { return
Error: Invalid diagram state
; @@ -56,14 +122,15 @@ export default function LidiaDiagram({ config }: LidiaDiagramProps) { {canGoBack && ( )}
-
+
); } diff --git a/website/src/css/lidia.css b/website/src/css/lidia.css index 37e13def67..2a4cce00e3 100644 --- a/website/src/css/lidia.css +++ b/website/src/css/lidia.css @@ -33,19 +33,51 @@ opacity: 0.8; } +.lidia-back-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + .lidia-svg-container { overflow: auto; display: flex; justify-content: center; align-items: center; min-height: 400px; + position: relative; +} + +.lidia-svg-wrapper { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + transition: opacity 0.6s ease-in-out; } -.lidia-svg-container svg { +.lidia-svg-wrapper svg { max-width: 100%; height: auto; } +/* Crossfade animation classes */ +.lidia-svg-wrapper-entering { + opacity: 0; +} + +.lidia-svg-wrapper.lidia-fade-out { + opacity: 0; + position: absolute; + top: 0; + left: 0; + right: 0; + pointer-events: none; +} + +.lidia-svg-wrapper.lidia-fade-in { + opacity: 1; +} + .lidia-clickable { cursor: pointer; transition: opacity 0.2s; From 71a614d230abf6bd3f40692722f7882a7c9d7799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Mon, 30 Jun 2025 18:02:53 -0700 Subject: [PATCH 5/7] add lidiaflow files --- .../lidia-flow-interactive-diagrams.mdx | 133 ++++++++++++ website/package.json | 1 + .../components/LidiaFlow/ClickableNode.tsx | 25 +++ .../components/LidiaFlow/LidiaFlowDiagram.tsx | 121 +++++++++++ .../LidiaFlow/hooks/useLidiaFlowState.ts | 44 ++++ website/src/components/LidiaFlow/index.tsx | 2 + website/src/components/LidiaFlow/types.ts | 33 +++ website/src/css/lidia-flow.css | 152 ++++++++++++++ .../diagrams/lidia-flow-example/config.json | 189 ++++++++++++++++++ website/yarn.lock | 90 +++++++-- 10 files changed, 778 insertions(+), 12 deletions(-) create mode 100644 arbitrum-docs/for-devs/lidia-flow-interactive-diagrams.mdx create mode 100644 website/src/components/LidiaFlow/ClickableNode.tsx create mode 100644 website/src/components/LidiaFlow/LidiaFlowDiagram.tsx create mode 100644 website/src/components/LidiaFlow/hooks/useLidiaFlowState.ts create mode 100644 website/src/components/LidiaFlow/index.tsx create mode 100644 website/src/components/LidiaFlow/types.ts create mode 100644 website/src/css/lidia-flow.css create mode 100644 website/static/diagrams/lidia-flow-example/config.json diff --git a/arbitrum-docs/for-devs/lidia-flow-interactive-diagrams.mdx b/arbitrum-docs/for-devs/lidia-flow-interactive-diagrams.mdx new file mode 100644 index 0000000000..9cd263e0f5 --- /dev/null +++ b/arbitrum-docs/for-devs/lidia-flow-interactive-diagrams.mdx @@ -0,0 +1,133 @@ +--- +title: LidiaFlow Interactive Diagrams +description: Learn how to use LidiaFlow, a ReactFlow-based component for creating interactive, click-to-explore diagrams in your Arbitrum documentation +--- + +import LidiaFlowDiagram from '@site/src/components/LidiaFlow'; +import exampleConfig from '@site/static/diagrams/lidia-flow-example/config.json'; + +# LidiaFlow Interactive Diagrams + +LidiaFlow is a ReactFlow-based component that enables interactive, click-to-morph diagrams for exploring complex technical concepts. Built on top of ReactFlow, it provides a more powerful and flexible alternative to traditional SVG-based diagrams while maintaining the simplicity of click-to-explore navigation. + +## Example + + + +## How it works + +- **Click** on nodes with blue highlights to explore deeper levels of detail +- **Navigate back** using the back button to return to previous states +- **Tooltips** appear on hover to guide your exploration +- **Mini-map** in the corner helps you navigate complex diagrams +- **Zoom and pan** to explore large diagrams with ease + +## Using LidiaFlow in your documentation + +To add interactive diagrams to your documentation: + +1. Define a configuration file with nodes, edges, and navigation flow +2. Import and use the `LidiaFlowDiagram` component in your MDX files + +### Example usage + +```mdx +import LidiaFlowDiagram from '@site/src/components/LidiaFlow'; +import myDiagramConfig from '@site/static/diagrams/my-diagram/config.json'; + + +``` + +### Configuration structure + +```json +{ + "id": "diagram-id", + "title": "Diagram Title", + "initialStateId": "overview", + "states": [ + { + "id": "overview", + "nodes": [ + { + "id": "1", + "type": "clickable", + "position": { "x": 250, "y": 0 }, + "data": { + "label": "Component Name", + "isClickable": true, + "tooltip": "Click to explore this component" + } + } + ], + "edges": [ + { + "id": "e1-2", + "source": "1", + "target": "2", + "animated": true + } + ], + "clickableAreas": [ + { + "nodeId": "1", + "nextStateId": "detail-view" + } + ] + } + ] +} +``` + +## Configuration Reference + +### Top-level configuration + +- `id`: Unique identifier for the diagram +- `title`: Title displayed in the diagram header +- `initialStateId`: ID of the state to show first +- `states`: Array of diagram states + +### State configuration + +- `id`: Unique identifier for the state +- `nodes`: Array of ReactFlow nodes +- `edges`: Array of ReactFlow edges +- `clickableAreas`: Array defining which nodes navigate to which states + +### Node configuration + +- `id`: Unique node identifier +- `type`: Node type (use `"clickable"` for interactive nodes) +- `position`: `{ x, y }` coordinates +- `data`: Node data including: + - `label`: Text displayed in the node + - `isClickable`: Whether the node can be clicked + - `tooltip`: Hover text for guidance + +### Edge configuration + +- `id`: Unique edge identifier +- `source`: Source node ID +- `target`: Target node ID +- `animated`: Optional boolean for animated edges + +## Best practices + +- Keep diagrams simple and focused on one concept per state +- Use clear, descriptive labels for nodes +- Provide helpful tooltips to guide users +- Limit navigation depth to 3-5 levels for optimal user experience +- Use the mini-map for complex diagrams with many nodes +- Consider using animated edges to show data flow + +## Advanced features + +LidiaFlow leverages ReactFlow's powerful features: + +- **Mini-map navigation** for large diagrams +- **Zoom controls** for detailed exploration +- **Smooth transitions** between states +- **Custom node types** (extend with your own components) +- **Keyboard navigation** support +- **Touch device** compatibility diff --git a/website/package.json b/website/package.json index 623b584476..64a6b7d32c 100644 --- a/website/package.json +++ b/website/package.json @@ -42,6 +42,7 @@ "@types/mdx": "^2.0.11", "@types/prismjs": "^1.26.5", "@types/react-syntax-highlighter": "^15.5.13", + "@xyflow/react": "^12.8.1", "classnames": "^2.5.1", "clsx": "^1.2.1", "docusaurus-lunr-search": "^3.3.2", diff --git a/website/src/components/LidiaFlow/ClickableNode.tsx b/website/src/components/LidiaFlow/ClickableNode.tsx new file mode 100644 index 0000000000..29bd7fc1c0 --- /dev/null +++ b/website/src/components/LidiaFlow/ClickableNode.tsx @@ -0,0 +1,25 @@ +import React, { memo } from 'react'; +import { Handle, Position, NodeProps } from '@xyflow/react'; +import type { ClickableNodeData } from './types'; + +const ClickableNode = memo(({ data, selected }: NodeProps) => { + return ( +
+ +
+
{data.label}
+ {data.isClickable &&
Click to explore
} +
+ +
+ ); +}); + +ClickableNode.displayName = 'ClickableNode'; + +export default ClickableNode; diff --git a/website/src/components/LidiaFlow/LidiaFlowDiagram.tsx b/website/src/components/LidiaFlow/LidiaFlowDiagram.tsx new file mode 100644 index 0000000000..958c9a2cb4 --- /dev/null +++ b/website/src/components/LidiaFlow/LidiaFlowDiagram.tsx @@ -0,0 +1,121 @@ +import React, { useCallback, useState, useEffect } from 'react'; +import ReactFlow, { + Background, + Controls, + MiniMap, + useNodesState, + useEdgesState, + Node, + NodeMouseHandler, + ReactFlowProvider, +} from '@xyflow/react'; +import '@xyflow/react/dist/style.css'; +import '../../css/lidia-flow.css'; + +import { useLidiaFlowState } from './hooks/useLidiaFlowState'; +import ClickableNode from './ClickableNode'; +import type { LidiaFlowConfig } from './types'; + +const nodeTypes = { + clickable: ClickableNode, +}; + +interface LidiaFlowDiagramProps { + config: LidiaFlowConfig; +} + +function LidiaFlowDiagramInner({ config }: LidiaFlowDiagramProps) { + const { currentState, navigateToState, goBack, canGoBack } = useLidiaFlowState(config); + const [nodes, setNodes, onNodesChange] = useNodesState([]); + const [edges, setEdges, onEdgesChange] = useEdgesState([]); + const [isTransitioning, setIsTransitioning] = useState(false); + + // Update nodes and edges when state changes + useEffect(() => { + if (currentState) { + setNodes(currentState.nodes); + setEdges(currentState.edges); + } + }, [currentState, setNodes, setEdges]); + + const onNodeClick: NodeMouseHandler = useCallback( + (event, node) => { + if (isTransitioning) return; + + const clickableArea = currentState?.clickableAreas.find((area) => area.nodeId === node.id); + + if (clickableArea && clickableArea.nextStateId) { + setIsTransitioning(true); + setTimeout(() => { + navigateToState(clickableArea.nextStateId); + setIsTransitioning(false); + }, 300); + } + }, + [currentState, navigateToState, isTransitioning], + ); + + const handleBackClick = useCallback(() => { + if (!isTransitioning && canGoBack) { + setIsTransitioning(true); + setTimeout(() => { + goBack(); + setIsTransitioning(false); + }, 300); + } + }, [goBack, canGoBack, isTransitioning]); + + if (!currentState) { + return
Error: Invalid diagram state
; + } + + return ( +
+
+

{config.title}

+ {canGoBack && ( + + )} +
+
+ + + + { + const clickableArea = currentState.clickableAreas.find( + (area) => area.nodeId === node.id, + ); + return clickableArea ? '#3b82f6' : '#9ca3af'; + }} + /> + +
+
+ ); +} + +export default function LidiaFlowDiagram(props: LidiaFlowDiagramProps) { + return ( + + + + ); +} diff --git a/website/src/components/LidiaFlow/hooks/useLidiaFlowState.ts b/website/src/components/LidiaFlow/hooks/useLidiaFlowState.ts new file mode 100644 index 0000000000..7948bdd42a --- /dev/null +++ b/website/src/components/LidiaFlow/hooks/useLidiaFlowState.ts @@ -0,0 +1,44 @@ +import { useState, useCallback, useMemo } from 'react'; +import type { LidiaFlowConfig, LidiaFlowState } from '../types'; + +export function useLidiaFlowState(config: LidiaFlowConfig) { + const [state, setState] = useState({ + currentStateId: config.initialStateId, + history: [], + }); + + const currentState = useMemo( + () => config.states.find((s) => s.id === state.currentStateId), + [config.states, state.currentStateId], + ); + + const navigateToState = useCallback((stateId: string) => { + setState((prev) => ({ + currentStateId: stateId, + history: [...prev.history, prev.currentStateId], + })); + }, []); + + const goBack = useCallback(() => { + setState((prev) => { + if (prev.history.length === 0) return prev; + + const newHistory = [...prev.history]; + const previousStateId = newHistory.pop()!; + + return { + currentStateId: previousStateId, + history: newHistory, + }; + }); + }, []); + + const canGoBack = state.history.length > 0; + + return { + currentState, + navigateToState, + goBack, + canGoBack, + }; +} diff --git a/website/src/components/LidiaFlow/index.tsx b/website/src/components/LidiaFlow/index.tsx new file mode 100644 index 0000000000..fff17a1d1a --- /dev/null +++ b/website/src/components/LidiaFlow/index.tsx @@ -0,0 +1,2 @@ +export { default } from './LidiaFlowDiagram'; +export type { LidiaFlowConfig, DiagramState, ClickableArea } from './types'; diff --git a/website/src/components/LidiaFlow/types.ts b/website/src/components/LidiaFlow/types.ts new file mode 100644 index 0000000000..b7a7bd3762 --- /dev/null +++ b/website/src/components/LidiaFlow/types.ts @@ -0,0 +1,33 @@ +import type { Node, Edge } from '@xyflow/react'; + +export interface ClickableArea { + nodeId: string; + nextStateId: string; + tooltip?: string; +} + +export interface DiagramState { + id: string; + nodes: Node[]; + edges: Edge[]; + clickableAreas: ClickableArea[]; +} + +export interface LidiaFlowConfig { + id: string; + title: string; + states: DiagramState[]; + initialStateId: string; +} + +export interface LidiaFlowState { + currentStateId: string; + history: string[]; +} + +export interface ClickableNodeData { + label: string; + tooltip?: string; + isClickable: boolean; + nextStateId?: string; +} diff --git a/website/src/css/lidia-flow.css b/website/src/css/lidia-flow.css new file mode 100644 index 0000000000..625aaebadb --- /dev/null +++ b/website/src/css/lidia-flow.css @@ -0,0 +1,152 @@ +/* Lidia Flow Container */ +.lidia-flow-container { + width: 100%; + height: 600px; + border: 1px solid #e5e7eb; + border-radius: 8px; + overflow: hidden; + background-color: #ffffff; +} + +/* Header */ +.lidia-flow-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px 24px; + background-color: #f9fafb; + border-bottom: 1px solid #e5e7eb; +} + +.lidia-flow-title { + font-size: 18px; + font-weight: 600; + color: #1f2937; + margin: 0; +} + +.lidia-flow-back-button { + padding: 8px 16px; + background-color: #3b82f6; + color: white; + border: none; + border-radius: 6px; + font-size: 14px; + cursor: pointer; + transition: all 0.2s ease; +} + +.lidia-flow-back-button:hover { + background-color: #2563eb; +} + +.lidia-flow-back-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* ReactFlow wrapper */ +.lidia-flow-wrapper { + height: calc(100% - 65px); + position: relative; + background-color: #fafafa; +} + +/* Transition effects */ +.lidia-flow-fade-enter { + opacity: 0; + transform: scale(0.95); +} + +.lidia-flow-fade-enter-active { + opacity: 1; + transform: scale(1); + transition: opacity 300ms ease-in-out, transform 300ms ease-in-out; +} + +.lidia-flow-fade-exit { + opacity: 1; + transform: scale(1); +} + +.lidia-flow-fade-exit-active { + opacity: 0; + transform: scale(0.95); + transition: opacity 300ms ease-in-out, transform 300ms ease-in-out; +} + +/* Custom Node Styles */ +.lidia-flow-node { + background: white; + border: 2px solid #e5e7eb; + border-radius: 8px; + padding: 16px 24px; + min-width: 150px; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); + transition: all 0.2s ease; +} + +.lidia-flow-node-clickable { + cursor: pointer; +} + +.lidia-flow-node-clickable:hover { + border-color: #3b82f6; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); + transform: translateY(-2px); +} + +.lidia-flow-node-selected { + border-color: #3b82f6; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +.lidia-flow-node-content { + text-align: center; +} + +.lidia-flow-node-label { + font-size: 16px; + font-weight: 600; + color: #1f2937; + margin-bottom: 4px; +} + +.lidia-flow-node-hint { + font-size: 12px; + color: #3b82f6; + margin-top: 8px; +} + +/* Handle styles */ +.lidia-flow-handle { + width: 8px; + height: 8px; + background-color: #3b82f6; + border: 2px solid white; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); +} + +/* ReactFlow overrides */ +.react-flow__node.selected .lidia-flow-node { + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +.react-flow__edge-path { + stroke: #9ca3af; + stroke-width: 2; +} + +.react-flow__edge.selected .react-flow__edge-path { + stroke: #3b82f6; +} + +/* Error state */ +.lidia-flow-error { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + color: #ef4444; + font-size: 16px; +} \ No newline at end of file diff --git a/website/static/diagrams/lidia-flow-example/config.json b/website/static/diagrams/lidia-flow-example/config.json new file mode 100644 index 0000000000..695b98b725 --- /dev/null +++ b/website/static/diagrams/lidia-flow-example/config.json @@ -0,0 +1,189 @@ +{ + "id": "arbitrum-architecture", + "title": "Arbitrum Architecture Overview", + "initialStateId": "overview", + "states": [ + { + "id": "overview", + "nodes": [ + { + "id": "1", + "type": "clickable", + "position": { "x": 250, "y": 0 }, + "data": { + "label": "Sequencer", + "isClickable": true, + "tooltip": "Click to explore the Sequencer components" + } + }, + { + "id": "2", + "type": "clickable", + "position": { "x": 100, "y": 150 }, + "data": { + "label": "L1 Contracts", + "isClickable": true, + "tooltip": "Click to explore L1 Contracts" + } + }, + { + "id": "3", + "type": "clickable", + "position": { "x": 400, "y": 150 }, + "data": { + "label": "Validators", + "isClickable": true, + "tooltip": "Click to explore Validator network" + } + }, + { + "id": "4", + "position": { "x": 250, "y": 300 }, + "data": { + "label": "User Transactions", + "isClickable": false + } + } + ], + "edges": [ + { "id": "e1-2", "source": "1", "target": "2", "animated": true }, + { "id": "e1-3", "source": "1", "target": "3", "animated": true }, + { "id": "e4-1", "source": "4", "target": "1" } + ], + "clickableAreas": [ + { "nodeId": "1", "nextStateId": "sequencer-detail" }, + { "nodeId": "2", "nextStateId": "l1-contracts-detail" }, + { "nodeId": "3", "nextStateId": "validators-detail" } + ] + }, + { + "id": "sequencer-detail", + "nodes": [ + { + "id": "s1", + "position": { "x": 250, "y": 0 }, + "data": { + "label": "Transaction Pool", + "isClickable": false + } + }, + { + "id": "s2", + "position": { "x": 250, "y": 100 }, + "data": { + "label": "Batch Creator", + "isClickable": false + } + }, + { + "id": "s3", + "position": { "x": 250, "y": 200 }, + "data": { + "label": "State Manager", + "isClickable": false + } + }, + { + "id": "s4", + "position": { "x": 250, "y": 300 }, + "data": { + "label": "L1 Publisher", + "isClickable": false + } + } + ], + "edges": [ + { "id": "es1-2", "source": "s1", "target": "s2" }, + { "id": "es2-3", "source": "s2", "target": "s3" }, + { "id": "es3-4", "source": "s3", "target": "s4" } + ], + "clickableAreas": [] + }, + { + "id": "l1-contracts-detail", + "nodes": [ + { + "id": "l1", + "position": { "x": 250, "y": 0 }, + "data": { + "label": "Rollup Contract", + "isClickable": false + } + }, + { + "id": "l2", + "position": { "x": 100, "y": 150 }, + "data": { + "label": "Inbox", + "isClickable": false + } + }, + { + "id": "l3", + "position": { "x": 400, "y": 150 }, + "data": { + "label": "Outbox", + "isClickable": false + } + }, + { + "id": "l4", + "position": { "x": 250, "y": 300 }, + "data": { + "label": "Challenge Manager", + "isClickable": false + } + } + ], + "edges": [ + { "id": "el1-2", "source": "l1", "target": "l2" }, + { "id": "el1-3", "source": "l1", "target": "l3" }, + { "id": "el1-4", "source": "l1", "target": "l4" } + ], + "clickableAreas": [] + }, + { + "id": "validators-detail", + "nodes": [ + { + "id": "v1", + "position": { "x": 250, "y": 0 }, + "data": { + "label": "Validator Node", + "isClickable": false + } + }, + { + "id": "v2", + "position": { "x": 100, "y": 150 }, + "data": { + "label": "State Sync", + "isClickable": false + } + }, + { + "id": "v3", + "position": { "x": 400, "y": 150 }, + "data": { + "label": "Fraud Proofs", + "isClickable": false + } + }, + { + "id": "v4", + "position": { "x": 250, "y": 300 }, + "data": { + "label": "Staking Module", + "isClickable": false + } + } + ], + "edges": [ + { "id": "ev1-2", "source": "v1", "target": "v2" }, + { "id": "ev1-3", "source": "v1", "target": "v3" }, + { "id": "ev1-4", "source": "v1", "target": "v4" } + ], + "clickableAreas": [] + } + ] +} \ No newline at end of file diff --git a/website/yarn.lock b/website/yarn.lock index 03be34a625..db580d916c 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -4532,7 +4532,7 @@ resolved "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.6.tgz" integrity sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ== -"@types/d3-drag@*": +"@types/d3-drag@*", "@types/d3-drag@^3.0.7": version "3.0.7" resolved "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz" integrity sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ== @@ -4578,7 +4578,7 @@ resolved "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz" integrity sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg== -"@types/d3-interpolate@*": +"@types/d3-interpolate@*", "@types/d3-interpolate@^3.0.4": version "3.0.4" resolved "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz" integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== @@ -4617,7 +4617,7 @@ dependencies: "@types/d3-time" "*" -"@types/d3-selection@*": +"@types/d3-selection@*", "@types/d3-selection@^3.0.10": version "3.0.11" resolved "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz" integrity sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w== @@ -4644,14 +4644,14 @@ resolved "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz" integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== -"@types/d3-transition@*": +"@types/d3-transition@*", "@types/d3-transition@^3.0.8": version "3.0.9" resolved "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz" integrity sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg== dependencies: "@types/d3-selection" "*" -"@types/d3-zoom@*": +"@types/d3-zoom@*", "@types/d3-zoom@^3.0.8": version "3.0.8" resolved "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz" integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw== @@ -5391,6 +5391,30 @@ resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +"@xyflow/react@^12.8.1": + version "12.8.1" + resolved "https://registry.yarnpkg.com/@xyflow/react/-/react-12.8.1.tgz#bf16e34bd9592fa4200d002d408329ee97aa0714" + integrity sha512-t5Rame4Gc/540VcOZd28yFe9Xd8lyjKUX+VTiyb1x4ykNXZH5zyDmsu+lj9je2O/jGBVb0pj1Vjcxrxyn+Xk2g== + dependencies: + "@xyflow/system" "0.0.65" + classcat "^5.0.3" + zustand "^4.4.0" + +"@xyflow/system@0.0.65": + version "0.0.65" + resolved "https://registry.yarnpkg.com/@xyflow/system/-/system-0.0.65.tgz#1824cb81369e389c34d02297bd1d871f0932004b" + integrity sha512-AliQPQeurQMoNlOdySnRoDQl9yDSA/1Lqi47Eo0m98lHcfrTdD9jK75H0tiGj+0qRC10SKNUXyMkT0KL0opg4g== + dependencies: + "@types/d3-drag" "^3.0.7" + "@types/d3-interpolate" "^3.0.4" + "@types/d3-selection" "^3.0.10" + "@types/d3-transition" "^3.0.8" + "@types/d3-zoom" "^3.0.8" + d3-drag "^3.0.0" + d3-interpolate "^3.0.1" + d3-selection "^3.0.0" + d3-zoom "^3.0.0" + abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" @@ -6158,6 +6182,11 @@ ci-info@^3.2.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== +classcat@^5.0.3: + version "5.0.5" + resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.5.tgz#8c209f359a93ac302404a10161b501eba9c09c77" + integrity sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w== + classnames@^2.5.1: version "2.5.1" resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz" @@ -6792,7 +6821,7 @@ d3-delaunay@6: resolved "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz" integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== -"d3-drag@2 - 3", d3-drag@3: +"d3-drag@2 - 3", d3-drag@3, d3-drag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz" integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== @@ -6847,7 +6876,7 @@ d3-hierarchy@3: resolved "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz" integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== -"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3: +"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@3, d3-interpolate@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz" integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== @@ -6906,7 +6935,7 @@ d3-scale@4: d3-time "2.1.1 - 3" d3-time-format "2 - 4" -"d3-selection@2 - 3", d3-selection@3: +"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz" integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== @@ -6955,7 +6984,7 @@ d3-shape@^1.2.0: d3-interpolate "1 - 3" d3-timer "1 - 3" -d3-zoom@3: +d3-zoom@3, d3-zoom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz" integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== @@ -12909,7 +12938,16 @@ std-env@^3.8.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.9.0.tgz#1a6f7243b339dca4c9fd55e1c7504c77ef23e8f1" integrity sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12958,7 +12996,14 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13616,6 +13661,11 @@ use-sidecar@^1.1.3: detect-node-es "^1.1.0" tslib "^2.0.0" +use-sync-external-store@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz#55122e2a3edd2a6c106174c27485e0fd59bcfca0" + integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A== + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" @@ -14056,7 +14106,16 @@ wildcard@^2.0.0, wildcard@^2.0.1: resolved "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -14146,6 +14205,13 @@ yocto-queue@^1.0.0: resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== +zustand@^4.4.0: + version "4.5.7" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.7.tgz#7d6bb2026a142415dd8be8891d7870e6dbe65f55" + integrity sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw== + dependencies: + use-sync-external-store "^1.2.2" + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz" From 1ad238770c228b648de5e83f2f0cd13aecf74e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Mon, 30 Jun 2025 18:04:46 -0700 Subject: [PATCH 6/7] add liliaflow demo to the sidebar --- website/sidebars.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/sidebars.js b/website/sidebars.js index c10d44eaff..6e9876d562 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -32,6 +32,11 @@ const sidebars = { label: 'Lidia Interactive Diagrams', id: 'for-devs/lidia-interactive-diagrams', }, + { + type: 'doc', + label: 'LidiaFlow Interactive Diagrams', + id: 'for-devs/lidia-flow-interactive-diagrams', + }, ], }, { From 425feb29b6b06eec7f843ad747311d98899ed606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Blanchemain?= Date: Mon, 30 Jun 2025 18:12:44 -0700 Subject: [PATCH 7/7] fix import --- website/src/components/LidiaFlow/LidiaFlowDiagram.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/src/components/LidiaFlow/LidiaFlowDiagram.tsx b/website/src/components/LidiaFlow/LidiaFlowDiagram.tsx index 958c9a2cb4..f60c27a59b 100644 --- a/website/src/components/LidiaFlow/LidiaFlowDiagram.tsx +++ b/website/src/components/LidiaFlow/LidiaFlowDiagram.tsx @@ -1,14 +1,14 @@ import React, { useCallback, useState, useEffect } from 'react'; -import ReactFlow, { +import { + ReactFlow, Background, Controls, MiniMap, useNodesState, useEdgesState, - Node, - NodeMouseHandler, ReactFlowProvider, } from '@xyflow/react'; +import type { Node, NodeMouseHandler } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; import '../../css/lidia-flow.css';