import { useId, useRef } from 'react' import { Info, ExternalLink } from 'lucide-react' import type { components } from '../generated/backend-openapi' type InstructionSection = NonNullable[number] const COMMUNITY_DISCLAIMER = 'This LoRA was created by a community member, not LTX. LTX does not endorse or take responsibility for community LoRAs. LTX has no control over the LoRA and any claims of any kind should be directed to the creator of the LoRA.' // Info icon → popover with a LoRA/IC-LoRA's instruction sections + a link to its HF page // (derived from repoId, no stored URL). Native popover API: top-layer (escapes the // modal's overflow clipping and stacks above the ), with ESC + click-outside // dismiss for free. The popover/popovertarget attrs aren't in @types/react 18.3's JSX // yet, so they're declared via cast objects below — but statically, so the element is // never rendered without `popover` (setting it post-mount let it flash inline in the row). export function LoraInfoPopover({ sections, name, repoId, isCommunity = true, maxHeight = '70vh', }: { sections: InstructionSection[] name: string repoId?: string // Fail closed: missing affiliation → show disclaimer. isCommunity?: boolean // Caller-tunable cap so the popover scrolls instead of overflowing its container // (e.g. the library modal needs a lower value than it does elsewhere). maxHeight?: string }) { const id = useId() const btnRef = useRef(null) const popRef = useRef(null) const showCommunityDisclaimer = isCommunity if (sections.length === 0 && !repoId && !showCommunityDisclaimer) return null // Native Popover API attrs missing from @types/react 18.3's JSX; cast so they render. const popoverAttrs = { popover: 'auto' } as unknown as React.HTMLAttributes const triggerAttrs = { popovertarget: id } as unknown as React.ButtonHTMLAttributes // The popover is viewport-fixed in the top layer; anchor it above the trigger on open. const anchor = () => { const btn = btnRef.current, pop = popRef.current if (!btn || !pop) return const r = btn.getBoundingClientRect() pop.style.margin = '0' pop.style.right = 'auto' pop.style.top = 'auto' pop.style.left = `${Math.max(8, r.left)}px` pop.style.bottom = `${window.innerHeight - r.top + 6}px` } return ( <>
{name}
{sections.map((s, i) => (
{s.title}
{Array.isArray(s.body) ? (
    {s.body.map((b, j) =>
  • {b}
  • )}
) : (

{s.body}

)}
))}
{showCommunityDisclaimer && (

{COMMUNITY_DISCLAIMER}

)} {repoId && ( )}
) }