From 3c2075a9321f1f140baa7393fdb3b10c33f2ebb4 Mon Sep 17 00:00:00 2001 From: seokju-na Date: Tue, 11 Dec 2018 03:23:10 +0900 Subject: [PATCH] #39 Add settings module --- src/browser/app.scss | 3 + src/browser/settings/_all-theme.scss | 5 + src/browser/settings/index.ts | 5 + .../_settings-dialog-theme.scss | 11 ++ .../settings-dialog/settings-dialog-data.ts | 3 + .../settings-dialog.component.html | 17 +++ .../settings-dialog.component.scss | 14 +++ .../settings-dialog.component.spec.ts | 108 ++++++++++++++++++ .../settings-dialog.component.ts | 45 ++++++++ .../settings-dialog/settings-dialog.ts | 25 ++++ src/browser/settings/settings.module.ts | 23 ++++ 11 files changed, 259 insertions(+) create mode 100644 src/browser/settings/_all-theme.scss create mode 100644 src/browser/settings/index.ts create mode 100644 src/browser/settings/settings-dialog/_settings-dialog-theme.scss create mode 100644 src/browser/settings/settings-dialog/settings-dialog-data.ts create mode 100644 src/browser/settings/settings-dialog/settings-dialog.component.html create mode 100644 src/browser/settings/settings-dialog/settings-dialog.component.scss create mode 100644 src/browser/settings/settings-dialog/settings-dialog.component.spec.ts create mode 100644 src/browser/settings/settings-dialog/settings-dialog.component.ts create mode 100644 src/browser/settings/settings-dialog/settings-dialog.ts create mode 100644 src/browser/settings/settings.module.ts diff --git a/src/browser/app.scss b/src/browser/app.scss index 380aaa3e..024e9e90 100644 --- a/src/browser/app.scss +++ b/src/browser/app.scss @@ -10,6 +10,7 @@ @import "app/all-theme"; @import "note/all-theme"; @import "vcs/all-theme"; +@import "settings/all-theme"; @include ui-core(); @@ -18,6 +19,7 @@ @include gd-ui-all-theme($basic-light-theme); @include gd-note-all-theme($basic-light-theme); @include gd-vcs-all-theme($basic-light-theme); + @include gd-settings-all-theme($basic-light-theme); } .BasicDarkTheme { @@ -25,4 +27,5 @@ @include gd-ui-all-theme($basic-dark-theme); @include gd-note-all-theme($basic-dark-theme); @include gd-vcs-all-theme($basic-dark-theme); + @include gd-settings-all-theme($basic-dark-theme); } diff --git a/src/browser/settings/_all-theme.scss b/src/browser/settings/_all-theme.scss new file mode 100644 index 00000000..48cef7d9 --- /dev/null +++ b/src/browser/settings/_all-theme.scss @@ -0,0 +1,5 @@ +@import "./settings-dialog/settings-dialog-theme"; + +@mixin gd-settings-all-theme($theme) { + @include gd-settings-dialog-theme($theme); +} diff --git a/src/browser/settings/index.ts b/src/browser/settings/index.ts new file mode 100644 index 00000000..386ad3b0 --- /dev/null +++ b/src/browser/settings/index.ts @@ -0,0 +1,5 @@ +export * from './settings.module'; +export * from './settings-context'; +export * from './settings-registry'; +export * from './settings-dialog/settings-dialog.component'; +export * from './settings-dialog/settings-dialog'; diff --git a/src/browser/settings/settings-dialog/_settings-dialog-theme.scss b/src/browser/settings/settings-dialog/_settings-dialog-theme.scss new file mode 100644 index 00000000..33c8af6c --- /dev/null +++ b/src/browser/settings/settings-dialog/_settings-dialog-theme.scss @@ -0,0 +1,11 @@ +@import "../../ui/style/theming"; + +@mixin gd-settings-dialog-theme($theme) { + $foreground: map-get($theme, foreground); + + .SettingsDialog { + &__content > gd-tab-group { + border-bottom: 1px solid gd-color($foreground, divider); + } + } +} diff --git a/src/browser/settings/settings-dialog/settings-dialog-data.ts b/src/browser/settings/settings-dialog/settings-dialog-data.ts new file mode 100644 index 00000000..94262c55 --- /dev/null +++ b/src/browser/settings/settings-dialog/settings-dialog-data.ts @@ -0,0 +1,3 @@ +export interface SettingsDialogData { + initialSettingId?: string; +} diff --git a/src/browser/settings/settings-dialog/settings-dialog.component.html b/src/browser/settings/settings-dialog/settings-dialog.component.html new file mode 100644 index 00000000..26c399c2 --- /dev/null +++ b/src/browser/settings/settings-dialog/settings-dialog.component.html @@ -0,0 +1,17 @@ + +

