Use document-style for Notebooks (#3902)

* Added hover support, adding box shadow and light outline on hovering and the "more actions" button showing on hover
* Added box shadow for dark themes (hooray!)
* Remove border from everything but the code cell unless a cell is selected or hovered over. This ensures this looks like a document
* Fix high contrast theming issues.
This commit is contained in:
Kevin Cunnane
2019-02-05 11:28:07 -08:00
committed by GitHub
parent 80c1c4c6c8
commit 098c40e9ac
8 changed files with 116 additions and 25 deletions

View File

@@ -4,7 +4,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-->
<div style="width: 100%; height: 100%; display: flex; flex-flow: row">
<div style="width: 100%; height: 100%; display: flex; flex-flow: row" (mouseover)="hover=true" (mouseleave)="hover=false">
<div #toolbar class="toolbar" style="flex: 0 0 auto; display: flex; flex-flow:column; width: 40px; min-height: 40px; orientation: portrait">
</div>
<div #editor class="editor" style="flex: 1 1 auto; overflow: hidden;">

View File

@@ -54,6 +54,15 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
this._activeCellId = value;
}
@Input() set hover(value: boolean) {
this._hover = value;
if (!this.isActive()) {
// Only make a change if we're not active, since this has priority
this.toggleMoreActionsButton(this._hover);
}
}
protected _actionBar: Taskbar;
private readonly _minimumHeight = 30;
private _editor: QueryTextEditor;
@@ -63,6 +72,7 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
private _model: NotebookModel;
private _activeCellId: string;
private _cellToggleMoreActions: CellToggleMoreActions;
private _hover: boolean;
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
@@ -202,4 +212,12 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange
this._editor.getContainer().scrollIntoView();
}
}
protected isActive() {
return this.cellModel && this.cellModel.id === this.activeCellId;
}
protected toggleMoreActionsButton(isActive: boolean) {
this._cellToggleMoreActions.toggle(isActive, this.moreActionsElementRef, this.model, this.cellModel);
}
}

View File

@@ -5,7 +5,7 @@
*--------------------------------------------------------------------------------------------*/
-->
<div style="width: 100%; height: 100%; display: flex; flex-flow: column">
<div class="notebook-code" style="flex: 0 0 auto;">
<div style="flex: 0 0 auto;">
<code-component [cellModel]="cellModel" [model]="model" [activeCellId]="activeCellId"></code-component>
</div>
<div style="flex: 0 0 auto; width: 100%; height: 100%; display: block">

View File

@@ -7,9 +7,7 @@ output-area-component {
}
output-area-component .notebook-output {
border-top-width: 1px;
border-top-style: solid;
border-top-width: 0px;
user-select: initial;
padding: 5px 20px 0px;
box-shadow: rgba(120, 120, 120, 0.75) 0px -2px 1px -2px;
}

View File

@@ -4,7 +4,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-->
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column">
<div style="overflow: hidden; width: 100%; height: 100%; display: flex; flex-flow: column" (mouseover)="hover=true" (mouseleave)="hover=false">
<loading-spinner [loading]="isLoading"></loading-spinner>
<div class="notebook-text" style="flex: 0 0 auto;">
<code-component *ngIf="isEditMode" [cellModel]="cellModel" (onContentChanged)="handleContentChanged()" [model]="model" [activeCellId]="activeCellId" [hideVerticalToolbar]=true>

View File

