/** * @file GitModal.tsx * @description The shared modal shell of the Changes panel's git tools (merge * editor, reflog, rebase, interactive rebase, reset, force push, remotes): a * portal over the screen with `useDialog`'s focus contract, a title row with a * close button, a scrolling body and an optional footer. `wide` widens it for * the three-pane merge editor; `tall` gives a viewer (blame, browse at a * revision, compare refs) the full height and a column body its own scrolling * child can fill; on a phone every size is the full width. `ModalButton` is * the History tools' footer button over the same BTN classes. * @author Nguyễn Ngọc Trí Vĩ */ import { useId, useRef, type ReactNode } from "react"; import { createPortal } from "react-dom"; import { useTranslation } from "react-i18next"; import { X } from "lucide-react"; import { useDialog } from "../../../hooks/useDialog"; export const BTN = "rounded border border-border-light px-2 py-1 text-[11px] text-fg-secondary hover:bg-surface-2 hover:text-fg-primary disabled:cursor-not-allowed disabled:opacity-40"; export const BTN_PRIMARY = "rounded border border-accent-solid bg-accent-solid px-2 py-1 text-[11px] font-medium text-white hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-40"; export const BTN_DANGER = "rounded border border-status-danger/60 px-2 py-1 text-[11px] font-medium text-status-danger hover:bg-status-danger/10 disabled:cursor-not-allowed disabled:opacity-40"; export function GitModal({ title, onClose, testId, wide = false, tall = false, footer, children, }: { title: ReactNode; onClose: () => void; testId?: string; wide?: boolean; /** A viewer: the full height, and a flex-column body. */ tall?: boolean; footer?: ReactNode; children: ReactNode; }) { const { t } = useTranslation(["gitTools"]); const panel = useRef(null); const titleId = useId(); useDialog(true, panel, onClose); return createPortal(
e.stopPropagation()} role="presentation" >
e.stopPropagation()} className={`flex max-h-[92vh] w-full flex-col rounded-xl border border-border bg-surface-1 shadow-2xl shadow-black/50 ${ wide || tall ? "max-w-6xl" : "max-w-lg" } ${tall ? "h-[92vh]" : ""}`} >

{title}

{children}
{footer && (
{footer}
)}
, document.body ); } /** A red inline error line, or nothing. */ export function ErrorLine({ error }: { error: string | null }) { if (!error) return null; return (

{error}

); } /** An amber explanation box shown before a rewrite runs. */ export function Warn({ children, testId }: { children: ReactNode; testId?: string }) { return (
{children}
); } /** A footer button: plain, `primary` (filled) or `danger` (red outline). */ export function ModalButton({ onClick, children, primary = false, danger = false, disabled = false, testId, title, }: { onClick: () => void; children: ReactNode; primary?: boolean; danger?: boolean; disabled?: boolean; testId?: string; title?: string; }) { return ( ); }