diff --git a/react-compiler.config.js b/react-compiler.config.js
index 8cbb25164..eade54013 100644
--- a/react-compiler.config.js
+++ b/react-compiler.config.js
@@ -6,6 +6,7 @@ export const REACT_COMPILER_ENABLED_DIRS = [
"src/components/Home",
"src/components/Editor",
"src/components/Learn",
+ "src/components/Onboarding",
// 0 useCallback/useMemo - ready to enable
"src/components/layout",
@@ -72,6 +73,7 @@ export const REACT_COMPILER_ENABLED_DIRS = [
"src/providers/DialogProvider",
"src/providers/TourProvider",
+ "src/providers/OnboardingProvider",
"src/routes/EditorV2",
// 11-20 useCallback/useMemo
diff --git a/src/components/Learn/LearnSearchBar.tsx b/src/components/Learn/LearnSearchBar.tsx
index 5937832a4..18c6f4f34 100644
--- a/src/components/Learn/LearnSearchBar.tsx
+++ b/src/components/Learn/LearnSearchBar.tsx
@@ -4,16 +4,19 @@ import { Icon } from "@/components/ui/icon";
import { Input, InputGroup } from "@/components/ui/input";
import { Text } from "@/components/ui/typography";
import { useAnalytics } from "@/providers/AnalyticsProvider";
+import { useOnboarding } from "@/providers/OnboardingProvider/OnboardingProvider";
import { TANGLE_WEBSITE_URL } from "@/utils/constants";
export function LearnSearchBar() {
const [value, setValue] = useState("");
const { track } = useAnalytics();
+ const { markDocsRead } = useOnboarding();
const handleSubmit = () => {
const query = value.trim();
if (!query) return;
track("learning_hub.search.submitted");
+ markDocsRead();
const url = `${TANGLE_WEBSITE_URL}search/?q=${encodeURIComponent(query)}`;
window.open(url, "_blank", "noopener,noreferrer");
};
diff --git a/src/components/Learn/OnboardingHero.tsx b/src/components/Learn/OnboardingHero.tsx
index c9b5f12d2..9552b8617 100644
--- a/src/components/Learn/OnboardingHero.tsx
+++ b/src/components/Learn/OnboardingHero.tsx
@@ -1,116 +1,92 @@
-import { Link } from "@tanstack/react-router";
-
+import { OnboardingChecklist } from "@/components/Onboarding/OnboardingChecklist";
import { Button } from "@/components/ui/button";
import { Icon } from "@/components/ui/icon";
import { BlockStack, InlineStack } from "@/components/ui/layout";
-import { Heading, Paragraph, Text } from "@/components/ui/typography";
+import { Heading, Paragraph } from "@/components/ui/typography";
import { cn } from "@/lib/utils";
-import { tracking } from "@/utils/tracking";
+import { useOnboarding } from "@/providers/OnboardingProvider/OnboardingProvider";
-interface OnboardingStep {
- id: string;
- label: string;
- completed: boolean;
+function scrollNearestScrollableToTop(el: HTMLElement | null) {
+ let node = el?.parentElement ?? null;
+ while (node) {
+ const { overflowY } = getComputedStyle(node);
+ if (
+ (overflowY === "auto" || overflowY === "scroll") &&
+ node.scrollHeight > node.clientHeight
+ ) {
+ node.scrollTo({ top: 0, behavior: "smooth" });
+ return;
+ }
+ node = node.parentElement;
+ }
+ window.scrollTo({ top: 0, behavior: "smooth" });
}
-const STUB_STEPS: OnboardingStep[] = [
- { id: "configure-backend", label: "Connect a backend", completed: true },
- { id: "import-sample", label: "Import a sample pipeline", completed: true },
- { id: "run-pipeline", label: "Run your first pipeline", completed: false },
- { id: "edit-component", label: "Edit a component", completed: false },
- {
- id: "create-pipeline",
- label: "Build a pipeline from scratch",
- completed: false,
- },
-];
+export function OnboardingHero({ className }: { className?: string }) {
+ const { isComplete, dismissed, dismiss, reopen } = useOnboarding();
-export function OnboardingHero() {
- const completed = STUB_STEPS.filter((s) => s.completed).length;
- const total = STUB_STEPS.length;
- const isComplete = completed === total;
- const nextStep = STUB_STEPS.find((s) => !s.completed);
+ if (dismissed) {
+ return (
+