@@ -41,6 +41,14 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
this._activeCellId = value;
}
@Input() set hover(value: boolean) {
this._hover = value;
if (!this.isActive()) {
// Only make a change if we're not active, since this has priority
this.updateMoreActions();
}
}
private _content: string;
private isEditMode: boolean;
private _sanitizer: ISanitizer;
@@ -50,6 +58,7 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
public readonly onDidClickLink = this._onDidClickLink.event;
protected isLoading: boolean;
private _cellToggleMoreActions: CellToggleMoreActions;
private _hover: boolean;
constructor(
@Inject(forwardRef(() => CommonServiceInterface)) private _bootstrapService: CommonServiceInterface,
@@ -158,24 +167,33 @@ export class TextCellComponent extends CellView implements OnInit, OnChanges {
public toggleEditMode(editMode?: boolean): void {
this.isEditMode = editMode !== undefined? editMode : !this.isEditMode;
if (!this.isEditMode && this.cellModel.id === this._activeCellId) {
this._cellToggleMoreActions.toggle(true, this.moreActionsElementRef, this.model, this.cellModel);
}
else {
this._cellToggleMoreActions.toggle(false, this.moreActionsElementRef, this.model, this.cellModel);
}
this.updateMoreActions();
this.updatePreview();
this._changeRef.detectChanges();
}
private setFocusAndScroll(): void {
if (this.cellModel.id === this._activeCellId) {
this.toggleEditMode(true);
} else {
this.toggleEditMode(false);
private updateMoreActions(): void {
if (!this.isEditMode && (this.isActive() || this._hover)) {
this.toggleMoreActionsButton(true);
}
else {
this.toggleMoreActionsButton(false);
}
}
private setFocusAndScroll(): void {
this.toggleEditMode(this.isActive());
if (this.output && this.output.nativeElement) {
(<HTMLElement>this.output.nativeElement).scrollTo();
}
}
protected isActive() {
return this.cellModel && this.cellModel.id === this.activeCellId;
}
protected toggleMoreActionsButton(isActive: boolean) {
this._cellToggleMoreActions.toggle(isActive, this.moreActionsElementRef, this.model, this.cellModel);
}
}

View File

@@ -8,8 +8,6 @@ text-cell-component {
}
text-cell-component .notebook-preview {
border-top-width: 1px;
border-top-style: solid;
user-select: initial;
padding-left: 8px;
padding-right: 8px;

View File

@@ -6,10 +6,12 @@ import 'vs/css!./notebook';
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { activeContrastBorder, buttonBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
import { activeContrastBorder, contrastBorder, buttonBackground, textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
let lightBoxShadow = '0px 4px 6px 0px rgba(0,0,0,0.14)';
let darkBoxShadow = '0 4px 6px 0px rgba(0, 0, 0, 1)';
// Active border
const activeBorder = theme.getColor(buttonBackground);
if (activeBorder) {
@@ -17,17 +19,64 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
.notebookEditor .notebook-cell.active {
border-color: ${activeBorder};
border-width: 1px;
box-shadow: 0px 4px 6px 0px rgba(0,0,0,0.14);
}
`);
}
// Box shadow handling
collector.addRule(`
.notebookEditor .notebook-cell.active {
box-shadow: ${lightBoxShadow};
}
.vs-dark .notebookEditor .notebook-cell.active {
box-shadow: ${darkBoxShadow};
}
.hc-black .notebookEditor .notebook-cell.active {
box-shadow: 0;
}
.notebookEditor .notebook-cell:hover:not(.active) {
box-shadow: ${lightBoxShadow};
}
.vs-dark .notebookEditor .notebook-cell:hover:not(.active) {
box-shadow: ${darkBoxShadow};
}
.hc-black .notebookEditor .notebook-cell:hover:not(.active) {
box-shadow: 0;
}
`);
// Inactive border
const inactiveBorder = theme.getColor(SIDE_BAR_BACKGROUND);
if (inactiveBorder) {
collector.addRule(`
.notebookEditor .notebook-cell code-component {
border-color: ${inactiveBorder};
border-width: 1px;
border-style: solid;
border-radius: 3px 3px 3px 3px;
}
.notebookEditor .notebook-cell.active code-component {
border-width: 0px 0px 1px 0px;
border-radius: 0px;
}
.notebookEditor .notebook-cell:hover code-component {
border-width: 0px 0px 1px 0px;
border-radius: 0px;
}
.notebookEditor .notebook-cell {
border-color: ${inactiveBorder};
border-width: 0px;
}
.notebookEditor .notebook-cell.active {
border-width: 1px;
}
.notebookEditor .notebook-cell:hover {
border-width: 1px;
}
`);
@@ -41,17 +90,27 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
// Styling with Outline color (e.g. high contrast theme)
const outline = theme.getColor(activeContrastBorder);
const hcOutline = theme.getColor(contrastBorder);
if (outline) {
collector.addRule(`
.hc-black .notebookEditor .notebook-cell:not(.active) code-component {
border-color: ${hcOutline};
border-width: 0px 0px 1px 0px;
}
.hc-black .notebookEditor .notebook-cell.active code-component {
border-color: ${outline};
border-width: 0px 0px 1px 0px;
}
.hc-black .notebookEditor .notebook-cell:not(.active) {
outline-color: ${hcOutline};
outline-width: 1px;
outline-style: solid;
}
.notebookEditor .notebook-cell.active {
outline-color: ${outline};
outline-width: 1px;
outline-style: solid;
}
.notebookEditor .notebook-cell:hover:not(.active) {
outline-style: dashed;
}
`);
}