82 lines
3.8 KiB
TypeScript
82 lines
3.8 KiB
TypeScript
import type { ReactElement } from 'react'
|
|
import type { DocumentDiff } from './types'
|
|
import { ArrowDown, ArrowUp, FilePlus, GitCompare } from 'lucide-react'
|
|
import { Fragment } from 'react'
|
|
import { statsParts } from './diffView'
|
|
|
|
export interface DiffBarProps {
|
|
diff: DocumentDiff
|
|
/** 「只看改动」开着:连着没变的块折成一条 */
|
|
onlyChanges: boolean
|
|
onToggleOnly: () => void
|
|
/** 有没有改动可以跳(筛掉的不算) */
|
|
canMove: boolean
|
|
/** 跳到上一处(-1)/ 下一处(1)改动 */
|
|
onMove: (step: 1 | -1) => void
|
|
}
|
|
|
|
/**
|
|
* 筛选栏第二行(标差异时才有):对比基准(「对比:上一次提交」),改动统计(「新增 2 · 修改 3 · 删除 1」,各按改动色,
|
|
* 没有的那种不写,都没有写「没有改动」),右边「只看改动」开关、上一处 / 下一处。基准里没有这个文件时只写基准,看横幅。
|
|
*/
|
|
export function DiffBar({ diff, onlyChanges, onToggleOnly, canMove, onMove }: DiffBarProps): ReactElement {
|
|
const parts = statsParts(diff.stats)
|
|
return (
|
|
<div className="mx-auto box-content flex h-[30px] max-w-[880px] items-center gap-2 px-6 text-xs whitespace-nowrap text-[var(--vscode-descriptionForeground)]">
|
|
<GitCompare size={14} strokeWidth={1.8} className="shrink-0" aria-hidden />
|
|
<span className="min-w-0 truncate">
|
|
对比:
|
|
<span className="text-[var(--vscode-foreground)]">{diff.base}</span>
|
|
</span>
|
|
{diff.newFile === undefined && (
|
|
<>
|
|
<span className="opacity-60" aria-hidden>·</span>
|
|
<span className="flex items-center gap-1.5">
|
|
{parts.length === 0
|
|
? '没有改动'
|
|
: parts.map((part, index) => (
|
|
<Fragment key={part.change}>
|
|
{index > 0 && <span aria-hidden>·</span>}
|
|
<span className="cr-diff-stat" data-change={part.change}>{part.text}</span>
|
|
</Fragment>
|
|
))}
|
|
</span>
|
|
<span className="flex-1" />
|
|
<button type="button" className="cr-only-changes flex h-6 items-center gap-1.5 rounded px-1.5" aria-pressed={onlyChanges} onClick={onToggleOnly}>
|
|
<span className="cr-switch" data-on={onlyChanges ? '' : undefined} aria-hidden>
|
|
<span className="cr-switch-knob" />
|
|
</span>
|
|
只看改动
|
|
</button>
|
|
<span className="flex items-center gap-0.5" role="group" aria-label="改动之间跳">
|
|
{([[-1, ArrowUp, '上一处改动'], [1, ArrowDown, '下一处改动']] as const).map(([step, Icon, label]) => (
|
|
<button
|
|
key={step}
|
|
type="button"
|
|
className="cr-tool flex h-[22px] w-6 items-center justify-center rounded disabled:opacity-40"
|
|
data-tooltip={label}
|
|
aria-label={label}
|
|
disabled={!canMove}
|
|
onClick={() => onMove(step)}
|
|
>
|
|
<Icon size={14} strokeWidth={1.8} className="text-[var(--vscode-foreground)]" aria-hidden />
|
|
</button>
|
|
))}
|
|
</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
/** 基准里没有这个文件(新文件、未跟踪的):预览顶部一条横幅,卡片不再逐张标绿。 */
|
|
export function NewFileBanner({ detail }: { detail: string }): ReactElement {
|
|
return (
|
|
<div className="cr-new-file mb-3 flex items-center gap-2 rounded-md px-3 py-[7px]" role="status">
|
|
<FilePlus size={16} strokeWidth={1.8} className="shrink-0" aria-hidden />
|
|
<span className="shrink-0 text-[12.5px] leading-[18px] font-medium text-[var(--vscode-foreground)]">新文件,全部是新增</span>
|
|
<span className="min-w-0 text-xs leading-[18px] text-[var(--vscode-descriptionForeground)]">{detail}</span>
|
|
</div>
|
|
)
|
|
}
|