import { useTutorial } from "$lib/TutorialProvider"; import { Button } from "$ui/Button"; import type { Component } from "solid-js"; import { createEffect, createMemo, createSignal, Index, onCleanup, Show } from "solid-js"; import { Motion, Presence } from "solid-motionone"; type Position = { top: number; left: number; width: number; height: number }; const getTooltipPosition = (target: Position, placement: "top" | "bottom" | "left" | "right") => { const padding = 12; const tooltipWidth = 320; switch (placement) { case "top": { const tooltipHeight = 240; return { top: target.top - padding - 16 - tooltipHeight, left: target.left + target.width / 2 - tooltipWidth / 2, }; } case "bottom": return { top: target.top + target.height + padding, left: target.left + target.width / 2 - tooltipWidth / 2 }; case "left": return { top: target.top + target.height / 2, left: target.left - padding - tooltipWidth, transform: "translateY(-50%)", }; case "right": return { top: target.top + target.height / 2, left: target.left + target.width + padding, transform: "translateY(-50%)", }; default: return { top: target.top + target.height + padding, left: target.left }; } }; export const TutorialOverlay: Component = () => { const tutorial = useTutorial(); const [targetPos, setTargetPos] = createSignal(null); const currentTarget = createMemo(() => { const step = tutorial.currentStep(); if (!step) return null; return tutorial.targets().get(step.id) ?? null; }); createEffect(() => { if (!tutorial.active()) return; const element = currentTarget(); if (!element) { setTargetPos(null); return; } const updatePosition = () => { const rect = element.getBoundingClientRect(); setTargetPos({ top: rect.top + window.scrollY, left: rect.left + window.scrollX, width: rect.width, height: rect.height, }); }; updatePosition(); window.addEventListener("resize", updatePosition); window.addEventListener("scroll", updatePosition); onCleanup(() => { window.removeEventListener("resize", updatePosition); window.removeEventListener("scroll", updatePosition); }); }); createEffect(() => { if (tutorial.active()) { document.body.style.overflow = "hidden"; } else { document.body.style.overflow = ""; } onCleanup(() => { document.body.style.overflow = ""; }); }); return ( {(pos) => ( <> tutorial.skipTutorial()} />

{tutorial.currentStep()?.title}

{tutorial.currentStep()?.desc}

{(_, i) => (
)}

Use ← → arrow keys or Esc to skip

)} ); }; export default TutorialOverlay;