import { ChevronDownIcon, ChevronRightIcon, FileIcon, FolderIcon, SearchIcon, } from 'lucide-react'; import { useMemo, useState } from 'react'; import { buildFileTree, filterFiles } from '#/lib/file-tree.js'; import { cn } from '#/lib/utils.js'; const STATUS_MARK = { added: '+', deleted: '−', modified: '±' }; const STATUS_COLOR = { added: 'text-foreground', deleted: 'text-faint', modified: 'text-faint', }; /** * One row per node, indented by depth. Directories carry their own open * state, so closing one leaves the rest as they were. */ function Node({ node, depth, onPick, picked }) { const [open, setOpen] = useState(true); const pad = { paddingLeft: `${depth * 12 + 8}px` }; if (node.type === 'file') { const status = node.file.status; return ( ); } const Chevron = open ? ChevronDownIcon : ChevronRightIcon; return (
{open && node.children.map((child) => ( ))}
); } /** * The changed files of a commit, as the tree they came from, beside the * diffs themselves. Picking one moves to it rather than opening a page: the * diffs are all on this screen already. */ export function DiffTree({ files, onPick, picked }) { const [filter, setFilter] = useState(''); const shown = useMemo(() => filterFiles(files, filter), [files, filter]); const tree = useMemo(() => buildFileTree(shown), [shown]); return (
setFilter(event.target.value)} placeholder="Filter files" aria-label="Filter changed files" className="h-9 w-full rounded-xl border border-input bg-background pr-2.5 pl-8 text-[13px] outline-none transition-colors placeholder:text-faint focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50" />
{shown.length === 0 ? (

No file matches that.

) : (
{tree.map((node) => ( ))}
)} {shown.length !== files.length && ( // Only while a filter is narrowing things. The commit card above // already says how many files changed.

{shown.length} of {files.length} shown

)}
); }