Add condition tooltips with 5.5e descriptions
All checks were successful
CI / check (push) Successful in 1m22s
CI / build-image (push) Successful in 19s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-22 22:48:23 +01:00
parent 9def2d7c24
commit 6336dec38a
4 changed files with 165 additions and 41 deletions

View File

@@ -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>,

View File

@@ -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

View 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,
)}
</>
);
}