✨ feat(vscode): 代码阅读预览标出新增 / 修改 / 删除的卡片(左侧改动色条、新增淡绿底挂小标、删掉的块原位收成一行可展开),筛选栏第二行写对比基准和改动统计,新文件顶部横幅

This commit is contained in:
cruldra committed 2026-09-30 08:41:55 +08:00
1 parent 2a5806c6b5
commit 3b7ce69842
10 files changed
+491 -20

No files matched your search

+18 -4
View File
@@ -1,15 +1,17 @@
import type { ReactElement } from 'react'
import type { BlockTreeState } from './BlockTree'
import type { NameMap, VersionNames } from './displayNames'
import type { DocumentMessage, Excluded, Reveal } from './types'
import type { DocumentDiff, DocumentMessage, Excluded, Reveal } from './types'
import type { OccurrencePage } from './useOccurrences'
import type { ViewState } from './viewState'
import { TriangleAlert } from 'lucide-react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { BlockLevel } from './BlockTree'
import { DiffBar, NewFileBanner } from './DiffBar'
import { diffTree, openedByDiff } from './diffView'
import { acceptNames, DisplayNameContext, documentNames } from './displayNames'
import { coveredByEditing, startEditing } from './editing'
import { applyFilter, keptWhileEditing } from './filter'
import { applyFilter, excludedBy, keptWhileEditing } from './filter'
import { FilterBar } from './FilterBar'
import { useDefinitionLinks } from './useDefinitionLinks'
import { HighlightContext, useOccurrences } from './useOccurrences'
@@ -43,9 +45,15 @@ export function App(): ReactElement | null {
const [keep, setKeep] = useState<ReadonlySet<string>>(NONE)
/** 页面上这个文档版本的中文名:文档带来的,扩展端查到了再换 */
const [names, setNames] = useState<VersionNames | undefined>()
/** 这份文件相比对比基准改了什么:侧栏开着「未提交的更改」或审查工单时扩展端算好了补来,不比时是 null */
const [diff, setDiff] = useState<DocumentDiff | null>(null)
/** 收到消息时读眼下哪些块在编辑(消息回调只在挂载时注册一次) */
const editing = useRef(view.editing)
const collapsed = useMemo(() => collapsedIds(doc?.blocks ?? [], view.folds), [doc, view.folds])
// 解析失败的文档没有块,不标差异;删掉的块按块筛选同样藏
const changes = useMemo(() => doc && doc.error === undefined
? diffTree(doc.blocks, diff, doc.version, removed => !excludedBy(removed.block, excluded))
: undefined, [doc, diff, excluded])
const collapsed = useMemo(() => collapsedIds(doc?.blocks ?? [], view.folds, openedByDiff(changes)), [doc, view.folds, changes])
const filter = useMemo(() => applyFilter(doc?.blocks ?? [], excluded, keep), [doc, excluded, keep])
const covered = useMemo(() => coveredByEditing(doc?.blocks ?? [], new Set(view.editing)), [doc, view.editing])
/** 记下这几块、属性行、子行折叠还是展开,从此不再按默认 */
@@ -88,6 +96,9 @@ export function App(): ReactElement | null {
case 'filter':
setExcluded(msg.excluded)
setKeep(NONE)
return
case 'diff':
setDiff(msg.diff)
}
})
postMessage({ type: 'ready' })
@@ -121,7 +132,8 @@ export function App(): ReactElement | null {
},
onToggleFold: id => setFolded([id], !collapsed.has(id)),
...(qa.state.available && { qa }),
}, [doc, view, collapsed, filter, covered, kindName, focusId, onFocused, setFolded, qa])
...(changes && { diff: changes }),
}, [doc, view, collapsed, filter, covered, kindName, focusId, onFocused, setFolded, qa, changes])
if (!doc || !tree)
return null
@@ -138,8 +150,10 @@ export function App(): ReactElement | null {
translators={doc.translators}
translatorId={doc.translatorId}
onSelectTranslator={id => postMessage({ type: 'selectTranslator', id })}
below={diff && doc.error === undefined && <DiffBar diff={diff} />}
/>
<div className="mx-auto box-content max-w-[880px] px-6 py-5">
{diff?.newFile !== undefined && doc.error === undefined && <NewFileBanner detail={diff.newFile} />}
{doc.error !== undefined && (
<div className="mb-3 flex items-start gap-2 rounded-lg border border-[var(--vscode-inputValidation-errorBorder)] bg-[var(--vscode-inputValidation-errorBackground)] px-3 py-2">
<TriangleAlert size={16} strokeWidth={1.8} className="mt-px shrink-0 text-[var(--vscode-errorForeground)]" />