diff --git a/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx b/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx index 66d87ae2..5bf3a1da 100644 --- a/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx +++ b/apps/web/src/arcade-games/rithmomachia/components/PlayingGuideModal.tsx @@ -28,6 +28,7 @@ export function PlayingGuideModal({ isOpen, onClose, standalone = false }: Playi const [position, setPosition] = useState({ x: 0, y: 0 }) const [size, setSize] = useState({ width: 800, height: 600 }) const [isDragging, setIsDragging] = useState(false) + const [windowWidth, setWindowWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 800) const [dragStart, setDragStart] = useState({ x: 0, y: 0 }) const [isResizing, setIsResizing] = useState(false) const [resizeDirection, setResizeDirection] = useState('') @@ -35,6 +36,13 @@ export function PlayingGuideModal({ isOpen, onClose, standalone = false }: Playi const [isHovered, setIsHovered] = useState(false) const modalRef = useRef(null) + // Track window width for responsive behavior + useEffect(() => { + const handleResize = () => setWindowWidth(window.innerWidth) + window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) + }, []) + // Center modal on mount (not in standalone mode) useEffect(() => { if (isOpen && modalRef.current && !standalone) { @@ -93,21 +101,25 @@ export function PlayingGuideModal({ isOpen, onClose, standalone = false }: Playi let newY = resizeStart.y // Handle different resize directions - calculate from initial state + // Ultra-flexible minimum width for narrow layouts + const minWidth = 150 + const minHeight = 300 + if (resizeDirection.includes('e')) { - newWidth = Math.max(450, Math.min(window.innerWidth * 0.9, resizeStart.width + deltaX)) + newWidth = Math.max(minWidth, Math.min(window.innerWidth * 0.9, resizeStart.width + deltaX)) } if (resizeDirection.includes('w')) { const desiredWidth = resizeStart.width - deltaX - newWidth = Math.max(450, Math.min(window.innerWidth * 0.9, desiredWidth)) + newWidth = Math.max(minWidth, Math.min(window.innerWidth * 0.9, desiredWidth)) // Move left edge by the amount we actually changed width newX = resizeStart.x + (resizeStart.width - newWidth) } if (resizeDirection.includes('s')) { - newHeight = Math.max(600, Math.min(window.innerHeight * 0.8, resizeStart.height + deltaY)) + newHeight = Math.max(minHeight, Math.min(window.innerHeight * 0.9, resizeStart.height + deltaY)) } if (resizeDirection.includes('n')) { const desiredHeight = resizeStart.height - deltaY - newHeight = Math.max(600, Math.min(window.innerHeight * 0.8, desiredHeight)) + newHeight = Math.max(minHeight, Math.min(window.innerHeight * 0.9, desiredHeight)) // Move top edge by the amount we actually changed height newY = resizeStart.y + (resizeStart.height - newHeight) } @@ -144,6 +156,12 @@ export function PlayingGuideModal({ isOpen, onClose, standalone = false }: Playi { id: 'victory', label: t('sections.victory'), icon: '👑' }, ] + // Determine layout mode based on modal width (or window width if standalone) + const effectiveWidth = standalone ? windowWidth : size.width + const isVeryNarrow = effectiveWidth < 250 + const isNarrow = effectiveWidth < 400 + const isMedium = effectiveWidth < 600 + const renderResizeHandles = () => { if (!isHovered || window.innerWidth < 768 || standalone) return null @@ -276,17 +294,15 @@ export function PlayingGuideModal({ isOpen, onClose, standalone = false }: Playi
= 768 ? 'grab' : 'default', }} + onMouseDown={handleMouseDown} > {/* Close and utility buttons - top right */}
- {/* Bust-out button (only if not already standalone) */} - {!standalone && ( + {/* Bust-out button (only if not already standalone and not very narrow) */} + {!standalone && !isVeryNarrow && (
- {/* Centered title and subtitle */} -
-

- {t('title')} -

-

- {t('subtitle')} -

-
+ {/* Centered title and subtitle - hide when very narrow */} + {!isVeryNarrow && ( +
+

+ {t('title')} +

+ {!isNarrow && ( +

+ {t('subtitle')} +

+ )} +
+ )}
- {/* Navigation Tabs */} + {/* Navigation Tabs - ultra responsive with scroll indicators */}
+
{sections.map((section) => ( ))} +
+ + {/* Fade indicators for horizontal scroll (when not very narrow) */} + {!isVeryNarrow && isNarrow && ( + <> +
+
+ + )}
{/* Content */}
{activeSection === 'overview' && (