{{ title }}

+ +
+ + + +
+ +
+ +
+
+
+
diff --git a/src/browser/settings/settings-dialog/settings-dialog.component.scss b/src/browser/settings/settings-dialog/settings-dialog.component.scss new file mode 100644 index 00000000..c71c05a9 --- /dev/null +++ b/src/browser/settings/settings-dialog/settings-dialog.component.scss @@ -0,0 +1,14 @@ +@import "../../ui/style/spacing"; + +.SettingsDialog { + &__content { + padding: 0 !important; + } + + &__container { + padding: $spacing; + } + + &__tabContent { + } +} diff --git a/src/browser/settings/settings-dialog/settings-dialog.component.spec.ts b/src/browser/settings/settings-dialog/settings-dialog.component.spec.ts new file mode 100644 index 00000000..e7b0fae4 --- /dev/null +++ b/src/browser/settings/settings-dialog/settings-dialog.component.spec.ts @@ -0,0 +1,108 @@ +import { NgModule } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { fastTestSetup, NoopComponent } from '../../../../test/helpers'; +import { MockDialog, MockDialogRef } from '../../../../test/mocks/browser'; +import { DialogRef } from '../../ui/dialog'; +import { UiModule } from '../../ui/ui.module'; +import { SettingsContext } from '../settings-context'; +import { SETTINGS_REGISTRATION, SettingsRegistry } from '../settings-registry'; +import { SettingsDialogData } from './settings-dialog-data'; +import { SettingsDialogComponent } from './settings-dialog.component'; + + +describe('browser.settings.SettingsDialogComponent', () => { + let component: SettingsDialogComponent; + let fixture: ComponentFixture; + + let mockDialogRef: MockDialogRef; + + let registry: SettingsRegistry; + const registration: SettingsContext[] = [ + { + id: 'settings-1', + tabName: 'Settings1', + component: NoopComponent, + }, + { + id: 'settings-2', + tabName: 'Settings2', + component: NoopComponent, + }, + { + id: 'settings-3', + tabName: 'Settings3', + component: NoopComponent, + }, + ]; + + @NgModule({ + declarations: [NoopComponent], + entryComponents: [NoopComponent], + exports: [NoopComponent], + }) + class NoopModuleWithEntries { + } + + fastTestSetup(); + + beforeAll(async () => { + mockDialogRef = new MockDialogRef(new MockDialog(), SettingsDialogComponent); + + await TestBed + .configureTestingModule({ + imports: [ + UiModule, + NoopModuleWithEntries, + ], + providers: [ + SettingsRegistry, + { provide: SETTINGS_REGISTRATION, useValue: registration }, + { provide: DialogRef, useValue: mockDialogRef }, + ], + declarations: [ + SettingsDialogComponent, + ], + }) + .compileComponents(); + }); + + beforeEach(() => { + registry = TestBed.get(SettingsRegistry); + + fixture = TestBed.createComponent(SettingsDialogComponent); + component = fixture.componentInstance; + component.data = {}; + }); + + afterEach(() => { + registry.ngOnDestroy(); + }); + + it('should select first tab by default.', () => { + fixture.detectChanges(); + expect(component.tabControl.activateTab.value).toEqual('settings-1'); + }); + + it('should select initial setting id if it provided.', () => { + component.data = { initialSettingId: 'settings-3' }; + fixture.detectChanges(); + + expect(component.tabControl.activateTab.value).toEqual('settings-3'); + }); + + it('should close dialog when click close button.', () => { + const closeCallback = jasmine.createSpy('close callback'); + const subscription = mockDialogRef.afterClosed().subscribe(closeCallback); + + fixture.detectChanges(); + + const closeButtonEl = fixture.debugElement.query( + By.css('button#settings-dialog-close-button'), + ).nativeElement as HTMLButtonElement; + closeButtonEl.click(); + + expect(closeCallback).toHaveBeenCalled(); + subscription.unsubscribe(); + }); +}); diff --git a/src/browser/settings/settings-dialog/settings-dialog.component.ts b/src/browser/settings/settings-dialog/settings-dialog.component.ts new file mode 100644 index 00000000..720854df --- /dev/null +++ b/src/browser/settings/settings-dialog/settings-dialog.component.ts @@ -0,0 +1,45 @@ +import { Component, Inject, Injector, OnInit, Optional } from '@angular/core'; +import { __DARWIN__ } from '../../../libs/platform'; +import { DIALOG_DATA, DialogRef } from '../../ui/dialog'; +import { TabControl } from '../../ui/tabs/tab-control'; +import { SettingsContext } from '../settings-context'; +import { SettingsRegistry } from '../settings-registry'; +import { SettingsDialogData } from './settings-dialog-data'; + + +@Component({ + selector: 'gd-settings-dialog', + templateUrl: './settings-dialog.component.html', + styleUrls: ['./settings-dialog.component.scss'], +}) +export class SettingsDialogComponent implements OnInit { + readonly title = __DARWIN__ ? 'Preferences' : 'Settings'; + readonly settingContexts: SettingsContext[]; + readonly tabControl: TabControl; + + constructor( + public _injector: Injector, + @Optional() @Inject(DIALOG_DATA) public data: SettingsDialogData, + private registry: SettingsRegistry, + private dialogRef: DialogRef, + ) { + this.settingContexts = this.registry.getSettings(); + this.tabControl = new TabControl(this.settingContexts.map(context => ({ + id: context.id, + name: context.tabName, + value: context.id, + }))); + } + + ngOnInit(): void { + if (this.data && this.data.initialSettingId) { + this.tabControl.selectTabByValue(this.data.initialSettingId); + } else { + this.tabControl.selectFirstTab(); + } + } + + closeThisDialog(): void { + this.dialogRef.close(); + } +} diff --git a/src/browser/settings/settings-dialog/settings-dialog.ts b/src/browser/settings/settings-dialog/settings-dialog.ts new file mode 100644 index 00000000..ff666821 --- /dev/null +++ b/src/browser/settings/settings-dialog/settings-dialog.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; +import { Dialog, DialogRef } from '../../ui/dialog'; +import { SettingsDialogData } from './settings-dialog-data'; +import { SettingsDialogComponent } from './settings-dialog.component'; + + +@Injectable() +export class SettingsDialog { + constructor(private dialog: Dialog) { + } + + open(data?: SettingsDialogData): DialogRef { + return this.dialog.open( + SettingsDialogComponent, + { + width: '500px', + maxHeight: '75vh', + disableBackdropClickClose: true, + data, + }, + ); + } +} diff --git a/src/browser/settings/settings.module.ts b/src/browser/settings/settings.module.ts new file mode 100644 index 00000000..68ccc305 --- /dev/null +++ b/src/browser/settings/settings.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { UiModule } from '../ui/ui.module'; +import { SettingsDialog } from './settings-dialog/settings-dialog'; +import { SettingsDialogComponent } from './settings-dialog/settings-dialog.component'; +import { SettingsRegistry } from './settings-registry'; + + +@NgModule({ + imports: [ + UiModule, + ], + declarations: [SettingsDialogComponent], + entryComponents: [ + SettingsDialogComponent, + ], + providers: [ + SettingsDialog, + SettingsRegistry, + ], + exports: [SettingsDialogComponent], +}) +export class SettingsModule { +}