diff --git a/src/App.module.css b/src/App.module.css index feb0a54..6fe48e1 100644 --- a/src/App.module.css +++ b/src/App.module.css @@ -49,7 +49,8 @@ --radius-xxl: 12px; /* Z-index */ - --z-modal: 1000; + --z-modal: 10000; + --z-tooltip: 50000; } body { background-color: var(--color-bg); diff --git a/src/components/httprequestviewer/RequestRowSummary.module.css b/src/components/httprequestviewer/RequestRowSummary.module.css index 018e882..8d725c9 100644 --- a/src/components/httprequestviewer/RequestRowSummary.module.css +++ b/src/components/httprequestviewer/RequestRowSummary.module.css @@ -25,10 +25,11 @@ tr { border: 1px solid #ffffff; } -tr:hover, tr:hover td { +/* Only apply hover effects to data rows, not header rows */ +tbody tr:hover, tbody tr:hover td { border: 1px dashed var(--color-bg-hover); } -tr:hover { +tbody tr:hover { filter: brightness(290%); } a { diff --git a/src/components/httprequestviewer/RequestsTable.module.css b/src/components/httprequestviewer/RequestsTable.module.css new file mode 100644 index 0000000..b6776ef --- /dev/null +++ b/src/components/httprequestviewer/RequestsTable.module.css @@ -0,0 +1,73 @@ +/* Table styles using CSS variables from App.module.css */ + +.tableContainer { + background: var(--color-bg-secondary); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + overflow: hidden; + /* Allow tooltips to show above table */ + position: relative; +} + +.table { + width: 100%; + border-collapse: collapse; +} + +.tableHeader { + background: var(--color-bg-light); +} + +/* Ensure header row doesn't inherit hover effects */ +.tableHeader tr:hover { + filter: none !important; + background: var(--color-bg-light) !important; + border: none !important; +} + +.tableHeader tr:hover td, +.tableHeader tr:hover th { + border: 1px solid var(--color-border) !important; + filter: none !important; +} + +/* Ensure tooltips in header work properly */ +.tableHeader .tooltipContainer { + position: relative; + z-index: 10; +} + +.tableHeaderCell { + padding: var(--spacing-sm); + font-size: var(--font-size-md); + font-weight: bold; + border-bottom: 1px solid var(--color-border); + color: var(--color-text); + /* Ensure tooltip positioning context */ + position: relative; + overflow: visible; +} + +.tableHeaderCell.center { + text-align: center; +} + +.tableHeaderCell.left { + text-align: left; +} + +.tableHeaderCell.right { + text-align: right; +} + +.tableHeaderCell.expandColumn { + width: 30px; +} + +/* No results message */ +.noResults { + text-align: center; + color: var(--color-text-muted); + padding: 40px; + font-size: var(--font-size-xl); +} \ No newline at end of file diff --git a/src/components/httprequestviewer/RequestsTable.tsx b/src/components/httprequestviewer/RequestsTable.tsx index 21f2117..e4ba0c9 100644 --- a/src/components/httprequestviewer/RequestsTable.tsx +++ b/src/components/httprequestviewer/RequestsTable.tsx @@ -3,7 +3,7 @@ import RequestRowSummary from './RequestRowSummary' import ScreenshotRow from './ScreenshotRow' import { Tooltip } from '../shared/Tooltip' import { TooltipType } from '../shared/tooltipDefinitions' -import styles from './HTTPRequestViewer.module.css' +import styles from './RequestsTable.module.css' import type { HTTPRequest, ScreenshotEvent } from './types/httpRequest' interface RequestsTableProps { diff --git a/src/components/shared/Modal.module.css b/src/components/shared/Modal.module.css new file mode 100644 index 0000000..5e13e00 --- /dev/null +++ b/src/components/shared/Modal.module.css @@ -0,0 +1,71 @@ +/* Modal component styles using CSS variables from App.module.css */ + +.modalOverlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: var(--z-modal); + padding: var(--spacing-lg); +} + +.modalContainer { + background-color: var(--color-bg-secondary); + border-radius: var(--radius-lg); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); + max-width: 600px; + max-height: 80vh; + width: 100%; + overflow: hidden; + display: flex; + flex-direction: column; + border: 1px solid var(--color-border); +} + +.modalHeader { + padding: var(--spacing-lg); + border-bottom: 1px solid var(--color-border); + display: flex; + align-items: center; + justify-content: space-between; + background-color: var(--color-bg-light); +} + +.modalTitle { + margin: 0; + color: var(--color-text); + font-size: var(--font-size-xxl); + font-weight: bold; +} + +.modalCloseButton { + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: var(--color-text-muted); + padding: 0; + width: 30px; + height: 30px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: background-color 0.2s ease; +} + +.modalCloseButton:hover { + background-color: var(--color-bg-hover); + color: var(--color-text); +} + +.modalBody { + padding: var(--spacing-lg); + overflow: auto; + flex: 1; +} \ No newline at end of file diff --git a/src/components/shared/Modal.tsx b/src/components/shared/Modal.tsx index 9704b4c..089c8fa 100644 --- a/src/components/shared/Modal.tsx +++ b/src/components/shared/Modal.tsx @@ -1,4 +1,5 @@ import { useEffect } from 'react' +import styles from './Modal.module.css' interface ModalProps { isOpen: boolean @@ -32,85 +33,28 @@ export function Modal({ isOpen, onClose, title, children }: ModalProps) { return (
e.stopPropagation()} > {/* Modal Header */} -
-

+
+

{title}

{/* Modal Content */} -
+
{children}
diff --git a/src/components/shared/Tooltip.module.css b/src/components/shared/Tooltip.module.css new file mode 100644 index 0000000..c1569a4 --- /dev/null +++ b/src/components/shared/Tooltip.module.css @@ -0,0 +1,174 @@ +/* Tooltip component styles using CSS variables from App.module.css */ + +.tooltipContainer { + position: relative; + display: inline-flex; + align-items: center; + gap: var(--spacing-xs); + /* Ensure tooltip positioning context */ + z-index: 1; +} + +.tooltipIcon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + background-color: var(--color-primary); + color: white; + border-radius: 50%; + font-size: var(--font-size-xs); + font-weight: bold; + cursor: help; + transition: all 0.2s ease; + user-select: none; +} + +.tooltipIcon:hover { + background-color: var(--color-text); + transform: scale(1.1); +} + +/* Hover tooltip */ +.hoverTooltip { + position: absolute; + top: auto; + bottom: calc(100% + var(--spacing-xs)); + left: 50%; + transform: translateX(-50%); + background-color: var(--color-bg-secondary); + color: var(--color-text); + padding: var(--spacing-sm) var(--spacing-md); + border-radius: var(--radius-md); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + font-size: var(--font-size-sm); + z-index: var(--z-tooltip); + max-width: 300px; + word-wrap: break-word; + white-space: normal; + /* Ensure tooltip doesn't get clipped by containers */ + pointer-events: none; + /* Prevent text selection */ + user-select: none; +} + +.hoverTooltip::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid var(--color-bg-secondary); + /* Ensure arrow is also on top */ + z-index: calc(var(--z-tooltip) + 1); + pointer-events: none; +} + +/* Fixed positioned tooltip for better visibility */ +.hoverTooltipFixed { + position: fixed; + transform: translateX(-50%) translateY(-100%); + background-color: var(--color-bg-secondary); + color: var(--color-text); + padding: var(--spacing-sm) var(--spacing-md); + border-radius: var(--radius-md); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); + font-size: var(--font-size-sm); + z-index: var(--z-tooltip); + max-width: 300px; + word-wrap: break-word; + white-space: normal; + pointer-events: none; + user-select: none; + border: 1px solid var(--color-border); + margin-top: -8px; +} + +.hoverTooltipFixed::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + width: 0; + height: 0; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid var(--color-bg-secondary); + z-index: calc(var(--z-tooltip) + 1); + pointer-events: none; +} + +.tooltipTitle { + font-weight: bold; + margin-bottom: var(--spacing-xs); + color: var(--color-text-highlight); +} + +.tooltipDescription { + margin-bottom: var(--spacing-xs); + line-height: 1.4; +} + +.tooltipHint { + font-size: var(--font-size-xs); + color: var(--color-text-muted); + font-style: italic; +} + +/* Modal content styling */ +.modalContent { + line-height: 1.6; +} + +.modalDescription { + margin-bottom: var(--spacing-lg); + color: var(--color-text); +} + +.modalSection { + margin-bottom: var(--spacing-lg); + padding: var(--spacing-md); + background-color: var(--color-bg-light); + border-radius: var(--radius-md); + border-left: 4px solid var(--color-primary); +} + +.modalSectionTitle { + font-weight: bold; + margin-bottom: var(--spacing-sm); + color: var(--color-text); + display: flex; + align-items: center; + gap: var(--spacing-xs); +} + +.modalSectionContent { + color: var(--color-text); + line-height: 1.5; +} + +.modalLinks { + display: flex; + flex-direction: column; + gap: var(--spacing-xs); +} + +.modalLink { + color: var(--color-primary); + text-decoration: none; + display: flex; + align-items: center; + gap: var(--spacing-xs); + transition: color 0.2s ease; +} + +.modalLink:hover { + color: var(--color-text-highlight); + text-decoration: underline; +} \ No newline at end of file diff --git a/src/components/shared/Tooltip.tsx b/src/components/shared/Tooltip.tsx index d195da5..c985d7f 100644 --- a/src/components/shared/Tooltip.tsx +++ b/src/components/shared/Tooltip.tsx @@ -2,6 +2,7 @@ import { useState } from 'react' import { Modal } from './Modal' import { TOOLTIP_DEFINITIONS } from './tooltipDefinitions' import type { TooltipTypeValues } from './tooltipDefinitions' +import styles from './Tooltip.module.css' // Tooltip component for field explanations interface TooltipProps { @@ -13,6 +14,7 @@ export function Tooltip({ children, type }: TooltipProps) { const { title, description, lighthouseRelation, calculation, links } = TOOLTIP_DEFINITIONS[type] const [isHovered, setIsHovered] = useState(false) const [isModalOpen, setIsModalOpen] = useState(false) + const [tooltipPosition, setTooltipPosition] = useState({ top: 0, left: 0 }) const handleIconClick = (e: React.MouseEvent) => { e.preventDefault() @@ -21,29 +23,51 @@ export function Tooltip({ children, type }: TooltipProps) { setIsModalOpen(true) } + const handleMouseEnter = (e: React.MouseEvent) => { + const rect = (e.target as HTMLElement).getBoundingClientRect() + setTooltipPosition({ + top: rect.top - 10, // Position above the icon + left: rect.left + rect.width / 2 // Center horizontally + }) + setIsHovered(true) + } + return ( <> -
+
{children} + className={styles.tooltipIcon} + onClick={handleIconClick} + onMouseEnter={handleMouseEnter} + onMouseLeave={() => setIsHovered(false)} + > ? - - {/* Hover tooltip - only show when not modal open */} - {isHovered && !isModalOpen && ( -
-
- {title} -
-
- {description} -
-
- Click for detailed information -
+
+ + {/* Hover tooltip - rendered as fixed positioned element */} + {isHovered && !isModalOpen && ( +
+
+ {title}
- )} +
+ {description} +
+
+ Click for detailed information +
+
+ )} + +
{/* Modal with detailed content */} @@ -52,45 +76,47 @@ export function Tooltip({ children, type }: TooltipProps) { onClose={() => setIsModalOpen(false)} title={title} > -
-
+
+
{description}
{lighthouseRelation && ( -
-
+
+
🎯 Lighthouse Relationship
-
+
{lighthouseRelation}
)} {calculation && ( -
-
+
+
🧮 Calculation
-
+
{calculation}
)} {links && links.length > 0 && ( -
-
+
+
📚 Learn More
-