- Create centralized tooltip definitions with TooltipType enum - Add comprehensive tooltip content for 31 different field types - Include Lighthouse relationships, calculations, and documentation links - Implement click-to-open modal system with rich content display - Refactor Tooltip component to use enum-based content lookup - Update RequestsTable and RequestDebugger to use simplified enum syntax - Add Modal component with keyboard shortcuts and backdrop dismiss - Maintain type safety with proper TypeScript interfaces - Clean up component props by centralizing all tooltip content Benefits: - Single source of truth for all tooltip definitions - Improved maintainability and consistency - Type-safe enum usage prevents errors - Reduced code duplication across components - Enhanced UX with detailed modal explanations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
119 lines
2.9 KiB
TypeScript
119 lines
2.9 KiB
TypeScript
import { useEffect } from 'react'
|
||
|
||
interface ModalProps {
|
||
isOpen: boolean
|
||
onClose: () => void
|
||
title: string
|
||
children: React.ReactNode
|
||
}
|
||
|
||
export function Modal({ isOpen, onClose, title, children }: ModalProps) {
|
||
// Close modal on Escape key
|
||
useEffect(() => {
|
||
const handleEscape = (event: KeyboardEvent) => {
|
||
if (event.key === 'Escape') {
|
||
onClose()
|
||
}
|
||
}
|
||
|
||
if (isOpen) {
|
||
document.addEventListener('keydown', handleEscape)
|
||
// Prevent body scrolling when modal is open
|
||
document.body.style.overflow = 'hidden'
|
||
}
|
||
|
||
return () => {
|
||
document.removeEventListener('keydown', handleEscape)
|
||
document.body.style.overflow = 'unset'
|
||
}
|
||
}, [isOpen, onClose])
|
||
|
||
if (!isOpen) return null
|
||
|
||
return (
|
||
<div
|
||
style={{
|
||
position: 'fixed',
|
||
top: 0,
|
||
left: 0,
|
||
right: 0,
|
||
bottom: 0,
|
||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
zIndex: 10000,
|
||
padding: '20px'
|
||
}}
|
||
onClick={onClose}
|
||
>
|
||
<div
|
||
style={{
|
||
backgroundColor: 'white',
|
||
borderRadius: '8px',
|
||
boxShadow: '0 20px 40px rgba(0, 0, 0, 0.3)',
|
||
maxWidth: '600px',
|
||
maxHeight: '80vh',
|
||
width: '100%',
|
||
overflow: 'hidden',
|
||
display: 'flex',
|
||
flexDirection: 'column'
|
||
}}
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
{/* Modal Header */}
|
||
<div
|
||
style={{
|
||
padding: '20px',
|
||
borderBottom: '1px solid #e9ecef',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
backgroundColor: '#f8f9fa'
|
||
}}
|
||
>
|
||
<h2 style={{ margin: 0, color: '#495057', fontSize: '18px', fontWeight: 'bold' }}>
|
||
{title}
|
||
</h2>
|
||
<button
|
||
onClick={onClose}
|
||
style={{
|
||
background: 'none',
|
||
border: 'none',
|
||
fontSize: '24px',
|
||
cursor: 'pointer',
|
||
color: '#6c757d',
|
||
padding: '0',
|
||
width: '30px',
|
||
height: '30px',
|
||
borderRadius: '50%',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
transition: 'background-color 0.2s'
|
||
}}
|
||
onMouseEnter={(e) => {
|
||
e.currentTarget.style.backgroundColor = '#e9ecef'
|
||
}}
|
||
onMouseLeave={(e) => {
|
||
e.currentTarget.style.backgroundColor = 'transparent'
|
||
}}
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
|
||
{/* Modal Content */}
|
||
<div
|
||
style={{
|
||
padding: '20px',
|
||
overflow: 'auto',
|
||
flex: 1
|
||
}}
|
||
>
|
||
{children}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
} |