diff --git a/builder-frontend/src/components/icon/QuestionMarkIcon.tsx b/builder-frontend/src/components/icon/QuestionMarkIcon.tsx new file mode 100644 index 00000000..4160540c --- /dev/null +++ b/builder-frontend/src/components/icon/QuestionMarkIcon.tsx @@ -0,0 +1,18 @@ +export default function QuestionMarkIcon(props: { class?: string }) { + return ( + + + + ); +} diff --git a/builder-frontend/src/components/shared/QuestionTooltip.tsx b/builder-frontend/src/components/shared/QuestionTooltip.tsx new file mode 100644 index 00000000..27306ab0 --- /dev/null +++ b/builder-frontend/src/components/shared/QuestionTooltip.tsx @@ -0,0 +1,99 @@ +import { createSignal, JSX, Show } from "solid-js"; +import QuestionMarkIcon from "../icon/QuestionMarkIcon"; + +export enum TooltipAlignment { + Center = "center", + Left = "left", + Right = "right", +} + +interface TooltipProps { + text: string; + children?: JSX.Element; +} + +export default function QuestionTooltip(props: TooltipProps) { + const [isVisible, setIsVisible] = createSignal(false); + const [position, setPosition] = createSignal<{ + x: number; + align: TooltipAlignment; + }>({ x: 0, align: TooltipAlignment.Center }); + + let containerRef: HTMLDivElement | undefined; + + const determineAlignment = (rect: DOMRect): TooltipAlignment => { + const tooltipWidth = 256; // w-64 is 16rem = 256px + + // Calculate potential left and right bounds if centered + const centerLeft = rect.left + rect.width / 2 - tooltipWidth / 2; + const centerRight = centerLeft + tooltipWidth; + + const viewportWidth = window.innerWidth; + const padding = 16; // 16px safety padding from screen edges + + if (centerLeft < padding) { + return TooltipAlignment.Left; + } else if (centerRight > viewportWidth - padding) { + return TooltipAlignment.Right; + } else { + return TooltipAlignment.Center; + } + }; + + const handleMouseEnter = () => { + if (containerRef) { + const rect = containerRef.getBoundingClientRect(); + const align = determineAlignment(rect); + setPosition({ x: 0, align }); + } + setIsVisible(true); + }; + + const handleMouseLeave = () => setIsVisible(false); + + return ( +
+ + } + > + {props.children} + + + +
+ {props.text} + {/* Decorative arrow pointing up */} +
+
+ +
+ ); +} \ No newline at end of file