69 lines
3.3 KiB
TypeScript
69 lines
3.3 KiB
TypeScript
/**
|
||
* 钉在顶上的卡片(同 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
|
||
}
|
||
|
||
/** 眼下钉着的几行占多高([StickyLines](vscode/webview-ui/src/codeReader/StickyLines.tsx#StickyLines) 画的 `.cr-sticky`),没钉时是 0。 */
|
||
export function stickyHeight(): number {
|
||
return document.querySelector<HTMLElement>('.cr-sticky')?.offsetHeight ?? 0
|
||
}
|
||
|
||
/** 两次算出来钉的一样(同几张、左右位置一样、推得一样多):一样就不重画 */
|
||
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
|
||
})
|
||
}
|