Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 27 additions & 106 deletions src/components/Tutorial.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -325,111 +348,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
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];
Expand Down Expand Up @@ -460,7 +378,10 @@ const Tutorial = ({
<div
ref={tooltipRef}
className={`absolute pointer-events-auto flex flex-col gap-4 max-w-sm w-full p-6 bg-white rounded-2xl shadow-2xl`}
style={tooltipStyle}
style={{
...tooltipStyle,
maxWidth: 'min(24rem, calc(100vw - 40px))'
}}
>
<div>
<div className="flex justify-between items-start mb-2">
Expand Down