Add condition tooltips with 5.5e descriptions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { cn } from "../lib/utils";
|
||||
import { Tooltip } from "./ui/tooltip.js";
|
||||
|
||||
const ICON_MAP: Record<string, LucideIcon> = {
|
||||
EyeOff,
|
||||
@@ -121,25 +122,28 @@ export function ConditionPicker({
|
||||
const isActive = active.has(def.id);
|
||||
const colorClass = COLOR_CLASSES[def.color] ?? "text-muted-foreground";
|
||||
return (
|
||||
<button
|
||||
key={def.id}
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded px-2 py-1 text-sm transition-colors hover:bg-hover-neutral-bg",
|
||||
isActive && "bg-card/50",
|
||||
)}
|
||||
onClick={() => onToggle(def.id)}
|
||||
>
|
||||
<Icon
|
||||
size={14}
|
||||
className={isActive ? colorClass : "text-muted-foreground"}
|
||||
/>
|
||||
<span
|
||||
className={isActive ? "text-foreground" : "text-muted-foreground"}
|
||||
<Tooltip key={def.id} content={def.description} className="block">
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded px-2 py-1 text-sm transition-colors hover:bg-hover-neutral-bg",
|
||||
isActive && "bg-card/50",
|
||||
)}
|
||||
onClick={() => onToggle(def.id)}
|
||||
>
|
||||
{def.label}
|
||||
</span>
|
||||
</button>
|
||||
<Icon
|
||||
size={14}
|
||||
className={isActive ? colorClass : "text-muted-foreground"}
|
||||
/>
|
||||
<span
|
||||
className={
|
||||
isActive ? "text-foreground" : "text-muted-foreground"
|
||||
}
|
||||
>
|
||||
{def.label}
|
||||
</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</div>,
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
ZapOff,
|
||||
} from "lucide-react";
|
||||
import { cn } from "../lib/utils.js";
|
||||
import { Tooltip } from "./ui/tooltip.js";
|
||||
|
||||
const ICON_MAP: Record<string, LucideIcon> = {
|
||||
EyeOff,
|
||||
@@ -71,22 +72,22 @@ export function ConditionTags({
|
||||
if (!Icon) return null;
|
||||
const colorClass = COLOR_CLASSES[def.color] ?? "text-muted-foreground";
|
||||
return (
|
||||
<button
|
||||
key={condId}
|
||||
type="button"
|
||||
title={def.label}
|
||||
aria-label={`Remove ${def.label}`}
|
||||
className={cn(
|
||||
"inline-flex items-center rounded p-0.5 transition-colors hover:bg-hover-neutral-bg",
|
||||
colorClass,
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onRemove(condId);
|
||||
}}
|
||||
>
|
||||
<Icon size={14} />
|
||||
</button>
|
||||
<Tooltip key={condId} content={`${def.label}: ${def.description}`}>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`Remove ${def.label}`}
|
||||
className={cn(
|
||||
"inline-flex items-center rounded p-0.5 transition-colors hover:bg-hover-neutral-bg",
|
||||
colorClass,
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onRemove(condId);
|
||||
}}
|
||||
>
|
||||
<Icon size={14} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
<button
|
||||
|
||||
55
apps/web/src/components/ui/tooltip.tsx
Normal file
55
apps/web/src/components/ui/tooltip.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { type ReactNode, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
|
||||
interface TooltipProps {
|
||||
content: string;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Tooltip({
|
||||
content,
|
||||
children,
|
||||
className,
|
||||
}: Readonly<TooltipProps>) {
|
||||
const ref = useRef<HTMLSpanElement>(null);
|
||||
const [pos, setPos] = useState<{ top: number; left: number } | null>(null);
|
||||
|
||||
function show() {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
const rect = el.getBoundingClientRect();
|
||||
setPos({
|
||||
top: rect.top - 4,
|
||||
left: rect.left + rect.width / 2,
|
||||
});
|
||||
}
|
||||
|
||||
function hide() {
|
||||
setPos(null);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
ref={ref}
|
||||
onPointerEnter={show}
|
||||
onPointerLeave={hide}
|
||||
className={className ?? "inline-flex"}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
{pos !== null &&
|
||||
createPortal(
|
||||
<div
|
||||
role="tooltip"
|
||||
className="pointer-events-none fixed z-[60] max-w-64 -translate-x-1/2 -translate-y-full rounded-md border border-border bg-background px-2.5 py-1.5 text-foreground text-xs leading-snug shadow-lg"
|
||||
style={{ top: pos.top, left: pos.left }}
|
||||
>
|
||||
{content}
|
||||
</div>,
|
||||
document.body,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user