From a1854caf508f898171782b10a4e88e4a9c87367a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 08:00:38 +0000 Subject: [PATCH 1/2] Refine Tutorial positioning logic and fix mobile layout - Remove duplicate and broken positioning code block in `src/components/Tutorial.jsx`. - Implement robust `maxWidth` constraint for mobile devices using `min(24rem, calc(100vw - 40px))`. - Ensure strict boundary clamping and center-priority positioning are preserved. --- src/components/Tutorial.jsx | 87 ++----------------------------------- 1 file changed, 4 insertions(+), 83 deletions(-) diff --git a/src/components/Tutorial.jsx b/src/components/Tutorial.jsx index 15cbbaa..2f85965 100644 --- a/src/components/Tutorial.jsx +++ b/src/components/Tutorial.jsx @@ -325,88 +325,6 @@ const Tutorial = ({ return () => observer.disconnect(); }, [rect, step]); - // Strict Positioning Logic - useLayoutEffect(() => { - if (step < 0 || step >= STEPS.length || !rect || !tooltipRef.current) return; - - const currentStep = STEPS[step]; - const PADDING = 20; - - // Measure ACTUAL tooltip dimensions - const CARD_W = tooltipRef.current.offsetWidth || 384; - const CARD_H = tooltipRef.current.offsetHeight || 250; - - let top, left, transform = 'none'; - - if (currentStep.position === 'bottom') { - top = rect.top + rect.height + 20; - left = rect.left; - } else if (currentStep.position === 'top') { - top = rect.top - CARD_H - 20; - left = rect.left; - } else if (currentStep.position === 'right') { - top = rect.top; - left = rect.left + rect.width + 20; - } else if (currentStep.position === 'left') { - top = rect.top; - left = rect.left - CARD_W - 20; - } else { // center - top = '50%'; - left = '50%'; - transform = 'translate(-50%, -50%)'; - } - - // --- Strict Boundary Logic --- - const winH = window.innerHeight; - const winW = window.innerWidth; - - if (typeof top === 'number') { - // 1. Flip Logic (Vertical) - // If overflow bottom, try flip top - if (top + CARD_H > winH - PADDING) { - if (currentStep.position === 'bottom') { - const flippedTop = rect.top - CARD_H - 20; - // Only flip if there is space on top - if (flippedTop > PADDING) top = flippedTop; - } - } - // If overflow top (e.g. from flip or 'top' pos), try flip bottom - if (top < PADDING) { - if (currentStep.position === 'top') { - const flippedBottom = rect.top + rect.height + 20; - if (flippedBottom + CARD_H < winH - PADDING) top = flippedBottom; - } - } - - // 2. Clamp Logic (Vertical) - Final fallback - if (top < PADDING) top = PADDING; - if (top + CARD_H > winH - PADDING) top = winH - CARD_H - PADDING; - } - - if (typeof left === 'number') { - // 1. Flip Logic (Horizontal) - if (left + CARD_W > winW - PADDING) { - if (currentStep.position === 'right') { - const flippedLeft = rect.left - CARD_W - 20; - if (flippedLeft > PADDING) left = flippedLeft; - } - } - if (left < PADDING) { - if (currentStep.position === 'left') { - const flippedRight = rect.left + rect.width + 20; - if (flippedRight + CARD_W < winW - PADDING) left = flippedRight; - } - } - - // 2. Clamp Logic (Horizontal) - if (left < PADDING) left = PADDING; - if (left + CARD_W > winW - PADDING) left = winW - CARD_W - PADDING; - } - - setTooltipPos({ top, left, transform }); - - }, [rect, step]); // Re-run when rect changes (target moves) or step changes (content changes) - const handleNext = () => { if (step === STEPS.length - 2) { // Finish step // Open Login Modal @@ -460,7 +378,10 @@ const Tutorial = ({
From 539a38eeef6410d6c75910277a9323d4ef38c5e7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 08:07:46 +0000 Subject: [PATCH 2/2] Fix ReferenceError in Tutorial component Moved `handleNext` and `handleSkip` function definitions to the top of the component body, ensuring they are declared before being accessed by `useEffect` hooks. This resolves the 'handleNext accessed before declared' runtime error. --- src/components/Tutorial.jsx | 46 ++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/components/Tutorial.jsx b/src/components/Tutorial.jsx index 2f85965..5be2285 100644 --- a/src/components/Tutorial.jsx +++ b/src/components/Tutorial.jsx @@ -135,6 +135,29 @@ const Tutorial = ({ } ]; + const handleNext = () => { + if (step === STEPS.length - 2) { // Finish step + // Open Login Modal + setIsLoginOpen(true); + // Wait a bit for modal to open then next + setTimeout(() => setStep(s => s + 1), 500); + } else if (step >= STEPS.length - 1) { + // End + setStep(-2); + setIsVisible(false); + } else { + setStep(s => s + 1); + } + }; + + const handleSkip = (dontShowAgain) => { + if (dontShowAgain) { + localStorage.setItem('rail_tutorial_skipped', 'true'); + } + setStep(-2); + setIsVisible(false); + }; + // Initialization check useEffect(() => { const skipped = localStorage.getItem('rail_tutorial_skipped'); @@ -325,29 +348,6 @@ const Tutorial = ({ return () => observer.disconnect(); }, [rect, step]); - const handleNext = () => { - if (step === STEPS.length - 2) { // Finish step - // Open Login Modal - setIsLoginOpen(true); - // Wait a bit for modal to open then next - setTimeout(() => setStep(s => s + 1), 500); - } else if (step >= STEPS.length - 1) { - // End - setStep(-2); - setIsVisible(false); - } else { - setStep(s => s + 1); - } - }; - - const handleSkip = (dontShowAgain) => { - if (dontShowAgain) { - localStorage.setItem('rail_tutorial_skipped', 'true'); - } - setStep(-2); - setIsVisible(false); - }; - if (!isVisible || step < 0) return null; const currentStep = STEPS[step];