Files
kandev/apps/web/components/editors/monaco/diff-viewer-toolbar.tsx
T
2026-02-21 22:14:56 +00:00

199 lines
5.4 KiB
TypeScript

import { cn } from "@kandev/ui/lib/utils";
import { Button } from "@kandev/ui/button";
import { Tooltip, TooltipTrigger, TooltipContent } from "@kandev/ui/tooltip";
import {
IconCopy,
IconTextWrap,
IconLayoutRows,
IconLayoutColumns,
IconPencil,
IconArrowBackUp,
IconFoldDown,
IconFold,
} from "@tabler/icons-react";
import type { FileDiffData } from "@/lib/diff/types";
import type { ViewMode } from "@/hooks/use-global-view-mode";
interface DiffViewerToolbarProps {
data: FileDiffData;
foldUnchanged: boolean;
setFoldUnchanged: (v: boolean) => void;
wordWrap: boolean;
setWordWrap: (v: boolean) => void;
globalViewMode: ViewMode;
setGlobalViewMode: (v: ViewMode) => void;
onCopyDiff: () => void;
onOpenFile?: (filePath: string) => void;
onRevert?: (filePath: string) => void;
}
const iconBtn = "h-6 w-6 p-0 cursor-pointer opacity-60 hover:opacity-100";
type DiffViewerActionsProps = Omit<DiffViewerToolbarProps, "data"> & { filePath: string };
function DiffViewerToggleButtons({
foldUnchanged,
setFoldUnchanged,
wordWrap,
setWordWrap,
globalViewMode,
setGlobalViewMode,
}: Pick<
DiffViewerActionsProps,
| "foldUnchanged"
| "setFoldUnchanged"
| "wordWrap"
| "setWordWrap"
| "globalViewMode"
| "setGlobalViewMode"
>) {
return (
<>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
className={cn(iconBtn, foldUnchanged && "opacity-100 bg-muted")}
onClick={() => setFoldUnchanged(!foldUnchanged)}
>
{foldUnchanged ? (
<IconFoldDown className="h-3.5 w-3.5" />
) : (
<IconFold className="h-3.5 w-3.5" />
)}
</Button>
</TooltipTrigger>
<TooltipContent>{foldUnchanged ? "Show all lines" : "Fold unchanged lines"}</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
className={cn(iconBtn, wordWrap && "opacity-100 bg-muted")}
onClick={() => setWordWrap(!wordWrap)}
>
<IconTextWrap className="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>Toggle word wrap</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
className={cn(iconBtn)}
onClick={() => setGlobalViewMode(globalViewMode === "split" ? "unified" : "split")}
>
{globalViewMode === "split" ? (
<IconLayoutRows className="h-3.5 w-3.5" />
) : (
<IconLayoutColumns className="h-3.5 w-3.5" />
)}
</Button>
</TooltipTrigger>
<TooltipContent>
{globalViewMode === "split" ? "Switch to unified view" : "Switch to split view"}
</TooltipContent>
</Tooltip>
</>
);
}
function DiffViewerActions({
filePath,
foldUnchanged,
setFoldUnchanged,
wordWrap,
setWordWrap,
globalViewMode,
setGlobalViewMode,
onCopyDiff,
onOpenFile,
onRevert,
}: DiffViewerActionsProps) {
return (
<div className="flex items-center gap-1">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" className={iconBtn} onClick={onCopyDiff}>
<IconCopy className="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>Copy diff</TooltipContent>
</Tooltip>
<DiffViewerToggleButtons
foldUnchanged={foldUnchanged}
setFoldUnchanged={setFoldUnchanged}
wordWrap={wordWrap}
setWordWrap={setWordWrap}
globalViewMode={globalViewMode}
setGlobalViewMode={setGlobalViewMode}
/>
{onRevert && (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
className={iconBtn}
onClick={() => onRevert(filePath)}
>
<IconArrowBackUp className="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>Revert changes</TooltipContent>
</Tooltip>
)}
{onOpenFile && (
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="sm"
className={iconBtn}
onClick={() => onOpenFile(filePath)}
>
<IconPencil className="h-3.5 w-3.5" />
</Button>
</TooltipTrigger>
<TooltipContent>Edit</TooltipContent>
</Tooltip>
)}
</div>
);
}
export function DiffViewerToolbar({
data,
foldUnchanged,
setFoldUnchanged,
wordWrap,
setWordWrap,
globalViewMode,
setGlobalViewMode,
onCopyDiff,
onOpenFile,
onRevert,
}: DiffViewerToolbarProps) {
return (
<div className="flex items-center justify-between px-3 py-1.5 border-b border-border/50 bg-card/50 rounded-t-md text-xs text-muted-foreground">
<span className="font-mono truncate">{data.filePath}</span>
<DiffViewerActions
filePath={data.filePath}
foldUnchanged={foldUnchanged}
setFoldUnchanged={setFoldUnchanged}
wordWrap={wordWrap}
setWordWrap={setWordWrap}
globalViewMode={globalViewMode}
setGlobalViewMode={setGlobalViewMode}
onCopyDiff={onCopyDiff}
onOpenFile={onOpenFile}
onRevert={onRevert}
/>
</div>
);
}