Skip to content

Walkthrough

Zhaoyi Shi edited this page Jul 20, 2025 · 1 revision

title: Walkthrough

🧭 Walkthrough System Wiki

📌 Small Intro

The walkthrough system provides guided, step-by-step tours for major pages in the graph algorithm visualizer. It uses react-joyride to guide users through features with visual highlights and tooltips.


🧱 Basic Structure

Each walkthrough is defined in its own React component under src\components\walkthrough, colocated with the page it describes:

Page Walkthrough Component
Home Page HomePageWalkthrough.tsx
Graph Selection Page GraphSelectPageWalkthrough.tsx
Graph Execution Page GraphPageWalkthrough.tsx
Algorithm Visualization Page AlgorithmPageWalkthrough.tsx

Global walkthrough state is managed via Zustand (src\stores\walkthrough-store.ts) and coordinated via src\hooks\WalkthroughController.ts.

✍️ How to Write a Walkthrough File

Each walkthrough is self-contained and affects only the page that imports it. Components remain decoupled and reusable.

1. Create the Walkthrough File

Create a new file (e.g., MyPageWalkthrough.tsx) and define the walkthrough steps using react-joyride:

const steps: Step[] = [
  {
    target: ".joyride-feature-button",
    content: <div>This button does XYZ. Try clicking it!</div>,
  },
  {
    target: "body",
    placement: "center",
    content: <div>🎉 All done!</div>,
  },
];

2. Render the Walkthrough Conditionally

Use the Zustand store to control the walkthrough state:

const MyPageWalkthrough: React.FC = () => {
  const { run, stepIndex, visible } = useWalkthroughStore((s) => s.walkthroughs.myPageKey);

  return (
    <>
      {visible && (
        <Joyride
          steps={steps}
          stepIndex={stepIndex}
          run={run}
          continuous
          callback={(data) => handleWalkthroughCallback("myPageKey", data)}
          ...
        />
      )}
    </>
  );
};

3. Pass Target Class Names into Components

To avoid hardcoding walkthrough-specific class names inside components, pass them as props from the page level.

✅ Example in AlgorithmPage.tsx:

<GraphSplitView
  ...
  classNameGraphCard="graph-card"
  classNameDownloadGraph="download-graph"
  classNameHelpText="help-text"
/>
<CodeViewer
  ...
  classNameController="controller"
  classNameViewVariables="view-variables"
/>

🔁 In your walkthrough steps:

{
  target: ".download-graph",
  content: <div>💾 Use this to download your graph!</div>
}

This ensures components stay reusable and unaffected by walkthrough logic.

4. Use a Consistent Walkthrough Key

  • Add the key to WalkthroughKey in walkthrough-store.ts
  • Initialize it in defaultEntries
  • Use that key in your walkthrough component and in handleWalkthroughCallback

🔁 How to Add It into the Control Logic

  1. Add the Key in Zustand Store

Update WalkthroughKey and defaultEntries in walkthrough-store.ts:

export type WalkthroughKey = "home" | "graphSelect" | "graph" | "algorithm" | "myPageKey";
  1. How Walkthrough Controller controls the Joyride Callback

Each Joyride component defines a callback prop that listens to lifecycle events emitted by react-joyride. These include step changes, user actions (next, back, skip), and tour completion.

We use a shared handler:

callback={(data) => handleWalkthroughCallback("myPageKey", data)}

The handleWalkthroughCallback function (in WalkthroughController.ts) receives the data object the joyride sends when user advance or go back and uses Zustand methods to:

  • Advance to the next step with goToStep
  • Stop the current walkthrough using stopWalkthrough
  • Automatically start the next walkthrough in sequence using startWalkthrough

The data object passed to the callback includes fields like:

{
  index: number;
  action: "next" | "prev" | "close" | "skip";
  lifecycle: "init" | "complete" | ...;
  status: "finished" | "skipped" | ...;
  type: "step:after" | "tour:end" | ...;
}

One thing to be noticed, every walkthrough step emits more than one data object. And we normally only listen to the one with lifecycle:"complete".

You can use this data to customize step behavior, transition timing, or conditionally trigger external logic during the tour.

  1. Link it in Controller if Needed

If it should automatically transition after the previous page, update nextMap in WalkthroughController.ts:

const nextMap: Record<WalkthroughKey, WalkthroughKey | null> = {
  home: "graphSelect",
  graphSelect: "graph",
  graph: "algorithm",
  algorithm: null,
};
  1. Trigger the Walkthrough

Use startWalkthrough("myPageKey") to begin the tour when appropriate.


🐞 What is the Glitch Problem and How to Fix It

The Problem

The website pages are based on React.animatedroutes, which gives a fading animation whenever navigating to another page. But the DOM element that walkthrough are tied to doesn't fade like others, which cause the "glitch" problem.

The Fix

To avoid this, use the useSafeNavigate hook (defined in src\utils\safe-navigate.ts), which wraps React Router's useNavigate:

const navigate = useSafeNavigate();
navigate("/some-page");

This hook ensures that all walkthroughs are temporarily hidden before navigation and restored after the target page has mounted, using the pauseWalkthroughs function from the Zustand store.

Internally, it wraps navigation like this:

store.pauseWalkthroughs(() => navigate(to, options));

You should use useSafeNavigate as a drop-in replacement for useNavigate anywhere navigation might occur during or after a walkthrough.

Clone this wiki locally