mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-24 09:35:37 -05:00
Add wizard sidebar navigation (#1911)
This commit is contained in:
@@ -13,6 +13,7 @@ import { CommonModule, APP_BASE_HREF } from '@angular/common';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { DialogContainer } from 'sql/platform/dialog/dialogContainer.component';
|
||||
import { WizardNavigation } from 'sql/platform/dialog/wizardNavigation.component';
|
||||
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
||||
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||
@@ -37,12 +38,13 @@ export const DialogModule = (params, selector: string, instantiationService: IIn
|
||||
SelectBox,
|
||||
InputBox,
|
||||
DialogContainer,
|
||||
WizardNavigation,
|
||||
ModelViewContent,
|
||||
ModelComponentWrapper,
|
||||
ComponentHostDirective,
|
||||
...extensionComponents
|
||||
],
|
||||
entryComponents: [DialogContainer, ...extensionComponents],
|
||||
entryComponents: [DialogContainer, WizardNavigation, ...extensionComponents],
|
||||
imports: [
|
||||
FormsModule,
|
||||
CommonModule,
|
||||
@@ -65,7 +67,8 @@ export const DialogModule = (params, selector: string, instantiationService: IIn
|
||||
}
|
||||
|
||||
ngDoBootstrap(appRef: ApplicationRef) {
|
||||
const factoryWrapper: any = this._resolver.resolveComponentFactory(DialogContainer);
|
||||
let componentClass = this.selector.startsWith(WizardNavigation.SELECTOR) ? WizardNavigation : DialogContainer;
|
||||
const factoryWrapper: any = this._resolver.resolveComponentFactory<WizardNavigation | DialogContainer>(componentClass);
|
||||
factoryWrapper.factory.selector = this.selector;
|
||||
appRef.bootstrap(factoryWrapper);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
.dialogModal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-width: 500px;
|
||||
|
||||
94
src/sql/platform/dialog/media/wizardNavigation.css
Normal file
94
src/sql/platform/dialog/media/wizardNavigation.css
Normal file
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.wizardNavigation-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 80px;
|
||||
height: calc(100% + 25px);
|
||||
margin-top: -25px;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-container {
|
||||
border-right-color: #2b56f2;
|
||||
border-right-style: solid;
|
||||
border-right-width: 1px;
|
||||
background-color: unset;
|
||||
}
|
||||
|
||||
.wizardNavigation-pageNumber {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-height: 130px;
|
||||
}
|
||||
|
||||
.wizardNavigation-pageNumber a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.wizardNavigation-dot {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
background-color: rgb(200, 200, 200);
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
border-style: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot {
|
||||
flex-grow: 1;
|
||||
background-color: unset;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.wizardNavigation-connector {
|
||||
width: 3px;
|
||||
display: inline-block;
|
||||
flex-grow: 1;
|
||||
background-color: rgb(200, 200, 200);
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-connector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.wizardNavigation-connector.active,
|
||||
.wizardNavigation-dot.active {
|
||||
background-color: rgb(9, 109, 201);
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot.active {
|
||||
border-color: #2b56f2;
|
||||
background-color: unset;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot.active:hover,
|
||||
.hc-black .wizardNavigation-dot.active.currentPage:hover {
|
||||
border-color: #F38518;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
.wizardNavigation-dot.active.currentPage {
|
||||
border-style: double;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-dot.active.currentPage {
|
||||
border-style: solid;
|
||||
border-color: #F38518;
|
||||
}
|
||||
|
||||
.wizardNavigation-connector.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
@@ -8,23 +8,22 @@
|
||||
import 'vs/css!./media/dialogModal';
|
||||
import { Modal, IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
||||
import { attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||
import { Wizard, Dialog, DialogButton, WizardPage } from 'sql/platform/dialog/dialogTypes';
|
||||
import { Wizard, DialogButton, WizardPage } from 'sql/platform/dialog/dialogTypes';
|
||||
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { DialogMessage } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { DialogModule } from 'sql/platform/dialog/dialog.module';
|
||||
import { Button } from 'vs/base/browser/ui/button/button';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { Builder } from 'vs/base/browser/builder';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||
import { localize } from 'vs/nls';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { DialogMessage, MessageLevel } from '../../workbench/api/common/sqlExtHostTypes';
|
||||
|
||||
export class WizardModal extends Modal {
|
||||
private _dialogPanes = new Map<WizardPage, DialogPane>();
|
||||
@@ -128,6 +127,8 @@ export class WizardModal extends Modal {
|
||||
this._body = bodyBuilder.getHTMLElement();
|
||||
});
|
||||
|
||||
this.initializeNavigation(this._body);
|
||||
|
||||
this._wizard.pages.forEach(page => {
|
||||
this.registerPage(page);
|
||||
});
|
||||
@@ -201,6 +202,22 @@ export class WizardModal extends Modal {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap angular for the wizard's left nav bar
|
||||
*/
|
||||
private initializeNavigation(bodyContainer: HTMLElement) {
|
||||
bootstrapAngular(this._instantiationService,
|
||||
DialogModule,
|
||||
bodyContainer,
|
||||
'wizard-navigation',
|
||||
{
|
||||
wizard: this._wizard,
|
||||
navigationHandler: (index: number) => this.showPage(index, index > this._wizard.currentPage)
|
||||
},
|
||||
undefined,
|
||||
() => undefined);
|
||||
}
|
||||
|
||||
public open(): void {
|
||||
this.showPage(0, false);
|
||||
this.show();
|
||||
|
||||
91
src/sql/platform/dialog/wizardNavigation.component.ts
Normal file
91
src/sql/platform/dialog/wizardNavigation.component.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./media/wizardNavigation';
|
||||
import { Component, Inject, forwardRef, ElementRef, AfterViewInit, ChangeDetectorRef, ViewChild } from '@angular/core';
|
||||
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Wizard } from './dialogTypes';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { attachStyler } from 'vs/platform/theme/common/styler';
|
||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
|
||||
export class WizardNavigationParams implements IBootstrapParams {
|
||||
wizard: Wizard;
|
||||
navigationHandler: (index: number) => void;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: WizardNavigation.SELECTOR,
|
||||
providers: [],
|
||||
template: `
|
||||
<div #container class="wizardNavigation-container">
|
||||
<ng-container *ngFor="let item of _params.wizard.pages; let i = index">
|
||||
<div class="wizardNavigation-pageNumber">
|
||||
<div class="wizardNavigation-connector" [ngClass]="{'invisible': !hasTopConnector(i), 'active': isActive(i)}"></div>
|
||||
<a [attr.href]="isActive(i) ? '' : null" [title]="item.title">
|
||||
<span class="wizardNavigation-dot" [ngClass]="{'active': isActive(i), 'currentPage': isCurrentPage(i)}" (click)="navigate(i)">{{i+1}}</span>
|
||||
</a>
|
||||
<div class="wizardNavigation-connector" [ngClass]="{'invisible': !hasBottomConnector(i), 'active': isActive(i)}"></div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class WizardNavigation implements AfterViewInit {
|
||||
public static readonly SELECTOR = 'wizard-navigation';
|
||||
|
||||
private _onResize = new Emitter<void>();
|
||||
public readonly onResize: Event<void> = this._onResize.event;
|
||||
|
||||
@ViewChild('container', { read: ElementRef }) private _container: ElementRef;
|
||||
constructor(
|
||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||
@Inject(IBootstrapParams) private _params: WizardNavigationParams,
|
||||
@Inject(IWorkbenchThemeService) private _themeService: IWorkbenchThemeService) {
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this._themeService.onThemeChange(() => this.style());
|
||||
this.style();
|
||||
this._params.wizard.onPageChanged(() => this._changeRef.detectChanges());
|
||||
}
|
||||
|
||||
hasTopConnector(index: number): boolean {
|
||||
return index > 0;
|
||||
}
|
||||
|
||||
hasBottomConnector(index: number): boolean {
|
||||
return index + 1 !== this._params.wizard.pages.length;
|
||||
}
|
||||
|
||||
isActive(index: number): boolean {
|
||||
return index <= this._params.wizard.currentPage;
|
||||
}
|
||||
|
||||
isCurrentPage(index: number): boolean {
|
||||
return index === this._params.wizard.currentPage;
|
||||
}
|
||||
|
||||
navigate(index: number): void {
|
||||
if (this.isActive(index)) {
|
||||
this._params.navigationHandler(index);
|
||||
}
|
||||
}
|
||||
|
||||
private style(): void {
|
||||
let theme = this._themeService.getTheme();
|
||||
let navigationBackgroundColor = theme.getColor(SIDE_BAR_BACKGROUND);
|
||||
if (theme.type === 'light') {
|
||||
navigationBackgroundColor = navigationBackgroundColor.lighten(0.03);
|
||||
} else if (theme.type === 'dark') {
|
||||
navigationBackgroundColor = navigationBackgroundColor.darken(0.03);
|
||||
}
|
||||
(this._container.nativeElement as HTMLElement).style.backgroundColor = navigationBackgroundColor.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user