From 5b55b8d70f93d3dd46dba888e109121e3b50c8e5 Mon Sep 17 00:00:00 2001 From: Michael Lively Date: Thu, 18 Jan 2024 15:45:52 -0800 Subject: [PATCH] CSS tweaks, folding icon, indentation option, high contrast background --- .../media/notebookEditorStickyScroll.css | 50 +++++++++++--- .../viewParts/notebookEditorStickyScroll.ts | 67 +++++++++++++++++-- 2 files changed, 101 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebookEditorStickyScroll.css b/src/vs/workbench/contrib/notebook/browser/media/notebookEditorStickyScroll.css index 4b4078aecbe8b..38522aba11355 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebookEditorStickyScroll.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebookEditorStickyScroll.css @@ -6,29 +6,61 @@ .monaco-workbench .notebookOverlay .notebook-sticky-scroll-container { display: none; background-color: var(--vscode-notebook-editorBackground); + padding-left: 9.5px; +} + +.monaco-workbench + .notebookOverlay + .notebook-sticky-scroll-container + .notebook-sticky-scroll-element { + display: flex; + align-items: center; +} + +.monaco-workbench + .notebookOverlay + .notebook-sticky-scroll-container + .notebook-sticky-scroll-element + .notebook-sticky-scroll-folding-icon { + transition: var(--vscode-editorStickyScroll-foldingOpacityTransition); +} + +.monaco-workbench + .notebookOverlay + .notebook-sticky-scroll-container + .notebook-sticky-scroll-element + .notebook-sticky-scroll-header { width: 100%; + padding-left: 6px; } .monaco-workbench .notebookOverlay .notebook-sticky-scroll-container - .notebook-sticky-scroll-line { - background-color: var(--vscode-notebook-editorBackground); - position: relative; - padding-left: 12px; - /* transition: margin-top 0.2s ease-in-out; */ + .notebook-sticky-scroll-element + .notebook-sticky-scroll-header:hover { + background-color: var(--vscode-editorStickyScrollHover-background); + width: 100%; + cursor: pointer; } .monaco-workbench.hc-light .notebookOverlay .notebook-sticky-scroll-container, .monaco-workbench.hc-black .notebookOverlay .notebook-sticky-scroll-container { background-color: var(--vscode-editorStickyScroll-background); border-bottom: 1px solid var(--vscode-contrastBorder); + padding-bottom: 3px; } -.monaco-workbench +.monaco-workbench.hc-light .notebookOverlay .notebook-sticky-scroll-container - .notebook-sticky-scroll-line:hover { - background-color: var(--vscode-editorStickyScrollHover-background); - cursor: pointer; + .notebook-sticky-scroll-element + .notebook-sticky-scroll-header:hover, +.monaco-workbench.hc-black + .notebookOverlay + .notebook-sticky-scroll-container + .notebook-sticky-scroll-element + .notebook-sticky-scroll-header:hover { + outline: 1px dashed var(--vscode-contrastActiveBorder); + outline-offset: -2px; } diff --git a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts index 0c812230c030b..886d53919f8b6 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewParts/notebookEditorStickyScroll.ts @@ -20,6 +20,8 @@ import { OutlineEntry } from 'vs/workbench/contrib/notebook/browser/viewModel/Ou import { NotebookCellOutlineProvider } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookOutlineProvider'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Delayer } from 'vs/base/common/async'; +import { ThemeIcon } from 'vs/base/common/themables'; +import { foldingCollapsedIcon, foldingExpandedIcon } from 'vs/editor/contrib/folding/browser/foldingDecorations'; export class ToggleNotebookStickyScroll extends Action2 { @@ -54,26 +56,46 @@ export class ToggleNotebookStickyScroll extends Action2 { export class NotebookStickyLine extends Disposable { constructor( public readonly element: HTMLElement, + public readonly foldingIcon: StickyFoldingIcon, + public readonly header: HTMLElement, public readonly entry: OutlineEntry, public readonly notebookEditor: INotebookEditor, ) { super(); - this._register(DOM.addDisposableListener(this.element, DOM.EventType.CLICK, () => { + // click the header to focus the cell + this._register(DOM.addDisposableListener(this.header, DOM.EventType.CLICK, () => { this.focusCell(); })); + + // click the folding icon to fold the range covered by the header + this._register(DOM.addDisposableListener(this.foldingIcon.domNode, DOM.EventType.CLICK, () => { + this.foldRange(); + })); + + // folding icon hovers + // this._register(DOM.addDisposableListener(this.element, DOM.EventType.MOUSE_OVER, () => { + // this.foldingIcon.setVisible(true); + // })); + // this._register(DOM.addDisposableListener(this.element, DOM.EventType.MOUSE_OUT, () => { + // this.foldingIcon.setVisible(false); + // })); + + } + + private foldRange() { + throw new Error('Method not implemented.'); } private focusCell() { this.notebookEditor.focusNotebookCell(this.entry.cell, 'container'); const cellScrollTop = this.notebookEditor.getAbsoluteTopOfElement(this.entry.cell); - const parentCount = this.getParentCount(); + const parentCount = NotebookStickyLine.getParentCount(this.entry); // 1.1 addresses visible cell padding, to make sure we don't focus md cell and also render its sticky line this.notebookEditor.setScrollTop(cellScrollTop - (parentCount + 1.1) * 22); } - private getParentCount() { + static getParentCount(entry: OutlineEntry) { let count = 0; - let entry = this.entry; while (entry.parent) { count++; entry = entry.parent; @@ -82,6 +104,26 @@ export class NotebookStickyLine extends Disposable { } } +class StickyFoldingIcon { + + public domNode: HTMLElement; + + constructor( + public isCollapsed: boolean, + public dimension: number + ) { + this.domNode = document.createElement('div'); + this.domNode.style.width = `${dimension}px`; + this.domNode.style.height = `${dimension}px`; + this.domNode.className = ThemeIcon.asClassName(isCollapsed ? foldingCollapsedIcon : foldingExpandedIcon); + } + + public setVisible(visible: boolean) { + this.domNode.style.cursor = visible ? 'pointer' : 'default'; + this.domNode.style.opacity = visible ? '1' : '0'; + } +} + export class NotebookStickyScroll extends Disposable { private readonly _disposables = new DisposableStore(); private currentStickyLines = new Map(); @@ -302,9 +344,20 @@ export class NotebookStickyScroll extends Disposable { static createStickyElement(entry: OutlineEntry, notebookEditor: INotebookEditor) { const stickyElement = document.createElement('div'); - stickyElement.classList.add('notebook-sticky-scroll-line'); - stickyElement.innerText = '#'.repeat(entry.level) + ' ' + entry.label; - return new NotebookStickyLine(stickyElement, entry, notebookEditor); + stickyElement.classList.add('notebook-sticky-scroll-element'); + stickyElement.style.paddingLeft = NotebookStickyLine.getParentCount(entry) * 20 + 'px'; + + const stickyFoldingIcon = new StickyFoldingIcon(false, 16); + stickyFoldingIcon.domNode.classList.add('notebook-sticky-scroll-folding-icon'); + // stickyFoldingIcon.domNode.style.setProperty('--vscode-editorStickyScroll-foldingOpacityTransition', `opacity 0.5s`); + stickyFoldingIcon.setVisible(true); + + const stickyHeader = document.createElement('div'); + stickyHeader.classList.add('notebook-sticky-scroll-header'); + stickyHeader.innerText = entry.label; + + stickyElement.append(stickyFoldingIcon.domNode, stickyHeader); + return new NotebookStickyLine(stickyElement, stickyFoldingIcon, stickyHeader, entry, notebookEditor); } private disposeCurrentStickyLines() {