✨ feat(vscode): 代码阅读滚进卡片的子块时把外层卡片钉在顶上,同 VS Code 的 Sticky Scroll
This commit is contained in:
1 parent
5ce2e904f4
commit
eb3d1b90cd
17 files changed
+548
-31
No files matched your search
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 钉在顶上的外层卡片(同 VS Code 编辑器的 Sticky Scroll):滚进一张卡片的子块、卡片自己的开头已经滚出去时,顶上钉一行它的图标和标题,
|
||||
* 外层的在上、里层的往下摞,每行一样高。竖直坐标都以筛选栏下沿为 0、往下为正(像素)。
|
||||
*/
|
||||
|
||||
/**
|
||||
* 页面上一张能钉住的卡片:子块画出来了的(折叠着的、被筛掉的、正在编辑的卡片下面没有)。
|
||||
* top 是卡片上沿,bottom 是它子块最后的下沿(卡片比子块还靠下时取卡片的);depth 是它外面套着几张卡片;left、right 是卡片左右边(视口里的 x)
|
||||
*/
|
||||
export interface StickyScope {
|
||||
id: string
|
||||
depth: number
|
||||
top: number
|
||||
bottom: number
|
||||
left: number
|
||||
right: number
|
||||
}
|
||||
|
||||
/** 眼下钉着的卡片,从外到里;offset 是最里那行被下面的内容往上顶了多少(≤ 0,它那张卡片快滚完时) */
|
||||
export interface PinnedLines {
|
||||
scopes: StickyScope[]
|
||||
offset: number
|
||||
}
|
||||
|
||||
export const NO_PINNED: PinnedLines = { scopes: [], offset: 0 }
|
||||
|
||||
/**
|
||||
* 钉住哪几张,照 VS Code 的 `StickyScrollController.findScrollWidgetState`:按页面先后(外层在前)看每张,它那一行在 depth × lineHeight;
|
||||
* 卡片上沿已经在这一行顶上面、子块的下沿还没过这一行顶时钉住。子块的下沿高过这一行的下沿时,这一行跟着往上推。
|
||||
* 钉满 limit 行就不再往里看:套得深时留外层的,同 VS Code。scopes 要按页面先后排。
|
||||
*/
|
||||
export function pinnedLines(scopes: readonly StickyScope[], lineHeight: number, limit: number): PinnedLines {
|
||||
const pinned: StickyScope[] = []
|
||||
let offset = 0
|
||||
for (const scope of scopes) {
|
||||
if (pinned.length >= limit)
|
||||
break
|
||||
const top = scope.depth * lineHeight
|
||||
if (top <= scope.top || top > scope.bottom)
|
||||
continue
|
||||
pinned.push(scope)
|
||||
offset = Math.min(0, scope.bottom - (top + lineHeight))
|
||||
}
|
||||
return { scopes: pinned, offset }
|
||||
}
|
||||
|
||||
/** 最多钉几行:设置里的 maxLineCount,且不超过可视区域(筛选栏下面,高 viewHeight)的四分之一,同 VS Code,窗口矮时不让钉住的行占满 */
|
||||
export function lineLimit(viewHeight: number, lineHeight: number, maxLineCount: number): number {
|
||||
return Math.min(maxLineCount, Math.round(viewHeight / lineHeight / 4))
|
||||
}
|
||||
|
||||
/** 一张卡片滚到顶上时,它上面钉着多高:外层的卡片都钉住,最多 limit 行;它自己在这几行下面露出来 */
|
||||
export function insetAbove(depth: number, lineHeight: number, limit: number): number {
|
||||
return Math.min(depth, limit) * lineHeight
|
||||
}
|
||||
|
||||
/** 两次算出来钉的一样(同几张、左右位置一样、推得一样多):一样就不重画 */
|
||||
export function samePinned(a: PinnedLines, b: PinnedLines): boolean {
|
||||
return a.offset === b.offset && a.scopes.length === b.scopes.length && a.scopes.every((scope, index) => {
|
||||
const other = b.scopes[index]
|
||||
return scope.id === other.id && scope.left === other.left && scope.right === other.right
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user